summaryrefslogtreecommitdiff
path: root/src/libcharon/plugins/eap_radius
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/plugins/eap_radius')
-rw-r--r--src/libcharon/plugins/eap_radius/Makefile.in3
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius.c28
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius_plugin.c79
-rw-r--r--src/libcharon/plugins/eap_radius/radius_client.c21
-rw-r--r--src/libcharon/plugins/eap_radius/radius_server.c55
-rw-r--r--src/libcharon/plugins/eap_radius/radius_server.h18
-rw-r--r--src/libcharon/plugins/eap_radius/radius_socket.c80
-rw-r--r--src/libcharon/plugins/eap_radius/radius_socket.h8
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_ @}*/