/[rdesktop]/jpeg/rdesktop/trunk/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 /jpeg/rdesktop/trunk/rdesktop.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1306 - (hide annotations)
Fri Oct 27 12:59:38 2006 UTC (17 years, 6 months ago) by astrand
Original Path: sourceforge.net/trunk/rdesktop/rdesktop.c
File MIME type: text/plain
File size: 33596 byte(s)
Prevent segfaults in out of memory conditions by checking the pointer returned from XGetImage.

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 stargo 1272 char *rdpsnd_optarg = NULL;
412 matty 10
413 astrand 973 #ifdef HAVE_LOCALE_H
414 astrand 962 /* Set locale according to environment */
415     locale = setlocale(LC_ALL, "");
416     if (locale)
417     {
418 astrand 974 locale = xstrdup(locale);
419 astrand 962 }
420    
421 astrand 973 #endif
422 matty 21 flags = RDP_LOGON_NORMAL;
423 matthewc 211 prompt_password = False;
424 matty 21 domain[0] = password[0] = shell[0] = directory[0] = 0;
425 stargo 636 g_embed_wnd = 0;
426 matty 21
427 n-ki 569 g_num_devices = 0;
428    
429 astrand 333 #ifdef RDP2VNC
430 forsberg 471 #define VNCOPT "V:Q:"
431 astrand 333 #else
432     #define VNCOPT
433     #endif
434    
435 jsorg71 725 while ((c = getopt(argc, argv,
436 astrand 1199 VNCOPT "Au:L:d:s:c:p:n:k:g:fbBeEmzCDKS:T:NX:a:x:Pr:045h?")) != -1)
437 matty 10 {
438     switch (c)
439     {
440 astrand 333 #ifdef RDP2VNC
441     case 'V':
442     rfb_port = strtol(optarg, NULL, 10);
443     if (rfb_port < 100)
444     rfb_port += 5900;
445     break;
446    
447 forsberg 471 case 'Q':
448 astrand 333 defer_time = strtol(optarg, NULL, 10);
449     if (defer_time < 0)
450     defer_time = 0;
451     break;
452     #endif
453    
454 astrand 1199 case 'A':
455     g_seamless_rdp = True;
456     break;
457    
458 matty 10 case 'u':
459 jsorg71 437 STRNCPY(g_username, optarg, sizeof(g_username));
460 astrand 289 username_option = 1;
461 matty 10 break;
462    
463 stargo 855 case 'L':
464     #ifdef HAVE_ICONV
465     STRNCPY(g_codepage, optarg, sizeof(g_codepage));
466     #else
467     error("iconv support not available\n");
468     #endif
469     break;
470    
471 matty 21 case 'd':
472 matty 30 STRNCPY(domain, optarg, sizeof(domain));
473 matty 21 break;
474    
475     case 's':
476 matty 30 STRNCPY(shell, optarg, sizeof(shell));
477 matty 21 break;
478    
479     case 'c':
480 matty 30 STRNCPY(directory, optarg, sizeof(directory));
481 matty 21 break;
482    
483 matty 30 case 'p':
484 matthewc 211 if ((optarg[0] == '-') && (optarg[1] == 0))
485     {
486     prompt_password = True;
487     break;
488     }
489    
490 matty 30 STRNCPY(password, optarg, sizeof(password));
491     flags |= RDP_LOGON_AUTO;
492 matthewc 211
493     /* try to overwrite argument so it won't appear in ps */
494 n-ki 171 p = optarg;
495     while (*p)
496     *(p++) = 'X';
497 matty 30 break;
498    
499 matty 10 case 'n':
500 jsorg71 710 STRNCPY(g_hostname, optarg, sizeof(g_hostname));
501 matty 10 break;
502    
503     case 'k':
504 astrand 975 STRNCPY(g_keymapname, optarg, sizeof(g_keymapname));
505 matty 10 break;
506    
507 matty 30 case 'g':
508 astrand 1199 geometry_option = True;
509 astrand 547 g_fullscreen = False;
510 astrand 263 if (!strcmp(optarg, "workarea"))
511     {
512 jsorg71 447 g_width = g_height = 0;
513 astrand 263 break;
514     }
515    
516 jsorg71 447 g_width = strtol(optarg, &p, 10);
517 astrand 500 if (g_width <= 0)
518     {
519     error("invalid geometry\n");
520     return 1;
521     }
522    
523 matty 30 if (*p == 'x')
524 stargo 800 g_height = strtol(p + 1, &p, 10);
525 matty 30
526 astrand 500 if (g_height <= 0)
527 matty 30 {
528     error("invalid geometry\n");
529     return 1;
530     }
531 astrand 500
532     if (*p == '%')
533 stargo 800 {
534 astrand 500 g_width = -g_width;
535 stargo 800 p++;
536     }
537 astrand 500
538 stargo 800 if (*p == '+' || *p == '-')
539 stargo 867 {
540     g_pos |= (*p == '-') ? 2 : 1;
541 stargo 800 g_xpos = strtol(p, &p, 10);
542 astrand 801
543 stargo 867 }
544 stargo 800 if (*p == '+' || *p == '-')
545 stargo 867 {
546     g_pos |= (*p == '-') ? 4 : 1;
547 stargo 800 g_ypos = strtol(p, NULL, 10);
548 stargo 867 }
549 stargo 800
550 matty 10 break;
551    
552 matty 30 case 'f':
553 jsorg71 447 g_fullscreen = True;
554 matty 30 break;
555    
556 matty 10 case 'b':
557 jsorg71 678 g_bitmap_cache = False;
558 matty 10 break;
559    
560 stargo 609 case 'B':
561     g_ownbackstore = False;
562     break;
563    
564 matty 30 case 'e':
565 jsorg71 437 g_encryption = False;
566 matty 10 break;
567 astrand 435 case 'E':
568 forsberg 427 packet_encryption = False;
569     break;
570 matty 30 case 'm':
571 jsorg71 447 g_sendmotion = False;
572 matty 28 break;
573 matty 29
574 n-ki 279 case 'C':
575 jsorg71 450 g_owncolmap = True;
576 n-ki 279 break;
577    
578 matthewc 520 case 'D':
579     g_hide_decorations = True;
580     break;
581    
582 astrand 76 case 'K':
583 jsorg71 450 g_grab_keyboard = False;
584 astrand 76 break;
585    
586 matthewc 520 case 'S':
587     if (!strcmp(optarg, "standard"))
588     {
589     g_win_button_size = 18;
590     break;
591     }
592    
593     g_win_button_size = strtol(optarg, &p, 10);
594    
595     if (*p)
596     {
597     error("invalid button size\n");
598     return 1;
599     }
600    
601     break;
602    
603 matthewc 223 case 'T':
604 jsorg71 450 STRNCPY(g_title, optarg, sizeof(g_title));
605 astrand 107 break;
606    
607 astrand 552 case 'N':
608     g_numlock_sync = True;
609     break;
610    
611 stargo 636 case 'X':
612 stargo 871 g_embed_wnd = strtol(optarg, NULL, 0);
613 stargo 636 break;
614 astrand 651
615 jsorg71 309 case 'a':
616 astrand 1042 g_server_depth = strtol(optarg, NULL, 10);
617     if (g_server_depth != 8 &&
618     g_server_depth != 16 &&
619     g_server_depth != 15 && g_server_depth != 24)
620 jsorg71 309 {
621 astrand 1042 error("Invalid server colour depth.\n");
622 jsorg71 309 return 1;
623     }
624     break;
625    
626 jsorg71 773 case 'z':
627     DEBUG(("rdp compression enabled\n"));
628 jdmeijer 889 flags |= (RDP_LOGON_COMPRESSION | RDP_LOGON_COMPRESSION2);
629 jsorg71 773 break;
630    
631 stargo 637 case 'x':
632 astrand 1010 if (str_startswith(optarg, "m")) /* modem */
633 stargo 637 {
634 astrand 651 g_rdp5_performanceflags =
635     RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG |
636     RDP5_NO_MENUANIMATIONS | RDP5_NO_THEMING;
637 stargo 637 }
638 astrand 1010 else if (str_startswith(optarg, "b")) /* broadband */
639 stargo 637 {
640     g_rdp5_performanceflags = RDP5_NO_WALLPAPER;
641     }
642 astrand 1010 else if (str_startswith(optarg, "l")) /* lan */
643 stargo 637 {
644     g_rdp5_performanceflags = RDP5_DISABLE_NOTHING;
645     }
646     else
647     {
648     g_rdp5_performanceflags = strtol(optarg, NULL, 16);
649     }
650     break;
651 astrand 651
652 jsorg71 725 case 'P':
653     g_bitmap_cache_persist_enable = True;
654     break;
655    
656 matthewc 520 case 'r':
657 n-ki 569
658 astrand 1010 if (str_startswith(optarg, "sound"))
659 n-ki 569 {
660 n-ki 629 optarg += 5;
661    
662     if (*optarg == ':')
663 n-ki 628 {
664 astrand 1224 optarg++;
665 n-ki 629 while ((p = next_arg(optarg, ',')))
666     {
667 astrand 1010 if (str_startswith(optarg, "remote"))
668 n-ki 629 flags |= RDP_LOGON_LEAVE_AUDIO;
669 n-ki 628
670 astrand 1010 if (str_startswith(optarg, "local"))
671 stargo 501 #ifdef WITH_RDPSND
672 stargo 1255 {
673 stargo 1272 rdpsnd_optarg =
674     next_arg(optarg, ':');
675     g_rdpsnd = True;
676 stargo 1255 }
677    
678 matthewc 520 #else
679 stargo 739 warning("Not compiled with sound support\n");
680 matthewc 520 #endif
681 n-ki 629
682 astrand 1010 if (str_startswith(optarg, "off"))
683 stargo 685 #ifdef WITH_RDPSND
684 n-ki 629 g_rdpsnd = False;
685 stargo 685 #else
686 stargo 739 warning("Not compiled with sound support\n");
687 stargo 685 #endif
688 n-ki 629
689     optarg = p;
690 n-ki 628 }
691     }
692     else
693     {
694     #ifdef WITH_RDPSND
695 stargo 1272 g_rdpsnd = True;
696 n-ki 628 #else
697 stargo 739 warning("Not compiled with sound support\n");
698 n-ki 628 #endif
699     }
700 n-ki 569 }
701 astrand 1010 else if (str_startswith(optarg, "disk"))
702 n-ki 569 {
703     /* -r disk:h:=/mnt/floppy */
704     disk_enum_devices(&g_num_devices, optarg + 4);
705     }
706 astrand 1010 else if (str_startswith(optarg, "comport"))
707 n-ki 569 {
708     serial_enum_devices(&g_num_devices, optarg + 7);
709     }
710 astrand 1053 else if (str_startswith(optarg, "lspci"))
711     {
712     lspci_enabled = True;
713     }
714 astrand 1010 else if (str_startswith(optarg, "lptport"))
715 n-ki 569 {
716     parallel_enum_devices(&g_num_devices, optarg + 7);
717     }
718 astrand 1010 else if (str_startswith(optarg, "printer"))
719 n-ki 569 {
720     printer_enum_devices(&g_num_devices, optarg + 7);
721     }
722 astrand 1010 else if (str_startswith(optarg, "clientname"))
723 forsberg 646 {
724 astrand 651 g_rdpdr_clientname = xmalloc(strlen(optarg + 11) + 1);
725 forsberg 646 strcpy(g_rdpdr_clientname, optarg + 11);
726     }
727 ossman_ 1207 else if (str_startswith(optarg, "clipboard"))
728     {
729     optarg += 9;
730    
731     if (*optarg == ':')
732     {
733     optarg++;
734    
735     if (str_startswith(optarg, "off"))
736     g_rdpclip = False;
737     else
738     cliprdr_set_mode(optarg);
739     }
740     else
741     g_rdpclip = True;
742     }
743 n-ki 569 else
744     {
745 ossman_ 1207 warning("Unknown -r argument\n\n\tPossible arguments are: comport, disk, lptport, printer, sound, clipboard\n");
746 n-ki 569 }
747 stargo 501 break;
748 matthewc 520
749 matthewc 482 case '0':
750     g_console_session = True;
751     break;
752    
753 astrand 458 case '4':
754     g_use_rdp5 = False;
755     break;
756    
757 forsberg 350 case '5':
758 jsorg71 438 g_use_rdp5 = True;
759 forsberg 350 break;
760 astrand 458
761 matty 28 case 'h':
762 matty 10 case '?':
763     default:
764     usage(argv[0]);
765     return 1;
766     }
767     }
768    
769 stargo 610 if (argc - optind != 1)
770 matty 10 {
771     usage(argv[0]);
772     return 1;
773     }
774    
775 matthewc 222 STRNCPY(server, argv[optind], sizeof(server));
776 astrand 444 parse_server_and_port(server);
777 matty 10
778 astrand 1199 if (g_seamless_rdp)
779     {
780     if (g_win_button_size)
781     {
782     error("You cannot use -S and -A at the same time\n");
783     return 1;
784     }
785     g_rdp5_performanceflags &= ~RDP5_NO_FULLWINDOWDRAG;
786     if (geometry_option)
787     {
788     error("You cannot use -g and -A at the same time\n");
789     return 1;
790     }
791     if (g_fullscreen)
792     {
793     error("You cannot use -f and -A at the same time\n");
794     return 1;
795     }
796     if (g_hide_decorations)
797     {
798     error("You cannot use -D and -A at the same time\n");
799     return 1;
800     }
801     if (g_embed_wnd)
802     {
803     error("You cannot use -X and -A at the same time\n");
804     return 1;
805     }
806     if (!g_use_rdp5)
807     {
808     error("You cannot use -4 and -A at the same time\n");
809     return 1;
810     }
811     g_width = -100;
812     g_grab_keyboard = False;
813     }
814    
815 astrand 289 if (!username_option)
816 matty 10 {
817     pw = getpwuid(getuid());
818     if ((pw == NULL) || (pw->pw_name == NULL))
819     {
820 matty 30 error("could not determine username, use -u\n");
821 matty 10 return 1;
822     }
823    
824 jsorg71 437 STRNCPY(g_username, pw->pw_name, sizeof(g_username));
825 matty 10 }
826    
827 stargo 855 #ifdef HAVE_ICONV
828     if (g_codepage[0] == 0)
829     {
830     if (setlocale(LC_CTYPE, ""))
831     {
832     STRNCPY(g_codepage, nl_langinfo(CODESET), sizeof(g_codepage));
833     }
834     else
835     {
836     STRNCPY(g_codepage, DEFAULT_CODEPAGE, sizeof(g_codepage));
837     }
838     }
839     #endif
840 stargo 861
841 jsorg71 710 if (g_hostname[0] == 0)
842 matty 10 {
843 matty 30 if (gethostname(fullhostname, sizeof(fullhostname)) == -1)
844 matty 10 {
845 matty 30 error("could not determine local hostname, use -n\n");
846 matty 10 return 1;
847     }
848 matty 30
849     p = strchr(fullhostname, '.');
850     if (p != NULL)
851     *p = 0;
852    
853 jsorg71 710 STRNCPY(g_hostname, fullhostname, sizeof(g_hostname));
854 matty 10 }
855    
856 astrand 975 if (g_keymapname[0] == 0)
857 astrand 973 {
858     if (locale && xkeymap_from_locale(locale))
859     {
860 astrand 975 fprintf(stderr, "Autoselected keyboard map %s\n", g_keymapname);
861 astrand 973 }
862     else
863     {
864 astrand 975 STRNCPY(g_keymapname, "en-us", sizeof(g_keymapname));
865 astrand 973 }
866     }
867     if (locale)
868     xfree(locale);
869    
870    
871 matthewc 211 if (prompt_password && read_password(password, sizeof(password)))
872     flags |= RDP_LOGON_AUTO;
873 matty 30
874 jsorg71 450 if (g_title[0] == 0)
875 astrand 107 {
876 jsorg71 450 strcpy(g_title, "rdesktop - ");
877     strncat(g_title, server, sizeof(g_title) - sizeof("rdesktop - "));
878 astrand 107 }
879 matty 12
880 astrand 333 #ifdef RDP2VNC
881     rdp2vnc_connect(server, flags, domain, password, shell, directory);
882 forsberg 424 return 0;
883 astrand 333 #else
884    
885 astrand 82 if (!ui_init())
886     return 1;
887 astrand 66
888 matthewc 474 #ifdef WITH_RDPSND
889 stargo 501 if (g_rdpsnd)
890 stargo 1272 {
891     if (!rdpsnd_init(rdpsnd_optarg))
892     {
893     warning("Initializing sound-support failed!\n");
894     }
895     }
896 matthewc 474 #endif
897 astrand 1053
898     if (lspci_enabled)
899     lspci_init();
900    
901 n-ki 569 rdpdr_init();
902 forsberg 416
903 astrand 977 while (run_count < 2 && continue_connect) /* add support for Session Directory; only reconnect once */
904     {
905     if (run_count == 0)
906     {
907     if (!rdp_connect(server, flags, domain, password, shell, directory))
908     return 1;
909     }
910     else if (!rdp_reconnect
911     (server, flags, domain, password, shell, directory, g_redirect_cookie))
912     return 1;
913 matthewc 53
914 astrand 977 /* By setting encryption to False here, we have an encrypted login
915     packet but unencrypted transfer of other packets */
916     if (!packet_encryption)
917     g_encryption = False;
918 forsberg 427
919    
920 astrand 977 DEBUG(("Connection successful.\n"));
921     memset(password, 0, sizeof(password));
922 matthewc 53
923 astrand 977 if (run_count == 0)
924     if (!ui_create_window())
925     continue_connect = False;
926    
927     if (continue_connect)
928     rdp_main_loop(&deactivated, &ext_disc_reason);
929    
930     DEBUG(("Disconnecting...\n"));
931     rdp_disconnect();
932    
933     if ((g_redirect == True) && (run_count == 0)) /* Support for Session Directory */
934     {
935     /* reset state of major globals */
936     rdesktop_reset_state();
937    
938     STRNCPY(domain, g_redirect_domain, sizeof(domain));
939     STRNCPY(g_username, g_redirect_username, sizeof(g_username));
940     STRNCPY(password, g_redirect_password, sizeof(password));
941     STRNCPY(server, g_redirect_server, sizeof(server));
942     flags |= RDP_LOGON_AUTO;
943    
944     g_redirect = False;
945     }
946     else
947     {
948     continue_connect = False;
949     ui_destroy_window();
950     break;
951     }
952    
953     run_count++;
954 matty 10 }
955    
956 jsorg71 725 cache_save_state();
957 matthewc 188 ui_deinit();
958 astrand 333
959 astrand 676 if (ext_disc_reason >= 2)
960     print_disconnect_reason(ext_disc_reason);
961    
962     if (deactivated)
963     {
964     /* clean disconnect */
965 forsberg 424 return 0;
966 astrand 676 }
967 forsberg 424 else
968 astrand 676 {
969     if (ext_disc_reason == exDiscReasonAPIInitiatedDisconnect
970     || ext_disc_reason == exDiscReasonAPIInitiatedLogoff)
971     {
972     /* not so clean disconnect, but nothing to worry about */
973     return 0;
974     }
975     else
976     {
977     /* return error */
978     return 2;
979     }
980     }
981 forsberg 424
982 astrand 333 #endif
983    
984 matty 10 }
985    
986 matthewc 220 #ifdef EGD_SOCKET
987     /* Read 32 random bytes from PRNGD or EGD socket (based on OpenSSL RAND_egd) */
988     static BOOL
989     generate_random_egd(uint8 * buf)
990     {
991     struct sockaddr_un addr;
992     BOOL ret = False;
993     int fd;
994    
995     fd = socket(AF_UNIX, SOCK_STREAM, 0);
996     if (fd == -1)
997     return False;
998    
999     addr.sun_family = AF_UNIX;
1000     memcpy(addr.sun_path, EGD_SOCKET, sizeof(EGD_SOCKET));
1001 astrand 259 if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
1002 matthewc 220 goto err;
1003    
1004     /* PRNGD and EGD use a simple communications protocol */
1005 astrand 259 buf[0] = 1; /* Non-blocking (similar to /dev/urandom) */
1006     buf[1] = 32; /* Number of requested random bytes */
1007 matthewc 220 if (write(fd, buf, 2) != 2)
1008     goto err;
1009    
1010 astrand 259 if ((read(fd, buf, 1) != 1) || (buf[0] == 0)) /* Available? */
1011 matthewc 220 goto err;
1012    
1013     if (read(fd, buf, 32) != 32)
1014     goto err;
1015    
1016     ret = True;
1017    
1018 astrand 259 err:
1019 matthewc 220 close(fd);
1020     return ret;
1021     }
1022     #endif
1023    
1024 matty 10 /* Generate a 32-byte random for the secure transport code. */
1025 matty 25 void
1026 astrand 64 generate_random(uint8 * random)
1027 matty 10 {
1028     struct stat st;
1029 matty 22 struct tms tmsbuf;
1030 matthewc 220 MD5_CTX md5;
1031     uint32 *r;
1032     int fd, n;
1033 matty 10
1034 matthewc 220 /* If we have a kernel random device, try that first */
1035 matty 30 if (((fd = open("/dev/urandom", O_RDONLY)) != -1)
1036     || ((fd = open("/dev/random", O_RDONLY)) != -1))
1037 matty 10 {
1038 matthewc 220 n = read(fd, random, 32);
1039 matty 10 close(fd);
1040 matthewc 220 if (n == 32)
1041     return;
1042 matty 10 }
1043    
1044 matthewc 220 #ifdef EGD_SOCKET
1045     /* As a second preference use an EGD */
1046     if (generate_random_egd(random))
1047     return;
1048     #endif
1049    
1050 matty 10 /* Otherwise use whatever entropy we can gather - ideas welcome. */
1051 astrand 259 r = (uint32 *) random;
1052 matty 10 r[0] = (getpid()) | (getppid() << 16);
1053     r[1] = (getuid()) | (getgid() << 16);
1054 matty 24 r[2] = times(&tmsbuf); /* system uptime (clocks) */
1055     gettimeofday((struct timeval *) &r[3], NULL); /* sec and usec */
1056 matty 10 stat("/tmp", &st);
1057     r[5] = st.st_atime;
1058     r[6] = st.st_mtime;
1059     r[7] = st.st_ctime;
1060 matthewc 220
1061     /* Hash both halves with MD5 to obscure possible patterns */
1062     MD5_Init(&md5);
1063 astrand 259 MD5_Update(&md5, random, 16);
1064 matthewc 220 MD5_Final(random, &md5);
1065 astrand 259 MD5_Update(&md5, random + 16, 16);
1066     MD5_Final(random + 16, &md5);
1067 matty 10 }
1068    
1069     /* malloc; exit if out of memory */
1070 matty 25 void *
1071     xmalloc(int size)
1072 matty 10 {
1073     void *mem = malloc(size);
1074     if (mem == NULL)
1075     {
1076 matty 30 error("xmalloc %d\n", size);
1077 matty 10 exit(1);
1078     }
1079     return mem;
1080     }
1081    
1082 astrand 1306 /* Exit on NULL pointer. Use to verify result from XGetImage etc */
1083     void
1084     exit_if_null(void *ptr)
1085     {
1086     if (ptr == NULL)
1087     {
1088     error("unexpected null pointer. Out of memory?\n");
1089     exit(1);
1090     }
1091     }
1092    
1093 astrand 974 /* strdup */
1094     char *
1095     xstrdup(const char *s)
1096     {
1097     char *mem = strdup(s);
1098     if (mem == NULL)
1099     {
1100     perror("strdup");
1101     exit(1);
1102     }
1103     return mem;
1104     }
1105    
1106 matty 10 /* realloc; exit if out of memory */
1107 matty 25 void *
1108     xrealloc(void *oldmem, int size)
1109 matty 10 {
1110 astrand 782 void *mem;
1111 jsorg71 773
1112     if (size < 1)
1113     size = 1;
1114     mem = realloc(oldmem, size);
1115 matty 10 if (mem == NULL)
1116     {
1117 matty 30 error("xrealloc %d\n", size);
1118 matty 10 exit(1);
1119     }
1120     return mem;
1121     }
1122    
1123     /* free */
1124 matty 25 void
1125     xfree(void *mem)
1126 matty 10 {
1127     free(mem);
1128     }
1129    
1130 matty 30 /* report an error */
1131 matty 25 void
1132 matty 30 error(char *format, ...)
1133     {
1134     va_list ap;
1135    
1136     fprintf(stderr, "ERROR: ");
1137    
1138     va_start(ap, format);
1139     vfprintf(stderr, format, ap);
1140     va_end(ap);
1141     }
1142    
1143 matthewc 297 /* report a warning */
1144     void
1145     warning(char *format, ...)
1146     {
1147     va_list ap;
1148    
1149     fprintf(stderr, "WARNING: ");
1150    
1151     va_start(ap, format);
1152     vfprintf(stderr, format, ap);
1153     va_end(ap);
1154     }
1155    
1156 matty 30 /* report an unimplemented protocol feature */
1157     void
1158     unimpl(char *format, ...)
1159     {
1160     va_list ap;
1161    
1162     fprintf(stderr, "NOT IMPLEMENTED: ");
1163    
1164     va_start(ap, format);
1165     vfprintf(stderr, format, ap);
1166     va_end(ap);
1167     }
1168    
1169     /* produce a hex dump */
1170     void
1171 n-ki 569 hexdump(unsigned char *p, unsigned int len)
1172 matty 10 {
1173     unsigned char *line = p;
1174 jsorg71 376 int i, thisline, offset = 0;
1175 matty 10
1176     while (offset < len)
1177     {
1178 matthewc 169 printf("%04x ", offset);
1179 matty 10 thisline = len - offset;
1180     if (thisline > 16)
1181     thisline = 16;
1182    
1183     for (i = 0; i < thisline; i++)
1184 matthewc 169 printf("%02x ", line[i]);
1185 matty 10
1186 matty 30 for (; i < 16; i++)
1187 matthewc 169 printf(" ");
1188 matty 30
1189 matty 10 for (i = 0; i < thisline; i++)
1190 matthewc 169 printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.');
1191 matty 10
1192 matthewc 169 printf("\n");
1193 matty 10 offset += thisline;
1194     line += thisline;
1195     }
1196     }
1197 astrand 325
1198 n-ki 569 /*
1199 n-ki 583 input: src is the string we look in for needle.
1200     Needle may be escaped by a backslash, in
1201     that case we ignore that particular needle.
1202 n-ki 569 return value: returns next src pointer, for
1203     succesive executions, like in a while loop
1204     if retval is 0, then there are no more args.
1205     pitfalls:
1206     src is modified. 0x00 chars are inserted to
1207     terminate strings.
1208     return val, points on the next val chr after ins
1209     0x00
1210 astrand 325
1211 n-ki 569 example usage:
1212     while( (pos = next_arg( optarg, ',')) ){
1213     printf("%s\n",optarg);
1214     optarg=pos;
1215     }
1216    
1217     */
1218     char *
1219     next_arg(char *src, char needle)
1220     {
1221     char *nextval;
1222 n-ki 571 char *p;
1223 n-ki 575 char *mvp = 0;
1224 n-ki 569
1225 n-ki 575 /* EOS */
1226 n-ki 569 if (*src == (char) 0x00)
1227     return 0;
1228    
1229 n-ki 571 p = src;
1230 n-ki 575 /* skip escaped needles */
1231 astrand 580 while ((nextval = strchr(p, needle)))
1232 n-ki 571 {
1233 n-ki 575 mvp = nextval - 1;
1234     /* found backslashed needle */
1235 astrand 580 if (*mvp == '\\' && (mvp > src))
1236 n-ki 575 {
1237     /* move string one to the left */
1238 astrand 580 while (*(mvp + 1) != (char) 0x00)
1239 n-ki 575 {
1240 astrand 580 *mvp = *(mvp + 1);
1241 astrand 1224 mvp++;
1242 n-ki 575 }
1243 astrand 580 *mvp = (char) 0x00;
1244 n-ki 575 p = nextval;
1245     }
1246     else
1247     {
1248 astrand 580 p = nextval + 1;
1249 n-ki 571 break;
1250 n-ki 575 }
1251    
1252 n-ki 571 }
1253    
1254 n-ki 575 /* more args available */
1255 n-ki 569 if (nextval)
1256     {
1257     *nextval = (char) 0x00;
1258     return ++nextval;
1259     }
1260    
1261 n-ki 575 /* no more args after this, jump to EOS */
1262 n-ki 569 nextval = src + strlen(src);
1263     return nextval;
1264     }
1265    
1266    
1267 stargo 570 void
1268 astrand 580 toupper_str(char *p)
1269 n-ki 569 {
1270 astrand 580 while (*p)
1271     {
1272     if ((*p >= 'a') && (*p <= 'z'))
1273 stargo 570 *p = toupper((int) *p);
1274 n-ki 569 p++;
1275     }
1276     }
1277    
1278    
1279 astrand 1010 BOOL
1280     str_startswith(const char *s, const char *prefix)
1281     {
1282     return (strncmp(s, prefix, strlen(prefix)) == 0);
1283     }
1284    
1285    
1286 astrand 1053 /* Split input into lines, and call linehandler for each
1287     line. Incomplete lines are saved in the rest variable, which should
1288     initially point to NULL. When linehandler returns False, stop and
1289     return False. Otherwise, return True. */
1290     BOOL
1291     str_handle_lines(const char *input, char **rest, str_handle_lines_t linehandler, void *data)
1292     {
1293     char *buf, *p;
1294     char *oldrest;
1295     size_t inputlen;
1296     size_t buflen;
1297     size_t restlen = 0;
1298     BOOL ret = True;
1299    
1300     /* Copy data to buffer */
1301     inputlen = strlen(input);
1302     if (*rest)
1303     restlen = strlen(*rest);
1304     buflen = restlen + inputlen + 1;
1305     buf = (char *) xmalloc(buflen);
1306     buf[0] = '\0';
1307     if (*rest)
1308     STRNCPY(buf, *rest, buflen);
1309     strncat(buf, input, inputlen);
1310     p = buf;
1311    
1312     while (1)
1313     {
1314     char *newline = strchr(p, '\n');
1315     if (newline)
1316     {
1317     *newline = '\0';
1318     if (!linehandler(p, data))
1319     {
1320     p = newline + 1;
1321     ret = False;
1322     break;
1323     }
1324     p = newline + 1;
1325     }
1326     else
1327     {
1328     break;
1329    
1330     }
1331     }
1332    
1333     /* Save in rest */
1334     oldrest = *rest;
1335     restlen = buf + buflen - p;
1336     *rest = (char *) xmalloc(restlen);
1337     STRNCPY((*rest), p, restlen);
1338     xfree(oldrest);
1339    
1340     xfree(buf);
1341     return ret;
1342     }
1343    
1344     /* Execute the program specified by argv. For each line in
1345     stdout/stderr output, call linehandler. Returns false on failure. */
1346     BOOL
1347     subprocess(char *const argv[], str_handle_lines_t linehandler, void *data)
1348     {
1349     pid_t child;
1350     int fd[2];
1351     int n = 1;
1352     char output[256];
1353     char *rest = NULL;
1354    
1355     if (pipe(fd) < 0)
1356     {
1357     perror("pipe");
1358     return False;
1359     }
1360    
1361     if ((child = fork()) < 0)
1362     {
1363     perror("fork");
1364     return False;
1365     }
1366    
1367     /* Child */
1368     if (child == 0)
1369     {
1370     /* Close read end */
1371     close(fd[0]);
1372    
1373     /* Redirect stdout and stderr to pipe */
1374     dup2(fd[1], 1);
1375     dup2(fd[1], 2);
1376    
1377     /* Execute */
1378     execvp(argv[0], argv);
1379     perror("Error executing child");
1380     _exit(128);
1381     }
1382    
1383     /* Parent. Close write end. */
1384     close(fd[1]);
1385     while (n > 0)
1386     {
1387     n = read(fd[0], output, 255);
1388     output[n] = '\0';
1389     str_handle_lines(output, &rest, linehandler, data);
1390     }
1391     xfree(rest);
1392    
1393     return True;
1394     }
1395    
1396    
1397 n-ki 569 /* not all clibs got ltoa */
1398     #define LTOA_BUFSIZE (sizeof(long) * 8 + 1)
1399    
1400     char *
1401 stargo 603 l_to_a(long N, int base)
1402 n-ki 569 {
1403     static char ret[LTOA_BUFSIZE];
1404    
1405 n-ki 583 char *head = ret, buf[LTOA_BUFSIZE], *tail = buf + sizeof(buf);
1406 n-ki 569
1407 n-ki 583 register int divrem;
1408    
1409     if (base < 36 || 2 > base)
1410 n-ki 569 base = 10;
1411    
1412 n-ki 583 if (N < 0)
1413 n-ki 569 {
1414     *head++ = '-';
1415 n-ki 583 N = -N;
1416 n-ki 569 }
1417    
1418 n-ki 583 tail = buf + sizeof(buf);
1419     *--tail = 0;
1420    
1421     do
1422 n-ki 569 {
1423 n-ki 583 divrem = N % base;
1424     *--tail = (divrem <= 9) ? divrem + '0' : divrem + 'a' - 10;
1425     N /= base;
1426 n-ki 569 }
1427 n-ki 583 while (N);
1428 n-ki 569
1429 n-ki 583 strcpy(head, tail);
1430 n-ki 569 return ret;
1431     }
1432    
1433    
1434 astrand 325 int
1435     load_licence(unsigned char **data)
1436     {
1437 matthewc 367 char *home, *path;
1438 astrand 325 struct stat st;
1439 matthewc 367 int fd, length;
1440 astrand 325
1441     home = getenv("HOME");
1442     if (home == NULL)
1443     return -1;
1444    
1445 jsorg71 710 path = (char *) xmalloc(strlen(home) + strlen(g_hostname) + sizeof("/.rdesktop/licence."));
1446     sprintf(path, "%s/.rdesktop/licence.%s", home, g_hostname);
1447 astrand 325
1448     fd = open(path, O_RDONLY);
1449     if (fd == -1)
1450     return -1;
1451    
1452     if (fstat(fd, &st))
1453     return -1;
1454    
1455 forsberg 416 *data = (uint8 *) xmalloc(st.st_size);
1456 matthewc 367 length = read(fd, *data, st.st_size);
1457     close(fd);
1458     xfree(path);
1459     return length;
1460 astrand 325 }
1461    
1462     void
1463     save_licence(unsigned char *data, int length)
1464     {
1465 matthewc 367 char *home, *path, *tmppath;
1466     int fd;
1467 astrand 325
1468     home = getenv("HOME");
1469     if (home == NULL)
1470     return;
1471    
1472 jsorg71 710 path = (char *) xmalloc(strlen(home) + strlen(g_hostname) + sizeof("/.rdesktop/licence."));
1473 astrand 325
1474 matthewc 367 sprintf(path, "%s/.rdesktop", home);
1475     if ((mkdir(path, 0700) == -1) && errno != EEXIST)
1476 astrand 325 {
1477 matthewc 367 perror(path);
1478     return;
1479 astrand 325 }
1480    
1481 matthewc 367 /* write licence to licence.hostname.new, then atomically rename to licence.hostname */
1482 astrand 325
1483 jsorg71 710 sprintf(path, "%s/.rdesktop/licence.%s", home, g_hostname);
1484 forsberg 416 tmppath = (char *) xmalloc(strlen(path) + sizeof(".new"));
1485 matthewc 367 strcpy(tmppath, path);
1486     strcat(tmppath, ".new");
1487    
1488 forsberg 416 fd = open(tmppath, O_WRONLY | O_CREAT | O_TRUNC, 0600);
1489 matthewc 367 if (fd == -1)
1490 astrand 325 {
1491 matthewc 367 perror(tmppath);
1492     return;
1493 astrand 325 }
1494    
1495 matthewc 367 if (write(fd, data, length) != length)
1496 astrand 325 {
1497 matthewc 367 perror(tmppath);
1498     unlink(tmppath);
1499 astrand 325 }
1500 matthewc 367 else if (rename(tmppath, path) == -1)
1501 astrand 325 {
1502 matthewc 367 perror(path);
1503     unlink(tmppath);
1504 astrand 325 }
1505    
1506 matthewc 367 close(fd);
1507     xfree(tmppath);
1508     xfree(path);
1509 astrand 325 }
1510 jsorg71 725
1511     /* Create the bitmap cache directory */
1512     BOOL
1513     rd_pstcache_mkdir(void)
1514     {
1515     char *home;
1516     char bmpcache_dir[256];
1517    
1518     home = getenv("HOME");
1519    
1520     if (home == NULL)
1521     return False;
1522    
1523     sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop");
1524    
1525     if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST)
1526     {
1527     perror(bmpcache_dir);
1528     return False;
1529     }
1530    
1531     sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop/cache");
1532    
1533     if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST)
1534     {
1535     perror(bmpcache_dir);
1536     return False;
1537     }
1538    
1539     return True;
1540     }
1541    
1542     /* open a file in the .rdesktop directory */
1543     int
1544     rd_open_file(char *filename)
1545     {
1546     char *home;
1547     char fn[256];
1548 astrand 738 int fd;
1549 jsorg71 725
1550     home = getenv("HOME");
1551     if (home == NULL)
1552     return -1;
1553     sprintf(fn, "%s/.rdesktop/%s", home, filename);
1554     fd = open(fn, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
1555     if (fd == -1)
1556     perror(fn);
1557     return fd;
1558     }
1559    
1560     /* close file */
1561     void
1562     rd_close_file(int fd)
1563     {
1564 astrand 738 close(fd);
1565 jsorg71 725 }
1566    
1567     /* read from file*/
1568     int
1569     rd_read_file(int fd, void *ptr, int len)
1570     {
1571 astrand 738 return read(fd, ptr, len);
1572 jsorg71 725 }
1573    
1574     /* write to file */
1575     int
1576 astrand 738 rd_write_file(int fd, void *ptr, int len)
1577 jsorg71 725 {
1578 astrand 738 return write(fd, ptr, len);
1579 jsorg71 725 }
1580    
1581     /* move file pointer */
1582     int
1583     rd_lseek_file(int fd, int offset)
1584     {
1585 astrand 738 return lseek(fd, offset, SEEK_SET);
1586 jsorg71 725 }
1587    
1588     /* do a write lock on a file */
1589     BOOL
1590     rd_lock_file(int fd, int start, int len)
1591     {
1592     struct flock lock;
1593    
1594     lock.l_type = F_WRLCK;
1595     lock.l_whence = SEEK_SET;
1596     lock.l_start = start;
1597     lock.l_len = len;
1598     if (fcntl(fd, F_SETLK, &lock) == -1)
1599     return False;
1600     return True;
1601     }

  ViewVC Help
Powered by ViewVC 1.1.26