aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius.c28
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius_provider.c142
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius_provider.h11
3 files changed, 176 insertions, 5 deletions
diff --git a/src/libcharon/plugins/eap_radius/eap_radius.c b/src/libcharon/plugins/eap_radius/eap_radius.c
index 28cd17eb8..62aa1fb69 100644
--- a/src/libcharon/plugins/eap_radius/eap_radius.c
+++ b/src/libcharon/plugins/eap_radius/eap_radius.c
@@ -336,12 +336,14 @@ static void process_cfg_attributes(private_eap_radius_t *this,
{
eap_radius_provider_t *provider;
enumerator_t *enumerator;
+ ike_sa_t *ike_sa;
host_t *host;
chunk_t data;
- int type;
+ int type, vendor;
+ ike_sa = charon->bus->get_sa(charon->bus);
provider = eap_radius_provider_get();
- if (provider)
+ if (provider && ike_sa)
{
enumerator = msg->create_enumerator(msg);
while (enumerator->enumerate(enumerator, &type, &data))
@@ -356,6 +358,28 @@ static void process_cfg_attributes(private_eap_radius_t *this,
}
}
enumerator->destroy(enumerator);
+
+ enumerator = msg->create_vendor_enumerator(msg);
+ while (enumerator->enumerate(enumerator, &vendor, &type, &data))
+ {
+ if (vendor == PEN_ALTIGA /* aka Cisco VPN3000 */)
+ {
+ switch (type)
+ {
+ case 15: /* CVPN3000-IPSec-Banner1 */
+ case 36: /* CVPN3000-IPSec-Banner2 */
+ if (ike_sa->supports_extension(ike_sa, EXT_CISCO_UNITY))
+ {
+ provider->add_attribute(provider, this->peer,
+ UNITY_BANNER, data);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
}
}
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_provider.c b/src/libcharon/plugins/eap_radius/eap_radius_provider.c
index 6cdbb3ca5..83fa83830 100644
--- a/src/libcharon/plugins/eap_radius/eap_radius_provider.c
+++ b/src/libcharon/plugins/eap_radius/eap_radius_provider.c
@@ -70,13 +70,34 @@ struct private_eap_radius_provider_t {
static eap_radius_provider_t *singleton = NULL;
/**
- * Hashtable entry with leases
+ * Configuration attribute in an entry
+ */
+typedef struct {
+ /** type of attribute */
+ configuration_attribute_type_t type;
+ /** attribute data */
+ chunk_t data;
+} attr_t;
+
+/**
+ * Destroy an attr_t
+ */
+static void destroy_attr(attr_t *this)
+{
+ free(this->data.ptr);
+ free(this);
+}
+
+/**
+ * Hashtable entry with leases and attributes
*/
typedef struct {
/** identity we assigned the IP lease */
identification_t *id;
/** list of IP leases received from AAA, as host_t */
linked_list_t *addrs;
+ /** list of configuration attributes, as attr_t */
+ linked_list_t *attrs;
} entry_t;
/**
@@ -86,6 +107,7 @@ static void destroy_entry(entry_t *this)
{
this->id->destroy(this->id);
this->addrs->destroy_offset(this->addrs, offsetof(host_t, destroy));
+ this->attrs->destroy_function(this->attrs, (void*)destroy_attr);
free(this);
}
@@ -102,6 +124,7 @@ static entry_t* get_or_create_entry(hashtable_t *hashtable, identification_t *id
INIT(entry,
.id = id->clone(id),
.addrs = linked_list_create(),
+ .attrs = linked_list_create(),
);
hashtable->put(hashtable, entry->id, entry);
}
@@ -113,7 +136,8 @@ static entry_t* get_or_create_entry(hashtable_t *hashtable, identification_t *id
*/
static void put_or_destroy_entry(hashtable_t *hashtable, entry_t *entry)
{
- if (entry->addrs->get_count(entry->addrs) > 0)
+ if (entry->addrs->get_count(entry->addrs) > 0 ||
+ entry->attrs->get_count(entry->attrs) > 0)
{
hashtable->put(hashtable, entry->id, entry);
}
@@ -170,6 +194,36 @@ static host_t* remove_addr(private_eap_radius_provider_t *this,
}
/**
+ * Insert an attribute entry to a locked claimed/unclaimed hashtable
+ */
+static void add_attr(private_eap_radius_provider_t *this,
+ hashtable_t *hashtable, identification_t *id, attr_t *attr)
+{
+ entry_t *entry;
+
+ entry = get_or_create_entry(hashtable, id);
+ entry->attrs->insert_last(entry->attrs, attr);
+}
+
+/**
+ * Remove the next attribute from the locked hashtable stored for given id
+ */
+static attr_t* remove_attr(private_eap_radius_provider_t *this,
+ hashtable_t *hashtable, identification_t *id)
+{
+ entry_t *entry;
+ attr_t *attr = NULL;
+
+ entry = hashtable->remove(hashtable, id);
+ if (entry)
+ {
+ entry->attrs->remove_first(entry->attrs, (void**)&attr);
+ put_or_destroy_entry(hashtable, entry);
+ }
+ return attr;
+}
+
+/**
* Clean up unclaimed leases assigned for an IKE_SA
*/
static void release_unclaimed(private_listener_t *this, ike_sa_t *ike_sa)
@@ -276,11 +330,77 @@ METHOD(attribute_provider_t, release_address, bool,
return FALSE;
}
+/**
+ * Enumerator implementation over attributes
+ */
+typedef struct {
+ /** implements enumerator_t */
+ enumerator_t public;
+ /** list of attributes to enumerate */
+ linked_list_t *list;
+ /** currently enumerating attribute */
+ attr_t *current;
+} attribute_enumerator_t;
+
+
+METHOD(enumerator_t, attribute_enumerate, bool,
+ attribute_enumerator_t *this, configuration_attribute_type_t *type,
+ chunk_t *data)
+{
+ if (this->current)
+ {
+ destroy_attr(this->current);
+ this->current = NULL;
+ }
+ if (this->list->remove_first(this->list, (void**)&this->current) == SUCCESS)
+ {
+ *type = this->current->type;
+ *data = this->current->data;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+METHOD(enumerator_t, attribute_destroy, void,
+ attribute_enumerator_t *this)
+{
+ if (this->current)
+ {
+ destroy_attr(this->current);
+ }
+ this->list->destroy_function(this->list, (void*)destroy_attr);
+ free(this);
+}
+
METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*,
private_eap_radius_provider_t *this, linked_list_t *pools,
identification_t *id, linked_list_t *vips)
{
- return enumerator_create_empty();
+ attribute_enumerator_t *enumerator;
+ attr_t *attr;
+
+ INIT(enumerator,
+ .public = {
+ .enumerate = (void*)_attribute_enumerate,
+ .destroy = _attribute_destroy,
+ },
+ .list = linked_list_create(),
+ );
+
+ /* we forward attributes regardless of pool configurations */
+ this->listener.mutex->lock(this->listener.mutex);
+ while (TRUE)
+ {
+ attr = remove_attr(this, this->listener.unclaimed, id);
+ if (!attr)
+ {
+ break;
+ }
+ enumerator->list->insert_last(enumerator->list, attr);
+ }
+ this->listener.mutex->unlock(this->listener.mutex);
+
+ return &enumerator->public;
}
METHOD(eap_radius_provider_t, add_framed_ip, void,
@@ -291,6 +411,21 @@ METHOD(eap_radius_provider_t, add_framed_ip, void,
this->listener.mutex->unlock(this->listener.mutex);
}
+METHOD(eap_radius_provider_t, add_attribute, void,
+ private_eap_radius_provider_t *this, identification_t *id,
+ configuration_attribute_type_t type, chunk_t data)
+{
+ attr_t *attr;
+
+ INIT(attr,
+ .type = type,
+ .data = chunk_clone(data),
+ );
+ this->listener.mutex->lock(this->listener.mutex);
+ add_attr(this, this->listener.unclaimed, id, attr);
+ this->listener.mutex->unlock(this->listener.mutex);
+}
+
METHOD(eap_radius_provider_t, destroy, void,
private_eap_radius_provider_t *this)
{
@@ -319,6 +454,7 @@ eap_radius_provider_t *eap_radius_provider_create()
.create_attribute_enumerator = _create_attribute_enumerator,
},
.add_framed_ip = _add_framed_ip,
+ .add_attribute = _add_attribute,
.destroy = _destroy,
},
.listener = {
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_provider.h b/src/libcharon/plugins/eap_radius/eap_radius_provider.h
index 2be9fefc2..a0b4a6b62 100644
--- a/src/libcharon/plugins/eap_radius/eap_radius_provider.h
+++ b/src/libcharon/plugins/eap_radius/eap_radius_provider.h
@@ -21,6 +21,7 @@
#ifndef EAP_RADIUS_PROVIDER_H_
#define EAP_RADIUS_PROVIDER_H_
+#include <attributes/attributes.h>
#include <attributes/attribute_provider.h>
typedef struct eap_radius_provider_t eap_radius_provider_t;
@@ -45,6 +46,16 @@ struct eap_radius_provider_t {
host_t *ip);
/**
+ * Add a configuration attribute received from RADIUS to forward.
+ *
+ * @param id client identity
+ * @param type attribute type
+ * @param data attribute data
+ */
+ void (*add_attribute)(eap_radius_provider_t *this, identification_t *id,
+ configuration_attribute_type_t type, chunk_t data);
+
+ /**
* Destroy a eap_radius_provider_t.
*/
void (*destroy)(eap_radius_provider_t *this);