summaryrefslogtreecommitdiff
path: root/src/libradius/radius_client.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libradius/radius_client.c')
-rw-r--r--src/libradius/radius_client.c157
1 files changed, 157 insertions, 0 deletions
diff --git a/src/libradius/radius_client.c b/src/libradius/radius_client.c
new file mode 100644
index 000000000..acdac78c9
--- /dev/null
+++ b/src/libradius/radius_client.c
@@ -0,0 +1,157 @@
+/*
+ * 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 "radius_config.h"
+
+#include <unistd.h>
+#include <errno.h>
+
+#include <debug.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 configuration
+ */
+ radius_config_t *config;
+
+ /**
+ * 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;
+ chunk_t data;
+
+ /* 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->config->get_nas_identifier(this->config));
+ /* add State attribute, if server sent one */
+ if (this->state.ptr)
+ {
+ req->add(req, RAT_STATE, this->state);
+ }
+ socket = this->config->get_socket(this->config);
+ DBG1(DBG_CFG, "sending RADIUS %N to server '%s'", radius_message_code_names,
+ req->get_code(req), this->config->get_name(this->config));
+
+ 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->config->get_name(this->config));
+ data = res->get_encoding(res);
+ DBG3(DBG_CFG, "%B", &data);
+
+ 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->config->put_socket(this->config, socket, TRUE);
+ return res;
+ }
+ this->config->put_socket(this->config, socket, FALSE);
+ 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->config->destroy(this->config);
+ chunk_clear(&this->msk);
+ free(this->state.ptr);
+ free(this);
+}
+
+/**
+ * See header
+ */
+radius_client_t *radius_client_create(radius_config_t *config)
+{
+ private_radius_client_t *this;
+
+ INIT(this,
+ .public = {
+ .request = _request,
+ .get_msk = _get_msk,
+ .destroy = _destroy,
+ },
+ .config = config,
+ );
+
+ return &this->public;
+}