VirtualBox

source: vbox/trunk/src/VBox/RDP/client/rdp.c@ 39858

Last change on this file since 39858 was 37224, checked in by vboxsync, 14 years ago

RDP/client: fix OSE

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette