1972a1bcfSBrian Somers /* 2972a1bcfSBrian Somers * Copyright 1999 Internet Business Solutions Ltd., Switzerland 3972a1bcfSBrian Somers * All rights reserved. 4972a1bcfSBrian Somers * 5972a1bcfSBrian Somers * Redistribution and use in source and binary forms, with or without 6972a1bcfSBrian Somers * modification, are permitted provided that the following conditions 7972a1bcfSBrian Somers * are met: 8972a1bcfSBrian Somers * 1. Redistributions of source code must retain the above copyright 9972a1bcfSBrian Somers * notice, this list of conditions and the following disclaimer. 10972a1bcfSBrian Somers * 2. Redistributions in binary form must reproduce the above copyright 11972a1bcfSBrian Somers * notice, this list of conditions and the following disclaimer in the 12972a1bcfSBrian Somers * documentation and/or other materials provided with the distribution. 13972a1bcfSBrian Somers * 14972a1bcfSBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15972a1bcfSBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16972a1bcfSBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17972a1bcfSBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18972a1bcfSBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19972a1bcfSBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20972a1bcfSBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21972a1bcfSBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22972a1bcfSBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23972a1bcfSBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24972a1bcfSBrian Somers * SUCH DAMAGE. 25972a1bcfSBrian Somers * 2697d92980SPeter Wemm * $FreeBSD$ 27972a1bcfSBrian Somers * 28972a1bcfSBrian Somers */ 29972a1bcfSBrian Somers 30972a1bcfSBrian Somers #include <sys/param.h> 316b457978SBrian Somers #include <sys/socket.h> 32972a1bcfSBrian Somers #include <netinet/in_systm.h> 33972a1bcfSBrian Somers #include <netinet/in.h> 34972a1bcfSBrian Somers #include <netinet/ip.h> 35972a1bcfSBrian Somers #include <arpa/inet.h> 36972a1bcfSBrian Somers #include <sys/un.h> 376b457978SBrian Somers #include <net/route.h> 38972a1bcfSBrian Somers 3910e629b9SBrian Somers #ifdef LOCALRAD 4010e629b9SBrian Somers #include "radlib.h" 4110e629b9SBrian Somers #else 42972a1bcfSBrian Somers #include <radlib.h> 4310e629b9SBrian Somers #endif 4410e629b9SBrian Somers 4510e629b9SBrian Somers #include <errno.h> 46972a1bcfSBrian Somers #include <stdio.h> 47972a1bcfSBrian Somers #include <stdlib.h> 48972a1bcfSBrian Somers #include <string.h> 49f0cdd9c0SBrian Somers #include <sys/time.h> 50972a1bcfSBrian Somers #include <termios.h> 51f10f5203SBrian Somers #include <ttyent.h> 52f10f5203SBrian Somers #include <unistd.h> 53f10f5203SBrian Somers #include <netdb.h> 54972a1bcfSBrian Somers 555d9e6103SBrian Somers #include "layer.h" 56972a1bcfSBrian Somers #include "defs.h" 57972a1bcfSBrian Somers #include "log.h" 58972a1bcfSBrian Somers #include "descriptor.h" 59972a1bcfSBrian Somers #include "prompt.h" 60972a1bcfSBrian Somers #include "timer.h" 61972a1bcfSBrian Somers #include "fsm.h" 62972a1bcfSBrian Somers #include "iplist.h" 63972a1bcfSBrian Somers #include "slcompress.h" 64972a1bcfSBrian Somers #include "throughput.h" 65972a1bcfSBrian Somers #include "lqr.h" 66972a1bcfSBrian Somers #include "hdlc.h" 67972a1bcfSBrian Somers #include "mbuf.h" 6830949fd4SBrian Somers #include "ncpaddr.h" 6930949fd4SBrian Somers #include "ip.h" 70972a1bcfSBrian Somers #include "ipcp.h" 7130949fd4SBrian Somers #include "ipv6cp.h" 72972a1bcfSBrian Somers #include "route.h" 73972a1bcfSBrian Somers #include "command.h" 74972a1bcfSBrian Somers #include "filter.h" 75972a1bcfSBrian Somers #include "lcp.h" 76972a1bcfSBrian Somers #include "ccp.h" 77972a1bcfSBrian Somers #include "link.h" 78972a1bcfSBrian Somers #include "mp.h" 79972a1bcfSBrian Somers #include "radius.h" 80f0cdd9c0SBrian Somers #include "auth.h" 81f0cdd9c0SBrian Somers #include "async.h" 82f0cdd9c0SBrian Somers #include "physical.h" 83f0cdd9c0SBrian Somers #include "chat.h" 84f0cdd9c0SBrian Somers #include "cbcp.h" 85f0cdd9c0SBrian Somers #include "chap.h" 86f0cdd9c0SBrian Somers #include "datalink.h" 8730949fd4SBrian Somers #include "ncp.h" 88972a1bcfSBrian Somers #include "bundle.h" 89972a1bcfSBrian Somers 90f0cdd9c0SBrian Somers /* 91f0cdd9c0SBrian Somers * rad_continue_send_request() has given us `got' (non-zero). Deal with it. 92f0cdd9c0SBrian Somers */ 93f0cdd9c0SBrian Somers static void 94f0cdd9c0SBrian Somers radius_Process(struct radius *r, int got) 95972a1bcfSBrian Somers { 96972a1bcfSBrian Somers char *argv[MAXARGS], *nuke; 97f0cdd9c0SBrian Somers struct bundle *bundle; 9830949fd4SBrian Somers int argc, addrs, width; 9928e610e3SBrian Somers size_t len; 10030949fd4SBrian Somers struct ncprange dest; 10130949fd4SBrian Somers struct ncpaddr gw; 102f0cdd9c0SBrian Somers const void *data; 103c42627ffSBrian Somers const char *stype; 10430949fd4SBrian Somers u_int32_t ipaddr; 10530949fd4SBrian Somers struct in_addr ip; 106972a1bcfSBrian Somers 107f0cdd9c0SBrian Somers r->cx.fd = -1; /* Stop select()ing */ 108c42627ffSBrian Somers stype = r->cx.auth ? "auth" : "acct"; 109972a1bcfSBrian Somers 110972a1bcfSBrian Somers switch (got) { 111972a1bcfSBrian Somers case RAD_ACCESS_ACCEPT: 112c42627ffSBrian Somers log_Printf(LogPHASE, "Radius(%s): ACCEPT received\n", stype); 113c42627ffSBrian Somers if (!r->cx.auth) { 114c42627ffSBrian Somers rad_close(r->cx.rad); 115c42627ffSBrian Somers return; 116c42627ffSBrian Somers } 117972a1bcfSBrian Somers break; 118972a1bcfSBrian Somers 119f0cdd9c0SBrian Somers case RAD_ACCESS_REJECT: 120c42627ffSBrian Somers log_Printf(LogPHASE, "Radius(%s): REJECT received\n", stype); 121c42627ffSBrian Somers if (r->cx.auth) 122f0cdd9c0SBrian Somers auth_Failure(r->cx.auth); 123f0cdd9c0SBrian Somers rad_close(r->cx.rad); 124f0cdd9c0SBrian Somers return; 125f0cdd9c0SBrian Somers 126972a1bcfSBrian Somers case RAD_ACCESS_CHALLENGE: 127972a1bcfSBrian Somers /* we can't deal with this (for now) ! */ 128f0cdd9c0SBrian Somers log_Printf(LogPHASE, "Radius: CHALLENGE received (can't handle yet)\n"); 129c42627ffSBrian Somers if (r->cx.auth) 130f0cdd9c0SBrian Somers auth_Failure(r->cx.auth); 131f0cdd9c0SBrian Somers rad_close(r->cx.rad); 132f0cdd9c0SBrian Somers return; 133972a1bcfSBrian Somers 134794c9bbcSBrian Somers case RAD_ACCOUNTING_RESPONSE: 135c42627ffSBrian Somers log_Printf(LogPHASE, "Radius(%s): Accounting response received\n", stype); 136c42627ffSBrian Somers if (r->cx.auth) 137c42627ffSBrian Somers auth_Failure(r->cx.auth); /* unexpected !!! */ 138c42627ffSBrian Somers 139794c9bbcSBrian Somers /* No further processing for accounting requests, please */ 140794c9bbcSBrian Somers rad_close(r->cx.rad); 141794c9bbcSBrian Somers return; 142794c9bbcSBrian Somers 143972a1bcfSBrian Somers case -1: 144c42627ffSBrian Somers log_Printf(LogPHASE, "radius(%s): %s\n", stype, rad_strerror(r->cx.rad)); 145c42627ffSBrian Somers if (r->cx.auth) 146f0cdd9c0SBrian Somers auth_Failure(r->cx.auth); 147f0cdd9c0SBrian Somers rad_close(r->cx.rad); 148f0cdd9c0SBrian Somers return; 149972a1bcfSBrian Somers 150972a1bcfSBrian Somers default: 151c42627ffSBrian Somers log_Printf(LogERROR, "rad_send_request(%s): Failed %d: %s\n", stype, 152f0cdd9c0SBrian Somers got, rad_strerror(r->cx.rad)); 153c42627ffSBrian Somers if (r->cx.auth) 154f0cdd9c0SBrian Somers auth_Failure(r->cx.auth); 155f0cdd9c0SBrian Somers rad_close(r->cx.rad); 156f0cdd9c0SBrian Somers return; 157972a1bcfSBrian Somers } 158972a1bcfSBrian Somers 159972a1bcfSBrian Somers /* So we've been accepted ! Let's see what we've got in our reply :-I */ 160972a1bcfSBrian Somers r->ip.s_addr = r->mask.s_addr = INADDR_NONE; 161972a1bcfSBrian Somers r->mtu = 0; 162972a1bcfSBrian Somers r->vj = 0; 163f0cdd9c0SBrian Somers while ((got = rad_get_attr(r->cx.rad, &data, &len)) > 0) { 164972a1bcfSBrian Somers switch (got) { 165972a1bcfSBrian Somers case RAD_FRAMED_IP_ADDRESS: 166972a1bcfSBrian Somers r->ip = rad_cvt_addr(data); 167f0cdd9c0SBrian Somers log_Printf(LogPHASE, " IP %s\n", inet_ntoa(r->ip)); 168972a1bcfSBrian Somers break; 169972a1bcfSBrian Somers 170bf1eaec5SBrian Somers case RAD_FILTER_ID: 171bf1eaec5SBrian Somers free(r->filterid); 172bf1eaec5SBrian Somers if ((r->filterid = rad_cvt_string(data, len)) == NULL) { 173bf1eaec5SBrian Somers log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); 174bf1eaec5SBrian Somers rad_close(r->cx.rad); 175bf1eaec5SBrian Somers return; 176bf1eaec5SBrian Somers } 177bf1eaec5SBrian Somers log_Printf(LogPHASE, " Filter \"%s\"\n", r->filterid); 178bf1eaec5SBrian Somers break; 179bf1eaec5SBrian Somers 180bf1eaec5SBrian Somers case RAD_SESSION_TIMEOUT: 181bf1eaec5SBrian Somers r->sessiontime = rad_cvt_int(data); 182bf1eaec5SBrian Somers log_Printf(LogPHASE, " Session-Timeout %lu\n", r->sessiontime); 183bf1eaec5SBrian Somers break; 184bf1eaec5SBrian Somers 185972a1bcfSBrian Somers case RAD_FRAMED_IP_NETMASK: 186972a1bcfSBrian Somers r->mask = rad_cvt_addr(data); 187f0cdd9c0SBrian Somers log_Printf(LogPHASE, " Netmask %s\n", inet_ntoa(r->mask)); 188972a1bcfSBrian Somers break; 189972a1bcfSBrian Somers 190972a1bcfSBrian Somers case RAD_FRAMED_MTU: 191972a1bcfSBrian Somers r->mtu = rad_cvt_int(data); 192f0cdd9c0SBrian Somers log_Printf(LogPHASE, " MTU %lu\n", r->mtu); 193972a1bcfSBrian Somers break; 194972a1bcfSBrian Somers 195972a1bcfSBrian Somers case RAD_FRAMED_ROUTING: 196972a1bcfSBrian Somers /* Disabled for now - should we automatically set up some filters ? */ 197972a1bcfSBrian Somers /* rad_cvt_int(data); */ 198972a1bcfSBrian Somers /* bit 1 = Send routing packets */ 199972a1bcfSBrian Somers /* bit 2 = Receive routing packets */ 200972a1bcfSBrian Somers break; 201972a1bcfSBrian Somers 202972a1bcfSBrian Somers case RAD_FRAMED_COMPRESSION: 203972a1bcfSBrian Somers r->vj = rad_cvt_int(data) == 1 ? 1 : 0; 204f0cdd9c0SBrian Somers log_Printf(LogPHASE, " VJ %sabled\n", r->vj ? "en" : "dis"); 205972a1bcfSBrian Somers break; 206972a1bcfSBrian Somers 207972a1bcfSBrian Somers case RAD_FRAMED_ROUTE: 208972a1bcfSBrian Somers /* 209972a1bcfSBrian Somers * We expect a string of the format ``dest[/bits] gw [metrics]'' 210972a1bcfSBrian Somers * Any specified metrics are ignored. MYADDR and HISADDR are 211972a1bcfSBrian Somers * understood for ``dest'' and ``gw'' and ``0.0.0.0'' is the same 212972a1bcfSBrian Somers * as ``HISADDR''. 213972a1bcfSBrian Somers */ 214972a1bcfSBrian Somers 215972a1bcfSBrian Somers if ((nuke = rad_cvt_string(data, len)) == NULL) { 216f0cdd9c0SBrian Somers log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); 217f0cdd9c0SBrian Somers rad_close(r->cx.rad); 218f0cdd9c0SBrian Somers return; 219972a1bcfSBrian Somers } 220972a1bcfSBrian Somers 221f0cdd9c0SBrian Somers log_Printf(LogPHASE, " Route: %s\n", nuke); 222f0cdd9c0SBrian Somers bundle = r->cx.auth->physical->dl->bundle; 22330949fd4SBrian Somers ip.s_addr = INADDR_ANY; 22430949fd4SBrian Somers ncprange_setip4host(&dest, ip); 225972a1bcfSBrian Somers argc = command_Interpret(nuke, strlen(nuke), argv); 226c39aa54eSBrian Somers if (argc < 0) 227c39aa54eSBrian Somers log_Printf(LogWARN, "radius: %s: Syntax error\n", 228c39aa54eSBrian Somers argc == 1 ? argv[0] : "\"\""); 229c39aa54eSBrian Somers else if (argc < 2) 230972a1bcfSBrian Somers log_Printf(LogWARN, "radius: %s: Invalid route\n", 231972a1bcfSBrian Somers argc == 1 ? argv[0] : "\"\""); 232972a1bcfSBrian Somers else if ((strcasecmp(argv[0], "default") != 0 && 23330949fd4SBrian Somers !ncprange_aton(&dest, &bundle->ncp, argv[0])) || 23430949fd4SBrian Somers !ncpaddr_aton(&gw, &bundle->ncp, argv[1])) 235972a1bcfSBrian Somers log_Printf(LogWARN, "radius: %s %s: Invalid route\n", 236972a1bcfSBrian Somers argv[0], argv[1]); 237972a1bcfSBrian Somers else { 23830949fd4SBrian Somers ncprange_getwidth(&dest, &width); 23930949fd4SBrian Somers if (width == 32 && strchr(argv[0], '/') == NULL) { 240972a1bcfSBrian Somers /* No mask specified - use the natural mask */ 24130949fd4SBrian Somers ncprange_getip4addr(&dest, &ip); 24230949fd4SBrian Somers ncprange_setip4mask(&dest, addr2mask(ip)); 24330949fd4SBrian Somers } 244972a1bcfSBrian Somers addrs = 0; 245972a1bcfSBrian Somers 246972a1bcfSBrian Somers if (!strncasecmp(argv[0], "HISADDR", 7)) 247972a1bcfSBrian Somers addrs = ROUTE_DSTHISADDR; 248972a1bcfSBrian Somers else if (!strncasecmp(argv[0], "MYADDR", 6)) 249972a1bcfSBrian Somers addrs = ROUTE_DSTMYADDR; 250972a1bcfSBrian Somers 25130949fd4SBrian Somers if (ncpaddr_getip4addr(&gw, &ipaddr) && ipaddr == INADDR_ANY) { 252972a1bcfSBrian Somers addrs |= ROUTE_GWHISADDR; 25330949fd4SBrian Somers ncpaddr_setip4(&gw, bundle->ncp.ipcp.peer_ip); 254972a1bcfSBrian Somers } else if (strcasecmp(argv[1], "HISADDR") == 0) 255972a1bcfSBrian Somers addrs |= ROUTE_GWHISADDR; 256972a1bcfSBrian Somers 25730949fd4SBrian Somers route_Add(&r->routes, addrs, &dest, &gw); 258972a1bcfSBrian Somers } 259972a1bcfSBrian Somers free(nuke); 260972a1bcfSBrian Somers break; 261972a1bcfSBrian Somers } 262972a1bcfSBrian Somers } 263972a1bcfSBrian Somers 264972a1bcfSBrian Somers if (got == -1) { 265f0cdd9c0SBrian Somers log_Printf(LogERROR, "rad_get_attr: %s (failing!)\n", 266f0cdd9c0SBrian Somers rad_strerror(r->cx.rad)); 267f0cdd9c0SBrian Somers auth_Failure(r->cx.auth); 268f0cdd9c0SBrian Somers rad_close(r->cx.rad); 269f0cdd9c0SBrian Somers } else { 270f0cdd9c0SBrian Somers r->valid = 1; 271f0cdd9c0SBrian Somers auth_Success(r->cx.auth); 272f0cdd9c0SBrian Somers rad_close(r->cx.rad); 273f0cdd9c0SBrian Somers } 274972a1bcfSBrian Somers } 275972a1bcfSBrian Somers 276f0cdd9c0SBrian Somers /* 2778e7bd08eSBrian Somers * We've either timed out or select()ed on the read descriptor 278f0cdd9c0SBrian Somers */ 279f0cdd9c0SBrian Somers static void 280f0cdd9c0SBrian Somers radius_Continue(struct radius *r, int sel) 281f0cdd9c0SBrian Somers { 282f0cdd9c0SBrian Somers struct timeval tv; 283f0cdd9c0SBrian Somers int got; 284972a1bcfSBrian Somers 285f0cdd9c0SBrian Somers timer_Stop(&r->cx.timer); 286f0cdd9c0SBrian Somers if ((got = rad_continue_send_request(r->cx.rad, sel, &r->cx.fd, &tv)) == 0) { 287f0cdd9c0SBrian Somers log_Printf(LogPHASE, "Radius: Request re-sent\n"); 288f0cdd9c0SBrian Somers r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS; 289f0cdd9c0SBrian Somers timer_Start(&r->cx.timer); 290f0cdd9c0SBrian Somers return; 291f0cdd9c0SBrian Somers } 292f0cdd9c0SBrian Somers 293f0cdd9c0SBrian Somers radius_Process(r, got); 294f0cdd9c0SBrian Somers } 295f0cdd9c0SBrian Somers 296f0cdd9c0SBrian Somers /* 297f0cdd9c0SBrian Somers * Time to call rad_continue_send_request() - timed out. 298f0cdd9c0SBrian Somers */ 299f0cdd9c0SBrian Somers static void 300f0cdd9c0SBrian Somers radius_Timeout(void *v) 301f0cdd9c0SBrian Somers { 302f0cdd9c0SBrian Somers radius_Continue((struct radius *)v, 0); 303f0cdd9c0SBrian Somers } 304f0cdd9c0SBrian Somers 305f0cdd9c0SBrian Somers /* 306f0cdd9c0SBrian Somers * Time to call rad_continue_send_request() - something to read. 307f0cdd9c0SBrian Somers */ 308f0cdd9c0SBrian Somers static void 309f013f33eSBrian Somers radius_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 310f0cdd9c0SBrian Somers { 311f0cdd9c0SBrian Somers radius_Continue(descriptor2radius(d), 1); 312f0cdd9c0SBrian Somers } 313f0cdd9c0SBrian Somers 314f0cdd9c0SBrian Somers /* 3158e7bd08eSBrian Somers * Behave as a struct fdescriptor (descriptor.h) 316f0cdd9c0SBrian Somers */ 317f0cdd9c0SBrian Somers static int 318f013f33eSBrian Somers radius_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 319f0cdd9c0SBrian Somers { 320f0cdd9c0SBrian Somers struct radius *rad = descriptor2radius(d); 321f0cdd9c0SBrian Somers 322f0cdd9c0SBrian Somers if (r && rad->cx.fd != -1) { 323f0cdd9c0SBrian Somers FD_SET(rad->cx.fd, r); 324f0cdd9c0SBrian Somers if (*n < rad->cx.fd + 1) 325f0cdd9c0SBrian Somers *n = rad->cx.fd + 1; 326f0cdd9c0SBrian Somers log_Printf(LogTIMER, "Radius: fdset(r) %d\n", rad->cx.fd); 32782d6780cSBrian Somers return 1; 328972a1bcfSBrian Somers } 329972a1bcfSBrian Somers 330f0cdd9c0SBrian Somers return 0; 331f0cdd9c0SBrian Somers } 332f0cdd9c0SBrian Somers 333f0cdd9c0SBrian Somers /* 3348e7bd08eSBrian Somers * Behave as a struct fdescriptor (descriptor.h) 335f0cdd9c0SBrian Somers */ 336f0cdd9c0SBrian Somers static int 337f013f33eSBrian Somers radius_IsSet(struct fdescriptor *d, const fd_set *fdset) 338f0cdd9c0SBrian Somers { 339f0cdd9c0SBrian Somers struct radius *r = descriptor2radius(d); 340f0cdd9c0SBrian Somers 341f0cdd9c0SBrian Somers return r && r->cx.fd != -1 && FD_ISSET(r->cx.fd, fdset); 342f0cdd9c0SBrian Somers } 343f0cdd9c0SBrian Somers 344f0cdd9c0SBrian Somers /* 3458e7bd08eSBrian Somers * Behave as a struct fdescriptor (descriptor.h) 346f0cdd9c0SBrian Somers */ 347f0cdd9c0SBrian Somers static int 348f013f33eSBrian Somers radius_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 349f0cdd9c0SBrian Somers { 350f0cdd9c0SBrian Somers /* We never want to write here ! */ 351f0cdd9c0SBrian Somers log_Printf(LogALERT, "radius_Write: Internal error: Bad call !\n"); 352f0cdd9c0SBrian Somers return 0; 353f0cdd9c0SBrian Somers } 354f0cdd9c0SBrian Somers 355f0cdd9c0SBrian Somers /* 356f0cdd9c0SBrian Somers * Initialise ourselves 357f0cdd9c0SBrian Somers */ 358f0cdd9c0SBrian Somers void 359f0cdd9c0SBrian Somers radius_Init(struct radius *r) 360f0cdd9c0SBrian Somers { 361f0cdd9c0SBrian Somers r->valid = 0; 362f0cdd9c0SBrian Somers r->cx.fd = -1; 363f0cdd9c0SBrian Somers *r->cfg.file = '\0';; 364f0cdd9c0SBrian Somers r->desc.type = RADIUS_DESCRIPTOR; 365f0cdd9c0SBrian Somers r->desc.UpdateSet = radius_UpdateSet; 366f0cdd9c0SBrian Somers r->desc.IsSet = radius_IsSet; 367f0cdd9c0SBrian Somers r->desc.Read = radius_Read; 368f0cdd9c0SBrian Somers r->desc.Write = radius_Write; 369f0cdd9c0SBrian Somers memset(&r->cx.timer, '\0', sizeof r->cx.timer); 370794c9bbcSBrian Somers log_Printf(LogDEBUG, "Radius: radius_Init\n"); 371f0cdd9c0SBrian Somers } 372f0cdd9c0SBrian Somers 373f0cdd9c0SBrian Somers /* 374f0cdd9c0SBrian Somers * Forget everything and go back to initialised state. 375f0cdd9c0SBrian Somers */ 376f0cdd9c0SBrian Somers void 377f0cdd9c0SBrian Somers radius_Destroy(struct radius *r) 378f0cdd9c0SBrian Somers { 379f0cdd9c0SBrian Somers r->valid = 0; 380794c9bbcSBrian Somers log_Printf(LogDEBUG, "Radius: radius_Destroy\n"); 381f0cdd9c0SBrian Somers timer_Stop(&r->cx.timer); 382f0cdd9c0SBrian Somers route_DeleteAll(&r->routes); 383bf1eaec5SBrian Somers free(r->filterid); 384bf1eaec5SBrian Somers r->filterid = NULL; 385f0cdd9c0SBrian Somers if (r->cx.fd != -1) { 386f0cdd9c0SBrian Somers r->cx.fd = -1; 387f0cdd9c0SBrian Somers rad_close(r->cx.rad); 388f0cdd9c0SBrian Somers } 389f0cdd9c0SBrian Somers } 390f0cdd9c0SBrian Somers 391f0cdd9c0SBrian Somers /* 392f0cdd9c0SBrian Somers * Start an authentication request to the RADIUS server. 393f0cdd9c0SBrian Somers */ 394f0cdd9c0SBrian Somers void 395f0cdd9c0SBrian Somers radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name, 39650ca6ec3SBrian Somers const char *key, int klen, const char *challenge, int clen) 397f0cdd9c0SBrian Somers { 398f10f5203SBrian Somers struct ttyent *ttyp; 399f0cdd9c0SBrian Somers struct timeval tv; 400f10f5203SBrian Somers int got, slot; 40126e6a622SBrian Somers char hostname[MAXHOSTNAMELEN]; 402f10f5203SBrian Somers struct hostent *hp; 403f10f5203SBrian Somers struct in_addr hostaddr; 404f0cdd9c0SBrian Somers 405f0cdd9c0SBrian Somers if (!*r->cfg.file) 406f0cdd9c0SBrian Somers return; 407f0cdd9c0SBrian Somers 408f0cdd9c0SBrian Somers if (r->cx.fd != -1) 409f0cdd9c0SBrian Somers /* 410f0cdd9c0SBrian Somers * We assume that our name/key/challenge is the same as last time, 411f0cdd9c0SBrian Somers * and just continue to wait for the RADIUS server(s). 412f0cdd9c0SBrian Somers */ 413f0cdd9c0SBrian Somers return; 414f0cdd9c0SBrian Somers 415f0cdd9c0SBrian Somers radius_Destroy(r); 416f0cdd9c0SBrian Somers 417794c9bbcSBrian Somers if ((r->cx.rad = rad_auth_open()) == NULL) { 418794c9bbcSBrian Somers log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno)); 419f0cdd9c0SBrian Somers return; 420f0cdd9c0SBrian Somers } 421f0cdd9c0SBrian Somers 422f0cdd9c0SBrian Somers if (rad_config(r->cx.rad, r->cfg.file) != 0) { 423f0cdd9c0SBrian Somers log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad)); 424f0cdd9c0SBrian Somers rad_close(r->cx.rad); 425f0cdd9c0SBrian Somers return; 426f0cdd9c0SBrian Somers } 427f0cdd9c0SBrian Somers 428f0cdd9c0SBrian Somers if (rad_create_request(r->cx.rad, RAD_ACCESS_REQUEST) != 0) { 429f0cdd9c0SBrian Somers log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad)); 430f0cdd9c0SBrian Somers rad_close(r->cx.rad); 431f0cdd9c0SBrian Somers return; 432f0cdd9c0SBrian Somers } 433f0cdd9c0SBrian Somers 434f0cdd9c0SBrian Somers if (rad_put_string(r->cx.rad, RAD_USER_NAME, name) != 0 || 435f0cdd9c0SBrian Somers rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 || 436f0cdd9c0SBrian Somers rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) { 437f0cdd9c0SBrian Somers log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 438f0cdd9c0SBrian Somers rad_close(r->cx.rad); 439f0cdd9c0SBrian Somers return; 440f0cdd9c0SBrian Somers } 441f0cdd9c0SBrian Somers 442f0cdd9c0SBrian Somers if (challenge != NULL) { 443f0cdd9c0SBrian Somers /* We're talking CHAP */ 44450ca6ec3SBrian Somers if (rad_put_attr(r->cx.rad, RAD_CHAP_PASSWORD, key, klen) != 0 || 44550ca6ec3SBrian Somers rad_put_attr(r->cx.rad, RAD_CHAP_CHALLENGE, challenge, clen) != 0) { 446f0cdd9c0SBrian Somers log_Printf(LogERROR, "CHAP: rad_put_string: %s\n", 447f0cdd9c0SBrian Somers rad_strerror(r->cx.rad)); 448f0cdd9c0SBrian Somers rad_close(r->cx.rad); 449f0cdd9c0SBrian Somers return; 450f0cdd9c0SBrian Somers } 45150ca6ec3SBrian Somers } else if (rad_put_attr(r->cx.rad, RAD_USER_PASSWORD, key, klen) != 0) { 452f0cdd9c0SBrian Somers /* We're talking PAP */ 453f0cdd9c0SBrian Somers log_Printf(LogERROR, "PAP: rad_put_string: %s\n", rad_strerror(r->cx.rad)); 454f0cdd9c0SBrian Somers rad_close(r->cx.rad); 455f0cdd9c0SBrian Somers return; 456f0cdd9c0SBrian Somers } 457f0cdd9c0SBrian Somers 458f10f5203SBrian Somers if (gethostname(hostname, sizeof hostname) != 0) 459f10f5203SBrian Somers log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno)); 460f10f5203SBrian Somers else { 461f10f5203SBrian Somers if ((hp = gethostbyname(hostname)) != NULL) { 462f10f5203SBrian Somers hostaddr.s_addr = *(u_long *)hp->h_addr; 463f10f5203SBrian Somers if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) { 464f10f5203SBrian Somers log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 465f10f5203SBrian Somers rad_strerror(r->cx.rad)); 466f10f5203SBrian Somers rad_close(r->cx.rad); 467f10f5203SBrian Somers return; 468f10f5203SBrian Somers } 469f10f5203SBrian Somers } 470f10f5203SBrian Somers if (rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) { 471f10f5203SBrian Somers log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 472f10f5203SBrian Somers rad_strerror(r->cx.rad)); 473f10f5203SBrian Somers rad_close(r->cx.rad); 474f10f5203SBrian Somers return; 475f10f5203SBrian Somers } 476f10f5203SBrian Somers } 477f10f5203SBrian Somers 478f10f5203SBrian Somers if (authp->physical->handler && 479f10f5203SBrian Somers authp->physical->handler->type == TTY_DEVICE) { 480f10f5203SBrian Somers setttyent(); 481f10f5203SBrian Somers for (slot = 1; (ttyp = getttyent()); ++slot) 482f10f5203SBrian Somers if (!strcmp(ttyp->ty_name, authp->physical->name.base)) { 483f10f5203SBrian Somers if (rad_put_int(r->cx.rad, RAD_NAS_PORT, slot) != 0) { 484f10f5203SBrian Somers log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 485f10f5203SBrian Somers rad_strerror(r->cx.rad)); 486f10f5203SBrian Somers rad_close(r->cx.rad); 487f10f5203SBrian Somers endttyent(); 488f10f5203SBrian Somers return; 489f10f5203SBrian Somers } 490f10f5203SBrian Somers break; 491f10f5203SBrian Somers } 492f10f5203SBrian Somers endttyent(); 493f10f5203SBrian Somers } 494f10f5203SBrian Somers 495f10f5203SBrian Somers 496c42627ffSBrian Somers r->cx.auth = authp; 497f0cdd9c0SBrian Somers if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv))) 498f0cdd9c0SBrian Somers radius_Process(r, got); 499f0cdd9c0SBrian Somers else { 500f0cdd9c0SBrian Somers log_Printf(LogPHASE, "Radius: Request sent\n"); 501f0cdd9c0SBrian Somers log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout); 502f0cdd9c0SBrian Somers r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS; 503f0cdd9c0SBrian Somers r->cx.timer.func = radius_Timeout; 504c42627ffSBrian Somers r->cx.timer.name = "radius auth"; 505f0cdd9c0SBrian Somers r->cx.timer.arg = r; 506f0cdd9c0SBrian Somers timer_Start(&r->cx.timer); 507f0cdd9c0SBrian Somers } 508f0cdd9c0SBrian Somers } 509f0cdd9c0SBrian Somers 510f0cdd9c0SBrian Somers /* 511794c9bbcSBrian Somers * Send an accounting request to the RADIUS server 512794c9bbcSBrian Somers */ 513794c9bbcSBrian Somers void 514794c9bbcSBrian Somers radius_Account(struct radius *r, struct radacct *ac, struct datalink *dl, 515794c9bbcSBrian Somers int acct_type, struct in_addr *peer_ip, struct in_addr *netmask, 516794c9bbcSBrian Somers struct pppThroughput *stats) 517794c9bbcSBrian Somers { 518794c9bbcSBrian Somers struct ttyent *ttyp; 519794c9bbcSBrian Somers struct timeval tv; 520794c9bbcSBrian Somers int got, slot; 52126e6a622SBrian Somers char hostname[MAXHOSTNAMELEN]; 522794c9bbcSBrian Somers struct hostent *hp; 523794c9bbcSBrian Somers struct in_addr hostaddr; 524794c9bbcSBrian Somers 525794c9bbcSBrian Somers if (!*r->cfg.file) 526794c9bbcSBrian Somers return; 527794c9bbcSBrian Somers 528794c9bbcSBrian Somers if (r->cx.fd != -1) 529794c9bbcSBrian Somers /* 530794c9bbcSBrian Somers * We assume that our name/key/challenge is the same as last time, 531794c9bbcSBrian Somers * and just continue to wait for the RADIUS server(s). 532794c9bbcSBrian Somers */ 533794c9bbcSBrian Somers return; 534794c9bbcSBrian Somers 535794c9bbcSBrian Somers radius_Destroy(r); 536794c9bbcSBrian Somers 537ba093e81SBrian Somers if ((r->cx.rad = rad_acct_open()) == NULL) { 538794c9bbcSBrian Somers log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno)); 539794c9bbcSBrian Somers return; 540794c9bbcSBrian Somers } 541794c9bbcSBrian Somers 542794c9bbcSBrian Somers if (rad_config(r->cx.rad, r->cfg.file) != 0) { 543794c9bbcSBrian Somers log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad)); 544794c9bbcSBrian Somers rad_close(r->cx.rad); 545794c9bbcSBrian Somers return; 546794c9bbcSBrian Somers } 547794c9bbcSBrian Somers 548794c9bbcSBrian Somers if (rad_create_request(r->cx.rad, RAD_ACCOUNTING_REQUEST) != 0) { 549794c9bbcSBrian Somers log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad)); 550794c9bbcSBrian Somers rad_close(r->cx.rad); 551794c9bbcSBrian Somers return; 552794c9bbcSBrian Somers } 553794c9bbcSBrian Somers 554794c9bbcSBrian Somers /* Grab some accounting data and initialize structure */ 555794c9bbcSBrian Somers if (acct_type == RAD_START) { 556794c9bbcSBrian Somers ac->rad_parent = r; 557794c9bbcSBrian Somers /* Fetch username from datalink */ 558794c9bbcSBrian Somers strncpy(ac->user_name, dl->peer.authname, sizeof ac->user_name); 559794c9bbcSBrian Somers ac->user_name[AUTHLEN-1] = '\0'; 560794c9bbcSBrian Somers 561794c9bbcSBrian Somers ac->authentic = 2; /* Assume RADIUS verified auth data */ 562794c9bbcSBrian Somers 563794c9bbcSBrian Somers /* Generate a session ID */ 564794c9bbcSBrian Somers snprintf(ac->session_id, sizeof ac->session_id, "%s%d-%s%lu", 565794c9bbcSBrian Somers dl->bundle->cfg.auth.name, (int)getpid(), 566794c9bbcSBrian Somers dl->peer.authname, (unsigned long)stats->uptime); 567794c9bbcSBrian Somers 568794c9bbcSBrian Somers /* And grab our MP socket name */ 569794c9bbcSBrian Somers snprintf(ac->multi_session_id, sizeof ac->multi_session_id, "%s", 570794c9bbcSBrian Somers dl->bundle->ncp.mp.active ? 571794c9bbcSBrian Somers dl->bundle->ncp.mp.server.socket.sun_path : ""); 572794c9bbcSBrian Somers 573794c9bbcSBrian Somers /* Fetch IP, netmask from IPCP */ 574794c9bbcSBrian Somers memcpy(&ac->ip, peer_ip, sizeof(ac->ip)); 575794c9bbcSBrian Somers memcpy(&ac->mask, netmask, sizeof(ac->mask)); 576794c9bbcSBrian Somers }; 577794c9bbcSBrian Somers 578794c9bbcSBrian Somers if (rad_put_string(r->cx.rad, RAD_USER_NAME, ac->user_name) != 0 || 579794c9bbcSBrian Somers rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 || 580794c9bbcSBrian Somers rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0 || 581794c9bbcSBrian Somers rad_put_addr(r->cx.rad, RAD_FRAMED_IP_ADDRESS, ac->ip) != 0 || 582794c9bbcSBrian Somers rad_put_addr(r->cx.rad, RAD_FRAMED_IP_NETMASK, ac->mask) != 0) { 583794c9bbcSBrian Somers log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 584794c9bbcSBrian Somers rad_close(r->cx.rad); 585794c9bbcSBrian Somers return; 586794c9bbcSBrian Somers } 587794c9bbcSBrian Somers 588794c9bbcSBrian Somers if (gethostname(hostname, sizeof hostname) != 0) 589794c9bbcSBrian Somers log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno)); 590794c9bbcSBrian Somers else { 591794c9bbcSBrian Somers if ((hp = gethostbyname(hostname)) != NULL) { 592794c9bbcSBrian Somers hostaddr.s_addr = *(u_long *)hp->h_addr; 593794c9bbcSBrian Somers if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) { 594794c9bbcSBrian Somers log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 595794c9bbcSBrian Somers rad_strerror(r->cx.rad)); 596794c9bbcSBrian Somers rad_close(r->cx.rad); 597794c9bbcSBrian Somers return; 598794c9bbcSBrian Somers } 599794c9bbcSBrian Somers } 600794c9bbcSBrian Somers if (rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) { 601794c9bbcSBrian Somers log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 602794c9bbcSBrian Somers rad_strerror(r->cx.rad)); 603794c9bbcSBrian Somers rad_close(r->cx.rad); 604794c9bbcSBrian Somers return; 605794c9bbcSBrian Somers } 606794c9bbcSBrian Somers } 607794c9bbcSBrian Somers 608794c9bbcSBrian Somers if (dl->physical->handler && 609794c9bbcSBrian Somers dl->physical->handler->type == TTY_DEVICE) { 610794c9bbcSBrian Somers setttyent(); 611794c9bbcSBrian Somers for (slot = 1; (ttyp = getttyent()); ++slot) 612794c9bbcSBrian Somers if (!strcmp(ttyp->ty_name, dl->physical->name.base)) { 613794c9bbcSBrian Somers if (rad_put_int(r->cx.rad, RAD_NAS_PORT, slot) != 0) { 614794c9bbcSBrian Somers log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 615794c9bbcSBrian Somers rad_strerror(r->cx.rad)); 616794c9bbcSBrian Somers rad_close(r->cx.rad); 617794c9bbcSBrian Somers endttyent(); 618794c9bbcSBrian Somers return; 619794c9bbcSBrian Somers } 620794c9bbcSBrian Somers break; 621794c9bbcSBrian Somers } 622794c9bbcSBrian Somers endttyent(); 623794c9bbcSBrian Somers } 624794c9bbcSBrian Somers 625794c9bbcSBrian Somers if (rad_put_int(r->cx.rad, RAD_ACCT_STATUS_TYPE, acct_type) != 0 || 626794c9bbcSBrian Somers rad_put_string(r->cx.rad, RAD_ACCT_SESSION_ID, ac->session_id) != 0 || 627794c9bbcSBrian Somers rad_put_string(r->cx.rad, RAD_ACCT_MULTI_SESSION_ID, 628794c9bbcSBrian Somers ac->multi_session_id) != 0 || 629794c9bbcSBrian Somers rad_put_int(r->cx.rad, RAD_ACCT_DELAY_TIME, 0) != 0) { 630794c9bbcSBrian Somers /* XXX ACCT_DELAY_TIME should be increased each time a packet is waiting */ 631794c9bbcSBrian Somers log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 632794c9bbcSBrian Somers rad_close(r->cx.rad); 633794c9bbcSBrian Somers return; 634794c9bbcSBrian Somers } 635794c9bbcSBrian Somers 636794c9bbcSBrian Somers if (acct_type == RAD_STOP) 637794c9bbcSBrian Somers /* Show some statistics */ 638794c9bbcSBrian Somers if (rad_put_int(r->cx.rad, RAD_ACCT_INPUT_OCTETS, stats->OctetsIn) != 0 || 639794c9bbcSBrian Somers rad_put_int(r->cx.rad, RAD_ACCT_INPUT_PACKETS, stats->PacketsIn) != 0 || 640794c9bbcSBrian Somers rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_OCTETS, stats->OctetsOut) != 0 || 641794c9bbcSBrian Somers rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_PACKETS, stats->PacketsOut) 642794c9bbcSBrian Somers != 0 || 643794c9bbcSBrian Somers rad_put_int(r->cx.rad, RAD_ACCT_SESSION_TIME, throughput_uptime(stats)) 644794c9bbcSBrian Somers != 0) { 645794c9bbcSBrian Somers log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 646794c9bbcSBrian Somers rad_close(r->cx.rad); 647794c9bbcSBrian Somers return; 648794c9bbcSBrian Somers } 649794c9bbcSBrian Somers 650c42627ffSBrian Somers r->cx.auth = NULL; /* Not valid for accounting requests */ 651794c9bbcSBrian Somers if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv))) 652794c9bbcSBrian Somers radius_Process(r, got); 653794c9bbcSBrian Somers else { 654794c9bbcSBrian Somers log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout); 655794c9bbcSBrian Somers r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS; 656794c9bbcSBrian Somers r->cx.timer.func = radius_Timeout; 657c42627ffSBrian Somers r->cx.timer.name = "radius acct"; 658794c9bbcSBrian Somers r->cx.timer.arg = r; 659794c9bbcSBrian Somers timer_Start(&r->cx.timer); 660794c9bbcSBrian Somers } 661794c9bbcSBrian Somers } 662794c9bbcSBrian Somers 663794c9bbcSBrian Somers /* 664f0cdd9c0SBrian Somers * How do things look at the moment ? 665f0cdd9c0SBrian Somers */ 666972a1bcfSBrian Somers void 667972a1bcfSBrian Somers radius_Show(struct radius *r, struct prompt *p) 668972a1bcfSBrian Somers { 66974457d3dSBrian Somers prompt_Printf(p, " Radius config: %s", 67074457d3dSBrian Somers *r->cfg.file ? r->cfg.file : "none"); 671972a1bcfSBrian Somers if (r->valid) { 672972a1bcfSBrian Somers prompt_Printf(p, "\n IP: %s\n", inet_ntoa(r->ip)); 673972a1bcfSBrian Somers prompt_Printf(p, " Netmask: %s\n", inet_ntoa(r->mask)); 674972a1bcfSBrian Somers prompt_Printf(p, " MTU: %lu\n", r->mtu); 675972a1bcfSBrian Somers prompt_Printf(p, " VJ: %sabled\n", r->vj ? "en" : "dis"); 676972a1bcfSBrian Somers if (r->routes) 677972a1bcfSBrian Somers route_ShowSticky(p, r->routes, " Routes", 16); 678972a1bcfSBrian Somers } else 679972a1bcfSBrian Somers prompt_Printf(p, " (not authenticated)\n"); 680972a1bcfSBrian Somers } 681