diff options
author | runge <runge> | 2007-05-16 21:32:52 +0000 |
---|---|---|
committer | runge <runge> | 2007-05-16 21:32:52 +0000 |
commit | 3110c0e32f2f1fe823917eebc33bedc44a84160c (patch) | |
tree | 5adec4f47905ebca5b36da5c5699d007f80654db /classes | |
parent | c49eee2cf625d8cfcefd23c6a33e6c9488570fcc (diff) | |
download | libvncserver-3110c0e32f2f1fe823917eebc33bedc44a84160c.zip libvncserver-3110c0e32f2f1fe823917eebc33bedc44a84160c.tar.gz |
Add SSL support to UltraVNC Java Viewer (has filetransfer gui). Fix UltraVNC bugs and improve FTP gui a bit.
Diffstat (limited to 'classes')
-rw-r--r-- | classes/ssl/Makefile.am | 2 | ||||
-rw-r--r-- | classes/ssl/README | 14 | ||||
-rw-r--r-- | classes/ssl/SignedUltraViewerSSL.jar | bin | 0 -> 91540 bytes | |||
-rw-r--r-- | classes/ssl/SignedVncViewer.jar | bin | 79005 -> 79003 bytes | |||
-rw-r--r-- | classes/ssl/UltraViewerSSL.jar | bin | 0 -> 88970 bytes | |||
-rw-r--r-- | classes/ssl/VncViewer.jar | bin | 76220 -> 76220 bytes | |||
-rwxr-xr-x | classes/ssl/ss_vncviewer | 259 | ||||
-rw-r--r-- | classes/ssl/tightvnc-1.3dev7_javasrc-vncviewer-ssl.patch | bin | 44072 -> 42592 bytes | |||
-rw-r--r-- | classes/ssl/ultra.vnc | 27 | ||||
-rw-r--r-- | classes/ssl/ultrasigned.vnc | 27 | ||||
-rw-r--r-- | classes/ssl/ultravnc-102-JavaViewer-ssl-etc.patch | 2323 |
11 files changed, 2593 insertions, 59 deletions
diff --git a/classes/ssl/Makefile.am b/classes/ssl/Makefile.am index b0d3664..29ad54d 100644 --- a/classes/ssl/Makefile.am +++ b/classes/ssl/Makefile.am @@ -1,2 +1,2 @@ -EXTRA_DIST=VncViewer.jar index.vnc SignedVncViewer.jar proxy.vnc README ss_vncviewer onetimekey +EXTRA_DIST=VncViewer.jar index.vnc SignedVncViewer.jar proxy.vnc README ss_vncviewer onetimekey UltraViewerSSL.jar SignedUltraViewerSSL.jar ultra.vnc ultrasigned.vnc diff --git a/classes/ssl/README b/classes/ssl/README index 7c3115f..1b794e4 100644 --- a/classes/ssl/README +++ b/classes/ssl/README @@ -69,4 +69,18 @@ Running Java SSL VncViewer from the command line: java -cp ./VncViewer.jar VncViewer HOST <thehost> PORT <theport> substitute <thehost> and <theport> with the actual values. + You can add any other parameters, e.g.: ignoreProxy yes +--------------------------------------------------------------- +UltraVNC: + +The UltraVNC java viewer has also been patched to support SSL. Various +bugs in the UltraVNC java viewer were also fixed. This viewer can be +useful because is support UltraVNC filetransfer, and so it works on +Unix, etc. + +UltraViewerSSL.jar +SignedUltraViewerSSL.jar +ultra.vnc +ultraproxy.vnc +ultravnc-102-JavaViewer-ssl-etc.patch diff --git a/classes/ssl/SignedUltraViewerSSL.jar b/classes/ssl/SignedUltraViewerSSL.jar Binary files differnew file mode 100644 index 0000000..8a60f0d --- /dev/null +++ b/classes/ssl/SignedUltraViewerSSL.jar diff --git a/classes/ssl/SignedVncViewer.jar b/classes/ssl/SignedVncViewer.jar Binary files differindex 1d60cb1..1244b2a 100644 --- a/classes/ssl/SignedVncViewer.jar +++ b/classes/ssl/SignedVncViewer.jar diff --git a/classes/ssl/UltraViewerSSL.jar b/classes/ssl/UltraViewerSSL.jar Binary files differnew file mode 100644 index 0000000..7543238 --- /dev/null +++ b/classes/ssl/UltraViewerSSL.jar diff --git a/classes/ssl/VncViewer.jar b/classes/ssl/VncViewer.jar Binary files differindex b4ac298..c2e416c 100644 --- a/classes/ssl/VncViewer.jar +++ b/classes/ssl/VncViewer.jar diff --git a/classes/ssl/ss_vncviewer b/classes/ssl/ss_vncviewer index a20f164..f7b4831 100755 --- a/classes/ssl/ss_vncviewer +++ b/classes/ssl/ss_vncviewer @@ -260,6 +260,12 @@ if [ "X$use_ssh" = "X1" -a "X$use_sshssl" = "X" ]; then fi fi +if echo "$orig" | grep '^V[Nn][Cc]://' > /dev/null; then + SSVNC_NO_ENC_WARN=1 + export SSVNC_NO_ENC_WARN + orig=`echo "$orig" | sed -e 's/^...:/vnc:/'` +fi + if echo "$orig" | grep '^vnc://' > /dev/null; then orig=`echo "$orig" | sed -e 's,vnc://,,'` verify="" @@ -271,9 +277,14 @@ elif echo "$orig" | grep '^vncs://' > /dev/null; then orig=`echo "$orig" | sed -e 's,vncs://,,'` elif echo "$orig" | grep '^vncssl://' > /dev/null; then orig=`echo "$orig" | sed -e 's,vncssl://,,'` +elif echo "$orig" | grep '^vnc+ssl://' > /dev/null; then + orig=`echo "$orig" | sed -e 's,vnc.ssl://,,'` elif echo "$orig" | grep '^vncssh://' > /dev/null; then orig=`echo "$orig" | sed -e 's,vncssh://,,'` use_ssh=1 +elif echo "$orig" | grep '^vnc+ssh://' > /dev/null; then + orig=`echo "$orig" | sed -e 's,vnc.ssh://,,'` + use_ssh=1 fi if [ "X$reverse" != "X" -a "X$direct_connect" = "X" ]; then VNCVIEWER_LISTEN_LOCALHOST=1 @@ -314,6 +325,8 @@ if uname | grep Linux > /dev/null; then inuse=`netstat -ant | egrep 'LISTEN|WAIT|ESTABLISH|CLOSE' | awk '{print $4}' | sed 's/^.*://'` elif uname | grep SunOS > /dev/null; then inuse=`netstat -an -f inet -P tcp | grep LISTEN | awk '{print $1}' | sed 's/^.*\.//'` +elif uname | grep -i bsd > /dev/null; then + inuse=`netstat -ant -f inet | grep LISTEN | awk '{print $4}' | sed 's/^.*\.//'` # add others... fi @@ -412,6 +425,31 @@ if echo "$0" | grep vncip > /dev/null; then VNCVIEWERCMD="$VNCIPCMD" fi +rchk() { + if [ "X$BASH_VERSION" = "X" ]; then + RANDOM=`date +%S``sh -c 'echo $$'``ps -elf 2>&1 | sum 2>&1 | awk '{print $1}'` + fi +} +rchk + +mytmp() { + tf=$1 + rm -rf "$tf" || exit 1 + if [ -d "$tf" ]; then + echo "tmp file $tf still exists as a directory." + exit 1 + elif [ -L "$tf" ]; then + echo "tmp file $tf still exists as a symlink." + exit 1 + elif [ -f "$tf" ]; then + echo "tmp file $tf still exists." + exit 1 + fi + touch "$tf" || exit 1 + chmod 600 "$tf" || exit 1 + rchk +} + if [ "X$use_ssh" = "X1" ]; then ssh_port="22" ssh_host="$host" @@ -472,28 +510,88 @@ if [ "X$use_ssh" = "X1" ]; then if [ "X$SS_VNCVIEWER_USE_C" != "X" ]; then C="-C" fi - if [ "X$reverse" = "X" ]; then + + getport="" + if echo "$ssh_cmd" | egrep "^(PORT=|P=)" > /dev/null; then + getport=1 + PORT="" + ssh_cmd=`echo "$ssh_cmd" | sed -e 's/^PORT=[ ]*//' -e 's/^P=//'` + SSVNC_NO_ENC_WARN=1 + if [ "X$use_sshssl" = "X" ]; then + direct_connect=1 + fi + fi + if [ "X$getport" != "X" ]; then + ssh_redir="-D ${use}" + elif [ "X$reverse" = "X" ]; then ssh_redir="-L ${use}:${vnc_host}:${port}" else ssh_redir="-R ${port}:${vnc_host}:${use}" fi pmark=`sh -c 'echo $$'` + # the -t option actually speeds up typing response via VNC!! + if [ "X$SS_VNCVIEWER_SSH_ONLY" != "X" ]; then echo "$ssh -x -p $ssh_port $targ $C $ssh_args $ssh_host \"$info\"" echo "" $ssh -x -p $ssh_port $targ $C $ssh_args $ssh_host "$ssh_cmd" exit $? + elif [ "X$SS_VNCVIEWER_NO_F" != "X" ]; then echo "$ssh -x -p $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host \"$info\"" echo "" $ssh -x -p $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host "$ssh_cmd" + rc=$? + + elif [ "X$getport" != "X" ]; then + echo "$ssh -x -f -p $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host \"$info\"" + echo "" + + tport=/tmp/tport${RANDOM}.$$ + mytmp $tport + $ssh -x -f -p $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host "$ssh_cmd" > $tport + rc=$? + + stty sane + i=0 + while [ $i -lt 10 ]; do + sleep 1 + PORT=`grep "^PORT=" $tport | head -1 | sed -e 's/PORT=//' -e 's/\r//g'` + if echo "$PORT" | grep '^[0-9][0-9]*$' > /dev/null; then + break + fi + vnss=`sed -e 's/\r//g' $tport | egrep -i '^(New.* desktop is|A VNC server is already running).*:[0-9[0-9]*$' | head -1 | awk '{print $NF}'` + if [ "X$vnss" != "X" ]; then + PORT=`echo "$vnss" | awk -F: '{print $2}'` + if echo "$PORT" | grep '^[0-9][0-9]*$' > /dev/null; then + if [ $PORT -lt 100 ]; then + PORT=`expr $PORT + 5900` + fi + fi + if echo "$PORT" | grep '^[0-9][0-9]*$' > /dev/null; then + break + fi + fi + i=`expr $i + 1` + done + + echo "PORT=$PORT" 1>&2 + PPROXY_SOCKS=1 + export PPROXY_SOCKS + host="localhost" + port="$PORT" + proxy="localhost:$use" + rm -f $tport + else echo "$ssh -x -f -p $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host \"$info\"" echo "" $ssh -x -f -p $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host "$ssh_cmd" + rc=$? fi - if [ "$?" != "0" ]; then + + if [ "$rc" != "0" ]; then echo "" echo "ssh to $ssh_host failed." exit 1 @@ -511,7 +609,9 @@ if [ "X$use_ssh" = "X1" ]; then fi c=`expr $c + 1` done - if [ "X$ssh_cmd" = "Xsleep $ssh_sleep" ] ; then + if [ "X$getport" != "X" ]; then + : + elif [ "X$ssh_cmd" = "Xsleep $ssh_sleep" ] ; then sleep 1 else # let any command get started a bit. @@ -521,7 +621,7 @@ if [ "X$use_ssh" = "X1" ]; then #reset stty sane #echo "pssh=\"$pssh\"" - if [ "X$use_sshssl" = "X" ]; then + if [ "X$use_sshssl" = "X" -a "X$getport" = "X" ]; then echo "Running viewer:" trap "final" 0 2 15 @@ -547,7 +647,12 @@ if [ "X$use_ssh" = "X1" ]; then port=$use use=$use2 N=`expr $use - 5900` - proxy="" + if [ "X$getport" != "X" ]; then + host="$host0" + port="$port0" + else + proxy="" + fi fi fi @@ -565,53 +670,33 @@ if [ "X$mycert" != "X" ]; then cert="cert = $mycert" fi -mytmp() { - tf=$1 - rm -rf "$tf" || exit 1 - if [ -d "$tf" ]; then - echo "tmp file $tf still exists as a directory." - exit 1 - elif [ -L "$tf" ]; then - echo "tmp file $tf still exists as a symlink." - exit 1 - elif [ -f "$tf" ]; then - echo "tmp file $tf still exists." - exit 1 - fi - touch "$tf" || exit 1 - chmod 600 "$tf" || exit 1 -} - -if echo "$RANDOM" | grep '[^0-9]' > /dev/null; then - RANDOM=`date +%S` -fi - pcode() { tf=$1 - SSVNC_PROXY=$proxy; export SSVNC_PROXY - SSVNC_DEST="$host:$port"; export SSVNC_DEST + PPROXY_PROXY=$proxy; export PPROXY_PROXY + PPROXY_DEST="$host:$port"; export PPROXY_DEST cod='#!/usr/bin/perl -# A hack to glue stunnel to a Web proxy for client connections. +# A hack to glue stunnel to a Web proxy or SOCKS for client connections. use IO::Socket::INET; -my ($first, $second) = split(/,/, $ENV{SSVNC_PROXY}); +my ($first, $second) = split(/,/, $ENV{PPROXY_PROXY}); my ($proxy_host, $proxy_port) = split(/:/, $first); -my $connect = $ENV{SSVNC_DEST}; +my $connect = $ENV{PPROXY_DEST}; -print STDERR "\nperl script for web proxing:\n"; +print STDERR "\nPPROXY v0.0: a tool for Web proxies and SOCKS connections.\n"; print STDERR "proxy_host: $proxy_host\n"; print STDERR "proxy_port: $proxy_port\n"; print STDERR "proxy_connect: $connect\n"; my $listen_handle = ""; -if ($ENV{SSVNC_LISTEN} != "") { +if ($ENV{PPROXY_LISTEN} != "") { my $listen_sock = IO::Socket::INET->new( Listen => 2, LocalAddr => "localhost", - LocalPort => $ENV{SSVNC_LISTEN}, - Proto => "tcp"); + LocalPort => $ENV{PPROXY_LISTEN}, + Proto => "tcp" + ); if (! $listen_sock) { die "perl proxy: $!\n"; } @@ -625,7 +710,8 @@ if ($ENV{SSVNC_LISTEN} != "") { my $sock = IO::Socket::INET->new( PeerAddr => $proxy_host, PeerPort => $proxy_port, - Proto => "tcp"); + Proto => "tcp" +); if (! $sock) { unlink($0); @@ -633,24 +719,77 @@ if (! $sock) { } my $con = ""; -if ($second ne "") { +my $con0 = ""; +if ($ENV{PPROXY_SOCKS} ne "") { + $second = ""; + my ($h, $p) = split(/:/, $connect); + $con .= pack("C", 0x04); + $con .= pack("C", 0x01); + $con .= pack("n", $p); + + my $SOCKS_4a = 0; + if ($h eq "localhost" || $h eq "127.0.0.1") { + $con .= pack("C", 127); + $con .= pack("C", 0); + $con .= pack("C", 0); + $con .= pack("C", 1); + } elsif ($h =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) { + $con .= pack("C", $1); + $con .= pack("C", $2); + $con .= pack("C", $3); + $con .= pack("C", $4); + } else { + $con .= pack("C", 0); + $con .= pack("C", 0); + $con .= pack("C", 0); + $con .= pack("C", 3); + $SOCKS_4a = 1; + } + + $con .= "nobody"; + $con .= pack("C", 0); + + if ($SOCKS_4a) { + $con .= $h; + $con .= pack("C", 0); + } + $con0 = "SOCKS4 via $proxy_host:$proxy_port to $h:$p\n\n"; + +} elsif ($second ne "") { $con = "CONNECT $second HTTP/1.1\r\n"; $con .= "Host: $second\r\n\r\n"; + $con0 = $con; } else { $con = "CONNECT $connect HTTP/1.1\r\n"; $con .= "Host: $connect\r\n\r\n"; + $con0 = $con; } -print STDERR "proxy_request1:\n$con"; +print STDERR "proxy_request1:\n$con0"; print $sock $con; unlink($0); my $rep = ""; -while ($rep !~ /\r\n\r\n/) { - my $c = getc($sock); - print STDERR $c; - $rep .= $c; +if ($ENV{PPROXY_SOCKS} ne "") { + $rep = "HTTP/1.0 200"; + for (my $i = 0; $i < 8; $i++) { + my $c; + sysread($sock, $c, 1); + my $s = unpack("C", $c); + if ($i == 0) { + $rep = "" if $s != 0x0; + } elsif ($i == 1) { + $rep = "" if $s != 0x5a; + } + } +} else { + while ($rep !~ /\r\n\r\n/) { + my $c; + sysread($sock, $c, 1); + print STDERR $c; + $rep .= $c; + } } if ($rep !~ m,HTTP/.* 200,) { die "proxy error: $rep\n"; @@ -665,7 +804,8 @@ if ($second ne "") { $rep = ""; while ($rep !~ /\r\n\r\n/) { - my $c = getc($sock); + my $c; + sysread($sock, $c, 1); print STDERR $c; $rep .= $c; } @@ -743,8 +883,8 @@ if [ "X$proxy" != "X" ]; then if [ "X$showcert" != "X1" -a "X$direct_connect" = "X" ]; then if uname | grep Darwin >/dev/null; then nd=`expr $use + 333` - SSVNC_LISTEN=$nd - export SSVNC_LISTEN + PPROXY_LISTEN=$nd + export PPROXY_LISTEN $ptmp 2>/dev/null & sleep 3 host="localhost" @@ -762,8 +902,8 @@ fi if [ "X$showcert" = "X1" ]; then if [ "X$proxy" != "X" ]; then - SSVNC_LISTEN=$use - export SSVNC_LISTEN + PPROXY_LISTEN=$use + export PPROXY_LISTEN $ptmp 2>/dev/null & sleep 3 host="localhost" @@ -774,24 +914,29 @@ if [ "X$showcert" = "X1" ]; then fi if [ "X$direct_connect" != "X" ]; then - echo "" - echo "Running viewer for direct connection:" - echo "" - echo "** NOTE: THERE WILL BE NO SSL OR SSH ENCRYPTION **" - echo "" - if type printf > /dev/null 2>&1; then + if [ "X$getport" = "X" ]; then + echo "" + echo "Running viewer for direct connection:" + echo "" + echo "** NOTE: THERE WILL BE NO SSL OR SSH ENCRYPTION **" + echo "" + fi + if [ "X$SSVNC_NO_ENC_WARN" != "X" ]; then + sleep 1 + elif type printf > /dev/null 2>&1; then printf "Are you sure you want to continue? [y]/n " + read x else echo -n "Are you sure you want to continue? [y]/n " + read x fi - read x if [ "X$x" = "Xn" ]; then exit 1 fi echo "" if [ "X$ptmp" != "X" ]; then - SSVNC_LISTEN=$use - export SSVNC_LISTEN + PPROXY_LISTEN=$use + export PPROXY_LISTEN $ptmp & if [ "X$reverse" = "X" ]; then sleep 2 @@ -816,8 +961,6 @@ if [ "X$direct_connect" != "X" ]; then exit $? fi -##debug = 7 -## debug = 6 tmp=/tmp/ss_vncviewer${RANDOM}.$$ mytmp "$tmp" diff --git a/classes/ssl/tightvnc-1.3dev7_javasrc-vncviewer-ssl.patch b/classes/ssl/tightvnc-1.3dev7_javasrc-vncviewer-ssl.patch Binary files differindex f438655..0ce4474 100644 --- a/classes/ssl/tightvnc-1.3dev7_javasrc-vncviewer-ssl.patch +++ b/classes/ssl/tightvnc-1.3dev7_javasrc-vncviewer-ssl.patch diff --git a/classes/ssl/ultra.vnc b/classes/ssl/ultra.vnc new file mode 100644 index 0000000..23b6a31 --- /dev/null +++ b/classes/ssl/ultra.vnc @@ -0,0 +1,27 @@ +<!-- + index.vnc - default HTML page for TightVNC Java viewer applet, to be + used with Xvnc. On any file ending in .vnc, the HTTP server embedded in + Xvnc will substitute the following variables when preceded by a dollar: + USER, DESKTOP, DISPLAY, APPLETWIDTH, APPLETHEIGHT, WIDTH, HEIGHT, PORT, + PARAMS. Use two dollar signs ($$) to get a dollar sign in the generated + HTML page. + + NOTE: the $PARAMS variable is not supported by the standard VNC, so + make sure you have TightVNC on the server side, if you're using this + variable. +--> + +<HTML> +<TITLE> +$USER's $DESKTOP desktop ($DISPLAY) +</TITLE> +<APPLET CODE=VncViewer.class ARCHIVE=UltraViewerSSL.jar + WIDTH=$APPLETWIDTH HEIGHT=$APPLETHEIGHT> +<param name=PORT value=$PORT> +<param name="Open New Window" value=yes> +<param name="ignoreMSLogonCheck" value=yes> +$PARAMS +</APPLET> +<BR> +<A href="http://www.ultravnc.com/">UltraVNC site</A> +</HTML> diff --git a/classes/ssl/ultrasigned.vnc b/classes/ssl/ultrasigned.vnc new file mode 100644 index 0000000..f7c08f8 --- /dev/null +++ b/classes/ssl/ultrasigned.vnc @@ -0,0 +1,27 @@ +<!-- + index.vnc - default HTML page for TightVNC Java viewer applet, to be + used with Xvnc. On any file ending in .vnc, the HTTP server embedded in + Xvnc will substitute the following variables when preceded by a dollar: + USER, DESKTOP, DISPLAY, APPLETWIDTH, APPLETHEIGHT, WIDTH, HEIGHT, PORT, + PARAMS. Use two dollar signs ($$) to get a dollar sign in the generated + HTML page. + + NOTE: the $PARAMS variable is not supported by the standard VNC, so + make sure you have TightVNC on the server side, if you're using this + variable. +--> + +<HTML> +<TITLE> +$USER's $DESKTOP desktop ($DISPLAY) +</TITLE> +<APPLET CODE=VncViewer.class ARCHIVE=SignedUltraViewerSSL.jar + WIDTH=$APPLETWIDTH HEIGHT=$APPLETHEIGHT> +<param name=PORT value=$PORT> +<param name="Open New Window" value=yes> +<param name="ignoreMSLogonCheck" value=yes> +$PARAMS +</APPLET> +<BR> +<A href="http://www.ultravnc.com/">UltraVNC site</A> +</HTML> diff --git a/classes/ssl/ultravnc-102-JavaViewer-ssl-etc.patch b/classes/ssl/ultravnc-102-JavaViewer-ssl-etc.patch new file mode 100644 index 0000000..ceef727 --- /dev/null +++ b/classes/ssl/ultravnc-102-JavaViewer-ssl-etc.patch @@ -0,0 +1,2323 @@ +diff -Naur JavaViewer.orig/ButtonPanel.java JavaViewer/ButtonPanel.java +--- JavaViewer.orig/ButtonPanel.java 2004-12-12 20:51:02.000000000 -0500 ++++ JavaViewer/ButtonPanel.java 2007-05-16 15:50:54.000000000 -0400 +@@ -163,9 +163,12 @@ + } + else if (evt.getSource() == ftpButton) + { ++// begin runge/x11vnc ++ viewer.ftp.setSavedLocations(); ++// end runge/x11vnc + viewer.ftp.setVisible(!viewer.ftp.isVisible()); + viewer.rfb.readServerDriveList(); +- ++ + } + } + } +diff -Naur JavaViewer.orig/FTPFrame.java JavaViewer/FTPFrame.java +--- JavaViewer.orig/FTPFrame.java 2005-03-15 23:53:14.000000000 -0500 ++++ JavaViewer/FTPFrame.java 2007-05-16 16:05:15.000000000 -0400 +@@ -26,6 +26,10 @@ + import java.util.Vector; + import javax.swing.*; + ++// begin runge/x11vnc ++import java.util.Arrays; ++// end runge/x11vnc ++ + + /* + * Created on Feb 25, 2004 +@@ -80,6 +84,17 @@ + private File localSelection = null; // Holds the currently selected local file + private String remoteSelection = null; // Holds the currently selected remote file + public String selectedTable = null; ++ ++// begin runge/x11vnc ++ private javax.swing.JButton viewButton = null; ++ public File saveLocalDirectory = null; ++ public long saveLocalDirectoryTime = 0; ++ public int saveLocalDirectoryCount = 0; ++ public String saveRemoteDirectory = null; ++ public long saveRemoteDirectoryTime = 0; ++ public int saveRemoteDirectoryCount = 0; ++ private boolean localCurrentIsDir = true; ++// end runge/x11vnc + + // sf@2004 - Separate directories and files for better lisibility + private ArrayList DirsList; +@@ -125,11 +140,59 @@ + + void refreshRemoteLocation() + { ++ + remoteList.clear(); + remoteFileTable.setListData(remoteList); ++System.out.println("refreshRemoteLocation '" + remoteLocation.getText() + "'"); // runge/x11vnc + viewer.rfb.readServerDirectory(remoteLocation.getText()); + } + ++// begin runge/x11vnc ++ public void setSavedLocations() { ++ saveLocalDirectory = currentLocalDirectory; ++ saveLocalDirectoryTime = System.currentTimeMillis(); ++ saveLocalDirectoryCount = 0; ++ ++ if (remoteLocation != null) { ++ saveRemoteDirectory = remoteLocation.getText(); ++System.out.println("RemoteSave '" + saveRemoteDirectory + "'"); ++ } ++ saveRemoteDirectoryTime = System.currentTimeMillis(); ++ saveRemoteDirectoryCount = 0; ++ } ++ ++ private File saveLocalHack(File dir) { ++ saveLocalDirectoryCount++; ++System.out.println("L " + saveLocalDirectoryCount + " dt: " + (System.currentTimeMillis() - saveLocalDirectoryTime) + " - " + saveLocalDirectory); ++ if (System.currentTimeMillis() > saveLocalDirectoryTime + 2000 || saveLocalDirectoryCount > 2) { ++ saveLocalDirectory = null; ++ } ++ if (saveLocalDirectory != null) { ++ currentLocalDirectory = saveLocalDirectory; ++ localLocation.setText(saveLocalDirectory.toString()); ++ return saveLocalDirectory; ++ } else { ++ return dir; ++ } ++ } ++ ++ private String saveRemoteHack(String indrive) { ++ saveRemoteDirectoryCount++; ++System.out.println("R " + saveRemoteDirectoryCount + " - " + saveRemoteDirectory); ++ if (saveRemoteDirectory != null && saveRemoteDirectoryCount > 1) { ++ saveRemoteDirectory = null; ++ } ++ if (saveRemoteDirectory != null) { ++ if (! saveRemoteDirectory.equals("")) { ++System.out.println("saveRemoteHack setText + refreshRemoteLocation '" + saveRemoteDirectory + "'"); ++ return saveRemoteDirectory; ++ } ++ } ++ return indrive; ++ } ++// end runge/x11vnc ++ ++ + /* + * Prints the list of drives on the remote directory and returns a String[]. + * str takes as string like A:fC:lD:lE:lF:lG:cH:c +@@ -185,6 +248,7 @@ + stopButton.setVisible(true); + stopButton.setEnabled(true); + receiveButton.setEnabled(false); ++ viewButton.setEnabled(false); // runge/x11vnc + remoteTopButton.setEnabled(false); + sendButton.setEnabled(false); + remoteFileTable.setEnabled(false); +@@ -207,6 +271,7 @@ + stopButton.setVisible(false); + stopButton.setEnabled(false); + receiveButton.setEnabled(true); ++ viewButton.setEnabled(true); // runge/x11vnc + remoteTopButton.setEnabled(true); + sendButton.setEnabled(true); + remoteFileTable.setEnabled(true); +@@ -405,6 +470,7 @@ + buttonPanel = new javax.swing.JPanel(); + buttonPanel.setLayout(null); + buttonPanel.add(getReceiveButton(), null); ++ buttonPanel.add(getViewButton(), null); // runge/x11vnc + buttonPanel.add(getNewFolderButton(), null); + buttonPanel.add(getCloseButton(), null); + buttonPanel.add(getDeleteButton(), null); +@@ -422,7 +488,7 @@ + private javax.swing.JButton getSendButton() { + if (sendButton == null) { + sendButton = new javax.swing.JButton(); +- sendButton.setBounds(20, 30, 97, 25); ++ sendButton.setBounds(15, 30, 107, 25); // runge/x11vnc + sendButton.setText("Send >>"); + sendButton.setName("sendButton"); + sendButton.addActionListener(this); +@@ -438,7 +504,7 @@ + private javax.swing.JButton getReceiveButton() { + if (receiveButton == null) { + receiveButton = new javax.swing.JButton(); +- receiveButton.setBounds(20, 60, 97, 25); ++ receiveButton.setBounds(15, 60, 107, 25); // runge/x11vnc + receiveButton.setText("<< Receive"); + receiveButton.setName("receiveButton"); + receiveButton.addActionListener(this); +@@ -453,7 +519,7 @@ + private javax.swing.JButton getDeleteButton() { + if (deleteButton == null) { + deleteButton = new javax.swing.JButton(); +- deleteButton.setBounds(20, 110, 97, 25); ++ deleteButton.setBounds(15, 110, 107, 25); // runge/x11vnc + deleteButton.setText("Delete File"); + deleteButton.setName("deleteButton"); + deleteButton.addActionListener(this); +@@ -468,7 +534,7 @@ + private javax.swing.JButton getNewFolderButton() { + if (newFolderButton == null) { + newFolderButton = new javax.swing.JButton(); +- newFolderButton.setBounds(20, 140, 97, 25); ++ newFolderButton.setBounds(15, 140, 107, 25); // runge/x11vnc + newFolderButton.setText("New Folder"); + newFolderButton.setName("newFolderButton"); + newFolderButton.addActionListener(this); +@@ -476,6 +542,24 @@ + return newFolderButton; + } + ++// begin runge/x11vnc ++ /** ++ * This method initializes viewButton ++ * ++ * @return javax.swing.JButton ++ */ ++ private javax.swing.JButton getViewButton() { ++ if (viewButton == null) { ++ viewButton = new javax.swing.JButton(); ++ viewButton.setBounds(15, 170, 107, 25); ++ viewButton.setText("View File"); ++ viewButton.setName("viewButton"); ++ viewButton.addActionListener(this); ++ } ++ return viewButton; ++ } ++// end runge/x11vnc ++ + /** + * This method initializes stopButton + * +@@ -486,7 +570,7 @@ + if (stopButton == null) + { + stopButton = new javax.swing.JButton(); +- stopButton.setBounds(20, 200, 97, 25); ++ stopButton.setBounds(15, 200, 107, 25); // runge/x11vnc + stopButton.setText("Stop"); + stopButton.setName("stopButton"); + stopButton.addActionListener(this); +@@ -503,7 +587,7 @@ + private javax.swing.JButton getCloseButton() { + if (closeButton == null) { + closeButton = new javax.swing.JButton(); +- closeButton.setBounds(20, 325, 97, 25); ++ closeButton.setBounds(15, 325, 107, 25); // runge/x11vnc + closeButton.setText("Close"); + closeButton.setName("closeButton"); + closeButton.addActionListener(this); +@@ -829,12 +913,19 @@ + { + doReceive(); + } ++// begin runge/x11vnc ++ else if (evt.getSource() == viewButton) ++ { ++ doView(); ++ } ++// end runge/x11vnc + else if (evt.getSource() == localDrivesComboBox) + { + changeLocalDrive(); + } + else if (evt.getSource() == remoteDrivesComboBox) + { ++System.out.println("remoteDrivesComboBox"); // runge/x11vnc + changeRemoteDrive(); + remoteList.clear(); + remoteFileTable.setListData(remoteList); +@@ -845,6 +936,7 @@ + } + else if (evt.getSource() == remoteTopButton) + { ++System.out.println("remoteTopButton"); // runge/x11vnc + changeRemoteDrive(); + } + else if(evt.getSource() == deleteButton) +@@ -979,6 +1071,56 @@ + viewer.rfb.requestRemoteFile(remoteFileName,localDestinationPath); + } + ++// begin runge/x11vnc ++ private void doView() ++ { ++ System.out.println("View Button Pressed"); ++ ++ if (selectedTable == null) { ++ return; ++ } ++ if (selectedTable.equals("remote")) { ++ viewRemote(); ++ } else if (selectedTable.equals("local")) { ++ viewLocal(); ++ } ++ } ++ ++ private File doReceiveTmp() ++ { ++ ++ if (remoteFileTable == null) { ++ return null; ++ } ++ String sFileName = ((String) this.remoteFileTable.getSelectedValue()); ++ if (sFileName == null) { ++ return null; ++ } ++ ++ // sf@2004 - Directory can't be transfered ++ if (sFileName.substring(0, 2).equals(" [") && sFileName.substring((sFileName.length() - 1), sFileName.length()).equals("]")) ++ { ++ return null; ++ } ++ ++ File tmp = null; ++ try { ++ tmp = File.createTempFile("ULTRAFTP", ".txt"); ++ } catch (Exception e) { ++ return null; ++ } ++ ++ //updateHistory("Downloaded " + localSelection.toString()); ++ String remoteFileName = this.remoteLocation.getText(); ++ remoteFileName+= ((String) this.remoteFileTable.getSelectedValue()).substring(1); ++ ++ String localDestinationPath = tmp.getAbsolutePath(); ++ viewer.rfb.requestRemoteFile(remoteFileName,localDestinationPath); ++ System.out.println("ReceiveTmp: " + localDestinationPath); ++ return tmp; ++ } ++// end runge/x11vnc ++ + private void doSend() + { + System.out.println("Send Button Pressed"); +@@ -1035,8 +1177,11 @@ + + if (!updateDriveList) { + String drive = remoteDrivesComboBox.getSelectedItem().toString().substring(0,1)+ ":\\"; ++System.out.println("changeRemoteDrive-A " + drive); // runge/x11vnc ++ drive = saveRemoteHack(drive); + viewer.rfb.readServerDirectory(drive); + remoteLocation.setText(drive); ++System.out.println("changeRemoteDrive-B " + drive); // runge/x11vnc + } + remoteList.clear(); + remoteFileTable.setListData(remoteList); +@@ -1048,6 +1193,7 @@ + private void changeLocalDrive() + { + File currentDrive = new File(localDrivesComboBox.getSelectedItem().toString()); ++System.out.println("changeLocalDrive " + currentDrive.toString()); // runge/x11vnc + if(currentDrive.canRead()) + { + localSelection = null; +@@ -1060,6 +1206,7 @@ + localStatus.setText("WARNING: Drive " + localDrivesComboBox.getSelectedItem().toString()); + connectionStatus.setText(" > WARNING - Local Drive unavailable (possibly restricted access or media not present)"); + } ++ + } + /** + * Determines which FileTable was double-clicked and updates the table +@@ -1101,7 +1248,7 @@ + String name = (remoteFileTable.getSelectedValue().toString()).substring(1); + if( !name.substring(0, 2).equals(" [")) + remoteSelection = remoteLocation.getText() + name.substring(0, name.length()); +- ++ + } + + /* +@@ -1115,10 +1262,38 @@ + localFileTable.setBackground(new Color(255, 255, 255)); + File currentSelection = new File(currentLocalDirectory, getTrimmedSelection()); + +- if(currentSelection.isFile()) ++// begin runge/x11vnc ++ // localSelection = currentSelection.getAbsoluteFile(); ++ if(currentSelection.isFile()) { + localSelection = currentSelection.getAbsoluteFile(); ++ localCurrentIsDir = false; ++ } else { ++ localCurrentIsDir = true; ++ } ++// end runge/x11vnc + + } ++ ++// begin runge/x11vnc ++ private void viewRemote() { ++ File tmp = doReceiveTmp(); ++ if (tmp == null) { ++ return; ++ } ++ TextViewer tv = new TextViewer("Remote: " + remoteSelection, tmp, true); ++ } ++ private void viewLocal() { ++ if (localSelection == null) { ++ return; ++ } ++ if (localCurrentIsDir) { ++ return; ++ } ++ File loc = new File(localSelection.toString()); ++ TextViewer tv = new TextViewer("Local: " + localSelection.toString(), loc, false); ++ } ++// end runge/x11vnc ++ + /** + * Updates the Remote File Table based on selection. Called from mouseClicked handler + */ +@@ -1149,6 +1324,7 @@ + remoteSelection = remoteLocation.getText() + name.substring(0, name.length()); + drive = remoteLocation.getText(); + // ?? ++ viewRemote(); // runge/x11vnc + } + else + { +@@ -1163,6 +1339,7 @@ + } + //remoteLocation.setText(drive); + } ++ + /** + * Updates the Local File Table based on selection. Called from MouseClicked handler + */ +@@ -1188,6 +1365,7 @@ + else if (currentSelection.isFile()) + { + localSelection = currentSelection.getAbsoluteFile(); ++ viewLocal(); // runge/x11vnc + } + else if (currentSelection.isDirectory()) + { +@@ -1247,9 +1425,20 @@ + */ + public void changeLocalDirectory(File dir) + { ++ dir = saveLocalHack(dir); // runge/x11vnc ++ + currentLocalDirectory = dir; // Updates Global + File allFiles[] = dir.listFiles(); // Reads files + String[] contents = dir.list(); ++// begin runge/x11vnc ++System.out.println("changeLocalDirectory: " + dir.toString()); ++ if (contents != null) { ++ java.util.Arrays.sort(contents, String.CASE_INSENSITIVE_ORDER); ++ for (int i = 0; i < contents.length; i++) { ++ allFiles[i] = new File(dir, contents[i]); ++ } ++ } ++// end runge/x11vnc + + localList.clear(); + localList.addElement(" [..]"); +@@ -1296,3 +1485,135 @@ + } + + } // @jve:visual-info decl-index=0 visual-constraint="10,10" ++ ++// begin runge/x11vnc ++class TextViewer extends JFrame implements ActionListener { ++ ++ JTextArea textArea = new JTextArea(35, 80); ++ File file = null; ++ JButton refreshButton; ++ JButton dismissButton; ++ Timer tim = null; ++ int rcnt = 0; ++ int tms = 250; ++ boolean delete_it = false; ++ ++ public TextViewer(String s, File f, boolean d) { ++ ++ delete_it = d; ++ file = f; ++ ++ JScrollPane scrollPane = new JScrollPane(textArea, ++ JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, ++ JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); ++ ++ textArea.setEditable(false); ++ textArea.setFont(new Font("Monospaced", Font.PLAIN, 12)); ++ ++ ++ refreshButton = new JButton(); ++ refreshButton.setText("Reload"); ++ refreshButton.setName("refreshButton"); ++ refreshButton.addActionListener(this); ++ ++ dismissButton = new JButton(); ++ dismissButton.setText("Dismiss"); ++ dismissButton.setName("dismissButton"); ++ dismissButton.addActionListener(this); ++ ++ JPanel buttons = new JPanel(); ++ buttons.setLayout(new BorderLayout()); ++ buttons.add(refreshButton, BorderLayout.WEST); ++ buttons.add(dismissButton, BorderLayout.EAST); ++ ++ JPanel content = new JPanel(); ++ content.setLayout(new BorderLayout()); ++ content.add(scrollPane, BorderLayout.CENTER); ++ content.add(buttons, BorderLayout.SOUTH); ++ ++ ActionListener tsk = new ActionListener() { ++ public void actionPerformed(ActionEvent evt) { ++ // System.out.println("tsk"); ++ refresh(); ++ } ++ }; ++ tim = new Timer(tms, tsk); ++ tim.start(); ++ ++ this.setContentPane(content); ++ this.setTitle("TextViewer - " + s); ++ this.pack(); ++ this.setVisible(true); ++ } ++ ++ private void refresh() { ++ ++ rcnt++; ++ if (rcnt * tms > 3000 && tim != null) { ++ tim.stop(); ++ tim = null; ++ } ++ BufferedReader input = null; ++ StringBuffer contents = new StringBuffer(); ++ try { ++ if (input == null) { ++ input = new BufferedReader(new FileReader(file)); ++ } ++ String line = null; ++ int i = 0; ++ while (( line = input.readLine()) != null) { ++ if (i == 0) { ++ // System.out.println("read"); ++ } ++ i++; ++ contents.append(line); ++ contents.append(System.getProperty("line.separator")); ++ } ++ } catch (Exception e) { ++ ; ++ } finally { ++ try { ++ if (input != null) { ++ input.close(); ++ input = null; ++ } ++ } catch (Exception e) { ++ ; ++ } ++ } ++ ++ textArea.setText(contents.toString()); ++ textArea.setCaretPosition(0); ++ } ++ ++ public void actionPerformed(ActionEvent evt) { ++ ++ if (evt.getSource() == refreshButton) { ++ refresh(); ++ } ++ if (evt.getSource() == dismissButton) { ++ cleanse(); ++ this.dispose(); ++ } ++ } ++ ++ private void cleanse() { ++ if (delete_it && file != null) { ++ try { ++ file.delete(); ++ file = null; ++ } catch (Exception e) { ++ ; ++ } ++ } ++ } ++ ++ protected void finalize() throws Throwable { ++ try { ++ cleanse(); ++ } finally { ++ super.finalize(); ++ } ++ } ++} ++// end runge/x11vnc +diff -Naur JavaViewer.orig/OptionsFrame.java JavaViewer/OptionsFrame.java +--- JavaViewer.orig/OptionsFrame.java 2005-11-21 18:50:16.000000000 -0500 ++++ JavaViewer/OptionsFrame.java 2007-05-13 22:18:30.000000000 -0400 +@@ -144,7 +144,10 @@ + choices[jpegQualityIndex].select("6"); + choices[cursorUpdatesIndex].select("Enable"); + choices[useCopyRectIndex].select("Yes"); +- choices[eightBitColorsIndex].select("64"); ++// begin runge/x11vnc ++// choices[eightBitColorsIndex].select("64"); ++ choices[eightBitColorsIndex].select("Full"); ++// end runge/x11vnc + choices[mouseButtonIndex].select("Normal"); + choices[viewOnlyIndex].select("No"); + choices[shareDesktopIndex].select("Yes"); +diff -Naur JavaViewer.orig/RfbProto.java JavaViewer/RfbProto.java +--- JavaViewer.orig/RfbProto.java 2006-05-24 15:14:40.000000000 -0400 ++++ JavaViewer/RfbProto.java 2007-05-16 15:57:07.000000000 -0400 +@@ -199,6 +199,10 @@ + // playback. + int numUpdatesInSession; + ++// begin runge/x11vnc ++ int readServerDriveListCnt = -1; ++ long readServerDriveListTime = 0; ++// end runge/x11vnc + // + // Constructor. Make TCP connection to RFB server. + // +@@ -207,7 +211,27 @@ + viewer = v; + host = h; + port = p; +- sock = new Socket(host, port); ++// begin runge/x11vnc ++// sock = new Socket(host, port); ++ if (! viewer.disableSSL) { ++ System.out.println("new SSLSocketToMe"); ++ SSLSocketToMe ssl; ++ try { ++ ssl = new SSLSocketToMe(host, port, v); ++ } catch (Exception e) { ++ throw new IOException(e.getMessage()); ++ } ++ ++ try { ++ sock = ssl.connectSock(); ++ } catch (Exception es) { ++ throw new IOException(es.getMessage()); ++ } ++ } else { ++ sock = new Socket(host, port); ++ } ++// end runge/x11vnc ++ + is = + new DataInputStream( + new BufferedInputStream(sock.getInputStream(), 16384)); +@@ -1263,11 +1287,47 @@ + || dwFileAttributes == 369623040) + { + fileName = " [" + fileName + "]"; +- remoteDirsList.add(fileName); // sf@2004 ++// begin runge/x11vnc ++// remoteDirsList.add(fileName); // sf@2004 ++ int i = -1; ++ String t1 = fileName.toLowerCase(); ++ for (int j = 0; j < remoteDirsList.size(); j++) { ++ String t = (String) remoteDirsList.get(j); ++ String t2 = t.toLowerCase(); ++ if (t1.compareTo(t2) < 0) { ++ i = j; ++ break; ++ } ++ } ++ if (i >= 0) { ++ remoteDirsList.add(i, fileName); ++ } else { ++ remoteDirsList.add(fileName); ++ } ++// end runge/x11vnc + } + else + { +- remoteFilesList.add(" " + fileName); // sf@2004 ++// begin runge/x11vnc ++// remoteFilesList.add(" " + fileName); // sf@2004 ++ ++ fileName = " " + fileName; ++ int i = -1; ++ String t1 = fileName.toLowerCase(); ++ for (int j = 0; j < remoteFilesList.size(); j++) { ++ String t = (String) remoteFilesList.get(j); ++ String t2 = t.toLowerCase(); ++ if (t1.compareTo(t2) < 0) { ++ i = j; ++ break; ++ } ++ } ++ if (i >= 0) { ++ remoteFilesList.add(i, fileName); ++ } else { ++ remoteFilesList.add(fileName); ++ } ++// end runge/x11vnc + } + + // a.add(fileName); +@@ -1289,6 +1349,16 @@ + remoteDirsList.clear(); + remoteFilesList.clear(); + ++// begin runge/x11vnc ++ // Hack for double listing at startup... probably libvncserver bug.. ++ readServerDriveListCnt++; ++ if (readServerDriveListCnt == 2) { ++ if (System.currentTimeMillis() - readServerDriveListTime < 1500) { ++System.out.println("readServerDriveListCnt skip " + readServerDriveListCnt); ++ return; ++ } ++ } ++// end runge/x11vnc + viewer.ftp.printDirectory(a); + } + +@@ -1312,6 +1382,10 @@ + 0, + 0, + null); ++// begin runge/x11vnc ++ readServerDriveListCnt = 0; ++ readServerDriveListTime = System.currentTimeMillis(); ++// end runge/x11vnc + } + catch (IOException e) + { +diff -Naur JavaViewer.orig/SSLSocketToMe.java JavaViewer/SSLSocketToMe.java +--- JavaViewer.orig/SSLSocketToMe.java 1969-12-31 19:00:00.000000000 -0500 ++++ JavaViewer/SSLSocketToMe.java 2007-04-29 20:40:35.000000000 -0400 +@@ -0,0 +1,1421 @@ ++/* ++ * SSLSocketToMe.java: add SSL encryption to Java VNC Viewer. ++ * ++ * Copyright (c) 2006 Karl J. Runge <runge@karlrunge.com> ++ * All rights reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ * ++ */ ++ ++import java.net.*; ++import java.io.*; ++import javax.net.ssl.*; ++import java.util.*; ++ ++import java.security.*; ++import java.security.cert.*; ++import java.security.spec.*; ++import java.security.cert.Certificate; ++import java.security.cert.CertificateFactory; ++ ++import java.awt.*; ++import java.awt.event.*; ++ ++public class SSLSocketToMe { ++ ++ /* basic member data: */ ++ String host; ++ int port; ++ VncViewer viewer; ++ boolean debug = true; ++ ++ /* sockets */ ++ SSLSocket socket = null; ++ SSLSocketFactory factory; ++ ++ /* fallback for Proxy connection */ ++ boolean proxy_in_use = false; ++ boolean proxy_is_https = false; ++ boolean proxy_failure = false; ++ public DataInputStream is = null; ++ public OutputStream os = null; ++ ++ String proxy_dialog_host = null; ++ int proxy_dialog_port = 0; ++ ++ Socket proxySock; ++ DataInputStream proxy_is; ++ OutputStream proxy_os; ++ ++ /* trust contexts */ ++ SSLContext trustloc_ctx; ++ SSLContext trustall_ctx; ++ SSLContext trusturl_ctx; ++ SSLContext trustone_ctx; ++ ++ TrustManager[] trustAllCerts; ++ TrustManager[] trustUrlCert; ++ TrustManager[] trustOneCert; ++ ++ boolean use_url_cert_for_auth = true; ++ boolean user_wants_to_see_cert = true; ++ ++ /* cert(s) we retrieve from VNC server */ ++ java.security.cert.Certificate[] trustallCerts = null; ++ java.security.cert.Certificate[] trusturlCerts = null; ++ ++ byte[] hex2bytes(String s) { ++ byte[] bytes = new byte[s.length()/2]; ++ for (int i=0; i<s.length()/2; i++) { ++ int j = 2*i; ++ try { ++ int val = Integer.parseInt(s.substring(j, j+2), 16); ++ if (val > 127) { ++ val -= 256; ++ } ++ Integer I = new Integer(val); ++ bytes[i] = Byte.decode(I.toString()).byteValue(); ++ ++ } catch (Exception e) { ++ ; ++ } ++ } ++ return bytes; ++ } ++ ++ SSLSocketToMe(String h, int p, VncViewer v) throws Exception { ++ host = h; ++ port = p; ++ viewer = v; ++ ++ /* we will first try default factory for certification: */ ++ ++ factory = (SSLSocketFactory) SSLSocketFactory.getDefault(); ++ ++ dbg("SSL startup: " + host + " " + port); ++ ++ /* create trust managers used if initial handshake fails: */ ++ ++ trustAllCerts = new TrustManager[] { ++ /* ++ * this one accepts everything. ++ */ ++ new X509TrustManager() { ++ public java.security.cert.X509Certificate[] ++ getAcceptedIssuers() { ++ return null; ++ } ++ public void checkClientTrusted( ++ java.security.cert.X509Certificate[] certs, ++ String authType) { ++ /* empty */ ++ } ++ public void checkServerTrusted( ++ java.security.cert.X509Certificate[] certs, ++ String authType) { ++ /* empty */ ++ dbg("ALL: an untrusted connect to grab cert."); ++ } ++ } ++ }; ++ ++ trustUrlCert = new TrustManager[] { ++ /* ++ * this one accepts only the retrieved server cert ++ * by SSLSocket by this applet. ++ */ ++ new X509TrustManager() { ++ public java.security.cert.X509Certificate[] ++ getAcceptedIssuers() { ++ return null; ++ } ++ public void checkClientTrusted( ++ java.security.cert.X509Certificate[] certs, ++ String authType) throws CertificateException { ++ throw new CertificateException("No Clients"); ++ } ++ public void checkServerTrusted( ++ java.security.cert.X509Certificate[] certs, ++ String authType) throws CertificateException { ++ if (trusturlCerts == null) { ++ throw new CertificateException( ++ "No Trust url Certs array."); ++ } ++ if (trusturlCerts.length < 1) { ++ throw new CertificateException( ++ "No Trust url Certs."); ++ } ++ if (trusturlCerts.length > 1) { ++ int i; ++ boolean ok = true; ++ for (i = 0; i < trusturlCerts.length - 1; i++) { ++ if (! trusturlCerts[i].equals(trusturlCerts[i+1])) { ++ ok = false; ++ } ++ } ++ if (! ok) { ++ throw new CertificateException( ++ "Too many Trust url Certs: " ++ + trusturlCerts.length ++ ); ++ } ++ } ++ if (certs == null) { ++ throw new CertificateException( ++ "No this-certs array."); ++ } ++ if (certs.length < 1) { ++ throw new CertificateException( ++ "No this-certs Certs."); ++ } ++ if (certs.length > 1) { ++ int i; ++ boolean ok = true; ++ for (i = 0; i < certs.length - 1; i++) { ++ if (! certs[i].equals(certs[i+1])) { ++ ok = false; ++ } ++ } ++ if (! ok) { ++ throw new CertificateException( ++ "Too many this-certs: " ++ + certs.length ++ ); ++ } ++ } ++ if (! trusturlCerts[0].equals(certs[0])) { ++ throw new CertificateException( ++ "Server Cert Changed != URL."); ++ } ++ dbg("URL: trusturlCerts[0] matches certs[0]"); ++ } ++ } ++ }; ++ trustOneCert = new TrustManager[] { ++ /* ++ * this one accepts only the retrieved server cert ++ * by SSLSocket by this applet. ++ */ ++ new X509TrustManager() { ++ public java.security.cert.X509Certificate[] ++ getAcceptedIssuers() { ++ return null; ++ } ++ public void checkClientTrusted( ++ java.security.cert.X509Certificate[] certs, ++ String authType) throws CertificateException { ++ throw new CertificateException("No Clients"); ++ } ++ public void checkServerTrusted( ++ java.security.cert.X509Certificate[] certs, ++ String authType) throws CertificateException { ++ if (trustallCerts == null) { ++ throw new CertificateException( ++ "No Trust All Server Certs array."); ++ } ++ if (trustallCerts.length < 1) { ++ throw new CertificateException( ++ "No Trust All Server Certs."); ++ } ++ if (trustallCerts.length > 1) { ++ int i; ++ boolean ok = true; ++ for (i = 0; i < trustallCerts.length - 1; i++) { ++ if (! trustallCerts[i].equals(trustallCerts[i+1])) { ++ ok = false; ++ } ++ } ++ if (! ok) { ++ throw new CertificateException( ++ "Too many Trust All Server Certs: " ++ + trustallCerts.length ++ ); ++ } ++ } ++ if (certs == null) { ++ throw new CertificateException( ++ "No this-certs array."); ++ } ++ if (certs.length < 1) { ++ throw new CertificateException( ++ "No this-certs Certs."); ++ } ++ if (certs.length > 1) { ++ int i; ++ boolean ok = true; ++ for (i = 0; i < certs.length - 1; i++) { ++ if (! certs[i].equals(certs[i+1])) { ++ ok = false; ++ } ++ } ++ if (! ok) { ++ throw new CertificateException( ++ "Too many this-certs: " ++ + certs.length ++ ); ++ } ++ } ++ if (! trustallCerts[0].equals(certs[0])) { ++ throw new CertificateException( ++ "Server Cert Changed != TRUSTALL."); ++ } ++ dbg("ONE: trustallCerts[0] matches certs[0]"); ++ } ++ } ++ }; ++ ++ /* ++ * They are used: ++ * ++ * 1) to retrieve the server cert in case of failure to ++ * display it to the user. ++ * 2) to subsequently connect to the server if user agrees. ++ */ ++ ++ KeyManager[] mykey = null; ++ ++ if (viewer.oneTimeKey != null && viewer.oneTimeKey.equals("PROMPT")) { ++ ClientCertDialog d = new ClientCertDialog(); ++ viewer.oneTimeKey = d.queryUser(); ++ } ++ ++ if (viewer.oneTimeKey != null && viewer.oneTimeKey.indexOf(",") > 0) { ++ int idx = viewer.oneTimeKey.indexOf(","); ++ ++ String onetimekey = viewer.oneTimeKey.substring(0, idx); ++ byte[] key = hex2bytes(onetimekey); ++ String onetimecert = viewer.oneTimeKey.substring(idx+1); ++ byte[] cert = hex2bytes(onetimecert); ++ ++ KeyFactory kf = KeyFactory.getInstance("RSA"); ++ PKCS8EncodedKeySpec keysp = new PKCS8EncodedKeySpec ( key ); ++ PrivateKey ff = kf.generatePrivate (keysp); ++ //dbg("ff " + ff); ++ String cert_str = new String(cert); ++ ++ CertificateFactory cf = CertificateFactory.getInstance("X.509"); ++ Collection c = cf.generateCertificates(new ByteArrayInputStream(cert)); ++ Certificate[] certs = new Certificate[c.toArray().length]; ++ if (c.size() == 1) { ++ Certificate tmpcert = cf.generateCertificate(new ByteArrayInputStream(cert)); ++ //dbg("tmpcert" + tmpcert); ++ certs[0] = tmpcert; ++ } else { ++ certs = (Certificate[]) c.toArray(); ++ } ++ ++ KeyStore ks = KeyStore.getInstance("JKS"); ++ ks.load(null, null); ++ ks.setKeyEntry("onetimekey", ff, "".toCharArray(), certs); ++ String da = KeyManagerFactory.getDefaultAlgorithm(); ++ KeyManagerFactory kmf = KeyManagerFactory.getInstance(da); ++ kmf.init(ks, "".toCharArray()); ++ ++ mykey = kmf.getKeyManagers(); ++ } ++ ++ ++ /* trust loc certs: */ ++ try { ++ trustloc_ctx = SSLContext.getInstance("SSL"); ++ trustloc_ctx.init(mykey, null, new ++ java.security.SecureRandom()); ++ ++ } catch (Exception e) { ++ String msg = "SSL trustloc_ctx FAILED."; ++ dbg(msg); ++ throw new Exception(msg); ++ } ++ ++ /* trust all certs: */ ++ try { ++ trustall_ctx = SSLContext.getInstance("SSL"); ++ trustall_ctx.init(mykey, trustAllCerts, new ++ java.security.SecureRandom()); ++ ++ } catch (Exception e) { ++ String msg = "SSL trustall_ctx FAILED."; ++ dbg(msg); ++ throw new Exception(msg); ++ } ++ ++ /* trust url certs: */ ++ try { ++ trusturl_ctx = SSLContext.getInstance("SSL"); ++ trusturl_ctx.init(mykey, trustUrlCert, new ++ java.security.SecureRandom()); ++ ++ } catch (Exception e) { ++ String msg = "SSL trusturl_ctx FAILED."; ++ dbg(msg); ++ throw new Exception(msg); ++ } ++ ++ /* trust the one cert from server: */ ++ try { ++ trustone_ctx = SSLContext.getInstance("SSL"); ++ trustone_ctx.init(mykey, trustOneCert, new ++ java.security.SecureRandom()); ++ ++ } catch (Exception e) { ++ String msg = "SSL trustone_ctx FAILED."; ++ dbg(msg); ++ throw new Exception(msg); ++ } ++ } ++ ++ boolean browser_cert_match() { ++ String msg = "Browser URL accept previously accepted cert"; ++ ++ if (user_wants_to_see_cert) { ++ return false; ++ } ++ ++ if (trustallCerts != null && trusturlCerts != null) { ++ if (trustallCerts.length == 1 && trusturlCerts.length == 1) { ++ if (trustallCerts[0].equals(trusturlCerts[0])) { ++ System.out.println(msg); ++ return true; ++ } ++ } ++ } ++ return false; ++ } ++ ++ public void check_for_proxy() { ++ ++ boolean result = false; ++ ++ trusturlCerts = null; ++ proxy_in_use = false; ++ if (viewer.ignoreProxy) { ++ return; ++ } ++ ++ String ustr = "https://" + host + ":"; ++ if (viewer.httpsPort != null) { ++ ustr += viewer.httpsPort; ++ } else { ++ ustr += port; // hmmm ++ } ++ ustr += viewer.urlPrefix + "/check.https.proxy.connection"; ++ dbg("ustr is: " + ustr); ++ ++ ++ try { ++ URL url = new URL(ustr); ++ HttpsURLConnection https = (HttpsURLConnection) ++ url.openConnection(); ++ ++ https.setUseCaches(false); ++ https.setRequestMethod("GET"); ++ https.setRequestProperty("Pragma", "No-Cache"); ++ https.setRequestProperty("Proxy-Connection", ++ "Keep-Alive"); ++ https.setDoInput(true); ++ ++ https.connect(); ++ ++ trusturlCerts = https.getServerCertificates(); ++ if (trusturlCerts == null) { ++ dbg("set trusturlCerts to null..."); ++ } else { ++ dbg("set trusturlCerts to non-null"); ++ } ++ ++ if (https.usingProxy()) { ++ proxy_in_use = true; ++ proxy_is_https = true; ++ dbg("HTTPS proxy in use. There may be connection problems."); ++ } ++ Object output = https.getContent(); ++ https.disconnect(); ++ result = true; ++ ++ } catch(Exception e) { ++ dbg("HttpsURLConnection: " + e.getMessage()); ++ } ++ ++ if (proxy_in_use) { ++ return; ++ } ++ ++ ustr = "http://" + host + ":" + port; ++ ustr += viewer.urlPrefix + "/index.vnc"; ++ ++ try { ++ URL url = new URL(ustr); ++ HttpURLConnection http = (HttpURLConnection) ++ url.openConnection(); ++ ++ http.setUseCaches(false); ++ http.setRequestMethod("GET"); ++ http.setRequestProperty("Pragma", "No-Cache"); ++ http.setRequestProperty("Proxy-Connection", ++ "Keep-Alive"); ++ http.setDoInput(true); ++ ++ http.connect(); ++ ++ if (http.usingProxy()) { ++ proxy_in_use = true; ++ proxy_is_https = false; ++ dbg("HTTP proxy in use. There may be connection problems."); ++ } ++ Object output = http.getContent(); ++ http.disconnect(); ++ ++ } catch(Exception e) { ++ dbg("HttpURLConnection: " + e.getMessage()); ++ } ++ } ++ ++ public Socket connectSock() throws IOException { ++ ++ /* ++ * first try a https connection to detect a proxy, and ++ * also grab the VNC server cert. ++ */ ++ check_for_proxy(); ++ ++ if (viewer.trustAllVncCerts) { ++ dbg("viewer.trustAllVncCerts-0 using trustall_ctx"); ++ factory = trustall_ctx.getSocketFactory(); ++ } else if (use_url_cert_for_auth && trusturlCerts != null) { ++ dbg("using trusturl_ctx"); ++ factory = trusturl_ctx.getSocketFactory(); ++ } else { ++ dbg("using trustloc_ctx"); ++ factory = trustloc_ctx.getSocketFactory(); ++ } ++ ++ socket = null; ++ try { ++ if (proxy_in_use && viewer.forceProxy) { ++ throw new Exception("forcing proxy (forceProxy)"); ++ } else if (viewer.CONNECT != null) { ++ throw new Exception("forcing CONNECT"); ++ } ++ ++ socket = (SSLSocket) factory.createSocket(host, port); ++ ++ } catch (Exception esock) { ++ dbg("esock: " + esock.getMessage()); ++ if (proxy_in_use || viewer.CONNECT != null) { ++ proxy_failure = true; ++ if (proxy_in_use) { ++ dbg("HTTPS proxy in use. Trying to go with it."); ++ } else { ++ dbg("viewer.CONNECT reverse proxy in use. Trying to go with it."); ++ } ++ try { ++ socket = proxy_socket(factory); ++ } catch (Exception e) { ++ dbg("err proxy_socket: " + e.getMessage()); ++ } ++ } ++ } ++ ++ try { ++ socket.startHandshake(); ++ dbg("Server Connection Verified on 1st try."); ++ ++ java.security.cert.Certificate[] currentTrustedCerts; ++ BrowserCertsDialog bcd; ++ ++ SSLSession sess = socket.getSession(); ++ currentTrustedCerts = sess.getPeerCertificates(); ++ ++ if (viewer.trustAllVncCerts) { ++ dbg("viewer.trustAllVncCerts-1"); ++ } else if (currentTrustedCerts == null || currentTrustedCerts.length < 1) { ++ socket.close(); ++ socket = null; ++ throw new SSLHandshakeException("no current certs"); ++ } ++ ++ String serv = ""; ++ try { ++ CertInfo ci = new CertInfo(currentTrustedCerts[0]); ++ serv = ci.get_certinfo("CN"); ++ } catch (Exception e) { ++ ; ++ } ++ ++ if (viewer.trustAllVncCerts) { ++ dbg("viewer.trustAllVncCerts-2"); ++ user_wants_to_see_cert = false; ++ } else if (viewer.trustUrlVncCert) { ++ dbg("viewer.trustUrlVncCert-1"); ++ user_wants_to_see_cert = false; ++ } else { ++ bcd = new BrowserCertsDialog(serv, host + ":" + port); ++ bcd.queryUser(); ++ if (bcd.showCertDialog) { ++ String msg = "user wants to see cert"; ++ dbg(msg); ++ user_wants_to_see_cert = true; ++ throw new SSLHandshakeException(msg); ++ } else { ++ user_wants_to_see_cert = false; ++ dbg("bcd: user said yes, accept it"); ++ } ++ } ++ ++ } catch (SSLHandshakeException eh) { ++ dbg("Could not automatically verify Server."); ++ dbg("msg: " + eh.getMessage()); ++ ++ socket.close(); ++ socket = null; ++ ++ /* ++ * Reconnect, trusting any cert, so we can grab ++ * the cert to show it to the user. The connection ++ * is not used for anything else. ++ */ ++ factory = trustall_ctx.getSocketFactory(); ++ if (proxy_failure) { ++ socket = proxy_socket(factory); ++ } else { ++ socket = (SSLSocket) factory.createSocket(host, port); ++ } ++ ++ try { ++ socket.startHandshake(); ++ dbg("TrustAll Server Connection Verified."); ++ ++ /* grab the cert: */ ++ try { ++ SSLSession sess = socket.getSession(); ++ trustallCerts = sess.getPeerCertificates(); ++ } catch (Exception e) { ++ throw new Exception("Could not get " + ++ "Peer Certificate"); ++ } ++ ++ if (viewer.trustAllVncCerts) { ++ dbg("viewer.trustAllVncCerts-3"); ++ } else if (! browser_cert_match()) { ++ /* ++ * close socket now, we will reopen after ++ * dialog if user agrees to use the cert. ++ */ ++ socket.close(); ++ socket = null; ++ ++ /* dialog with user to accept cert or not: */ ++ ++ TrustDialog td= new TrustDialog(host, port, ++ trustallCerts); ++ ++ if (! td.queryUser()) { ++ String msg = "User decided against it."; ++ dbg(msg); ++ throw new IOException(msg); ++ } ++ } ++ ++ } catch (Exception ehand2) { ++ dbg("** Could not TrustAll Verify Server."); ++ ++ throw new IOException(ehand2.getMessage()); ++ } ++ ++ /* ++ * Now connect a 3rd time, using the cert ++ * retrieved during connection 2 (that the user ++ * likely blindly agreed to). ++ */ ++ ++ factory = trustone_ctx.getSocketFactory(); ++ if (proxy_failure) { ++ socket = proxy_socket(factory); ++ } else { ++ socket = (SSLSocket) factory.createSocket(host, port); ++ } ++ ++ try { ++ socket.startHandshake(); ++ dbg("TrustAll Server Connection Verified #3."); ++ ++ } catch (Exception ehand3) { ++ dbg("** Could not TrustAll Verify Server #3."); ++ ++ throw new IOException(ehand3.getMessage()); ++ } ++ } ++ ++ if (socket != null && viewer.GET) { ++ String str = "GET "; ++ str += viewer.urlPrefix; ++ str += "/request.https.vnc.connection"; ++ str += " HTTP/1.0\r\n"; ++ str += "Pragma: No-Cache\r\n"; ++ str += "\r\n"; ++ System.out.println("sending GET: " + str); ++ OutputStream os = socket.getOutputStream(); ++ os.write(str.getBytes()); ++ os.flush(); ++ if (false) { ++ String rep = ""; ++ DataInputStream is = new DataInputStream( ++ new BufferedInputStream(socket.getInputStream(), 16384)); ++ while (true) { ++ rep += readline(is); ++ if (rep.indexOf("\r\n\r\n") >= 0) { ++ break; ++ } ++ } ++ System.out.println("rep: " + rep); ++ } ++ } ++ ++ dbg("SSL returning socket to caller."); ++ return (Socket) socket; ++ } ++ ++ private void dbg(String s) { ++ if (debug) { ++ System.out.println(s); ++ } ++ } ++ ++ private int gint(String s) { ++ int n = -1; ++ try { ++ Integer I = new Integer(s); ++ n = I.intValue(); ++ } catch (Exception ex) { ++ return -1; ++ } ++ return n; ++ } ++ ++ public SSLSocket proxy_socket(SSLSocketFactory factory) { ++ Properties props = null; ++ String proxyHost = null; ++ int proxyPort = 0; ++ String proxyHost_nossl = null; ++ int proxyPort_nossl = 0; ++ String str; ++ ++ /* see if we can guess the proxy info from Properties: */ ++ try { ++ props = System.getProperties(); ++ } catch (Exception e) { ++ dbg("props failed: " + e.getMessage()); ++ } ++ if (props != null) { ++ dbg("\n---------------\nAll props:"); ++ props.list(System.out); ++ dbg("\n---------------\n\n"); ++ ++ for (Enumeration e = props.propertyNames(); e.hasMoreElements(); ) { ++ String s = (String) e.nextElement(); ++ String v = System.getProperty(s); ++ String s2 = s.toLowerCase(); ++ String v2 = v.toLowerCase(); ++ ++ if (s2.indexOf("proxy") < 0 && v2.indexOf("proxy") < 0) { ++ continue; ++ } ++ if (v2.indexOf("https") < 0) { ++ continue; ++ } ++ ++ if (s2.indexOf("proxy.https.host") >= 0) { ++ proxyHost = v2; ++ continue; ++ } ++ if (s2.indexOf("proxy.https.port") >= 0) { ++ proxyPort = gint(v2); ++ continue; ++ } ++ if (s2.indexOf("proxy.http.host") >= 0) { ++ proxyHost_nossl = v2; ++ continue; ++ } ++ if (s2.indexOf("proxy.http.port") >= 0) { ++ proxyPort_nossl = gint(v2); ++ continue; ++ } ++ ++ String[] pieces = v.split("[,;]"); ++ for (int i = 0; i < pieces.length; i++) { ++ String p = pieces[i]; ++ int j = p.indexOf("https"); ++ if (j < 0) { ++ continue; ++ } ++ j = p.indexOf("=", j); ++ if (j < 0) { ++ continue; ++ } ++ p = p.substring(j+1); ++ String [] hp = p.split(":"); ++ if (hp.length != 2) { ++ continue; ++ } ++ if (hp[0].length() > 1 && hp[1].length() > 1) { ++ ++ proxyPort = gint(hp[1]); ++ if (proxyPort < 0) { ++ continue; ++ } ++ proxyHost = new String(hp[0]); ++ break; ++ } ++ } ++ } ++ } ++ if (proxyHost != null) { ++ if (proxyHost_nossl != null && proxyPort_nossl > 0) { ++ dbg("Using http proxy info instead of https."); ++ proxyHost = proxyHost_nossl; ++ proxyPort = proxyPort_nossl; ++ } ++ } ++ ++ if (proxy_in_use) { ++ if (proxy_dialog_host != null && proxy_dialog_port > 0) { ++ proxyHost = proxy_dialog_host; ++ proxyPort = proxy_dialog_port; ++ } ++ if (proxyHost != null) { ++ dbg("Lucky us! we figured out the Proxy parameters: " + proxyHost + " " + proxyPort); ++ } else { ++ /* ask user to help us: */ ++ ProxyDialog pd = new ProxyDialog(proxyHost, proxyPort); ++ pd.queryUser(); ++ proxyHost = pd.getHost(); ++ proxyPort = pd.getPort(); ++ proxy_dialog_host = new String(proxyHost); ++ proxy_dialog_port = proxyPort; ++ dbg("User said host: " + pd.getHost() + " port: " + pd.getPort()); ++ } ++ ++ dbg("proxy_in_use psocket:"); ++ proxySock = psocket(proxyHost, proxyPort); ++ if (proxySock == null) { ++ dbg("1-a sadly, returning a null socket"); ++ return null; ++ } ++ String hp = host + ":" + port; ++ ++ String req1 = "CONNECT " + hp + " HTTP/1.1\r\n" ++ + "Host: " + hp + "\r\n\r\n"; ++ ++ dbg("requesting1: " + req1); ++ ++ try { ++ proxy_os.write(req1.getBytes()); ++ String reply = readline(proxy_is); ++ ++ dbg("proxy replied1: " + reply.trim()); ++ ++ if (reply.indexOf("HTTP/1.") < 0 && reply.indexOf(" 200") < 0) { ++ proxySock.close(); ++ proxySock = psocket(proxyHost, proxyPort); ++ if (proxySock == null) { ++ dbg("2-a sadly, returning a null socket"); ++ return null; ++ } ++ } ++ } catch(Exception e) { ++ dbg("sock prob1: " + e.getMessage()); ++ } ++ ++ while (true) { ++ String line = readline(proxy_is); ++ dbg("proxy line1: " + line.trim()); ++ if (line.equals("\r\n") || line.equals("\n")) { ++ break; ++ } ++ } ++ } else if (viewer.CONNECT != null) { ++ dbg("viewer.CONNECT psocket:"); ++ proxySock = psocket(host, port); ++ if (proxySock == null) { ++ dbg("1-b sadly, returning a null socket"); ++ return null; ++ } ++ } ++ ++ if (viewer.CONNECT != null) { ++ String hp = viewer.CONNECT; ++ String req2 = "CONNECT " + hp + " HTTP/1.1\r\n" ++ + "Host: " + hp + "\r\n\r\n"; ++ ++ dbg("requesting2: " + req2); ++ ++ try { ++ proxy_os.write(req2.getBytes()); ++ String reply = readline(proxy_is); ++ ++ dbg("proxy replied2: " + reply.trim()); ++ ++ if (reply.indexOf("HTTP/1.") < 0 && reply.indexOf(" 200") < 0) { ++ proxySock.close(); ++ proxySock = psocket(proxyHost, proxyPort); ++ if (proxySock == null) { ++ dbg("2-b sadly, returning a null socket"); ++ return null; ++ } ++ } ++ } catch(Exception e) { ++ dbg("sock prob2: " + e.getMessage()); ++ } ++ ++ while (true) { ++ String line = readline(proxy_is); ++ dbg("proxy line2: " + line.trim()); ++ if (line.equals("\r\n") || line.equals("\n")) { ++ break; ++ } ++ } ++ ++ } ++ ++ Socket sslsock = null; ++ try { ++ sslsock = factory.createSocket(proxySock, host, port, true); ++ } catch(Exception e) { ++ dbg("sslsock prob: " + e.getMessage()); ++ dbg("3 sadly, returning a null socket"); ++ } ++ ++ return (SSLSocket) sslsock; ++ } ++ ++ Socket psocket(String h, int p) { ++ Socket psock = null; ++ try { ++ psock = new Socket(h, p); ++ proxy_is = new DataInputStream(new BufferedInputStream( ++ psock.getInputStream(), 16384)); ++ proxy_os = psock.getOutputStream(); ++ } catch(Exception e) { ++ dbg("psocket prob: " + e.getMessage()); ++ return null; ++ } ++ ++ return psock; ++ } ++ ++ String readline(DataInputStream i) { ++ byte[] ba = new byte[1]; ++ String s = new String(""); ++ ba[0] = 0; ++ try { ++ while (ba[0] != 0xa) { ++ ba[0] = (byte) i.readUnsignedByte(); ++ s += new String(ba); ++ } ++ } catch (Exception e) { ++ ; ++ } ++ return s; ++ } ++} ++ ++class TrustDialog implements ActionListener { ++ String msg, host, text; ++ int port; ++ java.security.cert.Certificate[] trustallCerts = null; ++ boolean viewing_cert = false; ++ boolean trust_this_session = false; ++ ++ /* ++ * this is the gui to show the user the cert and info and ask ++ * them if they want to continue using this cert. ++ */ ++ ++ Button ok, cancel, viewcert; ++ TextArea textarea; ++ Checkbox accept, deny; ++ Dialog dialog; ++ ++ String s1 = "Accept this certificate temporarily for this session"; ++ String s2 = "Do not accept this certificate and do not connect to" ++ + " this VNC server"; ++ String ln = "\n---------------------------------------------------\n\n"; ++ ++ TrustDialog (String h, int p, java.security.cert.Certificate[] s) { ++ host = h; ++ port = p; ++ trustallCerts = s; ++ ++ msg = "VNC Server " + host + ":" + port + " Not Verified"; ++ } ++ ++ public boolean queryUser() { ++ ++ /* create and display the dialog for unverified cert. */ ++ ++ Frame frame = new Frame(msg); ++ ++ dialog = new Dialog(frame, true); ++ ++ String infostr = ""; ++ if (trustallCerts.length == 1) { ++ CertInfo ci = new CertInfo(trustallCerts[0]); ++ infostr = ci.get_certinfo("all"); ++ } ++ ++ text = "\n" +++ "Unable to verify the identity of\n" +++ "\n" +++ " " + host + ":" + port + "\n" +++ "\n" +++ infostr +++ "\n" +++ "as a trusted VNC server.\n" +++ "\n" +++ "This may be due to:\n" +++ "\n" +++ " - Your requesting to View the Certificate before accepting.\n" +++ "\n" +++ " - The VNC server using a Self-Signed Certificate.\n" +++ "\n" +++ " - The VNC server using a Certificate Authority not recognized by your\n" +++ " Browser or Java Plugin runtime.\n" +++ "\n" +++ " - The use of an Apache SSL portal employing CONNECT proxying and the\n" +++ " Apache web server has a certificate different from the VNC server's. \n" +++ "\n" +++ " - A Man-In-The-Middle attack impersonating as the VNC server you wish\n" +++ " to connect to. (Wouldn't that be exciting!!)\n" +++ "\n" +++ "By safely copying the VNC server's Certificate (or using a common\n" +++ "Certificate Authority certificate) you can configure your Web Browser or\n" +++ "Java Plugin to automatically authenticate this Server.\n" +++ "\n" +++ "If you do so, then you will only have to click \"Yes\" when this VNC\n" +++ "Viewer applet asks you whether to trust your Browser/Java Plugin's\n" +++ "acceptance of the certificate. (except for the Apache portal case above.)\n" ++; ++ ++ /* the accept / do-not-accept radio buttons: */ ++ CheckboxGroup checkbox = new CheckboxGroup(); ++ accept = new Checkbox(s1, true, checkbox); ++ deny = new Checkbox(s2, false, checkbox); ++ ++ /* put the checkboxes in a panel: */ ++ Panel check = new Panel(); ++ check.setLayout(new GridLayout(2, 1)); ++ ++ check.add(accept); ++ check.add(deny); ++ ++ /* make the 3 buttons: */ ++ ok = new Button("OK"); ++ cancel = new Button("Cancel"); ++ viewcert = new Button("View Certificate"); ++ ++ ok.addActionListener(this); ++ cancel.addActionListener(this); ++ viewcert.addActionListener(this); ++ ++ /* put the buttons in their own panel: */ ++ Panel buttonrow = new Panel(); ++ buttonrow.setLayout(new FlowLayout(FlowLayout.LEFT)); ++ buttonrow.add(viewcert); ++ buttonrow.add(ok); ++ buttonrow.add(cancel); ++ ++ /* label at the top: */ ++ Label label = new Label(msg, Label.CENTER); ++ label.setFont(new Font("Helvetica", Font.BOLD, 16)); ++ ++ /* textarea in the middle */ ++ textarea = new TextArea(text, 36, 64, ++ TextArea.SCROLLBARS_VERTICAL_ONLY); ++ textarea.setEditable(false); ++ ++ /* put the two panels in their own panel at bottom: */ ++ Panel bot = new Panel(); ++ bot.setLayout(new GridLayout(2, 1)); ++ bot.add(check); ++ bot.add(buttonrow); ++ ++ /* now arrange things inside the dialog: */ ++ dialog.setLayout(new BorderLayout()); ++ ++ dialog.add("North", label); ++ dialog.add("South", bot); ++ dialog.add("Center", textarea); ++ ++ dialog.pack(); ++ dialog.resize(dialog.preferredSize()); ++ ++ dialog.show(); /* block here til OK or Cancel pressed. */ ++ ++ return trust_this_session; ++ } ++ ++ public synchronized void actionPerformed(ActionEvent evt) { ++ ++ if (evt.getSource() == viewcert) { ++ /* View Certificate button clicked */ ++ if (viewing_cert) { ++ /* show the original info text: */ ++ textarea.setText(text); ++ viewcert.setLabel("View Certificate"); ++ viewing_cert = false; ++ } else { ++ int i; ++ /* show all (likely just one) certs: */ ++ textarea.setText(""); ++ for (i=0; i < trustallCerts.length; i++) { ++ int j = i + 1; ++ textarea.append("Certificate[" + ++ j + "]\n\n"); ++ textarea.append( ++ trustallCerts[i].toString()); ++ textarea.append(ln); ++ } ++ viewcert.setLabel("View Info"); ++ viewing_cert = true; ++ ++ textarea.setCaretPosition(0); ++ } ++ ++ } else if (evt.getSource() == ok) { ++ /* OK button clicked */ ++ if (accept.getState()) { ++ trust_this_session = true; ++ } else { ++ trust_this_session = false; ++ } ++ dialog.dispose(); ++ ++ } else if (evt.getSource() == cancel) { ++ /* Cancel button clicked */ ++ trust_this_session = false; ++ ++ dialog.dispose(); ++ } ++ } ++ ++ String get_certinfo() { ++ String all = ""; ++ String fields[] = {"CN", "OU", "O", "L", "C"}; ++ int i; ++ if (trustallCerts.length < 1) { ++ all = ""; ++ return all; ++ } ++ String cert = trustallCerts[0].toString(); ++ ++ /* ++ * For now we simply scrape the cert string, there must ++ * be an API for this... perhaps optionValue? ++ */ ++ ++ for (i=0; i < fields.length; i++) { ++ int f, t, t1, t2; ++ String sub, mat = fields[i] + "="; ++ ++ f = cert.indexOf(mat, 0); ++ if (f > 0) { ++ t1 = cert.indexOf(", ", f); ++ t2 = cert.indexOf("\n", f); ++ if (t1 < 0 && t2 < 0) { ++ continue; ++ } else if (t1 < 0) { ++ t = t2; ++ } else if (t2 < 0) { ++ t = t1; ++ } else if (t1 < t2) { ++ t = t1; ++ } else { ++ t = t2; ++ } ++ if (t > f) { ++ sub = cert.substring(f, t); ++ all = all + " " + sub + "\n"; ++ } ++ } ++ } ++ return all; ++ } ++} ++ ++class ProxyDialog implements ActionListener { ++ String guessedHost = null; ++ String guessedPort = null; ++ /* ++ * this is the gui to show the user the cert and info and ask ++ * them if they want to continue using this cert. ++ */ ++ ++ Button ok; ++ Dialog dialog; ++ TextField entry; ++ String reply = ""; ++ ++ ProxyDialog (String h, int p) { ++ guessedHost = h; ++ try { ++ guessedPort = Integer.toString(p); ++ } catch (Exception e) { ++ guessedPort = "8080"; ++ } ++ } ++ ++ public void queryUser() { ++ ++ /* create and display the dialog for unverified cert. */ ++ ++ Frame frame = new Frame("Need Proxy host:port"); ++ ++ dialog = new Dialog(frame, true); ++ ++ ++ Label label = new Label("Please Enter your https Proxy info as host:port", Label.CENTER); ++ //label.setFont(new Font("Helvetica", Font.BOLD, 16)); ++ entry = new TextField(30); ++ ok = new Button("OK"); ++ ok.addActionListener(this); ++ ++ String guess = ""; ++ if (guessedHost != null) { ++ guess = guessedHost + ":" + guessedPort; ++ } ++ entry.setText(guess); ++ ++ dialog.setLayout(new BorderLayout()); ++ dialog.add("North", label); ++ dialog.add("Center", entry); ++ dialog.add("South", ok); ++ dialog.pack(); ++ dialog.resize(dialog.preferredSize()); ++ ++ dialog.show(); /* block here til OK or Cancel pressed. */ ++ return; ++ } ++ ++ public String getHost() { ++ int i = reply.indexOf(":"); ++ if (i < 0) { ++ return "unknown"; ++ } ++ String h = reply.substring(0, i); ++ return h; ++ } ++ ++ public int getPort() { ++ int i = reply.indexOf(":"); ++ int p = 8080; ++ if (i < 0) { ++ return p; ++ } ++ i++; ++ String ps = reply.substring(i); ++ try { ++ Integer I = new Integer(ps); ++ p = I.intValue(); ++ } catch (Exception e) { ++ ; ++ } ++ return p; ++ } ++ ++ public synchronized void actionPerformed(ActionEvent evt) { ++ System.out.println(evt.getActionCommand()); ++ if (evt.getSource() == ok) { ++ reply = entry.getText(); ++ dialog.dispose(); ++ } ++ } ++} ++ ++class ClientCertDialog implements ActionListener { ++ ++ Button ok; ++ Dialog dialog; ++ TextField entry; ++ String reply = ""; ++ ++ ClientCertDialog() { ++ ; ++ } ++ ++ public String queryUser() { ++ ++ /* create and display the dialog for unverified cert. */ ++ ++ Frame frame = new Frame("Enter SSL Client Cert+Key String"); ++ ++ dialog = new Dialog(frame, true); ++ ++ ++ Label label = new Label("Please Enter the SSL Client Cert+Key String 308204c0...,...522d2d0a", Label.CENTER); ++ entry = new TextField(30); ++ ok = new Button("OK"); ++ ok.addActionListener(this); ++ ++ dialog.setLayout(new BorderLayout()); ++ dialog.add("North", label); ++ dialog.add("Center", entry); ++ dialog.add("South", ok); ++ dialog.pack(); ++ dialog.resize(dialog.preferredSize()); ++ ++ dialog.show(); /* block here til OK or Cancel pressed. */ ++ return reply; ++ } ++ ++ public synchronized void actionPerformed(ActionEvent evt) { ++ System.out.println(evt.getActionCommand()); ++ if (evt.getSource() == ok) { ++ reply = entry.getText(); ++ dialog.dispose(); ++ } ++ } ++} ++ ++class BrowserCertsDialog implements ActionListener { ++ Button yes, no; ++ Dialog dialog; ++ String vncServer; ++ String hostport; ++ public boolean showCertDialog = true; ++ ++ BrowserCertsDialog(String serv, String hp) { ++ vncServer = serv; ++ hostport = hp; ++ } ++ ++ public void queryUser() { ++ ++ /* create and display the dialog for unverified cert. */ ++ ++ Frame frame = new Frame("Use Browser/JVM Certs?"); ++ ++ dialog = new Dialog(frame, true); ++ ++ String m = ""; ++m += "\n"; ++m += "This VNC Viewer applet does not have its own keystore to track\n"; ++m += "SSL certificates, and so cannot authenticate the certificate\n"; ++m += "of the VNC Server:\n"; ++m += "\n"; ++m += " " + hostport + "\n\n " + vncServer + "\n"; ++m += "\n"; ++m += "on its own.\n"; ++m += "\n"; ++m += "However, it has noticed that your Web Browser or Java VM Plugin\n"; ++m += "has previously accepted the same certificate. You may have set\n"; ++m += "this up permanently or just for this session, or the server\n"; ++m += "certificate was signed by a CA cert that your Web Browser or\n"; ++m += "Java VM Plugin has.\n"; ++m += "\n"; ++m += "Should this VNC Viewer applet now connect to the above VNC server?\n"; ++m += "\n"; ++ ++// String m = "\nShould this VNC Viewer applet use your Browser/JVM certs to\n"; ++// m += "authenticate the VNC Server:\n"; ++// m += "\n " + hostport + "\n\n " + vncServer + "\n\n"; ++// m += "(NOTE: this *includes* any certs you have Just Now accepted in a\n"; ++// m += "dialog box with your Web Browser or Java Applet Plugin)\n\n"; ++ ++ TextArea textarea = new TextArea(m, 20, 64, ++ TextArea.SCROLLBARS_VERTICAL_ONLY); ++ textarea.setEditable(false); ++ yes = new Button("Yes"); ++ yes.addActionListener(this); ++ no = new Button("No, Let Me See the Certificate."); ++ no.addActionListener(this); ++ ++ dialog.setLayout(new BorderLayout()); ++ dialog.add("North", textarea); ++ dialog.add("Center", yes); ++ dialog.add("South", no); ++ dialog.pack(); ++ dialog.resize(dialog.preferredSize()); ++ ++ dialog.show(); /* block here til Yes or No pressed. */ ++ return; ++ } ++ ++ public synchronized void actionPerformed(ActionEvent evt) { ++ System.out.println(evt.getActionCommand()); ++ if (evt.getSource() == yes) { ++ showCertDialog = false; ++ dialog.dispose(); ++ } else if (evt.getSource() == no) { ++ showCertDialog = true; ++ dialog.dispose(); ++ } ++ } ++} ++ ++class CertInfo { ++ String fields[] = {"CN", "OU", "O", "L", "C"}; ++ java.security.cert.Certificate cert; ++ String certString = ""; ++ ++ CertInfo(java.security.cert.Certificate c) { ++ cert = c; ++ certString = cert.toString(); ++ } ++ ++ String get_certinfo(String which) { ++ int i; ++ String cs = new String(certString); ++ String all = ""; ++ ++ /* ++ * For now we simply scrape the cert string, there must ++ * be an API for this... perhaps optionValue? ++ */ ++ for (i=0; i < fields.length; i++) { ++ int f, t, t1, t2; ++ String sub, mat = fields[i] + "="; ++ ++ f = cs.indexOf(mat, 0); ++ if (f > 0) { ++ t1 = cs.indexOf(", ", f); ++ t2 = cs.indexOf("\n", f); ++ if (t1 < 0 && t2 < 0) { ++ continue; ++ } else if (t1 < 0) { ++ t = t2; ++ } else if (t2 < 0) { ++ t = t1; ++ } else if (t1 < t2) { ++ t = t1; ++ } else { ++ t = t2; ++ } ++ if (t > f) { ++ sub = cs.substring(f, t); ++ all = all + " " + sub + "\n"; ++ if (which.equals(fields[i])) { ++ return sub; ++ } ++ } ++ } ++ } ++ if (which.equals("all")) { ++ return all; ++ } else { ++ return ""; ++ } ++ } ++} +diff -Naur JavaViewer.orig/VncCanvas.java JavaViewer/VncCanvas.java +--- JavaViewer.orig/VncCanvas.java 2005-11-21 18:50:18.000000000 -0500 ++++ JavaViewer/VncCanvas.java 2007-05-16 15:57:36.000000000 -0400 +@@ -27,6 +27,9 @@ + import java.lang.*; + import java.util.zip.*; + ++// begin runge/x11vnc ++import java.util.Collections; ++// end runge/x11vnc + + // + // VncCanvas is a subclass of Canvas which draws a VNC desktop on it. +@@ -85,6 +88,22 @@ + + cm24 = new DirectColorModel(24, 0xFF0000, 0x00FF00, 0x0000FF); + ++// begin runge/x11vnc ++// kludge to not show any Java cursor in the canvas since we are ++// showing the soft cursor (should be a user setting...) ++Cursor dot = Toolkit.getDefaultToolkit().createCustomCursor( ++ Toolkit.getDefaultToolkit().createImage(new byte[4]), new Point(0,0), ++ "dot"); ++this.setCursor(dot); ++ ++// while we are at it... get rid of the keyboard traversals that ++// make it so we can't type a Tab character: ++this.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, ++ Collections.EMPTY_SET); ++this.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, ++ Collections.EMPTY_SET); ++// end runge/x11vnc ++ + colors = new Color[256]; + // sf@2005 - Now Default + for (int i = 0; i < 256; i++) +@@ -237,6 +256,9 @@ + } + else + { ++// begin runge/x11vnc ++ viewer.options.oldEightBitColors = viewer.options.eightBitColors; ++// end runge/x11vnc + rfb.writeSetPixelFormat( + 32, + 24, +@@ -1532,9 +1554,14 @@ + else + { + result = +- 0xFF000000 | (pixBuf[i * 4 + 1] & 0xFF) +- << 16 | (pixBuf[i * 4 + 2] & 0xFF) +- << 8 | (pixBuf[i * 4 + 3] & 0xFF); ++// begin runge/x11vnc ++// 0xFF000000 | (pixBuf[i * 4 + 1] & 0xFF) ++// << 16 | (pixBuf[i * 4 + 2] & 0xFF) ++// << 8 | (pixBuf[i * 4 + 3] & 0xFF); ++ 0xFF000000 | (pixBuf[i * 4 + 2] & 0xFF) ++ << 16 | (pixBuf[i * 4 + 1] & 0xFF) ++ << 8 | (pixBuf[i * 4 + 0] & 0xFF); ++// end runge/x11vnc + } + } else { + result = 0; // Transparent pixel +@@ -1565,9 +1592,14 @@ + else + { + result = +- 0xFF000000 | (pixBuf[i * 4 + 1] & 0xFF) +- << 16 | (pixBuf[i * 4 + 2] & 0xFF) +- << 8 | (pixBuf[i * 4 + 3] & 0xFF); ++// begin runge/x11vnc ++// 0xFF000000 | (pixBuf[i * 4 + 1] & 0xFF) ++// << 16 | (pixBuf[i * 4 + 2] & 0xFF) ++// << 8 | (pixBuf[i * 4 + 3] & 0xFF); ++ 0xFF000000 | (pixBuf[i * 4 + 2] & 0xFF) ++ << 16 | (pixBuf[i * 4 + 1] & 0xFF) ++ << 8 | (pixBuf[i * 4 + 0] & 0xFF); ++// end runge/x11vnc + } + } else { + result = 0; // Transparent pixel +diff -Naur JavaViewer.orig/VncViewer.java JavaViewer/VncViewer.java +--- JavaViewer.orig/VncViewer.java 2006-05-24 15:14:40.000000000 -0400 ++++ JavaViewer/VncViewer.java 2007-05-15 15:09:10.000000000 -0400 +@@ -115,6 +115,22 @@ + int i; + // mslogon support 2 end + ++// begin runge/x11vnc ++boolean disableSSL; ++boolean GET; ++String CONNECT; ++String urlPrefix; ++String httpsPort; ++String oneTimeKey; ++boolean forceProxy; ++boolean ignoreProxy; ++boolean trustAllVncCerts; ++boolean trustUrlVncCert; ++ ++boolean ignoreMSLogonCheck; ++// end runge/x11vnc ++ ++ + // + // init() + // +@@ -336,7 +352,12 @@ + // + + +- prologueDetectAuthProtocol() ; ++// begin runge/x11vnc ++// prologueDetectAuthProtocol() ; ++ if (ignoreMSLogonCheck == false) { ++ prologueDetectAuthProtocol() ; ++ } ++// end runge/x11vnc + + authenticator = new AuthPanel(mslogon); + +@@ -435,7 +456,7 @@ + + rfb.readVersionMsg(); + +- System.out.println("RFB server supports protocol version " + ++ System.out.println("RFB server supports protocol version: " + + rfb.serverMajor + "." + rfb.serverMinor); + + rfb.writeVersionMsg(); +@@ -804,6 +825,75 @@ + deferScreenUpdates = readIntParameter("Defer screen updates", 20); + deferCursorUpdates = readIntParameter("Defer cursor updates", 10); + deferUpdateRequests = readIntParameter("Defer update requests", 50); ++ ++// begin runge/x11vnc ++ // SSL ++ disableSSL = false; ++ str = readParameter("DisableSSL", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) ++ disableSSL = true; ++ ++ httpsPort = readParameter("httpsPort", false); ++ ++ // Extra GET, CONNECT string: ++ CONNECT = readParameter("CONNECT", false); ++ if (CONNECT != null) { ++ CONNECT = CONNECT.replaceAll(" ", ":"); ++ } ++ ++ GET = false; ++ str = readParameter("GET", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) { ++ GET = true; ++ } ++ if (str != null && str.equalsIgnoreCase("1")) { ++ GET = true; ++ } ++ ++ urlPrefix = readParameter("urlPrefix", false); ++ if (urlPrefix != null) { ++ urlPrefix = urlPrefix.replaceAll("%2F", "/"); ++ urlPrefix = urlPrefix.replaceAll("%2f", "/"); ++ urlPrefix = urlPrefix.replaceAll("_2F_", "/"); ++ if (urlPrefix.indexOf("/") != 0) { ++ urlPrefix = "/" + urlPrefix; ++ } ++ } else { ++ urlPrefix = ""; ++ } ++ System.out.println("urlPrefix: '" + urlPrefix + "'"); ++ ++ oneTimeKey = readParameter("oneTimeKey", false); ++ if (oneTimeKey != null) { ++ System.out.println("oneTimeKey: is set"); ++ } ++ ++ forceProxy = false; ++ str = readParameter("forceProxy", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) { ++ forceProxy = true; ++ } ++ ignoreProxy = false; ++ str = readParameter("ignoreProxy", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) { ++ ignoreProxy = true; ++ } ++ trustAllVncCerts = false; ++ str = readParameter("trustAllVncCerts", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) { ++ trustAllVncCerts = true; ++ } ++ trustUrlVncCert = false; ++ str = readParameter("trustUrlVncCert", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) { ++ trustUrlVncCert = true; ++ } ++ ignoreMSLogonCheck = false; ++ str = readParameter("ignoreMSLogonCheck", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) { ++ ignoreMSLogonCheck = true; ++ } ++// end runge/x11vnc + } + + public String readParameter(String name, boolean required) { |