/[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 1392 - (hide annotations)
Sat Feb 10 05:48:50 2007 UTC (17 years, 4 months ago) by jsorg71
File MIME type: text/plain
File size: 34765 byte(s)
g_ prefix for global vars

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

  ViewVC Help
Powered by ViewVC 1.1.26