aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libcharon/plugins/tnc_pdp/Makefile.am3
-rw-r--r--src/libcharon/plugins/tnc_pdp/tnc_pdp.c53
-rw-r--r--src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c202
-rw-r--r--src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.h74
4 files changed, 320 insertions, 12 deletions
diff --git a/src/libcharon/plugins/tnc_pdp/Makefile.am b/src/libcharon/plugins/tnc_pdp/Makefile.am
index 170a6f989..2d4c4d55a 100644
--- a/src/libcharon/plugins/tnc_pdp/Makefile.am
+++ b/src/libcharon/plugins/tnc_pdp/Makefile.am
@@ -18,6 +18,7 @@ libstrongswan_tnc_pdp_la_LIBADD = \
endif
libstrongswan_tnc_pdp_la_SOURCES = \
- tnc_pdp_plugin.h tnc_pdp_plugin.c tnc_pdp.h tnc_pdp.c
+ tnc_pdp_plugin.h tnc_pdp_plugin.c \
+ tnc_pdp.h tnc_pdp.c tnc_pdp_connections.h tnc_pdp_connections.c
libstrongswan_tnc_pdp_la_LDFLAGS = -module -avoid-version
diff --git a/src/libcharon/plugins/tnc_pdp/tnc_pdp.c b/src/libcharon/plugins/tnc_pdp/tnc_pdp.c
index 1ef87f24f..db1f4c77c 100644
--- a/src/libcharon/plugins/tnc_pdp/tnc_pdp.c
+++ b/src/libcharon/plugins/tnc_pdp/tnc_pdp.c
@@ -14,6 +14,7 @@
*/
#include "tnc_pdp.h"
+#include "tnc_pdp_connections.h"
#include <errno.h>
#include <unistd.h>
@@ -84,9 +85,9 @@ struct private_tnc_pdp_t {
signer_t *signer;
/**
- * EAP method
+ * List of registered TNC-PDP connections
*/
- eap_method_t *method;
+ tnc_pdp_connections_t *connections;
};
@@ -195,7 +196,7 @@ static void send_response(private_tnc_pdp_t *this,
while (data.len > MAX_RADIUS_ATTRIBUTE_SIZE)
{
response->add(response, RAT_EAP_MESSAGE,
- chunk_create(data.ptr,MAX_RADIUS_ATTRIBUTE_SIZE));
+ chunk_create(data.ptr, MAX_RADIUS_ATTRIBUTE_SIZE));
data = chunk_skip(data, MAX_RADIUS_ATTRIBUTE_SIZE);
}
response->add(response, RAT_EAP_MESSAGE, data);
@@ -207,6 +208,7 @@ static void send_response(private_tnc_pdp_t *this,
DBG1(DBG_CFG, "sending RADIUS %N to client '%H'", radius_message_code_names,
code, client);
send_message(this, response, client);
+ response->destroy(response);
}
/**
@@ -217,8 +219,10 @@ static void process_eap(private_tnc_pdp_t *this, radius_message_t *request,
{
enumerator_t *enumerator;
eap_payload_t *in, *out = NULL;
+ eap_method_t *method;
eap_type_t eap_type;
chunk_t data, message = chunk_empty;
+ chunk_t user_name = chunk_empty, nas_id = chunk_empty;
radius_message_code_t code = RMC_ACCESS_CHALLENGE;
u_int32_t eap_vendor;
int type;
@@ -226,9 +230,22 @@ static void process_eap(private_tnc_pdp_t *this, radius_message_t *request,
enumerator = request->create_enumerator(request);
while (enumerator->enumerate(enumerator, &type, &data))
{
- if (type == RAT_EAP_MESSAGE && data.len)
+ switch (type)
{
- message = chunk_cat("mc", message, data);
+ case RAT_USER_NAME:
+ user_name = data;
+ break;
+ case RAT_NAS_IDENTIFIER:
+ nas_id = data;
+ break;
+ case RAT_EAP_MESSAGE:
+ if (data.len)
+ {
+ message = chunk_cat("mc", message, data);
+ }
+ break;
+ default:
+ break;
}
}
enumerator->destroy(enumerator);
@@ -255,19 +272,27 @@ static void process_eap(private_tnc_pdp_t *this, radius_message_t *request,
eap_identity = chunk_create(message.ptr + 5, message.len - 5);
peer = identification_create_from_data(eap_identity);
- this->method = charon->eap->create_instance(charon->eap, this->type,
- 0, EAP_SERVER, this->server, peer);
+ method = charon->eap->create_instance(charon->eap, this->type,
+ 0, EAP_SERVER, this->server, peer);
peer->destroy(peer);
- if (!this->method)
+ if (!method)
{
in->destroy(in);
return;
}
- this->method->initiate(this->method, &out);
+ this->connections->add(this->connections, nas_id, user_name, method);
+ method->initiate(method, &out);
}
else
{
- switch (this->method->process(this->method, in, &out))
+ method = this->connections->get_method(this->connections, nas_id,
+ user_name);
+ if (!method)
+ {
+ return;
+ }
+
+ switch (method->process(method, in, &out))
{
case NEED_MORE:
code = RMC_ACCESS_CHALLENGE;
@@ -287,6 +312,11 @@ static void process_eap(private_tnc_pdp_t *this, radius_message_t *request,
}
}
+ if (code == RMC_ACCESS_ACCEPT || code == RMC_ACCESS_REJECT)
+ {
+ this->connections->remove(this->connections, nas_id, user_name);
+ }
+
send_response(this, request, code, out, source);
in->destroy(in);
out->destroy(out);
@@ -412,7 +442,7 @@ METHOD(tnc_pdp_t, destroy, void,
DESTROY_IF(this->server);
DESTROY_IF(this->signer);
DESTROY_IF(this->hasher);
- DESTROY_IF(this->method);
+ DESTROY_IF(this->connections);
free(this);
}
@@ -433,6 +463,7 @@ tnc_pdp_t *tnc_pdp_create(u_int16_t port)
.ipv6 = open_socket(this, AF_INET6, port),
.hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5),
.signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_MD5_128),
+ .connections = tnc_pdp_connections_create(),
);
if (!this->ipv4 && !this->ipv6)
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..b57a15cf6
--- /dev/null
+++ b/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c
@@ -0,0 +1,202 @@
+/*
+ * 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;
+};
+
+/**
+ * Free the memory allocated to a data entry
+ */
+static void free_entry(entry_t *this)
+{
+ this->method->destroy(this->method);
+ 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,
+ eap_method_t *method)
+{
+ enumerator_t *enumerator;
+ entry_t *entry;
+ bool found = FALSE;
+
+ 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);
+ DBG1(DBG_CFG, "removed stale TNC PEP RADIUS connection");
+ entry->method = method;
+ 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;
+ 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_method, eap_method_t*,
+ private_tnc_pdp_connections_t *this, chunk_t nas_id, chunk_t user_name)
+{
+ 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;
+ 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_method = _get_method,
+ .destroy = _destroy,
+ },
+ .list = linked_list_create(),
+ );
+
+ return &this->public;
+}
+
diff --git a/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.h b/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.h
new file mode 100644
index 000000000..65268971a
--- /dev/null
+++ b/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.h
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+/**
+ * @defgroup tnc_pdp_connections tnc_pdp_connections
+ * @{ @ingroup tnc_pdp
+ */
+
+#ifndef TNC_PDP_CONNECTIONS_H_
+#define TNC_PDP_CONNECTIONS_H_
+
+typedef struct tnc_pdp_connections_t tnc_pdp_connections_t;
+
+#include <library.h>
+#include <sa/authenticators/eap/eap_method.h>
+
+/**
+ * Public interface of a tnc_pdp_connections object
+ */
+struct tnc_pdp_connections_t {
+
+ /**
+ * Register a new TNC PEP RADIUS Connection
+ *
+ * @param nas_id NAS identifier of Policy Enforcement Point
+ * @param user_name User name of TNC Client
+ * @param method EAP method state for this TNC PEP Connection
+ */
+ void (*add)(tnc_pdp_connections_t *this, chunk_t nas_id, chunk_t user_name,
+ eap_method_t *method);
+
+ /**
+ * Remove a TNC PEP RADIUS Connection
+ *
+ * @param nas_id NAS identifier of Policy Enforcement Point
+ * @param user_name User name of TNC Client
+ */
+ void (*remove)(tnc_pdp_connections_t *this, chunk_t nas_id,
+ chunk_t user_name);
+
+ /**
+ * Get the EAP method of a registered TNC PEP RADIUS Connection
+ *
+ * @param nas_id NAS identifier of Policy Enforcement Point
+ * @param user_name User name of TNC Client
+ * @return EAP method for this connection or NULL if not found
+ */
+ eap_method_t* (*get_method)(tnc_pdp_connections_t *this, chunk_t nas_id,
+ chunk_t user_name);
+
+ /**
+ * Destroys a tnc_pdp_connections_t object.
+ */
+ void (*destroy)(tnc_pdp_connections_t *this);
+};
+
+/**
+ * Create a tnc_pdp_connections_t instance
+ */
+tnc_pdp_connections_t* tnc_pdp_connections_create(void);
+
+#endif /** TNC_PDP_CONNECTIONS_PLUGIN_H_ @}*/