about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorJames Booth <boothj5@gmail.com>2015-09-24 00:18:18 +0100
committerJames Booth <boothj5@gmail.com>2015-09-24 00:18:18 +0100
commitd96e68ea53c6457dbbd441d6dbe13c5c994d7a22 (patch)
treea4ffc77f9468d3c3bd4db62f45d6f9f9c1882e52 /src
parent40ce5cb0e08c892dfa12488488e554e6c6a35f54 (diff)
downloadprofani-tty-d96e68ea53c6457dbbd441d6dbe13c5c994d7a22.tar.gz
Save trusted certificates to tlscerts file with more information
Diffstat (limited to 'src')
-rw-r--r--src/config/preferences.c74
-rw-r--r--src/config/preferences.h4
-rw-r--r--src/config/tlscerts.c181
-rw-r--r--src/config/tlscerts.h61
-rw-r--r--src/event/server_events.c24
-rw-r--r--src/event/server_events.h1
-rw-r--r--src/profanity.c4
7 files changed, 262 insertions, 87 deletions
diff --git a/src/config/preferences.c b/src/config/preferences.c
index 3584b457..7a198ac7 100644
--- a/src/config/preferences.c
+++ b/src/config/preferences.c
@@ -430,80 +430,6 @@ prefs_set_pgp_char(char ch)
     _save_prefs();
 }
 
-GList *
-prefs_get_trusted_certs(void)
-{
-    gsize length;
-    GList *fp_list = NULL;
-    gchar **fps = g_key_file_get_string_list(prefs, PREF_GROUP_CONNECTION, "certs", &length, NULL);
-    if (fps) {
-        int i = 0;
-        for (i = 0; i < length; i++) {
-            fp_list = g_list_append(fp_list, strdup(fps[i]));
-        }
-        g_strfreev(fps);
-        return fp_list;
-    } else {
-        return NULL;
-    }
-}
-
-void
-prefs_free_trusted_certs(GList *certs)
-{
-    if (certs) {
-        g_list_free_full(certs, free);
-    }
-}
-
-void
-prefs_add_trusted_cert(const char * const fp)
-{
-    gsize length;
-    gchar **list = g_key_file_get_string_list(prefs, PREF_GROUP_CONNECTION, "certs", &length, NULL);
-    GList *glist = NULL;
-
-    // list found
-    if (list) {
-        int i = 0;
-        for (i = 0; i < length; i++) {
-            // item already in list, exit function
-            if (strcmp(list[i], fp) == 0) {
-                g_list_free_full(glist, g_free);
-                g_strfreev(list);
-                return;
-            }
-            // add item to our g_list
-            glist = g_list_append(glist, strdup(list[i]));
-        }
-
-        // item not found, add to our g_list
-        glist = g_list_append(glist, strdup(fp));
-
-        // create the new list entry
-        const gchar* new_list[g_list_length(glist)+1];
-        GList *curr = glist;
-        i = 0;
-        while (curr) {
-            new_list[i++] = strdup(curr->data);
-            curr = g_list_next(curr);
-        }
-        new_list[i] = NULL;
-        g_key_file_set_string_list(prefs, PREF_GROUP_CONNECTION, "certs", new_list, g_list_length(glist));
-
-    // list not found
-    } else {
-        const gchar* new_list[2];
-        new_list[0] = strdup(fp);
-        new_list[1] = NULL;
-        g_key_file_set_string_list(prefs, PREF_GROUP_CONNECTION, "certs", new_list, 1);
-    }
-
-    g_strfreev(list);
-    g_list_free_full(glist, g_free);
-    _save_prefs();
-}
-
 gboolean
 prefs_add_alias(const char * const name, const char * const value)
 {
diff --git a/src/config/preferences.h b/src/config/preferences.h
index 9718cfcb..89b3fe24 100644
--- a/src/config/preferences.h
+++ b/src/config/preferences.h
@@ -163,8 +163,4 @@ char * prefs_get_string(preference_t pref);
 void prefs_free_string(char *pref);
 void prefs_set_string(preference_t pref, char *value);
 
-GList* prefs_get_trusted_certs(void);
-void prefs_free_trusted_certs(GList *certs);
-void prefs_add_trusted_cert(const char * const fp);
-
 #endif
diff --git a/src/config/tlscerts.c b/src/config/tlscerts.c
new file mode 100644
index 00000000..562e3b0b
--- /dev/null
+++ b/src/config/tlscerts.c
@@ -0,0 +1,181 @@
+/*
+ * tlscerts.c
+ *
+ * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com>
+ *
+ * This file is part of Profanity.
+ *
+ * Profanity 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Profanity 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 Profanity.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, as a special exception, the copyright holders give permission to
+ * link the code of portions of this program with the OpenSSL library under
+ * certain conditions as described in each individual source file, and
+ * distribute linked combinations including the two.
+ *
+ * You must obey the GNU General Public License in all respects for all of the
+ * code used other than OpenSSL. If you modify file(s) with this exception, you
+ * may extend this exception to your version of the file(s), but you are not
+ * obligated to do so. If you do not wish to do so, delete this exception
+ * statement from your version. If you delete this exception statement from all
+ * source files in the program, then also delete it here.
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include "config/tlscerts.h"
+#include "log.h"
+#include "common.h"
+
+static gchar *tlscerts_loc;
+static GKeyFile *tlscerts;
+
+static gchar* _get_tlscerts_file(void);
+static void _save_tlscerts(void);
+
+void
+tlscerts_init(void)
+{
+    log_info("Loading TLS certificates");
+    tlscerts_loc = _get_tlscerts_file();
+
+    if (g_file_test(tlscerts_loc, G_FILE_TEST_EXISTS)) {
+        g_chmod(tlscerts_loc, S_IRUSR | S_IWUSR);
+    }
+
+    tlscerts = g_key_file_new();
+    g_key_file_load_from_file(tlscerts, tlscerts_loc, G_KEY_FILE_KEEP_COMMENTS, NULL);
+}
+
+gboolean
+tlscerts_exists(const char * const fingerprint)
+{
+    return g_key_file_has_group(tlscerts, fingerprint);
+}
+
+TLSCertificate*
+tlscerts_new(const char * const fingerprint, const char * const domain, const char * const organisation,
+    const char * const email, const char * const notbefore, const char * const notafter)
+{
+    TLSCertificate *cert = malloc(sizeof(TLSCertificate));
+    if (fingerprint) {
+        cert->fingerprint = strdup(fingerprint);
+    } else {
+        cert->fingerprint = NULL;
+    }
+    if (domain) {
+        cert->domain = strdup(domain);
+    } else {
+        cert->domain = NULL;
+    }
+    if (organisation) {
+        cert->organisation = strdup(organisation);
+    } else {
+        cert->organisation = NULL;
+    }
+    if (email) {
+        cert->email = strdup(email);
+    } else {
+        cert->email= NULL;
+    }
+    if (notbefore) {
+        cert->notbefore = strdup(notbefore);
+    } else {
+        cert->notbefore = NULL;
+    }
+    if (notafter) {
+        cert->notafter = strdup(notafter);
+    } else {
+        cert->notafter = NULL;
+    }
+
+    return cert;
+}
+
+void
+tlscerts_add(TLSCertificate *cert)
+{
+    if (!cert) {
+        return;
+    }
+
+    if (!cert->fingerprint) {
+        return;
+    }
+
+    if (cert->domain) {
+        g_key_file_set_string(tlscerts, cert->fingerprint, "domain", cert->domain);
+    }
+    if (cert->organisation) {
+        g_key_file_set_string(tlscerts, cert->fingerprint, "organisation", cert->organisation);
+    }
+    if (cert->email) {
+        g_key_file_set_string(tlscerts, cert->fingerprint, "email", cert->email);
+    }
+    if (cert->notbefore) {
+        g_key_file_set_string(tlscerts, cert->fingerprint, "start", cert->notbefore);
+    }
+    if (cert->notafter) {
+        g_key_file_set_string(tlscerts, cert->fingerprint, "end", cert->notafter);
+    }
+
+    _save_tlscerts();
+}
+
+void
+tlscerts_free(TLSCertificate *cert)
+{
+    if (cert) {
+        free(cert->fingerprint);
+        free(cert->domain);
+        free(cert->organisation);
+        free(cert->email);
+        free(cert->notbefore);
+        free(cert->notafter);
+    }
+}
+
+void
+tlscerts_close(void)
+{
+    g_key_file_free(tlscerts);
+    tlscerts = NULL;
+}
+
+static gchar *
+_get_tlscerts_file(void)
+{
+    gchar *xdg_data = xdg_get_data_home();
+    GString *tlscerts_file = g_string_new(xdg_data);
+    g_string_append(tlscerts_file, "/profanity/tlscerts");
+    gchar *result = strdup(tlscerts_file->str);
+    g_free(xdg_data);
+    g_string_free(tlscerts_file, TRUE);
+
+    return result;
+}
+
+static void
+_save_tlscerts(void)
+{
+    gsize g_data_size;
+    gchar *g_tlscerts_data = g_key_file_to_data(tlscerts, &g_data_size, NULL);
+    g_file_set_contents(tlscerts_loc, g_tlscerts_data, g_data_size, NULL);
+    g_chmod(tlscerts_loc, S_IRUSR | S_IWUSR);
+    g_free(g_tlscerts_data);
+}
diff --git a/src/config/tlscerts.h b/src/config/tlscerts.h
new file mode 100644
index 00000000..782d4430
--- /dev/null
+++ b/src/config/tlscerts.h
@@ -0,0 +1,61 @@
+/*
+ * tlscerts.h
+ *
+ * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com>
+ *
+ * This file is part of Profanity.
+ *
+ * Profanity 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Profanity 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 Profanity.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, as a special exception, the copyright holders give permission to
+ * link the code of portions of this program with the OpenSSL library under
+ * certain conditions as described in each individual source file, and
+ * distribute linked combinations including the two.
+ *
+ * You must obey the GNU General Public License in all respects for all of the
+ * code used other than OpenSSL. If you modify file(s) with this exception, you
+ * may extend this exception to your version of the file(s), but you are not
+ * obligated to do so. If you do not wish to do so, delete this exception
+ * statement from your version. If you delete this exception statement from all
+ * source files in the program, then also delete it here.
+ *
+ */
+
+#ifndef TLSCERTS_H
+#define TLSCERTS_H
+
+typedef struct tls_cert_t {
+    char *fingerprint;
+    char *domain;
+    char *organisation;
+    char *email;
+    char *notbefore;
+    char *notafter;
+} TLSCertificate;
+
+void tlscerts_init(void);
+
+TLSCertificate *tlscerts_new(const char * const fingerprint, const char * const domain,
+    const char * const organisation, const char * const email,
+    const char * const notbefore, const char * const notafter);
+
+gboolean tlscerts_exists(const char * const fingerprint);
+
+void tlscerts_add(TLSCertificate *cert);
+
+void tlscerts_free(TLSCertificate *cert);
+
+void tlscerts_close(void);
+
+#endif
diff --git a/src/event/server_events.c b/src/event/server_events.c
index 176973ff..4eb4f785 100644
--- a/src/event/server_events.c
+++ b/src/event/server_events.c
@@ -44,6 +44,7 @@
 #include "config/account.h"
 #include "roster_list.h"
 #include "window_list.h"
+#include "config/tlscerts.h"
 
 #ifdef HAVE_LIBOTR
 #include "otr/otr.h"
@@ -643,12 +644,9 @@ int
 sv_ev_certfail(const char * const errormsg, const char * const certname, const char * const certfp,
     const char * const notbefore, const char * const notafter)
 {
-    GList *trusted = prefs_get_trusted_certs();
-    if (g_list_find_custom(trusted, certfp, (GCompareFunc)g_strcmp0)) {
-        prefs_free_trusted_certs(trusted);
+    if (tlscerts_exists(certfp)) {
         return 1;
     }
-    prefs_free_trusted_certs(trusted);
 
     char *domain = NULL;
     char *org = NULL;
@@ -676,15 +674,12 @@ sv_ev_certfail(const char * const errormsg, const char * const certname, const c
     cons_show_error("TLS certificate verification failed: %s", errormsg);
     if (domain) {
         cons_show("  Domain       : %s", domain);
-        free(domain);
     }
     if (org) {
         cons_show("  Organisation : %s", org);
-        free(org);
     }
     if (email) {
         cons_show("  Email        : %s", email);
-        free(email);
     }
     cons_show("  Fingerprint  : %s", certfp);
     cons_show("  Start        : %s", notbefore);
@@ -712,13 +707,26 @@ sv_ev_certfail(const char * const errormsg, const char * const certname, const c
 
     if (g_strcmp0(cmd, "/tls allow") == 0) {
         free(cmd);
+        free(domain);
+        free(org);
+        free(email);
         return 1;
     } else if (g_strcmp0(cmd, "/tls always") == 0) {
-        prefs_add_trusted_cert(certfp);
+        if (!tlscerts_exists(certfp)) {
+            TLSCertificate *cert = tlscerts_new(certfp, domain, org, email, notbefore, notafter);
+            tlscerts_add(cert);
+            tlscerts_free(cert);
+        }
         free(cmd);
+        free(domain);
+        free(org);
+        free(email);
         return 1;
     } else {
         free(cmd);
+        free(domain);
+        free(org);
+        free(email);
         return 0;
     }
 }
diff --git a/src/event/server_events.h b/src/event/server_events.h
index e9ada1ce..2aa90754 100644
--- a/src/event/server_events.h
+++ b/src/event/server_events.h
@@ -89,5 +89,4 @@ void sv_ev_roster_received(void);
 int sv_ev_certfail(const char * const errormsg, const char * const certname, const char * const certfp,
     const char * const notbefore, const char * const notafter);
 
-
 #endif
diff --git a/src/profanity.c b/src/profanity.c
index a56eb5e9..79e008d7 100644
--- a/src/profanity.c
+++ b/src/profanity.c
@@ -55,6 +55,7 @@
 #include "common.h"
 #include "contact.h"
 #include "roster_list.h"
+#include "config/tlscerts.h"
 #include "log.h"
 #include "muc.h"
 #ifdef HAVE_LIBOTR
@@ -68,6 +69,7 @@
 #include "ui/ui.h"
 #include "window_list.h"
 #include "event/client_events.h"
+#include "config/tlscerts.h"
 
 static void _check_autoaway(void);
 static void _init(const int disable_tls, char *log_level);
@@ -248,6 +250,7 @@ _init(const int disable_tls, char *log_level)
     log_info("Initialising contact list");
     roster_init();
     muc_init();
+    tlscerts_init();
 #ifdef HAVE_LIBOTR
     otr_init();
 #endif
@@ -284,6 +287,7 @@ _shutdown(void)
     chat_log_close();
     theme_close();
     accounts_close();
+    tlscerts_close();
     cmd_uninit();
     log_stderr_close();
     log_close();