/[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 1272 - (show annotations)
Thu Sep 21 19:00:11 2006 UTC (17 years, 8 months ago) by stargo
File MIME type: text/plain
File size: 33405 byte(s)
move sound-driver selection code in rdpsnd_init

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 char *rdpsnd_optarg = NULL;
412
413 #ifdef HAVE_LOCALE_H
414 /* Set locale according to environment */
415 locale = setlocale(LC_ALL, "");
416 if (locale)
417 {
418 locale = xstrdup(locale);
419 }
420
421 #endif
422 flags = RDP_LOGON_NORMAL;
423 prompt_password = False;
424 domain[0] = password[0] = shell[0] = directory[0] = 0;
425 g_embed_wnd = 0;
426
427 g_num_devices = 0;
428
429 #ifdef RDP2VNC
430 #define VNCOPT "V:Q:"
431 #else
432 #define VNCOPT
433 #endif
434
435 while ((c = getopt(argc, argv,
436 VNCOPT "Au:L:d:s:c:p:n:k:g:fbBeEmzCDKS:T:NX:a:x:Pr:045h?")) != -1)
437 {
438 switch (c)
439 {
440 #ifdef RDP2VNC
441 case 'V':
442 rfb_port = strtol(optarg, NULL, 10);
443 if (rfb_port < 100)
444 rfb_port += 5900;
445 break;
446
447 case 'Q':
448 defer_time = strtol(optarg, NULL, 10);
449 if (defer_time < 0)
450 defer_time = 0;
451 break;
452 #endif
453
454 case 'A':
455 g_seamless_rdp = True;
456 break;
457
458 case 'u':
459 STRNCPY(g_username, optarg, sizeof(g_username));
460 username_option = 1;
461 break;
462
463 case 'L':
464 #ifdef HAVE_ICONV
465 STRNCPY(g_codepage, optarg, sizeof(g_codepage));
466 #else
467 error("iconv support not available\n");
468 #endif
469 break;
470
471 case 'd':
472 STRNCPY(domain, optarg, sizeof(domain));
473 break;
474
475 case 's':
476 STRNCPY(shell, optarg, sizeof(shell));
477 break;
478
479 case 'c':
480 STRNCPY(directory, optarg, sizeof(directory));
481 break;
482
483 case 'p':
484 if ((optarg[0] == '-') && (optarg[1] == 0))
485 {
486 prompt_password = True;
487 break;
488 }
489
490 STRNCPY(password, optarg, sizeof(password));
491 flags |= RDP_LOGON_AUTO;
492
493 /* try to overwrite argument so it won't appear in ps */
494 p = optarg;
495 while (*p)
496 *(p++) = 'X';
497 break;
498
499 case 'n':
500 STRNCPY(g_hostname, optarg, sizeof(g_hostname));
501 break;
502
503 case 'k':
504 STRNCPY(g_keymapname, optarg, sizeof(g_keymapname));
505 break;
506
507 case 'g':
508 geometry_option = True;
509 g_fullscreen = False;
510 if (!strcmp(optarg, "workarea"))
511 {
512 g_width = g_height = 0;
513 break;
514 }
515
516 g_width = strtol(optarg, &p, 10);
517 if (g_width <= 0)
518 {
519 error("invalid geometry\n");
520 return 1;
521 }
522
523 if (*p == 'x')
524 g_height = strtol(p + 1, &p, 10);
525
526 if (g_height <= 0)
527 {
528 error("invalid geometry\n");
529 return 1;
530 }
531
532 if (*p == '%')
533 {
534 g_width = -g_width;
535 p++;
536 }
537
538 if (*p == '+' || *p == '-')
539 {
540 g_pos |= (*p == '-') ? 2 : 1;
541 g_xpos = strtol(p, &p, 10);
542
543 }
544 if (*p == '+' || *p == '-')
545 {
546 g_pos |= (*p == '-') ? 4 : 1;
547 g_ypos = strtol(p, NULL, 10);
548 }
549
550 break;
551
552 case 'f':
553 g_fullscreen = True;
554 break;
555
556 case 'b':
557 g_bitmap_cache = False;
558 break;
559
560 case 'B':
561 g_ownbackstore = False;
562 break;
563
564 case 'e':
565 g_encryption = False;
566 break;
567 case 'E':
568 packet_encryption = False;
569 break;
570 case 'm':
571 g_sendmotion = False;
572 break;
573
574 case 'C':
575 g_owncolmap = True;
576 break;
577
578 case 'D':
579 g_hide_decorations = True;
580 break;
581
582 case 'K':
583 g_grab_keyboard = False;
584 break;
585
586 case 'S':
587 if (!strcmp(optarg, "standard"))
588 {
589 g_win_button_size = 18;
590 break;
591 }
592
593 g_win_button_size = strtol(optarg, &p, 10);
594
595 if (*p)
596 {
597 error("invalid button size\n");
598 return 1;
599 }
600
601 break;
602
603 case 'T':
604 STRNCPY(g_title, optarg, sizeof(g_title));
605 break;
606
607 case 'N':
608 g_numlock_sync = True;
609 break;
610
611 case 'X':
612 g_embed_wnd = strtol(optarg, NULL, 0);
613 break;
614
615 case 'a':
616 g_server_depth = strtol(optarg, NULL, 10);
617 if (g_server_depth != 8 &&
618 g_server_depth != 16 &&
619 g_server_depth != 15 && g_server_depth != 24)
620 {
621 error("Invalid server colour depth.\n");
622 return 1;
623 }
624 break;
625
626 case 'z':
627 DEBUG(("rdp compression enabled\n"));
628 flags |= (RDP_LOGON_COMPRESSION | RDP_LOGON_COMPRESSION2);
629 break;
630
631 case 'x':
632 if (str_startswith(optarg, "m")) /* modem */
633 {
634 g_rdp5_performanceflags =
635 RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG |
636 RDP5_NO_MENUANIMATIONS | RDP5_NO_THEMING;
637 }
638 else if (str_startswith(optarg, "b")) /* broadband */
639 {
640 g_rdp5_performanceflags = RDP5_NO_WALLPAPER;
641 }
642 else if (str_startswith(optarg, "l")) /* lan */
643 {
644 g_rdp5_performanceflags = RDP5_DISABLE_NOTHING;
645 }
646 else
647 {
648 g_rdp5_performanceflags = strtol(optarg, NULL, 16);
649 }
650 break;
651
652 case 'P':
653 g_bitmap_cache_persist_enable = True;
654 break;
655
656 case 'r':
657
658 if (str_startswith(optarg, "sound"))
659 {
660 optarg += 5;
661
662 if (*optarg == ':')
663 {
664 optarg++;
665 while ((p = next_arg(optarg, ',')))
666 {
667 if (str_startswith(optarg, "remote"))
668 flags |= RDP_LOGON_LEAVE_AUDIO;
669
670 if (str_startswith(optarg, "local"))
671 #ifdef WITH_RDPSND
672 {
673 rdpsnd_optarg =
674 next_arg(optarg, ':');
675 g_rdpsnd = True;
676 }
677
678 #else
679 warning("Not compiled with sound support\n");
680 #endif
681
682 if (str_startswith(optarg, "off"))
683 #ifdef WITH_RDPSND
684 g_rdpsnd = False;
685 #else
686 warning("Not compiled with sound support\n");
687 #endif
688
689 optarg = p;
690 }
691 }
692 else
693 {
694 #ifdef WITH_RDPSND
695 g_rdpsnd = True;
696 #else
697 warning("Not compiled with sound support\n");
698 #endif
699 }
700 }
701 else if (str_startswith(optarg, "disk"))
702 {
703 /* -r disk:h:=/mnt/floppy */
704 disk_enum_devices(&g_num_devices, optarg + 4);
705 }
706 else if (str_startswith(optarg, "comport"))
707 {
708 serial_enum_devices(&g_num_devices, optarg + 7);
709 }
710 else if (str_startswith(optarg, "lspci"))
711 {
712 lspci_enabled = True;
713 }
714 else if (str_startswith(optarg, "lptport"))
715 {
716 parallel_enum_devices(&g_num_devices, optarg + 7);
717 }
718 else if (str_startswith(optarg, "printer"))
719 {
720 printer_enum_devices(&g_num_devices, optarg + 7);
721 }
722 else if (str_startswith(optarg, "clientname"))
723 {
724 g_rdpdr_clientname = xmalloc(strlen(optarg + 11) + 1);
725 strcpy(g_rdpdr_clientname, optarg + 11);
726 }
727 else if (str_startswith(optarg, "clipboard"))
728 {
729 optarg += 9;
730
731 if (*optarg == ':')
732 {
733 optarg++;
734
735 if (str_startswith(optarg, "off"))
736 g_rdpclip = False;
737 else
738 cliprdr_set_mode(optarg);
739 }
740 else
741 g_rdpclip = True;
742 }
743 else
744 {
745 warning("Unknown -r argument\n\n\tPossible arguments are: comport, disk, lptport, printer, sound, clipboard\n");
746 }
747 break;
748
749 case '0':
750 g_console_session = True;
751 break;
752
753 case '4':
754 g_use_rdp5 = False;
755 break;
756
757 case '5':
758 g_use_rdp5 = True;
759 break;
760
761 case 'h':
762 case '?':
763 default:
764 usage(argv[0]);
765 return 1;
766 }
767 }
768
769 if (argc - optind != 1)
770 {
771 usage(argv[0]);
772 return 1;
773 }
774
775 STRNCPY(server, argv[optind], sizeof(server));
776 parse_server_and_port(server);
777
778 if (g_seamless_rdp)
779 {
780 if (g_win_button_size)
781 {
782 error("You cannot use -S and -A at the same time\n");
783 return 1;
784 }
785 g_rdp5_performanceflags &= ~RDP5_NO_FULLWINDOWDRAG;
786 if (geometry_option)
787 {
788 error("You cannot use -g and -A at the same time\n");
789 return 1;
790 }
791 if (g_fullscreen)
792 {
793 error("You cannot use -f and -A at the same time\n");
794 return 1;
795 }
796 if (g_hide_decorations)
797 {
798 error("You cannot use -D and -A at the same time\n");
799 return 1;
800 }
801 if (g_embed_wnd)
802 {
803 error("You cannot use -X and -A at the same time\n");
804 return 1;
805 }
806 if (!g_use_rdp5)
807 {
808 error("You cannot use -4 and -A at the same time\n");
809 return 1;
810 }
811 g_width = -100;
812 g_grab_keyboard = False;
813 }
814
815 if (!username_option)
816 {
817 pw = getpwuid(getuid());
818 if ((pw == NULL) || (pw->pw_name == NULL))
819 {
820 error("could not determine username, use -u\n");
821 return 1;
822 }
823
824 STRNCPY(g_username, pw->pw_name, sizeof(g_username));
825 }
826
827 #ifdef HAVE_ICONV
828 if (g_codepage[0] == 0)
829 {
830 if (setlocale(LC_CTYPE, ""))
831 {
832 STRNCPY(g_codepage, nl_langinfo(CODESET), sizeof(g_codepage));
833 }
834 else
835 {
836 STRNCPY(g_codepage, DEFAULT_CODEPAGE, sizeof(g_codepage));
837 }
838 }
839 #endif
840
841 if (g_hostname[0] == 0)
842 {
843 if (gethostname(fullhostname, sizeof(fullhostname)) == -1)
844 {
845 error("could not determine local hostname, use -n\n");
846 return 1;
847 }
848
849 p = strchr(fullhostname, '.');
850 if (p != NULL)
851 *p = 0;
852
853 STRNCPY(g_hostname, fullhostname, sizeof(g_hostname));
854 }
855
856 if (g_keymapname[0] == 0)
857 {
858 if (locale && xkeymap_from_locale(locale))
859 {
860 fprintf(stderr, "Autoselected keyboard map %s\n", g_keymapname);
861 }
862 else
863 {
864 STRNCPY(g_keymapname, "en-us", sizeof(g_keymapname));
865 }
866 }
867 if (locale)
868 xfree(locale);
869
870
871 if (prompt_password && read_password(password, sizeof(password)))
872 flags |= RDP_LOGON_AUTO;
873
874 if (g_title[0] == 0)
875 {
876 strcpy(g_title, "rdesktop - ");
877 strncat(g_title, server, sizeof(g_title) - sizeof("rdesktop - "));
878 }
879
880 #ifdef RDP2VNC
881 rdp2vnc_connect(server, flags, domain, password, shell, directory);
882 return 0;
883 #else
884
885 if (!ui_init())
886 return 1;
887
888 #ifdef WITH_RDPSND
889 if (g_rdpsnd)
890 {
891 if (!rdpsnd_init(rdpsnd_optarg))
892 {
893 warning("Initializing sound-support failed!\n");
894 }
895 }
896 #endif
897
898 if (lspci_enabled)
899 lspci_init();
900
901 rdpdr_init();
902
903 while (run_count < 2 && continue_connect) /* add support for Session Directory; only reconnect once */
904 {
905 if (run_count == 0)
906 {
907 if (!rdp_connect(server, flags, domain, password, shell, directory))
908 return 1;
909 }
910 else if (!rdp_reconnect
911 (server, flags, domain, password, shell, directory, g_redirect_cookie))
912 return 1;
913
914 /* By setting encryption to False here, we have an encrypted login
915 packet but unencrypted transfer of other packets */
916 if (!packet_encryption)
917 g_encryption = False;
918
919
920 DEBUG(("Connection successful.\n"));
921 memset(password, 0, sizeof(password));
922
923 if (run_count == 0)
924 if (!ui_create_window())
925 continue_connect = False;
926
927 if (continue_connect)
928 rdp_main_loop(&deactivated, &ext_disc_reason);
929
930 DEBUG(("Disconnecting...\n"));
931 rdp_disconnect();
932
933 if ((g_redirect == True) && (run_count == 0)) /* Support for Session Directory */
934 {
935 /* reset state of major globals */
936 rdesktop_reset_state();
937
938 STRNCPY(domain, g_redirect_domain, sizeof(domain));
939 STRNCPY(g_username, g_redirect_username, sizeof(g_username));
940 STRNCPY(password, g_redirect_password, sizeof(password));
941 STRNCPY(server, g_redirect_server, sizeof(server));
942 flags |= RDP_LOGON_AUTO;
943
944 g_redirect = False;
945 }
946 else
947 {
948 continue_connect = False;
949 ui_destroy_window();
950 break;
951 }
952
953 run_count++;
954 }
955
956 cache_save_state();
957 ui_deinit();
958
959 if (ext_disc_reason >= 2)
960 print_disconnect_reason(ext_disc_reason);
961
962 if (deactivated)
963 {
964 /* clean disconnect */
965 return 0;
966 }
967 else
968 {
969 if (ext_disc_reason == exDiscReasonAPIInitiatedDisconnect
970 || ext_disc_reason == exDiscReasonAPIInitiatedLogoff)
971 {
972 /* not so clean disconnect, but nothing to worry about */
973 return 0;
974 }
975 else
976 {
977 /* return error */
978 return 2;
979 }
980 }
981
982 #endif
983
984 }
985
986 #ifdef EGD_SOCKET
987 /* Read 32 random bytes from PRNGD or EGD socket (based on OpenSSL RAND_egd) */
988 static BOOL
989 generate_random_egd(uint8 * buf)
990 {
991 struct sockaddr_un addr;
992 BOOL ret = False;
993 int fd;
994
995 fd = socket(AF_UNIX, SOCK_STREAM, 0);
996 if (fd == -1)
997 return False;
998
999 addr.sun_family = AF_UNIX;
1000 memcpy(addr.sun_path, EGD_SOCKET, sizeof(EGD_SOCKET));
1001 if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
1002 goto err;
1003
1004 /* PRNGD and EGD use a simple communications protocol */
1005 buf[0] = 1; /* Non-blocking (similar to /dev/urandom) */
1006 buf[1] = 32; /* Number of requested random bytes */
1007 if (write(fd, buf, 2) != 2)
1008 goto err;
1009
1010 if ((read(fd, buf, 1) != 1) || (buf[0] == 0)) /* Available? */
1011 goto err;
1012
1013 if (read(fd, buf, 32) != 32)
1014 goto err;
1015
1016 ret = True;
1017
1018 err:
1019 close(fd);
1020 return ret;
1021 }
1022 #endif
1023
1024 /* Generate a 32-byte random for the secure transport code. */
1025 void
1026 generate_random(uint8 * random)
1027 {
1028 struct stat st;
1029 struct tms tmsbuf;
1030 MD5_CTX md5;
1031 uint32 *r;
1032 int fd, n;
1033
1034 /* If we have a kernel random device, try that first */
1035 if (((fd = open("/dev/urandom", O_RDONLY)) != -1)
1036 || ((fd = open("/dev/random", O_RDONLY)) != -1))
1037 {
1038 n = read(fd, random, 32);
1039 close(fd);
1040 if (n == 32)
1041 return;
1042 }
1043
1044 #ifdef EGD_SOCKET
1045 /* As a second preference use an EGD */
1046 if (generate_random_egd(random))
1047 return;
1048 #endif
1049
1050 /* Otherwise use whatever entropy we can gather - ideas welcome. */
1051 r = (uint32 *) random;
1052 r[0] = (getpid()) | (getppid() << 16);
1053 r[1] = (getuid()) | (getgid() << 16);
1054 r[2] = times(&tmsbuf); /* system uptime (clocks) */
1055 gettimeofday((struct timeval *) &r[3], NULL); /* sec and usec */
1056 stat("/tmp", &st);
1057 r[5] = st.st_atime;
1058 r[6] = st.st_mtime;
1059 r[7] = st.st_ctime;
1060
1061 /* Hash both halves with MD5 to obscure possible patterns */
1062 MD5_Init(&md5);
1063 MD5_Update(&md5, random, 16);
1064 MD5_Final(random, &md5);
1065 MD5_Update(&md5, random + 16, 16);
1066 MD5_Final(random + 16, &md5);
1067 }
1068
1069 /* malloc; exit if out of memory */
1070 void *
1071 xmalloc(int size)
1072 {
1073 void *mem = malloc(size);
1074 if (mem == NULL)
1075 {
1076 error("xmalloc %d\n", size);
1077 exit(1);
1078 }
1079 return mem;
1080 }
1081
1082 /* strdup */
1083 char *
1084 xstrdup(const char *s)
1085 {
1086 char *mem = strdup(s);
1087 if (mem == NULL)
1088 {
1089 perror("strdup");
1090 exit(1);
1091 }
1092 return mem;
1093 }
1094
1095 /* realloc; exit if out of memory */
1096 void *
1097 xrealloc(void *oldmem, int size)
1098 {
1099 void *mem;
1100
1101 if (size < 1)
1102 size = 1;
1103 mem = realloc(oldmem, size);
1104 if (mem == NULL)
1105 {
1106 error("xrealloc %d\n", size);
1107 exit(1);
1108 }
1109 return mem;
1110 }
1111
1112 /* free */
1113 void
1114 xfree(void *mem)
1115 {
1116 free(mem);
1117 }
1118
1119 /* report an error */
1120 void
1121 error(char *format, ...)
1122 {
1123 va_list ap;
1124
1125 fprintf(stderr, "ERROR: ");
1126
1127 va_start(ap, format);
1128 vfprintf(stderr, format, ap);
1129 va_end(ap);
1130 }
1131
1132 /* report a warning */
1133 void
1134 warning(char *format, ...)
1135 {
1136 va_list ap;
1137
1138 fprintf(stderr, "WARNING: ");
1139
1140 va_start(ap, format);
1141 vfprintf(stderr, format, ap);
1142 va_end(ap);
1143 }
1144
1145 /* report an unimplemented protocol feature */
1146 void
1147 unimpl(char *format, ...)
1148 {
1149 va_list ap;
1150
1151 fprintf(stderr, "NOT IMPLEMENTED: ");
1152
1153 va_start(ap, format);
1154 vfprintf(stderr, format, ap);
1155 va_end(ap);
1156 }
1157
1158 /* produce a hex dump */
1159 void
1160 hexdump(unsigned char *p, unsigned int len)
1161 {
1162 unsigned char *line = p;
1163 int i, thisline, offset = 0;
1164
1165 while (offset < len)
1166 {
1167 printf("%04x ", offset);
1168 thisline = len - offset;
1169 if (thisline > 16)
1170 thisline = 16;
1171
1172 for (i = 0; i < thisline; i++)
1173 printf("%02x ", line[i]);
1174
1175 for (; i < 16; i++)
1176 printf(" ");
1177
1178 for (i = 0; i < thisline; i++)
1179 printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.');
1180
1181 printf("\n");
1182 offset += thisline;
1183 line += thisline;
1184 }
1185 }
1186
1187 /*
1188 input: src is the string we look in for needle.
1189 Needle may be escaped by a backslash, in
1190 that case we ignore that particular needle.
1191 return value: returns next src pointer, for
1192 succesive executions, like in a while loop
1193 if retval is 0, then there are no more args.
1194 pitfalls:
1195 src is modified. 0x00 chars are inserted to
1196 terminate strings.
1197 return val, points on the next val chr after ins
1198 0x00
1199
1200 example usage:
1201 while( (pos = next_arg( optarg, ',')) ){
1202 printf("%s\n",optarg);
1203 optarg=pos;
1204 }
1205
1206 */
1207 char *
1208 next_arg(char *src, char needle)
1209 {
1210 char *nextval;
1211 char *p;
1212 char *mvp = 0;
1213
1214 /* EOS */
1215 if (*src == (char) 0x00)
1216 return 0;
1217
1218 p = src;
1219 /* skip escaped needles */
1220 while ((nextval = strchr(p, needle)))
1221 {
1222 mvp = nextval - 1;
1223 /* found backslashed needle */
1224 if (*mvp == '\\' && (mvp > src))
1225 {
1226 /* move string one to the left */
1227 while (*(mvp + 1) != (char) 0x00)
1228 {
1229 *mvp = *(mvp + 1);
1230 mvp++;
1231 }
1232 *mvp = (char) 0x00;
1233 p = nextval;
1234 }
1235 else
1236 {
1237 p = nextval + 1;
1238 break;
1239 }
1240
1241 }
1242
1243 /* more args available */
1244 if (nextval)
1245 {
1246 *nextval = (char) 0x00;
1247 return ++nextval;
1248 }
1249
1250 /* no more args after this, jump to EOS */
1251 nextval = src + strlen(src);
1252 return nextval;
1253 }
1254
1255
1256 void
1257 toupper_str(char *p)
1258 {
1259 while (*p)
1260 {
1261 if ((*p >= 'a') && (*p <= 'z'))
1262 *p = toupper((int) *p);
1263 p++;
1264 }
1265 }
1266
1267
1268 BOOL
1269 str_startswith(const char *s, const char *prefix)
1270 {
1271 return (strncmp(s, prefix, strlen(prefix)) == 0);
1272 }
1273
1274
1275 /* Split input into lines, and call linehandler for each
1276 line. Incomplete lines are saved in the rest variable, which should
1277 initially point to NULL. When linehandler returns False, stop and
1278 return False. Otherwise, return True. */
1279 BOOL
1280 str_handle_lines(const char *input, char **rest, str_handle_lines_t linehandler, void *data)
1281 {
1282 char *buf, *p;
1283 char *oldrest;
1284 size_t inputlen;
1285 size_t buflen;
1286 size_t restlen = 0;
1287 BOOL ret = True;
1288
1289 /* Copy data to buffer */
1290 inputlen = strlen(input);
1291 if (*rest)
1292 restlen = strlen(*rest);
1293 buflen = restlen + inputlen + 1;
1294 buf = (char *) xmalloc(buflen);
1295 buf[0] = '\0';
1296 if (*rest)
1297 STRNCPY(buf, *rest, buflen);
1298 strncat(buf, input, inputlen);
1299 p = buf;
1300
1301 while (1)
1302 {
1303 char *newline = strchr(p, '\n');
1304 if (newline)
1305 {
1306 *newline = '\0';
1307 if (!linehandler(p, data))
1308 {
1309 p = newline + 1;
1310 ret = False;
1311 break;
1312 }
1313 p = newline + 1;
1314 }
1315 else
1316 {
1317 break;
1318
1319 }
1320 }
1321
1322 /* Save in rest */
1323 oldrest = *rest;
1324 restlen = buf + buflen - p;
1325 *rest = (char *) xmalloc(restlen);
1326 STRNCPY((*rest), p, restlen);
1327 xfree(oldrest);
1328
1329 xfree(buf);
1330 return ret;
1331 }
1332
1333 /* Execute the program specified by argv. For each line in
1334 stdout/stderr output, call linehandler. Returns false on failure. */
1335 BOOL
1336 subprocess(char *const argv[], str_handle_lines_t linehandler, void *data)
1337 {
1338 pid_t child;
1339 int fd[2];
1340 int n = 1;
1341 char output[256];
1342 char *rest = NULL;
1343
1344 if (pipe(fd) < 0)
1345 {
1346 perror("pipe");
1347 return False;
1348 }
1349
1350 if ((child = fork()) < 0)
1351 {
1352 perror("fork");
1353 return False;
1354 }
1355
1356 /* Child */
1357 if (child == 0)
1358 {
1359 /* Close read end */
1360 close(fd[0]);
1361
1362 /* Redirect stdout and stderr to pipe */
1363 dup2(fd[1], 1);
1364 dup2(fd[1], 2);
1365
1366 /* Execute */
1367 execvp(argv[0], argv);
1368 perror("Error executing child");
1369 _exit(128);
1370 }
1371
1372 /* Parent. Close write end. */
1373 close(fd[1]);
1374 while (n > 0)
1375 {
1376 n = read(fd[0], output, 255);
1377 output[n] = '\0';
1378 str_handle_lines(output, &rest, linehandler, data);
1379 }
1380 xfree(rest);
1381
1382 return True;
1383 }
1384
1385
1386 /* not all clibs got ltoa */
1387 #define LTOA_BUFSIZE (sizeof(long) * 8 + 1)
1388
1389 char *
1390 l_to_a(long N, int base)
1391 {
1392 static char ret[LTOA_BUFSIZE];
1393
1394 char *head = ret, buf[LTOA_BUFSIZE], *tail = buf + sizeof(buf);
1395
1396 register int divrem;
1397
1398 if (base < 36 || 2 > base)
1399 base = 10;
1400
1401 if (N < 0)
1402 {
1403 *head++ = '-';
1404 N = -N;
1405 }
1406
1407 tail = buf + sizeof(buf);
1408 *--tail = 0;
1409
1410 do
1411 {
1412 divrem = N % base;
1413 *--tail = (divrem <= 9) ? divrem + '0' : divrem + 'a' - 10;
1414 N /= base;
1415 }
1416 while (N);
1417
1418 strcpy(head, tail);
1419 return ret;
1420 }
1421
1422
1423 int
1424 load_licence(unsigned char **data)
1425 {
1426 char *home, *path;
1427 struct stat st;
1428 int fd, length;
1429
1430 home = getenv("HOME");
1431 if (home == NULL)
1432 return -1;
1433
1434 path = (char *) xmalloc(strlen(home) + strlen(g_hostname) + sizeof("/.rdesktop/licence."));
1435 sprintf(path, "%s/.rdesktop/licence.%s", home, g_hostname);
1436
1437 fd = open(path, O_RDONLY);
1438 if (fd == -1)
1439 return -1;
1440
1441 if (fstat(fd, &st))
1442 return -1;
1443
1444 *data = (uint8 *) xmalloc(st.st_size);
1445 length = read(fd, *data, st.st_size);
1446 close(fd);
1447 xfree(path);
1448 return length;
1449 }
1450
1451 void
1452 save_licence(unsigned char *data, int length)
1453 {
1454 char *home, *path, *tmppath;
1455 int fd;
1456
1457 home = getenv("HOME");
1458 if (home == NULL)
1459 return;
1460
1461 path = (char *) xmalloc(strlen(home) + strlen(g_hostname) + sizeof("/.rdesktop/licence."));
1462
1463 sprintf(path, "%s/.rdesktop", home);
1464 if ((mkdir(path, 0700) == -1) && errno != EEXIST)
1465 {
1466 perror(path);
1467 return;
1468 }
1469
1470 /* write licence to licence.hostname.new, then atomically rename to licence.hostname */
1471
1472 sprintf(path, "%s/.rdesktop/licence.%s", home, g_hostname);
1473 tmppath = (char *) xmalloc(strlen(path) + sizeof(".new"));
1474 strcpy(tmppath, path);
1475 strcat(tmppath, ".new");
1476
1477 fd = open(tmppath, O_WRONLY | O_CREAT | O_TRUNC, 0600);
1478 if (fd == -1)
1479 {
1480 perror(tmppath);
1481 return;
1482 }
1483
1484 if (write(fd, data, length) != length)
1485 {
1486 perror(tmppath);
1487 unlink(tmppath);
1488 }
1489 else if (rename(tmppath, path) == -1)
1490 {
1491 perror(path);
1492 unlink(tmppath);
1493 }
1494
1495 close(fd);
1496 xfree(tmppath);
1497 xfree(path);
1498 }
1499
1500 /* Create the bitmap cache directory */
1501 BOOL
1502 rd_pstcache_mkdir(void)
1503 {
1504 char *home;
1505 char bmpcache_dir[256];
1506
1507 home = getenv("HOME");
1508
1509 if (home == NULL)
1510 return False;
1511
1512 sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop");
1513
1514 if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST)
1515 {
1516 perror(bmpcache_dir);
1517 return False;
1518 }
1519
1520 sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop/cache");
1521
1522 if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST)
1523 {
1524 perror(bmpcache_dir);
1525 return False;
1526 }
1527
1528 return True;
1529 }
1530
1531 /* open a file in the .rdesktop directory */
1532 int
1533 rd_open_file(char *filename)
1534 {
1535 char *home;
1536 char fn[256];
1537 int fd;
1538
1539 home = getenv("HOME");
1540 if (home == NULL)
1541 return -1;
1542 sprintf(fn, "%s/.rdesktop/%s", home, filename);
1543 fd = open(fn, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
1544 if (fd == -1)
1545 perror(fn);
1546 return fd;
1547 }
1548
1549 /* close file */
1550 void
1551 rd_close_file(int fd)
1552 {
1553 close(fd);
1554 }
1555
1556 /* read from file*/
1557 int
1558 rd_read_file(int fd, void *ptr, int len)
1559 {
1560 return read(fd, ptr, len);
1561 }
1562
1563 /* write to file */
1564 int
1565 rd_write_file(int fd, void *ptr, int len)
1566 {
1567 return write(fd, ptr, len);
1568 }
1569
1570 /* move file pointer */
1571 int
1572 rd_lseek_file(int fd, int offset)
1573 {
1574 return lseek(fd, offset, SEEK_SET);
1575 }
1576
1577 /* do a write lock on a file */
1578 BOOL
1579 rd_lock_file(int fd, int start, int len)
1580 {
1581 struct flock lock;
1582
1583 lock.l_type = F_WRLCK;
1584 lock.l_whence = SEEK_SET;
1585 lock.l_start = start;
1586 lock.l_len = len;
1587 if (fcntl(fd, F_SETLK, &lock) == -1)
1588 return False;
1589 return True;
1590 }

  ViewVC Help
Powered by ViewVC 1.1.26