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