diff options
Diffstat (limited to 'src/libcharon/plugins/eap_radius/eap_radius_xauth.c')
| -rw-r--r-- | src/libcharon/plugins/eap_radius/eap_radius_xauth.c | 202 | 
1 files changed, 202 insertions, 0 deletions
| diff --git a/src/libcharon/plugins/eap_radius/eap_radius_xauth.c b/src/libcharon/plugins/eap_radius/eap_radius_xauth.c new file mode 100644 index 000000000..bd960d2bc --- /dev/null +++ b/src/libcharon/plugins/eap_radius/eap_radius_xauth.c @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 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_xauth.h" +#include "eap_radius_plugin.h" +#include "eap_radius.h" +#include "eap_radius_forward.h" + +#include <daemon.h> +#include <radius_client.h> + + +typedef struct private_eap_radius_xauth_t private_eap_radius_xauth_t; + +/** + * Private data of an eap_radius_xauth_t object. + */ +struct private_eap_radius_xauth_t { + +	/** +	 * Public interface. +	 */ +	eap_radius_xauth_t public; + +	/** +	 * ID of the server +	 */ +	identification_t *server; + +	/** +	 * ID of the peer +	 */ +	identification_t *peer; + +	/** +	 * RADIUS connection +	 */ +	radius_client_t *client; +}; + +METHOD(xauth_method_t, initiate, status_t, +	private_eap_radius_xauth_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; +} + +/** + * Verify a password using RADIUS User-Name/User-Password attributes + */ +static status_t verify_radius(private_eap_radius_xauth_t *this, chunk_t pass) +{ +	radius_message_t *request, *response; +	status_t status = FAILED; + +	request = radius_message_create(RMC_ACCESS_REQUEST); +	request->add(request, RAT_USER_NAME, this->peer->get_encoding(this->peer)); +	request->add(request, RAT_USER_PASSWORD, pass); + +	eap_radius_build_attributes(request); +	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_ACCEPT: +				eap_radius_process_attributes(response); +				status = SUCCESS; +				break; +			case RMC_ACCESS_CHALLENGE: +				DBG1(DBG_IKE, "RADIUS Access-Challenge not supported"); +				/* FALL */ +			case RMC_ACCESS_REJECT: +			default: +				DBG1(DBG_IKE, "RADIUS authentication of '%Y' failed", +					 this->peer); +				break; +		} +		response->destroy(response); +	} +	else +	{ +		eap_radius_handle_timeout(NULL); +	} +	request->destroy(request); +	return status; +} + +METHOD(xauth_method_t, process, status_t, +	private_eap_radius_xauth_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, pass = chunk_empty; + +	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); +				/* trim password to any null termination. As User-Password +				 * uses null padding, we can't have any null in it, and some +				 * clients actually send null terminated strings (Android). */ +				pass.len = strnlen(pass.ptr, pass.len); +				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; +	} +	return verify_radius(this, pass); +} + +METHOD(xauth_method_t, get_identity, identification_t*, +	private_eap_radius_xauth_t *this) +{ +	return this->peer; +} + +METHOD(xauth_method_t, destroy, void, +	private_eap_radius_xauth_t *this) +{ +	DESTROY_IF(this->client); +	this->server->destroy(this->server); +	this->peer->destroy(this->peer); +	free(this); +} + +/* + * Described in header. + */ +eap_radius_xauth_t *eap_radius_xauth_create_server(identification_t *server, +												   identification_t *peer) +{ +	private_eap_radius_xauth_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), +		.client = eap_radius_create_client(), +	); + +	if (!this->client) +	{ +		destroy(this); +		return NULL; +	} +	return &this->public; +} | 
