143313Sbrian/* 243313Sbrian * Copyright 1999 Internet Business Solutions Ltd., Switzerland 343313Sbrian * All rights reserved. 443313Sbrian * 543313Sbrian * Redistribution and use in source and binary forms, with or without 643313Sbrian * modification, are permitted provided that the following conditions 743313Sbrian * are met: 843313Sbrian * 1. Redistributions of source code must retain the above copyright 943313Sbrian * notice, this list of conditions and the following disclaimer. 1043313Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1143313Sbrian * notice, this list of conditions and the following disclaimer in the 1243313Sbrian * documentation and/or other materials provided with the distribution. 1343313Sbrian * 1443313Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1543313Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1643313Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1743313Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1843313Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1943313Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2043313Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2143313Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2243313Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2343313Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2443313Sbrian * SUCH DAMAGE. 2543313Sbrian * 2650479Speter * $FreeBSD$ 2743313Sbrian * 2843313Sbrian */ 2943313Sbrian 30129457Sdds#include <stdint.h> 3143313Sbrian#include <sys/param.h> 3298132Sbrian 33140905Sbrian#include <sys/select.h> 3458032Sbrian#include <sys/socket.h> 3543313Sbrian#include <netinet/in_systm.h> 3643313Sbrian#include <netinet/in.h> 3743313Sbrian#include <netinet/ip.h> 3843313Sbrian#include <arpa/inet.h> 3943313Sbrian#include <sys/un.h> 4058032Sbrian#include <net/route.h> 4143313Sbrian 4258037Sbrian#ifdef LOCALRAD 4358037Sbrian#include "radlib.h" 4496324Sbrian#include "radlib_vs.h" 4558037Sbrian#else 4658037Sbrian#include <radlib.h> 4796324Sbrian#include <radlib_vs.h> 4858037Sbrian#endif 4958037Sbrian 5043313Sbrian#include <errno.h> 5198132Sbrian#ifndef NODES 5298132Sbrian#include <md5.h> 5398132Sbrian#endif 54102500Sbrian#include <stdarg.h> 5543313Sbrian#include <stdio.h> 5643313Sbrian#include <stdlib.h> 5743313Sbrian#include <string.h> 5843693Sbrian#include <sys/time.h> 5943313Sbrian#include <termios.h> 6050840Sbrian#include <unistd.h> 6150840Sbrian#include <netdb.h> 6243313Sbrian 6346686Sbrian#include "layer.h" 6443313Sbrian#include "defs.h" 6543313Sbrian#include "log.h" 6643313Sbrian#include "descriptor.h" 6743313Sbrian#include "prompt.h" 6843313Sbrian#include "timer.h" 6943313Sbrian#include "fsm.h" 7043313Sbrian#include "iplist.h" 7143313Sbrian#include "slcompress.h" 7243313Sbrian#include "throughput.h" 7343313Sbrian#include "lqr.h" 7443313Sbrian#include "hdlc.h" 7543313Sbrian#include "mbuf.h" 7681634Sbrian#include "ncpaddr.h" 7781634Sbrian#include "ip.h" 7843313Sbrian#include "ipcp.h" 7981634Sbrian#include "ipv6cp.h" 8043313Sbrian#include "route.h" 8143313Sbrian#include "command.h" 8243313Sbrian#include "filter.h" 8343313Sbrian#include "lcp.h" 8443313Sbrian#include "ccp.h" 8543313Sbrian#include "link.h" 8643313Sbrian#include "mp.h" 8743313Sbrian#include "radius.h" 8843693Sbrian#include "auth.h" 8943693Sbrian#include "async.h" 9043693Sbrian#include "physical.h" 9143693Sbrian#include "chat.h" 9243693Sbrian#include "cbcp.h" 9343693Sbrian#include "chap.h" 9443693Sbrian#include "datalink.h" 9581634Sbrian#include "ncp.h" 9643313Sbrian#include "bundle.h" 9796324Sbrian#include "proto.h" 98169986Snovel#include "iface.h" 9943313Sbrian 10096324Sbrian#ifndef NODES 10196730Sbrianstruct mschap_response { 10296324Sbrian u_char ident; 10396324Sbrian u_char flags; 10496324Sbrian u_char lm_response[24]; 10596324Sbrian u_char nt_response[24]; 10696324Sbrian}; 10796730Sbrian 10896730Sbrianstruct mschap2_response { 10996730Sbrian u_char ident; 11096730Sbrian u_char flags; 11196730Sbrian u_char pchallenge[16]; 11296730Sbrian u_char reserved[8]; 11396730Sbrian u_char response[24]; 11496730Sbrian}; 11598132Sbrian 11698132Sbrian#define AUTH_LEN 16 11798132Sbrian#define SALT_LEN 2 11896324Sbrian#endif 11996324Sbrian 12098132Sbrianstatic const char * 12198132Sbrianradius_policyname(int policy) 12298132Sbrian{ 12398132Sbrian switch(policy) { 12498132Sbrian case MPPE_POLICY_ALLOWED: 12598132Sbrian return "Allowed"; 12698132Sbrian case MPPE_POLICY_REQUIRED: 12798132Sbrian return "Required"; 12898132Sbrian } 12998132Sbrian return NumStr(policy, NULL, 0); 13098132Sbrian} 13198132Sbrian 13298132Sbrianstatic const char * 13398132Sbrianradius_typesname(int types) 13498132Sbrian{ 13598132Sbrian switch(types) { 13698132Sbrian case MPPE_TYPE_40BIT: 13798132Sbrian return "40 bit"; 13898132Sbrian case MPPE_TYPE_128BIT: 13998132Sbrian return "128 bit"; 14098132Sbrian case MPPE_TYPE_40BIT|MPPE_TYPE_128BIT: 14198132Sbrian return "40 or 128 bit"; 14298132Sbrian } 14398132Sbrian return NumStr(types, NULL, 0); 14498132Sbrian} 14598132Sbrian 14698132Sbrian#ifndef NODES 14798132Sbrianstatic void 14898132Sbriandemangle(struct radius *r, const void *mangled, size_t mlen, 14998132Sbrian char **buf, size_t *len) 15098132Sbrian{ 15198132Sbrian char R[AUTH_LEN]; /* variable names as per rfc2548 */ 15298132Sbrian const char *S; 15398132Sbrian u_char b[16]; 15498132Sbrian const u_char *A, *C; 15598132Sbrian MD5_CTX Context; 15698132Sbrian int Slen, i, Clen, Ppos; 15798132Sbrian u_char *P; 15898132Sbrian 15998132Sbrian if (mlen % 16 != SALT_LEN) { 16098132Sbrian log_Printf(LogWARN, "Cannot interpret mangled data of length %ld\n", 16198132Sbrian (u_long)mlen); 16298132Sbrian *buf = NULL; 16398132Sbrian *len = 0; 16498132Sbrian return; 16598132Sbrian } 16698132Sbrian 16798132Sbrian /* We need the RADIUS Request-Authenticator */ 16898132Sbrian if (rad_request_authenticator(r->cx.rad, R, sizeof R) != AUTH_LEN) { 16998132Sbrian log_Printf(LogWARN, "Cannot obtain the RADIUS request authenticator\n"); 17098132Sbrian *buf = NULL; 17198132Sbrian *len = 0; 17298132Sbrian return; 17398132Sbrian } 17498132Sbrian 17598132Sbrian A = (const u_char *)mangled; /* Salt comes first */ 17698132Sbrian C = (const u_char *)mangled + SALT_LEN; /* Then the ciphertext */ 17798132Sbrian Clen = mlen - SALT_LEN; 17898132Sbrian S = rad_server_secret(r->cx.rad); /* We need the RADIUS secret */ 17998132Sbrian Slen = strlen(S); 18098132Sbrian P = alloca(Clen); /* We derive our plaintext */ 18198132Sbrian 18298132Sbrian MD5Init(&Context); 18398132Sbrian MD5Update(&Context, S, Slen); 18498132Sbrian MD5Update(&Context, R, AUTH_LEN); 18598132Sbrian MD5Update(&Context, A, SALT_LEN); 18698132Sbrian MD5Final(b, &Context); 18798132Sbrian Ppos = 0; 18898132Sbrian 18998132Sbrian while (Clen) { 19098132Sbrian Clen -= 16; 19198132Sbrian 19298132Sbrian for (i = 0; i < 16; i++) 19398132Sbrian P[Ppos++] = C[i] ^ b[i]; 19498132Sbrian 19598132Sbrian if (Clen) { 19698132Sbrian MD5Init(&Context); 19798132Sbrian MD5Update(&Context, S, Slen); 19898132Sbrian MD5Update(&Context, C, 16); 19998132Sbrian MD5Final(b, &Context); 20098132Sbrian } 20198132Sbrian 20298132Sbrian C += 16; 20398132Sbrian } 20498132Sbrian 20598132Sbrian /* 20698132Sbrian * The resulting plain text consists of a one-byte length, the text and 20798132Sbrian * maybe some padding. 20898132Sbrian */ 20998132Sbrian *len = *P; 21098132Sbrian if (*len > mlen - 1) { 21198132Sbrian log_Printf(LogWARN, "Mangled data seems to be garbage\n"); 21298132Sbrian *buf = NULL; 21398132Sbrian *len = 0; 21498132Sbrian return; 21598132Sbrian } 21698132Sbrian 217136375Sbrian if ((*buf = malloc(*len)) == NULL) { 218136375Sbrian log_Printf(LogWARN, "demangle: Out of memory (%lu bytes)\n", (u_long)*len); 219136375Sbrian *len = 0; 220136375Sbrian } else 221136375Sbrian memcpy(*buf, P + 1, *len); 22298132Sbrian} 22398132Sbrian#endif 22498132Sbrian 225116622Sume/* XXX: This should go into librarius. */ 226116622Sume#ifndef NOINET6 227116622Sumestatic uint8_t * 228116622Sumerad_cvt_ipv6prefix(const void *data, size_t len) 229116622Sume{ 230116622Sume const size_t ipv6len = sizeof(struct in6_addr) + 2; 231116622Sume uint8_t *s; 232116622Sume 233116622Sume if (len > ipv6len) 234116622Sume return NULL; 235116622Sume s = malloc(ipv6len); 236116622Sume if (s != NULL) { 237116622Sume memset(s, 0, ipv6len); 238116622Sume memcpy(s, data, len); 239116622Sume } 240116622Sume return s; 241116622Sume} 242116622Sume#endif 243116622Sume 24443693Sbrian/* 24543693Sbrian * rad_continue_send_request() has given us `got' (non-zero). Deal with it. 24643693Sbrian */ 24743693Sbrianstatic void 24843693Sbrianradius_Process(struct radius *r, int got) 24943313Sbrian{ 25043313Sbrian char *argv[MAXARGS], *nuke; 25143693Sbrian struct bundle *bundle; 25296324Sbrian int argc, addrs, res, width; 25345910Sbrian size_t len; 25481634Sbrian struct ncprange dest; 25581634Sbrian struct ncpaddr gw; 25643693Sbrian const void *data; 25771972Sbrian const char *stype; 25896324Sbrian u_int32_t ipaddr, vendor; 25981634Sbrian struct in_addr ip; 260116586Sume#ifndef NOINET6 261116622Sume uint8_t ipv6addr[INET6_ADDRSTRLEN]; 262116586Sume struct in6_addr ip6; 263116586Sume#endif 26443313Sbrian 26543693Sbrian r->cx.fd = -1; /* Stop select()ing */ 26671972Sbrian stype = r->cx.auth ? "auth" : "acct"; 26743313Sbrian 26843313Sbrian switch (got) { 26943313Sbrian case RAD_ACCESS_ACCEPT: 270132273Sbrian log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 271132273Sbrian "Radius(%s): ACCEPT received\n", stype); 27271972Sbrian if (!r->cx.auth) { 27371972Sbrian rad_close(r->cx.rad); 27471972Sbrian return; 27571972Sbrian } 27643313Sbrian break; 27743313Sbrian 27843693Sbrian case RAD_ACCESS_REJECT: 279132273Sbrian log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 280132273Sbrian "Radius(%s): REJECT received\n", stype); 28196324Sbrian if (!r->cx.auth) { 28296324Sbrian rad_close(r->cx.rad); 28396324Sbrian return; 28496324Sbrian } 28596324Sbrian break; 28643693Sbrian 28743313Sbrian case RAD_ACCESS_CHALLENGE: 28843313Sbrian /* we can't deal with this (for now) ! */ 289132273Sbrian log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 290132273Sbrian "Radius: CHALLENGE received (can't handle yet)\n"); 29171972Sbrian if (r->cx.auth) 29271972Sbrian auth_Failure(r->cx.auth); 29343693Sbrian rad_close(r->cx.rad); 29443693Sbrian return; 29543313Sbrian 29665178Sbrian case RAD_ACCOUNTING_RESPONSE: 297132273Sbrian /* 298132273Sbrian * It's probably not ideal to log this at PHASE level as we'll see 299132273Sbrian * too much stuff going to the log when ``set rad_alive'' is used. 300132273Sbrian * So we differ from older behaviour (ppp version 3.1 and before) 301132273Sbrian * and just log accounting responses to LogRADIUS. 302132273Sbrian */ 303132273Sbrian log_Printf(LogRADIUS, "Radius(%s): Accounting response received\n", 304132273Sbrian stype); 30571972Sbrian if (r->cx.auth) 30671972Sbrian auth_Failure(r->cx.auth); /* unexpected !!! */ 30771972Sbrian 30865178Sbrian /* No further processing for accounting requests, please */ 30965178Sbrian rad_close(r->cx.rad); 31065178Sbrian return; 31165178Sbrian 31243313Sbrian case -1: 313132273Sbrian log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 314132273Sbrian "radius(%s): %s\n", stype, rad_strerror(r->cx.rad)); 31571972Sbrian if (r->cx.auth) 31671972Sbrian auth_Failure(r->cx.auth); 31743693Sbrian rad_close(r->cx.rad); 31843693Sbrian return; 31943313Sbrian 32043313Sbrian default: 32171972Sbrian log_Printf(LogERROR, "rad_send_request(%s): Failed %d: %s\n", stype, 32243693Sbrian got, rad_strerror(r->cx.rad)); 32371972Sbrian if (r->cx.auth) 32471972Sbrian auth_Failure(r->cx.auth); 32543693Sbrian rad_close(r->cx.rad); 32643693Sbrian return; 32743313Sbrian } 32843313Sbrian 32996324Sbrian /* Let's see what we've got in our reply */ 33043313Sbrian r->ip.s_addr = r->mask.s_addr = INADDR_NONE; 33143313Sbrian r->mtu = 0; 33243313Sbrian r->vj = 0; 33396324Sbrian while ((res = rad_get_attr(r->cx.rad, &data, &len)) > 0) { 33496324Sbrian switch (res) { 33543313Sbrian case RAD_FRAMED_IP_ADDRESS: 33643313Sbrian r->ip = rad_cvt_addr(data); 337132273Sbrian log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 338132273Sbrian " IP %s\n", inet_ntoa(r->ip)); 33943313Sbrian break; 34043313Sbrian 34196153Sbrian case RAD_FILTER_ID: 34296153Sbrian free(r->filterid); 34396153Sbrian if ((r->filterid = rad_cvt_string(data, len)) == NULL) { 34496153Sbrian log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); 34596324Sbrian auth_Failure(r->cx.auth); 34696153Sbrian rad_close(r->cx.rad); 34796153Sbrian return; 34896153Sbrian } 349132273Sbrian log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 350132273Sbrian " Filter \"%s\"\n", r->filterid); 35196153Sbrian break; 35296153Sbrian 35396153Sbrian case RAD_SESSION_TIMEOUT: 35496153Sbrian r->sessiontime = rad_cvt_int(data); 355132273Sbrian log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 356132273Sbrian " Session-Timeout %lu\n", r->sessiontime); 35796153Sbrian break; 35896153Sbrian 35943313Sbrian case RAD_FRAMED_IP_NETMASK: 36043313Sbrian r->mask = rad_cvt_addr(data); 361132273Sbrian log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 362132273Sbrian " Netmask %s\n", inet_ntoa(r->mask)); 36343313Sbrian break; 36443313Sbrian 36543313Sbrian case RAD_FRAMED_MTU: 36643313Sbrian r->mtu = rad_cvt_int(data); 367132273Sbrian log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 368132273Sbrian " MTU %lu\n", r->mtu); 36943313Sbrian break; 37043313Sbrian 37143313Sbrian case RAD_FRAMED_ROUTING: 37243313Sbrian /* Disabled for now - should we automatically set up some filters ? */ 37343313Sbrian /* rad_cvt_int(data); */ 37443313Sbrian /* bit 1 = Send routing packets */ 37543313Sbrian /* bit 2 = Receive routing packets */ 37643313Sbrian break; 37743313Sbrian 37843313Sbrian case RAD_FRAMED_COMPRESSION: 37943313Sbrian r->vj = rad_cvt_int(data) == 1 ? 1 : 0; 380132273Sbrian log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 381132273Sbrian " VJ %sabled\n", r->vj ? "en" : "dis"); 38243313Sbrian break; 38343313Sbrian 38443313Sbrian case RAD_FRAMED_ROUTE: 38543313Sbrian /* 38643313Sbrian * We expect a string of the format ``dest[/bits] gw [metrics]'' 38743313Sbrian * Any specified metrics are ignored. MYADDR and HISADDR are 38843313Sbrian * understood for ``dest'' and ``gw'' and ``0.0.0.0'' is the same 38943313Sbrian * as ``HISADDR''. 39043313Sbrian */ 39143313Sbrian 39243313Sbrian if ((nuke = rad_cvt_string(data, len)) == NULL) { 39343693Sbrian log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); 39496324Sbrian auth_Failure(r->cx.auth); 39543693Sbrian rad_close(r->cx.rad); 39643693Sbrian return; 39743313Sbrian } 39843313Sbrian 399132273Sbrian log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 400132273Sbrian " Route: %s\n", nuke); 40143693Sbrian bundle = r->cx.auth->physical->dl->bundle; 40281634Sbrian ip.s_addr = INADDR_ANY; 403116586Sume ncpaddr_setip4(&gw, ip); 40481634Sbrian ncprange_setip4host(&dest, ip); 40543313Sbrian argc = command_Interpret(nuke, strlen(nuke), argv); 40654914Sbrian if (argc < 0) 40754914Sbrian log_Printf(LogWARN, "radius: %s: Syntax error\n", 40854914Sbrian argc == 1 ? argv[0] : "\"\""); 40954914Sbrian else if (argc < 2) 41043313Sbrian log_Printf(LogWARN, "radius: %s: Invalid route\n", 41143313Sbrian argc == 1 ? argv[0] : "\"\""); 41243313Sbrian else if ((strcasecmp(argv[0], "default") != 0 && 41381634Sbrian !ncprange_aton(&dest, &bundle->ncp, argv[0])) || 41481634Sbrian !ncpaddr_aton(&gw, &bundle->ncp, argv[1])) 41543313Sbrian log_Printf(LogWARN, "radius: %s %s: Invalid route\n", 41643313Sbrian argv[0], argv[1]); 41743313Sbrian else { 41881634Sbrian ncprange_getwidth(&dest, &width); 41981634Sbrian if (width == 32 && strchr(argv[0], '/') == NULL) { 42043313Sbrian /* No mask specified - use the natural mask */ 42181634Sbrian ncprange_getip4addr(&dest, &ip); 42281634Sbrian ncprange_setip4mask(&dest, addr2mask(ip)); 42381634Sbrian } 42443313Sbrian addrs = 0; 42543313Sbrian 42643313Sbrian if (!strncasecmp(argv[0], "HISADDR", 7)) 42743313Sbrian addrs = ROUTE_DSTHISADDR; 42843313Sbrian else if (!strncasecmp(argv[0], "MYADDR", 6)) 42943313Sbrian addrs = ROUTE_DSTMYADDR; 43043313Sbrian 43181634Sbrian if (ncpaddr_getip4addr(&gw, &ipaddr) && ipaddr == INADDR_ANY) { 43243313Sbrian addrs |= ROUTE_GWHISADDR; 43381634Sbrian ncpaddr_setip4(&gw, bundle->ncp.ipcp.peer_ip); 43443313Sbrian } else if (strcasecmp(argv[1], "HISADDR") == 0) 43543313Sbrian addrs |= ROUTE_GWHISADDR; 43643313Sbrian 43781634Sbrian route_Add(&r->routes, addrs, &dest, &gw); 43843313Sbrian } 43943313Sbrian free(nuke); 44043313Sbrian break; 44196324Sbrian 44296324Sbrian case RAD_REPLY_MESSAGE: 44396324Sbrian free(r->repstr); 44496324Sbrian if ((r->repstr = rad_cvt_string(data, len)) == NULL) { 44596324Sbrian log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); 44696324Sbrian auth_Failure(r->cx.auth); 44796324Sbrian rad_close(r->cx.rad); 44896324Sbrian return; 44996324Sbrian } 450132273Sbrian log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 451132273Sbrian " Reply-Message \"%s\"\n", r->repstr); 45296324Sbrian break; 45396324Sbrian 454116586Sume#ifndef NOINET6 455116622Sume case RAD_FRAMED_IPV6_PREFIX: 456116622Sume free(r->ipv6prefix); 457167147Sume if ((r->ipv6prefix = rad_cvt_ipv6prefix(data, len)) == NULL) { 458167147Sume log_Printf(LogERROR, "rad_cvt_ipv6prefix: %s\n", 459167147Sume "Malformed attribute in response"); 460167147Sume auth_Failure(r->cx.auth); 461167147Sume rad_close(r->cx.rad); 462167147Sume return; 463167147Sume } 464116622Sume inet_ntop(AF_INET6, &r->ipv6prefix[2], ipv6addr, sizeof(ipv6addr)); 465132273Sbrian log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 466132273Sbrian " IPv6 %s/%d\n", ipv6addr, r->ipv6prefix[1]); 467116622Sume break; 468116622Sume 469116586Sume case RAD_FRAMED_IPV6_ROUTE: 470116586Sume /* 471116586Sume * We expect a string of the format ``dest[/bits] gw [metrics]'' 472116586Sume * Any specified metrics are ignored. MYADDR6 and HISADDR6 are 473116586Sume * understood for ``dest'' and ``gw'' and ``::'' is the same 474116586Sume * as ``HISADDR6''. 475116586Sume */ 476116586Sume 477116586Sume if ((nuke = rad_cvt_string(data, len)) == NULL) { 478116586Sume log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); 479116586Sume auth_Failure(r->cx.auth); 480116586Sume rad_close(r->cx.rad); 481116586Sume return; 482116586Sume } 483116586Sume 484132273Sbrian log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 485132273Sbrian " IPv6 Route: %s\n", nuke); 486116586Sume bundle = r->cx.auth->physical->dl->bundle; 487116586Sume ncpaddr_setip6(&gw, &in6addr_any); 488116586Sume ncprange_set(&dest, &gw, 0); 489116586Sume argc = command_Interpret(nuke, strlen(nuke), argv); 490116586Sume if (argc < 0) 491116586Sume log_Printf(LogWARN, "radius: %s: Syntax error\n", 492116586Sume argc == 1 ? argv[0] : "\"\""); 493116586Sume else if (argc < 2) 494116586Sume log_Printf(LogWARN, "radius: %s: Invalid route\n", 495116586Sume argc == 1 ? argv[0] : "\"\""); 496116586Sume else if ((strcasecmp(argv[0], "default") != 0 && 497116586Sume !ncprange_aton(&dest, &bundle->ncp, argv[0])) || 498116586Sume !ncpaddr_aton(&gw, &bundle->ncp, argv[1])) 499116586Sume log_Printf(LogWARN, "radius: %s %s: Invalid route\n", 500116586Sume argv[0], argv[1]); 501116586Sume else { 502116586Sume addrs = 0; 503116586Sume 504116586Sume if (!strncasecmp(argv[0], "HISADDR6", 8)) 505116586Sume addrs = ROUTE_DSTHISADDR6; 506116586Sume else if (!strncasecmp(argv[0], "MYADDR6", 7)) 507116586Sume addrs = ROUTE_DSTMYADDR6; 508116586Sume 509116586Sume if (ncpaddr_getip6(&gw, &ip6) && IN6_IS_ADDR_UNSPECIFIED(&ip6)) { 510116586Sume addrs |= ROUTE_GWHISADDR6; 511116586Sume ncpaddr_copy(&gw, &bundle->ncp.ipv6cp.hisaddr); 512116586Sume } else if (strcasecmp(argv[1], "HISADDR6") == 0) 513116586Sume addrs |= ROUTE_GWHISADDR6; 514116586Sume 515116586Sume route_Add(&r->ipv6routes, addrs, &dest, &gw); 516116586Sume } 517116586Sume free(nuke); 518116586Sume break; 519116586Sume#endif 520116586Sume 52196324Sbrian case RAD_VENDOR_SPECIFIC: 52296324Sbrian if ((res = rad_get_vendor_attr(&vendor, &data, &len)) <= 0) { 52396324Sbrian log_Printf(LogERROR, "rad_get_vendor_attr: %s (failing!)\n", 52496324Sbrian rad_strerror(r->cx.rad)); 52596324Sbrian auth_Failure(r->cx.auth); 52696324Sbrian rad_close(r->cx.rad); 52796324Sbrian return; 52896324Sbrian } 52996324Sbrian 53096324Sbrian switch (vendor) { 53196324Sbrian case RAD_VENDOR_MICROSOFT: 53296324Sbrian switch (res) { 53398132Sbrian#ifndef NODES 53496324Sbrian case RAD_MICROSOFT_MS_CHAP_ERROR: 53596324Sbrian free(r->errstr); 53698149Sbrian if (len == 0) 53798149Sbrian r->errstr = NULL; 53898149Sbrian else { 53998712Sbrian if (len < 3 || ((const char *)data)[1] != '=') { 54098712Sbrian /* 54198712Sbrian * Only point at the String field if we don't think the 54298712Sbrian * peer has misformatted the response. 54398712Sbrian */ 544132790Skan data = (const char *)data + 1; 54598712Sbrian len--; 54698967Sbrian } else 54798967Sbrian log_Printf(LogWARN, "Warning: The MS-CHAP-Error " 54898967Sbrian "attribute is mis-formatted. Compensating\n"); 54998712Sbrian if ((r->errstr = rad_cvt_string((const char *)data, 55098712Sbrian len)) == NULL) { 55198149Sbrian log_Printf(LogERROR, "rad_cvt_string: %s\n", 55298149Sbrian rad_strerror(r->cx.rad)); 55398149Sbrian auth_Failure(r->cx.auth); 55498149Sbrian rad_close(r->cx.rad); 55598149Sbrian return; 55698149Sbrian } 557132273Sbrian log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 558132273Sbrian " MS-CHAP-Error \"%s\"\n", r->errstr); 55996324Sbrian } 56096324Sbrian break; 56196730Sbrian 56296730Sbrian case RAD_MICROSOFT_MS_CHAP2_SUCCESS: 56396730Sbrian free(r->msrepstr); 56498149Sbrian if (len == 0) 56598149Sbrian r->msrepstr = NULL; 56698149Sbrian else { 56798712Sbrian if (len < 3 || ((const char *)data)[1] != '=') { 56898712Sbrian /* 56998712Sbrian * Only point at the String field if we don't think the 57098712Sbrian * peer has misformatted the response. 57198712Sbrian */ 572132790Skan data = (const char *)data + 1; 57398712Sbrian len--; 57498967Sbrian } else 57598967Sbrian log_Printf(LogWARN, "Warning: The MS-CHAP2-Success " 57698967Sbrian "attribute is mis-formatted. Compensating\n"); 57798712Sbrian if ((r->msrepstr = rad_cvt_string((const char *)data, 57898712Sbrian len)) == NULL) { 57998149Sbrian log_Printf(LogERROR, "rad_cvt_string: %s\n", 58098149Sbrian rad_strerror(r->cx.rad)); 58198149Sbrian auth_Failure(r->cx.auth); 58298149Sbrian rad_close(r->cx.rad); 58398149Sbrian return; 58498149Sbrian } 585132273Sbrian log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 586132273Sbrian " MS-CHAP2-Success \"%s\"\n", r->msrepstr); 58796730Sbrian } 58896730Sbrian break; 58998243Sbrian 59098132Sbrian case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY: 59198132Sbrian r->mppe.policy = rad_cvt_int(data); 592132273Sbrian log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 593132273Sbrian " MS-MPPE-Encryption-Policy %s\n", 59498132Sbrian radius_policyname(r->mppe.policy)); 59598132Sbrian break; 59698132Sbrian 59798132Sbrian case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES: 59898132Sbrian r->mppe.types = rad_cvt_int(data); 599132273Sbrian log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 600132273Sbrian " MS-MPPE-Encryption-Types %s\n", 60198132Sbrian radius_typesname(r->mppe.types)); 60298132Sbrian break; 60398132Sbrian 60498132Sbrian case RAD_MICROSOFT_MS_MPPE_RECV_KEY: 60598132Sbrian free(r->mppe.recvkey); 60698132Sbrian demangle(r, data, len, &r->mppe.recvkey, &r->mppe.recvkeylen); 607132273Sbrian log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 608132273Sbrian " MS-MPPE-Recv-Key ********\n"); 60998132Sbrian break; 61098132Sbrian 61198132Sbrian case RAD_MICROSOFT_MS_MPPE_SEND_KEY: 61298132Sbrian demangle(r, data, len, &r->mppe.sendkey, &r->mppe.sendkeylen); 613132273Sbrian log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 614132273Sbrian " MS-MPPE-Send-Key ********\n"); 61598132Sbrian break; 61698132Sbrian#endif 61798132Sbrian 61896324Sbrian default: 61996324Sbrian log_Printf(LogDEBUG, "Dropping MICROSOFT vendor specific " 62096324Sbrian "RADIUS attribute %d\n", res); 62196324Sbrian break; 62296324Sbrian } 62396324Sbrian break; 62496324Sbrian 62596324Sbrian default: 62696324Sbrian log_Printf(LogDEBUG, "Dropping vendor %lu RADIUS attribute %d\n", 62796324Sbrian (unsigned long)vendor, res); 62896324Sbrian break; 62996324Sbrian } 63096324Sbrian break; 63196324Sbrian 63296324Sbrian default: 63396324Sbrian log_Printf(LogDEBUG, "Dropping RADIUS attribute %d\n", res); 63496324Sbrian break; 63543313Sbrian } 63643313Sbrian } 63743313Sbrian 63896324Sbrian if (res == -1) { 63943693Sbrian log_Printf(LogERROR, "rad_get_attr: %s (failing!)\n", 64043693Sbrian rad_strerror(r->cx.rad)); 64143693Sbrian auth_Failure(r->cx.auth); 64296324Sbrian } else if (got == RAD_ACCESS_REJECT) 64396324Sbrian auth_Failure(r->cx.auth); 64496324Sbrian else { 64543693Sbrian r->valid = 1; 64643693Sbrian auth_Success(r->cx.auth); 64743313Sbrian } 64896324Sbrian rad_close(r->cx.rad); 64943693Sbrian} 65043313Sbrian 65143693Sbrian/* 65258038Sbrian * We've either timed out or select()ed on the read descriptor 65343693Sbrian */ 65443693Sbrianstatic void 65543693Sbrianradius_Continue(struct radius *r, int sel) 65643693Sbrian{ 65743693Sbrian struct timeval tv; 65843693Sbrian int got; 65943313Sbrian 66043693Sbrian timer_Stop(&r->cx.timer); 66143693Sbrian if ((got = rad_continue_send_request(r->cx.rad, sel, &r->cx.fd, &tv)) == 0) { 662132273Sbrian log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 663132273Sbrian "Radius: Request re-sent\n"); 66443693Sbrian r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS; 66543693Sbrian timer_Start(&r->cx.timer); 66643693Sbrian return; 66743693Sbrian } 66843693Sbrian 66943693Sbrian radius_Process(r, got); 67043313Sbrian} 67143313Sbrian 67243693Sbrian/* 67343693Sbrian * Time to call rad_continue_send_request() - timed out. 67443693Sbrian */ 67543693Sbrianstatic void 67643693Sbrianradius_Timeout(void *v) 67743693Sbrian{ 67843693Sbrian radius_Continue((struct radius *)v, 0); 67943693Sbrian} 68043693Sbrian 68143693Sbrian/* 68243693Sbrian * Time to call rad_continue_send_request() - something to read. 68343693Sbrian */ 68443693Sbrianstatic void 685134789Sbrianradius_Read(struct fdescriptor *d, struct bundle *bundle __unused, 686134789Sbrian const fd_set *fdset __unused) 68743693Sbrian{ 68843693Sbrian radius_Continue(descriptor2radius(d), 1); 68943693Sbrian} 69043693Sbrian 69143693Sbrian/* 692140905Sbrian * Flush any pending transactions 693140905Sbrian */ 694140905Sbrianvoid 695140905Sbrianradius_Flush(struct radius *r) 696140905Sbrian{ 697140905Sbrian struct timeval tv; 698140905Sbrian fd_set s; 699140905Sbrian 700140905Sbrian while (r->cx.fd != -1) { 701140905Sbrian FD_ZERO(&s); 702140905Sbrian FD_SET(r->cx.fd, &s); 703140905Sbrian tv.tv_sec = 0; 704140905Sbrian tv.tv_usec = TICKUNIT; 705140905Sbrian select(r->cx.fd + 1, &s, NULL, NULL, &tv); 706140905Sbrian radius_Continue(r, 1); 707140905Sbrian } 708140905Sbrian} 709140905Sbrian 710140905Sbrian/* 71158038Sbrian * Behave as a struct fdescriptor (descriptor.h) 71243693Sbrian */ 71343693Sbrianstatic int 714134789Sbrianradius_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w __unused, 715134789Sbrian fd_set *e __unused, int *n) 71643693Sbrian{ 71743693Sbrian struct radius *rad = descriptor2radius(d); 71843693Sbrian 71943693Sbrian if (r && rad->cx.fd != -1) { 72043693Sbrian FD_SET(rad->cx.fd, r); 72143693Sbrian if (*n < rad->cx.fd + 1) 72243693Sbrian *n = rad->cx.fd + 1; 72343693Sbrian log_Printf(LogTIMER, "Radius: fdset(r) %d\n", rad->cx.fd); 72443693Sbrian return 1; 72543693Sbrian } 72643693Sbrian 72743693Sbrian return 0; 72843693Sbrian} 72943693Sbrian 73043693Sbrian/* 73158038Sbrian * Behave as a struct fdescriptor (descriptor.h) 73243693Sbrian */ 73343693Sbrianstatic int 73458028Sbrianradius_IsSet(struct fdescriptor *d, const fd_set *fdset) 73543693Sbrian{ 73643693Sbrian struct radius *r = descriptor2radius(d); 73743693Sbrian 73843693Sbrian return r && r->cx.fd != -1 && FD_ISSET(r->cx.fd, fdset); 73943693Sbrian} 74043693Sbrian 74143693Sbrian/* 74258038Sbrian * Behave as a struct fdescriptor (descriptor.h) 74343693Sbrian */ 74443693Sbrianstatic int 745134789Sbrianradius_Write(struct fdescriptor *d __unused, struct bundle *bundle __unused, 746134789Sbrian const fd_set *fdset __unused) 74743693Sbrian{ 74843693Sbrian /* We never want to write here ! */ 74943693Sbrian log_Printf(LogALERT, "radius_Write: Internal error: Bad call !\n"); 75043693Sbrian return 0; 75143693Sbrian} 75243693Sbrian 75343693Sbrian/* 75443693Sbrian * Initialise ourselves 75543693Sbrian */ 75643313Sbrianvoid 75743693Sbrianradius_Init(struct radius *r) 75843693Sbrian{ 75943693Sbrian r->desc.type = RADIUS_DESCRIPTOR; 76043693Sbrian r->desc.UpdateSet = radius_UpdateSet; 76143693Sbrian r->desc.IsSet = radius_IsSet; 76243693Sbrian r->desc.Read = radius_Read; 76343693Sbrian r->desc.Write = radius_Write; 76496324Sbrian r->cx.fd = -1; 76596324Sbrian r->cx.rad = NULL; 76643693Sbrian memset(&r->cx.timer, '\0', sizeof r->cx.timer); 76796324Sbrian r->cx.auth = NULL; 76896324Sbrian r->valid = 0; 76996324Sbrian r->vj = 0; 77096324Sbrian r->ip.s_addr = INADDR_ANY; 77196324Sbrian r->mask.s_addr = INADDR_NONE; 77296324Sbrian r->routes = NULL; 77396324Sbrian r->mtu = DEF_MTU; 77496730Sbrian r->msrepstr = NULL; 77596324Sbrian r->repstr = NULL; 776116586Sume#ifndef NOINET6 777116622Sume r->ipv6prefix = NULL; 778116586Sume r->ipv6routes = NULL; 779116586Sume#endif 78096324Sbrian r->errstr = NULL; 78198132Sbrian r->mppe.policy = 0; 78298132Sbrian r->mppe.types = 0; 78398132Sbrian r->mppe.recvkey = NULL; 78498132Sbrian r->mppe.recvkeylen = 0; 78598132Sbrian r->mppe.sendkey = NULL; 78698132Sbrian r->mppe.sendkeylen = 0; 787241844Seadler *r->cfg.file = '\0'; 78865178Sbrian log_Printf(LogDEBUG, "Radius: radius_Init\n"); 78943693Sbrian} 79043693Sbrian 79143693Sbrian/* 79243693Sbrian * Forget everything and go back to initialised state. 79343693Sbrian */ 79443693Sbrianvoid 79543693Sbrianradius_Destroy(struct radius *r) 79643693Sbrian{ 79743693Sbrian r->valid = 0; 79865178Sbrian log_Printf(LogDEBUG, "Radius: radius_Destroy\n"); 79943693Sbrian timer_Stop(&r->cx.timer); 80043693Sbrian route_DeleteAll(&r->routes); 801116586Sume#ifndef NOINET6 802116586Sume route_DeleteAll(&r->ipv6routes); 803116586Sume#endif 80496153Sbrian free(r->filterid); 80596153Sbrian r->filterid = NULL; 80696730Sbrian free(r->msrepstr); 80796730Sbrian r->msrepstr = NULL; 80896324Sbrian free(r->repstr); 80996324Sbrian r->repstr = NULL; 810116622Sume#ifndef NOINET6 811116622Sume free(r->ipv6prefix); 812116622Sume r->ipv6prefix = NULL; 813116622Sume#endif 81496324Sbrian free(r->errstr); 81596324Sbrian r->errstr = NULL; 81698132Sbrian free(r->mppe.recvkey); 81798132Sbrian r->mppe.recvkey = NULL; 81898132Sbrian r->mppe.recvkeylen = 0; 81998132Sbrian free(r->mppe.sendkey); 82098132Sbrian r->mppe.sendkey = NULL; 82198132Sbrian r->mppe.sendkeylen = 0; 82243693Sbrian if (r->cx.fd != -1) { 82343693Sbrian r->cx.fd = -1; 82443693Sbrian rad_close(r->cx.rad); 82543693Sbrian } 82643693Sbrian} 82743693Sbrian 82896582Sbrianstatic int 829169986Snovelradius_put_physical_details(struct radius *rad, struct physical *p) 83096582Sbrian{ 83196582Sbrian int slot, type; 83296582Sbrian 83396582Sbrian type = RAD_VIRTUAL; 83496582Sbrian if (p->handler) 83596582Sbrian switch (p->handler->type) { 83696582Sbrian case I4B_DEVICE: 83796582Sbrian type = RAD_ISDN_SYNC; 83896582Sbrian break; 83996582Sbrian 84096582Sbrian case TTY_DEVICE: 84196582Sbrian type = RAD_ASYNC; 84296582Sbrian break; 84396582Sbrian 84496582Sbrian case ETHER_DEVICE: 84596582Sbrian type = RAD_ETHERNET; 84696582Sbrian break; 84796582Sbrian 84896582Sbrian case TCP_DEVICE: 84996582Sbrian case UDP_DEVICE: 85096582Sbrian case EXEC_DEVICE: 85196582Sbrian case ATM_DEVICE: 85296582Sbrian case NG_DEVICE: 85396582Sbrian type = RAD_VIRTUAL; 85496582Sbrian break; 85596582Sbrian } 85696582Sbrian 857169986Snovel if (rad_put_int(rad->cx.rad, RAD_NAS_PORT_TYPE, type) != 0) { 858169986Snovel log_Printf(LogERROR, "rad_put: rad_put_int: %s\n", rad_strerror(rad->cx.rad)); 859169986Snovel rad_close(rad->cx.rad); 86096582Sbrian return 0; 86196582Sbrian } 86296582Sbrian 863169986Snovel switch (rad->port_id_type) { 864169986Snovel case RPI_PID: 865169986Snovel slot = (int)getpid(); 866169986Snovel break; 867169986Snovel case RPI_IFNUM: 868169986Snovel slot = p->dl->bundle->iface->index; 869169986Snovel break; 870169986Snovel case RPI_TUNNUM: 871169986Snovel slot = p->dl->bundle->unit; 872169986Snovel break; 873169986Snovel case RPI_DEFAULT: 874169986Snovel default: 875169986Snovel slot = physical_Slot(p); 876169986Snovel break; 877169986Snovel } 878169986Snovel 879169986Snovel if (slot >= 0) 880169986Snovel if (rad_put_int(rad->cx.rad, RAD_NAS_PORT, slot) != 0) { 881169986Snovel log_Printf(LogERROR, "rad_put: rad_put_int: %s\n", rad_strerror(rad->cx.rad)); 882169986Snovel rad_close(rad->cx.rad); 88396582Sbrian return 0; 88496582Sbrian } 88596582Sbrian 88696582Sbrian return 1; 88796582Sbrian} 88896582Sbrian 88943693Sbrian/* 89043693Sbrian * Start an authentication request to the RADIUS server. 89143693Sbrian */ 89296730Sbrianint 89343693Sbrianradius_Authenticate(struct radius *r, struct authinfo *authp, const char *name, 89496730Sbrian const char *key, int klen, const char *nchallenge, 89598311Sbrian int nclen) 89643693Sbrian{ 897134789Sbrian char hostname[MAXHOSTNAMELEN]; 89843693Sbrian struct timeval tv; 899134789Sbrian const char *what = "questionable"; /* silence warnings! */ 900134789Sbrian char *mac_addr; 90196582Sbrian int got; 90250840Sbrian struct hostent *hp; 90398132Sbrian struct in_addr hostaddr; 90496324Sbrian#ifndef NODES 90596730Sbrian struct mschap_response msresp; 90696730Sbrian struct mschap2_response msresp2; 90798311Sbrian const struct MSCHAPv2_resp *keyv2; 90896324Sbrian#endif 90943693Sbrian 91043693Sbrian if (!*r->cfg.file) 91196730Sbrian return 0; 91243693Sbrian 91343693Sbrian if (r->cx.fd != -1) 91443693Sbrian /* 91543693Sbrian * We assume that our name/key/challenge is the same as last time, 91643693Sbrian * and just continue to wait for the RADIUS server(s). 91743693Sbrian */ 91896730Sbrian return 1; 91943693Sbrian 92043693Sbrian radius_Destroy(r); 92143693Sbrian 92265178Sbrian if ((r->cx.rad = rad_auth_open()) == NULL) { 92365178Sbrian log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno)); 92496730Sbrian return 0; 92543693Sbrian } 92643693Sbrian 92743693Sbrian if (rad_config(r->cx.rad, r->cfg.file) != 0) { 92843693Sbrian log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad)); 92943693Sbrian rad_close(r->cx.rad); 93096730Sbrian return 0; 93143693Sbrian } 93243693Sbrian 93343693Sbrian if (rad_create_request(r->cx.rad, RAD_ACCESS_REQUEST) != 0) { 93443693Sbrian log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad)); 93543693Sbrian rad_close(r->cx.rad); 93696730Sbrian return 0; 93743693Sbrian } 93843693Sbrian 93999418Sbrian if (rad_put_string(r->cx.rad, RAD_USER_NAME, name) != 0 || 94043693Sbrian rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 || 94143693Sbrian rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) { 94243693Sbrian log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 94343693Sbrian rad_close(r->cx.rad); 94496730Sbrian return 0; 94543693Sbrian } 94643693Sbrian 94796324Sbrian switch (authp->physical->link.lcp.want_auth) { 94896324Sbrian case PROTO_PAP: 94996324Sbrian /* We're talking PAP */ 95096324Sbrian if (rad_put_attr(r->cx.rad, RAD_USER_PASSWORD, key, klen) != 0) { 95196324Sbrian log_Printf(LogERROR, "PAP: rad_put_string: %s\n", 95243693Sbrian rad_strerror(r->cx.rad)); 95343693Sbrian rad_close(r->cx.rad); 95496730Sbrian return 0; 95543693Sbrian } 956132273Sbrian what = "PAP"; 95796324Sbrian break; 95896324Sbrian 95996324Sbrian case PROTO_CHAP: 96096324Sbrian switch (authp->physical->link.lcp.want_authtype) { 96196324Sbrian case 0x5: 96296324Sbrian if (rad_put_attr(r->cx.rad, RAD_CHAP_PASSWORD, key, klen) != 0 || 96396730Sbrian rad_put_attr(r->cx.rad, RAD_CHAP_CHALLENGE, nchallenge, nclen) != 0) { 96496324Sbrian log_Printf(LogERROR, "CHAP: rad_put_string: %s\n", 96596324Sbrian rad_strerror(r->cx.rad)); 96696324Sbrian rad_close(r->cx.rad); 96796730Sbrian return 0; 96896324Sbrian } 969132273Sbrian what = "CHAP"; 97096324Sbrian break; 97196324Sbrian 97296324Sbrian#ifndef NODES 97396324Sbrian case 0x80: 97496324Sbrian if (klen != 50) { 97596730Sbrian log_Printf(LogERROR, "CHAP80: Unrecognised key length %d\n", klen); 97696324Sbrian rad_close(r->cx.rad); 97796730Sbrian return 0; 97896324Sbrian } 97996730Sbrian 98096324Sbrian rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT, 98196730Sbrian RAD_MICROSOFT_MS_CHAP_CHALLENGE, nchallenge, nclen); 98296730Sbrian msresp.ident = *key; 98396730Sbrian msresp.flags = 0x01; 98496730Sbrian memcpy(msresp.lm_response, key + 1, 24); 98596730Sbrian memcpy(msresp.nt_response, key + 25, 24); 98696324Sbrian rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT, 98796730Sbrian RAD_MICROSOFT_MS_CHAP_RESPONSE, &msresp, 98896730Sbrian sizeof msresp); 989132273Sbrian what = "MSCHAP"; 99096324Sbrian break; 99196324Sbrian 99296324Sbrian case 0x81: 99398311Sbrian if (klen != sizeof(*keyv2) + 1) { 99496730Sbrian log_Printf(LogERROR, "CHAP81: Unrecognised key length %d\n", klen); 99596730Sbrian rad_close(r->cx.rad); 99696730Sbrian return 0; 99796730Sbrian } 99896730Sbrian 99998311Sbrian keyv2 = (const struct MSCHAPv2_resp *)(key + 1); 100096730Sbrian rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT, 100196730Sbrian RAD_MICROSOFT_MS_CHAP_CHALLENGE, nchallenge, nclen); 100296730Sbrian msresp2.ident = *key; 100398311Sbrian msresp2.flags = keyv2->Flags; 100498311Sbrian memcpy(msresp2.response, keyv2->NTResponse, sizeof msresp2.response); 100596730Sbrian memset(msresp2.reserved, '\0', sizeof msresp2.reserved); 100698311Sbrian memcpy(msresp2.pchallenge, keyv2->PeerChallenge, 100798311Sbrian sizeof msresp2.pchallenge); 100896730Sbrian rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT, 100996730Sbrian RAD_MICROSOFT_MS_CHAP2_RESPONSE, &msresp2, 101096730Sbrian sizeof msresp2); 1011132273Sbrian what = "MSCHAPv2"; 101296730Sbrian break; 101396324Sbrian#endif 101496324Sbrian default: 101598243Sbrian log_Printf(LogERROR, "CHAP: Unrecognised type 0x%02x\n", 101696324Sbrian authp->physical->link.lcp.want_authtype); 101796324Sbrian rad_close(r->cx.rad); 101896730Sbrian return 0; 101996324Sbrian } 102043693Sbrian } 102143693Sbrian 102250840Sbrian if (gethostname(hostname, sizeof hostname) != 0) 102350840Sbrian log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno)); 102450840Sbrian else { 1025138198Sbrian if (Enabled(authp->physical->dl->bundle, OPT_NAS_IP_ADDRESS) && 1026138198Sbrian (hp = gethostbyname(hostname)) != NULL) { 102750840Sbrian hostaddr.s_addr = *(u_long *)hp->h_addr; 102850840Sbrian if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) { 102950840Sbrian log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 103050840Sbrian rad_strerror(r->cx.rad)); 103150840Sbrian rad_close(r->cx.rad); 103296730Sbrian return 0; 103350840Sbrian } 103450840Sbrian } 1035138198Sbrian if (Enabled(authp->physical->dl->bundle, OPT_NAS_IDENTIFIER) && 1036138198Sbrian rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) { 103750840Sbrian log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 103850840Sbrian rad_strerror(r->cx.rad)); 103950840Sbrian rad_close(r->cx.rad); 104096730Sbrian return 0; 104150840Sbrian } 104250840Sbrian } 104350840Sbrian 1044131122Sbrian if ((mac_addr = getenv("HISMACADDR")) != NULL && 1045131122Sbrian rad_put_string(r->cx.rad, RAD_CALLING_STATION_ID, mac_addr) != 0) { 1046131122Sbrian log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 1047131122Sbrian rad_close(r->cx.rad); 1048134789Sbrian return 0; 1049131122Sbrian } 1050131122Sbrian 1051169986Snovel radius_put_physical_details(r, authp->physical); 105250840Sbrian 1053132273Sbrian log_Printf(LogRADIUS, "Radius(auth): %s data sent for %s\n", what, name); 1054132273Sbrian 105571972Sbrian r->cx.auth = authp; 105643693Sbrian if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv))) 105743693Sbrian radius_Process(r, got); 105843693Sbrian else { 1059132273Sbrian log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 1060132273Sbrian "Radius: Request sent\n"); 106143693Sbrian log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout); 106243693Sbrian r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS; 106343693Sbrian r->cx.timer.func = radius_Timeout; 106471972Sbrian r->cx.timer.name = "radius auth"; 106543693Sbrian r->cx.timer.arg = r; 106643693Sbrian timer_Start(&r->cx.timer); 106743693Sbrian } 106896730Sbrian 106996730Sbrian return 1; 107043693Sbrian} 107143693Sbrian 1072116588Sume/* Fetch IP, netmask from IPCP */ 1073116588Sumevoid 1074116588Sumeradius_Account_Set_Ip(struct radacct *ac, struct in_addr *peer_ip, 1075116588Sume struct in_addr *netmask) 1076116588Sume{ 1077116588Sume ac->proto = PROTO_IPCP; 1078116990Sume memcpy(&ac->peer.ip.addr, peer_ip, sizeof(ac->peer.ip.addr)); 1079116990Sume memcpy(&ac->peer.ip.mask, netmask, sizeof(ac->peer.ip.mask)); 1080116588Sume} 1081116588Sume 1082116588Sume#ifndef NOINET6 1083116588Sume/* Fetch interface-id from IPV6CP */ 1084116588Sumevoid 1085116588Sumeradius_Account_Set_Ipv6(struct radacct *ac, u_char *ifid) 1086116588Sume{ 1087116588Sume ac->proto = PROTO_IPV6CP; 1088116990Sume memcpy(&ac->peer.ipv6.ifid, ifid, sizeof(ac->peer.ipv6.ifid)); 1089116588Sume} 1090116588Sume#endif 1091116588Sume 109243693Sbrian/* 109365178Sbrian * Send an accounting request to the RADIUS server 109465178Sbrian */ 109565178Sbrianvoid 109698243Sbrianradius_Account(struct radius *r, struct radacct *ac, struct datalink *dl, 1097116588Sume int acct_type, struct pppThroughput *stats) 109865178Sbrian{ 109965178Sbrian struct timeval tv; 110096582Sbrian int got; 110174049Sbrian char hostname[MAXHOSTNAMELEN]; 1102131122Sbrian char *mac_addr; 110365178Sbrian struct hostent *hp; 110498132Sbrian struct in_addr hostaddr; 110565178Sbrian 110665178Sbrian if (!*r->cfg.file) 110765178Sbrian return; 110865178Sbrian 110965178Sbrian if (r->cx.fd != -1) 111065178Sbrian /* 111165178Sbrian * We assume that our name/key/challenge is the same as last time, 111265178Sbrian * and just continue to wait for the RADIUS server(s). 111365178Sbrian */ 111465178Sbrian return; 111565178Sbrian 111698132Sbrian timer_Stop(&r->cx.timer); 111765178Sbrian 111867133Sbrian if ((r->cx.rad = rad_acct_open()) == NULL) { 111965178Sbrian log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno)); 112065178Sbrian return; 112165178Sbrian } 112265178Sbrian 112365178Sbrian if (rad_config(r->cx.rad, r->cfg.file) != 0) { 112465178Sbrian log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad)); 112565178Sbrian rad_close(r->cx.rad); 112665178Sbrian return; 112765178Sbrian } 112865178Sbrian 112965178Sbrian if (rad_create_request(r->cx.rad, RAD_ACCOUNTING_REQUEST) != 0) { 113065178Sbrian log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad)); 113165178Sbrian rad_close(r->cx.rad); 113265178Sbrian return; 113365178Sbrian } 113465178Sbrian 113565178Sbrian /* Grab some accounting data and initialize structure */ 113665178Sbrian if (acct_type == RAD_START) { 113765178Sbrian ac->rad_parent = r; 113865178Sbrian /* Fetch username from datalink */ 113999418Sbrian strncpy(ac->user_name, dl->peer.authname, sizeof ac->user_name); 114065178Sbrian ac->user_name[AUTHLEN-1] = '\0'; 114165178Sbrian 114265178Sbrian ac->authentic = 2; /* Assume RADIUS verified auth data */ 114398243Sbrian 114465178Sbrian /* Generate a session ID */ 114597904Sbrian snprintf(ac->session_id, sizeof ac->session_id, "%s%ld-%s%lu", 114697904Sbrian dl->bundle->cfg.auth.name, (long)getpid(), 114799418Sbrian dl->peer.authname, (unsigned long)stats->uptime); 114865178Sbrian 114965178Sbrian /* And grab our MP socket name */ 115065178Sbrian snprintf(ac->multi_session_id, sizeof ac->multi_session_id, "%s", 115165178Sbrian dl->bundle->ncp.mp.active ? 115265178Sbrian dl->bundle->ncp.mp.server.socket.sun_path : ""); 115365178Sbrian }; 115465178Sbrian 115565178Sbrian if (rad_put_string(r->cx.rad, RAD_USER_NAME, ac->user_name) != 0 || 115665178Sbrian rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 || 1157116588Sume rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) { 115865178Sbrian log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 115965178Sbrian rad_close(r->cx.rad); 116065178Sbrian return; 116165178Sbrian } 1162116588Sume switch (ac->proto) { 1163116588Sume case PROTO_IPCP: 1164116990Sume if (rad_put_addr(r->cx.rad, RAD_FRAMED_IP_ADDRESS, 1165132151Sbrian ac->peer.ip.addr) != 0 || 1166116990Sume rad_put_addr(r->cx.rad, RAD_FRAMED_IP_NETMASK, 1167116990Sume ac->peer.ip.mask) != 0) { 1168116588Sume log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 1169116588Sume rad_close(r->cx.rad); 1170116588Sume return; 1171116588Sume } 1172116588Sume break; 1173116588Sume#ifndef NOINET6 1174116588Sume case PROTO_IPV6CP: 1175116990Sume if (rad_put_attr(r->cx.rad, RAD_FRAMED_INTERFACE_ID, ac->peer.ipv6.ifid, 1176116990Sume sizeof(ac->peer.ipv6.ifid)) != 0) { 1177116588Sume log_Printf(LogERROR, "rad_put_attr: %s\n", rad_strerror(r->cx.rad)); 1178116588Sume rad_close(r->cx.rad); 1179116588Sume return; 1180116588Sume } 1181116622Sume if (r->ipv6prefix) { 1182116622Sume /* 1183116622Sume * Since PPP doesn't delegate an IPv6 prefix to a peer, 1184116622Sume * Framed-IPv6-Prefix may be not used, actually. 1185116622Sume */ 1186116622Sume if (rad_put_attr(r->cx.rad, RAD_FRAMED_IPV6_PREFIX, r->ipv6prefix, 1187116622Sume sizeof(struct in6_addr) + 2) != 0) { 1188116622Sume log_Printf(LogERROR, "rad_put_attr: %s\n", rad_strerror(r->cx.rad)); 1189116622Sume rad_close(r->cx.rad); 1190116622Sume return; 1191116622Sume } 1192116622Sume } 1193116588Sume break; 1194116588Sume#endif 1195116588Sume default: 1196116588Sume /* We don't log any protocol specific information */ 1197116588Sume break; 1198116588Sume } 119965178Sbrian 1200131122Sbrian if ((mac_addr = getenv("HISMACADDR")) != NULL && 1201131122Sbrian rad_put_string(r->cx.rad, RAD_CALLING_STATION_ID, mac_addr) != 0) { 1202131122Sbrian log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 1203131122Sbrian rad_close(r->cx.rad); 1204131122Sbrian return; 1205131122Sbrian } 1206131122Sbrian 120765178Sbrian if (gethostname(hostname, sizeof hostname) != 0) 120865178Sbrian log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno)); 120965178Sbrian else { 1210138198Sbrian if (Enabled(dl->bundle, OPT_NAS_IP_ADDRESS) && 1211138198Sbrian (hp = gethostbyname(hostname)) != NULL) { 121265178Sbrian hostaddr.s_addr = *(u_long *)hp->h_addr; 121365178Sbrian if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) { 121465178Sbrian log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 121565178Sbrian rad_strerror(r->cx.rad)); 121665178Sbrian rad_close(r->cx.rad); 121765178Sbrian return; 121865178Sbrian } 121965178Sbrian } 1220138198Sbrian if (Enabled(dl->bundle, OPT_NAS_IDENTIFIER) && 1221138198Sbrian rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) { 122265178Sbrian log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 122365178Sbrian rad_strerror(r->cx.rad)); 122465178Sbrian rad_close(r->cx.rad); 122565178Sbrian return; 122665178Sbrian } 122765178Sbrian } 122865178Sbrian 1229169986Snovel radius_put_physical_details(r, dl->physical); 123065178Sbrian 123165178Sbrian if (rad_put_int(r->cx.rad, RAD_ACCT_STATUS_TYPE, acct_type) != 0 || 123298243Sbrian rad_put_string(r->cx.rad, RAD_ACCT_SESSION_ID, ac->session_id) != 0 || 123365178Sbrian rad_put_string(r->cx.rad, RAD_ACCT_MULTI_SESSION_ID, 123465178Sbrian ac->multi_session_id) != 0 || 123598243Sbrian rad_put_int(r->cx.rad, RAD_ACCT_DELAY_TIME, 0) != 0) { 123665178Sbrian/* XXX ACCT_DELAY_TIME should be increased each time a packet is waiting */ 123765178Sbrian log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 123865178Sbrian rad_close(r->cx.rad); 123965178Sbrian return; 124065178Sbrian } 124165178Sbrian 1242132273Sbrian if (acct_type == RAD_STOP || acct_type == RAD_ALIVE) 1243132273Sbrian /* Show some statistics */ 1244129457Sdds if (rad_put_int(r->cx.rad, RAD_ACCT_INPUT_OCTETS, stats->OctetsIn % UINT32_MAX) != 0 || 1245129457Sdds rad_put_int(r->cx.rad, RAD_ACCT_INPUT_GIGAWORDS, stats->OctetsIn / UINT32_MAX) != 0 || 124665178Sbrian rad_put_int(r->cx.rad, RAD_ACCT_INPUT_PACKETS, stats->PacketsIn) != 0 || 1247129457Sdds rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_OCTETS, stats->OctetsOut % UINT32_MAX) != 0 || 1248129457Sdds rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_GIGAWORDS, stats->OctetsOut / UINT32_MAX) != 0 || 124965178Sbrian rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_PACKETS, stats->PacketsOut) 125065178Sbrian != 0 || 125165178Sbrian rad_put_int(r->cx.rad, RAD_ACCT_SESSION_TIME, throughput_uptime(stats)) 125265178Sbrian != 0) { 125365178Sbrian log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 125465178Sbrian rad_close(r->cx.rad); 125565178Sbrian return; 125665178Sbrian } 125765178Sbrian 1258132273Sbrian if (log_IsKept(LogPHASE) || log_IsKept(LogRADIUS)) { 1259134789Sbrian const char *what; 1260132273Sbrian int level; 1261132273Sbrian 1262132273Sbrian switch (acct_type) { 1263132273Sbrian case RAD_START: 1264132273Sbrian what = "START"; 1265132273Sbrian level = log_IsKept(LogPHASE) ? LogPHASE : LogRADIUS; 1266132273Sbrian break; 1267132273Sbrian case RAD_STOP: 1268132273Sbrian what = "STOP"; 1269132273Sbrian level = log_IsKept(LogPHASE) ? LogPHASE : LogRADIUS; 1270132273Sbrian break; 1271132273Sbrian case RAD_ALIVE: 1272132273Sbrian what = "ALIVE"; 1273132273Sbrian level = LogRADIUS; 1274132273Sbrian break; 1275132273Sbrian default: 1276132273Sbrian what = "<unknown>"; 1277132273Sbrian level = log_IsKept(LogPHASE) ? LogPHASE : LogRADIUS; 1278132273Sbrian break; 1279132273Sbrian } 1280132273Sbrian log_Printf(level, "Radius(acct): %s data sent\n", what); 1281132273Sbrian } 1282132273Sbrian 128371972Sbrian r->cx.auth = NULL; /* Not valid for accounting requests */ 128465178Sbrian if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv))) 128565178Sbrian radius_Process(r, got); 128665178Sbrian else { 128765178Sbrian log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout); 128865178Sbrian r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS; 128965178Sbrian r->cx.timer.func = radius_Timeout; 129071972Sbrian r->cx.timer.name = "radius acct"; 129165178Sbrian r->cx.timer.arg = r; 129265178Sbrian timer_Start(&r->cx.timer); 129365178Sbrian } 129465178Sbrian} 129565178Sbrian 129665178Sbrian/* 129743693Sbrian * How do things look at the moment ? 129843693Sbrian */ 129943693Sbrianvoid 130043313Sbrianradius_Show(struct radius *r, struct prompt *p) 130143313Sbrian{ 130271657Sbrian prompt_Printf(p, " Radius config: %s", 130371657Sbrian *r->cfg.file ? r->cfg.file : "none"); 130443313Sbrian if (r->valid) { 130571657Sbrian prompt_Printf(p, "\n IP: %s\n", inet_ntoa(r->ip)); 130671657Sbrian prompt_Printf(p, " Netmask: %s\n", inet_ntoa(r->mask)); 130771657Sbrian prompt_Printf(p, " MTU: %lu\n", r->mtu); 130871657Sbrian prompt_Printf(p, " VJ: %sabled\n", r->vj ? "en" : "dis"); 130996324Sbrian prompt_Printf(p, " Message: %s\n", r->repstr ? r->repstr : ""); 131098132Sbrian prompt_Printf(p, " MPPE Enc Policy: %s\n", 131198132Sbrian radius_policyname(r->mppe.policy)); 131298132Sbrian prompt_Printf(p, " MPPE Enc Types: %s\n", 131398132Sbrian radius_typesname(r->mppe.types)); 131498132Sbrian prompt_Printf(p, " MPPE Recv Key: %seceived\n", 131598132Sbrian r->mppe.recvkey ? "R" : "Not r"); 131698132Sbrian prompt_Printf(p, " MPPE Send Key: %seceived\n", 131798132Sbrian r->mppe.sendkey ? "R" : "Not r"); 131896730Sbrian prompt_Printf(p, " MS-CHAP2-Response: %s\n", 131996730Sbrian r->msrepstr ? r->msrepstr : ""); 132096324Sbrian prompt_Printf(p, " Error Message: %s\n", r->errstr ? r->errstr : ""); 132143313Sbrian if (r->routes) 132271657Sbrian route_ShowSticky(p, r->routes, " Routes", 16); 1323116586Sume#ifndef NOINET6 1324116586Sume if (r->ipv6routes) 1325116586Sume route_ShowSticky(p, r->ipv6routes, " IPv6 Routes", 16); 1326116586Sume#endif 132743313Sbrian } else 132843313Sbrian prompt_Printf(p, " (not authenticated)\n"); 132943313Sbrian} 1330132273Sbrian 1331132273Sbrianstatic void 1332132273Sbrianradius_alive(void *v) 1333132273Sbrian{ 1334132273Sbrian struct bundle *bundle = (struct bundle *)v; 1335132273Sbrian 1336132273Sbrian timer_Stop(&bundle->radius.alive.timer); 1337132273Sbrian bundle->radius.alive.timer.load = bundle->radius.alive.interval * SECTICKS; 1338132273Sbrian if (bundle->radius.alive.timer.load) { 1339132273Sbrian radius_Account(&bundle->radius, &bundle->radacct, 1340132273Sbrian bundle->links, RAD_ALIVE, &bundle->ncp.ipcp.throughput); 1341132273Sbrian timer_Start(&bundle->radius.alive.timer); 1342132273Sbrian } 1343132273Sbrian} 1344132273Sbrian 1345132273Sbrianvoid 1346132273Sbrianradius_StartTimer(struct bundle *bundle) 1347132273Sbrian{ 1348132273Sbrian if (bundle->radius.cfg.file && bundle->radius.alive.interval) { 1349132273Sbrian bundle->radius.alive.timer.func = radius_alive; 1350132273Sbrian bundle->radius.alive.timer.name = "radius alive"; 1351132273Sbrian bundle->radius.alive.timer.load = bundle->radius.alive.interval * SECTICKS; 1352132273Sbrian bundle->radius.alive.timer.arg = bundle; 1353132273Sbrian radius_alive(bundle); 1354132273Sbrian } 1355132273Sbrian} 1356132273Sbrian 1357132273Sbrianvoid 1358132273Sbrianradius_StopTimer(struct radius *r) 1359132273Sbrian{ 1360132273Sbrian timer_Stop(&r->alive.timer); 1361132273Sbrian} 1362