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

Contents of /jpeg/rdesktop/trunk/rdesktop.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1417 - (show annotations)
Thu Aug 30 04:47:36 2007 UTC (16 years, 9 months ago) by jsorg71
Original Path: sourceforge.net/trunk/rdesktop/rdesktop.c
File MIME type: text/plain
File size: 34797 byte(s)
32 bit color

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

  ViewVC Help
Powered by ViewVC 1.1.26