#!/bin/sh # # ss_vncviewer: wrapper for vncviewer to use an stunnel SSL tunnel # or an SSH tunnel. # # Copyright (c) 2006-2009 by Karl J. Runge # # ss_vncviewer is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or (at # your option) any later version. # # ss_vncviewer is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with ss_vncviewer; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA # or see . # # # 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: ss_vncviewer [cert-args] host:display # # e.g.: ss_vncviewer snoopy:0 # ss_vncviewer snoopy:0 -encodings "copyrect tight zrle hextile" # # [cert-args] can be: # # -verify /path/to/cacert.pem # -mycert /path/to/mycert.pem # -crl /path/to/my_crl.pem (or directory) # -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.) # # Use socks://host:port, socks4://host:port, or socks5://host,port # to force usage of a SOCKS proxy. Also repeater://host:port and # sslrepeater://host:port. # # -showcert Only fetch the certificate using the 'openssl s_client' # command (openssl(1) must in installed). # # See http://www.karlrunge.com/x11vnc/faq.html#faq-ssl-ca for details on # SSL certificates with VNC. # # A few other args (not related to SSL and certs): # # -2nd Run the vncviewer a 2nd time if the first connections fails. # # -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: # # ss_vncviewer -ssh bob@bobs-home.net:0 # ss_vncviewer -ssh -sshcmd 'x11vnc -localhost' bob@bobs-home.net:0 # # ss_vncviewer -ssh -proxy fred@mygate.com:2022 mymachine:0 # ss_vncviewer -ssh -proxy bob@bobs-home.net:2222 localhost:0 # # ss_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). # # ss_vncviewer -sshssl -proxy fred@mygate.com mymachine:0 # # -listen (or -reverse) set up a reverse connection. # # -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} if [ "X$SSVNC_TURBOVNC" != "X" ]; then if echo "$VNCVIEWERCMD" | grep '\.turbovnc' > /dev/null; then : else if type "$VNCVIEWERCMD.turbovnc" > /dev/null 2>/dev/null; then VNCVIEWERCMD="$VNCVIEWERCMD.turbovnc" fi fi fi # # Same for STUNNEL, e.g. set it to /path/to/stunnel or stunnel4, etc. # # turn on verbose debugging output if [ "X$SS_DEBUG" != "X" -a "X$SS_DEBUG" != "X0" ]; then set -xv fi PATH=$PATH:/usr/sbin:/usr/local/sbin:/dist/sbin; export PATH localhost="localhost" if uname | grep Darwin >/dev/null; then localhost="127.0.0.1" fi # work out which stunnel to use (debian installs as stunnel4) stunnel_set_here="" if [ "X$STUNNEL" = "X" ]; then check_stunnel=1 if [ "X$SSVNC_BASEDIRNAME" != "X" ]; then if [ -x "$SSVNC_BASEDIRNAME/stunnel" ]; then type stunnel > /dev/null 2>&1 if [ $? = 0 ]; then # found ours STUNNEL=stunnel check_stunnel=0 fi fi fi if [ "X$check_stunnel" = "X1" ]; then type stunnel4 > /dev/null 2>&1 if [ $? = 0 ]; then STUNNEL=stunnel4 else STUNNEL=stunnel fi fi stunnel_set_here=1 fi help() { tail -n +2 "$0" | sed -e '/^$/ q' } secondtry="" gotalpha="" use_ssh="" use_sshssl="" direct_connect="" ssh_sleep=15 # sleep longer in -listen mode: if echo "$*" | grep '.*-listen' > /dev/null; then ssh_sleep=1800 fi ssh_cmd="" # env override of ssh_cmd: if [ "X$SS_VNCVIEWER_SSH_CMD" != "X" ]; then ssh_cmd="$SS_VNCVIEWER_SSH_CMD" fi ssh_args="" showcert="" reverse="" ciphers="" anondh="ALL:RC4+RSA:+SSLv2:@STRENGTH" anondh_set="" stunnel_debug="6" if [ "X$SS_DEBUG" != "X" -o "X$SSVNC_VENCRYPT_DEBUG" != "X" -o "X$SSVNC_STUNNEL_DEBUG" != "X" ]; then stunnel_debug="7" fi if [ "X$1" = "X-viewerflavor" ]; then # special case, try to guess which viewer: # if echo "$VNCVIEWERCMD" | egrep -i '^(xmessage|sleep )' > /dev/null; then echo "unknown" exit 0 fi if echo "$VNCVIEWERCMD" | grep -i chicken.of > /dev/null; then echo "cotvnc" exit 0 fi if echo "$VNCVIEWERCMD" | grep -i ultra > /dev/null; then echo "ultravnc" exit 0 fi # OK, run it for help output... str=`$VNCVIEWERCMD -h 2>&1 | head -n 5` if echo "$str" | grep -i 'TightVNC.viewer' > /dev/null; then echo "tightvnc" elif echo "$str" | grep -i 'VNC viewer version 3' > /dev/null; then echo "realvnc3" elif echo "$str" | grep -i 'VNC viewer .*Edition 4' > /dev/null; then echo "realvnc4" elif echo "$str" | grep -i 'RealVNC.Ltd' > /dev/null; then echo "realvnc4" else echo "unknown" fi exit 0 fi if [ "X$1" = "X-viewerhelp" ]; then $VNCVIEWERCMD -h 2>&1 exit 0 fi # grab our cmdline options: while [ "X$1" != "X" ] do case $1 in "-verify") shift; verify="$1" ;; "-mycert") shift; mycert="$1" ;; "-crl") shift; crl="$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" ;; "-anondh") ciphers="ciphers=$anondh" anondh_set=1 ;; "-ciphers") shift; ciphers="ciphers=$1" ;; "-alpha") gotalpha=1 ;; "-showcert") showcert=1 ;; "-listen") reverse=1 ;; "-reverse") reverse=1 ;; "-2nd") secondtry=1 ;; "-grab") VNCVIEWER_GRAB_SERVER=1; export VNCVIEWER_GRAB_SERVER ;; "-x11cursor") VNCVIEWER_X11CURSOR=1; export VNCVIEWER_X11CURSOR ;; "-rawlocal") VNCVIEWER_RAWLOCAL=1; export VNCVIEWER_RAWLOCAL ;; "-scale") shift; SSVNC_SCALE="$1"; export SSVNC_SCALE ;; "-onelisten") SSVNC_LISTEN_ONCE=1; export SSVNC_LISTEN_ONCE ;; "-sendclipboard") VNCVIEWER_SEND_CLIPBOARD=1; export VNCVIEWER_SEND_CLIPBOARD ;; "-sendalways") VNCVIEWER_SEND_ALWAYS=1; export VNCVIEWER_SEND_ALWAYS ;; "-recvtext") shift; VNCVIEWER_RECV_TEXT="$1"; export VNCVIEWER_RECV_TEXT ;; "-escape") shift; VNCVIEWER_ESCAPE="$1"; export VNCVIEWER_ESCAPE ;; "-ssvnc_encodings") shift; VNCVIEWER_ENCODINGS="$1"; export VNCVIEWER_ENCODINGS ;; "-ssvnc_extra_opts") shift; VNCVIEWERCMD_EXTRA_OPTS="$1"; export VNCVIEWERCMD_EXTRA_OPTS ;; "-rfbversion") shift; VNCVIEWER_RFBVERSION="$1"; export VNCVIEWER_RFBVERSION ;; "-nobell") VNCVIEWER_NOBELL=1; export VNCVIEWER_NOBELL ;; "-popupfix") VNCVIEWER_POPUP_FIX=1; export VNCVIEWER_POPUP_FIX ;; "-realvnc4") VNCVIEWER_IS_REALVNC4=1; export VNCVIEWER_IS_REALVNC4 ;; "-h"*) help; exit 0 ;; "--h"*) help; exit 0 ;; *) break ;; esac shift done # maxconn is something we added to stunnel, this disables it: if [ "X$SS_VNCVIEWER_NO_MAXCONN" != "X" ]; then STUNNEL_EXTRA_OPTS=`echo "$STUNNEL_EXTRA_OPTS" | sed -e 's/maxconn/#maxconn/'` elif echo "$VNCVIEWERCMD" | egrep -i '^(xmessage|sleep )' > /dev/null; then STUNNEL_EXTRA_OPTS=`echo "$STUNNEL_EXTRA_OPTS" | sed -e 's/maxconn/#maxconn/'` elif [ "X$reverse" != "X" ]; then STUNNEL_EXTRA_OPTS=`echo "$STUNNEL_EXTRA_OPTS" | sed -e 's/maxconn/#maxconn/'` else # new way (our patches). other than the above, we set these: if [ "X$SKIP_STUNNEL_ONCE" = "X" ]; then STUNNEL_ONCE=1; export STUNNEL_ONCE fi if [ "X$SKIP_STUNNEL_MAX_CLIENTS" = "X" ]; then STUNNEL_MAX_CLIENTS=1; export STUNNEL_MAX_CLIENTS fi fi # always set this one: if [ "X$SKIP_STUNNEL_NO_SYSLOG" = "X" ]; then STUNNEL_NO_SYSLOG=1; export STUNNEL_NO_SYSLOG fi # this is the -t ssh option (gives better keyboard response thru SSH tunnel) targ="-t" if [ "X$SS_VNCVIEWER_NO_T" != "X" ]; then targ="" fi # set the alpha blending env. hack: if [ "X$gotalpha" = "X1" ]; then VNCVIEWER_ALPHABLEND=1 export VNCVIEWER_ALPHABLEND else NO_ALPHABLEND=1 export NO_ALPHABLEND fi if [ "X$reverse" != "X" ]; then ssh_sleep=1800 if [ "X$proxy" != "X" ]; then # check proxy usage under reverse connection: if [ "X$use_ssh" = "X" -a "X$use_sshssl" = "X" ]; then echo "" if echo "$proxy" | egrep -i "(repeater|vencrypt)://" > /dev/null; then : else echo "*Warning*: SSL -listen and a Web proxy does not make sense." sleep 2 fi elif echo "$proxy" | grep "," > /dev/null; then : else echo "" echo "*Warning*: -listen and a single proxy/gateway does not make sense." sleep 2 fi SSVNC_LISTEN_ONCE=1; export SSVNC_LISTEN_ONCE fi fi if [ "X$ssh_cmd" = "X" ]; then # if no remote ssh cmd, sleep a bit: ssh_cmd="sleep $ssh_sleep" fi # this should be a host:display: # orig="$1" shift dL="-L" if uname -sr | egrep 'SunOS 5\.[5-8]' > /dev/null; then dL="-h" fi rchk() { # a kludge to set $RANDOM if we are not bash: if [ "X$BASH_VERSION" = "X" ]; then RANDOM=`date +%S``sh -c 'echo $$'``ps -elf 2>&1 | sum 2>&1 | awk '{print $1}'` fi } rchk # a portable, but not absolutely safe, tmp file creator mytmp() { tf=$1 if type mktemp > /dev/null 2>&1; then # if we have mktemp(1), use it: tf2="$tf.XXXXXX" tf2=`mktemp "$tf2"` if [ "X$tf2" != "X" -a -f "$tf2" ]; then if [ "X$DEBUG_MKTEMP" != "X" ]; then echo "mytmp-mktemp: $tf2" 1>&2 fi echo "$tf2" return fi fi # fallback to multiple cmds: rm -rf "$tf" || exit 1 if [ -d "$tf" ]; then echo "tmp file $tf still exists as a directory." exit 1 elif [ $dL "$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 rchk if [ "X$DEBUG_MKTEMP" != "X" ]; then echo "mytmp-touch: $tf" 1>&2 fi echo "$tf" } # set up special case of ultravnc single click III mode: if echo "$proxy" | egrep "^sslrepeater://" > /dev/null; then pstr=`echo "$proxy" | sed -e 's,sslrepeater://,,'` pstr1=`echo "$pstr" | sed -e 's/+.*$//'` pstr2=`echo "$pstr" | sed -e 's/^[^+]*+//'` SSVNC_REPEATER="SCIII=$pstr2"; export SSVNC_REPEATER orig=$pstr1 echo echo "reset: SSVNC_REPEATER=$SSVNC_REPEATER orig=$orig proxy=''" proxy="" fi if echo "$proxy" | egrep "vencrypt://" > /dev/null; then vtmp="/tmp/ss_handshake${RANDOM}.$$.txt" vtmp=`mytmp "$vtmp"` SSVNC_PREDIGESTED_HANDSHAKE="$vtmp" export SSVNC_PREDIGESTED_HANDSHAKE if [ "X$SSVNC_USE_OURS" = "X" ]; then NEED_VENCRYPT_VIEWER_BRIDGE=1 fi fi if [ "X$SSVNC_USE_OURS" = "X" ]; then VNCVIEWERCMD_EXTRA_OPTS="" fi # check -ssh and -mycert/-verify conflict: 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 # direct mode Vnc:// means show no warnings. # direct mode vnc:// will show warnings. if echo "$orig" | grep '^V[Nn][Cc]://' > /dev/null; then SSVNC_NO_ENC_WARN=1 export SSVNC_NO_ENC_WARN orig=`echo "$orig" | sed -e 's/^...:/vnc:/'` fi # interprest the pseudo URL proto:// strings: if echo "$orig" | grep '^vnc://' > /dev/null; then orig=`echo "$orig" | sed -e 's,vnc://,,'` verify="" mycert="" crl="" use_ssh="" use_sshssl="" direct_connect=1 elif echo "$orig" | grep '^vncs://' > /dev/null; then orig=`echo "$orig" | sed -e 's,vncs://,,'` elif echo "$orig" | grep '^vncssl://' > /dev/null; then orig=`echo "$orig" | sed -e 's,vncssl://,,'` elif echo "$orig" | grep '^vnc+ssl://' > /dev/null; then orig=`echo "$orig" | sed -e 's,vnc.ssl://,,'` elif echo "$orig" | grep '^vncssh://' > /dev/null; then orig=`echo "$orig" | sed -e 's,vncssh://,,'` use_ssh=1 elif echo "$orig" | grep '^vnc+ssh://' > /dev/null; then orig=`echo "$orig" | sed -e 's,vnc.ssh://,,'` use_ssh=1 fi if [ "X$SSVNC_ULTRA_DSM" != "X" ]; then verify="" mycert="" crl="" use_ssh="" use_sshssl="" direct_connect=1 if echo "$SSVNC_ULTRA_DSM" | grep 'noultra:' > /dev/null; then SSVNC_NO_ULTRA_DSM=1; export SSVNC_NO_ULTRA_DSM fi fi # (possibly) tell the vncviewer to only listen on lo: if [ "X$reverse" != "X" -a "X$direct_connect" = "X" ]; then VNCVIEWER_LISTEN_LOCALHOST=1 export VNCVIEWER_LISTEN_LOCALHOST fi # rsh mode is an internal/secret thing only I use. rsh="" if echo "$orig" | grep '^rsh://' > /dev/null; then use_ssh=1 rsh=1 orig=`echo "$orig" | sed -e 's,rsh://,,'` elif echo "$orig" | grep '^rsh:' > /dev/null; then use_ssh=1 rsh=1 orig=`echo "$orig" | sed -e 's,rsh:,,'` fi # play around with host:display port: if echo "$orig" | grep ':' > /dev/null; then : else # add or assume :0 if no ':' if [ "X$reverse" = "X" ]; then orig="$orig:0" elif [ "X$orig" = "X" ]; then orig=":0" fi fi # extract host and disp number: host=`echo "$orig" | awk -F: '{print $1}'` disp=`echo "$orig" | awk -F: '{print $2}'` if [ "X$host" = "X" ]; then host=$localhost fi if [ "X$disp" = "X" ]; then port="" # probably -listen mode. elif [ $disp -lt 0 ]; then # negative means use |n| without question: port=`expr 0 - $disp` elif [ $disp -lt 200 ]; then # less than 200 means 5900+n if [ "X$reverse" = "X" ]; then port=`expr $disp + 5900` else port=`expr $disp + 5500` fi else # otherwise use the number directly, e.g. 443, 2345 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 | egrep 'LISTEN|WAIT|ESTABLISH|CLOSE' | awk '{print $1}' | sed 's/^.*\.//'` elif uname | egrep -i 'bsd|darwin' > /dev/null; then inuse=`netstat -ant -f inet | egrep 'LISTEN|WAIT|ESTABLISH|CLOSE' | awk '{print $4}' | sed 's/^.*\.//'` # add others... fi # this is a crude attempt for unique ports tags, etc. date_sec=`date +%S` # these are special cases of no vnc, e.g. sleep or xmessage. # these are for using ssvnc as a general port redirector. if echo "$VNCVIEWERCMD" | grep '^sleep[ ][ ]*[0-9][0-9]*' > /dev/null; then if [ "X$SS_VNCVIEWER_LISTEN_PORT" = "X" ]; then p=`echo "$VNCVIEWERCMD" | awk '{print $3}'` if [ "X$p" != "X" ]; then SS_VNCVIEWER_LISTEN_PORT=$p fi fi p2=`echo "$VNCVIEWERCMD" | awk '{print $2}'` VNCVIEWERCMD="eval sleep $p2; echo Local " elif echo "$VNCVIEWERCMD" | grep '^xmessage[ ][ ]*[0-9][0-9]*' > /dev/null; then if [ "X$SS_VNCVIEWER_LISTEN_PORT" = "X" ]; then p=`echo "$VNCVIEWERCMD" | awk '{print $2}'` SS_VNCVIEWER_LISTEN_PORT=$p fi fi # utility to find a free port to listen on. findfree() { try0=$1 try=$try0 use0="" if [ "X$SS_VNCVIEWER_LISTEN_PORT" != "X" ]; then echo "$SS_VNCVIEWER_LISTEN_PORT" return fi if [ $try -ge 6000 ]; then fmax=`expr $try + 1000` else fmax=6000 fi while [ $try -lt $fmax ] 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 } # utility for exiting; kills some helper processes, # removes files, etc. final() { echo "" if [ "X$tmp_cfg" != "X" ]; then rm -f $tmp_cfg fi if [ "X$SS_VNCVIEWER_RM" != "X" ]; then rm -f $SS_VNCVIEWER_RM 2>/dev/null fi if [ "X$tcert" != "X" ]; then rm -f $tcert fi if [ "X$pssh" != "X" ]; then echo "Terminating background ssh process" echo kill -TERM "$pssh" kill -TERM "$pssh" 2>/dev/null sleep 1 kill -KILL "$pssh" 2>/dev/null pssh="" fi if [ "X$stunnel_pid" != "X" ]; then echo "Terminating background stunnel process" echo kill -TERM "$stunnel_pid" kill -TERM "$stunnel_pid" 2>/dev/null sleep 1 kill -KILL "$stunnel_pid" 2>/dev/null stunnel_pid="" fi if [ "X$dsm_pid" != "X" ]; then echo "Terminating background ultravnc_dsm_helper process" echo kill -TERM "$dsm_pid" kill -TERM "$dsm_pid" 2>/dev/null sleep 1 kill -KILL "$dsm_pid" 2>/dev/null stunnel_pid="" fi if [ "X$tail_pid" != "X" ]; then kill -TERM $tail_pid fi if [ "X$tail_pid2" != "X" ]; then kill -TERM $tail_pid2 fi } if [ "X$reverse" = "X" ]; then # normal connections try 5930-5999: if [ "X$showcert" = "X" ]; then use=`findfree 5930` else # move away from normal place for (possibly many) -showcert pstart=`date +%S` pstart=`expr 6130 + $pstart + $pstart` use=`findfree $pstart` fi if [ $use -ge 5900 ]; then N=`expr $use - 5900` else N=$use fi else # reverse connections: p2=`expr $port + 30` use=`findfree $p2` if [ $use -ge 5500 ]; then N=`expr $use - 5500` else N=$use fi fi # this is for my special use of ss_vncip -> vncip viewer. if echo "$0" | grep vncip > /dev/null; then VNCVIEWERCMD="$VNCIPCMD" fi if echo "$VNCVIEWERCMD" | egrep -i '^(xmessage|sleep )' > /dev/null; then : elif [ "X$VNCVIEWERCMD_EXTRA_OPTS" != "X" ]; then VNCVIEWERCMD="$VNCVIEWERCMD $VNCVIEWERCMD_EXTRA_OPTS" fi # trick for the undocumented rsh://host:port method. rsh_setup() { if echo "$ssh_host" | grep '@' > /dev/null; then ul=`echo "$ssh_host" | awk -F@ '{print $1}'` ul="-l $ul" ssh_host=`echo "$ssh_host" | awk -F@ '{print $2}'` else ul="" fi ssh_cmd=`echo "$ssh_cmd" | sed -e 's/ -localhost/ /g'` } # trick for the undocumented rsh://host:port method. rsh_viewer() { trap "final" 0 2 15 if [ "X$PORT" = "X" ]; then exit 1 elif [ $PORT -ge 5900 ]; then vdpy=`expr $PORT - 5900` else vdpy=":$PORT" fi stty sane echo "$VNCVIEWERCMD" "$@" $ssh_host:$vdpy echo "" $VNCVIEWERCMD "$@" $ssh_host:$vdpy if [ $? != 0 ]; then sleep 2 $VNCVIEWERCMD "$@" $ssh_host:$vdpy fi } check_perl() { if type "$1" > /dev/null 2>&1; then : elif [ ! -x "$1" ]; then echo "" echo "*******************************************************" echo "** Problem finding the Perl command '$1': **" echo "" type "perl" echo "" echo "** Perhaps you need to install the Perl package. **" echo "*******************************************************" echo "" sleep 5 fi } # this is the PPROXY tool. used only here for now... pcode() { tf=$1 PPROXY_PROXY=$proxy; export PPROXY_PROXY PPROXY_DEST="$host:$port"; export PPROXY_DEST check_perl /usr/bin/perl cod='#!/usr/bin/perl # A hack to glue stunnel to a Web or SOCKS proxy, UltraVNC repeater for # client connections. # Also acts as a VeNCrypt bridge (by redirecting to stunnel.) use IO::Socket::INET; if (exists $ENV{PPROXY_SLEEP} && $ENV{PPROXY_SLEEP} > 0) { print STDERR "PPROXY_PID: $$\n"; sleep $ENV{PPROXY_SLEEP}; } foreach my $var (qw( PPROXY_DEST PPROXY_KILLPID PPROXY_LISTEN PPROXY_PROXY PPROXY_REMOVE PPROXY_REPEATER PPROXY_REVERSE PPROXY_SLEEP PPROXY_SOCKS PPROXY_VENCRYPT PPROXY_VENCRYPT_VIEWER_BRIDGE )) { if (0 || $ENV{SS_DEBUG} || $ENV{SSVNC_VENCRYPT_DEBUG}) { print STDERR "$var: $ENV{$var}\n"; } } if ($ENV{PPROXY_SOCKS} ne "" && $ENV{PPROXY_PROXY} !~ m,^socks5?://,i) { if ($ENV{PPROXY_SOCKS} eq "5") { $ENV{PPROXY_PROXY} = "socks5://$ENV{PPROXY_PROXY}"; } else { $ENV{PPROXY_PROXY} = "socks://$ENV{PPROXY_PROXY}"; } } my $rfbSecTypeAnonTls = 18; my $rfbSecTypeVencrypt = 19; my $rfbVencryptPlain = 256; my $rfbVencryptTlsNone = 257; my $rfbVencryptTlsVnc = 258; my $rfbVencryptTlsPlain = 259; my $rfbVencryptX509None = 260; my $rfbVencryptX509Vnc = 261; my $rfbVencryptX509Plain = 262; my $handshake_file = ""; if (exists $ENV{SSVNC_PREDIGESTED_HANDSHAKE}) { $handshake_file = $ENV{SSVNC_PREDIGESTED_HANDSHAKE}; } my $have_gettimeofday = 0; eval "use Time::HiRes"; if ($@ eq "") { $have_gettimeofday = 1; } sub gettime { my $t = "0.0"; if ($have_gettimeofday) { $t = Time::HiRes::gettimeofday(); } return $t; } my $listen_handle = ""; my $sock = ""; my $parent = $$; if ($ENV{PPROXY_VENCRYPT_VIEWER_BRIDGE}) { my ($from, $to) = split(/,/, $ENV{PPROXY_VENCRYPT_VIEWER_BRIDGE}); do_vencrypt_viewer_bridge($from, $to); exit 0; } my ($first, $second, $third) = split(/,/, $ENV{PPROXY_PROXY}, 3); my ($mode_1st, $mode_2nd, $mode_3rd) = ("", "", ""); ($first, $mode_1st) = url_parse($first); my ($proxy_host, $proxy_port) = split(/:/, $first); my $connect = $ENV{PPROXY_DEST}; if ($second ne "") { ($second, $mode_2nd) = url_parse($second); } if ($third ne "") { ($third, $mode_3rd) = url_parse($third); } print STDERR "\n"; print STDERR "PPROXY v0.3: a tool for Web, SOCKS, and UltraVNC proxies and VeNCrypt bridging.\n"; print STDERR "proxy_host: $proxy_host\n"; print STDERR "proxy_port: $proxy_port\n"; print STDERR "proxy_connect: $connect\n"; print STDERR "pproxy_params: $ENV{PPROXY_PROXY}\n"; print STDERR "pproxy_listen: $ENV{PPROXY_LISTEN}\n"; print STDERR "pproxy_reverse: $ENV{PPROXY_REVERSE}\n"; print STDERR "\n"; if (1) { print STDERR "pproxy 1st: $first\t- $mode_1st\n"; print STDERR "pproxy 2nd: $second\t- $mode_2nd\n"; print STDERR "pproxy 3rd: $third\t- $mode_3rd\n"; print STDERR "\n"; } sub pdie { my $msg = shift; kill_proxy_pids(); die "$msg"; } if ($ENV{PPROXY_REVERSE} ne "") { my ($rhost, $rport) = split(/:/, $ENV{PPROXY_REVERSE}); $rport = 5900 unless $rport; $listen_handle = IO::Socket::INET->new( PeerAddr => $rhost, PeerPort => $rport, Proto => "tcp" ); if (! $listen_handle) { pdie "pproxy: $! -- PPROXY_REVERSE\n"; } print STDERR "PPROXY_REVERSE: connected to $rhost $rport\n"; } elsif ($ENV{PPROXY_LISTEN} ne "") { my $listen_sock = ""; my $maxtry = 12; my $sleep = 5; my $p2 = ""; for (my $i=0; $i < $maxtry; $i++) { if ($ENV{PPROXY_LISTEN} =~ /^INADDR_ANY:(.*)/) { my $p = $1; $p2 = "*:$p"; $listen_sock = IO::Socket::INET->new( Listen => 2, LocalPort => $p, Proto => "tcp" ); } else { $p2 = "localhost:$ENV{PPROXY_LISTEN}"; $listen_sock = IO::Socket::INET->new( Listen => 2, LocalAddr => "127.0.0.1", LocalPort => $ENV{PPROXY_LISTEN}, Proto => "tcp" ); } if (! $listen_sock) { if ($i < $maxtry - 1) { warn "pproxy: $!\n"; warn "Could not listen on port $p2, retrying in $sleep seconds... (Ctrl-C to quit)\n"; sleep $sleep; } } else { last; } } if (! $listen_sock) { pdie "pproxy: $! -- PPROXY_LISTEN\n"; } print STDERR "pproxy: listening on $p2\n"; my $ip; ($listen_handle, $ip) = $listen_sock->accept(); my $err = $!; close $listen_sock; if (! $listen_handle) { pdie "pproxy: $err\n"; } } $sock = IO::Socket::INET->new( PeerAddr => $proxy_host, PeerPort => $proxy_port, Proto => "tcp" ); if (! $sock) { my $err = $!; unlink($0) if $ENV{PPROXY_REMOVE}; pdie "pproxy: $err\n"; } unlink($0) if $ENV{PPROXY_REMOVE}; if ($ENV{PPROXY_PROXY} =~ /^vencrypt:/ && $ENV{PPROXY_LISTEN} =~ /^INADDR_ANY:/) { print STDERR "\nPPROXY: vencrypt+reverse: swapping listen socket with connect socket.\n"; my $tmp_swap = $sock; $sock = $listen_handle; $listen_handle = $tmp_swap; } $cur_proxy = $first; setmode($mode_1st); if ($second ne "") { connection($second, 1); setmode($mode_2nd); $cur_proxy = $second; if ($third ne "") { connection($third, 2); setmode($mode_3rd); $cur_proxy = $third; connection($connect, 3); } else { connection($connect, 2); } } else { connection($connect, 1); } sub kill_proxy_pids() { if ($ENV{PPROXY_VENCRYPT_VIEWER_BRIDGE}) { return; } if ($ENV{PPROXY_KILLPID}) { foreach my $p (split(/,/, $ENV{PPROXY_KILLPID})) { if ($p =~ /^(\+|-)/) { $p = $parent + $p; } print STDERR "kill TERM, $p (PPROXY_KILLPID)\n"; kill "TERM", $p; } } } 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 "pproxy[$$]: $!\n"; last; } elsif ($len == 0) { print STDERR "pproxy[$$]: 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 "pproxy[$$]: Output is EOF. $!\n"; $quit = 1; last; } $len -= $written; $offset += $written; } last if $quit; } close($out); close($in); print STDERR "pproxy[$$]: finished xfer.\n"; } sub handler { print STDERR "pproxy[$$]: got SIGTERM.\n"; close $listen_handle if $listen_handle; close $sock if $sock; exit; } sub xfer_both { $child = fork; if (! defined $child) { kill_proxy_pids(); exit 1; } $SIG{TERM} = "handler"; if ($child) { if ($listen_handle) { print STDERR "pproxy parent[$$] listen_handle -> socket\n"; xfer($listen_handle, $sock); } else { print STDERR "pproxy parent[$$] STDIN -> socket\n"; xfer(STDIN, $sock); } select(undef, undef, undef, 0.25); if (kill 0, $child) { select(undef, undef, undef, 0.9); if (kill 0, $child) { print STDERR "pproxy[$$]: kill TERM child $child\n"; kill "TERM", $child; } else { print STDERR "pproxy[$$]: child $child gone.\n"; } } } else { select(undef, undef, undef, 0.05); if ($listen_handle) { print STDERR "pproxy child [$$] socket -> listen_handle\n\n"; xfer($sock, $listen_handle); } else { print STDERR "pproxy child [$$] socket -> STDOUT\n\n"; xfer($sock, STDOUT); } select(undef, undef, undef, 0.25); if (kill 0, $parent) { select(undef, undef, undef, 0.8); if (kill 0, $parent) { print STDERR "pproxy[$$]: kill TERM parent $parent\n"; kill "TERM", $parent; } else { print STDERR "pproxy[$$]: parent $parent gone.\n"; } } } kill_proxy_pids(); } xfer_both(); exit; sub url_parse { my $hostport = shift; my $mode = "http"; if ($hostport =~ m,^socks4?://(\S*)$,i) { $mode = "socks4"; $hostport = $1; } elsif ($hostport =~ m,^socks5://(\S*)$,i) { $mode = "socks5"; $hostport = $1; } elsif ($hostport =~ m,^https?://(\S*)$,i) { $mode = "http"; $hostport = $1; } elsif ($hostport =~ m,^repeater://(\S*)\+(\S*)$,i) { # ultravnc repeater proxy. $hostport = $1; $mode = "repeater:$2"; if ($hostport !~ /:\d+/) { $hostport .= ":5900"; } } elsif ($hostport =~ m,^vencrypt://(\S*)$,i) { # vencrypt handshake. $hostport = $1; my $m = "connect"; if ($hostpost =~ /^(\S+)\+(\S+)$/) { $hostport = $1; $mode = $2; } $mode = "vencrypt:$m"; if ($hostport !~ /:\d+/) { $hostport .= ":5900"; } } return ($hostport, $mode); } sub setmode { my $mode = shift; $ENV{PPROXY_REPEATER} = ""; $ENV{PPROXY_VENCRYPT} = ""; if ($mode =~ /^socks/) { if ($mode =~ /^socks5/) { $ENV{PPROXY_SOCKS} = 5; } else { $ENV{PPROXY_SOCKS} = 1; } } elsif ($mode =~ /^repeater:(.*)/) { $ENV{PPROXY_REPEATER} = $1; $ENV{PPROXY_SOCKS} = ""; } elsif ($mode =~ /^vencrypt:(.*)/) { $ENV{PPROXY_VENCRYPT} = $1; $ENV{PPROXY_SOCKS} = ""; } else { $ENV{PPROXY_SOCKS} = ""; } } sub connection { my ($CONNECT, $w) = @_; my $con = ""; my $msg = ""; if ($ENV{PPROXY_SOCKS} eq "5") { # SOCKS5 my ($h, $p) = split(/:/, $CONNECT); $con .= pack("C", 0x05); $con .= pack("C", 0x01); $con .= pack("C", 0x00); $msg = "SOCKS5 via $cur_proxy to $h:$p\n\n"; print STDERR "proxy_request$w: $msg"; syswrite($sock, $con, length($con)); my ($n1, $n2, $n3, $n4, $n5, $n6); my ($r1, $r2, $r3, $r4, $r5, $r6); my ($s1, $s2, $s3, $s4, $s5, $s6); $n1 = sysread($sock, $r1, 1); $n2 = sysread($sock, $r2, 1); $s1 = unpack("C", $r1); $s2 = unpack("C", $r2); if ($s1 != 0x05 || $s2 != 0x00) { print STDERR "SOCKS5 fail s1=$s1 s2=$s2 n1=$n1 n2=$n2\n"; close $sock; exit(1); } $con = ""; $con .= pack("C", 0x05); $con .= pack("C", 0x01); $con .= pack("C", 0x00); $con .= pack("C", 0x03); $con .= pack("C", length($h)); $con .= $h; $con .= pack("C", $p >> 8); $con .= pack("C", $p & 0xff); syswrite($sock, $con, length($con)); $n1 = sysread($sock, $r1, 1); $n2 = sysread($sock, $r2, 1); $n3 = sysread($sock, $r3, 1); $n4 = sysread($sock, $r4, 1); $s1 = unpack("C", $r1); $s2 = unpack("C", $r2); $s3 = unpack("C", $r3); $s4 = unpack("C", $r4); if ($s4 == 0x1) { sysread($sock, $r5, 4 + 2); } elsif ($s4 == 0x3) { sysread($sock, $r5, 1); $s5 = unpack("C", $r5); sysread($sock, $r6, $s5 + 2); } elsif ($s4 == 0x4) { sysread($sock, $r5, 16 + 2); } if ($s1 != 0x5 || $s2 != 0x0 || $s3 != 0x0) { print STDERR "SOCKS5 failed: s1=$s1 s2=$s2 s3=$s3 s4=$s4 n1=$n1 n2=$n2 n3=$n3 n4=$n4\n"; close $sock; exit(1); } } elsif ($ENV{PPROXY_SOCKS} ne "") { # SOCKS4 SOCKS4a my ($h, $p) = split(/:/, $CONNECT); $con .= pack("C", 0x04); $con .= pack("C", 0x01); $con .= pack("n", $p); my $SOCKS_4a = 0; if ($h eq "localhost" || $h eq "127.0.0.1") { $con .= pack("C", 127); $con .= pack("C", 0); $con .= pack("C", 0); $con .= pack("C", 1); } elsif ($h =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) { $con .= pack("C", $1); $con .= pack("C", $2); $con .= pack("C", $3); $con .= pack("C", $4); } else { $con .= pack("C", 0); $con .= pack("C", 0); $con .= pack("C", 0); $con .= pack("C", 3); $SOCKS_4a = 1; } $con .= "nobody"; $con .= pack("C", 0); $msg = "SOCKS4 via $cur_proxy to $h:$p\n\n"; if ($SOCKS_4a) { $con .= $h; $con .= pack("C", 0); $msg =~ s/SOCKS4/SOCKS4a/; } print STDERR "proxy_request$w: $msg"; syswrite($sock, $con, length($con)); my $ok = 1; for (my $i = 0; $i < 8; $i++) { my $c; sysread($sock, $c, 1); my $s = unpack("C", $c); if ($i == 0) { $ok = 0 if $s != 0x0; } elsif ($i == 1) { $ok = 0 if $s != 0x5a; } } if (! $ok) { print STDERR "SOCKS4 failed.\n"; close $sock; exit(1); } } elsif ($ENV{PPROXY_REPEATER} ne "") { my $rep = $ENV{PPROXY_REPEATER}; print STDERR "repeater: $rep\n"; $rep .= pack("x") x 250; syswrite($sock, $rep, 250); my $ok = 1; for (my $i = 0; $i < 12; $i++) { my $c; sysread($sock, $c, 1); print STDERR $c; } } elsif ($ENV{PPROXY_VENCRYPT} ne "") { my $vencrypt = $ENV{PPROXY_VENCRYPT}; vencrypt_dialog($vencrypt); } else { # Web Proxy: $con = "CONNECT $CONNECT HTTP/1.1\r\n"; $con .= "Host: $CONNECT\r\n"; $con .= "Connection: close\r\n\r\n"; $msg = $con; print STDERR "proxy_request$w: via $cur_proxy:\n$msg"; syswrite($sock, $con, length($con)); my $rep = ""; my $n = 0; while ($rep !~ /\r\n\r\n/ && $n < 30000) { my $c; sysread($sock, $c, 1); print STDERR $c; $rep .= $c; $n++; } if ($rep !~ m,HTTP/.* 200,) { print STDERR "HTTP CONNECT failed.\n"; close $sock; exit(1); } } } sub vdie { append_handshake("done\n"); close $sock; kill_proxy_pids(); exit(1); } sub anontls_handshake { my ($vmode, $db) = @_; print STDERR "\nPPROXY: Doing ANONTLS Handshake\n"; my $psec = pack("C", $rfbSecTypeAnonTls); syswrite($sock, $psec, 1); append_handshake("done\n"); } sub vencrypt_handshake { my ($vmode, $db) = @_; print STDERR "\nPPROXY: Doing VeNCrypt Handshake\n"; my $psec = pack("C", $rfbSecTypeVencrypt); if (exists $ENV{SSVNC_TEST_SEC_TYPE}) { my $fake = $ENV{SSVNC_TEST_SEC_TYPE}; print STDERR "PPROXY: sending sec-type: $fake\n"; $psec = pack("C", $fake); } syswrite($sock, $psec, 1); my $vmajor; my $vminor; sysread($sock, $vmajor, 1); sysread($sock, $vminor, 1); vdie if $vmajor eq "" || $vminor eq ""; $vmajor = unpack("C", $vmajor); $vminor = unpack("C", $vminor); print STDERR "server vencrypt version $vmajor.$vminor\n" if $db; if (exists $ENV{SSVNC_TEST_SEC_TYPE}) { print STDERR "PPROXY: continuing on in test mode.\n"; } else { vdie if $vmajor ne 0; vdie if $vminor < 2; } $vmajor = pack("C", 0); $vminor = pack("C", 2); append_handshake("subversion=0.2\n"); syswrite($sock, $vmajor, 1); syswrite($sock, $vminor, 1); my $result; sysread($sock, $result, 1); print STDERR "result empty\n" if $db && $result eq ""; vdie if $result eq ""; $result = unpack("C", $result); print STDERR "result=$result\n" if $db; vdie if $result ne 0; my $nsubtypes; sysread($sock, $nsubtypes, 1); vdie if $nsubtypes eq ""; $nsubtypes = unpack("C", $nsubtypes); print STDERR "nsubtypes=$nsubtypes\n" if $db; my %subtypes; for (my $i = 0; $i < $nsubtypes; $i++) { my $subtype = ""; sysread($sock, $subtype, 4); vdie if length($subtype) != 4; # XXX fix 64bit. $subtype = unpack("N", $subtype); print STDERR "subtype: $subtype\n" if $db; $subtypes{$subtype} = 1; append_handshake("sst$i=$subtype\n"); } my $subtype = 0; if (exists $subtypes{$rfbVencryptX509None}) { $subtype = $rfbVencryptX509None; print STDERR "selected rfbVencryptX509None\n" if $db; } elsif (exists $subtypes{$rfbVencryptX509Vnc}) { $subtype = $rfbVencryptX509Vnc; print STDERR "selected rfbVencryptX509Vnc\n" if $db; } elsif (exists $subtypes{$rfbVencryptX509Plain}) { $subtype = $rfbVencryptX509Plain; print STDERR "selected rfbVencryptX509Plain\n" if $db; } elsif (exists $subtypes{$rfbVencryptTlsNone}) { $subtype = $rfbVencryptTlsNone; print STDERR "selected rfbVencryptTlsNone\n" if $db; } elsif (exists $subtypes{$rfbVencryptTlsVnc}) { $subtype = $rfbVencryptTlsVnc; print STDERR "selected rfbVencryptTlsVnc\n" if $db; } elsif (exists $subtypes{$rfbVencryptTlsPlain}) { $subtype = $rfbVencryptTlsPlain; print STDERR "selected rfbVencryptTlsPlain\n" if $db; } if (exists $ENV{SSVNC_TEST_SEC_SUBTYPE}) { my $fake = $ENV{SSVNC_TEST_SEC_SUBTYPE}; print STDERR "PPROXY: sending sec-subtype: $fake\n"; $subtype = $fake; } append_handshake("subtype=$subtype\n"); my $pst = pack("N", $subtype); syswrite($sock, $pst, 4); if (exists $ENV{SSVNC_TEST_SEC_SUBTYPE}) { print STDERR "PPROXY: continuing on in test mode.\n"; } else { vdie if $subtype == 0; } my $ok; sysread($sock, $ok, 1); $ok = unpack("C", $ok); print STDERR "ok=$ok\n" if $db; append_handshake("done\n"); vdie if $ok == 0; } sub vencrypt_dialog { my $vmode = shift; my $db = 0; $db = 1 if exists $ENV{SS_DEBUG}; $db = 1 if exists $ENV{SSVNC_VENCRYPT_DEBUG}; append_handshake("mode=$vmode\n"); my $server_rfb = ""; #syswrite($sock, $rep, 250); for (my $i = 0; $i < 12; $i++) { my $c; sysread($sock, $c, 1); $server_rfb .= $c; print STDERR $c; } print STDERR "server_rfb: $server_rfb\n" if $db; append_handshake("server=$server_rfb"); my $minor = ""; if ($server_rfb =~ /^RFB 003\.(\d+)/) { $minor = $1; } else { vdie; } my $viewer_rfb = "RFB 003.008\n"; if ($minor < 7) { vdie; } elsif ($minor == 7) { $viewer_rfb = "RFB 003.007\n"; } my $nsec; my $t1 = gettime(); my $t0 = gettime(); syswrite($sock, $viewer_rfb, 12); sysread($sock, $nsec, 1); $t1 = gettime(); $t1 = sprintf("%.6f", $t1 - $t0); append_handshake("viewer=$viewer_rfb"); append_handshake("latency=$t1\n"); vdie if $nsec eq ""; $nsec = unpack("C", $nsec); print STDERR "nsec: $nsec\n" if $db; vdie if $nsec eq 0 || $nsec > 100; my %sectypes = (); for (my $i = 0; $i < $nsec; $i++) { my $sec; sysread($sock, $sec, 1); vdie if $sec eq ""; $sec = unpack("C", $sec); print STDERR "sec: $sec\n" if $db; $sectypes{$sec} = 1; } if (exists $sectypes{$rfbSecTypeVencrypt}) { print STDERR "found rfbSecTypeVencrypt\n" if $db; append_handshake("sectype=$rfbSecTypeVencrypt\n"); vencrypt_handshake($vmode, $db); } elsif (exists $sectypes{$rfbSecTypeAnonTls}) { print STDERR "found rfbSecTypeAnonTls\n" if $db; append_handshake("sectype=$rfbSecTypeAnonTls\n"); anontls_handshake($vmode, $db); } else { print STDERR "No supported sec-type found\n" if $db; vdie; } } sub append_handshake { my $str = shift; if ($handshake_file) { if (open(HSF, ">>$handshake_file")) { print HSF $str; close HSF; } } } sub do_vencrypt_viewer_bridge { my ($listen, $connect) = @_; print STDERR "\npproxy: starting vencrypt_viewer_bridge[$$]: $listen \-> $connect\n"; my $db = 0; my $backwards = 0; if ($listen < 0) { $backwards = 1; $listen = -$listen; } if ($handshake_file eq "") { die "pproxy: vencrypt_viewer_bridge[$$]: no SSVNC_PREDIGESTED_HANDSHAKE\n"; } my $listen_sock; my $maxtry = 12; my $sleep = 5; for (my $i=0; $i < $maxtry; $i++) { $listen_sock = IO::Socket::INET->new( Listen => 2, LocalAddr => "127.0.0.1", LocalPort => $listen, Proto => "tcp" ); if (! $listen_sock) { if ($i < $maxtry - 1) { warn "pproxy: vencrypt_viewer_bridge[$$]: $!\n"; warn "Could not listen on port $listen, retrying in $sleep seconds... (Ctrl-C to quit)\n"; sleep $sleep; } } else { last; } } if (! $listen_sock) { die "pproxy: vencrypt_viewer_bridge[$$]: $!\n"; } print STDERR "pproxy: vencrypt_viewer_bridge[$$]: listening on port $listen\n\n"; my ($viewer_sock, $ip) = $listen_sock->accept(); my $err = $!; close $listen_sock; if (! $viewer_sock) { die "pproxy: vencrypt_viewer_bridge[$$]: $err\n"; } print STDERR "vencrypt_viewer_bridge[$$]: viewer_sock $viewer_sock\n" if $db; print STDERR "pproxy: vencrypt_viewer_bridge[$$]: connecting to 127.0.0.1:$connect\n"; my $server_sock = IO::Socket::INET->new( PeerAddr => "127.0.0.1", PeerPort => $connect, Proto => "tcp" ); print STDERR "vencrypt_viewer_bridge[$$]: server_sock $server_sock\n" if $db; if (! $server_sock) { my $err = $!; die "pproxy: vencrypt_viewer_bridge[$$]: $err\n"; } if ($backwards) { print STDERR "vencrypt_viewer_bridge[$$]: reversing roles of viewer and server.\n"; my $t = $viewer_sock; $viewer_sock = $server_sock; $server_sock = $t; } my %hs = (); my $dt = 0.2; my $slept = 0.0; while ($slept < 20.0) { select(undef, undef, undef, $dt); $slept += $dt; if (-f $handshake_file && open(HSF, "<$handshake_file")) { my $done = 0; %hs = (); my $str = ""; while () { print STDERR "vencrypt_viewer_bridge[$$]: $_" if $ENV{VENCRYPT_VIEWER_BRIDGE_DEBUG}; $str .= "vencrypt_viewer_bridge[$$]: $_"; chomp; if ($_ eq "done") { $done = 1; } else { my ($k, $v) = split(/=/, $_, 2); if ($k ne "" && $v ne "") { $hs{$k} = $v; } } } close HSF; if ($done) { print STDERR "\n" . $str; last; } } } if (! exists $hs{server}) { $hs{server} = "RFB 003.008"; } if (! exists $hs{sectype}) { unlink($handshake_file); die "pproxy: vencrypt_viewer_bridge[$$]: no sectype.\n"; } syswrite($viewer_sock, "$hs{server}\n", length($hs{server}) + 1); my $viewer_rfb = ""; for (my $i = 0; $i < 12; $i++) { my $c; sysread($viewer_sock, $c, 1); $viewer_rfb .= $c; print STDERR $c; } my $viewer_major = 3; my $viewer_minor = 8; if ($viewer_rfb =~ /RFB (\d+)\.(\d+)/) { $viewer_major = $1; $viewer_minor = $2; } my $u0 = pack("C", 0); my $u1 = pack("C", 1); my $u2 = pack("C", 2); if ($hs{sectype} == $rfbSecTypeAnonTls) { unlink($handshake_file); print STDERR "\npproxy: vencrypt_viewer_bridge[$$]: rfbSecTypeAnonTls\n"; if ($viewer_major > 3 || $viewer_minor >= 7) { ; # setup ok, proceed to xfer. } else { print STDERR "pproxy: vencrypt_viewer_bridge[$$]: faking RFB version 3.3 to viewer.\n"; my $n; sysread($server_sock, $n, 1); $n = unpack("C", $n); if ($n == 0) { die "pproxy: vencrypt_viewer_bridge[$$]: nsectypes == $n.\n"; } my %types; for (my $i = 0; $i < $n; $i++) { my $t; sysread($server_sock, $t, 1); $t = unpack("C", $t); $types{$t} = 1; } my $use = 1; # None if (exists $types{1}) { $use = 1; # None } elsif (exists $types{2}) { $use = 2; # VncAuth } else { die "pproxy: vencrypt_viewer_bridge[$$]: no valid sectypes" . join(",", keys %types) . "\n"; } # send 4 bytes sectype to viewer: # (note this should be MSB, network byte order...) my $up = pack("C", $use); syswrite($viewer_sock, $u0, 1); syswrite($viewer_sock, $u0, 1); syswrite($viewer_sock, $u0, 1); syswrite($viewer_sock, $up, 1); # and tell server the one we selected: syswrite($server_sock, $up, 1); if ($use == 1) { # even None has security result, so read it here and discard it. my $sr = ""; sysread($server_sock, $sr, 4); } } } elsif ($hs{sectype} == $rfbSecTypeVencrypt) { print STDERR "\npproxy: vencrypt_viewer_bridge[$$]: rfbSecTypeVencrypt\n"; if (! exists $hs{subtype}) { unlink($handshake_file); die "pproxy: vencrypt_viewer_bridge[$$]: no subtype.\n"; } my $fake_type = "None"; my $plain = 0; my $sub_type = $hs{subtype}; if ($sub_type == $rfbVencryptTlsNone) { $fake_type = "None"; } elsif ($sub_type == $rfbVencryptTlsVnc) { $fake_type = "VncAuth"; } elsif ($sub_type == $rfbVencryptTlsPlain) { $fake_type = "None"; $plain = 1; } elsif ($sub_type == $rfbVencryptX509None) { $fake_type = "None"; } elsif ($sub_type == $rfbVencryptX509Vnc) { $fake_type = "VncAuth"; } elsif ($sub_type == $rfbVencryptX509Plain) { $fake_type = "None"; $plain = 1; } if ($plain) { if (!open(W, ">$handshake_file")) { unlink($handshake_file); die "pproxy: vencrypt_viewer_bridge[$$]: $handshake_file $!\n"; } print W <<"END"; proc print_out {} { global user pass env if [info exists env(SSVNC_UP_DEBUG)] { toplevel .b button .b.b -text "user=\$user pass=\$pass" -command {destroy .b} pack .b.b update tkwait window .b } if [info exists env(SSVNC_UP_FILE)] { set fh "" catch {set fh [open \$env(SSVNC_UP_FILE) w]} if {\$fh != ""} { puts \$fh user=\$user\\npass=\$pass flush \$fh close \$fh return } } puts stdout user=\$user\\npass=\$pass flush stdout } proc center_win {w} { update set W [winfo screenwidth \$w] set W [expr \$W + 1] wm geometry \$w +\$W+0 update set x [expr [winfo screenwidth \$w]/2 - [winfo width \$w]/2] set y [expr [winfo screenheight \$w]/2 - [winfo height \$w]/2] wm geometry \$w +\$x+\$y wm deiconify \$w update } wm withdraw . global env set up {} if [info exists env(SSVNC_UNIXPW)] { set rm 0 set up \$env(SSVNC_UNIXPW) if [regexp {^rm:} \$up] { set rm 1 regsub {^rm:} \$up {} up } if [file exists \$up] { set fh "" set f \$up catch {set fh [open \$up r]} if {\$fh != ""} { gets \$fh u gets \$fh p close \$fh set up "\$u@\$p" } if {\$rm} { catch {file delete \$f} } } } elseif [info exists env(SSVNC_VENCRYPT_USERPASS)] { set up \$env(SSVNC_VENCRYPT_USERPASS) } #puts stderr up=\$up if {\$up != ""} { if [regexp {@} \$up] { global user pass set user \$up set pass \$up regsub {@.*\$} \$user "" user regsub {^[^@]*@} \$pass "" pass print_out exit } } wm title . {VeNCrypt Viewer Bridge User/Pass} set user {} set pass {} label .l -text {SSVNC VeNCrypt Viewer Bridge} frame .f0 frame .f0.fL label .f0.fL.la -text {Username: } label .f0.fL.lb -text {Password: } pack .f0.fL.la .f0.fL.lb -side top frame .f0.fR entry .f0.fR.ea -width 24 -textvariable user entry .f0.fR.eb -width 24 -textvariable pass -show * pack .f0.fR.ea .f0.fR.eb -side top -fill x pack .f0.fL -side left pack .f0.fR -side right -expand 1 -fill x button .no -text Cancel -command {destroy .} button .ok -text Done -command {print_out; destroy .} center_win . pack .l .f0 .no .ok -side top -fill x update wm deiconify . bind .f0.fR.ea {focus .f0.fR.eb} bind .f0.fR.eb {print_out; destroy .} focus .f0.fR.ea wm resizable . 1 0 wm minsize . [winfo reqwidth .] [winfo reqheight .] END close W; #system("cat $handshake_file"); my $w = "wish"; if ($ENV{WISH}) { $w = $ENV{WISH}; } print STDERR "pproxy: vencrypt_viewer_bridge[$$]: prompt VencryptPlain user and passwd.\n"; my $res = ""; if (`uname` =~ /Darwin/) { my $mtmp = `mktemp /tmp/hsup.XXXXXX`; chomp $mtmp; system("env SSVNC_UP_FILE=$mtmp $w $handshake_file"); $res = `cat $mtmp`; unlink $mtmp; } else { $res = `$w $handshake_file`; } my $user = ""; my $pass = ""; if ($res =~ /user=(\S*)/) { $user = $1; } if ($res =~ /pass=(\S*)/) { $pass = $1; } print STDERR "pproxy: vencrypt_viewer_bridge[$$]: sending VencryptPlain user and passwd.\n"; my $ulen = pack("C", length($user)); my $plen = pack("C", length($pass)); # (note this should be MSB, network byte order...) syswrite($server_sock, $u0, 1); syswrite($server_sock, $u0, 1); syswrite($server_sock, $u0, 1); syswrite($server_sock, $ulen, 1); syswrite($server_sock, $u0, 1); syswrite($server_sock, $u0, 1); syswrite($server_sock, $u0, 1); syswrite($server_sock, $plen, 1); syswrite($server_sock, $user, length($user)); syswrite($server_sock, $pass, length($pass)); } unlink($handshake_file); my $ft = 0; if ($fake_type eq "None") { $ft = 1; } elsif ($fake_type eq "VncAuth") { $ft = 2; } else { die "pproxy: vencrypt_viewer_bridge[$$]: unknown fake type: $fake_type\n"; } my $fp = pack("C", $ft); if ($viewer_major > 3 || $viewer_minor >= 7) { syswrite($viewer_sock, $u1, 1); syswrite($viewer_sock, $fp, 1); my $cr; sysread($viewer_sock, $cr, 1); $cr = unpack("C", $cr); if ($cr != $ft) { die "pproxy: vencrypt_viewer_bridge[$$]: client selected wrong type: $cr / $ft\n"; } } else { print STDERR "pproxy: vencrypt_viewer_bridge[$$]: faking RFB version 3.3 to viewer.\n"; # send 4 bytes sect type to viewer: # (note this should be MSB, network byte order...) syswrite($viewer_sock, $u0, 1); syswrite($viewer_sock, $u0, 1); syswrite($viewer_sock, $u0, 1); syswrite($viewer_sock, $fp, 1); if ($ft == 1) { # even None has security result, so read it here and discard it. my $sr = ""; sysread($server_sock, $sr, 4); } } } $listen_handle = $viewer_sock; $sock = $server_sock; xfer_both(); } ' # ' # xpg_echo will expand \n \r, etc. # try to unset and then test for it. if type shopt > /dev/null 2>&1; then shopt -u xpg_echo >/dev/null 2>&1 fi v='print STDOUT "abc\n";' echo "$v" > $tf chmod 700 $tf lc=`wc -l $tf | awk '{print $1}'` if [ "X$lc" = "X1" ]; then echo "$cod" > $tf else printf "%s" "$cod" > $tf echo "" >> $tf fi # prime perl perl -e 'use IO::Socket::INET; select(undef, undef, undef, 0.01)' >/dev/null 2>&1 } # make_tcert is no longer invoked via the ssvnc gui (Listen mode). # make_tcert is for testing only now via -mycert BUILTIN make_tcert() { tcert="/tmp/ss_vnc_viewer_tcert${RANDOM}.$$" tcert=`mytmp "$tcert"` cat > $tcert < Advanced -> Private SSH KnownHosts file' (or set" echo "** Warning: SSVNC_KNOWN_HOSTS_FILE directly) to a per-connection known hosts" echo "** Warning: file. This yields a both secure and convenient solution." echo "" } # handle ssh case: # if [ "X$use_ssh" = "X1" ]; then # # USING SSH # ssh_port="22" ssh_host="$host" vnc_host="$localhost" ssh_UKHF="" localhost_extra="" # let user override ssh via $SSH ssh=${SSH:-"ssh -x"} sshword=`echo "$ssh" | awk '{print $1}'` if [ "X$sshword" != "X" ]; then if [ -x "$sshword" ]; then : elif type "$sshword" > /dev/null 2>&1; then : else echo "" echo "*********************************************************" echo "** Problem finding the SSH command '$sshword': **" echo "" type "$sshword" echo "" echo "** Perhaps you need to install the SSH client package. **" echo "*********************************************************" echo "" sleep 5 fi fi ssh_NHAFL="-o NoHostAuthenticationForLocalhost=yes" if [ "X$SSVNC_SSH_LOCALHOST_AUTH" = "X1" ]; then ssh_NHAFL="" fi if [ "X$SSVNC_KNOWN_HOSTS_FILE" != "X" ]; then ssh_NHAFL="" ssh_UKHF="-o UserKnownHostsFile=$SSVNC_KNOWN_HOSTS_FILE" ssh_args="$ssh_args $ssh_UKHF" if [ ! -f "$SSVNC_KNOWN_HOSTS_FILE" ]; then touch "$SSVNC_KNOWN_HOSTS_FILE" >/dev/null 2>&1 fi chmod 600 "$SSVNC_KNOWN_HOSTS_FILE" >/dev/null 2>&1 fi did_ssh_NHAFL="" if [ "X$SSVNC_LIM_ACCEPT_PRELOAD" != "X" ]; then SSVNC_LIM_ACCEPT_PRELOAD="$SSVNC_BASEDIR/$SSVNC_UNAME/$SSVNC_LIM_ACCEPT_PRELOAD" fi if [ "X$SSVNC_LIM_ACCEPT_PRELOAD" != "X" ]; then echo "" echo "SSVNC_LIM_ACCEPT_PRELOAD=$SSVNC_LIM_ACCEPT_PRELOAD" fi if [ "X$SSVNC_LIM_ACCEPT_PRELOAD" != "X" -a -f "$SSVNC_LIM_ACCEPT_PRELOAD" ]; then plvar=LD_PRELOAD if uname | grep Darwin >/dev/null; then plvar="DYLD_FORCE_FLAT_NAMESPACE=1 DYLD_INSERT_LIBRARIES" fi ssh="env $plvar=$SSVNC_LIM_ACCEPT_PRELOAD $ssh" else SSVNC_LIM_ACCEPT_PRELOAD="" fi ssh_vencrypt_proxy="" # We handle vencrypt for SSH+SSL mode. if echo "$proxy" | grep 'vencrypt://' > /dev/null; then proxynew="" for part in `echo "$proxy" | tr ',' ' '` do if echo "$part" | egrep -i '^vencrypt://' > /dev/null; then ssh_vencrypt_proxy=$part else if [ "X$proxynew" = "X" ]; then proxynew="$part" else proxynew="$proxynew,$part" fi fi done proxy=$proxynew fi Kecho ssh_vencrypt_proxy=$ssh_vencrypt_proxy # note that user must supply http:// for web proxy in SSH and SSH+SSL. # No xxxx:// implies ssh server+port. # if echo "$proxy" | egrep '(http|https|socks|socks4|socks5)://' > /dev/null; then # Handle Web or SOCKS proxy(ies) for the initial connect. Kecho host=$host Kecho port=$port pproxy="" sproxy1="" sproxy_rest="" for part in `echo "$proxy" | tr ',' ' '` do Kecho proxy_part=$part if [ "X$part" = "X" ]; then continue elif echo "$part" | egrep -i '^(http|https|socks|socks4|socks5)://' > /dev/null; then pproxy="$pproxy,$part" else if [ "X$sproxy1" = "X" ]; then sproxy1="$part" else sproxy_rest="$sproxy_rest,$part" fi fi done pproxy=`echo "$pproxy" | sed -e 's/^,,*//' -e 's/,,*/,/g'` sproxy_rest=`echo "$sproxy_rest" | sed -e 's/^,,*//' -e 's/,,*/,/g'` Kecho pproxy=$pproxy Kecho sproxy1=$sproxy1 Kecho sproxy_rest=$sproxy_rest sproxy1_host="" sproxy1_port="" sproxy1_user="" if [ "X$sproxy1" != "X" ]; then sproxy1_host=`echo "$sproxy1" | awk -F: '{print $1}'` sproxy1_user=`echo "$sproxy1_host" | awk -F@ '{print $1}'` sproxy1_host=`echo "$sproxy1_host" | awk -F@ '{print $2}'` if [ "X$sproxy1_host" = "X" ]; then sproxy1_host=$sproxy1_user sproxy1_user="" else sproxy1_user="${sproxy1_user}@" fi sproxy1_port=`echo "$sproxy1" | awk -F: '{print $2}'` if [ "X$sproxy1_port" = "X" ]; then sproxy1_port="22" fi else sproxy1_host=`echo "$host" | awk -F: '{print $1}'` sproxy1_user=`echo "$sproxy1_host" | awk -F@ '{print $1}'` sproxy1_host=`echo "$sproxy1_host" | awk -F@ '{print $2}'` if [ "X$sproxy1_host" = "X" ]; then sproxy1_host=$sproxy1_user sproxy1_user="" else sproxy1_user="${sproxy1_user}@" fi sproxy1_port=`echo "$host" | awk -F: '{print $2}'` if [ "X$sproxy1_port" = "X" ]; then sproxy1_port="22" fi fi Kecho sproxy1_host=$sproxy1_host Kecho sproxy1_port=$sproxy1_port Kecho sproxy1_user=$sproxy1_user ptmp="/tmp/ss_vncviewer_ssh${RANDOM}.$$.pl" ptmp=`mytmp "$ptmp"` PPROXY_REMOVE=1; export PPROXY_REMOVE proxy=$pproxy port_save=$port host_save=$host if [ "X$sproxy1_host" != "X" ]; then host=$sproxy1_host fi if [ "X$sproxy1_port" != "X" ]; then port=$sproxy1_port fi host=`echo "$host" | sed -e 's/^.*@//'` port=`echo "$port" | sed -e 's/^.*://'` pcode "$ptmp" port=$port_save host=$host_save nd=`findfree 6600` PPROXY_LISTEN=$nd; export PPROXY_LISTEN $ptmp & sleep 1 if [ "X$ssh_NHAFL" != "X" -a "X$did_ssh_NHAFL" != "X1" ]; then NHAFL_warning ssh_args="$ssh_args $ssh_NHAFL" did_ssh_NHAFL=1 fi sleep 1 if [ "X$sproxy1" = "X" ]; then u="" if echo "$host" | grep '@' > /dev/null; then u=`echo "$host" | sed -e 's/@.*$/@/'` fi proxy="${u}$localhost:$nd" else proxy="${sproxy1_user}$localhost:$nd" fi localhost_extra=".2" if [ "X$sproxy_rest" != "X" ]; then proxy="$proxy,$sproxy_rest" fi Kecho proxy=$proxy fi 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="-p $ssh_port1" 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` if [ "X$ssh_NHAFL" != "X" -a "X$did_ssh_NHAFL" != "X1" ]; then NHAFL_warning did_ssh_NHAFL=1 sleep 1 fi echo echo "Running 1st ssh proxy:" ukhf="" if [ "X$ssh_UKHF" != "X" ]; then ukhf="$ssh_UKHF$localhost_extra" fi echo "$ssh -f -x $ssh_port1 $targ -e none $ssh_NHAFL $ukhf -L $proxport:$ssh_host2:$ssh_port2 $ssh_host1 \"sleep 30\"" echo "" $ssh -f -x $ssh_port1 $targ -e none $ssh_NHAFL $ukhf -L $proxport:$ssh_host2:$ssh_port2 $ssh_host1 "sleep 30" ssh_args="$ssh_args $ssh_NHAFL" 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 300 ]; then info="..." else info="$ssh_cmd" fi C="" if [ "X$SS_VNCVIEWER_USE_C" != "X" ]; then C="-C" fi getport="" teeport="" if echo "$ssh_cmd" | egrep "(PORT=|P=) " > /dev/null; then getport=1 if echo "$ssh_cmd" | egrep "P= " > /dev/null; then teeport=1 fi PORT="" ssh_cmd=`echo "$ssh_cmd" | sed -e 's/PORT=[ ]*//' -e 's/P=//'` SSVNC_NO_ENC_WARN=1 if [ "X$use_sshssl" = "X" ]; then direct_connect=1 fi fi if [ "X$getport" != "X" ]; then ssh_redir="-D ${use}" elif [ "X$reverse" = "X" ]; then ssh_redir="-L ${use}:${vnc_host}:${port}" else ssh_redir="-R ${port}:${vnc_host}:${use}" fi pmark=`sh -c 'echo $$'` # the -t option actually speeds up typing response via VNC!! if [ "X$ssh_port" = "X22" ]; then ssh_port="" else ssh_port="-p $ssh_port" fi if [ "X$SS_VNCVIEWER_SSH_ONLY" != "X" ]; then echo "$ssh -x $ssh_port $targ $C $ssh_args $ssh_host \"$info\"" echo "" $ssh -x $ssh_port $targ $C $ssh_args $ssh_host "$ssh_cmd" exit $? elif [ "X$SS_VNCVIEWER_NO_F" != "X" ]; then echo "$ssh -x $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host \"$info\"" echo "" $ssh -x $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host "$ssh_cmd" rc=$? elif [ "X$getport" != "X" ]; then tport=/tmp/ss_vncviewer_tport${RANDOM}.$$ tport=`mytmp "$tport"` tport2=/tmp/ss_vncviewer_tport2${RANDOM}.$$ tport2=`mytmp "$tport2"` if [ "X$rsh" != "X1" ]; then if echo "$ssh_cmd" | grep "sudo " > /dev/null; then echo "" echo "Initial ssh with 'sudo id' to prime sudo so hopefully the next one" echo "will require no password..." echo "" targ="-t" $ssh -x $ssh_port $targ $ssh_args $ssh_host "sudo id; tty" echo "" fi echo "$ssh -x -f $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host \"$info\"" echo "" $ssh -x -f $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host "$ssh_cmd" > $tport 2> $tport2 if [ "X$teeport" = "X1" ]; then tail -f $tport 1>&2 & tail_pid=$! tail -f $tport2 1>&2 & tail_pid2=$! fi rc=$? else rsh_setup echo "rsh $ul $ssh_host \"$ssh_cmd\"" echo "" rsh $ul $ssh_host "$ssh_cmd" > $tport & sleep 1 rc=0 fi if [ "X$SSVNC_EXTRA_SLEEP" != "X" ]; then echo "sleep $SSVNC_EXTRA_SLEEP" sleep $SSVNC_EXTRA_SLEEP fi stty sane i=0 if type perl > /dev/null 2>&1; then imax=50 sleepit="perl -e 'select(undef, undef, undef, 0.20)'" else imax=10 sleepit="sleep 1" fi while [ $i -lt $imax ]; do #echo $sleepit eval $sleepit PORT=`grep "^PORT=" $tport | tr '\r' ' ' | head -n 1 | sed -e 's/PORT=//' -e 's/\r//g' -e 's/ *$//'` if echo "$PORT" | grep '^[0-9][0-9]*$' > /dev/null; then break fi vnss=`sed -e 's/\r//g' $tport $tport2 | egrep -i '^(New.* desktop is|A VNC server is already running).*:[0-9[0-9]*$' | head -n 1 | awk '{print $NF}'` if [ "X$vnss" != "X" ]; then PORT=`echo "$vnss" | awk -F: '{print $2}'` if echo "$PORT" | grep '^[0-9][0-9]*$' > /dev/null; then if [ $PORT -lt 100 ]; then PORT=`expr $PORT + 5900` fi fi if echo "$PORT" | grep '^[0-9][0-9]*$' > /dev/null; then vnss=`sed -e 's/\r//g' $tport | egrep -i '^(New.* desktop is|A VNC server is already running).*:[0-9[0-9]*$' | head -n 1` echo "vncserver string: $vnss" 1>&2 break fi fi i=`expr $i + 1` done echo "found: PORT='$PORT'" 1>&2 rm -f $tport $tport2 if [ "X$rsh" = "X1" ]; then rsh_viewer "$@" exit $? fi PPROXY_SOCKS=1 if [ "X$SSVNC_SOCKS5" != "X" ]; then PPROXY_SOCKS=5 fi export PPROXY_SOCKS host="$localhost" port="$PORT" proxy="$localhost:$use" else if [ "X$rsh" != "X1" ]; then echo "$ssh -x -f $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host \"$info\"" echo "" $ssh -x -f $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host "$ssh_cmd" rc=$? else rsh_setup echo "rsh $ul $ssh_host \"$ssh_cmd\"" echo "" rsh $ul $ssh_host "$ssh_cmd" & sleep 1 PORT=$port rsh_viewer "$@" exit $? fi fi if [ "$rc" != "0" ]; then echo "" echo "ssh to $ssh_host failed." exit 1 fi stty sane c=0 pssh="" while [ $c -lt 40 ] do p=`expr $pmark + $c` pout=`ps -p "$p" 2>/dev/null | grep -v '^[ ]*PID' | sed -e 's/-L.*$//' -e 's/-x .*$//'` if echo "$pout" | grep "ssh" > /dev/null; then if echo "$pout" | egrep -i 'ssh.*(-add|-agent|-ask|-keygen|-argv0|vnc)' >/dev/null; then : elif echo "$pout" | egrep -i 'scp|sshd' >/dev/null; then : else pssh=$p break fi fi c=`expr $c + 1` done if [ "X$getport" != "X" ]; then : elif [ "X$SSVNC_LIM_ACCEPT_PRELOAD" != "X" ] ; then sleep 2 elif [ "X$ssh_cmd" = "Xsleep $ssh_sleep" ] ; then #echo T sleep 1 sleep 1 elif echo "$ssh_cmd" | grep '^sleep ' >/dev/null; then #echo T sleep 2 sleep 2 else # let any command get started a bit. #echo T sleep 5 sleep 5 fi echo "" #reset stty sane if [ "X$SSVNC_EXTRA_SLEEP" != "X" ]; then echo "sleep $SSVNC_EXTRA_SLEEP" sleep $SSVNC_EXTRA_SLEEP fi echo "ssh_pid='$pssh'"; echo if [ "X$use_sshssl" = "X" -a "X$getport" = "X" ]; then echo "Running viewer:" trap "final" 0 2 15 if [ "X$reverse" = "X" ]; then echo "$VNCVIEWERCMD" "$@" $localhost:$N echo "" $VNCVIEWERCMD "$@" $localhost:$N if [ $? != 0 ]; then echo "vncviewer command failed: $?" if [ "X$secondtry" = "X1" ]; then sleep 2 $VNCVIEWERCMD "$@" $localhost:$N fi fi else echo "" echo "NOTE: Press Ctrl-C to terminate viewer LISTEN mode." echo "" N2=$N if [ "X$VNCVIEWER_IS_REALVNC4" = "X1" ]; then N2=`echo "$N2" | sed -e 's/://g'` if [ $N2 -le 200 ]; then N2=`expr $N2 + 5500` fi fi echo "$VNCVIEWERCMD" "$@" -listen $N2 echo "" $VNCVIEWERCMD "$@" -listen $N2 fi exit $? else use2=`findfree 5960` host0=$host port0=$port host=$localhost port=$use use=$use2 N=`expr $use - 5900` if [ "X$getport" != "X" ]; then host="$host0" port="$port0" else proxy="" fi if [ "X$ssh_vencrypt_proxy" != "X" ]; then ssh_vencrypt_proxy="vencrypt://$host:$port" if [ "X$proxy" = "X" ]; then proxy=$ssh_vencrypt_proxy else proxy="$proxy,$ssh_vencrypt_proxy" fi Kecho "proxy_now=$proxy" unset PPROXY_LISTEN fi fi fi if [ "X$stunnel_set_here" = "X1" -a "X$showcert" = "X" ]; then if type $STUNNEL > /dev/null 2>&1; then : else echo "" echo "***************************************************************" echo "** Problem finding the Stunnel command '$STUNNEL': **" echo "" type $STUNNEL echo "" echo "** Perhaps you need to install the stunnel/stunnel4 package. **" echo "***************************************************************" echo "" sleep 5 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$SSVNC_STUNNEL_VERIFY3" != "X" ]; then verify=`echo "$verify" | sed -e 's/verify = 2/verify = 3/'` fi if [ "X$mycert" != "X" ]; then cert="cert = $mycert" fi if [ "X$crl" != "X" ]; then if [ -d $crl ]; then crl="CRLpath = $crl" else crl="CRLfile = $crl" fi fi ptmp="" if [ "X$proxy" != "X" ]; then ptmp="/tmp/ss_vncviewer${RANDOM}.$$.pl" ptmp=`mytmp "$ptmp"` PPROXY_REMOVE=1; export PPROXY_REMOVE pcode "$ptmp" if [ "X$showcert" != "X1" -a "X$direct_connect" = "X" ]; then if uname | egrep 'Darwin|SunOS' >/dev/null; then vout=`echo "$proxy" | grep -i vencrypt` if [ "X$vout" != "X" -a "X$reverse" = "X1" ]; then # need to exec for reverse vencrypt connect="exec = $ptmp" else # on mac and solaris we need to listen on socket instead of stdio: nd=`findfree 6700` PPROXY_LISTEN=$nd export PPROXY_LISTEN if [ "X$reverse" = "X" ]; then $ptmp & fi sleep 2 host="$localhost" port="$nd" connect="connect = $localhost:$nd" fi else # otherwise on unix we can exec it: connect="exec = $ptmp" fi else connect="exec = $ptmp" fi else connect="connect = $host:$port" fi # handle showcert case: # if [ "X$showcert" = "X1" ]; then if [ "X$proxy" != "X" ]; then PPROXY_LISTEN=$use export PPROXY_LISTEN if [ "X$SS_DEBUG" != "X" ]; then $ptmp & else $ptmp 2>/dev/null & fi sleep 1 more_sleep=1 if uname | grep Linux > /dev/null; then if netstat -ant | grep LISTEN | grep "127.0.0.1:$use" > /dev/null; then more_sleep="" fi elif uname | grep SunOS > /dev/null; then if netstat -an -f inet -P tcp | grep LISTEN | grep "127.0.0.1.$use" > /dev/null; then more_sleep="" fi elif uname | egrep -i 'bsd|darwin' > /dev/null; then if netstat -ant -f inet | grep LISTEN | grep "127.0.0.1.$use" > /dev/null; then more_sleep="" fi fi if [ "X$more_sleep" = "X1" ]; then sleep 1 fi host="$localhost" port="$use" fi cipher_args="" if [ "X$ciphers" != "X" ]; then cipher_args=`echo "$ciphers" | sed -e 's/ciphers=/-cipher /'` fi if type openssl > /dev/null 2>&1; then : else echo "" echo "********************************************************" echo "** Problem finding the OpenSSL command 'openssl': **" echo "" type openssl 2>&1 echo "" echo "** Perhaps you need to install the 'openssl' package. **" echo "********************************************************" echo "" fi #echo "openssl s_client $cipher_args -connect $host:$port" if [ "X$reverse" = "X" ]; then host $host >/dev/null 2>&1 host $host >/dev/null 2>&1 timeout=15 if [ "X$SSVNC_FETCH_TIMEOUT" != "X" ]; then timeout=$SSVNC_FETCH_TIMEOUT fi if type pkill >/dev/null 2>&1; then (sleep $timeout; if kill -0 $$; then pkill -TERM -f "openssl.*s_client.*$host.*$port"; fi) >/dev/null 2>&1 & fi openssl s_client $cipher_args -prexit -connect $host:$port 2>&1 < /dev/null rc=$? else tcert="" if [ "X$mycert" = "X" ]; then tcert=`make_tcert` cert_args="-cert $tcert -CAfile $tcert" else cert_args="-cert $mycert -CAfile $mycert" fi tmp_out=/tmp/showcert_out${RANDOM}.$$ tmp_out=`mytmp "$tmp_out"` tmp_err=/tmp/showcert_err${RANDOM}.$$ tmp_err=`mytmp "$tmp_err"` #echo "openssl s_server $cipher_args $cert_args -accept $port -verify 2 > $tmp_out 2> $tmp_err" 1>&2 # assume we have perl: check_perl perl perl -e " \$p = open(O, \"|openssl s_server $cipher_args $cert_args -accept $port -verify 2 1>$tmp_out 2> $tmp_err\"); exit 1 unless \$p; while (1) { sleep 1; if (!open(F, \"<$tmp_out\")) { kill \$p; exit 1; } while () { if (/RFB 00/) { fsleep(0.25); print O \"RFB 000.000\\n\"; fsleep(1.00); kill \$p; fsleep(0.25); exit 0; } } close F; } sub fsleep { select(undef, undef, undef, shift); } "; echo "" cat $tmp_out echo "" echo "----2----" cat $tmp_err if grep BEGIN.CERTIFICATE $tmp_out >/dev/null; then rc=0 else rc=1 fi rm -f $tmp_out $tmp_err fi if [ "X$SSVNC_PREDIGESTED_HANDSHAKE" != "X" ]; then rm -f $SSVNC_PREDIGESTED_HANDSHAKE fi if [ "X$SSVNC_SHOWCERT_EXIT_0" = "X1" ]; then exit 0 else exit $rc fi fi # handle direct connect case: # if [ "X$direct_connect" != "X" ]; then if [ "X$SSVNC_ULTRA_DSM" != "X" ]; then SSVNC_NO_ENC_WARN=1 echo "" echo "Using UltraVNC DSM Plugin key for encryption:" echo "" ustr=`echo "$SSVNC_ULTRA_DSM" | sed -e 's/pw=[^ ]*/pw=******/g'` echo " $ustr PORT HOST:PORT" echo "" elif [ "X$getport" = "X" ]; then echo "" echo "Running viewer for direct connection:" if echo X"$@" | grep chatonly > /dev/null; then : else echo "" echo "** WARNING: THERE WILL BE NO SSL OR SSH ENCRYPTION **" echo "" fi fi x="" if [ "X$SSVNC_NO_ENC_WARN" != "X" ]; then if [ "X$getport" = "X" ]; then sleep 1 fi elif type printf > /dev/null 2>&1; then printf "Are you sure you want to continue? [y]/n " read x else echo -n "Are you sure you want to continue? [y]/n " read x fi if [ "X$x" = "Xn" ]; then exit 1 fi echo "" if [ "X$ptmp" != "X" ]; then if [ "X$reverse" = "X" ]; then PPROXY_LISTEN=$use export PPROXY_LISTEN else PPROXY_REVERSE="$localhost:$use" export PPROXY_REVERSE pps=3 if [ "X$SSVNC_EXTRA_SLEEP" != "X" ]; then pps=`expr $pps + $SSVNC_EXTRA_SLEEP` fi PPROXY_SLEEP=$pps; export PPROXY_SLEEP; PPROXY_KILLPID=+1; export PPROXY_KILLPID; fi $ptmp & if [ "X$reverse" = "X" ]; then #sleep 2 #echo T sleep 1 sleep 1 fi host="$localhost" disp="$N" port=`expr $disp + 5900` fi if [ "X$SSVNC_EXTRA_SLEEP" != "X" ]; then echo "T sleep $SSVNC_EXTRA_SLEEP" sleep $SSVNC_EXTRA_SLEEP fi if [ "X$reverse" = "X" ]; then hostdisp="$host:$disp" if [ "X$SSVNC_ULTRA_DSM" != "X" ]; then if [ "X$SSVNC_USE_OURS" = "X1" ]; then hostdisp="exec=$SSVNC_ULTRA_DSM 0 $host:$port" else pf=`findfree 5970` cmd="$SSVNC_ULTRA_DSM -$pf $host:$port" pf=`expr $pf - 5900` hostdisp="$localhost:$pf" ustr=`echo "$cmd" | sed -e 's/pw=[^ ]*/pw=******/g'` echo "Running:" echo echo "$ustr &" echo $cmd & dsm_pid=$! sleep 2 fi fi hostdisp2=`echo "$hostdisp" | sed -e 's/pw=[^ ]*/pw=******/g'` echo "$VNCVIEWERCMD" "$@" "$hostdisp2" trap "final" 0 2 15 echo "" $VNCVIEWERCMD "$@" "$hostdisp" if [ $? != 0 ]; then echo "vncviewer command failed: $?" if [ "X$secondtry" = "X1" ]; then sleep 2 $VNCVIEWERCMD "$@" "$hostdisp" fi fi else echo "" echo "NOTE: Press Ctrl-C to terminate viewer LISTEN mode." echo "" trap "final" 0 2 15 if [ "X$SSVNC_ULTRA_DSM" != "X" ]; then echo "NOTE: The ultravnc_dsm_helper only runs once. So after the first LISTEN" echo " ends, you may have to Press Ctrl-C and restart for another connection." echo "" SSVNC_LISTEN_ONCE=1; export SSVNC_LISTEN_ONCE VNCVIEWER_LISTEN_LOCALHOST=1 export VNCVIEWER_LISTEN_LOCALHOST dport=`expr 5500 + $disp` cmd="$SSVNC_ULTRA_DSM $dport $localhost:$use" ustr=`echo "$cmd" | sed -e 's/pw=[^ ]*/pw=******/g'` echo "Running:" echo echo "$ustr &" echo $cmd & dsm_pid=$! sleep 2 disp=$use if [ $disp -ge 5500 ]; then disp=`expr $disp - 5500` fi fi disp2=$disp if [ "X$VNCVIEWER_IS_REALVNC4" = "X1" ]; then disp2=`echo "$disp2" | sed -e 's/://g'` if [ $disp2 -le 200 ]; then disp2=`expr $disp2 + 5500` fi fi echo "$VNCVIEWERCMD" "$@" -listen $disp2 echo "" $VNCVIEWERCMD "$@" -listen $disp2 fi exit $? fi tmp_cfg=/tmp/ss_vncviewer${RANDOM}.$$ tmp_cfg=`mytmp "$tmp_cfg"` stunnel_exec="" if [ "X$SSVNC_USE_OURS" != "X1" ]; then : elif echo $STUNNEL_EXTRA_SVC_OPTS | grep '#stunnel-exec' > /dev/null; then stunnel_exec="#" fi if [ "X$reverse" = "X" ]; then if echo "$proxy" | grep "^repeater://" > /dev/null; then if [ "X$cert" = "XBUILTIN" ]; then ttcert=`make_tcert` cert="cert = $ttcert" fi # Note for listen mode, an empty cert will cause stunnel to fail. # The ssvnc gui will have already taken care of this. fi cat > "$tmp_cfg" < /dev/null; then hloc="$localhost:" pv=`findfree 5570` proxy="vencrypt:$pv:$port" port=$pv if [ "X$anondh_set" = "X1" ]; then # not needed for ANONDH in this mode #ciphers="ciphers = ADH:@STRENGTH" : fi fi cat > "$tmp_cfg" < /dev/null 2>&1 $STUNNEL "$tmp_cfg" < /dev/tty > /dev/tty & stunnel_pid=$! echo "" # pause here to let the user supply a possible passphrase for the # mycert key: if [ "X$mycert" != "X" ]; then nsl=10 dsl=0 if [ ! -f $mycert ]; then dsl=0 elif grep -i 'Proc-Type.*ENCRYPTED' "$mycert" > /dev/null 2>/dev/null; then dsl=1 fi if [ "X$dsl" = "X1" ]; then echo "" echo "(** pausing $nsl secs for possible certificate passphrase dialog **)" echo "" sleep $nsl echo "(** done pausing for passphrase **)" echo "" fi fi #echo T sleep 1 sleep 1 rm -f "$tmp_cfg" fi echo "" if [ "X$SSVNC_EXTRA_SLEEP" != "X" ]; then echo "sleep $SSVNC_EXTRA_SLEEP" sleep $SSVNC_EXTRA_SLEEP fi if [ "X$reverse" = "X" ]; then if [ "X$NEED_VENCRYPT_VIEWER_BRIDGE" = "X1" -a "X$ptmp" != "X" ] ; then port1=`expr 5900 + $N` # stunnel port port2=`findfree 5970` # bridge port (viewer connects to it.) N=`expr $port2 - 5900` env PPROXY_REMOVE=0 PPROXY_SLEEP=0 PPROXY_VENCRYPT_VIEWER_BRIDGE="$port2,$port1" $ptmp & sleep 1 fi echo "Running viewer:" vnc_hp=$localhost:$N if [ "X$stunnel_exec" != "X" ]; then vnc_hp="exec=$STUNNEL $tmp_cfg" fi echo "$VNCVIEWERCMD" "$@" "$vnc_hp" trap "final" 0 2 15 echo "" $VNCVIEWERCMD "$@" "$vnc_hp" if [ $? != 0 ]; then echo "vncviewer command failed: $?" if [ "X$secondtry" = "X1" ]; then sleep 2 $VNCVIEWERCMD "$@" "$vnc_hp" fi fi else echo "Running viewer:" echo "" echo "NOTE: Press Ctrl-C to terminate viewer LISTEN mode." echo "" trap "final" 0 2 15 N2=$N N2_trim=`echo "$N2" | sed -e 's/://g'` if [ $N2_trim -le 200 ]; then N2_trim=`expr $N2_trim + 5500` fi if [ "X$proxy" != "X" ]; then if echo "$proxy" | grep -i '^vencrypt:' > /dev/null; then pstunnel=`echo "$proxy" | awk -F: '{print $2}'` plisten=`echo "$proxy" | awk -F: '{print $3}'` PPROXY_LISTEN="INADDR_ANY:$plisten"; export PPROXY_LISTEN PPROXY_PROXY="vencrypt://$localhost:$pstunnel"; export PPROXY_PROXY PPROXY_DEST="$localhost:$pstunnel"; export PPROXY_DEST STUNNEL_ONCE=1; export STUNNEL_ONCE STUNNEL_MAX_CLIENTS=1; export STUNNEL_MAX_CLIENTS if [ "X$NEED_VENCRYPT_VIEWER_BRIDGE" = "X1" -a "X$ptmp" != "X" ] ; then port1=`expr 5500 + $N2` port2=`findfree 5580` N2=`expr $port2 - 5500` N2_trim=`echo "$N2" | sed -e 's/://g'` if [ $N2_trim -le 200 ]; then N2_trim=`expr $N2_trim + 5500` fi env PPROXY_REMOVE=0 PPROXY_SLEEP=0 PPROXY_VENCRYPT_VIEWER_BRIDGE="-$port1,$port2" $ptmp & sleep 1 fi else PPROXY_REVERSE="$localhost:$port"; export PPROXY_REVERSE PPROXY_SLEEP=1; export PPROXY_SLEEP; fi PPROXY_KILLPID=+1; export PPROXY_KILLPID; $ptmp & # Important to have no extra pids generated between here and VNCVIEWERCMD fi if [ "X$VNCVIEWER_IS_REALVNC4" = "X1" ]; then N2=$N2_trim fi echo "$VNCVIEWERCMD" "$@" -listen $N2 echo "" $VNCVIEWERCMD "$@" -listen $N2 fi sleep 1