diff options
author | runge <runge@karlrunge.com> | 2009-06-18 22:32:16 -0400 |
---|---|---|
committer | runge <runge@karlrunge.com> | 2009-06-18 22:32:16 -0400 |
commit | 61383c508e9a12c879bd94c77885e0ec0d7c47f8 (patch) | |
tree | b4bf1b16037eca9110aaec6d5f92a57a2c00a80f /classes | |
parent | d11b2abd8cf4d9afb1257695f8be1125d5625a65 (diff) | |
download | libtdevnc-61383c508e9a12c879bd94c77885e0ec0d7c47f8.tar.gz libtdevnc-61383c508e9a12c879bd94c77885e0ec0d7c47f8.zip |
classes/ssl: java viewer now handles auth-basic proxy logins.
misc/enhanced_tightvnc_viewer: update ssvnc.
Diffstat (limited to 'classes')
-rw-r--r-- | classes/ssl/SignedUltraViewerSSL.jar | bin | 103589 -> 107370 bytes | |||
-rw-r--r-- | classes/ssl/SignedVncViewer.jar | bin | 79617 -> 83396 bytes | |||
-rw-r--r-- | classes/ssl/UltraViewerSSL.jar | bin | 100714 -> 104365 bytes | |||
-rw-r--r-- | classes/ssl/VncViewer.jar | bin | 76830 -> 80481 bytes | |||
-rwxr-xr-x | classes/ssl/ss_vncviewer | 45 | ||||
-rw-r--r-- | classes/ssl/tightvnc-1.3dev7_javasrc-vncviewer-ssl.patch | 343 | ||||
-rw-r--r-- | classes/ssl/ultravnc-102-JavaViewer-ssl-etc.patch | 343 |
7 files changed, 644 insertions, 87 deletions
diff --git a/classes/ssl/SignedUltraViewerSSL.jar b/classes/ssl/SignedUltraViewerSSL.jar Binary files differindex d8297b3..2ca5b78 100644 --- a/classes/ssl/SignedUltraViewerSSL.jar +++ b/classes/ssl/SignedUltraViewerSSL.jar diff --git a/classes/ssl/SignedVncViewer.jar b/classes/ssl/SignedVncViewer.jar Binary files differindex 06a2179..1498b4b 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 differindex 041e757..b012433 100644 --- a/classes/ssl/UltraViewerSSL.jar +++ b/classes/ssl/UltraViewerSSL.jar diff --git a/classes/ssl/VncViewer.jar b/classes/ssl/VncViewer.jar Binary files differindex 4d35cb3..b647da6 100644 --- a/classes/ssl/VncViewer.jar +++ b/classes/ssl/VncViewer.jar diff --git a/classes/ssl/ss_vncviewer b/classes/ssl/ss_vncviewer index 2231108..ec004c7 100755 --- a/classes/ssl/ss_vncviewer +++ b/classes/ssl/ss_vncviewer @@ -46,8 +46,8 @@ # -showcert Only fetch the certificate using the 'openssl s_client' # command (openssl(1) must in installed). # -# See http://www.karlrunge.com/x11vnc/#faq-ssl-ca for details on SSL -# certificates with VNC. +# See http://www.karlrunge.com/x11vnc/faq.html#faq-ssl-ca for details on +# SSL certificates with VNC. # # A few other args (not related to SSL and certs): # @@ -115,6 +115,15 @@ # VNCIPCMD=${VNCVIEWERCMD:-vncip} VNCVIEWERCMD=${VNCVIEWERCMD:-vncviewer} +if [ "X$SSVNC_TURBOVNC" != "X" ]; then + if echo "$VNCVIEWERCMD" | grep '\.turbovnc' > /dev/null; then + : + else + if type "$VNCVIEWERCMD.turbovnc" > /dev/null 2>/dev/null; then + VNCVIEWERCMD="$VNCVIEWERCMD.turbovnc" + fi + fi +fi # # Same for STUNNEL, e.g. set it to /path/to/stunnel or stunnel4, etc. # @@ -268,6 +277,12 @@ do ;; "-onelisten") SSVNC_LISTEN_ONCE=1; export SSVNC_LISTEN_ONCE ;; + "-sendclipboard") VNCVIEWER_SEND_CLIPBOARD=1; export VNCVIEWER_SEND_CLIPBOARD + ;; + "-sendalways") VNCVIEWER_SEND_ALWAYS=1; export VNCVIEWER_SEND_ALWAYS + ;; + "-recvtext") shift; VNCVIEWER_RECV_TEXT="$1"; export VNCVIEWER_RECV_TEXT + ;; "-escape") shift; VNCVIEWER_ESCAPE="$1"; export VNCVIEWER_ESCAPE ;; "-ssvnc_encodings") shift; VNCVIEWER_ENCODINGS="$1"; export VNCVIEWER_ENCODINGS @@ -751,6 +766,19 @@ if (exists $ENV{SSVNC_PREDIGESTED_HANDSHAKE}) { $handshake_file = $ENV{SSVNC_PREDIGESTED_HANDSHAKE}; } +my $have_gettimeofday = 0; +eval "use Time::HiRes"; +if ($@ eq "") { + $have_gettimeofday = 1; +} +sub gettime { + my $t = "0.0"; + if ($have_gettimeofday) { + $t = Time::HiRes::gettimeofday(); + } + return $t; +} + sub append_handshake { my $str = shift; if ($handshake_file) { @@ -1324,12 +1352,19 @@ sub vencrypt_dialog { } elsif ($minor == 7) { $viewer_rfb = "RFB 003.007\n"; } - syswrite($sock, $viewer_rfb, 12); - append_handshake("viewer=$viewer_rfb"); - my $nsec; + my $t1 = gettime(); + my $t0 = gettime(); + syswrite($sock, $viewer_rfb, 12); sysread($sock, $nsec, 1); + + $t1 = gettime(); + $t1 = sprintf("%.6f", $t1 - $t0); + + append_handshake("viewer=$viewer_rfb"); + append_handshake("latency=$t1\n"); + vdie if $nsec eq ""; $nsec = unpack("C", $nsec); diff --git a/classes/ssl/tightvnc-1.3dev7_javasrc-vncviewer-ssl.patch b/classes/ssl/tightvnc-1.3dev7_javasrc-vncviewer-ssl.patch index 88185b7..1844eec 100644 --- a/classes/ssl/tightvnc-1.3dev7_javasrc-vncviewer-ssl.patch +++ b/classes/ssl/tightvnc-1.3dev7_javasrc-vncviewer-ssl.patch @@ -73,8 +73,8 @@ diff -x VncCanvas.java -Naur vnc_javasrc.orig/RfbProto.java vnc_javasrc/RfbProto serverMajor = (b[4] - '0') * 100 + (b[5] - '0') * 10 + (b[6] - '0'); diff -x VncCanvas.java -Naur vnc_javasrc.orig/SSLSocketToMe.java vnc_javasrc/SSLSocketToMe.java --- vnc_javasrc.orig/SSLSocketToMe.java 1969-12-31 19:00:00.000000000 -0500 -+++ vnc_javasrc/SSLSocketToMe.java 2008-04-15 12:54:51.000000000 -0400 -@@ -0,0 +1,1456 @@ ++++ vnc_javasrc/SSLSocketToMe.java 2009-06-18 09:47:22.000000000 -0400 +@@ -0,0 +1,1717 @@ +/* + * SSLSocketToMe.java: add SSL encryption to Java VNC Viewer. + * @@ -130,6 +130,7 @@ diff -x VncCanvas.java -Naur vnc_javasrc.orig/SSLSocketToMe.java vnc_javasrc/SSL + public DataInputStream is = null; + public OutputStream os = null; + ++ String proxy_auth_string = null; + String proxy_dialog_host = null; + int proxy_dialog_port = 0; + @@ -648,9 +649,9 @@ diff -x VncCanvas.java -Naur vnc_javasrc.orig/SSLSocketToMe.java vnc_javasrc/SSL + user_wants_to_see_cert = false; + } else { + bcd = new BrowserCertsDialog(serv, host + ":" + port); -+ dbg("bcd START"); ++ dbg("browser certs dialog START"); + bcd.queryUser(); -+ dbg("bcd DONE"); ++ dbg("browser certs dialog DONE"); + if (bcd.showCertDialog) { + String msg = "user wants to see cert"; + dbg(msg); @@ -658,14 +659,17 @@ diff -x VncCanvas.java -Naur vnc_javasrc.orig/SSLSocketToMe.java vnc_javasrc/SSL + throw new SSLHandshakeException(msg); + } else { + user_wants_to_see_cert = false; -+ dbg("bcd: user said yes, accept it"); ++ dbg("browser certs dialog: user said yes, accept it"); + } + } + + } catch (SSLHandshakeException eh) { + dbg("Could not automatically verify Server."); + dbg("msg: " + eh.getMessage()); ++ String getoutstr = "GET /index.vnc HTTP/1.0\r\nConnection: close\r\n\r\n"; + ++ OutputStream os = socket.getOutputStream(); ++ os.write(getoutstr.getBytes()); + socket.close(); + socket = null; + @@ -701,6 +705,8 @@ diff -x VncCanvas.java -Naur vnc_javasrc.orig/SSLSocketToMe.java vnc_javasrc/SSL + * close socket now, we will reopen after + * dialog if user agrees to use the cert. + */ ++ os = socket.getOutputStream(); ++ os.write(getoutstr.getBytes()); + socket.close(); + socket = null; + @@ -722,6 +728,15 @@ diff -x VncCanvas.java -Naur vnc_javasrc.orig/SSLSocketToMe.java vnc_javasrc/SSL + throw new IOException(ehand2.getMessage()); + } + ++ if (socket != null) { ++ try { ++ socket.close(); ++ } catch (Exception e) { ++ ; ++ } ++ socket = null; ++ } ++ + /* + * Now connect a 3rd time, using the cert + * retrieved during connection 2 (that the user @@ -806,6 +821,95 @@ diff -x VncCanvas.java -Naur vnc_javasrc.orig/SSLSocketToMe.java vnc_javasrc/SSL + return n; + } + ++ private void proxy_helper(String proxyHost, int proxyPort) { ++ ++ boolean proxy_auth = false; ++ String proxy_auth_basic_realm = ""; ++ String hp = host + ":" + port; ++ dbg("proxy_helper: " + proxyHost + ":" + proxyPort + " hp: " + hp); ++ ++ for (int k=0; k < 2; k++) { ++ dbg("proxy_in_use psocket:"); ++ ++ if (proxySock != null) { ++ try { ++ proxySock.close(); ++ } catch (Exception e) { ++ ; ++ } ++ } ++ ++ proxySock = psocket(proxyHost, proxyPort); ++ if (proxySock == null) { ++ dbg("1-a sadly, returning a null socket"); ++ return; ++ } ++ ++ String req1 = "CONNECT " + hp + " HTTP/1.1\r\n" ++ + "Host: " + hp + "\r\n"; ++ ++ dbg("requesting: " + req1); ++ ++ if (proxy_auth) { ++ if (proxy_auth_string == null) { ++ ProxyPasswdDialog pp = new ProxyPasswdDialog(proxyHost, proxyPort, proxy_auth_basic_realm); ++ pp.queryUser(); ++ proxy_auth_string = pp.getAuth(); ++ } ++ //dbg("auth1: " + proxy_auth_string); ++ String auth2 = Base64Coder.encodeString(proxy_auth_string); ++ //dbg("auth2: " + auth2); ++ req1 += "Proxy-Authorization: Basic " + auth2 + "\r\n"; ++ //dbg("req1: " + req1); ++ dbg("added Proxy-Authorization: Basic ... to request"); ++ } ++ req1 += "\r\n"; ++ ++ try { ++ proxy_os.write(req1.getBytes()); ++ String reply = readline(proxy_is); ++ ++ dbg("proxy replied: " + reply.trim()); ++ ++ if (reply.indexOf("HTTP/1.") == 0 && reply.indexOf(" 407 ") > 0) { ++ proxy_auth = true; ++ proxySock.close(); ++ } else 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; ++ } ++ } ++ } catch(Exception e) { ++ dbg("sock prob: " + e.getMessage()); ++ } ++ ++ while (true) { ++ String line = readline(proxy_is); ++ dbg("proxy line: " + line.trim()); ++ if (proxy_auth) { ++ String uc = line.toLowerCase(); ++ if (uc.indexOf("proxy-authenticate:") == 0) { ++ if (uc.indexOf(" basic ") >= 0) { ++ int idx = uc.indexOf(" realm"); ++ if (idx >= 0) { ++ proxy_auth_basic_realm = uc.substring(idx+1); ++ } ++ } ++ } ++ } ++ if (line.equals("\r\n") || line.equals("\n")) { ++ break; ++ } ++ } ++ if (!proxy_auth || proxy_auth_basic_realm.equals("")) { ++ break; ++ } ++ } ++ } ++ + public SSLSocket proxy_socket(SSLSocketFactory factory) { + Properties props = null; + String proxyHost = null; @@ -912,44 +1016,10 @@ diff -x VncCanvas.java -Naur vnc_javasrc.orig/SSLSocketToMe.java vnc_javasrc/SSL + dbg("User said host: " + pd.getHost() + " port: " + pd.getPort()); + } + -+ dbg("proxy_in_use psocket:"); -+ proxySock = psocket(proxyHost, proxyPort); ++ proxy_helper(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); @@ -991,7 +1061,6 @@ diff -x VncCanvas.java -Naur vnc_javasrc.orig/SSLSocketToMe.java vnc_javasrc/SSL + break; + } + } -+ + } + + Socket sslsock = null; @@ -1351,6 +1420,77 @@ diff -x VncCanvas.java -Naur vnc_javasrc.orig/SSLSocketToMe.java vnc_javasrc/SSL + } +} + ++class ProxyPasswdDialog implements ActionListener { ++ String guessedHost = null; ++ String guessedPort = null; ++ String guessedUser = null; ++ String guessedPasswd = null; ++ String realm = 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 entry1; ++ TextField entry2; ++ String reply1 = ""; ++ String reply2 = ""; ++ ++ ProxyPasswdDialog (String h, int p, String realm) { ++ guessedHost = h; ++ try { ++ guessedPort = Integer.toString(p); ++ } catch (Exception e) { ++ guessedPort = "8080"; ++ } ++ this.realm = realm; ++ } ++ ++ public void queryUser() { ++ ++ /* create and display the dialog for unverified cert. */ ++ ++ Frame frame = new Frame("Proxy Requires Username and Password"); ++ ++ dialog = new Dialog(frame, true); ++ ++ //Label label = new Label("Please Enter your Web Proxy Username in the top Entry and Password in the bottom Entry", Label.CENTER); ++ TextArea label = new TextArea("Please Enter your Web Proxy\nUsername in the Top Entry and\nPassword in the Bottom Entry,\nand then press OK.", 4, 20, TextArea.SCROLLBARS_NONE); ++ entry1 = new TextField(30); ++ entry2 = new TextField(30); ++ entry2.setEchoChar('*'); ++ ok = new Button("OK"); ++ ok.addActionListener(this); ++ ++ dialog.setLayout(new BorderLayout()); ++ dialog.add("North", label); ++ dialog.add("Center", entry1); ++ dialog.add("South", entry2); ++ dialog.add("East", ok); ++ dialog.pack(); ++ dialog.resize(dialog.preferredSize()); ++ ++ dialog.show(); /* block here til OK or Cancel pressed. */ ++ return; ++ } ++ ++ public String getAuth() { ++ return reply1 + ":" + reply2; ++ } ++ ++ public synchronized void actionPerformed(ActionEvent evt) { ++ System.out.println(evt.getActionCommand()); ++ if (evt.getSource() == ok) { ++ reply1 = entry1.getText(); ++ reply2 = entry2.getText(); ++ //dialog.dispose(); ++ dialog.hide(); ++ } ++ } ++} ++ +class ClientCertDialog implements ActionListener { + + Button ok; @@ -1531,6 +1671,127 @@ diff -x VncCanvas.java -Naur vnc_javasrc.orig/SSLSocketToMe.java vnc_javasrc/SSL + } + } +} ++ ++class Base64Coder { ++ ++ // Mapping table from 6-bit nibbles to Base64 characters. ++ private static char[] map1 = new char[64]; ++ static { ++ int i=0; ++ for (char c='A'; c<='Z'; c++) map1[i++] = c; ++ for (char c='a'; c<='z'; c++) map1[i++] = c; ++ for (char c='0'; c<='9'; c++) map1[i++] = c; ++ map1[i++] = '+'; map1[i++] = '/'; } ++ ++ // Mapping table from Base64 characters to 6-bit nibbles. ++ private static byte[] map2 = new byte[128]; ++ static { ++ for (int i=0; i<map2.length; i++) map2[i] = -1; ++ for (int i=0; i<64; i++) map2[map1[i]] = (byte)i; } ++ ++ /** ++ * Encodes a string into Base64 format. ++ * No blanks or line breaks are inserted. ++ * @param s a String to be encoded. ++ * @return A String with the Base64 encoded data. ++ */ ++ public static String encodeString (String s) { ++ return new String(encode(s.getBytes())); } ++ ++ /** ++ * Encodes a byte array into Base64 format. ++ * No blanks or line breaks are inserted. ++ * @param in an array containing the data bytes to be encoded. ++ * @return A character array with the Base64 encoded data. ++ */ ++ public static char[] encode (byte[] in) { ++ return encode(in,in.length); } ++ ++ /** ++ * Encodes a byte array into Base64 format. ++ * No blanks or line breaks are inserted. ++ * @param in an array containing the data bytes to be encoded. ++ * @param iLen number of bytes to process in <code>in</code>. ++ * @return A character array with the Base64 encoded data. ++ */ ++ public static char[] encode (byte[] in, int iLen) { ++ int oDataLen = (iLen*4+2)/3; // output length without padding ++ int oLen = ((iLen+2)/3)*4; // output length including padding ++ char[] out = new char[oLen]; ++ int ip = 0; ++ int op = 0; ++ while (ip < iLen) { ++ int i0 = in[ip++] & 0xff; ++ int i1 = ip < iLen ? in[ip++] & 0xff : 0; ++ int i2 = ip < iLen ? in[ip++] & 0xff : 0; ++ int o0 = i0 >>> 2; ++ int o1 = ((i0 & 3) << 4) | (i1 >>> 4); ++ int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6); ++ int o3 = i2 & 0x3F; ++ out[op++] = map1[o0]; ++ out[op++] = map1[o1]; ++ out[op] = op < oDataLen ? map1[o2] : '='; op++; ++ out[op] = op < oDataLen ? map1[o3] : '='; op++; } ++ return out; } ++ ++ /** ++ * Decodes a string from Base64 format. ++ * @param s a Base64 String to be decoded. ++ * @return A String containing the decoded data. ++ * @throws IllegalArgumentException if the input is not valid Base64 encoded data. ++ */ ++ public static String decodeString (String s) { ++ return new String(decode(s)); } ++ ++ /** ++ * Decodes a byte array from Base64 format. ++ * @param s a Base64 String to be decoded. ++ * @return An array containing the decoded data bytes. ++ * @throws IllegalArgumentException if the input is not valid Base64 encoded data. ++ */ ++ public static byte[] decode (String s) { ++ return decode(s.toCharArray()); } ++ ++ /** ++ * Decodes a byte array from Base64 format. ++ * No blanks or line breaks are allowed within the Base64 encoded data. ++ * @param in a character array containing the Base64 encoded data. ++ * @return An array containing the decoded data bytes. ++ * @throws IllegalArgumentException if the input is not valid Base64 encoded data. ++ */ ++ public static byte[] decode (char[] in) { ++ int iLen = in.length; ++ if (iLen%4 != 0) throw new IllegalArgumentException ("Length of Base64 encoded input string is not a multiple of 4."); ++ while (iLen > 0 && in[iLen-1] == '=') iLen--; ++ int oLen = (iLen*3) / 4; ++ byte[] out = new byte[oLen]; ++ int ip = 0; ++ int op = 0; ++ while (ip < iLen) { ++ int i0 = in[ip++]; ++ int i1 = in[ip++]; ++ int i2 = ip < iLen ? in[ip++] : 'A'; ++ int i3 = ip < iLen ? in[ip++] : 'A'; ++ if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127) ++ throw new IllegalArgumentException ("Illegal character in Base64 encoded data."); ++ int b0 = map2[i0]; ++ int b1 = map2[i1]; ++ int b2 = map2[i2]; ++ int b3 = map2[i3]; ++ if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0) ++ throw new IllegalArgumentException ("Illegal character in Base64 encoded data."); ++ int o0 = ( b0 <<2) | (b1>>>4); ++ int o1 = ((b1 & 0xf)<<4) | (b2>>>2); ++ int o2 = ((b2 & 3)<<6) | b3; ++ out[op++] = (byte)o0; ++ if (op<oLen) out[op++] = (byte)o1; ++ if (op<oLen) out[op++] = (byte)o2; } ++ return out; } ++ ++ // Dummy constructor. ++ private Base64Coder() {} ++ ++} diff -x VncCanvas.java -Naur vnc_javasrc.orig/VncViewer.java vnc_javasrc/VncViewer.java --- vnc_javasrc.orig/VncViewer.java 2004-03-04 08:34:25.000000000 -0500 +++ vnc_javasrc/VncViewer.java 2007-09-03 23:22:13.000000000 -0400 diff --git a/classes/ssl/ultravnc-102-JavaViewer-ssl-etc.patch b/classes/ssl/ultravnc-102-JavaViewer-ssl-etc.patch index f92d3c6..4db84d3 100644 --- a/classes/ssl/ultravnc-102-JavaViewer-ssl-etc.patch +++ b/classes/ssl/ultravnc-102-JavaViewer-ssl-etc.patch @@ -2644,8 +2644,8 @@ diff -Naur JavaViewer.orig/RfbProto.java JavaViewer/RfbProto.java // } diff -Naur JavaViewer.orig/SSLSocketToMe.java JavaViewer/SSLSocketToMe.java --- JavaViewer.orig/SSLSocketToMe.java 1969-12-31 19:00:00.000000000 -0500 -+++ JavaViewer/SSLSocketToMe.java 2008-04-15 12:54:51.000000000 -0400 -@@ -0,0 +1,1456 @@ ++++ JavaViewer/SSLSocketToMe.java 2009-06-18 09:47:22.000000000 -0400 +@@ -0,0 +1,1717 @@ +/* + * SSLSocketToMe.java: add SSL encryption to Java VNC Viewer. + * @@ -2701,6 +2701,7 @@ diff -Naur JavaViewer.orig/SSLSocketToMe.java JavaViewer/SSLSocketToMe.java + public DataInputStream is = null; + public OutputStream os = null; + ++ String proxy_auth_string = null; + String proxy_dialog_host = null; + int proxy_dialog_port = 0; + @@ -3219,9 +3220,9 @@ diff -Naur JavaViewer.orig/SSLSocketToMe.java JavaViewer/SSLSocketToMe.java + user_wants_to_see_cert = false; + } else { + bcd = new BrowserCertsDialog(serv, host + ":" + port); -+ dbg("bcd START"); ++ dbg("browser certs dialog START"); + bcd.queryUser(); -+ dbg("bcd DONE"); ++ dbg("browser certs dialog DONE"); + if (bcd.showCertDialog) { + String msg = "user wants to see cert"; + dbg(msg); @@ -3229,14 +3230,17 @@ diff -Naur JavaViewer.orig/SSLSocketToMe.java JavaViewer/SSLSocketToMe.java + throw new SSLHandshakeException(msg); + } else { + user_wants_to_see_cert = false; -+ dbg("bcd: user said yes, accept it"); ++ dbg("browser certs dialog: user said yes, accept it"); + } + } + + } catch (SSLHandshakeException eh) { + dbg("Could not automatically verify Server."); + dbg("msg: " + eh.getMessage()); ++ String getoutstr = "GET /index.vnc HTTP/1.0\r\nConnection: close\r\n\r\n"; + ++ OutputStream os = socket.getOutputStream(); ++ os.write(getoutstr.getBytes()); + socket.close(); + socket = null; + @@ -3272,6 +3276,8 @@ diff -Naur JavaViewer.orig/SSLSocketToMe.java JavaViewer/SSLSocketToMe.java + * close socket now, we will reopen after + * dialog if user agrees to use the cert. + */ ++ os = socket.getOutputStream(); ++ os.write(getoutstr.getBytes()); + socket.close(); + socket = null; + @@ -3293,6 +3299,15 @@ diff -Naur JavaViewer.orig/SSLSocketToMe.java JavaViewer/SSLSocketToMe.java + throw new IOException(ehand2.getMessage()); + } + ++ if (socket != null) { ++ try { ++ socket.close(); ++ } catch (Exception e) { ++ ; ++ } ++ socket = null; ++ } ++ + /* + * Now connect a 3rd time, using the cert + * retrieved during connection 2 (that the user @@ -3377,6 +3392,95 @@ diff -Naur JavaViewer.orig/SSLSocketToMe.java JavaViewer/SSLSocketToMe.java + return n; + } + ++ private void proxy_helper(String proxyHost, int proxyPort) { ++ ++ boolean proxy_auth = false; ++ String proxy_auth_basic_realm = ""; ++ String hp = host + ":" + port; ++ dbg("proxy_helper: " + proxyHost + ":" + proxyPort + " hp: " + hp); ++ ++ for (int k=0; k < 2; k++) { ++ dbg("proxy_in_use psocket:"); ++ ++ if (proxySock != null) { ++ try { ++ proxySock.close(); ++ } catch (Exception e) { ++ ; ++ } ++ } ++ ++ proxySock = psocket(proxyHost, proxyPort); ++ if (proxySock == null) { ++ dbg("1-a sadly, returning a null socket"); ++ return; ++ } ++ ++ String req1 = "CONNECT " + hp + " HTTP/1.1\r\n" ++ + "Host: " + hp + "\r\n"; ++ ++ dbg("requesting: " + req1); ++ ++ if (proxy_auth) { ++ if (proxy_auth_string == null) { ++ ProxyPasswdDialog pp = new ProxyPasswdDialog(proxyHost, proxyPort, proxy_auth_basic_realm); ++ pp.queryUser(); ++ proxy_auth_string = pp.getAuth(); ++ } ++ //dbg("auth1: " + proxy_auth_string); ++ String auth2 = Base64Coder.encodeString(proxy_auth_string); ++ //dbg("auth2: " + auth2); ++ req1 += "Proxy-Authorization: Basic " + auth2 + "\r\n"; ++ //dbg("req1: " + req1); ++ dbg("added Proxy-Authorization: Basic ... to request"); ++ } ++ req1 += "\r\n"; ++ ++ try { ++ proxy_os.write(req1.getBytes()); ++ String reply = readline(proxy_is); ++ ++ dbg("proxy replied: " + reply.trim()); ++ ++ if (reply.indexOf("HTTP/1.") == 0 && reply.indexOf(" 407 ") > 0) { ++ proxy_auth = true; ++ proxySock.close(); ++ } else 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; ++ } ++ } ++ } catch(Exception e) { ++ dbg("sock prob: " + e.getMessage()); ++ } ++ ++ while (true) { ++ String line = readline(proxy_is); ++ dbg("proxy line: " + line.trim()); ++ if (proxy_auth) { ++ String uc = line.toLowerCase(); ++ if (uc.indexOf("proxy-authenticate:") == 0) { ++ if (uc.indexOf(" basic ") >= 0) { ++ int idx = uc.indexOf(" realm"); ++ if (idx >= 0) { ++ proxy_auth_basic_realm = uc.substring(idx+1); ++ } ++ } ++ } ++ } ++ if (line.equals("\r\n") || line.equals("\n")) { ++ break; ++ } ++ } ++ if (!proxy_auth || proxy_auth_basic_realm.equals("")) { ++ break; ++ } ++ } ++ } ++ + public SSLSocket proxy_socket(SSLSocketFactory factory) { + Properties props = null; + String proxyHost = null; @@ -3483,44 +3587,10 @@ diff -Naur JavaViewer.orig/SSLSocketToMe.java JavaViewer/SSLSocketToMe.java + dbg("User said host: " + pd.getHost() + " port: " + pd.getPort()); + } + -+ dbg("proxy_in_use psocket:"); -+ proxySock = psocket(proxyHost, proxyPort); ++ proxy_helper(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); @@ -3562,7 +3632,6 @@ diff -Naur JavaViewer.orig/SSLSocketToMe.java JavaViewer/SSLSocketToMe.java + break; + } + } -+ + } + + Socket sslsock = null; @@ -3922,6 +3991,77 @@ diff -Naur JavaViewer.orig/SSLSocketToMe.java JavaViewer/SSLSocketToMe.java + } +} + ++class ProxyPasswdDialog implements ActionListener { ++ String guessedHost = null; ++ String guessedPort = null; ++ String guessedUser = null; ++ String guessedPasswd = null; ++ String realm = 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 entry1; ++ TextField entry2; ++ String reply1 = ""; ++ String reply2 = ""; ++ ++ ProxyPasswdDialog (String h, int p, String realm) { ++ guessedHost = h; ++ try { ++ guessedPort = Integer.toString(p); ++ } catch (Exception e) { ++ guessedPort = "8080"; ++ } ++ this.realm = realm; ++ } ++ ++ public void queryUser() { ++ ++ /* create and display the dialog for unverified cert. */ ++ ++ Frame frame = new Frame("Proxy Requires Username and Password"); ++ ++ dialog = new Dialog(frame, true); ++ ++ //Label label = new Label("Please Enter your Web Proxy Username in the top Entry and Password in the bottom Entry", Label.CENTER); ++ TextArea label = new TextArea("Please Enter your Web Proxy\nUsername in the Top Entry and\nPassword in the Bottom Entry,\nand then press OK.", 4, 20, TextArea.SCROLLBARS_NONE); ++ entry1 = new TextField(30); ++ entry2 = new TextField(30); ++ entry2.setEchoChar('*'); ++ ok = new Button("OK"); ++ ok.addActionListener(this); ++ ++ dialog.setLayout(new BorderLayout()); ++ dialog.add("North", label); ++ dialog.add("Center", entry1); ++ dialog.add("South", entry2); ++ dialog.add("East", ok); ++ dialog.pack(); ++ dialog.resize(dialog.preferredSize()); ++ ++ dialog.show(); /* block here til OK or Cancel pressed. */ ++ return; ++ } ++ ++ public String getAuth() { ++ return reply1 + ":" + reply2; ++ } ++ ++ public synchronized void actionPerformed(ActionEvent evt) { ++ System.out.println(evt.getActionCommand()); ++ if (evt.getSource() == ok) { ++ reply1 = entry1.getText(); ++ reply2 = entry2.getText(); ++ //dialog.dispose(); ++ dialog.hide(); ++ } ++ } ++} ++ +class ClientCertDialog implements ActionListener { + + Button ok; @@ -4102,6 +4242,127 @@ diff -Naur JavaViewer.orig/SSLSocketToMe.java JavaViewer/SSLSocketToMe.java + } + } +} ++ ++class Base64Coder { ++ ++ // Mapping table from 6-bit nibbles to Base64 characters. ++ private static char[] map1 = new char[64]; ++ static { ++ int i=0; ++ for (char c='A'; c<='Z'; c++) map1[i++] = c; ++ for (char c='a'; c<='z'; c++) map1[i++] = c; ++ for (char c='0'; c<='9'; c++) map1[i++] = c; ++ map1[i++] = '+'; map1[i++] = '/'; } ++ ++ // Mapping table from Base64 characters to 6-bit nibbles. ++ private static byte[] map2 = new byte[128]; ++ static { ++ for (int i=0; i<map2.length; i++) map2[i] = -1; ++ for (int i=0; i<64; i++) map2[map1[i]] = (byte)i; } ++ ++ /** ++ * Encodes a string into Base64 format. ++ * No blanks or line breaks are inserted. ++ * @param s a String to be encoded. ++ * @return A String with the Base64 encoded data. ++ */ ++ public static String encodeString (String s) { ++ return new String(encode(s.getBytes())); } ++ ++ /** ++ * Encodes a byte array into Base64 format. ++ * No blanks or line breaks are inserted. ++ * @param in an array containing the data bytes to be encoded. ++ * @return A character array with the Base64 encoded data. ++ */ ++ public static char[] encode (byte[] in) { ++ return encode(in,in.length); } ++ ++ /** ++ * Encodes a byte array into Base64 format. ++ * No blanks or line breaks are inserted. ++ * @param in an array containing the data bytes to be encoded. ++ * @param iLen number of bytes to process in <code>in</code>. ++ * @return A character array with the Base64 encoded data. ++ */ ++ public static char[] encode (byte[] in, int iLen) { ++ int oDataLen = (iLen*4+2)/3; // output length without padding ++ int oLen = ((iLen+2)/3)*4; // output length including padding ++ char[] out = new char[oLen]; ++ int ip = 0; ++ int op = 0; ++ while (ip < iLen) { ++ int i0 = in[ip++] & 0xff; ++ int i1 = ip < iLen ? in[ip++] & 0xff : 0; ++ int i2 = ip < iLen ? in[ip++] & 0xff : 0; ++ int o0 = i0 >>> 2; ++ int o1 = ((i0 & 3) << 4) | (i1 >>> 4); ++ int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6); ++ int o3 = i2 & 0x3F; ++ out[op++] = map1[o0]; ++ out[op++] = map1[o1]; ++ out[op] = op < oDataLen ? map1[o2] : '='; op++; ++ out[op] = op < oDataLen ? map1[o3] : '='; op++; } ++ return out; } ++ ++ /** ++ * Decodes a string from Base64 format. ++ * @param s a Base64 String to be decoded. ++ * @return A String containing the decoded data. ++ * @throws IllegalArgumentException if the input is not valid Base64 encoded data. ++ */ ++ public static String decodeString (String s) { ++ return new String(decode(s)); } ++ ++ /** ++ * Decodes a byte array from Base64 format. ++ * @param s a Base64 String to be decoded. ++ * @return An array containing the decoded data bytes. ++ * @throws IllegalArgumentException if the input is not valid Base64 encoded data. ++ */ ++ public static byte[] decode (String s) { ++ return decode(s.toCharArray()); } ++ ++ /** ++ * Decodes a byte array from Base64 format. ++ * No blanks or line breaks are allowed within the Base64 encoded data. ++ * @param in a character array containing the Base64 encoded data. ++ * @return An array containing the decoded data bytes. ++ * @throws IllegalArgumentException if the input is not valid Base64 encoded data. ++ */ ++ public static byte[] decode (char[] in) { ++ int iLen = in.length; ++ if (iLen%4 != 0) throw new IllegalArgumentException ("Length of Base64 encoded input string is not a multiple of 4."); ++ while (iLen > 0 && in[iLen-1] == '=') iLen--; ++ int oLen = (iLen*3) / 4; ++ byte[] out = new byte[oLen]; ++ int ip = 0; ++ int op = 0; ++ while (ip < iLen) { ++ int i0 = in[ip++]; ++ int i1 = in[ip++]; ++ int i2 = ip < iLen ? in[ip++] : 'A'; ++ int i3 = ip < iLen ? in[ip++] : 'A'; ++ if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127) ++ throw new IllegalArgumentException ("Illegal character in Base64 encoded data."); ++ int b0 = map2[i0]; ++ int b1 = map2[i1]; ++ int b2 = map2[i2]; ++ int b3 = map2[i3]; ++ if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0) ++ throw new IllegalArgumentException ("Illegal character in Base64 encoded data."); ++ int o0 = ( b0 <<2) | (b1>>>4); ++ int o1 = ((b1 & 0xf)<<4) | (b2>>>2); ++ int o2 = ((b2 & 3)<<6) | b3; ++ out[op++] = (byte)o0; ++ if (op<oLen) out[op++] = (byte)o1; ++ if (op<oLen) out[op++] = (byte)o2; } ++ return out; } ++ ++ // Dummy constructor. ++ private Base64Coder() {} ++ ++} 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-31 15:33:20.000000000 -0400 |