diff options
Diffstat (limited to 'webclients/ssl/ss_vncviewer')
-rwxr-xr-x | webclients/ssl/ss_vncviewer | 3676 |
1 files changed, 3676 insertions, 0 deletions
diff --git a/webclients/ssl/ss_vncviewer b/webclients/ssl/ss_vncviewer new file mode 100755 index 0000000..7e793ff --- /dev/null +++ b/webclients/ssl/ss_vncviewer @@ -0,0 +1,3676 @@ +#!/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 <runge@karlrunge.com> +# +# 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 <http://www.gnu.org/licenses/>. +# +# +# 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 <vncviewer-args> +# +# 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). On ssvnc 1.0.27 and +# later the bundled command 'ultravnc_dsm_helper' is used. +# +# 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" + ULTRAVNC_DSM_HELPER_SHOWCERT_ADH=1 + export ULTRAVNC_DSM_HELPER_SHOWCERT_ADH + 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 + + # we now try to PPROXY_LOOP_THYSELF, set this var to disable that. + #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 + +have_uvnc_dsm_helper_showcert="" +if [ "X$showcert" = "X1" -a "X$SSVNC_USE_S_CLIENT" = "X" -a "X$reverse" = "X" ]; then + if type ultravnc_dsm_helper >/dev/null 2>&1; then + if ultravnc_dsm_helper -help 2>&1 | grep -w showcert >/dev/null; then + have_uvnc_dsm_helper_showcert=1 + fi + fi +fi +have_uvnc_dsm_helper_ipv6="" +if [ "X$SSVNC_ULTRA_DSM" != "X" ]; then + if type ultravnc_dsm_helper >/dev/null 2>&1; then + if ultravnc_dsm_helper -help 2>&1 | grep -iw ipv6 >/dev/null; then + have_uvnc_dsm_helper_ipv6=1 + fi + fi +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 + +# 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 ':[0-9][0-9]*$' > /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: + +# try to see if it is ipv6 address: +ipv6=0 +if echo "$orig" | grep '\[' > /dev/null; then + # ipv6 [fe80::219:dbff:fee5:3f92%eth1]:5900 + host=`echo "$orig" | sed -e 's/\].*$//' -e 's/\[//'` + disp=`echo "$orig" | sed -e 's/^.*\]://'` + ipv6=1 +elif echo "$orig" | grep ':..*:' > /dev/null; then + # ipv6 fe80::219:dbff:fee5:3f92%eth1:5900 + host=`echo "$orig" | sed -e 's/:[^:]*$//'` + disp=`echo "$orig" | sed -e 's/^.*://'` + ipv6=1 +else + # regular host:port + host=`echo "$orig" | awk -F: '{print $1}'` + disp=`echo "$orig" | awk -F: '{print $2}'` +fi + +if [ "X$reverse" != "X" -a "X$STUNNEL_LISTEN" = "X" -a "X$host" != "X" ]; then + STUNNEL_LISTEN=$host + echo "set STUNNEL_LISTEN=$STUNNEL_LISTEN" +fi + +if [ "X$host" = "X" ]; then + host=$localhost +fi + +if [ "X$SSVNC_IPV6" = "X0" ]; then + # disable checking for it. + ipv6=0 +#elif [ "X$reverse" != "X" -a "X$ipv6" = "X1" ]; then +# ipv6=0 +elif [ "X$ipv6" = "X1" ]; then + : +elif echo "$host" | grep '^[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$' > /dev/null; then + : +else + # regular hostname, can't be sure... + gout="" + if type getent > /dev/null 2>/dev/null; then + gout=`getent hosts "$host" 2>/dev/null` + fi + if echo "$gout" | grep ':.*:' > /dev/null; then + if echo "$gout" | grep '^[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$' > /dev/null; then + : + else + echo "ipv6: "`echo "$gout" | grep ':.*:' | head -n 1` + ipv6=1 + fi + fi + if [ "X$ipv6" = "X0" ]; then + hout="" + if type host > /dev/null 2>/dev/null; then + host "$host" >/dev/null 2>&1 + host "$host" >/dev/null 2>&1 + hout=`host "$host" 2>/dev/null` + fi + if echo "$hout" | grep -i 'has ipv6 address' > /dev/null; then + if echo "$hout" | grep -i 'has address' > /dev/null; then + : + else + echo "ipv6: "`echo "$hout" | grep -i 'has ipv6 address' | head -n 1` + ipv6=1 + fi + fi + fi + if [ "X$ipv6" = "X0" ]; then + dout="" + if type dig > /dev/null 2>/dev/null; then + dout=`dig -t any "$host" 2>/dev/null` + fi + if echo "$dout" | grep -i "^$host" | grep '[ ]AAAA[ ]' > /dev/null; then + if echo "$dout" | grep -i "^$host" | grep '[ ]A[ ]' > /dev/null; then + : + else + echo "ipv6: "`echo "$dout" | grep -i '[ ]AAAA[ ]' | head -n 1` + ipv6=1 + fi + fi + fi + if [ "X$ipv6" = "X0" ]; then + sout=`env LOOKUP="$host" \ + perl -e ' eval {use Socket}; exit 0 if $@; + eval {use Socket6}; exit 0 if $@; + @res = getaddrinfo($ENV{LOOKUP}, "daytime", AF_UNSPEC, SOCK_STREAM); + $ipv4 = 0; + $ipv6 = 0; + $ip6 = ""; + while (scalar(@res) >= 5) { + ($family, $socktype, $proto, $saddr, $canon, @res) = @res; + $ipv4 = 1 if $family == AF_INET; + $ipv6 = 1 if $family == AF_INET6; + if ($family == AF_INET6 && $ip6 eq "") { + my ($host, $port) = getnameinfo($saddr, NI_NUMERICHOST | NI_NUMERICSERV); + $ip6 = $host; + } + } + if (! $ipv4 && $ipv6) { + print "AF_INET6_ONLY: $ENV{LOOKUP}: $ip6\n"; + } + exit 0; + ' 2>/dev/null` + if echo "$sout" | grep AF_INET6_ONLY > /dev/null; then + echo "$sout" + ipv6=1 + fi + fi +fi +if [ "X$ipv6" = "X1" ]; then + echo "ipv6: addr=$host disp=$disp" +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 + +if [ "X$ipv6" = "X1" -a "X$direct_connect" = "X1" ]; then + if [ "X$proxy" = "X" -a "X$reverse" = "X" ]; then + if [ "X$SSVNC_ULTRA_DSM" != "X" -a "X$have_uvnc_dsm_helper_ipv6" = "X1" ]; then + : + elif [ "X$SSVNC_NO_IPV6_PROXY" != "X" ]; then + : + elif [ "X$SSVNC_NO_IPV6_PROXY_DIRECT" != "X" ]; then + : + elif [ "X$SSVNC_USE_OURS" = "X1" ]; then + # requires 1.0.27 and later ssvncviewer binary + : + else + proxy="ipv6://$host:$port" + echo "direct connect: set proxy=$proxy" + fi + fi +fi + +# (possibly) tell the vncviewer to only listen on lo: +if [ "X$reverse" != "X" ]; then + if [ "X$direct_connect" = "X" -o "X$proxy" != "X" -o "X$STUNNEL_LISTEN" != "X" ]; then + VNCVIEWER_LISTEN_LOCALHOST=1 + export VNCVIEWER_LISTEN_LOCALHOST + fi +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; + +my $have_inet6 = ""; +eval "use IO::Socket::INET6;"; +$have_inet6 = 1 if $@ eq ""; + +#my $have_sock6 = ""; +#eval "use Socket; use Socket6;"; +#$have_sock6 = 1 if $@ eq ""; + +if (exists $ENV{PPROXY_LOOP_THYSELF}) { + # used for reverse vnc, run a repeating outer loop. + print STDERR "PPROXY_LOOP: $ENV{PPROXY_LOOP_THYSELF}\n"; + my $rm = $ENV{PPROXY_REMOVE}; + my $lp = $ENV{PPROXY_LOOP_THYSELF}; + delete $ENV{PPROXY_REMOVE}; + delete $ENV{PPROXY_LOOP_THYSELF}; + $ENV{PPROXY_LOOP_THYSELF_MASTER} = $$; + my $pid = $$; + my $dbg = 0; + my $c = 0; + use POSIX ":sys_wait_h"; + while (1) { + $pid = fork(); + last if ! defined $pid; + if ($pid eq "0") { + last; + } + $c++; + print STDERR "\nPPROXY_LOOP: pid=$$ child=$pid count=$c\n"; + while (1) { + waitpid(-1, WNOHANG); + fsleep(0.25); + if (! kill 0, $pid) { + print STDERR "PPROXY_LOOP: child=$pid gone.\n"; + last; + } + print STDERR "PPROXY_LOOP: child=$pid alive.\n" if $dbg; + if (! -f $lp) { + print STDERR "PPROXY_LOOP: flag file $lp gone, killing $pid\n"; + kill TERM, $pid; + fsleep(0.1); + wait; + last; + } + print STDERR "PPROXY_LOOP: file exists $lp\n" if $dbg; + } + last if ! -f $lp; + fsleep(0.25); + } + if ($pid ne "0") { + unlink($0) if $rm; + exit 0; + } +} + +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 = $$; + +my $initial_data = ""; + +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) = ($first, ""); +if ($proxy_host =~ /^(.*):(\d+)$/) { + $proxy_host = $1; + $proxy_port = $2; +} +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.4: a tool for Web, SOCKS, and UltraVNC proxies and for\n"; +print STDERR "PPROXY v0.4: IPv6 and VNC 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 "io_socket_inet6: $have_inet6\n"; +print STDERR "\n"; +if (! $have_inet6) { + print STDERR "PPROXY: To enable IPv6 connections, install the IO::Socket::INET6 perl module.\n\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) = ($ENV{PPROXY_REVERSE}, ""); + if ($rhost =~ /^(.*):(\d+)$/) { + $rhost = $1; + $rport = $2; + } + $rport = 5900 unless $rport; + my $emsg = ""; + $listen_handle = IO::Socket::INET->new( + PeerAddr => $rhost, + PeerPort => $rport, + Proto => "tcp" + ); + $emsg = $!; + if (! $listen_handle && $have_inet6) { + eval {$listen_handle = IO::Socket::INET6->new( + PeerAddr => $rhost, + PeerPort => $rport, + Proto => "tcp" + );}; + $emsg .= " / $!"; + } + if (! $listen_handle) { + pdie "pproxy: $emsg -- 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 = ""; + my $emsg = ""; + for (my $i=0; $i < $maxtry; $i++) { + my ($if, $p) = ("", $ENV{PPROXY_LISTEN}); + if ($p =~ /^(.*):(\d+)$/) { + $if = $1; + $p = $2; + } + $p2 = "*:$p"; + if ($if eq "") { + $if = "localhost"; + } + print STDERR "pproxy interface: $if\n"; + + $emsg = ""; + if (($if eq "INADDR_ANY6" || $if eq "::") && $have_inet6) { + eval {$listen_sock = IO::Socket::INET6->new( + Listen => 2, + ReuseAddr => 1, + Domain => AF_INET6, + LocalAddr => "::", + LocalPort => $p, + Proto => "tcp" + );}; + $p2 = ":::$p"; + } elsif ($if =~ /^INADDR_ANY/) { + $listen_sock = IO::Socket::INET->new( + Listen => 2, + ReuseAddr => 1, + LocalPort => $p, + Proto => "tcp" + ); + } elsif (($if eq "INADDR_LOOPBACK6" || $if eq "::1") && $have_inet6) { + $p2 = "::1:$p"; + eval {$listen_sock = IO::Socket::INET6->new( + Listen => 2, + ReuseAddr => 1, + Domain => AF_INET6, + LocalAddr => "::1", + LocalPort => $p, + Proto => "tcp" + );}; + $p2 = "::1:$p"; + } else { + $p2 = "$if:$p"; + $listen_sock = IO::Socket::INET->new( + Listen => 2, + ReuseAddr => 1, + LocalAddr => $if, + LocalPort => $p, + Proto => "tcp" + ); + $emsg = $!; + + if (! $listen_sock && $have_inet6) { + print STDERR "PPROXY_LISTEN: retry with INET6\n"; + eval {$listen_sock = IO::Socket::INET6->new( + Listen => 2, + ReuseAddr => 1, + Domain => AF_INET6, + LocalAddr => $if, + LocalPort => $p, + Proto => "tcp" + );}; + $emsg .= " / $!"; + } + } + if (! $listen_sock) { + if ($i < $maxtry - 1) { + warn "pproxy: $emsg $!\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: $emsg -- 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"; + } + + if ($ENV{PPROXY_LOOP_THYSELF_MASTER}) { + my $sml = $ENV{SSVNC_MULTIPLE_LISTEN}; + if ($sml ne "" && $sml ne "0") { + setpgrp(0, 0); + if (fork()) { + close $viewer_sock; + wait; + exit 0; + } + if (fork()) { + close $viewer_sock; + exit 0; + } + setpgrp(0, 0); + $parent = $$; + } + } +} + +$sock = IO::Socket::INET->new( + PeerAddr => $proxy_host, + PeerPort => $proxy_port, + Proto => "tcp" +); + +my $err = ""; + +if (! $sock && $have_inet6) { + $err = $!; + + print STDERR "pproxy: $!\n"; + + eval {$sock = IO::Socket::INET6->new( + PeerAddr => $proxy_host, + PeerPort => $proxy_port, + Proto => "tcp" + );}; + $err .= " / $!"; +} + +if (! $sock && ($proxy_host =~ /^::ffff:(\d+\.\d+\.\d+\.\d+)$/i || $proxy_host =~ /^::ffff:([\da-f]+:[\da-f]+)$/i)) { + print STDERR "pproxy: $!\n"; + my $ipv4_addr = $1; + if ($ipv4_addr =~ /:/) { + my ($a, $b) = split(/:/, $ipv4_addr); + $a = hex($a); + $b = hex($b); + $ipv4_addr = sprintf("%d.", ($a & 0xff00) >> 8); + $ipv4_addr .= sprintf("%d.", ($a & 0x00ff)); + $ipv4_addr .= sprintf("%d.", ($b & 0xff00) >> 8); + $ipv4_addr .= sprintf("%d", ($b & 0x00ff)); + } + + print STDERR "pproxy: re-trying with ipv4 addr: $ipv4_addr\n"; + + eval {$sock = IO::Socket::INET->new( + PeerAddr => $ipv4_addr, + PeerPort => $proxy_port, + Proto => "tcp" + );}; + $err .= " / $!"; +} + +if (! $sock) { + unlink($0) if $ENV{PPROXY_REMOVE}; + pdie "pproxy: $err\n"; +} + +unlink($0) if $ENV{PPROXY_REMOVE}; + +if ($ENV{PPROXY_PROXY} =~ /^vencrypt:/ && $ENV{PPROXY_VENCRYPT_REVERSE}) { + 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"; + if ($initial_data ne "") { + my $len = length $initial_data; + print STDERR "pproxy child [$$] sending initial_data, length $len\n\n"; + syswrite($listen_handle, $initial_data, $len); + } else { + print STDERR "\n"; + } + xfer($sock, $listen_handle); + } else { + print STDERR "pproxy child [$$] socket -> STDOUT\n"; + if ($initial_data ne "") { + my $len = length $initial_data; + print STDERR "pproxy child [$$] sending initial_data, length $len\n\n"; + syswrite(STDOUT, $initial_data, $len); + } else { + print STDERR "\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 fsleep { + select(undef, undef, undef, shift); +} + +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,^ipv6://(\S*)$,i) { + $mode = "ipv6"; + $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 =~ /^ipv6/i) { + $ENV{PPROXY_SOCKS} = 0; + } 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) = ($CONNECT, ""); + if ($h =~ /^(.*):(\d+)$/) { + $h = $1; + $p = $2; + } + $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} eq "1") { + # SOCKS4 SOCKS4a + my ($h, $p) = ($CONNECT, ""); + if ($h =~ /^(.*):(\d+)$/) { + $h = $1; + $p = $2; + } + $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_SOCKS} eq "0") { + # hack for ipv6 "proxy", nothing to do, assume INET6 call worked. + ; + } 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 $rfb = ""; + + my $ok = 1; + for (my $i = 0; $i < 12; $i++) { + my $c; + last if $ENV{PPROXY_GENERIC_REPEATER}; + sysread($sock, $c, 1); + print STDERR $c; + $rfb .= $c; + } + if ($rfb ne "" && $rfb !~ /^RFB 000\.000/) { + $initial_data = $rfb; + $rfb =~ s/\n//g; + print STDERR "detected non-UltraVNC repeater; forwarding \"$rfb\"\nlength: ", length($initial_data), "\n"; + } + } 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, + ReuseAddr => 1, + 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"; + } + if ($ENV{PPROXY_LOOP_THYSELF_MASTER}) { + my $sml = $ENV{SSVNC_MULTIPLE_LISTEN}; + if ($sml ne "" && $sml ne "0") { + setpgrp(0, 0); + if (fork()) { + close $viewer_sock; + wait; + exit 0; + } + if (fork()) { + close $viewer_sock; + exit 0; + } + setpgrp(0, 0); + $parent = $$; + } + } + 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 (<HSF>) { + 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 <Return> {focus .f0.fR.eb} + bind .f0.fR.eb <Return> {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 <<END +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAvkfXxb0wcxgrjV2ziFikjII+ze8iKcTBt47L0GM/c21efelN ++zZpJUUXLu4zz8Ryq8Q+sQgfNy7uTOpN9bUUaOk1TnD7gaDQnQWiNHmqbW2kL+DS +OKngJVPo9dETAS8hf7+D1e1DBZxjTc1a4RQqWJixwpYj99ixWzu8VC2m/xXsjvOs +jp4+DLBB490nbkwvstmhmiWm1CmI5O5xOkgioVNQqHvQMdVKOSz9PpbjvZiRX1Uo +qoMrk+2NOqwP90TB35yPASXb9zXKpO7DLhkube+yYGf+yk46aD707L07Eb7cosFP +S84vNZ9gX7rQ0UOwm5rYA/oZTBskgaqhtIzkLwIDAQABAoIBAD4ot/sXt5kRn0Ca +CIkU9AQWlC+v28grR2EQW9JiaZrqcoDNUzUqbCTJsi4ZkIFh2lf0TsqELbZYNW6Y +6AjJM7al4E0UqYSKJTv2WCuuRxdiRs2BMwthqyBmjeanev7bB6V0ybt7u3Y8xU/o +MrTuYnr4vrEjXPKdLirwk7AoDbKsRXHSIiHEIBOq1+dUQ32t36ukdnnza4wKDLZc +PKHiCdCk/wOGhuDlxD6RspqUAlRnJ8/aEhrgWxadFXw1hRhRsf/v1shtB0T3DmTe +Jchjwyiw9mryb9JZAcKxW+fUc4EVvj6VdQGqYInQJY5Yxm5JAlVQUJicuuJEvn6A +rj5osQECgYEA552CaHpUiFlB4HGkjaH00kL+f0+gRF4PANCPk6X3UPDVYzKnzmuu +yDvIdEETGFWBwoztUrOOKqVvPEQ+kBa2+DWWYaERZLtg2cI5byfDJxQ3ldzilS3J +1S3WgCojqcsG/hlxoQJ1dZFanUy/QhUZ0B+wlC+Zp1Q8AyuGQvhHp68CgYEA0lBI +eqq2GGCdJuNHMPFbi8Q0BnX55LW5C1hWjhuYiEkb3hOaIJuJrqvayBlhcQa2cGqp +uP34e9UCfoeLgmoCQ0b4KpL2NGov/mL4i8bMgog4hcoYuIi3qxN18vVR14VKEh4U +RLk0igAYPU+IK2QByaQlBo9OSaKkcfm7U1/pK4ECgYAxr6VpGk0GDvfF2Tsusv6d +GIgV8ZP09qSLTTJvvxvF/lQYeqZq7sjI5aJD5i3de4JhpO/IXQJzfZfWOuGc8XKA +3qYK/Y2IqXXGYRcHFGWV/Y1LFd55mCADHlk0l1WdOBOg8P5iRu/Br9PbiLpCx9oI +vrOXpnp03eod1/luZmqguwKBgQCWFRSj9Q7ddpSvG6HCG3ro0qsNsUMTI1tZ7UBX +SPogx4tLf1GN03D9ZUZLZVFUByZKMtPLX/Hi7K9K/A9ikaPrvsl6GEX6QYzeTGJx +3Pw0amFrmDzr8ySewNR6/PXahxPEuhJcuI31rPufRRI3ZLah3rFNbRbBFX+klkJH +zTnoAQKBgDbUK/aQFGduSy7WUT7LlM3UlGxJ2sA90TQh4JRQwzur0ACN5GdYZkqM +YBts4sBJVwwJoxD9OpbvKu3uKCt41BSj0/KyoBzjT44S2io2tj1syujtlVUsyyBy +/ca0A7WBB8lD1D7QMIhYUm2O9kYtSCLlUTHt5leqGaRG38DqlX36 +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIDzDCCArQCCQDSzxzxqhyqLzANBgkqhkiG9w0BAQQFADCBpzELMAkGA1UEBhMC +VVMxFjAUBgNVBAgTDU1hc3NhY2h1c2V0dHMxDzANBgNVBAcTBkJvc3RvbjETMBEG +A1UEChMKTXkgQ29tcGFueTEcMBoGA1UECxMTUHJvZHVjdCBEZXZlbG9wbWVudDEZ +MBcGA1UEAxMQd3d3Lm5vd2hlcmUubm9uZTEhMB8GCSqGSIb3DQEJARYSYWRtaW5A +bm93aGVyZS5ub25lMB4XDTA3MDMyMzE4MDc0NVoXDTI2MDUyMjE4MDc0NVowgacx +CzAJBgNVBAYTAlVTMRYwFAYDVQQIEw1NYXNzYWNodXNldHRzMQ8wDQYDVQQHEwZC +b3N0b24xEzARBgNVBAoTCk15IENvbXBhbnkxHDAaBgNVBAsTE1Byb2R1Y3QgRGV2 +ZWxvcG1lbnQxGTAXBgNVBAMTEHd3dy5ub3doZXJlLm5vbmUxITAfBgkqhkiG9w0B +CQEWEmFkbWluQG5vd2hlcmUubm9uZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAL5H18W9MHMYK41ds4hYpIyCPs3vIinEwbeOy9BjP3NtXn3pTfs2aSVF +Fy7uM8/EcqvEPrEIHzcu7kzqTfW1FGjpNU5w+4Gg0J0FojR5qm1tpC/g0jip4CVT +6PXREwEvIX+/g9XtQwWcY03NWuEUKliYscKWI/fYsVs7vFQtpv8V7I7zrI6ePgyw +QePdJ25ML7LZoZolptQpiOTucTpIIqFTUKh70DHVSjks/T6W472YkV9VKKqDK5Pt +jTqsD/dEwd+cjwEl2/c1yqTuwy4ZLm3vsmBn/spOOmg+9Oy9OxG+3KLBT0vOLzWf +YF+60NFDsJua2AP6GUwbJIGqobSM5C8CAwEAATANBgkqhkiG9w0BAQQFAAOCAQEA +vGomHEp6TVU83X2EBUgnbOhzKJ9u3fOI/Uf5L7p//Vxqow7OR1cguzh/YEzmXOIL +ilMVnzX9nj/bvcLAuqEP7MR1A8f4+E807p/L/Sf49BiCcwQq5I966sGKYXjkve+T +2GTBNwMSq+5kLSf6QY8VZI+qnrAudEQMeJByQhTZZ0dH8Njeq8EGl9KUio+VWaiW +CQK6xJuAvAHqa06OjLmwu1fYD4GLGSrOIiRVkSXV8qLIUmzxdJaIRznkFWsrCEKR +wAH966SAOvd2s6yOHMvyDRIL7WHxfESB6rDHsdIW/yny1fBePjv473KrxyXtbz7I +dMw1yW09l+eEo4A7GzwOdw== +-----END CERTIFICATE----- +END + chmod 600 $tcert + echo "$tcert" +} + +Kecho() { + NO_KECHO=1 + if [ "X$USER" = "Xrunge" -a "X$NO_KECHO" = "X" ]; then + echo "dbg: $*" + fi +} + +NHAFL_warning() { + echo "" + echo "** Warning: For the proxy: $proxy" + echo "** Warning: the ssh(1) option: $ssh_NHAFL" + echo "** Warning: will be used to avoid frequent 'ssh key has changed for localhost'" + echo "** Warning: dialogs and connection failures (for example, ssh will exit asking" + echo "** Warning: you to manually remove a key from ~/.ssh/known_hosts.)" + echo "** Warning: " + echo "** Warning: This decreases security: a Man-In-The-Middle attack is possible." + echo "** Warning: For chained ssh connections the first ssh leg is secure but the" + echo "** Warning: 2nd ssh leg is vulnerable. For an ssh connection going through" + echo "** Warning: a HTTP or SOCKS proxy the ssh connection is vulnerable." + echo "** Warning: " + echo "** Warning: You can set the SSVNC_SSH_LOCALHOST_AUTH=1 env. var. to disable" + echo "** Warning: using the NoHostAuthenticationForLocalhost=yes ssh option." + echo "** Warning: " + echo "** Warning: A better solution is to configure (in the SSVNC GUI) the setting:" + echo "** Warning: 'Options -> Advanced -> Private SSH KnownHosts file' (or set" + echo "** Warning: SSVNC_KNOWN_HOSTS_FILE directly) to a per-connection known hosts" + echo "** Warning: file. That file holds the 'localhost' cert for this specific" + echo "** Warning: connection. This yields a both secure and convenient solution." + echo "" +} + +space_expand() { + str=`echo "$1" | sed -e 's/%SPACE/ /g' -e 's/%TAB/\t/g'` + echo "$str" +} + +# 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 + # XXX fix ipv6 ip adder here and below. + 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 + # XXX no reverse forever PPROXY_LOOP_THYSELF ... + $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 + if echo "$ssh_host1" | grep '%' > /dev/null; then + uath=`space_expand "$ssh_host1"` + else + uath="$ssh_host1" + fi + echo "$ssh -f -x $ssh_port1 $targ -e none $ssh_NHAFL $ukhf -L $proxport:$ssh_host2:$ssh_port2 \"$uath\" \"sleep 30\"" + echo "" + $ssh -f -x $ssh_port1 $targ -e none $ssh_NHAFL $ukhf -L $proxport:$ssh_host2:$ssh_port2 "$uath" "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 echo "$ssh_host" | grep '%' > /dev/null; then + uath=`space_expand "$ssh_host"` + else + uath="$ssh_host" + fi + if [ "X$SS_VNCVIEWER_SSH_ONLY" != "X" ]; then + echo "$ssh -x $ssh_port $targ $C $ssh_args \"$uath\" \"$info\"" + echo "" + $ssh -x $ssh_port $targ $C $ssh_args "$uath" "$ssh_cmd" + exit $? + + elif [ "X$SS_VNCVIEWER_NO_F" != "X" ]; then + echo "$ssh -x $ssh_port $targ $C $ssh_redir $ssh_args \"$uath\" \"$info\"" + echo "" + $ssh -x $ssh_port $targ $C $ssh_redir $ssh_args "$uath" "$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 "$uath" "sudo id; tty" + echo "" + fi + echo "$ssh -x -f $ssh_port $targ $C $ssh_redir $ssh_args \"$uath\" \"$info\"" + echo "" + $ssh -x -f $ssh_port $targ $C $ssh_redir $ssh_args "$uath" "$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 + lh6="" + if [ "X$SSVNC_PORT_IPV6" != "X" ]; then + lh6=1 + elif egrep 'Info: listening on IPv6 only|Info: listening only on IPv6' $tport > /dev/null; then + lh6=1 + fi + if [ "X$lh6" = "X1" ]; then + echo "set SOCKS5 localhost to ::1" 1>&2 + fi + rm -f $tport $tport2 + if [ "X$rsh" = "X1" ]; then + rsh_viewer "$@" + exit $? + fi + PPROXY_SOCKS=5 + if [ "X$SSVNC_SOCKS5" != "X" ]; then + PPROXY_SOCKS=5 + elif [ "X$SSVNC_SOCKS4" != "X" ]; then + PPROXY_SOCKS=1 + fi + export PPROXY_SOCKS + if [ "X$lh6" = "X" ]; then + host="$localhost" + else + host="::1" + fi + port="$PORT" + proxy="$localhost:$use" + + else + if [ "X$rsh" != "X1" ]; then + echo "$ssh -x -f $ssh_port $targ $C $ssh_redir $ssh_args \"$uath\" \"$info\"" + echo "" + $ssh -x -f $ssh_port $targ $C $ssh_redir $ssh_args "$uath" "$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 \"$uath\" 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 + if [ "X$SSVNC_EXTRA_COMMAND" != "X" ]; then + (sh -c "$SSVNC_EXTRA_COMMAND") & + echo "($SSVNC_EXTRA_COMMAND) &"; echo + fi + 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 + +if [ "X$showcert" = "X1" ]; then + if [ "X$have_uvnc_dsm_helper_showcert" = "X1" ]; then + : + elif [ "X$SSVNC_NO_IPV6_PROXY" != "X" ]; then + : + elif [ "X$ipv6" = "X1" -a "X$proxy" = "X" ]; then + proxy="ipv6://$host:$port" + fi +fi + +if [ "X$direct_connect" != "X" -a "X$STUNNEL_LISTEN" != "X" ]; then + proxy=reverse_direct +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 [ "X$have_uvnc_dsm_helper_showcert" = "X1" ]; then + : + elif 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 + if type host > /dev/null 2>/dev/null; then + host $host >/dev/null 2>&1 + host $host >/dev/null 2>&1 + fi + timeout=15 + if [ "X$SSVNC_FETCH_TIMEOUT" != "X" ]; then + timeout=$SSVNC_FETCH_TIMEOUT + fi + if [ "X$have_uvnc_dsm_helper_showcert" = "X1" ]; then + if type pkill >/dev/null 2>&1; then + (sleep $timeout; if kill -0 $$; then pkill -TERM -f "ultravnc_dsm_helper.*$host.*$port"; fi) >/dev/null 2>&1 & + fi + ultravnc_dsm_helper showcert $host:$port 2>&1 + else + 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 + fi + 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 (<F>) { + 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 + if [ "X$proxy" = "Xreverse_direct" ]; then + PPROXY_LISTEN="$STUNNEL_LISTEN:`expr 5500 + $disp`" + PPROXY_DEST="$localhost:$use" + PPROXY_PROXY="ipv6://$localhost:$use" # not always ipv6.. + export PPROXY_LISTEN PPROXY_DEST PPROXY_PROXY + pps=1 + else + PPROXY_REVERSE="$localhost:$use" + export PPROXY_LISTEN + pps=3 + fi + if [ "X$SSVNC_LISTEN_ONCE" != "X1" ]; then + PPROXY_LOOP_THYSELF=`mytmp "/tmp/pproxy_loop_thyself.${RANDOM}.$$"` + export PPROXY_LOOP_THYSELF + pps=2 + fi + 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$SSVNC_EXTRA_COMMAND" != "X" ]; then + (sh -c "$SSVNC_EXTRA_COMMAND") & + echo "($SSVNC_EXTRA_COMMAND) &"; echo + 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 + if [ "X$SSVNC_LISTEN_ONCE" = "X1" ]; then + echo "NOTE: The ultravnc_dsm_helper only runs once. So after the first LISTEN" + echo " ends you must restart the Listening mode. You may also need to" + echo " Press Ctrl-C to stop the viewer and restart for another connection." + echo "" + fi + #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 + if [ "X$SSVNC_LISTEN_ONCE" = "X1" ]; then + $cmd & + dsm_pid=$! + else + while [ 1 ]; do $cmd; sleep 1; done & + dsm_pid=$! + fi + 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 + if [ "X$PPROXY_LOOP_THYSELF" != "X" ]; then + rm -f $PPROXY_LOOP_THYSELF + fi + 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" <<END +foreground = yes +pid = +client = yes +debug = $stunnel_debug +$ciphers +$STUNNEL_EXTRA_OPTS +$STUNNEL_EXTRA_OPTS_USER +$cert +$crl +$verify + +${stunnel_exec}[vnc_stunnel] +${stunnel_exec}accept = $localhost:$use +$connect +$STUNNEL_EXTRA_SVC_OPTS +$STUNNEL_EXTRA_SVC_OPTS_USER + +END + +else + # REVERSE case: + + stunnel_exec="" # doesn't work for listening. + + p2=`expr 5500 + $N` + connect="connect = $localhost:$p2" + 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. + + + hloc="" + if [ "X$use_ssh" = "X1" ]; then + hloc="$localhost:" + elif [ "X$STUNNEL_LISTEN" != "X" ]; then + hloc="$STUNNEL_LISTEN:" + fi + if echo "$proxy" | grep -i '^vencrypt:' > /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" <<END +foreground = yes +pid = +client = no +debug = $stunnel_debug +$ciphers +$STUNNEL_EXTRA_OPTS +$STUNNEL_EXTRA_OPTS_USER +$cert +$crl +$verify + +[vnc_stunnel] +accept = $hloc$port +$connect +$STUNNEL_EXTRA_SVC_OPTS +$STUNNEL_EXTRA_SVC_OPTS_USER + +END + +fi + +echo "" +echo "Using this stunnel configuration:" +echo "" +cat "$tmp_cfg" | uniq +echo "" +if egrep -i '^[ ]*(CApath|CAfile) =' "$tmp_cfg" > /dev/null ; then + : +else + echo "** WARNING: THE STUNNEL CONFIG HAS NO SERVER CERTIFICATE SPECIFIED **" + echo "** WARNING: (the CApath or CAfile stunnel option) THE VNC SERVER WILL **" + echo "** WARNING: NOT BE AUTHENTICATED. A MAN-IN-THE-MIDDLE ATTACK IS POSSIBLE **" + echo "" +fi +sleep 1 + +if [ "X$stunnel_exec" = "X" ]; then + echo "" + echo "Running stunnel:" + echo "$STUNNEL $tmp_cfg" + st=`echo "$STUNNEL" | awk '{print $1}'` + $st -help > /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$SSVNC_EXTRA_COMMAND" != "X" ]; then + (sh -c "$SSVNC_EXTRA_COMMAND") & + echo "($SSVNC_EXTRA_COMMAND) &"; echo +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}'` + IF=INADDR_ANY + if [ "X$STUNNEL_LISTEN" != "X" ]; then + IF=$STUNNEL_LISTEN + fi + PPROXY_VENCRYPT_REVERSE=1; export PPROXY_VENCRYPT_REVERSE + PPROXY_LISTEN="$IF:$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 + if [ "X$SSVNC_LISTEN_ONCE" != "X1" ]; then + PPROXY_LOOP_THYSELF=`mytmp "/tmp/pproxy_loop_thyself1.${RANDOM}.$$"` + export PPROXY_LOOP_THYSELF + PPROXY_LOOP_THYSELF0=$PPROXY_LOOP_THYSELF + 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; + if [ "X$SSVNC_LISTEN_ONCE" != "X1" ]; then + PPROXY_LOOP_THYSELF=`mytmp "/tmp/pproxy_loop_thyself2.${RANDOM}.$$"` + export PPROXY_LOOP_THYSELF + fi + $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 + + if [ "X$PPROXY_LOOP_THYSELF" != "X" ]; then + rm -f $PPROXY_LOOP_THYSELF + fi + if [ "X$PPROXY_LOOP_THYSELF0" != "X" ]; then + rm -f $PPROXY_LOOP_THYSELF0 + fi +fi + +sleep 1 |