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