/[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 1372 - (show annotations)
Mon Jan 8 04:47:06 2007 UTC (17 years, 4 months ago) by jsorg71
File MIME type: text/plain
File size: 34741 byte(s)
prefix BOOL with RD_

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

  ViewVC Help
Powered by ViewVC 1.1.26