/[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 1488 - (hide annotations)
Fri May 15 08:18:08 2009 UTC (15 years ago) by astrand
Original Path: sourceforge.net/rdesktop/trunk/rdesktop.c
File MIME type: text/plain
File size: 35111 byte(s)
Moving rdesktop trunk to correct location. 


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

  ViewVC Help
Powered by ViewVC 1.1.26