diff options
author | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2010-05-27 15:43:45 +0000 |
---|---|---|
committer | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2010-05-27 15:43:45 +0000 |
commit | 6c2828d075efdfc02348369149b4347447857c8c (patch) | |
tree | 6c9ec7c9f342792e5eb2c2973daa7bbbeb45362e /src/charon/plugins/eap_radius/radius_client.c | |
parent | cc7f376e575482c9a4866a4bd0c1f470394d740b (diff) | |
download | vyos-strongswan-6c2828d075efdfc02348369149b4347447857c8c.tar.gz vyos-strongswan-6c2828d075efdfc02348369149b4347447857c8c.zip |
Remove leftovers after source code restructuring.
Diffstat (limited to 'src/charon/plugins/eap_radius/radius_client.c')
-rw-r--r-- | src/charon/plugins/eap_radius/radius_client.c | 495 |
1 files changed, 0 insertions, 495 deletions
diff --git a/src/charon/plugins/eap_radius/radius_client.c b/src/charon/plugins/eap_radius/radius_client.c deleted file mode 100644 index 1d1f21742..000000000 --- a/src/charon/plugins/eap_radius/radius_client.c +++ /dev/null @@ -1,495 +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 <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> - -/** - * Default RADIUS server port, when not configured - */ -#define RADIUS_PORT 1812 - -/** - * 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_client_t private_radius_client_t; - -typedef struct entry_t entry_t; - -/** - * A socket pool entry. - */ -struct entry_t { - /** socket file descriptor */ - int fd; - /** 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; -}; - -/** - * Private data of an radius_client_t object. - */ -struct private_radius_client_t { - - /** - * Public radius_client_t interface. - */ - radius_client_t public; - - /** - * RADIUS servers State attribute - */ - chunk_t state; -}; - -/** - * Global list of radius sockets, contains entry_t's - */ -static linked_list_t *sockets; - -/** - * mutex to lock sockets list - */ -static mutex_t *mutex; - -/** - * condvar to wait for sockets - */ -static condvar_t *condvar; - -/** - * RADIUS secret - */ -static chunk_t secret; - -/** - * NAS-Identifier - */ -static chunk_t nas_identifier; - -/** - * Clean up socket list - */ -void radius_client_cleanup() -{ - entry_t *entry; - - mutex->destroy(mutex); - condvar->destroy(condvar); - while (sockets->remove_last(sockets, (void**)&entry) == SUCCESS) - { - entry->rng->destroy(entry->rng); - entry->hasher->destroy(entry->hasher); - entry->signer->destroy(entry->signer); - close(entry->fd); - free(entry); - } - sockets->destroy(sockets); -} - -/** - * Initialize the socket list - */ -bool radius_client_init() -{ - int i, count, fd; - u_int16_t port; - entry_t *entry; - host_t *host; - char *server; - - nas_identifier.ptr = lib->settings->get_str(lib->settings, - "charon.plugins.eap-radius.nas_identifier", "strongSwan"); - nas_identifier.len = strlen(nas_identifier.ptr); - - secret.ptr = lib->settings->get_str(lib->settings, - "charon.plugins.eap-radius.secret", NULL); - if (!secret.ptr) - { - DBG1(DBG_CFG, "no RADUIS secret defined"); - return FALSE; - } - secret.len = strlen(secret.ptr); - server = lib->settings->get_str(lib->settings, - "charon.plugins.eap-radius.server", NULL); - if (!server) - { - DBG1(DBG_CFG, "no RADUIS server defined"); - return FALSE; - } - port = lib->settings->get_int(lib->settings, - "charon.plugins.eap-radius.port", RADIUS_PORT); - host = host_create_from_dns(server, 0, port); - if (!host) - { - return FALSE; - } - count = lib->settings->get_int(lib->settings, - "charon.plugins.eap-radius.sockets", 1); - - sockets = linked_list_create(); - mutex = mutex_create(MUTEX_TYPE_DEFAULT); - condvar = condvar_create(CONDVAR_TYPE_DEFAULT); - for (i = 0; i < count; i++) - { - fd = socket(host->get_family(host), SOCK_DGRAM, IPPROTO_UDP); - if (fd < 0) - { - DBG1(DBG_CFG, "opening RADIUS socket failed"); - host->destroy(host); - radius_client_cleanup(); - return FALSE; - } - if (connect(fd, host->get_sockaddr(host), - *host->get_sockaddr_len(host)) < 0) - { - DBG1(DBG_CFG, "connecting RADIUS socket failed"); - host->destroy(host); - radius_client_cleanup(); - return FALSE; - } - entry = malloc_thing(entry_t); - entry->fd = fd; - /* we use per-socket crypto elements: this reduces overhead, but - * is still thread-save. */ - entry->hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5); - entry->signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_MD5_128); - entry->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - if (!entry->hasher || !entry->signer || !entry->rng) - { - DBG1(DBG_CFG, "RADIUS initialization failed, HMAC/MD5/RNG required"); - DESTROY_IF(entry->hasher); - DESTROY_IF(entry->signer); - DESTROY_IF(entry->rng); - free(entry); - host->destroy(host); - radius_client_cleanup(); - return FALSE; - } - entry->signer->set_key(entry->signer, secret); - /* we use a random identifier, helps if we restart often (testing) */ - entry->identifier = random(); - sockets->insert_last(sockets, entry); - } - host->destroy(host); - return TRUE; -} - -/** - * Get a socket from the pool, block if none available - */ -static entry_t* get_socket() -{ - entry_t *entry; - - mutex->lock(mutex); - while (sockets->remove_first(sockets, (void**)&entry) != SUCCESS) - { - condvar->wait(condvar, mutex); - } - mutex->unlock(mutex); - return entry; -} - -/** - * Release a socket to the pool - */ -static void put_socket(entry_t *entry) -{ - mutex->lock(mutex); - sockets->insert_last(sockets, entry); - mutex->unlock(mutex); - condvar->signal(condvar); -} - -/** - * 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); -} - -/** - * Implementation of radius_client_t.request - */ -static radius_message_t* request(private_radius_client_t *this, - radius_message_t *req) -{ - char virtual[] = {0x00,0x00,0x00,0x05}; - entry_t *socket; - chunk_t data; - int i; - - socket = get_socket(); - - /* set Message Identifier */ - req->set_identifier(req, socket->identifier++); - /* 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, nas_identifier); - /* add State attribute, if server sent one */ - if (this->state.ptr) - { - req->add(req, RAT_STATE, this->state); - } - /* sign the request */ - req->sign(req, socket->rng, socket->signer); - - data = req->get_encoding(req); - /* 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(socket->fd, data.ptr, data.len, 0) != data.len) - { - DBG1(DBG_CFG, "sending RADIUS message failed: %s", strerror(errno)); - put_socket(socket); - return NULL; - } - tv.tv_sec = i; - tv.tv_usec = 0; - - while (TRUE) - { - FD_ZERO(&fds); - FD_SET(socket->fd, &fds); - res = select(socket->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(socket->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, req->get_authenticator(req), - secret, socket->hasher, socket->signer)) - { - save_state(this, response); - put_socket(socket); - return response; - } - response->destroy(response); - } - DBG1(DBG_CFG, "received invalid RADIUS message, ignored"); - } - if (!retransmit) - { - break; - } - } - DBG1(DBG_CFG, "RADIUS server is not responding"); - put_socket(socket); - charon->bus->alert(charon->bus, ALERT_RADIUS_NOT_RESPONDING); - return NULL; -} - -/** - * Decrypt a MS-MPPE-Send/Recv-Key - */ -static chunk_t decrypt_mppe_key(private_radius_client_t *this, u_int16_t salt, - chunk_t C, radius_message_t *request) -{ - chunk_t A, R, P, seed; - u_char *c, *p; - hasher_t *hasher; - - /** - * 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; - } - - hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5); - if (!hasher) - { - 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)) */ - hasher->get_hash(hasher, secret, NULL); - hasher->get_hash(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; - } - hasher->destroy(hasher); - - /* 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)); -} - -/** - * Implementation of radius_client_t.decrypt_msk - */ -static chunk_t decrypt_msk(private_radius_client_t *this, - radius_message_t *response, radius_message_t *request) -{ - 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; -} - -/** - * Implementation of radius_client_t.destroy. - */ -static void destroy(private_radius_client_t *this) -{ - free(this->state.ptr); - free(this); -} - -/** - * See header - */ -radius_client_t *radius_client_create() -{ - private_radius_client_t *this = malloc_thing(private_radius_client_t); - - this->public.request = (radius_message_t*(*)(radius_client_t*, radius_message_t *msg))request; - this->public.decrypt_msk = (chunk_t(*)(radius_client_t*, radius_message_t *, radius_message_t *))decrypt_msk; - this->public.destroy = (void(*)(radius_client_t*))destroy; - - this->state = chunk_empty; - - return &this->public; -} - |