VirtualBox

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

Last change on this file since 57416 was 57416, checked in by vboxsync, 9 years ago

More DECLCALLBACK fixes; retired RTMemAutoPtr.

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

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