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