ss_vncviewer 79.5 KB
Newer Older
1 2
#!/bin/sh
#
3 4
# ss_vncviewer:  wrapper for vncviewer to use an stunnel SSL tunnel
#                or an SSH tunnel.
5
#
6
# Copyright (c) 2006-2009 by Karl J. Runge <runge@karlrunge.com>
7
#
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
# ss_vncviewer is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or (at
# your option) any later version.
# 
# ss_vncviewer is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with ss_vncviewer; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
# or see <http://www.gnu.org/licenses/>.
# 
# 
24 25 26 27 28 29 30 31 32
# You must have stunnel(8) installed on the system and in your PATH
# (however, see the -ssh option below, in which case you will need ssh(1)
# installed)  Note: stunnel is usually installed in an "sbin" subdirectory.
#
# You should have "x11vnc -ssl ..." or "x11vnc -stunnel ..." 
# already running as the VNC server on the remote machine.
# (or use stunnel on the server side for any other VNC server)
#
#
33
# Usage: ss_vncviewer [cert-args] host:display <vncviewer-args>
34
#
35 36
# e.g.:  ss_vncviewer snoopy:0
#        ss_vncviewer snoopy:0 -encodings "copyrect tight zrle hextile"
37 38 39 40 41
#
# [cert-args] can be:
#
#	-verify /path/to/cacert.pem		
#	-mycert /path/to/mycert.pem		
42
#	-crl    /path/to/my_crl.pem  (or directory)
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
#	-proxy  host:port
#
# -verify specifies a CA cert PEM file (or a self-signed one) for
#         authenticating the VNC server.
#
# -mycert specifies this client's cert+key PEM file for the VNC server to
#	  authenticate this client. 
#
# -proxy  try host:port as a Web proxy to use the CONNECT method
#         to reach the VNC server (e.g. your firewall requires a proxy).
#
#         For the "double proxy" case use -proxy host1:port1,host2:port2
#         (the first CONNECT is done through host1:port1 to host2:port2
#         and then a 2nd CONNECT to the destination VNC server.)
#
58
#         Use socks://host:port, socks4://host:port, or socks5://host,port
59 60
#         to force usage of a SOCKS proxy.  Also repeater://host:port and
#         sslrepeater://host:port.
61
#
62 63 64
# -showcert  Only fetch the certificate using the 'openssl s_client'
#            command (openssl(1) must in installed).
#
65 66
#    See http://www.karlrunge.com/x11vnc/faq.html#faq-ssl-ca for details on
#    SSL certificates with VNC.
67 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 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
# -ssh    Use ssh instead of stunnel SSL.  ssh(1) must be installed and you
#         must be able to log into the remote machine via ssh.
#
#         In this case "host:display" may be of the form "user@host:display"
#         where "user@host" is used for the ssh login (see ssh(1) manpage).
#
#         If -proxy is supplied it can be of the forms: "gwhost" "gwhost:port"
#         "user@gwhost" or "user@gwhost:port".  "gwhost" is an incoming ssh 
#         gateway machine (the VNC server is not running there), an ssh -L
#         redir is used to "host" in "host:display" from "gwhost". Any "user@"
#         part must be in the -proxy string (not in "host:display").
#
#         Under -proxy use "gwhost:port" if connecting to any ssh port
#         other than the default (22).  (even for the non-gateway case,
#         -proxy must be used to specify a non-standard ssh port)
#
#         A "double ssh" can be specified via a -proxy string with the two
#         hosts separated by a comma:
#
#             [user1@]host1[:port1],[user2@]host2[:port2]
#
#         in which case a ssh to host1 and thru it via a -L redir a 2nd
#         ssh is established to host2.  
#
#         Examples:
#
98 99
#         ss_vncviewer -ssh bob@bobs-home.net:0
#         ss_vncviewer -ssh -sshcmd 'x11vnc -localhost' bob@bobs-home.net:0
100
#
101 102
#         ss_vncviewer -ssh -proxy fred@mygate.com:2022 mymachine:0
#         ss_vncviewer -ssh -proxy bob@bobs-home.net:2222 localhost:0
103
#
104
#         ss_vncviewer -ssh -proxy fred@gw-host,fred@peecee localhost:0
105 106 107 108 109 110 111 112 113 114 115 116 117
#
# -sshcmd cmd   Run "cmd" via ssh instead of the default "sleep 15"
#               e.g. -sshcmd 'x11vnc -display :0 -localhost -rfbport 5900'
#
# -sshargs "args"  pass "args" to the ssh process, e.g. -L/-R port redirs.
#
# -sshssl Tunnel the SSL connection thru a SSH connection.  The tunnel as
#         under -ssh is set up and the SSL connection goes thru it.  Use
#         this if you want to have and end-to-end SSL connection but must
#         go thru a SSH gateway host (e.g. not the vnc server).  Or use
#         this if you need to tunnel additional services via -R and -L 
#         (see -sshargs above).
#
118
#         ss_vncviewer -sshssl -proxy fred@mygate.com mymachine:0
119
#
120
# -listen (or -reverse) set up a reverse connection.
121 122 123 124 125 126 127 128 129 130 131 132 133
#
# -alpha  turn on cursor alphablending hack if you are using the
#         enhanced tightvnc vncviewer.
#
# -grab   turn on XGrabServer hack if you are using the enhanced tightvnc
#         vncviewer (e.g. for fullscreen mode in some windowmanagers like
#         fvwm that do not otherwise work in fullscreen mode)
#
#
# set VNCVIEWERCMD to whatever vncviewer command you want to use.
#
VNCIPCMD=${VNCVIEWERCMD:-vncip}
VNCVIEWERCMD=${VNCVIEWERCMD:-vncviewer}
134 135 136 137 138 139 140 141 142
if [ "X$SSVNC_TURBOVNC" != "X" ]; then
	if echo "$VNCVIEWERCMD" | grep '\.turbovnc' > /dev/null; then
		:
	else
		if type "$VNCVIEWERCMD.turbovnc" > /dev/null 2>/dev/null; then
			VNCVIEWERCMD="$VNCVIEWERCMD.turbovnc"
		fi
	fi
fi
143 144 145 146
#
# Same for STUNNEL, e.g. set it to /path/to/stunnel or stunnel4, etc.
#

147
# turn on verbose debugging output
148
if [ "X$SS_DEBUG" != "X" -a "X$SS_DEBUG" != "X0" ]; then
runge's avatar
runge committed
149 150
	set -xv 
fi
151

152 153
PATH=$PATH:/usr/sbin:/usr/local/sbin:/dist/sbin; export PATH

154 155 156 157 158 159
localhost="localhost"
if uname | grep Darwin >/dev/null; then
	localhost="127.0.0.1"
fi

# work out which stunnel to use (debian installs as stunnel4)
160
stunnel_set_here=""
161
if [ "X$STUNNEL" = "X" ]; then
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
	check_stunnel=1
	if [ "X$SSVNC_BASEDIRNAME" != "X" ]; then
		if [ -x "$SSVNC_BASEDIRNAME/stunnel" ]; then
			type stunnel > /dev/null 2>&1
			if [ $? = 0 ]; then
				# found ours
				STUNNEL=stunnel
				check_stunnel=0
			fi
		fi
	fi
	if [ "X$check_stunnel" = "X1" ]; then
		type stunnel4 > /dev/null 2>&1
		if [ $? = 0 ]; then
			STUNNEL=stunnel4
		else
			STUNNEL=stunnel
		fi
180
	fi
181
	stunnel_set_here=1
182 183 184
fi

help() {
185
	tail -n +2 "$0" | sed -e '/^$/ q'
186 187
}

188
secondtry=""
189 190 191 192 193
gotalpha=""
use_ssh=""
use_sshssl=""
direct_connect=""
ssh_sleep=15
194 195

# sleep longer in -listen mode:
196 197 198
if echo "$*" | grep '.*-listen' > /dev/null; then
	ssh_sleep=1800
fi
199 200


201
ssh_cmd=""
202
# env override of ssh_cmd:
203 204
if [ "X$SS_VNCVIEWER_SSH_CMD" != "X" ]; then
	ssh_cmd="$SS_VNCVIEWER_SSH_CMD"
205
fi
206

207
ssh_args=""
208 209
showcert=""
reverse=""
210

runge's avatar
runge committed
211 212
ciphers=""
anondh="ALL:RC4+RSA:+SSLv2:@STRENGTH"
213 214 215 216 217
anondh_set=""
stunnel_debug="6"
if [ "X$SS_DEBUG" != "X" -o "X$SSVNC_VENCRYPT_DEBUG" != "X" -o "X$SSVNC_STUNNEL_DEBUG" != "X" ]; then
	stunnel_debug="7"
fi
runge's avatar
runge committed
218

219
if [ "X$1" = "X-viewerflavor" ]; then
220 221
	# special case, try to guess which viewer:
	#
runge's avatar
runge committed
222 223 224 225
	if echo "$VNCVIEWERCMD" | egrep -i '^(xmessage|sleep )' > /dev/null; then
		echo "unknown"
		exit 0
	fi
226 227 228 229
	if echo "$VNCVIEWERCMD" | grep -i chicken.of > /dev/null; then
		echo "cotvnc"
		exit 0
	fi
230 231 232 233
	if echo "$VNCVIEWERCMD" | grep -i ultra > /dev/null; then
		echo "ultravnc"
		exit 0
	fi
234
	# OK, run it for help output...
235
	str=`$VNCVIEWERCMD -h 2>&1 | head -n 5`
236 237 238 239
	if echo "$str" | grep -i 'TightVNC.viewer' > /dev/null; then
		echo "tightvnc"
	elif echo "$str" | grep -i 'VNC viewer version 3' > /dev/null; then
		echo "realvnc3"
240 241 242 243
	elif echo "$str" | grep -i 'VNC viewer .*Edition 4' > /dev/null; then
		echo "realvnc4"
	elif echo "$str" | grep -i 'RealVNC.Ltd' > /dev/null; then
		echo "realvnc4"
244 245 246 247 248
	else
		echo "unknown"
	fi
	exit 0
fi
249 250 251
if [ "X$1" = "X-viewerhelp" ]; then
	$VNCVIEWERCMD -h 2>&1
	exit 0
runge's avatar
runge committed
252 253
fi

254 255 256 257 258 259 260 261
# grab our cmdline options:
while [ "X$1" != "X" ]
do
    case $1 in 
	"-verify")	shift; verify="$1"
                ;;
	"-mycert")	shift; mycert="$1"
                ;;
262 263
	"-crl")		shift; crl="$1"
                ;;
264 265 266 267 268 269 270 271 272 273 274
	"-proxy")	shift; proxy="$1"
                ;;
	"-ssh")		use_ssh=1
                ;;
	"-sshssl")	use_ssh=1
			use_sshssl=1
                ;;
	"-sshcmd")	shift; ssh_cmd="$1"
                ;;
	"-sshargs")	shift; ssh_args="$1"
                ;;
runge's avatar
runge committed
275
	"-anondh")	ciphers="ciphers=$anondh"
276
			anondh_set=1
runge's avatar
runge committed
277 278 279
                ;;
	"-ciphers")	shift; ciphers="ciphers=$1"
                ;;
280 281
	"-alpha")	gotalpha=1
                ;;
282 283 284 285 286 287
	"-showcert")	showcert=1
                ;;
	"-listen")	reverse=1
                ;;
	"-reverse")	reverse=1
                ;;
288 289
	"-2nd")		secondtry=1
                ;;
290 291
	"-grab")	VNCVIEWER_GRAB_SERVER=1; export VNCVIEWER_GRAB_SERVER
                ;;
292 293 294 295 296 297
	"-x11cursor")	VNCVIEWER_X11CURSOR=1; export VNCVIEWER_X11CURSOR
                ;;
	"-rawlocal")	VNCVIEWER_RAWLOCAL=1; export VNCVIEWER_RAWLOCAL
                ;;
	"-scale")	shift; SSVNC_SCALE="$1"; export SSVNC_SCALE
                ;;
298 299
	"-onelisten")	SSVNC_LISTEN_ONCE=1; export SSVNC_LISTEN_ONCE
                ;;
300 301 302 303 304 305
	"-sendclipboard")	VNCVIEWER_SEND_CLIPBOARD=1; export VNCVIEWER_SEND_CLIPBOARD
                ;;
	"-sendalways")	VNCVIEWER_SEND_ALWAYS=1; export VNCVIEWER_SEND_ALWAYS
                ;;
	"-recvtext")	shift; VNCVIEWER_RECV_TEXT="$1"; export VNCVIEWER_RECV_TEXT
                ;;
runge's avatar
runge committed
306 307
	"-escape")	shift; VNCVIEWER_ESCAPE="$1"; export VNCVIEWER_ESCAPE
                ;;
308 309
	"-ssvnc_encodings")	shift; VNCVIEWER_ENCODINGS="$1"; export VNCVIEWER_ENCODINGS
                ;;
310 311
	"-ssvnc_extra_opts")	shift; VNCVIEWERCMD_EXTRA_OPTS="$1"; export VNCVIEWERCMD_EXTRA_OPTS
                ;;
312 313 314 315 316 317 318 319
	"-rfbversion")	shift; VNCVIEWER_RFBVERSION="$1"; export VNCVIEWER_RFBVERSION
                ;;
	"-nobell")	VNCVIEWER_NOBELL=1; export VNCVIEWER_NOBELL
                ;;
	"-popupfix")	VNCVIEWER_POPUP_FIX=1; export VNCVIEWER_POPUP_FIX
                ;;
	"-realvnc4")	VNCVIEWER_IS_REALVNC4=1; export VNCVIEWER_IS_REALVNC4
                ;;
320 321 322 323 324 325 326 327 328 329
	"-h"*)	help; exit 0
                ;;
	"--h"*)	help; exit 0
                ;;
	*)	break
                ;;
    esac
    shift
done

330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
# maxconn is something we added to stunnel, this disables it:
if [ "X$SS_VNCVIEWER_NO_MAXCONN" != "X" ]; then
	STUNNEL_EXTRA_OPTS=`echo "$STUNNEL_EXTRA_OPTS" | sed -e 's/maxconn/#maxconn/'`
elif echo "$VNCVIEWERCMD" | egrep -i '^(xmessage|sleep )' > /dev/null; then
	STUNNEL_EXTRA_OPTS=`echo "$STUNNEL_EXTRA_OPTS" | sed -e 's/maxconn/#maxconn/'`
elif [ "X$reverse" != "X" ]; then
	STUNNEL_EXTRA_OPTS=`echo "$STUNNEL_EXTRA_OPTS" | sed -e 's/maxconn/#maxconn/'`
else
	# new way (our patches).  other than the above, we set these:
	if [ "X$SKIP_STUNNEL_ONCE" = "X" ]; then
		STUNNEL_ONCE=1; export STUNNEL_ONCE
	fi
	if [ "X$SKIP_STUNNEL_MAX_CLIENTS" = "X" ]; then
		STUNNEL_MAX_CLIENTS=1; export STUNNEL_MAX_CLIENTS
	fi
fi
# always set this one:
if [ "X$SKIP_STUNNEL_NO_SYSLOG" = "X" ]; then
	STUNNEL_NO_SYSLOG=1; export STUNNEL_NO_SYSLOG
fi

# this is the -t ssh option (gives better keyboard response thru SSH tunnel)
352 353 354 355 356
targ="-t"
if [ "X$SS_VNCVIEWER_NO_T" != "X" ]; then
	targ=""
fi

357
# set the alpha blending env. hack: 
358 359 360 361
if [ "X$gotalpha" = "X1" ]; then
	VNCVIEWER_ALPHABLEND=1
	export VNCVIEWER_ALPHABLEND
else
362 363 364
	NO_ALPHABLEND=1
	export NO_ALPHABLEND
fi
365

366 367 368
if [ "X$reverse" != "X" ]; then
	ssh_sleep=1800
	if [ "X$proxy" != "X" ]; then
369
		# check proxy usage under reverse connection:
370 371
		if [ "X$use_ssh" = "X" -a "X$use_sshssl" = "X" ]; then
			echo ""
372
			if echo "$proxy" | egrep -i "(repeater|vencrypt)://" > /dev/null; then
373 374 375
				:
			else
				echo "*Warning*: SSL -listen and a Web proxy does not make sense."
376
				sleep 2
377
			fi
378 379 380 381 382
		elif echo "$proxy" | grep "," > /dev/null; then
			:
		else
			echo ""
			echo "*Warning*: -listen and a single proxy/gateway does not make sense."
383
			sleep 2
384
		fi
385
		SSVNC_LISTEN_ONCE=1; export SSVNC_LISTEN_ONCE
386 387 388
	fi
fi
if [ "X$ssh_cmd" = "X" ]; then
389
	# if no remote ssh cmd, sleep a bit:
390 391
	ssh_cmd="sleep $ssh_sleep"
fi
392

393 394
# this should be a host:display:
#
395 396 397
orig="$1"
shift

runge's avatar
runge committed
398 399 400 401 402
dL="-L"
if uname -sr | egrep 'SunOS 5\.[5-8]' > /dev/null; then
	dL="-h"
fi

403 404 405 406 407 408 409 410
rchk() {
	# a kludge to set $RANDOM if we are not bash:
	if [ "X$BASH_VERSION" = "X" ]; then
		RANDOM=`date +%S``sh -c 'echo $$'``ps -elf 2>&1 | sum 2>&1 | awk '{print $1}'`
	fi
}
rchk

runge's avatar
runge committed
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
# a portable, but not absolutely safe, tmp file creator
mytmp() {
	tf=$1
	if type mktemp > /dev/null 2>&1; then
		# if we have mktemp(1), use it:
		tf2="$tf.XXXXXX"
		tf2=`mktemp "$tf2"`
		if [ "X$tf2" != "X" -a -f "$tf2" ]; then
			if [ "X$DEBUG_MKTEMP" != "X" ]; then
				echo "mytmp-mktemp: $tf2" 1>&2
			fi
			echo "$tf2"
			return
		fi
	fi
	# fallback to multiple cmds:
	rm -rf "$tf" || exit 1
	if [ -d "$tf" ]; then
		echo "tmp file $tf still exists as a directory."
		exit 1
	elif [ $dL "$tf" ]; then
		echo "tmp file $tf still exists as a symlink."
		exit 1
	elif [ -f "$tf" ]; then
		echo "tmp file $tf still exists."
		exit 1
	fi
	touch "$tf" || exit 1
	chmod 600 "$tf" || exit 1
	rchk
	if [ "X$DEBUG_MKTEMP" != "X" ]; then
		echo "mytmp-touch: $tf" 1>&2
	fi
	echo "$tf"
}

447 448 449 450 451 452 453 454 455 456 457
# set up special case of ultravnc single click III mode:
if echo "$proxy" | egrep "^sslrepeater://" > /dev/null; then
	pstr=`echo "$proxy" | sed -e 's,sslrepeater://,,'`
	pstr1=`echo "$pstr" | sed -e 's/+.*$//'`
	pstr2=`echo "$pstr" | sed -e 's/^[^+]*+//'`
	SSVNC_REPEATER="SCIII=$pstr2"; export SSVNC_REPEATER
	orig=$pstr1
	echo
	echo "reset: SSVNC_REPEATER=$SSVNC_REPEATER orig=$orig proxy=''"
	proxy=""
fi
runge's avatar
runge committed
458 459 460 461 462
if echo "$proxy" | egrep "vencrypt://" > /dev/null; then
	vtmp="/tmp/ss_handshake${RANDOM}.$$.txt"
	vtmp=`mytmp "$vtmp"`
	SSVNC_PREDIGESTED_HANDSHAKE="$vtmp"
	export SSVNC_PREDIGESTED_HANDSHAKE
463 464 465 466 467 468
	if [ "X$SSVNC_USE_OURS" = "X" ]; then
		NEED_VENCRYPT_VIEWER_BRIDGE=1
	fi
fi
if [ "X$SSVNC_USE_OURS" = "X" ]; then
	VNCVIEWERCMD_EXTRA_OPTS=""
runge's avatar
runge committed
469
fi
470 471


472
# check -ssh and -mycert/-verify conflict:
473 474 475 476 477 478 479
if [ "X$use_ssh" = "X1" -a "X$use_sshssl" = "X" ]; then
	if [ "X$mycert" != "X" -o "X$verify" != "X" ]; then
		echo "-mycert and -verify cannot be used in -ssh mode" 
		exit 1
	fi
fi

480 481
# direct mode Vnc:// means show no warnings.
# direct mode vnc:// will show warnings.
482 483 484 485 486 487
if echo "$orig" | grep '^V[Nn][Cc]://' > /dev/null; then
	SSVNC_NO_ENC_WARN=1
	export SSVNC_NO_ENC_WARN
	orig=`echo "$orig" | sed -e 's/^...:/vnc:/'`
fi

488
# interprest the pseudo URL proto:// strings:
489 490 491 492
if echo "$orig" | grep '^vnc://' > /dev/null; then
	orig=`echo "$orig" | sed -e 's,vnc://,,'`
	verify=""
	mycert=""
493
	crl=""
494 495 496
	use_ssh=""
	use_sshssl=""
	direct_connect=1
497 498
elif echo "$orig" | grep '^vncs://' > /dev/null; then
	orig=`echo "$orig" | sed -e 's,vncs://,,'`
runge's avatar
runge committed
499 500
elif echo "$orig" | grep '^vncssl://' > /dev/null; then
	orig=`echo "$orig" | sed -e 's,vncssl://,,'`
501 502
elif echo "$orig" | grep '^vnc+ssl://' > /dev/null; then
	orig=`echo "$orig" | sed -e 's,vnc.ssl://,,'`
runge's avatar
runge committed
503 504 505
elif echo "$orig" | grep '^vncssh://' > /dev/null; then
	orig=`echo "$orig" | sed -e 's,vncssh://,,'`
	use_ssh=1
506 507 508
elif echo "$orig" | grep '^vnc+ssh://' > /dev/null; then
	orig=`echo "$orig" | sed -e 's,vnc.ssh://,,'`
	use_ssh=1
runge's avatar
runge committed
509
fi
510

511 512 513
if [ "X$SSVNC_ULTRA_DSM" != "X" ]; then
        verify=""
        mycert=""
514
        crl=""
515 516 517
        use_ssh=""
        use_sshssl=""
        direct_connect=1
518 519 520
	if echo "$SSVNC_ULTRA_DSM" | grep 'noultra:' > /dev/null; then
		SSVNC_NO_ULTRA_DSM=1; export SSVNC_NO_ULTRA_DSM
	fi
521 522
fi

523
# (possibly) tell the vncviewer to only listen on lo: 
runge's avatar
runge committed
524 525 526
if [ "X$reverse" != "X" -a "X$direct_connect" = "X" ]; then
	VNCVIEWER_LISTEN_LOCALHOST=1
	export VNCVIEWER_LISTEN_LOCALHOST
527 528
fi

529
# rsh mode is an internal/secret thing only I use.
530 531 532 533 534 535 536 537 538 539 540
rsh=""
if echo "$orig" | grep '^rsh://' > /dev/null; then
	use_ssh=1
	rsh=1
	orig=`echo "$orig" | sed -e 's,rsh://,,'`
elif echo "$orig" | grep '^rsh:' > /dev/null; then
	use_ssh=1
	rsh=1
	orig=`echo "$orig" | sed -e 's,rsh:,,'`
fi

541 542 543 544
# play around with host:display port:
if echo "$orig" | grep ':' > /dev/null; then
	:
else
545
	# add or assume :0 if no ':'
546 547
	if [ "X$reverse" = "X" ]; then
		orig="$orig:0"
runge's avatar
runge committed
548 549
	elif [ "X$orig" = "X" ]; then
		orig=":0"
550
	fi
551 552
fi

553
# extract host and disp number:
554 555 556
host=`echo "$orig" | awk -F: '{print $1}'`
disp=`echo "$orig" | awk -F: '{print $2}'`
if [ "X$host" = "X" ]; then
557
	host=$localhost
558
fi
runge's avatar
runge committed
559 560 561
if [ "X$disp" = "X" ]; then
	port=""	# probably -listen mode.
elif [ $disp -lt 0 ]; then
562
	# negative means use |n| without question:
563 564
	port=`expr 0 - $disp`
elif [ $disp -lt 200 ]; then
565
	# less than 200 means 5900+n
566 567 568 569 570
	if [ "X$reverse" = "X" ]; then
		port=`expr $disp + 5900`
	else
		port=`expr $disp + 5500`
	fi
571
else
572
	# otherwise use the number directly, e.g. 443, 2345
573 574 575 576 577 578 579 580
	port=$disp
fi

# try to find an open listening port via netstat(1):
inuse=""
if uname | grep Linux > /dev/null; then
	inuse=`netstat -ant | egrep 'LISTEN|WAIT|ESTABLISH|CLOSE' | awk '{print $4}' | sed 's/^.*://'`
elif uname | grep SunOS > /dev/null; then
581 582 583
	inuse=`netstat -an -f inet -P tcp | egrep 'LISTEN|WAIT|ESTABLISH|CLOSE' | awk '{print $1}' | sed 's/^.*\.//'`
elif uname | egrep -i 'bsd|darwin' > /dev/null; then
	inuse=`netstat -ant -f inet | egrep 'LISTEN|WAIT|ESTABLISH|CLOSE' | awk '{print $4}' | sed 's/^.*\.//'`
584 585 586
# add others...
fi

587
# this is a crude attempt for unique ports tags, etc.
588 589
date_sec=`date +%S`

590 591
# these are special cases of no vnc, e.g. sleep or xmessage.
# these are for using ssvnc as a general port redirector.
runge's avatar
runge committed
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607
if echo "$VNCVIEWERCMD" | grep '^sleep[ 	][ 	]*[0-9][0-9]*' > /dev/null; then
	if [ "X$SS_VNCVIEWER_LISTEN_PORT" = "X" ]; then
		p=`echo "$VNCVIEWERCMD" | awk '{print $3}'`
		if [ "X$p" != "X" ]; then
			SS_VNCVIEWER_LISTEN_PORT=$p
		fi
	fi
	p2=`echo "$VNCVIEWERCMD" | awk '{print $2}'`
	VNCVIEWERCMD="eval sleep $p2; echo Local "
elif echo "$VNCVIEWERCMD" | grep '^xmessage[ 	][ 	]*[0-9][0-9]*' > /dev/null; then
	if [ "X$SS_VNCVIEWER_LISTEN_PORT" = "X" ]; then
		p=`echo "$VNCVIEWERCMD" | awk '{print $2}'`
		SS_VNCVIEWER_LISTEN_PORT=$p
	fi
fi

608
# utility to find a free port to listen on.
609 610 611 612 613
findfree() {
	try0=$1
	try=$try0
	use0=""

runge's avatar
runge committed
614 615 616 617
	if [ "X$SS_VNCVIEWER_LISTEN_PORT" != "X" ]; then
		echo "$SS_VNCVIEWER_LISTEN_PORT"
		return	
	fi
618 619 620 621 622
	if [ $try -ge 6000 ]; then
		fmax=`expr $try + 1000`
	else
		fmax=6000
	fi
runge's avatar
runge committed
623

624
	while [ $try -lt $fmax ]
625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643
	do
		if [ "X$inuse" = "X" ]; then
			break
		fi
		if echo "$inuse" | grep -w $try > /dev/null; then
			:
		else
			use0=$try
			break
		fi
		try=`expr $try + 1`
	done
	if [ "X$use0" = "X" ]; then
		use0=`expr $date_sec + $try0`
	fi

	echo $use0
}

644 645
# utility for exiting; kills some helper processes,
# removes files, etc.
646 647
final() {
	echo ""
648 649 650
	if [ "X$tmp_cfg" != "X" ]; then
		rm -f $tmp_cfg
	fi
651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672
	if [ "X$SS_VNCVIEWER_RM" != "X" ]; then
		rm -f $SS_VNCVIEWER_RM 2>/dev/null
	fi
	if [ "X$tcert" != "X" ]; then
		rm -f $tcert
	fi
	if [ "X$pssh" != "X" ]; then
		echo "Terminating background ssh process"
		echo kill -TERM "$pssh"
		kill -TERM "$pssh" 2>/dev/null
		sleep 1
		kill -KILL "$pssh" 2>/dev/null
		pssh=""
	fi
	if [ "X$stunnel_pid" != "X" ]; then
		echo "Terminating background stunnel process"
		echo kill -TERM "$stunnel_pid"
		kill -TERM "$stunnel_pid" 2>/dev/null
		sleep 1
		kill -KILL "$stunnel_pid" 2>/dev/null
		stunnel_pid=""
	fi
673 674 675 676 677 678 679 680
	if [ "X$dsm_pid" != "X" ]; then
		echo "Terminating background ultravnc_dsm_helper process"
		echo kill -TERM "$dsm_pid"
		kill -TERM "$dsm_pid" 2>/dev/null
		sleep 1
		kill -KILL "$dsm_pid" 2>/dev/null
		stunnel_pid=""
	fi
681 682 683
	if [ "X$tail_pid" != "X" ]; then
		kill -TERM $tail_pid
	fi
684 685 686
	if [ "X$tail_pid2" != "X" ]; then
		kill -TERM $tail_pid2
	fi
687
}
688

689
if [ "X$reverse" = "X" ]; then
690
	# normal connections try 5930-5999:
691 692 693 694 695 696 697 698
	if [ "X$showcert" = "X" ]; then
		use=`findfree 5930`
	else
		# move away from normal place for (possibly many) -showcert
		pstart=`date +%S`
		pstart=`expr 6130 + $pstart + $pstart`
		use=`findfree $pstart`
	fi
699 700 701 702 703
	if [ $use -ge 5900 ]; then
		N=`expr $use - 5900`
	else
		N=$use
	fi
704
else
705
	# reverse connections:
706 707 708 709 710 711 712
	p2=`expr $port + 30`
	use=`findfree $p2`
	if [ $use -ge 5500 ]; then
		N=`expr $use - 5500`
	else
		N=$use
	fi
713 714
fi

715
# this is for my special use of ss_vncip -> vncip viewer.
716 717 718 719
if echo "$0" | grep vncip > /dev/null; then
	VNCVIEWERCMD="$VNCIPCMD"
fi

720 721 722 723 724 725
if echo "$VNCVIEWERCMD" | egrep -i '^(xmessage|sleep )' > /dev/null; then
	:
elif [ "X$VNCVIEWERCMD_EXTRA_OPTS" != "X" ]; then
	VNCVIEWERCMD="$VNCVIEWERCMD $VNCVIEWERCMD_EXTRA_OPTS"
fi

726
# trick for the undocumented rsh://host:port method.
727 728 729 730 731 732 733 734 735 736 737
rsh_setup() {
	if echo "$ssh_host" | grep '@' > /dev/null; then
		ul=`echo "$ssh_host" | awk -F@ '{print $1}'`
		ul="-l $ul"
		ssh_host=`echo "$ssh_host" | awk -F@ '{print $2}'`
	else
		ul=""
	fi
	ssh_cmd=`echo "$ssh_cmd" | sed -e 's/ -localhost/ /g'`
}

738
# trick for the undocumented rsh://host:port method.
739 740 741 742 743 744 745 746 747 748 749 750 751
rsh_viewer() {
	trap "final" 0 2 15
	if [ "X$PORT" = "X" ]; then
		exit 1
	elif [ $PORT -ge 5900 ]; then
		vdpy=`expr $PORT - 5900`
	else
		vdpy=":$PORT"
	fi
	stty sane
	echo "$VNCVIEWERCMD" "$@" $ssh_host:$vdpy
	echo ""
	$VNCVIEWERCMD "$@" $ssh_host:$vdpy
752 753 754 755 756 757
	if [ $? != 0 ]; then
		sleep 2
		$VNCVIEWERCMD "$@" $ssh_host:$vdpy
	fi
}

758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774
check_perl() {
	if type "$1" > /dev/null 2>&1; then
		:
	elif [ ! -x "$1" ]; then
		echo ""
		echo "*******************************************************"
		echo "** Problem finding the Perl command '$1': **"
		echo ""
		type "perl"
		echo ""
		echo "** Perhaps you need to install the Perl package. **"
		echo "*******************************************************"
		echo ""
		sleep 5
	fi
}

775 776 777 778 779
# this is the PPROXY tool.  used only here for now... 
pcode() {
	tf=$1
	PPROXY_PROXY=$proxy; export PPROXY_PROXY
	PPROXY_DEST="$host:$port"; export PPROXY_DEST
780 781
	check_perl /usr/bin/perl

782 783
	cod='#!/usr/bin/perl

784 785 786
# A hack to glue stunnel to a Web or SOCKS proxy, UltraVNC repeater for
# client connections.
# Also acts as a VeNCrypt bridge (by redirecting to stunnel.)
787 788 789

use IO::Socket::INET;

790
if (exists $ENV{PPROXY_SLEEP} && $ENV{PPROXY_SLEEP} > 0) {
791 792 793
	print STDERR "PPROXY_PID: $$\n";
	sleep $ENV{PPROXY_SLEEP};
}
794

795 796 797 798 799 800 801 802 803 804 805 806 807
foreach my $var (qw(
		PPROXY_DEST
		PPROXY_KILLPID
		PPROXY_LISTEN
		PPROXY_PROXY
		PPROXY_REMOVE
		PPROXY_REPEATER
		PPROXY_REVERSE
		PPROXY_SLEEP
		PPROXY_SOCKS
		PPROXY_VENCRYPT
		PPROXY_VENCRYPT_VIEWER_BRIDGE
    )) {
808
	if (0 || $ENV{SS_DEBUG} || $ENV{SSVNC_VENCRYPT_DEBUG}) {
809 810 811 812 813 814 815 816 817 818
		print STDERR "$var: $ENV{$var}\n";
	}
} 

if ($ENV{PPROXY_SOCKS} ne "" && $ENV{PPROXY_PROXY} !~ m,^socks5?://,i) {
	if ($ENV{PPROXY_SOCKS} eq "5") {
		$ENV{PPROXY_PROXY} = "socks5://$ENV{PPROXY_PROXY}";
	} else {
		$ENV{PPROXY_PROXY} = "socks://$ENV{PPROXY_PROXY}";
	}
819 820
}

821
my $rfbSecTypeAnonTls  = 18;
runge's avatar
runge committed
822 823 824 825 826 827 828 829 830 831 832 833 834 835 836
my $rfbSecTypeVencrypt = 19;

my $rfbVencryptPlain        = 256;
my $rfbVencryptTlsNone      = 257;
my $rfbVencryptTlsVnc       = 258;
my $rfbVencryptTlsPlain     = 259;
my $rfbVencryptX509None     = 260;
my $rfbVencryptX509Vnc      = 261;
my $rfbVencryptX509Plain    = 262;

my $handshake_file = "";
if (exists $ENV{SSVNC_PREDIGESTED_HANDSHAKE})  {
	$handshake_file = $ENV{SSVNC_PREDIGESTED_HANDSHAKE};
}

837 838 839 840 841 842 843 844 845 846 847 848 849
my $have_gettimeofday = 0;
eval "use Time::HiRes";
if ($@ eq "") {
	$have_gettimeofday = 1;
}
sub gettime {
	my $t = "0.0";
	if ($have_gettimeofday) {
		$t = Time::HiRes::gettimeofday();
	}
	return $t;
}

850 851 852 853 854 855 856 857
my $listen_handle = "";
my $sock = "";
my $parent = $$;

if ($ENV{PPROXY_VENCRYPT_VIEWER_BRIDGE}) {
	my ($from, $to) = split(/,/, $ENV{PPROXY_VENCRYPT_VIEWER_BRIDGE});
	do_vencrypt_viewer_bridge($from, $to);
	exit 0;
runge's avatar
runge committed
858 859
}

860 861 862 863 864
my ($first, $second, $third) = split(/,/, $ENV{PPROXY_PROXY}, 3);
my ($mode_1st, $mode_2nd, $mode_3rd) = ("", "", "");

($first, $mode_1st) = url_parse($first);

865 866 867 868
my ($proxy_host, $proxy_port) = split(/:/, $first);
my $connect = $ENV{PPROXY_DEST};

if ($second ne "") {
869
	($second, $mode_2nd) = url_parse($second);
870 871 872
}

if ($third ne "") {
873
	($third, $mode_3rd) = url_parse($third);
874 875
}

876

877
print STDERR "\n";
878
print STDERR "PPROXY v0.3: a tool for Web, SOCKS, and UltraVNC proxies and VeNCrypt bridging.\n";
879 880 881 882 883
print STDERR "proxy_host:       $proxy_host\n";
print STDERR "proxy_port:       $proxy_port\n";
print STDERR "proxy_connect:    $connect\n";
print STDERR "pproxy_params:    $ENV{PPROXY_PROXY}\n";
print STDERR "pproxy_listen:    $ENV{PPROXY_LISTEN}\n";
884
print STDERR "pproxy_reverse:   $ENV{PPROXY_REVERSE}\n";
885
print STDERR "\n";
886 887 888 889 890 891
if (1) {
	print STDERR "pproxy 1st: $first\t- $mode_1st\n";
	print STDERR "pproxy 2nd: $second\t- $mode_2nd\n";
	print STDERR "pproxy 3rd: $third\t- $mode_3rd\n";
	print STDERR "\n";
}
892

893 894 895 896 897 898
sub pdie {
	my $msg = shift;
	kill_proxy_pids();
	die "$msg";
}

899 900 901 902 903 904 905 906 907
if ($ENV{PPROXY_REVERSE} ne "") {
	my ($rhost, $rport) = split(/:/, $ENV{PPROXY_REVERSE});
	$rport = 5900 unless $rport;
	$listen_handle = IO::Socket::INET->new(
		PeerAddr => $rhost,
		PeerPort => $rport,
		Proto => "tcp"
	);
	if (! $listen_handle) {
908
		pdie "pproxy: $! -- PPROXY_REVERSE\n";
909 910
	}
	print STDERR "PPROXY_REVERSE: connected to $rhost $rport\n";
911

912
} elsif ($ENV{PPROXY_LISTEN} ne "") {
913
	my $listen_sock = "";
914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943
	my $maxtry = 12;
	my $sleep = 5;
	my $p2 = "";
	for (my $i=0; $i < $maxtry; $i++)  {
		if ($ENV{PPROXY_LISTEN} =~ /^INADDR_ANY:(.*)/) {
			my $p = $1;
			$p2 = "*:$p";
			$listen_sock = IO::Socket::INET->new(
				Listen    => 2,
				LocalPort => $p,
				Proto     => "tcp"
			);
		} else {
			$p2 = "localhost:$ENV{PPROXY_LISTEN}";
			$listen_sock = IO::Socket::INET->new(
				Listen    => 2,
				LocalAddr => "127.0.0.1",
				LocalPort => $ENV{PPROXY_LISTEN},
				Proto     => "tcp"
			);
		}
		if (! $listen_sock) {
			if ($i < $maxtry - 1) {
				warn "pproxy: $!\n";
				warn "Could not listen on port $p2, retrying in $sleep seconds... (Ctrl-C to quit)\n";
				sleep $sleep;
			}
		} else {
			last;
		}
944
	}
945
	if (! $listen_sock) {
946
		pdie "pproxy: $! -- PPROXY_LISTEN\n";
947
	}
948
	print STDERR "pproxy: listening on $p2\n";
949 950
	my $ip;
	($listen_handle, $ip) = $listen_sock->accept();
951 952
	my $err = $!;
	close $listen_sock;
953
	if (! $listen_handle) {
954
		pdie "pproxy: $err\n";
955 956 957
	}
}

958
$sock = IO::Socket::INET->new(
959 960 961 962 963 964 965 966
	PeerAddr => $proxy_host,
	PeerPort => $proxy_port,
	Proto => "tcp"
);

if (! $sock) {
	my $err = $!;
	unlink($0) if $ENV{PPROXY_REMOVE};
967
	pdie "pproxy: $err\n";
968 969
}

970 971
unlink($0) if $ENV{PPROXY_REMOVE};

972
if ($ENV{PPROXY_PROXY} =~ /^vencrypt:/ && $ENV{PPROXY_LISTEN} =~ /^INADDR_ANY:/) {
973
	print STDERR "\nPPROXY: vencrypt+reverse: swapping listen socket with connect socket.\n";
974 975 976 977 978
	my $tmp_swap = $sock;
	$sock = $listen_handle;
	$listen_handle = $tmp_swap;
}

979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999
$cur_proxy = $first;
setmode($mode_1st);

if ($second ne "") {
	connection($second, 1);

	setmode($mode_2nd);
	$cur_proxy = $second;

	if ($third ne "") {
		connection($third, 2);
		setmode($mode_3rd);
		$cur_proxy = $third;
		connection($connect, 3);
	} else {
		connection($connect, 2);
	}
} else {
	connection($connect, 1);
}

1000 1001 1002 1003
sub kill_proxy_pids() {
	if ($ENV{PPROXY_VENCRYPT_VIEWER_BRIDGE}) {
		return;
	}
1004 1005 1006 1007 1008
	if ($ENV{PPROXY_KILLPID}) {
		foreach my $p (split(/,/, $ENV{PPROXY_KILLPID})) {
			if ($p =~ /^(\+|-)/) {
				$p = $parent + $p;
			}
1009
			print STDERR "kill TERM, $p (PPROXY_KILLPID)\n";
1010 1011 1012
			kill "TERM", $p;
		}
	}
1013 1014
}

1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049
sub xfer {
	my($in, $out) = @_;
	$RIN = $WIN = $EIN = "";
	$ROUT = "";
	vec($RIN, fileno($in), 1) = 1;
	vec($WIN, fileno($in), 1) = 1;
	$EIN = $RIN | $WIN;

	while (1) {
		my $nf = 0;
		while (! $nf) {
			$nf = select($ROUT=$RIN, undef, undef, undef);
		}
		my $len = sysread($in, $buf, 8192);
		if (! defined($len)) {
			next if $! =~ /^Interrupted/;
			print STDERR "pproxy[$$]: $!\n";
			last;
		} elsif ($len == 0) {
			print STDERR "pproxy[$$]: Input is EOF.\n";
			last;
		}
		my $offset = 0;
		my $quit = 0;
		while ($len) {
			my $written = syswrite($out, $buf, $len, $offset);
			if (! defined $written) {
				print STDERR "pproxy[$$]: Output is EOF. $!\n";
				$quit = 1;
				last;
			}
			$len -= $written;
			$offset += $written;
		}
		last if $quit;
1050
	}
1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068
	close($out);
	close($in);
	print STDERR "pproxy[$$]: finished xfer.\n";
}

sub handler {
	print STDERR "pproxy[$$]: got SIGTERM.\n";
	close $listen_handle if $listen_handle;
	close $sock if $sock;
	exit;
}

sub xfer_both {
	$child = fork;

	if (! defined $child) {
		kill_proxy_pids();
		exit 1;
1069
	}
1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090

	$SIG{TERM} = "handler";

	if ($child) {
		if ($listen_handle) {
			print STDERR "pproxy parent[$$]  listen_handle -> socket\n";
			xfer($listen_handle, $sock);
		} else {
			print STDERR "pproxy parent[$$]  STDIN -> socket\n";
			xfer(STDIN, $sock);
		}
		select(undef, undef, undef, 0.25);
		if (kill 0, $child) {
			select(undef, undef, undef, 0.9);
			if (kill 0, $child) {
				print STDERR "pproxy[$$]: kill TERM child $child\n";
				kill "TERM", $child;
			} else {
				print STDERR "pproxy[$$]: child  $child gone.\n";
			}
		}
1091
	} else {
1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107
		select(undef, undef, undef, 0.05);
		if ($listen_handle) {
			print STDERR "pproxy child [$$]  socket -> listen_handle\n\n";
			xfer($sock, $listen_handle);
		} else {
			print STDERR "pproxy child [$$]  socket -> STDOUT\n\n";
			xfer($sock, STDOUT);
		}
		select(undef, undef, undef, 0.25);
		if (kill 0, $parent) {
			select(undef, undef, undef, 0.8);
			if (kill 0, $parent) {
				print STDERR "pproxy[$$]: kill TERM parent $parent\n";
				kill "TERM", $parent;
			} else {
				print STDERR "pproxy[$$]: parent $parent gone.\n";
1108 1109
			}
		}
1110
	}
1111 1112

	kill_proxy_pids();
1113
}
1114 1115 1116

xfer_both();

1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137
exit;

sub url_parse {
	my $hostport = shift;
	my $mode = "http";
	if ($hostport =~ m,^socks4?://(\S*)$,i) {
		$mode = "socks4";
		$hostport = $1;
	} elsif ($hostport =~ m,^socks5://(\S*)$,i) {
		$mode = "socks5";
		$hostport = $1;
	} elsif ($hostport =~ m,^https?://(\S*)$,i) {
		$mode = "http";
		$hostport = $1;
	} elsif ($hostport =~ m,^repeater://(\S*)\+(\S*)$,i) {
		# ultravnc repeater proxy.
		$hostport = $1;
		$mode = "repeater:$2";
		if ($hostport !~ /:\d+/) {
			$hostport .= ":5900";
		}
runge's avatar
runge committed
1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149
	} elsif ($hostport =~ m,^vencrypt://(\S*)$,i) {
		# vencrypt handshake.
		$hostport = $1;
		my $m = "connect";
		if ($hostpost =~ /^(\S+)\+(\S+)$/) {
			$hostport = $1;
			$mode = $2;
		}
		$mode = "vencrypt:$m";
		if ($hostport !~ /:\d+/) {
			$hostport .= ":5900";
		}
1150 1151 1152 1153 1154 1155 1156
	}
	return ($hostport, $mode);
}

sub setmode {
	my $mode = shift;
	$ENV{PPROXY_REPEATER} = "";
runge's avatar
runge committed
1157
	$ENV{PPROXY_VENCRYPT} = "";
1158 1159 1160 1161 1162 1163 1164 1165 1166
	if ($mode =~ /^socks/) {
		if ($mode =~ /^socks5/) {
			$ENV{PPROXY_SOCKS} = 5;
		} else {
			$ENV{PPROXY_SOCKS} = 1;
		}
	} elsif ($mode =~ /^repeater:(.*)/) {
		$ENV{PPROXY_REPEATER} = $1;
		$ENV{PPROXY_SOCKS} = "";
runge's avatar
runge committed
1167 1168 1169
	} elsif ($mode =~ /^vencrypt:(.*)/) {
		$ENV{PPROXY_VENCRYPT} = $1;
		$ENV{PPROXY_SOCKS} = "";
1170 1171 1172 1173 1174
	} else {
		$ENV{PPROXY_SOCKS} = "";
	}
}

1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298
sub connection {
	my ($CONNECT, $w) = @_;

	my $con = "";
	my $msg = "";

	if ($ENV{PPROXY_SOCKS} eq "5") {
		# SOCKS5
		my ($h, $p) = split(/:/, $CONNECT);
		$con .= pack("C", 0x05);
		$con .= pack("C", 0x01);
		$con .= pack("C", 0x00);

		$msg = "SOCKS5 via $cur_proxy to $h:$p\n\n";
		print STDERR "proxy_request$w: $msg";

		syswrite($sock, $con, length($con));

		my ($n1, $n2, $n3, $n4, $n5, $n6);
		my ($r1, $r2, $r3, $r4, $r5, $r6);
		my ($s1, $s2, $s3, $s4, $s5, $s6);

		$n1 = sysread($sock, $r1, 1);
		$n2 = sysread($sock, $r2, 1);

		$s1 = unpack("C", $r1);
		$s2 = unpack("C", $r2);
		if ($s1 != 0x05 || $s2 != 0x00) {
			print STDERR "SOCKS5 fail s1=$s1 s2=$s2 n1=$n1 n2=$n2\n";
			close $sock;
			exit(1);
		}

		$con = "";
		$con .= pack("C", 0x05);
		$con .= pack("C", 0x01);
		$con .= pack("C", 0x00);
		$con .= pack("C", 0x03);
		$con .= pack("C", length($h));
		$con .= $h;
		$con .= pack("C", $p >> 8);
		$con .= pack("C", $p & 0xff);

		syswrite($sock, $con, length($con));

		$n1 = sysread($sock, $r1, 1);
		$n2 = sysread($sock, $r2, 1);
		$n3 = sysread($sock, $r3, 1);
		$n4 = sysread($sock, $r4, 1);
		$s1 = unpack("C", $r1);
		$s2 = unpack("C", $r2);
		$s3 = unpack("C", $r3);
		$s4 = unpack("C", $r4);

		if ($s4 == 0x1) {
			sysread($sock, $r5, 4 + 2);
		} elsif ($s4 == 0x3) {
			sysread($sock, $r5, 1);
			$s5 = unpack("C", $r5);
			sysread($sock, $r6, $s5 + 2);
		} elsif ($s4 == 0x4) {
			sysread($sock, $r5, 16 + 2);
		}

		if ($s1 != 0x5 || $s2 != 0x0 || $s3 != 0x0) {
			print STDERR "SOCKS5 failed: s1=$s1 s2=$s2 s3=$s3 s4=$s4 n1=$n1 n2=$n2 n3=$n3 n4=$n4\n";
			close $sock;
			exit(1);
		}

	} elsif ($ENV{PPROXY_SOCKS} ne "") {
		# SOCKS4 SOCKS4a
		my ($h, $p) = split(/:/, $CONNECT);
		$con .= pack("C", 0x04);
		$con .= pack("C", 0x01);
		$con .= pack("n", $p);

		my $SOCKS_4a = 0;
		if ($h eq "localhost" || $h eq "127.0.0.1") {
			$con .= pack("C", 127);
			$con .= pack("C", 0);
			$con .= pack("C", 0);
			$con .= pack("C", 1);
		} elsif ($h =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) {
			$con .= pack("C", $1);
			$con .= pack("C", $2);
			$con .= pack("C", $3);
			$con .= pack("C", $4);
		} else {
			$con .= pack("C", 0);
			$con .= pack("C", 0);
			$con .= pack("C", 0);
			$con .= pack("C", 3);
			$SOCKS_4a = 1;
		}

		$con .= "nobody";
		$con .= pack("C", 0);

		$msg = "SOCKS4 via $cur_proxy to $h:$p\n\n";
		if ($SOCKS_4a) {
			$con .= $h;
			$con .= pack("C", 0);
			$msg =~ s/SOCKS4/SOCKS4a/;
		}
		print STDERR "proxy_request$w: $msg";
		syswrite($sock, $con, length($con));

		my $ok = 1;
		for (my $i = 0; $i < 8; $i++) {
			my $c;
			sysread($sock, $c, 1);
			my $s = unpack("C", $c);
			if ($i == 0) {
				$ok = 0 if $s != 0x0;
			} elsif ($i == 1) {
				$ok = 0 if $s != 0x5a;
			}
		}
		if (! $ok) {
			print STDERR "SOCKS4 failed.\n";
			close $sock;
			exit(1);
		}
1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310
	} elsif ($ENV{PPROXY_REPEATER} ne "") {
		my $rep = $ENV{PPROXY_REPEATER};
		print STDERR "repeater: $rep\n";
		$rep .= pack("x") x 250;
		syswrite($sock, $rep, 250);

		my $ok = 1;
		for (my $i = 0; $i < 12; $i++) {
			my $c;
			sysread($sock, $c, 1);
			print STDERR $c;
		}
runge's avatar
runge committed
1311 1312 1313
	} elsif ($ENV{PPROXY_VENCRYPT} ne "") {
		my $vencrypt = $ENV{PPROXY_VENCRYPT};
		vencrypt_dialog($vencrypt);
1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341

	} else {
		# Web Proxy:
		$con = "CONNECT $CONNECT HTTP/1.1\r\n";
		$con   .= "Host: $CONNECT\r\n";
		$con   .= "Connection: close\r\n\r\n";
		$msg = $con;

		print STDERR "proxy_request$w: via $cur_proxy:\n$msg";
		syswrite($sock, $con, length($con));

		my $rep = "";
		my $n = 0;
		while ($rep !~ /\r\n\r\n/ && $n < 30000) {
			my $c;
			sysread($sock, $c, 1);
			print STDERR $c;
			$rep .= $c;
			$n++;
		}
		if ($rep !~ m,HTTP/.* 200,) {
			print STDERR "HTTP CONNECT failed.\n";
			close $sock;
			exit(1);
		}
	}
}

runge's avatar
runge committed
1342 1343 1344
sub vdie {
	append_handshake("done\n");
	close $sock;
1345
	kill_proxy_pids();
runge's avatar
runge committed
1346 1347 1348
	exit(1);
}

1349
sub anontls_handshake {
runge's avatar
runge committed
1350 1351
	my ($vmode, $db) = @_;

1352
	print STDERR "\nPPROXY: Doing ANONTLS Handshake\n";
runge's avatar
runge committed
1353

1354
	my $psec = pack("C", $rfbSecTypeAnonTls);
runge's avatar
runge committed
1355 1356 1357 1358 1359 1360 1361 1362 1363
	syswrite($sock, $psec, 1);

	append_handshake("done\n");
}

sub vencrypt_handshake {
	
	my ($vmode, $db) = @_;

1364
	print STDERR "\nPPROXY: Doing VeNCrypt Handshake\n";
runge's avatar
runge committed
1365 1366

	my $psec = pack("C", $rfbSecTypeVencrypt);
1367 1368 1369 1370 1371 1372 1373

	if (exists $ENV{SSVNC_TEST_SEC_TYPE}) {
		my $fake = $ENV{SSVNC_TEST_SEC_TYPE};
		print STDERR "PPROXY: sending sec-type: $fake\n";
		$psec = pack("C", $fake);
	}

runge's avatar
runge committed
1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384
	syswrite($sock, $psec, 1);

	my $vmajor;
	my $vminor;
	sysread($sock, $vmajor, 1);
	sysread($sock, $vminor, 1);

	vdie if $vmajor eq "" || $vminor eq "";

	$vmajor = unpack("C", $vmajor);
	$vminor = unpack("C", $vminor);
1385
	print STDERR "server vencrypt version $vmajor.$vminor\n" if $db;
runge's avatar
runge committed
1386

1387 1388 1389 1390 1391 1392
	if (exists $ENV{SSVNC_TEST_SEC_TYPE}) {
		print STDERR "PPROXY: continuing on in test mode.\n";
	} else {
		vdie if $vmajor ne 0;
		vdie if $vminor < 2;
	}
runge's avatar
runge committed
1393 1394 1395 1396 1397 1398 1399 1400 1401 1402

	$vmajor = pack("C", 0);
	$vminor = pack("C", 2);
	append_handshake("subversion=0.2\n");

	syswrite($sock, $vmajor, 1);
	syswrite($sock, $vminor, 1);

	my $result;
	sysread($sock, $result, 1);
1403
	print STDERR "result empty\n" if $db && $result eq "";
runge's avatar
runge committed
1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451

	vdie if $result eq "";
	$result = unpack("C", $result);
	print STDERR "result=$result\n" if $db;

	vdie if $result ne 0;

	my $nsubtypes;
	sysread($sock, $nsubtypes, 1);

	vdie if $nsubtypes eq "";
	$nsubtypes = unpack("C", $nsubtypes);
	print STDERR "nsubtypes=$nsubtypes\n" if $db;

	my %subtypes;

	for (my $i = 0; $i < $nsubtypes; $i++) {
		my $subtype = ""; 
		sysread($sock, $subtype, 4);
		vdie if length($subtype) != 4;

		# XXX fix 64bit.
		$subtype = unpack("N", $subtype);
		print STDERR "subtype: $subtype\n" if $db;
		$subtypes{$subtype} = 1;
		append_handshake("sst$i=$subtype\n");
	}

	my $subtype = 0;
	if (exists $subtypes{$rfbVencryptX509None})  {
		$subtype = $rfbVencryptX509None;
		print STDERR "selected rfbVencryptX509None\n" if $db;
	} elsif (exists $subtypes{$rfbVencryptX509Vnc})  {
		$subtype = $rfbVencryptX509Vnc;
		print STDERR "selected rfbVencryptX509Vnc\n" if $db;
	} elsif (exists $subtypes{$rfbVencryptX509Plain})  {
		$subtype = $rfbVencryptX509Plain;
		print STDERR "selected rfbVencryptX509Plain\n" if $db;
	} elsif (exists $subtypes{$rfbVencryptTlsNone})  {
		$subtype = $rfbVencryptTlsNone;
		print STDERR "selected rfbVencryptTlsNone\n" if $db;
	} elsif (exists $subtypes{$rfbVencryptTlsVnc})  {
		$subtype = $rfbVencryptTlsVnc;
		print STDERR "selected rfbVencryptTlsVnc\n" if $db;
	} elsif (exists $subtypes{$rfbVencryptTlsPlain})  {
		$subtype = $rfbVencryptTlsPlain;
		print STDERR "selected rfbVencryptTlsPlain\n" if $db;
	}
1452 1453 1454 1455 1456 1457 1458

	if (exists $ENV{SSVNC_TEST_SEC_SUBTYPE}) {
		my $fake = $ENV{SSVNC_TEST_SEC_SUBTYPE};
		print STDERR "PPROXY: sending sec-subtype: $fake\n";
		$subtype = $fake;
	}

runge's avatar
runge committed
1459 1460 1461 1462 1463
	append_handshake("subtype=$subtype\n");

	my $pst = pack("N", $subtype);
	syswrite($sock, $pst, 4); 

1464 1465 1466 1467 1468
	if (exists $ENV{SSVNC_TEST_SEC_SUBTYPE}) {
		print STDERR "PPROXY: continuing on in test mode.\n";
	} else {
		vdie if $subtype == 0;
	}
runge's avatar
runge committed
1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484

	my $ok;
	sysread($sock, $ok, 1);
	$ok = unpack("C", $ok);
	print STDERR "ok=$ok\n" if $db;

	append_handshake("done\n");

	vdie if $ok == 0;
}

sub vencrypt_dialog {
	my $vmode = shift;
	my $db = 0;

	$db = 1 if exists $ENV{SS_DEBUG};
1485
	$db = 1 if exists $ENV{SSVNC_VENCRYPT_DEBUG};
runge's avatar
runge committed
1486 1487 1488 1489

	append_handshake("mode=$vmode\n");

	my $server_rfb = "";
1490
	#syswrite($sock, $rep, 250);
runge's avatar
runge committed
1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512
	for (my $i = 0; $i < 12; $i++) {
		my $c;
		sysread($sock, $c, 1);
		$server_rfb .= $c;
		print STDERR $c;
	}
	print STDERR "server_rfb: $server_rfb\n" if $db;
	append_handshake("server=$server_rfb");

	my $minor = "";
	if ($server_rfb =~ /^RFB 003\.(\d+)/) {
		$minor = $1;
	} else {
		vdie;
	}
	my $viewer_rfb = "RFB 003.008\n";
	if ($minor < 7) {
		vdie;
	} elsif ($minor == 7) {
		$viewer_rfb = "RFB 003.007\n";
	}
	my $nsec;
1513 1514
	my $t1 = gettime();
	my $t0 = gettime();
runge's avatar
runge committed
1515

1516
	syswrite($sock, $viewer_rfb, 12);
runge's avatar
runge committed
1517
	sysread($sock, $nsec, 1);
1518 1519 1520 1521 1522 1523 1524

	$t1 = gettime();
	$t1 = sprintf("%.6f", $t1 - $t0);

	append_handshake("viewer=$viewer_rfb");
	append_handshake("latency=$t1\n");

runge's avatar
runge committed
1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546
	vdie if $nsec eq "";

	$nsec = unpack("C", $nsec);

	print STDERR "nsec: $nsec\n" if $db;
	vdie if $nsec eq 0 || $nsec > 100;

	my %sectypes = ();

	for (my $i = 0; $i < $nsec; $i++) {
		my $sec;
		sysread($sock, $sec, 1);
		vdie if $sec eq "";
		$sec = unpack("C", $sec);
		print STDERR "sec: $sec\n" if $db;
		$sectypes{$sec} = 1;
	}
	
	if (exists $sectypes{$rfbSecTypeVencrypt}) {
		print STDERR "found rfbSecTypeVencrypt\n" if $db;
		append_handshake("sectype=$rfbSecTypeVencrypt\n");
		vencrypt_handshake($vmode, $db);
1547 1548 1549 1550
	} elsif (exists $sectypes{$rfbSecTypeAnonTls}) {
		print STDERR "found rfbSecTypeAnonTls\n" if $db;
		append_handshake("sectype=$rfbSecTypeAnonTls\n");
		anontls_handshake($vmode, $db);
runge's avatar
runge committed
1551 1552 1553 1554 1555 1556
	} else {
		print STDERR "No supported sec-type found\n" if $db;
		vdie;
	}
}

1557 1558 1559 1560 1561 1562
sub append_handshake {
	my $str = shift;
	if ($handshake_file) {
		if (open(HSF, ">>$handshake_file")) {
			print HSF $str;
			close HSF;
1563
		}
1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595
	}
}

sub do_vencrypt_viewer_bridge {
	my ($listen, $connect) = @_;
	print STDERR "\npproxy: starting vencrypt_viewer_bridge[$$]: $listen \-> $connect\n";
	my $db = 0;
	my $backwards = 0;
	if ($listen < 0) {
		$backwards = 1;
		$listen = -$listen;
	}
	if ($handshake_file eq "") {
		die "pproxy: vencrypt_viewer_bridge[$$]: no SSVNC_PREDIGESTED_HANDSHAKE\n";
	}
	my $listen_sock;
	my $maxtry = 12;
	my $sleep = 5;
	for (my $i=0; $i < $maxtry; $i++)  {
		$listen_sock = IO::Socket::INET->new(
			Listen    => 2,
			LocalAddr => "127.0.0.1",
			LocalPort => $listen,
			Proto     => "tcp"
		);
		if (! $listen_sock) {
			if ($i < $maxtry - 1) {
				warn "pproxy: vencrypt_viewer_bridge[$$]: $!\n";
				warn "Could not listen on port $listen, retrying in $sleep seconds... (Ctrl-C to quit)\n";
				sleep $sleep;
			}
		} else {
1596 1597
			last;
		}
1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655
	}
	if (! $listen_sock) {
		die "pproxy: vencrypt_viewer_bridge[$$]: $!\n";
	}
	print STDERR "pproxy: vencrypt_viewer_bridge[$$]: listening on port $listen\n\n";
	my ($viewer_sock, $ip) = $listen_sock->accept();
	my $err = $!;
	close $listen_sock;
	if (! $viewer_sock) {
		die "pproxy: vencrypt_viewer_bridge[$$]: $err\n";
	}
	print STDERR "vencrypt_viewer_bridge[$$]: viewer_sock $viewer_sock\n" if $db;

	print STDERR "pproxy: vencrypt_viewer_bridge[$$]: connecting to 127.0.0.1:$connect\n";
	my $server_sock = IO::Socket::INET->new(
		PeerAddr => "127.0.0.1",
		PeerPort => $connect,
		Proto => "tcp"
	);
	print STDERR "vencrypt_viewer_bridge[$$]: server_sock $server_sock\n" if $db;
	if (! $server_sock) {
		my $err = $!;
		die "pproxy: vencrypt_viewer_bridge[$$]: $err\n";
	}

	if ($backwards) {
		print STDERR "vencrypt_viewer_bridge[$$]: reversing roles of viewer and server.\n";
		my $t = $viewer_sock;
		$viewer_sock = $server_sock;
		$server_sock = $t;
	}

	my %hs = ();
	my $dt = 0.2;
	my $slept = 0.0;
	while ($slept < 20.0) {
		select(undef, undef, undef, $dt);
		$slept += $dt;
		if (-f $handshake_file && open(HSF, "<$handshake_file")) {
			my $done = 0;
			%hs = ();
			my $str = "";
			while (<HSF>) {
				print STDERR "vencrypt_viewer_bridge[$$]: $_" if $ENV{VENCRYPT_VIEWER_BRIDGE_DEBUG};
				$str .= "vencrypt_viewer_bridge[$$]: $_";
				chomp;
				if ($_ eq "done") {
					$done = 1;
				} else {
					my ($k, $v) = split(/=/, $_, 2);
					if ($k ne "" && $v ne "") {
						$hs{$k} = $v;
					}
				}
			}
			close HSF;
			if ($done) {
				print STDERR "\n" . $str;
1656 1657 1658 1659
				last;
			}
		}
	}
1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957
	if (! exists $hs{server}) {
		$hs{server} = "RFB 003.008";
	}
	if (! exists $hs{sectype}) {
		unlink($handshake_file);
		die "pproxy: vencrypt_viewer_bridge[$$]: no sectype.\n";
	}
	syswrite($viewer_sock, "$hs{server}\n", length($hs{server}) + 1);
	my $viewer_rfb = "";
	for (my $i = 0; $i < 12; $i++) {
		my $c;
		sysread($viewer_sock, $c, 1);
		$viewer_rfb .= $c;
		print STDERR $c;
	}
	my $viewer_major = 3;
	my $viewer_minor = 8;
	if ($viewer_rfb =~ /RFB (\d+)\.(\d+)/) {
		$viewer_major = $1;	
		$viewer_minor = $2;	
	}
	my $u0 = pack("C", 0);
	my $u1 = pack("C", 1);
	my $u2 = pack("C", 2);
	if ($hs{sectype} == $rfbSecTypeAnonTls) {
		unlink($handshake_file);
		print STDERR "\npproxy: vencrypt_viewer_bridge[$$]: rfbSecTypeAnonTls\n";
		if ($viewer_major > 3 || $viewer_minor >= 7) {
			;	# setup ok, proceed to xfer.
		} else {
			print STDERR "pproxy: vencrypt_viewer_bridge[$$]: faking RFB version 3.3 to viewer.\n";
			my $n;
			sysread($server_sock, $n, 1);
			$n = unpack("C", $n);
			if ($n == 0) {
				die "pproxy: vencrypt_viewer_bridge[$$]: nsectypes == $n.\n";
			}
			my %types;
			for (my $i = 0; $i < $n; $i++) {
				my $t;
				sysread($server_sock, $t, 1);
				$t = unpack("C", $t);
				$types{$t} = 1;
			}
			my $use = 1;	# None
			if (exists $types{1}) {
				$use = 1;	# None
			} elsif (exists $types{2}) {
				$use = 2;	# VncAuth
			} else {
				die "pproxy: vencrypt_viewer_bridge[$$]: no valid sectypes" . join(",", keys %types) . "\n";
			}
				
			# send 4 bytes sectype to viewer: 
			# (note this should be MSB, network byte order...)
			my $up = pack("C", $use);
			syswrite($viewer_sock, $u0, 1);
			syswrite($viewer_sock, $u0, 1);
			syswrite($viewer_sock, $u0, 1);
			syswrite($viewer_sock, $up, 1);
			# and tell server the one we selected:
			syswrite($server_sock, $up, 1);
			if ($use == 1) {
				# even None has security result, so read it here and discard it.
				my $sr = "";
				sysread($server_sock, $sr, 4);
			}
		}
	} elsif ($hs{sectype} == $rfbSecTypeVencrypt) {
		print STDERR "\npproxy: vencrypt_viewer_bridge[$$]: rfbSecTypeVencrypt\n";
		if (! exists $hs{subtype}) {
			unlink($handshake_file);
			die "pproxy: vencrypt_viewer_bridge[$$]: no subtype.\n";
		}
		my $fake_type = "None";
		my $plain = 0;
		my $sub_type = $hs{subtype};
		if ($sub_type == $rfbVencryptTlsNone) {
			$fake_type = "None";
		} elsif ($sub_type == $rfbVencryptTlsVnc) {
			$fake_type = "VncAuth";
		} elsif ($sub_type == $rfbVencryptTlsPlain) {
			$fake_type = "None";
			$plain = 1;
		} elsif ($sub_type == $rfbVencryptX509None) {
			$fake_type = "None";
		} elsif ($sub_type == $rfbVencryptX509Vnc) {
			$fake_type = "VncAuth";
		} elsif ($sub_type == $rfbVencryptX509Plain) {
			$fake_type = "None";
			$plain = 1;
		}
		if ($plain) {
			if (!open(W, ">$handshake_file")) {
				unlink($handshake_file);
				die "pproxy: vencrypt_viewer_bridge[$$]: $handshake_file $!\n";
			}
			print W <<"END";

			proc print_out {} {
				global user pass env

				if [info exists env(SSVNC_UP_DEBUG)] {
					toplevel .b
					button .b.b -text "user=\$user pass=\$pass" -command {destroy .b}
					pack .b.b
					update
					tkwait window .b
				}
				
				if [info exists env(SSVNC_UP_FILE)] {
					set fh "" 
					catch {set fh [open \$env(SSVNC_UP_FILE) w]}
					if {\$fh != ""} {
						puts \$fh user=\$user\\npass=\$pass
						flush \$fh
						close \$fh
						return
					}
				}
				puts stdout user=\$user\\npass=\$pass
				flush stdout
			}

			proc center_win {w} {
				update
				set W [winfo screenwidth  \$w]
				set W [expr \$W + 1]
				wm geometry \$w +\$W+0
				update
				set x [expr [winfo screenwidth  \$w]/2 - [winfo width  \$w]/2]
				set y [expr [winfo screenheight \$w]/2 - [winfo height \$w]/2]

				wm geometry \$w +\$x+\$y
				wm deiconify \$w
				update
			}

			wm withdraw .

			global env
			set up {}
			if [info exists env(SSVNC_UNIXPW)] {
				set rm 0
				set up \$env(SSVNC_UNIXPW)
				if [regexp {^rm:} \$up]  {
					set rm 1
					regsub {^rm:} \$up {} up
				}
				if [file exists \$up] {
					set fh ""
					set f \$up
					catch {set fh [open \$up r]}
					if {\$fh != ""} {
						gets \$fh u	
						gets \$fh p	
						close \$fh
						set up "\$u@\$p"
					}
					if {\$rm} {
						catch {file delete \$f}
					}
				}
			} elseif [info exists env(SSVNC_VENCRYPT_USERPASS)] {
				set up \$env(SSVNC_VENCRYPT_USERPASS)
			}
			#puts stderr up=\$up
			if {\$up != ""} {
				if [regexp {@} \$up] {
					global user pass
					set user \$up
					set pass \$up
					regsub {@.*\$}  \$user "" user
					regsub {^[^@]*@} \$pass "" pass
					print_out
					exit
				}
			}

			wm title . {VeNCrypt Viewer Bridge User/Pass}

			set user {}
			set pass {}

			label .l -text {SSVNC VeNCrypt Viewer Bridge}

			frame .f0
			frame .f0.fL
			label .f0.fL.la -text {Username: }
			label .f0.fL.lb -text {Password: }

			pack .f0.fL.la .f0.fL.lb -side top

			frame .f0.fR
			entry .f0.fR.ea -width 24 -textvariable user
			entry .f0.fR.eb -width 24 -textvariable pass -show *

			pack .f0.fR.ea .f0.fR.eb -side top -fill x

			pack .f0.fL -side left
			pack .f0.fR -side right -expand 1 -fill x

			button .no -text Cancel -command {destroy .}
			button .ok -text Done   -command {print_out; destroy .}

			center_win .
			pack .l .f0 .no .ok -side top -fill x
			update
			wm deiconify .

			bind .f0.fR.ea <Return> {focus .f0.fR.eb}
			bind .f0.fR.eb <Return> {print_out; destroy .}
			focus .f0.fR.ea

			wm resizable . 1 0
			wm minsize . [winfo reqwidth .] [winfo reqheight .]
END
			close W;

			#system("cat $handshake_file");
			my $w = "wish";
			if ($ENV{WISH}) {
				$w = $ENV{WISH};	
			}
			print STDERR "pproxy: vencrypt_viewer_bridge[$$]: prompt  VencryptPlain user and passwd.\n";
			my $res = "";
			if (`uname` =~ /Darwin/) {
				my $mtmp = `mktemp /tmp/hsup.XXXXXX`;
				chomp $mtmp;
				system("env SSVNC_UP_FILE=$mtmp $w $handshake_file");
				$res = `cat $mtmp`;
				unlink $mtmp;
			} else {
				$res = `$w $handshake_file`;
			}
			my $user = "";
			my $pass = "";
			if ($res =~ /user=(\S*)/) {
				$user = $1;
			}
			if ($res =~ /pass=(\S*)/) {
				$pass = $1;
			}
			print STDERR "pproxy: vencrypt_viewer_bridge[$$]: sending VencryptPlain user and passwd.\n";
			my $ulen = pack("C", length($user));
			my $plen = pack("C", length($pass));
			# (note this should be MSB, network byte order...)
			syswrite($server_sock, $u0, 1);
			syswrite($server_sock, $u0, 1);
			syswrite($server_sock, $u0, 1);
			syswrite($server_sock, $ulen, 1);
			syswrite($server_sock, $u0, 1);
			syswrite($server_sock, $u0, 1);
			syswrite($server_sock, $u0, 1);
			syswrite($server_sock, $plen, 1);
			syswrite($server_sock, $user, length($user));
			syswrite($server_sock, $pass, length($pass));
		}
		unlink($handshake_file);

		my $ft = 0;
		if ($fake_type eq "None") {
			$ft = 1;
		} elsif ($fake_type eq "VncAuth") {
			$ft = 2;
		} else {
			die "pproxy: vencrypt_viewer_bridge[$$]: unknown fake type: $fake_type\n";
		}
		my $fp = pack("C", $ft);
		if ($viewer_major > 3 || $viewer_minor >= 7) {
			syswrite($viewer_sock, $u1, 1);
			syswrite($viewer_sock, $fp, 1);
			my $cr;
			sysread($viewer_sock, $cr, 1);
			$cr = unpack("C", $cr);
			if ($cr != $ft) {
				die "pproxy: vencrypt_viewer_bridge[$$]: client selected wrong type: $cr / $ft\n";
			}
		} else {
			print STDERR "pproxy: vencrypt_viewer_bridge[$$]: faking RFB version 3.3 to viewer.\n";
			# send 4 bytes sect type to viewer: 
			# (note this should be MSB, network byte order...)
			syswrite($viewer_sock, $u0, 1);
			syswrite($viewer_sock, $u0, 1);
			syswrite($viewer_sock, $u0, 1);
			syswrite($viewer_sock, $fp, 1);
			if ($ft == 1) {
				# even None has security result, so read it here and discard it.
				my $sr = "";
				sysread($server_sock, $sr, 4);
			}
		}
	}

	$listen_handle = $viewer_sock;
	$sock = $server_sock;

	xfer_both();
1958 1959
}
'
1960
	# '
runge's avatar
runge committed
1961 1962
	# xpg_echo will expand \n \r, etc.
	# try to unset and then test for it.
1963 1964 1965
	if type shopt > /dev/null 2>&1; then
		shopt -u xpg_echo >/dev/null 2>&1
	fi
runge's avatar
runge committed
1966 1967
	v='print STDOUT "abc\n";'
	echo "$v" > $tf
1968
	chmod 700 $tf
runge's avatar
runge committed
1969 1970 1971 1972 1973 1974 1975 1976

	lc=`wc -l $tf | awk '{print $1}'`
	if [ "X$lc" = "X1" ]; then
		echo "$cod" > $tf
	else
		printf "%s" "$cod" > $tf
		echo "" >> $tf
	fi
1977 1978 1979 1980
	# prime perl
	perl -e 'use IO::Socket::INET; select(undef, undef, undef, 0.01)' >/dev/null 2>&1
}

1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041
# make_tcert is no longer invoked via the ssvnc gui (Listen mode).
# make_tcert is for testing only now via -mycert BUILTIN
make_tcert() {
	tcert="/tmp/ss_vnc_viewer_tcert${RANDOM}.$$"
	tcert=`mytmp "$tcert"`
	cat > $tcert <<END
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAvkfXxb0wcxgrjV2ziFikjII+ze8iKcTBt47L0GM/c21efelN
+zZpJUUXLu4zz8Ryq8Q+sQgfNy7uTOpN9bUUaOk1TnD7gaDQnQWiNHmqbW2kL+DS
OKngJVPo9dETAS8hf7+D1e1DBZxjTc1a4RQqWJixwpYj99ixWzu8VC2m/xXsjvOs
jp4+DLBB490nbkwvstmhmiWm1CmI5O5xOkgioVNQqHvQMdVKOSz9PpbjvZiRX1Uo
qoMrk+2NOqwP90TB35yPASXb9zXKpO7DLhkube+yYGf+yk46aD707L07Eb7cosFP
S84vNZ9gX7rQ0UOwm5rYA/oZTBskgaqhtIzkLwIDAQABAoIBAD4ot/sXt5kRn0Ca
CIkU9AQWlC+v28grR2EQW9JiaZrqcoDNUzUqbCTJsi4ZkIFh2lf0TsqELbZYNW6Y
6AjJM7al4E0UqYSKJTv2WCuuRxdiRs2BMwthqyBmjeanev7bB6V0ybt7u3Y8xU/o
MrTuYnr4vrEjXPKdLirwk7AoDbKsRXHSIiHEIBOq1+dUQ32t36ukdnnza4wKDLZc
PKHiCdCk/wOGhuDlxD6RspqUAlRnJ8/aEhrgWxadFXw1hRhRsf/v1shtB0T3DmTe
Jchjwyiw9mryb9JZAcKxW+fUc4EVvj6VdQGqYInQJY5Yxm5JAlVQUJicuuJEvn6A
rj5osQECgYEA552CaHpUiFlB4HGkjaH00kL+f0+gRF4PANCPk6X3UPDVYzKnzmuu
yDvIdEETGFWBwoztUrOOKqVvPEQ+kBa2+DWWYaERZLtg2cI5byfDJxQ3ldzilS3J
1S3WgCojqcsG/hlxoQJ1dZFanUy/QhUZ0B+wlC+Zp1Q8AyuGQvhHp68CgYEA0lBI
eqq2GGCdJuNHMPFbi8Q0BnX55LW5C1hWjhuYiEkb3hOaIJuJrqvayBlhcQa2cGqp
uP34e9UCfoeLgmoCQ0b4KpL2NGov/mL4i8bMgog4hcoYuIi3qxN18vVR14VKEh4U
RLk0igAYPU+IK2QByaQlBo9OSaKkcfm7U1/pK4ECgYAxr6VpGk0GDvfF2Tsusv6d
GIgV8ZP09qSLTTJvvxvF/lQYeqZq7sjI5aJD5i3de4JhpO/IXQJzfZfWOuGc8XKA
3qYK/Y2IqXXGYRcHFGWV/Y1LFd55mCADHlk0l1WdOBOg8P5iRu/Br9PbiLpCx9oI
vrOXpnp03eod1/luZmqguwKBgQCWFRSj9Q7ddpSvG6HCG3ro0qsNsUMTI1tZ7UBX
SPogx4tLf1GN03D9ZUZLZVFUByZKMtPLX/Hi7K9K/A9ikaPrvsl6GEX6QYzeTGJx
3Pw0amFrmDzr8ySewNR6/PXahxPEuhJcuI31rPufRRI3ZLah3rFNbRbBFX+klkJH
zTnoAQKBgDbUK/aQFGduSy7WUT7LlM3UlGxJ2sA90TQh4JRQwzur0ACN5GdYZkqM
YBts4sBJVwwJoxD9OpbvKu3uKCt41BSj0/KyoBzjT44S2io2tj1syujtlVUsyyBy
/ca0A7WBB8lD1D7QMIhYUm2O9kYtSCLlUTHt5leqGaRG38DqlX36
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIDzDCCArQCCQDSzxzxqhyqLzANBgkqhkiG9w0BAQQFADCBpzELMAkGA1UEBhMC
VVMxFjAUBgNVBAgTDU1hc3NhY2h1c2V0dHMxDzANBgNVBAcTBkJvc3RvbjETMBEG
A1UEChMKTXkgQ29tcGFueTEcMBoGA1UECxMTUHJvZHVjdCBEZXZlbG9wbWVudDEZ
MBcGA1UEAxMQd3d3Lm5vd2hlcmUubm9uZTEhMB8GCSqGSIb3DQEJARYSYWRtaW5A
bm93aGVyZS5ub25lMB4XDTA3MDMyMzE4MDc0NVoXDTI2MDUyMjE4MDc0NVowgacx
CzAJBgNVBAYTAlVTMRYwFAYDVQQIEw1NYXNzYWNodXNldHRzMQ8wDQYDVQQHEwZC
b3N0b24xEzARBgNVBAoTCk15IENvbXBhbnkxHDAaBgNVBAsTE1Byb2R1Y3QgRGV2
ZWxvcG1lbnQxGTAXBgNVBAMTEHd3dy5ub3doZXJlLm5vbmUxITAfBgkqhkiG9w0B
CQEWEmFkbWluQG5vd2hlcmUubm9uZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBAL5H18W9MHMYK41ds4hYpIyCPs3vIinEwbeOy9BjP3NtXn3pTfs2aSVF
Fy7uM8/EcqvEPrEIHzcu7kzqTfW1FGjpNU5w+4Gg0J0FojR5qm1tpC/g0jip4CVT
6PXREwEvIX+/g9XtQwWcY03NWuEUKliYscKWI/fYsVs7vFQtpv8V7I7zrI6ePgyw
QePdJ25ML7LZoZolptQpiOTucTpIIqFTUKh70DHVSjks/T6W472YkV9VKKqDK5Pt
jTqsD/dEwd+cjwEl2/c1yqTuwy4ZLm3vsmBn/spOOmg+9Oy9OxG+3KLBT0vOLzWf
YF+60NFDsJua2AP6GUwbJIGqobSM5C8CAwEAATANBgkqhkiG9w0BAQQFAAOCAQEA
vGomHEp6TVU83X2EBUgnbOhzKJ9u3fOI/Uf5L7p//Vxqow7OR1cguzh/YEzmXOIL
ilMVnzX9nj/bvcLAuqEP7MR1A8f4+E807p/L/Sf49BiCcwQq5I966sGKYXjkve+T
2GTBNwMSq+5kLSf6QY8VZI+qnrAudEQMeJByQhTZZ0dH8Njeq8EGl9KUio+VWaiW
CQK6xJuAvAHqa06OjLmwu1fYD4GLGSrOIiRVkSXV8qLIUmzxdJaIRznkFWsrCEKR
wAH966SAOvd2s6yOHMvyDRIL7WHxfESB6rDHsdIW/yny1fBePjv473KrxyXtbz7I
dMw1yW09l+eEo4A7GzwOdw==
-----END CERTIFICATE-----
END
	chmod 600 $tcert
	echo "$tcert"
}

2042
Kecho() {
2043 2044
	NO_KECHO=1
	if [ "X$USER" = "Xrunge" -a "X$NO_KECHO" = "X" ]; then
2045 2046
		echo "dbg: $*"
	fi
2047 2048
}

2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069
NHAFL_warning() {
	echo "" 
	echo "** Warning: For the proxy: $proxy" 
	echo "** Warning: the ssh(1) option: $ssh_NHAFL" 
	echo "** Warning: will be used to avoid frequent 'ssh key has changed for localhost'"
	echo "** Warning: dialogs and connection failures (for example, ssh will exit asking"
	echo "** Warning: you to manually remove a key from ~/.ssh/known_hosts.)"
	echo "** Warning: "
	echo "** Warning: This decreases security: a Man-In-The-Middle attack is possible."
	echo "** Warning: You can set the SSVNC_SSH_LOCALHOST_AUTH=1 env. var. to disable" 
	echo "** Warning: using the NoHostAuthenticationForLocalhost ssh option." 
	echo "** Warning: "
	echo "** Warning: A better solution is to configure (in the SSVNC GUI) the setting:"
	echo "** Warning: 'Options -> Advanced -> Private SSH KnownHosts file' (or set" 
	echo "** Warning: SSVNC_KNOWN_HOSTS_FILE directly) to a per-connection known hosts" 
	echo "** Warning: file.  This yields a both secure and convenient solution." 
	echo "" 
}

# handle ssh case:
#
2070
if [ "X$use_ssh" = "X1" ]; then
2071 2072 2073
	#
	# USING SSH
	#
2074 2075
	ssh_port="22"
	ssh_host="$host"
2076
	vnc_host="$localhost"
2077 2078
	ssh_UKHF=""
	localhost_extra=""
2079
	# let user override ssh via $SSH
2080
	ssh=${SSH:-"ssh -x"}
2081

2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117
	sshword=`echo "$ssh" | awk '{print $1}'`
	if [ "X$sshword" != "X" ]; then
		if [ -x "$sshword" ]; then
			:
		elif type "$sshword" > /dev/null 2>&1; then
			:
		else
			echo ""
			echo "*********************************************************"
			echo "** Problem finding the SSH command '$sshword': **"
			echo ""
			type "$sshword"
			echo ""
			echo "** Perhaps you need to install the SSH client package. **"
			echo "*********************************************************"
			echo ""
			sleep 5
		fi
	fi

	ssh_NHAFL="-o NoHostAuthenticationForLocalhost=yes"
	if [ "X$SSVNC_SSH_LOCALHOST_AUTH" = "X1" ]; then
		ssh_NHAFL=""
	fi
	if [ "X$SSVNC_KNOWN_HOSTS_FILE" != "X" ]; then
		ssh_NHAFL=""
	
		ssh_UKHF="-o UserKnownHostsFile=$SSVNC_KNOWN_HOSTS_FILE"
		ssh_args="$ssh_args $ssh_UKHF"
		if [ ! -f "$SSVNC_KNOWN_HOSTS_FILE" ]; then
			touch "$SSVNC_KNOWN_HOSTS_FILE" >/dev/null 2>&1
		fi
		chmod 600 "$SSVNC_KNOWN_HOSTS_FILE" >/dev/null 2>&1
	fi
	did_ssh_NHAFL=""

2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135
	if [ "X$SSVNC_LIM_ACCEPT_PRELOAD" != "X" ]; then
		SSVNC_LIM_ACCEPT_PRELOAD="$SSVNC_BASEDIR/$SSVNC_UNAME/$SSVNC_LIM_ACCEPT_PRELOAD"
	fi
	if [ "X$SSVNC_LIM_ACCEPT_PRELOAD" != "X" ]; then
		echo ""
		echo "SSVNC_LIM_ACCEPT_PRELOAD=$SSVNC_LIM_ACCEPT_PRELOAD"
	fi

	if [ "X$SSVNC_LIM_ACCEPT_PRELOAD" != "X" -a -f "$SSVNC_LIM_ACCEPT_PRELOAD" ]; then
		plvar=LD_PRELOAD
		if uname | grep Darwin >/dev/null; then
			plvar="DYLD_FORCE_FLAT_NAMESPACE=1 DYLD_INSERT_LIBRARIES"
		fi
		ssh="env $plvar=$SSVNC_LIM_ACCEPT_PRELOAD $ssh"
	else
		SSVNC_LIM_ACCEPT_PRELOAD=""
	fi

2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158
	ssh_vencrypt_proxy=""
	# We handle vencrypt for SSH+SSL mode.
	if echo "$proxy" | grep 'vencrypt://' > /dev/null; then
		proxynew=""
		for part in `echo "$proxy" | tr ',' ' '`
		do
			if echo "$part" | egrep -i '^vencrypt://' > /dev/null; then
				ssh_vencrypt_proxy=$part
			else
				if [ "X$proxynew" = "X" ]; then
					proxynew="$part"
				else
					proxynew="$proxynew,$part"
				fi
			fi
		done
		proxy=$proxynew
	fi 
	Kecho ssh_vencrypt_proxy=$ssh_vencrypt_proxy

	# note that user must supply http:// for web proxy in SSH and SSH+SSL.
	# No xxxx:// implies ssh server+port.
	#
2159 2160
	if echo "$proxy" | egrep '(http|https|socks|socks4|socks5)://' > /dev/null; then
		# Handle Web or SOCKS proxy(ies) for the initial connect.
runge's avatar
runge committed
2161 2162
		Kecho host=$host
		Kecho port=$port
2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182
		pproxy=""
		sproxy1=""
		sproxy_rest=""
		for part in `echo "$proxy" | tr ',' ' '`
		do
			Kecho proxy_part=$part
			if [ "X$part" = "X" ]; then
				continue
			elif echo "$part" | egrep -i '^(http|https|socks|socks4|socks5)://' > /dev/null; then
				pproxy="$pproxy,$part"
			else
				if [ "X$sproxy1" = "X" ]; then
					sproxy1="$part"
				else
					sproxy_rest="$sproxy_rest,$part"
				fi
			fi
		done
		pproxy=`echo "$pproxy" | sed -e 's/^,,*//' -e 's/,,*/,/g'`
		sproxy_rest=`echo "$sproxy_rest" | sed -e 's/^,,*//' -e 's/,,*/,/g'`
runge's avatar
runge committed
2183 2184 2185 2186

		Kecho pproxy=$pproxy
		Kecho sproxy1=$sproxy1
		Kecho sproxy_rest=$sproxy_rest
2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221

		sproxy1_host=""
		sproxy1_port=""
		sproxy1_user=""

		if [ "X$sproxy1" != "X" ]; then
			sproxy1_host=`echo "$sproxy1" | awk -F: '{print $1}'`
			sproxy1_user=`echo "$sproxy1_host" | awk -F@ '{print $1}'`
			sproxy1_host=`echo "$sproxy1_host" | awk -F@ '{print $2}'`
			if [ "X$sproxy1_host" = "X" ]; then
				sproxy1_host=$sproxy1_user
				sproxy1_user=""
			else
				sproxy1_user="${sproxy1_user}@"
			fi
			sproxy1_port=`echo "$sproxy1" | awk -F: '{print $2}'`
			if [ "X$sproxy1_port" = "X" ]; then
				sproxy1_port="22"
			fi
		else
			sproxy1_host=`echo "$host" | awk -F: '{print $1}'`
			sproxy1_user=`echo "$sproxy1_host" | awk -F@ '{print $1}'`
			sproxy1_host=`echo "$sproxy1_host" | awk -F@ '{print $2}'`
			if [ "X$sproxy1_host" = "X" ]; then
				sproxy1_host=$sproxy1_user
				sproxy1_user=""
			else
				sproxy1_user="${sproxy1_user}@"
			fi
			sproxy1_port=`echo "$host" | awk -F: '{print $2}'`
			if [ "X$sproxy1_port" = "X" ]; then
				sproxy1_port="22"
			fi
		fi

runge's avatar
runge committed
2222 2223 2224
		Kecho sproxy1_host=$sproxy1_host
		Kecho sproxy1_port=$sproxy1_port
		Kecho sproxy1_user=$sproxy1_user
2225

2226 2227
		ptmp="/tmp/ss_vncviewer_ssh${RANDOM}.$$.pl"
		ptmp=`mytmp "$ptmp"`
2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243
		PPROXY_REMOVE=1; export PPROXY_REMOVE
		proxy=$pproxy
		port_save=$port
		host_save=$host
		if [ "X$sproxy1_host" != "X" ]; then
			host=$sproxy1_host
		fi
		if [ "X$sproxy1_port" != "X" ]; then
			port=$sproxy1_port
		fi
		host=`echo "$host" | sed -e 's/^.*@//'`
		port=`echo "$port" | sed -e 's/^.*://'`
		pcode "$ptmp"
		port=$port_save
		host=$host_save

2244
		nd=`findfree 6600`
2245 2246
		PPROXY_LISTEN=$nd; export PPROXY_LISTEN
		$ptmp &
2247 2248 2249 2250 2251 2252 2253
		sleep 1
		if [ "X$ssh_NHAFL" != "X" -a "X$did_ssh_NHAFL" != "X1" ]; then
			NHAFL_warning
			ssh_args="$ssh_args $ssh_NHAFL"
			did_ssh_NHAFL=1
		fi
		sleep 1
2254 2255 2256 2257 2258 2259
		if [ "X$sproxy1" = "X" ]; then
			u=""
			if echo "$host" | grep '@' > /dev/null; then
				u=`echo "$host" | sed -e 's/@.*$/@/'`
			fi
			
2260
			proxy="${u}$localhost:$nd"
2261
		else
2262
			proxy="${sproxy1_user}$localhost:$nd"
2263
		fi
2264
		localhost_extra=".2"
2265 2266 2267
		if [ "X$sproxy_rest" != "X" ]; then
			proxy="$proxy,$sproxy_rest"
		fi
runge's avatar
runge committed
2268
		Kecho proxy=$proxy
2269 2270
	fi

2271
	if echo "$proxy" | grep "," > /dev/null; then
2272

2273 2274
		proxy1=`echo "$proxy" | awk -F, '{print $1}'`
		proxy2=`echo "$proxy" | awk -F, '{print $2}'`
2275

2276 2277 2278
		# user1@gw1.com:port1,user2@ws2:port2
		ssh_host1=`echo "$proxy1" | awk -F: '{print $1}'`
		ssh_port1=`echo "$proxy1" | awk -F: '{print $2}'`
2279
		if [ "X$ssh_port1" != "X" ]; then
2280
			ssh_port1="-p $ssh_port1"
2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295
		fi
		ssh_host2=`echo "$proxy2" | awk -F: '{print $1}'`
		ssh_user2=`echo "$ssh_host2" | awk -F@ '{print $1}'`
		ssh_host2=`echo "$ssh_host2" | awk -F@ '{print $2}'`
		if [ "X$ssh_host2" = "X" ]; then
			ssh_host2=$ssh_user2
			ssh_user2=""
		else
			ssh_user2="${ssh_user2}@"
		fi
		ssh_port2=`echo "$proxy2" | awk -F: '{print $2}'`
		if [ "X$ssh_port2" = "X" ]; then
			ssh_port2="22"
		fi
		proxport=`findfree 3500`
2296 2297 2298 2299 2300
		if [ "X$ssh_NHAFL" != "X" -a "X$did_ssh_NHAFL" != "X1" ]; then
			NHAFL_warning
			did_ssh_NHAFL=1
			sleep 1
		fi
2301 2302
		echo
		echo "Running 1st ssh proxy:"
2303 2304 2305 2306 2307
		ukhf=""
		if [ "X$ssh_UKHF" != "X" ]; then 
			ukhf="$ssh_UKHF$localhost_extra"
		fi
		echo "$ssh -f -x $ssh_port1 $targ -e none $ssh_NHAFL $ukhf -L $proxport:$ssh_host2:$ssh_port2 $ssh_host1 \"sleep 30\""
2308
		echo ""
2309 2310
		      $ssh -f -x $ssh_port1 $targ -e none $ssh_NHAFL $ukhf -L $proxport:$ssh_host2:$ssh_port2 $ssh_host1 "sleep 30"
		ssh_args="$ssh_args $ssh_NHAFL"
2311 2312
		sleep 1
		stty sane
2313
		proxy="${ssh_user2}$localhost:$proxport"
2314
	fi
2315

2316 2317 2318 2319 2320 2321 2322 2323
	if [ "X$proxy" != "X" ]; then
		ssh_port=`echo "$proxy" | awk -F: '{print $2}'`
		if [ "X$ssh_port" = "X" ]; then
			ssh_port="22"
		fi
		ssh_host=`echo "$proxy" | awk -F: '{print $1}'`
		vnc_host="$host"
	fi
2324

2325 2326 2327
	echo ""
	echo "Running ssh:"
	sz=`echo "$ssh_cmd" | wc -c`
2328
	if [ "$sz" -gt 300 ]; then
2329 2330 2331 2332 2333 2334
		info="..."
	else
		info="$ssh_cmd"
	fi

	C=""
2335
	if [ "X$SS_VNCVIEWER_USE_C" != "X" ]; then
2336 2337
		C="-C"
	fi
2338 2339

	getport=""
2340
	teeport=""
2341
	if echo "$ssh_cmd" | egrep "(PORT=|P=) " > /dev/null; then
2342
		getport=1
2343
		if echo "$ssh_cmd" | egrep "P= " > /dev/null; then
2344 2345 2346
			teeport=1
		fi

2347
		PORT=""
2348
		ssh_cmd=`echo "$ssh_cmd" | sed -e 's/PORT=[ 	]*//' -e 's/P=//'`
2349 2350 2351 2352 2353 2354 2355 2356
		SSVNC_NO_ENC_WARN=1
		if [ "X$use_sshssl" = "X" ]; then
			direct_connect=1
		fi
	fi
	if [ "X$getport" != "X" ]; then
		ssh_redir="-D ${use}"
	elif [ "X$reverse" = "X" ]; then
2357 2358 2359 2360 2361
		ssh_redir="-L ${use}:${vnc_host}:${port}"
	else
		ssh_redir="-R ${port}:${vnc_host}:${use}"
	fi
	pmark=`sh -c 'echo $$'`
2362

2363
	# the -t option actually speeds up typing response via VNC!!
2364 2365 2366 2367 2368
	if [ "X$ssh_port" = "X22" ]; then
		ssh_port=""
	else
		ssh_port="-p $ssh_port"
	fi
2369

2370
	if [ "X$SS_VNCVIEWER_SSH_ONLY" != "X" ]; then
2371
		echo "$ssh -x $ssh_port $targ $C $ssh_args $ssh_host \"$info\""
2372
		echo ""
2373
		$ssh -x $ssh_port $targ $C $ssh_args $ssh_host "$ssh_cmd"
2374
		exit $?
2375

2376
	elif [ "X$SS_VNCVIEWER_NO_F" != "X" ]; then
2377
		echo "$ssh -x $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host \"$info\""
2378
		echo ""
2379
		$ssh -x $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host "$ssh_cmd"
2380 2381 2382
		rc=$?

	elif [ "X$getport" != "X" ]; then
2383 2384
		tport=/tmp/ss_vncviewer_tport${RANDOM}.$$
		tport=`mytmp "$tport"`
2385 2386
		tport2=/tmp/ss_vncviewer_tport2${RANDOM}.$$
		tport2=`mytmp "$tport2"`
2387 2388

		if [ "X$rsh" != "X1" ]; then
2389
			if echo "$ssh_cmd" | grep "sudo " > /dev/null; then
2390 2391 2392 2393 2394 2395 2396 2397 2398 2399
				echo ""
				echo "Initial ssh with 'sudo id' to prime sudo so hopefully the next one"
				echo "will require no password..."
				echo ""
				targ="-t"
				$ssh -x $ssh_port $targ $ssh_args $ssh_host "sudo id; tty"
				echo ""
			fi
			echo "$ssh -x -f $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host \"$info\""
			echo ""
2400
			$ssh -x -f $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host "$ssh_cmd" > $tport 2> $tport2
2401
			if [ "X$teeport" = "X1" ]; then
2402
				tail -f $tport  1>&2 &
2403
				tail_pid=$!
2404 2405
				tail -f $tport2 1>&2 &
				tail_pid2=$!
2406 2407 2408 2409 2410 2411 2412 2413 2414 2415
			fi
			rc=$?
		else
			rsh_setup
			echo "rsh $ul $ssh_host \"$ssh_cmd\""
			echo ""
			rsh $ul $ssh_host "$ssh_cmd" > $tport &
			sleep 1
			rc=0
		fi
2416

2417
		if [ "X$SSVNC_EXTRA_SLEEP" != "X" ]; then
2418
			echo "sleep $SSVNC_EXTRA_SLEEP"
2419 2420 2421
			sleep $SSVNC_EXTRA_SLEEP
		fi

2422 2423
		stty sane
		i=0
2424 2425 2426 2427 2428 2429 2430 2431 2432 2433
		if type perl > /dev/null 2>&1; then
			imax=50
			sleepit="perl -e 'select(undef, undef, undef, 0.20)'"
		else
			imax=10
			sleepit="sleep 1"
		fi
		while [ $i -lt $imax ]; do
			#echo $sleepit
			eval $sleepit
2434
			PORT=`grep "^PORT=" $tport | tr '\r' ' ' | head -n 1 | sed -e 's/PORT=//' -e 's/\r//g' -e 's/ *$//'`
2435 2436 2437
			if echo "$PORT" | grep '^[0-9][0-9]*$' > /dev/null; then
				break
			fi
2438
			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}'`
2439 2440 2441 2442 2443 2444 2445 2446
			if [ "X$vnss" != "X" ]; then
				PORT=`echo "$vnss" | awk -F: '{print $2}'`
				if echo "$PORT" | grep '^[0-9][0-9]*$' > /dev/null; then
					if [ $PORT -lt 100 ]; then
						PORT=`expr $PORT + 5900`
					fi
				fi
				if echo "$PORT" | grep '^[0-9][0-9]*$' > /dev/null; then
2447 2448
					vnss=`sed -e 's/\r//g' $tport | egrep -i '^(New.* desktop is|A VNC server is already running).*:[0-9[0-9]*$' | head -n 1`
					echo "vncserver string: $vnss" 1>&2
2449 2450 2451 2452 2453 2454
					break
				fi
			fi
			i=`expr $i + 1`
		done

2455 2456
		echo "found: PORT='$PORT'" 1>&2
		rm -f $tport $tport2
2457 2458 2459 2460
		if [ "X$rsh" = "X1" ]; then
			rsh_viewer "$@"
			exit $?
		fi
2461
		PPROXY_SOCKS=1
2462 2463 2464
		if [ "X$SSVNC_SOCKS5" != "X" ]; then
			PPROXY_SOCKS=5
		fi
2465
		export PPROXY_SOCKS
2466
		host="$localhost"
2467
		port="$PORT"
2468
		proxy="$localhost:$use"
2469

2470
	else
2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485
		if [ "X$rsh" != "X1" ]; then
			echo "$ssh -x -f $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host \"$info\""
			echo ""
			$ssh -x -f $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host "$ssh_cmd"
			rc=$?
		else
			rsh_setup
			echo "rsh $ul $ssh_host \"$ssh_cmd\""
			echo ""
			rsh $ul $ssh_host "$ssh_cmd" &
			sleep 1
			PORT=$port
			rsh_viewer "$@"
			exit $?
		fi
2486
	fi
2487 2488

	if [ "$rc" != "0" ]; then
2489 2490 2491 2492
		echo ""
		echo "ssh to $ssh_host failed."
		exit 1
	fi
2493 2494 2495 2496
	stty sane

	c=0
	pssh=""
2497
	while [ $c -lt 40 ]
2498 2499
	do
		p=`expr $pmark + $c`
2500 2501 2502 2503 2504 2505 2506 2507 2508 2509
		pout=`ps -p "$p" 2>/dev/null | grep -v '^[ 	]*PID' | sed -e 's/-L.*$//' -e 's/-x .*$//'`
		if echo "$pout" | grep "ssh" > /dev/null; then
			if echo "$pout" | egrep -i 'ssh.*(-add|-agent|-ask|-keygen|-argv0|vnc)' >/dev/null; then
				:
			elif echo "$pout" | egrep -i 'scp|sshd' >/dev/null; then
				:
			else
				pssh=$p
				break
			fi
2510 2511 2512
		fi
		c=`expr $c + 1`
	done
2513 2514
	if [ "X$getport" != "X" ]; then
		:
2515 2516
	elif [ "X$SSVNC_LIM_ACCEPT_PRELOAD" != "X" ] ; then
		sleep 2
2517
	elif [ "X$ssh_cmd" = "Xsleep $ssh_sleep" ] ; then
2518
		#echo T sleep 1
2519
		sleep 1
2520 2521 2522
	elif echo "$ssh_cmd" | grep '^sleep ' >/dev/null; then
		#echo T sleep 2
		sleep 2
2523 2524
	else
		# let any command get started a bit.
2525
		#echo T sleep 5
2526 2527 2528
		sleep 5
	fi
	echo ""
2529 2530
	#reset
	stty sane
2531
	if [ "X$SSVNC_EXTRA_SLEEP" != "X" ]; then
2532
		echo "sleep $SSVNC_EXTRA_SLEEP"
2533 2534
		sleep $SSVNC_EXTRA_SLEEP
	fi
2535
	echo "ssh_pid='$pssh'"; echo
2536
	if [ "X$use_sshssl" = "X" -a "X$getport" = "X" ]; then
2537
		echo "Running viewer:"
2538 2539 2540

		trap "final" 0 2 15
		if [ "X$reverse" = "X" ]; then
2541
			echo "$VNCVIEWERCMD" "$@" $localhost:$N
2542
			echo ""
2543
			$VNCVIEWERCMD "$@" $localhost:$N
2544 2545 2546 2547
			if [ $? != 0 ]; then
				echo "vncviewer command failed: $?"
				if [ "X$secondtry" = "X1" ]; then
					sleep 2
2548
					$VNCVIEWERCMD "$@" $localhost:$N
2549 2550
				fi
			fi
2551 2552 2553 2554
		else
			echo ""
			echo "NOTE: Press Ctrl-C to terminate viewer LISTEN mode."
			echo ""
2555 2556 2557 2558 2559 2560 2561 2562
			N2=$N
			if [ "X$VNCVIEWER_IS_REALVNC4" = "X1" ]; then
				N2=`echo "$N2" | sed -e 's/://g'`
				if [ $N2 -le 200 ]; then
					N2=`expr $N2 + 5500`
				fi
			fi
			echo "$VNCVIEWERCMD" "$@" -listen $N2
2563
			echo ""
2564
			$VNCVIEWERCMD "$@" -listen $N2
2565
		fi
2566 2567 2568 2569 2570 2571

		exit $?
	else
		use2=`findfree 5960`
		host0=$host
		port0=$port
2572
		host=$localhost
2573 2574 2575
		port=$use
		use=$use2
		N=`expr $use - 5900`
2576 2577 2578 2579 2580 2581
		if [ "X$getport" != "X" ]; then
			host="$host0"
			port="$port0"
		else
			proxy=""
		fi
2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608
		if [ "X$ssh_vencrypt_proxy" != "X" ]; then
			ssh_vencrypt_proxy="vencrypt://$host:$port"
			if [ "X$proxy" = "X" ]; then
				proxy=$ssh_vencrypt_proxy
			else
				proxy="$proxy,$ssh_vencrypt_proxy"
			fi
			Kecho "proxy_now=$proxy"
			unset PPROXY_LISTEN
		fi
	fi
fi

if [ "X$stunnel_set_here" = "X1" -a "X$showcert" = "X" ]; then
	if type $STUNNEL > /dev/null 2>&1; then
		:
	else
		echo ""
		echo "***************************************************************"
		echo "** Problem finding the Stunnel command '$STUNNEL': **"
		echo ""
		type $STUNNEL
		echo ""
		echo "** Perhaps you need to install the stunnel/stunnel4 package. **"
		echo "***************************************************************"
		echo ""
		sleep 5
2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621
	fi
fi

# create the stunnel config file:
if [ "X$verify" != "X" ]; then
	if [ -d $verify ]; then
		verify="CApath = $verify"
	else
		verify="CAfile = $verify"
	fi
	verify="$verify
verify = 2"
fi
2622 2623 2624
if [ "X$SSVNC_STUNNEL_VERIFY3" != "X" ]; then
	verify=`echo "$verify" | sed -e 's/verify = 2/verify = 3/'`
fi
2625 2626 2627
if [ "X$mycert" != "X" ]; then
	cert="cert = $mycert"
fi
2628 2629 2630 2631 2632 2633 2634
if [ "X$crl" != "X" ]; then
	if [ -d $crl ]; then
		crl="CRLpath = $crl"
	else
		crl="CRLfile = $crl"
	fi
fi
2635 2636 2637

ptmp=""
if [ "X$proxy" != "X" ]; then
2638
	ptmp="/tmp/ss_vncviewer${RANDOM}.$$.pl"
2639
	ptmp=`mytmp "$ptmp"`
2640
	PPROXY_REMOVE=1; export PPROXY_REMOVE
2641
	pcode "$ptmp"
2642
	if [ "X$showcert" != "X1" -a "X$direct_connect" = "X" ]; then
2643
		if uname | egrep 'Darwin|SunOS' >/dev/null; then
2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659
			vout=`echo "$proxy" | grep -i vencrypt`
			if [ "X$vout" != "X" -a "X$reverse" = "X1" ]; then
				# need to exec for reverse vencrypt
				connect="exec = $ptmp"
			else
				# on mac and solaris we need to listen on socket instead of stdio:
				nd=`findfree 6700`
				PPROXY_LISTEN=$nd
				export PPROXY_LISTEN
				if [ "X$reverse" = "X" ]; then
					$ptmp &
				fi
				sleep 2
				host="$localhost"
				port="$nd"
				connect="connect = $localhost:$nd"
2660
			fi
2661
		else
2662
			# otherwise on unix we can exec it:
2663 2664 2665 2666 2667
			connect="exec = $ptmp"
		fi
	else
		connect="exec = $ptmp"
	fi
2668 2669 2670 2671
else
	connect="connect = $host:$port"
fi

2672 2673
# handle showcert case:
#
2674 2675
if [ "X$showcert" = "X1" ]; then
	if [ "X$proxy" != "X" ]; then
2676 2677
		PPROXY_LISTEN=$use
		export PPROXY_LISTEN
runge's avatar
runge committed
2678 2679 2680 2681 2682
		if [ "X$SS_DEBUG" != "X" ]; then
			$ptmp &
		else
			$ptmp 2>/dev/null &
		fi
2683
		sleep 1
2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700
		more_sleep=1
		if uname | grep Linux > /dev/null; then
			if netstat -ant | grep LISTEN | grep "127.0.0.1:$use" > /dev/null; then
				more_sleep=""
			fi
		elif uname | grep SunOS > /dev/null; then
			if netstat -an -f inet -P tcp | grep LISTEN | grep "127.0.0.1.$use" > /dev/null; then
				more_sleep=""
			fi
		elif uname | egrep -i 'bsd|darwin' > /dev/null; then
			if netstat -ant -f inet | grep LISTEN | grep "127.0.0.1.$use" > /dev/null; then
				more_sleep=""
			fi
		fi
		if [ "X$more_sleep" = "X1" ]; then
			sleep 1
		fi
2701
		host="$localhost"
2702 2703
		port="$use"
	fi
runge's avatar
runge committed
2704 2705 2706 2707
	cipher_args=""
	if [ "X$ciphers" != "X" ]; then
		cipher_args=`echo "$ciphers" | sed -e 's/ciphers=/-cipher /'`
	fi
2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720
	if type openssl > /dev/null 2>&1; then
		:
	else
		echo ""
		echo "********************************************************"
		echo "** Problem finding the OpenSSL command 'openssl': **" 
		echo ""
		type openssl 2>&1
		echo ""
		echo "** Perhaps you need to install the 'openssl' package. **"
		echo "********************************************************"
		echo ""
	fi
runge's avatar
runge committed
2721
	#echo "openssl s_client $cipher_args -connect $host:$port" 
2722
	if [ "X$reverse" = "X" ]; then
2723 2724 2725 2726 2727 2728 2729 2730 2731
		host $host >/dev/null 2>&1
		host $host >/dev/null 2>&1
		timeout=15
		if [ "X$SSVNC_FETCH_TIMEOUT" != "X" ]; then
			timeout=$SSVNC_FETCH_TIMEOUT
		fi
		if type pkill >/dev/null 2>&1; then
			(sleep $timeout; if kill -0 $$; then pkill -TERM -f "openssl.*s_client.*$host.*$port"; fi) >/dev/null 2>&1 &
		fi
2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748
		openssl s_client $cipher_args -prexit -connect $host:$port 2>&1 < /dev/null
		rc=$?
	else
		tcert=""
		if [ "X$mycert" = "X" ]; then
			tcert=`make_tcert`
			cert_args="-cert $tcert -CAfile $tcert"
		else
			cert_args="-cert $mycert -CAfile $mycert"
		fi
		tmp_out=/tmp/showcert_out${RANDOM}.$$
		tmp_out=`mytmp "$tmp_out"`
		tmp_err=/tmp/showcert_err${RANDOM}.$$
		tmp_err=`mytmp "$tmp_err"`

		#echo "openssl s_server $cipher_args $cert_args -accept $port -verify 2 > $tmp_out 2> $tmp_err" 1>&2

2749 2750 2751
		# assume we have perl:
		check_perl perl

2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790
		perl -e "
			\$p = open(O, \"|openssl s_server $cipher_args $cert_args -accept $port -verify 2 1>$tmp_out 2> $tmp_err\");
			exit 1 unless \$p;
			while (1) {
				sleep 1;
				if (!open(F, \"<$tmp_out\")) {
					kill \$p;
					exit 1;
				}
				while (<F>) {
					if (/RFB 00/) {
						fsleep(0.25);
						print O \"RFB 000.000\\n\";
						fsleep(1.00);
						kill \$p;
						fsleep(0.25);
						exit 0;
					}
				}
				close F;
			}
			sub fsleep {
				select(undef, undef, undef, shift);
			}
		";

		echo ""
		cat $tmp_out
		echo ""
		echo "----2----"
		cat $tmp_err
		if grep BEGIN.CERTIFICATE $tmp_out >/dev/null; then
			rc=0
		else
			rc=1
		fi

		rm -f $tmp_out $tmp_err
	fi
runge's avatar
runge committed
2791 2792 2793
	if [ "X$SSVNC_PREDIGESTED_HANDSHAKE" != "X" ]; then
		rm -f $SSVNC_PREDIGESTED_HANDSHAKE
	fi
2794 2795 2796 2797 2798
	if [ "X$SSVNC_SHOWCERT_EXIT_0" = "X1" ]; then
		exit 0
	else
		exit $rc
	fi
2799 2800
fi

2801 2802
# handle direct connect case:
#
2803
if [ "X$direct_connect" != "X" ]; then
2804 2805 2806 2807 2808
	if [ "X$SSVNC_ULTRA_DSM" != "X" ]; then
		SSVNC_NO_ENC_WARN=1
		echo ""
		echo "Using UltraVNC DSM Plugin key for encryption:"
		echo ""
2809 2810
		ustr=`echo "$SSVNC_ULTRA_DSM" | sed -e 's/pw=[^ ]*/pw=******/g'`
		echo "  $ustr PORT HOST:PORT"
2811 2812
		echo ""
	elif [ "X$getport" = "X" ]; then
2813 2814
		echo ""
		echo "Running viewer for direct connection:"
2815 2816 2817 2818
		if echo X"$@" | grep chatonly > /dev/null; then
			:
		else
			echo ""
2819
			echo "** WARNING: THERE WILL BE NO SSL OR SSH ENCRYPTION **"
2820 2821
			echo ""
		fi
2822
	fi
2823
	x=""
2824
	if [ "X$SSVNC_NO_ENC_WARN" != "X" ]; then
2825 2826 2827
		if [ "X$getport" = "X" ]; then
			sleep 1
		fi
2828
	elif type printf > /dev/null 2>&1; then
2829
		printf  "Are you sure you want to continue? [y]/n "
2830
		read x
2831 2832
	else
		echo -n "Are you sure you want to continue? [y]/n "
2833
		read x
2834 2835 2836 2837 2838 2839
	fi
	if [ "X$x" = "Xn" ]; then
		exit 1
	fi
	echo ""
	if [ "X$ptmp" != "X" ]; then
2840 2841 2842 2843
		if [ "X$reverse" = "X" ]; then
			PPROXY_LISTEN=$use
			export PPROXY_LISTEN
		else
2844
			PPROXY_REVERSE="$localhost:$use"
2845 2846 2847 2848 2849 2850 2851 2852 2853
			export PPROXY_REVERSE
			pps=3
			if [ "X$SSVNC_EXTRA_SLEEP" != "X" ]; then
				pps=`expr $pps + $SSVNC_EXTRA_SLEEP`
			fi
			PPROXY_SLEEP=$pps; export PPROXY_SLEEP;
			PPROXY_KILLPID=+1; export PPROXY_KILLPID;
		fi

2854
		$ptmp &
2855

2856
		if [ "X$reverse" = "X" ]; then
2857 2858 2859
			#sleep 2
			#echo T sleep 1
			sleep 1
2860
		fi
2861
		host="$localhost"
2862
		disp="$N"
2863
		port=`expr $disp + 5900`
2864
	fi
2865
	if [ "X$SSVNC_EXTRA_SLEEP" != "X" ]; then
2866
		echo "T sleep $SSVNC_EXTRA_SLEEP"
2867 2868
		sleep $SSVNC_EXTRA_SLEEP
	fi
2869
	if [ "X$reverse" = "X" ]; then
2870 2871
		hostdisp="$host:$disp"
		if [ "X$SSVNC_ULTRA_DSM" != "X" ]; then
2872 2873 2874 2875 2876 2877
			if [ "X$SSVNC_USE_OURS" = "X1" ]; then
				hostdisp="exec=$SSVNC_ULTRA_DSM 0 $host:$port"
			else
				pf=`findfree 5970`
				cmd="$SSVNC_ULTRA_DSM -$pf $host:$port"
				pf=`expr $pf - 5900`
2878
				hostdisp="$localhost:$pf"
2879 2880 2881 2882 2883 2884 2885 2886 2887
				ustr=`echo "$cmd" | sed -e 's/pw=[^ ]*/pw=******/g'`
				echo "Running:"
				echo
				echo "$ustr &"
				echo
				$cmd &
				dsm_pid=$!
				sleep 2
			fi
2888
		fi
2889 2890
		hostdisp2=`echo "$hostdisp" | sed -e 's/pw=[^ ]*/pw=******/g'`
		echo "$VNCVIEWERCMD" "$@" "$hostdisp2"
2891 2892
		trap "final" 0 2 15
		echo ""
2893
		$VNCVIEWERCMD "$@" "$hostdisp"
2894 2895 2896 2897
		if [ $? != 0 ]; then
			echo "vncviewer command failed: $?"
			if [ "X$secondtry" = "X1" ]; then
				sleep 2
2898
				$VNCVIEWERCMD "$@" "$hostdisp"
2899 2900
			fi
		fi
2901 2902 2903 2904 2905
	else
		echo ""
		echo "NOTE: Press Ctrl-C to terminate viewer LISTEN mode."
		echo ""
		trap "final" 0 2 15
2906 2907
		if [ "X$SSVNC_ULTRA_DSM" != "X" ]; then
			echo "NOTE: The ultravnc_dsm_helper only runs once.  So after the first LISTEN"
2908
			echo "      ends, you may have to Press Ctrl-C and restart for another connection."
2909
			echo ""
2910 2911 2912
			SSVNC_LISTEN_ONCE=1; export SSVNC_LISTEN_ONCE
			VNCVIEWER_LISTEN_LOCALHOST=1
			export VNCVIEWER_LISTEN_LOCALHOST
2913
			dport=`expr 5500 + $disp`
2914
			cmd="$SSVNC_ULTRA_DSM $dport $localhost:$use"
2915
			ustr=`echo "$cmd" | sed -e 's/pw=[^ ]*/pw=******/g'`
2916 2917
			echo "Running:"
			echo
2918
			echo "$ustr &"
2919 2920 2921 2922 2923 2924 2925 2926 2927
			echo
			$cmd &
			dsm_pid=$!
			sleep 2
			disp=$use
			if [ $disp -ge 5500 ]; then
				disp=`expr $disp - 5500`
			fi
		fi
2928 2929 2930 2931 2932 2933 2934 2935
		disp2=$disp
		if [ "X$VNCVIEWER_IS_REALVNC4" = "X1" ]; then
			disp2=`echo "$disp2" | sed -e 's/://g'`
			if [ $disp2 -le 200 ]; then
				disp2=`expr $disp2 + 5500`
			fi
		fi
		echo "$VNCVIEWERCMD" "$@" -listen $disp2
2936
		echo ""
2937
		$VNCVIEWERCMD "$@" -listen $disp2
2938
	fi
2939 2940 2941
	exit $?
fi

2942
tmp_cfg=/tmp/ss_vncviewer${RANDOM}.$$
2943
tmp_cfg=`mytmp "$tmp_cfg"`
2944

2945
stunnel_exec=""
2946 2947 2948
if [ "X$SSVNC_USE_OURS" != "X1" ]; then
	:
elif echo $STUNNEL_EXTRA_SVC_OPTS | grep '#stunnel-exec' > /dev/null; then
2949 2950 2951 2952 2953
	stunnel_exec="#"
fi

if [ "X$reverse" = "X" ]; then

2954
	if echo "$proxy" | grep "^repeater://" > /dev/null; then
2955 2956 2957 2958 2959 2960
		if [ "X$cert" = "XBUILTIN" ]; then
			ttcert=`make_tcert`
			cert="cert = $ttcert"
		fi
		# Note for listen mode, an empty cert will cause stunnel to fail.
		# The ssvnc gui will have already taken care of this.
2961 2962
	fi

2963 2964 2965 2966
	cat > "$tmp_cfg" <<END
foreground = yes
pid =
client = yes
2967
debug = $stunnel_debug
runge's avatar
runge committed
2968
$ciphers
2969 2970 2971
$STUNNEL_EXTRA_OPTS
$STUNNEL_EXTRA_OPTS_USER
$cert
2972 2973
$crl
$verify
2974 2975

${stunnel_exec}[vnc_stunnel]
2976
${stunnel_exec}accept = $localhost:$use
2977 2978 2979 2980 2981
$connect
$STUNNEL_EXTRA_SVC_OPTS
$STUNNEL_EXTRA_SVC_OPTS_USER

END
2982

2983
else
2984 2985
	# REVERSE case:

2986 2987 2988
	stunnel_exec=""	# doesn't work for listening.

	p2=`expr 5500 + $N`
2989
	connect="connect = $localhost:$p2"
2990 2991 2992 2993 2994 2995 2996
	if [ "X$cert" = "XBUILTIN" ]; then
		ttcert=`make_tcert`
		cert="cert = $ttcert"
	fi
	# Note for listen mode, an empty cert will cause stunnel to fail.
	# The ssvnc gui will have already taken care of this.

2997 2998 2999

	hloc=""
	if [ "X$use_ssh" = "X1" ]; then
3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011
		hloc="$localhost:"
	fi
	if echo "$proxy" | grep -i '^vencrypt:' > /dev/null; then
		hloc="$localhost:"
		pv=`findfree 5570`
		proxy="vencrypt:$pv:$port"
		port=$pv
		if [ "X$anondh_set" = "X1" ]; then
			# not needed for ANONDH in this mode
			#ciphers="ciphers = ADH:@STRENGTH"
			:
		fi
3012
	fi
3013
	cat > "$tmp_cfg" <<END
3014 3015 3016
foreground = yes
pid =
client = no
3017
debug = $stunnel_debug
runge's avatar
runge committed
3018
$ciphers
3019
$STUNNEL_EXTRA_OPTS
3020
$STUNNEL_EXTRA_OPTS_USER
3021
$cert
3022 3023
$crl
$verify
3024 3025 3026 3027

[vnc_stunnel]
accept = $hloc$port
$connect
3028 3029
$STUNNEL_EXTRA_SVC_OPTS
$STUNNEL_EXTRA_SVC_OPTS_USER
3030 3031

END
3032

3033
fi
3034 3035 3036 3037

echo ""
echo "Using this stunnel configuration:"
echo ""
3038
cat "$tmp_cfg" | uniq
3039
echo ""
3040 3041 3042 3043 3044 3045 3046 3047
if egrep -i '^[ 	]*(CApath|CAfile) =' "$tmp_cfg" > /dev/null ; then
	:
else
	echo "** WARNING: THE STUNNEL CONFIG HAS NO SERVER CERTIFICATE SPECIFIED       **"
	echo "** WARNING: (the CApath or CAfile stunnel option) THE VNC SERVER WILL    **"
	echo "** WARNING: NOT BE AUTHENTICATED. A MAN-IN-THE-MIDDLE ATTACK IS POSSIBLE **"
	echo ""
fi
3048 3049
sleep 1

3050
if [ "X$stunnel_exec" = "X" ]; then
3051
	echo ""
3052 3053 3054 3055 3056 3057
	echo "Running stunnel:"
	echo "$STUNNEL $tmp_cfg"
	st=`echo "$STUNNEL" | awk '{print $1}'`
	$st -help > /dev/null 2>&1
	$STUNNEL "$tmp_cfg" < /dev/tty > /dev/tty &
	stunnel_pid=$!
3058
	echo ""
3059 3060 3061 3062

	# pause here to let the user supply a possible passphrase for the
	# mycert key:
	if [ "X$mycert" != "X" ]; then
3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077
		nsl=10
		dsl=0
		if [ ! -f $mycert ]; then
			dsl=0
		elif grep -i 'Proc-Type.*ENCRYPTED' "$mycert" > /dev/null 2>/dev/null; then
			dsl=1
		fi
		if [ "X$dsl" = "X1" ]; then
			echo ""
			echo "(** pausing $nsl secs for possible certificate passphrase dialog **)"
			echo ""
			sleep $nsl
			echo "(** done pausing for passphrase **)"
			echo ""
		fi
3078 3079 3080 3081
	fi
	#echo T sleep 1
	sleep 1
	rm -f "$tmp_cfg"
3082
fi
3083

3084 3085

echo ""
3086
if [ "X$SSVNC_EXTRA_SLEEP" != "X" ]; then
3087
	echo "sleep $SSVNC_EXTRA_SLEEP"
3088 3089
	sleep $SSVNC_EXTRA_SLEEP
fi
3090

3091
if [ "X$reverse" = "X" ]; then
3092 3093 3094 3095 3096 3097 3098 3099
	if [ "X$NEED_VENCRYPT_VIEWER_BRIDGE" = "X1" -a "X$ptmp" != "X" ] ; then
		port1=`expr 5900 + $N`		# stunnel port
		port2=`findfree 5970`		# bridge port (viewer connects to it.)
		N=`expr $port2 - 5900`
		env PPROXY_REMOVE=0 PPROXY_SLEEP=0 PPROXY_VENCRYPT_VIEWER_BRIDGE="$port2,$port1" $ptmp &
		sleep 1
	fi
	echo "Running viewer:"
3100
	vnc_hp=$localhost:$N
3101 3102 3103 3104
	if [ "X$stunnel_exec" != "X" ]; then
		vnc_hp="exec=$STUNNEL $tmp_cfg"
	fi
	echo "$VNCVIEWERCMD" "$@" "$vnc_hp"
3105 3106
	trap "final" 0 2 15
	echo ""
3107
	$VNCVIEWERCMD "$@" "$vnc_hp"
3108 3109 3110 3111
	if [ $? != 0 ]; then
		echo "vncviewer command failed: $?"
		if [ "X$secondtry" = "X1" ]; then
			sleep 2
3112
			$VNCVIEWERCMD "$@" "$vnc_hp"
3113 3114
		fi
	fi
3115
else
3116
	echo "Running viewer:"
3117 3118 3119
	echo ""
	echo "NOTE: Press Ctrl-C to terminate viewer LISTEN mode."
	echo ""
3120
	trap "final" 0 2 15
3121
	N2=$N
3122 3123 3124
	N2_trim=`echo "$N2" | sed -e 's/://g'`
	if [ $N2_trim -le 200 ]; then
		N2_trim=`expr $N2_trim + 5500`
3125
	fi
3126
	if [ "X$proxy" != "X" ]; then
3127 3128 3129 3130 3131 3132 3133 3134
		if echo "$proxy" | grep -i '^vencrypt:' > /dev/null; then
			pstunnel=`echo "$proxy" | awk -F: '{print $2}'`
			plisten=`echo "$proxy" | awk -F: '{print $3}'`
			PPROXY_LISTEN="INADDR_ANY:$plisten"; export PPROXY_LISTEN
			PPROXY_PROXY="vencrypt://$localhost:$pstunnel"; export PPROXY_PROXY
			PPROXY_DEST="$localhost:$pstunnel"; export PPROXY_DEST
			STUNNEL_ONCE=1; export STUNNEL_ONCE
			STUNNEL_MAX_CLIENTS=1; export STUNNEL_MAX_CLIENTS
3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145
			if [ "X$NEED_VENCRYPT_VIEWER_BRIDGE" = "X1" -a "X$ptmp" != "X" ] ; then
				port1=`expr 5500 + $N2`
				port2=`findfree 5580`
				N2=`expr $port2 - 5500`
				N2_trim=`echo "$N2" | sed -e 's/://g'`
				if [ $N2_trim -le 200 ]; then
					N2_trim=`expr $N2_trim + 5500`
				fi
				env PPROXY_REMOVE=0 PPROXY_SLEEP=0 PPROXY_VENCRYPT_VIEWER_BRIDGE="-$port1,$port2" $ptmp &
				sleep 1
			fi
3146 3147 3148 3149
		else
			PPROXY_REVERSE="$localhost:$port"; export PPROXY_REVERSE
			PPROXY_SLEEP=1; export PPROXY_SLEEP;
		fi
3150 3151
		PPROXY_KILLPID=+1; export PPROXY_KILLPID;
		$ptmp &
3152 3153 3154 3155
		# Important to have no extra pids generated between here and VNCVIEWERCMD
	fi
	if [ "X$VNCVIEWER_IS_REALVNC4" = "X1" ]; then
		N2=$N2_trim
3156
	fi
3157 3158
	echo "$VNCVIEWERCMD" "$@" -listen $N2
	echo ""
3159
	$VNCVIEWERCMD "$@" -listen $N2
3160
fi
3161 3162

sleep 1