/[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 1226 - (show annotations)
Wed Apr 12 06:47:24 2006 UTC (18 years, 1 month ago) by astrand
File MIME type: text/plain
File size: 33075 byte(s)
The default color depth is now the depth of the root window.

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

  ViewVC Help
Powered by ViewVC 1.1.26