Commit 0ef122b6 authored by runge's avatar runge

Apache SSL gateway. More web proxy cases for Java and ssl_vncviewer.

parent d14cf0a8
#!/bin/sh
#
# ssl_vncviewer: wrapper for vncviewer to use stunnel SSL tunnel.
# ssl_vncviewer: wrapper for vncviewer to use an stunnel SSL tunnel.
#
# Copyright (c) 2006 by Karl J. Runge <runge@karlrunge.com>
#
# You must have stunnel(8) installed on the system and in your
# PATH (n.b. stunnel is usually in an sbin subdir).
......@@ -16,6 +18,7 @@
# [cert-args] can be:
# -verify /path/to/cacert.pem
# -mycert /path/to/mycert.pem
# -proxy host:port
#
# -verify specifies a CA cert PEM file (or a self-signed one) for
# authenticating the VNC server.
......@@ -23,12 +26,19 @@
# -mycert specifies this client's cert+key PEM file for the VNC server to
# authenticate this client.
#
# -proxy try host:port as a Web proxy to use the CONNECT method
# to reach the VNC server (e.g. your firewall requires a proxy).
# For the "double proxy" case use -proxy host1:port1,host2:port2
#
#
# set VNCVIEWERCMD to whatever vncviewer command you want to use:
#
VNCVIEWERCMD=${VNCVIEWERCMD:-vncviewer}
VNCVIEWERCMD="vncviewer"
PATH=$PATH:/usr/sbin:/usr/local/sbin:/dist/sbin; export PATH
help() {
head -26 $0 | tail +2
head -36 $0 | tail +2
}
# grab our cmdline options:
......@@ -39,6 +49,8 @@ do
;;
"-mycert") shift; mycert="$1"
;;
"-proxy") shift; proxy="$1"
;;
"-h"*) help; exit 0
;;
*) break
......@@ -59,12 +71,19 @@ host=`echo "$orig" | awk -F: '{print $1}'`
disp=`echo "$orig" | awk -F: '{print $2}'`
if [ $disp -lt 200 ]; then
port=`expr $disp + 5900`
else
port=$disp
fi
# try to find an open listening port via netstat(1):
use=""
inuse=""
if uname | grep Linux > /dev/null; then
inuse=`netstat -ant | grep LISTEN | awk '{print $4}' | sed 's/^.*://'`
elif uname | grep SunOS > /dev/null; then
inuse=`netstat -an -f inet -P tcp | grep LISTEN | awk '{print $1}' | sed 's/^.*\.//'`
fi
if [ "x$inuse" != "x" ]; then
try=5920
while [ $try -lt 6000 ]
do
......@@ -95,6 +114,145 @@ if [ "X$mycert" != "X" ]; then
cert="cert = $mycert"
fi
pcode() {
tf=$1
SSL_VNC_PROXY=$proxy; export SSL_VNC_PROXY
SSL_VNC_DEST="$host:$port"; export SSL_VNC_DEST
cod='#!/usr/bin/perl
# A hack to glue stunnel to a Web proxy for client connections.
use IO::Socket::INET;
my ($first, $second) = split(/,/, $ENV{SSL_VNC_PROXY});
my ($proxy_host, $proxy_port) = split(/:/, $first);
my $connect = $ENV{SSL_VNC_DEST};
print STDERR "\nperl script for web proxing:\n";
print STDERR "proxy_host: $proxy_host\n";
print STDERR "proxy_port: $proxy_port\n";
print STDERR "proxy_connect: $connect\n";
my $sock = IO::Socket::INET->new(
PeerAddr => $proxy_host,
PeerPort => $proxy_port,
Proto => "tcp");
if (! $sock) {
unlink($0);
die "perl proxy: $!\n";
}
my $con = "";
if ($second ne "") {
$con = "CONNECT $second HTTP/1.1\r\n";
$con .= "Host: $second\r\n\r\n";
} else {
$con = "CONNECT $connect HTTP/1.1\r\n";
$con .= "Host: $connect\r\n\r\n";
}
print STDERR "proxy_request1:\n$con";
print $sock $con;
unlink($0);
my $rep = "";
while ($rep !~ /\r\n\r\n/) {
my $c = getc($sock);
print STDERR $c;
$rep .= $c;
}
if ($rep !~ m,HTTP/.* 200,) {
die "proxy error: $rep\n";
}
if ($second ne "") {
$con = "CONNECT $connect HTTP/1.1\r\n";
$con .= "Host: $connect\r\n\r\n";
print STDERR "proxy_request2:\n$con";
print $sock $con;
$rep = "";
while ($rep !~ /\r\n\r\n/) {
my $c = getc($sock);
print STDERR $c;
$rep .= $c;
}
if ($rep !~ m,HTTP/.* 200,) {
die "proxy error: $rep\n";
}
}
if (fork) {
print STDERR "parent\[$$] STDIN -> socket\n\n";
xfer(STDIN, $sock);
} else {
print STDERR "child \[$$] socket -> STDOUT\n\n";
xfer($sock, STDOUT);
}
exit;
sub xfer {
my($in, $out) = @_;
$RIN = $WIN = $EIN = "";
$ROUT = "";
vec($RIN, fileno($in), 1) = 1;
vec($WIN, fileno($in), 1) = 1;
$EIN = $RIN | $WIN;
while (1) {
my $nf = 0;
while (! $nf) {
$nf = select($ROUT=$RIN, undef, undef, undef);
}
my $len = sysread($in, $buf, 8192);
if (! defined($len)) {
next if $! =~ /^Interrupted/;
print STDERR "perl proxy\[$$]: $!\n";
last;
} elsif ($len == 0) {
print STDERR "perl proxy\[$$]: Input is EOF.\n";
last;
}
my $offset = 0;
my $quit = 0;
while ($len) {
my $written = syswrite($out, $buf, $len, $offset);
if (! defined $written) {
print STDERR "perl proxy\[$$]: Output is EOF. $!\n";
$quit = 1;
last;
}
$len -= $written;
$offset += $written;
}
last if $quit;
}
close($in);
close($out);
}
'
rm -f $tf
if [ -f $tf ]; then
echo "$tf still exists!"
exit 1
fi
echo "$cod" > $tf
chmod 700 $tf
}
ptmp=""
if [ "X$proxy" != "X" ]; then
ptmp="/tmp/ssl_vncviewer.$$.pl"
pcode $ptmp
connect="exec = $ptmp"
else
connect="connect = $host:$port"
fi
##debug = 7
tmp=/tmp/ssl_vncviewer.$$
cat > $tmp <<END
......@@ -106,12 +264,13 @@ $cert
[vnc_stunnel]
accept = $use
connect= $host:$port
$connect
END
echo ""
echo "Using this stunnel configuration:"
cat $tmp
echo ""
cat $tmp | uniq
echo ""
sleep 1
......@@ -140,3 +299,4 @@ else
fi
kill $pid
sleep 1
......@@ -38,34 +38,43 @@ diff -x VncCanvas.java -Naur vnc_javasrc.orig/Makefile vnc_javasrc/Makefile
@$(ExportJavaClasses)
diff -x VncCanvas.java -Naur vnc_javasrc.orig/RfbProto.java vnc_javasrc/RfbProto.java
--- vnc_javasrc.orig/RfbProto.java 2004-03-04 08:34:25.000000000 -0500
+++ vnc_javasrc/RfbProto.java 2006-04-03 11:22:30.000000000 -0400
+++ vnc_javasrc/RfbProto.java 2006-04-16 11:17:37.000000000 -0400
@@ -199,7 +199,21 @@
host = h;
port = p;
- if (viewer.socketFactory == null) {
+ if (! viewer.disableSSL) {
+ System.out.println("new SSLSocketToMe");
+ SSLSocketToMe ssl;
+ try {
+ ssl = new SSLSocketToMe(host, port, v);
+ } catch (Exception e) {
+ throw new IOException(e.getMessage());
+ }
+
+ try {
+ sock = ssl.connectSock();
+ } catch (Exception es) {
+ throw new IOException(es.getMessage());
+ }
+ System.out.println("new SSLSocketToMe");
+ SSLSocketToMe ssl;
+ try {
+ ssl = new SSLSocketToMe(host, port, v);
+ } catch (Exception e) {
+ throw new IOException(e.getMessage());
+ }
+
+ try {
+ sock = ssl.connectSock();
+ } catch (Exception es) {
+ throw new IOException(es.getMessage());
+ }
+ } else if (viewer.socketFactory == null) {
sock = new Socket(host, port);
} else {
try {
@@ -255,7 +269,7 @@
|| (b[10] < '0') || (b[10] > '9') || (b[11] != '\n'))
{
throw new Exception("Host " + host + " port " + port +
- " is not an RFB server");
+ " is not an RFB server: " + b);
}
serverMajor = (b[4] - '0') * 100 + (b[5] - '0') * 10 + (b[6] - '0');
diff -x VncCanvas.java -Naur vnc_javasrc.orig/SSLSocketToMe.java vnc_javasrc/SSLSocketToMe.java
--- vnc_javasrc.orig/SSLSocketToMe.java 1969-12-31 19:00:00.000000000 -0500
+++ vnc_javasrc/SSLSocketToMe.java 2006-04-04 13:17:39.000000000 -0400
@@ -0,0 +1,1040 @@
+++ vnc_javasrc/SSLSocketToMe.java 2006-04-16 11:21:30.000000000 -0400
@@ -0,0 +1,1204 @@
+/*
+ * SSLSocketToMe.java: add SSL encryption to Java VNC Viewer.
+ *
......@@ -111,10 +120,14 @@ diff -x VncCanvas.java -Naur vnc_javasrc.orig/SSLSocketToMe.java vnc_javasrc/SSL
+
+ /* fallback for Proxy connection */
+ boolean proxy_in_use = false;
+ boolean proxy_is_https = false;
+ boolean proxy_failure = false;
+ public DataInputStream is = null;
+ public OutputStream os = null;
+
+ String proxy_dialog_host = null;
+ int proxy_dialog_port = 0;
+
+ Socket proxySock;
+ DataInputStream proxy_is;
+ OutputStream proxy_os;
......@@ -149,7 +162,6 @@ diff -x VncCanvas.java -Naur vnc_javasrc.orig/SSLSocketToMe.java vnc_javasrc/SSL
+
+ /* create trust managers used if initial handshake fails: */
+
+
+ trustAllCerts = new TrustManager[] {
+ /*
+ * this one accepts everything.
......@@ -349,15 +361,17 @@ diff -x VncCanvas.java -Naur vnc_javasrc.orig/SSLSocketToMe.java vnc_javasrc/SSL
+ return false;
+ }
+
+ public Socket connectSock() throws IOException {
+ public void check_for_proxy() {
+
+ boolean result = false;
+ String ustr = "https://" + host + ":" + port;
+ ustr += viewer.urlPrefix + "/check.https.proxy.connection";
+
+ trusturlCerts = null;
+ proxy_in_use = false;
+
+ /*
+ * first try a https connection to detect a proxy, and
+ * also grab the VNC server cert.
+ */
+ URL url = new URL("https://" + host + ":" + port +
+ "/check.https.proxy.connection");
+ try {
+ URL url = new URL(ustr);
+ HttpsURLConnection https = (HttpsURLConnection)
+ url.openConnection();
+
......@@ -374,15 +388,59 @@ diff -x VncCanvas.java -Naur vnc_javasrc.orig/SSLSocketToMe.java vnc_javasrc/SSL
+
+ if (https.usingProxy()) {
+ proxy_in_use = true;
+ proxy_is_https = true;
+ dbg("HTTPS proxy in use. There may be connection problems.");
+ }
+ Object output = https.getContent();
+ https.disconnect();
+ result = true;
+
+ } catch(Exception e) {
+ dbg("HttpsURLConnection: " + e.getMessage());
+ }
+
+ if (proxy_in_use) {
+ return;
+ }
+
+ ustr = "http://" + host + ":" + port;
+ ustr += viewer.urlPrefix + "/index.vnc";
+
+ try {
+ URL url = new URL(ustr);
+ HttpURLConnection http = (HttpURLConnection)
+ url.openConnection();
+
+ http.setUseCaches(false);
+ http.setRequestMethod("GET");
+ http.setRequestProperty("Pragma", "No-Cache");
+ http.setRequestProperty("Proxy-Connection",
+ "Keep-Alive");
+ http.setDoInput(true);
+
+ http.connect();
+
+ if (http.usingProxy()) {
+ proxy_in_use = true;
+ proxy_is_https = false;
+ dbg("HTTP proxy in use. There may be connection problems.");
+ }
+ Object output = http.getContent();
+ http.disconnect();
+
+ } catch(Exception e) {
+ trusturlCerts = null;
+ dbg("HttpURLConnection: " + e.getMessage());
+ }
+ }
+
+ public Socket connectSock() throws IOException {
+
+ /*
+ * first try a https connection to detect a proxy, and
+ * also grab the VNC server cert.
+ */
+ check_for_proxy();
+
+ if (use_url_cert_for_auth && trusturlCerts != null) {
+ factory = trusturl_ctx.getSocketFactory();
+ } else {
......@@ -391,11 +449,23 @@ diff -x VncCanvas.java -Naur vnc_javasrc.orig/SSLSocketToMe.java vnc_javasrc/SSL
+
+ socket = null;
+ try {
+ if (proxy_in_use && viewer.forceProxy) {
+ throw new Exception("forcing proxy (forceProxy)");
+ } else if (viewer.CONNECT != null) {
+ throw new Exception("forcing CONNECT");
+ }
+
+ socket = (SSLSocket) factory.createSocket(host, port);
+
+ } catch (Exception esock) {
+ if (proxy_in_use) {
+ dbg("esock: " + esock.getMessage());
+ if (proxy_in_use || viewer.CONNECT != null) {
+ proxy_failure = true;
+ dbg("HTTPS proxy in use. Trying to go with it.");
+ if (proxy_in_use) {
+ dbg("HTTPS proxy in use. Trying to go with it.");
+ } else {
+ dbg("viewer.CONNECT reverse proxy in use. Trying to go with it.");
+ }
+ try {
+ socket = proxy_socket(factory);
+ } catch (Exception e) {
......@@ -522,6 +592,31 @@ diff -x VncCanvas.java -Naur vnc_javasrc.orig/SSLSocketToMe.java vnc_javasrc/SSL
+ }
+ }
+
+ if (socket != null && viewer.GET != null) {
+ String str = "GET ";
+ str += viewer.urlPrefix;
+ str += "/request.https.vnc.connection";
+ str += " HTTP/1.0\r\n";
+ str += "Pragma: No-Cache\r\n";
+ str += "\r\n";
+ System.out.println("sending GET: " + str);
+ OutputStream os = socket.getOutputStream();
+ os.write(str.getBytes());
+ os.flush();
+ if (false) {
+ String rep = "";
+ DataInputStream is = new DataInputStream(
+ new BufferedInputStream(socket.getInputStream(), 16384));
+ while (true) {
+ rep += readline(is);
+ if (rep.indexOf("\r\n\r\n") >= 0) {
+ break;
+ }
+ }
+ System.out.println("rep: " + rep);
+ }
+ }
+
+ dbg("SSL returning socket to caller.");
+ return (Socket) socket;
+ }
......@@ -532,10 +627,24 @@ diff -x VncCanvas.java -Naur vnc_javasrc.orig/SSLSocketToMe.java vnc_javasrc/SSL
+ }
+ }
+
+ private int gint(String s) {
+ int n = -1;
+ try {
+ Integer I = new Integer(s);
+ n = I.intValue();
+ } catch (Exception ex) {
+ return -1;
+ }
+ return n;
+ }
+
+ public SSLSocket proxy_socket(SSLSocketFactory factory) {
+ Properties props = null;
+ String proxyHost = null;
+ int proxyPort = 0;
+ String proxyHost_nossl = null;
+ int proxyPort_nossl = 0;
+ String str;
+
+ /* see if we can guess the proxy info from Properties: */
+ try {
......@@ -548,16 +657,33 @@ diff -x VncCanvas.java -Naur vnc_javasrc.orig/SSLSocketToMe.java vnc_javasrc/SSL
+ props.list(System.out);
+ dbg("\n---------------\n\n");
+
+ for (Enumeration e = props.propertyNames(); e.hasMoreElements(); ) {
+ for (Enumeration e = props.propertyNames(); e.hasMoreElements(); ) {
+ String s = (String) e.nextElement();
+ String v = System.getProperty(s);
+ String l1 = s.toLowerCase();
+ String l2 = v.toLowerCase();
+ String s2 = s.toLowerCase();
+ String v2 = v.toLowerCase();
+
+ if (l1.indexOf("proxy") < 0 && l2.indexOf("proxy") < 0) {
+ if (s2.indexOf("proxy") < 0 && v2.indexOf("proxy") < 0) {
+ continue;
+ }
+ if (l2.indexOf("https") < 0) {
+ if (v2.indexOf("https") < 0) {
+ continue;
+ }
+
+ if (s2.indexOf("proxy.https.host") >= 0) {
+ proxyHost = v2;
+ continue;
+ }
+ if (s2.indexOf("proxy.https.port") >= 0) {
+ proxyPort = gint(v2);
+ continue;
+ }
+ if (s2.indexOf("proxy.http.host") >= 0) {
+ proxyHost_nossl = v2;
+ continue;
+ }
+ if (s2.indexOf("proxy.http.port") >= 0) {
+ proxyPort_nossl = gint(v2);
+ continue;
+ }
+
......@@ -578,10 +704,9 @@ diff -x VncCanvas.java -Naur vnc_javasrc.orig/SSLSocketToMe.java vnc_javasrc/SSL
+ continue;
+ }
+ if (hp[0].length() > 1 && hp[1].length() > 1) {
+ try {
+ Integer I = new Integer(hp[1]);
+ proxyPort = I.intValue();
+ } catch (Exception ex) {
+
+ proxyPort = gint(hp[1]);
+ if (proxyPort < 0) {
+ continue;
+ }
+ proxyHost = new String(hp[0]);
......@@ -591,65 +716,113 @@ diff -x VncCanvas.java -Naur vnc_javasrc.orig/SSLSocketToMe.java vnc_javasrc/SSL
+ }
+ }
+ if (proxyHost != null) {
+ dbg("Lucky us! we figured out the Proxy parameters: " + proxyHost + " " + proxyPort);
+ } else {
+ /* ask user to help us: */
+ ProxyDialog pd = new ProxyDialog(proxyHost, proxyPort);
+ pd.queryUser();
+ proxyHost = pd.getHost();
+ proxyPort = pd.getPort();
+ dbg("User said host: " + pd.getHost() + " port: " + pd.getPort());
+ if (proxyHost_nossl != null && proxyPort_nossl > 0) {
+ dbg("Using http proxy info instead of https.");
+ proxyHost = proxyHost_nossl;
+ proxyPort = proxyPort_nossl;
+ }
+ }
+
+ proxySock = psocket(proxyHost, proxyPort);
+ if (proxySock == null) {
+ dbg("1 sadly, returning a null socket");
+ return null;
+ }
+ String hp = host + ":" + port;
+ if (proxy_in_use) {
+ if (proxy_dialog_host != null && proxy_dialog_port > 0) {
+ proxyHost = proxy_dialog_host;
+ proxyPort = proxy_dialog_port;
+ }
+ if (proxyHost != null) {
+ dbg("Lucky us! we figured out the Proxy parameters: " + proxyHost + " " + proxyPort);
+ } else {
+ /* ask user to help us: */
+ ProxyDialog pd = new ProxyDialog(proxyHost, proxyPort);
+ pd.queryUser();
+ proxyHost = pd.getHost();
+ proxyPort = pd.getPort();
+ proxy_dialog_host = new String(proxyHost);
+ proxy_dialog_port = proxyPort;
+ dbg("User said host: " + pd.getHost() + " port: " + pd.getPort());
+ }
+
+ String req1 = "CONNECT " + hp + " HTTP/1.1\r\n"
+ + "Host: " + hp + "\r\n\r\n";
+ dbg("proxy_in_use psocket:");
+ proxySock = psocket(proxyHost, proxyPort);
+ if (proxySock == null) {
+ dbg("1-a sadly, returning a null socket");
+ return null;
+ }
+ String hp = host + ":" + port;
+
+ /* not working for SSL yet: */
+ String req2 = "GET https://" + hp
+ + "/request.https.proxy.connection HTTP/1.1\r\n"
+ + "Host: " + hp + "\r\n\r\n";
+ String req1 = "CONNECT " + hp + " HTTP/1.1\r\n"
+ + "Host: " + hp + "\r\n\r\n";
+
+ dbg("requesting: " + req1);
+ dbg("requesting1: " + req1);
+
+ try {
+ proxy_os.write(req1.getBytes());
+ String reply = readline(proxy_is);
+ try {
+ proxy_os.write(req1.getBytes());
+ String reply = readline(proxy_is);
+
+ dbg("proxy replied: " + reply);
+ dbg("proxy replied1: " + reply.trim());
+
+ if (reply.indexOf("HTTP/1.") < 0 && reply.indexOf(" 200") < 0) {
+ proxySock.close();
+ proxySock = psocket(proxyHost, proxyPort);
+ if (proxySock == null) {
+ dbg("2 sadly, returning a null socket");
+ return null;
+ if (reply.indexOf("HTTP/1.") < 0 && reply.indexOf(" 200") < 0) {
+ proxySock.close();
+ proxySock = psocket(proxyHost, proxyPort);
+ if (proxySock == null) {
+ dbg("2-a sadly, returning a null socket");
+ return null;
+ }
+ }
+ dbg("requesting: " + req2);
+ } catch(Exception e) {
+ dbg("sock prob1: " + e.getMessage());
+ }
+
+ while (true) {
+ String line = readline(proxy_is);
+ dbg("proxy line1: " + line.trim());
+ if (line.equals("\r\n") || line.equals("\n")) {
+ break;
+ }
+ }
+ } else if (viewer.CONNECT != null) {
+ dbg("viewer.CONNECT psocket:");
+ proxySock = psocket(host, port);
+ if (proxySock == null) {
+ dbg("1-b sadly, returning a null socket");
+ return null;
+ }
+ }
+
+ if (viewer.CONNECT != null) {
+ String hp = viewer.CONNECT;
+ String req2 = "CONNECT " + hp + " HTTP/1.1\r\n"
+ + "Host: " + hp + "\r\n\r\n";
+
+ dbg("requesting2: " + req2);
+
+ try {
+ proxy_os.write(req2.getBytes());
+ String reply = readline(proxy_is);
+
+ reply = readline(proxy_is);
+ dbg("proxy replied2: " + reply.trim());
+
+ dbg("proxy replied: " + reply);
+ if (reply.indexOf("HTTP/1.") < 0 && reply.indexOf(" 200") < 0) {
+ proxySock.close();
+ proxySock = psocket(proxyHost, proxyPort);
+ if (proxySock == null) {
+ dbg("2-b sadly, returning a null socket");
+ return null;
+ }
+ }
+ } catch(Exception e) {
+ dbg("sock prob2: " + e.getMessage());
+ }
+ } catch(Exception e) {
+ dbg("sock prob: " + e.getMessage());
+ }
+
+ while (true) {
+ String line = readline(proxy_is);
+ dbg("proxy line: " + line);
+ if (line.equals("\r\n") || line.equals("\n")) {
+ break;
+ while (true) {
+ String line = readline(proxy_is);
+ dbg("proxy line2: " + line.trim());
+ if (line.equals("\r\n") || line.equals("\n")) {
+ break;
+ }
+ }
+
+ }
+
+
+ Socket sslsock = null;
+ try {
+ sslsock = factory.createSocket(proxySock, host, port, true);
......@@ -1108,16 +1281,21 @@ diff -x VncCanvas.java -Naur vnc_javasrc.orig/SSLSocketToMe.java vnc_javasrc/SSL
+}
diff -x VncCanvas.java -Naur vnc_javasrc.orig/VncViewer.java vnc_javasrc/VncViewer.java
--- vnc_javasrc.orig/VncViewer.java 2004-03-04 08:34:25.000000000 -0500
+++ vnc_javasrc/VncViewer.java 2006-03-27 22:20:19.000000000 -0500
@@ -87,6 +87,7 @@
int deferScreenUpdates;
+++ vnc_javasrc/VncViewer.java 2006-04-16 11:21:13.000000000 -0400
@@ -88,6 +88,12 @@
int deferCursorUpdates;
int deferUpdateRequests;
+ boolean disableSSL;
+ boolean disableSSL;
+ String GET;
+ String CONNECT;
+ String urlPrefix;
+ boolean forceProxy;
+
// Reference to this applet for inter-applet communication.
public static java.applet.Applet refApplet;
@@ -626,6 +627,12 @@
@@ -626,6 +632,39 @@
// SocketFactory.
socketFactory = readParameter("SocketFactory", false);
......@@ -1127,6 +1305,33 @@ diff -x VncCanvas.java -Naur vnc_javasrc.orig/VncViewer.java vnc_javasrc/VncView
+ str = readParameter("DisableSSL", false);
+ if (str != null && str.equalsIgnoreCase("Yes"))
+ disableSSL = true;
+
+ // Extra GET, CONNECT string:
+ CONNECT = readParameter("CONNECT", false);
+ if (CONNECT != null) {
+ CONNECT = CONNECT.replaceAll(" ", ":");
+ }
+ GET = readParameter("GET", false);
+ urlPrefix = "";
+ if (GET != null) {
+ GET = GET.replaceAll("%2F", "/");
+ GET = GET.replaceAll("%2f", "/");
+ GET = GET.replaceAll("_2F_", "/");
+ if (! GET.equals("1")) {
+ if (GET.indexOf("/") != 0) {
+ urlPrefix += "/";
+ }
+ urlPrefix += GET;
+ }
+ }
+ urlPrefix = urlPrefix.replaceAll("%2f", "/");
+ System.out.println("urlPrefix: " + urlPrefix);
+
+ forceProxy = false;
+ str = readParameter("forceProxy", false);
+ if (str != null && str.equalsIgnoreCase("Yes")) {
+ forceProxy = true;
+ }
}
public String readParameter(String name, boolean required) {
2006-04-16 Karl Runge <runge@karlrunge.com>
* x11vnc: More web proxy work for Java SSL applet and wrapper
script ssl_vncviewer. Apache SSL gateway support for
incoming x11vnc connections. Handle "double proxy" case.
2006-04-05 Karl Runge <runge@karlrunge.com>
* x11vnc: add FBPM support (-fbpm) for Suns. -rawfb ZERO for
testing. Basic key+cert management utilities: -sslGenCA,
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -122,6 +122,11 @@ void clean_up_exit (int ret) {
/* remove the shm areas: */
clean_shm(0);
stop_stunnel();
if (use_openssl) {
ssl_helper_pid(0, 0); /* killall */
}
if (! dpy) exit(ret); /* raw_rb hack */
/* X keyboard cleanups */
......@@ -139,11 +144,6 @@ void clean_up_exit (int ret) {
if (use_solid_bg) {
solid_bg(1);
}
stop_stunnel();
if (use_openssl) {
ssl_helper_pid(0, 0); /* killall */
}
X_LOCK;
XTestDiscard_wr(dpy);
#if LIBVNCSERVER_HAVE_LIBXDAMAGE
......
......@@ -632,10 +632,8 @@ void print_help(int mode) {
" filesystem to prevent network snooping (for example\n"
" -ssldir /var/lib/x11vnc-certs).\n"
"\n"
" -ssldir effects the other -ssl* options. In the case\n"
" of maintenance commands where the VNC server is not run\n"
" (e.g. -sslGenCA), the -ssldir option must precede the\n"
" command. E.g. x11vnc -ssldir ~/mydir -sslCertInfo LIST\n"
" -ssldir affects nearly all of the other -ssl* options,\n"
" e.g. -ssl SAVE, -sslGenCert, etc..\n"
"\n"
"-sslverify [path] For either of the -ssl or -stunnel modes, use [path]\n"
" to provide certificates to authenticate incoming VNC\n"
......
......@@ -51,7 +51,7 @@ void check_stunnel(void) {
int start_stunnel(int stunnel_port, int x11vnc_port) {
#ifdef SSLCMDS
char extra[] = ":/usr/sbin:/usr/local/sbin";
char extra[] = ":/usr/sbin:/usr/local/sbin:/dist/sbin";
char *path, *p, *exe;
char *stunnel_path = NULL;
struct stat verify_buf;
......@@ -119,6 +119,15 @@ int start_stunnel(int stunnel_port, int x11vnc_port) {
stunnel_port, x11vnc_port);
}
if (stunnel_pem && strstr(stunnel_pem, "SAVE") == stunnel_pem) {
stunnel_pem = get_saved_pem(stunnel_pem, 1);
if (! stunnel_pem) {
rfbLog("start_stunnel: could not create or open"
" saved PEM:\n", stunnel_pem);
clean_up_exit(1);
}
}
if (ssl_verify) {
if (stat(ssl_verify, &verify_buf) != 0) {
rfbLog("stunnel: %s does not exist.\n", ssl_verify);
......@@ -510,30 +519,30 @@ void sslEncKey(char *path, int mode) {
sprintf(tca, "%s/CA/cacert.pem", cdir);
path = tca;
} else if (info_only && (!strcasecmp(path, "LIST") ||
} else if (info_only && (!strcasecmp(path, "LIST") || !strcasecmp(path, "LS") ||
!strcasecmp(path, "ALL"))) {
if (! cdir || strchr(cdir, '\'')) {
fprintf(stderr, "bad certdir char: %s\n", cdir ? cdir : "null");
exit(1);
}
tca = (char *) malloc(2*strlen(cdir) + strlen(program_name) + 1000);
sprintf(tca, "find '%s' -type f | egrep '\\.(crt|pem|key|req)$' "
sprintf(tca, "find '%s' | egrep '/(CA|tmp|clients)$|\\.(crt|pem|key|req)$' "
"| grep -v CA/newcerts", cdir);
if (!strcasecmp(path, "ALL")) {
/* ugh.. */
strcat(tca, " | grep -v private/cakey.pem | xargs -n1 ");
strcat(tca, " | egrep -v 'private/cakey.pem|(CA|tmp|clients)$' | xargs -n1 ");
strcat(tca, program_name);
strcat(tca, " -ssldir '");
strcat(tca, cdir);
strcat(tca, "' -sslCertInfo 2>&1 ");
} else if (listlong) {
strcat(tca, " | xargs ls -l ");
strcat(tca, " | xargs ls -ld ");
}
system(tca);
return;
} else if (info_only && (!strcasecmp(path, "HASHON") ||
!strcasecmp(path, "HASHOFF"))) {
} else if (info_only && (!strcasecmp(path, "HASHON")
|| !strcasecmp(path, "HASHOFF"))) {
tmp_fd = mkstemp(tmp);
if (tmp_fd < 0) {
......
......@@ -122,7 +122,9 @@ char *get_saved_pem(char *save, int create) {
char *new = NULL;
if (create) {
new = create_tmp_pem(path, prompt);
sslEncKey(new, 0);
if (! getenv("X11VNC_SSL_NO_PASSPHRASE") && ! inetd) {
sslEncKey(new, 0);
}
}
return new;
} else {
......@@ -977,6 +979,11 @@ static int is_ssl_readable(int s_in, time_t last_https, char *last_get,
int nfd, db = 0;
struct timeval tv;
fd_set rd;
if (getenv("ACCEPT_OPENSSL_DEBUG")) {
db = atoi(getenv("ACCEPT_OPENSSL_DEBUG"));
}
/*
* we'll do a select() on s_in for reading. this is not an
* absolute proof that SSL_read is ready (XXX use SSL utility).
......@@ -984,6 +991,7 @@ static int is_ssl_readable(int s_in, time_t last_https, char *last_get,
tv.tv_sec = 2;
tv.tv_usec = 0;
if (mode == OPENSSL_INETD) {
/*
* https via inetd is icky because x11vnc is restarted
......@@ -1003,7 +1011,7 @@ static int is_ssl_readable(int s_in, time_t last_https, char *last_get,
tv.tv_sec = 4;
}
}
if (1) fprintf(stderr, "tv_sec: %d - %s\n", (int) tv.tv_sec, last_get);
if (db) fprintf(stderr, "tv_sec: %d - %s\n", (int) tv.tv_sec, last_get);
FD_ZERO(&rd);
FD_SET(s_in, &rd);
......@@ -1024,7 +1032,7 @@ if (1) fprintf(stderr, "tv_sec: %d - %s\n", (int) tv.tv_sec, last_get);
static int watch_for_http_traffic(char *buf_a, int *n_a) {
int is_http, err, n, n2;
char *buf;
int db = 1;
int db = 0;
/*
* sniff the first couple bytes of the stream and try to see
* if it is http or not. if we read them OK, we must read the
......@@ -1032,6 +1040,9 @@ static int watch_for_http_traffic(char *buf_a, int *n_a) {
* what has be read is returned in buf_a and n_a.
* *buf_a is BSIZE+1 long and zeroed.
*/
if (getenv("ACCEPT_OPENSSL_DEBUG")) {
db = atoi(getenv("ACCEPT_OPENSSL_DEBUG"));
}
buf = (char *) calloc(sizeof(BSIZE+1), 1);
*n_a = 0;
......@@ -1076,6 +1087,7 @@ static int watch_for_http_traffic(char *buf_a, int *n_a) {
}
static int csock_timeout_sock = -1;
static void csock_timeout (int sig) {
rfbLog("sig: %d, csock_timeout.\n", sig);
if (csock_timeout_sock >= 0) {
......@@ -1114,6 +1126,10 @@ int proxy_hack(int vncsock, int listen, int s_in, int s_out, char *cookie,
rfbLog("SSL: accept_openssl: detected https proxied connection"
" request.\n");
if (getenv("ACCEPT_OPENSSL_DEBUG")) {
db = atoi(getenv("ACCEPT_OPENSSL_DEBUG"));
}
SSL_write(ssl, reply0, strlen(reply0));
SSL_shutdown(ssl);
SSL_shutdown(ssl);
......@@ -1192,6 +1208,10 @@ void accept_openssl(int mode) {
}
first = 0;
if (getenv("ACCEPT_OPENSSL_DEBUG")) {
db = atoi(getenv("ACCEPT_OPENSSL_DEBUG"));
}
/* do INETD, VNC, or HTTPS cases (result is client socket or pipe) */
if (mode == OPENSSL_INETD) {
ssl_initialized = 1;
......@@ -1314,7 +1334,8 @@ void accept_openssl(int mode) {
/* now connect back to parent socket: */
vncsock = rfbConnectToTcpAddr("127.0.0.1", cport);
if (vncsock < 0) {
rfbLog("SSL: ssl_helper: could not connect back to: %d\n", cport);
rfbLog("SSL: ssl_helper[%d]: could not connect"
" back to: %d\n", getpid(), cport);
close(vncsock);
exit(1);
}
......@@ -1327,6 +1348,7 @@ void accept_openssl(int mode) {
} else {
s_in = s_out = sock;
}
if (! ssl_init(s_in, s_out)) {
close(vncsock);
exit(1);
......@@ -1342,8 +1364,8 @@ void accept_openssl(int mode) {
have_httpd = 1;
}
if (mode == OPENSSL_HTTPS && ! have_httpd) {
rfbLog("SSL: accept_openssl: no httpd socket for "
"-https mode\n");
rfbLog("SSL: accept_openssl[%d]: no httpd socket for "
"-https mode\n", getpid());
close(vncsock);
exit(1);
}
......@@ -1371,7 +1393,6 @@ void accept_openssl(int mode) {
* Check if there is stuff to read from remote end
* if so it is likely a GET or HEAD.
*/
if (1) fprintf(stderr, "is_ssl_readable\n");
if (! is_ssl_readable(s_in, last_https, last_get,
mode)) {
goto write_cookie;
......@@ -1384,7 +1405,7 @@ void accept_openssl(int mode) {
* is ever sent. So often we timeout here.
*/
if (1) fprintf(stderr, "watch_for_http_traffic\n");
if (db) fprintf(stderr, "watch_for_http_traffic\n");
is_http = watch_for_http_traffic(buf, &n);
if (is_http < 0 || is_http == 0) {
......@@ -1392,27 +1413,47 @@ void accept_openssl(int mode) {
* error or http not detected, fall back
* to normal VNC socket.
*/
if (db) fprintf(stderr, "is_http err: %d n: %d\n", is_http, n);
write(vncsock, cookie, strlen(cookie));
if (n > 0) {
write(vncsock, buf, n);
}
goto wrote_cookie;
}
if (1) fprintf(stderr, "buf: '%s'\n", buf);
if (db) fprintf(stderr, "is_http: %d n: %d\n", is_http, n);
if (db) fprintf(stderr, "buf: '%s'\n", buf);
if (strstr(buf, "/request.https.proxy.connection")) {
if (strstr(buf, "/request.https.vnc.connection")) {
char reply[] = "HTTP/1.0 200 OK\r\n"
"Content-Type: octet-stream\r\n"
"Connection: Keep-Alive\r\n"
"Pragma: no-cache\r\n\r\n";
/*
* special case proxy coming thru https
* instead of a direct SSL connection.
*/
if (! proxy_hack(vncsock, listen, s_in, s_out,
cookie, mode)) {
strcpy(tbuf, uniq);
strcat(tbuf, cookie);
write(vncsock, tbuf, strlen(tbuf));
close(vncsock);
rfbLog("Handling VNC request via https GET. [%d]\n", getpid());
if (strstr(buf, "/reverse.proxy")) {
char *buf;
int n, ptr;
SSL_write(ssl, reply, strlen(reply));
buf = (char *) calloc((8192+1), 1);
n = 0;
ptr = 0;
while (ptr < 8192) {
n = SSL_read(ssl, buf + ptr, 1);
if (n > 0) {
ptr += n;
}
if (db) fprintf(stderr, "buf2: '%s'\n", buf);
if (strstr(buf, "\r\n\r\n")) {
break;
}
}
}
exit(0);
goto write_cookie;
} else if (strstr(buf, "/check.https.proxy.connection")) {
char reply[] = "HTTP/1.0 200 OK\r\n"
......@@ -1491,7 +1532,8 @@ if (db) fprintf(stderr, "iface: %s\n", iface);
rfbLog("Could not connect to httpd socket!\n");
exit(1);
}
if (db) fprintf(stderr, "ssl_helper: httpsock: %d %d\n", httpsock, n);
if (db) fprintf(stderr, "ssl_helper[%d]: httpsock: %d %d\n",
getpid(), httpsock, n);
/*
* send what we read to httpd, and then connect
......@@ -1651,11 +1693,14 @@ static void ssl_timeout (int sig) {
static int ssl_init(int s_in, int s_out) {
unsigned char *sid = (unsigned char *) "x11vnc SID";
char *name;
int db = 1, rc, err;
int db = 0, rc, err;
int ssock = s_in;
double start = dnow();
int timeout = 20;
if (getenv("SSL_DEBUG")) {
db = atoi(getenv("SSL_DEBUG"));
}
if (db) fprintf(stderr, "ssl_init: %d/%d\n", s_in, s_out);
ssl = SSL_new(ctx);
......@@ -1749,7 +1794,7 @@ if (db > 1) fprintf(stderr, "d\n");
usleep(10 * 1000);
}
rfbLog("SSL: ssl_helper: SSL_accept() succeeded for: %s\n", name);
rfbLog("SSL: ssl_helper[%d]: SSL_accept() succeeded for: %s\n", getpid(), name);
free(name);
return 1;
......@@ -1816,14 +1861,39 @@ static void ssl_xfer(int csock, int s_in, int s_out, int is_https) {
int cptr, sptr, c_rd, c_wr, s_rd, s_wr;
fd_set rd, wr;
struct timeval tv;
int ssock;
int ssock, cnt = 0;
/*
* we want to switch to a longer timeout for long term VNC
* connections (in case the network is not working for short
* periods), but we also want the timeout shorter at the beginning
* in case the client went away.
*/
time_t start;
int tv_https_early = 60;
int tv_https_later = 20;
int tv_vnc_early = 25;
int tv_vnc_later = 300;
int tv_cutover = 120;
int tv_use;
if (dbxfer) {
raw_xfer(csock, s_in, s_out);
return;
}
if (getenv("SSL_DEBUG")) {
db = atoi(getenv("SSL_DEBUG"));
}
if (db) fprintf(stderr, "ssl_xfer begin\n");
if (db) fprintf(stderr, "ssl_xfer begin\n");
start = time(0);
if (is_https) {
tv_use = tv_https_early;
} else {
tv_use = tv_vnc_early;
}
/*
* csock: clear text socket with libvncserver. "C"
......@@ -1890,6 +1960,7 @@ if (db) fprintf(stderr, "ssl_xfer begin\n");
*/
break;
}
cnt++;
/* set up the fd sets for the two sockets for read & write: */
......@@ -1927,11 +1998,15 @@ if (db) fprintf(stderr, "ssl_xfer begin\n");
}
}
if (is_https) {
tv.tv_sec = 50;
} else {
tv.tv_sec = 35;
if (tv_cutover && time(0) > start + tv_cutover) {
tv_cutover = 0;
if (is_https) {
tv_use = tv_https_later;
} else {
tv_use = tv_vnc_later;
}
}
tv.tv_sec = tv_use;
tv.tv_usec = 0;
/* do the select, repeat if interrupted */
......@@ -1939,7 +2014,7 @@ if (db) fprintf(stderr, "ssl_xfer begin\n");
nfd = select(fdmax+1, &rd, &wr, NULL, &tv);
} while (nfd < 0 && errno == EINTR);
if (db) fprintf(stderr, "nfd: %d\n", nfd);
if (db > 1) fprintf(stderr, "nfd: %d\n", nfd);
if (nfd < 0) {
rfbLog("SSL: ssl_xfer[%d]: select error: %d\n", getpid(), nfd);
......
......@@ -267,15 +267,20 @@ char genCert[] =
"\n"
"direrror() {\n"
" echo \"\"\n"
" echo \"You need first to run:\"\n"
" echo \"\"\n"
" if echo \"$DIR\" | grep '/\\.vnc/certs' > /dev/null; then\n"
" echo \"You need first to run: x11vnc -sslGenCA\"\n"
" echo \" x11vnc -sslGenCA\"\n"
" else\n"
" echo \"You need first to run: x11vnc -sslGenCA $DIR\"\n"
" echo \" x11vnc -sslGenCA $DIR\"\n"
" fi\n"
" echo \"\"\n"
" echo \"to create the CA cert file and other needed config files and directories.\"\n"
" echo \"\"\n"
" echo \"Then you can run: x11vnc -sslGenCert $type $name0\"\n"
" echo \"\"\n"
" if [ \"X$1\" != \"X\" ]; then\n"
" echo \"(missing: $1)\"\n"
" echo \"(missing file/dir: $1)\"\n"
" echo \"\"\n"
" fi\n"
" exit 1\n"
......
......@@ -2,7 +2,7 @@
.TH X11VNC "1" "April 2006" "x11vnc " "User Commands"
.SH NAME
x11vnc - allow VNC connections to real X11 displays
version: 0.8.1, lastmod: 2006-04-05
version: 0.8.1, lastmod: 2006-04-16
.SH SYNOPSIS
.B x11vnc
[OPTION]...
......@@ -755,10 +755,8 @@ might want your certificates and keys to be on a local
filesystem to prevent network snooping (for example
\fB-ssldir\fR /var/lib/x11vnc-certs).
.IP
\fB-ssldir\fR effects the other \fB-ssl*\fR options. In the case
of maintenance commands where the VNC server is not run
(e.g. \fB-sslGenCA),\fR the \fB-ssldir\fR option must precede the
command. E.g. x11vnc \fB-ssldir\fR ~/mydir \fB-sslCertInfo\fR LIST
\fB-ssldir\fR affects nearly all of the other \fB-ssl*\fR options,
e.g. \fB-ssl\fR SAVE, \fB-sslGenCert,\fR etc..
.PP
\fB-sslverify\fR \fI[path]\fR
.IP
......
......@@ -1439,6 +1439,21 @@ int main(int argc, char* argv[]) {
exit(1); \
}
/*
* do a quick check for parameters that apply to "utility"
* commands, i.e. ones that do not run the server.
*/
for (i=1; i < argc; i++) {
arg = argv[i];
if (strstr(arg, "--") == arg) {
arg++;
}
if (!strcmp(arg, "-ssldir")) {
CHECK_ARGC
ssl_certs_dir = strdup(argv[++i]);
}
}
for (i=1; i < argc; i++) {
/* quick-n-dirty --option handling. */
arg = argv[i];
......
......@@ -15,7 +15,7 @@ int xtrap_base_event_type = 0;
int xdamage_base_event_type = 0;
/* date +'lastmod: %Y-%m-%d' */
char lastmod[] = "0.8.1 lastmod: 2006-04-05";
char lastmod[] = "0.8.1 lastmod: 2006-04-16";
/* X display info */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment