/[rdesktop]/sourceforge.net/trunk/rdesktop/rdp.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /sourceforge.net/trunk/rdesktop/rdp.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 907 - (show annotations)
Tue May 31 18:49:05 2005 UTC (18 years, 11 months ago) by jdmeijer
File MIME type: text/plain
File size: 31193 byte(s)
Fix immediate disconnect when connecting to Windows XP RTM

1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Protocol services - RDP layer
4 Copyright (C) Matthew Chapman 1999-2005
5
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.
10
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.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include <time.h>
22 #include <errno.h>
23 #include <unistd.h>
24 #include "rdesktop.h"
25
26 #ifdef HAVE_ICONV
27 #ifdef HAVE_ICONV_H
28 #include <iconv.h>
29 #endif
30
31 #ifndef ICONV_CONST
32 #define ICONV_CONST ""
33 #endif
34 #endif
35
36 extern uint16 g_mcs_userid;
37 extern char g_username[64];
38 extern char g_codepage[16];
39 extern BOOL g_bitmap_compression;
40 extern BOOL g_orders;
41 extern BOOL g_encryption;
42 extern BOOL g_desktop_save;
43 extern BOOL g_polygon_ellipse_orders;
44 extern BOOL g_use_rdp5;
45 extern uint16 g_server_rdp_version;
46 extern uint32 g_rdp5_performanceflags;
47 extern int g_server_bpp;
48 extern int g_width;
49 extern int g_height;
50 extern BOOL g_bitmap_cache;
51 extern BOOL g_bitmap_cache_persist_enable;
52
53 uint8 *g_next_packet;
54 uint32 g_rdp_shareid;
55
56 extern RDPCOMP g_mppc_dict;
57
58 #if WITH_DEBUG
59 static uint32 g_packetno;
60 #endif
61
62 #ifdef HAVE_ICONV
63 static BOOL g_iconv_works = True;
64 #endif
65
66 /* Receive an RDP packet */
67 static STREAM
68 rdp_recv(uint8 * type)
69 {
70 static STREAM rdp_s;
71 uint16 length, pdu_type;
72 uint8 rdpver;
73
74 if ((rdp_s == NULL) || (g_next_packet >= rdp_s->end))
75 {
76 rdp_s = sec_recv(&rdpver);
77 if (rdp_s == NULL)
78 return NULL;
79 if (rdpver == 0xff)
80 {
81 g_next_packet = rdp_s->end;
82 *type = 0;
83 return rdp_s;
84 }
85 else if (rdpver != 3)
86 {
87 /* rdp5_process should move g_next_packet ok */
88 rdp5_process(rdp_s);
89 *type = 0;
90 return rdp_s;
91 }
92
93 g_next_packet = rdp_s->p;
94 }
95 else
96 {
97 rdp_s->p = g_next_packet;
98 }
99
100 in_uint16_le(rdp_s, length);
101 /* 32k packets are really 8, keepalive fix */
102 if (length == 0x8000)
103 {
104 g_next_packet += 8;
105 *type = 0;
106 return rdp_s;
107 }
108 in_uint16_le(rdp_s, pdu_type);
109 in_uint8s(rdp_s, 2); /* userid */
110 *type = pdu_type & 0xf;
111
112 #if WITH_DEBUG
113 DEBUG(("RDP packet #%d, (type %x)\n", ++g_packetno, *type));
114 hexdump(g_next_packet, length);
115 #endif /* */
116
117 g_next_packet += length;
118 return rdp_s;
119 }
120
121 /* Initialise an RDP data packet */
122 static STREAM
123 rdp_init_data(int maxlen)
124 {
125 STREAM s;
126
127 s = sec_init(g_encryption ? SEC_ENCRYPT : 0, maxlen + 18);
128 s_push_layer(s, rdp_hdr, 18);
129
130 return s;
131 }
132
133 /* Send an RDP data packet */
134 static void
135 rdp_send_data(STREAM s, uint8 data_pdu_type)
136 {
137 uint16 length;
138
139 s_pop_layer(s, rdp_hdr);
140 length = s->end - s->p;
141
142 out_uint16_le(s, length);
143 out_uint16_le(s, (RDP_PDU_DATA | 0x10));
144 out_uint16_le(s, (g_mcs_userid + 1001));
145
146 out_uint32_le(s, g_rdp_shareid);
147 out_uint8(s, 0); /* pad */
148 out_uint8(s, 1); /* streamid */
149 out_uint16_le(s, (length - 14));
150 out_uint8(s, data_pdu_type);
151 out_uint8(s, 0); /* compress_type */
152 out_uint16(s, 0); /* compress_len */
153
154 sec_send(s, g_encryption ? SEC_ENCRYPT : 0);
155 }
156
157 /* Output a string in Unicode */
158 void
159 rdp_out_unistr(STREAM s, char *string, int len)
160 {
161 #ifdef HAVE_ICONV
162 size_t ibl = strlen(string), obl = len + 2;
163 static iconv_t iconv_h = (iconv_t) - 1;
164 char *pin = string, *pout = (char *) s->p;
165
166 memset(pout, 0, len + 4);
167
168 if (g_iconv_works)
169 {
170 if (iconv_h == (iconv_t) - 1)
171 {
172 size_t i = 1, o = 4;
173 if ((iconv_h = iconv_open(WINDOWS_CODEPAGE, g_codepage)) == (iconv_t) - 1)
174 {
175 warning("rdp_out_unistr: iconv_open[%s -> %s] fail %d\n",
176 g_codepage, WINDOWS_CODEPAGE, (int) iconv_h);
177
178 g_iconv_works = False;
179 rdp_out_unistr(s, string, len);
180 return;
181 }
182 if (iconv(iconv_h, (ICONV_CONST char **) &pin, &i, &pout, &o) ==
183 (size_t) - 1)
184 {
185 iconv_close(iconv_h);
186 iconv_h = (iconv_t) - 1;
187 warning("rdp_out_unistr: iconv(1) fail, errno %d\n", errno);
188
189 g_iconv_works = False;
190 rdp_out_unistr(s, string, len);
191 return;
192 }
193 pin = string;
194 pout = (char *) s->p;
195 }
196
197 if (iconv(iconv_h, (ICONV_CONST char **) &pin, &ibl, &pout, &obl) == (size_t) - 1)
198 {
199 iconv_close(iconv_h);
200 iconv_h = (iconv_t) - 1;
201 warning("rdp_out_unistr: iconv(2) fail, errno %d\n", errno);
202
203 g_iconv_works = False;
204 rdp_out_unistr(s, string, len);
205 return;
206 }
207
208 s->p += len + 2;
209
210 }
211 else
212 #endif
213 {
214 int i = 0, j = 0;
215
216 len += 2;
217
218 while (i < len)
219 {
220 s->p[i++] = string[j++];
221 s->p[i++] = 0;
222 }
223
224 s->p += len;
225 }
226 }
227
228 /* Input a string in Unicode
229 *
230 * Returns str_len of string
231 */
232 int
233 rdp_in_unistr(STREAM s, char *string, int uni_len)
234 {
235 #ifdef HAVE_ICONV
236 size_t ibl = uni_len, obl = uni_len;
237 char *pin = (char *) s->p, *pout = string;
238 static iconv_t iconv_h = (iconv_t) - 1;
239
240 if (g_iconv_works)
241 {
242 if (iconv_h == (iconv_t) - 1)
243 {
244 if ((iconv_h = iconv_open(g_codepage, WINDOWS_CODEPAGE)) == (iconv_t) - 1)
245 {
246 warning("rdp_in_unistr: iconv_open[%s -> %s] fail %d\n",
247 WINDOWS_CODEPAGE, g_codepage, (int) iconv_h);
248
249 g_iconv_works = False;
250 return rdp_in_unistr(s, string, uni_len);
251 }
252 }
253
254 if (iconv(iconv_h, (ICONV_CONST char **) &pin, &ibl, &pout, &obl) == (size_t) - 1)
255 {
256 iconv_close(iconv_h);
257 iconv_h = (iconv_t) - 1;
258 warning("rdp_in_unistr: iconv fail, errno %d\n", errno);
259
260 g_iconv_works = False;
261 return rdp_in_unistr(s, string, uni_len);
262 }
263 return pout - string;
264 }
265 else
266 #endif
267 {
268 int i = 0;
269
270 while (i < uni_len / 2)
271 {
272 in_uint8a(s, &string[i++], 1);
273 in_uint8s(s, 1);
274 }
275
276 return i - 1;
277 }
278 }
279
280
281 /* Parse a logon info packet */
282 static void
283 rdp_send_logon_info(uint32 flags, char *domain, char *user,
284 char *password, char *program, char *directory)
285 {
286 char *ipaddr = tcp_get_address();
287 int len_domain = 2 * strlen(domain);
288 int len_user = 2 * strlen(user);
289 int len_password = 2 * strlen(password);
290 int len_program = 2 * strlen(program);
291 int len_directory = 2 * strlen(directory);
292 int len_ip = 2 * strlen(ipaddr);
293 int len_dll = 2 * strlen("C:\\WINNT\\System32\\mstscax.dll");
294 int packetlen = 0;
295 uint32 sec_flags = g_encryption ? (SEC_LOGON_INFO | SEC_ENCRYPT) : SEC_LOGON_INFO;
296 STREAM s;
297 time_t t = time(NULL);
298 time_t tzone;
299
300 if (!g_use_rdp5 || 1 == g_server_rdp_version)
301 {
302 DEBUG_RDP5(("Sending RDP4-style Logon packet\n"));
303
304 s = sec_init(sec_flags, 18 + len_domain + len_user + len_password
305 + len_program + len_directory + 10);
306
307 out_uint32(s, 0);
308 out_uint32_le(s, flags);
309 out_uint16_le(s, len_domain);
310 out_uint16_le(s, len_user);
311 out_uint16_le(s, len_password);
312 out_uint16_le(s, len_program);
313 out_uint16_le(s, len_directory);
314 rdp_out_unistr(s, domain, len_domain);
315 rdp_out_unistr(s, user, len_user);
316 rdp_out_unistr(s, password, len_password);
317 rdp_out_unistr(s, program, len_program);
318 rdp_out_unistr(s, directory, len_directory);
319 }
320 else
321 {
322
323 flags |= RDP_LOGON_BLOB;
324 DEBUG_RDP5(("Sending RDP5-style Logon packet\n"));
325 packetlen = 4 + /* Unknown uint32 */
326 4 + /* flags */
327 2 + /* len_domain */
328 2 + /* len_user */
329 (flags & RDP_LOGON_AUTO ? 2 : 0) + /* len_password */
330 (flags & RDP_LOGON_BLOB ? 2 : 0) + /* Length of BLOB */
331 2 + /* len_program */
332 2 + /* len_directory */
333 (0 < len_domain ? len_domain : 2) + /* domain */
334 len_user + (flags & RDP_LOGON_AUTO ? len_password : 0) + 0 + /* We have no 512 byte BLOB. Perhaps we must? */
335 (flags & RDP_LOGON_BLOB && !(flags & RDP_LOGON_AUTO) ? 2 : 0) + /* After the BLOB is a unknown int16. If there is a BLOB, that is. */
336 (0 < len_program ? len_program : 2) + (0 < len_directory ? len_directory : 2) + 2 + /* Unknown (2) */
337 2 + /* Client ip length */
338 len_ip + /* Client ip */
339 2 + /* DLL string length */
340 len_dll + /* DLL string */
341 2 + /* Unknown */
342 2 + /* Unknown */
343 64 + /* Time zone #0 */
344 2 + /* Unknown */
345 64 + /* Time zone #1 */
346 32; /* Unknown */
347
348 s = sec_init(sec_flags, packetlen);
349 DEBUG_RDP5(("Called sec_init with packetlen %d\n", packetlen));
350
351 out_uint32(s, 0); /* Unknown */
352 out_uint32_le(s, flags);
353 out_uint16_le(s, len_domain);
354 out_uint16_le(s, len_user);
355 if (flags & RDP_LOGON_AUTO)
356 {
357 out_uint16_le(s, len_password);
358
359 }
360 if (flags & RDP_LOGON_BLOB && !(flags & RDP_LOGON_AUTO))
361 {
362 out_uint16_le(s, 0);
363 }
364 out_uint16_le(s, len_program);
365 out_uint16_le(s, len_directory);
366 if (0 < len_domain)
367 rdp_out_unistr(s, domain, len_domain);
368 else
369 out_uint16_le(s, 0);
370 rdp_out_unistr(s, user, len_user);
371 if (flags & RDP_LOGON_AUTO)
372 {
373 rdp_out_unistr(s, password, len_password);
374 }
375 if (flags & RDP_LOGON_BLOB && !(flags & RDP_LOGON_AUTO))
376 {
377 out_uint16_le(s, 0);
378 }
379 if (0 < len_program)
380 {
381 rdp_out_unistr(s, program, len_program);
382
383 }
384 else
385 {
386 out_uint16_le(s, 0);
387 }
388 if (0 < len_directory)
389 {
390 rdp_out_unistr(s, directory, len_directory);
391 }
392 else
393 {
394 out_uint16_le(s, 0);
395 }
396 out_uint16_le(s, 2);
397 out_uint16_le(s, len_ip + 2); /* Length of client ip */
398 rdp_out_unistr(s, ipaddr, len_ip);
399 out_uint16_le(s, len_dll + 2);
400 rdp_out_unistr(s, "C:\\WINNT\\System32\\mstscax.dll", len_dll);
401
402 tzone = (mktime(gmtime(&t)) - mktime(localtime(&t))) / 60;
403 out_uint32_le(s, tzone);
404
405 rdp_out_unistr(s, "GTB, normaltid", 2 * strlen("GTB, normaltid"));
406 out_uint8s(s, 62 - 2 * strlen("GTB, normaltid"));
407
408 out_uint32_le(s, 0x0a0000);
409 out_uint32_le(s, 0x050000);
410 out_uint32_le(s, 3);
411 out_uint32_le(s, 0);
412 out_uint32_le(s, 0);
413
414 rdp_out_unistr(s, "GTB, sommartid", 2 * strlen("GTB, sommartid"));
415 out_uint8s(s, 62 - 2 * strlen("GTB, sommartid"));
416
417 out_uint32_le(s, 0x30000);
418 out_uint32_le(s, 0x050000);
419 out_uint32_le(s, 2);
420 out_uint32(s, 0);
421 out_uint32_le(s, 0xffffffc4);
422 out_uint32_le(s, 0xfffffffe);
423 out_uint32_le(s, g_rdp5_performanceflags);
424 out_uint32(s, 0);
425
426
427 }
428 s_mark_end(s);
429 sec_send(s, sec_flags);
430 }
431
432 /* Send a control PDU */
433 static void
434 rdp_send_control(uint16 action)
435 {
436 STREAM s;
437
438 s = rdp_init_data(8);
439
440 out_uint16_le(s, action);
441 out_uint16(s, 0); /* userid */
442 out_uint32(s, 0); /* control id */
443
444 s_mark_end(s);
445 rdp_send_data(s, RDP_DATA_PDU_CONTROL);
446 }
447
448 /* Send a synchronisation PDU */
449 static void
450 rdp_send_synchronise(void)
451 {
452 STREAM s;
453
454 s = rdp_init_data(4);
455
456 out_uint16_le(s, 1); /* type */
457 out_uint16_le(s, 1002);
458
459 s_mark_end(s);
460 rdp_send_data(s, RDP_DATA_PDU_SYNCHRONISE);
461 }
462
463 /* Send a single input event */
464 void
465 rdp_send_input(uint32 time, uint16 message_type, uint16 device_flags, uint16 param1, uint16 param2)
466 {
467 STREAM s;
468
469 s = rdp_init_data(16);
470
471 out_uint16_le(s, 1); /* number of events */
472 out_uint16(s, 0); /* pad */
473
474 out_uint32_le(s, time);
475 out_uint16_le(s, message_type);
476 out_uint16_le(s, device_flags);
477 out_uint16_le(s, param1);
478 out_uint16_le(s, param2);
479
480 s_mark_end(s);
481 rdp_send_data(s, RDP_DATA_PDU_INPUT);
482 }
483
484 /* Send a client window information PDU */
485 void
486 rdp_send_client_window_status(int status)
487 {
488 STREAM s;
489 static int current_status = 1;
490
491 if (current_status == status)
492 return;
493
494 s = rdp_init_data(12);
495
496 out_uint32_le(s, status);
497
498 switch (status)
499 {
500 case 0: /* shut the server up */
501 break;
502
503 case 1: /* receive data again */
504 out_uint32_le(s, 0); /* unknown */
505 out_uint16_le(s, g_width);
506 out_uint16_le(s, g_height);
507 break;
508 }
509
510 s_mark_end(s);
511 rdp_send_data(s, RDP_DATA_PDU_CLIENT_WINDOW_STATUS);
512 current_status = status;
513 }
514
515 /* Send persistent bitmap cache enumeration PDU's */
516 static void
517 rdp_enum_bmpcache2(void)
518 {
519 STREAM s;
520 HASH_KEY keylist[BMPCACHE2_NUM_PSTCELLS];
521 uint32 num_keys, offset, count, flags;
522
523 offset = 0;
524 num_keys = pstcache_enumerate(2, keylist);
525
526 while (offset < num_keys)
527 {
528 count = MIN(num_keys - offset, 169);
529
530 s = rdp_init_data(24 + count * sizeof(HASH_KEY));
531
532 flags = 0;
533 if (offset == 0)
534 flags |= PDU_FLAG_FIRST;
535 if (num_keys - offset <= 169)
536 flags |= PDU_FLAG_LAST;
537
538 /* header */
539 out_uint32_le(s, 0);
540 out_uint16_le(s, count);
541 out_uint16_le(s, 0);
542 out_uint16_le(s, 0);
543 out_uint16_le(s, 0);
544 out_uint16_le(s, 0);
545 out_uint16_le(s, num_keys);
546 out_uint32_le(s, 0);
547 out_uint32_le(s, flags);
548
549 /* list */
550 out_uint8a(s, keylist[offset], count * sizeof(HASH_KEY));
551
552 s_mark_end(s);
553 rdp_send_data(s, 0x2b);
554
555 offset += 169;
556 }
557 }
558
559 /* Send an (empty) font information PDU */
560 static void
561 rdp_send_fonts(uint16 seq)
562 {
563 STREAM s;
564
565 s = rdp_init_data(8);
566
567 out_uint16(s, 0); /* number of fonts */
568 out_uint16_le(s, 0); /* pad? */
569 out_uint16_le(s, seq); /* unknown */
570 out_uint16_le(s, 0x32); /* entry size */
571
572 s_mark_end(s);
573 rdp_send_data(s, RDP_DATA_PDU_FONT2);
574 }
575
576 /* Output general capability set */
577 static void
578 rdp_out_general_caps(STREAM s)
579 {
580 out_uint16_le(s, RDP_CAPSET_GENERAL);
581 out_uint16_le(s, RDP_CAPLEN_GENERAL);
582
583 out_uint16_le(s, 1); /* OS major type */
584 out_uint16_le(s, 3); /* OS minor type */
585 out_uint16_le(s, 0x200); /* Protocol version */
586 out_uint16(s, 0); /* Pad */
587 out_uint16(s, 0); /* Compression types */
588 out_uint16_le(s, g_use_rdp5 ? 0x40d : 0);
589 /* Pad, according to T.128. 0x40d seems to
590 trigger
591 the server to start sending RDP5 packets.
592 However, the value is 0x1d04 with W2KTSK and
593 NT4MS. Hmm.. Anyway, thankyou, Microsoft,
594 for sending such information in a padding
595 field.. */
596 out_uint16(s, 0); /* Update capability */
597 out_uint16(s, 0); /* Remote unshare capability */
598 out_uint16(s, 0); /* Compression level */
599 out_uint16(s, 0); /* Pad */
600 }
601
602 /* Output bitmap capability set */
603 static void
604 rdp_out_bitmap_caps(STREAM s)
605 {
606 out_uint16_le(s, RDP_CAPSET_BITMAP);
607 out_uint16_le(s, RDP_CAPLEN_BITMAP);
608
609 out_uint16_le(s, g_server_bpp); /* Preferred BPP */
610 out_uint16_le(s, 1); /* Receive 1 BPP */
611 out_uint16_le(s, 1); /* Receive 4 BPP */
612 out_uint16_le(s, 1); /* Receive 8 BPP */
613 out_uint16_le(s, 800); /* Desktop width */
614 out_uint16_le(s, 600); /* Desktop height */
615 out_uint16(s, 0); /* Pad */
616 out_uint16(s, 1); /* Allow resize */
617 out_uint16_le(s, g_bitmap_compression ? 1 : 0); /* Support compression */
618 out_uint16(s, 0); /* Unknown */
619 out_uint16_le(s, 1); /* Unknown */
620 out_uint16(s, 0); /* Pad */
621 }
622
623 /* Output order capability set */
624 static void
625 rdp_out_order_caps(STREAM s)
626 {
627 uint8 order_caps[32];
628
629 memset(order_caps, 0, 32);
630 order_caps[0] = 1; /* dest blt */
631 order_caps[1] = 1; /* pat blt */
632 order_caps[2] = 1; /* screen blt */
633 order_caps[3] = (g_bitmap_cache ? 1 : 0); /* memblt */
634 order_caps[4] = 0; /* triblt */
635 order_caps[8] = 1; /* line */
636 order_caps[9] = 1; /* line */
637 order_caps[10] = 1; /* rect */
638 order_caps[11] = (g_desktop_save ? 1 : 0); /* desksave */
639 order_caps[13] = 1; /* memblt */
640 order_caps[14] = 1; /* triblt */
641 order_caps[20] = (g_polygon_ellipse_orders ? 1 : 0); /* polygon */
642 order_caps[21] = (g_polygon_ellipse_orders ? 1 : 0); /* polygon2 */
643 order_caps[22] = 1; /* polyline */
644 order_caps[25] = (g_polygon_ellipse_orders ? 1 : 0); /* ellipse */
645 order_caps[26] = (g_polygon_ellipse_orders ? 1 : 0); /* ellipse2 */
646 order_caps[27] = 1; /* text2 */
647 out_uint16_le(s, RDP_CAPSET_ORDER);
648 out_uint16_le(s, RDP_CAPLEN_ORDER);
649
650 out_uint8s(s, 20); /* Terminal desc, pad */
651 out_uint16_le(s, 1); /* Cache X granularity */
652 out_uint16_le(s, 20); /* Cache Y granularity */
653 out_uint16(s, 0); /* Pad */
654 out_uint16_le(s, 1); /* Max order level */
655 out_uint16_le(s, 0x147); /* Number of fonts */
656 out_uint16_le(s, 0x2a); /* Capability flags */
657 out_uint8p(s, order_caps, 32); /* Orders supported */
658 out_uint16_le(s, 0x6a1); /* Text capability flags */
659 out_uint8s(s, 6); /* Pad */
660 out_uint32_le(s, g_desktop_save == False ? 0 : 0x38400); /* Desktop cache size */
661 out_uint32(s, 0); /* Unknown */
662 out_uint32_le(s, 0x4e4); /* Unknown */
663 }
664
665 /* Output bitmap cache capability set */
666 static void
667 rdp_out_bmpcache_caps(STREAM s)
668 {
669 int Bpp;
670 out_uint16_le(s, RDP_CAPSET_BMPCACHE);
671 out_uint16_le(s, RDP_CAPLEN_BMPCACHE);
672
673 Bpp = (g_server_bpp + 7) / 8;
674 out_uint8s(s, 24); /* unused */
675 out_uint16_le(s, 0x258); /* entries */
676 out_uint16_le(s, 0x100 * Bpp); /* max cell size */
677 out_uint16_le(s, 0x12c); /* entries */
678 out_uint16_le(s, 0x400 * Bpp); /* max cell size */
679 out_uint16_le(s, 0x106); /* entries */
680 out_uint16_le(s, 0x1000 * Bpp); /* max cell size */
681 }
682
683 /* Output bitmap cache v2 capability set */
684 static void
685 rdp_out_bmpcache2_caps(STREAM s)
686 {
687 out_uint16_le(s, RDP_CAPSET_BMPCACHE2);
688 out_uint16_le(s, RDP_CAPLEN_BMPCACHE2);
689
690 out_uint16_le(s, g_bitmap_cache_persist_enable ? 2 : 0); /* version */
691
692 out_uint16_be(s, 3); /* number of caches in this set */
693
694 /* max cell size for cache 0 is 16x16, 1 = 32x32, 2 = 64x64, etc */
695 out_uint32_le(s, BMPCACHE2_C0_CELLS);
696 out_uint32_le(s, BMPCACHE2_C1_CELLS);
697 if (pstcache_init(2))
698 {
699 out_uint32_le(s, BMPCACHE2_NUM_PSTCELLS | BMPCACHE2_FLAG_PERSIST);
700 }
701 else
702 {
703 out_uint32_le(s, BMPCACHE2_C2_CELLS);
704 }
705 out_uint8s(s, 20); /* other bitmap caches not used */
706 }
707
708 /* Output control capability set */
709 static void
710 rdp_out_control_caps(STREAM s)
711 {
712 out_uint16_le(s, RDP_CAPSET_CONTROL);
713 out_uint16_le(s, RDP_CAPLEN_CONTROL);
714
715 out_uint16(s, 0); /* Control capabilities */
716 out_uint16(s, 0); /* Remote detach */
717 out_uint16_le(s, 2); /* Control interest */
718 out_uint16_le(s, 2); /* Detach interest */
719 }
720
721 /* Output activation capability set */
722 static void
723 rdp_out_activate_caps(STREAM s)
724 {
725 out_uint16_le(s, RDP_CAPSET_ACTIVATE);
726 out_uint16_le(s, RDP_CAPLEN_ACTIVATE);
727
728 out_uint16(s, 0); /* Help key */
729 out_uint16(s, 0); /* Help index key */
730 out_uint16(s, 0); /* Extended help key */
731 out_uint16(s, 0); /* Window activate */
732 }
733
734 /* Output pointer capability set */
735 static void
736 rdp_out_pointer_caps(STREAM s)
737 {
738 out_uint16_le(s, RDP_CAPSET_POINTER);
739 out_uint16_le(s, RDP_CAPLEN_POINTER);
740
741 out_uint16(s, 0); /* Colour pointer */
742 out_uint16_le(s, 20); /* Cache size */
743 }
744
745 /* Output share capability set */
746 static void
747 rdp_out_share_caps(STREAM s)
748 {
749 out_uint16_le(s, RDP_CAPSET_SHARE);
750 out_uint16_le(s, RDP_CAPLEN_SHARE);
751
752 out_uint16(s, 0); /* userid */
753 out_uint16(s, 0); /* pad */
754 }
755
756 /* Output colour cache capability set */
757 static void
758 rdp_out_colcache_caps(STREAM s)
759 {
760 out_uint16_le(s, RDP_CAPSET_COLCACHE);
761 out_uint16_le(s, RDP_CAPLEN_COLCACHE);
762
763 out_uint16_le(s, 6); /* cache size */
764 out_uint16(s, 0); /* pad */
765 }
766
767 static uint8 caps_0x0d[] = {
768 0x01, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00,
769 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
770 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
771 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
772 0x00, 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
779 };
780
781 static uint8 caps_0x0c[] = { 0x01, 0x00, 0x00, 0x00 };
782
783 static uint8 caps_0x0e[] = { 0x01, 0x00, 0x00, 0x00 };
784
785 static uint8 caps_0x10[] = {
786 0xFE, 0x00, 0x04, 0x00, 0xFE, 0x00, 0x04, 0x00,
787 0xFE, 0x00, 0x08, 0x00, 0xFE, 0x00, 0x08, 0x00,
788 0xFE, 0x00, 0x10, 0x00, 0xFE, 0x00, 0x20, 0x00,
789 0xFE, 0x00, 0x40, 0x00, 0xFE, 0x00, 0x80, 0x00,
790 0xFE, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x08,
791 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00
792 };
793
794 /* Output unknown capability sets */
795 static void
796 rdp_out_unknown_caps(STREAM s, uint16 id, uint16 length, uint8 * caps)
797 {
798 out_uint16_le(s, id);
799 out_uint16_le(s, length);
800
801 out_uint8p(s, caps, length - 4);
802 }
803
804 #define RDP5_FLAG 0x0030
805 /* Send a confirm active PDU */
806 static void
807 rdp_send_confirm_active(void)
808 {
809 STREAM s;
810 uint32 sec_flags = g_encryption ? (RDP5_FLAG | SEC_ENCRYPT) : RDP5_FLAG;
811 uint16 caplen =
812 RDP_CAPLEN_GENERAL + RDP_CAPLEN_BITMAP + RDP_CAPLEN_ORDER +
813 RDP_CAPLEN_BMPCACHE + RDP_CAPLEN_COLCACHE +
814 RDP_CAPLEN_ACTIVATE + RDP_CAPLEN_CONTROL +
815 RDP_CAPLEN_POINTER + RDP_CAPLEN_SHARE +
816 0x58 + 0x08 + 0x08 + 0x34 /* unknown caps */ +
817 4 /* w2k fix, why? */ ;
818
819 s = sec_init(sec_flags, 6 + 14 + caplen + sizeof(RDP_SOURCE));
820
821 out_uint16_le(s, 2 + 14 + caplen + sizeof(RDP_SOURCE));
822 out_uint16_le(s, (RDP_PDU_CONFIRM_ACTIVE | 0x10)); /* Version 1 */
823 out_uint16_le(s, (g_mcs_userid + 1001));
824
825 out_uint32_le(s, g_rdp_shareid);
826 out_uint16_le(s, 0x3ea); /* userid */
827 out_uint16_le(s, sizeof(RDP_SOURCE));
828 out_uint16_le(s, caplen);
829
830 out_uint8p(s, RDP_SOURCE, sizeof(RDP_SOURCE));
831 out_uint16_le(s, 0xd); /* num_caps */
832 out_uint8s(s, 2); /* pad */
833
834 rdp_out_general_caps(s);
835 rdp_out_bitmap_caps(s);
836 rdp_out_order_caps(s);
837 g_use_rdp5 ? rdp_out_bmpcache2_caps(s) : rdp_out_bmpcache_caps(s);
838 rdp_out_colcache_caps(s);
839 rdp_out_activate_caps(s);
840 rdp_out_control_caps(s);
841 rdp_out_pointer_caps(s);
842 rdp_out_share_caps(s);
843
844 rdp_out_unknown_caps(s, 0x0d, 0x58, caps_0x0d); /* international? */
845 rdp_out_unknown_caps(s, 0x0c, 0x08, caps_0x0c);
846 rdp_out_unknown_caps(s, 0x0e, 0x08, caps_0x0e);
847 rdp_out_unknown_caps(s, 0x10, 0x34, caps_0x10); /* glyph cache? */
848
849 s_mark_end(s);
850 sec_send(s, sec_flags);
851 }
852
853 /* Process a general capability set */
854 static void
855 rdp_process_general_caps(STREAM s)
856 {
857 uint16 pad2octetsB; /* rdp5 flags? */
858
859 in_uint8s(s, 10);
860 in_uint16_le(s, pad2octetsB);
861
862 if (!pad2octetsB)
863 g_use_rdp5 = False;
864 }
865
866 /* Process a bitmap capability set */
867 static void
868 rdp_process_bitmap_caps(STREAM s)
869 {
870 uint16 width, height, bpp;
871
872 in_uint16_le(s, bpp);
873 in_uint8s(s, 6);
874
875 in_uint16_le(s, width);
876 in_uint16_le(s, height);
877
878 DEBUG(("setting desktop size and bpp to: %dx%dx%d\n", width, height, bpp));
879
880 /*
881 * The server may limit bpp and change the size of the desktop (for
882 * example when shadowing another session).
883 */
884 if (g_server_bpp != bpp)
885 {
886 warning("colour depth changed from %d to %d\n", g_server_bpp, bpp);
887 g_server_bpp = bpp;
888 }
889 if (g_width != width || g_height != height)
890 {
891 warning("screen size changed from %dx%d to %dx%d\n", g_width, g_height,
892 width, height);
893 g_width = width;
894 g_height = height;
895 ui_resize_window();
896 }
897 }
898
899 /* Process server capabilities */
900 void
901 rdp_process_server_caps(STREAM s, uint16 length)
902 {
903 int n;
904 uint8 *next, *start;
905 uint16 ncapsets, capset_type, capset_length;
906
907 start = s->p;
908
909 in_uint16_le(s, ncapsets);
910 in_uint8s(s, 2); /* pad */
911
912 for (n = 0; n < ncapsets; n++)
913 {
914 if (s->p > start + length)
915 return;
916
917 in_uint16_le(s, capset_type);
918 in_uint16_le(s, capset_length);
919
920 next = s->p + capset_length - 4;
921
922 switch (capset_type)
923 {
924 case RDP_CAPSET_GENERAL:
925 rdp_process_general_caps(s);
926 break;
927
928 case RDP_CAPSET_BITMAP:
929 rdp_process_bitmap_caps(s);
930 break;
931 }
932
933 s->p = next;
934 }
935 }
936
937 /* Respond to a demand active PDU */
938 static void
939 process_demand_active(STREAM s)
940 {
941 uint8 type;
942 uint16 len_src_descriptor, len_combined_caps;
943
944 in_uint32_le(s, g_rdp_shareid);
945 in_uint16_le(s, len_src_descriptor);
946 in_uint16_le(s, len_combined_caps);
947 in_uint8s(s, len_src_descriptor);
948
949 DEBUG(("DEMAND_ACTIVE(id=0x%x)\n", g_rdp_shareid));
950 rdp_process_server_caps(s, len_combined_caps);
951
952 rdp_send_confirm_active();
953 rdp_send_synchronise();
954 rdp_send_control(RDP_CTL_COOPERATE);
955 rdp_send_control(RDP_CTL_REQUEST_CONTROL);
956 rdp_recv(&type); /* RDP_PDU_SYNCHRONIZE */
957 rdp_recv(&type); /* RDP_CTL_COOPERATE */
958 rdp_recv(&type); /* RDP_CTL_GRANT_CONTROL */
959 rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, ui_get_numlock_state(read_keyboard_state()), 0);
960
961 if (g_use_rdp5)
962 {
963 rdp_enum_bmpcache2();
964 rdp_send_fonts(3);
965 }
966 else
967 {
968 rdp_send_fonts(1);
969 rdp_send_fonts(2);
970 }
971
972 rdp_recv(&type); /* RDP_PDU_UNKNOWN 0x28 (Fonts?) */
973 reset_order_state();
974 }
975
976 /* Process a colour pointer PDU */
977 void
978 process_colour_pointer_pdu(STREAM s)
979 {
980 uint16 x, y, width, height, cache_idx, masklen, datalen;
981 uint8 *mask, *data;
982 HCURSOR cursor;
983
984 in_uint16_le(s, cache_idx);
985 in_uint16_le(s, x);
986 in_uint16_le(s, y);
987 in_uint16_le(s, width);
988 in_uint16_le(s, height);
989 in_uint16_le(s, masklen);
990 in_uint16_le(s, datalen);
991 in_uint8p(s, data, datalen);
992 in_uint8p(s, mask, masklen);
993 cursor = ui_create_cursor(x, y, width, height, mask, data);
994 ui_set_cursor(cursor);
995 cache_put_cursor(cache_idx, cursor);
996 }
997
998 /* Process a cached pointer PDU */
999 void
1000 process_cached_pointer_pdu(STREAM s)
1001 {
1002 uint16 cache_idx;
1003
1004 in_uint16_le(s, cache_idx);
1005 ui_set_cursor(cache_get_cursor(cache_idx));
1006 }
1007
1008 /* Process a system pointer PDU */
1009 void
1010 process_system_pointer_pdu(STREAM s)
1011 {
1012 uint16 system_pointer_type;
1013
1014 in_uint16(s, system_pointer_type);
1015 switch (system_pointer_type)
1016 {
1017 case RDP_NULL_POINTER:
1018 ui_set_null_cursor();
1019 break;
1020
1021 default:
1022 unimpl("System pointer message 0x%x\n", system_pointer_type);
1023 }
1024 }
1025
1026 /* Process a pointer PDU */
1027 static void
1028 process_pointer_pdu(STREAM s)
1029 {
1030 uint16 message_type;
1031 uint16 x, y;
1032
1033 in_uint16_le(s, message_type);
1034 in_uint8s(s, 2); /* pad */
1035
1036 switch (message_type)
1037 {
1038 case RDP_POINTER_MOVE:
1039 in_uint16_le(s, x);
1040 in_uint16_le(s, y);
1041 if (s_check(s))
1042 ui_move_pointer(x, y);
1043 break;
1044
1045 case RDP_POINTER_COLOR:
1046 process_colour_pointer_pdu(s);
1047 break;
1048
1049 case RDP_POINTER_CACHED:
1050 process_cached_pointer_pdu(s);
1051 break;
1052
1053 case RDP_POINTER_SYSTEM:
1054 process_system_pointer_pdu(s);
1055 break;
1056
1057 default:
1058 unimpl("Pointer message 0x%x\n", message_type);
1059 }
1060 }
1061
1062 /* Process bitmap updates */
1063 void
1064 process_bitmap_updates(STREAM s)
1065 {
1066 uint16 num_updates;
1067 uint16 left, top, right, bottom, width, height;
1068 uint16 cx, cy, bpp, Bpp, compress, bufsize, size;
1069 uint8 *data, *bmpdata;
1070 int i;
1071
1072 in_uint16_le(s, num_updates);
1073
1074 for (i = 0; i < num_updates; i++)
1075 {
1076 in_uint16_le(s, left);
1077 in_uint16_le(s, top);
1078 in_uint16_le(s, right);
1079 in_uint16_le(s, bottom);
1080 in_uint16_le(s, width);
1081 in_uint16_le(s, height);
1082 in_uint16_le(s, bpp);
1083 Bpp = (bpp + 7) / 8;
1084 in_uint16_le(s, compress);
1085 in_uint16_le(s, bufsize);
1086
1087 cx = right - left + 1;
1088 cy = bottom - top + 1;
1089
1090 DEBUG(("BITMAP_UPDATE(l=%d,t=%d,r=%d,b=%d,w=%d,h=%d,Bpp=%d,cmp=%d)\n",
1091 left, top, right, bottom, width, height, Bpp, compress));
1092
1093 if (!compress)
1094 {
1095 int y;
1096 bmpdata = (uint8 *) xmalloc(width * height * Bpp);
1097 for (y = 0; y < height; y++)
1098 {
1099 in_uint8a(s, &bmpdata[(height - y - 1) * (width * Bpp)],
1100 width * Bpp);
1101 }
1102 ui_paint_bitmap(left, top, cx, cy, width, height, bmpdata);
1103 xfree(bmpdata);
1104 continue;
1105 }
1106
1107
1108 if (compress & 0x400)
1109 {
1110 size = bufsize;
1111 }
1112 else
1113 {
1114 in_uint8s(s, 2); /* pad */
1115 in_uint16_le(s, size);
1116 in_uint8s(s, 4); /* line_size, final_size */
1117 }
1118 in_uint8p(s, data, size);
1119 bmpdata = (uint8 *) xmalloc(width * height * Bpp);
1120 if (bitmap_decompress(bmpdata, width, height, data, size, Bpp))
1121 {
1122 ui_paint_bitmap(left, top, cx, cy, width, height, bmpdata);
1123 }
1124 else
1125 {
1126 DEBUG_RDP5(("Failed to decompress data\n"));
1127 }
1128
1129 xfree(bmpdata);
1130 }
1131 }
1132
1133 /* Process a palette update */
1134 void
1135 process_palette(STREAM s)
1136 {
1137 COLOURENTRY *entry;
1138 COLOURMAP map;
1139 HCOLOURMAP hmap;
1140 int i;
1141
1142 in_uint8s(s, 2); /* pad */
1143 in_uint16_le(s, map.ncolours);
1144 in_uint8s(s, 2); /* pad */
1145
1146 map.colours = (COLOURENTRY *) xmalloc(sizeof(COLOURENTRY) * map.ncolours);
1147
1148 DEBUG(("PALETTE(c=%d)\n", map.ncolours));
1149
1150 for (i = 0; i < map.ncolours; i++)
1151 {
1152 entry = &map.colours[i];
1153 in_uint8(s, entry->red);
1154 in_uint8(s, entry->green);
1155 in_uint8(s, entry->blue);
1156 }
1157
1158 hmap = ui_create_colourmap(&map);
1159 ui_set_colourmap(hmap);
1160
1161 xfree(map.colours);
1162 }
1163
1164 /* Process an update PDU */
1165 static void
1166 process_update_pdu(STREAM s)
1167 {
1168 uint16 update_type, count;
1169
1170 in_uint16_le(s, update_type);
1171
1172 ui_begin_update();
1173 switch (update_type)
1174 {
1175 case RDP_UPDATE_ORDERS:
1176 in_uint8s(s, 2); /* pad */
1177 in_uint16_le(s, count);
1178 in_uint8s(s, 2); /* pad */
1179 process_orders(s, count);
1180 break;
1181
1182 case RDP_UPDATE_BITMAP:
1183 process_bitmap_updates(s);
1184 break;
1185
1186 case RDP_UPDATE_PALETTE:
1187 process_palette(s);
1188 break;
1189
1190 case RDP_UPDATE_SYNCHRONIZE:
1191 break;
1192
1193 default:
1194 unimpl("update %d\n", update_type);
1195 }
1196 ui_end_update();
1197 }
1198
1199 /* Process a disconnect PDU */
1200 void
1201 process_disconnect_pdu(STREAM s, uint32 * ext_disc_reason)
1202 {
1203 in_uint32_le(s, *ext_disc_reason);
1204
1205 DEBUG(("Received disconnect PDU\n"));
1206 }
1207
1208 /* Process data PDU */
1209 static BOOL
1210 process_data_pdu(STREAM s, uint32 * ext_disc_reason)
1211 {
1212 uint8 data_pdu_type;
1213 uint8 ctype;
1214 uint16 clen;
1215 uint32 len;
1216
1217 uint32 roff, rlen;
1218
1219 struct stream *ns = &(g_mppc_dict.ns);
1220
1221 in_uint8s(s, 6); /* shareid, pad, streamid */
1222 in_uint16(s, len);
1223 in_uint8(s, data_pdu_type);
1224 in_uint8(s, ctype);
1225 in_uint16(s, clen);
1226 clen -= 18;
1227
1228 if (ctype & RDP_MPPC_COMPRESSED)
1229 {
1230 if (len > RDP_MPPC_DICT_SIZE)
1231 error("error decompressed packet size exceeds max\n");
1232 if (mppc_expand(s->p, clen, ctype, &roff, &rlen) == -1)
1233 error("error while decompressing packet\n");
1234
1235 /* len -= 18; */
1236
1237 /* allocate memory and copy the uncompressed data into the temporary stream */
1238 ns->data = (uint8 *) xrealloc(ns->data, rlen);
1239
1240 memcpy((ns->data), (unsigned char *) (g_mppc_dict.hist + roff), rlen);
1241
1242 ns->size = rlen;
1243 ns->end = (ns->data + ns->size);
1244 ns->p = ns->data;
1245 ns->rdp_hdr = ns->p;
1246
1247 s = ns;
1248 }
1249
1250 switch (data_pdu_type)
1251 {
1252 case RDP_DATA_PDU_UPDATE:
1253 process_update_pdu(s);
1254 break;
1255
1256 case RDP_DATA_PDU_CONTROL:
1257 DEBUG(("Received Control PDU\n"));
1258 break;
1259
1260 case RDP_DATA_PDU_SYNCHRONISE:
1261 DEBUG(("Received Sync PDU\n"));
1262 break;
1263
1264 case RDP_DATA_PDU_POINTER:
1265 process_pointer_pdu(s);
1266 break;
1267
1268 case RDP_DATA_PDU_BELL:
1269 ui_bell();
1270 break;
1271
1272 case RDP_DATA_PDU_LOGON:
1273 DEBUG(("Received Logon PDU\n"));
1274 /* User logged on */
1275 break;
1276
1277 case RDP_DATA_PDU_DISCONNECT:
1278 process_disconnect_pdu(s, ext_disc_reason);
1279 return True;
1280
1281 default:
1282 unimpl("data PDU %d\n", data_pdu_type);
1283 }
1284 return False;
1285 }
1286
1287 /* Process incoming packets */
1288 /* nevers gets out of here till app is done */
1289 void
1290 rdp_main_loop(BOOL * deactivated, uint32 * ext_disc_reason)
1291 {
1292 while (rdp_loop(deactivated, ext_disc_reason))
1293 ;
1294 }
1295
1296 /* used in uiports and rdp_main_loop, processes the rdp packets waiting */
1297 BOOL
1298 rdp_loop(BOOL * deactivated, uint32 * ext_disc_reason)
1299 {
1300 uint8 type;
1301 BOOL disc = False; /* True when a disconnect PDU was received */
1302 BOOL cont = True;
1303 STREAM s;
1304
1305 while (cont)
1306 {
1307 s = rdp_recv(&type);
1308 if (s == NULL)
1309 return False;
1310 switch (type)
1311 {
1312 case RDP_PDU_DEMAND_ACTIVE:
1313 process_demand_active(s);
1314 *deactivated = False;
1315 break;
1316 case RDP_PDU_DEACTIVATE:
1317 DEBUG(("RDP_PDU_DEACTIVATE\n"));
1318 *deactivated = True;
1319 break;
1320 case RDP_PDU_DATA:
1321 disc = process_data_pdu(s, ext_disc_reason);
1322 break;
1323 case 0:
1324 break;
1325 default:
1326 unimpl("PDU %d\n", type);
1327 }
1328 if (disc)
1329 return False;
1330 cont = g_next_packet < s->end;
1331 }
1332 return True;
1333 }
1334
1335 /* Establish a connection up to the RDP layer */
1336 BOOL
1337 rdp_connect(char *server, uint32 flags, char *domain, char *password,
1338 char *command, char *directory)
1339 {
1340 if (!sec_connect(server, g_username))
1341 return False;
1342
1343 rdp_send_logon_info(flags, domain, g_username, password, command, directory);
1344 return True;
1345 }
1346
1347 /* Disconnect from the RDP layer */
1348 void
1349 rdp_disconnect(void)
1350 {
1351 sec_disconnect();
1352 }

  ViewVC Help
Powered by ViewVC 1.1.26