summaryrefslogtreecommitdiffstats
path: root/x11vnc/enc.h
diff options
context:
space:
mode:
authorrunge <runge>2008-09-21 23:04:47 +0000
committerrunge <runge>2008-09-21 23:04:47 +0000
commit16c7ea1b357ab518ee5a40f2a663843f064479a9 (patch)
tree4f8cceaaa9920ae1ca6e4cb0468e5d87f1d63326 /x11vnc/enc.h
parenta1e5d55e356f4913169f6dd746b14548cc51695d (diff)
downloadlibvncserver-16c7ea1b357ab518ee5a40f2a663843f064479a9.zip
libvncserver-16c7ea1b357ab518ee5a40f2a663843f064479a9.tar.gz
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.
Diffstat (limited to 'x11vnc/enc.h')
-rw-r--r--x11vnc/enc.h878
1 files changed, 878 insertions, 0 deletions
diff --git a/x11vnc/enc.h b/x11vnc/enc.h
new file mode 100644
index 0000000..d6c195c
--- /dev/null
+++ b/x11vnc/enc.h
@@ -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 */
OpenPOWER on IntegriCloud