summaryrefslogtreecommitdiff
path: root/src/libcharon/config/auth_cfg.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/config/auth_cfg.c')
-rw-r--r--src/libcharon/config/auth_cfg.c768
1 files changed, 768 insertions, 0 deletions
diff --git a/src/libcharon/config/auth_cfg.c b/src/libcharon/config/auth_cfg.c
new file mode 100644
index 000000000..94362c756
--- /dev/null
+++ b/src/libcharon/config/auth_cfg.c
@@ -0,0 +1,768 @@
+/*
+ * Copyright (C) 2007-2009 Martin Willi
+ * Copyright (C) 2008 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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 "auth_cfg.h"
+
+#include <daemon.h>
+#include <utils/linked_list.h>
+#include <utils/identification.h>
+#include <credentials/certificates/certificate.h>
+
+ENUM(auth_rule_names, AUTH_RULE_IDENTITY, AUTH_HELPER_SUBJECT_HASH_URL,
+ "RULE_IDENTITY",
+ "RULE_AUTH_CLASS",
+ "RULE_EAP_IDENTITY",
+ "RULE_EAP_TYPE",
+ "RULE_EAP_VENDOR",
+ "RULE_CA_CERT",
+ "RULE_IM_CERT",
+ "RULE_SUBJECT_CERT",
+ "RULE_CRL_VALIDATION",
+ "RULE_OCSP_VALIDATION",
+ "RULE_AC_GROUP",
+ "HELPER_IM_CERT",
+ "HELPER_SUBJECT_CERT",
+ "HELPER_IM_HASH_URL",
+ "HELPER_SUBJECT_HASH_URL",
+);
+
+typedef struct private_auth_cfg_t private_auth_cfg_t;
+
+/**
+ * private data of item_set
+ */
+struct private_auth_cfg_t {
+
+ /**
+ * public functions
+ */
+ auth_cfg_t public;
+
+ /**
+ * list of entry_t
+ */
+ linked_list_t *entries;
+};
+
+typedef struct entry_t entry_t;
+
+struct entry_t {
+ /** rule type */
+ auth_rule_t type;
+ /** associated value */
+ void *value;
+};
+
+/**
+ * enumerator for auth_cfg_t.create_enumerator()
+ */
+typedef struct {
+ /** implements enumerator_t */
+ enumerator_t public;
+ /** inner enumerator from linked_list_t */
+ enumerator_t *inner;
+ /** current entry */
+ entry_t *current;
+} entry_enumerator_t;
+
+/**
+ * enumerate function for item_enumerator_t
+ */
+static bool enumerate(entry_enumerator_t *this, auth_rule_t *type, void **value)
+{
+ entry_t *entry;
+
+ if (this->inner->enumerate(this->inner, &entry))
+ {
+ this->current = entry;
+ *type = entry->type;
+ *value = entry->value;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * destroy function for item_enumerator_t
+ */
+static void entry_enumerator_destroy(entry_enumerator_t *this)
+{
+ this->inner->destroy(this->inner);
+ free(this);
+}
+
+/**
+ * Implementation of auth_cfg_t.create_enumerator.
+ */
+static enumerator_t* create_enumerator(private_auth_cfg_t *this)
+{
+ entry_enumerator_t *enumerator;
+
+ enumerator = malloc_thing(entry_enumerator_t);
+ enumerator->inner = this->entries->create_enumerator(this->entries);
+ enumerator->public.enumerate = (void*)enumerate;
+ enumerator->public.destroy = (void*)entry_enumerator_destroy;
+ enumerator->current = NULL;
+ return &enumerator->public;
+}
+
+/**
+ * Destroy the value associated with an entry
+ */
+static void destroy_entry_value(entry_t *entry)
+{
+ switch (entry->type)
+ {
+ case AUTH_RULE_IDENTITY:
+ case AUTH_RULE_EAP_IDENTITY:
+ case AUTH_RULE_AC_GROUP:
+ {
+ identification_t *id = (identification_t*)entry->value;
+ id->destroy(id);
+ break;
+ }
+ case AUTH_RULE_CA_CERT:
+ case AUTH_RULE_IM_CERT:
+ case AUTH_RULE_SUBJECT_CERT:
+ case AUTH_HELPER_IM_CERT:
+ case AUTH_HELPER_SUBJECT_CERT:
+ {
+ certificate_t *cert = (certificate_t*)entry->value;
+ cert->destroy(cert);
+ break;
+ }
+ case AUTH_HELPER_IM_HASH_URL:
+ case AUTH_HELPER_SUBJECT_HASH_URL:
+ {
+ free(entry->value);
+ break;
+ }
+ case AUTH_RULE_AUTH_CLASS:
+ case AUTH_RULE_EAP_TYPE:
+ case AUTH_RULE_EAP_VENDOR:
+ case AUTH_RULE_CRL_VALIDATION:
+ case AUTH_RULE_OCSP_VALIDATION:
+ break;
+ }
+}
+
+/**
+ * Implementation of auth_cfg_t.replace.
+ */
+static void replace(auth_cfg_t *this, entry_enumerator_t *enumerator,
+ auth_rule_t type, ...)
+{
+ if (enumerator->current)
+ {
+ va_list args;
+
+ va_start(args, type);
+
+ destroy_entry_value(enumerator->current);
+ enumerator->current->type = type;
+ switch (type)
+ {
+ case AUTH_RULE_AUTH_CLASS:
+ case AUTH_RULE_EAP_TYPE:
+ case AUTH_RULE_EAP_VENDOR:
+ case AUTH_RULE_CRL_VALIDATION:
+ case AUTH_RULE_OCSP_VALIDATION:
+ /* integer type */
+ enumerator->current->value = (void*)(uintptr_t)va_arg(args, u_int);
+ break;
+ case AUTH_RULE_IDENTITY:
+ case AUTH_RULE_EAP_IDENTITY:
+ case AUTH_RULE_AC_GROUP:
+ case AUTH_RULE_CA_CERT:
+ case AUTH_RULE_IM_CERT:
+ case AUTH_RULE_SUBJECT_CERT:
+ case AUTH_HELPER_IM_CERT:
+ case AUTH_HELPER_SUBJECT_CERT:
+ case AUTH_HELPER_IM_HASH_URL:
+ case AUTH_HELPER_SUBJECT_HASH_URL:
+ /* pointer type */
+ enumerator->current->value = va_arg(args, void*);
+ break;
+ }
+ va_end(args);
+ }
+}
+
+/**
+ * Implementation of auth_cfg_t.get.
+ */
+static void* get(private_auth_cfg_t *this, auth_rule_t type)
+{
+ enumerator_t *enumerator;
+ void *current_value, *best_value = NULL;
+ auth_rule_t current_type;
+ bool found = FALSE;
+
+ enumerator = create_enumerator(this);
+ while (enumerator->enumerate(enumerator, &current_type, &current_value))
+ {
+ if (type == current_type)
+ {
+ if (type == AUTH_RULE_CRL_VALIDATION ||
+ type == AUTH_RULE_OCSP_VALIDATION)
+ { /* for CRL/OCSP validation, always get() the highest value */
+ if (!found || current_value > best_value)
+ {
+ best_value = current_value;
+ }
+ found = TRUE;
+ continue;
+ }
+ best_value = current_value;
+ found = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ if (found)
+ {
+ return best_value;
+ }
+ switch (type)
+ {
+ /* use some sane defaults if we don't find an entry */
+ case AUTH_RULE_AUTH_CLASS:
+ return (void*)AUTH_CLASS_ANY;
+ case AUTH_RULE_EAP_TYPE:
+ return (void*)EAP_NAK;
+ case AUTH_RULE_EAP_VENDOR:
+ return (void*)0;
+ case AUTH_RULE_CRL_VALIDATION:
+ case AUTH_RULE_OCSP_VALIDATION:
+ return (void*)VALIDATION_FAILED;
+ case AUTH_RULE_IDENTITY:
+ case AUTH_RULE_EAP_IDENTITY:
+ case AUTH_RULE_AC_GROUP:
+ case AUTH_RULE_CA_CERT:
+ case AUTH_RULE_IM_CERT:
+ case AUTH_RULE_SUBJECT_CERT:
+ case AUTH_HELPER_IM_CERT:
+ case AUTH_HELPER_SUBJECT_CERT:
+ case AUTH_HELPER_IM_HASH_URL:
+ case AUTH_HELPER_SUBJECT_HASH_URL:
+ default:
+ return NULL;
+ }
+}
+
+/**
+ * Implementation of auth_cfg_t.add.
+ */
+static void add(private_auth_cfg_t *this, auth_rule_t type, ...)
+{
+ entry_t *entry = malloc_thing(entry_t);
+ va_list args;
+
+ va_start(args, type);
+ entry->type = type;
+ switch (type)
+ {
+ case AUTH_RULE_AUTH_CLASS:
+ case AUTH_RULE_EAP_TYPE:
+ case AUTH_RULE_EAP_VENDOR:
+ case AUTH_RULE_CRL_VALIDATION:
+ case AUTH_RULE_OCSP_VALIDATION:
+ /* integer type */
+ entry->value = (void*)(uintptr_t)va_arg(args, u_int);
+ break;
+ case AUTH_RULE_IDENTITY:
+ case AUTH_RULE_EAP_IDENTITY:
+ case AUTH_RULE_AC_GROUP:
+ case AUTH_RULE_CA_CERT:
+ case AUTH_RULE_IM_CERT:
+ case AUTH_RULE_SUBJECT_CERT:
+ case AUTH_HELPER_IM_CERT:
+ case AUTH_HELPER_SUBJECT_CERT:
+ case AUTH_HELPER_IM_HASH_URL:
+ case AUTH_HELPER_SUBJECT_HASH_URL:
+ /* pointer type */
+ entry->value = va_arg(args, void*);
+ break;
+ }
+ va_end(args);
+ this->entries->insert_last(this->entries, entry);
+}
+
+/**
+ * Implementation of auth_cfg_t.complies.
+ */
+static bool complies(private_auth_cfg_t *this, auth_cfg_t *constraints,
+ bool log_error)
+{
+ enumerator_t *e1, *e2;
+ bool success = TRUE;
+ auth_rule_t t1, t2;
+ void *value;
+
+ e1 = constraints->create_enumerator(constraints);
+ while (e1->enumerate(e1, &t1, &value))
+ {
+ switch (t1)
+ {
+ case AUTH_RULE_CA_CERT:
+ case AUTH_RULE_IM_CERT:
+ {
+ certificate_t *c1, *c2;
+
+ c1 = (certificate_t*)value;
+
+ success = FALSE;
+ e2 = create_enumerator(this);
+ while (e2->enumerate(e2, &t2, &c2))
+ {
+ if ((t2 == AUTH_RULE_CA_CERT || t2 == AUTH_RULE_IM_CERT) &&
+ c1->equals(c1, c2))
+ {
+ success = TRUE;
+ }
+ }
+ e2->destroy(e2);
+ if (!success && log_error)
+ {
+ DBG1(DBG_CFG, "constraint check failed: peer not "
+ "authenticated by CA '%Y'.", c1->get_subject(c1));
+ }
+ break;
+ }
+ case AUTH_RULE_SUBJECT_CERT:
+ {
+ certificate_t *c1, *c2;
+
+ c1 = (certificate_t*)value;
+ c2 = get(this, AUTH_RULE_SUBJECT_CERT);
+ if (!c2 || !c1->equals(c1, c2))
+ {
+ success = FALSE;
+ if (log_error)
+ {
+ DBG1(DBG_CFG, "constraint check failed: peer not "
+ "authenticated with peer cert '%Y'.",
+ c1->get_subject(c1));
+ }
+ }
+ break;
+ }
+ case AUTH_RULE_CRL_VALIDATION:
+ case AUTH_RULE_OCSP_VALIDATION:
+ {
+ cert_validation_t validated, required;
+
+ required = (uintptr_t)value;
+ validated = (uintptr_t)get(this, t1);
+ switch (required)
+ {
+ case VALIDATION_FAILED:
+ /* no constraint */
+ break;
+ case VALIDATION_SKIPPED:
+ if (validated == VALIDATION_SKIPPED)
+ {
+ break;
+ }
+ /* FALL */
+ case VALIDATION_GOOD:
+ if (validated == VALIDATION_GOOD)
+ {
+ break;
+ }
+ /* FALL */
+ default:
+ success = FALSE;
+ if (log_error)
+ {
+ DBG1(DBG_CFG, "constraint check failed: %N is %N, "
+ "but requires at least %N", auth_rule_names,
+ t1, cert_validation_names, validated,
+ cert_validation_names, required);
+ }
+ break;
+ }
+ break;
+ }
+ case AUTH_RULE_IDENTITY:
+ case AUTH_RULE_EAP_IDENTITY:
+ {
+ identification_t *id1, *id2;
+
+ id1 = (identification_t*)value;
+ id2 = get(this, t1);
+ if (!id2 || !id2->matches(id2, id1))
+ {
+ success = FALSE;
+ if (log_error)
+ {
+ DBG1(DBG_CFG, "constraint check failed: %sidentity '%Y'"
+ " required ", t1 == AUTH_RULE_IDENTITY ? "" :
+ "EAP ", id1);
+ }
+ }
+ break;
+ }
+ case AUTH_RULE_AUTH_CLASS:
+ {
+ if ((uintptr_t)value != AUTH_CLASS_ANY &&
+ (uintptr_t)value != (uintptr_t)get(this, t1))
+ {
+ success = FALSE;
+ if (log_error)
+ {
+ DBG1(DBG_CFG, "constraint requires %N authentication, "
+ "but %N was used", auth_class_names, (uintptr_t)value,
+ auth_class_names, (uintptr_t)get(this, t1));
+ }
+ }
+ break;
+ }
+ case AUTH_RULE_EAP_TYPE:
+ {
+ if ((uintptr_t)value != (uintptr_t)get(this, t1))
+ {
+ success = FALSE;
+ if (log_error)
+ {
+ DBG1(DBG_CFG, "constraint requires %N, "
+ "but %N was used", eap_type_names, (uintptr_t)value,
+ eap_type_names, (uintptr_t)get(this, t1));
+ }
+ }
+ break;
+ }
+ case AUTH_RULE_EAP_VENDOR:
+ {
+ if ((uintptr_t)value != (uintptr_t)get(this, t1))
+ {
+ success = FALSE;
+ if (log_error)
+ {
+ DBG1(DBG_CFG, "constraint requires EAP vendor %d, "
+ "but %d was used", (uintptr_t)value,
+ (uintptr_t)get(this, t1));
+ }
+ }
+ break;
+ }
+ case AUTH_RULE_AC_GROUP:
+ {
+ success = FALSE;
+ if (log_error)
+ {
+ DBG1(DBG_CFG, "constraint check %N not implemented!",
+ auth_rule_names, t1);
+ }
+ break;
+ }
+ case AUTH_HELPER_IM_CERT:
+ case AUTH_HELPER_SUBJECT_CERT:
+ case AUTH_HELPER_IM_HASH_URL:
+ case AUTH_HELPER_SUBJECT_HASH_URL:
+ /* skip helpers */
+ continue;
+ }
+ if (!success)
+ {
+ break;
+ }
+ }
+ e1->destroy(e1);
+ return success;
+}
+
+/**
+ * Implementation of auth_cfg_t.merge.
+ */
+static void merge(private_auth_cfg_t *this, private_auth_cfg_t *other, bool copy)
+{
+ if (!other)
+ { /* nothing to merge */
+ return;
+ }
+ if (copy)
+ {
+ enumerator_t *enumerator;
+ auth_rule_t type;
+ void *value;
+
+ enumerator = create_enumerator(other);
+ while (enumerator->enumerate(enumerator, &type, &value))
+ {
+ switch (type)
+ {
+ case AUTH_RULE_CA_CERT:
+ case AUTH_RULE_IM_CERT:
+ case AUTH_RULE_SUBJECT_CERT:
+ case AUTH_HELPER_IM_CERT:
+ case AUTH_HELPER_SUBJECT_CERT:
+ {
+ certificate_t *cert = (certificate_t*)value;
+
+ add(this, type, cert->get_ref(cert));
+ break;
+ }
+ case AUTH_RULE_CRL_VALIDATION:
+ case AUTH_RULE_OCSP_VALIDATION:
+ case AUTH_RULE_AUTH_CLASS:
+ case AUTH_RULE_EAP_TYPE:
+ case AUTH_RULE_EAP_VENDOR:
+ {
+ add(this, type, (uintptr_t)value);
+ break;
+ }
+ case AUTH_RULE_IDENTITY:
+ case AUTH_RULE_EAP_IDENTITY:
+ case AUTH_RULE_AC_GROUP:
+ {
+ identification_t *id = (identification_t*)value;
+
+ add(this, type, id->clone(id));
+ break;
+ }
+ case AUTH_HELPER_IM_HASH_URL:
+ case AUTH_HELPER_SUBJECT_HASH_URL:
+ {
+ add(this, type, strdup((char*)value));
+ break;
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+ }
+ else
+ {
+ entry_t *entry;
+
+ while (other->entries->remove_first(other->entries,
+ (void**)&entry) == SUCCESS)
+ {
+ this->entries->insert_last(this->entries, entry);
+ }
+ }
+}
+
+/**
+ * Implementation of auth_cfg_t.equals.
+ */
+static bool equals(private_auth_cfg_t *this, private_auth_cfg_t *other)
+{
+ enumerator_t *e1, *e2;
+ entry_t *i1, *i2;
+ bool equal = TRUE, found;
+
+ if (this->entries->get_count(this->entries) !=
+ other->entries->get_count(other->entries))
+ {
+ return FALSE;
+ }
+ e1 = this->entries->create_enumerator(this->entries);
+ while (e1->enumerate(e1, &i1))
+ {
+ found = FALSE;
+ e2 = other->entries->create_enumerator(other->entries);
+ while (e2->enumerate(e2, &i2))
+ {
+ if (i1->type == i2->type)
+ {
+ switch (i1->type)
+ {
+ case AUTH_RULE_AUTH_CLASS:
+ case AUTH_RULE_EAP_TYPE:
+ case AUTH_RULE_EAP_VENDOR:
+ case AUTH_RULE_CRL_VALIDATION:
+ case AUTH_RULE_OCSP_VALIDATION:
+ {
+ if (i1->value == i2->value)
+ {
+ found = TRUE;
+ break;
+ }
+ continue;
+ }
+ case AUTH_RULE_CA_CERT:
+ case AUTH_RULE_IM_CERT:
+ case AUTH_RULE_SUBJECT_CERT:
+ case AUTH_HELPER_IM_CERT:
+ case AUTH_HELPER_SUBJECT_CERT:
+ {
+ certificate_t *c1, *c2;
+
+ c1 = (certificate_t*)i1->value;
+ c2 = (certificate_t*)i2->value;
+
+ if (c1->equals(c1, c2))
+ {
+ found = TRUE;
+ break;
+ }
+ continue;
+ }
+ case AUTH_RULE_IDENTITY:
+ case AUTH_RULE_EAP_IDENTITY:
+ case AUTH_RULE_AC_GROUP:
+ {
+ identification_t *id1, *id2;
+
+ id1 = (identification_t*)i1->value;
+ id2 = (identification_t*)i2->value;
+
+ if (id1->equals(id1, id2))
+ {
+ found = TRUE;
+ break;
+ }
+ continue;
+ }
+ case AUTH_HELPER_IM_HASH_URL:
+ case AUTH_HELPER_SUBJECT_HASH_URL:
+ {
+ if (streq(i1->value, i2->value))
+ {
+ found = TRUE;
+ break;
+ }
+ continue;
+ }
+ }
+ break;
+ }
+ }
+ e2->destroy(e2);
+ if (!found)
+ {
+ equal = FALSE;
+ break;
+ }
+ }
+ e1->destroy(e1);
+ return equal;
+}
+
+/**
+ * Implementation of auth_cfg_t.purge
+ */
+static void purge(private_auth_cfg_t *this, bool keep_ca)
+{
+ entry_t *entry;
+ linked_list_t *cas;
+
+ cas = linked_list_create();
+ while (this->entries->remove_last(this->entries, (void**)&entry) == SUCCESS)
+ {
+ if (keep_ca && entry->type == AUTH_RULE_CA_CERT)
+ {
+ cas->insert_first(cas, entry);
+ }
+ else
+ {
+ destroy_entry_value(entry);
+ free(entry);
+ }
+ }
+ while (cas->remove_last(cas, (void**)&entry) == SUCCESS)
+ {
+ this->entries->insert_first(this->entries, entry);
+ }
+ cas->destroy(cas);
+}
+
+/**
+ * Implementation of auth_cfg_t.clone
+ */
+static auth_cfg_t* clone_(private_auth_cfg_t *this)
+{
+ enumerator_t *enumerator;
+ auth_cfg_t *clone;
+ entry_t *entry;
+
+ clone = auth_cfg_create();
+ enumerator = this->entries->create_enumerator(this->entries);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ switch (entry->type)
+ {
+ case AUTH_RULE_IDENTITY:
+ case AUTH_RULE_EAP_IDENTITY:
+ case AUTH_RULE_AC_GROUP:
+ {
+ identification_t *id = (identification_t*)entry->value;
+ clone->add(clone, entry->type, id->clone(id));
+ break;
+ }
+ case AUTH_RULE_CA_CERT:
+ case AUTH_RULE_IM_CERT:
+ case AUTH_RULE_SUBJECT_CERT:
+ case AUTH_HELPER_IM_CERT:
+ case AUTH_HELPER_SUBJECT_CERT:
+ {
+ certificate_t *cert = (certificate_t*)entry->value;
+ clone->add(clone, entry->type, cert->get_ref(cert));
+ break;
+ }
+ case AUTH_HELPER_IM_HASH_URL:
+ case AUTH_HELPER_SUBJECT_HASH_URL:
+ {
+ clone->add(clone, entry->type, strdup(entry->value));
+ break;
+ }
+ case AUTH_RULE_AUTH_CLASS:
+ case AUTH_RULE_EAP_TYPE:
+ case AUTH_RULE_EAP_VENDOR:
+ case AUTH_RULE_CRL_VALIDATION:
+ case AUTH_RULE_OCSP_VALIDATION:
+ clone->add(clone, entry->type, (uintptr_t)entry->value);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ return clone;
+}
+
+/**
+ * Implementation of auth_cfg_t.destroy
+ */
+static void destroy(private_auth_cfg_t *this)
+{
+ purge(this, FALSE);
+ this->entries->destroy(this->entries);
+ free(this);
+}
+
+/*
+ * see header file
+ */
+auth_cfg_t *auth_cfg_create()
+{
+ private_auth_cfg_t *this = malloc_thing(private_auth_cfg_t);
+
+ this->public.add = (void(*)(auth_cfg_t*, auth_rule_t type, ...))add;
+ this->public.get = (void*(*)(auth_cfg_t*, auth_rule_t type))get;
+ this->public.create_enumerator = (enumerator_t*(*)(auth_cfg_t*))create_enumerator;
+ this->public.replace = (void(*)(auth_cfg_t*,enumerator_t*,auth_rule_t,...))replace;
+ this->public.complies = (bool(*)(auth_cfg_t*, auth_cfg_t *,bool))complies;
+ this->public.merge = (void(*)(auth_cfg_t*, auth_cfg_t *other,bool))merge;
+ this->public.purge = (void(*)(auth_cfg_t*,bool))purge;
+ this->public.equals = (bool(*)(auth_cfg_t*, auth_cfg_t *other))equals;
+ this->public.clone = (auth_cfg_t*(*)(auth_cfg_t*))clone_;
+ this->public.destroy = (void(*)(auth_cfg_t*))destroy;
+
+ this->entries = linked_list_create();
+
+ return &this->public;
+}
+