summaryrefslogtreecommitdiff
path: root/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c')
-rw-r--r--src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c220
1 files changed, 220 insertions, 0 deletions
diff --git a/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c b/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c
new file mode 100644
index 000000000..175a57aba
--- /dev/null
+++ b/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2012 Andreas Steffen
+ * HSR 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 "tnc_pdp_connections.h"
+
+#include <utils/linked_list.h>
+#include <debug.h>
+
+typedef struct private_tnc_pdp_connections_t private_tnc_pdp_connections_t;
+typedef struct entry_t entry_t;
+
+/**
+ * Private data of tnc_pdp_connections_t
+ */
+struct private_tnc_pdp_connections_t {
+
+ /**
+ * Implements tnc_pdp_connections_t interface
+ */
+ tnc_pdp_connections_t public;
+
+ /**
+ * List of TNC PEP RADIUS Connections
+ */
+ linked_list_t *list;
+};
+
+/**
+ * Data entry for a TNC PEP RADIUS connection
+ */
+struct entry_t {
+
+ /**
+ * NAS identifier of PEP
+ */
+ chunk_t nas_id;
+
+ /**
+ * User name of TNC Client
+ */
+ chunk_t user_name;
+
+ /**
+ * EAP method state
+ */
+ eap_method_t *method;
+
+ /**
+ * IKE SA used for bus communication
+ */
+ ike_sa_t *ike_sa;
+};
+
+/**
+ * Free the memory allocated to a data entry
+ */
+static void free_entry(entry_t *this)
+{
+ this->method->destroy(this->method);
+ this->ike_sa->destroy(this->ike_sa);
+ free(this->nas_id.ptr);
+ free(this->user_name.ptr);
+ free(this);
+}
+
+/**
+ * Find a matching data entry
+ */
+static bool equals_entry( entry_t *this, chunk_t nas_id, chunk_t user_name)
+{
+ bool no_nas_id = !this->nas_id.ptr && !nas_id.ptr;
+
+ return (chunk_equals(this->nas_id, nas_id) || no_nas_id) &&
+ chunk_equals(this->user_name, user_name);
+}
+
+/**
+ * Find a matching data entry
+ */
+static void dbg_nas_user(chunk_t nas_id, chunk_t user_name, bool not, char *op)
+{
+ if (nas_id.len)
+ {
+ DBG1(DBG_CFG, "%s RADIUS connection for user '%.*s' NAS '%.*s'",
+ not ? "could not find" : op, user_name.len, user_name.ptr,
+ nas_id.len, nas_id.ptr);
+ }
+ else
+ {
+ DBG1(DBG_CFG, "%s RADIUS connection for user '%.*s'",
+ not ? "could not find" : op, user_name.len, user_name.ptr);
+ }
+}
+
+METHOD(tnc_pdp_connections_t, add, void,
+ private_tnc_pdp_connections_t *this, chunk_t nas_id, chunk_t user_name,
+ identification_t *peer, eap_method_t *method)
+{
+ enumerator_t *enumerator;
+ entry_t *entry;
+ ike_sa_id_t *ike_sa_id;
+ ike_sa_t *ike_sa;
+ bool found = FALSE;
+
+ ike_sa_id = ike_sa_id_create(0, 0, FALSE);
+ ike_sa = ike_sa_create(ike_sa_id);
+ ike_sa_id->destroy(ike_sa_id);
+ ike_sa->set_other_id(ike_sa, peer);
+
+ enumerator = this->list->create_enumerator(this->list);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (equals_entry(entry, nas_id, user_name))
+ {
+ found = TRUE;
+ entry->method->destroy(entry->method);
+ entry->ike_sa->destroy(entry->ike_sa);
+ DBG1(DBG_CFG, "removed stale RADIUS connection");
+ entry->method = method;
+ entry->ike_sa = ike_sa;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (!found)
+ {
+ entry = malloc_thing(entry_t);
+ entry->nas_id = chunk_clone(nas_id);
+ entry->user_name = chunk_clone(user_name);
+ entry->method = method;
+ entry->ike_sa = ike_sa;
+ this->list->insert_last(this->list, entry);
+ }
+ dbg_nas_user(nas_id, user_name, FALSE, "created");
+}
+
+METHOD(tnc_pdp_connections_t, remove_, void,
+ private_tnc_pdp_connections_t *this, chunk_t nas_id, chunk_t user_name)
+{
+ enumerator_t *enumerator;
+ entry_t *entry;
+
+ enumerator = this->list->create_enumerator(this->list);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (equals_entry(entry, nas_id, user_name))
+ {
+ free_entry(entry);
+ this->list->remove_at(this->list, enumerator);
+ dbg_nas_user(nas_id, user_name, FALSE, "removed");
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
+METHOD(tnc_pdp_connections_t, get_state, eap_method_t*,
+ private_tnc_pdp_connections_t *this, chunk_t nas_id, chunk_t user_name,
+ ike_sa_t **ike_sa)
+{
+ enumerator_t *enumerator;
+ entry_t *entry;
+ eap_method_t *found = NULL;
+
+ enumerator = this->list->create_enumerator(this->list);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (equals_entry(entry, nas_id, user_name))
+ {
+ found = entry->method;
+ *ike_sa = entry->ike_sa;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ dbg_nas_user(nas_id, user_name, !found, "found");
+ return found;
+}
+
+METHOD(tnc_pdp_connections_t, destroy, void,
+ private_tnc_pdp_connections_t *this)
+{
+ this->list->destroy_function(this->list, (void*)free_entry);
+ free(this);
+}
+
+/*
+ * see header file
+ */
+tnc_pdp_connections_t *tnc_pdp_connections_create(void)
+{
+ private_tnc_pdp_connections_t *this;
+
+ INIT(this,
+ .public = {
+ .add = _add,
+ .remove = _remove_,
+ .get_state = _get_state,
+ .destroy = _destroy,
+ },
+ .list = linked_list_create(),
+ );
+
+ return &this->public;
+}
+