/[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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 10 by matty, Tue Aug 15 10:23:24 2000 UTC revision 1042 by astrand, Tue Jan 24 12:40:24 2006 UTC
# Line 1  Line 1 
1  /*  /* -*- c-basic-offset: 8 -*-
2     rdesktop: A Remote Desktop Protocol client.     rdesktop: A Remote Desktop Protocol client.
3     Entrypoint and utility functions     Entrypoint and utility functions
4     Copyright (C) Matthew Chapman 1999-2000     Copyright (C) Matthew Chapman 1999-2005
5      
6     This program is free software; you can redistribute it and/or modify     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     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     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.     (at your option) any later version.
10      
11     This program is distributed in the hope that it will be useful,     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.     GNU General Public License for more details.
15      
16     You should have received a copy of the GNU General Public License     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */  */
20    
21  #include <stdlib.h>     /* malloc realloc free */  #include <stdarg.h>             /* va_list va_start va_end */
22  #include <unistd.h>     /* read close getuid getgid getpid getppid gethostname */  #include <unistd.h>             /* read close getuid getgid getpid getppid gethostname */
23  #include <fcntl.h>      /* open */  #include <fcntl.h>              /* open */
24  #include <getopt.h>     /* getopt */  #include <pwd.h>                /* getpwuid */
25  #include <pwd.h>        /* getpwuid */  #include <termios.h>            /* tcgetattr tcsetattr */
26  #include <sys/stat.h>   /* stat */  #include <sys/stat.h>           /* stat */
27  #include <sys/time.h>   /* gettimeofday */  #include <sys/time.h>           /* gettimeofday */
28  #include <sys/times.h>  /* times */  #include <sys/times.h>          /* times */
29    #include <ctype.h>              /* toupper */
30    #include <errno.h>
31  #include "rdesktop.h"  #include "rdesktop.h"
32    
33  char username[16];  #ifdef HAVE_LOCALE_H
34  char hostname[16];  #include <locale.h>
35  int width = 800;  #endif
36  int height = 600;  #ifdef HAVE_ICONV
37  int keylayout = 0x409;  #ifdef HAVE_LANGINFO_H
38  BOOL motion = False;  #include <langinfo.h>
39  BOOL orders = True;  #endif
40  BOOL licence = True;  #endif
41    
42    #ifdef EGD_SOCKET
43    #include <sys/types.h>
44    #include <sys/socket.h>         /* socket connect */
45    #include <sys/un.h>             /* sockaddr_un */
46    #endif
47    
48    #include <openssl/md5.h>
49    
50    char g_title[64] = "";
51    char g_username[64];
52    char g_hostname[16];
53    char g_keymapname[PATH_MAX] = "";
54    unsigned int g_keylayout = 0x409;       /* Defaults to US keyboard layout */
55    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    
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    int g_height = 600;
65    int g_xpos = 0;
66    int g_ypos = 0;
67    int g_pos = 0;                  /* 0 position unspecified,
68                                       1 specified,
69                                       2 xpos neg,
70                                       4 ypos neg  */
71    extern int g_tcp_port_rdp;
72    int g_server_depth = 8;
73    int g_win_button_size = 0;      /* If zero, disable single app mode */
74    BOOL g_bitmap_compression = True;
75    BOOL g_sendmotion = True;
76    BOOL g_bitmap_cache = True;
77    BOOL g_bitmap_cache_persist_enable = False;
78    BOOL g_bitmap_cache_precache = True;
79    BOOL g_encryption = True;
80    BOOL packet_encryption = True;
81    BOOL g_desktop_save = True;     /* desktop save order */
82    BOOL g_polygon_ellipse_orders = True;   /* polygon / ellipse orders */
83    BOOL g_fullscreen = False;
84    BOOL g_grab_keyboard = True;
85    BOOL g_hide_decorations = False;
86    BOOL g_use_rdp5 = True;
87    BOOL g_console_session = False;
88    BOOL g_numlock_sync = False;
89    BOOL g_owncolmap = False;
90    BOOL g_ownbackstore = True;     /* We can't rely on external BackingStore */
91    uint32 g_embed_wnd;
92    uint32 g_rdp5_performanceflags =
93            RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG | RDP5_NO_MENUANIMATIONS;
94    /* Session Directory redirection */
95    BOOL g_redirect = False;
96    char g_redirect_server[64];
97    char g_redirect_domain[16];
98    char g_redirect_password[64];
99    char g_redirect_username[64];
100    char g_redirect_cookie[128];
101    uint32 g_redirect_flags = 0;
102    
103    #ifdef WITH_RDPSND
104    BOOL g_rdpsnd = False;
105    #endif
106    
107    #ifdef HAVE_ICONV
108    char g_codepage[16] = "";
109    #endif
110    
111    extern RDPDR_DEVICE g_rdpdr_device[];
112    extern uint32 g_num_devices;
113    extern char *g_rdpdr_clientname;
114    
115    #ifdef RDP2VNC
116    extern int rfb_port;
117    extern int defer_time;
118    void
119    rdp2vnc_connect(char *server, uint32 flags, char *domain, char *password,
120                    char *shell, char *directory);
121    #endif
122  /* Display usage information */  /* Display usage information */
123  static void usage(char *program)  static void
124    usage(char *program)
125  {  {
126          STATUS("Usage: %s [options] server\n", program);          fprintf(stderr, "rdesktop: A Remote Desktop Protocol client.\n");
127          STATUS("   -u: user name\n");          fprintf(stderr, "Version " VERSION ". Copyright (C) 1999-2005 Matt Chapman.\n");
128          STATUS("   -n: client hostname\n");          fprintf(stderr, "See http://www.rdesktop.org/ for more information.\n\n");
129          STATUS("   -w: desktop width\n");  
130          STATUS("   -h: desktop height\n");          fprintf(stderr, "Usage: %s [options] server[:port]\n", program);
131          STATUS("   -k: keyboard layout (hex)\n");  #ifdef RDP2VNC
132          STATUS("   -m: send motion events\n");          fprintf(stderr, "   -V: vnc port\n");
133          STATUS("   -b: force bitmap updates\n");          fprintf(stderr, "   -Q: defer time (ms)\n");
134          STATUS("   -l: do not request licence\n\n");  #endif
135            fprintf(stderr, "   -u: user name\n");
136            fprintf(stderr, "   -d: domain\n");
137            fprintf(stderr, "   -s: shell\n");
138            fprintf(stderr, "   -c: working directory\n");
139            fprintf(stderr, "   -p: password (- to prompt)\n");
140            fprintf(stderr, "   -n: client hostname\n");
141            fprintf(stderr, "   -k: keyboard layout on server (en-us, de, sv, etc.)\n");
142            fprintf(stderr, "   -g: desktop geometry (WxH)\n");
143            fprintf(stderr, "   -f: full-screen mode\n");
144            fprintf(stderr, "   -b: force bitmap updates\n");
145    #ifdef HAVE_ICONV
146            fprintf(stderr, "   -L: local codepage\n");
147    #endif
148            fprintf(stderr, "   -B: use BackingStore of X-server (if available)\n");
149            fprintf(stderr, "   -e: disable encryption (French TS)\n");
150            fprintf(stderr, "   -E: disable encryption from client to server\n");
151            fprintf(stderr, "   -m: do not send motion events\n");
152            fprintf(stderr, "   -C: use private colour map\n");
153            fprintf(stderr, "   -D: hide window manager decorations\n");
154            fprintf(stderr, "   -K: keep window manager key bindings\n");
155            fprintf(stderr, "   -S: caption button size (single application mode)\n");
156            fprintf(stderr, "   -T: window title\n");
157            fprintf(stderr, "   -N: enable numlock syncronization\n");
158            fprintf(stderr, "   -X: embed into another window with a given id.\n");
159            fprintf(stderr, "   -a: connection colour depth\n");
160            fprintf(stderr, "   -z: enable rdp compression\n");
161            fprintf(stderr, "   -x: RDP5 experience (m[odem 28.8], b[roadband], l[an] or hex nr.)\n");
162            fprintf(stderr, "   -P: use persistent bitmap caching\n");
163            fprintf(stderr, "   -r: enable specified device redirection (this flag can be repeated)\n");
164            fprintf(stderr,
165                    "         '-r comport:COM1=/dev/ttyS0': enable serial redirection of /dev/ttyS0 to COM1\n");
166            fprintf(stderr, "             or      COM1=/dev/ttyS0,COM2=/dev/ttyS1\n");
167            fprintf(stderr,
168                    "         '-r disk:floppy=/mnt/floppy': enable redirection of /mnt/floppy to 'floppy' share\n");
169            fprintf(stderr, "             or   'floppy=/mnt/floppy,cdrom=/mnt/cdrom'\n");
170            fprintf(stderr, "         '-r clientname=<client name>': Set the client name displayed\n");
171            fprintf(stderr, "             for redirected disks\n");
172            fprintf(stderr,
173                    "         '-r lptport:LPT1=/dev/lp0': enable parallel redirection of /dev/lp0 to LPT1\n");
174            fprintf(stderr, "             or      LPT1=/dev/lp0,LPT2=/dev/lp1\n");
175            fprintf(stderr, "         '-r printer:mydeskjet': enable printer redirection\n");
176            fprintf(stderr,
177                    "             or      mydeskjet=\"HP LaserJet IIIP\" to enter server driver as well\n");
178            fprintf(stderr, "         '-r sound:[local|off|remote]': enable sound redirection\n");
179            fprintf(stderr, "                     remote would leave sound on server\n");
180            fprintf(stderr, "   -0: attach to console\n");
181            fprintf(stderr, "   -4: use RDP version 4\n");
182            fprintf(stderr, "   -5: use RDP version 5 (default)\n");
183    }
184    
185    static void
186    print_disconnect_reason(uint16 reason)
187    {
188            char *text;
189    
190            switch (reason)
191            {
192                    case exDiscReasonNoInfo:
193                            text = "No information available";
194                            break;
195    
196                    case exDiscReasonAPIInitiatedDisconnect:
197                            text = "Server initiated disconnect";
198                            break;
199    
200                    case exDiscReasonAPIInitiatedLogoff:
201                            text = "Server initiated logoff";
202                            break;
203    
204                    case exDiscReasonServerIdleTimeout:
205                            text = "Server idle timeout reached";
206                            break;
207    
208                    case exDiscReasonServerLogonTimeout:
209                            text = "Server logon timeout reached";
210                            break;
211    
212                    case exDiscReasonReplacedByOtherConnection:
213                            text = "The session was replaced";
214                            break;
215    
216                    case exDiscReasonOutOfMemory:
217                            text = "The server is out of memory";
218                            break;
219    
220                    case exDiscReasonServerDeniedConnection:
221                            text = "The server denied the connection";
222                            break;
223    
224                    case exDiscReasonServerDeniedConnectionFips:
225                            text = "The server denied the connection for security reason";
226                            break;
227    
228                    case exDiscReasonLicenseInternal:
229                            text = "Internal licensing error";
230                            break;
231    
232                    case exDiscReasonLicenseNoLicenseServer:
233                            text = "No license server available";
234                            break;
235    
236                    case exDiscReasonLicenseNoLicense:
237                            text = "No valid license available";
238                            break;
239    
240                    case exDiscReasonLicenseErrClientMsg:
241                            text = "Invalid licensing message";
242                            break;
243    
244                    case exDiscReasonLicenseHwidDoesntMatchLicense:
245                            text = "Hardware id doesn't match software license";
246                            break;
247    
248                    case exDiscReasonLicenseErrClientLicense:
249                            text = "Client license error";
250                            break;
251    
252                    case exDiscReasonLicenseCantFinishProtocol:
253                            text = "Network error during licensing protocol";
254                            break;
255    
256                    case exDiscReasonLicenseClientEndedProtocol:
257                            text = "Licensing protocol was not completed";
258                            break;
259    
260                    case exDiscReasonLicenseErrClientEncryption:
261                            text = "Incorrect client license enryption";
262                            break;
263    
264                    case exDiscReasonLicenseCantUpgradeLicense:
265                            text = "Can't upgrade license";
266                            break;
267    
268                    case exDiscReasonLicenseNoRemoteConnections:
269                            text = "The server is not licensed to accept remote connections";
270                            break;
271    
272                    default:
273                            if (reason > 0x1000 && reason < 0x7fff)
274                            {
275                                    text = "Internal protocol error";
276                            }
277                            else
278                            {
279                                    text = "Unknown reason";
280                            }
281            }
282            fprintf(stderr, "disconnect: %s.\n", text);
283    }
284    
285    static void
286    rdesktop_reset_state(void)
287    {
288            rdp_reset_state();
289    }
290    
291    static BOOL
292    read_password(char *password, int size)
293    {
294            struct termios tios;
295            BOOL ret = False;
296            int istty = 0;
297            char *p;
298    
299            if (tcgetattr(STDIN_FILENO, &tios) == 0)
300            {
301                    fprintf(stderr, "Password: ");
302                    tios.c_lflag &= ~ECHO;
303                    tcsetattr(STDIN_FILENO, TCSANOW, &tios);
304                    istty = 1;
305            }
306    
307            if (fgets(password, size, stdin) != NULL)
308            {
309                    ret = True;
310    
311                    /* strip final newline */
312                    p = strchr(password, '\n');
313                    if (p != NULL)
314                            *p = 0;
315            }
316    
317            if (istty)
318            {
319                    tios.c_lflag |= ECHO;
320                    tcsetattr(STDIN_FILENO, TCSANOW, &tios);
321                    fprintf(stderr, "\n");
322            }
323    
324            return ret;
325    }
326    
327    static void
328    parse_server_and_port(char *server)
329    {
330            char *p;
331    #ifdef IPv6
332            int addr_colons;
333    #endif
334    
335    #ifdef IPv6
336            p = server;
337            addr_colons = 0;
338            while (*p)
339                    if (*p++ == ':')
340                            addr_colons++;
341            if (addr_colons >= 2)
342            {
343                    /* numeric IPv6 style address format - [1:2:3::4]:port */
344                    p = strchr(server, ']');
345                    if (*server == '[' && p != NULL)
346                    {
347                            if (*(p + 1) == ':' && *(p + 2) != '\0')
348                                    g_tcp_port_rdp = strtol(p + 2, NULL, 10);
349                            /* remove the port number and brackets from the address */
350                            *p = '\0';
351                            strncpy(server, server + 1, strlen(server));
352                    }
353            }
354            else
355            {
356                    /* dns name or IPv4 style address format - server.example.com:port or 1.2.3.4:port */
357                    p = strchr(server, ':');
358                    if (p != NULL)
359                    {
360                            g_tcp_port_rdp = strtol(p + 1, NULL, 10);
361                            *p = 0;
362                    }
363            }
364    #else /* no IPv6 support */
365            p = strchr(server, ':');
366            if (p != NULL)
367            {
368                    g_tcp_port_rdp = strtol(p + 1, NULL, 10);
369                    *p = 0;
370            }
371    #endif /* IPv6 */
372    
373  }  }
374    
375  /* Client program */  /* Client program */
376  int main(int argc, char *argv[])  int
377    main(int argc, char *argv[])
378  {  {
379            char server[64];
380            char fullhostname[64];
381            char domain[16];
382            char password[64];
383            char shell[128];
384            char directory[32];
385            BOOL prompt_password, deactivated;
386          struct passwd *pw;          struct passwd *pw;
387          char *server;          uint32 flags, ext_disc_reason = 0;
388          char title[32];          char *p;
389          int c;          int c;
390            char *locale = NULL;
391            int username_option = 0;
392            int run_count = 0;      /* Session Directory support */
393            BOOL continue_connect = True;   /* Session Directory support */
394    
395    #ifdef HAVE_LOCALE_H
396            /* Set locale according to environment */
397            locale = setlocale(LC_ALL, "");
398            if (locale)
399            {
400                    locale = xstrdup(locale);
401            }
402    
403          STATUS("rdesktop: A Remote Desktop Protocol client.\n");  #endif
404          STATUS("Version "VERSION". Copyright (C) 1999-2000 Matt Chapman.\n\n");          flags = RDP_LOGON_NORMAL;
405            prompt_password = False;
406            domain[0] = password[0] = shell[0] = directory[0] = 0;
407            g_embed_wnd = 0;
408    
409            g_num_devices = 0;
410    
411    #ifdef RDP2VNC
412    #define VNCOPT "V:Q:"
413    #else
414    #define VNCOPT
415    #endif
416    
417          while ((c = getopt(argc, argv, "u:n:w:h:k:mbl?")) != -1)          while ((c = getopt(argc, argv,
418                               VNCOPT "u:L:d:s:c:p:n:k:g:fbBeEmzCDKS:T:NX:a:x:Pr:045h?")) != -1)
419          {          {
420                  switch (c)                  switch (c)
421                  {                  {
422    #ifdef RDP2VNC
423                            case 'V':
424                                    rfb_port = strtol(optarg, NULL, 10);
425                                    if (rfb_port < 100)
426                                            rfb_port += 5900;
427                                    break;
428    
429                            case 'Q':
430                                    defer_time = strtol(optarg, NULL, 10);
431                                    if (defer_time < 0)
432                                            defer_time = 0;
433                                    break;
434    #endif
435    
436                          case 'u':                          case 'u':
437                                  strncpy(username, optarg, sizeof(username));                                  STRNCPY(g_username, optarg, sizeof(g_username));
438                                    username_option = 1;
439                                  break;                                  break;
440    
441                          case 'n':                          case 'L':
442                                  strncpy(hostname, optarg, sizeof(hostname));  #ifdef HAVE_ICONV
443                                    STRNCPY(g_codepage, optarg, sizeof(g_codepage));
444    #else
445                                    error("iconv support not available\n");
446    #endif
447                                  break;                                  break;
448    
449                          case 'w':                          case 'd':
450                                  width = strtol(optarg, NULL, 10);                                  STRNCPY(domain, optarg, sizeof(domain));
451                                  break;                                  break;
452    
453                          case 'h':                          case 's':
454                                  height = strtol(optarg, NULL, 10);                                  STRNCPY(shell, optarg, sizeof(shell));
455                                    break;
456    
457                            case 'c':
458                                    STRNCPY(directory, optarg, sizeof(directory));
459                                    break;
460    
461                            case 'p':
462                                    if ((optarg[0] == '-') && (optarg[1] == 0))
463                                    {
464                                            prompt_password = True;
465                                            break;
466                                    }
467    
468                                    STRNCPY(password, optarg, sizeof(password));
469                                    flags |= RDP_LOGON_AUTO;
470    
471                                    /* try to overwrite argument so it won't appear in ps */
472                                    p = optarg;
473                                    while (*p)
474                                            *(p++) = 'X';
475                                    break;
476    
477                            case 'n':
478                                    STRNCPY(g_hostname, optarg, sizeof(g_hostname));
479                                  break;                                  break;
480    
481                          case 'k':                          case 'k':
482                                  keylayout = strtol(optarg, NULL, 16);                                  STRNCPY(g_keymapname, optarg, sizeof(g_keymapname));
483                                  break;                                  break;
484    
485                          case 'm':                          case 'g':
486                                  motion = True;                                  g_fullscreen = False;
487                                    if (!strcmp(optarg, "workarea"))
488                                    {
489                                            g_width = g_height = 0;
490                                            break;
491                                    }
492    
493                                    g_width = strtol(optarg, &p, 10);
494                                    if (g_width <= 0)
495                                    {
496                                            error("invalid geometry\n");
497                                            return 1;
498                                    }
499    
500                                    if (*p == 'x')
501                                            g_height = strtol(p + 1, &p, 10);
502    
503                                    if (g_height <= 0)
504                                    {
505                                            error("invalid geometry\n");
506                                            return 1;
507                                    }
508    
509                                    if (*p == '%')
510                                    {
511                                            g_width = -g_width;
512                                            p++;
513                                    }
514    
515                                    if (*p == '+' || *p == '-')
516                                    {
517                                            g_pos |= (*p == '-') ? 2 : 1;
518                                            g_xpos = strtol(p, &p, 10);
519    
520                                    }
521                                    if (*p == '+' || *p == '-')
522                                    {
523                                            g_pos |= (*p == '-') ? 4 : 1;
524                                            g_ypos = strtol(p, NULL, 10);
525                                    }
526    
527                                    break;
528    
529                            case 'f':
530                                    g_fullscreen = True;
531                                  break;                                  break;
532    
533                          case 'b':                          case 'b':
534                                  orders = False;                                  g_bitmap_cache = False;
535                                    break;
536    
537                            case 'B':
538                                    g_ownbackstore = False;
539                                    break;
540    
541                            case 'e':
542                                    g_encryption = False;
543                                    break;
544                            case 'E':
545                                    packet_encryption = False;
546                                    break;
547                            case 'm':
548                                    g_sendmotion = False;
549                                    break;
550    
551                            case 'C':
552                                    g_owncolmap = True;
553                                    break;
554    
555                            case 'D':
556                                    g_hide_decorations = True;
557                                    break;
558    
559                            case 'K':
560                                    g_grab_keyboard = False;
561                                  break;                                  break;
562    
563                          case 'l':                          case 'S':
564                                  licence = False;                                  if (!strcmp(optarg, "standard"))
565                                    {
566                                            g_win_button_size = 18;
567                                            break;
568                                    }
569    
570                                    g_win_button_size = strtol(optarg, &p, 10);
571    
572                                    if (*p)
573                                    {
574                                            error("invalid button size\n");
575                                            return 1;
576                                    }
577    
578                                    break;
579    
580                            case 'T':
581                                    STRNCPY(g_title, optarg, sizeof(g_title));
582                                    break;
583    
584                            case 'N':
585                                    g_numlock_sync = True;
586                                  break;                                  break;
587    
588                            case 'X':
589                                    g_embed_wnd = strtol(optarg, NULL, 0);
590                                    break;
591    
592                            case 'a':
593                                    g_server_depth = strtol(optarg, NULL, 10);
594                                    if (g_server_depth != 8 &&
595                                        g_server_depth != 16 &&
596                                        g_server_depth != 15 && g_server_depth != 24)
597                                    {
598                                            error("Invalid server colour depth.\n");
599                                            return 1;
600                                    }
601                                    break;
602    
603                            case 'z':
604                                    DEBUG(("rdp compression enabled\n"));
605                                    flags |= (RDP_LOGON_COMPRESSION | RDP_LOGON_COMPRESSION2);
606                                    break;
607    
608                            case 'x':
609                                    if (str_startswith(optarg, "m"))        /* modem */
610                                    {
611                                            g_rdp5_performanceflags =
612                                                    RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG |
613                                                    RDP5_NO_MENUANIMATIONS | RDP5_NO_THEMING;
614                                    }
615                                    else if (str_startswith(optarg, "b"))   /* broadband */
616                                    {
617                                            g_rdp5_performanceflags = RDP5_NO_WALLPAPER;
618                                    }
619                                    else if (str_startswith(optarg, "l"))   /* lan */
620                                    {
621                                            g_rdp5_performanceflags = RDP5_DISABLE_NOTHING;
622                                    }
623                                    else
624                                    {
625                                            g_rdp5_performanceflags = strtol(optarg, NULL, 16);
626                                    }
627                                    break;
628    
629                            case 'P':
630                                    g_bitmap_cache_persist_enable = True;
631                                    break;
632    
633                            case 'r':
634    
635                                    if (str_startswith(optarg, "sound"))
636                                    {
637                                            optarg += 5;
638    
639                                            if (*optarg == ':')
640                                            {
641                                                    *optarg++;
642                                                    while ((p = next_arg(optarg, ',')))
643                                                    {
644                                                            if (str_startswith(optarg, "remote"))
645                                                                    flags |= RDP_LOGON_LEAVE_AUDIO;
646    
647                                                            if (str_startswith(optarg, "local"))
648    #ifdef WITH_RDPSND
649                                                                    g_rdpsnd = True;
650    #else
651                                                                    warning("Not compiled with sound support\n");
652    #endif
653    
654                                                            if (str_startswith(optarg, "off"))
655    #ifdef WITH_RDPSND
656                                                                    g_rdpsnd = False;
657    #else
658                                                                    warning("Not compiled with sound support\n");
659    #endif
660    
661                                                            optarg = p;
662                                                    }
663                                            }
664                                            else
665                                            {
666    #ifdef WITH_RDPSND
667                                                    g_rdpsnd = True;
668    #else
669                                                    warning("Not compiled with sound support\n");
670    #endif
671                                            }
672                                    }
673                                    else if (str_startswith(optarg, "disk"))
674                                    {
675                                            /* -r disk:h:=/mnt/floppy */
676                                            disk_enum_devices(&g_num_devices, optarg + 4);
677                                    }
678                                    else if (str_startswith(optarg, "comport"))
679                                    {
680                                            serial_enum_devices(&g_num_devices, optarg + 7);
681                                    }
682                                    else if (str_startswith(optarg, "lptport"))
683                                    {
684                                            parallel_enum_devices(&g_num_devices, optarg + 7);
685                                    }
686                                    else if (str_startswith(optarg, "printer"))
687                                    {
688                                            printer_enum_devices(&g_num_devices, optarg + 7);
689                                    }
690                                    else if (str_startswith(optarg, "clientname"))
691                                    {
692                                            g_rdpdr_clientname = xmalloc(strlen(optarg + 11) + 1);
693                                            strcpy(g_rdpdr_clientname, optarg + 11);
694                                    }
695                                    else
696                                    {
697                                            warning("Unknown -r argument\n\n\tPossible arguments are: comport, disk, lptport, printer, sound\n");
698                                    }
699                                    break;
700    
701                            case '0':
702                                    g_console_session = True;
703                                    break;
704    
705                            case '4':
706                                    g_use_rdp5 = False;
707                                    break;
708    
709                            case '5':
710                                    g_use_rdp5 = True;
711                                    break;
712    
713                            case 'h':
714                          case '?':                          case '?':
715                          default:                          default:
716                                  usage(argv[0]);                                  usage(argv[0]);
# Line 105  int main(int argc, char *argv[]) Line 718  int main(int argc, char *argv[])
718                  }                  }
719          }          }
720    
721          if (argc - optind < 1)          if (argc - optind != 1)
722          {          {
723                  usage(argv[0]);                  usage(argv[0]);
724                  return 1;                  return 1;
725          }          }
726    
727          server = argv[optind];          STRNCPY(server, argv[optind], sizeof(server));
728            parse_server_and_port(server);
729    
730          if (username[0] == 0)          if (!username_option)
731          {          {
732                  pw = getpwuid(getuid());                  pw = getpwuid(getuid());
733                  if ((pw == NULL) || (pw->pw_name == NULL))                  if ((pw == NULL) || (pw->pw_name == NULL))
734                  {                  {
735                          STATUS("Could not determine user name.\n");                          error("could not determine username, use -u\n");
736                          return 1;                          return 1;
737                  }                  }
738    
739                  strncpy(username, pw->pw_name, sizeof(username));                  STRNCPY(g_username, pw->pw_name, sizeof(g_username));
740            }
741    
742    #ifdef HAVE_ICONV
743            if (g_codepage[0] == 0)
744            {
745                    if (setlocale(LC_CTYPE, ""))
746                    {
747                            STRNCPY(g_codepage, nl_langinfo(CODESET), sizeof(g_codepage));
748                    }
749                    else
750                    {
751                            STRNCPY(g_codepage, DEFAULT_CODEPAGE, sizeof(g_codepage));
752                    }
753          }          }
754    #endif
755    
756          if (hostname[0] == 0)          if (g_hostname[0] == 0)
757          {          {
758                  if (gethostname(hostname, sizeof(hostname)) == -1)                  if (gethostname(fullhostname, sizeof(fullhostname)) == -1)
759                  {                  {
760                          STATUS("Could not determine host name.\n");                          error("could not determine local hostname, use -n\n");
761                          return 1;                          return 1;
762                  }                  }
763    
764                    p = strchr(fullhostname, '.');
765                    if (p != NULL)
766                            *p = 0;
767    
768                    STRNCPY(g_hostname, fullhostname, sizeof(g_hostname));
769          }          }
770    
771          if (!rdp_connect(server))          if (g_keymapname[0] == 0)
772                  return 1;          {
773                    if (locale && xkeymap_from_locale(locale))
774                    {
775                            fprintf(stderr, "Autoselected keyboard map %s\n", g_keymapname);
776                    }
777                    else
778                    {
779                            STRNCPY(g_keymapname, "en-us", sizeof(g_keymapname));
780                    }
781            }
782            if (locale)
783                    xfree(locale);
784    
785    
786          STATUS("Connection successful.\n");          if (prompt_password && read_password(password, sizeof(password)))
787                    flags |= RDP_LOGON_AUTO;
788    
789          snprintf(title, sizeof(title), "rdesktop - %s", server);          if (g_title[0] == 0)
         if (ui_create_window(title))  
790          {          {
791                  rdp_main_loop();                  strcpy(g_title, "rdesktop - ");
792                  ui_destroy_window();                  strncat(g_title, server, sizeof(g_title) - sizeof("rdesktop - "));
793          }          }
794    
795          rdp_disconnect();  #ifdef RDP2VNC
796            rdp2vnc_connect(server, flags, domain, password, shell, directory);
797          return 0;          return 0;
798    #else
799    
800            if (!ui_init())
801                    return 1;
802    
803    #ifdef WITH_RDPSND
804            if (g_rdpsnd)
805                    rdpsnd_init();
806    #endif
807            rdpdr_init();
808    
809            while (run_count < 2 && continue_connect)       /* add support for Session Directory; only reconnect once */
810            {
811                    if (run_count == 0)
812                    {
813                            if (!rdp_connect(server, flags, domain, password, shell, directory))
814                                    return 1;
815                    }
816                    else if (!rdp_reconnect
817                             (server, flags, domain, password, shell, directory, g_redirect_cookie))
818                            return 1;
819    
820                    /* By setting encryption to False here, we have an encrypted login
821                       packet but unencrypted transfer of other packets */
822                    if (!packet_encryption)
823                            g_encryption = False;
824    
825    
826                    DEBUG(("Connection successful.\n"));
827                    memset(password, 0, sizeof(password));
828    
829                    if (run_count == 0)
830                            if (!ui_create_window())
831                                    continue_connect = False;
832    
833                    if (continue_connect)
834                            rdp_main_loop(&deactivated, &ext_disc_reason);
835    
836                    DEBUG(("Disconnecting...\n"));
837                    rdp_disconnect();
838    
839                    if ((g_redirect == True) && (run_count == 0))   /* Support for Session Directory */
840                    {
841                            /* reset state of major globals */
842                            rdesktop_reset_state();
843    
844                            STRNCPY(domain, g_redirect_domain, sizeof(domain));
845                            STRNCPY(g_username, g_redirect_username, sizeof(g_username));
846                            STRNCPY(password, g_redirect_password, sizeof(password));
847                            STRNCPY(server, g_redirect_server, sizeof(server));
848                            flags |= RDP_LOGON_AUTO;
849    
850                            g_redirect = False;
851                    }
852                    else
853                    {
854                            continue_connect = False;
855                            ui_destroy_window();
856                            break;
857                    }
858    
859                    run_count++;
860            }
861    
862            cache_save_state();
863            ui_deinit();
864    
865            if (ext_disc_reason >= 2)
866                    print_disconnect_reason(ext_disc_reason);
867    
868            if (deactivated)
869            {
870                    /* clean disconnect */
871                    return 0;
872            }
873            else
874            {
875                    if (ext_disc_reason == exDiscReasonAPIInitiatedDisconnect
876                        || ext_disc_reason == exDiscReasonAPIInitiatedLogoff)
877                    {
878                            /* not so clean disconnect, but nothing to worry about */
879                            return 0;
880                    }
881                    else
882                    {
883                            /* return error */
884                            return 2;
885                    }
886            }
887    
888    #endif
889    
890  }  }
891    
892  /* Generate a 32-byte random for the secure transport code. */  #ifdef EGD_SOCKET
893  void generate_random(uint8 *random)  /* Read 32 random bytes from PRNGD or EGD socket (based on OpenSSL RAND_egd) */
894    static BOOL
895    generate_random_egd(uint8 * buf)
896  {  {
897          struct stat st;          struct sockaddr_un addr;
898          uint32 *r = (uint32 *)random;          BOOL ret = False;
899          int fd;          int fd;
900    
901          /* If we have a kernel random device, use it. */          fd = socket(AF_UNIX, SOCK_STREAM, 0);
902          if ((fd = open("/dev/urandom", O_RDONLY)) != -1)          if (fd == -1)
903                    return False;
904    
905            addr.sun_family = AF_UNIX;
906            memcpy(addr.sun_path, EGD_SOCKET, sizeof(EGD_SOCKET));
907            if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
908                    goto err;
909    
910            /* PRNGD and EGD use a simple communications protocol */
911            buf[0] = 1;             /* Non-blocking (similar to /dev/urandom) */
912            buf[1] = 32;            /* Number of requested random bytes */
913            if (write(fd, buf, 2) != 2)
914                    goto err;
915    
916            if ((read(fd, buf, 1) != 1) || (buf[0] == 0))   /* Available? */
917                    goto err;
918    
919            if (read(fd, buf, 32) != 32)
920                    goto err;
921    
922            ret = True;
923    
924          err:
925            close(fd);
926            return ret;
927    }
928    #endif
929    
930    /* Generate a 32-byte random for the secure transport code. */
931    void
932    generate_random(uint8 * random)
933    {
934            struct stat st;
935            struct tms tmsbuf;
936            MD5_CTX md5;
937            uint32 *r;
938            int fd, n;
939    
940            /* If we have a kernel random device, try that first */
941            if (((fd = open("/dev/urandom", O_RDONLY)) != -1)
942                || ((fd = open("/dev/random", O_RDONLY)) != -1))
943          {          {
944                  read(fd, random, 32);                  n = read(fd, random, 32);
945                  close(fd);                  close(fd);
946                  return;                  if (n == 32)
947                            return;
948          }          }
949    
950    #ifdef EGD_SOCKET
951            /* As a second preference use an EGD */
952            if (generate_random_egd(random))
953                    return;
954    #endif
955    
956          /* Otherwise use whatever entropy we can gather - ideas welcome. */          /* Otherwise use whatever entropy we can gather - ideas welcome. */
957            r = (uint32 *) random;
958          r[0] = (getpid()) | (getppid() << 16);          r[0] = (getpid()) | (getppid() << 16);
959          r[1] = (getuid()) | (getgid() << 16);          r[1] = (getuid()) | (getgid() << 16);
960          r[2] = times(NULL); /* system uptime (clocks) */          r[2] = times(&tmsbuf);  /* system uptime (clocks) */
961          gettimeofday((struct timeval *)&r[3], NULL); /* sec and usec */          gettimeofday((struct timeval *) &r[3], NULL);   /* sec and usec */
962          stat("/tmp", &st);          stat("/tmp", &st);
963          r[5] = st.st_atime;          r[5] = st.st_atime;
964          r[6] = st.st_mtime;          r[6] = st.st_mtime;
965          r[7] = st.st_ctime;          r[7] = st.st_ctime;
966    
967            /* Hash both halves with MD5 to obscure possible patterns */
968            MD5_Init(&md5);
969            MD5_Update(&md5, random, 16);
970            MD5_Final(random, &md5);
971            MD5_Update(&md5, random + 16, 16);
972            MD5_Final(random + 16, &md5);
973  }  }
974    
975  /* malloc; exit if out of memory */  /* malloc; exit if out of memory */
976  void *xmalloc(int size)  void *
977    xmalloc(int size)
978  {  {
979          void *mem = malloc(size);          void *mem = malloc(size);
980          if (mem == NULL)          if (mem == NULL)
981          {          {
982                  ERROR("xmalloc %d\n", size);                  error("xmalloc %d\n", size);
983                    exit(1);
984            }
985            return mem;
986    }
987    
988    /* strdup */
989    char *
990    xstrdup(const char *s)
991    {
992            char *mem = strdup(s);
993            if (mem == NULL)
994            {
995                    perror("strdup");
996                  exit(1);                  exit(1);
997          }          }
998          return mem;          return mem;
999  }  }
1000    
1001  /* realloc; exit if out of memory */  /* realloc; exit if out of memory */
1002  void *xrealloc(void *oldmem, int size)  void *
1003    xrealloc(void *oldmem, int size)
1004  {  {
1005          void *mem = realloc(oldmem, size);          void *mem;
1006    
1007            if (size < 1)
1008                    size = 1;
1009            mem = realloc(oldmem, size);
1010          if (mem == NULL)          if (mem == NULL)
1011          {          {
1012                  ERROR("xrealloc %d\n", size);                  error("xrealloc %d\n", size);
1013                  exit(1);                  exit(1);
1014          }          }
1015          return mem;          return mem;
1016  }  }
1017    
1018  /* free */  /* free */
1019  void xfree(void *mem)  void
1020    xfree(void *mem)
1021  {  {
1022          free(mem);          free(mem);
1023  }  }
1024    
1025  /* Produce a hex dump */  /* report an error */
1026  void hexdump(unsigned char *p, unsigned int len)  void
1027    error(char *format, ...)
1028    {
1029            va_list ap;
1030    
1031            fprintf(stderr, "ERROR: ");
1032    
1033            va_start(ap, format);
1034            vfprintf(stderr, format, ap);
1035            va_end(ap);
1036    }
1037    
1038    /* report a warning */
1039    void
1040    warning(char *format, ...)
1041    {
1042            va_list ap;
1043    
1044            fprintf(stderr, "WARNING: ");
1045    
1046            va_start(ap, format);
1047            vfprintf(stderr, format, ap);
1048            va_end(ap);
1049    }
1050    
1051    /* report an unimplemented protocol feature */
1052    void
1053    unimpl(char *format, ...)
1054    {
1055            va_list ap;
1056    
1057            fprintf(stderr, "NOT IMPLEMENTED: ");
1058    
1059            va_start(ap, format);
1060            vfprintf(stderr, format, ap);
1061            va_end(ap);
1062    }
1063    
1064    /* produce a hex dump */
1065    void
1066    hexdump(unsigned char *p, unsigned int len)
1067  {  {
1068          unsigned char *line = p;          unsigned char *line = p;
1069          unsigned int thisline, offset = 0;          int i, thisline, offset = 0;
         int i;  
1070    
1071          while (offset < len)          while (offset < len)
1072          {          {
1073                  STATUS("%04x ", offset);                  printf("%04x ", offset);
1074                  thisline = len - offset;                  thisline = len - offset;
1075                  if (thisline > 16)                  if (thisline > 16)
1076                          thisline = 16;                          thisline = 16;
1077    
1078                  for (i = 0; i < thisline; i++)                  for (i = 0; i < thisline; i++)
1079                          STATUS("%02x ", line[i])                          printf("%02x ", line[i]);
1080    
1081                  for (; i < 16; i++)                  for (; i < 16; i++)
1082                          STATUS("   ");                          printf("   ");
1083    
1084                  for (i = 0; i < thisline; i++)                  for (i = 0; i < thisline; i++)
1085                          STATUS("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.');                          printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.');
1086    
1087                  STATUS("\n");                  printf("\n");
1088                  offset += thisline;                  offset += thisline;
1089                  line += thisline;                  line += thisline;
1090          }          }
1091  }  }
1092    
1093    /*
1094      input: src is the string we look in for needle.
1095             Needle may be escaped by a backslash, in
1096             that case we ignore that particular needle.
1097      return value: returns next src pointer, for
1098            succesive executions, like in a while loop
1099            if retval is 0, then there are no more args.
1100      pitfalls:
1101            src is modified. 0x00 chars are inserted to
1102            terminate strings.
1103            return val, points on the next val chr after ins
1104            0x00
1105    
1106            example usage:
1107            while( (pos = next_arg( optarg, ',')) ){
1108                    printf("%s\n",optarg);
1109                    optarg=pos;
1110            }
1111    
1112    */
1113    char *
1114    next_arg(char *src, char needle)
1115    {
1116            char *nextval;
1117            char *p;
1118            char *mvp = 0;
1119    
1120            /* EOS */
1121            if (*src == (char) 0x00)
1122                    return 0;
1123    
1124            p = src;
1125            /*  skip escaped needles */
1126            while ((nextval = strchr(p, needle)))
1127            {
1128                    mvp = nextval - 1;
1129                    /* found backslashed needle */
1130                    if (*mvp == '\\' && (mvp > src))
1131                    {
1132                            /* move string one to the left */
1133                            while (*(mvp + 1) != (char) 0x00)
1134                            {
1135                                    *mvp = *(mvp + 1);
1136                                    *mvp++;
1137                            }
1138                            *mvp = (char) 0x00;
1139                            p = nextval;
1140                    }
1141                    else
1142                    {
1143                            p = nextval + 1;
1144                            break;
1145                    }
1146    
1147            }
1148    
1149            /* more args available */
1150            if (nextval)
1151            {
1152                    *nextval = (char) 0x00;
1153                    return ++nextval;
1154            }
1155    
1156            /* no more args after this, jump to EOS */
1157            nextval = src + strlen(src);
1158            return nextval;
1159    }
1160    
1161    
1162    void
1163    toupper_str(char *p)
1164    {
1165            while (*p)
1166            {
1167                    if ((*p >= 'a') && (*p <= 'z'))
1168                            *p = toupper((int) *p);
1169                    p++;
1170            }
1171    }
1172    
1173    
1174    BOOL
1175    str_startswith(const char *s, const char *prefix)
1176    {
1177            return (strncmp(s, prefix, strlen(prefix)) == 0);
1178    }
1179    
1180    
1181    /* not all clibs got ltoa */
1182    #define LTOA_BUFSIZE (sizeof(long) * 8 + 1)
1183    
1184    char *
1185    l_to_a(long N, int base)
1186    {
1187            static char ret[LTOA_BUFSIZE];
1188    
1189            char *head = ret, buf[LTOA_BUFSIZE], *tail = buf + sizeof(buf);
1190    
1191            register int divrem;
1192    
1193            if (base < 36 || 2 > base)
1194                    base = 10;
1195    
1196            if (N < 0)
1197            {
1198                    *head++ = '-';
1199                    N = -N;
1200            }
1201    
1202            tail = buf + sizeof(buf);
1203            *--tail = 0;
1204    
1205            do
1206            {
1207                    divrem = N % base;
1208                    *--tail = (divrem <= 9) ? divrem + '0' : divrem + 'a' - 10;
1209                    N /= base;
1210            }
1211            while (N);
1212    
1213            strcpy(head, tail);
1214            return ret;
1215    }
1216    
1217    
1218    int
1219    load_licence(unsigned char **data)
1220    {
1221            char *home, *path;
1222            struct stat st;
1223            int fd, length;
1224    
1225            home = getenv("HOME");
1226            if (home == NULL)
1227                    return -1;
1228    
1229            path = (char *) xmalloc(strlen(home) + strlen(g_hostname) + sizeof("/.rdesktop/licence."));
1230            sprintf(path, "%s/.rdesktop/licence.%s", home, g_hostname);
1231    
1232            fd = open(path, O_RDONLY);
1233            if (fd == -1)
1234                    return -1;
1235    
1236            if (fstat(fd, &st))
1237                    return -1;
1238    
1239            *data = (uint8 *) xmalloc(st.st_size);
1240            length = read(fd, *data, st.st_size);
1241            close(fd);
1242            xfree(path);
1243            return length;
1244    }
1245    
1246    void
1247    save_licence(unsigned char *data, int length)
1248    {
1249            char *home, *path, *tmppath;
1250            int fd;
1251    
1252            home = getenv("HOME");
1253            if (home == NULL)
1254                    return;
1255    
1256            path = (char *) xmalloc(strlen(home) + strlen(g_hostname) + sizeof("/.rdesktop/licence."));
1257    
1258            sprintf(path, "%s/.rdesktop", home);
1259            if ((mkdir(path, 0700) == -1) && errno != EEXIST)
1260            {
1261                    perror(path);
1262                    return;
1263            }
1264    
1265            /* write licence to licence.hostname.new, then atomically rename to licence.hostname */
1266    
1267            sprintf(path, "%s/.rdesktop/licence.%s", home, g_hostname);
1268            tmppath = (char *) xmalloc(strlen(path) + sizeof(".new"));
1269            strcpy(tmppath, path);
1270            strcat(tmppath, ".new");
1271    
1272            fd = open(tmppath, O_WRONLY | O_CREAT | O_TRUNC, 0600);
1273            if (fd == -1)
1274            {
1275                    perror(tmppath);
1276                    return;
1277            }
1278    
1279            if (write(fd, data, length) != length)
1280            {
1281                    perror(tmppath);
1282                    unlink(tmppath);
1283            }
1284            else if (rename(tmppath, path) == -1)
1285            {
1286                    perror(path);
1287                    unlink(tmppath);
1288            }
1289    
1290            close(fd);
1291            xfree(tmppath);
1292            xfree(path);
1293    }
1294    
1295    /* Create the bitmap cache directory */
1296    BOOL
1297    rd_pstcache_mkdir(void)
1298    {
1299            char *home;
1300            char bmpcache_dir[256];
1301    
1302            home = getenv("HOME");
1303    
1304            if (home == NULL)
1305                    return False;
1306    
1307            sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop");
1308    
1309            if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST)
1310            {
1311                    perror(bmpcache_dir);
1312                    return False;
1313            }
1314    
1315            sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop/cache");
1316    
1317            if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST)
1318            {
1319                    perror(bmpcache_dir);
1320                    return False;
1321            }
1322    
1323            return True;
1324    }
1325    
1326    /* open a file in the .rdesktop directory */
1327    int
1328    rd_open_file(char *filename)
1329    {
1330            char *home;
1331            char fn[256];
1332            int fd;
1333    
1334            home = getenv("HOME");
1335            if (home == NULL)
1336                    return -1;
1337            sprintf(fn, "%s/.rdesktop/%s", home, filename);
1338            fd = open(fn, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
1339            if (fd == -1)
1340                    perror(fn);
1341            return fd;
1342    }
1343    
1344    /* close file */
1345    void
1346    rd_close_file(int fd)
1347    {
1348            close(fd);
1349    }
1350    
1351    /* read from file*/
1352    int
1353    rd_read_file(int fd, void *ptr, int len)
1354    {
1355            return read(fd, ptr, len);
1356    }
1357    
1358    /* write to file */
1359    int
1360    rd_write_file(int fd, void *ptr, int len)
1361    {
1362            return write(fd, ptr, len);
1363    }
1364    
1365    /* move file pointer */
1366    int
1367    rd_lseek_file(int fd, int offset)
1368    {
1369            return lseek(fd, offset, SEEK_SET);
1370    }
1371    
1372    /* do a write lock on a file */
1373    BOOL
1374    rd_lock_file(int fd, int start, int len)
1375    {
1376            struct flock lock;
1377    
1378            lock.l_type = F_WRLCK;
1379            lock.l_whence = SEEK_SET;
1380            lock.l_start = start;
1381            lock.l_len = len;
1382            if (fcntl(fd, F_SETLK, &lock) == -1)
1383                    return False;
1384            return True;
1385    }

Legend:
Removed from v.10  
changed lines
  Added in v.1042

  ViewVC Help
Powered by ViewVC 1.1.26