From 0a6f75c6226f8a0f47c96c6efec7efd82c28f680 Mon Sep 17 00:00:00 2001 From: runge Date: Thu, 23 Nov 2006 23:33:17 +0000 Subject: [PATCH] rename ssl_vncviewer to ss_vncviewer --- classes/ssl/ss_vncviewer | 638 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 638 insertions(+) create mode 100755 classes/ssl/ss_vncviewer diff --git a/classes/ssl/ss_vncviewer b/classes/ssl/ss_vncviewer new file mode 100755 index 0000000..0477eee --- /dev/null +++ b/classes/ssl/ss_vncviewer @@ -0,0 +1,638 @@ +#!/bin/sh +# +# ssl_vncviewer: wrapper for vncviewer to use an stunnel SSL tunnel +# or an SSH tunnel. +# +# Copyright (c) 2006 by Karl J. Runge +# +# You must have stunnel(8) installed on the system and in your PATH +# (however, see the -ssh option below, in which case you will need ssh(1) +# installed) Note: stunnel is usually installed in an "sbin" subdirectory. +# +# You should have "x11vnc -ssl ..." or "x11vnc -stunnel ..." +# already running as the VNC server on the remote machine. +# (or use stunnel on the server side for any other VNC server) +# +# +# Usage: ssl_vncviewer [cert-args] host:display +# +# 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 +# (the first CONNECT is done through host1:port1 to host2:port2 +# and then a 2nd CONNECT to the destination VNC server.) +# +# See http://www.karlrunge.com/x11vnc/#faq-ssl-ca for details on SSL +# certificates with VNC. +# +# A few other args (not related to SSL and certs): +# +# -ssh Use ssh instead of stunnel SSL. ssh(1) must be installed and you +# must be able to log into the remote machine via ssh. +# +# In this case "host:display" may be of the form "user@host:display" +# where "user@host" is used for the ssh login (see ssh(1) manpage). +# +# If -proxy is supplied it can be of the forms: "gwhost" "gwhost:port" +# "user@gwhost" or "user@gwhost:port". "gwhost" is an incoming ssh +# gateway machine (the VNC server is not running there), an ssh -L +# redir is used to "host" in "host:display" from "gwhost". Any "user@" +# part must be in the -proxy string (not in "host:display"). +# +# Under -proxy use "gwhost:port" if connecting to any ssh port +# other than the default (22). (even for the non-gateway case, +# -proxy must be used to specify a non-standard ssh port) +# +# A "double ssh" can be specified via a -proxy string with the two +# hosts separated by a comma: +# +# [user1@]host1[:port1],[user2@]host2[:port2] +# +# in which case a ssh to host1 and thru it via a -L redir a 2nd +# ssh is established to host2. +# +# Examples: +# +# ssl_vncviewer -ssh bob@bobs-home.net:0 +# ssl_vncviewer -ssh -sshcmd 'x11vnc -localhost' bob@bobs-home.net:0 +# +# ssl_vncviewer -ssh -proxy fred@mygate.com:2022 mymachine:0 +# ssl_vncviewer -ssh -proxy bob@bobs-home.net:2222 localhost:0 +# +# ssl_vncviewer -ssh -proxy fred@gw-host,fred@peecee localhost:0 +# +# -sshcmd cmd Run "cmd" via ssh instead of the default "sleep 15" +# e.g. -sshcmd 'x11vnc -display :0 -localhost -rfbport 5900' +# +# -sshargs "args" pass "args" to the ssh process, e.g. -L/-R port redirs. +# +# -sshssl Tunnel the SSL connection thru a SSH connection. The tunnel as +# under -ssh is set up and the SSL connection goes thru it. Use +# this if you want to have and end-to-end SSL connection but must +# go thru a SSH gateway host (e.g. not the vnc server). Or use +# this if you need to tunnel additional services via -R and -L +# (see -sshargs above). +# +# ssl_vncviewer -sshssl -proxy fred@mygate.com mymachine:0 +# +# +# -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. set it to /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() { + tail +2 "$0" | sed -e '/^$/ q' +} + +gotalpha="" +use_ssh="" +use_sshssl="" +direct_connect="" +ssh_sleep=15 +ssh_cmd="sleep $ssh_sleep" +if [ "X$SSL_VNCVIEWER_SSH_CMD" != "X" ]; then + ssh_cmd="$SSL_VNCVIEWER_SSH_CMD" +fi +ssh_args="" + +# grab our cmdline options: +while [ "X$1" != "X" ] +do + case $1 in + "-verify") shift; verify="$1" + ;; + "-mycert") shift; mycert="$1" + ;; + "-proxy") shift; proxy="$1" + ;; + "-ssh") use_ssh=1 + ;; + "-sshssl") use_ssh=1 + use_sshssl=1 + ;; + "-sshcmd") shift; ssh_cmd="$1" + ;; + "-sshargs") shift; ssh_args="$1" + ;; + "-alpha") gotalpha=1 + ;; + "-grab") VNCVIEWER_GRAB_SERVER=1; export VNCVIEWER_GRAB_SERVER + ;; + "-h"*) help; exit 0 + ;; + "--h"*) help; exit 0 + ;; + *) break + ;; + esac + shift +done + +if [ "X$gotalpha" != "X1" ]; then + NO_ALPHABLEND=1 + export NO_ALPHABLEND +fi + +orig="$1" +shift + +if [ "X$use_ssh" = "X1" -a "X$use_sshssl" = "X" ]; then + if [ "X$mycert" != "X" -o "X$verify" != "X" ]; then + echo "-mycert and -verify cannot be used in -ssh mode" + exit 1 + fi +fi + +if echo "$orig" | grep '^vnc://' > /dev/null; then + orig=`echo "$orig" | sed -e 's,vnc://,,'` + verify="" + mycert="" + use_ssh="" + use_sshssl="" + direct_connect=1 +fi + +# 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): +inuse="" +if uname | grep Linux > /dev/null; then + inuse=`netstat -ant | egrep 'LISTEN|WAIT|ESTABLISH|CLOSE' | 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/^.*\.//'` +# add others... +fi + +date_sec=`date +%S` + +findfree() { + try0=$1 + try=$try0 + use0="" + + while [ $try -lt 6000 ] + do + if [ "X$inuse" = "X" ]; then + break + fi + if echo "$inuse" | grep -w $try > /dev/null; then + : + else + use0=$try + break + fi + try=`expr $try + 1` + done + if [ "X$use0" = "X" ]; then + use0=`expr $date_sec + $try0` + fi + + echo $use0 +} + +use=`findfree 5930` + +if [ $use -ge 5900 ]; then + N=`expr $use - 5900` +else + N=$use +fi + +if echo "$0" | grep vncip > /dev/null; then + VNCVIEWERCMD="$VNCIPCMD" +fi + +if [ "X$use_ssh" = "X1" ]; then + ssh_port="22" + ssh_host="$host" + vnc_host="localhost" + ssh=${SSH:-"ssh -x"} + if echo "$proxy" | grep "," > /dev/null; then + proxy1=`echo "$proxy" | awk -F, '{print $1}'` + proxy2=`echo "$proxy" | awk -F, '{print $2}'` + # user1@gw1.com:port1,user2@ws2:port2 + ssh_host1=`echo "$proxy1" | awk -F: '{print $1}'` + ssh_port1=`echo "$proxy1" | awk -F: '{print $2}'` + if [ "X$ssh_port1" = "X" ]; then + ssh_port1="22" + fi + ssh_host2=`echo "$proxy2" | awk -F: '{print $1}'` + ssh_user2=`echo "$ssh_host2" | awk -F@ '{print $1}'` + ssh_host2=`echo "$ssh_host2" | awk -F@ '{print $2}'` + if [ "X$ssh_host2" = "X" ]; then + ssh_host2=$ssh_user2 + ssh_user2="" + else + ssh_user2="${ssh_user2}@" + fi + ssh_port2=`echo "$proxy2" | awk -F: '{print $2}'` + if [ "X$ssh_port2" = "X" ]; then + ssh_port2="22" + fi + proxport=`findfree 3500` + echo + echo "Running 1st ssh proxy:" + echo "$ssh -f -x -p $ssh_port1 -t -e none -L $proxport:$ssh_host2:$ssh_port2 $ssh_host1 \"sleep 30\"" + $ssh -f -x -p $ssh_port1 -t -e none -L $proxport:$ssh_host2:$ssh_port2 $ssh_host1 "sleep 30" + ssh_args="$ssh_args -o NoHostAuthenticationForLocalhost=yes" + sleep 1 + stty sane + proxy="${ssh_user2}localhost:$proxport" + fi + if [ "X$proxy" != "X" ]; then + ssh_port=`echo "$proxy" | awk -F: '{print $2}'` + if [ "X$ssh_port" = "X" ]; then + ssh_port="22" + fi + ssh_host=`echo "$proxy" | awk -F: '{print $1}'` + vnc_host="$host" + fi + echo "" + echo "Running ssh:" + sz=`echo "$ssh_cmd" | wc -c` + if [ "$sz" -gt 200 ]; then + info="..." + else + info="$ssh_cmd" + fi + + C="" + if [ "X$SSL_VNCVIEWER_USE_C" != "X" ]; then + C="-C" + fi + # the -t option actually speeds up typing response via VNC!! + if [ "X$SSL_VNCVIEWER_SSH_ONLY" != "X" ]; then + echo "$ssh -x -p $ssh_port -t $C $ssh_args $ssh_host \"$info\"" + echo "" + $ssh -x -p $ssh_port -t $C $ssh_args $ssh_host "$ssh_cmd" + exit $? + elif [ "X$SSL_VNCVIEWER_NO_F" != "X" ]; then + echo "$ssh -x -p $ssh_port -t $C -L ${use}:${vnc_host}:${port} $ssh_args $ssh_host \"$info\"" + echo "" + $ssh -x -p $ssh_port -t $C -L ${use}:${vnc_host}:${port} $ssh_args $ssh_host "$ssh_cmd" + else + echo "$ssh -x -f -p $ssh_port -t $C -L ${use}:${vnc_host}:${port} $ssh_args $ssh_host \"$info\"" + echo "" + $ssh -x -f -p $ssh_port -t $C -L ${use}:${vnc_host}:${port} $ssh_args $ssh_host "$ssh_cmd" + fi + if [ "$?" != "0" ]; then + echo "" + echo "ssh to $ssh_host failed." + exit 1 + fi + echo "" + if [ "X$ssh_cmd" = "Xsleep $ssh_sleep" ] ; then + sleep 1 + else + # let any command get started a bit. + sleep 5 + fi + echo "" + #reset + stty sane + if [ "X$use_sshssl" = "X" ]; then + echo "Running viewer:" + echo "$VNCVIEWERCMD" "$@" localhost:$N + echo "" + "$VNCVIEWERCMD" "$@" localhost:$N + + exit $? + else + use2=`findfree 5960` + host0=$host + port0=$port + host=localhost + port=$use + use=$use2 + N=`expr $use - 5900` + proxy="" + fi +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 + +mytmp() { + tf=$1 + rm -rf "$tf" || exit 1 + if [ -d "$tf" ]; then + echo "tmp file $tf still exists as a directory." + exit 1 + elif [ -L "$tf" ]; then + echo "tmp file $tf still exists as a symlink." + exit 1 + elif [ -f "$tf" ]; then + echo "tmp file $tf still exists." + exit 1 + fi + touch "$tf" || exit 1 + chmod 600 "$tf" || exit 1 +} + +if echo "$RANDOM" | grep '[^0-9]' > /dev/null; then + RANDOM=`date +%S` +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 $listen_handle = ""; +if ($ENV{SSL_VNC_LISTEN} != "") { + my $listen_sock = IO::Socket::INET->new( + Listen => 2, + LocalAddr => "localhost", + LocalPort => $ENV{SSL_VNC_LISTEN}, + Proto => "tcp"); + if (! $listen_sock) { + die "perl proxy: $!\n"; + } + my $ip; + ($listen_handle, $ip) = $listen_sock->accept(); + if (! $listen_handle) { + die "perl proxy: $!\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"; + if ($listen_handle) { + xfer($listen_handle, $sock); + } else { + xfer(STDIN, $sock); + } +} else { + print STDERR "child \[$$] socket -> STDOUT\n\n"; + if ($listen_handle) { + xfer($sock, $listen_handle); + } else { + 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); +} +' + echo "$cod" > $tf + chmod 700 $tf +} + +ptmp="" +if [ "X$proxy" != "X" ]; then + ptmp="/tmp/ssl_vncviewer${RANDOM}.$$.pl" + mytmp "$ptmp" + pcode "$ptmp" + connect="exec = $ptmp" +else + connect="connect = $host:$port" +fi + +if [ "X$direct_connect" != "X" ]; then + echo "" + echo "Running viewer for direct connection:" + echo "" + echo "** NOTE: THERE WILL BE NO SSL OR SSH ENCRYPTION **" + echo "" + if type printf > /dev/null 2>&1; then + printf "Are you sure you want to continue? [y]/n " + else + echo -n "Are you sure you want to continue? [y]/n " + fi + read x + if [ "X$x" = "Xn" ]; then + exit 1 + fi + echo "" + if [ "X$ptmp" != "X" ]; then + SSL_VNC_LISTEN=$use + export SSL_VNC_LISTEN + $ptmp & + sleep 2 + host="localhost" + disp="$N" + fi + echo "$VNCVIEWERCMD" "$@" $host:$disp + echo "" + "$VNCVIEWERCMD" "$@" $host:$disp + exit $? +fi + +##debug = 7 +tmp=/tmp/ssl_vncviewer${RANDOM}.$$ +mytmp "$tmp" + +cat > "$tmp" < /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" + +echo "" +echo "Running viewer:" +echo "$VNCVIEWERCMD" "$@" localhost:$N +echo "" +"$VNCVIEWERCMD" "$@" localhost:$N + +kill $pid +sleep 1