📄 rdesktop.c
字号:
/* -*- c-basic-offset: 8 -*-
rdesktop: A Remote Desktop Protocol client.
Entrypoint and utility functions
Copyright (C) Matthew Chapman 1999-2005
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdarg.h> /* va_list va_start va_end */
#include <unistd.h> /* read close getuid getgid getpid getppid gethostname */
#include <fcntl.h> /* open */
#include <pwd.h> /* getpwuid */
#include <termios.h> /* tcgetattr tcsetattr */
#include <sys/stat.h> /* stat */
#include <sys/time.h> /* gettimeofday */
#include <sys/times.h> /* times */
#include <ctype.h> /* toupper */
#include <errno.h>
#include "rdesktop.h"
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
#ifdef HAVE_ICONV
#ifdef HAVE_LANGINFO_H
#include <langinfo.h>
#endif
#endif
#ifdef EGD_SOCKET
#include <sys/types.h>
#include <sys/socket.h> /* socket connect */
#include <sys/un.h> /* sockaddr_un */
#endif
#include <openssl/md5.h>
#ifdef RDP2VNC
void
rdp2vnc_connect(char *server, uint32 flags, char *domain, char *password,
char *shell, char *directory);
#endif
/* Display usage information */
static void
usage(char *program)
{
fprintf(stderr, "rdesktop: A Remote Desktop Protocol client.\n");
fprintf(stderr, "Version " VERSION ". Copyright (C) 1999-2005 Matt Chapman.\n");
fprintf(stderr, "See http://www.rdesktop.org/ for more information.\n\n");
fprintf(stderr, "Usage: %s [options] server[:port]\n", program);
#ifdef RDP2VNC
fprintf(stderr, " -V: vnc port\n");
fprintf(stderr, " -Q: defer time (ms)\n");
#endif
fprintf(stderr, " -u: user name\n");
fprintf(stderr, " -d: domain\n");
fprintf(stderr, " -s: shell\n");
fprintf(stderr, " -c: working directory\n");
fprintf(stderr, " -p: password (- to prompt)\n");
fprintf(stderr, " -n: client hostname\n");
fprintf(stderr, " -k: keyboard layout on server (en-us, de, sv, etc.)\n");
fprintf(stderr, " -g: desktop geometry (WxH)\n");
fprintf(stderr, " -f: full-screen mode\n");
fprintf(stderr, " -b: force bitmap updates\n");
#ifdef HAVE_ICONV
fprintf(stderr, " -L: local codepage\n");
#endif
fprintf(stderr, " -A: enable SeamlessRDP mode\n");
fprintf(stderr, " -B: use BackingStore of X-server (if available)\n");
fprintf(stderr, " -e: disable encryption (French TS)\n");
fprintf(stderr, " -E: disable encryption from client to server\n");
fprintf(stderr, " -m: do not send motion events\n");
fprintf(stderr, " -C: use private colour map\n");
fprintf(stderr, " -D: hide window manager decorations\n");
fprintf(stderr, " -K: keep window manager key bindings\n");
fprintf(stderr, " -S: caption button size (single application mode)\n");
fprintf(stderr, " -T: window title\n");
fprintf(stderr, " -N: enable numlock syncronization\n");
fprintf(stderr, " -X: embed into another window with a given id.\n");
fprintf(stderr, " -a: connection colour depth\n");
fprintf(stderr, " -z: enable rdp compression\n");
fprintf(stderr, " -x: RDP5 experience (m[odem 28.8], b[roadband], l[an] or hex nr.)\n");
fprintf(stderr, " -P: use persistent bitmap caching\n");
fprintf(stderr, " -r: enable specified device redirection (this flag can be repeated)\n");
fprintf(stderr,
" '-r comport:COM1=/dev/ttyS0': enable serial redirection of /dev/ttyS0 to COM1\n");
fprintf(stderr, " or COM1=/dev/ttyS0,COM2=/dev/ttyS1\n");
fprintf(stderr,
" '-r disk:floppy=/mnt/floppy': enable redirection of /mnt/floppy to 'floppy' share\n");
fprintf(stderr, " or 'floppy=/mnt/floppy,cdrom=/mnt/cdrom'\n");
fprintf(stderr, " '-r clientname=<client name>': Set the client name displayed\n");
fprintf(stderr, " for redirected disks\n");
fprintf(stderr,
" '-r lptport:LPT1=/dev/lp0': enable parallel redirection of /dev/lp0 to LPT1\n");
fprintf(stderr, " or LPT1=/dev/lp0,LPT2=/dev/lp1\n");
fprintf(stderr, " '-r printer:mydeskjet': enable printer redirection\n");
fprintf(stderr,
" or mydeskjet=\"HP LaserJet IIIP\" to enter server driver as well\n");
fprintf(stderr, " '-r sound:[local|off|remote]': enable sound redirection\n");
fprintf(stderr, " remote would leave sound on server\n");
fprintf(stderr,
" '-r clipboard:[off|PRIMARYCLIPBOARD|CLIPBOARD]': enable clipboard\n");
fprintf(stderr, " redirection.\n");
fprintf(stderr,
" 'PRIMARYCLIPBOARD' looks at both PRIMARY and CLIPBOARD\n");
fprintf(stderr, " when sending data to server.\n");
fprintf(stderr, " 'CLIPBOARD' looks at only CLIPBOARD.\n");
fprintf(stderr, " -0: attach to console\n");
fprintf(stderr, " -4: use RDP version 4\n");
fprintf(stderr, " -5: use RDP version 5 (default)\n");
}
static void
print_disconnect_reason(uint16 reason)
{
char *text;
switch (reason)
{
case exDiscReasonNoInfo:
text = "No information available";
break;
case exDiscReasonAPIInitiatedDisconnect:
text = "Server initiated disconnect";
break;
case exDiscReasonAPIInitiatedLogoff:
text = "Server initiated logoff";
break;
case exDiscReasonServerIdleTimeout:
text = "Server idle timeout reached";
break;
case exDiscReasonServerLogonTimeout:
text = "Server logon timeout reached";
break;
case exDiscReasonReplacedByOtherConnection:
text = "The session was replaced";
break;
case exDiscReasonOutOfMemory:
text = "The server is out of memory";
break;
case exDiscReasonServerDeniedConnection:
text = "The server denied the connection";
break;
case exDiscReasonServerDeniedConnectionFips:
text = "The server denied the connection for security reason";
break;
case exDiscReasonLicenseInternal:
text = "Internal licensing error";
break;
case exDiscReasonLicenseNoLicenseServer:
text = "No license server available";
break;
case exDiscReasonLicenseNoLicense:
text = "No valid license available";
break;
case exDiscReasonLicenseErrClientMsg:
text = "Invalid licensing message";
break;
case exDiscReasonLicenseHwidDoesntMatchLicense:
text = "Hardware id doesn't match software license";
break;
case exDiscReasonLicenseErrClientLicense:
text = "Client license error";
break;
case exDiscReasonLicenseCantFinishProtocol:
text = "Network error during licensing protocol";
break;
case exDiscReasonLicenseClientEndedProtocol:
text = "Licensing protocol was not completed";
break;
case exDiscReasonLicenseErrClientEncryption:
text = "Incorrect client license enryption";
break;
case exDiscReasonLicenseCantUpgradeLicense:
text = "Can't upgrade license";
break;
case exDiscReasonLicenseNoRemoteConnections:
text = "The server is not licensed to accept remote connections";
break;
default:
if (reason > 0x1000 && reason < 0x7fff)
{
text = "Internal protocol error";
}
else
{
text = "Unknown reason";
}
}
fprintf(stderr, "disconnect: %s.\n", text);
}
static void
rdesktop_reset_state(RDPCLIENT * This)
{
rdp_reset_state(This);
}
static BOOL
read_password(char *password, int size)
{
struct termios tios;
BOOL ret = False;
int istty = 0;
char *p;
if (tcgetattr(STDIN_FILENO, &tios) == 0)
{
fprintf(stderr, "Password: ");
tios.c_lflag &= ~ECHO;
tcsetattr(STDIN_FILENO, TCSANOW, &tios);
istty = 1;
}
if (fgets(password, size, stdin) != NULL)
{
ret = True;
/* strip final newline */
p = strchr(password, '\n');
if (p != NULL)
*p = 0;
}
if (istty)
{
tios.c_lflag |= ECHO;
tcsetattr(STDIN_FILENO, TCSANOW, &tios);
fprintf(stderr, "\n");
}
return ret;
}
static void
parse_server_and_port(RDPCLIENT * This, char *server)
{
char *p;
#ifdef IPv6
int addr_colons;
#endif
#ifdef IPv6
p = server;
addr_colons = 0;
while (*p)
if (*p++ == ':')
addr_colons++;
if (addr_colons >= 2)
{
/* numeric IPv6 style address format - [1:2:3::4]:port */
p = strchr(server, ']');
if (*server == '[' && p != NULL)
{
if (*(p + 1) == ':' && *(p + 2) != '\0')
This->tcp_port_rdp = strtol(p + 2, NULL, 10);
/* remove the port number and brackets from the address */
*p = '\0';
strncpy(server, server + 1, strlen(server));
}
}
else
{
/* dns name or IPv4 style address format - server.example.com:port or 1.2.3.4:port */
p = strchr(server, ':');
if (p != NULL)
{
This->tcp_port_rdp = strtol(p + 1, NULL, 10);
*p = 0;
}
}
#else /* no IPv6 support */
p = strchr(server, ':');
if (p != NULL)
{
This->tcp_port_rdp = strtol(p + 1, NULL, 10);
*p = 0;
}
#endif /* IPv6 */
}
/* Client program */
int
main(int argc, char *argv[])
{
char server[64];
char fullhostname[64];
char domain[16];
char password[64];
char shell[256];
char directory[256];
BOOL prompt_password, deactivated;
struct passwd *pw;
uint32 flags, ext_disc_reason = 0;
char *p;
int c;
char *locale = NULL;
int username_option = 0;
BOOL geometry_option = False;
int run_count = 0; /* Session Directory support */
BOOL continue_connect = True; /* Session Directory support */
RDPCLIENT * This;
This = xmalloc(sizeof(RDPCLIENT));
memset(This, 0, sizeof(RDPCLIENT));
This->keylayout = 0x409; /* Defaults to US keyboard layout */
This->keyboard_type = 0x4; /* Defaults to US keyboard layout */
This->keyboard_subtype = 0x0; /* Defaults to US keyboard layout */
This->keyboard_functionkeys = 0xc; /* Defaults to US keyboard layout */
This->width = 800; /* width is special: If 0, the
geometry will be fetched from
_NET_WORKAREA. If negative,
absolute value specifies the
percent of the whole screen. */
This->height = 600;
This->server_depth = -1;
This->bitmap_compression = True;
This->sendmotion = True;
This->bitmap_cache = True;
This->bitmap_cache_persist_enable = False;
This->bitmap_cache_precache = True;
This->encryption = True;
This->packet_encryption = True;
This->desktop_save = True; /* desktop save order */
This->polygon_ellipse_orders = True; /* polygon / ellipse orders */
This->fullscreen = False;
This->grab_keyboard = True;
This->hide_decorations = False;
This->use_rdp5 = True;
This->rdpclip = True;
This->console_session = False;
This->numlock_sync = False;
This->lspci_enabled = False;
This->owncolmap = False;
This->ownbackstore = True; /* We can't rely on external BackingStore */
This->seamless_rdp = False;
This->rdp5_performanceflags = RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG | RDP5_NO_MENUANIMATIONS;
This->tcp_port_rdp = TCP_PORT_RDP;
#define NOT_SET -1
This->cache.bmpcache_lru[0] = NOT_SET;
This->cache.bmpcache_lru[1] = NOT_SET;
This->cache.bmpcache_lru[2] = NOT_SET;
This->cache.bmpcache_mru[0] = NOT_SET;
This->cache.bmpcache_mru[1] = NOT_SET;
This->cache.bmpcache_mru[2] = NOT_SET;
#ifdef HAVE_ICONV
This->rdp.iconv_works = True;
#endif
This->xclip.auto_mode = True;
#ifdef HAVE_LOCALE_H
/* Set locale according to environment */
locale = setlocale(LC_ALL, "");
if (locale)
{
locale = xstrdup(locale);
}
#endif
flags = RDP_LOGON_NORMAL;
prompt_password = False;
domain[0] = password[0] = shell[0] = directory[0] = 0;
This->embed_wnd = 0;
This->num_devices = 0;
#ifdef RDP2VNC
#define VNCOPT "V:Q:"
#else
#define VNCOPT
#endif
while ((c = getopt(argc, argv,
VNCOPT "Au:L:d:s:c:p:n:k:g:fbBeEmzCDKS:T:NX:a:x:Pr:045h?")) != -1)
{
switch (c)
{
#ifdef RDP2VNC
case 'V':
This->rfb_port = strtol(optarg, NULL, 10);
if (This->rfb_port < 100)
This->rfb_port += 5900;
break;
case 'Q':
This->defer_time = strtol(optarg, NULL, 10);
if (This->defer_time < 0)
This->defer_time = 0;
break;
#endif
case 'A':
This->seamless_rdp = True;
break;
case 'u':
STRNCPY(This->username, optarg, sizeof(This->username));
username_option = 1;
break;
case 'L':
#ifdef HAVE_ICONV
STRNCPY(This->codepage, optarg, sizeof(This->codepage));
#else
error("iconv support not available\n");
#endif
break;
case 'd':
STRNCPY(domain, optarg, sizeof(domain));
break;
case 's':
STRNCPY(shell, optarg, sizeof(shell));
break;
case 'c':
STRNCPY(directory, optarg, sizeof(directory));
break;
case 'p':
if ((optarg[0] == '-') && (optarg[1] == 0))
{
prompt_password = True;
break;
}
STRNCPY(password, optarg, sizeof(password));
flags |= RDP_LOGON_AUTO;
/* try to overwrite argument so it won't appear in ps */
p = optarg;
while (*p)
*(p++) = 'X';
break;
case 'n':
STRNCPY(This->hostname, optarg, sizeof(This->hostname));
break;
case 'k':
STRNCPY(This->keymapname, optarg, sizeof(This->keymapname));
break;
case 'g':
geometry_option = True;
This->fullscreen = False;
if (!strcmp(optarg, "workarea"))
{
This->width = This->height = 0;
break;
}
This->width = strtol(optarg, &p, 10);
if (This->width <= 0)
{
error("invalid geometry\n");
return 1;
}
if (*p == 'x')
This->height = strtol(p + 1, &p, 10);
if (This->height <= 0)
{
error("invalid geometry\n");
return 1;
}
if (*p == '%')
{
This->width = -This->width;
p++;
}
if (*p == '+' || *p == '-')
{
This->pos |= (*p == '-') ? 2 : 1;
This->xpos = strtol(p, &p, 10);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -