1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Protocol services - RDP layer
4 Copyright (C) Matthew Chapman 1999-2005
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 extern uint16 g_mcs_userid
;
25 extern char g_username
[];
26 extern char g_codepage
[];
27 extern BOOL g_bitmap_compression
;
29 extern BOOL g_encryption
;
30 extern BOOL g_desktop_save
;
31 extern BOOL g_polygon_ellipse_orders
;
32 extern BOOL g_use_rdp5
;
33 extern uint16 g_server_rdp_version
;
34 extern uint32 g_rdp5_performanceflags
;
35 extern int g_server_depth
;
38 extern BOOL g_bitmap_cache
;
39 extern BOOL g_bitmap_cache_persist_enable
;
44 extern RDPCOMP g_mppc_dict
;
46 /* Session Directory support */
47 extern BOOL g_redirect
;
48 extern char g_redirect_server
[64];
49 extern char g_redirect_domain
[16];
50 extern char g_redirect_password
[64];
51 extern char g_redirect_username
[64];
52 extern char g_redirect_cookie
[128];
53 extern uint32 g_redirect_flags
;
54 /* END Session Directory support */
57 static uint32 g_packetno
;
61 static BOOL g_iconv_works
= True
;
64 /* Receive an RDP packet */
66 rdp_recv(uint8
* type
)
69 uint16 length
, pdu_type
;
72 if ((rdp_s
== NULL
) || (g_next_packet
>= rdp_s
->end
) || (g_next_packet
== NULL
))
74 rdp_s
= sec_recv(&rdpver
);
79 g_next_packet
= rdp_s
->end
;
85 /* rdp5_process should move g_next_packet ok */
91 g_next_packet
= rdp_s
->p
;
95 rdp_s
->p
= g_next_packet
;
98 in_uint16_le(rdp_s
, length
);
99 /* 32k packets are really 8, keepalive fix */
100 if (length
== 0x8000)
106 in_uint16_le(rdp_s
, pdu_type
);
107 in_uint8s(rdp_s
, 2); /* userid */
108 *type
= pdu_type
& 0xf;
111 DEBUG(("RDP packet #%d, (type %x)\n", ++g_packetno
, *type
));
112 hexdump(g_next_packet
, length
);
115 g_next_packet
+= length
;
119 /* Initialise an RDP data packet */
121 rdp_init_data(int maxlen
)
125 s
= sec_init(g_encryption
? SEC_ENCRYPT
: 0, maxlen
+ 18);
126 s_push_layer(s
, rdp_hdr
, 18);
131 /* Send an RDP data packet */
133 rdp_send_data(STREAM s
, uint8 data_pdu_type
)
137 s_pop_layer(s
, rdp_hdr
);
138 length
= s
->end
- s
->p
;
140 out_uint16_le(s
, length
);
141 out_uint16_le(s
, (RDP_PDU_DATA
| 0x10));
142 out_uint16_le(s
, (g_mcs_userid
+ 1001));
144 out_uint32_le(s
, g_rdp_shareid
);
145 out_uint8(s
, 0); /* pad */
146 out_uint8(s
, 1); /* streamid */
147 out_uint16_le(s
, (length
- 14));
148 out_uint8(s
, data_pdu_type
);
149 out_uint8(s
, 0); /* compress_type */
150 out_uint16(s
, 0); /* compress_len */
152 sec_send(s
, g_encryption
? SEC_ENCRYPT
: 0);
155 /* Output a string in Unicode */
157 rdp_out_unistr(STREAM s
, char *string
, int len
)
160 size_t ibl
= strlen(string
), obl
= len
+ 2;
161 static iconv_t iconv_h
= (iconv_t
) - 1;
162 char *pin
= string
, *pout
= (char *) s
->p
;
164 memset(pout
, 0, len
+ 4);
168 if (iconv_h
== (iconv_t
) - 1)
171 if ((iconv_h
= iconv_open(WINDOWS_CODEPAGE
, g_codepage
)) == (iconv_t
) - 1)
173 warning("rdp_out_unistr: iconv_open[%s -> %s] fail %d\n",
174 g_codepage
, WINDOWS_CODEPAGE
, (int) iconv_h
);
176 g_iconv_works
= False
;
177 rdp_out_unistr(s
, string
, len
);
180 if (iconv(iconv_h
, (ICONV_CONST
char **) &pin
, &i
, &pout
, &o
) ==
183 iconv_close(iconv_h
);
184 iconv_h
= (iconv_t
) - 1;
185 warning("rdp_out_unistr: iconv(1) fail, errno %d\n", errno
);
187 g_iconv_works
= False
;
188 rdp_out_unistr(s
, string
, len
);
192 pout
= (char *) s
->p
;
195 if (iconv(iconv_h
, (ICONV_CONST
char **) &pin
, &ibl
, &pout
, &obl
) == (size_t) - 1)
197 iconv_close(iconv_h
);
198 iconv_h
= (iconv_t
) - 1;
199 warning("rdp_out_unistr: iconv(2) fail, errno %d\n", errno
);
201 g_iconv_works
= False
;
202 rdp_out_unistr(s
, string
, len
);
218 s
->p
[i
++] = string
[j
++];
226 /* Input a string in Unicode
228 * Returns str_len of string
231 rdp_in_unistr(STREAM s
, char *string
, int uni_len
)
234 size_t ibl
= uni_len
, obl
= uni_len
;
235 char *pin
= (char *) s
->p
, *pout
= string
;
236 static iconv_t iconv_h
= (iconv_t
) - 1;
240 if (iconv_h
== (iconv_t
) - 1)
242 if ((iconv_h
= iconv_open(g_codepage
, WINDOWS_CODEPAGE
)) == (iconv_t
) - 1)
244 warning("rdp_in_unistr: iconv_open[%s -> %s] fail %d\n",
245 WINDOWS_CODEPAGE
, g_codepage
, (int) iconv_h
);
247 g_iconv_works
= False
;
248 return rdp_in_unistr(s
, string
, uni_len
);
252 if (iconv(iconv_h
, (ICONV_CONST
char **) &pin
, &ibl
, &pout
, &obl
) == (size_t) - 1)
254 iconv_close(iconv_h
);
255 iconv_h
= (iconv_t
) - 1;
256 warning("rdp_in_unistr: iconv fail, errno %d\n", errno
);
258 g_iconv_works
= False
;
259 return rdp_in_unistr(s
, string
, uni_len
);
262 /* we must update the location of the current STREAM for future reads of s->p */
265 return pout
- string
;
272 while (i
< uni_len
/ 2)
274 in_uint8a(s
, &string
[i
++], 1);
283 /* Parse a logon info packet */
285 rdp_send_logon_info(uint32 flags
, char *domain
, char *user
,
286 char *password
, char *program
, char *directory
)
288 //char *ipaddr = tcp_get_address();
289 int len_domain
= 2 * strlen(domain
);
290 int len_user
= 2 * strlen(user
);
291 int len_password
= 2 * strlen(password
);
292 int len_program
= 2 * strlen(program
);
293 int len_directory
= 2 * strlen(directory
);
294 //int len_ip = 2 * strlen(ipaddr);
295 //int len_dll = 2 * strlen("C:\\WINNT\\System32\\mstscax.dll");
297 uint32 sec_flags
= g_encryption
? (SEC_LOGON_INFO
| SEC_ENCRYPT
) : SEC_LOGON_INFO
;
299 //time_t t = time(NULL);
302 if (!g_use_rdp5
|| 1 == g_server_rdp_version
)
304 DEBUG_RDP5(("Sending RDP4-style Logon packet\n"));
306 s
= sec_init(sec_flags
, 18 + len_domain
+ len_user
+ len_password
307 + len_program
+ len_directory
+ 10);
310 out_uint32_le(s
, flags
);
311 out_uint16_le(s
, len_domain
);
312 out_uint16_le(s
, len_user
);
313 out_uint16_le(s
, len_password
);
314 out_uint16_le(s
, len_program
);
315 out_uint16_le(s
, len_directory
);
316 rdp_out_unistr(s
, domain
, len_domain
);
317 rdp_out_unistr(s
, user
, len_user
);
318 rdp_out_unistr(s
, password
, len_password
);
319 rdp_out_unistr(s
, program
, len_program
);
320 rdp_out_unistr(s
, directory
, len_directory
);
325 flags
|= RDP_LOGON_BLOB
;
326 DEBUG_RDP5(("Sending RDP5-style Logon packet\n"));
327 packetlen
= 4 + /* Unknown uint32 */
331 (flags
& RDP_LOGON_AUTO
? 2 : 0) + /* len_password */
332 (flags
& RDP_LOGON_BLOB
? 2 : 0) + /* Length of BLOB */
333 2 + /* len_program */
334 2 + /* len_directory */
335 (0 < len_domain
? len_domain
: 2) + /* domain */
336 len_user
+ (flags
& RDP_LOGON_AUTO
? len_password
: 0) + 0 + /* We have no 512 byte BLOB. Perhaps we must? */
337 (flags
& RDP_LOGON_BLOB
&& !(flags
& RDP_LOGON_AUTO
) ? 2 : 0) + /* After the BLOB is a unknown int16. If there is a BLOB, that is. */
338 (0 < len_program
? len_program
: 2) + (0 < len_directory
? len_directory
: 2) + 2 + /* Unknown (2) */
339 2 + /* Client ip length */
340 len_ip
+ /* Client ip */
341 2 + /* DLL string length */
342 len_dll
+ /* DLL string */
345 64 + /* Time zone #0 */
347 64 + /* Time zone #1 */
350 s
= sec_init(sec_flags
, packetlen
);
351 DEBUG_RDP5(("Called sec_init with packetlen %d\n", packetlen
));
353 out_uint32(s
, 0); /* Unknown */
354 out_uint32_le(s
, flags
);
355 out_uint16_le(s
, len_domain
);
356 out_uint16_le(s
, len_user
);
357 if (flags
& RDP_LOGON_AUTO
)
359 out_uint16_le(s
, len_password
);
362 if (flags
& RDP_LOGON_BLOB
&& !(flags
& RDP_LOGON_AUTO
))
366 out_uint16_le(s
, len_program
);
367 out_uint16_le(s
, len_directory
);
369 rdp_out_unistr(s
, domain
, len_domain
);
372 rdp_out_unistr(s
, user
, len_user
);
373 if (flags
& RDP_LOGON_AUTO
)
375 rdp_out_unistr(s
, password
, len_password
);
377 if (flags
& RDP_LOGON_BLOB
&& !(flags
& RDP_LOGON_AUTO
))
383 rdp_out_unistr(s
, program
, len_program
);
390 if (0 < len_directory
)
392 rdp_out_unistr(s
, directory
, len_directory
);
399 out_uint16_le(s
, len_ip
+ 2); /* Length of client ip */
400 rdp_out_unistr(s
, ipaddr
, len_ip
);
401 out_uint16_le(s
, len_dll
+ 2);
402 rdp_out_unistr(s
, "C:\\WINNT\\System32\\mstscax.dll", len_dll
);
404 tzone
= (mktime(gmtime(&t
)) - mktime(localtime(&t
))) / 60;
405 out_uint32_le(s
, tzone
);
407 rdp_out_unistr(s
, "GTB, normaltid", 2 * strlen("GTB, normaltid"));
408 out_uint8s(s
, 62 - 2 * strlen("GTB, normaltid"));
410 out_uint32_le(s
, 0x0a0000);
411 out_uint32_le(s
, 0x050000);
416 rdp_out_unistr(s
, "GTB, sommartid", 2 * strlen("GTB, sommartid"));
417 out_uint8s(s
, 62 - 2 * strlen("GTB, sommartid"));
419 out_uint32_le(s
, 0x30000);
420 out_uint32_le(s
, 0x050000);
423 out_uint32_le(s
, 0xffffffc4);
424 out_uint32_le(s
, 0xfffffffe);
425 out_uint32_le(s
, g_rdp5_performanceflags
);
431 sec_send(s
, sec_flags
);
434 /* Send a control PDU */
436 rdp_send_control(uint16 action
)
440 s
= rdp_init_data(8);
442 out_uint16_le(s
, action
);
443 out_uint16(s
, 0); /* userid */
444 out_uint32(s
, 0); /* control id */
447 rdp_send_data(s
, RDP_DATA_PDU_CONTROL
);
450 /* Send a synchronisation PDU */
452 rdp_send_synchronise(void)
456 s
= rdp_init_data(4);
458 out_uint16_le(s
, 1); /* type */
459 out_uint16_le(s
, 1002);
462 rdp_send_data(s
, RDP_DATA_PDU_SYNCHRONISE
);
465 /* Send a single input event */
467 rdp_send_input(uint32 time
, uint16 message_type
, uint16 device_flags
, uint16 param1
, uint16 param2
)
471 s
= rdp_init_data(16);
473 out_uint16_le(s
, 1); /* number of events */
474 out_uint16(s
, 0); /* pad */
476 out_uint32_le(s
, time
);
477 out_uint16_le(s
, message_type
);
478 out_uint16_le(s
, device_flags
);
479 out_uint16_le(s
, param1
);
480 out_uint16_le(s
, param2
);
483 rdp_send_data(s
, RDP_DATA_PDU_INPUT
);
486 /* Send a client window information PDU */
488 rdp_send_client_window_status(int status
)
491 static int current_status
= 1;
493 if (current_status
== status
)
496 s
= rdp_init_data(12);
498 out_uint32_le(s
, status
);
502 case 0: /* shut the server up */
505 case 1: /* receive data again */
506 out_uint32_le(s
, 0); /* unknown */
507 out_uint16_le(s
, g_width
);
508 out_uint16_le(s
, g_height
);
513 rdp_send_data(s
, RDP_DATA_PDU_CLIENT_WINDOW_STATUS
);
514 current_status
= status
;
517 /* Send persistent bitmap cache enumeration PDU's */
519 rdp_enum_bmpcache2(void)
522 HASH_KEY keylist
[BMPCACHE2_NUM_PSTCELLS
];
523 uint32 num_keys
, offset
, count
, flags
;
526 num_keys
= pstcache_enumerate(2, keylist
);
528 while (offset
< num_keys
)
530 count
= MIN(num_keys
- offset
, 169);
532 s
= rdp_init_data(24 + count
* sizeof(HASH_KEY
));
536 flags
|= PDU_FLAG_FIRST
;
537 if (num_keys
- offset
<= 169)
538 flags
|= PDU_FLAG_LAST
;
542 out_uint16_le(s
, count
);
547 out_uint16_le(s
, num_keys
);
549 out_uint32_le(s
, flags
);
552 out_uint8a(s
, keylist
[offset
], count
* sizeof(HASH_KEY
));
555 rdp_send_data(s
, 0x2b);
561 /* Send an (empty) font information PDU */
563 rdp_send_fonts(uint16 seq
)
567 s
= rdp_init_data(8);
569 out_uint16(s
, 0); /* number of fonts */
570 out_uint16_le(s
, 0); /* pad? */
571 out_uint16_le(s
, seq
); /* unknown */
572 out_uint16_le(s
, 0x32); /* entry size */
575 rdp_send_data(s
, RDP_DATA_PDU_FONT2
);
578 /* Output general capability set */
580 rdp_out_general_caps(STREAM s
)
582 out_uint16_le(s
, RDP_CAPSET_GENERAL
);
583 out_uint16_le(s
, RDP_CAPLEN_GENERAL
);
585 out_uint16_le(s
, 1); /* OS major type */
586 out_uint16_le(s
, 3); /* OS minor type */
587 out_uint16_le(s
, 0x200); /* Protocol version */
588 out_uint16(s
, 0); /* Pad */
589 out_uint16(s
, 0); /* Compression types */
590 out_uint16_le(s
, g_use_rdp5
? 0x40d : 0);
591 /* Pad, according to T.128. 0x40d seems to
593 the server to start sending RDP5 packets.
594 However, the value is 0x1d04 with W2KTSK and
595 NT4MS. Hmm.. Anyway, thankyou, Microsoft,
596 for sending such information in a padding
598 out_uint16(s
, 0); /* Update capability */
599 out_uint16(s
, 0); /* Remote unshare capability */
600 out_uint16(s
, 0); /* Compression level */
601 out_uint16(s
, 0); /* Pad */
604 /* Output bitmap capability set */
606 rdp_out_bitmap_caps(STREAM s
)
608 out_uint16_le(s
, RDP_CAPSET_BITMAP
);
609 out_uint16_le(s
, RDP_CAPLEN_BITMAP
);
611 out_uint16_le(s
, g_server_depth
); /* Preferred colour depth */
612 out_uint16_le(s
, 1); /* Receive 1 BPP */
613 out_uint16_le(s
, 1); /* Receive 4 BPP */
614 out_uint16_le(s
, 1); /* Receive 8 BPP */
615 out_uint16_le(s
, 800); /* Desktop width */
616 out_uint16_le(s
, 600); /* Desktop height */
617 out_uint16(s
, 0); /* Pad */
618 out_uint16(s
, 1); /* Allow resize */
619 out_uint16_le(s
, g_bitmap_compression
? 1 : 0); /* Support compression */
620 out_uint16(s
, 0); /* Unknown */
621 out_uint16_le(s
, 1); /* Unknown */
622 out_uint16(s
, 0); /* Pad */
625 /* Output order capability set */
627 rdp_out_order_caps(STREAM s
)
629 uint8 order_caps
[32];
631 memset(order_caps
, 0, 32);
632 order_caps
[0] = 1; /* dest blt */
633 order_caps
[1] = 1; /* pat blt */
634 order_caps
[2] = 1; /* screen blt */
635 order_caps
[3] = (g_bitmap_cache
? 1 : 0); /* memblt */
636 order_caps
[4] = 0; /* triblt */
637 order_caps
[8] = 1; /* line */
638 order_caps
[9] = 1; /* line */
639 order_caps
[10] = 1; /* rect */
640 order_caps
[11] = (g_desktop_save
? 1 : 0); /* desksave */
641 order_caps
[13] = 1; /* memblt */
642 order_caps
[14] = 1; /* triblt */
643 order_caps
[20] = (g_polygon_ellipse_orders
? 1 : 0); /* polygon */
644 order_caps
[21] = (g_polygon_ellipse_orders
? 1 : 0); /* polygon2 */
645 order_caps
[22] = 1; /* polyline */
646 order_caps
[25] = (g_polygon_ellipse_orders
? 1 : 0); /* ellipse */
647 order_caps
[26] = (g_polygon_ellipse_orders
? 1 : 0); /* ellipse2 */
648 order_caps
[27] = 1; /* text2 */
649 out_uint16_le(s
, RDP_CAPSET_ORDER
);
650 out_uint16_le(s
, RDP_CAPLEN_ORDER
);
652 out_uint8s(s
, 20); /* Terminal desc, pad */
653 out_uint16_le(s
, 1); /* Cache X granularity */
654 out_uint16_le(s
, 20); /* Cache Y granularity */
655 out_uint16(s
, 0); /* Pad */
656 out_uint16_le(s
, 1); /* Max order level */
657 out_uint16_le(s
, 0x147); /* Number of fonts */
658 out_uint16_le(s
, 0x2a); /* Capability flags */
659 out_uint8p(s
, order_caps
, 32); /* Orders supported */
660 out_uint16_le(s
, 0x6a1); /* Text capability flags */
661 out_uint8s(s
, 6); /* Pad */
662 out_uint32_le(s
, g_desktop_save
== False
? 0 : 0x38400); /* Desktop cache size */
663 out_uint32(s
, 0); /* Unknown */
664 out_uint32_le(s
, 0x4e4); /* Unknown */
667 /* Output bitmap cache capability set */
669 rdp_out_bmpcache_caps(STREAM s
)
672 out_uint16_le(s
, RDP_CAPSET_BMPCACHE
);
673 out_uint16_le(s
, RDP_CAPLEN_BMPCACHE
);
675 Bpp
= (g_server_depth
+ 7) / 8; /* bytes per pixel */
676 out_uint8s(s
, 24); /* unused */
677 out_uint16_le(s
, 0x258); /* entries */
678 out_uint16_le(s
, 0x100 * Bpp
); /* max cell size */
679 out_uint16_le(s
, 0x12c); /* entries */
680 out_uint16_le(s
, 0x400 * Bpp
); /* max cell size */
681 out_uint16_le(s
, 0x106); /* entries */
682 out_uint16_le(s
, 0x1000 * Bpp
); /* max cell size */
685 /* Output bitmap cache v2 capability set */
687 rdp_out_bmpcache2_caps(STREAM s
)
689 out_uint16_le(s
, RDP_CAPSET_BMPCACHE2
);
690 out_uint16_le(s
, RDP_CAPLEN_BMPCACHE2
);
692 out_uint16_le(s
, g_bitmap_cache_persist_enable
? 2 : 0); /* version */
694 out_uint16_be(s
, 3); /* number of caches in this set */
696 /* max cell size for cache 0 is 16x16, 1 = 32x32, 2 = 64x64, etc */
697 out_uint32_le(s
, BMPCACHE2_C0_CELLS
);
698 out_uint32_le(s
, BMPCACHE2_C1_CELLS
);
699 if (pstcache_init(2))
701 out_uint32_le(s
, BMPCACHE2_NUM_PSTCELLS
| BMPCACHE2_FLAG_PERSIST
);
705 out_uint32_le(s
, BMPCACHE2_C2_CELLS
);
707 out_uint8s(s
, 20); /* other bitmap caches not used */
710 /* Output control capability set */
712 rdp_out_control_caps(STREAM s
)
714 out_uint16_le(s
, RDP_CAPSET_CONTROL
);
715 out_uint16_le(s
, RDP_CAPLEN_CONTROL
);
717 out_uint16(s
, 0); /* Control capabilities */
718 out_uint16(s
, 0); /* Remote detach */
719 out_uint16_le(s
, 2); /* Control interest */
720 out_uint16_le(s
, 2); /* Detach interest */
723 /* Output activation capability set */
725 rdp_out_activate_caps(STREAM s
)
727 out_uint16_le(s
, RDP_CAPSET_ACTIVATE
);
728 out_uint16_le(s
, RDP_CAPLEN_ACTIVATE
);
730 out_uint16(s
, 0); /* Help key */
731 out_uint16(s
, 0); /* Help index key */
732 out_uint16(s
, 0); /* Extended help key */
733 out_uint16(s
, 0); /* Window activate */
736 /* Output pointer capability set */
738 rdp_out_pointer_caps(STREAM s
)
740 out_uint16_le(s
, RDP_CAPSET_POINTER
);
741 out_uint16_le(s
, RDP_CAPLEN_POINTER
);
743 out_uint16(s
, 0); /* Colour pointer */
744 out_uint16_le(s
, 20); /* Cache size */
747 /* Output share capability set */
749 rdp_out_share_caps(STREAM s
)
751 out_uint16_le(s
, RDP_CAPSET_SHARE
);
752 out_uint16_le(s
, RDP_CAPLEN_SHARE
);
754 out_uint16(s
, 0); /* userid */
755 out_uint16(s
, 0); /* pad */
758 /* Output colour cache capability set */
760 rdp_out_colcache_caps(STREAM s
)
762 out_uint16_le(s
, RDP_CAPSET_COLCACHE
);
763 out_uint16_le(s
, RDP_CAPLEN_COLCACHE
);
765 out_uint16_le(s
, 6); /* cache size */
766 out_uint16(s
, 0); /* pad */
769 static uint8 caps_0x0d
[] = {
770 0x01, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00,
771 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
772 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
773 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
774 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
775 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
776 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
777 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
778 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
779 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
780 0x00, 0x00, 0x00, 0x00
783 static uint8 caps_0x0c
[] = { 0x01, 0x00, 0x00, 0x00 };
785 static uint8 caps_0x0e
[] = { 0x01, 0x00, 0x00, 0x00 };
787 static uint8 caps_0x10
[] = {
788 0xFE, 0x00, 0x04, 0x00, 0xFE, 0x00, 0x04, 0x00,
789 0xFE, 0x00, 0x08, 0x00, 0xFE, 0x00, 0x08, 0x00,
790 0xFE, 0x00, 0x10, 0x00, 0xFE, 0x00, 0x20, 0x00,
791 0xFE, 0x00, 0x40, 0x00, 0xFE, 0x00, 0x80, 0x00,
792 0xFE, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x08,
793 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00
796 /* Output unknown capability sets */
798 rdp_out_unknown_caps(STREAM s
, uint16 id
, uint16 length
, uint8
* caps
)
800 out_uint16_le(s
, id
);
801 out_uint16_le(s
, length
);
803 out_uint8p(s
, caps
, length
- 4);
806 #define RDP5_FLAG 0x0030
807 /* Send a confirm active PDU */
809 rdp_send_confirm_active(void)
812 uint32 sec_flags
= g_encryption
? (RDP5_FLAG
| SEC_ENCRYPT
) : RDP5_FLAG
;
814 RDP_CAPLEN_GENERAL
+ RDP_CAPLEN_BITMAP
+ RDP_CAPLEN_ORDER
+
815 RDP_CAPLEN_BMPCACHE
+ RDP_CAPLEN_COLCACHE
+
816 RDP_CAPLEN_ACTIVATE
+ RDP_CAPLEN_CONTROL
+
817 RDP_CAPLEN_POINTER
+ RDP_CAPLEN_SHARE
+
818 0x58 + 0x08 + 0x08 + 0x34 /* unknown caps */ +
819 4 /* w2k fix, why? */ ;
821 s
= sec_init(sec_flags
, 6 + 14 + caplen
+ sizeof(RDP_SOURCE
));
823 out_uint16_le(s
, 2 + 14 + caplen
+ sizeof(RDP_SOURCE
));
824 out_uint16_le(s
, (RDP_PDU_CONFIRM_ACTIVE
| 0x10)); /* Version 1 */
825 out_uint16_le(s
, (g_mcs_userid
+ 1001));
827 out_uint32_le(s
, g_rdp_shareid
);
828 out_uint16_le(s
, 0x3ea); /* userid */
829 out_uint16_le(s
, sizeof(RDP_SOURCE
));
830 out_uint16_le(s
, caplen
);
832 out_uint8p(s
, RDP_SOURCE
, sizeof(RDP_SOURCE
));
833 out_uint16_le(s
, 0xd); /* num_caps */
834 out_uint8s(s
, 2); /* pad */
836 rdp_out_general_caps(s
);
837 rdp_out_bitmap_caps(s
);
838 rdp_out_order_caps(s
);
839 g_use_rdp5
? rdp_out_bmpcache2_caps(s
) : rdp_out_bmpcache_caps(s
);
840 rdp_out_colcache_caps(s
);
841 rdp_out_activate_caps(s
);
842 rdp_out_control_caps(s
);
843 rdp_out_pointer_caps(s
);
844 rdp_out_share_caps(s
);
846 rdp_out_unknown_caps(s
, 0x0d, 0x58, caps_0x0d
); /* international? */
847 rdp_out_unknown_caps(s
, 0x0c, 0x08, caps_0x0c
);
848 rdp_out_unknown_caps(s
, 0x0e, 0x08, caps_0x0e
);
849 rdp_out_unknown_caps(s
, 0x10, 0x34, caps_0x10
); /* glyph cache? */
852 sec_send(s
, sec_flags
);
855 /* Process a general capability set */
857 rdp_process_general_caps(STREAM s
)
859 uint16 pad2octetsB
; /* rdp5 flags? */
862 in_uint16_le(s
, pad2octetsB
);
868 /* Process a bitmap capability set */
870 rdp_process_bitmap_caps(STREAM s
)
872 uint16 width
, height
, depth
;
874 in_uint16_le(s
, depth
);
877 in_uint16_le(s
, width
);
878 in_uint16_le(s
, height
);
880 DEBUG(("setting desktop size and depth to: %dx%dx%d\n", width
, height
, depth
));
883 * The server may limit depth and change the size of the desktop (for
884 * example when shadowing another session).
886 if (g_server_depth
!= depth
)
888 warning("Remote desktop does not support colour depth %d; falling back to %d\n",
889 g_server_depth
, depth
);
890 g_server_depth
= depth
;
892 if (g_width
!= width
|| g_height
!= height
)
894 warning("Remote desktop changed from %dx%d to %dx%d.\n", g_width
, g_height
,
902 /* Process server capabilities */
904 rdp_process_server_caps(STREAM s
, uint16 length
)
908 uint16 ncapsets
, capset_type
, capset_length
;
912 in_uint16_le(s
, ncapsets
);
913 in_uint8s(s
, 2); /* pad */
915 for (n
= 0; n
< ncapsets
; n
++)
917 if (s
->p
> start
+ length
)
920 in_uint16_le(s
, capset_type
);
921 in_uint16_le(s
, capset_length
);
923 next
= s
->p
+ capset_length
- 4;
927 case RDP_CAPSET_GENERAL
:
928 rdp_process_general_caps(s
);
931 case RDP_CAPSET_BITMAP
:
932 rdp_process_bitmap_caps(s
);
940 /* Respond to a demand active PDU */
942 process_demand_active(STREAM s
)
945 uint16 len_src_descriptor
, len_combined_caps
;
947 in_uint32_le(s
, g_rdp_shareid
);
948 in_uint16_le(s
, len_src_descriptor
);
949 in_uint16_le(s
, len_combined_caps
);
950 in_uint8s(s
, len_src_descriptor
);
952 DEBUG(("DEMAND_ACTIVE(id=0x%x)\n", g_rdp_shareid
));
953 rdp_process_server_caps(s
, len_combined_caps
);
955 rdp_send_confirm_active();
956 rdp_send_synchronise();
957 rdp_send_control(RDP_CTL_COOPERATE
);
958 rdp_send_control(RDP_CTL_REQUEST_CONTROL
);
959 rdp_recv(&type
); /* RDP_PDU_SYNCHRONIZE */
960 rdp_recv(&type
); /* RDP_CTL_COOPERATE */
961 rdp_recv(&type
); /* RDP_CTL_GRANT_CONTROL */
962 rdp_send_input(0, RDP_INPUT_SYNCHRONIZE
, 0, ui_get_numlock_state(read_keyboard_state()), 0);
966 rdp_enum_bmpcache2();
975 rdp_recv(&type
); /* RDP_PDU_UNKNOWN 0x28 (Fonts?) */
979 /* Process a colour pointer PDU */
981 process_colour_pointer_pdu(STREAM s
)
983 uint16 x
, y
, width
, height
, cache_idx
, masklen
, datalen
;
987 in_uint16_le(s
, cache_idx
);
990 in_uint16_le(s
, width
);
991 in_uint16_le(s
, height
);
992 in_uint16_le(s
, masklen
);
993 in_uint16_le(s
, datalen
);
994 in_uint8p(s
, data
, datalen
);
995 in_uint8p(s
, mask
, masklen
);
996 cursor
= ui_create_cursor(x
, y
, width
, height
, mask
, data
);
997 ui_set_cursor(cursor
);
998 cache_put_cursor(cache_idx
, cursor
);
1001 /* Process a cached pointer PDU */
1003 process_cached_pointer_pdu(STREAM s
)
1007 in_uint16_le(s
, cache_idx
);
1008 ui_set_cursor(cache_get_cursor(cache_idx
));
1011 /* Process a system pointer PDU */
1013 process_system_pointer_pdu(STREAM s
)
1015 uint16 system_pointer_type
;
1017 in_uint16(s
, system_pointer_type
);
1018 switch (system_pointer_type
)
1020 case RDP_NULL_POINTER
:
1021 ui_set_null_cursor();
1025 unimpl("System pointer message 0x%x\n", system_pointer_type
);
1029 /* Process a pointer PDU */
1031 process_pointer_pdu(STREAM s
)
1033 uint16 message_type
;
1036 in_uint16_le(s
, message_type
);
1037 in_uint8s(s
, 2); /* pad */
1039 switch (message_type
)
1041 case RDP_POINTER_MOVE
:
1045 ui_move_pointer(x
, y
);
1048 case RDP_POINTER_COLOR
:
1049 process_colour_pointer_pdu(s
);
1052 case RDP_POINTER_CACHED
:
1053 process_cached_pointer_pdu(s
);
1056 case RDP_POINTER_SYSTEM
:
1057 process_system_pointer_pdu(s
);
1061 unimpl("Pointer message 0x%x\n", message_type
);
1065 /* Process bitmap updates */
1067 process_bitmap_updates(STREAM s
)
1070 uint16 left
, top
, right
, bottom
, width
, height
;
1071 uint16 cx
, cy
, bpp
, Bpp
, compress
, bufsize
, size
;
1072 uint8
*data
, *bmpdata
;
1075 in_uint16_le(s
, num_updates
);
1077 for (i
= 0; i
< num_updates
; i
++)
1079 in_uint16_le(s
, left
);
1080 in_uint16_le(s
, top
);
1081 in_uint16_le(s
, right
);
1082 in_uint16_le(s
, bottom
);
1083 in_uint16_le(s
, width
);
1084 in_uint16_le(s
, height
);
1085 in_uint16_le(s
, bpp
);
1086 Bpp
= (bpp
+ 7) / 8;
1087 in_uint16_le(s
, compress
);
1088 in_uint16_le(s
, bufsize
);
1090 cx
= right
- left
+ 1;
1091 cy
= bottom
- top
+ 1;
1093 DEBUG(("BITMAP_UPDATE(l=%d,t=%d,r=%d,b=%d,w=%d,h=%d,Bpp=%d,cmp=%d)\n",
1094 left
, top
, right
, bottom
, width
, height
, Bpp
, compress
));
1099 bmpdata
= (uint8
*) xmalloc(width
* height
* Bpp
);
1100 for (y
= 0; y
< height
; y
++)
1102 in_uint8a(s
, &bmpdata
[(height
- y
- 1) * (width
* Bpp
)],
1105 ui_paint_bitmap(left
, top
, cx
, cy
, width
, height
, bmpdata
);
1111 if (compress
& 0x400)
1117 in_uint8s(s
, 2); /* pad */
1118 in_uint16_le(s
, size
);
1119 in_uint8s(s
, 4); /* line_size, final_size */
1121 in_uint8p(s
, data
, size
);
1122 bmpdata
= (uint8
*) xmalloc(width
* height
* Bpp
);
1123 if (bitmap_decompress(bmpdata
, width
, height
, data
, size
, Bpp
))
1125 ui_paint_bitmap(left
, top
, cx
, cy
, width
, height
, bmpdata
);
1129 DEBUG_RDP5(("Failed to decompress data\n"));
1136 /* Process a palette update */
1138 process_palette(STREAM s
)
1145 in_uint8s(s
, 2); /* pad */
1146 in_uint16_le(s
, map
.ncolours
);
1147 in_uint8s(s
, 2); /* pad */
1149 map
.colours
= (COLOURENTRY
*) xmalloc(sizeof(COLOURENTRY
) * map
.ncolours
);
1151 DEBUG(("PALETTE(c=%d)\n", map
.ncolours
));
1153 for (i
= 0; i
< map
.ncolours
; i
++)
1155 entry
= &map
.colours
[i
];
1156 in_uint8(s
, entry
->red
);
1157 in_uint8(s
, entry
->green
);
1158 in_uint8(s
, entry
->blue
);
1161 hmap
= ui_create_colourmap(&map
);
1162 ui_set_colourmap(hmap
);
1167 /* Process an update PDU */
1169 process_update_pdu(STREAM s
)
1171 uint16 update_type
, count
;
1173 in_uint16_le(s
, update_type
);
1176 switch (update_type
)
1178 case RDP_UPDATE_ORDERS
:
1179 in_uint8s(s
, 2); /* pad */
1180 in_uint16_le(s
, count
);
1181 in_uint8s(s
, 2); /* pad */
1182 process_orders(s
, count
);
1185 case RDP_UPDATE_BITMAP
:
1186 process_bitmap_updates(s
);
1189 case RDP_UPDATE_PALETTE
:
1193 case RDP_UPDATE_SYNCHRONIZE
:
1197 unimpl("update %d\n", update_type
);
1202 /* Process a disconnect PDU */
1204 process_disconnect_pdu(STREAM s
, uint32
* ext_disc_reason
)
1206 in_uint32_le(s
, *ext_disc_reason
);
1208 DEBUG(("Received disconnect PDU\n"));
1211 /* Process data PDU */
1213 process_data_pdu(STREAM s
, uint32
* ext_disc_reason
)
1215 uint8 data_pdu_type
;
1222 struct stream
*ns
= &(g_mppc_dict
.ns
);
1224 in_uint8s(s
, 6); /* shareid, pad, streamid */
1226 in_uint8(s
, data_pdu_type
);
1231 if (ctype
& RDP_MPPC_COMPRESSED
)
1233 if (len
> RDP_MPPC_DICT_SIZE
)
1234 error("error decompressed packet size exceeds max\n");
1235 if (mppc_expand(s
->p
, clen
, ctype
, &roff
, &rlen
) == -1)
1236 error("error while decompressing packet\n");
1240 /* allocate memory and copy the uncompressed data into the temporary stream */
1241 ns
->data
= (uint8
*) xrealloc(ns
->data
, rlen
);
1243 memcpy((ns
->data
), (unsigned char *) (g_mppc_dict
.hist
+ roff
), rlen
);
1246 ns
->end
= (ns
->data
+ ns
->size
);
1248 ns
->rdp_hdr
= ns
->p
;
1253 switch (data_pdu_type
)
1255 case RDP_DATA_PDU_UPDATE
:
1256 process_update_pdu(s
);
1259 case RDP_DATA_PDU_CONTROL
:
1260 DEBUG(("Received Control PDU\n"));
1263 case RDP_DATA_PDU_SYNCHRONISE
:
1264 DEBUG(("Received Sync PDU\n"));
1267 case RDP_DATA_PDU_POINTER
:
1268 process_pointer_pdu(s
);
1271 case RDP_DATA_PDU_BELL
:
1275 case RDP_DATA_PDU_LOGON
:
1276 DEBUG(("Received Logon PDU\n"));
1277 /* User logged on */
1280 case RDP_DATA_PDU_DISCONNECT
:
1281 process_disconnect_pdu(s
, ext_disc_reason
);
1285 unimpl("data PDU %d\n", data_pdu_type
);
1290 /* Process redirect PDU from Session Directory */
1292 process_redirect_pdu(STREAM s
/*, uint32 * ext_disc_reason */ )
1296 /* these 2 bytes are unknown, seem to be zeros */
1299 /* read connection flags */
1300 in_uint32_le(s
, g_redirect_flags
);
1302 /* read length of ip string */
1303 in_uint32_le(s
, len
);
1305 /* read ip string */
1306 rdp_in_unistr(s
, g_redirect_server
, len
);
1308 /* read length of cookie string */
1309 in_uint32_le(s
, len
);
1311 /* read cookie string (plain ASCII) */
1312 in_uint8a(s
, g_redirect_cookie
, len
);
1313 g_redirect_cookie
[len
] = 0;
1315 /* read length of username string */
1316 in_uint32_le(s
, len
);
1318 /* read username string */
1319 rdp_in_unistr(s
, g_redirect_username
, len
);
1321 /* read length of domain string */
1322 in_uint32_le(s
, len
);
1324 /* read domain string */
1325 rdp_in_unistr(s
, g_redirect_domain
, len
);
1327 /* read length of password string */
1328 in_uint32_le(s
, len
);
1330 /* read password string */
1331 rdp_in_unistr(s
, g_redirect_password
, len
);
1338 /* Process incoming packets */
1339 /* nevers gets out of here till app is done */
1341 rdp_main_loop(BOOL
* deactivated
, uint32
* ext_disc_reason
)
1343 while (rdp_loop(deactivated
, ext_disc_reason
))
1347 /* used in uiports and rdp_main_loop, processes the rdp packets waiting */
1349 rdp_loop(BOOL
* deactivated
, uint32
* ext_disc_reason
)
1352 BOOL disc
= False
; /* True when a disconnect PDU was received */
1358 s
= rdp_recv(&type
);
1363 case RDP_PDU_DEMAND_ACTIVE
:
1364 process_demand_active(s
);
1365 *deactivated
= False
;
1367 case RDP_PDU_DEACTIVATE
:
1368 DEBUG(("RDP_PDU_DEACTIVATE\n"));
1369 *deactivated
= True
;
1371 case RDP_PDU_REDIRECT
:
1372 return process_redirect_pdu(s
);
1375 disc
= process_data_pdu(s
, ext_disc_reason
);
1380 unimpl("PDU %d\n", type
);
1384 cont
= g_next_packet
< s
->end
;
1389 /* Establish a connection up to the RDP layer */
1391 rdp_connect(char *server
, uint32 flags
, char *domain
, char *password
,
1392 char *command
, char *directory
)
1394 if (!sec_connect(server
, g_username
))
1397 rdp_send_logon_info(flags
, domain
, g_username
, password
, command
, directory
);
1401 /* Establish a reconnection up to the RDP layer */
1403 rdp_reconnect(char *server
, uint32 flags
, char *domain
, char *password
,
1404 char *command
, char *directory
, char *cookie
)
1406 if (!sec_reconnect(server
))
1409 rdp_send_logon_info(flags
, domain
, g_username
, password
, command
, directory
);
1413 /* Called during redirection to reset the state to support redirection */
1415 rdp_reset_state(void)
1417 g_next_packet
= NULL
; /* reset the packet information */
1422 /* Disconnect from the RDP layer */
1424 rdp_disconnect(void)