From: Alan T. DeKok Date: Wed, 3 May 2017 18:57:36 +0000 (-0400) Subject: added radius_server_udp X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ef86409f24f69910c18ecdb7ca7b7fe567fd82b5;p=thirdparty%2Ffreeradius-server.git added radius_server_udp in src/lib/io for now, until we go clean up the rest of the code --- diff --git a/src/lib/io/all.mk b/src/lib/io/all.mk index 4d986c6b5e4..d8720620063 100644 --- a/src/lib/io/all.mk +++ b/src/lib/io/all.mk @@ -1,7 +1,7 @@ TARGET := libfreeradius-io.a SOURCES := ring_buffer.c message.c atomic_queue.c queue.c time.c channel.c track.c worker.c \ - schedule.c network.c control.c + schedule.c network.c control.c radius_server_udp.c TGT_PREREQS := libfreeradius-util.la TGT_LDLIBS := $(LIBS) diff --git a/src/lib/io/radius_server_udp.c b/src/lib/io/radius_server_udp.c new file mode 100644 index 00000000000..98bd6a66423 --- /dev/null +++ b/src/lib/io/radius_server_udp.c @@ -0,0 +1,155 @@ +/* + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * $Id$ + * + * @brief RADIUS Server UDP front-end + * @file io/radius_server_udp.c + * + * @copyright 2017 Alan DeKok + */ +RCSID("$Id$") + +#include +#include +#include +#include +#include +#include +#include + +#ifndef RDEBUG +#define RDEBUG(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__) +#endif + +#ifndef DEBUG +#define DEBUG(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__) +#endif + +typedef struct fr_packet_ctx_t { + int sockfd; + + uint8_t const *secret; + size_t secret_len; + + uint8_t original[20]; + uint8_t id; + + struct sockaddr_storage src; + socklen_t salen; +} fr_packet_ctx_t; + + +static int mod_decode(void const *ctx, uint8_t *const data, size_t data_len, REQUEST *request) +{ + fr_packet_ctx_t const *pc = ctx; + + RDEBUG("\t\tDECODE <<< request %zd - %p data %p size %zd\n", request->number, pc, data, data_len); + + return 0; +} + +static ssize_t mod_encode(void const *ctx, REQUEST *request, uint8_t *buffer, size_t buffer_len) +{ + fr_packet_ctx_t const *pc = ctx; + + RDEBUG("\t\tENCODE >>> request %zd - data %p %p room %zd\n", request->number, pc, buffer, buffer_len); + + buffer[0] = PW_CODE_ACCESS_ACCEPT; + buffer[1] = pc->id; + buffer[2] = 0; + buffer[3] = 20; + + (void) fr_radius_sign(buffer, pc->original, pc->secret, pc->secret_len); + + return 20; +} + +static size_t mod_nak(void const *ctx, uint8_t *const packet, size_t packet_len, UNUSED uint8_t *reply, UNUSED size_t reply_len) +{ + DEBUG("\t\tNAK !!! request %d - data %p %p size %zd\n", packet[1], ctx, packet, packet_len); + + return 10; +} + +static fr_transport_final_t mod_process(REQUEST *request, fr_transport_action_t action) +{ + RDEBUG("\t\tPROCESS --- request %zd action %d\n", request->number, action); + + return FR_TRANSPORT_REPLY; +} + +static ssize_t mod_read(int sockfd, void *ctx, uint8_t *buffer, size_t buffer_len) +{ + ssize_t data_size; + size_t packet_len; + fr_packet_ctx_t *pc = ctx; + decode_fail_t reason; + + pc->salen = sizeof(pc->src); + + data_size = recvfrom(sockfd, buffer, buffer_len, 0, (struct sockaddr *) &pc->src, &pc->salen); + if (data_size <= 0) return data_size; + + packet_len = data_size; + if (!fr_radius_ok(buffer, &packet_len, false, &reason)) { + return 0; + } + + if (!fr_radius_verify(buffer, NULL, pc->secret, pc->secret_len)) { + return 0; + } + + pc->id = buffer[1]; + memcpy(pc->original, buffer, sizeof(pc->original)); + + return packet_len; +} + + +static ssize_t mod_write(int sockfd, void *ctx, uint8_t *buffer, size_t buffer_len) +{ + ssize_t data_size; + fr_packet_ctx_t *pc = ctx; + + pc->salen = sizeof(pc->src); + + /* + * @todo - do more stuff + */ + data_size = sendto(sockfd, buffer, buffer_len, 0, (struct sockaddr *) &pc->src, pc->salen); + if (data_size <= 0) return data_size; + + /* + * @todo - post-write cleanups + */ + + return data_size; +} + +extern fr_transport_t fr_radius_server_udp; +fr_transport_t fr_radius_server_udp = { + .name = "radius_server_udp", + .id = 1, /* @todo fix me later */ + .default_message_size = 4096, + .read = mod_read, + .write = mod_write, + .decode = mod_decode, + .encode = mod_encode, + .nak = mod_nak, + .process = mod_process +}; diff --git a/src/protocols/radius/radius.h b/src/protocols/radius/radius.h new file mode 100644 index 00000000000..8392c7bb90a --- /dev/null +++ b/src/protocols/radius/radius.h @@ -0,0 +1,64 @@ +/* + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ +#ifndef _FR_RADIUS_RADIUS_H +#define _FR_RADIUS_RADIUS_H +/* + * $Id$ + * + * @file radius/radius.h + * @brief Structures and prototypes for base RADIUS functionality. + * + * @copyright 1999-2017 The FreeRADIUS server project + */ + +/* + * protocols/radius/base.c + */ +#define AUTH_PASS_LEN (AUTH_VECTOR_LEN) +#define MAX_PASS_LEN (128) +#define FR_TUNNEL_PW_ENC_LENGTH(_x) (2 + 1 + _x + PAD(_x + 1, 16)) +extern FR_NAME_NUMBER const fr_request_types[]; + +typedef enum { + DECODE_FAIL_NONE = 0, + DECODE_FAIL_MIN_LENGTH_PACKET, + DECODE_FAIL_MIN_LENGTH_FIELD, + DECODE_FAIL_MIN_LENGTH_MISMATCH, + DECODE_FAIL_HEADER_OVERFLOW, + DECODE_FAIL_UNKNOWN_PACKET_CODE, + DECODE_FAIL_INVALID_ATTRIBUTE, + DECODE_FAIL_ATTRIBUTE_TOO_SHORT, + DECODE_FAIL_ATTRIBUTE_OVERFLOW, + DECODE_FAIL_MA_INVALID_LENGTH, + DECODE_FAIL_ATTRIBUTE_UNDERFLOW, + DECODE_FAIL_TOO_MANY_ATTRIBUTES, + DECODE_FAIL_MA_MISSING, + DECODE_FAIL_MAX +} decode_fail_t; + +int fr_radius_sign(uint8_t *packet, uint8_t const *original, + uint8_t const *secret, size_t secret_len) CC_HINT(nonnull (1,3)); +int fr_radius_verify(uint8_t *packet, uint8_t const *original, + uint8_t const *secret, size_t secret_len) CC_HINT(nonnull (1,3)); +bool fr_radius_ok(uint8_t const *packet, size_t *packet_len_p, bool require_ma, + decode_fail_t *reason) CC_HINT(nonnull (1,2)); + +void fr_radius_ascend_secret(uint8_t *digest, uint8_t const *vector, + char const *secret, uint8_t const *value) CC_HINT(nonnull); + +ssize_t fr_radius_recv_header(int sockfd, fr_ipaddr_t *src_ipaddr, uint16_t *src_port, unsigned int *code); + +#endif /* _FR_RADIUS_RADIUS_H */