/[rdesktop]/jpeg/rdesktop/trunk/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 /jpeg/rdesktop/trunk/rdesktop.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1306 - (show annotations)
Fri Oct 27 12:59:38 2006 UTC (17 years, 6 months ago) by astrand
Original Path: sourceforge.net/trunk/rdesktop/rdesktop.c
File MIME type: text/plain
File size: 33596 byte(s)
Prevent segfaults in out of memory conditions by checking the pointer returned from XGetImage.

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 /* Exit on NULL pointer. Use to verify result from XGetImage etc */
1083 void
1084 exit_if_null(void *ptr)
1085 {
1086 if (ptr == NULL)
1087 {
1088 error("unexpected null pointer. Out of memory?\n");
1089 exit(1);
1090 }
1091 }
1092
1093 /* strdup */
1094 char *
1095 xstrdup(const char *s)
1096 {
1097 char *mem = strdup(s);
1098 if (mem == NULL)
1099 {
1100 perror("strdup");
1101 exit(1);
1102 }
1103 return mem;
1104 }
1105
1106 /* realloc; exit if out of memory */
1107 void *
1108 xrealloc(void *oldmem, int size)
1109 {
1110 void *mem;
1111
1112 if (size < 1)
1113 size = 1;
1114 mem = realloc(oldmem, size);
1115 if (mem == NULL)
1116 {
1117 error("xrealloc %d\n", size);
1118 exit(1);
1119 }
1120 return mem;
1121 }
1122
1123 /* free */
1124 void
1125 xfree(void *mem)
1126 {
1127 free(mem);
1128 }
1129
1130 /* report an error */
1131 void
1132 error(char *format, ...)
1133 {
1134 va_list ap;
1135
1136 fprintf(stderr, "ERROR: ");
1137
1138 va_start(ap, format);
1139 vfprintf(stderr, format, ap);
1140 va_end(ap);
1141 }
1142
1143 /* report a warning */
1144 void
1145 warning(char *format, ...)
1146 {
1147 va_list ap;
1148
1149 fprintf(stderr, "WARNING: ");
1150
1151 va_start(ap, format);
1152 vfprintf(stderr, format, ap);
1153 va_end(ap);
1154 }
1155
1156 /* report an unimplemented protocol feature */
1157 void
1158 unimpl(char *format, ...)
1159 {
1160 va_list ap;
1161
1162 fprintf(stderr, "NOT IMPLEMENTED: ");
1163
1164 va_start(ap, format);
1165 vfprintf(stderr, format, ap);
1166 va_end(ap);
1167 }
1168
1169 /* produce a hex dump */
1170 void
1171 hexdump(unsigned char *p, unsigned int len)
1172 {
1173 unsigned char *line = p;
1174 int i, thisline, offset = 0;
1175
1176 while (offset < len)
1177 {
1178 printf("%04x ", offset);
1179 thisline = len - offset;
1180 if (thisline > 16)
1181 thisline = 16;
1182
1183 for (i = 0; i < thisline; i++)
1184 printf("%02x ", line[i]);
1185
1186 for (; i < 16; i++)
1187 printf(" ");
1188
1189 for (i = 0; i < thisline; i++)
1190 printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.');
1191
1192 printf("\n");
1193 offset += thisline;
1194 line += thisline;
1195 }
1196 }
1197
1198 /*
1199 input: src is the string we look in for needle.
1200 Needle may be escaped by a backslash, in
1201 that case we ignore that particular needle.
1202 return value: returns next src pointer, for
1203 succesive executions, like in a while loop
1204 if retval is 0, then there are no more args.
1205 pitfalls:
1206 src is modified. 0x00 chars are inserted to
1207 terminate strings.
1208 return val, points on the next val chr after ins
1209 0x00
1210
1211 example usage:
1212 while( (pos = next_arg( optarg, ',')) ){
1213 printf("%s\n",optarg);
1214 optarg=pos;
1215 }
1216
1217 */
1218 char *
1219 next_arg(char *src, char needle)
1220 {
1221 char *nextval;
1222 char *p;
1223 char *mvp = 0;
1224
1225 /* EOS */
1226 if (*src == (char) 0x00)
1227 return 0;
1228
1229 p = src;
1230 /* skip escaped needles */
1231 while ((nextval = strchr(p, needle)))
1232 {
1233 mvp = nextval - 1;
1234 /* found backslashed needle */
1235 if (*mvp == '\\' && (mvp > src))
1236 {
1237 /* move string one to the left */
1238 while (*(mvp + 1) != (char) 0x00)
1239 {
1240 *mvp = *(mvp + 1);
1241 mvp++;
1242 }
1243 *mvp = (char) 0x00;
1244 p = nextval;
1245 }
1246 else
1247 {
1248 p = nextval + 1;
1249 break;
1250 }
1251
1252 }
1253
1254 /* more args available */
1255 if (nextval)
1256 {
1257 *nextval = (char) 0x00;
1258 return ++nextval;
1259 }
1260
1261 /* no more args after this, jump to EOS */
1262 nextval = src + strlen(src);
1263 return nextval;
1264 }
1265
1266
1267 void
1268 toupper_str(char *p)
1269 {
1270 while (*p)
1271 {
1272 if ((*p >= 'a') && (*p <= 'z'))
1273 *p = toupper((int) *p);
1274 p++;
1275 }
1276 }
1277
1278
1279 BOOL
1280 str_startswith(const char *s, const char *prefix)
1281 {
1282 return (strncmp(s, prefix, strlen(prefix)) == 0);
1283 }
1284
1285
1286 /* Split input into lines, and call linehandler for each
1287 line. Incomplete lines are saved in the rest variable, which should
1288 initially point to NULL. When linehandler returns False, stop and
1289 return False. Otherwise, return True. */
1290 BOOL
1291 str_handle_lines(const char *input, char **rest, str_handle_lines_t linehandler, void *data)
1292 {
1293 char *buf, *p;
1294 char *oldrest;
1295 size_t inputlen;
1296 size_t buflen;
1297 size_t restlen = 0;
1298 BOOL ret = True;
1299
1300 /* Copy data to buffer */
1301 inputlen = strlen(input);
1302 if (*rest)
1303 restlen = strlen(*rest);
1304 buflen = restlen + inputlen + 1;
1305 buf = (char *) xmalloc(buflen);
1306 buf[0] = '\0';
1307 if (*rest)
1308 STRNCPY(buf, *rest, buflen);
1309 strncat(buf, input, inputlen);
1310 p = buf;
1311
1312 while (1)
1313 {
1314 char *newline = strchr(p, '\n');
1315 if (newline)
1316 {
1317 *newline = '\0';
1318 if (!linehandler(p, data))
1319 {
1320 p = newline + 1;
1321 ret = False;
1322 break;
1323 }
1324 p = newline + 1;
1325 }
1326 else
1327 {
1328 break;
1329
1330 }
1331 }
1332
1333 /* Save in rest */
1334 oldrest = *rest;
1335 restlen = buf + buflen - p;
1336 *rest = (char *) xmalloc(restlen);
1337 STRNCPY((*rest), p, restlen);
1338 xfree(oldrest);
1339
1340 xfree(buf);
1341 return ret;
1342 }
1343
1344 /* Execute the program specified by argv. For each line in
1345 stdout/stderr output, call linehandler. Returns false on failure. */
1346 BOOL
1347 subprocess(char *const argv[], str_handle_lines_t linehandler, void *data)
1348 {
1349 pid_t child;
1350 int fd[2];
1351 int n = 1;
1352 char output[256];
1353 char *rest = NULL;
1354
1355 if (pipe(fd) < 0)
1356 {
1357 perror("pipe");
1358 return False;
1359 }
1360
1361 if ((child = fork()) < 0)
1362 {
1363 perror("fork");
1364 return False;
1365 }
1366
1367 /* Child */
1368 if (child == 0)
1369 {
1370 /* Close read end */
1371 close(fd[0]);
1372
1373 /* Redirect stdout and stderr to pipe */
1374 dup2(fd[1], 1);
1375 dup2(fd[1], 2);
1376
1377 /* Execute */
1378 execvp(argv[0], argv);
1379 perror("Error executing child");
1380 _exit(128);
1381 }
1382
1383 /* Parent. Close write end. */
1384 close(fd[1]);
1385 while (n > 0)
1386 {
1387 n = read(fd[0], output, 255);
1388 output[n] = '\0';
1389 str_handle_lines(output, &rest, linehandler, data);
1390 }
1391 xfree(rest);
1392
1393 return True;
1394 }
1395
1396
1397 /* not all clibs got ltoa */
1398 #define LTOA_BUFSIZE (sizeof(long) * 8 + 1)
1399
1400 char *
1401 l_to_a(long N, int base)
1402 {
1403 static char ret[LTOA_BUFSIZE];
1404
1405 char *head = ret, buf[LTOA_BUFSIZE], *tail = buf + sizeof(buf);
1406
1407 register int divrem;
1408
1409 if (base < 36 || 2 > base)
1410 base = 10;
1411
1412 if (N < 0)
1413 {
1414 *head++ = '-';
1415 N = -N;
1416 }
1417
1418 tail = buf + sizeof(buf);
1419 *--tail = 0;
1420
1421 do
1422 {
1423 divrem = N % base;
1424 *--tail = (divrem <= 9) ? divrem + '0' : divrem + 'a' - 10;
1425 N /= base;
1426 }
1427 while (N);
1428
1429 strcpy(head, tail);
1430 return ret;
1431 }
1432
1433
1434 int
1435 load_licence(unsigned char **data)
1436 {
1437 char *home, *path;
1438 struct stat st;
1439 int fd, length;
1440
1441 home = getenv("HOME");
1442 if (home == NULL)
1443 return -1;
1444
1445 path = (char *) xmalloc(strlen(home) + strlen(g_hostname) + sizeof("/.rdesktop/licence."));
1446 sprintf(path, "%s/.rdesktop/licence.%s", home, g_hostname);
1447
1448 fd = open(path, O_RDONLY);
1449 if (fd == -1)
1450 return -1;
1451
1452 if (fstat(fd, &st))
1453 return -1;
1454
1455 *data = (uint8 *) xmalloc(st.st_size);
1456 length = read(fd, *data, st.st_size);
1457 close(fd);
1458 xfree(path);
1459 return length;
1460 }
1461
1462 void
1463 save_licence(unsigned char *data, int length)
1464 {
1465 char *home, *path, *tmppath;
1466 int fd;
1467
1468 home = getenv("HOME");
1469 if (home == NULL)
1470 return;
1471
1472 path = (char *) xmalloc(strlen(home) + strlen(g_hostname) + sizeof("/.rdesktop/licence."));
1473
1474 sprintf(path, "%s/.rdesktop", home);
1475 if ((mkdir(path, 0700) == -1) && errno != EEXIST)
1476 {
1477 perror(path);
1478 return;
1479 }
1480
1481 /* write licence to licence.hostname.new, then atomically rename to licence.hostname */
1482
1483 sprintf(path, "%s/.rdesktop/licence.%s", home, g_hostname);
1484 tmppath = (char *) xmalloc(strlen(path) + sizeof(".new"));
1485 strcpy(tmppath, path);
1486 strcat(tmppath, ".new");
1487
1488 fd = open(tmppath, O_WRONLY | O_CREAT | O_TRUNC, 0600);
1489 if (fd == -1)
1490 {
1491 perror(tmppath);
1492 return;
1493 }
1494
1495 if (write(fd, data, length) != length)
1496 {
1497 perror(tmppath);
1498 unlink(tmppath);
1499 }
1500 else if (rename(tmppath, path) == -1)
1501 {
1502 perror(path);
1503 unlink(tmppath);
1504 }
1505
1506 close(fd);
1507 xfree(tmppath);
1508 xfree(path);
1509 }
1510
1511 /* Create the bitmap cache directory */
1512 BOOL
1513 rd_pstcache_mkdir(void)
1514 {
1515 char *home;
1516 char bmpcache_dir[256];
1517
1518 home = getenv("HOME");
1519
1520 if (home == NULL)
1521 return False;
1522
1523 sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop");
1524
1525 if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST)
1526 {
1527 perror(bmpcache_dir);
1528 return False;
1529 }
1530
1531 sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop/cache");
1532
1533 if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST)
1534 {
1535 perror(bmpcache_dir);
1536 return False;
1537 }
1538
1539 return True;
1540 }
1541
1542 /* open a file in the .rdesktop directory */
1543 int
1544 rd_open_file(char *filename)
1545 {
1546 char *home;
1547 char fn[256];
1548 int fd;
1549
1550 home = getenv("HOME");
1551 if (home == NULL)
1552 return -1;
1553 sprintf(fn, "%s/.rdesktop/%s", home, filename);
1554 fd = open(fn, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
1555 if (fd == -1)
1556 perror(fn);
1557 return fd;
1558 }
1559
1560 /* close file */
1561 void
1562 rd_close_file(int fd)
1563 {
1564 close(fd);
1565 }
1566
1567 /* read from file*/
1568 int
1569 rd_read_file(int fd, void *ptr, int len)
1570 {
1571 return read(fd, ptr, len);
1572 }
1573
1574 /* write to file */
1575 int
1576 rd_write_file(int fd, void *ptr, int len)
1577 {
1578 return write(fd, ptr, len);
1579 }
1580
1581 /* move file pointer */
1582 int
1583 rd_lseek_file(int fd, int offset)
1584 {
1585 return lseek(fd, offset, SEEK_SET);
1586 }
1587
1588 /* do a write lock on a file */
1589 BOOL
1590 rd_lock_file(int fd, int start, int len)
1591 {
1592 struct flock lock;
1593
1594 lock.l_type = F_WRLCK;
1595 lock.l_whence = SEEK_SET;
1596 lock.l_start = start;
1597 lock.l_len = len;
1598 if (fcntl(fd, F_SETLK, &lock) == -1)
1599 return False;
1600 return True;
1601 }

  ViewVC Help
Powered by ViewVC 1.1.26