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