1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Dynamic Channel Virtual Channel Extension.
4 Copyright 2017 Henrik Andersson <hean01@cendio.com> for Cendio AB
5 Copyright 2017 Karl Mikaelsson <derfian@cendio.se> for Cendio AB
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "rdesktop.h"
22
23 #define MAX_DVC_CHANNELS 20
24 #define INVALID_CHANNEL ((uint32)-1)
25
26 #define DYNVC_CREATE_REQ 0x01
27 #define DYNVC_DATA_FIRST 0x02
28 #define DYNVC_DATA 0x03
29 #define DYNVC_CLOSE 0x04
30 #define DYNVC_CAPABILITIES 0x05
31 #define DYNVC_DATA_FIRST_COMPRESSED 0x06
32 #define DYNVC_DATA_COMPRESSED 0x07
33 #define DYNVC_SOFT_SYNC_REQUEST 0x08
34 #define DYNVC_SOFT_SYNC_RESPONSE 0x09
35
36 typedef union dvc_hdr_t
37 {
38 uint8 data;
39 struct
40 {
41 uint8 cbid:2;
42 uint8 sp:2;
43 uint8 cmd:4;
44 } hdr;
45 } dvc_hdr_t;
46
47 typedef struct dvc_channel_t
48 {
49 uint32 hash;
50 uint32 channel_id;
51 dvc_channel_process_fn handler;
52 } dvc_channel_t;
53
54 static VCHANNEL *dvc_channel;
55 static dvc_channel_t channels[MAX_DVC_CHANNELS];
56
57 static uint32 dvc_in_channelid(STREAM s, dvc_hdr_t hdr);
58
59 static RD_BOOL
dvc_channels_exists(const char * name)60 dvc_channels_exists(const char *name)
61 {
62 int i;
63 uint32 hash;
64 hash = utils_djb2_hash(name);
65 for (i = 0; i < MAX_DVC_CHANNELS; i++)
66 {
67 if (channels[i].hash == hash)
68 return True;
69 }
70
71 return False;
72 }
73
74 static const dvc_channel_t *
dvc_channels_get_by_id(uint32 id)75 dvc_channels_get_by_id(uint32 id)
76 {
77 int i;
78
79 for (i = 0; i < MAX_DVC_CHANNELS; i++)
80 {
81 if (channels[i].channel_id == id)
82 {
83 return &channels[i];
84 }
85 }
86
87 return NULL;
88 }
89
90 static uint32
dvc_channels_get_id(const char * name)91 dvc_channels_get_id(const char *name)
92 {
93 int i;
94 uint32 hash;
95 hash = utils_djb2_hash(name);
96
97 for (i = 0; i < MAX_DVC_CHANNELS; i++)
98 {
99 if (channels[i].hash == hash)
100 {
101 return channels[i].channel_id;
102 }
103 }
104
105 return INVALID_CHANNEL;
106 }
107
108 static RD_BOOL
dvc_channels_remove_by_id(uint32 channelid)109 dvc_channels_remove_by_id(uint32 channelid)
110 {
111 int i;
112
113 for (i = 0; i < MAX_DVC_CHANNELS; i++)
114 {
115 if (channels[i].channel_id == channelid)
116 {
117 memset(&channels[i], 0, sizeof(dvc_channel_t));
118 return True;
119 }
120 }
121 return False;
122 }
123
124 static RD_BOOL
dvc_channels_add(const char * name,dvc_channel_process_fn handler,uint32 channel_id)125 dvc_channels_add(const char *name, dvc_channel_process_fn handler, uint32 channel_id)
126 {
127 int i;
128 uint32 hash;
129
130 if (dvc_channels_exists(name) == True)
131 {
132 logger(Core, Warning, "dvc_channels_add(), channel with name '%s' already exists",
133 name);
134 return False;
135 }
136
137 for (i = 0; i < MAX_DVC_CHANNELS; i++)
138 {
139 if (channels[i].hash == 0)
140 {
141 hash = utils_djb2_hash(name);
142 channels[i].hash = hash;
143 channels[i].handler = handler;
144 channels[i].channel_id = channel_id;
145 logger(Core, Debug,
146 "dvc_channels_add(), Added hash=%x, channel_id=%d, name=%s, handler=%p",
147 hash, channel_id, name, handler);
148 return True;
149 }
150 }
151
152 logger(Core, Warning,
153 "dvc_channels_add(), Failed to add channel, maximum number of channels are being used");
154 return False;
155 }
156
157 static int
dvc_channels_set_id(const char * name,uint32 channel_id)158 dvc_channels_set_id(const char *name, uint32 channel_id)
159 {
160 int i;
161 uint32 hash;
162
163 hash = utils_djb2_hash(name);
164
165 for (i = 0; i < MAX_DVC_CHANNELS; i++)
166 {
167 if (channels[i].hash == hash)
168 {
169 logger(Core, Debug, "dvc_channels_set_id(), name = '%s', channel_id = %d",
170 name, channel_id);
171 channels[i].channel_id = channel_id;
172 return 0;
173 }
174 }
175
176 return -1;
177 }
178
179 RD_BOOL
dvc_channels_is_available(const char * name)180 dvc_channels_is_available(const char *name)
181 {
182 int i;
183 uint32 hash;
184 hash = utils_djb2_hash(name);
185
186 for (i = 0; i < MAX_DVC_CHANNELS; i++)
187 {
188 if (channels[i].hash == hash)
189 {
190 return (channels[i].channel_id != INVALID_CHANNEL);
191 }
192 }
193
194 return False;
195 }
196
197 RD_BOOL
dvc_channels_register(const char * name,dvc_channel_process_fn handler)198 dvc_channels_register(const char *name, dvc_channel_process_fn handler)
199 {
200 return dvc_channels_add(name, handler, INVALID_CHANNEL);
201 }
202
203
204 static STREAM
dvc_init_packet(dvc_hdr_t hdr,uint32 channelid,size_t length)205 dvc_init_packet(dvc_hdr_t hdr, uint32 channelid, size_t length)
206 {
207 STREAM s;
208
209 length += 1; /* add 1 byte hdr */
210
211 if (channelid != INVALID_CHANNEL)
212 {
213 if (hdr.hdr.cbid == 0)
214 length += 1;
215 else if (hdr.hdr.cbid == 1)
216 length += 2;
217 else if (hdr.hdr.cbid == 2)
218 length += 4;
219 }
220
221 s = channel_init(dvc_channel, length);
222 out_uint8(s, hdr.data); /* DVC header */
223
224 if (channelid != INVALID_CHANNEL)
225 {
226 if (hdr.hdr.cbid == 0)
227 {
228 out_uint8(s, channelid);
229 }
230 else if (hdr.hdr.cbid == 1)
231 {
232 out_uint16_le(s, channelid);
233 }
234 else if (hdr.hdr.cbid == 2)
235 {
236 out_uint32_le(s, channelid);
237 }
238 }
239
240 return s;
241 }
242
243 void
dvc_send(const char * name,STREAM s)244 dvc_send(const char *name, STREAM s)
245 {
246 STREAM ls;
247 dvc_hdr_t hdr;
248 uint32 channel_id;
249
250 channel_id = dvc_channels_get_id(name);
251 if (channel_id == INVALID_CHANNEL)
252 {
253 logger(Core, Error, "dvc_send(), Trying to send data on invalid channel '%s'",
254 name);
255 return;
256 }
257
258 /* FIXME: we assume length is less than 1600 */
259
260 hdr.hdr.cmd = DYNVC_DATA;
261 hdr.hdr.cbid = 2;
262 hdr.hdr.sp = 0;
263
264 ls = dvc_init_packet(hdr, channel_id, s_length(s));
265
266 out_stream(ls, s);
267
268 s_mark_end(ls);
269
270 channel_send(ls, dvc_channel);
271 s_free(ls);
272 }
273
274
275 static void
dvc_send_capabilities_response()276 dvc_send_capabilities_response()
277 {
278 STREAM s;
279 dvc_hdr_t hdr;
280 uint16 supportedversion = 0x01;
281
282 hdr.hdr.cbid = 0x00;
283 hdr.hdr.sp = 0x00;
284 hdr.hdr.cmd = DYNVC_CAPABILITIES;
285
286 logger(Protocol, Debug,
287 "dvc_send_capabilities_response(), offering support for dvc %d", supportedversion);
288
289 s = dvc_init_packet(hdr, -1, 3);
290 out_uint8(s, 0x00); /* pad */
291 out_uint16_le(s, supportedversion); /* version */
292
293 s_mark_end(s);
294
295 channel_send(s, dvc_channel);
296 s_free(s);
297 }
298
299 static void
dvc_process_caps_pdu(STREAM s)300 dvc_process_caps_pdu(STREAM s)
301 {
302 uint16 version;
303
304 /* VERSION1 */
305 in_uint8s(s, 1); /* pad */
306 in_uint16_le(s, version); /* version */
307
308 logger(Protocol, Debug, "dvc_process_caps(), server supports dvc %d", version);
309
310 dvc_send_capabilities_response();
311 }
312
313 static void
dvc_send_create_response(RD_BOOL success,dvc_hdr_t hdr,uint32 channelid)314 dvc_send_create_response(RD_BOOL success, dvc_hdr_t hdr, uint32 channelid)
315 {
316 STREAM s;
317
318 logger(Protocol, Debug, "dvc_send_create_response(), %s request to create channelid %d",
319 (success ? "granted" : "denied"), channelid);
320 s = dvc_init_packet(hdr, channelid, 4);
321 out_uint32_le(s, success ? 0 : -1);
322 s_mark_end(s);
323
324 channel_send(s, dvc_channel);
325 s_free(s);
326 }
327
328 static void
dvc_process_create_pdu(STREAM s,dvc_hdr_t hdr)329 dvc_process_create_pdu(STREAM s, dvc_hdr_t hdr)
330 {
331 char name[512];
332 uint32 channelid;
333
334 channelid = dvc_in_channelid(s, hdr);
335
336 in_ansi_string(s, name, sizeof(name));
337
338 logger(Protocol, Debug, "dvc_process_create(), server requests channelid = %d, name = '%s'",
339 channelid, name);
340
341 if (dvc_channels_exists(name))
342 {
343 logger(Core, Verbose, "Established dynamic virtual channel '%s'", name);
344
345 dvc_channels_set_id(name, channelid);
346 dvc_send_create_response(True, hdr, channelid);
347 }
348 else
349 {
350 dvc_send_create_response(False, hdr, channelid);
351 }
352
353 }
354
355 static uint32
dvc_in_channelid(STREAM s,dvc_hdr_t hdr)356 dvc_in_channelid(STREAM s, dvc_hdr_t hdr)
357 {
358 uint32 id;
359
360 id = (uint32) - 1;
361
362 switch (hdr.hdr.cbid)
363 {
364 case 0:
365 in_uint8(s, id);
366 break;
367 case 1:
368 in_uint16_le(s, id);
369 break;
370 case 2:
371 in_uint32_le(s, id);
372 break;
373 }
374 return id;
375 }
376
377 static void
dvc_process_data_pdu(STREAM s,dvc_hdr_t hdr)378 dvc_process_data_pdu(STREAM s, dvc_hdr_t hdr)
379 {
380 const dvc_channel_t *ch;
381 uint32 channelid;
382
383 channelid = dvc_in_channelid(s, hdr);
384 ch = dvc_channels_get_by_id(channelid);
385 if (ch == NULL)
386 {
387 logger(Protocol, Warning,
388 "dvc_process_data(), Received data on unregistered channel %d", channelid);
389 return;
390 }
391
392 /* dispatch packet to channel handler */
393 ch->handler(s);
394 }
395
396 static void
dvc_process_close_pdu(STREAM s,dvc_hdr_t hdr)397 dvc_process_close_pdu(STREAM s, dvc_hdr_t hdr)
398 {
399 uint32 channelid;
400
401 channelid = dvc_in_channelid(s, hdr);
402 logger(Protocol, Debug, "dvc_process_close_pdu(), close channel %d", channelid);
403
404 if (!dvc_channels_remove_by_id(channelid))
405 {
406 logger(Protocol, Warning,
407 "dvc_process_close_pdu(), Received close request for unregistered channel %d",
408 channelid);
409 return;
410 }
411 }
412
413
414 static void
dvc_process_pdu(STREAM s)415 dvc_process_pdu(STREAM s)
416 {
417 dvc_hdr_t hdr;
418
419 in_uint8(s, hdr.data);
420
421 switch (hdr.hdr.cmd)
422 {
423 case DYNVC_CAPABILITIES:
424 dvc_process_caps_pdu(s);
425 break;
426 case DYNVC_CREATE_REQ:
427 dvc_process_create_pdu(s, hdr);
428 break;
429
430 case DYNVC_DATA:
431 dvc_process_data_pdu(s, hdr);
432 break;
433
434 case DYNVC_CLOSE:
435 dvc_process_close_pdu(s, hdr);
436 break;
437
438 #if 0 /* Unimplemented */
439
440 case DYNVC_DATA_FIRST:
441 break;
442 case DYNVC_DATA_FIRST_COMPRESSED:
443 break;
444 case DYNVC_DATA_COMPRESSED:
445 break;
446 case DYNVC_SOFT_SYNC_REQUEST:
447 break;
448 case DYNVC_SOFT_SYNC_RESPONSE:
449 break;
450
451 #endif
452
453 default:
454 logger(Protocol, Warning, "dvc_process_pdu(), Unhandled command type 0x%x",
455 hdr.hdr.cmd);
456 break;
457 }
458 }
459
460 RD_BOOL
dvc_init()461 dvc_init()
462 {
463 memset(channels, 0, sizeof(channels));
464 dvc_channel = channel_register("drdynvc",
465 CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP,
466 dvc_process_pdu);
467
468 return (dvc_channel != NULL);
469 }
470