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