/[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 24 - (show annotations)
Sat Jan 6 03:12:10 2001 UTC (23 years, 5 months ago) by matty
File MIME type: text/plain
File size: 15307 byte(s)
ran indent (-bli0 -i8 -cli8 -npcs -npsl)

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

  ViewVC Help
Powered by ViewVC 1.1.26