1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Protocol services - RDP layer
4 Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 1999-2008
5 Copyright 2003-2011 Peter Astrand <astrand@cendio.se> for Cendio AB
6 Copyright 2011-2014 Henrik Andersson <hean01@cendio.se> for Cendio AB
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.
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.
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/>.
24 extern uint16 g_mcs_userid
;
25 extern char g_username
[256];
26 extern char g_password
[256];
28 extern RD_BOOL g_bitmap_compression
;
29 extern RD_BOOL g_orders
;
30 extern RD_BOOL g_encryption
;
31 extern RD_BOOL g_desktop_save
;
32 extern RD_BOOL g_polygon_ellipse_orders
;
33 extern RDP_VERSION g_rdp_version
;
34 extern uint16 g_server_rdp_version
;
35 extern uint32 g_rdp5_performanceflags
;
36 extern int g_server_depth
;
39 extern RD_BOOL g_bitmap_cache
;
40 extern RD_BOOL g_bitmap_cache_persist_enable
;
41 extern RD_BOOL g_numlock_sync
;
42 extern RD_BOOL g_pending_resize
;
43 extern RD_BOOL g_network_error
;
48 extern RDPCOMP g_mppc_dict
;
50 /* Session Directory support */
51 extern RD_BOOL g_redirect
;
52 extern char *g_redirect_server
;
53 extern uint32 g_redirect_server_len
;
54 extern char *g_redirect_domain
;
55 extern uint32 g_redirect_domain_len
;
56 extern char *g_redirect_username
;
57 extern uint32 g_redirect_username_len
;
58 extern uint8
*g_redirect_lb_info
;
59 extern uint32 g_redirect_lb_info_len
;
60 extern uint8
*g_redirect_cookie
;
61 extern uint32 g_redirect_cookie_len
;
62 extern uint32 g_redirect_flags
;
63 extern uint32 g_redirect_session_id
;
65 /* END Session Directory support */
67 extern uint32 g_reconnect_logonid
;
68 extern char g_reconnect_random
[16];
69 extern time_t g_reconnect_random_ts
;
70 extern RD_BOOL g_has_reconnect_random
;
71 extern uint8 g_client_random
[SEC_RANDOM_SIZE
];
73 void ssl_hmac_md5(char* key
, int keylen
, char* data
, int len
, char* output
);
76 static uint32 g_packetno
;
80 static RD_BOOL g_iconv_works
= True
;
83 /* Receive an RDP packet */
85 rdp_recv(uint8
* type
)
88 uint16 length
, pdu_type
;
91 if ((rdp_s
== NULL
) || (g_next_packet
>= rdp_s
->end
) || (g_next_packet
== NULL
))
93 rdp_s
= sec_recv(&rdpver
);
98 g_next_packet
= rdp_s
->end
;
102 else if (rdpver
!= 3)
104 /* rdp5_process should move g_next_packet ok */
110 g_next_packet
= rdp_s
->p
;
114 rdp_s
->p
= g_next_packet
;
117 in_uint16_le(rdp_s
, length
);
118 /* 32k packets are really 8, keepalive fix */
119 if (length
== 0x8000)
125 in_uint16_le(rdp_s
, pdu_type
);
126 in_uint8s(rdp_s
, 2); /* userid */
127 *type
= pdu_type
& 0xf;
130 DEBUG(("RDP packet #%d, (type %x)\n", ++g_packetno
, *type
));
131 hexdump(g_next_packet
, length
);
134 g_next_packet
+= length
;
138 /* Initialise an RDP data packet */
140 rdp_init_data(int maxlen
)
144 s
= sec_init(g_encryption
? SEC_ENCRYPT
: 0, maxlen
+ 18);
145 s_push_layer(s
, rdp_hdr
, 18);
150 /* Send an RDP data packet */
152 rdp_send_data(STREAM s
, uint8 data_pdu_type
)
156 s_pop_layer(s
, rdp_hdr
);
157 length
= s
->end
- s
->p
;
159 out_uint16_le(s
, length
);
160 out_uint16_le(s
, (RDP_PDU_DATA
| 0x10));
161 out_uint16_le(s
, (g_mcs_userid
+ 1001));
163 out_uint32_le(s
, g_rdp_shareid
);
164 out_uint8(s
, 0); /* pad */
165 out_uint8(s
, 1); /* streamid */
166 out_uint16_le(s
, (length
- 14));
167 out_uint8(s
, data_pdu_type
);
168 out_uint8(s
, 0); /* compress_type */
169 out_uint16(s
, 0); /* compress_len */
171 sec_send(s
, g_encryption
? SEC_ENCRYPT
: 0);
174 /* Output a string in Unicode */
176 rdp_out_unistr(STREAM s
, char *string
, int len
)
178 if (string
== NULL
|| len
== 0)
182 size_t ibl
= strlen(string
), obl
= len
+ 2;
183 static iconv_t iconv_h
= (iconv_t
) - 1;
184 char *pin
= string
, *pout
= (char *) s
->p
;
186 memset(pout
, 0, len
+ 4);
190 if (iconv_h
== (iconv_t
) - 1)
193 if ((iconv_h
= iconv_open(WINDOWS_CODEPAGE
, g_codepage
)) == (iconv_t
) - 1)
195 warning("rdp_out_unistr: iconv_open[%s -> %s] fail %d\n",
196 g_codepage
, WINDOWS_CODEPAGE
, (int) iconv_h
);
198 g_iconv_works
= False
;
199 rdp_out_unistr(s
, string
, len
);
202 if (iconv(iconv_h
, (ICONV_CONST
char **) &pin
, &i
, &pout
, &o
) ==
205 iconv_close(iconv_h
);
206 iconv_h
= (iconv_t
) - 1;
207 warning("rdp_out_unistr: iconv(1) fail, errno %d\n", errno
);
209 g_iconv_works
= False
;
210 rdp_out_unistr(s
, string
, len
);
214 pout
= (char *) s
->p
;
217 if (iconv(iconv_h
, (ICONV_CONST
char **) &pin
, &ibl
, &pout
, &obl
) == (size_t) - 1)
219 iconv_close(iconv_h
);
220 iconv_h
= (iconv_t
) - 1;
221 warning("rdp_out_unistr: iconv(2) fail, errno %d\n", errno
);
223 g_iconv_works
= False
;
224 rdp_out_unistr(s
, string
, len
);
240 s
->p
[i
++] = string
[j
++];
248 /* Input a string in Unicode
250 * Returns str_len of string
253 rdp_in_unistr(STREAM s
, int in_len
, char **string
, uint32
* str_size
)
255 /* Dynamic allocate of destination string if not provided */
256 *string
= xmalloc(in_len
* 2);
257 *str_size
= in_len
* 2;
260 size_t ibl
= in_len
, obl
= *str_size
- 1;
261 char *pin
= (char *) s
->p
, *pout
= *string
;
262 static iconv_t iconv_h
= (iconv_t
) - 1;
266 if (iconv_h
== (iconv_t
) - 1)
268 if ((iconv_h
= iconv_open(g_codepage
, WINDOWS_CODEPAGE
)) == (iconv_t
) - 1)
270 warning("rdp_in_unistr: iconv_open[%s -> %s] fail %d\n",
271 WINDOWS_CODEPAGE
, g_codepage
, (int) iconv_h
);
273 g_iconv_works
= False
;
274 return rdp_in_unistr(s
, in_len
, string
, str_size
);
278 if (iconv(iconv_h
, (ICONV_CONST
char **) &pin
, &ibl
, &pout
, &obl
) == (size_t) - 1)
282 warning("server sent an unexpectedly long string, truncating\n");
286 warning("rdp_in_unistr: iconv fail, errno %d\n", errno
);
294 /* we must update the location of the current STREAM for future reads of s->p */
300 *str_size
= pout
- *string
;
307 uint32 len
= in_len
/ 2;
309 if (len
> *str_size
- 1)
311 warning("server sent an unexpectedly long string, truncating\n");
313 rem
= in_len
- 2 * len
;
318 in_uint8a(s
, &string
[i
++], 1);
329 /* Parse a logon info packet */
331 rdp_send_logon_info(uint32 flags
, char *domain
, char *user
,
332 char *password
, char *program
, char *directory
)
334 char *ipaddr
= tcp_get_address();
335 /* length of string in TS_INFO_PACKET excludes null terminator */
336 int len_domain
= 2 * strlen(domain
);
337 int len_user
= 2 * strlen(user
);
338 int len_password
= 2 * strlen(password
);
339 int len_program
= 2 * strlen(program
);
340 int len_directory
= 2 * strlen(directory
);
342 /* length of strings in TS_EXTENDED_PACKET includes null terminator */
343 int len_ip
= 2 * strlen(ipaddr
) + 2;
344 int len_dll
= 2 * strlen("C:\\") + 2;
347 uint32 sec_flags
= g_encryption
? (SEC_LOGON_INFO
| SEC_ENCRYPT
) : SEC_LOGON_INFO
;
349 time_t t
= time(NULL
);
351 uint8 security_verifier
[16];
353 if (g_rdp_version
== RDP_V4
|| 1 == g_server_rdp_version
)
355 DEBUG_RDP5(("Sending RDP4-style Logon packet\n"));
357 s
= sec_init(sec_flags
, 18 + len_domain
+ len_user
+ len_password
358 + len_program
+ len_directory
+ 10);
361 out_uint32_le(s
, flags
);
362 out_uint16_le(s
, len_domain
);
363 out_uint16_le(s
, len_user
);
364 out_uint16_le(s
, len_password
);
365 out_uint16_le(s
, len_program
);
366 out_uint16_le(s
, len_directory
);
367 rdp_out_unistr(s
, domain
, len_domain
);
368 rdp_out_unistr(s
, user
, len_user
);
369 rdp_out_unistr(s
, password
, len_password
);
370 rdp_out_unistr(s
, program
, len_program
);
371 rdp_out_unistr(s
, directory
, len_directory
);
375 DEBUG_RDP5(("Sending RDP5-style Logon packet\n"));
377 if (g_redirect
== True
&& g_redirect_cookie_len
> 0)
379 len_password
= g_redirect_cookie_len
;
380 len_password
-= 2; /* substract 2 bytes which is added below */
384 /* size of TS_INFO_PACKET */
390 2 + /* cbAlternateShell */
391 2 + /* cbWorkingDir */
392 2 + len_domain
+ /* Domain */
393 2 + len_user
+ /* UserName */
394 2 + len_password
+ /* Password */
395 2 + len_program
+ /* AlternateShell */
396 2 + len_directory
+ /* WorkingDir */
397 /* size of TS_EXTENDED_INFO_PACKET */
398 2 + /* clientAdressFamily */
399 2 + /* cbClientAdress */
400 len_ip
+ /* clientAddress */
401 2 + /* cbClientDir */
402 len_dll
+ /* clientDir */
403 /* size of TS_TIME_ZONE_INFORMATION */
404 4 + /* Bias, (UTC = local time + bias */
405 64 + /* StandardName, 32 unicode char array, Descriptive standard time on client */
406 16 + /* StandardDate */
407 4 + /* StandardBias */
408 64 + /* DaylightName, 32 unicode char array */
409 16 + /* DaylightDate */
410 4 + /* DaylightBias */
411 4 + /* clientSessionId */
412 4 + /* performanceFlags */
413 2 + /* cbAutoReconnectCookie, either 0 or 0x001c */
414 /* size of ARC_CS_PRIVATE_PACKET */
415 28; /* autoReconnectCookie */
418 s
= sec_init(sec_flags
, packetlen
);
419 DEBUG_RDP5(("Called sec_init with packetlen %d\n", packetlen
));
422 out_uint32(s
, 0); /* Code Page */
423 out_uint32_le(s
, flags
);
424 out_uint16_le(s
, len_domain
);
425 out_uint16_le(s
, len_user
);
426 out_uint16_le(s
, len_password
);
427 out_uint16_le(s
, len_program
);
428 out_uint16_le(s
, len_directory
);
431 rdp_out_unistr(s
, domain
, len_domain
);
433 out_uint16_le(s
, 0); /* mandatory 2 bytes null terminator */
436 rdp_out_unistr(s
, user
, len_user
);
438 out_uint16_le(s
, 0); /* mandatory 2 bytes null terminator */
440 if (0 < len_password
)
442 if (g_redirect
== True
&& 0 < g_redirect_cookie_len
)
444 out_uint8p(s
, g_redirect_cookie
, g_redirect_cookie_len
);
448 rdp_out_unistr(s
, password
, len_password
);
452 out_uint16_le(s
, 0); /* mandatory 2 bytes null terminator */
455 rdp_out_unistr(s
, program
, len_program
);
457 out_uint16_le(s
, 0); /* mandatory 2 bytes null terminator */
459 if (0 < len_directory
)
460 rdp_out_unistr(s
, directory
, len_directory
);
462 out_uint16_le(s
, 0); /* mandatory 2 bytes null terminator */
464 /* TS_EXTENDED_INFO_PACKET */
465 out_uint16_le(s
, 2); /* clientAddressFamily = AF_INET */
466 out_uint16_le(s
, len_ip
); /* cbClientAddress, Length of client ip */
467 rdp_out_unistr(s
, ipaddr
, len_ip
- 2); /* clientAddress */
468 out_uint16_le(s
, len_dll
); /* cbClientDir */
469 rdp_out_unistr(s
, "C:\\", len_dll
- 2); /* clientDir */
471 /* TS_TIME_ZONE_INFORMATION */
472 tzone
= (mktime(gmtime(&t
)) - mktime(localtime(&t
))) / 60;
473 out_uint32_le(s
, tzone
);
474 rdp_out_unistr(s
, "GTB, normaltid", 2 * strlen("GTB, normaltid"));
475 out_uint8s(s
, 62 - 2 * strlen("GTB, normaltid"));
476 out_uint32_le(s
, 0x0a0000);
477 out_uint32_le(s
, 0x050000);
481 rdp_out_unistr(s
, "GTB, sommartid", 2 * strlen("GTB, sommartid"));
482 out_uint8s(s
, 62 - 2 * strlen("GTB, sommartid"));
483 out_uint32_le(s
, 0x30000);
484 out_uint32_le(s
, 0x050000);
487 out_uint32_le(s
, 0xffffffc4); /* DaylightBias */
489 /* Rest of TS_EXTENDED_INFO_PACKET */
490 out_uint32_le(s
, 0); /* clientSessionId (Ignored by server MUST be 0) */
491 out_uint32_le(s
, g_rdp5_performanceflags
);
493 /* Client Auto-Reconnect */
494 if (g_has_reconnect_random
)
496 out_uint16_le(s
, 28); /* cbAutoReconnectLen */
497 /* ARC_CS_PRIVATE_PACKET */
498 out_uint32_le(s
, 28); /* cbLen */
499 out_uint32_le(s
, 1); /* Version */
500 out_uint32_le(s
, g_reconnect_logonid
); /* LogonId */
501 ssl_hmac_md5(g_reconnect_random
, sizeof(g_reconnect_random
),
502 (char *)g_client_random
, SEC_RANDOM_SIZE
, (char *)security_verifier
);
503 out_uint8a(s
, security_verifier
, sizeof(security_verifier
));
507 out_uint16_le(s
, 0); /* cbAutoReconnectLen */
512 /* clear the redirect flag */
515 sec_send(s
, sec_flags
);
518 /* Send a control PDU */
520 rdp_send_control(uint16 action
)
524 s
= rdp_init_data(8);
526 out_uint16_le(s
, action
);
527 out_uint16(s
, 0); /* userid */
528 out_uint32(s
, 0); /* control id */
531 rdp_send_data(s
, RDP_DATA_PDU_CONTROL
);
534 /* Send a synchronisation PDU */
536 rdp_send_synchronise(void)
540 s
= rdp_init_data(4);
542 out_uint16_le(s
, 1); /* type */
543 out_uint16_le(s
, 1002);
546 rdp_send_data(s
, RDP_DATA_PDU_SYNCHRONISE
);
549 /* Send a single input event */
551 rdp_send_input(uint32 time
, uint16 message_type
, uint16 device_flags
, uint16 param1
, uint16 param2
)
555 s
= rdp_init_data(16);
557 out_uint16_le(s
, 1); /* number of events */
558 out_uint16(s
, 0); /* pad */
560 out_uint32_le(s
, time
);
561 out_uint16_le(s
, message_type
);
562 out_uint16_le(s
, device_flags
);
563 out_uint16_le(s
, param1
);
564 out_uint16_le(s
, param2
);
567 rdp_send_data(s
, RDP_DATA_PDU_INPUT
);
570 /* Send a client window information PDU */
572 rdp_send_client_window_status(int status
)
575 static int current_status
= 1;
577 if (current_status
== status
)
580 s
= rdp_init_data(12);
582 out_uint32_le(s
, status
);
586 case 0: /* shut the server up */
589 case 1: /* receive data again */
590 out_uint32_le(s
, 0); /* unknown */
591 out_uint16_le(s
, g_width
);
592 out_uint16_le(s
, g_height
);
597 rdp_send_data(s
, RDP_DATA_PDU_CLIENT_WINDOW_STATUS
);
598 current_status
= status
;
601 /* Send persistent bitmap cache enumeration PDU's */
603 rdp_enum_bmpcache2(void)
606 HASH_KEY keylist
[BMPCACHE2_NUM_PSTCELLS
];
607 uint32 num_keys
, offset
, count
, flags
;
610 num_keys
= pstcache_enumerate(2, keylist
);
612 while (offset
< num_keys
)
614 count
= MIN(num_keys
- offset
, 169);
616 s
= rdp_init_data(24 + count
* sizeof(HASH_KEY
));
620 flags
|= PDU_FLAG_FIRST
;
621 if (num_keys
- offset
<= 169)
622 flags
|= PDU_FLAG_LAST
;
626 out_uint16_le(s
, count
);
631 out_uint16_le(s
, num_keys
);
633 out_uint32_le(s
, flags
);
636 out_uint8a(s
, keylist
[offset
], count
* sizeof(HASH_KEY
));
639 rdp_send_data(s
, 0x2b);
645 /* Send an (empty) font information PDU */
647 rdp_send_fonts(uint16 seq
)
651 s
= rdp_init_data(8);
653 out_uint16(s
, 0); /* number of fonts */
654 out_uint16_le(s
, 0); /* pad? */
655 out_uint16_le(s
, seq
); /* unknown */
656 out_uint16_le(s
, 0x32); /* entry size */
659 rdp_send_data(s
, RDP_DATA_PDU_FONT2
);
662 /* Output general capability set */
664 rdp_out_general_caps(STREAM s
)
666 out_uint16_le(s
, RDP_CAPSET_GENERAL
);
667 out_uint16_le(s
, RDP_CAPLEN_GENERAL
);
669 out_uint16_le(s
, 1); /* OS major type */
670 out_uint16_le(s
, 3); /* OS minor type */
671 out_uint16_le(s
, 0x200); /* Protocol version */
672 out_uint16(s
, 0); /* Pad */
673 out_uint16(s
, 0); /* Compression types */
674 out_uint16_le(s
, (g_rdp_version
>= RDP_V5
) ? 0x40d : 0);
675 /* Pad, according to T.128. 0x40d seems to
677 the server to start sending RDP5 packets.
678 However, the value is 0x1d04 with W2KTSK and
679 NT4MS. Hmm.. Anyway, thankyou, Microsoft,
680 for sending such information in a padding
682 out_uint16(s
, 0); /* Update capability */
683 out_uint16(s
, 0); /* Remote unshare capability */
684 out_uint16(s
, 0); /* Compression level */
685 out_uint16(s
, 0); /* Pad */
688 /* Output bitmap capability set */
690 rdp_out_bitmap_caps(STREAM s
)
692 out_uint16_le(s
, RDP_CAPSET_BITMAP
);
693 out_uint16_le(s
, RDP_CAPLEN_BITMAP
);
695 out_uint16_le(s
, g_server_depth
); /* Preferred colour depth */
696 out_uint16_le(s
, 1); /* Receive 1 BPP */
697 out_uint16_le(s
, 1); /* Receive 4 BPP */
698 out_uint16_le(s
, 1); /* Receive 8 BPP */
699 out_uint16_le(s
, 800); /* Desktop width */
700 out_uint16_le(s
, 600); /* Desktop height */
701 out_uint16(s
, 0); /* Pad */
702 out_uint16(s
, 1); /* Allow resize */
703 out_uint16_le(s
, g_bitmap_compression
? 1 : 0); /* Support compression */
704 out_uint16(s
, 0); /* Unknown */
705 out_uint16_le(s
, 1); /* Unknown */
706 out_uint16(s
, 0); /* Pad */
709 /* Output order capability set */
711 rdp_out_order_caps(STREAM s
)
713 uint8 order_caps
[32];
715 memset(order_caps
, 0, 32);
716 order_caps
[0] = 1; /* dest blt */
717 order_caps
[1] = 1; /* pat blt */
718 order_caps
[2] = 1; /* screen blt */
719 order_caps
[3] = (g_bitmap_cache
? 1 : 0); /* memblt */
720 order_caps
[4] = 0; /* triblt */
721 order_caps
[8] = 1; /* line */
722 order_caps
[9] = 1; /* line */
723 order_caps
[10] = 1; /* rect */
724 order_caps
[11] = (g_desktop_save
? 1 : 0); /* desksave */
725 order_caps
[13] = 1; /* memblt */
726 order_caps
[14] = 1; /* triblt */
727 order_caps
[20] = (g_polygon_ellipse_orders
? 1 : 0); /* polygon */
728 order_caps
[21] = (g_polygon_ellipse_orders
? 1 : 0); /* polygon2 */
729 order_caps
[22] = 1; /* polyline */
730 order_caps
[25] = (g_polygon_ellipse_orders
? 1 : 0); /* ellipse */
731 order_caps
[26] = (g_polygon_ellipse_orders
? 1 : 0); /* ellipse2 */
732 order_caps
[27] = 1; /* text2 */
733 out_uint16_le(s
, RDP_CAPSET_ORDER
);
734 out_uint16_le(s
, RDP_CAPLEN_ORDER
);
736 out_uint8s(s
, 20); /* Terminal desc, pad */
737 out_uint16_le(s
, 1); /* Cache X granularity */
738 out_uint16_le(s
, 20); /* Cache Y granularity */
739 out_uint16(s
, 0); /* Pad */
740 out_uint16_le(s
, 1); /* Max order level */
741 out_uint16_le(s
, 0x147); /* Number of fonts */
742 out_uint16_le(s
, 0x2a); /* Capability flags */
743 out_uint8p(s
, order_caps
, 32); /* Orders supported */
744 out_uint16_le(s
, 0x6a1); /* Text capability flags */
745 out_uint8s(s
, 6); /* Pad */
746 out_uint32_le(s
, g_desktop_save
== False
? 0 : 0x38400); /* Desktop cache size */
747 out_uint32(s
, 0); /* Unknown */
748 out_uint32_le(s
, 0x4e4); /* Unknown */
751 /* Output bitmap cache capability set */
753 rdp_out_bmpcache_caps(STREAM s
)
756 out_uint16_le(s
, RDP_CAPSET_BMPCACHE
);
757 out_uint16_le(s
, RDP_CAPLEN_BMPCACHE
);
759 Bpp
= (g_server_depth
+ 7) / 8; /* bytes per pixel */
760 out_uint8s(s
, 24); /* unused */
761 out_uint16_le(s
, 0x258); /* entries */
762 out_uint16_le(s
, 0x100 * Bpp
); /* max cell size */
763 out_uint16_le(s
, 0x12c); /* entries */
764 out_uint16_le(s
, 0x400 * Bpp
); /* max cell size */
765 out_uint16_le(s
, 0x106); /* entries */
766 out_uint16_le(s
, 0x1000 * Bpp
); /* max cell size */
769 /* Output bitmap cache v2 capability set */
771 rdp_out_bmpcache2_caps(STREAM s
)
773 out_uint16_le(s
, RDP_CAPSET_BMPCACHE2
);
774 out_uint16_le(s
, RDP_CAPLEN_BMPCACHE2
);
776 out_uint16_le(s
, g_bitmap_cache_persist_enable
? 2 : 0); /* version */
778 out_uint16_be(s
, 3); /* number of caches in this set */
780 /* max cell size for cache 0 is 16x16, 1 = 32x32, 2 = 64x64, etc */
781 out_uint32_le(s
, BMPCACHE2_C0_CELLS
);
782 out_uint32_le(s
, BMPCACHE2_C1_CELLS
);
783 if (pstcache_init(2))
785 out_uint32_le(s
, BMPCACHE2_NUM_PSTCELLS
| BMPCACHE2_FLAG_PERSIST
);
789 out_uint32_le(s
, BMPCACHE2_C2_CELLS
);
791 out_uint8s(s
, 20); /* other bitmap caches not used */
794 /* Output control capability set */
796 rdp_out_control_caps(STREAM s
)
798 out_uint16_le(s
, RDP_CAPSET_CONTROL
);
799 out_uint16_le(s
, RDP_CAPLEN_CONTROL
);
801 out_uint16(s
, 0); /* Control capabilities */
802 out_uint16(s
, 0); /* Remote detach */
803 out_uint16_le(s
, 2); /* Control interest */
804 out_uint16_le(s
, 2); /* Detach interest */
807 /* Output activation capability set */
809 rdp_out_activate_caps(STREAM s
)
811 out_uint16_le(s
, RDP_CAPSET_ACTIVATE
);
812 out_uint16_le(s
, RDP_CAPLEN_ACTIVATE
);
814 out_uint16(s
, 0); /* Help key */
815 out_uint16(s
, 0); /* Help index key */
816 out_uint16(s
, 0); /* Extended help key */
817 out_uint16(s
, 0); /* Window activate */
820 /* Output pointer capability set */
822 rdp_out_pointer_caps(STREAM s
)
824 out_uint16_le(s
, RDP_CAPSET_POINTER
);
825 out_uint16_le(s
, RDP_CAPLEN_POINTER
);
827 out_uint16(s
, 0); /* Colour pointer */
828 out_uint16_le(s
, 20); /* Cache size */
831 /* Output new pointer capability set */
833 rdp_out_newpointer_caps(STREAM s
)
835 out_uint16_le(s
, RDP_CAPSET_POINTER
);
836 out_uint16_le(s
, RDP_CAPLEN_NEWPOINTER
);
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 */
843 /* Output share capability set */
845 rdp_out_share_caps(STREAM s
)
847 out_uint16_le(s
, RDP_CAPSET_SHARE
);
848 out_uint16_le(s
, RDP_CAPLEN_SHARE
);
850 out_uint16(s
, 0); /* userid */
851 out_uint16(s
, 0); /* pad */
854 /* Output colour cache capability set */
856 rdp_out_colcache_caps(STREAM s
)
858 out_uint16_le(s
, RDP_CAPSET_COLCACHE
);
859 out_uint16_le(s
, RDP_CAPLEN_COLCACHE
);
861 out_uint16_le(s
, 6); /* cache size */
862 out_uint16(s
, 0); /* pad */
865 /* Output brush cache capability set */
867 rdp_out_brushcache_caps(STREAM s
)
869 out_uint16_le(s
, RDP_CAPSET_BRUSHCACHE
);
870 out_uint16_le(s
, RDP_CAPLEN_BRUSHCACHE
);
871 out_uint32_le(s
, 1); /* cache type */
874 static uint8 caps_0x0d
[] = {
875 0x01, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00,
876 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
877 0x0C, 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, 0x00, 0x00, 0x00, 0x00,
885 0x00, 0x00, 0x00, 0x00
888 static uint8 caps_0x0c
[] = { 0x01, 0x00, 0x00, 0x00 };
890 static uint8 caps_0x0e
[] = { 0x01, 0x00, 0x00, 0x00 };
892 static uint8 caps_0x10
[] = {
893 0xFE, 0x00, 0x04, 0x00, 0xFE, 0x00, 0x04, 0x00,
894 0xFE, 0x00, 0x08, 0x00, 0xFE, 0x00, 0x08, 0x00,
895 0xFE, 0x00, 0x10, 0x00, 0xFE, 0x00, 0x20, 0x00,
896 0xFE, 0x00, 0x40, 0x00, 0xFE, 0x00, 0x80, 0x00,
897 0xFE, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x08,
898 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00
901 /* Output unknown capability sets */
903 rdp_out_unknown_caps(STREAM s
, uint16 id
, uint16 length
, uint8
* caps
)
905 out_uint16_le(s
, id
);
906 out_uint16_le(s
, length
);
908 out_uint8p(s
, caps
, length
- 4);
911 #define RDP5_FLAG 0x0030
912 /* Send a confirm active PDU */
914 rdp_send_confirm_active(void)
917 uint32 sec_flags
= g_encryption
? (RDP5_FLAG
| SEC_ENCRYPT
) : RDP5_FLAG
;
919 RDP_CAPLEN_GENERAL
+ RDP_CAPLEN_BITMAP
+ RDP_CAPLEN_ORDER
+
920 RDP_CAPLEN_COLCACHE
+
921 RDP_CAPLEN_ACTIVATE
+ RDP_CAPLEN_CONTROL
+
923 RDP_CAPLEN_BRUSHCACHE
+ 0x58 + 0x08 + 0x08 + 0x34 /* unknown caps */ +
924 4 /* w2k fix, sessionid */ ;
926 if (g_rdp_version
>= RDP_V5
)
928 caplen
+= RDP_CAPLEN_BMPCACHE2
;
929 caplen
+= RDP_CAPLEN_NEWPOINTER
;
933 caplen
+= RDP_CAPLEN_BMPCACHE
;
934 caplen
+= RDP_CAPLEN_POINTER
;
937 s
= sec_init(sec_flags
, 6 + 14 + caplen
+ sizeof(RDP_SOURCE
));
939 out_uint16_le(s
, 2 + 14 + caplen
+ sizeof(RDP_SOURCE
));
940 out_uint16_le(s
, (RDP_PDU_CONFIRM_ACTIVE
| 0x10)); /* Version 1 */
941 out_uint16_le(s
, (g_mcs_userid
+ 1001));
943 out_uint32_le(s
, g_rdp_shareid
);
944 out_uint16_le(s
, 0x3ea); /* userid */
945 out_uint16_le(s
, sizeof(RDP_SOURCE
));
946 out_uint16_le(s
, caplen
);
948 out_uint8p(s
, RDP_SOURCE
, sizeof(RDP_SOURCE
));
949 out_uint16_le(s
, 0xe); /* num_caps */
950 out_uint8s(s
, 2); /* pad */
952 rdp_out_general_caps(s
);
953 rdp_out_bitmap_caps(s
);
954 rdp_out_order_caps(s
);
955 if (g_rdp_version
>= RDP_V5
)
957 rdp_out_bmpcache2_caps(s
);
958 rdp_out_newpointer_caps(s
);
962 rdp_out_bmpcache_caps(s
);
963 rdp_out_pointer_caps(s
);
965 rdp_out_colcache_caps(s
);
966 rdp_out_activate_caps(s
);
967 rdp_out_control_caps(s
);
968 rdp_out_share_caps(s
);
969 rdp_out_brushcache_caps(s
);
971 rdp_out_unknown_caps(s
, 0x0d, 0x58, caps_0x0d
); /* CAPSTYPE_INPUT */
972 rdp_out_unknown_caps(s
, 0x0c, 0x08, caps_0x0c
); /* CAPSTYPE_SOUND */
973 rdp_out_unknown_caps(s
, 0x0e, 0x08, caps_0x0e
); /* CAPSTYPE_FONT */
974 rdp_out_unknown_caps(s
, 0x10, 0x34, caps_0x10
); /* CAPSTYPE_GLYPHCACHE */
977 sec_send(s
, sec_flags
);
980 /* Process a general capability set */
982 rdp_process_general_caps(STREAM s
)
984 uint16 pad2octetsB
; /* rdp5 flags? */
987 in_uint16_le(s
, pad2octetsB
);
990 g_rdp_version
= RDP_V4
;
993 /* Process a bitmap capability set */
995 rdp_process_bitmap_caps(STREAM s
)
997 uint16 width
, height
, depth
;
999 in_uint16_le(s
, depth
);
1002 in_uint16_le(s
, width
);
1003 in_uint16_le(s
, height
);
1005 DEBUG(("setting desktop size and depth to: %dx%dx%d\n", width
, height
, depth
));
1008 * The server may limit depth and change the size of the desktop (for
1009 * example when shadowing another session).
1011 if (g_server_depth
!= depth
)
1013 warning("Remote desktop does not support colour depth %d; falling back to %d\n",
1014 g_server_depth
, depth
);
1015 g_server_depth
= depth
;
1017 if (g_width
!= width
|| g_height
!= height
)
1019 warning("Remote desktop changed from %dx%d to %dx%d.\n", g_width
, g_height
,
1027 /* Process server capabilities */
1029 rdp_process_server_caps(STREAM s
, uint16 length
)
1032 uint8
*next
, *start
;
1033 uint16 ncapsets
, capset_type
, capset_length
;
1037 in_uint16_le(s
, ncapsets
);
1038 in_uint8s(s
, 2); /* pad */
1040 for (n
= 0; n
< ncapsets
; n
++)
1042 if (s
->p
> start
+ length
)
1045 in_uint16_le(s
, capset_type
);
1046 in_uint16_le(s
, capset_length
);
1048 next
= s
->p
+ capset_length
- 4;
1050 switch (capset_type
)
1052 case RDP_CAPSET_GENERAL
:
1053 rdp_process_general_caps(s
);
1056 case RDP_CAPSET_BITMAP
:
1057 rdp_process_bitmap_caps(s
);
1065 /* Respond to a demand active PDU */
1067 process_demand_active(STREAM s
)
1070 uint16 len_src_descriptor
, len_combined_caps
;
1072 in_uint32_le(s
, g_rdp_shareid
);
1073 in_uint16_le(s
, len_src_descriptor
);
1074 in_uint16_le(s
, len_combined_caps
);
1075 in_uint8s(s
, len_src_descriptor
);
1077 DEBUG(("DEMAND_ACTIVE(id=0x%x)\n", g_rdp_shareid
));
1078 rdp_process_server_caps(s
, len_combined_caps
);
1080 rdp_send_confirm_active();
1081 rdp_send_synchronise();
1082 rdp_send_control(RDP_CTL_COOPERATE
);
1083 rdp_send_control(RDP_CTL_REQUEST_CONTROL
);
1084 rdp_recv(&type
); /* RDP_PDU_SYNCHRONIZE */
1085 rdp_recv(&type
); /* RDP_CTL_COOPERATE */
1086 rdp_recv(&type
); /* RDP_CTL_GRANT_CONTROL */
1087 rdp_send_input(0, RDP_INPUT_SYNCHRONIZE
, 0,
1088 g_numlock_sync
? ui_get_numlock_state(read_keyboard_state()) : 0, 0);
1090 if (g_rdp_version
>= RDP_V5
)
1092 rdp_enum_bmpcache2();
1101 rdp_recv(&type
); /* RDP_PDU_UNKNOWN 0x28 (Fonts?) */
1102 reset_order_state();
1105 /* Process a colour pointer PDU */
1107 process_colour_pointer_common(STREAM s
, int bpp
)
1109 uint16 width
, height
, cache_idx
, masklen
, datalen
;
1115 in_uint16_le(s
, cache_idx
);
1118 in_uint16_le(s
, width
);
1119 in_uint16_le(s
, height
);
1120 in_uint16_le(s
, masklen
);
1121 in_uint16_le(s
, datalen
);
1122 in_uint8p(s
, data
, datalen
);
1123 in_uint8p(s
, mask
, masklen
);
1124 if ((width
!= 32) || (height
!= 32))
1126 warning("process_colour_pointer_common: " "width %d height %d\n", width
, height
);
1129 /* keep hotspot within cursor bounding box */
1130 x
= MIN(x
, width
- 1);
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
);
1137 /* Process a colour pointer PDU */
1139 process_colour_pointer_pdu(STREAM s
)
1141 process_colour_pointer_common(s
, 24);
1144 /* Process a New Pointer PDU - these pointers have variable bit depth */
1146 process_new_pointer_pdu(STREAM s
)
1150 in_uint16_le(s
, xor_bpp
);
1151 process_colour_pointer_common(s
, xor_bpp
);
1154 /* Process a cached pointer PDU */
1156 process_cached_pointer_pdu(STREAM s
)
1160 in_uint16_le(s
, cache_idx
);
1161 ui_set_cursor(cache_get_cursor(cache_idx
));
1164 /* Process a system pointer PDU */
1166 process_system_pointer_pdu(STREAM s
)
1168 uint16 system_pointer_type
;
1170 in_uint16_le(s
, system_pointer_type
);
1171 switch (system_pointer_type
)
1173 case RDP_NULL_POINTER
:
1174 ui_set_null_cursor();
1178 unimpl("System pointer message 0x%x\n", system_pointer_type
);
1182 /* Process a pointer PDU */
1184 process_pointer_pdu(STREAM s
)
1186 uint16 message_type
;
1189 in_uint16_le(s
, message_type
);
1190 in_uint8s(s
, 2); /* pad */
1192 switch (message_type
)
1194 case RDP_POINTER_MOVE
:
1198 ui_move_pointer(x
, y
);
1201 case RDP_POINTER_COLOR
:
1202 process_colour_pointer_pdu(s
);
1205 case RDP_POINTER_CACHED
:
1206 process_cached_pointer_pdu(s
);
1209 case RDP_POINTER_SYSTEM
:
1210 process_system_pointer_pdu(s
);
1213 case RDP_POINTER_NEW
:
1214 process_new_pointer_pdu(s
);
1218 unimpl("Pointer message 0x%x\n", message_type
);
1222 /* Process bitmap updates */
1224 process_bitmap_updates(STREAM s
)
1227 uint16 left
, top
, right
, bottom
, width
, height
;
1228 uint16 cx
, cy
, bpp
, Bpp
, compress
, bufsize
, size
;
1229 uint8
*data
, *bmpdata
;
1232 in_uint16_le(s
, num_updates
);
1234 for (i
= 0; i
< num_updates
; i
++)
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
);
1247 cx
= right
- left
+ 1;
1248 cy
= bottom
- top
+ 1;
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
));
1256 bmpdata
= (uint8
*) xmalloc(width
* height
* Bpp
);
1257 for (y
= 0; y
< height
; y
++)
1259 in_uint8a(s
, &bmpdata
[(height
- y
- 1) * (width
* Bpp
)],
1262 ui_paint_bitmap(left
, top
, cx
, cy
, width
, height
, bmpdata
);
1268 if (compress
& 0x400)
1274 in_uint8s(s
, 2); /* pad */
1275 in_uint16_le(s
, size
);
1276 in_uint8s(s
, 4); /* line_size, final_size */
1278 in_uint8p(s
, data
, size
);
1279 bmpdata
= (uint8
*) xmalloc(width
* height
* Bpp
);
1280 if (bitmap_decompress(bmpdata
, width
, height
, data
, size
, Bpp
))
1282 ui_paint_bitmap(left
, top
, cx
, cy
, width
, height
, bmpdata
);
1286 DEBUG_RDP5(("Failed to decompress data\n"));
1293 /* Process a palette update */
1295 process_palette(STREAM s
)
1302 in_uint8s(s
, 2); /* pad */
1303 in_uint16_le(s
, map
.ncolours
);
1304 in_uint8s(s
, 2); /* pad */
1306 map
.colours
= (COLOURENTRY
*) xmalloc(sizeof(COLOURENTRY
) * map
.ncolours
);
1308 DEBUG(("PALETTE(c=%d)\n", map
.ncolours
));
1310 for (i
= 0; i
< map
.ncolours
; i
++)
1312 entry
= &map
.colours
[i
];
1313 in_uint8(s
, entry
->red
);
1314 in_uint8(s
, entry
->green
);
1315 in_uint8(s
, entry
->blue
);
1318 hmap
= ui_create_colourmap(&map
);
1319 ui_set_colourmap(hmap
);
1324 /* Process an update PDU */
1326 process_update_pdu(STREAM s
)
1328 uint16 update_type
, count
;
1330 in_uint16_le(s
, update_type
);
1333 switch (update_type
)
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
);
1342 case RDP_UPDATE_BITMAP
:
1343 process_bitmap_updates(s
);
1346 case RDP_UPDATE_PALETTE
:
1350 case RDP_UPDATE_SYNCHRONIZE
:
1354 unimpl("update %d\n", update_type
);
1360 /* Process a Save Session Info PDU */
1362 process_pdu_logon(STREAM s
)
1365 in_uint32_le(s
, infotype
);
1366 if (infotype
== INFOTYPE_LOGON_EXTENDED_INF
)
1368 uint32 fieldspresent
;
1370 in_uint8s(s
, 2); /* Length */
1371 in_uint32_le(s
, fieldspresent
);
1372 if (fieldspresent
& LOGON_EX_AUTORECONNECTCOOKIE
)
1377 /* TS_LOGON_INFO_FIELD */
1378 in_uint8s(s
, 4); /* cbFieldData */
1380 /* ARC_SC_PRIVATE_PACKET */
1381 in_uint32_le(s
, len
);
1384 warning("Invalid length in Auto-Reconnect packet\n");
1388 in_uint32_le(s
, version
);
1391 warning("Unsupported version of Auto-Reconnect packet\n");
1395 in_uint32_le(s
, g_reconnect_logonid
);
1396 in_uint8a(s
, g_reconnect_random
, 16);
1397 g_has_reconnect_random
= True
;
1398 g_reconnect_random_ts
= time(NULL
);
1399 DEBUG(("Saving auto-reconnect cookie, id=%u\n", g_reconnect_logonid
));
1405 /* Process a disconnect PDU */
1407 process_disconnect_pdu(STREAM s
, uint32
* ext_disc_reason
)
1409 in_uint32_le(s
, *ext_disc_reason
);
1411 DEBUG(("Received disconnect PDU\n"));
1414 /* Process data PDU */
1416 process_data_pdu(STREAM s
, uint32
* ext_disc_reason
)
1418 uint8 data_pdu_type
;
1425 struct stream
*ns
= &(g_mppc_dict
.ns
);
1427 in_uint8s(s
, 6); /* shareid, pad, streamid */
1428 in_uint16_le(s
, len
);
1429 in_uint8(s
, data_pdu_type
);
1431 in_uint16_le(s
, clen
);
1434 if (ctype
& RDP_MPPC_COMPRESSED
)
1436 if (len
> RDP_MPPC_DICT_SIZE
)
1437 error("error decompressed packet size exceeds max\n");
1438 if (mppc_expand(s
->p
, clen
, ctype
, &roff
, &rlen
) == -1)
1439 error("error while decompressing packet\n");
1443 /* allocate memory and copy the uncompressed data into the temporary stream */
1444 ns
->data
= (uint8
*) xrealloc(ns
->data
, rlen
);
1446 memcpy((ns
->data
), (unsigned char *) (g_mppc_dict
.hist
+ roff
), rlen
);
1449 ns
->end
= (ns
->data
+ ns
->size
);
1451 ns
->rdp_hdr
= ns
->p
;
1456 switch (data_pdu_type
)
1458 case RDP_DATA_PDU_UPDATE
:
1459 process_update_pdu(s
);
1462 case RDP_DATA_PDU_CONTROL
:
1463 DEBUG(("Received Control PDU\n"));
1466 case RDP_DATA_PDU_SYNCHRONISE
:
1467 DEBUG(("Received Sync PDU\n"));
1470 case RDP_DATA_PDU_POINTER
:
1471 process_pointer_pdu(s
);
1474 case RDP_DATA_PDU_BELL
:
1478 case RDP_DATA_PDU_LOGON
:
1479 DEBUG(("Received Logon PDU\n"));
1480 /* User logged on */
1481 process_pdu_logon(s
);
1484 case RDP_DATA_PDU_DISCONNECT
:
1485 process_disconnect_pdu(s
, ext_disc_reason
);
1487 /* We used to return true and disconnect immediately here, but
1488 * Windows Vista sends a disconnect PDU with reason 0 when
1489 * reconnecting to a disconnected session, and MSTSC doesn't
1490 * drop the connection. I think we should just save the status.
1494 case RDP_DATA_PDU_AUTORECONNECT_STATUS
:
1495 warning("Automatic reconnect using cookie, failed.\n");
1499 unimpl("data PDU %d\n", data_pdu_type
);
1504 /* Process redirect PDU from Session Directory */
1506 process_redirect_pdu(STREAM s
, RD_BOOL enhanced_redirect
/*, uint32 * ext_disc_reason */ )
1509 uint16 redirect_identifier
;
1511 /* reset any previous redirection information */
1513 free(g_redirect_server
);
1514 free(g_redirect_username
);
1515 free(g_redirect_domain
);
1516 free(g_redirect_lb_info
);
1517 free(g_redirect_cookie
);
1519 g_redirect_server
= NULL
;
1520 g_redirect_username
= NULL
;
1521 g_redirect_domain
= NULL
;
1522 g_redirect_lb_info
= NULL
;
1523 g_redirect_cookie
= NULL
;
1525 /* these 2 bytes are unknown, seem to be zeros */
1528 /* FIXME: Previous implementation only reads 4 bytes which has been working
1529 but todays spec says something different. Investigate and retest
1530 server redirection using WTS 2003 cluster.
1533 if (enhanced_redirect
)
1535 /* read identifier */
1536 in_uint16_le(s
, redirect_identifier
);
1537 if (redirect_identifier
!= 0x0400)
1538 error("Protocol error in server redirection, unexpected data.");
1540 /* FIXME: skip total length */
1543 /* read session_id */
1544 in_uint32_le(s
, g_redirect_session_id
);
1547 /* read connection flags */
1548 in_uint32_le(s
, g_redirect_flags
);
1550 if (g_redirect_flags
& PDU_REDIRECT_HAS_IP
)
1552 /* read length of ip string */
1553 in_uint32_le(s
, len
);
1555 /* read ip string */
1556 rdp_in_unistr(s
, len
, &g_redirect_server
, &g_redirect_server_len
);
1559 if (g_redirect_flags
& PDU_REDIRECT_HAS_LOAD_BALANCE_INFO
)
1561 /* read length of load balance info blob */
1562 in_uint32_le(s
, g_redirect_lb_info_len
);
1564 /* reallocate a loadbalance info blob */
1565 if (g_redirect_lb_info
!= NULL
)
1566 free(g_redirect_lb_info
);
1568 g_redirect_lb_info
= xmalloc(g_redirect_lb_info_len
);
1570 /* read load balance info blob */
1571 in_uint8p(s
, g_redirect_lb_info
, g_redirect_lb_info_len
);
1574 if (g_redirect_flags
& PDU_REDIRECT_HAS_USERNAME
)
1576 /* read length of username string */
1577 in_uint32_le(s
, len
);
1579 /* read username string */
1580 rdp_in_unistr(s
, len
, &g_redirect_username
, &g_redirect_username_len
);
1583 if (g_redirect_flags
& PDU_REDIRECT_HAS_DOMAIN
)
1585 /* read length of domain string */
1586 in_uint32_le(s
, len
);
1588 /* read domain string */
1589 rdp_in_unistr(s
, len
, &g_redirect_domain
, &g_redirect_domain_len
);
1592 if (g_redirect_flags
& PDU_REDIRECT_HAS_PASSWORD
)
1594 /* the information in this blob is either a password or a cookie that
1595 should be passed though as blob and not parsed as a unicode string */
1597 /* read blob length */
1598 in_uint32_le(s
, g_redirect_cookie_len
);
1600 /* reallocate cookie blob */
1601 if (g_redirect_cookie
!= NULL
)
1602 free(g_redirect_cookie
);
1604 g_redirect_cookie
= xmalloc(g_redirect_cookie_len
);
1606 /* read cookie as is */
1607 in_uint8p(s
, g_redirect_cookie
, g_redirect_cookie_len
);
1610 if (g_redirect_flags
& PDU_REDIRECT_DONT_STORE_USERNAME
)
1612 warning("PDU_REDIRECT_DONT_STORE_USERNAME set\n");
1615 if (g_redirect_flags
& PDU_REDIRECT_USE_SMARTCARD
)
1617 warning("PDU_REDIRECT_USE_SMARTCARD set\n");
1620 if (g_redirect_flags
& PDU_REDIRECT_INFORMATIONAL
)
1622 /* By spec this is only for information and doesn't mean that an actual
1623 redirect should be performed. How it should be used is not mentioned. */
1627 if (g_redirect_flags
& PDU_REDIRECT_HAS_TARGET_FQDN
)
1629 in_uint32_le(s
, len
);
1631 /* Let target fqdn replace target ip address */
1632 if (g_redirect_server
)
1634 free(g_redirect_server
);
1635 g_redirect_server
= NULL
;
1638 /* read fqdn string */
1639 rdp_in_unistr(s
, len
, &g_redirect_server
, &g_redirect_server_len
);
1642 if (g_redirect_flags
& PDU_REDIRECT_HAS_TARGET_NETBIOS
)
1644 warning("PDU_REDIRECT_HAS_TARGET_NETBIOS set\n");
1647 if (g_redirect_flags
& PDU_REDIRECT_HAS_TARGET_IP_ARRAY
)
1649 warning("PDU_REDIRECT_HAS_TARGET_IP_ARRAY set\n");
1655 /* Process incoming packets */
1657 rdp_main_loop(RD_BOOL
* deactivated
, uint32
* ext_disc_reason
)
1659 while (rdp_loop(deactivated
, ext_disc_reason
))
1661 if (g_pending_resize
|| g_redirect
)
1668 /* used in uiports and rdp_main_loop, processes the rdp packets waiting */
1670 rdp_loop(RD_BOOL
* deactivated
, uint32
* ext_disc_reason
)
1673 RD_BOOL cont
= True
;
1678 s
= rdp_recv(&type
);
1683 case RDP_PDU_DEMAND_ACTIVE
:
1684 process_demand_active(s
);
1685 *deactivated
= False
;
1687 case RDP_PDU_DEACTIVATE
:
1688 DEBUG(("RDP_PDU_DEACTIVATE\n"));
1689 *deactivated
= True
;
1691 case RDP_PDU_REDIRECT
:
1692 return process_redirect_pdu(s
, False
);
1694 case RDP_PDU_ENHANCED_REDIRECT
:
1695 return process_redirect_pdu(s
, True
);
1698 /* If we got a data PDU, we don't need to keep the password in memory
1699 anymore and therefor we should clear it for security reasons. */
1700 if (g_password
[0] != '\0')
1701 memset(g_password
, 0, sizeof(g_password
));
1703 process_data_pdu(s
, ext_disc_reason
);
1708 unimpl("PDU %d\n", type
);
1710 cont
= g_next_packet
< s
->end
;
1715 /* Establish a connection up to the RDP layer */
1717 rdp_connect(char *server
, uint32 flags
, char *domain
, char *password
,
1718 char *command
, char *directory
, RD_BOOL reconnect
)
1720 RD_BOOL deactivated
= False
;
1721 uint32 ext_disc_reason
= 0;
1723 if (!sec_connect(server
, g_username
, domain
, password
, reconnect
))
1726 rdp_send_logon_info(flags
, domain
, g_username
, password
, command
, directory
);
1728 /* run RDP loop until first licence demand active PDU */
1729 while (!g_rdp_shareid
)
1731 if (g_network_error
)
1734 if (!rdp_loop(&deactivated
, &ext_disc_reason
))
1743 /* Called during redirection to reset the state to support redirection */
1745 rdp_reset_state(void)
1747 g_next_packet
= NULL
; /* reset the packet information */
1752 /* Disconnect from the RDP layer */
1754 rdp_disconnect(void)