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