From 54b3cbdc787764892181f5880b0cc004494819db Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 12 Mar 2013 20:32:05 +0100 Subject: [PATCH] Add a radius message method to enumerate vendor specific attributes --- src/libradius/radius_message.c | 81 ++++++++++++++++++++++++++++++++++++++++++ src/libradius/radius_message.h | 11 ++++++ 2 files changed, 92 insertions(+) diff --git a/src/libradius/radius_message.c b/src/libradius/radius_message.c index 059dcda..e7717ff 100644 --- a/src/libradius/radius_message.c +++ b/src/libradius/radius_message.c @@ -16,6 +16,7 @@ #include "radius_message.h" #include +#include #include typedef struct private_radius_message_t private_radius_message_t; @@ -271,6 +272,85 @@ METHOD(radius_message_t, create_enumerator, enumerator_t*, return &e->public; } +/** + * Vendor attribute enumerator implementation + */ +typedef struct { + /** implements enumerator interface */ + enumerator_t public; + /** inner attribute enumerator */ + enumerator_t *inner; + /** current vendor ID */ + u_int32_t vendor; + /** reader for current vendor ID */ + bio_reader_t *reader; +} vendor_enumerator_t; + +METHOD(enumerator_t, vendor_enumerate, bool, + vendor_enumerator_t *this, int *vendor, int *type, chunk_t *data) +{ + chunk_t inner_data; + int inner_type; + u_int8_t type8, len; + + while (TRUE) + { + if (this->reader) + { + if (this->reader->remaining(this->reader) >= 2 && + this->reader->read_uint8(this->reader, &type8) && + this->reader->read_uint8(this->reader, &len) && len >= 2 && + this->reader->read_data(this->reader, len - 2, data)) + { + *vendor = this->vendor; + *type = type8; + return TRUE; + } + this->reader->destroy(this->reader); + this->reader = NULL; + } + if (this->inner->enumerate(this->inner, &inner_type, &inner_data)) + { + if (inner_type == RAT_VENDOR_SPECIFIC) + { + this->reader = bio_reader_create(inner_data); + if (!this->reader->read_uint32(this->reader, &this->vendor)) + { + this->reader->destroy(this->reader); + this->reader = NULL; + } + } + } + else + { + return FALSE; + } + } +} +METHOD(enumerator_t, vendor_destroy, void, + vendor_enumerator_t *this) +{ + DESTROY_IF(this->reader); + this->inner->destroy(this->inner); + free(this); +} + +METHOD(radius_message_t, create_vendor_enumerator, enumerator_t*, + private_radius_message_t *this) +{ + vendor_enumerator_t *e; + + INIT(e, + .public = { + .enumerate = (void*)_vendor_enumerate, + .destroy = _vendor_destroy, + }, + .inner = create_enumerator(this), + ); + + return &e->public; +} + METHOD(radius_message_t, add, void, private_radius_message_t *this, radius_attribute_type_t type, chunk_t data) { @@ -474,6 +554,7 @@ static private_radius_message_t *radius_message_create_empty() INIT(this, .public = { .create_enumerator = _create_enumerator, + .create_vendor_enumerator = _create_vendor_enumerator, .add = _add, .get_code = _get_code, .get_identifier = _get_identifier, diff --git a/src/libradius/radius_message.h b/src/libradius/radius_message.h index 18ec581..c493234 100644 --- a/src/libradius/radius_message.h +++ b/src/libradius/radius_message.h @@ -27,6 +27,7 @@ #define RADIUS_MESSAGE_H_ #include +#include #define MAX_RADIUS_ATTRIBUTE_SIZE 253 @@ -205,6 +206,16 @@ struct radius_message_t { enumerator_t* (*create_enumerator)(radius_message_t *this); /** + * Create an enumerator over contained RADIUS Vendor-ID attributes. + * + * This enumerator parses only vendor specific attributes in the format + * recommended in RFC2865. + * + * @return enumerator over (int vendor, int type, chunk_t data) + */ + enumerator_t* (*create_vendor_enumerator)(radius_message_t *this); + + /** * Add a RADIUS attribute to the message. * * @param type type of attribute to add -- 2.7.4