├── .gitignore ├── CMakeLists.txt ├── ChangeLog.md ├── LICENSE ├── README.md ├── capabilities.c ├── capabilities.h ├── convert_km.py ├── d3des.c ├── d3des.h ├── input.c ├── input.h ├── keymaps.c ├── keymaps.h ├── license.h ├── log.c ├── log.h ├── mcs.c ├── mcs.h ├── orders.h ├── packet.c ├── packet.h ├── rdp.c ├── rdp.h ├── sec.c ├── sec.h ├── session.c ├── session.h ├── tpkt.c ├── tpkt.h ├── vnc.c ├── vnc.h ├── vnc2rdp.c ├── vncauth.c ├── vncauth.h ├── x224.c └── x224.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Libraries 8 | *.lib 9 | *.a 10 | 11 | # Shared objects (inc. Windows DLLs) 12 | *.dll 13 | *.so 14 | *.so.* 15 | *.dylib 16 | 17 | # Executables 18 | *.exe 19 | *.out 20 | *.app 21 | *.i*86 22 | *.x86_64 23 | *.hex 24 | 25 | # CMake.gitignore 26 | CMakeCache.txt 27 | CMakeFiles 28 | Makefile 29 | cmake_install.cmake 30 | install_manifest.txt 31 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.6) 2 | project (vnc2rdp C) 3 | 4 | # set default build type: Release 5 | if(NOT CMAKE_BUILD_TYPE) 6 | set(CMAKE_BUILD_TYPE "Release") 7 | endif(NOT CMAKE_BUILD_TYPE) 8 | 9 | set(VNC2RDP_SRC 10 | capabilities.c 11 | capabilities.h 12 | d3des.c 13 | d3des.h 14 | input.c 15 | input.h 16 | keymaps.c 17 | keymaps.h 18 | license.h 19 | log.c 20 | log.h 21 | mcs.c 22 | mcs.h 23 | orders.h 24 | packet.c 25 | packet.h 26 | rdp.c 27 | rdp.h 28 | vnc2rdp.c 29 | sec.c 30 | sec.h 31 | session.c 32 | session.h 33 | tpkt.c 34 | tpkt.h 35 | vnc.c 36 | vnc.h 37 | vncauth.c 38 | vncauth.h 39 | x224.c 40 | x224.h 41 | ) 42 | 43 | add_executable(vnc2rdp ${VNC2RDP_SRC}) 44 | 45 | install(TARGETS vnc2rdp DESTINATION bin) 46 | -------------------------------------------------------------------------------- /ChangeLog.md: -------------------------------------------------------------------------------- 1 | #### vnc2rdp-v0.2.0 (2014-07-06) 2 | 3 | * Add support for keyboard input. 4 | * Add support for VNC server depth 8/15/16/24. 5 | * Add **viewonly** mode when connect to VNC server. 6 | * Improved performace of bitmap convert from VNC to RDP. 7 | 8 | #### vnc2rdp-v0.1.0 (2014-06-23) 9 | 10 | * Add support for VNC Raw/CopyRect encoding. 11 | * Add support for mouse event. 12 | * Add support for 32 bpp. 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Welcome 2 | 3 | **vnc2rdp** is a proxy for RDP client connect to VNC server, released under the [**Apache License, Version 2.0**](http://www.apache.org/licenses/LICENSE-2.0). 4 | 5 | Currently, vnc2rdp only support: 6 | 7 | RDP client: 8 | 9 | * mstsc.exe 10 | * [FreeRDP](http://www.freerdp.com/) 11 | 12 | VNC server: 13 | 14 | * RealVNC 15 | * TightVNC (v1.3) 16 | 17 | ### Screenshots 18 | 19 | Screenshot of using mstsc.exe connect to RealVNC Server via vnc2rdp: 20 | 21 | 22 | 23 | ### Download 24 | 25 | Current release: [vnc2rdp-0.2.0.tar.gz](https://github.com/leeyiw/vnc2rdp/archive/v0.2.0.tar.gz) ([ChangeLog](https://github.com/leeyiw/vnc2rdp/blob/master/ChangeLog.md)), MD5 checksum: `cb232c4f6b51d09545ea1095e095b682`. All releases are listed [**HERE**](https://github.com/leeyiw/vnc2rdp/releases). 26 | 27 | To download the latest development tree, use the following command: 28 | 29 | ```bash 30 | $ git clone git@github.com:leeyiw/vnc2rdp.git 31 | ``` 32 | 33 | ### Build and Install 34 | 35 | vnc2rdp use [CMake](http://www.cmake.org/) as it's build system. To build vnc2rdp, you need to install CMake first. After CMake was installed, use these commands to generate Makefile: 36 | 37 | ```bash 38 | $ git clone https://github.com/leeyiw/vnc2rdp.git 39 | $ cd vnc2rdp 40 | $ cmake . 41 | ``` 42 | 43 | After Makefile was generated, build vnc2rdp with `make`, and install with `make install`. All files installed to your system will be listed in `install_manifest.txt`. 44 | -------------------------------------------------------------------------------- /capabilities.c: -------------------------------------------------------------------------------- 1 | /** 2 | * vnc2rdp: proxy for RDP client connect to VNC server 3 | * 4 | * Copyright 2014 Yiwei Li 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include "capabilities.h" 20 | #include "vnc.h" 21 | 22 | static void 23 | v2r_cap_write_general_cap(v2r_rdp_t *r, v2r_packet_t *p) 24 | { 25 | /* capabilitySetType */ 26 | V2R_PACKET_WRITE_UINT16_LE(p, CAPSTYPE_GENERAL); 27 | /* lengthCapability */ 28 | V2R_PACKET_WRITE_UINT16_LE(p, 24); 29 | /* osMajorType */ 30 | V2R_PACKET_WRITE_UINT16_LE(p, OSMAJORTYPE_WINDOWS); 31 | /* osMinorType */ 32 | V2R_PACKET_WRITE_UINT16_LE(p, OSMINORTYPE_WINDOWS_NT); 33 | /* protocolVersion */ 34 | V2R_PACKET_WRITE_UINT16_LE(p, TS_CAPS_PROTOCOLVERSION); 35 | /* pad2octetsA */ 36 | V2R_PACKET_WRITE_UINT16_LE(p, 0); 37 | /* generalCompressionTypes */ 38 | V2R_PACKET_WRITE_UINT16_LE(p, 0); 39 | /* extraFlags */ 40 | V2R_PACKET_WRITE_UINT16_LE(p, 0); 41 | /* updateCapabilityFlag */ 42 | V2R_PACKET_WRITE_UINT16_LE(p, 0); 43 | /* remoteUnshareFlag */ 44 | V2R_PACKET_WRITE_UINT16_LE(p, 0); 45 | /* generalCompressionLevel */ 46 | V2R_PACKET_WRITE_UINT16_LE(p, 0); 47 | /* refreshRectSupport */ 48 | V2R_PACKET_WRITE_UINT8(p, 0x00); 49 | /* suppressOutputSupport */ 50 | V2R_PACKET_WRITE_UINT8(p, 0x01); 51 | } 52 | 53 | static void 54 | v2r_cap_write_bitmap_cap(v2r_rdp_t *r, v2r_packet_t *p) 55 | { 56 | /* capabilitySetType */ 57 | V2R_PACKET_WRITE_UINT16_LE(p, CAPSTYPE_BITMAP); 58 | /* lengthCapability */ 59 | V2R_PACKET_WRITE_UINT16_LE(p, 29); 60 | /* preferredBitsPerPixel */ 61 | V2R_PACKET_WRITE_UINT16_LE(p, r->session->vnc->bpp); 62 | /* receive1BitPerPixel */ 63 | V2R_PACKET_WRITE_UINT16_LE(p, 0x0001); 64 | /* receive4BitsPerPixel */ 65 | V2R_PACKET_WRITE_UINT16_LE(p, 0x0001); 66 | /* receive8BitsPerPixel */ 67 | V2R_PACKET_WRITE_UINT16_LE(p, 0x0001); 68 | /* desktopWidth */ 69 | V2R_PACKET_WRITE_UINT16_LE(p, r->session->vnc->framebuffer_width); 70 | /* desktopHeight */ 71 | V2R_PACKET_WRITE_UINT16_LE(p, r->session->vnc->framebuffer_height); 72 | /* pad2octets */ 73 | V2R_PACKET_WRITE_UINT16_LE(p, 0); 74 | /* desktopResizeFlag */ 75 | V2R_PACKET_WRITE_UINT16_LE(p, 0x0001); 76 | /* bitmapCompressionFlag */ 77 | V2R_PACKET_WRITE_UINT16_LE(p, 0x0001); 78 | /* highColorFlags */ 79 | V2R_PACKET_WRITE_UINT16_LE(p, 0); 80 | /* drawingFlags */ 81 | V2R_PACKET_WRITE_UINT8(p, 0x00); 82 | /* multipleRectangleSupport */ 83 | V2R_PACKET_WRITE_UINT16_LE(p, 0x0001); 84 | /* pad2octetsB */ 85 | V2R_PACKET_WRITE_UINT16_LE(p, 0); 86 | } 87 | 88 | static void 89 | v2r_cap_write_input_cap(v2r_rdp_t *r, v2r_packet_t *p) 90 | { 91 | /* capabilitySetType */ 92 | V2R_PACKET_WRITE_UINT16_LE(p, CAPSTYPE_INPUT); 93 | /* lengthCapability */ 94 | V2R_PACKET_WRITE_UINT16_LE(p, 88); 95 | /* inputFlags */ 96 | V2R_PACKET_WRITE_UINT16_LE(p, INPUT_FLAG_SCANCODES); 97 | /* pad2octetsA */ 98 | V2R_PACKET_WRITE_UINT16_LE(p, 0); 99 | /* keyboardLayout */ 100 | V2R_PACKET_WRITE_UINT32_LE(p, 0); 101 | /* keyboardType */ 102 | V2R_PACKET_WRITE_UINT32_LE(p, 0); 103 | /* keyboardSubType */ 104 | V2R_PACKET_WRITE_UINT32_LE(p, 0); 105 | /* keyboardFunctionKey */ 106 | V2R_PACKET_WRITE_UINT32_LE(p, 0); 107 | /* imeFileName */ 108 | V2R_PACKET_SEEK(p, 64); 109 | } 110 | 111 | v2r_cap_write_func v2r_cap_write_func_list[] = { 112 | v2r_cap_write_general_cap, 113 | v2r_cap_write_bitmap_cap, 114 | v2r_cap_write_input_cap 115 | }; 116 | 117 | uint16_t 118 | v2r_cap_get_write_count() 119 | { 120 | return sizeof(v2r_cap_write_func_list)/sizeof(v2r_cap_write_func_list[0]); 121 | } 122 | 123 | void 124 | v2r_cap_write_caps(v2r_rdp_t *r, v2r_packet_t *p) 125 | { 126 | int i = 0, write_count = v2r_cap_get_write_count(); 127 | for (i = 0; i < write_count; i++) { 128 | v2r_cap_write_func_list[i](r, p); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /capabilities.h: -------------------------------------------------------------------------------- 1 | /** 2 | * vnc2rdp: proxy for RDP client connect to VNC server 3 | * 4 | * Copyright 2014 Yiwei Li 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef _CAPABILITIES_H_ 20 | #define _CAPABILITIES_H_ 21 | 22 | #include "packet.h" 23 | #include "rdp.h" 24 | 25 | #define TS_CAPS_PROTOCOLVERSION 0x0200 26 | 27 | #define CAPSTYPE_GENERAL 0x0001 28 | #define CAPSTYPE_BITMAP 0x0002 29 | #define CAPSTYPE_ORDER 0x0003 30 | #define CAPSTYPE_BITMAPCACHE 0x0004 31 | #define CAPSTYPE_CONTROL 0x0005 32 | #define CAPSTYPE_ACTIVATION 0x0007 33 | #define CAPSTYPE_POINTER 0x0008 34 | #define CAPSTYPE_SHARE 0x0009 35 | #define CAPSTYPE_COLORCACHE 0x000A 36 | #define CAPSTYPE_SOUND 0x000C 37 | #define CAPSTYPE_INPUT 0x000D 38 | #define CAPSTYPE_FONT 0x000E 39 | #define CAPSTYPE_BRUSH 0x000F 40 | #define CAPSTYPE_GLYPHCACHE 0x0010 41 | #define CAPSTYPE_OFFSCREENCACHE 0x0011 42 | #define CAPSTYPE_BITMAPCACHE_HOSTSUPPORT 0x0012 43 | #define CAPSTYPE_BITMAPCACHE_REV2 0x0013 44 | #define CAPSTYPE_VIRTUALCHANNEL 0x0014 45 | #define CAPSTYPE_DRAWNINEGRIDCACHE 0x0015 46 | #define CAPSTYPE_DRAWGDIPLUS 0x0016 47 | #define CAPSTYPE_RAIL 0x0017 48 | #define CAPSTYPE_WINDOW 0x0018 49 | #define CAPSETTYPE_COMPDESK 0x0019 50 | #define CAPSETTYPE_MULTIFRAGMENTUPDATE 0x001A 51 | #define CAPSETTYPE_LARGE_POINTER 0x001B 52 | #define CAPSETTYPE_SURFACE_COMMANDS 0x001C 53 | #define CAPSETTYPE_BITMAP_CODECS 0x001D 54 | #define CAPSSETTYPE_FRAME_ACKNOWLEDGE 0x001E 55 | 56 | /* General Capability Set - osMajorType */ 57 | #define OSMAJORTYPE_UNSPECIFIED 0x0000 58 | #define OSMAJORTYPE_WINDOWS 0x0001 59 | #define OSMAJORTYPE_OS2 0x0002 60 | #define OSMAJORTYPE_MACINTOSH 0x0003 61 | #define OSMAJORTYPE_UNIX 0x0004 62 | #define OSMAJORTYPE_IOS 0x0005 63 | #define OSMAJORTYPE_OSX 0x0006 64 | #define OSMAJORTYPE_ANDROID 0x0007 65 | 66 | /* General Capability Set - osMinorType */ 67 | #define OSMINORTYPE_UNSPECIFIED 0x0000 68 | #define OSMINORTYPE_WINDOWS_31X 0x0001 69 | #define OSMINORTYPE_WINDOWS_95 0x0002 70 | #define OSMINORTYPE_WINDOWS_NT 0x0003 71 | #define OSMINORTYPE_OS2_V21 0x0004 72 | #define OSMINORTYPE_POWER_PC 0x0005 73 | #define OSMINORTYPE_MACINTOSH 0x0006 74 | #define OSMINORTYPE_NATIVE_XSERVER 0x0007 75 | #define OSMINORTYPE_PSEUDO_XSERVER 0x0008 76 | 77 | /* General Capability Set - extraFlags */ 78 | #define FASTPATH_OUTPUT_SUPPORTED 0x0001 79 | #define NO_BITMAP_COMPRESSION_HDR 0x0400 80 | #define LONG_CREDENTIALS_SUPPORTED 0x0004 81 | #define AUTORECONNECT_SUPPORTED 0x0008 82 | #define ENC_SALTED_CHECKSUM 0x0010 83 | 84 | /* Input Capability Set - inputFlags */ 85 | #define INPUT_FLAG_SCANCODES 0x0001 86 | #define INPUT_FLAG_MOUSEX 0x0004 87 | #define INPUT_FLAG_FASTPATH_INPUT 0x0008 88 | #define INPUT_FLAG_UNICODE 0x0010 89 | #define INPUT_FLAG_FASTPATH_INPUT2 0x0020 90 | #define INPUT_FLAG_UNUSED1 0x0040 91 | #define INPUT_FLAG_UNUSED2 0x0080 92 | #define TS_INPUT_FLAG_MOUSE_HWHEEL 0x0100 93 | 94 | typedef void (*v2r_cap_write_func)(v2r_rdp_t *r, v2r_packet_t *p); 95 | 96 | extern uint16_t v2r_cap_get_write_count(); 97 | extern void v2r_cap_write_caps(v2r_rdp_t *r, v2r_packet_t *p); 98 | 99 | #endif // _CAPABILITIES_H_ 100 | -------------------------------------------------------------------------------- /convert_km.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #-*- coding: utf-8 -*- 3 | 4 | """This script convert xrdp's km-xxxx.ini keymap file to vnc2rdp code""" 5 | 6 | import re 7 | import sys 8 | 9 | def main(): 10 | if len(sys.argv) != 2: 11 | print 'Usage: %s FILE' % sys.argv[0] 12 | 13 | km_filename = sys.argv[1] 14 | km_file = open(km_filename, 'r') 15 | 16 | km = { 17 | 'noshift': [0, 0, 0, 0, 0, 0, 0, 0], 18 | 'shift': [0, 0, 0, 0, 0, 0, 0, 0], 19 | 'altgr': [0, 0, 0, 0, 0, 0, 0, 0], 20 | 'capslock': [0, 0, 0, 0, 0, 0, 0, 0], 21 | 'shiftcapslock': [0, 0, 0, 0, 0, 0, 0, 0] 22 | } 23 | lines = km_file.readlines() 24 | keysym_rx = re.compile(r'^Key.*=(?P.*):.*$') 25 | for line in lines: 26 | if line.startswith('['): 27 | section = line[1:len(line) - 2] 28 | continue 29 | if not keysym_rx.match(line): 30 | continue 31 | keysym = int(keysym_rx.sub(r'\g', line)) 32 | km[section].append(keysym) 33 | 34 | for i, key in enumerate(km.keys()): 35 | print '.%s = {' % key 36 | for j, keysym in enumerate(km[key]): 37 | if j % 8 == 0: 38 | prefix = '\t' 39 | else: 40 | prefix = '' 41 | if j != len(km[key]) - 1: 42 | suffix = ',' 43 | if (j + 1) % 8 != 0: 44 | suffix += ' ' 45 | else: 46 | suffix += '\n' 47 | else: 48 | suffix = '\n' 49 | sys.stdout.write('%s0x%04x%s' % (prefix, keysym, suffix)) 50 | if i == len(km.keys()) - 1: 51 | print '}' 52 | else: 53 | print '},' 54 | 55 | if __name__ == '__main__': 56 | main() 57 | -------------------------------------------------------------------------------- /d3des.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This is D3DES (V5.09) by Richard Outerbridge with the double and 3 | * triple-length support removed for use in VNC. Also the bytebit[] array 4 | * has been reversed so that the most significant bit in each byte of the 5 | * key is ignored, not the least significant. 6 | * 7 | * These changes are: 8 | * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | */ 14 | 15 | /* D3DES (V5.09) - 16 | * 17 | * A portable, public domain, version of the Data Encryption Standard. 18 | * 19 | * Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge. 20 | * Thanks to: Dan Hoey for his excellent Initial and Inverse permutation 21 | * code; Jim Gillogly & Phil Karn for the DES key schedule code; Dennis 22 | * Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau, 23 | * for humouring me on. 24 | * 25 | * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge. 26 | * (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992. 27 | */ 28 | 29 | #include "d3des.h" 30 | 31 | static void scrunch(unsigned char *, unsigned long *); 32 | static void unscrun(unsigned long *, unsigned char *); 33 | static void desfunc(unsigned long *, unsigned long *); 34 | static void cookey(unsigned long *); 35 | 36 | static unsigned long KnL[32] = { 0L }; 37 | /* 38 | static unsigned long KnR[32] = { 0L }; 39 | static unsigned long Kn3[32] = { 0L }; 40 | static unsigned char Df_Key[24] = { 41 | 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef, 42 | 0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10, 43 | 0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67 }; 44 | */ 45 | 46 | static unsigned short bytebit[8] = { 47 | 01, 02, 04, 010, 020, 040, 0100, 0200 }; 48 | 49 | static unsigned long bigbyte[24] = { 50 | 0x800000L, 0x400000L, 0x200000L, 0x100000L, 51 | 0x80000L, 0x40000L, 0x20000L, 0x10000L, 52 | 0x8000L, 0x4000L, 0x2000L, 0x1000L, 53 | 0x800L, 0x400L, 0x200L, 0x100L, 54 | 0x80L, 0x40L, 0x20L, 0x10L, 55 | 0x8L, 0x4L, 0x2L, 0x1L }; 56 | 57 | /* Use the key schedule specified in the Standard (ANSI X3.92-1981). */ 58 | 59 | static unsigned char pc1[56] = { 60 | 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, 61 | 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 62 | 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 63 | 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 }; 64 | 65 | static unsigned char totrot[16] = { 66 | 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 }; 67 | 68 | static unsigned char pc2[48] = { 69 | 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, 70 | 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1, 71 | 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47, 72 | 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 }; 73 | 74 | void rfbDesKey(unsigned char *key, 75 | int edf) 76 | { 77 | register int i, j, l, m, n; 78 | unsigned char pc1m[56], pcr[56]; 79 | unsigned long kn[32]; 80 | 81 | for ( j = 0; j < 56; j++ ) { 82 | l = pc1[j]; 83 | m = l & 07; 84 | pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0; 85 | } 86 | for( i = 0; i < 16; i++ ) { 87 | if( edf == DE1 ) m = (15 - i) << 1; 88 | else m = i << 1; 89 | n = m + 1; 90 | kn[m] = kn[n] = 0L; 91 | for( j = 0; j < 28; j++ ) { 92 | l = j + totrot[i]; 93 | if( l < 28 ) pcr[j] = pc1m[l]; 94 | else pcr[j] = pc1m[l - 28]; 95 | } 96 | for( j = 28; j < 56; j++ ) { 97 | l = j + totrot[i]; 98 | if( l < 56 ) pcr[j] = pc1m[l]; 99 | else pcr[j] = pc1m[l - 28]; 100 | } 101 | for( j = 0; j < 24; j++ ) { 102 | if( pcr[pc2[j]] ) kn[m] |= bigbyte[j]; 103 | if( pcr[pc2[j+24]] ) kn[n] |= bigbyte[j]; 104 | } 105 | } 106 | cookey(kn); 107 | return; 108 | } 109 | 110 | static void cookey(register unsigned long *raw1) 111 | { 112 | register unsigned long *cook, *raw0; 113 | unsigned long dough[32]; 114 | register int i; 115 | 116 | cook = dough; 117 | for( i = 0; i < 16; i++, raw1++ ) { 118 | raw0 = raw1++; 119 | *cook = (*raw0 & 0x00fc0000L) << 6; 120 | *cook |= (*raw0 & 0x00000fc0L) << 10; 121 | *cook |= (*raw1 & 0x00fc0000L) >> 10; 122 | *cook++ |= (*raw1 & 0x00000fc0L) >> 6; 123 | *cook = (*raw0 & 0x0003f000L) << 12; 124 | *cook |= (*raw0 & 0x0000003fL) << 16; 125 | *cook |= (*raw1 & 0x0003f000L) >> 4; 126 | *cook++ |= (*raw1 & 0x0000003fL); 127 | } 128 | rfbUseKey(dough); 129 | return; 130 | } 131 | 132 | void rfbCPKey(register unsigned long *into) 133 | { 134 | register unsigned long *from, *endp; 135 | 136 | from = KnL, endp = &KnL[32]; 137 | while( from < endp ) *into++ = *from++; 138 | return; 139 | } 140 | 141 | void rfbUseKey(register unsigned long *from) 142 | { 143 | register unsigned long *to, *endp; 144 | 145 | to = KnL, endp = &KnL[32]; 146 | while( to < endp ) *to++ = *from++; 147 | return; 148 | } 149 | 150 | void rfbDes(unsigned char *inblock, 151 | unsigned char *outblock) 152 | { 153 | unsigned long work[2]; 154 | 155 | scrunch(inblock, work); 156 | desfunc(work, KnL); 157 | unscrun(work, outblock); 158 | return; 159 | } 160 | 161 | static void scrunch(register unsigned char *outof, 162 | register unsigned long *into) 163 | { 164 | *into = (*outof++ & 0xffL) << 24; 165 | *into |= (*outof++ & 0xffL) << 16; 166 | *into |= (*outof++ & 0xffL) << 8; 167 | *into++ |= (*outof++ & 0xffL); 168 | *into = (*outof++ & 0xffL) << 24; 169 | *into |= (*outof++ & 0xffL) << 16; 170 | *into |= (*outof++ & 0xffL) << 8; 171 | *into |= (*outof & 0xffL); 172 | return; 173 | } 174 | 175 | static void unscrun(register unsigned long *outof, 176 | register unsigned char *into) 177 | { 178 | *into++ = (unsigned char)((*outof >> 24) & 0xffL); 179 | *into++ = (unsigned char)((*outof >> 16) & 0xffL); 180 | *into++ = (unsigned char)((*outof >> 8) & 0xffL); 181 | *into++ = (unsigned char)( *outof++ & 0xffL); 182 | *into++ = (unsigned char)((*outof >> 24) & 0xffL); 183 | *into++ = (unsigned char)((*outof >> 16) & 0xffL); 184 | *into++ = (unsigned char)((*outof >> 8) & 0xffL); 185 | *into = (unsigned char)( *outof & 0xffL); 186 | return; 187 | } 188 | 189 | static unsigned long SP1[64] = { 190 | 0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L, 191 | 0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L, 192 | 0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L, 193 | 0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L, 194 | 0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L, 195 | 0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L, 196 | 0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L, 197 | 0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L, 198 | 0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L, 199 | 0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L, 200 | 0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L, 201 | 0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L, 202 | 0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L, 203 | 0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L, 204 | 0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L, 205 | 0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L }; 206 | 207 | static unsigned long SP2[64] = { 208 | 0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L, 209 | 0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L, 210 | 0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L, 211 | 0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L, 212 | 0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L, 213 | 0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L, 214 | 0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L, 215 | 0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L, 216 | 0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L, 217 | 0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L, 218 | 0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L, 219 | 0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L, 220 | 0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L, 221 | 0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L, 222 | 0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L, 223 | 0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L }; 224 | 225 | static unsigned long SP3[64] = { 226 | 0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L, 227 | 0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L, 228 | 0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L, 229 | 0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L, 230 | 0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L, 231 | 0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L, 232 | 0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L, 233 | 0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L, 234 | 0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L, 235 | 0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L, 236 | 0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L, 237 | 0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L, 238 | 0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L, 239 | 0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L, 240 | 0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L, 241 | 0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L }; 242 | 243 | static unsigned long SP4[64] = { 244 | 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L, 245 | 0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L, 246 | 0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L, 247 | 0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L, 248 | 0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L, 249 | 0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L, 250 | 0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L, 251 | 0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L, 252 | 0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L, 253 | 0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L, 254 | 0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L, 255 | 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L, 256 | 0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L, 257 | 0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L, 258 | 0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L, 259 | 0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L }; 260 | 261 | static unsigned long SP5[64] = { 262 | 0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L, 263 | 0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L, 264 | 0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L, 265 | 0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L, 266 | 0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L, 267 | 0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L, 268 | 0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L, 269 | 0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L, 270 | 0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L, 271 | 0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L, 272 | 0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L, 273 | 0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L, 274 | 0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L, 275 | 0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L, 276 | 0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L, 277 | 0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L }; 278 | 279 | static unsigned long SP6[64] = { 280 | 0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L, 281 | 0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L, 282 | 0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L, 283 | 0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L, 284 | 0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L, 285 | 0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L, 286 | 0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L, 287 | 0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L, 288 | 0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L, 289 | 0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L, 290 | 0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L, 291 | 0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L, 292 | 0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L, 293 | 0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L, 294 | 0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L, 295 | 0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L }; 296 | 297 | static unsigned long SP7[64] = { 298 | 0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L, 299 | 0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L, 300 | 0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L, 301 | 0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L, 302 | 0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L, 303 | 0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L, 304 | 0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L, 305 | 0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L, 306 | 0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L, 307 | 0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L, 308 | 0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L, 309 | 0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L, 310 | 0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L, 311 | 0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L, 312 | 0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L, 313 | 0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L }; 314 | 315 | static unsigned long SP8[64] = { 316 | 0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L, 317 | 0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L, 318 | 0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L, 319 | 0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L, 320 | 0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L, 321 | 0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L, 322 | 0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L, 323 | 0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L, 324 | 0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L, 325 | 0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L, 326 | 0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L, 327 | 0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L, 328 | 0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L, 329 | 0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L, 330 | 0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L, 331 | 0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L }; 332 | 333 | static void desfunc(register unsigned long *block, 334 | register unsigned long *keys) 335 | { 336 | register unsigned long fval, work, right, leftt; 337 | register int round; 338 | 339 | leftt = block[0]; 340 | right = block[1]; 341 | work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL; 342 | right ^= work; 343 | leftt ^= (work << 4); 344 | work = ((leftt >> 16) ^ right) & 0x0000ffffL; 345 | right ^= work; 346 | leftt ^= (work << 16); 347 | work = ((right >> 2) ^ leftt) & 0x33333333L; 348 | leftt ^= work; 349 | right ^= (work << 2); 350 | work = ((right >> 8) ^ leftt) & 0x00ff00ffL; 351 | leftt ^= work; 352 | right ^= (work << 8); 353 | right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL; 354 | work = (leftt ^ right) & 0xaaaaaaaaL; 355 | leftt ^= work; 356 | right ^= work; 357 | leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL; 358 | 359 | for( round = 0; round < 8; round++ ) { 360 | work = (right << 28) | (right >> 4); 361 | work ^= *keys++; 362 | fval = SP7[ work & 0x3fL]; 363 | fval |= SP5[(work >> 8) & 0x3fL]; 364 | fval |= SP3[(work >> 16) & 0x3fL]; 365 | fval |= SP1[(work >> 24) & 0x3fL]; 366 | work = right ^ *keys++; 367 | fval |= SP8[ work & 0x3fL]; 368 | fval |= SP6[(work >> 8) & 0x3fL]; 369 | fval |= SP4[(work >> 16) & 0x3fL]; 370 | fval |= SP2[(work >> 24) & 0x3fL]; 371 | leftt ^= fval; 372 | work = (leftt << 28) | (leftt >> 4); 373 | work ^= *keys++; 374 | fval = SP7[ work & 0x3fL]; 375 | fval |= SP5[(work >> 8) & 0x3fL]; 376 | fval |= SP3[(work >> 16) & 0x3fL]; 377 | fval |= SP1[(work >> 24) & 0x3fL]; 378 | work = leftt ^ *keys++; 379 | fval |= SP8[ work & 0x3fL]; 380 | fval |= SP6[(work >> 8) & 0x3fL]; 381 | fval |= SP4[(work >> 16) & 0x3fL]; 382 | fval |= SP2[(work >> 24) & 0x3fL]; 383 | right ^= fval; 384 | } 385 | 386 | right = (right << 31) | (right >> 1); 387 | work = (leftt ^ right) & 0xaaaaaaaaL; 388 | leftt ^= work; 389 | right ^= work; 390 | leftt = (leftt << 31) | (leftt >> 1); 391 | work = ((leftt >> 8) ^ right) & 0x00ff00ffL; 392 | right ^= work; 393 | leftt ^= (work << 8); 394 | work = ((leftt >> 2) ^ right) & 0x33333333L; 395 | right ^= work; 396 | leftt ^= (work << 2); 397 | work = ((right >> 16) ^ leftt) & 0x0000ffffL; 398 | leftt ^= work; 399 | right ^= (work << 16); 400 | work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL; 401 | leftt ^= work; 402 | right ^= (work << 4); 403 | *block++ = right; 404 | *block = leftt; 405 | return; 406 | } 407 | 408 | /* Validation sets: 409 | * 410 | * Single-length key, single-length plaintext - 411 | * Key : 0123 4567 89ab cdef 412 | * Plain : 0123 4567 89ab cde7 413 | * Cipher : c957 4425 6a5e d31d 414 | * 415 | * Double-length key, single-length plaintext - 416 | * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 417 | * Plain : 0123 4567 89ab cde7 418 | * Cipher : 7f1d 0a77 826b 8aff 419 | * 420 | * Double-length key, double-length plaintext - 421 | * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 422 | * Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff 423 | * Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7 424 | * 425 | * Triple-length key, single-length plaintext - 426 | * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567 427 | * Plain : 0123 4567 89ab cde7 428 | * Cipher : de0b 7c06 ae5e 0ed5 429 | * 430 | * Triple-length key, double-length plaintext - 431 | * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567 432 | * Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff 433 | * Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5 434 | * 435 | * d3des V5.0a rwo 9208.07 18:44 Graven Imagery 436 | **********************************************************************/ 437 | -------------------------------------------------------------------------------- /d3des.h: -------------------------------------------------------------------------------- 1 | #ifndef D3DES_H 2 | #define D3DES_H 3 | 4 | /* 5 | * This is D3DES (V5.09) by Richard Outerbridge with the double and 6 | * triple-length support removed for use in VNC. 7 | * 8 | * These changes are: 9 | * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. 10 | * 11 | * This software is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | */ 15 | 16 | /* d3des.h - 17 | * 18 | * Headers and defines for d3des.c 19 | * Graven Imagery, 1992. 20 | * 21 | * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge 22 | * (GEnie : OUTER; CIS : [71755,204]) 23 | */ 24 | 25 | #define EN0 0 /* MODE == encrypt */ 26 | #define DE1 1 /* MODE == decrypt */ 27 | 28 | extern void rfbDesKey(unsigned char *, int); 29 | /* hexkey[8] MODE 30 | * Sets the internal key register according to the hexadecimal 31 | * key contained in the 8 bytes of hexkey, according to the DES, 32 | * for encryption or decryption according to MODE. 33 | */ 34 | 35 | extern void rfbUseKey(unsigned long *); 36 | /* cookedkey[32] 37 | * Loads the internal key register with the data in cookedkey. 38 | */ 39 | 40 | extern void rfbCPKey(unsigned long *); 41 | /* cookedkey[32] 42 | * Copies the contents of the internal key register into the storage 43 | * located at &cookedkey[0]. 44 | */ 45 | 46 | extern void rfbDes(unsigned char *, unsigned char *); 47 | /* from[8] to[8] 48 | * Encrypts/Decrypts (according to the key currently loaded in the 49 | * internal key register) one block of eight bytes at address 'from' 50 | * into the block at address 'to'. They can be the same. 51 | */ 52 | 53 | /* d3des.h V5.09 rwo 9208.04 15:06 Graven Imagery 54 | ********************************************************************/ 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /input.c: -------------------------------------------------------------------------------- 1 | /** 2 | * vnc2rdp: proxy for RDP client connect to VNC server 3 | * 4 | * Copyright 2014 Yiwei Li 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include "input.h" 20 | #include "log.h" 21 | #include "vnc.h" 22 | 23 | static int 24 | v2r_input_process_sync_event(v2r_rdp_t *r, v2r_packet_t *p) 25 | { 26 | uint32_t toggle_flags; 27 | 28 | /* pad2Octets */ 29 | V2R_PACKET_SEEK_UINT16(p); 30 | /* toggleFlags */ 31 | V2R_PACKET_READ_UINT32_LE(p, toggle_flags); 32 | v2r_log_debug("synchronize event with toggle_flags: 0x%x", toggle_flags); 33 | 34 | r->capslock = toggle_flags & TS_SYNC_CAPS_LOCK; 35 | r->numlock = toggle_flags & TS_SYNC_NUM_LOCK; 36 | 37 | return 0; 38 | } 39 | 40 | static int 41 | v2r_input_process_keyboard_event(v2r_rdp_t *r, v2r_packet_t *p) 42 | { 43 | uint8_t down_flag = 1; 44 | uint16_t keyboard_flags, key_code, x11_key_code; 45 | uint32_t key; 46 | 47 | V2R_PACKET_READ_UINT16_LE(p, keyboard_flags); 48 | V2R_PACKET_READ_UINT16_LE(p, key_code); 49 | V2R_PACKET_SEEK_UINT16(p); 50 | 51 | v2r_log_debug("keyboard_flags: 0x%x, key_code: 0x%x", keyboard_flags, 52 | key_code); 53 | 54 | /* translate RDP scancode to X11 keycode */ 55 | if (keyboard_flags & KBDFLAGS_EXTENDED) { 56 | x11_key_code = scancode_to_x11_keycode_map[key_code][1]; 57 | } else { 58 | x11_key_code = scancode_to_x11_keycode_map[key_code][0]; 59 | } 60 | 61 | /* if the keyboard layout is not supported currently, send nothing to 62 | * server */ 63 | if (r->keymap == NULL) { 64 | return 0; 65 | } 66 | 67 | down_flag = (keyboard_flags & KBDFLAGS_RELEASE) ? 0 : 1; 68 | /* process special scancode */ 69 | switch (key_code) { 70 | case SCANCODE_LSHIFT: 71 | r->lshift = down_flag; 72 | break; 73 | case SCANCODE_RSHIFT: 74 | r->rshift = down_flag; 75 | break; 76 | case SCANCODE_LALT: 77 | r->altgr = down_flag; 78 | case SCANCODE_CAPSLOCK: 79 | if (down_flag) { 80 | r->capslock = !r->capslock; 81 | } 82 | break; 83 | case SCANCODE_NUMLOCK: 84 | if (down_flag) { 85 | r->numlock = !r->numlock; 86 | } 87 | break; 88 | default: 89 | break; 90 | } 91 | 92 | /* get X11 KeySym by keycode and current status */ 93 | if ((79 <= x11_key_code) && (x11_key_code <= 91)) { 94 | if (r->numlock) { 95 | key = r->keymap->shift[x11_key_code]; 96 | } else { 97 | key = r->keymap->noshift[x11_key_code]; 98 | } 99 | } else if (r->lshift || r->rshift) { 100 | if (r->capslock) { 101 | key = r->keymap->shiftcapslock[x11_key_code]; 102 | } else { 103 | key = r->keymap->shift[x11_key_code]; 104 | } 105 | } else if (r->capslock) { 106 | key = r->keymap->capslock[x11_key_code]; 107 | } else if (r->altgr) { 108 | key = r->keymap->altgr[x11_key_code]; 109 | } else { 110 | key = r->keymap->noshift[x11_key_code]; 111 | } 112 | 113 | if (v2r_vnc_send_key_event(r->session->vnc, down_flag, key) == -1) { 114 | goto fail; 115 | } 116 | 117 | return 0; 118 | 119 | fail: 120 | return -1; 121 | } 122 | 123 | static int 124 | v2r_input_process_mouse_event(v2r_rdp_t *r, v2r_packet_t *p) 125 | { 126 | uint8_t button_mask = 0; 127 | static uint8_t button1_clicked, button2_clicked, button3_clicked; 128 | uint16_t pointer_flags; 129 | static uint16_t x_pos, y_pos; 130 | 131 | V2R_PACKET_READ_UINT16_LE(p, pointer_flags); 132 | if (pointer_flags & PTRFLAGS_MOVE) { 133 | V2R_PACKET_READ_UINT16_LE(p, x_pos); 134 | V2R_PACKET_READ_UINT16_LE(p, y_pos); 135 | } else { 136 | V2R_PACKET_SEEK(p, 4); 137 | } 138 | if (pointer_flags & PTRFLAGS_WHEEL) { 139 | if (pointer_flags & PTRFLAGS_WHEEL_NEGATIVE) { 140 | button_mask = RFB_POINTER_WHEEL_DOWNWARDS; 141 | } else { 142 | button_mask = RFB_POINTER_WHEEL_UPWARDS; 143 | } 144 | if (v2r_vnc_send_pointer_event(r->session->vnc, button_mask, x_pos, 145 | y_pos) == -1) { 146 | goto fail; 147 | } 148 | if (v2r_vnc_send_pointer_event(r->session->vnc, 0, x_pos, 149 | y_pos) == -1) { 150 | goto fail; 151 | } 152 | } else { 153 | if (pointer_flags & PTRFLAGS_BUTTON1) { 154 | button1_clicked = pointer_flags & PTRFLAGS_DOWN ? 1 : 0; 155 | } else if (pointer_flags & PTRFLAGS_BUTTON2) { 156 | button2_clicked = pointer_flags & PTRFLAGS_DOWN ? 1 : 0; 157 | } else if (pointer_flags & PTRFLAGS_BUTTON3) { 158 | button3_clicked = pointer_flags & PTRFLAGS_DOWN ? 1 : 0; 159 | } 160 | if (button1_clicked) { 161 | button_mask |= RFB_POINTER_BUTTON_LEFT; 162 | } 163 | if (button2_clicked) { 164 | button_mask |= RFB_POINTER_BUTTON_RIGHT; 165 | } 166 | if (button3_clicked) { 167 | button_mask |= RFB_POINTER_BUTTON_MIDDLE; 168 | } 169 | if (v2r_vnc_send_pointer_event(r->session->vnc, button_mask, x_pos, 170 | y_pos) == -1) { 171 | goto fail; 172 | } 173 | } 174 | 175 | return 0; 176 | 177 | fail: 178 | return -1; 179 | } 180 | 181 | int 182 | v2r_input_process(v2r_rdp_t *r, v2r_packet_t *p) 183 | { 184 | uint16_t i, num_events, message_type; 185 | uint32_t event_time; 186 | 187 | V2R_PACKET_READ_UINT16_LE(p, num_events); 188 | V2R_PACKET_SEEK_UINT16(p); 189 | 190 | for (i = 0; i < num_events; i++) { 191 | V2R_PACKET_READ_UINT32_LE(p, event_time); 192 | V2R_PACKET_READ_UINT16_LE(p, message_type); 193 | switch (message_type) { 194 | case INPUT_EVENT_SYNC: 195 | if (v2r_input_process_sync_event(r, p) == -1) { 196 | goto fail; 197 | } 198 | break; 199 | case INPUT_EVENT_UNUSED: 200 | V2R_PACKET_SEEK(p, 6); 201 | break; 202 | case INPUT_EVENT_SCANCODE: 203 | if (v2r_input_process_keyboard_event(r, p) == -1) { 204 | goto fail; 205 | } 206 | break; 207 | case INPUT_EVENT_UNICODE: 208 | V2R_PACKET_SEEK(p, 6); 209 | break; 210 | case INPUT_EVENT_MOUSE: 211 | if (v2r_input_process_mouse_event(r, p) == -1) { 212 | goto fail; 213 | } 214 | break; 215 | case INPUT_EVENT_MOUSEX: 216 | V2R_PACKET_SEEK(p, 6); 217 | break; 218 | default: 219 | v2r_log_warn("unknown input event message type 0x%x", message_type); 220 | break; 221 | } 222 | } 223 | 224 | return 0; 225 | 226 | fail: 227 | return -1; 228 | } 229 | -------------------------------------------------------------------------------- /input.h: -------------------------------------------------------------------------------- 1 | /** 2 | * vnc2rdp: proxy for RDP client connect to VNC server 3 | * 4 | * Copyright 2014 Yiwei Li 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef _INPUT_H_ 20 | #define _INPUT_H_ 21 | 22 | #include "rdp.h" 23 | 24 | /* Slow-Path Input Event - messageType */ 25 | #define INPUT_EVENT_SYNC 0x0000 26 | #define INPUT_EVENT_UNUSED 0x0002 27 | #define INPUT_EVENT_SCANCODE 0x0004 28 | #define INPUT_EVENT_UNICODE 0x0005 29 | #define INPUT_EVENT_MOUSE 0x8001 30 | #define INPUT_EVENT_MOUSEX 0x8002 31 | 32 | /* Keyboard Event - keyboardFlags */ 33 | #define KBDFLAGS_EXTENDED 0x0100 34 | #define KBDFLAGS_DOWN 0x4000 35 | #define KBDFLAGS_RELEASE 0x8000 36 | 37 | /* Mouse Event - pointerFlags */ 38 | #define PTRFLAGS_HWHEEL 0x0400 39 | #define PTRFLAGS_WHEEL 0x0200 40 | #define PTRFLAGS_WHEEL_NEGATIVE 0x0100 41 | #define WheelRotationMask 0x01FF 42 | #define PTRFLAGS_MOVE 0x0800 43 | #define PTRFLAGS_DOWN 0x8000 44 | #define PTRFLAGS_BUTTON1 0x1000 45 | #define PTRFLAGS_BUTTON2 0x2000 46 | #define PTRFLAGS_BUTTON3 0x4000 47 | #define PTRFLAGS_BUTTON_ALL 0x7000 48 | 49 | /* Synchronize Event - toggleFlags */ 50 | #define TS_SYNC_SCROLL_LOCK 0x00000001 51 | #define TS_SYNC_NUM_LOCK 0x00000002 52 | #define TS_SYNC_CAPS_LOCK 0x00000004 53 | #define TS_SYNC_KANA_LOCK 0x00000008 54 | 55 | extern int v2r_input_process(v2r_rdp_t *r, v2r_packet_t *p); 56 | 57 | #endif // _INPUT_H_ 58 | -------------------------------------------------------------------------------- /keymaps.c: -------------------------------------------------------------------------------- 1 | #include "keymaps.h" 2 | 3 | uint8_t scancode_to_x11_keycode_map[][2] = { 4 | { 0, 0 }, 5 | { 9, 0 }, 6 | { 10, 0 }, 7 | { 11, 0 }, 8 | { 12, 0 }, 9 | { 13, 0 }, 10 | { 14, 0 }, 11 | { 15, 0 }, 12 | { 16, 0 }, 13 | { 17, 0 }, 14 | { 18, 0 }, 15 | { 19, 0 }, 16 | { 20, 0 }, 17 | { 21, 0 }, 18 | { 22, 0 }, 19 | { 23, 0 }, 20 | { 24, 0 }, 21 | { 25, 0 }, 22 | { 26, 0 }, 23 | { 27, 0 }, 24 | { 28, 0 }, 25 | { 29, 0 }, 26 | { 30, 0 }, 27 | { 31, 0 }, 28 | { 32, 0 }, 29 | { 33, 0 }, 30 | { 34, 0 }, 31 | { 35, 0 }, 32 | { 36, 108 }, 33 | { 37, 109 }, 34 | { 38, 0 }, 35 | { 39, 0 }, 36 | { 40, 0 }, 37 | { 41, 0 }, 38 | { 42, 0 }, 39 | { 43, 0 }, 40 | { 44, 0 }, 41 | { 45, 0 }, 42 | { 46, 0 }, 43 | { 47, 0 }, 44 | { 48, 0 }, 45 | { 49, 0 }, 46 | { 50, 0 }, 47 | { 51, 0 }, 48 | { 52, 0 }, 49 | { 53, 0 }, 50 | { 54, 0 }, 51 | { 55, 0 }, 52 | { 56, 0 }, 53 | { 57, 0 }, 54 | { 58, 0 }, 55 | { 59, 0 }, 56 | { 60, 0 }, 57 | { 61, 112 }, 58 | { 62, 0 }, 59 | { 63, 111 }, 60 | { 64, 113 }, 61 | { 65, 0 }, 62 | { 66, 0 }, 63 | { 67, 0 }, 64 | { 68, 0 }, 65 | { 69, 0 }, 66 | { 70, 0 }, 67 | { 71, 0 }, 68 | { 72, 0 }, 69 | { 73, 0 }, 70 | { 74, 0 }, 71 | { 75, 0 }, 72 | { 76, 0 }, 73 | { 77, 0 }, 74 | { 78, 0 }, 75 | { 79, 97 }, 76 | { 80, 98 }, 77 | { 81, 99 }, 78 | { 82, 0 }, 79 | { 83, 100 }, 80 | { 84, 0 }, 81 | { 85, 102 }, 82 | { 86, 0 }, 83 | { 87, 103 }, 84 | { 88, 104 }, 85 | { 89, 105 }, 86 | { 90, 106 }, 87 | { 91, 107 }, 88 | { 92, 0 }, 89 | { 93, 0 }, 90 | { 94, 0 }, 91 | { 95, 0 }, 92 | { 96, 0 }, 93 | { 97, 0 }, 94 | { 98, 0 }, 95 | { 0, 115 }, 96 | { 0, 116 }, 97 | { 0, 117 }, 98 | { 102, 0 }, 99 | { 103, 0 }, 100 | { 104, 0 }, 101 | { 105, 0 }, 102 | { 106, 0 }, 103 | { 107, 0 }, 104 | { 108, 0 }, 105 | { 109, 0 }, 106 | { 110, 0 }, 107 | { 111, 0 }, 108 | { 112, 0 }, 109 | { 113, 0 }, 110 | { 114, 0 }, 111 | { 115, 0 }, 112 | { 116, 0 }, 113 | { 117, 0 }, 114 | { 118, 0 }, 115 | { 119, 0 }, 116 | { 120, 0 }, 117 | { 121, 0 }, 118 | { 122, 0 }, 119 | { 123, 0 }, 120 | { 124, 0 }, 121 | { 125, 0 }, 122 | { 126, 0 }, 123 | { 127, 0 }, 124 | { 128, 0 }, 125 | { 129, 0 }, 126 | { 130, 0 }, 127 | { 131, 0 }, 128 | { 132, 0 }, 129 | { 133, 0 }, 130 | { 134, 0 }, 131 | { 135, 0 } 132 | }; 133 | 134 | static v2r_keymap_t keymap_us = { 135 | .noshift = { 136 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 137 | 0x0000, 0xff1b, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 138 | 0x0037, 0x0038, 0x0039, 0x0030, 0x002d, 0x003d, 0xff08, 0xff09, 139 | 0x0071, 0x0077, 0x0065, 0x0072, 0x0074, 0x0079, 0x0075, 0x0069, 140 | 0x006f, 0x0070, 0x005b, 0x005d, 0xff0d, 0xffe3, 0x0061, 0x0073, 141 | 0x0064, 0x0066, 0x0067, 0x0068, 0x006a, 0x006b, 0x006c, 0x003b, 142 | 0x0027, 0x0060, 0xffe1, 0x005c, 0x007a, 0x0078, 0x0063, 0x0076, 143 | 0x0062, 0x006e, 0x006d, 0x002c, 0x002e, 0x002f, 0xffe2, 0xffaa, 144 | 0xffe9, 0x0020, 0xffe5, 0xffbe, 0xffbf, 0xffc0, 0xffc1, 0xffc2, 145 | 0xffc3, 0xffc4, 0xffc5, 0xffc6, 0xffc7, 0xff7f, 0xff14, 0xff95, 146 | 0xff97, 0xff9a, 0xffad, 0xff96, 0xff9d, 0xff98, 0xffab, 0xff9c, 147 | 0xff99, 0xff9b, 0xff9e, 0xff9f, 0x0000, 0xff7e, 0x003c, 0xffc8, 148 | 0xffc9, 0xff50, 0xff52, 0xff55, 0xff51, 0x0000, 0xff53, 0xff57, 149 | 0xff54, 0xff56, 0xff63, 0xffff, 0xff8d, 0xffe4, 0xff13, 0xff61, 150 | 0xffaf, 0xffea, 0x0000, 0xffeb, 0xffec, 0xff67, 0x0000, 0x0000, 151 | 0x0000, 0x0000, 0x0000, 0x0000, 0xfe03, 0x0000, 0xffbd, 0x0000, 152 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 153 | 0x0000, 0x0000 154 | }, 155 | .shift = { 156 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 157 | 0x0000, 0xff1b, 0x0021, 0x0040, 0x0023, 0x0024, 0x0025, 0x005e, 158 | 0x0026, 0x002a, 0x0028, 0x0029, 0x005f, 0x002b, 0xff08, 0xfe20, 159 | 0x0051, 0x0057, 0x0045, 0x0052, 0x0054, 0x0059, 0x0055, 0x0049, 160 | 0x004f, 0x0050, 0x007b, 0x007d, 0xff0d, 0xffe3, 0x0041, 0x0053, 161 | 0x0044, 0x0046, 0x0047, 0x0048, 0x004a, 0x004b, 0x004c, 0x003a, 162 | 0x0022, 0x007e, 0xffe1, 0x007c, 0x005a, 0x0058, 0x0043, 0x0056, 163 | 0x0042, 0x004e, 0x004d, 0x003c, 0x003e, 0x003f, 0xffe2, 0xffaa, 164 | 0xffe7, 0x0020, 0xffe5, 0xffbe, 0xffbf, 0xffc0, 0xffc1, 0xffc2, 165 | 0xffc3, 0xffc4, 0xffc5, 0xffc6, 0xffc7, 0xfef9, 0xff14, 0xffb7, 166 | 0xffb8, 0xffb9, 0xffad, 0xffb4, 0xffb5, 0xffb6, 0xffab, 0xffb1, 167 | 0xffb2, 0xffb3, 0xffb0, 0xffae, 0x0000, 0xff7e, 0x003e, 0xffc8, 168 | 0xffc9, 0xff50, 0xff52, 0xff55, 0xff51, 0x0000, 0xff53, 0xff57, 169 | 0xff54, 0xff56, 0xff63, 0xffff, 0xff8d, 0xffe4, 0xff13, 0xff61, 170 | 0xffaf, 0xffe8, 0x0000, 0xffeb, 0xffec, 0xff67, 0x0000, 0x0000, 171 | 0x0000, 0x0000, 0x0000, 0x0000, 0xfe03, 0xffe9, 0xffbd, 0xffeb, 172 | 0xffed, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 173 | 0x0000, 0x0000 174 | }, 175 | .capslock = { 176 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 177 | 0x0000, 0xff1b, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 178 | 0x0037, 0x0038, 0x0039, 0x0030, 0x002d, 0x003d, 0xff08, 0xff09, 179 | 0x0051, 0x0057, 0x0045, 0x0052, 0x0054, 0x0059, 0x0055, 0x0049, 180 | 0x004f, 0x0050, 0x005b, 0x005d, 0xff0d, 0xffe3, 0x0041, 0x0053, 181 | 0x0044, 0x0046, 0x0047, 0x0048, 0x004a, 0x004b, 0x004c, 0x003b, 182 | 0x0027, 0x0060, 0xffe1, 0x005c, 0x005a, 0x0058, 0x0043, 0x0056, 183 | 0x0042, 0x004e, 0x004d, 0x002c, 0x002e, 0x002f, 0xffe2, 0xffaa, 184 | 0xffe9, 0x0020, 0xffe5, 0xffbe, 0xffbf, 0xffc0, 0xffc1, 0xffc2, 185 | 0xffc3, 0xffc4, 0xffc5, 0xffc6, 0xffc7, 0xff7f, 0xff14, 0xff95, 186 | 0xff97, 0xff9a, 0xffad, 0xff96, 0xff9d, 0xff98, 0xffab, 0xff9c, 187 | 0xff99, 0xff9b, 0xff9e, 0xff9f, 0x0000, 0xff7e, 0x003c, 0xffc8, 188 | 0xffc9, 0xff50, 0xff52, 0xff55, 0xff51, 0x0000, 0xff53, 0xff57, 189 | 0xff54, 0xff56, 0xff63, 0xffff, 0xff8d, 0xffe4, 0xff13, 0xff61, 190 | 0xffaf, 0xffea, 0x0000, 0xffeb, 0xffec, 0xff67, 0x0000, 0x0000, 191 | 0x0000, 0x0000, 0x0000, 0x0000, 0xfe03, 0x0000, 0xffbd, 0x0000, 192 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 193 | 0x0000, 0x0000 194 | }, 195 | .altgr = { 196 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 197 | 0x0000, 0xff1b, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 198 | 0x0037, 0x0038, 0x0039, 0x0030, 0x002d, 0x003d, 0xff08, 0xff09, 199 | 0x0071, 0x0077, 0x0065, 0x0072, 0x0074, 0x0079, 0x0075, 0x0069, 200 | 0x006f, 0x0070, 0x005b, 0x005d, 0xff0d, 0xffe3, 0x0061, 0x0073, 201 | 0x0064, 0x0066, 0x0067, 0x0068, 0x006a, 0x006b, 0x006c, 0x003b, 202 | 0x0027, 0x0060, 0xffe1, 0x005c, 0x007a, 0x0078, 0x0063, 0x0076, 203 | 0x0062, 0x006e, 0x006d, 0x002c, 0x002e, 0x002f, 0xffe2, 0xffaa, 204 | 0xffe9, 0x0020, 0xffe5, 0xffbe, 0xffbf, 0xffc0, 0xffc1, 0xffc2, 205 | 0xffc3, 0xffc4, 0xffc5, 0xffc6, 0xffc7, 0xff7f, 0xff14, 0xff95, 206 | 0xff97, 0xff9a, 0xffad, 0xff96, 0xff9d, 0xff98, 0xffab, 0xff9c, 207 | 0xff99, 0xff9b, 0xff9e, 0xff9f, 0x0000, 0xff7e, 0x007c, 0xffc8, 208 | 0xffc9, 0xff50, 0xff52, 0xff55, 0xff51, 0x0000, 0xff53, 0xff57, 209 | 0xff54, 0xff56, 0xff63, 0xffff, 0xff8d, 0xffe4, 0xff13, 0x0000, 210 | 0xffaf, 0xffea, 0x0000, 0xffeb, 0xffec, 0xff67, 0x0000, 0x0000, 211 | 0x0000, 0x0000, 0x0000, 0x0000, 0xfe03, 0x0000, 0xffbd, 0x0000, 212 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 213 | 0x0000, 0x0000 214 | }, 215 | .shiftcapslock = { 216 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 217 | 0x0000, 0xff1b, 0x0021, 0x0040, 0x0023, 0x0024, 0x0025, 0x005e, 218 | 0x0026, 0x002a, 0x0028, 0x0029, 0x005f, 0x002b, 0xff08, 0xfe20, 219 | 0x0071, 0x0077, 0x0065, 0x0072, 0x0074, 0x0079, 0x0075, 0x0069, 220 | 0x006f, 0x0070, 0x007b, 0x007d, 0xff0d, 0xffe3, 0x0061, 0x0073, 221 | 0x0064, 0x0066, 0x0067, 0x0068, 0x006a, 0x006b, 0x006c, 0x003a, 222 | 0x0022, 0x007e, 0xffe1, 0x007c, 0x007a, 0x0078, 0x0063, 0x0076, 223 | 0x0062, 0x006e, 0x006d, 0x003c, 0x003e, 0x003f, 0xffe2, 0xffaa, 224 | 0xffe7, 0x0020, 0xffe5, 0xffbe, 0xffbf, 0xffc0, 0xffc1, 0xffc2, 225 | 0xffc3, 0xffc4, 0xffc5, 0xffc6, 0xffc7, 0xfef9, 0xff14, 0xffb7, 226 | 0xffb8, 0xffb9, 0xffad, 0xffb4, 0xffb5, 0xffb6, 0xffab, 0xffb1, 227 | 0xffb2, 0xffb3, 0xffb0, 0xffae, 0x0000, 0xff7e, 0x003e, 0xffc8, 228 | 0xffc9, 0xff50, 0xff52, 0xff55, 0xff51, 0x0000, 0xff53, 0xff57, 229 | 0xff54, 0xff56, 0xff63, 0xffff, 0xff8d, 0xffe4, 0xff13, 0xff61, 230 | 0xffaf, 0xffe8, 0x0000, 0xffeb, 0xffec, 0xff67, 0x0000, 0x0000, 231 | 0x0000, 0x0000, 0x0000, 0x0000, 0xfe03, 0xffe9, 0xffbd, 0xffeb, 232 | 0xffed, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 233 | 0x0000, 0x0000 234 | } 235 | }; 236 | 237 | v2r_keymap_t * 238 | get_keymap_by_layout(uint32_t keyboard_layout) 239 | { 240 | v2r_keymap_t *k = 0; 241 | 242 | switch (keyboard_layout) { 243 | case KEYBOARD_LAYOUT_US: 244 | case KEYBOARD_LAYOUT_CHINESE_SIMPLIFIED: 245 | default: 246 | k = &keymap_us; 247 | break; 248 | } 249 | 250 | return k; 251 | } 252 | -------------------------------------------------------------------------------- /keymaps.h: -------------------------------------------------------------------------------- 1 | /** 2 | * vnc2rdp: proxy for RDP client connect to VNC server 3 | * 4 | * Copyright 2014 Yiwei Li 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef _KEYMAPS_H_ 20 | #define _KEYMAPS_H_ 21 | 22 | #include 23 | 24 | #define SCANCODE_LSHIFT 0x2a 25 | #define SCANCODE_RSHIFT 0x36 26 | #define SCANCODE_LALT 0x38 27 | #define SCANCODE_CAPSLOCK 0x3a 28 | #define SCANCODE_NUMLOCK 0x45 29 | 30 | #define KEYBOARD_LAYOUT_US 0x00000409 31 | #define KEYBOARD_LAYOUT_CHINESE_SIMPLIFIED 0x00000804 32 | 33 | typedef struct _v2r_keymap_t { 34 | uint32_t noshift[256]; 35 | uint32_t shift[256]; 36 | uint32_t altgr[256]; 37 | uint32_t capslock[256]; 38 | uint32_t shiftcapslock[256]; 39 | } v2r_keymap_t; 40 | 41 | extern uint8_t scancode_to_x11_keycode_map[][2]; 42 | extern v2r_keymap_t *get_keymap_by_layout(uint32_t keyboard_layout); 43 | 44 | #endif // _KEYMAPS_H_ 45 | -------------------------------------------------------------------------------- /license.h: -------------------------------------------------------------------------------- 1 | /** 2 | * vnc2rdp: proxy for RDP client connect to VNC server 3 | * 4 | * Copyright 2014 Yiwei Li 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef _LICENSE_H_ 20 | #define _LICENSE_H_ 21 | 22 | /* bMsgType */ 23 | #define LICENSE_REQUEST 0x01 24 | #define PLATFORM_CHALLENGE 0x02 25 | #define NEW_LICENSE 0x03 26 | #define UPGRADE_LICENSE 0x04 27 | #define LICENSE_INFO 0x12 28 | #define NEW_LICENSE_REQUEST 0x13 29 | #define PLATFORM_CHALLENGE_RESPONSE 0x15 30 | #define ERROR_ALERT 0xFF 31 | 32 | /* flags */ 33 | #define LicenseProtocolVersionMask 0x0F 34 | #define EXTENDED_ERROR_MSG_SUPPORTED 0x80 35 | #define PREAMBLE_VERSION_2_0 0x2 36 | #define PREAMBLE_VERSION_3_0 0x3 37 | 38 | /* wBlobType */ 39 | #define BB_DATA_BLOB 0x0001 40 | #define BB_RANDOM_BLOB 0x0002 41 | #define BB_CERTIFICATE_BLOB 0x0003 42 | #define BB_ERROR_BLOB 0x0004 43 | #define BB_ENCRYPTED_DATA_BLOB 0x0009 44 | #define BB_KEY_EXCHG_ALG_BLOB 0x000D 45 | #define BB_SCOPE_BLOB 0x000E 46 | #define BB_CLIENT_USER_NAME_BLOB 0x000F 47 | #define BB_CLIENT_MACHINE_NAME_BLOB 0x0010 48 | 49 | /* dwErrorCode */ 50 | #define ERR_INVALID_SERVER_CERTIFICATE 0x00000001 51 | #define ERR_NO_LICENSE 0x00000002 52 | #define ERR_INVALID_SCOPE 0x00000004 53 | #define ERR_NO_LICENSE_SERVER 0x00000006 54 | #define STATUS_VALID_CLIENT 0x00000007 55 | #define ERR_INVALID_CLIENT 0x00000008 56 | #define ERR_INVALID_PRODUCTID 0x0000000B 57 | #define ERR_INVALID_MESSAGE_LEN 0x0000000C 58 | #define ERR_INVALID_MAC 0x00000003 59 | 60 | /* dwStateTransition */ 61 | #define ST_TOTAL_ABORT 0x00000001 62 | #define ST_NO_TRANSITION 0x00000002 63 | #define ST_RESET_PHASE_TO_START 0x00000003 64 | #define ST_RESEND_LAST_MESSAGE 0x00000004 65 | 66 | #endif // _LICENSE_H_ 67 | -------------------------------------------------------------------------------- /log.c: -------------------------------------------------------------------------------- 1 | /** 2 | * vnc2rdp: proxy for RDP client connect to VNC server 3 | * 4 | * Copyright 2014 Yiwei Li 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "log.h" 27 | 28 | static const char *v2r_log_level_str[5] = { 29 | "DEBUG", "INFO", "WARN", "ERROR", "FATAL" 30 | }; 31 | 32 | void v2r_log(uint8_t level, const char *file, int line, const char *fmt, ...) 33 | { 34 | char log_data[V2R_LOG_MAX_LEN]; 35 | char *ptr = log_data; 36 | time_t current_time = time(NULL); 37 | struct tm t; 38 | va_list ap; 39 | 40 | /* 获取当前时间 */ 41 | localtime_r(¤t_time, &t); 42 | /* 格式化日志头部 */ 43 | ptr += snprintf(log_data, sizeof(log_data), 44 | "[%4d/%02d/%02d %02d:%02d:%02d] [%u] [%s] [%s:%d] ", 45 | t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, 46 | t.tm_sec, getpid(), v2r_log_level_str[level], file, line); 47 | /* 添加日志信息 */ 48 | va_start(ap, fmt); 49 | vsnprintf(ptr, sizeof(log_data) - (ptr - log_data), fmt, ap); 50 | va_end(ap); 51 | printf("%s\n", log_data); 52 | } 53 | -------------------------------------------------------------------------------- /log.h: -------------------------------------------------------------------------------- 1 | /** 2 | * vnc2rdp: proxy for RDP client connect to VNC server 3 | * 4 | * Copyright 2014 Yiwei Li 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef _V2R_LOG_H_ 20 | #define _V2R_LOG_H_ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #define V2R_LOG_MAX_LEN 2048 27 | 28 | #define V2R_LOG_DEBUG 0 29 | #define V2R_LOG_INFO 1 30 | #define V2R_LOG_WARN 2 31 | #define V2R_LOG_ERROR 3 32 | #define V2R_LOG_FATAL 4 33 | 34 | #ifndef NDEBUG 35 | #define v2r_log_debug(...) \ 36 | v2r_log(V2R_LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) 37 | #else 38 | #define v2r_log_debug(...) 39 | #endif 40 | 41 | #define v2r_log_info(...) \ 42 | v2r_log(V2R_LOG_INFO, __FILE__, __LINE__, __VA_ARGS__) 43 | #define v2r_log_warn(...) \ 44 | v2r_log(V2R_LOG_WARN, __FILE__, __LINE__, __VA_ARGS__) 45 | #define v2r_log_error(...) \ 46 | v2r_log(V2R_LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__) 47 | #define v2r_log_fatal(...) \ 48 | v2r_log(V2R_LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__) 49 | 50 | #define ERRMSG strerror(errno) 51 | 52 | void v2r_log(uint8_t level, const char *file, int line, const char *fmt, ...); 53 | 54 | #endif // _V2R_LOG_H_ 55 | -------------------------------------------------------------------------------- /mcs.c: -------------------------------------------------------------------------------- 1 | /** 2 | * vnc2rdp: proxy for RDP client connect to VNC server 3 | * 4 | * Copyright 2014 Yiwei Li 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | #include "log.h" 23 | #include "mcs.h" 24 | #include "rdp.h" 25 | #include "sec.h" 26 | #include "tpkt.h" 27 | 28 | static int 29 | v2r_mcs_parse_ber_encoding(v2r_packet_t *p, uint16_t identifier, 30 | uint16_t *length) 31 | { 32 | /* BER-encoding see http://en.wikipedia.org/wiki/X.690 */ 33 | uint16_t id, len, i, l; 34 | 35 | if (identifier > 0xFF) { 36 | V2R_PACKET_READ_UINT16_BE(p, id); 37 | } else { 38 | V2R_PACKET_READ_UINT8(p, id); 39 | } 40 | if (id != identifier) { 41 | return -1; 42 | } 43 | V2R_PACKET_READ_UINT8(p, len); 44 | if (len & 0x80) { 45 | len &= ~0x80; 46 | *length = 0; 47 | for (i = 0; i < len; i++) { 48 | V2R_PACKET_READ_UINT8(p, l); 49 | *length = (*length << 8) | l; 50 | } 51 | } else { 52 | *length = len; 53 | } 54 | return 0; 55 | } 56 | 57 | static int 58 | v2r_mcs_parse_client_core_data(v2r_packet_t *p, v2r_mcs_t *m) 59 | { 60 | uint32_t version; 61 | 62 | /* version */ 63 | V2R_PACKET_READ_UINT32_LE(p, version); 64 | v2r_log_info("client RDP version number: 0x%08x", version); 65 | /* desktopWidth */ 66 | V2R_PACKET_SEEK_UINT16(p); 67 | /* desktopHeight */ 68 | V2R_PACKET_SEEK_UINT16(p); 69 | /* colorDepth */ 70 | V2R_PACKET_SEEK_UINT16(p); 71 | /* SASSequence */ 72 | V2R_PACKET_SEEK_UINT16(p); 73 | /* keyboardLayout */ 74 | V2R_PACKET_READ_UINT32_LE(p, m->keyboard_layout); 75 | v2r_log_info("client keyboard layout: 0x%08x", m->keyboard_layout); 76 | 77 | return 0; 78 | } 79 | 80 | static int 81 | v2r_mcs_parse_client_security_data(v2r_packet_t *p, v2r_mcs_t *m) 82 | { 83 | /* encryptionMethods */ 84 | V2R_PACKET_READ_UINT32_LE(p, m->encryption_methods); 85 | v2r_log_info("client support encryption methods: 0x%x", 86 | m->encryption_methods); 87 | return 0; 88 | } 89 | 90 | static int 91 | v2r_mcs_parse_client_network_data(v2r_packet_t *p, v2r_mcs_t *m) 92 | { 93 | uint16_t channel_def_array_size = 0; 94 | 95 | V2R_PACKET_READ_UINT32_LE(p, m->channel_count); 96 | if (m->channel_count > MAX_CHANNELS_ALLOWED) { 97 | goto fail; 98 | } 99 | channel_def_array_size = m->channel_count * sizeof(channel_def_t); 100 | if (!V2R_PACKET_READ_REMAIN(p, channel_def_array_size)) { 101 | goto fail; 102 | } 103 | if (m->channel_count != 0) { 104 | m->channel_def_array = (channel_def_t *)malloc(channel_def_array_size); 105 | V2R_PACKET_READ_N(p, m->channel_def_array, channel_def_array_size); 106 | } 107 | 108 | return 0; 109 | 110 | fail: 111 | return -1; 112 | } 113 | 114 | static int 115 | v2r_mcs_recv_conn_init(v2r_packet_t *p, v2r_mcs_t *m) 116 | { 117 | uint16_t len = 0; 118 | uint8_t *header = NULL; 119 | uint16_t type = 0, length; 120 | 121 | if (v2r_x224_recv(m->x224, p) == -1) { 122 | goto fail; 123 | } 124 | /* parse connect-initial header */ 125 | if (v2r_mcs_parse_ber_encoding(p, BER_TAG_CONNECT_INITIAL, &len) == -1) { 126 | goto fail; 127 | } 128 | /* parse callingDomainSelector */ 129 | if (v2r_mcs_parse_ber_encoding(p, BER_TAG_OCTET_STRING, &len) == -1) { 130 | goto fail; 131 | } 132 | V2R_PACKET_SEEK(p, len); 133 | /* parse calledDomainSelector */ 134 | if (v2r_mcs_parse_ber_encoding(p, BER_TAG_OCTET_STRING, &len) == -1) { 135 | goto fail; 136 | } 137 | V2R_PACKET_SEEK(p, len); 138 | /* parse upwardFlag */ 139 | if (v2r_mcs_parse_ber_encoding(p, BER_TAG_BOOLEAN, &len) == -1) { 140 | goto fail; 141 | } 142 | V2R_PACKET_SEEK(p, len); 143 | /* parse targetParameters */ 144 | if (v2r_mcs_parse_ber_encoding(p, BER_TAG_DOMAIN_PARAMETERS, &len) 145 | == -1) { 146 | goto fail; 147 | } 148 | V2R_PACKET_SEEK(p, len); 149 | /* parse minimumParameters */ 150 | if (v2r_mcs_parse_ber_encoding(p, BER_TAG_DOMAIN_PARAMETERS, &len) 151 | == -1) { 152 | goto fail; 153 | } 154 | V2R_PACKET_SEEK(p, len); 155 | /* parse maximumParameters */ 156 | if (v2r_mcs_parse_ber_encoding(p, BER_TAG_DOMAIN_PARAMETERS, &len) 157 | == -1) { 158 | goto fail; 159 | } 160 | V2R_PACKET_SEEK(p, len); 161 | /* parse userData */ 162 | if (v2r_mcs_parse_ber_encoding(p, BER_TAG_OCTET_STRING, &len) == -1) { 163 | goto fail; 164 | } 165 | /* parse data segments */ 166 | if (!V2R_PACKET_READ_REMAIN(p, GCCCCRQ_HEADER_LEN)) { 167 | goto fail; 168 | } 169 | V2R_PACKET_SEEK(p, GCCCCRQ_HEADER_LEN); 170 | while (V2R_PACKET_READ_REMAIN(p, TS_UD_HEADER_LEN)) { 171 | header = p->current; 172 | /* parse user data header */ 173 | V2R_PACKET_READ_UINT16_LE(p, type); 174 | V2R_PACKET_READ_UINT16_LE(p, length); 175 | if (length < TS_UD_HEADER_LEN || 176 | !V2R_PACKET_READ_REMAIN(p, length - TS_UD_HEADER_LEN)) { 177 | goto fail; 178 | } 179 | switch (type) { 180 | case CS_CORE: 181 | if (v2r_mcs_parse_client_core_data(p, m) == -1) { 182 | goto fail; 183 | } 184 | break; 185 | case CS_SECURITY: 186 | if (v2r_mcs_parse_client_security_data(p, m) == -1) { 187 | goto fail; 188 | } 189 | break; 190 | case CS_NET: 191 | if (v2r_mcs_parse_client_network_data(p, m) == -1) { 192 | goto fail; 193 | } 194 | break; 195 | case CS_CLUSTER: 196 | break; 197 | default: 198 | break; 199 | } 200 | p->current = header + length; 201 | } 202 | 203 | return 0; 204 | 205 | fail: 206 | return -1; 207 | } 208 | 209 | static int 210 | v2r_mcs_write_ber_encoding(v2r_packet_t *p, uint16_t identifier, 211 | uint16_t length) 212 | { 213 | /* BER-encoding see http://en.wikipedia.org/wiki/X.690 */ 214 | if (identifier > 0xFF) { 215 | V2R_PACKET_WRITE_UINT16_BE(p, identifier); 216 | } else { 217 | V2R_PACKET_WRITE_UINT8(p, identifier); 218 | } 219 | if (length >= 0x80) { 220 | V2R_PACKET_WRITE_UINT8(p, 0x82); 221 | V2R_PACKET_WRITE_UINT16_BE(p, length); 222 | } else { 223 | V2R_PACKET_WRITE_UINT8(p, length); 224 | } 225 | return 0; 226 | } 227 | 228 | static int 229 | v2r_mcs_write_server_security_data(v2r_packet_t *p, v2r_mcs_t *m) 230 | { 231 | uint8_t *p_length = NULL, *p_current = NULL; 232 | 233 | V2R_PACKET_WRITE_UINT16_LE(p, SC_SECURITY); 234 | p_length = p->current; 235 | V2R_PACKET_SEEK_UINT16(p); 236 | V2R_PACKET_WRITE_UINT32_LE(p, m->session->opt->encryption_method); 237 | if (m->session->opt->encryption_method == ENCRYPTION_METHOD_NONE) { 238 | V2R_PACKET_WRITE_UINT32_LE(p, ENCRYPTION_LEVEL_NONE); 239 | } else { 240 | V2R_PACKET_WRITE_UINT32_LE(p, ENCRYPTION_LEVEL_CLIENT_COMPATIBLE); 241 | } 242 | if (m->session->opt->encryption_method == ENCRYPTION_METHOD_NONE) { 243 | /* serverRandomLen */ 244 | V2R_PACKET_WRITE_UINT32_LE(p, 0); 245 | /* serverCertLen */ 246 | V2R_PACKET_WRITE_UINT32_LE(p, 0); 247 | } else { 248 | /* serverRandomLen */ 249 | V2R_PACKET_WRITE_UINT32_LE(p, 32); 250 | /* serverCertLen, the length of server certificate is fixed 184 */ 251 | V2R_PACKET_WRITE_UINT32_LE(p, 184); 252 | /* serverRandom */ 253 | if (v2r_sec_generate_server_random(m->session->rdp->sec) == -1) { 254 | goto fail; 255 | } 256 | V2R_PACKET_WRITE_N(p, m->session->rdp->sec->server_random, 257 | SERVER_RANDOM_LEN); 258 | /* serverCertificate */ 259 | if (v2r_sec_write_server_certificate(m->session->rdp->sec, p) == -1) { 260 | goto fail; 261 | } 262 | } 263 | p_current = p->current; 264 | p->current = p_length; 265 | V2R_PACKET_WRITE_UINT16_LE(p, p_current - p_length + 2); 266 | p->current = p_current; 267 | 268 | return 0; 269 | 270 | fail: 271 | return -1; 272 | } 273 | 274 | static int 275 | v2r_mcs_send_conn_resp(v2r_packet_t *p, v2r_mcs_t *m) 276 | { 277 | v2r_packet_t *u = NULL; 278 | uint8_t gccccrsp_header[] = { 279 | 0x00, 0x05, 0x00, 0x14, 0x7c, 0x00, 0x01, 0x2a, 0x14, 0x76, 280 | 0x0a, 0x01, 0x01, 0x00, 0x01, 0xc0, 0x00, 0x4d, 0x63, 0x44, 281 | 0x6e 282 | }; 283 | uint16_t i = 0, mcs_rsp_len = 0; 284 | uint16_t channel_count_even = m->channel_count + (m->channel_count & 1); 285 | 286 | u = v2r_packet_init(4096); 287 | if (u == NULL) { 288 | goto fail; 289 | } 290 | 291 | /* GCC layer header */ 292 | V2R_PACKET_WRITE_N(u, gccccrsp_header, sizeof(gccccrsp_header)); 293 | /* next content length */ 294 | V2R_PACKET_WRITE_UINT8(u, 0x2C + channel_count_even * 2); 295 | 296 | /* Server Core Data */ 297 | V2R_PACKET_WRITE_UINT16_LE(u, SC_CORE); 298 | V2R_PACKET_WRITE_UINT16_LE(u, 16); 299 | V2R_PACKET_WRITE_UINT32_LE(u, 0x00080004); 300 | V2R_PACKET_WRITE_UINT32_LE(u, m->x224->requested_protocols); 301 | V2R_PACKET_WRITE_UINT32_LE(u, 0x00000000); 302 | 303 | /* Server Security Data */ 304 | if (v2r_mcs_write_server_security_data(u, m) == -1) { 305 | goto fail; 306 | } 307 | 308 | /* Server Network Data */ 309 | V2R_PACKET_WRITE_UINT16_LE(u, SC_NET); 310 | V2R_PACKET_WRITE_UINT16_LE(u, 8 + 2 * channel_count_even); 311 | V2R_PACKET_WRITE_UINT16_LE(u, MCS_IO_CHANNEL_ID); 312 | V2R_PACKET_WRITE_UINT16_LE(u, m->channel_count); 313 | for (i = 0; i < channel_count_even; i++) { 314 | if (i < m->channel_count) { 315 | V2R_PACKET_WRITE_UINT16_LE(u, MCS_IO_CHANNEL_ID + i + 1); 316 | } else { 317 | V2R_PACKET_WRITE_UINT16_LE(u, 0); 318 | } 319 | } 320 | 321 | /* finish construct user data */ 322 | V2R_PACKET_END(u); 323 | 324 | /* start construct entire packet */ 325 | v2r_x224_init_packet(p); 326 | mcs_rsp_len = V2R_PACKET_LEN(u) + (V2R_PACKET_LEN(u) > 0x80 ? 38 : 36); 327 | v2r_mcs_write_ber_encoding(p, BER_TAG_CONNECT_RESPONSE, mcs_rsp_len); 328 | v2r_mcs_write_ber_encoding(p, BER_TAG_ENUMERATED, 1); 329 | V2R_PACKET_WRITE_UINT8(p, 0); 330 | v2r_mcs_write_ber_encoding(p, BER_TAG_INTEGER, 1); 331 | V2R_PACKET_WRITE_UINT8(p, 0); 332 | v2r_mcs_write_ber_encoding(p, BER_TAG_DOMAIN_PARAMETERS, 26); 333 | v2r_mcs_write_ber_encoding(p, BER_TAG_INTEGER, 1); 334 | V2R_PACKET_WRITE_UINT8(p, 34); 335 | v2r_mcs_write_ber_encoding(p, BER_TAG_INTEGER, 1); 336 | V2R_PACKET_WRITE_UINT8(p, 3); 337 | v2r_mcs_write_ber_encoding(p, BER_TAG_INTEGER, 1); 338 | V2R_PACKET_WRITE_UINT8(p, 0); 339 | v2r_mcs_write_ber_encoding(p, BER_TAG_INTEGER, 1); 340 | V2R_PACKET_WRITE_UINT8(p, 1); 341 | v2r_mcs_write_ber_encoding(p, BER_TAG_INTEGER, 1); 342 | V2R_PACKET_WRITE_UINT8(p, 0); 343 | v2r_mcs_write_ber_encoding(p, BER_TAG_INTEGER, 1); 344 | V2R_PACKET_WRITE_UINT8(p, 1); 345 | v2r_mcs_write_ber_encoding(p, BER_TAG_INTEGER, 3); 346 | V2R_PACKET_WRITE_UINT8(p, 0x00); 347 | V2R_PACKET_WRITE_UINT8(p, 0xFF); 348 | V2R_PACKET_WRITE_UINT8(p, 0xF8); 349 | v2r_mcs_write_ber_encoding(p, BER_TAG_INTEGER, 1); 350 | V2R_PACKET_WRITE_UINT8(p, 2); 351 | v2r_mcs_write_ber_encoding(p, BER_TAG_OCTET_STRING, V2R_PACKET_LEN(u)); 352 | V2R_PACKET_WRITE_N(p, u->data, V2R_PACKET_LEN(u)); 353 | 354 | V2R_PACKET_END(p); 355 | v2r_x224_send(m->x224, p); 356 | 357 | v2r_packet_destory(u); 358 | return 0; 359 | 360 | fail: 361 | v2r_packet_destory(u); 362 | return -1; 363 | } 364 | 365 | static int 366 | v2r_mcs_recv_erect_domain_req(v2r_packet_t *p, v2r_mcs_t *m) 367 | { 368 | uint8_t choice; 369 | 370 | if (v2r_x224_recv(m->x224, p) == -1) { 371 | goto fail; 372 | } 373 | if (!V2R_PACKET_READ_REMAIN(p, sizeof(uint8_t))) { 374 | goto fail; 375 | } 376 | V2R_PACKET_READ_UINT8(p, choice); 377 | if ((choice >> 2) != MCS_ERECT_DOMAIN_REQUEST) { 378 | goto fail; 379 | } 380 | 381 | return 0; 382 | 383 | fail: 384 | return -1; 385 | } 386 | 387 | static int 388 | v2r_mcs_recv_attach_user_request(v2r_packet_t *p, v2r_mcs_t *m) 389 | { 390 | uint8_t choice; 391 | 392 | if (v2r_x224_recv(m->x224, p) == -1) { 393 | goto fail; 394 | } 395 | if (!V2R_PACKET_READ_REMAIN(p, sizeof(uint8_t))) { 396 | goto fail; 397 | } 398 | V2R_PACKET_READ_UINT8(p, choice); 399 | if ((choice >> 2) != MCS_ATTACH_USER_REQUEST) { 400 | goto fail; 401 | } 402 | 403 | return 0; 404 | 405 | fail: 406 | return -1; 407 | } 408 | 409 | static int 410 | v2r_mcs_send_attach_user_confirm(v2r_packet_t *p, v2r_mcs_t *m) 411 | { 412 | v2r_x224_init_packet(p); 413 | 414 | V2R_PACKET_WRITE_UINT8(p, (MCS_ATTACH_USER_CONFIRM << 2) | 2); 415 | V2R_PACKET_WRITE_UINT8(p, 0); 416 | /* User Channel ID */ 417 | m->user_channel_id = MCS_IO_CHANNEL_ID + m->channel_count + 1; 418 | V2R_PACKET_WRITE_UINT16_BE(p, m->user_channel_id - MCS_BASE_CHANNEL_ID); 419 | 420 | V2R_PACKET_END(p); 421 | return v2r_x224_send(m->x224, p); 422 | } 423 | 424 | static int 425 | v2r_mcs_join_channel(v2r_packet_t *p, v2r_mcs_t *m, uint16_t id) 426 | { 427 | uint8_t choice; 428 | uint16_t user_id, channel_id; 429 | 430 | /* recieve channel join request */ 431 | if (v2r_x224_recv(m->x224, p) == -1) { 432 | goto fail; 433 | } 434 | if (!V2R_PACKET_READ_REMAIN(p, 5)) { 435 | goto fail; 436 | } 437 | V2R_PACKET_READ_UINT8(p, choice); 438 | if ((choice >> 2) != MCS_CHANNEL_JOIN_REQUEST) { 439 | goto fail; 440 | } 441 | V2R_PACKET_READ_UINT16_BE(p, user_id); 442 | if (MCS_BASE_CHANNEL_ID + user_id != m->user_channel_id) { 443 | goto fail; 444 | } 445 | V2R_PACKET_READ_UINT16_BE(p, channel_id); 446 | if (channel_id != id) { 447 | goto fail; 448 | } 449 | 450 | /* send channel join confirm */ 451 | v2r_x224_init_packet(p); 452 | V2R_PACKET_WRITE_UINT8(p, (MCS_CHANNEL_JOIN_CONFIRM << 2) | 2); 453 | V2R_PACKET_WRITE_UINT8(p, 0); 454 | V2R_PACKET_WRITE_UINT16_BE(p, m->user_channel_id - MCS_BASE_CHANNEL_ID); 455 | V2R_PACKET_WRITE_UINT16_BE(p, channel_id); 456 | V2R_PACKET_WRITE_UINT16_BE(p, channel_id); 457 | 458 | V2R_PACKET_END(p); 459 | return v2r_x224_send(m->x224, p); 460 | 461 | fail: 462 | return -1; 463 | } 464 | 465 | int 466 | v2r_mcs_build_conn(v2r_mcs_t *m, int client_fd) 467 | { 468 | uint16_t i = 0; 469 | v2r_packet_t *p = NULL; 470 | 471 | if (v2r_x224_build_conn(m->x224, client_fd) == -1) { 472 | goto fail; 473 | } 474 | 475 | p = v2r_packet_init(8192); 476 | if (p == NULL) { 477 | goto fail; 478 | } 479 | 480 | if (v2r_mcs_recv_conn_init(p, m) == -1) { 481 | goto fail; 482 | } 483 | if (v2r_mcs_send_conn_resp(p, m) == -1) { 484 | goto fail; 485 | } 486 | if (v2r_mcs_recv_erect_domain_req(p, m) == -1) { 487 | goto fail; 488 | } 489 | if (v2r_mcs_recv_attach_user_request(p, m) == -1) { 490 | goto fail; 491 | } 492 | if (v2r_mcs_send_attach_user_confirm(p, m) == -1) { 493 | goto fail; 494 | } 495 | /* User Channel */ 496 | if (v2r_mcs_join_channel(p, m, m->user_channel_id) == -1) { 497 | goto fail; 498 | } 499 | /* MCS I/O Channel */ 500 | if (v2r_mcs_join_channel(p, m, MCS_IO_CHANNEL_ID) == -1) { 501 | goto fail; 502 | } 503 | /* Static Virtual Channel */ 504 | for (i = 0; i < m->channel_count; i++) { 505 | if (v2r_mcs_join_channel(p, m, MCS_IO_CHANNEL_ID + i + 1) 506 | == -1) { 507 | goto fail; 508 | } 509 | } 510 | 511 | v2r_packet_destory(p); 512 | return 0; 513 | 514 | fail: 515 | v2r_packet_destory(p); 516 | return -1; 517 | } 518 | 519 | v2r_mcs_t * 520 | v2r_mcs_init(v2r_session_t *session) 521 | { 522 | v2r_mcs_t *m = NULL; 523 | 524 | m = (v2r_mcs_t *)malloc(sizeof(v2r_mcs_t)); 525 | if (m == NULL) { 526 | goto fail; 527 | } 528 | memset(m, 0, sizeof(v2r_mcs_t)); 529 | 530 | m->session = session; 531 | 532 | m->x224 = v2r_x224_init(session); 533 | if (m->x224 == NULL) { 534 | goto fail; 535 | } 536 | 537 | return m; 538 | 539 | fail: 540 | v2r_mcs_destory(m); 541 | return NULL; 542 | } 543 | 544 | void 545 | v2r_mcs_destory(v2r_mcs_t *m) 546 | { 547 | if (m == NULL) { 548 | return; 549 | } 550 | if (m->x224 != NULL) { 551 | v2r_x224_destory(m->x224); 552 | } 553 | if (m->channel_def_array != NULL) { 554 | free(m->channel_def_array); 555 | } 556 | free(m); 557 | } 558 | 559 | int 560 | v2r_mcs_recv(v2r_mcs_t *m , v2r_packet_t *p, uint8_t *choice, 561 | uint16_t *channel_id) 562 | { 563 | uint16_t user_id; 564 | 565 | if (v2r_x224_recv(m->x224, p) == -1) { 566 | goto fail; 567 | } 568 | if (!V2R_PACKET_READ_REMAIN(p, 1)) { 569 | goto fail; 570 | } 571 | V2R_PACKET_READ_UINT8(p, *choice); 572 | *choice = *choice >> 2; 573 | switch (*choice) { 574 | case MCS_SEND_DATA_REQUEST: 575 | case MCS_SEND_DATA_INDICATION: 576 | V2R_PACKET_READ_UINT16_BE(p, user_id); 577 | if (MCS_BASE_CHANNEL_ID + user_id != m->user_channel_id) { 578 | goto fail; 579 | } 580 | V2R_PACKET_READ_UINT16_BE(p, *channel_id); 581 | V2R_PACKET_SEEK(p, 1); 582 | V2R_PACKET_SEEK(p, (p->current[0] & 0x80) ? 2 : 1); 583 | break; 584 | } 585 | 586 | return 0; 587 | 588 | fail: 589 | return -1; 590 | } 591 | 592 | int 593 | v2r_mcs_send(v2r_mcs_t *m, v2r_packet_t *p, uint8_t choice, 594 | uint16_t channel_id) 595 | { 596 | p->current = p->mcs; 597 | V2R_PACKET_WRITE_UINT8(p, choice << 2); 598 | V2R_PACKET_WRITE_UINT16_BE(p, m->user_channel_id - MCS_BASE_CHANNEL_ID); 599 | V2R_PACKET_WRITE_UINT16_BE(p, channel_id); 600 | V2R_PACKET_WRITE_UINT8(p, 0x70); 601 | V2R_PACKET_WRITE_UINT16_BE(p, 0x8000 | (p->end - p->mcs - 8)); 602 | return v2r_x224_send(m->x224, p); 603 | } 604 | 605 | void 606 | v2r_mcs_init_packet(v2r_packet_t *p) 607 | { 608 | v2r_x224_init_packet(p); 609 | p->mcs = p->current; 610 | V2R_PACKET_SEEK(p, 8); 611 | } 612 | -------------------------------------------------------------------------------- /mcs.h: -------------------------------------------------------------------------------- 1 | /** 2 | * vnc2rdp: proxy for RDP client connect to VNC server 3 | * 4 | * Copyright 2014 Yiwei Li 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef _MCS_H_ 20 | #define _MCS_H_ 21 | 22 | #include "session.h" 23 | #include "x224.h" 24 | 25 | #define BER_TAG_CONNECT_INITIAL 0x7F65 26 | #define BER_TAG_CONNECT_RESPONSE 0x7F66 27 | #define BER_TAG_BOOLEAN 0x01 28 | #define BER_TAG_INTEGER 0x02 29 | #define BER_TAG_OCTET_STRING 0x04 30 | #define BER_TAG_ENUMERATED 0x0A 31 | #define BER_TAG_DOMAIN_PARAMETERS 0x30 32 | 33 | #define MCS_ERECT_DOMAIN_REQUEST 1 34 | #define MCS_ATTACH_USER_REQUEST 10 35 | #define MCS_ATTACH_USER_CONFIRM 11 36 | #define MCS_CHANNEL_JOIN_REQUEST 14 37 | #define MCS_CHANNEL_JOIN_CONFIRM 15 38 | #define MCS_SEND_DATA_REQUEST 25 39 | #define MCS_SEND_DATA_INDICATION 26 40 | 41 | #define GCCCCRQ_HEADER_LEN 23 42 | #define TS_UD_HEADER_LEN 4 43 | 44 | #define CS_CORE 0xC001 45 | #define CS_SECURITY 0xC002 46 | #define CS_NET 0xC003 47 | #define CS_CLUSTER 0xC004 48 | #define SC_CORE 0x0C01 49 | #define SC_SECURITY 0x0C02 50 | #define SC_NET 0x0C03 51 | 52 | #define MAX_CHANNELS_ALLOWED 31 53 | #define MCS_BASE_CHANNEL_ID 1001 54 | #define MCS_IO_CHANNEL_ID 1003 55 | 56 | typedef struct _channel_def_t { 57 | char name[8]; 58 | uint32_t options; 59 | } channel_def_t; 60 | 61 | typedef struct _v2r_mcs_t { 62 | v2r_session_t *session; 63 | v2r_x224_t *x224; 64 | 65 | /* client core data */ 66 | uint32_t keyboard_layout; 67 | 68 | /* client security data */ 69 | uint32_t encryption_methods; 70 | 71 | /* client network data */ 72 | uint32_t channel_count; 73 | channel_def_t *channel_def_array; 74 | uint16_t user_channel_id; 75 | } v2r_mcs_t; 76 | 77 | extern v2r_mcs_t *v2r_mcs_init(v2r_session_t *session); 78 | extern void v2r_mcs_destory(v2r_mcs_t *m); 79 | extern int v2r_mcs_build_conn(v2r_mcs_t *m, int client_fd); 80 | extern int v2r_mcs_recv(v2r_mcs_t *m, v2r_packet_t *p, uint8_t *choice, 81 | uint16_t *channel_id); 82 | extern int v2r_mcs_send(v2r_mcs_t *m, v2r_packet_t *p, uint8_t choice, 83 | uint16_t channel_id); 84 | extern void v2r_mcs_init_packet(v2r_packet_t *p); 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /orders.h: -------------------------------------------------------------------------------- 1 | /** 2 | * vnc2rdp: proxy for RDP client connect to VNC server 3 | * 4 | * Copyright 2014 Yiwei Li 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef _ORDERS_H_ 20 | #define _ORDERS_H_ 21 | 22 | /* Primary Drawing Order - controlFlags */ 23 | #define TS_STANDARD 0x01 24 | #define TS_BOUNDS 0x04 25 | #define TS_TYPE_CHANGE 0x08 26 | #define TS_DELTA_COORDINATES 0x10 27 | #define TS_ZERO_BOUNDS_DELTAS 0x20 28 | #define TS_ZERO_FIELD_BYTE_BIT0 0x40 29 | #define TS_ZERO_FIELD_BYTE_BIT1 0x80 30 | 31 | /* Primary Drawing Order - orderType */ 32 | #define TS_ENC_DSTBLT_ORDER 0x00 33 | #define TS_ENC_PATBLT_ORDER 0x01 34 | #define TS_ENC_SCRBLT_ORDER 0x02 35 | #define TS_ENC_DRAWNINEGRID_ORDER 0x07 36 | #define TS_ENC_MULTI_DRAWNINEGRID_ORDER 0x08 37 | #define TS_ENC_LINETO_ORDER 0x09 38 | #define TS_ENC_OPAQUERECT_ORDER 0x0A 39 | #define TS_ENC_SAVEBITMAP_ORDER 0x0B 40 | #define TS_ENC_MEMBLT_ORDER 0x0D 41 | #define TS_ENC_MEM3BLT_ORDER 0x0E 42 | #define TS_ENC_MULTIDSTBLT_ORDER 0x0F 43 | #define TS_ENC_MULTIPATBLT_ORDER 0x10 44 | #define TS_ENC_MULTISCRBLT_ORDER 0x11 45 | #define TS_ENC_MULTIOPAQUERECT_ORDER 0x12 46 | #define TS_ENC_FAST_INDEX_ORDER 0x13 47 | #define TS_ENC_POLYGON_SC_ORDER 0x14 48 | #define TS_ENC_POLYGON_CB_ORDER 0x15 49 | #define TS_ENC_POLYLINE_ORDER 0x16 50 | #define TS_ENC_FAST_GLYPH_ORDER 0x18 51 | #define TS_ENC_ELLIPSE_SC_ORDER 0x19 52 | #define TS_ENC_ELLIPSE_CB_ORDER 0x1A 53 | #define TS_ENC_INDEX_ORDER 0x1B 54 | 55 | #endif // _ORDERS_H_ 56 | -------------------------------------------------------------------------------- /packet.c: -------------------------------------------------------------------------------- 1 | /** 2 | * vnc2rdp: proxy for RDP client connect to VNC server 3 | * 4 | * Copyright 2014 Yiwei Li 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | #include "packet.h" 23 | 24 | v2r_packet_t * 25 | v2r_packet_init(size_t max_len) 26 | { 27 | v2r_packet_t *p = NULL; 28 | 29 | p = (v2r_packet_t *)malloc(sizeof(v2r_packet_t)); 30 | if (p == NULL) { 31 | return NULL; 32 | } 33 | memset(p, 0, sizeof(v2r_packet_t)); 34 | 35 | p->data = (uint8_t *)malloc(max_len); 36 | if (p->data == NULL) { 37 | goto fail; 38 | } 39 | p->max_len = max_len; 40 | p->current = p->data; 41 | 42 | return p; 43 | 44 | fail: 45 | v2r_packet_destory(p); 46 | return NULL; 47 | } 48 | 49 | void 50 | v2r_packet_reset(v2r_packet_t *p) 51 | { 52 | if (p == NULL) { 53 | return; 54 | } 55 | p->current = p->data; 56 | p->end = p->data; 57 | p->tpkt = NULL; 58 | p->x224 = NULL; 59 | p->mcs = NULL; 60 | p->sec = NULL; 61 | } 62 | 63 | void 64 | v2r_packet_destory(v2r_packet_t *p) 65 | { 66 | if (p == NULL) { 67 | return; 68 | } 69 | if (p->data != NULL) { 70 | free(p->data); 71 | } 72 | free(p); 73 | } 74 | -------------------------------------------------------------------------------- /packet.h: -------------------------------------------------------------------------------- 1 | /** 2 | * vnc2rdp: proxy for RDP client connect to VNC server 3 | * 4 | * Copyright 2014 Yiwei Li 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef _PACKET_H_ 20 | #define _PACKET_H_ 21 | 22 | #include 23 | #include 24 | 25 | #define V2R_PACKET_READ_REMAIN(p, n) \ 26 | ((p)->current + n <= (p)->end) 27 | 28 | #define V2R_PACKET_READ_UINT8(p, v) \ 29 | do { \ 30 | (v) = *(p)->current++; \ 31 | } while (0) 32 | #define V2R_PACKET_READ_UINT16_BE(p, v) \ 33 | do { \ 34 | (v) = *((uint8_t *)((p)->current++)) << 8; \ 35 | (v) |= *((uint8_t *)((p)->current++)); \ 36 | } while (0) 37 | #define V2R_PACKET_READ_UINT16_LE(p, v) \ 38 | do { \ 39 | (v) = *((uint16_t *)((p)->current)); \ 40 | (p)->current += sizeof(uint16_t); \ 41 | } while (0) 42 | #define V2R_PACKET_READ_UINT32_BE(p, v) \ 43 | do { \ 44 | (v) = (uint32_t) \ 45 | ( \ 46 | (*((uint8_t *)((p)->current + 0)) << 24) | \ 47 | (*((uint8_t *)((p)->current + 1)) << 16) | \ 48 | (*((uint8_t *)((p)->current + 2)) << 8) | \ 49 | (*((uint8_t *)((p)->current + 3)) << 0) \ 50 | ); \ 51 | (p)->current += sizeof(uint32_t); \ 52 | } while (0) 53 | #define V2R_PACKET_READ_UINT32_LE(p, v) \ 54 | do { \ 55 | (v) = *((uint32_t *)((p)->current)); \ 56 | (p)->current += sizeof(uint32_t); \ 57 | } while (0) 58 | #define V2R_PACKET_READ_N(p, v, n) \ 59 | do { \ 60 | memcpy((v), (p)->current, (n)); \ 61 | (p)->current += n; \ 62 | } while (0) 63 | 64 | #define V2R_PACKET_WRITE_UINT8(p, v) \ 65 | do { \ 66 | *(p)->current++ = (uint8_t)v; \ 67 | } while (0) 68 | #define V2R_PACKET_WRITE_UINT16_BE(p, v) \ 69 | do { \ 70 | *((p)->current++) = (uint8_t)((v) >> 8); \ 71 | *((p)->current++) = (uint8_t)((v) >> 0); \ 72 | } while (0) 73 | #define V2R_PACKET_WRITE_UINT16_LE(p, v) \ 74 | do { \ 75 | *((uint16_t *)((p)->current)) = (uint16_t)(v); \ 76 | (p)->current += sizeof(uint16_t); \ 77 | } while (0) 78 | #define V2R_PACKET_WRITE_UINT32_BE(p, v) \ 79 | do { \ 80 | *((p)->current++) = (int8_t)((v) >> 24); \ 81 | *((p)->current++) = (int8_t)((v) >> 16); \ 82 | *((p)->current++) = (int8_t)((v) >> 8); \ 83 | *((p)->current++) = (int8_t)((v) >> 0); \ 84 | } while (0) 85 | #define V2R_PACKET_WRITE_UINT32_LE(p, v) \ 86 | do { \ 87 | *((uint32_t *)((p)->current)) = (uint32_t)(v); \ 88 | (p)->current += sizeof(uint32_t); \ 89 | } while (0) 90 | #define V2R_PACKET_WRITE_N(p, v, n) \ 91 | do { \ 92 | memcpy((p)->current, (v), (n)); \ 93 | (p)->current += n; \ 94 | } while (0) 95 | 96 | #define V2R_PACKET_SEEK(p, n) (p)->current += (n) 97 | #define V2R_PACKET_SEEK_UINT8(p) V2R_PACKET_SEEK(p, sizeof(uint8_t)) 98 | #define V2R_PACKET_SEEK_UINT16(p) V2R_PACKET_SEEK(p, sizeof(uint16_t)) 99 | 100 | #define V2R_PACKET_END(p) (p)->end = (p)->current 101 | #define V2R_PACKET_LEN(p) ((p)->end - (p)->data) 102 | 103 | typedef struct _v2r_packet_t { 104 | uint32_t max_len; 105 | uint8_t *data; 106 | uint8_t *current; 107 | uint8_t *end; 108 | /* RDP layer marks */ 109 | uint8_t *tpkt; 110 | uint8_t *x224; 111 | uint8_t *mcs; 112 | uint8_t *sec; 113 | uint8_t *rdp; 114 | } v2r_packet_t; 115 | 116 | extern v2r_packet_t *v2r_packet_init(size_t max_len); 117 | extern void v2r_packet_reset(v2r_packet_t *p); 118 | extern void v2r_packet_destory(v2r_packet_t *p); 119 | 120 | #endif // _PACKET_H_ 121 | -------------------------------------------------------------------------------- /rdp.c: -------------------------------------------------------------------------------- 1 | /** 2 | * vnc2rdp: proxy for RDP client connect to VNC server 3 | * 4 | * Copyright 2014 Yiwei Li 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | #include "capabilities.h" 23 | #include "input.h" 24 | #include "license.h" 25 | #include "log.h" 26 | #include "orders.h" 27 | #include "rdp.h" 28 | #include "vnc.h" 29 | 30 | static int 31 | v2r_rdp_recv_client_info(v2r_rdp_t *r, v2r_packet_t *p) 32 | { 33 | uint16_t sec_flags = 0, channel_id = 0; 34 | 35 | if (v2r_sec_recv(r->sec, p, &sec_flags, &channel_id) == -1) { 36 | goto fail; 37 | } 38 | if (sec_flags != SEC_INFO_PKT || channel_id != MCS_IO_CHANNEL_ID) { 39 | goto fail; 40 | } 41 | 42 | return 0; 43 | 44 | fail: 45 | return -1; 46 | } 47 | 48 | static int 49 | v2r_rdp_send_license_error(v2r_rdp_t *r, v2r_packet_t *p) 50 | { 51 | v2r_sec_init_packet(p); 52 | 53 | /* bMsgType */ 54 | V2R_PACKET_WRITE_UINT8(p, ERROR_ALERT); 55 | /* flags */ 56 | V2R_PACKET_WRITE_UINT8(p, PREAMBLE_VERSION_3_0); 57 | /* wMsgSize */ 58 | V2R_PACKET_WRITE_UINT16_LE(p, 16); 59 | /* dwErrorCode */ 60 | V2R_PACKET_WRITE_UINT32_LE(p, STATUS_VALID_CLIENT); 61 | /* dwStateTransition */ 62 | V2R_PACKET_WRITE_UINT32_LE(p, ST_NO_TRANSITION); 63 | /* wBlobType */ 64 | V2R_PACKET_WRITE_UINT16_LE(p, BB_ERROR_BLOB); 65 | /* wBlobLen */ 66 | V2R_PACKET_WRITE_UINT16_LE(p, 0); 67 | 68 | V2R_PACKET_END(p); 69 | return v2r_sec_send(r->sec, p, SEC_LICENSE_PKT, MCS_IO_CHANNEL_ID); 70 | } 71 | 72 | static int 73 | v2r_rdp_send_demand_active(v2r_rdp_t *r, v2r_packet_t *p) 74 | { 75 | uint8_t *cap_size_ptr = NULL; 76 | uint16_t *length_combined_capabilities = NULL; 77 | share_data_hdr_t hdr; 78 | 79 | v2r_rdp_init_packet(p, sizeof(share_ctrl_hdr_t)); 80 | /* shareControlHeader */ 81 | hdr.share_ctrl_hdr.type = PDUTYPE_DEMANDACTIVEPDU; 82 | /* shareId */ 83 | V2R_PACKET_WRITE_UINT32_LE(p, 0x1000 + r->sec->mcs->user_channel_id); 84 | /* lengthSourceDescriptor */ 85 | V2R_PACKET_WRITE_UINT16_LE(p, 4); 86 | /* lengthCombinedCapabilities: mark this place */ 87 | length_combined_capabilities = (uint16_t *)p->current; 88 | V2R_PACKET_WRITE_UINT16_LE(p, 0); 89 | /* sourceDescriptor */ 90 | V2R_PACKET_WRITE_N(p, "RDP", 4); 91 | /* numberCapabilities */ 92 | cap_size_ptr = p->current; 93 | V2R_PACKET_WRITE_UINT16_LE(p, v2r_cap_get_write_count()); 94 | /* pad2Octets */ 95 | V2R_PACKET_WRITE_UINT16_LE(p, 0); 96 | /* capabilitySets */ 97 | v2r_cap_write_caps(r, p); 98 | *length_combined_capabilities = p->current - cap_size_ptr; 99 | /* sessionId */ 100 | V2R_PACKET_WRITE_UINT32_LE(p, 0); 101 | 102 | V2R_PACKET_END(p); 103 | return v2r_rdp_send(r, p, &hdr); 104 | } 105 | 106 | static int 107 | v2r_rdp_recv_confirm_active(v2r_rdp_t *r, v2r_packet_t *p) 108 | { 109 | share_data_hdr_t hdr; 110 | 111 | if (v2r_rdp_recv(r, p, &hdr) == -1) { 112 | goto fail; 113 | } 114 | if (hdr.share_ctrl_hdr.type != PDUTYPE_CONFIRMACTIVEPDU) { 115 | goto fail; 116 | } 117 | 118 | return 0; 119 | 120 | fail: 121 | return -1; 122 | } 123 | 124 | static int 125 | v2r_rdp_recv_synchronize(v2r_rdp_t *r, v2r_packet_t *p) 126 | { 127 | share_data_hdr_t hdr; 128 | 129 | if (v2r_rdp_recv(r, p, &hdr) == -1) { 130 | goto fail; 131 | } 132 | if (hdr.share_ctrl_hdr.type != PDUTYPE_DATAPDU || 133 | hdr.pdu_type2 != PDUTYPE2_SYNCHRONIZE) { 134 | goto fail; 135 | } 136 | 137 | return 0; 138 | 139 | fail: 140 | return -1; 141 | } 142 | 143 | static int 144 | v2r_rdp_recv_control_cooperate(v2r_rdp_t *r, v2r_packet_t *p) 145 | { 146 | uint16_t action = 0; 147 | share_data_hdr_t hdr; 148 | 149 | if (v2r_rdp_recv(r, p, &hdr) == -1) { 150 | goto fail; 151 | } 152 | if (hdr.share_ctrl_hdr.type != PDUTYPE_DATAPDU || 153 | hdr.pdu_type2 != PDUTYPE2_CONTROL) { 154 | goto fail; 155 | } 156 | /* action */ 157 | V2R_PACKET_READ_UINT16_LE(p, action); 158 | if (action != CTRLACTION_COOPERATE) { 159 | goto fail; 160 | } 161 | 162 | return 0; 163 | 164 | fail: 165 | return -1; 166 | } 167 | 168 | static int 169 | v2r_rdp_recv_control_request(v2r_rdp_t *r, v2r_packet_t *p) 170 | { 171 | uint16_t action = 0; 172 | share_data_hdr_t hdr; 173 | 174 | if (v2r_rdp_recv(r, p, &hdr) == -1) { 175 | goto fail; 176 | } 177 | if (hdr.share_ctrl_hdr.type != PDUTYPE_DATAPDU || 178 | hdr.pdu_type2 != PDUTYPE2_CONTROL) { 179 | goto fail; 180 | } 181 | /* action */ 182 | V2R_PACKET_READ_UINT16_LE(p, action); 183 | if (action != CTRLACTION_REQUEST_CONTROL) { 184 | goto fail; 185 | } 186 | 187 | return 0; 188 | 189 | fail: 190 | return -1; 191 | } 192 | 193 | static int 194 | v2r_rdp_recv_font_list(v2r_rdp_t *r, v2r_packet_t *p) 195 | { 196 | share_data_hdr_t hdr; 197 | 198 | if (v2r_rdp_recv(r, p, &hdr) == -1) { 199 | goto fail; 200 | } 201 | if (hdr.share_ctrl_hdr.type != PDUTYPE_DATAPDU || 202 | hdr.pdu_type2 != PDUTYPE2_FONTLIST) { 203 | goto fail; 204 | } 205 | 206 | return 0; 207 | 208 | fail: 209 | return -1; 210 | } 211 | 212 | static int 213 | v2r_rdp_send_synchronize(v2r_rdp_t *r, v2r_packet_t *p) 214 | { 215 | share_data_hdr_t hdr; 216 | 217 | v2r_rdp_init_packet(p, sizeof(share_data_hdr_t)); 218 | /* shareDataHeader */ 219 | hdr.share_ctrl_hdr.type = PDUTYPE_DATAPDU; 220 | hdr.pdu_type2 = PDUTYPE2_SYNCHRONIZE; 221 | /* messageType */ 222 | V2R_PACKET_WRITE_UINT16_LE(p, SYNCMSGTYPE_SYNC); 223 | /* targetUser */ 224 | V2R_PACKET_WRITE_UINT16_LE(p, MCS_IO_CHANNEL_ID); 225 | 226 | V2R_PACKET_END(p); 227 | return v2r_rdp_send(r, p, &hdr); 228 | } 229 | 230 | static int 231 | v2r_rdp_send_control_cooperate(v2r_rdp_t *r, v2r_packet_t *p) 232 | { 233 | share_data_hdr_t hdr; 234 | 235 | v2r_rdp_init_packet(p, sizeof(share_data_hdr_t)); 236 | /* shareDataHeader */ 237 | hdr.share_ctrl_hdr.type = PDUTYPE_DATAPDU; 238 | hdr.pdu_type2 = PDUTYPE2_CONTROL; 239 | /* action */ 240 | V2R_PACKET_WRITE_UINT16_LE(p, CTRLACTION_COOPERATE); 241 | /* grantId */ 242 | V2R_PACKET_WRITE_UINT16_LE(p, 0); 243 | /* controlId */ 244 | V2R_PACKET_WRITE_UINT32_LE(p, 0); 245 | 246 | V2R_PACKET_END(p); 247 | return v2r_rdp_send(r, p, &hdr); 248 | } 249 | 250 | static int 251 | v2r_rdp_send_control_grant_control(v2r_rdp_t *r, v2r_packet_t *p) 252 | { 253 | share_data_hdr_t hdr; 254 | 255 | v2r_rdp_init_packet(p, sizeof(share_data_hdr_t)); 256 | /* shareDataHeader */ 257 | hdr.share_ctrl_hdr.type = PDUTYPE_DATAPDU; 258 | hdr.pdu_type2 = PDUTYPE2_CONTROL; 259 | /* action */ 260 | V2R_PACKET_WRITE_UINT16_LE(p, CTRLACTION_GRANTED_CONTROL); 261 | /* grantId */ 262 | V2R_PACKET_WRITE_UINT16_LE(p, r->sec->mcs->user_channel_id); 263 | /* controlId */ 264 | V2R_PACKET_WRITE_UINT32_LE(p, 0x03EA); 265 | 266 | V2R_PACKET_END(p); 267 | return v2r_rdp_send(r, p, &hdr); 268 | } 269 | 270 | static int 271 | v2r_rdp_send_font_map(v2r_rdp_t *r, v2r_packet_t *p) 272 | { 273 | share_data_hdr_t hdr; 274 | 275 | v2r_rdp_init_packet(p, sizeof(share_data_hdr_t)); 276 | /* shareDataHeader */ 277 | hdr.share_ctrl_hdr.type = PDUTYPE_DATAPDU; 278 | hdr.pdu_type2 = PDUTYPE2_FONTMAP; 279 | /* numberEntries */ 280 | V2R_PACKET_WRITE_UINT16_LE(p, 0); 281 | /* totalNumEntries */ 282 | V2R_PACKET_WRITE_UINT16_LE(p, 0); 283 | /* mapFlags */ 284 | V2R_PACKET_WRITE_UINT16_LE(p, FONTMAP_FIRST|FONTMAP_LAST); 285 | /* entrySize */ 286 | V2R_PACKET_WRITE_UINT16_LE(p, 0x0004); 287 | 288 | V2R_PACKET_END(p); 289 | return v2r_rdp_send(r, p, &hdr); 290 | } 291 | 292 | int 293 | v2r_rdp_build_conn(v2r_rdp_t *r, int client_fd) 294 | { 295 | v2r_packet_t *p = NULL; 296 | 297 | if (v2r_sec_build_conn(r->sec, client_fd) == -1) { 298 | goto fail; 299 | } 300 | 301 | p = v2r_packet_init(8192); 302 | if (p == NULL) { 303 | goto fail; 304 | } 305 | 306 | if (v2r_rdp_recv_client_info(r, p) == -1) { 307 | goto fail; 308 | } 309 | if (v2r_rdp_send_license_error(r, p) == -1) { 310 | goto fail; 311 | } 312 | if (v2r_rdp_send_demand_active(r, p) == -1) { 313 | goto fail; 314 | } 315 | if (v2r_rdp_recv_confirm_active(r, p) == -1) { 316 | goto fail; 317 | } 318 | if (v2r_rdp_recv_synchronize(r, p) == -1) { 319 | goto fail; 320 | } 321 | if (v2r_rdp_recv_control_cooperate(r, p) == -1) { 322 | goto fail; 323 | } 324 | if (v2r_rdp_recv_control_request(r, p) == -1) { 325 | goto fail; 326 | } 327 | if (v2r_rdp_recv_font_list(r, p) == -1) { 328 | goto fail; 329 | } 330 | if (v2r_rdp_send_synchronize(r, p) == -1) { 331 | goto fail; 332 | } 333 | if (v2r_rdp_send_control_cooperate(r, p) == -1) { 334 | goto fail; 335 | } 336 | if (v2r_rdp_send_control_grant_control(r, p) == -1) { 337 | goto fail; 338 | } 339 | if (v2r_rdp_send_font_map(r, p) == -1) { 340 | goto fail; 341 | } 342 | 343 | v2r_packet_destory(p); 344 | return 0; 345 | 346 | fail: 347 | v2r_packet_destory(p); 348 | return -1; 349 | } 350 | 351 | v2r_rdp_t * 352 | v2r_rdp_init(v2r_session_t *session) 353 | { 354 | v2r_rdp_t *r = NULL; 355 | 356 | r = (v2r_rdp_t *)malloc(sizeof(v2r_rdp_t)); 357 | if (r == NULL) { 358 | goto fail; 359 | } 360 | memset(r, 0, sizeof(v2r_rdp_t)); 361 | 362 | r->session = session; 363 | r->packet = v2r_packet_init(65535); 364 | if (r->packet == NULL) { 365 | goto fail; 366 | } 367 | r->sec = v2r_sec_init(session); 368 | if (r->sec == NULL) { 369 | goto fail; 370 | } 371 | r->allow_display_updates = ALLOW_DISPLAY_UPDATES; 372 | /* find keymap by keyboard layout, if there is no fit keymap currently, 373 | * vnc2rdp will continue work but don't provide keyboard function */ 374 | r->keymap = get_keymap_by_layout(r->sec->mcs->keyboard_layout); 375 | if (r->keymap == NULL) { 376 | v2r_log_error("unsupported keyboard layout: 0x%08x", 377 | r->sec->mcs->keyboard_layout); 378 | } 379 | 380 | return r; 381 | 382 | fail: 383 | v2r_rdp_destory(r); 384 | return NULL; 385 | } 386 | 387 | void 388 | v2r_rdp_destory(v2r_rdp_t *r) 389 | { 390 | if (r == NULL) { 391 | return; 392 | } 393 | if (r->packet != NULL) { 394 | v2r_packet_destory(r->packet); 395 | } 396 | if (r->sec != NULL) { 397 | v2r_sec_destory(r->sec); 398 | } 399 | free(r); 400 | } 401 | 402 | void 403 | v2r_rdp_init_packet(v2r_packet_t *p, uint16_t offset) 404 | { 405 | v2r_mcs_init_packet(p); 406 | p->rdp = p->current; 407 | V2R_PACKET_SEEK(p, offset); 408 | } 409 | 410 | int 411 | v2r_rdp_recv(v2r_rdp_t *r, v2r_packet_t *p, share_data_hdr_t *hdr) 412 | { 413 | uint8_t choice; 414 | uint16_t channel_id; 415 | 416 | if (v2r_mcs_recv(r->sec->mcs, p, &choice, &channel_id) == -1) { 417 | goto fail; 418 | } 419 | if (!V2R_PACKET_READ_REMAIN(p, sizeof(share_ctrl_hdr_t))) { 420 | goto fail; 421 | } 422 | V2R_PACKET_READ_N(p, &(hdr->share_ctrl_hdr), sizeof(share_ctrl_hdr_t)); 423 | if (hdr->share_ctrl_hdr.version_low != TS_PROTOCOL_VERSION || 424 | hdr->share_ctrl_hdr.version_high != 0x00) { 425 | goto fail; 426 | } 427 | if (hdr->share_ctrl_hdr.type == PDUTYPE_DATAPDU) { 428 | V2R_PACKET_READ_N(p, (void *)hdr + sizeof(share_ctrl_hdr_t), 429 | sizeof(share_data_hdr_t) - sizeof(share_ctrl_hdr_t)); 430 | } 431 | 432 | return 0; 433 | 434 | fail: 435 | return -1; 436 | } 437 | 438 | int 439 | v2r_rdp_send(v2r_rdp_t *r, v2r_packet_t *p, share_data_hdr_t *hdr) 440 | { 441 | hdr->share_ctrl_hdr.total_length = p->end - p->rdp; 442 | hdr->share_ctrl_hdr.version_low = TS_PROTOCOL_VERSION; 443 | hdr->share_ctrl_hdr.version_high = 0x00; 444 | hdr->share_ctrl_hdr.pdu_source = MCS_IO_CHANNEL_ID; 445 | if (hdr->share_ctrl_hdr.type == PDUTYPE_DATAPDU) { 446 | hdr->share_id = 0x1000 + r->sec->mcs->user_channel_id; 447 | hdr->pad1 = 0; 448 | hdr->stream_id = STREAM_LOW; 449 | hdr->uncompressed_length = p->end - p->rdp - 14; 450 | hdr->compressed_type = 0; 451 | hdr->compressed_length = 0; 452 | } 453 | 454 | p->current = p->rdp; 455 | if (hdr->share_ctrl_hdr.type == PDUTYPE_DATAPDU) { 456 | V2R_PACKET_WRITE_N(p, hdr, sizeof(share_data_hdr_t)); 457 | } else { 458 | V2R_PACKET_WRITE_N(p, &(hdr->share_ctrl_hdr), sizeof(share_ctrl_hdr_t)); 459 | } 460 | 461 | return v2r_mcs_send(r->sec->mcs, p, MCS_SEND_DATA_INDICATION, 462 | MCS_IO_CHANNEL_ID); 463 | } 464 | 465 | int 466 | v2r_rdp_send_bitmap_update(v2r_rdp_t *r, uint16_t left, uint16_t top, 467 | uint16_t right, uint16_t bottom, 468 | uint16_t width, uint16_t height, 469 | uint16_t bpp, uint16_t bitmap_length, 470 | uint8_t *bitmap_data) 471 | { 472 | share_data_hdr_t hdr; 473 | 474 | v2r_rdp_init_packet(r->packet, sizeof(share_data_hdr_t)); 475 | 476 | /* shareDataHeader */ 477 | hdr.share_ctrl_hdr.type = PDUTYPE_DATAPDU; 478 | hdr.pdu_type2 = PDUTYPE2_UPDATE; 479 | /* updateType */ 480 | V2R_PACKET_WRITE_UINT16_LE(r->packet, UPDATETYPE_BITMAP); 481 | /* numberRectangles */ 482 | V2R_PACKET_WRITE_UINT16_LE(r->packet, 1); 483 | /* destLeft */ 484 | V2R_PACKET_WRITE_UINT16_LE(r->packet, left); 485 | /* destTop */ 486 | V2R_PACKET_WRITE_UINT16_LE(r->packet, top); 487 | /* destRight */ 488 | V2R_PACKET_WRITE_UINT16_LE(r->packet, right); 489 | /* destBottom */ 490 | V2R_PACKET_WRITE_UINT16_LE(r->packet, bottom); 491 | /* width */ 492 | V2R_PACKET_WRITE_UINT16_LE(r->packet, width); 493 | /* height */ 494 | V2R_PACKET_WRITE_UINT16_LE(r->packet, height); 495 | /* bitsPerPixel */ 496 | V2R_PACKET_WRITE_UINT16_LE(r->packet, bpp); 497 | /* flags */ 498 | V2R_PACKET_WRITE_UINT16_LE(r->packet, 0); 499 | /* bitmapLength */ 500 | V2R_PACKET_WRITE_UINT16_LE(r->packet, bitmap_length); 501 | /* bitmapDataStream */ 502 | V2R_PACKET_WRITE_N(r->packet, bitmap_data, bitmap_length); 503 | 504 | /* send packet */ 505 | V2R_PACKET_END(r->packet); 506 | if (v2r_rdp_send(r, r->packet, &hdr) == -1) { 507 | goto fail; 508 | } 509 | 510 | return 0; 511 | 512 | fail: 513 | return -1; 514 | } 515 | 516 | int 517 | v2r_rdp_send_palette_update(v2r_rdp_t *r, uint32_t number_colors, 518 | uint8_t (*palette_entries)[3]) 519 | { 520 | uint32_t i; 521 | share_data_hdr_t hdr; 522 | 523 | v2r_rdp_init_packet(r->packet, sizeof(share_data_hdr_t)); 524 | 525 | /* shareDataHeader */ 526 | hdr.share_ctrl_hdr.type = PDUTYPE_DATAPDU; 527 | hdr.pdu_type2 = PDUTYPE2_UPDATE; 528 | /* updateType */ 529 | V2R_PACKET_WRITE_UINT16_LE(r->packet, UPDATETYPE_PALETTE); 530 | /* pad2Octets */ 531 | V2R_PACKET_WRITE_UINT16_LE(r->packet, 0); 532 | /* numberColors */ 533 | V2R_PACKET_WRITE_UINT32_LE(r->packet, number_colors); 534 | /* paletteEntries */ 535 | V2R_PACKET_WRITE_N(r->packet, palette_entries, 536 | number_colors * sizeof(*palette_entries)); 537 | 538 | /* send packet */ 539 | V2R_PACKET_END(r->packet); 540 | if (v2r_rdp_send(r, r->packet, &hdr) == -1) { 541 | goto fail; 542 | } 543 | 544 | return 0; 545 | 546 | fail: 547 | return -1; 548 | } 549 | 550 | int 551 | v2r_rdp_send_play_sound(v2r_rdp_t *r, uint32_t duration, uint32_t frequency) 552 | { 553 | share_data_hdr_t hdr; 554 | 555 | v2r_rdp_init_packet(r->packet, sizeof(share_data_hdr_t)); 556 | 557 | /* shareDataHeader */ 558 | hdr.share_ctrl_hdr.type = PDUTYPE_DATAPDU; 559 | hdr.pdu_type2 = PDUTYPE2_PLAY_SOUND; 560 | /* duration */ 561 | V2R_PACKET_WRITE_UINT32_LE(r->packet, duration); 562 | /* frequency */ 563 | V2R_PACKET_WRITE_UINT32_LE(r->packet, frequency); 564 | 565 | /* send packet */ 566 | V2R_PACKET_END(r->packet); 567 | if (v2r_rdp_send(r, r->packet, &hdr) == -1) { 568 | goto fail; 569 | } 570 | 571 | return 0; 572 | 573 | fail: 574 | return -1; 575 | } 576 | 577 | int 578 | v2r_rdp_send_scrblt_order(v2r_rdp_t *r, uint16_t left, uint16_t top, 579 | uint16_t width, uint16_t height, 580 | uint16_t x_src, uint16_t y_src) 581 | { 582 | share_data_hdr_t hdr; 583 | 584 | v2r_rdp_init_packet(r->packet, sizeof(share_data_hdr_t)); 585 | 586 | /* shareDataHeader */ 587 | hdr.share_ctrl_hdr.type = PDUTYPE_DATAPDU; 588 | hdr.pdu_type2 = PDUTYPE2_UPDATE; 589 | /* updateType */ 590 | V2R_PACKET_WRITE_UINT16_LE(r->packet, UPDATETYPE_ORDERS); 591 | /* pad2OctetsA */ 592 | V2R_PACKET_WRITE_UINT16_LE(r->packet, 0); 593 | /* numberOrders */ 594 | V2R_PACKET_WRITE_UINT16_LE(r->packet, 1); 595 | /* pad2OctetsB */ 596 | V2R_PACKET_WRITE_UINT16_LE(r->packet, 0); 597 | 598 | /* orderData */ 599 | 600 | /* controlFlags */ 601 | V2R_PACKET_WRITE_UINT8(r->packet, TS_STANDARD|TS_TYPE_CHANGE); 602 | /* orderType */ 603 | V2R_PACKET_WRITE_UINT8(r->packet, TS_ENC_SCRBLT_ORDER); 604 | /* fieldFlags */ 605 | V2R_PACKET_WRITE_UINT8(r->packet, 0x7F); 606 | /* nLeftRect */ 607 | V2R_PACKET_WRITE_UINT16_LE(r->packet, left); 608 | /* nTopRect */ 609 | V2R_PACKET_WRITE_UINT16_LE(r->packet, top); 610 | /* nWidth */ 611 | V2R_PACKET_WRITE_UINT16_LE(r->packet, width); 612 | /* nHeight */ 613 | V2R_PACKET_WRITE_UINT16_LE(r->packet, height); 614 | /* bRop */ 615 | V2R_PACKET_WRITE_UINT8(r->packet, 0xCC); 616 | /* nXSrc */ 617 | V2R_PACKET_WRITE_UINT16_LE(r->packet, x_src); 618 | /* nYSrc */ 619 | V2R_PACKET_WRITE_UINT16_LE(r->packet, y_src); 620 | 621 | /* send packet */ 622 | V2R_PACKET_END(r->packet); 623 | if (v2r_rdp_send(r, r->packet, &hdr) == -1) { 624 | goto fail; 625 | } 626 | 627 | return 0; 628 | 629 | fail: 630 | return -1; 631 | } 632 | 633 | static int 634 | v2r_rdp_process_suppress_output(v2r_rdp_t *r, v2r_packet_t *p) 635 | { 636 | uint16_t left, top, right, bottom; 637 | v2r_vnc_t *v = r->session->vnc; 638 | 639 | V2R_PACKET_READ_UINT8(p, r->allow_display_updates); 640 | v2r_log_debug("client send suppress output with allow_display_updates: %d", 641 | r->allow_display_updates); 642 | 643 | if (r->allow_display_updates == ALLOW_DISPLAY_UPDATES) { 644 | V2R_PACKET_READ_UINT16_LE(p, left); 645 | V2R_PACKET_READ_UINT16_LE(p, top); 646 | V2R_PACKET_READ_UINT16_LE(p, right); 647 | V2R_PACKET_READ_UINT16_LE(p, bottom); 648 | v2r_log_debug("with desktop rect: %d,%d,%d,%d", 649 | left, top, right, bottom); 650 | if (v2r_vnc_send_fb_update_req(v, 0, 0, 0, v->framebuffer_width, 651 | v->framebuffer_height) == -1) { 652 | goto fail; 653 | } 654 | } 655 | 656 | return 0; 657 | 658 | fail: 659 | return -1; 660 | } 661 | 662 | static int 663 | v2r_rdp_process_data(v2r_rdp_t *r, v2r_packet_t *p, const share_data_hdr_t *hdr) 664 | { 665 | switch (hdr->pdu_type2) { 666 | case PDUTYPE2_INPUT: 667 | if (v2r_input_process(r, p) == -1) { 668 | goto fail; 669 | } 670 | break; 671 | case PDUTYPE2_SUPPRESS_OUTPUT: 672 | if (v2r_rdp_process_suppress_output(r, p) == -1) { 673 | goto fail; 674 | } 675 | break; 676 | case PDUTYPE2_SHUTDOWN_REQUEST: 677 | /* when client send shutdown request, we should close connection 678 | * immediately, see [MS-RDPBCGR 1.3.1.4.1] */ 679 | v2r_log_debug("client send shutdown request"); 680 | goto fail; 681 | default: 682 | v2r_log_warn("unknown data pdu type: 0x%x", hdr->pdu_type2); 683 | break; 684 | } 685 | 686 | return 0; 687 | 688 | fail: 689 | return -1; 690 | } 691 | 692 | int 693 | v2r_rdp_process(v2r_rdp_t *r) 694 | { 695 | share_data_hdr_t hdr; 696 | 697 | if (v2r_rdp_recv(r, r->packet, &hdr) == -1) { 698 | goto fail; 699 | } 700 | switch (hdr.share_ctrl_hdr.type) { 701 | case PDUTYPE_DEMANDACTIVEPDU: 702 | break; 703 | case PDUTYPE_DATAPDU: 704 | if (v2r_rdp_process_data(r, r->packet, &hdr) == -1) { 705 | goto fail; 706 | } 707 | break; 708 | } 709 | 710 | return 0; 711 | 712 | fail: 713 | return -1; 714 | } 715 | -------------------------------------------------------------------------------- /rdp.h: -------------------------------------------------------------------------------- 1 | /** 2 | * vnc2rdp: proxy for RDP client connect to VNC server 3 | * 4 | * Copyright 2014 Yiwei Li 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef _RDP_H_ 20 | #define _RDP_H_ 21 | 22 | #include "keymaps.h" 23 | #include "sec.h" 24 | #include "session.h" 25 | 26 | #define TS_PROTOCOL_VERSION 0x1 27 | 28 | /* Share Control Header - pduType */ 29 | #define PDUTYPE_DEMANDACTIVEPDU 0x1 30 | #define PDUTYPE_CONFIRMACTIVEPDU 0x3 31 | #define PDUTYPE_DEACTIVATEALLPDU 0x6 32 | #define PDUTYPE_DATAPDU 0x7 33 | #define PDUTYPE_SERVER_REDIR_PKT 0xA 34 | 35 | /* Share Data Header - streamId */ 36 | #define STREAM_UNDEFINED 0x00 37 | #define STREAM_LOW 0x01 38 | #define STREAM_MED 0x02 39 | #define STREAM_HI 0x04 40 | 41 | /* Share Data Header - pduType2 */ 42 | #define PDUTYPE2_UPDATE 0x02 43 | #define PDUTYPE2_CONTROL 0x14 44 | #define PDUTYPE2_POINTER 0x1B 45 | #define PDUTYPE2_INPUT 0x1C 46 | #define PDUTYPE2_SYNCHRONIZE 0x1F 47 | #define PDUTYPE2_REFRESH_RECT 0x21 48 | #define PDUTYPE2_PLAY_SOUND 0x22 49 | #define PDUTYPE2_SUPPRESS_OUTPUT 0x23 50 | #define PDUTYPE2_SHUTDOWN_REQUEST 0x24 51 | #define PDUTYPE2_SHUTDOWN_DENIED 0x25 52 | #define PDUTYPE2_SAVE_SESSION_INFO 0x26 53 | #define PDUTYPE2_FONTLIST 0x27 54 | #define PDUTYPE2_FONTMAP 0x28 55 | #define PDUTYPE2_SET_KEYBOARD_INDICATORS 0x29 56 | #define PDUTYPE2_BITMAPCACHE_PERSISTENT_LIST 0x2B 57 | #define PDUTYPE2_BITMAPCACHE_ERROR_PDU 0x2C 58 | #define PDUTYPE2_SET_KEYBOARD_IME_STATUS 0x2D 59 | #define PDUTYPE2_OFFSCRCACHE_ERROR_PDU 0x2E 60 | #define PDUTYPE2_SET_ERROR_INFO_PDU 0x2F 61 | #define PDUTYPE2_DRAWNINEGRID_ERROR_PDU 0x30 62 | #define PDUTYPE2_DRAWGDIPLUS_ERROR_PDU 0x31 63 | #define PDUTYPE2_ARC_STATUS_PDU 0x32 64 | #define PDUTYPE2_STATUS_INFO_PDU 0x36 65 | #define PDUTYPE2_MONITOR_LAYOUT_PDU 0x37 66 | 67 | /* Synchronize PDU Data - messageType */ 68 | #define SYNCMSGTYPE_SYNC 0x0001 69 | 70 | /* Control PDU Data - action */ 71 | #define CTRLACTION_REQUEST_CONTROL 0x0001 72 | #define CTRLACTION_GRANTED_CONTROL 0x0002 73 | #define CTRLACTION_DETACH 0x0003 74 | #define CTRLACTION_COOPERATE 0x0004 75 | 76 | /* Font Map PDU Data - mapFlags */ 77 | #define FONTMAP_FIRST 0x0001 78 | #define FONTMAP_LAST 0x0002 79 | 80 | /* Server Graphics Update PDU - updateType */ 81 | #define UPDATETYPE_ORDERS 0x0000 82 | #define UPDATETYPE_BITMAP 0x0001 83 | #define UPDATETYPE_PALETTE 0x0002 84 | #define UPDATETYPE_SYNCHRONIZE 0x0003 85 | 86 | /* Bitmap Data - flags */ 87 | #define BITMAP_COMPRESSION 0x0001 88 | #define NO_BITMAP_COMPRESSION_HDR 0x0400 89 | 90 | /* Suppress Output PDU Data - allowDisplayUpdates */ 91 | #define SUPPRESS_DISPLAY_UPDATES 0x00 92 | #define ALLOW_DISPLAY_UPDATES 0x01 93 | 94 | typedef struct _v2r_rdp_t { 95 | v2r_session_t *session; 96 | v2r_sec_t *sec; 97 | v2r_packet_t *packet; 98 | 99 | uint8_t allow_display_updates; 100 | 101 | /* keyboard input variables */ 102 | v2r_keymap_t *keymap; 103 | uint8_t lshift; 104 | uint8_t rshift; 105 | uint8_t capslock; 106 | uint8_t numlock; 107 | uint8_t altgr; 108 | } v2r_rdp_t; 109 | 110 | typedef struct _share_ctrl_hdr_t { 111 | uint16_t total_length; 112 | uint16_t type:4; 113 | uint16_t version_low:4; 114 | uint16_t version_high:8; 115 | uint16_t pdu_source; 116 | } __attribute__ ((packed)) share_ctrl_hdr_t; 117 | 118 | typedef struct _share_data_hdr_t { 119 | share_ctrl_hdr_t share_ctrl_hdr; 120 | uint32_t share_id; 121 | uint8_t pad1; 122 | uint8_t stream_id; 123 | uint16_t uncompressed_length; 124 | uint8_t pdu_type2; 125 | uint8_t compressed_type; 126 | uint16_t compressed_length; 127 | } __attribute__ ((packed)) share_data_hdr_t; 128 | 129 | extern v2r_rdp_t *v2r_rdp_init(v2r_session_t *session); 130 | extern void v2r_rdp_destory(v2r_rdp_t *r); 131 | extern int v2r_rdp_build_conn(v2r_rdp_t *r, int client_fd); 132 | extern void v2r_rdp_init_packet(v2r_packet_t *p, uint16_t offset); 133 | extern int v2r_rdp_recv(v2r_rdp_t *r, v2r_packet_t *p, share_data_hdr_t *hdr); 134 | extern int v2r_rdp_send(v2r_rdp_t *r, v2r_packet_t *p, share_data_hdr_t *hdr); 135 | extern int v2r_rdp_send_bitmap_update(v2r_rdp_t *r, uint16_t left, uint16_t top, 136 | uint16_t right, uint16_t bottom, 137 | uint16_t width, uint16_t height, 138 | uint16_t bpp, uint16_t bitmap_length, 139 | uint8_t *data); 140 | extern int v2r_rdp_send_palette_update(v2r_rdp_t *r, uint32_t number_colors, 141 | uint8_t (*palette_entries)[3]); 142 | extern int v2r_rdp_send_play_sound(v2r_rdp_t *r, uint32_t duration, 143 | uint32_t frequency); 144 | extern int v2r_rdp_send_scrblt_order(v2r_rdp_t *r, uint16_t left, uint16_t top, 145 | uint16_t width, uint16_t height, 146 | uint16_t x_src, uint16_t y_src); 147 | extern int v2r_rdp_process(v2r_rdp_t *r); 148 | 149 | #endif // _RDP_H_ 150 | -------------------------------------------------------------------------------- /sec.c: -------------------------------------------------------------------------------- 1 | /** 2 | * vnc2rdp: proxy for RDP client connect to VNC server 3 | * 4 | * Copyright 2014 Yiwei Li 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include "log.h" 24 | #include "sec.h" 25 | 26 | static const uint8_t pub_exp[4] = {0x01, 0x00, 0x01, 0x00}; 27 | static const uint8_t modulus[64] = { 28 | 0x67, 0xab, 0x0e, 0x6a, 0x9f, 0xd6, 0x2b, 0xa3, 0x32, 0x2f, 29 | 0x41, 0xd1, 0xce, 0xee, 0x61, 0xc3, 0x76, 0x0b, 0x26, 0x11, 30 | 0x70, 0x48, 0x8a, 0x8d, 0x23, 0x81, 0x95, 0xa0, 0x39, 0xf7, 31 | 0x5b, 0xaa, 0x3e, 0xf1, 0xed, 0xb8, 0xc4, 0xee, 0xce, 0x5f, 32 | 0x6a, 0xf5, 0x43, 0xce, 0x5f, 0x60, 0xca, 0x6c, 0x06, 0x75, 33 | 0xae, 0xc0, 0xd6, 0xa4, 0x0c, 0x92, 0xa4, 0xc6, 0x75, 0xea, 34 | 0x64, 0xb2, 0x50, 0x5b 35 | }; 36 | static const uint8_t modulus_zero_padding[8] = { 37 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 38 | }; 39 | static const uint8_t signature[64] = { 40 | 0x6a, 0x41, 0xb1, 0x43, 0xcf, 0x47, 0x6f, 0xf1, 0xe6, 0xcc, 41 | 0xa1, 0x72, 0x97, 0xd9, 0xe1, 0x85, 0x15, 0xb3, 0xc2, 0x39, 42 | 0xa0, 0xa6, 0x26, 0x1a, 0xb6, 0x49, 0x01, 0xfa, 0xa6, 0xda, 43 | 0x60, 0xd7, 0x45, 0xf7, 0x2c, 0xee, 0xe4, 0x8e, 0x64, 0x2e, 44 | 0x37, 0x49, 0xf0, 0x4c, 0x94, 0x6f, 0x08, 0xf5, 0x63, 0x4c, 45 | 0x56, 0x29, 0x55, 0x5a, 0x63, 0x41, 0x2c, 0x20, 0x65, 0x95, 46 | 0x99, 0xb1, 0x15, 0x7c 47 | }; 48 | static const uint8_t signature_zero_padding[8] = { 49 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 50 | }; 51 | 52 | int 53 | v2r_sec_build_conn(v2r_sec_t *s, int client_fd) 54 | { 55 | if (v2r_mcs_build_conn(s->mcs, client_fd) == -1) { 56 | goto fail; 57 | } 58 | 59 | /* TODO receive Client Security Exchange PDU */ 60 | return 0; 61 | 62 | fail: 63 | return -1; 64 | } 65 | 66 | v2r_sec_t * 67 | v2r_sec_init(v2r_session_t *session) 68 | { 69 | v2r_sec_t *s = NULL; 70 | 71 | s = (v2r_sec_t *)malloc(sizeof(v2r_sec_t)); 72 | if (s == NULL) { 73 | goto fail; 74 | } 75 | memset(s, 0, sizeof(v2r_sec_t)); 76 | 77 | s->session = session; 78 | 79 | s->mcs = v2r_mcs_init(session); 80 | if (s->mcs == NULL) { 81 | goto fail; 82 | } 83 | 84 | return s; 85 | 86 | fail: 87 | v2r_sec_destory(s); 88 | return NULL; 89 | } 90 | 91 | void 92 | v2r_sec_destory(v2r_sec_t *s) 93 | { 94 | if (s == NULL) { 95 | return; 96 | } 97 | if (s->mcs != NULL) { 98 | v2r_mcs_destory(s->mcs); 99 | } 100 | free(s); 101 | } 102 | 103 | int 104 | v2r_sec_recv(v2r_sec_t *s, v2r_packet_t *p, uint16_t *sec_flags, 105 | uint16_t *channel_id) 106 | { 107 | uint8_t choice = 0; 108 | 109 | if (v2r_mcs_recv(s->mcs, p, &choice, channel_id) == -1) { 110 | goto fail; 111 | } 112 | /* check if is send data request */ 113 | if (choice != MCS_SEND_DATA_REQUEST) { 114 | goto fail; 115 | } 116 | /* parse security header */ 117 | V2R_PACKET_READ_UINT16_LE(p, *sec_flags); 118 | /* skip flagsHi */ 119 | V2R_PACKET_SEEK(p, 2); 120 | 121 | return 0; 122 | 123 | fail: 124 | return -1; 125 | } 126 | 127 | int 128 | v2r_sec_send(v2r_sec_t *s, v2r_packet_t *p, uint16_t sec_flags, 129 | uint16_t channel_id) 130 | { 131 | p->current = p->sec; 132 | V2R_PACKET_WRITE_UINT16_LE(p, sec_flags); 133 | V2R_PACKET_WRITE_UINT16_LE(p, 0); 134 | return v2r_mcs_send(s->mcs, p, MCS_SEND_DATA_INDICATION, channel_id); 135 | } 136 | 137 | void 138 | v2r_sec_init_packet(v2r_packet_t *p) 139 | { 140 | v2r_mcs_init_packet(p); 141 | p->sec = p->current; 142 | V2R_PACKET_SEEK(p, 4); 143 | } 144 | 145 | int 146 | v2r_sec_generate_server_random(v2r_sec_t *s) 147 | { 148 | int i; 149 | unsigned int seed; 150 | struct timespec tp; 151 | 152 | if (clock_gettime(CLOCK_MONOTONIC_COARSE, &tp) == -1) { 153 | v2r_log_error("get current time error: %s", ERRMSG); 154 | goto fail; 155 | } 156 | seed = (unsigned int)tp.tv_nsec; 157 | for (i = 0; i < SERVER_RANDOM_LEN; i++) { 158 | s->server_random[i] = rand_r(&seed); 159 | } 160 | 161 | return 0; 162 | 163 | fail: 164 | return -1; 165 | } 166 | 167 | int 168 | v2r_sec_write_server_certificate(v2r_sec_t *s, v2r_packet_t *p) 169 | { 170 | /* Currently we only support server proprietary certificate */ 171 | uint32_t keylen, bitlen, datalen; 172 | 173 | bitlen = 64 * 8; 174 | keylen = bitlen / 8 + 8; 175 | datalen = bitlen / 8 - 1; 176 | 177 | /* dwVersion */ 178 | V2R_PACKET_WRITE_UINT32_LE(p, CERT_CHAIN_VERSION_1); 179 | /* dwSigAlgId */ 180 | V2R_PACKET_WRITE_UINT32_LE(p, 0x00000001); 181 | /* dwKeyAlgId */ 182 | V2R_PACKET_WRITE_UINT32_LE(p, 0x00000001); 183 | /* wPublicKeyBlobType */ 184 | V2R_PACKET_WRITE_UINT16_LE(p, 0x0006); 185 | /* wPublicKeyBlobLen */ 186 | V2R_PACKET_WRITE_UINT16_LE(p, 92); 187 | /* magic */ 188 | V2R_PACKET_WRITE_UINT32_LE(p, 0x31415352); 189 | /* keylen */ 190 | V2R_PACKET_WRITE_UINT32_LE(p, keylen); 191 | /* bitlen */ 192 | V2R_PACKET_WRITE_UINT32_LE(p, bitlen); 193 | /* datalen */ 194 | V2R_PACKET_WRITE_UINT32_LE(p, datalen); 195 | /* pubExp */ 196 | V2R_PACKET_WRITE_N(p, pub_exp, sizeof(pub_exp)); 197 | /* modulus */ 198 | V2R_PACKET_WRITE_N(p, modulus, sizeof(modulus)); 199 | /* 8 bytes of zero padding */ 200 | V2R_PACKET_WRITE_N(p, modulus_zero_padding, sizeof(modulus_zero_padding)); 201 | /* wSignatureBlobType */ 202 | V2R_PACKET_WRITE_UINT16_LE(p, 0x0008); 203 | /* wSignatureBlobLen */ 204 | V2R_PACKET_WRITE_UINT16_LE(p, 0x0048); 205 | /* SignatureBlob */ 206 | V2R_PACKET_WRITE_N(p, signature, sizeof(signature)); 207 | /* 8 bytes of zero padding */ 208 | V2R_PACKET_WRITE_N(p, signature_zero_padding, 209 | sizeof(signature_zero_padding)); 210 | 211 | return 0; 212 | } 213 | -------------------------------------------------------------------------------- /sec.h: -------------------------------------------------------------------------------- 1 | /** 2 | * vnc2rdp: proxy for RDP client connect to VNC server 3 | * 4 | * Copyright 2014 Yiwei Li 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef _SEC_H_ 20 | #define _SEC_H_ 21 | 22 | #include "mcs.h" 23 | #include "session.h" 24 | 25 | #define ENCRYPTION_METHOD_NONE 0x00000000 26 | #define ENCRYPTION_METHOD_40BIT 0x00000001 27 | #define ENCRYPTION_METHOD_128BIT 0x00000002 28 | #define ENCRYPTION_METHOD_56BIT 0x00000008 29 | #define ENCRYPTION_METHOD_FIPS 0x00000010 30 | 31 | #define ENCRYPTION_LEVEL_NONE 0x00000000 32 | #define ENCRYPTION_LEVEL_LOW 0x00000001 33 | #define ENCRYPTION_LEVEL_CLIENT_COMPATIBLE 0x00000002 34 | #define ENCRYPTION_LEVEL_HIGH 0x00000003 35 | #define ENCRYPTION_LEVEL_FIPS 0x00000004 36 | 37 | /* Server Security Data - serverRandomLen */ 38 | #define SERVER_RANDOM_LEN 32 39 | 40 | /* Server Certificate - certChainVersion */ 41 | #define CERT_CHAIN_VERSION_1 0x00000001 42 | #define CERT_CHAIN_VERSION_2 0x00000002 43 | 44 | #define SEC_EXCHANGE_PKT 0x0001 45 | #define SEC_TRANSPORT_REQ 0x0002 46 | #define RDP_SEC_TRANSPORT_RSP 0x0004 47 | #define SEC_ENCRYPT 0x0008 48 | #define SEC_RESET_SEQNO 0x0010 49 | #define SEC_IGNORE_SEQNO 0x0020 50 | #define SEC_INFO_PKT 0x0040 51 | #define SEC_LICENSE_PKT 0x0080 52 | #define SEC_LICENSE_ENCRYPT_CS 0x0200 53 | #define SEC_LICENSE_ENCRYPT_SC 0x0200 54 | #define SEC_REDIRECTION_PKT 0x0400 55 | #define SEC_SECURE_CHECKSUM 0x0800 56 | #define SEC_AUTODETECT_REQ 0x1000 57 | #define SEC_AUTODETECT_RSP 0x2000 58 | #define SEC_HEARTBEAT 0x4000 59 | #define SEC_FLAGSHI_VALID 0x8000 60 | 61 | typedef struct _v2r_sec_t { 62 | v2r_session_t *session; 63 | v2r_mcs_t *mcs; 64 | 65 | uint8_t server_random[SERVER_RANDOM_LEN]; 66 | } v2r_sec_t; 67 | 68 | extern v2r_sec_t *v2r_sec_init(v2r_session_t *session); 69 | extern void v2r_sec_destory(v2r_sec_t *s); 70 | extern int v2r_sec_build_conn(v2r_sec_t *s, int client_fd); 71 | extern int v2r_sec_recv(v2r_sec_t *s, v2r_packet_t *p, uint16_t *sec_flags, 72 | uint16_t *channel_id); 73 | extern int v2r_sec_send(v2r_sec_t *s, v2r_packet_t *p, uint16_t sec_flags, 74 | uint16_t channel_id); 75 | extern void v2r_sec_init_packet(v2r_packet_t *p); 76 | extern int v2r_sec_generate_server_random(v2r_sec_t *s); 77 | extern int v2r_sec_write_server_certificate(v2r_sec_t *s, v2r_packet_t *p); 78 | 79 | #endif // _SEC_H_ 80 | -------------------------------------------------------------------------------- /session.c: -------------------------------------------------------------------------------- 1 | /** 2 | * vnc2rdp: proxy for RDP client connect to VNC server 3 | * 4 | * Copyright 2014 Yiwei Li 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "log.h" 25 | #include "rdp.h" 26 | #include "session.h" 27 | #include "vnc.h" 28 | 29 | v2r_session_t * 30 | v2r_session_init(const v2r_session_opt_t *opt) 31 | { 32 | v2r_session_t *s = NULL; 33 | 34 | s = (v2r_session_t *)malloc(sizeof(v2r_session_t)); 35 | if (s == NULL) { 36 | goto fail; 37 | } 38 | memset(s, 0, sizeof(v2r_session_t)); 39 | 40 | s->opt = opt; 41 | 42 | /* connect to VNC server */ 43 | s->vnc = v2r_vnc_init(s); 44 | if (s->vnc == NULL) { 45 | v2r_log_error("connect to vnc server error"); 46 | goto fail; 47 | } 48 | v2r_log_info("connect to vnc server success"); 49 | 50 | /* accept RDP connection */ 51 | s->rdp = v2r_rdp_init(s); 52 | if (s->rdp == NULL) { 53 | v2r_log_error("accept new rdp connection error"); 54 | goto fail; 55 | } 56 | v2r_log_info("accept new rdp connection success"); 57 | 58 | return s; 59 | 60 | fail: 61 | v2r_session_destory(s); 62 | return NULL; 63 | } 64 | 65 | void 66 | v2r_session_destory(v2r_session_t *s) 67 | { 68 | if (s == NULL) { 69 | return; 70 | } 71 | if (s->rdp != NULL) { 72 | v2r_rdp_destory(s->rdp); 73 | } 74 | if (s->vnc != NULL) { 75 | v2r_vnc_destory(s->vnc); 76 | } 77 | if (s->epoll_fd != 0) { 78 | close(s->epoll_fd); 79 | } 80 | free(s); 81 | } 82 | 83 | int 84 | v2r_session_build_conn(v2r_session_t *s, int client_fd, int server_fd) 85 | { 86 | if (v2r_vnc_build_conn(s->vnc, server_fd) == -1) { 87 | goto fail; 88 | } 89 | if (v2r_rdp_build_conn(s->rdp, client_fd) == -1) { 90 | goto fail; 91 | } 92 | 93 | return 0; 94 | 95 | fail: 96 | return -1; 97 | } 98 | 99 | void 100 | v2r_session_transmit(v2r_session_t *s) 101 | { 102 | int i, nfds, rdp_fd, vnc_fd; 103 | struct epoll_event ev, events[MAX_EVENTS]; 104 | 105 | s->epoll_fd = epoll_create(2); 106 | if (s->epoll_fd == -1) { 107 | goto fail; 108 | } 109 | 110 | rdp_fd = s->rdp->sec->mcs->x224->tpkt->fd; 111 | vnc_fd = s->vnc->fd; 112 | 113 | memset(&ev, 0, sizeof(ev)); 114 | ev.events = EPOLLIN; 115 | ev.data.fd = rdp_fd; 116 | if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, rdp_fd, &ev) == -1) { 117 | goto fail; 118 | } 119 | 120 | memset(&ev, 0, sizeof(ev)); 121 | ev.events = EPOLLIN; 122 | ev.data.fd = vnc_fd; 123 | if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, vnc_fd, &ev) == -1) { 124 | goto fail; 125 | } 126 | 127 | v2r_log_info("session transmit start"); 128 | 129 | while (1) { 130 | nfds = epoll_wait(s->epoll_fd, events, MAX_EVENTS, -1); 131 | if (nfds == -1) { 132 | goto fail; 133 | } 134 | for (i = 0; i < nfds; i++) { 135 | if (events[i].data.fd == rdp_fd) { 136 | if (v2r_rdp_process(s->rdp) == -1) { 137 | goto fail; 138 | } 139 | } else if (events[i].data.fd == vnc_fd) { 140 | if (v2r_vnc_process(s->vnc) == -1) { 141 | goto fail; 142 | } 143 | } 144 | } 145 | } 146 | 147 | fail: 148 | v2r_log_info("session transmit end"); 149 | return; 150 | } 151 | -------------------------------------------------------------------------------- /session.h: -------------------------------------------------------------------------------- 1 | /** 2 | * vnc2rdp: proxy for RDP client connect to VNC server 3 | * 4 | * Copyright 2014 Yiwei Li 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef _SESSION_H_ 20 | #define _SESSION_H_ 21 | 22 | #include 23 | 24 | #define MAX_EVENTS 64 25 | 26 | struct _v2r_rdp_t; 27 | struct _v2r_vnc_t; 28 | typedef struct _v2r_rdp_t v2r_rdp_t; 29 | typedef struct _v2r_vnc_t v2r_vnc_t; 30 | 31 | typedef struct _v2r_session_opt_t { 32 | uint32_t encryption_method; 33 | char vnc_server_ip[INET_ADDRSTRLEN]; 34 | uint16_t vnc_server_port; 35 | char vnc_password[8]; 36 | uint8_t shared; 37 | uint8_t viewonly; 38 | } v2r_session_opt_t; 39 | 40 | typedef struct _v2r_session_t { 41 | v2r_rdp_t *rdp; 42 | v2r_vnc_t *vnc; 43 | int epoll_fd; 44 | const v2r_session_opt_t *opt; 45 | } v2r_session_t; 46 | 47 | extern v2r_session_t *v2r_session_init(const v2r_session_opt_t *opt); 48 | extern void v2r_session_destory(v2r_session_t *s); 49 | extern int v2r_session_build_conn(v2r_session_t *s, int client_fd, 50 | int server_fd); 51 | extern void v2r_session_transmit(v2r_session_t *s); 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /tpkt.c: -------------------------------------------------------------------------------- 1 | /** 2 | * vnc2rdp: proxy for RDP client connect to VNC server 3 | * 4 | * Copyright 2014 Yiwei Li 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "log.h" 27 | #include "tpkt.h" 28 | 29 | v2r_tpkt_t * 30 | v2r_tpkt_init(v2r_session_t *session) 31 | { 32 | v2r_tpkt_t *t = NULL; 33 | 34 | t = (v2r_tpkt_t *)malloc(sizeof(v2r_tpkt_t)); 35 | if (t == NULL) { 36 | goto fail; 37 | } 38 | memset(t, 0, sizeof(v2r_tpkt_t)); 39 | 40 | t->session = session; 41 | 42 | return t; 43 | 44 | fail: 45 | v2r_tpkt_destory(t); 46 | return NULL; 47 | } 48 | 49 | void 50 | v2r_tpkt_destory(v2r_tpkt_t *t) 51 | { 52 | if (t == NULL) { 53 | return; 54 | } 55 | if (t->fd != 0) { 56 | close(t->fd); 57 | } 58 | free(t); 59 | } 60 | 61 | int 62 | v2r_tpkt_build_conn(v2r_tpkt_t *t, int client_fd) 63 | { 64 | int optval = 1; 65 | 66 | t->fd = client_fd; 67 | 68 | /* disable Nagle algorithm */ 69 | if (setsockopt(t->fd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval)) 70 | == -1) { 71 | goto fail; 72 | } 73 | 74 | return 0; 75 | 76 | fail: 77 | return -1; 78 | } 79 | 80 | int 81 | v2r_tpkt_recv(v2r_tpkt_t *t, v2r_packet_t *p) 82 | { 83 | int n = 0; 84 | uint8_t tpkt_version = 0; 85 | uint16_t tpkt_len = 0; 86 | 87 | v2r_packet_reset(p); 88 | 89 | n = recv(t->fd, p->current, TPKT_HEADER_LEN, MSG_WAITALL); 90 | if (n == -1) { 91 | v2r_log_error("recevie data from RDP client error: %s", ERRMSG); 92 | goto fail; 93 | } 94 | if (n == 0) { 95 | v2r_log_info("RDP client orderly shutdown"); 96 | goto fail; 97 | } 98 | p->end += n; 99 | 100 | /* TPKT version must be 3 */ 101 | V2R_PACKET_READ_UINT8(p, tpkt_version); 102 | if (tpkt_version != TPKT_VERSION) { 103 | goto fail; 104 | } 105 | V2R_PACKET_SEEK_UINT8(p); 106 | V2R_PACKET_READ_UINT16_BE(p, tpkt_len); 107 | 108 | n = recv(t->fd, p->current, tpkt_len - TPKT_HEADER_LEN, 109 | MSG_WAITALL); 110 | if (n == -1) { 111 | v2r_log_error("recevie data from RDP client error: %s", ERRMSG); 112 | goto fail; 113 | } 114 | if (n == 0) { 115 | v2r_log_info("RDP client orderly shutdown"); 116 | goto fail; 117 | } 118 | p->end += n; 119 | 120 | return 0; 121 | 122 | fail: 123 | return -1; 124 | } 125 | 126 | int 127 | v2r_tpkt_send(v2r_tpkt_t *t, v2r_packet_t *p) 128 | { 129 | p->current = p->tpkt; 130 | V2R_PACKET_WRITE_UINT8(p, TPKT_VERSION); 131 | V2R_PACKET_WRITE_UINT8(p, 0); 132 | V2R_PACKET_WRITE_UINT16_BE(p, V2R_PACKET_LEN(p)); 133 | 134 | if (-1 == send(t->fd, p->data, V2R_PACKET_LEN(p), 0)) { 135 | goto fail; 136 | } 137 | 138 | return 0; 139 | 140 | fail: 141 | return -1; 142 | } 143 | 144 | void 145 | v2r_tpkt_init_packet(v2r_packet_t *p) 146 | { 147 | v2r_packet_reset(p); 148 | p->tpkt = p->current; 149 | V2R_PACKET_SEEK(p, TPKT_HEADER_LEN); 150 | } 151 | -------------------------------------------------------------------------------- /tpkt.h: -------------------------------------------------------------------------------- 1 | /** 2 | * vnc2rdp: proxy for RDP client connect to VNC server 3 | * 4 | * Copyright 2014 Yiwei Li 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef _TPKT_H_ 20 | #define _TPKT_H_ 21 | 22 | #include "packet.h" 23 | #include "session.h" 24 | 25 | #define TPKT_HEADER_LEN 4 26 | #define TPKT_VERSION 3 27 | 28 | typedef struct _v2r_tpkt_t { 29 | v2r_session_t *session; 30 | 31 | int fd; 32 | } v2r_tpkt_t; 33 | 34 | extern v2r_tpkt_t *v2r_tpkt_init(v2r_session_t *session); 35 | extern void v2r_tpkt_destory(v2r_tpkt_t *t); 36 | extern int v2r_tpkt_build_conn(v2r_tpkt_t *t, int client_fd); 37 | extern int v2r_tpkt_recv(v2r_tpkt_t *t, v2r_packet_t *p); 38 | extern int v2r_tpkt_send(v2r_tpkt_t *t, v2r_packet_t *p); 39 | extern void v2r_tpkt_init_packet(v2r_packet_t *p); 40 | 41 | #endif // _TPKT_H_ 42 | -------------------------------------------------------------------------------- /vnc.c: -------------------------------------------------------------------------------- 1 | /** 2 | * vnc2rdp: proxy for RDP client connect to VNC server 3 | * 4 | * Copyright 2014 Yiwei Li 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "log.h" 26 | #include "rdp.h" 27 | #include "vnc.h" 28 | #include "vncauth.h" 29 | 30 | static int 31 | v2r_vnc_recv(v2r_vnc_t *v) 32 | { 33 | int n = 0; 34 | 35 | v2r_packet_reset(v->packet); 36 | 37 | n = recv(v->fd, v->packet->current, v->packet->max_len, 0); 38 | if (n == -1 || n == 0) { 39 | goto fail; 40 | } 41 | v->packet->end += n; 42 | 43 | return 0; 44 | 45 | fail: 46 | return -1; 47 | } 48 | 49 | static int 50 | v2r_vnc_recv1(v2r_vnc_t *v, size_t len) 51 | { 52 | int n = 0; 53 | 54 | v2r_packet_reset(v->packet); 55 | 56 | n = recv(v->fd, v->packet->current, len, MSG_WAITALL); 57 | if (n == -1 || n == 0) { 58 | goto fail; 59 | } 60 | v->packet->end += n; 61 | 62 | return 0; 63 | 64 | fail: 65 | return -1; 66 | } 67 | 68 | static int 69 | v2r_vnc_send(v2r_vnc_t *v) 70 | { 71 | int n = 0; 72 | 73 | n = send(v->fd, v->packet->data, V2R_PACKET_LEN(v->packet), 0); 74 | if (n == -1) { 75 | goto fail; 76 | } 77 | 78 | return 0; 79 | 80 | fail: 81 | return -1; 82 | } 83 | 84 | static int 85 | v2r_vnc_process_vnc_authentication(v2r_vnc_t *v) 86 | { 87 | uint8_t challenge[CHALLENGESIZE]; 88 | uint32_t security_result; 89 | 90 | /* receive challenge */ 91 | if (v2r_vnc_recv1(v, CHALLENGESIZE) == -1) { 92 | goto fail; 93 | } 94 | V2R_PACKET_READ_N(v->packet, challenge, CHALLENGESIZE); 95 | rfbEncryptBytes(challenge, v->session->opt->vnc_password); 96 | /* send response */ 97 | v2r_packet_reset(v->packet); 98 | V2R_PACKET_WRITE_N(v->packet, challenge, CHALLENGESIZE); 99 | V2R_PACKET_END(v->packet); 100 | if (v2r_vnc_send(v) == -1) { 101 | goto fail; 102 | } 103 | /* receive SecurityResult */ 104 | if (v2r_vnc_recv1(v, sizeof(security_result)) == -1) { 105 | goto fail; 106 | } 107 | V2R_PACKET_READ_UINT32_BE(v->packet, security_result); 108 | if (security_result == RFB_SEC_RESULT_OK) { 109 | v2r_log_info("vnc authentication success"); 110 | } else { 111 | v2r_log_error("vnc authentication failed"); 112 | goto fail; 113 | } 114 | 115 | return 0; 116 | 117 | fail: 118 | return -1; 119 | } 120 | 121 | static int 122 | v2r_vnc_recv_server_init(v2r_vnc_t *v) 123 | { 124 | if (v2r_vnc_recv(v) == -1) { 125 | goto fail; 126 | } 127 | V2R_PACKET_READ_UINT16_BE(v->packet, v->framebuffer_width); 128 | V2R_PACKET_READ_UINT16_BE(v->packet, v->framebuffer_height); 129 | V2R_PACKET_READ_UINT8(v->packet, v->bits_per_pixel); 130 | V2R_PACKET_READ_UINT8(v->packet, v->depth); 131 | V2R_PACKET_READ_UINT8(v->packet, v->big_endian_flag); 132 | V2R_PACKET_READ_UINT8(v->packet, v->true_colour_flag); 133 | V2R_PACKET_READ_UINT16_BE(v->packet, v->red_max); 134 | V2R_PACKET_READ_UINT16_BE(v->packet, v->green_max); 135 | V2R_PACKET_READ_UINT16_BE(v->packet, v->blue_max); 136 | V2R_PACKET_READ_UINT8(v->packet, v->red_shift); 137 | V2R_PACKET_READ_UINT8(v->packet, v->green_shift); 138 | V2R_PACKET_READ_UINT8(v->packet, v->blue_shift); 139 | v2r_log_info("server framebuffer size: %dx%d", v->framebuffer_width, 140 | v->framebuffer_height); 141 | v2r_log_info("server bpp: %d, depth: %d, big_endian: %d, true_colour: %d, " 142 | "red_max: %d, green_max: %d, blue_max: %d, " 143 | "red_shift: %d, green_shift: %d, blue_shift: %d", 144 | v->bits_per_pixel, v->depth, v->big_endian_flag, 145 | v->true_colour_flag, v->red_max, v->green_max, v->blue_max, 146 | v->red_shift, v->green_shift, v->blue_shift); 147 | 148 | /* set big_endian_flag to 0 because RDP use little endian */ 149 | v->big_endian_flag = 0; 150 | 151 | /* set colour shift to RDP order */ 152 | switch (v->depth) { 153 | case 24: 154 | v->red_shift = 16; 155 | v->green_shift = 8; 156 | v->blue_shift = 0; 157 | v->bpp = 32; 158 | break; 159 | case 16: 160 | v->red_shift = 11; 161 | v->green_shift = 5; 162 | v->blue_shift = 0; 163 | v->bpp = 16; 164 | break; 165 | case 15: 166 | v->red_shift = 10; 167 | v->green_shift = 5; 168 | v->blue_shift = 0; 169 | v->bpp = 15; 170 | break; 171 | case 8: 172 | v->true_colour_flag = 0; 173 | v->bpp = 8; 174 | break; 175 | } 176 | 177 | return 0; 178 | 179 | fail: 180 | return -1; 181 | } 182 | 183 | int 184 | v2r_vnc_build_conn(v2r_vnc_t *v, int server_fd) 185 | { 186 | int optval = 1; 187 | 188 | v->fd = server_fd; 189 | 190 | /* disable Nagle algorithm */ 191 | if (setsockopt(v->fd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval)) 192 | == -1) { 193 | goto fail; 194 | } 195 | 196 | /* receive ProtocolVersion */ 197 | if (v2r_vnc_recv(v) == -1) { 198 | goto fail; 199 | } 200 | 201 | /* send ProtocolVersion */ 202 | v2r_packet_reset(v->packet); 203 | V2R_PACKET_WRITE_N(v->packet, RFB_PROTOCOL_VERSION, 204 | strlen(RFB_PROTOCOL_VERSION)); 205 | V2R_PACKET_END(v->packet); 206 | if (v2r_vnc_send(v) == -1) { 207 | goto fail; 208 | } 209 | 210 | /* receive security-type */ 211 | if (v2r_vnc_recv1(v, sizeof(v->security_type)) == -1) { 212 | goto fail; 213 | } 214 | V2R_PACKET_READ_UINT32_BE(v->packet, v->security_type); 215 | switch (v->security_type) { 216 | case RFB_SEC_TYPE_NONE: 217 | break; 218 | case RFB_SEC_TYPE_VNC_AUTH: 219 | if (v2r_vnc_process_vnc_authentication(v) == -1) { 220 | goto fail; 221 | } 222 | break; 223 | default: 224 | goto fail; 225 | } 226 | 227 | /* send ClientInit message */ 228 | v2r_packet_reset(v->packet); 229 | V2R_PACKET_WRITE_UINT8(v->packet, v->session->opt->shared); 230 | v2r_log_info("connect with shared-flag: %d", v->session->opt->shared); 231 | V2R_PACKET_END(v->packet); 232 | if (v2r_vnc_send(v) == -1) { 233 | goto fail; 234 | } 235 | 236 | /* recv ServerInit message */ 237 | if (v2r_vnc_recv_server_init(v) == -1) { 238 | goto fail; 239 | } 240 | 241 | /* send SetPixelFormat message */ 242 | v2r_packet_reset(v->packet); 243 | V2R_PACKET_WRITE_UINT8(v->packet, RFB_SET_PIXEL_FORMAT); 244 | V2R_PACKET_WRITE_UINT8(v->packet, 0); 245 | V2R_PACKET_WRITE_UINT8(v->packet, 0); 246 | V2R_PACKET_WRITE_UINT8(v->packet, 0); 247 | /* bits-per-pixel */ 248 | V2R_PACKET_WRITE_UINT8(v->packet, v->bits_per_pixel); 249 | /* depth */ 250 | V2R_PACKET_WRITE_UINT8(v->packet, v->depth); 251 | /* big-endian-flag */ 252 | V2R_PACKET_WRITE_UINT8(v->packet, v->big_endian_flag); 253 | /* true-colour-flag */ 254 | V2R_PACKET_WRITE_UINT8(v->packet, v->true_colour_flag); 255 | /* red-max */ 256 | V2R_PACKET_WRITE_UINT16_BE(v->packet, v->red_max); 257 | /* green-max */ 258 | V2R_PACKET_WRITE_UINT16_BE(v->packet, v->green_max); 259 | /* blue-max */ 260 | V2R_PACKET_WRITE_UINT16_BE(v->packet, v->blue_max); 261 | /* red-shift */ 262 | V2R_PACKET_WRITE_UINT8(v->packet, v->red_shift); 263 | /* green-shift */ 264 | V2R_PACKET_WRITE_UINT8(v->packet, v->green_shift); 265 | /* blue-shift */ 266 | V2R_PACKET_WRITE_UINT8(v->packet, v->blue_shift); 267 | /* padding */ 268 | V2R_PACKET_WRITE_UINT8(v->packet, 0); 269 | V2R_PACKET_WRITE_UINT8(v->packet, 0); 270 | V2R_PACKET_WRITE_UINT8(v->packet, 0); 271 | V2R_PACKET_END(v->packet); 272 | if (v2r_vnc_send(v) == -1) { 273 | goto fail; 274 | } 275 | 276 | /* send SetEncodings message */ 277 | v2r_packet_reset(v->packet); 278 | V2R_PACKET_WRITE_UINT8(v->packet, RFB_SET_ENCODINGS); 279 | V2R_PACKET_WRITE_UINT8(v->packet, 0); 280 | V2R_PACKET_WRITE_UINT16_BE(v->packet, 2); 281 | V2R_PACKET_WRITE_UINT32_BE(v->packet, RFB_ENCODING_RAW); 282 | V2R_PACKET_WRITE_UINT32_BE(v->packet, RFB_ENCODING_COPYRECT); 283 | //V2R_PACKET_WRITE_UINT32_BE(v->packet, RFB_ENCODING_CURSOR); 284 | //V2R_PACKET_WRITE_UINT32_BE(v->packet, RFB_ENCODING_DESKTOP_SIZE); 285 | V2R_PACKET_END(v->packet); 286 | if (v2r_vnc_send(v) == -1) { 287 | goto fail; 288 | } 289 | 290 | /* send FramebufferUpdateRequest message */ 291 | if (v2r_vnc_send_fb_update_req(v, 0, 0, 0, v->framebuffer_width, 292 | v->framebuffer_height) == -1) { 293 | goto fail; 294 | } 295 | 296 | return 0; 297 | 298 | fail: 299 | return -1; 300 | } 301 | 302 | v2r_vnc_t * 303 | v2r_vnc_init(v2r_session_t *s) 304 | { 305 | v2r_vnc_t *v = NULL; 306 | 307 | v = (v2r_vnc_t *)malloc(sizeof(v2r_vnc_t)); 308 | if (v == NULL) { 309 | goto fail; 310 | } 311 | memset(v, 0, sizeof(v2r_vnc_t)); 312 | 313 | v->session = s; 314 | v->packet = v2r_packet_init(65535); 315 | if (v->packet == NULL) { 316 | goto fail; 317 | } 318 | v->buffer = NULL; 319 | v->buffer_size = 0; 320 | 321 | return v; 322 | 323 | fail: 324 | v2r_vnc_destory(v); 325 | return NULL; 326 | } 327 | 328 | void 329 | v2r_vnc_destory(v2r_vnc_t *v) 330 | { 331 | if (v == NULL) { 332 | return; 333 | } 334 | if (v->fd != 0) { 335 | close(v->fd); 336 | } 337 | if (v->packet != NULL) { 338 | v2r_packet_destory(v->packet); 339 | } 340 | if (v->buffer != NULL) { 341 | free(v->buffer); 342 | } 343 | free(v); 344 | } 345 | 346 | static int 347 | v2r_vnc_process_raw_encoding(v2r_vnc_t *v, uint16_t x, uint16_t y, 348 | uint16_t w, uint16_t h) 349 | { 350 | uint16_t left, top, right, bottom, width, height, i; 351 | uint32_t data_size, line_size, rdp_line_size, rdp_data_size; 352 | uint32_t max_line_per_packet, line_per_packet; 353 | const uint32_t max_byte_per_packet = 8192; 354 | 355 | /* VNC bitmap size */ 356 | data_size = w * h * v->bits_per_pixel / 8; 357 | /* VNC bitmap row size */ 358 | line_size = w * v->bits_per_pixel / 8; 359 | /* RDP bitmap row should contains a multiple of four bytes */ 360 | rdp_line_size = (line_size % 4) ? ((line_size / 4) + 1) * 4 : line_size; 361 | /* RDP bitmap size */ 362 | rdp_data_size = rdp_line_size * h; 363 | /* send at most max_line_per_packet line to RDP client in a RDP bitmap 364 | * update PDU */ 365 | max_line_per_packet = max_byte_per_packet / rdp_line_size; 366 | 367 | /* if data size is larger than vnc packet's buffer, 368 | * init a new packet with a larger buffer */ 369 | if (data_size > v->packet->max_len) { 370 | v2r_packet_destory(v->packet); 371 | v->packet = v2r_packet_init(data_size); 372 | if (v->packet == NULL) { 373 | goto fail; 374 | } 375 | } 376 | /* and realloc a new buffer for VNC image upside down */ 377 | if (rdp_data_size > v->buffer_size) { 378 | v->buffer_size = rdp_data_size; 379 | v->buffer = (uint8_t *)realloc(v->buffer, v->buffer_size); 380 | if (v->buffer == NULL) { 381 | v2r_log_error("failed to allocate memory for swap buffer"); 382 | goto fail; 383 | } 384 | } 385 | 386 | /* receive VNC bitmap data */ 387 | if (v2r_vnc_recv1(v, data_size) == -1) { 388 | goto fail; 389 | } 390 | 391 | for (i = 0; i < h; i++) { 392 | memcpy(v->buffer + (h - i - 1) * rdp_line_size, 393 | v->packet->data + i * line_size, 394 | line_size); 395 | } 396 | 397 | /* 398 | left = x; 399 | top = y; 400 | right = x + w - 1; 401 | bottom = y + h - 1; 402 | width = w; 403 | height = h; 404 | if (v2r_rdp_send_bitmap_update(v->session->rdp, left, top, right, bottom, 405 | width, height, 32, data_size, 406 | v->packet->data) == -1) { 407 | goto fail; 408 | } 409 | */ 410 | 411 | for (i = 0; i < h;) { 412 | if (i + max_line_per_packet > h) { 413 | line_per_packet = h - i; 414 | } else { 415 | line_per_packet = max_line_per_packet; 416 | } 417 | left = x; 418 | top = y + h - i - line_per_packet; 419 | right = x + w - 1; 420 | bottom = y + h - i - 1; 421 | width = w; 422 | height = line_per_packet; 423 | if (v2r_rdp_send_bitmap_update(v->session->rdp, 424 | left, top, right, bottom, 425 | width, height, v->bpp, 426 | rdp_line_size * line_per_packet, 427 | v->buffer + i * rdp_line_size) == -1) { 428 | goto fail; 429 | } 430 | i += line_per_packet; 431 | } 432 | 433 | return 0; 434 | 435 | fail: 436 | return -1; 437 | } 438 | 439 | static int 440 | v2r_vnc_process_copy_rect_encoding(v2r_vnc_t *v, uint16_t x, uint16_t y, 441 | uint16_t w, uint16_t h) 442 | { 443 | uint16_t src_x, src_y; 444 | 445 | if (v2r_vnc_recv1(v, 4) == -1) { 446 | goto fail; 447 | } 448 | V2R_PACKET_READ_UINT16_BE(v->packet, src_x); 449 | V2R_PACKET_READ_UINT16_BE(v->packet, src_y); 450 | v2r_log_debug("copy rect from src_x: %d src_y: %d", src_x, src_y); 451 | 452 | if (v2r_rdp_send_scrblt_order(v->session->rdp, x, y, w, h, src_x, src_y) 453 | == -1) { 454 | goto fail; 455 | } 456 | 457 | return 0; 458 | 459 | fail: 460 | return -1; 461 | } 462 | 463 | static int 464 | v2r_vnc_process_framebuffer_update(v2r_vnc_t *v) 465 | { 466 | uint16_t nrects = 0, i = 0, x, y, w, h; 467 | int32_t encoding_type; 468 | 469 | if (v2r_vnc_recv1(v, 3) == -1) { 470 | goto fail; 471 | } 472 | V2R_PACKET_SEEK_UINT8(v->packet); 473 | V2R_PACKET_READ_UINT16_BE(v->packet, nrects); 474 | //v2r_log_debug("receive framebuffer update with %d rects", nrects); 475 | 476 | for (i = 0; i < nrects; i++) { 477 | if (v2r_vnc_recv1(v, 12) == -1) { 478 | goto fail; 479 | } 480 | V2R_PACKET_READ_UINT16_BE(v->packet, x); 481 | V2R_PACKET_READ_UINT16_BE(v->packet, y); 482 | V2R_PACKET_READ_UINT16_BE(v->packet, w); 483 | V2R_PACKET_READ_UINT16_BE(v->packet, h); 484 | V2R_PACKET_READ_UINT32_BE(v->packet, encoding_type); 485 | //v2r_log_debug("rect %d of %d: pos: %d,%d size: %dx%d encoding: %d", 486 | // i + 1, nrects, x, y, w, h, encoding_type); 487 | 488 | switch (encoding_type) { 489 | case RFB_ENCODING_RAW: 490 | if (v2r_vnc_process_raw_encoding(v, x, y, w, h) == -1) { 491 | goto fail; 492 | } 493 | break; 494 | case RFB_ENCODING_COPYRECT: 495 | if (v2r_vnc_process_copy_rect_encoding(v, x, y, w, h) == -1) { 496 | goto fail; 497 | } 498 | break; 499 | default: 500 | v2r_log_warn("unknown encoding type: %d", encoding_type); 501 | break; 502 | } 503 | } 504 | 505 | /* send FramebufferUpdateRequest message */ 506 | if (v2r_vnc_send_fb_update_req(v, 1, 0, 0, v->framebuffer_width, 507 | v->framebuffer_height) == -1) { 508 | goto fail; 509 | } 510 | 511 | return 0; 512 | 513 | fail: 514 | return -1; 515 | } 516 | 517 | static int 518 | v2r_vnc_process_set_colour_map_entries(v2r_vnc_t *v) 519 | { 520 | uint16_t i, first_colour, n_colours, red, green, blue; 521 | 522 | if (v2r_vnc_recv1(v, 5) == -1) { 523 | goto fail; 524 | } 525 | V2R_PACKET_SEEK(v->packet, 1); 526 | V2R_PACKET_READ_UINT16_BE(v->packet, first_colour); 527 | V2R_PACKET_READ_UINT16_BE(v->packet, n_colours); 528 | v2r_log_info("set colour map entries with first_colour: %d, n_colours: %d", 529 | first_colour, n_colours); 530 | if (v2r_vnc_recv1(v, n_colours * 6) == -1) { 531 | goto fail; 532 | } 533 | for (i = 0; i < n_colours; i++) { 534 | V2R_PACKET_READ_UINT16_LE(v->packet, red); 535 | V2R_PACKET_READ_UINT16_LE(v->packet, green); 536 | V2R_PACKET_READ_UINT16_LE(v->packet, blue); 537 | v->colour_map[first_colour + i][0] = red; 538 | v->colour_map[first_colour + i][1] = green; 539 | v->colour_map[first_colour + i][2] = blue; 540 | } 541 | 542 | if (v2r_rdp_send_palette_update(v->session->rdp, 543 | RFB_COLOUR_MAP_ENTRIES_SIZE, 544 | v->colour_map) == -1) { 545 | goto fail; 546 | } 547 | 548 | return 0; 549 | 550 | fail: 551 | return -1; 552 | } 553 | 554 | static int 555 | v2r_vnc_process_bell(v2r_vnc_t *v) 556 | { 557 | v2r_log_debug("server ring a bell"); 558 | 559 | /* The value of duration 300 and frequency 200 sounds comfortable for a 560 | * bell ring, it can be changed. ant if you change duration too small it 561 | * will be very diffcult to find out there is a bell ring */ 562 | if (v2r_rdp_send_play_sound(v->session->rdp, 300, 200) == -1) { 563 | goto fail; 564 | } 565 | 566 | return 0; 567 | 568 | fail: 569 | return -1; 570 | } 571 | 572 | static int 573 | v2r_vnc_process_server_cut_text(v2r_vnc_t *v) 574 | { 575 | uint32_t length; 576 | 577 | if (v2r_vnc_recv1(v, 7) == -1) { 578 | goto fail; 579 | } 580 | V2R_PACKET_SEEK(v->packet, 3); 581 | V2R_PACKET_READ_UINT32_BE(v->packet, length); 582 | if (v2r_vnc_recv1(v, length) == -1) { 583 | goto fail; 584 | } 585 | 586 | return 0; 587 | 588 | fail: 589 | return -1; 590 | } 591 | 592 | int 593 | v2r_vnc_process(v2r_vnc_t *v) 594 | { 595 | uint8_t msg_type; 596 | 597 | if (v2r_vnc_recv1(v, 1) == -1) { 598 | goto fail; 599 | } 600 | V2R_PACKET_READ_UINT8(v->packet, msg_type); 601 | 602 | switch (msg_type) { 603 | case RFB_FRAMEBUFFER_UPDATE: 604 | if (v2r_vnc_process_framebuffer_update(v) == -1) { 605 | goto fail; 606 | } 607 | break; 608 | case RFB_SET_COLOUR_MAP_ENTRIES: 609 | if (v2r_vnc_process_set_colour_map_entries(v) == -1) { 610 | goto fail; 611 | } 612 | break; 613 | case RFB_BELL: 614 | if (v2r_vnc_process_bell(v) == -1) { 615 | goto fail; 616 | } 617 | break; 618 | case RFB_SERVER_CUT_TEXT: 619 | if (v2r_vnc_process_server_cut_text(v) == -1) { 620 | goto fail; 621 | } 622 | break; 623 | default: 624 | v2r_log_debug("reveive unknown message type %d from vnc server", 625 | msg_type); 626 | goto fail; 627 | break; 628 | } 629 | 630 | return 0; 631 | 632 | fail: 633 | return -1; 634 | } 635 | 636 | int 637 | v2r_vnc_send_fb_update_req(v2r_vnc_t *v, uint8_t incremental, 638 | uint16_t x_pos, uint16_t y_pos, 639 | uint16_t width, uint16_t height) 640 | { 641 | /* if client sent Suppress Output PDU, then don't send framebuffer 642 | * update request */ 643 | if (v->session->rdp != NULL && 644 | v->session->rdp->allow_display_updates == SUPPRESS_DISPLAY_UPDATES) { 645 | return 0; 646 | } 647 | 648 | /* send FramebufferUpdateRequest message */ 649 | v2r_packet_reset(v->packet); 650 | 651 | /* message-type */ 652 | V2R_PACKET_WRITE_UINT8(v->packet, RFB_FRAMEBUFFER_UPDATE_REQUEST); 653 | /* incremental */ 654 | V2R_PACKET_WRITE_UINT8(v->packet, incremental); 655 | /* x-position */ 656 | V2R_PACKET_WRITE_UINT16_BE(v->packet, x_pos); 657 | /* y-position */ 658 | V2R_PACKET_WRITE_UINT16_BE(v->packet, y_pos); 659 | /* width */ 660 | V2R_PACKET_WRITE_UINT16_BE(v->packet, width); 661 | /* height */ 662 | V2R_PACKET_WRITE_UINT16_BE(v->packet, height); 663 | 664 | V2R_PACKET_END(v->packet); 665 | if (v2r_vnc_send(v) == -1) { 666 | goto fail; 667 | } 668 | 669 | return 0; 670 | 671 | fail: 672 | return -1; 673 | } 674 | 675 | int 676 | v2r_vnc_send_key_event(v2r_vnc_t *v, uint8_t down_flag, uint32_t key) 677 | { 678 | /* if 'viewonly' is specified, don't send keyboard event to server */ 679 | if (v->session->opt->viewonly) { 680 | return 0; 681 | } 682 | 683 | /* send KeyEvent message */ 684 | v2r_packet_reset(v->packet); 685 | /* message-type */ 686 | V2R_PACKET_WRITE_UINT8(v->packet, RFB_KEY_EVENT); 687 | /* down-flag */ 688 | V2R_PACKET_WRITE_UINT8(v->packet, down_flag); 689 | /* padding */ 690 | V2R_PACKET_WRITE_UINT16_BE(v->packet, 0); 691 | /* key */ 692 | V2R_PACKET_WRITE_UINT32_BE(v->packet, key); 693 | V2R_PACKET_END(v->packet); 694 | 695 | return v2r_vnc_send(v); 696 | } 697 | 698 | int 699 | v2r_vnc_send_pointer_event(v2r_vnc_t *v, uint8_t btn_mask, 700 | uint16_t x_pos, uint16_t y_pos) 701 | { 702 | /* if 'viewonly' is specified, don't send pointer event to server */ 703 | if (v->session->opt->viewonly) { 704 | return 0; 705 | } 706 | 707 | /* send PointerEvent message */ 708 | v2r_packet_reset(v->packet); 709 | /* message-type */ 710 | V2R_PACKET_WRITE_UINT8(v->packet, RFB_POINTER_EVENT); 711 | /* button-mask */ 712 | V2R_PACKET_WRITE_UINT8(v->packet, btn_mask); 713 | /* x-position */ 714 | V2R_PACKET_WRITE_UINT16_BE(v->packet, x_pos); 715 | V2R_PACKET_WRITE_UINT16_BE(v->packet, y_pos); 716 | V2R_PACKET_END(v->packet); 717 | 718 | return v2r_vnc_send(v); 719 | } 720 | -------------------------------------------------------------------------------- /vnc.h: -------------------------------------------------------------------------------- 1 | /** 2 | * vnc2rdp: proxy for RDP client connect to VNC server 3 | * 4 | * Copyright 2014 Yiwei Li 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef _VNC_H_ 20 | #define _VNC_H_ 21 | 22 | #include "packet.h" 23 | #include "session.h" 24 | 25 | #define RFB_PROTOCOL_VERSION "RFB 003.003\n" 26 | 27 | #define RFB_SEC_TYPE_NONE 1 28 | #define RFB_SEC_TYPE_VNC_AUTH 2 29 | 30 | /* SecurityResult */ 31 | #define RFB_SEC_RESULT_OK 0 32 | #define RFB_SEC_RESULT_FAILED 1 33 | 34 | /* client to server messages */ 35 | #define RFB_SET_PIXEL_FORMAT 0 36 | #define RFB_SET_ENCODINGS 2 37 | #define RFB_FRAMEBUFFER_UPDATE_REQUEST 3 38 | #define RFB_KEY_EVENT 4 39 | #define RFB_POINTER_EVENT 5 40 | #define RFB_CLIENT_CUT_TEXT 6 41 | 42 | /* PointerEvent */ 43 | #define RFB_POINTER_BUTTON_LEFT 0x01 44 | #define RFB_POINTER_BUTTON_MIDDLE 0x02 45 | #define RFB_POINTER_BUTTON_RIGHT 0x04 46 | #define RFB_POINTER_WHEEL_UPWARDS 0x08 47 | #define RFB_POINTER_WHEEL_DOWNWARDS 0x10 48 | 49 | /* server to client messages */ 50 | #define RFB_FRAMEBUFFER_UPDATE 0 51 | #define RFB_SET_COLOUR_MAP_ENTRIES 1 52 | #define RFB_BELL 2 53 | #define RFB_SERVER_CUT_TEXT 3 54 | 55 | #define RFB_ENCODING_RAW 0 56 | #define RFB_ENCODING_COPYRECT 1 57 | #define RFB_ENCODING_RRE 2 58 | #define RFB_ENCODING_HEXTILE 5 59 | #define RFB_ENCODING_ZRLE 16 60 | #define RFB_ENCODING_CURSOR -239 61 | #define RFB_ENCODING_DESKTOP_SIZE -223 62 | 63 | #define RFB_COLOUR_MAP_ENTRIES_SIZE 256 64 | 65 | typedef struct _v2r_vnc_t { 66 | int fd; 67 | v2r_packet_t *packet; 68 | uint8_t *buffer; /**< buffer for swap bitmap */ 69 | uint32_t buffer_size; /**< buffer size */ 70 | 71 | uint32_t security_type; 72 | uint16_t framebuffer_width; 73 | uint16_t framebuffer_height; 74 | uint8_t bits_per_pixel; 75 | uint8_t depth; 76 | uint8_t big_endian_flag; 77 | uint8_t true_colour_flag; 78 | uint16_t red_max; 79 | uint16_t green_max; 80 | uint16_t blue_max; 81 | uint8_t red_shift; 82 | uint8_t green_shift; 83 | uint8_t blue_shift; 84 | 85 | uint16_t bpp; /**< bits-per-pixel send to RDP client */ 86 | uint8_t colour_map[RFB_COLOUR_MAP_ENTRIES_SIZE][3]; 87 | 88 | v2r_session_t *session; 89 | } v2r_vnc_t; 90 | 91 | extern v2r_vnc_t *v2r_vnc_init(v2r_session_t *s); 92 | extern void v2r_vnc_destory(v2r_vnc_t *v); 93 | extern int v2r_vnc_build_conn(v2r_vnc_t *v, int server_fd); 94 | extern int v2r_vnc_process(v2r_vnc_t *v); 95 | extern int v2r_vnc_send_fb_update_req(v2r_vnc_t *v, uint8_t incremental, 96 | uint16_t x_pos, uint16_t y_pos, 97 | uint16_t width, uint16_t height); 98 | extern int v2r_vnc_send_key_event(v2r_vnc_t *v, uint8_t down_flag, 99 | uint32_t key); 100 | extern int v2r_vnc_send_pointer_event(v2r_vnc_t *v, uint8_t btn_mask, 101 | uint16_t x_pos, uint16_t y_pos); 102 | 103 | #endif // _VNC_H_ 104 | -------------------------------------------------------------------------------- /vnc2rdp.c: -------------------------------------------------------------------------------- 1 | /** 2 | * vnc2rdp: proxy for RDP client connect to VNC server 3 | * 4 | * Copyright 2014 Yiwei Li 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "log.h" 29 | #include "rdp.h" 30 | #include "sec.h" 31 | #include "session.h" 32 | #include "vnc.h" 33 | 34 | #define ERROR(...) \ 35 | fprintf(stderr, "ERROR: "); \ 36 | fprintf(stderr, __VA_ARGS__) 37 | 38 | int g_process = 1; 39 | 40 | void 41 | signal_handler(int signal) 42 | { 43 | if (signal == SIGINT) { 44 | g_process = 0; 45 | } 46 | } 47 | 48 | static void 49 | process_connection(int client_fd, const v2r_session_opt_t *opt) 50 | { 51 | int server_fd; 52 | struct sockaddr_in server_addr; 53 | v2r_session_t *session = NULL; 54 | 55 | /* connect to VNC server */ 56 | server_fd = socket(AF_INET, SOCK_STREAM, 0); 57 | if (server_fd == -1) { 58 | v2r_log_error("create socket for VNC server error: %s", ERRMSG); 59 | goto fail; 60 | } 61 | memset(&server_addr, 0, sizeof(server_addr)); 62 | server_addr.sin_family = AF_INET; 63 | server_addr.sin_port = htons(opt->vnc_server_port); 64 | if (inet_pton(AF_INET, opt->vnc_server_ip, &server_addr.sin_addr) != 1) { 65 | v2r_log_error("convert ip '%s' error: %s", opt->vnc_server_ip, ERRMSG); 66 | goto fail; 67 | } 68 | if (connect(server_fd, (struct sockaddr *)&server_addr, 69 | sizeof(server_addr)) == -1) { 70 | v2r_log_error("connect to VNC server error: %s", ERRMSG); 71 | goto fail; 72 | } 73 | 74 | /* init session */ 75 | session = v2r_session_init(opt); 76 | if (session == NULL) { 77 | v2r_log_error("session init failed"); 78 | goto fail; 79 | } 80 | 81 | if (v2r_session_build_conn(session, client_fd, server_fd) == -1) { 82 | goto fail; 83 | } 84 | 85 | /* start proxy */ 86 | v2r_session_transmit(session); 87 | 88 | fail: 89 | v2r_session_destory(session); 90 | } 91 | 92 | static void 93 | parse_address(const char *address, char *ip, int len, uint16_t *port) 94 | { 95 | char *colon; 96 | size_t ip_len; 97 | 98 | if (address == NULL) { 99 | return; 100 | } 101 | 102 | colon = strchr(address, ':'); 103 | if (colon) { 104 | /* if ip buffer is larger than ip in address, then copy it, 105 | * otherwise ignore it */ 106 | ip_len = colon - address; 107 | if (ip_len != 0 && ip_len <= len) { 108 | memcpy(ip, address, ip_len); 109 | ip[ip_len] = '\0'; 110 | } 111 | if (*(colon + 1) != '\0') { 112 | *port = atoi(colon + 1); 113 | } 114 | } else { 115 | /* if ip buffer is larger than ip in address, then copy it, 116 | * otherwise ignore it */ 117 | ip_len = strlen(address); 118 | if (ip_len <= len) { 119 | memcpy(ip, address, ip_len); 120 | ip[ip_len] = '\0'; 121 | } 122 | } 123 | } 124 | 125 | static void 126 | usage(const char *name) 127 | { 128 | const char *msg = 129 | "Usage: %s [options] server:port\n" 130 | "\n" 131 | " -l, --listen=ADDRESS listen address, default: 0.0.0.0:3389\n" 132 | " -e, --encryption=METHOD preferred RDP encryption method, default: none,\n" 133 | " possible values are: none/40bit/56bit/128bit\n" 134 | " -p, --password=PASSWORD VNC server password, for VNC authentication\n" 135 | " -s, --shared connect to VNC server use share mode, share\n" 136 | " desktop with other clients (default)\n" 137 | " -n, --noshared connect to VNC server use exclusive mode by\n" 138 | " disconnect all other client\n" 139 | " -v, --viewonly disable transfer of mouse and keyboard events\n" 140 | " from the client to the server\n" 141 | " -h, --help print this help message and exit\n" 142 | "\n"; 143 | 144 | fprintf(stderr, msg, name); 145 | } 146 | 147 | int 148 | main(int argc, char *argv[]) 149 | { 150 | char listen_ip[INET_ADDRSTRLEN]; 151 | uint8_t shared = 0, noshared = 0; 152 | uint16_t listen_port; 153 | int listen_fd, client_fd, ch, optval = 1; 154 | struct sockaddr_in listen_addr; 155 | struct sigaction act; 156 | struct option longopts[] = { 157 | {"listen", required_argument, NULL, 'l'}, 158 | {"encryption", required_argument, NULL, 'e'}, 159 | {"password", required_argument, NULL, 'p'}, 160 | {"shared", no_argument, NULL, 's'}, 161 | {"noshared", no_argument, NULL, 'n'}, 162 | {"viewonly", no_argument, NULL, 'v'}, 163 | {"help", no_argument, NULL, 'h'}, 164 | {NULL, 0, NULL, 0} 165 | }; 166 | v2r_session_opt_t opt; 167 | 168 | /* clear session option */ 169 | memset(&opt, 0, sizeof(opt)); 170 | 171 | /* default listen address is 0.0.0.0:3389 */ 172 | strcpy(listen_ip, "0.0.0.0"); 173 | listen_port = 3389; 174 | /* default encryption level is none */ 175 | opt.encryption_method = ENCRYPTION_METHOD_NONE; 176 | 177 | while ((ch = getopt_long(argc, argv, "l:e:p:snvh", longopts, NULL)) != -1) { 178 | switch (ch) { 179 | case 'l': 180 | parse_address(optarg, listen_ip, sizeof(listen_ip), &listen_port); 181 | break; 182 | case 'e': 183 | if (strcmp(optarg, "none") == 0) { 184 | opt.encryption_method = ENCRYPTION_METHOD_NONE; 185 | } else if (strcmp(optarg, "40bit") == 0) { 186 | opt.encryption_method = ENCRYPTION_METHOD_40BIT; 187 | } else if (strcmp(optarg, "56bit") == 0) { 188 | opt.encryption_method = ENCRYPTION_METHOD_56BIT; 189 | } else if (strcmp(optarg, "128bit") == 0) { 190 | opt.encryption_method = ENCRYPTION_METHOD_128BIT; 191 | } else { 192 | ERROR("Unknown encryption level: %s\n", optarg); 193 | usage(argv[0]); 194 | exit(EXIT_FAILURE); 195 | } 196 | case 'p': 197 | strncpy(opt.vnc_password, optarg, sizeof(opt.vnc_password)); 198 | break; 199 | case 's': 200 | shared = 1; 201 | break; 202 | case 'n': 203 | noshared = 1; 204 | break; 205 | case 'v': 206 | opt.viewonly = 1; 207 | break; 208 | case 'h': 209 | case '?': 210 | default: 211 | usage(argv[0]); 212 | exit(EXIT_FAILURE); 213 | } 214 | } 215 | 216 | /* --shared and --noshared cannot use at same the time */ 217 | if (shared && noshared) { 218 | ERROR("Both --shared and --noshared are specified\n"); 219 | usage(argv[0]); 220 | exit(EXIT_FAILURE); 221 | } 222 | opt.shared = noshared ? 0 : 1; 223 | 224 | /* command line option must contain VNC server address */ 225 | if (argc - optind != 1) { 226 | usage(argv[0]); 227 | exit(EXIT_FAILURE); 228 | } 229 | 230 | /* server address has no default value */ 231 | parse_address(argv[optind], opt.vnc_server_ip, sizeof(opt.vnc_server_ip), 232 | &(opt.vnc_server_port)); 233 | if (opt.vnc_server_ip[0] == '\0' || opt.vnc_server_port == 0) { 234 | ERROR("Bad format of server address: %s\n", argv[optind]); 235 | usage(argv[0]); 236 | exit(EXIT_FAILURE); 237 | } 238 | 239 | /* set signal handler */ 240 | memset(&act, 0, sizeof(act)); 241 | act.sa_handler = signal_handler; 242 | sigemptyset(&act.sa_mask); 243 | act.sa_flags = 0; 244 | if (sigaction(SIGINT, &act, NULL) < 0) { 245 | v2r_log_error("register signal handler error: %s", ERRMSG); 246 | exit(EXIT_FAILURE); 247 | } 248 | 249 | if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { 250 | v2r_log_error("create listen socket error: %s", ERRMSG); 251 | exit(EXIT_FAILURE); 252 | } 253 | 254 | /* set address reuse */ 255 | if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) 256 | == -1) { 257 | v2r_log_error("set socket reuse address error: %s", ERRMSG); 258 | exit(EXIT_FAILURE); 259 | } 260 | 261 | memset(&listen_addr, 0, sizeof(listen_addr)); 262 | listen_addr.sin_family = AF_INET; 263 | listen_addr.sin_port = htons(listen_port); 264 | if (inet_pton(AF_INET, listen_ip, &listen_addr.sin_addr) != 1) { 265 | v2r_log_error("convert ip '%s' error: %s", listen_ip, ERRMSG); 266 | exit(EXIT_FAILURE); 267 | } 268 | 269 | if (bind(listen_fd, (struct sockaddr *)&listen_addr, sizeof(listen_addr)) 270 | == -1) { 271 | v2r_log_error("bind socket to address error: %s", ERRMSG); 272 | exit(EXIT_FAILURE); 273 | } 274 | 275 | if (listen(listen_fd, 64) == -1) { 276 | v2r_log_error("listen socket error: %s", ERRMSG); 277 | exit(EXIT_FAILURE); 278 | } 279 | 280 | v2r_log_info("listening new connection"); 281 | while (g_process) { 282 | client_fd = accept(listen_fd, NULL, NULL); 283 | if (client_fd == -1) { 284 | v2r_log_error("accept new connection error: %s", ERRMSG); 285 | continue; 286 | } 287 | process_connection(client_fd, &opt); 288 | } 289 | close(listen_fd); 290 | 291 | return 0; 292 | } 293 | -------------------------------------------------------------------------------- /vncauth.c: -------------------------------------------------------------------------------- 1 | /** 2 | * vnc2rdp: proxy for RDP client connect to VNC server 3 | * 4 | * Copyright 2014 Yiwei Li 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | 21 | #include "d3des.h" 22 | #include "vncauth.h" 23 | 24 | /* 25 | * Encrypt CHALLENGESIZE bytes in memory using a password. 26 | */ 27 | void 28 | rfbEncryptBytes(unsigned char *bytes, const char *passwd) 29 | { 30 | unsigned char key[8]; 31 | unsigned int i; 32 | 33 | /* key is simply password padded with nulls */ 34 | 35 | for (i = 0; i < 8; i++) { 36 | if (i < strlen(passwd)) { 37 | key[i] = passwd[i]; 38 | } else { 39 | key[i] = 0; 40 | } 41 | } 42 | 43 | rfbDesKey(key, EN0); 44 | 45 | for (i = 0; i < CHALLENGESIZE; i += 8) { 46 | rfbDes(bytes + i, bytes + i); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /vncauth.h: -------------------------------------------------------------------------------- 1 | /** 2 | * vnc2rdp: proxy for RDP client connect to VNC server 3 | * 4 | * Copyright 2014 Yiwei Li 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef _VNCAUTH_H_ 20 | #define _VNCAUTH_H_ 21 | 22 | #define CHALLENGESIZE 16 23 | 24 | extern void rfbEncryptBytes(unsigned char *bytes, const char *passwd); 25 | 26 | #endif // _VNCAUTH_H_ 27 | -------------------------------------------------------------------------------- /x224.c: -------------------------------------------------------------------------------- 1 | /** 2 | * vnc2rdp: proxy for RDP client connect to VNC server 3 | * 4 | * Copyright 2014 Yiwei Li 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | #include "x224.h" 23 | #include "tpkt.h" 24 | 25 | int 26 | v2r_x224_build_conn(v2r_x224_t *x, int client_fd) 27 | { 28 | v2r_packet_t *p = NULL; 29 | uint8_t li = 0, tpdu_code = 0; 30 | uint8_t terminated = 0, type = 0, flags = 0; 31 | uint16_t length = 0; 32 | 33 | if (v2r_tpkt_build_conn(x->tpkt, client_fd) == -1) { 34 | goto fail; 35 | } 36 | 37 | p = v2r_packet_init(8192); 38 | if (p == NULL) { 39 | goto fail; 40 | } 41 | 42 | /* receive Client X.224 Connection Request PDU */ 43 | if (v2r_tpkt_recv(x->tpkt, p) == -1) { 44 | goto fail; 45 | } 46 | /* parse X.224 Class 0 Connection Request header */ 47 | V2R_PACKET_READ_UINT8(p, li); 48 | V2R_PACKET_READ_UINT8(p, tpdu_code); 49 | if (tpdu_code != TPDU_CODE_CR) { 50 | goto fail; 51 | } 52 | V2R_PACKET_SEEK(p, 5); 53 | /* see if it is routingToken or cookie field */ 54 | if (V2R_PACKET_READ_REMAIN(p, strlen(X224_ROUTING_TOKEN_PREFIX)) && 55 | !strncmp((const char *)p->current, X224_ROUTING_TOKEN_PREFIX, 56 | strlen(X224_ROUTING_TOKEN_PREFIX))) { 57 | V2R_PACKET_SEEK(p, strlen(X224_ROUTING_TOKEN_PREFIX)); 58 | while (V2R_PACKET_READ_REMAIN(p, 2)) { 59 | if (p->current[0] == '\r' && p->current[1] == '\n') { 60 | V2R_PACKET_SEEK(p, 2); 61 | terminated = 1; 62 | break; 63 | } 64 | p->current++; 65 | } 66 | } else if (V2R_PACKET_READ_REMAIN(p, strlen(X224_COOKIE_PREFIX)) && 67 | !strncmp((const char *)p->current, X224_COOKIE_PREFIX, 68 | strlen(X224_COOKIE_PREFIX))) { 69 | V2R_PACKET_SEEK(p, strlen(X224_COOKIE_PREFIX)); 70 | while (V2R_PACKET_READ_REMAIN(p, 2)) { 71 | if (p->current[0] == '\r' && p->current[1] == '\n') { 72 | V2R_PACKET_SEEK(p, 2); 73 | terminated = 1; 74 | break; 75 | } 76 | p->current++; 77 | } 78 | } else { 79 | terminated = 1; 80 | } 81 | if (!terminated) { 82 | goto fail; 83 | } 84 | 85 | /* parse RDP Negotiation Request if exists */ 86 | if (V2R_PACKET_READ_REMAIN(p, 8)) { 87 | V2R_PACKET_READ_UINT8(p, type); 88 | if (type != TYPE_RDP_NEG_REQ) { 89 | goto fail; 90 | } 91 | V2R_PACKET_READ_UINT8(p, flags); 92 | V2R_PACKET_READ_UINT16_LE(p, length); 93 | if (length != 0x0008) { 94 | goto fail; 95 | } 96 | V2R_PACKET_READ_UINT32_LE(p, x->requested_protocols); 97 | } 98 | 99 | /* build Server X.224 Connection Confirm PDU */ 100 | v2r_tpkt_init_packet(p); 101 | /* Length indicator field is set fixed to 14 */ 102 | V2R_PACKET_WRITE_UINT8(p, 14); 103 | V2R_PACKET_WRITE_UINT8(p, TPDU_CODE_CC); 104 | V2R_PACKET_WRITE_UINT16_LE(p, 0); 105 | V2R_PACKET_WRITE_UINT16_LE(p, 0); 106 | V2R_PACKET_WRITE_UINT8(p, 0); 107 | /* fill RDP Negotiation Response */ 108 | V2R_PACKET_WRITE_UINT8(p, TYPE_RDP_NEG_RSP); 109 | V2R_PACKET_WRITE_UINT8(p, 0); 110 | V2R_PACKET_WRITE_UINT16_LE(p, 0x0008); 111 | V2R_PACKET_WRITE_UINT32_LE(p, PROTOCOL_RDP); 112 | /* send Server X.224 Connection Confirm PDU */ 113 | V2R_PACKET_END(p); 114 | v2r_tpkt_send(x->tpkt, p); 115 | 116 | v2r_packet_destory(p); 117 | return 0; 118 | 119 | fail: 120 | v2r_packet_destory(p); 121 | return -1; 122 | } 123 | 124 | v2r_x224_t * 125 | v2r_x224_init(v2r_session_t *session) 126 | { 127 | v2r_x224_t *x = NULL; 128 | 129 | x = (v2r_x224_t *)malloc(sizeof(v2r_x224_t)); 130 | if (x == NULL) { 131 | goto fail; 132 | } 133 | memset(x, 0, sizeof(v2r_x224_t)); 134 | 135 | x->session = session; 136 | 137 | x->tpkt = v2r_tpkt_init(session); 138 | if (x->tpkt == NULL) { 139 | goto fail; 140 | } 141 | 142 | return x; 143 | 144 | fail: 145 | v2r_x224_destory(x); 146 | return NULL; 147 | } 148 | 149 | void 150 | v2r_x224_destory(v2r_x224_t *x) 151 | { 152 | if (x == NULL) { 153 | return; 154 | } 155 | if (x->tpkt != NULL) { 156 | v2r_tpkt_destory(x->tpkt); 157 | } 158 | free(x); 159 | } 160 | 161 | int 162 | v2r_x224_recv(v2r_x224_t *x, v2r_packet_t *p) 163 | { 164 | uint8_t li = 0, tpdu_code = 0; 165 | 166 | if (v2r_tpkt_recv(x->tpkt, p) == -1) { 167 | goto fail; 168 | } 169 | /* parse X.224 data pdu header */ 170 | V2R_PACKET_READ_UINT8(p, li); 171 | V2R_PACKET_READ_UINT8(p, tpdu_code); 172 | if (tpdu_code != TPDU_CODE_DT) { 173 | goto fail; 174 | } 175 | V2R_PACKET_SEEK_UINT8(p); 176 | 177 | return 0; 178 | 179 | fail: 180 | return -1; 181 | } 182 | 183 | int 184 | v2r_x224_send(v2r_x224_t *x, v2r_packet_t *p) 185 | { 186 | p->current = p->x224; 187 | V2R_PACKET_WRITE_UINT8(p, 2); 188 | V2R_PACKET_WRITE_UINT8(p, TPDU_CODE_DT); 189 | V2R_PACKET_WRITE_UINT8(p, 0x80); 190 | 191 | return v2r_tpkt_send(x->tpkt, p); 192 | } 193 | 194 | void 195 | v2r_x224_init_packet(v2r_packet_t *p) 196 | { 197 | v2r_tpkt_init_packet(p); 198 | p->x224 = p->current; 199 | V2R_PACKET_SEEK(p, X224_DATA_HEADER_LEN); 200 | } 201 | -------------------------------------------------------------------------------- /x224.h: -------------------------------------------------------------------------------- 1 | /** 2 | * vnc2rdp: proxy for RDP client connect to VNC server 3 | * 4 | * Copyright 2014 Yiwei Li 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef _X224_H_ 20 | #define _X224_H_ 21 | 22 | #define TPDU_CODE_CR 0xE0 23 | #define TPDU_CODE_CC 0xD0 24 | #define TPDU_CODE_DT 0xF0 25 | 26 | #define X224_DATA_HEADER_LEN 3 27 | 28 | #define TYPE_RDP_NEG_REQ 0x01 29 | #define TYPE_RDP_NEG_RSP 0x02 30 | 31 | #define X224_ROUTING_TOKEN_PREFIX "Cookie: msts=" 32 | #define X224_COOKIE_PREFIX "Cookie: mstshash=" 33 | 34 | #define PROTOCOL_RDP 0x00000000 35 | #define PROTOCOL_SSL 0x00000001 36 | #define PROTOCOL_HYBRID 0x00000002 37 | #define PROTOCOL_HYBRID_EX 0x00000008 38 | 39 | #include "packet.h" 40 | #include "session.h" 41 | #include "tpkt.h" 42 | 43 | typedef struct _v2r_x224_t { 44 | v2r_session_t *session; 45 | v2r_tpkt_t *tpkt; 46 | 47 | uint32_t requested_protocols; 48 | } v2r_x224_t; 49 | 50 | extern v2r_x224_t *v2r_x224_init(v2r_session_t *session); 51 | extern void v2r_x224_destory(v2r_x224_t *x); 52 | extern int v2r_x224_build_conn(v2r_x224_t *x, int client_fd); 53 | extern int v2r_x224_recv(v2r_x224_t *x, v2r_packet_t *p); 54 | extern int v2r_x224_send(v2r_x224_t *x, v2r_packet_t *p); 55 | extern void v2r_x224_init_packet(v2r_packet_t *p); 56 | 57 | #endif // _X224_H_ 58 | --------------------------------------------------------------------------------