/[rdesktop]/sourceforge.net/trunk/rdesktop/rdesktop.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /sourceforge.net/trunk/rdesktop/rdesktop.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1309 - (show annotations)
Wed Nov 1 20:52:01 2006 UTC (17 years, 7 months ago) by stargo
File MIME type: text/plain
File size: 34610 byte(s)
Smartcard support by Alexi Volkov <alexi@pravex.kiev.ua> and additional
patches for smartcard-support by Jennings Jared <jared.jennings.ctr@eglin.af.mil>

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

  ViewVC Help
Powered by ViewVC 1.1.26