VirtualBox

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

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

rdesktop 1.8.3 unmodified

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

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