VirtualBox

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

Last change on this file since 40651 was 40651, checked in by vboxsync, 13 years ago

Runtime/r3/posix, RDP/client: Solaris 11 iconv change. Avoid referencing xpg5_iconv symbol by circumventing pragma redefine_extname.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 38.6 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/* Output new pointer capability set */
831static void
832rdp_out_newpointer_caps(STREAM s)
833{
834 out_uint16_le(s, RDP_CAPSET_POINTER);
835 out_uint16_le(s, RDP_CAPLEN_NEWPOINTER);
836
837 out_uint16_le(s, 1); /* Colour pointer */
838 out_uint16_le(s, 20); /* Cache size */
839 out_uint16_le(s, 20); /* Cache size for new pointers */
840}
841
842/* Output share capability set */
843static void
844rdp_out_share_caps(STREAM s)
845{
846 out_uint16_le(s, RDP_CAPSET_SHARE);
847 out_uint16_le(s, RDP_CAPLEN_SHARE);
848
849 out_uint16(s, 0); /* userid */
850 out_uint16(s, 0); /* pad */
851}
852
853/* Output colour cache capability set */
854static void
855rdp_out_colcache_caps(STREAM s)
856{
857 out_uint16_le(s, RDP_CAPSET_COLCACHE);
858 out_uint16_le(s, RDP_CAPLEN_COLCACHE);
859
860 out_uint16_le(s, 6); /* cache size */
861 out_uint16(s, 0); /* pad */
862}
863
864/* Output brush cache capability set */
865static void
866rdp_out_brushcache_caps(STREAM s)
867{
868 out_uint16_le(s, RDP_CAPSET_BRUSHCACHE);
869 out_uint16_le(s, RDP_CAPLEN_BRUSHCACHE);
870 out_uint32_le(s, 1); /* cache type */
871}
872
873static uint8 caps_0x0d[] = {
874 0x01, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00,
875 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
876 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
877 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
878 0x00, 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
885};
886
887static uint8 caps_0x0c[] = { 0x01, 0x00, 0x00, 0x00 };
888
889static uint8 caps_0x0e[] = { 0x01, 0x00, 0x00, 0x00 };
890
891static uint8 caps_0x10[] = {
892 0xFE, 0x00, 0x04, 0x00, 0xFE, 0x00, 0x04, 0x00,
893 0xFE, 0x00, 0x08, 0x00, 0xFE, 0x00, 0x08, 0x00,
894 0xFE, 0x00, 0x10, 0x00, 0xFE, 0x00, 0x20, 0x00,
895 0xFE, 0x00, 0x40, 0x00, 0xFE, 0x00, 0x80, 0x00,
896 0xFE, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x08,
897 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00
898};
899
900/* Output unknown capability sets */
901static void
902rdp_out_unknown_caps(STREAM s, uint16 id, uint16 length, uint8 * caps)
903{
904 out_uint16_le(s, id);
905 out_uint16_le(s, length);
906
907 out_uint8p(s, caps, length - 4);
908}
909
910#define RDP5_FLAG 0x0030
911/* Send a confirm active PDU */
912static void
913rdp_send_confirm_active(void)
914{
915 STREAM s;
916 uint32 sec_flags = g_encryption ? (RDP5_FLAG | SEC_ENCRYPT) : RDP5_FLAG;
917 uint16 caplen =
918 RDP_CAPLEN_GENERAL + RDP_CAPLEN_BITMAP + RDP_CAPLEN_ORDER +
919 RDP_CAPLEN_COLCACHE +
920 RDP_CAPLEN_ACTIVATE + RDP_CAPLEN_CONTROL +
921 RDP_CAPLEN_SHARE +
922 RDP_CAPLEN_BRUSHCACHE + 0x58 + 0x08 + 0x08 + 0x34 /* unknown caps */ +
923 4 /* w2k fix, sessionid */ ;
924
925 if (g_use_rdp5)
926 {
927 caplen += RDP_CAPLEN_BMPCACHE2;
928 caplen += RDP_CAPLEN_NEWPOINTER;
929 }
930 else
931 {
932 caplen += RDP_CAPLEN_BMPCACHE;
933 caplen += RDP_CAPLEN_POINTER;
934 }
935
936 s = sec_init(sec_flags, 6 + 14 + caplen + sizeof(RDP_SOURCE));
937
938 out_uint16_le(s, 2 + 14 + caplen + sizeof(RDP_SOURCE));
939 out_uint16_le(s, (RDP_PDU_CONFIRM_ACTIVE | 0x10)); /* Version 1 */
940 out_uint16_le(s, (g_mcs_userid + 1001));
941
942 out_uint32_le(s, g_rdp_shareid);
943 out_uint16_le(s, 0x3ea); /* userid */
944 out_uint16_le(s, sizeof(RDP_SOURCE));
945 out_uint16_le(s, caplen);
946
947 out_uint8p(s, RDP_SOURCE, sizeof(RDP_SOURCE));
948 out_uint16_le(s, 0xe); /* num_caps */
949 out_uint8s(s, 2); /* pad */
950
951 rdp_out_general_caps(s);
952 rdp_out_bitmap_caps(s);
953 rdp_out_order_caps(s);
954 if (g_use_rdp5)
955 {
956 rdp_out_bmpcache2_caps(s);
957 rdp_out_newpointer_caps(s);
958 }
959 else
960 {
961 rdp_out_bmpcache_caps(s);
962 rdp_out_pointer_caps(s);
963 }
964 rdp_out_colcache_caps(s);
965 rdp_out_activate_caps(s);
966 rdp_out_control_caps(s);
967 rdp_out_share_caps(s);
968 rdp_out_brushcache_caps(s);
969
970 rdp_out_unknown_caps(s, 0x0d, 0x58, caps_0x0d); /* CAPSTYPE_INPUT */
971 rdp_out_unknown_caps(s, 0x0c, 0x08, caps_0x0c); /* CAPSTYPE_SOUND */
972 rdp_out_unknown_caps(s, 0x0e, 0x08, caps_0x0e); /* CAPSTYPE_FONT */
973 rdp_out_unknown_caps(s, 0x10, 0x34, caps_0x10); /* CAPSTYPE_GLYPHCACHE */
974
975 s_mark_end(s);
976 sec_send(s, sec_flags);
977}
978
979/* Process a general capability set */
980static void
981rdp_process_general_caps(STREAM s)
982{
983 uint16 pad2octetsB; /* rdp5 flags? */
984
985 in_uint8s(s, 10);
986 in_uint16_le(s, pad2octetsB);
987
988 if (!pad2octetsB)
989 g_use_rdp5 = False;
990}
991
992/* Process a bitmap capability set */
993static void
994rdp_process_bitmap_caps(STREAM s)
995{
996 uint16 width, height, depth;
997
998 in_uint16_le(s, depth);
999 in_uint8s(s, 6);
1000
1001 in_uint16_le(s, width);
1002 in_uint16_le(s, height);
1003
1004 DEBUG(("setting desktop size and depth to: %dx%dx%d\n", width, height, depth));
1005
1006 /*
1007 * The server may limit depth and change the size of the desktop (for
1008 * example when shadowing another session).
1009 */
1010 if (g_server_depth != depth)
1011 {
1012 warning("Remote desktop does not support colour depth %d; falling back to %d\n",
1013 g_server_depth, depth);
1014 g_server_depth = depth;
1015 }
1016 if (g_width != width || g_height != height)
1017 {
1018 warning("Remote desktop changed from %dx%d to %dx%d.\n", g_width, g_height,
1019 width, height);
1020 g_width = width;
1021 g_height = height;
1022 ui_resize_window();
1023 }
1024}
1025
1026/* Process server capabilities */
1027static void
1028rdp_process_server_caps(STREAM s, uint16 length)
1029{
1030 int n;
1031 uint8 *next, *start;
1032 uint16 ncapsets, capset_type, capset_length;
1033
1034 start = s->p;
1035
1036 in_uint16_le(s, ncapsets);
1037 in_uint8s(s, 2); /* pad */
1038
1039 for (n = 0; n < ncapsets; n++)
1040 {
1041 if (s->p > start + length)
1042 return;
1043
1044 in_uint16_le(s, capset_type);
1045 in_uint16_le(s, capset_length);
1046
1047 next = s->p + capset_length - 4;
1048
1049 switch (capset_type)
1050 {
1051 case RDP_CAPSET_GENERAL:
1052 rdp_process_general_caps(s);
1053 break;
1054
1055 case RDP_CAPSET_BITMAP:
1056 rdp_process_bitmap_caps(s);
1057 break;
1058 }
1059
1060 s->p = next;
1061 }
1062}
1063
1064/* Respond to a demand active PDU */
1065static void
1066process_demand_active(STREAM s)
1067{
1068 uint8 type;
1069 uint16 len_src_descriptor, len_combined_caps;
1070
1071 in_uint32_le(s, g_rdp_shareid);
1072 in_uint16_le(s, len_src_descriptor);
1073 in_uint16_le(s, len_combined_caps);
1074 in_uint8s(s, len_src_descriptor);
1075
1076 DEBUG(("DEMAND_ACTIVE(id=0x%x)\n", g_rdp_shareid));
1077 rdp_process_server_caps(s, len_combined_caps);
1078
1079 rdp_send_confirm_active();
1080 rdp_send_synchronise();
1081 rdp_send_control(RDP_CTL_COOPERATE);
1082 rdp_send_control(RDP_CTL_REQUEST_CONTROL);
1083 rdp_recv(&type); /* RDP_PDU_SYNCHRONIZE */
1084 rdp_recv(&type); /* RDP_CTL_COOPERATE */
1085 rdp_recv(&type); /* RDP_CTL_GRANT_CONTROL */
1086 rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0,
1087 g_numlock_sync ? ui_get_numlock_state(read_keyboard_state()) : 0, 0);
1088
1089 if (g_use_rdp5)
1090 {
1091 rdp_enum_bmpcache2();
1092 rdp_send_fonts(3);
1093 }
1094 else
1095 {
1096 rdp_send_fonts(1);
1097 rdp_send_fonts(2);
1098 }
1099
1100 rdp_recv(&type); /* RDP_PDU_UNKNOWN 0x28 (Fonts?) */
1101 reset_order_state();
1102}
1103
1104/* Process a colour pointer PDU */
1105static void
1106process_colour_pointer_common(STREAM s, int bpp)
1107{
1108 uint16 width, height, cache_idx, masklen, datalen;
1109 sint16 x, y;
1110 uint8 *mask;
1111 uint8 *data;
1112 RD_HCURSOR cursor;
1113
1114 in_uint16_le(s, cache_idx);
1115 in_uint16_le(s, x);
1116 in_uint16_le(s, y);
1117 in_uint16_le(s, width);
1118 in_uint16_le(s, height);
1119 in_uint16_le(s, masklen);
1120 in_uint16_le(s, datalen);
1121 in_uint8p(s, data, datalen);
1122 in_uint8p(s, mask, masklen);
1123 if ((width != 32) || (height != 32))
1124 {
1125 warning("process_colour_pointer_common: " "width %d height %d\n", width, height);
1126 }
1127 /* sometimes x or y is out of bounds */
1128 x = MAX(x, 0);
1129 x = MIN(x, width - 1);
1130 y = MAX(y, 0);
1131 y = MIN(y, height - 1);
1132 cursor = ui_create_cursor(x, y, width, height, mask, data, bpp);
1133 ui_set_cursor(cursor);
1134 cache_put_cursor(cache_idx, cursor);
1135}
1136
1137/* Process a colour pointer PDU */
1138void
1139process_colour_pointer_pdu(STREAM s)
1140{
1141 process_colour_pointer_common(s, 24);
1142}
1143
1144/* Process a New Pointer PDU - these pointers have variable bit depth */
1145void
1146process_new_pointer_pdu(STREAM s)
1147{
1148 int xor_bpp;
1149
1150 in_uint16_le(s, xor_bpp);
1151 process_colour_pointer_common(s, xor_bpp);
1152}
1153
1154/* Process a cached pointer PDU */
1155void
1156process_cached_pointer_pdu(STREAM s)
1157{
1158 uint16 cache_idx;
1159
1160 in_uint16_le(s, cache_idx);
1161 ui_set_cursor(cache_get_cursor(cache_idx));
1162}
1163
1164/* Process a system pointer PDU */
1165void
1166process_system_pointer_pdu(STREAM s)
1167{
1168 uint16 system_pointer_type;
1169
1170 in_uint16_le(s, system_pointer_type);
1171 switch (system_pointer_type)
1172 {
1173 case RDP_NULL_POINTER:
1174 ui_set_null_cursor();
1175 break;
1176
1177 default:
1178 unimpl("System pointer message 0x%x\n", system_pointer_type);
1179 }
1180}
1181
1182/* Process a pointer PDU */
1183static void
1184process_pointer_pdu(STREAM s)
1185{
1186 uint16 message_type;
1187 uint16 x, y;
1188
1189 in_uint16_le(s, message_type);
1190 in_uint8s(s, 2); /* pad */
1191
1192 switch (message_type)
1193 {
1194 case RDP_POINTER_MOVE:
1195 in_uint16_le(s, x);
1196 in_uint16_le(s, y);
1197 if (s_check(s))
1198 ui_move_pointer(x, y);
1199 break;
1200
1201 case RDP_POINTER_COLOR:
1202 process_colour_pointer_pdu(s);
1203 break;
1204
1205 case RDP_POINTER_CACHED:
1206 process_cached_pointer_pdu(s);
1207 break;
1208
1209 case RDP_POINTER_SYSTEM:
1210 process_system_pointer_pdu(s);
1211 break;
1212
1213 case RDP_POINTER_NEW:
1214 process_new_pointer_pdu(s);
1215 break;
1216
1217 default:
1218 unimpl("Pointer message 0x%x\n", message_type);
1219 }
1220}
1221
1222/* Process bitmap updates */
1223void
1224process_bitmap_updates(STREAM s)
1225{
1226 uint16 num_updates;
1227 uint16 left, top, right, bottom, width, height;
1228 uint16 cx, cy, bpp, Bpp, compress, bufsize, size;
1229 uint8 *data, *bmpdata;
1230 int i;
1231
1232 in_uint16_le(s, num_updates);
1233
1234 for (i = 0; i < num_updates; i++)
1235 {
1236 in_uint16_le(s, left);
1237 in_uint16_le(s, top);
1238 in_uint16_le(s, right);
1239 in_uint16_le(s, bottom);
1240 in_uint16_le(s, width);
1241 in_uint16_le(s, height);
1242 in_uint16_le(s, bpp);
1243 Bpp = (bpp + 7) / 8;
1244 in_uint16_le(s, compress);
1245 in_uint16_le(s, bufsize);
1246
1247 cx = right - left + 1;
1248 cy = bottom - top + 1;
1249
1250 DEBUG(("BITMAP_UPDATE(l=%d,t=%d,r=%d,b=%d,w=%d,h=%d,Bpp=%d,cmp=%d)\n",
1251 left, top, right, bottom, width, height, Bpp, compress));
1252
1253 if (!compress)
1254 {
1255 int y;
1256 bmpdata = (uint8 *) xmalloc(width * height * Bpp);
1257 for (y = 0; y < height; y++)
1258 {
1259 in_uint8a(s, &bmpdata[(height - y - 1) * (width * Bpp)],
1260 width * Bpp);
1261 }
1262 ui_paint_bitmap(left, top, cx, cy, width, height, bmpdata);
1263 xfree(bmpdata);
1264 continue;
1265 }
1266
1267
1268 if (compress & 0x400)
1269 {
1270 size = bufsize;
1271 }
1272 else
1273 {
1274 in_uint8s(s, 2); /* pad */
1275 in_uint16_le(s, size);
1276 in_uint8s(s, 4); /* line_size, final_size */
1277 }
1278 in_uint8p(s, data, size);
1279 bmpdata = (uint8 *) xmalloc(width * height * Bpp);
1280 if (bitmap_decompress(bmpdata, width, height, data, size, Bpp))
1281 {
1282 ui_paint_bitmap(left, top, cx, cy, width, height, bmpdata);
1283 }
1284 else
1285 {
1286 DEBUG_RDP5(("Failed to decompress data\n"));
1287 }
1288
1289 xfree(bmpdata);
1290 }
1291}
1292
1293/* Process a palette update */
1294void
1295process_palette(STREAM s)
1296{
1297 COLOURENTRY *entry;
1298 COLOURMAP map;
1299 RD_HCOLOURMAP hmap;
1300 int i;
1301
1302 in_uint8s(s, 2); /* pad */
1303 in_uint16_le(s, map.ncolours);
1304 in_uint8s(s, 2); /* pad */
1305
1306 map.colours = (COLOURENTRY *) xmalloc(sizeof(COLOURENTRY) * map.ncolours);
1307
1308 DEBUG(("PALETTE(c=%d)\n", map.ncolours));
1309
1310 for (i = 0; i < map.ncolours; i++)
1311 {
1312 entry = &map.colours[i];
1313 in_uint8(s, entry->red);
1314 in_uint8(s, entry->green);
1315 in_uint8(s, entry->blue);
1316 }
1317
1318 hmap = ui_create_colourmap(&map);
1319 ui_set_colourmap(hmap);
1320
1321 xfree(map.colours);
1322}
1323
1324/* Process an update PDU */
1325static void
1326process_update_pdu(STREAM s)
1327{
1328 uint16 update_type, count;
1329
1330 in_uint16_le(s, update_type);
1331
1332 ui_begin_update();
1333 switch (update_type)
1334 {
1335 case RDP_UPDATE_ORDERS:
1336 in_uint8s(s, 2); /* pad */
1337 in_uint16_le(s, count);
1338 in_uint8s(s, 2); /* pad */
1339 process_orders(s, count);
1340 break;
1341
1342 case RDP_UPDATE_BITMAP:
1343 process_bitmap_updates(s);
1344 break;
1345
1346 case RDP_UPDATE_PALETTE:
1347 process_palette(s);
1348 break;
1349
1350 case RDP_UPDATE_SYNCHRONIZE:
1351 break;
1352
1353 default:
1354 unimpl("update %d\n", update_type);
1355 }
1356 ui_end_update();
1357}
1358
1359
1360/* Process a Save Session Info PDU */
1361void
1362process_pdu_logon(STREAM s)
1363{
1364 uint32 infotype;
1365 in_uint32_le(s, infotype);
1366 if (infotype == INFOTYPE_LOGON_EXTENDED_INF)
1367 {
1368 uint32 fieldspresent;
1369
1370 in_uint8s(s, 2); /* Length */
1371 in_uint32_le(s, fieldspresent);
1372 if (fieldspresent & LOGON_EX_AUTORECONNECTCOOKIE)
1373 {
1374 uint32 len;
1375 uint32 version;
1376
1377 /* TS_LOGON_INFO_FIELD */
1378 in_uint8s(s, 4); /* cbFieldData */
1379
1380 /* ARC_SC_PRIVATE_PACKET */
1381 in_uint32_le(s, len);
1382 if (len != 28)
1383 {
1384 warning("Invalid length in Auto-Reconnect packet\n");
1385 return;
1386 }
1387
1388 in_uint32_le(s, version);
1389 if (version != 1)
1390 {
1391 warning("Unsupported version of Auto-Reconnect packet\n");
1392 return;
1393 }
1394
1395 in_uint32_le(s, g_reconnect_logonid);
1396 in_uint8a(s, g_reconnect_random, 16);
1397 g_has_reconnect_random = True;
1398 DEBUG(("Saving auto-reconnect cookie, id=%u\n", g_reconnect_logonid));
1399 }
1400 }
1401}
1402
1403
1404/* Process a disconnect PDU */
1405void
1406process_disconnect_pdu(STREAM s, uint32 * ext_disc_reason)
1407{
1408 in_uint32_le(s, *ext_disc_reason);
1409
1410 DEBUG(("Received disconnect PDU\n"));
1411}
1412
1413/* Process data PDU */
1414static RD_BOOL
1415process_data_pdu(STREAM s, uint32 * ext_disc_reason)
1416{
1417 uint8 data_pdu_type;
1418 uint8 ctype;
1419 uint16 clen;
1420 uint32 len;
1421
1422 uint32 roff, rlen;
1423
1424 struct stream *ns = &(g_mppc_dict.ns);
1425
1426 in_uint8s(s, 6); /* shareid, pad, streamid */
1427 in_uint16_le(s, len);
1428 in_uint8(s, data_pdu_type);
1429 in_uint8(s, ctype);
1430 in_uint16_le(s, clen);
1431 clen -= 18;
1432
1433 if (ctype & RDP_MPPC_COMPRESSED)
1434 {
1435 if (len > RDP_MPPC_DICT_SIZE)
1436 error("error decompressed packet size exceeds max\n");
1437 if (mppc_expand(s->p, clen, ctype, &roff, &rlen) == -1)
1438 error("error while decompressing packet\n");
1439
1440 /* len -= 18; */
1441
1442 /* allocate memory and copy the uncompressed data into the temporary stream */
1443 ns->data = (uint8 *) xrealloc(ns->data, rlen);
1444
1445 memcpy((ns->data), (unsigned char *) (g_mppc_dict.hist + roff), rlen);
1446
1447 ns->size = rlen;
1448 ns->end = (ns->data + ns->size);
1449 ns->p = ns->data;
1450 ns->rdp_hdr = ns->p;
1451
1452 s = ns;
1453 }
1454
1455 switch (data_pdu_type)
1456 {
1457 case RDP_DATA_PDU_UPDATE:
1458 process_update_pdu(s);
1459 break;
1460
1461 case RDP_DATA_PDU_CONTROL:
1462 DEBUG(("Received Control PDU\n"));
1463 break;
1464
1465 case RDP_DATA_PDU_SYNCHRONISE:
1466 DEBUG(("Received Sync PDU\n"));
1467 break;
1468
1469 case RDP_DATA_PDU_POINTER:
1470 process_pointer_pdu(s);
1471 break;
1472
1473 case RDP_DATA_PDU_BELL:
1474 ui_bell();
1475 break;
1476
1477 case RDP_DATA_PDU_LOGON:
1478 DEBUG(("Received Logon PDU\n"));
1479 /* User logged on */
1480 process_pdu_logon(s);
1481 break;
1482
1483 case RDP_DATA_PDU_DISCONNECT:
1484 process_disconnect_pdu(s, ext_disc_reason);
1485
1486 /* We used to return true and disconnect immediately here, but
1487 * Windows Vista sends a disconnect PDU with reason 0 when
1488 * reconnecting to a disconnected session, and MSTSC doesn't
1489 * drop the connection. I think we should just save the status.
1490 */
1491 break;
1492
1493 default:
1494 unimpl("data PDU %d\n", data_pdu_type);
1495 }
1496 return False;
1497}
1498
1499/* Process redirect PDU from Session Directory */
1500static RD_BOOL
1501process_redirect_pdu(STREAM s /*, uint32 * ext_disc_reason */ )
1502{
1503 uint32 len;
1504
1505 /* these 2 bytes are unknown, seem to be zeros */
1506 in_uint8s(s, 2);
1507
1508 /* read connection flags */
1509 in_uint32_le(s, g_redirect_flags);
1510
1511 if (g_redirect_flags & PDU_REDIRECT_HAS_IP)
1512 {
1513 /* read length of ip string */
1514 in_uint32_le(s, len);
1515
1516 /* read ip string */
1517 rdp_in_unistr(s, g_redirect_server, sizeof(g_redirect_server), len);
1518 }
1519
1520 if (g_redirect_flags & PDU_REDIRECT_HAS_COOKIE)
1521 {
1522 /* read length of cookie string */
1523 in_uint32_le(s, len);
1524
1525 /* read cookie string (plain ASCII) */
1526 if (len > sizeof(g_redirect_cookie) - 1)
1527 {
1528 uint32 rem = len - (sizeof(g_redirect_cookie) - 1);
1529 len = sizeof(g_redirect_cookie) - 1;
1530
1531 warning("Unexpectedly large redirection cookie\n");
1532 in_uint8a(s, g_redirect_cookie, len);
1533 in_uint8s(s, rem);
1534 }
1535 else
1536 {
1537 in_uint8a(s, g_redirect_cookie, len);
1538 }
1539 g_redirect_cookie[len] = 0;
1540 }
1541
1542 if (g_redirect_flags & PDU_REDIRECT_HAS_USERNAME)
1543 {
1544 /* read length of username string */
1545 in_uint32_le(s, len);
1546
1547 /* read username string */
1548 g_redirect_username = (char *) xmalloc(len + 1);
1549 rdp_in_unistr(s, g_redirect_username, strlen(g_redirect_username), len);
1550 }
1551
1552 if (g_redirect_flags & PDU_REDIRECT_HAS_DOMAIN)
1553 {
1554 /* read length of domain string */
1555 in_uint32_le(s, len);
1556
1557 /* read domain string */
1558 rdp_in_unistr(s, g_redirect_domain, sizeof(g_redirect_domain), len);
1559 }
1560
1561 if (g_redirect_flags & PDU_REDIRECT_HAS_PASSWORD)
1562 {
1563 /* read length of password string */
1564 in_uint32_le(s, len);
1565
1566 /* read password string */
1567 rdp_in_unistr(s, g_redirect_password, sizeof(g_redirect_password), len);
1568 }
1569
1570 if (g_redirect_flags & PDU_REDIRECT_DONT_STORE_USERNAME)
1571 {
1572 warning("PDU_REDIRECT_DONT_STORE_USERNAME set\n");
1573 }
1574
1575 if (g_redirect_flags & PDU_REDIRECT_USE_SMARTCARD)
1576 {
1577 warning("PDU_REDIRECT_USE_SMARTCARD set\n");
1578 }
1579
1580 if (g_redirect_flags & PDU_REDIRECT_INFORMATIONAL)
1581 {
1582 warning("PDU_REDIRECT_INFORMATIONAL set\n");
1583 }
1584
1585 if (g_redirect_flags & PDU_REDIRECT_HAS_TARGET_FQDN)
1586 {
1587 warning("PDU_REDIRECT_HAS_TARGET_FQDN set\n");
1588 }
1589
1590 if (g_redirect_flags & PDU_REDIRECT_HAS_TARGET_NETBIOS)
1591 {
1592 warning("PDU_REDIRECT_HAS_TARGET_NETBIOS set\n");
1593 }
1594
1595 if (g_redirect_flags & PDU_REDIRECT_HAS_TARGET_IP_ARRAY)
1596 {
1597 warning("PDU_REDIRECT_HAS_TARGET_IP_ARRAY set\n");
1598 }
1599
1600 g_redirect = True;
1601
1602 return True;
1603}
1604
1605/* Process incoming packets */
1606void
1607rdp_main_loop(RD_BOOL * deactivated, uint32 * ext_disc_reason)
1608{
1609 while (rdp_loop(deactivated, ext_disc_reason))
1610 {
1611 if (g_pending_resize)
1612 {
1613 return;
1614 }
1615 }
1616}
1617
1618/* used in uiports and rdp_main_loop, processes the rdp packets waiting */
1619RD_BOOL
1620rdp_loop(RD_BOOL * deactivated, uint32 * ext_disc_reason)
1621{
1622 uint8 type;
1623 RD_BOOL cont = True;
1624 STREAM s;
1625
1626 while (cont)
1627 {
1628 s = rdp_recv(&type);
1629 if (s == NULL)
1630 return False;
1631 switch (type)
1632 {
1633 case RDP_PDU_DEMAND_ACTIVE:
1634 process_demand_active(s);
1635 *deactivated = False;
1636 break;
1637 case RDP_PDU_DEACTIVATE:
1638 DEBUG(("RDP_PDU_DEACTIVATE\n"));
1639 *deactivated = True;
1640 break;
1641 case RDP_PDU_REDIRECT:
1642 return process_redirect_pdu(s);
1643 break;
1644 case RDP_PDU_DATA:
1645 process_data_pdu(s, ext_disc_reason);
1646 break;
1647 case 0:
1648 break;
1649 default:
1650 unimpl("PDU %d\n", type);
1651 }
1652 cont = g_next_packet < s->end;
1653 }
1654 return True;
1655}
1656
1657/* Establish a connection up to the RDP layer */
1658RD_BOOL
1659rdp_connect(char *server, uint32 flags, char *domain, char *password,
1660 char *command, char *directory, RD_BOOL reconnect)
1661{
1662 if (!sec_connect(server, g_username, reconnect))
1663 return False;
1664
1665 rdp_send_logon_info(flags, domain, g_username, password, command, directory);
1666 return True;
1667}
1668
1669/* Called during redirection to reset the state to support redirection */
1670void
1671rdp_reset_state(void)
1672{
1673 g_next_packet = NULL; /* reset the packet information */
1674 g_rdp_shareid = 0;
1675 sec_reset_state();
1676}
1677
1678/* Disconnect from the RDP layer */
1679void
1680rdp_disconnect(void)
1681{
1682 sec_disconnect();
1683}
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