VirtualBox

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

Last change on this file since 93115 was 88297, checked in by vboxsync, 4 years ago

Some small Solaris-specific build warning fixes:

include/iprt/x86.h: Undefine MSR_IA32_FLUSH_CMD to avoid warning about
'"MSR_IA32_FLUSH_CMD" redefined' when compiling SUPLibLdr.cpp.
SUPLibLdr.cpp includes <stdlib.h> which ultimately pulls in
<sys/controlregs.h> which has its own definition of MSR_IA32_FLUSH_CMD.

Additions/solaris/SharedFolders: Updated a handful of function prototypes
under SharedFolders/solaris10 which don't take any arguments to be
explicitly declared as 'function(void)' to silence gcc warnings from
-Wstrict-prototypes.

Main/src-server/solaris: Fixed two places where -Wconversion identified
possible alteration of the value due to different sized types.

RDP/client: Addressed an incorrect conversion descriptor type passed to
iconv(3C) in utils.c:utils_locale_to_utf8() (corresponding to unresolved
upstream issue #387 (https://github.com/rdesktop/rdesktop/issues/387).
Tidied up some inconsistent iconv(3C) argument type usage: the use of
-DUSE_LEGACY_PROTOTYPES requires -DICONV_CONST=const. Fixed some
incorrect strncpy()/strcat() calls using the corresponding code from
upstream.

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