VirtualBox

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

Last change on this file since 50926 was 45164, checked in by vboxsync, 12 years ago

rdesktop-vrdp: workaround for mouse pointer shape with rdesktop 1.7.x.

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