/[rdesktop]/jpeg/rdesktop/trunk/rdesktop.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /jpeg/rdesktop/trunk/rdesktop.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1426 - (hide annotations)
Sat Jan 5 05:43:02 2008 UTC (16 years, 4 months ago) by matthewc
Original Path: sourceforge.net/trunk/rdesktop/rdesktop.c
File MIME type: text/plain
File size: 34802 byte(s)
Add some more warnings and sanity checks.

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

  ViewVC Help
Powered by ViewVC 1.1.26