diff options
Diffstat (limited to 'src/libcharon/plugins/eap_radius')
-rw-r--r-- | src/libcharon/plugins/eap_radius/Makefile.in | 3 | ||||
-rw-r--r-- | src/libcharon/plugins/eap_radius/eap_radius.c | 28 | ||||
-rw-r--r-- | src/libcharon/plugins/eap_radius/eap_radius_plugin.c | 79 | ||||
-rw-r--r-- | src/libcharon/plugins/eap_radius/radius_client.c | 21 | ||||
-rw-r--r-- | src/libcharon/plugins/eap_radius/radius_server.c | 55 | ||||
-rw-r--r-- | src/libcharon/plugins/eap_radius/radius_server.h | 18 | ||||
-rw-r--r-- | src/libcharon/plugins/eap_radius/radius_socket.c | 80 | ||||
-rw-r--r-- | src/libcharon/plugins/eap_radius/radius_socket.h | 8 |
8 files changed, 205 insertions, 87 deletions
diff --git a/src/libcharon/plugins/eap_radius/Makefile.in b/src/libcharon/plugins/eap_radius/Makefile.in index 99084e2c1..740c64055 100644 --- a/src/libcharon/plugins/eap_radius/Makefile.in +++ b/src/libcharon/plugins/eap_radius/Makefile.in @@ -245,6 +245,8 @@ nm_ca_dir = @nm_ca_dir@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ +pcsclite_CFLAGS = @pcsclite_CFLAGS@ +pcsclite_LIBS = @pcsclite_LIBS@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ @@ -268,6 +270,7 @@ soup_LIBS = @soup_LIBS@ srcdir = @srcdir@ strongswan_conf = @strongswan_conf@ sysconfdir = @sysconfdir@ +systemdsystemunitdir = @systemdsystemunitdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ diff --git a/src/libcharon/plugins/eap_radius/eap_radius.c b/src/libcharon/plugins/eap_radius/eap_radius.c index 157034fe5..dfe0e2e09 100644 --- a/src/libcharon/plugins/eap_radius/eap_radius.c +++ b/src/libcharon/plugins/eap_radius/eap_radius.c @@ -55,6 +55,11 @@ struct private_eap_radius_t { u_int32_t vendor; /** + * EAP message identifier + */ + u_int8_t identifier; + + /** * RADIUS client instance */ radius_client_t *client; @@ -107,7 +112,7 @@ static void add_eap_identity(private_eap_radius_t *this, hdr = alloca(len); hdr->code = EAP_RESPONSE; - hdr->identifier = 0; + hdr->identifier = this->identifier; hdr->length = htons(len); hdr->type = EAP_IDENTITY; memcpy(hdr->data, prefix.ptr, prefix.len); @@ -139,9 +144,12 @@ static bool radius2ike(private_eap_radius_t *this, if (message.len) { *out = payload = eap_payload_create_data(message); - free(message.ptr); + /* apply EAP method selected by RADIUS server */ this->type = payload->get_type(payload, &this->vendor); + + DBG3(DBG_IKE, "%N payload %B", eap_type_names, this->type, &message); + free(message.ptr); return TRUE; } return FALSE; @@ -284,6 +292,8 @@ METHOD(eap_method_t, process, status_t, request = radius_message_create_request(); request->add(request, RAT_USER_NAME, this->peer->get_encoding(this->peer)); data = in->get_data(in); + DBG3(DBG_IKE, "%N payload %B", eap_type_names, this->type, &data); + /* fragment data suitable for RADIUS (not more than 253 bytes) */ while (data.len > 253) { @@ -351,6 +361,18 @@ METHOD(eap_method_t, get_msk, status_t, return FAILED; } +METHOD(eap_method_t, get_identifier, u_int8_t, + private_eap_radius_t *this) +{ + return this->identifier; +} + +METHOD(eap_method_t, set_identifier, void, + private_eap_radius_t *this, u_int8_t identifier) +{ + this->identifier = identifier; +} + METHOD(eap_method_t, is_mutual, bool, private_eap_radius_t *this) { @@ -388,6 +410,8 @@ eap_radius_t *eap_radius_create(identification_t *server, identification_t *peer .get_type = _get_type, .is_mutual = _is_mutual, .get_msk = _get_msk, + .get_identifier = _get_identifier, + .set_identifier = _set_identifier, .destroy = _destroy, }, }, diff --git a/src/libcharon/plugins/eap_radius/eap_radius_plugin.c b/src/libcharon/plugins/eap_radius/eap_radius_plugin.c index 1c24d77d5..c218bd48b 100644 --- a/src/libcharon/plugins/eap_radius/eap_radius_plugin.c +++ b/src/libcharon/plugins/eap_radius/eap_radius_plugin.c @@ -20,6 +20,7 @@ #include "radius_server.h" #include <daemon.h> +#include <threading/rwlock.h> /** * Default RADIUS server port, when not configured @@ -42,6 +43,11 @@ struct private_eap_radius_plugin_t { * List of RADIUS servers */ linked_list_t *servers; + + /** + * Lock for server list + */ + rwlock_t *lock; }; /** @@ -49,20 +55,10 @@ struct private_eap_radius_plugin_t { */ static private_eap_radius_plugin_t *instance = NULL; -METHOD(plugin_t, destroy, void, - private_eap_radius_plugin_t *this) -{ - charon->eap->remove_method(charon->eap, (eap_constructor_t)eap_radius_create); - this->servers->destroy_offset(this->servers, - offsetof(radius_server_t, destroy)); - free(this); - instance = NULL; -} - /** * Load RADIUS servers from configuration */ -static bool load_servers(private_eap_radius_plugin_t *this) +static void load_servers(private_eap_radius_plugin_t *this) { enumerator_t *enumerator; radius_server_t *server; @@ -78,7 +74,7 @@ static bool load_servers(private_eap_radius_plugin_t *this) if (!secret) { DBG1(DBG_CFG, "no RADUIS secret defined"); - return FALSE; + return; } nas_identifier = lib->settings->get_str(lib->settings, "charon.plugins.eap-radius.nas_identifier", "strongSwan"); @@ -86,15 +82,15 @@ static bool load_servers(private_eap_radius_plugin_t *this) "charon.plugins.eap-radius.port", RADIUS_PORT); sockets = lib->settings->get_int(lib->settings, "charon.plugins.eap-radius.sockets", 1); - server = radius_server_create(address, port, nas_identifier, + server = radius_server_create(address, address, port, nas_identifier, secret, sockets, 0); if (!server) { DBG1(DBG_CFG, "no RADUIS server defined"); - return FALSE; + return; } this->servers->insert_last(this->servers, server); - return TRUE; + return; } enumerator = lib->settings->create_section_enumerator(lib->settings, @@ -124,7 +120,7 @@ static bool load_servers(private_eap_radius_plugin_t *this) "charon.plugins.eap-radius.servers.%s.sockets", 1, section); preference = lib->settings->get_int(lib->settings, "charon.plugins.eap-radius.servers.%s.preference", 0, section); - server = radius_server_create(address, port, nas_identifier, + server = radius_server_create(section, address, port, nas_identifier, secret, sockets, preference); if (!server) { @@ -135,14 +131,40 @@ static bool load_servers(private_eap_radius_plugin_t *this) } enumerator->destroy(enumerator); - if (this->servers->get_count(this->servers) == 0) - { - DBG1(DBG_CFG, "no valid RADIUS server configuration found"); - return FALSE; - } + DBG1(DBG_CFG, "loaded %d RADIUS server configuration%s", + this->servers->get_count(this->servers), + this->servers->get_count(this->servers) == 1 ? "" : "s"); +} + +METHOD(plugin_t, get_name, char*, + private_eap_radius_plugin_t *this) +{ + return "eap-radius"; +} + +METHOD(plugin_t, reload, bool, + private_eap_radius_plugin_t *this) +{ + this->lock->write_lock(this->lock); + this->servers->destroy_offset(this->servers, + offsetof(radius_server_t, destroy)); + this->servers = linked_list_create(); + load_servers(this); + this->lock->unlock(this->lock); return TRUE; } +METHOD(plugin_t, destroy, void, + private_eap_radius_plugin_t *this) +{ + charon->eap->remove_method(charon->eap, (eap_constructor_t)eap_radius_create); + this->servers->destroy_offset(this->servers, + offsetof(radius_server_t, destroy)); + this->lock->destroy(this->lock); + free(this); + instance = NULL; +} + /* * see header file */ @@ -153,17 +175,17 @@ plugin_t *eap_radius_plugin_create() INIT(this, .public = { .plugin = { + .get_name = _get_name, + .reload = _reload, .destroy = _destroy, }, }, .servers = linked_list_create(), + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), ); - if (!load_servers(this)) - { - destroy(this); - return NULL; - } + load_servers(this); + charon->eap->add_method(charon->eap, EAP_RADIUS, 0, EAP_SERVER, (eap_constructor_t)eap_radius_create); @@ -179,7 +201,10 @@ enumerator_t *eap_radius_create_server_enumerator() { if (instance) { - return instance->servers->create_enumerator(instance->servers); + instance->lock->read_lock(instance->lock); + return enumerator_create_cleaner( + instance->servers->create_enumerator(instance->servers), + (void*)instance->lock->unlock, instance->lock); } return enumerator_create_empty(); } diff --git a/src/libcharon/plugins/eap_radius/radius_client.c b/src/libcharon/plugins/eap_radius/radius_client.c index 232b9135e..245308e59 100644 --- a/src/libcharon/plugins/eap_radius/radius_client.c +++ b/src/libcharon/plugins/eap_radius/radius_client.c @@ -98,13 +98,14 @@ METHOD(radius_client_t, request, radius_message_t*, req->add(req, RAT_STATE, this->state); } socket = this->server->get_socket(this->server); - DBG1(DBG_CFG, "sending RADIUS %N to %#H", radius_message_code_names, - req->get_code(req), this->server->get_address(this->server)); + DBG1(DBG_CFG, "sending RADIUS %N to server '%s'", radius_message_code_names, + req->get_code(req), this->server->get_name(this->server)); res = socket->request(socket, req); if (res) { - DBG1(DBG_CFG, "received RADIUS %N from %#H", radius_message_code_names, - res->get_code(res), this->server->get_address(this->server)); + DBG1(DBG_CFG, "received RADIUS %N from server '%s'", + radius_message_code_names, res->get_code(res), + this->server->get_name(this->server)); save_state(this, res); if (res->get_code(res) == RMC_ACCESS_ACCEPT) { @@ -128,6 +129,7 @@ METHOD(radius_client_t, get_msk, chunk_t, METHOD(radius_client_t, destroy, void, private_radius_client_t *this) { + this->server->destroy(this->server); chunk_clear(&this->msk); free(this->state.ptr); free(this); @@ -159,15 +161,16 @@ radius_client_t *radius_client_create() /* for two with equal preference, 50-50 chance */ (current == best && random() % 2 == 0)) { - DBG2(DBG_CFG, "RADIUS server %H is candidate: %d", - server->get_address(server), current); + DBG2(DBG_CFG, "RADIUS server '%s' is candidate: %d", + server->get_name(server), current); best = current; - this->server = server; + DESTROY_IF(this->server); + this->server = server->get_ref(server); } else { - DBG2(DBG_CFG, "RADIUS server %H skipped: %d", - server->get_address(server), current); + DBG2(DBG_CFG, "RADIUS server '%s' skipped: %d", + server->get_name(server), current); } } enumerator->destroy(enumerator); diff --git a/src/libcharon/plugins/eap_radius/radius_server.c b/src/libcharon/plugins/eap_radius/radius_server.c index f54b8b2cd..3baf39807 100644 --- a/src/libcharon/plugins/eap_radius/radius_server.c +++ b/src/libcharon/plugins/eap_radius/radius_server.c @@ -32,11 +32,6 @@ struct private_radius_server_t { radius_server_t public; /** - * RADIUS server address - */ - host_t *host; - - /** * list of radius sockets, as radius_socket_t */ linked_list_t *sockets; @@ -57,9 +52,9 @@ struct private_radius_server_t { condvar_t *condvar; /** - * RADIUS secret + * Server name */ - chunk_t secret; + char *name; /** * NAS-Identifier @@ -80,6 +75,11 @@ struct private_radius_server_t { * Retry counter for unreachable servers */ int retry; + + /** + * reference count + */ + refcount_t ref; }; METHOD(radius_server_t, get_socket, radius_socket_t*, @@ -147,27 +147,37 @@ METHOD(radius_server_t, get_preference, int, return pref; } -METHOD(radius_server_t, get_address, host_t*, +METHOD(radius_server_t, get_name, char*, + private_radius_server_t *this) +{ + return this->name; +} + +METHOD(radius_server_t, get_ref, radius_server_t*, private_radius_server_t *this) { - return this->host; + ref_get(&this->ref); + return &this->public; } + METHOD(radius_server_t, destroy, void, private_radius_server_t *this) { - DESTROY_IF(this->host); - this->mutex->destroy(this->mutex); - this->condvar->destroy(this->condvar); - this->sockets->destroy_offset(this->sockets, - offsetof(radius_socket_t, destroy)); - free(this); + if (ref_put(&this->ref)) + { + this->mutex->destroy(this->mutex); + this->condvar->destroy(this->condvar); + this->sockets->destroy_offset(this->sockets, + offsetof(radius_socket_t, destroy)); + free(this); + } } /** * See header */ -radius_server_t *radius_server_create(char *server, u_int16_t port, +radius_server_t *radius_server_create(char *name, char *address, u_int16_t port, char *nas_identifier, char *secret, int sockets, int preference) { private_radius_server_t *this; @@ -179,7 +189,8 @@ radius_server_t *radius_server_create(char *server, u_int16_t port, .put_socket = _put_socket, .get_nas_identifier = _get_nas_identifier, .get_preference = _get_preference, - .get_address = _get_address, + .get_name = _get_name, + .get_ref = _get_ref, .destroy = _destroy, }, .reachable = TRUE, @@ -188,18 +199,14 @@ radius_server_t *radius_server_create(char *server, u_int16_t port, .sockets = linked_list_create(), .mutex = mutex_create(MUTEX_TYPE_DEFAULT), .condvar = condvar_create(CONDVAR_TYPE_DEFAULT), - .host = host_create_from_dns(server, 0, port), + .name = name, .preference = preference, + .ref = 1, ); - if (!this->host) - { - destroy(this); - return NULL; - } while (sockets--) { - socket = radius_socket_create(this->host, + socket = radius_socket_create(address, port, chunk_create(secret, strlen(secret))); if (!socket) { diff --git a/src/libcharon/plugins/eap_radius/radius_server.h b/src/libcharon/plugins/eap_radius/radius_server.h index ba4c94619..c59361c49 100644 --- a/src/libcharon/plugins/eap_radius/radius_server.h +++ b/src/libcharon/plugins/eap_radius/radius_server.h @@ -61,11 +61,18 @@ struct radius_server_t { int (*get_preference)(radius_server_t *this); /** - * Get the address of the RADIUS server. + * Get the name of the RADIUS server. * - * @return address, internal data + * @return server name */ - host_t* (*get_address)(radius_server_t *this); + char* (*get_name)(radius_server_t *this); + + /** + * Increase reference count of this server. + * + * @return this + */ + radius_server_t* (*get_ref)(radius_server_t *this); /** * Destroy a radius_server_t. @@ -76,14 +83,15 @@ struct radius_server_t { /** * Create a radius_server instance. * - * @param server server address + * @param name server name + * @param address server address * @param port server port * @param nas_identifier NAS-Identifier to use with this server * @param secret secret to use with this server * @param sockets number of sockets to create in pool * @param preference preference boost for this server */ -radius_server_t *radius_server_create(char *server, u_int16_t port, +radius_server_t *radius_server_create(char *name, char *address, u_int16_t port, char *nas_identifier, char *secret, int sockets, int preference); #endif /** RADIUS_SERVER_H_ @}*/ diff --git a/src/libcharon/plugins/eap_radius/radius_socket.c b/src/libcharon/plugins/eap_radius/radius_socket.c index f46c27ede..b3229c288 100644 --- a/src/libcharon/plugins/eap_radius/radius_socket.c +++ b/src/libcharon/plugins/eap_radius/radius_socket.c @@ -49,6 +49,16 @@ struct private_radius_socket_t { int fd; /** + * Server address + */ + char *address; + + /** + * Server port + */ + u_int16_t port; + + /** * current RADIUS identifier */ u_int8_t identifier; @@ -74,6 +84,45 @@ struct private_radius_socket_t { chunk_t secret; }; +/** + * Check or establish RADIUS connection + */ +static bool check_connection(private_radius_socket_t *this) +{ + if (this->fd == -1) + { + host_t *server; + + server = host_create_from_dns(this->address, AF_UNSPEC, this->port); + if (!server) + { + DBG1(DBG_CFG, "resolving RADIUS server address '%s' failed", + this->address); + return FALSE; + } + this->fd = socket(server->get_family(server), SOCK_DGRAM, IPPROTO_UDP); + if (this->fd == -1) + { + DBG1(DBG_CFG, "opening RADIUS socket for %#H failed: %s", + server, strerror(errno)); + server->destroy(server); + return FALSE; + } + if (connect(this->fd, server->get_sockaddr(server), + *server->get_sockaddr_len(server)) < 0) + { + DBG1(DBG_CFG, "connecting RADIUS socket to %#H failed: %s", + server, strerror(errno)); + server->destroy(server); + close(this->fd); + this->fd = -1; + return FALSE; + } + server->destroy(server); + } + return TRUE; +} + METHOD(radius_socket_t, request, radius_message_t*, private_radius_socket_t *this, radius_message_t *request) { @@ -85,6 +134,11 @@ METHOD(radius_socket_t, request, radius_message_t*, /* sign the request */ request->sign(request, this->rng, this->signer); + if (!check_connection(this)) + { + return NULL; + } + data = request->get_encoding(request); /* timeout after 2, 3, 4, 5 seconds */ for (i = 2; i <= 5; i++) @@ -257,14 +311,18 @@ METHOD(radius_socket_t, destroy, void, DESTROY_IF(this->hasher); DESTROY_IF(this->signer); DESTROY_IF(this->rng); - close(this->fd); + if (this->fd != -1) + { + close(this->fd); + } free(this); } /** * See header */ -radius_socket_t *radius_socket_create(host_t *host, chunk_t secret) +radius_socket_t *radius_socket_create(char *address, u_int16_t port, + chunk_t secret) { private_radius_socket_t *this; @@ -274,23 +332,11 @@ radius_socket_t *radius_socket_create(host_t *host, chunk_t secret) .decrypt_msk = _decrypt_msk, .destroy = _destroy, }, + .address = address, + .port = port, + .fd = -1, ); - this->fd = socket(host->get_family(host), SOCK_DGRAM, IPPROTO_UDP); - if (this->fd < 0) - { - DBG1(DBG_CFG, "opening RADIUS socket failed: %s", strerror(errno)); - free(this); - return NULL; - } - if (connect(this->fd, host->get_sockaddr(host), - *host->get_sockaddr_len(host)) < 0) - { - DBG1(DBG_CFG, "connecting RADIUS socket failed"); - close(this->fd); - free(this); - return NULL; - } this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5); this->signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_MD5_128); this->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); diff --git a/src/libcharon/plugins/eap_radius/radius_socket.h b/src/libcharon/plugins/eap_radius/radius_socket.h index fe8491a8f..2875008eb 100644 --- a/src/libcharon/plugins/eap_radius/radius_socket.h +++ b/src/libcharon/plugins/eap_radius/radius_socket.h @@ -34,7 +34,7 @@ struct radius_socket_t { /** * Send a RADIUS request, wait for response. - + * * The socket fills in RADIUS Message identifier, builds a * Request-Authenticator and calculates the Message-Authenticator * attribute. @@ -66,9 +66,11 @@ struct radius_socket_t { /** * Create a radius_socket instance. * - * @param host RADIUS server address to connect to + * @param address server name + * @param port server port * @param secret RADIUS secret */ -radius_socket_t *radius_socket_create(host_t *host, chunk_t secret); +radius_socket_t *radius_socket_create(char *address, u_int16_t port, + chunk_t secret); #endif /** RADIUS_SOCKET_H_ @}*/ |