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