rdesktop.c revision 8484c4787af17f5d59803f389274826754bfc23b
/* -*- c-basic-offset: 8 -*-
rdesktop: A Remote Desktop Protocol client.
Entrypoint and utility functions
Copyright (C) Matthew Chapman 1999-2008
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.
*/
/*
* Sun GPL Disclaimer: For the avoidance of doubt, except that if any license choice
* other than GPL or LGPL is available it will apply instead, Sun elects to use only
* the General Public License version 2 (GPLv2) at this time for any software where
* a choice of GPL license versions is made available with the language indicating
* that GPLv2 or any later version may be used, or where a choice of which version
* of the GPL is applied is otherwise unspecified.
*/
#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 <ctype.h> /* toupper */
#include <errno.h>
#include "rdesktop.h"
#ifdef VBOX
#endif
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
#ifdef HAVE_ICONV
#ifdef HAVE_LANGINFO_H
#include <langinfo.h>
#endif
#endif
#ifdef EGD_SOCKET
#endif
#include "ssl.h"
char g_username[64];
char g_hostname[16];
geometry will be fetched from
_NET_WORKAREA. If negative,
absolute value specifies the
percent of the whole screen. */
int g_height = 600;
int g_xpos = 0;
int g_ypos = 0;
int g_pos = 0; /* 0 position unspecified,
1 specified,
2 xpos neg,
4 ypos neg */
extern int g_tcp_port_rdp;
int g_server_depth = -1;
int g_win_button_size = 0; /* If zero, disable single app mode */
#ifndef VBOX
#else /* VBOX */
/* Always use numlock synchronization with VRDP. */
#endif /* VBOX */
/* Session Directory redirection */
char g_redirect_server[64];
char g_redirect_domain[16];
char g_redirect_password[64];
char g_redirect_username[64];
char g_redirect_cookie[128];
uint32 g_redirect_flags = 0;
#ifdef WITH_RDPSND
#endif
#ifdef WITH_RDPUSB
#endif
#ifdef HAVE_ICONV
#endif
extern RDPDR_DEVICE g_rdpdr_device[];
extern uint32 g_num_devices;
extern char *g_rdpdr_clientname;
#ifdef RDP2VNC
extern int rfb_port;
extern int defer_time;
void
#endif
/* Display usage information */
static void
{
#ifdef VBOX
#endif
#ifdef RDP2VNC
#endif
#ifdef HAVE_ICONV
#endif
" or mydeskjet=\"HP LaserJet IIIP\" to enter server driver as well\n");
#ifdef WITH_RDPSND
" '-r sound:[local[:driver[:device]]|off|remote]': enable sound redirection\n");
#endif
#ifdef WITH_RDPUSB
" '-r usb': enable USB redirection\n");
#endif
" '-r clipboard:[off|PRIMARYCLIPBOARD|CLIPBOARD]': enable clipboard\n");
" 'PRIMARYCLIPBOARD' looks at both PRIMARY and CLIPBOARD\n");
#ifdef WITH_SCARD
" \"AKS ifdh 0\" -> Device shown in Windows enviroment \n");
" \"AKS ifdh 0\" -> Device shown in Windows enviroment \n");
" \"AKS\" -> Device vendor name \n");
#endif
}
static void
{
char *text;
switch (reason)
{
case exDiscReasonNoInfo:
text = "No information available";
break;
text = "Server initiated disconnect";
break;
text = "Server initiated logoff";
break;
text = "Server idle timeout reached";
break;
text = "Server logon timeout reached";
break;
text = "The session was replaced";
break;
case exDiscReasonOutOfMemory:
text = "The server is out of memory";
break;
text = "The server denied the connection";
break;
text = "The server denied the connection for security reason";
break;
text = "Internal licensing error";
break;
text = "No license server available";
break;
text = "No valid license available";
break;
text = "Invalid licensing message";
break;
text = "Hardware id doesn't match software license";
break;
text = "Client license error";
break;
text = "Network error during licensing protocol";
break;
text = "Licensing protocol was not completed";
break;
text = "Incorrect client license enryption";
break;
text = "Can't upgrade license";
break;
text = "The server is not licensed to accept remote connections";
break;
default:
{
text = "Internal protocol error";
}
else
{
text = "Unknown reason";
}
}
}
static void
rdesktop_reset_state(void)
{
}
static RD_BOOL
{
int istty = 0;
char *p;
{
istty = 1;
}
{
/* strip final newline */
if (p != NULL)
*p = 0;
}
if (istty)
{
}
return ret;
}
static void
parse_server_and_port(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 */
{
if (*(p + 1) == ':' && *(p + 2) != '\0')
/* remove the port number and brackets from the address */
*p = '\0';
}
}
else
{
/* dns name or IPv4 style address format - server.example.com:port or 1.2.3.4:port */
if (p != NULL)
{
*p = 0;
}
}
#else /* no IPv6 support */
if (p != NULL)
{
*p = 0;
}
#endif /* IPv6 */
}
/* Client program */
int
{
char server[64];
char fullhostname[64];
char domain[16];
char password[64];
char shell[256];
char directory[256];
char *p;
int c;
int username_option = 0;
int run_count = 0; /* Session Directory support */
#ifdef WITH_RDPSND
char *rdpsnd_optarg = NULL;
#endif
#ifdef HAVE_LOCALE_H
/* Set locale according to environment */
if (locale)
{
}
#endif
g_embed_wnd = 0;
g_num_devices = 0;
#ifdef RDP2VNC
#define VNCOPT "V:Q:"
#else
#define VNCOPT
#endif
{
switch (c)
{
#ifdef RDP2VNC
case 'V':
if (rfb_port < 100)
rfb_port += 5900;
break;
case 'Q':
if (defer_time < 0)
defer_time = 0;
break;
#endif
case 'A':
break;
case 'u':
username_option = 1;
break;
case 'L':
#ifdef HAVE_ICONV
#else
error("iconv support not available\n");
#endif
break;
case 'd':
break;
case 's':
break;
case 'c':
break;
case 'p':
{
break;
}
flags |= RDP_LOGON_AUTO;
/* try to overwrite argument so it won't appear in ps */
p = optarg;
while (*p)
*(p++) = 'X';
break;
case 'n':
break;
case 'k':
break;
case 'g':
{
break;
}
if (g_width <= 0)
{
error("invalid geometry\n");
return 1;
}
if (*p == 'x')
if (g_height <= 0)
{
error("invalid geometry\n");
return 1;
}
if (*p == '%')
{
p++;
}
if (*p == '+' || *p == '-')
{
}
if (*p == '+' || *p == '-')
{
}
break;
case 'f':
g_fullscreen = True;
break;
case 'b':
break;
case 'B':
break;
case 'e':
break;
case 'E':
break;
case 'm':
break;
case 'C':
g_owncolmap = True;
break;
case 'D':
break;
case 'K':
break;
case 'S':
{
g_win_button_size = 18;
break;
}
if (*p)
{
error("invalid button size\n");
return 1;
}
break;
case 'T':
break;
case 'N':
break;
case 'X':
break;
case 'a':
if (g_server_depth != 8 &&
g_server_depth != 16 &&
&& g_server_depth != 32)
{
error("Invalid server colour depth.\n");
return 1;
}
break;
case 'z':
DEBUG(("rdp compression enabled\n"));
break;
case 'x':
{
}
{
}
{
}
else
{
}
break;
case 'P':
break;
case 'r':
{
optarg += 5;
if (*optarg == ':')
{
optarg++;
{
#ifdef WITH_RDPSND
{
}
#else
warning("Not compiled with sound support\n");
#endif
#ifdef WITH_RDPSND
#else
warning("Not compiled with sound support\n");
#endif
optarg = p;
}
}
else
{
#ifdef WITH_RDPSND
#else
warning("Not compiled with sound support\n");
#endif
}
}
{
#ifdef WITH_RDPUSB
#else
warning("Not compiled with USB support\n");
#endif
}
{
}
{
}
{
}
{
}
{
}
{
}
{
optarg += 9;
if (*optarg == ':')
{
optarg++;
else
}
else
}
{
#ifdef WITH_SCARD
#else
warning("Not compiled with smartcard support\n");
#endif
}
else
{
warning("Unknown -r argument\n\n\tPossible arguments are: comport, disk, lptport, printer, sound, clipboard, scard\n");
}
break;
case '0':
break;
case '4':
g_use_rdp5 = False;
break;
case '5':
g_use_rdp5 = True;
break;
case 'h':
case '?':
default:
return 1;
}
}
{
return 1;
}
if (g_seamless_rdp)
{
if (g_win_button_size)
{
error("You cannot use -S and -A at the same time\n");
return 1;
}
if (geometry_option)
{
error("You cannot use -g and -A at the same time\n");
return 1;
}
if (g_fullscreen)
{
error("You cannot use -f and -A at the same time\n");
return 1;
}
if (g_hide_decorations)
{
error("You cannot use -D and -A at the same time\n");
return 1;
}
if (g_embed_wnd)
{
error("You cannot use -X and -A at the same time\n");
return 1;
}
if (!g_use_rdp5)
{
error("You cannot use -4 and -A at the same time\n");
return 1;
}
g_width = -100;
}
if (!username_option)
{
{
error("could not determine username, use -u\n");
return 1;
}
}
#ifdef HAVE_ICONV
if (g_codepage[0] == 0)
{
{
}
else
{
}
}
#endif
if (g_hostname[0] == 0)
{
{
error("could not determine local hostname, use -n\n");
return 1;
}
if (p != NULL)
*p = 0;
}
if (g_keymapname[0] == 0)
{
{
}
else
{
}
}
if (locale)
flags |= RDP_LOGON_AUTO;
if (g_title[0] == 0)
{
}
#ifdef RDP2VNC
return 0;
#else
if (!ui_init())
return 1;
#ifdef WITH_RDPSND
if (g_rdpsnd)
{
if (!rdpsnd_init(rdpsnd_optarg))
{
warning("Initializing sound-support failed!\n");
}
}
#endif
#ifdef WITH_RDPUSB
if (g_rdpusb)
rdpusb_init();
#endif
if (g_lspci_enabled)
lspci_init();
rdpdr_init();
while (run_count < 2 && continue_connect) /* add support for Session Directory; only reconnect once */
{
if (run_count == 0)
{
return 1;
}
else if (!rdp_reconnect
return 1;
/* By setting encryption to False here, we have an encrypted login
packet but unencrypted transfer of other packets */
if (!g_packet_encryption)
DEBUG(("Connection successful.\n"));
if (run_count == 0)
if (!ui_create_window())
if (continue_connect)
DEBUG(("Disconnecting...\n"));
{
/* reset state of major globals */
flags |= RDP_LOGON_AUTO;
g_redirect = False;
}
else
{
break;
}
run_count++;
}
ui_deinit();
#ifdef WITH_RDPUSB
if (g_rdpusb)
rdpusb_close();
#endif
if (ext_disc_reason >= 2)
if (deactivated)
{
/* clean disconnect */
return 0;
}
else
{
{
/* not so clean disconnect, but nothing to worry about */
return 0;
}
else
{
/* return error */
return 2;
}
}
#endif
}
#ifdef EGD_SOCKET
/* Read 32 random bytes from PRNGD or EGD socket (based on OpenSSL RAND_egd) */
static RD_BOOL
{
struct sockaddr_un addr;
int fd;
if (fd == -1)
return False;
goto err;
/* PRNGD and EGD use a simple communications protocol */
goto err;
goto err;
goto err;
err:
return ret;
}
#endif
/* Generate a 32-byte random for the secure transport code. */
void
{
uint32 *r;
int fd, n;
/* If we have a kernel random device, try that first */
{
if (n == 32)
return;
}
#ifdef EGD_SOCKET
/* As a second preference use an EGD */
if (generate_random_egd(random))
return;
#endif
/* Otherwise use whatever entropy we can gather - ideas welcome. */
/* Hash both halves with MD5 to obscure possible patterns */
ssl_md5_init(&md5);
}
/* malloc; exit if out of memory */
void *
{
{
exit(1);
}
return mem;
}
/* Exit on NULL pointer. Use to verify result from XGetImage etc */
void
exit_if_null(void *ptr)
{
{
error("unexpected null pointer. Out of memory?\n");
exit(1);
}
}
/* strdup */
char *
xstrdup(const char *s)
{
{
perror("strdup");
exit(1);
}
return mem;
}
/* realloc; exit if out of memory */
void *
{
void *mem;
if (size == 0)
size = 1;
{
exit(1);
}
return mem;
}
/* free */
void
{
}
/* report an error */
void
{
}
/* report a warning */
void
{
}
/* report an unimplemented protocol feature */
void
{
}
/* produce a hex dump */
void
{
unsigned char *line = p;
{
if (thisline > 16)
thisline = 16;
for (i = 0; i < thisline; i++)
for (; i < 16; i++)
printf(" ");
for (i = 0; i < thisline; i++)
printf("\n");
}
}
/*
input: src is the string we look in for needle.
Needle may be escaped by a backslash, in
that case we ignore that particular needle.
return value: returns next src pointer, for
succesive executions, like in a while loop
if retval is 0, then there are no more args.
pitfalls:
src is modified. 0x00 chars are inserted to
terminate strings.
return val, points on the next val chr after ins
0x00
example usage:
while( (pos = next_arg( optarg, ',')) ){
printf("%s\n",optarg);
optarg=pos;
}
*/
char *
{
char *nextval;
char *p;
char *mvp = 0;
/* EOS */
if (*src == (char) 0x00)
return 0;
p = src;
/* skip escaped needles */
{
/* found backslashed needle */
{
/* move string one to the left */
{
mvp++;
}
*mvp = (char) 0x00;
p = nextval;
}
else
{
p = nextval + 1;
break;
}
}
/* more args available */
if (nextval)
{
*nextval = (char) 0x00;
return ++nextval;
}
/* no more args after this, jump to EOS */
return nextval;
}
void
toupper_str(char *p)
{
while (*p)
{
if ((*p >= 'a') && (*p <= 'z'))
*p = toupper((int) *p);
p++;
}
}
str_startswith(const char *s, const char *prefix)
{
}
/* Split input into lines, and call linehandler for each
line. Incomplete lines are saved in the rest variable, which should
initially point to NULL. When linehandler returns False, stop and
return False. Otherwise, return True. */
{
char *buf, *p;
char *oldrest;
/* Copy data to buffer */
if (*rest)
buf[0] = '\0';
if (*rest)
p = buf;
while (1)
{
if (newline)
{
*newline = '\0';
if (!linehandler(p, data))
{
p = newline + 1;
break;
}
p = newline + 1;
}
else
{
break;
}
}
/* Save in rest */
return ret;
}
/* Execute the program specified by argv. For each line in
{
int fd[2];
int n = 1;
char output[256];
{
perror("pipe");
return False;
}
{
perror("fork");
return False;
}
/* Child */
if (child == 0)
{
/* Close read end */
/* Redirect stdout and stderr to pipe */
/* Execute */
perror("Error executing child");
_exit(128);
}
/* Parent. Close write end. */
while (n > 0)
{
output[n] = '\0';
}
return True;
}
/* not all clibs got ltoa */
char *
{
static char ret[LTOA_BUFSIZE];
register int divrem;
base = 10;
if (N < 0)
{
*head++ = '-';
N = -N;
}
*--tail = 0;
do
{
N /= base;
}
while (N);
return ret;
}
int
load_licence(unsigned char **data)
{
return -1;
if (fd == -1)
return -1;
return -1;
return length;
}
void
{
int fd;
return;
{
return;
}
if (fd == -1)
{
return;
}
{
}
{
}
}
/* Create the bitmap cache directory */
rd_pstcache_mkdir(void)
{
char *home;
char bmpcache_dir[256];
return False;
{
return False;
}
{
return False;
}
return True;
}
/* open a file in the .rdesktop directory */
int
rd_open_file(char *filename)
{
char *home;
char fn[256];
int fd;
return -1;
if (fd == -1)
return fd;
}
/* close file */
void
rd_close_file(int fd)
{
}
/* read from file*/
int
{
}
/* write to file */
int
{
}
/* move file pointer */
int
{
}
/* do a write lock on a file */
{
return False;
return True;
}