/[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 1089 - (show annotations)
Fri Mar 10 08:50:43 2006 UTC (18 years, 2 months ago) by astrand
File MIME type: text/plain
File size: 32344 byte(s)
Initial support for SeamlessRDP

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

  ViewVC Help
Powered by ViewVC 1.1.26