11de7b4b8SPedro F. Giffuni /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni *
4972a1bcfSBrian Somers * Copyright 1999 Internet Business Solutions Ltd., Switzerland
5972a1bcfSBrian Somers * All rights reserved.
6972a1bcfSBrian Somers *
7972a1bcfSBrian Somers * Redistribution and use in source and binary forms, with or without
8972a1bcfSBrian Somers * modification, are permitted provided that the following conditions
9972a1bcfSBrian Somers * are met:
10972a1bcfSBrian Somers * 1. Redistributions of source code must retain the above copyright
11972a1bcfSBrian Somers * notice, this list of conditions and the following disclaimer.
12972a1bcfSBrian Somers * 2. Redistributions in binary form must reproduce the above copyright
13972a1bcfSBrian Somers * notice, this list of conditions and the following disclaimer in the
14972a1bcfSBrian Somers * documentation and/or other materials provided with the distribution.
15972a1bcfSBrian Somers *
16972a1bcfSBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17972a1bcfSBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18972a1bcfSBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19972a1bcfSBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20972a1bcfSBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21972a1bcfSBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22972a1bcfSBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23972a1bcfSBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24972a1bcfSBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25972a1bcfSBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26972a1bcfSBrian Somers * SUCH DAMAGE.
27972a1bcfSBrian Somers *
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 *
radius_policyname(int policy)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 *
radius_typesname(int types)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
demangle(struct radius * r,const void * mangled,size_t mlen,char ** buf,size_t * len)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 *
rad_cvt_ipv6prefix(const void * data,size_t len)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
radius_Process(struct radius * r,int got)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
radius_Continue(struct radius * r,int sel)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
radius_Timeout(void * v)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
radius_Read(struct fdescriptor * d,struct bundle * bundle __unused,const fd_set * fdset __unused)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
radius_Flush(struct radius * r)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
radius_UpdateSet(struct fdescriptor * d,fd_set * r,fd_set * w __unused,fd_set * e __unused,int * n)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
radius_IsSet(struct fdescriptor * d,const fd_set * fdset)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
radius_Write(struct fdescriptor * d __unused,struct bundle * bundle __unused,const fd_set * fdset __unused)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
radius_Init(struct radius * r)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;
787db702c59SEitan Adler *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
radius_Destroy(struct radius * r)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
radius_put_physical_details(struct radius * rad,struct physical * p)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
radius_Authenticate(struct radius * r,struct authinfo * authp,const char * name,const char * key,int klen,const char * nchallenge,int nclen)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
radius_Account_Set_Ip(struct radacct * ac,struct in_addr * peer_ip,struct in_addr * netmask)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
radius_Account_Set_Ipv6(struct radacct * ac,u_char * ifid)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
radius_Account(struct radius * r,struct radacct * ac,struct datalink * dl,int acct_type,struct pppThroughput * stats)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 : "");
115380c7cc1cSPedro F. Giffuni }
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
radius_Show(struct radius * r,struct prompt * p)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
radius_alive(void * v)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
radius_StartTimer(struct bundle * bundle)1346e715b13bSBrian Somers radius_StartTimer(struct bundle *bundle)
1347e715b13bSBrian Somers {
13489304cfd0SDimitry Andric 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
radius_StopTimer(struct radius * r)1358e715b13bSBrian Somers radius_StopTimer(struct radius *r)
1359e715b13bSBrian Somers {
1360e715b13bSBrian Somers timer_Stop(&r->alive.timer);
1361e715b13bSBrian Somers }
1362