├── .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 | --------------------------------------------------------------------------------