eap-radius: Optionally send Class attributes in RADIUS accounting messages
If enabled, add the RADIUS Class attributes received in Access-Accept messages to RADIUS accounting messages as suggested by RFC 2865 section 5.25. Fixes #2451.
This commit is contained in:
@@ -13,6 +13,10 @@ charon.plugins.eap-radius.accounting_requires_vip = no
|
|||||||
If enabled, accounting is disabled unless an IKE_SA has at least one
|
If enabled, accounting is disabled unless an IKE_SA has at least one
|
||||||
virtual IP. Only for IKEv2, for IKEv1 a virtual IP is strictly necessary.
|
virtual IP. Only for IKEv2, for IKEv1 a virtual IP is strictly necessary.
|
||||||
|
|
||||||
|
charon.plugins.eap-radius.accounting_send_class = no
|
||||||
|
If enabled, adds the Class attributes received in Access-Accept message to
|
||||||
|
the RADIUS accounting messages.
|
||||||
|
|
||||||
charon.plugins.eap-radius.class_group = no
|
charon.plugins.eap-radius.class_group = no
|
||||||
Use class attributes in Access-Accept messages as group membership
|
Use class attributes in Access-Accept messages as group membership
|
||||||
information.
|
information.
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright (C) 2012-2017 Tobias Brunner
|
||||||
* Copyright (C) 2009 Martin Willi
|
* Copyright (C) 2009 Martin Willi
|
||||||
* Hochschule fuer Technik Rapperswil
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* 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
|
* under the terms of the GNU General Public License as published by the
|
||||||
@@ -271,37 +272,47 @@ METHOD(eap_method_t, initiate, status_t,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle the Class attribute as group membership information
|
* Handle the Class attribute
|
||||||
*/
|
*/
|
||||||
static void process_class(radius_message_t *msg)
|
static void process_class(radius_message_t *msg)
|
||||||
{
|
{
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
|
ike_sa_t *ike_sa;
|
||||||
|
identification_t *id;
|
||||||
|
auth_cfg_t *auth;
|
||||||
chunk_t data;
|
chunk_t data;
|
||||||
|
bool class_group, class_send;
|
||||||
int type;
|
int type;
|
||||||
|
|
||||||
|
class_group = lib->settings->get_bool(lib->settings,
|
||||||
|
"%s.plugins.eap-radius.class_group", FALSE, lib->ns);
|
||||||
|
class_send = lib->settings->get_bool(lib->settings,
|
||||||
|
"%s.plugins.eap-radius.accounting_send_class", FALSE, lib->ns);
|
||||||
|
ike_sa = charon->bus->get_sa(charon->bus);
|
||||||
|
|
||||||
|
if ((!class_group && !class_send) || !ike_sa)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
enumerator = msg->create_enumerator(msg);
|
enumerator = msg->create_enumerator(msg);
|
||||||
while (enumerator->enumerate(enumerator, &type, &data))
|
while (enumerator->enumerate(enumerator, &type, &data))
|
||||||
{
|
{
|
||||||
if (type == RAT_CLASS)
|
if (type == RAT_CLASS)
|
||||||
{
|
{
|
||||||
identification_t *id;
|
if (class_group && data.len < 44)
|
||||||
ike_sa_t *ike_sa;
|
|
||||||
auth_cfg_t *auth;
|
|
||||||
|
|
||||||
if (data.len >= 44)
|
|
||||||
{ /* quirk: ignore long class attributes, these are used for
|
{ /* quirk: ignore long class attributes, these are used for
|
||||||
* other purposes by some RADIUS servers (such as NPS). */
|
* other purposes by some RADIUS servers (such as NPS). */
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ike_sa = charon->bus->get_sa(charon->bus);
|
|
||||||
if (ike_sa)
|
|
||||||
{
|
|
||||||
auth = ike_sa->get_auth_cfg(ike_sa, FALSE);
|
auth = ike_sa->get_auth_cfg(ike_sa, FALSE);
|
||||||
id = identification_create_from_data(data);
|
id = identification_create_from_data(data);
|
||||||
DBG1(DBG_CFG, "received group membership '%Y' from RADIUS", id);
|
DBG1(DBG_CFG, "received group membership '%Y' from RADIUS",
|
||||||
|
id);
|
||||||
auth->add(auth, AUTH_RULE_GROUP, id);
|
auth->add(auth, AUTH_RULE_GROUP, id);
|
||||||
}
|
}
|
||||||
|
if (class_send)
|
||||||
|
{
|
||||||
|
eap_radius_accounting_add_class(ike_sa, data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
enumerator->destroy(enumerator);
|
enumerator->destroy(enumerator);
|
||||||
@@ -631,11 +642,7 @@ static void process_cfg_attributes(radius_message_t *msg)
|
|||||||
*/
|
*/
|
||||||
void eap_radius_process_attributes(radius_message_t *message)
|
void eap_radius_process_attributes(radius_message_t *message)
|
||||||
{
|
{
|
||||||
if (lib->settings->get_bool(lib->settings,
|
process_class(message);
|
||||||
"%s.plugins.eap-radius.class_group", FALSE, lib->ns))
|
|
||||||
{
|
|
||||||
process_class(message);
|
|
||||||
}
|
|
||||||
if (lib->settings->get_bool(lib->settings,
|
if (lib->settings->get_bool(lib->settings,
|
||||||
"%s.plugins.eap-radius.filter_id", FALSE, lib->ns))
|
"%s.plugins.eap-radius.filter_id", FALSE, lib->ns))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 Tobias Brunner
|
* Copyright (C) 2015-2017 Tobias Brunner
|
||||||
* Hochschule fuer Technik Rapperswil
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012 Martin Willi
|
* Copyright (C) 2012 Martin Willi
|
||||||
* Copyright (C) 2012 revosec AG
|
* Copyright (C) 2012 revosec AG
|
||||||
@@ -160,6 +160,8 @@ typedef struct {
|
|||||||
ike_sa_id_t *id;
|
ike_sa_id_t *id;
|
||||||
/** RADIUS accounting session ID */
|
/** RADIUS accounting session ID */
|
||||||
char sid[24];
|
char sid[24];
|
||||||
|
/** cached Class attributes */
|
||||||
|
array_t *class_attrs;
|
||||||
/** number of sent/received octets/packets for expired SAs */
|
/** number of sent/received octets/packets for expired SAs */
|
||||||
usage_t usage;
|
usage_t usage;
|
||||||
/** list of cached SAs, sa_entry_t (sorted by their unique ID) */
|
/** list of cached SAs, sa_entry_t (sorted by their unique ID) */
|
||||||
@@ -186,6 +188,7 @@ static void destroy_entry(entry_t *this)
|
|||||||
{
|
{
|
||||||
array_destroy_function(this->cached, (void*)free, NULL);
|
array_destroy_function(this->cached, (void*)free, NULL);
|
||||||
array_destroy_function(this->migrated, (void*)free, NULL);
|
array_destroy_function(this->migrated, (void*)free, NULL);
|
||||||
|
array_destroy_function(this->class_attrs, (void*)chunk_free, NULL);
|
||||||
this->id->destroy(this->id);
|
this->id->destroy(this->id);
|
||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
@@ -457,6 +460,23 @@ static void add_ike_sa_parameters(private_eap_radius_accounting_t *this,
|
|||||||
enumerator->destroy(enumerator);
|
enumerator->destroy(enumerator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the Class attributes received in the Access-Accept message to the
|
||||||
|
* RADIUS accounting message
|
||||||
|
*/
|
||||||
|
static void add_class_attributes(radius_message_t *message, entry_t *entry)
|
||||||
|
{
|
||||||
|
enumerator_t *enumerator;
|
||||||
|
chunk_t *cls;
|
||||||
|
|
||||||
|
enumerator = array_create_enumerator(entry->class_attrs);
|
||||||
|
while (enumerator->enumerate(enumerator, &cls))
|
||||||
|
{
|
||||||
|
message->add(message, RAT_CLASS, *cls);
|
||||||
|
}
|
||||||
|
enumerator->destroy(enumerator);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an existing or create a new entry from the locked session table
|
* Get an existing or create a new entry from the locked session table
|
||||||
*/
|
*/
|
||||||
@@ -585,6 +605,7 @@ static job_requeue_t send_interim(interim_data_t *data)
|
|||||||
message->add(message, RAT_ACCT_STATUS_TYPE, chunk_from_thing(value));
|
message->add(message, RAT_ACCT_STATUS_TYPE, chunk_from_thing(value));
|
||||||
message->add(message, RAT_ACCT_SESSION_ID,
|
message->add(message, RAT_ACCT_SESSION_ID,
|
||||||
chunk_create(entry->sid, strlen(entry->sid)));
|
chunk_create(entry->sid, strlen(entry->sid)));
|
||||||
|
add_class_attributes(message, entry);
|
||||||
add_ike_sa_parameters(this, message, ike_sa);
|
add_ike_sa_parameters(this, message, ike_sa);
|
||||||
|
|
||||||
value = htonl(usage.bytes.sent);
|
value = htonl(usage.bytes.sent);
|
||||||
@@ -704,6 +725,7 @@ static void send_start(private_eap_radius_accounting_t *this, ike_sa_t *ike_sa)
|
|||||||
message->add(message, RAT_ACCT_STATUS_TYPE, chunk_from_thing(value));
|
message->add(message, RAT_ACCT_STATUS_TYPE, chunk_from_thing(value));
|
||||||
message->add(message, RAT_ACCT_SESSION_ID,
|
message->add(message, RAT_ACCT_SESSION_ID,
|
||||||
chunk_create(entry->sid, strlen(entry->sid)));
|
chunk_create(entry->sid, strlen(entry->sid)));
|
||||||
|
add_class_attributes(message, entry);
|
||||||
|
|
||||||
if (!entry->interim.interval)
|
if (!entry->interim.interval)
|
||||||
{
|
{
|
||||||
@@ -766,6 +788,7 @@ static void send_stop(private_eap_radius_accounting_t *this, ike_sa_t *ike_sa)
|
|||||||
message->add(message, RAT_ACCT_STATUS_TYPE, chunk_from_thing(value));
|
message->add(message, RAT_ACCT_STATUS_TYPE, chunk_from_thing(value));
|
||||||
message->add(message, RAT_ACCT_SESSION_ID,
|
message->add(message, RAT_ACCT_SESSION_ID,
|
||||||
chunk_create(entry->sid, strlen(entry->sid)));
|
chunk_create(entry->sid, strlen(entry->sid)));
|
||||||
|
add_class_attributes(message, entry);
|
||||||
add_ike_sa_parameters(this, message, ike_sa);
|
add_ike_sa_parameters(this, message, ike_sa);
|
||||||
|
|
||||||
value = htonl(entry->usage.bytes.sent);
|
value = htonl(entry->usage.bytes.sent);
|
||||||
@@ -1064,3 +1087,24 @@ void eap_radius_accounting_start_interim(ike_sa_t *ike_sa, uint32_t interval)
|
|||||||
singleton->mutex->unlock(singleton->mutex);
|
singleton->mutex->unlock(singleton->mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Described in header
|
||||||
|
*/
|
||||||
|
void eap_radius_accounting_add_class(ike_sa_t *ike_sa, chunk_t cls)
|
||||||
|
{
|
||||||
|
if (singleton)
|
||||||
|
{
|
||||||
|
entry_t *entry;
|
||||||
|
chunk_t clone;
|
||||||
|
|
||||||
|
DBG2(DBG_CFG, "cache RADIUS Class attribute %B", &cls);
|
||||||
|
singleton->mutex->lock(singleton->mutex);
|
||||||
|
entry = get_or_create_entry(singleton, ike_sa->get_id(ike_sa),
|
||||||
|
ike_sa->get_unique_id(ike_sa));
|
||||||
|
clone = chunk_clone(cls);
|
||||||
|
array_insert_create_value(&entry->class_attrs, sizeof(chunk_t),
|
||||||
|
ARRAY_TAIL, &clone);
|
||||||
|
singleton->mutex->unlock(singleton->mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright (C) 2017 Tobias Brunner
|
||||||
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
|
*
|
||||||
* Copyright (C) 2012 Martin Willi
|
* Copyright (C) 2012 Martin Willi
|
||||||
* Copyright (C) 2012 revosec AG
|
* Copyright (C) 2012 revosec AG
|
||||||
*
|
*
|
||||||
@@ -54,4 +57,12 @@ eap_radius_accounting_t *eap_radius_accounting_create();
|
|||||||
*/
|
*/
|
||||||
void eap_radius_accounting_start_interim(ike_sa_t *ike_sa, uint32_t interval);
|
void eap_radius_accounting_start_interim(ike_sa_t *ike_sa, uint32_t interval);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a Class attribute for the given IKE_SA.
|
||||||
|
*
|
||||||
|
* @param ike_sa IKE_SA for which the attribute was received
|
||||||
|
* @param cls Class attribute value
|
||||||
|
*/
|
||||||
|
void eap_radius_accounting_add_class(ike_sa_t *ike_sa, chunk_t cls);
|
||||||
|
|
||||||
#endif /** EAP_RADIUS_ACCOUNTING_H_ @}*/
|
#endif /** EAP_RADIUS_ACCOUNTING_H_ @}*/
|
||||||
|
|||||||
Reference in New Issue
Block a user