/[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 886 - (show annotations)
Sat Apr 16 11:42:34 2005 UTC (19 years, 1 month ago) by stargo
File MIME type: text/plain
File size: 31016 byte(s)
Enable rdp-compression for all bpps.
Many thanks to Vahur Sinijärv <vahur.sinijarv@cydonia.ee> for
finding the fix.

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

  ViewVC Help
Powered by ViewVC 1.1.26