diff options
-rw-r--r-- | src/libcharon/plugins/tnc_pdp/Makefile.am | 3 | ||||
-rw-r--r-- | src/libcharon/plugins/tnc_pdp/tnc_pdp.c | 53 | ||||
-rw-r--r-- | src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c | 202 | ||||
-rw-r--r-- | src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.h | 74 |
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_ @}*/ |