/[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 1271 - (hide annotations)
Mon Sep 18 21:42:50 2006 UTC (17 years, 9 months ago) by stargo
File MIME type: text/plain
File size: 33935 byte(s)
handle missing audio-drivers better

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

  ViewVC Help
Powered by ViewVC 1.1.26