On 11/10/2010 10:24 PM, Martin Koegler wrote:
> The best thing would be to change the default value of cafile at the
> startup of the program to $HOME/.... . The current implementation only
> allows fixed values as default. I hit a similar problem while there
> was only one security type parameter for viewer and server.
> 
> My approch was "[PATCH 02/13] Allow changing the default value of
> string parameters" from 17.Jul.2010 in the tigervnc-devel mailing list archiv.
> 
> Changing the default value at program startup is in my option better, than
> interpreting a value in unexpected ways.
Ok, Adam made a commit with this patch for me today so I was able to use it.

Now, whenever the file is present and readable the default is shown
appropriately.


> 
> I don't see any issue with an message box for an authentification
> failure, which claims that the authentification has failed, because
> there is a problem with (processing) the certificate.

The thing is, that in those cases you get a dialog box for example
"hostname xxx does not match yyy do you want to continue?" and if you
press no, you get another dialog "hostname mismatch", which might be
annoying, since you've already been informed.

Nevertheless, it's not  a big deal, just UI subtilities, so I reverted
to standard auth exception which is fine for me too.

Added also the various other changes, and the UserMsgBox is implemented
slightly differently but not so differently either as in your patch
(didn't want to clutter things too much). It's re-useable the same way
of course.

Thanks!

-- 
Guillaume Destuynder - m-privacy GmbH -

Am Köllnischen Park 1, 10179 Berlin
Tel: +49 30 24342334
Fax: +49 30 24342336
Web: http://www.m-privacy.de, http://oss.m-privacy.de
Handelsregister:
 Amtsgericht Charlottenburg HRB 84946
Geschäftsführer:
 Dipl.-Kfm. Holger Maczkowsky,
 Roman Maczkowsky
GnuPG-Key-ID: 0x3FB1D217
--- /dev/null	2010-11-11 10:28:05.298999998 +0100
+++ common/rfb/UserMsgBox.h	2010-11-10 16:27:14.570999263 +0100
@@ -0,0 +1,37 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  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; 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+#ifndef __RFB_USERMSGBOX_H__
+#define __RFB_USERMSGBOX_H__
+namespace rfb {
+  class UserMsgBox {
+  public:
+    enum MsgBoxFlags{
+      M_OK = 0,
+      M_OKCANCEL = 1,
+      M_YESNO = 4,
+      M_ICONERROR = 0x10,
+      M_ICONQUESTION = 0x20,
+      M_ICONWARNING = 0x30,
+      M_ICONINFORMATION = 0x40,
+      M_DEFBUTTON1 = 0,
+      M_DEFBUTTON2 = 0x100
+    };
+    virtual bool showMsgBox(int flags,const char* title, const char* text)=0;
+  };
+}
+#endif
Index: unix/vncviewer/CConn.h
===================================================================
--- unix/vncviewer/CConn.h	(revision 4194)
+++ unix/vncviewer/CConn.h	(working copy)
@@ -26,6 +26,7 @@
 #include <rfb/CConnection.h>
 #include <rfb/Exception.h>
 #include <rfb/UserPasswdGetter.h>
+#include <rfb/UserMsgBox.h>
 #include <rdr/FdInStream.h>
 #include <list>
 
@@ -44,7 +45,7 @@
               public TXDeleteWindowCallback,
               public rdr::FdInStreamBlockCallback,
               public TXMenuCallback , public OptionsDialogCallback,
-              public TXEventHandler
+              public TXEventHandler, public rfb::UserMsgBox
 {
 public:
 
@@ -61,6 +62,9 @@
   // UserPasswdGetter methods
   virtual void getUserPasswd(char** user, char** password);
 
+  // UserMsgBox methods
+  virtual bool showMsgBox(int flags, const char* title, const char* text);
+
   // TXMenuCallback methods
   void menuSelect(long id, TXMenu* m);
 
Index: unix/vncviewer/CConn.cxx
===================================================================
--- unix/vncviewer/CConn.cxx	(revision 4194)
+++ unix/vncviewer/CConn.cxx	(working copy)
@@ -21,6 +21,9 @@
 //
 
 #include <unistd.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include "CConn.h"
 #include <rfb/CMsgWriter.h>
 #include <rfb/encodings.h>
@@ -75,7 +78,8 @@
   menuKeysym = XStringToKeysym(menuKeyStr.buf);
 
   setShared(shared);
-  CSecurity::upg = this; /* Security instance is created in CConnection costructor. */
+  CSecurity::upg = this; /* Security instance is created in CConnection constructor. */
+  CSecurityTLS::msg = this;
 
   CharArray encStr(preferredEncoding.getData());
   int encNum = encodingNum(encStr.buf);
@@ -125,6 +129,15 @@
   delete sock;
 }
 
+bool CConn::showMsgBox(int flags, const char* title, const char* text)
+{
+  CharArray titleText(strlen(title) + 12);
+  sprintf(titleText.buf, "VNC Viewer: %s", title);
+
+  TXMsgBox msgBox(dpy,text,flags,titleText.buf);
+  return msgBox.show();
+}
+
 // deleteWindow() is called when the user closes the desktop or menu windows.
 
 void CConn::deleteWindow(TXWindow* w) {
@@ -232,7 +245,6 @@
   *password = strDup(dlg.passwdEntry.getText());
 }
 
-
 // CConnection callback methods
 
 // serverInit() is called when the serverInit message has been received.  At
Index: unix/vncviewer/vncviewer.cxx
===================================================================
--- unix/vncviewer/vncviewer.cxx	(revision 4194)
+++ unix/vncviewer/vncviewer.cxx	(working copy)
@@ -33,6 +33,7 @@
 #include <locale.h>
 #include <os/os.h>
 #include <rfb/Logger_stdio.h>
+#include <rfb/CSecurityTLS.h>
 #include <rfb/LogWriter.h>
 #include <network/TcpSocket.h>
 #include "TXWindow.h"
@@ -278,6 +279,8 @@
 				 "Copyright (C) 2004-2009 Peter Astrand for Cendio AB\n"
 				 "See http://www.tigervnc.org for information on TigerVNC.");
 
+  rfb::CSecurityTLS::setDefaults();
+
   // Write about text to console, still using normal locale codeset
   snprintf(aboutText, sizeof(aboutText),
 	   gettext(englishAbout), PACKAGE_VERSION, buildtime);
Index: common/rfb/SecurityClient.cxx
===================================================================
--- common/rfb/SecurityClient.cxx	(revision 4194)
+++ common/rfb/SecurityClient.cxx	(working copy)
@@ -37,6 +37,7 @@
 using namespace rfb;
 
 UserPasswdGetter *CSecurity::upg = NULL;
+UserMsgBox *CSecurityTLS::msg = NULL;
 
 StringParameter SecurityClient::secTypes
 ("SecurityTypes",
@@ -51,6 +52,7 @@
 CSecurity* SecurityClient::GetCSecurity(U32 secType)
 {
   assert (CSecurity::upg != NULL); /* (upg == NULL) means bug in the viewer */
+  assert (CSecurityTLS::msg != NULL);
 
   if (!IsSupported(secType))
     goto bail;
Index: common/rfb/CSecurityTLS.h
===================================================================
--- common/rfb/CSecurityTLS.h	(revision 4194)
+++ common/rfb/CSecurityTLS.h	(working copy)
@@ -33,11 +33,13 @@
 #include <rfb/CSecurity.h>
 #include <rfb/SSecurityVeNCrypt.h>
 #include <rfb/Security.h>
+#include <rfb/UserMsgBox.h>
 #include <rdr/InStream.h>
 #include <rdr/OutStream.h>
 #include <gnutls/gnutls.h>
 
 namespace rfb {
+  class UserMsgBox;
   class CSecurityTLS : public CSecurity {
   public:
     CSecurityTLS(bool _anon);
@@ -46,9 +48,11 @@
     virtual int getType() const { return anon ? secTypeTLSNone : secTypeX509None; }
     virtual const char* description() const
       { return anon ? "TLS Encryption without VncAuth" : "X509 Encryption without VncAuth"; }
+    static void setDefaults();
 
     static StringParameter x509ca;
     static StringParameter x509crl;
+    static UserMsgBox *msg;
 
   protected:
     void shutdown();
Index: common/rfb/Makefile.am
===================================================================
--- common/rfb/Makefile.am	(revision 4194)
+++ common/rfb/Makefile.am	(working copy)
@@ -27,7 +27,7 @@
 	TransImageGetter.h transInitTempl.h transTempl.h TrueColourMap.h \
 	UpdateTracker.h UserPasswdGetter.h util.h VNCSConnectionST.h \
 	VNCServer.h VNCServerST.h zrleDecode.h ZRLEDecoder.h zrleEncode.h \
-	ZRLEEncoder.h
+	ZRLEEncoder.h UserMsgBox.h
 
 librfb_la_SOURCES = $(HDRS) Blacklist.cxx CConnection.cxx CMsgHandler.cxx \
 	CMsgReader.cxx CMsgReaderV3.cxx CMsgWriter.cxx CMsgWriterV3.cxx \
Index: common/rfb/CSecurityTLS.cxx
===================================================================
--- common/rfb/CSecurityTLS.cxx	(revision 4194)
+++ common/rfb/CSecurityTLS.cxx	(working copy)
@@ -2,6 +2,7 @@
  * Copyright (C) 2004 Red Hat Inc.
  * Copyright (C) 2005 Martin Koegler
  * Copyright (C) 2010 TigerVNC Team
+ * Copyright (C) 2010 m-privacy GmbH
  *    
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -27,13 +28,18 @@
 #error "This header should not be compiled without HAVE_GNUTLS defined"
 #endif
 
+#include <stdlib.h>
+#include <unistd.h>
+
 #include <rfb/CSecurityTLS.h>
 #include <rfb/SSecurityVeNCrypt.h> 
 #include <rfb/CConnection.h>
 #include <rfb/LogWriter.h>
 #include <rfb/Exception.h>
+#include <rfb/UserMsgBox.h>
 #include <rdr/TLSInStream.h>
 #include <rdr/TLSOutStream.h>
+#include <os/os.h>
 
 #include <gnutls/x509.h>
 
@@ -76,6 +82,24 @@
   crlfile = x509crl.getData();
 }
 
+void CSecurityTLS::setDefaults()
+{
+  char* homeDir = NULL;
+
+  if (strlen(x509ca.getData()) == 0) {
+    if (gethomedir(&homeDir) == -1)
+      vlog.error("Could not obtain home directory path, failed to open ~/.vnc/x509_certs");
+    else {
+      CharArray caDefault(strlen(homeDir)+17);
+      sprintf(caDefault.buf, "%s/.vnc/x509_certs", homeDir);
+      delete [] homeDir;
+
+      if (!access(caDefault.buf, R_OK))
+        x509ca.setDefaultStr(strdup(caDefault.buf));
+    }
+  }
+}
+
 void CSecurityTLS::shutdown()
 {
   if (session)
@@ -206,6 +230,7 @@
   const gnutls_datum *cert_list;
   unsigned int cert_list_size = 0;
   unsigned int i;
+  gnutls_datum_t info;
 
   if (anon)
     return;
@@ -226,25 +251,96 @@
     throw AuthFailureException("certificate verification failed");
   }
 
-  if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
-    throw AuthFailureException("certificate issuer unknown");
+  if (status & GNUTLS_CERT_REVOKED) {
+    throw AuthFailureException("certificate has been revoked");
+  }
 
-  if (status & GNUTLS_CERT_INVALID)
-    throw AuthFailureException("certificate not trusted");
+  if (status & GNUTLS_CERT_NOT_ACTIVATED) {
+    throw AuthFailureException("certificate has not been activated");
+  }
 
   for (i = 0; i < cert_list_size; i++) {
     gnutls_x509_crt crt;
     gnutls_x509_crt_init(&crt);
 
     if (gnutls_x509_crt_import(crt, &cert_list[i],GNUTLS_X509_FMT_DER) < 0)
-      throw AuthFailureException("Decoding of certificate failed");
+      throw AuthFailureException("decoding of certificate failed");
 
+    if (gnutls_x509_crt_print(crt, GNUTLS_CRT_PRINT_ONELINE, &info)) {
+        gnutls_free(info.data);
+	throw AuthFailureException("Could not find certificate to display");
+    }
+
     if (gnutls_x509_crt_check_hostname(crt, client->getServerName()) == 0) {
-#if 0
-      throw AuthFailureException("Hostname mismatch"); /* Non-fatal for now... */
-#endif
+      char buf[255];
+      sprintf(buf, "Hostname (%s) does not match any certificate, do you want to continue?", client->getServerName());
+      vlog.debug("hostname mismatch");
+      if(!msg->showMsgBox(UserMsgBox::M_YESNO, "hostname mismatch", buf))
+        throw AuthFailureException("hostname mismatch");
     }
+
+    if (status & GNUTLS_CERT_EXPIRED) {
+      vlog.debug("certificate has expired");
+      if (!msg->showMsgBox(UserMsgBox::M_YESNO, "certficate has expired", "The certificate of the server has expired, do you want to continue?"))
+        throw AuthFailureException("certificate has expired");
+    }
+
+    if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
+      size_t out_size;
+      char *homeDir = NULL;
+      char *out_buf;
+      char *certinfo;
+      int len = 0;
+
+      vlog.debug("certificate issuer unknown");
+
+      len = snprintf(NULL, 0, "This certificate has been signed by an unknown authority:\n\n%s\n\nDo you want to save it and continue?\n ", info.data);
+      if (len < 0)
+        AuthFailureException("certificate decoding error");
+
+      vlog.debug("%s", info.data);
+
+      certinfo = (char*) malloc(len);
+      snprintf(certinfo, len, "This certificate has been signed by an unknown authority:\n\n%s\n\nDo you want to save it and continue? ", info.data);
+
+      for (int i=0;i<len-1;i++)
+        if (certinfo[i] == ',' && certinfo[i+1] == ' ')
+		certinfo[i] = '\n';
+
+     if (!msg->showMsgBox(UserMsgBox::M_YESNO, "certificate issuer unknown", certinfo)) {
+        free(certinfo);
+	throw AuthFailureException("certificate issuer unknown");
+      }
+      free(certinfo);
+
+      if (gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, NULL, &out_size) == GNUTLS_E_SHORT_MEMORY_BUFFER)
+        AuthFailureException("out of memory");
+
+      //Save cert
+      out_buf = (char *) malloc(out_size);
+      if (gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, out_buf, &out_size) < 0)
+        AuthFailureException("certificate issuer unknown, and certificate export failed");
+      
+      if (gethomedir(&homeDir) == -1)
+        vlog.error("Could not obtain home directory path, failed to write to ~/.vnc/x509_certs");
+      else {
+	FILE *f;
+        CharArray caSave(strlen(homeDir)+17);
+	sprintf(caSave.buf, "%s/.vnc/x509_certs", homeDir);
+	delete [] homeDir;
+       	f = fopen(caSave.buf, "a+");
+	if (!f)
+          msg->showMsgBox(UserMsgBox::M_OK, "certificate save failed", "Could not save the certificate");
+	else {
+          fprintf(f, "%s\n", out_buf);
+	  fclose(f);
+	}
+      }
+      free(out_buf);
+    } else if (status & GNUTLS_CERT_INVALID)
+        throw AuthFailureException("certificate not trusted");
     gnutls_x509_crt_deinit(crt);
+    gnutls_free(info.data);
   }
 }
 
------------------------------------------------------------------------------
Centralized Desktop Delivery: Dell and VMware Reference Architecture
Simplifying enterprise desktop deployment and management using
Dell EqualLogic storage and VMware View: A highly scalable, end-to-end
client virtualization framework. Read more!
http://p.sf.net/sfu/dell-eql-dev2dev
_______________________________________________
Tigervnc-devel mailing list
Tigervnc-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/tigervnc-devel

Reply via email to