x11vnc: -findauth, -auth guess, & etc.

pull/1/head
runge 14 years ago
parent 49cdfb4c1f
commit 09f63f0395

@ -1,3 +1,21 @@
2009-11-18 Karl Runge <runge@karlrunge.com>
* x11vnc: use -timeout setting for reverse connections too.
Delay calling xfixes at the beginning of 1st connection to avoid
display manager Xorg server crash. Delay selwin creation at the
begin 1st connection to avoid being killed by display manager.
Options -findauth and '-auth guess'. Export icon_mode query.
Do not open X display in -rawfb mode unless asked. Bugfix for
-sid/-id handling window offscreen or bigger than display.
Search for windows with _DBUS_SESSION_BUS_PID to decide which
dbus_launch is ours. Fix missing displays in FIND_DISPLAY
script. Add X11VNC_SKIP_DISPLAY_NEGATE. Improvements to
'x11vnc Properties' gui dialog and connecting with x11vnc via
socket (client list.) X11VNC_SYSTEM_GREETER1 for previous text
font size. Fix bug with unixpw and vencrypt plain login.
Have fast fb read rate keep waitms and defer the same.
More heuristics to check try if GDM is still running (window
names gdm-*)
2009-10-17 Karl Runge <runge@karlrunge.com>
* x11vnc: support for -solid option in xfce desktop.
List -Q guess_dbus query. Implement -showrfbauth option.

File diff suppressed because it is too large Load Diff

@ -332,6 +332,7 @@ static int XIOerr(Display *d) {
rfbLog("*** XIO error: Note the reopened state may be unstable.\n");
usleep (3000 * 1000);
dpy = XOpenDisplay_wr(dstr);
last_open_xdisplay = time(NULL);
if (dpy) {
rfbLog("*** XIO error: Reopened display '%s' successfully.\n", dstr);
if (db) rfbLog("*** XIO error: '%s' 0x%x\n", dstr, dpy);

@ -127,7 +127,8 @@ int all_clients_initialized(void) {
while( (cl = rfbClientIteratorNext(iter)) ) {
if (cl->state != RFB_NORMAL) {
ok = 0;
break;
} else {
client_normal_count++;
}
}
rfbReleaseClientIterator(iter);
@ -2352,6 +2353,20 @@ char *get_repeater_string(char *str, int *len) {
return prestring;
}
#ifndef USE_TIMEOUT_INTERRUPT
#define USE_TIMEOUT_INTERRUPT 0
#endif
static void reverse_connect_timeout (int sig) {
rfbLog("sig: %d, reverse_connect_timeout.\n", sig);
#if USE_TIMEOUT_INTERRUPT
rfbLog("reverse_connect_timeout proceeding assuming connect(2) interrupt.\n");
#else
clean_up_exit(0);
#endif
}
/*
* Do a reverse connect for a single "host" or "host:port"
*/
@ -2362,6 +2377,7 @@ static int do_reverse_connect(char *str_in) {
char *prestring = NULL;
int prestring_len = 0;
int rport = 5500, len = strlen(str);
int set_alarm = 0;
if (len < 1) {
return 0;
@ -2432,7 +2448,19 @@ static int do_reverse_connect(char *str_in) {
/* XXX use header */
#define OPENSSL_REVERSE 4
openssl_init(1);
if (first_conn_timeout > 0) {
set_alarm = 1;
signal(SIGALRM, reverse_connect_timeout);
#if USE_TIMEOUT_INTERRUPT
siginterrupt(SIGALRM, 1);
#endif
rfbLog("reverse_connect: using alarm() timeout of %d seconds.\n", first_conn_timeout);
alarm(first_conn_timeout);
}
accept_openssl(OPENSSL_REVERSE, vncsock);
if (set_alarm) {alarm(0); signal(SIGALRM, SIG_DFL);}
openssl_init(0);
free(host);
return 1;
@ -2467,8 +2495,19 @@ static int do_reverse_connect(char *str_in) {
}
}
if (first_conn_timeout > 0) {
set_alarm = 1;
signal(SIGALRM, reverse_connect_timeout);
#if USE_TIMEOUT_INTERRUPT
siginterrupt(SIGALRM, 1);
#endif
rfbLog("reverse_connect: using alarm() timeout of %d seconds.\n", first_conn_timeout);
alarm(first_conn_timeout);
}
if (connect_proxy != NULL) {
int sock = proxy_connect(host, rport);
if (set_alarm) {alarm(0); signal(SIGALRM, SIG_DFL);}
if (sock >= 0) {
if (prestring != NULL) {
write(sock, prestring, prestring_len);
@ -2480,6 +2519,7 @@ static int do_reverse_connect(char *str_in) {
}
} else if (prestring != NULL) {
int sock = rfbConnectToTcpAddr(host, rport);
if (set_alarm) {alarm(0); signal(SIGALRM, SIG_DFL);}
if (sock >= 0) {
write(sock, prestring, prestring_len);
free(prestring);
@ -2489,6 +2529,7 @@ static int do_reverse_connect(char *str_in) {
}
} else {
cl = rfbReverseConnection(screen, host, rport);
if (set_alarm) {alarm(0); signal(SIGALRM, SIG_DFL);}
if (cl != NULL && use_threads) {
cl->onHold = FALSE;
rfbStartOnHoldClient(cl);
@ -3227,7 +3268,7 @@ char *wininfo(Window win, int show_children) {
children = (Window *) calloc(2 * sizeof(Window), 1);
children[0] = win;
}
for (n=0; n < nchildren; n++) {
for (n=0; n < (int) nchildren; n++) {
char tmp[32];
char *str = "Invalid";
Window w = children[n];
@ -3239,7 +3280,7 @@ char *wininfo(Window win, int show_children) {
str = tmp;
}
}
if (strlen(get_str) + 1 + strlen(str) >= size) {
if ((int) (strlen(get_str) + 1 + strlen(str)) >= size) {
break;
}
if (n > 0) {
@ -3523,7 +3564,6 @@ enum rfbNewClientAction new_client(rfbClientPtr client) {
clients_served++;
if (use_openssl || use_stunnel) {
if (! ssl_initialized) {
rfbLog("denying additional client: %s ssl not setup"

@ -41,6 +41,7 @@ so, delete this exception statement from your version.
#include "macosx.h"
int xfixes_present = 0;
int xfixes_first_initialized = 0;
int use_xfixes = 1;
int got_xfixes_cursor_notify = 0;
int cursor_changes = 0;
@ -984,6 +985,7 @@ static void tree_descend_cursor(int *depth, Window *w, win_str_info_t *winfo) {
void initialize_xfixes(void) {
#if LIBVNCSERVER_HAVE_LIBXFIXES
if (xfixes_present) {
xfixes_first_initialized = 1;
X_LOCK;
if (use_xfixes) {
XFixesSelectCursorInput(dpy, rootwin,
@ -1319,6 +1321,9 @@ static int get_exact_cursor(int init) {
if (last_idx) {
which = last_idx;
}
if (! xfixes_first_initialized) {
return which;
}
if (! got_xfixes_cursor_notify && xfixes_base_event_type) {
/* try again for XFixesCursorNotify event */

@ -36,6 +36,7 @@ so, delete this exception statement from your version.
/* -- cursor.h -- */
extern int xfixes_present;
extern int xfixes_first_initialized;
extern int use_xfixes;
extern int got_xfixes_cursor_notify;
extern int cursor_changes;

@ -36,7 +36,7 @@ so, delete this exception statement from your version.
/* -- enc.h -- */
#if 0
:r /home/runge/ultraSC/rc4/ultravnc_dsm_helper.c
:r /home/runge/uvnc/ultraSC/rc4/ultravnc_dsm_helper.c
#endif
/*
@ -100,14 +100,29 @@ static char *usage =
"\n"
"usage: ultravnc_dsm_helper cipher keyfile listenport remotehost:port\n"
"\n"
"e.g.: ultravnc_dsm_helper arc4 ./arc4.key 5901 snoopy.com:5900\n"
"e.g.: ultravnc_dsm_helper arc4 ./arc4.key 5901 snoopy.net:5900\n"
"\n"
" cipher: specify 'msrc4', 'msrc4_sc', 'arc4', 'aesv2',\n"
" 'aes-cfb', 'aes256', 'blowfish', or '3des'.\n"
" 'aes-cfb', 'aes256', 'blowfish', '3des',\n"
" 'securevnc'.\n"
"\n"
" 'msrc4_sc' enables a workaround for UVNC SC -plugin use.\n"
" (it might not be required in SC circa 2009 and later; try 'msrc4'.)\n"
"\n"
" use '.' to have it try to guess the cipher from the keyfile name.\n"
" use 'securevnc' for SecureVNCPlugin (RSA key exchange). 'keyfile' is\n"
" used as a server RSA keystore in this mode. If 'keyfile' does not\n"
" exist the user is prompted whether to save the key or not (a MD5\n"
" hash of it is shown) If 'keyfile' already exists the server key\n"
" must match its contents or the connection is dropped.\n"
"\n"
" HOWEVER, if 'keyfile' ends in the string 'ClientAuth.pkey', then the\n"
" normal SecureVNCPlugin client key authentication is performed.\n"
" If you want to do both have 'keyfile' end with 'ClientAuth.pkey.rsa'\n"
" that file will be used for the RSA keystore, and the '.rsa' will be\n"
" trimmed off and the remaining name used as the Client Auth file.\n"
"\n"
" use '.' to have it try to guess the cipher from the keyfile name,\n"
" e.g. 'arc4.key' implies arc4, 'rc4.key' implies msrc4, etc.\n"
"\n"
" use 'rev:arc4', etc. to reverse the roles of encrypter and decrypter.\n"
" (i.e. if you want to use it for a vnc server, not vnc viewer)\n"
@ -119,8 +134,9 @@ static char *usage =
" use 'noultra:rev:...' if both are to be supplied.\n"
"\n"
" keyfile: file holding the key (16 bytes for arc4 and aesv2, 87 for msrc4)\n"
" E.g. dd if=/dev/random of=./my.key bs=16 count=1\n"
" keyfile can also be pw=<string> to use \"string\" for the key.\n"
" E.g. dd if=/dev/random of=./my.key bs=16 count=1\n"
" keyfile can also be pw=<string> to use \"string\" for the key.\n"
" Or for 'securevnc' the RSA keystore and/or ClientAuth file.\n"
"\n"
" listenport: port to listen for incoming connection on. (use 0 to connect\n"
" to stdio, use a negative value to force localhost)\n"
@ -182,6 +198,8 @@ static char *prog = "ultravnc_dsm_helper";
#if ENC_HAVE_OPENSSL
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <openssl/err.h>
static const EVP_CIPHER *Cipher;
static const EVP_MD *Digest;
#endif
@ -229,6 +247,18 @@ static pid_t parent, child;
# define PRINT_LOOP_DBG3
#endif
/* SecureVNCPlugin from: http://adamwalling.com/SecureVNC/ */
#define SECUREVNC_RSA_PUBKEY_SIZE 270
#define SECUREVNC_ENCRYPTED_KEY_SIZE 256
#define SECUREVNC_SIGNATURE_SIZE 256
#define SECUREVNC_KEY_SIZE 16
#define SECUREVNC_RESERVED_SIZE 4
#define SECUREVNC_RC4_DROP_BYTES 3072
#define SECUREVNC_RAND_KEY_SOURCE 1024
static int securevnc = 0;
static int securevnc_arc4 = 0;
static char *securevnc_file = NULL;
static void enc_connections(int, char*, int);
#if !ENC_HAVE_OPENSSL
@ -261,7 +291,7 @@ extern void enc_do(char *ciph, char *keyfile, char *lport, char *rhp) {
struct stat sb;
char *q, *p, *connect_host;
char tmp[16];
int fd, len, listen_port, connect_port, mbits;
int fd, len = 0, listen_port, connect_port, mbits;
q = ciph;
@ -303,6 +333,10 @@ extern void enc_do(char *ciph, char *keyfile, char *lport, char *rhp) {
} else if (strstr(q, "3des") == q) {
Cipher = EVP_des_ede3_cfb(); cipher = "3des";
} else if (strstr(q, "securevnc") == q) {
Cipher = EVP_aes_128_ofb(); cipher = "securevnc";
securevnc = 1;
} else if (strstr(q, ".") == q) {
/* otherwise, try to guess cipher from key filename: */
if (strstr(keyfile, "arc4.key")) {
@ -326,6 +360,10 @@ extern void enc_do(char *ciph, char *keyfile, char *lport, char *rhp) {
} else if (strstr(keyfile, "3des.key")) {
Cipher = EVP_des_ede3_cfb(); cipher = "3des";
} else if (strstr(keyfile, "securevnc.")) {
Cipher = EVP_aes_128_ofb(); cipher = "securevnc";
securevnc = 1;
} else {
fprintf(stderr, "cannot figure out cipher, supply 'msrc4', 'arc4', or 'aesv2' ...\n");
exit(1);
@ -336,7 +374,11 @@ extern void enc_do(char *ciph, char *keyfile, char *lport, char *rhp) {
}
/* set the default message digest (md5) */
Digest = EVP_md5();
if (!securevnc) {
Digest = EVP_md5();
} else {
Digest = EVP_sha1();
}
/*
* Look for user specified salt and IV sizes at the end
@ -406,6 +448,15 @@ extern void enc_do(char *ciph, char *keyfile, char *lport, char *rhp) {
/* check for and read in the key file */
memset(keydata, 0, sizeof(keydata));
if (securevnc) {
/* note the keyfile for rsa verification later */
if (keyfile != NULL && strcasecmp(keyfile, "none")) {
securevnc_file = keyfile;
}
goto readed_in;
}
if (stat(keyfile, &sb) != 0) {
if (strstr(keyfile, "pw=") == keyfile) {
/* user specified key/password on cmdline */
@ -498,12 +549,13 @@ static void enc_xfer(int sock_fr, int sock_to, int encrypt) {
unsigned char E_keystr[EVP_MAX_KEY_LENGTH];
unsigned char D_keystr[EVP_MAX_KEY_LENGTH];
EVP_CIPHER_CTX E_ctx, D_ctx;
EVP_CIPHER_CTX *ctx;
EVP_CIPHER_CTX *ctx = NULL;
unsigned char buf[BSIZE], out[BSIZE];
unsigned char *psrc = NULL, *keystr;
unsigned char salt[SALT+1];
unsigned char ivec[EVP_MAX_IV_LENGTH];
unsigned char ivec_real[EVP_MAX_IV_LENGTH];
unsigned char *ivec = ivec_real;
int i, cnt, len, m, n = 0, vb = 0, first = 1;
int whoops = 1; /* for the msrc4 problem */
@ -513,7 +565,7 @@ static void enc_xfer(int sock_fr, int sock_to, int encrypt) {
memset(buf, 0, BSIZE);
memset(out, 0, BSIZE);
memset(salt, 0, sizeof(salt));
memset(ivec, 0, sizeof(ivec));
memset(ivec_real, 0, sizeof(ivec_real));
memset(E_keystr, 0, sizeof(E_keystr));
memset(D_keystr, 0, sizeof(D_keystr));
@ -538,7 +590,22 @@ static void enc_xfer(int sock_fr, int sock_to, int encrypt) {
encstr = encrypt ? "encrypt" : "decrypt"; /* string for messages */
encsym = encrypt ? "+" : "-";
/* use the encryption/decryption context variables below */
if (encrypt) {
ctx = &E_ctx;
keystr = E_keystr;
} else {
ctx = &D_ctx;
keystr = D_keystr;
}
if (securevnc) {
first = 0; /* no need for salt+iv on first time */
salt_size = 0; /* we want no salt */
n = 0; /* nothing read */
ivec_size = 0; /* we want no IV. */
ivec = NULL;
} else if (encrypt) {
/* encrypter initializes the salt and initialization vector */
/*
@ -558,10 +625,6 @@ static void enc_xfer(int sock_fr, int sock_to, int encrypt) {
ENC_PT_DBG(buf, n);
/* use the encryption context variables below */
ctx = &E_ctx;
keystr = E_keystr;
} else {
/* decrypter needs to read salt + iv from the wire: */
@ -615,10 +678,6 @@ static void enc_xfer(int sock_fr, int sock_to, int encrypt) {
}
}
}
/* use the decryption context variables below */
ctx = &D_ctx;
keystr = D_keystr;
}
/* debug output */
@ -644,8 +703,10 @@ static void enc_xfer(int sock_fr, int sock_to, int encrypt) {
(unsigned char *) keydata, NULL, encrypt);
}
} else {
/* XXX might not be correct */
/* XXX might not be correct, just exit. */
fprintf(stderr, "%s: %s - Not sure about msrc4 && !whoops case, exiting.\n", prog, encstr);
exit(1);
EVP_BytesToKey(Cipher, Digest, NULL, (unsigned char *) keydata,
keydata_len, 1, keystr, ivec);
EVP_CIPHER_CTX_init(ctx);
@ -654,10 +715,12 @@ static void enc_xfer(int sock_fr, int sock_to, int encrypt) {
}
} else {
unsigned char *in_salt;
unsigned char *in_salt = NULL;
/* check salt and IV source and size. */
if (salt_size <= 0) {
if (securevnc) {
in_salt = NULL;
} else if (salt_size <= 0) {
/* let salt_size = 0 mean keep it out of the MD5 */
fprintf(stderr, "%s: %s - WARNING: no salt\n",
prog, encstr);
@ -665,7 +728,8 @@ static void enc_xfer(int sock_fr, int sock_to, int encrypt) {
} else {
in_salt = salt;
}
if (ivec_size < Cipher->iv_len) {
if (ivec_size < Cipher->iv_len && !securevnc) {
fprintf(stderr, "%s: %s - WARNING: short IV %d < %d\n",
prog, encstr, ivec_size, Cipher->iv_len);
}
@ -697,6 +761,9 @@ static void enc_xfer(int sock_fr, int sock_to, int encrypt) {
* Ultra DSM compatibility mode. Note that this
* clobbers the ivec we set up above! Under
* noultra we overwrite ivec only if ivec_size=0.
*
* SecureVNC also goes through here. in_salt and ivec are NULL.
* And ivec is NULL below in the EVP_CipherInit_ex() call.
*/
EVP_BytesToKey(Cipher, Digest, in_salt, (unsigned char *) keydata,
keydata_len, 1, keystr, ivec);
@ -710,13 +777,21 @@ static void enc_xfer(int sock_fr, int sock_to, int encrypt) {
/* set the cipher & initialize */
/*
* XXX N.B.: DSM plugin had encrypt=1 for both
* (i.e. perfectly symmetric)
* XXX N.B.: DSM plugin implementation had encrypt=1
* for both (i.e. perfectly symmetric)
*/
EVP_CipherInit_ex(ctx, Cipher, NULL, keystr, ivec, encrypt);
}
if (securevnc && securevnc_arc4) {
/* need to discard initial 3072 bytes */
unsigned char buf1[SECUREVNC_RC4_DROP_BYTES];
unsigned char buf2[SECUREVNC_RC4_DROP_BYTES];
int cnt = 0;
EVP_CipherUpdate(ctx, buf1, &cnt, buf2, SECUREVNC_RC4_DROP_BYTES);
}
/* debug output */
PRINT_KEYSTR_AND_FRIENDS;
@ -825,6 +900,474 @@ static void enc_xfer(int sock_fr, int sock_to, int encrypt) {
}
}
static int securevnc_server_rsa_save_dialog(char *file, char *md5str, unsigned char* rsabuf) {
/* since we are likely running in the background, use this kludge by running tk */
FILE *p;
char str[2], *q = file, *cmd = getenv("WISH") ? getenv("WISH") : "wish";
int rc;
memset(str, 0, sizeof(str));
p = popen(cmd, "w");
if (p == NULL) {
fprintf(stderr, "checkserver_rsa: could not run: %s\n", cmd);
return 0;
}
/* start piping tk/tcl code to it: */
fprintf(p, "wm withdraw .\n");
fprintf(p, "set x [expr [winfo screenwidth .]/2]\n");
fprintf(p, "set y [expr [winfo screenheight .]/2]\n");
fprintf(p, "wm geometry . +$x+$y; update\n");
fprintf(p, "catch {option add *Dialog.msg.font {helvetica -14 bold}}\n");
fprintf(p, "catch {option add *Dialog.msg.wrapLength 6i}\n");
fprintf(p, "set ans [tk_messageBox -title \"Save and Trust UltraVNC RSA Key?\" -icon question ");
fprintf(p, "-type yesno -message \"Save and Trust UltraVNC SecureVNCPlugin RSA Key\\n\\n");
fprintf(p, "With MD5 sum: %s\\n\\n", md5str);
fprintf(p, "In file: ");
while (*q != '\0') {
/* sanitize user supplied string: */
str[0] = *q;
if (strpbrk(str, "[](){}`'\"$&*|<>") == NULL) {
fprintf(p, "%s", str);
}
q++;
}
fprintf(p, " ?\"]\n");
fprintf(p, "if { $ans == \"yes\" } {destroy .; exit 0} else {destroy .; exit 1}\n");
rc = pclose(p);
if (rc == 0) {
fprintf(stderr, "checkserver_rsa: query returned: %d. saving it.\n", rc);
p = fopen(file, "w");
if (p == NULL) {
fprintf(stderr, "checkserver_rsa: could not open %s\n", file);
return 0;
}
write(fileno(p), rsabuf, SECUREVNC_RSA_PUBKEY_SIZE);
fclose(p);
return 2;
} else {
fprintf(stderr, "checkserver_rsa: query returned: %d. NOT saving it.\n", rc);
return -1;
}
}
static char *rsa_md5_sum(unsigned char* rsabuf) {
EVP_MD_CTX md;
char digest[EVP_MAX_MD_SIZE], tmp[16];
char md5str[EVP_MAX_MD_SIZE * 8];
unsigned int i, size = 0;
EVP_DigestInit(&md, EVP_md5());
EVP_DigestUpdate(&md, rsabuf, SECUREVNC_RSA_PUBKEY_SIZE);
EVP_DigestFinal(&md, (unsigned char *)digest, &size);
memset(md5str, 0, sizeof(md5str));
for (i=0; i < size; i++) {
unsigned char uc = (unsigned char) digest[i];
sprintf(tmp, "%02x", (int) uc);
strcat(md5str, tmp);
}
return strdup(md5str);
}
static int securevnc_check_server_rsa(char *file, unsigned char *rsabuf) {
struct stat sb;
unsigned char filebuf[SECUREVNC_RSA_PUBKEY_SIZE];
char *md5str = rsa_md5_sum(rsabuf);
if (!file) {
return 0;
}
memset(filebuf, 0, sizeof(filebuf));
if (stat(file, &sb) == 0) {
int n, fd, i, ok = 1;
if (sb.st_size != SECUREVNC_RSA_PUBKEY_SIZE) {
fprintf(stderr, "checkserver_rsa: file is wrong size: %d != %d '%s'\n",
(int) sb.st_size, SECUREVNC_RSA_PUBKEY_SIZE, file);
return 0;
}
fd = open(file, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "checkserver_rsa: could not open: '%s'\n", file);
return 0;
}
n = (int) read(fd, filebuf, SECUREVNC_RSA_PUBKEY_SIZE);
close(fd);
if (n != SECUREVNC_RSA_PUBKEY_SIZE) {
fprintf(stderr, "checkserver_rsa: could not read all of file: %d != %d '%s'\n",
n, SECUREVNC_RSA_PUBKEY_SIZE, file);
return 0;
}
for (i=0; i < SECUREVNC_RSA_PUBKEY_SIZE; i++) {
if (filebuf[i] != rsabuf[i]) {
ok = 0;
}
}
if (!ok) {
char *str1 = rsa_md5_sum(rsabuf);
char *str2 = rsa_md5_sum(filebuf);
fprintf(stderr, "checkserver_rsa: rsa keystore contents differ for '%s'\n", file);
fprintf(stderr, "checkserver_rsa: MD5 sum of server key: %s\n", str1);
fprintf(stderr, "checkserver_rsa: MD5 sum of keystore: %s\n", str2);
}
return ok;
} else {
fprintf(stderr, "checkserver_rsa: rsa keystore file does not exist: '%s'\n", file);
fprintf(stderr, "checkserver_rsa: asking user if we should store rsa key in it.\n\n");
fprintf(stderr, "checkserver_rsa: RSA key has MD5 sum: %s\n\n", md5str);
return securevnc_server_rsa_save_dialog(file, md5str, rsabuf);
}
}
static RSA *load_client_auth(char *file) {
struct stat sb;
int fd, n;
char *contents;
RSA *rsa;
if (!file) {
return NULL;
}
if (stat(file, &sb) != 0) {
return NULL;
}
fd = open(file, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "load_client_auth: could not open: '%s'\n", file);
return NULL;
}
contents = (char *) malloc(sb.st_size);
n = (int) read(fd, contents, sb.st_size);
close(fd);
if (n != sb.st_size) {
fprintf(stderr, "load_client_auth: could not read all of: '%s'\n", file);
free(contents);
return NULL;
}
rsa = d2i_RSAPrivateKey(NULL, (const unsigned char **) ((void *) &contents), sb.st_size);
if (!rsa) {
fprintf(stderr, "load_client_auth: d2i_RSAPrivateKey failed for: '%s'\n", file);
return NULL;
}
if (RSA_check_key(rsa) != 1) {
fprintf(stderr, "load_client_auth: rsa key invalid: '%s'\n", file);
return NULL;
}
return rsa;
}
static void sslexit(char *msg) {
fprintf(stderr, "%s: %s\n", msg, ERR_error_string(ERR_get_error(), NULL));
exit(1);
}
static void securevnc_setup(int conn1, int conn2) {
RSA *rsa = NULL;
EVP_CIPHER_CTX init_ctx;
unsigned char keystr[EVP_MAX_KEY_LENGTH];
unsigned char *rsabuf, *rsasav;
unsigned char *encrypted_keybuf;
unsigned char *initkey;
unsigned int server_flags = 0;
unsigned char one = 1, zero = 0, sig = 16;
unsigned char b1, b2, b3, b4;
unsigned char buf[BSIZE], to_viewer[BSIZE];
int to_viewer_len = 0;
int n = 0, len, rc;
int server = reverse ? conn1 : conn2;
int viewer = reverse ? conn2 : conn1;
char *client_auth = NULL;
int client_auth_req = 0;
int keystore_verified = 0;
ERR_load_crypto_strings();
/* alloc and read from server the 270 comprising the rsa public key: */
rsabuf = (unsigned char *) calloc(SECUREVNC_RSA_PUBKEY_SIZE, 1);
rsasav = (unsigned char *) calloc(SECUREVNC_RSA_PUBKEY_SIZE, 1);
len = 0;
while (len < SECUREVNC_RSA_PUBKEY_SIZE) {
n = read(server, rsabuf + len, SECUREVNC_RSA_PUBKEY_SIZE - len);
if (n == 0 || (n < 0 && errno != EINTR)) {
fprintf(stderr, "securevnc_setup: fail read rsabuf: n=%d len=%d\n", n, len);
exit(1);
}
len += n;
}
if (len != SECUREVNC_RSA_PUBKEY_SIZE) {
fprintf(stderr, "securevnc_setup: fail final read rsabuf: n=%d len=%d\n", n, len);
exit(1);
}
fprintf(stderr, "securevnc_setup: rsa data read len: %d\n", len);
memcpy(rsasav, rsabuf, SECUREVNC_RSA_PUBKEY_SIZE);
fprintf(stderr, "securevnc_setup: RSA key has MD5 sum: %s\n", rsa_md5_sum(rsabuf));
fprintf(stderr, "securevnc_setup:\n");
fprintf(stderr, "securevnc_setup: One way to print out the SecureVNC Server key MD5 sum is:\n\n");
fprintf(stderr, "openssl rsa -inform DER -outform DER -pubout -in ./Server_SecureVNC.pkey | dd bs=1 skip=24 | md5sum\n\n");
if (securevnc_file == NULL) {
fprintf(stderr, "securevnc_setup:\n");
fprintf(stderr, "securevnc_setup: ** WARNING: ULTRAVNC SERVER RSA KEY NOT VERIFIED. **\n");
fprintf(stderr, "securevnc_setup: ** WARNING: A MAN-IN-THE-MIDDLE ATTACK IS POSSIBLE. **\n");
fprintf(stderr, "securevnc_setup:\n");
} else {
char *q = strrchr(securevnc_file, 'C');
int skip = 0;
if (q) {
if (!strcmp(q, "ClientAuth.pkey")) {
client_auth = strdup(securevnc_file);
skip = 1;
} else if (!strcmp(q, "ClientAuth.pkey.rsa")) {
client_auth = strdup(securevnc_file);
q = strrchr(client_auth, '.');
*q = '\0';
}
}
if (!skip) {
rc = securevnc_check_server_rsa(securevnc_file, rsabuf);
}
if (skip) {
;
} else if (rc == 0) {
fprintf(stderr, "securevnc_setup:\n");
fprintf(stderr, "securevnc_setup: VERIFY_ERROR: SERVER RSA KEY DID NOT MATCH:\n");
fprintf(stderr, "securevnc_setup: %s\n", securevnc_file);
fprintf(stderr, "securevnc_setup:\n");
exit(1);
} else if (rc == -1) {
fprintf(stderr, "securevnc_setup: User cancelled the save and hence the connection.\n");
fprintf(stderr, "securevnc_setup: %s\n", securevnc_file);
exit(1);
} else if (rc == 1) {
fprintf(stderr, "securevnc_setup: VERIFY SUCCESS: server rsa key matches the contents of:\n");
fprintf(stderr, "securevnc_setup: %s\n", securevnc_file);
keystore_verified = 1;
} else if (rc == 2) {
fprintf(stderr, "securevnc_setup: Server rsa key stored in:\n");
fprintf(stderr, "securevnc_setup: %s\n", securevnc_file);
keystore_verified = 2;
}
}
/*
* read in the server flags. Note that SecureVNCPlugin sends these
* in little endian and not network order!!
*/
read(server, (char *) &b1, 1);
read(server, (char *) &b2, 1);
read(server, (char *) &b3, 1);
read(server, (char *) &b4, 1);
server_flags = 0;
server_flags |= ((unsigned int) b4) << 24;
server_flags |= ((unsigned int) b3) << 16;
server_flags |= ((unsigned int) b2) << 8;
server_flags |= ((unsigned int) b1) << 0;
fprintf(stderr, "securevnc_setup: server_flags: 0x%08x\n", server_flags);
/* check for arc4 usage: */
if (server_flags & 0x1) {
fprintf(stderr, "securevnc_setup: server uses AES cipher.\n");
} else {
fprintf(stderr, "securevnc_setup: server uses ARC4 cipher.\n");
securevnc_arc4 = 1;
Cipher = EVP_rc4();
}
/* check for client auth signature requirement: */
if (server_flags & (sig << 24)) {
fprintf(stderr, "securevnc_setup: server requires Client Auth signature.\n");
client_auth_req = 1;
if (!client_auth) {
fprintf(stderr, "securevnc_setup: However, NO *ClientAuth.pkey keyfile was supplied on our\n");
fprintf(stderr, "securevnc_setup: command line. Exiting.\n");
exit(1);
}
}
/*
* The first packet 'RFB 003.006' is obscured with key
* that is a sha1 hash of public key. So make this tmp key now:
*
*/
initkey = (unsigned char *) calloc(SECUREVNC_KEY_SIZE, 1);
EVP_BytesToKey(EVP_rc4(), EVP_sha1(), NULL, rsabuf, SECUREVNC_RSA_PUBKEY_SIZE, 1, initkey, NULL);
/* expand the transported rsabuf into an rsa object */
rsa = d2i_RSAPublicKey(NULL, (const unsigned char **) &rsabuf, SECUREVNC_RSA_PUBKEY_SIZE);
if (rsa == NULL) {
sslexit("securevnc_setup: failed to create rsa");
}
/*
* Back to the work involving the tmp obscuring key:
*/
EVP_CIPHER_CTX_init(&init_ctx);
rc = EVP_CipherInit_ex(&init_ctx, EVP_rc4(), NULL, initkey, NULL, 1);
if (rc == 0) {
sslexit("securevnc_setup: EVP_CipherInit_ex(init_ctx) failed");
}
/* for the first obscured packet, read what we can... */
n = read(server, (char *) buf, BSIZE);
fprintf(stderr, "securevnc_setup: data read: %d\n", n);
if (n < 0) {
exit(1);
}
fprintf(stderr, "securevnc_setup: initial data[%d]: ", n);
/* decode with the tmp key */
if (n > 0) {
memset(to_viewer, 0, sizeof(to_viewer));
if (EVP_CipherUpdate(&init_ctx, to_viewer, &len, buf, n) == 0) {
sslexit("securevnc_setup: EVP_CipherUpdate(init_ctx) failed");
exit(1);
}
to_viewer_len = len;
}
EVP_CIPHER_CTX_cleanup(&init_ctx);
free(initkey);
/* print what we would send to the viewer (sent below): */
write(2, to_viewer, 12); /* and first 12 bytes 'RFB ...' as message */
/* now create the random session key: */
encrypted_keybuf = (unsigned char*) calloc(RSA_size(rsa), 1);
fprintf(stderr, "securevnc_setup: creating random session key: %d/%d\n",
SECUREVNC_KEY_SIZE, SECUREVNC_RAND_KEY_SOURCE);
keydata_len = SECUREVNC_RAND_KEY_SOURCE;
rc = RAND_bytes((unsigned char *)keydata, SECUREVNC_RAND_KEY_SOURCE);
if (rc <= 0) {
fprintf(stderr, "securevnc_setup: RAND_bytes() failed: %s\n", ERR_error_string(ERR_get_error(), NULL));
rc = RAND_pseudo_bytes((unsigned char *)keydata, SECUREVNC_RAND_KEY_SOURCE);
fprintf(stderr, "securevnc_setup: RAND_pseudo_bytes() rc=%d\n", rc);
if (getenv("RANDSTR")) {
char *s = getenv("RANDSTR");
fprintf(stderr, "securevnc_setup: seeding with RANDSTR len=%d\n", strlen(s));
RAND_add(s, strlen(s), strlen(s));
}
}
/* N.B. this will be repeated in enc_xfer() setup. */
EVP_BytesToKey(Cipher, Digest, NULL, (unsigned char *) keydata, keydata_len, 1, keystr, NULL);
/* encrypt the session key with the server's public rsa key: */
n = RSA_public_encrypt(SECUREVNC_KEY_SIZE, keystr, encrypted_keybuf, rsa, RSA_PKCS1_PADDING);
if (n == -1) {
sslexit("securevnc_setup: RSA_public_encrypt() failed");
exit(1);
}
fprintf(stderr, "securevnc_setup: encrypted session key size: %d. sending to server.\n", n);
/* send it to the server: */
write(server, encrypted_keybuf, n);
free(encrypted_keybuf);
/*
* Reply back with flags indicating cipher (same as one sent to
* us) and we do not want client-side auth.
*
* We send it out on the wire in little endian order:
*/
if (securevnc_arc4) {
write(server, (char *)&zero, 1);
} else {
write(server, (char *)&one, 1);
}
write(server, (char *)&zero, 1);
write(server, (char *)&zero, 1);
if (client_auth_req) {
write(server, (char *)&sig, 1);
} else {
write(server, (char *)&zero, 1);
}
if (client_auth_req && client_auth) {
RSA *client_rsa = load_client_auth(client_auth);
EVP_MD_CTX dctx;
unsigned char digest[EVP_MAX_MD_SIZE], *signature;
unsigned int ndig = 0, nsig = 0;
if (0) {
/* for testing only, use the wrong RSA key: */
client_rsa = RSA_generate_key(2048, 0x10001, NULL, NULL);
}
if (client_rsa == NULL) {
fprintf(stderr, "securevnc_setup: problem reading rsa key from '%s'\n", client_auth);
exit(1);
}
EVP_DigestInit(&dctx, EVP_sha1());
EVP_DigestUpdate(&dctx, keystr, SECUREVNC_KEY_SIZE);
/*
* Without something like the following MITM is still possible.
* This is because the MITM knows keystr and can use it with
* the server connection as well, and then he just forwards our
* signed digest. The additional information below would be the
* MITM's rsa public key, and so the real VNC server will notice
* the difference. And MITM can't sign keystr+server_rsa.pub since
* he doesn't have Viewer_ClientAuth.pkey.
*/
if (0) {
EVP_DigestUpdate(&dctx, rsasav, SECUREVNC_RSA_PUBKEY_SIZE);
if (!keystore_verified) {
fprintf(stderr, "securevnc_setup:\n");
fprintf(stderr, "securevnc_setup: Warning: even *WITH* Client Authentication in SecureVNC,\n");
fprintf(stderr, "securevnc_setup: an attacker may be able to trick you into connecting to his\n");
fprintf(stderr, "securevnc_setup: fake VNC server and supplying VNC or Windows passwords, etc.\n");
fprintf(stderr, "securevnc_setup: To increase security manually verify the Server RSA key's MD5\n");
fprintf(stderr, "securevnc_setup: checksum and then have SSVNC save the key in its keystore to\n");
fprintf(stderr, "securevnc_setup: be used to verify the server in subsequent connections.\n");
fprintf(stderr, "securevnc_setup:\n");
}
} else {
if (!keystore_verified) {
fprintf(stderr, "securevnc_setup:\n");
fprintf(stderr, "securevnc_setup: WARNING: THE FIRST VERSION OF THE SECUREVNC PROTOCOL IS\n");
fprintf(stderr, "securevnc_setup: WARNING: BEING USED. *EVEN* WITH CLIENT AUTHENTICATION IT\n");
fprintf(stderr, "securevnc_setup: WARNING: IS SUSCEPTIBLE TO A MAN-IN-THE-MIDDLE ATTACK.\n");
fprintf(stderr, "securevnc_setup: To increase security manually verify the Server RSA key's MD5\n");
fprintf(stderr, "securevnc_setup: checksum and then have SSVNC save the key in its keystore to\n");
fprintf(stderr, "securevnc_setup: be used to verify the server in subsequent connections.\n");
fprintf(stderr, "securevnc_setup:\n");
}
}
EVP_DigestFinal(&dctx, (unsigned char *)digest, &ndig);
signature = (unsigned char *) calloc(RSA_size(client_rsa), 1);
RSA_sign(NID_sha1, digest, ndig, signature, &nsig, client_rsa);
fprintf(stderr, "securevnc_setup: sending ClientAuth.pkey signed data: %d\n", nsig);
write(server, signature, nsig);
free(signature);
RSA_free(client_rsa);
}
fprintf(stderr, "securevnc_setup: done.\n");
/* now send the 'RFB ...' to the viewer */
if (to_viewer_len > 0) {
write(viewer, to_viewer, to_viewer_len);
}
}
/*
* Listens on incoming port for a client, then connects to remote server.
* Then forks into two processes one is the encrypter the other the
@ -931,6 +1474,10 @@ static void enc_connections(int listen_port, char *connect_host, int connect_por
use_input_fds:
if (securevnc) {
securevnc_setup(conn1, conn2);
}
/* fork into two processes; one for each direction: */
parent = getpid();
@ -960,7 +1507,7 @@ extern int main (int argc, char *argv[]) {
char *kf, *q;
if (argc < 4) {
fprintf(stderr, "%s\n", usage);
fprintf(stdout, "%s\n", usage);
exit(1);
}

@ -114,6 +114,10 @@ void print_help(int mode) {
" before startup. Same as -xauth file. See Xsecurity(7),\n"
" xauth(1) man pages for more info.\n"
"\n"
" Use '-auth guess' to have x11vnc use its -findauth\n"
" mechanism (described below) to try to guess the\n"
" XAUTHORITY filename and use it.\n"
"\n"
"-N If the X display is :N, try to set the VNC display to\n"
" also be :N This just sets the -rfbport option to 5900+N\n"
" The program will exit immediately if that port is not\n"
@ -137,6 +141,14 @@ void print_help(int mode) {
" X session. Note: the reopened state may be unstable.\n"
" Set X11VNC_REOPEN_DISPLAY=n to reopen n times.\n"
"\n"
" Update: as of 0.9.9, x11vnc tries to automatically avoid\n"
" being killed by the display manager by delaying creating\n"
" windows or using XFIXES. So you shouldn't need to use\n"
" KillInitClients=false as long as you log in quickly\n"
" enough (within 45 seconds of connecting.) You can\n"
" disable this by setting X11VNC_AVOID_WINDOWS=never.\n"
" You can also set it to the number of seconds to delay.\n"
"\n"
"-reflect host:N Instead of connecting to and polling an X display,\n"
" connect to the remote VNC server host:N and be a\n"
" reflector/repeater for it. This is useful for trying\n"
@ -413,6 +425,18 @@ void print_help(int mode) {
"-timeout n Exit unless a client connects within the first n seconds\n"
" after startup.\n"
"\n"
" If there have been no connection attempts after n\n"
" seconds x11vnc exits immediately. If a client is\n"
" trying to connect but has not progressed to the normal\n"
" operating state, x11vnc gives it a few more seconds\n"
" to finish and exits if it does not make it to the\n"
" normal state.\n"
"\n"
" For reverse connections via -connect or -connect_or_exit\n"
" a timeout of n seconds will be set for all reverse\n"
" connects. If the connect timeout alarm goes off,\n"
" x11vnc will exit immediately.\n"
"\n"
"-sleepin n At startup sleep n seconds before proceeding (e.g. to\n"
" allow redirs and listening clients to start up)\n"
"\n"
@ -1025,6 +1049,18 @@ void print_help(int mode) {
" (i.e. all the X displays on the local machine that you\n"
" have access rights to).\n"
"\n"
"-findauth [disp] Apply the -find/-finddpy heuristics to try to guess the\n"
" XAUTHORITY file for DISPLAY 'disp'. If 'disp' is not\n"
" supplied, then the value in the -display earlier in\n"
" the cmdline is used; failing that $DISPLAY is used;\n"
" and failing that \":0\" is used.\n"
"\n"
" If nothing is printed out, that means no XAUTHORITY was\n"
" found for 'disp'. If \"XAUTHORITY=\" is printed out,\n"
" that means use the default (i.e. do not set XAUTHORITY).\n"
" If \"XAUTHORITY=/path/to/file\" is printed out, then\n"
" use that file.\n"
"\n"
"-create First try to find the user's display using FINDDISPLAY,\n"
" if that doesn't succeed create an X session via the\n"
" FINDCREATEDISPLAY method. This is an alias for\n"
@ -1106,6 +1142,10 @@ void print_help(int mode) {
" in before the user hits Escape. The username is ignored\n"
" but the colon options are not.\n"
"\n"
" The default message is 2 lines in a small font, set\n"
" the env. var. X11VNC_SYSTEM_GREETER1=true for a 1 line\n"
" message in a larger font.\n"
"\n"
" If the user pressed Escape the FINDCREATEDISPLAY command\n"
" will be run with the env. var. X11VNC_XDM_ONLY=1.\n"
"\n"
@ -2592,6 +2632,8 @@ void print_help(int mode) {
" force it by prefixing color with \"gnome:\", \"kde:\",\n"
" \"cde:\", \"xfce:\", or \"root:\".\n"
"\n"
" Update: -solid no longer works on KDE4.\n"
"\n"
" This mode works in a limited way on the Mac OS X Console\n"
" with one color ('kelp') using the screensaver writing\n"
" to the background. Look in \"~/Library/Screen Savers\"\n"
@ -3043,6 +3085,15 @@ void print_help(int mode) {
"\n"
"-noxfixes Do not use the XFIXES extension to draw the exact cursor\n"
" shape even if it is available.\n"
"\n"
" Note: To work around a crash in Xorg 1.5 and later\n"
" some people needed to use -noxfixes. The Xorg crash\n"
" occurred right after a Display Manager (e.g. GDM) login.\n"
" Starting with x11vnc 0.9.9 it tries to automatically\n"
" avoid using XFIXES until it is sure a window manager\n"
" is running. See the -reopen option for more info and\n"
" how to use X11VNC_AVOID_WINDOWS=never to disable it.\n"
"\n"
"-alphacut n When using the XFIXES extension for the cursor shape,\n"
" cursors with transparency will not usually be displayed\n"
" exactly (but opaque ones will). This option sets n as\n"
@ -5099,9 +5150,9 @@ void print_help(int mode) {
" macnoresize macresize nomacnoresize maciconanim macmenu\n"
" macnomenu nomacmenu macuskbd nomacuskbd noremote\n"
"\n"
" aro= noop display vncdisplay autoport loop loopbg\n"
" desktopname guess_desktop guess_dbus http_url\n"
" auth xauth users rootshift clipshift scale_str\n"
" aro= noop display vncdisplay icon_mode autoport\n"
" loop loopbg desktopname guess_desktop guess_dbus\n"
" http_url auth xauth users rootshift clipshift scale_str\n"
" scaled_x scaled_y scale_numer scale_denom scale_fac_x\n"
" scale_fac_y scaling_blend scaling_nomult4 scaling_pad\n"
" scaling_interpolate inetd privremote unsafe safer\n"
@ -5218,7 +5269,7 @@ void print_help(int mode) {
" stunnel, ssl, unixpw, WAIT, zeroconf, id, accept,\n"
" afteraccept, gone, pipeinput, v4l-info, rawfb-setup,\n"
" dt, gui, ssh, storepasswd, passwdfile, custom_passwd,\n"
" crash.\n"
" findauth, crash.\n"
"\n"
" See each option's help to learn the associated external\n"
" command. Note that the -nocmds option takes precedence\n"

@ -787,7 +787,7 @@ char *process_remote_cmd(char *cmd, int stringonly) {
while (fgets(tmp, 1024, f) != NULL) {
char *c = strchr(tmp, '#');
if (c) *c = '\0';
if (strlen(p) + strlen(tmp) > sbuf.st_size) {
if (strlen(p) + strlen(tmp) > (size_t) sbuf.st_size) {
break;
}
strcat(p, tmp);
@ -5548,6 +5548,10 @@ char *process_remote_cmd(char *cmd, int stringonly) {
NONUL(vnc_desktop_name));
goto qry;
}
if (!strcmp(p, "icon_mode")) {
snprintf(buf, bufn, "aro=%s:%d", p, icon_mode);
goto qry;
}
if (!strcmp(p, "autoport")) {
snprintf(buf, bufn, "aro=%s:%d", p, auto_port);
goto qry;

@ -649,6 +649,7 @@ void set_raw_fb_params(int restore) {
if (! dpy && raw_fb_orig_dpy) {
dpy = XOpenDisplay_wr(raw_fb_orig_dpy);
last_open_xdisplay = time(NULL);
if (dpy) {
if (! quiet) rfbLog("reopened DISPLAY: %s\n",
raw_fb_orig_dpy);
@ -1366,7 +1367,7 @@ void linux_dev_fb_msg(char* q) {
#define RAWFB_SHM 3
XImage *initialize_raw_fb(int reset) {
char *str, *q;
char *str, *rstr, *q;
int w, h, b, shmid = 0;
unsigned long rm = 0, gm = 0, bm = 0, tm;
static XImage ximage_struct; /* n.b.: not (XImage *) */
@ -1453,22 +1454,32 @@ if (db) fprintf(stderr, "initialize_raw_fb reset\n");
return NULL;
}
if (raw_fb_str[0] == '+') {
rstr = strdup(raw_fb_str+1);
closedpy = 0;
if (! window) {
window = rootwin;
}
} else {
rstr = strdup(raw_fb_str);
}
/* testing aliases */
if (!strcasecmp(raw_fb_str, "NULL") || !strcasecmp(raw_fb_str, "ZERO")
|| !strcasecmp(raw_fb_str, "NONE")) {
raw_fb_str = strdup("map:/dev/zero@640x480x32");
} else if (!strcasecmp(raw_fb_str, "NULLBIG") || !strcasecmp(raw_fb_str, "NONEBIG")) {
raw_fb_str = strdup("map:/dev/zero@1024x768x32");
}
if (!strcasecmp(raw_fb_str, "RAND")) {
raw_fb_str = strdup("file:/dev/urandom@128x128x16");
} else if (!strcasecmp(raw_fb_str, "RANDBIG")) {
raw_fb_str = strdup("file:/dev/urandom@640x480x16");
} else if (!strcasecmp(raw_fb_str, "RANDHUGE")) {
raw_fb_str = strdup("file:/dev/urandom@1024x768x16");
}
if (strstr(raw_fb_str, "solid=") == raw_fb_str) {
char *n = raw_fb_str + strlen("solid=");
if (!strcasecmp(rstr, "NULL") || !strcasecmp(rstr, "ZERO")
|| !strcasecmp(rstr, "NONE")) {
rstr = strdup("map:/dev/zero@640x480x32");
} else if (!strcasecmp(rstr, "NULLBIG") || !strcasecmp(rstr, "NONEBIG")) {
rstr = strdup("map:/dev/zero@1024x768x32");
}
if (!strcasecmp(rstr, "RAND")) {
rstr = strdup("file:/dev/urandom@128x128x16");
} else if (!strcasecmp(rstr, "RANDBIG")) {
rstr = strdup("file:/dev/urandom@640x480x16");
} else if (!strcasecmp(rstr, "RANDHUGE")) {
rstr = strdup("file:/dev/urandom@1024x768x16");
}
if (strstr(rstr, "solid=") == rstr) {
char *n = rstr + strlen("solid=");
char tmp[] = "/tmp/solid.XXXXXX";
char str[100];
unsigned int vals[1024], val;
@ -1495,8 +1506,8 @@ if (db) fprintf(stderr, "initialize_raw_fb reset\n");
fd = open(tmp, O_WRONLY);
unlink_me = strdup(tmp);
sprintf(str, "map:%s@%dx%dx32", tmp, w, h);
raw_fb_str = strdup(str);
} else if (strstr(raw_fb_str, "swirl") == raw_fb_str) {
rstr = strdup(str);
} else if (strstr(rstr, "swirl") == rstr) {
char tmp[] = "/tmp/solid.XXXXXX";
char str[100];
unsigned int val[1024];
@ -1517,11 +1528,11 @@ if (db) fprintf(stderr, "initialize_raw_fb reset\n");
fd = open(tmp, O_WRONLY);
unlink_me = strdup(tmp);
sprintf(str, "map:%s@%dx%dx32", tmp, w, h);
raw_fb_str = strdup(str);
rstr = strdup(str);
}
if ( (q = strstr(raw_fb_str, "setup:")) == raw_fb_str) {
if ( (q = strstr(rstr, "setup:")) == rstr) {
FILE *pipe;
char line[1024], *t;
@ -1563,16 +1574,7 @@ if (db) fprintf(stderr, "initialize_raw_fb reset\n");
rfbLog("setup command returned: %s\n", str);
} else {
str = strdup(raw_fb_str);
}
if (str[0] == '+') {
char *t = strdup(str+1);
free(str);
str = t;
closedpy = 0;
if (! window) {
window = rootwin;
}
str = strdup(rstr);
}
raw_fb_shm = 0;
@ -2368,17 +2370,26 @@ if (0) fprintf(stderr, "DefaultDepth: %d visial_id: %d\n", depth, (int) visual_
again:
if (subwin) {
int shift = 0;
int shift = 0, resize = 0;
int subwin_x, subwin_y;
int disp_x = DisplayWidth(dpy, scr);
int disp_y = DisplayHeight(dpy, scr);
Window twin;
/* subwins can be a dicey if they are changing size... */
trapped_xerror = 0;
old_handler = XSetErrorHandler(trap_xerror);
old_handler = XSetErrorHandler(trap_xerror); /* reset in if(subwin) block below */
XTranslateCoordinates(dpy, window, rootwin, 0, 0, &subwin_x,
&subwin_y, &twin);
if (wdpy_x > disp_x) {
resize = 1;
dpy_x = wdpy_x = disp_x - 4;
}
if (wdpy_y > disp_y) {
resize = 1;
dpy_y = wdpy_y = disp_y - 4;
}
if (subwin_x + wdpy_x > disp_x) {
shift = 1;
subwin_x = disp_x - wdpy_x - 3;
@ -2396,12 +2407,17 @@ if (0) fprintf(stderr, "DefaultDepth: %d visial_id: %d\n", depth, (int) visual_
subwin_y = 1;
}
if (resize) {
XResizeWindow(dpy, window, wdpy_x, wdpy_y);
}
if (shift) {
XMoveWindow(dpy, window, subwin_x, subwin_y);
off_x = subwin_x;
off_y = subwin_y;
}
XMapRaised(dpy, window);
XRaiseWindow(dpy, window);
XFlush_wr(dpy);
XSync(dpy, False);
}
try++;
@ -4131,15 +4147,25 @@ void watch_loop(void) {
}
}
if (! screen || ! screen->clientHead) {
/* waiting for a client */
if (first_conn_timeout) {
if (first_conn_timeout) {
int t = first_conn_timeout;
if (!clients_served) {
if (time(NULL) - start > first_conn_timeout) {
rfbLog("No client after %d secs.\n",
first_conn_timeout);
rfbLog("No client after %d secs.\n", t);
shut_down = 1;