/* * Copyright (C) 2011 Tobias Brunner * 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 . * * 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_generic.h" #include #include typedef struct private_xauth_generic_t private_xauth_generic_t; /** * Private data of an xauth_generic_t object. */ struct private_xauth_generic_t { /** * Public interface. */ xauth_generic_t public; /** * ID of the server */ identification_t *server; /** * ID of the peer */ identification_t *peer; }; METHOD(xauth_method_t, initiate_peer, status_t, private_xauth_generic_t *this, cp_payload_t **out) { /* peer never initiates */ return FAILED; } METHOD(xauth_method_t, process_peer, status_t, private_xauth_generic_t *this, cp_payload_t *in, cp_payload_t **out) { configuration_attribute_t *attr; enumerator_t *enumerator; shared_key_t *shared; cp_payload_t *cp; chunk_t msg; enumerator = in->create_attribute_enumerator(in); while (enumerator->enumerate(enumerator, &attr)) { if (attr->get_type(attr) == XAUTH_MESSAGE) { chunk_printable(attr->get_chunk(attr), &msg, '?'); DBG1(DBG_CFG, "XAuth message: %.*s", (int)msg.len, msg.ptr); free(msg.ptr); } } enumerator->destroy(enumerator); cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_REPLY); enumerator = in->create_attribute_enumerator(in); while (enumerator->enumerate(enumerator, &attr)) { shared_key_type_t type = SHARED_EAP; switch (attr->get_type(attr)) { case XAUTH_USER_NAME: cp->add_attribute(cp, configuration_attribute_create_chunk( PLV1_CONFIGURATION_ATTRIBUTE, XAUTH_USER_NAME, this->peer->get_encoding(this->peer))); break; case XAUTH_NEXT_PIN: type = SHARED_PIN; /* FALL */ case XAUTH_USER_PASSWORD: #ifdef NETAPP shared = lib->credmgr->get_shared(lib->credmgr, type, this->peer, this->server, -1); #else /* !NETAPP */ shared = lib->credmgr->get_shared(lib->credmgr, type, this->peer, this->server); #endif /* NETAPP */ if (!shared) { DBG1(DBG_IKE, "no XAuth %s found for '%Y' - '%Y'", type == SHARED_EAP ? "password" : "PIN", this->peer, this->server); enumerator->destroy(enumerator); cp->destroy(cp); return FAILED; } cp->add_attribute(cp, configuration_attribute_create_chunk( PLV1_CONFIGURATION_ATTRIBUTE, attr->get_type(attr), shared->get_key(shared))); shared->destroy(shared); break; default: break; } } enumerator->destroy(enumerator); *out = cp; return NEED_MORE; } METHOD(xauth_method_t, initiate_server, status_t, private_xauth_generic_t *this, cp_payload_t **out) { cp_payload_t *cp; cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_REQUEST); cp->add_attribute(cp, configuration_attribute_create_chunk( PLV1_CONFIGURATION_ATTRIBUTE, XAUTH_USER_NAME, chunk_empty)); cp->add_attribute(cp, configuration_attribute_create_chunk( PLV1_CONFIGURATION_ATTRIBUTE, XAUTH_USER_PASSWORD, chunk_empty)); *out = cp; return NEED_MORE; } METHOD(xauth_method_t, process_server, status_t, private_xauth_generic_t *this, cp_payload_t *in, cp_payload_t **out) { configuration_attribute_t *attr; enumerator_t *enumerator; shared_key_t *shared; identification_t *id; chunk_t user = chunk_empty, pass = chunk_empty; status_t status = FAILED; int tried = 0; 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: pass = attr->get_chunk(attr); break; default: break; } } enumerator->destroy(enumerator); if (!user.ptr || !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 (pass.len && pass.ptr[pass.len - 1] == 0) { /* fix null-terminated passwords (Android etc.) */ pass.len -= 1; } #ifdef NETAPP enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr, SHARED_EAP, this->server, this->peer, -1); #else /* !NETAPP */ enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr, SHARED_EAP, this->server, this->peer); #endif /* NETAPP */ while (enumerator->enumerate(enumerator, &shared, NULL, NULL)) { if (chunk_equals_const(shared->get_key(shared), pass)) { status = SUCCESS; break; } tried++; } enumerator->destroy(enumerator); if (status != SUCCESS) { if (!tried) { DBG1(DBG_IKE, "no XAuth secret found for '%Y' - '%Y'", this->server, this->peer); } else { DBG1(DBG_IKE, "none of %d found XAuth secrets for '%Y' - '%Y' " "matched", tried, this->server, this->peer); } } return status; } METHOD(xauth_method_t, get_identity, identification_t*, private_xauth_generic_t *this) { return this->peer; } METHOD(xauth_method_t, destroy, void, private_xauth_generic_t *this) { this->server->destroy(this->server); this->peer->destroy(this->peer); free(this); } /* * Described in header. */ xauth_generic_t *xauth_generic_create_peer(identification_t *server, identification_t *peer, char *profile) { private_xauth_generic_t *this; INIT(this, .public = { .xauth_method = { .initiate = _initiate_peer, .process = _process_peer, .get_identity = _get_identity, .destroy = _destroy, }, }, .server = server->clone(server), .peer = peer->clone(peer), ); return &this->public; } /* * Described in header. */ xauth_generic_t *xauth_generic_create_server(identification_t *server, identification_t *peer, char *profile) { private_xauth_generic_t *this; INIT(this, .public = { .xauth_method = { .initiate = _initiate_server, .process = _process_server, .get_identity = _get_identity, .destroy = _destroy, }, }, .server = server->clone(server), .peer = peer->clone(peer), ); return &this->public; }