/[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 1309 - (hide annotations)
Wed Nov 1 20:52:01 2006 UTC (17 years, 7 months ago) by stargo
File MIME type: text/plain
File size: 34610 byte(s)
Smartcard support by Alexi Volkov <alexi@pravex.kiev.ua> and additional
patches for smartcard-support by Jennings Jared <jared.jennings.ctr@eglin.af.mil>

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

  ViewVC Help
Powered by ViewVC 1.1.26