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 336b457978SBrian Somers #include <sys/socket.h> 34972a1bcfSBrian Somers #include <netinet/in_systm.h> 35972a1bcfSBrian Somers #include <netinet/in.h> 36972a1bcfSBrian Somers #include <netinet/ip.h> 37972a1bcfSBrian Somers #include <arpa/inet.h> 38972a1bcfSBrian Somers #include <sys/un.h> 396b457978SBrian Somers #include <net/route.h> 40972a1bcfSBrian Somers 4110e629b9SBrian Somers #ifdef LOCALRAD 4210e629b9SBrian Somers #include "radlib.h" 43ff8e577bSBrian Somers #include "radlib_vs.h" 4410e629b9SBrian Somers #else 45972a1bcfSBrian Somers #include <radlib.h> 46ff8e577bSBrian Somers #include <radlib_vs.h> 4710e629b9SBrian Somers #endif 4810e629b9SBrian Somers 4910e629b9SBrian Somers #include <errno.h> 508fb5ef5aSBrian Somers #ifndef NODES 518fb5ef5aSBrian Somers #include <md5.h> 528fb5ef5aSBrian Somers #endif 536eafd353SBrian Somers #include <stdarg.h> 54972a1bcfSBrian Somers #include <stdio.h> 55972a1bcfSBrian Somers #include <stdlib.h> 56972a1bcfSBrian Somers #include <string.h> 57f0cdd9c0SBrian Somers #include <sys/time.h> 58972a1bcfSBrian Somers #include <termios.h> 59f10f5203SBrian Somers #include <unistd.h> 60f10f5203SBrian Somers #include <netdb.h> 61972a1bcfSBrian Somers 625d9e6103SBrian Somers #include "layer.h" 63972a1bcfSBrian Somers #include "defs.h" 64972a1bcfSBrian Somers #include "log.h" 65972a1bcfSBrian Somers #include "descriptor.h" 66972a1bcfSBrian Somers #include "prompt.h" 67972a1bcfSBrian Somers #include "timer.h" 68972a1bcfSBrian Somers #include "fsm.h" 69972a1bcfSBrian Somers #include "iplist.h" 70972a1bcfSBrian Somers #include "slcompress.h" 71972a1bcfSBrian Somers #include "throughput.h" 72972a1bcfSBrian Somers #include "lqr.h" 73972a1bcfSBrian Somers #include "hdlc.h" 74972a1bcfSBrian Somers #include "mbuf.h" 7530949fd4SBrian Somers #include "ncpaddr.h" 7630949fd4SBrian Somers #include "ip.h" 77972a1bcfSBrian Somers #include "ipcp.h" 7830949fd4SBrian Somers #include "ipv6cp.h" 79972a1bcfSBrian Somers #include "route.h" 80972a1bcfSBrian Somers #include "command.h" 81972a1bcfSBrian Somers #include "filter.h" 82972a1bcfSBrian Somers #include "lcp.h" 83972a1bcfSBrian Somers #include "ccp.h" 84972a1bcfSBrian Somers #include "link.h" 85972a1bcfSBrian Somers #include "mp.h" 86972a1bcfSBrian Somers #include "radius.h" 87f0cdd9c0SBrian Somers #include "auth.h" 88f0cdd9c0SBrian Somers #include "async.h" 89f0cdd9c0SBrian Somers #include "physical.h" 90f0cdd9c0SBrian Somers #include "chat.h" 91f0cdd9c0SBrian Somers #include "cbcp.h" 92f0cdd9c0SBrian Somers #include "chap.h" 93f0cdd9c0SBrian Somers #include "datalink.h" 9430949fd4SBrian Somers #include "ncp.h" 95972a1bcfSBrian Somers #include "bundle.h" 96ff8e577bSBrian Somers #include "proto.h" 97ff8e577bSBrian Somers 98ff8e577bSBrian Somers #ifndef NODES 99a16061b2SBrian Somers struct mschap_response { 100ff8e577bSBrian Somers u_char ident; 101ff8e577bSBrian Somers u_char flags; 102ff8e577bSBrian Somers u_char lm_response[24]; 103ff8e577bSBrian Somers u_char nt_response[24]; 104ff8e577bSBrian Somers }; 105a16061b2SBrian Somers 106a16061b2SBrian Somers struct mschap2_response { 107a16061b2SBrian Somers u_char ident; 108a16061b2SBrian Somers u_char flags; 109a16061b2SBrian Somers u_char pchallenge[16]; 110a16061b2SBrian Somers u_char reserved[8]; 111a16061b2SBrian Somers u_char response[24]; 112a16061b2SBrian Somers }; 1138fb5ef5aSBrian Somers 1148fb5ef5aSBrian Somers #define AUTH_LEN 16 1158fb5ef5aSBrian Somers #define SALT_LEN 2 1168fb5ef5aSBrian Somers #endif 1178fb5ef5aSBrian Somers 1188fb5ef5aSBrian Somers static const char * 1198fb5ef5aSBrian Somers radius_policyname(int policy) 1208fb5ef5aSBrian Somers { 1218fb5ef5aSBrian Somers switch(policy) { 1228fb5ef5aSBrian Somers case MPPE_POLICY_ALLOWED: 1238fb5ef5aSBrian Somers return "Allowed"; 1248fb5ef5aSBrian Somers case MPPE_POLICY_REQUIRED: 1258fb5ef5aSBrian Somers return "Required"; 1268fb5ef5aSBrian Somers } 1278fb5ef5aSBrian Somers return NumStr(policy, NULL, 0); 1288fb5ef5aSBrian Somers } 1298fb5ef5aSBrian Somers 1308fb5ef5aSBrian Somers static const char * 1318fb5ef5aSBrian Somers radius_typesname(int types) 1328fb5ef5aSBrian Somers { 1338fb5ef5aSBrian Somers switch(types) { 1348fb5ef5aSBrian Somers case MPPE_TYPE_40BIT: 1358fb5ef5aSBrian Somers return "40 bit"; 1368fb5ef5aSBrian Somers case MPPE_TYPE_128BIT: 1378fb5ef5aSBrian Somers return "128 bit"; 1388fb5ef5aSBrian Somers case MPPE_TYPE_40BIT|MPPE_TYPE_128BIT: 1398fb5ef5aSBrian Somers return "40 or 128 bit"; 1408fb5ef5aSBrian Somers } 1418fb5ef5aSBrian Somers return NumStr(types, NULL, 0); 1428fb5ef5aSBrian Somers } 1438fb5ef5aSBrian Somers 1448fb5ef5aSBrian Somers #ifndef NODES 1458fb5ef5aSBrian Somers static void 1468fb5ef5aSBrian Somers demangle(struct radius *r, const void *mangled, size_t mlen, 1478fb5ef5aSBrian Somers char **buf, size_t *len) 1488fb5ef5aSBrian Somers { 1498fb5ef5aSBrian Somers char R[AUTH_LEN]; /* variable names as per rfc2548 */ 1508fb5ef5aSBrian Somers const char *S; 1518fb5ef5aSBrian Somers u_char b[16]; 1528fb5ef5aSBrian Somers const u_char *A, *C; 1538fb5ef5aSBrian Somers MD5_CTX Context; 1548fb5ef5aSBrian Somers int Slen, i, Clen, Ppos; 1558fb5ef5aSBrian Somers u_char *P; 1568fb5ef5aSBrian Somers 1578fb5ef5aSBrian Somers if (mlen % 16 != SALT_LEN) { 1588fb5ef5aSBrian Somers log_Printf(LogWARN, "Cannot interpret mangled data of length %ld\n", 1598fb5ef5aSBrian Somers (u_long)mlen); 1608fb5ef5aSBrian Somers *buf = NULL; 1618fb5ef5aSBrian Somers *len = 0; 1628fb5ef5aSBrian Somers return; 1638fb5ef5aSBrian Somers } 1648fb5ef5aSBrian Somers 1658fb5ef5aSBrian Somers /* We need the RADIUS Request-Authenticator */ 1668fb5ef5aSBrian Somers if (rad_request_authenticator(r->cx.rad, R, sizeof R) != AUTH_LEN) { 1678fb5ef5aSBrian Somers log_Printf(LogWARN, "Cannot obtain the RADIUS request authenticator\n"); 1688fb5ef5aSBrian Somers *buf = NULL; 1698fb5ef5aSBrian Somers *len = 0; 1708fb5ef5aSBrian Somers return; 1718fb5ef5aSBrian Somers } 1728fb5ef5aSBrian Somers 1738fb5ef5aSBrian Somers A = (const u_char *)mangled; /* Salt comes first */ 1748fb5ef5aSBrian Somers C = (const u_char *)mangled + SALT_LEN; /* Then the ciphertext */ 1758fb5ef5aSBrian Somers Clen = mlen - SALT_LEN; 1768fb5ef5aSBrian Somers S = rad_server_secret(r->cx.rad); /* We need the RADIUS secret */ 1778fb5ef5aSBrian Somers Slen = strlen(S); 1788fb5ef5aSBrian Somers P = alloca(Clen); /* We derive our plaintext */ 1798fb5ef5aSBrian Somers 1808fb5ef5aSBrian Somers MD5Init(&Context); 1818fb5ef5aSBrian Somers MD5Update(&Context, S, Slen); 1828fb5ef5aSBrian Somers MD5Update(&Context, R, AUTH_LEN); 1838fb5ef5aSBrian Somers MD5Update(&Context, A, SALT_LEN); 1848fb5ef5aSBrian Somers MD5Final(b, &Context); 1858fb5ef5aSBrian Somers Ppos = 0; 1868fb5ef5aSBrian Somers 1878fb5ef5aSBrian Somers while (Clen) { 1888fb5ef5aSBrian Somers Clen -= 16; 1898fb5ef5aSBrian Somers 1908fb5ef5aSBrian Somers for (i = 0; i < 16; i++) 1918fb5ef5aSBrian Somers P[Ppos++] = C[i] ^ b[i]; 1928fb5ef5aSBrian Somers 1938fb5ef5aSBrian Somers if (Clen) { 1948fb5ef5aSBrian Somers MD5Init(&Context); 1958fb5ef5aSBrian Somers MD5Update(&Context, S, Slen); 1968fb5ef5aSBrian Somers MD5Update(&Context, C, 16); 1978fb5ef5aSBrian Somers MD5Final(b, &Context); 1988fb5ef5aSBrian Somers } 1998fb5ef5aSBrian Somers 2008fb5ef5aSBrian Somers C += 16; 2018fb5ef5aSBrian Somers } 2028fb5ef5aSBrian Somers 2038fb5ef5aSBrian Somers /* 2048fb5ef5aSBrian Somers * The resulting plain text consists of a one-byte length, the text and 2058fb5ef5aSBrian Somers * maybe some padding. 2068fb5ef5aSBrian Somers */ 2078fb5ef5aSBrian Somers *len = *P; 2088fb5ef5aSBrian Somers if (*len > mlen - 1) { 2098fb5ef5aSBrian Somers log_Printf(LogWARN, "Mangled data seems to be garbage\n"); 2108fb5ef5aSBrian Somers *buf = NULL; 2118fb5ef5aSBrian Somers *len = 0; 2128fb5ef5aSBrian Somers return; 2138fb5ef5aSBrian Somers } 2148fb5ef5aSBrian Somers 2158fb5ef5aSBrian Somers *buf = malloc(*len); 2168fb5ef5aSBrian Somers memcpy(*buf, P + 1, *len); 2178fb5ef5aSBrian Somers } 218ff8e577bSBrian Somers #endif 219972a1bcfSBrian Somers 220ec3e98b8SHajimu UMEMOTO /* XXX: This should go into librarius. */ 221ec3e98b8SHajimu UMEMOTO #ifndef NOINET6 222ec3e98b8SHajimu UMEMOTO static uint8_t * 223ec3e98b8SHajimu UMEMOTO rad_cvt_ipv6prefix(const void *data, size_t len) 224ec3e98b8SHajimu UMEMOTO { 225ec3e98b8SHajimu UMEMOTO const size_t ipv6len = sizeof(struct in6_addr) + 2; 226ec3e98b8SHajimu UMEMOTO uint8_t *s; 227ec3e98b8SHajimu UMEMOTO 228ec3e98b8SHajimu UMEMOTO if (len > ipv6len) 229ec3e98b8SHajimu UMEMOTO return NULL; 230ec3e98b8SHajimu UMEMOTO s = malloc(ipv6len); 231ec3e98b8SHajimu UMEMOTO if (s != NULL) { 232ec3e98b8SHajimu UMEMOTO memset(s, 0, ipv6len); 233ec3e98b8SHajimu UMEMOTO memcpy(s, data, len); 234ec3e98b8SHajimu UMEMOTO } 235ec3e98b8SHajimu UMEMOTO return s; 236ec3e98b8SHajimu UMEMOTO } 237ec3e98b8SHajimu UMEMOTO #endif 238ec3e98b8SHajimu UMEMOTO 239f0cdd9c0SBrian Somers /* 240f0cdd9c0SBrian Somers * rad_continue_send_request() has given us `got' (non-zero). Deal with it. 241f0cdd9c0SBrian Somers */ 242f0cdd9c0SBrian Somers static void 243f0cdd9c0SBrian Somers radius_Process(struct radius *r, int got) 244972a1bcfSBrian Somers { 245972a1bcfSBrian Somers char *argv[MAXARGS], *nuke; 246f0cdd9c0SBrian Somers struct bundle *bundle; 247ff8e577bSBrian Somers int argc, addrs, res, width; 24828e610e3SBrian Somers size_t len; 24930949fd4SBrian Somers struct ncprange dest; 25030949fd4SBrian Somers struct ncpaddr gw; 251f0cdd9c0SBrian Somers const void *data; 252c42627ffSBrian Somers const char *stype; 253ff8e577bSBrian Somers u_int32_t ipaddr, vendor; 25430949fd4SBrian Somers struct in_addr ip; 2550fe74aa4SHajimu UMEMOTO #ifndef NOINET6 256ec3e98b8SHajimu UMEMOTO uint8_t ipv6addr[INET6_ADDRSTRLEN]; 2570fe74aa4SHajimu UMEMOTO struct in6_addr ip6; 2580fe74aa4SHajimu UMEMOTO #endif 259972a1bcfSBrian Somers 260f0cdd9c0SBrian Somers r->cx.fd = -1; /* Stop select()ing */ 261c42627ffSBrian Somers stype = r->cx.auth ? "auth" : "acct"; 262972a1bcfSBrian Somers 263972a1bcfSBrian Somers switch (got) { 264972a1bcfSBrian Somers case RAD_ACCESS_ACCEPT: 265e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 266e715b13bSBrian Somers "Radius(%s): ACCEPT received\n", stype); 267c42627ffSBrian Somers if (!r->cx.auth) { 268c42627ffSBrian Somers rad_close(r->cx.rad); 269c42627ffSBrian Somers return; 270c42627ffSBrian Somers } 271972a1bcfSBrian Somers break; 272972a1bcfSBrian Somers 273f0cdd9c0SBrian Somers case RAD_ACCESS_REJECT: 274e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 275e715b13bSBrian Somers "Radius(%s): REJECT received\n", stype); 276ff8e577bSBrian Somers if (!r->cx.auth) { 277f0cdd9c0SBrian Somers rad_close(r->cx.rad); 278f0cdd9c0SBrian Somers return; 279ff8e577bSBrian Somers } 280ff8e577bSBrian Somers break; 281f0cdd9c0SBrian Somers 282972a1bcfSBrian Somers case RAD_ACCESS_CHALLENGE: 283972a1bcfSBrian Somers /* we can't deal with this (for now) ! */ 284e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 285e715b13bSBrian Somers "Radius: CHALLENGE received (can't handle yet)\n"); 286c42627ffSBrian Somers if (r->cx.auth) 287f0cdd9c0SBrian Somers auth_Failure(r->cx.auth); 288f0cdd9c0SBrian Somers rad_close(r->cx.rad); 289f0cdd9c0SBrian Somers return; 290972a1bcfSBrian Somers 291794c9bbcSBrian Somers case RAD_ACCOUNTING_RESPONSE: 292e715b13bSBrian Somers /* 293e715b13bSBrian Somers * It's probably not ideal to log this at PHASE level as we'll see 294e715b13bSBrian Somers * too much stuff going to the log when ``set rad_alive'' is used. 295e715b13bSBrian Somers * So we differ from older behaviour (ppp version 3.1 and before) 296e715b13bSBrian Somers * and just log accounting responses to LogRADIUS. 297e715b13bSBrian Somers */ 298e715b13bSBrian Somers log_Printf(LogRADIUS, "Radius(%s): Accounting response received\n", 299e715b13bSBrian Somers stype); 300c42627ffSBrian Somers if (r->cx.auth) 301c42627ffSBrian Somers auth_Failure(r->cx.auth); /* unexpected !!! */ 302c42627ffSBrian Somers 303794c9bbcSBrian Somers /* No further processing for accounting requests, please */ 304794c9bbcSBrian Somers rad_close(r->cx.rad); 305794c9bbcSBrian Somers return; 306794c9bbcSBrian Somers 307972a1bcfSBrian Somers case -1: 308e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 309e715b13bSBrian Somers "radius(%s): %s\n", stype, rad_strerror(r->cx.rad)); 310c42627ffSBrian Somers if (r->cx.auth) 311f0cdd9c0SBrian Somers auth_Failure(r->cx.auth); 312f0cdd9c0SBrian Somers rad_close(r->cx.rad); 313f0cdd9c0SBrian Somers return; 314972a1bcfSBrian Somers 315972a1bcfSBrian Somers default: 316c42627ffSBrian Somers log_Printf(LogERROR, "rad_send_request(%s): Failed %d: %s\n", stype, 317f0cdd9c0SBrian Somers got, rad_strerror(r->cx.rad)); 318c42627ffSBrian Somers if (r->cx.auth) 319f0cdd9c0SBrian Somers auth_Failure(r->cx.auth); 320f0cdd9c0SBrian Somers rad_close(r->cx.rad); 321f0cdd9c0SBrian Somers return; 322972a1bcfSBrian Somers } 323972a1bcfSBrian Somers 324ff8e577bSBrian Somers /* Let's see what we've got in our reply */ 325972a1bcfSBrian Somers r->ip.s_addr = r->mask.s_addr = INADDR_NONE; 326972a1bcfSBrian Somers r->mtu = 0; 327972a1bcfSBrian Somers r->vj = 0; 328ff8e577bSBrian Somers while ((res = rad_get_attr(r->cx.rad, &data, &len)) > 0) { 329ff8e577bSBrian Somers switch (res) { 330972a1bcfSBrian Somers case RAD_FRAMED_IP_ADDRESS: 331972a1bcfSBrian Somers r->ip = rad_cvt_addr(data); 332e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 333e715b13bSBrian Somers " IP %s\n", inet_ntoa(r->ip)); 334972a1bcfSBrian Somers break; 335972a1bcfSBrian Somers 336bf1eaec5SBrian Somers case RAD_FILTER_ID: 337bf1eaec5SBrian Somers free(r->filterid); 338bf1eaec5SBrian Somers if ((r->filterid = rad_cvt_string(data, len)) == NULL) { 339bf1eaec5SBrian Somers log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); 340ff8e577bSBrian Somers auth_Failure(r->cx.auth); 341bf1eaec5SBrian Somers rad_close(r->cx.rad); 342bf1eaec5SBrian Somers return; 343bf1eaec5SBrian Somers } 344e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 345e715b13bSBrian Somers " Filter \"%s\"\n", r->filterid); 346bf1eaec5SBrian Somers break; 347bf1eaec5SBrian Somers 348bf1eaec5SBrian Somers case RAD_SESSION_TIMEOUT: 349bf1eaec5SBrian Somers r->sessiontime = rad_cvt_int(data); 350e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 351e715b13bSBrian Somers " Session-Timeout %lu\n", r->sessiontime); 352bf1eaec5SBrian Somers break; 353bf1eaec5SBrian Somers 354972a1bcfSBrian Somers case RAD_FRAMED_IP_NETMASK: 355972a1bcfSBrian Somers r->mask = rad_cvt_addr(data); 356e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 357e715b13bSBrian Somers " Netmask %s\n", inet_ntoa(r->mask)); 358972a1bcfSBrian Somers break; 359972a1bcfSBrian Somers 360972a1bcfSBrian Somers case RAD_FRAMED_MTU: 361972a1bcfSBrian Somers r->mtu = rad_cvt_int(data); 362e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 363e715b13bSBrian Somers " MTU %lu\n", r->mtu); 364972a1bcfSBrian Somers break; 365972a1bcfSBrian Somers 366972a1bcfSBrian Somers case RAD_FRAMED_ROUTING: 367972a1bcfSBrian Somers /* Disabled for now - should we automatically set up some filters ? */ 368972a1bcfSBrian Somers /* rad_cvt_int(data); */ 369972a1bcfSBrian Somers /* bit 1 = Send routing packets */ 370972a1bcfSBrian Somers /* bit 2 = Receive routing packets */ 371972a1bcfSBrian Somers break; 372972a1bcfSBrian Somers 373972a1bcfSBrian Somers case RAD_FRAMED_COMPRESSION: 374972a1bcfSBrian Somers r->vj = rad_cvt_int(data) == 1 ? 1 : 0; 375e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 376e715b13bSBrian Somers " VJ %sabled\n", r->vj ? "en" : "dis"); 377972a1bcfSBrian Somers break; 378972a1bcfSBrian Somers 379972a1bcfSBrian Somers case RAD_FRAMED_ROUTE: 380972a1bcfSBrian Somers /* 381972a1bcfSBrian Somers * We expect a string of the format ``dest[/bits] gw [metrics]'' 382972a1bcfSBrian Somers * Any specified metrics are ignored. MYADDR and HISADDR are 383972a1bcfSBrian Somers * understood for ``dest'' and ``gw'' and ``0.0.0.0'' is the same 384972a1bcfSBrian Somers * as ``HISADDR''. 385972a1bcfSBrian Somers */ 386972a1bcfSBrian Somers 387972a1bcfSBrian Somers if ((nuke = rad_cvt_string(data, len)) == NULL) { 388f0cdd9c0SBrian Somers log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); 389ff8e577bSBrian Somers auth_Failure(r->cx.auth); 390f0cdd9c0SBrian Somers rad_close(r->cx.rad); 391f0cdd9c0SBrian Somers return; 392972a1bcfSBrian Somers } 393972a1bcfSBrian Somers 394e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 395e715b13bSBrian Somers " Route: %s\n", nuke); 396f0cdd9c0SBrian Somers bundle = r->cx.auth->physical->dl->bundle; 39730949fd4SBrian Somers ip.s_addr = INADDR_ANY; 3980fe74aa4SHajimu UMEMOTO ncpaddr_setip4(&gw, ip); 39930949fd4SBrian Somers ncprange_setip4host(&dest, ip); 400972a1bcfSBrian Somers argc = command_Interpret(nuke, strlen(nuke), argv); 401c39aa54eSBrian Somers if (argc < 0) 402c39aa54eSBrian Somers log_Printf(LogWARN, "radius: %s: Syntax error\n", 403c39aa54eSBrian Somers argc == 1 ? argv[0] : "\"\""); 404c39aa54eSBrian Somers else if (argc < 2) 405972a1bcfSBrian Somers log_Printf(LogWARN, "radius: %s: Invalid route\n", 406972a1bcfSBrian Somers argc == 1 ? argv[0] : "\"\""); 407972a1bcfSBrian Somers else if ((strcasecmp(argv[0], "default") != 0 && 40830949fd4SBrian Somers !ncprange_aton(&dest, &bundle->ncp, argv[0])) || 40930949fd4SBrian Somers !ncpaddr_aton(&gw, &bundle->ncp, argv[1])) 410972a1bcfSBrian Somers log_Printf(LogWARN, "radius: %s %s: Invalid route\n", 411972a1bcfSBrian Somers argv[0], argv[1]); 412972a1bcfSBrian Somers else { 41330949fd4SBrian Somers ncprange_getwidth(&dest, &width); 41430949fd4SBrian Somers if (width == 32 && strchr(argv[0], '/') == NULL) { 415972a1bcfSBrian Somers /* No mask specified - use the natural mask */ 41630949fd4SBrian Somers ncprange_getip4addr(&dest, &ip); 41730949fd4SBrian Somers ncprange_setip4mask(&dest, addr2mask(ip)); 41830949fd4SBrian Somers } 419972a1bcfSBrian Somers addrs = 0; 420972a1bcfSBrian Somers 421972a1bcfSBrian Somers if (!strncasecmp(argv[0], "HISADDR", 7)) 422972a1bcfSBrian Somers addrs = ROUTE_DSTHISADDR; 423972a1bcfSBrian Somers else if (!strncasecmp(argv[0], "MYADDR", 6)) 424972a1bcfSBrian Somers addrs = ROUTE_DSTMYADDR; 425972a1bcfSBrian Somers 42630949fd4SBrian Somers if (ncpaddr_getip4addr(&gw, &ipaddr) && ipaddr == INADDR_ANY) { 427972a1bcfSBrian Somers addrs |= ROUTE_GWHISADDR; 42830949fd4SBrian Somers ncpaddr_setip4(&gw, bundle->ncp.ipcp.peer_ip); 429972a1bcfSBrian Somers } else if (strcasecmp(argv[1], "HISADDR") == 0) 430972a1bcfSBrian Somers addrs |= ROUTE_GWHISADDR; 431972a1bcfSBrian Somers 43230949fd4SBrian Somers route_Add(&r->routes, addrs, &dest, &gw); 433972a1bcfSBrian Somers } 434972a1bcfSBrian Somers free(nuke); 435972a1bcfSBrian Somers break; 436972a1bcfSBrian Somers 437ff8e577bSBrian Somers case RAD_REPLY_MESSAGE: 438ff8e577bSBrian Somers free(r->repstr); 439ff8e577bSBrian Somers if ((r->repstr = rad_cvt_string(data, len)) == NULL) { 440ff8e577bSBrian Somers log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); 441ff8e577bSBrian Somers auth_Failure(r->cx.auth); 442ff8e577bSBrian Somers rad_close(r->cx.rad); 443ff8e577bSBrian Somers return; 444ff8e577bSBrian Somers } 445e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 446e715b13bSBrian Somers " Reply-Message \"%s\"\n", r->repstr); 447ff8e577bSBrian Somers break; 448ff8e577bSBrian Somers 4490fe74aa4SHajimu UMEMOTO #ifndef NOINET6 450ec3e98b8SHajimu UMEMOTO case RAD_FRAMED_IPV6_PREFIX: 451ec3e98b8SHajimu UMEMOTO free(r->ipv6prefix); 452ec3e98b8SHajimu UMEMOTO r->ipv6prefix = rad_cvt_ipv6prefix(data, len); 453ec3e98b8SHajimu UMEMOTO inet_ntop(AF_INET6, &r->ipv6prefix[2], ipv6addr, sizeof(ipv6addr)); 454e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 455e715b13bSBrian Somers " IPv6 %s/%d\n", ipv6addr, r->ipv6prefix[1]); 456ec3e98b8SHajimu UMEMOTO break; 457ec3e98b8SHajimu UMEMOTO 4580fe74aa4SHajimu UMEMOTO case RAD_FRAMED_IPV6_ROUTE: 4590fe74aa4SHajimu UMEMOTO /* 4600fe74aa4SHajimu UMEMOTO * We expect a string of the format ``dest[/bits] gw [metrics]'' 4610fe74aa4SHajimu UMEMOTO * Any specified metrics are ignored. MYADDR6 and HISADDR6 are 4620fe74aa4SHajimu UMEMOTO * understood for ``dest'' and ``gw'' and ``::'' is the same 4630fe74aa4SHajimu UMEMOTO * as ``HISADDR6''. 4640fe74aa4SHajimu UMEMOTO */ 4650fe74aa4SHajimu UMEMOTO 4660fe74aa4SHajimu UMEMOTO if ((nuke = rad_cvt_string(data, len)) == NULL) { 4670fe74aa4SHajimu UMEMOTO log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); 4680fe74aa4SHajimu UMEMOTO auth_Failure(r->cx.auth); 4690fe74aa4SHajimu UMEMOTO rad_close(r->cx.rad); 4700fe74aa4SHajimu UMEMOTO return; 4710fe74aa4SHajimu UMEMOTO } 4720fe74aa4SHajimu UMEMOTO 473e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 474e715b13bSBrian Somers " IPv6 Route: %s\n", nuke); 4750fe74aa4SHajimu UMEMOTO bundle = r->cx.auth->physical->dl->bundle; 4760fe74aa4SHajimu UMEMOTO ncpaddr_setip6(&gw, &in6addr_any); 4770fe74aa4SHajimu UMEMOTO ncprange_set(&dest, &gw, 0); 4780fe74aa4SHajimu UMEMOTO argc = command_Interpret(nuke, strlen(nuke), argv); 4790fe74aa4SHajimu UMEMOTO if (argc < 0) 4800fe74aa4SHajimu UMEMOTO log_Printf(LogWARN, "radius: %s: Syntax error\n", 4810fe74aa4SHajimu UMEMOTO argc == 1 ? argv[0] : "\"\""); 4820fe74aa4SHajimu UMEMOTO else if (argc < 2) 4830fe74aa4SHajimu UMEMOTO log_Printf(LogWARN, "radius: %s: Invalid route\n", 4840fe74aa4SHajimu UMEMOTO argc == 1 ? argv[0] : "\"\""); 4850fe74aa4SHajimu UMEMOTO else if ((strcasecmp(argv[0], "default") != 0 && 4860fe74aa4SHajimu UMEMOTO !ncprange_aton(&dest, &bundle->ncp, argv[0])) || 4870fe74aa4SHajimu UMEMOTO !ncpaddr_aton(&gw, &bundle->ncp, argv[1])) 4880fe74aa4SHajimu UMEMOTO log_Printf(LogWARN, "radius: %s %s: Invalid route\n", 4890fe74aa4SHajimu UMEMOTO argv[0], argv[1]); 4900fe74aa4SHajimu UMEMOTO else { 4910fe74aa4SHajimu UMEMOTO addrs = 0; 4920fe74aa4SHajimu UMEMOTO 4930fe74aa4SHajimu UMEMOTO if (!strncasecmp(argv[0], "HISADDR6", 8)) 4940fe74aa4SHajimu UMEMOTO addrs = ROUTE_DSTHISADDR6; 4950fe74aa4SHajimu UMEMOTO else if (!strncasecmp(argv[0], "MYADDR6", 7)) 4960fe74aa4SHajimu UMEMOTO addrs = ROUTE_DSTMYADDR6; 4970fe74aa4SHajimu UMEMOTO 4980fe74aa4SHajimu UMEMOTO if (ncpaddr_getip6(&gw, &ip6) && IN6_IS_ADDR_UNSPECIFIED(&ip6)) { 4990fe74aa4SHajimu UMEMOTO addrs |= ROUTE_GWHISADDR6; 5000fe74aa4SHajimu UMEMOTO ncpaddr_copy(&gw, &bundle->ncp.ipv6cp.hisaddr); 5010fe74aa4SHajimu UMEMOTO } else if (strcasecmp(argv[1], "HISADDR6") == 0) 5020fe74aa4SHajimu UMEMOTO addrs |= ROUTE_GWHISADDR6; 5030fe74aa4SHajimu UMEMOTO 5040fe74aa4SHajimu UMEMOTO route_Add(&r->ipv6routes, addrs, &dest, &gw); 5050fe74aa4SHajimu UMEMOTO } 5060fe74aa4SHajimu UMEMOTO free(nuke); 5070fe74aa4SHajimu UMEMOTO break; 5080fe74aa4SHajimu UMEMOTO #endif 5090fe74aa4SHajimu UMEMOTO 510ff8e577bSBrian Somers case RAD_VENDOR_SPECIFIC: 511ff8e577bSBrian Somers if ((res = rad_get_vendor_attr(&vendor, &data, &len)) <= 0) { 512ff8e577bSBrian Somers log_Printf(LogERROR, "rad_get_vendor_attr: %s (failing!)\n", 513f0cdd9c0SBrian Somers rad_strerror(r->cx.rad)); 514f0cdd9c0SBrian Somers auth_Failure(r->cx.auth); 515f0cdd9c0SBrian Somers rad_close(r->cx.rad); 516ff8e577bSBrian Somers return; 517ff8e577bSBrian Somers } 518ff8e577bSBrian Somers 519ff8e577bSBrian Somers switch (vendor) { 520ff8e577bSBrian Somers case RAD_VENDOR_MICROSOFT: 521ff8e577bSBrian Somers switch (res) { 5228fb5ef5aSBrian Somers #ifndef NODES 523ff8e577bSBrian Somers case RAD_MICROSOFT_MS_CHAP_ERROR: 524ff8e577bSBrian Somers free(r->errstr); 525a95b23a6SBrian Somers if (len == 0) 526a95b23a6SBrian Somers r->errstr = NULL; 527a95b23a6SBrian Somers else { 52899cfc2e2SBrian Somers if (len < 3 || ((const char *)data)[1] != '=') { 52999cfc2e2SBrian Somers /* 53099cfc2e2SBrian Somers * Only point at the String field if we don't think the 53199cfc2e2SBrian Somers * peer has misformatted the response. 53299cfc2e2SBrian Somers */ 53399cfc2e2SBrian Somers ((const char *)data)++; 53499cfc2e2SBrian Somers len--; 535579abfd8SBrian Somers } else 536579abfd8SBrian Somers log_Printf(LogWARN, "Warning: The MS-CHAP-Error " 537579abfd8SBrian Somers "attribute is mis-formatted. Compensating\n"); 53899cfc2e2SBrian Somers if ((r->errstr = rad_cvt_string((const char *)data, 53999cfc2e2SBrian Somers len)) == NULL) { 540ff8e577bSBrian Somers log_Printf(LogERROR, "rad_cvt_string: %s\n", 541ff8e577bSBrian Somers rad_strerror(r->cx.rad)); 542ff8e577bSBrian Somers auth_Failure(r->cx.auth); 543ff8e577bSBrian Somers rad_close(r->cx.rad); 544ff8e577bSBrian Somers return; 545ff8e577bSBrian Somers } 546e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 547e715b13bSBrian Somers " MS-CHAP-Error \"%s\"\n", r->errstr); 548a95b23a6SBrian Somers } 549ff8e577bSBrian Somers break; 550ff8e577bSBrian Somers 551a16061b2SBrian Somers case RAD_MICROSOFT_MS_CHAP2_SUCCESS: 552a16061b2SBrian Somers free(r->msrepstr); 553a95b23a6SBrian Somers if (len == 0) 554a95b23a6SBrian Somers r->msrepstr = NULL; 555a95b23a6SBrian Somers else { 55699cfc2e2SBrian Somers if (len < 3 || ((const char *)data)[1] != '=') { 55799cfc2e2SBrian Somers /* 55899cfc2e2SBrian Somers * Only point at the String field if we don't think the 55999cfc2e2SBrian Somers * peer has misformatted the response. 56099cfc2e2SBrian Somers */ 56199cfc2e2SBrian Somers ((const char *)data)++; 56299cfc2e2SBrian Somers len--; 563579abfd8SBrian Somers } else 564579abfd8SBrian Somers log_Printf(LogWARN, "Warning: The MS-CHAP2-Success " 565579abfd8SBrian Somers "attribute is mis-formatted. Compensating\n"); 56699cfc2e2SBrian Somers if ((r->msrepstr = rad_cvt_string((const char *)data, 56799cfc2e2SBrian Somers len)) == NULL) { 568a16061b2SBrian Somers log_Printf(LogERROR, "rad_cvt_string: %s\n", 569a16061b2SBrian Somers rad_strerror(r->cx.rad)); 570a16061b2SBrian Somers auth_Failure(r->cx.auth); 571a16061b2SBrian Somers rad_close(r->cx.rad); 572a16061b2SBrian Somers return; 573a16061b2SBrian Somers } 574e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 575e715b13bSBrian Somers " MS-CHAP2-Success \"%s\"\n", r->msrepstr); 576a95b23a6SBrian Somers } 577a16061b2SBrian Somers break; 578a16061b2SBrian Somers 5798fb5ef5aSBrian Somers case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY: 5808fb5ef5aSBrian Somers r->mppe.policy = rad_cvt_int(data); 581e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 582e715b13bSBrian Somers " MS-MPPE-Encryption-Policy %s\n", 5838fb5ef5aSBrian Somers radius_policyname(r->mppe.policy)); 5848fb5ef5aSBrian Somers break; 5858fb5ef5aSBrian Somers 5868fb5ef5aSBrian Somers case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES: 5878fb5ef5aSBrian Somers r->mppe.types = rad_cvt_int(data); 588e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 589e715b13bSBrian Somers " MS-MPPE-Encryption-Types %s\n", 5908fb5ef5aSBrian Somers radius_typesname(r->mppe.types)); 5918fb5ef5aSBrian Somers break; 5928fb5ef5aSBrian Somers 5938fb5ef5aSBrian Somers case RAD_MICROSOFT_MS_MPPE_RECV_KEY: 5948fb5ef5aSBrian Somers free(r->mppe.recvkey); 5958fb5ef5aSBrian Somers demangle(r, data, len, &r->mppe.recvkey, &r->mppe.recvkeylen); 596e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 597e715b13bSBrian Somers " MS-MPPE-Recv-Key ********\n"); 5988fb5ef5aSBrian Somers break; 5998fb5ef5aSBrian Somers 6008fb5ef5aSBrian Somers case RAD_MICROSOFT_MS_MPPE_SEND_KEY: 6018fb5ef5aSBrian Somers demangle(r, data, len, &r->mppe.sendkey, &r->mppe.sendkeylen); 602e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 603e715b13bSBrian Somers " MS-MPPE-Send-Key ********\n"); 6048fb5ef5aSBrian Somers break; 6058fb5ef5aSBrian Somers #endif 6068fb5ef5aSBrian Somers 607ff8e577bSBrian Somers default: 608ff8e577bSBrian Somers log_Printf(LogDEBUG, "Dropping MICROSOFT vendor specific " 609ff8e577bSBrian Somers "RADIUS attribute %d\n", res); 610ff8e577bSBrian Somers break; 611ff8e577bSBrian Somers } 612ff8e577bSBrian Somers break; 613ff8e577bSBrian Somers 614ff8e577bSBrian Somers default: 615ff8e577bSBrian Somers log_Printf(LogDEBUG, "Dropping vendor %lu RADIUS attribute %d\n", 616ff8e577bSBrian Somers (unsigned long)vendor, res); 617ff8e577bSBrian Somers break; 618ff8e577bSBrian Somers } 619ff8e577bSBrian Somers break; 620ff8e577bSBrian Somers 621ff8e577bSBrian Somers default: 622ff8e577bSBrian Somers log_Printf(LogDEBUG, "Dropping RADIUS attribute %d\n", res); 623ff8e577bSBrian Somers break; 624ff8e577bSBrian Somers } 625ff8e577bSBrian Somers } 626ff8e577bSBrian Somers 627ff8e577bSBrian Somers if (res == -1) { 628ff8e577bSBrian Somers log_Printf(LogERROR, "rad_get_attr: %s (failing!)\n", 629ff8e577bSBrian Somers rad_strerror(r->cx.rad)); 630ff8e577bSBrian Somers auth_Failure(r->cx.auth); 631ff8e577bSBrian Somers } else if (got == RAD_ACCESS_REJECT) 632ff8e577bSBrian Somers auth_Failure(r->cx.auth); 633ff8e577bSBrian Somers else { 634f0cdd9c0SBrian Somers r->valid = 1; 635f0cdd9c0SBrian Somers auth_Success(r->cx.auth); 636f0cdd9c0SBrian Somers } 637ff8e577bSBrian Somers rad_close(r->cx.rad); 638972a1bcfSBrian Somers } 639972a1bcfSBrian Somers 640f0cdd9c0SBrian Somers /* 6418e7bd08eSBrian Somers * We've either timed out or select()ed on the read descriptor 642f0cdd9c0SBrian Somers */ 643f0cdd9c0SBrian Somers static void 644f0cdd9c0SBrian Somers radius_Continue(struct radius *r, int sel) 645f0cdd9c0SBrian Somers { 646f0cdd9c0SBrian Somers struct timeval tv; 647f0cdd9c0SBrian Somers int got; 648972a1bcfSBrian Somers 649f0cdd9c0SBrian Somers timer_Stop(&r->cx.timer); 650f0cdd9c0SBrian Somers if ((got = rad_continue_send_request(r->cx.rad, sel, &r->cx.fd, &tv)) == 0) { 651e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 652e715b13bSBrian Somers "Radius: Request re-sent\n"); 653f0cdd9c0SBrian Somers r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS; 654f0cdd9c0SBrian Somers timer_Start(&r->cx.timer); 655f0cdd9c0SBrian Somers return; 656f0cdd9c0SBrian Somers } 657f0cdd9c0SBrian Somers 658f0cdd9c0SBrian Somers radius_Process(r, got); 659f0cdd9c0SBrian Somers } 660f0cdd9c0SBrian Somers 661f0cdd9c0SBrian Somers /* 662f0cdd9c0SBrian Somers * Time to call rad_continue_send_request() - timed out. 663f0cdd9c0SBrian Somers */ 664f0cdd9c0SBrian Somers static void 665f0cdd9c0SBrian Somers radius_Timeout(void *v) 666f0cdd9c0SBrian Somers { 667f0cdd9c0SBrian Somers radius_Continue((struct radius *)v, 0); 668f0cdd9c0SBrian Somers } 669f0cdd9c0SBrian Somers 670f0cdd9c0SBrian Somers /* 671f0cdd9c0SBrian Somers * Time to call rad_continue_send_request() - something to read. 672f0cdd9c0SBrian Somers */ 673f0cdd9c0SBrian Somers static void 674f013f33eSBrian Somers radius_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 675f0cdd9c0SBrian Somers { 676f0cdd9c0SBrian Somers radius_Continue(descriptor2radius(d), 1); 677f0cdd9c0SBrian Somers } 678f0cdd9c0SBrian Somers 679f0cdd9c0SBrian Somers /* 6808e7bd08eSBrian Somers * Behave as a struct fdescriptor (descriptor.h) 681f0cdd9c0SBrian Somers */ 682f0cdd9c0SBrian Somers static int 683f013f33eSBrian Somers radius_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 684f0cdd9c0SBrian Somers { 685f0cdd9c0SBrian Somers struct radius *rad = descriptor2radius(d); 686f0cdd9c0SBrian Somers 687f0cdd9c0SBrian Somers if (r && rad->cx.fd != -1) { 688f0cdd9c0SBrian Somers FD_SET(rad->cx.fd, r); 689f0cdd9c0SBrian Somers if (*n < rad->cx.fd + 1) 690f0cdd9c0SBrian Somers *n = rad->cx.fd + 1; 691f0cdd9c0SBrian Somers log_Printf(LogTIMER, "Radius: fdset(r) %d\n", rad->cx.fd); 69282d6780cSBrian Somers return 1; 693972a1bcfSBrian Somers } 694972a1bcfSBrian Somers 695f0cdd9c0SBrian Somers return 0; 696f0cdd9c0SBrian Somers } 697f0cdd9c0SBrian Somers 698f0cdd9c0SBrian Somers /* 6998e7bd08eSBrian Somers * Behave as a struct fdescriptor (descriptor.h) 700f0cdd9c0SBrian Somers */ 701f0cdd9c0SBrian Somers static int 702f013f33eSBrian Somers radius_IsSet(struct fdescriptor *d, const fd_set *fdset) 703f0cdd9c0SBrian Somers { 704f0cdd9c0SBrian Somers struct radius *r = descriptor2radius(d); 705f0cdd9c0SBrian Somers 706f0cdd9c0SBrian Somers return r && r->cx.fd != -1 && FD_ISSET(r->cx.fd, fdset); 707f0cdd9c0SBrian Somers } 708f0cdd9c0SBrian Somers 709f0cdd9c0SBrian Somers /* 7108e7bd08eSBrian Somers * Behave as a struct fdescriptor (descriptor.h) 711f0cdd9c0SBrian Somers */ 712f0cdd9c0SBrian Somers static int 713f013f33eSBrian Somers radius_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 714f0cdd9c0SBrian Somers { 715f0cdd9c0SBrian Somers /* We never want to write here ! */ 716f0cdd9c0SBrian Somers log_Printf(LogALERT, "radius_Write: Internal error: Bad call !\n"); 717f0cdd9c0SBrian Somers return 0; 718f0cdd9c0SBrian Somers } 719f0cdd9c0SBrian Somers 720f0cdd9c0SBrian Somers /* 721f0cdd9c0SBrian Somers * Initialise ourselves 722f0cdd9c0SBrian Somers */ 723f0cdd9c0SBrian Somers void 724f0cdd9c0SBrian Somers radius_Init(struct radius *r) 725f0cdd9c0SBrian Somers { 726f0cdd9c0SBrian Somers r->desc.type = RADIUS_DESCRIPTOR; 727f0cdd9c0SBrian Somers r->desc.UpdateSet = radius_UpdateSet; 728f0cdd9c0SBrian Somers r->desc.IsSet = radius_IsSet; 729f0cdd9c0SBrian Somers r->desc.Read = radius_Read; 730f0cdd9c0SBrian Somers r->desc.Write = radius_Write; 731ff8e577bSBrian Somers r->cx.fd = -1; 732ff8e577bSBrian Somers r->cx.rad = NULL; 733f0cdd9c0SBrian Somers memset(&r->cx.timer, '\0', sizeof r->cx.timer); 734ff8e577bSBrian Somers r->cx.auth = NULL; 735ff8e577bSBrian Somers r->valid = 0; 736ff8e577bSBrian Somers r->vj = 0; 737ff8e577bSBrian Somers r->ip.s_addr = INADDR_ANY; 738ff8e577bSBrian Somers r->mask.s_addr = INADDR_NONE; 739ff8e577bSBrian Somers r->routes = NULL; 740ff8e577bSBrian Somers r->mtu = DEF_MTU; 741a16061b2SBrian Somers r->msrepstr = NULL; 742ff8e577bSBrian Somers r->repstr = NULL; 7430fe74aa4SHajimu UMEMOTO #ifndef NOINET6 744ec3e98b8SHajimu UMEMOTO r->ipv6prefix = NULL; 7450fe74aa4SHajimu UMEMOTO r->ipv6routes = NULL; 7460fe74aa4SHajimu UMEMOTO #endif 747ff8e577bSBrian Somers r->errstr = NULL; 7488fb5ef5aSBrian Somers r->mppe.policy = 0; 7498fb5ef5aSBrian Somers r->mppe.types = 0; 7508fb5ef5aSBrian Somers r->mppe.recvkey = NULL; 7518fb5ef5aSBrian Somers r->mppe.recvkeylen = 0; 7528fb5ef5aSBrian Somers r->mppe.sendkey = NULL; 7538fb5ef5aSBrian Somers r->mppe.sendkeylen = 0; 754ff8e577bSBrian Somers *r->cfg.file = '\0';; 755794c9bbcSBrian Somers log_Printf(LogDEBUG, "Radius: radius_Init\n"); 756f0cdd9c0SBrian Somers } 757f0cdd9c0SBrian Somers 758f0cdd9c0SBrian Somers /* 759f0cdd9c0SBrian Somers * Forget everything and go back to initialised state. 760f0cdd9c0SBrian Somers */ 761f0cdd9c0SBrian Somers void 762f0cdd9c0SBrian Somers radius_Destroy(struct radius *r) 763f0cdd9c0SBrian Somers { 764f0cdd9c0SBrian Somers r->valid = 0; 765794c9bbcSBrian Somers log_Printf(LogDEBUG, "Radius: radius_Destroy\n"); 766f0cdd9c0SBrian Somers timer_Stop(&r->cx.timer); 767f0cdd9c0SBrian Somers route_DeleteAll(&r->routes); 7680fe74aa4SHajimu UMEMOTO #ifndef NOINET6 7690fe74aa4SHajimu UMEMOTO route_DeleteAll(&r->ipv6routes); 7700fe74aa4SHajimu UMEMOTO #endif 771bf1eaec5SBrian Somers free(r->filterid); 772bf1eaec5SBrian Somers r->filterid = NULL; 773a16061b2SBrian Somers free(r->msrepstr); 774a16061b2SBrian Somers r->msrepstr = NULL; 775ff8e577bSBrian Somers free(r->repstr); 776ff8e577bSBrian Somers r->repstr = NULL; 777ec3e98b8SHajimu UMEMOTO #ifndef NOINET6 778ec3e98b8SHajimu UMEMOTO free(r->ipv6prefix); 779ec3e98b8SHajimu UMEMOTO r->ipv6prefix = NULL; 780ec3e98b8SHajimu UMEMOTO #endif 781ff8e577bSBrian Somers free(r->errstr); 782ff8e577bSBrian Somers r->errstr = NULL; 7838fb5ef5aSBrian Somers free(r->mppe.recvkey); 7848fb5ef5aSBrian Somers r->mppe.recvkey = NULL; 7858fb5ef5aSBrian Somers r->mppe.recvkeylen = 0; 7868fb5ef5aSBrian Somers free(r->mppe.sendkey); 7878fb5ef5aSBrian Somers r->mppe.sendkey = NULL; 7888fb5ef5aSBrian Somers r->mppe.sendkeylen = 0; 789f0cdd9c0SBrian Somers if (r->cx.fd != -1) { 790f0cdd9c0SBrian Somers r->cx.fd = -1; 791f0cdd9c0SBrian Somers rad_close(r->cx.rad); 792f0cdd9c0SBrian Somers } 793f0cdd9c0SBrian Somers } 794f0cdd9c0SBrian Somers 795de59e178SBrian Somers static int 796de59e178SBrian Somers radius_put_physical_details(struct rad_handle *rad, struct physical *p) 797de59e178SBrian Somers { 798de59e178SBrian Somers int slot, type; 799de59e178SBrian Somers 800de59e178SBrian Somers type = RAD_VIRTUAL; 801de59e178SBrian Somers if (p->handler) 802de59e178SBrian Somers switch (p->handler->type) { 803de59e178SBrian Somers case I4B_DEVICE: 804de59e178SBrian Somers type = RAD_ISDN_SYNC; 805de59e178SBrian Somers break; 806de59e178SBrian Somers 807de59e178SBrian Somers case TTY_DEVICE: 808de59e178SBrian Somers type = RAD_ASYNC; 809de59e178SBrian Somers break; 810de59e178SBrian Somers 811de59e178SBrian Somers case ETHER_DEVICE: 812de59e178SBrian Somers type = RAD_ETHERNET; 813de59e178SBrian Somers break; 814de59e178SBrian Somers 815de59e178SBrian Somers case TCP_DEVICE: 816de59e178SBrian Somers case UDP_DEVICE: 817de59e178SBrian Somers case EXEC_DEVICE: 818de59e178SBrian Somers case ATM_DEVICE: 819de59e178SBrian Somers case NG_DEVICE: 820de59e178SBrian Somers type = RAD_VIRTUAL; 821de59e178SBrian Somers break; 822de59e178SBrian Somers } 823de59e178SBrian Somers 824de59e178SBrian Somers if (rad_put_int(rad, RAD_NAS_PORT_TYPE, type) != 0) { 825de59e178SBrian Somers log_Printf(LogERROR, "rad_put: rad_put_int: %s\n", rad_strerror(rad)); 826de59e178SBrian Somers rad_close(rad); 827de59e178SBrian Somers return 0; 828de59e178SBrian Somers } 829de59e178SBrian Somers 830de59e178SBrian Somers if ((slot = physical_Slot(p)) >= 0) 831de59e178SBrian Somers if (rad_put_int(rad, RAD_NAS_PORT, slot) != 0) { 832de59e178SBrian Somers log_Printf(LogERROR, "rad_put: rad_put_int: %s\n", rad_strerror(rad)); 833de59e178SBrian Somers rad_close(rad); 834de59e178SBrian Somers return 0; 835de59e178SBrian Somers } 836de59e178SBrian Somers 837de59e178SBrian Somers return 1; 838de59e178SBrian Somers } 839de59e178SBrian Somers 840f0cdd9c0SBrian Somers /* 841f0cdd9c0SBrian Somers * Start an authentication request to the RADIUS server. 842f0cdd9c0SBrian Somers */ 843a16061b2SBrian Somers int 844f0cdd9c0SBrian Somers radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name, 845a16061b2SBrian Somers const char *key, int klen, const char *nchallenge, 846250be50bSBrian Somers int nclen) 847f0cdd9c0SBrian Somers { 848f0cdd9c0SBrian Somers struct timeval tv; 849de59e178SBrian Somers int got; 85026e6a622SBrian Somers char hostname[MAXHOSTNAMELEN]; 851e715b13bSBrian Somers char *mac_addr, *what; 852aadbb4eaSBrian Somers #if 0 853f10f5203SBrian Somers struct hostent *hp; 854f10f5203SBrian Somers struct in_addr hostaddr; 8558fb5ef5aSBrian Somers #endif 856ff8e577bSBrian Somers #ifndef NODES 857a16061b2SBrian Somers struct mschap_response msresp; 858a16061b2SBrian Somers struct mschap2_response msresp2; 859250be50bSBrian Somers const struct MSCHAPv2_resp *keyv2; 860ff8e577bSBrian Somers #endif 861f0cdd9c0SBrian Somers 862f0cdd9c0SBrian Somers if (!*r->cfg.file) 863a16061b2SBrian Somers return 0; 864f0cdd9c0SBrian Somers 865f0cdd9c0SBrian Somers if (r->cx.fd != -1) 866f0cdd9c0SBrian Somers /* 867f0cdd9c0SBrian Somers * We assume that our name/key/challenge is the same as last time, 868f0cdd9c0SBrian Somers * and just continue to wait for the RADIUS server(s). 869f0cdd9c0SBrian Somers */ 870a16061b2SBrian Somers return 1; 871f0cdd9c0SBrian Somers 872f0cdd9c0SBrian Somers radius_Destroy(r); 873f0cdd9c0SBrian Somers 874794c9bbcSBrian Somers if ((r->cx.rad = rad_auth_open()) == NULL) { 875794c9bbcSBrian Somers log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno)); 876a16061b2SBrian Somers return 0; 877f0cdd9c0SBrian Somers } 878f0cdd9c0SBrian Somers 879f0cdd9c0SBrian Somers if (rad_config(r->cx.rad, r->cfg.file) != 0) { 880f0cdd9c0SBrian Somers log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad)); 881f0cdd9c0SBrian Somers rad_close(r->cx.rad); 882a16061b2SBrian Somers return 0; 883f0cdd9c0SBrian Somers } 884f0cdd9c0SBrian Somers 885f0cdd9c0SBrian Somers if (rad_create_request(r->cx.rad, RAD_ACCESS_REQUEST) != 0) { 886f0cdd9c0SBrian Somers log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad)); 887f0cdd9c0SBrian Somers rad_close(r->cx.rad); 888a16061b2SBrian Somers return 0; 889f0cdd9c0SBrian Somers } 890f0cdd9c0SBrian Somers 8914dc4e1eeSBrian Somers if (rad_put_string(r->cx.rad, RAD_USER_NAME, name) != 0 || 892f0cdd9c0SBrian Somers rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 || 893f0cdd9c0SBrian Somers rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) { 894f0cdd9c0SBrian Somers log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 895f0cdd9c0SBrian Somers rad_close(r->cx.rad); 896a16061b2SBrian Somers return 0; 897f0cdd9c0SBrian Somers } 898f0cdd9c0SBrian Somers 899ff8e577bSBrian Somers switch (authp->physical->link.lcp.want_auth) { 900ff8e577bSBrian Somers case PROTO_PAP: 901ff8e577bSBrian Somers /* We're talking PAP */ 902ff8e577bSBrian Somers if (rad_put_attr(r->cx.rad, RAD_USER_PASSWORD, key, klen) != 0) { 903ff8e577bSBrian Somers log_Printf(LogERROR, "PAP: rad_put_string: %s\n", 904ff8e577bSBrian Somers rad_strerror(r->cx.rad)); 905ff8e577bSBrian Somers rad_close(r->cx.rad); 906a16061b2SBrian Somers return 0; 907ff8e577bSBrian Somers } 908e715b13bSBrian Somers what = "PAP"; 909ff8e577bSBrian Somers break; 910ff8e577bSBrian Somers 911ff8e577bSBrian Somers case PROTO_CHAP: 912ff8e577bSBrian Somers switch (authp->physical->link.lcp.want_authtype) { 913ff8e577bSBrian Somers case 0x5: 91450ca6ec3SBrian Somers if (rad_put_attr(r->cx.rad, RAD_CHAP_PASSWORD, key, klen) != 0 || 915a16061b2SBrian Somers rad_put_attr(r->cx.rad, RAD_CHAP_CHALLENGE, nchallenge, nclen) != 0) { 916f0cdd9c0SBrian Somers log_Printf(LogERROR, "CHAP: rad_put_string: %s\n", 917f0cdd9c0SBrian Somers rad_strerror(r->cx.rad)); 918f0cdd9c0SBrian Somers rad_close(r->cx.rad); 919a16061b2SBrian Somers return 0; 920f0cdd9c0SBrian Somers } 921e715b13bSBrian Somers what = "CHAP"; 922ff8e577bSBrian Somers break; 923ff8e577bSBrian Somers 924ff8e577bSBrian Somers #ifndef NODES 925ff8e577bSBrian Somers case 0x80: 926ff8e577bSBrian Somers if (klen != 50) { 927a16061b2SBrian Somers log_Printf(LogERROR, "CHAP80: Unrecognised key length %d\n", klen); 928f0cdd9c0SBrian Somers rad_close(r->cx.rad); 929a16061b2SBrian Somers return 0; 930f0cdd9c0SBrian Somers } 931a16061b2SBrian Somers 932ff8e577bSBrian Somers rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT, 933a16061b2SBrian Somers RAD_MICROSOFT_MS_CHAP_CHALLENGE, nchallenge, nclen); 934a16061b2SBrian Somers msresp.ident = *key; 935a16061b2SBrian Somers msresp.flags = 0x01; 936a16061b2SBrian Somers memcpy(msresp.lm_response, key + 1, 24); 937a16061b2SBrian Somers memcpy(msresp.nt_response, key + 25, 24); 938ff8e577bSBrian Somers rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT, 939a16061b2SBrian Somers RAD_MICROSOFT_MS_CHAP_RESPONSE, &msresp, 940a16061b2SBrian Somers sizeof msresp); 941e715b13bSBrian Somers what = "MSCHAP"; 942ff8e577bSBrian Somers break; 943ff8e577bSBrian Somers 944ff8e577bSBrian Somers case 0x81: 945250be50bSBrian Somers if (klen != sizeof(*keyv2) + 1) { 946a16061b2SBrian Somers log_Printf(LogERROR, "CHAP81: Unrecognised key length %d\n", klen); 947a16061b2SBrian Somers rad_close(r->cx.rad); 948a16061b2SBrian Somers return 0; 949a16061b2SBrian Somers } 950a16061b2SBrian Somers 951250be50bSBrian Somers keyv2 = (const struct MSCHAPv2_resp *)(key + 1); 952a16061b2SBrian Somers rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT, 953a16061b2SBrian Somers RAD_MICROSOFT_MS_CHAP_CHALLENGE, nchallenge, nclen); 954a16061b2SBrian Somers msresp2.ident = *key; 955250be50bSBrian Somers msresp2.flags = keyv2->Flags; 956250be50bSBrian Somers memcpy(msresp2.response, keyv2->NTResponse, sizeof msresp2.response); 957a16061b2SBrian Somers memset(msresp2.reserved, '\0', sizeof msresp2.reserved); 958250be50bSBrian Somers memcpy(msresp2.pchallenge, keyv2->PeerChallenge, 959250be50bSBrian Somers sizeof msresp2.pchallenge); 960a16061b2SBrian Somers rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT, 961a16061b2SBrian Somers RAD_MICROSOFT_MS_CHAP2_RESPONSE, &msresp2, 962a16061b2SBrian Somers sizeof msresp2); 963e715b13bSBrian Somers what = "MSCHAPv2"; 964a16061b2SBrian Somers break; 965ff8e577bSBrian Somers #endif 966ff8e577bSBrian Somers default: 967ff8e577bSBrian Somers log_Printf(LogERROR, "CHAP: Unrecognised type 0x%02x\n", 968ff8e577bSBrian Somers authp->physical->link.lcp.want_authtype); 969ff8e577bSBrian Somers rad_close(r->cx.rad); 970a16061b2SBrian Somers return 0; 971ff8e577bSBrian Somers } 972ff8e577bSBrian Somers } 973f0cdd9c0SBrian Somers 974f10f5203SBrian Somers if (gethostname(hostname, sizeof hostname) != 0) 975f10f5203SBrian Somers log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno)); 976f10f5203SBrian Somers else { 977aadbb4eaSBrian Somers #if 0 978f10f5203SBrian Somers if ((hp = gethostbyname(hostname)) != NULL) { 979f10f5203SBrian Somers hostaddr.s_addr = *(u_long *)hp->h_addr; 980f10f5203SBrian Somers if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) { 981f10f5203SBrian Somers log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 982f10f5203SBrian Somers rad_strerror(r->cx.rad)); 983f10f5203SBrian Somers rad_close(r->cx.rad); 984a16061b2SBrian Somers return 0; 985f10f5203SBrian Somers } 986f10f5203SBrian Somers } 987aadbb4eaSBrian Somers #endif 988f10f5203SBrian Somers if (rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) { 989f10f5203SBrian Somers log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 990f10f5203SBrian Somers rad_strerror(r->cx.rad)); 991f10f5203SBrian Somers rad_close(r->cx.rad); 992a16061b2SBrian Somers return 0; 993f10f5203SBrian Somers } 994f10f5203SBrian Somers } 995f10f5203SBrian Somers 9965de776b9SBrian Somers if ((mac_addr = getenv("HISMACADDR")) != NULL && 9975de776b9SBrian Somers rad_put_string(r->cx.rad, RAD_CALLING_STATION_ID, mac_addr) != 0) { 9985de776b9SBrian Somers log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 9995de776b9SBrian Somers rad_close(r->cx.rad); 10005de776b9SBrian Somers return; 10015de776b9SBrian Somers } 10025de776b9SBrian Somers 1003de59e178SBrian Somers radius_put_physical_details(r->cx.rad, authp->physical); 1004f10f5203SBrian Somers 1005e715b13bSBrian Somers log_Printf(LogRADIUS, "Radius(auth): %s data sent for %s\n", what, name); 1006e715b13bSBrian Somers 1007c42627ffSBrian Somers r->cx.auth = authp; 1008f0cdd9c0SBrian Somers if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv))) 1009f0cdd9c0SBrian Somers radius_Process(r, got); 1010f0cdd9c0SBrian Somers else { 1011e715b13bSBrian Somers log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, 1012e715b13bSBrian Somers "Radius: Request sent\n"); 1013f0cdd9c0SBrian Somers log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout); 1014f0cdd9c0SBrian Somers r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS; 1015f0cdd9c0SBrian Somers r->cx.timer.func = radius_Timeout; 1016c42627ffSBrian Somers r->cx.timer.name = "radius auth"; 1017f0cdd9c0SBrian Somers r->cx.timer.arg = r; 1018f0cdd9c0SBrian Somers timer_Start(&r->cx.timer); 1019f0cdd9c0SBrian Somers } 1020a16061b2SBrian Somers 1021a16061b2SBrian Somers return 1; 1022f0cdd9c0SBrian Somers } 1023f0cdd9c0SBrian Somers 1024cf7c10d0SHajimu UMEMOTO /* Fetch IP, netmask from IPCP */ 1025cf7c10d0SHajimu UMEMOTO void 1026cf7c10d0SHajimu UMEMOTO radius_Account_Set_Ip(struct radacct *ac, struct in_addr *peer_ip, 1027cf7c10d0SHajimu UMEMOTO struct in_addr *netmask) 1028cf7c10d0SHajimu UMEMOTO { 1029cf7c10d0SHajimu UMEMOTO ac->proto = PROTO_IPCP; 10302cc2a59dSHajimu UMEMOTO memcpy(&ac->peer.ip.addr, peer_ip, sizeof(ac->peer.ip.addr)); 10312cc2a59dSHajimu UMEMOTO memcpy(&ac->peer.ip.mask, netmask, sizeof(ac->peer.ip.mask)); 1032cf7c10d0SHajimu UMEMOTO } 1033cf7c10d0SHajimu UMEMOTO 1034cf7c10d0SHajimu UMEMOTO #ifndef NOINET6 1035cf7c10d0SHajimu UMEMOTO /* Fetch interface-id from IPV6CP */ 1036cf7c10d0SHajimu UMEMOTO void 1037cf7c10d0SHajimu UMEMOTO radius_Account_Set_Ipv6(struct radacct *ac, u_char *ifid) 1038cf7c10d0SHajimu UMEMOTO { 1039cf7c10d0SHajimu UMEMOTO ac->proto = PROTO_IPV6CP; 10402cc2a59dSHajimu UMEMOTO memcpy(&ac->peer.ipv6.ifid, ifid, sizeof(ac->peer.ipv6.ifid)); 1041cf7c10d0SHajimu UMEMOTO } 1042cf7c10d0SHajimu UMEMOTO #endif 1043cf7c10d0SHajimu UMEMOTO 1044f0cdd9c0SBrian Somers /* 1045794c9bbcSBrian Somers * Send an accounting request to the RADIUS server 1046794c9bbcSBrian Somers */ 1047794c9bbcSBrian Somers void 1048794c9bbcSBrian Somers radius_Account(struct radius *r, struct radacct *ac, struct datalink *dl, 1049cf7c10d0SHajimu UMEMOTO int acct_type, struct pppThroughput *stats) 1050794c9bbcSBrian Somers { 1051794c9bbcSBrian Somers struct timeval tv; 1052de59e178SBrian Somers int got; 105326e6a622SBrian Somers char hostname[MAXHOSTNAMELEN]; 10545de776b9SBrian Somers char *mac_addr; 1055aadbb4eaSBrian Somers #if 0 1056794c9bbcSBrian Somers struct hostent *hp; 1057794c9bbcSBrian Somers struct in_addr hostaddr; 10588fb5ef5aSBrian Somers #endif 1059794c9bbcSBrian Somers 1060794c9bbcSBrian Somers if (!*r->cfg.file) 1061794c9bbcSBrian Somers return; 1062794c9bbcSBrian Somers 1063794c9bbcSBrian Somers if (r->cx.fd != -1) 1064794c9bbcSBrian Somers /* 1065794c9bbcSBrian Somers * We assume that our name/key/challenge is the same as last time, 1066794c9bbcSBrian Somers * and just continue to wait for the RADIUS server(s). 1067794c9bbcSBrian Somers */ 1068794c9bbcSBrian Somers return; 1069794c9bbcSBrian Somers 10708fb5ef5aSBrian Somers timer_Stop(&r->cx.timer); 1071794c9bbcSBrian Somers 1072ba093e81SBrian Somers if ((r->cx.rad = rad_acct_open()) == NULL) { 1073794c9bbcSBrian Somers log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno)); 1074794c9bbcSBrian Somers return; 1075794c9bbcSBrian Somers } 1076794c9bbcSBrian Somers 1077794c9bbcSBrian Somers if (rad_config(r->cx.rad, r->cfg.file) != 0) { 1078794c9bbcSBrian Somers log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad)); 1079794c9bbcSBrian Somers rad_close(r->cx.rad); 1080794c9bbcSBrian Somers return; 1081794c9bbcSBrian Somers } 1082794c9bbcSBrian Somers 1083794c9bbcSBrian Somers if (rad_create_request(r->cx.rad, RAD_ACCOUNTING_REQUEST) != 0) { 1084794c9bbcSBrian Somers log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad)); 1085794c9bbcSBrian Somers rad_close(r->cx.rad); 1086794c9bbcSBrian Somers return; 1087794c9bbcSBrian Somers } 1088794c9bbcSBrian Somers 1089794c9bbcSBrian Somers /* Grab some accounting data and initialize structure */ 1090794c9bbcSBrian Somers if (acct_type == RAD_START) { 1091794c9bbcSBrian Somers ac->rad_parent = r; 1092794c9bbcSBrian Somers /* Fetch username from datalink */ 10934dc4e1eeSBrian Somers strncpy(ac->user_name, dl->peer.authname, sizeof ac->user_name); 1094794c9bbcSBrian Somers ac->user_name[AUTHLEN-1] = '\0'; 1095794c9bbcSBrian Somers 1096794c9bbcSBrian Somers ac->authentic = 2; /* Assume RADIUS verified auth data */ 1097794c9bbcSBrian Somers 1098794c9bbcSBrian Somers /* Generate a session ID */ 109912b5aabaSBrian Somers snprintf(ac->session_id, sizeof ac->session_id, "%s%ld-%s%lu", 110012b5aabaSBrian Somers dl->bundle->cfg.auth.name, (long)getpid(), 11014dc4e1eeSBrian Somers dl->peer.authname, (unsigned long)stats->uptime); 1102794c9bbcSBrian Somers 1103794c9bbcSBrian Somers /* And grab our MP socket name */ 1104794c9bbcSBrian Somers snprintf(ac->multi_session_id, sizeof ac->multi_session_id, "%s", 1105794c9bbcSBrian Somers dl->bundle->ncp.mp.active ? 1106794c9bbcSBrian Somers dl->bundle->ncp.mp.server.socket.sun_path : ""); 1107794c9bbcSBrian Somers }; 1108794c9bbcSBrian Somers 1109794c9bbcSBrian Somers if (rad_put_string(r->cx.rad, RAD_USER_NAME, ac->user_name) != 0 || 1110794c9bbcSBrian Somers rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 || 1111cf7c10d0SHajimu UMEMOTO rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) { 1112794c9bbcSBrian Somers log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 1113794c9bbcSBrian Somers rad_close(r->cx.rad); 1114794c9bbcSBrian Somers return; 1115794c9bbcSBrian Somers } 1116cf7c10d0SHajimu UMEMOTO switch (ac->proto) { 1117cf7c10d0SHajimu UMEMOTO case PROTO_IPCP: 11182cc2a59dSHajimu UMEMOTO if (rad_put_addr(r->cx.rad, RAD_FRAMED_IP_ADDRESS, 11197cbe2606SBrian Somers ac->peer.ip.addr) != 0 || 11202cc2a59dSHajimu UMEMOTO rad_put_addr(r->cx.rad, RAD_FRAMED_IP_NETMASK, 11212cc2a59dSHajimu UMEMOTO ac->peer.ip.mask) != 0) { 1122cf7c10d0SHajimu UMEMOTO log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 1123cf7c10d0SHajimu UMEMOTO rad_close(r->cx.rad); 1124cf7c10d0SHajimu UMEMOTO return; 1125cf7c10d0SHajimu UMEMOTO } 1126cf7c10d0SHajimu UMEMOTO break; 1127cf7c10d0SHajimu UMEMOTO #ifndef NOINET6 1128cf7c10d0SHajimu UMEMOTO case PROTO_IPV6CP: 11292cc2a59dSHajimu UMEMOTO if (rad_put_attr(r->cx.rad, RAD_FRAMED_INTERFACE_ID, ac->peer.ipv6.ifid, 11302cc2a59dSHajimu UMEMOTO sizeof(ac->peer.ipv6.ifid)) != 0) { 1131cf7c10d0SHajimu UMEMOTO log_Printf(LogERROR, "rad_put_attr: %s\n", rad_strerror(r->cx.rad)); 1132cf7c10d0SHajimu UMEMOTO rad_close(r->cx.rad); 1133cf7c10d0SHajimu UMEMOTO return; 1134cf7c10d0SHajimu UMEMOTO } 1135ec3e98b8SHajimu UMEMOTO if (r->ipv6prefix) { 1136ec3e98b8SHajimu UMEMOTO /* 1137ec3e98b8SHajimu UMEMOTO * Since PPP doesn't delegate an IPv6 prefix to a peer, 1138ec3e98b8SHajimu UMEMOTO * Framed-IPv6-Prefix may be not used, actually. 1139ec3e98b8SHajimu UMEMOTO */ 1140ec3e98b8SHajimu UMEMOTO if (rad_put_attr(r->cx.rad, RAD_FRAMED_IPV6_PREFIX, r->ipv6prefix, 1141ec3e98b8SHajimu UMEMOTO sizeof(struct in6_addr) + 2) != 0) { 1142ec3e98b8SHajimu UMEMOTO log_Printf(LogERROR, "rad_put_attr: %s\n", rad_strerror(r->cx.rad)); 1143ec3e98b8SHajimu UMEMOTO rad_close(r->cx.rad); 1144ec3e98b8SHajimu UMEMOTO return; 1145ec3e98b8SHajimu UMEMOTO } 1146ec3e98b8SHajimu UMEMOTO } 1147cf7c10d0SHajimu UMEMOTO break; 1148cf7c10d0SHajimu UMEMOTO #endif 1149cf7c10d0SHajimu UMEMOTO default: 1150cf7c10d0SHajimu UMEMOTO /* We don't log any protocol specific information */ 1151cf7c10d0SHajimu UMEMOTO break; 1152cf7c10d0SHajimu UMEMOTO } 1153794c9bbcSBrian Somers 11545de776b9SBrian Somers if ((mac_addr = getenv("HISMACADDR")) != NULL && 11555de776b9SBrian Somers rad_put_string(r->cx.rad, RAD_CALLING_STATION_ID, mac_addr) != 0) { 11565de776b9SBrian Somers log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 11575de776b9SBrian Somers rad_close(r->cx.rad); 11585de776b9SBrian Somers return; 11595de776b9SBrian Somers } 11605de776b9SBrian Somers 1161794c9bbcSBrian Somers if (gethostname(hostname, sizeof hostname) != 0) 1162794c9bbcSBrian Somers log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno)); 1163794c9bbcSBrian Somers else { 1164aadbb4eaSBrian Somers #if 0 1165794c9bbcSBrian Somers if ((hp = gethostbyname(hostname)) != NULL) { 1166794c9bbcSBrian Somers hostaddr.s_addr = *(u_long *)hp->h_addr; 1167794c9bbcSBrian Somers if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) { 1168794c9bbcSBrian Somers log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 1169794c9bbcSBrian Somers rad_strerror(r->cx.rad)); 1170794c9bbcSBrian Somers rad_close(r->cx.rad); 1171794c9bbcSBrian Somers return; 1172794c9bbcSBrian Somers } 1173794c9bbcSBrian Somers } 1174aadbb4eaSBrian Somers #endif 1175794c9bbcSBrian Somers if (rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) { 1176794c9bbcSBrian Somers log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 1177794c9bbcSBrian Somers rad_strerror(r->cx.rad)); 1178794c9bbcSBrian Somers rad_close(r->cx.rad); 1179794c9bbcSBrian Somers return; 1180794c9bbcSBrian Somers } 1181794c9bbcSBrian Somers } 1182794c9bbcSBrian Somers 1183de59e178SBrian Somers radius_put_physical_details(r->cx.rad, dl->physical); 1184794c9bbcSBrian Somers 1185794c9bbcSBrian Somers if (rad_put_int(r->cx.rad, RAD_ACCT_STATUS_TYPE, acct_type) != 0 || 1186794c9bbcSBrian Somers rad_put_string(r->cx.rad, RAD_ACCT_SESSION_ID, ac->session_id) != 0 || 1187794c9bbcSBrian Somers rad_put_string(r->cx.rad, RAD_ACCT_MULTI_SESSION_ID, 1188794c9bbcSBrian Somers ac->multi_session_id) != 0 || 1189794c9bbcSBrian Somers rad_put_int(r->cx.rad, RAD_ACCT_DELAY_TIME, 0) != 0) { 1190794c9bbcSBrian Somers /* XXX ACCT_DELAY_TIME should be increased each time a packet is waiting */ 1191794c9bbcSBrian Somers log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 1192794c9bbcSBrian Somers rad_close(r->cx.rad); 1193794c9bbcSBrian Somers return; 1194794c9bbcSBrian Somers } 1195794c9bbcSBrian Somers 1196e715b13bSBrian Somers if (acct_type == RAD_STOP || acct_type == RAD_ALIVE) 1197794c9bbcSBrian Somers /* Show some statistics */ 1198dfb3194aSDiomidis Spinellis if (rad_put_int(r->cx.rad, RAD_ACCT_INPUT_OCTETS, stats->OctetsIn % UINT32_MAX) != 0 || 1199dfb3194aSDiomidis Spinellis rad_put_int(r->cx.rad, RAD_ACCT_INPUT_GIGAWORDS, stats->OctetsIn / UINT32_MAX) != 0 || 1200794c9bbcSBrian Somers rad_put_int(r->cx.rad, RAD_ACCT_INPUT_PACKETS, stats->PacketsIn) != 0 || 1201dfb3194aSDiomidis Spinellis rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_OCTETS, stats->OctetsOut % UINT32_MAX) != 0 || 1202dfb3194aSDiomidis Spinellis rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_GIGAWORDS, stats->OctetsOut / UINT32_MAX) != 0 || 1203794c9bbcSBrian Somers rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_PACKETS, stats->PacketsOut) 1204794c9bbcSBrian Somers != 0 || 1205794c9bbcSBrian Somers rad_put_int(r->cx.rad, RAD_ACCT_SESSION_TIME, throughput_uptime(stats)) 1206794c9bbcSBrian Somers != 0) { 1207794c9bbcSBrian Somers log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 1208794c9bbcSBrian Somers rad_close(r->cx.rad); 1209794c9bbcSBrian Somers return; 1210794c9bbcSBrian Somers } 1211794c9bbcSBrian Somers 1212e715b13bSBrian Somers if (log_IsKept(LogPHASE) || log_IsKept(LogRADIUS)) { 1213e715b13bSBrian Somers char *what; 1214e715b13bSBrian Somers int level; 1215e715b13bSBrian Somers 1216e715b13bSBrian Somers switch (acct_type) { 1217e715b13bSBrian Somers case RAD_START: 1218e715b13bSBrian Somers what = "START"; 1219e715b13bSBrian Somers level = log_IsKept(LogPHASE) ? LogPHASE : LogRADIUS; 1220e715b13bSBrian Somers break; 1221e715b13bSBrian Somers case RAD_STOP: 1222e715b13bSBrian Somers what = "STOP"; 1223e715b13bSBrian Somers level = log_IsKept(LogPHASE) ? LogPHASE : LogRADIUS; 1224e715b13bSBrian Somers break; 1225e715b13bSBrian Somers case RAD_ALIVE: 1226e715b13bSBrian Somers what = "ALIVE"; 1227e715b13bSBrian Somers level = LogRADIUS; 1228e715b13bSBrian Somers break; 1229e715b13bSBrian Somers default: 1230e715b13bSBrian Somers what = "<unknown>"; 1231e715b13bSBrian Somers level = log_IsKept(LogPHASE) ? LogPHASE : LogRADIUS; 1232e715b13bSBrian Somers break; 1233e715b13bSBrian Somers } 1234e715b13bSBrian Somers log_Printf(level, "Radius(acct): %s data sent\n", what); 1235e715b13bSBrian Somers } 1236e715b13bSBrian Somers 1237c42627ffSBrian Somers r->cx.auth = NULL; /* Not valid for accounting requests */ 1238794c9bbcSBrian Somers if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv))) 1239794c9bbcSBrian Somers radius_Process(r, got); 1240794c9bbcSBrian Somers else { 1241794c9bbcSBrian Somers log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout); 1242794c9bbcSBrian Somers r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS; 1243794c9bbcSBrian Somers r->cx.timer.func = radius_Timeout; 1244c42627ffSBrian Somers r->cx.timer.name = "radius acct"; 1245794c9bbcSBrian Somers r->cx.timer.arg = r; 1246794c9bbcSBrian Somers timer_Start(&r->cx.timer); 1247794c9bbcSBrian Somers } 1248794c9bbcSBrian Somers } 1249794c9bbcSBrian Somers 1250794c9bbcSBrian Somers /* 1251f0cdd9c0SBrian Somers * How do things look at the moment ? 1252f0cdd9c0SBrian Somers */ 1253972a1bcfSBrian Somers void 1254972a1bcfSBrian Somers radius_Show(struct radius *r, struct prompt *p) 1255972a1bcfSBrian Somers { 125674457d3dSBrian Somers prompt_Printf(p, " Radius config: %s", 125774457d3dSBrian Somers *r->cfg.file ? r->cfg.file : "none"); 1258972a1bcfSBrian Somers if (r->valid) { 1259972a1bcfSBrian Somers prompt_Printf(p, "\n IP: %s\n", inet_ntoa(r->ip)); 1260972a1bcfSBrian Somers prompt_Printf(p, " Netmask: %s\n", inet_ntoa(r->mask)); 1261972a1bcfSBrian Somers prompt_Printf(p, " MTU: %lu\n", r->mtu); 1262972a1bcfSBrian Somers prompt_Printf(p, " VJ: %sabled\n", r->vj ? "en" : "dis"); 1263ff8e577bSBrian Somers prompt_Printf(p, " Message: %s\n", r->repstr ? r->repstr : ""); 12648fb5ef5aSBrian Somers prompt_Printf(p, " MPPE Enc Policy: %s\n", 12658fb5ef5aSBrian Somers radius_policyname(r->mppe.policy)); 12668fb5ef5aSBrian Somers prompt_Printf(p, " MPPE Enc Types: %s\n", 12678fb5ef5aSBrian Somers radius_typesname(r->mppe.types)); 12688fb5ef5aSBrian Somers prompt_Printf(p, " MPPE Recv Key: %seceived\n", 12698fb5ef5aSBrian Somers r->mppe.recvkey ? "R" : "Not r"); 12708fb5ef5aSBrian Somers prompt_Printf(p, " MPPE Send Key: %seceived\n", 12718fb5ef5aSBrian Somers r->mppe.sendkey ? "R" : "Not r"); 1272a16061b2SBrian Somers prompt_Printf(p, " MS-CHAP2-Response: %s\n", 1273a16061b2SBrian Somers r->msrepstr ? r->msrepstr : ""); 1274ff8e577bSBrian Somers prompt_Printf(p, " Error Message: %s\n", r->errstr ? r->errstr : ""); 1275972a1bcfSBrian Somers if (r->routes) 1276972a1bcfSBrian Somers route_ShowSticky(p, r->routes, " Routes", 16); 12770fe74aa4SHajimu UMEMOTO #ifndef NOINET6 12780fe74aa4SHajimu UMEMOTO if (r->ipv6routes) 12790fe74aa4SHajimu UMEMOTO route_ShowSticky(p, r->ipv6routes, " IPv6 Routes", 16); 12800fe74aa4SHajimu UMEMOTO #endif 1281972a1bcfSBrian Somers } else 1282972a1bcfSBrian Somers prompt_Printf(p, " (not authenticated)\n"); 1283972a1bcfSBrian Somers } 1284e715b13bSBrian Somers 1285e715b13bSBrian Somers static void 1286e715b13bSBrian Somers radius_alive(void *v) 1287e715b13bSBrian Somers { 1288e715b13bSBrian Somers struct bundle *bundle = (struct bundle *)v; 1289e715b13bSBrian Somers 1290e715b13bSBrian Somers timer_Stop(&bundle->radius.alive.timer); 1291e715b13bSBrian Somers bundle->radius.alive.timer.load = bundle->radius.alive.interval * SECTICKS; 1292e715b13bSBrian Somers if (bundle->radius.alive.timer.load) { 1293e715b13bSBrian Somers radius_Account(&bundle->radius, &bundle->radacct, 1294e715b13bSBrian Somers bundle->links, RAD_ALIVE, &bundle->ncp.ipcp.throughput); 1295e715b13bSBrian Somers timer_Start(&bundle->radius.alive.timer); 1296e715b13bSBrian Somers } 1297e715b13bSBrian Somers } 1298e715b13bSBrian Somers 1299e715b13bSBrian Somers void 1300e715b13bSBrian Somers radius_StartTimer(struct bundle *bundle) 1301e715b13bSBrian Somers { 1302e715b13bSBrian Somers if (bundle->radius.cfg.file && bundle->radius.alive.interval) { 1303e715b13bSBrian Somers bundle->radius.alive.timer.func = radius_alive; 1304e715b13bSBrian Somers bundle->radius.alive.timer.name = "radius alive"; 1305e715b13bSBrian Somers bundle->radius.alive.timer.load = bundle->radius.alive.interval * SECTICKS; 1306e715b13bSBrian Somers bundle->radius.alive.timer.arg = bundle; 1307e715b13bSBrian Somers radius_alive(bundle); 1308e715b13bSBrian Somers } 1309e715b13bSBrian Somers } 1310e715b13bSBrian Somers 1311e715b13bSBrian Somers void 1312e715b13bSBrian Somers radius_StopTimer(struct radius *r) 1313e715b13bSBrian Somers { 1314e715b13bSBrian Somers timer_Stop(&r->alive.timer); 1315e715b13bSBrian Somers } 1316