/[rdesktop]/sourceforge.net/branches/seamlessrdp-branch/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/branches/seamlessrdp-branch/rdesktop/rdesktop.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1089 - (hide annotations)
Fri Mar 10 08:50:43 2006 UTC (18 years, 2 months ago) by astrand
File MIME type: text/plain
File size: 32344 byte(s)
Initial support for SeamlessRDP

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

  ViewVC Help
Powered by ViewVC 1.1.26