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