eap-radius: Optionally send Class attributes in RADIUS accounting messages
authorTobias Brunner <tobias@strongswan.org>
Mon, 23 Oct 2017 10:08:17 +0000 (12:08 +0200)
committerTobias Brunner <tobias@strongswan.org>
Thu, 2 Nov 2017 08:57:05 +0000 (09:57 +0100)
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.

conf/plugins/eap-radius.opt
src/libcharon/plugins/eap_radius/eap_radius.c
src/libcharon/plugins/eap_radius/eap_radius_accounting.c
src/libcharon/plugins/eap_radius/eap_radius_accounting.h

index c3668ec..f18a74c 100644 (file)
@@ -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
        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
        Use class attributes in Access-Accept messages as group membership
        information.
index a2530e6..fbbf6da 100644 (file)
@@ -1,6 +1,7 @@
 /*
+ * Copyright (C) 2012-2017 Tobias Brunner
  * 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
  * 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)
 {
        enumerator_t *enumerator;
+       ike_sa_t *ike_sa;
+       identification_t *id;
+       auth_cfg_t *auth;
        chunk_t data;
+       bool class_group, class_send;
        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);
        while (enumerator->enumerate(enumerator, &type, &data))
        {
                if (type == RAT_CLASS)
                {
-                       identification_t *id;
-                       ike_sa_t *ike_sa;
-                       auth_cfg_t *auth;
-
-                       if (data.len >= 44)
+                       if (class_group && data.len < 44)
                        {       /* quirk: ignore long class attributes, these are used for
                                 * 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);
                                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);
                        }
+                       if (class_send)
+                       {
+                               eap_radius_accounting_add_class(ike_sa, data);
+                       }
                }
        }
        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)
 {
-       if (lib->settings->get_bool(lib->settings,
-                                               "%s.plugins.eap-radius.class_group", FALSE, lib->ns))
-       {
-               process_class(message);
-       }
+       process_class(message);
        if (lib->settings->get_bool(lib->settings,
                                                "%s.plugins.eap-radius.filter_id", FALSE, lib->ns))
        {
index e1f5be0..9261149 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Copyright (C) 2015 Tobias Brunner
- * Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2015-2017 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
  *
  * Copyright (C) 2012 Martin Willi
  * Copyright (C) 2012 revosec AG
@@ -160,6 +160,8 @@ typedef struct {
        ike_sa_id_t *id;
        /** RADIUS accounting session ID */
        char sid[24];
+       /** cached Class attributes */
+       array_t *class_attrs;
        /** number of sent/received octets/packets for expired SAs */
        usage_t usage;
        /** 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->migrated, (void*)free, NULL);
+       array_destroy_function(this->class_attrs, (void*)chunk_free, NULL);
        this->id->destroy(this->id);
        free(this);
 }
@@ -458,6 +461,23 @@ static void add_ike_sa_parameters(private_eap_radius_accounting_t *this,
 }
 
 /**
+ * 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
  */
 static entry_t* get_or_create_entry(private_eap_radius_accounting_t *this,
@@ -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_SESSION_ID,
                                         chunk_create(entry->sid, strlen(entry->sid)));
+               add_class_attributes(message, entry);
                add_ike_sa_parameters(this, message, ike_sa);
 
                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_SESSION_ID,
                                 chunk_create(entry->sid, strlen(entry->sid)));
+       add_class_attributes(message, entry);
 
        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_SESSION_ID,
                                         chunk_create(entry->sid, strlen(entry->sid)));
+               add_class_attributes(message, entry);
                add_ike_sa_parameters(this, message, ike_sa);
 
                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);
        }
 }
+
+/*
+ * 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);
+       }
+}
\ No newline at end of file
index f7a19c9..dc1edcf 100644 (file)
@@ -1,4 +1,7 @@
 /*
+ * Copyright (C) 2017 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
  * Copyright (C) 2012 Martin Willi
  * 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);
 
+/**
+ * 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_ @}*/