VirtualBox

source: vbox/trunk/src/VBox/RDP/client-1.8.3/rdesktop.c@ 65817

最後變更 在這個檔案從65817是 65817,由 vboxsync 提交於 8 年 前

rdesktop: initialize IPRT, cures thread adoption related assertion (caused by confusion about the main thread). Thread functionality needs initialization.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 44.0 KB
 
1/* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Entrypoint and utility functions
4 Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 1999-2008
5 Copyright 2002-2011 Peter Astrand <[email protected]> for Cendio AB
6 Copyright 2010-2014 Henrik Andersson <[email protected]> for Cendio AB
7
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22/*
23 * Oracle GPL Disclaimer: For the avoidance of doubt, except that if any license choice
24 * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
25 * the General Public License version 2 (GPLv2) at this time for any software where
26 * a choice of GPL license versions is made available with the language indicating
27 * that GPLv2 or any later version may be used, or where a choice of which version
28 * of the GPL is applied is otherwise unspecified.
29 */
30
31#include <stdarg.h> /* va_list va_start va_end */
32#include <unistd.h> /* read close getuid getgid getpid getppid gethostname */
33#include <fcntl.h> /* open */
34#include <pwd.h> /* getpwuid */
35#include <termios.h> /* tcgetattr tcsetattr */
36#include <sys/stat.h> /* stat */
37#include <sys/time.h> /* gettimeofday */
38#include <sys/times.h> /* times */
39#include <ctype.h> /* toupper */
40#include <limits.h>
41#include <errno.h>
42#include <signal.h>
43#include "rdesktop.h"
44
45#ifdef VBOX
46# include <iprt/initterm.h>
47# include <VBox/version.h>
48# include <iprt/log.h>
49#endif
50
51#ifdef HAVE_LOCALE_H
52#include <locale.h>
53#endif
54#ifdef HAVE_ICONV
55#ifdef HAVE_LANGINFO_H
56#include <langinfo.h>
57#endif
58#endif
59
60#ifdef EGD_SOCKET
61#include <sys/types.h>
62#include <sys/socket.h> /* socket connect */
63#include <sys/un.h> /* sockaddr_un */
64#endif
65
66#include "ssl.h"
67
68/* Reconnect timeout based on approxiamted cookie life-time */
69#define RECONNECT_TIMEOUT (3600+600)
70#define RDESKTOP_LICENSE_STORE "/.local/share/rdesktop/licenses"
71
72uint8 g_static_rdesktop_salt_16[16] = {
73 0xb8, 0x82, 0x29, 0x31, 0xc5, 0x39, 0xd9, 0x44,
74 0x54, 0x15, 0x5e, 0x14, 0x71, 0x38, 0xd5, 0x4d
75};
76
77char g_title[64] = "";
78char *g_username;
79char g_password[64] = "";
80char g_hostname[16] = "";
81char g_keymapname[PATH_MAX] = "";
82unsigned int g_keylayout = 0x409; /* Defaults to US keyboard layout */
83int g_keyboard_type = 0x4; /* Defaults to US keyboard layout */
84int g_keyboard_subtype = 0x0; /* Defaults to US keyboard layout */
85int g_keyboard_functionkeys = 0xc; /* Defaults to US keyboard layout */
86int g_sizeopt = 0; /* If non-zero, a special size has been
87 requested. If 1, the geometry will be fetched
88 from _NET_WORKAREA. If negative, absolute value
89 specifies the percent of the whole screen. */
90int g_width = 800;
91int g_height = 600;
92int g_xpos = 0;
93int g_ypos = 0;
94int g_pos = 0; /* 0 position unspecified,
95 1 specified,
96 2 xpos neg,
97 4 ypos neg */
98extern int g_tcp_port_rdp;
99int g_server_depth = -1;
100int g_win_button_size = 0; /* If zero, disable single app mode */
101RD_BOOL g_network_error = False;
102RD_BOOL g_bitmap_compression = True;
103RD_BOOL g_sendmotion = True;
104RD_BOOL g_bitmap_cache = True;
105RD_BOOL g_bitmap_cache_persist_enable = False;
106RD_BOOL g_bitmap_cache_precache = True;
107RD_BOOL g_use_ctrl = True;
108RD_BOOL g_encryption = True;
109RD_BOOL g_encryption_initial = True;
110RD_BOOL g_packet_encryption = True;
111RD_BOOL g_desktop_save = True; /* desktop save order */
112RD_BOOL g_polygon_ellipse_orders = True; /* polygon / ellipse orders */
113RD_BOOL g_fullscreen = False;
114RD_BOOL g_grab_keyboard = True;
115RD_BOOL g_hide_decorations = False;
116RDP_VERSION g_rdp_version = RDP_V5; /* Default to version 5 */
117RD_BOOL g_rdpclip = True;
118RD_BOOL g_console_session = False;
119#ifndef VBOX
120RD_BOOL g_numlock_sync = False;
121#else /* VBOX */
122/* Always use numlock synchronization with VRDP. */
123RD_BOOL g_numlock_sync = True;
124#endif /* VBOX */
125RD_BOOL g_lspci_enabled = False;
126RD_BOOL g_owncolmap = False;
127RD_BOOL g_ownbackstore = True; /* We can't rely on external BackingStore */
128RD_BOOL g_seamless_rdp = False;
129RD_BOOL g_use_password_as_pin = False;
130char g_seamless_shell[512];
131char g_seamless_spawn_cmd[512];
132RD_BOOL g_seamless_persistent_mode = True;
133RD_BOOL g_user_quit = False;
134uint32 g_embed_wnd;
135uint32 g_rdp5_performanceflags =
136 RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG | RDP5_NO_MENUANIMATIONS | RDP5_NO_CURSOR_SHADOW;
137/* Session Directory redirection */
138RD_BOOL g_redirect = False;
139char *g_redirect_server;
140uint32 g_redirect_server_len;
141char *g_redirect_domain;
142uint32 g_redirect_domain_len;
143char *g_redirect_username;
144uint32 g_redirect_username_len;
145uint8 *g_redirect_lb_info;
146uint32 g_redirect_lb_info_len;
147uint8 *g_redirect_cookie;
148uint32 g_redirect_cookie_len;
149uint32 g_redirect_flags = 0;
150uint32 g_redirect_session_id = 0;
151
152uint32 g_reconnect_logonid = 0;
153char g_reconnect_random[16];
154time_t g_reconnect_random_ts;
155RD_BOOL g_has_reconnect_random = False;
156RD_BOOL g_reconnect_loop = False;
157uint8 g_client_random[SEC_RANDOM_SIZE];
158RD_BOOL g_pending_resize = False;
159
160#ifdef WITH_RDPSND
161RD_BOOL g_rdpsnd = False;
162#endif
163
164#ifdef WITH_RDPUSB
165RD_BOOL g_rdpusb = False;
166#endif
167
168#ifdef WITH_BIRD_VD_HACKS
169RD_BOOL g_keep_virtual_desktop_shortcuts = False;
170#endif
171
172#ifdef HAVE_ICONV
173char g_codepage[16] = "";
174#endif
175
176char *g_sc_csp_name = NULL; /* Smartcard CSP name */
177char *g_sc_reader_name = NULL;
178char *g_sc_card_name = NULL;
179char *g_sc_container_name = NULL;
180
181extern RDPDR_DEVICE g_rdpdr_device[];
182extern uint32 g_num_devices;
183extern char *g_rdpdr_clientname;
184
185#ifdef RDP2VNC
186extern int rfb_port;
187extern int defer_time;
188void
189rdp2vnc_connect(char *server, uint32 flags, char *domain, char *password,
190 char *shell, char *directory);
191#endif
192/* Display usage information */
193static void
194usage(char *program)
195{
196 fprintf(stderr, "rdesktop: A Remote Desktop Protocol client.\n");
197 fprintf(stderr,
198 "Version " PACKAGE_VERSION ". Copyright (C) 1999-2011 Matthew Chapman et al.\n");
199#ifdef VBOX
200 fprintf(stderr, "Modified for VirtualBox by " VBOX_VENDOR "\n");
201#endif
202 fprintf(stderr, "See http://www.rdesktop.org/ for more information.\n\n");
203
204 fprintf(stderr, "Usage: %s [options] server[:port]\n", program);
205#ifdef RDP2VNC
206 fprintf(stderr, " -V: vnc port\n");
207 fprintf(stderr, " -Q: defer time (ms)\n");
208#endif
209 fprintf(stderr, " -u: user name\n");
210 fprintf(stderr, " -d: domain\n");
211 fprintf(stderr, " -s: shell / seamless application to start remotly\n");
212 fprintf(stderr, " -c: working directory\n");
213 fprintf(stderr, " -p: password (- to prompt)\n");
214 fprintf(stderr, " -n: client hostname\n");
215 fprintf(stderr, " -k: keyboard layout on server (en-us, de, sv, etc.)\n");
216 fprintf(stderr, " -g: desktop geometry (WxH)\n");
217#ifdef WITH_SCARD
218 fprintf(stderr, " -i: enables smartcard authentication, password is used as pin\n");
219#endif
220 fprintf(stderr, " -f: full-screen mode\n");
221 fprintf(stderr, " -b: force bitmap updates\n");
222#ifdef HAVE_ICONV
223 fprintf(stderr, " -L: local codepage\n");
224#endif
225 fprintf(stderr, " -A: path to SeamlessRDP shell, this enables SeamlessRDP mode\n");
226 fprintf(stderr, " -B: use BackingStore of X-server (if available)\n");
227 fprintf(stderr, " -e: disable encryption (French TS)\n");
228 fprintf(stderr, " -E: disable encryption from client to server\n");
229 fprintf(stderr, " -m: do not send motion events\n");
230 fprintf(stderr, " -C: use private colour map\n");
231 fprintf(stderr, " -D: hide window manager decorations\n");
232 fprintf(stderr, " -K: keep window manager key bindings\n");
233 fprintf(stderr, " -S: caption button size (single application mode)\n");
234 fprintf(stderr, " -T: window title\n");
235 fprintf(stderr, " -t: disable use of remote ctrl\n");
236 fprintf(stderr, " -N: enable numlock syncronization\n");
237 fprintf(stderr, " -X: embed into another window with a given id.\n");
238 fprintf(stderr, " -a: connection colour depth\n");
239 fprintf(stderr, " -z: enable rdp compression\n");
240 fprintf(stderr, " -x: RDP5 experience (m[odem 28.8], b[roadband], l[an] or hex nr.)\n");
241 fprintf(stderr, " -P: use persistent bitmap caching\n");
242 fprintf(stderr, " -r: enable specified device redirection (this flag can be repeated)\n");
243 fprintf(stderr,
244 " '-r comport:COM1=/dev/ttyS0': enable serial redirection of /dev/ttyS0 to COM1\n");
245 fprintf(stderr, " or COM1=/dev/ttyS0,COM2=/dev/ttyS1\n");
246 fprintf(stderr,
247 " '-r disk:floppy=/mnt/floppy': enable redirection of /mnt/floppy to 'floppy' share\n");
248 fprintf(stderr, " or 'floppy=/mnt/floppy,cdrom=/mnt/cdrom'\n");
249 fprintf(stderr, " '-r clientname=<client name>': Set the client name displayed\n");
250 fprintf(stderr, " for redirected disks\n");
251 fprintf(stderr,
252 " '-r lptport:LPT1=/dev/lp0': enable parallel redirection of /dev/lp0 to LPT1\n");
253 fprintf(stderr, " or LPT1=/dev/lp0,LPT2=/dev/lp1\n");
254 fprintf(stderr, " '-r printer:mydeskjet': enable printer redirection\n");
255 fprintf(stderr,
256 " or mydeskjet=\"HP LaserJet IIIP\" to enter server driver as well\n");
257#ifdef WITH_RDPSND
258 fprintf(stderr,
259 " '-r sound:[local[:driver[:device]]|off|remote]': enable sound redirection\n");
260 fprintf(stderr, " remote would leave sound on server\n");
261 fprintf(stderr, " available drivers for 'local':\n");
262 rdpsnd_show_help();
263#endif
264#ifdef WITH_RDPUSB
265 fprintf(stderr,
266 " '-r usb': enable USB redirection\n");
267#endif
268 fprintf(stderr,
269 " '-r clipboard:[off|PRIMARYCLIPBOARD|CLIPBOARD]': enable clipboard\n");
270 fprintf(stderr, " redirection.\n");
271 fprintf(stderr,
272 " 'PRIMARYCLIPBOARD' looks at both PRIMARY and CLIPBOARD\n");
273 fprintf(stderr, " when sending data to server.\n");
274 fprintf(stderr, " 'CLIPBOARD' looks at only CLIPBOARD.\n");
275#ifdef WITH_SCARD
276 fprintf(stderr, " '-r scard[:\"Scard Name\"=\"Alias Name[;Vendor Name]\"[,...]]\n");
277 fprintf(stderr, " example: -r scard:\"eToken PRO 00 00\"=\"AKS ifdh 0\"\n");
278 fprintf(stderr,
279 " \"eToken PRO 00 00\" -> Device in Linux/Unix enviroment\n");
280 fprintf(stderr,
281 " \"AKS ifdh 0\" -> Device shown in Windows enviroment \n");
282 fprintf(stderr, " example: -r scard:\"eToken PRO 00 00\"=\"AKS ifdh 0;AKS\"\n");
283 fprintf(stderr,
284 " \"eToken PRO 00 00\" -> Device in Linux/Unix enviroment\n");
285 fprintf(stderr,
286 " \"AKS ifdh 0\" -> Device shown in Windows enviroment \n");
287 fprintf(stderr,
288 " \"AKS\" -> Device vendor name \n");
289#endif
290 fprintf(stderr, " -0: attach to console\n");
291 fprintf(stderr, " -4: use RDP version 4\n");
292 fprintf(stderr, " -5: use RDP version 5 (default)\n");
293#ifdef WITH_BIRD_VD_HACKS
294 fprintf(stderr, " -H keep-virtual-desktop-shortcuts: Keep keyboard shortcuts typical\n"
295 " for switching virtual desktops (C-A-Left/Right). \n");
296#endif
297#ifdef WITH_SCARD
298 fprintf(stderr, " -o: name=value: Adds an additional option to rdesktop.\n");
299 fprintf(stderr,
300 " sc-csp-name Specifies the Crypto Service Provider name which\n");
301 fprintf(stderr,
302 " is used to authenticate the user by smartcard\n");
303 fprintf(stderr,
304 " sc-container-name Specifies the container name, this is usally the username\n");
305 fprintf(stderr, " sc-reader-name Smartcard reader name to use\n");
306 fprintf(stderr,
307 " sc-card-name Specifies the card name of the smartcard to use\n");
308#endif
309
310 fprintf(stderr, "\n");
311
312}
313
314static int
315handle_disconnect_reason(RD_BOOL deactivated, uint16 reason)
316{
317 char *text;
318 int retval;
319
320 switch (reason)
321 {
322 case exDiscReasonNoInfo:
323 text = "No information available";
324 if (deactivated)
325 retval = EX_OK;
326 else
327 retval = EXRD_UNKNOWN;
328 break;
329
330 case exDiscReasonAPIInitiatedDisconnect:
331 text = "Server initiated disconnect";
332 retval = EXRD_API_DISCONNECT;
333 break;
334
335 case exDiscReasonAPIInitiatedLogoff:
336 text = "Server initiated logoff";
337 retval = EXRD_API_LOGOFF;
338 break;
339
340 case exDiscReasonServerIdleTimeout:
341 text = "Server idle timeout reached";
342 retval = EXRD_IDLE_TIMEOUT;
343 break;
344
345 case exDiscReasonServerLogonTimeout:
346 text = "Server logon timeout reached";
347 retval = EXRD_LOGON_TIMEOUT;
348 break;
349
350 case exDiscReasonReplacedByOtherConnection:
351 text = "The session was replaced";
352 retval = EXRD_REPLACED;
353 break;
354
355 case exDiscReasonOutOfMemory:
356 text = "The server is out of memory";
357 retval = EXRD_OUT_OF_MEM;
358 break;
359
360 case exDiscReasonServerDeniedConnection:
361 text = "The server denied the connection";
362 retval = EXRD_DENIED;
363 break;
364
365 case exDiscReasonServerDeniedConnectionFips:
366 text = "The server denied the connection for security reason";
367 retval = EXRD_DENIED_FIPS;
368 break;
369
370 case exDiscReasonServerInsufficientPrivileges:
371 text = "The user cannot connect to the server due to insufficient access privileges.";
372 retval = EXRD_INSUFFICIENT_PRIVILEGES;
373 break;
374
375 case exDiscReasonServerFreshCredentialsRequired:
376 text = "The server does not accept saved user credentials and requires that the user enter their credentials for each connection.";
377 retval = EXRD_FRESH_CREDENTIALS_REQUIRED;
378 break;
379
380 case exDiscReasonRPCInitiatedDisconnectByUser:
381 text = "Disconnect initiated by administration tool";
382 retval = EXRD_RPC_DISCONNECT_BY_USER;
383 break;
384
385 case exDiscReasonByUser:
386 text = "Disconnect initiated by user";
387 retval = EXRD_DISCONNECT_BY_USER;
388 break;
389
390 case exDiscReasonLicenseInternal:
391 text = "Internal licensing error";
392 retval = EXRD_LIC_INTERNAL;
393 break;
394
395 case exDiscReasonLicenseNoLicenseServer:
396 text = "No license server available";
397 retval = EXRD_LIC_NOSERVER;
398 break;
399
400 case exDiscReasonLicenseNoLicense:
401 text = "No valid license available";
402 retval = EXRD_LIC_NOLICENSE;
403 break;
404
405 case exDiscReasonLicenseErrClientMsg:
406 text = "Invalid licensing message";
407 retval = EXRD_LIC_MSG;
408 break;
409
410 case exDiscReasonLicenseHwidDoesntMatchLicense:
411 text = "Hardware id doesn't match software license";
412 retval = EXRD_LIC_HWID;
413 break;
414
415 case exDiscReasonLicenseErrClientLicense:
416 text = "Client license error";
417 retval = EXRD_LIC_CLIENT;
418 break;
419
420 case exDiscReasonLicenseCantFinishProtocol:
421 text = "Network error during licensing protocol";
422 retval = EXRD_LIC_NET;
423 break;
424
425 case exDiscReasonLicenseClientEndedProtocol:
426 text = "Licensing protocol was not completed";
427 retval = EXRD_LIC_PROTO;
428 break;
429
430 case exDiscReasonLicenseErrClientEncryption:
431 text = "Incorrect client license encryption";
432 retval = EXRD_LIC_ENC;
433 break;
434
435 case exDiscReasonLicenseCantUpgradeLicense:
436 text = "Can't upgrade license";
437 retval = EXRD_LIC_UPGRADE;
438 break;
439
440 case exDiscReasonLicenseNoRemoteConnections:
441 text = "The server is not licensed to accept remote connections";
442 retval = EXRD_LIC_NOREMOTE;
443 break;
444
445 default:
446 if (reason > 0x1000 && reason < 0x7fff)
447 {
448 text = "Internal protocol error";
449 }
450 else
451 {
452 text = "Unknown reason";
453 }
454 retval = EXRD_UNKNOWN;
455 }
456 if (reason != exDiscReasonNoInfo)
457 fprintf(stderr, "disconnect: %s.\n", text);
458
459 return retval;
460}
461
462static void
463rdesktop_reset_state(void)
464{
465 rdp_reset_state();
466#ifdef WITH_SCARD
467 scard_reset_state();
468#endif
469#ifdef WITH_RDPSND
470 rdpsnd_reset_state();
471#endif
472}
473
474static RD_BOOL
475read_password(char *password, int size)
476{
477 struct termios tios;
478 RD_BOOL ret = False;
479 int istty = 0;
480 char *p;
481
482 if (tcgetattr(STDIN_FILENO, &tios) == 0)
483 {
484 fprintf(stderr, "Password: ");
485 tios.c_lflag &= ~ECHO;
486 tcsetattr(STDIN_FILENO, TCSANOW, &tios);
487 istty = 1;
488 }
489
490 if (fgets(password, size, stdin) != NULL)
491 {
492 ret = True;
493
494 /* strip final newline */
495 p = strchr(password, '\n');
496 if (p != NULL)
497 *p = 0;
498 }
499
500 if (istty)
501 {
502 tios.c_lflag |= ECHO;
503 tcsetattr(STDIN_FILENO, TCSANOW, &tios);
504 fprintf(stderr, "\n");
505 }
506
507 return ret;
508}
509
510static void
511parse_server_and_port(char *server)
512{
513 char *p;
514#ifdef IPv6
515 int addr_colons;
516#endif
517
518#ifdef IPv6
519 p = server;
520 addr_colons = 0;
521 while (*p)
522 if (*p++ == ':')
523 addr_colons++;
524 if (addr_colons >= 2)
525 {
526 /* numeric IPv6 style address format - [1:2:3::4]:port */
527 p = strchr(server, ']');
528 if (*server == '[' && p != NULL)
529 {
530 if (*(p + 1) == ':' && *(p + 2) != '\0')
531 g_tcp_port_rdp = strtol(p + 2, NULL, 10);
532 /* remove the port number and brackets from the address */
533 *p = '\0';
534 strncpy(server, server + 1, strlen(server));
535 }
536 }
537 else
538 {
539 /* dns name or IPv4 style address format - server.example.com:port or 1.2.3.4:port */
540 p = strchr(server, ':');
541 if (p != NULL)
542 {
543 g_tcp_port_rdp = strtol(p + 1, NULL, 10);
544 *p = 0;
545 }
546 }
547#else /* no IPv6 support */
548 p = strchr(server, ':');
549 if (p != NULL)
550 {
551 g_tcp_port_rdp = strtol(p + 1, NULL, 10);
552 *p = 0;
553 }
554#endif /* IPv6 */
555
556}
557
558#ifdef VBOX
559/* This disables iprt logging */
560DECLEXPORT(PRTLOGGER) RTCALL RTLogDefaultInit(void)
561{
562 return NULL;
563}
564#endif
565
566/* Client program */
567int
568main(int argc, char *argv[])
569{
570 char server[256];
571 char fullhostname[64];
572 char domain[256];
573 char shell[256];
574 char directory[256];
575 RD_BOOL prompt_password, deactivated;
576 struct passwd *pw;
577 uint32 flags, ext_disc_reason = 0;
578 char *p;
579 int c;
580 char *locale = NULL;
581 int username_option = 0;
582 RD_BOOL geometry_option = False;
583#ifdef WITH_RDPSND
584 char *rdpsnd_optarg = NULL;
585#endif
586
587#ifdef VBOX
588 RTR3InitExe(argc, &argv, 0);
589#endif
590
591#ifdef HAVE_LOCALE_H
592 /* Set locale according to environment */
593 locale = setlocale(LC_ALL, "");
594 if (locale)
595 {
596 locale = xstrdup(locale);
597 }
598
599#endif
600
601 /* Ignore SIGPIPE, since we are using popen() */
602 struct sigaction act;
603 memset(&act, 0, sizeof(act));
604 act.sa_handler = SIG_IGN;
605 sigemptyset(&act.sa_mask);
606 act.sa_flags = 0;
607 sigaction(SIGPIPE, &act, NULL);
608
609 /* setup default flags for TS_INFO_PACKET */
610 flags = RDP_INFO_MOUSE | RDP_INFO_DISABLECTRLALTDEL
611 | RDP_INFO_UNICODE | RDP_INFO_MAXIMIZESHELL | RDP_INFO_ENABLEWINDOWSKEY;
612
613 prompt_password = False;
614 g_seamless_spawn_cmd[0] = domain[0] = g_password[0] = shell[0] = directory[0] = 0;
615 g_embed_wnd = 0;
616
617 g_num_devices = 0;
618
619#ifdef RDP2VNC
620#define VNCOPT "V:Q:"
621#else
622#define VNCOPT
623#endif
624#ifdef WITH_BIRD_VD_HACKS
625#define VDHOPT "H:"
626#else
627#define VDHOPT
628#endif
629
630 while ((c = getopt(argc, argv,
631 VNCOPT VDHOPT "A:u:L:d:s:c:p:n:k:g:o:fbBeEitmzCDKS:T:NX:a:x:Pr:045h?")) != -1)
632 {
633 switch (c)
634 {
635#ifdef RDP2VNC
636 case 'V':
637 rfb_port = strtol(optarg, NULL, 10);
638 if (rfb_port < 100)
639 rfb_port += 5900;
640 break;
641
642 case 'Q':
643 defer_time = strtol(optarg, NULL, 10);
644 if (defer_time < 0)
645 defer_time = 0;
646 break;
647#endif
648
649 case 'A':
650 g_seamless_rdp = True;
651 STRNCPY(g_seamless_shell, optarg, sizeof(g_seamless_shell));
652 break;
653
654 case 'u':
655 g_username = (char *) xmalloc(strlen(optarg) + 1);
656 STRNCPY(g_username, optarg, strlen(optarg) + 1);
657 username_option = 1;
658 break;
659
660 case 'L':
661#ifdef HAVE_ICONV
662 STRNCPY(g_codepage, optarg, sizeof(g_codepage));
663#else
664 error("iconv support not available\n");
665#endif
666 break;
667
668 case 'd':
669 STRNCPY(domain, optarg, sizeof(domain));
670 break;
671
672 case 's':
673 STRNCPY(shell, optarg, sizeof(shell));
674 g_seamless_persistent_mode = False;
675 break;
676
677 case 'c':
678 STRNCPY(directory, optarg, sizeof(directory));
679 break;
680
681 case 'p':
682 if ((optarg[0] == '-') && (optarg[1] == 0))
683 {
684 prompt_password = True;
685 break;
686 }
687
688 STRNCPY(g_password, optarg, sizeof(g_password));
689 flags |= RDP_INFO_AUTOLOGON;
690
691 /* try to overwrite argument so it won't appear in ps */
692 p = optarg;
693 while (*p)
694 *(p++) = 'X';
695 break;
696#ifdef WITH_SCARD
697 case 'i':
698 flags |= RDP_INFO_PASSWORD_IS_SC_PIN;
699 g_use_password_as_pin = True;
700 break;
701#endif
702 case 't':
703 g_use_ctrl = False;
704 break;
705
706 case 'n':
707 STRNCPY(g_hostname, optarg, sizeof(g_hostname));
708 break;
709
710 case 'k':
711 STRNCPY(g_keymapname, optarg, sizeof(g_keymapname));
712 break;
713
714 case 'g':
715 geometry_option = True;
716 g_fullscreen = False;
717 if (!strcmp(optarg, "workarea"))
718 {
719 g_sizeopt = 1;
720 break;
721 }
722
723 g_width = strtol(optarg, &p, 10);
724 if (g_width <= 0)
725 {
726 error("invalid geometry\n");
727 return EX_USAGE;
728 }
729
730 if (*p == 'x')
731 g_height = strtol(p + 1, &p, 10);
732
733 if (g_height <= 0)
734 {
735 error("invalid geometry\n");
736 return EX_USAGE;
737 }
738
739 if (*p == '%')
740 {
741 g_sizeopt = -g_width;
742 g_width = 800;
743 p++;
744 }
745
746 if (*p == '+' || *p == '-')
747 {
748 g_pos |= (*p == '-') ? 2 : 1;
749 g_xpos = strtol(p, &p, 10);
750
751 }
752 if (*p == '+' || *p == '-')
753 {
754 g_pos |= (*p == '-') ? 4 : 1;
755 g_ypos = strtol(p, NULL, 10);
756 }
757
758 break;
759
760 case 'f':
761 g_fullscreen = True;
762 break;
763
764 case 'b':
765 g_bitmap_cache = False;
766 break;
767
768 case 'B':
769 g_ownbackstore = False;
770 break;
771
772 case 'e':
773 g_encryption_initial = g_encryption = False;
774 break;
775 case 'E':
776 g_packet_encryption = False;
777 break;
778 case 'm':
779 g_sendmotion = False;
780 break;
781
782 case 'C':
783 g_owncolmap = True;
784 break;
785
786 case 'D':
787 g_hide_decorations = True;
788 break;
789
790 case 'K':
791 g_grab_keyboard = False;
792 break;
793
794 case 'S':
795 if (!strcmp(optarg, "standard"))
796 {
797 g_win_button_size = 18;
798 break;
799 }
800
801 g_win_button_size = strtol(optarg, &p, 10);
802
803 if (*p)
804 {
805 error("invalid button size\n");
806 return EX_USAGE;
807 }
808
809 break;
810
811 case 'T':
812 STRNCPY(g_title, optarg, sizeof(g_title));
813 break;
814
815 case 'N':
816 g_numlock_sync = True;
817 break;
818
819 case 'X':
820 g_embed_wnd = strtol(optarg, NULL, 0);
821 break;
822
823 case 'a':
824 g_server_depth = strtol(optarg, NULL, 10);
825 if (g_server_depth != 8 &&
826 g_server_depth != 16 &&
827 g_server_depth != 15 && g_server_depth != 24
828 && g_server_depth != 32)
829 {
830 error("Invalid server colour depth.\n");
831 return EX_USAGE;
832 }
833 break;
834
835 case 'z':
836 DEBUG(("rdp compression enabled\n"));
837 flags |= (RDP_INFO_COMPRESSION | RDP_INFO_COMPRESSION2);
838 break;
839
840 case 'x':
841 if (str_startswith(optarg, "m")) /* modem */
842 {
843 g_rdp5_performanceflags = RDP5_NO_CURSOR_SHADOW |
844 RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG |
845 RDP5_NO_MENUANIMATIONS | RDP5_NO_THEMING;
846 }
847 else if (str_startswith(optarg, "b")) /* broadband */
848 {
849 g_rdp5_performanceflags =
850 RDP5_NO_CURSOR_SHADOW | RDP5_NO_WALLPAPER;
851 }
852 else if (str_startswith(optarg, "l")) /* lan */
853 {
854 g_rdp5_performanceflags =
855 RDP5_NO_CURSOR_SHADOW | RDP5_DISABLE_NOTHING;
856 }
857 else
858 {
859 g_rdp5_performanceflags =
860 RDP5_NO_CURSOR_SHADOW | strtol(optarg, NULL, 16);
861 }
862 break;
863
864 case 'P':
865 g_bitmap_cache_persist_enable = True;
866 break;
867
868 case 'r':
869
870 if (str_startswith(optarg, "sound"))
871 {
872 optarg += 5;
873
874 if (*optarg == ':')
875 {
876 optarg++;
877 while ((p = next_arg(optarg, ',')))
878 {
879 if (str_startswith(optarg, "remote"))
880 flags |= RDP_INFO_REMOTE_CONSOLE_AUDIO;
881
882 if (str_startswith(optarg, "local"))
883#ifdef WITH_RDPSND
884 {
885 rdpsnd_optarg =
886 next_arg(optarg, ':');
887 g_rdpsnd = True;
888 }
889
890#else
891 warning("Not compiled with sound support\n");
892#endif
893
894 if (str_startswith(optarg, "off"))
895#ifdef WITH_RDPSND
896 g_rdpsnd = False;
897#else
898 warning("Not compiled with sound support\n");
899#endif
900
901 optarg = p;
902 }
903 }
904 else
905 {
906#ifdef WITH_RDPSND
907 g_rdpsnd = True;
908#else
909 warning("Not compiled with sound support\n");
910#endif
911 }
912 }
913 else if (str_startswith(optarg, "usb"))
914 {
915#ifdef WITH_RDPUSB
916 g_rdpusb = True;
917#else
918 warning("Not compiled with USB support\n");
919#endif
920 }
921 else if (str_startswith(optarg, "disk"))
922 {
923 /* -r disk:h:=/mnt/floppy */
924 disk_enum_devices(&g_num_devices, optarg + 4);
925 }
926 else if (str_startswith(optarg, "comport"))
927 {
928 serial_enum_devices(&g_num_devices, optarg + 7);
929 }
930 else if (str_startswith(optarg, "lspci"))
931 {
932 g_lspci_enabled = True;
933 }
934 else if (str_startswith(optarg, "lptport"))
935 {
936 parallel_enum_devices(&g_num_devices, optarg + 7);
937 }
938 else if (str_startswith(optarg, "printer"))
939 {
940 printer_enum_devices(&g_num_devices, optarg + 7);
941 }
942 else if (str_startswith(optarg, "clientname"))
943 {
944 g_rdpdr_clientname = xmalloc(strlen(optarg + 11) + 1);
945 strcpy(g_rdpdr_clientname, optarg + 11);
946 }
947 else if (str_startswith(optarg, "clipboard"))
948 {
949 optarg += 9;
950
951 if (*optarg == ':')
952 {
953 optarg++;
954
955 if (str_startswith(optarg, "off"))
956 g_rdpclip = False;
957 else
958 cliprdr_set_mode(optarg);
959 }
960 else
961 g_rdpclip = True;
962 }
963 else if (strncmp("scard", optarg, 5) == 0)
964 {
965#ifdef WITH_SCARD
966 scard_enum_devices(&g_num_devices, optarg + 5);
967#else
968 warning("Not compiled with smartcard support\n");
969#endif
970 }
971 else
972 {
973 warning("Unknown -r argument\n\n\tPossible arguments are: comport, disk, lptport, printer, sound, clipboard, scard\n");
974 }
975 break;
976
977 case '0':
978 g_console_session = True;
979 break;
980
981 case '4':
982 g_rdp_version = RDP_V4;
983 break;
984
985 case '5':
986 g_rdp_version = RDP_V5;
987 break;
988#if WITH_SCARD
989 case 'o':
990 {
991 char *p = strchr(optarg, '=');
992 if (p == NULL)
993 {
994 warning("Skipping option '%s' specified, lacks name=value format.\n");
995 continue;
996 }
997
998 if (strncmp(optarg, "sc-csp-name", strlen("sc-scp-name")) ==
999 0)
1000 g_sc_csp_name = strdup(p + 1);
1001 else if (strncmp
1002 (optarg, "sc-reader-name",
1003 strlen("sc-reader-name")) == 0)
1004 g_sc_reader_name = strdup(p + 1);
1005 else if (strncmp
1006 (optarg, "sc-card-name",
1007 strlen("sc-card-name")) == 0)
1008 g_sc_card_name = strdup(p + 1);
1009 else if (strncmp
1010 (optarg, "sc-container-name",
1011 strlen("sc-container-name")) == 0)
1012 g_sc_container_name = strdup(p + 1);
1013
1014 }
1015 break;
1016#endif
1017
1018#ifdef WITH_BIRD_VD_HACKS
1019 case 'H': /* hacks */
1020 if (!strcmp(optarg, "keep-virtual-desktop-shortcuts"))
1021 g_keep_virtual_desktop_shortcuts = True;
1022 else
1023 error("Unknown -H argument\n\n\tPossible argument is: keep-virtual-desktop-shortcuts\n");
1024 break;
1025#endif
1026
1027 case 'h':
1028 case '?':
1029 default:
1030 usage(argv[0]);
1031 return EX_USAGE;
1032 }
1033 }
1034
1035 if (argc - optind != 1)
1036 {
1037 usage(argv[0]);
1038 return EX_USAGE;
1039 }
1040
1041 STRNCPY(server, argv[optind], sizeof(server));
1042 parse_server_and_port(server);
1043
1044 if (g_seamless_rdp)
1045 {
1046 if (shell[0])
1047 STRNCPY(g_seamless_spawn_cmd, shell, sizeof(g_seamless_spawn_cmd));
1048
1049 STRNCPY(shell, g_seamless_shell, sizeof(shell));
1050
1051 if (g_win_button_size)
1052 {
1053 error("You cannot use -S and -A at the same time\n");
1054 return EX_USAGE;
1055 }
1056 g_rdp5_performanceflags &= ~RDP5_NO_FULLWINDOWDRAG;
1057 if (geometry_option)
1058 {
1059 error("You cannot use -g and -A at the same time\n");
1060 return EX_USAGE;
1061 }
1062 if (g_fullscreen)
1063 {
1064 error("You cannot use -f and -A at the same time\n");
1065 return EX_USAGE;
1066 }
1067 if (g_hide_decorations)
1068 {
1069 error("You cannot use -D and -A at the same time\n");
1070 return EX_USAGE;
1071 }
1072 if (g_embed_wnd)
1073 {
1074 error("You cannot use -X and -A at the same time\n");
1075 return EX_USAGE;
1076 }
1077 if (g_rdp_version < RDP_V5)
1078 {
1079 error("You cannot use -4 and -A at the same time\n");
1080 return EX_USAGE;
1081 }
1082 g_sizeopt = -100;
1083 g_grab_keyboard = False;
1084 }
1085
1086 if (!username_option)
1087 {
1088 pw = getpwuid(getuid());
1089 if ((pw == NULL) || (pw->pw_name == NULL))
1090 {
1091 error("could not determine username, use -u\n");
1092 return EX_OSERR;
1093 }
1094 /* +1 for trailing \0 */
1095 int pwlen = strlen(pw->pw_name) + 1;
1096 g_username = (char *) xmalloc(pwlen);
1097 STRNCPY(g_username, pw->pw_name, pwlen);
1098 }
1099
1100#ifdef HAVE_ICONV
1101 if (g_codepage[0] == 0)
1102 {
1103 if (setlocale(LC_CTYPE, ""))
1104 {
1105 STRNCPY(g_codepage, nl_langinfo(CODESET), sizeof(g_codepage));
1106 }
1107 else
1108 {
1109 STRNCPY(g_codepage, DEFAULT_CODEPAGE, sizeof(g_codepage));
1110 }
1111 }
1112#endif
1113
1114 if (g_hostname[0] == 0)
1115 {
1116 if (gethostname(fullhostname, sizeof(fullhostname)) == -1)
1117 {
1118 error("could not determine local hostname, use -n\n");
1119 return EX_OSERR;
1120 }
1121
1122 p = strchr(fullhostname, '.');
1123 if (p != NULL)
1124 *p = 0;
1125
1126 STRNCPY(g_hostname, fullhostname, sizeof(g_hostname));
1127 }
1128
1129 if (g_keymapname[0] == 0)
1130 {
1131 if (locale && xkeymap_from_locale(locale))
1132 {
1133 fprintf(stderr, "Autoselected keyboard map %s\n", g_keymapname);
1134 }
1135 else
1136 {
1137 STRNCPY(g_keymapname, "en-us", sizeof(g_keymapname));
1138 }
1139 }
1140 if (locale)
1141 xfree(locale);
1142
1143
1144 if (prompt_password && read_password(g_password, sizeof(g_password)))
1145 flags |= RDP_INFO_AUTOLOGON;
1146
1147 if (g_title[0] == 0)
1148 {
1149 strcpy(g_title, "rdesktop - ");
1150 strncat(g_title, server, sizeof(g_title) - sizeof("rdesktop - "));
1151 }
1152
1153#ifdef RDP2VNC
1154 rdp2vnc_connect(server, flags, domain, g_password, shell, directory);
1155 return EX_OK;
1156#else
1157
1158 /* Only startup ctrl functionality is seamless are used for now. */
1159 if (g_use_ctrl && g_seamless_rdp)
1160 {
1161 if (ctrl_init(server, domain, g_username) < 0)
1162 {
1163 error("Failed to initialize ctrl mode.");
1164 exit(1);
1165 }
1166
1167 if (ctrl_is_slave())
1168 {
1169 fprintf(stdout,
1170 "rdesktop in slave mode sending command to master process.\n");
1171
1172 if (g_seamless_spawn_cmd[0])
1173 return ctrl_send_command("seamless.spawn", g_seamless_spawn_cmd);
1174
1175 fprintf(stdout, "No command specified to be spawn in seamless mode.\n");
1176 return EX_USAGE;
1177 }
1178 }
1179
1180 if (!ui_init())
1181 return EX_OSERR;
1182
1183#ifdef WITH_RDPSND
1184 if (!rdpsnd_init(rdpsnd_optarg))
1185 warning("Initializing sound-support failed!\n");
1186#endif
1187
1188#ifdef WITH_RDPUSB
1189 if (g_rdpusb)
1190 rdpusb_init();
1191#endif
1192
1193 if (g_lspci_enabled)
1194 lspci_init();
1195
1196 rdpdr_init();
1197 g_reconnect_loop = False;
1198 while (1)
1199 {
1200 rdesktop_reset_state();
1201
1202 if (g_redirect)
1203 {
1204 STRNCPY(domain, g_redirect_domain, sizeof(domain));
1205 xfree(g_username);
1206 g_username = (char *) xmalloc(strlen(g_redirect_username) + 1);
1207 STRNCPY(g_username, g_redirect_username, strlen(g_redirect_username) + 1);
1208 STRNCPY(server, g_redirect_server, sizeof(server));
1209 flags |= RDP_INFO_AUTOLOGON;
1210
1211 fprintf(stderr, "Redirected to %s@%s session %d.\n",
1212 g_redirect_username, g_redirect_server, g_redirect_session_id);
1213
1214 /* A redirect on SSL from a 2003 WTS will result in a 'connection reset by peer'
1215 and therefor we just clear this error before we connect to redirected server.
1216 */
1217 g_network_error = False;
1218 g_redirect = False;
1219 }
1220
1221 ui_init_connection();
1222 if (!rdp_connect
1223 (server, flags, domain, g_password, shell, directory, g_reconnect_loop))
1224 {
1225
1226 g_network_error = False;
1227
1228 if (g_reconnect_loop == False)
1229 return EX_PROTOCOL;
1230
1231 /* check if auto reconnect cookie has timed out */
1232 if (time(NULL) - g_reconnect_random_ts > RECONNECT_TIMEOUT)
1233 {
1234 fprintf(stderr, "Tried to reconnect for %d minutes, giving up.\n",
1235 RECONNECT_TIMEOUT / 60);
1236 return EX_PROTOCOL;
1237 }
1238
1239 sleep(4);
1240 continue;
1241 }
1242
1243 if (g_redirect)
1244 {
1245 rdp_disconnect();
1246 continue;
1247 }
1248
1249 /* By setting encryption to False here, we have an encrypted login
1250 packet but unencrypted transfer of other packets */
1251 if (!g_packet_encryption)
1252 g_encryption_initial = g_encryption = False;
1253
1254 DEBUG(("Connection successful.\n"));
1255
1256 rd_create_ui();
1257 tcp_run_ui(True);
1258
1259 deactivated = False;
1260 g_reconnect_loop = False;
1261 rdp_main_loop(&deactivated, &ext_disc_reason);
1262
1263 tcp_run_ui(False);
1264
1265 DEBUG(("Disconnecting...\n"));
1266 rdp_disconnect();
1267
1268 if (g_redirect)
1269 continue;
1270
1271 /* handle network error and start autoreconnect */
1272 if (g_network_error && !deactivated)
1273 {
1274 fprintf(stderr,
1275 "Disconnected due to network error, retrying to reconnect for %d minutes.\n",
1276 RECONNECT_TIMEOUT / 60);
1277 g_network_error = False;
1278 g_reconnect_loop = True;
1279 continue;
1280 }
1281
1282 ui_seamless_end();
1283 ui_destroy_window();
1284
1285 /* Enter a reconnect loop if we have a pending resize request */
1286 if (g_pending_resize)
1287 {
1288 g_pending_resize = False;
1289 g_reconnect_loop = True;
1290 continue;
1291 }
1292 break;
1293 }
1294
1295 cache_save_state();
1296 ui_deinit();
1297
1298#ifdef WITH_RDPUSB
1299 if (g_rdpusb)
1300 rdpusb_close();
1301#endif
1302
1303 if (g_user_quit)
1304 return EXRD_WINDOW_CLOSED;
1305
1306 return handle_disconnect_reason(deactivated, ext_disc_reason);
1307
1308#endif
1309 if (g_redirect_username)
1310 xfree(g_redirect_username);
1311
1312 xfree(g_username);
1313}
1314
1315#ifdef EGD_SOCKET
1316/* Read 32 random bytes from PRNGD or EGD socket (based on OpenSSL RAND_egd) */
1317static RD_BOOL
1318generate_random_egd(uint8 * buf)
1319{
1320 struct sockaddr_un addr;
1321 RD_BOOL ret = False;
1322 int fd;
1323
1324 fd = socket(AF_UNIX, SOCK_STREAM, 0);
1325 if (fd == -1)
1326 return False;
1327
1328 addr.sun_family = AF_UNIX;
1329 memcpy(addr.sun_path, EGD_SOCKET, sizeof(EGD_SOCKET));
1330 if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
1331 goto err;
1332
1333 /* PRNGD and EGD use a simple communications protocol */
1334 buf[0] = 1; /* Non-blocking (similar to /dev/urandom) */
1335 buf[1] = 32; /* Number of requested random bytes */
1336 if (write(fd, buf, 2) != 2)
1337 goto err;
1338
1339 if ((read(fd, buf, 1) != 1) || (buf[0] == 0)) /* Available? */
1340 goto err;
1341
1342 if (read(fd, buf, 32) != 32)
1343 goto err;
1344
1345 ret = True;
1346
1347 err:
1348 close(fd);
1349 return ret;
1350}
1351#endif
1352
1353/* Generate a 32-byte random for the secure transport code. */
1354void
1355generate_random(uint8 * random)
1356{
1357 struct stat st;
1358 struct tms tmsbuf;
1359 RDSSL_MD5 md5;
1360 uint32 *r;
1361 int fd, n;
1362
1363 /* If we have a kernel random device, try that first */
1364 if (((fd = open("/dev/urandom", O_RDONLY)) != -1)
1365 || ((fd = open("/dev/random", O_RDONLY)) != -1))
1366 {
1367 n = read(fd, random, 32);
1368 close(fd);
1369 if (n == 32)
1370 return;
1371 }
1372
1373#ifdef EGD_SOCKET
1374 /* As a second preference use an EGD */
1375 if (generate_random_egd(random))
1376 return;
1377#endif
1378
1379 /* Otherwise use whatever entropy we can gather - ideas welcome. */
1380 r = (uint32 *) random;
1381 r[0] = (getpid()) | (getppid() << 16);
1382 r[1] = (getuid()) | (getgid() << 16);
1383 r[2] = times(&tmsbuf); /* system uptime (clocks) */
1384 gettimeofday((struct timeval *) &r[3], NULL); /* sec and usec */
1385 stat("/tmp", &st);
1386 r[5] = st.st_atime;
1387 r[6] = st.st_mtime;
1388 r[7] = st.st_ctime;
1389
1390 /* Hash both halves with MD5 to obscure possible patterns */
1391 rdssl_md5_init(&md5);
1392 rdssl_md5_update(&md5, random, 16);
1393 rdssl_md5_final(&md5, random);
1394 rdssl_md5_update(&md5, random + 16, 16);
1395 rdssl_md5_final(&md5, random + 16);
1396}
1397
1398/* malloc; exit if out of memory */
1399void *
1400xmalloc(int size)
1401{
1402 void *mem = malloc(size);
1403 if (mem == NULL)
1404 {
1405 error("xmalloc %d\n", size);
1406 exit(EX_UNAVAILABLE);
1407 }
1408 return mem;
1409}
1410
1411/* Exit on NULL pointer. Use to verify result from XGetImage etc */
1412void
1413exit_if_null(void *ptr)
1414{
1415 if (ptr == NULL)
1416 {
1417 error("unexpected null pointer. Out of memory?\n");
1418 exit(EX_UNAVAILABLE);
1419 }
1420}
1421
1422/* strdup */
1423char *
1424xstrdup(const char *s)
1425{
1426 char *mem = strdup(s);
1427 if (mem == NULL)
1428 {
1429 perror("strdup");
1430 exit(EX_UNAVAILABLE);
1431 }
1432 return mem;
1433}
1434
1435/* realloc; exit if out of memory */
1436void *
1437xrealloc(void *oldmem, size_t size)
1438{
1439 void *mem;
1440
1441 if (size == 0)
1442 size = 1;
1443 mem = realloc(oldmem, size);
1444 if (mem == NULL)
1445 {
1446 error("xrealloc %ld\n", size);
1447 exit(EX_UNAVAILABLE);
1448 }
1449 return mem;
1450}
1451
1452/* free */
1453void
1454xfree(void *mem)
1455{
1456 free(mem);
1457}
1458
1459/* report an error */
1460void
1461error(char *format, ...)
1462{
1463 va_list ap;
1464
1465 fprintf(stderr, "ERROR: ");
1466
1467 va_start(ap, format);
1468 vfprintf(stderr, format, ap);
1469 va_end(ap);
1470}
1471
1472/* report a warning */
1473void
1474warning(char *format, ...)
1475{
1476 va_list ap;
1477
1478 fprintf(stderr, "WARNING: ");
1479
1480 va_start(ap, format);
1481 vfprintf(stderr, format, ap);
1482 va_end(ap);
1483}
1484
1485/* report an unimplemented protocol feature */
1486void
1487unimpl(char *format, ...)
1488{
1489 va_list ap;
1490
1491 fprintf(stderr, "NOT IMPLEMENTED: ");
1492
1493 va_start(ap, format);
1494 vfprintf(stderr, format, ap);
1495 va_end(ap);
1496}
1497
1498/* produce a hex dump */
1499void
1500hexdump(unsigned char *p, unsigned int len)
1501{
1502 unsigned char *line = p;
1503 int i, thisline, offset = 0;
1504
1505 while (offset < len)
1506 {
1507 printf("%04x ", offset);
1508 thisline = len - offset;
1509 if (thisline > 16)
1510 thisline = 16;
1511
1512 for (i = 0; i < thisline; i++)
1513 printf("%02x ", line[i]);
1514
1515 for (; i < 16; i++)
1516 printf(" ");
1517
1518 for (i = 0; i < thisline; i++)
1519 printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.');
1520
1521 printf("\n");
1522 offset += thisline;
1523 line += thisline;
1524 }
1525}
1526
1527/*
1528 input: src is the string we look in for needle.
1529 Needle may be escaped by a backslash, in
1530 that case we ignore that particular needle.
1531 return value: returns next src pointer, for
1532 succesive executions, like in a while loop
1533 if retval is 0, then there are no more args.
1534 pitfalls:
1535 src is modified. 0x00 chars are inserted to
1536 terminate strings.
1537 return val, points on the next val chr after ins
1538 0x00
1539
1540 example usage:
1541 while( (pos = next_arg( optarg, ',')) ){
1542 printf("%s\n",optarg);
1543 optarg=pos;
1544 }
1545
1546*/
1547char *
1548next_arg(char *src, char needle)
1549{
1550 char *nextval;
1551 char *p;
1552 char *mvp = 0;
1553
1554 /* EOS */
1555 if (*src == (char) 0x00)
1556 return 0;
1557
1558 p = src;
1559 /* skip escaped needles */
1560 while ((nextval = strchr(p, needle)))
1561 {
1562 mvp = nextval - 1;
1563 /* found backslashed needle */
1564 if (*mvp == '\\' && (mvp > src))
1565 {
1566 /* move string one to the left */
1567 while (*(mvp + 1) != (char) 0x00)
1568 {
1569 *mvp = *(mvp + 1);
1570 mvp++;
1571 }
1572 *mvp = (char) 0x00;
1573 p = nextval;
1574 }
1575 else
1576 {
1577 p = nextval + 1;
1578 break;
1579 }
1580
1581 }
1582
1583 /* more args available */
1584 if (nextval)
1585 {
1586 *nextval = (char) 0x00;
1587 return ++nextval;
1588 }
1589
1590 /* no more args after this, jump to EOS */
1591 nextval = src + strlen(src);
1592 return nextval;
1593}
1594
1595
1596void
1597toupper_str(char *p)
1598{
1599 while (*p)
1600 {
1601 if ((*p >= 'a') && (*p <= 'z'))
1602 *p = toupper((int) *p);
1603 p++;
1604 }
1605}
1606
1607
1608RD_BOOL
1609str_startswith(const char *s, const char *prefix)
1610{
1611 return (strncmp(s, prefix, strlen(prefix)) == 0);
1612}
1613
1614
1615/* Split input into lines, and call linehandler for each
1616 line. Incomplete lines are saved in the rest variable, which should
1617 initially point to NULL. When linehandler returns False, stop and
1618 return False. Otherwise, return True. */
1619RD_BOOL
1620str_handle_lines(const char *input, char **rest, str_handle_lines_t linehandler, void *data)
1621{
1622 char *buf, *p;
1623 char *oldrest;
1624 size_t inputlen;
1625 size_t buflen;
1626 size_t restlen = 0;
1627 RD_BOOL ret = True;
1628
1629 /* Copy data to buffer */
1630 inputlen = strlen(input);
1631 if (*rest)
1632 restlen = strlen(*rest);
1633 buflen = restlen + inputlen + 1;
1634 buf = (char *) xmalloc(buflen);
1635 buf[0] = '\0';
1636 if (*rest)
1637 STRNCPY(buf, *rest, buflen);
1638 strncat(buf, input, inputlen);
1639 p = buf;
1640
1641 while (1)
1642 {
1643 char *newline = strchr(p, '\n');
1644 if (newline)
1645 {
1646 *newline = '\0';
1647 if (!linehandler(p, data))
1648 {
1649 p = newline + 1;
1650 ret = False;
1651 break;
1652 }
1653 p = newline + 1;
1654 }
1655 else
1656 {
1657 break;
1658
1659 }
1660 }
1661
1662 /* Save in rest */
1663 oldrest = *rest;
1664 restlen = buf + buflen - p;
1665 *rest = (char *) xmalloc(restlen);
1666 STRNCPY((*rest), p, restlen);
1667 xfree(oldrest);
1668
1669 xfree(buf);
1670 return ret;
1671}
1672
1673/* Execute the program specified by argv. For each line in
1674 stdout/stderr output, call linehandler. Returns false on failure. */
1675RD_BOOL
1676subprocess(char *const argv[], str_handle_lines_t linehandler, void *data)
1677{
1678 pid_t child;
1679 int fd[2];
1680 int n = 1;
1681 char output[256];
1682 char *rest = NULL;
1683
1684 if (pipe(fd) < 0)
1685 {
1686 perror("pipe");
1687 return False;
1688 }
1689
1690 if ((child = fork()) < 0)
1691 {
1692 perror("fork");
1693 return False;
1694 }
1695
1696 /* Child */
1697 if (child == 0)
1698 {
1699 /* Close read end */
1700 close(fd[0]);
1701
1702 /* Redirect stdout and stderr to pipe */
1703 dup2(fd[1], 1);
1704 dup2(fd[1], 2);
1705
1706 /* Execute */
1707 execvp(argv[0], argv);
1708 perror("Error executing child");
1709 _exit(128);
1710 }
1711
1712 /* Parent. Close write end. */
1713 close(fd[1]);
1714 while (n > 0)
1715 {
1716 n = read(fd[0], output, 255);
1717 output[n] = '\0';
1718 str_handle_lines(output, &rest, linehandler, data);
1719 }
1720 xfree(rest);
1721
1722 return True;
1723}
1724
1725
1726/* not all clibs got ltoa */
1727#define LTOA_BUFSIZE (sizeof(long) * 8 + 1)
1728
1729char *
1730l_to_a(long N, int base)
1731{
1732 static char ret[LTOA_BUFSIZE];
1733
1734 char *head = ret, buf[LTOA_BUFSIZE], *tail = buf + sizeof(buf);
1735
1736 register int divrem;
1737
1738 if (base < 36 || 2 > base)
1739 base = 10;
1740
1741 if (N < 0)
1742 {
1743 *head++ = '-';
1744 N = -N;
1745 }
1746
1747 tail = buf + sizeof(buf);
1748 *--tail = 0;
1749
1750 do
1751 {
1752 divrem = N % base;
1753 *--tail = (divrem <= 9) ? divrem + '0' : divrem + 'a' - 10;
1754 N /= base;
1755 }
1756 while (N);
1757
1758 strcpy(head, tail);
1759 return ret;
1760}
1761
1762int
1763load_licence(unsigned char **data)
1764{
1765 uint8 ho[20], hi[16];
1766 char *home, path[PATH_MAX], hash[41];
1767 struct stat st;
1768 int fd, length;
1769
1770 home = getenv("HOME");
1771 if (home == NULL)
1772 return -1;
1773
1774 memset(hi, 0, sizeof(hi));
1775 snprintf((char *) hi, 16, "%s", g_hostname);
1776 sec_hash_sha1_16(ho, hi, g_static_rdesktop_salt_16);
1777 sec_hash_to_string(hash, sizeof(hash), ho, sizeof(ho));
1778
1779 snprintf(path, PATH_MAX, "%s" RDESKTOP_LICENSE_STORE "/%s.cal", home, hash);
1780 path[sizeof(path) - 1] = '\0';
1781
1782 fd = open(path, O_RDONLY);
1783 if (fd == -1)
1784 {
1785 /* fallback to try reading old license file */
1786 snprintf(path, PATH_MAX, "%s/.rdesktop/license.%s", home, g_hostname);
1787 path[sizeof(path) - 1] = '\0';
1788 if ((fd = open(path, O_RDONLY)) == -1)
1789 return -1;
1790 }
1791
1792 if (fstat(fd, &st))
1793 {
1794 close(fd);
1795 return -1;
1796 }
1797
1798 *data = (uint8 *) xmalloc(st.st_size);
1799 length = read(fd, *data, st.st_size);
1800 close(fd);
1801 return length;
1802}
1803
1804void
1805save_licence(unsigned char *data, int length)
1806{
1807 uint8 ho[20], hi[16];
1808 char *home, path[PATH_MAX], tmppath[PATH_MAX], hash[41];
1809 int fd;
1810
1811 home = getenv("HOME");
1812 if (home == NULL)
1813 return;
1814
1815 snprintf(path, PATH_MAX, "%s" RDESKTOP_LICENSE_STORE, home);
1816 path[sizeof(path) - 1] = '\0';
1817 if (utils_mkdir_p(path, 0700) == -1)
1818 {
1819 perror(path);
1820 return;
1821 }
1822
1823 memset(hi, 0, sizeof(hi));
1824 snprintf((char *) hi, 16, "%s", g_hostname);
1825 sec_hash_sha1_16(ho, hi, g_static_rdesktop_salt_16);
1826 sec_hash_to_string(hash, sizeof(hash), ho, sizeof(ho));
1827
1828 /* write licence to {sha1}.cal.new, then atomically
1829 rename to {sha1}.cal */
1830 snprintf(path, PATH_MAX, "%s" RDESKTOP_LICENSE_STORE "/%s.cal", home, hash);
1831 path[sizeof(path) - 1] = '\0';
1832
1833 snprintf(tmppath, PATH_MAX, "%s.new", path);
1834 path[sizeof(path) - 1] = '\0';
1835
1836 fd = open(tmppath, O_WRONLY | O_CREAT | O_TRUNC, 0600);
1837 if (fd == -1)
1838 {
1839 perror(tmppath);
1840 return;
1841 }
1842
1843 if (write(fd, data, length) != length)
1844 {
1845 perror(tmppath);
1846 unlink(tmppath);
1847 }
1848 else if (rename(tmppath, path) == -1)
1849 {
1850 perror(path);
1851 unlink(tmppath);
1852 }
1853
1854 close(fd);
1855}
1856
1857/* create rdesktop ui */
1858void
1859rd_create_ui()
1860{
1861 /* only create a window if we dont have one intialized */
1862 if (!ui_have_window())
1863 {
1864 if (!ui_create_window())
1865 exit(EX_OSERR);
1866 }
1867}
1868
1869/* Create the bitmap cache directory */
1870RD_BOOL
1871rd_pstcache_mkdir(void)
1872{
1873 char *home;
1874 char bmpcache_dir[256];
1875
1876 home = getenv("HOME");
1877
1878 if (home == NULL)
1879 return False;
1880
1881#ifdef VBOX
1882 snprintf(bmpcache_dir, sizeof(bmpcache_dir), "%s/%s", home, ".rdesktop");
1883#else
1884 sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop");
1885#endif
1886
1887 if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST)
1888 {
1889 perror(bmpcache_dir);
1890 return False;
1891 }
1892
1893#ifdef VBOX
1894 snprintf(bmpcache_dir, sizeof(bmpcache_dir), "%s/%s", home, ".rdesktop/cache");
1895#else
1896 sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop/cache");
1897#endif
1898
1899 if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST)
1900 {
1901 perror(bmpcache_dir);
1902 return False;
1903 }
1904
1905 return True;
1906}
1907
1908/* open a file in the .rdesktop directory */
1909int
1910rd_open_file(char *filename)
1911{
1912 char *home;
1913 char fn[256];
1914 int fd;
1915
1916 home = getenv("HOME");
1917 if (home == NULL)
1918 return -1;
1919#ifdef VBOX
1920 snprintf(fn, sizeof(fn), "%s/.rdesktop/%s", home, filename);
1921#else
1922 sprintf(fn, "%s/.rdesktop/%s", home, filename);
1923#endif
1924 fd = open(fn, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
1925 if (fd == -1)
1926 perror(fn);
1927 return fd;
1928}
1929
1930/* close file */
1931void
1932rd_close_file(int fd)
1933{
1934 close(fd);
1935}
1936
1937/* read from file*/
1938int
1939rd_read_file(int fd, void *ptr, int len)
1940{
1941 return read(fd, ptr, len);
1942}
1943
1944/* write to file */
1945int
1946rd_write_file(int fd, void *ptr, int len)
1947{
1948 return write(fd, ptr, len);
1949}
1950
1951/* move file pointer */
1952int
1953rd_lseek_file(int fd, int offset)
1954{
1955 return lseek(fd, offset, SEEK_SET);
1956}
1957
1958/* do a write lock on a file */
1959RD_BOOL
1960rd_lock_file(int fd, int start, int len)
1961{
1962 struct flock lock;
1963
1964 lock.l_type = F_WRLCK;
1965 lock.l_whence = SEEK_SET;
1966 lock.l_start = start;
1967 lock.l_len = len;
1968 if (fcntl(fd, F_SETLK, &lock) == -1)
1969 return False;
1970 return True;
1971}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette