diff options
author | Yves-Alexis Perez <corsac@corsac.net> | 2012-06-28 21:16:07 +0200 |
---|---|---|
committer | Yves-Alexis Perez <corsac@corsac.net> | 2012-06-28 21:16:07 +0200 |
commit | a3b482a8facde4b453ad821bfe40effbe3d17903 (patch) | |
tree | 636f02074b05b7473f5db1fe60fa2bceb0094a62 /src/libcharon/plugins/certexpire/certexpire_export.c | |
parent | d816a1afbd841e9943bb439fe4e110b7c4970550 (diff) | |
parent | b34738ed08c2227300d554b139e2495ca5da97d6 (diff) | |
download | vyos-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.c | 388 |
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; +} |