/[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 1255 - (show annotations)
Sun Sep 17 11:04:50 2006 UTC (17 years, 9 months ago) by stargo
File MIME type: text/plain
File size: 33873 byte(s)
allow multiple sound-drivers to be compiled in simultaneously and
make the runtime selectable

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 g_rdpsnd = True;
694 if (!rdpsnd_select_driver
695 (driver, options))
696 {
697 warning("Driver not available\n");
698 }
699 }
700
701 #else
702 warning("Not compiled with sound support\n");
703 #endif
704
705 if (str_startswith(optarg, "off"))
706 #ifdef WITH_RDPSND
707 g_rdpsnd = False;
708 #else
709 warning("Not compiled with sound support\n");
710 #endif
711
712 optarg = p;
713 }
714 }
715 else
716 {
717 #ifdef WITH_RDPSND
718 g_rdpsnd = True;
719 if (!rdpsnd_select_driver(NULL, NULL))
720 {
721 warning("No sound-driver available\n");
722 }
723 #else
724 warning("Not compiled with sound support\n");
725 #endif
726 }
727 }
728 else if (str_startswith(optarg, "disk"))
729 {
730 /* -r disk:h:=/mnt/floppy */
731 disk_enum_devices(&g_num_devices, optarg + 4);
732 }
733 else if (str_startswith(optarg, "comport"))
734 {
735 serial_enum_devices(&g_num_devices, optarg + 7);
736 }
737 else if (str_startswith(optarg, "lspci"))
738 {
739 lspci_enabled = True;
740 }
741 else if (str_startswith(optarg, "lptport"))
742 {
743 parallel_enum_devices(&g_num_devices, optarg + 7);
744 }
745 else if (str_startswith(optarg, "printer"))
746 {
747 printer_enum_devices(&g_num_devices, optarg + 7);
748 }
749 else if (str_startswith(optarg, "clientname"))
750 {
751 g_rdpdr_clientname = xmalloc(strlen(optarg + 11) + 1);
752 strcpy(g_rdpdr_clientname, optarg + 11);
753 }
754 else if (str_startswith(optarg, "clipboard"))
755 {
756 optarg += 9;
757
758 if (*optarg == ':')
759 {
760 optarg++;
761
762 if (str_startswith(optarg, "off"))
763 g_rdpclip = False;
764 else
765 cliprdr_set_mode(optarg);
766 }
767 else
768 g_rdpclip = True;
769 }
770 else
771 {
772 warning("Unknown -r argument\n\n\tPossible arguments are: comport, disk, lptport, printer, sound, clipboard\n");
773 }
774 break;
775
776 case '0':
777 g_console_session = True;
778 break;
779
780 case '4':
781 g_use_rdp5 = False;
782 break;
783
784 case '5':
785 g_use_rdp5 = True;
786 break;
787
788 case 'h':
789 case '?':
790 default:
791 usage(argv[0]);
792 return 1;
793 }
794 }
795
796 if (argc - optind != 1)
797 {
798 usage(argv[0]);
799 return 1;
800 }
801
802 STRNCPY(server, argv[optind], sizeof(server));
803 parse_server_and_port(server);
804
805 if (g_seamless_rdp)
806 {
807 if (g_win_button_size)
808 {
809 error("You cannot use -S and -A at the same time\n");
810 return 1;
811 }
812 g_rdp5_performanceflags &= ~RDP5_NO_FULLWINDOWDRAG;
813 if (geometry_option)
814 {
815 error("You cannot use -g and -A at the same time\n");
816 return 1;
817 }
818 if (g_fullscreen)
819 {
820 error("You cannot use -f and -A at the same time\n");
821 return 1;
822 }
823 if (g_hide_decorations)
824 {
825 error("You cannot use -D and -A at the same time\n");
826 return 1;
827 }
828 if (g_embed_wnd)
829 {
830 error("You cannot use -X and -A at the same time\n");
831 return 1;
832 }
833 if (!g_use_rdp5)
834 {
835 error("You cannot use -4 and -A at the same time\n");
836 return 1;
837 }
838 g_width = -100;
839 g_grab_keyboard = False;
840 }
841
842 if (!username_option)
843 {
844 pw = getpwuid(getuid());
845 if ((pw == NULL) || (pw->pw_name == NULL))
846 {
847 error("could not determine username, use -u\n");
848 return 1;
849 }
850
851 STRNCPY(g_username, pw->pw_name, sizeof(g_username));
852 }
853
854 #ifdef HAVE_ICONV
855 if (g_codepage[0] == 0)
856 {
857 if (setlocale(LC_CTYPE, ""))
858 {
859 STRNCPY(g_codepage, nl_langinfo(CODESET), sizeof(g_codepage));
860 }
861 else
862 {
863 STRNCPY(g_codepage, DEFAULT_CODEPAGE, sizeof(g_codepage));
864 }
865 }
866 #endif
867
868 if (g_hostname[0] == 0)
869 {
870 if (gethostname(fullhostname, sizeof(fullhostname)) == -1)
871 {
872 error("could not determine local hostname, use -n\n");
873 return 1;
874 }
875
876 p = strchr(fullhostname, '.');
877 if (p != NULL)
878 *p = 0;
879
880 STRNCPY(g_hostname, fullhostname, sizeof(g_hostname));
881 }
882
883 if (g_keymapname[0] == 0)
884 {
885 if (locale && xkeymap_from_locale(locale))
886 {
887 fprintf(stderr, "Autoselected keyboard map %s\n", g_keymapname);
888 }
889 else
890 {
891 STRNCPY(g_keymapname, "en-us", sizeof(g_keymapname));
892 }
893 }
894 if (locale)
895 xfree(locale);
896
897
898 if (prompt_password && read_password(password, sizeof(password)))
899 flags |= RDP_LOGON_AUTO;
900
901 if (g_title[0] == 0)
902 {
903 strcpy(g_title, "rdesktop - ");
904 strncat(g_title, server, sizeof(g_title) - sizeof("rdesktop - "));
905 }
906
907 #ifdef RDP2VNC
908 rdp2vnc_connect(server, flags, domain, password, shell, directory);
909 return 0;
910 #else
911
912 if (!ui_init())
913 return 1;
914
915 #ifdef WITH_RDPSND
916 if (g_rdpsnd)
917 rdpsnd_init();
918 #endif
919
920 if (lspci_enabled)
921 lspci_init();
922
923 rdpdr_init();
924
925 while (run_count < 2 && continue_connect) /* add support for Session Directory; only reconnect once */
926 {
927 if (run_count == 0)
928 {
929 if (!rdp_connect(server, flags, domain, password, shell, directory))
930 return 1;
931 }
932 else if (!rdp_reconnect
933 (server, flags, domain, password, shell, directory, g_redirect_cookie))
934 return 1;
935
936 /* By setting encryption to False here, we have an encrypted login
937 packet but unencrypted transfer of other packets */
938 if (!packet_encryption)
939 g_encryption = False;
940
941
942 DEBUG(("Connection successful.\n"));
943 memset(password, 0, sizeof(password));
944
945 if (run_count == 0)
946 if (!ui_create_window())
947 continue_connect = False;
948
949 if (continue_connect)
950 rdp_main_loop(&deactivated, &ext_disc_reason);
951
952 DEBUG(("Disconnecting...\n"));
953 rdp_disconnect();
954
955 if ((g_redirect == True) && (run_count == 0)) /* Support for Session Directory */
956 {
957 /* reset state of major globals */
958 rdesktop_reset_state();
959
960 STRNCPY(domain, g_redirect_domain, sizeof(domain));
961 STRNCPY(g_username, g_redirect_username, sizeof(g_username));
962 STRNCPY(password, g_redirect_password, sizeof(password));
963 STRNCPY(server, g_redirect_server, sizeof(server));
964 flags |= RDP_LOGON_AUTO;
965
966 g_redirect = False;
967 }
968 else
969 {
970 continue_connect = False;
971 ui_destroy_window();
972 break;
973 }
974
975 run_count++;
976 }
977
978 cache_save_state();
979 ui_deinit();
980
981 if (ext_disc_reason >= 2)
982 print_disconnect_reason(ext_disc_reason);
983
984 if (deactivated)
985 {
986 /* clean disconnect */
987 return 0;
988 }
989 else
990 {
991 if (ext_disc_reason == exDiscReasonAPIInitiatedDisconnect
992 || ext_disc_reason == exDiscReasonAPIInitiatedLogoff)
993 {
994 /* not so clean disconnect, but nothing to worry about */
995 return 0;
996 }
997 else
998 {
999 /* return error */
1000 return 2;
1001 }
1002 }
1003
1004 #endif
1005
1006 }
1007
1008 #ifdef EGD_SOCKET
1009 /* Read 32 random bytes from PRNGD or EGD socket (based on OpenSSL RAND_egd) */
1010 static BOOL
1011 generate_random_egd(uint8 * buf)
1012 {
1013 struct sockaddr_un addr;
1014 BOOL ret = False;
1015 int fd;
1016
1017 fd = socket(AF_UNIX, SOCK_STREAM, 0);
1018 if (fd == -1)
1019 return False;
1020
1021 addr.sun_family = AF_UNIX;
1022 memcpy(addr.sun_path, EGD_SOCKET, sizeof(EGD_SOCKET));
1023 if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
1024 goto err;
1025
1026 /* PRNGD and EGD use a simple communications protocol */
1027 buf[0] = 1; /* Non-blocking (similar to /dev/urandom) */
1028 buf[1] = 32; /* Number of requested random bytes */
1029 if (write(fd, buf, 2) != 2)
1030 goto err;
1031
1032 if ((read(fd, buf, 1) != 1) || (buf[0] == 0)) /* Available? */
1033 goto err;
1034
1035 if (read(fd, buf, 32) != 32)
1036 goto err;
1037
1038 ret = True;
1039
1040 err:
1041 close(fd);
1042 return ret;
1043 }
1044 #endif
1045
1046 /* Generate a 32-byte random for the secure transport code. */
1047 void
1048 generate_random(uint8 * random)
1049 {
1050 struct stat st;
1051 struct tms tmsbuf;
1052 MD5_CTX md5;
1053 uint32 *r;
1054 int fd, n;
1055
1056 /* If we have a kernel random device, try that first */
1057 if (((fd = open("/dev/urandom", O_RDONLY)) != -1)
1058 || ((fd = open("/dev/random", O_RDONLY)) != -1))
1059 {
1060 n = read(fd, random, 32);
1061 close(fd);
1062 if (n == 32)
1063 return;
1064 }
1065
1066 #ifdef EGD_SOCKET
1067 /* As a second preference use an EGD */
1068 if (generate_random_egd(random))
1069 return;
1070 #endif
1071
1072 /* Otherwise use whatever entropy we can gather - ideas welcome. */
1073 r = (uint32 *) random;
1074 r[0] = (getpid()) | (getppid() << 16);
1075 r[1] = (getuid()) | (getgid() << 16);
1076 r[2] = times(&tmsbuf); /* system uptime (clocks) */
1077 gettimeofday((struct timeval *) &r[3], NULL); /* sec and usec */
1078 stat("/tmp", &st);
1079 r[5] = st.st_atime;
1080 r[6] = st.st_mtime;
1081 r[7] = st.st_ctime;
1082
1083 /* Hash both halves with MD5 to obscure possible patterns */
1084 MD5_Init(&md5);
1085 MD5_Update(&md5, random, 16);
1086 MD5_Final(random, &md5);
1087 MD5_Update(&md5, random + 16, 16);
1088 MD5_Final(random + 16, &md5);
1089 }
1090
1091 /* malloc; exit if out of memory */
1092 void *
1093 xmalloc(int size)
1094 {
1095 void *mem = malloc(size);
1096 if (mem == NULL)
1097 {
1098 error("xmalloc %d\n", size);
1099 exit(1);
1100 }
1101 return mem;
1102 }
1103
1104 /* strdup */
1105 char *
1106 xstrdup(const char *s)
1107 {
1108 char *mem = strdup(s);
1109 if (mem == NULL)
1110 {
1111 perror("strdup");
1112 exit(1);
1113 }
1114 return mem;
1115 }
1116
1117 /* realloc; exit if out of memory */
1118 void *
1119 xrealloc(void *oldmem, int size)
1120 {
1121 void *mem;
1122
1123 if (size < 1)
1124 size = 1;
1125 mem = realloc(oldmem, size);
1126 if (mem == NULL)
1127 {
1128 error("xrealloc %d\n", size);
1129 exit(1);
1130 }
1131 return mem;
1132 }
1133
1134 /* free */
1135 void
1136 xfree(void *mem)
1137 {
1138 free(mem);
1139 }
1140
1141 /* report an error */
1142 void
1143 error(char *format, ...)
1144 {
1145 va_list ap;
1146
1147 fprintf(stderr, "ERROR: ");
1148
1149 va_start(ap, format);
1150 vfprintf(stderr, format, ap);
1151 va_end(ap);
1152 }
1153
1154 /* report a warning */
1155 void
1156 warning(char *format, ...)
1157 {
1158 va_list ap;
1159
1160 fprintf(stderr, "WARNING: ");
1161
1162 va_start(ap, format);
1163 vfprintf(stderr, format, ap);
1164 va_end(ap);
1165 }
1166
1167 /* report an unimplemented protocol feature */
1168 void
1169 unimpl(char *format, ...)
1170 {
1171 va_list ap;
1172
1173 fprintf(stderr, "NOT IMPLEMENTED: ");
1174
1175 va_start(ap, format);
1176 vfprintf(stderr, format, ap);
1177 va_end(ap);
1178 }
1179
1180 /* produce a hex dump */
1181 void
1182 hexdump(unsigned char *p, unsigned int len)
1183 {
1184 unsigned char *line = p;
1185 int i, thisline, offset = 0;
1186
1187 while (offset < len)
1188 {
1189 printf("%04x ", offset);
1190 thisline = len - offset;
1191 if (thisline > 16)
1192 thisline = 16;
1193
1194 for (i = 0; i < thisline; i++)
1195 printf("%02x ", line[i]);
1196
1197 for (; i < 16; i++)
1198 printf(" ");
1199
1200 for (i = 0; i < thisline; i++)
1201 printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.');
1202
1203 printf("\n");
1204 offset += thisline;
1205 line += thisline;
1206 }
1207 }
1208
1209 /*
1210 input: src is the string we look in for needle.
1211 Needle may be escaped by a backslash, in
1212 that case we ignore that particular needle.
1213 return value: returns next src pointer, for
1214 succesive executions, like in a while loop
1215 if retval is 0, then there are no more args.
1216 pitfalls:
1217 src is modified. 0x00 chars are inserted to
1218 terminate strings.
1219 return val, points on the next val chr after ins
1220 0x00
1221
1222 example usage:
1223 while( (pos = next_arg( optarg, ',')) ){
1224 printf("%s\n",optarg);
1225 optarg=pos;
1226 }
1227
1228 */
1229 char *
1230 next_arg(char *src, char needle)
1231 {
1232 char *nextval;
1233 char *p;
1234 char *mvp = 0;
1235
1236 /* EOS */
1237 if (*src == (char) 0x00)
1238 return 0;
1239
1240 p = src;
1241 /* skip escaped needles */
1242 while ((nextval = strchr(p, needle)))
1243 {
1244 mvp = nextval - 1;
1245 /* found backslashed needle */
1246 if (*mvp == '\\' && (mvp > src))
1247 {
1248 /* move string one to the left */
1249 while (*(mvp + 1) != (char) 0x00)
1250 {
1251 *mvp = *(mvp + 1);
1252 mvp++;
1253 }
1254 *mvp = (char) 0x00;
1255 p = nextval;
1256 }
1257 else
1258 {
1259 p = nextval + 1;
1260 break;
1261 }
1262
1263 }
1264
1265 /* more args available */
1266 if (nextval)
1267 {
1268 *nextval = (char) 0x00;
1269 return ++nextval;
1270 }
1271
1272 /* no more args after this, jump to EOS */
1273 nextval = src + strlen(src);
1274 return nextval;
1275 }
1276
1277
1278 void
1279 toupper_str(char *p)
1280 {
1281 while (*p)
1282 {
1283 if ((*p >= 'a') && (*p <= 'z'))
1284 *p = toupper((int) *p);
1285 p++;
1286 }
1287 }
1288
1289
1290 BOOL
1291 str_startswith(const char *s, const char *prefix)
1292 {
1293 return (strncmp(s, prefix, strlen(prefix)) == 0);
1294 }
1295
1296
1297 /* Split input into lines, and call linehandler for each
1298 line. Incomplete lines are saved in the rest variable, which should
1299 initially point to NULL. When linehandler returns False, stop and
1300 return False. Otherwise, return True. */
1301 BOOL
1302 str_handle_lines(const char *input, char **rest, str_handle_lines_t linehandler, void *data)
1303 {
1304 char *buf, *p;
1305 char *oldrest;
1306 size_t inputlen;
1307 size_t buflen;
1308 size_t restlen = 0;
1309 BOOL ret = True;
1310
1311 /* Copy data to buffer */
1312 inputlen = strlen(input);
1313 if (*rest)
1314 restlen = strlen(*rest);
1315 buflen = restlen + inputlen + 1;
1316 buf = (char *) xmalloc(buflen);
1317 buf[0] = '\0';
1318 if (*rest)
1319 STRNCPY(buf, *rest, buflen);
1320 strncat(buf, input, inputlen);
1321 p = buf;
1322
1323 while (1)
1324 {
1325 char *newline = strchr(p, '\n');
1326 if (newline)
1327 {
1328 *newline = '\0';
1329 if (!linehandler(p, data))
1330 {
1331 p = newline + 1;
1332 ret = False;
1333 break;
1334 }
1335 p = newline + 1;
1336 }
1337 else
1338 {
1339 break;
1340
1341 }
1342 }
1343
1344 /* Save in rest */
1345 oldrest = *rest;
1346 restlen = buf + buflen - p;
1347 *rest = (char *) xmalloc(restlen);
1348 STRNCPY((*rest), p, restlen);
1349 xfree(oldrest);
1350
1351 xfree(buf);
1352 return ret;
1353 }
1354
1355 /* Execute the program specified by argv. For each line in
1356 stdout/stderr output, call linehandler. Returns false on failure. */
1357 BOOL
1358 subprocess(char *const argv[], str_handle_lines_t linehandler, void *data)
1359 {
1360 pid_t child;
1361 int fd[2];
1362 int n = 1;
1363 char output[256];
1364 char *rest = NULL;
1365
1366 if (pipe(fd) < 0)
1367 {
1368 perror("pipe");
1369 return False;
1370 }
1371
1372 if ((child = fork()) < 0)
1373 {
1374 perror("fork");
1375 return False;
1376 }
1377
1378 /* Child */
1379 if (child == 0)
1380 {
1381 /* Close read end */
1382 close(fd[0]);
1383
1384 /* Redirect stdout and stderr to pipe */
1385 dup2(fd[1], 1);
1386 dup2(fd[1], 2);
1387
1388 /* Execute */
1389 execvp(argv[0], argv);
1390 perror("Error executing child");
1391 _exit(128);
1392 }
1393
1394 /* Parent. Close write end. */
1395 close(fd[1]);
1396 while (n > 0)
1397 {
1398 n = read(fd[0], output, 255);
1399 output[n] = '\0';
1400 str_handle_lines(output, &rest, linehandler, data);
1401 }
1402 xfree(rest);
1403
1404 return True;
1405 }
1406
1407
1408 /* not all clibs got ltoa */
1409 #define LTOA_BUFSIZE (sizeof(long) * 8 + 1)
1410
1411 char *
1412 l_to_a(long N, int base)
1413 {
1414 static char ret[LTOA_BUFSIZE];
1415
1416 char *head = ret, buf[LTOA_BUFSIZE], *tail = buf + sizeof(buf);
1417
1418 register int divrem;
1419
1420 if (base < 36 || 2 > base)
1421 base = 10;
1422
1423 if (N < 0)
1424 {
1425 *head++ = '-';
1426 N = -N;
1427 }
1428
1429 tail = buf + sizeof(buf);
1430 *--tail = 0;
1431
1432 do
1433 {
1434 divrem = N % base;
1435 *--tail = (divrem <= 9) ? divrem + '0' : divrem + 'a' - 10;
1436 N /= base;
1437 }
1438 while (N);
1439
1440 strcpy(head, tail);
1441 return ret;
1442 }
1443
1444
1445 int
1446 load_licence(unsigned char **data)
1447 {
1448 char *home, *path;
1449 struct stat st;
1450 int fd, length;
1451
1452 home = getenv("HOME");
1453 if (home == NULL)
1454 return -1;
1455
1456 path = (char *) xmalloc(strlen(home) + strlen(g_hostname) + sizeof("/.rdesktop/licence."));
1457 sprintf(path, "%s/.rdesktop/licence.%s", home, g_hostname);
1458
1459 fd = open(path, O_RDONLY);
1460 if (fd == -1)
1461 return -1;
1462
1463 if (fstat(fd, &st))
1464 return -1;
1465
1466 *data = (uint8 *) xmalloc(st.st_size);
1467 length = read(fd, *data, st.st_size);
1468 close(fd);
1469 xfree(path);
1470 return length;
1471 }
1472
1473 void
1474 save_licence(unsigned char *data, int length)
1475 {
1476 char *home, *path, *tmppath;
1477 int fd;
1478
1479 home = getenv("HOME");
1480 if (home == NULL)
1481 return;
1482
1483 path = (char *) xmalloc(strlen(home) + strlen(g_hostname) + sizeof("/.rdesktop/licence."));
1484
1485 sprintf(path, "%s/.rdesktop", home);
1486 if ((mkdir(path, 0700) == -1) && errno != EEXIST)
1487 {
1488 perror(path);
1489 return;
1490 }
1491
1492 /* write licence to licence.hostname.new, then atomically rename to licence.hostname */
1493
1494 sprintf(path, "%s/.rdesktop/licence.%s", home, g_hostname);
1495 tmppath = (char *) xmalloc(strlen(path) + sizeof(".new"));
1496 strcpy(tmppath, path);
1497 strcat(tmppath, ".new");
1498
1499 fd = open(tmppath, O_WRONLY | O_CREAT | O_TRUNC, 0600);
1500 if (fd == -1)
1501 {
1502 perror(tmppath);
1503 return;
1504 }
1505
1506 if (write(fd, data, length) != length)
1507 {
1508 perror(tmppath);
1509 unlink(tmppath);
1510 }
1511 else if (rename(tmppath, path) == -1)
1512 {
1513 perror(path);
1514 unlink(tmppath);
1515 }
1516
1517 close(fd);
1518 xfree(tmppath);
1519 xfree(path);
1520 }
1521
1522 /* Create the bitmap cache directory */
1523 BOOL
1524 rd_pstcache_mkdir(void)
1525 {
1526 char *home;
1527 char bmpcache_dir[256];
1528
1529 home = getenv("HOME");
1530
1531 if (home == NULL)
1532 return False;
1533
1534 sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop");
1535
1536 if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST)
1537 {
1538 perror(bmpcache_dir);
1539 return False;
1540 }
1541
1542 sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop/cache");
1543
1544 if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST)
1545 {
1546 perror(bmpcache_dir);
1547 return False;
1548 }
1549
1550 return True;
1551 }
1552
1553 /* open a file in the .rdesktop directory */
1554 int
1555 rd_open_file(char *filename)
1556 {
1557 char *home;
1558 char fn[256];
1559 int fd;
1560
1561 home = getenv("HOME");
1562 if (home == NULL)
1563 return -1;
1564 sprintf(fn, "%s/.rdesktop/%s", home, filename);
1565 fd = open(fn, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
1566 if (fd == -1)
1567 perror(fn);
1568 return fd;
1569 }
1570
1571 /* close file */
1572 void
1573 rd_close_file(int fd)
1574 {
1575 close(fd);
1576 }
1577
1578 /* read from file*/
1579 int
1580 rd_read_file(int fd, void *ptr, int len)
1581 {
1582 return read(fd, ptr, len);
1583 }
1584
1585 /* write to file */
1586 int
1587 rd_write_file(int fd, void *ptr, int len)
1588 {
1589 return write(fd, ptr, len);
1590 }
1591
1592 /* move file pointer */
1593 int
1594 rd_lseek_file(int fd, int offset)
1595 {
1596 return lseek(fd, offset, SEEK_SET);
1597 }
1598
1599 /* do a write lock on a file */
1600 BOOL
1601 rd_lock_file(int fd, int start, int len)
1602 {
1603 struct flock lock;
1604
1605 lock.l_type = F_WRLCK;
1606 lock.l_whence = SEEK_SET;
1607 lock.l_start = start;
1608 lock.l_len = len;
1609 if (fcntl(fd, F_SETLK, &lock) == -1)
1610 return False;
1611 return True;
1612 }

  ViewVC Help
Powered by ViewVC 1.1.26