├── .gitignore
├── LICENSE
├── README.md
├── core
├── io.go
├── io_test.go
├── socket.go
└── types.go
├── emission
└── emitter.go
├── example
└── main.go
├── glog
└── log.go
├── go.mod
├── go.sum
├── grdp.go
└── protocol
├── lic
└── lic.go
├── nla
├── cssp.go
├── cssp_test.go
├── encode.go
├── encode_test.go
├── ntlm.go
└── ntlm_test.go
├── pdu
├── caps.go
├── data.go
└── pdu.go
├── sec
└── sec.go
├── t125
├── ber
│ └── ber.go
├── gcc
│ └── gcc.go
├── mcs.go
└── per
│ └── per.go
├── tpkt
└── tpkt.go
└── x224
└── x224.go
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Golang Retome Desktop Protocol
2 |
3 | grdp is a pure Golang implementation of the Microsoft RDP (Remote Desktop Protocol) protocol (**client side authorization only**).
4 |
5 | ## Status
6 |
7 | **The project is under development and not finished yet.**
8 |
9 | * [ ] SSL Authentication (soon)
10 | * [ ] NLA Authentication
11 |
12 | ## Example
13 |
14 | ```golang
15 | client := grdp.NewClient("192.168.0.2:3389", glog.DEBUG)
16 | err := client.Login("Administrator", "123456")
17 | if err != nil {
18 | fmt.Println("login failed,", err)
19 | } else {
20 | fmt.Println("login success")
21 | }
22 | ```
23 |
24 | ## Take ideas from
25 |
26 | * [rdpy](https://github.com/citronneur/rdpy)
27 | * [node-rdpjs](https://github.com/citronneur/node-rdpjs)
28 | * [gordp](https://github.com/Madnikulin50/gordp)
29 | * [ncrack_rdp](https://github.com/nmap/ncrack/blob/master/modules/ncrack_rdp.cc)
--------------------------------------------------------------------------------
/core/io.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "encoding/binary"
5 | "encoding/hex"
6 | "github.com/icodeface/grdp/glog"
7 | "io"
8 | )
9 |
10 | type ReadBytesComplete func(result []byte, err error)
11 |
12 | func StartReadBytes(len int, r io.Reader, cb ReadBytesComplete) {
13 | b := make([]byte, len)
14 | go func() {
15 | _, err := io.ReadFull(r, b)
16 | glog.Debug("GetBytes: ", hex.EncodeToString(b))
17 | cb(b, err)
18 | }()
19 | }
20 |
21 | func ReadBytes(len int, r io.Reader) ([]byte, error) {
22 | b := make([]byte, len)
23 | length, err := io.ReadFull(r, b)
24 | return b[:length], err
25 | }
26 |
27 | func ReadByte(r io.Reader) (byte, error) {
28 | b, err := ReadBytes(1, r)
29 | return b[0], err
30 | }
31 |
32 | func ReadUInt8(r io.Reader) (uint8, error) {
33 | b, err := ReadBytes(1, r)
34 | return uint8(b[0]), err
35 | }
36 |
37 | func ReadUint16LE(r io.Reader) (uint16, error) {
38 | b := make([]byte, 2)
39 | _, err := io.ReadFull(r, b)
40 | if err != nil {
41 | return 0, nil
42 | }
43 | return binary.LittleEndian.Uint16(b), nil
44 | }
45 |
46 | func ReadUint16BE(r io.Reader) (uint16, error) {
47 | b := make([]byte, 2)
48 | _, err := io.ReadFull(r, b)
49 | if err != nil {
50 | return 0, nil
51 | }
52 | return binary.BigEndian.Uint16(b), nil
53 | }
54 |
55 | func ReadUInt32LE(r io.Reader) (uint32, error) {
56 | b := make([]byte, 4)
57 | _, err := io.ReadFull(r, b)
58 | if err != nil {
59 | return 0, nil
60 | }
61 | return binary.LittleEndian.Uint32(b), nil
62 | }
63 |
64 | func ReadUInt32BE(r io.Reader) (uint32, error) {
65 | b := make([]byte, 4)
66 | _, err := io.ReadFull(r, b)
67 | if err != nil {
68 | return 0, nil
69 | }
70 | return binary.BigEndian.Uint32(b), nil
71 | }
72 |
73 | func WriteByte(data byte, w io.Writer) (int, error) {
74 | b := make([]byte, 1)
75 | b[0] = byte(data)
76 | return w.Write(b)
77 | }
78 |
79 | func WriteBytes(data []byte, w io.Writer) (int, error) {
80 | return w.Write(data)
81 | }
82 |
83 | func WriteUInt8(data uint8, w io.Writer) (int, error) {
84 | b := make([]byte, 1)
85 | b[0] = byte(data)
86 | return w.Write(b)
87 | }
88 |
89 | func WriteUInt16BE(data uint16, w io.Writer) (int, error) {
90 | b := make([]byte, 2)
91 | binary.BigEndian.PutUint16(b, data)
92 | return w.Write(b)
93 | }
94 |
95 | func WriteUInt16LE(data uint16, w io.Writer) (int, error) {
96 | b := make([]byte, 2)
97 | binary.LittleEndian.PutUint16(b, data)
98 | return w.Write(b)
99 | }
100 |
101 | func WriteUInt32LE(data uint32, w io.Writer) (int, error) {
102 | b := make([]byte, 4)
103 | binary.LittleEndian.PutUint32(b, data)
104 | return w.Write(b)
105 | }
106 |
107 | func WriteUInt32BE(data uint32, w io.Writer) (int, error) {
108 | b := make([]byte, 4)
109 | binary.BigEndian.PutUint32(b, data)
110 | return w.Write(b)
111 | }
112 |
--------------------------------------------------------------------------------
/core/io_test.go:
--------------------------------------------------------------------------------
1 | package core_test
2 |
3 | import (
4 | "bytes"
5 | "encoding/hex"
6 | "github.com/icodeface/grdp/core"
7 | "testing"
8 | )
9 |
10 | func TestWriteUInt16LE(t *testing.T) {
11 | buff := &bytes.Buffer{}
12 | core.WriteUInt32LE(66538, buff)
13 | result := hex.EncodeToString(buff.Bytes())
14 | expected := "ea030100"
15 | if result != expected {
16 | t.Error(result, "not equals to", expected)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/core/socket.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "encoding/hex"
5 | "fmt"
6 | "github.com/icodeface/grdp/glog"
7 | "github.com/icodeface/grdp/protocol/nla"
8 | "github.com/icodeface/tls"
9 | "net"
10 | )
11 |
12 | type SocketLayer struct {
13 | conn net.Conn
14 | tlsConn *tls.Conn
15 | ntlm *nla.NTLMv2
16 | }
17 |
18 | func NewSocketLayer(conn net.Conn, ntlm *nla.NTLMv2) *SocketLayer {
19 | l := &SocketLayer{
20 | conn: conn,
21 | tlsConn: nil,
22 | ntlm: ntlm,
23 | }
24 | return l
25 | }
26 |
27 | func (s *SocketLayer) Read(b []byte) (n int, err error) {
28 | if s.tlsConn != nil {
29 | return s.tlsConn.Read(b)
30 | }
31 | return s.conn.Read(b)
32 | }
33 |
34 | func (s *SocketLayer) Write(b []byte) (n int, err error) {
35 | if s.tlsConn != nil {
36 | return s.tlsConn.Write(b)
37 | }
38 | return s.conn.Write(b)
39 | }
40 |
41 | func (s *SocketLayer) Close() error {
42 | if s.tlsConn != nil {
43 | err := s.tlsConn.Close()
44 | if err != nil {
45 | return err
46 | }
47 | }
48 | return s.conn.Close()
49 | }
50 |
51 | func (s *SocketLayer) StartTLS() error {
52 | glog.Info("StartTLS")
53 | config := &tls.Config{
54 | InsecureSkipVerify: true,
55 | MinVersion: tls.VersionTLS10,
56 | MaxVersion: tls.VersionTLS13,
57 | PreferServerCipherSuites: true,
58 | }
59 | s.tlsConn = tls.Client(s.conn, config)
60 | return s.tlsConn.Handshake()
61 | }
62 |
63 | func (s *SocketLayer) StartNLA() error {
64 | glog.Info("StartNLA")
65 | err := s.StartTLS()
66 | if err != nil {
67 | glog.Info("start tls failed", err)
68 | return err
69 | }
70 | req := nla.EncodeDERTRequest([]nla.Message{s.ntlm.GetNegotiateMessage()}, "", "")
71 | _, err = s.Write(req)
72 | if err != nil {
73 | glog.Info("send NegotiateMessage", err)
74 | return err
75 | }
76 |
77 | resp := make([]byte, 1024)
78 | n, err := s.Read(resp)
79 | if err != nil {
80 | return fmt.Errorf("read %s", err)
81 | }
82 | return s.recvChallenge(resp[:n])
83 | }
84 |
85 | func (s *SocketLayer) recvChallenge(data []byte) error {
86 | glog.Debug("recvChallenge", hex.EncodeToString(data))
87 | tsreq, err := nla.DecodeDERTRequest(data)
88 | if err != nil {
89 | return err
90 | }
91 |
92 | // get pubkey
93 |
94 | pubkey := ""
95 |
96 | msg := s.ntlm.GetAuthenticateMessage(tsreq.NegoTokens[0].Data)
97 | req := nla.EncodeDERTRequest([]nla.Message{msg}, "", pubkey)
98 | _, err = s.Write(req)
99 | if err != nil {
100 | glog.Info("send AuthenticateMessage", err)
101 | return err
102 | }
103 |
104 | //resp := make([]byte, 1024)
105 | //_, err = s.Read(resp)
106 | //if err != nil {
107 | // return err
108 | //}
109 | //return s.recvPubKeyInc(resp)
110 |
111 | fmt.Println("todo")
112 | return nil
113 |
114 | }
115 |
116 | func (s *SocketLayer) recvPubKeyInc(data []byte) error {
117 | // todo
118 | return nil
119 | }
120 |
--------------------------------------------------------------------------------
/core/types.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import "github.com/icodeface/grdp/emission"
4 |
5 | type Transport interface {
6 | Read(b []byte) (n int, err error)
7 | Write(b []byte) (n int, err error)
8 | Close() error
9 |
10 | On(event, listener interface{}) *emission.Emitter
11 | Once(event, listener interface{}) *emission.Emitter
12 | Emit(event interface{}, arguments ...interface{}) *emission.Emitter
13 | }
14 |
15 | type FastPathListener interface {
16 | RecvFastPath(secFlag byte, s []byte)
17 | }
18 |
19 | type FastPathSender interface {
20 | SendFastPath(secFlag byte, s []byte) (int, error)
21 | }
22 |
--------------------------------------------------------------------------------
/emission/emitter.go:
--------------------------------------------------------------------------------
1 | // Package emission provides an event emitter.
2 | // copy form https://raw.githubusercontent.com/chuckpreslar/emission/master/emitter.go
3 | // fix issue with nest once
4 |
5 | package emission
6 |
7 | import (
8 | "errors"
9 | "fmt"
10 | "os"
11 | "reflect"
12 | "sync"
13 | )
14 |
15 | // Default number of maximum listeners for an event.
16 | const DefaultMaxListeners = 10
17 |
18 | // Error presented when an invalid argument is provided as a listener function
19 | var ErrNoneFunction = errors.New("Kind of Value for listener is not Func.")
20 |
21 | // RecoveryListener ...
22 | type RecoveryListener func(interface{}, interface{}, error)
23 |
24 | // Emitter ...
25 | type Emitter struct {
26 | // Mutex to prevent race conditions within the Emitter.
27 | *sync.Mutex
28 | // Map of event to a slice of listener function's reflect Values.
29 | events map[interface{}][]reflect.Value
30 | // Optional RecoveryListener to call when a panic occurs.
31 | recoverer RecoveryListener
32 | // Maximum listeners for debugging potential memory leaks.
33 | maxListeners int
34 |
35 | // Map of event to a slice of listener function's reflect Values.
36 | onces map[interface{}][]reflect.Value
37 | }
38 |
39 | // AddListener appends the listener argument to the event arguments slice
40 | // in the Emitter's events map. If the number of listeners for an event
41 | // is greater than the Emitter's maximum listeners then a warning is printed.
42 | // If the relect Value of the listener does not have a Kind of Func then
43 | // AddListener panics. If a RecoveryListener has been set then it is called
44 | // recovering from the panic.
45 | func (emitter *Emitter) AddListener(event, listener interface{}) *Emitter {
46 | emitter.Lock()
47 | defer emitter.Unlock()
48 |
49 | fn := reflect.ValueOf(listener)
50 |
51 | if reflect.Func != fn.Kind() {
52 | if nil == emitter.recoverer {
53 | panic(ErrNoneFunction)
54 | } else {
55 | emitter.recoverer(event, listener, ErrNoneFunction)
56 | }
57 | }
58 |
59 | if emitter.maxListeners != -1 && emitter.maxListeners < len(emitter.events[event])+1 {
60 | fmt.Fprintf(os.Stdout, "Warning: event `%v` has exceeded the maximum "+
61 | "number of listeners of %d.\n", event, emitter.maxListeners)
62 | }
63 |
64 | emitter.events[event] = append(emitter.events[event], fn)
65 |
66 | return emitter
67 | }
68 |
69 | // On is an alias for AddListener.
70 | func (emitter *Emitter) On(event, listener interface{}) *Emitter {
71 | return emitter.AddListener(event, listener)
72 | }
73 |
74 | // RemoveListener removes the listener argument from the event arguments slice
75 | // in the Emitter's events map. If the reflect Value of the listener does not
76 | // have a Kind of Func then RemoveListener panics. If a RecoveryListener has
77 | // been set then it is called after recovering from the panic.
78 | func (emitter *Emitter) RemoveListener(event, listener interface{}) *Emitter {
79 | emitter.Lock()
80 | defer emitter.Unlock()
81 |
82 | fn := reflect.ValueOf(listener)
83 |
84 | if reflect.Func != fn.Kind() {
85 | if nil == emitter.recoverer {
86 | panic(ErrNoneFunction)
87 | } else {
88 | emitter.recoverer(event, listener, ErrNoneFunction)
89 | }
90 | }
91 |
92 | if events, ok := emitter.events[event]; ok {
93 | newEvents := []reflect.Value{}
94 |
95 | for _, listener := range events {
96 | if fn.Pointer() != listener.Pointer() {
97 | newEvents = append(newEvents, listener)
98 | }
99 | }
100 |
101 | emitter.events[event] = newEvents
102 | }
103 |
104 | if events, ok := emitter.onces[event]; ok {
105 | newEvents := []reflect.Value{}
106 |
107 | for _, listener := range events {
108 | if fn.Pointer() != listener.Pointer() {
109 | newEvents = append(newEvents, listener)
110 | }
111 | }
112 |
113 | emitter.onces[event] = newEvents
114 | }
115 |
116 | return emitter
117 | }
118 |
119 | // Off is an alias for RemoveListener.
120 | func (emitter *Emitter) Off(event, listener interface{}) *Emitter {
121 | return emitter.RemoveListener(event, listener)
122 | }
123 |
124 | // Once generates a new function which invokes the supplied listener
125 | // only once before removing itself from the event's listener slice
126 | // in the Emitter's events map. If the reflect Value of the listener
127 | // does not have a Kind of Func then Once panics. If a RecoveryListener
128 | // has been set then it is called after recovering from the panic.
129 | func (emitter *Emitter) Once(event, listener interface{}) *Emitter {
130 | emitter.Lock()
131 | defer emitter.Unlock()
132 |
133 | fn := reflect.ValueOf(listener)
134 |
135 | if reflect.Func != fn.Kind() {
136 | if nil == emitter.recoverer {
137 | panic(ErrNoneFunction)
138 | } else {
139 | emitter.recoverer(event, listener, ErrNoneFunction)
140 | }
141 | }
142 |
143 | if emitter.maxListeners != -1 && emitter.maxListeners < len(emitter.onces[event])+1 {
144 | fmt.Fprintf(os.Stdout, "Warning: event `%v` has exceeded the maximum "+
145 | "number of listeners of %d.\n", event, emitter.maxListeners)
146 | }
147 |
148 | emitter.onces[event] = append(emitter.onces[event], fn)
149 | return emitter
150 | }
151 |
152 | // Emit attempts to use the reflect package to Call each listener stored
153 | // in the Emitter's events map with the supplied arguments. Each listener
154 | // is called within its own go routine. The reflect package will panic if
155 | // the agruments supplied do not align the parameters of a listener function.
156 | // If a RecoveryListener has been set then it is called after recovering from
157 | // the panic.
158 | func (emitter *Emitter) Emit(event interface{}, arguments ...interface{}) *Emitter {
159 | var (
160 | listeners []reflect.Value
161 | ok bool
162 | )
163 |
164 | // Lock the mutex when reading from the Emitter's
165 | // events map.
166 | emitter.Lock()
167 |
168 | if listeners, ok = emitter.events[event]; !ok {
169 | // If the Emitter does not include the event in its
170 | // event map, it has no listeners to Call yet.
171 | emitter.Unlock()
172 | goto ONCES
173 | }
174 |
175 | // Unlock the mutex immediately following the read
176 | // instead of deferring so that listeners registered
177 | // with Once can aquire the mutex for removal.
178 | emitter.Unlock()
179 | emitter.callListeners(listeners, event, arguments...)
180 |
181 | ONCES:
182 | // execute onces
183 | emitter.Lock()
184 | if listeners, ok = emitter.onces[event]; !ok {
185 | emitter.Unlock()
186 | return emitter
187 | }
188 | emitter.Unlock()
189 | emitter.callListeners(listeners, event, arguments...)
190 | // clear executed listeners
191 | emitter.onces[event] = emitter.onces[event][len(listeners):]
192 | return emitter
193 | }
194 |
195 | func (emitter *Emitter) callListeners(listeners []reflect.Value, event interface{}, arguments ...interface{}) {
196 | var wg sync.WaitGroup
197 |
198 | wg.Add(len(listeners))
199 |
200 | for _, fn := range listeners {
201 | go func(fn reflect.Value) {
202 | defer wg.Done()
203 |
204 | // Recover from potential panics, supplying them to a
205 | // RecoveryListener if one has been set, else allowing
206 | // the panic to occur.
207 | if nil != emitter.recoverer {
208 | defer func() {
209 | if r := recover(); nil != r {
210 | err := fmt.Errorf("%v", r)
211 | emitter.recoverer(event, fn.Interface(), err)
212 | }
213 | }()
214 | }
215 |
216 | var values []reflect.Value
217 |
218 | for i := 0; i < len(arguments); i++ {
219 | if arguments[i] == nil {
220 | values = append(values, reflect.New(fn.Type().In(i)).Elem())
221 | } else {
222 | values = append(values, reflect.ValueOf(arguments[i]))
223 | }
224 | }
225 |
226 | fn.Call(values)
227 | }(fn)
228 | }
229 |
230 | wg.Wait()
231 | }
232 |
233 | // RecoverWith sets the listener to call when a panic occurs, recovering from
234 | // panics and attempting to keep the application from crashing.
235 | func (emitter *Emitter) RecoverWith(listener RecoveryListener) *Emitter {
236 | emitter.recoverer = listener
237 | return emitter
238 | }
239 |
240 | // SetMaxListeners sets the maximum number of listeners per
241 | // event for the Emitter. If -1 is passed as the maximum,
242 | // all events may have unlimited listeners. By default, each
243 | // event can have a maximum number of 10 listeners which is
244 | // useful for finding memory leaks.
245 | func (emitter *Emitter) SetMaxListeners(max int) *Emitter {
246 | emitter.Lock()
247 | defer emitter.Unlock()
248 |
249 | emitter.maxListeners = max
250 | return emitter
251 | }
252 |
253 | // GetListenerCount gets count of listeners for a given event.
254 | func (emitter *Emitter) GetListenerCount(event interface{}) (count int) {
255 | emitter.Lock()
256 | if listeners, ok := emitter.events[event]; ok {
257 | count = len(listeners)
258 | }
259 | emitter.Unlock()
260 | return
261 | }
262 |
263 | // NewEmitter returns a new Emitter object, defaulting the
264 | // number of maximum listeners per event to the DefaultMaxListeners
265 | // constant and initializing its events map.
266 | func NewEmitter() (emitter *Emitter) {
267 | emitter = new(Emitter)
268 | emitter.Mutex = new(sync.Mutex)
269 | emitter.events = make(map[interface{}][]reflect.Value)
270 | emitter.maxListeners = DefaultMaxListeners
271 | emitter.onces = make(map[interface{}][]reflect.Value)
272 | return
273 | }
274 |
--------------------------------------------------------------------------------
/example/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/icodeface/grdp"
6 | "github.com/icodeface/grdp/glog"
7 | )
8 |
9 | func main() {
10 | client := grdp.NewClient("192.168.0.3:3889", glog.DEBUG)
11 | err := client.Login("Administrator", "123456")
12 | if err != nil {
13 | fmt.Println("login failed,", err)
14 | } else {
15 | fmt.Println("login success")
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/glog/log.go:
--------------------------------------------------------------------------------
1 | package glog
2 |
3 | import (
4 | "log"
5 | "sync"
6 | )
7 |
8 | var (
9 | logger *log.Logger
10 | level LEVEL
11 | mu sync.Mutex
12 | )
13 |
14 | type LEVEL int
15 |
16 | const (
17 | DEBUG LEVEL = iota
18 | INFO
19 | WARN
20 | ERROR
21 | NONE
22 | )
23 |
24 | func SetLogger(l *log.Logger) {
25 | logger = l
26 | }
27 |
28 | func SetLevel(l LEVEL) {
29 | level = l
30 | }
31 |
32 | func checkLogger() {
33 | if logger == nil && level != NONE {
34 | panic("logger not inited")
35 | }
36 | }
37 |
38 | func Debug(v ...interface{}) {
39 | checkLogger()
40 | if level <= DEBUG {
41 | mu.Lock()
42 | defer mu.Unlock()
43 | logger.SetPrefix("[DEBUG]")
44 | logger.Print(v)
45 | }
46 | }
47 |
48 | func Info(v ...interface{}) {
49 | checkLogger()
50 | if level <= INFO {
51 | mu.Lock()
52 | defer mu.Unlock()
53 | logger.SetPrefix("[INFO]")
54 | logger.Print(v)
55 | }
56 | }
57 |
58 | func Warn(v ...interface{}) {
59 | checkLogger()
60 | if level <= WARN {
61 | mu.Lock()
62 | defer mu.Unlock()
63 | logger.SetPrefix("[WARN]")
64 | logger.Print(v)
65 | }
66 | }
67 |
68 | func Error(v ...interface{}) {
69 | checkLogger()
70 | if level <= ERROR {
71 | mu.Lock()
72 | defer mu.Unlock()
73 | logger.SetPrefix("[ERROR]")
74 | logger.Print(v)
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/icodeface/grdp
2 |
3 | go 1.12
4 |
5 | require (
6 | github.com/icodeface/tls v0.0.0-20190904082144-a3e1fe30543e
7 | github.com/lunixbochs/struc v0.0.0-20190326164542-a9e4041416c2
8 | golang.org/x/crypto v0.0.0-20190909091759-094676da4a83
9 | )
10 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/icodeface/tls v0.0.0-20190904081526-e03692abd1c9 h1:GQupZCLP/Co5jVtI6rdwfgrPE7DOUGvQMrDm2uI4xko=
2 | github.com/icodeface/tls v0.0.0-20190904081526-e03692abd1c9/go.mod h1:VJNHW2GxCtQP/IQtXykBIPBV8maPJ/dHWirVTwm9GwY=
3 | github.com/icodeface/tls v0.0.0-20190904082144-a3e1fe30543e h1:3V+yaobzgt0CfQTbMoTEwDY5qbvrVnRgr96JBZ00Vhw=
4 | github.com/icodeface/tls v0.0.0-20190904082144-a3e1fe30543e/go.mod h1:VJNHW2GxCtQP/IQtXykBIPBV8maPJ/dHWirVTwm9GwY=
5 | github.com/lunixbochs/struc v0.0.0-20190326164542-a9e4041416c2 h1:xvBq0/ARZLqmB57m6jds017I+KtXPcsKBHv6dUUac4A=
6 | github.com/lunixbochs/struc v0.0.0-20190326164542-a9e4041416c2/go.mod h1:iOJu9pApjjmEmNq7PqlA5R9mDu/HMF5EM3llWKX/TyA=
7 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
8 | golang.org/x/crypto v0.0.0-20190909091759-094676da4a83 h1:mgAKeshyNqWKdENOnQsg+8dRTwZFIwFaO3HNl52sweA=
9 | golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
10 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
11 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
12 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
13 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
14 |
--------------------------------------------------------------------------------
/grdp.go:
--------------------------------------------------------------------------------
1 | package grdp
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "github.com/icodeface/grdp/core"
7 | "github.com/icodeface/grdp/glog"
8 | "github.com/icodeface/grdp/protocol/nla"
9 | "github.com/icodeface/grdp/protocol/pdu"
10 | "github.com/icodeface/grdp/protocol/sec"
11 | "github.com/icodeface/grdp/protocol/t125"
12 | "github.com/icodeface/grdp/protocol/tpkt"
13 | "github.com/icodeface/grdp/protocol/x224"
14 | "log"
15 | "net"
16 | "os"
17 | "strings"
18 | "sync"
19 | "time"
20 | )
21 |
22 | type Client struct {
23 | Host string // ip:port
24 | tpkt *tpkt.TPKT
25 | x224 *x224.X224
26 | mcs *t125.MCSClient
27 | sec *sec.Client
28 | pdu *pdu.Client
29 | }
30 |
31 | func NewClient(host string, logLevel glog.LEVEL) *Client {
32 | glog.SetLevel(logLevel)
33 | logger := log.New(os.Stdout, "", 0)
34 | glog.SetLogger(logger)
35 | return &Client{
36 | Host: host,
37 | }
38 | }
39 |
40 | func (g *Client) Login(user, pwd string) error {
41 | conn, err := net.DialTimeout("tcp", g.Host, 3*time.Second)
42 | if err != nil {
43 | return errors.New(fmt.Sprintf("[dial err] %v", err))
44 | }
45 | defer conn.Close()
46 |
47 | domain := strings.Split(g.Host, ":")[0]
48 |
49 | g.tpkt = tpkt.New(core.NewSocketLayer(conn, nla.NewNTLMv2(domain, user, pwd)))
50 | g.x224 = x224.New(g.tpkt)
51 | g.mcs = t125.NewMCSClient(g.x224)
52 | g.sec = sec.NewClient(g.mcs)
53 | g.pdu = pdu.NewClient(g.sec)
54 |
55 | g.sec.SetUser(user)
56 | g.sec.SetPwd(pwd)
57 | g.sec.SetDomain(domain)
58 |
59 | g.tpkt.SetFastPathListener(g.pdu)
60 | g.pdu.SetFastPathSender(g.tpkt)
61 |
62 | g.x224.SetRequestedProtocol(x224.PROTOCOL_SSL | x224.PROTOCOL_HYBRID)
63 |
64 | err = g.x224.Connect()
65 | if err != nil {
66 | return errors.New(fmt.Sprintf("[x224 connect err] %v", err))
67 | }
68 |
69 | wg := &sync.WaitGroup{}
70 | wg.Add(1)
71 |
72 | g.pdu.On("error", func(e error) {
73 | err = e
74 | glog.Error(e)
75 | wg.Done()
76 | }).On("close", func() {
77 | err = errors.New("close")
78 | glog.Info("on close")
79 | wg.Done()
80 | }).On("success", func() {
81 | err = nil
82 | glog.Info("on success")
83 | wg.Done()
84 | }).On("ready", func() {
85 | glog.Info("on ready")
86 | }).On("update", func(rectangles []pdu.BitmapData) {
87 | glog.Info("on update")
88 | })
89 |
90 | wg.Wait()
91 | return err
92 | }
93 |
--------------------------------------------------------------------------------
/protocol/lic/lic.go:
--------------------------------------------------------------------------------
1 | package lic
2 |
3 | import (
4 | "github.com/icodeface/grdp/core"
5 | "io"
6 | )
7 |
8 | const (
9 | LICENSE_REQUEST = 0x01
10 | PLATFORM_CHALLENGE = 0x02
11 | NEW_LICENSE = 0x03
12 | UPGRADE_LICENSE = 0x04
13 | LICENSE_INFO = 0x12
14 | NEW_LICENSE_REQUEST = 0x13
15 | PLATFORM_CHALLENGE_RESPONSE = 0x15
16 | ERROR_ALERT = 0xFF
17 | )
18 |
19 | // error code
20 | const (
21 | ERR_INVALID_SERVER_CERTIFICATE = 0x00000001
22 | ERR_NO_LICENSE = 0x00000002
23 | ERR_INVALID_SCOPE = 0x00000004
24 | ERR_NO_LICENSE_SERVER = 0x00000006
25 | STATUS_VALID_CLIENT = 0x00000007
26 | ERR_INVALID_CLIENT = 0x00000008
27 | ERR_INVALID_PRODUCTID = 0x0000000B
28 | ERR_INVALID_MESSAGE_LEN = 0x0000000C
29 | ERR_INVALID_MAC = 0x00000003
30 | )
31 |
32 | // state transition
33 | const (
34 | ST_TOTAL_ABORT = 0x00000001
35 | ST_NO_TRANSITION = 0x00000002
36 | ST_RESET_PHASE_TO_START = 0x00000003
37 | ST_RESEND_LAST_MESSAGE = 0x00000004
38 | )
39 |
40 | type ErrorMessage struct {
41 | DwErrorCode uint32
42 | DwStateTransaction uint32
43 | Blob []byte
44 | }
45 |
46 | func readErrorMessage(r io.Reader) *ErrorMessage {
47 | m := &ErrorMessage{}
48 | m.DwErrorCode, _ = core.ReadUInt32LE(r)
49 | m.DwStateTransaction, _ = core.ReadUInt32LE(r)
50 | return m
51 | }
52 |
53 | type LicensePacket struct {
54 | BMsgtype uint8
55 | Flag uint8
56 | WMsgSize uint16
57 | LicensingMessage interface{}
58 | }
59 |
60 | func ReadLicensePacket(r io.Reader) *LicensePacket {
61 | l := &LicensePacket{}
62 | l.BMsgtype, _ = core.ReadUInt8(r)
63 | l.Flag, _ = core.ReadUInt8(r)
64 | l.WMsgSize, _ = core.ReadUint16LE(r)
65 |
66 | switch l.BMsgtype {
67 | case ERROR_ALERT:
68 | l.LicensingMessage = readErrorMessage(r)
69 | default:
70 | l.LicensingMessage, _ = core.ReadBytes(int(l.WMsgSize-4), r)
71 | }
72 | return l
73 | }
74 |
--------------------------------------------------------------------------------
/protocol/nla/cssp.go:
--------------------------------------------------------------------------------
1 | package nla
2 |
3 | import (
4 | "encoding/asn1"
5 | "github.com/icodeface/grdp/glog"
6 | )
7 |
8 | type NegoToken struct {
9 | Data []byte `asn1:"explicit,tag:0"`
10 | }
11 |
12 | type TSRequest struct {
13 | Version int `asn1:"explicit,tag:0"`
14 | NegoTokens []NegoToken `asn1:"optional,explicit,tag:1"`
15 | AuthInfo string `asn1:"optional,explicit,tag:2"`
16 | PubKeyAuth string `asn1:"optional,explicit,tag:3"`
17 | ErrorCode int `asn1:"optional,explicit,tag:4"`
18 | }
19 |
20 | type TSCredentials struct {
21 | }
22 |
23 | type TSPasswordCreds struct {
24 | }
25 |
26 | type TSCspDataDetail struct {
27 | }
28 |
29 | type TSSmartCardCreds struct {
30 | }
31 |
32 | type OpenSSLRSAPublicKey struct {
33 | }
34 |
35 | func EncodeDERTRequest(msgs []Message, authInfo string, pubKeyAuth string) []byte {
36 | req := TSRequest{
37 | Version: 2,
38 | NegoTokens: make([]NegoToken, 0),
39 | }
40 |
41 | for _, msg := range msgs {
42 | token := NegoToken{msg.Serialize()}
43 | req.NegoTokens = append(req.NegoTokens, token)
44 | }
45 |
46 | if len(authInfo) > 0 {
47 | // todo
48 | }
49 |
50 | if len(pubKeyAuth) > 0 {
51 | // todo
52 | }
53 |
54 | result, err := asn1.Marshal(req)
55 | if err != nil {
56 | glog.Error(err)
57 | }
58 | return result
59 | }
60 |
61 | func DecodeDERTRequest(s []byte) (*TSRequest, error) {
62 | treq := &TSRequest{}
63 | _, err := asn1.Unmarshal(s, treq)
64 | return treq, err
65 | }
66 |
--------------------------------------------------------------------------------
/protocol/nla/cssp_test.go:
--------------------------------------------------------------------------------
1 | package nla_test
2 |
3 | import (
4 | "encoding/hex"
5 | "github.com/icodeface/grdp/protocol/nla"
6 | "testing"
7 | )
8 |
9 | func TestEncodeDERTRequest(t *testing.T) {
10 | ntlm := nla.NewNTLMv2("", "", "")
11 | result := nla.EncodeDERTRequest([]nla.Message{ntlm.GetNegotiateMessage()}, "", "")
12 | if hex.EncodeToString(result) != "302fa003020102a12830263024a02204204e544c4d53535000010000003582086000000000000000000000000000000000" {
13 | t.Error("not equal")
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/protocol/nla/encode.go:
--------------------------------------------------------------------------------
1 | package nla
2 |
3 | import (
4 | "crypto/hmac"
5 | "crypto/md5"
6 | "crypto/rc4"
7 | "encoding/binary"
8 | "golang.org/x/crypto/md4"
9 | "strings"
10 | "unicode/utf16"
11 | )
12 |
13 | func convertUTF16ToLittleEndianBytes(u []uint16) []byte {
14 | b := make([]byte, 2*len(u))
15 | for index, value := range u {
16 | binary.LittleEndian.PutUint16(b[index*2:], value)
17 | }
18 | return b
19 | }
20 |
21 | // s.encode('utf-16le')
22 | func UnicodeEncode(p string) []byte {
23 | return convertUTF16ToLittleEndianBytes(utf16.Encode([]rune(p)))
24 | }
25 |
26 | func MD4(data []byte) []byte {
27 | h := md4.New()
28 | h.Write(data)
29 | return h.Sum(nil)
30 | }
31 |
32 | func MD5(data []byte) []byte {
33 | h := md5.New()
34 | h.Write(data)
35 | return h.Sum(nil)
36 | }
37 |
38 | func HMAC_MD5(key, data []byte) []byte {
39 | h := hmac.New(md5.New, key)
40 | h.Write(data)
41 | return h.Sum(nil)
42 | }
43 |
44 | // Version 2 of NTLM hash function
45 | func NTOWFv2(password, user, domain string) []byte {
46 | return HMAC_MD5(MD4(UnicodeEncode(password)), UnicodeEncode(strings.ToUpper(user)+domain))
47 | }
48 |
49 | // Same as NTOWFv2
50 | func LMOWFv2(password, user, domain string) []byte {
51 | return NTOWFv2(password, user, domain)
52 | }
53 |
54 | func RC4K(key, src []byte) []byte {
55 | result := make([]byte, len(src))
56 | rc4obj, _ := rc4.NewCipher(key)
57 | rc4obj.XORKeyStream(result, src)
58 | return result
59 | }
60 |
--------------------------------------------------------------------------------
/protocol/nla/encode_test.go:
--------------------------------------------------------------------------------
1 | package nla_test
2 |
3 | import (
4 | "encoding/hex"
5 | "github.com/icodeface/grdp/protocol/nla"
6 | "testing"
7 | )
8 |
9 | func TestNTOWFv2(t *testing.T) {
10 | res := hex.EncodeToString(nla.NTOWFv2("", "", ""))
11 | expected := "f4c1a15dd59d4da9bd595599220d971a"
12 | if res != expected {
13 | t.Error(res, "not equal to", expected)
14 | }
15 |
16 | res = hex.EncodeToString(nla.NTOWFv2("user", "pwd", "dom"))
17 | expected = "652feb8208b3a8a6264c9c5d5b820979"
18 | if res != expected {
19 | t.Error(res, "not equal to", expected)
20 | }
21 | }
22 |
23 | func TestRC4K(t *testing.T) {
24 | key, _ := hex.DecodeString("55638e834ce774c100637f197bc0683f")
25 | src, _ := hex.DecodeString("177d16086dd3f06fa8d594e3bad005b7")
26 | res := hex.EncodeToString(nla.RC4K(key, src))
27 | expected := "f5ab375222707a492bd5a90705d96d1d"
28 | if res != expected {
29 | t.Error(res, "not equal to", expected)
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/protocol/nla/ntlm.go:
--------------------------------------------------------------------------------
1 | package nla
2 |
3 | import (
4 | "bytes"
5 | "crypto/rand"
6 | "github.com/icodeface/grdp/glog"
7 | "github.com/lunixbochs/struc"
8 | "os"
9 | )
10 |
11 | const (
12 | MsvAvEOL = 0x0000
13 | MsvAvNbComputerName = 0x0001
14 | MsvAvNbDomainName = 0x0002
15 | MsvAvDnsComputerName = 0x0003
16 | MsvAvDnsDomainName = 0x0004
17 | MsvAvDnsTreeName = 0x0005
18 | MsvAvFlags = 0x0006
19 | MsvAvTimestamp = 0x0007
20 | MsvAvSingleHost = 0x0008
21 | MsvAvTargetName = 0x0009
22 | MsvChannelBindings = 0x000A
23 | )
24 |
25 | type AVPair struct {
26 | Id uint16 `struc:"little"`
27 | Len uint16 `struc:"little,sizeof=Value"`
28 | Value []byte
29 | }
30 |
31 | const (
32 | NTLMSSP_NEGOTIATE_56 = 0x80000000
33 | NTLMSSP_NEGOTIATE_KEY_EXCH = 0x40000000
34 | NTLMSSP_NEGOTIATE_128 = 0x20000000
35 | NTLMSSP_NEGOTIATE_VERSION = 0x02000000
36 | NTLMSSP_NEGOTIATE_TARGET_INFO = 0x00800000
37 | NTLMSSP_REQUEST_NON_NT_SESSION_KEY = 0x00400000
38 | NTLMSSP_NEGOTIATE_IDENTIFY = 0x00100000
39 | NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY = 0x00080000
40 | NTLMSSP_TARGET_TYPE_SERVER = 0x00020000
41 | NTLMSSP_TARGET_TYPE_DOMAIN = 0x00010000
42 | NTLMSSP_NEGOTIATE_ALWAYS_SIGN = 0x00008000
43 | NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED = 0x00002000
44 | NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED = 0x00001000
45 | NTLMSSP_NEGOTIATE_NTLM = 0x00000200
46 | NTLMSSP_NEGOTIATE_LM_KEY = 0x00000080
47 | NTLMSSP_NEGOTIATE_DATAGRAM = 0x00000040
48 | NTLMSSP_NEGOTIATE_SEAL = 0x00000020
49 | NTLMSSP_NEGOTIATE_SIGN = 0x00000010
50 | NTLMSSP_REQUEST_TARGET = 0x00000004
51 | NTLM_NEGOTIATE_OEM = 0x00000002
52 | NTLMSSP_NEGOTIATE_UNICODE = 0x00000001
53 | )
54 |
55 | type NVersion struct {
56 | ProductMajorVersion uint8
57 | ProductMinorVersion uint8
58 | ProductBuild uint16 `struc:"little"`
59 | Reserved [3]byte
60 | UInt8 uint8
61 | }
62 |
63 | type Message interface {
64 | Serialize() []byte
65 | }
66 |
67 | type NegotiateMessage struct {
68 | Signature [8]byte
69 | MessageType uint32 `struc:"little"`
70 | NegotiateFlags uint32 `struc:"little"`
71 | DomainNameLen uint16 `struc:"little"`
72 | DomainNameMaxLen uint16 `struc:"little"`
73 | DomainNameBufferOffset uint32 `struc:"little"`
74 | WorkstationLen uint16 `struc:"little"`
75 | WorkstationMaxLen uint16 `struc:"little"`
76 | WorkstationBufferOffset uint32 `struc:"little"`
77 | Varsion NVersion
78 | Payload []byte `struc:"skip"`
79 | }
80 |
81 | func NewNegotiateMessage() *NegotiateMessage {
82 | return &NegotiateMessage{
83 | Signature: [8]byte{'N', 'T', 'L', 'M', 'S', 'S', 'P', 0x00},
84 | MessageType: 0x00000001,
85 | }
86 | }
87 |
88 | func (m *NegotiateMessage) Serialize() []byte {
89 | buff := &bytes.Buffer{}
90 | struc.Pack(buff, m)
91 | res := buff.Bytes()
92 | if (m.NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) <= 0 {
93 | res = append(res[0:32], res[40:]...)
94 | }
95 | return res
96 | }
97 |
98 | type ChallengeMessage struct {
99 | Signature [8]byte
100 | MessageType uint32 `struc:"little"`
101 | TargetNameLen uint16 `struc:"little"`
102 | TargetNameMaxLen uint16 `struc:"little"`
103 | TargetNameBufferOffset uint32 `struc:"little"`
104 | NegotiateFlags uint32 `struc:"little"`
105 | ServerChallenge [8]byte
106 | Reserved [8]byte
107 | TargetInfoLen uint16 `struc:"little"`
108 | TargetInfoMaxLen uint16 `struc:"little"`
109 | TargetInfoBufferOffset uint32 `struc:"little"`
110 | Version NVersion
111 | Payload []byte `struc:"skip"`
112 | }
113 |
114 | // total len - payload len
115 | func (m *ChallengeMessage) BaseLen() uint32 {
116 | return 56
117 | }
118 |
119 | func (m *ChallengeMessage) getTargetInfo() []byte {
120 | if m.TargetInfoLen == 0 {
121 | return make([]byte, 0)
122 | }
123 | offset := m.BaseLen()
124 | start := m.TargetInfoBufferOffset - offset
125 | return m.Payload[start : start+uint32(m.TargetInfoLen)]
126 | }
127 |
128 | func (m *ChallengeMessage) Serialize() []byte {
129 | buff := &bytes.Buffer{}
130 | struc.Pack(buff, m)
131 | buff.Write(m.Payload)
132 | return buff.Bytes()
133 | }
134 |
135 | func NewChallengeMessage() *ChallengeMessage {
136 | return &ChallengeMessage{
137 | Signature: [8]byte{'N', 'T', 'L', 'M', 'S', 'S', 'P', 0x00},
138 | MessageType: 0x00000002,
139 | }
140 | }
141 |
142 | type AuthenticateMessage struct {
143 | Signature [8]byte
144 | MessageType uint32 `struc:"little"`
145 | LmChallengeResponseLen uint16 `struc:"little"`
146 | LmChallengeResponseMaxLen uint16 `struc:"little"`
147 | LmChallengeResponseBufferOffset uint32 `struc:"little"`
148 | NtChallengeResponseLen uint16 `struc:"little"`
149 | NtChallengeResponseMaxLen uint16 `struc:"little"`
150 | NtChallengeResponseBufferOffset uint32 `struc:"little"`
151 | DomainNameLen uint16 `struc:"little"`
152 | DomainNameMaxLen uint16 `struc:"little"`
153 | DomainNameBufferOffset uint32 `struc:"little"`
154 | UserNameLen uint16 `struc:"little"`
155 | UserNameMaxLen uint16 `struc:"little"`
156 | UserNameBufferOffset uint32 `struc:"little"`
157 | WorkstationLen uint16 `struc:"little"`
158 | WorkstationMaxLen uint16 `struc:"little"`
159 | WorkstationBufferOffset uint32 `struc:"little"`
160 | EncryptedRandomSessionLen uint16 `struc:"little"`
161 | EncryptedRandomSessionMaxLen uint16 `struc:"little"`
162 | EncryptedRandomSessionBufferOffset uint32 `struc:"little"`
163 | NegotiateFlags uint32 `struc:"little"`
164 | Version NVersion
165 | MIC [16]byte
166 | Payload []byte `struc:"skip"`
167 | }
168 |
169 | func (m *AuthenticateMessage) BaseLen() uint32 {
170 | return 88
171 | }
172 |
173 | func NewAuthenticateMessage(negFlag uint32, domain, user, workstation string,
174 | lmchallResp, ntchallResp, enRandomSessKey []byte) *AuthenticateMessage {
175 | msg := &AuthenticateMessage{
176 | Signature: [8]byte{'N', 'T', 'L', 'M', 'S', 'S', 'P', 0x00},
177 | MessageType: 0x00000003,
178 | NegotiateFlags: negFlag,
179 | }
180 | payloadBuff := &bytes.Buffer{}
181 |
182 | domainBytes := UnicodeEncode(domain)
183 | msg.DomainNameLen = uint16(len(domainBytes))
184 | msg.DomainNameBufferOffset = msg.BaseLen()
185 | payloadBuff.Write(domainBytes)
186 |
187 | userBytes := UnicodeEncode(user)
188 | msg.UserNameLen = uint16(len(userBytes))
189 | msg.UserNameBufferOffset = msg.DomainNameBufferOffset + uint32(msg.DomainNameLen)
190 | payloadBuff.Write(userBytes)
191 |
192 | wsBytes := UnicodeEncode(workstation)
193 | msg.WorkstationLen = uint16(len(wsBytes))
194 | msg.WorkstationBufferOffset = msg.UserNameBufferOffset + uint32(msg.UserNameLen)
195 | payloadBuff.Write(wsBytes)
196 |
197 | msg.LmChallengeResponseLen = uint16(len(lmchallResp))
198 | msg.LmChallengeResponseBufferOffset = msg.WorkstationBufferOffset + uint32(msg.WorkstationLen)
199 | payloadBuff.Write(lmchallResp)
200 |
201 | msg.NtChallengeResponseLen = uint16(len(ntchallResp))
202 | msg.NtChallengeResponseBufferOffset = msg.LmChallengeResponseBufferOffset + uint32(msg.LmChallengeResponseLen)
203 | payloadBuff.Write(ntchallResp)
204 |
205 | msg.EncryptedRandomSessionLen = uint16(len(enRandomSessKey))
206 | msg.EncryptedRandomSessionBufferOffset = msg.NtChallengeResponseBufferOffset + uint32(msg.NtChallengeResponseLen)
207 | payloadBuff.Write(enRandomSessKey)
208 |
209 | msg.Payload = payloadBuff.Bytes()
210 | return msg
211 | }
212 |
213 | func (m *AuthenticateMessage) Serialize() []byte {
214 | buff := &bytes.Buffer{}
215 | struc.Pack(buff, m)
216 | buff.Write(m.Payload)
217 | res := buff.Bytes()
218 | return res
219 | }
220 |
221 | type NTLMv2 struct {
222 | domain string
223 | user string
224 | password string
225 | respKeyNT []byte
226 | respKeyLM []byte
227 | negotiateMessage *NegotiateMessage
228 | challengeMessage *ChallengeMessage
229 | authenticateMessage *AuthenticateMessage
230 | }
231 |
232 | func NewNTLMv2(domain, user, password string) *NTLMv2 {
233 | return &NTLMv2{
234 | domain: domain,
235 | user: user,
236 | password: password,
237 | respKeyNT: NTOWFv2(password, user, domain),
238 | respKeyLM: LMOWFv2(password, user, domain),
239 | }
240 | }
241 |
242 | // generate first handshake messgae
243 | func (n *NTLMv2) GetNegotiateMessage() *NegotiateMessage {
244 | negoMsg := NewNegotiateMessage()
245 | negoMsg.NegotiateFlags = NTLMSSP_NEGOTIATE_KEY_EXCH |
246 | NTLMSSP_NEGOTIATE_128 |
247 | NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY |
248 | NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
249 | NTLMSSP_NEGOTIATE_NTLM |
250 | NTLMSSP_NEGOTIATE_SEAL |
251 | NTLMSSP_NEGOTIATE_SIGN |
252 | NTLMSSP_REQUEST_TARGET |
253 | NTLMSSP_NEGOTIATE_UNICODE
254 | n.negotiateMessage = negoMsg
255 | return n.negotiateMessage
256 | }
257 |
258 | // process NTLMv2 Authenticate hash
259 | func (n *NTLMv2) ComputeResponse(respKeyNT, respKeyLM, serverChallenge, clientChallenge,
260 | timestamp, serverName []byte) (ntChallResp, lmChallResp, SessBaseKey []byte) {
261 |
262 | tempBuff := &bytes.Buffer{}
263 | tempBuff.Write([]byte{0x01, 0x01}) // Responser version, HiResponser version
264 | tempBuff.Write([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
265 | tempBuff.Write(timestamp)
266 | tempBuff.Write(clientChallenge)
267 | tempBuff.Write([]byte{0x00, 0x00, 0x00, 0x00})
268 | tempBuff.Write(serverName)
269 |
270 | ntBuf := bytes.NewBuffer(serverChallenge)
271 | ntBuf.Write(tempBuff.Bytes())
272 | ntProof := HMAC_MD5(respKeyNT, ntBuf.Bytes())
273 |
274 | ntChallResp = make([]byte, 0, len(ntProof)+tempBuff.Len())
275 | ntChallResp = append(ntChallResp, ntProof...)
276 | ntChallResp = append(ntChallResp, tempBuff.Bytes()...)
277 |
278 | lmBuf := bytes.NewBuffer(serverChallenge)
279 | lmBuf.Write(clientChallenge)
280 | lmChallResp = HMAC_MD5(respKeyLM, lmBuf.Bytes())
281 | lmChallResp = append(lmChallResp, clientChallenge...)
282 |
283 | SessBaseKey = HMAC_MD5(respKeyNT, ntProof)
284 | return
285 | }
286 |
287 | func MIC(exportedSessionKey []byte, negotiateMessage, challengeMessage, authenticateMessage Message) []byte {
288 | buff := bytes.Buffer{}
289 | buff.Write(negotiateMessage.Serialize())
290 | buff.Write(challengeMessage.Serialize())
291 | buff.Write(authenticateMessage.Serialize())
292 | return HMAC_MD5(exportedSessionKey, buff.Bytes())
293 | }
294 |
295 | func SIGNKEY(exportedSessionKey []byte, isClient bool) []byte {
296 | buff := bytes.NewBuffer(exportedSessionKey)
297 | if isClient {
298 | buff.WriteString("session key to client-to-server signing key magic constant\x00")
299 | } else {
300 | buff.WriteString("session key to server-to-client signing key magic constant\x00")
301 | }
302 | return MD5(buff.Bytes())
303 | }
304 |
305 | func (n *NTLMv2) GetAuthenticateMessage(s []byte) *AuthenticateMessage {
306 | challengeMsg := &ChallengeMessage{}
307 | err := struc.Unpack(bytes.NewReader(s), challengeMsg)
308 | if err != nil {
309 | glog.Error("read challengeMsg", err)
310 | return nil
311 | }
312 | challengeMsg.Payload = s[challengeMsg.BaseLen():]
313 | n.challengeMessage = challengeMsg
314 |
315 | serverName := challengeMsg.getTargetInfo()
316 | //serverChallenge := n.challengeMessage.ServerChallenge[:]
317 | clientChallenge := make([]byte, 64)
318 | _, err = rand.Read(clientChallenge)
319 | if err != nil {
320 | glog.Error("read clientChallenge", err)
321 | return nil
322 | }
323 |
324 | computeMIC := false
325 | var timestamp []byte
326 | avr := bytes.NewReader(serverName)
327 | for {
328 | av := &AVPair{}
329 | if err = struc.Unpack(avr, av); err != nil {
330 | glog.Error("read av", err)
331 | break
332 | }
333 | if av.Id == MsvAvEOL {
334 | break
335 | }
336 | if av.Id == MsvAvTimestamp {
337 | timestamp = av.Value
338 | computeMIC = true
339 | break
340 | }
341 | }
342 | if timestamp == nil {
343 | glog.Error("todo timestamp not found")
344 | return nil
345 | }
346 |
347 | //ntChallengeResponse, lmChallengeResponse, keyExchangeKey := n.ComputeResponse(
348 | // n.respKeyNT, n.respKeyLM, serverChallenge, clientChallenge, timestamp, serverName)
349 | exportedSessionKey := make([]byte, 128)
350 | rand.Read(exportedSessionKey)
351 | //encryptedRandomSessionKey := RC4K(keyExchangeKey, exportedSessionKey)
352 |
353 | n.authenticateMessage = NewAuthenticateMessage(challengeMsg.NegotiateFlags,
354 | n.domain, n.user, "", nil, nil, nil)
355 |
356 | if computeMIC {
357 | copy(n.authenticateMessage.MIC[:], MIC(exportedSessionKey, n.negotiateMessage, n.challengeMessage, n.authenticateMessage)[:16])
358 | }
359 |
360 | // self._authenticateMessage = createAuthenticationMessage(challengeMessage.NegotiateFlags.value,
361 | // domain, user, NtChallengeResponse, LmChallengeResponse, EncryptedRandomSessionKey, "")
362 |
363 | //jj, _ := json.Marshal(challengeMsg)
364 | //fmt.Println(string(jj))
365 | //
366 | //fmt.Println("Payload", string(challengeMsg.Payload[:]))
367 |
368 | os.Exit(0)
369 |
370 | //
371 | //
372 | //
373 | //n.authenticateMessage = NewAuthenticateMessage()
374 | // todo
375 |
376 | return n.authenticateMessage
377 | }
378 |
--------------------------------------------------------------------------------
/protocol/nla/ntlm_test.go:
--------------------------------------------------------------------------------
1 | package nla_test
2 |
3 | import (
4 | "bytes"
5 | "encoding/hex"
6 | "github.com/icodeface/grdp/protocol/nla"
7 | "github.com/lunixbochs/struc"
8 | "testing"
9 | )
10 |
11 | func TestNewNegotiateMessage(t *testing.T) {
12 | ntlm := nla.NewNTLMv2("", "", "")
13 | negoMsg := ntlm.GetNegotiateMessage()
14 | buff := &bytes.Buffer{}
15 | struc.Pack(buff, negoMsg)
16 |
17 | result := hex.EncodeToString(buff.Bytes())
18 | expected := "4e544c4d535350000100000035820860000000000000000000000000000000000000000000000000"
19 |
20 | if result != expected {
21 | t.Error(result, " not equals to", expected)
22 | }
23 | }
24 |
25 | func TestNTLMv2_ComputeResponse(t *testing.T) {
26 | ntlm := nla.NewNTLMv2("", "", "")
27 |
28 | ResponseKeyNT, _ := hex.DecodeString("39e32c766260586a9036f1ceb04c3007")
29 | ResponseKeyLM, _ := hex.DecodeString("39e32c766260586a9036f1ceb04c3007")
30 | ServerChallenge, _ := hex.DecodeString("adcb9d1c8d4a5ed8")
31 | ClienChallenge, _ := hex.DecodeString("1a78bed8e5d5efa7")
32 | Timestamp, _ := hex.DecodeString("a02f44f01267d501")
33 | ServerName, _ := hex.DecodeString("02001e00570049004e002d00460037005200410041004d004100500034004a00430001001e00570049004e002d00460037005200410041004d004100500034004a00430004001e00570049004e002d00460037005200410041004d004100500034004a00430003001e00570049004e002d00460037005200410041004d004100500034004a00430007000800a02f44f01267d50100000000")
34 |
35 | NtChallengeResponse, LmChallengeResponse, SessionBaseKey := ntlm.ComputeResponse(ResponseKeyNT, ResponseKeyLM, ServerChallenge, ClienChallenge, Timestamp, ServerName)
36 |
37 | ntChallRespExpected := "4e7316531937d2fc91e7230853844b890101000000000000a02f44f01267d5011a78bed8e5d5efa70000000002001e00570049004e002d00460037005200410041004d004100500034004a00430001001e00570049004e002d00460037005200410041004d004100500034004a00430004001e00570049004e002d00460037005200410041004d004100500034004a00430003001e00570049004e002d00460037005200410041004d004100500034004a00430007000800a02f44f01267d50100000000"
38 | lmChallRespExpected := "d4dc6edc0c37dd70f69b5c4f05a615661a78bed8e5d5efa7"
39 | sessBaseKeyExpected := "034009be89a0507b2bd6d28e966e1dab"
40 |
41 | if hex.EncodeToString(NtChallengeResponse) != ntChallRespExpected {
42 | t.Error("NtChallengeResponse incorrect")
43 | }
44 |
45 | if hex.EncodeToString(LmChallengeResponse) != lmChallRespExpected {
46 | t.Error("LmChallengeResponse incorrect")
47 | }
48 |
49 | if hex.EncodeToString(SessionBaseKey) != sessBaseKeyExpected {
50 | t.Error("SessionBaseKey incorrect")
51 | }
52 | }
53 |
54 | func TestSIGNKEY(t *testing.T) {
55 | exportedSessionKey, _ := hex.DecodeString("be32c3c56ea6683200a35329d67880c3")
56 | result := hex.EncodeToString(nla.SIGNKEY(exportedSessionKey, true))
57 | expected := "79b4f9a4113230f378a0af99f784adae"
58 | if result != expected {
59 | t.Error(result, "not equal to", expected)
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/protocol/pdu/caps.go:
--------------------------------------------------------------------------------
1 | package pdu
2 |
3 | import (
4 | "bytes"
5 | "encoding/hex"
6 | "errors"
7 | "fmt"
8 | "github.com/icodeface/grdp/core"
9 | "github.com/icodeface/grdp/glog"
10 | "github.com/icodeface/grdp/protocol/t125/gcc"
11 | "github.com/lunixbochs/struc"
12 | "io"
13 | )
14 |
15 | type CapsType uint16
16 |
17 | const (
18 | CAPSTYPE_GENERAL CapsType = 0x0001
19 | CAPSTYPE_BITMAP = 0x0002
20 | CAPSTYPE_ORDER = 0x0003
21 | CAPSTYPE_BITMAPCACHE = 0x0004
22 | CAPSTYPE_CONTROL = 0x0005
23 | CAPSTYPE_ACTIVATION = 0x0007
24 | CAPSTYPE_POINTER = 0x0008
25 | CAPSTYPE_SHARE = 0x0009
26 | CAPSTYPE_COLORCACHE = 0x000A
27 | CAPSTYPE_SOUND = 0x000C
28 | CAPSTYPE_INPUT = 0x000D
29 | CAPSTYPE_FONT = 0x000E
30 | CAPSTYPE_BRUSH = 0x000F
31 | CAPSTYPE_GLYPHCACHE = 0x0010
32 | CAPSTYPE_OFFSCREENCACHE = 0x0011
33 | CAPSTYPE_BITMAPCACHE_HOSTSUPPORT = 0x0012
34 | CAPSTYPE_BITMAPCACHE_REV2 = 0x0013
35 | CAPSTYPE_VIRTUALCHANNEL = 0x0014
36 | CAPSTYPE_DRAWNINEGRIDCACHE = 0x0015
37 | CAPSTYPE_DRAWGDIPLUS = 0x0016
38 | CAPSTYPE_RAIL = 0x0017
39 | CAPSTYPE_WINDOW = 0x0018
40 | CAPSETTYPE_COMPDESK = 0x0019
41 | CAPSETTYPE_MULTIFRAGMENTUPDATE = 0x001A
42 | CAPSETTYPE_LARGE_POINTER = 0x001B
43 | CAPSETTYPE_SURFACE_COMMANDS = 0x001C
44 | CAPSETTYPE_BITMAP_CODECS = 0x001D
45 | CAPSSETTYPE_FRAME_ACKNOWLEDGE = 0x001E
46 | )
47 |
48 | type MajorType uint16
49 |
50 | const (
51 | OSMAJORTYPE_UNSPECIFIED MajorType = 0x0000
52 | OSMAJORTYPE_WINDOWS = 0x0001
53 | OSMAJORTYPE_OS2 = 0x0002
54 | OSMAJORTYPE_MACINTOSH = 0x0003
55 | OSMAJORTYPE_UNIX = 0x0004
56 | OSMAJORTYPE_IOS = 0x0005
57 | OSMAJORTYPE_OSX = 0x0006
58 | OSMAJORTYPE_ANDROID = 0x0007
59 | )
60 |
61 | type MinorType uint16
62 |
63 | const (
64 | OSMINORTYPE_UNSPECIFIED MinorType = 0x0000
65 | OSMINORTYPE_WINDOWS_31X = 0x0001
66 | OSMINORTYPE_WINDOWS_95 = 0x0002
67 | OSMINORTYPE_WINDOWS_NT = 0x0003
68 | OSMINORTYPE_OS2_V21 = 0x0004
69 | OSMINORTYPE_POWER_PC = 0x0005
70 | OSMINORTYPE_MACINTOSH = 0x0006
71 | OSMINORTYPE_NATIVE_XSERVER = 0x0007
72 | OSMINORTYPE_PSEUDO_XSERVER = 0x0008
73 | OSMINORTYPE_WINDOWS_RT = 0x0009
74 | )
75 |
76 | const (
77 | FASTPATH_OUTPUT_SUPPORTED uint16 = 0x0001
78 | NO_BITMAP_COMPRESSION_HDR = 0x0400
79 | LONG_CREDENTIALS_SUPPORTED = 0x0004
80 | AUTORECONNECT_SUPPORTED = 0x0008
81 | ENC_SALTED_CHECKSUM = 0x0010
82 | )
83 |
84 | type OrderFlag uint16
85 |
86 | const (
87 | NEGOTIATEORDERSUPPORT OrderFlag = 0x0002
88 | ZEROBOUNDSDELTASSUPPORT = 0x0008
89 | COLORINDEXSUPPORT = 0x0020
90 | SOLIDPATTERNBRUSHONLY = 0x0040
91 | ORDERFLAGS_EXTRA_FLAGS = 0x0080
92 | )
93 |
94 | /**
95 | * @see http://msdn.microsoft.com/en-us/library/cc240556.aspx
96 | */
97 | type Order uint8
98 |
99 | const (
100 | TS_NEG_DSTBLT_INDEX Order = 0x00
101 | TS_NEG_PATBLT_INDEX = 0x01
102 | TS_NEG_SCRBLT_INDEX = 0x02
103 | TS_NEG_MEMBLT_INDEX = 0x03
104 | TS_NEG_MEM3BLT_INDEX = 0x04
105 | TS_NEG_DRAWNINEGRID_INDEX = 0x07
106 | TS_NEG_LINETO_INDEX = 0x08
107 | TS_NEG_MULTI_DRAWNINEGRID_INDEX = 0x09
108 | TS_NEG_SAVEBITMAP_INDEX = 0x0B
109 | TS_NEG_MULTIDSTBLT_INDEX = 0x0F
110 | TS_NEG_MULTIPATBLT_INDEX = 0x10
111 | TS_NEG_MULTISCRBLT_INDEX = 0x11
112 | TS_NEG_MULTIOPAQUERECT_INDEX = 0x12
113 | TS_NEG_FAST_INDEX_INDEX = 0x13
114 | TS_NEG_POLYGON_SC_INDEX = 0x14
115 | TS_NEG_POLYGON_CB_INDEX = 0x15
116 | TS_NEG_POLYLINE_INDEX = 0x16
117 | TS_NEG_FAST_GLYPH_INDEX = 0x18
118 | TS_NEG_ELLIPSE_SC_INDEX = 0x19
119 | TS_NEG_ELLIPSE_CB_INDEX = 0x1A
120 | TS_NEG_INDEX_INDEX = 0x1B
121 | )
122 |
123 | type OrderEx uint16
124 |
125 | const (
126 | ORDERFLAGS_EX_CACHE_BITMAP_REV3_SUPPORT OrderEx = 0x0002
127 | ORDERFLAGS_EX_ALTSEC_FRAME_MARKER_SUPPORT = 0x0004
128 | )
129 |
130 | /**
131 | * @see http://msdn.microsoft.com/en-us/library/cc240563.aspx
132 | */
133 |
134 | const (
135 | INPUT_FLAG_SCANCODES uint16 = 0x0001
136 | INPUT_FLAG_MOUSEX = 0x0004
137 | INPUT_FLAG_FASTPATH_INPUT = 0x0008
138 | INPUT_FLAG_UNICODE = 0x0010
139 | INPUT_FLAG_FASTPATH_INPUT2 = 0x0020
140 | INPUT_FLAG_UNUSED1 = 0x0040
141 | INPUT_FLAG_UNUSED2 = 0x0080
142 | TS_INPUT_FLAG_MOUSE_HWHEEL = 0x0100
143 | )
144 |
145 | /**
146 | * @see http://msdn.microsoft.com/en-us/library/cc240564.aspx
147 | */
148 | type BrushSupport uint32
149 |
150 | const (
151 | BRUSH_DEFAULT BrushSupport = 0x00000000
152 | BRUSH_COLOR_8x8 = 0x00000001
153 | BRUSH_COLOR_FULL = 0x00000002
154 | )
155 |
156 | /**
157 | * @see http://msdn.microsoft.com/en-us/library/cc240565.aspx
158 | */
159 | type GlyphSupport uint16
160 |
161 | const (
162 | GLYPH_SUPPORT_NONE GlyphSupport = 0x0000
163 | GLYPH_SUPPORT_PARTIAL = 0x0001
164 | GLYPH_SUPPORT_FULL = 0x0002
165 | GLYPH_SUPPORT_ENCODE = 0x0003
166 | )
167 |
168 | /**
169 | * @see http://msdn.microsoft.com/en-us/library/cc240550.aspx
170 | */
171 | type OffscreenSupportLevel uint32
172 |
173 | const (
174 | OSL_FALSE OffscreenSupportLevel = 0x00000000
175 | OSL_TRUE = 0x00000001
176 | )
177 |
178 | /**
179 | * @see http://msdn.microsoft.com/en-us/library/cc240551.aspx
180 | */
181 | type VirtualChannelCompressionFlag uint32
182 |
183 | const (
184 | VCCAPS_NO_COMPR VirtualChannelCompressionFlag = 0x00000000
185 | VCCAPS_COMPR_SC = 0x00000001
186 | VCCAPS_COMPR_CS_8K = 0x00000002
187 | )
188 |
189 | type SoundFlag uint16
190 |
191 | const (
192 | SOUND_NONE SoundFlag = 0x0000
193 | SOUND_BEEPS_FLAG = 0x0001
194 | )
195 |
196 | type Capability interface {
197 | Type() CapsType
198 | }
199 |
200 | type GeneralCapability struct {
201 | // 010018000100030000020000000015040000000000000000
202 | OSMajorType MajorType `struc:"little"`
203 | OSMinorType MinorType `struc:"little"`
204 | ProtocolVersion uint16 `struc:"little"`
205 | Pad2octetsA uint16 `struc:"little"`
206 | GeneralCompressionTypes uint16 `struc:"little"`
207 | ExtraFlags uint16 `struc:"little"`
208 | UpdateCapabilityFlag uint16 `struc:"little"`
209 | RemoteUnshareFlag uint16 `struc:"little"`
210 | GeneralCompressionLevel uint16 `struc:"little"`
211 | RefreshRectSupport uint8 `struc:"little"`
212 | SuppressOutputSupport uint8 `struc:"little"`
213 | }
214 |
215 | func (*GeneralCapability) Type() CapsType {
216 | return CAPSTYPE_GENERAL
217 | }
218 |
219 | type BitmapCapability struct {
220 | // 02001c00180001000100010000052003000000000100000001000000
221 | PreferredBitsPerPixel gcc.HighColor `struc:"little"`
222 | Receive1BitPerPixel uint16 `struc:"little"`
223 | Receive4BitsPerPixel uint16 `struc:"little"`
224 | Receive8BitsPerPixel uint16 `struc:"little"`
225 | DesktopWidth uint16 `struc:"little"`
226 | DesktopHeight uint16 `struc:"little"`
227 | Pad2octets uint16 `struc:"little"`
228 | DesktopResizeFlag uint16 `struc:"little"`
229 | BitmapCompressionFlag uint16 `struc:"little"`
230 | HighColorFlags uint8 `struc:"little"`
231 | DrawingFlags uint8 `struc:"little"`
232 | MultipleRectangleSupport uint16 `struc:"little"`
233 | Pad2octetsB uint16 `struc:"little"`
234 | }
235 |
236 | func (*BitmapCapability) Type() CapsType {
237 | return CAPSTYPE_BITMAP
238 | }
239 |
240 | type BitmapCacheCapability struct {
241 | // 04002800000000000000000000000000000000000000000000000000000000000000000000000000
242 | Pad1 uint32 `struc:"little"`
243 | Pad2 uint32 `struc:"little"`
244 | Pad3 uint32 `struc:"little"`
245 | Pad4 uint32 `struc:"little"`
246 | Pad5 uint32 `struc:"little"`
247 | Pad6 uint32 `struc:"little"`
248 | Cache0Entries uint16 `struc:"little"`
249 | Cache0MaximumCellSize uint16 `struc:"little"`
250 | Cache1Entries uint16 `struc:"little"`
251 | Cache1MaximumCellSize uint16 `struc:"little"`
252 | Cache2Entries uint16 `struc:"little"`
253 | Cache2MaximumCellSize uint16 `struc:"little"`
254 | }
255 |
256 | func (*BitmapCacheCapability) Type() CapsType {
257 | return CAPSTYPE_BITMAPCACHE
258 | }
259 |
260 | type OrderCapability struct {
261 | // 030058000000000000000000000000000000000000000000010014000000010000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000008403000000000000000000
262 | TerminalDescriptor [16]byte
263 | Pad4octetsA uint32 `struc:"little"`
264 | DesktopSaveXGranularity uint16 `struc:"little"`
265 | DesktopSaveYGranularity uint16 `struc:"little"`
266 | Pad2octetsA uint16 `struc:"little"`
267 | MaximumOrderLevel uint16 `struc:"little"`
268 | NumberFonts uint16 `struc:"little"`
269 | OrderFlags OrderFlag `struc:"little"`
270 | OrderSupport [32]byte
271 | TextFlags uint16 `struc:"little"`
272 | OrderSupportExFlags uint16 `struc:"little"`
273 | Pad4octetsB uint32 `struc:"little"`
274 | DesktopSaveSize uint32 `struc:"little"`
275 | Pad2octetsC uint16 `struc:"little"`
276 | Pad2octetsD uint16 `struc:"little"`
277 | TextANSICodePage uint16 `struc:"little"`
278 | Pad2octetsE uint16 `struc:"little"`
279 | }
280 |
281 | func (*OrderCapability) Type() CapsType {
282 | return CAPSTYPE_ORDER
283 | }
284 |
285 | type PointerCapability struct {
286 | ColorPointerFlag uint16 `struc:"little"`
287 | ColorPointerCacheSize uint16 `struc:"little"`
288 | // old version of rdp doesn't support ...
289 | // PointerCacheSize uint16 `struc:"little"` // only server need
290 | }
291 |
292 | func (*PointerCapability) Type() CapsType {
293 | return CAPSTYPE_POINTER
294 | }
295 |
296 | type InputCapability struct {
297 | // 0d005c001500000009040000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000
298 | Flags uint16 `struc:"little"`
299 | Pad2octetsA uint16 `struc:"little"`
300 | // same value as gcc.ClientCoreSettings.kbdLayout
301 | KeyboardLayout gcc.KeyboardLayout `struc:"little"`
302 | // same value as gcc.ClientCoreSettings.keyboardType
303 | KeyboardType uint32 `struc:"little"`
304 | // same value as gcc.ClientCoreSettings.keyboardSubType
305 | KeyboardSubType uint32 `struc:"little"`
306 | // same value as gcc.ClientCoreSettings.keyboardFnKeys
307 | KeyboardFunctionKey uint32 `struc:"little"`
308 | // same value as gcc.ClientCoreSettingrrs.imeFileName
309 | ImeFileName [64]byte
310 | //need add 0c000000 in the end
311 | }
312 |
313 | func (*InputCapability) Type() CapsType {
314 | return CAPSTYPE_INPUT
315 | }
316 |
317 | type BrushCapability struct {
318 | // 0f00080000000000
319 | SupportLevel BrushSupport `struc:"little"`
320 | }
321 |
322 | func (*BrushCapability) Type() CapsType {
323 | return CAPSTYPE_BRUSH
324 | }
325 |
326 | type cacheEntry struct {
327 | Entries uint16 `struc:"little"`
328 | MaximumCellSize uint16 `struc:"little"`
329 | }
330 |
331 | type GlyphCapability struct {
332 | // 10003400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
333 | GlyphCache [10]cacheEntry `struc:"little"`
334 | FragCache uint32 `struc:"little"`
335 | SupportLevel GlyphSupport `struc:"little"`
336 | Pad2octets uint16 `struc:"little"`
337 | }
338 |
339 | func (*GlyphCapability) Type() CapsType {
340 | return CAPSTYPE_GLYPHCACHE
341 | }
342 |
343 | type OffscreenBitmapCacheCapability struct {
344 | // 11000c000000000000000000
345 | SupportLevel OffscreenSupportLevel `struc:"little"`
346 | CacheSize uint16 `struc:"little"`
347 | CacheEntries uint16 `struc:"little"`
348 | }
349 |
350 | func (*OffscreenBitmapCacheCapability) Type() CapsType {
351 | return CAPSTYPE_OFFSCREENCACHE
352 | }
353 |
354 | type VirtualChannelCapability struct {
355 | // 14000c000000000000000000
356 | Flags VirtualChannelCompressionFlag `struc:"little"`
357 | VCChunkSize uint32 `struc:"little"` // optional
358 | }
359 |
360 | func (*VirtualChannelCapability) Type() CapsType {
361 | return CAPSTYPE_VIRTUALCHANNEL
362 | }
363 |
364 | type SoundCapability struct {
365 | // 0c00080000000000
366 | Flags SoundFlag `struc:"little"`
367 | Pad2octets uint16 `struc:"little"`
368 | }
369 |
370 | func (*SoundCapability) Type() CapsType {
371 | return CAPSTYPE_SOUND
372 | }
373 |
374 | type ControlCapability struct {
375 | ControlFlags uint16 `struc:"little"`
376 | RemoteDetachFlag uint16 `struc:"little"`
377 | ControlInterest uint16 `struc:"little"`
378 | DetachInterest uint16 `struc:"little"`
379 | }
380 |
381 | func (*ControlCapability) Type() CapsType {
382 | return CAPSTYPE_CONTROL
383 | }
384 |
385 | type WindowActivationCapability struct {
386 | HelpKeyFlag uint16 `struc:"little"`
387 | HelpKeyIndexFlag uint16 `struc:"little"`
388 | HelpExtendedKeyFlag uint16 `struc:"little"`
389 | WindowManagerKeyFlag uint16 `struc:"little"`
390 | }
391 |
392 | func (*WindowActivationCapability) Type() CapsType {
393 | return CAPSTYPE_ACTIVATION
394 | }
395 |
396 | type FontCapability struct {
397 | SupportFlags uint16 `struc:"little"`
398 | Pad2octets uint16 `struc:"little"`
399 | }
400 |
401 | func (*FontCapability) Type() CapsType {
402 | return CAPSTYPE_FONT
403 | }
404 |
405 | type ColorCacheCapability struct {
406 | CacheSize uint16 `struc:"little"`
407 | Pad2octets uint16 `struc:"little"`
408 | }
409 |
410 | func (*ColorCacheCapability) Type() CapsType {
411 | return CAPSTYPE_COLORCACHE
412 | }
413 |
414 | type ShareCapability struct {
415 | NodeId uint16 `struc:"little"`
416 | Pad2octets uint16 `struc:"little"`
417 | }
418 |
419 | func (*ShareCapability) Type() CapsType {
420 | return CAPSTYPE_SHARE
421 | }
422 |
423 | type MultiFragmentUpdate struct {
424 | // 1a00080000000000
425 | MaxRequestSize uint32 `struc:"little"`
426 | }
427 |
428 | func (*MultiFragmentUpdate) Type() CapsType {
429 | return CAPSETTYPE_MULTIFRAGMENTUPDATE
430 | }
431 |
432 | // see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpegdi/52635737-d144-4f47-9c88-b48ceaf3efb4
433 |
434 | type DrawGDIPlusCapability struct {
435 | SupportLevel uint32
436 | GdipVersion uint32
437 | CacheLevel uint32
438 | GdipCacheEntries [10]byte
439 | GdipCacheChunkSize [8]byte
440 | GdipImageCacheProperties [6]byte
441 | }
442 |
443 | func (*DrawGDIPlusCapability) Type() CapsType {
444 | return CAPSTYPE_DRAWGDIPLUS
445 | }
446 |
447 | // see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/86507fed-a0ee-4242-b802-237534a8f65e
448 | type BitmapCodec struct {
449 | GUID [16]byte
450 | ID uint8
451 | PropertiesLength uint16 `struc:"little,sizeof=Properties"`
452 | Properties []byte
453 | }
454 |
455 | // see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/408b1878-9f6e-4106-8329-1af42219ba6a
456 | type BitmapCodecS struct {
457 | Count uint8 `struc:"sizeof=Array"`
458 | Array []BitmapCodec
459 | }
460 |
461 | // see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/17e80f50-d163-49de-a23b-fd6456aa472f
462 | type BitmapCodecsCapability struct {
463 | SupportedBitmapCodecs BitmapCodecS // A variable-length field containing a TS_BITMAPCODECS structure (section 2.2.7.2.10.1).
464 | }
465 |
466 | func (*BitmapCodecsCapability) Type() CapsType {
467 | return CAPSETTYPE_BITMAP_CODECS
468 | }
469 |
470 | // see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/fc05c385-46c3-42cb-9ed2-c475a3990e0b
471 | type BitmapCacheHostSupportCapability struct {
472 | CacheVersion uint8
473 | Pad1 uint8
474 | Pad2 uint16
475 | }
476 |
477 | func (*BitmapCacheHostSupportCapability) Type() CapsType {
478 | return CAPSTYPE_BITMAPCACHE_HOSTSUPPORT
479 | }
480 |
481 | // see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/41323437-c753-460e-8108-495a6fdd68a8
482 | type LargePointerCapability struct {
483 | SupportFlags uint16 `struc:"little"`
484 | }
485 |
486 | func (*LargePointerCapability) Type() CapsType {
487 | return CAPSETTYPE_LARGE_POINTER
488 | }
489 |
490 | // see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdperp/36a25e21-25e1-4954-aae8-09aaf6715c79
491 | type RemoteProgramsCapability struct {
492 | RailSupportLevel uint32 `struc:"little"`
493 | }
494 |
495 | func (*RemoteProgramsCapability) Type() CapsType {
496 | return CAPSTYPE_RAIL
497 | }
498 |
499 | // see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdperp/82ec7a69-f7e3-4294-830d-666178b35d15
500 | type WindowListCapability struct {
501 | WndSupportLevel uint32 `struc:"little"`
502 | NumIconCaches uint8
503 | NumIconCacheEntries uint16 `struc:"little"`
504 | }
505 |
506 | func (*WindowListCapability) Type() CapsType {
507 | return CAPSTYPE_WINDOW
508 | }
509 |
510 | // see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/9132002f-f133-4a0f-ba2f-2dc48f1e7f93
511 | type DesktopCompositionCapability struct {
512 | CompDeskSupportLevel uint16 `struc:"little"`
513 | }
514 |
515 | func (*DesktopCompositionCapability) Type() CapsType {
516 | return CAPSETTYPE_COMPDESK
517 | }
518 |
519 | // see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/aa953018-c0a8-4761-bb12-86586c2cd56a
520 | type SurfaceCommandsCapability struct {
521 | CmdFlags uint32 `struc:"little"`
522 | Reserved uint32 `struc:"little"`
523 | }
524 |
525 | func (*SurfaceCommandsCapability) Type() CapsType {
526 | return CAPSETTYPE_SURFACE_COMMANDS
527 | }
528 |
529 | func readCapability(r io.Reader) (Capability, error) {
530 | capType, err := core.ReadUint16LE(r)
531 | if err != nil {
532 | return nil, err
533 | }
534 | capLen, err := core.ReadUint16LE(r)
535 | if err != nil {
536 | return nil, err
537 | }
538 | capBytes, err := core.ReadBytes(int(capLen)-4, r)
539 | if err != nil {
540 | return nil, err
541 | }
542 | capReader := bytes.NewReader(capBytes)
543 |
544 | var c Capability
545 | switch CapsType(capType) {
546 | case CAPSTYPE_GENERAL:
547 | c = &GeneralCapability{}
548 | case CAPSTYPE_BITMAP:
549 | c = &BitmapCapability{}
550 | case CAPSTYPE_ORDER:
551 | c = &OrderCapability{}
552 | case CAPSTYPE_BITMAPCACHE:
553 | c = &BitmapCacheCapability{}
554 | case CAPSTYPE_POINTER:
555 | c = &PointerCapability{}
556 | case CAPSTYPE_INPUT:
557 | c = &InputCapability{}
558 | case CAPSTYPE_BRUSH:
559 | c = &BrushCapability{}
560 | case CAPSTYPE_GLYPHCACHE:
561 | c = &GlyphCapability{}
562 | case CAPSTYPE_OFFSCREENCACHE:
563 | c = &OffscreenBitmapCacheCapability{}
564 | case CAPSTYPE_VIRTUALCHANNEL:
565 | c = &VirtualChannelCapability{}
566 | case CAPSTYPE_SOUND:
567 | c = &SoundCapability{}
568 | case CAPSTYPE_CONTROL:
569 | c = &ControlCapability{}
570 | case CAPSTYPE_ACTIVATION:
571 | c = &WindowActivationCapability{}
572 | case CAPSTYPE_FONT:
573 | c = &FontCapability{}
574 | case CAPSTYPE_COLORCACHE:
575 | c = &ColorCacheCapability{}
576 | case CAPSTYPE_SHARE:
577 | c = &ShareCapability{}
578 | case CAPSETTYPE_MULTIFRAGMENTUPDATE:
579 | c = &MultiFragmentUpdate{}
580 | case CAPSTYPE_DRAWGDIPLUS:
581 | c = &DrawGDIPlusCapability{}
582 | case CAPSETTYPE_BITMAP_CODECS:
583 | c = &BitmapCodecsCapability{}
584 | case CAPSTYPE_BITMAPCACHE_HOSTSUPPORT:
585 | c = &BitmapCacheHostSupportCapability{}
586 | case CAPSETTYPE_LARGE_POINTER:
587 | c = &LargePointerCapability{}
588 | case CAPSTYPE_RAIL:
589 | c = &RemoteProgramsCapability{}
590 | case CAPSTYPE_WINDOW:
591 | c = &WindowListCapability{}
592 | case CAPSETTYPE_COMPDESK:
593 | c = &DesktopCompositionCapability{}
594 | case CAPSETTYPE_SURFACE_COMMANDS:
595 | c = &SurfaceCommandsCapability{}
596 | default:
597 | err := errors.New(fmt.Sprintf("unsupported Capability type 0x%04x", capType))
598 | glog.Error(err)
599 | return nil, err
600 | }
601 | if err := struc.Unpack(capReader, c); err != nil {
602 | glog.Error("Capability unpack error", err, fmt.Sprintf("0x%04x", capType), hex.EncodeToString(capBytes))
603 | return nil, err
604 | }
605 | return c, nil
606 | }
607 |
--------------------------------------------------------------------------------
/protocol/pdu/data.go:
--------------------------------------------------------------------------------
1 | package pdu
2 |
3 | import (
4 | "bytes"
5 | "errors"
6 | "fmt"
7 | "github.com/icodeface/grdp/core"
8 | "github.com/icodeface/grdp/glog"
9 | "github.com/lunixbochs/struc"
10 | "io"
11 | )
12 |
13 | const (
14 | PDUTYPE_DEMANDACTIVEPDU = 0x11
15 | PDUTYPE_CONFIRMACTIVEPDU = 0x13
16 | PDUTYPE_DEACTIVATEALLPDU = 0x16
17 | PDUTYPE_DATAPDU = 0x17
18 | PDUTYPE_SERVER_REDIR_PKT = 0x1A
19 | )
20 |
21 | const (
22 | PDUTYPE2_UPDATE = 0x02
23 | PDUTYPE2_CONTROL = 0x14
24 | PDUTYPE2_POINTER = 0x1B
25 | PDUTYPE2_INPUT = 0x1C
26 | PDUTYPE2_SYNCHRONIZE = 0x1F
27 | PDUTYPE2_REFRESH_RECT = 0x21
28 | PDUTYPE2_PLAY_SOUND = 0x22
29 | PDUTYPE2_SUPPRESS_OUTPUT = 0x23
30 | PDUTYPE2_SHUTDOWN_REQUEST = 0x24
31 | PDUTYPE2_SHUTDOWN_DENIED = 0x25
32 | PDUTYPE2_SAVE_SESSION_INFO = 0x26
33 | PDUTYPE2_FONTLIST = 0x27
34 | PDUTYPE2_FONTMAP = 0x28
35 | PDUTYPE2_SET_KEYBOARD_INDICATORS = 0x29
36 | PDUTYPE2_BITMAPCACHE_PERSISTENT_LIST = 0x2B
37 | PDUTYPE2_BITMAPCACHE_ERROR_PDU = 0x2C
38 | PDUTYPE2_SET_KEYBOARD_IME_STATUS = 0x2D
39 | PDUTYPE2_OFFSCRCACHE_ERROR_PDU = 0x2E
40 | PDUTYPE2_SET_ERROR_INFO_PDU = 0x2F
41 | PDUTYPE2_DRAWNINEGRID_ERROR_PDU = 0x30
42 | PDUTYPE2_DRAWGDIPLUS_ERROR_PDU = 0x31
43 | PDUTYPE2_ARC_STATUS_PDU = 0x32
44 | PDUTYPE2_STATUS_INFO_PDU = 0x36
45 | PDUTYPE2_MONITOR_LAYOUT_PDU = 0x37
46 | )
47 |
48 | const (
49 | CTRLACTION_REQUEST_CONTROL = 0x0001
50 | CTRLACTION_GRANTED_CONTROL = 0x0002
51 | CTRLACTION_DETACH = 0x0003
52 | CTRLACTION_COOPERATE = 0x0004
53 | )
54 |
55 | const (
56 | STREAM_UNDEFINED = 0x00
57 | STREAM_LOW = 0x01
58 | STREAM_MED = 0x02
59 | STREAM_HI = 0x04
60 | )
61 |
62 | const (
63 | FASTPATH_UPDATETYPE_ORDERS = 0x0
64 | FASTPATH_UPDATETYPE_BITMAP = 0x1
65 | FASTPATH_UPDATETYPE_PALETTE = 0x2
66 | FASTPATH_UPDATETYPE_SYNCHRONIZE = 0x3
67 | FASTPATH_UPDATETYPE_SURFCMDS = 0x4
68 | FASTPATH_UPDATETYPE_PTR_NULL = 0x5
69 | FASTPATH_UPDATETYPE_PTR_DEFAULT = 0x6
70 | FASTPATH_UPDATETYPE_PTR_POSITION = 0x8
71 | FASTPATH_UPDATETYPE_COLOR = 0x9
72 | FASTPATH_UPDATETYPE_CACHED = 0xA
73 | FASTPATH_UPDATETYPE_POINTER = 0xB
74 | )
75 |
76 | type ShareDataHeader struct {
77 | SharedId uint32 `struc:"little"`
78 | Padding1 uint8 `struc:"little"`
79 | StreamId uint8 `struc:"little"`
80 | UncompressedLength uint16 `struc:"little"`
81 | PDUType2 uint8 `struc:"little"`
82 | CompressedType uint8 `struc:"little"`
83 | CompressedLength uint16 `struc:"little"`
84 | }
85 |
86 | func NewShareDataHeader(size int, type2 uint8, shareId uint32) *ShareDataHeader {
87 | return &ShareDataHeader{
88 | SharedId: shareId,
89 | PDUType2: type2,
90 | StreamId: STREAM_LOW,
91 | UncompressedLength: uint16(size + 4),
92 | }
93 | }
94 |
95 | type PDUMessage interface {
96 | Type() uint16
97 | Serialize() []byte
98 | }
99 |
100 | type DemandActivePDU struct {
101 | SharedId uint32 `struc:"little"`
102 | LengthSourceDescriptor uint16 `struc:"little,sizeof=SourceDescriptor"`
103 | LengthCombinedCapabilities uint16 `struc:"little"`
104 | SourceDescriptor string `struc:"sizefrom=LengthSourceDescriptor"`
105 | NumberCapabilities uint16 `struc:"little,sizeof=CapabilitySets"`
106 | Pad2Octets uint16 `struc:"little"`
107 | CapabilitySets []Capability `struc:"sizefrom=NumberCapabilities"`
108 | SessionId uint32 `struc:"little"`
109 | }
110 |
111 | func (d *DemandActivePDU) Type() uint16 {
112 | return PDUTYPE_DEMANDACTIVEPDU
113 | }
114 |
115 | func (d *DemandActivePDU) Serialize() []byte {
116 | buff := &bytes.Buffer{}
117 | core.WriteUInt32LE(d.SharedId, buff)
118 | core.WriteUInt16LE(d.LengthSourceDescriptor, buff)
119 | core.WriteUInt16LE(d.LengthCombinedCapabilities, buff)
120 | core.WriteBytes([]byte(d.SourceDescriptor), buff)
121 | core.WriteUInt16LE(uint16(len(d.CapabilitySets)), buff)
122 | core.WriteUInt16LE(d.Pad2Octets, buff)
123 | for _, cap := range d.CapabilitySets {
124 | core.WriteUInt16LE(uint16(cap.Type()), buff)
125 | capBuff := &bytes.Buffer{}
126 | struc.Pack(capBuff, cap)
127 | capBytes := capBuff.Bytes()
128 | core.WriteUInt16LE(uint16(len(capBytes)+4), buff)
129 | core.WriteBytes(capBytes, buff)
130 | }
131 | core.WriteUInt32LE(d.SessionId, buff)
132 | return buff.Bytes()
133 | }
134 |
135 | func readDemandActivePDU(r io.Reader) (*DemandActivePDU, error) {
136 | d := &DemandActivePDU{}
137 | var err error
138 | d.SharedId, err = core.ReadUInt32LE(r)
139 | if err != nil {
140 | return nil, err
141 | }
142 | d.LengthSourceDescriptor, err = core.ReadUint16LE(r)
143 | d.LengthCombinedCapabilities, err = core.ReadUint16LE(r)
144 | sourceDescriptorBytes, err := core.ReadBytes(int(d.LengthSourceDescriptor), r)
145 | if err != nil {
146 | return nil, err
147 | }
148 | d.SourceDescriptor = string(sourceDescriptorBytes)
149 | d.NumberCapabilities, err = core.ReadUint16LE(r)
150 | d.Pad2Octets, err = core.ReadUint16LE(r)
151 | d.CapabilitySets = make([]Capability, 0)
152 | glog.Debug("NumberCapabilities is", d.NumberCapabilities)
153 | for i := 0; i < int(d.NumberCapabilities); i++ {
154 | c, err := readCapability(r)
155 | if err != nil {
156 | return nil, err
157 | }
158 | d.CapabilitySets = append(d.CapabilitySets, c)
159 | }
160 | d.SessionId, err = core.ReadUInt32LE(r)
161 | if err != nil {
162 | return nil, err
163 | }
164 | return d, nil
165 | }
166 |
167 | type ConfirmActivePDU struct {
168 | SharedId uint32 `struc:"little"`
169 | OriginatorId uint16 `struc:"little"`
170 | LengthSourceDescriptor uint16 `struc:"little,sizeof=SourceDescriptor"`
171 | LengthCombinedCapabilities uint16 `struc:"little"`
172 | SourceDescriptor string `struc:"sizefrom=LengthSourceDescriptor"`
173 | NumberCapabilities uint16 `struc:"little,sizeof=CapabilitySets"`
174 | Pad2Octets uint16 `struc:"little"`
175 | CapabilitySets []Capability `struc:"sizefrom=NumberCapabilities"`
176 | }
177 |
178 | func (*ConfirmActivePDU) Type() uint16 {
179 | return PDUTYPE_CONFIRMACTIVEPDU
180 | }
181 |
182 | func (c *ConfirmActivePDU) Serialize() []byte {
183 | buff := &bytes.Buffer{}
184 | core.WriteUInt32LE(c.SharedId, buff)
185 | core.WriteUInt16LE(c.OriginatorId, buff)
186 | core.WriteUInt16LE(uint16(len(c.SourceDescriptor)), buff)
187 |
188 | capsBuff := &bytes.Buffer{}
189 | for _, capa := range c.CapabilitySets {
190 | core.WriteUInt16LE(uint16(capa.Type()), capsBuff)
191 | capBuff := &bytes.Buffer{}
192 | struc.Pack(capBuff, capa)
193 | if capa.Type() == CAPSTYPE_INPUT {
194 | core.WriteBytes([]byte{0x0c, 0x00, 0x00, 0x00}, capBuff)
195 | }
196 | capBytes := capBuff.Bytes()
197 | core.WriteUInt16LE(uint16(len(capBytes)+4), capsBuff)
198 | core.WriteBytes(capBytes, capsBuff)
199 | }
200 | capsBytes := capsBuff.Bytes()
201 |
202 | core.WriteUInt16LE(uint16(2+2+len(capsBytes)), buff)
203 | core.WriteBytes([]byte(c.SourceDescriptor), buff)
204 | core.WriteUInt16LE(uint16(len(c.CapabilitySets)), buff)
205 | core.WriteUInt16LE(c.Pad2Octets, buff)
206 | core.WriteBytes(capsBytes, buff)
207 | return buff.Bytes()
208 | }
209 |
210 | // 9401 => share control header
211 | // 1300 => share control header
212 | // ec03 => share control header
213 | // ea030100 => shareId 66538
214 | // ea03 => OriginatorId
215 | // 0400
216 | // 8001 => LengthCombinedCapabilities
217 | // 72647079
218 | // 0c00 => NumberCapabilities 12
219 | // 0000
220 | // caps below
221 | // 010018000100030000020000000015040000000000000000
222 | // 02001c00180001000100010000052003000000000100000001000000
223 | // 030058000000000000000000000000000000000000000000010014000000010000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000008403000000000000000000
224 | // 04002800000000000000000000000000000000000000000000000000000000000000000000000000
225 | // 0800080000001400
226 | // 0c00080000000000
227 | // 0d005c001500000009040000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000
228 | // 0f00080000000000
229 | // 10003400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
230 | // 11000c000000000000000000
231 | // 14000c000000000000000000
232 | // 1a00080000000000
233 |
234 | func NewConfirmActivePDU() *ConfirmActivePDU {
235 | return &ConfirmActivePDU{
236 | OriginatorId: 0x03EA,
237 | CapabilitySets: make([]Capability, 0),
238 | SourceDescriptor: "rdpy",
239 | }
240 | }
241 |
242 | func readConfirmActivePDU(r io.Reader) (*ConfirmActivePDU, error) {
243 | p := &ConfirmActivePDU{}
244 | var err error
245 | p.SharedId, err = core.ReadUInt32LE(r)
246 | if err != nil {
247 | return nil, err
248 | }
249 | p.OriginatorId, err = core.ReadUint16LE(r)
250 | p.LengthSourceDescriptor, err = core.ReadUint16LE(r)
251 | p.LengthCombinedCapabilities, err = core.ReadUint16LE(r)
252 |
253 | sourceDescriptorBytes, err := core.ReadBytes(int(p.LengthSourceDescriptor), r)
254 | if err != nil {
255 | return nil, err
256 | }
257 | p.SourceDescriptor = string(sourceDescriptorBytes)
258 | p.NumberCapabilities, err = core.ReadUint16LE(r)
259 | p.Pad2Octets, err = core.ReadUint16LE(r)
260 |
261 | p.CapabilitySets = make([]Capability, 0)
262 | for i := 0; i < int(p.NumberCapabilities); i++ {
263 | c, err := readCapability(r)
264 | if err != nil {
265 | return nil, err
266 | }
267 | p.CapabilitySets = append(p.CapabilitySets, c)
268 | }
269 | return p, nil
270 | }
271 |
272 | type DeactiveAllPDU struct {
273 | ShareId uint32 `struc:"little"`
274 | LengthSourceDescriptor uint16 `struc:"little,sizeof=SourceDescriptor"`
275 | SourceDescriptor []byte
276 | }
277 |
278 | func (*DeactiveAllPDU) Type() uint16 {
279 | return PDUTYPE_DEACTIVATEALLPDU
280 | }
281 |
282 | func (d *DeactiveAllPDU) Serialize() []byte {
283 | buff := &bytes.Buffer{}
284 | struc.Pack(buff, d)
285 | return buff.Bytes()
286 | }
287 |
288 | func readDeactiveAllPDU(r io.Reader) (*DeactiveAllPDU, error) {
289 | p := &DeactiveAllPDU{}
290 | err := struc.Unpack(r, p)
291 | return p, err
292 | }
293 |
294 | type DataPDU struct {
295 | Header *ShareDataHeader
296 | Data DataPDUData
297 | }
298 |
299 | func (*DataPDU) Type() uint16 {
300 | return PDUTYPE_DATAPDU
301 | }
302 |
303 | func (d *DataPDU) Serialize() []byte {
304 | buff := &bytes.Buffer{}
305 | struc.Pack(buff, d.Header)
306 | struc.Pack(buff, d.Data)
307 | return buff.Bytes()
308 | }
309 |
310 | func NewDataPDU(data DataPDUData, shareId uint32) *DataPDU {
311 | dataBuff := &bytes.Buffer{}
312 | struc.Pack(dataBuff, data)
313 | return &DataPDU{
314 | Header: NewShareDataHeader(len(dataBuff.Bytes()), data.Type2(), shareId),
315 | Data: data,
316 | }
317 | }
318 |
319 | func readDataPDU(r io.Reader) (*DataPDU, error) {
320 | header := &ShareDataHeader{}
321 | err := struc.Unpack(r, header)
322 | if err != nil {
323 | glog.Error("read data pdu header error", err)
324 | return nil, err
325 | }
326 | var d DataPDUData
327 | switch header.PDUType2 {
328 | case PDUTYPE2_SYNCHRONIZE:
329 | d = &SynchronizeDataPDU{}
330 | case PDUTYPE2_CONTROL:
331 | d = &ControlDataPDU{}
332 | case PDUTYPE2_FONTLIST:
333 | d = &FontListDataPDU{}
334 | case PDUTYPE2_SET_ERROR_INFO_PDU:
335 | d = &ErrorInfoDataPDU{}
336 | case PDUTYPE2_FONTMAP:
337 | d = &FontMapDataPDU{}
338 | default:
339 | err = errors.New(fmt.Sprintf("Unknown data pdu type2 0x%02x", header.PDUType2))
340 | glog.Error(err)
341 | return nil, err
342 | }
343 | err = struc.Unpack(r, d)
344 | if err != nil {
345 | glog.Error("read data pdu data error", err)
346 | return nil, err
347 | }
348 | p := &DataPDU{
349 | Header: header,
350 | Data: d,
351 | }
352 | return p, nil
353 | }
354 |
355 | type DataPDUData interface {
356 | Type2() uint8
357 | }
358 |
359 | type SynchronizeDataPDU struct {
360 | MessageType uint16 `struc:"little"`
361 | TargetUser uint16 `struc:"little"`
362 | }
363 |
364 | func (*SynchronizeDataPDU) Type2() uint8 {
365 | return PDUTYPE2_SYNCHRONIZE
366 | }
367 |
368 | func NewSynchronizeDataPDU(targetUser uint16) *SynchronizeDataPDU {
369 | return &SynchronizeDataPDU{
370 | MessageType: 1,
371 | TargetUser: targetUser,
372 | }
373 | }
374 |
375 | type ControlDataPDU struct {
376 | Action uint16 `struc:"little"`
377 | GrantId uint16 `struc:"little"`
378 | ControlId uint32 `struc:"little"`
379 | }
380 |
381 | func (*ControlDataPDU) Type2() uint8 {
382 | return PDUTYPE2_CONTROL
383 | }
384 |
385 | type FontListDataPDU struct {
386 | NumberFonts uint16 `struc:"little"`
387 | TotalNumFonts uint16 `struc:"little"`
388 | ListFlags uint16 `struc:"little"`
389 | EntrySize uint16 `struc:"little"`
390 | }
391 |
392 | func (*FontListDataPDU) Type2() uint8 {
393 | return PDUTYPE2_FONTLIST
394 | }
395 |
396 | type ErrorInfoDataPDU struct {
397 | ErrorInfo uint32 `struc:"little"`
398 | }
399 |
400 | func (*ErrorInfoDataPDU) Type2() uint8 {
401 | return PDUTYPE2_SET_ERROR_INFO_PDU
402 | }
403 |
404 | type FontMapDataPDU struct {
405 | NumberEntries uint16 `struc:"little"`
406 | TotalNumEntries uint16 `struc:"little"`
407 | MapFlags uint16 `struc:"little"`
408 | EntrySize uint16 `struc:"little"`
409 | }
410 |
411 | func (*FontMapDataPDU) Type2() uint8 {
412 | return PDUTYPE2_FONTMAP
413 | }
414 |
415 | type UpdateData interface {
416 | FastPathUpdateType() uint8
417 | }
418 |
419 | type BitmapCompressedDataHeader struct {
420 | CbCompFirstRowSize uint16 `struc:"little"`
421 | CbCompMainBodySize uint16 `struc:"little"`
422 | CbScanWidth uint16 `struc:"little"`
423 | CbUncompressedSize uint16 `struc:"little"`
424 | }
425 |
426 | type BitmapData struct {
427 | DestLeft uint16 `struc:"little"`
428 | DestTop uint16 `struc:"little"`
429 | DestRight uint16 `struc:"little"`
430 | DestBottom uint16 `struc:"little"`
431 | Width uint16 `struc:"little"`
432 | Height uint16 `struc:"little"`
433 | BitsPerPixel uint16 `struc:"little"`
434 | Flags uint16 `struc:"little"`
435 | BitmapLength uint16 `struc:"little,sizeof=BitmapDataStream"`
436 | BitmapComprHdr *BitmapCompressedDataHeader
437 | BitmapDataStream []byte
438 | }
439 |
440 | type FastPathBitmapUpdateDataPDU struct {
441 | Header uint16 `struc:"little"`
442 | NumberRectangles uint16 `struc:"little,sizeof=Rectangles"`
443 | Rectangles []BitmapData
444 | }
445 |
446 | func (*FastPathBitmapUpdateDataPDU) FastPathUpdateType() uint8 {
447 | return FASTPATH_UPDATETYPE_BITMAP
448 | }
449 |
450 | type FastPathUpdatePDU struct {
451 | UpdateHeader uint8
452 | CompressionFlags uint8
453 | Size uint16
454 | Data UpdateData
455 | }
456 |
457 | func readFastPathUpdatePDU(r io.Reader) (*FastPathUpdatePDU, error) {
458 | f := &FastPathUpdatePDU{}
459 | var err error
460 | f.UpdateHeader, err = core.ReadUInt8(r)
461 | if err != nil {
462 | return nil, err
463 | }
464 | f.CompressionFlags, err = core.ReadUInt8(r)
465 | f.Size, err = core.ReadUint16LE(r)
466 | if err != nil {
467 | return nil, err
468 | }
469 | dataBytes, err := core.ReadBytes(int(f.Size), r)
470 | if err != nil {
471 | return nil, err
472 | }
473 | var d UpdateData
474 | switch f.UpdateHeader & 0xf {
475 | case FASTPATH_UPDATETYPE_BITMAP:
476 | d = &FastPathBitmapUpdateDataPDU{}
477 | default:
478 | glog.Debug("unsupported FastPathUpdatePDU data type", f.UpdateHeader)
479 | d = nil
480 | }
481 | if d != nil {
482 | err = struc.Unpack(bytes.NewReader(dataBytes), d)
483 | if err != nil {
484 | return nil, err
485 | }
486 | }
487 | f.Data = d
488 | return f, nil
489 | }
490 |
491 | type ShareControlHeader struct {
492 | TotalLength uint16 `struc:"little"`
493 | PDUType uint16 `struc:"little"`
494 | PDUSource uint16 `struc:"little"`
495 | }
496 |
497 | type PDU struct {
498 | ShareCtrlHeader *ShareControlHeader
499 | Message PDUMessage
500 | }
501 |
502 | func NewPDU(userId uint16, message PDUMessage) *PDU {
503 | pdu := &PDU{}
504 | pdu.ShareCtrlHeader = &ShareControlHeader{
505 | TotalLength: uint16(len(message.Serialize()) + 6),
506 | PDUType: message.Type(),
507 | PDUSource: userId,
508 | }
509 | pdu.Message = message
510 | return pdu
511 | }
512 |
513 | func readPDU(r io.Reader) (*PDU, error) {
514 | pdu := &PDU{}
515 | var err error
516 | header := &ShareControlHeader{}
517 | err = struc.Unpack(r, header)
518 | if err != nil {
519 | return nil, err
520 | }
521 | pdu.ShareCtrlHeader = header
522 |
523 | var d PDUMessage
524 | switch pdu.ShareCtrlHeader.PDUType {
525 | case PDUTYPE_DEMANDACTIVEPDU:
526 | d, err = readDemandActivePDU(r)
527 | case PDUTYPE_DATAPDU:
528 | d, err = readDataPDU(r)
529 | case PDUTYPE_CONFIRMACTIVEPDU:
530 | d, err = readConfirmActivePDU(r)
531 | case PDUTYPE_DEACTIVATEALLPDU:
532 | d, err = readDeactiveAllPDU(r)
533 | default:
534 | glog.Error("PDU invalid pdu type")
535 | }
536 | if err != nil {
537 | return nil, err
538 | }
539 | pdu.Message = d
540 | return pdu, err
541 | }
542 |
543 | func (p *PDU) serialize() []byte {
544 | buff := &bytes.Buffer{}
545 | struc.Pack(buff, p.ShareCtrlHeader)
546 | core.WriteBytes(p.Message.Serialize(), buff)
547 | return buff.Bytes()
548 | }
549 |
--------------------------------------------------------------------------------
/protocol/pdu/pdu.go:
--------------------------------------------------------------------------------
1 | package pdu
2 |
3 | import (
4 | "bytes"
5 | "encoding/hex"
6 | "fmt"
7 | "github.com/icodeface/grdp/core"
8 | "github.com/icodeface/grdp/emission"
9 | "github.com/icodeface/grdp/glog"
10 | "github.com/icodeface/grdp/protocol/t125/gcc"
11 | )
12 |
13 | type PDULayer struct {
14 | emission.Emitter
15 | transport core.Transport
16 | sharedId uint32
17 | userId uint16
18 | channelId uint16
19 | serverCapabilities map[CapsType]Capability
20 | clientCapabilities map[CapsType]Capability
21 | fastPathSender core.FastPathSender
22 | }
23 |
24 | func NewPDULayer(t core.Transport) *PDULayer {
25 | p := &PDULayer{
26 | Emitter: *emission.NewEmitter(),
27 | transport: t,
28 | sharedId: 0x103EA,
29 | serverCapabilities: map[CapsType]Capability{
30 | CAPSTYPE_GENERAL: &GeneralCapability{
31 | ProtocolVersion: 0x0200,
32 | },
33 | CAPSTYPE_BITMAP: &BitmapCapability{
34 | Receive1BitPerPixel: 0x0001,
35 | Receive4BitsPerPixel: 0x0001,
36 | Receive8BitsPerPixel: 0x0001,
37 | BitmapCompressionFlag: 0x0001,
38 | MultipleRectangleSupport: 0x0001,
39 | },
40 | CAPSTYPE_ORDER: &OrderCapability{
41 | DesktopSaveXGranularity: 1,
42 | DesktopSaveYGranularity: 20,
43 | MaximumOrderLevel: 1,
44 | OrderFlags: NEGOTIATEORDERSUPPORT,
45 | DesktopSaveSize: 480 * 480,
46 | },
47 | CAPSTYPE_POINTER: &PointerCapability{ColorPointerCacheSize: 20},
48 | CAPSTYPE_INPUT: &InputCapability{},
49 | CAPSTYPE_VIRTUALCHANNEL: &VirtualChannelCapability{},
50 | CAPSTYPE_FONT: &FontCapability{SupportFlags: 0x0001},
51 | CAPSTYPE_COLORCACHE: &ColorCacheCapability{CacheSize: 0x0006},
52 | CAPSTYPE_SHARE: &ShareCapability{},
53 | },
54 | clientCapabilities: map[CapsType]Capability{
55 | CAPSTYPE_GENERAL: &GeneralCapability{
56 | ProtocolVersion: 0x0200,
57 | },
58 | CAPSTYPE_BITMAP: &BitmapCapability{
59 | Receive1BitPerPixel: 0x0001,
60 | Receive4BitsPerPixel: 0x0001,
61 | Receive8BitsPerPixel: 0x0001,
62 | BitmapCompressionFlag: 0x0001,
63 | MultipleRectangleSupport: 0x0001,
64 | },
65 | CAPSTYPE_ORDER: &OrderCapability{
66 | DesktopSaveXGranularity: 1,
67 | DesktopSaveYGranularity: 20,
68 | MaximumOrderLevel: 1,
69 | OrderFlags: NEGOTIATEORDERSUPPORT,
70 | DesktopSaveSize: 480 * 480,
71 | },
72 | CAPSTYPE_BITMAPCACHE: &BitmapCacheCapability{},
73 | CAPSTYPE_POINTER: &PointerCapability{ColorPointerCacheSize: 20},
74 | CAPSTYPE_INPUT: &InputCapability{},
75 | CAPSTYPE_BRUSH: &BrushCapability{},
76 | CAPSTYPE_GLYPHCACHE: &GlyphCapability{},
77 | CAPSTYPE_OFFSCREENCACHE: &OffscreenBitmapCacheCapability{},
78 | CAPSTYPE_VIRTUALCHANNEL: &VirtualChannelCapability{},
79 | CAPSTYPE_SOUND: &SoundCapability{},
80 | CAPSETTYPE_MULTIFRAGMENTUPDATE: &MultiFragmentUpdate{},
81 | },
82 | }
83 |
84 | t.On("close", func() {
85 | p.Emit("close")
86 | }).On("error", func(err error) {
87 | p.Emit("error", err)
88 | })
89 | return p
90 | }
91 |
92 | func (p *PDULayer) sendPDU(message PDUMessage) {
93 | pdu := NewPDU(p.userId, message)
94 | p.transport.Write(pdu.serialize())
95 | }
96 |
97 | func (p *PDULayer) sendDataPDU(message DataPDUData) {
98 | dataPdu := NewDataPDU(message, p.sharedId)
99 | p.sendPDU(dataPdu)
100 | }
101 |
102 | func (p *PDULayer) SetFastPathSender(f core.FastPathSender) {
103 | p.fastPathSender = f
104 | }
105 |
106 | type Client struct {
107 | *PDULayer
108 | clientCoreData *gcc.ClientCoreData
109 | }
110 |
111 | func NewClient(t core.Transport) *Client {
112 | c := &Client{
113 | PDULayer: NewPDULayer(t),
114 | }
115 | c.transport.Once("connect", c.connect)
116 | return c
117 | }
118 |
119 | func (c *Client) connect(data *gcc.ClientCoreData, userId uint16, channelId uint16) {
120 | glog.Debug("pdu connect")
121 | c.clientCoreData = data
122 | c.userId = userId
123 | c.channelId = channelId
124 | c.transport.Once("data", c.recvDemandActivePDU)
125 | }
126 |
127 | func (c *Client) recvDemandActivePDU(s []byte) {
128 | glog.Debug("PDU recvDemandActivePDU", hex.EncodeToString(s))
129 | r := bytes.NewReader(s)
130 | pdu, err := readPDU(r)
131 | if err != nil {
132 | glog.Error(err)
133 | return
134 | }
135 | if pdu.ShareCtrlHeader.PDUType != PDUTYPE_DEMANDACTIVEPDU {
136 | glog.Info("PDU ignore message during connection sequence, type is", pdu.ShareCtrlHeader.PDUType)
137 | c.transport.Once("data", c.recvDemandActivePDU)
138 | return
139 | }
140 | c.sharedId = pdu.Message.(*DemandActivePDU).SharedId
141 |
142 | for _, caps := range pdu.Message.(*DemandActivePDU).CapabilitySets {
143 | c.serverCapabilities[caps.Type()] = caps
144 | }
145 |
146 | c.sendConfirmActivePDU()
147 | c.sendClientFinalizeSynchronizePDU()
148 | c.transport.Once("data", c.recvServerSynchronizePDU)
149 | }
150 |
151 | func (c *Client) sendConfirmActivePDU() {
152 | glog.Debug("PDU start sendConfirmActivePDU")
153 | generalCapa := c.clientCapabilities[CAPSTYPE_GENERAL].(*GeneralCapability)
154 | generalCapa.OSMajorType = OSMAJORTYPE_WINDOWS
155 | generalCapa.OSMinorType = OSMINORTYPE_WINDOWS_NT
156 | generalCapa.ExtraFlags = LONG_CREDENTIALS_SUPPORTED | NO_BITMAP_COMPRESSION_HDR | ENC_SALTED_CHECKSUM
157 | //if not self._fastPathSender is None:
158 | generalCapa.ExtraFlags |= FASTPATH_OUTPUT_SUPPORTED
159 |
160 | bitmapCapa := c.clientCapabilities[CAPSTYPE_BITMAP].(*BitmapCapability)
161 | bitmapCapa.PreferredBitsPerPixel = c.clientCoreData.HighColorDepth
162 | bitmapCapa.DesktopWidth = c.clientCoreData.DesktopWidth
163 | bitmapCapa.DesktopHeight = c.clientCoreData.DesktopHeight
164 |
165 | orderCapa := c.clientCapabilities[CAPSTYPE_ORDER].(*OrderCapability)
166 | orderCapa.OrderFlags |= ZEROBOUNDSDELTASSUPPORT
167 |
168 | inputCapa := c.clientCapabilities[CAPSTYPE_INPUT].(*InputCapability)
169 | inputCapa.Flags = INPUT_FLAG_SCANCODES | INPUT_FLAG_MOUSEX | INPUT_FLAG_UNICODE
170 | inputCapa.KeyboardLayout = c.clientCoreData.KbdLayout
171 | inputCapa.KeyboardType = c.clientCoreData.KeyboardType
172 | inputCapa.KeyboardSubType = c.clientCoreData.KeyboardSubType
173 | // inputCapa.KeyboardFunctionKey = c.clientCoreData.KeyboardFnKeys
174 | inputCapa.ImeFileName = c.clientCoreData.ImeFileName
175 |
176 | pdu := NewConfirmActivePDU()
177 | pdu.SharedId = c.sharedId
178 | for _, v := range c.clientCapabilities {
179 | pdu.CapabilitySets = append(pdu.CapabilitySets, v)
180 | }
181 | c.sendPDU(pdu)
182 | }
183 |
184 | func (c *Client) sendClientFinalizeSynchronizePDU() {
185 | glog.Debug("PDU start sendClientFinalizeSynchronizePDU")
186 | c.sendDataPDU(NewSynchronizeDataPDU(c.channelId))
187 | c.sendDataPDU(&ControlDataPDU{Action: CTRLACTION_COOPERATE})
188 | c.sendDataPDU(&ControlDataPDU{Action: CTRLACTION_REQUEST_CONTROL})
189 | c.sendDataPDU(&FontListDataPDU{ListFlags: 0x0003, EntrySize: 0x0032})
190 | }
191 |
192 | func (c *Client) recvServerSynchronizePDU(s []byte) {
193 | glog.Debug("PDU recvServerSynchronizePDU")
194 | r := bytes.NewReader(s)
195 | pdu, err := readPDU(r)
196 | if err != nil {
197 | glog.Error(err)
198 | return
199 | }
200 | dataPdu, ok := pdu.Message.(*DataPDU)
201 | if !ok || dataPdu.Header.PDUType2 != PDUTYPE2_SYNCHRONIZE {
202 | if ok {
203 | glog.Error("recvServerSynchronizePDU ignore datapdu type2", dataPdu.Header.PDUType2)
204 | } else {
205 | glog.Error("recvServerSynchronizePDU ignore message type", pdu.ShareCtrlHeader.PDUType)
206 | }
207 | c.transport.Once("data", c.recvServerSynchronizePDU)
208 | return
209 | }
210 | c.transport.Once("data", c.recvServerControlCooperatePDU)
211 | }
212 |
213 | func (c *Client) recvServerControlCooperatePDU(s []byte) {
214 | glog.Debug("PDU recvServerControlCooperatePDU")
215 | r := bytes.NewReader(s)
216 | pdu, err := readPDU(r)
217 | if err != nil {
218 | glog.Error(err)
219 | return
220 | }
221 | dataPdu, ok := pdu.Message.(*DataPDU)
222 | if !ok || dataPdu.Header.PDUType2 != PDUTYPE2_CONTROL {
223 | if ok {
224 | glog.Error("recvServerControlCooperatePDU ignore datapdu type2", dataPdu.Header.PDUType2)
225 | } else {
226 | glog.Error("recvServerControlCooperatePDU ignore message type", pdu.ShareCtrlHeader.PDUType)
227 | }
228 | c.transport.Once("data", c.recvServerControlCooperatePDU)
229 | return
230 | }
231 | if dataPdu.Data.(*ControlDataPDU).Action != CTRLACTION_COOPERATE {
232 | glog.Error("recvServerControlCooperatePDU ignore action", dataPdu.Data.(*ControlDataPDU).Action)
233 | c.transport.Once("data", c.recvServerControlCooperatePDU)
234 | return
235 | }
236 | c.transport.Once("data", c.recvServerControlGrantedPDU)
237 | }
238 |
239 | func (c *Client) recvServerControlGrantedPDU(s []byte) {
240 | glog.Debug("PDU recvServerControlGrantedPDU")
241 | r := bytes.NewReader(s)
242 | pdu, err := readPDU(r)
243 | if err != nil {
244 | glog.Error(err)
245 | return
246 | }
247 | dataPdu, ok := pdu.Message.(*DataPDU)
248 | if !ok || dataPdu.Header.PDUType2 != PDUTYPE2_CONTROL {
249 | if ok {
250 | glog.Error("recvServerControlGrantedPDU ignore datapdu type2", dataPdu.Header.PDUType2)
251 | } else {
252 | glog.Error("recvServerControlGrantedPDU ignore message type", pdu.ShareCtrlHeader.PDUType)
253 | }
254 | c.transport.Once("data", c.recvServerControlGrantedPDU)
255 | return
256 | }
257 | if dataPdu.Data.(*ControlDataPDU).Action != CTRLACTION_GRANTED_CONTROL {
258 | glog.Error("recvServerControlGrantedPDU ignore action", dataPdu.Data.(*ControlDataPDU).Action)
259 | c.transport.Once("data", c.recvServerControlGrantedPDU)
260 | return
261 | }
262 | c.transport.Once("data", c.recvServerFontMapPDU)
263 | }
264 |
265 | func (c *Client) recvServerFontMapPDU(s []byte) {
266 | glog.Debug("PDU recvServerFontMapPDU")
267 | r := bytes.NewReader(s)
268 | pdu, err := readPDU(r)
269 | if err != nil {
270 | glog.Error(err)
271 | return
272 | }
273 | dataPdu, ok := pdu.Message.(*DataPDU)
274 | if !ok || dataPdu.Header.PDUType2 != PDUTYPE2_FONTMAP {
275 | if ok {
276 | glog.Error("recvServerFontMapPDU ignore datapdu type2", dataPdu.Header.PDUType2)
277 | } else {
278 | glog.Error("recvServerFontMapPDU ignore message type", pdu.ShareCtrlHeader.PDUType)
279 | }
280 | return
281 | }
282 | c.transport.Once("data", c.recvPDU)
283 | c.Emit("ready")
284 | }
285 |
286 | func (c *Client) recvPDU(s []byte) {
287 | fmt.Println("PDU recvPDU", hex.EncodeToString(s))
288 | r := bytes.NewReader(s)
289 | for r.Len() > 0 {
290 | p, err := readPDU(r)
291 | if err != nil {
292 | glog.Error(err)
293 | return
294 | }
295 | if p.ShareCtrlHeader.PDUType == PDUTYPE_DEACTIVATEALLPDU {
296 | c.transport.On("data", c.recvDemandActivePDU)
297 | }
298 | }
299 | }
300 |
301 | func (c *Client) RecvFastPath(secFlag byte, s []byte) {
302 | glog.Debug("PDU RecvFastPath", hex.EncodeToString(s))
303 | r := bytes.NewReader(s)
304 | for r.Len() > 0 {
305 | p, err := readFastPathUpdatePDU(r)
306 | if err != nil {
307 | glog.Error(err)
308 | return
309 | }
310 | if p.UpdateHeader == FASTPATH_UPDATETYPE_BITMAP {
311 | c.Emit("update", p.Data.(*FastPathBitmapUpdateDataPDU).Rectangles)
312 | }
313 | }
314 | }
315 |
--------------------------------------------------------------------------------
/protocol/sec/sec.go:
--------------------------------------------------------------------------------
1 | package sec
2 |
3 | import (
4 | "bytes"
5 | "encoding/hex"
6 | "errors"
7 | "github.com/icodeface/grdp/core"
8 | "github.com/icodeface/grdp/emission"
9 | "github.com/icodeface/grdp/glog"
10 | "github.com/icodeface/grdp/protocol/lic"
11 | "github.com/icodeface/grdp/protocol/t125"
12 | "github.com/icodeface/grdp/protocol/t125/gcc"
13 | "github.com/lunixbochs/struc"
14 | "io"
15 | "unicode/utf16"
16 | )
17 |
18 | /**
19 | * SecurityFlag
20 | * @see http://msdn.microsoft.com/en-us/library/cc240579.aspx
21 | */
22 | const (
23 | EXCHANGE_PKT uint16 = 0x0001
24 | TRANSPORT_REQ = 0x0002
25 | TRANSPORT_RSP = 0x0004
26 | ENCRYPT = 0x0008
27 | RESET_SEQNO = 0x0010
28 | IGNORE_SEQNO = 0x0020
29 | INFO_PKT = 0x0040
30 | LICENSE_PKT = 0x0080
31 | LICENSE_ENCRYPT_CS = 0x0200
32 | LICENSE_ENCRYPT_SC = 0x0200
33 | REDIRECTION_PKT = 0x0400
34 | SECURE_CHECKSUM = 0x0800
35 | AUTODETECT_REQ = 0x1000
36 | AUTODETECT_RSP = 0x2000
37 | HEARTBEAT = 0x4000
38 | FLAGSHI_VALID = 0x8000
39 | )
40 |
41 | const (
42 | INFO_MOUSE uint32 = 0x00000001
43 | INFO_DISABLECTRLALTDEL = 0x00000002
44 | INFO_AUTOLOGON = 0x00000008
45 | INFO_UNICODE = 0x00000010
46 | INFO_MAXIMIZESHELL = 0x00000020
47 | INFO_LOGONNOTIFY = 0x00000040
48 | INFO_COMPRESSION = 0x00000080
49 | INFO_ENABLEWINDOWSKEY = 0x00000100
50 | INFO_REMOTECONSOLEAUDIO = 0x00002000
51 | INFO_FORCE_ENCRYPTED_CS_PDU = 0x00004000
52 | INFO_RAIL = 0x00008000
53 | INFO_LOGONERRORS = 0x00010000
54 | INFO_MOUSE_HAS_WHEEL = 0x00020000
55 | INFO_PASSWORD_IS_SC_PIN = 0x00040000
56 | INFO_NOAUDIOPLAYBACK = 0x00080000
57 | INFO_USING_SAVED_CREDS = 0x00100000
58 | INFO_AUDIOCAPTURE = 0x00200000
59 | INFO_VIDEO_DISABLE = 0x00400000
60 | INFO_CompressionTypeMask = 0x00001E00
61 | )
62 |
63 | const (
64 | AF_INET uint16 = 0x00002
65 | AF_INET6 = 0x0017
66 | )
67 |
68 | const (
69 | PERF_DISABLE_WALLPAPER uint32 = 0x00000001
70 | PERF_DISABLE_FULLWINDOWDRAG = 0x00000002
71 | PERF_DISABLE_MENUANIMATIONS = 0x00000004
72 | PERF_DISABLE_THEMING = 0x00000008
73 | PERF_DISABLE_CURSOR_SHADOW = 0x00000020
74 | PERF_DISABLE_CURSORSETTINGS = 0x00000040
75 | PERF_ENABLE_FONT_SMOOTHING = 0x00000080
76 | PERF_ENABLE_DESKTOP_COMPOSITION = 0x00000100
77 | )
78 |
79 | type RDPExtendedInfo struct {
80 | ClientAddressFamily uint16 `struc:"little"`
81 | CbClientAddress uint16 `struc:"little,sizeof=ClientAddress"`
82 | ClientAddress []byte `struc:"[]byte"`
83 | CbClientDir uint16 `struc:"little,sizeof=ClientDir"`
84 | ClientDir []byte `struc:"[]byte"`
85 | ClientTimeZone []byte `struc:"[172]byte"`
86 | ClientSessionId uint32 `struc:"litttle"`
87 | PerformanceFlags uint32 `struc:"little"`
88 | }
89 |
90 | func NewExtendedInfo() *RDPExtendedInfo {
91 | return &RDPExtendedInfo{
92 | ClientAddressFamily: AF_INET,
93 | ClientAddress: []byte{0, 0},
94 | ClientDir: []byte{0, 0},
95 | ClientTimeZone: make([]byte, 172),
96 | }
97 | }
98 |
99 | type RDPInfo struct {
100 | CodePage uint32
101 | Flag uint32
102 | CbDomain uint16
103 | CbUserName uint16
104 | CbPassword uint16
105 | CbAlternateShell uint16
106 | CbWorkingDir uint16
107 | Domain []byte
108 | UserName []byte
109 | Password []byte
110 | AlternateShell []byte
111 | WorkingDir []byte
112 | ExtendedInfo *RDPExtendedInfo
113 | }
114 |
115 | func NewRDPInfo() *RDPInfo {
116 | info := &RDPInfo{
117 | Flag: INFO_MOUSE | INFO_UNICODE | INFO_LOGONNOTIFY | INFO_LOGONERRORS | INFO_DISABLECTRLALTDEL | INFO_ENABLEWINDOWSKEY,
118 | Domain: []byte{0, 0},
119 | UserName: []byte{0, 0},
120 | Password: []byte{0, 0},
121 | AlternateShell: []byte{0, 0},
122 | WorkingDir: []byte{0, 0},
123 | ExtendedInfo: NewExtendedInfo(),
124 | }
125 | return info
126 | }
127 |
128 | func (o *RDPInfo) Serialize(hasExtended bool) []byte {
129 | buff := &bytes.Buffer{}
130 | core.WriteUInt32LE(o.CodePage, buff) // 0000000
131 | core.WriteUInt32LE(o.Flag, buff) // 0530101
132 | core.WriteUInt16LE(uint16(len(o.Domain)-2), buff) // 001c
133 | core.WriteUInt16LE(uint16(len(o.UserName)-2), buff) // 0008
134 | core.WriteUInt16LE(uint16(len(o.Password)-2), buff) //000c
135 | core.WriteUInt16LE(uint16(len(o.AlternateShell)-2), buff) //0000
136 | core.WriteUInt16LE(uint16(len(o.WorkingDir)-2), buff) //0000
137 | core.WriteBytes(o.Domain, buff)
138 | core.WriteBytes(o.UserName, buff)
139 | core.WriteBytes(o.Password, buff)
140 | core.WriteBytes(o.AlternateShell, buff)
141 | core.WriteBytes(o.WorkingDir, buff)
142 | if hasExtended {
143 | struc.Pack(buff, o.ExtendedInfo)
144 | }
145 | return buff.Bytes()
146 | }
147 |
148 | type SecurityHeader struct {
149 | securityFlag uint16
150 | securityFlagHi uint16
151 | }
152 |
153 | func readSecurityHeader(r io.Reader) *SecurityHeader {
154 | s := &SecurityHeader{}
155 | s.securityFlag, _ = core.ReadUint16LE(r)
156 | s.securityFlagHi, _ = core.ReadUint16LE(r)
157 | return s
158 | }
159 |
160 | type SEC struct {
161 | emission.Emitter
162 | transport core.Transport
163 | info *RDPInfo
164 | machineName string
165 | clientData []interface{}
166 | serverData []interface{}
167 | }
168 |
169 | func NewSEC(t core.Transport) *SEC {
170 | sec := &SEC{
171 | *emission.NewEmitter(),
172 | t,
173 | NewRDPInfo(),
174 | "",
175 | nil,
176 | nil,
177 | }
178 |
179 | t.On("close", func() {
180 | sec.Emit("close")
181 | }).On("error", func(err error) {
182 | sec.Emit("error", err)
183 | })
184 | return sec
185 | }
186 |
187 | func (s *SEC) Read(b []byte) (n int, err error) {
188 | return s.transport.Read(b)
189 | }
190 |
191 | func (s *SEC) Write(b []byte) (n int, err error) {
192 | return s.transport.Write(b)
193 | }
194 |
195 | func (s *SEC) Close() error {
196 | return s.transport.Close()
197 | }
198 |
199 | func (s *SEC) sendFlagged(flag uint16, data []byte) {
200 | glog.Debug("sendFlagged", hex.EncodeToString(data))
201 | buff := &bytes.Buffer{}
202 | core.WriteUInt16LE(flag, buff)
203 | core.WriteUInt16LE(0, buff)
204 | core.WriteBytes(data, buff)
205 | s.transport.Write(buff.Bytes())
206 | }
207 |
208 | type Client struct {
209 | *SEC
210 | userId uint16
211 | channelId uint16
212 | }
213 |
214 | func NewClient(t core.Transport) *Client {
215 | c := &Client{
216 | SEC: NewSEC(t),
217 | }
218 | t.On("connect", c.connect)
219 | return c
220 | }
221 |
222 | func (c *Client) SetUser(user string) {
223 | buff := &bytes.Buffer{}
224 | for _, ch := range utf16.Encode([]rune(user)) {
225 | core.WriteUInt16LE(ch, buff)
226 | }
227 | core.WriteUInt16LE(0, buff)
228 | c.info.UserName = buff.Bytes()
229 | }
230 |
231 | func (c *Client) SetPwd(pwd string) {
232 | buff := &bytes.Buffer{}
233 | for _, ch := range utf16.Encode([]rune(pwd)) {
234 | core.WriteUInt16LE(ch, buff)
235 | }
236 | core.WriteUInt16LE(0, buff)
237 | c.info.Password = buff.Bytes()
238 | }
239 |
240 | func (c *Client) SetDomain(domain string) {
241 | buff := &bytes.Buffer{}
242 | for _, ch := range utf16.Encode([]rune(domain)) {
243 | core.WriteUInt16LE(ch, buff)
244 | }
245 | core.WriteUInt16LE(0, buff)
246 | c.info.Domain = buff.Bytes()
247 | }
248 |
249 | func (c *Client) connect(clientData []interface{}, serverData []interface{}, userId uint16, channels []t125.MCSChannelInfo) {
250 | glog.Debug("sec on connect")
251 | c.clientData = clientData
252 | c.serverData = serverData
253 | c.userId = userId
254 | for _, channel := range channels {
255 | if channel.Name == "global" {
256 | c.channelId = channel.ID
257 | break
258 | }
259 | }
260 | c.sendInfoPkt()
261 | c.transport.Once("global", c.recvLicenceInfo)
262 | }
263 |
264 | func (c *Client) sendInfoPkt() {
265 | c.sendFlagged(INFO_PKT, c.info.Serialize(c.clientData[0].(*gcc.ClientCoreData).RdpVersion == gcc.RDP_VERSION_5_PLUS))
266 | }
267 |
268 | func (c *Client) recvLicenceInfo(s []byte) {
269 | glog.Debug("sec recvLicenceInfo", hex.EncodeToString(s))
270 | r := bytes.NewReader(s)
271 | if (readSecurityHeader(r).securityFlag & LICENSE_PKT) <= 0 {
272 | c.Emit("error", errors.New("NODE_RDP_PROTOCOL_PDU_SEC_BAD_LICENSE_HEADER"))
273 | return
274 | }
275 |
276 | p := lic.ReadLicensePacket(r)
277 |
278 | switch p.BMsgtype {
279 | case lic.NEW_LICENSE:
280 | glog.Info("sec NEW_LICENSE")
281 | c.Emit("success")
282 | goto connect
283 | case lic.ERROR_ALERT:
284 | glog.Info("sec ERROR_ALERT")
285 | message := p.LicensingMessage.(*lic.ErrorMessage)
286 | if message.DwErrorCode == lic.STATUS_VALID_CLIENT && message.DwStateTransaction == lic.ST_NO_TRANSITION {
287 | goto connect
288 | }
289 | goto retry
290 | case lic.LICENSE_REQUEST:
291 | c.sendClientNewLicenseRequest()
292 | goto retry
293 | case lic.PLATFORM_CHALLENGE:
294 | c.sendClientChallengeResponse()
295 | goto retry
296 | default:
297 | glog.Error("Not a valid license packet")
298 | c.Emit("error", errors.New("Not a valid license packet"))
299 | return
300 | }
301 |
302 | connect:
303 | c.transport.On("global", c.recvData)
304 | c.Emit("connect", c.clientData[0].(*gcc.ClientCoreData), c.userId, c.channelId)
305 | return
306 |
307 | retry:
308 | c.transport.Once("global", c.recvLicenceInfo)
309 | return
310 | }
311 |
312 | func (c *Client) sendClientNewLicenseRequest() {
313 | glog.Debug("sec sendClientNewLicenseRequest todo")
314 |
315 | }
316 |
317 | func (c *Client) sendClientChallengeResponse() {
318 | glog.Debug("sec sendClientChallengeResponse todo")
319 | }
320 |
321 | func (c *Client) recvData(s []byte) {
322 | glog.Debug("sec recvData", hex.EncodeToString(s))
323 | c.Emit("data", s)
324 | }
325 |
--------------------------------------------------------------------------------
/protocol/t125/ber/ber.go:
--------------------------------------------------------------------------------
1 | package ber
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "github.com/icodeface/grdp/core"
7 | "io"
8 | )
9 |
10 | const (
11 | CLASS_MASK uint8 = 0xC0
12 | CLASS_UNIV = 0x00
13 | CLASS_APPL = 0x40
14 | CLASS_CTXT = 0x80
15 | CLASS_PRIV = 0xC0
16 | )
17 |
18 | const (
19 | PC_MASK uint8 = 0x20
20 | PC_PRIMITIVE = 0x00
21 | PC_CONSTRUCT = 0x20
22 | )
23 |
24 | const (
25 | TAG_MASK uint8 = 0x1F
26 | TAG_BOOLEAN = 0x01
27 | TAG_INTEGER = 0x02
28 | TAG_BIT_STRING = 0x03
29 | TAG_OCTET_STRING = 0x04
30 | TAG_OBJECT_IDENFIER = 0x06
31 | TAG_ENUMERATED = 0x0A
32 | TAG_SEQUENCE = 0x10
33 | TAG_SEQUENCE_OF = 0x10
34 | )
35 |
36 | func berPC(pc bool) uint8 {
37 | if pc {
38 | return PC_CONSTRUCT
39 | }
40 | return PC_PRIMITIVE
41 | }
42 |
43 | func ReadEnumerated(r io.Reader) (uint8, error) {
44 | if !ReadUniversalTag(TAG_ENUMERATED, false, r) {
45 | return 0, errors.New("invalid ber tag")
46 | }
47 | length, err := ReadLength(r)
48 | if err != nil {
49 | return 0, err
50 | }
51 | if length != 1 {
52 | return 0, errors.New(fmt.Sprintf("enumerate size is wrong, get %v, expect 1", length))
53 | }
54 | return core.ReadUInt8(r)
55 | }
56 |
57 | func ReadUniversalTag(tag uint8, pc bool, r io.Reader) bool {
58 | bb, _ := core.ReadUInt8(r)
59 | return bb == (CLASS_UNIV|berPC(pc))|(TAG_MASK&tag)
60 | }
61 |
62 | func WriteUniversalTag(tag uint8, pc bool, w io.Writer) {
63 | core.WriteUInt8((CLASS_UNIV|berPC(pc))|(TAG_MASK&tag), w)
64 | }
65 |
66 | func ReadLength(r io.Reader) (int, error) {
67 | ret := 0
68 | size, _ := core.ReadUInt8(r)
69 | if size&0x80 > 0 {
70 | size = size &^ 0x80
71 | if size == 1 {
72 | r, err := core.ReadUInt8(r)
73 | if err != nil {
74 | return 0, err
75 | }
76 | ret = int(r)
77 | } else if size == 2 {
78 | r, err := core.ReadUint16BE(r)
79 | if err != nil {
80 | return 0, err
81 | }
82 | ret = int(r)
83 | } else {
84 | return 0, errors.New("BER length may be 1 or 2")
85 | }
86 | } else {
87 | ret = int(size)
88 | }
89 | return ret, nil
90 | }
91 |
92 | func WriteLength(size int, w io.Writer) {
93 | if size > 0x7f {
94 | core.WriteUInt8(0x82, w)
95 | core.WriteUInt16BE(uint16(size), w)
96 | } else {
97 | core.WriteUInt8(uint8(size), w)
98 | }
99 | }
100 |
101 | func ReadInteger(r io.Reader) (int, error) {
102 | if !ReadUniversalTag(TAG_INTEGER, false, r) {
103 | return 0, errors.New("Bad integer tag")
104 | }
105 | size, _ := ReadLength(r)
106 | switch size {
107 | case 1:
108 | num, _ := core.ReadUInt8(r)
109 | return int(num), nil
110 | case 2:
111 | num, _ := core.ReadUint16BE(r)
112 | return int(num), nil
113 | case 3:
114 | integer1, _ := core.ReadUInt8(r)
115 | integer2, _ := core.ReadUint16BE(r)
116 | return int(integer2) + int(integer1<<16), nil
117 | case 4:
118 | num, _ := core.ReadUInt32BE(r)
119 | return int(num), nil
120 | default:
121 | return 0, errors.New("wrong size")
122 | }
123 | }
124 |
125 | func WriteInteger(n int, w io.Writer) {
126 | WriteUniversalTag(TAG_INTEGER, false, w)
127 | if n <= 0xff {
128 | WriteLength(1, w)
129 | core.WriteUInt8(uint8(n), w)
130 | } else if n <= 0xffff {
131 | WriteLength(2, w)
132 | core.WriteUInt16BE(uint16(n), w)
133 | } else {
134 | WriteLength(4, w)
135 | core.WriteUInt32BE(uint32(n), w)
136 | }
137 | }
138 |
139 | func WriteOctetstring(str string, w io.Writer) {
140 | WriteUniversalTag(TAG_OCTET_STRING, false, w)
141 | WriteLength(len(str), w)
142 | core.WriteBytes([]byte(str), w)
143 | }
144 |
145 | func WriteBoolean(b bool, w io.Writer) {
146 | bb := uint8(0)
147 | if b {
148 | bb = uint8(0xff)
149 | }
150 | WriteUniversalTag(TAG_BOOLEAN, false, w)
151 | WriteLength(1, w)
152 | core.WriteUInt8(bb, w)
153 | }
154 |
155 | func ReadApplicationTag(tag uint8, r io.Reader) (int, error) {
156 | bb, _ := core.ReadUInt8(r)
157 | if tag > 30 {
158 | if bb != (CLASS_APPL|PC_CONSTRUCT)|TAG_MASK {
159 | return 0, errors.New("ReadApplicationTag invalid data")
160 | }
161 | bb, _ := core.ReadUInt8(r)
162 | if bb != tag {
163 | return 0, errors.New("ReadApplicationTag bad tag")
164 | }
165 | } else {
166 | if bb != (CLASS_APPL|PC_CONSTRUCT)|(TAG_MASK&tag) {
167 | return 0, errors.New("ReadApplicationTag invalid data2")
168 | }
169 | }
170 | return ReadLength(r)
171 | }
172 |
173 | func WriteApplicationTag(tag uint8, size int, w io.Writer) {
174 | if tag > 30 {
175 | core.WriteUInt8((CLASS_APPL|PC_CONSTRUCT)|TAG_MASK, w)
176 | core.WriteUInt8(tag, w)
177 | WriteLength(size, w)
178 | } else {
179 | core.WriteUInt8((CLASS_APPL|PC_CONSTRUCT)|(TAG_MASK&tag), w)
180 | WriteLength(size, w)
181 | }
182 | }
183 |
184 | func WriteEncodedDomainParams(data []byte, w io.Writer) {
185 | WriteUniversalTag(TAG_SEQUENCE, true, w)
186 | WriteLength(len(data), w)
187 | core.WriteBytes(data, w)
188 | }
189 |
--------------------------------------------------------------------------------
/protocol/t125/gcc/gcc.go:
--------------------------------------------------------------------------------
1 | package gcc
2 |
3 | import (
4 | "bytes"
5 | "github.com/icodeface/grdp/core"
6 | "github.com/icodeface/grdp/glog"
7 | "github.com/icodeface/grdp/protocol/t125/per"
8 | "github.com/lunixbochs/struc"
9 | )
10 |
11 | var t124_02_98_oid = []byte{0, 0, 20, 124, 0, 1}
12 | var h221_cs_key = "Duca"
13 | var h221_sc_key = "McDn"
14 |
15 | /**
16 | * @see http://msdn.microsoft.com/en-us/library/cc240509.aspx
17 | */
18 | type Message uint16
19 |
20 | const (
21 | //server -> client
22 | SC_CORE Message = 0x0C01
23 | SC_SECURITY = 0x0C02
24 | SC_NET = 0x0C03
25 | //client -> server
26 | CS_CORE = 0xC001
27 | CS_SECURITY = 0xC002
28 | CS_NET = 0xC003
29 | CS_CLUSTER = 0xC004
30 | CS_MONITOR = 0xC005
31 | )
32 |
33 | /**
34 | * @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
35 | */
36 | type ColorDepth uint16
37 |
38 | const (
39 | RNS_UD_COLOR_8BPP ColorDepth = 0xCA01
40 | RNS_UD_COLOR_16BPP_555 = 0xCA02
41 | RNS_UD_COLOR_16BPP_565 = 0xCA03
42 | RNS_UD_COLOR_24BPP = 0xCA04
43 | )
44 |
45 | /**
46 | * @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
47 | */
48 | type HighColor uint16
49 |
50 | const (
51 | HIGH_COLOR_4BPP HighColor = 0x0004
52 | HIGH_COLOR_8BPP = 0x0008
53 | HIGH_COLOR_15BPP = 0x000f
54 | HIGH_COLOR_16BPP = 0x0010
55 | HIGH_COLOR_24BPP = 0x0018
56 | )
57 |
58 | /**
59 | * @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
60 | */
61 | type Support uint16
62 |
63 | const (
64 | RNS_UD_24BPP_SUPPORT uint16 = 0x0001
65 | RNS_UD_16BPP_SUPPORT = 0x0002
66 | RNS_UD_15BPP_SUPPORT = 0x0004
67 | RNS_UD_32BPP_SUPPORT = 0x0008
68 | )
69 |
70 | /**
71 | * @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
72 | */
73 | type CapabilityFlag uint16
74 |
75 | const (
76 | RNS_UD_CS_SUPPORT_ERRINFO_PDU uint16 = 0x0001
77 | RNS_UD_CS_WANT_32BPP_SESSION = 0x0002
78 | RNS_UD_CS_SUPPORT_STATUSINFO_PDU = 0x0004
79 | RNS_UD_CS_STRONG_ASYMMETRIC_KEYS = 0x0008
80 | RNS_UD_CS_UNUSED = 0x0010
81 | RNS_UD_CS_VALID_CONNECTION_TYPE = 0x0020
82 | RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU = 0x0040
83 | RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT = 0x0080
84 | RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL = 0x0100
85 | RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE = 0x0200
86 | RNS_UD_CS_SUPPORT_HEARTBEAT_PDU = 0x0400
87 | )
88 |
89 | /**
90 | * @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
91 | */
92 | type ConnectionType uint8
93 |
94 | const (
95 | CONNECTION_TYPE_MODEM ConnectionType = 0x01
96 | CONNECTION_TYPE_BROADBAND_LOW = 0x02
97 | CONNECTION_TYPE_SATELLITEV = 0x03
98 | CONNECTION_TYPE_BROADBAND_HIGH = 0x04
99 | CONNECTION_TYPE_WAN = 0x05
100 | CONNECTION_TYPE_LAN = 0x06
101 | CONNECTION_TYPE_AUTODETECT = 0x07
102 | )
103 |
104 | /**
105 | * @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
106 | */
107 | type VERSION uint32
108 |
109 | const (
110 | RDP_VERSION_4 VERSION = 0x00080001
111 | RDP_VERSION_5_PLUS = 0x00080004
112 | )
113 |
114 | type Sequence uint16
115 |
116 | const (
117 | RNS_UD_SAS_DEL Sequence = 0xAA03
118 | )
119 |
120 | /**
121 | * @see http://msdn.microsoft.com/en-us/library/cc240511.aspx
122 | */
123 | type EncryptionMethod uint32
124 |
125 | const (
126 | ENCRYPTION_FLAG_40BIT uint32 = 0x00000001
127 | ENCRYPTION_FLAG_128BIT = 0x00000002
128 | ENCRYPTION_FLAG_56BIT = 0x00000008
129 | FIPS_ENCRYPTION_FLAG = 0x00000010
130 | )
131 |
132 | /**
133 | * @see http://msdn.microsoft.com/en-us/library/cc240518.aspx
134 | */
135 | type EncryptionLevel uint32
136 |
137 | const (
138 | ENCRYPTION_LEVEL_NONE EncryptionLevel = 0x00000000
139 | ENCRYPTION_LEVEL_LOW = 0x00000001
140 | ENCRYPTION_LEVEL_CLIENT_COMPATIBLE = 0x00000002
141 | ENCRYPTION_LEVEL_HIGH = 0x00000003
142 | ENCRYPTION_LEVEL_FIPS = 0x00000004
143 | )
144 |
145 | /**
146 | * @see http://msdn.microsoft.com/en-us/library/cc240513.aspx
147 | */
148 | type ChannelOptions uint32
149 |
150 | const (
151 | CHANNEL_OPTION_INITIALIZED ChannelOptions = 0x80000000
152 | CHANNEL_OPTION_ENCRYPT_RDP = 0x40000000
153 | CHANNEL_OPTION_ENCRYPT_SC = 0x20000000
154 | CHANNEL_OPTION_ENCRYPT_CS = 0x10000000
155 | CHANNEL_OPTION_PRI_HIGH = 0x08000000
156 | CHANNEL_OPTION_PRI_MED = 0x04000000
157 | CHANNEL_OPTION_PRI_LOW = 0x02000000
158 | CHANNEL_OPTION_COMPRESS_RDP = 0x00800000
159 | CHANNEL_OPTION_COMPRESS = 0x00400000
160 | CHANNEL_OPTION_SHOW_PROTOCOL = 0x00200000
161 | REMOTE_CONTROL_PERSISTENT = 0x00100000
162 | )
163 |
164 | /**
165 | * IBM_101_102_KEYS is the most common keyboard type
166 | */
167 | type KeyboardType uint32
168 |
169 | const (
170 | KT_IBM_PC_XT_83_KEY KeyboardType = 0x00000001
171 | KT_OLIVETTI = 0x00000002
172 | KT_IBM_PC_AT_84_KEY = 0x00000003
173 | KT_IBM_101_102_KEYS = 0x00000004
174 | KT_NOKIA_1050 = 0x00000005
175 | KT_NOKIA_9140 = 0x00000006
176 | KT_JAPANESE = 0x00000007
177 | )
178 |
179 | /**
180 | * @see http://technet.microsoft.com/en-us/library/cc766503%28WS.10%29.aspx
181 | */
182 | type KeyboardLayout uint32
183 |
184 | const (
185 | ARABIC KeyboardLayout = 0x00000401
186 | BULGARIAN = 0x00000402
187 | CHINESE_US_KEYBOARD = 0x00000404
188 | CZECH = 0x00000405
189 | DANISH = 0x00000406
190 | GERMAN = 0x00000407
191 | GREEK = 0x00000408
192 | US = 0x00000409
193 | SPANISH = 0x0000040a
194 | FINNISH = 0x0000040b
195 | FRENCH = 0x0000040c
196 | HEBREW = 0x0000040d
197 | HUNGARIAN = 0x0000040e
198 | ICELANDIC = 0x0000040f
199 | ITALIAN = 0x00000410
200 | JAPANESE = 0x00000411
201 | KOREAN = 0x00000412
202 | DUTCH = 0x00000413
203 | NORWEGIAN = 0x00000414
204 | )
205 |
206 | /**
207 | * @see http://msdn.microsoft.com/en-us/library/cc240521.aspx
208 | */
209 | type CertificateType uint32
210 |
211 | const (
212 | CERT_CHAIN_VERSION_1 CertificateType = 0x00000001
213 | CERT_CHAIN_VERSION_2 = 0x00000002
214 | )
215 |
216 | type ChannelDef struct {
217 | Name [8]byte
218 | Options uint32
219 | }
220 |
221 | type ClientCoreData struct {
222 | RdpVersion VERSION `struc:"uint32,little"`
223 | DesktopWidth uint16 `struc:"little"`
224 | DesktopHeight uint16 `struc:"little"`
225 | ColorDepth ColorDepth `struc:"little"`
226 | SasSequence Sequence `struc:"little"`
227 | KbdLayout KeyboardLayout `struc:"little"`
228 | ClientBuild uint32 `struc:"little"`
229 | ClientName [32]byte `struc:"[32]byte"`
230 | KeyboardType uint32 `struc:"little"`
231 | KeyboardSubType uint32 `struc:"little"`
232 | KeyboardFnKeys uint32 `struc:"little"`
233 | ImeFileName [64]byte `struc:"[64]byte"`
234 | PostBeta2ColorDepth ColorDepth `struc:"little"`
235 | ClientProductId uint16 `struc:"little"`
236 | SerialNumber uint32 `struc:"little"`
237 | HighColorDepth HighColor `struc:"little"`
238 | SupportedColorDepths uint16 `struc:"little"`
239 | EarlyCapabilityFlags uint16 `struc:"little"`
240 | ClientDigProductId [64]byte `struc:"[64]byte"`
241 | ConnectionType uint8 `struc:"uint8"`
242 | Pad1octet uint8 `struc:"uint8"`
243 | ServerSelectedProtocol uint32 `struc:"little"`
244 | }
245 |
246 | func NewClientCoreData() *ClientCoreData {
247 | return &ClientCoreData{
248 | RDP_VERSION_5_PLUS, 1280, 800, RNS_UD_COLOR_8BPP,
249 | RNS_UD_SAS_DEL, US, 3790, [32]byte{'m', 's', 't', 's', 'c'}, KT_IBM_101_102_KEYS,
250 | 0, 12, [64]byte{}, RNS_UD_COLOR_8BPP, 1, 0, HIGH_COLOR_24BPP,
251 | RNS_UD_15BPP_SUPPORT | RNS_UD_16BPP_SUPPORT | RNS_UD_24BPP_SUPPORT | RNS_UD_32BPP_SUPPORT,
252 | RNS_UD_CS_SUPPORT_ERRINFO_PDU, [64]byte{}, 0, 0, 0}
253 | }
254 |
255 | func (data *ClientCoreData) Block() []byte {
256 | buff := &bytes.Buffer{}
257 | core.WriteUInt16LE(CS_CORE, buff) // 01C0
258 | core.WriteUInt16LE(0xd8, buff) // d800
259 | struc.Pack(buff, data)
260 | return buff.Bytes()
261 | }
262 |
263 | type ClientNetworkData struct {
264 | ChannelCount uint32
265 | ChannelDefArray []ChannelDef
266 | }
267 |
268 | func NewClientNetworkData() *ClientNetworkData {
269 | return &ClientNetworkData{}
270 | }
271 |
272 | func (d *ClientNetworkData) Block() []byte {
273 | buff := &bytes.Buffer{}
274 | core.WriteUInt16LE(CS_NET, buff) // type
275 | core.WriteUInt16LE(0x08, buff) // len 8
276 | buff.Write([]byte{0, 0, 0, 0}) // data
277 | return buff.Bytes()
278 | }
279 |
280 | type ClientSecurityData struct {
281 | EncryptionMethods uint32
282 | ExtEncryptionMethods uint32
283 | }
284 |
285 | func NewClientSecurityData() *ClientSecurityData {
286 | return &ClientSecurityData{
287 | ENCRYPTION_FLAG_40BIT | ENCRYPTION_FLAG_56BIT | ENCRYPTION_FLAG_128BIT,
288 | 00}
289 | }
290 |
291 | func (d *ClientSecurityData) Block() []byte {
292 | buff := &bytes.Buffer{}
293 | core.WriteUInt16LE(CS_SECURITY, buff) // type
294 | core.WriteUInt16LE(0x0c, buff) // len 12
295 | core.WriteUInt32LE(d.EncryptionMethods, buff)
296 | core.WriteUInt32LE(d.ExtEncryptionMethods, buff)
297 | return buff.Bytes()
298 | }
299 |
300 | type ServerCoreData struct {
301 | RdpVersion VERSION
302 | ClientRequestedProtocol uint32 //optional
303 | EarlyCapabilityFlags uint32 //optional
304 | raw []byte
305 | }
306 |
307 | func NewServerCoreData() *ServerCoreData {
308 | return &ServerCoreData{
309 | RDP_VERSION_5_PLUS, 0, 0, []byte{}}
310 | }
311 |
312 | func (d *ServerCoreData) Serialize() []byte {
313 | return []byte{}
314 | }
315 |
316 | type ServerNetworkData struct {
317 | ChannelIdArray []uint16
318 | }
319 |
320 | func NewServerNetworkData() *ServerNetworkData {
321 | return &ServerNetworkData{}
322 | }
323 |
324 | type ServerSecurityData struct {
325 | EncryptionMethod uint32
326 | EncryptionLevel uint32
327 | raw []byte
328 | }
329 |
330 | func NewServerSecurityData() *ServerSecurityData {
331 | return &ServerSecurityData{
332 | 0, 0, []byte{}}
333 | }
334 |
335 | func MakeConferenceCreateRequest(userData []byte) []byte {
336 | buff := &bytes.Buffer{}
337 | per.WriteChoice(0, buff) // 00
338 | per.WriteObjectIdentifier(t124_02_98_oid, buff) // 05:00:14:7c:00:01
339 | per.WriteLength(len(userData)+14, buff)
340 | per.WriteChoice(0, buff) // 00
341 | per.WriteSelection(0x08, buff) // 08
342 | per.WriteNumericString("1", 1, buff) // 00 10
343 | per.WritePadding(1, buff) // 00
344 | per.WriteNumberOfSet(1, buff) // 01
345 | per.WriteChoice(0xc0, buff) // c0
346 | per.WriteOctetStream(h221_cs_key, 4, buff) // 00 44:75:63:61
347 | per.WriteOctetStream(string(userData), 0, buff)
348 | return buff.Bytes()
349 | }
350 |
351 | func ReadConferenceCreateResponse(data []byte) []interface{} {
352 | // todo
353 | glog.Debug("ReadConferenceCreateResponse todo")
354 | ret := make([]interface{}, 0)
355 | return ret
356 | }
357 |
--------------------------------------------------------------------------------
/protocol/t125/mcs.go:
--------------------------------------------------------------------------------
1 | package t125
2 |
3 | import (
4 | "bytes"
5 | "encoding/hex"
6 | "errors"
7 | "fmt"
8 | "github.com/icodeface/grdp/core"
9 | "github.com/icodeface/grdp/emission"
10 | "github.com/icodeface/grdp/glog"
11 | "github.com/icodeface/grdp/protocol/t125/ber"
12 | "github.com/icodeface/grdp/protocol/t125/gcc"
13 | "github.com/icodeface/grdp/protocol/t125/per"
14 | "io"
15 | )
16 |
17 | // take idea from https://github.com/Madnikulin50/gordp
18 |
19 | // Multiple Channel Service layer
20 |
21 | type MCSMessage uint8
22 |
23 | const (
24 | MCS_TYPE_CONNECT_INITIAL MCSMessage = 0x65
25 | MCS_TYPE_CONNECT_RESPONSE = 0x66
26 | )
27 |
28 | type MCSDomainPDU uint16
29 |
30 | const (
31 | ERECT_DOMAIN_REQUEST MCSDomainPDU = 1
32 | DISCONNECT_PROVIDER_ULTIMATUM = 8
33 | ATTACH_USER_REQUEST = 10
34 | ATTACH_USER_CONFIRM = 11
35 | CHANNEL_JOIN_REQUEST = 14
36 | CHANNEL_JOIN_CONFIRM = 15
37 | SEND_DATA_REQUEST = 25
38 | SEND_DATA_INDICATION = 26
39 | )
40 |
41 | const (
42 | MCS_GLOBAL_CHANNEL uint16 = 1003
43 | MCS_USERCHANNEL_BASE = 1001
44 | )
45 |
46 | /**
47 | * Format MCS PDULayer header packet
48 | * @param mcsPdu {integer}
49 | * @param options {integer}
50 | * @returns {type.UInt8} headers
51 | */
52 | func writeMCSPDUHeader(mcsPdu MCSDomainPDU, options uint8, w io.Writer) {
53 | core.WriteUInt8((uint8(mcsPdu)<<2)|options, w)
54 | }
55 |
56 | func readMCSPDUHeader(options uint8, mcsPdu MCSDomainPDU) bool {
57 | return (options >> 2) == uint8(mcsPdu)
58 | }
59 |
60 | type DomainParameters struct {
61 | MaxChannelIds int
62 | MaxUserIds int
63 | MaxTokenIds int
64 | NumPriorities int
65 | MinThoughput int
66 | MaxHeight int
67 | MaxMCSPDUsize int
68 | ProtocolVersion int
69 | }
70 |
71 | /**
72 | * @see http://www.itu.int/rec/T-REC-T.125-199802-I/en page 25
73 | * @returns {asn1.univ.Sequence}
74 | */
75 | func NewDomainParameters(
76 | maxChannelIds int,
77 | maxUserIds int,
78 | maxTokenIds int,
79 | numPriorities int,
80 | minThoughput int,
81 | maxHeight int,
82 | maxMCSPDUsize int,
83 | protocolVersion int) *DomainParameters {
84 | return &DomainParameters{maxChannelIds, maxUserIds, maxTokenIds,
85 | numPriorities, minThoughput, maxHeight, maxMCSPDUsize, protocolVersion}
86 | }
87 |
88 | func (d *DomainParameters) BER() []byte {
89 | buff := &bytes.Buffer{}
90 | ber.WriteInteger(d.MaxChannelIds, buff)
91 | ber.WriteInteger(d.MaxUserIds, buff)
92 | ber.WriteInteger(d.MaxTokenIds, buff)
93 | ber.WriteInteger(1, buff)
94 | ber.WriteInteger(0, buff)
95 | ber.WriteInteger(1, buff)
96 | ber.WriteInteger(d.MaxMCSPDUsize, buff)
97 | ber.WriteInteger(2, buff)
98 | return buff.Bytes()
99 | }
100 |
101 | func ReadDomainParameters(r io.Reader) (*DomainParameters, error) {
102 | if !ber.ReadUniversalTag(ber.TAG_SEQUENCE, true, r) {
103 | return nil, errors.New("bad BER tags")
104 | }
105 | d := &DomainParameters{}
106 | ber.ReadLength(r)
107 |
108 | d.MaxChannelIds, _ = ber.ReadInteger(r)
109 | d.MaxUserIds, _ = ber.ReadInteger(r)
110 | d.MaxTokenIds, _ = ber.ReadInteger(r)
111 | ber.ReadInteger(r)
112 | ber.ReadInteger(r)
113 | ber.ReadInteger(r)
114 | d.MaxMCSPDUsize, _ = ber.ReadInteger(r)
115 | ber.ReadInteger(r)
116 | return d, nil
117 | }
118 |
119 | /**
120 | * @see http://www.itu.int/rec/T-REC-T.125-199802-I/en page 25
121 | * @param userData {Buffer}
122 | * @returns {asn1.univ.Sequence}
123 | */
124 | type ConnectInitial struct {
125 | CallingDomainSelector []byte
126 | CalledDomainSelector []byte
127 | UpwardFlag bool
128 | TargetParameters DomainParameters
129 | MinimumParameters DomainParameters
130 | MaximumParameters DomainParameters
131 | UserData []byte
132 | }
133 |
134 | func NewConnectInitial(userData []byte) ConnectInitial {
135 | return ConnectInitial{[]byte{0x1},
136 | []byte{0x1},
137 | true,
138 | *NewDomainParameters(34, 2, 0, 1, 0, 1, 0xffff, 2),
139 | *NewDomainParameters(1, 1, 1, 1, 0, 1, 0x420, 2),
140 | *NewDomainParameters(0xffff, 0xfc17, 0xffff, 1, 0, 1, 0xffff, 2),
141 | userData}
142 | }
143 |
144 | func (c *ConnectInitial) BER() []byte {
145 | buff := &bytes.Buffer{}
146 | ber.WriteOctetstring(string(c.CallingDomainSelector), buff)
147 | ber.WriteOctetstring(string(c.CalledDomainSelector), buff)
148 | ber.WriteBoolean(c.UpwardFlag, buff)
149 | ber.WriteEncodedDomainParams(c.TargetParameters.BER(), buff)
150 | ber.WriteEncodedDomainParams(c.MinimumParameters.BER(), buff)
151 | ber.WriteEncodedDomainParams(c.MaximumParameters.BER(), buff)
152 | ber.WriteOctetstring(string(c.UserData), buff)
153 | return buff.Bytes()
154 | }
155 |
156 | /**
157 | * @see http://www.itu.int/rec/T-REC-T.125-199802-I/en page 25
158 | * @returns {asn1.univ.Sequence}
159 | */
160 |
161 | type ConnectResponse struct {
162 | result uint8
163 | calledConnectId int
164 | domainParameters *DomainParameters
165 | userData []byte
166 | }
167 |
168 | func NewConnectResponse(userData []byte) *ConnectResponse {
169 | return &ConnectResponse{0,
170 | 0,
171 | NewDomainParameters(22, 3, 0, 1, 0, 1, 0xfff8, 2),
172 | userData}
173 | }
174 |
175 | func ReadConnectResponse(r io.Reader) (*ConnectResponse, error) {
176 | c := &ConnectResponse{}
177 | var err error
178 | _, err = ber.ReadApplicationTag(MCS_TYPE_CONNECT_RESPONSE, r)
179 | if err != nil {
180 | return nil, err
181 | }
182 | c.result, err = ber.ReadEnumerated(r)
183 | if err != nil {
184 | return nil, err
185 | }
186 |
187 | c.calledConnectId, err = ber.ReadInteger(r)
188 | c.domainParameters, err = ReadDomainParameters(r)
189 | if err != nil {
190 | return nil, err
191 | }
192 | if !ber.ReadUniversalTag(ber.TAG_OCTET_STRING, false, r) {
193 | return nil, errors.New("invalid expected BER tag")
194 | }
195 | dataLen, _ := ber.ReadLength(r)
196 | c.userData, err = core.ReadBytes(dataLen, r)
197 | return c, err
198 | }
199 |
200 | type MCSChannelInfo struct {
201 | ID uint16
202 | Name string
203 | }
204 |
205 | type MCS struct {
206 | emission.Emitter
207 | transport core.Transport
208 | recvOpCode MCSDomainPDU
209 | sendOpCode MCSDomainPDU
210 | channels []MCSChannelInfo
211 | }
212 |
213 | func NewMCS(t core.Transport, recvOpCode MCSDomainPDU, sendOpCode MCSDomainPDU) *MCS {
214 | m := &MCS{
215 | *emission.NewEmitter(),
216 | t,
217 | recvOpCode,
218 | sendOpCode,
219 | []MCSChannelInfo{{MCS_GLOBAL_CHANNEL, "global"}},
220 | }
221 |
222 | m.transport.On("close", func() {
223 | m.Emit("close")
224 | }).On("error", func(err error) {
225 | m.Emit("error", err)
226 | })
227 | return m
228 | }
229 |
230 | func (x *MCS) Read(b []byte) (n int, err error) {
231 | return x.transport.Read(b)
232 | }
233 |
234 | func (x *MCS) Write(b []byte) (n int, err error) {
235 | return x.transport.Write(b)
236 | }
237 |
238 | func (m *MCS) Close() error {
239 | return m.transport.Close()
240 | }
241 |
242 | type MCSClient struct {
243 | *MCS
244 | clientCoreData *gcc.ClientCoreData
245 | clientNetworkData *gcc.ClientNetworkData
246 | clientSecurityData *gcc.ClientSecurityData
247 |
248 | serverCoreData *gcc.ServerCoreData
249 | serverNetworkData *gcc.ServerNetworkData
250 | serverSecurityData *gcc.ServerSecurityData
251 |
252 | channelsConnected int
253 | userId uint16
254 | }
255 |
256 | func NewMCSClient(t core.Transport) *MCSClient {
257 | c := &MCSClient{
258 | MCS: NewMCS(t, SEND_DATA_INDICATION, SEND_DATA_REQUEST),
259 | clientCoreData: gcc.NewClientCoreData(),
260 | clientNetworkData: gcc.NewClientNetworkData(),
261 | clientSecurityData: gcc.NewClientSecurityData(),
262 | }
263 | c.transport.On("connect", c.connect)
264 | return c
265 | }
266 |
267 | func (c *MCSClient) connect(selectedProtocol uint32) {
268 | glog.Debug("mcs client on connect", selectedProtocol)
269 | c.clientCoreData.ServerSelectedProtocol = selectedProtocol
270 |
271 | // sendConnectInitial
272 | userDataBuff := bytes.Buffer{}
273 | userDataBuff.Write(c.clientCoreData.Block())
274 | userDataBuff.Write(c.clientNetworkData.Block())
275 | userDataBuff.Write(c.clientSecurityData.Block())
276 |
277 | ccReq := gcc.MakeConferenceCreateRequest(userDataBuff.Bytes())
278 | connectInitial := NewConnectInitial(ccReq)
279 | connectInitialBerEncoded := connectInitial.BER()
280 |
281 | dataBuff := &bytes.Buffer{}
282 | ber.WriteApplicationTag(uint8(MCS_TYPE_CONNECT_INITIAL), len(connectInitialBerEncoded), dataBuff)
283 | dataBuff.Write(connectInitialBerEncoded)
284 |
285 | _, err := c.transport.Write(dataBuff.Bytes())
286 | if err != nil {
287 | c.Emit("error", errors.New(fmt.Sprintf("mcs sendConnectInitial write error %v", err)))
288 | return
289 | }
290 | glog.Debug("mcs wait for data event")
291 | c.transport.Once("data", c.recvConnectResponse)
292 | }
293 |
294 | func (c *MCSClient) recvConnectResponse(s []byte) {
295 | glog.Debug("mcs recvConnectResponse", hex.EncodeToString(s))
296 | cResp, err := ReadConnectResponse(bytes.NewReader(s))
297 | if err != nil {
298 | c.Emit("error", errors.New(fmt.Sprintf("ReadConnectResponse %v", err)))
299 | return
300 | }
301 |
302 | // record server gcc block
303 | serverSettings := gcc.ReadConferenceCreateResponse(cResp.userData)
304 | for _, v := range serverSettings {
305 | switch v.(type) {
306 | case gcc.ServerSecurityData:
307 | {
308 | c.serverSecurityData = v.(*gcc.ServerSecurityData)
309 | }
310 | case gcc.ServerCoreData:
311 | {
312 | c.serverCoreData = v.(*gcc.ServerCoreData)
313 | }
314 | case gcc.ServerNetworkData:
315 | {
316 | c.serverNetworkData = v.(*gcc.ServerNetworkData)
317 | }
318 | default:
319 | err := errors.New(fmt.Sprintf("unhandle server gcc block %v %v", v, cResp.userData))
320 | glog.Error(err)
321 | c.Emit("error", err)
322 | return
323 | }
324 | }
325 |
326 | glog.Debug("mcs sendErectDomainRequest")
327 | c.sendErectDomainRequest()
328 |
329 | glog.Debug("mcs sendAttachUserRequest")
330 | c.sendAttachUserRequest()
331 |
332 | c.transport.Once("data", c.recvAttachUserConfirm)
333 | }
334 |
335 | func (c *MCSClient) sendErectDomainRequest() {
336 | buff := &bytes.Buffer{}
337 | writeMCSPDUHeader(ERECT_DOMAIN_REQUEST, 0, buff)
338 | per.WriteInteger(0, buff)
339 | per.WriteInteger(0, buff)
340 | c.transport.Write(buff.Bytes())
341 | }
342 |
343 | func (c *MCSClient) sendAttachUserRequest() {
344 | buff := &bytes.Buffer{}
345 | writeMCSPDUHeader(ATTACH_USER_REQUEST, 0, buff)
346 | c.transport.Write(buff.Bytes())
347 | }
348 |
349 | func (c *MCSClient) recvAttachUserConfirm(s []byte) {
350 | glog.Debug("mcs recvAttachUserConfirm", hex.EncodeToString(s))
351 | r := bytes.NewReader(s)
352 |
353 | option, err := core.ReadUInt8(r)
354 | if err != nil {
355 | c.Emit("error", err)
356 | return
357 | }
358 |
359 | if !readMCSPDUHeader(option, ATTACH_USER_CONFIRM) {
360 | c.Emit("error", errors.New("NODE_RDP_PROTOCOL_T125_MCS_BAD_HEADER"))
361 | return
362 | }
363 |
364 | e, err := per.ReadEnumerates(r)
365 | if err != nil {
366 | c.Emit("error", err)
367 | return
368 | }
369 | if e != 0 {
370 | c.Emit("error", errors.New("NODE_RDP_PROTOCOL_T125_MCS_SERVER_REJECT_USER'"))
371 | return
372 | }
373 |
374 | userId, _ := per.ReadInteger16(r)
375 | userId += MCS_USERCHANNEL_BASE
376 | c.userId = userId
377 |
378 | c.channels = append(c.channels, MCSChannelInfo{userId, "user"})
379 | c.connectChannels()
380 | }
381 |
382 | func (c *MCSClient) connectChannels() {
383 | glog.Debug("mcs connectChannels")
384 | if c.channelsConnected == len(c.channels) {
385 | c.transport.On("data", c.recvData)
386 | // send client and sever gcc informations callback to sec
387 | clientData := make([]interface{}, 0)
388 | clientData = append(clientData, c.clientCoreData)
389 | clientData = append(clientData, c.clientSecurityData)
390 | clientData = append(clientData, c.clientNetworkData)
391 |
392 | serverData := make([]interface{}, 0)
393 | serverData = append(serverData, c.serverCoreData)
394 | serverData = append(serverData, c.serverSecurityData)
395 | glog.Debug("msc connectChannels callback to sec")
396 | c.Emit("connect", clientData, serverData, c.userId, c.channels)
397 | return
398 | }
399 |
400 | // sendChannelJoinRequest
401 | c.sendChannelJoinRequest(c.channels[c.channelsConnected].ID)
402 | c.channelsConnected += 1
403 | c.transport.Once("data", c.recvChannelJoinConfirm)
404 | }
405 |
406 | func (c *MCSClient) sendChannelJoinRequest(channelId uint16) {
407 | glog.Debug("mcs sendChannelJoinRequest")
408 | buff := &bytes.Buffer{}
409 | writeMCSPDUHeader(CHANNEL_JOIN_REQUEST, 0, buff)
410 | per.WriteInteger16(c.userId-MCS_USERCHANNEL_BASE, buff)
411 | per.WriteInteger16(channelId, buff)
412 | c.transport.Write(buff.Bytes())
413 | }
414 |
415 | func (c *MCSClient) recvData(s []byte) {
416 | glog.Debug("msc on data recvData")
417 |
418 | r := bytes.NewReader(s)
419 | option, err := core.ReadUInt8(r)
420 | if err != nil {
421 | c.Emit("error", err)
422 | return
423 | }
424 |
425 | if readMCSPDUHeader(option, DISCONNECT_PROVIDER_ULTIMATUM) {
426 | c.Emit("error", errors.New("MCS DISCONNECT_PROVIDER_ULTIMATUM"))
427 | c.transport.Close()
428 | return
429 | } else if !readMCSPDUHeader(option, c.recvOpCode) {
430 | c.Emit("error", errors.New("Invalid expected MCS opcode receive data"))
431 | return
432 | }
433 |
434 | userId, _ := per.ReadInteger16(r)
435 | userId += MCS_USERCHANNEL_BASE
436 |
437 | channelId, _ := per.ReadInteger16(r)
438 |
439 | per.ReadEnumerates(r)
440 | size, _ := per.ReadLength(r)
441 |
442 | // channel ID doesn't match a requested layer
443 | found := false
444 | channelName := ""
445 | for _, channel := range c.channels {
446 | if channel.ID == channelId {
447 | found = true
448 | channelName = channel.Name
449 | break
450 | }
451 | }
452 | if !found {
453 | glog.Error("mcs receive data for an unconnected layer")
454 | return
455 | }
456 | left, err := core.ReadBytes(int(size), r)
457 | if err != nil {
458 | c.Emit("error", errors.New(fmt.Sprintf("mcs recvData get data error %v", err)))
459 | return
460 | }
461 | glog.Debug("mcs emit channel", channelName)
462 | c.Emit(channelName, left)
463 | }
464 |
465 | func (c *MCSClient) recvChannelJoinConfirm(s []byte) {
466 | glog.Debug("mcs recvChannelJoinConfirm", hex.EncodeToString(s))
467 | r := bytes.NewReader(s)
468 | option, err := core.ReadUInt8(r)
469 | if err != nil {
470 | c.Emit("error", err)
471 | return
472 | }
473 |
474 | if !readMCSPDUHeader(option, CHANNEL_JOIN_CONFIRM) {
475 | c.Emit("error", errors.New("NODE_RDP_PROTOCOL_T125_MCS_WAIT_CHANNEL_JOIN_CONFIRM"))
476 | return
477 | }
478 |
479 | confirm, _ := per.ReadEnumerates(r)
480 | userId, _ := per.ReadInteger16(r)
481 | userId += MCS_USERCHANNEL_BASE
482 | if c.userId != userId {
483 | c.Emit("error", errors.New("NODE_RDP_PROTOCOL_T125_MCS_INVALID_USER_ID"))
484 | return
485 | }
486 |
487 | channelId, _ := per.ReadInteger16(r)
488 | if (confirm != 0) && (channelId == uint16(MCS_GLOBAL_CHANNEL) || channelId == c.userId) {
489 | c.Emit("error", errors.New("NODE_RDP_PROTOCOL_T125_MCS_SERVER_MUST_CONFIRM_STATIC_CHANNEL"))
490 | return
491 | }
492 |
493 | c.connectChannels()
494 | }
495 |
496 | func (c *MCSClient) Write(data []byte) (n int, err error) {
497 | buff := &bytes.Buffer{}
498 | writeMCSPDUHeader(c.sendOpCode, 0, buff)
499 | per.WriteInteger16(c.userId+MCS_USERCHANNEL_BASE, buff)
500 | per.WriteInteger16(c.channels[0].ID, buff)
501 | core.WriteUInt8(0x70, buff)
502 | per.WriteLength(len(data), buff)
503 | core.WriteBytes(data, buff)
504 | return c.transport.Write(buff.Bytes())
505 | }
506 |
--------------------------------------------------------------------------------
/protocol/t125/per/per.go:
--------------------------------------------------------------------------------
1 | package per
2 |
3 | import (
4 | "bytes"
5 | "github.com/icodeface/grdp/core"
6 | "io"
7 | )
8 |
9 | func ReadEnumerates(r io.Reader) (uint8, error) {
10 | return core.ReadUInt8(r)
11 | }
12 |
13 | func WriteInteger(n int, w io.Writer) {
14 | if n <= 0xff {
15 | WriteLength(1, w)
16 | core.WriteUInt8(uint8(n), w)
17 | } else if n <= 0xffff {
18 | WriteLength(2, w)
19 | core.WriteUInt16BE(uint16(n), w)
20 | } else {
21 | WriteLength(4, w)
22 | core.WriteUInt32BE(uint32(n), w)
23 | }
24 | }
25 |
26 | func ReadInteger16(r io.Reader) (uint16, error) {
27 | return core.ReadUint16BE(r)
28 | }
29 |
30 | func WriteInteger16(value uint16, w io.Writer) {
31 | core.WriteUInt16BE(value, w)
32 | }
33 |
34 | /**
35 | * @param choice {integer}
36 | * @returns {type.UInt8} choice per encoded
37 | */
38 | func WriteChoice(choice uint8, w io.Writer) {
39 | core.WriteUInt8(choice, w)
40 | }
41 |
42 | /**
43 | * @param value {raw} value to convert to per format
44 | * @returns type objects per encoding value
45 | */
46 | func WriteLength(value int, w io.Writer) {
47 | if value > 0x7f {
48 | core.WriteUInt16BE(uint16(value|0x8000), w)
49 | } else {
50 | core.WriteUInt8(uint8(value), w)
51 | }
52 | }
53 |
54 | func ReadLength(r io.Reader) (uint16, error) {
55 | b, err := core.ReadUInt8(r)
56 | if err != nil {
57 | return 0, nil
58 | }
59 | var size uint16
60 | if b&0x80 > 0 {
61 | b = b &^ 0x80
62 | size = uint16(b) << 8
63 | left, _ := core.ReadUInt8(r)
64 | size += uint16(left)
65 | } else {
66 | size = uint16(b)
67 | }
68 | return size, nil
69 | }
70 |
71 | /**
72 | * @param oid {array} oid to write
73 | * @returns {type.Component} per encoded object identifier
74 | */
75 | func WriteObjectIdentifier(oid []byte, w io.Writer) {
76 | core.WriteUInt8(5, w)
77 | core.WriteByte((oid[0]<<4)&(oid[1]&0x0f), w)
78 | core.WriteByte(oid[2], w)
79 | core.WriteByte(oid[3], w)
80 | core.WriteByte(oid[4], w)
81 | core.WriteByte(oid[5], w)
82 | }
83 |
84 | /**
85 | * @param selection {integer}
86 | * @returns {type.UInt8} per encoded selection
87 | */
88 | func WriteSelection(selection uint8, w io.Writer) {
89 | core.WriteUInt8(selection, w)
90 | }
91 |
92 | func WriteNumericString(s string, minValue int, w io.Writer) {
93 | length := len(s)
94 | mLength := minValue
95 | if length >= minValue {
96 | mLength = length - minValue
97 | }
98 | buff := &bytes.Buffer{}
99 | for i := 0; i < length; i += 2 {
100 | c1 := int(s[i])
101 | c2 := 0x30
102 | if i+1 < length {
103 | c2 = int(s[i+1])
104 | }
105 | c1 = (c1 - 0x30) % 10
106 | c2 = (c2 - 0x30) % 10
107 | core.WriteUInt8(uint8((c1<<4)|c2), buff)
108 | }
109 | WriteLength(mLength, w)
110 | w.Write(buff.Bytes())
111 | }
112 |
113 | func WritePadding(length int, w io.Writer) {
114 | b := make([]byte, length)
115 | w.Write(b)
116 | }
117 |
118 | func WriteNumberOfSet(n int, w io.Writer) {
119 | core.WriteUInt8(uint8(n), w)
120 | }
121 |
122 | /**
123 | * @param oStr {String}
124 | * @param minValue {integer} default 0
125 | * @returns {type.Component} per encoded octet stream
126 | */
127 | func WriteOctetStream(oStr string, minValue int, w io.Writer) {
128 | length := len(oStr)
129 | mlength := minValue
130 |
131 | if length-minValue >= 0 {
132 | mlength = length - minValue
133 | }
134 | WriteLength(mlength, w)
135 | w.Write([]byte(oStr)[:length])
136 | }
137 |
--------------------------------------------------------------------------------
/protocol/tpkt/tpkt.go:
--------------------------------------------------------------------------------
1 | package tpkt
2 |
3 | import (
4 | "bytes"
5 | "encoding/hex"
6 | "github.com/icodeface/grdp/core"
7 | "github.com/icodeface/grdp/emission"
8 | "github.com/icodeface/grdp/glog"
9 | )
10 |
11 | // take idea from https://github.com/Madnikulin50/gordp
12 |
13 | /**
14 | * Type of tpkt packet
15 | * Fastpath is use to shortcut RDP stack
16 | * @see http://msdn.microsoft.com/en-us/library/cc240621.aspx
17 | * @see http://msdn.microsoft.com/en-us/library/cc240589.aspx
18 | */
19 | const (
20 | FASTPATH_ACTION_FASTPATH = 0x0
21 | FASTPATH_ACTION_X224 = 0x3
22 | )
23 |
24 | /**
25 | * TPKT layer of rdp stack
26 | */
27 | type TPKT struct {
28 | emission.Emitter
29 | Conn *core.SocketLayer
30 | secFlag byte
31 | fastPathListener core.FastPathListener
32 | }
33 |
34 | func New(s *core.SocketLayer) *TPKT {
35 | t := &TPKT{
36 | Emitter: *emission.NewEmitter(),
37 | Conn: s,
38 | secFlag: 0}
39 | core.StartReadBytes(2, s, t.recvHeader)
40 | return t
41 | }
42 |
43 | func (t *TPKT) Read(b []byte) (n int, err error) {
44 | return t.Conn.Read(b)
45 | }
46 |
47 | func (t *TPKT) Write(data []byte) (n int, err error) {
48 | buff := &bytes.Buffer{}
49 | core.WriteUInt8(FASTPATH_ACTION_X224, buff)
50 | core.WriteUInt8(0, buff)
51 | core.WriteUInt16BE(uint16(len(data)+4), buff)
52 | buff.Write(data)
53 | glog.Debug("tpkt Write", hex.EncodeToString(buff.Bytes()))
54 | return t.Conn.Write(buff.Bytes())
55 | }
56 |
57 | func (t *TPKT) Close() error {
58 | return t.Conn.Close()
59 | }
60 |
61 | func (t *TPKT) SetFastPathListener(f core.FastPathListener) {
62 | t.fastPathListener = f
63 | }
64 |
65 | func (t *TPKT) SendFastPath(secFlag byte, data []byte) (n int, err error) {
66 | buff := &bytes.Buffer{}
67 | core.WriteUInt8(FASTPATH_ACTION_FASTPATH|((secFlag&0x3)<<6), buff)
68 | core.WriteUInt16BE(uint16(len(data)+3)|0x8000, buff)
69 | buff.Write(data)
70 | glog.Debug("TPTK SendFastPath", hex.EncodeToString(buff.Bytes()))
71 | return t.Conn.Write(buff.Bytes())
72 | }
73 |
74 | func (t *TPKT) recvHeader(s []byte, err error) {
75 | glog.Debug("tpkt recvHeader", hex.EncodeToString(s), err)
76 | if err != nil {
77 | t.Emit("error", err)
78 | return
79 | }
80 | version := s[0]
81 | if version == FASTPATH_ACTION_X224 {
82 | glog.Debug("tptk recvHeader FASTPATH_ACTION_X224, wait for recvExtendedHeader")
83 | core.StartReadBytes(2, t.Conn, t.recvExtendedHeader)
84 | } else {
85 | t.secFlag = (version >> 6) & 0x3
86 | length := int(s[1])
87 | if length&0x80 != 0 {
88 | core.StartReadBytes(1, t.Conn, func(s []byte, err error) {
89 | t.recvExtendedFastPathHeader(s, length, err)
90 | })
91 | } else {
92 | core.StartReadBytes(length-2, t.Conn, t.recvFastPath)
93 | }
94 | }
95 | }
96 |
97 | func (t *TPKT) recvExtendedHeader(s []byte, err error) {
98 | glog.Debug("tpkt recvExtendedHeader", hex.EncodeToString(s), err)
99 | if err != nil {
100 | return
101 | }
102 | r := bytes.NewReader(s)
103 | size, _ := core.ReadUint16BE(r)
104 | glog.Debug("tpkt wait recvData")
105 | core.StartReadBytes(int(size-4), t.Conn, t.recvData)
106 | }
107 |
108 | func (t *TPKT) recvData(s []byte, err error) {
109 | glog.Debug("tpkt recvData", hex.EncodeToString(s), err)
110 | if err != nil {
111 | return
112 | }
113 | t.Emit("data", s)
114 | glog.Debug("tpkt wait recvHeader")
115 | core.StartReadBytes(2, t.Conn, t.recvHeader)
116 | }
117 |
118 | func (t *TPKT) recvExtendedFastPathHeader(s []byte, length int, err error) {
119 | glog.Debug("tpkt recvExtendedFastPathHeader", hex.EncodeToString(s), length, err)
120 | r := bytes.NewReader(s)
121 | rightPart, err := core.ReadUInt8(r)
122 | if err != nil {
123 | glog.Error("TPTK recvExtendedFastPathHeader", err)
124 | return
125 | }
126 | leftPart := length & ^0x80
127 | packetSize := (leftPart << 8) + int(rightPart)
128 | core.StartReadBytes(packetSize-3, t.Conn, t.recvFastPath)
129 | }
130 |
131 | func (t *TPKT) recvFastPath(s []byte, err error) {
132 | glog.Debug("tpkt recvFastPath")
133 | if err != nil {
134 | return
135 | }
136 | t.fastPathListener.RecvFastPath(t.secFlag, s)
137 | core.StartReadBytes(2, t.Conn, t.recvHeader)
138 | }
139 |
--------------------------------------------------------------------------------
/protocol/x224/x224.go:
--------------------------------------------------------------------------------
1 | package x224
2 |
3 | import (
4 | "bytes"
5 | "encoding/hex"
6 | "errors"
7 | "fmt"
8 | "github.com/icodeface/grdp/core"
9 | "github.com/icodeface/grdp/emission"
10 | "github.com/icodeface/grdp/glog"
11 | "github.com/icodeface/grdp/protocol/tpkt"
12 | "github.com/lunixbochs/struc"
13 | )
14 |
15 | // take idea from https://github.com/Madnikulin50/gordp
16 |
17 | /**
18 | * Message type present in X224 packet header
19 | */
20 | type MessageType byte
21 |
22 | const (
23 | TPDU_CONNECTION_REQUEST MessageType = 0xE0
24 | TPDU_CONNECTION_CONFIRM = 0xD0
25 | TPDU_DISCONNECT_REQUEST = 0x80
26 | TPDU_DATA = 0xF0
27 | TPDU_ERROR = 0x70
28 | )
29 |
30 | /**
31 | * Type of negotiation present in negotiation packet
32 | */
33 | type NegotiationType byte
34 |
35 | const (
36 | TYPE_RDP_NEG_REQ NegotiationType = 0x01
37 | TYPE_RDP_NEG_RSP = 0x02
38 | TYPE_RDP_NEG_FAILURE = 0x03
39 | )
40 |
41 | /**
42 | * Protocols available for x224 layer
43 | */
44 |
45 | const (
46 | PROTOCOL_RDP uint32 = 0x00000000
47 | PROTOCOL_SSL = 0x00000001
48 | PROTOCOL_HYBRID = 0x00000002
49 | PROTOCOL_HYBRID_EX = 0x00000008
50 | )
51 |
52 | /**
53 | * Use to negotiate security layer of RDP stack
54 | * In node-rdpjs only ssl is available
55 | * @param opt {object} component type options
56 | * @see request -> http://msdn.microsoft.com/en-us/library/cc240500.aspx
57 | * @see response -> http://msdn.microsoft.com/en-us/library/cc240506.aspx
58 | * @see failure ->http://msdn.microsoft.com/en-us/library/cc240507.aspx
59 | */
60 | type Negotiation struct {
61 | Type NegotiationType `struc:"byte"`
62 | Flag uint8 `struc:"uint8"`
63 | Length uint16 `struc:"little"`
64 | Result uint32 `struc:"little"`
65 | }
66 |
67 | func NewNegotiation() *Negotiation {
68 | return &Negotiation{0, 0, 0x0008 /*constant*/, PROTOCOL_RDP}
69 | }
70 |
71 | /**
72 | * X224 client connection request
73 | * @param opt {object} component type options
74 | * @see http://msdn.microsoft.com/en-us/library/cc240470.aspx
75 | */
76 | type ClientConnectionRequestPDU struct {
77 | Len uint8
78 | Code MessageType
79 | Padding1 uint16
80 | Padding2 uint16
81 | Padding3 uint8
82 | Cookie []byte
83 | ProtocolNeg *Negotiation
84 | }
85 |
86 | func NewClientConnectionRequestPDU(coockie []byte) *ClientConnectionRequestPDU {
87 | x := ClientConnectionRequestPDU{0, TPDU_CONNECTION_REQUEST, 0, 0, 0,
88 | coockie, NewNegotiation()}
89 | x.Len = uint8(len(x.Serialize()) - 1)
90 | return &x
91 | }
92 |
93 | func (x *ClientConnectionRequestPDU) Serialize() []byte {
94 | buff := &bytes.Buffer{}
95 | core.WriteUInt8(x.Len, buff)
96 | core.WriteUInt8(uint8(x.Code), buff)
97 | core.WriteUInt16BE(x.Padding1, buff)
98 | core.WriteUInt16BE(x.Padding2, buff)
99 | core.WriteUInt8(x.Padding3, buff)
100 |
101 | buff.Write(x.Cookie)
102 | if x.Len > 14 {
103 | core.WriteUInt16LE(0x0A0D, buff)
104 | }
105 | struc.Pack(buff, x.ProtocolNeg)
106 | return buff.Bytes()
107 | }
108 |
109 | /**
110 | * X224 Server connection confirm
111 | * @param opt {object} component type options
112 | * @see http://msdn.microsoft.com/en-us/library/cc240506.aspx
113 | */
114 | type ServerConnectionConfirm struct {
115 | Len uint8
116 | Code MessageType
117 | Padding1 uint16
118 | Padding2 uint16
119 | Padding3 uint8
120 | ProtocolNeg *Negotiation
121 | }
122 |
123 | /**
124 | * Header of each data message from x224 layer
125 | * @returns {type.Component}
126 | */
127 | type DataHeader struct {
128 | Header uint8
129 | MessageType MessageType
130 | Separator uint8
131 | }
132 |
133 | func NewDataHeader() *DataHeader {
134 | return &DataHeader{2, TPDU_DATA /* constant */, 0x80 /*constant*/}
135 | }
136 |
137 | /**
138 | * Common X224 Automata
139 | * @param presentation {Layer} presentation layer
140 | */
141 | type X224 struct {
142 | emission.Emitter
143 | transport core.Transport
144 | requestedProtocol uint32
145 | selectedProtocol uint32
146 | dataHeader *DataHeader
147 | }
148 |
149 | func New(t core.Transport) *X224 {
150 | x := &X224{
151 | *emission.NewEmitter(),
152 | t,
153 | PROTOCOL_SSL | PROTOCOL_HYBRID,
154 | PROTOCOL_SSL,
155 | NewDataHeader(),
156 | }
157 |
158 | t.On("close", func() {
159 | x.Emit("close")
160 | }).On("error", func(err error) {
161 | x.Emit("error", err)
162 | })
163 |
164 | return x
165 | }
166 |
167 | func (x *X224) Read(b []byte) (n int, err error) {
168 | return x.transport.Read(b)
169 | }
170 |
171 | func (x *X224) Write(b []byte) (n int, err error) {
172 | buff := &bytes.Buffer{}
173 | err = struc.Pack(buff, x.dataHeader)
174 | if err != nil {
175 | return 0, err
176 | }
177 | buff.Write(b)
178 | glog.Debug("x224 write", hex.EncodeToString(buff.Bytes()))
179 | return x.transport.Write(buff.Bytes())
180 | }
181 |
182 | func (x *X224) Close() error {
183 | return x.transport.Close()
184 | }
185 |
186 | func (x *X224) SetRequestedProtocol(p uint32) {
187 | x.requestedProtocol = p
188 | }
189 |
190 | func (x *X224) Connect() error {
191 | if x.transport == nil {
192 | return errors.New("no transport")
193 | }
194 | message := NewClientConnectionRequestPDU(make([]byte, 0))
195 | message.ProtocolNeg.Type = TYPE_RDP_NEG_REQ
196 | message.ProtocolNeg.Result = uint32(x.requestedProtocol)
197 |
198 | glog.Debug("x224 sendConnectionRequest", hex.EncodeToString(message.Serialize()))
199 | _, err := x.transport.Write(message.Serialize())
200 | x.transport.Once("data", x.recvConnectionConfirm)
201 | return err
202 | }
203 |
204 | func (x *X224) recvConnectionConfirm(s []byte) {
205 | glog.Debug("x224 recvConnectionConfirm", hex.EncodeToString(s))
206 | message := &ServerConnectionConfirm{}
207 | if err := struc.Unpack(bytes.NewReader(s), message); err != nil {
208 | glog.Error("ReadServerConnectionConfirm err", err)
209 | return
210 | }
211 |
212 | if message.ProtocolNeg.Type == TYPE_RDP_NEG_FAILURE {
213 | glog.Error(fmt.Sprintf("NODE_RDP_PROTOCOL_X224_NEG_FAILURE with code: %d,see https://msdn.microsoft.com/en-us/library/cc240507.aspx",
214 | message.ProtocolNeg.Result))
215 | return
216 | }
217 |
218 | if message.ProtocolNeg.Type == TYPE_RDP_NEG_RSP {
219 | glog.Info("TYPE_RDP_NEG_RSP")
220 | x.selectedProtocol = message.ProtocolNeg.Result
221 | }
222 |
223 | if x.selectedProtocol == PROTOCOL_HYBRID_EX {
224 | glog.Error("NODE_RDP_PROTOCOL_HYBRID_EX_NOT_SUPPORTED")
225 | return
226 | }
227 |
228 | x.transport.On("data", x.recvData)
229 |
230 | if x.selectedProtocol == PROTOCOL_RDP {
231 | glog.Info("*** RDP security selected ***")
232 | return
233 | }
234 |
235 | if x.selectedProtocol == PROTOCOL_SSL {
236 | glog.Info("*** SSL security selected ***")
237 | err := x.transport.(*tpkt.TPKT).Conn.StartTLS()
238 | if err != nil {
239 | glog.Error("start tls failed", err)
240 | return
241 | }
242 | x.Emit("connect", x.selectedProtocol)
243 | return
244 | }
245 |
246 | if x.selectedProtocol == PROTOCOL_HYBRID {
247 | glog.Info("*** NLA Security selected ***")
248 | err := x.transport.(*tpkt.TPKT).Conn.StartNLA()
249 | if err != nil {
250 | glog.Error("start NLA failed", err)
251 | return
252 | }
253 | x.Emit("connect", x.selectedProtocol)
254 | return
255 | }
256 | }
257 |
258 | func (x *X224) recvData(s []byte) {
259 | glog.Debug("x224 recvData", hex.EncodeToString(s), "emit data")
260 | // x224 header takes 3 bytes
261 | x.Emit("data", s[3:])
262 | }
263 |
--------------------------------------------------------------------------------