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