/[rdesktop]/sourceforge.net/trunk/rdesktop/rdesktop.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /sourceforge.net/trunk/rdesktop/rdesktop.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1053 - (hide annotations)
Thu Mar 2 15:22:25 2006 UTC (18 years, 4 months ago) by astrand
File MIME type: text/plain
File size: 31422 byte(s)
Added support for a new virtual channel, lspci, which makes it
possible for the remote RDP server to enumerate the local PCI devices.

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

  ViewVC Help
Powered by ViewVC 1.1.26