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