Home | History | Annotate | Download | only in ssl
      1 #!/bin/sh
      2 #
      3 # ss_vncviewer:  wrapper for vncviewer to use an stunnel SSL tunnel
      4 #                or an SSH tunnel.
      5 #
      6 # Copyright (c) 2006-2009 by Karl J. Runge <runge (at] karlrunge.com>
      7 #
      8 # ss_vncviewer is free software; you can redistribute it and/or modify
      9 # it under the terms of the GNU General Public License as published by
     10 # the Free Software Foundation; either version 2 of the License, or (at
     11 # your option) any later version.
     12 # 
     13 # ss_vncviewer is distributed in the hope that it will be useful,
     14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16 # GNU General Public License for more details.
     17 # 
     18 # You should have received a copy of the GNU General Public License
     19 # along with ss_vncviewer; if not, write to the Free Software
     20 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
     21 # or see <http://www.gnu.org/licenses/>.
     22 # 
     23 # 
     24 # You must have stunnel(8) installed on the system and in your PATH
     25 # (however, see the -ssh option below, in which case you will need ssh(1)
     26 # installed)  Note: stunnel is usually installed in an "sbin" subdirectory.
     27 #
     28 # You should have "x11vnc -ssl ..." or "x11vnc -stunnel ..." 
     29 # already running as the VNC server on the remote machine.
     30 # (or use stunnel on the server side for any other VNC server)
     31 #
     32 #
     33 # Usage: ss_vncviewer [cert-args] host:display <vncviewer-args>
     34 #
     35 # e.g.:  ss_vncviewer snoopy:0
     36 #        ss_vncviewer snoopy:0 -encodings "copyrect tight zrle hextile"
     37 #
     38 # [cert-args] can be:
     39 #
     40 #	-verify /path/to/cacert.pem		
     41 #	-mycert /path/to/mycert.pem		
     42 #	-crl    /path/to/my_crl.pem  (or directory)
     43 #	-proxy  host:port
     44 #
     45 # -verify specifies a CA cert PEM file (or a self-signed one) for
     46 #         authenticating the VNC server.
     47 #
     48 # -mycert specifies this client's cert+key PEM file for the VNC server to
     49 #	  authenticate this client. 
     50 #
     51 # -proxy  try host:port as a Web proxy to use the CONNECT method
     52 #         to reach the VNC server (e.g. your firewall requires a proxy).
     53 #
     54 #         For the "double proxy" case use -proxy host1:port1,host2:port2
     55 #         (the first CONNECT is done through host1:port1 to host2:port2
     56 #         and then a 2nd CONNECT to the destination VNC server.)
     57 #
     58 #         Use socks://host:port, socks4://host:port, or socks5://host,port
     59 #         to force usage of a SOCKS proxy.  Also repeater://host:port and
     60 #         sslrepeater://host:port.
     61 #
     62 # -showcert  Only fetch the certificate using the 'openssl s_client'
     63 #            command (openssl(1) must in installed).  On ssvnc 1.0.27 and
     64 #            later the bundled command 'ultravnc_dsm_helper' is used.
     65 #
     66 #    See http://www.karlrunge.com/x11vnc/faq.html#faq-ssl-ca for details on
     67 #    SSL certificates with VNC.
     68 #
     69 # A few other args (not related to SSL and certs):
     70 #
     71 # -2nd    Run the vncviewer a 2nd time if the first connections fails.
     72 #
     73 # -ssh    Use ssh instead of stunnel SSL.  ssh(1) must be installed and you
     74 #         must be able to log into the remote machine via ssh.
     75 #
     76 #         In this case "host:display" may be of the form "user@host:display"
     77 #         where "user@host" is used for the ssh login (see ssh(1) manpage).
     78 #
     79 #         If -proxy is supplied it can be of the forms: "gwhost" "gwhost:port"
     80 #         "user@gwhost" or "user@gwhost:port".  "gwhost" is an incoming ssh 
     81 #         gateway machine (the VNC server is not running there), an ssh -L
     82 #         redir is used to "host" in "host:display" from "gwhost". Any "user@"
     83 #         part must be in the -proxy string (not in "host:display").
     84 #
     85 #         Under -proxy use "gwhost:port" if connecting to any ssh port
     86 #         other than the default (22).  (even for the non-gateway case,
     87 #         -proxy must be used to specify a non-standard ssh port)
     88 #
     89 #         A "double ssh" can be specified via a -proxy string with the two
     90 #         hosts separated by a comma:
     91 #
     92 #             [user1@]host1[:port1],[user2@]host2[:port2]
     93 #
     94 #         in which case a ssh to host1 and thru it via a -L redir a 2nd
     95 #         ssh is established to host2.  
     96 #
     97 #         Examples:
     98 #
     99 #         ss_vncviewer -ssh bob (at] bobs-home.net:0
    100 #         ss_vncviewer -ssh -sshcmd 'x11vnc -localhost' bob (at] bobs-home.net:0
    101 #
    102 #         ss_vncviewer -ssh -proxy fred (at] mygate.com:2022 mymachine:0
    103 #         ss_vncviewer -ssh -proxy bob (at] bobs-home.net:2222 localhost:0
    104 #
    105 #         ss_vncviewer -ssh -proxy fred@gw-host,fred@peecee localhost:0
    106 #
    107 # -sshcmd cmd   Run "cmd" via ssh instead of the default "sleep 15"
    108 #               e.g. -sshcmd 'x11vnc -display :0 -localhost -rfbport 5900'
    109 #
    110 # -sshargs "args"  pass "args" to the ssh process, e.g. -L/-R port redirs.
    111 #
    112 # -sshssl Tunnel the SSL connection thru a SSH connection.  The tunnel as
    113 #         under -ssh is set up and the SSL connection goes thru it.  Use
    114 #         this if you want to have and end-to-end SSL connection but must
    115 #         go thru a SSH gateway host (e.g. not the vnc server).  Or use
    116 #         this if you need to tunnel additional services via -R and -L 
    117 #         (see -sshargs above).
    118 #
    119 #         ss_vncviewer -sshssl -proxy fred (at] mygate.com mymachine:0
    120 #
    121 # -listen (or -reverse) set up a reverse connection.
    122 #
    123 # -alpha  turn on cursor alphablending hack if you are using the
    124 #         enhanced tightvnc vncviewer.
    125 #
    126 # -grab   turn on XGrabServer hack if you are using the enhanced tightvnc
    127 #         vncviewer (e.g. for fullscreen mode in some windowmanagers like
    128 #         fvwm that do not otherwise work in fullscreen mode)
    129 #
    130 #
    131 # set VNCVIEWERCMD to whatever vncviewer command you want to use.
    132 #
    133 VNCIPCMD=${VNCVIEWERCMD:-vncip}
    134 VNCVIEWERCMD=${VNCVIEWERCMD:-vncviewer}
    135 if [ "X$SSVNC_TURBOVNC" != "X" ]; then
    136 	if echo "$VNCVIEWERCMD" | grep '\.turbovnc' > /dev/null; then
    137 		:
    138 	else
    139 		if type "$VNCVIEWERCMD.turbovnc" > /dev/null 2>/dev/null; then
    140 			VNCVIEWERCMD="$VNCVIEWERCMD.turbovnc"
    141 		fi
    142 	fi
    143 fi
    144 #
    145 # Same for STUNNEL, e.g. set it to /path/to/stunnel or stunnel4, etc.
    146 #
    147 
    148 # turn on verbose debugging output
    149 if [ "X$SS_DEBUG" != "X" -a "X$SS_DEBUG" != "X0" ]; then
    150 	set -xv 
    151 fi
    152 
    153 PATH=$PATH:/usr/sbin:/usr/local/sbin:/dist/sbin; export PATH
    154 
    155 localhost="localhost"
    156 if uname | grep Darwin >/dev/null; then
    157 	localhost="127.0.0.1"
    158 fi
    159 
    160 # work out which stunnel to use (debian installs as stunnel4)
    161 stunnel_set_here=""
    162 if [ "X$STUNNEL" = "X" ]; then
    163 	check_stunnel=1
    164 	if [ "X$SSVNC_BASEDIRNAME" != "X" ]; then
    165 		if [ -x "$SSVNC_BASEDIRNAME/stunnel" ]; then
    166 			type stunnel > /dev/null 2>&1
    167 			if [ $? = 0 ]; then
    168 				# found ours
    169 				STUNNEL=stunnel
    170 				check_stunnel=0
    171 			fi
    172 		fi
    173 	fi
    174 	if [ "X$check_stunnel" = "X1" ]; then
    175 		type stunnel4 > /dev/null 2>&1
    176 		if [ $? = 0 ]; then
    177 			STUNNEL=stunnel4
    178 		else
    179 			STUNNEL=stunnel
    180 		fi
    181 	fi
    182 	stunnel_set_here=1
    183 fi
    184 
    185 help() {
    186 	tail -n +2 "$0" | sed -e '/^$/ q'
    187 }
    188 
    189 secondtry=""
    190 gotalpha=""
    191 use_ssh=""
    192 use_sshssl=""
    193 direct_connect=""
    194 ssh_sleep=15
    195 
    196 # sleep longer in -listen mode:
    197 if echo "$*" | grep '.*-listen' > /dev/null; then
    198 	ssh_sleep=1800
    199 fi
    200 
    201 
    202 ssh_cmd=""
    203 # env override of ssh_cmd:
    204 if [ "X$SS_VNCVIEWER_SSH_CMD" != "X" ]; then
    205 	ssh_cmd="$SS_VNCVIEWER_SSH_CMD"
    206 fi
    207 
    208 ssh_args=""
    209 showcert=""
    210 reverse=""
    211 
    212 ciphers=""
    213 anondh="ALL:RC4+RSA:+SSLv2:@STRENGTH"
    214 anondh_set=""
    215 stunnel_debug="6"
    216 if [ "X$SS_DEBUG" != "X" -o "X$SSVNC_VENCRYPT_DEBUG" != "X" -o "X$SSVNC_STUNNEL_DEBUG" != "X" ]; then
    217 	stunnel_debug="7"
    218 fi
    219 
    220 if [ "X$1" = "X-viewerflavor" ]; then
    221 	# special case, try to guess which viewer:
    222 	#
    223 	if echo "$VNCVIEWERCMD" | egrep -i '^(xmessage|sleep )' > /dev/null; then
    224 		echo "unknown"
    225 		exit 0
    226 	fi
    227 	if echo "$VNCVIEWERCMD" | grep -i chicken.of > /dev/null; then
    228 		echo "cotvnc"
    229 		exit 0
    230 	fi
    231 	if echo "$VNCVIEWERCMD" | grep -i ultra > /dev/null; then
    232 		echo "ultravnc"
    233 		exit 0
    234 	fi
    235 	# OK, run it for help output...
    236 	str=`$VNCVIEWERCMD -h 2>&1 | head -n 5`
    237 	if echo "$str" | grep -i 'TightVNC.viewer' > /dev/null; then
    238 		echo "tightvnc"
    239 	elif echo "$str" | grep -i 'VNC viewer version 3' > /dev/null; then
    240 		echo "realvnc3"
    241 	elif echo "$str" | grep -i 'VNC viewer .*Edition 4' > /dev/null; then
    242 		echo "realvnc4"
    243 	elif echo "$str" | grep -i 'RealVNC.Ltd' > /dev/null; then
    244 		echo "realvnc4"
    245 	else
    246 		echo "unknown"
    247 	fi
    248 	exit 0
    249 fi
    250 if [ "X$1" = "X-viewerhelp" ]; then
    251 	$VNCVIEWERCMD -h 2>&1
    252 	exit 0
    253 fi
    254 
    255 # grab our cmdline options:
    256 while [ "X$1" != "X" ]
    257 do
    258     case $1 in 
    259 	"-verify")	shift; verify="$1"
    260                 ;;
    261 	"-mycert")	shift; mycert="$1"
    262                 ;;
    263 	"-crl")		shift; crl="$1"
    264                 ;;
    265 	"-proxy")	shift; proxy="$1"
    266                 ;;
    267 	"-ssh")		use_ssh=1
    268                 ;;
    269 	"-sshssl")	use_ssh=1
    270 			use_sshssl=1
    271                 ;;
    272 	"-sshcmd")	shift; ssh_cmd="$1"
    273                 ;;
    274 	"-sshargs")	shift; ssh_args="$1"
    275                 ;;
    276 	"-anondh")	ciphers="ciphers=$anondh"
    277 			ULTRAVNC_DSM_HELPER_SHOWCERT_ADH=1
    278 			export ULTRAVNC_DSM_HELPER_SHOWCERT_ADH
    279 			anondh_set=1
    280                 ;;
    281 	"-ciphers")	shift; ciphers="ciphers=$1"
    282                 ;;
    283 	"-alpha")	gotalpha=1
    284                 ;;
    285 	"-showcert")	showcert=1
    286                 ;;
    287 	"-listen")	reverse=1
    288                 ;;
    289 	"-reverse")	reverse=1
    290                 ;;
    291 	"-2nd")		secondtry=1
    292                 ;;
    293 	"-grab")	VNCVIEWER_GRAB_SERVER=1; export VNCVIEWER_GRAB_SERVER
    294                 ;;
    295 	"-x11cursor")	VNCVIEWER_X11CURSOR=1; export VNCVIEWER_X11CURSOR
    296                 ;;
    297 	"-rawlocal")	VNCVIEWER_RAWLOCAL=1; export VNCVIEWER_RAWLOCAL
    298                 ;;
    299 	"-scale")	shift; SSVNC_SCALE="$1"; export SSVNC_SCALE
    300                 ;;
    301 	"-onelisten")	SSVNC_LISTEN_ONCE=1; export SSVNC_LISTEN_ONCE
    302                 ;;
    303 	"-sendclipboard")	VNCVIEWER_SEND_CLIPBOARD=1; export VNCVIEWER_SEND_CLIPBOARD
    304                 ;;
    305 	"-sendalways")	VNCVIEWER_SEND_ALWAYS=1; export VNCVIEWER_SEND_ALWAYS
    306                 ;;
    307 	"-recvtext")	shift; VNCVIEWER_RECV_TEXT="$1"; export VNCVIEWER_RECV_TEXT
    308                 ;;
    309 	"-escape")	shift; VNCVIEWER_ESCAPE="$1"; export VNCVIEWER_ESCAPE
    310                 ;;
    311 	"-ssvnc_encodings")	shift; VNCVIEWER_ENCODINGS="$1"; export VNCVIEWER_ENCODINGS
    312                 ;;
    313 	"-ssvnc_extra_opts")	shift; VNCVIEWERCMD_EXTRA_OPTS="$1"; export VNCVIEWERCMD_EXTRA_OPTS
    314                 ;;
    315 	"-rfbversion")	shift; VNCVIEWER_RFBVERSION="$1"; export VNCVIEWER_RFBVERSION
    316                 ;;
    317 	"-nobell")	VNCVIEWER_NOBELL=1; export VNCVIEWER_NOBELL
    318                 ;;
    319 	"-popupfix")	VNCVIEWER_POPUP_FIX=1; export VNCVIEWER_POPUP_FIX
    320                 ;;
    321 	"-realvnc4")	VNCVIEWER_IS_REALVNC4=1; export VNCVIEWER_IS_REALVNC4
    322                 ;;
    323 	"-h"*)	help; exit 0
    324                 ;;
    325 	"--h"*)	help; exit 0
    326                 ;;
    327 	*)	break
    328                 ;;
    329     esac
    330     shift
    331 done
    332 
    333 # maxconn is something we added to stunnel, this disables it:
    334 if [ "X$SS_VNCVIEWER_NO_MAXCONN" != "X" ]; then
    335 	STUNNEL_EXTRA_OPTS=`echo "$STUNNEL_EXTRA_OPTS" | sed -e 's/maxconn/#maxconn/'`
    336 elif echo "$VNCVIEWERCMD" | egrep -i '^(xmessage|sleep )' > /dev/null; then
    337 	STUNNEL_EXTRA_OPTS=`echo "$STUNNEL_EXTRA_OPTS" | sed -e 's/maxconn/#maxconn/'`
    338 elif [ "X$reverse" != "X" ]; then
    339 	STUNNEL_EXTRA_OPTS=`echo "$STUNNEL_EXTRA_OPTS" | sed -e 's/maxconn/#maxconn/'`
    340 else
    341 	# new way (our patches).  other than the above, we set these:
    342 	if [ "X$SKIP_STUNNEL_ONCE" = "X" ]; then
    343 		STUNNEL_ONCE=1; export STUNNEL_ONCE
    344 	fi
    345 	if [ "X$SKIP_STUNNEL_MAX_CLIENTS" = "X" ]; then
    346 		STUNNEL_MAX_CLIENTS=1; export STUNNEL_MAX_CLIENTS
    347 	fi
    348 fi
    349 # always set this one:
    350 if [ "X$SKIP_STUNNEL_NO_SYSLOG" = "X" ]; then
    351 	STUNNEL_NO_SYSLOG=1; export STUNNEL_NO_SYSLOG
    352 fi
    353 
    354 # this is the -t ssh option (gives better keyboard response thru SSH tunnel)
    355 targ="-t"
    356 if [ "X$SS_VNCVIEWER_NO_T" != "X" ]; then
    357 	targ=""
    358 fi
    359 
    360 # set the alpha blending env. hack: 
    361 if [ "X$gotalpha" = "X1" ]; then
    362 	VNCVIEWER_ALPHABLEND=1
    363 	export VNCVIEWER_ALPHABLEND
    364 else
    365 	NO_ALPHABLEND=1
    366 	export NO_ALPHABLEND
    367 fi
    368 
    369 if [ "X$reverse" != "X" ]; then
    370 	ssh_sleep=1800
    371 	if [ "X$proxy" != "X" ]; then
    372 		# check proxy usage under reverse connection:
    373 		if [ "X$use_ssh" = "X" -a "X$use_sshssl" = "X" ]; then
    374 			echo ""
    375 			if echo "$proxy" | egrep -i "(repeater|vencrypt)://" > /dev/null; then
    376 				:
    377 			else
    378 				echo "*Warning*: SSL -listen and a Web proxy does not make sense."
    379 				sleep 2
    380 			fi
    381 		elif echo "$proxy" | grep "," > /dev/null; then
    382 			:
    383 		else
    384 			echo ""
    385 			echo "*Warning*: -listen and a single proxy/gateway does not make sense."
    386 			sleep 2
    387 		fi
    388 
    389 		# we now try to PPROXY_LOOP_THYSELF, set this var to disable that.
    390 		#SSVNC_LISTEN_ONCE=1; export SSVNC_LISTEN_ONCE
    391 	fi
    392 fi
    393 if [ "X$ssh_cmd" = "X" ]; then
    394 	# if no remote ssh cmd, sleep a bit:
    395 	ssh_cmd="sleep $ssh_sleep"
    396 fi
    397 
    398 # this should be a host:display:
    399 #
    400 orig="$1"
    401 shift
    402 
    403 dL="-L"
    404 if uname -sr | egrep 'SunOS 5\.[5-8]' > /dev/null; then
    405 	dL="-h"
    406 fi
    407 
    408 have_uvnc_dsm_helper_showcert=""
    409 if [ "X$showcert" = "X1" -a "X$SSVNC_USE_S_CLIENT" = "X" -a "X$reverse" = "X" ]; then
    410 	if type ultravnc_dsm_helper >/dev/null 2>&1; then
    411 		if ultravnc_dsm_helper -help 2>&1 | grep -w showcert >/dev/null; then
    412 			have_uvnc_dsm_helper_showcert=1
    413 		fi
    414 	fi
    415 fi
    416 have_uvnc_dsm_helper_ipv6=""
    417 if [ "X$SSVNC_ULTRA_DSM" != "X" ]; then
    418 	if type ultravnc_dsm_helper >/dev/null 2>&1; then
    419 		if ultravnc_dsm_helper -help 2>&1 | grep -iw ipv6 >/dev/null; then
    420 			have_uvnc_dsm_helper_ipv6=1
    421 		fi
    422 	fi
    423 fi
    424 
    425 rchk() {
    426 	# a kludge to set $RANDOM if we are not bash:
    427 	if [ "X$BASH_VERSION" = "X" ]; then
    428 		RANDOM=`date +%S``sh -c 'echo $$'``ps -elf 2>&1 | sum 2>&1 | awk '{print $1}'`
    429 	fi
    430 }
    431 rchk
    432 
    433 # a portable, but not absolutely safe, tmp file creator
    434 mytmp() {
    435 	tf=$1
    436 	if type mktemp > /dev/null 2>&1; then
    437 		# if we have mktemp(1), use it:
    438 		tf2="$tf.XXXXXX"
    439 		tf2=`mktemp "$tf2"`
    440 		if [ "X$tf2" != "X" -a -f "$tf2" ]; then
    441 			if [ "X$DEBUG_MKTEMP" != "X" ]; then
    442 				echo "mytmp-mktemp: $tf2" 1>&2
    443 			fi
    444 			echo "$tf2"
    445 			return
    446 		fi
    447 	fi
    448 	# fallback to multiple cmds:
    449 	rm -rf "$tf" || exit 1
    450 	if [ -d "$tf" ]; then
    451 		echo "tmp file $tf still exists as a directory."
    452 		exit 1
    453 	elif [ $dL "$tf" ]; then
    454 		echo "tmp file $tf still exists as a symlink."
    455 		exit 1
    456 	elif [ -f "$tf" ]; then
    457 		echo "tmp file $tf still exists."
    458 		exit 1
    459 	fi
    460 	touch "$tf" || exit 1
    461 	chmod 600 "$tf" || exit 1
    462 	rchk
    463 	if [ "X$DEBUG_MKTEMP" != "X" ]; then
    464 		echo "mytmp-touch: $tf" 1>&2
    465 	fi
    466 	echo "$tf"
    467 }
    468 
    469 # set up special case of ultravnc single click III mode:
    470 if echo "$proxy" | egrep "^sslrepeater://" > /dev/null; then
    471 	pstr=`echo "$proxy" | sed -e 's,sslrepeater://,,'`
    472 	pstr1=`echo "$pstr" | sed -e 's/+.*$//'`
    473 	pstr2=`echo "$pstr" | sed -e 's/^[^+]*+//'`
    474 	SSVNC_REPEATER="SCIII=$pstr2"; export SSVNC_REPEATER
    475 	orig=$pstr1
    476 	echo
    477 	echo "reset: SSVNC_REPEATER=$SSVNC_REPEATER orig=$orig proxy=''"
    478 	proxy=""
    479 fi
    480 if echo "$proxy" | egrep "vencrypt://" > /dev/null; then
    481 	vtmp="/tmp/ss_handshake${RANDOM}.$$.txt"
    482 	vtmp=`mytmp "$vtmp"`
    483 	SSVNC_PREDIGESTED_HANDSHAKE="$vtmp"
    484 	export SSVNC_PREDIGESTED_HANDSHAKE
    485 	if [ "X$SSVNC_USE_OURS" = "X" ]; then
    486 		NEED_VENCRYPT_VIEWER_BRIDGE=1
    487 	fi
    488 fi
    489 if [ "X$SSVNC_USE_OURS" = "X" ]; then
    490 	VNCVIEWERCMD_EXTRA_OPTS=""
    491 fi
    492 
    493 
    494 # check -ssh and -mycert/-verify conflict:
    495 if [ "X$use_ssh" = "X1" -a "X$use_sshssl" = "X" ]; then
    496 	if [ "X$mycert" != "X" -o "X$verify" != "X" ]; then
    497 		echo "-mycert and -verify cannot be used in -ssh mode" 
    498 		exit 1
    499 	fi
    500 fi
    501 
    502 # direct mode Vnc:// means show no warnings.
    503 # direct mode vnc:// will show warnings.
    504 if echo "$orig" | grep '^V[Nn][Cc]://' > /dev/null; then
    505 	SSVNC_NO_ENC_WARN=1
    506 	export SSVNC_NO_ENC_WARN
    507 	orig=`echo "$orig" | sed -e 's/^...:/vnc:/'`
    508 fi
    509 
    510 # interprest the pseudo URL proto:// strings:
    511 if echo "$orig" | grep '^vnc://' > /dev/null; then
    512 	orig=`echo "$orig" | sed -e 's,vnc://,,'`
    513 	verify=""
    514 	mycert=""
    515 	crl=""
    516 	use_ssh=""
    517 	use_sshssl=""
    518 	direct_connect=1
    519 elif echo "$orig" | grep '^vncs://' > /dev/null; then
    520 	orig=`echo "$orig" | sed -e 's,vncs://,,'`
    521 elif echo "$orig" | grep '^vncssl://' > /dev/null; then
    522 	orig=`echo "$orig" | sed -e 's,vncssl://,,'`
    523 elif echo "$orig" | grep '^vnc+ssl://' > /dev/null; then
    524 	orig=`echo "$orig" | sed -e 's,vnc.ssl://,,'`
    525 elif echo "$orig" | grep '^vncssh://' > /dev/null; then
    526 	orig=`echo "$orig" | sed -e 's,vncssh://,,'`
    527 	use_ssh=1
    528 elif echo "$orig" | grep '^vnc+ssh://' > /dev/null; then
    529 	orig=`echo "$orig" | sed -e 's,vnc.ssh://,,'`
    530 	use_ssh=1
    531 fi
    532 
    533 if [ "X$SSVNC_ULTRA_DSM" != "X" ]; then
    534         verify=""
    535         mycert=""
    536         crl=""
    537         use_ssh=""
    538         use_sshssl=""
    539         direct_connect=1
    540 	if echo "$SSVNC_ULTRA_DSM" | grep 'noultra:' > /dev/null; then
    541 		SSVNC_NO_ULTRA_DSM=1; export SSVNC_NO_ULTRA_DSM
    542 	fi
    543 fi
    544 
    545 # rsh mode is an internal/secret thing only I use.
    546 rsh=""
    547 if echo "$orig" | grep '^rsh://' > /dev/null; then
    548 	use_ssh=1
    549 	rsh=1
    550 	orig=`echo "$orig" | sed -e 's,rsh://,,'`
    551 elif echo "$orig" | grep '^rsh:' > /dev/null; then
    552 	use_ssh=1
    553 	rsh=1
    554 	orig=`echo "$orig" | sed -e 's,rsh:,,'`
    555 fi
    556 
    557 # play around with host:display port:
    558 if echo "$orig" | grep ':[0-9][0-9]*$' > /dev/null; then
    559 	:
    560 else
    561 	# add or assume :0 if no ':'
    562 	if [ "X$reverse" = "X" ]; then
    563 		orig="$orig:0"
    564 	elif [ "X$orig" = "X" ]; then
    565 		orig=":0"
    566 	fi
    567 fi
    568 
    569 # extract host and disp number:
    570 
    571 # try to see if it is ipv6 address:
    572 ipv6=0
    573 if echo "$orig" | grep '\[' > /dev/null; then
    574 	# ipv6 [fe80::219:dbff:fee5:3f92%eth1]:5900
    575 	host=`echo "$orig" | sed -e 's/\].*$//' -e 's/\[//'`
    576 	disp=`echo "$orig" | sed -e 's/^.*\]://'`
    577 	ipv6=1
    578 elif echo "$orig" | grep ':..*:' > /dev/null; then
    579 	# ipv6 fe80::219:dbff:fee5:3f92%eth1:5900
    580 	host=`echo "$orig" | sed -e 's/:[^:]*$//'`
    581 	disp=`echo "$orig" | sed -e 's/^.*://'`
    582 	ipv6=1
    583 else
    584 	# regular host:port
    585 	host=`echo "$orig" | awk -F: '{print $1}'`
    586 	disp=`echo "$orig" | awk -F: '{print $2}'`
    587 fi
    588 
    589 if [ "X$reverse" != "X" -a "X$STUNNEL_LISTEN" = "X" -a "X$host" != "X" ]; then
    590 	STUNNEL_LISTEN=$host
    591 	echo "set STUNNEL_LISTEN=$STUNNEL_LISTEN"
    592 fi
    593 
    594 if [ "X$host" = "X" ]; then
    595 	host=$localhost
    596 fi
    597 
    598 if [ "X$SSVNC_IPV6" = "X0" ]; then
    599 	# disable checking for it.
    600 	ipv6=0
    601 #elif [ "X$reverse" != "X" -a "X$ipv6" = "X1" ]; then
    602 #	ipv6=0
    603 elif [ "X$ipv6" = "X1" ]; then
    604 	:
    605 elif echo "$host" | grep '^[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$' > /dev/null; then
    606 	:
    607 else
    608 	# regular hostname, can't be sure...
    609 	gout=""
    610 	if type getent > /dev/null 2>/dev/null; then
    611 		gout=`getent hosts "$host" 2>/dev/null`
    612 	fi
    613 	if echo "$gout" | grep ':.*:' > /dev/null; then
    614 		if echo "$gout" | grep '^[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$' > /dev/null; then
    615 			:
    616 		else
    617 			echo "ipv6: "`echo "$gout" | grep ':.*:' | head -n 1`
    618 			ipv6=1
    619 		fi
    620 	fi
    621 	if [ "X$ipv6" = "X0" ]; then
    622 		hout=""
    623 		if type host > /dev/null 2>/dev/null; then
    624 			host "$host" >/dev/null 2>&1
    625 			host "$host" >/dev/null 2>&1
    626 			hout=`host "$host" 2>/dev/null`
    627 		fi
    628 		if echo "$hout" | grep -i 'has ipv6 address' > /dev/null; then
    629 			if echo "$hout" | grep -i 'has address' > /dev/null; then
    630 				:
    631 			else
    632 				echo "ipv6: "`echo "$hout" | grep -i 'has ipv6 address' | head -n 1`
    633 				ipv6=1
    634 			fi
    635 		fi
    636 	fi
    637 	if [ "X$ipv6" = "X0" ]; then
    638 		dout=""
    639 		if type dig > /dev/null 2>/dev/null; then
    640 		dout=`dig -t any "$host" 2>/dev/null`
    641 		fi
    642 		if echo "$dout" | grep -i "^$host" | grep '[ 	]AAAA[ 	]' > /dev/null; then
    643 			if echo "$dout" | grep -i "^$host" | grep '[ 	]A[ 	]' > /dev/null; then
    644 				:
    645 			else
    646 				echo "ipv6: "`echo "$dout" | grep -i '[ 	]AAAA[ 	]' | head -n 1`
    647 				ipv6=1
    648 			fi
    649 		fi
    650 	fi
    651 	if [ "X$ipv6" = "X0" ]; then
    652 		sout=`env LOOKUP="$host" \
    653 		      perl -e '	eval {use Socket};  exit 0 if $@;
    654 				eval {use Socket6}; exit 0 if $@;
    655 				@res = getaddrinfo($ENV{LOOKUP}, "daytime", AF_UNSPEC, SOCK_STREAM);
    656 				$ipv4 = 0;
    657 				$ipv6 = 0;
    658 				$ip6 = "";
    659 				while (scalar(@res) >= 5) {
    660 					($family, $socktype, $proto, $saddr, $canon, @res) = @res;
    661 					$ipv4 = 1 if $family == AF_INET;
    662 					$ipv6 = 1 if $family == AF_INET6;
    663 					if ($family == AF_INET6 && $ip6 eq "") {
    664 						my ($host, $port) = getnameinfo($saddr, NI_NUMERICHOST | NI_NUMERICSERV);
    665 						$ip6 = $host;
    666 					}
    667 				}
    668 				if (! $ipv4 && $ipv6) {
    669 					print "AF_INET6_ONLY: $ENV{LOOKUP}: $ip6\n";
    670 				}
    671 				exit 0;
    672 			' 2>/dev/null`
    673 		if echo "$sout" | grep AF_INET6_ONLY > /dev/null; then
    674 			echo "$sout"
    675 			ipv6=1
    676 		fi
    677 	fi
    678 fi
    679 if [ "X$ipv6" = "X1" ]; then
    680 	echo "ipv6: addr=$host disp=$disp"
    681 fi
    682 if [ "X$disp" = "X" ]; then
    683 	port=""	# probably -listen mode.
    684 elif [ $disp -lt 0 ]; then
    685 	# negative means use |n| without question:
    686 	port=`expr 0 - $disp`
    687 elif [ $disp -lt 200 ]; then
    688 	# less than 200 means 5900+n
    689 	if [ "X$reverse" = "X" ]; then
    690 		port=`expr $disp + 5900`
    691 	else
    692 		port=`expr $disp + 5500`
    693 	fi
    694 else
    695 	# otherwise use the number directly, e.g. 443, 2345
    696 	port=$disp
    697 fi
    698 
    699 if [ "X$ipv6" = "X1" -a "X$direct_connect" = "X1" ]; then
    700 	if [ "X$proxy" = "X" -a "X$reverse" = "X" ]; then
    701 		if [ "X$SSVNC_ULTRA_DSM" != "X" -a "X$have_uvnc_dsm_helper_ipv6" = "X1" ]; then
    702 			:
    703 		elif [ "X$SSVNC_NO_IPV6_PROXY" != "X" ]; then
    704 			:
    705 		elif [ "X$SSVNC_NO_IPV6_PROXY_DIRECT" != "X" ]; then
    706 			:
    707 		elif [ "X$SSVNC_USE_OURS" = "X1" ]; then
    708 			# requires 1.0.27 and later ssvncviewer binary
    709 			:
    710 		else
    711 			proxy="ipv6://$host:$port"
    712 			echo "direct connect: set proxy=$proxy"
    713 		fi
    714 	fi
    715 fi
    716 
    717 # (possibly) tell the vncviewer to only listen on lo: 
    718 if [ "X$reverse" != "X" ]; then
    719 	if [ "X$direct_connect" = "X" -o "X$proxy" != "X" -o "X$STUNNEL_LISTEN" != "X" ]; then
    720 		VNCVIEWER_LISTEN_LOCALHOST=1
    721 		export VNCVIEWER_LISTEN_LOCALHOST
    722 	fi
    723 fi
    724 
    725 # try to find an open listening port via netstat(1):
    726 inuse=""
    727 if uname | grep Linux > /dev/null; then
    728 	inuse=`netstat -ant | egrep 'LISTEN|WAIT|ESTABLISH|CLOSE' | awk '{print $4}' | sed 's/^.*://'`
    729 elif uname | grep SunOS > /dev/null; then
    730 	inuse=`netstat -an -f inet -P tcp | egrep 'LISTEN|WAIT|ESTABLISH|CLOSE' | awk '{print $1}' | sed 's/^.*\.//'`
    731 elif uname | egrep -i 'bsd|darwin' > /dev/null; then
    732 	inuse=`netstat -ant -f inet | egrep 'LISTEN|WAIT|ESTABLISH|CLOSE' | awk '{print $4}' | sed 's/^.*\.//'`
    733 # add others...
    734 fi
    735 
    736 # this is a crude attempt for unique ports tags, etc.
    737 date_sec=`date +%S`
    738 
    739 # these are special cases of no vnc, e.g. sleep or xmessage.
    740 # these are for using ssvnc as a general port redirector.
    741 if echo "$VNCVIEWERCMD" | grep '^sleep[ 	][ 	]*[0-9][0-9]*' > /dev/null; then
    742 	if [ "X$SS_VNCVIEWER_LISTEN_PORT" = "X" ]; then
    743 		p=`echo "$VNCVIEWERCMD" | awk '{print $3}'`
    744 		if [ "X$p" != "X" ]; then
    745 			SS_VNCVIEWER_LISTEN_PORT=$p
    746 		fi
    747 	fi
    748 	p2=`echo "$VNCVIEWERCMD" | awk '{print $2}'`
    749 	VNCVIEWERCMD="eval sleep $p2; echo Local "
    750 elif echo "$VNCVIEWERCMD" | grep '^xmessage[ 	][ 	]*[0-9][0-9]*' > /dev/null; then
    751 	if [ "X$SS_VNCVIEWER_LISTEN_PORT" = "X" ]; then
    752 		p=`echo "$VNCVIEWERCMD" | awk '{print $2}'`
    753 		SS_VNCVIEWER_LISTEN_PORT=$p
    754 	fi
    755 fi
    756 
    757 # utility to find a free port to listen on.
    758 findfree() {
    759 	try0=$1
    760 	try=$try0
    761 	use0=""
    762 
    763 	if [ "X$SS_VNCVIEWER_LISTEN_PORT" != "X" ]; then
    764 		echo "$SS_VNCVIEWER_LISTEN_PORT"
    765 		return	
    766 	fi
    767 	if [ $try -ge 6000 ]; then
    768 		fmax=`expr $try + 1000`
    769 	else
    770 		fmax=6000
    771 	fi
    772 
    773 	while [ $try -lt $fmax ]
    774 	do
    775 		if [ "X$inuse" = "X" ]; then
    776 			break
    777 		fi
    778 		if echo "$inuse" | grep -w $try > /dev/null; then
    779 			:
    780 		else
    781 			use0=$try
    782 			break
    783 		fi
    784 		try=`expr $try + 1`
    785 	done
    786 	if [ "X$use0" = "X" ]; then
    787 		use0=`expr $date_sec + $try0`
    788 	fi
    789 
    790 	echo $use0
    791 }
    792 
    793 # utility for exiting; kills some helper processes,
    794 # removes files, etc.
    795 final() {
    796 	echo ""
    797 	if [ "X$tmp_cfg" != "X" ]; then
    798 		rm -f $tmp_cfg
    799 	fi
    800 	if [ "X$SS_VNCVIEWER_RM" != "X" ]; then
    801 		rm -f $SS_VNCVIEWER_RM 2>/dev/null
    802 	fi
    803 	if [ "X$tcert" != "X" ]; then
    804 		rm -f $tcert
    805 	fi
    806 	if [ "X$pssh" != "X" ]; then
    807 		echo "Terminating background ssh process"
    808 		echo kill -TERM "$pssh"
    809 		kill -TERM "$pssh" 2>/dev/null
    810 		sleep 1
    811 		kill -KILL "$pssh" 2>/dev/null
    812 		pssh=""
    813 	fi
    814 	if [ "X$stunnel_pid" != "X" ]; then
    815 		echo "Terminating background stunnel process"
    816 		echo kill -TERM "$stunnel_pid"
    817 		kill -TERM "$stunnel_pid" 2>/dev/null
    818 		sleep 1
    819 		kill -KILL "$stunnel_pid" 2>/dev/null
    820 		stunnel_pid=""
    821 	fi
    822 	if [ "X$dsm_pid" != "X" ]; then
    823 		echo "Terminating background ultravnc_dsm_helper process"
    824 		echo kill -TERM "$dsm_pid"
    825 		kill -TERM "$dsm_pid" 2>/dev/null
    826 		sleep 1
    827 		kill -KILL "$dsm_pid" 2>/dev/null
    828 		stunnel_pid=""
    829 	fi
    830 	if [ "X$tail_pid" != "X" ]; then
    831 		kill -TERM $tail_pid
    832 	fi
    833 	if [ "X$tail_pid2" != "X" ]; then
    834 		kill -TERM $tail_pid2
    835 	fi
    836 }
    837 
    838 if [ "X$reverse" = "X" ]; then
    839 	# normal connections try 5930-5999:
    840 	if [ "X$showcert" = "X" ]; then
    841 		use=`findfree 5930`
    842 	else
    843 		# move away from normal place for (possibly many) -showcert
    844 		pstart=`date +%S`
    845 		pstart=`expr 6130 + $pstart + $pstart`
    846 		use=`findfree $pstart`
    847 	fi
    848 	if [ $use -ge 5900 ]; then
    849 		N=`expr $use - 5900`
    850 	else
    851 		N=$use
    852 	fi
    853 else
    854 	# reverse connections:
    855 	p2=`expr $port + 30`
    856 	use=`findfree $p2`
    857 	if [ $use -ge 5500 ]; then
    858 		N=`expr $use - 5500`
    859 	else
    860 		N=$use
    861 	fi
    862 fi
    863 
    864 # this is for my special use of ss_vncip -> vncip viewer.
    865 if echo "$0" | grep vncip > /dev/null; then
    866 	VNCVIEWERCMD="$VNCIPCMD"
    867 fi
    868 
    869 if echo "$VNCVIEWERCMD" | egrep -i '^(xmessage|sleep )' > /dev/null; then
    870 	:
    871 elif [ "X$VNCVIEWERCMD_EXTRA_OPTS" != "X" ]; then
    872 	VNCVIEWERCMD="$VNCVIEWERCMD $VNCVIEWERCMD_EXTRA_OPTS"
    873 fi
    874 
    875 # trick for the undocumented rsh://host:port method.
    876 rsh_setup() {
    877 	if echo "$ssh_host" | grep '@' > /dev/null; then
    878 		ul=`echo "$ssh_host" | awk -F@ '{print $1}'`
    879 		ul="-l $ul"
    880 		ssh_host=`echo "$ssh_host" | awk -F@ '{print $2}'`
    881 	else
    882 		ul=""
    883 	fi
    884 	ssh_cmd=`echo "$ssh_cmd" | sed -e 's/ -localhost/ /g'`
    885 }
    886 
    887 # trick for the undocumented rsh://host:port method.
    888 rsh_viewer() {
    889 	trap "final" 0 2 15
    890 	if [ "X$PORT" = "X" ]; then
    891 		exit 1
    892 	elif [ $PORT -ge 5900 ]; then
    893 		vdpy=`expr $PORT - 5900`
    894 	else
    895 		vdpy=":$PORT"
    896 	fi
    897 	stty sane
    898 	echo "$VNCVIEWERCMD" "$@" $ssh_host:$vdpy
    899 	echo ""
    900 	$VNCVIEWERCMD "$@" $ssh_host:$vdpy
    901 	if [ $? != 0 ]; then
    902 		sleep 2
    903 		$VNCVIEWERCMD "$@" $ssh_host:$vdpy
    904 	fi
    905 }
    906 
    907 check_perl() {
    908 	if type "$1" > /dev/null 2>&1; then
    909 		:
    910 	elif [ ! -x "$1" ]; then
    911 		echo ""
    912 		echo "*******************************************************"
    913 		echo "** Problem finding the Perl command '$1': **"
    914 		echo ""
    915 		type "perl"
    916 		echo ""
    917 		echo "** Perhaps you need to install the Perl package. **"
    918 		echo "*******************************************************"
    919 		echo ""
    920 		sleep 5
    921 	fi
    922 }
    923 
    924 # this is the PPROXY tool.  used only here for now... 
    925 pcode() {
    926 	tf=$1
    927 	PPROXY_PROXY=$proxy; export PPROXY_PROXY
    928 	PPROXY_DEST="$host:$port"; export PPROXY_DEST
    929 	check_perl /usr/bin/perl
    930 
    931 	cod='#!/usr/bin/perl
    932 
    933 # A hack to glue stunnel to a Web or SOCKS proxy, UltraVNC repeater for
    934 # client connections.
    935 # Also acts as a VeNCrypt bridge (by redirecting to stunnel.)
    936 
    937 use IO::Socket::INET;
    938 
    939 my $have_inet6 = "";
    940 eval "use IO::Socket::INET6;";
    941 $have_inet6 = 1 if $@ eq "";
    942 
    943 #my $have_sock6 = "";
    944 #eval "use Socket; use Socket6;";
    945 #$have_sock6 = 1 if $@ eq "";
    946 
    947 if (exists $ENV{PPROXY_LOOP_THYSELF}) {
    948 	# used for reverse vnc, run a repeating outer loop.
    949 	print STDERR "PPROXY_LOOP: $ENV{PPROXY_LOOP_THYSELF}\n";
    950 	my $rm = $ENV{PPROXY_REMOVE};
    951 	my $lp = $ENV{PPROXY_LOOP_THYSELF};
    952 	delete $ENV{PPROXY_REMOVE};
    953 	delete $ENV{PPROXY_LOOP_THYSELF};
    954 	$ENV{PPROXY_LOOP_THYSELF_MASTER} = $$;
    955 	my $pid = $$;
    956 	my $dbg = 0;
    957 	my $c = 0;
    958 	use POSIX ":sys_wait_h";
    959 	while (1) {
    960 		$pid = fork();
    961 		last if ! defined $pid;
    962 		if ($pid eq "0") {
    963 			last;
    964 		}
    965 		$c++;
    966 		print STDERR "\nPPROXY_LOOP: pid=$$ child=$pid count=$c\n";
    967 		while (1) {
    968 			waitpid(-1, WNOHANG);
    969 			fsleep(0.25);
    970 			if (! kill 0, $pid) {
    971 				print STDERR "PPROXY_LOOP: child=$pid gone.\n";
    972 				last;
    973 			}
    974 			print STDERR "PPROXY_LOOP: child=$pid alive.\n" if $dbg;
    975 			if (! -f $lp) {
    976 				print STDERR "PPROXY_LOOP: flag file $lp gone, killing $pid\n";
    977 				kill TERM, $pid;
    978 				fsleep(0.1);
    979 				wait;
    980 				last;
    981 			}
    982 			print STDERR "PPROXY_LOOP: file exists $lp\n" if $dbg;
    983 		}
    984 		last if ! -f $lp;
    985 		fsleep(0.25);
    986 	}
    987 	if ($pid ne "0") {
    988 		unlink($0) if $rm;
    989 		exit 0;
    990 	}
    991 }
    992 
    993 if (exists $ENV{PPROXY_SLEEP} && $ENV{PPROXY_SLEEP} > 0) {
    994 	print STDERR "PPROXY_PID: $$\n";
    995 	sleep $ENV{PPROXY_SLEEP};
    996 }
    997 
    998 foreach my $var (qw(
    999 		PPROXY_DEST
   1000 		PPROXY_KILLPID
   1001 		PPROXY_LISTEN
   1002 		PPROXY_PROXY
   1003 		PPROXY_REMOVE
   1004 		PPROXY_REPEATER
   1005 		PPROXY_REVERSE
   1006 		PPROXY_SLEEP
   1007 		PPROXY_SOCKS
   1008 		PPROXY_VENCRYPT
   1009 		PPROXY_VENCRYPT_VIEWER_BRIDGE
   1010     )) {
   1011 	if (0 || $ENV{SS_DEBUG} || $ENV{SSVNC_VENCRYPT_DEBUG}) {
   1012 		print STDERR "$var: $ENV{$var}\n";
   1013 	}
   1014 } 
   1015 
   1016 if ($ENV{PPROXY_SOCKS} ne "" && $ENV{PPROXY_PROXY} !~ m,^socks5?://,i) {
   1017 	if ($ENV{PPROXY_SOCKS} eq "5") {
   1018 		$ENV{PPROXY_PROXY} = "socks5://$ENV{PPROXY_PROXY}";
   1019 	} else {
   1020 		$ENV{PPROXY_PROXY} = "socks://$ENV{PPROXY_PROXY}";
   1021 	}
   1022 }
   1023 
   1024 my $rfbSecTypeAnonTls  = 18;
   1025 my $rfbSecTypeVencrypt = 19;
   1026 
   1027 my $rfbVencryptPlain        = 256;
   1028 my $rfbVencryptTlsNone      = 257;
   1029 my $rfbVencryptTlsVnc       = 258;
   1030 my $rfbVencryptTlsPlain     = 259;
   1031 my $rfbVencryptX509None     = 260;
   1032 my $rfbVencryptX509Vnc      = 261;
   1033 my $rfbVencryptX509Plain    = 262;
   1034 
   1035 my $handshake_file = "";
   1036 if (exists $ENV{SSVNC_PREDIGESTED_HANDSHAKE})  {
   1037 	$handshake_file = $ENV{SSVNC_PREDIGESTED_HANDSHAKE};
   1038 }
   1039 
   1040 my $have_gettimeofday = 0;
   1041 eval "use Time::HiRes;";
   1042 if ($@ eq "") {
   1043 	$have_gettimeofday = 1;
   1044 }
   1045 sub gettime {
   1046 	my $t = "0.0";
   1047 	if ($have_gettimeofday) {
   1048 		$t = Time::HiRes::gettimeofday();
   1049 	}
   1050 	return $t;
   1051 }
   1052 
   1053 my $listen_handle = "";
   1054 my $sock = "";
   1055 my $parent = $$;
   1056 
   1057 my $initial_data = "";
   1058 
   1059 if ($ENV{PPROXY_VENCRYPT_VIEWER_BRIDGE}) {
   1060 	my ($from, $to) = split(/,/, $ENV{PPROXY_VENCRYPT_VIEWER_BRIDGE});
   1061 	do_vencrypt_viewer_bridge($from, $to);
   1062 	exit 0;
   1063 }
   1064 
   1065 my ($first, $second, $third) = split(/,/, $ENV{PPROXY_PROXY}, 3);
   1066 my ($mode_1st, $mode_2nd, $mode_3rd) = ("", "", "");
   1067 
   1068 ($first, $mode_1st) = url_parse($first);
   1069 
   1070 my ($proxy_host, $proxy_port) = ($first, "");
   1071 if ($proxy_host =~ /^(.*):(\d+)$/) {
   1072 	$proxy_host = $1;
   1073 	$proxy_port = $2;
   1074 }
   1075 my $connect = $ENV{PPROXY_DEST};
   1076 
   1077 if ($second ne "") {
   1078 	($second, $mode_2nd) = url_parse($second);
   1079 }
   1080 
   1081 if ($third ne "") {
   1082 	($third, $mode_3rd) = url_parse($third);
   1083 }
   1084 
   1085 
   1086 print STDERR "\n";
   1087 print STDERR "PPROXY v0.4: a tool for Web, SOCKS, and UltraVNC proxies and for\n";
   1088 print STDERR "PPROXY v0.4: IPv6 and VNC VeNCrypt bridging.\n";
   1089 print STDERR "proxy_host:       $proxy_host\n";
   1090 print STDERR "proxy_port:       $proxy_port\n";
   1091 print STDERR "proxy_connect:    $connect\n";
   1092 print STDERR "pproxy_params:    $ENV{PPROXY_PROXY}\n";
   1093 print STDERR "pproxy_listen:    $ENV{PPROXY_LISTEN}\n";
   1094 print STDERR "pproxy_reverse:   $ENV{PPROXY_REVERSE}\n";
   1095 print STDERR "io_socket_inet6:  $have_inet6\n";
   1096 print STDERR "\n";
   1097 if (! $have_inet6) {
   1098 	print STDERR "PPROXY: To enable IPv6 connections, install the IO::Socket::INET6 perl module.\n\n";
   1099 }
   1100 
   1101 if (1) {
   1102 	print STDERR "pproxy 1st: $first\t- $mode_1st\n";
   1103 	print STDERR "pproxy 2nd: $second\t- $mode_2nd\n";
   1104 	print STDERR "pproxy 3rd: $third\t- $mode_3rd\n";
   1105 	print STDERR "\n";
   1106 }
   1107 
   1108 sub pdie {
   1109 	my $msg = shift;
   1110 	kill_proxy_pids();
   1111 	die "$msg";
   1112 }
   1113 
   1114 if ($ENV{PPROXY_REVERSE} ne "") {
   1115 	my ($rhost, $rport) = ($ENV{PPROXY_REVERSE}, "");
   1116 	if ($rhost =~ /^(.*):(\d+)$/) {
   1117 		$rhost = $1;
   1118 		$rport = $2;
   1119 	}
   1120 	$rport = 5900 unless $rport;
   1121 	my $emsg = "";
   1122 	$listen_handle = IO::Socket::INET->new(
   1123 		PeerAddr => $rhost,
   1124 		PeerPort => $rport,
   1125 		Proto => "tcp"
   1126 	);
   1127 	$emsg = $!;
   1128 	if (! $listen_handle && $have_inet6) {
   1129 		eval {$listen_handle = IO::Socket::INET6->new(
   1130 			PeerAddr => $rhost,
   1131 			PeerPort => $rport,
   1132 			Proto => "tcp"
   1133 		);};
   1134 		$emsg .= " / $!";
   1135 	}
   1136 	if (! $listen_handle) {
   1137 		pdie "pproxy: $emsg -- PPROXY_REVERSE\n";
   1138 	}
   1139 	print STDERR "PPROXY_REVERSE: connected to $rhost $rport\n";
   1140 
   1141 } elsif ($ENV{PPROXY_LISTEN} ne "") {
   1142 	my $listen_sock = "";
   1143 	my $maxtry = 12;
   1144 	my $sleep = 5;
   1145 	my $p2 = "";
   1146 	my $emsg = "";
   1147 	for (my $i=0; $i < $maxtry; $i++)  {
   1148 		my ($if, $p) = ("", $ENV{PPROXY_LISTEN});
   1149 		if ($p =~ /^(.*):(\d+)$/) {
   1150 			$if = $1;
   1151 			$p = $2;
   1152 		}
   1153 		$p2 = "*:$p";
   1154 		if ($if eq "") {
   1155 			$if = "localhost";
   1156 		}
   1157 		print STDERR "pproxy interface: $if\n";
   1158 
   1159 		$emsg = "";
   1160 		if (($if eq "INADDR_ANY6" || $if eq "::") && $have_inet6) {
   1161 			eval {$listen_sock = IO::Socket::INET6->new(
   1162 				Listen    => 2,
   1163 				ReuseAddr => 1,
   1164 				Domain    => AF_INET6,
   1165 				LocalAddr => "::",
   1166 				LocalPort => $p,
   1167 				Proto     => "tcp"
   1168 			);};
   1169 			$p2 = ":::$p";
   1170 		} elsif ($if =~ /^INADDR_ANY/) {
   1171 			$listen_sock = IO::Socket::INET->new(
   1172 				Listen    => 2,
   1173 				ReuseAddr => 1,
   1174 				LocalPort => $p,
   1175 				Proto     => "tcp"
   1176 			);
   1177 		} elsif (($if eq "INADDR_LOOPBACK6" || $if eq "::1") && $have_inet6) {
   1178 			$p2 = "::1:$p";
   1179 			eval {$listen_sock = IO::Socket::INET6->new(
   1180 				Listen    => 2,
   1181 				ReuseAddr => 1,
   1182 				Domain    => AF_INET6,
   1183 				LocalAddr => "::1",
   1184 				LocalPort => $p,
   1185 				Proto     => "tcp"
   1186 			);};
   1187 			$p2 = "::1:$p";
   1188 		} else {
   1189 			$p2 = "$if:$p";
   1190 			$listen_sock = IO::Socket::INET->new(
   1191 				Listen    => 2,
   1192 				ReuseAddr => 1,
   1193 				LocalAddr => $if,
   1194 				LocalPort => $p,
   1195 				Proto     => "tcp"
   1196 			);
   1197 			$emsg = $!;
   1198 			
   1199 			if (! $listen_sock && $have_inet6) {
   1200 				print STDERR "PPROXY_LISTEN: retry with INET6\n";
   1201 				eval {$listen_sock = IO::Socket::INET6->new(
   1202 					Listen    => 2,
   1203 					ReuseAddr => 1,
   1204 					Domain    => AF_INET6,
   1205 					LocalAddr => $if,
   1206 					LocalPort => $p,
   1207 					Proto     => "tcp"
   1208 				);};
   1209 				$emsg .= " / $!";
   1210 			}
   1211 		}
   1212 		if (! $listen_sock) {
   1213 			if ($i < $maxtry - 1) {
   1214 				warn "pproxy: $emsg $!\n";
   1215 				warn "Could not listen on port $p2, retrying in $sleep seconds... (Ctrl-C to quit)\n";
   1216 				sleep $sleep;
   1217 			}
   1218 		} else {
   1219 			last;
   1220 		}
   1221 	}
   1222 	if (! $listen_sock) {
   1223 		pdie "pproxy: $emsg -- PPROXY_LISTEN\n";
   1224 	}
   1225 	print STDERR "pproxy: listening on $p2\n";
   1226 	my $ip;
   1227 	($listen_handle, $ip) = $listen_sock->accept();
   1228 	my $err = $!;
   1229 	close $listen_sock;
   1230 	if (! $listen_handle) {
   1231 		pdie "pproxy: $err\n";
   1232 	}
   1233 
   1234 	if ($ENV{PPROXY_LOOP_THYSELF_MASTER}) {
   1235 		my $sml = $ENV{SSVNC_MULTIPLE_LISTEN}; 
   1236 		if ($sml ne "" && $sml ne "0") {
   1237 			setpgrp(0, 0);
   1238 			if (fork()) {
   1239 				close $viewer_sock;
   1240 				wait;
   1241 				exit 0;
   1242 			}
   1243 			if (fork()) {
   1244 				close $viewer_sock;
   1245 				exit 0;
   1246 			}
   1247 			setpgrp(0, 0);
   1248 			$parent = $$;
   1249 		}
   1250 	}
   1251 }
   1252 
   1253 $sock = IO::Socket::INET->new(
   1254 	PeerAddr => $proxy_host,
   1255 	PeerPort => $proxy_port,
   1256 	Proto => "tcp"
   1257 );
   1258 
   1259 my $err = "";
   1260 
   1261 if (! $sock && $have_inet6) {
   1262 	$err = $!;
   1263 
   1264 	print STDERR "pproxy: $!\n";
   1265 
   1266 	eval {$sock = IO::Socket::INET6->new(
   1267 		PeerAddr => $proxy_host,
   1268 		PeerPort => $proxy_port,
   1269 		Proto => "tcp"
   1270 	);};
   1271 	$err .= " / $!";
   1272 }
   1273 
   1274 if (! $sock && ($proxy_host =~ /^::ffff:(\d+\.\d+\.\d+\.\d+)$/i || $proxy_host =~ /^::ffff:([\da-f]+:[\da-f]+)$/i)) {
   1275 	print STDERR "pproxy: $!\n";
   1276 	my $ipv4_addr = $1;
   1277 	if ($ipv4_addr =~ /:/) {
   1278 		my ($a, $b) = split(/:/, $ipv4_addr);
   1279 		$a = hex($a);
   1280 		$b = hex($b);
   1281 		$ipv4_addr  = sprintf("%d.", ($a & 0xff00) >> 8);
   1282 		$ipv4_addr .= sprintf("%d.", ($a & 0x00ff));
   1283 		$ipv4_addr .= sprintf("%d.", ($b & 0xff00) >> 8);
   1284 		$ipv4_addr .= sprintf("%d",  ($b & 0x00ff));
   1285 	}
   1286 
   1287 	print STDERR "pproxy: re-trying with ipv4 addr: $ipv4_addr\n";
   1288 
   1289 	eval {$sock = IO::Socket::INET->new(
   1290 		PeerAddr => $ipv4_addr,
   1291 		PeerPort => $proxy_port,
   1292 		Proto => "tcp"
   1293 	);};
   1294 	$err .= " / $!";
   1295 }
   1296 
   1297 if (! $sock) {
   1298 	unlink($0) if $ENV{PPROXY_REMOVE};
   1299 	pdie "pproxy: $err\n";
   1300 }
   1301 
   1302 unlink($0) if $ENV{PPROXY_REMOVE};
   1303 
   1304 if ($ENV{PPROXY_PROXY} =~ /^vencrypt:/ && $ENV{PPROXY_VENCRYPT_REVERSE}) {
   1305 	print STDERR "\nPPROXY: vencrypt+reverse: swapping listen socket with connect socket.\n";
   1306 	my $tmp_swap = $sock;
   1307 	$sock = $listen_handle;
   1308 	$listen_handle = $tmp_swap;
   1309 }
   1310 
   1311 $cur_proxy = $first;
   1312 setmode($mode_1st);
   1313 
   1314 if ($second ne "") {
   1315 	connection($second, 1);
   1316 
   1317 	setmode($mode_2nd);
   1318 	$cur_proxy = $second;
   1319 
   1320 	if ($third ne "") {
   1321 		connection($third, 2);
   1322 		setmode($mode_3rd);
   1323 		$cur_proxy = $third;
   1324 		connection($connect, 3);
   1325 	} else {
   1326 		connection($connect, 2);
   1327 	}
   1328 } else {
   1329 	connection($connect, 1);
   1330 }
   1331 
   1332 sub kill_proxy_pids() {
   1333 	if ($ENV{PPROXY_VENCRYPT_VIEWER_BRIDGE}) {
   1334 		return;
   1335 	}
   1336 	if ($ENV{PPROXY_KILLPID}) {
   1337 		foreach my $p (split(/,/, $ENV{PPROXY_KILLPID})) {
   1338 			if ($p =~ /^(\+|-)/) {
   1339 				$p = $parent + $p;
   1340 			}
   1341 			print STDERR "kill TERM, $p (PPROXY_KILLPID)\n";
   1342 			kill "TERM", $p;
   1343 		}
   1344 	}
   1345 }
   1346 
   1347 sub xfer {
   1348 	my($in, $out) = @_;
   1349 	$RIN = $WIN = $EIN = "";
   1350 	$ROUT = "";
   1351 	vec($RIN, fileno($in), 1) = 1;
   1352 	vec($WIN, fileno($in), 1) = 1;
   1353 	$EIN = $RIN | $WIN;
   1354 
   1355 	while (1) {
   1356 		my $nf = 0;
   1357 		while (! $nf) {
   1358 			$nf = select($ROUT=$RIN, undef, undef, undef);
   1359 		}
   1360 		my $len = sysread($in, $buf, 8192);
   1361 		if (! defined($len)) {
   1362 			next if $! =~ /^Interrupted/;
   1363 			print STDERR "pproxy[$$]: $!\n";
   1364 			last;
   1365 		} elsif ($len == 0) {
   1366 			print STDERR "pproxy[$$]: Input is EOF.\n";
   1367 			last;
   1368 		}
   1369 		my $offset = 0;
   1370 		my $quit = 0;
   1371 		while ($len) {
   1372 			my $written = syswrite($out, $buf, $len, $offset);
   1373 			if (! defined $written) {
   1374 				print STDERR "pproxy[$$]: Output is EOF. $!\n";
   1375 				$quit = 1;
   1376 				last;
   1377 			}
   1378 			$len -= $written;
   1379 			$offset += $written;
   1380 		}
   1381 		last if $quit;
   1382 	}
   1383 	close($out);
   1384 	close($in);
   1385 	print STDERR "pproxy[$$]: finished xfer.\n";
   1386 }
   1387 
   1388 sub handler {
   1389 	print STDERR "pproxy[$$]: got SIGTERM.\n";
   1390 	close $listen_handle if $listen_handle;
   1391 	close $sock if $sock;
   1392 	exit;
   1393 }
   1394 
   1395 sub xfer_both {
   1396 	$child = fork;
   1397 
   1398 	if (! defined $child) {
   1399 		kill_proxy_pids();
   1400 		exit 1;
   1401 	}
   1402 
   1403 	$SIG{TERM} = "handler";
   1404 
   1405 	if ($child) {
   1406 		if ($listen_handle) {
   1407 			print STDERR "pproxy parent[$$]  listen_handle -> socket\n";
   1408 			xfer($listen_handle, $sock);
   1409 		} else {
   1410 			print STDERR "pproxy parent[$$]  STDIN -> socket\n";
   1411 			xfer(STDIN, $sock);
   1412 		}
   1413 		select(undef, undef, undef, 0.25);
   1414 		if (kill 0, $child) {
   1415 			select(undef, undef, undef, 0.9);
   1416 			if (kill 0, $child) {
   1417 				print STDERR "pproxy[$$]: kill TERM child $child\n";
   1418 				kill "TERM", $child;
   1419 			} else {
   1420 				print STDERR "pproxy[$$]: child  $child gone.\n";
   1421 			}
   1422 		}
   1423 	} else {
   1424 		select(undef, undef, undef, 0.05);
   1425 		if ($listen_handle) {
   1426 			print STDERR "pproxy child [$$]  socket -> listen_handle\n";
   1427 			if ($initial_data ne "") {
   1428 				my $len = length $initial_data;
   1429 				print STDERR "pproxy child [$$]  sending initial_data, length $len\n\n";
   1430 				syswrite($listen_handle, $initial_data, $len);
   1431 			} else {
   1432 				print STDERR "\n";
   1433 			}
   1434 			xfer($sock, $listen_handle);
   1435 		} else {
   1436 			print STDERR "pproxy child [$$]  socket -> STDOUT\n";
   1437 			if ($initial_data ne "") {
   1438 				my $len = length $initial_data;
   1439 				print STDERR "pproxy child [$$]  sending initial_data, length $len\n\n";
   1440 				syswrite(STDOUT, $initial_data, $len);
   1441 			} else {
   1442 				print STDERR "\n";
   1443 			}
   1444 			xfer($sock, STDOUT);
   1445 		}
   1446 		select(undef, undef, undef, 0.25);
   1447 		if (kill 0, $parent) {
   1448 			select(undef, undef, undef, 0.8);
   1449 			if (kill 0, $parent) {
   1450 				print STDERR "pproxy[$$]: kill TERM parent $parent\n";
   1451 				kill "TERM", $parent;
   1452 			} else {
   1453 				print STDERR "pproxy[$$]: parent $parent gone.\n";
   1454 			}
   1455 		}
   1456 	}
   1457 
   1458 	kill_proxy_pids();
   1459 }
   1460 
   1461 xfer_both();
   1462 
   1463 exit;
   1464 
   1465 sub fsleep {
   1466 	select(undef, undef, undef, shift);
   1467 }
   1468 
   1469 sub url_parse {
   1470 	my $hostport = shift;
   1471 	my $mode = "http";
   1472 	if ($hostport =~ m,^socks4?://(\S*)$,i) {
   1473 		$mode = "socks4";
   1474 		$hostport = $1;
   1475 	} elsif ($hostport =~ m,^socks5://(\S*)$,i) {
   1476 		$mode = "socks5";
   1477 		$hostport = $1;
   1478 	} elsif ($hostport =~ m,^https?://(\S*)$,i) {
   1479 		$mode = "http";
   1480 		$hostport = $1;
   1481 	} elsif ($hostport =~ m,^ipv6://(\S*)$,i) {
   1482 		$mode = "ipv6";
   1483 		$hostport = $1;
   1484 	} elsif ($hostport =~ m,^repeater://(\S*)\+(\S*)$,i) {
   1485 		# ultravnc repeater proxy.
   1486 		$hostport = $1;
   1487 		$mode = "repeater:$2";
   1488 		if ($hostport !~ /:\d+$/) {
   1489 			$hostport .= ":5900";
   1490 		}
   1491 	} elsif ($hostport =~ m,^vencrypt://(\S*)$,i) {
   1492 		# vencrypt handshake.
   1493 		$hostport = $1;
   1494 		my $m = "connect";
   1495 		if ($hostpost =~ /^(\S+)\+(\S+)$/) {
   1496 			$hostport = $1;
   1497 			$mode = $2;
   1498 		}
   1499 		$mode = "vencrypt:$m";
   1500 		if ($hostport !~ /:\d+$/) {
   1501 			$hostport .= ":5900";
   1502 		}
   1503 	}
   1504 	return ($hostport, $mode);
   1505 }
   1506 
   1507 sub setmode {
   1508 	my $mode = shift;
   1509 	$ENV{PPROXY_REPEATER} = "";
   1510 	$ENV{PPROXY_VENCRYPT} = "";
   1511 	if ($mode =~ /^socks/) {
   1512 		if ($mode =~ /^socks5/) {
   1513 			$ENV{PPROXY_SOCKS} = 5;
   1514 		} else {
   1515 			$ENV{PPROXY_SOCKS} = 1;
   1516 		}
   1517 	} elsif ($mode =~ /^ipv6/i) {
   1518 		$ENV{PPROXY_SOCKS} = 0;
   1519 	} elsif ($mode =~ /^repeater:(.*)/) {
   1520 		$ENV{PPROXY_REPEATER} = $1;
   1521 		$ENV{PPROXY_SOCKS} = "";
   1522 	} elsif ($mode =~ /^vencrypt:(.*)/) {
   1523 		$ENV{PPROXY_VENCRYPT} = $1;
   1524 		$ENV{PPROXY_SOCKS} = "";
   1525 	} else {
   1526 		$ENV{PPROXY_SOCKS} = "";
   1527 	}
   1528 }
   1529 
   1530 sub connection {
   1531 	my ($CONNECT, $w) = @_;
   1532 
   1533 	my $con = "";
   1534 	my $msg = "";
   1535 
   1536 	if ($ENV{PPROXY_SOCKS} eq "5") {
   1537 		# SOCKS5
   1538 		my ($h, $p) = ($CONNECT, "");
   1539 		if ($h =~ /^(.*):(\d+)$/) {
   1540 			$h = $1;
   1541 			$p = $2;
   1542 		}
   1543 		$con .= pack("C", 0x05);
   1544 		$con .= pack("C", 0x01);
   1545 		$con .= pack("C", 0x00);
   1546 
   1547 		$msg = "SOCKS5 via $cur_proxy to $h:$p\n\n";
   1548 		print STDERR "proxy_request$w: $msg";
   1549 
   1550 		syswrite($sock, $con, length($con));
   1551 
   1552 		my ($n1, $n2, $n3, $n4, $n5, $n6);
   1553 		my ($r1, $r2, $r3, $r4, $r5, $r6);
   1554 		my ($s1, $s2, $s3, $s4, $s5, $s6);
   1555 
   1556 		$n1 = sysread($sock, $r1, 1);
   1557 		$n2 = sysread($sock, $r2, 1);
   1558 
   1559 		$s1 = unpack("C", $r1);
   1560 		$s2 = unpack("C", $r2);
   1561 		if ($s1 != 0x05 || $s2 != 0x00) {
   1562 			print STDERR "SOCKS5 fail s1=$s1 s2=$s2 n1=$n1 n2=$n2\n";
   1563 			close $sock;
   1564 			exit(1);
   1565 		}
   1566 
   1567 		$con = "";
   1568 		$con .= pack("C", 0x05);
   1569 		$con .= pack("C", 0x01);
   1570 		$con .= pack("C", 0x00);
   1571 		$con .= pack("C", 0x03);
   1572 		$con .= pack("C", length($h));
   1573 		$con .= $h;
   1574 		$con .= pack("C", $p >> 8);
   1575 		$con .= pack("C", $p & 0xff);
   1576 
   1577 		syswrite($sock, $con, length($con));
   1578 
   1579 		$n1 = sysread($sock, $r1, 1);
   1580 		$n2 = sysread($sock, $r2, 1);
   1581 		$n3 = sysread($sock, $r3, 1);
   1582 		$n4 = sysread($sock, $r4, 1);
   1583 		$s1 = unpack("C", $r1);
   1584 		$s2 = unpack("C", $r2);
   1585 		$s3 = unpack("C", $r3);
   1586 		$s4 = unpack("C", $r4);
   1587 
   1588 		if ($s4 == 0x1) {
   1589 			sysread($sock, $r5, 4 + 2);
   1590 		} elsif ($s4 == 0x3) {
   1591 			sysread($sock, $r5, 1);
   1592 			$s5 = unpack("C", $r5);
   1593 			sysread($sock, $r6, $s5 + 2);
   1594 		} elsif ($s4 == 0x4) {
   1595 			sysread($sock, $r5, 16 + 2);
   1596 		}
   1597 
   1598 		if ($s1 != 0x5 || $s2 != 0x0 || $s3 != 0x0) {
   1599 			print STDERR "SOCKS5 failed: s1=$s1 s2=$s2 s3=$s3 s4=$s4 n1=$n1 n2=$n2 n3=$n3 n4=$n4\n";
   1600 			close $sock;
   1601 			exit(1);
   1602 		}
   1603 
   1604 	} elsif ($ENV{PPROXY_SOCKS} eq "1") {
   1605 		# SOCKS4 SOCKS4a
   1606 		my ($h, $p) = ($CONNECT, "");
   1607 		if ($h =~ /^(.*):(\d+)$/) {
   1608 			$h = $1;
   1609 			$p = $2;
   1610 		}
   1611 		$con .= pack("C", 0x04);
   1612 		$con .= pack("C", 0x01);
   1613 		$con .= pack("n", $p);
   1614 
   1615 		my $SOCKS_4a = 0;
   1616 		if ($h eq "localhost" || $h eq "127.0.0.1") {
   1617 			$con .= pack("C", 127);
   1618 			$con .= pack("C", 0);
   1619 			$con .= pack("C", 0);
   1620 			$con .= pack("C", 1);
   1621 		} elsif ($h =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) {
   1622 			$con .= pack("C", $1);
   1623 			$con .= pack("C", $2);
   1624 			$con .= pack("C", $3);
   1625 			$con .= pack("C", $4);
   1626 		} else {
   1627 			$con .= pack("C", 0);
   1628 			$con .= pack("C", 0);
   1629 			$con .= pack("C", 0);
   1630 			$con .= pack("C", 3);
   1631 			$SOCKS_4a = 1;
   1632 		}
   1633 
   1634 		$con .= "nobody";
   1635 		$con .= pack("C", 0);
   1636 
   1637 		$msg = "SOCKS4 via $cur_proxy to $h:$p\n\n";
   1638 		if ($SOCKS_4a) {
   1639 			$con .= $h;
   1640 			$con .= pack("C", 0);
   1641 			$msg =~ s/SOCKS4/SOCKS4a/;
   1642 		}
   1643 		print STDERR "proxy_request$w: $msg";
   1644 		syswrite($sock, $con, length($con));
   1645 
   1646 		my $ok = 1;
   1647 		for (my $i = 0; $i < 8; $i++) {
   1648 			my $c;
   1649 			sysread($sock, $c, 1);
   1650 			my $s = unpack("C", $c);
   1651 			if ($i == 0) {
   1652 				$ok = 0 if $s != 0x0;
   1653 			} elsif ($i == 1) {
   1654 				$ok = 0 if $s != 0x5a;
   1655 			}
   1656 		}
   1657 		if (! $ok) {
   1658 			print STDERR "SOCKS4 failed.\n";
   1659 			close $sock;
   1660 			exit(1);
   1661 		}
   1662 	} elsif ($ENV{PPROXY_SOCKS} eq "0") {
   1663 		# hack for ipv6 "proxy", nothing to do, assume INET6 call worked.
   1664 		;
   1665 	} elsif ($ENV{PPROXY_REPEATER} ne "") {
   1666 		my $rep = $ENV{PPROXY_REPEATER};
   1667 		print STDERR "repeater: $rep\n";
   1668 		$rep .= pack("x") x 250;
   1669 		syswrite($sock, $rep, 250);
   1670 
   1671 		my $rfb = "";
   1672 
   1673 		my $ok = 1;
   1674 		for (my $i = 0; $i < 12; $i++) {
   1675 			my $c;
   1676 			last if $ENV{PPROXY_GENERIC_REPEATER};
   1677 			sysread($sock, $c, 1);
   1678 			print STDERR $c;
   1679 			$rfb .= $c;
   1680 		}
   1681 		if ($rfb ne "" && $rfb !~ /^RFB 000\.000/) {
   1682 			$initial_data = $rfb;
   1683 			$rfb =~ s/\n//g;
   1684 			print STDERR "detected non-UltraVNC repeater; forwarding \"$rfb\"\nlength: ", length($initial_data), "\n";
   1685 		}
   1686 	} elsif ($ENV{PPROXY_VENCRYPT} ne "") {
   1687 		my $vencrypt = $ENV{PPROXY_VENCRYPT};
   1688 		vencrypt_dialog($vencrypt);
   1689 
   1690 	} else {
   1691 		# Web Proxy:
   1692 		$con = "CONNECT $CONNECT HTTP/1.1\r\n";
   1693 		$con   .= "Host: $CONNECT\r\n";
   1694 		$con   .= "Connection: close\r\n\r\n";
   1695 		$msg = $con;
   1696 
   1697 		print STDERR "proxy_request$w: via $cur_proxy:\n$msg";
   1698 		syswrite($sock, $con, length($con));
   1699 
   1700 		my $rep = "";
   1701 		my $n = 0;
   1702 		while ($rep !~ /\r\n\r\n/ && $n < 30000) {
   1703 			my $c;
   1704 			sysread($sock, $c, 1);
   1705 			print STDERR $c;
   1706 			$rep .= $c;
   1707 			$n++;
   1708 		}
   1709 		if ($rep !~ m,HTTP/.* 200,) {
   1710 			print STDERR "HTTP CONNECT failed.\n";
   1711 			close $sock;
   1712 			exit(1);
   1713 		}
   1714 	}
   1715 }
   1716 
   1717 sub vdie {
   1718 	append_handshake("done\n");
   1719 	close $sock;
   1720 	kill_proxy_pids();
   1721 	exit(1);
   1722 }
   1723 
   1724 sub anontls_handshake {
   1725 	my ($vmode, $db) = @_;
   1726 
   1727 	print STDERR "\nPPROXY: Doing ANONTLS Handshake\n";
   1728 
   1729 	my $psec = pack("C", $rfbSecTypeAnonTls);
   1730 	syswrite($sock, $psec, 1);
   1731 
   1732 	append_handshake("done\n");
   1733 }
   1734 
   1735 sub vencrypt_handshake {
   1736 	
   1737 	my ($vmode, $db) = @_;
   1738 
   1739 	print STDERR "\nPPROXY: Doing VeNCrypt Handshake\n";
   1740 
   1741 	my $psec = pack("C", $rfbSecTypeVencrypt);
   1742 
   1743 	if (exists $ENV{SSVNC_TEST_SEC_TYPE}) {
   1744 		my $fake = $ENV{SSVNC_TEST_SEC_TYPE};
   1745 		print STDERR "PPROXY: sending sec-type: $fake\n";
   1746 		$psec = pack("C", $fake);
   1747 	}
   1748 
   1749 	syswrite($sock, $psec, 1);
   1750 
   1751 	my $vmajor;
   1752 	my $vminor;
   1753 	sysread($sock, $vmajor, 1);
   1754 	sysread($sock, $vminor, 1);
   1755 
   1756 	vdie if $vmajor eq "" || $vminor eq "";
   1757 
   1758 	$vmajor = unpack("C", $vmajor);
   1759 	$vminor = unpack("C", $vminor);
   1760 	print STDERR "server vencrypt version $vmajor.$vminor\n" if $db;
   1761 
   1762 	if (exists $ENV{SSVNC_TEST_SEC_TYPE}) {
   1763 		print STDERR "PPROXY: continuing on in test mode.\n";
   1764 	} else {
   1765 		vdie if $vmajor ne 0;
   1766 		vdie if $vminor < 2;
   1767 	}
   1768 
   1769 	$vmajor = pack("C", 0);
   1770 	$vminor = pack("C", 2);
   1771 	append_handshake("subversion=0.2\n");
   1772 
   1773 	syswrite($sock, $vmajor, 1);
   1774 	syswrite($sock, $vminor, 1);
   1775 
   1776 	my $result;
   1777 	sysread($sock, $result, 1);
   1778 	print STDERR "result empty\n" if $db && $result eq "";
   1779 
   1780 	vdie if $result eq "";
   1781 	$result = unpack("C", $result);
   1782 	print STDERR "result=$result\n" if $db;
   1783 
   1784 	vdie if $result ne 0;
   1785 
   1786 	my $nsubtypes;
   1787 	sysread($sock, $nsubtypes, 1);
   1788 
   1789 	vdie if $nsubtypes eq "";
   1790 	$nsubtypes = unpack("C", $nsubtypes);
   1791 	print STDERR "nsubtypes=$nsubtypes\n" if $db;
   1792 
   1793 	my %subtypes;
   1794 
   1795 	for (my $i = 0; $i < $nsubtypes; $i++) {
   1796 		my $subtype = ""; 
   1797 		sysread($sock, $subtype, 4);
   1798 		vdie if length($subtype) != 4;
   1799 
   1800 		# XXX fix 64bit.
   1801 		$subtype = unpack("N", $subtype);
   1802 		print STDERR "subtype: $subtype\n" if $db;
   1803 		$subtypes{$subtype} = 1;
   1804 		append_handshake("sst$i=$subtype\n");
   1805 	}
   1806 
   1807 	my $subtype = 0;
   1808 	if (exists $subtypes{$rfbVencryptX509None})  {
   1809 		$subtype = $rfbVencryptX509None;
   1810 		print STDERR "selected rfbVencryptX509None\n" if $db;
   1811 	} elsif (exists $subtypes{$rfbVencryptX509Vnc})  {
   1812 		$subtype = $rfbVencryptX509Vnc;
   1813 		print STDERR "selected rfbVencryptX509Vnc\n" if $db;
   1814 	} elsif (exists $subtypes{$rfbVencryptX509Plain})  {
   1815 		$subtype = $rfbVencryptX509Plain;
   1816 		print STDERR "selected rfbVencryptX509Plain\n" if $db;
   1817 	} elsif (exists $subtypes{$rfbVencryptTlsNone})  {
   1818 		$subtype = $rfbVencryptTlsNone;
   1819 		print STDERR "selected rfbVencryptTlsNone\n" if $db;
   1820 	} elsif (exists $subtypes{$rfbVencryptTlsVnc})  {
   1821 		$subtype = $rfbVencryptTlsVnc;
   1822 		print STDERR "selected rfbVencryptTlsVnc\n" if $db;
   1823 	} elsif (exists $subtypes{$rfbVencryptTlsPlain})  {
   1824 		$subtype = $rfbVencryptTlsPlain;
   1825 		print STDERR "selected rfbVencryptTlsPlain\n" if $db;
   1826 	}
   1827 
   1828 	if (exists $ENV{SSVNC_TEST_SEC_SUBTYPE}) {
   1829 		my $fake = $ENV{SSVNC_TEST_SEC_SUBTYPE};
   1830 		print STDERR "PPROXY: sending sec-subtype: $fake\n";
   1831 		$subtype = $fake;
   1832 	}
   1833 
   1834 	append_handshake("subtype=$subtype\n");
   1835 
   1836 	my $pst = pack("N", $subtype);
   1837 	syswrite($sock, $pst, 4); 
   1838 
   1839 	if (exists $ENV{SSVNC_TEST_SEC_SUBTYPE}) {
   1840 		print STDERR "PPROXY: continuing on in test mode.\n";
   1841 	} else {
   1842 		vdie if $subtype == 0;
   1843 	}
   1844 
   1845 	my $ok;
   1846 	sysread($sock, $ok, 1);
   1847 	$ok = unpack("C", $ok);
   1848 	print STDERR "ok=$ok\n" if $db;
   1849 
   1850 	append_handshake("done\n");
   1851 
   1852 	vdie if $ok == 0;
   1853 }
   1854 
   1855 sub vencrypt_dialog {
   1856 	my $vmode = shift;
   1857 	my $db = 0;
   1858 
   1859 	$db = 1 if exists $ENV{SS_DEBUG};
   1860 	$db = 1 if exists $ENV{SSVNC_VENCRYPT_DEBUG};
   1861 
   1862 	append_handshake("mode=$vmode\n");
   1863 
   1864 	my $server_rfb = "";
   1865 	#syswrite($sock, $rep, 250);
   1866 	for (my $i = 0; $i < 12; $i++) {
   1867 		my $c;
   1868 		sysread($sock, $c, 1);
   1869 		$server_rfb .= $c;
   1870 		print STDERR $c;
   1871 	}
   1872 	print STDERR "server_rfb: $server_rfb\n" if $db;
   1873 	append_handshake("server=$server_rfb");
   1874 
   1875 	my $minor = "";
   1876 	if ($server_rfb =~ /^RFB 003\.(\d+)/) {
   1877 		$minor = $1;
   1878 	} else {
   1879 		vdie;
   1880 	}
   1881 	my $viewer_rfb = "RFB 003.008\n";
   1882 	if ($minor < 7) {
   1883 		vdie;
   1884 	} elsif ($minor == 7) {
   1885 		$viewer_rfb = "RFB 003.007\n";
   1886 	}
   1887 	my $nsec;
   1888 	my $t1 = gettime();
   1889 	my $t0 = gettime();
   1890 
   1891 	syswrite($sock, $viewer_rfb, 12);
   1892 	sysread($sock, $nsec, 1);
   1893 
   1894 	$t1 = gettime();
   1895 	$t1 = sprintf("%.6f", $t1 - $t0);
   1896 
   1897 	append_handshake("viewer=$viewer_rfb");
   1898 	append_handshake("latency=$t1\n");
   1899 
   1900 	vdie if $nsec eq "";
   1901 
   1902 	$nsec = unpack("C", $nsec);
   1903 
   1904 	print STDERR "nsec: $nsec\n" if $db;
   1905 	vdie if $nsec eq 0 || $nsec > 100;
   1906 
   1907 	my %sectypes = ();
   1908 
   1909 	for (my $i = 0; $i < $nsec; $i++) {
   1910 		my $sec;
   1911 		sysread($sock, $sec, 1);
   1912 		vdie if $sec eq "";
   1913 		$sec = unpack("C", $sec);
   1914 		print STDERR "sec: $sec\n" if $db;
   1915 		$sectypes{$sec} = 1;
   1916 	}
   1917 	
   1918 	if (exists $sectypes{$rfbSecTypeVencrypt}) {
   1919 		print STDERR "found rfbSecTypeVencrypt\n" if $db;
   1920 		append_handshake("sectype=$rfbSecTypeVencrypt\n");
   1921 		vencrypt_handshake($vmode, $db);
   1922 	} elsif (exists $sectypes{$rfbSecTypeAnonTls}) {
   1923 		print STDERR "found rfbSecTypeAnonTls\n" if $db;
   1924 		append_handshake("sectype=$rfbSecTypeAnonTls\n");
   1925 		anontls_handshake($vmode, $db);
   1926 	} else {
   1927 		print STDERR "No supported sec-type found\n" if $db;
   1928 		vdie;
   1929 	}
   1930 }
   1931 
   1932 sub append_handshake {
   1933 	my $str = shift;
   1934 	if ($handshake_file) {
   1935 		if (open(HSF, ">>$handshake_file")) {
   1936 			print HSF $str;
   1937 			close HSF;
   1938 		}
   1939 	}
   1940 }
   1941 
   1942 sub do_vencrypt_viewer_bridge {
   1943 	my ($listen, $connect) = @_;
   1944 	print STDERR "\npproxy: starting vencrypt_viewer_bridge[$$]: $listen \-> $connect\n";
   1945 	my $db = 0;
   1946 	my $backwards = 0;
   1947 	if ($listen < 0) {
   1948 		$backwards = 1;
   1949 		$listen = -$listen;
   1950 	}
   1951 	if ($handshake_file eq "") {
   1952 		die "pproxy: vencrypt_viewer_bridge[$$]: no SSVNC_PREDIGESTED_HANDSHAKE\n";
   1953 	}
   1954 	my $listen_sock;
   1955 	my $maxtry = 12;
   1956 	my $sleep = 5;
   1957 	for (my $i=0; $i < $maxtry; $i++)  {
   1958 		$listen_sock = IO::Socket::INET->new(
   1959 			Listen    => 2,
   1960 			ReuseAddr => 1,
   1961 			LocalAddr => "127.0.0.1",
   1962 			LocalPort => $listen,
   1963 			Proto     => "tcp"
   1964 		);
   1965 		if (! $listen_sock) {
   1966 			if ($i < $maxtry - 1) {
   1967 				warn "pproxy: vencrypt_viewer_bridge[$$]: $!\n";
   1968 				warn "Could not listen on port $listen, retrying in $sleep seconds... (Ctrl-C to quit)\n";
   1969 				sleep $sleep;
   1970 			}
   1971 		} else {
   1972 			last;
   1973 		}
   1974 	}
   1975 	if (! $listen_sock) {
   1976 		die "pproxy: vencrypt_viewer_bridge[$$]: $!\n";
   1977 	}
   1978 	print STDERR "pproxy: vencrypt_viewer_bridge[$$]: listening on port $listen\n\n";
   1979 	my ($viewer_sock, $ip) = $listen_sock->accept();
   1980 	my $err = $!;
   1981 	close $listen_sock;
   1982 	if (! $viewer_sock) {
   1983 		die "pproxy: vencrypt_viewer_bridge[$$]: $err\n";
   1984 	}
   1985 	if ($ENV{PPROXY_LOOP_THYSELF_MASTER}) {
   1986 		my $sml = $ENV{SSVNC_MULTIPLE_LISTEN}; 
   1987 		if ($sml ne "" && $sml ne "0") {
   1988 			setpgrp(0, 0);
   1989 			if (fork()) {
   1990 				close $viewer_sock;
   1991 				wait;
   1992 				exit 0;
   1993 			}
   1994 			if (fork()) {
   1995 				close $viewer_sock;
   1996 				exit 0;
   1997 			}
   1998 			setpgrp(0, 0);
   1999 			$parent = $$;
   2000 		}
   2001 	}
   2002 	print STDERR "vencrypt_viewer_bridge[$$]: viewer_sock $viewer_sock\n" if $db;
   2003 
   2004 	print STDERR "pproxy: vencrypt_viewer_bridge[$$]: connecting to 127.0.0.1:$connect\n";
   2005 	my $server_sock = IO::Socket::INET->new(
   2006 		PeerAddr => "127.0.0.1",
   2007 		PeerPort => $connect,
   2008 		Proto => "tcp"
   2009 	);
   2010 	print STDERR "vencrypt_viewer_bridge[$$]: server_sock $server_sock\n" if $db;
   2011 	if (! $server_sock) {
   2012 		my $err = $!;
   2013 		die "pproxy: vencrypt_viewer_bridge[$$]: $err\n";
   2014 	}
   2015 
   2016 	if ($backwards) {
   2017 		print STDERR "vencrypt_viewer_bridge[$$]: reversing roles of viewer and server.\n";
   2018 		my $t = $viewer_sock;
   2019 		$viewer_sock = $server_sock;
   2020 		$server_sock = $t;
   2021 	}
   2022 
   2023 	my %hs = ();
   2024 	my $dt = 0.2;
   2025 	my $slept = 0.0;
   2026 	while ($slept < 20.0) {
   2027 		select(undef, undef, undef, $dt);
   2028 		$slept += $dt;
   2029 		if (-f $handshake_file && open(HSF, "<$handshake_file")) {
   2030 			my $done = 0;
   2031 			%hs = ();
   2032 			my $str = "";
   2033 			while (<HSF>) {
   2034 				print STDERR "vencrypt_viewer_bridge[$$]: $_" if $ENV{VENCRYPT_VIEWER_BRIDGE_DEBUG};
   2035 				$str .= "vencrypt_viewer_bridge[$$]: $_";
   2036 				chomp;
   2037 				if ($_ eq "done") {
   2038 					$done = 1;
   2039 				} else {
   2040 					my ($k, $v) = split(/=/, $_, 2);
   2041 					if ($k ne "" && $v ne "") {
   2042 						$hs{$k} = $v;
   2043 					}
   2044 				}
   2045 			}
   2046 			close HSF;
   2047 			if ($done) {
   2048 				print STDERR "\n" . $str;
   2049 				last;
   2050 			}
   2051 		}
   2052 	}
   2053 	if (! exists $hs{server}) {
   2054 		$hs{server} = "RFB 003.008";
   2055 	}
   2056 	if (! exists $hs{sectype}) {
   2057 		unlink($handshake_file);
   2058 		die "pproxy: vencrypt_viewer_bridge[$$]: no sectype.\n";
   2059 	}
   2060 	syswrite($viewer_sock, "$hs{server}\n", length($hs{server}) + 1);
   2061 	my $viewer_rfb = "";
   2062 	for (my $i = 0; $i < 12; $i++) {
   2063 		my $c;
   2064 		sysread($viewer_sock, $c, 1);
   2065 		$viewer_rfb .= $c;
   2066 		print STDERR $c;
   2067 	}
   2068 	my $viewer_major = 3;
   2069 	my $viewer_minor = 8;
   2070 	if ($viewer_rfb =~ /RFB (\d+)\.(\d+)/) {
   2071 		$viewer_major = $1;	
   2072 		$viewer_minor = $2;	
   2073 	}
   2074 	my $u0 = pack("C", 0);
   2075 	my $u1 = pack("C", 1);
   2076 	my $u2 = pack("C", 2);
   2077 	if ($hs{sectype} == $rfbSecTypeAnonTls) {
   2078 		unlink($handshake_file);
   2079 		print STDERR "\npproxy: vencrypt_viewer_bridge[$$]: rfbSecTypeAnonTls\n";
   2080 		if ($viewer_major > 3 || $viewer_minor >= 7) {
   2081 			;	# setup ok, proceed to xfer.
   2082 		} else {
   2083 			print STDERR "pproxy: vencrypt_viewer_bridge[$$]: faking RFB version 3.3 to viewer.\n";
   2084 			my $n;
   2085 			sysread($server_sock, $n, 1);
   2086 			$n = unpack("C", $n);
   2087 			if ($n == 0) {
   2088 				die "pproxy: vencrypt_viewer_bridge[$$]: nsectypes == $n.\n";
   2089 			}
   2090 			my %types;
   2091 			for (my $i = 0; $i < $n; $i++) {
   2092 				my $t;
   2093 				sysread($server_sock, $t, 1);
   2094 				$t = unpack("C", $t);
   2095 				$types{$t} = 1;
   2096 			}
   2097 			my $use = 1;	# None
   2098 			if (exists $types{1}) {
   2099 				$use = 1;	# None
   2100 			} elsif (exists $types{2}) {
   2101 				$use = 2;	# VncAuth
   2102 			} else {
   2103 				die "pproxy: vencrypt_viewer_bridge[$$]: no valid sectypes" . join(",", keys %types) . "\n";
   2104 			}
   2105 				
   2106 			# send 4 bytes sectype to viewer: 
   2107 			# (note this should be MSB, network byte order...)
   2108 			my $up = pack("C", $use);
   2109 			syswrite($viewer_sock, $u0, 1);
   2110 			syswrite($viewer_sock, $u0, 1);
   2111 			syswrite($viewer_sock, $u0, 1);
   2112 			syswrite($viewer_sock, $up, 1);
   2113 			# and tell server the one we selected:
   2114 			syswrite($server_sock, $up, 1);
   2115 			if ($use == 1) {
   2116 				# even None has security result, so read it here and discard it.
   2117 				my $sr = "";
   2118 				sysread($server_sock, $sr, 4);
   2119 			}
   2120 		}
   2121 	} elsif ($hs{sectype} == $rfbSecTypeVencrypt) {
   2122 		print STDERR "\npproxy: vencrypt_viewer_bridge[$$]: rfbSecTypeVencrypt\n";
   2123 		if (! exists $hs{subtype}) {
   2124 			unlink($handshake_file);
   2125 			die "pproxy: vencrypt_viewer_bridge[$$]: no subtype.\n";
   2126 		}
   2127 		my $fake_type = "None";
   2128 		my $plain = 0;
   2129 		my $sub_type = $hs{subtype};
   2130 		if ($sub_type == $rfbVencryptTlsNone) {
   2131 			$fake_type = "None";
   2132 		} elsif ($sub_type == $rfbVencryptTlsVnc) {
   2133 			$fake_type = "VncAuth";
   2134 		} elsif ($sub_type == $rfbVencryptTlsPlain) {
   2135 			$fake_type = "None";
   2136 			$plain = 1;
   2137 		} elsif ($sub_type == $rfbVencryptX509None) {
   2138 			$fake_type = "None";
   2139 		} elsif ($sub_type == $rfbVencryptX509Vnc) {
   2140 			$fake_type = "VncAuth";
   2141 		} elsif ($sub_type == $rfbVencryptX509Plain) {
   2142 			$fake_type = "None";
   2143 			$plain = 1;
   2144 		}
   2145 		if ($plain) {
   2146 			if (!open(W, ">$handshake_file")) {
   2147 				unlink($handshake_file);
   2148 				die "pproxy: vencrypt_viewer_bridge[$$]: $handshake_file $!\n";
   2149 			}
   2150 			print W <<"END";
   2151 
   2152 			proc print_out {} {
   2153 				global user pass env
   2154 
   2155 				if [info exists env(SSVNC_UP_DEBUG)] {
   2156 					toplevel .b
   2157 					button .b.b -text "user=\$user pass=\$pass" -command {destroy .b}
   2158 					pack .b.b
   2159 					update
   2160 					tkwait window .b
   2161 				}
   2162 				
   2163 				if [info exists env(SSVNC_UP_FILE)] {
   2164 					set fh "" 
   2165 					catch {set fh [open \$env(SSVNC_UP_FILE) w]}
   2166 					if {\$fh != ""} {
   2167 						puts \$fh user=\$user\\npass=\$pass
   2168 						flush \$fh
   2169 						close \$fh
   2170 						return
   2171 					}
   2172 				}
   2173 				puts stdout user=\$user\\npass=\$pass
   2174 				flush stdout
   2175 			}
   2176 
   2177 			proc center_win {w} {
   2178 				update
   2179 				set W [winfo screenwidth  \$w]
   2180 				set W [expr \$W + 1]
   2181 				wm geometry \$w +\$W+0
   2182 				update
   2183 				set x [expr [winfo screenwidth  \$w]/2 - [winfo width  \$w]/2]
   2184 				set y [expr [winfo screenheight \$w]/2 - [winfo height \$w]/2]
   2185 
   2186 				wm geometry \$w +\$x+\$y
   2187 				wm deiconify \$w
   2188 				update
   2189 			}
   2190 
   2191 			wm withdraw .
   2192 
   2193 			global env
   2194 			set up {}
   2195 			if [info exists env(SSVNC_UNIXPW)] {
   2196 				set rm 0
   2197 				set up \$env(SSVNC_UNIXPW)
   2198 				if [regexp {^rm:} \$up]  {
   2199 					set rm 1
   2200 					regsub {^rm:} \$up {} up
   2201 				}
   2202 				if [file exists \$up] {
   2203 					set fh ""
   2204 					set f \$up
   2205 					catch {set fh [open \$up r]}
   2206 					if {\$fh != ""} {
   2207 						gets \$fh u	
   2208 						gets \$fh p	
   2209 						close \$fh
   2210 						set up "\$u@\$p"
   2211 					}
   2212 					if {\$rm} {
   2213 						catch {file delete \$f}
   2214 					}
   2215 				}
   2216 			} elseif [info exists env(SSVNC_VENCRYPT_USERPASS)] {
   2217 				set up \$env(SSVNC_VENCRYPT_USERPASS)
   2218 			}
   2219 			#puts stderr up=\$up
   2220 			if {\$up != ""} {
   2221 				if [regexp {@} \$up] {
   2222 					global user pass
   2223 					set user \$up
   2224 					set pass \$up
   2225 					regsub {@.*\$}  \$user "" user
   2226 					regsub {^[^@]*@} \$pass "" pass
   2227 					print_out
   2228 					exit
   2229 				}
   2230 			}
   2231 
   2232 			wm title . {VeNCrypt Viewer Bridge User/Pass}
   2233 
   2234 			set user {}
   2235 			set pass {}
   2236 
   2237 			label .l -text {SSVNC VeNCrypt Viewer Bridge}
   2238 
   2239 			frame .f0
   2240 			frame .f0.fL
   2241 			label .f0.fL.la -text {Username: }
   2242 			label .f0.fL.lb -text {Password: }
   2243 
   2244 			pack .f0.fL.la .f0.fL.lb -side top
   2245 
   2246 			frame .f0.fR
   2247 			entry .f0.fR.ea -width 24 -textvariable user
   2248 			entry .f0.fR.eb -width 24 -textvariable pass -show *
   2249 
   2250 			pack .f0.fR.ea .f0.fR.eb -side top -fill x
   2251 
   2252 			pack .f0.fL -side left
   2253 			pack .f0.fR -side right -expand 1 -fill x
   2254 
   2255 			button .no -text Cancel -command {destroy .}
   2256 			button .ok -text Done   -command {print_out; destroy .}
   2257 
   2258 			center_win .
   2259 			pack .l .f0 .no .ok -side top -fill x
   2260 			update
   2261 			wm deiconify .
   2262 
   2263 			bind .f0.fR.ea <Return> {focus .f0.fR.eb}
   2264 			bind .f0.fR.eb <Return> {print_out; destroy .}
   2265 			focus .f0.fR.ea
   2266 
   2267 			wm resizable . 1 0
   2268 			wm minsize . [winfo reqwidth .] [winfo reqheight .]
   2269 END
   2270 			close W;
   2271 
   2272 			#system("cat $handshake_file");
   2273 			my $w = "wish";
   2274 			if ($ENV{WISH}) {
   2275 				$w = $ENV{WISH};	
   2276 			}
   2277 			print STDERR "pproxy: vencrypt_viewer_bridge[$$]: prompt  VencryptPlain user and passwd.\n";
   2278 			my $res = "";
   2279 			if (`uname` =~ /Darwin/) {
   2280 				my $mtmp = `mktemp /tmp/hsup.XXXXXX`;
   2281 				chomp $mtmp;
   2282 				system("env SSVNC_UP_FILE=$mtmp $w $handshake_file");
   2283 				$res = `cat $mtmp`;
   2284 				unlink $mtmp;
   2285 			} else {
   2286 				$res = `$w $handshake_file`;
   2287 			}
   2288 			my $user = "";
   2289 			my $pass = "";
   2290 			if ($res =~ /user=(\S*)/) {
   2291 				$user = $1;
   2292 			}
   2293 			if ($res =~ /pass=(\S*)/) {
   2294 				$pass = $1;
   2295 			}
   2296 			print STDERR "pproxy: vencrypt_viewer_bridge[$$]: sending VencryptPlain user and passwd.\n";
   2297 			my $ulen = pack("C", length($user));
   2298 			my $plen = pack("C", length($pass));
   2299 			# (note this should be MSB, network byte order...)
   2300 			syswrite($server_sock, $u0, 1);
   2301 			syswrite($server_sock, $u0, 1);
   2302 			syswrite($server_sock, $u0, 1);
   2303 			syswrite($server_sock, $ulen, 1);
   2304 			syswrite($server_sock, $u0, 1);
   2305 			syswrite($server_sock, $u0, 1);
   2306 			syswrite($server_sock, $u0, 1);
   2307 			syswrite($server_sock, $plen, 1);
   2308 			syswrite($server_sock, $user, length($user));
   2309 			syswrite($server_sock, $pass, length($pass));
   2310 		}
   2311 		unlink($handshake_file);
   2312 
   2313 		my $ft = 0;
   2314 		if ($fake_type eq "None") {
   2315 			$ft = 1;
   2316 		} elsif ($fake_type eq "VncAuth") {
   2317 			$ft = 2;
   2318 		} else {
   2319 			die "pproxy: vencrypt_viewer_bridge[$$]: unknown fake type: $fake_type\n";
   2320 		}
   2321 		my $fp = pack("C", $ft);
   2322 		if ($viewer_major > 3 || $viewer_minor >= 7) {
   2323 			syswrite($viewer_sock, $u1, 1);
   2324 			syswrite($viewer_sock, $fp, 1);
   2325 			my $cr;
   2326 			sysread($viewer_sock, $cr, 1);
   2327 			$cr = unpack("C", $cr);
   2328 			if ($cr != $ft) {
   2329 				die "pproxy: vencrypt_viewer_bridge[$$]: client selected wrong type: $cr / $ft\n";
   2330 			}
   2331 		} else {
   2332 			print STDERR "pproxy: vencrypt_viewer_bridge[$$]: faking RFB version 3.3 to viewer.\n";
   2333 			# send 4 bytes sect type to viewer: 
   2334 			# (note this should be MSB, network byte order...)
   2335 			syswrite($viewer_sock, $u0, 1);
   2336 			syswrite($viewer_sock, $u0, 1);
   2337 			syswrite($viewer_sock, $u0, 1);
   2338 			syswrite($viewer_sock, $fp, 1);
   2339 			if ($ft == 1) {
   2340 				# even None has security result, so read it here and discard it.
   2341 				my $sr = "";
   2342 				sysread($server_sock, $sr, 4);
   2343 			}
   2344 		}
   2345 	}
   2346 
   2347 	$listen_handle = $viewer_sock;
   2348 	$sock = $server_sock;
   2349 
   2350 	xfer_both();
   2351 }
   2352 '
   2353 	# '
   2354 	# xpg_echo will expand \n \r, etc.
   2355 	# try to unset and then test for it.
   2356 	if type shopt > /dev/null 2>&1; then
   2357 		shopt -u xpg_echo >/dev/null 2>&1
   2358 	fi
   2359 	v='print STDOUT "abc\n";'
   2360 	echo "$v" > $tf
   2361 	chmod 700 $tf
   2362 
   2363 	lc=`wc -l $tf | awk '{print $1}'`
   2364 	if [ "X$lc" = "X1" ]; then
   2365 		echo "$cod" > $tf
   2366 	else
   2367 		printf "%s" "$cod" > $tf
   2368 		echo "" >> $tf
   2369 	fi
   2370 	# prime perl
   2371 	perl -e 'use IO::Socket::INET; select(undef, undef, undef, 0.01)' >/dev/null 2>&1
   2372 }
   2373 
   2374 # make_tcert is no longer invoked via the ssvnc gui (Listen mode).
   2375 # make_tcert is for testing only now via -mycert BUILTIN
   2376 make_tcert() {
   2377 	tcert="/tmp/ss_vnc_viewer_tcert${RANDOM}.$$"
   2378 	tcert=`mytmp "$tcert"`
   2379 	cat > $tcert <<END
   2380 -----BEGIN RSA PRIVATE KEY-----
   2381 MIIEowIBAAKCAQEAvkfXxb0wcxgrjV2ziFikjII+ze8iKcTBt47L0GM/c21efelN
   2382 +zZpJUUXLu4zz8Ryq8Q+sQgfNy7uTOpN9bUUaOk1TnD7gaDQnQWiNHmqbW2kL+DS
   2383 OKngJVPo9dETAS8hf7+D1e1DBZxjTc1a4RQqWJixwpYj99ixWzu8VC2m/xXsjvOs
   2384 jp4+DLBB490nbkwvstmhmiWm1CmI5O5xOkgioVNQqHvQMdVKOSz9PpbjvZiRX1Uo
   2385 qoMrk+2NOqwP90TB35yPASXb9zXKpO7DLhkube+yYGf+yk46aD707L07Eb7cosFP
   2386 S84vNZ9gX7rQ0UOwm5rYA/oZTBskgaqhtIzkLwIDAQABAoIBAD4ot/sXt5kRn0Ca
   2387 CIkU9AQWlC+v28grR2EQW9JiaZrqcoDNUzUqbCTJsi4ZkIFh2lf0TsqELbZYNW6Y
   2388 6AjJM7al4E0UqYSKJTv2WCuuRxdiRs2BMwthqyBmjeanev7bB6V0ybt7u3Y8xU/o
   2389 MrTuYnr4vrEjXPKdLirwk7AoDbKsRXHSIiHEIBOq1+dUQ32t36ukdnnza4wKDLZc
   2390 PKHiCdCk/wOGhuDlxD6RspqUAlRnJ8/aEhrgWxadFXw1hRhRsf/v1shtB0T3DmTe
   2391 Jchjwyiw9mryb9JZAcKxW+fUc4EVvj6VdQGqYInQJY5Yxm5JAlVQUJicuuJEvn6A
   2392 rj5osQECgYEA552CaHpUiFlB4HGkjaH00kL+f0+gRF4PANCPk6X3UPDVYzKnzmuu
   2393 yDvIdEETGFWBwoztUrOOKqVvPEQ+kBa2+DWWYaERZLtg2cI5byfDJxQ3ldzilS3J
   2394 1S3WgCojqcsG/hlxoQJ1dZFanUy/QhUZ0B+wlC+Zp1Q8AyuGQvhHp68CgYEA0lBI
   2395 eqq2GGCdJuNHMPFbi8Q0BnX55LW5C1hWjhuYiEkb3hOaIJuJrqvayBlhcQa2cGqp
   2396 uP34e9UCfoeLgmoCQ0b4KpL2NGov/mL4i8bMgog4hcoYuIi3qxN18vVR14VKEh4U
   2397 RLk0igAYPU+IK2QByaQlBo9OSaKkcfm7U1/pK4ECgYAxr6VpGk0GDvfF2Tsusv6d
   2398 GIgV8ZP09qSLTTJvvxvF/lQYeqZq7sjI5aJD5i3de4JhpO/IXQJzfZfWOuGc8XKA
   2399 3qYK/Y2IqXXGYRcHFGWV/Y1LFd55mCADHlk0l1WdOBOg8P5iRu/Br9PbiLpCx9oI
   2400 vrOXpnp03eod1/luZmqguwKBgQCWFRSj9Q7ddpSvG6HCG3ro0qsNsUMTI1tZ7UBX
   2401 SPogx4tLf1GN03D9ZUZLZVFUByZKMtPLX/Hi7K9K/A9ikaPrvsl6GEX6QYzeTGJx
   2402 3Pw0amFrmDzr8ySewNR6/PXahxPEuhJcuI31rPufRRI3ZLah3rFNbRbBFX+klkJH
   2403 zTnoAQKBgDbUK/aQFGduSy7WUT7LlM3UlGxJ2sA90TQh4JRQwzur0ACN5GdYZkqM
   2404 YBts4sBJVwwJoxD9OpbvKu3uKCt41BSj0/KyoBzjT44S2io2tj1syujtlVUsyyBy
   2405 /ca0A7WBB8lD1D7QMIhYUm2O9kYtSCLlUTHt5leqGaRG38DqlX36
   2406 -----END RSA PRIVATE KEY-----
   2407 -----BEGIN CERTIFICATE-----
   2408 MIIDzDCCArQCCQDSzxzxqhyqLzANBgkqhkiG9w0BAQQFADCBpzELMAkGA1UEBhMC
   2409 VVMxFjAUBgNVBAgTDU1hc3NhY2h1c2V0dHMxDzANBgNVBAcTBkJvc3RvbjETMBEG
   2410 A1UEChMKTXkgQ29tcGFueTEcMBoGA1UECxMTUHJvZHVjdCBEZXZlbG9wbWVudDEZ
   2411 MBcGA1UEAxMQd3d3Lm5vd2hlcmUubm9uZTEhMB8GCSqGSIb3DQEJARYSYWRtaW5A
   2412 bm93aGVyZS5ub25lMB4XDTA3MDMyMzE4MDc0NVoXDTI2MDUyMjE4MDc0NVowgacx
   2413 CzAJBgNVBAYTAlVTMRYwFAYDVQQIEw1NYXNzYWNodXNldHRzMQ8wDQYDVQQHEwZC
   2414 b3N0b24xEzARBgNVBAoTCk15IENvbXBhbnkxHDAaBgNVBAsTE1Byb2R1Y3QgRGV2
   2415 ZWxvcG1lbnQxGTAXBgNVBAMTEHd3dy5ub3doZXJlLm5vbmUxITAfBgkqhkiG9w0B
   2416 CQEWEmFkbWluQG5vd2hlcmUubm9uZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
   2417 AQoCggEBAL5H18W9MHMYK41ds4hYpIyCPs3vIinEwbeOy9BjP3NtXn3pTfs2aSVF
   2418 Fy7uM8/EcqvEPrEIHzcu7kzqTfW1FGjpNU5w+4Gg0J0FojR5qm1tpC/g0jip4CVT
   2419 6PXREwEvIX+/g9XtQwWcY03NWuEUKliYscKWI/fYsVs7vFQtpv8V7I7zrI6ePgyw
   2420 QePdJ25ML7LZoZolptQpiOTucTpIIqFTUKh70DHVSjks/T6W472YkV9VKKqDK5Pt
   2421 jTqsD/dEwd+cjwEl2/c1yqTuwy4ZLm3vsmBn/spOOmg+9Oy9OxG+3KLBT0vOLzWf
   2422 YF+60NFDsJua2AP6GUwbJIGqobSM5C8CAwEAATANBgkqhkiG9w0BAQQFAAOCAQEA
   2423 vGomHEp6TVU83X2EBUgnbOhzKJ9u3fOI/Uf5L7p//Vxqow7OR1cguzh/YEzmXOIL
   2424 ilMVnzX9nj/bvcLAuqEP7MR1A8f4+E807p/L/Sf49BiCcwQq5I966sGKYXjkve+T
   2425 2GTBNwMSq+5kLSf6QY8VZI+qnrAudEQMeJByQhTZZ0dH8Njeq8EGl9KUio+VWaiW
   2426 CQK6xJuAvAHqa06OjLmwu1fYD4GLGSrOIiRVkSXV8qLIUmzxdJaIRznkFWsrCEKR
   2427 wAH966SAOvd2s6yOHMvyDRIL7WHxfESB6rDHsdIW/yny1fBePjv473KrxyXtbz7I
   2428 dMw1yW09l+eEo4A7GzwOdw==
   2429 -----END CERTIFICATE-----
   2430 END
   2431 	chmod 600 $tcert
   2432 	echo "$tcert"
   2433 }
   2434 
   2435 Kecho() {
   2436 	NO_KECHO=1
   2437 	if [ "X$USER" = "Xrunge" -a "X$NO_KECHO" = "X" ]; then
   2438 		echo "dbg: $*"
   2439 	fi
   2440 }
   2441 
   2442 NHAFL_warning() {
   2443 	echo "" 
   2444 	echo "** Warning: For the proxy: $proxy" 
   2445 	echo "** Warning: the ssh(1) option: $ssh_NHAFL" 
   2446 	echo "** Warning: will be used to avoid frequent 'ssh key has changed for localhost'"
   2447 	echo "** Warning: dialogs and connection failures (for example, ssh will exit asking"
   2448 	echo "** Warning: you to manually remove a key from ~/.ssh/known_hosts.)"
   2449 	echo "** Warning: "
   2450 	echo "** Warning: This decreases security: a Man-In-The-Middle attack is possible."
   2451 	echo "** Warning: For chained ssh connections the first ssh leg is secure but the"
   2452 	echo "** Warning: 2nd ssh leg is vulnerable.  For an ssh connection going through"
   2453 	echo "** Warning: a HTTP or SOCKS proxy the ssh connection is vulnerable."
   2454 	echo "** Warning: "
   2455 	echo "** Warning: You can set the SSVNC_SSH_LOCALHOST_AUTH=1 env. var. to disable" 
   2456 	echo "** Warning: using the NoHostAuthenticationForLocalhost=yes ssh option." 
   2457 	echo "** Warning: "
   2458 	echo "** Warning: A better solution is to configure (in the SSVNC GUI) the setting:"
   2459 	echo "** Warning: 'Options -> Advanced -> Private SSH KnownHosts file' (or set" 
   2460 	echo "** Warning: SSVNC_KNOWN_HOSTS_FILE directly) to a per-connection known hosts" 
   2461 	echo "** Warning: file.  That file holds the 'localhost' cert for this specific" 
   2462 	echo "** Warning: connection.  This yields a both secure and convenient solution." 
   2463 	echo "" 
   2464 }
   2465 
   2466 space_expand() {
   2467 	str=`echo "$1" | sed -e 's/%SPACE/ /g' -e 's/%TAB/\t/g'`
   2468 	echo "$str"
   2469 }
   2470 
   2471 # handle ssh case:
   2472 #
   2473 if [ "X$use_ssh" = "X1" ]; then
   2474 	#
   2475 	# USING SSH
   2476 	#
   2477 	ssh_port="22"
   2478 	ssh_host="$host"
   2479 	vnc_host="$localhost"
   2480 	ssh_UKHF=""
   2481 	localhost_extra=""
   2482 	# let user override ssh via $SSH
   2483 	ssh=${SSH:-"ssh -x"}
   2484 
   2485 	sshword=`echo "$ssh" | awk '{print $1}'`
   2486 	if [ "X$sshword" != "X" ]; then
   2487 		if [ -x "$sshword" ]; then
   2488 			:
   2489 		elif type "$sshword" > /dev/null 2>&1; then
   2490 			:
   2491 		else
   2492 			echo ""
   2493 			echo "*********************************************************"
   2494 			echo "** Problem finding the SSH command '$sshword': **"
   2495 			echo ""
   2496 			type "$sshword"
   2497 			echo ""
   2498 			echo "** Perhaps you need to install the SSH client package. **"
   2499 			echo "*********************************************************"
   2500 			echo ""
   2501 			sleep 5
   2502 		fi
   2503 	fi
   2504 
   2505 	ssh_NHAFL="-o NoHostAuthenticationForLocalhost=yes"
   2506 	if [ "X$SSVNC_SSH_LOCALHOST_AUTH" = "X1" ]; then
   2507 		ssh_NHAFL=""
   2508 	fi
   2509 	if [ "X$SSVNC_KNOWN_HOSTS_FILE" != "X" ]; then
   2510 		ssh_NHAFL=""
   2511 	
   2512 		ssh_UKHF="-o UserKnownHostsFile=$SSVNC_KNOWN_HOSTS_FILE"
   2513 		ssh_args="$ssh_args $ssh_UKHF"
   2514 		if [ ! -f "$SSVNC_KNOWN_HOSTS_FILE" ]; then
   2515 			touch "$SSVNC_KNOWN_HOSTS_FILE" >/dev/null 2>&1
   2516 		fi
   2517 		chmod 600 "$SSVNC_KNOWN_HOSTS_FILE" >/dev/null 2>&1
   2518 	fi
   2519 	did_ssh_NHAFL=""
   2520 
   2521 	if [ "X$SSVNC_LIM_ACCEPT_PRELOAD" != "X" ]; then
   2522 		SSVNC_LIM_ACCEPT_PRELOAD="$SSVNC_BASEDIR/$SSVNC_UNAME/$SSVNC_LIM_ACCEPT_PRELOAD"
   2523 	fi
   2524 	if [ "X$SSVNC_LIM_ACCEPT_PRELOAD" != "X" ]; then
   2525 		echo ""
   2526 		echo "SSVNC_LIM_ACCEPT_PRELOAD=$SSVNC_LIM_ACCEPT_PRELOAD"
   2527 	fi
   2528 
   2529 	if [ "X$SSVNC_LIM_ACCEPT_PRELOAD" != "X" -a -f "$SSVNC_LIM_ACCEPT_PRELOAD" ]; then
   2530 		plvar=LD_PRELOAD
   2531 		if uname | grep Darwin >/dev/null; then
   2532 			plvar="DYLD_FORCE_FLAT_NAMESPACE=1 DYLD_INSERT_LIBRARIES"
   2533 		fi
   2534 		ssh="env $plvar=$SSVNC_LIM_ACCEPT_PRELOAD $ssh"
   2535 	else
   2536 		SSVNC_LIM_ACCEPT_PRELOAD=""
   2537 	fi
   2538 
   2539 	ssh_vencrypt_proxy=""
   2540 	# We handle vencrypt for SSH+SSL mode.
   2541 	if echo "$proxy" | grep 'vencrypt://' > /dev/null; then
   2542 		proxynew=""
   2543 		for part in `echo "$proxy" | tr ',' ' '`
   2544 		do
   2545 			if echo "$part" | egrep -i '^vencrypt://' > /dev/null; then
   2546 				ssh_vencrypt_proxy=$part
   2547 			else
   2548 				if [ "X$proxynew" = "X" ]; then
   2549 					proxynew="$part"
   2550 				else
   2551 					proxynew="$proxynew,$part"
   2552 				fi
   2553 			fi
   2554 		done
   2555 		proxy=$proxynew
   2556 	fi 
   2557 	Kecho ssh_vencrypt_proxy=$ssh_vencrypt_proxy
   2558 
   2559 	# note that user must supply http:// for web proxy in SSH and SSH+SSL.
   2560 	# No xxxx:// implies ssh server+port.
   2561 	#
   2562 	if echo "$proxy" | egrep '(http|https|socks|socks4|socks5)://' > /dev/null; then
   2563 		# Handle Web or SOCKS proxy(ies) for the initial connect.
   2564 		Kecho host=$host
   2565 		Kecho port=$port
   2566 		pproxy=""
   2567 		sproxy1=""
   2568 		sproxy_rest=""
   2569 		for part in `echo "$proxy" | tr ',' ' '`
   2570 		do
   2571 			Kecho proxy_part=$part
   2572 			if [ "X$part" = "X" ]; then
   2573 				continue
   2574 			elif echo "$part" | egrep -i '^(http|https|socks|socks4|socks5)://' > /dev/null; then
   2575 				pproxy="$pproxy,$part"
   2576 			else
   2577 				if [ "X$sproxy1" = "X" ]; then
   2578 					sproxy1="$part"
   2579 				else
   2580 					sproxy_rest="$sproxy_rest,$part"
   2581 				fi
   2582 			fi
   2583 		done
   2584 		pproxy=`echo "$pproxy" | sed -e 's/^,,*//' -e 's/,,*/,/g'`
   2585 		sproxy_rest=`echo "$sproxy_rest" | sed -e 's/^,,*//' -e 's/,,*/,/g'`
   2586 
   2587 		Kecho pproxy=$pproxy
   2588 		Kecho sproxy1=$sproxy1
   2589 		Kecho sproxy_rest=$sproxy_rest
   2590 
   2591 		sproxy1_host=""
   2592 		sproxy1_port=""
   2593 		sproxy1_user=""
   2594 
   2595 		if [ "X$sproxy1" != "X" ]; then
   2596 			# XXX fix ipv6 ip adder here and below.
   2597 			sproxy1_host=`echo "$sproxy1" | awk -F: '{print $1}'`
   2598 			sproxy1_user=`echo "$sproxy1_host" | awk -F@ '{print $1}'`
   2599 			sproxy1_host=`echo "$sproxy1_host" | awk -F@ '{print $2}'`
   2600 			if [ "X$sproxy1_host" = "X" ]; then
   2601 				sproxy1_host=$sproxy1_user
   2602 				sproxy1_user=""
   2603 			else
   2604 				sproxy1_user="${sproxy1_user}@"
   2605 			fi
   2606 			sproxy1_port=`echo "$sproxy1" | awk -F: '{print $2}'`
   2607 			if [ "X$sproxy1_port" = "X" ]; then
   2608 				sproxy1_port="22"
   2609 			fi
   2610 		else
   2611 			sproxy1_host=`echo "$host" | awk -F: '{print $1}'`
   2612 			sproxy1_user=`echo "$sproxy1_host" | awk -F@ '{print $1}'`
   2613 			sproxy1_host=`echo "$sproxy1_host" | awk -F@ '{print $2}'`
   2614 			if [ "X$sproxy1_host" = "X" ]; then
   2615 				sproxy1_host=$sproxy1_user
   2616 				sproxy1_user=""
   2617 			else
   2618 				sproxy1_user="${sproxy1_user}@"
   2619 			fi
   2620 			sproxy1_port=`echo "$host" | awk -F: '{print $2}'`
   2621 			if [ "X$sproxy1_port" = "X" ]; then
   2622 				sproxy1_port="22"
   2623 			fi
   2624 		fi
   2625 
   2626 		Kecho sproxy1_host=$sproxy1_host
   2627 		Kecho sproxy1_port=$sproxy1_port
   2628 		Kecho sproxy1_user=$sproxy1_user
   2629 
   2630 		ptmp="/tmp/ss_vncviewer_ssh${RANDOM}.$$.pl"
   2631 		ptmp=`mytmp "$ptmp"`
   2632 		PPROXY_REMOVE=1; export PPROXY_REMOVE
   2633 		proxy=$pproxy
   2634 		port_save=$port
   2635 		host_save=$host
   2636 		if [ "X$sproxy1_host" != "X" ]; then
   2637 			host=$sproxy1_host
   2638 		fi
   2639 		if [ "X$sproxy1_port" != "X" ]; then
   2640 			port=$sproxy1_port
   2641 		fi
   2642 		host=`echo "$host" | sed -e 's/^.*@//'`
   2643 		port=`echo "$port" | sed -e 's/^.*://'`
   2644 		pcode "$ptmp"
   2645 		port=$port_save
   2646 		host=$host_save
   2647 
   2648 		nd=`findfree 6600`
   2649 		PPROXY_LISTEN=$nd; export PPROXY_LISTEN
   2650 		# XXX no reverse forever PPROXY_LOOP_THYSELF ...
   2651 		$ptmp &
   2652 		sleep 1
   2653 		if [ "X$ssh_NHAFL" != "X" -a "X$did_ssh_NHAFL" != "X1" ]; then
   2654 			NHAFL_warning
   2655 			ssh_args="$ssh_args $ssh_NHAFL"
   2656 			did_ssh_NHAFL=1
   2657 		fi
   2658 		sleep 1
   2659 		if [ "X$sproxy1" = "X" ]; then
   2660 			u=""
   2661 			if echo "$host" | grep '@' > /dev/null; then
   2662 				u=`echo "$host" | sed -e 's/@.*$/@/'`
   2663 			fi
   2664 			
   2665 			proxy="${u}$localhost:$nd"
   2666 		else
   2667 			proxy="${sproxy1_user}$localhost:$nd"
   2668 		fi
   2669 		localhost_extra=".2"
   2670 		if [ "X$sproxy_rest" != "X" ]; then
   2671 			proxy="$proxy,$sproxy_rest"
   2672 		fi
   2673 		Kecho proxy=$proxy
   2674 	fi
   2675 
   2676 	if echo "$proxy" | grep "," > /dev/null; then
   2677 
   2678 		proxy1=`echo "$proxy" | awk -F, '{print $1}'`
   2679 		proxy2=`echo "$proxy" | awk -F, '{print $2}'`
   2680 
   2681 		# user1 (at] gw1.com:port1,user2@ws2:port2
   2682 		ssh_host1=`echo "$proxy1" | awk -F: '{print $1}'`
   2683 		ssh_port1=`echo "$proxy1" | awk -F: '{print $2}'`
   2684 		if [ "X$ssh_port1" != "X" ]; then
   2685 			ssh_port1="-p $ssh_port1"
   2686 		fi
   2687 		ssh_host2=`echo "$proxy2" | awk -F: '{print $1}'`
   2688 		ssh_user2=`echo "$ssh_host2" | awk -F@ '{print $1}'`
   2689 		ssh_host2=`echo "$ssh_host2" | awk -F@ '{print $2}'`
   2690 		if [ "X$ssh_host2" = "X" ]; then
   2691 			ssh_host2=$ssh_user2
   2692 			ssh_user2=""
   2693 		else
   2694 			ssh_user2="${ssh_user2}@"
   2695 		fi
   2696 		ssh_port2=`echo "$proxy2" | awk -F: '{print $2}'`
   2697 		if [ "X$ssh_port2" = "X" ]; then
   2698 			ssh_port2="22"
   2699 		fi
   2700 		proxport=`findfree 3500`
   2701 		if [ "X$ssh_NHAFL" != "X" -a "X$did_ssh_NHAFL" != "X1" ]; then
   2702 			NHAFL_warning
   2703 			did_ssh_NHAFL=1
   2704 			sleep 1
   2705 		fi
   2706 		echo
   2707 		echo "Running 1st ssh proxy:"
   2708 		ukhf=""
   2709 		if [ "X$ssh_UKHF" != "X" ]; then 
   2710 			ukhf="$ssh_UKHF$localhost_extra"
   2711 		fi
   2712 		if echo "$ssh_host1" | grep '%' > /dev/null; then
   2713 			uath=`space_expand "$ssh_host1"`
   2714 		else
   2715 			uath="$ssh_host1"
   2716 		fi
   2717 		echo "$ssh -f -x $ssh_port1 $targ -e none $ssh_NHAFL $ukhf -L $proxport:$ssh_host2:$ssh_port2 \"$uath\" \"sleep 30\""
   2718 		echo ""
   2719 		      $ssh -f -x $ssh_port1 $targ -e none $ssh_NHAFL $ukhf -L $proxport:$ssh_host2:$ssh_port2 "$uath" "sleep 30"
   2720 		ssh_args="$ssh_args $ssh_NHAFL"
   2721 		sleep 1
   2722 		stty sane
   2723 		proxy="${ssh_user2}$localhost:$proxport"
   2724 	fi
   2725 
   2726 	if [ "X$proxy" != "X" ]; then
   2727 		ssh_port=`echo "$proxy" | awk -F: '{print $2}'`
   2728 		if [ "X$ssh_port" = "X" ]; then
   2729 			ssh_port="22"
   2730 		fi
   2731 		ssh_host=`echo "$proxy" | awk -F: '{print $1}'`
   2732 		vnc_host="$host"
   2733 	fi
   2734 
   2735 	echo ""
   2736 	echo "Running ssh:"
   2737 	sz=`echo "$ssh_cmd" | wc -c`
   2738 	if [ "$sz" -gt 300 ]; then
   2739 		info="..."
   2740 	else
   2741 		info="$ssh_cmd"
   2742 	fi
   2743 
   2744 	C=""
   2745 	if [ "X$SS_VNCVIEWER_USE_C" != "X" ]; then
   2746 		C="-C"
   2747 	fi
   2748 
   2749 	getport=""
   2750 	teeport=""
   2751 	if echo "$ssh_cmd" | egrep "(PORT=|P=) " > /dev/null; then
   2752 		getport=1
   2753 		if echo "$ssh_cmd" | egrep "P= " > /dev/null; then
   2754 			teeport=1
   2755 		fi
   2756 
   2757 		PORT=""
   2758 		ssh_cmd=`echo "$ssh_cmd" | sed -e 's/PORT=[ 	]*//' -e 's/P=//'`
   2759 		SSVNC_NO_ENC_WARN=1
   2760 		if [ "X$use_sshssl" = "X" ]; then
   2761 			direct_connect=1
   2762 		fi
   2763 	fi
   2764 	if [ "X$getport" != "X" ]; then
   2765 		ssh_redir="-D ${use}"
   2766 	elif [ "X$reverse" = "X" ]; then
   2767 		ssh_redir="-L ${use}:${vnc_host}:${port}"
   2768 	else
   2769 		ssh_redir="-R ${port}:${vnc_host}:${use}"
   2770 	fi
   2771 	pmark=`sh -c 'echo $$'`
   2772 
   2773 	# the -t option actually speeds up typing response via VNC!!
   2774 	if [ "X$ssh_port" = "X22" ]; then
   2775 		ssh_port=""
   2776 	else
   2777 		ssh_port="-p $ssh_port"
   2778 	fi
   2779 
   2780 	if echo "$ssh_host" | grep '%' > /dev/null; then
   2781 		uath=`space_expand "$ssh_host"`
   2782 	else
   2783 		uath="$ssh_host"
   2784 	fi
   2785 	if [ "X$SS_VNCVIEWER_SSH_ONLY" != "X" ]; then
   2786 		echo "$ssh -x $ssh_port $targ $C $ssh_args \"$uath\" \"$info\""
   2787 		echo ""
   2788 		$ssh -x $ssh_port $targ $C $ssh_args "$uath" "$ssh_cmd"
   2789 		exit $?
   2790 
   2791 	elif [ "X$SS_VNCVIEWER_NO_F" != "X" ]; then
   2792 		echo "$ssh -x $ssh_port $targ $C $ssh_redir $ssh_args \"$uath\" \"$info\""
   2793 		echo ""
   2794 		$ssh -x $ssh_port $targ $C $ssh_redir $ssh_args "$uath" "$ssh_cmd"
   2795 		rc=$?
   2796 
   2797 	elif [ "X$getport" != "X" ]; then
   2798 		tport=/tmp/ss_vncviewer_tport${RANDOM}.$$
   2799 		tport=`mytmp "$tport"`
   2800 		tport2=/tmp/ss_vncviewer_tport2${RANDOM}.$$
   2801 		tport2=`mytmp "$tport2"`
   2802 
   2803 		if [ "X$rsh" != "X1" ]; then
   2804 			if echo "$ssh_cmd" | grep "sudo " > /dev/null; then
   2805 				echo ""
   2806 				echo "Initial ssh with 'sudo id' to prime sudo so hopefully the next one"
   2807 				echo "will require no password..."
   2808 				echo ""
   2809 				targ="-t"
   2810 				$ssh -x $ssh_port $targ $ssh_args "$uath" "sudo id; tty"
   2811 				echo ""
   2812 			fi
   2813 			echo "$ssh -x -f $ssh_port $targ $C $ssh_redir $ssh_args \"$uath\" \"$info\""
   2814 			echo ""
   2815 			$ssh -x -f $ssh_port $targ $C $ssh_redir $ssh_args "$uath" "$ssh_cmd" > $tport 2> $tport2
   2816 			if [ "X$teeport" = "X1" ]; then
   2817 				tail -f $tport  1>&2 &
   2818 				tail_pid=$!
   2819 				tail -f $tport2 1>&2 &
   2820 				tail_pid2=$!
   2821 			fi
   2822 			rc=$?
   2823 		else
   2824 			rsh_setup
   2825 			echo "rsh $ul \"$ssh_host\" \"$ssh_cmd\""
   2826 			echo ""
   2827 			rsh $ul "$ssh_host" "$ssh_cmd" > $tport &
   2828 			sleep 1
   2829 			rc=0
   2830 		fi
   2831 
   2832 		if [ "X$SSVNC_EXTRA_SLEEP" != "X" ]; then
   2833 			echo "sleep $SSVNC_EXTRA_SLEEP"
   2834 			sleep $SSVNC_EXTRA_SLEEP
   2835 		fi
   2836 
   2837 		stty sane
   2838 		i=0
   2839 		if type perl > /dev/null 2>&1; then
   2840 			imax=50
   2841 			sleepit="perl -e 'select(undef, undef, undef, 0.20)'"
   2842 		else
   2843 			imax=10
   2844 			sleepit="sleep 1"
   2845 		fi
   2846 		while [ $i -lt $imax ]; do
   2847 			#echo $sleepit
   2848 			eval $sleepit
   2849 			PORT=`grep "^PORT=" $tport | tr '\r' ' ' | head -n 1 | sed -e 's/PORT=//' -e 's/\r//g' -e 's/ *$//'`
   2850 			if echo "$PORT" | grep '^[0-9][0-9]*$' > /dev/null; then
   2851 				break
   2852 			fi
   2853 			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}'`
   2854 			if [ "X$vnss" != "X" ]; then
   2855 				PORT=`echo "$vnss" | awk -F: '{print $2}'`
   2856 				if echo "$PORT" | grep '^[0-9][0-9]*$' > /dev/null; then
   2857 					if [ $PORT -lt 100 ]; then
   2858 						PORT=`expr $PORT + 5900`
   2859 					fi
   2860 				fi
   2861 				if echo "$PORT" | grep '^[0-9][0-9]*$' > /dev/null; then
   2862 					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`
   2863 					echo "vncserver string: $vnss" 1>&2
   2864 					break
   2865 				fi
   2866 			fi
   2867 			i=`expr $i + 1`
   2868 		done
   2869 
   2870 		echo "found: PORT='$PORT'" 1>&2
   2871 		lh6=""
   2872 		if [ "X$SSVNC_PORT_IPV6" != "X" ]; then
   2873 			lh6=1
   2874 		elif egrep 'Info: listening on IPv6 only|Info: listening only on IPv6' $tport > /dev/null; then
   2875 			lh6=1
   2876 		fi
   2877 		if [ "X$lh6" = "X1" ]; then
   2878 			echo "set SOCKS5 localhost to ::1" 1>&2
   2879 		fi
   2880 		rm -f $tport $tport2
   2881 		if [ "X$rsh" = "X1" ]; then
   2882 			rsh_viewer "$@"
   2883 			exit $?
   2884 		fi
   2885 		PPROXY_SOCKS=5
   2886 		if [ "X$SSVNC_SOCKS5" != "X" ]; then
   2887 			PPROXY_SOCKS=5
   2888 		elif [ "X$SSVNC_SOCKS4" != "X" ]; then
   2889 			PPROXY_SOCKS=1
   2890 		fi
   2891 		export PPROXY_SOCKS
   2892 		if [ "X$lh6" = "X" ]; then
   2893 			host="$localhost"
   2894 		else
   2895 			host="::1"
   2896 		fi
   2897 		port="$PORT"
   2898 		proxy="$localhost:$use"
   2899 
   2900 	else
   2901 		if [ "X$rsh" != "X1" ]; then
   2902 			echo "$ssh -x -f $ssh_port $targ $C $ssh_redir $ssh_args \"$uath\" \"$info\""
   2903 			echo ""
   2904 			$ssh -x -f $ssh_port $targ $C $ssh_redir $ssh_args "$uath" "$ssh_cmd"
   2905 			rc=$?
   2906 		else
   2907 			rsh_setup
   2908 			echo "rsh $ul \"$ssh_host\" \"$ssh_cmd\""
   2909 			echo ""
   2910 			rsh $ul "$ssh_host" "$ssh_cmd" &
   2911 			sleep 1
   2912 			PORT=$port
   2913 			rsh_viewer "$@"
   2914 			exit $?
   2915 		fi
   2916 	fi
   2917 
   2918 	if [ "$rc" != "0" ]; then
   2919 		echo ""
   2920 		echo "ssh to \"$uath\" failed."
   2921 		exit 1
   2922 	fi
   2923 	stty sane
   2924 
   2925 	c=0
   2926 	pssh=""
   2927 	while [ $c -lt 40 ]
   2928 	do
   2929 		p=`expr $pmark + $c`
   2930 		pout=`ps -p "$p" 2>/dev/null | grep -v '^[ 	]*PID' | sed -e 's/-L.*$//' -e 's/-x .*$//'`
   2931 		if echo "$pout" | grep "ssh" > /dev/null; then
   2932 			if echo "$pout" | egrep -i 'ssh.*(-add|-agent|-ask|-keygen|-argv0|vnc)' >/dev/null; then
   2933 				:
   2934 			elif echo "$pout" | egrep -i 'scp|sshd' >/dev/null; then
   2935 				:
   2936 			else
   2937 				pssh=$p
   2938 				break
   2939 			fi
   2940 		fi
   2941 		c=`expr $c + 1`
   2942 	done
   2943 	if [ "X$getport" != "X" ]; then
   2944 		:
   2945 	elif [ "X$SSVNC_LIM_ACCEPT_PRELOAD" != "X" ] ; then
   2946 		sleep 2
   2947 	elif [ "X$ssh_cmd" = "Xsleep $ssh_sleep" ] ; then
   2948 		#echo T sleep 1
   2949 		sleep 1
   2950 	elif echo "$ssh_cmd" | grep '^sleep ' >/dev/null; then
   2951 		#echo T sleep 2
   2952 		sleep 2
   2953 	else
   2954 		# let any command get started a bit.
   2955 		#echo T sleep 5
   2956 		sleep 5
   2957 	fi
   2958 	echo ""
   2959 	#reset
   2960 	stty sane
   2961 	if [ "X$SSVNC_EXTRA_SLEEP" != "X" ]; then
   2962 		echo "sleep $SSVNC_EXTRA_SLEEP"
   2963 		sleep $SSVNC_EXTRA_SLEEP
   2964 	fi
   2965 	echo "ssh_pid='$pssh'"; echo
   2966 	if [ "X$use_sshssl" = "X" -a "X$getport" = "X" ]; then
   2967 		if [ "X$SSVNC_EXTRA_COMMAND" != "X" ]; then
   2968 			(sh -c "$SSVNC_EXTRA_COMMAND") &
   2969 			echo "($SSVNC_EXTRA_COMMAND) &"; echo
   2970 		fi
   2971 		echo "Running viewer:"
   2972 
   2973 		trap "final" 0 2 15
   2974 		if [ "X$reverse" = "X" ]; then
   2975 			echo "$VNCVIEWERCMD" "$@" $localhost:$N
   2976 			echo ""
   2977 			$VNCVIEWERCMD "$@" $localhost:$N
   2978 			if [ $? != 0 ]; then
   2979 				echo "vncviewer command failed: $?"
   2980 				if [ "X$secondtry" = "X1" ]; then
   2981 					sleep 2
   2982 					$VNCVIEWERCMD "$@" $localhost:$N
   2983 				fi
   2984 			fi
   2985 		else
   2986 			echo ""
   2987 			echo "NOTE: Press Ctrl-C to terminate viewer LISTEN mode."
   2988 			echo ""
   2989 			N2=$N
   2990 			if [ "X$VNCVIEWER_IS_REALVNC4" = "X1" ]; then
   2991 				N2=`echo "$N2" | sed -e 's/://g'`
   2992 				if [ $N2 -le 200 ]; then
   2993 					N2=`expr $N2 + 5500`
   2994 				fi
   2995 			fi
   2996 			echo "$VNCVIEWERCMD" "$@" -listen $N2
   2997 			echo ""
   2998 			$VNCVIEWERCMD "$@" -listen $N2
   2999 		fi
   3000 
   3001 		exit $?
   3002 	else
   3003 		use2=`findfree 5960`
   3004 		host0=$host
   3005 		port0=$port
   3006 		host=$localhost
   3007 		port=$use
   3008 		use=$use2
   3009 		N=`expr $use - 5900`
   3010 		if [ "X$getport" != "X" ]; then
   3011 			host="$host0"
   3012 			port="$port0"
   3013 		else
   3014 			proxy=""
   3015 		fi
   3016 		if [ "X$ssh_vencrypt_proxy" != "X" ]; then
   3017 			ssh_vencrypt_proxy="vencrypt://$host:$port"
   3018 			if [ "X$proxy" = "X" ]; then
   3019 				proxy=$ssh_vencrypt_proxy
   3020 			else
   3021 				proxy="$proxy,$ssh_vencrypt_proxy"
   3022 			fi
   3023 			Kecho "proxy_now=$proxy"
   3024 			unset PPROXY_LISTEN
   3025 		fi
   3026 	fi
   3027 fi
   3028 
   3029 if [ "X$stunnel_set_here" = "X1" -a "X$showcert" = "X" ]; then
   3030 	if type $STUNNEL > /dev/null 2>&1; then
   3031 		:
   3032 	else
   3033 		echo ""
   3034 		echo "***************************************************************"
   3035 		echo "** Problem finding the Stunnel command '$STUNNEL': **"
   3036 		echo ""
   3037 		type $STUNNEL
   3038 		echo ""
   3039 		echo "** Perhaps you need to install the stunnel/stunnel4 package. **"
   3040 		echo "***************************************************************"
   3041 		echo ""
   3042 		sleep 5
   3043 	fi
   3044 fi
   3045 
   3046 # create the stunnel config file:
   3047 if [ "X$verify" != "X" ]; then
   3048 	if [ -d $verify ]; then
   3049 		verify="CApath = $verify"
   3050 	else
   3051 		verify="CAfile = $verify"
   3052 	fi
   3053 	verify="$verify
   3054 verify = 2"
   3055 fi
   3056 if [ "X$SSVNC_STUNNEL_VERIFY3" != "X" ]; then
   3057 	verify=`echo "$verify" | sed -e 's/verify = 2/verify = 3/'`
   3058 fi
   3059 if [ "X$mycert" != "X" ]; then
   3060 	cert="cert = $mycert"
   3061 fi
   3062 if [ "X$crl" != "X" ]; then
   3063 	if [ -d $crl ]; then
   3064 		crl="CRLpath = $crl"
   3065 	else
   3066 		crl="CRLfile = $crl"
   3067 	fi
   3068 fi
   3069 
   3070 if [ "X$showcert" = "X1" ]; then
   3071 	if [ "X$have_uvnc_dsm_helper_showcert" = "X1" ]; then
   3072 		:
   3073 	elif [ "X$SSVNC_NO_IPV6_PROXY" != "X" ]; then
   3074 		:
   3075 	elif [ "X$ipv6" = "X1" -a "X$proxy" = "X" ]; then
   3076 		proxy="ipv6://$host:$port"
   3077 	fi
   3078 fi
   3079 
   3080 if [ "X$direct_connect" != "X" -a "X$STUNNEL_LISTEN" != "X" ]; then
   3081 	proxy=reverse_direct
   3082 fi
   3083 
   3084 ptmp=""
   3085 if [ "X$proxy" != "X" ]; then
   3086 	ptmp="/tmp/ss_vncviewer${RANDOM}.$$.pl"
   3087 	ptmp=`mytmp "$ptmp"`
   3088 	PPROXY_REMOVE=1; export PPROXY_REMOVE
   3089 	pcode "$ptmp"
   3090 	if [ "X$showcert" != "X1" -a "X$direct_connect" = "X" ]; then
   3091 		if uname | egrep 'Darwin|SunOS' >/dev/null; then
   3092 			vout=`echo "$proxy" | grep -i vencrypt`
   3093 			if [ "X$vout" != "X" -a "X$reverse" = "X1" ]; then
   3094 				# need to exec for reverse vencrypt
   3095 				connect="exec = $ptmp"
   3096 			else
   3097 				# on mac and solaris we need to listen on socket instead of stdio:
   3098 				nd=`findfree 6700`
   3099 				PPROXY_LISTEN=$nd
   3100 				export PPROXY_LISTEN
   3101 				if [ "X$reverse" = "X" ]; then
   3102 					$ptmp &
   3103 				fi
   3104 				sleep 2
   3105 				host="$localhost"
   3106 				port="$nd"
   3107 				connect="connect = $localhost:$nd"
   3108 			fi
   3109 		else
   3110 			# otherwise on unix we can exec it:
   3111 			connect="exec = $ptmp"
   3112 		fi
   3113 	else
   3114 		connect="exec = $ptmp"
   3115 	fi
   3116 else
   3117 	connect="connect = $host:$port"
   3118 fi
   3119 
   3120 # handle showcert case:
   3121 #
   3122 if [ "X$showcert" = "X1" ]; then
   3123 	if [ "X$proxy" != "X" ]; then
   3124 		PPROXY_LISTEN=$use
   3125 		export PPROXY_LISTEN
   3126 		if [ "X$SS_DEBUG" != "X" ]; then
   3127 			$ptmp &
   3128 		else
   3129 			$ptmp 2>/dev/null &
   3130 		fi
   3131 		sleep 1
   3132 		more_sleep=1
   3133 		if uname | grep Linux > /dev/null; then
   3134 			if netstat -ant | grep LISTEN | grep "127.0.0.1:$use" > /dev/null; then
   3135 				more_sleep=""
   3136 			fi
   3137 		elif uname | grep SunOS > /dev/null; then
   3138 			if netstat -an -f inet -P tcp | grep LISTEN | grep "127.0.0.1.$use" > /dev/null; then
   3139 				more_sleep=""
   3140 			fi
   3141 		elif uname | egrep -i 'bsd|darwin' > /dev/null; then
   3142 			if netstat -ant -f inet | grep LISTEN | grep "127.0.0.1.$use" > /dev/null; then
   3143 				more_sleep=""
   3144 			fi
   3145 		fi
   3146 		if [ "X$more_sleep" = "X1" ]; then
   3147 			sleep 1
   3148 		fi
   3149 		host="$localhost"
   3150 		port="$use"
   3151 	fi
   3152 	cipher_args=""
   3153 	if [ "X$ciphers" != "X" ]; then
   3154 		cipher_args=`echo "$ciphers" | sed -e 's/ciphers=/-cipher /'`
   3155 	fi
   3156 	if [ "X$have_uvnc_dsm_helper_showcert" = "X1" ]; then
   3157 		:
   3158 	elif type openssl > /dev/null 2>&1; then
   3159 		:
   3160 	else
   3161 		echo ""
   3162 		echo "********************************************************"
   3163 		echo "** Problem finding the OpenSSL command 'openssl': **" 
   3164 		echo ""
   3165 		type openssl 2>&1
   3166 		echo ""
   3167 		echo "** Perhaps you need to install the 'openssl' package. **"
   3168 		echo "********************************************************"
   3169 		echo ""
   3170 	fi
   3171 	#echo "openssl s_client $cipher_args -connect $host:$port" 
   3172 	if [ "X$reverse" = "X" ]; then
   3173 		if type host > /dev/null 2>/dev/null; then
   3174 			host $host >/dev/null 2>&1
   3175 			host $host >/dev/null 2>&1
   3176 		fi
   3177 		timeout=15
   3178 		if [ "X$SSVNC_FETCH_TIMEOUT" != "X" ]; then
   3179 			timeout=$SSVNC_FETCH_TIMEOUT
   3180 		fi
   3181 		if [ "X$have_uvnc_dsm_helper_showcert" = "X1" ]; then
   3182 			if type pkill >/dev/null 2>&1; then
   3183 				(sleep $timeout; if kill -0 $$; then pkill -TERM -f "ultravnc_dsm_helper.*$host.*$port"; fi) >/dev/null 2>&1 &
   3184 			fi
   3185 			ultravnc_dsm_helper showcert $host:$port 2>&1
   3186 		else
   3187 			if type pkill >/dev/null 2>&1; then
   3188 				(sleep $timeout; if kill -0 $$; then pkill -TERM -f "openssl.*s_client.*$host.*$port"; fi) >/dev/null 2>&1 &
   3189 			fi
   3190 			openssl s_client $cipher_args -prexit -connect $host:$port 2>&1 < /dev/null
   3191 		fi
   3192 		rc=$?
   3193 	else
   3194 		tcert=""
   3195 		if [ "X$mycert" = "X" ]; then
   3196 			tcert=`make_tcert`
   3197 			cert_args="-cert $tcert -CAfile $tcert"
   3198 		else
   3199 			cert_args="-cert $mycert -CAfile $mycert"
   3200 		fi
   3201 		tmp_out=/tmp/showcert_out${RANDOM}.$$
   3202 		tmp_out=`mytmp "$tmp_out"`
   3203 		tmp_err=/tmp/showcert_err${RANDOM}.$$
   3204 		tmp_err=`mytmp "$tmp_err"`
   3205 
   3206 		#echo "openssl s_server $cipher_args $cert_args -accept $port -verify 2 > $tmp_out 2> $tmp_err" 1>&2
   3207 
   3208 		# assume we have perl:
   3209 		check_perl perl
   3210 
   3211 		perl -e "
   3212 			\$p = open(O, \"|openssl s_server $cipher_args $cert_args -accept $port -verify 2 1>$tmp_out 2> $tmp_err\");
   3213 			exit 1 unless \$p;
   3214 			while (1) {
   3215 				sleep 1;
   3216 				if (!open(F, \"<$tmp_out\")) {
   3217 					kill \$p;
   3218 					exit 1;
   3219 				}
   3220 				while (<F>) {
   3221 					if (/RFB 00/) {
   3222 						fsleep(0.25);
   3223 						print O \"RFB 000.000\\n\";
   3224 						fsleep(1.00);
   3225 						kill \$p;
   3226 						fsleep(0.25);
   3227 						exit 0;
   3228 					}
   3229 				}
   3230 				close F;
   3231 			}
   3232 			sub fsleep {
   3233 				select(undef, undef, undef, shift);
   3234 			}
   3235 		";
   3236 
   3237 		echo ""
   3238 		cat $tmp_out
   3239 		echo ""
   3240 		echo "----2----"
   3241 		cat $tmp_err
   3242 		if grep BEGIN.CERTIFICATE $tmp_out >/dev/null; then
   3243 			rc=0
   3244 		else
   3245 			rc=1
   3246 		fi
   3247 
   3248 		rm -f $tmp_out $tmp_err
   3249 	fi
   3250 	if [ "X$SSVNC_PREDIGESTED_HANDSHAKE" != "X" ]; then
   3251 		rm -f $SSVNC_PREDIGESTED_HANDSHAKE
   3252 	fi
   3253 	if [ "X$SSVNC_SHOWCERT_EXIT_0" = "X1" ]; then
   3254 		exit 0
   3255 	else
   3256 		exit $rc
   3257 	fi
   3258 fi
   3259 
   3260 # handle direct connect case:
   3261 #
   3262 if [ "X$direct_connect" != "X" ]; then
   3263 	if [ "X$SSVNC_ULTRA_DSM" != "X" ]; then
   3264 		SSVNC_NO_ENC_WARN=1
   3265 		echo ""
   3266 		echo "Using UltraVNC DSM Plugin key for encryption:"
   3267 		echo ""
   3268 		ustr=`echo "$SSVNC_ULTRA_DSM" | sed -e 's/pw=[^ ]*/pw=******/g'`
   3269 		echo "  $ustr PORT HOST:PORT"
   3270 		echo ""
   3271 	elif [ "X$getport" = "X" ]; then
   3272 		echo ""
   3273 		echo "Running viewer for direct connection:"
   3274 		if echo X"$@" | grep chatonly > /dev/null; then
   3275 			:
   3276 		else
   3277 			echo ""
   3278 			echo "** WARNING: THERE WILL BE NO SSL OR SSH ENCRYPTION **"
   3279 			echo ""
   3280 		fi
   3281 	fi
   3282 	x=""
   3283 	if [ "X$SSVNC_NO_ENC_WARN" != "X" ]; then
   3284 		if [ "X$getport" = "X" ]; then
   3285 			sleep 1
   3286 		fi
   3287 	elif type printf > /dev/null 2>&1; then
   3288 		printf  "Are you sure you want to continue? [y]/n "
   3289 		read x
   3290 	else
   3291 		echo -n "Are you sure you want to continue? [y]/n "
   3292 		read x
   3293 	fi
   3294 	if [ "X$x" = "Xn" ]; then
   3295 		exit 1
   3296 	fi
   3297 	echo ""
   3298 	if [ "X$ptmp" != "X" ]; then
   3299 		if [ "X$reverse" = "X" ]; then
   3300 			PPROXY_LISTEN=$use
   3301 			export PPROXY_LISTEN
   3302 		else
   3303 			if [ "X$proxy" = "Xreverse_direct" ]; then
   3304 				PPROXY_LISTEN="$STUNNEL_LISTEN:`expr 5500 + $disp`"
   3305 				PPROXY_DEST="$localhost:$use"
   3306 				PPROXY_PROXY="ipv6://$localhost:$use"	# not always ipv6..
   3307 				export PPROXY_LISTEN PPROXY_DEST PPROXY_PROXY
   3308 				pps=1
   3309 			else
   3310 				PPROXY_REVERSE="$localhost:$use"
   3311 				export PPROXY_LISTEN
   3312 				pps=3
   3313 			fi
   3314 			if [ "X$SSVNC_LISTEN_ONCE" != "X1" ]; then
   3315 				PPROXY_LOOP_THYSELF=`mytmp "/tmp/pproxy_loop_thyself.${RANDOM}.$$"`
   3316 				export PPROXY_LOOP_THYSELF
   3317 				pps=2
   3318 			fi
   3319 			if [ "X$SSVNC_EXTRA_SLEEP" != "X" ]; then
   3320 				pps=`expr $pps + $SSVNC_EXTRA_SLEEP`
   3321 			fi
   3322 			PPROXY_SLEEP=$pps; export PPROXY_SLEEP;
   3323 			PPROXY_KILLPID=+1; export PPROXY_KILLPID;
   3324 		fi
   3325 
   3326 		$ptmp &
   3327 
   3328 		if [ "X$reverse" = "X" ]; then
   3329 			#sleep 2
   3330 			#echo T sleep 1
   3331 			sleep 1
   3332 		fi
   3333 		host="$localhost"
   3334 		disp="$N"
   3335 		port=`expr $disp + 5900`
   3336 	fi
   3337 	if [ "X$SSVNC_EXTRA_SLEEP" != "X" ]; then
   3338 		echo "T sleep $SSVNC_EXTRA_SLEEP"
   3339 		sleep $SSVNC_EXTRA_SLEEP
   3340 	fi
   3341 	if [ "X$SSVNC_EXTRA_COMMAND" != "X" ]; then
   3342 		(sh -c "$SSVNC_EXTRA_COMMAND") &
   3343 		echo "($SSVNC_EXTRA_COMMAND) &"; echo
   3344 	fi
   3345 	if [ "X$reverse" = "X" ]; then
   3346 		hostdisp="$host:$disp"
   3347 		if [ "X$SSVNC_ULTRA_DSM" != "X" ]; then
   3348 			if [ "X$SSVNC_USE_OURS" = "X1" ]; then
   3349 				hostdisp="exec=$SSVNC_ULTRA_DSM 0 $host:$port"
   3350 			else
   3351 				pf=`findfree 5970`
   3352 				cmd="$SSVNC_ULTRA_DSM -$pf $host:$port"
   3353 				pf=`expr $pf - 5900`
   3354 				hostdisp="$localhost:$pf"
   3355 				ustr=`echo "$cmd" | sed -e 's/pw=[^ ]*/pw=******/g'`
   3356 				echo "Running:"
   3357 				echo
   3358 				echo "$ustr &"
   3359 				echo
   3360 				$cmd &
   3361 				dsm_pid=$!
   3362 				sleep 2
   3363 			fi
   3364 		fi
   3365 		hostdisp2=`echo "$hostdisp" | sed -e 's/pw=[^ ]*/pw=******/g'`
   3366 		echo "$VNCVIEWERCMD" "$@" "$hostdisp2"
   3367 		trap "final" 0 2 15
   3368 		echo ""
   3369 		$VNCVIEWERCMD "$@" "$hostdisp"
   3370 		if [ $? != 0 ]; then
   3371 			echo "vncviewer command failed: $?"
   3372 			if [ "X$secondtry" = "X1" ]; then
   3373 				sleep 2
   3374 				$VNCVIEWERCMD "$@" "$hostdisp"
   3375 			fi
   3376 		fi
   3377 	else
   3378 		echo ""
   3379 		echo "NOTE: Press Ctrl-C to terminate viewer LISTEN mode."
   3380 		echo ""
   3381 		trap "final" 0 2 15
   3382 		if [ "X$SSVNC_ULTRA_DSM" != "X" ]; then
   3383 			if [ "X$SSVNC_LISTEN_ONCE" = "X1" ]; then
   3384 				echo "NOTE: The ultravnc_dsm_helper only runs once.  So after the first LISTEN"
   3385 				echo "      ends you must restart the Listening mode.  You may also need to"
   3386 				echo "      Press Ctrl-C to stop the viewer and restart for another connection."
   3387 				echo ""
   3388 			fi
   3389 			#SSVNC_LISTEN_ONCE=1; export SSVNC_LISTEN_ONCE
   3390 			VNCVIEWER_LISTEN_LOCALHOST=1
   3391 			export VNCVIEWER_LISTEN_LOCALHOST
   3392 			dport=`expr 5500 + $disp`
   3393 			cmd="$SSVNC_ULTRA_DSM $dport $localhost:$use"
   3394 			ustr=`echo "$cmd" | sed -e 's/pw=[^ ]*/pw=******/g'`
   3395 			echo "Running:"
   3396 			echo
   3397 			echo "$ustr &"
   3398 			echo
   3399 			if [ "X$SSVNC_LISTEN_ONCE" = "X1" ]; then
   3400 				$cmd &
   3401 				dsm_pid=$!
   3402 			else
   3403 				while [ 1 ]; do $cmd; sleep 1; done &
   3404 				dsm_pid=$!
   3405 			fi
   3406 			sleep 2
   3407 			disp=$use
   3408 			if [ $disp -ge 5500 ]; then
   3409 				disp=`expr $disp - 5500`
   3410 			fi
   3411 		fi
   3412 		disp2=$disp
   3413 		if [ "X$VNCVIEWER_IS_REALVNC4" = "X1" ]; then
   3414 			disp2=`echo "$disp2" | sed -e 's/://g'`
   3415 			if [ $disp2 -le 200 ]; then
   3416 				disp2=`expr $disp2 + 5500`
   3417 			fi
   3418 		fi
   3419 		echo "$VNCVIEWERCMD" "$@" -listen $disp2
   3420 		echo ""
   3421 		$VNCVIEWERCMD "$@" -listen $disp2
   3422 		if [ "X$PPROXY_LOOP_THYSELF" != "X" ]; then
   3423 			rm -f $PPROXY_LOOP_THYSELF
   3424 		fi
   3425 	fi
   3426 	exit $?
   3427 fi
   3428 
   3429 tmp_cfg=/tmp/ss_vncviewer${RANDOM}.$$
   3430 tmp_cfg=`mytmp "$tmp_cfg"`
   3431 
   3432 stunnel_exec=""
   3433 if [ "X$SSVNC_USE_OURS" != "X1" ]; then
   3434 	:
   3435 elif echo $STUNNEL_EXTRA_SVC_OPTS | grep '#stunnel-exec' > /dev/null; then
   3436 	stunnel_exec="#"
   3437 fi
   3438 
   3439 if [ "X$reverse" = "X" ]; then
   3440 
   3441 	if echo "$proxy" | grep "^repeater://" > /dev/null; then
   3442 		if [ "X$cert" = "XBUILTIN" ]; then
   3443 			ttcert=`make_tcert`
   3444 			cert="cert = $ttcert"
   3445 		fi
   3446 		# Note for listen mode, an empty cert will cause stunnel to fail.
   3447 		# The ssvnc gui will have already taken care of this.
   3448 	fi
   3449 
   3450 	cat > "$tmp_cfg" <<END
   3451 foreground = yes
   3452 pid =
   3453 client = yes
   3454 debug = $stunnel_debug
   3455 $ciphers
   3456 $STUNNEL_EXTRA_OPTS
   3457 $STUNNEL_EXTRA_OPTS_USER
   3458 $cert
   3459 $crl
   3460 $verify
   3461 
   3462 ${stunnel_exec}[vnc_stunnel]
   3463 ${stunnel_exec}accept = $localhost:$use
   3464 $connect
   3465 $STUNNEL_EXTRA_SVC_OPTS
   3466 $STUNNEL_EXTRA_SVC_OPTS_USER
   3467 
   3468 END
   3469 
   3470 else
   3471 	# REVERSE case:
   3472 
   3473 	stunnel_exec=""	# doesn't work for listening.
   3474 
   3475 	p2=`expr 5500 + $N`
   3476 	connect="connect = $localhost:$p2"
   3477 	if [ "X$cert" = "XBUILTIN" ]; then
   3478 		ttcert=`make_tcert`
   3479 		cert="cert = $ttcert"
   3480 	fi
   3481 	# Note for listen mode, an empty cert will cause stunnel to fail.
   3482 	# The ssvnc gui will have already taken care of this.
   3483 
   3484 
   3485 	hloc=""
   3486 	if [ "X$use_ssh" = "X1" ]; then
   3487 		hloc="$localhost:"
   3488 	elif [ "X$STUNNEL_LISTEN" != "X" ]; then
   3489 		hloc="$STUNNEL_LISTEN:"
   3490 	fi
   3491 	if echo "$proxy" | grep -i '^vencrypt:' > /dev/null; then
   3492 		hloc="$localhost:"
   3493 		pv=`findfree 5570`
   3494 		proxy="vencrypt:$pv:$port"
   3495 		port=$pv
   3496 		if [ "X$anondh_set" = "X1" ]; then
   3497 			# not needed for ANONDH in this mode
   3498 			#ciphers="ciphers = ADH:@STRENGTH"
   3499 			:
   3500 		fi
   3501 	fi
   3502 	cat > "$tmp_cfg" <<END
   3503 foreground = yes
   3504 pid =
   3505 client = no
   3506 debug = $stunnel_debug
   3507 $ciphers
   3508 $STUNNEL_EXTRA_OPTS
   3509 $STUNNEL_EXTRA_OPTS_USER
   3510 $cert
   3511 $crl
   3512 $verify
   3513 
   3514 [vnc_stunnel]
   3515 accept = $hloc$port
   3516 $connect
   3517 $STUNNEL_EXTRA_SVC_OPTS
   3518 $STUNNEL_EXTRA_SVC_OPTS_USER
   3519 
   3520 END
   3521 
   3522 fi
   3523 
   3524 echo ""
   3525 echo "Using this stunnel configuration:"
   3526 echo ""
   3527 cat "$tmp_cfg" | uniq
   3528 echo ""
   3529 if egrep -i '^[ 	]*(CApath|CAfile) =' "$tmp_cfg" > /dev/null ; then
   3530 	:
   3531 else
   3532 	echo "** WARNING: THE STUNNEL CONFIG HAS NO SERVER CERTIFICATE SPECIFIED       **"
   3533 	echo "** WARNING: (the CApath or CAfile stunnel option) THE VNC SERVER WILL    **"
   3534 	echo "** WARNING: NOT BE AUTHENTICATED. A MAN-IN-THE-MIDDLE ATTACK IS POSSIBLE **"
   3535 	echo ""
   3536 fi
   3537 sleep 1
   3538 
   3539 if [ "X$stunnel_exec" = "X" ]; then
   3540 	echo ""
   3541 	echo "Running stunnel:"
   3542 	echo "$STUNNEL $tmp_cfg"
   3543 	st=`echo "$STUNNEL" | awk '{print $1}'`
   3544 	$st -help > /dev/null 2>&1
   3545 	$STUNNEL "$tmp_cfg" < /dev/tty > /dev/tty &
   3546 	stunnel_pid=$!
   3547 	echo ""
   3548 
   3549 	# pause here to let the user supply a possible passphrase for the
   3550 	# mycert key:
   3551 	if [ "X$mycert" != "X" ]; then
   3552 		nsl=10
   3553 		dsl=0
   3554 		if [ ! -f $mycert ]; then
   3555 			dsl=0
   3556 		elif grep -i 'Proc-Type.*ENCRYPTED' "$mycert" > /dev/null 2>/dev/null; then
   3557 			dsl=1
   3558 		fi
   3559 		if [ "X$dsl" = "X1" ]; then
   3560 			echo ""
   3561 			echo "(** pausing $nsl secs for possible certificate passphrase dialog **)"
   3562 			echo ""
   3563 			sleep $nsl
   3564 			echo "(** done pausing for passphrase **)"
   3565 			echo ""
   3566 		fi
   3567 	fi
   3568 	#echo T sleep 1
   3569 	sleep 1
   3570 	rm -f "$tmp_cfg"
   3571 fi
   3572 
   3573 
   3574 echo ""
   3575 if [ "X$SSVNC_EXTRA_SLEEP" != "X" ]; then
   3576 	echo "sleep $SSVNC_EXTRA_SLEEP"
   3577 	sleep $SSVNC_EXTRA_SLEEP
   3578 fi
   3579 if [ "X$SSVNC_EXTRA_COMMAND" != "X" ]; then
   3580 	(sh -c "$SSVNC_EXTRA_COMMAND") &
   3581 	echo "($SSVNC_EXTRA_COMMAND) &"; echo
   3582 fi
   3583 
   3584 if [ "X$reverse" = "X" ]; then
   3585 	if [ "X$NEED_VENCRYPT_VIEWER_BRIDGE" = "X1" -a "X$ptmp" != "X" ] ; then
   3586 		port1=`expr 5900 + $N`		# stunnel port
   3587 		port2=`findfree 5970`		# bridge port (viewer connects to it.)
   3588 		N=`expr $port2 - 5900`
   3589 		env PPROXY_REMOVE=0 PPROXY_SLEEP=0 PPROXY_VENCRYPT_VIEWER_BRIDGE="$port2,$port1" $ptmp &
   3590 		sleep 1
   3591 	fi
   3592 	echo "Running viewer:"
   3593 	vnc_hp=$localhost:$N
   3594 	if [ "X$stunnel_exec" != "X" ]; then
   3595 		vnc_hp="exec=$STUNNEL $tmp_cfg"
   3596 	fi
   3597 	echo "$VNCVIEWERCMD" "$@" "$vnc_hp"
   3598 	trap "final" 0 2 15
   3599 	echo ""
   3600 	$VNCVIEWERCMD "$@" "$vnc_hp"
   3601 	if [ $? != 0 ]; then
   3602 		echo "vncviewer command failed: $?"
   3603 		if [ "X$secondtry" = "X1" ]; then
   3604 			sleep 2
   3605 			$VNCVIEWERCMD "$@" "$vnc_hp"
   3606 		fi
   3607 	fi
   3608 else
   3609 	echo "Running viewer:"
   3610 	echo ""
   3611 	echo "NOTE: Press Ctrl-C to terminate viewer LISTEN mode."
   3612 	echo ""
   3613 	trap "final" 0 2 15
   3614 	N2=$N
   3615 	N2_trim=`echo "$N2" | sed -e 's/://g'`
   3616 	if [ $N2_trim -le 200 ]; then
   3617 		N2_trim=`expr $N2_trim + 5500`
   3618 	fi
   3619 	if [ "X$proxy" != "X" ]; then
   3620 		if echo "$proxy" | grep -i '^vencrypt:' > /dev/null; then
   3621 			pstunnel=`echo "$proxy" | awk -F: '{print $2}'`
   3622 			plisten=`echo "$proxy" | awk -F: '{print $3}'`
   3623 			IF=INADDR_ANY
   3624 			if [ "X$STUNNEL_LISTEN" != "X" ]; then
   3625 				IF=$STUNNEL_LISTEN
   3626 			fi
   3627 			PPROXY_VENCRYPT_REVERSE=1; export PPROXY_VENCRYPT_REVERSE
   3628 			PPROXY_LISTEN="$IF:$plisten"; export PPROXY_LISTEN
   3629 			PPROXY_PROXY="vencrypt://$localhost:$pstunnel"; export PPROXY_PROXY
   3630 			PPROXY_DEST="$localhost:$pstunnel"; export PPROXY_DEST
   3631 			STUNNEL_ONCE=1; export STUNNEL_ONCE
   3632 			STUNNEL_MAX_CLIENTS=1; export STUNNEL_MAX_CLIENTS
   3633 			if [ "X$NEED_VENCRYPT_VIEWER_BRIDGE" = "X1" -a "X$ptmp" != "X" ] ; then
   3634 				port1=`expr 5500 + $N2`
   3635 				port2=`findfree 5580`
   3636 				N2=`expr $port2 - 5500`
   3637 				N2_trim=`echo "$N2" | sed -e 's/://g'`
   3638 				if [ $N2_trim -le 200 ]; then
   3639 					N2_trim=`expr $N2_trim + 5500`
   3640 				fi
   3641 				if [ "X$SSVNC_LISTEN_ONCE" != "X1" ]; then
   3642 					PPROXY_LOOP_THYSELF=`mytmp "/tmp/pproxy_loop_thyself1.${RANDOM}.$$"`
   3643 					export PPROXY_LOOP_THYSELF
   3644 					PPROXY_LOOP_THYSELF0=$PPROXY_LOOP_THYSELF
   3645 				fi
   3646 				env PPROXY_REMOVE=0 PPROXY_SLEEP=0 PPROXY_VENCRYPT_VIEWER_BRIDGE="-$port1,$port2" $ptmp &
   3647 				sleep 1
   3648 			fi
   3649 		else
   3650 			PPROXY_REVERSE="$localhost:$port"; export PPROXY_REVERSE
   3651 			PPROXY_SLEEP=1; export PPROXY_SLEEP;
   3652 		fi
   3653 		PPROXY_KILLPID=+1; export PPROXY_KILLPID;
   3654 		if [ "X$SSVNC_LISTEN_ONCE" != "X1" ]; then
   3655 			PPROXY_LOOP_THYSELF=`mytmp "/tmp/pproxy_loop_thyself2.${RANDOM}.$$"`
   3656 			export PPROXY_LOOP_THYSELF
   3657 		fi
   3658 		$ptmp &
   3659 		# Important to have no extra pids generated between here and VNCVIEWERCMD
   3660 	fi
   3661 	if [ "X$VNCVIEWER_IS_REALVNC4" = "X1" ]; then
   3662 		N2=$N2_trim
   3663 	fi
   3664 	echo "$VNCVIEWERCMD" "$@" -listen $N2
   3665 	echo ""
   3666 	$VNCVIEWERCMD "$@" -listen $N2
   3667 
   3668 	if [ "X$PPROXY_LOOP_THYSELF" != "X" ]; then
   3669 		rm -f $PPROXY_LOOP_THYSELF
   3670 	fi
   3671 	if [ "X$PPROXY_LOOP_THYSELF0" != "X" ]; then
   3672 		rm -f $PPROXY_LOOP_THYSELF0
   3673 	fi
   3674 fi
   3675 
   3676 sleep 1
   3677