VirtualBox

source: vbox/trunk/src/VBox/RDP/client/rdesktop.c@ 50174

Last change on this file since 50174 was 38836, checked in by vboxsync, 13 years ago

rdesktop: Quick virtual desktop usability hack, disabled by default.

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