Home | History | Annotate | Download | only in util
      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 ':' > /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 		else
    708 			proxy="ipv6://$host:$port"
    709 			echo "direct connect: set proxy=$proxy"
    710 		fi
    711 	fi
    712 fi
    713 
    714 # (possibly) tell the vncviewer to only listen on lo: 
    715 if [ "X$reverse" != "X" ]; then
    716 	if [ "X$direct_connect" = "X" -o "X$proxy" != "X" -o "X$STUNNEL_LISTEN" != "X" ]; then
    717 		VNCVIEWER_LISTEN_LOCALHOST=1
    718 		export VNCVIEWER_LISTEN_LOCALHOST
    719 	fi
    720 fi
    721 
    722 # try to find an open listening port via netstat(1):
    723 inuse=""
    724 if uname | grep Linux > /dev/null; then
    725 	inuse=`netstat -ant | egrep 'LISTEN|WAIT|ESTABLISH|CLOSE' | awk '{print $4}' | sed 's/^.*://'`
    726 elif uname | grep SunOS > /dev/null; then
    727 	inuse=`netstat -an -f inet -P tcp | egrep 'LISTEN|WAIT|ESTABLISH|CLOSE' | awk '{print $1}' | sed 's/^.*\.//'`
    728 elif uname | egrep -i 'bsd|darwin' > /dev/null; then
    729 	inuse=`netstat -ant -f inet | egrep 'LISTEN|WAIT|ESTABLISH|CLOSE' | awk '{print $4}' | sed 's/^.*\.//'`
    730 # add others...
    731 fi
    732 
    733 # this is a crude attempt for unique ports tags, etc.
    734 date_sec=`date +%S`
    735 
    736 # these are special cases of no vnc, e.g. sleep or xmessage.
    737 # these are for using ssvnc as a general port redirector.
    738 if echo "$VNCVIEWERCMD" | grep '^sleep[ 	][ 	]*[0-9][0-9]*' > /dev/null; then
    739 	if [ "X$SS_VNCVIEWER_LISTEN_PORT" = "X" ]; then
    740 		p=`echo "$VNCVIEWERCMD" | awk '{print $3}'`
    741 		if [ "X$p" != "X" ]; then
    742 			SS_VNCVIEWER_LISTEN_PORT=$p
    743 		fi
    744 	fi
    745 	p2=`echo "$VNCVIEWERCMD" | awk '{print $2}'`
    746 	VNCVIEWERCMD="eval sleep $p2; echo Local "
    747 elif echo "$VNCVIEWERCMD" | grep '^xmessage[ 	][ 	]*[0-9][0-9]*' > /dev/null; then
    748 	if [ "X$SS_VNCVIEWER_LISTEN_PORT" = "X" ]; then
    749 		p=`echo "$VNCVIEWERCMD" | awk '{print $2}'`
    750 		SS_VNCVIEWER_LISTEN_PORT=$p
    751 	fi
    752 fi
    753 
    754 # utility to find a free port to listen on.
    755 findfree() {
    756 	try0=$1
    757 	try=$try0
    758 	use0=""
    759 
    760 	if [ "X$SS_VNCVIEWER_LISTEN_PORT" != "X" ]; then
    761 		echo "$SS_VNCVIEWER_LISTEN_PORT"
    762 		return	
    763 	fi
    764 	if [ $try -ge 6000 ]; then
    765 		fmax=`expr $try + 1000`
    766 	else
    767 		fmax=6000
    768 	fi
    769 
    770 	while [ $try -lt $fmax ]
    771 	do
    772 		if [ "X$inuse" = "X" ]; then
    773 			break
    774 		fi
    775 		if echo "$inuse" | grep -w $try > /dev/null; then
    776 			:
    777 		else
    778 			use0=$try
    779 			break
    780 		fi
    781 		try=`expr $try + 1`
    782 	done
    783 	if [ "X$use0" = "X" ]; then
    784 		use0=`expr $date_sec + $try0`
    785 	fi
    786 
    787 	echo $use0
    788 }
    789 
    790 # utility for exiting; kills some helper processes,
    791 # removes files, etc.
    792 final() {
    793 	echo ""
    794 	if [ "X$tmp_cfg" != "X" ]; then
    795 		rm -f $tmp_cfg
    796 	fi
    797 	if [ "X$SS_VNCVIEWER_RM" != "X" ]; then
    798 		rm -f $SS_VNCVIEWER_RM 2>/dev/null
    799 	fi
    800 	if [ "X$tcert" != "X" ]; then
    801 		rm -f $tcert
    802 	fi
    803 	if [ "X$pssh" != "X" ]; then
    804 		echo "Terminating background ssh process"
    805 		echo kill -TERM "$pssh"
    806 		kill -TERM "$pssh" 2>/dev/null
    807 		sleep 1
    808 		kill -KILL "$pssh" 2>/dev/null
    809 		pssh=""
    810 	fi
    811 	if [ "X$stunnel_pid" != "X" ]; then
    812 		echo "Terminating background stunnel process"
    813 		echo kill -TERM "$stunnel_pid"
    814 		kill -TERM "$stunnel_pid" 2>/dev/null
    815 		sleep 1
    816 		kill -KILL "$stunnel_pid" 2>/dev/null
    817 		stunnel_pid=""
    818 	fi
    819 	if [ "X$dsm_pid" != "X" ]; then
    820 		echo "Terminating background ultravnc_dsm_helper process"
    821 		echo kill -TERM "$dsm_pid"
    822 		kill -TERM "$dsm_pid" 2>/dev/null
    823 		sleep 1
    824 		kill -KILL "$dsm_pid" 2>/dev/null
    825 		stunnel_pid=""
    826 	fi
    827 	if [ "X$tail_pid" != "X" ]; then
    828 		kill -TERM $tail_pid
    829 	fi
    830 	if [ "X$tail_pid2" != "X" ]; then
    831 		kill -TERM $tail_pid2
    832 	fi
    833 }
    834 
    835 if [ "X$reverse" = "X" ]; then
    836 	# normal connections try 5930-5999:
    837 	if [ "X$showcert" = "X" ]; then
    838 		use=`findfree 5930`
    839 	else
    840 		# move away from normal place for (possibly many) -showcert
    841 		pstart=`date +%S`
    842 		pstart=`expr 6130 + $pstart + $pstart`
    843 		use=`findfree $pstart`
    844 	fi
    845 	if [ $use -ge 5900 ]; then
    846 		N=`expr $use - 5900`
    847 	else
    848 		N=$use
    849 	fi
    850 else
    851 	# reverse connections:
    852 	p2=`expr $port + 30`
    853 	use=`findfree $p2`
    854 	if [ $use -ge 5500 ]; then
    855 		N=`expr $use - 5500`
    856 	else
    857 		N=$use
    858 	fi
    859 fi
    860 
    861 # this is for my special use of ss_vncip -> vncip viewer.
    862 if echo "$0" | grep vncip > /dev/null; then
    863 	VNCVIEWERCMD="$VNCIPCMD"
    864 fi
    865 
    866 if echo "$VNCVIEWERCMD" | egrep -i '^(xmessage|sleep )' > /dev/null; then
    867 	:
    868 elif [ "X$VNCVIEWERCMD_EXTRA_OPTS" != "X" ]; then
    869 	VNCVIEWERCMD="$VNCVIEWERCMD $VNCVIEWERCMD_EXTRA_OPTS"
    870 fi
    871 
    872 # trick for the undocumented rsh://host:port method.
    873 rsh_setup() {
    874 	if echo "$ssh_host" | grep '@' > /dev/null; then
    875 		ul=`echo "$ssh_host" | awk -F@ '{print $1}'`
    876 		ul="-l $ul"
    877 		ssh_host=`echo "$ssh_host" | awk -F@ '{print $2}'`
    878 	else
    879 		ul=""
    880 	fi
    881 	ssh_cmd=`echo "$ssh_cmd" | sed -e 's/ -localhost/ /g'`
    882 }
    883 
    884 # trick for the undocumented rsh://host:port method.
    885 rsh_viewer() {
    886 	trap "final" 0 2 15
    887 	if [ "X$PORT" = "X" ]; then
    888 		exit 1
    889 	elif [ $PORT -ge 5900 ]; then
    890 		vdpy=`expr $PORT - 5900`
    891 	else
    892 		vdpy=":$PORT"
    893 	fi
    894 	stty sane
    895 	echo "$VNCVIEWERCMD" "$@" $ssh_host:$vdpy
    896 	echo ""
    897 	$VNCVIEWERCMD "$@" $ssh_host:$vdpy
    898 	if [ $? != 0 ]; then
    899 		sleep 2
    900 		$VNCVIEWERCMD "$@" $ssh_host:$vdpy
    901 	fi
    902 }
    903 
    904 check_perl() {
    905 	if type "$1" > /dev/null 2>&1; then
    906 		:
    907 	elif [ ! -x "$1" ]; then
    908 		echo ""
    909 		echo "*******************************************************"
    910 		echo "** Problem finding the Perl command '$1': **"
    911 		echo ""
    912 		type "perl"
    913 		echo ""
    914 		echo "** Perhaps you need to install the Perl package. **"
    915 		echo "*******************************************************"
    916 		echo ""
    917 		sleep 5
    918 	fi
    919 }
    920 
    921 # this is the PPROXY tool.  used only here for now... 
    922 pcode() {
    923 	tf=$1
    924 	PPROXY_PROXY=$proxy; export PPROXY_PROXY
    925 	PPROXY_DEST="$host:$port"; export PPROXY_DEST
    926 	check_perl /usr/bin/perl
    927 
    928 	cod='#!/usr/bin/perl
    929 
    930 # A hack to glue stunnel to a Web or SOCKS proxy, UltraVNC repeater for
    931 # client connections.
    932 # Also acts as a VeNCrypt bridge (by redirecting to stunnel.)
    933 
    934 use IO::Socket::INET;
    935 
    936 my $have_inet6 = "";
    937 eval "use IO::Socket::INET6;";
    938 $have_inet6 = 1 if $@ eq "";
    939 
    940 #my $have_sock6 = "";
    941 #eval "use Socket; use Socket6;";
    942 #$have_sock6 = 1 if $@ eq "";
    943 
    944 if (exists $ENV{PPROXY_LOOP_THYSELF}) {
    945 	# used for reverse vnc, run a repeating outer loop.
    946 	print STDERR "PPROXY_LOOP: $ENV{PPROXY_LOOP_THYSELF}\n";
    947 	my $rm = $ENV{PPROXY_REMOVE};
    948 	my $lp = $ENV{PPROXY_LOOP_THYSELF};
    949 	delete $ENV{PPROXY_REMOVE};
    950 	delete $ENV{PPROXY_LOOP_THYSELF};
    951 	$ENV{PPROXY_LOOP_THYSELF_MASTER} = $$;
    952 	my $pid = $$;
    953 	my $dbg = 0;
    954 	my $c = 0;
    955 	use POSIX ":sys_wait_h";
    956 	while (1) {
    957 		$pid = fork();
    958 		last if ! defined $pid;
    959 		if ($pid eq "0") {
    960 			last;
    961 		}
    962 		$c++;
    963 		print STDERR "\nPPROXY_LOOP: pid=$$ child=$pid count=$c\n";
    964 		while (1) {
    965 			waitpid(-1, WNOHANG);
    966 			fsleep(0.25);
    967 			if (! kill 0, $pid) {
    968 				print STDERR "PPROXY_LOOP: child=$pid gone.\n";
    969 				last;
    970 			}
    971 			print STDERR "PPROXY_LOOP: child=$pid alive.\n" if $dbg;
    972 			if (! -f $lp) {
    973 				print STDERR "PPROXY_LOOP: flag file $lp gone, killing $pid\n";
    974 				kill TERM, $pid;
    975 				fsleep(0.1);
    976 				wait;
    977 				last;
    978 			}
    979 			print STDERR "PPROXY_LOOP: file exists $lp\n" if $dbg;
    980 		}
    981 		last if ! -f $lp;
    982 		fsleep(0.25);
    983 	}
    984 	if ($pid ne "0") {
    985 		unlink($0) if $rm;
    986 		exit 0;
    987 	}
    988 }
    989 
    990 if (exists $ENV{PPROXY_SLEEP} && $ENV{PPROXY_SLEEP} > 0) {
    991 	print STDERR "PPROXY_PID: $$\n";
    992 	sleep $ENV{PPROXY_SLEEP};
    993 }
    994 
    995 foreach my $var (qw(
    996 		PPROXY_DEST
    997 		PPROXY_KILLPID
    998 		PPROXY_LISTEN
    999 		PPROXY_PROXY
   1000 		PPROXY_REMOVE
   1001 		PPROXY_REPEATER
   1002 		PPROXY_REVERSE
   1003 		PPROXY_SLEEP
   1004 		PPROXY_SOCKS
   1005 		PPROXY_VENCRYPT
   1006 		PPROXY_VENCRYPT_VIEWER_BRIDGE
   1007     )) {
   1008 	if (0 || $ENV{SS_DEBUG} || $ENV{SSVNC_VENCRYPT_DEBUG}) {
   1009 		print STDERR "$var: $ENV{$var}\n";
   1010 	}
   1011 } 
   1012 
   1013 if ($ENV{PPROXY_SOCKS} ne "" && $ENV{PPROXY_PROXY} !~ m,^socks5?://,i) {
   1014 	if ($ENV{PPROXY_SOCKS} eq "5") {
   1015 		$ENV{PPROXY_PROXY} = "socks5://$ENV{PPROXY_PROXY}";
   1016 	} else {
   1017 		$ENV{PPROXY_PROXY} = "socks://$ENV{PPROXY_PROXY}";
   1018 	}
   1019 }
   1020 
   1021 my $rfbSecTypeAnonTls  = 18;
   1022 my $rfbSecTypeVencrypt = 19;
   1023 
   1024 my $rfbVencryptPlain        = 256;
   1025 my $rfbVencryptTlsNone      = 257;
   1026 my $rfbVencryptTlsVnc       = 258;
   1027 my $rfbVencryptTlsPlain     = 259;
   1028 my $rfbVencryptX509None     = 260;
   1029 my $rfbVencryptX509Vnc      = 261;
   1030 my $rfbVencryptX509Plain    = 262;
   1031 
   1032 my $handshake_file = "";
   1033 if (exists $ENV{SSVNC_PREDIGESTED_HANDSHAKE})  {
   1034 	$handshake_file = $ENV{SSVNC_PREDIGESTED_HANDSHAKE};
   1035 }
   1036 
   1037 my $have_gettimeofday = 0;
   1038 eval "use Time::HiRes;";
   1039 if ($@ eq "") {
   1040 	$have_gettimeofday = 1;
   1041 }
   1042 sub gettime {
   1043 	my $t = "0.0";
   1044 	if ($have_gettimeofday) {
   1045 		$t = Time::HiRes::gettimeofday();
   1046 	}
   1047 	return $t;
   1048 }
   1049 
   1050 my $listen_handle = "";
   1051 my $sock = "";
   1052 my $parent = $$;
   1053 
   1054 my $initial_data = "";
   1055 
   1056 if ($ENV{PPROXY_VENCRYPT_VIEWER_BRIDGE}) {
   1057 	my ($from, $to) = split(/,/, $ENV{PPROXY_VENCRYPT_VIEWER_BRIDGE});
   1058 	do_vencrypt_viewer_bridge($from, $to);
   1059 	exit 0;
   1060 }
   1061 
   1062 my ($first, $second, $third) = split(/,/, $ENV{PPROXY_PROXY}, 3);
   1063 my ($mode_1st, $mode_2nd, $mode_3rd) = ("", "", "");
   1064 
   1065 ($first, $mode_1st) = url_parse($first);
   1066 
   1067 my ($proxy_host, $proxy_port) = ($first, "");
   1068 if ($proxy_host =~ /^(.*):(\d+)$/) {
   1069 	$proxy_host = $1;
   1070 	$proxy_port = $2;
   1071 }
   1072 my $connect = $ENV{PPROXY_DEST};
   1073 
   1074 if ($second ne "") {
   1075 	($second, $mode_2nd) = url_parse($second);
   1076 }
   1077 
   1078 if ($third ne "") {
   1079 	($third, $mode_3rd) = url_parse($third);
   1080 }
   1081 
   1082 
   1083 print STDERR "\n";
   1084 print STDERR "PPROXY v0.4: a tool for Web, SOCKS, and UltraVNC proxies and for\n";
   1085 print STDERR "PPROXY v0.4: IPv6 and VNC VeNCrypt bridging.\n";
   1086 print STDERR "proxy_host:       $proxy_host\n";
   1087 print STDERR "proxy_port:       $proxy_port\n";
   1088 print STDERR "proxy_connect:    $connect\n";
   1089 print STDERR "pproxy_params:    $ENV{PPROXY_PROXY}\n";
   1090 print STDERR "pproxy_listen:    $ENV{PPROXY_LISTEN}\n";
   1091 print STDERR "pproxy_reverse:   $ENV{PPROXY_REVERSE}\n";
   1092 print STDERR "io_socket_inet6:  $have_inet6\n";
   1093 print STDERR "\n";
   1094 if (! $have_inet6) {
   1095 	print STDERR "PPROXY: To enable IPv6 connections, install the IO::Socket::INET6 perl module.\n\n";
   1096 }
   1097 
   1098 if (1) {
   1099 	print STDERR "pproxy 1st: $first\t- $mode_1st\n";
   1100 	print STDERR "pproxy 2nd: $second\t- $mode_2nd\n";
   1101 	print STDERR "pproxy 3rd: $third\t- $mode_3rd\n";
   1102 	print STDERR "\n";
   1103 }
   1104 
   1105 sub pdie {
   1106 	my $msg = shift;
   1107 	kill_proxy_pids();
   1108 	die "$msg";
   1109 }
   1110 
   1111 if ($ENV{PPROXY_REVERSE} ne "") {
   1112 	my ($rhost, $rport) = ($ENV{PPROXY_REVERSE}, "");
   1113 	if ($rhost =~ /^(.*):(\d+)$/) {
   1114 		$rhost = $1;
   1115 		$rport = $2;
   1116 	}
   1117 	$rport = 5900 unless $rport;
   1118 	my $emsg = "";
   1119 	$listen_handle = IO::Socket::INET->new(
   1120 		PeerAddr => $rhost,
   1121 		PeerPort => $rport,
   1122 		Proto => "tcp"
   1123 	);
   1124 	$emsg = $!;
   1125 	if (! $listen_handle && $have_inet6) {
   1126 		eval {$listen_handle = IO::Socket::INET6->new(
   1127 			PeerAddr => $rhost,
   1128 			PeerPort => $rport,
   1129 			Proto => "tcp"
   1130 		);};
   1131 		$emsg .= " / $!";
   1132 	}
   1133 	if (! $listen_handle) {
   1134 		pdie "pproxy: $emsg -- PPROXY_REVERSE\n";
   1135 	}
   1136 	print STDERR "PPROXY_REVERSE: connected to $rhost $rport\n";
   1137 
   1138 } elsif ($ENV{PPROXY_LISTEN} ne "") {
   1139 	my $listen_sock = "";
   1140 	my $maxtry = 12;
   1141 	my $sleep = 5;
   1142 	my $p2 = "";
   1143 	my $emsg = "";
   1144 	for (my $i=0; $i < $maxtry; $i++)  {
   1145 		my ($if, $p) = ("", $ENV{PPROXY_LISTEN});
   1146 		if ($p =~ /^(.*):(\d+)$/) {
   1147 			$if = $1;
   1148 			$p = $2;
   1149 		}
   1150 		$p2 = "*:$p";
   1151 		if ($if eq "") {
   1152 			$if = "localhost";
   1153 		}
   1154 		print STDERR "pproxy interface: $if\n";
   1155 
   1156 		$emsg = "";
   1157 		if (($if eq "INADDR_ANY6" || $if eq "::") && $have_inet6) {
   1158 			eval {$listen_sock = IO::Socket::INET6->new(
   1159 				Listen    => 2,
   1160 				ReuseAddr => 1,
   1161 				Domain    => AF_INET6,
   1162 				LocalAddr => "::",
   1163 				LocalPort => $p,
   1164 				Proto     => "tcp"
   1165 			);};
   1166 			$p2 = ":::$p";
   1167 		} elsif ($if =~ /^INADDR_ANY/) {
   1168 			$listen_sock = IO::Socket::INET->new(
   1169 				Listen    => 2,
   1170 				ReuseAddr => 1,
   1171 				LocalPort => $p,
   1172 				Proto     => "tcp"
   1173 			);
   1174 		} elsif (($if eq "INADDR_LOOPBACK6" || $if eq "::1") && $have_inet6) {
   1175 			$p2 = "::1:$p";
   1176 			eval {$listen_sock = IO::Socket::INET6->new(
   1177 				Listen    => 2,
   1178 				ReuseAddr => 1,
   1179 				Domain    => AF_INET6,
   1180 				LocalAddr => "::1",
   1181 				LocalPort => $p,
   1182 				Proto     => "tcp"
   1183 			);};
   1184 			$p2 = "::1:$p";
   1185 		} else {
   1186 			$p2 = "$if:$p";
   1187 			$listen_sock = IO::Socket::INET->new(
   1188 				Listen    => 2,
   1189 				ReuseAddr => 1,
   1190 				LocalAddr => $if,
   1191 				LocalPort => $p,
   1192 				Proto     => "tcp"
   1193 			);
   1194 			$emsg = $!;
   1195 			
   1196 			if (! $listen_sock && $have_inet6) {
   1197 				print STDERR "PPROXY_LISTEN: retry with INET6\n";
   1198 				eval {$listen_sock = IO::Socket::INET6->new(
   1199 					Listen    => 2,
   1200 					ReuseAddr => 1,
   1201 					Domain    => AF_INET6,
   1202 					LocalAddr => $if,
   1203 					LocalPort => $p,
   1204 					Proto     => "tcp"
   1205 				);};
   1206 				$emsg .= " / $!";
   1207 			}
   1208 		}
   1209 		if (! $listen_sock) {
   1210 			if ($i < $maxtry - 1) {
   1211 				warn "pproxy: $emsg $!\n";
   1212 				warn "Could not listen on port $p2, retrying in $sleep seconds... (Ctrl-C to quit)\n";
   1213 				sleep $sleep;
   1214 			}
   1215 		} else {
   1216 			last;
   1217 		}
   1218 	}
   1219 	if (! $listen_sock) {
   1220 		pdie "pproxy: $emsg -- PPROXY_LISTEN\n";
   1221 	}
   1222 	print STDERR "pproxy: listening on $p2\n";
   1223 	my $ip;
   1224 	($listen_handle, $ip) = $listen_sock->accept();
   1225 	my $err = $!;
   1226 	close $listen_sock;
   1227 	if (! $listen_handle) {
   1228 		pdie "pproxy: $err\n";
   1229 	}
   1230 
   1231 	if ($ENV{PPROXY_LOOP_THYSELF_MASTER}) {
   1232 		my $sml = $ENV{SSVNC_MULTIPLE_LISTEN}; 
   1233 		if ($sml ne "" && $sml ne "0") {
   1234 			setpgrp(0, 0);
   1235 			if (fork()) {
   1236 				close $viewer_sock;
   1237 				wait;
   1238 				exit 0;
   1239 			}
   1240 			if (fork()) {
   1241 				close $viewer_sock;
   1242 				exit 0;
   1243 			}
   1244 			setpgrp(0, 0);
   1245 			$parent = $$;
   1246 		}
   1247 	}
   1248 }
   1249 
   1250 $sock = IO::Socket::INET->new(
   1251 	PeerAddr => $proxy_host,
   1252 	PeerPort => $proxy_port,
   1253 	Proto => "tcp"
   1254 );
   1255 
   1256 my $err = "";
   1257 
   1258 if (! $sock && $have_inet6) {
   1259 	$err = $!;
   1260 
   1261 	eval {$sock = IO::Socket::INET6->new(
   1262 		PeerAddr => $proxy_host,
   1263 		PeerPort => $proxy_port,
   1264 		Proto => "tcp"
   1265 	);};
   1266 	$err .= " / $!";
   1267 }
   1268 
   1269 if (! $sock) {
   1270 	unlink($0) if $ENV{PPROXY_REMOVE};
   1271 	pdie "pproxy: $err\n";
   1272 }
   1273 
   1274 unlink($0) if $ENV{PPROXY_REMOVE};
   1275 
   1276 if ($ENV{PPROXY_PROXY} =~ /^vencrypt:/ && $ENV{PPROXY_VENCRYPT_REVERSE}) {
   1277 	print STDERR "\nPPROXY: vencrypt+reverse: swapping listen socket with connect socket.\n";
   1278 	my $tmp_swap = $sock;
   1279 	$sock = $listen_handle;
   1280 	$listen_handle = $tmp_swap;
   1281 }
   1282 
   1283 $cur_proxy = $first;
   1284 setmode($mode_1st);
   1285 
   1286 if ($second ne "") {
   1287 	connection($second, 1);
   1288 
   1289 	setmode($mode_2nd);
   1290 	$cur_proxy = $second;
   1291 
   1292 	if ($third ne "") {
   1293 		connection($third, 2);
   1294 		setmode($mode_3rd);
   1295 		$cur_proxy = $third;
   1296 		connection($connect, 3);
   1297 	} else {
   1298 		connection($connect, 2);
   1299 	}
   1300 } else {
   1301 	connection($connect, 1);
   1302 }
   1303 
   1304 sub kill_proxy_pids() {
   1305 	if ($ENV{PPROXY_VENCRYPT_VIEWER_BRIDGE}) {
   1306 		return;
   1307 	}
   1308 	if ($ENV{PPROXY_KILLPID}) {
   1309 		foreach my $p (split(/,/, $ENV{PPROXY_KILLPID})) {
   1310 			if ($p =~ /^(\+|-)/) {
   1311 				$p = $parent + $p;
   1312 			}
   1313 			print STDERR "kill TERM, $p (PPROXY_KILLPID)\n";
   1314 			kill "TERM", $p;
   1315 		}
   1316 	}
   1317 }
   1318 
   1319 sub xfer {
   1320 	my($in, $out) = @_;
   1321 	$RIN = $WIN = $EIN = "";
   1322 	$ROUT = "";
   1323 	vec($RIN, fileno($in), 1) = 1;
   1324 	vec($WIN, fileno($in), 1) = 1;
   1325 	$EIN = $RIN | $WIN;
   1326 
   1327 	while (1) {
   1328 		my $nf = 0;
   1329 		while (! $nf) {
   1330 			$nf = select($ROUT=$RIN, undef, undef, undef);
   1331 		}
   1332 		my $len = sysread($in, $buf, 8192);
   1333 		if (! defined($len)) {
   1334 			next if $! =~ /^Interrupted/;
   1335 			print STDERR "pproxy[$$]: $!\n";
   1336 			last;
   1337 		} elsif ($len == 0) {
   1338 			print STDERR "pproxy[$$]: Input is EOF.\n";
   1339 			last;
   1340 		}
   1341 		my $offset = 0;
   1342 		my $quit = 0;
   1343 		while ($len) {
   1344 			my $written = syswrite($out, $buf, $len, $offset);
   1345 			if (! defined $written) {
   1346 				print STDERR "pproxy[$$]: Output is EOF. $!\n";
   1347 				$quit = 1;
   1348 				last;
   1349 			}
   1350 			$len -= $written;
   1351 			$offset += $written;
   1352 		}
   1353 		last if $quit;
   1354 	}
   1355 	close($out);
   1356 	close($in);
   1357 	print STDERR "pproxy[$$]: finished xfer.\n";
   1358 }
   1359 
   1360 sub handler {
   1361 	print STDERR "pproxy[$$]: got SIGTERM.\n";
   1362 	close $listen_handle if $listen_handle;
   1363 	close $sock if $sock;
   1364 	exit;
   1365 }
   1366 
   1367 sub xfer_both {
   1368 	$child = fork;
   1369 
   1370 	if (! defined $child) {
   1371 		kill_proxy_pids();
   1372 		exit 1;
   1373 	}
   1374 
   1375 	$SIG{TERM} = "handler";
   1376 
   1377 	if ($child) {
   1378 		if ($listen_handle) {
   1379 			print STDERR "pproxy parent[$$]  listen_handle -> socket\n";
   1380 			xfer($listen_handle, $sock);
   1381 		} else {
   1382 			print STDERR "pproxy parent[$$]  STDIN -> socket\n";
   1383 			xfer(STDIN, $sock);
   1384 		}
   1385 		select(undef, undef, undef, 0.25);
   1386 		if (kill 0, $child) {
   1387 			select(undef, undef, undef, 0.9);
   1388 			if (kill 0, $child) {
   1389 				print STDERR "pproxy[$$]: kill TERM child $child\n";
   1390 				kill "TERM", $child;
   1391 			} else {
   1392 				print STDERR "pproxy[$$]: child  $child gone.\n";
   1393 			}
   1394 		}
   1395 	} else {
   1396 		select(undef, undef, undef, 0.05);
   1397 		if ($listen_handle) {
   1398 			print STDERR "pproxy child [$$]  socket -> listen_handle\n";
   1399 			if ($initial_data ne "") {
   1400 				my $len = length $initial_data;
   1401 				print STDERR "pproxy child [$$]  sending initial_data, length $len\n\n";
   1402 				syswrite($listen_handle, $initial_data, $len);
   1403 			} else {
   1404 				print STDERR "\n";
   1405 			}
   1406 			xfer($sock, $listen_handle);
   1407 		} else {
   1408 			print STDERR "pproxy child [$$]  socket -> STDOUT\n";
   1409 			if ($initial_data ne "") {
   1410 				my $len = length $initial_data;
   1411 				print STDERR "pproxy child [$$]  sending initial_data, length $len\n\n";
   1412 				syswrite(STDOUT, $initial_data, $len);
   1413 			} else {
   1414 				print STDERR "\n";
   1415 			}
   1416 			xfer($sock, STDOUT);
   1417 		}
   1418 		select(undef, undef, undef, 0.25);
   1419 		if (kill 0, $parent) {
   1420 			select(undef, undef, undef, 0.8);
   1421 			if (kill 0, $parent) {
   1422 				print STDERR "pproxy[$$]: kill TERM parent $parent\n";
   1423 				kill "TERM", $parent;
   1424 			} else {
   1425 				print STDERR "pproxy[$$]: parent $parent gone.\n";
   1426 			}
   1427 		}
   1428 	}
   1429 
   1430 	kill_proxy_pids();
   1431 }
   1432 
   1433 xfer_both();
   1434 
   1435 exit;
   1436 
   1437 sub fsleep {
   1438 	select(undef, undef, undef, shift);
   1439 }
   1440 
   1441 sub url_parse {
   1442 	my $hostport = shift;
   1443 	my $mode = "http";
   1444 	if ($hostport =~ m,^socks4?://(\S*)$,i) {
   1445 		$mode = "socks4";
   1446 		$hostport = $1;
   1447 	} elsif ($hostport =~ m,^socks5://(\S*)$,i) {
   1448 		$mode = "socks5";
   1449 		$hostport = $1;
   1450 	} elsif ($hostport =~ m,^https?://(\S*)$,i) {
   1451 		$mode = "http";
   1452 		$hostport = $1;
   1453 	} elsif ($hostport =~ m,^ipv6://(\S*)$,i) {
   1454 		$mode = "ipv6";
   1455 		$hostport = $1;
   1456 	} elsif ($hostport =~ m,^repeater://(\S*)\+(\S*)$,i) {
   1457 		# ultravnc repeater proxy.
   1458 		$hostport = $1;
   1459 		$mode = "repeater:$2";
   1460 		if ($hostport !~ /:\d+$/) {
   1461 			$hostport .= ":5900";
   1462 		}
   1463 	} elsif ($hostport =~ m,^vencrypt://(\S*)$,i) {
   1464 		# vencrypt handshake.
   1465 		$hostport = $1;
   1466 		my $m = "connect";
   1467 		if ($hostpost =~ /^(\S+)\+(\S+)$/) {
   1468 			$hostport = $1;
   1469 			$mode = $2;
   1470 		}
   1471 		$mode = "vencrypt:$m";
   1472 		if ($hostport !~ /:\d+$/) {
   1473 			$hostport .= ":5900";
   1474 		}
   1475 	}
   1476 	return ($hostport, $mode);
   1477 }
   1478 
   1479 sub setmode {
   1480 	my $mode = shift;
   1481 	$ENV{PPROXY_REPEATER} = "";
   1482 	$ENV{PPROXY_VENCRYPT} = "";
   1483 	if ($mode =~ /^socks/) {
   1484 		if ($mode =~ /^socks5/) {
   1485 			$ENV{PPROXY_SOCKS} = 5;
   1486 		} else {
   1487 			$ENV{PPROXY_SOCKS} = 1;
   1488 		}
   1489 	} elsif ($mode =~ /^ipv6/i) {
   1490 		$ENV{PPROXY_SOCKS} = 0;
   1491 	} elsif ($mode =~ /^repeater:(.*)/) {
   1492 		$ENV{PPROXY_REPEATER} = $1;
   1493 		$ENV{PPROXY_SOCKS} = "";
   1494 	} elsif ($mode =~ /^vencrypt:(.*)/) {
   1495 		$ENV{PPROXY_VENCRYPT} = $1;
   1496 		$ENV{PPROXY_SOCKS} = "";
   1497 	} else {
   1498 		$ENV{PPROXY_SOCKS} = "";
   1499 	}
   1500 }
   1501 
   1502 sub connection {
   1503 	my ($CONNECT, $w) = @_;
   1504 
   1505 	my $con = "";
   1506 	my $msg = "";
   1507 
   1508 	if ($ENV{PPROXY_SOCKS} eq "5") {
   1509 		# SOCKS5
   1510 		my ($h, $p) = ($CONNECT, "");
   1511 		if ($h =~ /^(.*):(\d+)$/) {
   1512 			$h = $1;
   1513 			$p = $2;
   1514 		}
   1515 		$con .= pack("C", 0x05);
   1516 		$con .= pack("C", 0x01);
   1517 		$con .= pack("C", 0x00);
   1518 
   1519 		$msg = "SOCKS5 via $cur_proxy to $h:$p\n\n";
   1520 		print STDERR "proxy_request$w: $msg";
   1521 
   1522 		syswrite($sock, $con, length($con));
   1523 
   1524 		my ($n1, $n2, $n3, $n4, $n5, $n6);
   1525 		my ($r1, $r2, $r3, $r4, $r5, $r6);
   1526 		my ($s1, $s2, $s3, $s4, $s5, $s6);
   1527 
   1528 		$n1 = sysread($sock, $r1, 1);
   1529 		$n2 = sysread($sock, $r2, 1);
   1530 
   1531 		$s1 = unpack("C", $r1);
   1532 		$s2 = unpack("C", $r2);
   1533 		if ($s1 != 0x05 || $s2 != 0x00) {
   1534 			print STDERR "SOCKS5 fail s1=$s1 s2=$s2 n1=$n1 n2=$n2\n";
   1535 			close $sock;
   1536 			exit(1);
   1537 		}
   1538 
   1539 		$con = "";
   1540 		$con .= pack("C", 0x05);
   1541 		$con .= pack("C", 0x01);
   1542 		$con .= pack("C", 0x00);
   1543 		$con .= pack("C", 0x03);
   1544 		$con .= pack("C", length($h));
   1545 		$con .= $h;
   1546 		$con .= pack("C", $p >> 8);
   1547 		$con .= pack("C", $p & 0xff);
   1548 
   1549 		syswrite($sock, $con, length($con));
   1550 
   1551 		$n1 = sysread($sock, $r1, 1);
   1552 		$n2 = sysread($sock, $r2, 1);
   1553 		$n3 = sysread($sock, $r3, 1);
   1554 		$n4 = sysread($sock, $r4, 1);
   1555 		$s1 = unpack("C", $r1);
   1556 		$s2 = unpack("C", $r2);
   1557 		$s3 = unpack("C", $r3);
   1558 		$s4 = unpack("C", $r4);
   1559 
   1560 		if ($s4 == 0x1) {
   1561 			sysread($sock, $r5, 4 + 2);
   1562 		} elsif ($s4 == 0x3) {
   1563 			sysread($sock, $r5, 1);
   1564 			$s5 = unpack("C", $r5);
   1565 			sysread($sock, $r6, $s5 + 2);
   1566 		} elsif ($s4 == 0x4) {
   1567 			sysread($sock, $r5, 16 + 2);
   1568 		}
   1569 
   1570 		if ($s1 != 0x5 || $s2 != 0x0 || $s3 != 0x0) {
   1571 			print STDERR "SOCKS5 failed: s1=$s1 s2=$s2 s3=$s3 s4=$s4 n1=$n1 n2=$n2 n3=$n3 n4=$n4\n";
   1572 			close $sock;
   1573 			exit(1);
   1574 		}
   1575 
   1576 	} elsif ($ENV{PPROXY_SOCKS} eq "1") {
   1577 		# SOCKS4 SOCKS4a
   1578 		my ($h, $p) = ($CONNECT, "");
   1579 		if ($h =~ /^(.*):(\d+)$/) {
   1580 			$h = $1;
   1581 			$p = $2;
   1582 		}
   1583 		$con .= pack("C", 0x04);
   1584 		$con .= pack("C", 0x01);
   1585 		$con .= pack("n", $p);
   1586 
   1587 		my $SOCKS_4a = 0;
   1588 		if ($h eq "localhost" || $h eq "127.0.0.1") {
   1589 			$con .= pack("C", 127);
   1590 			$con .= pack("C", 0);
   1591 			$con .= pack("C", 0);
   1592 			$con .= pack("C", 1);
   1593 		} elsif ($h =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) {
   1594 			$con .= pack("C", $1);
   1595 			$con .= pack("C", $2);
   1596 			$con .= pack("C", $3);
   1597 			$con .= pack("C", $4);
   1598 		} else {
   1599 			$con .= pack("C", 0);
   1600 			$con .= pack("C", 0);
   1601 			$con .= pack("C", 0);
   1602 			$con .= pack("C", 3);
   1603 			$SOCKS_4a = 1;
   1604 		}
   1605 
   1606 		$con .= "nobody";
   1607 		$con .= pack("C", 0);
   1608 
   1609 		$msg = "SOCKS4 via $cur_proxy to $h:$p\n\n";
   1610 		if ($SOCKS_4a) {
   1611 			$con .= $h;
   1612 			$con .= pack("C", 0);
   1613 			$msg =~ s/SOCKS4/SOCKS4a/;
   1614 		}
   1615 		print STDERR "proxy_request$w: $msg";
   1616 		syswrite($sock, $con, length($con));
   1617 
   1618 		my $ok = 1;
   1619 		for (my $i = 0; $i < 8; $i++) {
   1620 			my $c;
   1621 			sysread($sock, $c, 1);
   1622 			my $s = unpack("C", $c);
   1623 			if ($i == 0) {
   1624 				$ok = 0 if $s != 0x0;
   1625 			} elsif ($i == 1) {
   1626 				$ok = 0 if $s != 0x5a;
   1627 			}
   1628 		}
   1629 		if (! $ok) {
   1630 			print STDERR "SOCKS4 failed.\n";
   1631 			close $sock;
   1632 			exit(1);
   1633 		}
   1634 	} elsif ($ENV{PPROXY_SOCKS} eq "0") {
   1635 		# hack for ipv6 "proxy", nothing to do, assume INET6 call worked.
   1636 		;
   1637 	} elsif ($ENV{PPROXY_REPEATER} ne "") {
   1638 		my $rep = $ENV{PPROXY_REPEATER};
   1639 		print STDERR "repeater: $rep\n";
   1640 		$rep .= pack("x") x 250;
   1641 		syswrite($sock, $rep, 250);
   1642 
   1643 		my $rfb = "";
   1644 
   1645 		my $ok = 1;
   1646 		for (my $i = 0; $i < 12; $i++) {
   1647 			my $c;
   1648 			last if $ENV{PPROXY_GENERIC_REPEATER};
   1649 			sysread($sock, $c, 1);
   1650 			print STDERR $c;
   1651 			$rfb .= $c;
   1652 		}
   1653 		if ($rfb ne "" && $rfb !~ /^RFB 000\.000/) {
   1654 			$initial_data = $rfb;
   1655 			$rfb =~ s/\n//g;
   1656 			print STDERR "detected non-UltraVNC repeater; forwarding \"$rfb\"\nlength: ", length($initial_data), "\n";
   1657 		}
   1658 	} elsif ($ENV{PPROXY_VENCRYPT} ne "") {
   1659 		my $vencrypt = $ENV{PPROXY_VENCRYPT};
   1660 		vencrypt_dialog($vencrypt);
   1661 
   1662 	} else {
   1663 		# Web Proxy:
   1664 		$con = "CONNECT $CONNECT HTTP/1.1\r\n";
   1665 		$con   .= "Host: $CONNECT\r\n";
   1666 		$con   .= "Connection: close\r\n\r\n";
   1667 		$msg = $con;
   1668 
   1669 		print STDERR "proxy_request$w: via $cur_proxy:\n$msg";
   1670 		syswrite($sock, $con, length($con));
   1671 
   1672 		my $rep = "";
   1673 		my $n = 0;
   1674 		while ($rep !~ /\r\n\r\n/ && $n < 30000) {
   1675 			my $c;
   1676 			sysread($sock, $c, 1);
   1677 			print STDERR $c;
   1678 			$rep .= $c;
   1679 			$n++;
   1680 		}
   1681 		if ($rep !~ m,HTTP/.* 200,) {
   1682 			print STDERR "HTTP CONNECT failed.\n";
   1683 			close $sock;
   1684 			exit(1);
   1685 		}
   1686 	}
   1687 }
   1688 
   1689 sub vdie {
   1690 	append_handshake("done\n");
   1691 	close $sock;
   1692 	kill_proxy_pids();
   1693 	exit(1);
   1694 }
   1695 
   1696 sub anontls_handshake {
   1697 	my ($vmode, $db) = @_;
   1698 
   1699 	print STDERR "\nPPROXY: Doing ANONTLS Handshake\n";
   1700 
   1701 	my $psec = pack("C", $rfbSecTypeAnonTls);
   1702 	syswrite($sock, $psec, 1);
   1703 
   1704 	append_handshake("done\n");
   1705 }
   1706 
   1707 sub vencrypt_handshake {
   1708 	
   1709 	my ($vmode, $db) = @_;
   1710 
   1711 	print STDERR "\nPPROXY: Doing VeNCrypt Handshake\n";
   1712 
   1713 	my $psec = pack("C", $rfbSecTypeVencrypt);
   1714 
   1715 	if (exists $ENV{SSVNC_TEST_SEC_TYPE}) {
   1716 		my $fake = $ENV{SSVNC_TEST_SEC_TYPE};
   1717 		print STDERR "PPROXY: sending sec-type: $fake\n";
   1718 		$psec = pack("C", $fake);
   1719 	}
   1720 
   1721 	syswrite($sock, $psec, 1);
   1722 
   1723 	my $vmajor;
   1724 	my $vminor;
   1725 	sysread($sock, $vmajor, 1);
   1726 	sysread($sock, $vminor, 1);
   1727 
   1728 	vdie if $vmajor eq "" || $vminor eq "";
   1729 
   1730 	$vmajor = unpack("C", $vmajor);
   1731 	$vminor = unpack("C", $vminor);
   1732 	print STDERR "server vencrypt version $vmajor.$vminor\n" if $db;
   1733 
   1734 	if (exists $ENV{SSVNC_TEST_SEC_TYPE}) {
   1735 		print STDERR "PPROXY: continuing on in test mode.\n";
   1736 	} else {
   1737 		vdie if $vmajor ne 0;
   1738 		vdie if $vminor < 2;
   1739 	}
   1740 
   1741 	$vmajor = pack("C", 0);
   1742 	$vminor = pack("C", 2);
   1743 	append_handshake("subversion=0.2\n");
   1744 
   1745 	syswrite($sock, $vmajor, 1);
   1746 	syswrite($sock, $vminor, 1);
   1747 
   1748 	my $result;
   1749 	sysread($sock, $result, 1);
   1750 	print STDERR "result empty\n" if $db && $result eq "";
   1751 
   1752 	vdie if $result eq "";
   1753 	$result = unpack("C", $result);
   1754 	print STDERR "result=$result\n" if $db;
   1755 
   1756 	vdie if $result ne 0;
   1757 
   1758 	my $nsubtypes;
   1759 	sysread($sock, $nsubtypes, 1);
   1760 
   1761 	vdie if $nsubtypes eq "";
   1762 	$nsubtypes = unpack("C", $nsubtypes);
   1763 	print STDERR "nsubtypes=$nsubtypes\n" if $db;
   1764 
   1765 	my %subtypes;
   1766 
   1767 	for (my $i = 0; $i < $nsubtypes; $i++) {
   1768 		my $subtype = ""; 
   1769 		sysread($sock, $subtype, 4);
   1770 		vdie if length($subtype) != 4;
   1771 
   1772 		# XXX fix 64bit.
   1773 		$subtype = unpack("N", $subtype);
   1774 		print STDERR "subtype: $subtype\n" if $db;
   1775 		$subtypes{$subtype} = 1;
   1776 		append_handshake("sst$i=$subtype\n");
   1777 	}
   1778 
   1779 	my $subtype = 0;
   1780 	if (exists $subtypes{$rfbVencryptX509None})  {
   1781 		$subtype = $rfbVencryptX509None;
   1782 		print STDERR "selected rfbVencryptX509None\n" if $db;
   1783 	} elsif (exists $subtypes{$rfbVencryptX509Vnc})  {
   1784 		$subtype = $rfbVencryptX509Vnc;
   1785 		print STDERR "selected rfbVencryptX509Vnc\n" if $db;
   1786 	} elsif (exists $subtypes{$rfbVencryptX509Plain})  {
   1787 		$subtype = $rfbVencryptX509Plain;
   1788 		print STDERR "selected rfbVencryptX509Plain\n" if $db;
   1789 	} elsif (exists $subtypes{$rfbVencryptTlsNone})  {
   1790 		$subtype = $rfbVencryptTlsNone;
   1791 		print STDERR "selected rfbVencryptTlsNone\n" if $db;
   1792 	} elsif (exists $subtypes{$rfbVencryptTlsVnc})  {
   1793 		$subtype = $rfbVencryptTlsVnc;
   1794 		print STDERR "selected rfbVencryptTlsVnc\n" if $db;
   1795 	} elsif (exists $subtypes{$rfbVencryptTlsPlain})  {
   1796 		$subtype = $rfbVencryptTlsPlain;
   1797 		print STDERR "selected rfbVencryptTlsPlain\n" if $db;
   1798 	}
   1799 
   1800 	if (exists $ENV{SSVNC_TEST_SEC_SUBTYPE}) {
   1801 		my $fake = $ENV{SSVNC_TEST_SEC_SUBTYPE};
   1802 		print STDERR "PPROXY: sending sec-subtype: $fake\n";
   1803 		$subtype = $fake;
   1804 	}
   1805 
   1806 	append_handshake("subtype=$subtype\n");
   1807 
   1808 	my $pst = pack("N", $subtype);
   1809 	syswrite($sock, $pst, 4); 
   1810 
   1811 	if (exists $ENV{SSVNC_TEST_SEC_SUBTYPE}) {
   1812 		print STDERR "PPROXY: continuing on in test mode.\n";
   1813 	} else {
   1814 		vdie if $subtype == 0;
   1815 	}
   1816 
   1817 	my $ok;
   1818 	sysread($sock, $ok, 1);
   1819 	$ok = unpack("C", $ok);
   1820 	print STDERR "ok=$ok\n" if $db;
   1821 
   1822 	append_handshake("done\n");
   1823 
   1824 	vdie if $ok == 0;
   1825 }
   1826 
   1827 sub vencrypt_dialog {
   1828 	my $vmode = shift;
   1829 	my $db = 0;
   1830 
   1831 	$db = 1 if exists $ENV{SS_DEBUG};
   1832 	$db = 1 if exists $ENV{SSVNC_VENCRYPT_DEBUG};
   1833 
   1834 	append_handshake("mode=$vmode\n");
   1835 
   1836 	my $server_rfb = "";
   1837 	#syswrite($sock, $rep, 250);
   1838 	for (my $i = 0; $i < 12; $i++) {
   1839 		my $c;
   1840 		sysread($sock, $c, 1);
   1841 		$server_rfb .= $c;
   1842 		print STDERR $c;
   1843 	}
   1844 	print STDERR "server_rfb: $server_rfb\n" if $db;
   1845 	append_handshake("server=$server_rfb");
   1846 
   1847 	my $minor = "";
   1848 	if ($server_rfb =~ /^RFB 003\.(\d+)/) {
   1849 		$minor = $1;
   1850 	} else {
   1851 		vdie;
   1852 	}
   1853 	my $viewer_rfb = "RFB 003.008\n";
   1854 	if ($minor < 7) {
   1855 		vdie;
   1856 	} elsif ($minor == 7) {
   1857 		$viewer_rfb = "RFB 003.007\n";
   1858 	}
   1859 	my $nsec;
   1860 	my $t1 = gettime();
   1861 	my $t0 = gettime();
   1862 
   1863 	syswrite($sock, $viewer_rfb, 12);
   1864 	sysread($sock, $nsec, 1);
   1865 
   1866 	$t1 = gettime();
   1867 	$t1 = sprintf("%.6f", $t1 - $t0);
   1868 
   1869 	append_handshake("viewer=$viewer_rfb");
   1870 	append_handshake("latency=$t1\n");
   1871 
   1872 	vdie if $nsec eq "";
   1873 
   1874 	$nsec = unpack("C", $nsec);
   1875 
   1876 	print STDERR "nsec: $nsec\n" if $db;
   1877 	vdie if $nsec eq 0 || $nsec > 100;
   1878 
   1879 	my %sectypes = ();
   1880 
   1881 	for (my $i = 0; $i < $nsec; $i++) {
   1882 		my $sec;
   1883 		sysread($sock, $sec, 1);
   1884 		vdie if $sec eq "";
   1885 		$sec = unpack("C", $sec);
   1886 		print STDERR "sec: $sec\n" if $db;
   1887 		$sectypes{$sec} = 1;
   1888 	}
   1889 	
   1890 	if (exists $sectypes{$rfbSecTypeVencrypt}) {
   1891 		print STDERR "found rfbSecTypeVencrypt\n" if $db;
   1892 		append_handshake("sectype=$rfbSecTypeVencrypt\n");
   1893 		vencrypt_handshake($vmode, $db);
   1894 	} elsif (exists $sectypes{$rfbSecTypeAnonTls}) {
   1895 		print STDERR "found rfbSecTypeAnonTls\n" if $db;
   1896 		append_handshake("sectype=$rfbSecTypeAnonTls\n");
   1897 		anontls_handshake($vmode, $db);
   1898 	} else {
   1899 		print STDERR "No supported sec-type found\n" if $db;
   1900 		vdie;
   1901 	}
   1902 }
   1903 
   1904 sub append_handshake {
   1905 	my $str = shift;
   1906 	if ($handshake_file) {
   1907 		if (open(HSF, ">>$handshake_file")) {
   1908 			print HSF $str;
   1909 			close HSF;
   1910 		}
   1911 	}
   1912 }
   1913 
   1914 sub do_vencrypt_viewer_bridge {
   1915 	my ($listen, $connect) = @_;
   1916 	print STDERR "\npproxy: starting vencrypt_viewer_bridge[$$]: $listen \-> $connect\n";
   1917 	my $db = 0;
   1918 	my $backwards = 0;
   1919 	if ($listen < 0) {
   1920 		$backwards = 1;
   1921 		$listen = -$listen;
   1922 	}
   1923 	if ($handshake_file eq "") {
   1924 		die "pproxy: vencrypt_viewer_bridge[$$]: no SSVNC_PREDIGESTED_HANDSHAKE\n";
   1925 	}
   1926 	my $listen_sock;
   1927 	my $maxtry = 12;
   1928 	my $sleep = 5;
   1929 	for (my $i=0; $i < $maxtry; $i++)  {
   1930 		$listen_sock = IO::Socket::INET->new(
   1931 			Listen    => 2,
   1932 			ReuseAddr => 1,
   1933 			LocalAddr => "127.0.0.1",
   1934 			LocalPort => $listen,
   1935 			Proto     => "tcp"
   1936 		);
   1937 		if (! $listen_sock) {
   1938 			if ($i < $maxtry - 1) {
   1939 				warn "pproxy: vencrypt_viewer_bridge[$$]: $!\n";
   1940 				warn "Could not listen on port $listen, retrying in $sleep seconds... (Ctrl-C to quit)\n";
   1941 				sleep $sleep;
   1942 			}
   1943 		} else {
   1944 			last;
   1945 		}
   1946 	}
   1947 	if (! $listen_sock) {
   1948 		die "pproxy: vencrypt_viewer_bridge[$$]: $!\n";
   1949 	}
   1950 	print STDERR "pproxy: vencrypt_viewer_bridge[$$]: listening on port $listen\n\n";
   1951 	my ($viewer_sock, $ip) = $listen_sock->accept();
   1952 	my $err = $!;
   1953 	close $listen_sock;
   1954 	if (! $viewer_sock) {
   1955 		die "pproxy: vencrypt_viewer_bridge[$$]: $err\n";
   1956 	}
   1957 	if ($ENV{PPROXY_LOOP_THYSELF_MASTER}) {
   1958 		my $sml = $ENV{SSVNC_MULTIPLE_LISTEN}; 
   1959 		if ($sml ne "" && $sml ne "0") {
   1960 			setpgrp(0, 0);
   1961 			if (fork()) {
   1962 				close $viewer_sock;
   1963 				wait;
   1964 				exit 0;
   1965 			}
   1966 			if (fork()) {
   1967 				close $viewer_sock;
   1968 				exit 0;
   1969 			}
   1970 			setpgrp(0, 0);
   1971 			$parent = $$;
   1972 		}
   1973 	}
   1974 	print STDERR "vencrypt_viewer_bridge[$$]: viewer_sock $viewer_sock\n" if $db;
   1975 
   1976 	print STDERR "pproxy: vencrypt_viewer_bridge[$$]: connecting to 127.0.0.1:$connect\n";
   1977 	my $server_sock = IO::Socket::INET->new(
   1978 		PeerAddr => "127.0.0.1",
   1979 		PeerPort => $connect,
   1980 		Proto => "tcp"
   1981 	);
   1982 	print STDERR "vencrypt_viewer_bridge[$$]: server_sock $server_sock\n" if $db;
   1983 	if (! $server_sock) {
   1984 		my $err = $!;
   1985 		die "pproxy: vencrypt_viewer_bridge[$$]: $err\n";
   1986 	}
   1987 
   1988 	if ($backwards) {
   1989 		print STDERR "vencrypt_viewer_bridge[$$]: reversing roles of viewer and server.\n";
   1990 		my $t = $viewer_sock;
   1991 		$viewer_sock = $server_sock;
   1992 		$server_sock = $t;
   1993 	}
   1994 
   1995 	my %hs = ();
   1996 	my $dt = 0.2;
   1997 	my $slept = 0.0;
   1998 	while ($slept < 20.0) {
   1999 		select(undef, undef, undef, $dt);
   2000 		$slept += $dt;
   2001 		if (-f $handshake_file && open(HSF, "<$handshake_file")) {
   2002 			my $done = 0;
   2003 			%hs = ();
   2004 			my $str = "";
   2005 			while (<HSF>) {
   2006 				print STDERR "vencrypt_viewer_bridge[$$]: $_" if $ENV{VENCRYPT_VIEWER_BRIDGE_DEBUG};
   2007 				$str .= "vencrypt_viewer_bridge[$$]: $_";
   2008 				chomp;
   2009 				if ($_ eq "done") {
   2010 					$done = 1;
   2011 				} else {
   2012 					my ($k, $v) = split(/=/, $_, 2);
   2013 					if ($k ne "" && $v ne "") {
   2014 						$hs{$k} = $v;
   2015 					}
   2016 				}
   2017 			}
   2018 			close HSF;
   2019 			if ($done) {
   2020 				print STDERR "\n" . $str;
   2021 				last;
   2022 			}
   2023 		}
   2024 	}
   2025 	if (! exists $hs{server}) {
   2026 		$hs{server} = "RFB 003.008";
   2027 	}
   2028 	if (! exists $hs{sectype}) {
   2029 		unlink($handshake_file);
   2030 		die "pproxy: vencrypt_viewer_bridge[$$]: no sectype.\n";
   2031 	}
   2032 	syswrite($viewer_sock, "$hs{server}\n", length($hs{server}) + 1);
   2033 	my $viewer_rfb = "";
   2034 	for (my $i = 0; $i < 12; $i++) {
   2035 		my $c;
   2036 		sysread($viewer_sock, $c, 1);
   2037 		$viewer_rfb .= $c;
   2038 		print STDERR $c;
   2039 	}
   2040 	my $viewer_major = 3;
   2041 	my $viewer_minor = 8;
   2042 	if ($viewer_rfb =~ /RFB (\d+)\.(\d+)/) {
   2043 		$viewer_major = $1;	
   2044 		$viewer_minor = $2;	
   2045 	}
   2046 	my $u0 = pack("C", 0);
   2047 	my $u1 = pack("C", 1);
   2048 	my $u2 = pack("C", 2);
   2049 	if ($hs{sectype} == $rfbSecTypeAnonTls) {
   2050 		unlink($handshake_file);
   2051 		print STDERR "\npproxy: vencrypt_viewer_bridge[$$]: rfbSecTypeAnonTls\n";
   2052 		if ($viewer_major > 3 || $viewer_minor >= 7) {
   2053 			;	# setup ok, proceed to xfer.
   2054 		} else {
   2055 			print STDERR "pproxy: vencrypt_viewer_bridge[$$]: faking RFB version 3.3 to viewer.\n";
   2056 			my $n;
   2057 			sysread($server_sock, $n, 1);
   2058 			$n = unpack("C", $n);
   2059 			if ($n == 0) {
   2060 				die "pproxy: vencrypt_viewer_bridge[$$]: nsectypes == $n.\n";
   2061 			}
   2062 			my %types;
   2063 			for (my $i = 0; $i < $n; $i++) {
   2064 				my $t;
   2065 				sysread($server_sock, $t, 1);
   2066 				$t = unpack("C", $t);
   2067 				$types{$t} = 1;
   2068 			}
   2069 			my $use = 1;	# None
   2070 			if (exists $types{1}) {
   2071 				$use = 1;	# None
   2072 			} elsif (exists $types{2}) {
   2073 				$use = 2;	# VncAuth
   2074 			} else {
   2075 				die "pproxy: vencrypt_viewer_bridge[$$]: no valid sectypes" . join(",", keys %types) . "\n";
   2076 			}
   2077 				
   2078 			# send 4 bytes sectype to viewer: 
   2079 			# (note this should be MSB, network byte order...)
   2080 			my $up = pack("C", $use);
   2081 			syswrite($viewer_sock, $u0, 1);
   2082 			syswrite($viewer_sock, $u0, 1);
   2083 			syswrite($viewer_sock, $u0, 1);
   2084 			syswrite($viewer_sock, $up, 1);
   2085 			# and tell server the one we selected:
   2086 			syswrite($server_sock, $up, 1);
   2087 			if ($use == 1) {
   2088 				# even None has security result, so read it here and discard it.
   2089 				my $sr = "";
   2090 				sysread($server_sock, $sr, 4);
   2091 			}
   2092 		}
   2093 	} elsif ($hs{sectype} == $rfbSecTypeVencrypt) {
   2094 		print STDERR "\npproxy: vencrypt_viewer_bridge[$$]: rfbSecTypeVencrypt\n";
   2095 		if (! exists $hs{subtype}) {
   2096 			unlink($handshake_file);
   2097 			die "pproxy: vencrypt_viewer_bridge[$$]: no subtype.\n";
   2098 		}
   2099 		my $fake_type = "None";
   2100 		my $plain = 0;
   2101 		my $sub_type = $hs{subtype};
   2102 		if ($sub_type == $rfbVencryptTlsNone) {
   2103 			$fake_type = "None";
   2104 		} elsif ($sub_type == $rfbVencryptTlsVnc) {
   2105 			$fake_type = "VncAuth";
   2106 		} elsif ($sub_type == $rfbVencryptTlsPlain) {
   2107 			$fake_type = "None";
   2108 			$plain = 1;
   2109 		} elsif ($sub_type == $rfbVencryptX509None) {
   2110 			$fake_type = "None";
   2111 		} elsif ($sub_type == $rfbVencryptX509Vnc) {
   2112 			$fake_type = "VncAuth";
   2113 		} elsif ($sub_type == $rfbVencryptX509Plain) {
   2114 			$fake_type = "None";
   2115 			$plain = 1;
   2116 		}
   2117 		if ($plain) {
   2118 			if (!open(W, ">$handshake_file")) {
   2119 				unlink($handshake_file);
   2120 				die "pproxy: vencrypt_viewer_bridge[$$]: $handshake_file $!\n";
   2121 			}
   2122 			print W <<"END";
   2123 
   2124 			proc print_out {} {
   2125 				global user pass env
   2126 
   2127 				if [info exists env(SSVNC_UP_DEBUG)] {
   2128 					toplevel .b
   2129 					button .b.b -text "user=\$user pass=\$pass" -command {destroy .b}
   2130 					pack .b.b
   2131 					update
   2132 					tkwait window .b
   2133 				}
   2134 				
   2135 				if [info exists env(SSVNC_UP_FILE)] {
   2136 					set fh "" 
   2137 					catch {set fh [open \$env(SSVNC_UP_FILE) w]}
   2138 					if {\$fh != ""} {
   2139 						puts \$fh user=\$user\\npass=\$pass
   2140 						flush \$fh
   2141 						close \$fh
   2142 						return
   2143 					}
   2144 				}
   2145 				puts stdout user=\$user\\npass=\$pass
   2146 				flush stdout
   2147 			}
   2148 
   2149 			proc center_win {w} {
   2150 				update
   2151 				set W [winfo screenwidth  \$w]
   2152 				set W [expr \$W + 1]
   2153 				wm geometry \$w +\$W+0
   2154 				update
   2155 				set x [expr [winfo screenwidth  \$w]/2 - [winfo width  \$w]/2]
   2156 				set y [expr [winfo screenheight \$w]/2 - [winfo height \$w]/2]
   2157 
   2158 				wm geometry \$w +\$x+\$y
   2159 				wm deiconify \$w
   2160 				update
   2161 			}
   2162 
   2163 			wm withdraw .
   2164 
   2165 			global env
   2166 			set up {}
   2167 			if [info exists env(SSVNC_UNIXPW)] {
   2168 				set rm 0
   2169 				set up \$env(SSVNC_UNIXPW)
   2170 				if [regexp {^rm:} \$up]  {
   2171 					set rm 1
   2172 					regsub {^rm:} \$up {} up
   2173 				}
   2174 				if [file exists \$up] {
   2175 					set fh ""
   2176 					set f \$up
   2177 					catch {set fh [open \$up r]}
   2178 					if {\$fh != ""} {
   2179 						gets \$fh u	
   2180 						gets \$fh p	
   2181 						close \$fh
   2182 						set up "\$u@\$p"
   2183 					}
   2184 					if {\$rm} {
   2185 						catch {file delete \$f}
   2186 					}
   2187 				}
   2188 			} elseif [info exists env(SSVNC_VENCRYPT_USERPASS)] {
   2189 				set up \$env(SSVNC_VENCRYPT_USERPASS)
   2190 			}
   2191 			#puts stderr up=\$up
   2192 			if {\$up != ""} {
   2193 				if [regexp {@} \$up] {
   2194 					global user pass
   2195 					set user \$up
   2196 					set pass \$up
   2197 					regsub {@.*\$}  \$user "" user
   2198 					regsub {^[^@]*@} \$pass "" pass
   2199 					print_out
   2200 					exit
   2201 				}
   2202 			}
   2203 
   2204 			wm title . {VeNCrypt Viewer Bridge User/Pass}
   2205 
   2206 			set user {}
   2207 			set pass {}
   2208 
   2209 			label .l -text {SSVNC VeNCrypt Viewer Bridge}
   2210 
   2211 			frame .f0
   2212 			frame .f0.fL
   2213 			label .f0.fL.la -text {Username: }
   2214 			label .f0.fL.lb -text {Password: }
   2215 
   2216 			pack .f0.fL.la .f0.fL.lb -side top
   2217 
   2218 			frame .f0.fR
   2219 			entry .f0.fR.ea -width 24 -textvariable user
   2220 			entry .f0.fR.eb -width 24 -textvariable pass -show *
   2221 
   2222 			pack .f0.fR.ea .f0.fR.eb -side top -fill x
   2223 
   2224 			pack .f0.fL -side left
   2225 			pack .f0.fR -side right -expand 1 -fill x
   2226 
   2227 			button .no -text Cancel -command {destroy .}
   2228 			button .ok -text Done   -command {print_out; destroy .}
   2229 
   2230 			center_win .
   2231 			pack .l .f0 .no .ok -side top -fill x
   2232 			update
   2233 			wm deiconify .
   2234 
   2235 			bind .f0.fR.ea <Return> {focus .f0.fR.eb}
   2236 			bind .f0.fR.eb <Return> {print_out; destroy .}
   2237 			focus .f0.fR.ea
   2238 
   2239 			wm resizable . 1 0
   2240 			wm minsize . [winfo reqwidth .] [winfo reqheight .]
   2241 END
   2242 			close W;
   2243 
   2244 			#system("cat $handshake_file");
   2245 			my $w = "wish";
   2246 			if ($ENV{WISH}) {
   2247 				$w = $ENV{WISH};	
   2248 			}
   2249 			print STDERR "pproxy: vencrypt_viewer_bridge[$$]: prompt  VencryptPlain user and passwd.\n";
   2250 			my $res = "";
   2251 			if (`uname` =~ /Darwin/) {
   2252 				my $mtmp = `mktemp /tmp/hsup.XXXXXX`;
   2253 				chomp $mtmp;
   2254 				system("env SSVNC_UP_FILE=$mtmp $w $handshake_file");
   2255 				$res = `cat $mtmp`;
   2256 				unlink $mtmp;
   2257 			} else {
   2258 				$res = `$w $handshake_file`;
   2259 			}
   2260 			my $user = "";
   2261 			my $pass = "";
   2262 			if ($res =~ /user=(\S*)/) {
   2263 				$user = $1;
   2264 			}
   2265 			if ($res =~ /pass=(\S*)/) {
   2266 				$pass = $1;
   2267 			}
   2268 			print STDERR "pproxy: vencrypt_viewer_bridge[$$]: sending VencryptPlain user and passwd.\n";
   2269 			my $ulen = pack("C", length($user));
   2270 			my $plen = pack("C", length($pass));
   2271 			# (note this should be MSB, network byte order...)
   2272 			syswrite($server_sock, $u0, 1);
   2273 			syswrite($server_sock, $u0, 1);
   2274 			syswrite($server_sock, $u0, 1);
   2275 			syswrite($server_sock, $ulen, 1);
   2276 			syswrite($server_sock, $u0, 1);
   2277 			syswrite($server_sock, $u0, 1);
   2278 			syswrite($server_sock, $u0, 1);
   2279 			syswrite($server_sock, $plen, 1);
   2280 			syswrite($server_sock, $user, length($user));
   2281 			syswrite($server_sock, $pass, length($pass));
   2282 		}
   2283 		unlink($handshake_file);
   2284 
   2285 		my $ft = 0;
   2286 		if ($fake_type eq "None") {
   2287 			$ft = 1;
   2288 		} elsif ($fake_type eq "VncAuth") {
   2289 			$ft = 2;
   2290 		} else {
   2291 			die "pproxy: vencrypt_viewer_bridge[$$]: unknown fake type: $fake_type\n";
   2292 		}
   2293 		my $fp = pack("C", $ft);
   2294 		if ($viewer_major > 3 || $viewer_minor >= 7) {
   2295 			syswrite($viewer_sock, $u1, 1);
   2296 			syswrite($viewer_sock, $fp, 1);
   2297 			my $cr;
   2298 			sysread($viewer_sock, $cr, 1);
   2299 			$cr = unpack("C", $cr);
   2300 			if ($cr != $ft) {
   2301 				die "pproxy: vencrypt_viewer_bridge[$$]: client selected wrong type: $cr / $ft\n";
   2302 			}
   2303 		} else {
   2304 			print STDERR "pproxy: vencrypt_viewer_bridge[$$]: faking RFB version 3.3 to viewer.\n";
   2305 			# send 4 bytes sect type to viewer: 
   2306 			# (note this should be MSB, network byte order...)
   2307 			syswrite($viewer_sock, $u0, 1);
   2308 			syswrite($viewer_sock, $u0, 1);
   2309 			syswrite($viewer_sock, $u0, 1);
   2310 			syswrite($viewer_sock, $fp, 1);
   2311 			if ($ft == 1) {
   2312 				# even None has security result, so read it here and discard it.
   2313 				my $sr = "";
   2314 				sysread($server_sock, $sr, 4);
   2315 			}
   2316 		}
   2317 	}
   2318 
   2319 	$listen_handle = $viewer_sock;
   2320 	$sock = $server_sock;
   2321 
   2322 	xfer_both();
   2323 }
   2324 '
   2325 	# '
   2326 	# xpg_echo will expand \n \r, etc.
   2327 	# try to unset and then test for it.
   2328 	if type shopt > /dev/null 2>&1; then
   2329 		shopt -u xpg_echo >/dev/null 2>&1
   2330 	fi
   2331 	v='print STDOUT "abc\n";'
   2332 	echo "$v" > $tf
   2333 	chmod 700 $tf
   2334 
   2335 	lc=`wc -l $tf | awk '{print $1}'`
   2336 	if [ "X$lc" = "X1" ]; then
   2337 		echo "$cod" > $tf
   2338 	else
   2339 		printf "%s" "$cod" > $tf
   2340 		echo "" >> $tf
   2341 	fi
   2342 	# prime perl
   2343 	perl -e 'use IO::Socket::INET; select(undef, undef, undef, 0.01)' >/dev/null 2>&1
   2344 }
   2345 
   2346 # make_tcert is no longer invoked via the ssvnc gui (Listen mode).
   2347 # make_tcert is for testing only now via -mycert BUILTIN
   2348 make_tcert() {
   2349 	tcert="/tmp/ss_vnc_viewer_tcert${RANDOM}.$$"
   2350 	tcert=`mytmp "$tcert"`
   2351 	cat > $tcert <<END
   2352 -----BEGIN RSA PRIVATE KEY-----
   2353 MIIEowIBAAKCAQEAvkfXxb0wcxgrjV2ziFikjII+ze8iKcTBt47L0GM/c21efelN
   2354 +zZpJUUXLu4zz8Ryq8Q+sQgfNy7uTOpN9bUUaOk1TnD7gaDQnQWiNHmqbW2kL+DS
   2355 OKngJVPo9dETAS8hf7+D1e1DBZxjTc1a4RQqWJixwpYj99ixWzu8VC2m/xXsjvOs
   2356 jp4+DLBB490nbkwvstmhmiWm1CmI5O5xOkgioVNQqHvQMdVKOSz9PpbjvZiRX1Uo
   2357 qoMrk+2NOqwP90TB35yPASXb9zXKpO7DLhkube+yYGf+yk46aD707L07Eb7cosFP
   2358 S84vNZ9gX7rQ0UOwm5rYA/oZTBskgaqhtIzkLwIDAQABAoIBAD4ot/sXt5kRn0Ca
   2359 CIkU9AQWlC+v28grR2EQW9JiaZrqcoDNUzUqbCTJsi4ZkIFh2lf0TsqELbZYNW6Y
   2360 6AjJM7al4E0UqYSKJTv2WCuuRxdiRs2BMwthqyBmjeanev7bB6V0ybt7u3Y8xU/o
   2361 MrTuYnr4vrEjXPKdLirwk7AoDbKsRXHSIiHEIBOq1+dUQ32t36ukdnnza4wKDLZc
   2362 PKHiCdCk/wOGhuDlxD6RspqUAlRnJ8/aEhrgWxadFXw1hRhRsf/v1shtB0T3DmTe
   2363 Jchjwyiw9mryb9JZAcKxW+fUc4EVvj6VdQGqYInQJY5Yxm5JAlVQUJicuuJEvn6A
   2364 rj5osQECgYEA552CaHpUiFlB4HGkjaH00kL+f0+gRF4PANCPk6X3UPDVYzKnzmuu
   2365 yDvIdEETGFWBwoztUrOOKqVvPEQ+kBa2+DWWYaERZLtg2cI5byfDJxQ3ldzilS3J
   2366 1S3WgCojqcsG/hlxoQJ1dZFanUy/QhUZ0B+wlC+Zp1Q8AyuGQvhHp68CgYEA0lBI
   2367 eqq2GGCdJuNHMPFbi8Q0BnX55LW5C1hWjhuYiEkb3hOaIJuJrqvayBlhcQa2cGqp
   2368 uP34e9UCfoeLgmoCQ0b4KpL2NGov/mL4i8bMgog4hcoYuIi3qxN18vVR14VKEh4U
   2369 RLk0igAYPU+IK2QByaQlBo9OSaKkcfm7U1/pK4ECgYAxr6VpGk0GDvfF2Tsusv6d
   2370 GIgV8ZP09qSLTTJvvxvF/lQYeqZq7sjI5aJD5i3de4JhpO/IXQJzfZfWOuGc8XKA
   2371 3qYK/Y2IqXXGYRcHFGWV/Y1LFd55mCADHlk0l1WdOBOg8P5iRu/Br9PbiLpCx9oI
   2372 vrOXpnp03eod1/luZmqguwKBgQCWFRSj9Q7ddpSvG6HCG3ro0qsNsUMTI1tZ7UBX
   2373 SPogx4tLf1GN03D9ZUZLZVFUByZKMtPLX/Hi7K9K/A9ikaPrvsl6GEX6QYzeTGJx
   2374 3Pw0amFrmDzr8ySewNR6/PXahxPEuhJcuI31rPufRRI3ZLah3rFNbRbBFX+klkJH
   2375 zTnoAQKBgDbUK/aQFGduSy7WUT7LlM3UlGxJ2sA90TQh4JRQwzur0ACN5GdYZkqM
   2376 YBts4sBJVwwJoxD9OpbvKu3uKCt41BSj0/KyoBzjT44S2io2tj1syujtlVUsyyBy
   2377 /ca0A7WBB8lD1D7QMIhYUm2O9kYtSCLlUTHt5leqGaRG38DqlX36
   2378 -----END RSA PRIVATE KEY-----
   2379 -----BEGIN CERTIFICATE-----
   2380 MIIDzDCCArQCCQDSzxzxqhyqLzANBgkqhkiG9w0BAQQFADCBpzELMAkGA1UEBhMC
   2381 VVMxFjAUBgNVBAgTDU1hc3NhY2h1c2V0dHMxDzANBgNVBAcTBkJvc3RvbjETMBEG
   2382 A1UEChMKTXkgQ29tcGFueTEcMBoGA1UECxMTUHJvZHVjdCBEZXZlbG9wbWVudDEZ
   2383 MBcGA1UEAxMQd3d3Lm5vd2hlcmUubm9uZTEhMB8GCSqGSIb3DQEJARYSYWRtaW5A
   2384 bm93aGVyZS5ub25lMB4XDTA3MDMyMzE4MDc0NVoXDTI2MDUyMjE4MDc0NVowgacx
   2385 CzAJBgNVBAYTAlVTMRYwFAYDVQQIEw1NYXNzYWNodXNldHRzMQ8wDQYDVQQHEwZC
   2386 b3N0b24xEzARBgNVBAoTCk15IENvbXBhbnkxHDAaBgNVBAsTE1Byb2R1Y3QgRGV2
   2387 ZWxvcG1lbnQxGTAXBgNVBAMTEHd3dy5ub3doZXJlLm5vbmUxITAfBgkqhkiG9w0B
   2388 CQEWEmFkbWluQG5vd2hlcmUubm9uZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
   2389 AQoCggEBAL5H18W9MHMYK41ds4hYpIyCPs3vIinEwbeOy9BjP3NtXn3pTfs2aSVF
   2390 Fy7uM8/EcqvEPrEIHzcu7kzqTfW1FGjpNU5w+4Gg0J0FojR5qm1tpC/g0jip4CVT
   2391 6PXREwEvIX+/g9XtQwWcY03NWuEUKliYscKWI/fYsVs7vFQtpv8V7I7zrI6ePgyw
   2392 QePdJ25ML7LZoZolptQpiOTucTpIIqFTUKh70DHVSjks/T6W472YkV9VKKqDK5Pt
   2393 jTqsD/dEwd+cjwEl2/c1yqTuwy4ZLm3vsmBn/spOOmg+9Oy9OxG+3KLBT0vOLzWf
   2394 YF+60NFDsJua2AP6GUwbJIGqobSM5C8CAwEAATANBgkqhkiG9w0BAQQFAAOCAQEA
   2395 vGomHEp6TVU83X2EBUgnbOhzKJ9u3fOI/Uf5L7p//Vxqow7OR1cguzh/YEzmXOIL
   2396 ilMVnzX9nj/bvcLAuqEP7MR1A8f4+E807p/L/Sf49BiCcwQq5I966sGKYXjkve+T
   2397 2GTBNwMSq+5kLSf6QY8VZI+qnrAudEQMeJByQhTZZ0dH8Njeq8EGl9KUio+VWaiW
   2398 CQK6xJuAvAHqa06OjLmwu1fYD4GLGSrOIiRVkSXV8qLIUmzxdJaIRznkFWsrCEKR
   2399 wAH966SAOvd2s6yOHMvyDRIL7WHxfESB6rDHsdIW/yny1fBePjv473KrxyXtbz7I
   2400 dMw1yW09l+eEo4A7GzwOdw==
   2401 -----END CERTIFICATE-----
   2402 END
   2403 	chmod 600 $tcert
   2404 	echo "$tcert"
   2405 }
   2406 
   2407 Kecho() {
   2408 	NO_KECHO=1
   2409 	if [ "X$USER" = "Xrunge" -a "X$NO_KECHO" = "X" ]; then
   2410 		echo "dbg: $*"
   2411 	fi
   2412 }
   2413 
   2414 NHAFL_warning() {
   2415 	echo "" 
   2416 	echo "** Warning: For the proxy: $proxy" 
   2417 	echo "** Warning: the ssh(1) option: $ssh_NHAFL" 
   2418 	echo "** Warning: will be used to avoid frequent 'ssh key has changed for localhost'"
   2419 	echo "** Warning: dialogs and connection failures (for example, ssh will exit asking"
   2420 	echo "** Warning: you to manually remove a key from ~/.ssh/known_hosts.)"
   2421 	echo "** Warning: "
   2422 	echo "** Warning: This decreases security: a Man-In-The-Middle attack is possible."
   2423 	echo "** Warning: For chained ssh connections the first ssh leg is secure but the"
   2424 	echo "** Warning: 2nd ssh leg is vulnerable.  For an ssh connection going through"
   2425 	echo "** Warning: a HTTP or SOCKS proxy the ssh connection is vulnerable."
   2426 	echo "** Warning: "
   2427 	echo "** Warning: You can set the SSVNC_SSH_LOCALHOST_AUTH=1 env. var. to disable" 
   2428 	echo "** Warning: using the NoHostAuthenticationForLocalhost=yes ssh option." 
   2429 	echo "** Warning: "
   2430 	echo "** Warning: A better solution is to configure (in the SSVNC GUI) the setting:"
   2431 	echo "** Warning: 'Options -> Advanced -> Private SSH KnownHosts file' (or set" 
   2432 	echo "** Warning: SSVNC_KNOWN_HOSTS_FILE directly) to a per-connection known hosts" 
   2433 	echo "** Warning: file.  That file holds the 'localhost' cert for this specific" 
   2434 	echo "** Warning: connection.  This yields a both secure and convenient solution." 
   2435 	echo "" 
   2436 }
   2437 
   2438 space_expand() {
   2439 	str=`echo "$1" | sed -e 's/%SPACE/ /g' -e 's/%TAB/\t/g'`
   2440 	echo "$str"
   2441 }
   2442 
   2443 # handle ssh case:
   2444 #
   2445 if [ "X$use_ssh" = "X1" ]; then
   2446 	#
   2447 	# USING SSH
   2448 	#
   2449 	ssh_port="22"
   2450 	ssh_host="$host"
   2451 	vnc_host="$localhost"
   2452 	ssh_UKHF=""
   2453 	localhost_extra=""
   2454 	# let user override ssh via $SSH
   2455 	ssh=${SSH:-"ssh -x"}
   2456 
   2457 	sshword=`echo "$ssh" | awk '{print $1}'`
   2458 	if [ "X$sshword" != "X" ]; then
   2459 		if [ -x "$sshword" ]; then
   2460 			:
   2461 		elif type "$sshword" > /dev/null 2>&1; then
   2462 			:
   2463 		else
   2464 			echo ""
   2465 			echo "*********************************************************"
   2466 			echo "** Problem finding the SSH command '$sshword': **"
   2467 			echo ""
   2468 			type "$sshword"
   2469 			echo ""
   2470 			echo "** Perhaps you need to install the SSH client package. **"
   2471 			echo "*********************************************************"
   2472 			echo ""
   2473 			sleep 5
   2474 		fi
   2475 	fi
   2476 
   2477 	ssh_NHAFL="-o NoHostAuthenticationForLocalhost=yes"
   2478 	if [ "X$SSVNC_SSH_LOCALHOST_AUTH" = "X1" ]; then
   2479 		ssh_NHAFL=""
   2480 	fi
   2481 	if [ "X$SSVNC_KNOWN_HOSTS_FILE" != "X" ]; then
   2482 		ssh_NHAFL=""
   2483 	
   2484 		ssh_UKHF="-o UserKnownHostsFile=$SSVNC_KNOWN_HOSTS_FILE"
   2485 		ssh_args="$ssh_args $ssh_UKHF"
   2486 		if [ ! -f "$SSVNC_KNOWN_HOSTS_FILE" ]; then
   2487 			touch "$SSVNC_KNOWN_HOSTS_FILE" >/dev/null 2>&1
   2488 		fi
   2489 		chmod 600 "$SSVNC_KNOWN_HOSTS_FILE" >/dev/null 2>&1
   2490 	fi
   2491 	did_ssh_NHAFL=""
   2492 
   2493 	if [ "X$SSVNC_LIM_ACCEPT_PRELOAD" != "X" ]; then
   2494 		SSVNC_LIM_ACCEPT_PRELOAD="$SSVNC_BASEDIR/$SSVNC_UNAME/$SSVNC_LIM_ACCEPT_PRELOAD"
   2495 	fi
   2496 	if [ "X$SSVNC_LIM_ACCEPT_PRELOAD" != "X" ]; then
   2497 		echo ""
   2498 		echo "SSVNC_LIM_ACCEPT_PRELOAD=$SSVNC_LIM_ACCEPT_PRELOAD"
   2499 	fi
   2500 
   2501 	if [ "X$SSVNC_LIM_ACCEPT_PRELOAD" != "X" -a -f "$SSVNC_LIM_ACCEPT_PRELOAD" ]; then
   2502 		plvar=LD_PRELOAD
   2503 		if uname | grep Darwin >/dev/null; then
   2504 			plvar="DYLD_FORCE_FLAT_NAMESPACE=1 DYLD_INSERT_LIBRARIES"
   2505 		fi
   2506 		ssh="env $plvar=$SSVNC_LIM_ACCEPT_PRELOAD $ssh"
   2507 	else
   2508 		SSVNC_LIM_ACCEPT_PRELOAD=""
   2509 	fi
   2510 
   2511 	ssh_vencrypt_proxy=""
   2512 	# We handle vencrypt for SSH+SSL mode.
   2513 	if echo "$proxy" | grep 'vencrypt://' > /dev/null; then
   2514 		proxynew=""
   2515 		for part in `echo "$proxy" | tr ',' ' '`
   2516 		do
   2517 			if echo "$part" | egrep -i '^vencrypt://' > /dev/null; then
   2518 				ssh_vencrypt_proxy=$part
   2519 			else
   2520 				if [ "X$proxynew" = "X" ]; then
   2521 					proxynew="$part"
   2522 				else
   2523 					proxynew="$proxynew,$part"
   2524 				fi
   2525 			fi
   2526 		done
   2527 		proxy=$proxynew
   2528 	fi 
   2529 	Kecho ssh_vencrypt_proxy=$ssh_vencrypt_proxy
   2530 
   2531 	# note that user must supply http:// for web proxy in SSH and SSH+SSL.
   2532 	# No xxxx:// implies ssh server+port.
   2533 	#
   2534 	if echo "$proxy" | egrep '(http|https|socks|socks4|socks5)://' > /dev/null; then
   2535 		# Handle Web or SOCKS proxy(ies) for the initial connect.
   2536 		Kecho host=$host
   2537 		Kecho port=$port
   2538 		pproxy=""
   2539 		sproxy1=""
   2540 		sproxy_rest=""
   2541 		for part in `echo "$proxy" | tr ',' ' '`
   2542 		do
   2543 			Kecho proxy_part=$part
   2544 			if [ "X$part" = "X" ]; then
   2545 				continue
   2546 			elif echo "$part" | egrep -i '^(http|https|socks|socks4|socks5)://' > /dev/null; then
   2547 				pproxy="$pproxy,$part"
   2548 			else
   2549 				if [ "X$sproxy1" = "X" ]; then
   2550 					sproxy1="$part"
   2551 				else
   2552 					sproxy_rest="$sproxy_rest,$part"
   2553 				fi
   2554 			fi
   2555 		done
   2556 		pproxy=`echo "$pproxy" | sed -e 's/^,,*//' -e 's/,,*/,/g'`
   2557 		sproxy_rest=`echo "$sproxy_rest" | sed -e 's/^,,*//' -e 's/,,*/,/g'`
   2558 
   2559 		Kecho pproxy=$pproxy
   2560 		Kecho sproxy1=$sproxy1
   2561 		Kecho sproxy_rest=$sproxy_rest
   2562 
   2563 		sproxy1_host=""
   2564 		sproxy1_port=""
   2565 		sproxy1_user=""
   2566 
   2567 		if [ "X$sproxy1" != "X" ]; then
   2568 			sproxy1_host=`echo "$sproxy1" | awk -F: '{print $1}'`
   2569 			sproxy1_user=`echo "$sproxy1_host" | awk -F@ '{print $1}'`
   2570 			sproxy1_host=`echo "$sproxy1_host" | awk -F@ '{print $2}'`
   2571 			if [ "X$sproxy1_host" = "X" ]; then
   2572 				sproxy1_host=$sproxy1_user
   2573 				sproxy1_user=""
   2574 			else
   2575 				sproxy1_user="${sproxy1_user}@"
   2576 			fi
   2577 			sproxy1_port=`echo "$sproxy1" | awk -F: '{print $2}'`
   2578 			if [ "X$sproxy1_port" = "X" ]; then
   2579 				sproxy1_port="22"
   2580 			fi
   2581 		else
   2582 			sproxy1_host=`echo "$host" | awk -F: '{print $1}'`
   2583 			sproxy1_user=`echo "$sproxy1_host" | awk -F@ '{print $1}'`
   2584 			sproxy1_host=`echo "$sproxy1_host" | awk -F@ '{print $2}'`
   2585 			if [ "X$sproxy1_host" = "X" ]; then
   2586 				sproxy1_host=$sproxy1_user
   2587 				sproxy1_user=""
   2588 			else
   2589 				sproxy1_user="${sproxy1_user}@"
   2590 			fi
   2591 			sproxy1_port=`echo "$host" | awk -F: '{print $2}'`
   2592 			if [ "X$sproxy1_port" = "X" ]; then
   2593 				sproxy1_port="22"
   2594 			fi
   2595 		fi
   2596 
   2597 		Kecho sproxy1_host=$sproxy1_host
   2598 		Kecho sproxy1_port=$sproxy1_port
   2599 		Kecho sproxy1_user=$sproxy1_user
   2600 
   2601 		ptmp="/tmp/ss_vncviewer_ssh${RANDOM}.$$.pl"
   2602 		ptmp=`mytmp "$ptmp"`
   2603 		PPROXY_REMOVE=1; export PPROXY_REMOVE
   2604 		proxy=$pproxy
   2605 		port_save=$port
   2606 		host_save=$host
   2607 		if [ "X$sproxy1_host" != "X" ]; then
   2608 			host=$sproxy1_host
   2609 		fi
   2610 		if [ "X$sproxy1_port" != "X" ]; then
   2611 			port=$sproxy1_port
   2612 		fi
   2613 		host=`echo "$host" | sed -e 's/^.*@//'`
   2614 		port=`echo "$port" | sed -e 's/^.*://'`
   2615 		pcode "$ptmp"
   2616 		port=$port_save
   2617 		host=$host_save
   2618 
   2619 		nd=`findfree 6600`
   2620 		PPROXY_LISTEN=$nd; export PPROXY_LISTEN
   2621 		# XXX no reverse forever PPROXY_LOOP_THYSELF ...
   2622 		$ptmp &
   2623 		sleep 1
   2624 		if [ "X$ssh_NHAFL" != "X" -a "X$did_ssh_NHAFL" != "X1" ]; then
   2625 			NHAFL_warning
   2626 			ssh_args="$ssh_args $ssh_NHAFL"
   2627 			did_ssh_NHAFL=1
   2628 		fi
   2629 		sleep 1
   2630 		if [ "X$sproxy1" = "X" ]; then
   2631 			u=""
   2632 			if echo "$host" | grep '@' > /dev/null; then
   2633 				u=`echo "$host" | sed -e 's/@.*$/@/'`
   2634 			fi
   2635 			
   2636 			proxy="${u}$localhost:$nd"
   2637 		else
   2638 			proxy="${sproxy1_user}$localhost:$nd"
   2639 		fi
   2640 		localhost_extra=".2"
   2641 		if [ "X$sproxy_rest" != "X" ]; then
   2642 			proxy="$proxy,$sproxy_rest"
   2643 		fi
   2644 		Kecho proxy=$proxy
   2645 	fi
   2646 
   2647 	if echo "$proxy" | grep "," > /dev/null; then
   2648 
   2649 		proxy1=`echo "$proxy" | awk -F, '{print $1}'`
   2650 		proxy2=`echo "$proxy" | awk -F, '{print $2}'`
   2651 
   2652 		# user1 (at] gw1.com:port1,user2@ws2:port2
   2653 		ssh_host1=`echo "$proxy1" | awk -F: '{print $1}'`
   2654 		ssh_port1=`echo "$proxy1" | awk -F: '{print $2}'`
   2655 		if [ "X$ssh_port1" != "X" ]; then
   2656 			ssh_port1="-p $ssh_port1"
   2657 		fi
   2658 		ssh_host2=`echo "$proxy2" | awk -F: '{print $1}'`
   2659 		ssh_user2=`echo "$ssh_host2" | awk -F@ '{print $1}'`
   2660 		ssh_host2=`echo "$ssh_host2" | awk -F@ '{print $2}'`
   2661 		if [ "X$ssh_host2" = "X" ]; then
   2662 			ssh_host2=$ssh_user2
   2663 			ssh_user2=""
   2664 		else
   2665 			ssh_user2="${ssh_user2}@"
   2666 		fi
   2667 		ssh_port2=`echo "$proxy2" | awk -F: '{print $2}'`
   2668 		if [ "X$ssh_port2" = "X" ]; then
   2669 			ssh_port2="22"
   2670 		fi
   2671 		proxport=`findfree 3500`
   2672 		if [ "X$ssh_NHAFL" != "X" -a "X$did_ssh_NHAFL" != "X1" ]; then
   2673 			NHAFL_warning
   2674 			did_ssh_NHAFL=1
   2675 			sleep 1
   2676 		fi
   2677 		echo
   2678 		echo "Running 1st ssh proxy:"
   2679 		ukhf=""
   2680 		if [ "X$ssh_UKHF" != "X" ]; then 
   2681 			ukhf="$ssh_UKHF$localhost_extra"
   2682 		fi
   2683 		if echo "$ssh_host1" | grep '%' > /dev/null; then
   2684 			uath=`space_expand "$ssh_host1"`
   2685 		else
   2686 			uath="$ssh_host1"
   2687 		fi
   2688 		echo "$ssh -f -x $ssh_port1 $targ -e none $ssh_NHAFL $ukhf -L $proxport:$ssh_host2:$ssh_port2 \"$uath\" \"sleep 30\""
   2689 		echo ""
   2690 		      $ssh -f -x $ssh_port1 $targ -e none $ssh_NHAFL $ukhf -L $proxport:$ssh_host2:$ssh_port2 "$uath" "sleep 30"
   2691 		ssh_args="$ssh_args $ssh_NHAFL"
   2692 		sleep 1
   2693 		stty sane
   2694 		proxy="${ssh_user2}$localhost:$proxport"
   2695 	fi
   2696 
   2697 	if [ "X$proxy" != "X" ]; then
   2698 		ssh_port=`echo "$proxy" | awk -F: '{print $2}'`
   2699 		if [ "X$ssh_port" = "X" ]; then
   2700 			ssh_port="22"
   2701 		fi
   2702 		ssh_host=`echo "$proxy" | awk -F: '{print $1}'`
   2703 		vnc_host="$host"
   2704 	fi
   2705 
   2706 	echo ""
   2707 	echo "Running ssh:"
   2708 	sz=`echo "$ssh_cmd" | wc -c`
   2709 	if [ "$sz" -gt 300 ]; then
   2710 		info="..."
   2711 	else
   2712 		info="$ssh_cmd"
   2713 	fi
   2714 
   2715 	C=""
   2716 	if [ "X$SS_VNCVIEWER_USE_C" != "X" ]; then
   2717 		C="-C"
   2718 	fi
   2719 
   2720 	getport=""
   2721 	teeport=""
   2722 	if echo "$ssh_cmd" | egrep "(PORT=|P=) " > /dev/null; then
   2723 		getport=1
   2724 		if echo "$ssh_cmd" | egrep "P= " > /dev/null; then
   2725 			teeport=1
   2726 		fi
   2727 
   2728 		PORT=""
   2729 		ssh_cmd=`echo "$ssh_cmd" | sed -e 's/PORT=[ 	]*//' -e 's/P=//'`
   2730 		SSVNC_NO_ENC_WARN=1
   2731 		if [ "X$use_sshssl" = "X" ]; then
   2732 			direct_connect=1
   2733 		fi
   2734 	fi
   2735 	if [ "X$getport" != "X" ]; then
   2736 		ssh_redir="-D ${use}"
   2737 	elif [ "X$reverse" = "X" ]; then
   2738 		ssh_redir="-L ${use}:${vnc_host}:${port}"
   2739 	else
   2740 		ssh_redir="-R ${port}:${vnc_host}:${use}"
   2741 	fi
   2742 	pmark=`sh -c 'echo $$'`
   2743 
   2744 	# the -t option actually speeds up typing response via VNC!!
   2745 	if [ "X$ssh_port" = "X22" ]; then
   2746 		ssh_port=""
   2747 	else
   2748 		ssh_port="-p $ssh_port"
   2749 	fi
   2750 
   2751 	if echo "$ssh_host" | grep '%' > /dev/null; then
   2752 		uath=`space_expand "$ssh_host"`
   2753 	else
   2754 		uath="$ssh_host"
   2755 	fi
   2756 	if [ "X$SS_VNCVIEWER_SSH_ONLY" != "X" ]; then
   2757 		echo "$ssh -x $ssh_port $targ $C $ssh_args \"$uath\" \"$info\""
   2758 		echo ""
   2759 		$ssh -x $ssh_port $targ $C $ssh_args "$uath" "$ssh_cmd"
   2760 		exit $?
   2761 
   2762 	elif [ "X$SS_VNCVIEWER_NO_F" != "X" ]; then
   2763 		echo "$ssh -x $ssh_port $targ $C $ssh_redir $ssh_args \"$uath\" \"$info\""
   2764 		echo ""
   2765 		$ssh -x $ssh_port $targ $C $ssh_redir $ssh_args "$uath" "$ssh_cmd"
   2766 		rc=$?
   2767 
   2768 	elif [ "X$getport" != "X" ]; then
   2769 		tport=/tmp/ss_vncviewer_tport${RANDOM}.$$
   2770 		tport=`mytmp "$tport"`
   2771 		tport2=/tmp/ss_vncviewer_tport2${RANDOM}.$$
   2772 		tport2=`mytmp "$tport2"`
   2773 
   2774 		if [ "X$rsh" != "X1" ]; then
   2775 			if echo "$ssh_cmd" | grep "sudo " > /dev/null; then
   2776 				echo ""
   2777 				echo "Initial ssh with 'sudo id' to prime sudo so hopefully the next one"
   2778 				echo "will require no password..."
   2779 				echo ""
   2780 				targ="-t"
   2781 				$ssh -x $ssh_port $targ $ssh_args "$uath" "sudo id; tty"
   2782 				echo ""
   2783 			fi
   2784 			echo "$ssh -x -f $ssh_port $targ $C $ssh_redir $ssh_args \"$uath\" \"$info\""
   2785 			echo ""
   2786 			$ssh -x -f $ssh_port $targ $C $ssh_redir $ssh_args "$uath" "$ssh_cmd" > $tport 2> $tport2
   2787 			if [ "X$teeport" = "X1" ]; then
   2788 				tail -f $tport  1>&2 &
   2789 				tail_pid=$!
   2790 				tail -f $tport2 1>&2 &
   2791 				tail_pid2=$!
   2792 			fi
   2793 			rc=$?
   2794 		else
   2795 			rsh_setup
   2796 			echo "rsh $ul \"$ssh_host\" \"$ssh_cmd\""
   2797 			echo ""
   2798 			rsh $ul "$ssh_host" "$ssh_cmd" > $tport &
   2799 			sleep 1
   2800 			rc=0
   2801 		fi
   2802 
   2803 		if [ "X$SSVNC_EXTRA_SLEEP" != "X" ]; then
   2804 			echo "sleep $SSVNC_EXTRA_SLEEP"
   2805 			sleep $SSVNC_EXTRA_SLEEP
   2806 		fi
   2807 
   2808 		stty sane
   2809 		i=0
   2810 		if type perl > /dev/null 2>&1; then
   2811 			imax=50
   2812 			sleepit="perl -e 'select(undef, undef, undef, 0.20)'"
   2813 		else
   2814 			imax=10
   2815 			sleepit="sleep 1"
   2816 		fi
   2817 		while [ $i -lt $imax ]; do
   2818 			#echo $sleepit
   2819 			eval $sleepit
   2820 			PORT=`grep "^PORT=" $tport | tr '\r' ' ' | head -n 1 | sed -e 's/PORT=//' -e 's/\r//g' -e 's/ *$//'`
   2821 			if echo "$PORT" | grep '^[0-9][0-9]*$' > /dev/null; then
   2822 				break
   2823 			fi
   2824 			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}'`
   2825 			if [ "X$vnss" != "X" ]; then
   2826 				PORT=`echo "$vnss" | awk -F: '{print $2}'`
   2827 				if echo "$PORT" | grep '^[0-9][0-9]*$' > /dev/null; then
   2828 					if [ $PORT -lt 100 ]; then
   2829 						PORT=`expr $PORT + 5900`
   2830 					fi
   2831 				fi
   2832 				if echo "$PORT" | grep '^[0-9][0-9]*$' > /dev/null; then
   2833 					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`
   2834 					echo "vncserver string: $vnss" 1>&2
   2835 					break
   2836 				fi
   2837 			fi
   2838 			i=`expr $i + 1`
   2839 		done
   2840 
   2841 		echo "found: PORT='$PORT'" 1>&2
   2842 		lh6=""
   2843 		if [ "X$SSVNC_PORT_IPV6" != "X" ]; then
   2844 			lh6=1
   2845 		elif egrep 'Info: listening on IPv6 only|Info: listening only on IPv6' $tport > /dev/null; then
   2846 			lh6=1
   2847 		fi
   2848 		if [ "X$lh6" = "X1" ]; then
   2849 			echo "set SOCKS5 localhost to ::1" 1>&2
   2850 		fi
   2851 		rm -f $tport $tport2
   2852 		if [ "X$rsh" = "X1" ]; then
   2853 			rsh_viewer "$@"
   2854 			exit $?
   2855 		fi
   2856 		PPROXY_SOCKS=5
   2857 		if [ "X$SSVNC_SOCKS5" != "X" ]; then
   2858 			PPROXY_SOCKS=5
   2859 		elif [ "X$SSVNC_SOCKS4" != "X" ]; then
   2860 			PPROXY_SOCKS=1
   2861 		fi
   2862 		export PPROXY_SOCKS
   2863 		if [ "X$lh6" = "X" ]; then
   2864 			host="$localhost"
   2865 		else
   2866 			host="::1"
   2867 		fi
   2868 		port="$PORT"
   2869 		proxy="$localhost:$use"
   2870 
   2871 	else
   2872 		if [ "X$rsh" != "X1" ]; then
   2873 			echo "$ssh -x -f $ssh_port $targ $C $ssh_redir $ssh_args \"$uath\" \"$info\""
   2874 			echo ""
   2875 			$ssh -x -f $ssh_port $targ $C $ssh_redir $ssh_args "$uath" "$ssh_cmd"
   2876 			rc=$?
   2877 		else
   2878 			rsh_setup
   2879 			echo "rsh $ul \"$ssh_host\" \"$ssh_cmd\""
   2880 			echo ""
   2881 			rsh $ul "$ssh_host" "$ssh_cmd" &
   2882 			sleep 1
   2883 			PORT=$port
   2884 			rsh_viewer "$@"
   2885 			exit $?
   2886 		fi
   2887 	fi
   2888 
   2889 	if [ "$rc" != "0" ]; then
   2890 		echo ""
   2891 		echo "ssh to \"$uath\" failed."
   2892 		exit 1
   2893 	fi
   2894 	stty sane
   2895 
   2896 	c=0
   2897 	pssh=""
   2898 	while [ $c -lt 40 ]
   2899 	do
   2900 		p=`expr $pmark + $c`
   2901 		pout=`ps -p "$p" 2>/dev/null | grep -v '^[ 	]*PID' | sed -e 's/-L.*$//' -e 's/-x .*$//'`
   2902 		if echo "$pout" | grep "ssh" > /dev/null; then
   2903 			if echo "$pout" | egrep -i 'ssh.*(-add|-agent|-ask|-keygen|-argv0|vnc)' >/dev/null; then
   2904 				:
   2905 			elif echo "$pout" | egrep -i 'scp|sshd' >/dev/null; then
   2906 				:
   2907 			else
   2908 				pssh=$p
   2909 				break
   2910 			fi
   2911 		fi
   2912 		c=`expr $c + 1`
   2913 	done
   2914 	if [ "X$getport" != "X" ]; then
   2915 		:
   2916 	elif [ "X$SSVNC_LIM_ACCEPT_PRELOAD" != "X" ] ; then
   2917 		sleep 2
   2918 	elif [ "X$ssh_cmd" = "Xsleep $ssh_sleep" ] ; then
   2919 		#echo T sleep 1
   2920 		sleep 1
   2921 	elif echo "$ssh_cmd" | grep '^sleep ' >/dev/null; then
   2922 		#echo T sleep 2
   2923 		sleep 2
   2924 	else
   2925 		# let any command get started a bit.
   2926 		#echo T sleep 5
   2927 		sleep 5
   2928 	fi
   2929 	echo ""
   2930 	#reset
   2931 	stty sane
   2932 	if [ "X$SSVNC_EXTRA_SLEEP" != "X" ]; then
   2933 		echo "sleep $SSVNC_EXTRA_SLEEP"
   2934 		sleep $SSVNC_EXTRA_SLEEP
   2935 	fi
   2936 	echo "ssh_pid='$pssh'"; echo
   2937 	if [ "X$use_sshssl" = "X" -a "X$getport" = "X" ]; then
   2938 		echo "Running viewer:"
   2939 
   2940 		trap "final" 0 2 15
   2941 		if [ "X$reverse" = "X" ]; then
   2942 			echo "$VNCVIEWERCMD" "$@" $localhost:$N
   2943 			echo ""
   2944 			$VNCVIEWERCMD "$@" $localhost:$N
   2945 			if [ $? != 0 ]; then
   2946 				echo "vncviewer command failed: $?"
   2947 				if [ "X$secondtry" = "X1" ]; then
   2948 					sleep 2
   2949 					$VNCVIEWERCMD "$@" $localhost:$N
   2950 				fi
   2951 			fi
   2952 		else
   2953 			echo ""
   2954 			echo "NOTE: Press Ctrl-C to terminate viewer LISTEN mode."
   2955 			echo ""
   2956 			N2=$N
   2957 			if [ "X$VNCVIEWER_IS_REALVNC4" = "X1" ]; then
   2958 				N2=`echo "$N2" | sed -e 's/://g'`
   2959 				if [ $N2 -le 200 ]; then
   2960 					N2=`expr $N2 + 5500`
   2961 				fi
   2962 			fi
   2963 			echo "$VNCVIEWERCMD" "$@" -listen $N2
   2964 			echo ""
   2965 			$VNCVIEWERCMD "$@" -listen $N2
   2966 		fi
   2967 
   2968 		exit $?
   2969 	else
   2970 		use2=`findfree 5960`
   2971 		host0=$host
   2972 		port0=$port
   2973 		host=$localhost
   2974 		port=$use
   2975 		use=$use2
   2976 		N=`expr $use - 5900`
   2977 		if [ "X$getport" != "X" ]; then
   2978 			host="$host0"
   2979 			port="$port0"
   2980 		else
   2981 			proxy=""
   2982 		fi
   2983 		if [ "X$ssh_vencrypt_proxy" != "X" ]; then
   2984 			ssh_vencrypt_proxy="vencrypt://$host:$port"
   2985 			if [ "X$proxy" = "X" ]; then
   2986 				proxy=$ssh_vencrypt_proxy
   2987 			else
   2988 				proxy="$proxy,$ssh_vencrypt_proxy"
   2989 			fi
   2990 			Kecho "proxy_now=$proxy"
   2991 			unset PPROXY_LISTEN
   2992 		fi
   2993 	fi
   2994 fi
   2995 
   2996 if [ "X$stunnel_set_here" = "X1" -a "X$showcert" = "X" ]; then
   2997 	if type $STUNNEL > /dev/null 2>&1; then
   2998 		:
   2999 	else
   3000 		echo ""
   3001 		echo "***************************************************************"
   3002 		echo "** Problem finding the Stunnel command '$STUNNEL': **"
   3003 		echo ""
   3004 		type $STUNNEL
   3005 		echo ""
   3006 		echo "** Perhaps you need to install the stunnel/stunnel4 package. **"
   3007 		echo "***************************************************************"
   3008 		echo ""
   3009 		sleep 5
   3010 	fi
   3011 fi
   3012 
   3013 # create the stunnel config file:
   3014 if [ "X$verify" != "X" ]; then
   3015 	if [ -d $verify ]; then
   3016 		verify="CApath = $verify"
   3017 	else
   3018 		verify="CAfile = $verify"
   3019 	fi
   3020 	verify="$verify
   3021 verify = 2"
   3022 fi
   3023 if [ "X$SSVNC_STUNNEL_VERIFY3" != "X" ]; then
   3024 	verify=`echo "$verify" | sed -e 's/verify = 2/verify = 3/'`
   3025 fi
   3026 if [ "X$mycert" != "X" ]; then
   3027 	cert="cert = $mycert"
   3028 fi
   3029 if [ "X$crl" != "X" ]; then
   3030 	if [ -d $crl ]; then
   3031 		crl="CRLpath = $crl"
   3032 	else
   3033 		crl="CRLfile = $crl"
   3034 	fi
   3035 fi
   3036 
   3037 if [ "X$showcert" = "X1" ]; then
   3038 	if [ "X$have_uvnc_dsm_helper_showcert" = "X1" ]; then
   3039 		:
   3040 	elif [ "X$SSVNC_NO_IPV6_PROXY" != "X" ]; then
   3041 		:
   3042 	elif [ "X$ipv6" = "X1" -a "X$proxy" = "X" ]; then
   3043 		proxy="ipv6://$host:$port"
   3044 	fi
   3045 fi
   3046 
   3047 if [ "X$direct_connect" != "X" -a "X$STUNNEL_LISTEN" != "X" ]; then
   3048 	proxy=reverse_direct
   3049 fi
   3050 
   3051 ptmp=""
   3052 if [ "X$proxy" != "X" ]; then
   3053 	ptmp="/tmp/ss_vncviewer${RANDOM}.$$.pl"
   3054 	ptmp=`mytmp "$ptmp"`
   3055 	PPROXY_REMOVE=1; export PPROXY_REMOVE
   3056 	pcode "$ptmp"
   3057 	if [ "X$showcert" != "X1" -a "X$direct_connect" = "X" ]; then
   3058 		if uname | egrep 'Darwin|SunOS' >/dev/null; then
   3059 			vout=`echo "$proxy" | grep -i vencrypt`
   3060 			if [ "X$vout" != "X" -a "X$reverse" = "X1" ]; then
   3061 				# need to exec for reverse vencrypt
   3062 				connect="exec = $ptmp"
   3063 			else
   3064 				# on mac and solaris we need to listen on socket instead of stdio:
   3065 				nd=`findfree 6700`
   3066 				PPROXY_LISTEN=$nd
   3067 				export PPROXY_LISTEN
   3068 				if [ "X$reverse" = "X" ]; then
   3069 					$ptmp &
   3070 				fi
   3071 				sleep 2
   3072 				host="$localhost"
   3073 				port="$nd"
   3074 				connect="connect = $localhost:$nd"
   3075 			fi
   3076 		else
   3077 			# otherwise on unix we can exec it:
   3078 			connect="exec = $ptmp"
   3079 		fi
   3080 	else
   3081 		connect="exec = $ptmp"
   3082 	fi
   3083 else
   3084 	connect="connect = $host:$port"
   3085 fi
   3086 
   3087 # handle showcert case:
   3088 #
   3089 if [ "X$showcert" = "X1" ]; then
   3090 	if [ "X$proxy" != "X" ]; then
   3091 		PPROXY_LISTEN=$use
   3092 		export PPROXY_LISTEN
   3093 		if [ "X$SS_DEBUG" != "X" ]; then
   3094 			$ptmp &
   3095 		else
   3096 			$ptmp 2>/dev/null &
   3097 		fi
   3098 		sleep 1
   3099 		more_sleep=1
   3100 		if uname | grep Linux > /dev/null; then
   3101 			if netstat -ant | grep LISTEN | grep "127.0.0.1:$use" > /dev/null; then
   3102 				more_sleep=""
   3103 			fi
   3104 		elif uname | grep SunOS > /dev/null; then
   3105 			if netstat -an -f inet -P tcp | grep LISTEN | grep "127.0.0.1.$use" > /dev/null; then
   3106 				more_sleep=""
   3107 			fi
   3108 		elif uname | egrep -i 'bsd|darwin' > /dev/null; then
   3109 			if netstat -ant -f inet | grep LISTEN | grep "127.0.0.1.$use" > /dev/null; then
   3110 				more_sleep=""
   3111 			fi
   3112 		fi
   3113 		if [ "X$more_sleep" = "X1" ]; then
   3114 			sleep 1
   3115 		fi
   3116 		host="$localhost"
   3117 		port="$use"
   3118 	fi
   3119 	cipher_args=""
   3120 	if [ "X$ciphers" != "X" ]; then
   3121 		cipher_args=`echo "$ciphers" | sed -e 's/ciphers=/-cipher /'`
   3122 	fi
   3123 	if [ "X$have_uvnc_dsm_helper_showcert" = "X1" ]; then
   3124 		:
   3125 	elif type openssl > /dev/null 2>&1; then
   3126 		:
   3127 	else
   3128 		echo ""
   3129 		echo "********************************************************"
   3130 		echo "** Problem finding the OpenSSL command 'openssl': **" 
   3131 		echo ""
   3132 		type openssl 2>&1
   3133 		echo ""
   3134 		echo "** Perhaps you need to install the 'openssl' package. **"
   3135 		echo "********************************************************"
   3136 		echo ""
   3137 	fi
   3138 	#echo "openssl s_client $cipher_args -connect $host:$port" 
   3139 	if [ "X$reverse" = "X" ]; then
   3140 		if type host > /dev/null 2>/dev/null; then
   3141 			host $host >/dev/null 2>&1
   3142 			host $host >/dev/null 2>&1
   3143 		fi
   3144 		timeout=15
   3145 		if [ "X$SSVNC_FETCH_TIMEOUT" != "X" ]; then
   3146 			timeout=$SSVNC_FETCH_TIMEOUT
   3147 		fi
   3148 		if [ "X$have_uvnc_dsm_helper_showcert" = "X1" ]; then
   3149 			if type pkill >/dev/null 2>&1; then
   3150 				(sleep $timeout; if kill -0 $$; then pkill -TERM -f "ultravnc_dsm_helper.*$host.*$port"; fi) >/dev/null 2>&1 &
   3151 			fi
   3152 			ultravnc_dsm_helper showcert $host:$port 2>&1
   3153 		else
   3154 			if type pkill >/dev/null 2>&1; then
   3155 				(sleep $timeout; if kill -0 $$; then pkill -TERM -f "openssl.*s_client.*$host.*$port"; fi) >/dev/null 2>&1 &
   3156 			fi
   3157 			openssl s_client $cipher_args -prexit -connect $host:$port 2>&1 < /dev/null
   3158 		fi
   3159 		rc=$?
   3160 	else
   3161 		tcert=""
   3162 		if [ "X$mycert" = "X" ]; then
   3163 			tcert=`make_tcert`
   3164 			cert_args="-cert $tcert -CAfile $tcert"
   3165 		else
   3166 			cert_args="-cert $mycert -CAfile $mycert"
   3167 		fi
   3168 		tmp_out=/tmp/showcert_out${RANDOM}.$$
   3169 		tmp_out=`mytmp "$tmp_out"`
   3170 		tmp_err=/tmp/showcert_err${RANDOM}.$$
   3171 		tmp_err=`mytmp "$tmp_err"`
   3172 
   3173 		#echo "openssl s_server $cipher_args $cert_args -accept $port -verify 2 > $tmp_out 2> $tmp_err" 1>&2
   3174 
   3175 		# assume we have perl:
   3176 		check_perl perl
   3177 
   3178 		perl -e "
   3179 			\$p = open(O, \"|openssl s_server $cipher_args $cert_args -accept $port -verify 2 1>$tmp_out 2> $tmp_err\");
   3180 			exit 1 unless \$p;
   3181 			while (1) {
   3182 				sleep 1;
   3183 				if (!open(F, \"<$tmp_out\")) {
   3184 					kill \$p;
   3185 					exit 1;
   3186 				}
   3187 				while (<F>) {
   3188 					if (/RFB 00/) {
   3189 						fsleep(0.25);
   3190 						print O \"RFB 000.000\\n\";
   3191 						fsleep(1.00);
   3192 						kill \$p;
   3193 						fsleep(0.25);
   3194 						exit 0;
   3195 					}
   3196 				}
   3197 				close F;
   3198 			}
   3199 			sub fsleep {
   3200 				select(undef, undef, undef, shift);
   3201 			}
   3202 		";
   3203 
   3204 		echo ""
   3205 		cat $tmp_out
   3206 		echo ""
   3207 		echo "----2----"
   3208 		cat $tmp_err
   3209 		if grep BEGIN.CERTIFICATE $tmp_out >/dev/null; then
   3210 			rc=0
   3211 		else
   3212 			rc=1
   3213 		fi
   3214 
   3215 		rm -f $tmp_out $tmp_err
   3216 	fi
   3217 	if [ "X$SSVNC_PREDIGESTED_HANDSHAKE" != "X" ]; then
   3218 		rm -f $SSVNC_PREDIGESTED_HANDSHAKE
   3219 	fi
   3220 	if [ "X$SSVNC_SHOWCERT_EXIT_0" = "X1" ]; then
   3221 		exit 0
   3222 	else
   3223 		exit $rc
   3224 	fi
   3225 fi
   3226 
   3227 # handle direct connect case:
   3228 #
   3229 if [ "X$direct_connect" != "X" ]; then
   3230 	if [ "X$SSVNC_ULTRA_DSM" != "X" ]; then
   3231 		SSVNC_NO_ENC_WARN=1
   3232 		echo ""
   3233 		echo "Using UltraVNC DSM Plugin key for encryption:"
   3234 		echo ""
   3235 		ustr=`echo "$SSVNC_ULTRA_DSM" | sed -e 's/pw=[^ ]*/pw=******/g'`
   3236 		echo "  $ustr PORT HOST:PORT"
   3237 		echo ""
   3238 	elif [ "X$getport" = "X" ]; then
   3239 		echo ""
   3240 		echo "Running viewer for direct connection:"
   3241 		if echo X"$@" | grep chatonly > /dev/null; then
   3242 			:
   3243 		else
   3244 			echo ""
   3245 			echo "** WARNING: THERE WILL BE NO SSL OR SSH ENCRYPTION **"
   3246 			echo ""
   3247 		fi
   3248 	fi
   3249 	x=""
   3250 	if [ "X$SSVNC_NO_ENC_WARN" != "X" ]; then
   3251 		if [ "X$getport" = "X" ]; then
   3252 			sleep 1
   3253 		fi
   3254 	elif type printf > /dev/null 2>&1; then
   3255 		printf  "Are you sure you want to continue? [y]/n "
   3256 		read x
   3257 	else
   3258 		echo -n "Are you sure you want to continue? [y]/n "
   3259 		read x
   3260 	fi
   3261 	if [ "X$x" = "Xn" ]; then
   3262 		exit 1
   3263 	fi
   3264 	echo ""
   3265 	if [ "X$ptmp" != "X" ]; then
   3266 		if [ "X$reverse" = "X" ]; then
   3267 			PPROXY_LISTEN=$use
   3268 			export PPROXY_LISTEN
   3269 		else
   3270 			if [ "X$proxy" = "Xreverse_direct" ]; then
   3271 				PPROXY_LISTEN="$STUNNEL_LISTEN:`expr 5500 + $disp`"
   3272 				PPROXY_DEST="$localhost:$use"
   3273 				PPROXY_PROXY="ipv6://$localhost:$use"	# not always ipv6..
   3274 				export PPROXY_LISTEN PPROXY_DEST PPROXY_PROXY
   3275 				pps=1
   3276 			else
   3277 				PPROXY_REVERSE="$localhost:$use"
   3278 				export PPROXY_LISTEN
   3279 				pps=3
   3280 			fi
   3281 			if [ "X$SSVNC_LISTEN_ONCE" != "X1" ]; then
   3282 				PPROXY_LOOP_THYSELF=`mytmp "/tmp/pproxy_loop_thyself.${RANDOM}.$$"`
   3283 				export PPROXY_LOOP_THYSELF
   3284 				pps=2
   3285 			fi
   3286 			if [ "X$SSVNC_EXTRA_SLEEP" != "X" ]; then
   3287 				pps=`expr $pps + $SSVNC_EXTRA_SLEEP`
   3288 			fi
   3289 			PPROXY_SLEEP=$pps; export PPROXY_SLEEP;
   3290 			PPROXY_KILLPID=+1; export PPROXY_KILLPID;
   3291 		fi
   3292 
   3293 		$ptmp &
   3294 
   3295 		if [ "X$reverse" = "X" ]; then
   3296 			#sleep 2
   3297 			#echo T sleep 1
   3298 			sleep 1
   3299 		fi
   3300 		host="$localhost"
   3301 		disp="$N"
   3302 		port=`expr $disp + 5900`
   3303 	fi
   3304 	if [ "X$SSVNC_EXTRA_SLEEP" != "X" ]; then
   3305 		echo "T sleep $SSVNC_EXTRA_SLEEP"
   3306 		sleep $SSVNC_EXTRA_SLEEP
   3307 	fi
   3308 	if [ "X$reverse" = "X" ]; then
   3309 		hostdisp="$host:$disp"
   3310 		if [ "X$SSVNC_ULTRA_DSM" != "X" ]; then
   3311 			if [ "X$SSVNC_USE_OURS" = "X1" ]; then
   3312 				hostdisp="exec=$SSVNC_ULTRA_DSM 0 $host:$port"
   3313 			else
   3314 				pf=`findfree 5970`
   3315 				cmd="$SSVNC_ULTRA_DSM -$pf $host:$port"
   3316 				pf=`expr $pf - 5900`
   3317 				hostdisp="$localhost:$pf"
   3318 				ustr=`echo "$cmd" | sed -e 's/pw=[^ ]*/pw=******/g'`
   3319 				echo "Running:"
   3320 				echo
   3321 				echo "$ustr &"
   3322 				echo
   3323 				$cmd &
   3324 				dsm_pid=$!
   3325 				sleep 2
   3326 			fi
   3327 		fi
   3328 		hostdisp2=`echo "$hostdisp" | sed -e 's/pw=[^ ]*/pw=******/g'`
   3329 		echo "$VNCVIEWERCMD" "$@" "$hostdisp2"
   3330 		trap "final" 0 2 15
   3331 		echo ""
   3332 		$VNCVIEWERCMD "$@" "$hostdisp"
   3333 		if [ $? != 0 ]; then
   3334 			echo "vncviewer command failed: $?"
   3335 			if [ "X$secondtry" = "X1" ]; then
   3336 				sleep 2
   3337 				$VNCVIEWERCMD "$@" "$hostdisp"
   3338 			fi
   3339 		fi
   3340 	else
   3341 		echo ""
   3342 		echo "NOTE: Press Ctrl-C to terminate viewer LISTEN mode."
   3343 		echo ""
   3344 		trap "final" 0 2 15
   3345 		if [ "X$SSVNC_ULTRA_DSM" != "X" ]; then
   3346 			if [ "X$SSVNC_LISTEN_ONCE" = "X1" ]; then
   3347 				echo "NOTE: The ultravnc_dsm_helper only runs once.  So after the first LISTEN"
   3348 				echo "      ends you must restart the Listening mode.  You may also need to"
   3349 				echo "      Press Ctrl-C to stop the viewer and restart for another connection."
   3350 				echo ""
   3351 			fi
   3352 			#SSVNC_LISTEN_ONCE=1; export SSVNC_LISTEN_ONCE
   3353 			VNCVIEWER_LISTEN_LOCALHOST=1
   3354 			export VNCVIEWER_LISTEN_LOCALHOST
   3355 			dport=`expr 5500 + $disp`
   3356 			cmd="$SSVNC_ULTRA_DSM $dport $localhost:$use"
   3357 			ustr=`echo "$cmd" | sed -e 's/pw=[^ ]*/pw=******/g'`
   3358 			echo "Running:"
   3359 			echo
   3360 			echo "$ustr &"
   3361 			echo
   3362 			if [ "X$SSVNC_LISTEN_ONCE" = "X1" ]; then
   3363 				$cmd &
   3364 				dsm_pid=$!
   3365 			else
   3366 				while [ 1 ]; do $cmd; sleep 1; done &
   3367 				dsm_pid=$!
   3368 			fi
   3369 			sleep 2
   3370 			disp=$use
   3371 			if [ $disp -ge 5500 ]; then
   3372 				disp=`expr $disp - 5500`
   3373 			fi
   3374 		fi
   3375 		disp2=$disp
   3376 		if [ "X$VNCVIEWER_IS_REALVNC4" = "X1" ]; then
   3377 			disp2=`echo "$disp2" | sed -e 's/://g'`
   3378 			if [ $disp2 -le 200 ]; then
   3379 				disp2=`expr $disp2 + 5500`
   3380 			fi
   3381 		fi
   3382 		echo "$VNCVIEWERCMD" "$@" -listen $disp2
   3383 		echo ""
   3384 		$VNCVIEWERCMD "$@" -listen $disp2
   3385 		if [ "X$PPROXY_LOOP_THYSELF" != "X" ]; then
   3386 			rm -f $PPROXY_LOOP_THYSELF
   3387 		fi
   3388 	fi
   3389 	exit $?
   3390 fi
   3391 
   3392 tmp_cfg=/tmp/ss_vncviewer${RANDOM}.$$
   3393 tmp_cfg=`mytmp "$tmp_cfg"`
   3394 
   3395 stunnel_exec=""
   3396 if [ "X$SSVNC_USE_OURS" != "X1" ]; then
   3397 	:
   3398 elif echo $STUNNEL_EXTRA_SVC_OPTS | grep '#stunnel-exec' > /dev/null; then
   3399 	stunnel_exec="#"
   3400 fi
   3401 
   3402 if [ "X$reverse" = "X" ]; then
   3403 
   3404 	if echo "$proxy" | grep "^repeater://" > /dev/null; then
   3405 		if [ "X$cert" = "XBUILTIN" ]; then
   3406 			ttcert=`make_tcert`
   3407 			cert="cert = $ttcert"
   3408 		fi
   3409 		# Note for listen mode, an empty cert will cause stunnel to fail.
   3410 		# The ssvnc gui will have already taken care of this.
   3411 	fi
   3412 
   3413 	cat > "$tmp_cfg" <<END
   3414 foreground = yes
   3415 pid =
   3416 client = yes
   3417 debug = $stunnel_debug
   3418 $ciphers
   3419 $STUNNEL_EXTRA_OPTS
   3420 $STUNNEL_EXTRA_OPTS_USER
   3421 $cert
   3422 $crl
   3423 $verify
   3424 
   3425 ${stunnel_exec}[vnc_stunnel]
   3426 ${stunnel_exec}accept = $localhost:$use
   3427 $connect
   3428 $STUNNEL_EXTRA_SVC_OPTS
   3429 $STUNNEL_EXTRA_SVC_OPTS_USER
   3430 
   3431 END
   3432 
   3433 else
   3434 	# REVERSE case:
   3435 
   3436 	stunnel_exec=""	# doesn't work for listening.
   3437 
   3438 	p2=`expr 5500 + $N`
   3439 	connect="connect = $localhost:$p2"
   3440 	if [ "X$cert" = "XBUILTIN" ]; then
   3441 		ttcert=`make_tcert`
   3442 		cert="cert = $ttcert"
   3443 	fi
   3444 	# Note for listen mode, an empty cert will cause stunnel to fail.
   3445 	# The ssvnc gui will have already taken care of this.
   3446 
   3447 
   3448 	hloc=""
   3449 	if [ "X$use_ssh" = "X1" ]; then
   3450 		hloc="$localhost:"
   3451 	elif [ "X$STUNNEL_LISTEN" != "X" ]; then
   3452 		hloc="$STUNNEL_LISTEN:"
   3453 	fi
   3454 	if echo "$proxy" | grep -i '^vencrypt:' > /dev/null; then
   3455 		hloc="$localhost:"
   3456 		pv=`findfree 5570`
   3457 		proxy="vencrypt:$pv:$port"
   3458 		port=$pv
   3459 		if [ "X$anondh_set" = "X1" ]; then
   3460 			# not needed for ANONDH in this mode
   3461 			#ciphers="ciphers = ADH:@STRENGTH"
   3462 			:
   3463 		fi
   3464 	fi
   3465 	cat > "$tmp_cfg" <<END
   3466 foreground = yes
   3467 pid =
   3468 client = no
   3469 debug = $stunnel_debug
   3470 $ciphers
   3471 $STUNNEL_EXTRA_OPTS
   3472 $STUNNEL_EXTRA_OPTS_USER
   3473 $cert
   3474 $crl
   3475 $verify
   3476 
   3477 [vnc_stunnel]
   3478 accept = $hloc$port
   3479 $connect
   3480 $STUNNEL_EXTRA_SVC_OPTS
   3481 $STUNNEL_EXTRA_SVC_OPTS_USER
   3482 
   3483 END
   3484 
   3485 fi
   3486 
   3487 echo ""
   3488 echo "Using this stunnel configuration:"
   3489 echo ""
   3490 cat "$tmp_cfg" | uniq
   3491 echo ""
   3492 if egrep -i '^[ 	]*(CApath|CAfile) =' "$tmp_cfg" > /dev/null ; then
   3493 	:
   3494 else
   3495 	echo "** WARNING: THE STUNNEL CONFIG HAS NO SERVER CERTIFICATE SPECIFIED       **"
   3496 	echo "** WARNING: (the CApath or CAfile stunnel option) THE VNC SERVER WILL    **"
   3497 	echo "** WARNING: NOT BE AUTHENTICATED. A MAN-IN-THE-MIDDLE ATTACK IS POSSIBLE **"
   3498 	echo ""
   3499 fi
   3500 sleep 1
   3501 
   3502 if [ "X$stunnel_exec" = "X" ]; then
   3503 	echo ""
   3504 	echo "Running stunnel:"
   3505 	echo "$STUNNEL $tmp_cfg"
   3506 	st=`echo "$STUNNEL" | awk '{print $1}'`
   3507 	$st -help > /dev/null 2>&1
   3508 	$STUNNEL "$tmp_cfg" < /dev/tty > /dev/tty &
   3509 	stunnel_pid=$!
   3510 	echo ""
   3511 
   3512 	# pause here to let the user supply a possible passphrase for the
   3513 	# mycert key:
   3514 	if [ "X$mycert" != "X" ]; then
   3515 		nsl=10
   3516 		dsl=0
   3517 		if [ ! -f $mycert ]; then
   3518 			dsl=0
   3519 		elif grep -i 'Proc-Type.*ENCRYPTED' "$mycert" > /dev/null 2>/dev/null; then
   3520 			dsl=1
   3521 		fi
   3522 		if [ "X$dsl" = "X1" ]; then
   3523 			echo ""
   3524 			echo "(** pausing $nsl secs for possible certificate passphrase dialog **)"
   3525 			echo ""
   3526 			sleep $nsl
   3527 			echo "(** done pausing for passphrase **)"
   3528 			echo ""
   3529 		fi
   3530 	fi
   3531 	#echo T sleep 1
   3532 	sleep 1
   3533 	rm -f "$tmp_cfg"
   3534 fi
   3535 
   3536 
   3537 echo ""
   3538 if [ "X$SSVNC_EXTRA_SLEEP" != "X" ]; then
   3539 	echo "sleep $SSVNC_EXTRA_SLEEP"
   3540 	sleep $SSVNC_EXTRA_SLEEP
   3541 fi
   3542 
   3543 if [ "X$reverse" = "X" ]; then
   3544 	if [ "X$NEED_VENCRYPT_VIEWER_BRIDGE" = "X1" -a "X$ptmp" != "X" ] ; then
   3545 		port1=`expr 5900 + $N`		# stunnel port
   3546 		port2=`findfree 5970`		# bridge port (viewer connects to it.)
   3547 		N=`expr $port2 - 5900`
   3548 		env PPROXY_REMOVE=0 PPROXY_SLEEP=0 PPROXY_VENCRYPT_VIEWER_BRIDGE="$port2,$port1" $ptmp &
   3549 		sleep 1
   3550 	fi
   3551 	echo "Running viewer:"
   3552 	vnc_hp=$localhost:$N
   3553 	if [ "X$stunnel_exec" != "X" ]; then
   3554 		vnc_hp="exec=$STUNNEL $tmp_cfg"
   3555 	fi
   3556 	echo "$VNCVIEWERCMD" "$@" "$vnc_hp"
   3557 	trap "final" 0 2 15
   3558 	echo ""
   3559 	$VNCVIEWERCMD "$@" "$vnc_hp"
   3560 	if [ $? != 0 ]; then
   3561 		echo "vncviewer command failed: $?"
   3562 		if [ "X$secondtry" = "X1" ]; then
   3563 			sleep 2
   3564 			$VNCVIEWERCMD "$@" "$vnc_hp"
   3565 		fi
   3566 	fi
   3567 else
   3568 	echo "Running viewer:"
   3569 	echo ""
   3570 	echo "NOTE: Press Ctrl-C to terminate viewer LISTEN mode."
   3571 	echo ""
   3572 	trap "final" 0 2 15
   3573 	N2=$N
   3574 	N2_trim=`echo "$N2" | sed -e 's/://g'`
   3575 	if [ $N2_trim -le 200 ]; then
   3576 		N2_trim=`expr $N2_trim + 5500`
   3577 	fi
   3578 	if [ "X$proxy" != "X" ]; then
   3579 		if echo "$proxy" | grep -i '^vencrypt:' > /dev/null; then
   3580 			pstunnel=`echo "$proxy" | awk -F: '{print $2}'`
   3581 			plisten=`echo "$proxy" | awk -F: '{print $3}'`
   3582 			IF=INADDR_ANY
   3583 			if [ "X$STUNNEL_LISTEN" != "X" ]; then
   3584 				IF=$STUNNEL_LISTEN
   3585 			fi
   3586 			PPROXY_VENCRYPT_REVERSE=1; export PPROXY_VENCRYPT_REVERSE
   3587 			PPROXY_LISTEN="$IF:$plisten"; export PPROXY_LISTEN
   3588 			PPROXY_PROXY="vencrypt://$localhost:$pstunnel"; export PPROXY_PROXY
   3589 			PPROXY_DEST="$localhost:$pstunnel"; export PPROXY_DEST
   3590 			STUNNEL_ONCE=1; export STUNNEL_ONCE
   3591 			STUNNEL_MAX_CLIENTS=1; export STUNNEL_MAX_CLIENTS
   3592 			if [ "X$NEED_VENCRYPT_VIEWER_BRIDGE" = "X1" -a "X$ptmp" != "X" ] ; then
   3593 				port1=`expr 5500 + $N2`
   3594 				port2=`findfree 5580`
   3595 				N2=`expr $port2 - 5500`
   3596 				N2_trim=`echo "$N2" | sed -e 's/://g'`
   3597 				if [ $N2_trim -le 200 ]; then
   3598 					N2_trim=`expr $N2_trim + 5500`
   3599 				fi
   3600 				if [ "X$SSVNC_LISTEN_ONCE" != "X1" ]; then
   3601 					PPROXY_LOOP_THYSELF=`mytmp "/tmp/pproxy_loop_thyself1.${RANDOM}.$$"`
   3602 					export PPROXY_LOOP_THYSELF
   3603 					PPROXY_LOOP_THYSELF0=$PPROXY_LOOP_THYSELF
   3604 				fi
   3605 				env PPROXY_REMOVE=0 PPROXY_SLEEP=0 PPROXY_VENCRYPT_VIEWER_BRIDGE="-$port1,$port2" $ptmp &
   3606 				sleep 1
   3607 			fi
   3608 		else
   3609 			PPROXY_REVERSE="$localhost:$port"; export PPROXY_REVERSE
   3610 			PPROXY_SLEEP=1; export PPROXY_SLEEP;
   3611 		fi
   3612 		PPROXY_KILLPID=+1; export PPROXY_KILLPID;
   3613 		if [ "X$SSVNC_LISTEN_ONCE" != "X1" ]; then
   3614 			PPROXY_LOOP_THYSELF=`mytmp "/tmp/pproxy_loop_thyself2.${RANDOM}.$$"`
   3615 			export PPROXY_LOOP_THYSELF
   3616 		fi
   3617 		$ptmp &
   3618 		# Important to have no extra pids generated between here and VNCVIEWERCMD
   3619 	fi
   3620 	if [ "X$VNCVIEWER_IS_REALVNC4" = "X1" ]; then
   3621 		N2=$N2_trim
   3622 	fi
   3623 	echo "$VNCVIEWERCMD" "$@" -listen $N2
   3624 	echo ""
   3625 	$VNCVIEWERCMD "$@" -listen $N2
   3626 
   3627 	if [ "X$PPROXY_LOOP_THYSELF" != "X" ]; then
   3628 		rm -f $PPROXY_LOOP_THYSELF
   3629 	fi
   3630 	if [ "X$PPROXY_LOOP_THYSELF0" != "X" ]; then
   3631 		rm -f $PPROXY_LOOP_THYSELF0
   3632 	fi
   3633 fi
   3634 
   3635 sleep 1
   3636