/[rdesktop]/sourceforge.net/branches/seamlessrdp-branch/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/branches/seamlessrdp-branch/rdesktop/rdesktop.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1053 - (show annotations)
Thu Mar 2 15:22:25 2006 UTC (18 years, 3 months ago) by astrand
Original Path: sourceforge.net/trunk/rdesktop/rdesktop.c
File MIME type: text/plain
File size: 31422 byte(s)
Added support for a new virtual channel, lspci, which makes it
possible for the remote RDP server to enumerate the local PCI devices.

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

  ViewVC Help
Powered by ViewVC 1.1.26