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