summaryrefslogtreecommitdiff
path: root/src/libcharon/plugins/certexpire/certexpire_export.c
diff options
context:
space:
mode:
authorYves-Alexis Perez <corsac@corsac.net>2012-06-28 21:16:07 +0200
committerYves-Alexis Perez <corsac@corsac.net>2012-06-28 21:16:07 +0200
commita3b482a8facde4b453ad821bfe40effbe3d17903 (patch)
tree636f02074b05b7473f5db1fe60fa2bceb0094a62 /src/libcharon/plugins/certexpire/certexpire_export.c
parentd816a1afbd841e9943bb439fe4e110b7c4970550 (diff)
parentb34738ed08c2227300d554b139e2495ca5da97d6 (diff)
downloadvyos-strongswan-a3b482a8facde4b453ad821bfe40effbe3d17903.tar.gz
vyos-strongswan-a3b482a8facde4b453ad821bfe40effbe3d17903.zip
Merge tag 'upstream/4.6.4'
Upstream version 4.6.4
Diffstat (limited to 'src/libcharon/plugins/certexpire/certexpire_export.c')
-rw-r--r--src/libcharon/plugins/certexpire/certexpire_export.c388
1 files changed, 388 insertions, 0 deletions
diff --git a/src/libcharon/plugins/certexpire/certexpire_export.c b/src/libcharon/plugins/certexpire/certexpire_export.c
new file mode 100644
index 000000000..c73b0beda
--- /dev/null
+++ b/src/libcharon/plugins/certexpire/certexpire_export.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2011 Martin Willi
+ * Copyright (C) 2011 revosec AG
+ *
+ * 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; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+#include "certexpire_export.h"
+
+#include "certexpire_cron.h"
+
+#include <time.h>
+#include <limits.h>
+#include <errno.h>
+
+#include <debug.h>
+#include <utils/hashtable.h>
+#include <threading/mutex.h>
+#include <credentials/certificates/x509.h>
+
+typedef struct private_certexpire_export_t private_certexpire_export_t;
+
+/**
+ * Private data of an certexpire_export_t object.
+ */
+struct private_certexpire_export_t {
+
+ /**
+ * Public certexpire_export_t interface.
+ */
+ certexpire_export_t public;
+
+ /**
+ * hashtable caching local trustchains, mapping entry_t => entry_t
+ */
+ hashtable_t *local;
+
+ /**
+ * hashtable caching remote trustchains, mapping entry_t => entry_t
+ */
+ hashtable_t *remote;
+
+ /**
+ * Mutex to lock hashtables
+ */
+ mutex_t *mutex;
+
+ /**
+ * Cronjob for export
+ */
+ certexpire_cron_t *cron;
+
+ /**
+ * strftime() format to generate local CSV file
+ */
+ char *local_path;
+
+ /**
+ * strftime() format to generate remote CSV file
+ */
+ char *remote_path;
+
+ /**
+ * stftime() format of the exported expiration date
+ */
+ char *format;
+
+ /**
+ * CSV field separator
+ */
+ char *separator;
+
+ /**
+ * TRUE to use fixed field count, CA at end
+ */
+ bool fixed_fields;
+
+ /**
+ * String to use in empty fields, if using fixed_fields
+ */
+ char *empty_string;
+};
+
+/**
+ * Maximum number of expiration dates we store (for subject + IM CAs + CA)
+ */
+#define MAX_TRUSTCHAIN_LENGTH 7
+
+/**
+ * Hashtable entry
+ */
+typedef struct {
+ /** certificate subject as subjectAltName or CN of a DN */
+ char id[128];
+ /** list of expiration dates, 0 if no certificate */
+ time_t expire[MAX_TRUSTCHAIN_LENGTH];
+} entry_t;
+
+/**
+ * Hashtable hash function
+ */
+static u_int hash(entry_t *key)
+{
+ return chunk_hash(chunk_create(key->id, strlen(key->id)));
+}
+
+/**
+ * Hashtable equals function
+ */
+static bool equals(entry_t *a, entry_t *b)
+{
+ return streq(a->id, b->id);
+}
+
+/**
+ * Export a single trustchain to a path
+ */
+static void export_csv(private_certexpire_export_t *this, char *path,
+ hashtable_t *chains)
+{
+ enumerator_t *enumerator;
+ char buf[PATH_MAX];
+ entry_t *entry;
+ FILE *file;
+ struct tm tm;
+ time_t t;
+ int i;
+
+ t = time(NULL);
+ localtime_r(&t, &tm);
+
+ strftime(buf, sizeof(buf), path, &tm);
+ file = fopen(buf, "a");
+ if (file)
+ {
+ DBG1(DBG_CFG, "exporting expiration dates of %d trustchain%s to '%s'",
+ chains->get_count(chains),
+ chains->get_count(chains) == 1 ? "" : "s", buf);
+ this->mutex->lock(this->mutex);
+ enumerator = chains->create_enumerator(chains);
+ while (enumerator->enumerate(enumerator, NULL, &entry))
+ {
+ fprintf(file, "%s%s", entry->id, this->separator);
+ for (i = 0; i < MAX_TRUSTCHAIN_LENGTH; i++)
+ {
+ if (entry->expire[i])
+ {
+ localtime_r(&entry->expire[i], &tm);
+ strftime(buf, sizeof(buf), this->format, &tm);
+ fprintf(file, "%s", buf);
+ }
+ if (i == MAX_TRUSTCHAIN_LENGTH - 1)
+ {
+ fprintf(file, "\n");
+ }
+ else if (entry->expire[i])
+ {
+ fprintf(file, "%s", this->separator);
+ }
+ else if (this->fixed_fields)
+ {
+ fprintf(file, "%s%s", this->empty_string, this->separator);
+ }
+ }
+ chains->remove_at(chains, enumerator);
+ free(entry);
+ }
+ enumerator->destroy(enumerator);
+ this->mutex->unlock(this->mutex);
+ fclose(file);
+ }
+ else
+ {
+ DBG1(DBG_CFG, "opening CSV file '%s' failed: %s", buf, strerror(errno));
+ }
+}
+
+/**
+ * Export cached trustchain expiration dates to CSV files
+ */
+static void cron_export(private_certexpire_export_t *this)
+{
+ if (this->local_path)
+ {
+ export_csv(this, this->local_path, this->local);
+ }
+ if (this->remote_path)
+ {
+ export_csv(this, this->remote_path, this->remote);
+ }
+}
+
+METHOD(certexpire_export_t, add, void,
+ private_certexpire_export_t *this, linked_list_t *trustchain, bool local)
+{
+ enumerator_t *enumerator;
+ certificate_t *cert;
+ int count;
+
+ /* don't store expiration dates if no path configured */
+ if (local)
+ {
+ if (!this->local_path)
+ {
+ return;
+ }
+ }
+ else
+ {
+ if (!this->remote_path)
+ {
+ return;
+ }
+ }
+
+ count = min(trustchain->get_count(trustchain), MAX_TRUSTCHAIN_LENGTH) - 1;
+
+ enumerator = trustchain->create_enumerator(trustchain);
+ /* get subject cert */
+ if (enumerator->enumerate(enumerator, &cert))
+ {
+ identification_t *id;
+ entry_t *entry;
+ int i;
+
+ INIT(entry);
+
+ /* prefer FQDN subjectAltName... */
+ if (cert->get_type(cert) == CERT_X509)
+ {
+ x509_t *x509 = (x509_t*)cert;
+ enumerator_t *sans;
+
+ sans = x509->create_subjectAltName_enumerator(x509);
+ while (sans->enumerate(sans, &id))
+ {
+ if (id->get_type(id) == ID_FQDN)
+ {
+ snprintf(entry->id, sizeof(entry->id), "%Y", id);
+ break;
+ }
+ }
+ sans->destroy(sans);
+ }
+ /* fallback to CN of DN */
+ if (!entry->id[0])
+ {
+ enumerator_t *parts;
+ id_part_t part;
+ chunk_t data;
+
+ id = cert->get_subject(cert);
+ parts = id->create_part_enumerator(id);
+ while (parts->enumerate(parts, &part, &data))
+ {
+ if (part == ID_PART_RDN_CN)
+ {
+ snprintf(entry->id, sizeof(entry->id), "%.*s",
+ (int)data.len, data.ptr);
+ break;
+ }
+ }
+ parts->destroy(parts);
+ }
+ /* no usable identity? skip */
+ if (!entry->id[0])
+ {
+ enumerator->destroy(enumerator);
+ free(entry);
+ return;
+ }
+
+ /* get intermediate CA expiration dates */
+ cert->get_validity(cert, NULL, NULL, &entry->expire[0]);
+ for (i = 1; i < count && enumerator->enumerate(enumerator, &cert); i++)
+ {
+ cert->get_validity(cert, NULL, NULL, &entry->expire[i]);
+ }
+ /* get CA expiration date, as last array entry */
+ if (enumerator->enumerate(enumerator, &cert))
+ {
+ cert->get_validity(cert, NULL, NULL,
+ &entry->expire[MAX_TRUSTCHAIN_LENGTH - 1]);
+ }
+ this->mutex->lock(this->mutex);
+ if (local)
+ {
+ entry = this->local->put(this->local, entry, entry);
+ }
+ else
+ {
+ entry = this->remote->put(this->remote, entry, entry);
+ }
+ this->mutex->unlock(this->mutex);
+ if (entry)
+ {
+ free(entry);
+ }
+ if (!this->cron)
+ { /* export directly if no cron job defined */
+ if (local)
+ {
+ export_csv(this, this->local_path, this->local);
+ }
+ else
+ {
+ export_csv(this, this->remote_path, this->remote);
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
+METHOD(certexpire_export_t, destroy, void,
+ private_certexpire_export_t *this)
+{
+ entry_t *key, *value;
+ enumerator_t *enumerator;
+
+ enumerator = this->local->create_enumerator(this->local);
+ while (enumerator->enumerate(enumerator, &key, &value))
+ {
+ free(value);
+ }
+ enumerator->destroy(enumerator);
+ enumerator = this->remote->create_enumerator(this->remote);
+ while (enumerator->enumerate(enumerator, &key, &value))
+ {
+ free(value);
+ }
+ enumerator->destroy(enumerator);
+
+ this->local->destroy(this->local);
+ this->remote->destroy(this->remote);
+ DESTROY_IF(this->cron);
+ this->mutex->destroy(this->mutex);
+ free(this);
+}
+
+/**
+ * See header
+ */
+certexpire_export_t *certexpire_export_create()
+{
+ private_certexpire_export_t *this;
+ char *cron;
+
+ INIT(this,
+ .public = {
+ .add = _add,
+ .destroy = _destroy,
+ },
+ .local = hashtable_create((hashtable_hash_t)hash,
+ (hashtable_equals_t)equals, 4),
+ .remote = hashtable_create((hashtable_hash_t)hash,
+ (hashtable_equals_t)equals, 32),
+ .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ .local_path = lib->settings->get_str(lib->settings,
+ "charon.plugins.certexpire.csv.local", NULL),
+ .remote_path = lib->settings->get_str(lib->settings,
+ "charon.plugins.certexpire.csv.remote", NULL),
+ .separator = lib->settings->get_str(lib->settings,
+ "charon.plugins.certexpire.csv.separator", ","),
+ .format = lib->settings->get_str(lib->settings,
+ "charon.plugins.certexpire.csv.format", "%d:%m:%Y"),
+ .fixed_fields = lib->settings->get_bool(lib->settings,
+ "charon.plugins.certexpire.csv.fixed_fields", TRUE),
+ .empty_string = lib->settings->get_str(lib->settings,
+ "charon.plugins.certexpire.csv.empty_string", ""),
+ );
+
+ cron = lib->settings->get_str(lib->settings,
+ "charon.plugins.certexpire.csv.cron", NULL);
+ if (cron)
+ {
+ this->cron = certexpire_cron_create(cron,
+ (certexpire_cron_job_t)cron_export, this);
+ }
+ return &this->public;
+}