diff --git a/x11vnc/ChangeLog b/x11vnc/ChangeLog index 75505a8..1a03b2c 100644 --- a/x11vnc/ChangeLog +++ b/x11vnc/ChangeLog @@ -1,3 +1,12 @@ +2010-05-01 Karl Runge + * x11vnc: X11VNC_DISABLE_SSL_CLIENT_MODE option to disable SSL + client role in reverse connections. Improvements to logging in + ultravnc_repeater, ULTRAVNC_REPEATER_NO_RFB option. Increase + SSL timeout and print message if 'repeater' mode is detected for + reverse SSL connection. Fix RECORD scroll XCopyArea detection + with recent gtk/gdk library; set X11VNC_SCROLL_MUST_EQUAL + to disable. Limit logging of RECORD error messages. + 2010-04-25 Karl Runge * x11vnc: incorporate new ultravnc_dsm_helper.c, add pointer_mask remote control query. Cut openssl default -ping delay. diff --git a/x11vnc/README b/x11vnc/README index 7456442..2f5032b 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: Fri Apr 23 00:36:17 EDT 2010 +x11vnc README file Date: Fri Apr 30 00:43:58 EDT 2010 The following information is taken from these URLs: @@ -34,7 +34,8 @@ x11vnc: a VNC server for real X displays advertising; and TightVNC and UltraVNC file-transfer. It has also been extended to work with non-X devices: natively on Mac OS X Aqua/Quartz, webcams and TV tuner capture devices, and embedded Linux systems such - as Qtopia Core. More features are described here. + as Qtopia Core. Full IPv6 support is provided. More features are + described here. It also provides an encrypted Terminal Services mode (-create, -svc, or -xdmsvc options) based on Unix usernames and Unix passwords where @@ -56,14 +57,10 @@ x11vnc: a VNC server for real X displays to many problems; and interesting applications, but nevertheless please feel free to contact me if you have problems or questions (and if I save you time or expense by giving you some of my time, please - consider a PayPal Donation.) - - Do check the FAQ and this page first; I realize the pages are massive, - but you can often use your browser's find-in-page search action using - a keyword to find the answer to your problem or question. - - Please help test the performance speedup feature using viewer-side - pixel caching "ncache". + consider a PayPal Donation.) Do check the FAQ and this page first; I + realize the pages are massive, but you can often use your browser's + find-in-page search action using a keyword to find the answer to your + problem or question. SSVNC: An x11vnc side-project provides an Enhanced TightVNC Viewer package (SSVNC) for Unix, Windows, and Mac OS X with automatic SSL @@ -948,14 +945,16 @@ make from being downloaded successfully in single-port HTTPS/VNC inetd mode. The env. var. X11VNC_HTTPS_DOWNLOAD_WAIT_TIME can be used to adjust for how many seconds a -inetd or -https httpd download is - waited for (default 15 seconds.) - * The TightVNC sercurity type (TightVNC features enabler) now works + waited for (default 15 seconds.) The applet will now autodetect + x11vnc and use GET=1 for faster connecting. Many other + improvements and fixes. + * The TightVNC security type (TightVNC features enabler) now works for RFB version 3.8. * The X property X11VNC_TRAP_XRANDR can be set on a desktop to force x11vnc to use the -xrandr screen size change trapping code. * New remote control query options: pointer_x, pointer_y, - pointer_same, and pointer_root. A demo script using them - misc/panner.pl is provided. + pointer_same, pointer_root, and pointer_mask. A demo script using + them misc/panner.pl is provided. * The -sslScripts option prints out the SSL certificate management scripts. @@ -1567,7 +1566,9 @@ LAY * Using -threads can expose some bugs/crashes in libvncserver. Please feel free to contact me if you have any questions, problems, or - comments about x11vnc, etc. + comments about x11vnc, etc. Please be polite, thorough, and not + demanding (sadly, the number of people contacting me that are rude and + demanding is increasing dramatically.) Also, some people ask if they can make a donation, see this link for that. @@ -2234,8 +2235,8 @@ libssl.so libcrypto.so libcrypt.so This is most likely due to you not having a working build environment for the XTEST client library libXtst.so. The library is probably - present on your system, but the package installing the development - header file is missing. + present on your system, but the package installing the build header + file is missing. If you were watching carefully while configure was running you would have seen: @@ -12078,7 +12079,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-22 +x11vnc: allow VNC connections to real X11 displays. 0.9.10 lastmod: 2010-04-28 x11vnc options: -display disp -auth file -N @@ -12208,7 +12209,7 @@ libvncserver-tight-extension options: % x11vnc -help -x11vnc: allow VNC connections to real X11 displays. 0.9.10 lastmod: 2010-04-22 +x11vnc: allow VNC connections to real X11 displays. 0.9.10 lastmod: 2010-04-28 (type "x11vnc -opts" to just list the options.) @@ -12786,6 +12787,28 @@ Options: See also the -proxy option below for additional ways to plumb reverse connections. + Reverse SSL: using -connect in -ssl mode makes x11vnc + act as an SSL client (initiates SSL connection) rather + than an SSL server. The idea is x11vnc might be + connecting to stunnel on the viewer side with the + viewer in listening mode. If you do not want this + behavior, use -env X11VNC_DISABLE_SSL_CLIENT_MODE=1. + With this the viewer side can act as the SSL client + as it normally does for forward connections. + + Reverse SSL Repeater mode: This will work, but note + that if the VNC Client does any sort of a 'Fetch Cert' + action before connecting, then the Repeater will + likely drop the connection and both sides will need + to restart. Consider the use of -connect_or_exit + and -loop300,2 to have x11vnc reconnect once to the + repeater after the fetch. You will probably also want + to supply -sslonly to avoid x11vnc thinking the delay + in response means the connection is VeNCrypt. The env + var X11VNC_DISABLE_SSL_CLIENT_MODE=1 discussed above + may also be useful (i.e. the viewer can do a forward + connection as it normally does.) + IPv6: as of x11vnc 0.9.10 the -connect option should connect to IPv6 hosts properly. If there are problems you can disable IPv6 by setting -DX11VNC_IPV6=0 diff --git a/x11vnc/connections.c b/x11vnc/connections.c index c664377..246acae 100644 --- a/x11vnc/connections.c +++ b/x11vnc/connections.c @@ -2644,7 +2644,9 @@ static int do_reverse_connect(char *str_in) { } /* XXX use header */ #define OPENSSL_REVERSE 6 - openssl_init(1); + if (!getenv("X11VNC_DISABLE_SSL_CLIENT_MODE")) { + openssl_init(1); + } if (first_conn_timeout > 0) { set_alarm = 1; diff --git a/x11vnc/help.c b/x11vnc/help.c index 1289a42..90dddfd 100644 --- a/x11vnc/help.c +++ b/x11vnc/help.c @@ -642,6 +642,28 @@ void print_help(int mode) { " See also the -proxy option below for additional ways\n" " to plumb reverse connections.\n" "\n" +" Reverse SSL: using -connect in -ssl mode makes x11vnc\n" +" act as an SSL client (initiates SSL connection) rather\n" +" than an SSL server. The idea is x11vnc might be\n" +" connecting to stunnel on the viewer side with the\n" +" viewer in listening mode. If you do not want this\n" +" behavior, use -env X11VNC_DISABLE_SSL_CLIENT_MODE=1.\n" +" With this the viewer side can act as the SSL client\n" +" as it normally does for forward connections.\n" +"\n" +" Reverse SSL Repeater mode: This will work, but note\n" +" that if the VNC Client does any sort of a 'Fetch Cert'\n" +" action before connecting, then the Repeater will\n" +" likely drop the connection and both sides will need\n" +" to restart. Consider the use of -connect_or_exit\n" +" and -loop300,2 to have x11vnc reconnect once to the\n" +" repeater after the fetch. You will probably also want\n" +" to supply -sslonly to avoid x11vnc thinking the delay\n" +" in response means the connection is VeNCrypt. The env\n" +" var X11VNC_DISABLE_SSL_CLIENT_MODE=1 discussed above\n" +" may also be useful (i.e. the viewer can do a forward\n" +" connection as it normally does.)\n" +"\n" " IPv6: as of x11vnc 0.9.10 the -connect option should\n" " connect to IPv6 hosts properly. If there are problems\n" " you can disable IPv6 by setting -DX11VNC_IPV6=0\n" diff --git a/x11vnc/misc/ultravnc_repeater.pl b/x11vnc/misc/ultravnc_repeater.pl index 5528bed..00ade34 100755 --- a/x11vnc/misc/ultravnc_repeater.pl +++ b/x11vnc/misc/ultravnc_repeater.pl @@ -50,6 +50,8 @@ ULTRAVNC_REPEATER_LOOP=1 or ULTRAVNC_REPEATER_LOOP=BG, the latter forks into the background. Set ULTRAVNC_REPEATER_PIDFILE to a file to store the master pid in. +Set ULTRAVNC_REPEATER_NO_RFB=1 to disable sending "RFB 000.000" to +the client. Then this program acts as general TCP rendezvous tool. Examples: @@ -83,7 +85,7 @@ my $looppid = ''; my $pidfile = ''; # sub get_out { - print STDERR "$_[0]:\t$$ looppid=$looppid\n"; + lprint("$_[0]:\t$$ looppid=$looppid"); if ($looppid) { kill 'TERM', $looppid; fsleep(0.2); @@ -93,6 +95,10 @@ sub get_out { exit 0; } +sub lprint { + print STDERR scalar(localtime), ": ", @_, "\n"; +} + # These are overridden in actual server thread: # $SIG{INT} = \&get_out; @@ -108,7 +114,7 @@ sub open_pidfile { close PID; $pidfile = $pf; } else { - print STDERR "could not open pidfile: $pf - $! - continuing...\n"; + lprint("could not open pidfile: $pf - $! - continuing..."); } delete $ENV{ULTRAVNC_REPEATER_PIDFILE}; } @@ -150,7 +156,7 @@ if (exists $ENV{ULTRAVNC_REPEATER_LOOP}) { open_pidfile(); } - print STDERR "ultravnc_repeater.pl: starting service at ", scalar(localtime), " master-pid=$$\n"; + lprint("ultravnc_repeater.pl: starting service. master-pid=$$"); while (1) { $looppid = fork; if (! defined $looppid) { @@ -161,7 +167,7 @@ if (exists $ENV{ULTRAVNC_REPEATER_LOOP}) { exec $0, @ARGV; exit 1; } - print STDERR "ultravnc_repeater.pl: re-starting service at ", scalar(localtime), " master-pid=$$\n"; + lprint("ultravnc_repeater.pl: re-starting service. master-pid=$$"); sleep 1; } exit 0; @@ -184,7 +190,7 @@ eval "use IO::Socket::INET6;"; $have_inet6 = 1 if $@ eq ""; print "perl module IO::Socket::INET6 not available: no IPv6 support.\n" if ! $have_inet6; -my $prog = 'ultravnc_repeater.pl'; +my $prog = 'ultravnc_repeater'; my %ID; my $refuse = 0; @@ -196,7 +202,7 @@ if (@ARGV && $ARGV[0] =~ /-h/) { } if (@ARGV && $ARGV[0] eq '-r') { $refuse = 1; - print "enabling refuse mode (-r).\n"; + lprint("enabling refuse mode (-r)."); shift; } @@ -285,15 +291,16 @@ my $SOCK1 = ''; my $SOCK2 = ''; my $CURR = ''; -print "watching for IPv4 connections on $client_port/client\n" if $client_listen; -print "watching for IPv4 connections on $server_port/server\n" if $server_listen; -print "watching for IPv6 connections on $client_port/client\n" if $client_listen6; -print "watching for IPv6 connections on $server_port/server\n" if $server_listen6; +lprint("$prog: starting up. pid: $$"); +lprint("watching for IPv4 connections on $client_port/client.") if $client_listen; +lprint("watching for IPv4 connections on $server_port/server.") if $server_listen; +lprint("watching for IPv6 connections on $client_port/client.") if $client_listen6; +lprint("watching for IPv6 connections on $server_port/server.") if $server_listen6; my $alarm_sock = ''; my $got_alarm = 0; sub alarm_handler { - print "$prog: got sig alarm.\n"; + lprint("$prog: got sig alarm."); if ($alarm_sock ne '') { close $alarm_sock; } @@ -303,24 +310,28 @@ sub alarm_handler { while (my @ready = $select->can_read()) { foreach my $fh (@ready) { - if ($fh == $client_listen || $fh == $client_listen6) { - print "new vnc client connecting at ", scalar(localtime), "\n"; - } elsif ($fh == $server_listen || $fh == $server_listen6) { - print "new vnc server connecting at ", scalar(localtime), "\n"; + if (($client_listen && $fh == $client_listen) || ($client_listen6 && $fh == $client_listen6)) { + lprint("new vnc client connecting."); + } elsif (($server_listen && $fh == $server_listen) || ($server_listen6 && $fh == $server_listen6)) { + lprint("new vnc server connecting."); } my $sock = $fh->accept(); if (! $sock) { - print "$prog: accept $!\n"; + lprint("$prog: accept $!"); next; } - if ($fh == $client_listen || $fh == $client_listen6) { - my $str = "RFB 000.000\n"; - my $len = length $str; - my $n = syswrite($sock, $str, $len, 0); - if ($n != $len) { - print "$prog: bad $str write: $n != $len $!\n"; - close $sock; + if (($client_listen && $fh == $client_listen) || ($client_listen6 && $fh == $client_listen6)) { + if (exists $ENV{ULTRAVNC_REPEATER_NO_RFB} && $ENV{ULTRAVNC_REPEATER_NO_RFB}) { + lprint("ULTRAVNC_REPEATER_NO_RFB: not sending RFB 000.000"); + } else { + my $str = "RFB 000.000\n"; + my $len = length $str; + my $n = syswrite($sock, $str, $len, 0); + if ($n != $len) { + lprint("$prog: bad $str write: $n != $len $!"); + close $sock; + } } } @@ -336,15 +347,15 @@ while (my @ready = $select->can_read()) { alarm(0); if ($got_alarm) { - print "$prog: read timed out: $!\n"; + lprint("$prog: read timed out: $!"); } elsif (! defined $n) { - print "$prog: read error: $!\n"; + lprint("$prog: read error: $!"); } elsif ($repeater_bufsize > 0 && $n != $size) { - print "$prog: short read $n != $size $!\n"; + lprint("$prog: short read $n != $size $!"); close $sock; - } elsif ($fh == $client_listen || $fh == $client_listen6) { + } elsif (($client_listen && $fh == $client_listen) || ($client_listen6 && $fh == $client_listen6)) { do_new_client($sock, $buf); - } elsif ($fh == $server_listen || $fh == $server_listen6) { + } elsif (($server_listen && $fh == $server_listen) || ($server_listen6 && $fh == $server_listen6)) { do_new_server($sock, $buf); } } @@ -355,33 +366,42 @@ sub do_new_client { if ($buf =~ /^ID:(\w+)/) { my $id = $1; + if (exists $ID{$id} && exists $ID{$id}{client} && $ID{$id}{client} eq "0") { + if (!established($ID{$id}{sock})) { + lprint("server socket for ID:$id is no longer established, closing it."); + close $ID{$id}{sock}; + delete $ID{$id}; + } else { + lprint("server socket for ID:$id is still established."); + } + } if (exists $ID{$id}) { if ($ID{$id}{client}) { my $ref = $refuse; if ($ref && !established($ID{$id}{sock})) { - print "socket for ID:$id is no longer established, closing it.\n"; + lprint("socket for ID:$id is no longer established, closing it."); $ref = 0; } if ($ref) { - print "refusing extra vnc client for ID:$id\n"; + lprint("refusing extra vnc client for ID:$id."); close $sock; return; } else { - print "closing and deleting previous vnc client with ID:$id\n"; + lprint("closing and deleting previous vnc client with ID:$id."); close $ID{$id}{sock}; - print "storing new vnc client with ID:$id\n"; + lprint("storing new vnc client with ID:$id."); $ID{$id}{client} = 1; $ID{$id}{sock} = $sock; } } else { - print "hooking up new vnc client with existing vnc server for ID:$id\n"; + lprint("hooking up new vnc client with existing vnc server for ID:$id."); my $sock2 = $ID{$id}{sock}; delete $ID{$id}; hookup($sock, $sock2, "ID:$id"); } } else { - print "storing new vnc client with ID:$id\n"; + lprint("storing new vnc client with ID:$id."); $ID{$id}{client} = 1; $ID{$id}{sock} = $sock; } @@ -400,32 +420,32 @@ sub do_new_client { } if ($port < 0) { my $pnew = -$port; - print "resetting port from $port to $pnew\n"; + lprint("resetting port from $port to $pnew."); $port = $pnew; } elsif ($port < 200) { my $pnew = $port + 5900; - print "resetting port from $port to $pnew\n"; + lprint("resetting port from $port to $pnew."); $port = $pnew; } - print "making vnc client connection directly to vnc server host='$host' port='$port'\n"; + lprint("making vnc client connection directly to vnc server host='$host' port='$port'."); my $sock2 = IO::Socket::INET->new( PeerAddr => $host, PeerPort => $port, Proto => "tcp" ); if (! $sock2 && $have_inet6) { - print "IPv4 connect error: $!, trying IPv6 ...\n"; + lprint("IPv4 connect error: $!, trying IPv6 ..."); eval{$sock2 = IO::Socket::INET6->new( PeerAddr => $host, PeerPort => $port, Proto => "tcp" );}; - print "IPv6 connect error: $!\n" if !$sock2; + lprint("IPv6 connect error: $!") if !$sock2; } else { - print "IPv4 connect error: $!\n" if !$sock2; + lprint("IPv4 connect error: $!") if !$sock2; } if (!$sock2) { - print "failed to connect to $host:$port\n"; + lprint("failed to connect to $host:$port."); close $sock; return; } @@ -439,48 +459,79 @@ sub do_new_server { if ($buf =~ /^ID:(\w+)/) { my $id = $1; my $store = 1; + if (exists $ID{$id} && exists $ID{$id}{client} && $ID{$id}{client} eq "1") { + if (!established($ID{$id}{sock})) { + lprint("client socket for ID:$id is no longer established, closing it."); + close $ID{$id}{sock}; + delete $ID{$id}; + } else { + lprint("client socket for ID:$id is still established."); + } + } if (exists $ID{$id}) { if (! $ID{$id}{client}) { my $ref = $refuse; if ($ref && !established($ID{$id}{sock})) { - print "socket for ID:$id is no longer established, closing it.\n"; + lprint("socket for ID:$id is no longer established, closing it."); $ref = 0; } if ($ref) { - print "refusing extra vnc server for ID:$id\n"; + lprint("refusing extra vnc server for ID:$id."); close $sock; return; } else { - print "closing and deleting previous vnc server with ID:$id\n"; + lprint("closing and deleting previous vnc server with ID:$id."); close $ID{$id}{sock}; - print "storing new vnc server with ID:$id\n"; + lprint("storing new vnc server with ID:$id."); $ID{$id}{client} = 0; $ID{$id}{sock} = $sock; } } else { - print "hooking up new vnc server with existing vnc client for ID:$id\n"; + lprint("hooking up new vnc server with existing vnc client for ID:$id."); my $sock2 = $ID{$id}{sock}; delete $ID{$id}; hookup($sock, $sock2, "ID:$id"); } } else { - print "storing new vnc server with ID:$id\n"; + lprint("storing new vnc server with ID:$id."); $ID{$id}{client} = 0; $ID{$id}{sock} = $sock; } } else { - print "invalid ID:NNNNN string for vnc server: $buf\n"; + lprint("invalid ID:NNNNN string for vnc server: $buf"); close $sock; return; } } sub established { + my $fh = shift; + + return established_linux_proc($fh); + + # not working: + my $est = 1; + my $str = "Z"; + my $res; + #$res = recv($fh, $str, 1, MSG_PEEK | MSG_DONTWAIT); + if (defined($res)) { + lprint("established OK: $! '$str'."); + $est = 1; + } else { + # would check for EAGAIN here to decide ... + lprint("established err: $! '$str'."); + $est = 1; + } + return $est; +} + + +sub established_linux_proc { # hack for Linux to see if remote side has gone away: my $fh = shift; - # if we can't figure things out, we return true. + # if we can't figure things out, we must return true. if ($uname !~ /Linux/) { return 1; } @@ -549,7 +600,7 @@ sub established { } sub handler { - print STDERR "$prog\[$$/$CURR]: got SIGTERM.\n"; + lprint("\[$$/$CURR] got SIGTERM."); close $SOCK1 if $SOCK1; close $SOCK2 if $SOCK2; exit; @@ -561,7 +612,7 @@ sub hookup { my $worker = fork(); if (! defined $worker) { - print "failed to fork worker: $!\n"; + lprint("failed to fork worker: $!"); close $sock1; close $sock2; return; @@ -604,10 +655,10 @@ sub xfer { my $len = sysread($in, $buf, 8192); if (! defined($len)) { next if $! =~ /^Interrupted/; - print STDERR "$prog\[$$/$CURR]: $!\n"; + lprint("\[$$/$CURR] $!"); last; } elsif ($len == 0) { - print STDERR "$prog\[$$/$CURR]: Input is EOF.\n"; + lprint("\[$$/$CURR] Input is EOF."); last; } my $offset = 0; @@ -615,7 +666,7 @@ sub xfer { while ($len) { my $written = syswrite($out, $buf, $len, $offset); if (! defined $written) { - print STDERR "$prog\[$$/$CURR]: Output is EOF. $!\n"; + lprint("\[$$/$CURR] Output is EOF. $!"); $quit = 1; last; } @@ -626,7 +677,7 @@ sub xfer { } close($out); close($in); - print STDERR "$prog\[$$/$CURR]: finished xfer.\n"; + lprint("\[$$/$CURR] finished xfer."); } sub xfer_both { @@ -637,7 +688,7 @@ sub xfer_both { my $child = fork(); if (! defined $child) { - print STDERR "$prog\[$$/$CURR] failed to fork: $!\n"; + lprint("$prog\[$$/$CURR] failed to fork: $!"); return; } @@ -645,30 +696,30 @@ sub xfer_both { $SIG{INT} = "handler"; if ($child) { - print STDERR "$prog parent[$$/$CURR] 1 -> 2\n"; + lprint("[$$/$CURR] parent 1 -> 2."); xfer($sock1, $sock2); select(undef, undef, undef, 0.25); if (kill 0, $child) { select(undef, undef, undef, 0.9); if (kill 0, $child) { - print STDERR "$prog\[$$/$CURR]: kill TERM child $child\n"; + lprint("\[$$/$CURR] kill TERM child $child"); kill "TERM", $child; } else { - print STDERR "$prog\[$$/$CURR]: child $child gone.\n"; + lprint("\[$$/$CURR] child $child gone."); } } } else { select(undef, undef, undef, 0.05); - print STDERR "$prog child [$$/$CURR] 2 -> 1\n"; + lprint("[$$/$CURR] child 2 -> 1."); xfer($sock2, $sock1); select(undef, undef, undef, 0.25); if (kill 0, $parent) { select(undef, undef, undef, 0.8); if (kill 0, $parent) { - print STDERR "$prog\[$$/$CURR]: kill TERM parent $parent\n"; + lprint("\[$$/$CURR] kill TERM parent $parent."); kill "TERM", $parent; } else { - print STDERR "$prog\[$$/$CURR]: parent $parent gone.\n"; + lprint("\[$$/$CURR] parent $parent gone."); } } } diff --git a/x11vnc/sslhelper.c b/x11vnc/sslhelper.c index 0cb120c..a363eee 100644 --- a/x11vnc/sslhelper.c +++ b/x11vnc/sslhelper.c @@ -1923,6 +1923,8 @@ static void pr_ssl_info(int verb) { static void ssl_timeout (int sig) { int i; rfbLog("sig: %d, ssl_init[%d] timed out.\n", sig, getpid()); + rfbLog("To increase the SSL initialization timeout use, e.g.:\n"); + rfbLog(" -env SSL_INIT_TIMEOUT=120 (for 120 seconds)\n"); for (i=0; i < 256; i++) { close(i); } @@ -1944,10 +1946,17 @@ static int ssl_init(int s_in, int s_out, int skip_vnc_tls, double last_https) { if (getenv("SSL_DEBUG")) { db = atoi(getenv("SSL_DEBUG")); } + usleep(100 * 1000); if (getenv("SSL_INIT_TIMEOUT")) { timeout = atoi(getenv("SSL_INIT_TIMEOUT")); + } else if (client_connect != NULL && strstr(client_connect, "repeater")) { + rfbLog("SSL: ssl_init[%d]: detected 'repeater' in connect string.\n", getpid()); + rfbLog("SSL: setting timeout to 1 hour: -env SSL_INIT_TIMEOUT=3600\n"); + rfbLog("SSL: use that option to set a different timeout value,\n"); + rfbLog("SSL: however note that with Windows UltraVNC repeater it\n"); + rfbLog("SSL: may timeout before your setting due to other reasons.\n"); + timeout = 3600; } - if (db) fprintf(stderr, "ssl_init: %d/%d\n", s_in, s_out); if (skip_vnc_tls) { rfbLog("SSL: ssl_helper[%d]: HTTPS mode, skipping check_vnc_tls_mode()\n", @@ -1955,6 +1964,8 @@ static int ssl_init(int s_in, int s_out, int skip_vnc_tls, double last_https) { } else if (!check_vnc_tls_mode(s_in, s_out, last_https)) { return 0; } + rfbLog("SSL: ssl_init[%d]: %d/%d initialization timeout: %d secs.\n", + getpid(), s_in, s_out, timeout); ssl = SSL_new(ctx); if (ssl == NULL) { @@ -2026,32 +2037,32 @@ static int ssl_init(int s_in, int s_out, int skip_vnc_tls, double last_https) { } else if (err == SSL_ERROR_WANT_READ) { if (db) fprintf(stderr, "got SSL_ERROR_WANT_READ\n"); - rfbLog("SSL: ssl_helper[%d]: SSL_accept() failed for: %s:%d\n", - getpid(), name, peerport); + rfbLog("SSL: ssl_helper[%d]: %s() failed for: %s:%d 1\n", + getpid(), ssl_client_mode ? "SSL_connect" : "SSL_accept", name, peerport); pr_ssl_info(1); return 0; } else if (err == SSL_ERROR_WANT_WRITE) { if (db) fprintf(stderr, "got SSL_ERROR_WANT_WRITE\n"); - rfbLog("SSL: ssl_helper[%d]: SSL_accept() failed for: %s:%d\n", - getpid(), name, peerport); + rfbLog("SSL: ssl_helper[%d]: %s() failed for: %s:%d 2\n", + getpid(), ssl_client_mode ? "SSL_connect" : "SSL_accept", name, peerport); pr_ssl_info(1); return 0; } else if (err == SSL_ERROR_SYSCALL) { if (db) fprintf(stderr, "got SSL_ERROR_SYSCALL\n"); - rfbLog("SSL: ssl_helper[%d]: SSL_accept() failed for: %s:%d\n", - getpid(), name, peerport); + rfbLog("SSL: ssl_helper[%d]: %s() failed for: %s:%d 3\n", + getpid(), ssl_client_mode ? "SSL_connect" : "SSL_accept", name, peerport); pr_ssl_info(1); return 0; } else if (err == SSL_ERROR_ZERO_RETURN) { if (db) fprintf(stderr, "got SSL_ERROR_ZERO_RETURN\n"); - rfbLog("SSL: ssl_helper[%d]: SSL_accept() failed for: %s:%d\n", - getpid(), name, peerport); + rfbLog("SSL: ssl_helper[%d]: %s() failed for: %s:%d 4\n", + getpid(), ssl_client_mode ? "SSL_connect" : "SSL_accept", name, peerport); pr_ssl_info(1); return 0; @@ -2059,7 +2070,8 @@ static int ssl_init(int s_in, int s_out, int skip_vnc_tls, double last_https) { unsigned long err; int cnt = 0; - rfbLog("SSL: ssl_helper[%d]: SSL_accept() *FATAL: %d SSL FAILED\n", getpid(), rc); + rfbLog("SSL: ssl_helper[%d]: %s() *FATAL: %d SSL FAILED\n", + getpid(), ssl_client_mode ? "SSL_connect" : "SSL_accept", rc); while ((err = ERR_get_error()) != 0) { rfbLog("SSL: %s\n", ERR_error_string(err, NULL)); if (cnt++ > 100) { @@ -2071,8 +2083,8 @@ static int ssl_init(int s_in, int s_out, int skip_vnc_tls, double last_https) { } else if (dnow() > start + 3.0) { - rfbLog("SSL: ssl_helper[%d]: timeout looping SSL_accept() " - "fatal.\n", getpid()); + rfbLog("SSL: ssl_helper[%d]: timeout looping %s() " + "fatal.\n", getpid(), ssl_client_mode ? "SSL_connect" : "SSL_accept"); pr_ssl_info(1); return 0; diff --git a/x11vnc/x11vnc.1 b/x11vnc/x11vnc.1 index 05a5683..2b09a19 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-22 + version: 0.9.10, lastmod: 2010-04-28 .SH SYNOPSIS .B x11vnc [OPTION]... @@ -697,6 +697,28 @@ newline and carriage return. "\\c" is expanded to See also the \fB-proxy\fR option below for additional ways to plumb reverse connections. .IP +Reverse SSL: using \fB-connect\fR in \fB-ssl\fR mode makes x11vnc +act as an SSL client (initiates SSL connection) rather +than an SSL server. The idea is x11vnc might be +connecting to stunnel on the viewer side with the +viewer in listening mode. If you do not want this +behavior, use \fB-env\fR X11VNC_DISABLE_SSL_CLIENT_MODE=1. +With this the viewer side can act as the SSL client +as it normally does for forward connections. +.IP +Reverse SSL Repeater mode: This will work, but note +that if the VNC Client does any sort of a 'Fetch Cert' +action before connecting, then the Repeater will +likely drop the connection and both sides will need +to restart. Consider the use of \fB-connect_or_exit\fR +and \fB-loop300,2\fR to have x11vnc reconnect once to the +repeater after the fetch. You will probably also want +to supply \fB-sslonly\fR to avoid x11vnc thinking the delay +in response means the connection is VeNCrypt. The env +var X11VNC_DISABLE_SSL_CLIENT_MODE=1 discussed above +may also be useful (i.e. the viewer can do a forward +connection as it normally does.) +.IP IPv6: as of x11vnc 0.9.10 the \fB-connect\fR option should connect to IPv6 hosts properly. If there are problems you can disable IPv6 by setting \fB-DX11VNC_IPV6=0\fR diff --git a/x11vnc/x11vnc_defs.c b/x11vnc/x11vnc_defs.c index ee335cf..1e03394 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-22"; +char lastmod[] = "0.9.10 lastmod: 2010-04-28"; /* X display info */ diff --git a/x11vnc/xrecord.c b/x11vnc/xrecord.c index ab32fbe..4f79dce 100644 --- a/x11vnc/xrecord.c +++ b/x11vnc/xrecord.c @@ -535,12 +535,13 @@ static double xrecord_start = 0.0; static void record_CA(XPointer ptr, XRecordInterceptData *rec_data) { xCopyAreaReq *req; Window src = None, dst = None, c; - XWindowAttributes attr; - int src_x, src_y, dst_x, dst_y, rx, ry; - int good = 1, dx, dy, k=0, i; + XWindowAttributes attr, attr2; + int src_x, src_y, dst_x, dst_y, rx, ry, rx2, ry2; + int good = 1, dx = 0, dy = 0, k=0, i; unsigned int w, h; int dba = 0, db = debug_scroll; int cache_index, next_index, valid; + static int must_equal = -1; if (dba || db) { if (rec_data->category == XRecordFromClient) { @@ -584,6 +585,13 @@ if (db > 1) fprintf(stderr, "record_CA-%d\n", k++); } if (db > 1) fprintf(stderr, "record_CA-%d\n", k++); + if (must_equal < 0) { + must_equal = 0; + if (getenv("X11VNC_SCROLL_MUST_EQUAL")) { + must_equal = 1; + } + } + /* xterm, gnome-terminal, others. @@ -618,25 +626,36 @@ short period of time with a painting error: two cursors, one above the other. h = req->height; if (w*h < (unsigned int) scrollcopyrect_min_area) { + if (db > 1) fprintf(stderr, "record_CA scroll area too small.\n"); good = 0; } else if (!src || !dst) { - good = 0; - } else if (src != dst) { + if (db > 1) fprintf(stderr, "record_CA null src or dst.\n"); good = 0; } else if (scr_ev_cnt >= SCR_EV_MAX) { + if (db > 1) fprintf(stderr, "record_CA null too many scr events.\n"); + good = 0; + } else if (must_equal && src != dst) { + if (db > 1) fprintf(stderr, "record_CA src not equal dst.\n"); good = 0; } - dx = dst_x - src_x; - dy = dst_y - src_y; + if (src == dst) { + dx = dst_x - src_x; + dy = dst_y - src_y; - if (dx != 0 && dy != 0) { - good = 0; + if (dx != 0 && dy != 0) { + good = 0; + } } +if (!good && (dba || db > 1)) fprintf(stderr, "record_CA-x src_x: %d src_y: %d " + "dst_x: %d dst_y: %d w: %d h: %d scr_ev_cnt: %d 0x%lx/0x%lx\n", + src_x, src_y, dst_x, dst_y, w, h, scr_ev_cnt, src, dst); + if (! good) { return; } + if (db > 1) fprintf(stderr, "record_CA-%d\n", k++); /* @@ -687,14 +706,84 @@ if (db > 1) fprintf(stderr, "record_CA-%d\n", k++); } if (! valid) { + if (db > 1) fprintf(stderr, "record_CA not valid-1.\n"); return; } if (db > 1) fprintf(stderr, "record_CA-%d\n", k++); if (attr.map_state != IsViewable) { + if (db > 1) fprintf(stderr, "record_CA not viewable-1.\n"); return; } + /* recent gdk/gtk windows use different src and dst. for compositing? */ + if (src != dst) { + if (lookup_attr_cache(dst, &cache_index, &next_index)) { + i = cache_index; + attr2.x = scr_attr_cache[i].x; + attr2.y = scr_attr_cache[i].y; + attr2.width = scr_attr_cache[i].width; + attr2.height = scr_attr_cache[i].height; + attr2.map_state = scr_attr_cache[i].map_state; + rx2 = scr_attr_cache[i].rx; + ry2 = scr_attr_cache[i].ry; + valid = scr_attr_cache[i].valid; + + } else { + valid = valid_window(dst, &attr2, 1); + + if (valid) { + if (!xtranslate(dst, rootwin, 0, 0, &rx2, &ry2, &c, 1)) { + valid = 0; + } + } + if (next_index >= 0) { + i = next_index; + scr_attr_cache[i].win = dst; + scr_attr_cache[i].fetched = 1; + scr_attr_cache[i].valid = valid; + scr_attr_cache[i].time = dnow(); + if (valid) { + scr_attr_cache[i].x = attr2.x; + scr_attr_cache[i].y = attr2.y; + scr_attr_cache[i].width = attr2.width; + scr_attr_cache[i].height = attr2.height; + scr_attr_cache[i].border_width = attr2.border_width; + scr_attr_cache[i].depth = attr2.depth; + scr_attr_cache[i].class = attr2.class; + scr_attr_cache[i].backing_store = + attr2.backing_store; + scr_attr_cache[i].map_state = attr2.map_state; + + scr_attr_cache[i].rx = rx2; + scr_attr_cache[i].ry = ry2; + } + } + } + +if (dba || db > 1) fprintf(stderr, "record_CA-? src_x: %d src_y: %d " + "dst_x: %d dst_y: %d w: %d h: %d scr_ev_cnt: %d 0x%lx/0x%lx\n", + src_x, src_y, dst_x, dst_y, w, h, scr_ev_cnt, src, dst); + + if (! valid) { + if (db > 1) fprintf(stderr, "record_CA not valid-2.\n"); + return; + } + if (attr2.map_state != IsViewable) { + if (db > 1) fprintf(stderr, "record_CA not viewable-2.\n"); + return; + } + dst_x = dst_x - (rx - rx2); + dst_y = dst_y - (ry - ry2); + + dx = dst_x - src_x; + dy = dst_y - src_y; + + if (dx != 0 && dy != 0) { + return; + } + } + if (0 || dba || db) { double st, dt; @@ -1546,14 +1635,30 @@ void check_xrecord_reset(int force) { #endif } -#define RECORD_ERROR_MSG \ +#define RECORD_ERROR_MSG(tag) \ if (! quiet) { \ - rfbLog("trapped RECORD XError: %s %d/%d/%d (0x%lx)\n", \ - xerror_string(trapped_record_xerror_event), \ - (int) trapped_record_xerror_event->error_code, \ - (int) trapped_record_xerror_event->request_code, \ - (int) trapped_record_xerror_event->minor_code, \ - (int) trapped_record_xerror_event->resourceid); \ + static int cnt = 0; \ + static time_t last = 0; \ + int show = 0; \ + cnt++; \ + if (debug_scroll || cnt < 20) { \ + show = 1; \ + } else if (cnt == 20) { \ + last = time(NULL); \ + rfbLog("disabling RECORD XError messages for 600s\n"); \ + show = 1; \ + } else if (time(NULL) > last + 600) { \ + cnt = 0; \ + show = 1; \ + } \ + if (show) { \ + rfbLog("trapped RECORD XError: %s %s %d/%d/%d (0x%lx)\n", \ + tag, xerror_string(trapped_record_xerror_event), \ + (int) trapped_record_xerror_event->error_code, \ + (int) trapped_record_xerror_event->request_code, \ + (int) trapped_record_xerror_event->minor_code, \ + (int) trapped_record_xerror_event->resourceid); \ + } \ } void xrecord_watch(int start, int setby) { @@ -1659,7 +1764,7 @@ if (db > 1) fprintf(stderr, "=== shutdown-scroll 0x%lx\n", rc_scroll); XRecordProcessReplies(rdpy_data); if (trapped_record_xerror) { - RECORD_ERROR_MSG; + RECORD_ERROR_MSG("shutdown"); last_error = now; } @@ -1683,7 +1788,7 @@ if (db > 1) fprintf(stderr, "=== disab-scroll 0x%lx 0x%lx\n", rc_scroll, rcs_scr XRecordProcessReplies(rdpy_data); if (trapped_record_xerror) { - RECORD_ERROR_MSG; + RECORD_ERROR_MSG("disable"); shutdown_record_context(rc_scroll, 0, reopen_dpys); @@ -1906,7 +2011,7 @@ if (db > 1) fprintf(stderr, "=-= reg-scroll 0x%lx 0x%lx\n", rc_scroll, rcs_scr if (db) fprintf(stderr, "rc_scroll: 0x%lx\n", rc_scroll); if (trapped_record_xerror) { - RECORD_ERROR_MSG; + RECORD_ERROR_MSG("register"); } if (! rc_scroll) { @@ -1955,7 +2060,7 @@ if (db) fprintf(stderr, "rc_scroll: 0x%lx\n", rc_scroll); rfbLog("failed to enable RECORD context " "rc_scroll: 0x%lx rc: %d\n", rc_scroll, rc); if (trapped_record_xerror) { - RECORD_ERROR_MSG; + RECORD_ERROR_MSG("enable-failed"); } } shutdown_record_context(rc_scroll, 0, reopen_dpys);