x11vnc: Add symmetric key encryption -enc cipher:keyfile,

works with SSVNC.  Make -remap work on MacOSX console.
update to 0.9.5 strings.  Add a couple menu items to tkx11vnc.
pull/1/head
runge 16 years ago
parent a1e5d55e35
commit 16c7ea1b35

@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
VERSION="0.9.4" VERSION="0.9.5"
cd "$(dirname "$0")" cd "$(dirname "$0")"

@ -1,3 +1,8 @@
2008-09-21 Karl Runge <runge@karlrunge.com>
* x11vnc: Add symmetric key encryption -enc cipher:keyfile,
works with SSVNC. Make -remap work on MacOSX console.
update to 0.9.5 strings. Add a couple menu items to tkx11vnc.
2008-09-17 Karl Runge <runge@karlrunge.com> 2008-09-17 Karl Runge <runge@karlrunge.com>
* x11vnc: make -allow work in -ssl mode. * x11vnc: make -allow work in -ssl mode.

@ -21,7 +21,7 @@ LD_CYGIPC=-lcygipc
endif endif
bin_PROGRAMS=x11vnc bin_PROGRAMS=x11vnc
x11vnc_SOURCES = 8to24.c avahi.c cleanup.c connections.c cursor.c gui.c help.c inet.c keyboard.c linuxfb.c macosx.c macosxCG.c macosxCGP.c macosxCGS.c options.c pm.c pointer.c rates.c remote.c scan.c screen.c selection.c solid.c sslcmds.c sslhelper.c uinput.c unixpw.c user.c userinput.c util.c v4l.c win_utils.c x11vnc.c x11vnc_defs.c xdamage.c xevents.c xinerama.c xkb_bell.c xrandr.c xrecord.c xwrappers.c 8to24.h allowed_input_t.h avahi.h blackout_t.h cleanup.h connections.h cursor.h enums.h gui.h help.h inet.h keyboard.h linuxfb.h macosx.h macosxCG.h macosxCGP.h macosxCGS.h nox11.h nox11_funcs.h options.h params.h pm.h pointer.h rates.h remote.h scan.h screen.h scrollevent_t.h selection.h solid.h sslcmds.h sslhelper.h ssltools.h tkx11vnc.h uinput.h unixpw.h user.h userinput.h util.h v4l.h win_utils.h winattr_t.h x11vnc.h xdamage.h xevents.h xinerama.h xkb_bell.h xrandr.h xrecord.h xwrappers.h x11vnc_SOURCES = 8to24.c avahi.c cleanup.c connections.c cursor.c gui.c help.c inet.c keyboard.c linuxfb.c macosx.c macosxCG.c macosxCGP.c macosxCGS.c options.c pm.c pointer.c rates.c remote.c scan.c screen.c selection.c solid.c sslcmds.c sslhelper.c uinput.c unixpw.c user.c userinput.c util.c v4l.c win_utils.c x11vnc.c x11vnc_defs.c xdamage.c xevents.c xinerama.c xkb_bell.c xrandr.c xrecord.c xwrappers.c 8to24.h allowed_input_t.h avahi.h blackout_t.h cleanup.h connections.h cursor.h enc.h enums.h gui.h help.h inet.h keyboard.h linuxfb.h macosx.h macosxCG.h macosxCGP.h macosxCGS.h nox11.h nox11_funcs.h options.h params.h pm.h pointer.h rates.h remote.h scan.h screen.h scrollevent_t.h selection.h solid.h sslcmds.h sslhelper.h ssltools.h tkx11vnc.h uinput.h unixpw.h user.h userinput.h util.h v4l.h win_utils.h winattr_t.h x11vnc.h xdamage.h xevents.h xinerama.h xkb_bell.h xrandr.h xrecord.h xwrappers.h
if HAVE_SYSTEM_LIBVNCSERVER if HAVE_SYSTEM_LIBVNCSERVER
INCLUDES=@SYSTEM_LIBVNCSERVER_CFLAGS@ @X_CFLAGS@ @AVAHI_CFLAGS@ INCLUDES=@SYSTEM_LIBVNCSERVER_CFLAGS@ @X_CFLAGS@ @AVAHI_CFLAGS@

File diff suppressed because it is too large Load Diff

@ -0,0 +1,878 @@
#ifndef _X11VNC_ENC_H
#define _X11VNC_ENC_H
/* -- enc.h -- */
#if 0
:r /home/runge/ultraSC/rc4/ultravnc_dsm_helper.c
#endif
/*
* ultravnc_dsm_helper.c unix/openssl UltraVNC encryption encoder/decoder.
*
* compile via:
cc -O -o ultravnc_dsm_helper ultravnc_dsm_helper.c -lssl -lcrypto
cc -DDBG -O -o ultravnc_dsm_helper ultravnc_dsm_helper.c -lssl -lcrypto
*
* See usage below for how to run it.
*
* Note: since the UltraVNC DSM plugin implementation changes the RFB
* (aka VNC) protocol (extra data is sent), you will *ALSO* need to modify
* your VNC viewer or server to discard (or insert) this extra data.
*
* This tool knows nothing about the RFB protocol: it simply
* encrypts/decrypts a stream using a symmetric cipher, arc4 and aesv2,
* (others have been added, see usage). It could be used as a general
* encrypted tunnel:
*
* any-client <=> ultravnc_dsm_helper <--network--> ultravnc_dsm_helper(reverse mode) <=> any-server
*
* e.g. to connect a non-ultra-dsm-vnc viewer to a non-ultra-dsm-vnc server
*
* -----------------------------------------------------------------------
* Copyright (c) 2008 Karl J. Runge <runge@karlrunge.com>
* All rights reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
* -----------------------------------------------------------------------
*/
static char *usage =
"\n"
"usage: ultravnc_dsm_helper cipher keyfile listenport remotehost:port\n"
"\n"
"e.g.: ultravnc_dsm_helper arc4 ./arc4.key 5901 snoopy.com:5900\n"
"\n"
" cipher: specify 'msrc4', 'msrc4_sc', 'arc4', 'aesv2',\n"
" 'aes-cfb', 'blowfish', or '3des'.\n"
"\n"
" 'msrc4_sc' enables a workaround for UVNC SC -plugin use.\n"
"\n"
" use '.' to have it try to guess the cipher from the keyfile name.\n"
"\n"
" use 'rev:arc4', etc. to reverse the roles of encrypter and decrypter.\n"
" (i.e. if you want to use it for a vnc server, not vnc viewer)\n"
"\n"
" use 'noultra:...' to skip steps involving salt and IV to be compatible\n"
" to be compatible with UltraVNC DSM, i.e. assume a normal symmetric\n"
" cipher at the other end.\n"
"\n"
" use 'noultra:rev:...' if both are to be supplied.\n"
"\n"
" keyfile: file holding the key (16 bytes for arc4 and aesv2, 87 for msrc4)\n"
" E.g. dd if=/dev/random of=./my.key bs=16 count=1\n"
" keyfile can also be pw=<string> to use \"string\" for the key.\n"
"\n"
" listenport: port to listen for incoming connection on. (use 0 to connect\n"
" to stdio, use a negative value to force localhost)\n"
"\n"
" remotehost:port: host and port to connect to. (e.g. ultravnc server)\n"
"\n"
"\n"
" Also: cipher may be cipher@n,m where n is the salt size and m is the\n"
" initialization vector size. E.g. aesv2@8,16\n"
;
/*
* We can also run as a module included into x11vnc (-enc option)
* The includer must set ENC_MODULE and ENC_HAVE_OPENSSL.
*
* Note that when running as a module we still assume we have been
* forked off of the parent process and are communicating back to it
* via a socket. So we still exit(3) at the end or on error. And
* the globals would not work.
*/
#ifdef ENC_MODULE
# define main __enc_main
static char *prog = "enc_helper";
#else
# define ENC_HAVE_OPENSSL 1
static char *prog = "ultravnc_dsm_helper";
#endif
/* unix includes */
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#ifndef INADDR_NONE
#define INADDR_NONE ((in_addr_t) 0xffffffff)
#endif
#if ENC_HAVE_OPENSSL
/* openssl includes */
#include <openssl/evp.h>
#include <openssl/rand.h>
static const EVP_CIPHER *Cipher;
#endif
static char *cipher = NULL; /* name of cipher, e.g. "aesv2" */
static int reverse = 0; /* listening connection */
static int msrc4_sc = 0; /* enables workaround for SC I/II */
static int noultra = 0; /* manage salt and iv differently than ultradsm */
/* The data that was read in from key file (or pw=password) */
static char keydata[1024];
static int keydata_len;
/* Size of salt and IV; based on UltraVNC DSM */
#define SALT 16
#define MSRC4_SALT 11
#define IVEC 16
/* Set default values of salt and IV */
static int salt_size = SALT;
static int ivec_size = IVEC;
/* To track parent and child pids */
static pid_t parent, child;
#define BSIZE 8192
/* Some very verbose debugging stuff I enable for testing */
#ifdef DBG
# include "dbg.h"
#else
# define DEC_CT_DBG(p, n)
# define DEC_PT_DBG(p, n)
# define ENC_CT_DBG(p, n)
# define ENC_PT_DBG(p, n)
# define PRINT_IVEC
# define PRINT_KEYDATA
# define PRINT_KEYSTR_AND_FRIENDS
#endif
static void enc_connections(int, char*, int);
#if !ENC_HAVE_OPENSSL
/* In case we are a module and there is no OpenSSL buildtime support */
extern void enc_do(char *ciph, char *keyfile, char *lport, char *rhp) {
fprintf(stderr, "%s: not compiled with OpenSSL\n", prog);
exit(1);
}
#else
/* If we are a module, enc_do() is the only interface we export. */
/* This works out key type & etc., reads key, calls enc_connections */
extern void enc_do(char *ciph, char *keyfile, char *lport, char *rhp) {
struct stat sb;
char *q, *p, *connect_host;
char tmp[16];
int fd, len, listen_port, connect_port, mbits;
/* check for noultra mode: */
q = ciph;
if (strstr(q, "noultra:") == q) {
noultra = 1;
q += strlen("noultra:");
}
/* check for reverse mode: */
if (strstr(q, "rev:") == q) {
reverse = 1;
q += strlen("rev:");
}
/* work out which cipher and set Cipher to the selected one. */
if (!strcasecmp(q, "msrc4")) {
Cipher = EVP_rc4(); cipher = "msrc4";
} else if (!strcasecmp(q, "msrc4_sc")) {
Cipher = EVP_rc4(); cipher = "msrc4";
msrc4_sc = 1; /* no salt/iv workaround */
} else if (strstr(q, "arc4") == q) {
Cipher = EVP_rc4(); cipher = "arc4";
} else if (strstr(q, "aesv2") == q || strstr(q, "aes-ofb") == q) {
Cipher = EVP_aes_128_ofb(); cipher = "aesv2";
} else if (strstr(q, "aes-cfb") == q) {
Cipher = EVP_aes_128_cfb(); cipher = "aes-cfb";
} else if (strstr(q, "blowfish") == q) {
Cipher = EVP_bf_cfb(); cipher = "blowfish";
} else if (strstr(q, "3des") == q) {
Cipher = EVP_des_ede3_ofb(); cipher = "3des";
} else {
/* otherwise, try to guess cipher from key filename: */
if (strstr(keyfile, "arc4.key")) {
Cipher = EVP_rc4(); cipher = "arc4";
} else if (strstr(keyfile, "rc4.key")) {
Cipher = EVP_rc4(); cipher = "msrc4";
} else if (strstr(keyfile, "aesv2.key")) {
Cipher = EVP_aes_128_ofb(); cipher = "aesv2";
} else if (strstr(keyfile, "aes-cfb.key")) {
Cipher = EVP_aes_128_cfb(); cipher = "aes-cfb";
} else if (strstr(keyfile, "blowfish.key")) {
Cipher = EVP_bf_cfb(); cipher = "blowfish";
} else if (strstr(keyfile, "3des.key")) {
Cipher = EVP_des_ede3_ofb(); cipher = "3des";
} else {
fprintf(stderr, "cannot figure out cipher, supply 'msrc4', 'arc4', or 'aesv2' ...\n");
exit(1);
}
}
/* look for user specified salt and IV sizes at the end: */
p = strchr(q, '@');
if (p) {
int s, v;
if (sscanf(p+1, "%d,%d", &s, &v) == 2) {
if (0 <= s && s <= SALT) {
salt_size = s;
}
if (0 <= v && v <= EVP_MAX_IV_LENGTH) {
ivec_size = v;
}
} else if (sscanf(p+1, "%d", &s) == 1) {
if (0 <= s && s <= SALT) {
salt_size = s;
}
}
}
/* port to listen on (0 => stdio, negative => localhost) */
listen_port = atoi(lport);
/* extract remote hostname and port */
q = strrchr(rhp, ':');
if (q) {
connect_port = atoi(q+1);
*q = '\0';
} else {
/* otherwise guess VNC display 0 ... */
connect_port = 5900;
}
connect_host = strdup(rhp);
/* check for and read in the key file */
if (stat(keyfile, &sb) != 0) {
if (strstr(keyfile, "pw=") == keyfile) {
/* user specified key/password on cmdline */
int i;
len = 0;
for (i=0; i < strlen(keyfile); i++) {
/* load the string to keydata: */
int n = i + strlen("pw=");
keydata[i] = keyfile[n];
if (keyfile[n] == '\0') break;
len++;
}
goto readed_in;
}
perror("stat");
exit(1);
}
if (sb.st_size > 1024) {
fprintf(stderr, "%s: key file too big.\n", prog);
exit(1);
}
fd = open(keyfile, O_RDONLY);
if (fd < 0) {
perror("open");
exit(1);
}
/* read it all in */
len = (int) read(fd, keydata, (size_t) sb.st_size);
if (len != sb.st_size) {
perror("read");
fprintf(stderr, "%s, could not read key file.\n", prog);
exit(1);
}
close(fd);
readed_in:
/* check for ultravnc msrc4 format 'rc4.key' */
mbits = 0;
if (strstr(keydata, "128 bit") == keydata) {
mbits = 128;
} else if (strstr(keydata, " 56 bit") == keydata) {
mbits = 56;
} else if (strstr(keydata, " 40 bit") == keydata) {
mbits = 40;
}
if (mbits > 0) {
/* 4 is for int key length, 12 is for BLOBHEADER. */
int i, offset = strlen("xxx bit") + 4 + 12;
/* the key is stored in reverse order! */
len = mbits/8;
for (i=0; i < len; i++) {
tmp[i] = keydata[offset + len - i - 1];
}
/* clear keydata and then copy the reversed bytes there: */
memset(keydata, 0, sizeof(keydata));
memcpy(keydata, tmp, len);
}
keydata_len = len;
/* initialize random */
RAND_poll();
/*
* Setup connections, then transfer data when they are all
* hooked up.
*/
enc_connections(listen_port, connect_host, connect_port);
}
#endif
#if ENC_HAVE_OPENSSL
/*
* Initialize cipher context and then loop till EOF doing transfer &
* encrypt or decrypt.
*/
static void enc_xfer(int sock_fr, int sock_to, int encrypt) {
/*
* We keep both E and D aspects in case we revert back to a
* single process calling select(2) on all fds...
*/
unsigned char E_keystr[EVP_MAX_KEY_LENGTH];
unsigned char D_keystr[EVP_MAX_KEY_LENGTH];
EVP_CIPHER_CTX E_ctx, D_ctx;
EVP_CIPHER_CTX *ctx;
unsigned char buf[BSIZE], out[BSIZE];
unsigned char *psrc = NULL, *keystr;
unsigned char salt[SALT+1];
unsigned char ivec[EVP_MAX_IV_LENGTH];
int i, cnt, len, n = 0, m, vb = 0, pa = 1, first = 1;
int whoops = 1; /* for the msrc4 problem */
char *encstr;
/* zero the buffers */
memset(buf, 0, BSIZE);
memset(out, 0, BSIZE);
memset(salt, 0, sizeof(salt));
memset(ivec, 0, sizeof(ivec));
memset(E_keystr, 0, sizeof(E_keystr));
memset(D_keystr, 0, sizeof(D_keystr));
if (!strcmp(cipher, "msrc4")) {
salt_size = MSRC4_SALT; /* 11 vs. 16 */
}
if (getenv("ENCRYPT_VERBOSE")) {
vb = 1; /* let user turn on some debugging via env. var. */
}
/*
* reverse mode, e.g. we help a vnc server instead of a viewer.
*/
if (reverse) {
encrypt = (!encrypt);
}
encstr = encrypt ? "encrypt" : "decrypt"; /* string for messages */
if (msrc4_sc) {
whoops = 1;
}
if (encrypt) {
/* encrypter initializes the salt and initialization vector */
/*
* Our salt is 16 bytes but I believe only the first 8
* bytes are used by EVP_BytesToKey(3). Since we send it
* to the other "plugin" we need to keep it 16.
*/
RAND_bytes(salt, salt_size);
RAND_bytes(ivec, ivec_size);
/* place them in the send buffer: */
memcpy(buf, salt, salt_size);
memcpy(buf+salt_size, ivec, ivec_size);
n = salt_size + ivec_size;
ENC_PT_DBG(buf, n);
/* use the encryption context variables below */
ctx = &E_ctx;
keystr = E_keystr;
} else {
/* decrypter needs to read salt + iv from the wire: */
/* sleep 100 ms (TODO: select on fd) */
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 100 * 1000;
select(1, NULL, NULL, NULL, &tv);
n = read(sock_fr, buf, salt_size+ivec_size+96);
if (n == 0 && salt_size+ivec_size > 0) {
fprintf(stderr, "%s: decrypt finished.\n", prog);
goto finished;
}
if (n < salt_size+ivec_size) {
if (msrc4_sc && n == 12) {
fprintf(stderr, "%s: only %d bytes read. Assuming UVNC Single Click server.\n", prog, n);
} else {
if (n < 0) perror("read");
fprintf(stderr, "%s: could not read enough for salt and ivec: n=%d\n", prog, n);
goto finished;
}
}
DEC_CT_DBG(buf, n);
if (msrc4_sc && n == 12) {
; /* send it as is */
} else {
/* extract them to their buffers: */
memcpy(salt, buf, salt_size);
memcpy(ivec, buf+salt_size, ivec_size);
/* the rest is some encrypted data: */
n = n - salt_size - ivec_size;
psrc = buf + salt_size + ivec_size;
if (n > 0) {
/* copy it down to the start of buf for sending below */
for (i=0; i < n; i++) {
buf[i] = psrc[i];
}
}
}
/* use the decryption context variables below */
ctx = &D_ctx;
keystr = D_keystr;
}
/* debug output */
PRINT_KEYDATA;
PRINT_IVEC;
if (!strcmp(cipher, "msrc4")) {
/* special cases for MSRC4: */
if (whoops) {
fprintf(stderr, "%s: %s - WARNING: MSRC4 mode and IGNORING random salt\n", prog, encstr);
fprintf(stderr, "%s: %s - WARNING: and initialization vector!!\n", prog, encstr);
EVP_CIPHER_CTX_init(ctx);
EVP_CipherInit_ex(ctx, Cipher, NULL, (unsigned char *) keydata, NULL, encrypt);
} else {
/* XXX might not be correct */
exit(1);
EVP_BytesToKey(Cipher, EVP_md5(), NULL, keydata, keydata_len, 1, keystr, ivec);
EVP_CIPHER_CTX_init(ctx);
EVP_CipherInit_ex(ctx, Cipher, NULL, keystr, ivec, encrypt);
}
} else {
unsigned char *in_salt;
if (salt_size <= 0) {
/* let salt_size = 0 mean keep it out of the MD5 */
fprintf(stderr, "%s: %s - WARNING: no salt\n", prog, encstr);
in_salt = NULL;
} else {
in_salt = salt;
}
if (ivec_size < Cipher->iv_len) {
fprintf(stderr, "%s: %s - WARNING: short IV %d < %d\n", prog, encstr, ivec_size, Cipher->iv_len);
}
/* make the hashed value and place in keystr */
/* XXX N.B.: DSM plugin had count=0, and overwrote ivec by not passing NULL iv */
if (noultra && ivec_size > 0) {
EVP_BytesToKey(Cipher, EVP_md5(), in_salt, keydata, keydata_len, 1, keystr, NULL);
} else {
/* even under noultra we overwrite ivec if ivec_size = 0 */
EVP_BytesToKey(Cipher, EVP_md5(), in_salt, keydata, keydata_len, 1, keystr, ivec);
}
/* initialize the context */
EVP_CIPHER_CTX_init(ctx);
/* set the cipher & initialize */
/* XXX N.B.: DSM plugin had encrypt=1 for both (i.e. perfectly symmetric) */
EVP_CipherInit_ex(ctx, Cipher, NULL, keystr, ivec, encrypt);
}
/* debug output */
PRINT_KEYSTR_AND_FRIENDS;
/* now loop forever processing the data stream */
while (1) {
errno = 0;
if (first && n > 0) {
if (encrypt && msrc4_sc) {
/* skip sending salt+iv */
first = 0;
continue;
}
/* use that first block of data placed in buf above */
} else {
/* general case of loop, read some in: */
n = read(sock_fr, buf, BSIZE);
}
/* debug output: */
if (vb) fprintf(stderr, "%s%d/%d ", encrypt ? "+" : "-", n, errno);
if (n <= 0) {} else if (encrypt) {ENC_PT_DBG(buf, n);} else {DEC_CT_DBG(buf, n);}
if (n == 0 || (n < 0 && errno != EINTR)) {
/* failure to read any data... it is EOF or fatal error. */
/* debug output: */
char tmp[32]; int err = errno;
if (encrypt) {ENC_PT_DBG("--EOF--", 7);} else {DEC_CT_DBG("--EOF--", 7);}
sprintf(tmp, "err=%d,n=%d", err, n);
fprintf(stderr, "%s: %s - input stream finished: n=%d, err=%d", prog, encstr, n, err);
if (encrypt) {ENC_PT_DBG(tmp, strlen(tmp));} else {DEC_CT_DBG(tmp, strlen(tmp));}
/* EOF or fatal error */
break;
} else if (n > 0) {
/* we read in some data, now transform it: */
if (first && encrypt) {
/* first time, copy the salt and ivec to out[] for sending */
memcpy(out, buf, n);
cnt = n;
} else if (!EVP_CipherUpdate(ctx, out, &cnt, buf, n)) {
/* otherwise, we transform the data */
fprintf(stderr, "%s: enc_xfer EVP_CipherUpdate failed.\n", prog);
break;
}
/* debug output: */
if (vb) fprintf(stderr, "c%d/%d ", cnt, n);
if (encrypt) {ENC_CT_DBG(out, cnt);} else {DEC_PT_DBG(out, cnt);}
/* write transformed data to the other end: */
len = cnt;
psrc = out;
while (len > 0) {
errno = 0;
m = write(sock_to, psrc, len);
/* debug output: */
if (vb) fprintf(stderr, "m%s%d/%d ", encrypt ? "+" : "-", m, errno);
if (m > 0) {
/* scoot them by how much was written: */
psrc += m;
len -= m;
}
if (m < 0 && (errno == EINTR || errno == EAGAIN)) {
/* interrupted or blocked */
continue;
}
/* EOF or fatal error */
break;
}
} else {
/* this is EINTR */
}
first = 0;
}
/* transfer done (viewer exited or some error) */
finished:
fprintf(stderr, "\n%s: %s - close sock_to\n", prog, encstr);
close(sock_to);
fprintf(stderr, "%s: %s - close sock_fr\n", prog, encstr);
close(sock_fr);
/* kill our partner after 2 secs. */
sleep(2);
if (child) {
if (kill(child, SIGTERM) == 0) {
fprintf(stderr, "%s[%d]: %s - killed my partner: %d\n",
prog, (int) getpid(), encstr, (int) child);
}
} else {
if (kill(parent, SIGTERM) == 0) {
fprintf(stderr, "%s[%d]: %s - killed my partner: %d\n",
prog, (int) getpid(), encstr, (int) parent);
}
}
}
/*
* Listens on incoming port for a client, then connects to remote server.
* Then forks into two processes one is the encrypter the other the
* decrypter.
*/
static void enc_connections(int listen_port, char *connect_host, int connect_port) {
int listen_fd, conn1, conn2, ret, n, one = 1;
socklen_t clen;
struct hostent *hp;
struct sockaddr_in client, server;
/* zero means use stdio (preferably from socketpair()) */
if (listen_port == 0) {
conn1 = fileno(stdin);
goto use_stdio;
}
/* fd=n,m means use the supplied already established sockets */
if (sscanf(connect_host, "fd=%d,%d", &conn1, &conn2) == 2) {
goto use_input_fds;
}
/* create the listening socket: */
memset(&client, 0, sizeof(client));
client.sin_family = AF_INET;
if (listen_port < 0) {
/* negative port means use loopback */
client.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
client.sin_port = htons(-listen_port);
} else {
client.sin_addr.s_addr = htonl(INADDR_ANY);
client.sin_port = htons(listen_port);
}
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_fd < 0) {
perror("socket");
exit(1);
}
ret = setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
if (ret < 0) {
perror("setsockopt");
exit(1);
}
ret = bind(listen_fd, (struct sockaddr *) &client, sizeof(client));
if (ret < 0) {
perror("bind");
exit(1);
}
ret = listen(listen_fd, 2);
if (ret < 0) {
perror("listen");
exit(1);
}
fprintf(stderr, "%s: waiting for connection on port: %d\n", prog, listen_port);
/* wait for a connection: */
clen = sizeof(client);
conn1 = accept(listen_fd, (struct sockaddr *) &client, &clen);
if (conn1 < 0) {
perror("accept");
exit(1);
}
/* done with the listening socket: */
close(listen_fd);
use_stdio:
fprintf(stderr, "%s: got connection: %d\n", prog, conn1);
/* now connect to remote server: */
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(connect_port);
if ((server.sin_addr.s_addr = inet_addr(connect_host)) == htonl(INADDR_NONE)) {
if (!(hp = gethostbyname(connect_host))) {
perror("gethostbyname");
close(conn1);
exit(1);
}
server.sin_addr.s_addr = *(unsigned long *)hp->h_addr;
}
conn2 = socket(AF_INET, SOCK_STREAM, 0);
if (conn2 < 0) {
perror("socket");
close(conn1);
exit(1);
}
if (connect(conn2, (struct sockaddr *)&server, (sizeof(server))) < 0) {
perror("connect");
close(conn1);
exit(1);
}
use_input_fds:
/* fork into two processes; one for each direction: */
parent = getpid();
child = fork();
if (child == (pid_t) -1) {
/* couldn't fork... */
perror("fork");
exit(1);
}
/* Do transfer/encode/decode loop: */
if (child == 0) {
/* encrypter: local-viewer -> remote-server */
enc_xfer(conn1, conn2, 1);
} else {
/* decrypter: remote-server -> local-viewer */
enc_xfer(conn2, conn1, 0);
}
}
#endif /* ENC_HAVE_OPENSSL */
extern int main (int argc, char *argv[]) {
char *kf, *q;
if (argc < 4) {
fprintf(stderr, "%s\n", usage);
exit(1);
}
/* guard against pw= on cmdline (e.g. linux) */
kf = strdup(argv[2]);
q = strstr(argv[2], "pw=");
if (q) {
while (*q != '\0') {
*q = '\0';
q++;
}
}
enc_do(argv[1], kf, argv[3], argv[4]);
return 0;
}
/*
* a crude utility to have this work "keyless" i.e. the vnc password
* is used instead of a pre-shared key file.
*/
/*
#!/usr/bin/perl
#
# md5_to_rc4key.pl
#
# This program requires md5sum(1) installed on your machine.
#
# It translates a VNC password to a ultravnc dsm plugin
# compatible key file.
#
# Supply VNC password on cmdline, capture in key file:
#
# md5_to_rc4key.pl swordfish > rc4.key
# md5_to_rc4key.pl -a swordfish > arc4.key
#
# Use rc4.key with ultravnc_dsm_helper in msrc4 mode,
# or arc4.key in either arc4 or aesv4 mode.
#
#
$rfmt = 1;
if ($ARGV[0] eq '-a') {
$rfmt = 0;
shift;
}
# n.b. this is not super secure against bad locals...
$pw = shift;
$tmp = "/tmp/md5out.$$";
open(MD5, "| md5sum > $tmp");
print MD5 $pw;
close MD5;
$md5 = `cat $tmp`;
unlink $tmp;
($md5, $junk) = split(/\s/, $md5);
print "128 bit" if $rfmt;
print 'a' x 4 if $rfmt;
print 'b' x 12 if $rfmt;
$str = '';
foreach $d (split(//, $md5)) {
$str .= $d;
if (length($str) == 2) {
push @key, $str;
$str = '';
}
}
@key = (reverse @key) if $rfmt;
foreach $h (@key) {
$c = pack('c', hex("0x$h"));
print $c;
}
print 'c' x 48 if $rfmt;
*/
#endif /* _X11VNC_ENC_H */

@ -1715,6 +1715,79 @@ void print_help(int mode) {
"-stunnel3 [pem] Use version 3.x stunnel command line syntax instead of\n" "-stunnel3 [pem] Use version 3.x stunnel command line syntax instead of\n"
" version 4.x\n" " version 4.x\n"
"\n" "\n"
"-enc cipher:keyfile Use symmetric encryption with cipher \"cipher\"\n"
" and secret key data in \"keyfile\". If keyfile is\n"
" pw=<string> then \"string\" is used as the key data.\n"
"\n"
" NOTE: It is recommended that you use SSL via the -ssl\n"
" option instead of this option because SSL is well\n"
" understood and takes great care to establish unique\n"
" session keys and is more compatible with other software.\n"
" Use this option if you do not want to deal with SSL\n"
" certificates for authentication and do not want to\n"
" use SSH but want some encryption for your VNC session.\n"
" Or if you must interface with some symmetric key tunnel.\n"
"\n"
" Note that this mode will NOT work with the UltraVNC DSM\n"
" plugins because they alter the RFB protocol in addition\n"
" to tunnelling with the symmetric cipher (an unfortunate\n"
" choice of implementation).\n"
"\n"
" cipher can be one of: arc4, aesv2, aes-cfb, blowfish,\n"
" or 3des. See the OpenSSL documentation for more info.\n"
" The keysize is 128 bits. Here is one way to make a\n"
" keyfile with that many bits:\n"
"\n"
" dd if=/dev/random of=./my.key bs=16 count=1\n"
"\n"
" you will need to securely share this key with the other\n"
" side of the VNC connection (See SSVNC for examples).\n"
"\n"
" Example: -enc blowfish:./my.key\n"
" Example: -enc blowfish:pw=swordfish\n"
"\n"
" By default 16 bytes of random salt followed by 16 bytes\n"
" of random initialization vector are sent at the very\n"
" beginning of the stream. The other side must read these\n"
" and initialize their cipher with them. These values\n"
" make the session key unique (without them the security\n"
" is minimal). Similarly, the other side must send us\n"
" its random salt and IV with those same lengths.\n"
"\n"
" The salt and key data are combined to create a session\n"
" key using an md5 hash as described in EVP_BytesToKey(3).\n"
"\n"
" The exact call is: EVP_BytesToKey(Cipher, EVP_md5(),\n"
" salt, keydata, len, 1, keystr, NULL); where salt is\n"
" the random data as described above, and keydata is the\n"
" shared secret key data. keystr is the resulting session\n"
" key. The cipher is then seeded with keystr and uses\n"
" the random initialization vector as its first block.\n"
"\n"
" To modify the amount of random salt and initialization\n"
" vector use cipher@n,m where n is the salt length and\n"
" m the initialization vector length. E.g.\n"
"\n"
" -enc aes-cfb@8,16:./my.key\n"
"\n"
" It is not a good idea to set either one to zero,\n"
" although you may be forced to if the other side of the\n"
" tunnel is not under your control.\n"
"\n"
" The SSVNC vnc viewer project supplies a symmetric\n"
" encryption tool named \"ultravnc_dsm_helper\" that can\n"
" be used on the viewer side. For example:\n"
"\n"
" ssvncviewer exec='ultravnc_dsm_helper arc4 my.key 0 h:p'\n"
"\n"
" where h:p is the hostname and port of the x11vnc server.\n"
" ultravnc_dsm_helper may also be used standalone to\n"
" provide a symmetric encryption tunnel for any viewer\n"
" or server (VNC or otherwise.)\n"
"\n"
" Also see the 'Non-Ultra DSM' SSVNC option for the\n"
" 'UltraVNC DSM Encryption Plugin' advanced option.\n"
"\n"
"-https [port] Choose a separate HTTPS port (-ssl mode only).\n" "-https [port] Choose a separate HTTPS port (-ssl mode only).\n"
"\n" "\n"
" In -ssl mode, it turns out you can use the\n" " In -ssl mode, it turns out you can use the\n"
@ -2542,6 +2615,9 @@ void print_help(int mode) {
" initial state of the modifier is ignored and not reset)\n" " initial state of the modifier is ignored and not reset)\n"
" To include button events use \"Button1\", ... etc.\n" " To include button events use \"Button1\", ... etc.\n"
"\n" "\n"
" -buttonmap currently does not work on MacOSX console\n"
" or in -rawfb mode.\n"
"\n"
"-nodragging Do not update the display during mouse dragging events\n" "-nodragging Do not update the display during mouse dragging events\n"
" (mouse button held down). Greatly improves response on\n" " (mouse button held down). Greatly improves response on\n"
" slow setups, but you lose all visual feedback for drags,\n" " slow setups, but you lose all visual feedback for drags,\n"

@ -2710,15 +2710,20 @@ static void modifier_tweak_keyboard(rfbBool down, rfbKeySym keysym,
void initialize_keyboard_and_pointer(void) { void initialize_keyboard_and_pointer(void) {
#ifdef MACOSX
if (macosx_console) {
initialize_remap(remap_file);
initialize_pointer_map(pointer_remap);
}
#endif
RAWFB_RET_VOID RAWFB_RET_VOID
if (use_modifier_tweak) { if (use_modifier_tweak) {
initialize_modtweak(); initialize_modtweak();
} }
if (remap_file != NULL) {
initialize_remap(remap_file);
}
initialize_remap(remap_file);
initialize_pointer_map(pointer_remap); initialize_pointer_map(pointer_remap);
clear_modifiers(1); clear_modifiers(1);
@ -2783,13 +2788,67 @@ if (0) fprintf(stderr, "GAI: %s - %s\n", str, cd->input);
} }
} }
static void apply_remap(rfbKeySym *keysym, int *isbutton) {
if (keyremaps) {
keyremap_t *remap = keyremaps;
while (remap != NULL) {
if (remap->before == *keysym) {
*keysym = remap->after;
*isbutton = remap->isbutton;
if (debug_keyboard) {
char *str1, *str2;
X_LOCK;
str1 = XKeysymToString(remap->before);
str2 = XKeysymToString(remap->after);
rfbLog("keyboard(): remapping keysym: "
"0x%x \"%s\" -> 0x%x \"%s\"\n",
(int) remap->before,
str1 ? str1 : "null",
(int) remap->after,
remap->isbutton ? "button" :
str2 ? str2 : "null");
X_UNLOCK;
}
break;
}
remap = remap->next;
}
}
}
/* for -pipeinput mode */ /* for -pipeinput mode */
static void pipe_keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) { static void pipe_keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
int can_input = 0, uid = 0; int can_input = 0, uid = 0, isbutton = 0;
allowed_input_t input; allowed_input_t input;
char *name; char *name;
ClientData *cd = (ClientData *) client->clientData; ClientData *cd = (ClientData *) client->clientData;
apply_remap(&keysym, &isbutton);
if (isbutton) {
int mask, button = (int) keysym;
int x = cursor_x, y = cursor_y;
if (!down) {
return;
}
if (debug_keyboard) {
rfbLog("keyboard(): remapping keystroke to button %d"
" click\n", button);
}
dtime0(&last_key_to_button_remap_time);
/*
* This in principle can be a little dicey... i.e. even
* remap the button click to keystroke sequences!
* Usually just will simulate the button click.
*/
mask = 1<<(button-1);
pointer(mask, x, y, client);
mask = 0;
pointer(mask, x, y, client);
return;
}
if (pipeinput_int == PIPEINPUT_VID) { if (pipeinput_int == PIPEINPUT_VID) {
v4l_key_command(down, keysym, client); v4l_key_command(down, keysym, client);
} else if (pipeinput_int == PIPEINPUT_CONSOLE) { } else if (pipeinput_int == PIPEINPUT_CONSOLE) {
@ -3184,31 +3243,8 @@ void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
RAWFB_RET_VOID RAWFB_RET_VOID
if (keyremaps) {
keyremap_t *remap = keyremaps; apply_remap(&keysym, &isbutton);
while (remap != NULL) {
if (remap->before == keysym) {
keysym = remap->after;
isbutton = remap->isbutton;
if (debug_keyboard) {
char *str1, *str2;
X_LOCK;
str1 = XKeysymToString(remap->before);
str2 = XKeysymToString(remap->after);
rfbLog("keyboard(): remapping keysym: "
"0x%x \"%s\" -> 0x%x \"%s\"\n",
(int) remap->before,
str1 ? str1 : "null",
(int) remap->after,
remap->isbutton ? "button" :
str2 ? str2 : "null");
X_UNLOCK;
}
break;
}
remap = remap->next;
}
}
if (use_xrecord && ! xrecording && down) { if (use_xrecord && ! xrecording && down) {

@ -30,6 +30,7 @@ int http_ssl = 0;
int ssl_no_fail = 0; int ssl_no_fail = 0;
char *openssl_pem = NULL; char *openssl_pem = NULL;
char *ssl_certs_dir = NULL; char *ssl_certs_dir = NULL;
char *enc_str = NULL;
int https_port_num = -1; int https_port_num = -1;
int https_port_redir = 0; int https_port_redir = 0;
char *ssl_verify = NULL; char *ssl_verify = NULL;

@ -30,6 +30,7 @@ extern int http_ssl;
extern int ssl_no_fail; extern int ssl_no_fail;
extern char *openssl_pem; extern char *openssl_pem;
extern char *ssl_certs_dir; extern char *ssl_certs_dir;
extern char *enc_str;
extern int https_port_num; extern int https_port_num;
extern int https_port_redir; extern int https_port_redir;
extern char *ssl_verify; extern char *ssl_verify;

@ -54,7 +54,7 @@ static prtremap_t pointer_map[MAX_BUTTONS+1][MAX_BUTTON_EVENTS];
* For parsing the -buttonmap sections, e.g. "4" or ":Up+Up+Up:" * For parsing the -buttonmap sections, e.g. "4" or ":Up+Up+Up:"
*/ */
static void buttonparse(int from, char **s) { static void buttonparse(int from, char **s) {
#if NO_X11 #if (0 && NO_X11)
if (!from || !s) {} if (!from || !s) {}
return; return;
#else #else
@ -130,7 +130,11 @@ static void buttonparse(int from, char **s) {
*/ */
char *str; char *str;
X_LOCK; X_LOCK;
#if NO_X11
kcode = NoSymbol;
#else
kcode = XKeysymToKeycode(dpy, ksym); kcode = XKeysymToKeycode(dpy, ksym);
#endif
pointer_map[from][n].keysym = ksym; pointer_map[from][n].keysym = ksym;
pointer_map[from][n].keycode = kcode; pointer_map[from][n].keycode = kcode;
@ -216,10 +220,6 @@ static void buttonparse(int from, char **s) {
* process the -buttonmap string * process the -buttonmap string
*/ */
void initialize_pointer_map(char *pointer_remap) { void initialize_pointer_map(char *pointer_remap) {
#if NO_X11
if (!pointer_remap) {}
return;
#else
unsigned char map[MAX_BUTTONS]; unsigned char map[MAX_BUTTONS];
int i, k; int i, k;
/* /*
@ -230,9 +230,13 @@ void initialize_pointer_map(char *pointer_remap) {
*/ */
if (!raw_fb_str) { if (!raw_fb_str) {
#if NO_X11
num_buttons = 5;
#else
X_LOCK; X_LOCK;
num_buttons = XGetPointerMapping(dpy, map, MAX_BUTTONS); num_buttons = XGetPointerMapping(dpy, map, MAX_BUTTONS);
X_UNLOCK; X_UNLOCK;
#endif
} else { } else {
num_buttons = 5; num_buttons = 5;
} }
@ -295,7 +299,6 @@ void initialize_pointer_map(char *pointer_remap) {
} }
free(remap); free(remap);
} }
#endif /* NO_X11 */
} }
/* /*

@ -3080,7 +3080,11 @@ void announce(int lport, int ssl, char *iface) {
if (! ssl) { if (! ssl) {
tvdt = "The VNC desktop is: "; tvdt = "The VNC desktop is: ";
} else { } else {
tvdt = "The SSL VNC desktop is: "; if (enc_str) {
tvdt = "The ENC VNC desktop is: ";
} else {
tvdt = "The SSL VNC desktop is: ";
}
} }
if (iface != NULL && *iface != '\0' && strcmp(iface, "any")) { if (iface != NULL && *iface != '\0' && strcmp(iface, "any")) {
@ -3209,7 +3213,11 @@ void set_vnc_desktop_name(void) {
if (stunnel_port) { if (stunnel_port) {
fprintf(stdout, "SSLPORT=%d\n", stunnel_port); fprintf(stdout, "SSLPORT=%d\n", stunnel_port);
} else if (use_openssl) { } else if (use_openssl) {
fprintf(stdout, "SSLPORT=%d\n", screen->port); if (enc_str) {
fprintf(stdout, "ENCPORT=%d\n", screen->port);
} else {
fprintf(stdout, "SSLPORT=%d\n", screen->port);
}
} }
fflush(stdout); fflush(stdout);
if (flagfile) { if (flagfile) {

@ -702,6 +702,14 @@ void openssl_init(int isclient) {
do_dh = DO_DH; do_dh = DO_DH;
if (enc_str != NULL) {
if (first) {
init_prng();
}
first = 0;
return;
}
if (! quiet) { if (! quiet) {
rfbLog("\n"); rfbLog("\n");
rfbLog("Initializing SSL (%s connect mode).\n", isclient ? "client":"server"); rfbLog("Initializing SSL (%s connect mode).\n", isclient ? "client":"server");
@ -2079,6 +2087,9 @@ static int ssl_init(int s_in, int s_out) {
double start = dnow(); double start = dnow();
int timeout = 20; int timeout = 20;
if (enc_str != NULL) {
return 1;
}
if (getenv("SSL_DEBUG")) { if (getenv("SSL_DEBUG")) {
db = atoi(getenv("SSL_DEBUG")); db = atoi(getenv("SSL_DEBUG"));
} }
@ -2247,6 +2258,8 @@ if (db > 1) fprintf(stderr, "ssl_init: 4\n");
return 1; return 1;
} }
static symmetric_encryption_xfer(int csock, int s_in, int s_out);
static void ssl_xfer(int csock, int s_in, int s_out, int is_https) { static void ssl_xfer(int csock, int s_in, int s_out, int is_https) {
int dbxfer = 0, db = 0, check_pending, fdmax, nfd, n, i, err; int dbxfer = 0, db = 0, check_pending, fdmax, nfd, n, i, err;
char cbuf[ABSIZE], sbuf[ABSIZE]; char cbuf[ABSIZE], sbuf[ABSIZE];
@ -2274,6 +2287,10 @@ static void ssl_xfer(int csock, int s_in, int s_out, int is_https) {
raw_xfer(csock, s_in, s_out); raw_xfer(csock, s_in, s_out);
return; return;
} }
if (enc_str != NULL) {
symmetric_encryption_xfer(csock, s_in, s_out);
return;
}
if (getenv("SSL_DEBUG")) { if (getenv("SSL_DEBUG")) {
db = atoi(getenv("SSL_DEBUG")); db = atoi(getenv("SSL_DEBUG"));
} }
@ -2685,8 +2702,8 @@ void check_https(void) {
#define MSZ 4096 #define MSZ 4096
static void init_prng(void) { static void init_prng(void) {
int db = 0, bytes; int db = 0, bytes, ubytes, fd;
char file[MSZ]; char file[MSZ], dtmp[100];
RAND_file_name(file, MSZ); RAND_file_name(file, MSZ);
@ -2695,19 +2712,42 @@ static void init_prng(void) {
bytes = RAND_load_file(file, -1); bytes = RAND_load_file(file, -1);
if (db) fprintf(stderr, "bytes read: %d\n", bytes); if (db) fprintf(stderr, "bytes read: %d\n", bytes);
bytes += RAND_load_file("/dev/urandom", 64); ubytes = RAND_load_file("/dev/urandom", 64);
if (db) fprintf(stderr, "bytes read: %d\n", bytes); bytes += ubytes;
if (db) fprintf(stderr, "bytes read: %d / %d\n", bytes, ubytes);
/* mix in more predictable stuff as well for fallback */
sprintf(dtmp, "/tmp/p%.8f.XXXXXX", dnow());
fd = mkstemp(dtmp);
RAND_add(dtmp, strlen(dtmp), 0);
if (fd >= 0) {
close(fd);
unlink(dtmp);
}
sprintf(dtmp, "%d-%.8f", (int) getpid(), dnow());
RAND_add(dtmp, strlen(dtmp), 0);
if (!RAND_status()) {
ubytes = -1;
rfbLog("calling RAND_poll()\n");
RAND_poll();
}
if (bytes > 0) { if (bytes > 0) {
if (! quiet) { if (! quiet) {
rfbLog("initialized PRNG with %d random bytes.\n", rfbLog("initialized PRNG with %d random bytes.\n",
bytes); bytes);
} }
if (ubytes > 32 && rnow() < 0.25) {
RAND_write_file(file);
}
return; return;
} }
bytes += RAND_load_file("/dev/random", 8); bytes += RAND_load_file("/dev/random", 8);
if (db) fprintf(stderr, "bytes read: %d\n", bytes); if (db) fprintf(stderr, "bytes read: %d\n", bytes);
RAND_poll();
if (! quiet) { if (! quiet) {
rfbLog("initialized PRNG with %d random bytes.\n", bytes); rfbLog("initialized PRNG with %d random bytes.\n", bytes);
} }
@ -2800,3 +2840,36 @@ if (db) fprintf(stderr, "raw_xfer bad write: %d -> %d | %d/%d errno=%d\n", cso
#endif /* FORK_OK */ #endif /* FORK_OK */
} }
#define ENC_MODULE
#if LIBVNCSERVER_HAVE_LIBSSL
#define ENC_HAVE_OPENSSL 1
#else
#define ENC_HAVE_OPENSSL 0
#endif
#include "enc.h"
static symmetric_encryption_xfer(int csock, int s_in, int s_out) {
char tmp[100];
char *cipher, *keyfile, *q;
if (! enc_str) {
return;
}
cipher = (char *) malloc(strlen(enc_str) + 100);
q = strchr(enc_str, ':');
if (!q) return;
*q = '\0';
if (getenv("X11VNC_USE_ULTRADSM_IV")) {
sprintf(cipher, "rev:%s", enc_str);
} else {
sprintf(cipher, "noultra:rev:%s", enc_str);
}
keyfile = strdup(q+1);
*q = ':';
/* TBD: s_in != s_out */
sprintf(tmp, "fd=%d,%d", s_in, csock);
enc_do(cipher, keyfile, "-1", tmp);
}

@ -127,6 +127,7 @@ Clients
-- D -- D
tightfilexfer tightfilexfer
ultrafilexfer ultrafilexfer
proxy:
=GAL Java-applet:: =GAL Java-applet::
=D http =D http
httpdir: httpdir:
@ -142,6 +143,7 @@ Displays
=S reflect: =S reflect:
=D desktop: =D desktop:
=D rfbport: =D rfbport:
=S autoport
=0 gui: =0 gui:
Screen Screen
@ -267,6 +269,7 @@ Misc
bg bg
=S loop =S loop
=S loopbg =S loopbg
=S sleepin:
=-C:ignore,exit sigpipe: =-C:ignore,exit sigpipe:
=0 inetd =0 inetd
@ -327,6 +330,8 @@ Permissions
=F ssldir: =F ssldir:
=F sslverify: =F sslverify:
ssltimeout: ssltimeout:
--
enc:
=GAL LOFF =GAL LOFF
=GAL Misc-Perms:: =GAL Misc-Perms::
safer safer

@ -138,6 +138,7 @@ char gui_code[] = "";
" -- D\n" " -- D\n"
" tightfilexfer\n" " tightfilexfer\n"
" ultrafilexfer\n" " ultrafilexfer\n"
" proxy:\n"
" =GAL Java-applet::\n" " =GAL Java-applet::\n"
" =D http\n" " =D http\n"
" httpdir:\n" " httpdir:\n"
@ -153,6 +154,7 @@ char gui_code[] = "";
" =S reflect:\n" " =S reflect:\n"
" =D desktop:\n" " =D desktop:\n"
" =D rfbport:\n" " =D rfbport:\n"
" =S autoport\n"
" =0 gui:\n" " =0 gui:\n"
"\n" "\n"
"Screen\n" "Screen\n"
@ -278,6 +280,7 @@ char gui_code[] = "";
" bg\n" " bg\n"
" =S loop\n" " =S loop\n"
" =S loopbg\n" " =S loopbg\n"
" =S sleepin:\n"
" =-C:ignore,exit sigpipe:\n" " =-C:ignore,exit sigpipe:\n"
" =0 inetd\n" " =0 inetd\n"
"\n" "\n"
@ -338,6 +341,8 @@ char gui_code[] = "";
" =F ssldir:\n" " =F ssldir:\n"
" =F sslverify:\n" " =F sslverify:\n"
" ssltimeout:\n" " ssltimeout:\n"
" --\n"
" enc:\n"
" =GAL LOFF\n" " =GAL LOFF\n"
" =GAL Misc-Perms::\n" " =GAL Misc-Perms::\n"
" safer\n" " safer\n"

@ -388,7 +388,7 @@ double dnowx(void) {
} }
double rnow(void) { double rnow(void) {
double t = dnowx(); double t = dnow();
t = t - ((int) t); t = t - ((int) t);
if (t > 1.0) { if (t > 1.0) {
t = 1.0; t = 1.0;

@ -2,7 +2,7 @@
.TH X11VNC "1" "September 2008" "x11vnc " "User Commands" .TH X11VNC "1" "September 2008" "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.4, lastmod: 2008-09-16 version: 0.9.5, lastmod: 2008-09-21
.SH SYNOPSIS .SH SYNOPSIS
.B x11vnc .B x11vnc
[OPTION]... [OPTION]...
@ -1932,6 +1932,82 @@ and SSVNC for more examples.
Use version 3.x stunnel command line syntax instead of Use version 3.x stunnel command line syntax instead of
version 4.x version 4.x
.PP .PP
\fB-enc\fR \fIcipher:keyfile\fR
.IP
Use symmetric encryption with cipher "cipher"
and secret key data in "keyfile". If keyfile is
pw=<string> then "string" is used as the key data.
.IP
NOTE: It is recommended that you use SSL via the \fB-ssl\fR
option instead of this option because SSL is well
understood and takes great care to establish unique
session keys and is more compatible with other software.
Use this option if you do not want to deal with SSL
certificates for authentication and do not want to
use SSH but want some encryption for your VNC session.
Or if you must interface with some symmetric key tunnel.
.IP
Note that this mode will NOT work with the UltraVNC DSM
plugins because they alter the RFB protocol in addition
to tunnelling with the symmetric cipher (an unfortunate
choice of implementation).
.IP
cipher can be one of: arc4, aesv2, aes-cfb, blowfish,
or 3des. See the OpenSSL documentation for more info.
The keysize is 128 bits. Here is one way to make a
keyfile with that many bits:
.IP
dd if=/dev/random of=./my.key bs=16 count=1
.IP
you will need to securely share this key with the other
side of the VNC connection (See SSVNC for examples).
.IP
Example: \fB-enc\fR blowfish:./my.key
Example: \fB-enc\fR blowfish:pw=swordfish
.IP
By default 16 bytes of random salt followed by 16 bytes
of random initialization vector are sent at the very
beginning of the stream. The other side must read these
and initialize their cipher with them. These values
make the session key unique (without them the security
is minimal). Similarly, the other side must send us
its random salt and IV with those same lengths.
.IP
The salt and key data are combined to create a session
key using an md5 hash as described in
.IR EVP_BytesToKey (3).
.IP
The exact call is: EVP_BytesToKey(Cipher, EVP_md5(),
salt, keydata, len, 1, keystr, NULL); where salt is
the random data as described above, and keydata is the
shared secret key data. keystr is the resulting session
key. The cipher is then seeded with keystr and uses
the random initialization vector as its first block.
.IP
To modify the amount of random salt and initialization
vector use cipher@n,m where n is the salt length and
m the initialization vector length. E.g.
.IP
\fB-enc\fR aes-cfb@8,16:./my.key
.IP
It is not a good idea to set either one to zero,
although you may be forced to if the other side of the
tunnel is not under your control.
.IP
The SSVNC vnc viewer project supplies a symmetric
encryption tool named "ultravnc_dsm_helper" that can
be used on the viewer side. For example:
.IP
ssvncviewer exec='ultravnc_dsm_helper arc4 my.key 0 h:p'
.IP
where h:p is the hostname and port of the x11vnc server.
ultravnc_dsm_helper may also be used standalone to
provide a symmetric encryption tunnel for any viewer
or server (VNC or otherwise.)
.IP
Also see the 'Non-Ultra DSM' SSVNC option for the
\'UltraVNC DSM Encryption Plugin' advanced option.
.PP
\fB-https\fR \fI[port]\fR \fB-https\fR \fI[port]\fR
.IP .IP
Choose a separate HTTPS port (-ssl mode only). Choose a separate HTTPS port (-ssl mode only).
@ -2961,6 +3037,10 @@ modifier's up/down state is toggled, e.g. to send
shift down and the 2nd one is shift up). (note: the shift down and the 2nd one is shift up). (note: the
initial state of the modifier is ignored and not reset) initial state of the modifier is ignored and not reset)
To include button events use "Button1", ... etc. To include button events use "Button1", ... etc.
.IP
.IP
\fB-buttonmap\fR currently does not work on MacOSX console
or in \fB-rawfb\fR mode.
.PP .PP
\fB-nodragging\fR \fB-nodragging\fR
.IP .IP

@ -1443,7 +1443,7 @@ static int argc2 = 0;
static char **argv2; static char **argv2;
static void check_rcfile(int argc, char **argv) { static void check_rcfile(int argc, char **argv) {
int i, j, pwlast, norc = 0, argmax = 1024; int i, j, pwlast, enclast, norc = 0, argmax = 1024;
char *infile = NULL; char *infile = NULL;
char rcfile[1024]; char rcfile[1024];
FILE *rc = NULL; FILE *rc = NULL;
@ -1661,6 +1661,7 @@ static void check_rcfile(int argc, char **argv) {
free(buf); free(buf);
} }
pwlast = 0; pwlast = 0;
enclast = 0;
for (i=1; i < argc; i++) { for (i=1; i < argc; i++) {
argv2[argc2++] = strdup(argv[i]); argv2[argc2++] = strdup(argv[i]);
@ -1674,6 +1675,18 @@ static void check_rcfile(int argc, char **argv) {
} }
strzero(p); strzero(p);
} }
if (enclast || !strcmp("-enc", argv[i])) {
char *q, *p = argv[i];
if (enclast) {
enclast = 0;
} else {
enclast = 1;
}
q = strstr(p, "pw=");
if (q) {
strzero(q);
}
}
if (argc2 >= argmax) { if (argc2 >= argmax) {
fprintf(stderr, "too many rcfile options\n"); fprintf(stderr, "too many rcfile options\n");
exit(1); exit(1);
@ -2760,6 +2773,11 @@ int main(int argc, char* argv[]) {
i++; i++;
} }
} }
} else if (!strcmp(arg, "-enc")) {
char *q;
use_openssl = 1;
CHECK_ARGC
enc_str = strdup(argv[++i]);
} else if (!strcmp(arg, "-ssltimeout")) { } else if (!strcmp(arg, "-ssltimeout")) {
CHECK_ARGC CHECK_ARGC
ssl_timeout_secs = atoi(argv[++i]); ssl_timeout_secs = atoi(argv[++i]);
@ -4949,3 +4967,5 @@ if (0) fprintf(stderr, "XA: %s\n", getenv("XAUTHORITY"));
#undef argv #undef argv
} }

@ -15,7 +15,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.4 lastmod: 2008-09-16"; char lastmod[] = "0.9.5 lastmod: 2008-09-21";
/* X display info */ /* X display info */

Loading…
Cancel
Save