|
|
|
#!/bin/sh
|
|
|
|
#
|
|
|
|
# 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).
|
|
|
|
#
|
|
|
|
# You should have "x11vnc -ssl ..." or "x11vnc -stunnel ..."
|
|
|
|
# running as the VNC server.
|
|
|
|
#
|
|
|
|
# usage: ssl_vncviewer [cert-args] host:display <vncviewer-args>
|
|
|
|
#
|
|
|
|
# e.g.: ssl_vncviewer snoopy:0
|
|
|
|
# ssl_vncviewer snoopy:0 -encodings "copyrect tight zrle hextile"
|
|
|
|
#
|
|
|
|
# [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.
|
|
|
|
#
|
|
|
|
# -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
|
|
|
|
#
|
|
|
|
# A couple other args (not related to certs):
|
|
|
|
#
|
|
|
|
# -alpha turn on cursor alphablending hack if you are using the
|
|
|
|
# enhanced tightvnc vncviewer.
|
|
|
|
#
|
|
|
|
# -grab turn on XGrabServer hack if you are using the enhanced tightvnc
|
|
|
|
# vncviewer (e.g. for fullscreen mode in some windowmanagers like
|
|
|
|
# fvwm that do not otherwise work in fullscreen mode)
|
|
|
|
#
|
|
|
|
#
|
|
|
|
# set VNCVIEWERCMD to whatever vncviewer command you want to use:
|
|
|
|
#
|
|
|
|
VNCIPCMD=${VNCVIEWERCMD:-vncip}
|
|
|
|
VNCVIEWERCMD=${VNCVIEWERCMD:-vncviewer}
|
|
|
|
#
|
|
|
|
# Same for STUNNEL, e.g. /path/to/stunnel or stunnel4, etc.
|
|
|
|
#
|
|
|
|
|
|
|
|
PATH=$PATH:/usr/sbin:/usr/local/sbin:/dist/sbin; export PATH
|
|
|
|
|
|
|
|
if [ "X$STUNNEL" = "X" ]; then
|
|
|
|
type stunnel4 > /dev/null 2>&1
|
|
|
|
if [ $? = 0 ]; then
|
|
|
|
STUNNEL=stunnel4
|
|
|
|
else
|
|
|
|
STUNNEL=stunnel
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
|
|
|
help() {
|
|
|
|
head -39 $0 | tail +2
|
|
|
|
}
|
|
|
|
|
|
|
|
gotalpha=""
|
|
|
|
|
|
|
|
# grab our cmdline options:
|
|
|
|
while [ "X$1" != "X" ]
|
|
|
|
do
|
|
|
|
case $1 in
|
|
|
|
"-verify") shift; verify="$1"
|
|
|
|
;;
|
|
|
|
"-mycert") shift; mycert="$1"
|
|
|
|
;;
|
|
|
|
"-proxy") shift; proxy="$1"
|
|
|
|
;;
|
|
|
|
"-alpha") gotalpha=1
|
|
|
|
;;
|
|
|
|
"-grab") VNCVIEWER_GRAB_SERVER=1; export VNCVIEWER_GRAB_SERVER
|
|
|
|
;;
|
|
|
|
"-h"*) help; exit 0
|
|
|
|
;;
|
|
|
|
*) break
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
shift
|
|
|
|
done
|
|
|
|
|
|
|
|
if [ "X$gotalpha" != "X1" ]; then
|
|
|
|
NO_ALPHABLEND=1
|
|
|
|
export NO_ALPHABLEND
|
|
|
|
fi
|
|
|
|
|
|
|
|
orig="$1"
|
|
|
|
shift
|
|
|
|
|
|
|
|
# play around with host:display port:
|
|
|
|
if echo "$orig" | grep ':' > /dev/null; then
|
|
|
|
:
|
|
|
|
else
|
|
|
|
orig="$orig:0"
|
|
|
|
fi
|
|
|
|
|
|
|
|
host=`echo "$orig" | awk -F: '{print $1}'`
|
|
|
|
disp=`echo "$orig" | awk -F: '{print $2}'`
|
|
|
|
if [ "X$host" = "X" ]; then
|
|
|
|
host=localhost
|
|
|
|
fi
|
|
|
|
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
|
|
|
|
if echo "$inuse" | grep -w $try > /dev/null; then
|
|
|
|
:
|
|
|
|
else
|
|
|
|
use=$try
|
|
|
|
break
|
|
|
|
fi
|
|
|
|
try=`expr $try + 1`
|
|
|
|
done
|
|
|
|
fi
|
|
|
|
if [ "X$use" = "X" ]; then
|
|
|
|
# otherwise choose a "random" one:
|
|
|
|
use=`date +%S`
|
|
|
|
use=`expr $use + 5920`
|
|
|
|
fi
|
|
|
|
|
|
|
|
# create the stunnel config file:
|
|
|
|
if [ "X$verify" != "X" ]; then
|
|
|
|
if [ -d $verify ]; then
|
|
|
|
verify="CApath = $verify"
|
|
|
|
else
|
|
|
|
verify="CAfile = $verify"
|
|
|
|
fi
|
|
|
|
verify="$verify
|
|
|
|
verify = 2"
|
|
|
|
fi
|
|
|
|
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
|
|
|
|
foreground = yes
|
|
|
|
pid =
|
|
|
|
client = yes
|
|
|
|
$verify
|
|
|
|
$cert
|
|
|
|
|
|
|
|
[vnc_stunnel]
|
|
|
|
accept = $use
|
|
|
|
$connect
|
|
|
|
END
|
|
|
|
|
|
|
|
echo ""
|
|
|
|
echo "Using this stunnel configuration:"
|
|
|
|
echo ""
|
|
|
|
cat $tmp | uniq
|
|
|
|
echo ""
|
|
|
|
sleep 1
|
|
|
|
|
|
|
|
echo "running: $STUNNEL $tmp"
|
|
|
|
$STUNNEL $tmp < /dev/tty > /dev/tty &
|
|
|
|
pid=$!
|
|
|
|
echo ""
|
|
|
|
|
|
|
|
# pause here to let the user supply a possible passphrase for the
|
|
|
|
# mycert key:
|
|
|
|
if [ "X$mycert" != "X" ]; then
|
|
|
|
sleep 4
|
|
|
|
fi
|
|
|
|
sleep 2
|
|
|
|
rm -f $tmp
|
|
|
|
|
|
|
|
if [ $use -ge 5900 ]; then
|
|
|
|
n=`expr $use - 5900`
|
|
|
|
fi
|
|
|
|
|
|
|
|
if echo "$0" | grep vncip > /dev/null; then
|
|
|
|
# hack for runge's special wrapper script vncip.
|
|
|
|
$VNCIPCMD "$@" localhost:$n
|
|
|
|
else
|
|
|
|
$VNCVIEWERCMD "$@" localhost:$n
|
|
|
|
fi
|
|
|
|
|
|
|
|
kill $pid
|
|
|
|
sleep 1
|