VirtualBox

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

Last change on this file since 37224 was 37224, checked in by vboxsync, 14 years ago

RDP/client: fix OSE

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