From d90ade8f796ed8490fcebd787185df77c1f5283a Mon Sep 17 00:00:00 2001 From: Andreas Steffen Date: Tue, 13 Mar 2012 16:26:10 +0100 Subject: [PATCH] implemented RADIUS Filter-ID attribute --- src/libcharon/plugins/tnc_pdp/tnc_pdp.c | 74 +++++++++++++++++----- .../plugins/tnc_pdp/tnc_pdp_connections.c | 26 ++++++-- .../plugins/tnc_pdp/tnc_pdp_connections.h | 11 ++-- src/libradius/radius_message.h | 2 + 4 files changed, 89 insertions(+), 24 deletions(-) diff --git a/src/libcharon/plugins/tnc_pdp/tnc_pdp.c b/src/libcharon/plugins/tnc_pdp/tnc_pdp.c index db1f4c7..1beeb8d 100644 --- a/src/libcharon/plugins/tnc_pdp/tnc_pdp.c +++ b/src/libcharon/plugins/tnc_pdp/tnc_pdp.c @@ -181,10 +181,12 @@ static void send_message(private_tnc_pdp_t *this, radius_message_t *message, */ static void send_response(private_tnc_pdp_t *this, radius_message_t *request, radius_message_code_t code, - eap_payload_t *eap, host_t *client) + eap_payload_t *eap, identification_t *group, + host_t *client) { radius_message_t *response; chunk_t data; + u_int32_t tunnel_type; response = radius_message_create(code); if (eap) @@ -201,6 +203,14 @@ static void send_response(private_tnc_pdp_t *this, } response->add(response, RAT_EAP_MESSAGE, data); } + if (group) + { + tunnel_type = RADIUS_TUNNEL_TYPE_ESP; + htoun32(data.ptr, tunnel_type); + data.len = sizeof(tunnel_type); + response->add(response, RAT_TUNNEL_TYPE, data); + response->add(response, RAT_FILTER_ID, group->get_encoding(group)); + } response->set_identifier(response, request->get_identifier(request)); response->sign(response, request->get_authenticator(request), this->secret, this->hasher, this->signer, NULL, TRUE); @@ -221,10 +231,11 @@ static void process_eap(private_tnc_pdp_t *this, radius_message_t *request, eap_payload_t *in, *out = NULL; eap_method_t *method; eap_type_t eap_type; + u_int32_t eap_vendor; chunk_t data, message = chunk_empty; chunk_t user_name = chunk_empty, nas_id = chunk_empty; + identification_t *group = NULL; radius_message_code_t code = RMC_ACCESS_CHALLENGE; - u_int32_t eap_vendor; int type; enumerator = request->create_enumerator(request); @@ -258,7 +269,6 @@ static void process_eap(private_tnc_pdp_t *this, radius_message_t *request, eap_type = in->get_type(in, &eap_vendor); DBG3(DBG_CFG, "%N payload %B", eap_type_names, eap_type, &message); - free(message.ptr); if (eap_type == EAP_IDENTITY) { @@ -267,30 +277,36 @@ static void process_eap(private_tnc_pdp_t *this, radius_message_t *request, if (message.len < 5) { - return; + goto end; } eap_identity = chunk_create(message.ptr + 5, message.len - 5); peer = identification_create_from_data(eap_identity); - method = charon->eap->create_instance(charon->eap, this->type, 0, EAP_SERVER, this->server, peer); - peer->destroy(peer); if (!method) { - in->destroy(in); - return; + peer->destroy(peer); + goto end; } - this->connections->add(this->connections, nas_id, user_name, method); + this->connections->add(this->connections, nas_id, user_name, peer, + method); method->initiate(method, &out); } else { - method = this->connections->get_method(this->connections, nas_id, - user_name); + ike_sa_t *ike_sa; + auth_cfg_t *auth; + auth_rule_t type; + identification_t *data; + enumerator_t *e; + + method = this->connections->get_state(this->connections, nas_id, + user_name, &ike_sa); if (!method) { - return; + goto end; } + charon->bus->set_sa(charon->bus, ike_sa); switch (method->process(method, in, &out)) { @@ -299,6 +315,19 @@ static void process_eap(private_tnc_pdp_t *this, radius_message_t *request, break; case SUCCESS: code = RMC_ACCESS_ACCEPT; + + auth = ike_sa->get_auth_cfg(ike_sa, FALSE); + e = auth->create_enumerator(auth); + while (e->enumerate(e, &type, &data)) + { + /* look for group memberships */ + if (type == AUTH_RULE_GROUP) + { + group = data; + } + } + e->destroy(e); + DESTROY_IF(out); out = eap_payload_create_code(EAP_SUCCESS, in->get_identifier(in)); @@ -310,16 +339,20 @@ static void process_eap(private_tnc_pdp_t *this, radius_message_t *request, out = eap_payload_create_code(EAP_FAILURE, in->get_identifier(in)); } + charon->bus->set_sa(charon->bus, NULL); } + send_response(this, request, code, out, group, source); + out->destroy(out); + 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); +end: + free(message.ptr); in->destroy(in); - out->destroy(out); } } @@ -452,13 +485,12 @@ METHOD(tnc_pdp_t, destroy, void, tnc_pdp_t *tnc_pdp_create(u_int16_t port) { private_tnc_pdp_t *this; - char *secret, *server; + char *secret, *server, *eap_type_str; INIT(this, .public = { .destroy = _destroy, }, - .type = EAP_TTLS, .ipv4 = open_socket(this, AF_INET, port), .ipv6 = open_socket(this, AF_INET6, port), .hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5), @@ -507,6 +539,16 @@ tnc_pdp_t *tnc_pdp_create(u_int16_t port) this->secret = chunk_create(secret, strlen(secret)); this->signer->set_key(this->signer, this->secret); + eap_type_str = lib->settings->get_str(lib->settings, + "charon.plugins.tnc-pdp.method", "ttls"); + this->type = eap_type_from_string(eap_type_str); + if (this->type == 0) + { + DBG1(DBG_CFG, "unrecognized eap method \"%s\"", eap_type_str); + destroy(this); + return NULL; + } + DBG1(DBG_IKE, "eap method %N selected", eap_type_names, this->type); this->job = callback_job_create_with_prio((callback_job_cb_t)receive, this, NULL, NULL, JOB_PRIO_CRITICAL); diff --git a/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c b/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c index 0271840..175a57a 100644 --- a/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c +++ b/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c @@ -56,6 +56,11 @@ struct entry_t { * EAP method state */ eap_method_t *method; + + /** + * IKE SA used for bus communication + */ + ike_sa_t *ike_sa; }; /** @@ -64,6 +69,7 @@ struct entry_t { static void free_entry(entry_t *this) { this->method->destroy(this->method); + this->ike_sa->destroy(this->ike_sa); free(this->nas_id.ptr); free(this->user_name.ptr); free(this); @@ -100,12 +106,19 @@ static void dbg_nas_user(chunk_t nas_id, chunk_t user_name, bool not, char *op) 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) + identification_t *peer, eap_method_t *method) { enumerator_t *enumerator; entry_t *entry; + ike_sa_id_t *ike_sa_id; + ike_sa_t *ike_sa; bool found = FALSE; + ike_sa_id = ike_sa_id_create(0, 0, FALSE); + ike_sa = ike_sa_create(ike_sa_id); + ike_sa_id->destroy(ike_sa_id); + ike_sa->set_other_id(ike_sa, peer); + enumerator = this->list->create_enumerator(this->list); while (enumerator->enumerate(enumerator, &entry)) { @@ -113,8 +126,10 @@ METHOD(tnc_pdp_connections_t, add, void, { found = TRUE; entry->method->destroy(entry->method); + entry->ike_sa->destroy(entry->ike_sa); DBG1(DBG_CFG, "removed stale RADIUS connection"); entry->method = method; + entry->ike_sa = ike_sa; break; } } @@ -126,6 +141,7 @@ METHOD(tnc_pdp_connections_t, add, void, entry->nas_id = chunk_clone(nas_id); entry->user_name = chunk_clone(user_name); entry->method = method; + entry->ike_sa = ike_sa; this->list->insert_last(this->list, entry); } dbg_nas_user(nas_id, user_name, FALSE, "created"); @@ -151,8 +167,9 @@ METHOD(tnc_pdp_connections_t, remove_, void, 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) +METHOD(tnc_pdp_connections_t, get_state, eap_method_t*, + private_tnc_pdp_connections_t *this, chunk_t nas_id, chunk_t user_name, + ike_sa_t **ike_sa) { enumerator_t *enumerator; entry_t *entry; @@ -164,6 +181,7 @@ METHOD(tnc_pdp_connections_t, get_method, eap_method_t*, if (equals_entry(entry, nas_id, user_name)) { found = entry->method; + *ike_sa = entry->ike_sa; break; } } @@ -191,7 +209,7 @@ tnc_pdp_connections_t *tnc_pdp_connections_create(void) .public = { .add = _add, .remove = _remove_, - .get_method = _get_method, + .get_state = _get_state, .destroy = _destroy, }, .list = linked_list_create(), diff --git a/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.h b/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.h index 6526897..b9f5d09 100644 --- a/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.h +++ b/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.h @@ -24,6 +24,7 @@ typedef struct tnc_pdp_connections_t tnc_pdp_connections_t; #include +#include #include /** @@ -36,10 +37,11 @@ struct tnc_pdp_connections_t { * * @param nas_id NAS identifier of Policy Enforcement Point * @param user_name User name of TNC Client + * @param peer Peer identity * @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); + identification_t *peer, eap_method_t *method); /** * Remove a TNC PEP RADIUS Connection @@ -51,14 +53,15 @@ struct tnc_pdp_connections_t { chunk_t user_name); /** - * Get the EAP method of a registered TNC PEP RADIUS Connection + * Get the EAP method and IKE_SA of a registered TNC PEP RADIUS Connection * * @param nas_id NAS identifier of Policy Enforcement Point * @param user_name User name of TNC Client + * @param ike_sa IKE_SA used for bus communication only * @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); + eap_method_t* (*get_state)(tnc_pdp_connections_t *this, chunk_t nas_id, + chunk_t user_name, ike_sa_t **ike_sa); /** * Destroys a tnc_pdp_connections_t object. diff --git a/src/libradius/radius_message.h b/src/libradius/radius_message.h index 55cb484..90698ae 100644 --- a/src/libradius/radius_message.h +++ b/src/libradius/radius_message.h @@ -30,6 +30,8 @@ #define MAX_RADIUS_ATTRIBUTE_SIZE 253 +#define RADIUS_TUNNEL_TYPE_ESP 9 + typedef struct radius_message_t radius_message_t; typedef enum radius_message_code_t radius_message_code_t; typedef enum radius_attribute_type_t radius_attribute_type_t; -- 2.7.4