/[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 10 - (show annotations)
Tue Aug 15 10:23:24 2000 UTC (23 years, 8 months ago) by matty
File MIME type: text/plain
File size: 15056 byte(s)
Major commit of work from laptop - done in various free moments.
Implemented encryption layer and some basic licensing negotiation.
Reorganised code somewhat. While this is not quite as clean, it is
a lot faster - our parser speed was becoming a bottle-neck.

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

  ViewVC Help
Powered by ViewVC 1.1.26