diff options
author | brian <brian@FreeBSD.org> | 1999-01-28 01:56:34 +0000 |
---|---|---|
committer | brian <brian@FreeBSD.org> | 1999-01-28 01:56:34 +0000 |
commit | c970e06ccf646c8d420b2216f605eefeef3cdc0d (patch) | |
tree | bb4ef8e30fe918a76dda062613ff6dce7f4acf28 /usr.sbin/ppp/radius.c | |
parent | bada4b37ff3f7d5effb75895357b4276798f82de (diff) | |
download | FreeBSD-src-c970e06ccf646c8d420b2216f605eefeef3cdc0d.zip FreeBSD-src-c970e06ccf646c8d420b2216f605eefeef3cdc0d.tar.gz |
Initial RADIUS support (using libradius). See the man page for
details. Compiling with -DNORADIUS (the default for `release')
removes support.
TODO: The functionality in libradius::rad_send_request() needs
to be supplied as a set of routines so that ppp doesn't
have to wait indefinitely for the radius server(s). Instead,
we need to get a descriptor back, select() on the descriptor,
and ask libradius to service it when necessary.
For now, ppp blocks SIGALRM while in rad_send_request(), so
it misses PAP/CHAP retries & timeouts if they occur.
Only PAP is functional. When CHAP is attempted, libradius
complains that no User-Password has been specified... rfc2138
says that it *mustn't* be used for CHAP :-(
Sponsored by: Internet Business Solutions Ltd., Switzerland
Diffstat (limited to 'usr.sbin/ppp/radius.c')
-rw-r--r-- | usr.sbin/ppp/radius.c | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/usr.sbin/ppp/radius.c b/usr.sbin/ppp/radius.c new file mode 100644 index 0000000..70611e4 --- /dev/null +++ b/usr.sbin/ppp/radius.c @@ -0,0 +1,287 @@ +/* + * Copyright 1999 Internet Business Solutions Ltd., Switzerland + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id:$ + * + */ + +#include <sys/param.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <arpa/inet.h> +#include <sys/un.h> + +#include <errno.h> +#include <radlib.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "defs.h" +#include "log.h" +#include "descriptor.h" +#include "prompt.h" +#include "timer.h" +#include "fsm.h" +#include "iplist.h" +#include "slcompress.h" +#include "throughput.h" +#include "lqr.h" +#include "hdlc.h" +#include "mbuf.h" +#include "ipcp.h" +#include "route.h" +#include "command.h" +#include "filter.h" +#include "server.h" +#include "lcp.h" +#include "ccp.h" +#include "link.h" +#include "mp.h" +#include "radius.h" +#include "bundle.h" + +void +radius_Init(struct radius *r) +{ + r->valid = 0; + *r->cfg.file = '\0';; +} + +void +radius_Destroy(struct radius *r) +{ + r->valid = 0; + route_DeleteAll(&r->routes); +} + +int +radius_Authenticate(struct radius *r, struct bundle *bundle, const char *name, + const char *key, const char *challenge) +{ + struct rad_handle *h; + sigset_t alrm, prevset; + const void *data; + int got, len, argc, addrs; + char *argv[MAXARGS], *nuke; + struct in_range dest; + struct in_addr gw; + + radius_Destroy(r); + + if (!*r->cfg.file) + return 0; + + if ((h = rad_open()) == NULL) { + log_Printf(LogERROR, "rad_open: %s\n", strerror(errno)); + return 0; + } + + if (rad_config(h, r->cfg.file) != 0) { + log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(h)); + rad_close(h); + return 0; + } + + if (rad_create_request(h, RAD_ACCESS_REQUEST) != 0) { + log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(h)); + rad_close(h); + return 0; + } + + if (rad_put_string(h, RAD_USER_NAME, name) != 0 || + rad_put_int(h, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 || + rad_put_int(h, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) { + log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(h)); + rad_close(h); + return 0; + } + + if (challenge != NULL) { /* CHAP */ + if (rad_put_string(h, RAD_CHAP_PASSWORD, key) != 0 || + rad_put_string(h, RAD_CHAP_CHALLENGE, challenge) != 0) { + log_Printf(LogERROR, "CHAP: rad_put_string: %s\n", rad_strerror(h)); + rad_close(h); + return 0; + } + } else if (rad_put_string(h, RAD_USER_PASSWORD, key) != 0) { /* PAP */ + /* We're talking PAP */ + log_Printf(LogERROR, "PAP: rad_put_string: %s\n", rad_strerror(h)); + rad_close(h); + return 0; + } + + /* + * Having to do this is bad news. The right way is to grab the + * descriptor that rad_send_request() selects on and add it to + * our own selection list (making a full ``struct descriptor''), + * then to ``continue'' the call when the descriptor is ready. + * This requires altering libradius.... + */ + sigemptyset(&alrm); + sigaddset(&alrm, SIGALRM); + sigprocmask(SIG_BLOCK, &alrm, &prevset); + got = rad_send_request(h); + sigprocmask(SIG_SETMASK, &prevset, NULL); + + switch (got) { + case RAD_ACCESS_ACCEPT: + break; + + case RAD_ACCESS_CHALLENGE: + /* we can't deal with this (for now) ! */ + log_Printf(LogPHASE, "Can't handle radius CHALLENGEs !\n"); + rad_close(h); + return 0; + + case -1: + log_Printf(LogPHASE, "radius: %s\n", rad_strerror(h)); + rad_close(h); + return 0; + + default: + log_Printf(LogERROR, "rad_send_request: Failed %d: %s\n", + got, rad_strerror(h)); + rad_close(h); + return 0; + + case RAD_ACCESS_REJECT: + log_Printf(LogPHASE, "radius: Rejected !\n"); + rad_close(h); + return 0; + } + + /* So we've been accepted ! Let's see what we've got in our reply :-I */ + r->ip.s_addr = r->mask.s_addr = INADDR_NONE; + r->mtu = 0; + r->vj = 0; + while ((got = rad_get_attr(h, &data, &len)) > 0) { + switch (got) { + case RAD_FRAMED_IP_ADDRESS: + r->ip = rad_cvt_addr(data); + log_Printf(LogDEBUG, "radius: Got IP %s\n", inet_ntoa(r->ip)); + break; + + case RAD_FRAMED_IP_NETMASK: + r->mask = rad_cvt_addr(data); + log_Printf(LogDEBUG, "radius: Got MASK %s\n", inet_ntoa(r->mask)); + break; + + case RAD_FRAMED_MTU: + r->mtu = rad_cvt_int(data); + log_Printf(LogDEBUG, "radius: Got MTU %lu\n", r->mtu); + break; + + case RAD_FRAMED_ROUTING: + /* Disabled for now - should we automatically set up some filters ? */ + /* rad_cvt_int(data); */ + /* bit 1 = Send routing packets */ + /* bit 2 = Receive routing packets */ + break; + + case RAD_FRAMED_COMPRESSION: + r->vj = rad_cvt_int(data) == 1 ? 1 : 0; + log_Printf(LogDEBUG, "radius: Got VJ %sabled\n", r->vj ? "en" : "dis"); + break; + + case RAD_FRAMED_ROUTE: + /* + * We expect a string of the format ``dest[/bits] gw [metrics]'' + * Any specified metrics are ignored. MYADDR and HISADDR are + * understood for ``dest'' and ``gw'' and ``0.0.0.0'' is the same + * as ``HISADDR''. + */ + + if ((nuke = rad_cvt_string(data, len)) == NULL) { + log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(h)); + rad_close(h); + return 0; + } + + dest.ipaddr.s_addr = dest.mask.s_addr = INADDR_ANY; + dest.width = 0; + argc = command_Interpret(nuke, strlen(nuke), argv); + if (argc < 2) + log_Printf(LogWARN, "radius: %s: Invalid route\n", + argc == 1 ? argv[0] : "\"\""); + else if ((strcasecmp(argv[0], "default") != 0 && + !ParseAddr(&bundle->ncp.ipcp, argv[0], &dest.ipaddr, + &dest.mask, &dest.width)) || + !ParseAddr(&bundle->ncp.ipcp, argv[1], &gw, NULL, NULL)) + log_Printf(LogWARN, "radius: %s %s: Invalid route\n", + argv[0], argv[1]); + else { + if (dest.width == 32 && strchr(argv[0], '/') == NULL) + /* No mask specified - use the natural mask */ + dest.mask.s_addr = addr2mask(dest.ipaddr.s_addr); + addrs = 0; + + if (!strncasecmp(argv[0], "HISADDR", 7)) + addrs = ROUTE_DSTHISADDR; + else if (!strncasecmp(argv[0], "MYADDR", 6)) + addrs = ROUTE_DSTMYADDR; + + if (gw.s_addr == INADDR_ANY) { + addrs |= ROUTE_GWHISADDR; + gw = bundle->ncp.ipcp.peer_ip; + } else if (strcasecmp(argv[1], "HISADDR") == 0) + addrs |= ROUTE_GWHISADDR; + + route_Add(&r->routes, addrs, dest.ipaddr, dest.mask, gw); + } + free(nuke); + break; + } + } + + if (got == -1) { + log_Printf(LogERROR, "rad_get_attr: %s\n", rad_strerror(h)); + rad_close(h); + return 0; + } + + log_Printf(LogPHASE, "radius: SUCCESS\n"); + + rad_close(h); + return r->valid = 1; +} + +void +radius_Show(struct radius *r, struct prompt *p) +{ + prompt_Printf(p, " Radius config: %s", *r->cfg.file ? r->cfg.file : "none"); + if (r->valid) { + prompt_Printf(p, "\n IP: %s\n", inet_ntoa(r->ip)); + prompt_Printf(p, " Netmask: %s\n", inet_ntoa(r->mask)); + prompt_Printf(p, " MTU: %lu\n", r->mtu); + prompt_Printf(p, " VJ: %sabled\n", r->vj ? "en" : "dis"); + if (r->routes) + route_ShowSticky(p, r->routes, " Routes", 16); + } else + prompt_Printf(p, " (not authenticated)\n"); +} |