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
|
endif
|
||||||
|
|
||||||
libstrongswan_tnc_pdp_la_SOURCES = \
|
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
|
libstrongswan_tnc_pdp_la_LDFLAGS = -module -avoid-version
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "tnc_pdp.h"
|
#include "tnc_pdp.h"
|
||||||
|
#include "tnc_pdp_connections.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@@ -84,9 +85,9 @@ struct private_tnc_pdp_t {
|
|||||||
signer_t *signer;
|
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)
|
while (data.len > MAX_RADIUS_ATTRIBUTE_SIZE)
|
||||||
{
|
{
|
||||||
response->add(response, RAT_EAP_MESSAGE,
|
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);
|
data = chunk_skip(data, MAX_RADIUS_ATTRIBUTE_SIZE);
|
||||||
}
|
}
|
||||||
response->add(response, RAT_EAP_MESSAGE, data);
|
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,
|
DBG1(DBG_CFG, "sending RADIUS %N to client '%H'", radius_message_code_names,
|
||||||
code, client);
|
code, client);
|
||||||
send_message(this, response, 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;
|
enumerator_t *enumerator;
|
||||||
eap_payload_t *in, *out = NULL;
|
eap_payload_t *in, *out = NULL;
|
||||||
|
eap_method_t *method;
|
||||||
eap_type_t eap_type;
|
eap_type_t eap_type;
|
||||||
chunk_t data, message = chunk_empty;
|
chunk_t data, message = chunk_empty;
|
||||||
|
chunk_t user_name = chunk_empty, nas_id = chunk_empty;
|
||||||
radius_message_code_t code = RMC_ACCESS_CHALLENGE;
|
radius_message_code_t code = RMC_ACCESS_CHALLENGE;
|
||||||
u_int32_t eap_vendor;
|
u_int32_t eap_vendor;
|
||||||
int type;
|
int type;
|
||||||
@@ -226,9 +230,22 @@ static void process_eap(private_tnc_pdp_t *this, radius_message_t *request,
|
|||||||
enumerator = request->create_enumerator(request);
|
enumerator = request->create_enumerator(request);
|
||||||
while (enumerator->enumerate(enumerator, &type, &data))
|
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);
|
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);
|
eap_identity = chunk_create(message.ptr + 5, message.len - 5);
|
||||||
peer = identification_create_from_data(eap_identity);
|
peer = identification_create_from_data(eap_identity);
|
||||||
|
|
||||||
this->method = charon->eap->create_instance(charon->eap, this->type,
|
method = charon->eap->create_instance(charon->eap, this->type,
|
||||||
0, EAP_SERVER, this->server, peer);
|
0, EAP_SERVER, this->server, peer);
|
||||||
peer->destroy(peer);
|
peer->destroy(peer);
|
||||||
if (!this->method)
|
if (!method)
|
||||||
{
|
{
|
||||||
in->destroy(in);
|
in->destroy(in);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this->method->initiate(this->method, &out);
|
this->connections->add(this->connections, nas_id, user_name, method);
|
||||||
|
method->initiate(method, &out);
|
||||||
}
|
}
|
||||||
else
|
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:
|
case NEED_MORE:
|
||||||
code = RMC_ACCESS_CHALLENGE;
|
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);
|
send_response(this, request, code, out, source);
|
||||||
in->destroy(in);
|
in->destroy(in);
|
||||||
out->destroy(out);
|
out->destroy(out);
|
||||||
@@ -412,7 +442,7 @@ METHOD(tnc_pdp_t, destroy, void,
|
|||||||
DESTROY_IF(this->server);
|
DESTROY_IF(this->server);
|
||||||
DESTROY_IF(this->signer);
|
DESTROY_IF(this->signer);
|
||||||
DESTROY_IF(this->hasher);
|
DESTROY_IF(this->hasher);
|
||||||
DESTROY_IF(this->method);
|
DESTROY_IF(this->connections);
|
||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -433,6 +463,7 @@ tnc_pdp_t *tnc_pdp_create(u_int16_t port)
|
|||||||
.ipv6 = open_socket(this, AF_INET6, port),
|
.ipv6 = open_socket(this, AF_INET6, port),
|
||||||
.hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5),
|
.hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5),
|
||||||
.signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_MD5_128),
|
.signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_MD5_128),
|
||||||
|
.connections = tnc_pdp_connections_create(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!this->ipv4 && !this->ipv6)
|
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