1*1de7b4b8SPedro F. Giffuni /*- 2*1de7b4b8SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*1de7b4b8SPedro F. Giffuni * 4972a1bcfSBrian Somers * Copyright 1999 Internet Business Solutions Ltd., Switzerland 5972a1bcfSBrian Somers * All rights reserved. 6972a1bcfSBrian Somers * 7972a1bcfSBrian Somers * Redistribution and use in source and binary forms, with or without 8972a1bcfSBrian Somers * modification, are permitted provided that the following conditions 9972a1bcfSBrian Somers * are met: 10972a1bcfSBrian Somers * 1. Redistributions of source code must retain the above copyright 11972a1bcfSBrian Somers * notice, this list of conditions and the following disclaimer. 12972a1bcfSBrian Somers * 2. Redistributions in binary form must reproduce the above copyright 13972a1bcfSBrian Somers * notice, this list of conditions and the following disclaimer in the 14972a1bcfSBrian Somers * documentation and/or other materials provided with the distribution. 15972a1bcfSBrian Somers * 16972a1bcfSBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17972a1bcfSBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18972a1bcfSBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19972a1bcfSBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20972a1bcfSBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21972a1bcfSBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22972a1bcfSBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23972a1bcfSBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24972a1bcfSBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25972a1bcfSBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26972a1bcfSBrian Somers * SUCH DAMAGE. 27972a1bcfSBrian Somers * 2897d92980SPeter Wemm * $FreeBSD$ 29972a1bcfSBrian Somers * 30972a1bcfSBrian Somers */ 31972a1bcfSBrian Somers 32dfb3194aSDiomidis Spinellis #include <stdint.h> 33972a1bcfSBrian Somers #include <sys/param.h> 348fb5ef5aSBrian Somers 3588044778SBrian Somers #include <sys/select.h> 366b457978SBrian Somers #include <sys/socket.h> 37972a1bcfSBrian Somers #include <netinet/in_systm.h> 38972a1bcfSBrian Somers #include <netinet/in.h> 39972a1bcfSBrian Somers #include <netinet/ip.h> 40972a1bcfSBrian Somers #include <arpa/inet.h> 41972a1bcfSBrian Somers #include <sys/un.h> 426b457978SBrian Somers #include <net/route.h> 43972a1bcfSBrian Somers 4410e629b9SBrian Somers #ifdef LOCALRAD 4510e629b9SBrian Somers #include "radlib.h" 46ff8e577bSBrian Somers #include "radlib_vs.h" 4710e629b9SBrian Somers #else 48972a1bcfSBrian Somers #include <radlib.h> 49ff8e577bSBrian Somers #include <radlib_vs.h> 5010e629b9SBrian Somers #endif 5110e629b9SBrian Somers 5210e629b9SBrian Somers #include <errno.h> 538fb5ef5aSBrian Somers #ifndef NODES 548fb5ef5aSBrian Somers #include <md5.h> 558fb5ef5aSBrian Somers #endif 566eafd353SBrian Somers #include <stdarg.h> 57972a1bcfSBrian Somers #include <stdio.h> 58972a1bcfSBrian Somers #include <stdlib.h> 59972a1bcfSBrian Somers #include <string.h> 60f0cdd9c0SBrian Somers #include <sys/time.h> 61972a1bcfSBrian Somers #include <termios.h> 62f10f5203SBrian Somers #include <unistd.h> 63f10f5203SBrian Somers #include <netdb.h> 64972a1bcfSBrian Somers 655d9e6103SBrian Somers #include "layer.h" 66972a1bcfSBrian Somers #include "defs.h" 67972a1bcfSBrian Somers #include "log.h" 68972a1bcfSBrian Somers #include "descriptor.h" 69972a1bcfSBrian Somers #include "prompt.h" 70972a1bcfSBrian Somers #include "timer.h" 71972a1bcfSBrian Somers #include "fsm.h" 72972a1bcfSBrian Somers #include "iplist.h" 73972a1bcfSBrian Somers #include "slcompress.h" 74972a1bcfSBrian Somers #include "throughput.h" 75972a1bcfSBrian Somers #include "lqr.h" 76972a1bcfSBrian Somers #include "hdlc.h" 77972a1bcfSBrian Somers #include "mbuf.h" 7830949fd4SBrian Somers #include "ncpaddr.h" 7930949fd4SBrian Somers #include "ip.h" 80972a1bcfSBrian Somers #include "ipcp.h" 8130949fd4SBrian Somers #include "ipv6cp.h" 82972a1bcfSBrian Somers #include "route.h" 83972a1bcfSBrian Somers #include "command.h" 84972a1bcfSBrian Somers #include "filter.h" 85972a1bcfSBrian Somers #include "lcp.h" 86972a1bcfSBrian Somers #include "ccp.h" 87972a1bcfSBrian Somers #include "link.h" 88972a1bcfSBrian Somers #include "mp.h" 89972a1bcfSBrian Somers #include "radius.h" 90f0cdd9c0SBrian Somers #include "auth.h" 91f0cdd9c0SBrian Somers #include "async.h" 92f0cdd9c0SBrian Somers #include "physical.h" 93f0cdd9c0SBrian Somers #include "chat.h" 94f0cdd9c0SBrian Somers #include "cbcp.h" 95f0cdd9c0SBrian Somers #include "chap.h" 96f0cdd9c0SBrian Somers #include "datalink.h" 9730949fd4SBrian Somers #include "ncp.h" 98972a1bcfSBrian Somers #include "bundle.h" 99ff8e577bSBrian Somers #include "proto.h" 100d4d4a70aSRoman Bogorodskiy #include "iface.h" 101ff8e577bSBrian Somers 102ff8e577bSBrian Somers #ifndef NODES 103a16061b2SBrian Somers struct mschap_response { 104ff8e577bSBrian Somers u_char ident; 105ff8e577bSBrian Somers u_char flags; 106ff8e577bSBrian Somers u_char lm_response[24]; 107ff8e577bSBrian Somers u_char nt_response[24]; 108ff8e577bSBrian Somers }; 109a16061b2SBrian Somers 110a16061b2SBrian Somers struct mschap2_response { 111a16061b2SBrian Somers u_char ident; 112a16061b2SBrian Somers u_char flags; 113a16061b2SBrian Somers u_char pchallenge[16]; 114a16061b2SBrian Somers u_char reserved[8]; 115a16061b2SBrian Somers u_char response[24]; 116a16061b2SBrian Somers }; 1178fb5ef5aSBrian Somers 1188fb5ef5aSBrian Somers #define AUTH_LEN 16 1198fb5ef5aSBrian Somers #define SALT_LEN 2 1208fb5ef5aSBrian Somers #endif 1218fb5ef5aSBrian Somers 1228fb5ef5aSBrian Somers static const char * 1238fb5ef5aSBrian Somers radius_policyname(int policy) 1248fb5ef5aSBrian Somers { 1258fb5ef5aSBrian Somers switch(policy) { 1268fb5ef5aSBrian Somers case MPPE_POLICY_ALLOWED: 1278fb5ef5aSBrian Somers return "Allowed"; 1288fb5ef5aSBrian Somers case MPPE_POLICY_REQUIRED: 1298fb5ef5aSBrian Somers return "Required"; 1308fb5ef5aSBrian Somers } 1318fb5ef5aSBrian Somers return NumStr(policy, NULL, 0); 1328fb5ef5aSBrian Somers } 1338fb5ef5aSBrian Somers 1348fb5ef5aSBrian Somers static const char * 1358fb5ef5aSBrian Somers radius_typesname(int types) 1368fb5ef5aSBrian Somers { 1378fb5ef5aSBrian Somers switch(types) { 1388fb5ef5aSBrian Somers case MPPE_TYPE_40BIT: 1398fb5ef5aSBrian Somers return "40 bit"; 1408fb5ef5aSBrian Somers case MPPE_TYPE_128BIT: 1418fb5ef5aSBrian Somers return "128 bit"; 1428fb5ef5aSBrian Somers case MPPE_TYPE_40BIT|MPPE_TYPE_128BIT: 1438fb5ef5aSBrian Somers return "40 or 128 bit"; 1448fb5ef5aSBrian Somers } 1458fb5ef5aSBrian Somers return NumStr(types, NULL, 0); 1468fb5ef5aSBrian Somers } 1478fb5ef5aSBrian Somers 1488fb5ef5aSBrian Somers #ifndef NODES 1498fb5ef5aSBrian Somers static void 1508fb5ef5aSBrian Somers demangle(struct radius *r, const void *mangled, size_t mlen, 1518fb5ef5aSBrian Somers char **buf, size_t *len) 1528fb5ef5aSBrian Somers { 1538fb5ef5aSBrian Somers char R[AUTH_LEN]; /* variable names as per rfc2548 */ 1548fb5ef5aSBrian Somers const char *S; 1558fb5ef5aSBrian Somers u_char b[16]; 1568fb5ef5aSBrian Somers const u_char *A, *C; 1578fb5ef5aSBrian Somers MD5_CTX Context; 1588fb5ef5aSBrian Somers int Slen, i, Clen, Ppos; 1598fb5ef5aSBrian Somers u_char *P; 1608fb5ef5aSBrian Somers 1618fb5ef5aSBrian Somers if (mlen % 16 != SALT_LEN) { 1628fb5ef5aSBrian Somers log_Printf(LogWARN, "Cannot interpret mangled data of length %ld\n", 1638fb5ef5aSBrian Somers (u_long)mlen); 1648fb5ef5aSBrian Somers *buf = NULL; 1658fb5ef5aSBrian Somers *len = 0; 1668fb5ef5aSBrian Somers return; 1678fb5ef5aSBrian Somers } 1688fb5ef5aSBrian Somers 1698fb5ef5aSBrian Somers /* We need the RADIUS Request-Authenticator */ 1708fb5ef5aSBrian Somers if (rad_request_authenticator(r->cx.rad, R, sizeof R) != AUTH_LEN) { 1718fb5ef5aSBrian Somers log_Printf(LogWARN, "Cannot obtain the RADIUS request authenticator\n"); 1728fb5ef5aSBrian Somers *buf = NULL; 1738fb5ef5aSBrian Somers *len = 0; 1748fb5ef5aSBrian Somers return; 1758fb5ef5aSBrian Somers } 1768fb5ef5aSBrian Somers 1778fb5ef5aSBrian Somers A = (const u_char *)mangled; /* Salt comes first */ 1788fb5ef5aSBrian Somers C = (const u_char *)mangled + SALT_LEN; /* Then the ciphertext */ 1798fb5ef5aSBrian Somers Clen = mlen - SALT_LEN; 1808fb5ef5aSBrian Somers S = rad_server_secret(r->cx.rad); /* We need the RADIUS secret */ 1818fb5ef5aSBrian Somers Slen = strlen(S); 1828fb5ef5aSBrian Somers P = alloca(Clen); /* We derive our plaintext */ 1838fb5ef5aSBrian Somers 1848fb5ef5aSBrian Somers MD5Init(&Context); 1858fb5ef5aSBrian Somers MD5Update(&Context, S, Slen); 1868fb5ef5aSBrian Somers MD5Update(&Context, R, AUTH_LEN); 1878fb5ef5aSBrian Somers MD5Update(&Context, A, SALT_LEN); 1888fb5ef5aSBrian Somers MD5Final(b, &Context); 1898fb5ef5aSBrian Somers Ppos = 0; 1908fb5ef5aSBrian Somers 1918fb5ef5aSBrian Somers while (Clen) { 1928fb5ef5aSBrian Somers Clen -= 16; 1938fb5ef5aSBrian Somers 1948fb5ef5aSBrian Somers for (i = 0; i < 16; i++) 1958fb5ef5aSBrian Somers P[Ppos++] = C[i] ^ b[i]; 1968fb5ef5aSBrian Somers 1978fb5ef5aSBrian Somers if (Clen) { 1988fb5ef5aSBrian Somers MD5Init(&Context); 1998fb5ef5aSBrian Somers MD5Update(&Context, S, Slen); 2008fb5ef5aSBrian Somers MD5Update(&Context, C, 16); 2018fb5ef5aSBrian Somers MD5Final(b, &Context); 2028fb5ef5aSBrian Somers } 2038fb5ef5aSBrian Somers 2048fb5ef5aSBrian Somers C += 16; 2058fb5ef5aSBrian Somers } 2068fb5ef5aSBrian Somers 2078fb5ef5aSBrian Somers /* 2088fb5ef5aSBrian Somers * The resulting plain text consists of a one-byte length, the text and 2098fb5ef5aSBrian Somers * maybe some padding. 2108fb5ef5aSBrian Somers */ 2118fb5ef5aSBrian Somers *len = *P; 2128fb5ef5aSBrian Somers if (*len > mlen - 1) { 2138fb5ef5aSBrian Somers log_Printf(LogWARN, "Mangled data seems to be garbage\n"); 2148fb5ef5aSBrian Somers *buf = NULL; 2158fb5ef5aSBrian Somers *len = 0; 2168fb5ef5aSBrian Somers return; 2178fb5ef5aSBrian Somers } 2188fb5ef5aSBrian Somers 2195d604c11SBrian Somers if ((*buf = malloc(*len)) == NULL) { 2205d604c11SBrian Somers log_Printf(LogWARN, "demangle: Out of memory (%lu bytes)\n", (u_long)*len); 2215d604c11SBrian Somers *len = 0; 2225d604c11SBrian Somers } else 2238fb5ef5aSBrian Somers memcpy(*buf, P + 1, *len); 2248fb5ef5aSBrian Somers } 225ff8e577bSBrian Somers #endif 226972a1bcfSBrian Somers 227ec3e98b8SHajimu UMEMOTO /* XXX: This should go into librarius. */ 228ec3e98b8SHajimu UMEMOTO #ifndef NOINET6 229ec3e98b8SHajimu UMEMOTO static uint8_t * 230ec3e98b8SHajimu UMEMOTO rad_cvt_ipv6prefix(const void *data, size_t len) 231ec3e98b8SHajimu UMEMOTO { 232ec3e98b8SHajimu UMEMOTO const size_t ipv6len = sizeof(struct in6_addr) + 2; 233ec3e98b8SHajimu UMEMOTO uint8_t *s; 234ec3e98b8SHajimu UMEMOTO 235ec3e98b8SHajimu UMEMOTO if (len > ipv6len) 236ec3e98b8SHajimu UMEMOTO return NULL; 237ec3e98b8SHajimu UMEMOTO s = malloc(ipv6len); 238ec3e98b8SHajimu UMEMOTO if (s != NULL) { 239ec3e98b8SHajimu UMEMOTO memset(s, 0, ipv6len); 240ec3e98b8SHajimu UMEMOTO memcpy(s, data, len); 241ec3e98b8SHajimu UMEMOTO } 242ec3e98b8SHajimu UMEMOTO return s; 243ec3e98b8SHajimu UMEMOTO } 244ec3e98b8SHajimu UMEMOTO #endif 245ec3e98b8SHajimu UMEMOTO 246f0cdd9c0SBrian Somers /* 247f0cdd9c0SBrian Somers * rad_continue_send_request() has given us `got' (non-zero). Deal with it. 248f0cdd9c0SBrian Somers */ 249f0cdd9c0SBrian Somers static void 250f0cdd9c0SBrian Somers radius_Process(struct radius *r, int got) 251972a1bcfSBrian Somers { 252972a1bcfSBrian Somers char *argv[MAXARGS], *nuke; 253f0cdd9c0SBrian Somers struct bundle *bundle; 254ff8e577bSBrian Somers int argc, addrs, res, width; 25528e610e3SBrian Somers size_t len; 25630949fd4SBrian Somers struct ncprange dest; 25730949fd4SBrian Somers struct ncpaddr gw; 258f0cdd9c0SBrian Somers const void *data; 259c42627ffSBrian Somers const char *stype; 260ff8e577bSBrian Somers u_int32_t ipaddr, vendor; 26130949fd4SBrian Somers struct in_addr ip; 2620fe74aa4SHajimu UMEMOTO #ifndef NOINET6 263ec3e98b8SHajimu UMEMOTO uint8_t ipv6addr[INET6_ADDRSTRLEN]; 2640fe74aa4SHajimu UMEMOTO struct in6_addr ip6; 2650fe74aa4SHajimu UMEMOTO #endif 266972a1bcfSBrian Somers 267f0cdd9c0SBrian Somers r->cx.fd = -1; /* Stop select()ing */ 268c42627ffSBrian Somers stype = r->cx.auth ? "auth" : "acct"; 269972a1bcfSBrian Somers 270972a1bcfSBrian Somers switch (got) { 271972a1bcfSBrian Somers case RAD_ACCESS_ACCEPT: 272e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 273e715b13bSBrian Somers "Radius(%s): ACCEPT received\n", stype); 274c42627ffSBrian Somers if (!r->cx.auth) { 275c42627ffSBrian Somers rad_close(r->cx.rad); 276c42627ffSBrian Somers return; 277c42627ffSBrian Somers } 278972a1bcfSBrian Somers break; 279972a1bcfSBrian Somers 280f0cdd9c0SBrian Somers case RAD_ACCESS_REJECT: 281e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 282e715b13bSBrian Somers "Radius(%s): REJECT received\n", stype); 283ff8e577bSBrian Somers if (!r->cx.auth) { 284f0cdd9c0SBrian Somers rad_close(r->cx.rad); 285f0cdd9c0SBrian Somers return; 286ff8e577bSBrian Somers } 287ff8e577bSBrian Somers break; 288f0cdd9c0SBrian Somers 289972a1bcfSBrian Somers case RAD_ACCESS_CHALLENGE: 290972a1bcfSBrian Somers /* we can't deal with this (for now) ! */ 291e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 292e715b13bSBrian Somers "Radius: CHALLENGE received (can't handle yet)\n"); 293c42627ffSBrian Somers if (r->cx.auth) 294f0cdd9c0SBrian Somers auth_Failure(r->cx.auth); 295f0cdd9c0SBrian Somers rad_close(r->cx.rad); 296f0cdd9c0SBrian Somers return; 297972a1bcfSBrian Somers 298794c9bbcSBrian Somers case RAD_ACCOUNTING_RESPONSE: 299e715b13bSBrian Somers /* 300e715b13bSBrian Somers * It's probably not ideal to log this at PHASE level as we'll see 301e715b13bSBrian Somers * too much stuff going to the log when ``set rad_alive'' is used. 302e715b13bSBrian Somers * So we differ from older behaviour (ppp version 3.1 and before) 303e715b13bSBrian Somers * and just log accounting responses to LogRADIUS. 304e715b13bSBrian Somers */ 305e715b13bSBrian Somers log_Printf(LogRADIUS, "Radius(%s): Accounting response received\n", 306e715b13bSBrian Somers stype); 307c42627ffSBrian Somers if (r->cx.auth) 308c42627ffSBrian Somers auth_Failure(r->cx.auth); /* unexpected !!! */ 309c42627ffSBrian Somers 310794c9bbcSBrian Somers /* No further processing for accounting requests, please */ 311794c9bbcSBrian Somers rad_close(r->cx.rad); 312794c9bbcSBrian Somers return; 313794c9bbcSBrian Somers 314972a1bcfSBrian Somers case -1: 315e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 316e715b13bSBrian Somers "radius(%s): %s\n", stype, rad_strerror(r->cx.rad)); 317c42627ffSBrian Somers if (r->cx.auth) 318f0cdd9c0SBrian Somers auth_Failure(r->cx.auth); 319f0cdd9c0SBrian Somers rad_close(r->cx.rad); 320f0cdd9c0SBrian Somers return; 321972a1bcfSBrian Somers 322972a1bcfSBrian Somers default: 323c42627ffSBrian Somers log_Printf(LogERROR, "rad_send_request(%s): Failed %d: %s\n", stype, 324f0cdd9c0SBrian Somers got, rad_strerror(r->cx.rad)); 325c42627ffSBrian Somers if (r->cx.auth) 326f0cdd9c0SBrian Somers auth_Failure(r->cx.auth); 327f0cdd9c0SBrian Somers rad_close(r->cx.rad); 328f0cdd9c0SBrian Somers return; 329972a1bcfSBrian Somers } 330972a1bcfSBrian Somers 331ff8e577bSBrian Somers /* Let's see what we've got in our reply */ 332972a1bcfSBrian Somers r->ip.s_addr = r->mask.s_addr = INADDR_NONE; 333972a1bcfSBrian Somers r->mtu = 0; 334972a1bcfSBrian Somers r->vj = 0; 335ff8e577bSBrian Somers while ((res = rad_get_attr(r->cx.rad, &data, &len)) > 0) { 336ff8e577bSBrian Somers switch (res) { 337972a1bcfSBrian Somers case RAD_FRAMED_IP_ADDRESS: 338972a1bcfSBrian Somers r->ip = rad_cvt_addr(data); 339e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 340e715b13bSBrian Somers " IP %s\n", inet_ntoa(r->ip)); 341972a1bcfSBrian Somers break; 342972a1bcfSBrian Somers 343bf1eaec5SBrian Somers case RAD_FILTER_ID: 344bf1eaec5SBrian Somers free(r->filterid); 345bf1eaec5SBrian Somers if ((r->filterid = rad_cvt_string(data, len)) == NULL) { 346bf1eaec5SBrian Somers log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); 347ff8e577bSBrian Somers auth_Failure(r->cx.auth); 348bf1eaec5SBrian Somers rad_close(r->cx.rad); 349bf1eaec5SBrian Somers return; 350bf1eaec5SBrian Somers } 351e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 352e715b13bSBrian Somers " Filter \"%s\"\n", r->filterid); 353bf1eaec5SBrian Somers break; 354bf1eaec5SBrian Somers 355bf1eaec5SBrian Somers case RAD_SESSION_TIMEOUT: 356bf1eaec5SBrian Somers r->sessiontime = rad_cvt_int(data); 357e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 358e715b13bSBrian Somers " Session-Timeout %lu\n", r->sessiontime); 359bf1eaec5SBrian Somers break; 360bf1eaec5SBrian Somers 361972a1bcfSBrian Somers case RAD_FRAMED_IP_NETMASK: 362972a1bcfSBrian Somers r->mask = rad_cvt_addr(data); 363e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 364e715b13bSBrian Somers " Netmask %s\n", inet_ntoa(r->mask)); 365972a1bcfSBrian Somers break; 366972a1bcfSBrian Somers 367972a1bcfSBrian Somers case RAD_FRAMED_MTU: 368972a1bcfSBrian Somers r->mtu = rad_cvt_int(data); 369e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 370e715b13bSBrian Somers " MTU %lu\n", r->mtu); 371972a1bcfSBrian Somers break; 372972a1bcfSBrian Somers 373972a1bcfSBrian Somers case RAD_FRAMED_ROUTING: 374972a1bcfSBrian Somers /* Disabled for now - should we automatically set up some filters ? */ 375972a1bcfSBrian Somers /* rad_cvt_int(data); */ 376972a1bcfSBrian Somers /* bit 1 = Send routing packets */ 377972a1bcfSBrian Somers /* bit 2 = Receive routing packets */ 378972a1bcfSBrian Somers break; 379972a1bcfSBrian Somers 380972a1bcfSBrian Somers case RAD_FRAMED_COMPRESSION: 381972a1bcfSBrian Somers r->vj = rad_cvt_int(data) == 1 ? 1 : 0; 382e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 383e715b13bSBrian Somers " VJ %sabled\n", r->vj ? "en" : "dis"); 384972a1bcfSBrian Somers break; 385972a1bcfSBrian Somers 386972a1bcfSBrian Somers case RAD_FRAMED_ROUTE: 387972a1bcfSBrian Somers /* 388972a1bcfSBrian Somers * We expect a string of the format ``dest[/bits] gw [metrics]'' 389972a1bcfSBrian Somers * Any specified metrics are ignored. MYADDR and HISADDR are 390972a1bcfSBrian Somers * understood for ``dest'' and ``gw'' and ``0.0.0.0'' is the same 391972a1bcfSBrian Somers * as ``HISADDR''. 392972a1bcfSBrian Somers */ 393972a1bcfSBrian Somers 394972a1bcfSBrian Somers if ((nuke = rad_cvt_string(data, len)) == NULL) { 395f0cdd9c0SBrian Somers log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); 396ff8e577bSBrian Somers auth_Failure(r->cx.auth); 397f0cdd9c0SBrian Somers rad_close(r->cx.rad); 398f0cdd9c0SBrian Somers return; 399972a1bcfSBrian Somers } 400972a1bcfSBrian Somers 401e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 402e715b13bSBrian Somers " Route: %s\n", nuke); 403f0cdd9c0SBrian Somers bundle = r->cx.auth->physical->dl->bundle; 40430949fd4SBrian Somers ip.s_addr = INADDR_ANY; 4050fe74aa4SHajimu UMEMOTO ncpaddr_setip4(&gw, ip); 40630949fd4SBrian Somers ncprange_setip4host(&dest, ip); 407972a1bcfSBrian Somers argc = command_Interpret(nuke, strlen(nuke), argv); 408c39aa54eSBrian Somers if (argc < 0) 409c39aa54eSBrian Somers log_Printf(LogWARN, "radius: %s: Syntax error\n", 410c39aa54eSBrian Somers argc == 1 ? argv[0] : "\"\""); 411c39aa54eSBrian Somers else if (argc < 2) 412972a1bcfSBrian Somers log_Printf(LogWARN, "radius: %s: Invalid route\n", 413972a1bcfSBrian Somers argc == 1 ? argv[0] : "\"\""); 414972a1bcfSBrian Somers else if ((strcasecmp(argv[0], "default") != 0 && 41530949fd4SBrian Somers !ncprange_aton(&dest, &bundle->ncp, argv[0])) || 41630949fd4SBrian Somers !ncpaddr_aton(&gw, &bundle->ncp, argv[1])) 417972a1bcfSBrian Somers log_Printf(LogWARN, "radius: %s %s: Invalid route\n", 418972a1bcfSBrian Somers argv[0], argv[1]); 419972a1bcfSBrian Somers else { 42030949fd4SBrian Somers ncprange_getwidth(&dest, &width); 42130949fd4SBrian Somers if (width == 32 && strchr(argv[0], '/') == NULL) { 422972a1bcfSBrian Somers /* No mask specified - use the natural mask */ 42330949fd4SBrian Somers ncprange_getip4addr(&dest, &ip); 42430949fd4SBrian Somers ncprange_setip4mask(&dest, addr2mask(ip)); 42530949fd4SBrian Somers } 426972a1bcfSBrian Somers addrs = 0; 427972a1bcfSBrian Somers 428972a1bcfSBrian Somers if (!strncasecmp(argv[0], "HISADDR", 7)) 429972a1bcfSBrian Somers addrs = ROUTE_DSTHISADDR; 430972a1bcfSBrian Somers else if (!strncasecmp(argv[0], "MYADDR", 6)) 431972a1bcfSBrian Somers addrs = ROUTE_DSTMYADDR; 432972a1bcfSBrian Somers 43330949fd4SBrian Somers if (ncpaddr_getip4addr(&gw, &ipaddr) && ipaddr == INADDR_ANY) { 434972a1bcfSBrian Somers addrs |= ROUTE_GWHISADDR; 43530949fd4SBrian Somers ncpaddr_setip4(&gw, bundle->ncp.ipcp.peer_ip); 436972a1bcfSBrian Somers } else if (strcasecmp(argv[1], "HISADDR") == 0) 437972a1bcfSBrian Somers addrs |= ROUTE_GWHISADDR; 438972a1bcfSBrian Somers 43930949fd4SBrian Somers route_Add(&r->routes, addrs, &dest, &gw); 440972a1bcfSBrian Somers } 441972a1bcfSBrian Somers free(nuke); 442972a1bcfSBrian Somers break; 443972a1bcfSBrian Somers 444ff8e577bSBrian Somers case RAD_REPLY_MESSAGE: 445ff8e577bSBrian Somers free(r->repstr); 446ff8e577bSBrian Somers if ((r->repstr = rad_cvt_string(data, len)) == NULL) { 447ff8e577bSBrian Somers log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); 448ff8e577bSBrian Somers auth_Failure(r->cx.auth); 449ff8e577bSBrian Somers rad_close(r->cx.rad); 450ff8e577bSBrian Somers return; 451ff8e577bSBrian Somers } 452e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 453e715b13bSBrian Somers " Reply-Message \"%s\"\n", r->repstr); 454ff8e577bSBrian Somers break; 455ff8e577bSBrian Somers 4560fe74aa4SHajimu UMEMOTO #ifndef NOINET6 457ec3e98b8SHajimu UMEMOTO case RAD_FRAMED_IPV6_PREFIX: 458ec3e98b8SHajimu UMEMOTO free(r->ipv6prefix); 459a404ab16SHajimu UMEMOTO if ((r->ipv6prefix = rad_cvt_ipv6prefix(data, len)) == NULL) { 460a404ab16SHajimu UMEMOTO log_Printf(LogERROR, "rad_cvt_ipv6prefix: %s\n", 461a404ab16SHajimu UMEMOTO "Malformed attribute in response"); 462a404ab16SHajimu UMEMOTO auth_Failure(r->cx.auth); 463a404ab16SHajimu UMEMOTO rad_close(r->cx.rad); 464a404ab16SHajimu UMEMOTO return; 465a404ab16SHajimu UMEMOTO } 466ec3e98b8SHajimu UMEMOTO inet_ntop(AF_INET6, &r->ipv6prefix[2], ipv6addr, sizeof(ipv6addr)); 467e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 468e715b13bSBrian Somers " IPv6 %s/%d\n", ipv6addr, r->ipv6prefix[1]); 469ec3e98b8SHajimu UMEMOTO break; 470ec3e98b8SHajimu UMEMOTO 4710fe74aa4SHajimu UMEMOTO case RAD_FRAMED_IPV6_ROUTE: 4720fe74aa4SHajimu UMEMOTO /* 4730fe74aa4SHajimu UMEMOTO * We expect a string of the format ``dest[/bits] gw [metrics]'' 4740fe74aa4SHajimu UMEMOTO * Any specified metrics are ignored. MYADDR6 and HISADDR6 are 4750fe74aa4SHajimu UMEMOTO * understood for ``dest'' and ``gw'' and ``::'' is the same 4760fe74aa4SHajimu UMEMOTO * as ``HISADDR6''. 4770fe74aa4SHajimu UMEMOTO */ 4780fe74aa4SHajimu UMEMOTO 4790fe74aa4SHajimu UMEMOTO if ((nuke = rad_cvt_string(data, len)) == NULL) { 4800fe74aa4SHajimu UMEMOTO log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); 4810fe74aa4SHajimu UMEMOTO auth_Failure(r->cx.auth); 4820fe74aa4SHajimu UMEMOTO rad_close(r->cx.rad); 4830fe74aa4SHajimu UMEMOTO return; 4840fe74aa4SHajimu UMEMOTO } 4850fe74aa4SHajimu UMEMOTO 486e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 487e715b13bSBrian Somers " IPv6 Route: %s\n", nuke); 4880fe74aa4SHajimu UMEMOTO bundle = r->cx.auth->physical->dl->bundle; 4890fe74aa4SHajimu UMEMOTO ncpaddr_setip6(&gw, &in6addr_any); 4900fe74aa4SHajimu UMEMOTO ncprange_set(&dest, &gw, 0); 4910fe74aa4SHajimu UMEMOTO argc = command_Interpret(nuke, strlen(nuke), argv); 4920fe74aa4SHajimu UMEMOTO if (argc < 0) 4930fe74aa4SHajimu UMEMOTO log_Printf(LogWARN, "radius: %s: Syntax error\n", 4940fe74aa4SHajimu UMEMOTO argc == 1 ? argv[0] : "\"\""); 4950fe74aa4SHajimu UMEMOTO else if (argc < 2) 4960fe74aa4SHajimu UMEMOTO log_Printf(LogWARN, "radius: %s: Invalid route\n", 4970fe74aa4SHajimu UMEMOTO argc == 1 ? argv[0] : "\"\""); 4980fe74aa4SHajimu UMEMOTO else if ((strcasecmp(argv[0], "default") != 0 && 4990fe74aa4SHajimu UMEMOTO !ncprange_aton(&dest, &bundle->ncp, argv[0])) || 5000fe74aa4SHajimu UMEMOTO !ncpaddr_aton(&gw, &bundle->ncp, argv[1])) 5010fe74aa4SHajimu UMEMOTO log_Printf(LogWARN, "radius: %s %s: Invalid route\n", 5020fe74aa4SHajimu UMEMOTO argv[0], argv[1]); 5030fe74aa4SHajimu UMEMOTO else { 5040fe74aa4SHajimu UMEMOTO addrs = 0; 5050fe74aa4SHajimu UMEMOTO 5060fe74aa4SHajimu UMEMOTO if (!strncasecmp(argv[0], "HISADDR6", 8)) 5070fe74aa4SHajimu UMEMOTO addrs = ROUTE_DSTHISADDR6; 5080fe74aa4SHajimu UMEMOTO else if (!strncasecmp(argv[0], "MYADDR6", 7)) 5090fe74aa4SHajimu UMEMOTO addrs = ROUTE_DSTMYADDR6; 5100fe74aa4SHajimu UMEMOTO 5110fe74aa4SHajimu UMEMOTO if (ncpaddr_getip6(&gw, &ip6) && IN6_IS_ADDR_UNSPECIFIED(&ip6)) { 5120fe74aa4SHajimu UMEMOTO addrs |= ROUTE_GWHISADDR6; 5130fe74aa4SHajimu UMEMOTO ncpaddr_copy(&gw, &bundle->ncp.ipv6cp.hisaddr); 5140fe74aa4SHajimu UMEMOTO } else if (strcasecmp(argv[1], "HISADDR6") == 0) 5150fe74aa4SHajimu UMEMOTO addrs |= ROUTE_GWHISADDR6; 5160fe74aa4SHajimu UMEMOTO 5170fe74aa4SHajimu UMEMOTO route_Add(&r->ipv6routes, addrs, &dest, &gw); 5180fe74aa4SHajimu UMEMOTO } 5190fe74aa4SHajimu UMEMOTO free(nuke); 5200fe74aa4SHajimu UMEMOTO break; 5210fe74aa4SHajimu UMEMOTO #endif 5220fe74aa4SHajimu UMEMOTO 523ff8e577bSBrian Somers case RAD_VENDOR_SPECIFIC: 524ff8e577bSBrian Somers if ((res = rad_get_vendor_attr(&vendor, &data, &len)) <= 0) { 525ff8e577bSBrian Somers log_Printf(LogERROR, "rad_get_vendor_attr: %s (failing!)\n", 526f0cdd9c0SBrian Somers rad_strerror(r->cx.rad)); 527f0cdd9c0SBrian Somers auth_Failure(r->cx.auth); 528f0cdd9c0SBrian Somers rad_close(r->cx.rad); 529ff8e577bSBrian Somers return; 530ff8e577bSBrian Somers } 531ff8e577bSBrian Somers 532ff8e577bSBrian Somers switch (vendor) { 533ff8e577bSBrian Somers case RAD_VENDOR_MICROSOFT: 534ff8e577bSBrian Somers switch (res) { 5358fb5ef5aSBrian Somers #ifndef NODES 536ff8e577bSBrian Somers case RAD_MICROSOFT_MS_CHAP_ERROR: 537ff8e577bSBrian Somers free(r->errstr); 538a95b23a6SBrian Somers if (len == 0) 539a95b23a6SBrian Somers r->errstr = NULL; 540a95b23a6SBrian Somers else { 54199cfc2e2SBrian Somers if (len < 3 || ((const char *)data)[1] != '=') { 54299cfc2e2SBrian Somers /* 54399cfc2e2SBrian Somers * Only point at the String field if we don't think the 54499cfc2e2SBrian Somers * peer has misformatted the response. 54599cfc2e2SBrian Somers */ 5461bb0b6deSAlexander Kabaev data = (const char *)data + 1; 54799cfc2e2SBrian Somers len--; 548579abfd8SBrian Somers } else 549579abfd8SBrian Somers log_Printf(LogWARN, "Warning: The MS-CHAP-Error " 550579abfd8SBrian Somers "attribute is mis-formatted. Compensating\n"); 55199cfc2e2SBrian Somers if ((r->errstr = rad_cvt_string((const char *)data, 55299cfc2e2SBrian Somers len)) == NULL) { 553ff8e577bSBrian Somers log_Printf(LogERROR, "rad_cvt_string: %s\n", 554ff8e577bSBrian Somers rad_strerror(r->cx.rad)); 555ff8e577bSBrian Somers auth_Failure(r->cx.auth); 556ff8e577bSBrian Somers rad_close(r->cx.rad); 557ff8e577bSBrian Somers return; 558ff8e577bSBrian Somers } 559e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 560e715b13bSBrian Somers " MS-CHAP-Error \"%s\"\n", r->errstr); 561a95b23a6SBrian Somers } 562ff8e577bSBrian Somers break; 563ff8e577bSBrian Somers 564a16061b2SBrian Somers case RAD_MICROSOFT_MS_CHAP2_SUCCESS: 565a16061b2SBrian Somers free(r->msrepstr); 566a95b23a6SBrian Somers if (len == 0) 567a95b23a6SBrian Somers r->msrepstr = NULL; 568a95b23a6SBrian Somers else { 56999cfc2e2SBrian Somers if (len < 3 || ((const char *)data)[1] != '=') { 57099cfc2e2SBrian Somers /* 57199cfc2e2SBrian Somers * Only point at the String field if we don't think the 57299cfc2e2SBrian Somers * peer has misformatted the response. 57399cfc2e2SBrian Somers */ 5741bb0b6deSAlexander Kabaev data = (const char *)data + 1; 57599cfc2e2SBrian Somers len--; 576579abfd8SBrian Somers } else 577579abfd8SBrian Somers log_Printf(LogWARN, "Warning: The MS-CHAP2-Success " 578579abfd8SBrian Somers "attribute is mis-formatted. Compensating\n"); 57999cfc2e2SBrian Somers if ((r->msrepstr = rad_cvt_string((const char *)data, 58099cfc2e2SBrian Somers len)) == NULL) { 581a16061b2SBrian Somers log_Printf(LogERROR, "rad_cvt_string: %s\n", 582a16061b2SBrian Somers rad_strerror(r->cx.rad)); 583a16061b2SBrian Somers auth_Failure(r->cx.auth); 584a16061b2SBrian Somers rad_close(r->cx.rad); 585a16061b2SBrian Somers return; 586a16061b2SBrian Somers } 587e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 588e715b13bSBrian Somers " MS-CHAP2-Success \"%s\"\n", r->msrepstr); 589a95b23a6SBrian Somers } 590a16061b2SBrian Somers break; 591a16061b2SBrian Somers 5928fb5ef5aSBrian Somers case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY: 5938fb5ef5aSBrian Somers r->mppe.policy = rad_cvt_int(data); 594e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 595e715b13bSBrian Somers " MS-MPPE-Encryption-Policy %s\n", 5968fb5ef5aSBrian Somers radius_policyname(r->mppe.policy)); 5978fb5ef5aSBrian Somers break; 5988fb5ef5aSBrian Somers 5998fb5ef5aSBrian Somers case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES: 6008fb5ef5aSBrian Somers r->mppe.types = rad_cvt_int(data); 601e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 602e715b13bSBrian Somers " MS-MPPE-Encryption-Types %s\n", 6038fb5ef5aSBrian Somers radius_typesname(r->mppe.types)); 6048fb5ef5aSBrian Somers break; 6058fb5ef5aSBrian Somers 6068fb5ef5aSBrian Somers case RAD_MICROSOFT_MS_MPPE_RECV_KEY: 6078fb5ef5aSBrian Somers free(r->mppe.recvkey); 6088fb5ef5aSBrian Somers demangle(r, data, len, &r->mppe.recvkey, &r->mppe.recvkeylen); 609e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 610e715b13bSBrian Somers " MS-MPPE-Recv-Key ********\n"); 6118fb5ef5aSBrian Somers break; 6128fb5ef5aSBrian Somers 6138fb5ef5aSBrian Somers case RAD_MICROSOFT_MS_MPPE_SEND_KEY: 6148fb5ef5aSBrian Somers demangle(r, data, len, &r->mppe.sendkey, &r->mppe.sendkeylen); 615e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 616e715b13bSBrian Somers " MS-MPPE-Send-Key ********\n"); 6178fb5ef5aSBrian Somers break; 6188fb5ef5aSBrian Somers #endif 6198fb5ef5aSBrian Somers 620ff8e577bSBrian Somers default: 621ff8e577bSBrian Somers log_Printf(LogDEBUG, "Dropping MICROSOFT vendor specific " 622ff8e577bSBrian Somers "RADIUS attribute %d\n", res); 623ff8e577bSBrian Somers break; 624ff8e577bSBrian Somers } 625ff8e577bSBrian Somers break; 626ff8e577bSBrian Somers 627ff8e577bSBrian Somers default: 628ff8e577bSBrian Somers log_Printf(LogDEBUG, "Dropping vendor %lu RADIUS attribute %d\n", 629ff8e577bSBrian Somers (unsigned long)vendor, res); 630ff8e577bSBrian Somers break; 631ff8e577bSBrian Somers } 632ff8e577bSBrian Somers break; 633ff8e577bSBrian Somers 634ff8e577bSBrian Somers default: 635ff8e577bSBrian Somers log_Printf(LogDEBUG, "Dropping RADIUS attribute %d\n", res); 636ff8e577bSBrian Somers break; 637ff8e577bSBrian Somers } 638ff8e577bSBrian Somers } 639ff8e577bSBrian Somers 640ff8e577bSBrian Somers if (res == -1) { 641ff8e577bSBrian Somers log_Printf(LogERROR, "rad_get_attr: %s (failing!)\n", 642ff8e577bSBrian Somers rad_strerror(r->cx.rad)); 643ff8e577bSBrian Somers auth_Failure(r->cx.auth); 644ff8e577bSBrian Somers } else if (got == RAD_ACCESS_REJECT) 645ff8e577bSBrian Somers auth_Failure(r->cx.auth); 646ff8e577bSBrian Somers else { 647f0cdd9c0SBrian Somers r->valid = 1; 648f0cdd9c0SBrian Somers auth_Success(r->cx.auth); 649f0cdd9c0SBrian Somers } 650ff8e577bSBrian Somers rad_close(r->cx.rad); 651972a1bcfSBrian Somers } 652972a1bcfSBrian Somers 653f0cdd9c0SBrian Somers /* 6548e7bd08eSBrian Somers * We've either timed out or select()ed on the read descriptor 655f0cdd9c0SBrian Somers */ 656f0cdd9c0SBrian Somers static void 657f0cdd9c0SBrian Somers radius_Continue(struct radius *r, int sel) 658f0cdd9c0SBrian Somers { 659f0cdd9c0SBrian Somers struct timeval tv; 660f0cdd9c0SBrian Somers int got; 661972a1bcfSBrian Somers 662f0cdd9c0SBrian Somers timer_Stop(&r->cx.timer); 663f0cdd9c0SBrian Somers if ((got = rad_continue_send_request(r->cx.rad, sel, &r->cx.fd, &tv)) == 0) { 664e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 665e715b13bSBrian Somers "Radius: Request re-sent\n"); 666f0cdd9c0SBrian Somers r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS; 667f0cdd9c0SBrian Somers timer_Start(&r->cx.timer); 668f0cdd9c0SBrian Somers return; 669f0cdd9c0SBrian Somers } 670f0cdd9c0SBrian Somers 671f0cdd9c0SBrian Somers radius_Process(r, got); 672f0cdd9c0SBrian Somers } 673f0cdd9c0SBrian Somers 674f0cdd9c0SBrian Somers /* 675f0cdd9c0SBrian Somers * Time to call rad_continue_send_request() - timed out. 676f0cdd9c0SBrian Somers */ 677f0cdd9c0SBrian Somers static void 678f0cdd9c0SBrian Somers radius_Timeout(void *v) 679f0cdd9c0SBrian Somers { 680f0cdd9c0SBrian Somers radius_Continue((struct radius *)v, 0); 681f0cdd9c0SBrian Somers } 682f0cdd9c0SBrian Somers 683f0cdd9c0SBrian Somers /* 684f0cdd9c0SBrian Somers * Time to call rad_continue_send_request() - something to read. 685f0cdd9c0SBrian Somers */ 686f0cdd9c0SBrian Somers static void 687057f1760SBrian Somers radius_Read(struct fdescriptor *d, struct bundle *bundle __unused, 688057f1760SBrian Somers const fd_set *fdset __unused) 689f0cdd9c0SBrian Somers { 690f0cdd9c0SBrian Somers radius_Continue(descriptor2radius(d), 1); 691f0cdd9c0SBrian Somers } 692f0cdd9c0SBrian Somers 693f0cdd9c0SBrian Somers /* 69488044778SBrian Somers * Flush any pending transactions 69588044778SBrian Somers */ 69688044778SBrian Somers void 69788044778SBrian Somers radius_Flush(struct radius *r) 69888044778SBrian Somers { 69988044778SBrian Somers struct timeval tv; 70088044778SBrian Somers fd_set s; 70188044778SBrian Somers 70288044778SBrian Somers while (r->cx.fd != -1) { 70388044778SBrian Somers FD_ZERO(&s); 70488044778SBrian Somers FD_SET(r->cx.fd, &s); 70588044778SBrian Somers tv.tv_sec = 0; 70688044778SBrian Somers tv.tv_usec = TICKUNIT; 70788044778SBrian Somers select(r->cx.fd + 1, &s, NULL, NULL, &tv); 70888044778SBrian Somers radius_Continue(r, 1); 70988044778SBrian Somers } 71088044778SBrian Somers } 71188044778SBrian Somers 71288044778SBrian Somers /* 7138e7bd08eSBrian Somers * Behave as a struct fdescriptor (descriptor.h) 714f0cdd9c0SBrian Somers */ 715f0cdd9c0SBrian Somers static int 716057f1760SBrian Somers radius_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w __unused, 717057f1760SBrian Somers fd_set *e __unused, int *n) 718f0cdd9c0SBrian Somers { 719f0cdd9c0SBrian Somers struct radius *rad = descriptor2radius(d); 720f0cdd9c0SBrian Somers 721f0cdd9c0SBrian Somers if (r && rad->cx.fd != -1) { 722f0cdd9c0SBrian Somers FD_SET(rad->cx.fd, r); 723f0cdd9c0SBrian Somers if (*n < rad->cx.fd + 1) 724f0cdd9c0SBrian Somers *n = rad->cx.fd + 1; 725f0cdd9c0SBrian Somers log_Printf(LogTIMER, "Radius: fdset(r) %d\n", rad->cx.fd); 72682d6780cSBrian Somers return 1; 727972a1bcfSBrian Somers } 728972a1bcfSBrian Somers 729f0cdd9c0SBrian Somers return 0; 730f0cdd9c0SBrian Somers } 731f0cdd9c0SBrian Somers 732f0cdd9c0SBrian Somers /* 7338e7bd08eSBrian Somers * Behave as a struct fdescriptor (descriptor.h) 734f0cdd9c0SBrian Somers */ 735f0cdd9c0SBrian Somers static int 736f013f33eSBrian Somers radius_IsSet(struct fdescriptor *d, const fd_set *fdset) 737f0cdd9c0SBrian Somers { 738f0cdd9c0SBrian Somers struct radius *r = descriptor2radius(d); 739f0cdd9c0SBrian Somers 740f0cdd9c0SBrian Somers return r && r->cx.fd != -1 && FD_ISSET(r->cx.fd, fdset); 741f0cdd9c0SBrian Somers } 742f0cdd9c0SBrian Somers 743f0cdd9c0SBrian Somers /* 7448e7bd08eSBrian Somers * Behave as a struct fdescriptor (descriptor.h) 745f0cdd9c0SBrian Somers */ 746f0cdd9c0SBrian Somers static int 747057f1760SBrian Somers radius_Write(struct fdescriptor *d __unused, struct bundle *bundle __unused, 748057f1760SBrian Somers const fd_set *fdset __unused) 749f0cdd9c0SBrian Somers { 750f0cdd9c0SBrian Somers /* We never want to write here ! */ 751f0cdd9c0SBrian Somers log_Printf(LogALERT, "radius_Write: Internal error: Bad call !\n"); 752f0cdd9c0SBrian Somers return 0; 753f0cdd9c0SBrian Somers } 754f0cdd9c0SBrian Somers 755f0cdd9c0SBrian Somers /* 756f0cdd9c0SBrian Somers * Initialise ourselves 757f0cdd9c0SBrian Somers */ 758f0cdd9c0SBrian Somers void 759f0cdd9c0SBrian Somers radius_Init(struct radius *r) 760f0cdd9c0SBrian Somers { 761f0cdd9c0SBrian Somers r->desc.type = RADIUS_DESCRIPTOR; 762f0cdd9c0SBrian Somers r->desc.UpdateSet = radius_UpdateSet; 763f0cdd9c0SBrian Somers r->desc.IsSet = radius_IsSet; 764f0cdd9c0SBrian Somers r->desc.Read = radius_Read; 765f0cdd9c0SBrian Somers r->desc.Write = radius_Write; 766ff8e577bSBrian Somers r->cx.fd = -1; 767ff8e577bSBrian Somers r->cx.rad = NULL; 768f0cdd9c0SBrian Somers memset(&r->cx.timer, '\0', sizeof r->cx.timer); 769ff8e577bSBrian Somers r->cx.auth = NULL; 770ff8e577bSBrian Somers r->valid = 0; 771ff8e577bSBrian Somers r->vj = 0; 772ff8e577bSBrian Somers r->ip.s_addr = INADDR_ANY; 773ff8e577bSBrian Somers r->mask.s_addr = INADDR_NONE; 774ff8e577bSBrian Somers r->routes = NULL; 775ff8e577bSBrian Somers r->mtu = DEF_MTU; 776a16061b2SBrian Somers r->msrepstr = NULL; 777ff8e577bSBrian Somers r->repstr = NULL; 7780fe74aa4SHajimu UMEMOTO #ifndef NOINET6 779ec3e98b8SHajimu UMEMOTO r->ipv6prefix = NULL; 7800fe74aa4SHajimu UMEMOTO r->ipv6routes = NULL; 7810fe74aa4SHajimu UMEMOTO #endif 782ff8e577bSBrian Somers r->errstr = NULL; 7838fb5ef5aSBrian Somers r->mppe.policy = 0; 7848fb5ef5aSBrian Somers r->mppe.types = 0; 7858fb5ef5aSBrian Somers r->mppe.recvkey = NULL; 7868fb5ef5aSBrian Somers r->mppe.recvkeylen = 0; 7878fb5ef5aSBrian Somers r->mppe.sendkey = NULL; 7888fb5ef5aSBrian Somers r->mppe.sendkeylen = 0; 789db702c59SEitan Adler *r->cfg.file = '\0'; 790794c9bbcSBrian Somers log_Printf(LogDEBUG, "Radius: radius_Init\n"); 791f0cdd9c0SBrian Somers } 792f0cdd9c0SBrian Somers 793f0cdd9c0SBrian Somers /* 794f0cdd9c0SBrian Somers * Forget everything and go back to initialised state. 795f0cdd9c0SBrian Somers */ 796f0cdd9c0SBrian Somers void 797f0cdd9c0SBrian Somers radius_Destroy(struct radius *r) 798f0cdd9c0SBrian Somers { 799f0cdd9c0SBrian Somers r->valid = 0; 800794c9bbcSBrian Somers log_Printf(LogDEBUG, "Radius: radius_Destroy\n"); 801f0cdd9c0SBrian Somers timer_Stop(&r->cx.timer); 802f0cdd9c0SBrian Somers route_DeleteAll(&r->routes); 8030fe74aa4SHajimu UMEMOTO #ifndef NOINET6 8040fe74aa4SHajimu UMEMOTO route_DeleteAll(&r->ipv6routes); 8050fe74aa4SHajimu UMEMOTO #endif 806bf1eaec5SBrian Somers free(r->filterid); 807bf1eaec5SBrian Somers r->filterid = NULL; 808a16061b2SBrian Somers free(r->msrepstr); 809a16061b2SBrian Somers r->msrepstr = NULL; 810ff8e577bSBrian Somers free(r->repstr); 811ff8e577bSBrian Somers r->repstr = NULL; 812ec3e98b8SHajimu UMEMOTO #ifndef NOINET6 813ec3e98b8SHajimu UMEMOTO free(r->ipv6prefix); 814ec3e98b8SHajimu UMEMOTO r->ipv6prefix = NULL; 815ec3e98b8SHajimu UMEMOTO #endif 816ff8e577bSBrian Somers free(r->errstr); 817ff8e577bSBrian Somers r->errstr = NULL; 8188fb5ef5aSBrian Somers free(r->mppe.recvkey); 8198fb5ef5aSBrian Somers r->mppe.recvkey = NULL; 8208fb5ef5aSBrian Somers r->mppe.recvkeylen = 0; 8218fb5ef5aSBrian Somers free(r->mppe.sendkey); 8228fb5ef5aSBrian Somers r->mppe.sendkey = NULL; 8238fb5ef5aSBrian Somers r->mppe.sendkeylen = 0; 824f0cdd9c0SBrian Somers if (r->cx.fd != -1) { 825f0cdd9c0SBrian Somers r->cx.fd = -1; 826f0cdd9c0SBrian Somers rad_close(r->cx.rad); 827f0cdd9c0SBrian Somers } 828f0cdd9c0SBrian Somers } 829f0cdd9c0SBrian Somers 830de59e178SBrian Somers static int 831d4d4a70aSRoman Bogorodskiy radius_put_physical_details(struct radius *rad, struct physical *p) 832de59e178SBrian Somers { 833de59e178SBrian Somers int slot, type; 834de59e178SBrian Somers 835de59e178SBrian Somers type = RAD_VIRTUAL; 836de59e178SBrian Somers if (p->handler) 837de59e178SBrian Somers switch (p->handler->type) { 838de59e178SBrian Somers case I4B_DEVICE: 839de59e178SBrian Somers type = RAD_ISDN_SYNC; 840de59e178SBrian Somers break; 841de59e178SBrian Somers 842de59e178SBrian Somers case TTY_DEVICE: 843de59e178SBrian Somers type = RAD_ASYNC; 844de59e178SBrian Somers break; 845de59e178SBrian Somers 846de59e178SBrian Somers case ETHER_DEVICE: 847de59e178SBrian Somers type = RAD_ETHERNET; 848de59e178SBrian Somers break; 849de59e178SBrian Somers 850de59e178SBrian Somers case TCP_DEVICE: 851de59e178SBrian Somers case UDP_DEVICE: 852de59e178SBrian Somers case EXEC_DEVICE: 853de59e178SBrian Somers case ATM_DEVICE: 854de59e178SBrian Somers case NG_DEVICE: 855de59e178SBrian Somers type = RAD_VIRTUAL; 856de59e178SBrian Somers break; 857de59e178SBrian Somers } 858de59e178SBrian Somers 859d4d4a70aSRoman Bogorodskiy if (rad_put_int(rad->cx.rad, RAD_NAS_PORT_TYPE, type) != 0) { 860d4d4a70aSRoman Bogorodskiy log_Printf(LogERROR, "rad_put: rad_put_int: %s\n", rad_strerror(rad->cx.rad)); 861d4d4a70aSRoman Bogorodskiy rad_close(rad->cx.rad); 862de59e178SBrian Somers return 0; 863de59e178SBrian Somers } 864de59e178SBrian Somers 865d4d4a70aSRoman Bogorodskiy switch (rad->port_id_type) { 866d4d4a70aSRoman Bogorodskiy case RPI_PID: 867d4d4a70aSRoman Bogorodskiy slot = (int)getpid(); 868d4d4a70aSRoman Bogorodskiy break; 869d4d4a70aSRoman Bogorodskiy case RPI_IFNUM: 870d4d4a70aSRoman Bogorodskiy slot = p->dl->bundle->iface->index; 871d4d4a70aSRoman Bogorodskiy break; 872d4d4a70aSRoman Bogorodskiy case RPI_TUNNUM: 873d4d4a70aSRoman Bogorodskiy slot = p->dl->bundle->unit; 874d4d4a70aSRoman Bogorodskiy break; 875d4d4a70aSRoman Bogorodskiy case RPI_DEFAULT: 876d4d4a70aSRoman Bogorodskiy default: 877d4d4a70aSRoman Bogorodskiy slot = physical_Slot(p); 878d4d4a70aSRoman Bogorodskiy break; 879d4d4a70aSRoman Bogorodskiy } 880d4d4a70aSRoman Bogorodskiy 881d4d4a70aSRoman Bogorodskiy if (slot >= 0) 882d4d4a70aSRoman Bogorodskiy if (rad_put_int(rad->cx.rad, RAD_NAS_PORT, slot) != 0) { 883d4d4a70aSRoman Bogorodskiy log_Printf(LogERROR, "rad_put: rad_put_int: %s\n", rad_strerror(rad->cx.rad)); 884d4d4a70aSRoman Bogorodskiy rad_close(rad->cx.rad); 885de59e178SBrian Somers return 0; 886de59e178SBrian Somers } 887de59e178SBrian Somers 888de59e178SBrian Somers return 1; 889de59e178SBrian Somers } 890de59e178SBrian Somers 891f0cdd9c0SBrian Somers /* 892f0cdd9c0SBrian Somers * Start an authentication request to the RADIUS server. 893f0cdd9c0SBrian Somers */ 894a16061b2SBrian Somers int 895f0cdd9c0SBrian Somers radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name, 896a16061b2SBrian Somers const char *key, int klen, const char *nchallenge, 897250be50bSBrian Somers int nclen) 898f0cdd9c0SBrian Somers { 89926e6a622SBrian Somers char hostname[MAXHOSTNAMELEN]; 900057f1760SBrian Somers struct timeval tv; 901057f1760SBrian Somers const char *what = "questionable"; /* silence warnings! */ 902057f1760SBrian Somers char *mac_addr; 903057f1760SBrian Somers int got; 904f10f5203SBrian Somers struct hostent *hp; 905f10f5203SBrian Somers struct in_addr hostaddr; 906ff8e577bSBrian Somers #ifndef NODES 907a16061b2SBrian Somers struct mschap_response msresp; 908a16061b2SBrian Somers struct mschap2_response msresp2; 909250be50bSBrian Somers const struct MSCHAPv2_resp *keyv2; 910ff8e577bSBrian Somers #endif 911f0cdd9c0SBrian Somers 912f0cdd9c0SBrian Somers if (!*r->cfg.file) 913a16061b2SBrian Somers return 0; 914f0cdd9c0SBrian Somers 915f0cdd9c0SBrian Somers if (r->cx.fd != -1) 916f0cdd9c0SBrian Somers /* 917f0cdd9c0SBrian Somers * We assume that our name/key/challenge is the same as last time, 918f0cdd9c0SBrian Somers * and just continue to wait for the RADIUS server(s). 919f0cdd9c0SBrian Somers */ 920a16061b2SBrian Somers return 1; 921f0cdd9c0SBrian Somers 922f0cdd9c0SBrian Somers radius_Destroy(r); 923f0cdd9c0SBrian Somers 924794c9bbcSBrian Somers if ((r->cx.rad = rad_auth_open()) == NULL) { 925794c9bbcSBrian Somers log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno)); 926a16061b2SBrian Somers return 0; 927f0cdd9c0SBrian Somers } 928f0cdd9c0SBrian Somers 929f0cdd9c0SBrian Somers if (rad_config(r->cx.rad, r->cfg.file) != 0) { 930f0cdd9c0SBrian Somers log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad)); 931f0cdd9c0SBrian Somers rad_close(r->cx.rad); 932a16061b2SBrian Somers return 0; 933f0cdd9c0SBrian Somers } 934f0cdd9c0SBrian Somers 935f0cdd9c0SBrian Somers if (rad_create_request(r->cx.rad, RAD_ACCESS_REQUEST) != 0) { 936f0cdd9c0SBrian Somers log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad)); 937f0cdd9c0SBrian Somers rad_close(r->cx.rad); 938a16061b2SBrian Somers return 0; 939f0cdd9c0SBrian Somers } 940f0cdd9c0SBrian Somers 9414dc4e1eeSBrian Somers if (rad_put_string(r->cx.rad, RAD_USER_NAME, name) != 0 || 942f0cdd9c0SBrian Somers rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 || 943f0cdd9c0SBrian Somers rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) { 944f0cdd9c0SBrian Somers log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 945f0cdd9c0SBrian Somers rad_close(r->cx.rad); 946a16061b2SBrian Somers return 0; 947f0cdd9c0SBrian Somers } 948f0cdd9c0SBrian Somers 949ff8e577bSBrian Somers switch (authp->physical->link.lcp.want_auth) { 950ff8e577bSBrian Somers case PROTO_PAP: 951ff8e577bSBrian Somers /* We're talking PAP */ 952ff8e577bSBrian Somers if (rad_put_attr(r->cx.rad, RAD_USER_PASSWORD, key, klen) != 0) { 953ff8e577bSBrian Somers log_Printf(LogERROR, "PAP: rad_put_string: %s\n", 954ff8e577bSBrian Somers rad_strerror(r->cx.rad)); 955ff8e577bSBrian Somers rad_close(r->cx.rad); 956a16061b2SBrian Somers return 0; 957ff8e577bSBrian Somers } 958e715b13bSBrian Somers what = "PAP"; 959ff8e577bSBrian Somers break; 960ff8e577bSBrian Somers 961ff8e577bSBrian Somers case PROTO_CHAP: 962ff8e577bSBrian Somers switch (authp->physical->link.lcp.want_authtype) { 963ff8e577bSBrian Somers case 0x5: 96450ca6ec3SBrian Somers if (rad_put_attr(r->cx.rad, RAD_CHAP_PASSWORD, key, klen) != 0 || 965a16061b2SBrian Somers rad_put_attr(r->cx.rad, RAD_CHAP_CHALLENGE, nchallenge, nclen) != 0) { 966f0cdd9c0SBrian Somers log_Printf(LogERROR, "CHAP: rad_put_string: %s\n", 967f0cdd9c0SBrian Somers rad_strerror(r->cx.rad)); 968f0cdd9c0SBrian Somers rad_close(r->cx.rad); 969a16061b2SBrian Somers return 0; 970f0cdd9c0SBrian Somers } 971e715b13bSBrian Somers what = "CHAP"; 972ff8e577bSBrian Somers break; 973ff8e577bSBrian Somers 974ff8e577bSBrian Somers #ifndef NODES 975ff8e577bSBrian Somers case 0x80: 976ff8e577bSBrian Somers if (klen != 50) { 977a16061b2SBrian Somers log_Printf(LogERROR, "CHAP80: Unrecognised key length %d\n", klen); 978f0cdd9c0SBrian Somers rad_close(r->cx.rad); 979a16061b2SBrian Somers return 0; 980f0cdd9c0SBrian Somers } 981a16061b2SBrian Somers 982ff8e577bSBrian Somers rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT, 983a16061b2SBrian Somers RAD_MICROSOFT_MS_CHAP_CHALLENGE, nchallenge, nclen); 984a16061b2SBrian Somers msresp.ident = *key; 985a16061b2SBrian Somers msresp.flags = 0x01; 986a16061b2SBrian Somers memcpy(msresp.lm_response, key + 1, 24); 987a16061b2SBrian Somers memcpy(msresp.nt_response, key + 25, 24); 988ff8e577bSBrian Somers rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT, 989a16061b2SBrian Somers RAD_MICROSOFT_MS_CHAP_RESPONSE, &msresp, 990a16061b2SBrian Somers sizeof msresp); 991e715b13bSBrian Somers what = "MSCHAP"; 992ff8e577bSBrian Somers break; 993ff8e577bSBrian Somers 994ff8e577bSBrian Somers case 0x81: 995250be50bSBrian Somers if (klen != sizeof(*keyv2) + 1) { 996a16061b2SBrian Somers log_Printf(LogERROR, "CHAP81: Unrecognised key length %d\n", klen); 997a16061b2SBrian Somers rad_close(r->cx.rad); 998a16061b2SBrian Somers return 0; 999a16061b2SBrian Somers } 1000a16061b2SBrian Somers 1001250be50bSBrian Somers keyv2 = (const struct MSCHAPv2_resp *)(key + 1); 1002a16061b2SBrian Somers rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT, 1003a16061b2SBrian Somers RAD_MICROSOFT_MS_CHAP_CHALLENGE, nchallenge, nclen); 1004a16061b2SBrian Somers msresp2.ident = *key; 1005250be50bSBrian Somers msresp2.flags = keyv2->Flags; 1006250be50bSBrian Somers memcpy(msresp2.response, keyv2->NTResponse, sizeof msresp2.response); 1007a16061b2SBrian Somers memset(msresp2.reserved, '\0', sizeof msresp2.reserved); 1008250be50bSBrian Somers memcpy(msresp2.pchallenge, keyv2->PeerChallenge, 1009250be50bSBrian Somers sizeof msresp2.pchallenge); 1010a16061b2SBrian Somers rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT, 1011a16061b2SBrian Somers RAD_MICROSOFT_MS_CHAP2_RESPONSE, &msresp2, 1012a16061b2SBrian Somers sizeof msresp2); 1013e715b13bSBrian Somers what = "MSCHAPv2"; 1014a16061b2SBrian Somers break; 1015ff8e577bSBrian Somers #endif 1016ff8e577bSBrian Somers default: 1017ff8e577bSBrian Somers log_Printf(LogERROR, "CHAP: Unrecognised type 0x%02x\n", 1018ff8e577bSBrian Somers authp->physical->link.lcp.want_authtype); 1019ff8e577bSBrian Somers rad_close(r->cx.rad); 1020a16061b2SBrian Somers return 0; 1021ff8e577bSBrian Somers } 1022ff8e577bSBrian Somers } 1023f0cdd9c0SBrian Somers 1024f10f5203SBrian Somers if (gethostname(hostname, sizeof hostname) != 0) 1025f10f5203SBrian Somers log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno)); 1026f10f5203SBrian Somers else { 10270508c09aSBrian Somers if (Enabled(authp->physical->dl->bundle, OPT_NAS_IP_ADDRESS) && 10280508c09aSBrian Somers (hp = gethostbyname(hostname)) != NULL) { 1029f10f5203SBrian Somers hostaddr.s_addr = *(u_long *)hp->h_addr; 1030f10f5203SBrian Somers if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) { 1031f10f5203SBrian Somers log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 1032f10f5203SBrian Somers rad_strerror(r->cx.rad)); 1033f10f5203SBrian Somers rad_close(r->cx.rad); 1034a16061b2SBrian Somers return 0; 1035f10f5203SBrian Somers } 1036f10f5203SBrian Somers } 10370508c09aSBrian Somers if (Enabled(authp->physical->dl->bundle, OPT_NAS_IDENTIFIER) && 10380508c09aSBrian Somers rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) { 1039f10f5203SBrian Somers log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 1040f10f5203SBrian Somers rad_strerror(r->cx.rad)); 1041f10f5203SBrian Somers rad_close(r->cx.rad); 1042a16061b2SBrian Somers return 0; 1043f10f5203SBrian Somers } 1044f10f5203SBrian Somers } 1045f10f5203SBrian Somers 10465de776b9SBrian Somers if ((mac_addr = getenv("HISMACADDR")) != NULL && 10475de776b9SBrian Somers rad_put_string(r->cx.rad, RAD_CALLING_STATION_ID, mac_addr) != 0) { 10485de776b9SBrian Somers log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 10495de776b9SBrian Somers rad_close(r->cx.rad); 1050057f1760SBrian Somers return 0; 10515de776b9SBrian Somers } 10525de776b9SBrian Somers 1053d4d4a70aSRoman Bogorodskiy radius_put_physical_details(r, authp->physical); 1054f10f5203SBrian Somers 1055e715b13bSBrian Somers log_Printf(LogRADIUS, "Radius(auth): %s data sent for %s\n", what, name); 1056e715b13bSBrian Somers 1057c42627ffSBrian Somers r->cx.auth = authp; 1058f0cdd9c0SBrian Somers if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv))) 1059f0cdd9c0SBrian Somers radius_Process(r, got); 1060f0cdd9c0SBrian Somers else { 1061e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 1062e715b13bSBrian Somers "Radius: Request sent\n"); 1063f0cdd9c0SBrian Somers log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout); 1064f0cdd9c0SBrian Somers r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS; 1065f0cdd9c0SBrian Somers r->cx.timer.func = radius_Timeout; 1066c42627ffSBrian Somers r->cx.timer.name = "radius auth"; 1067f0cdd9c0SBrian Somers r->cx.timer.arg = r; 1068f0cdd9c0SBrian Somers timer_Start(&r->cx.timer); 1069f0cdd9c0SBrian Somers } 1070a16061b2SBrian Somers 1071a16061b2SBrian Somers return 1; 1072f0cdd9c0SBrian Somers } 1073f0cdd9c0SBrian Somers 1074cf7c10d0SHajimu UMEMOTO /* Fetch IP, netmask from IPCP */ 1075cf7c10d0SHajimu UMEMOTO void 1076cf7c10d0SHajimu UMEMOTO radius_Account_Set_Ip(struct radacct *ac, struct in_addr *peer_ip, 1077cf7c10d0SHajimu UMEMOTO struct in_addr *netmask) 1078cf7c10d0SHajimu UMEMOTO { 1079cf7c10d0SHajimu UMEMOTO ac->proto = PROTO_IPCP; 10802cc2a59dSHajimu UMEMOTO memcpy(&ac->peer.ip.addr, peer_ip, sizeof(ac->peer.ip.addr)); 10812cc2a59dSHajimu UMEMOTO memcpy(&ac->peer.ip.mask, netmask, sizeof(ac->peer.ip.mask)); 1082cf7c10d0SHajimu UMEMOTO } 1083cf7c10d0SHajimu UMEMOTO 1084cf7c10d0SHajimu UMEMOTO #ifndef NOINET6 1085cf7c10d0SHajimu UMEMOTO /* Fetch interface-id from IPV6CP */ 1086cf7c10d0SHajimu UMEMOTO void 1087cf7c10d0SHajimu UMEMOTO radius_Account_Set_Ipv6(struct radacct *ac, u_char *ifid) 1088cf7c10d0SHajimu UMEMOTO { 1089cf7c10d0SHajimu UMEMOTO ac->proto = PROTO_IPV6CP; 10902cc2a59dSHajimu UMEMOTO memcpy(&ac->peer.ipv6.ifid, ifid, sizeof(ac->peer.ipv6.ifid)); 1091cf7c10d0SHajimu UMEMOTO } 1092cf7c10d0SHajimu UMEMOTO #endif 1093cf7c10d0SHajimu UMEMOTO 1094f0cdd9c0SBrian Somers /* 1095794c9bbcSBrian Somers * Send an accounting request to the RADIUS server 1096794c9bbcSBrian Somers */ 1097794c9bbcSBrian Somers void 1098794c9bbcSBrian Somers radius_Account(struct radius *r, struct radacct *ac, struct datalink *dl, 1099cf7c10d0SHajimu UMEMOTO int acct_type, struct pppThroughput *stats) 1100794c9bbcSBrian Somers { 1101794c9bbcSBrian Somers struct timeval tv; 1102de59e178SBrian Somers int got; 110326e6a622SBrian Somers char hostname[MAXHOSTNAMELEN]; 11045de776b9SBrian Somers char *mac_addr; 1105794c9bbcSBrian Somers struct hostent *hp; 1106794c9bbcSBrian Somers struct in_addr hostaddr; 1107794c9bbcSBrian Somers 1108794c9bbcSBrian Somers if (!*r->cfg.file) 1109794c9bbcSBrian Somers return; 1110794c9bbcSBrian Somers 1111794c9bbcSBrian Somers if (r->cx.fd != -1) 1112794c9bbcSBrian Somers /* 1113794c9bbcSBrian Somers * We assume that our name/key/challenge is the same as last time, 1114794c9bbcSBrian Somers * and just continue to wait for the RADIUS server(s). 1115794c9bbcSBrian Somers */ 1116794c9bbcSBrian Somers return; 1117794c9bbcSBrian Somers 11188fb5ef5aSBrian Somers timer_Stop(&r->cx.timer); 1119794c9bbcSBrian Somers 1120ba093e81SBrian Somers if ((r->cx.rad = rad_acct_open()) == NULL) { 1121794c9bbcSBrian Somers log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno)); 1122794c9bbcSBrian Somers return; 1123794c9bbcSBrian Somers } 1124794c9bbcSBrian Somers 1125794c9bbcSBrian Somers if (rad_config(r->cx.rad, r->cfg.file) != 0) { 1126794c9bbcSBrian Somers log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad)); 1127794c9bbcSBrian Somers rad_close(r->cx.rad); 1128794c9bbcSBrian Somers return; 1129794c9bbcSBrian Somers } 1130794c9bbcSBrian Somers 1131794c9bbcSBrian Somers if (rad_create_request(r->cx.rad, RAD_ACCOUNTING_REQUEST) != 0) { 1132794c9bbcSBrian Somers log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad)); 1133794c9bbcSBrian Somers rad_close(r->cx.rad); 1134794c9bbcSBrian Somers return; 1135794c9bbcSBrian Somers } 1136794c9bbcSBrian Somers 1137794c9bbcSBrian Somers /* Grab some accounting data and initialize structure */ 1138794c9bbcSBrian Somers if (acct_type == RAD_START) { 1139794c9bbcSBrian Somers ac->rad_parent = r; 1140794c9bbcSBrian Somers /* Fetch username from datalink */ 11414dc4e1eeSBrian Somers strncpy(ac->user_name, dl->peer.authname, sizeof ac->user_name); 1142794c9bbcSBrian Somers ac->user_name[AUTHLEN-1] = '\0'; 1143794c9bbcSBrian Somers 1144794c9bbcSBrian Somers ac->authentic = 2; /* Assume RADIUS verified auth data */ 1145794c9bbcSBrian Somers 1146794c9bbcSBrian Somers /* Generate a session ID */ 114712b5aabaSBrian Somers snprintf(ac->session_id, sizeof ac->session_id, "%s%ld-%s%lu", 114812b5aabaSBrian Somers dl->bundle->cfg.auth.name, (long)getpid(), 11494dc4e1eeSBrian Somers dl->peer.authname, (unsigned long)stats->uptime); 1150794c9bbcSBrian Somers 1151794c9bbcSBrian Somers /* And grab our MP socket name */ 1152794c9bbcSBrian Somers snprintf(ac->multi_session_id, sizeof ac->multi_session_id, "%s", 1153794c9bbcSBrian Somers dl->bundle->ncp.mp.active ? 1154794c9bbcSBrian Somers dl->bundle->ncp.mp.server.socket.sun_path : ""); 115580c7cc1cSPedro F. Giffuni } 1156794c9bbcSBrian Somers 1157794c9bbcSBrian Somers if (rad_put_string(r->cx.rad, RAD_USER_NAME, ac->user_name) != 0 || 1158794c9bbcSBrian Somers rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 || 1159cf7c10d0SHajimu UMEMOTO rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) { 1160794c9bbcSBrian Somers log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 1161794c9bbcSBrian Somers rad_close(r->cx.rad); 1162794c9bbcSBrian Somers return; 1163794c9bbcSBrian Somers } 1164cf7c10d0SHajimu UMEMOTO switch (ac->proto) { 1165cf7c10d0SHajimu UMEMOTO case PROTO_IPCP: 11662cc2a59dSHajimu UMEMOTO if (rad_put_addr(r->cx.rad, RAD_FRAMED_IP_ADDRESS, 11677cbe2606SBrian Somers ac->peer.ip.addr) != 0 || 11682cc2a59dSHajimu UMEMOTO rad_put_addr(r->cx.rad, RAD_FRAMED_IP_NETMASK, 11692cc2a59dSHajimu UMEMOTO ac->peer.ip.mask) != 0) { 1170cf7c10d0SHajimu UMEMOTO log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 1171cf7c10d0SHajimu UMEMOTO rad_close(r->cx.rad); 1172cf7c10d0SHajimu UMEMOTO return; 1173cf7c10d0SHajimu UMEMOTO } 1174cf7c10d0SHajimu UMEMOTO break; 1175cf7c10d0SHajimu UMEMOTO #ifndef NOINET6 1176cf7c10d0SHajimu UMEMOTO case PROTO_IPV6CP: 11772cc2a59dSHajimu UMEMOTO if (rad_put_attr(r->cx.rad, RAD_FRAMED_INTERFACE_ID, ac->peer.ipv6.ifid, 11782cc2a59dSHajimu UMEMOTO sizeof(ac->peer.ipv6.ifid)) != 0) { 1179cf7c10d0SHajimu UMEMOTO log_Printf(LogERROR, "rad_put_attr: %s\n", rad_strerror(r->cx.rad)); 1180cf7c10d0SHajimu UMEMOTO rad_close(r->cx.rad); 1181cf7c10d0SHajimu UMEMOTO return; 1182cf7c10d0SHajimu UMEMOTO } 1183ec3e98b8SHajimu UMEMOTO if (r->ipv6prefix) { 1184ec3e98b8SHajimu UMEMOTO /* 1185ec3e98b8SHajimu UMEMOTO * Since PPP doesn't delegate an IPv6 prefix to a peer, 1186ec3e98b8SHajimu UMEMOTO * Framed-IPv6-Prefix may be not used, actually. 1187ec3e98b8SHajimu UMEMOTO */ 1188ec3e98b8SHajimu UMEMOTO if (rad_put_attr(r->cx.rad, RAD_FRAMED_IPV6_PREFIX, r->ipv6prefix, 1189ec3e98b8SHajimu UMEMOTO sizeof(struct in6_addr) + 2) != 0) { 1190ec3e98b8SHajimu UMEMOTO log_Printf(LogERROR, "rad_put_attr: %s\n", rad_strerror(r->cx.rad)); 1191ec3e98b8SHajimu UMEMOTO rad_close(r->cx.rad); 1192ec3e98b8SHajimu UMEMOTO return; 1193ec3e98b8SHajimu UMEMOTO } 1194ec3e98b8SHajimu UMEMOTO } 1195cf7c10d0SHajimu UMEMOTO break; 1196cf7c10d0SHajimu UMEMOTO #endif 1197cf7c10d0SHajimu UMEMOTO default: 1198cf7c10d0SHajimu UMEMOTO /* We don't log any protocol specific information */ 1199cf7c10d0SHajimu UMEMOTO break; 1200cf7c10d0SHajimu UMEMOTO } 1201794c9bbcSBrian Somers 12025de776b9SBrian Somers if ((mac_addr = getenv("HISMACADDR")) != NULL && 12035de776b9SBrian Somers rad_put_string(r->cx.rad, RAD_CALLING_STATION_ID, mac_addr) != 0) { 12045de776b9SBrian Somers log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 12055de776b9SBrian Somers rad_close(r->cx.rad); 12065de776b9SBrian Somers return; 12075de776b9SBrian Somers } 12085de776b9SBrian Somers 1209794c9bbcSBrian Somers if (gethostname(hostname, sizeof hostname) != 0) 1210794c9bbcSBrian Somers log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno)); 1211794c9bbcSBrian Somers else { 12120508c09aSBrian Somers if (Enabled(dl->bundle, OPT_NAS_IP_ADDRESS) && 12130508c09aSBrian Somers (hp = gethostbyname(hostname)) != NULL) { 1214794c9bbcSBrian Somers hostaddr.s_addr = *(u_long *)hp->h_addr; 1215794c9bbcSBrian Somers if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) { 1216794c9bbcSBrian Somers log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 1217794c9bbcSBrian Somers rad_strerror(r->cx.rad)); 1218794c9bbcSBrian Somers rad_close(r->cx.rad); 1219794c9bbcSBrian Somers return; 1220794c9bbcSBrian Somers } 1221794c9bbcSBrian Somers } 12220508c09aSBrian Somers if (Enabled(dl->bundle, OPT_NAS_IDENTIFIER) && 12230508c09aSBrian Somers rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) { 1224794c9bbcSBrian Somers log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 1225794c9bbcSBrian Somers rad_strerror(r->cx.rad)); 1226794c9bbcSBrian Somers rad_close(r->cx.rad); 1227794c9bbcSBrian Somers return; 1228794c9bbcSBrian Somers } 1229794c9bbcSBrian Somers } 1230794c9bbcSBrian Somers 1231d4d4a70aSRoman Bogorodskiy radius_put_physical_details(r, dl->physical); 1232794c9bbcSBrian Somers 1233794c9bbcSBrian Somers if (rad_put_int(r->cx.rad, RAD_ACCT_STATUS_TYPE, acct_type) != 0 || 1234794c9bbcSBrian Somers rad_put_string(r->cx.rad, RAD_ACCT_SESSION_ID, ac->session_id) != 0 || 1235794c9bbcSBrian Somers rad_put_string(r->cx.rad, RAD_ACCT_MULTI_SESSION_ID, 1236794c9bbcSBrian Somers ac->multi_session_id) != 0 || 1237794c9bbcSBrian Somers rad_put_int(r->cx.rad, RAD_ACCT_DELAY_TIME, 0) != 0) { 1238794c9bbcSBrian Somers /* XXX ACCT_DELAY_TIME should be increased each time a packet is waiting */ 1239794c9bbcSBrian Somers log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 1240794c9bbcSBrian Somers rad_close(r->cx.rad); 1241794c9bbcSBrian Somers return; 1242794c9bbcSBrian Somers } 1243794c9bbcSBrian Somers 1244e715b13bSBrian Somers if (acct_type == RAD_STOP || acct_type == RAD_ALIVE) 1245794c9bbcSBrian Somers /* Show some statistics */ 1246dfb3194aSDiomidis Spinellis if (rad_put_int(r->cx.rad, RAD_ACCT_INPUT_OCTETS, stats->OctetsIn % UINT32_MAX) != 0 || 1247dfb3194aSDiomidis Spinellis rad_put_int(r->cx.rad, RAD_ACCT_INPUT_GIGAWORDS, stats->OctetsIn / UINT32_MAX) != 0 || 1248794c9bbcSBrian Somers rad_put_int(r->cx.rad, RAD_ACCT_INPUT_PACKETS, stats->PacketsIn) != 0 || 1249dfb3194aSDiomidis Spinellis rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_OCTETS, stats->OctetsOut % UINT32_MAX) != 0 || 1250dfb3194aSDiomidis Spinellis rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_GIGAWORDS, stats->OctetsOut / UINT32_MAX) != 0 || 1251794c9bbcSBrian Somers rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_PACKETS, stats->PacketsOut) 1252794c9bbcSBrian Somers != 0 || 1253794c9bbcSBrian Somers rad_put_int(r->cx.rad, RAD_ACCT_SESSION_TIME, throughput_uptime(stats)) 1254794c9bbcSBrian Somers != 0) { 1255794c9bbcSBrian Somers log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 1256794c9bbcSBrian Somers rad_close(r->cx.rad); 1257794c9bbcSBrian Somers return; 1258794c9bbcSBrian Somers } 1259794c9bbcSBrian Somers 1260e715b13bSBrian Somers if (log_IsKept(LogPHASE) || log_IsKept(LogRADIUS)) { 1261057f1760SBrian Somers const char *what; 1262e715b13bSBrian Somers int level; 1263e715b13bSBrian Somers 1264e715b13bSBrian Somers switch (acct_type) { 1265e715b13bSBrian Somers case RAD_START: 1266e715b13bSBrian Somers what = "START"; 1267e715b13bSBrian Somers level = log_IsKept(LogPHASE) ? LogPHASE : LogRADIUS; 1268e715b13bSBrian Somers break; 1269e715b13bSBrian Somers case RAD_STOP: 1270e715b13bSBrian Somers what = "STOP"; 1271e715b13bSBrian Somers level = log_IsKept(LogPHASE) ? LogPHASE : LogRADIUS; 1272e715b13bSBrian Somers break; 1273e715b13bSBrian Somers case RAD_ALIVE: 1274e715b13bSBrian Somers what = "ALIVE"; 1275e715b13bSBrian Somers level = LogRADIUS; 1276e715b13bSBrian Somers break; 1277e715b13bSBrian Somers default: 1278e715b13bSBrian Somers what = "<unknown>"; 1279e715b13bSBrian Somers level = log_IsKept(LogPHASE) ? LogPHASE : LogRADIUS; 1280e715b13bSBrian Somers break; 1281e715b13bSBrian Somers } 1282e715b13bSBrian Somers log_Printf(level, "Radius(acct): %s data sent\n", what); 1283e715b13bSBrian Somers } 1284e715b13bSBrian Somers 1285c42627ffSBrian Somers r->cx.auth = NULL; /* Not valid for accounting requests */ 1286794c9bbcSBrian Somers if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv))) 1287794c9bbcSBrian Somers radius_Process(r, got); 1288794c9bbcSBrian Somers else { 1289794c9bbcSBrian Somers log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout); 1290794c9bbcSBrian Somers r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS; 1291794c9bbcSBrian Somers r->cx.timer.func = radius_Timeout; 1292c42627ffSBrian Somers r->cx.timer.name = "radius acct"; 1293794c9bbcSBrian Somers r->cx.timer.arg = r; 1294794c9bbcSBrian Somers timer_Start(&r->cx.timer); 1295794c9bbcSBrian Somers } 1296794c9bbcSBrian Somers } 1297794c9bbcSBrian Somers 1298794c9bbcSBrian Somers /* 1299f0cdd9c0SBrian Somers * How do things look at the moment ? 1300f0cdd9c0SBrian Somers */ 1301972a1bcfSBrian Somers void 1302972a1bcfSBrian Somers radius_Show(struct radius *r, struct prompt *p) 1303972a1bcfSBrian Somers { 130474457d3dSBrian Somers prompt_Printf(p, " Radius config: %s", 130574457d3dSBrian Somers *r->cfg.file ? r->cfg.file : "none"); 1306972a1bcfSBrian Somers if (r->valid) { 1307972a1bcfSBrian Somers prompt_Printf(p, "\n IP: %s\n", inet_ntoa(r->ip)); 1308972a1bcfSBrian Somers prompt_Printf(p, " Netmask: %s\n", inet_ntoa(r->mask)); 1309972a1bcfSBrian Somers prompt_Printf(p, " MTU: %lu\n", r->mtu); 1310972a1bcfSBrian Somers prompt_Printf(p, " VJ: %sabled\n", r->vj ? "en" : "dis"); 1311ff8e577bSBrian Somers prompt_Printf(p, " Message: %s\n", r->repstr ? r->repstr : ""); 13128fb5ef5aSBrian Somers prompt_Printf(p, " MPPE Enc Policy: %s\n", 13138fb5ef5aSBrian Somers radius_policyname(r->mppe.policy)); 13148fb5ef5aSBrian Somers prompt_Printf(p, " MPPE Enc Types: %s\n", 13158fb5ef5aSBrian Somers radius_typesname(r->mppe.types)); 13168fb5ef5aSBrian Somers prompt_Printf(p, " MPPE Recv Key: %seceived\n", 13178fb5ef5aSBrian Somers r->mppe.recvkey ? "R" : "Not r"); 13188fb5ef5aSBrian Somers prompt_Printf(p, " MPPE Send Key: %seceived\n", 13198fb5ef5aSBrian Somers r->mppe.sendkey ? "R" : "Not r"); 1320a16061b2SBrian Somers prompt_Printf(p, " MS-CHAP2-Response: %s\n", 1321a16061b2SBrian Somers r->msrepstr ? r->msrepstr : ""); 1322ff8e577bSBrian Somers prompt_Printf(p, " Error Message: %s\n", r->errstr ? r->errstr : ""); 1323972a1bcfSBrian Somers if (r->routes) 1324972a1bcfSBrian Somers route_ShowSticky(p, r->routes, " Routes", 16); 13250fe74aa4SHajimu UMEMOTO #ifndef NOINET6 13260fe74aa4SHajimu UMEMOTO if (r->ipv6routes) 13270fe74aa4SHajimu UMEMOTO route_ShowSticky(p, r->ipv6routes, " IPv6 Routes", 16); 13280fe74aa4SHajimu UMEMOTO #endif 1329972a1bcfSBrian Somers } else 1330972a1bcfSBrian Somers prompt_Printf(p, " (not authenticated)\n"); 1331972a1bcfSBrian Somers } 1332e715b13bSBrian Somers 1333e715b13bSBrian Somers static void 1334e715b13bSBrian Somers radius_alive(void *v) 1335e715b13bSBrian Somers { 1336e715b13bSBrian Somers struct bundle *bundle = (struct bundle *)v; 1337e715b13bSBrian Somers 1338e715b13bSBrian Somers timer_Stop(&bundle->radius.alive.timer); 1339e715b13bSBrian Somers bundle->radius.alive.timer.load = bundle->radius.alive.interval * SECTICKS; 1340e715b13bSBrian Somers if (bundle->radius.alive.timer.load) { 1341e715b13bSBrian Somers radius_Account(&bundle->radius, &bundle->radacct, 1342e715b13bSBrian Somers bundle->links, RAD_ALIVE, &bundle->ncp.ipcp.throughput); 1343e715b13bSBrian Somers timer_Start(&bundle->radius.alive.timer); 1344e715b13bSBrian Somers } 1345e715b13bSBrian Somers } 1346e715b13bSBrian Somers 1347e715b13bSBrian Somers void 1348e715b13bSBrian Somers radius_StartTimer(struct bundle *bundle) 1349e715b13bSBrian Somers { 13509304cfd0SDimitry Andric if (*bundle->radius.cfg.file && bundle->radius.alive.interval) { 1351e715b13bSBrian Somers bundle->radius.alive.timer.func = radius_alive; 1352e715b13bSBrian Somers bundle->radius.alive.timer.name = "radius alive"; 1353e715b13bSBrian Somers bundle->radius.alive.timer.load = bundle->radius.alive.interval * SECTICKS; 1354e715b13bSBrian Somers bundle->radius.alive.timer.arg = bundle; 1355e715b13bSBrian Somers radius_alive(bundle); 1356e715b13bSBrian Somers } 1357e715b13bSBrian Somers } 1358e715b13bSBrian Somers 1359e715b13bSBrian Somers void 1360e715b13bSBrian Somers radius_StopTimer(struct radius *r) 1361e715b13bSBrian Somers { 1362e715b13bSBrian Somers timer_Stop(&r->alive.timer); 1363e715b13bSBrian Somers } 1364