/[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 25 - (show annotations)
Sat Jan 6 03:47:04 2001 UTC (23 years, 4 months ago) by matty
File MIME type: text/plain
File size: 15300 byte(s)
Changed indentation style (-psl).

1 /*
2 rdesktop: A Remote Desktop Protocol client.
3 Protocol services - RDP layer
4 Copyright (C) Matthew Chapman 1999-2000
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 "rdesktop.h"
22
23 extern uint16 mcs_userid;
24 extern char username[16];
25 extern BOOL orders;
26
27 unsigned char *next_packet;
28 uint32 rdp_shareid;
29
30 /* Initialise an RDP packet */
31 static STREAM
32 rdp_init(int maxlen)
33 {
34 STREAM s;
35
36 s = sec_init(SEC_ENCRYPT, maxlen + 6);
37 s_push_layer(s, rdp_hdr, 6);
38
39 return s;
40 }
41
42 /* Send an RDP packet */
43 static void
44 rdp_send(STREAM s, uint8 pdu_type)
45 {
46 uint16 length;
47
48 s_pop_layer(s, rdp_hdr);
49 length = s->end - s->p;
50
51 out_uint16_le(s, length);
52 out_uint16_le(s, (pdu_type | 0x10)); /* Version 1 */
53 out_uint16_le(s, (mcs_userid + 1001));
54
55 sec_send(s, SEC_ENCRYPT);
56 }
57
58 /* Receive an RDP packet */
59 static STREAM
60 rdp_recv(uint8 *type)
61 {
62 static STREAM rdp_s;
63 uint16 length, pdu_type;
64
65 if ((rdp_s == NULL) || (next_packet >= rdp_s->end))
66 {
67 rdp_s = sec_recv();
68 if (rdp_s == NULL)
69 return NULL;
70
71 next_packet = rdp_s->p;
72 }
73 else
74 {
75 rdp_s->p = next_packet;
76 }
77
78 in_uint16_le(rdp_s, length);
79 in_uint16_le(rdp_s, pdu_type);
80 in_uint8s(rdp_s, 2); /* userid */
81
82 next_packet += length;
83 *type = pdu_type & 0xf;
84
85 #if RDP_DEBUG
86 DEBUG("RDP packet (type %x):\n", *type);
87 hexdump(rdp_s->p, length);
88 #endif
89
90 return rdp_s;
91 }
92
93 /* Initialise an RDP data packet */
94 static STREAM
95 rdp_init_data(int maxlen)
96 {
97 STREAM s;
98
99 s = sec_init(SEC_ENCRYPT, maxlen + 18);
100 s_push_layer(s, rdp_hdr, 18);
101
102 return s;
103 }
104
105 /* Send an RDP data packet */
106 static void
107 rdp_send_data(STREAM s, uint8 data_pdu_type)
108 {
109 uint16 length;
110
111 s_pop_layer(s, rdp_hdr);
112 length = s->end - s->p;
113
114 out_uint16_le(s, length);
115 out_uint16_le(s, (RDP_PDU_DATA | 0x10));
116 out_uint16_le(s, (mcs_userid + 1001));
117
118 out_uint32_le(s, rdp_shareid);
119 out_uint8(s, 0); /* pad */
120 out_uint8(s, 1); /* streamid */
121 out_uint16(s, (length - 14));
122 out_uint8(s, data_pdu_type);
123 out_uint8(s, 0); /* compress_type */
124 out_uint16(s, 0); /* compress_len */
125
126 sec_send(s, SEC_ENCRYPT);
127 }
128
129 /* Output a string in Unicode */
130 void
131 rdp_out_unistr(STREAM s, char *string, int len)
132 {
133 int i = 0, j = 0;
134
135 len += 2;
136
137 while (i < len)
138 {
139 s->p[i++] = string[j++];
140 s->p[i++] = 0;
141 }
142
143 s->p += len;
144 }
145
146 /* Parse a logon info packet */
147 static void
148 rdp_send_logon_info(uint32 flags, char *domain, char *user,
149 char *password, char *program, char *directory)
150 {
151 int len_domain = 2 * strlen(domain);
152 int len_user = 2 * strlen(user);
153 int len_password = 2 * strlen(password);
154 int len_program = 2 * strlen(program);
155 int len_directory = 2 * strlen(directory);
156 uint32 sec_flags = SEC_LOGON_INFO | SEC_ENCRYPT;
157 STREAM s;
158
159 s = sec_init(sec_flags, 18 + len_domain + len_user + len_password
160 + len_program + len_directory + 10);
161
162 out_uint32(s, 0);
163 out_uint32_le(s, flags);
164 out_uint16_le(s, len_domain);
165 out_uint16_le(s, len_user);
166 out_uint16_le(s, len_password);
167 out_uint16_le(s, len_program);
168 out_uint16_le(s, len_directory);
169 rdp_out_unistr(s, domain, len_domain);
170 rdp_out_unistr(s, user, len_user);
171 rdp_out_unistr(s, password, len_password);
172 rdp_out_unistr(s, program, len_program);
173 rdp_out_unistr(s, directory, len_directory);
174
175 s_mark_end(s);
176 sec_send(s, sec_flags);
177 }
178
179 /* Send a control PDU */
180 static void
181 rdp_send_control(uint16 action)
182 {
183 STREAM s;
184
185 s = rdp_init_data(8);
186
187 out_uint16_le(s, action);
188 out_uint16(s, 0); /* userid */
189 out_uint32(s, 0); /* control id */
190
191 s_mark_end(s);
192 rdp_send_data(s, RDP_DATA_PDU_CONTROL);
193 }
194
195 /* Send a synchronisation PDU */
196 static void
197 rdp_send_synchronise()
198 {
199 STREAM s;
200
201 s = rdp_init_data(4);
202
203 out_uint16_le(s, 1); /* type */
204 out_uint16_le(s, 1002);
205
206 s_mark_end(s);
207 rdp_send_data(s, RDP_DATA_PDU_SYNCHRONISE);
208 }
209
210 /* Send a single input event */
211 void
212 rdp_send_input(uint32 time, uint16 message_type, uint16 device_flags,
213 uint16 param1, uint16 param2)
214 {
215 STREAM s;
216
217 s = rdp_init_data(16);
218
219 out_uint16_le(s, 1); /* number of events */
220 out_uint16(s, 0); /* pad */
221
222 out_uint32_le(s, time);
223 out_uint16_le(s, message_type);
224 out_uint16_le(s, device_flags);
225 out_uint16_le(s, param1);
226 out_uint16_le(s, param2);
227
228 s_mark_end(s);
229 rdp_send_data(s, RDP_DATA_PDU_INPUT);
230 }
231
232 /* Send an (empty) font information PDU */
233 static void
234 rdp_send_fonts(uint16 seq)
235 {
236 STREAM s;
237
238 s = rdp_init_data(8);
239
240 out_uint16(s, 0); /* number of fonts */
241 out_uint16_le(s, 0x3e); /* unknown */
242 out_uint16_le(s, seq); /* unknown */
243 out_uint16_le(s, 0x32); /* entry size */
244
245 s_mark_end(s);
246 rdp_send_data(s, RDP_DATA_PDU_FONT2);
247 }
248
249 /* Output general capability set */
250 static void
251 rdp_out_general_caps(STREAM s)
252 {
253 out_uint16_le(s, RDP_CAPSET_GENERAL);
254 out_uint16_le(s, RDP_CAPLEN_GENERAL);
255
256 out_uint16_le(s, 1); /* OS major type */
257 out_uint16_le(s, 3); /* OS minor type */
258 out_uint16_le(s, 0x200); /* Protocol version */
259 out_uint16(s, 0); /* Pad */
260 out_uint16(s, 0); /* Compression types */
261 out_uint16(s, 0); /* Pad */
262 out_uint16(s, 0); /* Update capability */
263 out_uint16(s, 0); /* Remote unshare capability */
264 out_uint16(s, 0); /* Compression level */
265 out_uint16(s, 0); /* Pad */
266 }
267
268 /* Output bitmap capability set */
269 static void
270 rdp_out_bitmap_caps(STREAM s)
271 {
272 out_uint16_le(s, RDP_CAPSET_BITMAP);
273 out_uint16_le(s, RDP_CAPLEN_BITMAP);
274
275 out_uint16_le(s, 8); /* Preferred BPP */
276 out_uint16(s, 1); /* Receive 1 BPP */
277 out_uint16(s, 1); /* Receive 4 BPP */
278 out_uint16_le(s, 1); /* Receive 8 BPP */
279 out_uint16_le(s, 800); /* Desktop width */
280 out_uint16_le(s, 600); /* Desktop height */
281 out_uint16(s, 0); /* Pad */
282 out_uint16(s, 0); /* Allow resize */
283 out_uint16_le(s, 1); /* Support compression */
284 out_uint16(s, 0); /* Unknown */
285 out_uint16_le(s, 1); /* Unknown */
286 out_uint16(s, 0); /* Pad */
287 }
288
289 /* Output order capability set */
290 static void
291 rdp_out_order_caps(STREAM s)
292 {
293 uint8 order_caps[32];
294
295 memset(order_caps, orders, 32);
296
297 out_uint16_le(s, RDP_CAPSET_ORDER);
298 out_uint16_le(s, RDP_CAPLEN_ORDER);
299
300 out_uint8s(s, 20); /* Terminal desc, pad */
301 out_uint16_le(s, 1); /* Cache X granularity */
302 out_uint16_le(s, 20); /* Cache Y granularity */
303 out_uint16(s, 0); /* Pad */
304 out_uint16_le(s, 1); /* Max order level */
305 out_uint16_le(s, 0x147); /* Number of fonts */
306 out_uint16_le(s, 0x2a); /* Capability flags */
307 out_uint8p(s, order_caps, 32); /* Orders supported */
308 out_uint16_le(s, 0x6a1); /* Text capability flags */
309 out_uint8s(s, 6); /* Pad */
310 out_uint32(s, 0x38400); /* Desktop cache size */
311 out_uint32(s, 0); /* Unknown */
312 out_uint32(s, 0x4e4); /* Unknown */
313 }
314
315 /* Output bitmap cache capability set */
316 static void
317 rdp_out_bmpcache_caps(STREAM s)
318 {
319 out_uint16_le(s, RDP_CAPSET_BMPCACHE);
320 out_uint16_le(s, RDP_CAPLEN_BMPCACHE);
321
322 out_uint8s(s, 24); /* unused */
323 out_uint16_le(s, 0x258); /* entries */
324 out_uint16_le(s, 0x100); /* max cell size */
325 out_uint16_le(s, 0x12c); /* entries */
326 out_uint16_le(s, 0x400); /* max cell size */
327 out_uint16_le(s, 0x106); /* entries */
328 out_uint16_le(s, 0x1000); /* max cell size */
329 }
330
331 /* Output control capability set */
332 static void
333 rdp_out_control_caps(STREAM s)
334 {
335 out_uint16_le(s, RDP_CAPSET_CONTROL);
336 out_uint16_le(s, RDP_CAPLEN_CONTROL);
337
338 out_uint16(s, 0); /* Control capabilities */
339 out_uint16(s, 0); /* Remote detach */
340 out_uint16_le(s, 2); /* Control interest */
341 out_uint16_le(s, 2); /* Detach interest */
342 }
343
344 /* Output activation capability set */
345 static void
346 rdp_out_activate_caps(STREAM s)
347 {
348 out_uint16_le(s, RDP_CAPSET_ACTIVATE);
349 out_uint16_le(s, RDP_CAPLEN_ACTIVATE);
350
351 out_uint16(s, 0); /* Help key */
352 out_uint16(s, 0); /* Help index key */
353 out_uint16(s, 0); /* Extended help key */
354 out_uint16(s, 0); /* Window activate */
355 }
356
357 /* Output pointer capability set */
358 static void
359 rdp_out_pointer_caps(STREAM s)
360 {
361 out_uint16_le(s, RDP_CAPSET_POINTER);
362 out_uint16_le(s, RDP_CAPLEN_POINTER);
363
364 out_uint16(s, 0); /* Colour pointer */
365 out_uint16_le(s, 20); /* Cache size */
366 }
367
368 /* Output share capability set */
369 static void
370 rdp_out_share_caps(STREAM s)
371 {
372 out_uint16_le(s, RDP_CAPSET_SHARE);
373 out_uint16_le(s, RDP_CAPLEN_SHARE);
374
375 out_uint16(s, 0); /* userid */
376 out_uint16(s, 0); /* pad */
377 }
378
379 /* Output colour cache capability set */
380 static void
381 rdp_out_colcache_caps(STREAM s)
382 {
383 out_uint16_le(s, RDP_CAPSET_COLCACHE);
384 out_uint16_le(s, RDP_CAPLEN_COLCACHE);
385
386 out_uint16_le(s, 6); /* cache size */
387 out_uint16(s, 0); /* pad */
388 }
389
390 static uint8 canned_caps[] = {
391 0x01, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x04,
392 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
393 0x00, 0x00, 0x00, 0x00, 0x00,
394 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
395 0x00, 0x00, 0x00, 0x00, 0x00,
396 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
397 0x00, 0x00, 0x00, 0x00, 0x00,
398 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
399 0x00, 0x00, 0x00, 0x00, 0x00,
400 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
401 0x0C, 0x00, 0x08, 0x00, 0x01,
402 0x00, 0x00, 0x00, 0x0E, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00,
403 0x10, 0x00, 0x34, 0x00, 0xFE,
404 0x00, 0x04, 0x00, 0xFE, 0x00, 0x04, 0x00, 0xFE, 0x00, 0x08, 0x00,
405 0xFE, 0x00, 0x08, 0x00, 0xFE,
406 0x00, 0x10, 0x00, 0xFE, 0x00, 0x20, 0x00, 0xFE, 0x00, 0x40, 0x00,
407 0xFE, 0x00, 0x80, 0x00, 0xFE,
408 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x01,
409 0x02, 0x00, 0x00, 0x00
410 };
411
412 /* Output unknown capability set */
413 static void
414 rdp_out_unknown_caps(STREAM s)
415 {
416 out_uint16_le(s, RDP_CAPSET_UNKNOWN);
417 out_uint16_le(s, 0x58);
418
419 out_uint8p(s, canned_caps, RDP_CAPLEN_UNKNOWN - 4);
420 }
421
422 /* Send a confirm active PDU */
423 static void
424 rdp_send_confirm_active()
425 {
426 STREAM s;
427 uint16 caplen =
428 RDP_CAPLEN_GENERAL + RDP_CAPLEN_BITMAP + RDP_CAPLEN_ORDER +
429 RDP_CAPLEN_BMPCACHE + RDP_CAPLEN_COLCACHE +
430 RDP_CAPLEN_ACTIVATE + RDP_CAPLEN_CONTROL +
431 RDP_CAPLEN_POINTER + RDP_CAPLEN_SHARE + RDP_CAPLEN_UNKNOWN;
432
433 s = rdp_init(14 + caplen + sizeof(RDP_SOURCE));
434
435 out_uint32_le(s, rdp_shareid);
436 out_uint16_le(s, 0x3ea); /* userid */
437 out_uint16_le(s, sizeof(RDP_SOURCE));
438 out_uint16_le(s, caplen);
439
440 out_uint8p(s, RDP_SOURCE, sizeof(RDP_SOURCE));
441 out_uint16_le(s, 0xd); /* num_caps */
442 out_uint8s(s, 2); /* pad */
443
444 rdp_out_general_caps(s);
445 rdp_out_bitmap_caps(s);
446 rdp_out_order_caps(s);
447 rdp_out_bmpcache_caps(s);
448 rdp_out_colcache_caps(s);
449 rdp_out_activate_caps(s);
450 rdp_out_control_caps(s);
451 rdp_out_pointer_caps(s);
452 rdp_out_share_caps(s);
453 rdp_out_unknown_caps(s);
454
455 s_mark_end(s);
456 rdp_send(s, RDP_PDU_CONFIRM_ACTIVE);
457 }
458
459 /* Respond to a demand active PDU */
460 static void
461 process_demand_active(STREAM s)
462 {
463 uint8 type;
464
465 in_uint32_le(s, rdp_shareid);
466
467 DEBUG("DEMAND_ACTIVE(id=0x%x)\n", rdp_shareid);
468
469 rdp_send_confirm_active();
470 rdp_send_synchronise();
471 rdp_send_control(RDP_CTL_COOPERATE);
472 rdp_send_control(RDP_CTL_REQUEST_CONTROL);
473 rdp_recv(&type); // RDP_PDU_SYNCHRONIZE
474 rdp_recv(&type); // RDP_CTL_COOPERATE
475 rdp_recv(&type); // RDP_CTL_GRANT_CONTROL
476 rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, 0, 0);
477 rdp_send_fonts(1);
478 rdp_send_fonts(2);
479 rdp_recv(&type); // RDP_PDU_UNKNOWN 0x28
480 reset_order_state();
481 }
482
483 /* Process a pointer PDU */
484 static void
485 process_pointer_pdu(STREAM s)
486 {
487 uint16 message_type;
488 uint16 x, y;
489
490 in_uint16_le(s, message_type);
491 in_uint8s(s, 2); /* pad */
492
493 switch (message_type)
494 {
495 case RDP_POINTER_MOVE:
496 in_uint16_le(s, x);
497 in_uint16_le(s, y);
498 if (s_check(s))
499 ui_move_pointer(x, y);
500 break;
501
502 default:
503 DEBUG("Pointer message 0x%x\n", message_type);
504 }
505 }
506
507 /* Process bitmap updates */
508 static void
509 process_bitmap_updates(STREAM s)
510 {
511 uint16 num_updates;
512 uint16 left, top, right, bottom, width, height;
513 uint16 cx, cy, bpp, compress, bufsize, size;
514 uint8 *data, *rawdata;
515 int i;
516
517 in_uint16_le(s, num_updates);
518
519 for (i = 0; i < num_updates; i++)
520 {
521 in_uint16_le(s, left);
522 in_uint16_le(s, top);
523 in_uint16_le(s, right);
524 in_uint16_le(s, bottom);
525 in_uint16_le(s, width);
526 in_uint16_le(s, height);
527 in_uint16_le(s, bpp);
528 in_uint16_le(s, compress);
529 in_uint16_le(s, bufsize);
530
531 cx = right - left + 1;
532 cy = bottom - top + 1;
533
534 DEBUG("UPDATE(l=%d,t=%d,r=%d,b=%d,w=%d,h=%d,cmp=%d)\n",
535 left, top, right, bottom, width, height, compress);
536
537 if (!compress)
538 {
539 in_uint8p(s, data, bufsize);
540 ui_paint_bitmap(left, top, cx, cy, width, height,
541 data);
542 return;
543 }
544
545 in_uint8s(s, 2); /* pad */
546 in_uint16_le(s, size);
547 in_uint8s(s, 4); /* line_size, final_size */
548 in_uint8p(s, data, size);
549
550 rawdata = xmalloc(width * height);
551 if (bitmap_decompress(rawdata, width, height, data, size))
552 {
553 ui_paint_bitmap(left, top, cx, cy, width, height,
554 rawdata);
555 }
556
557 xfree(rawdata);
558 }
559 }
560
561 /* Process a palette update */
562 static void
563 process_palette(STREAM s)
564 {
565 HCOLOURMAP hmap;
566 COLOURMAP map;
567
568 in_uint8s(s, 2); /* pad */
569 in_uint16_le(s, map.ncolours);
570 in_uint8s(s, 2); /* pad */
571 in_uint8p(s, (uint8 *) map.colours, (map.ncolours * 3));
572
573 hmap = ui_create_colourmap(&map);
574 ui_set_colourmap(hmap);
575 }
576
577 /* Process an update PDU */
578 static void
579 process_update_pdu(STREAM s)
580 {
581 uint16 update_type;
582
583 in_uint16_le(s, update_type);
584
585 switch (update_type)
586 {
587 case RDP_UPDATE_ORDERS:
588 process_orders(s);
589 break;
590
591 case RDP_UPDATE_BITMAP:
592 process_bitmap_updates(s);
593 break;
594
595 case RDP_UPDATE_PALETTE:
596 process_palette(s);
597 break;
598
599 case RDP_UPDATE_SYNCHRONIZE:
600 break;
601
602 default:
603 NOTIMP("update %d\n", update_type);
604 }
605
606 }
607
608 /* Process data PDU */
609 static void
610 process_data_pdu(STREAM s)
611 {
612 uint8 data_pdu_type;
613
614 in_uint8s(s, 8); /* shareid, pad, streamid, length */
615 in_uint8(s, data_pdu_type);
616 in_uint8s(s, 3); /* compress_type, compress_len */
617
618 switch (data_pdu_type)
619 {
620 case RDP_DATA_PDU_UPDATE:
621 process_update_pdu(s);
622 break;
623
624 case RDP_DATA_PDU_POINTER:
625 process_pointer_pdu(s);
626 break;
627
628 case RDP_DATA_PDU_BELL:
629 ui_bell();
630 break;
631
632 case RDP_DATA_PDU_LOGON:
633 /* User logged on */
634 break;
635
636 default:
637 NOTIMP("data PDU %d\n", data_pdu_type);
638 }
639 }
640
641 /* Process incoming packets */
642 void
643 rdp_main_loop()
644 {
645 uint8 type;
646 STREAM s;
647
648 while ((s = rdp_recv(&type)) != NULL)
649 {
650 switch (type)
651 {
652 case RDP_PDU_DEMAND_ACTIVE:
653 process_demand_active(s);
654 break;
655
656 case RDP_PDU_DEACTIVATE:
657 break;
658
659 case RDP_PDU_DATA:
660 process_data_pdu(s);
661 break;
662
663 default:
664 NOTIMP("PDU %d\n", type);
665 }
666 }
667 }
668
669 /* Establish a connection up to the RDP layer */
670 BOOL
671 rdp_connect(char *server, uint32 flags, char *domain, char *password,
672 char *command, char *directory)
673 {
674 if (!sec_connect(server))
675 return False;
676
677 rdp_send_logon_info(flags, domain, username, password,
678 command, directory);
679 return True;
680 }
681
682 /* Disconnect from the RDP layer */
683 void
684 rdp_disconnect()
685 {
686 sec_disconnect();
687 }

  ViewVC Help
Powered by ViewVC 1.1.26