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

pull/1/head
runge 15 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> 2009-10-17 Karl Runge <runge@karlrunge.com>
* x11vnc: support for -solid option in xfce desktop. * x11vnc: support for -solid option in xfce desktop.
List -Q guess_dbus query. Implement -showrfbauth option. 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"); rfbLog("*** XIO error: Note the reopened state may be unstable.\n");
usleep (3000 * 1000); usleep (3000 * 1000);
dpy = XOpenDisplay_wr(dstr); dpy = XOpenDisplay_wr(dstr);
last_open_xdisplay = time(NULL);
if (dpy) { if (dpy) {
rfbLog("*** XIO error: Reopened display '%s' successfully.\n", dstr); rfbLog("*** XIO error: Reopened display '%s' successfully.\n", dstr);
if (db) rfbLog("*** XIO error: '%s' 0x%x\n", dstr, dpy); if (db) rfbLog("*** XIO error: '%s' 0x%x\n", dstr, dpy);

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

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

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

@ -36,7 +36,7 @@ so, delete this exception statement from your version.
/* -- enc.h -- */ /* -- enc.h -- */
#if 0 #if 0
:r /home/runge/ultraSC/rc4/ultravnc_dsm_helper.c :r /home/runge/uvnc/ultraSC/rc4/ultravnc_dsm_helper.c
#endif #endif
/* /*
@ -100,14 +100,29 @@ static char *usage =
"\n" "\n"
"usage: ultravnc_dsm_helper cipher keyfile listenport remotehost:port\n" "usage: ultravnc_dsm_helper cipher keyfile listenport remotehost:port\n"
"\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" "\n"
" cipher: specify 'msrc4', 'msrc4_sc', 'arc4', 'aesv2',\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" "\n"
" 'msrc4_sc' enables a workaround for UVNC SC -plugin use.\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" "\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" "\n"
" use 'rev:arc4', etc. to reverse the roles of encrypter and decrypter.\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" " (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" " use 'noultra:rev:...' if both are to be supplied.\n"
"\n" "\n"
" keyfile: file holding the key (16 bytes for arc4 and aesv2, 87 for msrc4)\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" " 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" " 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" "\n"
" listenport: port to listen for incoming connection on. (use 0 to connect\n" " listenport: port to listen for incoming connection on. (use 0 to connect\n"
" to stdio, use a negative value to force localhost)\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 #if ENC_HAVE_OPENSSL
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/rand.h> #include <openssl/rand.h>
#include <openssl/rsa.h>
#include <openssl/err.h>
static const EVP_CIPHER *Cipher; static const EVP_CIPHER *Cipher;
static const EVP_MD *Digest; static const EVP_MD *Digest;
#endif #endif
@ -229,6 +247,18 @@ static pid_t parent, child;
# define PRINT_LOOP_DBG3 # define PRINT_LOOP_DBG3
#endif #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); static void enc_connections(int, char*, int);
#if !ENC_HAVE_OPENSSL #if !ENC_HAVE_OPENSSL
@ -261,7 +291,7 @@ extern void enc_do(char *ciph, char *keyfile, char *lport, char *rhp) {
struct stat sb; struct stat sb;
char *q, *p, *connect_host; char *q, *p, *connect_host;
char tmp[16]; char tmp[16];
int fd, len, listen_port, connect_port, mbits; int fd, len = 0, listen_port, connect_port, mbits;
q = ciph; q = ciph;
@ -303,6 +333,10 @@ extern void enc_do(char *ciph, char *keyfile, char *lport, char *rhp) {
} else if (strstr(q, "3des") == q) { } else if (strstr(q, "3des") == q) {
Cipher = EVP_des_ede3_cfb(); cipher = "3des"; 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) { } else if (strstr(q, ".") == q) {
/* otherwise, try to guess cipher from key filename: */ /* otherwise, try to guess cipher from key filename: */
if (strstr(keyfile, "arc4.key")) { 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")) { } else if (strstr(keyfile, "3des.key")) {
Cipher = EVP_des_ede3_cfb(); cipher = "3des"; Cipher = EVP_des_ede3_cfb(); cipher = "3des";
} else if (strstr(keyfile, "securevnc.")) {
Cipher = EVP_aes_128_ofb(); cipher = "securevnc";
securevnc = 1;
} else { } else {
fprintf(stderr, "cannot figure out cipher, supply 'msrc4', 'arc4', or 'aesv2' ...\n"); fprintf(stderr, "cannot figure out cipher, supply 'msrc4', 'arc4', or 'aesv2' ...\n");
exit(1); exit(1);
@ -336,7 +374,11 @@ extern void enc_do(char *ciph, char *keyfile, char *lport, char *rhp) {
} }
/* set the default message digest (md5) */ /* 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 * 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 */ /* check for and read in the key file */
memset(keydata, 0, sizeof(keydata)); 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 (stat(keyfile, &sb) != 0) {
if (strstr(keyfile, "pw=") == keyfile) { if (strstr(keyfile, "pw=") == keyfile) {
/* user specified key/password on cmdline */ /* 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 E_keystr[EVP_MAX_KEY_LENGTH];
unsigned char D_keystr[EVP_MAX_KEY_LENGTH]; unsigned char D_keystr[EVP_MAX_KEY_LENGTH];
EVP_CIPHER_CTX E_ctx, D_ctx; EVP_CIPHER_CTX E_ctx, D_ctx;
EVP_CIPHER_CTX *ctx; EVP_CIPHER_CTX *ctx = NULL;
unsigned char buf[BSIZE], out[BSIZE]; unsigned char buf[BSIZE], out[BSIZE];
unsigned char *psrc = NULL, *keystr; unsigned char *psrc = NULL, *keystr;
unsigned char salt[SALT+1]; 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 i, cnt, len, m, n = 0, vb = 0, first = 1;
int whoops = 1; /* for the msrc4 problem */ 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(buf, 0, BSIZE);
memset(out, 0, BSIZE); memset(out, 0, BSIZE);
memset(salt, 0, sizeof(salt)); 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(E_keystr, 0, sizeof(E_keystr));
memset(D_keystr, 0, sizeof(D_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 */ encstr = encrypt ? "encrypt" : "decrypt"; /* string for messages */
encsym = encrypt ? "+" : "-"; encsym = encrypt ? "+" : "-";
/* use the encryption/decryption context variables below */
if (encrypt) { 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 */ /* 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); ENC_PT_DBG(buf, n);
/* use the encryption context variables below */
ctx = &E_ctx;
keystr = E_keystr;
} else { } else {
/* decrypter needs to read salt + iv from the wire: */ /* 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 */ /* debug output */
@ -644,8 +703,10 @@ static void enc_xfer(int sock_fr, int sock_to, int encrypt) {
(unsigned char *) keydata, NULL, encrypt); (unsigned char *) keydata, NULL, encrypt);
} }
} else { } 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); exit(1);
EVP_BytesToKey(Cipher, Digest, NULL, (unsigned char *) keydata, EVP_BytesToKey(Cipher, Digest, NULL, (unsigned char *) keydata,
keydata_len, 1, keystr, ivec); keydata_len, 1, keystr, ivec);
EVP_CIPHER_CTX_init(ctx); EVP_CIPHER_CTX_init(ctx);
@ -654,10 +715,12 @@ static void enc_xfer(int sock_fr, int sock_to, int encrypt) {
} }
} else { } else {
unsigned char *in_salt; unsigned char *in_salt = NULL;
/* check salt and IV source and size. */ /* 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 */ /* let salt_size = 0 mean keep it out of the MD5 */
fprintf(stderr, "%s: %s - WARNING: no salt\n", fprintf(stderr, "%s: %s - WARNING: no salt\n",
prog, encstr); prog, encstr);
@ -665,7 +728,8 @@ static void enc_xfer(int sock_fr, int sock_to, int encrypt) {
} else { } else {
in_salt = salt; 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", fprintf(stderr, "%s: %s - WARNING: short IV %d < %d\n",
prog, encstr, ivec_size, Cipher->iv_len); 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 * Ultra DSM compatibility mode. Note that this
* clobbers the ivec we set up above! Under * clobbers the ivec we set up above! Under
* noultra we overwrite ivec only if ivec_size=0. * 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, EVP_BytesToKey(Cipher, Digest, in_salt, (unsigned char *) keydata,
keydata_len, 1, keystr, ivec); 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 */ /* set the cipher & initialize */
/* /*
* XXX N.B.: DSM plugin had encrypt=1 for both * XXX N.B.: DSM plugin implementation had encrypt=1
* (i.e. perfectly symmetric) * for both (i.e. perfectly symmetric)
*/ */
EVP_CipherInit_ex(ctx, Cipher, NULL, keystr, ivec, encrypt); 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 */ /* debug output */
PRINT_KEYSTR_AND_FRIENDS; 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. * Listens on incoming port for a client, then connects to remote server.
* Then forks into two processes one is the encrypter the other the * 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: use_input_fds:
if (securevnc) {
securevnc_setup(conn1, conn2);
}
/* fork into two processes; one for each direction: */ /* fork into two processes; one for each direction: */
parent = getpid(); parent = getpid();
@ -960,7 +1507,7 @@ extern int main (int argc, char *argv[]) {
char *kf, *q; char *kf, *q;
if (argc < 4) { if (argc < 4) {
fprintf(stderr, "%s\n", usage); fprintf(stdout, "%s\n", usage);
exit(1); exit(1);
} }

@ -114,6 +114,10 @@ void print_help(int mode) {
" before startup. Same as -xauth file. See Xsecurity(7),\n" " before startup. Same as -xauth file. See Xsecurity(7),\n"
" xauth(1) man pages for more info.\n" " xauth(1) man pages for more info.\n"
"\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" "-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" " also be :N This just sets the -rfbport option to 5900+N\n"
" The program will exit immediately if that port is not\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" " X session. Note: the reopened state may be unstable.\n"
" Set X11VNC_REOPEN_DISPLAY=n to reopen n times.\n" " Set X11VNC_REOPEN_DISPLAY=n to reopen n times.\n"
"\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" "-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" " connect to the remote VNC server host:N and be a\n"
" reflector/repeater for it. This is useful for trying\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" "-timeout n Exit unless a client connects within the first n seconds\n"
" after startup.\n" " after startup.\n"
"\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" "-sleepin n At startup sleep n seconds before proceeding (e.g. to\n"
" allow redirs and listening clients to start up)\n" " allow redirs and listening clients to start up)\n"
"\n" "\n"
@ -1025,6 +1049,18 @@ void print_help(int mode) {
" (i.e. all the X displays on the local machine that you\n" " (i.e. all the X displays on the local machine that you\n"
" have access rights to).\n" " have access rights to).\n"
"\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" "-create First try to find the user's display using FINDDISPLAY,\n"
" if that doesn't succeed create an X session via the\n" " if that doesn't succeed create an X session via the\n"
" FINDCREATEDISPLAY method. This is an alias for\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" " in before the user hits Escape. The username is ignored\n"
" but the colon options are not.\n" " but the colon options are not.\n"
"\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" " If the user pressed Escape the FINDCREATEDISPLAY command\n"
" will be run with the env. var. X11VNC_XDM_ONLY=1.\n" " will be run with the env. var. X11VNC_XDM_ONLY=1.\n"
"\n" "\n"
@ -2592,6 +2632,8 @@ void print_help(int mode) {
" force it by prefixing color with \"gnome:\", \"kde:\",\n" " force it by prefixing color with \"gnome:\", \"kde:\",\n"
" \"cde:\", \"xfce:\", or \"root:\".\n" " \"cde:\", \"xfce:\", or \"root:\".\n"
"\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" " This mode works in a limited way on the Mac OS X Console\n"
" with one color ('kelp') using the screensaver writing\n" " with one color ('kelp') using the screensaver writing\n"
" to the background. Look in \"~/Library/Screen Savers\"\n" " to the background. Look in \"~/Library/Screen Savers\"\n"
@ -3043,6 +3085,15 @@ void print_help(int mode) {
"\n" "\n"
"-noxfixes Do not use the XFIXES extension to draw the exact cursor\n" "-noxfixes Do not use the XFIXES extension to draw the exact cursor\n"
" shape even if it is available.\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" "-alphacut n When using the XFIXES extension for the cursor shape,\n"
" cursors with transparency will not usually be displayed\n" " cursors with transparency will not usually be displayed\n"
" exactly (but opaque ones will). This option sets n as\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" " macnoresize macresize nomacnoresize maciconanim macmenu\n"
" macnomenu nomacmenu macuskbd nomacuskbd noremote\n" " macnomenu nomacmenu macuskbd nomacuskbd noremote\n"
"\n" "\n"
" aro= noop display vncdisplay autoport loop loopbg\n" " aro= noop display vncdisplay icon_mode autoport\n"
" desktopname guess_desktop guess_dbus http_url\n" " loop loopbg desktopname guess_desktop guess_dbus\n"
" auth xauth users rootshift clipshift scale_str\n" " http_url auth xauth users rootshift clipshift scale_str\n"
" scaled_x scaled_y scale_numer scale_denom scale_fac_x\n" " scaled_x scaled_y scale_numer scale_denom scale_fac_x\n"
" scale_fac_y scaling_blend scaling_nomult4 scaling_pad\n" " scale_fac_y scaling_blend scaling_nomult4 scaling_pad\n"
" scaling_interpolate inetd privremote unsafe safer\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" " stunnel, ssl, unixpw, WAIT, zeroconf, id, accept,\n"
" afteraccept, gone, pipeinput, v4l-info, rawfb-setup,\n" " afteraccept, gone, pipeinput, v4l-info, rawfb-setup,\n"
" dt, gui, ssh, storepasswd, passwdfile, custom_passwd,\n" " dt, gui, ssh, storepasswd, passwdfile, custom_passwd,\n"
" crash.\n" " findauth, crash.\n"
"\n" "\n"
" See each option's help to learn the associated external\n" " See each option's help to learn the associated external\n"
" command. Note that the -nocmds option takes precedence\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) { while (fgets(tmp, 1024, f) != NULL) {
char *c = strchr(tmp, '#'); char *c = strchr(tmp, '#');
if (c) *c = '\0'; if (c) *c = '\0';
if (strlen(p) + strlen(tmp) > sbuf.st_size) { if (strlen(p) + strlen(tmp) > (size_t) sbuf.st_size) {
break; break;
} }
strcat(p, tmp); strcat(p, tmp);
@ -5548,6 +5548,10 @@ char *process_remote_cmd(char *cmd, int stringonly) {
NONUL(vnc_desktop_name)); NONUL(vnc_desktop_name));
goto qry; goto qry;
} }
if (!strcmp(p, "icon_mode")) {
snprintf(buf, bufn, "aro=%s:%d", p, icon_mode);
goto qry;
}
if (!strcmp(p, "autoport")) { if (!strcmp(p, "autoport")) {
snprintf(buf, bufn, "aro=%s:%d", p, auto_port); snprintf(buf, bufn, "aro=%s:%d", p, auto_port);
goto qry; goto qry;

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

@ -49,7 +49,7 @@ int own_clipboard = 0; /* whether we currently own CLIPBOARD or not */
int set_clipboard = 1; int set_clipboard = 1;
int set_cutbuffer = 0; /* to avoid bouncing the CutText right back */ int set_cutbuffer = 0; /* to avoid bouncing the CutText right back */
int sel_waittime = 15; /* some seconds to skip before first send */ int sel_waittime = 15; /* some seconds to skip before first send */
Window selwin; /* special window for our selection */ Window selwin = None; /* special window for our selection */
Atom clipboard_atom = None; Atom clipboard_atom = None;
/* /*

@ -565,8 +565,9 @@ char *dbus_session(void) {
return ""; return "";
#else #else
{ {
Atom dbus_prop; Atom dbus_prop, dbus_pid;
Window r, w, *children; Window r, w, *children;
int sbest = -1;
unsigned int ui; unsigned int ui;
int rc, i; int rc, i;
@ -574,6 +575,7 @@ char *dbus_session(void) {
X_LOCK; X_LOCK;
dbus_prop = XInternAtom(dpy, "_DBUS_SESSION_BUS_ADDRESS", True); dbus_prop = XInternAtom(dpy, "_DBUS_SESSION_BUS_ADDRESS", True);
dbus_pid = XInternAtom(dpy, "_DBUS_SESSION_BUS_PID", True);
X_UNLOCK; X_UNLOCK;
if (dbus_prop == None) { if (dbus_prop == None) {
return ""; return "";
@ -596,16 +598,43 @@ char *dbus_session(void) {
if (!rc || children == NULL || ui == 0) { if (!rc || children == NULL || ui == 0) {
return ""; return "";
} }
for (i=0; i < ui; i++) { for (i=0; i < (int) ui; i++) {
int pid = -1;
X_LOCK; X_LOCK;
memset(tmp, 0, sizeof(tmp)); memset(tmp, 0, sizeof(tmp));
get_prop(tmp, sizeof(tmp)-1, dbus_prop, children[i]); get_prop(tmp, sizeof(tmp)-1, dbus_prop, children[i]);
if (dbus_pid != None) {
Atom atype;
int aformat;
unsigned long nitems, bafter;
unsigned char *prop;
if (XGetWindowProperty(dpy, children[i], dbus_pid,
0, 1, False, XA_CARDINAL, &atype, &aformat,
&nitems, &bafter, &prop) == Success
&& atype == XA_CARDINAL) {
pid = *((int *) prop);
XFree_wr(prop);
}
}
X_UNLOCK; X_UNLOCK;
if (strcmp(tmp, "")) { if (strcmp(tmp, "") && !strchr(tmp, '\'')) {
if (!strchr(tmp, '\'')) { int score = 0;
if (1 < pid && pid < 10000000) {
struct stat sb;
char procfile[32];
sprintf(procfile, "/proc/%d", pid);
if (stat(procfile, &sb) == 0) {
score += 10000000;
}
score += pid;
}
if (getenv("X11VNC_DBUS_DEBUG")) fprintf(stderr, "win: 0x%lx pid: %8d score: %8d str: %s\n", children[i], pid, score, tmp);
if (score > sbest) {
sprintf(_dbus_str, "env DBUS_SESSION_BUS_ADDRESS='%s'", tmp); sprintf(_dbus_str, "env DBUS_SESSION_BUS_ADDRESS='%s'", tmp);
break; sbest = score;
} }
} }
} }
@ -757,10 +786,10 @@ static void solid_xfce(char *color) {
if (! color) { if (! color) {
if (! orig_image_show) { if (! orig_image_show) {
orig_image_show = strdup("true"); orig_image_show = "true";
} }
if (! orig_color_style) { if (! orig_color_style) {
orig_color_style = strdup("0"); orig_color_style = "0";
} }
if (strstr(orig_image_show, "'") != NULL) { if (strstr(orig_image_show, "'") != NULL) {
rfbLog("invalid image show: %s\n", orig_image_show); rfbLog("invalid image show: %s\n", orig_image_show);
@ -770,51 +799,65 @@ static void solid_xfce(char *color) {
rfbLog("invalid color style: %s\n", orig_color_style); rfbLog("invalid color style: %s\n", orig_color_style);
return; return;
} }
cmd = (char *) malloc(strlen(set_image_show) - 2 + strlen(orig_image_show) + strlen(dbus) + 1); if (orig_image_show[0] != '\0') {
sprintf(cmd, set_image_show, dbus, orig_image_show); cmd = (char *) malloc(strlen(set_image_show) - 2 + strlen(orig_image_show) + strlen(dbus) + 1);
dt_cmd(cmd); sprintf(cmd, set_image_show, dbus, orig_image_show);
free(cmd); dt_cmd(cmd);
cmd = (char *) malloc(strlen(set_color_style) - 2 + strlen(orig_color_style) + strlen(dbus) + 1); free(cmd);
sprintf(cmd, set_color_style, dbus, orig_color_style); }
dt_cmd(cmd); if (orig_color_style[0] != '\0') {
free(cmd); cmd = (char *) malloc(strlen(set_color_style) - 2 + strlen(orig_color_style) + strlen(dbus) + 1);
sprintf(cmd, set_color_style, dbus, orig_color_style);
dt_cmd(cmd);
free(cmd);
}
return; return;
} }
if (! orig_image_show) { if (! orig_image_show) {
char *q; char *q;
orig_image_show = "";
if (cmd_ok("dt")) { if (cmd_ok("dt")) {
cmd = (char *) malloc(strlen(get_image_show) + strlen(dbus) + 1); cmd = (char *) malloc(strlen(get_image_show) + strlen(dbus) + 1);
sprintf(cmd, get_image_show, dbus); sprintf(cmd, get_image_show, dbus);
orig_image_show = strdup(cmd_output(cmd)); orig_image_show = strdup(cmd_output(cmd));
if ((q = strrchr(orig_image_show, '\n')) != NULL) {
*q = '\0';
}
fprintf(stderr, "get_image_show returned: '%s'\n\n", orig_image_show);
free(cmd); free(cmd);
} if (strcasecmp(orig_image_show, "false") && strcasecmp(orig_image_show, "true")) {
if (*orig_image_show == '\0') { fprintf(stderr, "unrecognized image_show, disabling.\n");
orig_image_show = strdup("true"); free(orig_image_show);
} orig_image_show = "";
if ((q = strchr(orig_image_show, '\n')) != NULL) { }
*q = '\0';
} }
} }
if (! orig_color_style) { if (! orig_color_style) {
char *q; char *q;
orig_color_style = "";
if (cmd_ok("dt")) { if (cmd_ok("dt")) {
cmd = (char *) malloc(strlen(get_color_style) + strlen(dbus) + 1); cmd = (char *) malloc(strlen(get_color_style) + strlen(dbus) + 1);
sprintf(cmd, get_color_style, dbus); sprintf(cmd, get_color_style, dbus);
orig_color_style = strdup(cmd_output(cmd)); orig_color_style = strdup(cmd_output(cmd));
if ((q = strrchr(orig_color_style, '\n')) != NULL) {
*q = '\0';
}
fprintf(stderr, "get_color_style returned: '%s'\n\n", orig_color_style);
free(cmd); free(cmd);
} if (strlen(orig_color_style) > 1 || !isdigit((unsigned char) (*orig_color_style))) {
if (*orig_color_style == '\0') { fprintf(stderr, "unrecognized color_style, disabling.\n");
orig_color_style = strdup("0"); free(orig_color_style);
} orig_color_style = "";
if ((q = strchr(orig_color_style, '\n')) != NULL) { }
*q = '\0';
} }
} }
if (strstr(color, "'") != NULL) { if (strstr(color, "'") != NULL) {
rfbLog("invalid color: %s\n", color); rfbLog("invalid color: %s\n", color);
return; return;
} }
cmd = (char *) malloc(strlen(set_color_style) + strlen("0") + strlen(dbus) + 1); cmd = (char *) malloc(strlen(set_color_style) + strlen("0") + strlen(dbus) + 1);
sprintf(cmd, set_color_style, dbus, "0"); sprintf(cmd, set_color_style, dbus, "0");
dt_cmd(cmd); dt_cmd(cmd);

@ -802,6 +802,9 @@ char find_display[] =
" showxauth=\"\"\n" " showxauth=\"\"\n"
" shift\n" " shift\n"
"fi\n" "fi\n"
"if [ \"X$FIND_DISPLAY_NO_SHOW_XAUTH\" != \"X\" ]; then\n"
" showxauth=\"\"\n"
"fi\n"
"\n" "\n"
"# -f means use this xauthority file:\n" "# -f means use this xauthority file:\n"
"if [ \"X$1\" = \"X-f\" ]; then\n" "if [ \"X$1\" = \"X-f\" ]; then\n"
@ -946,6 +949,9 @@ char find_display[] =
"\n" "\n"
"skip_display() {\n" "skip_display() {\n"
" dtry=$1\n" " dtry=$1\n"
" dtry1=`echo \"$dtry\" | sed -e 's/^://'`\n"
" dtry2=`echo \"$dtry\" | sed -e 's/\\.[0-9][0-9]*$//'`\n"
"\n"
" if [ \"X$X11VNC_SKIP_DISPLAY\" = \"X\" ]; then\n" " if [ \"X$X11VNC_SKIP_DISPLAY\" = \"X\" ]; then\n"
" # no skip list, return display:\n" " # no skip list, return display:\n"
" echo \"$dtry\"\n" " echo \"$dtry\"\n"
@ -987,15 +993,26 @@ char find_display[] =
" else\n" " else\n"
" skip=\":$skip\"\n" " skip=\":$skip\"\n"
" fi\n" " fi\n"
" if echo \"$skip\" | grep \":$dtry\\>\" > /dev/null; then\n" " if echo \"$skip\" | grep \":$dtry1\\>\" > /dev/null; then\n"
" mat=1\n"
" break\n"
" elif echo \"$skip\" | grep \":$dtry2\\>\" > /dev/null; then\n"
" mat=1\n" " mat=1\n"
" break\n" " break\n"
" fi\n" " fi\n"
" done\n" " done\n"
" if [ \"X$mat\" = \"X1\" ]; then\n" " if [ \"X$X11VNC_SKIP_DISPLAY_NEGATE\" = \"X\" ]; then\n"
" echo \"\"\n" " if [ \"X$mat\" = \"X1\" ]; then\n"
" echo \"\"\n"
" else\n"
" echo \"$dtry\"\n"
" fi\n"
" else\n" " else\n"
" echo \"$dtry\"\n" " if [ \"X$mat\" = \"X1\" ]; then\n"
" echo \"$dtry\"\n"
" else\n"
" echo \"\"\n"
" fi\n"
" fi\n" " fi\n"
" fi\n" " fi\n"
"}\n" "}\n"
@ -1327,7 +1344,9 @@ char find_display[] =
"# append ,VT=n if applicable:\n" "# append ,VT=n if applicable:\n"
"dpy2=`prdpy \"$display\"`\n" "dpy2=`prdpy \"$display\"`\n"
"\n" "\n"
"echo \"DISPLAY=$dpy2\"\n" "if [ \"X$FIND_DISPLAY_NO_SHOW_DISPLAY\" = \"X\" ]; then\n"
" echo \"DISPLAY=$dpy2\"\n"
"fi\n"
"if [ \"X$FIND_DISPLAY_XAUTHORITY_PATH\" != \"X\" ]; then\n" "if [ \"X$FIND_DISPLAY_XAUTHORITY_PATH\" != \"X\" ]; then\n"
" # caller wants XAUTHORITY printed out too.\n" " # caller wants XAUTHORITY printed out too.\n"
" if [ \"X$xauth_use\" != \"X\" -a -f \"$xauth_use\" ]; then\n" " if [ \"X$xauth_use\" != \"X\" -a -f \"$xauth_use\" ]; then\n"

@ -2721,6 +2721,7 @@ proc copy_default_vars {} {
proc update_menu_vars {{query ""}} { proc update_menu_vars {{query ""}} {
global all_settings menu_var query_result_list global all_settings menu_var query_result_list
global x11vnc_icon_mode
set debug [in_debug_mode] set debug [in_debug_mode]
@ -2734,6 +2735,14 @@ proc update_menu_vars {{query ""}} {
foreach piece $query_result_list { foreach piece $query_result_list {
#puts stderr "UMV: $piece" #puts stderr "UMV: $piece"
if [regexp {icon_mode:0} $piece] {
set x11vnc_icon_mode 0
#puts stderr "x11vnc_icon_mode: $x11vnc_icon_mode"
}
if [regexp {icon_mode:1} $piece] {
set x11vnc_icon_mode 1
#puts stderr "x11vnc_icon_mode: $x11vnc_icon_mode"
}
if {[regexp {^([^:][^:]*):(.*)$} $piece m0 item val]} { if {[regexp {^([^:][^:]*):(.*)$} $piece m0 item val]} {
if {[info exists menu_var($item)]} { if {[info exists menu_var($item)]} {
set old $menu_var($item) set old $menu_var($item)
@ -4319,7 +4328,7 @@ proc props_apply {} {
} }
proc props_advanced {} { proc props_advanced {} {
global icon_mode icon_win props_win full_win global icon_mode props_win full_win
global props_advanced_first global props_advanced_first
if ![info exists props_advanced_first] { if ![info exists props_advanced_first] {
@ -4337,6 +4346,7 @@ proc props_advanced {} {
set w $full_win set w $full_win
wm minsize $w [winfo width $w] [winfo height $w] wm minsize $w [winfo width $w] [winfo height $w]
} }
push_new_value "remote-cmd" "remote-cmd" "Q:clients" 1
} }
proc do_props {} { proc do_props {} {
@ -4475,17 +4485,20 @@ proc do_props {} {
} }
set props_buttons [list] set props_buttons [list]
set w .props set wp .props
catch {destroy $w} set w $wp
toplevel $w catch {destroy $wp}
wm title $w "x11vnc Properties" toplevel $wp
wm title $wp "x11vnc Properties"
frame $w.lf
set w $w.lf
set b1 "$w.buttons1" set b1 "$w.buttons1"
frame $b1 frame $b1
button $b1.ok -text OK -command "if {\[props_apply\]} {destroy $w}" -font $bfont button $b1.ok -text OK -command "if {\[props_apply\]} {destroy $wp}" -font $bfont
button $b1.cancel -text Cancel -command "destroy $w" -font $bfont button $b1.cancel -text Cancel -command "destroy $wp" -font $bfont
button $b1.apply -text Apply -command "props_apply" -font $bfont button $b1.apply -text Apply -command "props_apply" -font $bfont
bind $w <KeyPress-Escape> "destroy $w" bind $w <KeyPress-Escape> "destroy $wp"
pack $b1.ok $b1.cancel $b1.apply -side left -expand 0 pack $b1.ok $b1.cancel $b1.apply -side left -expand 0
lappend props_buttons $b1.apply $b1.cancel $b1.ok lappend props_buttons $b1.apply $b1.cancel $b1.ok
@ -4494,7 +4507,7 @@ proc do_props {} {
frame $b2 frame $b2
button $b2.advanced -text " Advanced ... " \ button $b2.advanced -text " Advanced ... " \
-command "destroy $w; props_advanced" -font $bfont -command "destroy $wp; props_advanced" -font $bfont
if {! $icon_noadvanced} { if {! $icon_noadvanced} {
lappend props_buttons $b2.advanced lappend props_buttons $b2.advanced
pack $b2.advanced -side left -expand 0 pack $b2.advanced -side left -expand 0
@ -4516,6 +4529,17 @@ proc do_props {} {
entry $pw.e -show "*" -textvariable props_passwd -font $bfont entry $pw.e -show "*" -textvariable props_passwd -font $bfont
pack $pw.e -fill x -expand 1 -padx 1m -pady $pady -side top pack $pw.e -fill x -expand 1 -padx 1m -pady $pady -side top
global x11vnc_icon_mode
if {! $x11vnc_icon_mode} {
catch { $pw.e configure -state disabled}
if {! $have_labelframes} {
catch { $pw.l configure -state disabled}
}
} else {
lappend props_buttons $pw.e
}
set vp "$w.viewpw" set vp "$w.viewpw"
if {$have_labelframes} { if {$have_labelframes} {
labelframe $vp -text "ViewOnly Password" -font $bfont labelframe $vp -text "ViewOnly Password" -font $bfont
@ -4528,8 +4552,14 @@ proc do_props {} {
entry $vp.e -show "*" -textvariable props_viewpasswd -font $bfont entry $vp.e -show "*" -textvariable props_viewpasswd -font $bfont
pack $vp.e -fill x -expand 1 -padx 1m -pady $pady -side top pack $vp.e -fill x -expand 1 -padx 1m -pady $pady -side top
if {! $x11vnc_icon_mode} {
lappend props_buttons $vp.e catch { $vp.e configure -state disabled}
if {! $have_labelframes} {
catch { $vp.l configure -state disabled}
}
} else {
lappend props_buttons $vp.e
}
if {! $icon_mode_at_startup} { if {! $icon_mode_at_startup} {
$vp.e configure -state disabled $vp.e configure -state disabled
@ -4542,8 +4572,6 @@ proc do_props {} {
catch {$pw configure -foreground grey60} catch {$pw configure -foreground grey60}
} }
lappend props_buttons $pw.e
set sb "$w.solid" set sb "$w.solid"
frame $sb frame $sb
checkbutton $sb.button -text "Solid Background Color" \ checkbutton $sb.button -text "Solid Background Color" \
@ -4604,17 +4632,21 @@ proc do_props {} {
set show_props_instructions 1 set show_props_instructions 1
} }
wm withdraw $w wm withdraw .props
set wl $w
pack $wl -side left
if {$msg != ""} { if {$msg != ""} {
set tw [textwidth $msg] set tw [textwidth $msg]
set th [textheight $msg] set th [textheight $msg]
set th [expr $th - 1] set th [expr $th - 1]
set ms "$w.msg" set ms ".props.msg"
text $ms -font $ffont -relief ridge -width $tw -height $th text $ms -font $ffont -relief ridge -width $tw -height $th
$ms insert 1.0 $msg $ms insert 1.0 $msg
set si "$w.instructions" set si "$wl.instructions"
frame $si frame $si
checkbutton $si.button -text "Show Instructions" \ checkbutton $si.button -text "Show Instructions" \
-variable show_props_instructions -anchor w -font $bfont \ -variable show_props_instructions -anchor w -font $bfont \
@ -4624,15 +4656,17 @@ proc do_props {} {
pack $si -side bottom -fill x -pady 0m -padx $px pack $si -side bottom -fill x -pady 0m -padx $px
if {$show_props_instructions} { if {$show_props_instructions} {
pack $ms -side bottom -fill x -pady $pady -padx $px pack $ms -side left -fill both
} }
update update
} }
lappend props_buttons $ac.button $cf.button $vo.button $sh.button $zc.button $jv.button $sb.button lappend props_buttons $ac.button $cf.button $vo.button $sh.button $zc.button $jv.button $sb.button
set w .props
update update
wm resizable $w 1 0 wm resizable $w 1 0
center_win $w center_win $w
@ -4647,7 +4681,7 @@ proc do_props {} {
proc toggle_instructions {ms pady px} { proc toggle_instructions {ms pady px} {
global show_props_instructions global show_props_instructions
if {$show_props_instructions} { if {$show_props_instructions} {
pack $ms -side bottom -fill x -pady $pady -padx $px pack $ms -side left -fill both
} else { } else {
pack forget $ms pack forget $ms
} }
@ -4898,6 +4932,13 @@ proc show_client_balloon {} {
if {$client_balloon == ""} { if {$client_balloon == ""} {
set client_balloon $noinfo set client_balloon $noinfo
} }
if {! [info exists icon_win]} {
return
} elseif {$icon_win == ""} {
return
} elseif {! [winfo exists $icon_win]} {
return
}
set x [expr [winfo rootx $icon_win] + ([winfo width $icon_win]/2)] set x [expr [winfo rootx $icon_win] + ([winfo width $icon_win]/2)]
set y [expr [winfo rooty $icon_win] + [winfo height $icon_win] + 4] set y [expr [winfo rooty $icon_win] + [winfo height $icon_win] + 4]
@ -4946,10 +4987,11 @@ proc kill_client_balloon {} {
proc icon_win_cfg {clients} { proc icon_win_cfg {clients} {
global icon_win client_tail client_sock client_info_read global icon_win client_tail client_sock client_info_read
if {![info exists icon_win]} { if {! [info exists icon_win]} {
return return
} } elseif {$icon_win == ""} {
if {$icon_win == ""} { return
} elseif {! [winfo exists $icon_win]} {
return return
} }
if {$clients > 0} { if {$clients > 0} {
@ -5109,6 +5151,14 @@ proc set_icon_label {} {
global icon_win global icon_win
set lab [get_icon_label] set lab [get_icon_label]
if {! [info exists icon_win]} {
return
} elseif {$icon_win == ""} {
return
} elseif {! [winfo exists $icon_win]} {
return
}
if {[info exists icon_win]} { if {[info exists icon_win]} {
$icon_win configure -text $lab $icon_win configure -text $lab
@ -6276,6 +6326,18 @@ proc run_remote_cmd_via_sock {opts} {
if {$db} {puts stderr "run_remote_cmd_via_sock: \"$res\""} if {$db} {puts stderr "run_remote_cmd_via_sock: \"$res\""}
set res [string trim $res] set res [string trim $res]
if [regexp {=clients:} $res] {
regsub {^.*=clients:} $res "" cres
regsub {,aro=.*$} $cres "" cres
regsub {,ans=.*$} $cres "" cres
if {$cres == "none"} {
set cres ""
}
update_clients_menu $cres
set client_str $cres
set_client_balloon $cres
}
if [regexp {^clients:} $res] { if [regexp {^clients:} $res] {
regsub {^clients:} $res "" tmp regsub {^clients:} $res "" tmp
if {$tmp == "none"} { if {$tmp == "none"} {
@ -6663,7 +6725,6 @@ proc setup_client_sock {{enable 1}} {
} }
proc setup_tray_embed {} { proc setup_tray_embed {} {
global icon_win
update update
set w [winfo width .] set w [winfo width .]
set h [winfo height .] set h [winfo height .]
@ -6754,7 +6815,6 @@ proc restart_everything {gui_mode} {
} }
proc undo_tray_embed {} { proc undo_tray_embed {} {
global icon_win
set wid [winfo id .] set wid [winfo id .]
push_new_value "remote-cmd" "remote-cmd" "trayunembed:$wid" 0 push_new_value "remote-cmd" "remote-cmd" "trayunembed:$wid" 0
} }
@ -6782,7 +6842,7 @@ global bfont ffont sfont snfont old_labels have_labelframes
global connected_to_x11vnc global connected_to_x11vnc
global cache_all_query_vars global cache_all_query_vars
global last_query_all_time query_all_freq client_tail client_sock client_info_read global last_query_all_time query_all_freq client_tail client_sock client_info_read
global icon_mode icon_mode_at_startup global icon_mode icon_mode_at_startup x11vnc_icon_mode
global tray_embed tray_running icon_setpasswd icon_embed_id global tray_embed tray_running icon_setpasswd icon_embed_id
global icon_noadvanced icon_minimal global icon_noadvanced icon_minimal
global make_gui_count text_area_str global make_gui_count text_area_str
@ -7052,6 +7112,7 @@ if {[info exists env(X11VNC_SIMPLE_GUI)]} {
} }
set icon_mode 0 set icon_mode 0
set x11vnc_icon_mode 0
set tray_embed 0 set tray_embed 0
set tray_running 0 set tray_running 0
@ -7159,11 +7220,11 @@ proc check_setpasswd {} {
set do_props_msg "" set do_props_msg ""
if {$icon_setpasswd} { if {$icon_setpasswd} {
set m "\n" set m "\n"
set m " Note the x11vnc icon in the system tray \n" set m "${m} Note the x11vnc icon in the system tray.\n"
set m "${m} This panel is its 'Properties' dialog.\n" set m "${m} This panel is its 'Properties' dialog.\n"
set m "${m}\n" set m "${m}\n"
set m "${m} To specify a Session Password and to\n" set m "${m} To specify a Session Password and to\n"
set m "${m} allow VNC clients to connect, follow\n" set m "${m} allow VNC viewers to connect, follow\n"
set m "${m} these steps:\n" set m "${m} these steps:\n"
set m "${m}\n" set m "${m}\n"
set m "${m} Enter a passwd in the Password field\n" set m "${m} Enter a passwd in the Password field\n"
@ -7173,9 +7234,12 @@ proc check_setpasswd {} {
set m "${m} Set 'Accept Connections' and then Press \n" set m "${m} Set 'Accept Connections' and then Press \n"
set m "${m} 'Apply' to allow incoming connections.\n" set m "${m} 'Apply' to allow incoming connections.\n"
set m "${m}\n" set m "${m}\n"
set m "${m} No Viewer can connect until you do this.\n"
set m "${m}\n"
set m "${m} The passwords are only for this x11vnc\n" set m "${m} The passwords are only for this x11vnc\n"
set m "${m} session and are not saved. Run x11vnc\n" set m "${m} session and are not saved. Run x11vnc\n"
set m "${m} manually for more control.\n" set m "${m} manually for more control (e.g. -rfbauth \n"
set m "${m} for a saved password.)\n"
set m "${m}\n" set m "${m}\n"
set m "${m} See 'Help' for details on each option.\n" set m "${m} See 'Help' for details on each option.\n"
@ -7237,6 +7301,7 @@ if {$icon_mode} {
dtime G dtime G
old_balloon old_balloon
check_setpasswd check_setpasswd
push_new_value "remote-cmd" "remote-cmd" "Q:clients" 1
} else { } else {
make_gui "full" make_gui "full"
dtime G dtime G

@ -2732,6 +2732,7 @@ char gui_code[] = "";
"\n" "\n"
"proc update_menu_vars {{query \"\"}} {\n" "proc update_menu_vars {{query \"\"}} {\n"
" global all_settings menu_var query_result_list\n" " global all_settings menu_var query_result_list\n"
" global x11vnc_icon_mode\n"
"\n" "\n"
" set debug [in_debug_mode]\n" " set debug [in_debug_mode]\n"
"\n" "\n"
@ -2745,6 +2746,14 @@ char gui_code[] = "";
"\n" "\n"
" foreach piece $query_result_list {\n" " foreach piece $query_result_list {\n"
"#puts stderr \"UMV: $piece\"\n" "#puts stderr \"UMV: $piece\"\n"
" if [regexp {icon_mode:0} $piece] {\n"
" set x11vnc_icon_mode 0\n"
" #puts stderr \"x11vnc_icon_mode: $x11vnc_icon_mode\"\n"
" }\n"
" if [regexp {icon_mode:1} $piece] {\n"
" set x11vnc_icon_mode 1\n"
" #puts stderr \"x11vnc_icon_mode: $x11vnc_icon_mode\"\n"
" }\n"
" if {[regexp {^([^:][^:]*):(.*)$} $piece m0 item val]} {\n" " if {[regexp {^([^:][^:]*):(.*)$} $piece m0 item val]} {\n"
" if {[info exists menu_var($item)]} {\n" " if {[info exists menu_var($item)]} {\n"
" set old $menu_var($item)\n" " set old $menu_var($item)\n"
@ -4330,7 +4339,7 @@ char gui_code[] = "";
"}\n" "}\n"
"\n" "\n"
"proc props_advanced {} {\n" "proc props_advanced {} {\n"
" global icon_mode icon_win props_win full_win\n" " global icon_mode props_win full_win\n"
" global props_advanced_first\n" " global props_advanced_first\n"
"\n" "\n"
" if ![info exists props_advanced_first] {\n" " if ![info exists props_advanced_first] {\n"
@ -4348,6 +4357,7 @@ char gui_code[] = "";
" set w $full_win\n" " set w $full_win\n"
" wm minsize $w [winfo width $w] [winfo height $w]\n" " wm minsize $w [winfo width $w] [winfo height $w]\n"
" }\n" " }\n"
" push_new_value \"remote-cmd\" \"remote-cmd\" \"Q:clients\" 1\n"
"}\n" "}\n"
"\n" "\n"
"proc do_props {} {\n" "proc do_props {} {\n"
@ -4486,17 +4496,20 @@ char gui_code[] = "";
" }\n" " }\n"
" set props_buttons [list]\n" " set props_buttons [list]\n"
"\n" "\n"
" set w .props\n" " set wp .props\n"
" catch {destroy $w}\n" " set w $wp\n"
" toplevel $w\n" " catch {destroy $wp}\n"
" wm title $w \"x11vnc Properties\"\n" " toplevel $wp\n"
" wm title $wp \"x11vnc Properties\"\n"
" frame $w.lf\n"
" set w $w.lf\n"
" set b1 \"$w.buttons1\"\n" " set b1 \"$w.buttons1\"\n"
" frame $b1\n" " frame $b1\n"
" button $b1.ok -text OK -command \"if {\\[props_apply\\]} {destroy $w}\" -font $bfont\n" " button $b1.ok -text OK -command \"if {\\[props_apply\\]} {destroy $wp}\" -font $bfont\n"
" button $b1.cancel -text Cancel -command \"destroy $w\" -font $bfont\n" " button $b1.cancel -text Cancel -command \"destroy $wp\" -font $bfont\n"
" button $b1.apply -text Apply -command \"props_apply\" -font $bfont\n" " button $b1.apply -text Apply -command \"props_apply\" -font $bfont\n"
"\n" "\n"
" bind $w <KeyPress-Escape> \"destroy $w\"\n" " bind $w <KeyPress-Escape> \"destroy $wp\"\n"
"\n" "\n"
" pack $b1.ok $b1.cancel $b1.apply -side left -expand 0\n" " pack $b1.ok $b1.cancel $b1.apply -side left -expand 0\n"
" lappend props_buttons $b1.apply $b1.cancel $b1.ok\n" " lappend props_buttons $b1.apply $b1.cancel $b1.ok\n"
@ -4505,7 +4518,7 @@ char gui_code[] = "";
" frame $b2\n" " frame $b2\n"
"\n" "\n"
" button $b2.advanced -text \" Advanced ... \" \\\n" " button $b2.advanced -text \" Advanced ... \" \\\n"
" -command \"destroy $w; props_advanced\" -font $bfont\n" " -command \"destroy $wp; props_advanced\" -font $bfont\n"
" if {! $icon_noadvanced} {\n" " if {! $icon_noadvanced} {\n"
" lappend props_buttons $b2.advanced\n" " lappend props_buttons $b2.advanced\n"
" pack $b2.advanced -side left -expand 0\n" " pack $b2.advanced -side left -expand 0\n"
@ -4527,6 +4540,17 @@ char gui_code[] = "";
" entry $pw.e -show \"*\" -textvariable props_passwd -font $bfont\n" " entry $pw.e -show \"*\" -textvariable props_passwd -font $bfont\n"
" pack $pw.e -fill x -expand 1 -padx 1m -pady $pady -side top\n" " pack $pw.e -fill x -expand 1 -padx 1m -pady $pady -side top\n"
"\n" "\n"
" global x11vnc_icon_mode\n"
" if {! $x11vnc_icon_mode} {\n"
" catch { $pw.e configure -state disabled}\n"
" if {! $have_labelframes} {\n"
" catch { $pw.l configure -state disabled}\n"
" }\n"
" } else {\n"
" lappend props_buttons $pw.e\n"
" }\n"
"\n"
"\n"
" set vp \"$w.viewpw\"\n" " set vp \"$w.viewpw\"\n"
" if {$have_labelframes} {\n" " if {$have_labelframes} {\n"
" labelframe $vp -text \"ViewOnly Password\" -font $bfont\n" " labelframe $vp -text \"ViewOnly Password\" -font $bfont\n"
@ -4539,8 +4563,14 @@ char gui_code[] = "";
" entry $vp.e -show \"*\" -textvariable props_viewpasswd -font $bfont\n" " entry $vp.e -show \"*\" -textvariable props_viewpasswd -font $bfont\n"
" pack $vp.e -fill x -expand 1 -padx 1m -pady $pady -side top\n" " pack $vp.e -fill x -expand 1 -padx 1m -pady $pady -side top\n"
"\n" "\n"
"\n" " if {! $x11vnc_icon_mode} {\n"
" lappend props_buttons $vp.e\n" " catch { $vp.e configure -state disabled}\n"
" if {! $have_labelframes} {\n"
" catch { $vp.l configure -state disabled}\n"
" }\n"
" } else {\n"
" lappend props_buttons $vp.e\n"
" }\n"
"\n" "\n"
" if {! $icon_mode_at_startup} {\n" " if {! $icon_mode_at_startup} {\n"
" $vp.e configure -state disabled\n" " $vp.e configure -state disabled\n"
@ -4553,8 +4583,6 @@ char gui_code[] = "";
" catch {$pw configure -foreground grey60}\n" " catch {$pw configure -foreground grey60}\n"
" }\n" " }\n"
"\n" "\n"
" lappend props_buttons $pw.e\n"
"\n"
" set sb \"$w.solid\"\n" " set sb \"$w.solid\"\n"
" frame $sb\n" " frame $sb\n"
" checkbutton $sb.button -text \"Solid Background Color\" \\\n" " checkbutton $sb.button -text \"Solid Background Color\" \\\n"
@ -4615,17 +4643,21 @@ char gui_code[] = "";
" set show_props_instructions 1\n" " set show_props_instructions 1\n"
" }\n" " }\n"
"\n" "\n"
" wm withdraw $w\n" " wm withdraw .props\n"
"\n"
" set wl $w\n"
"\n"
" pack $wl -side left\n"
"\n" "\n"
" if {$msg != \"\"} {\n" " if {$msg != \"\"} {\n"
" set tw [textwidth $msg]\n" " set tw [textwidth $msg]\n"
" set th [textheight $msg]\n" " set th [textheight $msg]\n"
" set th [expr $th - 1]\n" " set th [expr $th - 1]\n"
" set ms \"$w.msg\"\n" " set ms \".props.msg\"\n"
" text $ms -font $ffont -relief ridge -width $tw -height $th\n" " text $ms -font $ffont -relief ridge -width $tw -height $th\n"
" $ms insert 1.0 $msg\n" " $ms insert 1.0 $msg\n"
"\n" "\n"
" set si \"$w.instructions\"\n" " set si \"$wl.instructions\"\n"
" frame $si\n" " frame $si\n"
" checkbutton $si.button -text \"Show Instructions\" \\\n" " checkbutton $si.button -text \"Show Instructions\" \\\n"
" -variable show_props_instructions -anchor w -font $bfont \\\n" " -variable show_props_instructions -anchor w -font $bfont \\\n"
@ -4635,15 +4667,17 @@ char gui_code[] = "";
" pack $si -side bottom -fill x -pady 0m -padx $px\n" " pack $si -side bottom -fill x -pady 0m -padx $px\n"
"\n" "\n"
" if {$show_props_instructions} {\n" " if {$show_props_instructions} {\n"
" pack $ms -side bottom -fill x -pady $pady -padx $px\n" " pack $ms -side left -fill both\n"
" }\n" " }\n"
"\n" "\n"
" update\n" " update\n"
" }\n" " }\n"
"\n" "\n"
"\n"
" lappend props_buttons $ac.button $cf.button $vo.button $sh.button $zc.button $jv.button $sb.button\n" " lappend props_buttons $ac.button $cf.button $vo.button $sh.button $zc.button $jv.button $sb.button\n"
"\n" "\n"
" \n" " \n"
" set w .props\n"
" update\n" " update\n"
" wm resizable $w 1 0\n" " wm resizable $w 1 0\n"
" center_win $w\n" " center_win $w\n"
@ -4658,7 +4692,7 @@ char gui_code[] = "";
"proc toggle_instructions {ms pady px} {\n" "proc toggle_instructions {ms pady px} {\n"
" global show_props_instructions\n" " global show_props_instructions\n"
" if {$show_props_instructions} {\n" " if {$show_props_instructions} {\n"
" pack $ms -side bottom -fill x -pady $pady -padx $px\n" " pack $ms -side left -fill both\n"
" } else {\n" " } else {\n"
" pack forget $ms\n" " pack forget $ms\n"
" }\n" " }\n"
@ -4909,6 +4943,13 @@ char gui_code[] = "";
" if {$client_balloon == \"\"} {\n" " if {$client_balloon == \"\"} {\n"
" set client_balloon $noinfo\n" " set client_balloon $noinfo\n"
" }\n" " }\n"
" if {! [info exists icon_win]} {\n"
" return\n"
" } elseif {$icon_win == \"\"} {\n"
" return\n"
" } elseif {! [winfo exists $icon_win]} {\n"
" return\n"
" }\n"
"\n" "\n"
" set x [expr [winfo rootx $icon_win] + ([winfo width $icon_win]/2)]\n" " set x [expr [winfo rootx $icon_win] + ([winfo width $icon_win]/2)]\n"
" set y [expr [winfo rooty $icon_win] + [winfo height $icon_win] + 4]\n" " set y [expr [winfo rooty $icon_win] + [winfo height $icon_win] + 4]\n"
@ -4957,10 +4998,11 @@ char gui_code[] = "";
"proc icon_win_cfg {clients} {\n" "proc icon_win_cfg {clients} {\n"
" global icon_win client_tail client_sock client_info_read\n" " global icon_win client_tail client_sock client_info_read\n"
"\n" "\n"
" if {![info exists icon_win]} {\n" " if {! [info exists icon_win]} {\n"
" return\n" " return\n"
" }\n" " } elseif {$icon_win == \"\"} {\n"
" if {$icon_win == \"\"} {\n" " return\n"
" } elseif {! [winfo exists $icon_win]} {\n"
" return\n" " return\n"
" }\n" " }\n"
" if {$clients > 0} {\n" " if {$clients > 0} {\n"
@ -5120,6 +5162,14 @@ char gui_code[] = "";
" global icon_win\n" " global icon_win\n"
"\n" "\n"
" set lab [get_icon_label]\n" " set lab [get_icon_label]\n"
"\n"
" if {! [info exists icon_win]} {\n"
" return\n"
" } elseif {$icon_win == \"\"} {\n"
" return\n"
" } elseif {! [winfo exists $icon_win]} {\n"
" return\n"
" }\n"
" \n" " \n"
" if {[info exists icon_win]} {\n" " if {[info exists icon_win]} {\n"
" $icon_win configure -text $lab\n" " $icon_win configure -text $lab\n"
@ -6287,6 +6337,18 @@ char gui_code[] = "";
" if {$db} {puts stderr \"run_remote_cmd_via_sock: \\\"$res\\\"\"}\n" " if {$db} {puts stderr \"run_remote_cmd_via_sock: \\\"$res\\\"\"}\n"
" set res [string trim $res]\n" " set res [string trim $res]\n"
"\n" "\n"
" if [regexp {=clients:} $res] {\n"
" regsub {^.*=clients:} $res \"\" cres\n"
" regsub {,aro=.*$} $cres \"\" cres\n"
" regsub {,ans=.*$} $cres \"\" cres\n"
" if {$cres == \"none\"} {\n"
" set cres \"\"\n"
" }\n"
" update_clients_menu $cres\n"
" set client_str $cres\n"
" set_client_balloon $cres\n"
" }\n"
"\n"
" if [regexp {^clients:} $res] {\n" " if [regexp {^clients:} $res] {\n"
" regsub {^clients:} $res \"\" tmp\n" " regsub {^clients:} $res \"\" tmp\n"
" if {$tmp == \"none\"} {\n" " if {$tmp == \"none\"} {\n"
@ -6674,7 +6736,6 @@ char gui_code[] = "";
"}\n" "}\n"
"\n" "\n"
"proc setup_tray_embed {} {\n" "proc setup_tray_embed {} {\n"
" global icon_win\n"
" update\n" " update\n"
" set w [winfo width .]\n" " set w [winfo width .]\n"
" set h [winfo height .]\n" " set h [winfo height .]\n"
@ -6765,7 +6826,6 @@ char gui_code[] = "";
"}\n" "}\n"
"\n" "\n"
"proc undo_tray_embed {} {\n" "proc undo_tray_embed {} {\n"
" global icon_win\n"
" set wid [winfo id .] \n" " set wid [winfo id .] \n"
" push_new_value \"remote-cmd\" \"remote-cmd\" \"trayunembed:$wid\" 0\n" " push_new_value \"remote-cmd\" \"remote-cmd\" \"trayunembed:$wid\" 0\n"
"}\n" "}\n"
@ -6793,7 +6853,7 @@ char gui_code[] = "";
"global connected_to_x11vnc\n" "global connected_to_x11vnc\n"
"global cache_all_query_vars\n" "global cache_all_query_vars\n"
"global last_query_all_time query_all_freq client_tail client_sock client_info_read\n" "global last_query_all_time query_all_freq client_tail client_sock client_info_read\n"
"global icon_mode icon_mode_at_startup\n" "global icon_mode icon_mode_at_startup x11vnc_icon_mode\n"
"global tray_embed tray_running icon_setpasswd icon_embed_id\n" "global tray_embed tray_running icon_setpasswd icon_embed_id\n"
"global icon_noadvanced icon_minimal\n" "global icon_noadvanced icon_minimal\n"
"global make_gui_count text_area_str\n" "global make_gui_count text_area_str\n"
@ -7063,6 +7123,7 @@ char gui_code[] = "";
"}\n" "}\n"
"\n" "\n"
"set icon_mode 0\n" "set icon_mode 0\n"
"set x11vnc_icon_mode 0\n"
"set tray_embed 0\n" "set tray_embed 0\n"
"set tray_running 0\n" "set tray_running 0\n"
"\n" "\n"
@ -7170,11 +7231,11 @@ char gui_code[] = "";
" set do_props_msg \"\"\n" " set do_props_msg \"\"\n"
" if {$icon_setpasswd} {\n" " if {$icon_setpasswd} {\n"
" set m \"\\n\"\n" " set m \"\\n\"\n"
" set m \" Note the x11vnc icon in the system tray \\n\" \n" " set m \"${m} Note the x11vnc icon in the system tray.\\n\" \n"
" set m \"${m} This panel is its 'Properties' dialog.\\n\" \n" " set m \"${m} This panel is its 'Properties' dialog.\\n\" \n"
" set m \"${m}\\n\" \n" " set m \"${m}\\n\" \n"
" set m \"${m} To specify a Session Password and to\\n\" \n" " set m \"${m} To specify a Session Password and to\\n\" \n"
" set m \"${m} allow VNC clients to connect, follow\\n\" \n" " set m \"${m} allow VNC viewers to connect, follow\\n\" \n"
" set m \"${m} these steps:\\n\" \n" " set m \"${m} these steps:\\n\" \n"
" set m \"${m}\\n\" \n" " set m \"${m}\\n\" \n"
" set m \"${m} Enter a passwd in the Password field\\n\" \n" " set m \"${m} Enter a passwd in the Password field\\n\" \n"
@ -7184,9 +7245,12 @@ char gui_code[] = "";
" set m \"${m} Set 'Accept Connections' and then Press \\n\" \n" " set m \"${m} Set 'Accept Connections' and then Press \\n\" \n"
" set m \"${m} 'Apply' to allow incoming connections.\\n\" \n" " set m \"${m} 'Apply' to allow incoming connections.\\n\" \n"
" set m \"${m}\\n\" \n" " set m \"${m}\\n\" \n"
" set m \"${m} No Viewer can connect until you do this.\\n\" \n"
" set m \"${m}\\n\" \n"
" set m \"${m} The passwords are only for this x11vnc\\n\" \n" " set m \"${m} The passwords are only for this x11vnc\\n\" \n"
" set m \"${m} session and are not saved. Run x11vnc\\n\" \n" " set m \"${m} session and are not saved. Run x11vnc\\n\" \n"
" set m \"${m} manually for more control.\\n\" \n" " set m \"${m} manually for more control (e.g. -rfbauth \\n\" \n"
" set m \"${m} for a saved password.)\\n\" \n"
" set m \"${m}\\n\" \n" " set m \"${m}\\n\" \n"
" set m \"${m} See 'Help' for details on each option.\\n\" \n" " set m \"${m} See 'Help' for details on each option.\\n\" \n"
"\n" "\n"
@ -7248,6 +7312,7 @@ char gui_code[] = "";
" dtime G\n" " dtime G\n"
" old_balloon\n" " old_balloon\n"
" check_setpasswd\n" " check_setpasswd\n"
" push_new_value \"remote-cmd\" \"remote-cmd\" \"Q:clients\" 1\n"
"} else {\n" "} else {\n"
" make_gui \"full\"\n" " make_gui \"full\"\n"
" dtime G\n" " dtime G\n"

@ -468,10 +468,17 @@ void unixpw_screen(int init) {
if (unixpw_system_greeter) { if (unixpw_system_greeter) {
unixpw_system_greeter_active = 0; unixpw_system_greeter_active = 0;
if (use_dpy && strstr(use_dpy, "xdmcp")) { if (use_dpy && strstr(use_dpy, "xdmcp")) {
char moo[] = "Press 'Escape' for System Greeter"; if (getenv("X11VNC_SYSTEM_GREETER1")) {
char moo[] = "Press 'Escape' for System Greeter";
rfbDrawString(pscreen, &default8x16Font, x-90, y-30, moo, white_pixel());
} else {
char moo1[] = "Press 'Escape' for New Session via System Greeter,";
char moo2[] = "or otherwise login here for Existing Session: ";
rfbDrawString(pscreen, &default6x13Font, x-110, y-38, moo1, white_pixel());
rfbDrawString(pscreen, &default6x13Font, x-110, y-25, moo2, white_pixel());
}
set_env("X11VNC_XDM_ONLY", "0"); set_env("X11VNC_XDM_ONLY", "0");
unixpw_system_greeter_active = 1; unixpw_system_greeter_active = 1;
rfbDrawString(pscreen, &default8x16Font, x-90, y-30, moo, white_pixel());
} }
} }

@ -1590,7 +1590,7 @@ static void loop_for_connect(int did_client_connect) {
if (screen && screen->clientHead) { if (screen && screen->clientHead) {
int i; int i;
if (unixpw) { if (unixpw) {
if (! unixpw_in_progress) { if (! unixpw_in_progress && !vencrypt_enable_plain_login) {
rfbLog("unixpw but no unixpw_in_progress\n"); rfbLog("unixpw but no unixpw_in_progress\n");
clean_up_exit(1); clean_up_exit(1);
} }
@ -1648,7 +1648,7 @@ static void loop_for_connect(int did_client_connect) {
static void do_unixpw_loop(void) { static void do_unixpw_loop(void) {
if (unixpw) { if (unixpw) {
if (! unixpw_in_progress) { if (! unixpw_in_progress && !vencrypt_enable_plain_login) {
rfbLog("unixpw but no unixpw_in_progress\n"); rfbLog("unixpw but no unixpw_in_progress\n");
clean_up_exit(1); clean_up_exit(1);
} }
@ -2785,7 +2785,9 @@ int wait_for_client(int *argc, char** argv, int http) {
if (db) fprintf(stderr, "args %d %s\n", i, argv[i]); if (db) fprintf(stderr, "args %d %s\n", i, argv[i]);
} }
if (!quiet && !strstr(use_dpy, "FINDDISPLAY-run")) { if (!quiet && !strstr(use_dpy, "FINDDISPLAY-run")) {
rfbLog("\n");
rfbLog("wait_for_client: %s\n", use_dpy); rfbLog("wait_for_client: %s\n", use_dpy);
rfbLog("\n");
} }
str = strdup(use_dpy); str = strdup(use_dpy);

@ -1,8 +1,8 @@
.\" This file was automatically generated from x11vnc -help output. .\" This file was automatically generated from x11vnc -help output.
.TH X11VNC "1" "October 2009" "x11vnc " "User Commands" .TH X11VNC "1" "November 2009" "x11vnc " "User Commands"
.SH NAME .SH NAME
x11vnc - allow VNC connections to real X11 displays x11vnc - allow VNC connections to real X11 displays
version: 0.9.9, lastmod: 2009-10-15 version: 0.9.9, lastmod: 2009-11-18
.SH SYNOPSIS .SH SYNOPSIS
.B x11vnc .B x11vnc
[OPTION]... [OPTION]...
@ -76,6 +76,10 @@ before startup. Same as \fB-xauth\fR file. See
, ,
.IR xauth (1) .IR xauth (1)
man pages for more info. man pages for more info.
.IP
Use '-auth guess' to have x11vnc use its \fB-findauth\fR
mechanism (described below) to try to guess the
XAUTHORITY filename and use it.
.PP .PP
\fB-N\fR \fB-N\fR
.IP .IP
@ -107,6 +111,14 @@ for display managers like GDM (KillInitClients option)
that kill x11vnc just after the user logs into the that kill x11vnc just after the user logs into the
X session. Note: the reopened state may be unstable. X session. Note: the reopened state may be unstable.
Set X11VNC_REOPEN_DISPLAY=n to reopen n times. Set X11VNC_REOPEN_DISPLAY=n to reopen n times.
.IP
Update: as of 0.9.9, x11vnc tries to automatically avoid
being killed by the display manager by delaying creating
windows or using XFIXES. So you shouldn't need to use
KillInitClients=false as long as you log in quickly
enough (within 45 seconds of connecting.) You can
disable this by setting X11VNC_AVOID_WINDOWS=never.
You can also set it to the number of seconds to delay.
.PP .PP
\fB-reflect\fR \fIhost:N\fR \fB-reflect\fR \fIhost:N\fR
.IP .IP
@ -444,6 +456,18 @@ mode. This usage could use useful: \fB-svc\fR \fB-bg\fR \fB-loopbg\fR
.IP .IP
Exit unless a client connects within the first n seconds Exit unless a client connects within the first n seconds
after startup. after startup.
.IP
If there have been no connection attempts after n
seconds x11vnc exits immediately. If a client is
trying to connect but has not progressed to the normal
operating state, x11vnc gives it a few more seconds
to finish and exits if it does not make it to the
normal state.
.IP
For reverse connections via \fB-connect\fR or \fB-connect_or_exit\fR
a timeout of n seconds will be set for all reverse
connects. If the connect timeout alarm goes off,
x11vnc will exit immediately.
.PP .PP
\fB-sleepin\fR \fIn\fR \fB-sleepin\fR \fIn\fR
.IP .IP
@ -1149,6 +1173,20 @@ Have the FINDDISPLAY program list all of your displays
(i.e. all the X displays on the local machine that you (i.e. all the X displays on the local machine that you
have access rights to). have access rights to).
.PP .PP
\fB-findauth\fR \fI[disp]\fR
.IP
Apply the \fB-find/-finddpy\fR heuristics to try to guess the
XAUTHORITY file for DISPLAY 'disp'. If 'disp' is not
supplied, then the value in the \fB-display\fR earlier in
the cmdline is used; failing that $DISPLAY is used;
and failing that ":0" is used.
.IP
If nothing is printed out, that means no XAUTHORITY was
found for 'disp'. If "XAUTHORITY=" is printed out,
that means use the default (i.e. do not set XAUTHORITY).
If "XAUTHORITY=/path/to/file" is printed out, then
use that file.
.PP
\fB-create\fR \fB-create\fR
.IP .IP
First try to find the user's display using FINDDISPLAY, First try to find the user's display using FINDDISPLAY,
@ -1253,6 +1291,10 @@ WAIT: are also applied in this mode if they are typed
in before the user hits Escape. The username is ignored in before the user hits Escape. The username is ignored
but the colon options are not. but the colon options are not.
.IP .IP
The default message is 2 lines in a small font, set
the env. var. X11VNC_SYSTEM_GREETER1=true for a 1 line
message in a larger font.
.IP
If the user pressed Escape the FINDCREATEDISPLAY command If the user pressed Escape the FINDCREATEDISPLAY command
will be run with the env. var. X11VNC_XDM_ONLY=1. will be run with the env. var. X11VNC_XDM_ONLY=1.
.IP .IP
@ -2878,6 +2920,8 @@ If x11vnc guesses your desktop incorrectly, you can
force it by prefixing color with "gnome:", "kde:", force it by prefixing color with "gnome:", "kde:",
"cde:", "xfce:", or "root:". "cde:", "xfce:", or "root:".
.IP .IP
Update: \fB-solid\fR no longer works on KDE4.
.IP
This mode works in a limited way on the Mac OS X Console This mode works in a limited way on the Mac OS X Console
with one color ('kelp') using the screensaver writing with one color ('kelp') using the screensaver writing
to the background. Look in "~/Library/Screen Savers" to the background. Look in "~/Library/Screen Savers"
@ -3447,6 +3491,14 @@ Ignored when in XFIXES cursor-grabbing mode.
.IP .IP
Do not use the XFIXES extension to draw the exact cursor Do not use the XFIXES extension to draw the exact cursor
shape even if it is available. shape even if it is available.
.IP
Note: To work around a crash in Xorg 1.5 and later
some people needed to use \fB-noxfixes.\fR The Xorg crash
occurred right after a Display Manager (e.g. GDM) login.
Starting with x11vnc 0.9.9 it tries to automatically
avoid using XFIXES until it is sure a window manager
is running. See the \fB-reopen\fR option for more info and
how to use X11VNC_AVOID_WINDOWS=never to disable it.
.PP .PP
\fB-alphacut\fR \fIn\fR \fB-alphacut\fR \fIn\fR
.IP .IP
@ -6052,9 +6104,9 @@ nomacnowait macwheel macnoswap macswap nomacnoswap
macnoresize macresize nomacnoresize maciconanim macmenu macnoresize macresize nomacnoresize maciconanim macmenu
macnomenu nomacmenu macuskbd nomacuskbd noremote macnomenu nomacmenu macuskbd nomacuskbd noremote
.IP .IP
aro= noop display vncdisplay autoport loop loopbg aro= noop display vncdisplay icon_mode autoport
desktopname guess_desktop guess_dbus http_url loop loopbg desktopname guess_desktop guess_dbus
auth xauth users rootshift clipshift scale_str http_url auth xauth users rootshift clipshift scale_str
scaled_x scaled_y scale_numer scale_denom scale_fac_x scaled_x scaled_y scale_numer scale_denom scale_fac_x
scale_fac_y scaling_blend scaling_nomult4 scaling_pad scale_fac_y scaling_blend scaling_nomult4 scaling_pad
scaling_interpolate inetd privremote unsafe safer scaling_interpolate inetd privremote unsafe safer
@ -6201,7 +6253,7 @@ associated options is:
stunnel, ssl, unixpw, WAIT, zeroconf, id, accept, stunnel, ssl, unixpw, WAIT, zeroconf, id, accept,
afteraccept, gone, pipeinput, v4l-info, rawfb-setup, afteraccept, gone, pipeinput, v4l-info, rawfb-setup,
dt, gui, ssh, storepasswd, passwdfile, custom_passwd, dt, gui, ssh, storepasswd, passwdfile, custom_passwd,
crash. findauth, crash.
.IP .IP
See each option's help to learn the associated external See each option's help to learn the associated external
command. Note that the \fB-nocmds\fR option takes precedence command. Note that the \fB-nocmds\fR option takes precedence

@ -1907,6 +1907,62 @@ static void do_sleepin(char *sleep) {
} }
} }
static void check_guess_auth_file(void) {
if (!strcasecmp(auth_file, "guess")) {
char line[4096], *cmd, *q, *disp = use_dpy ? use_dpy: "";
FILE *p;
int n;
if (!program_name) {
rfbLog("-auth guess: no program_name found.\n");
clean_up_exit(1);
}
if (strpbrk(program_name, " \t\r\n")) {
rfbLog("-auth guess: whitespace in program_name '%s'\n", program_name);
clean_up_exit(1);
}
if (no_external_cmds || !cmd_ok("findauth")) {
rfbLog("-auth guess: cannot run external commands in -nocmds mode:\n");
clean_up_exit(1);
}
cmd = (char *)malloc(100 + strlen(program_name) + strlen(disp));
sprintf(cmd, "%s -findauth %s", program_name, disp);
p = popen(cmd, "r");
if (!p) {
rfbLog("-auth guess: could not run cmd '%s'\n", cmd);
clean_up_exit(1);
}
memset(line, 0, sizeof(line));
n = fread(line, 1, sizeof(line), p);
pclose(p);
q = strrchr(line, '\n');
if (q) *q = '\0';
if (!strcmp(disp, "")) {
disp = getenv("DISPLAY");
if (!disp) {
disp = "unset";
}
}
if (!strcmp(line, "")) {
rfbLog("-auth guess: failed for display='%s'\n", disp);
clean_up_exit(1);
} else if (strstr(line, "XAUTHORITY=") != line) {
rfbLog("-auth guess: failed. '%s' for display='%s'\n", line, disp);
clean_up_exit(1);
} else if (!strcmp(line, "XAUTHORITY=")) {
rfbLog("-auth guess: using default XAUTHORITY for display='%s'\n", disp);
q = getenv("XAUTHORITY");
if (q) {
*(q-2) = '_'; /* yow */
}
auth_file = NULL;
} else {
rfbLog("-auth guess: using '%s' for disp='%s'\n", line, disp);
auth_file = strdup(line + strlen("XAUTHORITY="));
}
}
}
extern int dragum(void); extern int dragum(void);
extern int is_decimal(char *); extern int is_decimal(char *);
@ -1947,8 +2003,10 @@ int main(int argc, char* argv[]) {
dtime0(&x11vnc_start); dtime0(&x11vnc_start);
if (!getuid() || !geteuid()) { if (!getuid() || !geteuid()) {
started_as_root = 1; started_as_root = 1;
rfbLog("getuid: %d geteuid: %d\n", getuid(), geteuid());
/* check for '-users =bob' */ /* check for '-users =bob' */
immediate_switch_user(argc, argv); immediate_switch_user(argc, argv);
@ -2091,6 +2149,27 @@ int main(int argc, char* argv[]) {
exit(0); exit(0);
continue; continue;
} }
if (!strcmp(arg, "-findauth")) {
int ic = 0;
if (use_dpy != NULL) {
set_env("DISPLAY", use_dpy);
}
use_dpy = strdup("WAIT:cmd=FINDDISPLAY-run");
if (argc > i+1) {
set_env("X11VNC_SKIP_DISPLAY", argv[i+1]);
} else if (getenv("DISPLAY")) {
set_env("X11VNC_SKIP_DISPLAY", getenv("DISPLAY"));
} else {
set_env("X11VNC_SKIP_DISPLAY", ":0");
}
set_env("X11VNC_SKIP_DISPLAY_NEGATE", "1");
set_env("FIND_DISPLAY_XAUTHORITY_PATH", "1");
set_env("FIND_DISPLAY_NO_SHOW_XAUTH", "1");
set_env("FIND_DISPLAY_NO_SHOW_DISPLAY", "1");
wait_for_client(&ic, NULL, 0);
exit(0);
continue;
}
if (!strcmp(arg, "-create")) { if (!strcmp(arg, "-create")) {
use_dpy = strdup("WAIT:cmd=FINDCREATEDISPLAY-Xvfb"); use_dpy = strdup("WAIT:cmd=FINDCREATEDISPLAY-Xvfb");
continue; continue;
@ -4635,10 +4714,14 @@ int main(int argc, char* argv[]) {
CLIENT_INIT; CLIENT_INIT;
/* open the X display: */ /* open the X display: */
if (auth_file) { if (auth_file) {
set_env("XAUTHORITY", auth_file); check_guess_auth_file();
if (0) fprintf(stderr, "XA: %s\n", getenv("XAUTHORITY")); if (auth_file != NULL) {
set_env("XAUTHORITY", auth_file);
}
} }
#if LIBVNCSERVER_HAVE_XKEYBOARD #if LIBVNCSERVER_HAVE_XKEYBOARD
/* /*
* Disable XKEYBOARD before calling XOpenDisplay() * Disable XKEYBOARD before calling XOpenDisplay()
@ -4724,7 +4807,7 @@ if (0) fprintf(stderr, "XA: %s\n", getenv("XAUTHORITY"));
; ;
} else } else
#endif #endif
if (use_dpy) { if (use_dpy && strcmp(use_dpy, "")) {
dpy = XOpenDisplay_wr(use_dpy); dpy = XOpenDisplay_wr(use_dpy);
#ifdef MACOSX #ifdef MACOSX
} else if (!subwin && getenv("DISPLAY") } else if (!subwin && getenv("DISPLAY")
@ -4733,11 +4816,36 @@ if (0) fprintf(stderr, "XA: %s\n", getenv("XAUTHORITY"));
rfbLog("MacOSX: Ignoring $DISPLAY '%s'\n", getenv("DISPLAY")); rfbLog("MacOSX: Ignoring $DISPLAY '%s'\n", getenv("DISPLAY"));
rfbLog("MacOSX: Use -display $DISPLAY to force it.\n"); rfbLog("MacOSX: Use -display $DISPLAY to force it.\n");
#endif #endif
} else if (raw_fb_str != NULL && raw_fb_str[0] != '+' && !got_noviewonly) {
rfbLog("Not opening DISPLAY in -rawfb mode (force via -rawfb +str)\n");
dpy = NULL; /* don't open it. */
} else if ( (use_dpy = getenv("DISPLAY")) ) { } else if ( (use_dpy = getenv("DISPLAY")) ) {
if (strstr(use_dpy, "localhost") == use_dpy) {
rfbLog("\n");
rfbLog("WARNING: DISPLAY starts with localhost: '%s'\n", use_dpy);
rfbLog("WARNING: Is this an SSH X11 port forwarding? You most\n");
rfbLog("WARNING: likely don't want x11vnc to use that DISPLAY.\n");
rfbLog("WARNING: You probably should supply something\n");
rfbLog("WARNING: like: -display :0 to access the physical\n");
rfbLog("WARNING: X display on the machine where x11vnc is running.\n");
rfbLog("\n");
usleep(500 * 1000);
} else if (using_shm && use_dpy[0] != ':') {
rfbLog("\n");
rfbLog("WARNING: DISPLAY might not be local: '%s'\n", use_dpy);
rfbLog("WARNING: Is this the DISPLAY of another machine? Usually,\n");
rfbLog("WARNING: x11vnc is run on the same machine with the\n");
rfbLog("WARNING: physical X display to be exported by VNC. If\n");
rfbLog("WARNING: that is what you really meant, supply something\n");
rfbLog("WARNING: like: -display :0 on the x11vnc command line.\n");
rfbLog("\n");
usleep(250 * 1000);
}
dpy = XOpenDisplay_wr(use_dpy); dpy = XOpenDisplay_wr(use_dpy);
} else { } else {
dpy = XOpenDisplay_wr(""); dpy = XOpenDisplay_wr("");
} }
last_open_xdisplay = time(NULL);
if (terminal_services_daemon != NULL) { if (terminal_services_daemon != NULL) {
terminal_services(terminal_services_daemon); terminal_services(terminal_services_daemon);
@ -4751,8 +4859,7 @@ if (0) fprintf(stderr, "XA: %s\n", getenv("XAUTHORITY"));
#endif #endif
if (! dpy && raw_fb_str) { if (! dpy && raw_fb_str) {
rfbLog("continuing without X display in -rawfb mode, " rfbLog("Continuing without X display in -rawfb mode.\n");
"hold on tight..\n");
goto raw_fb_pass_go_and_collect_200_dollars; goto raw_fb_pass_go_and_collect_200_dollars;
} }
@ -4771,6 +4878,7 @@ if (0) fprintf(stderr, "XA: %s\n", getenv("XAUTHORITY"));
fprintf(stderr, "\n"); fprintf(stderr, "\n");
use_dpy = ":0"; use_dpy = ":0";
dpy = XOpenDisplay_wr(use_dpy); dpy = XOpenDisplay_wr(use_dpy);
last_open_xdisplay = time(NULL);
if (dpy) { if (dpy) {
rfbLog("*** XOpenDisplay of \":0\" successful.\n"); rfbLog("*** XOpenDisplay of \":0\" successful.\n");
} }
@ -4805,6 +4913,10 @@ if (0) fprintf(stderr, "XA: %s\n", getenv("XAUTHORITY"));
if (dpy) { if (dpy) {
Window w = XCreateSimpleWindow(dpy, rootwin, 0, 0, 1, 1, 0, 0, 0); Window w = XCreateSimpleWindow(dpy, rootwin, 0, 0, 1, 1, 0, 0, 0);
if (! quiet) rfbLog("rootwin: 0x%lx reswin: 0x%lx dpy: 0x%x\n", rootwin, w, dpy); if (! quiet) rfbLog("rootwin: 0x%lx reswin: 0x%lx dpy: 0x%x\n", rootwin, w, dpy);
if (w != None) {
XDestroyWindow(dpy, w);
}
XSync(dpy, False);
} }
#endif #endif
@ -5403,6 +5515,10 @@ if (0) fprintf(stderr, "XA: %s\n", getenv("XAUTHORITY"));
if (speeds_read_rate_measured > 80) { if (speeds_read_rate_measured > 80) {
/* framebuffer read is fast at > 80 MB/sec */ /* framebuffer read is fast at > 80 MB/sec */
int same = 0;
if (waitms == defer_update) {
same = 1;
}
if (! got_waitms) { if (! got_waitms) {
waitms /= 2; waitms /= 2;
if (waitms < 5) { if (waitms < 5) {
@ -5414,7 +5530,11 @@ if (0) fprintf(stderr, "XA: %s\n", getenv("XAUTHORITY"));
} }
if (! got_deferupdate && ! got_defer) { if (! got_deferupdate && ! got_defer) {
if (defer_update > 10) { if (defer_update > 10) {
defer_update = 10; if (same) {
defer_update = waitms;
} else {
defer_update = 10;
}
if (screen) { if (screen) {
screen->deferUpdateTime = defer_update; screen->deferUpdateTime = defer_update;
} }

@ -520,7 +520,7 @@ extern unsigned char *tile_has_diff, *tile_tried, *tile_copied;
extern unsigned char *tile_has_xdamage_diff, *tile_row_has_xdamage_diff; extern unsigned char *tile_has_xdamage_diff, *tile_row_has_xdamage_diff;
/* times of recent events */ /* times of recent events */
extern time_t last_event, last_input, last_client; extern time_t last_event, last_input, last_client, last_open_xdisplay;
extern time_t last_keyboard_input, last_pointer_input; extern time_t last_keyboard_input, last_pointer_input;
extern time_t last_local_input; /* macosx */ extern time_t last_local_input; /* macosx */
extern time_t last_fb_bytes_sent; extern time_t last_fb_bytes_sent;
@ -558,6 +558,7 @@ extern char *terminal_services_daemon;
extern int client_count; extern int client_count;
extern int clients_served; extern int clients_served;
extern int client_normal_count;
/* more transient kludge variables: */ /* more transient kludge variables: */
extern int cursor_x, cursor_y; /* x and y from the viewer(s) */ extern int cursor_x, cursor_y; /* x and y from the viewer(s) */

@ -47,7 +47,7 @@ int xtrap_base_event_type = 0;
int xdamage_base_event_type = 0; int xdamage_base_event_type = 0;
/* date +'lastmod: %Y-%m-%d' */ /* date +'lastmod: %Y-%m-%d' */
char lastmod[] = "0.9.9 lastmod: 2009-10-15"; char lastmod[] = "0.9.9 lastmod: 2009-11-18";
/* X display info */ /* X display info */
@ -157,7 +157,7 @@ unsigned char *tile_has_diff = NULL, *tile_tried = NULL, *tile_copied = NULL;
unsigned char *tile_has_xdamage_diff = NULL, *tile_row_has_xdamage_diff = NULL; unsigned char *tile_has_xdamage_diff = NULL, *tile_row_has_xdamage_diff = NULL;
/* times of recent events */ /* times of recent events */
time_t last_event = 0, last_input = 0, last_client = 0; time_t last_event = 0, last_input = 0, last_client = 0, last_open_xdisplay = 0;
time_t last_local_input = 0; time_t last_local_input = 0;
time_t last_keyboard_input = 0, last_pointer_input = 0; time_t last_keyboard_input = 0, last_pointer_input = 0;
time_t last_fb_bytes_sent = 0; time_t last_fb_bytes_sent = 0;
@ -195,6 +195,7 @@ char *terminal_services_daemon = NULL;
int client_count = 0; int client_count = 0;
int clients_served = 0; int clients_served = 0;
int client_normal_count = 0;
/* more transient kludge variables: */ /* more transient kludge variables: */
int cursor_x = 0, cursor_y = 0; /* x and y from the viewer(s) */ int cursor_x = 0, cursor_y = 0; /* x and y from the viewer(s) */

@ -77,6 +77,7 @@ void set_text_chat(rfbClientPtr cl, int l, char *t);
int get_keyboard_led_state_hook(rfbScreenInfoPtr s); int get_keyboard_led_state_hook(rfbScreenInfoPtr s);
int get_file_transfer_permitted(rfbClientPtr cl); int get_file_transfer_permitted(rfbClientPtr cl);
void get_prop(char *str, int len, Atom prop, Window w); void get_prop(char *str, int len, Atom prop, Window w);
int guess_dm_gone(int t1, int t2);
static void initialize_xevents(int reset); static void initialize_xevents(int reset);
static void print_xevent_bases(void); static void print_xevent_bases(void);
@ -119,6 +120,189 @@ void initialize_clipboard_atom(void) {
#endif /* NO_X11 */ #endif /* NO_X11 */
} }
/*
we observed these strings:
6 gdm_string: Gnome-power-manager
6 gdm_string: Gnome-session
6 gdm_string: Gnome-settings-daemon
6 gdm_string: Login Window
6 gdm_string: Notify-osd
6 gdm_string: Panel
12 gdm_string: Metacity
12 gdm_string: gnome-power-manager
12 gdm_string: gnome-session
12 gdm_string: gnome-settings-daemon
12 gdm_string: notify-osd
18 gdm_string: Gdm-simple-greeter
24 gdm_string: metacity
36 gdm_string: gdm-simple-greeter
*/
static int gdm_string(char *str) {
if (str == NULL) {
return 0;
}
if (str[0] == '\0') {
return 0;
}
if (0) fprintf(stderr, "gdm_string: %s\n", str);
if (strstr(str, "gdm-") == str || strstr(str, "Gdm-") == str) {
if (strstr(str, "-greeter") != NULL) {
return 1;
}
}
return 0;
}
static int gdm_still_running(void) {
#if NO_X11
return 0;
#else
Window r, parent;
Window *winlist;
unsigned int nc;
int rc, i;
static XClassHint *classhint = NULL;
XErrorHandler old_handler;
int saw_gdm_name = 0;
/* some times a window can go away before we get to it */
trapped_xerror = 0;
old_handler = XSetErrorHandler(trap_xerror);
if (! classhint) {
classhint = XAllocClassHint();
}
/* we are xlocked. */
rc = XQueryTree_wr(dpy, DefaultRootWindow(dpy), &r, &parent, &winlist, &nc);
if (!rc || winlist == NULL || nc == 0) {
nc = 0;
}
for (i=0; i < (int) nc; i++) {
char *name = NULL;
Window w = winlist[i];
if (XFetchName(dpy, w, &name) && name != NULL) {
saw_gdm_name += gdm_string(name);
XFree_wr(name);
}
classhint->res_name = NULL;
classhint->res_class = NULL;
if (XGetClassHint(dpy, w, classhint)) {
name = classhint->res_name;
if (name != NULL) {
saw_gdm_name += gdm_string(name);
XFree_wr(name);
}
name = classhint->res_class;
if (name != NULL) {
saw_gdm_name += gdm_string(name);
XFree_wr(name);
}
}
if (saw_gdm_name > 0) {
break;
}
}
if (winlist != NULL) {
XFree_wr(winlist);
}
XSync(dpy, False);
XSetErrorHandler(old_handler);
trapped_xerror = 0;
return saw_gdm_name;
#endif
}
static int wm_running(void) {
char *s = getenv("DEBUG_WM_RUNNING");
RAWFB_RET(0)
#if NO_X11
return 0;
#else
/*
* Unfortunately with recent GDM (v2.28), they run gnome-session,
* dbus-launch, and metacity for the Login greeter! So the simple
* XInternAtom checks below no longer work.
*/
if (gdm_still_running()) {
return 0;
}
/* we are xlocked. */
if (XInternAtom(dpy, "_NET_SUPPORTED", True) != None) {
if (s) rfbLog("wm is running (_NET_SUPPORTED).\n");
return 1;
}
if (XInternAtom(dpy, "_WIN_PROTOCOLS", True) != None) {
if (s) rfbLog("wm is running (_WIN_PROTOCOLS).\n");
return 1;
}
if (XInternAtom(dpy, "_XROOTPMAP_ID", True) != None) {
if (s) rfbLog("wm is running (_XROOTPMAP_ID).\n");
return 1;
}
if (XInternAtom(dpy, "_MIT_PRIORITY_COLORS", True) != None) {
if (s) rfbLog("wm is running (_MIT_PRIORITY_COLORS).\n");
return 1;
}
if (s) rfbLog("wm is not running.\n");
return 0;
#endif /* NO_X11 */
}
int guess_dm_gone(int t1, int t2) {
int wait = t2;
char *avoid = getenv("X11VNC_AVOID_WINDOWS");
time_t tcheck = last_client;
if (last_open_xdisplay > last_client) {
/* better time for -display WAIT:... */
tcheck = last_open_xdisplay;
}
if (avoid && !strcmp(avoid, "never")) {
return 1;
}
if (!screen || !screen->clientHead) {
return 0;
}
if (avoid) {
int n = atoi(avoid);
if (n > 1) {
wait = n;
} else {
wait = 90;
}
} else {
static time_t saw_wm = 0;
wait = t2;
X_LOCK;
if (wm_running()) {
if (saw_wm == 0) {
saw_wm = time(NULL);
} else if (time(NULL) <= saw_wm + 2) {
/* try to wait a few seconds after transition */
;
} else {
wait = t1;
}
}
X_UNLOCK;
}
/* we assume they've logged in OK after wait seconds... */
if (time(NULL) <= tcheck + wait) {
return 0;
}
return 1;
}
static void initialize_xevents(int reset) { static void initialize_xevents(int reset) {
#if NO_X11 #if NO_X11
RAWFB_RET_VOID RAWFB_RET_VOID
@ -162,11 +346,17 @@ static void initialize_xevents(int reset) {
if (watch_selection && !did_xcreate_simple_window) { if (watch_selection && !did_xcreate_simple_window) {
/* create fake window for our selection ownership, etc */ /* create fake window for our selection ownership, etc */
X_LOCK; /*
selwin = XCreateSimpleWindow(dpy, rootwin, 0, 0, 1, 1, 0, 0, 0); * We try to delay creating selwin until we are past
X_UNLOCK; * any GDM, (or other KillInitClients=true) manager.
did_xcreate_simple_window = 1; */
if (0) rfbLog("selwin: 0x%lx\n", selwin); if (guess_dm_gone(5, 45)) {
X_LOCK;
selwin = XCreateSimpleWindow(dpy, rootwin, 3, 2, 1, 1, 0, 0, 0);
X_UNLOCK;
did_xcreate_simple_window = 1;
if (! quiet) rfbLog("created selwin: 0x%lx\n", selwin);
}
} }
if ((xrandr || xrandr_maybe) && !did_xrandr) { if ((xrandr || xrandr_maybe) && !did_xrandr) {
@ -190,8 +380,16 @@ static void initialize_xevents(int reset) {
did_clipboard_atom = 1; did_clipboard_atom = 1;
} }
if (xfixes_present && use_xfixes && !did_xfixes) { if (xfixes_present && use_xfixes && !did_xfixes) {
initialize_xfixes(); /*
did_xfixes = 1; * We try to delay creating initializing xfixes until
* we are past the display manager, due to Xorg bug:
* http://bugs.freedesktop.org/show_bug.cgi?id=18451
*/
if (guess_dm_gone(5, 45)) {
initialize_xfixes();
did_xfixes = 1;
if (! quiet) rfbLog("called initialize_xfixes()\n");
}
} }
if (xdamage_present && !did_xdamage) { if (xdamage_present && !did_xdamage) {
initialize_xdamage(); initialize_xdamage();
@ -1182,7 +1380,7 @@ void check_xevents(int reset) {
} }
#endif #endif
#if LIBVNCSERVER_HAVE_LIBXFIXES #if LIBVNCSERVER_HAVE_LIBXFIXES
if (xfixes_present && use_xfixes && xfixes_base_event_type) { if (xfixes_present && use_xfixes && xfixes_first_initialized && xfixes_base_event_type) {
if (XCheckTypedEvent(dpy, xfixes_base_event_type + if (XCheckTypedEvent(dpy, xfixes_base_event_type +
XFixesCursorNotify, &xev)) { XFixesCursorNotify, &xev)) {
got_xfixes_cursor_notify++; got_xfixes_cursor_notify++;
@ -1260,7 +1458,7 @@ void check_xevents(int reset) {
req = "CLIPBOARD"; req = "CLIPBOARD";
} }
if (which != 0 && ! own && have_clients && if (which != 0 && ! own && have_clients &&
XGetSelectionOwner(dpy, atom) != None) { XGetSelectionOwner(dpy, atom) != None && selwin != None) {
XConvertSelection(dpy, atom, XA_STRING, XA_STRING, XConvertSelection(dpy, atom, XA_STRING, XA_STRING,
selwin, CurrentTime); selwin, CurrentTime);
if (debug_sel) { if (debug_sel) {
@ -1501,7 +1699,7 @@ void xcut_receive(char *text, int len, rfbClientPtr cl) {
X_LOCK; X_LOCK;
/* associate this text with PRIMARY (and SECONDARY...) */ /* associate this text with PRIMARY (and SECONDARY...) */
if (set_primary && ! own_primary) { if (set_primary && ! own_primary && selwin != None) {
own_primary = 1; own_primary = 1;
/* we need to grab the PRIMARY selection */ /* we need to grab the PRIMARY selection */
XSetSelectionOwner(dpy, XA_PRIMARY, selwin, CurrentTime); XSetSelectionOwner(dpy, XA_PRIMARY, selwin, CurrentTime);
@ -1511,7 +1709,7 @@ void xcut_receive(char *text, int len, rfbClientPtr cl) {
} }
} }
if (set_clipboard && ! own_clipboard && clipboard_atom != None) { if (set_clipboard && ! own_clipboard && clipboard_atom != None && selwin != None) {
own_clipboard = 1; own_clipboard = 1;
/* we need to grab the CLIPBOARD selection */ /* we need to grab the CLIPBOARD selection */
XSetSelectionOwner(dpy, clipboard_atom, selwin, CurrentTime); XSetSelectionOwner(dpy, clipboard_atom, selwin, CurrentTime);

@ -60,6 +60,7 @@ extern void set_text_chat(rfbClientPtr cl, int l, char *t);
extern int get_keyboard_led_state_hook(rfbScreenInfoPtr s); extern int get_keyboard_led_state_hook(rfbScreenInfoPtr s);
extern int get_file_transfer_permitted(rfbClientPtr cl); extern int get_file_transfer_permitted(rfbClientPtr cl);
extern void get_prop(char *str, int len, Atom prop, Window w); extern void get_prop(char *str, int len, Atom prop, Window w);
extern int guess_dm_gone(int t1, int t2);
#endif /* _X11VNC_XEVENTS_H */ #endif /* _X11VNC_XEVENTS_H */

Loading…
Cancel
Save