xref: /reactos/base/applications/mstsc/rdp.c (revision 1734f297)
1 /* -*- c-basic-offset: 8 -*-
2    rdesktop: A Remote Desktop Protocol client.
3    Protocol services - RDP layer
4    Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 1999-2008
5    Copyright 2003-2011 Peter Astrand <astrand@cendio.se> for Cendio AB
6    Copyright 2011-2014 Henrik Andersson <hean01@cendio.se> for Cendio AB
7 
8    This program is free software: you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation, either version 3 of the License, or
11    (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21 
22 #include "precomp.h"
23 
24 extern uint16 g_mcs_userid;
25 extern char g_username[256];
26 extern char g_password[256];
27 char g_codepage[16];
28 extern RD_BOOL g_bitmap_compression;
29 extern RD_BOOL g_orders;
30 extern RD_BOOL g_encryption;
31 extern RD_BOOL g_desktop_save;
32 extern RD_BOOL g_polygon_ellipse_orders;
33 extern RDP_VERSION g_rdp_version;
34 extern uint16 g_server_rdp_version;
35 extern uint32 g_rdp5_performanceflags;
36 extern int g_server_depth;
37 extern int g_width;
38 extern int g_height;
39 extern RD_BOOL g_bitmap_cache;
40 extern RD_BOOL g_bitmap_cache_persist_enable;
41 extern RD_BOOL g_numlock_sync;
42 extern RD_BOOL g_pending_resize;
43 extern RD_BOOL g_network_error;
44 
45 uint8 *g_next_packet;
46 uint32 g_rdp_shareid;
47 
48 extern RDPCOMP g_mppc_dict;
49 
50 /* Session Directory support */
51 extern RD_BOOL g_redirect;
52 extern char *g_redirect_server;
53 extern uint32 g_redirect_server_len;
54 extern char *g_redirect_domain;
55 extern uint32 g_redirect_domain_len;
56 extern char *g_redirect_username;
57 extern uint32 g_redirect_username_len;
58 extern uint8 *g_redirect_lb_info;
59 extern uint32 g_redirect_lb_info_len;
60 extern uint8 *g_redirect_cookie;
61 extern uint32 g_redirect_cookie_len;
62 extern uint32 g_redirect_flags;
63 extern uint32 g_redirect_session_id;
64 
65 /* END Session Directory support */
66 
67 extern uint32 g_reconnect_logonid;
68 extern char g_reconnect_random[16];
69 extern time_t g_reconnect_random_ts;
70 extern RD_BOOL g_has_reconnect_random;
71 extern uint8 g_client_random[SEC_RANDOM_SIZE];
72 
73 void rdssl_hmac_md5(char* key, int keylen, char* data, int len, char* output);
74 
75 #if WITH_DEBUG
76 static uint32 g_packetno;
77 #endif
78 
79 #ifdef HAVE_ICONV
80 static RD_BOOL g_iconv_works = True;
81 #endif
82 
83 /* Receive an RDP packet */
84 static STREAM
85 rdp_recv(uint8 * type)
86 {
87 	static STREAM rdp_s;
88 	uint16 length, pdu_type;
89 	uint8 rdpver;
90 
91 	if ((rdp_s == NULL) || (g_next_packet >= rdp_s->end) || (g_next_packet == NULL))
92 	{
93 		rdp_s = sec_recv(&rdpver);
94 		if (rdp_s == NULL)
95 			return NULL;
96 		if (rdpver == 0xff)
97 		{
98 			g_next_packet = rdp_s->end;
99 			*type = 0;
100 			return rdp_s;
101 		}
102 		else if (rdpver != 3)
103 		{
104 			/* rdp5_process should move g_next_packet ok */
105 			rdp5_process(rdp_s);
106 			*type = 0;
107 			return rdp_s;
108 		}
109 
110 		g_next_packet = rdp_s->p;
111 	}
112 	else
113 	{
114 		rdp_s->p = g_next_packet;
115 	}
116 
117 	in_uint16_le(rdp_s, length);
118 	/* 32k packets are really 8, keepalive fix */
119 	if (length == 0x8000)
120 	{
121 		g_next_packet += 8;
122 		*type = 0;
123 		return rdp_s;
124 	}
125 	in_uint16_le(rdp_s, pdu_type);
126 	in_uint8s(rdp_s, 2);	/* userid */
127 	*type = pdu_type & 0xf;
128 
129 #ifdef WITH_DEBUG
130 	DEBUG(("RDP packet #%d, (type %x)\n", ++g_packetno, *type));
131 	hexdump(g_next_packet, length);
132 #endif /*  */
133 
134 	g_next_packet += length;
135 	return rdp_s;
136 }
137 
138 /* Initialise an RDP data packet */
139 static STREAM
140 rdp_init_data(int maxlen)
141 {
142 	STREAM s;
143 
144 	s = sec_init(g_encryption ? SEC_ENCRYPT : 0, maxlen + 18);
145 	s_push_layer(s, rdp_hdr, 18);
146 
147 	return s;
148 }
149 
150 /* Send an RDP data packet */
151 static void
152 rdp_send_data(STREAM s, uint8 data_pdu_type)
153 {
154 	uint16 length;
155 
156 	s_pop_layer(s, rdp_hdr);
157 	length = s->end - s->p;
158 
159 	out_uint16_le(s, length);
160 	out_uint16_le(s, (RDP_PDU_DATA | 0x10));
161 	out_uint16_le(s, (g_mcs_userid + 1001));
162 
163 	out_uint32_le(s, g_rdp_shareid);
164 	out_uint8(s, 0);	/* pad */
165 	out_uint8(s, 1);	/* streamid */
166 	out_uint16_le(s, (length - 14));
167 	out_uint8(s, data_pdu_type);
168 	out_uint8(s, 0);	/* compress_type */
169 	out_uint16(s, 0);	/* compress_len */
170 
171 	sec_send(s, g_encryption ? SEC_ENCRYPT : 0);
172 }
173 
174 /* Output a string in Unicode with mandatory null termination. If
175    string is NULL or len is 0, write an unicode null termination to
176    stream. */
177 void
178 rdp_out_unistr_mandatory_null(STREAM s, char *string, int len)
179 {
180 	if (string && len > 0)
181 		rdp_out_unistr(s, string, len);
182 	else
183 		out_uint16_le(s, 0);
184 }
185 
186 /* Output a string in Unicode */
187 void
188 rdp_out_unistr(STREAM s, char *string, int len)
189 {
190 	if (string == NULL || len == 0)
191 		return;
192 
193 #ifdef HAVE_ICONV
194 	size_t ibl = strlen(string), obl = len + 2;
195 	static iconv_t iconv_h = (iconv_t) - 1;
196 	char *pin = string, *pout = (char *) s->p;
197 
198 	memset(pout, 0, len + 4);
199 
200 	if (g_iconv_works)
201 	{
202 		if (iconv_h == (iconv_t) - 1)
203 		{
204 			size_t i = 1, o = 4;
205 			if ((iconv_h = iconv_open(WINDOWS_CODEPAGE, g_codepage)) == (iconv_t) - 1)
206 			{
207 				warning("rdp_out_unistr: iconv_open[%s -> %s] fail %d\n",
208 					g_codepage, WINDOWS_CODEPAGE, (int) iconv_h);
209 
210 				g_iconv_works = False;
211 				rdp_out_unistr(s, string, len);
212 				return;
213 			}
214 			if (iconv(iconv_h, (ICONV_CONST char **) &pin, &i, &pout, &o) ==
215 			    (size_t) - 1)
216 			{
217 				iconv_close(iconv_h);
218 				iconv_h = (iconv_t) - 1;
219 				warning("rdp_out_unistr: iconv(1) fail, errno %d\n", errno);
220 
221 				g_iconv_works = False;
222 				rdp_out_unistr(s, string, len);
223 				return;
224 			}
225 			pin = string;
226 			pout = (char *) s->p;
227 		}
228 
229 		if (iconv(iconv_h, (ICONV_CONST char **) &pin, &ibl, &pout, &obl) == (size_t) - 1)
230 		{
231 			iconv_close(iconv_h);
232 			iconv_h = (iconv_t) - 1;
233 			warning("rdp_out_unistr: iconv(2) fail, errno %d\n", errno);
234 
235 			g_iconv_works = False;
236 			rdp_out_unistr(s, string, len);
237 			return;
238 		}
239 
240 		s->p += len + 2;
241 
242 	}
243 	else
244 #endif
245 	{
246 		int i = 0, j = 0;
247 
248 		len += 2;
249 
250 		while (i < len)
251 		{
252 			s->p[i++] = string[j++];
253 			s->p[i++] = 0;
254 		}
255 
256 		s->p += len;
257 	}
258 }
259 
260 /* Input a string in Unicode
261  *
262  * Returns str_len of string
263  */
264 void
265 rdp_in_unistr(STREAM s, int in_len, char **string, uint32 * str_size)
266 {
267 	/* Dynamic allocate of destination string if not provided */
268 	*string = xmalloc(in_len * 2);
269 	*str_size = in_len * 2;
270 
271 #ifdef HAVE_ICONV
272 	size_t ibl = in_len, obl = *str_size - 1;
273 	char *pin = (char *) s->p, *pout = *string;
274 	static iconv_t iconv_h = (iconv_t) - 1;
275 
276 	if (g_iconv_works)
277 	{
278 		if (iconv_h == (iconv_t) - 1)
279 		{
280 			if ((iconv_h = iconv_open(g_codepage, WINDOWS_CODEPAGE)) == (iconv_t) - 1)
281 			{
282 				warning("rdp_in_unistr: iconv_open[%s -> %s] fail %d\n",
283 					WINDOWS_CODEPAGE, g_codepage, (int) iconv_h);
284 
285 				g_iconv_works = False;
286 				return rdp_in_unistr(s, in_len, string, str_size);
287 			}
288 		}
289 
290 		if (iconv(iconv_h, (ICONV_CONST char **) &pin, &ibl, &pout, &obl) == (size_t) - 1)
291 		{
292 			if (errno == E2BIG)
293 			{
294 				warning("server sent an unexpectedly long string, truncating\n");
295 			}
296 			else
297 			{
298 				warning("rdp_in_unistr: iconv fail, errno %d\n", errno);
299 
300 				free(*string);
301 				*string = NULL;
302 				*str_size = 0;
303 			}
304 		}
305 
306 		/* we must update the location of the current STREAM for future reads of s->p */
307 		s->p += in_len;
308 
309 		*pout = 0;
310 
311 		if (*string)
312 			*str_size = pout - *string;
313 	}
314 	else
315 #endif
316 	{
317 		int i = 0;
318 		int rem = 0;
319 		uint32 len = in_len / 2;
320 
321 		if (len > *str_size - 1)
322 		{
323 			warning("server sent an unexpectedly long string, truncating\n");
324 			len = *str_size - 1;
325 			rem = in_len - 2 * len;
326 		}
327 
328 		while (i < len)
329 		{
330 			in_uint8a(s, &string[i++], 1);
331 			in_uint8s(s, 1);
332 		}
333 
334 		in_uint8s(s, rem);
335 		string[len] = 0;
336 		*str_size = len;
337 	}
338 }
339 
340 
341 /* Parse a logon info packet */
342 static void
343 rdp_send_logon_info(uint32 flags, char *domain, char *user,
344 		    char *password, char *program, char *directory)
345 {
346 	char *ipaddr = tcp_get_address();
347 	/* length of string in TS_INFO_PACKET excludes null terminator */
348 	int len_domain = 2 * strlen(domain);
349 	int len_user = 2 * strlen(user);
350 	int len_password = 2 * strlen(password);
351 	int len_program = 2 * strlen(program);
352 	int len_directory = 2 * strlen(directory);
353 
354 	/* length of strings in TS_EXTENDED_PACKET includes null terminator */
355 	char dllName[MAX_PATH];
356 	int len_ip = 2 * strlen(ipaddr) + 2;
357 	int len_dll = 0;
358 
359 	int packetlen = 0;
360 	uint32 sec_flags = g_encryption ? (SEC_INFO_PKT | SEC_ENCRYPT) : SEC_INFO_PKT;
361 	STREAM s;
362 	time_t t = time(NULL);
363 	time_t tzone;
364 	uint8 security_verifier[16];
365 
366 	GetModuleFileNameA(NULL, dllName, ARRAYSIZE(dllName));
367 	len_dll = 2 * strlen(dllName) + 2;
368 
369 	if (g_rdp_version == RDP_V4 || 1 == g_server_rdp_version)
370 	{
371         DEBUG_RDP5(("Sending RDP4-style Logon packet\n"));
372 
373 		s = sec_init(sec_flags, 18 + len_domain + len_user + len_password
374 			     + len_program + len_directory + 10);
375 
376 		out_uint32(s, 0);
377 		out_uint32_le(s, flags);
378 		out_uint16_le(s, len_domain);
379 		out_uint16_le(s, len_user);
380 		out_uint16_le(s, len_password);
381 		out_uint16_le(s, len_program);
382 		out_uint16_le(s, len_directory);
383 
384 		rdp_out_unistr_mandatory_null(s, domain, len_domain);
385 		rdp_out_unistr_mandatory_null(s, user, len_user);
386 		rdp_out_unistr_mandatory_null(s, password, len_password);
387 		rdp_out_unistr_mandatory_null(s, program, len_program);
388 		rdp_out_unistr_mandatory_null(s, directory, len_directory);
389 	}
390 	else
391 	{
392 		DEBUG_RDP5(("Sending RDP5-style Logon packet\n"));
393 
394 		if (g_redirect == True && g_redirect_cookie_len > 0)
395 		{
396 			flags |= RDP_INFO_AUTOLOGON;
397 			len_password = g_redirect_cookie_len;
398 			len_password -= 2;	/* substract 2 bytes which is added below */
399 		}
400 
401 		packetlen =
402 			/* size of TS_INFO_PACKET */
403 			4 +	/* CodePage */
404 			4 +	/* flags */
405 			2 +	/* cbDomain */
406 			2 +	/* cbUserName */
407 			2 +	/* cbPassword */
408 			2 +	/* cbAlternateShell */
409 			2 +	/* cbWorkingDir */
410 			2 + len_domain +	/* Domain */
411 			2 + len_user +	/* UserName */
412 			2 + len_password +	/* Password */
413 			2 + len_program +	/* AlternateShell */
414 			2 + len_directory +	/* WorkingDir */
415 			/* size of TS_EXTENDED_INFO_PACKET */
416 			2 +	/* clientAddressFamily */
417 			2 +	/* cbClientAddress */
418 			len_ip +	/* clientAddress */
419 			2 +	/* cbClientDir */
420 			len_dll +	/* clientDir */
421 			/* size of TS_TIME_ZONE_INFORMATION */
422 			4 +	/* Bias, (UTC = local time + bias */
423 			64 +	/* StandardName, 32 unicode char array, Descriptive standard time on client */
424 			16 +	/* StandardDate */
425 			4 +	/* StandardBias */
426 			64 +	/* DaylightName, 32 unicode char array */
427 			16 +	/* DaylightDate */
428 			4 +	/* DaylightBias */
429 			4 +	/* clientSessionId */
430 			4 +	/* performanceFlags */
431 			2 +	/* cbAutoReconnectCookie, either 0 or 0x001c */
432 			/* size of ARC_CS_PRIVATE_PACKET */
433 			28;	/* autoReconnectCookie */
434 
435 
436 		s = sec_init(sec_flags, packetlen);
437 		DEBUG_RDP5(("Called sec_init with packetlen %d\n", packetlen));
438 
439 		/* TS_INFO_PACKET */
440 		out_uint32(s, 0);	/* Code Page */
441 		out_uint32_le(s, flags);
442 		out_uint16_le(s, len_domain);
443 		out_uint16_le(s, len_user);
444 		out_uint16_le(s, len_password);
445 		out_uint16_le(s, len_program);
446 		out_uint16_le(s, len_directory);
447 
448 		rdp_out_unistr_mandatory_null(s, domain, len_domain);
449 		rdp_out_unistr_mandatory_null(s, user, len_user);
450 
451 		if (g_redirect == True && 0 < g_redirect_cookie_len)
452 		{
453 			out_uint8p(s, g_redirect_cookie, g_redirect_cookie_len);
454 		}
455 		else
456 		{
457 			rdp_out_unistr_mandatory_null(s, password, len_password);
458 		}
459 
460 
461 		rdp_out_unistr_mandatory_null(s, program, len_program);
462 		rdp_out_unistr_mandatory_null(s, directory, len_directory);
463 
464 		/* TS_EXTENDED_INFO_PACKET */
465 		out_uint16_le(s, 2);	/* clientAddressFamily = AF_INET */
466 		out_uint16_le(s, len_ip);	/* cbClientAddress */
467 		rdp_out_unistr_mandatory_null(s, ipaddr, len_ip - 2);	/* clientAddress */
468 		out_uint16_le(s, len_dll);	/* cbClientDir */
469 		rdp_out_unistr(s, dllName, len_dll - 2);	/* clientDir */
470 
471 		/* TS_TIME_ZONE_INFORMATION */
472 		tzone = (mktime(gmtime(&t)) - mktime(localtime(&t))) / 60;
473 		out_uint32_le(s, tzone);
474 		rdp_out_unistr(s, "GTB, normaltid", 2 * strlen("GTB, normaltid"));
475 		out_uint8s(s, 62 - 2 * strlen("GTB, normaltid"));
476 		out_uint32_le(s, 0x0a0000);
477 		out_uint32_le(s, 0x050000);
478 		out_uint32_le(s, 3);
479 		out_uint32_le(s, 0);
480 		out_uint32_le(s, 0);
481 		rdp_out_unistr(s, "GTB, sommartid", 2 * strlen("GTB, sommartid"));
482 		out_uint8s(s, 62 - 2 * strlen("GTB, sommartid"));
483 		out_uint32_le(s, 0x30000);
484 		out_uint32_le(s, 0x050000);
485 		out_uint32_le(s, 2);
486 		out_uint32(s, 0);
487 		out_uint32_le(s, 0xffffffc4);	/* DaylightBias */
488 
489 		/* Rest of TS_EXTENDED_INFO_PACKET */
490 		out_uint32_le(s, 0);	/* clientSessionId (Ignored by server MUST be 0) */
491 		out_uint32_le(s, g_rdp5_performanceflags);
492 
493 		/* Client Auto-Reconnect */
494 		if (g_has_reconnect_random)
495 		{
496 			out_uint16_le(s, 28);	/* cbAutoReconnectLen */
497 			/* ARC_CS_PRIVATE_PACKET */
498 			out_uint32_le(s, 28);	/* cbLen */
499 			out_uint32_le(s, 1);	/* Version */
500 			out_uint32_le(s, g_reconnect_logonid);	/* LogonId */
501 			rdssl_hmac_md5(g_reconnect_random, sizeof(g_reconnect_random),
502 				           (char *)g_client_random, SEC_RANDOM_SIZE, (char *)security_verifier);
503 			out_uint8a(s, security_verifier, sizeof(security_verifier));
504 		}
505 		else
506 		{
507 			out_uint16_le(s, 0);	/* cbAutoReconnectLen */
508 		}
509 	}
510 	s_mark_end(s);
511 
512 	/* clear the redirect flag */
513 	g_redirect = False;
514 
515 	sec_send(s, sec_flags);
516 }
517 
518 /* Send a control PDU */
519 static void
520 rdp_send_control(uint16 action)
521 {
522 	STREAM s;
523 
524 	s = rdp_init_data(8);
525 
526 	out_uint16_le(s, action);
527 	out_uint16(s, 0);	/* userid */
528 	out_uint32(s, 0);	/* control id */
529 
530 	s_mark_end(s);
531 	rdp_send_data(s, RDP_DATA_PDU_CONTROL);
532 }
533 
534 /* Send a synchronisation PDU */
535 static void
536 rdp_send_synchronise(void)
537 {
538 	STREAM s;
539 
540 	s = rdp_init_data(4);
541 
542 	out_uint16_le(s, 1);	/* type */
543 	out_uint16_le(s, 1002);
544 
545 	s_mark_end(s);
546 	rdp_send_data(s, RDP_DATA_PDU_SYNCHRONISE);
547 }
548 
549 /* Send a single input event */
550 void
551 rdp_send_input(uint32 time, uint16 message_type, uint16 device_flags, uint16 param1, uint16 param2)
552 {
553 	STREAM s;
554 
555 	s = rdp_init_data(16);
556 
557 	out_uint16_le(s, 1);	/* number of events */
558 	out_uint16(s, 0);	/* pad */
559 
560 	out_uint32_le(s, time);
561 	out_uint16_le(s, message_type);
562 	out_uint16_le(s, device_flags);
563 	out_uint16_le(s, param1);
564 	out_uint16_le(s, param2);
565 
566 	s_mark_end(s);
567 	rdp_send_data(s, RDP_DATA_PDU_INPUT);
568 }
569 
570 /* Send a client window information PDU */
571 void
572 rdp_send_client_window_status(int status)
573 {
574 	STREAM s;
575 	static int current_status = 1;
576 
577 	if (current_status == status)
578 		return;
579 
580 	s = rdp_init_data(12);
581 
582 	out_uint32_le(s, status);
583 
584 	switch (status)
585 	{
586 		case 0:	/* shut the server up */
587 			break;
588 
589 		case 1:	/* receive data again */
590 			out_uint32_le(s, 0);	/* unknown */
591 			out_uint16_le(s, g_width);
592 			out_uint16_le(s, g_height);
593 			break;
594 	}
595 
596 	s_mark_end(s);
597 	rdp_send_data(s, RDP_DATA_PDU_CLIENT_WINDOW_STATUS);
598 	current_status = status;
599 }
600 
601 /* Send persistent bitmap cache enumeration PDU's */
602 static void
603 rdp_enum_bmpcache2(void)
604 {
605 	STREAM s;
606 	HASH_KEY keylist[BMPCACHE2_NUM_PSTCELLS];
607 	uint32 num_keys, offset, count, flags;
608 
609 	offset = 0;
610 	num_keys = pstcache_enumerate(2, keylist);
611 
612 	while (offset < num_keys)
613 	{
614 		count = MIN(num_keys - offset, 169);
615 
616 		s = rdp_init_data(24 + count * sizeof(HASH_KEY));
617 
618 		flags = 0;
619 		if (offset == 0)
620 			flags |= PDU_FLAG_FIRST;
621 		if (num_keys - offset <= 169)
622 			flags |= PDU_FLAG_LAST;
623 
624 		/* header */
625 		out_uint32_le(s, 0);
626 		out_uint16_le(s, count);
627 		out_uint16_le(s, 0);
628 		out_uint16_le(s, 0);
629 		out_uint16_le(s, 0);
630 		out_uint16_le(s, 0);
631 		out_uint16_le(s, num_keys);
632 		out_uint32_le(s, 0);
633 		out_uint32_le(s, flags);
634 
635 		/* list */
636 		out_uint8a(s, keylist[offset], count * sizeof(HASH_KEY));
637 
638 		s_mark_end(s);
639 		rdp_send_data(s, 0x2b);
640 
641 		offset += 169;
642 	}
643 }
644 
645 /* Send an (empty) font information PDU */
646 static void
647 rdp_send_fonts(uint16 seq)
648 {
649 	STREAM s;
650 
651 	s = rdp_init_data(8);
652 
653 	out_uint16(s, 0);	/* number of fonts */
654 	out_uint16_le(s, 0);	/* pad? */
655 	out_uint16_le(s, seq);	/* unknown */
656 	out_uint16_le(s, 0x32);	/* entry size */
657 
658 	s_mark_end(s);
659 	rdp_send_data(s, RDP_DATA_PDU_FONT2);
660 }
661 
662 /* Output general capability set */
663 static void
664 rdp_out_general_caps(STREAM s)
665 {
666 	out_uint16_le(s, RDP_CAPSET_GENERAL);
667 	out_uint16_le(s, RDP_CAPLEN_GENERAL);
668 
669 	out_uint16_le(s, 1);	/* OS major type */
670 	out_uint16_le(s, 3);	/* OS minor type */
671 	out_uint16_le(s, 0x200);	/* Protocol version */
672 	out_uint16(s, 0);	/* Pad */
673 	out_uint16(s, 0);	/* Compression types */
674 	out_uint16_le(s, (g_rdp_version >= RDP_V5) ? 0x40d : 0);
675 	/* Pad, according to T.128. 0x40d seems to
676 	   trigger
677 	   the server to start sending RDP5 packets.
678 	   However, the value is 0x1d04 with W2KTSK and
679 	   NT4MS. Hmm.. Anyway, thankyou, Microsoft,
680 	   for sending such information in a padding
681 	   field.. */
682 	out_uint16(s, 0);	/* Update capability */
683 	out_uint16(s, 0);	/* Remote unshare capability */
684 	out_uint16(s, 0);	/* Compression level */
685 	out_uint16(s, 0);	/* Pad */
686 }
687 
688 /* Output bitmap capability set */
689 static void
690 rdp_out_bitmap_caps(STREAM s)
691 {
692 	out_uint16_le(s, RDP_CAPSET_BITMAP);
693 	out_uint16_le(s, RDP_CAPLEN_BITMAP);
694 
695 	out_uint16_le(s, g_server_depth);	/* Preferred colour depth */
696 	out_uint16_le(s, 1);	/* Receive 1 BPP */
697 	out_uint16_le(s, 1);	/* Receive 4 BPP */
698 	out_uint16_le(s, 1);	/* Receive 8 BPP */
699 	out_uint16_le(s, 800);	/* Desktop width */
700 	out_uint16_le(s, 600);	/* Desktop height */
701 	out_uint16(s, 0);	/* Pad */
702 	out_uint16(s, 1);	/* Allow resize */
703 	out_uint16_le(s, g_bitmap_compression ? 1 : 0);	/* Support compression */
704 	out_uint16(s, 0);	/* Unknown */
705 	out_uint16_le(s, 1);	/* Unknown */
706 	out_uint16(s, 0);	/* Pad */
707 }
708 
709 /* Output order capability set */
710 static void
711 rdp_out_order_caps(STREAM s)
712 {
713 	uint8 order_caps[32];
714 
715 	memset(order_caps, 0, 32);
716 	order_caps[0] = 1;	/* dest blt */
717 	order_caps[1] = 1;	/* pat blt */
718 	order_caps[2] = 1;	/* screen blt */
719 	order_caps[3] = (g_bitmap_cache ? 1 : 0);	/* memblt */
720 	order_caps[4] = 0;	/* triblt */
721 	order_caps[8] = 1;	/* line */
722 	order_caps[9] = 1;	/* line */
723 	order_caps[10] = 1;	/* rect */
724 	order_caps[11] = (g_desktop_save ? 1 : 0);	/* desksave */
725 	order_caps[13] = 1;	/* memblt */
726 	order_caps[14] = 1;	/* triblt */
727 	order_caps[20] = (g_polygon_ellipse_orders ? 1 : 0);	/* polygon */
728 	order_caps[21] = (g_polygon_ellipse_orders ? 1 : 0);	/* polygon2 */
729 	order_caps[22] = 1;	/* polyline */
730 	order_caps[25] = (g_polygon_ellipse_orders ? 1 : 0);	/* ellipse */
731 	order_caps[26] = (g_polygon_ellipse_orders ? 1 : 0);	/* ellipse2 */
732 	order_caps[27] = 1;	/* text2 */
733 	out_uint16_le(s, RDP_CAPSET_ORDER);
734 	out_uint16_le(s, RDP_CAPLEN_ORDER);
735 
736 	out_uint8s(s, 20);	/* Terminal desc, pad */
737 	out_uint16_le(s, 1);	/* Cache X granularity */
738 	out_uint16_le(s, 20);	/* Cache Y granularity */
739 	out_uint16(s, 0);	/* Pad */
740 	out_uint16_le(s, 1);	/* Max order level */
741 	out_uint16_le(s, 0x147);	/* Number of fonts */
742 	out_uint16_le(s, 0x2a);	/* Capability flags */
743 	out_uint8p(s, order_caps, 32);	/* Orders supported */
744 	out_uint16_le(s, 0x6a1);	/* Text capability flags */
745 	out_uint8s(s, 6);	/* Pad */
746 	out_uint32_le(s, g_desktop_save == False ? 0 : 0x38400);	/* Desktop cache size */
747 	out_uint32(s, 0);	/* Unknown */
748 	out_uint32_le(s, 0x4e4);	/* Unknown */
749 }
750 
751 /* Output bitmap cache capability set */
752 static void
753 rdp_out_bmpcache_caps(STREAM s)
754 {
755 	int Bpp;
756 	out_uint16_le(s, RDP_CAPSET_BMPCACHE);
757 	out_uint16_le(s, RDP_CAPLEN_BMPCACHE);
758 
759 	Bpp = (g_server_depth + 7) / 8;	/* bytes per pixel */
760 	out_uint8s(s, 24);	/* unused */
761 	out_uint16_le(s, 0x258);	/* entries */
762 	out_uint16_le(s, 0x100 * Bpp);	/* max cell size */
763 	out_uint16_le(s, 0x12c);	/* entries */
764 	out_uint16_le(s, 0x400 * Bpp);	/* max cell size */
765 	out_uint16_le(s, 0x106);	/* entries */
766 	out_uint16_le(s, 0x1000 * Bpp);	/* max cell size */
767 }
768 
769 /* Output bitmap cache v2 capability set */
770 static void
771 rdp_out_bmpcache2_caps(STREAM s)
772 {
773 	out_uint16_le(s, RDP_CAPSET_BMPCACHE2);
774 	out_uint16_le(s, RDP_CAPLEN_BMPCACHE2);
775 
776 	out_uint16_le(s, g_bitmap_cache_persist_enable ? 2 : 0);	/* version */
777 
778 	out_uint16_be(s, 3);	/* number of caches in this set */
779 
780 	/* max cell size for cache 0 is 16x16, 1 = 32x32, 2 = 64x64, etc */
781 	out_uint32_le(s, BMPCACHE2_C0_CELLS);
782 	out_uint32_le(s, BMPCACHE2_C1_CELLS);
783 	if (pstcache_init(2))
784 	{
785 		out_uint32_le(s, BMPCACHE2_NUM_PSTCELLS | BMPCACHE2_FLAG_PERSIST);
786 	}
787 	else
788 	{
789 		out_uint32_le(s, BMPCACHE2_C2_CELLS);
790 	}
791 	out_uint8s(s, 20);	/* other bitmap caches not used */
792 }
793 
794 /* Output control capability set */
795 static void
796 rdp_out_control_caps(STREAM s)
797 {
798 	out_uint16_le(s, RDP_CAPSET_CONTROL);
799 	out_uint16_le(s, RDP_CAPLEN_CONTROL);
800 
801 	out_uint16(s, 0);	/* Control capabilities */
802 	out_uint16(s, 0);	/* Remote detach */
803 	out_uint16_le(s, 2);	/* Control interest */
804 	out_uint16_le(s, 2);	/* Detach interest */
805 }
806 
807 /* Output activation capability set */
808 static void
809 rdp_out_activate_caps(STREAM s)
810 {
811 	out_uint16_le(s, RDP_CAPSET_ACTIVATE);
812 	out_uint16_le(s, RDP_CAPLEN_ACTIVATE);
813 
814 	out_uint16(s, 0);	/* Help key */
815 	out_uint16(s, 0);	/* Help index key */
816 	out_uint16(s, 0);	/* Extended help key */
817 	out_uint16(s, 0);	/* Window activate */
818 }
819 
820 /* Output pointer capability set */
821 static void
822 rdp_out_pointer_caps(STREAM s)
823 {
824 	out_uint16_le(s, RDP_CAPSET_POINTER);
825 	out_uint16_le(s, RDP_CAPLEN_POINTER);
826 
827 	out_uint16(s, 0);	/* Colour pointer */
828 	out_uint16_le(s, 20);	/* Cache size */
829 }
830 
831 /* Output new pointer capability set */
832 static void
833 rdp_out_newpointer_caps(STREAM s)
834 {
835 	out_uint16_le(s, RDP_CAPSET_POINTER);
836 	out_uint16_le(s, RDP_CAPLEN_NEWPOINTER);
837 
838 	out_uint16_le(s, 1);	/* Colour pointer */
839 	out_uint16_le(s, 20);	/* Cache size */
840 	out_uint16_le(s, 20);	/* Cache size for new pointers */
841 }
842 
843 /* Output share capability set */
844 static void
845 rdp_out_share_caps(STREAM s)
846 {
847 	out_uint16_le(s, RDP_CAPSET_SHARE);
848 	out_uint16_le(s, RDP_CAPLEN_SHARE);
849 
850 	out_uint16(s, 0);	/* userid */
851 	out_uint16(s, 0);	/* pad */
852 }
853 
854 /* Output colour cache capability set */
855 static void
856 rdp_out_colcache_caps(STREAM s)
857 {
858 	out_uint16_le(s, RDP_CAPSET_COLCACHE);
859 	out_uint16_le(s, RDP_CAPLEN_COLCACHE);
860 
861 	out_uint16_le(s, 6);	/* cache size */
862 	out_uint16(s, 0);	/* pad */
863 }
864 
865 /* Output brush cache capability set */
866 static void
867 rdp_out_brushcache_caps(STREAM s)
868 {
869 	out_uint16_le(s, RDP_CAPSET_BRUSHCACHE);
870 	out_uint16_le(s, RDP_CAPLEN_BRUSHCACHE);
871 	out_uint32_le(s, 1);	/* cache type */
872 }
873 
874 static uint8 caps_0x0d[] = {
875 	0x01, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00,
876 	0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
877 	0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
878 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
879 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
880 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
881 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
882 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
883 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
884 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
885 	0x00, 0x00, 0x00, 0x00
886 };
887 
888 static uint8 caps_0x0c[] = { 0x01, 0x00, 0x00, 0x00 };
889 
890 static uint8 caps_0x0e[] = { 0x01, 0x00, 0x00, 0x00 };
891 
892 static uint8 caps_0x10[] = {
893 	0xFE, 0x00, 0x04, 0x00, 0xFE, 0x00, 0x04, 0x00,
894 	0xFE, 0x00, 0x08, 0x00, 0xFE, 0x00, 0x08, 0x00,
895 	0xFE, 0x00, 0x10, 0x00, 0xFE, 0x00, 0x20, 0x00,
896 	0xFE, 0x00, 0x40, 0x00, 0xFE, 0x00, 0x80, 0x00,
897 	0xFE, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x08,
898 	0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00
899 };
900 
901 /* Output unknown capability sets */
902 static void
903 rdp_out_unknown_caps(STREAM s, uint16 id, uint16 length, uint8 * caps)
904 {
905 	out_uint16_le(s, id);
906 	out_uint16_le(s, length);
907 
908 	out_uint8p(s, caps, length - 4);
909 }
910 
911 #define RDP5_FLAG 0x0030
912 /* Send a confirm active PDU */
913 static void
914 rdp_send_confirm_active(void)
915 {
916 	STREAM s;
917 	uint32 sec_flags = g_encryption ? (RDP5_FLAG | SEC_ENCRYPT) : RDP5_FLAG;
918 	uint16 caplen =
919 		RDP_CAPLEN_GENERAL + RDP_CAPLEN_BITMAP + RDP_CAPLEN_ORDER +
920 		RDP_CAPLEN_COLCACHE +
921 		RDP_CAPLEN_ACTIVATE + RDP_CAPLEN_CONTROL +
922 		RDP_CAPLEN_SHARE +
923 		RDP_CAPLEN_BRUSHCACHE + 0x58 + 0x08 + 0x08 + 0x34 /* unknown caps */  +
924 		4 /* w2k fix, sessionid */ ;
925 
926 	if (g_rdp_version >= RDP_V5)
927 	{
928 		caplen += RDP_CAPLEN_BMPCACHE2;
929 		caplen += RDP_CAPLEN_NEWPOINTER;
930 	}
931 	else
932 	{
933 		caplen += RDP_CAPLEN_BMPCACHE;
934 		caplen += RDP_CAPLEN_POINTER;
935 	}
936 
937 	s = sec_init(sec_flags, 6 + 14 + caplen + sizeof(RDP_SOURCE));
938 
939 	out_uint16_le(s, 2 + 14 + caplen + sizeof(RDP_SOURCE));
940 	out_uint16_le(s, (RDP_PDU_CONFIRM_ACTIVE | 0x10));	/* Version 1 */
941 	out_uint16_le(s, (g_mcs_userid + 1001));
942 
943 	out_uint32_le(s, g_rdp_shareid);
944 	out_uint16_le(s, 0x3ea);	/* userid */
945 	out_uint16_le(s, sizeof(RDP_SOURCE));
946 	out_uint16_le(s, caplen);
947 
948 	out_uint8p(s, RDP_SOURCE, sizeof(RDP_SOURCE));
949 	out_uint16_le(s, 0xe);	/* num_caps */
950 	out_uint8s(s, 2);	/* pad */
951 
952 	rdp_out_general_caps(s);
953 	rdp_out_bitmap_caps(s);
954 	rdp_out_order_caps(s);
955 	if (g_rdp_version >= RDP_V5)
956 	{
957 		rdp_out_bmpcache2_caps(s);
958 		rdp_out_newpointer_caps(s);
959 	}
960 	else
961 	{
962 		rdp_out_bmpcache_caps(s);
963 		rdp_out_pointer_caps(s);
964 	}
965 	rdp_out_colcache_caps(s);
966 	rdp_out_activate_caps(s);
967 	rdp_out_control_caps(s);
968 	rdp_out_share_caps(s);
969 	rdp_out_brushcache_caps(s);
970 
971 	rdp_out_unknown_caps(s, 0x0d, 0x58, caps_0x0d);	/* CAPSTYPE_INPUT */
972 	rdp_out_unknown_caps(s, 0x0c, 0x08, caps_0x0c);	/* CAPSTYPE_SOUND */
973 	rdp_out_unknown_caps(s, 0x0e, 0x08, caps_0x0e);	/* CAPSTYPE_FONT */
974 	rdp_out_unknown_caps(s, 0x10, 0x34, caps_0x10);	/* CAPSTYPE_GLYPHCACHE */
975 
976 	s_mark_end(s);
977 	sec_send(s, sec_flags);
978 }
979 
980 /* Process a general capability set */
981 static void
982 rdp_process_general_caps(STREAM s)
983 {
984 	uint16 pad2octetsB;	/* rdp5 flags? */
985 
986 	in_uint8s(s, 10);
987 	in_uint16_le(s, pad2octetsB);
988 
989 	if (!pad2octetsB)
990 		g_rdp_version = RDP_V4;
991 }
992 
993 /* Process a bitmap capability set */
994 static void
995 rdp_process_bitmap_caps(STREAM s)
996 {
997 	uint16 width, height, depth;
998 
999 	in_uint16_le(s, depth);
1000 	in_uint8s(s, 6);
1001 
1002 	in_uint16_le(s, width);
1003 	in_uint16_le(s, height);
1004 
1005 	DEBUG(("setting desktop size and depth to: %dx%dx%d\n", width, height, depth));
1006 
1007 	/*
1008 	 * The server may limit depth and change the size of the desktop (for
1009 	 * example when shadowing another session).
1010 	 */
1011 	if (g_server_depth != depth)
1012 	{
1013 		warning("Remote desktop does not support colour depth %d; falling back to %d\n",
1014 			g_server_depth, depth);
1015 		g_server_depth = depth;
1016 	}
1017 	if (g_width != width || g_height != height)
1018 	{
1019 		warning("Remote desktop changed from %dx%d to %dx%d.\n", g_width, g_height,
1020 			width, height);
1021 		g_width = width;
1022 		g_height = height;
1023 		ui_resize_window();
1024 	}
1025 }
1026 
1027 /* Process server capabilities */
1028 static void
1029 rdp_process_server_caps(STREAM s, uint16 length)
1030 {
1031 	int n;
1032 	uint8 *next, *start;
1033 	uint16 ncapsets, capset_type, capset_length;
1034 
1035 	start = s->p;
1036 
1037 	in_uint16_le(s, ncapsets);
1038 	in_uint8s(s, 2);	/* pad */
1039 
1040 	for (n = 0; n < ncapsets; n++)
1041 	{
1042 		if (s->p > start + length)
1043 			return;
1044 
1045 		in_uint16_le(s, capset_type);
1046 		in_uint16_le(s, capset_length);
1047 
1048 		next = s->p + capset_length - 4;
1049 
1050 		switch (capset_type)
1051 		{
1052 			case RDP_CAPSET_GENERAL:
1053 				rdp_process_general_caps(s);
1054 				break;
1055 
1056 			case RDP_CAPSET_BITMAP:
1057 				rdp_process_bitmap_caps(s);
1058 				break;
1059 		}
1060 
1061 		s->p = next;
1062 	}
1063 }
1064 
1065 /* Respond to a demand active PDU */
1066 static void
1067 process_demand_active(STREAM s)
1068 {
1069 	uint8 type;
1070 	uint16 len_src_descriptor, len_combined_caps;
1071 
1072 	in_uint32_le(s, g_rdp_shareid);
1073 	in_uint16_le(s, len_src_descriptor);
1074 	in_uint16_le(s, len_combined_caps);
1075 	in_uint8s(s, len_src_descriptor);
1076 
1077 	DEBUG(("DEMAND_ACTIVE(id=0x%x)\n", g_rdp_shareid));
1078 	rdp_process_server_caps(s, len_combined_caps);
1079 
1080 	rdp_send_confirm_active();
1081 	rdp_send_synchronise();
1082 	rdp_send_control(RDP_CTL_COOPERATE);
1083 	rdp_send_control(RDP_CTL_REQUEST_CONTROL);
1084 	rdp_recv(&type);	/* RDP_PDU_SYNCHRONIZE */
1085 	rdp_recv(&type);	/* RDP_CTL_COOPERATE */
1086 	rdp_recv(&type);	/* RDP_CTL_GRANT_CONTROL */
1087 	rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0,
1088 		       g_numlock_sync ? ui_get_numlock_state(read_keyboard_state()) : 0, 0);
1089 
1090 	if (g_rdp_version >= RDP_V5)
1091 	{
1092 		rdp_enum_bmpcache2();
1093 		rdp_send_fonts(3);
1094 	}
1095 	else
1096 	{
1097 		rdp_send_fonts(1);
1098 		rdp_send_fonts(2);
1099 	}
1100 
1101 	rdp_recv(&type);	/* RDP_PDU_UNKNOWN 0x28 (Fonts?) */
1102 	reset_order_state();
1103 }
1104 
1105 /* Process a colour pointer PDU */
1106 static void
1107 process_colour_pointer_common(STREAM s, int bpp)
1108 {
1109 	uint16 width, height, cache_idx, masklen, datalen;
1110 	uint16 x, y;
1111 	uint8 *mask;
1112 	uint8 *data;
1113 	RD_HCURSOR cursor;
1114 
1115 	in_uint16_le(s, cache_idx);
1116 	in_uint16_le(s, x);
1117 	in_uint16_le(s, y);
1118 	in_uint16_le(s, width);
1119 	in_uint16_le(s, height);
1120 	in_uint16_le(s, masklen);
1121 	in_uint16_le(s, datalen);
1122 	in_uint8p(s, data, datalen);
1123 	in_uint8p(s, mask, masklen);
1124 	if ((width != 32) || (height != 32))
1125 	{
1126 		warning("process_colour_pointer_common: " "width %d height %d\n", width, height);
1127 	}
1128 
1129 	/* keep hotspot within cursor bounding box */
1130 	x = MIN(x, width - 1);
1131 	y = MIN(y, height - 1);
1132 	cursor = ui_create_cursor(x, y, width, height, mask, data, bpp);
1133 	ui_set_cursor(cursor);
1134 	cache_put_cursor(cache_idx, cursor);
1135 }
1136 
1137 /* Process a colour pointer PDU */
1138 void
1139 process_colour_pointer_pdu(STREAM s)
1140 {
1141 	process_colour_pointer_common(s, 24);
1142 }
1143 
1144 /* Process a New Pointer PDU - these pointers have variable bit depth */
1145 void
1146 process_new_pointer_pdu(STREAM s)
1147 {
1148 	int xor_bpp;
1149 
1150 	in_uint16_le(s, xor_bpp);
1151 	process_colour_pointer_common(s, xor_bpp);
1152 }
1153 
1154 /* Process a cached pointer PDU */
1155 void
1156 process_cached_pointer_pdu(STREAM s)
1157 {
1158 	uint16 cache_idx;
1159 
1160 	in_uint16_le(s, cache_idx);
1161 	ui_set_cursor(cache_get_cursor(cache_idx));
1162 }
1163 
1164 /* Process a system pointer PDU */
1165 void
1166 process_system_pointer_pdu(STREAM s)
1167 {
1168 	uint16 system_pointer_type;
1169 
1170 	in_uint16_le(s, system_pointer_type);
1171 	switch (system_pointer_type)
1172 	{
1173 		case RDP_NULL_POINTER:
1174 			ui_set_null_cursor();
1175 			break;
1176 
1177 		default:
1178 			unimpl("System pointer message 0x%x\n", system_pointer_type);
1179 	}
1180 }
1181 
1182 /* Process a pointer PDU */
1183 static void
1184 process_pointer_pdu(STREAM s)
1185 {
1186 	uint16 message_type;
1187 	uint16 x, y;
1188 
1189 	in_uint16_le(s, message_type);
1190 	in_uint8s(s, 2);	/* pad */
1191 
1192 	switch (message_type)
1193 	{
1194 		case RDP_POINTER_MOVE:
1195 			in_uint16_le(s, x);
1196 			in_uint16_le(s, y);
1197 			if (s_check(s))
1198 				ui_move_pointer(x, y);
1199 			break;
1200 
1201 		case RDP_POINTER_COLOR:
1202 			process_colour_pointer_pdu(s);
1203 			break;
1204 
1205 		case RDP_POINTER_CACHED:
1206 			process_cached_pointer_pdu(s);
1207 			break;
1208 
1209 		case RDP_POINTER_SYSTEM:
1210 			process_system_pointer_pdu(s);
1211 			break;
1212 
1213 		case RDP_POINTER_NEW:
1214 			process_new_pointer_pdu(s);
1215 			break;
1216 
1217 		default:
1218 			unimpl("Pointer message 0x%x\n", message_type);
1219 	}
1220 }
1221 
1222 /* Process bitmap updates */
1223 void
1224 process_bitmap_updates(STREAM s)
1225 {
1226 	uint16 num_updates;
1227 	uint16 left, top, right, bottom, width, height;
1228 	uint16 cx, cy, bpp, Bpp, compress, bufsize, size;
1229 	uint8 *data, *bmpdata;
1230 	int i;
1231 
1232 	in_uint16_le(s, num_updates);
1233 
1234 	for (i = 0; i < num_updates; i++)
1235 	{
1236 		in_uint16_le(s, left);
1237 		in_uint16_le(s, top);
1238 		in_uint16_le(s, right);
1239 		in_uint16_le(s, bottom);
1240 		in_uint16_le(s, width);
1241 		in_uint16_le(s, height);
1242 		in_uint16_le(s, bpp);
1243 		Bpp = (bpp + 7) / 8;
1244 		in_uint16_le(s, compress);
1245 		in_uint16_le(s, bufsize);
1246 
1247 		cx = right - left + 1;
1248 		cy = bottom - top + 1;
1249 
1250 		DEBUG(("BITMAP_UPDATE(l=%d,t=%d,r=%d,b=%d,w=%d,h=%d,Bpp=%d,cmp=%d)\n",
1251 		       left, top, right, bottom, width, height, Bpp, compress));
1252 
1253 		if (!compress)
1254 		{
1255 			int y;
1256 			bmpdata = (uint8 *) xmalloc(width * height * Bpp);
1257 			for (y = 0; y < height; y++)
1258 			{
1259 				in_uint8a(s, &bmpdata[(height - y - 1) * (width * Bpp)],
1260 					  width * Bpp);
1261 			}
1262 			ui_paint_bitmap(left, top, cx, cy, width, height, bmpdata);
1263 			xfree(bmpdata);
1264 			continue;
1265 		}
1266 
1267 
1268 		if (compress & 0x400)
1269 		{
1270 			size = bufsize;
1271 		}
1272 		else
1273 		{
1274 			in_uint8s(s, 2);	/* pad */
1275 			in_uint16_le(s, size);
1276 			in_uint8s(s, 4);	/* line_size, final_size */
1277 		}
1278 		in_uint8p(s, data, size);
1279 		bmpdata = (uint8 *) xmalloc(width * height * Bpp);
1280 		if (bitmap_decompress(bmpdata, width, height, data, size, Bpp))
1281 		{
1282 			ui_paint_bitmap(left, top, cx, cy, width, height, bmpdata);
1283 		}
1284 		else
1285 		{
1286 			DEBUG_RDP5(("Failed to decompress data\n"));
1287 		}
1288 
1289 		xfree(bmpdata);
1290 	}
1291 }
1292 
1293 /* Process a palette update */
1294 void
1295 process_palette(STREAM s)
1296 {
1297 	COLOURENTRY *entry;
1298 	COLOURMAP map;
1299 	RD_HCOLOURMAP hmap;
1300 	int i;
1301 
1302 	in_uint8s(s, 2);	/* pad */
1303 	in_uint16_le(s, map.ncolours);
1304 	in_uint8s(s, 2);	/* pad */
1305 
1306 	map.colours = (COLOURENTRY *) xmalloc(sizeof(COLOURENTRY) * map.ncolours);
1307 
1308 	DEBUG(("PALETTE(c=%d)\n", map.ncolours));
1309 
1310 	for (i = 0; i < map.ncolours; i++)
1311 	{
1312 		entry = &map.colours[i];
1313 		in_uint8(s, entry->red);
1314 		in_uint8(s, entry->green);
1315 		in_uint8(s, entry->blue);
1316 	}
1317 
1318 	hmap = ui_create_colourmap(&map);
1319 	ui_set_colourmap(hmap);
1320 
1321 	xfree(map.colours);
1322 }
1323 
1324 /* Process an update PDU */
1325 static void
1326 process_update_pdu(STREAM s)
1327 {
1328 	uint16 update_type, count;
1329 
1330 	in_uint16_le(s, update_type);
1331 
1332 	ui_begin_update();
1333 	switch (update_type)
1334 	{
1335 		case RDP_UPDATE_ORDERS:
1336 			in_uint8s(s, 2);	/* pad */
1337 			in_uint16_le(s, count);
1338 			in_uint8s(s, 2);	/* pad */
1339 			process_orders(s, count);
1340 			break;
1341 
1342 		case RDP_UPDATE_BITMAP:
1343 			process_bitmap_updates(s);
1344 			break;
1345 
1346 		case RDP_UPDATE_PALETTE:
1347 			process_palette(s);
1348 			break;
1349 
1350 		case RDP_UPDATE_SYNCHRONIZE:
1351 			break;
1352 
1353 		default:
1354 			unimpl("update %d\n", update_type);
1355 	}
1356 	ui_end_update();
1357 }
1358 
1359 
1360 /* Process a Save Session Info PDU */
1361 void
1362 process_pdu_logon(STREAM s)
1363 {
1364 	uint32 infotype;
1365 	in_uint32_le(s, infotype);
1366 	if (infotype == INFOTYPE_LOGON_EXTENDED_INF)
1367 	{
1368 		uint32 fieldspresent;
1369 
1370 		in_uint8s(s, 2);	/* Length */
1371 		in_uint32_le(s, fieldspresent);
1372 		if (fieldspresent & LOGON_EX_AUTORECONNECTCOOKIE)
1373 		{
1374 			uint32 len;
1375 			uint32 version;
1376 
1377 			/* TS_LOGON_INFO_FIELD */
1378 			in_uint8s(s, 4);	/* cbFieldData */
1379 
1380 			/* ARC_SC_PRIVATE_PACKET */
1381 			in_uint32_le(s, len);
1382 			if (len != 28)
1383 			{
1384 				warning("Invalid length in Auto-Reconnect packet\n");
1385 				return;
1386 			}
1387 
1388 			in_uint32_le(s, version);
1389 			if (version != 1)
1390 			{
1391 				warning("Unsupported version of Auto-Reconnect packet\n");
1392 				return;
1393 			}
1394 
1395 			in_uint32_le(s, g_reconnect_logonid);
1396 			in_uint8a(s, g_reconnect_random, 16);
1397 			g_has_reconnect_random = True;
1398 			g_reconnect_random_ts = time(NULL);
1399 			DEBUG(("Saving auto-reconnect cookie, id=%u\n", g_reconnect_logonid));
1400 		}
1401 	}
1402 }
1403 
1404 
1405 /* Process a disconnect PDU */
1406 void
1407 process_disconnect_pdu(STREAM s, uint32 * ext_disc_reason)
1408 {
1409 	in_uint32_le(s, *ext_disc_reason);
1410 
1411 	DEBUG(("Received disconnect PDU\n"));
1412 }
1413 
1414 /* Process data PDU */
1415 static RD_BOOL
1416 process_data_pdu(STREAM s, uint32 * ext_disc_reason)
1417 {
1418 	uint8 data_pdu_type;
1419 	uint8 ctype;
1420 	uint16 clen;
1421 	uint32 len;
1422 
1423 	uint32 roff, rlen;
1424 
1425 	struct stream *ns = &(g_mppc_dict.ns);
1426 
1427 	in_uint8s(s, 6);	/* shareid, pad, streamid */
1428 	in_uint16_le(s, len);
1429 	in_uint8(s, data_pdu_type);
1430 	in_uint8(s, ctype);
1431 	in_uint16_le(s, clen);
1432 	clen -= 18;
1433 
1434 	if (ctype & RDP_MPPC_COMPRESSED)
1435 	{
1436 		if (len > RDP_MPPC_DICT_SIZE)
1437 			error("error decompressed packet size exceeds max\n");
1438 		if (mppc_expand(s->p, clen, ctype, &roff, &rlen) == -1)
1439 			error("error while decompressing packet\n");
1440 
1441 		/* len -= 18; */
1442 
1443 		/* allocate memory and copy the uncompressed data into the temporary stream */
1444 		ns->data = (uint8 *) xrealloc(ns->data, rlen);
1445 
1446 		memcpy((ns->data), (unsigned char *) (g_mppc_dict.hist + roff), rlen);
1447 
1448 		ns->size = rlen;
1449 		ns->end = (ns->data + ns->size);
1450 		ns->p = ns->data;
1451 		ns->rdp_hdr = ns->p;
1452 
1453 		s = ns;
1454 	}
1455 
1456 	switch (data_pdu_type)
1457 	{
1458 		case RDP_DATA_PDU_UPDATE:
1459 			process_update_pdu(s);
1460 			break;
1461 
1462 		case RDP_DATA_PDU_CONTROL:
1463 			DEBUG(("Received Control PDU\n"));
1464 			break;
1465 
1466 		case RDP_DATA_PDU_SYNCHRONISE:
1467 			DEBUG(("Received Sync PDU\n"));
1468 			break;
1469 
1470 		case RDP_DATA_PDU_POINTER:
1471 			process_pointer_pdu(s);
1472 			break;
1473 
1474 		case RDP_DATA_PDU_BELL:
1475 			ui_bell();
1476 			break;
1477 
1478 		case RDP_DATA_PDU_LOGON:
1479 			DEBUG(("Received Logon PDU\n"));
1480 			/* User logged on */
1481 			process_pdu_logon(s);
1482 			break;
1483 
1484 		case RDP_DATA_PDU_DISCONNECT:
1485 			process_disconnect_pdu(s, ext_disc_reason);
1486 
1487 			/* We used to return true and disconnect immediately here, but
1488 			 * Windows Vista sends a disconnect PDU with reason 0 when
1489 			 * reconnecting to a disconnected session, and MSTSC doesn't
1490 			 * drop the connection.  I think we should just save the status.
1491 			 */
1492 			break;
1493 
1494 		case RDP_DATA_PDU_AUTORECONNECT_STATUS:
1495 			warning("Automatic reconnect using cookie, failed.\n");
1496 			break;
1497 
1498 		default:
1499 			unimpl("data PDU %d\n", data_pdu_type);
1500 	}
1501 	return False;
1502 }
1503 
1504 /* Process redirect PDU from Session Directory */
1505 static RD_BOOL
1506 process_redirect_pdu(STREAM s, RD_BOOL enhanced_redirect /*, uint32 * ext_disc_reason */ )
1507 {
1508 	uint32 len;
1509 	uint16 redirect_identifier;
1510 
1511 	/* reset any previous redirection information */
1512 	g_redirect = True;
1513 	free(g_redirect_server);
1514 	free(g_redirect_username);
1515 	free(g_redirect_domain);
1516 	free(g_redirect_lb_info);
1517 	free(g_redirect_cookie);
1518 
1519 	g_redirect_server = NULL;
1520 	g_redirect_username = NULL;
1521 	g_redirect_domain = NULL;
1522 	g_redirect_lb_info = NULL;
1523 	g_redirect_cookie = NULL;
1524 
1525 	/* these 2 bytes are unknown, seem to be zeros */
1526 	in_uint8s(s, 2);
1527 
1528 	/* FIXME: Previous implementation only reads 4 bytes which has been working
1529 	   but todays spec says something different. Investigate and retest
1530 	   server redirection using WTS 2003 cluster.
1531 	 */
1532 
1533 	if (enhanced_redirect)
1534 	{
1535 		/* read identifier */
1536 		in_uint16_le(s, redirect_identifier);
1537 		if (redirect_identifier != 0x0400)
1538 			error("Protocol error in server redirection, unexpected data.");
1539 
1540 		/* FIXME: skip total length */
1541 		in_uint8s(s, 2);
1542 
1543 		/* read session_id */
1544 		in_uint32_le(s, g_redirect_session_id);
1545 	}
1546 
1547 	/* read connection flags */
1548 	in_uint32_le(s, g_redirect_flags);
1549 
1550 	if (g_redirect_flags & LB_TARGET_NET_ADDRESS)
1551 	{
1552 		/* read length of ip string */
1553 		in_uint32_le(s, len);
1554 
1555 		/* read ip string */
1556 		rdp_in_unistr(s, len, &g_redirect_server, &g_redirect_server_len);
1557 	}
1558 
1559 	if (g_redirect_flags & LB_LOAD_BALANCE_INFO)
1560 	{
1561 		/* read length of load balance info blob */
1562 		in_uint32_le(s, g_redirect_lb_info_len);
1563 
1564 		/* reallocate a loadbalance info blob */
1565 		if (g_redirect_lb_info != NULL)
1566 			free(g_redirect_lb_info);
1567 
1568 		g_redirect_lb_info = xmalloc(g_redirect_lb_info_len);
1569 
1570 		/* read load balance info blob */
1571 		in_uint8p(s, g_redirect_lb_info, g_redirect_lb_info_len);
1572 	}
1573 
1574 	if (g_redirect_flags & LB_USERNAME)
1575 	{
1576 		/* read length of username string */
1577 		in_uint32_le(s, len);
1578 
1579 		/* read username string */
1580 		rdp_in_unistr(s, len, &g_redirect_username, &g_redirect_username_len);
1581 	}
1582 
1583 	if (g_redirect_flags & LB_DOMAIN)
1584 	{
1585 		/* read length of domain string */
1586 		in_uint32_le(s, len);
1587 
1588 		/* read domain string */
1589 		rdp_in_unistr(s, len, &g_redirect_domain, &g_redirect_domain_len);
1590 	}
1591 
1592 	if (g_redirect_flags & LB_PASSWORD)
1593 	{
1594 		/* the information in this blob is either a password or a cookie that
1595 		   should be passed though as blob and not parsed as a unicode string */
1596 
1597 		/* read blob length */
1598 		in_uint32_le(s, g_redirect_cookie_len);
1599 
1600 		/* reallocate cookie blob */
1601 		if (g_redirect_cookie != NULL)
1602 			free(g_redirect_cookie);
1603 
1604 		g_redirect_cookie = xmalloc(g_redirect_cookie_len);
1605 
1606 		/* read cookie as is */
1607 		in_uint8p(s, g_redirect_cookie, g_redirect_cookie_len);
1608 	}
1609 
1610 	if (g_redirect_flags & LB_DONTSTOREUSERNAME)
1611 	{
1612 		warning("LB_DONTSTOREUSERNAME set\n");
1613 	}
1614 
1615 	if (g_redirect_flags & LB_SMARTCARD_LOGON)
1616 	{
1617 		warning("LB_SMARTCARD_LOGON set\n");
1618 	}
1619 
1620 	if (g_redirect_flags & LB_NOREDIRECT)
1621 	{
1622 		/* By spec this is only for information and doesn't mean that an actual
1623 		   redirect should be performed. How it should be used is not mentioned. */
1624 		g_redirect = False;
1625 	}
1626 
1627 	if (g_redirect_flags & LB_TARGET_FQDN)
1628 	{
1629 		in_uint32_le(s, len);
1630 
1631 		/* Let target fqdn replace target ip address */
1632 		if (g_redirect_server)
1633 		{
1634 			free(g_redirect_server);
1635 			g_redirect_server = NULL;
1636 		}
1637 
1638 		/* read fqdn string */
1639 		rdp_in_unistr(s, len, &g_redirect_server, &g_redirect_server_len);
1640 	}
1641 
1642 	if (g_redirect_flags & LB_TARGET_NETBIOS)
1643 	{
1644 		warning("LB_TARGET_NETBIOS set\n");
1645 	}
1646 
1647 	if (g_redirect_flags & LB_TARGET_NET_ADDRESSES)
1648 	{
1649 		warning("LB_TARGET_NET_ADDRESSES set\n");
1650 	}
1651 
1652 	if (g_redirect_flags & LB_CLIENT_TSV_URL)
1653 	{
1654 		warning("LB_CLIENT_TSV_URL set\n");
1655 	}
1656 
1657 	if (g_redirect_flags & LB_SERVER_TSV_CAPABLE)
1658 	{
1659 		warning("LB_SERVER_TSV_CAPABLE set\n");
1660 	}
1661 
1662 	if (g_redirect_flags & LB_PASSWORD_IS_PK_ENCRYPTED)
1663 	{
1664 		warning("LB_PASSWORD_IS_PK_ENCRYPTED set\n");
1665 	}
1666 
1667 	if (g_redirect_flags & LB_REDIRECTION_GUID)
1668 	{
1669 		warning("LB_REDIRECTION_GUID set\n");
1670 	}
1671 
1672 	if (g_redirect_flags & LB_TARGET_CERTIFICATE)
1673 	{
1674 		warning("LB_TARGET_CERTIFICATE set\n");
1675 	}
1676 
1677 	return True;
1678 }
1679 
1680 /* Process incoming packets */
1681 void
1682 rdp_main_loop(RD_BOOL * deactivated, uint32 * ext_disc_reason)
1683 {
1684 	while (rdp_loop(deactivated, ext_disc_reason))
1685 	{
1686 		if (g_pending_resize || g_redirect)
1687 		{
1688 			return;
1689 		}
1690 	}
1691 }
1692 
1693 /* used in uiports and rdp_main_loop, processes the rdp packets waiting */
1694 RD_BOOL
1695 rdp_loop(RD_BOOL * deactivated, uint32 * ext_disc_reason)
1696 {
1697 	uint8 type;
1698 	RD_BOOL cont = True;
1699 	STREAM s;
1700 
1701 	while (cont)
1702 	{
1703 		s = rdp_recv(&type);
1704 		if (s == NULL)
1705 			return False;
1706 		switch (type)
1707 		{
1708 			case RDP_PDU_DEMAND_ACTIVE:
1709 				process_demand_active(s);
1710 				*deactivated = False;
1711 				break;
1712 			case RDP_PDU_DEACTIVATE:
1713 				DEBUG(("RDP_PDU_DEACTIVATE\n"));
1714 				*deactivated = True;
1715 				break;
1716 			case RDP_PDU_REDIRECT:
1717 				return process_redirect_pdu(s, False);
1718 				break;
1719 			case RDP_PDU_ENHANCED_REDIRECT:
1720 				return process_redirect_pdu(s, True);
1721 				break;
1722 			case RDP_PDU_DATA:
1723 				/* If we got a data PDU, we don't need to keep the password in memory
1724 				   anymore and therefor we should clear it for security reasons. */
1725 				if (g_password[0] != '\0')
1726 					memset(g_password, 0, sizeof(g_password));
1727 
1728 				process_data_pdu(s, ext_disc_reason);
1729 				break;
1730 			case 0:
1731 				break;
1732 			default:
1733 				unimpl("PDU %d\n", type);
1734 		}
1735 		cont = g_next_packet < s->end;
1736 	}
1737 	return True;
1738 }
1739 
1740 /* Establish a connection up to the RDP layer */
1741 RD_BOOL
1742 rdp_connect(char *server, uint32 flags, char *domain, char *password,
1743 	    char *command, char *directory, RD_BOOL reconnect)
1744 {
1745 	RD_BOOL deactivated = False;
1746 	uint32 ext_disc_reason = 0;
1747 
1748 	if (!sec_connect(server, g_username, domain, password, reconnect))
1749 		return False;
1750 
1751 	rdp_send_logon_info(flags, domain, g_username, password, command, directory);
1752 
1753 	/* run RDP loop until first licence demand active PDU */
1754 	while (!g_rdp_shareid)
1755 	{
1756 		if (g_network_error)
1757 			return False;
1758 
1759 		if (!rdp_loop(&deactivated, &ext_disc_reason))
1760 			return False;
1761 
1762 		if (g_redirect)
1763 			return True;
1764 	}
1765 	return True;
1766 }
1767 
1768 /* Called during redirection to reset the state to support redirection */
1769 void
1770 rdp_reset_state(void)
1771 {
1772 	g_next_packet = NULL;	/* reset the packet information */
1773 	g_rdp_shareid = 0;
1774 	sec_reset_state();
1775 }
1776 
1777 /* Disconnect from the RDP layer */
1778 void
1779 rdp_disconnect(void)
1780 {
1781 	sec_disconnect();
1782 }
1783