[pan2: 198/268] Changes to the certificate mechanisms: * load/save from/to servers.xml tag * certstore loads certs a



commit 44229f2defd6421d9241dd7e8f0be66bb9c30f4d
Author: Heinrich MÃller <sphemuel stud informatik uni-erlangen de>
Date:   Fri Nov 18 13:40:34 2011 +0100

    Changes to the certificate mechanisms:
    * load/save from/to servers.xml tag
    * certstore loads certs at startup from this file
    * user-modifiable

 pan.cbp                              |    2 +
 pan/data-impl/Makefile.am            |    6 +-
 pan/data-impl/cert-store.cc          |  234 ----------------------------------
 pan/data-impl/data-impl.cc           |    1 +
 pan/data-impl/data-impl.h            |   28 ++---
 pan/data-impl/server.cc              |   43 ++++++-
 pan/data/Makefile.am                 |   22 ++--
 pan/data/cert-store.cc               |  229 +++++++++++++++++++++++++++++++++
 pan/{data-impl => data}/cert-store.h |   23 +++-
 pan/data/data.h                      |   28 ++++-
 pan/data/encode-cache.h              |    9 +-
 pan/data/server-info.h               |    4 +
 pan/general/file-util.cc             |   10 +-
 pan/general/file-util.h              |    2 +
 pan/gui/gui.cc                       |   23 +++-
 pan/gui/gui.h                        |    4 +-
 pan/gui/pan.cc                       |    2 +-
 pan/gui/server-ui.cc                 |   20 ++-
 pan/tasks/nntp-pool.cc               |    2 +-
 pan/tasks/nntp-pool.h                |    4 +-
 pan/tasks/queue.h                    |    2 +-
 pan/tasks/socket-impl-main.cc        |    2 +-
 pan/tasks/socket-impl-main.h         |    4 +-
 pan/tasks/socket-impl-openssl.cc     |   11 +-
 pan/tasks/socket-impl-openssl.h      |    4 +-
 pan/tasks/task-groups.h              |    2 +-
 pan/tasks/task-upload.h              |    1 +
 27 files changed, 400 insertions(+), 322 deletions(-)
---
diff --git a/pan.cbp b/pan.cbp
index cd009b6..382480f 100644
--- a/pan.cbp
+++ b/pan.cbp
@@ -70,6 +70,8 @@
 		<Unit filename="pan/data/article-test.cc" />
 		<Unit filename="pan/data/article.cc" />
 		<Unit filename="pan/data/article.h" />
+		<Unit filename="pan/data/cert-store.cc" />
+		<Unit filename="pan/data/cert-store.h" />
 		<Unit filename="pan/data/data.cc" />
 		<Unit filename="pan/data/data.h" />
 		<Unit filename="pan/data/defgroup.h" />
diff --git a/pan/data-impl/Makefile.am b/pan/data-impl/Makefile.am
index 4b817b9..695c050 100644
--- a/pan/data-impl/Makefile.am
+++ b/pan/data-impl/Makefile.am
@@ -13,8 +13,7 @@ libpandata_a_SOURCES = \
  server.cc \
  my-tree.cc \
  task-archive.cc \
- xover.cc \
- cert-store.cc
+ xover.cc 
 
 noinst_HEADERS = \
  article-filter.h \
@@ -23,8 +22,7 @@ noinst_HEADERS = \
  data-io.h \
  defgroup.h \
  profiles.h \
- memchunk.h \
- cert-store.h
+ memchunk.h 
 
 noinst_PROGRAMS = \
  add-server \
diff --git a/pan/data-impl/data-impl.cc b/pan/data-impl/data-impl.cc
index 13b353f..531da3a 100644
--- a/pan/data-impl/data-impl.cc
+++ b/pan/data-impl/data-impl.cc
@@ -65,6 +65,7 @@ DataImpl :: DataImpl (bool unit_test, int cache_megs, DataIO * io):
   ProfilesImpl (*io),
   _cache (get_cache_path(), cache_megs),
   _encode_cache (get_encode_cache_path(), cache_megs),
+  _certstore(*this),
   _unit_test (unit_test),
   _data_io (io),
   _descriptions_loaded (false),
diff --git a/pan/data-impl/data-impl.h b/pan/data-impl/data-impl.h
index 012e890..fc96789 100644
--- a/pan/data-impl/data-impl.h
+++ b/pan/data-impl/data-impl.h
@@ -45,7 +45,7 @@
 #include <pan/data-impl/memchunk.h>
 
 #ifdef HAVE_OPENSSL
-  #include <pan/data-impl/cert-store.h>
+  #include <pan/data/cert-store.h>
   #include <openssl/crypto.h>
   #include <openssl/x509.h>
   #include <openssl/x509v3.h>
@@ -111,29 +111,15 @@ namespace pan
 
       void save_server_properties (DataIO&) const;
 
-      struct Server
-      {
-         std::string username;
-         std::string password;
-         std::string host;
-         std::string newsrc_filename;
-         int port;
-         int article_expiration_age;
-         int max_connections;
-         int rank;
-         int ssl_support;
-         typedef sorted_vector<Quark,true,AlphabeticalQuarkOrdering> groups_t;
-         groups_t groups;
-
-         Server(): port(119), article_expiration_age(31), max_connections(2), rank(1), ssl_support(0) {}
-      };
-
       typedef Loki::AssocVector<Quark,Server> servers_t;
 
       servers_t _servers;
 
       Server* find_server (const Quark& server);
-      const Server* find_server (const Quark& server) const;
+
+    public:
+      virtual const Server* find_server (const Quark& server) const;
+      virtual bool find_server_by_hn (const Quark& server, Quark& setme) const;
 
     public: // mutators
 
@@ -157,6 +143,8 @@ namespace pan
 
       virtual void set_server_ssl_support (const Quark& server, int ssl);
 
+      virtual void set_server_cert (const Quark & server, const StringView & cert);
+
       virtual void set_server_article_expiration_age  (const Quark  & server,
                                                        int            days);
 
@@ -183,6 +171,8 @@ namespace pan
 
       virtual bool get_server_ssl_support (const Quark & server) const;
 
+      virtual std::string get_server_cert (const Quark & server) const;
+
       virtual int get_server_rank (const Quark& server) const;
 
       virtual int get_server_limits (const Quark & server) const;
diff --git a/pan/data-impl/server.cc b/pan/data-impl/server.cc
index f28baa7..10af926 100644
--- a/pan/data-impl/server.cc
+++ b/pan/data-impl/server.cc
@@ -78,26 +78,36 @@ DataImpl :: add_new_server ()
   return new_server;
 }
 
-DataImpl :: Server*
+Data :: Server*
 DataImpl :: find_server (const Quark& server)
 {
   Server * retval (0);
+
   servers_t::iterator it (_servers.find (server));
   if (it != _servers.end())
     retval = &it->second;
   return retval;
 }
 
-const DataImpl :: Server*
+const Data :: Server*
 DataImpl :: find_server (const Quark& server) const
 {
   const Server * retval (0);
+
   servers_t::const_iterator it (_servers.find (server));
   if (it != _servers.end())
     retval = &it->second;
   return retval;
 }
 
+bool
+DataImpl :: find_server_by_hn (const Quark& server, Quark& setme) const
+{
+  foreach_const(servers_t, _servers, it)
+    if (it->second.host == server.c_str()) { setme = it->first; return true; }
+  return false;
+}
+
 void
 DataImpl :: set_server_article_expiration_age  (const Quark  & server,
                                                 int            days)
@@ -168,6 +178,16 @@ DataImpl :: set_server_ssl_support (const Quark   & server,
 }
 
 void
+DataImpl :: set_server_cert  (const Quark   & server,
+                              const StringView & cert)
+{
+  Server * s (find_server (server));
+  assert (s != 0);
+  s->cert = cert;
+
+}
+
+void
 DataImpl :: save_server_info (const Quark& server)
 {
   Server * s (find_server (server));
@@ -226,6 +246,17 @@ DataImpl :: get_server_ssl_support (const Quark & server) const
   return retval;
 }
 
+std::string
+DataImpl :: get_server_cert (const Quark & server) const
+{
+  std::string str;
+  const Server * s (find_server (server));
+  if (s) {
+    str = s->cert;
+  }
+  return str;
+}
+
 int
 DataImpl :: get_server_limits (const Quark & server) const
 {
@@ -350,7 +381,9 @@ DataImpl :: load_server_properties (const DataIO& source)
     s.max_connections = to_int (kv["connection-limit"], 2);
     s.article_expiration_age = to_int(kv["expire-articles-n-days-old"], 31);
     s.rank = to_int(kv["rank"], 1);
-    s.ssl_support = to_int(kv["use-ssl"], 0);
+    int ssl(to_int(kv["use-ssl"], 0));
+    s.ssl_support = ssl;
+    if (ssl == 1) s.cert = kv["cert"];
     s.newsrc_filename = kv["newsrc"];
     if (s.newsrc_filename.empty()) { // set a default filename
       std::ostringstream o;
@@ -359,7 +392,6 @@ DataImpl :: load_server_properties (const DataIO& source)
     }
   }
 
-//  save_server_properties (*const_cast<DataIO*>(&source));
 }
 
 namespace
@@ -404,7 +436,8 @@ DataImpl :: save_server_properties (DataIO& data_io) const
          << indent(depth) << "<connection-limit>" << s->max_connections << "</connection-limit>\n"
          << indent(depth) << "<newsrc>" << s->newsrc_filename << "</newsrc>\n"
          << indent(depth) << "<rank>" << s->rank << "</rank>\n"
-         << indent(depth) << "<use-ssl>" << s->ssl_support << "</use-ssl>\n";
+         << indent(depth) << "<use-ssl>" << s->ssl_support << "</use-ssl>\n"
+         << indent(depth) << "<cert>"    << s->cert << "</cert>\n";
 
     *out << indent(--depth) << "</server>\n";
   }
diff --git a/pan/data/Makefile.am b/pan/data/Makefile.am
index b979ea9..3e4e34b 100644
--- a/pan/data/Makefile.am
+++ b/pan/data/Makefile.am
@@ -1,7 +1,7 @@
 AM_CPPFLAGS = -I top_srcdir@ @GMIME_CFLAGS@ @GLIB_CFLAGS@ @GTK_CFLAGS@
 LDADD = @GTK_LIBS@
 
-SUBDIRS = decode-test-cache
+#SUBDIRS = decode-test-cache
 
 noinst_LIBRARIES = libdata.a
 
@@ -9,6 +9,7 @@ libdata_a_SOURCES = \
  article.cc \
  article-cache.cc \
  encode-cache.cc \
+ cert-store.cc \
  data.cc \
  parts.cc \
  xref.cc
@@ -17,23 +18,24 @@ noinst_HEADERS = \
  article.h \
  article-cache.h \
  encode-cache.h \
+ cert-store.h \
  data.h \
  defgroup.h \
  parts.h \
  server-info.h \
  xref.h
 
-noinst_PROGRAMS = \
- article-test \
- xref-test
+#noinst_PROGRAMS = \
+# article-test \
+# xref-test
 
 #dnl decode-test
 #dnl decode_test_SOURCES = decode-test.cc
 #dnl decode_test_LDADD = $(TEST_LDADD)
 
-TESTS = $(noinst_PROGRAMS)
-TEST_LDADD = ./libdata.a ../usenet-utils/libusenetutils.a ../general/libgeneralutils.a @GMIME_LIBS@ @GLIB_LIBS@
-xref_test_SOURCES = xref-test.cc
-xref_test_LDADD = $(TEST_LDADD)
-article_test_SOURCES = article-test.cc
-article_test_LDADD = $(TEST_LDADD)
+#TESTS = $(noinst_PROGRAMS)
+#TEST_LDADD = ./libdata.a ../usenet-utils/libusenetutils.a ../general/libgeneralutils.a @GMIME_LIBS@ @GLIB_LIBS@
+#xref_test_SOURCES = xref-test.cc
+#xref_test_LDADD = $(TEST_LDADD)
+#article_test_SOURCES = article-test.cc
+#article_test_LDADD = $(TEST_LDADD)
diff --git a/pan/data/cert-store.cc b/pan/data/cert-store.cc
new file mode 100644
index 0000000..60715fe
--- /dev/null
+++ b/pan/data/cert-store.cc
@@ -0,0 +1,229 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Pan - A Newsreader for Gtk+
+ * Copyright (C) 2002-2006  Charles Kerr <charles rebelbase com>
+ *
+ * This program 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 program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <string>
+#include <glib/giochannel.h>
+#include <glib/gstring.h>
+#include <pan/tasks/socket.h>
+#include <config.h>
+#include <map>
+#include <string>
+#include <sstream>
+#include <fstream>
+#include <iostream>
+#include <string>
+
+extern "C" {
+  #include <glib/gi18n.h>
+}
+
+#include <pan/general/debug.h>
+#include <pan/general/e-util.h>
+#include <pan/general/macros.h>
+#include <pan/usenet-utils/ssl-utils.h>
+#include <pan/general/file-util.h>
+#include <pan/general/messages.h>
+#include <pan/general/log.h>
+#include <pan/general/string-view.h>
+#include <pan/usenet-utils/mime-utils.h>
+
+#include "cert-store.h"
+
+using namespace pan;
+
+#ifdef HAVE_OPENSSL
+namespace pan
+{
+
+  int
+  verify_callback(int ok, X509_STORE_CTX *store)
+  {
+
+    SSL * ssl = (SSL*)X509_STORE_CTX_get_ex_data(store, SSL_get_ex_data_X509_STORE_CTX_idx());
+    mydata_t* mydata = (mydata_t*)SSL_get_ex_data(ssl, SSL_get_fd(ssl));
+
+    if (!ok)
+    {
+      if (mydata->ignore_all==1) { return 1; }
+
+      X509 *cert = X509_STORE_CTX_get_current_cert(store);
+      int depth = X509_STORE_CTX_get_error_depth(store);
+      int err = X509_STORE_CTX_get_error(store);
+
+      /* accept user-override on self-signed certificates */
+      if (err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN ||
+          err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
+          err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
+          err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)
+        mydata->cs->verify_failed(cert, mydata->server, mydata->cert_name, err);
+      else
+        g_warning("[[DEBUG:]] unknown error condition, please report me: %s", ssl_err_to_string(err).c_str());
+    }
+
+    return ok;
+  }
+
+  int
+  CertStore :: get_all_certs_from_disk(std::set<X509*>& setme)
+  {
+
+    int cnt(0);
+    quarks_t servers(_data.get_servers());
+    foreach_const(quarks_t, servers, it)
+    {
+      const Data::Server* s(_data.find_server(*it));
+      if (!s) continue;
+      const char* filename(s->cert.c_str());
+      if (!filename) continue;
+      FILE *fp = fopen(filename,"r");
+      if (!fp) continue;
+      X509 *x = X509_new();
+      if (!x) { fclose(fp); continue; }
+      PEM_read_X509(fp,&x, 0, 0);
+      fclose(fp);
+      setme.insert(x);
+      _certs.insert(s->host);
+      _cert_to_server[s->host] = x;
+      ++cnt;
+    }
+
+    return cnt;
+  }
+
+  void
+  CertStore :: init_me()
+  {
+    assert (_ctx);
+
+    _store = SSL_CTX_get_cert_store(_ctx);
+
+    std::set<X509*> certs;
+    int r(0);
+    get_all_certs_from_disk (certs);
+    foreach_const (std::set<X509*>, certs, it)
+      if (X509_STORE_add_cert(_store, *it) != 0) ++r;
+    if (r != 0) Log::add_info_va(_("Succesfully added %d SSL PEM certificate(s) to Certificate Store."), r);
+    SSL_CTX_set_verify(_ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback);
+
+  }
+
+  void
+  CertStore :: remove_hard(const Quark& server)
+  {
+    char buf[2048];
+    g_snprintf (buf, sizeof(buf), "%s%c%s.pem", _path.c_str(), G_DIR_SEPARATOR, server.c_str());
+    unlink(buf);
+  }
+
+  void
+  CertStore :: remove (const Quark& server)
+  {
+    if (_cert_to_server.count(server) > 0)
+    {
+      _cert_to_server.erase(server);
+      _certs.erase(server);
+      remove_hard(server);
+//      SSL_CTX_set_cert_store(_ctx, X509_STORE_new());
+      Quark setme;
+      _data.find_server_by_hn(server, setme);
+      _data.set_server_cert(setme, "");
+      _data.save_server_info(setme);
+      init_me();
+    }
+
+  }
+
+  CertStore :: CertStore (Data& data): _data(data)
+  {
+    char buf[2048];
+    g_snprintf(buf,sizeof(buf),"%s%cssl_certs",file::get_pan_home().c_str(), G_DIR_SEPARATOR);
+    _path = buf;
+    if (!file::ensure_dir_exists (buf))
+    {
+      std::cerr<<"Error initializing certstore. Check your permissions for the directory \"ssl-certs\" and main subfolder in your home directory! Fatal, exiting.";
+      file::print_file_info(std::cerr, buf);
+      exit(EXIT_FAILURE);
+    }
+  }
+
+  CertStore :: ~CertStore ()
+  {}
+
+
+
+  bool
+  CertStore :: add(X509* cert, const Quark& server)
+  {
+    if (!cert || server.empty()) return false;
+    X509_STORE_add_cert(get_store(),cert);
+
+    std::string addr; int port;
+    _data.get_server_addr(server, addr, port);
+    _certs.insert(addr);
+    _cert_to_server[addr] = cert;
+
+    const char* buf(build_cert_name(addr.c_str()).c_str());
+
+    _data.set_server_cert(server, buf);
+    _data.save_server_info(server);
+
+    FILE * fp = fopen(buf, "wb");
+    if (!fp) return false;
+    if (PEM_write_X509(fp, cert) != 1) { fclose(fp); return false; }
+    fclose(fp);
+    chmod (buf, 0600);
+
+    valid_cert_added(cert, server.c_str());
+    return true;
+  }
+
+
+  X509*
+  CertStore :: get_cert_to_server(const Quark& server) const
+  {
+    X509* ret(0);
+    Quark serv;
+
+    /* strip port from server if existing */
+    std::string s(server);
+    std::string::size_type idx = s.rfind(":");
+    if(idx != std::string::npos)
+      serv = s.substr(0,idx);
+    else
+      serv = server;
+
+    if (_cert_to_server.count(serv) > 0)
+      ret = _cert_to_server.find(serv)->second;
+    return ret;
+  }
+
+  std::string
+  CertStore :: build_cert_name(std::string host)
+  {
+    char buf[2048];
+    g_snprintf(buf,sizeof(buf),"%s%cssl_certs%c%s.pem",file::get_pan_home().c_str(),
+               G_DIR_SEPARATOR,G_DIR_SEPARATOR, host.c_str());
+    return buf;
+  }
+
+
+}  // namespace pan
+
+
+#endif
diff --git a/pan/data-impl/cert-store.h b/pan/data/cert-store.h
similarity index 88%
rename from pan/data-impl/cert-store.h
rename to pan/data/cert-store.h
index 311c16a..7fe1a80 100644
--- a/pan/data-impl/cert-store.h
+++ b/pan/data/cert-store.h
@@ -28,6 +28,9 @@
   #include <openssl/rand.h>
   #include <openssl/x509.h>
 #endif
+
+#include <pan/data/data.h>
+
 #include <pan/tasks/socket.h>
 #include <pan/general/quark.h>
 #include <pan/general/macros.h>
@@ -39,11 +42,13 @@
 
 namespace pan
 {
+  class Data;
+
   class CertStore
   {
 #ifdef HAVE_OPENSSL
     public:
-      CertStore () ;
+      CertStore (Data& data) ;
       virtual ~CertStore () ;
 
     private:
@@ -57,12 +62,13 @@ namespace pan
       std::string _path;
       std::vector<SSL_SESSION*> _sessions;
       certs_t _blacklist;
+      Data& _data;
 
     public:
       SSL_CTX* get_ctx() { return _ctx; }
       X509_STORE* get_store() const { return _store; }
       int get_all_certs_from_disk(std::set<X509*>& setme);
-      const X509* get_cert_to_server(const Quark& server) const;
+      X509* get_cert_to_server(const Quark& server) const;
       SSL_SESSION* get_session()
       {
         SSL_SESSION* ret(0);
@@ -103,15 +109,18 @@ namespace pan
       void remove_hard(const Quark&);
 
     public:
+
       bool add(X509*, const Quark&) ;
       void remove (const Quark&);
       bool exist (const Quark& q) { return (_certs.count(q) > 0); }
 
+      static std::string build_cert_name(std::string host);
+
       struct Listener
       {
         virtual ~Listener() {}
         /* functions that other listeners listen on */
-        virtual void on_verify_cert_failed (X509* cert UNUSED, std::string server UNUSED, int nr UNUSED) = 0;
+        virtual void on_verify_cert_failed (X509* cert UNUSED, std::string server UNUSED, std::string cert_name UNUSED, int nr UNUSED) = 0;
         virtual void on_valid_cert_added (X509* cert UNUSED, std::string server UNUSED) = 0;
       };
 
@@ -122,10 +131,11 @@ namespace pan
       void remove_listener (Listener * l) { _listeners.erase(l);  }
 
       /* notify functions for listener list */
-      void verify_failed (X509* c, std::string server, int nr)
+      void verify_failed (X509* c, std::string server, std::string cn, int nr)
       {
+        std::cerr<<"verify failed "<<server<<" "<<cn<<"\n";
         for (listeners_t::iterator it(_listeners.begin()), end(_listeners.end()); it!=end; ++it)
-          (*it)->on_verify_cert_failed (c, server, nr);
+          (*it)->on_verify_cert_failed (c, server, cn, nr);
       }
 
       void valid_cert_added (X509* c, std::string server)
@@ -148,12 +158,13 @@ namespace pan
    int ignore_all;
    CertStore* cs;
    std::string server;
+   std::string cert_name;
    CertStore::Listener* l;
 
 #else
 
   public:
-    CertStore () {};
+    CertStore (Data&) {};
     virtual ~CertStore () {};
 
     void add_listener (void * l) {}
diff --git a/pan/data/data.h b/pan/data/data.h
index eb75cbd..fda34ed 100644
--- a/pan/data/data.h
+++ b/pan/data/data.h
@@ -32,14 +32,15 @@
 #include <pan/data/article.h>
 #include <pan/data/article-cache.h>
 #include <pan/data/encode-cache.h>
+#include <pan/data/cert-store.h>
 #include <pan/data/server-info.h>
-#include <pan/data-impl/cert-store.h>
 
 namespace pan
 {
   class FilterInfo;
   class RulesInfo;
   class Queue;
+  class CertStore;
 
   /**
    * Data Interface class for seeing the mapping between groups and servers.
@@ -162,6 +163,26 @@ namespace pan
     public virtual Profiles,
     public virtual ArticleReferences
   {
+
+    public:
+      struct Server
+      {
+         std::string username;
+         std::string password;
+         std::string host;
+         std::string newsrc_filename;
+         std::string cert;
+         int port;
+         int article_expiration_age;
+         int max_connections;
+         int rank;
+         int ssl_support;
+         typedef sorted_vector<Quark,true,AlphabeticalQuarkOrdering> groups_t;
+         groups_t groups;
+
+         Server(): port(119), article_expiration_age(31), max_connections(2), rank(1), ssl_support(0) {}
+      };
+
     protected:
 
       Data () {}
@@ -184,6 +205,11 @@ namespace pan
 
     public:
 
+      /** Gets a quark to the provided hostname */
+      virtual bool find_server_by_hn (const Quark& server, Quark& setme) const = 0;
+
+      virtual const Server* find_server (const Quark& server) const = 0;
+
       virtual quarks_t get_servers () const = 0;
 
       virtual void delete_server (const Quark& server) = 0;
diff --git a/pan/data/encode-cache.h b/pan/data/encode-cache.h
index 34091ef..b805825 100644
--- a/pan/data/encode-cache.h
+++ b/pan/data/encode-cache.h
@@ -34,14 +34,11 @@ namespace pan
   class StringView;
 
   /**
-   * A disk cache for binary attachments.
+   * A disk cache for binary attachments to be yenc-encoded
    *
-   * This allows a cache to be set to a certain maximum size, where
-   * the oldest articles will be aged out when the cache is full.
-   *
-   * It also has a lock/unlock mechanism to allow the cache to grow
+   * It has a lock/unlock mechanism to allow the cache to grow
    * past its limit briefly to allow large multipart articles' pieces
-   * to all be held at once (for decoding).
+   * to all be held at once (for encoding).
    *
    * FIXME: This should probably be an interface class implemented in
    * data-impl in the same way profiles was.
diff --git a/pan/data/server-info.h b/pan/data/server-info.h
index 9d20785..cdcf73e 100644
--- a/pan/data/server-info.h
+++ b/pan/data/server-info.h
@@ -64,6 +64,8 @@ namespace pan
       virtual void set_server_ssl_support (const Quark& server,
                                     int          ssl) = 0;
 
+      virtual void set_server_cert (const Quark & server, const StringView & cert) = 0;
+
       virtual void save_server_info (const Quark& server) = 0;
 
     public: // accessors
@@ -81,6 +83,8 @@ namespace pan
 
       virtual bool get_server_ssl_support (const Quark & server) const = 0;
 
+      virtual std::string get_server_cert (const Quark & server) const = 0;
+
       /** If set_server_limits() has never been called, 2 is returned. */
       virtual int get_server_limits (const Quark & server) const = 0;
 
diff --git a/pan/general/file-util.cc b/pan/general/file-util.cc
index 8b97daa..f4ec2bc 100644
--- a/pan/general/file-util.cc
+++ b/pan/general/file-util.cc
@@ -145,7 +145,8 @@ file :: ensure_dir_exists (const StringView& dirname_sv)
     if (cmd == EX_BIT)
       if (chmod(dirname.c_str(), 0740))
       {
-        Log::add_urgent_va("Error setting executable bit for directory '%s' : Please check your permissions.", dirname.c_str());
+        Log::add_urgent_va("Error setting executable bit for directory '%s' : "
+                           "Please check your permissions.", dirname.c_str());
         print_file_info(std::cerr,dirname.c_str());
       }
   }
@@ -158,12 +159,7 @@ file :: file_exists (const char * filename)
    return filename && *filename && g_file_test (filename, G_FILE_TEST_EXISTS);
 }
 
-/**
-*** Attempt to make a filename safe for use.
-*** This is done by replacing illegal characters with '_'.
-*** This function assumes the input is UTF8 since gmime uses UTF8 interface.
-*** return value must be g_free'd.
-**/
+
 std::string
 file :: sanitize (const StringView& fname)
 {
diff --git a/pan/general/file-util.h b/pan/general/file-util.h
index 4f49d1b..1ef563a 100644
--- a/pan/general/file-util.h
+++ b/pan/general/file-util.h
@@ -79,6 +79,8 @@ namespace pan
      * <ol>
      * <li>Replacing illegal characters with '_'.
      * <li>Ensure the resulting string is UTF8-safe
+     * <li>This function assumes the input is UTF8 since gmime uses UTF8 interface.
+     * <li>Return value must be g_free'd.
      * </ol>
      */
     std::string sanitize (const StringView& filename);
diff --git a/pan/gui/gui.cc b/pan/gui/gui.cc
index 8597758..fede36f 100644
--- a/pan/gui/gui.cc
+++ b/pan/gui/gui.cc
@@ -2096,20 +2096,33 @@ GUI :: on_prefs_string_changed (const StringView& key, const StringView& value)
 
 #ifdef HAVE_OPENSSL
 void
-GUI :: on_verify_cert_failed(X509* cert, std::string server, int nr)
+GUI :: on_verify_cert_failed(X509* cert, std::string server, std::string cert_name, int nr)
 {
-  if (!cert) return;
+  std::cerr<<"on verify failed gui ("<<server<<") ("<<cert_name<<")\n";
+  if (!cert || cert_name.empty() || server.empty()) return;
+
+  Quark setme;
+  bool found(_data.find_server_by_hn(server, setme));
+
   if (GUI::confirm_accept_new_cert_dialog(get_window(_root),cert,server))
-    if (!_certstore.add(cert, server))
+    if (!_certstore.add(cert, setme))
       Log::add_urgent_va("Error adding certificate of server '%s' to Certificate Store",server.c_str());
+    else
+    {
+      std::cerr<<"added cert "<<cert<<" to server "<<server<<std::endl;
 
+      if (found)
+      {
+        std::cerr<<"on verify failed gui ("<<server<<") ("<<cert_name<<")\n";
+        _data.set_server_cert(setme, cert_name);
+        _data.save_server_info(setme);
+      }
+    }
 }
 
 void
 GUI :: on_valid_cert_added (X509* cert, std::string server)
 {
-  std::cerr<<"whitelist "<<server<<std::endl;
-
   /* whitelist to make avaible for nntp-pool */
   _certstore.whitelist(server);
 
diff --git a/pan/gui/gui.h b/pan/gui/gui.h
index 7617890..3dec2fd 100644
--- a/pan/gui/gui.h
+++ b/pan/gui/gui.h
@@ -25,7 +25,7 @@
 #include <pan/data/article-cache.h>
 #include <pan/data/encode-cache.h>
 #include <pan/tasks/queue.h>
-#include <pan/data-impl/cert-store.h>
+#include <pan/data/cert-store.h>
 #include <pan/gui/action-manager.h>
 #include <pan/gui/pan-ui.h>
 #include <pan/gui/prefs.h>
@@ -183,7 +183,7 @@ namespace pan
       virtual void on_queue_error (Queue&, const StringView& message);
 #ifdef HAVE_OPENSSL
     private:  // CertStore::Listener
-      virtual void on_verify_cert_failed(X509*, std::string, int);
+      virtual void on_verify_cert_failed(X509*, std::string, std::string, int);
       virtual void on_valid_cert_added (X509*, std::string);
 #endif
     private: // Log::Listener
diff --git a/pan/gui/pan.cc b/pan/gui/pan.cc
index 679e387..3d3f5c8 100644
--- a/pan/gui/pan.cc
+++ b/pan/gui/pan.cc
@@ -42,7 +42,7 @@ extern "C" {
   #include <pan/tasks/socket-impl-openssl.h>
 #endif
 
-#include <pan/data-impl/cert-store.h>
+#include <pan/data/cert-store.h>
 #include <pan/tasks/socket-impl-gio.h>
 #include <pan/tasks/socket-impl-main.h>
 #include <pan/tasks/task-groups.h>
diff --git a/pan/gui/server-ui.cc b/pan/gui/server-ui.cc
index 4403fad..48e81d9 100644
--- a/pan/gui/server-ui.cc
+++ b/pan/gui/server-ui.cc
@@ -40,7 +40,7 @@ extern "C" {
 
 #ifdef HAVE_OPENSSL
 
-  #include <pan/data-impl/cert-store.h>
+  #include <pan/data/cert-store.h>
   #include <openssl/crypto.h>
   #include <openssl/x509.h>
   #include <openssl/x509v3.h>
@@ -62,6 +62,7 @@ namespace
     Data& data;
     Queue& queue;
     Quark server;
+    StringView cert;
     GtkWidget * dialog;
     GtkWidget * address_entry;
     GtkWidget * port_spin;
@@ -108,7 +109,7 @@ namespace
     d->server = server;
 
     int port(119), max_conn(4), age(31*3), rank(1), ssl(0);
-    std::string addr, user, pass;
+    std::string addr, user, pass, cert;
     if (!server.empty()) {
       d->data.get_server_addr (server, addr, port);
       d->data.get_server_auth (server, user, pass);
@@ -116,6 +117,7 @@ namespace
       rank = d->data.get_server_rank (server);
       max_conn = d->data.get_server_limits (server);
       ssl = d->data.get_server_ssl_support(server);
+      cert = d->data.get_server_cert(server);
     }
 
     pan_entry_set_text (d->address_entry, addr);
@@ -192,6 +194,7 @@ namespace
       if (gtk_combo_box_get_active_iter (combo, &iter))
         gtk_tree_model_get (gtk_combo_box_get_model(combo), &iter, 1, &rank, -1);
       int ssl(0);
+      StringView cert(d->cert);
 #ifdef HAVE_OPENSSL
       combo = GTK_COMBO_BOX (d->ssl_combo);
       if (gtk_combo_box_get_active_iter (combo, &iter))
@@ -220,6 +223,7 @@ namespace
         d->data.set_server_article_expiration_age (d->server, age);
         d->data.set_server_rank (d->server, rank);
         d->data.set_server_ssl_support(d->server, ssl);
+        d->data.set_server_cert(d->server,cert);
         d->data.save_server_info(d->server);
         d->queue.upkeep ();
       }
@@ -371,6 +375,7 @@ pan :: server_edit_dialog_new (Data& data, Queue& queue, GtkWindow * window, con
 
     // ssl 3.0 option
 #ifdef HAVE_OPENSSL
+    // select ssl/plaintext
     HIG::workarea_add_section_divider (t, &row);
     HIG::workarea_add_section_title (t, &row, _("Security"));
     HIG::workarea_add_section_spacer (t, row, 2);
@@ -656,7 +661,7 @@ namespace
     char buf[4096] ;
 
     if (!selected_server.empty()) {
-      X509* cert = (X509*)store.get_cert_to_server(addr);
+      X509* cert (store.get_cert_to_server(addr));
       if (cert)
       {
         pretty_print_x509(buf,sizeof(buf),addr, cert,false);
@@ -666,9 +671,8 @@ namespace
         GTK_DIALOG_MODAL,
         GTK_MESSAGE_INFO,
         GTK_BUTTONS_CLOSE, buf);
-//        g_snprintf(buf,sizeof(buf), _("Server Certificate for <b>'%s'</b>"), addr.c_str());
-//        gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG(w), "%s", buf);
-//        gtk_window_set_title(GTK_WINDOW(w), buf);
+        g_snprintf(buf,sizeof(buf), _("Server Certificate for <b>'%s'</b>"), addr.c_str());
+        gtk_window_set_title(GTK_WINDOW(w), buf);
         gtk_widget_show_all (w);
         g_signal_connect_swapped (w, "response", G_CALLBACK (gtk_widget_destroy), w);
       }
@@ -721,7 +725,7 @@ namespace
   }
 
 
-  /* add a cert from disk, overwriting the current certificate for the selected server */
+  /* add a cert from disk, overwriting the current setting for the selected server */
   void
   cert_add_button_clicked_cb (GtkButton *, gpointer user_data)
   {
@@ -743,7 +747,7 @@ namespace
       PEM_read_X509(fp,&x, 0, 0);
       fclose(fp);
       d->data.get_server_addr(selected_server, addr, port);
-      if (!store.add(x,addr))
+      if (!store.add(x,selected_server))
       {
       _err:
         Log::add_err_va("Error adding certificate of server '%s' to CertStore. Check the console output!", addr.c_str());
diff --git a/pan/tasks/nntp-pool.cc b/pan/tasks/nntp-pool.cc
index 9cdfc22..ff0abde 100644
--- a/pan/tasks/nntp-pool.cc
+++ b/pan/tasks/nntp-pool.cc
@@ -350,7 +350,7 @@ NNTP_Pool :: idle_upkeep ()
 
 #ifdef HAVE_OPENSSL
 void
-NNTP_Pool:: on_verify_cert_failed(X509* cert, std::string server, int nr)
+NNTP_Pool:: on_verify_cert_failed(X509* cert, std::string server, std::string cert_name, int nr)
 {
 //  abort_tasks();
 }
diff --git a/pan/tasks/nntp-pool.h b/pan/tasks/nntp-pool.h
index 0a256b1..f173863 100644
--- a/pan/tasks/nntp-pool.h
+++ b/pan/tasks/nntp-pool.h
@@ -29,7 +29,7 @@
 #include <pan/tasks/socket-impl-main.h>
 
 #ifdef HAVE_OPENSSL
-  #include <pan/data-impl/cert-store.h>
+  #include <pan/data/cert-store.h>
 #endif
 
 namespace pan
@@ -89,7 +89,7 @@ namespace pan
 #ifdef HAVE_OPENSSL
     private:
       // CertStore::Listener
-      virtual void on_verify_cert_failed (X509*, std::string, int) ;
+      virtual void on_verify_cert_failed (X509*, std::string, std::string, int) ;
       virtual void on_valid_cert_added (X509*, std::string );
 #endif
     private:
diff --git a/pan/tasks/queue.h b/pan/tasks/queue.h
index 0aba713..75fcbc1 100644
--- a/pan/tasks/queue.h
+++ b/pan/tasks/queue.h
@@ -37,7 +37,7 @@
 #include <pan/tasks/socket-impl-main.h>
 
 #ifdef HAVE_OPENSSL
-  #include <pan/data-impl/cert-store.h>
+  #include <pan/data/cert-store.h>
 #endif
 
 namespace pan
diff --git a/pan/tasks/socket-impl-main.cc b/pan/tasks/socket-impl-main.cc
index b41ea99..2889bc7 100644
--- a/pan/tasks/socket-impl-main.cc
+++ b/pan/tasks/socket-impl-main.cc
@@ -175,7 +175,7 @@ SocketCreator :: create_socket (const StringView & host,
 
 #ifdef HAVE_OPENSSL
 void
-SocketCreator :: on_verify_cert_failed(X509* cert, std::string server, int nr)
+SocketCreator :: on_verify_cert_failed(X509* cert, std::string server, std::string cert_name, int nr)
 {
 //    delete_all_socks(socket_map, server);
 }
diff --git a/pan/tasks/socket-impl-main.h b/pan/tasks/socket-impl-main.h
index 16cd43c..a8ff82b 100644
--- a/pan/tasks/socket-impl-main.h
+++ b/pan/tasks/socket-impl-main.h
@@ -42,7 +42,7 @@
   #include "socket-impl-openssl.h"
 #endif
 
-#include <pan/data-impl/cert-store.h>
+#include <pan/data/cert-store.h>
 #include "socket-impl-gio.h"
 
 namespace
@@ -140,7 +140,7 @@ namespace pan
       std::multimap<std::string, Socket*> socket_map;
 
       // CertStore::Listener
-      virtual void on_verify_cert_failed(X509*, std::string, int);
+      virtual void on_verify_cert_failed(X509*, std::string, std::string, int);
       virtual void on_valid_cert_added (X509*, std::string );
 #endif
       CertStore & store;
diff --git a/pan/tasks/socket-impl-openssl.cc b/pan/tasks/socket-impl-openssl.cc
index 9dccaaf..d550c99 100644
--- a/pan/tasks/socket-impl-openssl.cc
+++ b/pan/tasks/socket-impl-openssl.cc
@@ -95,7 +95,7 @@ extern "C" {
 #include <pan/usenet-utils/gnksa.h>
 #include "socket-impl-openssl.h"
 #include "socket-impl-main.h"
-#include <pan/data-impl/cert-store.h>
+#include <pan/data/cert-store.h>
 
 using namespace pan;
 
@@ -372,7 +372,8 @@ namespace
   }
 
 
-  int ssl_handshake(GIOChannel *handle, CertStore::Listener* listener, CertStore* cs, std::string host, SSL_SESSION* session, bool rehandshake)
+  int ssl_handshake(GIOChannel *handle, CertStore::Listener* listener,
+                    CertStore* cs, std::string host, SSL_SESSION* session, bool rehandshake)
   {
 
     GIOSSLChannel *chan = (GIOSSLChannel *)handle;
@@ -382,11 +383,13 @@ namespace
     const char *errstr;
 
     /* init custom data for callback */
-    mydata_t mydata;// = new mydata_t();
+    mydata_t mydata;
     mydata.ctx = chan->ctx;
     mydata.cs = cs;
     mydata.ignore_all = 0;
     mydata.l = listener;
+    /* build cert name from scratch or from Server* */
+    mydata.cert_name = CertStore::build_cert_name(host);
     mydata.server = host;
     SSL_set_ex_data(chan->ssl, SSL_get_fd(chan->ssl), &mydata);
 
@@ -808,7 +811,7 @@ GIOChannelSocketSSL :: ssl_get_iochannel(GIOChannel *handle, gboolean verify)
 }
 
 void
-GIOChannelSocketSSL :: on_verify_cert_failed (X509* cert, std::string server, int nr)
+GIOChannelSocketSSL :: on_verify_cert_failed (X509* cert, std::string server, std::string cert_name, int nr)
 {
   if (!_certstore.in_blacklist(server)) _certstore.blacklist(server);
 }
diff --git a/pan/tasks/socket-impl-openssl.h b/pan/tasks/socket-impl-openssl.h
index 85a3b8e..38ef501 100644
--- a/pan/tasks/socket-impl-openssl.h
+++ b/pan/tasks/socket-impl-openssl.h
@@ -28,7 +28,7 @@
 #include <pan/tasks/socket-impl-gio.h>
 
 #ifdef HAVE_OPENSSL
-  #include <pan/data-impl/cert-store.h>
+  #include <pan/data/cert-store.h>
   #include <openssl/crypto.h>
   #include <openssl/x509.h>
   #include <openssl/x509v3.h>
@@ -87,7 +87,7 @@ namespace pan
       DoResult do_write ();
 
       // CertStore::Listener
-      virtual void on_verify_cert_failed (X509*, std::string, int) ;
+      virtual void on_verify_cert_failed (X509*, std::string, std::string, int) ;
       virtual void on_valid_cert_added (X509*, std::string );
 
       GIOChannel * create_channel (const StringView& host_in, int port, std::string& setme_err);
diff --git a/pan/tasks/task-groups.h b/pan/tasks/task-groups.h
index 860aa5e..d520e1a 100644
--- a/pan/tasks/task-groups.h
+++ b/pan/tasks/task-groups.h
@@ -23,7 +23,7 @@
 #include <pan/general/quark.h>
 #include <pan/data/data.h>
 #include <pan/tasks/task.h>
-#include <pan/data-impl/cert-store.h>
+#include <pan/data/cert-store.h>
 #include <pan/tasks/nntp.h>
 
 namespace pan
diff --git a/pan/tasks/task-upload.h b/pan/tasks/task-upload.h
index 2be4800..9048c71 100644
--- a/pan/tasks/task-upload.h
+++ b/pan/tasks/task-upload.h
@@ -46,6 +46,7 @@ extern "C" {
 namespace pan
 {
   struct Encoder;
+  class Data;
 
   /**
    * Task for uploading binary data to usenet



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]