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.
32 #define ICONV_CONST ""
36 /* Receive an RDP packet */
38 rdp_recv(RDPCLIENT
* This
, uint8
* type
)
40 static STREAM rdp_s
; // FIXME HORROR
41 uint16 length
, pdu_type
;
44 if ((rdp_s
== NULL
) || (This
->next_packet
>= rdp_s
->end
) || (This
->next_packet
== NULL
))
46 rdp_s
= sec_recv(This
, &rdpver
);
51 This
->next_packet
= rdp_s
->end
;
57 /* rdp5_process should move This->next_packet ok */
58 if(!rdp5_process(This
, rdp_s
))
64 This
->next_packet
= rdp_s
->p
;
68 rdp_s
->p
= This
->next_packet
;
71 in_uint16_le(rdp_s
, length
);
72 /* 32k packets are really 8, keepalive fix */
75 This
->next_packet
+= 8;
79 in_uint16_le(rdp_s
, pdu_type
);
80 in_uint8s(rdp_s
, 2); /* userid */
81 *type
= pdu_type
& 0xf;
84 DEBUG(("RDP packet #%d, (type %x)\n", ++This
->rdp
.packetno
, *type
));
85 hexdump(This
->next_packet
, length
);
88 This
->next_packet
+= length
;
92 /* Initialise an RDP data packet */
94 rdp_init_data(RDPCLIENT
* This
, int maxlen
)
98 s
= sec_init(This
, This
->encryption
? SEC_ENCRYPT
: 0, maxlen
+ 18);
103 s_push_layer(s
, rdp_hdr
, 18);
108 /* Send an RDP data packet */
110 rdp_send_data(RDPCLIENT
* This
, STREAM s
, uint8 data_pdu_type
)
114 s_pop_layer(s
, rdp_hdr
);
115 length
= (uint16
)(s
->end
- s
->p
);
117 out_uint16_le(s
, length
);
118 out_uint16_le(s
, (RDP_PDU_DATA
| 0x10));
119 out_uint16_le(s
, (This
->mcs_userid
+ 1001));
121 out_uint32_le(s
, This
->rdp_shareid
);
122 out_uint8(s
, 0); /* pad */
123 out_uint8(s
, 1); /* streamid */
124 out_uint16_le(s
, (length
- 14));
125 out_uint8(s
, data_pdu_type
);
126 out_uint8(s
, 0); /* compress_type */
127 out_uint16(s
, 0); /* compress_len */
129 return sec_send(This
, s
, This
->encryption
? SEC_ENCRYPT
: 0);
132 /* Output a string in Unicode */
134 rdp_out_unistr(RDPCLIENT
* This
, STREAM s
, wchar_t *string
, int len
)
137 size_t ibl
= strlen(string
), obl
= len
+ 2;
138 static iconv_t iconv_h
= (iconv_t
) - 1;
139 char *pin
= string
, *pout
= (char *) s
->p
;
141 memset(pout
, 0, len
+ 4);
143 if (This
->rdp
.iconv_works
)
145 if (iconv_h
== (iconv_t
) - 1)
148 if ((iconv_h
= iconv_open(WINDOWS_CODEPAGE
, This
->codepage
)) == (iconv_t
) - 1)
150 warning("rdp_out_unistr: iconv_open[%s -> %s] fail %d\n",
151 This
->codepage
, WINDOWS_CODEPAGE
, (int) iconv_h
);
153 This
->rdp
.iconv_works
= False
;
154 rdp_out_unistr(This
, s
, string
, len
);
157 if (iconv(iconv_h
, (ICONV_CONST
char **) &pin
, &i
, &pout
, &o
) ==
160 iconv_close(iconv_h
);
161 iconv_h
= (iconv_t
) - 1;
162 warning("rdp_out_unistr: iconv(1) fail, errno %d\n", errno
);
164 This
->rdp
.iconv_works
= False
;
165 rdp_out_unistr(This
, s
, string
, len
);
169 pout
= (char *) s
->p
;
172 if (iconv(iconv_h
, (ICONV_CONST
char **) &pin
, &ibl
, &pout
, &obl
) == (size_t) - 1)
174 iconv_close(iconv_h
);
175 iconv_h
= (iconv_t
) - 1;
176 warning("rdp_out_unistr: iconv(2) fail, errno %d\n", errno
);
178 This
->rdp
.iconv_works
= False
;
179 rdp_out_unistr(This
, s
, string
, len
);
197 s
->p
[i
++] = (c
>> 0) & 0xFF;
198 s
->p
[i
++] = (c
>> 8) & 0xFF;
205 /* Input a string in Unicode
207 * Returns str_len of string
210 rdp_in_unistr(RDPCLIENT
* This
, STREAM s
, wchar_t *string
, int uni_len
)
213 size_t ibl
= uni_len
, obl
= uni_len
;
214 char *pin
= (char *) s
->p
, *pout
= string
;
215 static iconv_t iconv_h
= (iconv_t
) - 1;
217 if (This
->rdp
.iconv_works
)
219 if (iconv_h
== (iconv_t
) - 1)
221 if ((iconv_h
= iconv_open(This
->codepage
, WINDOWS_CODEPAGE
)) == (iconv_t
) - 1)
223 warning("rdp_in_unistr: iconv_open[%s -> %s] fail %d\n",
224 WINDOWS_CODEPAGE
, This
->codepage
, (int) iconv_h
);
226 This
->rdp
.iconv_works
= False
;
227 return rdp_in_unistr(This
, s
, string
, uni_len
);
231 if (iconv(iconv_h
, (ICONV_CONST
char **) &pin
, &ibl
, &pout
, &obl
) == (size_t) - 1)
233 iconv_close(iconv_h
);
234 iconv_h
= (iconv_t
) - 1;
235 warning("rdp_in_unistr: iconv fail, errno %d\n", errno
);
237 This
->rdp
.iconv_works
= False
;
238 return rdp_in_unistr(This
, s
, string
, uni_len
);
241 /* we must update the location of the current STREAM for future reads of s->p */
244 return pout
- string
;
252 while (i
< uni_len
/ 2)
254 in_uint8a(s
, &string
[i
++], 1);
263 /* Parse a logon info packet */
265 rdp_send_logon_info(RDPCLIENT
* This
, uint32 flags
, wchar_t *domain
, wchar_t *user
,
266 wchar_t *password
, wchar_t *program
, wchar_t *directory
)
268 wchar_t *ipaddr
= tcp_get_address(This
);
269 int len_domain
= 2 * (int)wcslen(domain
);
270 int len_user
= 2 * (int)wcslen(user
);
271 int len_password
= 2 * (int)wcslen(password
);
272 int len_program
= 2 * (int)wcslen(program
);
273 int len_directory
= 2 * (int)wcslen(directory
);
274 int len_ip
= 2 * (int)wcslen(ipaddr
);
275 int len_dll
= 2 * (int)wcslen(L
"C:\\WINNT\\System32\\mstscax.dll");
277 uint32 sec_flags
= This
->encryption
? (SEC_LOGON_INFO
| SEC_ENCRYPT
) : SEC_LOGON_INFO
;
279 time_t t
= time(NULL
);
282 if (!This
->use_rdp5
|| 1 == This
->server_rdp_version
)
284 DEBUG_RDP5(("Sending RDP4-style Logon packet\n"));
286 s
= sec_init(This
, sec_flags
, 18 + len_domain
+ len_user
+ len_password
287 + len_program
+ len_directory
+ 10);
293 out_uint32_le(s
, flags
);
294 out_uint16_le(s
, len_domain
);
295 out_uint16_le(s
, len_user
);
296 out_uint16_le(s
, len_password
);
297 out_uint16_le(s
, len_program
);
298 out_uint16_le(s
, len_directory
);
299 rdp_out_unistr(This
, s
, domain
, len_domain
);
300 rdp_out_unistr(This
, s
, user
, len_user
);
301 rdp_out_unistr(This
, s
, password
, len_password
);
302 rdp_out_unistr(This
, s
, program
, len_program
);
303 rdp_out_unistr(This
, s
, directory
, len_directory
);
308 flags
|= RDP_LOGON_BLOB
;
309 DEBUG_RDP5(("Sending RDP5-style Logon packet\n"));
310 packetlen
= 4 + /* Unknown uint32 */
314 (flags
& RDP_LOGON_AUTO
? 2 : 0) + /* len_password */
315 (flags
& RDP_LOGON_BLOB
? 2 : 0) + /* Length of BLOB */
316 2 + /* len_program */
317 2 + /* len_directory */
318 (0 < len_domain
? len_domain
: 2) + /* domain */
319 len_user
+ (flags
& RDP_LOGON_AUTO
? len_password
: 0) + 0 + /* We have no 512 byte BLOB. Perhaps we must? */
320 (flags
& RDP_LOGON_BLOB
&& !(flags
& RDP_LOGON_AUTO
) ? 2 : 0) + /* After the BLOB is a unknown int16. If there is a BLOB, that is. */
321 (0 < len_program
? len_program
: 2) + (0 < len_directory
? len_directory
: 2) + 2 + /* Unknown (2) */
322 2 + /* Client ip length */
323 len_ip
+ /* Client ip */
324 2 + /* DLL string length */
325 len_dll
+ /* DLL string */
328 64 + /* Time zone #0 */
330 64 + /* Time zone #1 */
333 s
= sec_init(This
, sec_flags
, packetlen
);
334 DEBUG_RDP5(("Called sec_init with packetlen %d\n", packetlen
));
339 out_uint32(s
, 0); /* Unknown */
340 out_uint32_le(s
, flags
);
341 out_uint16_le(s
, len_domain
);
342 out_uint16_le(s
, len_user
);
343 if (flags
& RDP_LOGON_AUTO
)
345 out_uint16_le(s
, len_password
);
348 if (flags
& RDP_LOGON_BLOB
&& !(flags
& RDP_LOGON_AUTO
))
352 out_uint16_le(s
, len_program
);
353 out_uint16_le(s
, len_directory
);
355 rdp_out_unistr(This
, s
, domain
, len_domain
);
358 rdp_out_unistr(This
, s
, user
, len_user
);
359 if (flags
& RDP_LOGON_AUTO
)
361 rdp_out_unistr(This
, s
, password
, len_password
);
363 if (flags
& RDP_LOGON_BLOB
&& !(flags
& RDP_LOGON_AUTO
))
369 rdp_out_unistr(This
, s
, program
, len_program
);
376 if (0 < len_directory
)
378 rdp_out_unistr(This
, s
, directory
, len_directory
);
385 out_uint16_le(s
, len_ip
+ 2); /* Length of client ip */
386 rdp_out_unistr(This
, s
, ipaddr
, len_ip
);
387 out_uint16_le(s
, len_dll
+ 2);
388 rdp_out_unistr(This
, s
, L
"C:\\WINNT\\System32\\mstscax.dll", len_dll
);
390 tzone
= (mktime(gmtime(&t
)) - mktime(localtime(&t
))) / 60;
391 out_uint32_le(s
, (uint32
)tzone
);
393 rdp_out_unistr(This
, s
, L
"GTB, normaltid", 2 * (int)wcslen(L
"GTB, normaltid"));
394 out_uint8s(s
, 62 - 2 * wcslen(L
"GTB, normaltid"));
396 out_uint32_le(s
, 0x0a0000);
397 out_uint32_le(s
, 0x050000);
402 rdp_out_unistr(This
, s
, L
"GTB, sommartid", 2 * (int)wcslen(L
"GTB, sommartid"));
403 out_uint8s(s
, 62 - 2 * wcslen(L
"GTB, sommartid"));
405 out_uint32_le(s
, 0x30000);
406 out_uint32_le(s
, 0x050000);
409 out_uint32_le(s
, 0xffffffc4);
410 out_uint32_le(s
, 0xfffffffe);
411 out_uint32_le(s
, This
->rdp5_performanceflags
);
417 return sec_send(This
, s
, sec_flags
);
420 /* Send a control PDU */
422 rdp_send_control(RDPCLIENT
* This
, uint16 action
)
426 s
= rdp_init_data(This
, 8);
431 out_uint16_le(s
, action
);
432 out_uint16(s
, 0); /* userid */
433 out_uint32(s
, 0); /* control id */
436 return rdp_send_data(This
, s
, RDP_DATA_PDU_CONTROL
);
439 /* Send a synchronisation PDU */
441 rdp_send_synchronise(RDPCLIENT
* This
)
445 s
= rdp_init_data(This
, 4);
450 out_uint16_le(s
, 1); /* type */
451 out_uint16_le(s
, 1002);
454 return rdp_send_data(This
, s
, RDP_DATA_PDU_SYNCHRONISE
);
457 /* Send a single input event */
459 rdp_send_input(RDPCLIENT
* This
, uint32 time
, uint16 message_type
, uint16 device_flags
, uint16 param1
, uint16 param2
)
463 s
= rdp_init_data(This
, 16);
468 out_uint16_le(s
, 1); /* number of events */
469 out_uint16(s
, 0); /* pad */
471 out_uint32_le(s
, time
);
472 out_uint16_le(s
, message_type
);
473 out_uint16_le(s
, device_flags
);
474 out_uint16_le(s
, param1
);
475 out_uint16_le(s
, param2
);
478 return rdp_send_data(This
, s
, RDP_DATA_PDU_INPUT
);
481 /* Send a client window information PDU */
483 rdp_send_client_window_status(RDPCLIENT
* This
, int status
)
487 if (This
->rdp
.current_status
== status
)
490 s
= rdp_init_data(This
, 12);
495 out_uint32_le(s
, status
);
499 case 0: /* shut the server up */
502 case 1: /* receive data again */
503 out_uint32_le(s
, 0); /* unknown */
504 out_uint16_le(s
, This
->width
);
505 out_uint16_le(s
, This
->height
);
510 This
->rdp
.current_status
= status
;
511 return rdp_send_data(This
, s
, RDP_DATA_PDU_CLIENT_WINDOW_STATUS
);
514 /* Send persistent bitmap cache enumeration PDU's */
516 rdp_enum_bmpcache2(RDPCLIENT
* This
) // THIS
519 HASH_KEY keylist
[BMPCACHE2_NUM_PSTCELLS
];
520 uint32 num_keys
, offset
, count
, flags
;
523 num_keys
= pstcache_enumerate(This
, 2, keylist
);
525 while (offset
< num_keys
)
527 count
= MIN(num_keys
- offset
, 169);
529 s
= rdp_init_data(This
, 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 if(!rdp_send_data(This
, s
, 0x2b))
564 /* Send an (empty) font information PDU */
566 rdp_send_fonts(RDPCLIENT
* This
, uint16 seq
)
570 s
= rdp_init_data(This
, 8);
575 out_uint16(s
, 0); /* number of fonts */
576 out_uint16_le(s
, 0); /* pad? */
577 out_uint16_le(s
, seq
); /* unknown */
578 out_uint16_le(s
, 0x32); /* entry size */
581 return rdp_send_data(This
, s
, RDP_DATA_PDU_FONT2
);
584 /* Output general capability set */
586 rdp_out_general_caps(RDPCLIENT
* This
, STREAM s
)
588 out_uint16_le(s
, RDP_CAPSET_GENERAL
);
589 out_uint16_le(s
, RDP_CAPLEN_GENERAL
);
591 out_uint16_le(s
, 1); /* OS major type */
592 out_uint16_le(s
, 3); /* OS minor type */
593 out_uint16_le(s
, 0x200); /* Protocol version */
594 out_uint16(s
, 0); /* Pad */
595 out_uint16(s
, 0); /* Compression types */
596 out_uint16_le(s
, This
->use_rdp5
? 0x40d : 0);
597 /* Pad, according to T.128. 0x40d seems to
599 the server to start sending RDP5 packets.
600 However, the value is 0x1d04 with W2KTSK and
601 NT4MS. Hmm.. Anyway, thankyou, Microsoft,
602 for sending such information in a padding
604 out_uint16(s
, 0); /* Update capability */
605 out_uint16(s
, 0); /* Remote unshare capability */
606 out_uint16(s
, 0); /* Compression level */
607 out_uint16(s
, 0); /* Pad */
610 /* Output bitmap capability set */
612 rdp_out_bitmap_caps(RDPCLIENT
* This
, STREAM s
)
614 out_uint16_le(s
, RDP_CAPSET_BITMAP
);
615 out_uint16_le(s
, RDP_CAPLEN_BITMAP
);
617 out_uint16_le(s
, This
->server_depth
); /* Preferred colour depth */
618 out_uint16_le(s
, 1); /* Receive 1 BPP */
619 out_uint16_le(s
, 1); /* Receive 4 BPP */
620 out_uint16_le(s
, 1); /* Receive 8 BPP */
621 out_uint16_le(s
, 800); /* Desktop width */
622 out_uint16_le(s
, 600); /* Desktop height */
623 out_uint16(s
, 0); /* Pad */
624 out_uint16(s
, 1); /* Allow resize */
625 out_uint16_le(s
, This
->bitmap_compression
? 1 : 0); /* Support compression */
626 out_uint16(s
, 0); /* Unknown */
627 out_uint16_le(s
, 1); /* Unknown */
628 out_uint16(s
, 0); /* Pad */
631 /* Output order capability set */
633 rdp_out_order_caps(RDPCLIENT
* This
, STREAM s
)
635 uint8 order_caps
[32];
637 memset(order_caps
, 0, 32);
638 order_caps
[0] = 1; /* dest blt */
639 order_caps
[1] = 1; /* pat blt */
640 order_caps
[2] = 1; /* screen blt */
641 order_caps
[3] = (This
->bitmap_cache
? 1 : 0); /* memblt */
642 order_caps
[4] = 0; /* triblt */
643 order_caps
[8] = 1; /* line */
644 order_caps
[9] = 1; /* line */
645 order_caps
[10] = 1; /* rect */
646 order_caps
[11] = (This
->desktop_save
? 1 : 0); /* desksave */
647 order_caps
[13] = 1; /* memblt */
648 order_caps
[14] = 1; /* triblt */
649 order_caps
[20] = (This
->polygon_ellipse_orders
? 1 : 0); /* polygon */
650 order_caps
[21] = (This
->polygon_ellipse_orders
? 1 : 0); /* polygon2 */
651 order_caps
[22] = 1; /* polyline */
652 order_caps
[25] = (This
->polygon_ellipse_orders
? 1 : 0); /* ellipse */
653 order_caps
[26] = (This
->polygon_ellipse_orders
? 1 : 0); /* ellipse2 */
654 order_caps
[27] = 1; /* text2 */
655 out_uint16_le(s
, RDP_CAPSET_ORDER
);
656 out_uint16_le(s
, RDP_CAPLEN_ORDER
);
658 out_uint8s(s
, 20); /* Terminal desc, pad */
659 out_uint16_le(s
, 1); /* Cache X granularity */
660 out_uint16_le(s
, 20); /* Cache Y granularity */
661 out_uint16(s
, 0); /* Pad */
662 out_uint16_le(s
, 1); /* Max order level */
663 out_uint16_le(s
, 0x147); /* Number of fonts */
664 out_uint16_le(s
, 0x2a); /* Capability flags */
665 out_uint8p(s
, order_caps
, 32); /* Orders supported */
666 out_uint16_le(s
, 0x6a1); /* Text capability flags */
667 out_uint8s(s
, 6); /* Pad */
668 out_uint32_le(s
, This
->desktop_save
== False
? 0 : 0x38400); /* Desktop cache size */
669 out_uint32(s
, 0); /* Unknown */
670 out_uint32_le(s
, 0x4e4); /* Unknown */
673 /* Output bitmap cache capability set */
675 rdp_out_bmpcache_caps(RDPCLIENT
* This
, STREAM s
)
678 out_uint16_le(s
, RDP_CAPSET_BMPCACHE
);
679 out_uint16_le(s
, RDP_CAPLEN_BMPCACHE
);
681 Bpp
= (This
->server_depth
+ 7) / 8; /* bytes per pixel */
682 out_uint8s(s
, 24); /* unused */
683 out_uint16_le(s
, 0x258); /* entries */
684 out_uint16_le(s
, 0x100 * Bpp
); /* max cell size */
685 out_uint16_le(s
, 0x12c); /* entries */
686 out_uint16_le(s
, 0x400 * Bpp
); /* max cell size */
687 out_uint16_le(s
, 0x106); /* entries */
688 out_uint16_le(s
, 0x1000 * Bpp
); /* max cell size */
691 /* Output bitmap cache v2 capability set */
693 rdp_out_bmpcache2_caps(RDPCLIENT
* This
, STREAM s
)
695 out_uint16_le(s
, RDP_CAPSET_BMPCACHE2
);
696 out_uint16_le(s
, RDP_CAPLEN_BMPCACHE2
);
698 out_uint16_le(s
, This
->bitmap_cache_persist_enable
? 2 : 0); /* version */
700 out_uint16_be(s
, 3); /* number of caches in this set */
702 /* max cell size for cache 0 is 16x16, 1 = 32x32, 2 = 64x64, etc */
703 out_uint32_le(s
, BMPCACHE2_C0_CELLS
);
704 out_uint32_le(s
, BMPCACHE2_C1_CELLS
);
705 if (pstcache_init(This
, 2))
707 out_uint32_le(s
, BMPCACHE2_NUM_PSTCELLS
| BMPCACHE2_FLAG_PERSIST
);
711 out_uint32_le(s
, BMPCACHE2_C2_CELLS
);
713 out_uint8s(s
, 20); /* other bitmap caches not used */
716 /* Output control capability set */
718 rdp_out_control_caps(STREAM s
)
720 out_uint16_le(s
, RDP_CAPSET_CONTROL
);
721 out_uint16_le(s
, RDP_CAPLEN_CONTROL
);
723 out_uint16(s
, 0); /* Control capabilities */
724 out_uint16(s
, 0); /* Remote detach */
725 out_uint16_le(s
, 2); /* Control interest */
726 out_uint16_le(s
, 2); /* Detach interest */
729 /* Output activation capability set */
731 rdp_out_activate_caps(STREAM s
)
733 out_uint16_le(s
, RDP_CAPSET_ACTIVATE
);
734 out_uint16_le(s
, RDP_CAPLEN_ACTIVATE
);
736 out_uint16(s
, 0); /* Help key */
737 out_uint16(s
, 0); /* Help index key */
738 out_uint16(s
, 0); /* Extended help key */
739 out_uint16(s
, 0); /* Window activate */
742 /* Output pointer capability set */
744 rdp_out_pointer_caps(STREAM s
)
746 out_uint16_le(s
, RDP_CAPSET_POINTER
);
747 out_uint16_le(s
, RDP_CAPLEN_POINTER
);
749 out_uint16(s
, 0); /* Colour pointer */
750 out_uint16_le(s
, 20); /* Cache size */
753 /* Output share capability set */
755 rdp_out_share_caps(STREAM s
)
757 out_uint16_le(s
, RDP_CAPSET_SHARE
);
758 out_uint16_le(s
, RDP_CAPLEN_SHARE
);
760 out_uint16(s
, 0); /* userid */
761 out_uint16(s
, 0); /* pad */
764 /* Output colour cache capability set */
766 rdp_out_colcache_caps(STREAM s
)
768 out_uint16_le(s
, RDP_CAPSET_COLCACHE
);
769 out_uint16_le(s
, RDP_CAPLEN_COLCACHE
);
771 out_uint16_le(s
, 6); /* cache size */
772 out_uint16(s
, 0); /* pad */
775 static const uint8 caps_0x0d
[] = {
776 0x01, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00,
777 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
778 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
779 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
780 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
781 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
782 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
783 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
784 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
785 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
786 0x00, 0x00, 0x00, 0x00
789 static const uint8 caps_0x0c
[] = { 0x01, 0x00, 0x00, 0x00 };
791 static const uint8 caps_0x0e
[] = { 0x01, 0x00, 0x00, 0x00 };
793 static const uint8 caps_0x10
[] = {
794 0xFE, 0x00, 0x04, 0x00, 0xFE, 0x00, 0x04, 0x00,
795 0xFE, 0x00, 0x08, 0x00, 0xFE, 0x00, 0x08, 0x00,
796 0xFE, 0x00, 0x10, 0x00, 0xFE, 0x00, 0x20, 0x00,
797 0xFE, 0x00, 0x40, 0x00, 0xFE, 0x00, 0x80, 0x00,
798 0xFE, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x08,
799 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00
802 /* Output unknown capability sets */
804 rdp_out_unknown_caps(STREAM s
, uint16 id
, uint16 length
, const uint8
* caps
)
806 out_uint16_le(s
, id
);
807 out_uint16_le(s
, length
);
809 out_uint8p(s
, caps
, length
- 4);
812 #define RDP5_FLAG 0x0030
813 /* Send a confirm active PDU */
815 rdp_send_confirm_active(RDPCLIENT
* This
)
818 uint32 sec_flags
= This
->encryption
? (RDP5_FLAG
| SEC_ENCRYPT
) : RDP5_FLAG
;
820 RDP_CAPLEN_GENERAL
+ RDP_CAPLEN_BITMAP
+ RDP_CAPLEN_ORDER
+
821 RDP_CAPLEN_BMPCACHE
+ RDP_CAPLEN_COLCACHE
+
822 RDP_CAPLEN_ACTIVATE
+ RDP_CAPLEN_CONTROL
+
823 RDP_CAPLEN_POINTER
+ RDP_CAPLEN_SHARE
+
824 0x58 + 0x08 + 0x08 + 0x34 /* unknown caps */ +
825 4 /* w2k fix, why? */ ;
827 s
= sec_init(This
, sec_flags
, 6 + 14 + caplen
+ sizeof(RDP_SOURCE
));
832 out_uint16_le(s
, 2 + 14 + caplen
+ sizeof(RDP_SOURCE
));
833 out_uint16_le(s
, (RDP_PDU_CONFIRM_ACTIVE
| 0x10)); /* Version 1 */
834 out_uint16_le(s
, (This
->mcs_userid
+ 1001));
836 out_uint32_le(s
, This
->rdp_shareid
);
837 out_uint16_le(s
, 0x3ea); /* userid */
838 out_uint16_le(s
, sizeof(RDP_SOURCE
));
839 out_uint16_le(s
, caplen
);
841 out_uint8p(s
, RDP_SOURCE
, sizeof(RDP_SOURCE
));
842 out_uint16_le(s
, 0xd); /* num_caps */
843 out_uint8s(s
, 2); /* pad */
845 rdp_out_general_caps(This
, s
);
846 rdp_out_bitmap_caps(This
, s
);
847 rdp_out_order_caps(This
, s
);
848 This
->use_rdp5
? rdp_out_bmpcache2_caps(This
, s
) : rdp_out_bmpcache_caps(This
, s
);
849 rdp_out_colcache_caps(s
);
850 rdp_out_activate_caps(s
);
851 rdp_out_control_caps(s
);
852 rdp_out_pointer_caps(s
);
853 rdp_out_share_caps(s
);
855 rdp_out_unknown_caps(s
, 0x0d, 0x58, caps_0x0d
); /* international? */
856 rdp_out_unknown_caps(s
, 0x0c, 0x08, caps_0x0c
);
857 rdp_out_unknown_caps(s
, 0x0e, 0x08, caps_0x0e
);
858 rdp_out_unknown_caps(s
, 0x10, 0x34, caps_0x10
); /* glyph cache? */
861 return sec_send(This
, s
, sec_flags
);
864 /* Process a general capability set */
866 rdp_process_general_caps(RDPCLIENT
* This
, STREAM s
)
868 uint16 pad2octetsB
; /* rdp5 flags? */
871 in_uint16_le(s
, pad2octetsB
);
874 This
->use_rdp5
= False
;
877 /* Process a bitmap capability set */
879 rdp_process_bitmap_caps(RDPCLIENT
* This
, STREAM s
)
881 uint16 width
, height
, depth
;
883 in_uint16_le(s
, depth
);
886 in_uint16_le(s
, width
);
887 in_uint16_le(s
, height
);
889 DEBUG(("setting desktop size and depth to: %dx%dx%d\n", width
, height
, depth
));
892 * The server may limit depth and change the size of the desktop (for
893 * example when shadowing another session).
895 if (This
->server_depth
!= depth
)
897 warning("Remote desktop does not support colour depth %d; falling back to %d\n",
898 This
->server_depth
, depth
);
899 This
->server_depth
= depth
;
901 if (This
->width
!= width
|| This
->height
!= height
)
903 warning("Remote desktop changed from %dx%d to %dx%d.\n", This
->width
, This
->height
,
906 This
->height
= height
;
907 ui_resize_window(This
);
911 /* Process server capabilities */
913 rdp_process_server_caps(RDPCLIENT
* This
, STREAM s
, uint16 length
)
917 uint16 ncapsets
, capset_type
, capset_length
;
921 in_uint16_le(s
, ncapsets
);
922 in_uint8s(s
, 2); /* pad */
924 for (n
= 0; n
< ncapsets
; n
++)
926 if (s
->p
> start
+ length
)
929 in_uint16_le(s
, capset_type
);
930 in_uint16_le(s
, capset_length
);
932 next
= s
->p
+ capset_length
- 4;
936 case RDP_CAPSET_GENERAL
:
937 rdp_process_general_caps(This
, s
);
940 case RDP_CAPSET_BITMAP
:
941 rdp_process_bitmap_caps(This
, s
);
949 /* Respond to a demand active PDU */
951 process_demand_active(RDPCLIENT
* This
, STREAM s
)
954 uint16 len_src_descriptor
, len_combined_caps
;
956 in_uint32_le(s
, This
->rdp_shareid
);
957 in_uint16_le(s
, len_src_descriptor
);
958 in_uint16_le(s
, len_combined_caps
);
959 in_uint8s(s
, len_src_descriptor
);
961 DEBUG(("DEMAND_ACTIVE(id=0x%x)\n", This
->rdp_shareid
));
962 rdp_process_server_caps(This
, s
, len_combined_caps
);
966 !rdp_send_confirm_active(This
) ||
967 !rdp_send_synchronise(This
) ||
968 !rdp_send_control(This
, RDP_CTL_COOPERATE
) ||
969 !rdp_send_control(This
, RDP_CTL_REQUEST_CONTROL
) ||
970 !rdp_recv(This
, &type
) || /* RDP_PDU_SYNCHRONIZE */
971 !rdp_recv(This
, &type
) || /* RDP_CTL_COOPERATE */
972 !rdp_recv(This
, &type
) || /* RDP_CTL_GRANT_CONTROL */
973 !rdp_send_input(This
, 0, RDP_INPUT_SYNCHRONIZE
, 0,
974 /*This->numlock_sync ? ui_get_numlock_state(This, read_keyboard_state(This)) :*/ 0, 0) // TODO: keyboard mess
980 if(!rdp_enum_bmpcache2(This
) || !rdp_send_fonts(This
, 3))
985 if(!rdp_send_fonts(This
, 1) || !rdp_send_fonts(This
, 2))
989 if(!rdp_recv(This
, &type
)) /* RDP_PDU_UNKNOWN 0x28 (Fonts?) */
992 reset_order_state(This
);
996 /* Process a colour pointer PDU */
998 process_colour_pointer_pdu(RDPCLIENT
* This
, STREAM s
)
1000 uint16 x
, y
, width
, height
, cache_idx
, masklen
, datalen
;
1004 in_uint16_le(s
, cache_idx
);
1007 in_uint16_le(s
, width
);
1008 in_uint16_le(s
, height
);
1009 in_uint16_le(s
, masklen
);
1010 in_uint16_le(s
, datalen
);
1011 in_uint8p(s
, data
, datalen
);
1012 in_uint8p(s
, mask
, masklen
);
1013 cursor
= ui_create_cursor(This
, x
, y
, width
, height
, mask
, data
);
1014 ui_set_cursor(This
, cursor
);
1015 cache_put_cursor(This
, cache_idx
, cursor
);
1018 /* Process a cached pointer PDU */
1020 process_cached_pointer_pdu(RDPCLIENT
* This
, STREAM s
)
1024 in_uint16_le(s
, cache_idx
);
1025 ui_set_cursor(This
, cache_get_cursor(This
, cache_idx
));
1028 /* Process a system pointer PDU */
1030 process_system_pointer_pdu(RDPCLIENT
* This
, STREAM s
)
1032 uint16 system_pointer_type
;
1034 in_uint16(s
, system_pointer_type
);
1035 switch (system_pointer_type
)
1037 case RDP_NULL_POINTER
:
1038 ui_set_null_cursor(This
);
1042 unimpl("System pointer message 0x%x\n", system_pointer_type
);
1046 /* Process a pointer PDU */
1048 process_pointer_pdu(RDPCLIENT
* This
, STREAM s
)
1050 uint16 message_type
;
1053 in_uint16_le(s
, message_type
);
1054 in_uint8s(s
, 2); /* pad */
1056 switch (message_type
)
1058 case RDP_POINTER_MOVE
:
1062 ui_move_pointer(This
, x
, y
);
1065 case RDP_POINTER_COLOR
:
1066 process_colour_pointer_pdu(This
, s
);
1069 case RDP_POINTER_CACHED
:
1070 process_cached_pointer_pdu(This
, s
);
1073 case RDP_POINTER_SYSTEM
:
1074 process_system_pointer_pdu(This
, s
);
1078 unimpl("Pointer message 0x%x\n", message_type
);
1082 /* Process bitmap updates */
1084 process_bitmap_updates(RDPCLIENT
* This
, STREAM s
)
1087 uint16 left
, top
, right
, bottom
, width
, height
;
1088 uint16 cx
, cy
, bpp
, Bpp
, compress
, bufsize
, size
;
1089 uint8
*data
, *bmpdata
;
1092 in_uint16_le(s
, num_updates
);
1094 for (i
= 0; i
< num_updates
; i
++)
1096 in_uint16_le(s
, left
);
1097 in_uint16_le(s
, top
);
1098 in_uint16_le(s
, right
);
1099 in_uint16_le(s
, bottom
);
1100 in_uint16_le(s
, width
);
1101 in_uint16_le(s
, height
);
1102 in_uint16_le(s
, bpp
);
1103 Bpp
= (bpp
+ 7) / 8;
1104 in_uint16_le(s
, compress
);
1105 in_uint16_le(s
, bufsize
);
1107 cx
= right
- left
+ 1;
1108 cy
= bottom
- top
+ 1;
1110 DEBUG(("BITMAP_UPDATE(l=%d,t=%d,r=%d,b=%d,w=%d,h=%d,Bpp=%d,cmp=%d)\n",
1111 left
, top
, right
, bottom
, width
, height
, Bpp
, compress
));
1117 bmpdata
= (uint8
*) xmalloc(width
* height
* Bpp
);
1118 for (y
= 0; y
< height
; y
++)
1120 in_uint8a(s
, &bmpdata
[(height
- y
- 1) * (width
* Bpp
)],
1123 ui_paint_bitmap(This
, left
, top
, cx
, cy
, width
, height
, bmpdata
);
1126 in_uint8p(s
, bmpdata
, width
* height
* Bpp
);
1127 ui_paint_bitmap(This
, left
, top
, cx
, cy
, width
, height
, bmpdata
);
1133 if (compress
& 0x400)
1139 in_uint8s(s
, 2); /* pad */
1140 in_uint16_le(s
, size
);
1141 in_uint8s(s
, 4); /* line_size, final_size */
1143 in_uint8p(s
, data
, size
);
1144 bmpdata
= (uint8
*) malloc(width
* height
* Bpp
);
1149 if (bitmap_decompress(bmpdata
, width
, height
, data
, size
, Bpp
))
1151 ui_paint_bitmap(This
, left
, top
, cx
, cy
, width
, height
, bmpdata
);
1155 DEBUG_RDP5(("Failed to decompress data\n"));
1162 /* Process a palette update */
1164 process_palette(RDPCLIENT
* This
, STREAM s
)
1171 in_uint8s(s
, 2); /* pad */
1172 in_uint16_le(s
, map
.ncolours
);
1173 in_uint8s(s
, 2); /* pad */
1175 map
.colours
= (COLOURENTRY
*) malloc(sizeof(COLOURENTRY
) * map
.ncolours
);
1177 if(map
.colours
== NULL
)
1179 in_uint8s(s
, sizeof(*entry
) * map
.ncolours
);
1183 DEBUG(("PALETTE(c=%d)\n", map
.ncolours
));
1185 for (i
= 0; i
< map
.ncolours
; i
++)
1187 entry
= &map
.colours
[i
];
1188 in_uint8(s
, entry
->red
);
1189 in_uint8(s
, entry
->green
);
1190 in_uint8(s
, entry
->blue
);
1193 hmap
= ui_create_colourmap(This
, &map
);
1194 ui_set_colourmap(This
, hmap
);
1199 /* Process an update PDU */
1201 process_update_pdu(RDPCLIENT
* This
, STREAM s
)
1203 uint16 update_type
, count
;
1205 in_uint16_le(s
, update_type
);
1207 ui_begin_update(This
);
1208 switch (update_type
)
1210 case RDP_UPDATE_ORDERS
:
1211 in_uint8s(s
, 2); /* pad */
1212 in_uint16_le(s
, count
);
1213 in_uint8s(s
, 2); /* pad */
1214 process_orders(This
, s
, count
);
1217 case RDP_UPDATE_BITMAP
:
1218 process_bitmap_updates(This
, s
);
1221 case RDP_UPDATE_PALETTE
:
1222 process_palette(This
, s
);
1225 case RDP_UPDATE_SYNCHRONIZE
:
1229 unimpl("update %d\n", update_type
);
1231 ui_end_update(This
);
1234 /* Process a disconnect PDU */
1236 process_disconnect_pdu(STREAM s
, uint32
* ext_disc_reason
)
1238 in_uint32_le(s
, *ext_disc_reason
);
1240 DEBUG(("Received disconnect PDU\n"));
1243 /* Process data PDU */
1245 process_data_pdu(RDPCLIENT
* This
, STREAM s
, uint32
* ext_disc_reason
)
1247 uint8 data_pdu_type
;
1254 struct stream
*ns
= &(This
->mppc_dict
.ns
);
1256 in_uint8s(s
, 6); /* shareid, pad, streamid */
1258 in_uint8(s
, data_pdu_type
);
1263 if (ctype
& RDP_MPPC_COMPRESSED
)
1267 if (len
> RDP_MPPC_DICT_SIZE
)
1268 error("error decompressed packet size exceeds max\n");
1269 if (mppc_expand(This
, s
->p
, clen
, ctype
, &roff
, &rlen
) == -1)
1270 error("error while decompressing packet\n");
1274 /* allocate memory and copy the uncompressed data into the temporary stream */
1275 p
= realloc(ns
->data
, rlen
);
1279 This
->disconnect_reason
= 262;
1283 ns
->data
= (uint8
*) p
;
1285 memcpy((ns
->data
), (unsigned char *) (This
->mppc_dict
.hist
+ roff
), rlen
);
1288 ns
->end
= (ns
->data
+ ns
->size
);
1290 ns
->rdp_hdr
= ns
->p
;
1295 switch (data_pdu_type
)
1297 case RDP_DATA_PDU_UPDATE
:
1298 process_update_pdu(This
, s
);
1301 case RDP_DATA_PDU_CONTROL
:
1302 DEBUG(("Received Control PDU\n"));
1305 case RDP_DATA_PDU_SYNCHRONISE
:
1306 DEBUG(("Received Sync PDU\n"));
1309 case RDP_DATA_PDU_POINTER
:
1310 process_pointer_pdu(This
, s
);
1313 case RDP_DATA_PDU_BELL
:
1317 case RDP_DATA_PDU_LOGON
:
1318 DEBUG(("Received Logon PDU\n"));
1320 /* User logged on */
1323 case RDP_DATA_PDU_DISCONNECT
:
1324 process_disconnect_pdu(s
, ext_disc_reason
);
1326 /* We used to return true and disconnect immediately here, but
1327 * Windows Vista sends a disconnect PDU with reason 0 when
1328 * reconnecting to a disconnected session, and MSTSC doesn't
1329 * drop the connection. I think we should just save the status.
1334 unimpl("data PDU %d\n", data_pdu_type
);
1339 /* Process redirect PDU from Session Directory */
1341 process_redirect_pdu(RDPCLIENT
* This
, STREAM s
/*, uint32 * ext_disc_reason */ )
1351 uint32 username_len
;
1357 uint32 password_len
;
1360 /* these 2 bytes are unknown, seem to be zeros */
1363 /* read connection flags */
1364 in_uint32_le(s
, flags
);
1366 /* read length of ip string */
1367 in_uint32_le(s
, server_len
);
1369 /* read ip string */
1370 server
= (wchar_t *)s
->p
;
1371 in_uint8s(s
, server_len
);
1373 /* read length of cookie string */
1374 in_uint32_le(s
, cookie_len
);
1376 /* read cookie string (plain ASCII) */
1377 cookie
= (char *)s
->p
;
1378 in_uint8s(s
, cookie_len
);
1380 /* read length of username string */
1381 in_uint32_le(s
, username_len
);
1383 /* read username string */
1384 username
= (wchar_t *)s
->p
;
1385 in_uint8s(s
, username_len
);
1387 /* read length of domain string */
1388 in_uint32_le(s
, domain_len
);
1390 /* read domain string */
1391 domain
= (wchar_t *)s
->p
;
1392 in_uint8s(s
, domain_len
);
1394 /* read length of password string */
1395 in_uint32_le(s
, password_len
);
1397 /* read password string */
1398 password
= (wchar_t *)s
->p
;
1399 in_uint8s(s
, password_len
);
1401 This
->redirect
= True
;
1403 return event_redirect
1420 /* Process incoming packets */
1421 /* nevers gets out of here till app is done */
1423 rdp_main_loop(RDPCLIENT
* This
, BOOL
* deactivated
, uint32
* ext_disc_reason
)
1425 while (rdp_loop(This
, deactivated
, ext_disc_reason
))
1429 /* used in uiports and rdp_main_loop, processes the rdp packets waiting */
1431 rdp_loop(RDPCLIENT
* This
, BOOL
* deactivated
, uint32
* ext_disc_reason
)
1434 BOOL disc
= False
; /* True when a disconnect PDU was received */
1440 s
= rdp_recv(This
, &type
);
1445 case RDP_PDU_DEMAND_ACTIVE
:
1446 if(!process_demand_active(This
, s
))
1448 *deactivated
= False
;
1450 case RDP_PDU_DEACTIVATE
:
1451 DEBUG(("RDP_PDU_DEACTIVATE\n"));
1452 *deactivated
= True
;
1454 case RDP_PDU_REDIRECT
:
1455 return process_redirect_pdu(This
, s
);
1458 disc
= process_data_pdu(This
, s
, ext_disc_reason
);
1463 unimpl("PDU %d\n", type
);
1467 cont
= This
->next_packet
< s
->end
;
1472 /* Establish a connection up to the RDP layer */
1474 rdp_connect(RDPCLIENT
* This
, char *server
, uint32 flags
, wchar_t *username
, wchar_t *domain
, wchar_t *password
,
1475 wchar_t *command
, wchar_t *directory
, wchar_t *hostname
, char *cookie
)
1477 if (!sec_connect(This
, server
, hostname
, cookie
))
1480 rdp_send_logon_info(This
, flags
, domain
, username
, password
, command
, directory
);
1484 /* Establish a reconnection up to the RDP layer */
1486 rdp_reconnect(RDPCLIENT
* This
, char *server
, uint32 flags
, wchar_t *username
, wchar_t *domain
, wchar_t *password
,
1487 wchar_t *command
, wchar_t *directory
, wchar_t *hostname
, char *cookie
)
1489 if (!sec_reconnect(This
, server
, hostname
, cookie
))
1492 rdp_send_logon_info(This
, flags
, domain
, username
, password
, command
, directory
);
1496 /* Called during redirection to reset the state to support redirection */
1498 rdp_reset_state(RDPCLIENT
* This
)
1500 This
->next_packet
= NULL
; /* reset the packet information */
1501 This
->rdp_shareid
= 0;
1502 sec_reset_state(This
);
1505 /* Disconnect from the RDP layer */
1507 rdp_disconnect(RDPCLIENT
* This
)
1509 sec_disconnect(This
);