VirtualBox

source: vbox/trunk/src/VBox/RDP/client/rdesktop.c@ 9902

Last change on this file since 9902 was 9902, checked in by vboxsync, 16 years ago

Added rdesktop 1.6.0.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.5 KB
Line 
1/* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Entrypoint and utility functions
4 Copyright (C) Matthew Chapman 1999-2008
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 <stdarg.h> /* va_list va_start va_end */
22#include <unistd.h> /* read close getuid getgid getpid getppid gethostname */
23#include <fcntl.h> /* open */
24#include <pwd.h> /* getpwuid */
25#include <termios.h> /* tcgetattr tcsetattr */
26#include <sys/stat.h> /* stat */
27#include <sys/time.h> /* gettimeofday */
28#include <sys/times.h> /* times */
29#include <ctype.h> /* toupper */
30#include <errno.h>
31#include "rdesktop.h"
32
33#ifdef HAVE_LOCALE_H
34#include <locale.h>
35#endif
36#ifdef HAVE_ICONV
37#ifdef HAVE_LANGINFO_H
38#include <langinfo.h>
39#endif
40#endif
41
42#ifdef EGD_SOCKET
43#include <sys/types.h>
44#include <sys/socket.h> /* socket connect */
45#include <sys/un.h> /* sockaddr_un */
46#endif
47
48#include "ssl.h"
49
50char g_title[64] = "";
51char g_username[64];
52char g_hostname[16];
53char g_keymapname[PATH_MAX] = "";
54unsigned int g_keylayout = 0x409; /* Defaults to US keyboard layout */
55int g_keyboard_type = 0x4; /* Defaults to US keyboard layout */
56int g_keyboard_subtype = 0x0; /* Defaults to US keyboard layout */
57int g_keyboard_functionkeys = 0xc; /* Defaults to US keyboard layout */
58
59int g_width = 800; /* width is special: If 0, the
60 geometry will be fetched from
61 _NET_WORKAREA. If negative,
62 absolute value specifies the
63 percent of the whole screen. */
64int g_height = 600;
65int g_xpos = 0;
66int g_ypos = 0;
67int g_pos = 0; /* 0 position unspecified,
68 1 specified,
69 2 xpos neg,
70 4 ypos neg */
71extern int g_tcp_port_rdp;
72int g_server_depth = -1;
73int g_win_button_size = 0; /* If zero, disable single app mode */
74RD_BOOL g_bitmap_compression = True;
75RD_BOOL g_sendmotion = True;
76RD_BOOL g_bitmap_cache = True;
77RD_BOOL g_bitmap_cache_persist_enable = False;
78RD_BOOL g_bitmap_cache_precache = True;
79RD_BOOL g_encryption = True;
80RD_BOOL g_packet_encryption = True;
81RD_BOOL g_desktop_save = True; /* desktop save order */
82RD_BOOL g_polygon_ellipse_orders = True; /* polygon / ellipse orders */
83RD_BOOL g_fullscreen = False;
84RD_BOOL g_grab_keyboard = True;
85RD_BOOL g_hide_decorations = False;
86RD_BOOL g_use_rdp5 = True;
87RD_BOOL g_rdpclip = True;
88RD_BOOL g_console_session = False;
89RD_BOOL g_numlock_sync = False;
90RD_BOOL g_lspci_enabled = False;
91RD_BOOL g_owncolmap = False;
92RD_BOOL g_ownbackstore = True; /* We can't rely on external BackingStore */
93RD_BOOL g_seamless_rdp = False;
94uint32 g_embed_wnd;
95uint32 g_rdp5_performanceflags =
96 RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG | RDP5_NO_MENUANIMATIONS;
97/* Session Directory redirection */
98RD_BOOL g_redirect = False;
99char g_redirect_server[64];
100char g_redirect_domain[16];
101char g_redirect_password[64];
102char g_redirect_username[64];
103char g_redirect_cookie[128];
104uint32 g_redirect_flags = 0;
105
106#ifdef WITH_RDPSND
107RD_BOOL g_rdpsnd = False;
108#endif
109
110#ifdef WITH_RDPUSB
111RD_BOOL g_rdpusb = False;
112#endif
113
114#ifdef HAVE_ICONV
115char g_codepage[16] = "";
116#endif
117
118extern RDPDR_DEVICE g_rdpdr_device[];
119extern uint32 g_num_devices;
120extern char *g_rdpdr_clientname;
121
122#ifdef RDP2VNC
123extern int rfb_port;
124extern int defer_time;
125void
126rdp2vnc_connect(char *server, uint32 flags, char *domain, char *password,
127 char *shell, char *directory);
128#endif
129/* Display usage information */
130static void
131usage(char *program)
132{
133 fprintf(stderr, "rdesktop: A Remote Desktop Protocol client.\n");
134 fprintf(stderr, "Version " VERSION ". Copyright (C) 1999-2008 Matthew Chapman.\n");
135 fprintf(stderr, "Modified for VirtualBox by Sun Microsystems, Inc.\n");
136 fprintf(stderr, "See http://www.rdesktop.org/ for more information.\n\n");
137
138 fprintf(stderr, "Usage: %s [options] server[:port]\n", program);
139#ifdef RDP2VNC
140 fprintf(stderr, " -V: vnc port\n");
141 fprintf(stderr, " -Q: defer time (ms)\n");
142#endif
143 fprintf(stderr, " -u: user name\n");
144 fprintf(stderr, " -d: domain\n");
145 fprintf(stderr, " -s: shell\n");
146 fprintf(stderr, " -c: working directory\n");
147 fprintf(stderr, " -p: password (- to prompt)\n");
148 fprintf(stderr, " -n: client hostname\n");
149 fprintf(stderr, " -k: keyboard layout on server (en-us, de, sv, etc.)\n");
150 fprintf(stderr, " -g: desktop geometry (WxH)\n");
151 fprintf(stderr, " -f: full-screen mode\n");
152 fprintf(stderr, " -b: force bitmap updates\n");
153#ifdef HAVE_ICONV
154 fprintf(stderr, " -L: local codepage\n");
155#endif
156 fprintf(stderr, " -A: enable SeamlessRDP mode\n");
157 fprintf(stderr, " -B: use BackingStore of X-server (if available)\n");
158 fprintf(stderr, " -e: disable encryption (French TS)\n");
159 fprintf(stderr, " -E: disable encryption from client to server\n");
160 fprintf(stderr, " -m: do not send motion events\n");
161 fprintf(stderr, " -C: use private colour map\n");
162 fprintf(stderr, " -D: hide window manager decorations\n");
163 fprintf(stderr, " -K: keep window manager key bindings\n");
164 fprintf(stderr, " -S: caption button size (single application mode)\n");
165 fprintf(stderr, " -T: window title\n");
166 fprintf(stderr, " -N: enable numlock syncronization\n");
167 fprintf(stderr, " -X: embed into another window with a given id.\n");
168 fprintf(stderr, " -a: connection colour depth\n");
169 fprintf(stderr, " -z: enable rdp compression\n");
170 fprintf(stderr, " -x: RDP5 experience (m[odem 28.8], b[roadband], l[an] or hex nr.)\n");
171 fprintf(stderr, " -P: use persistent bitmap caching\n");
172 fprintf(stderr, " -r: enable specified device redirection (this flag can be repeated)\n");
173 fprintf(stderr,
174 " '-r comport:COM1=/dev/ttyS0': enable serial redirection of /dev/ttyS0 to COM1\n");
175 fprintf(stderr, " or COM1=/dev/ttyS0,COM2=/dev/ttyS1\n");
176 fprintf(stderr,
177 " '-r disk:floppy=/mnt/floppy': enable redirection of /mnt/floppy to 'floppy' share\n");
178 fprintf(stderr, " or 'floppy=/mnt/floppy,cdrom=/mnt/cdrom'\n");
179 fprintf(stderr, " '-r clientname=<client name>': Set the client name displayed\n");
180 fprintf(stderr, " for redirected disks\n");
181 fprintf(stderr,
182 " '-r lptport:LPT1=/dev/lp0': enable parallel redirection of /dev/lp0 to LPT1\n");
183 fprintf(stderr, " or LPT1=/dev/lp0,LPT2=/dev/lp1\n");
184 fprintf(stderr, " '-r printer:mydeskjet': enable printer redirection\n");
185 fprintf(stderr,
186 " or mydeskjet=\"HP LaserJet IIIP\" to enter server driver as well\n");
187#ifdef WITH_RDPSND
188 fprintf(stderr,
189 " '-r sound:[local[:driver[:device]]|off|remote]': enable sound redirection\n");
190 fprintf(stderr, " remote would leave sound on server\n");
191 fprintf(stderr, " available drivers for 'local':\n");
192 rdpsnd_show_help();
193#endif
194#ifdef WITH_RDPUSB
195 fprintf(stderr,
196 " '-r usb': enable USB redirection\n");
197#endif
198 fprintf(stderr,
199 " '-r clipboard:[off|PRIMARYCLIPBOARD|CLIPBOARD]': enable clipboard\n");
200 fprintf(stderr, " redirection.\n");
201 fprintf(stderr,
202 " 'PRIMARYCLIPBOARD' looks at both PRIMARY and CLIPBOARD\n");
203 fprintf(stderr, " when sending data to server.\n");
204 fprintf(stderr, " 'CLIPBOARD' looks at only CLIPBOARD.\n");
205#ifdef WITH_SCARD
206 fprintf(stderr, " '-r scard[:\"Scard Name\"=\"Alias Name[;Vendor Name]\"[,...]]\n");
207 fprintf(stderr, " example: -r scard:\"eToken PRO 00 00\"=\"AKS ifdh 0\"\n");
208 fprintf(stderr,
209 " \"eToken PRO 00 00\" -> Device in Linux/Unix enviroment\n");
210 fprintf(stderr,
211 " \"AKS ifdh 0\" -> Device shown in Windows enviroment \n");
212 fprintf(stderr, " example: -r scard:\"eToken PRO 00 00\"=\"AKS ifdh 0;AKS\"\n");
213 fprintf(stderr,
214 " \"eToken PRO 00 00\" -> Device in Linux/Unix enviroment\n");
215 fprintf(stderr,
216 " \"AKS ifdh 0\" -> Device shown in Windows enviroment \n");
217 fprintf(stderr,
218 " \"AKS\" -> Device vendor name \n");
219#endif
220 fprintf(stderr, " -0: attach to console\n");
221 fprintf(stderr, " -4: use RDP version 4\n");
222 fprintf(stderr, " -5: use RDP version 5 (default)\n");
223}
224
225static void
226print_disconnect_reason(uint16 reason)
227{
228 char *text;
229
230 switch (reason)
231 {
232 case exDiscReasonNoInfo:
233 text = "No information available";
234 break;
235
236 case exDiscReasonAPIInitiatedDisconnect:
237 text = "Server initiated disconnect";
238 break;
239
240 case exDiscReasonAPIInitiatedLogoff:
241 text = "Server initiated logoff";
242 break;
243
244 case exDiscReasonServerIdleTimeout:
245 text = "Server idle timeout reached";
246 break;
247
248 case exDiscReasonServerLogonTimeout:
249 text = "Server logon timeout reached";
250 break;
251
252 case exDiscReasonReplacedByOtherConnection:
253 text = "The session was replaced";
254 break;
255
256 case exDiscReasonOutOfMemory:
257 text = "The server is out of memory";
258 break;
259
260 case exDiscReasonServerDeniedConnection:
261 text = "The server denied the connection";
262 break;
263
264 case exDiscReasonServerDeniedConnectionFips:
265 text = "The server denied the connection for security reason";
266 break;
267
268 case exDiscReasonLicenseInternal:
269 text = "Internal licensing error";
270 break;
271
272 case exDiscReasonLicenseNoLicenseServer:
273 text = "No license server available";
274 break;
275
276 case exDiscReasonLicenseNoLicense:
277 text = "No valid license available";
278 break;
279
280 case exDiscReasonLicenseErrClientMsg:
281 text = "Invalid licensing message";
282 break;
283
284 case exDiscReasonLicenseHwidDoesntMatchLicense:
285 text = "Hardware id doesn't match software license";
286 break;
287
288 case exDiscReasonLicenseErrClientLicense:
289 text = "Client license error";
290 break;
291
292 case exDiscReasonLicenseCantFinishProtocol:
293 text = "Network error during licensing protocol";
294 break;
295
296 case exDiscReasonLicenseClientEndedProtocol:
297 text = "Licensing protocol was not completed";
298 break;
299
300 case exDiscReasonLicenseErrClientEncryption:
301 text = "Incorrect client license enryption";
302 break;
303
304 case exDiscReasonLicenseCantUpgradeLicense:
305 text = "Can't upgrade license";
306 break;
307
308 case exDiscReasonLicenseNoRemoteConnections:
309 text = "The server is not licensed to accept remote connections";
310 break;
311
312 default:
313 if (reason > 0x1000 && reason < 0x7fff)
314 {
315 text = "Internal protocol error";
316 }
317 else
318 {
319 text = "Unknown reason";
320 }
321 }
322 fprintf(stderr, "disconnect: %s.\n", text);
323}
324
325static void
326rdesktop_reset_state(void)
327{
328 rdp_reset_state();
329}
330
331static RD_BOOL
332read_password(char *password, int size)
333{
334 struct termios tios;
335 RD_BOOL ret = False;
336 int istty = 0;
337 char *p;
338
339 if (tcgetattr(STDIN_FILENO, &tios) == 0)
340 {
341 fprintf(stderr, "Password: ");
342 tios.c_lflag &= ~ECHO;
343 tcsetattr(STDIN_FILENO, TCSANOW, &tios);
344 istty = 1;
345 }
346
347 if (fgets(password, size, stdin) != NULL)
348 {
349 ret = True;
350
351 /* strip final newline */
352 p = strchr(password, '\n');
353 if (p != NULL)
354 *p = 0;
355 }
356
357 if (istty)
358 {
359 tios.c_lflag |= ECHO;
360 tcsetattr(STDIN_FILENO, TCSANOW, &tios);
361 fprintf(stderr, "\n");
362 }
363
364 return ret;
365}
366
367static void
368parse_server_and_port(char *server)
369{
370 char *p;
371#ifdef IPv6
372 int addr_colons;
373#endif
374
375#ifdef IPv6
376 p = server;
377 addr_colons = 0;
378 while (*p)
379 if (*p++ == ':')
380 addr_colons++;
381 if (addr_colons >= 2)
382 {
383 /* numeric IPv6 style address format - [1:2:3::4]:port */
384 p = strchr(server, ']');
385 if (*server == '[' && p != NULL)
386 {
387 if (*(p + 1) == ':' && *(p + 2) != '\0')
388 g_tcp_port_rdp = strtol(p + 2, NULL, 10);
389 /* remove the port number and brackets from the address */
390 *p = '\0';
391 strncpy(server, server + 1, strlen(server));
392 }
393 }
394 else
395 {
396 /* dns name or IPv4 style address format - server.example.com:port or 1.2.3.4:port */
397 p = strchr(server, ':');
398 if (p != NULL)
399 {
400 g_tcp_port_rdp = strtol(p + 1, NULL, 10);
401 *p = 0;
402 }
403 }
404#else /* no IPv6 support */
405 p = strchr(server, ':');
406 if (p != NULL)
407 {
408 g_tcp_port_rdp = strtol(p + 1, NULL, 10);
409 *p = 0;
410 }
411#endif /* IPv6 */
412
413}
414
415/* Client program */
416int
417main(int argc, char *argv[])
418{
419 char server[64];
420 char fullhostname[64];
421 char domain[16];
422 char password[64];
423 char shell[256];
424 char directory[256];
425 RD_BOOL prompt_password, deactivated;
426 struct passwd *pw;
427 uint32 flags, ext_disc_reason = 0;
428 char *p;
429 int c;
430 char *locale = NULL;
431 int username_option = 0;
432 RD_BOOL geometry_option = False;
433 int run_count = 0; /* Session Directory support */
434 RD_BOOL continue_connect = True; /* Session Directory support */
435#ifdef WITH_RDPSND
436 char *rdpsnd_optarg = NULL;
437#endif
438
439#ifdef HAVE_LOCALE_H
440 /* Set locale according to environment */
441 locale = setlocale(LC_ALL, "");
442 if (locale)
443 {
444 locale = xstrdup(locale);
445 }
446
447#endif
448 flags = RDP_LOGON_NORMAL;
449 prompt_password = False;
450 domain[0] = password[0] = shell[0] = directory[0] = 0;
451 g_embed_wnd = 0;
452
453 g_num_devices = 0;
454
455#ifdef RDP2VNC
456#define VNCOPT "V:Q:"
457#else
458#define VNCOPT
459#endif
460
461 while ((c = getopt(argc, argv,
462 VNCOPT "Au:L:d:s:c:p:n:k:g:fbBeEmzCDKS:T:NX:a:x:Pr:045h?")) != -1)
463 {
464 switch (c)
465 {
466#ifdef RDP2VNC
467 case 'V':
468 rfb_port = strtol(optarg, NULL, 10);
469 if (rfb_port < 100)
470 rfb_port += 5900;
471 break;
472
473 case 'Q':
474 defer_time = strtol(optarg, NULL, 10);
475 if (defer_time < 0)
476 defer_time = 0;
477 break;
478#endif
479
480 case 'A':
481 g_seamless_rdp = True;
482 break;
483
484 case 'u':
485 STRNCPY(g_username, optarg, sizeof(g_username));
486 username_option = 1;
487 break;
488
489 case 'L':
490#ifdef HAVE_ICONV
491 STRNCPY(g_codepage, optarg, sizeof(g_codepage));
492#else
493 error("iconv support not available\n");
494#endif
495 break;
496
497 case 'd':
498 STRNCPY(domain, optarg, sizeof(domain));
499 break;
500
501 case 's':
502 STRNCPY(shell, optarg, sizeof(shell));
503 break;
504
505 case 'c':
506 STRNCPY(directory, optarg, sizeof(directory));
507 break;
508
509 case 'p':
510 if ((optarg[0] == '-') && (optarg[1] == 0))
511 {
512 prompt_password = True;
513 break;
514 }
515
516 STRNCPY(password, optarg, sizeof(password));
517 flags |= RDP_LOGON_AUTO;
518
519 /* try to overwrite argument so it won't appear in ps */
520 p = optarg;
521 while (*p)
522 *(p++) = 'X';
523 break;
524
525 case 'n':
526 STRNCPY(g_hostname, optarg, sizeof(g_hostname));
527 break;
528
529 case 'k':
530 STRNCPY(g_keymapname, optarg, sizeof(g_keymapname));
531 break;
532
533 case 'g':
534 geometry_option = True;
535 g_fullscreen = False;
536 if (!strcmp(optarg, "workarea"))
537 {
538 g_width = g_height = 0;
539 break;
540 }
541
542 g_width = strtol(optarg, &p, 10);
543 if (g_width <= 0)
544 {
545 error("invalid geometry\n");
546 return 1;
547 }
548
549 if (*p == 'x')
550 g_height = strtol(p + 1, &p, 10);
551
552 if (g_height <= 0)
553 {
554 error("invalid geometry\n");
555 return 1;
556 }
557
558 if (*p == '%')
559 {
560 g_width = -g_width;
561 p++;
562 }
563
564 if (*p == '+' || *p == '-')
565 {
566 g_pos |= (*p == '-') ? 2 : 1;
567 g_xpos = strtol(p, &p, 10);
568
569 }
570 if (*p == '+' || *p == '-')
571 {
572 g_pos |= (*p == '-') ? 4 : 1;
573 g_ypos = strtol(p, NULL, 10);
574 }
575
576 break;
577
578 case 'f':
579 g_fullscreen = True;
580 break;
581
582 case 'b':
583 g_bitmap_cache = False;
584 break;
585
586 case 'B':
587 g_ownbackstore = False;
588 break;
589
590 case 'e':
591 g_encryption = False;
592 break;
593 case 'E':
594 g_packet_encryption = False;
595 break;
596 case 'm':
597 g_sendmotion = False;
598 break;
599
600 case 'C':
601 g_owncolmap = True;
602 break;
603
604 case 'D':
605 g_hide_decorations = True;
606 break;
607
608 case 'K':
609 g_grab_keyboard = False;
610 break;
611
612 case 'S':
613 if (!strcmp(optarg, "standard"))
614 {
615 g_win_button_size = 18;
616 break;
617 }
618
619 g_win_button_size = strtol(optarg, &p, 10);
620
621 if (*p)
622 {
623 error("invalid button size\n");
624 return 1;
625 }
626
627 break;
628
629 case 'T':
630 STRNCPY(g_title, optarg, sizeof(g_title));
631 break;
632
633 case 'N':
634 g_numlock_sync = True;
635 break;
636
637 case 'X':
638 g_embed_wnd = strtol(optarg, NULL, 0);
639 break;
640
641 case 'a':
642 g_server_depth = strtol(optarg, NULL, 10);
643 if (g_server_depth != 8 &&
644 g_server_depth != 16 &&
645 g_server_depth != 15 && g_server_depth != 24
646 && g_server_depth != 32)
647 {
648 error("Invalid server colour depth.\n");
649 return 1;
650 }
651 break;
652
653 case 'z':
654 DEBUG(("rdp compression enabled\n"));
655 flags |= (RDP_LOGON_COMPRESSION | RDP_LOGON_COMPRESSION2);
656 break;
657
658 case 'x':
659 if (str_startswith(optarg, "m")) /* modem */
660 {
661 g_rdp5_performanceflags =
662 RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG |
663 RDP5_NO_MENUANIMATIONS | RDP5_NO_THEMING;
664 }
665 else if (str_startswith(optarg, "b")) /* broadband */
666 {
667 g_rdp5_performanceflags = RDP5_NO_WALLPAPER;
668 }
669 else if (str_startswith(optarg, "l")) /* lan */
670 {
671 g_rdp5_performanceflags = RDP5_DISABLE_NOTHING;
672 }
673 else
674 {
675 g_rdp5_performanceflags = strtol(optarg, NULL, 16);
676 }
677 break;
678
679 case 'P':
680 g_bitmap_cache_persist_enable = True;
681 break;
682
683 case 'r':
684
685 if (str_startswith(optarg, "sound"))
686 {
687 optarg += 5;
688
689 if (*optarg == ':')
690 {
691 optarg++;
692 while ((p = next_arg(optarg, ',')))
693 {
694 if (str_startswith(optarg, "remote"))
695 flags |= RDP_LOGON_LEAVE_AUDIO;
696
697 if (str_startswith(optarg, "local"))
698#ifdef WITH_RDPSND
699 {
700 rdpsnd_optarg =
701 next_arg(optarg, ':');
702 g_rdpsnd = True;
703 }
704
705#else
706 warning("Not compiled with sound support\n");
707#endif
708
709 if (str_startswith(optarg, "off"))
710#ifdef WITH_RDPSND
711 g_rdpsnd = False;
712#else
713 warning("Not compiled with sound support\n");
714#endif
715
716 optarg = p;
717 }
718 }
719 else
720 {
721#ifdef WITH_RDPSND
722 g_rdpsnd = True;
723#else
724 warning("Not compiled with sound support\n");
725#endif
726 }
727 }
728 else if (str_startswith(optarg, "usb"))
729 {
730#ifdef WITH_RDPUSB
731 g_rdpusb = True;
732#else
733 warning("Not compiled with USB support\n");
734#endif
735 }
736 else if (str_startswith(optarg, "disk"))
737 {
738 /* -r disk:h:=/mnt/floppy */
739 disk_enum_devices(&g_num_devices, optarg + 4);
740 }
741 else if (str_startswith(optarg, "comport"))
742 {
743 serial_enum_devices(&g_num_devices, optarg + 7);
744 }
745 else if (str_startswith(optarg, "lspci"))
746 {
747 g_lspci_enabled = True;
748 }
749 else if (str_startswith(optarg, "lptport"))
750 {
751 parallel_enum_devices(&g_num_devices, optarg + 7);
752 }
753 else if (str_startswith(optarg, "printer"))
754 {
755 printer_enum_devices(&g_num_devices, optarg + 7);
756 }
757 else if (str_startswith(optarg, "clientname"))
758 {
759 g_rdpdr_clientname = xmalloc(strlen(optarg + 11) + 1);
760 strcpy(g_rdpdr_clientname, optarg + 11);
761 }
762 else if (str_startswith(optarg, "clipboard"))
763 {
764 optarg += 9;
765
766 if (*optarg == ':')
767 {
768 optarg++;
769
770 if (str_startswith(optarg, "off"))
771 g_rdpclip = False;
772 else
773 cliprdr_set_mode(optarg);
774 }
775 else
776 g_rdpclip = True;
777 }
778 else if (strncmp("scard", optarg, 5) == 0)
779 {
780#ifdef WITH_SCARD
781 scard_enum_devices(&g_num_devices, optarg + 5);
782#else
783 warning("Not compiled with smartcard support\n");
784#endif
785 }
786 else
787 {
788 warning("Unknown -r argument\n\n\tPossible arguments are: comport, disk, lptport, printer, sound, clipboard, scard\n");
789 }
790 break;
791
792 case '0':
793 g_console_session = True;
794 break;
795
796 case '4':
797 g_use_rdp5 = False;
798 break;
799
800 case '5':
801 g_use_rdp5 = True;
802 break;
803
804 case 'h':
805 case '?':
806 default:
807 usage(argv[0]);
808 return 1;
809 }
810 }
811
812 if (argc - optind != 1)
813 {
814 usage(argv[0]);
815 return 1;
816 }
817
818 STRNCPY(server, argv[optind], sizeof(server));
819 parse_server_and_port(server);
820
821 if (g_seamless_rdp)
822 {
823 if (g_win_button_size)
824 {
825 error("You cannot use -S and -A at the same time\n");
826 return 1;
827 }
828 g_rdp5_performanceflags &= ~RDP5_NO_FULLWINDOWDRAG;
829 if (geometry_option)
830 {
831 error("You cannot use -g and -A at the same time\n");
832 return 1;
833 }
834 if (g_fullscreen)
835 {
836 error("You cannot use -f and -A at the same time\n");
837 return 1;
838 }
839 if (g_hide_decorations)
840 {
841 error("You cannot use -D and -A at the same time\n");
842 return 1;
843 }
844 if (g_embed_wnd)
845 {
846 error("You cannot use -X and -A at the same time\n");
847 return 1;
848 }
849 if (!g_use_rdp5)
850 {
851 error("You cannot use -4 and -A at the same time\n");
852 return 1;
853 }
854 g_width = -100;
855 g_grab_keyboard = False;
856 }
857
858 if (!username_option)
859 {
860 pw = getpwuid(getuid());
861 if ((pw == NULL) || (pw->pw_name == NULL))
862 {
863 error("could not determine username, use -u\n");
864 return 1;
865 }
866
867 STRNCPY(g_username, pw->pw_name, sizeof(g_username));
868 }
869
870#ifdef HAVE_ICONV
871 if (g_codepage[0] == 0)
872 {
873 if (setlocale(LC_CTYPE, ""))
874 {
875 STRNCPY(g_codepage, nl_langinfo(CODESET), sizeof(g_codepage));
876 }
877 else
878 {
879 STRNCPY(g_codepage, DEFAULT_CODEPAGE, sizeof(g_codepage));
880 }
881 }
882#endif
883
884 if (g_hostname[0] == 0)
885 {
886 if (gethostname(fullhostname, sizeof(fullhostname)) == -1)
887 {
888 error("could not determine local hostname, use -n\n");
889 return 1;
890 }
891
892 p = strchr(fullhostname, '.');
893 if (p != NULL)
894 *p = 0;
895
896 STRNCPY(g_hostname, fullhostname, sizeof(g_hostname));
897 }
898
899 if (g_keymapname[0] == 0)
900 {
901 if (locale && xkeymap_from_locale(locale))
902 {
903 fprintf(stderr, "Autoselected keyboard map %s\n", g_keymapname);
904 }
905 else
906 {
907 STRNCPY(g_keymapname, "en-us", sizeof(g_keymapname));
908 }
909 }
910 if (locale)
911 xfree(locale);
912
913
914 if (prompt_password && read_password(password, sizeof(password)))
915 flags |= RDP_LOGON_AUTO;
916
917 if (g_title[0] == 0)
918 {
919 strcpy(g_title, "rdesktop - ");
920 strncat(g_title, server, sizeof(g_title) - sizeof("rdesktop - "));
921 }
922
923#ifdef RDP2VNC
924 rdp2vnc_connect(server, flags, domain, password, shell, directory);
925 return 0;
926#else
927
928 if (!ui_init())
929 return 1;
930
931#ifdef WITH_RDPSND
932 if (g_rdpsnd)
933 {
934 if (!rdpsnd_init(rdpsnd_optarg))
935 {
936 warning("Initializing sound-support failed!\n");
937 }
938 }
939#endif
940
941#ifdef WITH_RDPUSB
942 if (g_rdpusb)
943 rdpusb_init();
944#endif
945
946 if (g_lspci_enabled)
947 lspci_init();
948
949 rdpdr_init();
950
951 while (run_count < 2 && continue_connect) /* add support for Session Directory; only reconnect once */
952 {
953 if (run_count == 0)
954 {
955 if (!rdp_connect(server, flags, domain, password, shell, directory))
956 return 1;
957 }
958 else if (!rdp_reconnect
959 (server, flags, domain, password, shell, directory, g_redirect_cookie))
960 return 1;
961
962 /* By setting encryption to False here, we have an encrypted login
963 packet but unencrypted transfer of other packets */
964 if (!g_packet_encryption)
965 g_encryption = False;
966
967
968 DEBUG(("Connection successful.\n"));
969 memset(password, 0, sizeof(password));
970
971 if (run_count == 0)
972 if (!ui_create_window())
973 continue_connect = False;
974
975 if (continue_connect)
976 rdp_main_loop(&deactivated, &ext_disc_reason);
977
978 DEBUG(("Disconnecting...\n"));
979 rdp_disconnect();
980
981 if ((g_redirect == True) && (run_count == 0)) /* Support for Session Directory */
982 {
983 /* reset state of major globals */
984 rdesktop_reset_state();
985
986 STRNCPY(domain, g_redirect_domain, sizeof(domain));
987 STRNCPY(g_username, g_redirect_username, sizeof(g_username));
988 STRNCPY(password, g_redirect_password, sizeof(password));
989 STRNCPY(server, g_redirect_server, sizeof(server));
990 flags |= RDP_LOGON_AUTO;
991
992 g_redirect = False;
993 }
994 else
995 {
996 continue_connect = False;
997 ui_destroy_window();
998 break;
999 }
1000
1001 run_count++;
1002 }
1003
1004 cache_save_state();
1005 ui_deinit();
1006
1007#ifdef WITH_RDPUSB
1008 if (g_rdpusb)
1009 rdpusb_close();
1010#endif
1011
1012 if (ext_disc_reason >= 2)
1013 print_disconnect_reason(ext_disc_reason);
1014
1015 if (deactivated)
1016 {
1017 /* clean disconnect */
1018 return 0;
1019 }
1020 else
1021 {
1022 if (ext_disc_reason == exDiscReasonAPIInitiatedDisconnect
1023 || ext_disc_reason == exDiscReasonAPIInitiatedLogoff)
1024 {
1025 /* not so clean disconnect, but nothing to worry about */
1026 return 0;
1027 }
1028 else
1029 {
1030 /* return error */
1031 return 2;
1032 }
1033 }
1034
1035#endif
1036
1037}
1038
1039#ifdef EGD_SOCKET
1040/* Read 32 random bytes from PRNGD or EGD socket (based on OpenSSL RAND_egd) */
1041static RD_BOOL
1042generate_random_egd(uint8 * buf)
1043{
1044 struct sockaddr_un addr;
1045 RD_BOOL ret = False;
1046 int fd;
1047
1048 fd = socket(AF_UNIX, SOCK_STREAM, 0);
1049 if (fd == -1)
1050 return False;
1051
1052 addr.sun_family = AF_UNIX;
1053 memcpy(addr.sun_path, EGD_SOCKET, sizeof(EGD_SOCKET));
1054 if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
1055 goto err;
1056
1057 /* PRNGD and EGD use a simple communications protocol */
1058 buf[0] = 1; /* Non-blocking (similar to /dev/urandom) */
1059 buf[1] = 32; /* Number of requested random bytes */
1060 if (write(fd, buf, 2) != 2)
1061 goto err;
1062
1063 if ((read(fd, buf, 1) != 1) || (buf[0] == 0)) /* Available? */
1064 goto err;
1065
1066 if (read(fd, buf, 32) != 32)
1067 goto err;
1068
1069 ret = True;
1070
1071 err:
1072 close(fd);
1073 return ret;
1074}
1075#endif
1076
1077/* Generate a 32-byte random for the secure transport code. */
1078void
1079generate_random(uint8 * random)
1080{
1081 struct stat st;
1082 struct tms tmsbuf;
1083 SSL_MD5 md5;
1084 uint32 *r;
1085 int fd, n;
1086
1087 /* If we have a kernel random device, try that first */
1088 if (((fd = open("/dev/urandom", O_RDONLY)) != -1)
1089 || ((fd = open("/dev/random", O_RDONLY)) != -1))
1090 {
1091 n = read(fd, random, 32);
1092 close(fd);
1093 if (n == 32)
1094 return;
1095 }
1096
1097#ifdef EGD_SOCKET
1098 /* As a second preference use an EGD */
1099 if (generate_random_egd(random))
1100 return;
1101#endif
1102
1103 /* Otherwise use whatever entropy we can gather - ideas welcome. */
1104 r = (uint32 *) random;
1105 r[0] = (getpid()) | (getppid() << 16);
1106 r[1] = (getuid()) | (getgid() << 16);
1107 r[2] = times(&tmsbuf); /* system uptime (clocks) */
1108 gettimeofday((struct timeval *) &r[3], NULL); /* sec and usec */
1109 stat("/tmp", &st);
1110 r[5] = st.st_atime;
1111 r[6] = st.st_mtime;
1112 r[7] = st.st_ctime;
1113
1114 /* Hash both halves with MD5 to obscure possible patterns */
1115 ssl_md5_init(&md5);
1116 ssl_md5_update(&md5, random, 16);
1117 ssl_md5_final(&md5, random);
1118 ssl_md5_update(&md5, random + 16, 16);
1119 ssl_md5_final(&md5, random + 16);
1120}
1121
1122/* malloc; exit if out of memory */
1123void *
1124xmalloc(int size)
1125{
1126 void *mem = malloc(size);
1127 if (mem == NULL)
1128 {
1129 error("xmalloc %d\n", size);
1130 exit(1);
1131 }
1132 return mem;
1133}
1134
1135/* Exit on NULL pointer. Use to verify result from XGetImage etc */
1136void
1137exit_if_null(void *ptr)
1138{
1139 if (ptr == NULL)
1140 {
1141 error("unexpected null pointer. Out of memory?\n");
1142 exit(1);
1143 }
1144}
1145
1146/* strdup */
1147char *
1148xstrdup(const char *s)
1149{
1150 char *mem = strdup(s);
1151 if (mem == NULL)
1152 {
1153 perror("strdup");
1154 exit(1);
1155 }
1156 return mem;
1157}
1158
1159/* realloc; exit if out of memory */
1160void *
1161xrealloc(void *oldmem, size_t size)
1162{
1163 void *mem;
1164
1165 if (size == 0)
1166 size = 1;
1167 mem = realloc(oldmem, size);
1168 if (mem == NULL)
1169 {
1170 error("xrealloc %ld\n", size);
1171 exit(1);
1172 }
1173 return mem;
1174}
1175
1176/* free */
1177void
1178xfree(void *mem)
1179{
1180 free(mem);
1181}
1182
1183/* report an error */
1184void
1185error(char *format, ...)
1186{
1187 va_list ap;
1188
1189 fprintf(stderr, "ERROR: ");
1190
1191 va_start(ap, format);
1192 vfprintf(stderr, format, ap);
1193 va_end(ap);
1194}
1195
1196/* report a warning */
1197void
1198warning(char *format, ...)
1199{
1200 va_list ap;
1201
1202 fprintf(stderr, "WARNING: ");
1203
1204 va_start(ap, format);
1205 vfprintf(stderr, format, ap);
1206 va_end(ap);
1207}
1208
1209/* report an unimplemented protocol feature */
1210void
1211unimpl(char *format, ...)
1212{
1213 va_list ap;
1214
1215 fprintf(stderr, "NOT IMPLEMENTED: ");
1216
1217 va_start(ap, format);
1218 vfprintf(stderr, format, ap);
1219 va_end(ap);
1220}
1221
1222/* produce a hex dump */
1223void
1224hexdump(unsigned char *p, unsigned int len)
1225{
1226 unsigned char *line = p;
1227 int i, thisline, offset = 0;
1228
1229 while (offset < len)
1230 {
1231 printf("%04x ", offset);
1232 thisline = len - offset;
1233 if (thisline > 16)
1234 thisline = 16;
1235
1236 for (i = 0; i < thisline; i++)
1237 printf("%02x ", line[i]);
1238
1239 for (; i < 16; i++)
1240 printf(" ");
1241
1242 for (i = 0; i < thisline; i++)
1243 printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.');
1244
1245 printf("\n");
1246 offset += thisline;
1247 line += thisline;
1248 }
1249}
1250
1251/*
1252 input: src is the string we look in for needle.
1253 Needle may be escaped by a backslash, in
1254 that case we ignore that particular needle.
1255 return value: returns next src pointer, for
1256 succesive executions, like in a while loop
1257 if retval is 0, then there are no more args.
1258 pitfalls:
1259 src is modified. 0x00 chars are inserted to
1260 terminate strings.
1261 return val, points on the next val chr after ins
1262 0x00
1263
1264 example usage:
1265 while( (pos = next_arg( optarg, ',')) ){
1266 printf("%s\n",optarg);
1267 optarg=pos;
1268 }
1269
1270*/
1271char *
1272next_arg(char *src, char needle)
1273{
1274 char *nextval;
1275 char *p;
1276 char *mvp = 0;
1277
1278 /* EOS */
1279 if (*src == (char) 0x00)
1280 return 0;
1281
1282 p = src;
1283 /* skip escaped needles */
1284 while ((nextval = strchr(p, needle)))
1285 {
1286 mvp = nextval - 1;
1287 /* found backslashed needle */
1288 if (*mvp == '\\' && (mvp > src))
1289 {
1290 /* move string one to the left */
1291 while (*(mvp + 1) != (char) 0x00)
1292 {
1293 *mvp = *(mvp + 1);
1294 mvp++;
1295 }
1296 *mvp = (char) 0x00;
1297 p = nextval;
1298 }
1299 else
1300 {
1301 p = nextval + 1;
1302 break;
1303 }
1304
1305 }
1306
1307 /* more args available */
1308 if (nextval)
1309 {
1310 *nextval = (char) 0x00;
1311 return ++nextval;
1312 }
1313
1314 /* no more args after this, jump to EOS */
1315 nextval = src + strlen(src);
1316 return nextval;
1317}
1318
1319
1320void
1321toupper_str(char *p)
1322{
1323 while (*p)
1324 {
1325 if ((*p >= 'a') && (*p <= 'z'))
1326 *p = toupper((int) *p);
1327 p++;
1328 }
1329}
1330
1331
1332RD_BOOL
1333str_startswith(const char *s, const char *prefix)
1334{
1335 return (strncmp(s, prefix, strlen(prefix)) == 0);
1336}
1337
1338
1339/* Split input into lines, and call linehandler for each
1340 line. Incomplete lines are saved in the rest variable, which should
1341 initially point to NULL. When linehandler returns False, stop and
1342 return False. Otherwise, return True. */
1343RD_BOOL
1344str_handle_lines(const char *input, char **rest, str_handle_lines_t linehandler, void *data)
1345{
1346 char *buf, *p;
1347 char *oldrest;
1348 size_t inputlen;
1349 size_t buflen;
1350 size_t restlen = 0;
1351 RD_BOOL ret = True;
1352
1353 /* Copy data to buffer */
1354 inputlen = strlen(input);
1355 if (*rest)
1356 restlen = strlen(*rest);
1357 buflen = restlen + inputlen + 1;
1358 buf = (char *) xmalloc(buflen);
1359 buf[0] = '\0';
1360 if (*rest)
1361 STRNCPY(buf, *rest, buflen);
1362 strncat(buf, input, inputlen);
1363 p = buf;
1364
1365 while (1)
1366 {
1367 char *newline = strchr(p, '\n');
1368 if (newline)
1369 {
1370 *newline = '\0';
1371 if (!linehandler(p, data))
1372 {
1373 p = newline + 1;
1374 ret = False;
1375 break;
1376 }
1377 p = newline + 1;
1378 }
1379 else
1380 {
1381 break;
1382
1383 }
1384 }
1385
1386 /* Save in rest */
1387 oldrest = *rest;
1388 restlen = buf + buflen - p;
1389 *rest = (char *) xmalloc(restlen);
1390 STRNCPY((*rest), p, restlen);
1391 xfree(oldrest);
1392
1393 xfree(buf);
1394 return ret;
1395}
1396
1397/* Execute the program specified by argv. For each line in
1398 stdout/stderr output, call linehandler. Returns false on failure. */
1399RD_BOOL
1400subprocess(char *const argv[], str_handle_lines_t linehandler, void *data)
1401{
1402 pid_t child;
1403 int fd[2];
1404 int n = 1;
1405 char output[256];
1406 char *rest = NULL;
1407
1408 if (pipe(fd) < 0)
1409 {
1410 perror("pipe");
1411 return False;
1412 }
1413
1414 if ((child = fork()) < 0)
1415 {
1416 perror("fork");
1417 return False;
1418 }
1419
1420 /* Child */
1421 if (child == 0)
1422 {
1423 /* Close read end */
1424 close(fd[0]);
1425
1426 /* Redirect stdout and stderr to pipe */
1427 dup2(fd[1], 1);
1428 dup2(fd[1], 2);
1429
1430 /* Execute */
1431 execvp(argv[0], argv);
1432 perror("Error executing child");
1433 _exit(128);
1434 }
1435
1436 /* Parent. Close write end. */
1437 close(fd[1]);
1438 while (n > 0)
1439 {
1440 n = read(fd[0], output, 255);
1441 output[n] = '\0';
1442 str_handle_lines(output, &rest, linehandler, data);
1443 }
1444 xfree(rest);
1445
1446 return True;
1447}
1448
1449
1450/* not all clibs got ltoa */
1451#define LTOA_BUFSIZE (sizeof(long) * 8 + 1)
1452
1453char *
1454l_to_a(long N, int base)
1455{
1456 static char ret[LTOA_BUFSIZE];
1457
1458 char *head = ret, buf[LTOA_BUFSIZE], *tail = buf + sizeof(buf);
1459
1460 register int divrem;
1461
1462 if (base < 36 || 2 > base)
1463 base = 10;
1464
1465 if (N < 0)
1466 {
1467 *head++ = '-';
1468 N = -N;
1469 }
1470
1471 tail = buf + sizeof(buf);
1472 *--tail = 0;
1473
1474 do
1475 {
1476 divrem = N % base;
1477 *--tail = (divrem <= 9) ? divrem + '0' : divrem + 'a' - 10;
1478 N /= base;
1479 }
1480 while (N);
1481
1482 strcpy(head, tail);
1483 return ret;
1484}
1485
1486
1487int
1488load_licence(unsigned char **data)
1489{
1490 char *home, *path;
1491 struct stat st;
1492 int fd, length;
1493
1494 home = getenv("HOME");
1495 if (home == NULL)
1496 return -1;
1497
1498 path = (char *) xmalloc(strlen(home) + strlen(g_hostname) + sizeof("/.rdesktop/licence."));
1499 sprintf(path, "%s/.rdesktop/licence.%s", home, g_hostname);
1500
1501 fd = open(path, O_RDONLY);
1502 if (fd == -1)
1503 return -1;
1504
1505 if (fstat(fd, &st))
1506 return -1;
1507
1508 *data = (uint8 *) xmalloc(st.st_size);
1509 length = read(fd, *data, st.st_size);
1510 close(fd);
1511 xfree(path);
1512 return length;
1513}
1514
1515void
1516save_licence(unsigned char *data, int length)
1517{
1518 char *home, *path, *tmppath;
1519 int fd;
1520
1521 home = getenv("HOME");
1522 if (home == NULL)
1523 return;
1524
1525 path = (char *) xmalloc(strlen(home) + strlen(g_hostname) + sizeof("/.rdesktop/licence."));
1526
1527 sprintf(path, "%s/.rdesktop", home);
1528 if ((mkdir(path, 0700) == -1) && errno != EEXIST)
1529 {
1530 perror(path);
1531 return;
1532 }
1533
1534 /* write licence to licence.hostname.new, then atomically rename to licence.hostname */
1535
1536 sprintf(path, "%s/.rdesktop/licence.%s", home, g_hostname);
1537 tmppath = (char *) xmalloc(strlen(path) + sizeof(".new"));
1538 strcpy(tmppath, path);
1539 strcat(tmppath, ".new");
1540
1541 fd = open(tmppath, O_WRONLY | O_CREAT | O_TRUNC, 0600);
1542 if (fd == -1)
1543 {
1544 perror(tmppath);
1545 return;
1546 }
1547
1548 if (write(fd, data, length) != length)
1549 {
1550 perror(tmppath);
1551 unlink(tmppath);
1552 }
1553 else if (rename(tmppath, path) == -1)
1554 {
1555 perror(path);
1556 unlink(tmppath);
1557 }
1558
1559 close(fd);
1560 xfree(tmppath);
1561 xfree(path);
1562}
1563
1564/* Create the bitmap cache directory */
1565RD_BOOL
1566rd_pstcache_mkdir(void)
1567{
1568 char *home;
1569 char bmpcache_dir[256];
1570
1571 home = getenv("HOME");
1572
1573 if (home == NULL)
1574 return False;
1575
1576 sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop");
1577
1578 if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST)
1579 {
1580 perror(bmpcache_dir);
1581 return False;
1582 }
1583
1584 sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop/cache");
1585
1586 if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST)
1587 {
1588 perror(bmpcache_dir);
1589 return False;
1590 }
1591
1592 return True;
1593}
1594
1595/* open a file in the .rdesktop directory */
1596int
1597rd_open_file(char *filename)
1598{
1599 char *home;
1600 char fn[256];
1601 int fd;
1602
1603 home = getenv("HOME");
1604 if (home == NULL)
1605 return -1;
1606 sprintf(fn, "%s/.rdesktop/%s", home, filename);
1607 fd = open(fn, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
1608 if (fd == -1)
1609 perror(fn);
1610 return fd;
1611}
1612
1613/* close file */
1614void
1615rd_close_file(int fd)
1616{
1617 close(fd);
1618}
1619
1620/* read from file*/
1621int
1622rd_read_file(int fd, void *ptr, int len)
1623{
1624 return read(fd, ptr, len);
1625}
1626
1627/* write to file */
1628int
1629rd_write_file(int fd, void *ptr, int len)
1630{
1631 return write(fd, ptr, len);
1632}
1633
1634/* move file pointer */
1635int
1636rd_lseek_file(int fd, int offset)
1637{
1638 return lseek(fd, offset, SEEK_SET);
1639}
1640
1641/* do a write lock on a file */
1642RD_BOOL
1643rd_lock_file(int fd, int start, int len)
1644{
1645 struct flock lock;
1646
1647 lock.l_type = F_WRLCK;
1648 lock.l_whence = SEEK_SET;
1649 lock.l_start = start;
1650 lock.l_len = len;
1651 if (fcntl(fd, F_SETLK, &lock) == -1)
1652 return False;
1653 return True;
1654}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette