keep a list of RADIUS connections with EAP method states

This commit is contained in:
Andreas Steffen
2012-03-13 16:27:17 +01:00
parent 595f44e9a3
commit 70b2bfa5cb
4 changed files with 320 additions and 12 deletions
+2 -1
View File
@@ -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
+42 -11
View File
@@ -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)
@@ -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;
}
@@ -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_ @}*/