VirtualBox

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

Last change on this file since 8057 was 7826, checked in by vboxsync, 17 years ago

Export modified rdesktop version including USB support to OSE. It's GPL anyway.

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