diff options
-rw-r--r-- | java/com/tigervnc/rfb/CSecurity.java | 2 | ||||
-rw-r--r-- | java/com/tigervnc/rfb/CSecurityIdent.java | 7 | ||||
-rw-r--r-- | java/com/tigervnc/rfb/CSecurityPlain.java | 4 | ||||
-rw-r--r-- | java/com/tigervnc/rfb/CSecurityTLS.java | 66 | ||||
-rw-r--r-- | java/com/tigervnc/rfb/CSecurityVeNCrypt.java | 8 | ||||
-rw-r--r-- | java/com/tigervnc/rfb/CSecurityVncAuth.java | 2 | ||||
-rw-r--r-- | java/com/tigervnc/rfb/SecurityClient.java | 11 | ||||
-rw-r--r-- | java/com/tigervnc/rfb/UserPasswdGetter.java | 2 | ||||
-rw-r--r-- | java/com/tigervnc/vncviewer/CConn.java | 58 | ||||
-rw-r--r-- | java/com/tigervnc/vncviewer/UserDialog.java | 187 | ||||
-rw-r--r-- | java/com/tigervnc/vncviewer/VncViewer.java | 3 |
11 files changed, 243 insertions, 107 deletions
diff --git a/java/com/tigervnc/rfb/CSecurity.java b/java/com/tigervnc/rfb/CSecurity.java index f67680cd..a99a5f87 100644 --- a/java/com/tigervnc/rfb/CSecurity.java +++ b/java/com/tigervnc/rfb/CSecurity.java @@ -42,5 +42,5 @@ abstract public class CSecurity { * Use variable directly instead of dumb get/set methods. * It MUST be set by viewer. */ - static UserPasswdGetter upg; + public static UserPasswdGetter upg; } diff --git a/java/com/tigervnc/rfb/CSecurityIdent.java b/java/com/tigervnc/rfb/CSecurityIdent.java index 9eb6e0b6..e53432bf 100644 --- a/java/com/tigervnc/rfb/CSecurityIdent.java +++ b/java/com/tigervnc/rfb/CSecurityIdent.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Brian P. Hinz +/* Copyright (C) 2011-2017 Brian P. Hinz * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,7 +30,7 @@ public class CSecurityIdent extends CSecurity { StringBuffer username = new StringBuffer(); - CConn.upg.getUserPasswd(username, null); + upg.getUserPasswd(username, null); // Return the response to the server os.writeU32(username.length()); @@ -46,9 +46,6 @@ public class CSecurityIdent extends CSecurity { public int getType() { return Security.secTypeIdent; } - java.net.Socket sock; - UserPasswdGetter upg; - static LogWriter vlog = new LogWriter("Ident"); public String description() { return "No Encryption"; } diff --git a/java/com/tigervnc/rfb/CSecurityPlain.java b/java/com/tigervnc/rfb/CSecurityPlain.java index d6f8ffde..98f6b8cc 100644 --- a/java/com/tigervnc/rfb/CSecurityPlain.java +++ b/java/com/tigervnc/rfb/CSecurityPlain.java @@ -1,6 +1,6 @@ /* Copyright (C) 2005 Martin Koegler * Copyright (C) 2010 TigerVNC Team - * Copyright (C) 2011 Brian P. Hinz + * Copyright (C) 2011-2017 Brian P. Hinz * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,7 +34,7 @@ public class CSecurityPlain extends CSecurity { StringBuffer username = new StringBuffer(); StringBuffer password = new StringBuffer(); - CConn.upg.getUserPasswd(username, password); + upg.getUserPasswd(username, password); // Return the response to the server os.writeU32(username.length()); diff --git a/java/com/tigervnc/rfb/CSecurityTLS.java b/java/com/tigervnc/rfb/CSecurityTLS.java index 733e97d4..c91f36a1 100644 --- a/java/com/tigervnc/rfb/CSecurityTLS.java +++ b/java/com/tigervnc/rfb/CSecurityTLS.java @@ -56,6 +56,8 @@ import com.tigervnc.rdr.*; import com.tigervnc.network.*; import com.tigervnc.vncviewer.*; +import static javax.swing.JOptionPane.*; + public class CSecurityTLS extends CSecurity { public static StringParameter X509CA @@ -64,6 +66,7 @@ public class CSecurityTLS extends CSecurity { public static StringParameter X509CRL = new StringParameter("X509CRL", "X509 CRL file", "", Configuration.ConfigurationObject.ConfViewer); + public static UserMsgBox msg; private void initGlobal() { @@ -254,6 +257,16 @@ public class CSecurityTLS extends CSecurity { { Collection<? extends Certificate> certs = null; X509Certificate cert = chain[0]; + try { + cert.checkValidity(); + } catch(CertificateNotYetValidException e) { + throw new AuthFailureException("server certificate has not been activated"); + } catch(CertificateExpiredException e) { + if (!msg.showMsgBox(YES_NO_OPTION, "certificate has expired", + "The certificate of the server has expired, "+ + "do you want to continue?")) + throw new AuthFailureException("server certificate has expired"); + } String thumbprint = getThumbprint(cert); File vncDir = new File(FileUtils.getVncHomeDir()); File certFile = new File(vncDir, "x509_savedcerts.pem"); @@ -270,8 +283,7 @@ public class CSecurityTLS extends CSecurity { tm.checkServerTrusted(chain, authType); } catch (java.lang.Exception e) { if (e.getCause() instanceof CertPathBuilderException) { - Object[] answer = {"YES", "NO"}; - int ret = JOptionPane.showOptionDialog(null, + String certinfo = "This certificate has been signed by an unknown authority\n"+ "\n"+ " Subject: "+cert.getSubjectX500Principal().getName()+"\n"+ @@ -283,46 +295,38 @@ public class CSecurityTLS extends CSecurity { " Not Valid After: "+cert.getNotAfter()+"\n"+ " SHA1 Fingerprint: "+getThumbprint(cert)+"\n"+ "\n"+ - "Do you want to save it and continue?", - "Certificate Issuer Unknown", - JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, - null, answer, answer[0]); - if (ret == JOptionPane.YES_OPTION) { + "Do you want to save it and continue?"; + if (!msg.showMsgBox(YES_NO_OPTION, "certificate issuer unknown", + certinfo)) { + throw new AuthFailureException("certificate issuer unknown"); + } + if (certs == null || !certs.contains(cert)) { + byte[] der = cert.getEncoded(); + String pem = DatatypeConverter.printBase64Binary(der); + pem = pem.replaceAll("(.{64})", "$1\n"); + FileWriter fw = null; try { if (!vncDir.exists()) vncDir.mkdir(); if (!certFile.exists() && !certFile.createNewFile()) { vlog.error("Certificate save failed."); - return; - } - } catch (java.lang.Exception ioe) { - // skip save if security settings prohibit access to filesystem - vlog.error("Certificate save failed: "+ioe.getMessage()); - return; - } - if (certs == null || !certs.contains(cert)) { - byte[] der = cert.getEncoded(); - String pem = DatatypeConverter.printBase64Binary(der); - pem = pem.replaceAll("(.{64})", "$1\n"); - FileWriter fw = null; - try { + } else { fw = new FileWriter(certFile.getAbsolutePath(), true); fw.write("-----BEGIN CERTIFICATE-----\n"); fw.write(pem+"\n"); fw.write("-----END CERTIFICATE-----\n"); - } catch (IOException ioe) { - throw new Exception(ioe.getMessage()); - } finally { - try { - if (fw != null) - fw.close(); - } catch(IOException ioe2) { - throw new Exception(ioe2.getMessage()); - } + } + } catch (IOException ioe) { + msg.showMsgBox(OK_OPTION, "certificate save failed", + "Could not save the certificate"); + } finally { + try { + if (fw != null) + fw.close(); + } catch(IOException ioe2) { + throw new Exception(ioe2.getMessage()); } } - } else { - throw new WarningException("Peer certificate verification failed."); } } else { throw new SystemException(e.getMessage()); diff --git a/java/com/tigervnc/rfb/CSecurityVeNCrypt.java b/java/com/tigervnc/rfb/CSecurityVeNCrypt.java index 179900a4..daf205cd 100644 --- a/java/com/tigervnc/rfb/CSecurityVeNCrypt.java +++ b/java/com/tigervnc/rfb/CSecurityVeNCrypt.java @@ -178,7 +178,13 @@ public class CSecurityVeNCrypt extends CSecurity { } public final int getType() { return chosenType; } - public final String description() { return Security.secTypeName(chosenType); } + public final String description() + { + if (csecurity != null) + return csecurity.description(); + return "VeNCrypt"; + } + public static StringParameter secTypesStr; diff --git a/java/com/tigervnc/rfb/CSecurityVncAuth.java b/java/com/tigervnc/rfb/CSecurityVncAuth.java index e053e410..e8c5686d 100644 --- a/java/com/tigervnc/rfb/CSecurityVncAuth.java +++ b/java/com/tigervnc/rfb/CSecurityVncAuth.java @@ -36,7 +36,7 @@ public class CSecurityVncAuth extends CSecurity { byte[] challenge = new byte[vncAuthChallengeSize]; is.readBytes(challenge, 0, vncAuthChallengeSize); StringBuffer passwd = new StringBuffer(); - CConn.upg.getUserPasswd(null, passwd); + upg.getUserPasswd(null, passwd); // Calculate the correct response byte[] key = new byte[8]; diff --git a/java/com/tigervnc/rfb/SecurityClient.java b/java/com/tigervnc/rfb/SecurityClient.java index ff2433c2..d3557337 100644 --- a/java/com/tigervnc/rfb/SecurityClient.java +++ b/java/com/tigervnc/rfb/SecurityClient.java @@ -1,6 +1,6 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. * Copyright (C) 2010 TigerVNC Team - * Copyright (C) 2011-2012 Brian P. Hinz + * Copyright (C) 2011-2017 Brian P. Hinz * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,16 +20,14 @@ package com.tigervnc.rfb; -import com.tigervnc.vncviewer.CConn; - public class SecurityClient extends Security { public SecurityClient() { super(secTypes); } public CSecurity GetCSecurity(int secType) { - assert (CConn.upg != null); /* (upg == null) means bug in the viewer */ - assert (msg != null); + assert (CSecurity.upg != null); /* (upg == null) means bug in the viewer */ + assert (CSecurityTLS.msg != null); if (!IsSupported(secType)) throw new Exception("Security type not supported"); @@ -75,9 +73,6 @@ public class SecurityClient extends Security { CSecurityTLS.setDefaults(); } - //UserPasswdGetter upg = null; - String msg = null; - public static StringParameter secTypes = new StringParameter("SecurityTypes", "Specify which security scheme to use (None, VncAuth, Plain, Ident, TLSNone, TLSVnc, TLSPlain, TLSIdent, X509None, X509Vnc, X509Plain, X509Ident)", diff --git a/java/com/tigervnc/rfb/UserPasswdGetter.java b/java/com/tigervnc/rfb/UserPasswdGetter.java index feb05ed1..7390b11a 100644 --- a/java/com/tigervnc/rfb/UserPasswdGetter.java +++ b/java/com/tigervnc/rfb/UserPasswdGetter.java @@ -23,5 +23,5 @@ package com.tigervnc.rfb; public interface UserPasswdGetter { - public boolean getUserPasswd(StringBuffer user, StringBuffer password); + public void getUserPasswd(StringBuffer user, StringBuffer password); } diff --git a/java/com/tigervnc/vncviewer/CConn.java b/java/com/tigervnc/vncviewer/CConn.java index d71c307f..3aee46d5 100644 --- a/java/com/tigervnc/vncviewer/CConn.java +++ b/java/com/tigervnc/vncviewer/CConn.java @@ -63,7 +63,7 @@ import com.tigervnc.network.TcpSocket; import static com.tigervnc.vncviewer.Parameters.*; public class CConn extends CConnection implements - UserPasswdGetter, FdInStreamBlockCallback, ActionListener { + FdInStreamBlockCallback, ActionListener { // 8 colours (1 bit per component) static final PixelFormat verylowColorPF = @@ -92,8 +92,6 @@ public class CConn extends CConnection implements setShared(shared.getValue()); sock = socket; - upg = this; - int encNum = Encodings.encodingNum(preferredEncoding.getValue()); if (encNum != -1) currentEncoding = encNum; @@ -208,58 +206,6 @@ public class CConn extends CConnection implements } } - // getUserPasswd() is called by the CSecurity object when it needs us to read - // a password from the user. - - public final boolean getUserPasswd(StringBuffer user, StringBuffer passwd) { - String title = ("VNC Authentication [" - +csecurity.description() + "]"); - String passwordFileStr = passwordFile.getValue(); - PasswdDialog dlg; - - if (user == null && !passwordFileStr.equals("")) { - InputStream fp = null; - try { - fp = new FileInputStream(passwordFileStr); - } catch(FileNotFoundException e) { - throw new Exception("Opening password file failed"); - } - byte[] obfPwd = new byte[256]; - try { - fp.read(obfPwd); - fp.close(); - } catch(IOException e) { - throw new Exception("Failed to read VncPasswd file"); - } - String PlainPasswd = VncAuth.unobfuscatePasswd(obfPwd); - passwd.append(PlainPasswd); - passwd.setLength(PlainPasswd.length()); - return true; - } - - if (user == null) { - dlg = new PasswdDialog(title, (user == null), (passwd == null)); - } else { - if ((passwd == null) && sendLocalUsername.getValue()) { - user.append((String)System.getProperties().get("user.name")); - return true; - } - dlg = new PasswdDialog(title, sendLocalUsername.getValue(), - (passwd == null)); - } - dlg.showDialog(); - if (user != null) { - if (sendLocalUsername.getValue()) { - user.append((String)System.getProperties().get("user.name")); - } else { - user.append(dlg.userEntry.getText()); - } - } - if (passwd != null) - passwd.append(new String(dlg.passwdEntry.getPassword())); - return true; - } - ////////////////////// CConnection callback methods ////////////////////// // serverInit() is called when the serverInit message has been received. At @@ -729,8 +675,6 @@ public class CConn extends CConnection implements // the following need no synchronization: - public static UserPasswdGetter upg; - // shuttingDown is set by the GUI thread and only ever tested by the RFB // thread after the window has been destroyed. boolean shuttingDown = false; diff --git a/java/com/tigervnc/vncviewer/UserDialog.java b/java/com/tigervnc/vncviewer/UserDialog.java new file mode 100644 index 00000000..fad836a5 --- /dev/null +++ b/java/com/tigervnc/vncviewer/UserDialog.java @@ -0,0 +1,187 @@ +/* Copyright (C) 2017 Brian P. Hinz + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +package com.tigervnc.vncviewer; + +import java.awt.*; +import java.awt.event.*; +import java.io.IOException; +import java.io.InputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.util.*; +import javax.swing.*; +import javax.swing.event.*; +import javax.swing.border.*; +import javax.swing.plaf.LayerUI; + +import com.tigervnc.rfb.*; +import com.tigervnc.rfb.Point; +import com.tigervnc.rfb.Exception; + +import static com.tigervnc.vncviewer.Parameters.*; +import static javax.swing.GroupLayout.*; +import static javax.swing.JOptionPane.*; + + +public class UserDialog implements UserPasswdGetter, UserMsgBox +{ + private class MyLayerUI extends LayerUI { + // Using a JButton for the "?" icon yields the best look, but there + // does not seem to be any reasonable way to disable a JButton without + // also changing the color. This wrapper just intercepts any mouse + // click events so that the button just looks like an icon. + @Override + public void eventDispatched(AWTEvent e, JLayer l) { + if (e instanceof InputEvent) + ((InputEvent) e).consume(); + } + + @Override + public void installUI(JComponent c) { + super.installUI(c); + if (c instanceof JLayer) { + JLayer<?> layer = (JLayer<?>)c; + layer.setLayerEventMask(AWTEvent.MOUSE_EVENT_MASK); + } + } + + @Override + protected void processMouseEvent(MouseEvent e, JLayer l) { + super.processMouseEvent(e, l); + } + } + + public final void getUserPasswd(StringBuffer user, StringBuffer password) + { + String passwordFileStr = passwordFile.getValue(); + + if ((password == null) && sendLocalUsername.getValue()) { + user.append((String)System.getProperties().get("user.name")); + return; + } + + if (user == null && !passwordFileStr.equals("")) { + InputStream fp = null; + try { + fp = new FileInputStream(passwordFileStr); + } catch(FileNotFoundException e) { + throw new Exception("Opening password file failed"); + } + byte[] obfPwd = new byte[256]; + try { + fp.read(obfPwd); + fp.close(); + } catch(IOException e) { + throw new Exception("Failed to read VncPasswd file"); + } + String PlainPasswd = VncAuth.unobfuscatePasswd(obfPwd); + password.append(PlainPasswd); + password.setLength(PlainPasswd.length()); + return; + } + + JDialog win; + JTextField username = null; + JPasswordField passwd = null; + JLayer icon; + + int y; + + JPanel msg = new JPanel(null); + msg.setSize(410, 145); + + y = 10; + + JButton iconb = new JButton("?"); + iconb.setVerticalAlignment(JLabel.CENTER); + iconb.setFont(new Font("Times", Font.BOLD, 34)); + iconb.setForeground(Color.BLUE); + LayerUI ui = new MyLayerUI(); + icon = new JLayer(iconb, ui); + icon.setBounds(10, y, 50, 50); + msg.add(icon); + + y += 5; + + if (user != null && !sendLocalUsername.getValue()) { + JLabel userLabel = new JLabel("Username:"); + userLabel.setBounds(70, y, msg.getSize().width-70-10, 20); + msg.add(userLabel); + y += 20 + 5; + username = new JTextField(30); + username.setBounds(70, y, msg.getSize().width-70-10, 25); + msg.add(username); + y += 25 + 5; + } + + JLabel passwdLabel = new JLabel("Password:"); + passwdLabel.setBounds(70, y, msg.getSize().width-70-10, 20); + msg.add(passwdLabel); + y += 20 + 5; + passwd = new JPasswordField(30); + passwd.setBounds(70, y, msg.getSize().width-70-10, 25); + msg.add(passwd); + y += 25 + 5; + + msg.setPreferredSize(new Dimension(410, y)); + + Object[] options = {"OK \u21B5", "Cancel"}; + JOptionPane pane = new JOptionPane(msg, + PLAIN_MESSAGE, + OK_CANCEL_OPTION, + null, //do not use a custom Icon + options, //the titles of buttons + options[0]);//default button title + pane.setBorder(new EmptyBorder(0,0,0,0)); + Component c = pane.getComponent(pane.getComponentCount()-1); + ((JComponent)c).setBorder(new EmptyBorder(0,0,10,10)); + win = pane.createDialog("VNC Authentication"); + + win.setVisible(true); + + if (pane.getValue() == null || pane.getValue().equals("Cancel")) + throw new Exception("Authentication cancelled"); + + if (user != null) + if (sendLocalUsername.getValue()) + user.append((String)System.getProperties().get("user.name")); + else + user.append(username.getText()); + if (password != null) + password.append(new String(passwd.getPassword())); + } + + public boolean showMsgBox(int flags, String title, String text) + { + switch (flags & 0xf) { + case OK_CANCEL_OPTION: + return (showConfirmDialog(null, text, title, OK_CANCEL_OPTION) == OK_OPTION); + case YES_NO_OPTION: + return (showConfirmDialog(null, text, title, YES_NO_OPTION) == YES_OPTION); + default: + if (((flags & 0xf0) == ERROR_MESSAGE) || + ((flags & 0xf0) == WARNING_MESSAGE)) + showMessageDialog(null, text, title, (flags & 0xf0)); + else + showMessageDialog(null, text, title, PLAIN_MESSAGE); + return true; + } + } +} diff --git a/java/com/tigervnc/vncviewer/VncViewer.java b/java/com/tigervnc/vncviewer/VncViewer.java index 8786c11d..74f2ca37 100644 --- a/java/com/tigervnc/vncviewer/VncViewer.java +++ b/java/com/tigervnc/vncviewer/VncViewer.java @@ -486,6 +486,9 @@ public class VncViewer extends javax.swing.JApplet public void run() { cc = null; + UserDialog dlg = new UserDialog(); + CSecurity.upg = dlg; + CSecurityTLS.msg = dlg; Socket sock = null; /* Specifying -via and -listen together is nonsense */ |