/[rdesktop]/sourceforge.net/trunk/rdesktop/rdesktop.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /sourceforge.net/trunk/rdesktop/rdesktop.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1271 - (show annotations)
Mon Sep 18 21:42:50 2006 UTC (17 years, 8 months ago) by stargo
File MIME type: text/plain
File size: 33935 byte(s)
handle missing audio-drivers better

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

  ViewVC Help
Powered by ViewVC 1.1.26