From 8d79a63d3c8caca5d0db4827e072f7c773387afa Mon Sep 17 00:00:00 2001 From: runge Date: Sun, 25 Apr 2010 21:05:49 -0400 Subject: [PATCH] incorporate new ultravnc_dsm_helper.c. --- x11vnc/ChangeLog | 4 + x11vnc/README | 19 +- x11vnc/enc.h | 628 ++++++++++++++++++++++++++++++++++++++++--- x11vnc/help.c | 11 +- x11vnc/remote.c | 8 +- x11vnc/scan.c | 3 +- x11vnc/sslhelper.c | 15 ++ x11vnc/x11vnc.1 | 13 +- x11vnc/x11vnc_defs.c | 2 +- 9 files changed, 653 insertions(+), 50 deletions(-) diff --git a/x11vnc/ChangeLog b/x11vnc/ChangeLog index 9c59c06..75505a8 100644 --- a/x11vnc/ChangeLog +++ b/x11vnc/ChangeLog @@ -1,3 +1,7 @@ +2010-04-25 Karl Runge + * x11vnc: incorporate new ultravnc_dsm_helper.c, add pointer_mask + remote control query. Cut openssl default -ping delay. + 2010-04-18 Karl Runge * x11vnc/misc: improvements to demo scripts * x11vnc: Alias -coe for -connect_or_exit. more accurate diff --git a/x11vnc/README b/x11vnc/README index b822bc3..7456442 100644 --- a/x11vnc/README +++ b/x11vnc/README @@ -2,7 +2,7 @@ Copyright (C) 2002-2010 Karl J. Runge All rights reserved. -x11vnc README file Date: Sun Apr 18 17:09:43 EDT 2010 +x11vnc README file Date: Fri Apr 23 00:36:17 EDT 2010 The following information is taken from these URLs: @@ -11183,6 +11183,8 @@ Enhanced TightVNC Viewer (SSVNC: SSL/SSH VNC viewer) (-grab/-graball option). * Fix for Popup menu positioning for old window managers (-popupfix option). + * The VNC Viewer ssvncviewer supports IPv6 natively (no helpers + needed.) The list of 3rd party software bundled in the archive files: * TightVNC Viewer (windows, unix, macosx) @@ -12076,7 +12078,7 @@ x11vnc: a VNC server for real X displays Here are all of x11vnc command line options: % x11vnc -opts (see below for -help long descriptions) -x11vnc: allow VNC connections to real X11 displays. 0.9.10 lastmod: 2010-04-18 +x11vnc: allow VNC connections to real X11 displays. 0.9.10 lastmod: 2010-04-22 x11vnc options: -display disp -auth file -N @@ -12206,7 +12208,7 @@ libvncserver-tight-extension options: % x11vnc -help -x11vnc: allow VNC connections to real X11 displays. 0.9.10 lastmod: 2010-04-18 +x11vnc: allow VNC connections to real X11 displays. 0.9.10 lastmod: 2010-04-22 (type "x11vnc -opts" to just list the options.) @@ -12299,7 +12301,7 @@ Options: -6 IPv6 listening support. In addition to IPv4, the IPv6 address is listened on for incoming connections. - The same port as IPv4 is used. + The same port number as IPv4 is used. NOTE: This x11vnc binary was compiled to have the "-6" IPv6 listening mode ENABLED by default (CPPFLAGS @@ -17258,6 +17260,7 @@ n pointer_y print XQueryPointer y cursor position. pointer_same print XQueryPointer ptr on same screen. pointer_root print XQueryPointer curr ptr rootwin. + pointer_mask print XQueryPointer button and mods mask mouse_x print x11vnc's idea of cursor position. mouse_y print x11vnc's idea of cursor position. noop do nothing. @@ -17567,9 +17570,11 @@ n ext_xrecord ext_xkb ext_xshm ext_xinerama ext_overlay ext_xfixes ext_xdamage ext_xrandr rootwin num_buttons button_mask mouse_x mouse_y grab_state pointer_pos - pointer_x pointer_y pointer_same pointer_root bpp depth - indexed_color dpy_x dpy_y wdpy_x wdpy_y off_x off_y - cdpy_x cdpy_y coff_x coff_y rfbauth passwd viewpasswd + pointer_x pointer_y pointer_same pointer_root + pointer_mask bpp depth indexed_color dpy_x dpy_y wdpy_x + wdpy_y off_x off_y cdpy_x cdpy_y coff_x coff_y rfbauth + passwd viewpasswd + -QD variable Just like -query variable, but returns the default value for that parameter (no running x11vnc server is consulted) diff --git a/x11vnc/enc.h b/x11vnc/enc.h index 4dca954..55d49bb 100644 --- a/x11vnc/enc.h +++ b/x11vnc/enc.h @@ -42,11 +42,12 @@ so, delete this exception statement from your version. /* * ultravnc_dsm_helper.c unix/openssl UltraVNC encryption encoder/decoder. * (also a generic symmetric encryption tunnel) + * (also a generic TCP relay and supports IPv6) * * compile via: - cc -O -o ultravnc_dsm_helper ultravnc_dsm_helper.c -lcrypto - cc -DDBG -O -o ultravnc_dsm_helper ultravnc_dsm_helper.c -lcrypto + 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. @@ -65,6 +66,10 @@ so, delete this exception statement from your version. * e.g. to connect a non-ultra-dsm-vnc viewer to a non-ultra-dsm-vnc server * without using SSH or SSL. * + * It can also be used as a general TCP relay (no encryption.) + * + * It supports IPv6 and so can also be used as a IPv6 gateway. + * * ----------------------------------------------------------------------- * Copyright (C) 2008-2010 Karl J. Runge * All rights reserved. @@ -98,13 +103,28 @@ so, delete this exception statement from your version. static char *usage = "\n" - "usage: ultravnc_dsm_helper cipher keyfile listenport remotehost:port\n" + "ultravnc_dsm_helper: a symmetric encryption tunnel. version 0.2\n" + "\n" + " Created to enable encrypted VNC connections to UltraVNC, it can act as\n" + " a general encrypted tunnel between any two applications. It can also\n" + " be used as a general TCP relay (i.e. no encryption) or an IPv6 gateway.\n" + "\n" + "Usage: ultravnc_dsm_helper cipher keyfile listenport remotehost:port\n" + " ultravnc_dsm_helper relay listenport remotehost:port\n" + " ultravnc_dsm_helper showcert remotehost:port\n" "\n" "e.g.: ultravnc_dsm_helper arc4 ./arc4.key 5901 snoopy.net:5900\n" "\n" - " cipher: specify 'msrc4', 'msrc4_sc', 'arc4', 'aesv2',\n" - " 'aes-cfb', 'aes256', 'blowfish', '3des',\n" - " 'securevnc'.\n" + " IPv6 is supported: both IPv4 and IPv6 are attempted to listen on (port\n" + " 'listenport'.) For connections to remotehost, if IPv4 fails\n" + " then IPv6 is tried. Set the env. var ULTRAVNC_DSM_HELPER_NOIPV6\n" + " to completely disable the use of IPv6.\n" + "\n" + "\n" + " cipher: specify 'msrc4', 'msrc4_sc', 'arc4', 'aesv2', 'aes-cfb',\n" + " 'aes256', 'blowfish', '3des', 'securevnc'.\n" + "\n" + " Also 'none', 'relay', or 'showcert'. See below for details.\n" "\n" " 'msrc4_sc' enables a workaround for UVNC SC -plugin use.\n" " (it might not be required in SC circa 2009 and later; try 'msrc4'.)\n" @@ -127,19 +147,22 @@ static char *usage = " 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" + " use 'noultra:...' to skip steps involving salt and IV to try to be\n" + " compatible with UltraVNC DSM, i.e. assume a normal symmetric cipher\n" + " at the other end.\n" "\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" " E.g. dd if=/dev/random of=./my.key bs=16 count=1\n" " keyfile can also be pw= 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" - " to stdio, use a negative value to force localhost)\n" + " to stdio, use a negative value to force localhost listening)\n" + "\n" "\n" " remotehost:port: host and port to connect to. (e.g. ultravnc server)\n" "\n" @@ -150,6 +173,39 @@ static char *usage = "\n" " Use cipher@md+n,m to change the message digest. E.g. arc4@sha+8,16\n" " Supported: 'md5', 'sha', 'sha1', 'ripemd160'.\n" + "\n" + "\n" + " TCP Relay mode: to connect without any encryption use a cipher type of\n" + " either 'relay' or 'none' (both are the equivalent):\n" + "\n" + " ultravnc_dsm_helper relay listenport remotehost:port\n" + " ultravnc_dsm_helper none listenport remotehost:port\n" + "\n" + " where 'relay' or 'none' is a literal string.\n" + " Note that for this mode no keyfile is suppled.\n" + " Note that this mode can act as an IPv4 to IPv6 gateway.\n" + "\n" + " ultravnc_dsm_helper relay 8080 ipv6.beijing2008.cn:80\n" + "\n" + "\n" + " SSL Show Certificate mode: Set the cipher to 'showcert' to fetch\n" + " the SSL certificate from remotehost:port and print it to the stdout.\n" + " No certificate authentication or verification is performed. E.g.\n" + "\n" + " ultravnc_dsm_helper showcert www.verisign.com:443\n" + "\n" + " (the output resembles that of 'openssl s_client ...') Set the env var\n" + " ULTRAVNC_DSM_HELPER_SHOWCERT_ADH=1 for Anonymous Diffie Hellman mode.\n" + "\n" + "\n" + " Looping Mode: Set the env. var. ULTRAVNC_DSM_HELPER_LOOP=1 to have it\n" + " restart itself after every disconnection in an endless loop. It pauses\n" + " 500 msec before restarting. Use ULTRAVNC_DSM_HELPER_LOOP=N to set the\n" + " pause to N msec.\n" + "\n" + " You can also set the env. var. ULTRAVNC_DSM_HELPER_BG to have the\n" + " program fork into the background for each connection, thereby acting\n" + " as a simple daemon.\n" ; /* @@ -200,6 +256,8 @@ static char *prog = "ultravnc_dsm_helper"; #include #include #include +#include +#include static const EVP_CIPHER *Cipher; static const EVP_MD *Digest; #endif @@ -291,7 +349,7 @@ extern void enc_do(char *ciph, char *keyfile, char *lport, char *rhp) { struct stat sb; char *q, *p, *connect_host; char tmp[16]; - int fd, len = 0, listen_port, connect_port, mbits; + int fd, len = 0, listen_port = 0, connect_port, mbits; q = ciph; @@ -337,6 +395,12 @@ extern void enc_do(char *ciph, char *keyfile, char *lport, char *rhp) { Cipher = EVP_aes_128_ofb(); cipher = "securevnc"; securevnc = 1; + } else if (strstr(q, "none") == q || strstr(q, "relay") == q) { + cipher = "none"; + + } else if (strstr(q, "showcert") == q) { + cipher = "showcert"; + } else if (strstr(q, ".") == q) { /* otherwise, try to guess cipher from key filename: */ if (strstr(keyfile, "arc4.key")) { @@ -433,7 +497,9 @@ extern void enc_do(char *ciph, char *keyfile, char *lport, char *rhp) { } /* port to listen on (0 => stdio, negative => localhost) */ - listen_port = atoi(lport); + if (lport != NULL) { + listen_port = atoi(lport); + } /* extract remote hostname and port */ q = strrchr(rhp, ':'); @@ -449,6 +515,13 @@ extern void enc_do(char *ciph, char *keyfile, char *lport, char *rhp) { /* check for and read in the key file */ memset(keydata, 0, sizeof(keydata)); + if (!strcmp(cipher, "none")) { + goto readed_in; + } + if (!strcmp(cipher, "showcert")) { + goto readed_in; + } + if (securevnc) { /* note the keyfile for rsa verification later */ if (keyfile != NULL && strcasecmp(keyfile, "none")) { @@ -536,6 +609,81 @@ extern void enc_do(char *ciph, char *keyfile, char *lport, char *rhp) { } #endif +static void enc_raw_xfer(int sock_fr, int sock_to) { + + unsigned char buf[BSIZE]; + unsigned char *psrc = NULL; + int len, m, n = 0; + + /* zero the buffers */ + memset(buf, 0, BSIZE); + + /* now loop forever processing the data stream */ + while (1) { + errno = 0; + + /* general case of loop, read some in: */ + n = read(sock_fr, buf, BSIZE); + + if (n == 0 || (n < 0 && errno != EINTR)) { + /* failure to read any data, it is EOF or fatal error */ + int err = errno; + + /* debug output: */ + fprintf(stderr, "%s: input stream finished: n=%d, err=%d", prog, n, err); + + /* EOF or fatal error */ + break; + + } else if (n > 0) { + + /* write data to the other end: */ + len = n; + psrc = buf; + while (len > 0) { + errno = 0; + m = write(sock_to, psrc, len); + + 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 */ + } + } + + /* transfer done (viewer exited or some error) */ + + fprintf(stderr, "\n%s: close sock_to\n", prog); + close(sock_to); + + fprintf(stderr, "%s: close sock_fr\n", prog); + close(sock_fr); + + /* kill our partner after 1 secs. */ + sleep(1); + if (child) { + if (kill(child, SIGTERM) == 0) { + fprintf(stderr, "%s[%d]: killed my partner: %d\n", + prog, (int) getpid(), (int) child); + } + } else { + if (kill(parent, SIGTERM) == 0) { + fprintf(stderr, "%s[%d]: killed my partner: %d\n", + prog, (int) getpid(), (int) parent); + } + } +} + #if ENC_HAVE_OPENSSL /* * Initialize cipher context and then loop till EOF doing transfer & @@ -1368,16 +1516,163 @@ static void securevnc_setup(int conn1, int conn2) { write(viewer, to_viewer, to_viewer_len); } } + +#ifndef ENC_DISABLE_SHOW_CERT +static void enc_sslerrexit(void) { + unsigned long err = ERR_get_error(); + + if (err) { + char str[256]; + ERR_error_string(err, str); + fprintf(stdout, "ssl error: %s\n", str); + } + exit(1); +} +#endif + +static void show_cert(int sock) { +#ifndef ENC_DISABLE_SHOW_CERT + SSL_CTX *ctx; + SSL *ssl = NULL; + STACK_OF(X509) *sk = NULL; + X509 *peer = NULL; + SSL_CIPHER *c; + BIO *bio; + unsigned char *sid = (unsigned char *) "ultravnc_dsm_helper SID"; + long mode; + int i; + + fprintf(stdout, "CONNECTED(%08X)\n",sock); + + SSL_library_init(); + SSL_load_error_strings(); + + if (!RAND_status()) { + RAND_poll(); + } + /* this is not for a secured connection. */ + for (i=0; i < 100; i++) { + if (!RAND_status()) { + char tmp[32]; + sprintf(tmp, "%d", getpid() * (17 + i)); + RAND_add(tmp, strlen(tmp), 5); + } else { + break; + } + } + + ctx = SSL_CTX_new( SSLv23_client_method() ); + if (ctx == NULL) { + fprintf(stdout, "show_cert: SSL_CTX_new failed.\n"); + close(sock); + enc_sslerrexit(); + } + + mode = 0; + mode |= SSL_MODE_ENABLE_PARTIAL_WRITE; + mode |= SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER; + SSL_CTX_set_mode(ctx, mode); + + if (getenv("ULTRAVNC_DSM_HELPER_SHOWCERT_ADH")) { + SSL_CTX_set_cipher_list(ctx, "ADH:@STRENGTH"); + SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); + } + + ssl = SSL_new(ctx); + + if (ssl == NULL) { + fprintf(stdout, "show_cert: SSL_new failed.\n"); + close(sock); + enc_sslerrexit(); + } + + SSL_set_session_id_context(ssl, sid, strlen((char *)sid)); + + if (! SSL_set_fd(ssl, sock)) { + fprintf(stdout, "show_cert: SSL_set_fd failed.\n"); + close(sock); + enc_sslerrexit(); + } + + SSL_set_connect_state(ssl); + + if (SSL_connect(ssl) <= 0) { + unsigned long err = ERR_get_error(); + fprintf(stdout, "show_cert: SSL_connect failed.\n"); + if (err) { + char str[256]; + ERR_error_string(err, str); + fprintf(stdout, "ssl error: %s\n", str); + } + } + + SSL_get_verify_result(ssl); + + sk = SSL_get_peer_cert_chain(ssl); + if (sk != NULL) { + fprintf(stdout, "---\nCertificate chain\n"); + for (i=0; i < sk_X509_num(sk); i++) { + char buf[2048]; + X509_NAME_oneline(X509_get_subject_name(sk_X509_value(sk,i)), buf, sizeof buf); + fprintf(stdout, "%2d s:%s\n", i, buf); + X509_NAME_oneline(X509_get_issuer_name(sk_X509_value(sk,i)), buf, sizeof buf); + fprintf(stdout, " i:%s\n", buf); + } + } else { + fprintf(stdout, "show_cert: SSL_get_peer_cert_chain failed.\n"); + } + fprintf(stdout, "---\n"); + peer = SSL_get_peer_certificate(ssl); + bio = BIO_new_fp(stdout, BIO_NOCLOSE); + if (peer != NULL) { + char buf[2048]; + BIO_printf(bio,"Server certificate\n"); + PEM_write_bio_X509(bio, peer); + + X509_NAME_oneline(X509_get_subject_name(peer), buf, sizeof buf); + BIO_printf(bio,"subject=%s\n",buf); + X509_NAME_oneline(X509_get_issuer_name(peer), buf, sizeof buf); + BIO_printf(bio,"issuer=%s\n",buf); + } else { + fprintf(stdout, "show_cert: SSL_get_peer_certificate failed.\n"); + } + + c = SSL_get_current_cipher(ssl); + BIO_printf(bio,"---\nNew, %s, Cipher is %s\n", SSL_CIPHER_get_version(c), SSL_CIPHER_get_name(c)); + + if (peer != NULL) { + EVP_PKEY *pktmp; + pktmp = X509_get_pubkey(peer); + BIO_printf(bio,"Server public key is %d bit\n", EVP_PKEY_bits(pktmp)); + EVP_PKEY_free(pktmp); + } + BIO_printf(bio,"---\nDONE\n---\n"); + + fflush(stdout); + +#endif + close(sock); + exit(0); +} + +#ifndef SOL_IPV6 +#ifdef IPPROTO_IPV6 +#define SOL_IPV6 IPPROTO_IPV6 +#endif +#endif + /* * 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, one = 1; + int listen_fd = -1, listen_fd6 = -1, conn1 = -1, conn2 = -1, ret, one = 1; socklen_t clen; struct hostent *hp; struct sockaddr_in client, server; + fd_set fds; + int maxfd = -1; /* zero means use stdio (preferably from socketpair()) */ if (listen_port == 0) { @@ -1385,6 +1680,10 @@ static void enc_connections(int listen_port, char *connect_host, int connect_por goto use_stdio; } + if (!strcmp(cipher, "showcert")) { + 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; @@ -1405,25 +1704,95 @@ static void enc_connections(int listen_port, char *connect_host, int connect_por listen_fd = socket(AF_INET, SOCK_STREAM, 0); if (listen_fd < 0) { perror("socket"); - exit(1); + goto try6; } ret = setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)); if (ret < 0) { perror("setsockopt"); - exit(1); + close(listen_fd); + listen_fd = -1; + goto try6; } ret = bind(listen_fd, (struct sockaddr *) &client, sizeof(client)); if (ret < 0) { perror("bind"); - exit(1); + close(listen_fd); + listen_fd = -1; + goto try6; } ret = listen(listen_fd, 2); if (ret < 0) { perror("listen"); + close(listen_fd); + listen_fd = -1; + goto try6; + } + + try6: +#ifdef AF_INET6 + if (!getenv("ULTRAVNC_DSM_HELPER_NOIPV6")) { + struct sockaddr_in6 sin; + int one = 1, sock = -1; + + sock = socket(AF_INET6, SOCK_STREAM, 0); + if (sock < 0) { + perror("socket6"); + goto fail; + } + + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)) < 0) { + perror("setsockopt6 SO_REUSEADDR"); + close(sock); + sock = -1; + goto fail; + } + +#if defined(SOL_IPV6) && defined(IPV6_V6ONLY) + if (setsockopt(sock, SOL_IPV6, IPV6_V6ONLY, (char *)&one, sizeof(one)) < 0) { + perror("setsockopt6 IPV6_V6ONLY"); + close(sock); + sock = -1; + goto fail; + } +#endif + + memset((char *)&sin, 0, sizeof(sin)); + sin.sin6_family = AF_INET6; + + if (listen_port < 0) { + sin.sin6_addr = in6addr_loopback; + sin.sin6_port = htons(-listen_port); + } else { + sin.sin6_addr = in6addr_any; + sin.sin6_port = htons(listen_port); + } + + if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) { + perror("bind6"); + close(sock); + sock = -1; + goto fail; + } + + if (listen(sock, 2) < 0) { + perror("listen6"); + close(sock); + sock = -1; + goto fail; + } + + fail: + listen_fd6 = sock; + } +#endif + + if (listen_fd < 0 && listen_fd6 < 0) { + fprintf(stderr, "%s: could not listen on port: %d\n", + prog, listen_port); exit(1); } @@ -1431,15 +1800,85 @@ static void enc_connections(int listen_port, char *connect_host, int connect_por prog, listen_port); /* wait for a connection: */ - clen = sizeof(client); - conn1 = accept(listen_fd, (struct sockaddr *) &client, &clen); - if (conn1 < 0) { - perror("accept"); + FD_ZERO(&fds); + if (listen_fd >= 0) { + FD_SET(listen_fd, &fds); + if (listen_fd > maxfd) { + maxfd = listen_fd; + } + } + if (listen_fd6 >= 0) { + FD_SET(listen_fd6, &fds); + if (listen_fd6 > maxfd) { + maxfd = listen_fd6; + } + } + if (select(maxfd+1, &fds, NULL, NULL, NULL) <= 0) { + perror("select"); + exit(1); + } + + if (FD_ISSET(listen_fd, &fds)) { + clen = sizeof(client); + conn1 = accept(listen_fd, (struct sockaddr *) &client, &clen); + if (conn1 < 0) { + perror("accept"); + exit(1); + } + } else if (FD_ISSET(listen_fd6, &fds)) { +#ifdef AF_INET6 + struct sockaddr_in6 addr; + socklen_t addrlen = sizeof(addr); + + conn1 = accept(listen_fd6, (struct sockaddr *) &addr, &addrlen); + if (conn1 < 0) { + perror("accept6"); + exit(1); + } +#else + fprintf(stderr, "No IPv6 / AF_INET6 support.\n"); + exit(1); +#endif + } + + if (setsockopt(conn1, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one)) < 0) { + perror("setsockopt TCP_NODELAY"); exit(1); } - /* done with the listening socket: */ - close(listen_fd); + /* done with the listening socket(s): */ + if (listen_fd >= 0) { + close(listen_fd); + } + if (listen_fd6 >= 0) { + close(listen_fd6); + } + + if (getenv("ULTRAVNC_DSM_HELPER_BG")) { + int p, n; + if ((p = fork()) > 0) { + fprintf(stderr, "%s: putting child %d in background.\n", + prog, p); + exit(0); + } else if (p == -1) { + fprintf(stderr, "%s: could not fork\n", prog); + perror("fork"); + exit(1); + } + if (setsid() == -1) { + fprintf(stderr, "%s: setsid failed\n", prog); + perror("setsid"); + exit(1); + } + /* adjust our stdio */ + n = open("/dev/null", O_RDONLY); + dup2(n, 0); + dup2(n, 1); + dup2(n, 2); + if (n > 2) { + close(n); + } + } use_stdio: @@ -1453,8 +1892,7 @@ static void enc_connections(int listen_port, char *connect_host, int connect_por if ((server.sin_addr.s_addr = inet_addr(connect_host)) == htonl(INADDR_NONE)) { if (!(hp = gethostbyname(connect_host))) { perror("gethostbyname"); - close(conn1); - exit(1); + goto tryconn6; } server.sin_addr.s_addr = *(unsigned long *)hp->h_addr; } @@ -1462,18 +1900,92 @@ static void enc_connections(int listen_port, char *connect_host, int connect_por conn2 = socket(AF_INET, SOCK_STREAM, 0); if (conn2 < 0) { perror("socket"); - close(conn1); - exit(1); + goto tryconn6; } if (connect(conn2, (struct sockaddr *)&server, (sizeof(server))) < 0) { perror("connect"); - close(conn1); + goto tryconn6; + } + + tryconn6: +#ifdef AF_INET6 + if (conn2 < 0 && !getenv("ULTRAVNC_DSM_HELPER_NOIPV6")) { + int err; + struct addrinfo *ai; + struct addrinfo hints; + char service[32]; + + fprintf(stderr, "connect[ipv6]: trying to connect via IPv6 to %s\n", connect_host); + conn2 = -1; + + memset(&hints, 0, sizeof(hints)); + sprintf(service, "%d", connect_port); + + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; +#ifdef AI_ADDRCONFIG + hints.ai_flags |= AI_ADDRCONFIG; +#endif +#ifdef AI_NUMERICSERV + hints.ai_flags |= AI_NUMERICSERV; +#endif + + err = getaddrinfo(connect_host, service, &hints, &ai); + if (err != 0) { + fprintf(stderr, "getaddrinfo[%d]: %s\n", err, gai_strerror(err)); + } else { + struct addrinfo *ap = ai; + while (ap != NULL) { + int fd = -1; + fd = socket(ap->ai_family, ap->ai_socktype, ap->ai_protocol); + if (fd == -1) { + perror("socket6"); + } else { + int dmsg = 0; + int res = connect(fd, ap->ai_addr, ap->ai_addrlen); +#if defined(SOL_IPV6) && defined(IPV6_V6ONLY) + if (res != 0) { + int zero = 0; + perror("connect6"); + dmsg = 1; + if (setsockopt(fd, SOL_IPV6, IPV6_V6ONLY, (char *)&zero, sizeof(zero)) == 0) { + fprintf(stderr, "connect[ipv6]: trying again with IPV6_V6ONLY=0\n"); + res = connect(fd, ap->ai_addr, ap->ai_addrlen); + dmsg = 0; + } + } +#endif + if (res == 0) { + conn2 = fd; + break; + } else { + if (!dmsg) perror("connect6"); + close(fd); + } + } + ap = ap->ai_next; + } + freeaddrinfo(ai); + } + } +#endif + if (conn2 < 0) { + fprintf(stderr, "could not connect to %s\n", connect_host); exit(1); } + if (conn2 >= 0 && setsockopt(conn2, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one)) < 0) { + perror("setsockopt TCP_NODELAY"); + } use_input_fds: + if (!strcmp(cipher, "showcert")) { + show_cert(conn2); + close(conn2); + exit(0); + } + if (securevnc) { securevnc_setup(conn1, conn2); } @@ -1495,18 +2007,74 @@ static void enc_connections(int listen_port, char *connect_host, int connect_por if (child == 0) { /* encrypter: local-viewer -> remote-server */ - enc_xfer(conn1, conn2, 1); + if (!strcmp(cipher, "none") || !strcmp(cipher, "relay")) { + enc_raw_xfer(conn1, conn2); + } else { + enc_xfer(conn1, conn2, 1); + } } else { /* decrypter: remote-server -> local-viewer */ - enc_xfer(conn2, conn1, 0); + if (!strcmp(cipher, "none") || !strcmp(cipher, "relay")) { + enc_raw_xfer(conn2, conn1); + } else { + enc_xfer(conn2, conn1, 0); + } } } #endif /* ENC_HAVE_OPENSSL */ +static void doloop (int argc, char *argv[]) { + int ms = atoi(getenv("ULTRAVNC_DSM_HELPER_LOOP")); + if (ms > 0) { + char *cmd; + int i, len = 0; + for (i = 0; i < argc; i++) { + len += strlen(argv[i]) + 2; + } + cmd = (char *)malloc(len); + cmd[0] = '\0'; + for (i = 0; i < argc; i++) { + strcat(cmd, argv[i]); + if (i < argc - 1) { + strcat(cmd, " "); + } + } + + putenv("ULTRAVNC_DSM_HELPER_LOOP_SET=1"); + if (ms == 1) { + ms = 500; + } + i = 0; + while (1) { + fprintf(stderr, "loop running[%d]: %s\n", ++i, cmd); + system(cmd); + usleep(1000 * ms); + } + } +} + extern int main (int argc, char *argv[]) { char *kf, *q; - if (argc < 4) { + if (getenv("ULTRAVNC_DSM_HELPER_LOOP")) { + if (!getenv("ULTRAVNC_DSM_HELPER_LOOP_SET")) { + doloop(argc, argv); + } + } + + if (argc == 3) { + if (!strcmp(argv[1], "showcert")) { + enc_do(argv[1], NULL, NULL, argv[2]); + return 0; + } + } + if (argc == 4) { + if (!strcmp(argv[1], "none") || !strcmp(argv[1], "relay")) { + enc_do(argv[1], NULL, argv[2], argv[3]); + return 0; + } + } + if (argc < 5) { fprintf(stdout, "%s\n", usage); exit(1); } diff --git a/x11vnc/help.c b/x11vnc/help.c index c23112c..1289a42 100644 --- a/x11vnc/help.c +++ b/x11vnc/help.c @@ -144,7 +144,7 @@ void print_help(int mode) { #if X11VNC_IPV6 "-6 IPv6 listening support. In addition to IPv4, the\n" " IPv6 address is listened on for incoming connections.\n" -" The same port as IPv4 is used.\n" +" The same port number as IPv4 is used.\n" "\n" #if X11VNC_LISTEN6 " NOTE: This x11vnc binary was compiled to have the\n" @@ -5131,6 +5131,7 @@ void print_help(int mode) { " pointer_y print XQueryPointer y cursor position.\n" " pointer_same print XQueryPointer ptr on same screen.\n" " pointer_root print XQueryPointer curr ptr rootwin.\n" +" pointer_mask print XQueryPointer button and mods mask\n" " mouse_x print x11vnc's idea of cursor position.\n" " mouse_y print x11vnc's idea of cursor position.\n" " noop do nothing.\n" @@ -5440,9 +5441,11 @@ void print_help(int mode) { " ext_xrecord ext_xkb ext_xshm ext_xinerama ext_overlay\n" " ext_xfixes ext_xdamage ext_xrandr rootwin num_buttons\n" " button_mask mouse_x mouse_y grab_state pointer_pos\n" -" pointer_x pointer_y pointer_same pointer_root bpp depth\n" -" indexed_color dpy_x dpy_y wdpy_x wdpy_y off_x off_y\n" -" cdpy_x cdpy_y coff_x coff_y rfbauth passwd viewpasswd\n" +" pointer_x pointer_y pointer_same pointer_root\n" +" pointer_mask bpp depth indexed_color dpy_x dpy_y wdpy_x\n" +" wdpy_y off_x off_y cdpy_x cdpy_y coff_x coff_y rfbauth\n" +" passwd viewpasswd\n" +"\n" "-QD variable Just like -query variable, but returns the default\n" " value for that parameter (no running x11vnc server\n" " is consulted)\n" diff --git a/x11vnc/remote.c b/x11vnc/remote.c index 2a45d8b..6b2903b 100644 --- a/x11vnc/remote.c +++ b/x11vnc/remote.c @@ -6126,10 +6126,10 @@ char *process_remote_cmd(char *cmd, int stringonly) { } goto qry; } - if (!strcmp(p, "pointer_pos") || !strcmp(p, "pointer_x") || !strcmp(p, "pointer_y") || !strcmp(p, "pointer_same") || !strcmp(p, "pointer_root")) { + if (!strcmp(p, "pointer_pos") || !strcmp(p, "pointer_x") || !strcmp(p, "pointer_y") || !strcmp(p, "pointer_same") || !strcmp(p, "pointer_root") || !strcmp(p, "pointer_mask")) { int px = -1, py = -1; int wx, wy; - unsigned int m; + unsigned int m = 0; Window r, c; Bool same_screen = True; @@ -6144,6 +6144,8 @@ char *process_remote_cmd(char *cmd, int stringonly) { snprintf(buf, bufn, "aro=%s:%d", p, same_screen); } else if (!strcmp(p, "pointer_root")) { /* skip-cmd-list */ snprintf(buf, bufn, "aro=%s:0x%x", p, (unsigned int) rootwin); + } else if (!strcmp(p, "pointer_mask")) { /* skip-cmd-list */ + snprintf(buf, bufn, "aro=%s:0x%x", p, m); } if (!dpy) { goto qry; @@ -6166,6 +6168,8 @@ char *process_remote_cmd(char *cmd, int stringonly) { snprintf(buf, bufn, "aro=%s:%d", p, same_screen); } else if (!strcmp(p, "pointer_root")) { /* skip-cmd-list */ snprintf(buf, bufn, "aro=%s:0x%x", p, (unsigned int) r); + } else if (!strcmp(p, "pointer_mask")) { /* skip-cmd-list */ + snprintf(buf, bufn, "aro=%s:0x%x", p, m); } if (rc_npieces < 10) { rfbLog("remote_cmd: %s: %s\n", p, buf); diff --git a/x11vnc/scan.c b/x11vnc/scan.c index 03a37a0..7ef931c 100644 --- a/x11vnc/scan.c +++ b/x11vnc/scan.c @@ -3014,11 +3014,12 @@ static void ping_clients(int tile_cnt) { if (tile_cnt > 0) { last_send = now; } else if (tile_cnt < 0) { + /* negative tile_cnt is -ping case */ if (now >= last_send - tile_cnt) { mark_rect_as_modified(0, 0, 1, 1, 1); last_send = now; } - } else if (now - last_send > 2) { + } else if (now - last_send > 5) { /* Send small heartbeat to client */ mark_rect_as_modified(0, 0, 1, 1, 1); last_send = now; diff --git a/x11vnc/sslhelper.c b/x11vnc/sslhelper.c index 3fc97b4..0cb120c 100644 --- a/x11vnc/sslhelper.c +++ b/x11vnc/sslhelper.c @@ -2717,6 +2717,19 @@ void openssl_port(int restart) { return; } + if (ipv6_listen && screen->port <= 0) { + if (got_rfbport) { + screen->port = got_rfbport_val; + } else { + int ap = 5900; + if (auto_port > 0) { + ap = auto_port; + } + screen->port = find_free_port6(ap, ap+200); + } + rfbLog("openssl_port: reset port from 0 => %d\n", screen->port); + } + if (restart) { port = screen->port; } else if (screen->listenSock > -1 && screen->port > 0) { @@ -4279,6 +4292,8 @@ if (db) rfbLog("raw_xfer bad write: %d -> %d | %d/%d errno=%d\n", csock, s_out #define ENC_HAVE_OPENSSL 0 #endif +#define ENC_DISABLE_SHOW_CERT + #include "enc.h" static void symmetric_encryption_xfer(int csock, int s_in, int s_out) { diff --git a/x11vnc/x11vnc.1 b/x11vnc/x11vnc.1 index 66ce03b..05a5683 100644 --- a/x11vnc/x11vnc.1 +++ b/x11vnc/x11vnc.1 @@ -2,7 +2,7 @@ .TH X11VNC "1" "April 2010" "x11vnc " "User Commands" .SH NAME x11vnc - allow VNC connections to real X11 displays - version: 0.9.10, lastmod: 2010-04-18 + version: 0.9.10, lastmod: 2010-04-22 .SH SYNOPSIS .B x11vnc [OPTION]... @@ -114,7 +114,7 @@ enter the port number. .IP IPv6 listening support. In addition to IPv4, the IPv6 address is listened on for incoming connections. -The same port as IPv4 is used. +The same port number as IPv4 is used. .IP NOTE: This x11vnc binary was compiled to have the "-6" IPv6 listening mode ENABLED by default (CPPFLAGS @@ -6004,6 +6004,8 @@ pointer_same print XQueryPointer ptr on same screen. .IP pointer_root print XQueryPointer curr ptr rootwin. .IP +pointer_mask print XQueryPointer button and mods mask +.IP mouse_x print x11vnc's idea of cursor position. .IP mouse_y print x11vnc's idea of cursor position. @@ -6411,9 +6413,10 @@ pipeinput clients client_count pid ext_xtest ext_xtrap ext_xrecord ext_xkb ext_xshm ext_xinerama ext_overlay ext_xfixes ext_xdamage ext_xrandr rootwin num_buttons button_mask mouse_x mouse_y grab_state pointer_pos -pointer_x pointer_y pointer_same pointer_root bpp depth -indexed_color dpy_x dpy_y wdpy_x wdpy_y off_x off_y -cdpy_x cdpy_y coff_x coff_y rfbauth passwd viewpasswd +pointer_x pointer_y pointer_same pointer_root +pointer_mask bpp depth indexed_color dpy_x dpy_y wdpy_x +wdpy_y off_x off_y cdpy_x cdpy_y coff_x coff_y rfbauth +passwd viewpasswd .PP \fB-QD\fR \fIvariable\fR .IP diff --git a/x11vnc/x11vnc_defs.c b/x11vnc/x11vnc_defs.c index ac6dfc9..ee335cf 100644 --- a/x11vnc/x11vnc_defs.c +++ b/x11vnc/x11vnc_defs.c @@ -47,7 +47,7 @@ int xtrap_base_event_type = 0; int xdamage_base_event_type = 0; /* date +'lastmod: %Y-%m-%d' */ -char lastmod[] = "0.9.10 lastmod: 2010-04-18"; +char lastmod[] = "0.9.10 lastmod: 2010-04-22"; /* X display info */