VirtualBox

source: vbox/trunk/src/VBox/RDP/client-1.8.3/rdp.c@ 67954

Last change on this file since 67954 was 55123, checked in by vboxsync, 10 years ago

rdesktop 1.8.3 modified for VBox

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