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 rdssl_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 with mandatory null termination. If
175 string is NULL or len is 0, write an unicode null termination to
178 rdp_out_unistr_mandatory_null(STREAM s
, char *string
, int len
)
180 if (string
&& len
> 0)
181 rdp_out_unistr(s
, string
, len
);
186 /* Output a string in Unicode */
188 rdp_out_unistr(STREAM s
, char *string
, int len
)
190 if (string
== NULL
|| len
== 0)
194 size_t ibl
= strlen(string
), obl
= len
+ 2;
195 static iconv_t iconv_h
= (iconv_t
) - 1;
196 char *pin
= string
, *pout
= (char *) s
->p
;
198 memset(pout
, 0, len
+ 4);
202 if (iconv_h
== (iconv_t
) - 1)
205 if ((iconv_h
= iconv_open(WINDOWS_CODEPAGE
, g_codepage
)) == (iconv_t
) - 1)
207 warning("rdp_out_unistr: iconv_open[%s -> %s] fail %d\n",
208 g_codepage
, WINDOWS_CODEPAGE
, (int) iconv_h
);
210 g_iconv_works
= False
;
211 rdp_out_unistr(s
, string
, len
);
214 if (iconv(iconv_h
, (ICONV_CONST
char **) &pin
, &i
, &pout
, &o
) ==
217 iconv_close(iconv_h
);
218 iconv_h
= (iconv_t
) - 1;
219 warning("rdp_out_unistr: iconv(1) fail, errno %d\n", errno
);
221 g_iconv_works
= False
;
222 rdp_out_unistr(s
, string
, len
);
226 pout
= (char *) s
->p
;
229 if (iconv(iconv_h
, (ICONV_CONST
char **) &pin
, &ibl
, &pout
, &obl
) == (size_t) - 1)
231 iconv_close(iconv_h
);
232 iconv_h
= (iconv_t
) - 1;
233 warning("rdp_out_unistr: iconv(2) fail, errno %d\n", errno
);
235 g_iconv_works
= False
;
236 rdp_out_unistr(s
, string
, len
);
252 s
->p
[i
++] = string
[j
++];
260 /* Input a string in Unicode
262 * Returns str_len of string
265 rdp_in_unistr(STREAM s
, int in_len
, char **string
, uint32
* str_size
)
267 /* Dynamic allocate of destination string if not provided */
268 *string
= xmalloc(in_len
* 2);
269 *str_size
= in_len
* 2;
272 size_t ibl
= in_len
, obl
= *str_size
- 1;
273 char *pin
= (char *) s
->p
, *pout
= *string
;
274 static iconv_t iconv_h
= (iconv_t
) - 1;
278 if (iconv_h
== (iconv_t
) - 1)
280 if ((iconv_h
= iconv_open(g_codepage
, WINDOWS_CODEPAGE
)) == (iconv_t
) - 1)
282 warning("rdp_in_unistr: iconv_open[%s -> %s] fail %d\n",
283 WINDOWS_CODEPAGE
, g_codepage
, (int) iconv_h
);
285 g_iconv_works
= False
;
286 return rdp_in_unistr(s
, in_len
, string
, str_size
);
290 if (iconv(iconv_h
, (ICONV_CONST
char **) &pin
, &ibl
, &pout
, &obl
) == (size_t) - 1)
294 warning("server sent an unexpectedly long string, truncating\n");
298 warning("rdp_in_unistr: iconv fail, errno %d\n", errno
);
306 /* we must update the location of the current STREAM for future reads of s->p */
312 *str_size
= pout
- *string
;
319 uint32 len
= in_len
/ 2;
321 if (len
> *str_size
- 1)
323 warning("server sent an unexpectedly long string, truncating\n");
325 rem
= in_len
- 2 * len
;
330 in_uint8a(s
, &string
[i
++], 1);
341 /* Parse a logon info packet */
343 rdp_send_logon_info(uint32 flags
, char *domain
, char *user
,
344 char *password
, char *program
, char *directory
)
346 char *ipaddr
= tcp_get_address();
347 /* length of string in TS_INFO_PACKET excludes null terminator */
348 int len_domain
= 2 * strlen(domain
);
349 int len_user
= 2 * strlen(user
);
350 int len_password
= 2 * strlen(password
);
351 int len_program
= 2 * strlen(program
);
352 int len_directory
= 2 * strlen(directory
);
354 /* length of strings in TS_EXTENDED_PACKET includes null terminator */
355 int len_ip
= 2 * strlen(ipaddr
) + 2;
356 int len_dll
= 2 * strlen("C:\\") + 2;
359 uint32 sec_flags
= g_encryption
? (SEC_INFO_PKT
| SEC_ENCRYPT
) : SEC_INFO_PKT
;
361 time_t t
= time(NULL
);
363 uint8 security_verifier
[16];
365 if (g_rdp_version
== RDP_V4
|| 1 == g_server_rdp_version
)
367 DEBUG_RDP5(("Sending RDP4-style Logon packet\n"));
369 s
= sec_init(sec_flags
, 18 + len_domain
+ len_user
+ len_password
370 + len_program
+ len_directory
+ 10);
373 out_uint32_le(s
, flags
);
374 out_uint16_le(s
, len_domain
);
375 out_uint16_le(s
, len_user
);
376 out_uint16_le(s
, len_password
);
377 out_uint16_le(s
, len_program
);
378 out_uint16_le(s
, len_directory
);
380 rdp_out_unistr_mandatory_null(s
, domain
, len_domain
);
381 rdp_out_unistr_mandatory_null(s
, user
, len_user
);
382 rdp_out_unistr_mandatory_null(s
, password
, len_password
);
383 rdp_out_unistr_mandatory_null(s
, program
, len_program
);
384 rdp_out_unistr_mandatory_null(s
, directory
, len_directory
);
388 DEBUG_RDP5(("Sending RDP5-style Logon packet\n"));
390 if (g_redirect
== True
&& g_redirect_cookie_len
> 0)
392 flags
|= RDP_INFO_AUTOLOGON
;
393 len_password
= g_redirect_cookie_len
;
394 len_password
-= 2; /* substract 2 bytes which is added below */
398 /* size of TS_INFO_PACKET */
404 2 + /* cbAlternateShell */
405 2 + /* cbWorkingDir */
406 2 + len_domain
+ /* Domain */
407 2 + len_user
+ /* UserName */
408 2 + len_password
+ /* Password */
409 2 + len_program
+ /* AlternateShell */
410 2 + len_directory
+ /* WorkingDir */
411 /* size of TS_EXTENDED_INFO_PACKET */
412 2 + /* clientAddressFamily */
413 2 + /* cbClientAddress */
414 len_ip
+ /* clientAddress */
415 2 + /* cbClientDir */
416 len_dll
+ /* clientDir */
417 /* size of TS_TIME_ZONE_INFORMATION */
418 4 + /* Bias, (UTC = local time + bias */
419 64 + /* StandardName, 32 unicode char array, Descriptive standard time on client */
420 16 + /* StandardDate */
421 4 + /* StandardBias */
422 64 + /* DaylightName, 32 unicode char array */
423 16 + /* DaylightDate */
424 4 + /* DaylightBias */
425 4 + /* clientSessionId */
426 4 + /* performanceFlags */
427 2 + /* cbAutoReconnectCookie, either 0 or 0x001c */
428 /* size of ARC_CS_PRIVATE_PACKET */
429 28; /* autoReconnectCookie */
432 s
= sec_init(sec_flags
, packetlen
);
433 DEBUG_RDP5(("Called sec_init with packetlen %d\n", packetlen
));
436 out_uint32(s
, 0); /* Code Page */
437 out_uint32_le(s
, flags
);
438 out_uint16_le(s
, len_domain
);
439 out_uint16_le(s
, len_user
);
440 out_uint16_le(s
, len_password
);
441 out_uint16_le(s
, len_program
);
442 out_uint16_le(s
, len_directory
);
444 rdp_out_unistr_mandatory_null(s
, domain
, len_domain
);
445 rdp_out_unistr_mandatory_null(s
, user
, len_user
);
447 if (g_redirect
== True
&& 0 < g_redirect_cookie_len
)
449 out_uint8p(s
, g_redirect_cookie
, g_redirect_cookie_len
);
453 rdp_out_unistr_mandatory_null(s
, password
, len_password
);
457 rdp_out_unistr_mandatory_null(s
, program
, len_program
);
458 rdp_out_unistr_mandatory_null(s
, directory
, len_directory
);
460 /* TS_EXTENDED_INFO_PACKET */
461 out_uint16_le(s
, 2); /* clientAddressFamily = AF_INET */
462 out_uint16_le(s
, len_ip
); /* cbClientAddress */
463 rdp_out_unistr_mandatory_null(s
, ipaddr
, len_ip
- 2); /* clientAddress */
464 out_uint16_le(s
, len_dll
); /* cbClientDir */
465 rdp_out_unistr(s
, "C:\\", len_dll
- 2); /* clientDir */
467 /* TS_TIME_ZONE_INFORMATION */
468 tzone
= (mktime(gmtime(&t
)) - mktime(localtime(&t
))) / 60;
469 out_uint32_le(s
, tzone
);
470 rdp_out_unistr(s
, "GTB, normaltid", 2 * strlen("GTB, normaltid"));
471 out_uint8s(s
, 62 - 2 * strlen("GTB, normaltid"));
472 out_uint32_le(s
, 0x0a0000);
473 out_uint32_le(s
, 0x050000);
477 rdp_out_unistr(s
, "GTB, sommartid", 2 * strlen("GTB, sommartid"));
478 out_uint8s(s
, 62 - 2 * strlen("GTB, sommartid"));
479 out_uint32_le(s
, 0x30000);
480 out_uint32_le(s
, 0x050000);
483 out_uint32_le(s
, 0xffffffc4); /* DaylightBias */
485 /* Rest of TS_EXTENDED_INFO_PACKET */
486 out_uint32_le(s
, 0); /* clientSessionId (Ignored by server MUST be 0) */
487 out_uint32_le(s
, g_rdp5_performanceflags
);
489 /* Client Auto-Reconnect */
490 if (g_has_reconnect_random
)
492 out_uint16_le(s
, 28); /* cbAutoReconnectLen */
493 /* ARC_CS_PRIVATE_PACKET */
494 out_uint32_le(s
, 28); /* cbLen */
495 out_uint32_le(s
, 1); /* Version */
496 out_uint32_le(s
, g_reconnect_logonid
); /* LogonId */
497 rdssl_hmac_md5(g_reconnect_random
, sizeof(g_reconnect_random
),
498 (char *)g_client_random
, SEC_RANDOM_SIZE
, (char *)security_verifier
);
499 out_uint8a(s
, security_verifier
, sizeof(security_verifier
));
503 out_uint16_le(s
, 0); /* cbAutoReconnectLen */
508 /* clear the redirect flag */
511 sec_send(s
, sec_flags
);
514 /* Send a control PDU */
516 rdp_send_control(uint16 action
)
520 s
= rdp_init_data(8);
522 out_uint16_le(s
, action
);
523 out_uint16(s
, 0); /* userid */
524 out_uint32(s
, 0); /* control id */
527 rdp_send_data(s
, RDP_DATA_PDU_CONTROL
);
530 /* Send a synchronisation PDU */
532 rdp_send_synchronise(void)
536 s
= rdp_init_data(4);
538 out_uint16_le(s
, 1); /* type */
539 out_uint16_le(s
, 1002);
542 rdp_send_data(s
, RDP_DATA_PDU_SYNCHRONISE
);
545 /* Send a single input event */
547 rdp_send_input(uint32 time
, uint16 message_type
, uint16 device_flags
, uint16 param1
, uint16 param2
)
551 s
= rdp_init_data(16);
553 out_uint16_le(s
, 1); /* number of events */
554 out_uint16(s
, 0); /* pad */
556 out_uint32_le(s
, time
);
557 out_uint16_le(s
, message_type
);
558 out_uint16_le(s
, device_flags
);
559 out_uint16_le(s
, param1
);
560 out_uint16_le(s
, param2
);
563 rdp_send_data(s
, RDP_DATA_PDU_INPUT
);
566 /* Send a client window information PDU */
568 rdp_send_client_window_status(int status
)
571 static int current_status
= 1;
573 if (current_status
== status
)
576 s
= rdp_init_data(12);
578 out_uint32_le(s
, status
);
582 case 0: /* shut the server up */
585 case 1: /* receive data again */
586 out_uint32_le(s
, 0); /* unknown */
587 out_uint16_le(s
, g_width
);
588 out_uint16_le(s
, g_height
);
593 rdp_send_data(s
, RDP_DATA_PDU_CLIENT_WINDOW_STATUS
);
594 current_status
= status
;
597 /* Send persistent bitmap cache enumeration PDU's */
599 rdp_enum_bmpcache2(void)
602 HASH_KEY keylist
[BMPCACHE2_NUM_PSTCELLS
];
603 uint32 num_keys
, offset
, count
, flags
;
606 num_keys
= pstcache_enumerate(2, keylist
);
608 while (offset
< num_keys
)
610 count
= MIN(num_keys
- offset
, 169);
612 s
= rdp_init_data(24 + count
* sizeof(HASH_KEY
));
616 flags
|= PDU_FLAG_FIRST
;
617 if (num_keys
- offset
<= 169)
618 flags
|= PDU_FLAG_LAST
;
622 out_uint16_le(s
, count
);
627 out_uint16_le(s
, num_keys
);
629 out_uint32_le(s
, flags
);
632 out_uint8a(s
, keylist
[offset
], count
* sizeof(HASH_KEY
));
635 rdp_send_data(s
, 0x2b);
641 /* Send an (empty) font information PDU */
643 rdp_send_fonts(uint16 seq
)
647 s
= rdp_init_data(8);
649 out_uint16(s
, 0); /* number of fonts */
650 out_uint16_le(s
, 0); /* pad? */
651 out_uint16_le(s
, seq
); /* unknown */
652 out_uint16_le(s
, 0x32); /* entry size */
655 rdp_send_data(s
, RDP_DATA_PDU_FONT2
);
658 /* Output general capability set */
660 rdp_out_general_caps(STREAM s
)
662 out_uint16_le(s
, RDP_CAPSET_GENERAL
);
663 out_uint16_le(s
, RDP_CAPLEN_GENERAL
);
665 out_uint16_le(s
, 1); /* OS major type */
666 out_uint16_le(s
, 3); /* OS minor type */
667 out_uint16_le(s
, 0x200); /* Protocol version */
668 out_uint16(s
, 0); /* Pad */
669 out_uint16(s
, 0); /* Compression types */
670 out_uint16_le(s
, (g_rdp_version
>= RDP_V5
) ? 0x40d : 0);
671 /* Pad, according to T.128. 0x40d seems to
673 the server to start sending RDP5 packets.
674 However, the value is 0x1d04 with W2KTSK and
675 NT4MS. Hmm.. Anyway, thankyou, Microsoft,
676 for sending such information in a padding
678 out_uint16(s
, 0); /* Update capability */
679 out_uint16(s
, 0); /* Remote unshare capability */
680 out_uint16(s
, 0); /* Compression level */
681 out_uint16(s
, 0); /* Pad */
684 /* Output bitmap capability set */
686 rdp_out_bitmap_caps(STREAM s
)
688 out_uint16_le(s
, RDP_CAPSET_BITMAP
);
689 out_uint16_le(s
, RDP_CAPLEN_BITMAP
);
691 out_uint16_le(s
, g_server_depth
); /* Preferred colour depth */
692 out_uint16_le(s
, 1); /* Receive 1 BPP */
693 out_uint16_le(s
, 1); /* Receive 4 BPP */
694 out_uint16_le(s
, 1); /* Receive 8 BPP */
695 out_uint16_le(s
, 800); /* Desktop width */
696 out_uint16_le(s
, 600); /* Desktop height */
697 out_uint16(s
, 0); /* Pad */
698 out_uint16(s
, 1); /* Allow resize */
699 out_uint16_le(s
, g_bitmap_compression
? 1 : 0); /* Support compression */
700 out_uint16(s
, 0); /* Unknown */
701 out_uint16_le(s
, 1); /* Unknown */
702 out_uint16(s
, 0); /* Pad */
705 /* Output order capability set */
707 rdp_out_order_caps(STREAM s
)
709 uint8 order_caps
[32];
711 memset(order_caps
, 0, 32);
712 order_caps
[0] = 1; /* dest blt */
713 order_caps
[1] = 1; /* pat blt */
714 order_caps
[2] = 1; /* screen blt */
715 order_caps
[3] = (g_bitmap_cache
? 1 : 0); /* memblt */
716 order_caps
[4] = 0; /* triblt */
717 order_caps
[8] = 1; /* line */
718 order_caps
[9] = 1; /* line */
719 order_caps
[10] = 1; /* rect */
720 order_caps
[11] = (g_desktop_save
? 1 : 0); /* desksave */
721 order_caps
[13] = 1; /* memblt */
722 order_caps
[14] = 1; /* triblt */
723 order_caps
[20] = (g_polygon_ellipse_orders
? 1 : 0); /* polygon */
724 order_caps
[21] = (g_polygon_ellipse_orders
? 1 : 0); /* polygon2 */
725 order_caps
[22] = 1; /* polyline */
726 order_caps
[25] = (g_polygon_ellipse_orders
? 1 : 0); /* ellipse */
727 order_caps
[26] = (g_polygon_ellipse_orders
? 1 : 0); /* ellipse2 */
728 order_caps
[27] = 1; /* text2 */
729 out_uint16_le(s
, RDP_CAPSET_ORDER
);
730 out_uint16_le(s
, RDP_CAPLEN_ORDER
);
732 out_uint8s(s
, 20); /* Terminal desc, pad */
733 out_uint16_le(s
, 1); /* Cache X granularity */
734 out_uint16_le(s
, 20); /* Cache Y granularity */
735 out_uint16(s
, 0); /* Pad */
736 out_uint16_le(s
, 1); /* Max order level */
737 out_uint16_le(s
, 0x147); /* Number of fonts */
738 out_uint16_le(s
, 0x2a); /* Capability flags */
739 out_uint8p(s
, order_caps
, 32); /* Orders supported */
740 out_uint16_le(s
, 0x6a1); /* Text capability flags */
741 out_uint8s(s
, 6); /* Pad */
742 out_uint32_le(s
, g_desktop_save
== False
? 0 : 0x38400); /* Desktop cache size */
743 out_uint32(s
, 0); /* Unknown */
744 out_uint32_le(s
, 0x4e4); /* Unknown */
747 /* Output bitmap cache capability set */
749 rdp_out_bmpcache_caps(STREAM s
)
752 out_uint16_le(s
, RDP_CAPSET_BMPCACHE
);
753 out_uint16_le(s
, RDP_CAPLEN_BMPCACHE
);
755 Bpp
= (g_server_depth
+ 7) / 8; /* bytes per pixel */
756 out_uint8s(s
, 24); /* unused */
757 out_uint16_le(s
, 0x258); /* entries */
758 out_uint16_le(s
, 0x100 * Bpp
); /* max cell size */
759 out_uint16_le(s
, 0x12c); /* entries */
760 out_uint16_le(s
, 0x400 * Bpp
); /* max cell size */
761 out_uint16_le(s
, 0x106); /* entries */
762 out_uint16_le(s
, 0x1000 * Bpp
); /* max cell size */
765 /* Output bitmap cache v2 capability set */
767 rdp_out_bmpcache2_caps(STREAM s
)
769 out_uint16_le(s
, RDP_CAPSET_BMPCACHE2
);
770 out_uint16_le(s
, RDP_CAPLEN_BMPCACHE2
);
772 out_uint16_le(s
, g_bitmap_cache_persist_enable
? 2 : 0); /* version */
774 out_uint16_be(s
, 3); /* number of caches in this set */
776 /* max cell size for cache 0 is 16x16, 1 = 32x32, 2 = 64x64, etc */
777 out_uint32_le(s
, BMPCACHE2_C0_CELLS
);
778 out_uint32_le(s
, BMPCACHE2_C1_CELLS
);
779 if (pstcache_init(2))
781 out_uint32_le(s
, BMPCACHE2_NUM_PSTCELLS
| BMPCACHE2_FLAG_PERSIST
);
785 out_uint32_le(s
, BMPCACHE2_C2_CELLS
);
787 out_uint8s(s
, 20); /* other bitmap caches not used */
790 /* Output control capability set */
792 rdp_out_control_caps(STREAM s
)
794 out_uint16_le(s
, RDP_CAPSET_CONTROL
);
795 out_uint16_le(s
, RDP_CAPLEN_CONTROL
);
797 out_uint16(s
, 0); /* Control capabilities */
798 out_uint16(s
, 0); /* Remote detach */
799 out_uint16_le(s
, 2); /* Control interest */
800 out_uint16_le(s
, 2); /* Detach interest */
803 /* Output activation capability set */
805 rdp_out_activate_caps(STREAM s
)
807 out_uint16_le(s
, RDP_CAPSET_ACTIVATE
);
808 out_uint16_le(s
, RDP_CAPLEN_ACTIVATE
);
810 out_uint16(s
, 0); /* Help key */
811 out_uint16(s
, 0); /* Help index key */
812 out_uint16(s
, 0); /* Extended help key */
813 out_uint16(s
, 0); /* Window activate */
816 /* Output pointer capability set */
818 rdp_out_pointer_caps(STREAM s
)
820 out_uint16_le(s
, RDP_CAPSET_POINTER
);
821 out_uint16_le(s
, RDP_CAPLEN_POINTER
);
823 out_uint16(s
, 0); /* Colour pointer */
824 out_uint16_le(s
, 20); /* Cache size */
827 /* Output new pointer capability set */
829 rdp_out_newpointer_caps(STREAM s
)
831 out_uint16_le(s
, RDP_CAPSET_POINTER
);
832 out_uint16_le(s
, RDP_CAPLEN_NEWPOINTER
);
834 out_uint16_le(s
, 1); /* Colour pointer */
835 out_uint16_le(s
, 20); /* Cache size */
836 out_uint16_le(s
, 20); /* Cache size for new pointers */
839 /* Output share capability set */
841 rdp_out_share_caps(STREAM s
)
843 out_uint16_le(s
, RDP_CAPSET_SHARE
);
844 out_uint16_le(s
, RDP_CAPLEN_SHARE
);
846 out_uint16(s
, 0); /* userid */
847 out_uint16(s
, 0); /* pad */
850 /* Output colour cache capability set */
852 rdp_out_colcache_caps(STREAM s
)
854 out_uint16_le(s
, RDP_CAPSET_COLCACHE
);
855 out_uint16_le(s
, RDP_CAPLEN_COLCACHE
);
857 out_uint16_le(s
, 6); /* cache size */
858 out_uint16(s
, 0); /* pad */
861 /* Output brush cache capability set */
863 rdp_out_brushcache_caps(STREAM s
)
865 out_uint16_le(s
, RDP_CAPSET_BRUSHCACHE
);
866 out_uint16_le(s
, RDP_CAPLEN_BRUSHCACHE
);
867 out_uint32_le(s
, 1); /* cache type */
870 static uint8 caps_0x0d
[] = {
871 0x01, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00,
872 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
873 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
874 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
875 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
876 0x00, 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
884 static uint8 caps_0x0c
[] = { 0x01, 0x00, 0x00, 0x00 };
886 static uint8 caps_0x0e
[] = { 0x01, 0x00, 0x00, 0x00 };
888 static uint8 caps_0x10
[] = {
889 0xFE, 0x00, 0x04, 0x00, 0xFE, 0x00, 0x04, 0x00,
890 0xFE, 0x00, 0x08, 0x00, 0xFE, 0x00, 0x08, 0x00,
891 0xFE, 0x00, 0x10, 0x00, 0xFE, 0x00, 0x20, 0x00,
892 0xFE, 0x00, 0x40, 0x00, 0xFE, 0x00, 0x80, 0x00,
893 0xFE, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x08,
894 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00
897 /* Output unknown capability sets */
899 rdp_out_unknown_caps(STREAM s
, uint16 id
, uint16 length
, uint8
* caps
)
901 out_uint16_le(s
, id
);
902 out_uint16_le(s
, length
);
904 out_uint8p(s
, caps
, length
- 4);
907 #define RDP5_FLAG 0x0030
908 /* Send a confirm active PDU */
910 rdp_send_confirm_active(void)
913 uint32 sec_flags
= g_encryption
? (RDP5_FLAG
| SEC_ENCRYPT
) : RDP5_FLAG
;
915 RDP_CAPLEN_GENERAL
+ RDP_CAPLEN_BITMAP
+ RDP_CAPLEN_ORDER
+
916 RDP_CAPLEN_COLCACHE
+
917 RDP_CAPLEN_ACTIVATE
+ RDP_CAPLEN_CONTROL
+
919 RDP_CAPLEN_BRUSHCACHE
+ 0x58 + 0x08 + 0x08 + 0x34 /* unknown caps */ +
920 4 /* w2k fix, sessionid */ ;
922 if (g_rdp_version
>= RDP_V5
)
924 caplen
+= RDP_CAPLEN_BMPCACHE2
;
925 caplen
+= RDP_CAPLEN_NEWPOINTER
;
929 caplen
+= RDP_CAPLEN_BMPCACHE
;
930 caplen
+= RDP_CAPLEN_POINTER
;
933 s
= sec_init(sec_flags
, 6 + 14 + caplen
+ sizeof(RDP_SOURCE
));
935 out_uint16_le(s
, 2 + 14 + caplen
+ sizeof(RDP_SOURCE
));
936 out_uint16_le(s
, (RDP_PDU_CONFIRM_ACTIVE
| 0x10)); /* Version 1 */
937 out_uint16_le(s
, (g_mcs_userid
+ 1001));
939 out_uint32_le(s
, g_rdp_shareid
);
940 out_uint16_le(s
, 0x3ea); /* userid */
941 out_uint16_le(s
, sizeof(RDP_SOURCE
));
942 out_uint16_le(s
, caplen
);
944 out_uint8p(s
, RDP_SOURCE
, sizeof(RDP_SOURCE
));
945 out_uint16_le(s
, 0xe); /* num_caps */
946 out_uint8s(s
, 2); /* pad */
948 rdp_out_general_caps(s
);
949 rdp_out_bitmap_caps(s
);
950 rdp_out_order_caps(s
);
951 if (g_rdp_version
>= RDP_V5
)
953 rdp_out_bmpcache2_caps(s
);
954 rdp_out_newpointer_caps(s
);
958 rdp_out_bmpcache_caps(s
);
959 rdp_out_pointer_caps(s
);
961 rdp_out_colcache_caps(s
);
962 rdp_out_activate_caps(s
);
963 rdp_out_control_caps(s
);
964 rdp_out_share_caps(s
);
965 rdp_out_brushcache_caps(s
);
967 rdp_out_unknown_caps(s
, 0x0d, 0x58, caps_0x0d
); /* CAPSTYPE_INPUT */
968 rdp_out_unknown_caps(s
, 0x0c, 0x08, caps_0x0c
); /* CAPSTYPE_SOUND */
969 rdp_out_unknown_caps(s
, 0x0e, 0x08, caps_0x0e
); /* CAPSTYPE_FONT */
970 rdp_out_unknown_caps(s
, 0x10, 0x34, caps_0x10
); /* CAPSTYPE_GLYPHCACHE */
973 sec_send(s
, sec_flags
);
976 /* Process a general capability set */
978 rdp_process_general_caps(STREAM s
)
980 uint16 pad2octetsB
; /* rdp5 flags? */
983 in_uint16_le(s
, pad2octetsB
);
986 g_rdp_version
= RDP_V4
;
989 /* Process a bitmap capability set */
991 rdp_process_bitmap_caps(STREAM s
)
993 uint16 width
, height
, depth
;
995 in_uint16_le(s
, depth
);
998 in_uint16_le(s
, width
);
999 in_uint16_le(s
, height
);
1001 DEBUG(("setting desktop size and depth to: %dx%dx%d\n", width
, height
, depth
));
1004 * The server may limit depth and change the size of the desktop (for
1005 * example when shadowing another session).
1007 if (g_server_depth
!= depth
)
1009 warning("Remote desktop does not support colour depth %d; falling back to %d\n",
1010 g_server_depth
, depth
);
1011 g_server_depth
= depth
;
1013 if (g_width
!= width
|| g_height
!= height
)
1015 warning("Remote desktop changed from %dx%d to %dx%d.\n", g_width
, g_height
,
1023 /* Process server capabilities */
1025 rdp_process_server_caps(STREAM s
, uint16 length
)
1028 uint8
*next
, *start
;
1029 uint16 ncapsets
, capset_type
, capset_length
;
1033 in_uint16_le(s
, ncapsets
);
1034 in_uint8s(s
, 2); /* pad */
1036 for (n
= 0; n
< ncapsets
; n
++)
1038 if (s
->p
> start
+ length
)
1041 in_uint16_le(s
, capset_type
);
1042 in_uint16_le(s
, capset_length
);
1044 next
= s
->p
+ capset_length
- 4;
1046 switch (capset_type
)
1048 case RDP_CAPSET_GENERAL
:
1049 rdp_process_general_caps(s
);
1052 case RDP_CAPSET_BITMAP
:
1053 rdp_process_bitmap_caps(s
);
1061 /* Respond to a demand active PDU */
1063 process_demand_active(STREAM s
)
1066 uint16 len_src_descriptor
, len_combined_caps
;
1068 in_uint32_le(s
, g_rdp_shareid
);
1069 in_uint16_le(s
, len_src_descriptor
);
1070 in_uint16_le(s
, len_combined_caps
);
1071 in_uint8s(s
, len_src_descriptor
);
1073 DEBUG(("DEMAND_ACTIVE(id=0x%x)\n", g_rdp_shareid
));
1074 rdp_process_server_caps(s
, len_combined_caps
);
1076 rdp_send_confirm_active();
1077 rdp_send_synchronise();
1078 rdp_send_control(RDP_CTL_COOPERATE
);
1079 rdp_send_control(RDP_CTL_REQUEST_CONTROL
);
1080 rdp_recv(&type
); /* RDP_PDU_SYNCHRONIZE */
1081 rdp_recv(&type
); /* RDP_CTL_COOPERATE */
1082 rdp_recv(&type
); /* RDP_CTL_GRANT_CONTROL */
1083 rdp_send_input(0, RDP_INPUT_SYNCHRONIZE
, 0,
1084 g_numlock_sync
? ui_get_numlock_state(read_keyboard_state()) : 0, 0);
1086 if (g_rdp_version
>= RDP_V5
)
1088 rdp_enum_bmpcache2();
1097 rdp_recv(&type
); /* RDP_PDU_UNKNOWN 0x28 (Fonts?) */
1098 reset_order_state();
1101 /* Process a colour pointer PDU */
1103 process_colour_pointer_common(STREAM s
, int bpp
)
1105 uint16 width
, height
, cache_idx
, masklen
, datalen
;
1111 in_uint16_le(s
, cache_idx
);
1114 in_uint16_le(s
, width
);
1115 in_uint16_le(s
, height
);
1116 in_uint16_le(s
, masklen
);
1117 in_uint16_le(s
, datalen
);
1118 in_uint8p(s
, data
, datalen
);
1119 in_uint8p(s
, mask
, masklen
);
1120 if ((width
!= 32) || (height
!= 32))
1122 warning("process_colour_pointer_common: " "width %d height %d\n", width
, height
);
1125 /* keep hotspot within cursor bounding box */
1126 x
= MIN(x
, width
- 1);
1127 y
= MIN(y
, height
- 1);
1128 cursor
= ui_create_cursor(x
, y
, width
, height
, mask
, data
, bpp
);
1129 ui_set_cursor(cursor
);
1130 cache_put_cursor(cache_idx
, cursor
);
1133 /* Process a colour pointer PDU */
1135 process_colour_pointer_pdu(STREAM s
)
1137 process_colour_pointer_common(s
, 24);
1140 /* Process a New Pointer PDU - these pointers have variable bit depth */
1142 process_new_pointer_pdu(STREAM s
)
1146 in_uint16_le(s
, xor_bpp
);
1147 process_colour_pointer_common(s
, xor_bpp
);
1150 /* Process a cached pointer PDU */
1152 process_cached_pointer_pdu(STREAM s
)
1156 in_uint16_le(s
, cache_idx
);
1157 ui_set_cursor(cache_get_cursor(cache_idx
));
1160 /* Process a system pointer PDU */
1162 process_system_pointer_pdu(STREAM s
)
1164 uint16 system_pointer_type
;
1166 in_uint16_le(s
, system_pointer_type
);
1167 switch (system_pointer_type
)
1169 case RDP_NULL_POINTER
:
1170 ui_set_null_cursor();
1174 unimpl("System pointer message 0x%x\n", system_pointer_type
);
1178 /* Process a pointer PDU */
1180 process_pointer_pdu(STREAM s
)
1182 uint16 message_type
;
1185 in_uint16_le(s
, message_type
);
1186 in_uint8s(s
, 2); /* pad */
1188 switch (message_type
)
1190 case RDP_POINTER_MOVE
:
1194 ui_move_pointer(x
, y
);
1197 case RDP_POINTER_COLOR
:
1198 process_colour_pointer_pdu(s
);
1201 case RDP_POINTER_CACHED
:
1202 process_cached_pointer_pdu(s
);
1205 case RDP_POINTER_SYSTEM
:
1206 process_system_pointer_pdu(s
);
1209 case RDP_POINTER_NEW
:
1210 process_new_pointer_pdu(s
);
1214 unimpl("Pointer message 0x%x\n", message_type
);
1218 /* Process bitmap updates */
1220 process_bitmap_updates(STREAM s
)
1223 uint16 left
, top
, right
, bottom
, width
, height
;
1224 uint16 cx
, cy
, bpp
, Bpp
, compress
, bufsize
, size
;
1225 uint8
*data
, *bmpdata
;
1228 in_uint16_le(s
, num_updates
);
1230 for (i
= 0; i
< num_updates
; i
++)
1232 in_uint16_le(s
, left
);
1233 in_uint16_le(s
, top
);
1234 in_uint16_le(s
, right
);
1235 in_uint16_le(s
, bottom
);
1236 in_uint16_le(s
, width
);
1237 in_uint16_le(s
, height
);
1238 in_uint16_le(s
, bpp
);
1239 Bpp
= (bpp
+ 7) / 8;
1240 in_uint16_le(s
, compress
);
1241 in_uint16_le(s
, bufsize
);
1243 cx
= right
- left
+ 1;
1244 cy
= bottom
- top
+ 1;
1246 DEBUG(("BITMAP_UPDATE(l=%d,t=%d,r=%d,b=%d,w=%d,h=%d,Bpp=%d,cmp=%d)\n",
1247 left
, top
, right
, bottom
, width
, height
, Bpp
, compress
));
1252 bmpdata
= (uint8
*) xmalloc(width
* height
* Bpp
);
1253 for (y
= 0; y
< height
; y
++)
1255 in_uint8a(s
, &bmpdata
[(height
- y
- 1) * (width
* Bpp
)],
1258 ui_paint_bitmap(left
, top
, cx
, cy
, width
, height
, bmpdata
);
1264 if (compress
& 0x400)
1270 in_uint8s(s
, 2); /* pad */
1271 in_uint16_le(s
, size
);
1272 in_uint8s(s
, 4); /* line_size, final_size */
1274 in_uint8p(s
, data
, size
);
1275 bmpdata
= (uint8
*) xmalloc(width
* height
* Bpp
);
1276 if (bitmap_decompress(bmpdata
, width
, height
, data
, size
, Bpp
))
1278 ui_paint_bitmap(left
, top
, cx
, cy
, width
, height
, bmpdata
);
1282 DEBUG_RDP5(("Failed to decompress data\n"));
1289 /* Process a palette update */
1291 process_palette(STREAM s
)
1298 in_uint8s(s
, 2); /* pad */
1299 in_uint16_le(s
, map
.ncolours
);
1300 in_uint8s(s
, 2); /* pad */
1302 map
.colours
= (COLOURENTRY
*) xmalloc(sizeof(COLOURENTRY
) * map
.ncolours
);
1304 DEBUG(("PALETTE(c=%d)\n", map
.ncolours
));
1306 for (i
= 0; i
< map
.ncolours
; i
++)
1308 entry
= &map
.colours
[i
];
1309 in_uint8(s
, entry
->red
);
1310 in_uint8(s
, entry
->green
);
1311 in_uint8(s
, entry
->blue
);
1314 hmap
= ui_create_colourmap(&map
);
1315 ui_set_colourmap(hmap
);
1320 /* Process an update PDU */
1322 process_update_pdu(STREAM s
)
1324 uint16 update_type
, count
;
1326 in_uint16_le(s
, update_type
);
1329 switch (update_type
)
1331 case RDP_UPDATE_ORDERS
:
1332 in_uint8s(s
, 2); /* pad */
1333 in_uint16_le(s
, count
);
1334 in_uint8s(s
, 2); /* pad */
1335 process_orders(s
, count
);
1338 case RDP_UPDATE_BITMAP
:
1339 process_bitmap_updates(s
);
1342 case RDP_UPDATE_PALETTE
:
1346 case RDP_UPDATE_SYNCHRONIZE
:
1350 unimpl("update %d\n", update_type
);
1356 /* Process a Save Session Info PDU */
1358 process_pdu_logon(STREAM s
)
1361 in_uint32_le(s
, infotype
);
1362 if (infotype
== INFOTYPE_LOGON_EXTENDED_INF
)
1364 uint32 fieldspresent
;
1366 in_uint8s(s
, 2); /* Length */
1367 in_uint32_le(s
, fieldspresent
);
1368 if (fieldspresent
& LOGON_EX_AUTORECONNECTCOOKIE
)
1373 /* TS_LOGON_INFO_FIELD */
1374 in_uint8s(s
, 4); /* cbFieldData */
1376 /* ARC_SC_PRIVATE_PACKET */
1377 in_uint32_le(s
, len
);
1380 warning("Invalid length in Auto-Reconnect packet\n");
1384 in_uint32_le(s
, version
);
1387 warning("Unsupported version of Auto-Reconnect packet\n");
1391 in_uint32_le(s
, g_reconnect_logonid
);
1392 in_uint8a(s
, g_reconnect_random
, 16);
1393 g_has_reconnect_random
= True
;
1394 g_reconnect_random_ts
= time(NULL
);
1395 DEBUG(("Saving auto-reconnect cookie, id=%u\n", g_reconnect_logonid
));
1401 /* Process a disconnect PDU */
1403 process_disconnect_pdu(STREAM s
, uint32
* ext_disc_reason
)
1405 in_uint32_le(s
, *ext_disc_reason
);
1407 DEBUG(("Received disconnect PDU\n"));
1410 /* Process data PDU */
1412 process_data_pdu(STREAM s
, uint32
* ext_disc_reason
)
1414 uint8 data_pdu_type
;
1421 struct stream
*ns
= &(g_mppc_dict
.ns
);
1423 in_uint8s(s
, 6); /* shareid, pad, streamid */
1424 in_uint16_le(s
, len
);
1425 in_uint8(s
, data_pdu_type
);
1427 in_uint16_le(s
, clen
);
1430 if (ctype
& RDP_MPPC_COMPRESSED
)
1432 if (len
> RDP_MPPC_DICT_SIZE
)
1433 error("error decompressed packet size exceeds max\n");
1434 if (mppc_expand(s
->p
, clen
, ctype
, &roff
, &rlen
) == -1)
1435 error("error while decompressing packet\n");
1439 /* allocate memory and copy the uncompressed data into the temporary stream */
1440 ns
->data
= (uint8
*) xrealloc(ns
->data
, rlen
);
1442 memcpy((ns
->data
), (unsigned char *) (g_mppc_dict
.hist
+ roff
), rlen
);
1445 ns
->end
= (ns
->data
+ ns
->size
);
1447 ns
->rdp_hdr
= ns
->p
;
1452 switch (data_pdu_type
)
1454 case RDP_DATA_PDU_UPDATE
:
1455 process_update_pdu(s
);
1458 case RDP_DATA_PDU_CONTROL
:
1459 DEBUG(("Received Control PDU\n"));
1462 case RDP_DATA_PDU_SYNCHRONISE
:
1463 DEBUG(("Received Sync PDU\n"));
1466 case RDP_DATA_PDU_POINTER
:
1467 process_pointer_pdu(s
);
1470 case RDP_DATA_PDU_BELL
:
1474 case RDP_DATA_PDU_LOGON
:
1475 DEBUG(("Received Logon PDU\n"));
1476 /* User logged on */
1477 process_pdu_logon(s
);
1480 case RDP_DATA_PDU_DISCONNECT
:
1481 process_disconnect_pdu(s
, ext_disc_reason
);
1483 /* We used to return true and disconnect immediately here, but
1484 * Windows Vista sends a disconnect PDU with reason 0 when
1485 * reconnecting to a disconnected session, and MSTSC doesn't
1486 * drop the connection. I think we should just save the status.
1490 case RDP_DATA_PDU_AUTORECONNECT_STATUS
:
1491 warning("Automatic reconnect using cookie, failed.\n");
1495 unimpl("data PDU %d\n", data_pdu_type
);
1500 /* Process redirect PDU from Session Directory */
1502 process_redirect_pdu(STREAM s
, RD_BOOL enhanced_redirect
/*, uint32 * ext_disc_reason */ )
1505 uint16 redirect_identifier
;
1507 /* reset any previous redirection information */
1509 free(g_redirect_server
);
1510 free(g_redirect_username
);
1511 free(g_redirect_domain
);
1512 free(g_redirect_lb_info
);
1513 free(g_redirect_cookie
);
1515 g_redirect_server
= NULL
;
1516 g_redirect_username
= NULL
;
1517 g_redirect_domain
= NULL
;
1518 g_redirect_lb_info
= NULL
;
1519 g_redirect_cookie
= NULL
;
1521 /* these 2 bytes are unknown, seem to be zeros */
1524 /* FIXME: Previous implementation only reads 4 bytes which has been working
1525 but todays spec says something different. Investigate and retest
1526 server redirection using WTS 2003 cluster.
1529 if (enhanced_redirect
)
1531 /* read identifier */
1532 in_uint16_le(s
, redirect_identifier
);
1533 if (redirect_identifier
!= 0x0400)
1534 error("Protocol error in server redirection, unexpected data.");
1536 /* FIXME: skip total length */
1539 /* read session_id */
1540 in_uint32_le(s
, g_redirect_session_id
);
1543 /* read connection flags */
1544 in_uint32_le(s
, g_redirect_flags
);
1546 if (g_redirect_flags
& LB_TARGET_NET_ADDRESS
)
1548 /* read length of ip string */
1549 in_uint32_le(s
, len
);
1551 /* read ip string */
1552 rdp_in_unistr(s
, len
, &g_redirect_server
, &g_redirect_server_len
);
1555 if (g_redirect_flags
& LB_LOAD_BALANCE_INFO
)
1557 /* read length of load balance info blob */
1558 in_uint32_le(s
, g_redirect_lb_info_len
);
1560 /* reallocate a loadbalance info blob */
1561 if (g_redirect_lb_info
!= NULL
)
1562 free(g_redirect_lb_info
);
1564 g_redirect_lb_info
= xmalloc(g_redirect_lb_info_len
);
1566 /* read load balance info blob */
1567 in_uint8p(s
, g_redirect_lb_info
, g_redirect_lb_info_len
);
1570 if (g_redirect_flags
& LB_USERNAME
)
1572 /* read length of username string */
1573 in_uint32_le(s
, len
);
1575 /* read username string */
1576 rdp_in_unistr(s
, len
, &g_redirect_username
, &g_redirect_username_len
);
1579 if (g_redirect_flags
& LB_DOMAIN
)
1581 /* read length of domain string */
1582 in_uint32_le(s
, len
);
1584 /* read domain string */
1585 rdp_in_unistr(s
, len
, &g_redirect_domain
, &g_redirect_domain_len
);
1588 if (g_redirect_flags
& LB_PASSWORD
)
1590 /* the information in this blob is either a password or a cookie that
1591 should be passed though as blob and not parsed as a unicode string */
1593 /* read blob length */
1594 in_uint32_le(s
, g_redirect_cookie_len
);
1596 /* reallocate cookie blob */
1597 if (g_redirect_cookie
!= NULL
)
1598 free(g_redirect_cookie
);
1600 g_redirect_cookie
= xmalloc(g_redirect_cookie_len
);
1602 /* read cookie as is */
1603 in_uint8p(s
, g_redirect_cookie
, g_redirect_cookie_len
);
1606 if (g_redirect_flags
& LB_DONTSTOREUSERNAME
)
1608 warning("LB_DONTSTOREUSERNAME set\n");
1611 if (g_redirect_flags
& LB_SMARTCARD_LOGON
)
1613 warning("LB_SMARTCARD_LOGON set\n");
1616 if (g_redirect_flags
& LB_NOREDIRECT
)
1618 /* By spec this is only for information and doesn't mean that an actual
1619 redirect should be performed. How it should be used is not mentioned. */
1623 if (g_redirect_flags
& LB_TARGET_FQDN
)
1625 in_uint32_le(s
, len
);
1627 /* Let target fqdn replace target ip address */
1628 if (g_redirect_server
)
1630 free(g_redirect_server
);
1631 g_redirect_server
= NULL
;
1634 /* read fqdn string */
1635 rdp_in_unistr(s
, len
, &g_redirect_server
, &g_redirect_server_len
);
1638 if (g_redirect_flags
& LB_TARGET_NETBIOS
)
1640 warning("LB_TARGET_NETBIOS set\n");
1643 if (g_redirect_flags
& LB_TARGET_NET_ADDRESSES
)
1645 warning("LB_TARGET_NET_ADDRESSES set\n");
1648 if (g_redirect_flags
& LB_CLIENT_TSV_URL
)
1650 warning("LB_CLIENT_TSV_URL set\n");
1653 if (g_redirect_flags
& LB_SERVER_TSV_CAPABLE
)
1655 warning("LB_SERVER_TSV_CAPABLE set\n");
1658 if (g_redirect_flags
& LB_PASSWORD_IS_PK_ENCRYPTED
)
1660 warning("LB_PASSWORD_IS_PK_ENCRYPTED set\n");
1663 if (g_redirect_flags
& LB_REDIRECTION_GUID
)
1665 warning("LB_REDIRECTION_GUID set\n");
1668 if (g_redirect_flags
& LB_TARGET_CERTIFICATE
)
1670 warning("LB_TARGET_CERTIFICATE set\n");
1676 /* Process incoming packets */
1678 rdp_main_loop(RD_BOOL
* deactivated
, uint32
* ext_disc_reason
)
1680 while (rdp_loop(deactivated
, ext_disc_reason
))
1682 if (g_pending_resize
|| g_redirect
)
1689 /* used in uiports and rdp_main_loop, processes the rdp packets waiting */
1691 rdp_loop(RD_BOOL
* deactivated
, uint32
* ext_disc_reason
)
1694 RD_BOOL cont
= True
;
1699 s
= rdp_recv(&type
);
1704 case RDP_PDU_DEMAND_ACTIVE
:
1705 process_demand_active(s
);
1706 *deactivated
= False
;
1708 case RDP_PDU_DEACTIVATE
:
1709 DEBUG(("RDP_PDU_DEACTIVATE\n"));
1710 *deactivated
= True
;
1712 case RDP_PDU_REDIRECT
:
1713 return process_redirect_pdu(s
, False
);
1715 case RDP_PDU_ENHANCED_REDIRECT
:
1716 return process_redirect_pdu(s
, True
);
1719 /* If we got a data PDU, we don't need to keep the password in memory
1720 anymore and therefor we should clear it for security reasons. */
1721 if (g_password
[0] != '\0')
1722 memset(g_password
, 0, sizeof(g_password
));
1724 process_data_pdu(s
, ext_disc_reason
);
1729 unimpl("PDU %d\n", type
);
1731 cont
= g_next_packet
< s
->end
;
1736 /* Establish a connection up to the RDP layer */
1738 rdp_connect(char *server
, uint32 flags
, char *domain
, char *password
,
1739 char *command
, char *directory
, RD_BOOL reconnect
)
1741 RD_BOOL deactivated
= False
;
1742 uint32 ext_disc_reason
= 0;
1744 if (!sec_connect(server
, g_username
, domain
, password
, reconnect
))
1747 rdp_send_logon_info(flags
, domain
, g_username
, password
, command
, directory
);
1749 /* run RDP loop until first licence demand active PDU */
1750 while (!g_rdp_shareid
)
1752 if (g_network_error
)
1755 if (!rdp_loop(&deactivated
, &ext_disc_reason
))
1764 /* Called during redirection to reset the state to support redirection */
1766 rdp_reset_state(void)
1768 g_next_packet
= NULL
; /* reset the packet information */
1773 /* Disconnect from the RDP layer */
1775 rdp_disconnect(void)