VirtualBox

source: vbox/trunk/src/VBox/RDP/client-1.8.4/rdp.c@ 78048

Last change on this file since 78048 was 76779, checked in by vboxsync, 6 years ago

RDP: add client-1.8.4.
bugref:9356: Update rdesktop-vrdp to 1.8.4
client-1.8.4 is a Subversion copy of 1.8.3 with the upstream 1.8.3 to 1.8.4
patch applied and a couple of fixes and changes after review, namely:

  • Stopped disabling the new pointer data format for our build, as this is no

longer needed.

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