/[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 864 - (show annotations)
Mon Mar 14 18:02:24 2005 UTC (19 years, 2 months ago) by stargo
File MIME type: text/plain
File size: 30683 byte(s)
handle iconv-failure more gracefully

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

  ViewVC Help
Powered by ViewVC 1.1.26