diff options
Diffstat (limited to 'src/libcharon/plugins')
-rw-r--r-- | src/libcharon/plugins/eap_radius/Makefile.am | 1 | ||||
-rw-r--r-- | src/libcharon/plugins/eap_radius/eap_radius.c | 108 | ||||
-rw-r--r-- | src/libcharon/plugins/eap_radius/eap_radius.h | 22 | ||||
-rw-r--r-- | src/libcharon/plugins/eap_radius/eap_radius_forward.c | 3 | ||||
-rw-r--r-- | src/libcharon/plugins/eap_radius/eap_radius_plugin.c | 4 | ||||
-rw-r--r-- | src/libcharon/plugins/eap_radius/eap_radius_xauth.c | 202 | ||||
-rw-r--r-- | src/libcharon/plugins/eap_radius/eap_radius_xauth.h | 49 |
7 files changed, 333 insertions, 56 deletions
diff --git a/src/libcharon/plugins/eap_radius/Makefile.am b/src/libcharon/plugins/eap_radius/Makefile.am index 67b540407..6fdb0d099 100644 --- a/src/libcharon/plugins/eap_radius/Makefile.am +++ b/src/libcharon/plugins/eap_radius/Makefile.am @@ -17,6 +17,7 @@ endif libstrongswan_eap_radius_la_SOURCES = \ eap_radius_plugin.h eap_radius_plugin.c \ eap_radius.h eap_radius.c \ + eap_radius_xauth.h eap_radius_xauth.c \ eap_radius_accounting.h eap_radius_accounting.c \ eap_radius_provider.h eap_radius_provider.c \ eap_radius_dae.h eap_radius_dae.c \ diff --git a/src/libcharon/plugins/eap_radius/eap_radius.c b/src/libcharon/plugins/eap_radius/eap_radius.c index 1400c75a1..b06b6c392 100644 --- a/src/libcharon/plugins/eap_radius/eap_radius.c +++ b/src/libcharon/plugins/eap_radius/eap_radius.c @@ -75,21 +75,6 @@ struct private_eap_radius_t { * Prefix to prepend to EAP identity */ char *id_prefix; - - /** - * Handle the Class attribute as group membership information? - */ - bool class_group; - - /** - * Handle the Filter-Id attribute as IPsec CHILD_SA name? - */ - bool filter_id; - - /** - * Format string we use for Called/Calling-Station-Id for a host - */ - char *station_id_fmt; }; /** @@ -163,21 +148,16 @@ static bool radius2ike(private_eap_radius_t *this, } /** - * Add a set of RADIUS attributes to a request message + * See header. */ -static void add_radius_request_attrs(private_eap_radius_t *this, - radius_message_t *request) +void eap_radius_build_attributes(radius_message_t *request) { ike_sa_t *ike_sa; host_t *host; - char buf[40]; + char buf[40], *station_id_fmt;; u_int32_t value; chunk_t chunk; - chunk = chunk_from_str(this->id_prefix); - chunk = chunk_cata("cc", chunk, this->peer->get_encoding(this->peer)); - request->add(request, RAT_USER_NAME, chunk); - /* virtual NAS-Port-Type */ value = htonl(5); request->add(request, RAT_NAS_PORT_TYPE, chunk_from_thing(value)); @@ -205,13 +185,37 @@ static void add_radius_request_attrs(private_eap_radius_t *this, default: break; } - snprintf(buf, sizeof(buf), this->station_id_fmt, host); + if (lib->settings->get_bool(lib->settings, + "%s.plugins.eap-radius.station_id_with_port", + TRUE, charon->name)) + { + station_id_fmt = "%#H"; + } + else + { + station_id_fmt = "%H"; + } + snprintf(buf, sizeof(buf), station_id_fmt, host); request->add(request, RAT_CALLED_STATION_ID, chunk_from_str(buf)); host = ike_sa->get_other_host(ike_sa); - snprintf(buf, sizeof(buf), this->station_id_fmt, host); + snprintf(buf, sizeof(buf), station_id_fmt, host); request->add(request, RAT_CALLING_STATION_ID, chunk_from_str(buf)); } +} + +/** + * Add a set of RADIUS attributes to a request message + */ +static void add_radius_request_attrs(private_eap_radius_t *this, + radius_message_t *request) +{ + chunk_t chunk; + chunk = chunk_from_str(this->id_prefix); + chunk = chunk_cata("cc", chunk, this->peer->get_encoding(this->peer)); + request->add(request, RAT_USER_NAME, chunk); + + eap_radius_build_attributes(request); eap_radius_forward_from_ike(request); } @@ -268,7 +272,7 @@ METHOD(eap_method_t, initiate, status_t, /** * Handle the Class attribute as group membership information */ -static void process_class(private_eap_radius_t *this, radius_message_t *msg) +static void process_class(radius_message_t *msg) { enumerator_t *enumerator; chunk_t data; @@ -305,7 +309,7 @@ static void process_class(private_eap_radius_t *this, radius_message_t *msg) /** * Handle the Filter-Id attribute as IPsec CHILD_SA name */ -static void process_filter_id(private_eap_radius_t *this, radius_message_t *msg) +static void process_filter_id(radius_message_t *msg) { enumerator_t *enumerator; int type; @@ -361,7 +365,7 @@ static void process_filter_id(private_eap_radius_t *this, radius_message_t *msg) /** * Handle Session-Timeout attribte and Interim updates */ -static void process_timeout(private_eap_radius_t *this, radius_message_t *msg) +static void process_timeout(radius_message_t *msg) { enumerator_t *enumerator; ike_sa_t *ike_sa; @@ -390,8 +394,7 @@ static void process_timeout(private_eap_radius_t *this, radius_message_t *msg) /** * Handle Framed-IP-Address and other IKE configuration attributes */ -static void process_cfg_attributes(private_eap_radius_t *this, - radius_message_t *msg) +static void process_cfg_attributes(radius_message_t *msg) { eap_radius_provider_t *provider; enumerator_t *enumerator; @@ -444,6 +447,25 @@ static void process_cfg_attributes(private_eap_radius_t *this, } } +/** + * See header. + */ +void eap_radius_process_attributes(radius_message_t *message) +{ + if (lib->settings->get_bool(lib->settings, + "%s.plugins.eap-radius.class_group", FALSE, charon->name)) + { + process_class(message); + } + if (lib->settings->get_bool(lib->settings, + "%s.plugins.eap-radius.filter_id", FALSE, charon->name)) + { + process_filter_id(message); + } + process_timeout(message); + process_cfg_attributes(message); +} + METHOD(eap_method_t, process, status_t, private_eap_radius_t *this, eap_payload_t *in, eap_payload_t **out) { @@ -481,16 +503,7 @@ METHOD(eap_method_t, process, status_t, status = FAILED; break; case RMC_ACCESS_ACCEPT: - if (this->class_group) - { - process_class(this, response); - } - if (this->filter_id) - { - process_filter_id(this, response); - } - process_timeout(this, response); - process_cfg_attributes(this, response); + eap_radius_process_attributes(response); DBG1(DBG_IKE, "RADIUS authentication of '%Y' successful", this->peer); status = SUCCESS; @@ -591,22 +604,7 @@ eap_radius_t *eap_radius_create(identification_t *server, identification_t *peer .id_prefix = lib->settings->get_str(lib->settings, "%s.plugins.eap-radius.id_prefix", "", charon->name), - .class_group = lib->settings->get_bool(lib->settings, - "%s.plugins.eap-radius.class_group", FALSE, - charon->name), - .filter_id = lib->settings->get_bool(lib->settings, - "%s.plugins.eap-radius.filter_id", FALSE, - charon->name), ); - if (lib->settings->get_bool(lib->settings, - "%s.plugins.eap-radius.station_id_with_port", TRUE, charon->name)) - { - this->station_id_fmt = "%#H"; - } - else - { - this->station_id_fmt = "%H"; - } this->client = eap_radius_create_client(); if (!this->client) { diff --git a/src/libcharon/plugins/eap_radius/eap_radius.h b/src/libcharon/plugins/eap_radius/eap_radius.h index 875543554..ce583ac44 100644 --- a/src/libcharon/plugins/eap_radius/eap_radius.h +++ b/src/libcharon/plugins/eap_radius/eap_radius.h @@ -24,6 +24,7 @@ typedef struct eap_radius_t eap_radius_t; #include <sa/eap/eap_method.h> +#include <radius_message.h> /** * Implementation of the eap_method_t interface using a RADIUS server. @@ -45,4 +46,25 @@ struct eap_radius_t { */ eap_radius_t *eap_radius_create(identification_t *server, identification_t *peer); +/** + * Process additional attributes from an Access-Accept. + * + * Parses and applies additional authorization attributes from an Accept + * message, such as group membership information or IKE configuration + * attributes. + * + * @param message Access-Accept message to process + */ +void eap_radius_process_attributes(radius_message_t *message); + +/** + * Build additional attributes for an Access-Request. + * + * Adds additional RADIUS attributes to use with Access-Request, such as + * different NAS specific attributes. + * + * @param message Access-Request message to add attributes to + */ +void eap_radius_build_attributes(radius_message_t *message); + #endif /** EAP_RADIUS_H_ @}*/ diff --git a/src/libcharon/plugins/eap_radius/eap_radius_forward.c b/src/libcharon/plugins/eap_radius/eap_radius_forward.c index e9124877c..3e80e8918 100644 --- a/src/libcharon/plugins/eap_radius/eap_radius_forward.c +++ b/src/libcharon/plugins/eap_radius/eap_radius_forward.c @@ -248,7 +248,8 @@ static void ike2queue(message_t *message, linked_list_t *queue, enumerator = message->create_payload_enumerator(message); while (enumerator->enumerate(enumerator, &payload)) { - if (payload->get_type(payload) == NOTIFY) + if (payload->get_type(payload) == NOTIFY || + payload->get_type(payload) == NOTIFY_V1) { notify = (notify_payload_t*)payload; if (notify->get_notify_type(notify) == RADIUS_ATTRIBUTE) diff --git a/src/libcharon/plugins/eap_radius/eap_radius_plugin.c b/src/libcharon/plugins/eap_radius/eap_radius_plugin.c index 63592db06..90a4ef6de 100644 --- a/src/libcharon/plugins/eap_radius/eap_radius_plugin.c +++ b/src/libcharon/plugins/eap_radius/eap_radius_plugin.c @@ -17,6 +17,7 @@ #include "eap_radius_plugin.h" #include "eap_radius.h" +#include "eap_radius_xauth.h" #include "eap_radius_accounting.h" #include "eap_radius_dae.h" #include "eap_radius_forward.h" @@ -236,6 +237,9 @@ METHOD(plugin_t, get_features, int, PLUGIN_CALLBACK(eap_method_register, eap_radius_create), PLUGIN_PROVIDE(EAP_SERVER, EAP_RADIUS), PLUGIN_DEPENDS(CUSTOM, "eap-radius"), + PLUGIN_CALLBACK(xauth_method_register, eap_radius_xauth_create_server), + PLUGIN_PROVIDE(XAUTH_SERVER, "radius"), + PLUGIN_DEPENDS(CUSTOM, "eap-radius"), PLUGIN_CALLBACK((plugin_feature_callback_t)plugin_cb, NULL), PLUGIN_PROVIDE(CUSTOM, "eap-radius"), PLUGIN_DEPENDS(HASHER, HASH_MD5), diff --git a/src/libcharon/plugins/eap_radius/eap_radius_xauth.c b/src/libcharon/plugins/eap_radius/eap_radius_xauth.c new file mode 100644 index 000000000..bd960d2bc --- /dev/null +++ b/src/libcharon/plugins/eap_radius/eap_radius_xauth.c @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "eap_radius_xauth.h" +#include "eap_radius_plugin.h" +#include "eap_radius.h" +#include "eap_radius_forward.h" + +#include <daemon.h> +#include <radius_client.h> + + +typedef struct private_eap_radius_xauth_t private_eap_radius_xauth_t; + +/** + * Private data of an eap_radius_xauth_t object. + */ +struct private_eap_radius_xauth_t { + + /** + * Public interface. + */ + eap_radius_xauth_t public; + + /** + * ID of the server + */ + identification_t *server; + + /** + * ID of the peer + */ + identification_t *peer; + + /** + * RADIUS connection + */ + radius_client_t *client; +}; + +METHOD(xauth_method_t, initiate, status_t, + private_eap_radius_xauth_t *this, cp_payload_t **out) +{ + cp_payload_t *cp; + + cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REQUEST); + cp->add_attribute(cp, configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, chunk_empty)); + cp->add_attribute(cp, configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_PASSWORD, chunk_empty)); + *out = cp; + return NEED_MORE; +} + +/** + * Verify a password using RADIUS User-Name/User-Password attributes + */ +static status_t verify_radius(private_eap_radius_xauth_t *this, chunk_t pass) +{ + radius_message_t *request, *response; + status_t status = FAILED; + + request = radius_message_create(RMC_ACCESS_REQUEST); + request->add(request, RAT_USER_NAME, this->peer->get_encoding(this->peer)); + request->add(request, RAT_USER_PASSWORD, pass); + + eap_radius_build_attributes(request); + eap_radius_forward_from_ike(request); + + response = this->client->request(this->client, request); + if (response) + { + eap_radius_forward_to_ike(response); + switch (response->get_code(response)) + { + case RMC_ACCESS_ACCEPT: + eap_radius_process_attributes(response); + status = SUCCESS; + break; + case RMC_ACCESS_CHALLENGE: + DBG1(DBG_IKE, "RADIUS Access-Challenge not supported"); + /* FALL */ + case RMC_ACCESS_REJECT: + default: + DBG1(DBG_IKE, "RADIUS authentication of '%Y' failed", + this->peer); + break; + } + response->destroy(response); + } + else + { + eap_radius_handle_timeout(NULL); + } + request->destroy(request); + return status; +} + +METHOD(xauth_method_t, process, status_t, + private_eap_radius_xauth_t *this, cp_payload_t *in, cp_payload_t **out) +{ + configuration_attribute_t *attr; + enumerator_t *enumerator; + identification_t *id; + chunk_t user = chunk_empty, pass = chunk_empty; + + enumerator = in->create_attribute_enumerator(in); + while (enumerator->enumerate(enumerator, &attr)) + { + switch (attr->get_type(attr)) + { + case XAUTH_USER_NAME: + user = attr->get_chunk(attr); + break; + case XAUTH_USER_PASSWORD: + pass = attr->get_chunk(attr); + /* trim password to any null termination. As User-Password + * uses null padding, we can't have any null in it, and some + * clients actually send null terminated strings (Android). */ + pass.len = strnlen(pass.ptr, pass.len); + break; + default: + break; + } + } + enumerator->destroy(enumerator); + + if (!user.ptr || !pass.ptr) + { + DBG1(DBG_IKE, "peer did not respond to our XAuth request"); + return FAILED; + } + if (user.len) + { + id = identification_create_from_data(user); + if (!id) + { + DBG1(DBG_IKE, "failed to parse provided XAuth username"); + return FAILED; + } + this->peer->destroy(this->peer); + this->peer = id; + } + return verify_radius(this, pass); +} + +METHOD(xauth_method_t, get_identity, identification_t*, + private_eap_radius_xauth_t *this) +{ + return this->peer; +} + +METHOD(xauth_method_t, destroy, void, + private_eap_radius_xauth_t *this) +{ + DESTROY_IF(this->client); + this->server->destroy(this->server); + this->peer->destroy(this->peer); + free(this); +} + +/* + * Described in header. + */ +eap_radius_xauth_t *eap_radius_xauth_create_server(identification_t *server, + identification_t *peer) +{ + private_eap_radius_xauth_t *this; + + INIT(this, + .public = { + .xauth_method = { + .initiate = _initiate, + .process = _process, + .get_identity = _get_identity, + .destroy = _destroy, + }, + }, + .server = server->clone(server), + .peer = peer->clone(peer), + .client = eap_radius_create_client(), + ); + + if (!this->client) + { + destroy(this); + return NULL; + } + return &this->public; +} diff --git a/src/libcharon/plugins/eap_radius/eap_radius_xauth.h b/src/libcharon/plugins/eap_radius/eap_radius_xauth.h new file mode 100644 index 000000000..8571bbc9f --- /dev/null +++ b/src/libcharon/plugins/eap_radius/eap_radius_xauth.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup eap_radius_xauth eap_radius_xauth + * @{ @ingroup eap_radius + */ + +#ifndef EAP_RADIUS_XAUTH_H_ +#define EAP_RADIUS_XAUTH_H_ + +#include <sa/xauth/xauth_method.h> + +typedef struct eap_radius_xauth_t eap_radius_xauth_t; + +/** + * XAuth backend using plain RADIUS authentication (no EAP involved). + */ +struct eap_radius_xauth_t { + + /** + * Implements XAuth module interface + */ + xauth_method_t xauth_method; +}; + +/** + * Creates the RADIUS XAuth method, acting as server. + * + * @param server ID of the XAuth server + * @param peer ID of the XAuth client + * @return xauth_generic_t object + */ +eap_radius_xauth_t *eap_radius_xauth_create_server(identification_t *server, + identification_t *peer); + +#endif /** EAP_RADIUS_XAUTH_H_ @}*/ |