keep a list of RADIUS connections with EAP method states
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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_ @}*/
|
||||
Reference in New Issue
Block a user