1972a1bcfSBrian Somers /* 2972a1bcfSBrian Somers * Copyright 1999 Internet Business Solutions Ltd., Switzerland 3972a1bcfSBrian Somers * All rights reserved. 4972a1bcfSBrian Somers * 5972a1bcfSBrian Somers * Redistribution and use in source and binary forms, with or without 6972a1bcfSBrian Somers * modification, are permitted provided that the following conditions 7972a1bcfSBrian Somers * are met: 8972a1bcfSBrian Somers * 1. Redistributions of source code must retain the above copyright 9972a1bcfSBrian Somers * notice, this list of conditions and the following disclaimer. 10972a1bcfSBrian Somers * 2. Redistributions in binary form must reproduce the above copyright 11972a1bcfSBrian Somers * notice, this list of conditions and the following disclaimer in the 12972a1bcfSBrian Somers * documentation and/or other materials provided with the distribution. 13972a1bcfSBrian Somers * 14972a1bcfSBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15972a1bcfSBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16972a1bcfSBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17972a1bcfSBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18972a1bcfSBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19972a1bcfSBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20972a1bcfSBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21972a1bcfSBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22972a1bcfSBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23972a1bcfSBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24972a1bcfSBrian Somers * SUCH DAMAGE. 25972a1bcfSBrian Somers * 2697d92980SPeter Wemm * $FreeBSD$ 27972a1bcfSBrian Somers * 28972a1bcfSBrian Somers */ 29972a1bcfSBrian Somers 30dfb3194aSDiomidis Spinellis #include <stdint.h> 31972a1bcfSBrian Somers #include <sys/param.h> 328fb5ef5aSBrian Somers 3388044778SBrian Somers #include <sys/select.h> 346b457978SBrian Somers #include <sys/socket.h> 35972a1bcfSBrian Somers #include <netinet/in_systm.h> 36972a1bcfSBrian Somers #include <netinet/in.h> 37972a1bcfSBrian Somers #include <netinet/ip.h> 38972a1bcfSBrian Somers #include <arpa/inet.h> 39972a1bcfSBrian Somers #include <sys/un.h> 406b457978SBrian Somers #include <net/route.h> 41972a1bcfSBrian Somers 4210e629b9SBrian Somers #ifdef LOCALRAD 4310e629b9SBrian Somers #include "radlib.h" 44ff8e577bSBrian Somers #include "radlib_vs.h" 4510e629b9SBrian Somers #else 46972a1bcfSBrian Somers #include <radlib.h> 47ff8e577bSBrian Somers #include <radlib_vs.h> 4810e629b9SBrian Somers #endif 4910e629b9SBrian Somers 5010e629b9SBrian Somers #include <errno.h> 518fb5ef5aSBrian Somers #ifndef NODES 528fb5ef5aSBrian Somers #include <md5.h> 538fb5ef5aSBrian Somers #endif 546eafd353SBrian Somers #include <stdarg.h> 55972a1bcfSBrian Somers #include <stdio.h> 56972a1bcfSBrian Somers #include <stdlib.h> 57972a1bcfSBrian Somers #include <string.h> 58f0cdd9c0SBrian Somers #include <sys/time.h> 59972a1bcfSBrian Somers #include <termios.h> 60f10f5203SBrian Somers #include <unistd.h> 61f10f5203SBrian Somers #include <netdb.h> 62972a1bcfSBrian Somers 635d9e6103SBrian Somers #include "layer.h" 64972a1bcfSBrian Somers #include "defs.h" 65972a1bcfSBrian Somers #include "log.h" 66972a1bcfSBrian Somers #include "descriptor.h" 67972a1bcfSBrian Somers #include "prompt.h" 68972a1bcfSBrian Somers #include "timer.h" 69972a1bcfSBrian Somers #include "fsm.h" 70972a1bcfSBrian Somers #include "iplist.h" 71972a1bcfSBrian Somers #include "slcompress.h" 72972a1bcfSBrian Somers #include "throughput.h" 73972a1bcfSBrian Somers #include "lqr.h" 74972a1bcfSBrian Somers #include "hdlc.h" 75972a1bcfSBrian Somers #include "mbuf.h" 7630949fd4SBrian Somers #include "ncpaddr.h" 7730949fd4SBrian Somers #include "ip.h" 78972a1bcfSBrian Somers #include "ipcp.h" 7930949fd4SBrian Somers #include "ipv6cp.h" 80972a1bcfSBrian Somers #include "route.h" 81972a1bcfSBrian Somers #include "command.h" 82972a1bcfSBrian Somers #include "filter.h" 83972a1bcfSBrian Somers #include "lcp.h" 84972a1bcfSBrian Somers #include "ccp.h" 85972a1bcfSBrian Somers #include "link.h" 86972a1bcfSBrian Somers #include "mp.h" 87972a1bcfSBrian Somers #include "radius.h" 88f0cdd9c0SBrian Somers #include "auth.h" 89f0cdd9c0SBrian Somers #include "async.h" 90f0cdd9c0SBrian Somers #include "physical.h" 91f0cdd9c0SBrian Somers #include "chat.h" 92f0cdd9c0SBrian Somers #include "cbcp.h" 93f0cdd9c0SBrian Somers #include "chap.h" 94f0cdd9c0SBrian Somers #include "datalink.h" 9530949fd4SBrian Somers #include "ncp.h" 96972a1bcfSBrian Somers #include "bundle.h" 97ff8e577bSBrian Somers #include "proto.h" 98d4d4a70aSRoman Bogorodskiy #include "iface.h" 99ff8e577bSBrian Somers 100ff8e577bSBrian Somers #ifndef NODES 101a16061b2SBrian Somers struct mschap_response { 102ff8e577bSBrian Somers u_char ident; 103ff8e577bSBrian Somers u_char flags; 104ff8e577bSBrian Somers u_char lm_response[24]; 105ff8e577bSBrian Somers u_char nt_response[24]; 106ff8e577bSBrian Somers }; 107a16061b2SBrian Somers 108a16061b2SBrian Somers struct mschap2_response { 109a16061b2SBrian Somers u_char ident; 110a16061b2SBrian Somers u_char flags; 111a16061b2SBrian Somers u_char pchallenge[16]; 112a16061b2SBrian Somers u_char reserved[8]; 113a16061b2SBrian Somers u_char response[24]; 114a16061b2SBrian Somers }; 1158fb5ef5aSBrian Somers 1168fb5ef5aSBrian Somers #define AUTH_LEN 16 1178fb5ef5aSBrian Somers #define SALT_LEN 2 1188fb5ef5aSBrian Somers #endif 1198fb5ef5aSBrian Somers 1208fb5ef5aSBrian Somers static const char * 1218fb5ef5aSBrian Somers radius_policyname(int policy) 1228fb5ef5aSBrian Somers { 1238fb5ef5aSBrian Somers switch(policy) { 1248fb5ef5aSBrian Somers case MPPE_POLICY_ALLOWED: 1258fb5ef5aSBrian Somers return "Allowed"; 1268fb5ef5aSBrian Somers case MPPE_POLICY_REQUIRED: 1278fb5ef5aSBrian Somers return "Required"; 1288fb5ef5aSBrian Somers } 1298fb5ef5aSBrian Somers return NumStr(policy, NULL, 0); 1308fb5ef5aSBrian Somers } 1318fb5ef5aSBrian Somers 1328fb5ef5aSBrian Somers static const char * 1338fb5ef5aSBrian Somers radius_typesname(int types) 1348fb5ef5aSBrian Somers { 1358fb5ef5aSBrian Somers switch(types) { 1368fb5ef5aSBrian Somers case MPPE_TYPE_40BIT: 1378fb5ef5aSBrian Somers return "40 bit"; 1388fb5ef5aSBrian Somers case MPPE_TYPE_128BIT: 1398fb5ef5aSBrian Somers return "128 bit"; 1408fb5ef5aSBrian Somers case MPPE_TYPE_40BIT|MPPE_TYPE_128BIT: 1418fb5ef5aSBrian Somers return "40 or 128 bit"; 1428fb5ef5aSBrian Somers } 1438fb5ef5aSBrian Somers return NumStr(types, NULL, 0); 1448fb5ef5aSBrian Somers } 1458fb5ef5aSBrian Somers 1468fb5ef5aSBrian Somers #ifndef NODES 1478fb5ef5aSBrian Somers static void 1488fb5ef5aSBrian Somers demangle(struct radius *r, const void *mangled, size_t mlen, 1498fb5ef5aSBrian Somers char **buf, size_t *len) 1508fb5ef5aSBrian Somers { 1518fb5ef5aSBrian Somers char R[AUTH_LEN]; /* variable names as per rfc2548 */ 1528fb5ef5aSBrian Somers const char *S; 1538fb5ef5aSBrian Somers u_char b[16]; 1548fb5ef5aSBrian Somers const u_char *A, *C; 1558fb5ef5aSBrian Somers MD5_CTX Context; 1568fb5ef5aSBrian Somers int Slen, i, Clen, Ppos; 1578fb5ef5aSBrian Somers u_char *P; 1588fb5ef5aSBrian Somers 1598fb5ef5aSBrian Somers if (mlen % 16 != SALT_LEN) { 1608fb5ef5aSBrian Somers log_Printf(LogWARN, "Cannot interpret mangled data of length %ld\n", 1618fb5ef5aSBrian Somers (u_long)mlen); 1628fb5ef5aSBrian Somers *buf = NULL; 1638fb5ef5aSBrian Somers *len = 0; 1648fb5ef5aSBrian Somers return; 1658fb5ef5aSBrian Somers } 1668fb5ef5aSBrian Somers 1678fb5ef5aSBrian Somers /* We need the RADIUS Request-Authenticator */ 1688fb5ef5aSBrian Somers if (rad_request_authenticator(r->cx.rad, R, sizeof R) != AUTH_LEN) { 1698fb5ef5aSBrian Somers log_Printf(LogWARN, "Cannot obtain the RADIUS request authenticator\n"); 1708fb5ef5aSBrian Somers *buf = NULL; 1718fb5ef5aSBrian Somers *len = 0; 1728fb5ef5aSBrian Somers return; 1738fb5ef5aSBrian Somers } 1748fb5ef5aSBrian Somers 1758fb5ef5aSBrian Somers A = (const u_char *)mangled; /* Salt comes first */ 1768fb5ef5aSBrian Somers C = (const u_char *)mangled + SALT_LEN; /* Then the ciphertext */ 1778fb5ef5aSBrian Somers Clen = mlen - SALT_LEN; 1788fb5ef5aSBrian Somers S = rad_server_secret(r->cx.rad); /* We need the RADIUS secret */ 1798fb5ef5aSBrian Somers Slen = strlen(S); 1808fb5ef5aSBrian Somers P = alloca(Clen); /* We derive our plaintext */ 1818fb5ef5aSBrian Somers 1828fb5ef5aSBrian Somers MD5Init(&Context); 1838fb5ef5aSBrian Somers MD5Update(&Context, S, Slen); 1848fb5ef5aSBrian Somers MD5Update(&Context, R, AUTH_LEN); 1858fb5ef5aSBrian Somers MD5Update(&Context, A, SALT_LEN); 1868fb5ef5aSBrian Somers MD5Final(b, &Context); 1878fb5ef5aSBrian Somers Ppos = 0; 1888fb5ef5aSBrian Somers 1898fb5ef5aSBrian Somers while (Clen) { 1908fb5ef5aSBrian Somers Clen -= 16; 1918fb5ef5aSBrian Somers 1928fb5ef5aSBrian Somers for (i = 0; i < 16; i++) 1938fb5ef5aSBrian Somers P[Ppos++] = C[i] ^ b[i]; 1948fb5ef5aSBrian Somers 1958fb5ef5aSBrian Somers if (Clen) { 1968fb5ef5aSBrian Somers MD5Init(&Context); 1978fb5ef5aSBrian Somers MD5Update(&Context, S, Slen); 1988fb5ef5aSBrian Somers MD5Update(&Context, C, 16); 1998fb5ef5aSBrian Somers MD5Final(b, &Context); 2008fb5ef5aSBrian Somers } 2018fb5ef5aSBrian Somers 2028fb5ef5aSBrian Somers C += 16; 2038fb5ef5aSBrian Somers } 2048fb5ef5aSBrian Somers 2058fb5ef5aSBrian Somers /* 2068fb5ef5aSBrian Somers * The resulting plain text consists of a one-byte length, the text and 2078fb5ef5aSBrian Somers * maybe some padding. 2088fb5ef5aSBrian Somers */ 2098fb5ef5aSBrian Somers *len = *P; 2108fb5ef5aSBrian Somers if (*len > mlen - 1) { 2118fb5ef5aSBrian Somers log_Printf(LogWARN, "Mangled data seems to be garbage\n"); 2128fb5ef5aSBrian Somers *buf = NULL; 2138fb5ef5aSBrian Somers *len = 0; 2148fb5ef5aSBrian Somers return; 2158fb5ef5aSBrian Somers } 2168fb5ef5aSBrian Somers 2175d604c11SBrian Somers if ((*buf = malloc(*len)) == NULL) { 2185d604c11SBrian Somers log_Printf(LogWARN, "demangle: Out of memory (%lu bytes)\n", (u_long)*len); 2195d604c11SBrian Somers *len = 0; 2205d604c11SBrian Somers } else 2218fb5ef5aSBrian Somers memcpy(*buf, P + 1, *len); 2228fb5ef5aSBrian Somers } 223ff8e577bSBrian Somers #endif 224972a1bcfSBrian Somers 225ec3e98b8SHajimu UMEMOTO /* XXX: This should go into librarius. */ 226ec3e98b8SHajimu UMEMOTO #ifndef NOINET6 227ec3e98b8SHajimu UMEMOTO static uint8_t * 228ec3e98b8SHajimu UMEMOTO rad_cvt_ipv6prefix(const void *data, size_t len) 229ec3e98b8SHajimu UMEMOTO { 230ec3e98b8SHajimu UMEMOTO const size_t ipv6len = sizeof(struct in6_addr) + 2; 231ec3e98b8SHajimu UMEMOTO uint8_t *s; 232ec3e98b8SHajimu UMEMOTO 233ec3e98b8SHajimu UMEMOTO if (len > ipv6len) 234ec3e98b8SHajimu UMEMOTO return NULL; 235ec3e98b8SHajimu UMEMOTO s = malloc(ipv6len); 236ec3e98b8SHajimu UMEMOTO if (s != NULL) { 237ec3e98b8SHajimu UMEMOTO memset(s, 0, ipv6len); 238ec3e98b8SHajimu UMEMOTO memcpy(s, data, len); 239ec3e98b8SHajimu UMEMOTO } 240ec3e98b8SHajimu UMEMOTO return s; 241ec3e98b8SHajimu UMEMOTO } 242ec3e98b8SHajimu UMEMOTO #endif 243ec3e98b8SHajimu UMEMOTO 244f0cdd9c0SBrian Somers /* 245f0cdd9c0SBrian Somers * rad_continue_send_request() has given us `got' (non-zero). Deal with it. 246f0cdd9c0SBrian Somers */ 247f0cdd9c0SBrian Somers static void 248f0cdd9c0SBrian Somers radius_Process(struct radius *r, int got) 249972a1bcfSBrian Somers { 250972a1bcfSBrian Somers char *argv[MAXARGS], *nuke; 251f0cdd9c0SBrian Somers struct bundle *bundle; 252ff8e577bSBrian Somers int argc, addrs, res, width; 25328e610e3SBrian Somers size_t len; 25430949fd4SBrian Somers struct ncprange dest; 25530949fd4SBrian Somers struct ncpaddr gw; 256f0cdd9c0SBrian Somers const void *data; 257c42627ffSBrian Somers const char *stype; 258ff8e577bSBrian Somers u_int32_t ipaddr, vendor; 25930949fd4SBrian Somers struct in_addr ip; 2600fe74aa4SHajimu UMEMOTO #ifndef NOINET6 261ec3e98b8SHajimu UMEMOTO uint8_t ipv6addr[INET6_ADDRSTRLEN]; 2620fe74aa4SHajimu UMEMOTO struct in6_addr ip6; 2630fe74aa4SHajimu UMEMOTO #endif 264972a1bcfSBrian Somers 265f0cdd9c0SBrian Somers r->cx.fd = -1; /* Stop select()ing */ 266c42627ffSBrian Somers stype = r->cx.auth ? "auth" : "acct"; 267972a1bcfSBrian Somers 268972a1bcfSBrian Somers switch (got) { 269972a1bcfSBrian Somers case RAD_ACCESS_ACCEPT: 270e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 271e715b13bSBrian Somers "Radius(%s): ACCEPT received\n", stype); 272c42627ffSBrian Somers if (!r->cx.auth) { 273c42627ffSBrian Somers rad_close(r->cx.rad); 274c42627ffSBrian Somers return; 275c42627ffSBrian Somers } 276972a1bcfSBrian Somers break; 277972a1bcfSBrian Somers 278f0cdd9c0SBrian Somers case RAD_ACCESS_REJECT: 279e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 280e715b13bSBrian Somers "Radius(%s): REJECT received\n", stype); 281ff8e577bSBrian Somers if (!r->cx.auth) { 282f0cdd9c0SBrian Somers rad_close(r->cx.rad); 283f0cdd9c0SBrian Somers return; 284ff8e577bSBrian Somers } 285ff8e577bSBrian Somers break; 286f0cdd9c0SBrian Somers 287972a1bcfSBrian Somers case RAD_ACCESS_CHALLENGE: 288972a1bcfSBrian Somers /* we can't deal with this (for now) ! */ 289e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 290e715b13bSBrian Somers "Radius: CHALLENGE received (can't handle yet)\n"); 291c42627ffSBrian Somers if (r->cx.auth) 292f0cdd9c0SBrian Somers auth_Failure(r->cx.auth); 293f0cdd9c0SBrian Somers rad_close(r->cx.rad); 294f0cdd9c0SBrian Somers return; 295972a1bcfSBrian Somers 296794c9bbcSBrian Somers case RAD_ACCOUNTING_RESPONSE: 297e715b13bSBrian Somers /* 298e715b13bSBrian Somers * It's probably not ideal to log this at PHASE level as we'll see 299e715b13bSBrian Somers * too much stuff going to the log when ``set rad_alive'' is used. 300e715b13bSBrian Somers * So we differ from older behaviour (ppp version 3.1 and before) 301e715b13bSBrian Somers * and just log accounting responses to LogRADIUS. 302e715b13bSBrian Somers */ 303e715b13bSBrian Somers log_Printf(LogRADIUS, "Radius(%s): Accounting response received\n", 304e715b13bSBrian Somers stype); 305c42627ffSBrian Somers if (r->cx.auth) 306c42627ffSBrian Somers auth_Failure(r->cx.auth); /* unexpected !!! */ 307c42627ffSBrian Somers 308794c9bbcSBrian Somers /* No further processing for accounting requests, please */ 309794c9bbcSBrian Somers rad_close(r->cx.rad); 310794c9bbcSBrian Somers return; 311794c9bbcSBrian Somers 312972a1bcfSBrian Somers case -1: 313e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 314e715b13bSBrian Somers "radius(%s): %s\n", stype, rad_strerror(r->cx.rad)); 315c42627ffSBrian Somers if (r->cx.auth) 316f0cdd9c0SBrian Somers auth_Failure(r->cx.auth); 317f0cdd9c0SBrian Somers rad_close(r->cx.rad); 318f0cdd9c0SBrian Somers return; 319972a1bcfSBrian Somers 320972a1bcfSBrian Somers default: 321c42627ffSBrian Somers log_Printf(LogERROR, "rad_send_request(%s): Failed %d: %s\n", stype, 322f0cdd9c0SBrian Somers got, rad_strerror(r->cx.rad)); 323c42627ffSBrian Somers if (r->cx.auth) 324f0cdd9c0SBrian Somers auth_Failure(r->cx.auth); 325f0cdd9c0SBrian Somers rad_close(r->cx.rad); 326f0cdd9c0SBrian Somers return; 327972a1bcfSBrian Somers } 328972a1bcfSBrian Somers 329ff8e577bSBrian Somers /* Let's see what we've got in our reply */ 330972a1bcfSBrian Somers r->ip.s_addr = r->mask.s_addr = INADDR_NONE; 331972a1bcfSBrian Somers r->mtu = 0; 332972a1bcfSBrian Somers r->vj = 0; 333ff8e577bSBrian Somers while ((res = rad_get_attr(r->cx.rad, &data, &len)) > 0) { 334ff8e577bSBrian Somers switch (res) { 335972a1bcfSBrian Somers case RAD_FRAMED_IP_ADDRESS: 336972a1bcfSBrian Somers r->ip = rad_cvt_addr(data); 337e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 338e715b13bSBrian Somers " IP %s\n", inet_ntoa(r->ip)); 339972a1bcfSBrian Somers break; 340972a1bcfSBrian Somers 341bf1eaec5SBrian Somers case RAD_FILTER_ID: 342bf1eaec5SBrian Somers free(r->filterid); 343bf1eaec5SBrian Somers if ((r->filterid = rad_cvt_string(data, len)) == NULL) { 344bf1eaec5SBrian Somers log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); 345ff8e577bSBrian Somers auth_Failure(r->cx.auth); 346bf1eaec5SBrian Somers rad_close(r->cx.rad); 347bf1eaec5SBrian Somers return; 348bf1eaec5SBrian Somers } 349e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 350e715b13bSBrian Somers " Filter \"%s\"\n", r->filterid); 351bf1eaec5SBrian Somers break; 352bf1eaec5SBrian Somers 353bf1eaec5SBrian Somers case RAD_SESSION_TIMEOUT: 354bf1eaec5SBrian Somers r->sessiontime = rad_cvt_int(data); 355e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 356e715b13bSBrian Somers " Session-Timeout %lu\n", r->sessiontime); 357bf1eaec5SBrian Somers break; 358bf1eaec5SBrian Somers 359972a1bcfSBrian Somers case RAD_FRAMED_IP_NETMASK: 360972a1bcfSBrian Somers r->mask = rad_cvt_addr(data); 361e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 362e715b13bSBrian Somers " Netmask %s\n", inet_ntoa(r->mask)); 363972a1bcfSBrian Somers break; 364972a1bcfSBrian Somers 365972a1bcfSBrian Somers case RAD_FRAMED_MTU: 366972a1bcfSBrian Somers r->mtu = rad_cvt_int(data); 367e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 368e715b13bSBrian Somers " MTU %lu\n", r->mtu); 369972a1bcfSBrian Somers break; 370972a1bcfSBrian Somers 371972a1bcfSBrian Somers case RAD_FRAMED_ROUTING: 372972a1bcfSBrian Somers /* Disabled for now - should we automatically set up some filters ? */ 373972a1bcfSBrian Somers /* rad_cvt_int(data); */ 374972a1bcfSBrian Somers /* bit 1 = Send routing packets */ 375972a1bcfSBrian Somers /* bit 2 = Receive routing packets */ 376972a1bcfSBrian Somers break; 377972a1bcfSBrian Somers 378972a1bcfSBrian Somers case RAD_FRAMED_COMPRESSION: 379972a1bcfSBrian Somers r->vj = rad_cvt_int(data) == 1 ? 1 : 0; 380e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 381e715b13bSBrian Somers " VJ %sabled\n", r->vj ? "en" : "dis"); 382972a1bcfSBrian Somers break; 383972a1bcfSBrian Somers 384972a1bcfSBrian Somers case RAD_FRAMED_ROUTE: 385972a1bcfSBrian Somers /* 386972a1bcfSBrian Somers * We expect a string of the format ``dest[/bits] gw [metrics]'' 387972a1bcfSBrian Somers * Any specified metrics are ignored. MYADDR and HISADDR are 388972a1bcfSBrian Somers * understood for ``dest'' and ``gw'' and ``0.0.0.0'' is the same 389972a1bcfSBrian Somers * as ``HISADDR''. 390972a1bcfSBrian Somers */ 391972a1bcfSBrian Somers 392972a1bcfSBrian Somers if ((nuke = rad_cvt_string(data, len)) == NULL) { 393f0cdd9c0SBrian Somers log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); 394ff8e577bSBrian Somers auth_Failure(r->cx.auth); 395f0cdd9c0SBrian Somers rad_close(r->cx.rad); 396f0cdd9c0SBrian Somers return; 397972a1bcfSBrian Somers } 398972a1bcfSBrian Somers 399e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 400e715b13bSBrian Somers " Route: %s\n", nuke); 401f0cdd9c0SBrian Somers bundle = r->cx.auth->physical->dl->bundle; 40230949fd4SBrian Somers ip.s_addr = INADDR_ANY; 4030fe74aa4SHajimu UMEMOTO ncpaddr_setip4(&gw, ip); 40430949fd4SBrian Somers ncprange_setip4host(&dest, ip); 405972a1bcfSBrian Somers argc = command_Interpret(nuke, strlen(nuke), argv); 406c39aa54eSBrian Somers if (argc < 0) 407c39aa54eSBrian Somers log_Printf(LogWARN, "radius: %s: Syntax error\n", 408c39aa54eSBrian Somers argc == 1 ? argv[0] : "\"\""); 409c39aa54eSBrian Somers else if (argc < 2) 410972a1bcfSBrian Somers log_Printf(LogWARN, "radius: %s: Invalid route\n", 411972a1bcfSBrian Somers argc == 1 ? argv[0] : "\"\""); 412972a1bcfSBrian Somers else if ((strcasecmp(argv[0], "default") != 0 && 41330949fd4SBrian Somers !ncprange_aton(&dest, &bundle->ncp, argv[0])) || 41430949fd4SBrian Somers !ncpaddr_aton(&gw, &bundle->ncp, argv[1])) 415972a1bcfSBrian Somers log_Printf(LogWARN, "radius: %s %s: Invalid route\n", 416972a1bcfSBrian Somers argv[0], argv[1]); 417972a1bcfSBrian Somers else { 41830949fd4SBrian Somers ncprange_getwidth(&dest, &width); 41930949fd4SBrian Somers if (width == 32 && strchr(argv[0], '/') == NULL) { 420972a1bcfSBrian Somers /* No mask specified - use the natural mask */ 42130949fd4SBrian Somers ncprange_getip4addr(&dest, &ip); 42230949fd4SBrian Somers ncprange_setip4mask(&dest, addr2mask(ip)); 42330949fd4SBrian Somers } 424972a1bcfSBrian Somers addrs = 0; 425972a1bcfSBrian Somers 426972a1bcfSBrian Somers if (!strncasecmp(argv[0], "HISADDR", 7)) 427972a1bcfSBrian Somers addrs = ROUTE_DSTHISADDR; 428972a1bcfSBrian Somers else if (!strncasecmp(argv[0], "MYADDR", 6)) 429972a1bcfSBrian Somers addrs = ROUTE_DSTMYADDR; 430972a1bcfSBrian Somers 43130949fd4SBrian Somers if (ncpaddr_getip4addr(&gw, &ipaddr) && ipaddr == INADDR_ANY) { 432972a1bcfSBrian Somers addrs |= ROUTE_GWHISADDR; 43330949fd4SBrian Somers ncpaddr_setip4(&gw, bundle->ncp.ipcp.peer_ip); 434972a1bcfSBrian Somers } else if (strcasecmp(argv[1], "HISADDR") == 0) 435972a1bcfSBrian Somers addrs |= ROUTE_GWHISADDR; 436972a1bcfSBrian Somers 43730949fd4SBrian Somers route_Add(&r->routes, addrs, &dest, &gw); 438972a1bcfSBrian Somers } 439972a1bcfSBrian Somers free(nuke); 440972a1bcfSBrian Somers break; 441972a1bcfSBrian Somers 442ff8e577bSBrian Somers case RAD_REPLY_MESSAGE: 443ff8e577bSBrian Somers free(r->repstr); 444ff8e577bSBrian Somers if ((r->repstr = rad_cvt_string(data, len)) == NULL) { 445ff8e577bSBrian Somers log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); 446ff8e577bSBrian Somers auth_Failure(r->cx.auth); 447ff8e577bSBrian Somers rad_close(r->cx.rad); 448ff8e577bSBrian Somers return; 449ff8e577bSBrian Somers } 450e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 451e715b13bSBrian Somers " Reply-Message \"%s\"\n", r->repstr); 452ff8e577bSBrian Somers break; 453ff8e577bSBrian Somers 4540fe74aa4SHajimu UMEMOTO #ifndef NOINET6 455ec3e98b8SHajimu UMEMOTO case RAD_FRAMED_IPV6_PREFIX: 456ec3e98b8SHajimu UMEMOTO free(r->ipv6prefix); 457a404ab16SHajimu UMEMOTO if ((r->ipv6prefix = rad_cvt_ipv6prefix(data, len)) == NULL) { 458a404ab16SHajimu UMEMOTO log_Printf(LogERROR, "rad_cvt_ipv6prefix: %s\n", 459a404ab16SHajimu UMEMOTO "Malformed attribute in response"); 460a404ab16SHajimu UMEMOTO auth_Failure(r->cx.auth); 461a404ab16SHajimu UMEMOTO rad_close(r->cx.rad); 462a404ab16SHajimu UMEMOTO return; 463a404ab16SHajimu UMEMOTO } 464ec3e98b8SHajimu UMEMOTO inet_ntop(AF_INET6, &r->ipv6prefix[2], ipv6addr, sizeof(ipv6addr)); 465e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 466e715b13bSBrian Somers " IPv6 %s/%d\n", ipv6addr, r->ipv6prefix[1]); 467ec3e98b8SHajimu UMEMOTO break; 468ec3e98b8SHajimu UMEMOTO 4690fe74aa4SHajimu UMEMOTO case RAD_FRAMED_IPV6_ROUTE: 4700fe74aa4SHajimu UMEMOTO /* 4710fe74aa4SHajimu UMEMOTO * We expect a string of the format ``dest[/bits] gw [metrics]'' 4720fe74aa4SHajimu UMEMOTO * Any specified metrics are ignored. MYADDR6 and HISADDR6 are 4730fe74aa4SHajimu UMEMOTO * understood for ``dest'' and ``gw'' and ``::'' is the same 4740fe74aa4SHajimu UMEMOTO * as ``HISADDR6''. 4750fe74aa4SHajimu UMEMOTO */ 4760fe74aa4SHajimu UMEMOTO 4770fe74aa4SHajimu UMEMOTO if ((nuke = rad_cvt_string(data, len)) == NULL) { 4780fe74aa4SHajimu UMEMOTO log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); 4790fe74aa4SHajimu UMEMOTO auth_Failure(r->cx.auth); 4800fe74aa4SHajimu UMEMOTO rad_close(r->cx.rad); 4810fe74aa4SHajimu UMEMOTO return; 4820fe74aa4SHajimu UMEMOTO } 4830fe74aa4SHajimu UMEMOTO 484e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 485e715b13bSBrian Somers " IPv6 Route: %s\n", nuke); 4860fe74aa4SHajimu UMEMOTO bundle = r->cx.auth->physical->dl->bundle; 4870fe74aa4SHajimu UMEMOTO ncpaddr_setip6(&gw, &in6addr_any); 4880fe74aa4SHajimu UMEMOTO ncprange_set(&dest, &gw, 0); 4890fe74aa4SHajimu UMEMOTO argc = command_Interpret(nuke, strlen(nuke), argv); 4900fe74aa4SHajimu UMEMOTO if (argc < 0) 4910fe74aa4SHajimu UMEMOTO log_Printf(LogWARN, "radius: %s: Syntax error\n", 4920fe74aa4SHajimu UMEMOTO argc == 1 ? argv[0] : "\"\""); 4930fe74aa4SHajimu UMEMOTO else if (argc < 2) 4940fe74aa4SHajimu UMEMOTO log_Printf(LogWARN, "radius: %s: Invalid route\n", 4950fe74aa4SHajimu UMEMOTO argc == 1 ? argv[0] : "\"\""); 4960fe74aa4SHajimu UMEMOTO else if ((strcasecmp(argv[0], "default") != 0 && 4970fe74aa4SHajimu UMEMOTO !ncprange_aton(&dest, &bundle->ncp, argv[0])) || 4980fe74aa4SHajimu UMEMOTO !ncpaddr_aton(&gw, &bundle->ncp, argv[1])) 4990fe74aa4SHajimu UMEMOTO log_Printf(LogWARN, "radius: %s %s: Invalid route\n", 5000fe74aa4SHajimu UMEMOTO argv[0], argv[1]); 5010fe74aa4SHajimu UMEMOTO else { 5020fe74aa4SHajimu UMEMOTO addrs = 0; 5030fe74aa4SHajimu UMEMOTO 5040fe74aa4SHajimu UMEMOTO if (!strncasecmp(argv[0], "HISADDR6", 8)) 5050fe74aa4SHajimu UMEMOTO addrs = ROUTE_DSTHISADDR6; 5060fe74aa4SHajimu UMEMOTO else if (!strncasecmp(argv[0], "MYADDR6", 7)) 5070fe74aa4SHajimu UMEMOTO addrs = ROUTE_DSTMYADDR6; 5080fe74aa4SHajimu UMEMOTO 5090fe74aa4SHajimu UMEMOTO if (ncpaddr_getip6(&gw, &ip6) && IN6_IS_ADDR_UNSPECIFIED(&ip6)) { 5100fe74aa4SHajimu UMEMOTO addrs |= ROUTE_GWHISADDR6; 5110fe74aa4SHajimu UMEMOTO ncpaddr_copy(&gw, &bundle->ncp.ipv6cp.hisaddr); 5120fe74aa4SHajimu UMEMOTO } else if (strcasecmp(argv[1], "HISADDR6") == 0) 5130fe74aa4SHajimu UMEMOTO addrs |= ROUTE_GWHISADDR6; 5140fe74aa4SHajimu UMEMOTO 5150fe74aa4SHajimu UMEMOTO route_Add(&r->ipv6routes, addrs, &dest, &gw); 5160fe74aa4SHajimu UMEMOTO } 5170fe74aa4SHajimu UMEMOTO free(nuke); 5180fe74aa4SHajimu UMEMOTO break; 5190fe74aa4SHajimu UMEMOTO #endif 5200fe74aa4SHajimu UMEMOTO 521ff8e577bSBrian Somers case RAD_VENDOR_SPECIFIC: 522ff8e577bSBrian Somers if ((res = rad_get_vendor_attr(&vendor, &data, &len)) <= 0) { 523ff8e577bSBrian Somers log_Printf(LogERROR, "rad_get_vendor_attr: %s (failing!)\n", 524f0cdd9c0SBrian Somers rad_strerror(r->cx.rad)); 525f0cdd9c0SBrian Somers auth_Failure(r->cx.auth); 526f0cdd9c0SBrian Somers rad_close(r->cx.rad); 527ff8e577bSBrian Somers return; 528ff8e577bSBrian Somers } 529ff8e577bSBrian Somers 530ff8e577bSBrian Somers switch (vendor) { 531ff8e577bSBrian Somers case RAD_VENDOR_MICROSOFT: 532ff8e577bSBrian Somers switch (res) { 5338fb5ef5aSBrian Somers #ifndef NODES 534ff8e577bSBrian Somers case RAD_MICROSOFT_MS_CHAP_ERROR: 535ff8e577bSBrian Somers free(r->errstr); 536a95b23a6SBrian Somers if (len == 0) 537a95b23a6SBrian Somers r->errstr = NULL; 538a95b23a6SBrian Somers else { 53999cfc2e2SBrian Somers if (len < 3 || ((const char *)data)[1] != '=') { 54099cfc2e2SBrian Somers /* 54199cfc2e2SBrian Somers * Only point at the String field if we don't think the 54299cfc2e2SBrian Somers * peer has misformatted the response. 54399cfc2e2SBrian Somers */ 5441bb0b6deSAlexander Kabaev data = (const char *)data + 1; 54599cfc2e2SBrian Somers len--; 546579abfd8SBrian Somers } else 547579abfd8SBrian Somers log_Printf(LogWARN, "Warning: The MS-CHAP-Error " 548579abfd8SBrian Somers "attribute is mis-formatted. Compensating\n"); 54999cfc2e2SBrian Somers if ((r->errstr = rad_cvt_string((const char *)data, 55099cfc2e2SBrian Somers len)) == NULL) { 551ff8e577bSBrian Somers log_Printf(LogERROR, "rad_cvt_string: %s\n", 552ff8e577bSBrian Somers rad_strerror(r->cx.rad)); 553ff8e577bSBrian Somers auth_Failure(r->cx.auth); 554ff8e577bSBrian Somers rad_close(r->cx.rad); 555ff8e577bSBrian Somers return; 556ff8e577bSBrian Somers } 557e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 558e715b13bSBrian Somers " MS-CHAP-Error \"%s\"\n", r->errstr); 559a95b23a6SBrian Somers } 560ff8e577bSBrian Somers break; 561ff8e577bSBrian Somers 562a16061b2SBrian Somers case RAD_MICROSOFT_MS_CHAP2_SUCCESS: 563a16061b2SBrian Somers free(r->msrepstr); 564a95b23a6SBrian Somers if (len == 0) 565a95b23a6SBrian Somers r->msrepstr = NULL; 566a95b23a6SBrian Somers else { 56799cfc2e2SBrian Somers if (len < 3 || ((const char *)data)[1] != '=') { 56899cfc2e2SBrian Somers /* 56999cfc2e2SBrian Somers * Only point at the String field if we don't think the 57099cfc2e2SBrian Somers * peer has misformatted the response. 57199cfc2e2SBrian Somers */ 5721bb0b6deSAlexander Kabaev data = (const char *)data + 1; 57399cfc2e2SBrian Somers len--; 574579abfd8SBrian Somers } else 575579abfd8SBrian Somers log_Printf(LogWARN, "Warning: The MS-CHAP2-Success " 576579abfd8SBrian Somers "attribute is mis-formatted. Compensating\n"); 57799cfc2e2SBrian Somers if ((r->msrepstr = rad_cvt_string((const char *)data, 57899cfc2e2SBrian Somers len)) == NULL) { 579a16061b2SBrian Somers log_Printf(LogERROR, "rad_cvt_string: %s\n", 580a16061b2SBrian Somers rad_strerror(r->cx.rad)); 581a16061b2SBrian Somers auth_Failure(r->cx.auth); 582a16061b2SBrian Somers rad_close(r->cx.rad); 583a16061b2SBrian Somers return; 584a16061b2SBrian Somers } 585e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 586e715b13bSBrian Somers " MS-CHAP2-Success \"%s\"\n", r->msrepstr); 587a95b23a6SBrian Somers } 588a16061b2SBrian Somers break; 589a16061b2SBrian Somers 5908fb5ef5aSBrian Somers case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY: 5918fb5ef5aSBrian Somers r->mppe.policy = rad_cvt_int(data); 592e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 593e715b13bSBrian Somers " MS-MPPE-Encryption-Policy %s\n", 5948fb5ef5aSBrian Somers radius_policyname(r->mppe.policy)); 5958fb5ef5aSBrian Somers break; 5968fb5ef5aSBrian Somers 5978fb5ef5aSBrian Somers case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES: 5988fb5ef5aSBrian Somers r->mppe.types = rad_cvt_int(data); 599e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 600e715b13bSBrian Somers " MS-MPPE-Encryption-Types %s\n", 6018fb5ef5aSBrian Somers radius_typesname(r->mppe.types)); 6028fb5ef5aSBrian Somers break; 6038fb5ef5aSBrian Somers 6048fb5ef5aSBrian Somers case RAD_MICROSOFT_MS_MPPE_RECV_KEY: 6058fb5ef5aSBrian Somers free(r->mppe.recvkey); 6068fb5ef5aSBrian Somers demangle(r, data, len, &r->mppe.recvkey, &r->mppe.recvkeylen); 607e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 608e715b13bSBrian Somers " MS-MPPE-Recv-Key ********\n"); 6098fb5ef5aSBrian Somers break; 6108fb5ef5aSBrian Somers 6118fb5ef5aSBrian Somers case RAD_MICROSOFT_MS_MPPE_SEND_KEY: 6128fb5ef5aSBrian Somers demangle(r, data, len, &r->mppe.sendkey, &r->mppe.sendkeylen); 613e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 614e715b13bSBrian Somers " MS-MPPE-Send-Key ********\n"); 6158fb5ef5aSBrian Somers break; 6168fb5ef5aSBrian Somers #endif 6178fb5ef5aSBrian Somers 618ff8e577bSBrian Somers default: 619ff8e577bSBrian Somers log_Printf(LogDEBUG, "Dropping MICROSOFT vendor specific " 620ff8e577bSBrian Somers "RADIUS attribute %d\n", res); 621ff8e577bSBrian Somers break; 622ff8e577bSBrian Somers } 623ff8e577bSBrian Somers break; 624ff8e577bSBrian Somers 625ff8e577bSBrian Somers default: 626ff8e577bSBrian Somers log_Printf(LogDEBUG, "Dropping vendor %lu RADIUS attribute %d\n", 627ff8e577bSBrian Somers (unsigned long)vendor, res); 628ff8e577bSBrian Somers break; 629ff8e577bSBrian Somers } 630ff8e577bSBrian Somers break; 631ff8e577bSBrian Somers 632ff8e577bSBrian Somers default: 633ff8e577bSBrian Somers log_Printf(LogDEBUG, "Dropping RADIUS attribute %d\n", res); 634ff8e577bSBrian Somers break; 635ff8e577bSBrian Somers } 636ff8e577bSBrian Somers } 637ff8e577bSBrian Somers 638ff8e577bSBrian Somers if (res == -1) { 639ff8e577bSBrian Somers log_Printf(LogERROR, "rad_get_attr: %s (failing!)\n", 640ff8e577bSBrian Somers rad_strerror(r->cx.rad)); 641ff8e577bSBrian Somers auth_Failure(r->cx.auth); 642ff8e577bSBrian Somers } else if (got == RAD_ACCESS_REJECT) 643ff8e577bSBrian Somers auth_Failure(r->cx.auth); 644ff8e577bSBrian Somers else { 645f0cdd9c0SBrian Somers r->valid = 1; 646f0cdd9c0SBrian Somers auth_Success(r->cx.auth); 647f0cdd9c0SBrian Somers } 648ff8e577bSBrian Somers rad_close(r->cx.rad); 649972a1bcfSBrian Somers } 650972a1bcfSBrian Somers 651f0cdd9c0SBrian Somers /* 6528e7bd08eSBrian Somers * We've either timed out or select()ed on the read descriptor 653f0cdd9c0SBrian Somers */ 654f0cdd9c0SBrian Somers static void 655f0cdd9c0SBrian Somers radius_Continue(struct radius *r, int sel) 656f0cdd9c0SBrian Somers { 657f0cdd9c0SBrian Somers struct timeval tv; 658f0cdd9c0SBrian Somers int got; 659972a1bcfSBrian Somers 660f0cdd9c0SBrian Somers timer_Stop(&r->cx.timer); 661f0cdd9c0SBrian Somers if ((got = rad_continue_send_request(r->cx.rad, sel, &r->cx.fd, &tv)) == 0) { 662e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 663e715b13bSBrian Somers "Radius: Request re-sent\n"); 664f0cdd9c0SBrian Somers r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS; 665f0cdd9c0SBrian Somers timer_Start(&r->cx.timer); 666f0cdd9c0SBrian Somers return; 667f0cdd9c0SBrian Somers } 668f0cdd9c0SBrian Somers 669f0cdd9c0SBrian Somers radius_Process(r, got); 670f0cdd9c0SBrian Somers } 671f0cdd9c0SBrian Somers 672f0cdd9c0SBrian Somers /* 673f0cdd9c0SBrian Somers * Time to call rad_continue_send_request() - timed out. 674f0cdd9c0SBrian Somers */ 675f0cdd9c0SBrian Somers static void 676f0cdd9c0SBrian Somers radius_Timeout(void *v) 677f0cdd9c0SBrian Somers { 678f0cdd9c0SBrian Somers radius_Continue((struct radius *)v, 0); 679f0cdd9c0SBrian Somers } 680f0cdd9c0SBrian Somers 681f0cdd9c0SBrian Somers /* 682f0cdd9c0SBrian Somers * Time to call rad_continue_send_request() - something to read. 683f0cdd9c0SBrian Somers */ 684f0cdd9c0SBrian Somers static void 685057f1760SBrian Somers radius_Read(struct fdescriptor *d, struct bundle *bundle __unused, 686057f1760SBrian Somers const fd_set *fdset __unused) 687f0cdd9c0SBrian Somers { 688f0cdd9c0SBrian Somers radius_Continue(descriptor2radius(d), 1); 689f0cdd9c0SBrian Somers } 690f0cdd9c0SBrian Somers 691f0cdd9c0SBrian Somers /* 69288044778SBrian Somers * Flush any pending transactions 69388044778SBrian Somers */ 69488044778SBrian Somers void 69588044778SBrian Somers radius_Flush(struct radius *r) 69688044778SBrian Somers { 69788044778SBrian Somers struct timeval tv; 69888044778SBrian Somers fd_set s; 69988044778SBrian Somers 70088044778SBrian Somers while (r->cx.fd != -1) { 70188044778SBrian Somers FD_ZERO(&s); 70288044778SBrian Somers FD_SET(r->cx.fd, &s); 70388044778SBrian Somers tv.tv_sec = 0; 70488044778SBrian Somers tv.tv_usec = TICKUNIT; 70588044778SBrian Somers select(r->cx.fd + 1, &s, NULL, NULL, &tv); 70688044778SBrian Somers radius_Continue(r, 1); 70788044778SBrian Somers } 70888044778SBrian Somers } 70988044778SBrian Somers 71088044778SBrian Somers /* 7118e7bd08eSBrian Somers * Behave as a struct fdescriptor (descriptor.h) 712f0cdd9c0SBrian Somers */ 713f0cdd9c0SBrian Somers static int 714057f1760SBrian Somers radius_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w __unused, 715057f1760SBrian Somers fd_set *e __unused, int *n) 716f0cdd9c0SBrian Somers { 717f0cdd9c0SBrian Somers struct radius *rad = descriptor2radius(d); 718f0cdd9c0SBrian Somers 719f0cdd9c0SBrian Somers if (r && rad->cx.fd != -1) { 720f0cdd9c0SBrian Somers FD_SET(rad->cx.fd, r); 721f0cdd9c0SBrian Somers if (*n < rad->cx.fd + 1) 722f0cdd9c0SBrian Somers *n = rad->cx.fd + 1; 723f0cdd9c0SBrian Somers log_Printf(LogTIMER, "Radius: fdset(r) %d\n", rad->cx.fd); 72482d6780cSBrian Somers return 1; 725972a1bcfSBrian Somers } 726972a1bcfSBrian Somers 727f0cdd9c0SBrian Somers return 0; 728f0cdd9c0SBrian Somers } 729f0cdd9c0SBrian Somers 730f0cdd9c0SBrian Somers /* 7318e7bd08eSBrian Somers * Behave as a struct fdescriptor (descriptor.h) 732f0cdd9c0SBrian Somers */ 733f0cdd9c0SBrian Somers static int 734f013f33eSBrian Somers radius_IsSet(struct fdescriptor *d, const fd_set *fdset) 735f0cdd9c0SBrian Somers { 736f0cdd9c0SBrian Somers struct radius *r = descriptor2radius(d); 737f0cdd9c0SBrian Somers 738f0cdd9c0SBrian Somers return r && r->cx.fd != -1 && FD_ISSET(r->cx.fd, fdset); 739f0cdd9c0SBrian Somers } 740f0cdd9c0SBrian Somers 741f0cdd9c0SBrian Somers /* 7428e7bd08eSBrian Somers * Behave as a struct fdescriptor (descriptor.h) 743f0cdd9c0SBrian Somers */ 744f0cdd9c0SBrian Somers static int 745057f1760SBrian Somers radius_Write(struct fdescriptor *d __unused, struct bundle *bundle __unused, 746057f1760SBrian Somers const fd_set *fdset __unused) 747f0cdd9c0SBrian Somers { 748f0cdd9c0SBrian Somers /* We never want to write here ! */ 749f0cdd9c0SBrian Somers log_Printf(LogALERT, "radius_Write: Internal error: Bad call !\n"); 750f0cdd9c0SBrian Somers return 0; 751f0cdd9c0SBrian Somers } 752f0cdd9c0SBrian Somers 753f0cdd9c0SBrian Somers /* 754f0cdd9c0SBrian Somers * Initialise ourselves 755f0cdd9c0SBrian Somers */ 756f0cdd9c0SBrian Somers void 757f0cdd9c0SBrian Somers radius_Init(struct radius *r) 758f0cdd9c0SBrian Somers { 759f0cdd9c0SBrian Somers r->desc.type = RADIUS_DESCRIPTOR; 760f0cdd9c0SBrian Somers r->desc.UpdateSet = radius_UpdateSet; 761f0cdd9c0SBrian Somers r->desc.IsSet = radius_IsSet; 762f0cdd9c0SBrian Somers r->desc.Read = radius_Read; 763f0cdd9c0SBrian Somers r->desc.Write = radius_Write; 764ff8e577bSBrian Somers r->cx.fd = -1; 765ff8e577bSBrian Somers r->cx.rad = NULL; 766f0cdd9c0SBrian Somers memset(&r->cx.timer, '\0', sizeof r->cx.timer); 767ff8e577bSBrian Somers r->cx.auth = NULL; 768ff8e577bSBrian Somers r->valid = 0; 769ff8e577bSBrian Somers r->vj = 0; 770ff8e577bSBrian Somers r->ip.s_addr = INADDR_ANY; 771ff8e577bSBrian Somers r->mask.s_addr = INADDR_NONE; 772ff8e577bSBrian Somers r->routes = NULL; 773ff8e577bSBrian Somers r->mtu = DEF_MTU; 774a16061b2SBrian Somers r->msrepstr = NULL; 775ff8e577bSBrian Somers r->repstr = NULL; 7760fe74aa4SHajimu UMEMOTO #ifndef NOINET6 777ec3e98b8SHajimu UMEMOTO r->ipv6prefix = NULL; 7780fe74aa4SHajimu UMEMOTO r->ipv6routes = NULL; 7790fe74aa4SHajimu UMEMOTO #endif 780ff8e577bSBrian Somers r->errstr = NULL; 7818fb5ef5aSBrian Somers r->mppe.policy = 0; 7828fb5ef5aSBrian Somers r->mppe.types = 0; 7838fb5ef5aSBrian Somers r->mppe.recvkey = NULL; 7848fb5ef5aSBrian Somers r->mppe.recvkeylen = 0; 7858fb5ef5aSBrian Somers r->mppe.sendkey = NULL; 7868fb5ef5aSBrian Somers r->mppe.sendkeylen = 0; 787ff8e577bSBrian Somers *r->cfg.file = '\0';; 788794c9bbcSBrian Somers log_Printf(LogDEBUG, "Radius: radius_Init\n"); 789f0cdd9c0SBrian Somers } 790f0cdd9c0SBrian Somers 791f0cdd9c0SBrian Somers /* 792f0cdd9c0SBrian Somers * Forget everything and go back to initialised state. 793f0cdd9c0SBrian Somers */ 794f0cdd9c0SBrian Somers void 795f0cdd9c0SBrian Somers radius_Destroy(struct radius *r) 796f0cdd9c0SBrian Somers { 797f0cdd9c0SBrian Somers r->valid = 0; 798794c9bbcSBrian Somers log_Printf(LogDEBUG, "Radius: radius_Destroy\n"); 799f0cdd9c0SBrian Somers timer_Stop(&r->cx.timer); 800f0cdd9c0SBrian Somers route_DeleteAll(&r->routes); 8010fe74aa4SHajimu UMEMOTO #ifndef NOINET6 8020fe74aa4SHajimu UMEMOTO route_DeleteAll(&r->ipv6routes); 8030fe74aa4SHajimu UMEMOTO #endif 804bf1eaec5SBrian Somers free(r->filterid); 805bf1eaec5SBrian Somers r->filterid = NULL; 806a16061b2SBrian Somers free(r->msrepstr); 807a16061b2SBrian Somers r->msrepstr = NULL; 808ff8e577bSBrian Somers free(r->repstr); 809ff8e577bSBrian Somers r->repstr = NULL; 810ec3e98b8SHajimu UMEMOTO #ifndef NOINET6 811ec3e98b8SHajimu UMEMOTO free(r->ipv6prefix); 812ec3e98b8SHajimu UMEMOTO r->ipv6prefix = NULL; 813ec3e98b8SHajimu UMEMOTO #endif 814ff8e577bSBrian Somers free(r->errstr); 815ff8e577bSBrian Somers r->errstr = NULL; 8168fb5ef5aSBrian Somers free(r->mppe.recvkey); 8178fb5ef5aSBrian Somers r->mppe.recvkey = NULL; 8188fb5ef5aSBrian Somers r->mppe.recvkeylen = 0; 8198fb5ef5aSBrian Somers free(r->mppe.sendkey); 8208fb5ef5aSBrian Somers r->mppe.sendkey = NULL; 8218fb5ef5aSBrian Somers r->mppe.sendkeylen = 0; 822f0cdd9c0SBrian Somers if (r->cx.fd != -1) { 823f0cdd9c0SBrian Somers r->cx.fd = -1; 824f0cdd9c0SBrian Somers rad_close(r->cx.rad); 825f0cdd9c0SBrian Somers } 826f0cdd9c0SBrian Somers } 827f0cdd9c0SBrian Somers 828de59e178SBrian Somers static int 829d4d4a70aSRoman Bogorodskiy radius_put_physical_details(struct radius *rad, struct physical *p) 830de59e178SBrian Somers { 831de59e178SBrian Somers int slot, type; 832de59e178SBrian Somers 833de59e178SBrian Somers type = RAD_VIRTUAL; 834de59e178SBrian Somers if (p->handler) 835de59e178SBrian Somers switch (p->handler->type) { 836de59e178SBrian Somers case I4B_DEVICE: 837de59e178SBrian Somers type = RAD_ISDN_SYNC; 838de59e178SBrian Somers break; 839de59e178SBrian Somers 840de59e178SBrian Somers case TTY_DEVICE: 841de59e178SBrian Somers type = RAD_ASYNC; 842de59e178SBrian Somers break; 843de59e178SBrian Somers 844de59e178SBrian Somers case ETHER_DEVICE: 845de59e178SBrian Somers type = RAD_ETHERNET; 846de59e178SBrian Somers break; 847de59e178SBrian Somers 848de59e178SBrian Somers case TCP_DEVICE: 849de59e178SBrian Somers case UDP_DEVICE: 850de59e178SBrian Somers case EXEC_DEVICE: 851de59e178SBrian Somers case ATM_DEVICE: 852de59e178SBrian Somers case NG_DEVICE: 853de59e178SBrian Somers type = RAD_VIRTUAL; 854de59e178SBrian Somers break; 855de59e178SBrian Somers } 856de59e178SBrian Somers 857d4d4a70aSRoman Bogorodskiy if (rad_put_int(rad->cx.rad, RAD_NAS_PORT_TYPE, type) != 0) { 858d4d4a70aSRoman Bogorodskiy log_Printf(LogERROR, "rad_put: rad_put_int: %s\n", rad_strerror(rad->cx.rad)); 859d4d4a70aSRoman Bogorodskiy rad_close(rad->cx.rad); 860de59e178SBrian Somers return 0; 861de59e178SBrian Somers } 862de59e178SBrian Somers 863d4d4a70aSRoman Bogorodskiy switch (rad->port_id_type) { 864d4d4a70aSRoman Bogorodskiy case RPI_PID: 865d4d4a70aSRoman Bogorodskiy slot = (int)getpid(); 866d4d4a70aSRoman Bogorodskiy break; 867d4d4a70aSRoman Bogorodskiy case RPI_IFNUM: 868d4d4a70aSRoman Bogorodskiy slot = p->dl->bundle->iface->index; 869d4d4a70aSRoman Bogorodskiy break; 870d4d4a70aSRoman Bogorodskiy case RPI_TUNNUM: 871d4d4a70aSRoman Bogorodskiy slot = p->dl->bundle->unit; 872d4d4a70aSRoman Bogorodskiy break; 873d4d4a70aSRoman Bogorodskiy case RPI_DEFAULT: 874d4d4a70aSRoman Bogorodskiy default: 875d4d4a70aSRoman Bogorodskiy slot = physical_Slot(p); 876d4d4a70aSRoman Bogorodskiy break; 877d4d4a70aSRoman Bogorodskiy } 878d4d4a70aSRoman Bogorodskiy 879d4d4a70aSRoman Bogorodskiy if (slot >= 0) 880d4d4a70aSRoman Bogorodskiy if (rad_put_int(rad->cx.rad, RAD_NAS_PORT, slot) != 0) { 881d4d4a70aSRoman Bogorodskiy log_Printf(LogERROR, "rad_put: rad_put_int: %s\n", rad_strerror(rad->cx.rad)); 882d4d4a70aSRoman Bogorodskiy rad_close(rad->cx.rad); 883de59e178SBrian Somers return 0; 884de59e178SBrian Somers } 885de59e178SBrian Somers 886de59e178SBrian Somers return 1; 887de59e178SBrian Somers } 888de59e178SBrian Somers 889f0cdd9c0SBrian Somers /* 890f0cdd9c0SBrian Somers * Start an authentication request to the RADIUS server. 891f0cdd9c0SBrian Somers */ 892a16061b2SBrian Somers int 893f0cdd9c0SBrian Somers radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name, 894a16061b2SBrian Somers const char *key, int klen, const char *nchallenge, 895250be50bSBrian Somers int nclen) 896f0cdd9c0SBrian Somers { 89726e6a622SBrian Somers char hostname[MAXHOSTNAMELEN]; 898057f1760SBrian Somers struct timeval tv; 899057f1760SBrian Somers const char *what = "questionable"; /* silence warnings! */ 900057f1760SBrian Somers char *mac_addr; 901057f1760SBrian Somers int got; 902f10f5203SBrian Somers struct hostent *hp; 903f10f5203SBrian Somers struct in_addr hostaddr; 904ff8e577bSBrian Somers #ifndef NODES 905a16061b2SBrian Somers struct mschap_response msresp; 906a16061b2SBrian Somers struct mschap2_response msresp2; 907250be50bSBrian Somers const struct MSCHAPv2_resp *keyv2; 908ff8e577bSBrian Somers #endif 909f0cdd9c0SBrian Somers 910f0cdd9c0SBrian Somers if (!*r->cfg.file) 911a16061b2SBrian Somers return 0; 912f0cdd9c0SBrian Somers 913f0cdd9c0SBrian Somers if (r->cx.fd != -1) 914f0cdd9c0SBrian Somers /* 915f0cdd9c0SBrian Somers * We assume that our name/key/challenge is the same as last time, 916f0cdd9c0SBrian Somers * and just continue to wait for the RADIUS server(s). 917f0cdd9c0SBrian Somers */ 918a16061b2SBrian Somers return 1; 919f0cdd9c0SBrian Somers 920f0cdd9c0SBrian Somers radius_Destroy(r); 921f0cdd9c0SBrian Somers 922794c9bbcSBrian Somers if ((r->cx.rad = rad_auth_open()) == NULL) { 923794c9bbcSBrian Somers log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno)); 924a16061b2SBrian Somers return 0; 925f0cdd9c0SBrian Somers } 926f0cdd9c0SBrian Somers 927f0cdd9c0SBrian Somers if (rad_config(r->cx.rad, r->cfg.file) != 0) { 928f0cdd9c0SBrian Somers log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad)); 929f0cdd9c0SBrian Somers rad_close(r->cx.rad); 930a16061b2SBrian Somers return 0; 931f0cdd9c0SBrian Somers } 932f0cdd9c0SBrian Somers 933f0cdd9c0SBrian Somers if (rad_create_request(r->cx.rad, RAD_ACCESS_REQUEST) != 0) { 934f0cdd9c0SBrian Somers log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad)); 935f0cdd9c0SBrian Somers rad_close(r->cx.rad); 936a16061b2SBrian Somers return 0; 937f0cdd9c0SBrian Somers } 938f0cdd9c0SBrian Somers 9394dc4e1eeSBrian Somers if (rad_put_string(r->cx.rad, RAD_USER_NAME, name) != 0 || 940f0cdd9c0SBrian Somers rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 || 941f0cdd9c0SBrian Somers rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) { 942f0cdd9c0SBrian Somers log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 943f0cdd9c0SBrian Somers rad_close(r->cx.rad); 944a16061b2SBrian Somers return 0; 945f0cdd9c0SBrian Somers } 946f0cdd9c0SBrian Somers 947ff8e577bSBrian Somers switch (authp->physical->link.lcp.want_auth) { 948ff8e577bSBrian Somers case PROTO_PAP: 949ff8e577bSBrian Somers /* We're talking PAP */ 950ff8e577bSBrian Somers if (rad_put_attr(r->cx.rad, RAD_USER_PASSWORD, key, klen) != 0) { 951ff8e577bSBrian Somers log_Printf(LogERROR, "PAP: rad_put_string: %s\n", 952ff8e577bSBrian Somers rad_strerror(r->cx.rad)); 953ff8e577bSBrian Somers rad_close(r->cx.rad); 954a16061b2SBrian Somers return 0; 955ff8e577bSBrian Somers } 956e715b13bSBrian Somers what = "PAP"; 957ff8e577bSBrian Somers break; 958ff8e577bSBrian Somers 959ff8e577bSBrian Somers case PROTO_CHAP: 960ff8e577bSBrian Somers switch (authp->physical->link.lcp.want_authtype) { 961ff8e577bSBrian Somers case 0x5: 96250ca6ec3SBrian Somers if (rad_put_attr(r->cx.rad, RAD_CHAP_PASSWORD, key, klen) != 0 || 963a16061b2SBrian Somers rad_put_attr(r->cx.rad, RAD_CHAP_CHALLENGE, nchallenge, nclen) != 0) { 964f0cdd9c0SBrian Somers log_Printf(LogERROR, "CHAP: rad_put_string: %s\n", 965f0cdd9c0SBrian Somers rad_strerror(r->cx.rad)); 966f0cdd9c0SBrian Somers rad_close(r->cx.rad); 967a16061b2SBrian Somers return 0; 968f0cdd9c0SBrian Somers } 969e715b13bSBrian Somers what = "CHAP"; 970ff8e577bSBrian Somers break; 971ff8e577bSBrian Somers 972ff8e577bSBrian Somers #ifndef NODES 973ff8e577bSBrian Somers case 0x80: 974ff8e577bSBrian Somers if (klen != 50) { 975a16061b2SBrian Somers log_Printf(LogERROR, "CHAP80: Unrecognised key length %d\n", klen); 976f0cdd9c0SBrian Somers rad_close(r->cx.rad); 977a16061b2SBrian Somers return 0; 978f0cdd9c0SBrian Somers } 979a16061b2SBrian Somers 980ff8e577bSBrian Somers rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT, 981a16061b2SBrian Somers RAD_MICROSOFT_MS_CHAP_CHALLENGE, nchallenge, nclen); 982a16061b2SBrian Somers msresp.ident = *key; 983a16061b2SBrian Somers msresp.flags = 0x01; 984a16061b2SBrian Somers memcpy(msresp.lm_response, key + 1, 24); 985a16061b2SBrian Somers memcpy(msresp.nt_response, key + 25, 24); 986ff8e577bSBrian Somers rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT, 987a16061b2SBrian Somers RAD_MICROSOFT_MS_CHAP_RESPONSE, &msresp, 988a16061b2SBrian Somers sizeof msresp); 989e715b13bSBrian Somers what = "MSCHAP"; 990ff8e577bSBrian Somers break; 991ff8e577bSBrian Somers 992ff8e577bSBrian Somers case 0x81: 993250be50bSBrian Somers if (klen != sizeof(*keyv2) + 1) { 994a16061b2SBrian Somers log_Printf(LogERROR, "CHAP81: Unrecognised key length %d\n", klen); 995a16061b2SBrian Somers rad_close(r->cx.rad); 996a16061b2SBrian Somers return 0; 997a16061b2SBrian Somers } 998a16061b2SBrian Somers 999250be50bSBrian Somers keyv2 = (const struct MSCHAPv2_resp *)(key + 1); 1000a16061b2SBrian Somers rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT, 1001a16061b2SBrian Somers RAD_MICROSOFT_MS_CHAP_CHALLENGE, nchallenge, nclen); 1002a16061b2SBrian Somers msresp2.ident = *key; 1003250be50bSBrian Somers msresp2.flags = keyv2->Flags; 1004250be50bSBrian Somers memcpy(msresp2.response, keyv2->NTResponse, sizeof msresp2.response); 1005a16061b2SBrian Somers memset(msresp2.reserved, '\0', sizeof msresp2.reserved); 1006250be50bSBrian Somers memcpy(msresp2.pchallenge, keyv2->PeerChallenge, 1007250be50bSBrian Somers sizeof msresp2.pchallenge); 1008a16061b2SBrian Somers rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT, 1009a16061b2SBrian Somers RAD_MICROSOFT_MS_CHAP2_RESPONSE, &msresp2, 1010a16061b2SBrian Somers sizeof msresp2); 1011e715b13bSBrian Somers what = "MSCHAPv2"; 1012a16061b2SBrian Somers break; 1013ff8e577bSBrian Somers #endif 1014ff8e577bSBrian Somers default: 1015ff8e577bSBrian Somers log_Printf(LogERROR, "CHAP: Unrecognised type 0x%02x\n", 1016ff8e577bSBrian Somers authp->physical->link.lcp.want_authtype); 1017ff8e577bSBrian Somers rad_close(r->cx.rad); 1018a16061b2SBrian Somers return 0; 1019ff8e577bSBrian Somers } 1020ff8e577bSBrian Somers } 1021f0cdd9c0SBrian Somers 1022f10f5203SBrian Somers if (gethostname(hostname, sizeof hostname) != 0) 1023f10f5203SBrian Somers log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno)); 1024f10f5203SBrian Somers else { 10250508c09aSBrian Somers if (Enabled(authp->physical->dl->bundle, OPT_NAS_IP_ADDRESS) && 10260508c09aSBrian Somers (hp = gethostbyname(hostname)) != NULL) { 1027f10f5203SBrian Somers hostaddr.s_addr = *(u_long *)hp->h_addr; 1028f10f5203SBrian Somers if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) { 1029f10f5203SBrian Somers log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 1030f10f5203SBrian Somers rad_strerror(r->cx.rad)); 1031f10f5203SBrian Somers rad_close(r->cx.rad); 1032a16061b2SBrian Somers return 0; 1033f10f5203SBrian Somers } 1034f10f5203SBrian Somers } 10350508c09aSBrian Somers if (Enabled(authp->physical->dl->bundle, OPT_NAS_IDENTIFIER) && 10360508c09aSBrian Somers rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) { 1037f10f5203SBrian Somers log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 1038f10f5203SBrian Somers rad_strerror(r->cx.rad)); 1039f10f5203SBrian Somers rad_close(r->cx.rad); 1040a16061b2SBrian Somers return 0; 1041f10f5203SBrian Somers } 1042f10f5203SBrian Somers } 1043f10f5203SBrian Somers 10445de776b9SBrian Somers if ((mac_addr = getenv("HISMACADDR")) != NULL && 10455de776b9SBrian Somers rad_put_string(r->cx.rad, RAD_CALLING_STATION_ID, mac_addr) != 0) { 10465de776b9SBrian Somers log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 10475de776b9SBrian Somers rad_close(r->cx.rad); 1048057f1760SBrian Somers return 0; 10495de776b9SBrian Somers } 10505de776b9SBrian Somers 1051d4d4a70aSRoman Bogorodskiy radius_put_physical_details(r, authp->physical); 1052f10f5203SBrian Somers 1053e715b13bSBrian Somers log_Printf(LogRADIUS, "Radius(auth): %s data sent for %s\n", what, name); 1054e715b13bSBrian Somers 1055c42627ffSBrian Somers r->cx.auth = authp; 1056f0cdd9c0SBrian Somers if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv))) 1057f0cdd9c0SBrian Somers radius_Process(r, got); 1058f0cdd9c0SBrian Somers else { 1059e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 1060e715b13bSBrian Somers "Radius: Request sent\n"); 1061f0cdd9c0SBrian Somers log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout); 1062f0cdd9c0SBrian Somers r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS; 1063f0cdd9c0SBrian Somers r->cx.timer.func = radius_Timeout; 1064c42627ffSBrian Somers r->cx.timer.name = "radius auth"; 1065f0cdd9c0SBrian Somers r->cx.timer.arg = r; 1066f0cdd9c0SBrian Somers timer_Start(&r->cx.timer); 1067f0cdd9c0SBrian Somers } 1068a16061b2SBrian Somers 1069a16061b2SBrian Somers return 1; 1070f0cdd9c0SBrian Somers } 1071f0cdd9c0SBrian Somers 1072cf7c10d0SHajimu UMEMOTO /* Fetch IP, netmask from IPCP */ 1073cf7c10d0SHajimu UMEMOTO void 1074cf7c10d0SHajimu UMEMOTO radius_Account_Set_Ip(struct radacct *ac, struct in_addr *peer_ip, 1075cf7c10d0SHajimu UMEMOTO struct in_addr *netmask) 1076cf7c10d0SHajimu UMEMOTO { 1077cf7c10d0SHajimu UMEMOTO ac->proto = PROTO_IPCP; 10782cc2a59dSHajimu UMEMOTO memcpy(&ac->peer.ip.addr, peer_ip, sizeof(ac->peer.ip.addr)); 10792cc2a59dSHajimu UMEMOTO memcpy(&ac->peer.ip.mask, netmask, sizeof(ac->peer.ip.mask)); 1080cf7c10d0SHajimu UMEMOTO } 1081cf7c10d0SHajimu UMEMOTO 1082cf7c10d0SHajimu UMEMOTO #ifndef NOINET6 1083cf7c10d0SHajimu UMEMOTO /* Fetch interface-id from IPV6CP */ 1084cf7c10d0SHajimu UMEMOTO void 1085cf7c10d0SHajimu UMEMOTO radius_Account_Set_Ipv6(struct radacct *ac, u_char *ifid) 1086cf7c10d0SHajimu UMEMOTO { 1087cf7c10d0SHajimu UMEMOTO ac->proto = PROTO_IPV6CP; 10882cc2a59dSHajimu UMEMOTO memcpy(&ac->peer.ipv6.ifid, ifid, sizeof(ac->peer.ipv6.ifid)); 1089cf7c10d0SHajimu UMEMOTO } 1090cf7c10d0SHajimu UMEMOTO #endif 1091cf7c10d0SHajimu UMEMOTO 1092f0cdd9c0SBrian Somers /* 1093794c9bbcSBrian Somers * Send an accounting request to the RADIUS server 1094794c9bbcSBrian Somers */ 1095794c9bbcSBrian Somers void 1096794c9bbcSBrian Somers radius_Account(struct radius *r, struct radacct *ac, struct datalink *dl, 1097cf7c10d0SHajimu UMEMOTO int acct_type, struct pppThroughput *stats) 1098794c9bbcSBrian Somers { 1099794c9bbcSBrian Somers struct timeval tv; 1100de59e178SBrian Somers int got; 110126e6a622SBrian Somers char hostname[MAXHOSTNAMELEN]; 11025de776b9SBrian Somers char *mac_addr; 1103794c9bbcSBrian Somers struct hostent *hp; 1104794c9bbcSBrian Somers struct in_addr hostaddr; 1105794c9bbcSBrian Somers 1106794c9bbcSBrian Somers if (!*r->cfg.file) 1107794c9bbcSBrian Somers return; 1108794c9bbcSBrian Somers 1109794c9bbcSBrian Somers if (r->cx.fd != -1) 1110794c9bbcSBrian Somers /* 1111794c9bbcSBrian Somers * We assume that our name/key/challenge is the same as last time, 1112794c9bbcSBrian Somers * and just continue to wait for the RADIUS server(s). 1113794c9bbcSBrian Somers */ 1114794c9bbcSBrian Somers return; 1115794c9bbcSBrian Somers 11168fb5ef5aSBrian Somers timer_Stop(&r->cx.timer); 1117794c9bbcSBrian Somers 1118ba093e81SBrian Somers if ((r->cx.rad = rad_acct_open()) == NULL) { 1119794c9bbcSBrian Somers log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno)); 1120794c9bbcSBrian Somers return; 1121794c9bbcSBrian Somers } 1122794c9bbcSBrian Somers 1123794c9bbcSBrian Somers if (rad_config(r->cx.rad, r->cfg.file) != 0) { 1124794c9bbcSBrian Somers log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad)); 1125794c9bbcSBrian Somers rad_close(r->cx.rad); 1126794c9bbcSBrian Somers return; 1127794c9bbcSBrian Somers } 1128794c9bbcSBrian Somers 1129794c9bbcSBrian Somers if (rad_create_request(r->cx.rad, RAD_ACCOUNTING_REQUEST) != 0) { 1130794c9bbcSBrian Somers log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad)); 1131794c9bbcSBrian Somers rad_close(r->cx.rad); 1132794c9bbcSBrian Somers return; 1133794c9bbcSBrian Somers } 1134794c9bbcSBrian Somers 1135794c9bbcSBrian Somers /* Grab some accounting data and initialize structure */ 1136794c9bbcSBrian Somers if (acct_type == RAD_START) { 1137794c9bbcSBrian Somers ac->rad_parent = r; 1138794c9bbcSBrian Somers /* Fetch username from datalink */ 11394dc4e1eeSBrian Somers strncpy(ac->user_name, dl->peer.authname, sizeof ac->user_name); 1140794c9bbcSBrian Somers ac->user_name[AUTHLEN-1] = '\0'; 1141794c9bbcSBrian Somers 1142794c9bbcSBrian Somers ac->authentic = 2; /* Assume RADIUS verified auth data */ 1143794c9bbcSBrian Somers 1144794c9bbcSBrian Somers /* Generate a session ID */ 114512b5aabaSBrian Somers snprintf(ac->session_id, sizeof ac->session_id, "%s%ld-%s%lu", 114612b5aabaSBrian Somers dl->bundle->cfg.auth.name, (long)getpid(), 11474dc4e1eeSBrian Somers dl->peer.authname, (unsigned long)stats->uptime); 1148794c9bbcSBrian Somers 1149794c9bbcSBrian Somers /* And grab our MP socket name */ 1150794c9bbcSBrian Somers snprintf(ac->multi_session_id, sizeof ac->multi_session_id, "%s", 1151794c9bbcSBrian Somers dl->bundle->ncp.mp.active ? 1152794c9bbcSBrian Somers dl->bundle->ncp.mp.server.socket.sun_path : ""); 1153794c9bbcSBrian Somers }; 1154794c9bbcSBrian Somers 1155794c9bbcSBrian Somers if (rad_put_string(r->cx.rad, RAD_USER_NAME, ac->user_name) != 0 || 1156794c9bbcSBrian Somers rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 || 1157cf7c10d0SHajimu UMEMOTO rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) { 1158794c9bbcSBrian Somers log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 1159794c9bbcSBrian Somers rad_close(r->cx.rad); 1160794c9bbcSBrian Somers return; 1161794c9bbcSBrian Somers } 1162cf7c10d0SHajimu UMEMOTO switch (ac->proto) { 1163cf7c10d0SHajimu UMEMOTO case PROTO_IPCP: 11642cc2a59dSHajimu UMEMOTO if (rad_put_addr(r->cx.rad, RAD_FRAMED_IP_ADDRESS, 11657cbe2606SBrian Somers ac->peer.ip.addr) != 0 || 11662cc2a59dSHajimu UMEMOTO rad_put_addr(r->cx.rad, RAD_FRAMED_IP_NETMASK, 11672cc2a59dSHajimu UMEMOTO ac->peer.ip.mask) != 0) { 1168cf7c10d0SHajimu UMEMOTO log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 1169cf7c10d0SHajimu UMEMOTO rad_close(r->cx.rad); 1170cf7c10d0SHajimu UMEMOTO return; 1171cf7c10d0SHajimu UMEMOTO } 1172cf7c10d0SHajimu UMEMOTO break; 1173cf7c10d0SHajimu UMEMOTO #ifndef NOINET6 1174cf7c10d0SHajimu UMEMOTO case PROTO_IPV6CP: 11752cc2a59dSHajimu UMEMOTO if (rad_put_attr(r->cx.rad, RAD_FRAMED_INTERFACE_ID, ac->peer.ipv6.ifid, 11762cc2a59dSHajimu UMEMOTO sizeof(ac->peer.ipv6.ifid)) != 0) { 1177cf7c10d0SHajimu UMEMOTO log_Printf(LogERROR, "rad_put_attr: %s\n", rad_strerror(r->cx.rad)); 1178cf7c10d0SHajimu UMEMOTO rad_close(r->cx.rad); 1179cf7c10d0SHajimu UMEMOTO return; 1180cf7c10d0SHajimu UMEMOTO } 1181ec3e98b8SHajimu UMEMOTO if (r->ipv6prefix) { 1182ec3e98b8SHajimu UMEMOTO /* 1183ec3e98b8SHajimu UMEMOTO * Since PPP doesn't delegate an IPv6 prefix to a peer, 1184ec3e98b8SHajimu UMEMOTO * Framed-IPv6-Prefix may be not used, actually. 1185ec3e98b8SHajimu UMEMOTO */ 1186ec3e98b8SHajimu UMEMOTO if (rad_put_attr(r->cx.rad, RAD_FRAMED_IPV6_PREFIX, r->ipv6prefix, 1187ec3e98b8SHajimu UMEMOTO sizeof(struct in6_addr) + 2) != 0) { 1188ec3e98b8SHajimu UMEMOTO log_Printf(LogERROR, "rad_put_attr: %s\n", rad_strerror(r->cx.rad)); 1189ec3e98b8SHajimu UMEMOTO rad_close(r->cx.rad); 1190ec3e98b8SHajimu UMEMOTO return; 1191ec3e98b8SHajimu UMEMOTO } 1192ec3e98b8SHajimu UMEMOTO } 1193cf7c10d0SHajimu UMEMOTO break; 1194cf7c10d0SHajimu UMEMOTO #endif 1195cf7c10d0SHajimu UMEMOTO default: 1196cf7c10d0SHajimu UMEMOTO /* We don't log any protocol specific information */ 1197cf7c10d0SHajimu UMEMOTO break; 1198cf7c10d0SHajimu UMEMOTO } 1199794c9bbcSBrian Somers 12005de776b9SBrian Somers if ((mac_addr = getenv("HISMACADDR")) != NULL && 12015de776b9SBrian Somers rad_put_string(r->cx.rad, RAD_CALLING_STATION_ID, mac_addr) != 0) { 12025de776b9SBrian Somers log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 12035de776b9SBrian Somers rad_close(r->cx.rad); 12045de776b9SBrian Somers return; 12055de776b9SBrian Somers } 12065de776b9SBrian Somers 1207794c9bbcSBrian Somers if (gethostname(hostname, sizeof hostname) != 0) 1208794c9bbcSBrian Somers log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno)); 1209794c9bbcSBrian Somers else { 12100508c09aSBrian Somers if (Enabled(dl->bundle, OPT_NAS_IP_ADDRESS) && 12110508c09aSBrian Somers (hp = gethostbyname(hostname)) != NULL) { 1212794c9bbcSBrian Somers hostaddr.s_addr = *(u_long *)hp->h_addr; 1213794c9bbcSBrian Somers if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) { 1214794c9bbcSBrian Somers log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 1215794c9bbcSBrian Somers rad_strerror(r->cx.rad)); 1216794c9bbcSBrian Somers rad_close(r->cx.rad); 1217794c9bbcSBrian Somers return; 1218794c9bbcSBrian Somers } 1219794c9bbcSBrian Somers } 12200508c09aSBrian Somers if (Enabled(dl->bundle, OPT_NAS_IDENTIFIER) && 12210508c09aSBrian Somers rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) { 1222794c9bbcSBrian Somers log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 1223794c9bbcSBrian Somers rad_strerror(r->cx.rad)); 1224794c9bbcSBrian Somers rad_close(r->cx.rad); 1225794c9bbcSBrian Somers return; 1226794c9bbcSBrian Somers } 1227794c9bbcSBrian Somers } 1228794c9bbcSBrian Somers 1229d4d4a70aSRoman Bogorodskiy radius_put_physical_details(r, dl->physical); 1230794c9bbcSBrian Somers 1231794c9bbcSBrian Somers if (rad_put_int(r->cx.rad, RAD_ACCT_STATUS_TYPE, acct_type) != 0 || 1232794c9bbcSBrian Somers rad_put_string(r->cx.rad, RAD_ACCT_SESSION_ID, ac->session_id) != 0 || 1233794c9bbcSBrian Somers rad_put_string(r->cx.rad, RAD_ACCT_MULTI_SESSION_ID, 1234794c9bbcSBrian Somers ac->multi_session_id) != 0 || 1235794c9bbcSBrian Somers rad_put_int(r->cx.rad, RAD_ACCT_DELAY_TIME, 0) != 0) { 1236794c9bbcSBrian Somers /* XXX ACCT_DELAY_TIME should be increased each time a packet is waiting */ 1237794c9bbcSBrian Somers log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 1238794c9bbcSBrian Somers rad_close(r->cx.rad); 1239794c9bbcSBrian Somers return; 1240794c9bbcSBrian Somers } 1241794c9bbcSBrian Somers 1242e715b13bSBrian Somers if (acct_type == RAD_STOP || acct_type == RAD_ALIVE) 1243794c9bbcSBrian Somers /* Show some statistics */ 1244dfb3194aSDiomidis Spinellis if (rad_put_int(r->cx.rad, RAD_ACCT_INPUT_OCTETS, stats->OctetsIn % UINT32_MAX) != 0 || 1245dfb3194aSDiomidis Spinellis rad_put_int(r->cx.rad, RAD_ACCT_INPUT_GIGAWORDS, stats->OctetsIn / UINT32_MAX) != 0 || 1246794c9bbcSBrian Somers rad_put_int(r->cx.rad, RAD_ACCT_INPUT_PACKETS, stats->PacketsIn) != 0 || 1247dfb3194aSDiomidis Spinellis rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_OCTETS, stats->OctetsOut % UINT32_MAX) != 0 || 1248dfb3194aSDiomidis Spinellis rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_GIGAWORDS, stats->OctetsOut / UINT32_MAX) != 0 || 1249794c9bbcSBrian Somers rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_PACKETS, stats->PacketsOut) 1250794c9bbcSBrian Somers != 0 || 1251794c9bbcSBrian Somers rad_put_int(r->cx.rad, RAD_ACCT_SESSION_TIME, throughput_uptime(stats)) 1252794c9bbcSBrian Somers != 0) { 1253794c9bbcSBrian Somers log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 1254794c9bbcSBrian Somers rad_close(r->cx.rad); 1255794c9bbcSBrian Somers return; 1256794c9bbcSBrian Somers } 1257794c9bbcSBrian Somers 1258e715b13bSBrian Somers if (log_IsKept(LogPHASE) || log_IsKept(LogRADIUS)) { 1259057f1760SBrian Somers const char *what; 1260e715b13bSBrian Somers int level; 1261e715b13bSBrian Somers 1262e715b13bSBrian Somers switch (acct_type) { 1263e715b13bSBrian Somers case RAD_START: 1264e715b13bSBrian Somers what = "START"; 1265e715b13bSBrian Somers level = log_IsKept(LogPHASE) ? LogPHASE : LogRADIUS; 1266e715b13bSBrian Somers break; 1267e715b13bSBrian Somers case RAD_STOP: 1268e715b13bSBrian Somers what = "STOP"; 1269e715b13bSBrian Somers level = log_IsKept(LogPHASE) ? LogPHASE : LogRADIUS; 1270e715b13bSBrian Somers break; 1271e715b13bSBrian Somers case RAD_ALIVE: 1272e715b13bSBrian Somers what = "ALIVE"; 1273e715b13bSBrian Somers level = LogRADIUS; 1274e715b13bSBrian Somers break; 1275e715b13bSBrian Somers default: 1276e715b13bSBrian Somers what = "<unknown>"; 1277e715b13bSBrian Somers level = log_IsKept(LogPHASE) ? LogPHASE : LogRADIUS; 1278e715b13bSBrian Somers break; 1279e715b13bSBrian Somers } 1280e715b13bSBrian Somers log_Printf(level, "Radius(acct): %s data sent\n", what); 1281e715b13bSBrian Somers } 1282e715b13bSBrian Somers 1283c42627ffSBrian Somers r->cx.auth = NULL; /* Not valid for accounting requests */ 1284794c9bbcSBrian Somers if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv))) 1285794c9bbcSBrian Somers radius_Process(r, got); 1286794c9bbcSBrian Somers else { 1287794c9bbcSBrian Somers log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout); 1288794c9bbcSBrian Somers r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS; 1289794c9bbcSBrian Somers r->cx.timer.func = radius_Timeout; 1290c42627ffSBrian Somers r->cx.timer.name = "radius acct"; 1291794c9bbcSBrian Somers r->cx.timer.arg = r; 1292794c9bbcSBrian Somers timer_Start(&r->cx.timer); 1293794c9bbcSBrian Somers } 1294794c9bbcSBrian Somers } 1295794c9bbcSBrian Somers 1296794c9bbcSBrian Somers /* 1297f0cdd9c0SBrian Somers * How do things look at the moment ? 1298f0cdd9c0SBrian Somers */ 1299972a1bcfSBrian Somers void 1300972a1bcfSBrian Somers radius_Show(struct radius *r, struct prompt *p) 1301972a1bcfSBrian Somers { 130274457d3dSBrian Somers prompt_Printf(p, " Radius config: %s", 130374457d3dSBrian Somers *r->cfg.file ? r->cfg.file : "none"); 1304972a1bcfSBrian Somers if (r->valid) { 1305972a1bcfSBrian Somers prompt_Printf(p, "\n IP: %s\n", inet_ntoa(r->ip)); 1306972a1bcfSBrian Somers prompt_Printf(p, " Netmask: %s\n", inet_ntoa(r->mask)); 1307972a1bcfSBrian Somers prompt_Printf(p, " MTU: %lu\n", r->mtu); 1308972a1bcfSBrian Somers prompt_Printf(p, " VJ: %sabled\n", r->vj ? "en" : "dis"); 1309ff8e577bSBrian Somers prompt_Printf(p, " Message: %s\n", r->repstr ? r->repstr : ""); 13108fb5ef5aSBrian Somers prompt_Printf(p, " MPPE Enc Policy: %s\n", 13118fb5ef5aSBrian Somers radius_policyname(r->mppe.policy)); 13128fb5ef5aSBrian Somers prompt_Printf(p, " MPPE Enc Types: %s\n", 13138fb5ef5aSBrian Somers radius_typesname(r->mppe.types)); 13148fb5ef5aSBrian Somers prompt_Printf(p, " MPPE Recv Key: %seceived\n", 13158fb5ef5aSBrian Somers r->mppe.recvkey ? "R" : "Not r"); 13168fb5ef5aSBrian Somers prompt_Printf(p, " MPPE Send Key: %seceived\n", 13178fb5ef5aSBrian Somers r->mppe.sendkey ? "R" : "Not r"); 1318a16061b2SBrian Somers prompt_Printf(p, " MS-CHAP2-Response: %s\n", 1319a16061b2SBrian Somers r->msrepstr ? r->msrepstr : ""); 1320ff8e577bSBrian Somers prompt_Printf(p, " Error Message: %s\n", r->errstr ? r->errstr : ""); 1321972a1bcfSBrian Somers if (r->routes) 1322972a1bcfSBrian Somers route_ShowSticky(p, r->routes, " Routes", 16); 13230fe74aa4SHajimu UMEMOTO #ifndef NOINET6 13240fe74aa4SHajimu UMEMOTO if (r->ipv6routes) 13250fe74aa4SHajimu UMEMOTO route_ShowSticky(p, r->ipv6routes, " IPv6 Routes", 16); 13260fe74aa4SHajimu UMEMOTO #endif 1327972a1bcfSBrian Somers } else 1328972a1bcfSBrian Somers prompt_Printf(p, " (not authenticated)\n"); 1329972a1bcfSBrian Somers } 1330e715b13bSBrian Somers 1331e715b13bSBrian Somers static void 1332e715b13bSBrian Somers radius_alive(void *v) 1333e715b13bSBrian Somers { 1334e715b13bSBrian Somers struct bundle *bundle = (struct bundle *)v; 1335e715b13bSBrian Somers 1336e715b13bSBrian Somers timer_Stop(&bundle->radius.alive.timer); 1337e715b13bSBrian Somers bundle->radius.alive.timer.load = bundle->radius.alive.interval * SECTICKS; 1338e715b13bSBrian Somers if (bundle->radius.alive.timer.load) { 1339e715b13bSBrian Somers radius_Account(&bundle->radius, &bundle->radacct, 1340e715b13bSBrian Somers bundle->links, RAD_ALIVE, &bundle->ncp.ipcp.throughput); 1341e715b13bSBrian Somers timer_Start(&bundle->radius.alive.timer); 1342e715b13bSBrian Somers } 1343e715b13bSBrian Somers } 1344e715b13bSBrian Somers 1345e715b13bSBrian Somers void 1346e715b13bSBrian Somers radius_StartTimer(struct bundle *bundle) 1347e715b13bSBrian Somers { 1348e715b13bSBrian Somers if (bundle->radius.cfg.file && bundle->radius.alive.interval) { 1349e715b13bSBrian Somers bundle->radius.alive.timer.func = radius_alive; 1350e715b13bSBrian Somers bundle->radius.alive.timer.name = "radius alive"; 1351e715b13bSBrian Somers bundle->radius.alive.timer.load = bundle->radius.alive.interval * SECTICKS; 1352e715b13bSBrian Somers bundle->radius.alive.timer.arg = bundle; 1353e715b13bSBrian Somers radius_alive(bundle); 1354e715b13bSBrian Somers } 1355e715b13bSBrian Somers } 1356e715b13bSBrian Somers 1357e715b13bSBrian Somers void 1358e715b13bSBrian Somers radius_StopTimer(struct radius *r) 1359e715b13bSBrian Somers { 1360e715b13bSBrian Somers timer_Stop(&r->alive.timer); 1361e715b13bSBrian Somers } 1362