/[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 905 - (show annotations)
Fri May 20 22:09:32 2005 UTC (19 years, 1 month ago) by jdmeijer
File MIME type: text/plain
File size: 31093 byte(s)
Tell the server to stop sending window updates when the rdesktop window is unmapped

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
490 s = rdp_init_data(12);
491
492 out_uint32_le(s, status);
493
494 switch (status)
495 {
496 case 0: /* shut the server up */
497 break;
498
499 case 1: /* receive data again */
500 out_uint32_le(s, 0); /* unknown */
501 out_uint16_le(s, g_width);
502 out_uint16_le(s, g_height);
503 break;
504 }
505
506 s_mark_end(s);
507 rdp_send_data(s, RDP_DATA_PDU_CLIENT_WINDOW_STATUS);
508 }
509
510 /* Send persistent bitmap cache enumeration PDU's */
511 static void
512 rdp_enum_bmpcache2(void)
513 {
514 STREAM s;
515 HASH_KEY keylist[BMPCACHE2_NUM_PSTCELLS];
516 uint32 num_keys, offset, count, flags;
517
518 offset = 0;
519 num_keys = pstcache_enumerate(2, keylist);
520
521 while (offset < num_keys)
522 {
523 count = MIN(num_keys - offset, 169);
524
525 s = rdp_init_data(24 + count * sizeof(HASH_KEY));
526
527 flags = 0;
528 if (offset == 0)
529 flags |= PDU_FLAG_FIRST;
530 if (num_keys - offset <= 169)
531 flags |= PDU_FLAG_LAST;
532
533 /* header */
534 out_uint32_le(s, 0);
535 out_uint16_le(s, count);
536 out_uint16_le(s, 0);
537 out_uint16_le(s, 0);
538 out_uint16_le(s, 0);
539 out_uint16_le(s, 0);
540 out_uint16_le(s, num_keys);
541 out_uint32_le(s, 0);
542 out_uint32_le(s, flags);
543
544 /* list */
545 out_uint8a(s, keylist[offset], count * sizeof(HASH_KEY));
546
547 s_mark_end(s);
548 rdp_send_data(s, 0x2b);
549
550 offset += 169;
551 }
552 }
553
554 /* Send an (empty) font information PDU */
555 static void
556 rdp_send_fonts(uint16 seq)
557 {
558 STREAM s;
559
560 s = rdp_init_data(8);
561
562 out_uint16(s, 0); /* number of fonts */
563 out_uint16_le(s, 0); /* pad? */
564 out_uint16_le(s, seq); /* unknown */
565 out_uint16_le(s, 0x32); /* entry size */
566
567 s_mark_end(s);
568 rdp_send_data(s, RDP_DATA_PDU_FONT2);
569 }
570
571 /* Output general capability set */
572 static void
573 rdp_out_general_caps(STREAM s)
574 {
575 out_uint16_le(s, RDP_CAPSET_GENERAL);
576 out_uint16_le(s, RDP_CAPLEN_GENERAL);
577
578 out_uint16_le(s, 1); /* OS major type */
579 out_uint16_le(s, 3); /* OS minor type */
580 out_uint16_le(s, 0x200); /* Protocol version */
581 out_uint16(s, 0); /* Pad */
582 out_uint16(s, 0); /* Compression types */
583 out_uint16_le(s, g_use_rdp5 ? 0x40d : 0);
584 /* Pad, according to T.128. 0x40d seems to
585 trigger
586 the server to start sending RDP5 packets.
587 However, the value is 0x1d04 with W2KTSK and
588 NT4MS. Hmm.. Anyway, thankyou, Microsoft,
589 for sending such information in a padding
590 field.. */
591 out_uint16(s, 0); /* Update capability */
592 out_uint16(s, 0); /* Remote unshare capability */
593 out_uint16(s, 0); /* Compression level */
594 out_uint16(s, 0); /* Pad */
595 }
596
597 /* Output bitmap capability set */
598 static void
599 rdp_out_bitmap_caps(STREAM s)
600 {
601 out_uint16_le(s, RDP_CAPSET_BITMAP);
602 out_uint16_le(s, RDP_CAPLEN_BITMAP);
603
604 out_uint16_le(s, g_server_bpp); /* Preferred BPP */
605 out_uint16_le(s, 1); /* Receive 1 BPP */
606 out_uint16_le(s, 1); /* Receive 4 BPP */
607 out_uint16_le(s, 1); /* Receive 8 BPP */
608 out_uint16_le(s, 800); /* Desktop width */
609 out_uint16_le(s, 600); /* Desktop height */
610 out_uint16(s, 0); /* Pad */
611 out_uint16(s, 1); /* Allow resize */
612 out_uint16_le(s, g_bitmap_compression ? 1 : 0); /* Support compression */
613 out_uint16(s, 0); /* Unknown */
614 out_uint16_le(s, 1); /* Unknown */
615 out_uint16(s, 0); /* Pad */
616 }
617
618 /* Output order capability set */
619 static void
620 rdp_out_order_caps(STREAM s)
621 {
622 uint8 order_caps[32];
623
624 memset(order_caps, 0, 32);
625 order_caps[0] = 1; /* dest blt */
626 order_caps[1] = 1; /* pat blt */
627 order_caps[2] = 1; /* screen blt */
628 order_caps[3] = (g_bitmap_cache ? 1 : 0); /* memblt */
629 order_caps[4] = 0; /* triblt */
630 order_caps[8] = 1; /* line */
631 order_caps[9] = 1; /* line */
632 order_caps[10] = 1; /* rect */
633 order_caps[11] = (g_desktop_save ? 1 : 0); /* desksave */
634 order_caps[13] = 1; /* memblt */
635 order_caps[14] = 1; /* triblt */
636 order_caps[20] = (g_polygon_ellipse_orders ? 1 : 0); /* polygon */
637 order_caps[21] = (g_polygon_ellipse_orders ? 1 : 0); /* polygon2 */
638 order_caps[22] = 1; /* polyline */
639 order_caps[25] = (g_polygon_ellipse_orders ? 1 : 0); /* ellipse */
640 order_caps[26] = (g_polygon_ellipse_orders ? 1 : 0); /* ellipse2 */
641 order_caps[27] = 1; /* text2 */
642 out_uint16_le(s, RDP_CAPSET_ORDER);
643 out_uint16_le(s, RDP_CAPLEN_ORDER);
644
645 out_uint8s(s, 20); /* Terminal desc, pad */
646 out_uint16_le(s, 1); /* Cache X granularity */
647 out_uint16_le(s, 20); /* Cache Y granularity */
648 out_uint16(s, 0); /* Pad */
649 out_uint16_le(s, 1); /* Max order level */
650 out_uint16_le(s, 0x147); /* Number of fonts */
651 out_uint16_le(s, 0x2a); /* Capability flags */
652 out_uint8p(s, order_caps, 32); /* Orders supported */
653 out_uint16_le(s, 0x6a1); /* Text capability flags */
654 out_uint8s(s, 6); /* Pad */
655 out_uint32_le(s, g_desktop_save == False ? 0 : 0x38400); /* Desktop cache size */
656 out_uint32(s, 0); /* Unknown */
657 out_uint32_le(s, 0x4e4); /* Unknown */
658 }
659
660 /* Output bitmap cache capability set */
661 static void
662 rdp_out_bmpcache_caps(STREAM s)
663 {
664 int Bpp;
665 out_uint16_le(s, RDP_CAPSET_BMPCACHE);
666 out_uint16_le(s, RDP_CAPLEN_BMPCACHE);
667
668 Bpp = (g_server_bpp + 7) / 8;
669 out_uint8s(s, 24); /* unused */
670 out_uint16_le(s, 0x258); /* entries */
671 out_uint16_le(s, 0x100 * Bpp); /* max cell size */
672 out_uint16_le(s, 0x12c); /* entries */
673 out_uint16_le(s, 0x400 * Bpp); /* max cell size */
674 out_uint16_le(s, 0x106); /* entries */
675 out_uint16_le(s, 0x1000 * Bpp); /* max cell size */
676 }
677
678 /* Output bitmap cache v2 capability set */
679 static void
680 rdp_out_bmpcache2_caps(STREAM s)
681 {
682 out_uint16_le(s, RDP_CAPSET_BMPCACHE2);
683 out_uint16_le(s, RDP_CAPLEN_BMPCACHE2);
684
685 out_uint16_le(s, g_bitmap_cache_persist_enable ? 2 : 0); /* version */
686
687 out_uint16_be(s, 3); /* number of caches in this set */
688
689 /* max cell size for cache 0 is 16x16, 1 = 32x32, 2 = 64x64, etc */
690 out_uint32_le(s, BMPCACHE2_C0_CELLS);
691 out_uint32_le(s, BMPCACHE2_C1_CELLS);
692 if (pstcache_init(2))
693 {
694 out_uint32_le(s, BMPCACHE2_NUM_PSTCELLS | BMPCACHE2_FLAG_PERSIST);
695 }
696 else
697 {
698 out_uint32_le(s, BMPCACHE2_C2_CELLS);
699 }
700 out_uint8s(s, 20); /* other bitmap caches not used */
701 }
702
703 /* Output control capability set */
704 static void
705 rdp_out_control_caps(STREAM s)
706 {
707 out_uint16_le(s, RDP_CAPSET_CONTROL);
708 out_uint16_le(s, RDP_CAPLEN_CONTROL);
709
710 out_uint16(s, 0); /* Control capabilities */
711 out_uint16(s, 0); /* Remote detach */
712 out_uint16_le(s, 2); /* Control interest */
713 out_uint16_le(s, 2); /* Detach interest */
714 }
715
716 /* Output activation capability set */
717 static void
718 rdp_out_activate_caps(STREAM s)
719 {
720 out_uint16_le(s, RDP_CAPSET_ACTIVATE);
721 out_uint16_le(s, RDP_CAPLEN_ACTIVATE);
722
723 out_uint16(s, 0); /* Help key */
724 out_uint16(s, 0); /* Help index key */
725 out_uint16(s, 0); /* Extended help key */
726 out_uint16(s, 0); /* Window activate */
727 }
728
729 /* Output pointer capability set */
730 static void
731 rdp_out_pointer_caps(STREAM s)
732 {
733 out_uint16_le(s, RDP_CAPSET_POINTER);
734 out_uint16_le(s, RDP_CAPLEN_POINTER);
735
736 out_uint16(s, 0); /* Colour pointer */
737 out_uint16_le(s, 20); /* Cache size */
738 }
739
740 /* Output share capability set */
741 static void
742 rdp_out_share_caps(STREAM s)
743 {
744 out_uint16_le(s, RDP_CAPSET_SHARE);
745 out_uint16_le(s, RDP_CAPLEN_SHARE);
746
747 out_uint16(s, 0); /* userid */
748 out_uint16(s, 0); /* pad */
749 }
750
751 /* Output colour cache capability set */
752 static void
753 rdp_out_colcache_caps(STREAM s)
754 {
755 out_uint16_le(s, RDP_CAPSET_COLCACHE);
756 out_uint16_le(s, RDP_CAPLEN_COLCACHE);
757
758 out_uint16_le(s, 6); /* cache size */
759 out_uint16(s, 0); /* pad */
760 }
761
762 static uint8 caps_0x0d[] = {
763 0x01, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00,
764 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
765 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
766 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
767 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
768 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
769 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
770 0x00, 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
774 };
775
776 static uint8 caps_0x0c[] = { 0x01, 0x00, 0x00, 0x00 };
777
778 static uint8 caps_0x0e[] = { 0x01, 0x00, 0x00, 0x00 };
779
780 static uint8 caps_0x10[] = {
781 0xFE, 0x00, 0x04, 0x00, 0xFE, 0x00, 0x04, 0x00,
782 0xFE, 0x00, 0x08, 0x00, 0xFE, 0x00, 0x08, 0x00,
783 0xFE, 0x00, 0x10, 0x00, 0xFE, 0x00, 0x20, 0x00,
784 0xFE, 0x00, 0x40, 0x00, 0xFE, 0x00, 0x80, 0x00,
785 0xFE, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x08,
786 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00
787 };
788
789 /* Output unknown capability sets */
790 static void
791 rdp_out_unknown_caps(STREAM s, uint16 id, uint16 length, uint8 * caps)
792 {
793 out_uint16_le(s, id);
794 out_uint16_le(s, length);
795
796 out_uint8p(s, caps, length - 4);
797 }
798
799 #define RDP5_FLAG 0x0030
800 /* Send a confirm active PDU */
801 static void
802 rdp_send_confirm_active(void)
803 {
804 STREAM s;
805 uint32 sec_flags = g_encryption ? (RDP5_FLAG | SEC_ENCRYPT) : RDP5_FLAG;
806 uint16 caplen =
807 RDP_CAPLEN_GENERAL + RDP_CAPLEN_BITMAP + RDP_CAPLEN_ORDER +
808 RDP_CAPLEN_BMPCACHE + RDP_CAPLEN_COLCACHE +
809 RDP_CAPLEN_ACTIVATE + RDP_CAPLEN_CONTROL +
810 RDP_CAPLEN_POINTER + RDP_CAPLEN_SHARE +
811 0x58 + 0x08 + 0x08 + 0x34 /* unknown caps */ +
812 4 /* w2k fix, why? */ ;
813
814 s = sec_init(sec_flags, 6 + 14 + caplen + sizeof(RDP_SOURCE));
815
816 out_uint16_le(s, 2 + 14 + caplen + sizeof(RDP_SOURCE));
817 out_uint16_le(s, (RDP_PDU_CONFIRM_ACTIVE | 0x10)); /* Version 1 */
818 out_uint16_le(s, (g_mcs_userid + 1001));
819
820 out_uint32_le(s, g_rdp_shareid);
821 out_uint16_le(s, 0x3ea); /* userid */
822 out_uint16_le(s, sizeof(RDP_SOURCE));
823 out_uint16_le(s, caplen);
824
825 out_uint8p(s, RDP_SOURCE, sizeof(RDP_SOURCE));
826 out_uint16_le(s, 0xd); /* num_caps */
827 out_uint8s(s, 2); /* pad */
828
829 rdp_out_general_caps(s);
830 rdp_out_bitmap_caps(s);
831 rdp_out_order_caps(s);
832 g_use_rdp5 ? rdp_out_bmpcache2_caps(s) : rdp_out_bmpcache_caps(s);
833 rdp_out_colcache_caps(s);
834 rdp_out_activate_caps(s);
835 rdp_out_control_caps(s);
836 rdp_out_pointer_caps(s);
837 rdp_out_share_caps(s);
838
839 rdp_out_unknown_caps(s, 0x0d, 0x58, caps_0x0d); /* international? */
840 rdp_out_unknown_caps(s, 0x0c, 0x08, caps_0x0c);
841 rdp_out_unknown_caps(s, 0x0e, 0x08, caps_0x0e);
842 rdp_out_unknown_caps(s, 0x10, 0x34, caps_0x10); /* glyph cache? */
843
844 s_mark_end(s);
845 sec_send(s, sec_flags);
846 }
847
848 /* Process a general capability set */
849 static void
850 rdp_process_general_caps(STREAM s)
851 {
852 uint16 pad2octetsB; /* rdp5 flags? */
853
854 in_uint8s(s, 10);
855 in_uint16_le(s, pad2octetsB);
856
857 if (!pad2octetsB)
858 g_use_rdp5 = False;
859 }
860
861 /* Process a bitmap capability set */
862 static void
863 rdp_process_bitmap_caps(STREAM s)
864 {
865 uint16 width, height, bpp;
866
867 in_uint16_le(s, bpp);
868 in_uint8s(s, 6);
869
870 in_uint16_le(s, width);
871 in_uint16_le(s, height);
872
873 DEBUG(("setting desktop size and bpp to: %dx%dx%d\n", width, height, bpp));
874
875 /*
876 * The server may limit bpp and change the size of the desktop (for
877 * example when shadowing another session).
878 */
879 if (g_server_bpp != bpp)
880 {
881 warning("colour depth changed from %d to %d\n", g_server_bpp, bpp);
882 g_server_bpp = bpp;
883 }
884 if (g_width != width || g_height != height)
885 {
886 warning("screen size changed from %dx%d to %dx%d\n", g_width, g_height,
887 width, height);
888 g_width = width;
889 g_height = height;
890 ui_resize_window();
891 }
892 }
893
894 /* Process server capabilities */
895 void
896 rdp_process_server_caps(STREAM s, uint16 length)
897 {
898 int n;
899 uint8 *next, *start;
900 uint16 ncapsets, capset_type, capset_length;
901
902 start = s->p;
903
904 in_uint16_le(s, ncapsets);
905 in_uint8s(s, 2); /* pad */
906
907 for (n = 0; n < ncapsets; n++)
908 {
909 if (s->p > start + length)
910 return;
911
912 in_uint16_le(s, capset_type);
913 in_uint16_le(s, capset_length);
914
915 next = s->p + capset_length - 4;
916
917 switch (capset_type)
918 {
919 case RDP_CAPSET_GENERAL:
920 rdp_process_general_caps(s);
921 break;
922
923 case RDP_CAPSET_BITMAP:
924 rdp_process_bitmap_caps(s);
925 break;
926 }
927
928 s->p = next;
929 }
930 }
931
932 /* Respond to a demand active PDU */
933 static void
934 process_demand_active(STREAM s)
935 {
936 uint8 type;
937 uint16 len_src_descriptor, len_combined_caps;
938
939 in_uint32_le(s, g_rdp_shareid);
940 in_uint16_le(s, len_src_descriptor);
941 in_uint16_le(s, len_combined_caps);
942 in_uint8s(s, len_src_descriptor);
943
944 DEBUG(("DEMAND_ACTIVE(id=0x%x)\n", g_rdp_shareid));
945 rdp_process_server_caps(s, len_combined_caps);
946
947 rdp_send_confirm_active();
948 rdp_send_synchronise();
949 rdp_send_control(RDP_CTL_COOPERATE);
950 rdp_send_control(RDP_CTL_REQUEST_CONTROL);
951 rdp_recv(&type); /* RDP_PDU_SYNCHRONIZE */
952 rdp_recv(&type); /* RDP_CTL_COOPERATE */
953 rdp_recv(&type); /* RDP_CTL_GRANT_CONTROL */
954 rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, ui_get_numlock_state(read_keyboard_state()), 0);
955
956 if (g_use_rdp5)
957 {
958 rdp_enum_bmpcache2();
959 rdp_send_fonts(3);
960 }
961 else
962 {
963 rdp_send_fonts(1);
964 rdp_send_fonts(2);
965 }
966
967 rdp_recv(&type); /* RDP_PDU_UNKNOWN 0x28 (Fonts?) */
968 reset_order_state();
969 }
970
971 /* Process a colour pointer PDU */
972 void
973 process_colour_pointer_pdu(STREAM s)
974 {
975 uint16 x, y, width, height, cache_idx, masklen, datalen;
976 uint8 *mask, *data;
977 HCURSOR cursor;
978
979 in_uint16_le(s, cache_idx);
980 in_uint16_le(s, x);
981 in_uint16_le(s, y);
982 in_uint16_le(s, width);
983 in_uint16_le(s, height);
984 in_uint16_le(s, masklen);
985 in_uint16_le(s, datalen);
986 in_uint8p(s, data, datalen);
987 in_uint8p(s, mask, masklen);
988 cursor = ui_create_cursor(x, y, width, height, mask, data);
989 ui_set_cursor(cursor);
990 cache_put_cursor(cache_idx, cursor);
991 }
992
993 /* Process a cached pointer PDU */
994 void
995 process_cached_pointer_pdu(STREAM s)
996 {
997 uint16 cache_idx;
998
999 in_uint16_le(s, cache_idx);
1000 ui_set_cursor(cache_get_cursor(cache_idx));
1001 }
1002
1003 /* Process a system pointer PDU */
1004 void
1005 process_system_pointer_pdu(STREAM s)
1006 {
1007 uint16 system_pointer_type;
1008
1009 in_uint16(s, system_pointer_type);
1010 switch (system_pointer_type)
1011 {
1012 case RDP_NULL_POINTER:
1013 ui_set_null_cursor();
1014 break;
1015
1016 default:
1017 unimpl("System pointer message 0x%x\n", system_pointer_type);
1018 }
1019 }
1020
1021 /* Process a pointer PDU */
1022 static void
1023 process_pointer_pdu(STREAM s)
1024 {
1025 uint16 message_type;
1026 uint16 x, y;
1027
1028 in_uint16_le(s, message_type);
1029 in_uint8s(s, 2); /* pad */
1030
1031 switch (message_type)
1032 {
1033 case RDP_POINTER_MOVE:
1034 in_uint16_le(s, x);
1035 in_uint16_le(s, y);
1036 if (s_check(s))
1037 ui_move_pointer(x, y);
1038 break;
1039
1040 case RDP_POINTER_COLOR:
1041 process_colour_pointer_pdu(s);
1042 break;
1043
1044 case RDP_POINTER_CACHED:
1045 process_cached_pointer_pdu(s);
1046 break;
1047
1048 case RDP_POINTER_SYSTEM:
1049 process_system_pointer_pdu(s);
1050 break;
1051
1052 default:
1053 unimpl("Pointer message 0x%x\n", message_type);
1054 }
1055 }
1056
1057 /* Process bitmap updates */
1058 void
1059 process_bitmap_updates(STREAM s)
1060 {
1061 uint16 num_updates;
1062 uint16 left, top, right, bottom, width, height;
1063 uint16 cx, cy, bpp, Bpp, compress, bufsize, size;
1064 uint8 *data, *bmpdata;
1065 int i;
1066
1067 in_uint16_le(s, num_updates);
1068
1069 for (i = 0; i < num_updates; i++)
1070 {
1071 in_uint16_le(s, left);
1072 in_uint16_le(s, top);
1073 in_uint16_le(s, right);
1074 in_uint16_le(s, bottom);
1075 in_uint16_le(s, width);
1076 in_uint16_le(s, height);
1077 in_uint16_le(s, bpp);
1078 Bpp = (bpp + 7) / 8;
1079 in_uint16_le(s, compress);
1080 in_uint16_le(s, bufsize);
1081
1082 cx = right - left + 1;
1083 cy = bottom - top + 1;
1084
1085 DEBUG(("BITMAP_UPDATE(l=%d,t=%d,r=%d,b=%d,w=%d,h=%d,Bpp=%d,cmp=%d)\n",
1086 left, top, right, bottom, width, height, Bpp, compress));
1087
1088 if (!compress)
1089 {
1090 int y;
1091 bmpdata = (uint8 *) xmalloc(width * height * Bpp);
1092 for (y = 0; y < height; y++)
1093 {
1094 in_uint8a(s, &bmpdata[(height - y - 1) * (width * Bpp)],
1095 width * Bpp);
1096 }
1097 ui_paint_bitmap(left, top, cx, cy, width, height, bmpdata);
1098 xfree(bmpdata);
1099 continue;
1100 }
1101
1102
1103 if (compress & 0x400)
1104 {
1105 size = bufsize;
1106 }
1107 else
1108 {
1109 in_uint8s(s, 2); /* pad */
1110 in_uint16_le(s, size);
1111 in_uint8s(s, 4); /* line_size, final_size */
1112 }
1113 in_uint8p(s, data, size);
1114 bmpdata = (uint8 *) xmalloc(width * height * Bpp);
1115 if (bitmap_decompress(bmpdata, width, height, data, size, Bpp))
1116 {
1117 ui_paint_bitmap(left, top, cx, cy, width, height, bmpdata);
1118 }
1119 else
1120 {
1121 DEBUG_RDP5(("Failed to decompress data\n"));
1122 }
1123
1124 xfree(bmpdata);
1125 }
1126 }
1127
1128 /* Process a palette update */
1129 void
1130 process_palette(STREAM s)
1131 {
1132 COLOURENTRY *entry;
1133 COLOURMAP map;
1134 HCOLOURMAP hmap;
1135 int i;
1136
1137 in_uint8s(s, 2); /* pad */
1138 in_uint16_le(s, map.ncolours);
1139 in_uint8s(s, 2); /* pad */
1140
1141 map.colours = (COLOURENTRY *) xmalloc(sizeof(COLOURENTRY) * map.ncolours);
1142
1143 DEBUG(("PALETTE(c=%d)\n", map.ncolours));
1144
1145 for (i = 0; i < map.ncolours; i++)
1146 {
1147 entry = &map.colours[i];
1148 in_uint8(s, entry->red);
1149 in_uint8(s, entry->green);
1150 in_uint8(s, entry->blue);
1151 }
1152
1153 hmap = ui_create_colourmap(&map);
1154 ui_set_colourmap(hmap);
1155
1156 xfree(map.colours);
1157 }
1158
1159 /* Process an update PDU */
1160 static void
1161 process_update_pdu(STREAM s)
1162 {
1163 uint16 update_type, count;
1164
1165 in_uint16_le(s, update_type);
1166
1167 ui_begin_update();
1168 switch (update_type)
1169 {
1170 case RDP_UPDATE_ORDERS:
1171 in_uint8s(s, 2); /* pad */
1172 in_uint16_le(s, count);
1173 in_uint8s(s, 2); /* pad */
1174 process_orders(s, count);
1175 break;
1176
1177 case RDP_UPDATE_BITMAP:
1178 process_bitmap_updates(s);
1179 break;
1180
1181 case RDP_UPDATE_PALETTE:
1182 process_palette(s);
1183 break;
1184
1185 case RDP_UPDATE_SYNCHRONIZE:
1186 break;
1187
1188 default:
1189 unimpl("update %d\n", update_type);
1190 }
1191 ui_end_update();
1192 }
1193
1194 /* Process a disconnect PDU */
1195 void
1196 process_disconnect_pdu(STREAM s, uint32 * ext_disc_reason)
1197 {
1198 in_uint32_le(s, *ext_disc_reason);
1199
1200 DEBUG(("Received disconnect PDU\n"));
1201 }
1202
1203 /* Process data PDU */
1204 static BOOL
1205 process_data_pdu(STREAM s, uint32 * ext_disc_reason)
1206 {
1207 uint8 data_pdu_type;
1208 uint8 ctype;
1209 uint16 clen;
1210 uint32 len;
1211
1212 uint32 roff, rlen;
1213
1214 struct stream *ns = &(g_mppc_dict.ns);
1215
1216 in_uint8s(s, 6); /* shareid, pad, streamid */
1217 in_uint16(s, len);
1218 in_uint8(s, data_pdu_type);
1219 in_uint8(s, ctype);
1220 in_uint16(s, clen);
1221 clen -= 18;
1222
1223 if (ctype & RDP_MPPC_COMPRESSED)
1224 {
1225 if (len > RDP_MPPC_DICT_SIZE)
1226 error("error decompressed packet size exceeds max\n");
1227 if (mppc_expand(s->p, clen, ctype, &roff, &rlen) == -1)
1228 error("error while decompressing packet\n");
1229
1230 /* len -= 18; */
1231
1232 /* allocate memory and copy the uncompressed data into the temporary stream */
1233 ns->data = (uint8 *) xrealloc(ns->data, rlen);
1234
1235 memcpy((ns->data), (unsigned char *) (g_mppc_dict.hist + roff), rlen);
1236
1237 ns->size = rlen;
1238 ns->end = (ns->data + ns->size);
1239 ns->p = ns->data;
1240 ns->rdp_hdr = ns->p;
1241
1242 s = ns;
1243 }
1244
1245 switch (data_pdu_type)
1246 {
1247 case RDP_DATA_PDU_UPDATE:
1248 process_update_pdu(s);
1249 break;
1250
1251 case RDP_DATA_PDU_CONTROL:
1252 DEBUG(("Received Control PDU\n"));
1253 break;
1254
1255 case RDP_DATA_PDU_SYNCHRONISE:
1256 DEBUG(("Received Sync PDU\n"));
1257 break;
1258
1259 case RDP_DATA_PDU_POINTER:
1260 process_pointer_pdu(s);
1261 break;
1262
1263 case RDP_DATA_PDU_BELL:
1264 ui_bell();
1265 break;
1266
1267 case RDP_DATA_PDU_LOGON:
1268 DEBUG(("Received Logon PDU\n"));
1269 /* User logged on */
1270 break;
1271
1272 case RDP_DATA_PDU_DISCONNECT:
1273 process_disconnect_pdu(s, ext_disc_reason);
1274 return True;
1275
1276 default:
1277 unimpl("data PDU %d\n", data_pdu_type);
1278 }
1279 return False;
1280 }
1281
1282 /* Process incoming packets */
1283 /* nevers gets out of here till app is done */
1284 void
1285 rdp_main_loop(BOOL * deactivated, uint32 * ext_disc_reason)
1286 {
1287 while (rdp_loop(deactivated, ext_disc_reason))
1288 ;
1289 }
1290
1291 /* used in uiports and rdp_main_loop, processes the rdp packets waiting */
1292 BOOL
1293 rdp_loop(BOOL * deactivated, uint32 * ext_disc_reason)
1294 {
1295 uint8 type;
1296 BOOL disc = False; /* True when a disconnect PDU was received */
1297 BOOL cont = True;
1298 STREAM s;
1299
1300 while (cont)
1301 {
1302 s = rdp_recv(&type);
1303 if (s == NULL)
1304 return False;
1305 switch (type)
1306 {
1307 case RDP_PDU_DEMAND_ACTIVE:
1308 process_demand_active(s);
1309 *deactivated = False;
1310 break;
1311 case RDP_PDU_DEACTIVATE:
1312 DEBUG(("RDP_PDU_DEACTIVATE\n"));
1313 *deactivated = True;
1314 break;
1315 case RDP_PDU_DATA:
1316 disc = process_data_pdu(s, ext_disc_reason);
1317 break;
1318 case 0:
1319 break;
1320 default:
1321 unimpl("PDU %d\n", type);
1322 }
1323 if (disc)
1324 return False;
1325 cont = g_next_packet < s->end;
1326 }
1327 return True;
1328 }
1329
1330 /* Establish a connection up to the RDP layer */
1331 BOOL
1332 rdp_connect(char *server, uint32 flags, char *domain, char *password,
1333 char *command, char *directory)
1334 {
1335 if (!sec_connect(server, g_username))
1336 return False;
1337
1338 rdp_send_logon_info(flags, domain, g_username, password, command, directory);
1339 return True;
1340 }
1341
1342 /* Disconnect from the RDP layer */
1343 void
1344 rdp_disconnect(void)
1345 {
1346 sec_disconnect();
1347 }

  ViewVC Help
Powered by ViewVC 1.1.26