summaryrefslogtreecommitdiff
path: root/src/libcharon/plugins/xauth_eap/xauth_eap.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/plugins/xauth_eap/xauth_eap.c')
-rw-r--r--src/libcharon/plugins/xauth_eap/xauth_eap.c289
1 files changed, 289 insertions, 0 deletions
diff --git a/src/libcharon/plugins/xauth_eap/xauth_eap.c b/src/libcharon/plugins/xauth_eap/xauth_eap.c
new file mode 100644
index 000000000..1da1d9f85
--- /dev/null
+++ b/src/libcharon/plugins/xauth_eap/xauth_eap.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2011 Martin Willi
+ * Copyright (C) 2011 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 "xauth_eap.h"
+
+#include <daemon.h>
+
+#include <library.h>
+#include <credentials/sets/callback_cred.h>
+
+typedef struct private_xauth_eap_t private_xauth_eap_t;
+
+/**
+ * Private data of an xauth_eap_t object.
+ */
+struct private_xauth_eap_t {
+
+ /**
+ * Public interface.
+ */
+ xauth_eap_t public;
+
+ /**
+ * ID of the server
+ */
+ identification_t *server;
+
+ /**
+ * ID of the peer
+ */
+ identification_t *peer;
+
+ /**
+ * Callback credential set
+ */
+ callback_cred_t *cred;
+
+ /**
+ * XAuth password
+ */
+ chunk_t pass;
+};
+
+/**
+ * Callback credential set function
+ */
+static shared_key_t* shared_cb(private_xauth_eap_t *this, shared_key_type_t type,
+ identification_t *me, identification_t *other,
+ id_match_t *match_me, id_match_t *match_other)
+{
+ shared_key_t *shared;
+
+ if (!this->pass.len)
+ {
+ return NULL;
+ }
+ if (type != SHARED_EAP && type != SHARED_ANY)
+ {
+ return NULL;
+ }
+ if (me)
+ {
+ if (!this->peer->equals(this->peer, me))
+ {
+ return NULL;
+ }
+ if (match_me)
+ {
+ *match_me = ID_MATCH_PERFECT;
+ }
+ }
+ else if (match_me)
+ {
+ *match_me = ID_MATCH_ANY;
+ }
+ if (other)
+ {
+ if (!this->server->equals(this->server, other))
+ {
+ return NULL;
+ }
+ if (match_other)
+ {
+ *match_other = ID_MATCH_PERFECT;
+ }
+ }
+ else if (match_other)
+ {
+ *match_other = ID_MATCH_ANY;
+ }
+ shared = shared_key_create(SHARED_EAP, chunk_clone(this->pass));
+ this->pass = chunk_empty;
+ return shared;
+}
+
+/**
+ * Do EAP exchanges to verify secret
+ */
+static bool verify_eap(private_xauth_eap_t *this, eap_method_t *backend)
+{
+ eap_payload_t *request, *response;
+ eap_method_t *frontend;
+ eap_type_t type;
+ u_int32_t vendor;
+ status_t status;
+
+ if (backend->initiate(backend, &request) != NEED_MORE)
+ {
+ return FALSE;
+ }
+ type = request->get_type(request, &vendor);
+ frontend = charon->eap->create_instance(charon->eap, type, vendor,
+ EAP_PEER, this->server, this->peer);
+ if (!frontend)
+ {
+ DBG1(DBG_IKE, "XAuth-EAP backend requested %N, but not supported",
+ eap_type_names, type);
+ request->destroy(request);
+ return FALSE;
+ }
+ while (TRUE)
+ {
+ /* credential set is active in frontend only, but not in backend */
+ lib->credmgr->add_local_set(lib->credmgr, &this->cred->set, TRUE);
+ status = frontend->process(frontend, request, &response);
+ lib->credmgr->remove_local_set(lib->credmgr, &this->cred->set);
+ request->destroy(request);
+ if (status != NEED_MORE)
+ { /* clients should never return SUCCESS */
+ frontend->destroy(frontend);
+ return FALSE;
+ }
+ status = backend->process(backend, response, &request);
+ response->destroy(response);
+ switch (status)
+ {
+ case SUCCESS:
+ frontend->destroy(frontend);
+ return TRUE;
+ case NEED_MORE:
+ break;
+ default:
+ frontend->destroy(frontend);
+ return FALSE;
+ }
+ }
+}
+
+METHOD(xauth_method_t, initiate, status_t,
+ private_xauth_eap_t *this, cp_payload_t **out)
+{
+ cp_payload_t *cp;
+
+ cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REQUEST);
+ cp->add_attribute(cp, configuration_attribute_create_chunk(
+ CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, chunk_empty));
+ cp->add_attribute(cp, configuration_attribute_create_chunk(
+ CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_PASSWORD, chunk_empty));
+ *out = cp;
+ return NEED_MORE;
+}
+
+METHOD(xauth_method_t, process, status_t,
+ private_xauth_eap_t *this, cp_payload_t *in, cp_payload_t **out)
+{
+ configuration_attribute_t *attr;
+ enumerator_t *enumerator;
+ identification_t *id;
+ chunk_t user = chunk_empty;
+ eap_method_t *backend;
+ eap_type_t type;
+ char *name;
+ bool ok;
+
+ enumerator = in->create_attribute_enumerator(in);
+ while (enumerator->enumerate(enumerator, &attr))
+ {
+ switch (attr->get_type(attr))
+ {
+ case XAUTH_USER_NAME:
+ user = attr->get_chunk(attr);
+ break;
+ case XAUTH_USER_PASSWORD:
+ this->pass = attr->get_chunk(attr);
+ break;
+ default:
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (!user.ptr || !this->pass.ptr)
+ {
+ DBG1(DBG_IKE, "peer did not respond to our XAuth request");
+ return FAILED;
+ }
+ if (user.len)
+ {
+ id = identification_create_from_data(user);
+ if (!id)
+ {
+ DBG1(DBG_IKE, "failed to parse provided XAuth username");
+ return FAILED;
+ }
+ this->peer->destroy(this->peer);
+ this->peer = id;
+ }
+ if (this->pass.len && this->pass.ptr[this->pass.len - 1] == 0)
+ { /* fix null-terminated passwords (Android etc.) */
+ this->pass.len -= 1;
+ }
+
+ name = lib->settings->get_str(lib->settings,
+ "%s.plugins.xauth-eap.backend", "radius",
+ charon->name);
+ type = eap_type_from_string(name);
+ if (!type)
+ {
+ DBG1(DBG_CFG, "Unknown XAuth-EAP method: %s", name);
+ return FAILED;
+ }
+ backend = charon->eap->create_instance(charon->eap, type, 0, EAP_SERVER,
+ this->server, this->peer);
+ if (!backend)
+ {
+ DBG1(DBG_CFG, "XAuth-EAP method backend not supported: %s", name);
+ return FAILED;
+ }
+ ok = verify_eap(this, backend);
+ backend->destroy(backend);
+ if (ok)
+ {
+ return SUCCESS;
+ }
+ return FAILED;
+}
+
+METHOD(xauth_method_t, get_identity, identification_t*,
+ private_xauth_eap_t *this)
+{
+ return this->peer;
+}
+
+METHOD(xauth_method_t, destroy, void,
+ private_xauth_eap_t *this)
+{
+ this->cred->destroy(this->cred);
+ this->server->destroy(this->server);
+ this->peer->destroy(this->peer);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+xauth_eap_t *xauth_eap_create_server(identification_t *server,
+ identification_t *peer)
+{
+ private_xauth_eap_t *this;
+
+ INIT(this,
+ .public = {
+ .xauth_method = {
+ .initiate = _initiate,
+ .process = _process,
+ .get_identity = _get_identity,
+ .destroy = _destroy,
+ },
+ },
+ .server = server->clone(server),
+ .peer = peer->clone(peer),
+ );
+
+ this->cred = callback_cred_create_shared((void*)shared_cb, this);
+
+ return &this->public;
+}