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

Annotation of /sourceforge.net/branches/seamlessrdp-branch/rdesktop/rdesktop.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 427 - (hide annotations)
Thu Jun 19 11:51:18 2003 UTC (20 years, 11 months ago) by forsberg
Original Path: sourceforge.net/trunk/rdesktop/rdesktop.c
File MIME type: text/plain
File size: 14110 byte(s)
Make it possible to disable encryption for all packets except the
packets exchanged in the setup phase.

Seems to work with all encryption levels on my W2003 Server (Beta).

1 forsberg 350 /* -*- c-basic-offset: 8 -*-
2 matty 10 rdesktop: A Remote Desktop Protocol client.
3     Entrypoint and utility functions
4 matthewc 304 Copyright (C) Matthew Chapman 1999-2003
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 astrand 325 #include <errno.h>
30 matty 10 #include "rdesktop.h"
31    
32 matthewc 220 #ifdef EGD_SOCKET
33     #include <sys/socket.h> /* socket connect */
34     #include <sys/un.h> /* sockaddr_un */
35     #endif
36    
37     #ifdef WITH_OPENSSL
38     #include <openssl/md5.h>
39     #else
40     #include "crypto/md5.h"
41     #endif
42    
43 astrand 107 char title[32] = "";
44 matty 10 char username[16];
45     char hostname[16];
46 matthewc 38 char keymapname[16];
47 astrand 66 int keylayout = 0x409; /* Defaults to US keyboard layout */
48 jsorg71 309 int width = 800; /* If width or height are reset to zero, the geometry will
49 astrand 263 be fetched from _NET_WORKAREA */
50 matthewc 160 int height = 600;
51 jsorg71 58 int tcp_port_rdp = TCP_PORT_RDP;
52 jsorg71 309 int server_bpp = 8;
53 astrand 328 int win_button_size = 0; /* If zero, disable single app mode */
54 matty 28 BOOL bitmap_compression = True;
55 matty 29 BOOL sendmotion = True;
56 matty 10 BOOL orders = True;
57 matty 30 BOOL encryption = True;
58 forsberg 427 BOOL packet_encryption = True;
59 matty 28 BOOL desktop_save = True;
60     BOOL fullscreen = False;
61 astrand 76 BOOL grab_keyboard = True;
62 astrand 262 BOOL hide_decorations = False;
63 forsberg 350 BOOL use_rdp5 = False;
64 n-ki 279 extern BOOL owncolmap;
65 matty 10
66 astrand 333 #ifdef RDP2VNC
67     extern int rfb_port;
68     extern int defer_time;
69     void
70     rdp2vnc_connect(char *server, uint32 flags, char *domain, char *password,
71     char *shell, char *directory);
72     #endif
73 matty 10 /* Display usage information */
74 matty 25 static void
75     usage(char *program)
76 matty 10 {
77 matthewc 122 fprintf(stderr, "rdesktop: A Remote Desktop Protocol client.\n");
78 matthewc 304 fprintf(stderr, "Version " VERSION ". Copyright (C) 1999-2003 Matt Chapman.\n");
79 matthewc 122 fprintf(stderr, "See http://www.rdesktop.org/ for more information.\n\n");
80    
81 matthewc 222 fprintf(stderr, "Usage: %s [options] server[:port]\n", program);
82 astrand 333 #ifdef RDP2VNC
83     fprintf(stderr, " -V: vnc port\n");
84     fprintf(stderr, " -E: defer time (ms)\n");
85     #endif
86 astrand 111 fprintf(stderr, " -u: user name\n");
87     fprintf(stderr, " -d: domain\n");
88     fprintf(stderr, " -s: shell\n");
89 astrand 329 fprintf(stderr, " -S: caption button size (single application mode)\n");
90 astrand 111 fprintf(stderr, " -c: working directory\n");
91 matthewc 211 fprintf(stderr, " -p: password (- to prompt)\n");
92 astrand 111 fprintf(stderr, " -n: client hostname\n");
93 matthewc 223 fprintf(stderr, " -k: keyboard layout on terminal server (us,sv,gr,etc.)\n");
94 astrand 111 fprintf(stderr, " -g: desktop geometry (WxH)\n");
95     fprintf(stderr, " -f: full-screen mode\n");
96     fprintf(stderr, " -b: force bitmap updates\n");
97     fprintf(stderr, " -e: disable encryption (French TS)\n");
98 forsberg 427 fprintf(stderr, " -E: disable encryption of everything but the logon packet\n");
99 astrand 111 fprintf(stderr, " -m: do not send motion events\n");
100 n-ki 279 fprintf(stderr, " -C: use private colour map\n");
101 astrand 111 fprintf(stderr, " -K: keep window manager key bindings\n");
102 matthewc 223 fprintf(stderr, " -T: window title\n");
103 astrand 262 fprintf(stderr, " -D: hide window manager decorations\n");
104 jsorg71 309 fprintf(stderr, " -a: server bpp\n");
105 forsberg 350 fprintf(stderr, " -5: Use RDP5 (EXPERIMENTAL!)\n");
106 matty 10 }
107    
108 matthewc 211 static BOOL
109     read_password(char *password, int size)
110     {
111     struct termios tios;
112     BOOL ret = False;
113     int istty = 0;
114     char *p;
115    
116     if (tcgetattr(STDIN_FILENO, &tios) == 0)
117     {
118     fprintf(stderr, "Password: ");
119     tios.c_lflag &= ~ECHO;
120     tcsetattr(STDIN_FILENO, TCSANOW, &tios);
121     istty = 1;
122     }
123    
124     if (fgets(password, size, stdin) != NULL)
125     {
126     ret = True;
127    
128     /* strip final newline */
129     p = strchr(password, '\n');
130     if (p != NULL)
131     *p = 0;
132     }
133    
134     if (istty)
135     {
136     tios.c_lflag |= ECHO;
137     tcsetattr(STDIN_FILENO, TCSANOW, &tios);
138     fprintf(stderr, "\n");
139     }
140    
141     return ret;
142     }
143    
144 matty 10 /* Client program */
145 matty 25 int
146     main(int argc, char *argv[])
147 matty 10 {
148 matthewc 222 char server[64];
149 matty 30 char fullhostname[64];
150 matty 21 char domain[16];
151     char password[16];
152 astrand 238 char shell[128];
153 matty 21 char directory[32];
154 forsberg 424 BOOL prompt_password, rdp_retval = False;
155 matty 30 struct passwd *pw;
156     uint32 flags;
157 matthewc 222 char *p;
158 matty 10 int c;
159 astrand 289 int username_option = 0;
160 matty 10
161 matty 21 flags = RDP_LOGON_NORMAL;
162 matthewc 211 prompt_password = False;
163 matty 21 domain[0] = password[0] = shell[0] = directory[0] = 0;
164 matthewc 240 strcpy(keymapname, "en-us");
165 matty 21
166 astrand 333 #ifdef RDP2VNC
167     #define VNCOPT "V:E:"
168     #else
169     #define VNCOPT
170     #endif
171    
172 forsberg 427 while ((c = getopt(argc, argv, VNCOPT "u:d:s:S:c:p:n:k:g:a:fbeEmCKT:Dh?54")) != -1)
173 matty 10 {
174     switch (c)
175     {
176 astrand 333 #ifdef RDP2VNC
177     case 'V':
178     rfb_port = strtol(optarg, NULL, 10);
179     if (rfb_port < 100)
180     rfb_port += 5900;
181     break;
182    
183     case 'E':
184     defer_time = strtol(optarg, NULL, 10);
185     if (defer_time < 0)
186     defer_time = 0;
187     break;
188     #endif
189    
190 matty 10 case 'u':
191 matty 30 STRNCPY(username, optarg, sizeof(username));
192 astrand 289 username_option = 1;
193 matty 10 break;
194    
195 matty 21 case 'd':
196 matty 30 STRNCPY(domain, optarg, sizeof(domain));
197 matty 21 break;
198    
199     case 's':
200 matty 30 STRNCPY(shell, optarg, sizeof(shell));
201 matty 21 break;
202    
203 astrand 328 case 'S':
204     if (!strcmp(optarg, "standard"))
205     {
206     win_button_size = 18;
207     break;
208     }
209    
210     win_button_size = strtol(optarg, &p, 10);
211    
212     if (*p)
213     {
214     error("invalid button size\n");
215     return 1;
216     }
217    
218     break;
219    
220 matty 21 case 'c':
221 matty 30 STRNCPY(directory, optarg, sizeof(directory));
222 matty 21 break;
223    
224 matty 30 case 'p':
225 matthewc 211 if ((optarg[0] == '-') && (optarg[1] == 0))
226     {
227     prompt_password = True;
228     break;
229     }
230    
231 matty 30 STRNCPY(password, optarg, sizeof(password));
232     flags |= RDP_LOGON_AUTO;
233 matthewc 211
234     /* try to overwrite argument so it won't appear in ps */
235 n-ki 171 p = optarg;
236     while (*p)
237     *(p++) = 'X';
238 matty 30 break;
239    
240 matty 10 case 'n':
241 matty 30 STRNCPY(hostname, optarg, sizeof(hostname));
242 matty 10 break;
243    
244     case 'k':
245 astrand 82 STRNCPY(keymapname, optarg, sizeof(keymapname));
246 matty 10 break;
247    
248 matty 30 case 'g':
249 astrand 263 if (!strcmp(optarg, "workarea"))
250     {
251     width = height = 0;
252     break;
253     }
254    
255 matty 30 width = strtol(optarg, &p, 10);
256     if (*p == 'x')
257 astrand 64 height = strtol(p + 1, NULL, 10);
258 matty 30
259     if ((width == 0) || (height == 0))
260     {
261     error("invalid geometry\n");
262     return 1;
263     }
264 matty 10 break;
265    
266 matty 30 case 'f':
267     fullscreen = True;
268     break;
269    
270 matty 10 case 'b':
271     orders = False;
272     break;
273    
274 matty 30 case 'e':
275     encryption = False;
276 matty 10 break;
277 forsberg 427 case 'E':
278     packet_encryption = False;
279     break;
280 matty 30 case 'm':
281     sendmotion = False;
282 matty 28 break;
283 matty 29
284 n-ki 279 case 'C':
285     owncolmap = True;
286     break;
287    
288 astrand 76 case 'K':
289     grab_keyboard = False;
290     break;
291    
292 matthewc 223 case 'T':
293 matthewc 222 STRNCPY(title, optarg, sizeof(title));
294 astrand 107 break;
295    
296 astrand 262 case 'D':
297     hide_decorations = True;
298     break;
299    
300 jsorg71 309 case 'a':
301     server_bpp = strtol(optarg, NULL, 10);
302 astrand 318 if (server_bpp != 8 && server_bpp != 16 && server_bpp != 15
303     && server_bpp != 24)
304 jsorg71 309 {
305     error("invalid server bpp\n");
306     return 1;
307     }
308     break;
309    
310 forsberg 350 case '5':
311     use_rdp5 = True;
312     break;
313 matty 28 case 'h':
314 matty 10 case '?':
315     default:
316     usage(argv[0]);
317     return 1;
318     }
319     }
320    
321     if (argc - optind < 1)
322     {
323     usage(argv[0]);
324     return 1;
325     }
326    
327 matthewc 222 STRNCPY(server, argv[optind], sizeof(server));
328     p = strchr(server, ':');
329     if (p != NULL)
330     {
331     tcp_port_rdp = strtol(p + 1, NULL, 10);
332     *p = 0;
333     }
334 matty 10
335 astrand 289 if (!username_option)
336 matty 10 {
337     pw = getpwuid(getuid());
338     if ((pw == NULL) || (pw->pw_name == NULL))
339     {
340 matty 30 error("could not determine username, use -u\n");
341 matty 10 return 1;
342     }
343    
344 matty 30 STRNCPY(username, pw->pw_name, sizeof(username));
345 matty 10 }
346    
347     if (hostname[0] == 0)
348     {
349 matty 30 if (gethostname(fullhostname, sizeof(fullhostname)) == -1)
350 matty 10 {
351 matty 30 error("could not determine local hostname, use -n\n");
352 matty 10 return 1;
353     }
354 matty 30
355     p = strchr(fullhostname, '.');
356     if (p != NULL)
357     *p = 0;
358    
359     STRNCPY(hostname, fullhostname, sizeof(hostname));
360 matty 10 }
361    
362 matthewc 211 if (prompt_password && read_password(password, sizeof(password)))
363     flags |= RDP_LOGON_AUTO;
364 matty 30
365 matthewc 211 if (title[0] == 0)
366 astrand 107 {
367     strcpy(title, "rdesktop - ");
368     strncat(title, server, sizeof(title) - sizeof("rdesktop - "));
369     }
370 matty 12
371 astrand 333 #ifdef RDP2VNC
372     rdp2vnc_connect(server, flags, domain, password, shell, directory);
373 forsberg 424 return 0;
374 astrand 333 #else
375    
376 astrand 82 if (!ui_init())
377     return 1;
378 astrand 66
379 forsberg 416 ipc_init(); // Must be run after ui_init, we need X to be setup.
380    
381     if (use_rdp5)
382     cliprdr_init(); // FIXME: Should perhaps be integrated into the channel management code?
383    
384 matthewc 53 if (!rdp_connect(server, flags, domain, password, shell, directory))
385     return 1;
386    
387 forsberg 427 /* By setting encryption to False here, we have an encrypted login
388     packet but unencrypted transfer of other packets */
389     if (!packet_encryption)
390     encryption = False;
391    
392    
393 matthewc 122 DEBUG(("Connection successful.\n"));
394 matthewc 211 memset(password, 0, sizeof(password));
395 matthewc 53
396 jsorg71 100 if (ui_create_window())
397 matty 10 {
398 forsberg 424 rdp_retval = rdp_main_loop();
399 matty 10 ui_destroy_window();
400     }
401    
402 matthewc 122 DEBUG(("Disconnecting...\n"));
403 matthewc 53 rdp_disconnect();
404 matthewc 188 ui_deinit();
405 astrand 333
406 forsberg 424 if (True == rdp_retval)
407     return 0;
408     else
409     return 2;
410    
411 astrand 333 #endif
412    
413 matty 10 }
414    
415 matthewc 220 #ifdef EGD_SOCKET
416     /* Read 32 random bytes from PRNGD or EGD socket (based on OpenSSL RAND_egd) */
417     static BOOL
418     generate_random_egd(uint8 * buf)
419     {
420     struct sockaddr_un addr;
421     BOOL ret = False;
422     int fd;
423    
424     fd = socket(AF_UNIX, SOCK_STREAM, 0);
425     if (fd == -1)
426     return False;
427    
428     addr.sun_family = AF_UNIX;
429     memcpy(addr.sun_path, EGD_SOCKET, sizeof(EGD_SOCKET));
430 astrand 259 if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
431 matthewc 220 goto err;
432    
433     /* PRNGD and EGD use a simple communications protocol */
434 astrand 259 buf[0] = 1; /* Non-blocking (similar to /dev/urandom) */
435     buf[1] = 32; /* Number of requested random bytes */
436 matthewc 220 if (write(fd, buf, 2) != 2)
437     goto err;
438    
439 astrand 259 if ((read(fd, buf, 1) != 1) || (buf[0] == 0)) /* Available? */
440 matthewc 220 goto err;
441    
442     if (read(fd, buf, 32) != 32)
443     goto err;
444    
445     ret = True;
446    
447 astrand 259 err:
448 matthewc 220 close(fd);
449     return ret;
450     }
451     #endif
452    
453 matty 10 /* Generate a 32-byte random for the secure transport code. */
454 matty 25 void
455 astrand 64 generate_random(uint8 * random)
456 matty 10 {
457     struct stat st;
458 matty 22 struct tms tmsbuf;
459 matthewc 220 MD5_CTX md5;
460     uint32 *r;
461     int fd, n;
462 matty 10
463 matthewc 220 /* If we have a kernel random device, try that first */
464 matty 30 if (((fd = open("/dev/urandom", O_RDONLY)) != -1)
465     || ((fd = open("/dev/random", O_RDONLY)) != -1))
466 matty 10 {
467 matthewc 220 n = read(fd, random, 32);
468 matty 10 close(fd);
469 matthewc 220 if (n == 32)
470     return;
471 matty 10 }
472    
473 matthewc 220 #ifdef EGD_SOCKET
474     /* As a second preference use an EGD */
475     if (generate_random_egd(random))
476     return;
477     #endif
478    
479 matty 10 /* Otherwise use whatever entropy we can gather - ideas welcome. */
480 astrand 259 r = (uint32 *) random;
481 matty 10 r[0] = (getpid()) | (getppid() << 16);
482     r[1] = (getuid()) | (getgid() << 16);
483 matty 24 r[2] = times(&tmsbuf); /* system uptime (clocks) */
484     gettimeofday((struct timeval *) &r[3], NULL); /* sec and usec */
485 matty 10 stat("/tmp", &st);
486     r[5] = st.st_atime;
487     r[6] = st.st_mtime;
488     r[7] = st.st_ctime;
489 matthewc 220
490     /* Hash both halves with MD5 to obscure possible patterns */
491     MD5_Init(&md5);
492 astrand 259 MD5_Update(&md5, random, 16);
493 matthewc 220 MD5_Final(random, &md5);
494 astrand 259 MD5_Update(&md5, random + 16, 16);
495     MD5_Final(random + 16, &md5);
496 matty 10 }
497    
498     /* malloc; exit if out of memory */
499 matty 25 void *
500     xmalloc(int size)
501 matty 10 {
502     void *mem = malloc(size);
503     if (mem == NULL)
504     {
505 matty 30 error("xmalloc %d\n", size);
506 matty 10 exit(1);
507     }
508     return mem;
509     }
510    
511     /* realloc; exit if out of memory */
512 matty 25 void *
513     xrealloc(void *oldmem, int size)
514 matty 10 {
515     void *mem = realloc(oldmem, size);
516     if (mem == NULL)
517     {
518 matty 30 error("xrealloc %d\n", size);
519 matty 10 exit(1);
520     }
521     return mem;
522     }
523    
524     /* free */
525 matty 25 void
526     xfree(void *mem)
527 matty 10 {
528     free(mem);
529     }
530    
531 matty 30 /* report an error */
532 matty 25 void
533 matty 30 error(char *format, ...)
534     {
535     va_list ap;
536    
537     fprintf(stderr, "ERROR: ");
538    
539     va_start(ap, format);
540     vfprintf(stderr, format, ap);
541     va_end(ap);
542     }
543    
544 matthewc 297 /* report a warning */
545     void
546     warning(char *format, ...)
547     {
548     va_list ap;
549    
550     fprintf(stderr, "WARNING: ");
551    
552     va_start(ap, format);
553     vfprintf(stderr, format, ap);
554     va_end(ap);
555     }
556    
557 matty 30 /* report an unimplemented protocol feature */
558     void
559     unimpl(char *format, ...)
560     {
561     va_list ap;
562    
563     fprintf(stderr, "NOT IMPLEMENTED: ");
564    
565     va_start(ap, format);
566     vfprintf(stderr, format, ap);
567     va_end(ap);
568     }
569    
570     /* produce a hex dump */
571     void
572 jsorg71 376 hexdump(unsigned char *p, int len)
573 matty 10 {
574     unsigned char *line = p;
575 jsorg71 376 int i, thisline, offset = 0;
576 matty 10
577     while (offset < len)
578     {
579 matthewc 169 printf("%04x ", offset);
580 matty 10 thisline = len - offset;
581     if (thisline > 16)
582     thisline = 16;
583    
584     for (i = 0; i < thisline; i++)
585 matthewc 169 printf("%02x ", line[i]);
586 matty 10
587 matty 30 for (; i < 16; i++)
588 matthewc 169 printf(" ");
589 matty 30
590 matty 10 for (i = 0; i < thisline; i++)
591 matthewc 169 printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.');
592 matty 10
593 matthewc 169 printf("\n");
594 matty 10 offset += thisline;
595     line += thisline;
596     }
597     }
598 astrand 325
599    
600     int
601     load_licence(unsigned char **data)
602     {
603 matthewc 367 char *home, *path;
604 astrand 325 struct stat st;
605 matthewc 367 int fd, length;
606 astrand 325
607     home = getenv("HOME");
608     if (home == NULL)
609     return -1;
610    
611 forsberg 416 path = (char *) xmalloc(strlen(home) + strlen(hostname) + sizeof("/.rdesktop/licence."));
612 astrand 325 sprintf(path, "%s/.rdesktop/licence.%s", home, hostname);
613    
614     fd = open(path, O_RDONLY);
615     if (fd == -1)
616     return -1;
617    
618     if (fstat(fd, &st))
619     return -1;
620    
621 forsberg 416 *data = (uint8 *) xmalloc(st.st_size);
622 matthewc 367 length = read(fd, *data, st.st_size);
623     close(fd);
624     xfree(path);
625     return length;
626 astrand 325 }
627    
628     void
629     save_licence(unsigned char *data, int length)
630     {
631 matthewc 367 char *home, *path, *tmppath;
632     int fd;
633 astrand 325
634     home = getenv("HOME");
635     if (home == NULL)
636     return;
637    
638 forsberg 416 path = (char *) xmalloc(strlen(home) + strlen(hostname) + sizeof("/.rdesktop/licence."));
639 astrand 325
640 matthewc 367 sprintf(path, "%s/.rdesktop", home);
641     if ((mkdir(path, 0700) == -1) && errno != EEXIST)
642 astrand 325 {
643 matthewc 367 perror(path);
644     return;
645 astrand 325 }
646    
647 matthewc 367 /* write licence to licence.hostname.new, then atomically rename to licence.hostname */
648 astrand 325
649 matthewc 367 sprintf(path, "%s/.rdesktop/licence.%s", home, hostname);
650 forsberg 416 tmppath = (char *) xmalloc(strlen(path) + sizeof(".new"));
651 matthewc 367 strcpy(tmppath, path);
652     strcat(tmppath, ".new");
653    
654 forsberg 416 fd = open(tmppath, O_WRONLY | O_CREAT | O_TRUNC, 0600);
655 matthewc 367 if (fd == -1)
656 astrand 325 {
657 matthewc 367 perror(tmppath);
658     return;
659 astrand 325 }
660    
661 matthewc 367 if (write(fd, data, length) != length)
662 astrand 325 {
663 matthewc 367 perror(tmppath);
664     unlink(tmppath);
665 astrand 325 }
666 matthewc 367 else if (rename(tmppath, path) == -1)
667 astrand 325 {
668 matthewc 367 perror(path);
669     unlink(tmppath);
670 astrand 325 }
671    
672 matthewc 367 close(fd);
673     xfree(tmppath);
674     xfree(path);
675 astrand 325 }

  ViewVC Help
Powered by ViewVC 1.1.26