diff options
author | Brian Hinz <bphinz@users.sourceforge.net> | 2012-04-05 03:37:50 +0000 |
---|---|---|
committer | Brian Hinz <bphinz@users.sourceforge.net> | 2012-04-05 03:37:50 +0000 |
commit | cf0e312b59e1c0afb4996188afafc8835eec191d (patch) | |
tree | 4a644800acad93b144100955d380991efa3faf1e /java/com/tigervnc | |
parent | b3ea375488ddb5ca8f9e90f7be95a269571262ad (diff) | |
download | tigervnc-cf0e312b59e1c0afb4996188afafc8835eec191d.tar.gz tigervnc-cf0e312b59e1c0afb4996188afafc8835eec191d.zip |
adds experimental support for SSH tunneling to the Java client. Has not been tested with large desktop sizes yet. CMakeLists.txt needs some rework.
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4882 3789f03b-4d11-0410-bbf8-ca57d06f2519
Diffstat (limited to 'java/com/tigervnc')
-rw-r--r-- | java/com/tigervnc/network/TcpListener.java | 2 | ||||
-rw-r--r-- | java/com/tigervnc/network/TcpSocket.java | 34 | ||||
-rw-r--r-- | java/com/tigervnc/vncviewer/CConn.java | 2 | ||||
-rw-r--r-- | java/com/tigervnc/vncviewer/PasswdDialog.java | 90 | ||||
-rw-r--r-- | java/com/tigervnc/vncviewer/VncViewer.java | 100 |
5 files changed, 204 insertions, 24 deletions
diff --git a/java/com/tigervnc/network/TcpListener.java b/java/com/tigervnc/network/TcpListener.java index 4cc8c0da..cb0a69aa 100644 --- a/java/com/tigervnc/network/TcpListener.java +++ b/java/com/tigervnc/network/TcpListener.java @@ -100,7 +100,7 @@ public class TcpListener extends SocketListener { // Accept an incoming connection try { - if (selector.select() > 0) { + if (selector.select(0) > 0) { Set keys = selector.selectedKeys(); Iterator iter = keys.iterator(); while (iter.hasNext()) { diff --git a/java/com/tigervnc/network/TcpSocket.java b/java/com/tigervnc/network/TcpSocket.java index 9277dd14..1d127f50 100644 --- a/java/com/tigervnc/network/TcpSocket.java +++ b/java/com/tigervnc/network/TcpSocket.java @@ -171,29 +171,23 @@ public class TcpSocket extends Socket { return ((InetSocketAddress)((SocketDescriptor)getFd()).socket().getRemoteSocketAddress()).getPort(); } + /* Tunnelling support. */ + public static int findFreeTcpPort() { + java.net.ServerSocket sock; + int port; + try { + sock = new java.net.ServerSocket(0); + port = sock.getLocalPort(); + sock.close(); + } catch (java.io.IOException e) { + throw new SocketException("unable to create socket: "+e.toString()); + } + return port; + } + private boolean closeFd; static LogWriter vlog = new LogWriter("TcpSocket"); } -/* Tunnelling support. */ -/* -public int findFreeTcpPort() { - int sock; - - if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) - throw SocketException("unable to create socket", errorNumber); - - int port = 0; - if (bind (sock, (struct sockaddr *)&addr, sizeof (addr)) < 0) - throw SocketException("unable to find free port", errorNumber); - - socklen_t n = sizeof(addr); - if (getsockname (sock, (struct sockaddr *)&addr, &n) < 0) - throw SocketException("unable to get port number", errorNumber); - - closesocket(sock); - return ntohs(addr.sin_port); -} -*/ diff --git a/java/com/tigervnc/vncviewer/CConn.java b/java/com/tigervnc/vncviewer/CConn.java index a87ddaea..053bef2a 100644 --- a/java/com/tigervnc/vncviewer/CConn.java +++ b/java/com/tigervnc/vncviewer/CConn.java @@ -314,7 +314,7 @@ public class CConn extends CConnection } } if (passwd != null) - passwd.append(dlg.passwdEntry.getText()); + passwd.append(new String(dlg.passwdEntry.getPassword())); return true; } diff --git a/java/com/tigervnc/vncviewer/PasswdDialog.java b/java/com/tigervnc/vncviewer/PasswdDialog.java index d947828d..51c268fa 100644 --- a/java/com/tigervnc/vncviewer/PasswdDialog.java +++ b/java/com/tigervnc/vncviewer/PasswdDialog.java @@ -18,10 +18,14 @@ package com.tigervnc.vncviewer; +import java.awt.*; import java.awt.event.*; import javax.swing.*; +import com.jcraft.jsch.*; -class PasswdDialog extends Dialog implements KeyListener{ +class PasswdDialog extends Dialog implements KeyListener, + UserInfo, + UIKeyboardInteractive { public PasswdDialog(String title, boolean userDisabled, boolean passwdDisabled) { super(true); @@ -79,8 +83,90 @@ class PasswdDialog extends Dialog implements KeyListener{ } } + public String getPassword(){ + return new String(passwdEntry.getPassword()); + } + public String getPassphrase(){ return null; } + public boolean promptPassphrase(String message){ return false; } + public boolean promptPassword(String message){ + setTitle(message); + showDialog(); + if (passwdEntry != null) + return true; + return false; + } + public void showMessage(String message){ + JOptionPane.showMessageDialog(null, message); + } + public boolean promptYesNo(String str){ + Object[] options={ "yes", "no" }; + int foo=JOptionPane.showOptionDialog(null, + str, + "Warning", + JOptionPane.DEFAULT_OPTION, + JOptionPane.WARNING_MESSAGE, + null, options, options[0]); + return foo==0; + } + public String[] promptKeyboardInteractive(String destination, + String name, + String instruction, + String[] prompt, + boolean[] echo){ + Container panel = new JPanel(); + panel.setLayout(new GridBagLayout()); + + GridBagConstraints gbc = + new GridBagConstraints(0,0,1,1,1,1, + GridBagConstraints.NORTHWEST, + GridBagConstraints.NONE, + new Insets(0,0,0,0),0,0); + gbc.weightx = 1.0; + gbc.gridwidth = GridBagConstraints.REMAINDER; + gbc.gridx = 0; + panel.add(new JLabel(instruction), gbc); + gbc.gridy++; + + gbc.gridwidth = GridBagConstraints.RELATIVE; + + JTextField[] texts=new JTextField[prompt.length]; + for(int i=0; i<prompt.length; i++){ + gbc.fill = GridBagConstraints.NONE; + gbc.gridx = 0; + gbc.weightx = 1; + panel.add(new JLabel(prompt[i]),gbc); + + gbc.gridx = 1; + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.weighty = 1; + if(echo[i]){ + texts[i]=new JTextField(20); + } + else{ + texts[i]=new JPasswordField(20); + } + panel.add(texts[i], gbc); + gbc.gridy++; + } + + if(JOptionPane.showConfirmDialog(null, panel, + destination+": "+name, + JOptionPane.OK_CANCEL_OPTION, + JOptionPane.QUESTION_MESSAGE) + ==JOptionPane.OK_OPTION){ + String[] response=new String[prompt.length]; + for(int i=0; i<prompt.length; i++){ + response[i]=texts[i].getText(); + } + return response; + } + else{ + return null; // cancel + } + } + JLabel userLabel; JTextField userEntry; JLabel passwdLabel; - JTextField passwdEntry; + JPasswordField passwdEntry; } diff --git a/java/com/tigervnc/vncviewer/VncViewer.java b/java/com/tigervnc/vncviewer/VncViewer.java index 91504d2c..f7d1f62a 100644 --- a/java/com/tigervnc/vncviewer/VncViewer.java +++ b/java/com/tigervnc/vncviewer/VncViewer.java @@ -33,15 +33,21 @@ import java.awt.Graphics; import java.awt.Image; import java.io.InputStream; import java.io.IOException; +import java.io.File; import java.lang.Character; import java.util.jar.Attributes; import java.util.jar.Manifest; +import java.util.ArrayList; +import java.util.Iterator; import javax.swing.*; import com.tigervnc.rdr.*; import com.tigervnc.rfb.*; import com.tigervnc.network.*; +import com.jcraft.jsch.JSch; +import com.jcraft.jsch.Session; + public class VncViewer extends java.applet.Applet implements Runnable { public static final String about1 = "TigerVNC Viewer for Java"; @@ -130,6 +136,82 @@ public class VncViewer extends java.applet.Applet implements Runnable System.exit(1); } + /* Tunnelling support. */ + private void interpretViaParam(StringParameter gatewayHost, + StringParameter remoteHost, IntParameter remotePort, + StringParameter vncServerName, IntParameter localPort) + { + final int SERVER_PORT_OFFSET = 5900;; + int pos = vncServerName.getValueStr().indexOf(":"); + if (pos == -1) + remotePort.setParam(""+SERVER_PORT_OFFSET+""); + else { + int portOffset = SERVER_PORT_OFFSET; + int len; + pos++; + len = vncServerName.getValueStr().substring(pos).length(); + if (vncServerName.getValueStr().substring(pos, pos).equals(":")) { + /* Two colons is an absolute port number, not an offset. */ + pos++; + len--; + portOffset = 0; + } + try { + if (len <= 0 || !vncServerName.getValueStr().substring(pos).matches("[0-9]+")) + usage(); + portOffset += Integer.parseInt(vncServerName.getValueStr().substring(pos)); + remotePort.setParam(""+portOffset+""); + } catch (java.lang.NumberFormatException e) { + usage(); + } + } + + if (vncServerName != null) + remoteHost.setParam(vncServerName.getValueStr().split(":")[0]); + + gatewayHost.setParam(via.getValueStr()); + vncServerName.setParam("localhost::"+localPort.getValue()); + } + + private void + createTunnel(String gatewayHost, String remoteHost, + int remotePort, int localPort) + { + try{ + JSch jsch=new JSch(); + String homeDir = new String(""); + try { + homeDir = System.getProperty("user.home"); + } catch(java.security.AccessControlException e) { + System.out.println("Cannot access user.home system property"); + } + // NOTE: jsch does not support all ciphers. User may be + // prompted to accept host key authenticy even if + // the key is in the known_hosts file. + File knownHosts = new File(homeDir+"/.ssh/known_hosts"); + if (knownHosts.exists() && knownHosts.canRead()) + jsch.setKnownHosts(knownHosts.getAbsolutePath()); + ArrayList<File> privateKeys = new ArrayList<File>(); + privateKeys.add(new File(homeDir+"/.ssh/id_rsa")); + privateKeys.add(new File(homeDir+"/.ssh/id_dsa")); + for (Iterator i = privateKeys.iterator(); i.hasNext();) { + File privateKey = (File)i.next(); + if (privateKey.exists() && privateKey.canRead()) + jsch.addIdentity(privateKey.getAbsolutePath()); + } + // username and passphrase will be given via UserInfo interface. + PasswdDialog dlg = new PasswdDialog(new String("SSH Authentication"), false, false); + dlg.userEntry.setText((String)System.getProperties().get("user.name")); + Session session=jsch.getSession(dlg.userEntry.getText(), gatewayHost, 22); + session.setUserInfo(dlg); + session.connect(); + + session.setPortForwardingL(localPort, remoteHost, remotePort); + } catch (java.lang.Exception e) { + System.out.println(e); + } + } + public VncViewer() { applet = true; firstApplet = true; @@ -193,6 +275,21 @@ public class VncViewer extends java.applet.Applet implements Runnable CConn cc = null; Socket sock = null; + /* Tunnelling support. */ + if (via.getValueStr() != null) { + StringParameter gatewayHost = new StringParameter("", "", ""); + StringParameter remoteHost = new StringParameter("", "", "localhost"); + IntParameter localPort = + new IntParameter("", "", TcpSocket.findFreeTcpPort()); + IntParameter remotePort = new IntParameter("", "", 5900); + if (vncServerName.getValueStr() == null) + usage(); + interpretViaParam(gatewayHost, remoteHost, remotePort, + vncServerName, localPort); + createTunnel(gatewayHost.getValueStr(), remoteHost.getValueStr(), + remotePort.getValue(), localPort.getValue()); + } + if (listenMode.getValue()) { int port = 5500; @@ -322,6 +419,9 @@ public class VncViewer extends java.applet.Applet implements Runnable = new BoolParameter("AcceptBell", "Produce a system beep when requested to by the server.", true); + StringParameter via + = new StringParameter("via", "Gateway to tunnel via", null); + BoolParameter customCompressLevel = new BoolParameter("CustomCompressLevel", "Use custom compression level. "+ |