summaryrefslogtreecommitdiff
path: root/src/libcharon/plugins/eap_radius
diff options
context:
space:
mode:
authorYves-Alexis Perez <corsac@corsac.net>2012-06-28 21:16:07 +0200
committerYves-Alexis Perez <corsac@corsac.net>2012-06-28 21:16:07 +0200
commitb34738ed08c2227300d554b139e2495ca5da97d6 (patch)
tree62f33b52820f2e49f0e53c0f8c636312037c8054 /src/libcharon/plugins/eap_radius
parent0a9d51a49042a68daa15b0c74a2b7f152f52606b (diff)
downloadvyos-strongswan-b34738ed08c2227300d554b139e2495ca5da97d6.tar.gz
vyos-strongswan-b34738ed08c2227300d554b139e2495ca5da97d6.zip
Imported Upstream version 4.6.4
Diffstat (limited to 'src/libcharon/plugins/eap_radius')
-rw-r--r--src/libcharon/plugins/eap_radius/Makefile.am10
-rw-r--r--src/libcharon/plugins/eap_radius/Makefile.in31
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius.c61
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius_accounting.c339
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius_accounting.h49
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius_dae.c543
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius_dae.h44
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius_forward.c458
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius_forward.h65
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius_plugin.c177
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius_plugin.h9
-rw-r--r--src/libcharon/plugins/eap_radius/radius_client.c186
-rw-r--r--src/libcharon/plugins/eap_radius/radius_client.h66
-rw-r--r--src/libcharon/plugins/eap_radius/radius_message.c457
-rw-r--r--src/libcharon/plugins/eap_radius/radius_message.h276
-rw-r--r--src/libcharon/plugins/eap_radius/radius_server.c219
-rw-r--r--src/libcharon/plugins/eap_radius/radius_server.h97
-rw-r--r--src/libcharon/plugins/eap_radius/radius_socket.c355
-rw-r--r--src/libcharon/plugins/eap_radius/radius_socket.h76
19 files changed, 1710 insertions, 1808 deletions
diff --git a/src/libcharon/plugins/eap_radius/Makefile.am b/src/libcharon/plugins/eap_radius/Makefile.am
index afc50bced..181497ab5 100644
--- a/src/libcharon/plugins/eap_radius/Makefile.am
+++ b/src/libcharon/plugins/eap_radius/Makefile.am
@@ -1,21 +1,21 @@
INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \
- -I$(top_srcdir)/src/libcharon
+ -I$(top_srcdir)/src/libcharon -I$(top_srcdir)/src/libradius
AM_CFLAGS = -rdynamic
if MONOLITHIC
noinst_LTLIBRARIES = libstrongswan-eap-radius.la
else
+libstrongswan_eap_radius_la_LIBADD = $(top_builddir)/src/libradius/libradius.la
plugin_LTLIBRARIES = libstrongswan-eap-radius.la
endif
libstrongswan_eap_radius_la_SOURCES = \
eap_radius_plugin.h eap_radius_plugin.c \
eap_radius.h eap_radius.c \
- radius_server.h radius_server.c \
- radius_socket.h radius_socket.c \
- radius_client.h radius_client.c \
- radius_message.h radius_message.c
+ eap_radius_accounting.h eap_radius_accounting.c \
+ eap_radius_dae.h eap_radius_dae.c \
+ eap_radius_forward.h eap_radius_forward.c
libstrongswan_eap_radius_la_LDFLAGS = -module -avoid-version
diff --git a/src/libcharon/plugins/eap_radius/Makefile.in b/src/libcharon/plugins/eap_radius/Makefile.in
index 740c64055..0bef44042 100644
--- a/src/libcharon/plugins/eap_radius/Makefile.in
+++ b/src/libcharon/plugins/eap_radius/Makefile.in
@@ -74,10 +74,11 @@ am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
am__installdirs = "$(DESTDIR)$(plugindir)"
LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES)
-libstrongswan_eap_radius_la_LIBADD =
+@MONOLITHIC_FALSE@libstrongswan_eap_radius_la_DEPENDENCIES = \
+@MONOLITHIC_FALSE@ $(top_builddir)/src/libradius/libradius.la
am_libstrongswan_eap_radius_la_OBJECTS = eap_radius_plugin.lo \
- eap_radius.lo radius_server.lo radius_socket.lo \
- radius_client.lo radius_message.lo
+ eap_radius.lo eap_radius_accounting.lo eap_radius_dae.lo \
+ eap_radius_forward.lo
libstrongswan_eap_radius_la_OBJECTS = \
$(am_libstrongswan_eap_radius_la_OBJECTS)
libstrongswan_eap_radius_la_LINK = $(LIBTOOL) --tag=CC \
@@ -196,6 +197,9 @@ am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
+attest_plugins = @attest_plugins@
+axis2c_CFLAGS = @axis2c_CFLAGS@
+axis2c_LIBS = @axis2c_LIBS@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
@@ -204,6 +208,7 @@ build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
c_plugins = @c_plugins@
+clearsilver_LIBS = @clearsilver_LIBS@
datadir = @datadir@
datarootdir = @datarootdir@
dbusservicedir = @dbusservicedir@
@@ -220,11 +225,13 @@ host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
+imcvdir = @imcvdir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
ipsecdir = @ipsecdir@
ipsecgroup = @ipsecgroup@
+ipseclibdir = @ipseclibdir@
ipsecuser = @ipsecuser@
libcharon_plugins = @libcharon_plugins@
libdir = @libdir@
@@ -268,6 +275,7 @@ sharedstatedir = @sharedstatedir@
soup_CFLAGS = @soup_CFLAGS@
soup_LIBS = @soup_LIBS@
srcdir = @srcdir@
+starter_plugins = @starter_plugins@
strongswan_conf = @strongswan_conf@
sysconfdir = @sysconfdir@
systemdsystemunitdir = @systemdsystemunitdir@
@@ -279,18 +287,18 @@ urandom_device = @urandom_device@
xml_CFLAGS = @xml_CFLAGS@
xml_LIBS = @xml_LIBS@
INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \
- -I$(top_srcdir)/src/libcharon
+ -I$(top_srcdir)/src/libcharon -I$(top_srcdir)/src/libradius
AM_CFLAGS = -rdynamic
@MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-eap-radius.la
+@MONOLITHIC_FALSE@libstrongswan_eap_radius_la_LIBADD = $(top_builddir)/src/libradius/libradius.la
@MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-eap-radius.la
libstrongswan_eap_radius_la_SOURCES = \
eap_radius_plugin.h eap_radius_plugin.c \
eap_radius.h eap_radius.c \
- radius_server.h radius_server.c \
- radius_socket.h radius_socket.c \
- radius_client.h radius_client.c \
- radius_message.h radius_message.c
+ eap_radius_accounting.h eap_radius_accounting.c \
+ eap_radius_dae.h eap_radius_dae.c \
+ eap_radius_forward.h eap_radius_forward.c
libstrongswan_eap_radius_la_LDFLAGS = -module -avoid-version
all: all-am
@@ -377,11 +385,10 @@ distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_radius.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_radius_accounting.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_radius_dae.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_radius_forward.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_radius_plugin.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radius_client.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radius_message.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radius_server.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radius_socket.Plo@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
diff --git a/src/libcharon/plugins/eap_radius/eap_radius.c b/src/libcharon/plugins/eap_radius/eap_radius.c
index dfe0e2e09..c0a3703b6 100644
--- a/src/libcharon/plugins/eap_radius/eap_radius.c
+++ b/src/libcharon/plugins/eap_radius/eap_radius.c
@@ -14,14 +14,14 @@
*/
#include "eap_radius.h"
+#include "eap_radius_plugin.h"
+#include "eap_radius_forward.h"
-#include "radius_message.h"
-#include "radius_client.h"
+#include <radius_message.h>
+#include <radius_client.h>
#include <daemon.h>
-#define TUNNEL_TYPE_ESP 9
-
typedef struct private_eap_radius_t private_eap_radius_t;
/**
@@ -162,7 +162,7 @@ METHOD(eap_method_t, initiate, status_t,
status_t status = FAILED;
chunk_t username;
- request = radius_message_create_request();
+ request = radius_message_create(RMC_ACCESS_REQUEST);
username = chunk_create(this->id_prefix, strlen(this->id_prefix));
username = chunk_cata("cc", username, this->peer->get_encoding(this->peer));
request->add(request, RAT_USER_NAME, username);
@@ -175,16 +175,22 @@ METHOD(eap_method_t, initiate, status_t,
{
add_eap_identity(this, request);
}
+ eap_radius_forward_from_ike(request);
response = this->client->request(this->client, request);
if (response)
{
+ eap_radius_forward_to_ike(response);
if (radius2ike(this, response, out))
{
status = NEED_MORE;
}
response->destroy(response);
}
+ else
+ {
+ charon->bus->alert(charon->bus, ALERT_RADIUS_NOT_RESPONDING);
+ }
request->destroy(request);
return status;
}
@@ -253,7 +259,7 @@ static void process_filter_id(private_eap_radius_t *this, radius_message_t *msg)
tunnel_type = untoh32(data.ptr);
DBG1(DBG_IKE, "received RADIUS attribute Tunnel-Type: "
"tag = %u, value = %u", tunnel_tag, tunnel_type);
- is_esp_tunnel = (tunnel_type == TUNNEL_TYPE_ESP);
+ is_esp_tunnel = (tunnel_type == RADIUS_TUNNEL_TYPE_ESP);
break;
case RAT_FILTER_ID:
filter_id = data;
@@ -282,6 +288,31 @@ static void process_filter_id(private_eap_radius_t *this, radius_message_t *msg)
}
}
+/**
+ * Handle Session-Timeout attribte
+ */
+static void process_timeout(private_eap_radius_t *this, radius_message_t *msg)
+{
+ enumerator_t *enumerator;
+ ike_sa_t *ike_sa;
+ chunk_t data;
+ int type;
+
+ enumerator = msg->create_enumerator(msg);
+ while (enumerator->enumerate(enumerator, &type, &data))
+ {
+ if (type == RAT_SESSION_TIMEOUT && data.len == 4)
+ {
+ ike_sa = charon->bus->get_sa(charon->bus);
+ if (ike_sa)
+ {
+ ike_sa->set_auth_lifetime(ike_sa, untoh32(data.ptr));
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
METHOD(eap_method_t, process, status_t,
private_eap_radius_t *this, eap_payload_t *in, eap_payload_t **out)
{
@@ -289,22 +320,25 @@ METHOD(eap_method_t, process, status_t,
status_t status = FAILED;
chunk_t data;
- request = radius_message_create_request();
+ request = radius_message_create(RMC_ACCESS_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)
+
+ /* fragment data suitable for RADIUS */
+ while (data.len > MAX_RADIUS_ATTRIBUTE_SIZE)
{
- request->add(request, RAT_EAP_MESSAGE, chunk_create(data.ptr, 253));
- data = chunk_skip(data, 253);
+ request->add(request, RAT_EAP_MESSAGE,
+ chunk_create(data.ptr,MAX_RADIUS_ATTRIBUTE_SIZE));
+ data = chunk_skip(data, MAX_RADIUS_ATTRIBUTE_SIZE);
}
request->add(request, RAT_EAP_MESSAGE, data);
+ 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_CHALLENGE:
@@ -324,6 +358,7 @@ METHOD(eap_method_t, process, status_t,
{
process_filter_id(this, response);
}
+ process_timeout(this, response);
DBG1(DBG_IKE, "RADIUS authentication of '%Y' successful",
this->peer);
status = SUCCESS;
@@ -427,7 +462,7 @@ eap_radius_t *eap_radius_create(identification_t *server, identification_t *peer
"charon.plugins.eap-radius.filter_id", FALSE),
);
- this->client = radius_client_create();
+ this->client = eap_radius_create_client();
if (!this->client)
{
free(this);
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_accounting.c b/src/libcharon/plugins/eap_radius/eap_radius_accounting.c
new file mode 100644
index 000000000..45be22704
--- /dev/null
+++ b/src/libcharon/plugins/eap_radius/eap_radius_accounting.c
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 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_accounting.h"
+#include "eap_radius_plugin.h"
+
+#include <time.h>
+
+#include <radius_message.h>
+#include <radius_client.h>
+#include <daemon.h>
+#include <utils/hashtable.h>
+#include <threading/mutex.h>
+
+typedef struct private_eap_radius_accounting_t private_eap_radius_accounting_t;
+
+/**
+ * Private data of an eap_radius_accounting_t object.
+ */
+struct private_eap_radius_accounting_t {
+
+ /**
+ * Public eap_radius_accounting_t interface.
+ */
+ eap_radius_accounting_t public;
+
+ /**
+ * Hashtable with sessions, IKE_SA unique id => entry_t
+ */
+ hashtable_t *sessions;
+
+ /**
+ * Mutex to lock sessions
+ */
+ mutex_t *mutex;
+
+ /**
+ * Session ID prefix
+ */
+ u_int32_t prefix;
+};
+
+/**
+ * Hashtable entry with usage stats
+ */
+typedef struct {
+ /** RADIUS accounting session ID */
+ char sid[16];
+ /** number of octets sent */
+ u_int64_t sent;
+ /** number of octets received */
+ u_int64_t received;
+ /** session creation time */
+ time_t created;
+} entry_t;
+
+/**
+ * Accounting message status types
+ */
+typedef enum {
+ ACCT_STATUS_START = 1,
+ ACCT_STATUS_STOP = 2,
+ ACCT_STATUS_INTERIM_UPDATE = 3,
+ ACCT_STATUS_ACCOUNTING_ON = 7,
+ ACCT_STATUS_ACCOUNTING_OFF = 8,
+} radius_acct_status_t;
+
+/**
+ * Hashtable hash function
+ */
+static u_int hash(uintptr_t key)
+{
+ return key;
+}
+
+/**
+ * Hashtable equals function
+ */
+static bool equals(uintptr_t a, uintptr_t b)
+{
+ return a == b;
+}
+
+/**
+ * Update usage counter when a CHILD_SA rekeys/goes down
+ */
+static void update_usage(private_eap_radius_accounting_t *this,
+ ike_sa_t *ike_sa, child_sa_t *child_sa)
+{
+ u_int64_t sent, received;
+ entry_t *entry;
+
+ child_sa->get_usestats(child_sa, FALSE, NULL, &sent);
+ child_sa->get_usestats(child_sa, TRUE, NULL, &received);
+
+ this->mutex->lock(this->mutex);
+ entry = this->sessions->get(this->sessions,
+ (void*)(uintptr_t)ike_sa->get_unique_id(ike_sa));
+ if (entry)
+ {
+ entry->sent += sent;
+ entry->received += received;
+ }
+ this->mutex->unlock(this->mutex);
+}
+
+/**
+ * Send a RADIUS message, wait for response
+ */
+static bool send_message(private_eap_radius_accounting_t *this,
+ radius_message_t *request)
+{
+ radius_message_t *response;
+ radius_client_t *client;
+ bool ack = FALSE;
+
+ client = eap_radius_create_client();
+ if (client)
+ {
+ response = client->request(client, request);
+ if (response)
+ {
+ ack = response->get_code(response) == RMC_ACCOUNTING_RESPONSE;
+ response->destroy(response);
+ }
+ else
+ {
+ charon->bus->alert(charon->bus, ALERT_RADIUS_NOT_RESPONDING);
+ }
+ client->destroy(client);
+ }
+ return ack;
+}
+
+/**
+ * Add common IKE_SA parameters to RADIUS account message
+ */
+static void add_ike_sa_parameters(radius_message_t *message, ike_sa_t *ike_sa)
+{
+ host_t *vip;
+ char buf[64];
+ chunk_t data;
+
+ snprintf(buf, sizeof(buf), "%Y", ike_sa->get_other_eap_id(ike_sa));
+ message->add(message, RAT_USER_NAME, chunk_create(buf, strlen(buf)));
+ snprintf(buf, sizeof(buf), "%#H", ike_sa->get_other_host(ike_sa));
+ message->add(message, RAT_CALLING_STATION_ID, chunk_create(buf, strlen(buf)));
+ vip = ike_sa->get_virtual_ip(ike_sa, FALSE);
+ if (vip && vip->get_family(vip) == AF_INET)
+ {
+ message->add(message, RAT_FRAMED_IP_ADDRESS, vip->get_address(vip));
+ }
+ if (vip && vip->get_family(vip) == AF_INET6)
+ {
+ /* we currently assign /128 prefixes, only (reserved, length) */
+ data = chunk_from_chars(0, 128);
+ data = chunk_cata("cc", data, vip->get_address(vip));
+ message->add(message, RAT_FRAMED_IPV6_PREFIX, data);
+ }
+}
+
+/**
+ * Send an accounting start message
+ */
+static void send_start(private_eap_radius_accounting_t *this, ike_sa_t *ike_sa)
+{
+ radius_message_t *message;
+ entry_t *entry;
+ u_int32_t id, value;
+
+ id = ike_sa->get_unique_id(ike_sa);
+ INIT(entry,
+ .created = time_monotonic(NULL),
+ );
+ snprintf(entry->sid, sizeof(entry->sid), "%u-%u", this->prefix, id);
+
+ message = radius_message_create(RMC_ACCOUNTING_REQUEST);
+ value = htonl(ACCT_STATUS_START);
+ message->add(message, RAT_ACCT_STATUS_TYPE, chunk_from_thing(value));
+ message->add(message, RAT_ACCT_SESSION_ID,
+ chunk_create(entry->sid, strlen(entry->sid)));
+ add_ike_sa_parameters(message, ike_sa);
+ if (send_message(this, message))
+ {
+ this->mutex->lock(this->mutex);
+ entry = this->sessions->put(this->sessions, (void*)(uintptr_t)id, entry);
+ this->mutex->unlock(this->mutex);
+ free(entry);
+ }
+ message->destroy(message);
+}
+
+/**
+ * Send an account stop message
+ */
+static void send_stop(private_eap_radius_accounting_t *this, ike_sa_t *ike_sa)
+{
+ radius_message_t *message;
+ entry_t *entry;
+ u_int32_t id, value;
+
+ id = ike_sa->get_unique_id(ike_sa);
+ this->mutex->lock(this->mutex);
+ entry = this->sessions->remove(this->sessions, (void*)(uintptr_t)id);
+ this->mutex->unlock(this->mutex);
+ if (entry)
+ {
+ message = radius_message_create(RMC_ACCOUNTING_REQUEST);
+ value = htonl(ACCT_STATUS_STOP);
+ message->add(message, RAT_ACCT_STATUS_TYPE, chunk_from_thing(value));
+ message->add(message, RAT_ACCT_SESSION_ID,
+ chunk_create(entry->sid, strlen(entry->sid)));
+ add_ike_sa_parameters(message, ike_sa);
+ value = htonl(entry->sent);
+ message->add(message, RAT_ACCT_OUTPUT_OCTETS, chunk_from_thing(value));
+ value = htonl(entry->sent >> 32);
+ if (value)
+ {
+ message->add(message, RAT_ACCT_OUTPUT_GIGAWORDS,
+ chunk_from_thing(value));
+ }
+ value = htonl(entry->received);
+ message->add(message, RAT_ACCT_INPUT_OCTETS, chunk_from_thing(value));
+ value = htonl(entry->received >> 32);
+ if (value)
+ {
+ message->add(message, RAT_ACCT_INPUT_GIGAWORDS,
+ chunk_from_thing(value));
+ }
+ value = htonl(time_monotonic(NULL) - entry->created);
+ message->add(message, RAT_ACCT_SESSION_TIME, chunk_from_thing(value));
+
+ send_message(this, message);
+ message->destroy(message);
+ free(entry);
+ }
+}
+
+METHOD(listener_t, ike_updown, bool,
+ private_eap_radius_accounting_t *this, ike_sa_t *ike_sa, bool up)
+{
+ if (!up)
+ {
+ enumerator_t *enumerator;
+ child_sa_t *child_sa;
+
+ /* update usage for all children just before sending stop */
+ enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
+ while (enumerator->enumerate(enumerator, &child_sa))
+ {
+ update_usage(this, ike_sa, child_sa);
+ }
+ enumerator->destroy(enumerator);
+
+ send_stop(this, ike_sa);
+ }
+ return TRUE;
+}
+
+METHOD(listener_t, message_hook, bool,
+ private_eap_radius_accounting_t *this, ike_sa_t *ike_sa,
+ message_t *message, bool incoming)
+{
+ /* start accounting here, virtual IP now is set */
+ if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
+ message->get_exchange_type(message) == IKE_AUTH &&
+ !incoming && !message->get_request(message))
+ {
+ send_start(this, ike_sa);
+ }
+ return TRUE;
+}
+
+METHOD(listener_t, child_rekey, bool,
+ private_eap_radius_accounting_t *this, ike_sa_t *ike_sa,
+ child_sa_t *old, child_sa_t *new)
+{
+ update_usage(this, ike_sa, old);
+
+ return TRUE;
+}
+
+METHOD(listener_t, child_updown, bool,
+ private_eap_radius_accounting_t *this, ike_sa_t *ike_sa,
+ child_sa_t *child_sa, bool up)
+{
+ if (!up && ike_sa->get_state(ike_sa) == IKE_ESTABLISHED)
+ {
+ update_usage(this, ike_sa, child_sa);
+ }
+ return TRUE;
+}
+
+METHOD(eap_radius_accounting_t, destroy, void,
+ private_eap_radius_accounting_t *this)
+{
+ this->mutex->destroy(this->mutex);
+ this->sessions->destroy(this->sessions);
+ free(this);
+}
+
+/**
+ * See header
+ */
+eap_radius_accounting_t *eap_radius_accounting_create()
+{
+ private_eap_radius_accounting_t *this;
+
+ INIT(this,
+ .public = {
+ .listener = {
+ .ike_updown = _ike_updown,
+ .message = _message_hook,
+ .child_updown = _child_updown,
+ .child_rekey = _child_rekey,
+ },
+ .destroy = _destroy,
+ },
+ /* use system time as Session ID prefix */
+ .prefix = (u_int32_t)time(NULL),
+ .sessions = hashtable_create((hashtable_hash_t)hash,
+ (hashtable_equals_t)equals, 32),
+ .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ );
+
+ return &this->public;
+}
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_accounting.h b/src/libcharon/plugins/eap_radius/eap_radius_accounting.h
new file mode 100644
index 000000000..811a5bb90
--- /dev/null
+++ b/src/libcharon/plugins/eap_radius/eap_radius_accounting.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 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_accounting eap_radius_accounting
+ * @{ @ingroup eap_radius
+ */
+
+#ifndef EAP_RADIUS_ACCOUNTING_H_
+#define EAP_RADIUS_ACCOUNTING_H_
+
+#include <bus/listeners/listener.h>
+
+typedef struct eap_radius_accounting_t eap_radius_accounting_t;
+
+/**
+ * RADIUS accounting for IKE/IPsec.
+ */
+struct eap_radius_accounting_t {
+
+ /**
+ * Implements listener_t.
+ */
+ listener_t listener;
+
+ /**
+ * Destroy a eap_radius_accounting_t.
+ */
+ void (*destroy)(eap_radius_accounting_t *this);
+};
+
+/**
+ * Create a eap_radius_accounting instance.
+ */
+eap_radius_accounting_t *eap_radius_accounting_create();
+
+#endif /** EAP_RADIUS_ACCOUNTING_H_ @}*/
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_dae.c b/src/libcharon/plugins/eap_radius/eap_radius_dae.c
new file mode 100644
index 000000000..e84fe5b9c
--- /dev/null
+++ b/src/libcharon/plugins/eap_radius/eap_radius_dae.c
@@ -0,0 +1,543 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 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_dae.h"
+
+#include <radius_message.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <daemon.h>
+#include <threading/thread.h>
+#include <processing/jobs/callback_job.h>
+#include <processing/jobs/delete_ike_sa_job.h>
+
+#define RADIUS_DAE_PORT 3799
+
+typedef struct private_eap_radius_dae_t private_eap_radius_dae_t;
+
+/**
+ * Private data of an eap_radius_dae_t object.
+ */
+struct private_eap_radius_dae_t {
+
+ /**
+ * Public eap_radius_dae_t interface.
+ */
+ eap_radius_dae_t public;
+
+ /**
+ * RADIUS session state
+ */
+ eap_radius_accounting_t *accounting;
+
+ /**
+ * Socket to listen on authorization extension port
+ */
+ int fd;
+
+ /**
+ * Listen job
+ */
+ callback_job_t *job;
+
+ /**
+ * RADIUS shared secret for DAE exchanges
+ */
+ chunk_t secret;
+
+ /**
+ * MD5 hasher
+ */
+ hasher_t *hasher;
+
+ /**
+ * HMAC MD5 signer, with secret set
+ */
+ signer_t *signer;
+
+ /**
+ * List of responses for retransmission, as entry_t
+ */
+ linked_list_t *responses;
+};
+
+/**
+ * Entry to store responses for retransmit
+ */
+typedef struct {
+ /** stored response */
+ radius_message_t *response;
+ /** client that sent the request */
+ host_t *client;
+} entry_t;
+
+/**
+ * Clean up an entry
+ */
+static void entry_destroy(entry_t *entry)
+{
+ entry->response->destroy(entry->response);
+ entry->client->destroy(entry->client);
+ free(entry);
+}
+
+/**
+ * Save/Replace response for retransmission
+ */
+static void save_retransmit(private_eap_radius_dae_t *this,
+ radius_message_t *response, host_t *client)
+{
+ enumerator_t *enumerator;
+ entry_t *entry;
+ bool found = FALSE;
+
+ enumerator = this->responses->create_enumerator(this->responses);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (client->equals(client, entry->client))
+ {
+ entry->response->destroy(entry->response);
+ entry->response = response;
+ found = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (!found)
+ {
+ INIT(entry,
+ .response = response,
+ .client = client->clone(client),
+ );
+ this->responses->insert_first(this->responses, entry);
+ }
+}
+
+/**
+ * Send a RADIUS message to client
+ */
+static void send_message(private_eap_radius_dae_t *this,
+ radius_message_t *message, host_t *client)
+{
+ chunk_t data;
+
+ data = message->get_encoding(message);
+ if (sendto(this->fd, data.ptr, data.len, 0, client->get_sockaddr(client),
+ *client->get_sockaddr_len(client)) != data.len)
+ {
+ DBG1(DBG_CFG, "sending RADIUS DAE response failed: %s", strerror(errno));
+ }
+}
+
+/**
+ * Check if we request is a retransmit, retransmit stored response
+ */
+static bool send_retransmit(private_eap_radius_dae_t *this,
+ radius_message_t *request, host_t *client)
+{
+ enumerator_t *enumerator;
+ entry_t *entry;
+ bool found = FALSE;
+
+ enumerator = this->responses->create_enumerator(this->responses);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (client->equals(client, entry->client) &&
+ request->get_identifier(request) ==
+ entry->response->get_identifier(entry->response))
+ {
+ DBG1(DBG_CFG, "received retransmit of RADIUS %N, retransmitting %N "
+ "to %H", radius_message_code_names, request->get_code(request),
+ radius_message_code_names,
+ entry->response->get_code(entry->response), client);
+ send_message(this, entry->response, client);
+ found = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ return found;
+}
+
+/**
+ * Send an ACK/NAK response for a request
+ */
+static void send_response(private_eap_radius_dae_t *this,
+ radius_message_t *request, radius_message_code_t code,
+ host_t *client)
+{
+ radius_message_t *response;
+
+ response = radius_message_create(code);
+ response->set_identifier(response, request->get_identifier(request));
+ response->sign(response, request->get_authenticator(request),
+ this->secret, this->hasher, this->signer, NULL, FALSE);
+
+ send_message(this, response, client);
+ save_retransmit(this, response, client);
+}
+
+/**
+ * Add all IKE_SAs matching to user to a list
+ */
+static void add_matching_ike_sas(linked_list_t *list, identification_t *user)
+{
+ enumerator_t *enumerator;
+ ike_sa_t *ike_sa;
+ ike_sa_id_t *id;
+
+ enumerator = charon->ike_sa_manager->create_enumerator(
+ charon->ike_sa_manager, FALSE);
+ while (enumerator->enumerate(enumerator, &ike_sa))
+ {
+ if (user->matches(user, ike_sa->get_other_eap_id(ike_sa)))
+ {
+ id = ike_sa->get_id(ike_sa);
+ list->insert_last(list, id->clone(id));
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
+/**
+ * Get list of IKE_SAs matching a Disconnect/CoA request
+ */
+static linked_list_t *get_matching_ike_sas(private_eap_radius_dae_t *this,
+ radius_message_t *request, host_t *client)
+{
+ enumerator_t *enumerator;
+ identification_t *user;
+ linked_list_t *ids;
+ chunk_t data;
+ int type;
+
+ ids = linked_list_create();
+
+ enumerator = request->create_enumerator(request);
+ while (enumerator->enumerate(enumerator, &type, &data))
+ {
+ if (type == RAT_USER_NAME && data.len)
+ {
+ user = identification_create_from_data(data);
+ DBG1(DBG_CFG, "received RADIUS DAE %N for %Y from %H",
+ radius_message_code_names, request->get_code(request),
+ user, client);
+ add_matching_ike_sas(ids, user);
+ user->destroy(user);
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ return ids;
+}
+
+/**
+ * Process a DAE disconnect request, send response
+ */
+static void process_disconnect(private_eap_radius_dae_t *this,
+ radius_message_t *request, host_t *client)
+{
+ enumerator_t *enumerator;
+ linked_list_t *ids;
+ ike_sa_id_t *id;
+
+ ids = get_matching_ike_sas(this, request, client);
+
+ if (ids->get_count(ids))
+ {
+ DBG1(DBG_CFG, "closing %d IKE_SA%s matching %N, sending %N",
+ ids->get_count(ids), ids->get_count(ids) > 1 ? "s" : "",
+ radius_message_code_names, RMC_DISCONNECT_REQUEST,
+ radius_message_code_names, RMC_DISCONNECT_ACK);
+
+ enumerator = ids->create_enumerator(ids);
+ while (enumerator->enumerate(enumerator, &id))
+ {
+ lib->processor->queue_job(lib->processor, (job_t*)
+ delete_ike_sa_job_create(id, TRUE));
+ }
+ enumerator->destroy(enumerator);
+
+ send_response(this, request, RMC_DISCONNECT_ACK, client);
+ }
+ else
+ {
+ DBG1(DBG_CFG, "no IKE_SA matches %N, sending %N",
+ radius_message_code_names, RMC_DISCONNECT_REQUEST,
+ radius_message_code_names, RMC_DISCONNECT_NAK);
+ send_response(this, request, RMC_DISCONNECT_NAK, client);
+ }
+ ids->destroy_offset(ids, offsetof(ike_sa_id_t, destroy));
+}
+
+/**
+ * Apply a new lifetime to an IKE_SA
+ */
+static void apply_lifetime(private_eap_radius_dae_t *this, ike_sa_id_t *id,
+ u_int32_t lifetime)
+{
+ ike_sa_t *ike_sa;
+
+ ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id);
+ if (ike_sa)
+ {
+ if (ike_sa->set_auth_lifetime(ike_sa, lifetime) == DESTROY_ME)
+ {
+ charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
+ ike_sa);
+ }
+ else
+ {
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ }
+ }
+}
+
+/**
+ * Process a DAE CoA request, send response
+ */
+static void process_coa(private_eap_radius_dae_t *this,
+ radius_message_t *request, host_t *client)
+{
+ enumerator_t *enumerator;
+ linked_list_t *ids;
+ ike_sa_id_t *id;
+ chunk_t data;
+ int type;
+ u_int32_t lifetime = 0;
+ bool lifetime_seen = FALSE;
+
+ ids = get_matching_ike_sas(this, request, client);
+
+ if (ids->get_count(ids))
+ {
+ enumerator = request->create_enumerator(request);
+ while (enumerator->enumerate(enumerator, &type, &data))
+ {
+ if (type == RAT_SESSION_TIMEOUT && data.len == 4)
+ {
+ lifetime = untoh32(data.ptr);
+ lifetime_seen = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (lifetime_seen)
+ {
+ DBG1(DBG_CFG, "applying %us lifetime to %d IKE_SA%s matching %N, "
+ "sending %N", lifetime, ids->get_count(ids),
+ ids->get_count(ids) > 1 ? "s" : "",
+ radius_message_code_names, RMC_COA_REQUEST,
+ radius_message_code_names, RMC_COA_ACK);
+
+ enumerator = ids->create_enumerator(ids);
+ while (enumerator->enumerate(enumerator, &id))
+ {
+ apply_lifetime(this, id, lifetime);
+ }
+ enumerator->destroy(enumerator);
+ send_response(this, request, RMC_COA_ACK, client);
+ }
+ else
+ {
+ DBG1(DBG_CFG, "no Session-Timeout attribute found in %N, sending %N",
+ radius_message_code_names, RMC_COA_REQUEST,
+ radius_message_code_names, RMC_COA_NAK);
+ send_response(this, request, RMC_COA_NAK, client);
+ }
+ }
+ else
+ {
+ DBG1(DBG_CFG, "no IKE_SA matches %N, sending %N",
+ radius_message_code_names, RMC_COA_REQUEST,
+ radius_message_code_names, RMC_COA_NAK);
+ send_response(this, request, RMC_COA_NAK, client);
+ }
+ ids->destroy_offset(ids, offsetof(ike_sa_id_t, destroy));
+}
+
+/**
+ * Receive RADIUS DAE requests
+ */
+static job_requeue_t receive(private_eap_radius_dae_t *this)
+{
+ struct sockaddr_storage addr;
+ socklen_t addr_len = sizeof(addr);
+ radius_message_t *request;
+ char buf[2048];
+ ssize_t len;
+ bool oldstate;
+ host_t *client;
+
+ oldstate = thread_cancelability(TRUE);
+ len = recvfrom(this->fd, buf, sizeof(buf), 0,
+ (struct sockaddr*)&addr, &addr_len);
+ thread_cancelability(oldstate);
+
+ if (len > 0)
+ {
+ request = radius_message_parse(chunk_create(buf, len));
+ if (request)
+ {
+ client = host_create_from_sockaddr((struct sockaddr*)&addr);
+ if (client)
+ {
+ if (!send_retransmit(this, request, client))
+ {
+ if (request->verify(request, NULL, this->secret,
+ this->hasher, this->signer))
+ {
+ switch (request->get_code(request))
+ {
+ case RMC_DISCONNECT_REQUEST:
+ process_disconnect(this, request, client);
+ break;
+ case RMC_COA_REQUEST:
+ process_coa(this, request, client);
+ break;
+ default:
+ DBG1(DBG_CFG, "ignoring unsupported RADIUS DAE "
+ "%N message from %H",
+ radius_message_code_names,
+ request->get_code(request), client);
+ break;
+ }
+ }
+ }
+ client->destroy(client);
+ }
+ request->destroy(request);
+ }
+ else
+ {
+ DBG1(DBG_NET, "ignoring invalid RADIUS DAE request");
+ }
+ }
+ else
+ {
+ DBG1(DBG_NET, "receiving RADIUS DAE request failed: %s", strerror(errno));
+ }
+ return JOB_REQUEUE_DIRECT;
+}
+
+/**
+ * Open DAE socket
+ */
+static bool open_socket(private_eap_radius_dae_t *this)
+{
+ host_t *host;
+
+ this->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (this->fd == -1)
+ {
+ DBG1(DBG_CFG, "unable to open RADIUS DAE socket: %s", strerror(errno));
+ return FALSE;
+ }
+
+ host = host_create_from_string(
+ lib->settings->get_str(lib->settings,
+ "charon.plugins.eap-radius.dae.listen", "0.0.0.0"),
+ lib->settings->get_int(lib->settings,
+ "charon.plugins.eap-radius.dae.port", RADIUS_DAE_PORT));
+ if (!host)
+ {
+ DBG1(DBG_CFG, "invalid RADIUS DAE listen address");
+ return FALSE;
+ }
+
+ if (bind(this->fd, host->get_sockaddr(host),
+ *host->get_sockaddr_len(host)) == -1)
+ {
+ DBG1(DBG_CFG, "unable to bind RADIUS DAE socket: %s", strerror(errno));
+ host->destroy(host);
+ return FALSE;
+ }
+ host->destroy(host);
+ return TRUE;
+}
+
+METHOD(eap_radius_dae_t, destroy, void,
+ private_eap_radius_dae_t *this)
+{
+ if (this->job)
+ {
+ this->job->cancel(this->job);
+ }
+ if (this->fd != -1)
+ {
+ close(this->fd);
+ }
+ DESTROY_IF(this->signer);
+ DESTROY_IF(this->hasher);
+ this->responses->destroy_function(this->responses, (void*)entry_destroy);
+ free(this);
+}
+
+/**
+ * See header
+ */
+eap_radius_dae_t *eap_radius_dae_create(eap_radius_accounting_t *accounting)
+{
+ private_eap_radius_dae_t *this;
+
+ INIT(this,
+ .public = {
+ .destroy = _destroy,
+ },
+ .accounting = accounting,
+ .fd = -1,
+ .secret = {
+ .ptr = lib->settings->get_str(lib->settings,
+ "charon.plugins.eap-radius.dae.secret", NULL),
+ },
+ .hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5),
+ .signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_MD5_128),
+ .responses = linked_list_create(),
+ );
+
+ if (!this->hasher || !this->signer)
+ {
+ destroy(this);
+ return NULL;
+ }
+ if (!this->secret.ptr)
+ {
+ DBG1(DBG_CFG, "missing RADIUS DAE secret, disabled");
+ destroy(this);
+ return NULL;
+ }
+ this->secret.len = strlen(this->secret.ptr);
+ this->signer->set_key(this->signer, this->secret);
+
+ if (!open_socket(this))
+ {
+ destroy(this);
+ return NULL;
+ }
+
+ this->job = callback_job_create_with_prio((callback_job_cb_t)receive,
+ this, NULL, NULL, JOB_PRIO_CRITICAL);
+ lib->processor->queue_job(lib->processor, (job_t*)this->job);
+
+ return &this->public;
+}
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_dae.h b/src/libcharon/plugins/eap_radius/eap_radius_dae.h
new file mode 100644
index 000000000..759eadb49
--- /dev/null
+++ b/src/libcharon/plugins/eap_radius/eap_radius_dae.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 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_dae eap_radius_dae
+ * @{ @ingroup eap_radius
+ */
+
+#ifndef EAP_RADIUS_DAE_H_
+#define EAP_RADIUS_DAE_H_
+
+#include "eap_radius_accounting.h"
+
+typedef struct eap_radius_dae_t eap_radius_dae_t;
+
+/**
+ * Dynamic Authorization Extensions (RFC 5176) for EAP-RADIUS.
+ */
+struct eap_radius_dae_t {
+
+ /**
+ * Destroy a eap_radius_dae_t.
+ */
+ void (*destroy)(eap_radius_dae_t *this);
+};
+
+/**
+ * Create a eap_radius_dae instance.
+ */
+eap_radius_dae_t *eap_radius_dae_create(eap_radius_accounting_t *accounting);
+
+#endif /** EAP_RADIUS_DAE_H_ @}*/
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_forward.c b/src/libcharon/plugins/eap_radius/eap_radius_forward.c
new file mode 100644
index 000000000..cb4ca74e3
--- /dev/null
+++ b/src/libcharon/plugins/eap_radius/eap_radius_forward.c
@@ -0,0 +1,458 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 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_forward.h"
+
+#include <daemon.h>
+#include <utils/linked_list.h>
+#include <utils/hashtable.h>
+#include <threading/mutex.h>
+
+typedef struct private_eap_radius_forward_t private_eap_radius_forward_t;
+
+/**
+ * Private data of an eap_radius_forward_t object.
+ */
+struct private_eap_radius_forward_t {
+
+ /**
+ * Public eap_radius_forward_t interface.
+ */
+ eap_radius_forward_t public;
+
+ /**
+ * List of attribute types to copy from IKE, as attr_t
+ */
+ linked_list_t *from_attr;
+
+ /**
+ * List of attribute types to copy to IKE, as attr_t
+ */
+ linked_list_t *to_attr;
+
+ /**
+ * Queued to forward from IKE, unique_id => linked_list_t of chunk_t
+ */
+ hashtable_t *from;
+
+ /**
+ * Queued to forward to IKE, unique_id => linked_list_t of chunk_t
+ */
+ hashtable_t *to;
+
+ /**
+ * Mutex to lock concurrent access to hashtables
+ */
+ mutex_t *mutex;
+};
+
+/**
+ * RADIUS attribute selector
+ */
+typedef struct {
+ /** vendor ID, 0 for standard attributes */
+ u_int32_t vendor;
+ /** attribute type */
+ u_int8_t type;
+} attr_t;
+
+/**
+ * Single instance of this
+ */
+static private_eap_radius_forward_t *singleton = NULL;
+
+/**
+ * Hashtable hash function
+ */
+static u_int hash(uintptr_t key)
+{
+ return key;
+}
+
+/**
+ * Hashtable equals function
+ */
+static bool equals(uintptr_t a, uintptr_t b)
+{
+ return a == b;
+}
+
+/**
+ * Free a queue entry
+ */
+static void free_attribute(chunk_t *chunk)
+{
+ free(chunk->ptr);
+ free(chunk);
+}
+
+/**
+ * Lookup/create an attribute queue from a table
+ */
+static linked_list_t *lookup_queue(private_eap_radius_forward_t *this,
+ hashtable_t *table)
+{
+ linked_list_t *queue = NULL;
+ ike_sa_t *ike_sa;
+ uintptr_t id;
+
+ ike_sa = charon->bus->get_sa(charon->bus);
+ if (ike_sa && ike_sa->supports_extension(ike_sa, EXT_STRONGSWAN))
+ {
+ id = ike_sa->get_unique_id(ike_sa);
+ this->mutex->lock(this->mutex);
+ queue = table->get(table, (void*)id);
+ if (!queue)
+ {
+ queue = linked_list_create();
+ table->put(table, (void*)id, queue);
+ }
+ this->mutex->unlock(this->mutex);
+ }
+ return queue;
+}
+
+/**
+ * Remove attribute queue from table
+ */
+static void remove_queue(private_eap_radius_forward_t *this,
+ hashtable_t *table, ike_sa_t *ike_sa)
+{
+ linked_list_t *queue;
+
+ this->mutex->lock(this->mutex);
+ queue = table->remove(table, (void*)(uintptr_t)ike_sa->get_unique_id(ike_sa));
+ this->mutex->unlock(this->mutex);
+ if (queue)
+ {
+ queue->destroy_function(queue, (void*)free_attribute);
+ }
+}
+
+/**
+ * Check if RADIUS attribute is contained in selector
+ */
+static bool is_attribute_selected(linked_list_t *selector,
+ radius_attribute_type_t type, chunk_t data)
+{
+ enumerator_t *enumerator;
+ u_int32_t vendor = 0;
+ attr_t *sel;
+ bool found = FALSE;
+
+ if (type == RAT_VENDOR_SPECIFIC)
+ {
+ if (data.len < 4)
+ {
+ return FALSE;
+ }
+ vendor = untoh32(data.ptr);
+ }
+ enumerator = selector->create_enumerator(selector);
+ while (!found && enumerator->enumerate(enumerator, &sel))
+ {
+ if (sel->vendor == vendor)
+ {
+ if (vendor)
+ {
+ if (sel->type == 0)
+ { /* any of that vendor is fine */
+ found = TRUE;
+ }
+ else if (data.len > 4 && data.ptr[4] == sel->type)
+ { /* vendor specific type field, as defined in RFC 2865 */
+ found = TRUE;
+ }
+ }
+ else
+ {
+ if (sel->type == type)
+ {
+ found = TRUE;
+ }
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ return found;
+}
+
+/**
+ * Copy RADIUS attributes from queue to a RADIUS message
+ */
+static void queue2radius(linked_list_t *queue, radius_message_t *message)
+{
+ chunk_t *data;
+
+ while (queue->remove_last(queue, (void**)&data) == SUCCESS)
+ {
+ if (data->len >= 2)
+ {
+ message->add(message, data->ptr[0], chunk_skip(*data, 2));
+ }
+ free_attribute(data);
+ }
+}
+
+/**
+ * Copy RADIUS attributes from a RADIUS message to the queue
+ */
+static void radius2queue(radius_message_t *message, linked_list_t *queue,
+ linked_list_t *selector)
+{
+ enumerator_t *enumerator;
+ int type;
+ chunk_t data, hdr, *ptr;
+
+ enumerator = message->create_enumerator(message);
+ while (enumerator->enumerate(enumerator, &type, &data))
+ {
+ if (is_attribute_selected(selector, type, data))
+ {
+ hdr = chunk_alloc(2);
+ hdr.ptr[0] = type;
+ hdr.ptr[1] = data.len + 2;
+
+ INIT(ptr);
+ *ptr = chunk_cat("mc", hdr, data);
+ queue->insert_last(queue, ptr);
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
+/**
+ * Copy RADIUS attribute nofifies from IKE message to queue
+ */
+static void ike2queue(message_t *message, linked_list_t *queue,
+ linked_list_t *selector)
+{
+ enumerator_t *enumerator;
+ payload_t *payload;
+ notify_payload_t *notify;
+ chunk_t data, *ptr;
+
+ enumerator = message->create_payload_enumerator(message);
+ while (enumerator->enumerate(enumerator, &payload))
+ {
+ if (payload->get_type(payload) == NOTIFY)
+ {
+ notify = (notify_payload_t*)payload;
+ if (notify->get_notify_type(notify) == RADIUS_ATTRIBUTE)
+ {
+ data = notify->get_notification_data(notify);
+ if (data.len >= 2 && is_attribute_selected(selector,
+ data.ptr[0], chunk_skip(data, 2)))
+ {
+ INIT(ptr);
+ *ptr = chunk_clone(data);
+ queue->insert_last(queue, ptr);
+ }
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
+/**
+ * Copy RADUIS attributes from queue to IKE message notifies
+ */
+static void queue2ike(linked_list_t *queue, message_t *message)
+{
+ chunk_t *data;
+
+ while (queue->remove_last(queue, (void**)&data) == SUCCESS)
+ {
+ message->add_notify(message, FALSE, RADIUS_ATTRIBUTE, *data);
+ free_attribute(data);
+ }
+}
+
+/**
+ * See header.
+ */
+void eap_radius_forward_from_ike(radius_message_t *request)
+{
+ private_eap_radius_forward_t *this = singleton;
+ linked_list_t *queue;
+
+ if (this)
+ {
+ queue = lookup_queue(this, this->from);
+ if (queue)
+ {
+ queue2radius(queue, request);
+ }
+ }
+}
+
+/**
+ * See header.
+ */
+void eap_radius_forward_to_ike(radius_message_t *response)
+{
+ private_eap_radius_forward_t *this = singleton;
+ linked_list_t *queue;
+
+ if (this)
+ {
+ queue = lookup_queue(this, this->to);
+ if (queue)
+ {
+ radius2queue(response, queue, this->to_attr);
+ }
+ }
+}
+
+METHOD(listener_t, message, bool,
+ private_eap_radius_forward_t *this,
+ ike_sa_t *ike_sa, message_t *message, bool incoming)
+{
+ linked_list_t *queue;
+
+ if (message->get_exchange_type(message) == IKE_AUTH)
+ {
+ if (incoming)
+ {
+ queue = lookup_queue(this, this->from);
+ if (queue)
+ {
+ ike2queue(message, queue, this->from_attr);
+ }
+ }
+ else
+ {
+ queue = lookup_queue(this, this->to);
+ if (queue)
+ {
+ queue2ike(queue, message);
+ }
+ }
+ }
+ return TRUE;
+}
+
+METHOD(listener_t, ike_updown, bool,
+ private_eap_radius_forward_t *this, ike_sa_t *ike_sa, bool up)
+{
+ /* up or down, we don't need the state anymore */
+ remove_queue(this, this->from, ike_sa);
+ remove_queue(this, this->to, ike_sa);
+ return TRUE;
+}
+
+/**
+ * Parse a selector string to a list of attr_t selectors
+ */
+static linked_list_t* parse_selector(char *selector)
+{
+ enumerator_t *enumerator;
+ linked_list_t *list;
+ char *token, *pos;
+
+ list = linked_list_create();
+ enumerator = enumerator_create_token(selector, ",", " ");
+ while (enumerator->enumerate(enumerator, &token))
+ {
+ int type, vendor = 0;
+ attr_t *attr;
+
+ pos = strchr(token, ':');
+ if (pos)
+ {
+ *(pos++) = 0;
+ vendor = atoi(token);
+ token = pos;
+ }
+ type = enum_from_name(radius_attribute_type_names, token);
+ if (type == -1)
+ {
+ type = atoi(token);
+ }
+ if (vendor == 0 && type == 0)
+ {
+ DBG1(DBG_CFG, "ignoring unknown RADIUS attribute type '%s'", token);
+ }
+ else
+ {
+ INIT(attr,
+ .type = type,
+ .vendor = vendor,
+ );
+ list->insert_last(list, attr);
+ if (!vendor)
+ {
+ DBG1(DBG_IKE, "forwarding RADIUS attribute %N",
+ radius_attribute_type_names, type);
+ }
+ else
+ {
+ DBG1(DBG_IKE, "forwarding RADIUS VSA %d-%d", vendor, type);
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+ return list;
+}
+
+METHOD(eap_radius_forward_t, destroy, void,
+ private_eap_radius_forward_t *this)
+{
+ this->from_attr->destroy_function(this->from_attr, free);
+ this->to_attr->destroy_function(this->to_attr, free);
+ this->from->destroy(this->from);
+ this->to->destroy(this->to);
+ this->mutex->destroy(this->mutex);
+ free(this);
+ singleton = NULL;
+}
+
+/**
+ * See header
+ */
+eap_radius_forward_t *eap_radius_forward_create()
+{
+ private_eap_radius_forward_t *this;
+
+ INIT(this,
+ .public = {
+ .listener = {
+ .message = _message,
+ .ike_updown = _ike_updown,
+ },
+ .destroy = _destroy,
+ },
+ .from_attr = parse_selector(lib->settings->get_str(lib->settings,
+ "charon.plugins.eap-radius.forward.ike_to_radius", "")),
+ .to_attr = parse_selector(lib->settings->get_str(lib->settings,
+ "charon.plugins.eap-radius.forward.radius_to_ike", "")),
+ .from = hashtable_create((hashtable_hash_t)hash,
+ (hashtable_equals_t)equals, 8),
+ .to = hashtable_create((hashtable_hash_t)hash,
+ (hashtable_equals_t)equals, 8),
+ .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ );
+
+ if (this->from_attr->get_count(this->from_attr) == 0 &&
+ this->to_attr->get_count(this->to_attr) == 0)
+ {
+ destroy(this);
+ return NULL;
+ }
+
+ singleton = this;
+ return &this->public;
+}
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_forward.h b/src/libcharon/plugins/eap_radius/eap_radius_forward.h
new file mode 100644
index 000000000..2c1dbf7a8
--- /dev/null
+++ b/src/libcharon/plugins/eap_radius/eap_radius_forward.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 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_forward eap_radius_forward
+ * @{ @ingroup eap_radius
+ */
+
+#ifndef EAP_RADIUS_FORWARD_H_
+#define EAP_RADIUS_FORWARD_H_
+
+#include <radius_message.h>
+
+#include <bus/listeners/listener.h>
+
+typedef struct eap_radius_forward_t eap_radius_forward_t;
+
+/**
+ * Forward RADIUS attributes in Notifies between client and AAA backend.
+ */
+struct eap_radius_forward_t {
+
+ /**
+ * Implements a listener.
+ */
+ listener_t listener;
+
+ /**
+ * Destroy a eap_radius_forward_t.
+ */
+ void (*destroy)(eap_radius_forward_t *this);
+};
+
+/**
+ * Create a eap_radius_forward instance.
+ */
+eap_radius_forward_t *eap_radius_forward_create();
+
+/**
+ * Forward RADIUS attributes from IKE notifies to a RADIUS request.
+ *
+ * @param request RADIUS request message to add attributes to
+ */
+void eap_radius_forward_from_ike(radius_message_t *request);
+
+/**
+ * Forward RADIUS attributes from a RADIUS response to IKE notifies.
+ *
+ * @param response RADIUS respose to read notifies from
+ */
+void eap_radius_forward_to_ike(radius_message_t *response);
+
+#endif /** EAP_RADIUS_FORWARD_H_ @}*/
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_plugin.c b/src/libcharon/plugins/eap_radius/eap_radius_plugin.c
index c218bd48b..8ee0ab81a 100644
--- a/src/libcharon/plugins/eap_radius/eap_radius_plugin.c
+++ b/src/libcharon/plugins/eap_radius/eap_radius_plugin.c
@@ -16,16 +16,25 @@
#include "eap_radius_plugin.h"
#include "eap_radius.h"
-#include "radius_client.h"
-#include "radius_server.h"
+#include "eap_radius_accounting.h"
+#include "eap_radius_dae.h"
+#include "eap_radius_forward.h"
+
+#include <radius_client.h>
+#include <radius_config.h>
#include <daemon.h>
#include <threading/rwlock.h>
/**
- * Default RADIUS server port, when not configured
+ * Default RADIUS server port for authentication
*/
-#define RADIUS_PORT 1812
+#define AUTH_PORT 1812
+
+/**
+ * Default RADIUS server port for accounting
+ */
+#define ACCT_PORT 1813
typedef struct private_eap_radius_plugin_t private_eap_radius_plugin_t;
@@ -40,14 +49,29 @@ struct private_eap_radius_plugin_t {
eap_radius_plugin_t public;
/**
- * List of RADIUS servers
+ * List of RADIUS server configurations
*/
- linked_list_t *servers;
+ linked_list_t *configs;
/**
- * Lock for server list
+ * Lock for configs list
*/
rwlock_t *lock;
+
+ /**
+ * RADIUS sessions for accounting
+ */
+ eap_radius_accounting_t *accounting;
+
+ /**
+ * Dynamic authorization extensions
+ */
+ eap_radius_dae_t *dae;
+
+ /**
+ * RADIUS <-> IKE attribute forwarding
+ */
+ eap_radius_forward_t *forward;
};
/**
@@ -58,12 +82,12 @@ static private_eap_radius_plugin_t *instance = NULL;
/**
* Load RADIUS servers from configuration
*/
-static void load_servers(private_eap_radius_plugin_t *this)
+static void load_configs(private_eap_radius_plugin_t *this)
{
enumerator_t *enumerator;
- radius_server_t *server;
+ radius_config_t *config;
char *nas_identifier, *secret, *address, *section;
- int port, sockets, preference;
+ int auth_port, acct_port, sockets, preference;
address = lib->settings->get_str(lib->settings,
"charon.plugins.eap-radius.server", NULL);
@@ -78,18 +102,18 @@ static void load_servers(private_eap_radius_plugin_t *this)
}
nas_identifier = lib->settings->get_str(lib->settings,
"charon.plugins.eap-radius.nas_identifier", "strongSwan");
- port = lib->settings->get_int(lib->settings,
- "charon.plugins.eap-radius.port", RADIUS_PORT);
+ auth_port = lib->settings->get_int(lib->settings,
+ "charon.plugins.eap-radius.port", AUTH_PORT);
sockets = lib->settings->get_int(lib->settings,
"charon.plugins.eap-radius.sockets", 1);
- server = radius_server_create(address, address, port, nas_identifier,
- secret, sockets, 0);
- if (!server)
+ config = radius_config_create(address, address, auth_port, ACCT_PORT,
+ nas_identifier, secret, sockets, 0);
+ if (!config)
{
DBG1(DBG_CFG, "no RADUIS server defined");
return;
}
- this->servers->insert_last(this->servers, server);
+ this->configs->insert_last(this->configs, config);
return;
}
@@ -114,26 +138,32 @@ static void load_servers(private_eap_radius_plugin_t *this)
nas_identifier = lib->settings->get_str(lib->settings,
"charon.plugins.eap-radius.servers.%s.nas_identifier",
"strongSwan", section);
- port = lib->settings->get_int(lib->settings,
- "charon.plugins.eap-radius.servers.%s.port", RADIUS_PORT, section);
+ auth_port = lib->settings->get_int(lib->settings,
+ "charon.plugins.eap-radius.servers.%s.auth_port",
+ lib->settings->get_int(lib->settings,
+ "charon.plugins.eap-radius.servers.%s.port",
+ AUTH_PORT, section),
+ section);
+ acct_port = lib->settings->get_int(lib->settings,
+ "charon.plugins.eap-radius.servers.%s.acct_port", ACCT_PORT, section);
sockets = lib->settings->get_int(lib->settings,
"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(section, address, port, nas_identifier,
- secret, sockets, preference);
- if (!server)
+ config = radius_config_create(section, address, auth_port, acct_port,
+ nas_identifier, secret, sockets, preference);
+ if (!config)
{
DBG1(DBG_CFG, "loading RADIUS server '%s' failed, skipped", section);
continue;
}
- this->servers->insert_last(this->servers, server);
+ this->configs->insert_last(this->configs, config);
}
enumerator->destroy(enumerator);
DBG1(DBG_CFG, "loaded %d RADIUS server configuration%s",
- this->servers->get_count(this->servers),
- this->servers->get_count(this->servers) == 1 ? "" : "s");
+ this->configs->get_count(this->configs),
+ this->configs->get_count(this->configs) == 1 ? "" : "s");
}
METHOD(plugin_t, get_name, char*,
@@ -142,14 +172,28 @@ METHOD(plugin_t, get_name, char*,
return "eap-radius";
}
+METHOD(plugin_t, get_features, int,
+ eap_radius_plugin_t *this, plugin_feature_t *features[])
+{
+ static plugin_feature_t f[] = {
+ PLUGIN_CALLBACK(eap_method_register, eap_radius_create),
+ PLUGIN_PROVIDE(EAP_SERVER, EAP_RADIUS),
+ PLUGIN_DEPENDS(HASHER, HASH_MD5),
+ PLUGIN_DEPENDS(SIGNER, AUTH_HMAC_MD5_128),
+ PLUGIN_DEPENDS(RNG, RNG_WEAK),
+ };
+ *features = f;
+ return countof(f);
+}
+
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->configs->destroy_offset(this->configs,
+ offsetof(radius_config_t, destroy));
+ this->configs = linked_list_create();
+ load_configs(this);
this->lock->unlock(this->lock);
return TRUE;
}
@@ -157,10 +201,17 @@ METHOD(plugin_t, reload, bool,
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));
+ if (this->forward)
+ {
+ charon->bus->remove_listener(charon->bus, &this->forward->listener);
+ this->forward->destroy(this->forward);
+ }
+ DESTROY_IF(this->dae);
+ this->configs->destroy_offset(this->configs,
+ offsetof(radius_config_t, destroy));
this->lock->destroy(this->lock);
+ charon->bus->remove_listener(charon->bus, &this->accounting->listener);
+ this->accounting->destroy(this->accounting);
free(this);
instance = NULL;
}
@@ -176,36 +227,78 @@ plugin_t *eap_radius_plugin_create()
.public = {
.plugin = {
.get_name = _get_name,
+ .get_features = _get_features,
.reload = _reload,
.destroy = _destroy,
},
},
- .servers = linked_list_create(),
+ .configs = linked_list_create(),
.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+ .accounting = eap_radius_accounting_create(),
+ .forward = eap_radius_forward_create(),
);
- load_servers(this);
-
- charon->eap->add_method(charon->eap, EAP_RADIUS, 0,
- EAP_SERVER, (eap_constructor_t)eap_radius_create);
-
+ load_configs(this);
instance = this;
+ if (lib->settings->get_bool(lib->settings,
+ "charon.plugins.eap-radius.accounting", FALSE))
+ {
+ charon->bus->add_listener(charon->bus, &this->accounting->listener);
+ }
+ if (lib->settings->get_bool(lib->settings,
+ "charon.plugins.eap-radius.dae.enable", FALSE))
+ {
+ this->dae = eap_radius_dae_create(this->accounting);
+ }
+ if (this->forward)
+ {
+ charon->bus->add_listener(charon->bus, &this->forward->listener);
+ }
+
return &this->public.plugin;
}
/**
* See header
*/
-enumerator_t *eap_radius_create_server_enumerator()
+radius_client_t *eap_radius_create_client()
{
if (instance)
{
+ enumerator_t *enumerator;
+ radius_config_t *config, *selected = NULL;
+ int current, best = -1;
+
instance->lock->read_lock(instance->lock);
- return enumerator_create_cleaner(
- instance->servers->create_enumerator(instance->servers),
- (void*)instance->lock->unlock, instance->lock);
+ enumerator = instance->configs->create_enumerator(instance->configs);
+ while (enumerator->enumerate(enumerator, &config))
+ {
+ current = config->get_preference(config);
+ if (current > best ||
+ /* for two with equal preference, 50-50 chance */
+ (current == best && random() % 2 == 0))
+ {
+ DBG2(DBG_CFG, "RADIUS server '%s' is candidate: %d",
+ config->get_name(config), current);
+ best = current;
+ DESTROY_IF(selected);
+ selected = config->get_ref(config);
+ }
+ else
+ {
+ DBG2(DBG_CFG, "RADIUS server '%s' skipped: %d",
+ config->get_name(config), current);
+ }
+ }
+ enumerator->destroy(enumerator);
+ instance->lock->unlock(instance->lock);
+
+ if (selected)
+ {
+ return radius_client_create(selected);
+ }
}
- return enumerator_create_empty();
+ return NULL;
}
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_plugin.h b/src/libcharon/plugins/eap_radius/eap_radius_plugin.h
index cb724364a..1570bd566 100644
--- a/src/libcharon/plugins/eap_radius/eap_radius_plugin.h
+++ b/src/libcharon/plugins/eap_radius/eap_radius_plugin.h
@@ -25,7 +25,8 @@
#define EAP_RADIUS_PLUGIN_H_
#include <plugins/plugin.h>
-#include <utils/enumerator.h>
+
+#include <radius_client.h>
typedef struct eap_radius_plugin_t eap_radius_plugin_t;
@@ -44,10 +45,10 @@ struct eap_radius_plugin_t {
};
/**
- * Create an enumerator over all loaded RADIUS servers.
+ * Get a RADIUS client instance to connect to servers.
*
- * @return enumerator over radius_server_t
+ * @return RADIUS client
*/
-enumerator_t *eap_radius_create_server_enumerator();
+radius_client_t *eap_radius_create_client();
#endif /** EAP_RADIUS_PLUGIN_H_ @}*/
diff --git a/src/libcharon/plugins/eap_radius/radius_client.c b/src/libcharon/plugins/eap_radius/radius_client.c
deleted file mode 100644
index 245308e59..000000000
--- a/src/libcharon/plugins/eap_radius/radius_client.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (C) 2009 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * 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 "radius_client.h"
-
-#include "eap_radius_plugin.h"
-#include "radius_server.h"
-
-#include <unistd.h>
-#include <errno.h>
-
-#include <daemon.h>
-#include <utils/host.h>
-#include <utils/linked_list.h>
-#include <threading/condvar.h>
-#include <threading/mutex.h>
-
-typedef struct private_radius_client_t private_radius_client_t;
-
-/**
- * Private data of an radius_client_t object.
- */
-struct private_radius_client_t {
-
- /**
- * Public radius_client_t interface.
- */
- radius_client_t public;
-
- /**
- * Selected RADIUS server
- */
- radius_server_t *server;
-
- /**
- * RADIUS servers State attribute
- */
- chunk_t state;
-
- /**
- * EAP MSK, from MPPE keys
- */
- chunk_t msk;
-};
-
-/**
- * Save the state attribute to include in further request
- */
-static void save_state(private_radius_client_t *this, radius_message_t *msg)
-{
- enumerator_t *enumerator;
- int type;
- chunk_t data;
-
- enumerator = msg->create_enumerator(msg);
- while (enumerator->enumerate(enumerator, &type, &data))
- {
- if (type == RAT_STATE)
- {
- free(this->state.ptr);
- this->state = chunk_clone(data);
- enumerator->destroy(enumerator);
- return;
- }
- }
- enumerator->destroy(enumerator);
- /* no state attribute found, remove state */
- chunk_free(&this->state);
-}
-
-METHOD(radius_client_t, request, radius_message_t*,
- private_radius_client_t *this, radius_message_t *req)
-{
- char virtual[] = {0x00,0x00,0x00,0x05};
- radius_socket_t *socket;
- radius_message_t *res;
-
- /* we add the "Virtual" NAS-Port-Type, as we SHOULD include one */
- req->add(req, RAT_NAS_PORT_TYPE, chunk_create(virtual, sizeof(virtual)));
- /* add our NAS-Identifier */
- req->add(req, RAT_NAS_IDENTIFIER,
- this->server->get_nas_identifier(this->server));
- /* add State attribute, if server sent one */
- if (this->state.ptr)
- {
- req->add(req, RAT_STATE, this->state);
- }
- socket = this->server->get_socket(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 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)
- {
- chunk_clear(&this->msk);
- this->msk = socket->decrypt_msk(socket, req, res);
- }
- this->server->put_socket(this->server, socket, TRUE);
- return res;
- }
- this->server->put_socket(this->server, socket, FALSE);
- charon->bus->alert(charon->bus, ALERT_RADIUS_NOT_RESPONDING);
- return NULL;
-}
-
-METHOD(radius_client_t, get_msk, chunk_t,
- private_radius_client_t *this)
-{
- return this->msk;
-}
-
-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);
-}
-
-/**
- * See header
- */
-radius_client_t *radius_client_create()
-{
- private_radius_client_t *this;
- enumerator_t *enumerator;
- radius_server_t *server;
- int current, best = -1;
-
- INIT(this,
- .public = {
- .request = _request,
- .get_msk = _get_msk,
- .destroy = _destroy,
- },
- );
-
- enumerator = eap_radius_create_server_enumerator();
- while (enumerator->enumerate(enumerator, &server))
- {
- current = server->get_preference(server);
- if (current > best ||
- /* for two with equal preference, 50-50 chance */
- (current == best && random() % 2 == 0))
- {
- DBG2(DBG_CFG, "RADIUS server '%s' is candidate: %d",
- server->get_name(server), current);
- best = current;
- DESTROY_IF(this->server);
- this->server = server->get_ref(server);
- }
- else
- {
- DBG2(DBG_CFG, "RADIUS server '%s' skipped: %d",
- server->get_name(server), current);
- }
- }
- enumerator->destroy(enumerator);
-
- if (!this->server)
- {
- free(this);
- return NULL;
- }
-
- return &this->public;
-}
-
diff --git a/src/libcharon/plugins/eap_radius/radius_client.h b/src/libcharon/plugins/eap_radius/radius_client.h
deleted file mode 100644
index e4f3a7222..000000000
--- a/src/libcharon/plugins/eap_radius/radius_client.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2009 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * 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 radius_client radius_client
- * @{ @ingroup eap_radius
- */
-
-#ifndef RADIUS_CLIENT_H_
-#define RADIUS_CLIENT_H_
-
-#include "radius_message.h"
-
-typedef struct radius_client_t radius_client_t;
-
-/**
- * RADIUS client functionality.
- *
- * To communicate with a RADIUS server, create a client and send messages over
- * it. The client allocates a socket from the best RADIUS server abailable.
- */
-struct radius_client_t {
-
- /**
- * Send a RADIUS request and wait for the response.
- *
- * The client fills in NAS-Identifier nad NAS-Port-Type
- *
- * @param msg RADIUS request message to send
- * @return response, NULL if timed out/verification failed
- */
- radius_message_t* (*request)(radius_client_t *this, radius_message_t *msg);
-
- /**
- * Get the EAP MSK after successful RADIUS authentication.
- *
- * @return MSK, allocated
- */
- chunk_t (*get_msk)(radius_client_t *this);
-
- /**
- * Destroy the client, release the socket.
- */
- void (*destroy)(radius_client_t *this);
-};
-
-/**
- * Create a RADIUS client.
- *
- * @return radius_client_t object
- */
-radius_client_t *radius_client_create();
-
-#endif /** RADIUS_CLIENT_H_ @}*/
diff --git a/src/libcharon/plugins/eap_radius/radius_message.c b/src/libcharon/plugins/eap_radius/radius_message.c
deleted file mode 100644
index 23a29b772..000000000
--- a/src/libcharon/plugins/eap_radius/radius_message.c
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- * Copyright (C) 2009 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * 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 "radius_message.h"
-
-#include <daemon.h>
-#include <crypto/hashers/hasher.h>
-
-typedef struct private_radius_message_t private_radius_message_t;
-typedef struct rmsg_t rmsg_t;
-typedef struct rattr_t rattr_t;
-
-/**
- * RADIUS message header
- */
-struct rmsg_t {
- /** message code, radius_message_code_t */
- u_int8_t code;
- /** message identifier */
- u_int8_t identifier;
- /** length of Code, Identifier, Length, Authenticator and Attributes */
- u_int16_t length;
- /** message authenticator, MD5 hash */
- u_int8_t authenticator[HASH_SIZE_MD5];
- /** variable list of packed attributes */
- u_int8_t attributes[];
-} __attribute__((packed));
-
-/**
- * RADIUS message attribute.
- */
-struct rattr_t {
- /** attribute type, radius_attribute_type_t */
- u_int8_t type;
- /** length of the attriubte, including the Type, Length and Value fields */
- u_int8_t length;
- /** variable length attribute value */
- u_int8_t value[];
-} __attribute__((packed));
-
-/**
- * Private data of an radius_message_t object.
- */
-struct private_radius_message_t {
-
- /**
- * Public radius_message_t interface.
- */
- radius_message_t public;
-
- /**
- * message data, allocated
- */
- rmsg_t *msg;
-};
-
-ENUM_BEGIN(radius_message_code_names, RMC_ACCESS_REQUEST, RMC_ACCOUNTING_RESPONSE,
- "Access-Request",
- "Access-Accept",
- "Access-Reject",
- "Accounting-Request",
- "Accounting-Response");
-ENUM_NEXT(radius_message_code_names, RMC_ACCESS_CHALLENGE, RMC_ACCESS_CHALLENGE, RMC_ACCOUNTING_RESPONSE,
- "Access-Challenge");
-ENUM_END(radius_message_code_names, RMC_ACCESS_CHALLENGE);
-
-ENUM(radius_attribute_type_names, RAT_USER_NAME, RAT_MIP6_HOME_LINK_PREFIX,
- "User-Name",
- "User-Password",
- "CHAP-Password",
- "NAS-IP-Address",
- "NAS-Port",
- "Service-Type",
- "Framed-Protocol",
- "Framed-IP-Address",
- "Framed-IP-Netmask",
- "Framed-Routing",
- "Filter-Id",
- "Framed-MTU",
- "Framed-Compression",
- "Login-IP-Host",
- "Login-Service",
- "Login-TCP-Port",
- "Unassigned",
- "Reply-Message",
- "Callback-Number",
- "Callback-Id",
- "Unassigned",
- "Framed-Route",
- "Framed-IPX-Network",
- "State",
- "Class",
- "Vendor-Specific",
- "Session-Timeout",
- "Idle-Timeout",
- "Termination-Action",
- "Called-Station-Id",
- "Calling-Station-Id",
- "NAS-Identifier",
- "Proxy-State",
- "Login-LAT-Service",
- "Login-LAT-Node",
- "Login-LAT-Group",
- "Framed-AppleTalk-Link",
- "Framed-AppleTalk-Network",
- "Framed-AppleTalk-Zone",
- "Acct-Status-Type",
- "Acct-Delay-Time",
- "Acct-Input-Octets",
- "Acct-Output-Octets",
- "Acct-Session-Id",
- "Acct-Authentic",
- "Acct-Session-Time",
- "Acct-Input-Packets",
- "Acct-Output-Packets",
- "Acct-Terminate-Cause",
- "Acct-Multi-Session-Id",
- "Acct-Link-Count",
- "Acct-Input-Gigawords",
- "Acct-Output-Gigawords",
- "Unassigned",
- "Event-Timestamp",
- "Egress-VLANID",
- "Ingress-Filters",
- "Egress-VLAN-Name",
- "User-Priority-Table",
- "CHAP-Challenge",
- "NAS-Port-Type",
- "Port-Limit",
- "Login-LAT-Port",
- "Tunnel-Type",
- "Tunnel-Medium-Type",
- "Tunnel-Client-Endpoint",
- "Tunnel-Server-Endpoint",
- "Acct-Tunnel-Connection",
- "Tunnel-Password",
- "ARAP-Password",
- "ARAP-Features",
- "ARAP-Zone-Access",
- "ARAP-Security",
- "ARAP-Security-Data",
- "Password-Retry",
- "Prompt",
- "Connect-Info",
- "Configuration-Token",
- "EAP-Message",
- "Message-Authenticator",
- "Tunnel-Private-Group-ID",
- "Tunnel-Assignment-ID",
- "Tunnel-Preference",
- "ARAP-Challenge-Response",
- "Acct-Interim-Interval",
- "Acct-Tunnel-Packets-Lost",
- "NAS-Port-Id",
- "Framed-Pool",
- "CUI",
- "Tunnel-Client-Auth-ID",
- "Tunnel-Server-Auth-ID",
- "NAS-Filter-Rule",
- "Unassigned",
- "Originating-Line-Info",
- "NAS-IPv6-Address",
- "Framed-Interface-Id",
- "Framed-IPv6-Prefix",
- "Login-IPv6-Host",
- "Framed-IPv6-Route",
- "Framed-IPv6-Pool",
- "Error-Cause",
- "EAP-Key-Name",
- "Digest-Response",
- "Digest-Realm",
- "Digest-Nonce",
- "Digest-Response-Auth",
- "Digest-Nextnonce",
- "Digest-Method",
- "Digest-URI",
- "Digest-Qop",
- "Digest-Algorithm",
- "Digest-Entity-Body-Hash",
- "Digest-CNonce",
- "Digest-Nonce-Count",
- "Digest-Username",
- "Digest-Opaque",
- "Digest-Auth-Param",
- "Digest-AKA-Auts",
- "Digest-Domain",
- "Digest-Stale",
- "Digest-HA1",
- "SIP-AOR",
- "Delegated-IPv6-Prefix",
- "MIP6-Feature-Vector",
- "MIP6-Home-Link-Prefix");
-
-/**
- * Attribute enumerator implementation
- */
-typedef struct {
- /** implements enumerator interface */
- enumerator_t public;
- /** currently pointing attribute */
- rattr_t *next;
- /** bytes left */
- int left;
-} attribute_enumerator_t;
-
-METHOD(enumerator_t, attribute_enumerate, bool,
- attribute_enumerator_t *this, int *type, chunk_t *data)
-{
- if (this->left == 0)
- {
- return FALSE;
- }
- if (this->left < sizeof(rattr_t) ||
- this->left < this->next->length)
- {
- DBG1(DBG_IKE, "RADIUS message truncated");
- return FALSE;
- }
- *type = this->next->type;
- data->ptr = this->next->value;
- data->len = this->next->length - sizeof(rattr_t);
- this->left -= this->next->length;
- this->next = ((void*)this->next) + this->next->length;
- return TRUE;
-}
-
-METHOD(radius_message_t, create_enumerator, enumerator_t*,
- private_radius_message_t *this)
-{
- attribute_enumerator_t *e;
-
- if (ntohs(this->msg->length) < sizeof(rmsg_t) + sizeof(rattr_t))
- {
- return enumerator_create_empty();
- }
- INIT(e,
- .public = {
- .enumerate = (void*)_attribute_enumerate,
- .destroy = (void*)free,
- },
- .next = (rattr_t*)this->msg->attributes,
- .left = ntohs(this->msg->length) - sizeof(rmsg_t),
- );
- return &e->public;
-}
-
-METHOD(radius_message_t, add, void,
- private_radius_message_t *this, radius_attribute_type_t type, chunk_t data)
-{
- rattr_t *attribute;
-
- data.len = min(data.len, 253);
- this->msg = realloc(this->msg,
- ntohs(this->msg->length) + sizeof(rattr_t) + data.len);
- attribute = ((void*)this->msg) + ntohs(this->msg->length);
- attribute->type = type;
- attribute->length = data.len + sizeof(rattr_t);
- memcpy(attribute->value, data.ptr, data.len);
- this->msg->length = htons(ntohs(this->msg->length) + attribute->length);
-}
-
-METHOD(radius_message_t, sign, void,
- private_radius_message_t *this, rng_t *rng, signer_t *signer)
-{
- char buf[HASH_SIZE_MD5];
-
- /* build Request-Authenticator */
- rng->get_bytes(rng, HASH_SIZE_MD5, this->msg->authenticator);
-
- /* build Message-Authenticator attribute, using 16 null bytes */
- memset(buf, 0, sizeof(buf));
- add(this, RAT_MESSAGE_AUTHENTICATOR, chunk_create(buf, sizeof(buf)));
- signer->get_signature(signer,
- chunk_create((u_char*)this->msg, ntohs(this->msg->length)),
- ((u_char*)this->msg) + ntohs(this->msg->length) - HASH_SIZE_MD5);
-}
-
-METHOD(radius_message_t, verify, bool,
- private_radius_message_t *this, u_int8_t *req_auth, chunk_t secret,
- hasher_t *hasher, signer_t *signer)
-{
- char buf[HASH_SIZE_MD5], res_auth[HASH_SIZE_MD5];
- enumerator_t *enumerator;
- int type;
- chunk_t data, msg;
- bool has_eap = FALSE, has_auth = FALSE;
-
- /* replace Response by Request Authenticator for verification */
- memcpy(res_auth, this->msg->authenticator, HASH_SIZE_MD5);
- memcpy(this->msg->authenticator, req_auth, HASH_SIZE_MD5);
- msg = chunk_create((u_char*)this->msg, ntohs(this->msg->length));
-
- /* verify Response-Authenticator */
- hasher->get_hash(hasher, msg, NULL);
- hasher->get_hash(hasher, secret, buf);
- if (!memeq(buf, res_auth, HASH_SIZE_MD5))
- {
- DBG1(DBG_CFG, "RADIUS Response-Authenticator verification failed");
- return FALSE;
- }
-
- /* verify Message-Authenticator attribute */
- enumerator = create_enumerator(this);
- while (enumerator->enumerate(enumerator, &type, &data))
- {
- if (type == RAT_MESSAGE_AUTHENTICATOR)
- {
- if (data.len != HASH_SIZE_MD5)
- {
- DBG1(DBG_CFG, "RADIUS Message-Authenticator invalid length");
- enumerator->destroy(enumerator);
- return FALSE;
- }
- memcpy(buf, data.ptr, data.len);
- memset(data.ptr, 0, data.len);
- if (signer->verify_signature(signer, msg,
- chunk_create(buf, sizeof(buf))))
- {
- /* restore Message-Authenticator */
- memcpy(data.ptr, buf, data.len);
- has_auth = TRUE;
- break;
- }
- else
- {
- DBG1(DBG_CFG, "RADIUS Message-Authenticator verification failed");
- enumerator->destroy(enumerator);
- return FALSE;
- }
- }
- else if (type == RAT_EAP_MESSAGE)
- {
- has_eap = TRUE;
- }
- }
- enumerator->destroy(enumerator);
- /* restore Response-Authenticator */
- memcpy(this->msg->authenticator, res_auth, HASH_SIZE_MD5);
-
- if (has_eap && !has_auth)
- { /* Message-Authenticator is required if we have an EAP-Message */
- DBG1(DBG_CFG, "RADIUS Message-Authenticator attribute missing");
- return FALSE;
- }
- return TRUE;
-}
-
-METHOD(radius_message_t, get_code, radius_message_code_t,
- private_radius_message_t *this)
-{
- return this->msg->code;
-}
-
-METHOD(radius_message_t, get_identifier, u_int8_t,
- private_radius_message_t *this)
-{
- return this->msg->identifier;
-}
-
-METHOD(radius_message_t, set_identifier, void,
- private_radius_message_t *this, u_int8_t identifier)
-{
- this->msg->identifier = identifier;
-}
-
-METHOD(radius_message_t, get_authenticator, u_int8_t*,
- private_radius_message_t *this)
-{
- return this->msg->authenticator;
-}
-
-
-METHOD(radius_message_t, get_encoding, chunk_t,
- private_radius_message_t *this)
-{
- return chunk_create((u_char*)this->msg, ntohs(this->msg->length));
-}
-
-METHOD(radius_message_t, destroy, void,
- private_radius_message_t *this)
-{
- free(this->msg);
- free(this);
-}
-
-/**
- * Generic constructor
- */
-static private_radius_message_t *radius_message_create()
-{
- private_radius_message_t *this;
-
- INIT(this,
- .public = {
- .create_enumerator = _create_enumerator,
- .add = _add,
- .get_code = _get_code,
- .get_identifier = _get_identifier,
- .set_identifier = _set_identifier,
- .get_authenticator = _get_authenticator,
- .get_encoding = _get_encoding,
- .sign = _sign,
- .verify = _verify,
- .destroy = _destroy,
- },
- );
-
- return this;
-}
-
-/**
- * See header
- */
-radius_message_t *radius_message_create_request()
-{
- private_radius_message_t *this = radius_message_create();
-
- INIT(this->msg,
- .code = RMC_ACCESS_REQUEST,
- .identifier = 0,
- .length = htons(sizeof(rmsg_t)),
- );
-
- return &this->public;
-}
-
-/**
- * See header
- */
-radius_message_t *radius_message_parse_response(chunk_t data)
-{
- private_radius_message_t *this = radius_message_create();
-
- this->msg = malloc(data.len);
- memcpy(this->msg, data.ptr, data.len);
- if (data.len < sizeof(rmsg_t) ||
- ntohs(this->msg->length) != data.len)
- {
- DBG1(DBG_IKE, "RADIUS message has invalid length");
- destroy(this);
- return NULL;
- }
- return &this->public;
-}
-
diff --git a/src/libcharon/plugins/eap_radius/radius_message.h b/src/libcharon/plugins/eap_radius/radius_message.h
deleted file mode 100644
index 266839d3b..000000000
--- a/src/libcharon/plugins/eap_radius/radius_message.h
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright (C) 2009 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * 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 radius_message radius_message
- * @{ @ingroup eap_radius
- */
-
-#ifndef RADIUS_MESSAGE_H_
-#define RADIUS_MESSAGE_H_
-
-#include <library.h>
-
-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;
-
-/**
- * RADIUS Message Codes.
- */
-enum radius_message_code_t {
- RMC_ACCESS_REQUEST = 1,
- RMC_ACCESS_ACCEPT = 2,
- RMC_ACCESS_REJECT = 3,
- RMC_ACCOUNTING_REQUEST = 4,
- RMC_ACCOUNTING_RESPONSE = 5,
- RMC_ACCESS_CHALLENGE = 11,
-};
-
-/**
- * Enum names for radius_attribute_type_t.
- */
-extern enum_name_t *radius_message_code_names;
-
-/**
- * RADIUS Attribute Types.
- */
-enum radius_attribute_type_t {
- RAT_USER_NAME = 1,
- RAT_USER_PASSWORD = 2,
- RAT_CHAP_PASSWORD = 3,
- RAT_NAS_IP_ADDRESS = 4,
- RAT_NAS_PORT = 5,
- RAT_SERVICE_TYPE = 6,
- RAT_FRAMED_PROTOCOL = 7,
- RAT_FRAMED_IP_ADDRESS = 8,
- RAT_FRAMED_IP_NETMASK = 9,
- RAT_FRAMED_ROUTING = 10,
- RAT_FILTER_ID = 11,
- RAT_FRAMED_MTU = 12,
- RAT_FRAMED_COMPRESSION = 13,
- RAT_LOGIN_IP_HOST = 14,
- RAT_LOGIN_SERVICE = 15,
- RAT_LOGIN_TCP_PORT = 16,
- RAT_REPLY_MESSAGE = 18,
- RAT_CALLBACK_NUMBER = 19,
- RAT_CALLBACK_ID = 20,
- RAT_FRAMED_ROUTE = 22,
- RAT_FRAMED_IPX_NETWORK = 23,
- RAT_STATE = 24,
- RAT_CLASS = 25,
- RAT_VENDOR_SPECIFIC = 26,
- RAT_SESSION_TIMEOUT = 27,
- RAT_IDLE_TIMEOUT = 28,
- RAT_TERMINATION_ACTION = 29,
- RAT_CALLED_STATION_ID = 30,
- RAT_CALLING_STATION_ID = 31,
- RAT_NAS_IDENTIFIER = 32,
- RAT_PROXY_STATE = 33,
- RAT_LOGIN_LAT_SERVICE = 34,
- RAT_LOGIN_LAT_NODE = 35,
- RAT_LOGIN_LAT_GROUP = 36,
- RAT_FRAMED_APPLETALK_LINK = 37,
- RAT_FRAMED_APPLETALK_NETWORK = 38,
- RAT_FRAMED_APPLETALK_ZONE = 39,
- RAT_ACCT_STATUS_TYPE = 40,
- RAT_ACCT_DELAY_TIME = 41,
- RAT_ACCT_INPUT_OCTETS = 42,
- RAT_ACCT_OUTPUT_OCTETS = 43,
- RAT_ACCT_SESSION_ID = 44,
- RAT_ACCT_AUTHENTIC = 45,
- RAT_ACCT_SESSION_TIME = 46,
- RAT_ACCT_INPUT_PACKETS = 47,
- RAT_ACCT_OUTPUT_PACKETS = 48,
- RAT_ACCT_TERMINATE_CAUSE = 49,
- RAT_ACCT_MULTI_SESSION_ID = 50,
- RAT_ACCT_LINK_COUNT = 51,
- RAT_ACCT_INPUT_GIGAWORDS = 52,
- RAT_ACCT_OUTPUT_GIGAWORDS = 53,
- RAT_EVENT_TIMESTAMP = 55,
- RAT_EGRESS_VLANID = 56,
- RAT_INGRESS_FILTERS = 57,
- RAT_EGRESS_VLAN_NAME = 58,
- RAT_USER_PRIORITY_TABLE = 59,
- RAT_CHAP_CHALLENGE = 60,
- RAT_NAS_PORT_TYPE = 61,
- RAT_PORT_LIMIT = 62,
- RAT_LOGIN_LAT_PORT = 63,
- RAT_TUNNEL_TYPE = 64,
- RAT_TUNNEL_MEDIUM_TYPE = 65,
- RAT_TUNNEL_CLIENT_ENDPOINT = 66,
- RAT_TUNNEL_SERVER_ENDPOINT = 67,
- RAT_ACCT_TUNNEL_CONNECTION = 68,
- RAT_TUNNEL_PASSWORD = 69,
- RAT_ARAP_PASSWORD = 70,
- RAT_ARAP_FEATURES = 71,
- RAT_ARAP_ZONE_ACCESS = 72,
- RAT_ARAP_SECURITY = 73,
- RAT_ARAP_SECURITY_DATA = 74,
- RAT_PASSWORD_RETRY = 75,
- RAT_PROMPT = 76,
- RAT_CONNECT_INFO = 77,
- RAT_CONFIGURATION_TOKEN = 78,
- RAT_EAP_MESSAGE = 79,
- RAT_MESSAGE_AUTHENTICATOR = 80,
- RAT_TUNNEL_PRIVATE_GROUP_ID = 81,
- RAT_TUNNEL_ASSIGNMENT_ID = 82,
- RAT_TUNNEL_PREFERENCE = 83,
- RAT_ARAP_CHALLENGE_RESPONSE = 84,
- RAT_ACCT_INTERIM_INTERVAL = 85,
- RAT_ACCT_TUNNEL_PACKETS_LOST = 86,
- RAT_NAS_PORT_ID = 87,
- RAT_FRAMED_POOL = 88,
- RAT_CUI = 89,
- RAT_TUNNEL_CLIENT_AUTH_ID = 90,
- RAT_TUNNEL_SERVER_AUTH_ID = 91,
- RAT_NAS_FILTER_RULE = 92,
- RAT_UNASSIGNED = 93,
- RAT_ORIGINATING_LINE_INFO = 94,
- RAT_NAS_IPV6_ADDRESS = 95,
- RAT_FRAMED_INTERFACE_ID = 96,
- RAT_FRAMED_IPV6_PREFIX = 97,
- RAT_LOGIN_IPV6_HOST = 98,
- RAT_FRAMED_IPV6_ROUTE = 99,
- RAT_FRAMED_IPV6_POOL = 100,
- RAT_ERROR_CAUSE = 101,
- RAT_EAP_KEY_NAME = 102,
- RAT_DIGEST_RESPONSE = 103,
- RAT_DIGEST_REALM = 104,
- RAT_DIGEST_NONCE = 105,
- RAT_DIGEST_RESPONSE_AUTH = 106,
- RAT_DIGEST_NEXTNONCE = 107,
- RAT_DIGEST_METHOD = 108,
- RAT_DIGEST_URI = 109,
- RAT_DIGEST_QOP = 110,
- RAT_DIGEST_ALGORITHM = 111,
- RAT_DIGEST_ENTITY_BODY_HASH = 112,
- RAT_DIGEST_CNONCE = 113,
- RAT_DIGEST_NONCE_COUNT = 114,
- RAT_DIGEST_USERNAME = 115,
- RAT_DIGEST_OPAQUE = 116,
- RAT_DIGEST_AUTH_PARAM = 117,
- RAT_DIGEST_AKA_AUTS = 118,
- RAT_DIGEST_DOMAIN = 119,
- RAT_DIGEST_STALE = 120,
- RAT_DIGEST_HA1 = 121,
- RAT_SIP_AOR = 122,
- RAT_DELEGATED_IPV6_PREFIX = 123,
- RAT_MIP6_FEATURE_VECTOR = 124,
- RAT_MIP6_HOME_LINK_PREFIX = 125,
-};
-
-/**
- * Enum names for radius_attribute_type_t.
- */
-extern enum_name_t *radius_attribute_type_names;
-
-/**
- * A RADIUS message, contains attributes.
- */
-struct radius_message_t {
-
- /**
- * Create an enumerator over contained RADIUS attributes.
- *
- * @return enumerator over (int type, chunk_t data)
- */
- enumerator_t* (*create_enumerator)(radius_message_t *this);
-
- /**
- * Add a RADIUS attribute to the message.
- *
- * @param type type of attribute to add
- * @param attribute data, gets cloned
- */
- void (*add)(radius_message_t *this, radius_attribute_type_t type,
- chunk_t data);
-
- /**
- * Get the message type (code).
- *
- * @return message code
- */
- radius_message_code_t (*get_code)(radius_message_t *this);
-
- /**
- * Get the message identifier.
- *
- * @return message identifier
- */
- u_int8_t (*get_identifier)(radius_message_t *this);
-
- /**
- * Set the message identifier.
- *
- * @param identifier message identifier
- */
- void (*set_identifier)(radius_message_t *this, u_int8_t identifier);
-
- /**
- * Get the 16 byte authenticator.
- *
- * @return pointer to the Authenticator field
- */
- u_int8_t* (*get_authenticator)(radius_message_t *this);
-
- /**
- * Get the RADIUS message in its encoded form.
- *
- * @return chunk pointing to internal RADIUS message.
- */
- chunk_t (*get_encoding)(radius_message_t *this);
-
- /**
- * Calculate and add the Message-Authenticator attribute to the message.
- *
- * @param rng RNG to create Request-Authenticator
- * @param signer HMAC-MD5 signer with secret set
- */
- void (*sign)(radius_message_t *this, rng_t *rng, signer_t *signer);
-
- /**
- * Verify the integrity of a received RADIUS response.
- *
- * @param req_auth 16 byte Authenticator of the corresponding request
- * @param secret shared RADIUS secret
- * @param hasher hasher to verify Response-Authenticator
- * @param signer signer to verify Message-Authenticator attribute
- */
- bool (*verify)(radius_message_t *this, u_int8_t *req_auth, chunk_t secret,
- hasher_t *hasher, signer_t *signer);
-
- /**
- * Destroy the message.
- */
- void (*destroy)(radius_message_t *this);
-};
-
-/**
- * Create an empty RADIUS request message (RMT_ACCESS_REQUEST).
- *
- * @return radius_message_t object
- */
-radius_message_t *radius_message_create_request();
-
-/**
- * Parse and verify a recevied RADIUS response.
- *
- * @param data received message data
- * @return radius_message_t object, NULL if length invalid
- */
-radius_message_t *radius_message_parse_response(chunk_t data);
-
-#endif /** RADIUS_MESSAGE_H_ @}*/
diff --git a/src/libcharon/plugins/eap_radius/radius_server.c b/src/libcharon/plugins/eap_radius/radius_server.c
deleted file mode 100644
index 3baf39807..000000000
--- a/src/libcharon/plugins/eap_radius/radius_server.c
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright (C) 2010 Martin Willi
- * Copyright (C) 2010 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 "radius_server.h"
-
-#include <threading/mutex.h>
-#include <threading/condvar.h>
-#include <utils/linked_list.h>
-
-typedef struct private_radius_server_t private_radius_server_t;
-
-/**
- * Private data of an radius_server_t object.
- */
-struct private_radius_server_t {
-
- /**
- * Public radius_server_t interface.
- */
- radius_server_t public;
-
- /**
- * list of radius sockets, as radius_socket_t
- */
- linked_list_t *sockets;
-
- /**
- * Total number of sockets, in list + currently in use
- */
- int socket_count;
-
- /**
- * mutex to lock sockets list
- */
- mutex_t *mutex;
-
- /**
- * condvar to wait for sockets
- */
- condvar_t *condvar;
-
- /**
- * Server name
- */
- char *name;
-
- /**
- * NAS-Identifier
- */
- chunk_t nas_identifier;
-
- /**
- * Preference boost for this server
- */
- int preference;
-
- /**
- * Is the server currently reachable
- */
- bool reachable;
-
- /**
- * Retry counter for unreachable servers
- */
- int retry;
-
- /**
- * reference count
- */
- refcount_t ref;
-};
-
-METHOD(radius_server_t, get_socket, radius_socket_t*,
- private_radius_server_t *this)
-{
- radius_socket_t *skt;
-
- this->mutex->lock(this->mutex);
- while (this->sockets->remove_first(this->sockets, (void**)&skt) != SUCCESS)
- {
- this->condvar->wait(this->condvar, this->mutex);
- }
- this->mutex->unlock(this->mutex);
- return skt;
-}
-
-METHOD(radius_server_t, put_socket, void,
- private_radius_server_t *this, radius_socket_t *skt, bool result)
-{
- this->mutex->lock(this->mutex);
- this->sockets->insert_last(this->sockets, skt);
- this->mutex->unlock(this->mutex);
- this->condvar->signal(this->condvar);
- this->reachable = result;
-}
-
-METHOD(radius_server_t, get_nas_identifier, chunk_t,
- private_radius_server_t *this)
-{
- return this->nas_identifier;
-}
-
-METHOD(radius_server_t, get_preference, int,
- private_radius_server_t *this)
-{
- int pref;
-
- if (this->socket_count == 0)
- { /* don't have sockets, huh? */
- return -1;
- }
- /* calculate preference between 0-100 + boost */
- pref = this->preference;
- pref += this->sockets->get_count(this->sockets) * 100 / this->socket_count;
- if (this->reachable)
- { /* reachable server get a boost: pref = 110-210 + boost */
- return pref + 110;
- }
- /* Not reachable. Increase preference randomly to let it retry from
- * time to time, especially if other servers have high load. */
- this->retry++;
- if (this->retry % 128 == 0)
- { /* every 64th request gets 210, same as unloaded reachable */
- return pref + 110;
- }
- if (this->retry % 32 == 0)
- { /* every 32th request gets 190, wins against average loaded */
- return pref + 90;
- }
- if (this->retry % 8 == 0)
- { /* every 8th request gets 110, same as server under load */
- return pref + 10;
- }
- /* other get ~100, less than fully loaded */
- return pref;
-}
-
-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)
-{
- ref_get(&this->ref);
- return &this->public;
-}
-
-
-METHOD(radius_server_t, destroy, void,
- private_radius_server_t *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 *name, char *address, u_int16_t port,
- char *nas_identifier, char *secret, int sockets, int preference)
-{
- private_radius_server_t *this;
- radius_socket_t *socket;
-
- INIT(this,
- .public = {
- .get_socket = _get_socket,
- .put_socket = _put_socket,
- .get_nas_identifier = _get_nas_identifier,
- .get_preference = _get_preference,
- .get_name = _get_name,
- .get_ref = _get_ref,
- .destroy = _destroy,
- },
- .reachable = TRUE,
- .nas_identifier = chunk_create(nas_identifier, strlen(nas_identifier)),
- .socket_count = sockets,
- .sockets = linked_list_create(),
- .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
- .condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
- .name = name,
- .preference = preference,
- .ref = 1,
- );
-
- while (sockets--)
- {
- socket = radius_socket_create(address, port,
- chunk_create(secret, strlen(secret)));
- if (!socket)
- {
- destroy(this);
- return NULL;
- }
- this->sockets->insert_last(this->sockets, socket);
- }
- return &this->public;
-}
diff --git a/src/libcharon/plugins/eap_radius/radius_server.h b/src/libcharon/plugins/eap_radius/radius_server.h
deleted file mode 100644
index c59361c49..000000000
--- a/src/libcharon/plugins/eap_radius/radius_server.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2010 Martin Willi
- * Copyright (C) 2010 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 radius_server radius_server
- * @{ @ingroup eap_radius
- */
-
-#ifndef RADIUS_SERVER_H_
-#define RADIUS_SERVER_H_
-
-typedef struct radius_server_t radius_server_t;
-
-#include "radius_socket.h"
-
-/**
- * RADIUS server configuration.
- */
-struct radius_server_t {
-
- /**
- * Get a RADIUS socket from the pool to communicate with this server.
- *
- * @return RADIUS socket
- */
- radius_socket_t* (*get_socket)(radius_server_t *this);
-
- /**
- * Release a socket to the pool after use.
- *
- * @param skt RADIUS socket to release
- * @param result result of the socket use, TRUE for success
- */
- void (*put_socket)(radius_server_t *this, radius_socket_t *skt, bool result);
-
- /**
- * Get the NAS-Identifier to use with this server.
- *
- * @return NAS-Identifier, internal data
- */
- chunk_t (*get_nas_identifier)(radius_server_t *this);
-
- /**
- * Get the preference of this server.
- *
- * Based on the available sockets and the server reachability a preference
- * value is calculated: better servers return a higher value.
- */
- int (*get_preference)(radius_server_t *this);
-
- /**
- * Get the name of the RADIUS server.
- *
- * @return server name
- */
- 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.
- */
- void (*destroy)(radius_server_t *this);
-};
-
-/**
- * Create a radius_server instance.
- *
- * @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 *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
deleted file mode 100644
index b3229c288..000000000
--- a/src/libcharon/plugins/eap_radius/radius_socket.c
+++ /dev/null
@@ -1,355 +0,0 @@
-/*
- * Copyright (C) 2010 Martin Willi
- * Copyright (C) 2010 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 "radius_socket.h"
-
-#include <errno.h>
-#include <unistd.h>
-
-#include <debug.h>
-
-/**
- * Vendor-Id of Microsoft specific attributes
- */
-#define VENDOR_ID_MICROSOFT 311
-
-/**
- * Microsoft specific vendor attributes
- */
-#define MS_MPPE_SEND_KEY 16
-#define MS_MPPE_RECV_KEY 17
-
-typedef struct private_radius_socket_t private_radius_socket_t;
-
-/**
- * Private data of an radius_socket_t object.
- */
-struct private_radius_socket_t {
-
- /**
- * Public radius_socket_t interface.
- */
- radius_socket_t public;
-
- /**
- * socket file descriptor
- */
- int fd;
-
- /**
- * Server address
- */
- char *address;
-
- /**
- * Server port
- */
- u_int16_t port;
-
- /**
- * current RADIUS identifier
- */
- u_int8_t identifier;
-
- /**
- * hasher to use for response verification
- */
- hasher_t *hasher;
-
- /**
- * HMAC-MD5 signer to build Message-Authenticator attribute
- */
- signer_t *signer;
-
- /**
- * random number generator for RADIUS request authenticator
- */
- rng_t *rng;
-
- /**
- * RADIUS secret
- */
- 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)
-{
- chunk_t data;
- int i;
-
- /* set Message Identifier */
- request->set_identifier(request, this->identifier++);
- /* 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++)
- {
- radius_message_t *response;
- bool retransmit = FALSE;
- struct timeval tv;
- char buf[4096];
- fd_set fds;
- int res;
-
- if (send(this->fd, data.ptr, data.len, 0) != data.len)
- {
- DBG1(DBG_CFG, "sending RADIUS message failed: %s", strerror(errno));
- return NULL;
- }
- tv.tv_sec = i;
- tv.tv_usec = 0;
-
- while (TRUE)
- {
- FD_ZERO(&fds);
- FD_SET(this->fd, &fds);
- res = select(this->fd + 1, &fds, NULL, NULL, &tv);
- /* TODO: updated tv to time not waited. Linux does this for us. */
- if (res < 0)
- { /* failed */
- DBG1(DBG_CFG, "waiting for RADIUS message failed: %s",
- strerror(errno));
- break;
- }
- if (res == 0)
- { /* timeout */
- DBG1(DBG_CFG, "retransmitting RADIUS message");
- retransmit = TRUE;
- break;
- }
- res = recv(this->fd, buf, sizeof(buf), MSG_DONTWAIT);
- if (res <= 0)
- {
- DBG1(DBG_CFG, "receiving RADIUS message failed: %s",
- strerror(errno));
- break;
- }
- response = radius_message_parse_response(chunk_create(buf, res));
- if (response)
- {
- if (response->verify(response,
- request->get_authenticator(request), this->secret,
- this->hasher, this->signer))
- {
- return response;
- }
- response->destroy(response);
- }
- DBG1(DBG_CFG, "received invalid RADIUS message, ignored");
- }
- if (!retransmit)
- {
- break;
- }
- }
- DBG1(DBG_CFG, "RADIUS server is not responding");
- return NULL;
-}
-
-/**
- * Decrypt a MS-MPPE-Send/Recv-Key
- */
-static chunk_t decrypt_mppe_key(private_radius_socket_t *this, u_int16_t salt,
- chunk_t C, radius_message_t *request)
-{
- chunk_t A, R, P, seed;
- u_char *c, *p;
-
- /**
- * From RFC2548 (encryption):
- * b(1) = MD5(S + R + A) c(1) = p(1) xor b(1) C = c(1)
- * b(2) = MD5(S + c(1)) c(2) = p(2) xor b(2) C = C + c(2)
- * . . .
- * b(i) = MD5(S + c(i-1)) c(i) = p(i) xor b(i) C = C + c(i)
- */
-
- if (C.len % HASH_SIZE_MD5 || C.len < HASH_SIZE_MD5)
- {
- return chunk_empty;
- }
-
- A = chunk_create((u_char*)&salt, sizeof(salt));
- R = chunk_create(request->get_authenticator(request), HASH_SIZE_MD5);
- P = chunk_alloca(C.len);
- p = P.ptr;
- c = C.ptr;
-
- seed = chunk_cata("cc", R, A);
-
- while (c < C.ptr + C.len)
- {
- /* b(i) = MD5(S + c(i-1)) */
- this->hasher->get_hash(this->hasher, this->secret, NULL);
- this->hasher->get_hash(this->hasher, seed, p);
-
- /* p(i) = b(i) xor c(1) */
- memxor(p, c, HASH_SIZE_MD5);
-
- /* prepare next round */
- seed = chunk_create(c, HASH_SIZE_MD5);
- c += HASH_SIZE_MD5;
- p += HASH_SIZE_MD5;
- }
-
- /* remove truncation, first byte is key length */
- if (*P.ptr >= P.len)
- { /* decryption failed? */
- return chunk_empty;
- }
- return chunk_clone(chunk_create(P.ptr + 1, *P.ptr));
-}
-
-METHOD(radius_socket_t, decrypt_msk, chunk_t,
- private_radius_socket_t *this, radius_message_t *request,
- radius_message_t *response)
-{
- struct {
- u_int32_t id;
- u_int8_t type;
- u_int8_t length;
- u_int16_t salt;
- u_int8_t key[];
- } __attribute__((packed)) *mppe_key;
- enumerator_t *enumerator;
- chunk_t data, send = chunk_empty, recv = chunk_empty;
- int type;
-
- enumerator = response->create_enumerator(response);
- while (enumerator->enumerate(enumerator, &type, &data))
- {
- if (type == RAT_VENDOR_SPECIFIC &&
- data.len > sizeof(*mppe_key))
- {
- mppe_key = (void*)data.ptr;
- if (ntohl(mppe_key->id) == VENDOR_ID_MICROSOFT &&
- mppe_key->length == data.len - sizeof(mppe_key->id))
- {
- data = chunk_create(mppe_key->key, data.len - sizeof(*mppe_key));
- if (mppe_key->type == MS_MPPE_SEND_KEY)
- {
- send = decrypt_mppe_key(this, mppe_key->salt, data, request);
- }
- if (mppe_key->type == MS_MPPE_RECV_KEY)
- {
- recv = decrypt_mppe_key(this, mppe_key->salt, data, request);
- }
- }
- }
- }
- enumerator->destroy(enumerator);
- if (send.ptr && recv.ptr)
- {
- return chunk_cat("mm", recv, send);
- }
- chunk_clear(&send);
- chunk_clear(&recv);
- return chunk_empty;
-}
-
-METHOD(radius_socket_t, destroy, void,
- private_radius_socket_t *this)
-{
- DESTROY_IF(this->hasher);
- DESTROY_IF(this->signer);
- DESTROY_IF(this->rng);
- if (this->fd != -1)
- {
- close(this->fd);
- }
- free(this);
-}
-
-/**
- * See header
- */
-radius_socket_t *radius_socket_create(char *address, u_int16_t port,
- chunk_t secret)
-{
- private_radius_socket_t *this;
-
- INIT(this,
- .public = {
- .request = _request,
- .decrypt_msk = _decrypt_msk,
- .destroy = _destroy,
- },
- .address = address,
- .port = port,
- .fd = -1,
- );
-
- 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);
- if (!this->hasher || !this->signer || !this->rng)
- {
- DBG1(DBG_CFG, "RADIUS initialization failed, HMAC/MD5/RNG required");
- destroy(this);
- return NULL;
- }
- this->secret = secret;
- this->signer->set_key(this->signer, secret);
- /* we use a random identifier, helps if we restart often */
- this->identifier = random();
-
- return &this->public;
-}
diff --git a/src/libcharon/plugins/eap_radius/radius_socket.h b/src/libcharon/plugins/eap_radius/radius_socket.h
deleted file mode 100644
index 2875008eb..000000000
--- a/src/libcharon/plugins/eap_radius/radius_socket.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2010 Martin Willi
- * Copyright (C) 2010 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 radius_socket radius_socket
- * @{ @ingroup eap_radius
- */
-
-#ifndef RADIUS_SOCKET_H_
-#define RADIUS_SOCKET_H_
-
-typedef struct radius_socket_t radius_socket_t;
-
-#include "radius_message.h"
-
-#include <utils/host.h>
-
-/**
- * RADIUS socket to a server.
- */
-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.
- * The received response gets verified using the Response-Identifier
- * and the Message-Authenticator attribute.
- *
- * @param request request message
- * @return response message, NULL if timed out
- */
- radius_message_t* (*request)(radius_socket_t *this,
- radius_message_t *request);
-
- /**
- * Decrypt the MSK encoded in a messages MS-MPPE-Send/Recv-Key.
- *
- * @param request associated RADIUS request message
- * @param response RADIUS response message containing attributes
- * @return allocated MSK, empty chunk if none found
- */
- chunk_t (*decrypt_msk)(radius_socket_t *this, radius_message_t *request,
- radius_message_t *response);
-
- /**
- * Destroy a radius_socket_t.
- */
- void (*destroy)(radius_socket_t *this);
-};
-
-/**
- * Create a radius_socket instance.
- *
- * @param address server name
- * @param port server port
- * @param secret RADIUS secret
- */
-radius_socket_t *radius_socket_create(char *address, u_int16_t port,
- chunk_t secret);
-
-#endif /** RADIUS_SOCKET_H_ @}*/