xref: /freebsd/usr.sbin/ppp/radius.c (revision 2cc2a59d853313fa17f65af4402d3ab8f36fbe75)
1972a1bcfSBrian Somers /*
2972a1bcfSBrian Somers  * Copyright 1999 Internet Business Solutions Ltd., Switzerland
3972a1bcfSBrian Somers  * All rights reserved.
4972a1bcfSBrian Somers  *
5972a1bcfSBrian Somers  * Redistribution and use in source and binary forms, with or without
6972a1bcfSBrian Somers  * modification, are permitted provided that the following conditions
7972a1bcfSBrian Somers  * are met:
8972a1bcfSBrian Somers  * 1. Redistributions of source code must retain the above copyright
9972a1bcfSBrian Somers  *    notice, this list of conditions and the following disclaimer.
10972a1bcfSBrian Somers  * 2. Redistributions in binary form must reproduce the above copyright
11972a1bcfSBrian Somers  *    notice, this list of conditions and the following disclaimer in the
12972a1bcfSBrian Somers  *    documentation and/or other materials provided with the distribution.
13972a1bcfSBrian Somers  *
14972a1bcfSBrian Somers  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15972a1bcfSBrian Somers  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16972a1bcfSBrian Somers  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17972a1bcfSBrian Somers  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18972a1bcfSBrian Somers  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19972a1bcfSBrian Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20972a1bcfSBrian Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21972a1bcfSBrian Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22972a1bcfSBrian Somers  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23972a1bcfSBrian Somers  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24972a1bcfSBrian Somers  * SUCH DAMAGE.
25972a1bcfSBrian Somers  *
2697d92980SPeter Wemm  * $FreeBSD$
27972a1bcfSBrian Somers  *
28972a1bcfSBrian Somers  */
29972a1bcfSBrian Somers 
30972a1bcfSBrian Somers #include <sys/param.h>
318fb5ef5aSBrian Somers 
326b457978SBrian Somers #include <sys/socket.h>
33972a1bcfSBrian Somers #include <netinet/in_systm.h>
34972a1bcfSBrian Somers #include <netinet/in.h>
35972a1bcfSBrian Somers #include <netinet/ip.h>
36972a1bcfSBrian Somers #include <arpa/inet.h>
37972a1bcfSBrian Somers #include <sys/un.h>
386b457978SBrian Somers #include <net/route.h>
39972a1bcfSBrian Somers 
4010e629b9SBrian Somers #ifdef LOCALRAD
4110e629b9SBrian Somers #include "radlib.h"
42ff8e577bSBrian Somers #include "radlib_vs.h"
4310e629b9SBrian Somers #else
44972a1bcfSBrian Somers #include <radlib.h>
45ff8e577bSBrian Somers #include <radlib_vs.h>
4610e629b9SBrian Somers #endif
4710e629b9SBrian Somers 
4810e629b9SBrian Somers #include <errno.h>
498fb5ef5aSBrian Somers #ifndef NODES
508fb5ef5aSBrian Somers #include <md5.h>
518fb5ef5aSBrian Somers #endif
526eafd353SBrian Somers #include <stdarg.h>
53972a1bcfSBrian Somers #include <stdio.h>
54972a1bcfSBrian Somers #include <stdlib.h>
55972a1bcfSBrian Somers #include <string.h>
56f0cdd9c0SBrian Somers #include <sys/time.h>
57972a1bcfSBrian Somers #include <termios.h>
58f10f5203SBrian Somers #include <unistd.h>
59f10f5203SBrian Somers #include <netdb.h>
60972a1bcfSBrian Somers 
615d9e6103SBrian Somers #include "layer.h"
62972a1bcfSBrian Somers #include "defs.h"
63972a1bcfSBrian Somers #include "log.h"
64972a1bcfSBrian Somers #include "descriptor.h"
65972a1bcfSBrian Somers #include "prompt.h"
66972a1bcfSBrian Somers #include "timer.h"
67972a1bcfSBrian Somers #include "fsm.h"
68972a1bcfSBrian Somers #include "iplist.h"
69972a1bcfSBrian Somers #include "slcompress.h"
70972a1bcfSBrian Somers #include "throughput.h"
71972a1bcfSBrian Somers #include "lqr.h"
72972a1bcfSBrian Somers #include "hdlc.h"
73972a1bcfSBrian Somers #include "mbuf.h"
7430949fd4SBrian Somers #include "ncpaddr.h"
7530949fd4SBrian Somers #include "ip.h"
76972a1bcfSBrian Somers #include "ipcp.h"
7730949fd4SBrian Somers #include "ipv6cp.h"
78972a1bcfSBrian Somers #include "route.h"
79972a1bcfSBrian Somers #include "command.h"
80972a1bcfSBrian Somers #include "filter.h"
81972a1bcfSBrian Somers #include "lcp.h"
82972a1bcfSBrian Somers #include "ccp.h"
83972a1bcfSBrian Somers #include "link.h"
84972a1bcfSBrian Somers #include "mp.h"
85972a1bcfSBrian Somers #include "radius.h"
86f0cdd9c0SBrian Somers #include "auth.h"
87f0cdd9c0SBrian Somers #include "async.h"
88f0cdd9c0SBrian Somers #include "physical.h"
89f0cdd9c0SBrian Somers #include "chat.h"
90f0cdd9c0SBrian Somers #include "cbcp.h"
91f0cdd9c0SBrian Somers #include "chap.h"
92f0cdd9c0SBrian Somers #include "datalink.h"
9330949fd4SBrian Somers #include "ncp.h"
94972a1bcfSBrian Somers #include "bundle.h"
95ff8e577bSBrian Somers #include "proto.h"
96ff8e577bSBrian Somers 
97ff8e577bSBrian Somers #ifndef NODES
98a16061b2SBrian Somers struct mschap_response {
99ff8e577bSBrian Somers   u_char ident;
100ff8e577bSBrian Somers   u_char flags;
101ff8e577bSBrian Somers   u_char lm_response[24];
102ff8e577bSBrian Somers   u_char nt_response[24];
103ff8e577bSBrian Somers };
104a16061b2SBrian Somers 
105a16061b2SBrian Somers struct mschap2_response {
106a16061b2SBrian Somers   u_char ident;
107a16061b2SBrian Somers   u_char flags;
108a16061b2SBrian Somers   u_char pchallenge[16];
109a16061b2SBrian Somers   u_char reserved[8];
110a16061b2SBrian Somers   u_char response[24];
111a16061b2SBrian Somers };
1128fb5ef5aSBrian Somers 
1138fb5ef5aSBrian Somers #define	AUTH_LEN	16
1148fb5ef5aSBrian Somers #define	SALT_LEN	2
1158fb5ef5aSBrian Somers #endif
1168fb5ef5aSBrian Somers 
1178fb5ef5aSBrian Somers static const char *
1188fb5ef5aSBrian Somers radius_policyname(int policy)
1198fb5ef5aSBrian Somers {
1208fb5ef5aSBrian Somers   switch(policy) {
1218fb5ef5aSBrian Somers   case MPPE_POLICY_ALLOWED:
1228fb5ef5aSBrian Somers     return "Allowed";
1238fb5ef5aSBrian Somers   case MPPE_POLICY_REQUIRED:
1248fb5ef5aSBrian Somers     return "Required";
1258fb5ef5aSBrian Somers   }
1268fb5ef5aSBrian Somers   return NumStr(policy, NULL, 0);
1278fb5ef5aSBrian Somers }
1288fb5ef5aSBrian Somers 
1298fb5ef5aSBrian Somers static const char *
1308fb5ef5aSBrian Somers radius_typesname(int types)
1318fb5ef5aSBrian Somers {
1328fb5ef5aSBrian Somers   switch(types) {
1338fb5ef5aSBrian Somers   case MPPE_TYPE_40BIT:
1348fb5ef5aSBrian Somers     return "40 bit";
1358fb5ef5aSBrian Somers   case MPPE_TYPE_128BIT:
1368fb5ef5aSBrian Somers     return "128 bit";
1378fb5ef5aSBrian Somers   case MPPE_TYPE_40BIT|MPPE_TYPE_128BIT:
1388fb5ef5aSBrian Somers     return "40 or 128 bit";
1398fb5ef5aSBrian Somers   }
1408fb5ef5aSBrian Somers   return NumStr(types, NULL, 0);
1418fb5ef5aSBrian Somers }
1428fb5ef5aSBrian Somers 
1438fb5ef5aSBrian Somers #ifndef NODES
1448fb5ef5aSBrian Somers static void
1458fb5ef5aSBrian Somers demangle(struct radius *r, const void *mangled, size_t mlen,
1468fb5ef5aSBrian Somers          char **buf, size_t *len)
1478fb5ef5aSBrian Somers {
1488fb5ef5aSBrian Somers   char R[AUTH_LEN];		/* variable names as per rfc2548 */
1498fb5ef5aSBrian Somers   const char *S;
1508fb5ef5aSBrian Somers   u_char b[16];
1518fb5ef5aSBrian Somers   const u_char *A, *C;
1528fb5ef5aSBrian Somers   MD5_CTX Context;
1538fb5ef5aSBrian Somers   int Slen, i, Clen, Ppos;
1548fb5ef5aSBrian Somers   u_char *P;
1558fb5ef5aSBrian Somers 
1568fb5ef5aSBrian Somers   if (mlen % 16 != SALT_LEN) {
1578fb5ef5aSBrian Somers     log_Printf(LogWARN, "Cannot interpret mangled data of length %ld\n",
1588fb5ef5aSBrian Somers                (u_long)mlen);
1598fb5ef5aSBrian Somers     *buf = NULL;
1608fb5ef5aSBrian Somers     *len = 0;
1618fb5ef5aSBrian Somers     return;
1628fb5ef5aSBrian Somers   }
1638fb5ef5aSBrian Somers 
1648fb5ef5aSBrian Somers   /* We need the RADIUS Request-Authenticator */
1658fb5ef5aSBrian Somers   if (rad_request_authenticator(r->cx.rad, R, sizeof R) != AUTH_LEN) {
1668fb5ef5aSBrian Somers     log_Printf(LogWARN, "Cannot obtain the RADIUS request authenticator\n");
1678fb5ef5aSBrian Somers     *buf = NULL;
1688fb5ef5aSBrian Somers     *len = 0;
1698fb5ef5aSBrian Somers     return;
1708fb5ef5aSBrian Somers   }
1718fb5ef5aSBrian Somers 
1728fb5ef5aSBrian Somers   A = (const u_char *)mangled;			/* Salt comes first */
1738fb5ef5aSBrian Somers   C = (const u_char *)mangled + SALT_LEN;	/* Then the ciphertext */
1748fb5ef5aSBrian Somers   Clen = mlen - SALT_LEN;
1758fb5ef5aSBrian Somers   S = rad_server_secret(r->cx.rad);		/* We need the RADIUS secret */
1768fb5ef5aSBrian Somers   Slen = strlen(S);
1778fb5ef5aSBrian Somers   P = alloca(Clen);				/* We derive our plaintext */
1788fb5ef5aSBrian Somers 
1798fb5ef5aSBrian Somers   MD5Init(&Context);
1808fb5ef5aSBrian Somers   MD5Update(&Context, S, Slen);
1818fb5ef5aSBrian Somers   MD5Update(&Context, R, AUTH_LEN);
1828fb5ef5aSBrian Somers   MD5Update(&Context, A, SALT_LEN);
1838fb5ef5aSBrian Somers   MD5Final(b, &Context);
1848fb5ef5aSBrian Somers   Ppos = 0;
1858fb5ef5aSBrian Somers 
1868fb5ef5aSBrian Somers   while (Clen) {
1878fb5ef5aSBrian Somers     Clen -= 16;
1888fb5ef5aSBrian Somers 
1898fb5ef5aSBrian Somers     for (i = 0; i < 16; i++)
1908fb5ef5aSBrian Somers       P[Ppos++] = C[i] ^ b[i];
1918fb5ef5aSBrian Somers 
1928fb5ef5aSBrian Somers     if (Clen) {
1938fb5ef5aSBrian Somers       MD5Init(&Context);
1948fb5ef5aSBrian Somers       MD5Update(&Context, S, Slen);
1958fb5ef5aSBrian Somers       MD5Update(&Context, C, 16);
1968fb5ef5aSBrian Somers       MD5Final(b, &Context);
1978fb5ef5aSBrian Somers     }
1988fb5ef5aSBrian Somers 
1998fb5ef5aSBrian Somers     C += 16;
2008fb5ef5aSBrian Somers   }
2018fb5ef5aSBrian Somers 
2028fb5ef5aSBrian Somers   /*
2038fb5ef5aSBrian Somers    * The resulting plain text consists of a one-byte length, the text and
2048fb5ef5aSBrian Somers    * maybe some padding.
2058fb5ef5aSBrian Somers    */
2068fb5ef5aSBrian Somers   *len = *P;
2078fb5ef5aSBrian Somers   if (*len > mlen - 1) {
2088fb5ef5aSBrian Somers     log_Printf(LogWARN, "Mangled data seems to be garbage\n");
2098fb5ef5aSBrian Somers     *buf = NULL;
2108fb5ef5aSBrian Somers     *len = 0;
2118fb5ef5aSBrian Somers     return;
2128fb5ef5aSBrian Somers   }
2138fb5ef5aSBrian Somers 
2148fb5ef5aSBrian Somers   *buf = malloc(*len);
2158fb5ef5aSBrian Somers   memcpy(*buf, P + 1, *len);
2168fb5ef5aSBrian Somers }
217ff8e577bSBrian Somers #endif
218972a1bcfSBrian Somers 
219ec3e98b8SHajimu UMEMOTO /* XXX: This should go into librarius. */
220ec3e98b8SHajimu UMEMOTO #ifndef NOINET6
221ec3e98b8SHajimu UMEMOTO static uint8_t *
222ec3e98b8SHajimu UMEMOTO rad_cvt_ipv6prefix(const void *data, size_t len)
223ec3e98b8SHajimu UMEMOTO {
224ec3e98b8SHajimu UMEMOTO 	const size_t ipv6len = sizeof(struct in6_addr) + 2;
225ec3e98b8SHajimu UMEMOTO 	uint8_t *s;
226ec3e98b8SHajimu UMEMOTO 
227ec3e98b8SHajimu UMEMOTO 	if (len > ipv6len)
228ec3e98b8SHajimu UMEMOTO 		return NULL;
229ec3e98b8SHajimu UMEMOTO 	s = malloc(ipv6len);
230ec3e98b8SHajimu UMEMOTO 	if (s != NULL) {
231ec3e98b8SHajimu UMEMOTO 		memset(s, 0, ipv6len);
232ec3e98b8SHajimu UMEMOTO 		memcpy(s, data, len);
233ec3e98b8SHajimu UMEMOTO 	}
234ec3e98b8SHajimu UMEMOTO 	return s;
235ec3e98b8SHajimu UMEMOTO }
236ec3e98b8SHajimu UMEMOTO #endif
237ec3e98b8SHajimu UMEMOTO 
238f0cdd9c0SBrian Somers /*
239f0cdd9c0SBrian Somers  * rad_continue_send_request() has given us `got' (non-zero).  Deal with it.
240f0cdd9c0SBrian Somers  */
241f0cdd9c0SBrian Somers static void
242f0cdd9c0SBrian Somers radius_Process(struct radius *r, int got)
243972a1bcfSBrian Somers {
244972a1bcfSBrian Somers   char *argv[MAXARGS], *nuke;
245f0cdd9c0SBrian Somers   struct bundle *bundle;
246ff8e577bSBrian Somers   int argc, addrs, res, width;
24728e610e3SBrian Somers   size_t len;
24830949fd4SBrian Somers   struct ncprange dest;
24930949fd4SBrian Somers   struct ncpaddr gw;
250f0cdd9c0SBrian Somers   const void *data;
251c42627ffSBrian Somers   const char *stype;
252ff8e577bSBrian Somers   u_int32_t ipaddr, vendor;
25330949fd4SBrian Somers   struct in_addr ip;
2540fe74aa4SHajimu UMEMOTO #ifndef NOINET6
255ec3e98b8SHajimu UMEMOTO   uint8_t ipv6addr[INET6_ADDRSTRLEN];
2560fe74aa4SHajimu UMEMOTO   struct in6_addr ip6;
2570fe74aa4SHajimu UMEMOTO #endif
258972a1bcfSBrian Somers 
259f0cdd9c0SBrian Somers   r->cx.fd = -1;		/* Stop select()ing */
260c42627ffSBrian Somers   stype = r->cx.auth ? "auth" : "acct";
261972a1bcfSBrian Somers 
262972a1bcfSBrian Somers   switch (got) {
263972a1bcfSBrian Somers     case RAD_ACCESS_ACCEPT:
264c42627ffSBrian Somers       log_Printf(LogPHASE, "Radius(%s): ACCEPT received\n", stype);
265c42627ffSBrian Somers       if (!r->cx.auth) {
266c42627ffSBrian Somers         rad_close(r->cx.rad);
267c42627ffSBrian Somers         return;
268c42627ffSBrian Somers       }
269972a1bcfSBrian Somers       break;
270972a1bcfSBrian Somers 
271f0cdd9c0SBrian Somers     case RAD_ACCESS_REJECT:
272c42627ffSBrian Somers       log_Printf(LogPHASE, "Radius(%s): REJECT received\n", stype);
273ff8e577bSBrian Somers       if (!r->cx.auth) {
274f0cdd9c0SBrian Somers         rad_close(r->cx.rad);
275f0cdd9c0SBrian Somers         return;
276ff8e577bSBrian Somers       }
277ff8e577bSBrian Somers       break;
278f0cdd9c0SBrian Somers 
279972a1bcfSBrian Somers     case RAD_ACCESS_CHALLENGE:
280972a1bcfSBrian Somers       /* we can't deal with this (for now) ! */
281f0cdd9c0SBrian Somers       log_Printf(LogPHASE, "Radius: CHALLENGE received (can't handle yet)\n");
282c42627ffSBrian Somers       if (r->cx.auth)
283f0cdd9c0SBrian Somers         auth_Failure(r->cx.auth);
284f0cdd9c0SBrian Somers       rad_close(r->cx.rad);
285f0cdd9c0SBrian Somers       return;
286972a1bcfSBrian Somers 
287794c9bbcSBrian Somers     case RAD_ACCOUNTING_RESPONSE:
288c42627ffSBrian Somers       log_Printf(LogPHASE, "Radius(%s): Accounting response received\n", stype);
289c42627ffSBrian Somers       if (r->cx.auth)
290c42627ffSBrian Somers         auth_Failure(r->cx.auth);		/* unexpected !!! */
291c42627ffSBrian Somers 
292794c9bbcSBrian Somers       /* No further processing for accounting requests, please */
293794c9bbcSBrian Somers       rad_close(r->cx.rad);
294794c9bbcSBrian Somers       return;
295794c9bbcSBrian Somers 
296972a1bcfSBrian Somers     case -1:
297c42627ffSBrian Somers       log_Printf(LogPHASE, "radius(%s): %s\n", stype, rad_strerror(r->cx.rad));
298c42627ffSBrian Somers       if (r->cx.auth)
299f0cdd9c0SBrian Somers         auth_Failure(r->cx.auth);
300f0cdd9c0SBrian Somers       rad_close(r->cx.rad);
301f0cdd9c0SBrian Somers       return;
302972a1bcfSBrian Somers 
303972a1bcfSBrian Somers     default:
304c42627ffSBrian Somers       log_Printf(LogERROR, "rad_send_request(%s): Failed %d: %s\n", stype,
305f0cdd9c0SBrian Somers                  got, rad_strerror(r->cx.rad));
306c42627ffSBrian Somers       if (r->cx.auth)
307f0cdd9c0SBrian Somers         auth_Failure(r->cx.auth);
308f0cdd9c0SBrian Somers       rad_close(r->cx.rad);
309f0cdd9c0SBrian Somers       return;
310972a1bcfSBrian Somers   }
311972a1bcfSBrian Somers 
312ff8e577bSBrian Somers   /* Let's see what we've got in our reply */
313972a1bcfSBrian Somers   r->ip.s_addr = r->mask.s_addr = INADDR_NONE;
314972a1bcfSBrian Somers   r->mtu = 0;
315972a1bcfSBrian Somers   r->vj = 0;
316ff8e577bSBrian Somers   while ((res = rad_get_attr(r->cx.rad, &data, &len)) > 0) {
317ff8e577bSBrian Somers     switch (res) {
318972a1bcfSBrian Somers       case RAD_FRAMED_IP_ADDRESS:
319972a1bcfSBrian Somers         r->ip = rad_cvt_addr(data);
320f0cdd9c0SBrian Somers         log_Printf(LogPHASE, " IP %s\n", inet_ntoa(r->ip));
321972a1bcfSBrian Somers         break;
322972a1bcfSBrian Somers 
323bf1eaec5SBrian Somers       case RAD_FILTER_ID:
324bf1eaec5SBrian Somers         free(r->filterid);
325bf1eaec5SBrian Somers         if ((r->filterid = rad_cvt_string(data, len)) == NULL) {
326bf1eaec5SBrian Somers           log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
327ff8e577bSBrian Somers           auth_Failure(r->cx.auth);
328bf1eaec5SBrian Somers           rad_close(r->cx.rad);
329bf1eaec5SBrian Somers           return;
330bf1eaec5SBrian Somers         }
331bf1eaec5SBrian Somers         log_Printf(LogPHASE, " Filter \"%s\"\n", r->filterid);
332bf1eaec5SBrian Somers         break;
333bf1eaec5SBrian Somers 
334bf1eaec5SBrian Somers       case RAD_SESSION_TIMEOUT:
335bf1eaec5SBrian Somers         r->sessiontime = rad_cvt_int(data);
336bf1eaec5SBrian Somers         log_Printf(LogPHASE, " Session-Timeout %lu\n", r->sessiontime);
337bf1eaec5SBrian Somers         break;
338bf1eaec5SBrian Somers 
339972a1bcfSBrian Somers       case RAD_FRAMED_IP_NETMASK:
340972a1bcfSBrian Somers         r->mask = rad_cvt_addr(data);
341f0cdd9c0SBrian Somers         log_Printf(LogPHASE, " Netmask %s\n", inet_ntoa(r->mask));
342972a1bcfSBrian Somers         break;
343972a1bcfSBrian Somers 
344972a1bcfSBrian Somers       case RAD_FRAMED_MTU:
345972a1bcfSBrian Somers         r->mtu = rad_cvt_int(data);
346f0cdd9c0SBrian Somers         log_Printf(LogPHASE, " MTU %lu\n", r->mtu);
347972a1bcfSBrian Somers         break;
348972a1bcfSBrian Somers 
349972a1bcfSBrian Somers       case RAD_FRAMED_ROUTING:
350972a1bcfSBrian Somers         /* Disabled for now - should we automatically set up some filters ? */
351972a1bcfSBrian Somers         /* rad_cvt_int(data); */
352972a1bcfSBrian Somers         /* bit 1 = Send routing packets */
353972a1bcfSBrian Somers         /* bit 2 = Receive routing packets */
354972a1bcfSBrian Somers         break;
355972a1bcfSBrian Somers 
356972a1bcfSBrian Somers       case RAD_FRAMED_COMPRESSION:
357972a1bcfSBrian Somers         r->vj = rad_cvt_int(data) == 1 ? 1 : 0;
358f0cdd9c0SBrian Somers         log_Printf(LogPHASE, " VJ %sabled\n", r->vj ? "en" : "dis");
359972a1bcfSBrian Somers         break;
360972a1bcfSBrian Somers 
361972a1bcfSBrian Somers       case RAD_FRAMED_ROUTE:
362972a1bcfSBrian Somers         /*
363972a1bcfSBrian Somers          * We expect a string of the format ``dest[/bits] gw [metrics]''
364972a1bcfSBrian Somers          * Any specified metrics are ignored.  MYADDR and HISADDR are
365972a1bcfSBrian Somers          * understood for ``dest'' and ``gw'' and ``0.0.0.0'' is the same
366972a1bcfSBrian Somers          * as ``HISADDR''.
367972a1bcfSBrian Somers          */
368972a1bcfSBrian Somers 
369972a1bcfSBrian Somers         if ((nuke = rad_cvt_string(data, len)) == NULL) {
370f0cdd9c0SBrian Somers           log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
371ff8e577bSBrian Somers           auth_Failure(r->cx.auth);
372f0cdd9c0SBrian Somers           rad_close(r->cx.rad);
373f0cdd9c0SBrian Somers           return;
374972a1bcfSBrian Somers         }
375972a1bcfSBrian Somers 
376f0cdd9c0SBrian Somers         log_Printf(LogPHASE, " Route: %s\n", nuke);
377f0cdd9c0SBrian Somers         bundle = r->cx.auth->physical->dl->bundle;
37830949fd4SBrian Somers         ip.s_addr = INADDR_ANY;
3790fe74aa4SHajimu UMEMOTO         ncpaddr_setip4(&gw, ip);
38030949fd4SBrian Somers         ncprange_setip4host(&dest, ip);
381972a1bcfSBrian Somers         argc = command_Interpret(nuke, strlen(nuke), argv);
382c39aa54eSBrian Somers         if (argc < 0)
383c39aa54eSBrian Somers           log_Printf(LogWARN, "radius: %s: Syntax error\n",
384c39aa54eSBrian Somers                      argc == 1 ? argv[0] : "\"\"");
385c39aa54eSBrian Somers         else if (argc < 2)
386972a1bcfSBrian Somers           log_Printf(LogWARN, "radius: %s: Invalid route\n",
387972a1bcfSBrian Somers                      argc == 1 ? argv[0] : "\"\"");
388972a1bcfSBrian Somers         else if ((strcasecmp(argv[0], "default") != 0 &&
38930949fd4SBrian Somers                   !ncprange_aton(&dest, &bundle->ncp, argv[0])) ||
39030949fd4SBrian Somers                  !ncpaddr_aton(&gw, &bundle->ncp, argv[1]))
391972a1bcfSBrian Somers           log_Printf(LogWARN, "radius: %s %s: Invalid route\n",
392972a1bcfSBrian Somers                      argv[0], argv[1]);
393972a1bcfSBrian Somers         else {
39430949fd4SBrian Somers           ncprange_getwidth(&dest, &width);
39530949fd4SBrian Somers           if (width == 32 && strchr(argv[0], '/') == NULL) {
396972a1bcfSBrian Somers             /* No mask specified - use the natural mask */
39730949fd4SBrian Somers             ncprange_getip4addr(&dest, &ip);
39830949fd4SBrian Somers             ncprange_setip4mask(&dest, addr2mask(ip));
39930949fd4SBrian Somers           }
400972a1bcfSBrian Somers           addrs = 0;
401972a1bcfSBrian Somers 
402972a1bcfSBrian Somers           if (!strncasecmp(argv[0], "HISADDR", 7))
403972a1bcfSBrian Somers             addrs = ROUTE_DSTHISADDR;
404972a1bcfSBrian Somers           else if (!strncasecmp(argv[0], "MYADDR", 6))
405972a1bcfSBrian Somers             addrs = ROUTE_DSTMYADDR;
406972a1bcfSBrian Somers 
40730949fd4SBrian Somers           if (ncpaddr_getip4addr(&gw, &ipaddr) && ipaddr == INADDR_ANY) {
408972a1bcfSBrian Somers             addrs |= ROUTE_GWHISADDR;
40930949fd4SBrian Somers             ncpaddr_setip4(&gw, bundle->ncp.ipcp.peer_ip);
410972a1bcfSBrian Somers           } else if (strcasecmp(argv[1], "HISADDR") == 0)
411972a1bcfSBrian Somers             addrs |= ROUTE_GWHISADDR;
412972a1bcfSBrian Somers 
41330949fd4SBrian Somers           route_Add(&r->routes, addrs, &dest, &gw);
414972a1bcfSBrian Somers         }
415972a1bcfSBrian Somers         free(nuke);
416972a1bcfSBrian Somers         break;
417972a1bcfSBrian Somers 
418ff8e577bSBrian Somers       case RAD_REPLY_MESSAGE:
419ff8e577bSBrian Somers         free(r->repstr);
420ff8e577bSBrian Somers         if ((r->repstr = rad_cvt_string(data, len)) == NULL) {
421ff8e577bSBrian Somers           log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
422ff8e577bSBrian Somers           auth_Failure(r->cx.auth);
423ff8e577bSBrian Somers           rad_close(r->cx.rad);
424ff8e577bSBrian Somers           return;
425ff8e577bSBrian Somers         }
426ff8e577bSBrian Somers         log_Printf(LogPHASE, " Reply-Message \"%s\"\n", r->repstr);
427ff8e577bSBrian Somers         break;
428ff8e577bSBrian Somers 
4290fe74aa4SHajimu UMEMOTO #ifndef NOINET6
430ec3e98b8SHajimu UMEMOTO       case RAD_FRAMED_IPV6_PREFIX:
431ec3e98b8SHajimu UMEMOTO 	free(r->ipv6prefix);
432ec3e98b8SHajimu UMEMOTO         r->ipv6prefix = rad_cvt_ipv6prefix(data, len);
433ec3e98b8SHajimu UMEMOTO 	inet_ntop(AF_INET6, &r->ipv6prefix[2], ipv6addr, sizeof(ipv6addr));
434ec3e98b8SHajimu UMEMOTO         log_Printf(LogPHASE, " IPv6 %s/%d\n", ipv6addr, r->ipv6prefix[1]);
435ec3e98b8SHajimu UMEMOTO         break;
436ec3e98b8SHajimu UMEMOTO 
4370fe74aa4SHajimu UMEMOTO       case RAD_FRAMED_IPV6_ROUTE:
4380fe74aa4SHajimu UMEMOTO         /*
4390fe74aa4SHajimu UMEMOTO          * We expect a string of the format ``dest[/bits] gw [metrics]''
4400fe74aa4SHajimu UMEMOTO          * Any specified metrics are ignored.  MYADDR6 and HISADDR6 are
4410fe74aa4SHajimu UMEMOTO          * understood for ``dest'' and ``gw'' and ``::'' is the same
4420fe74aa4SHajimu UMEMOTO          * as ``HISADDR6''.
4430fe74aa4SHajimu UMEMOTO          */
4440fe74aa4SHajimu UMEMOTO 
4450fe74aa4SHajimu UMEMOTO         if ((nuke = rad_cvt_string(data, len)) == NULL) {
4460fe74aa4SHajimu UMEMOTO           log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
4470fe74aa4SHajimu UMEMOTO           auth_Failure(r->cx.auth);
4480fe74aa4SHajimu UMEMOTO           rad_close(r->cx.rad);
4490fe74aa4SHajimu UMEMOTO           return;
4500fe74aa4SHajimu UMEMOTO         }
4510fe74aa4SHajimu UMEMOTO 
4520fe74aa4SHajimu UMEMOTO         log_Printf(LogPHASE, " IPv6 Route: %s\n", nuke);
4530fe74aa4SHajimu UMEMOTO         bundle = r->cx.auth->physical->dl->bundle;
4540fe74aa4SHajimu UMEMOTO 	ncpaddr_setip6(&gw, &in6addr_any);
4550fe74aa4SHajimu UMEMOTO 	ncprange_set(&dest, &gw, 0);
4560fe74aa4SHajimu UMEMOTO         argc = command_Interpret(nuke, strlen(nuke), argv);
4570fe74aa4SHajimu UMEMOTO         if (argc < 0)
4580fe74aa4SHajimu UMEMOTO           log_Printf(LogWARN, "radius: %s: Syntax error\n",
4590fe74aa4SHajimu UMEMOTO                      argc == 1 ? argv[0] : "\"\"");
4600fe74aa4SHajimu UMEMOTO         else if (argc < 2)
4610fe74aa4SHajimu UMEMOTO           log_Printf(LogWARN, "radius: %s: Invalid route\n",
4620fe74aa4SHajimu UMEMOTO                      argc == 1 ? argv[0] : "\"\"");
4630fe74aa4SHajimu UMEMOTO         else if ((strcasecmp(argv[0], "default") != 0 &&
4640fe74aa4SHajimu UMEMOTO                   !ncprange_aton(&dest, &bundle->ncp, argv[0])) ||
4650fe74aa4SHajimu UMEMOTO                  !ncpaddr_aton(&gw, &bundle->ncp, argv[1]))
4660fe74aa4SHajimu UMEMOTO           log_Printf(LogWARN, "radius: %s %s: Invalid route\n",
4670fe74aa4SHajimu UMEMOTO                      argv[0], argv[1]);
4680fe74aa4SHajimu UMEMOTO         else {
4690fe74aa4SHajimu UMEMOTO           addrs = 0;
4700fe74aa4SHajimu UMEMOTO 
4710fe74aa4SHajimu UMEMOTO           if (!strncasecmp(argv[0], "HISADDR6", 8))
4720fe74aa4SHajimu UMEMOTO             addrs = ROUTE_DSTHISADDR6;
4730fe74aa4SHajimu UMEMOTO           else if (!strncasecmp(argv[0], "MYADDR6", 7))
4740fe74aa4SHajimu UMEMOTO             addrs = ROUTE_DSTMYADDR6;
4750fe74aa4SHajimu UMEMOTO 
4760fe74aa4SHajimu UMEMOTO           if (ncpaddr_getip6(&gw, &ip6) && IN6_IS_ADDR_UNSPECIFIED(&ip6)) {
4770fe74aa4SHajimu UMEMOTO             addrs |= ROUTE_GWHISADDR6;
4780fe74aa4SHajimu UMEMOTO             ncpaddr_copy(&gw, &bundle->ncp.ipv6cp.hisaddr);
4790fe74aa4SHajimu UMEMOTO           } else if (strcasecmp(argv[1], "HISADDR6") == 0)
4800fe74aa4SHajimu UMEMOTO             addrs |= ROUTE_GWHISADDR6;
4810fe74aa4SHajimu UMEMOTO 
4820fe74aa4SHajimu UMEMOTO           route_Add(&r->ipv6routes, addrs, &dest, &gw);
4830fe74aa4SHajimu UMEMOTO         }
4840fe74aa4SHajimu UMEMOTO         free(nuke);
4850fe74aa4SHajimu UMEMOTO         break;
4860fe74aa4SHajimu UMEMOTO #endif
4870fe74aa4SHajimu UMEMOTO 
488ff8e577bSBrian Somers       case RAD_VENDOR_SPECIFIC:
489ff8e577bSBrian Somers         if ((res = rad_get_vendor_attr(&vendor, &data, &len)) <= 0) {
490ff8e577bSBrian Somers           log_Printf(LogERROR, "rad_get_vendor_attr: %s (failing!)\n",
491f0cdd9c0SBrian Somers                      rad_strerror(r->cx.rad));
492f0cdd9c0SBrian Somers           auth_Failure(r->cx.auth);
493f0cdd9c0SBrian Somers           rad_close(r->cx.rad);
494ff8e577bSBrian Somers           return;
495ff8e577bSBrian Somers         }
496ff8e577bSBrian Somers 
497ff8e577bSBrian Somers 	switch (vendor) {
498ff8e577bSBrian Somers           case RAD_VENDOR_MICROSOFT:
499ff8e577bSBrian Somers             switch (res) {
5008fb5ef5aSBrian Somers #ifndef NODES
501ff8e577bSBrian Somers               case RAD_MICROSOFT_MS_CHAP_ERROR:
502ff8e577bSBrian Somers                 free(r->errstr);
503a95b23a6SBrian Somers                 if (len == 0)
504a95b23a6SBrian Somers                   r->errstr = NULL;
505a95b23a6SBrian Somers                 else {
50699cfc2e2SBrian Somers                   if (len < 3 || ((const char *)data)[1] != '=') {
50799cfc2e2SBrian Somers                     /*
50899cfc2e2SBrian Somers                      * Only point at the String field if we don't think the
50999cfc2e2SBrian Somers                      * peer has misformatted the response.
51099cfc2e2SBrian Somers                      */
51199cfc2e2SBrian Somers                     ((const char *)data)++;
51299cfc2e2SBrian Somers                     len--;
513579abfd8SBrian Somers                   } else
514579abfd8SBrian Somers                     log_Printf(LogWARN, "Warning: The MS-CHAP-Error "
515579abfd8SBrian Somers                                "attribute is mis-formatted.  Compensating\n");
51699cfc2e2SBrian Somers                   if ((r->errstr = rad_cvt_string((const char *)data,
51799cfc2e2SBrian Somers                                                   len)) == NULL) {
518ff8e577bSBrian Somers                     log_Printf(LogERROR, "rad_cvt_string: %s\n",
519ff8e577bSBrian Somers                                rad_strerror(r->cx.rad));
520ff8e577bSBrian Somers                     auth_Failure(r->cx.auth);
521ff8e577bSBrian Somers                     rad_close(r->cx.rad);
522ff8e577bSBrian Somers                     return;
523ff8e577bSBrian Somers                   }
524ff8e577bSBrian Somers                   log_Printf(LogPHASE, " MS-CHAP-Error \"%s\"\n", r->errstr);
525a95b23a6SBrian Somers                 }
526ff8e577bSBrian Somers                 break;
527ff8e577bSBrian Somers 
528a16061b2SBrian Somers               case RAD_MICROSOFT_MS_CHAP2_SUCCESS:
529a16061b2SBrian Somers                 free(r->msrepstr);
530a95b23a6SBrian Somers                 if (len == 0)
531a95b23a6SBrian Somers                   r->msrepstr = NULL;
532a95b23a6SBrian Somers                 else {
53399cfc2e2SBrian Somers                   if (len < 3 || ((const char *)data)[1] != '=') {
53499cfc2e2SBrian Somers                     /*
53599cfc2e2SBrian Somers                      * Only point at the String field if we don't think the
53699cfc2e2SBrian Somers                      * peer has misformatted the response.
53799cfc2e2SBrian Somers                      */
53899cfc2e2SBrian Somers                     ((const char *)data)++;
53999cfc2e2SBrian Somers                     len--;
540579abfd8SBrian Somers                   } else
541579abfd8SBrian Somers                     log_Printf(LogWARN, "Warning: The MS-CHAP2-Success "
542579abfd8SBrian Somers                                "attribute is mis-formatted.  Compensating\n");
54399cfc2e2SBrian Somers                   if ((r->msrepstr = rad_cvt_string((const char *)data,
54499cfc2e2SBrian Somers                                                     len)) == NULL) {
545a16061b2SBrian Somers                     log_Printf(LogERROR, "rad_cvt_string: %s\n",
546a16061b2SBrian Somers                                rad_strerror(r->cx.rad));
547a16061b2SBrian Somers                     auth_Failure(r->cx.auth);
548a16061b2SBrian Somers                     rad_close(r->cx.rad);
549a16061b2SBrian Somers                     return;
550a16061b2SBrian Somers                   }
551a95b23a6SBrian Somers                   log_Printf(LogPHASE, " MS-CHAP2-Success \"%s\"\n",
552a95b23a6SBrian Somers                              r->msrepstr);
553a95b23a6SBrian Somers                 }
554a16061b2SBrian Somers                 break;
555a16061b2SBrian Somers 
5568fb5ef5aSBrian Somers               case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY:
5578fb5ef5aSBrian Somers                 r->mppe.policy = rad_cvt_int(data);
5588fb5ef5aSBrian Somers                 log_Printf(LogPHASE, " MS-MPPE-Encryption-Policy %s\n",
5598fb5ef5aSBrian Somers                            radius_policyname(r->mppe.policy));
5608fb5ef5aSBrian Somers                 break;
5618fb5ef5aSBrian Somers 
5628fb5ef5aSBrian Somers               case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES:
5638fb5ef5aSBrian Somers                 r->mppe.types = rad_cvt_int(data);
5648fb5ef5aSBrian Somers                 log_Printf(LogPHASE, " MS-MPPE-Encryption-Types %s\n",
5658fb5ef5aSBrian Somers                            radius_typesname(r->mppe.types));
5668fb5ef5aSBrian Somers                 break;
5678fb5ef5aSBrian Somers 
5688fb5ef5aSBrian Somers               case RAD_MICROSOFT_MS_MPPE_RECV_KEY:
5698fb5ef5aSBrian Somers                 free(r->mppe.recvkey);
5708fb5ef5aSBrian Somers 		demangle(r, data, len, &r->mppe.recvkey, &r->mppe.recvkeylen);
5718fb5ef5aSBrian Somers                 log_Printf(LogPHASE, " MS-MPPE-Recv-Key ********\n");
5728fb5ef5aSBrian Somers                 break;
5738fb5ef5aSBrian Somers 
5748fb5ef5aSBrian Somers               case RAD_MICROSOFT_MS_MPPE_SEND_KEY:
5758fb5ef5aSBrian Somers 		demangle(r, data, len, &r->mppe.sendkey, &r->mppe.sendkeylen);
5768fb5ef5aSBrian Somers                 log_Printf(LogPHASE, " MS-MPPE-Send-Key ********\n");
5778fb5ef5aSBrian Somers                 break;
5788fb5ef5aSBrian Somers #endif
5798fb5ef5aSBrian Somers 
580ff8e577bSBrian Somers               default:
581ff8e577bSBrian Somers                 log_Printf(LogDEBUG, "Dropping MICROSOFT vendor specific "
582ff8e577bSBrian Somers                            "RADIUS attribute %d\n", res);
583ff8e577bSBrian Somers                 break;
584ff8e577bSBrian Somers             }
585ff8e577bSBrian Somers             break;
586ff8e577bSBrian Somers 
587ff8e577bSBrian Somers           default:
588ff8e577bSBrian Somers             log_Printf(LogDEBUG, "Dropping vendor %lu RADIUS attribute %d\n",
589ff8e577bSBrian Somers                        (unsigned long)vendor, res);
590ff8e577bSBrian Somers             break;
591ff8e577bSBrian Somers         }
592ff8e577bSBrian Somers         break;
593ff8e577bSBrian Somers 
594ff8e577bSBrian Somers       default:
595ff8e577bSBrian Somers         log_Printf(LogDEBUG, "Dropping RADIUS attribute %d\n", res);
596ff8e577bSBrian Somers         break;
597ff8e577bSBrian Somers     }
598ff8e577bSBrian Somers   }
599ff8e577bSBrian Somers 
600ff8e577bSBrian Somers   if (res == -1) {
601ff8e577bSBrian Somers     log_Printf(LogERROR, "rad_get_attr: %s (failing!)\n",
602ff8e577bSBrian Somers                rad_strerror(r->cx.rad));
603ff8e577bSBrian Somers     auth_Failure(r->cx.auth);
604ff8e577bSBrian Somers   } else if (got == RAD_ACCESS_REJECT)
605ff8e577bSBrian Somers     auth_Failure(r->cx.auth);
606ff8e577bSBrian Somers   else {
607f0cdd9c0SBrian Somers     r->valid = 1;
608f0cdd9c0SBrian Somers     auth_Success(r->cx.auth);
609f0cdd9c0SBrian Somers   }
610ff8e577bSBrian Somers   rad_close(r->cx.rad);
611972a1bcfSBrian Somers }
612972a1bcfSBrian Somers 
613f0cdd9c0SBrian Somers /*
6148e7bd08eSBrian Somers  * We've either timed out or select()ed on the read descriptor
615f0cdd9c0SBrian Somers  */
616f0cdd9c0SBrian Somers static void
617f0cdd9c0SBrian Somers radius_Continue(struct radius *r, int sel)
618f0cdd9c0SBrian Somers {
619f0cdd9c0SBrian Somers   struct timeval tv;
620f0cdd9c0SBrian Somers   int got;
621972a1bcfSBrian Somers 
622f0cdd9c0SBrian Somers   timer_Stop(&r->cx.timer);
623f0cdd9c0SBrian Somers   if ((got = rad_continue_send_request(r->cx.rad, sel, &r->cx.fd, &tv)) == 0) {
624f0cdd9c0SBrian Somers     log_Printf(LogPHASE, "Radius: Request re-sent\n");
625f0cdd9c0SBrian Somers     r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
626f0cdd9c0SBrian Somers     timer_Start(&r->cx.timer);
627f0cdd9c0SBrian Somers     return;
628f0cdd9c0SBrian Somers   }
629f0cdd9c0SBrian Somers 
630f0cdd9c0SBrian Somers   radius_Process(r, got);
631f0cdd9c0SBrian Somers }
632f0cdd9c0SBrian Somers 
633f0cdd9c0SBrian Somers /*
634f0cdd9c0SBrian Somers  * Time to call rad_continue_send_request() - timed out.
635f0cdd9c0SBrian Somers  */
636f0cdd9c0SBrian Somers static void
637f0cdd9c0SBrian Somers radius_Timeout(void *v)
638f0cdd9c0SBrian Somers {
639f0cdd9c0SBrian Somers   radius_Continue((struct radius *)v, 0);
640f0cdd9c0SBrian Somers }
641f0cdd9c0SBrian Somers 
642f0cdd9c0SBrian Somers /*
643f0cdd9c0SBrian Somers  * Time to call rad_continue_send_request() - something to read.
644f0cdd9c0SBrian Somers  */
645f0cdd9c0SBrian Somers static void
646f013f33eSBrian Somers radius_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
647f0cdd9c0SBrian Somers {
648f0cdd9c0SBrian Somers   radius_Continue(descriptor2radius(d), 1);
649f0cdd9c0SBrian Somers }
650f0cdd9c0SBrian Somers 
651f0cdd9c0SBrian Somers /*
6528e7bd08eSBrian Somers  * Behave as a struct fdescriptor (descriptor.h)
653f0cdd9c0SBrian Somers  */
654f0cdd9c0SBrian Somers static int
655f013f33eSBrian Somers radius_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
656f0cdd9c0SBrian Somers {
657f0cdd9c0SBrian Somers   struct radius *rad = descriptor2radius(d);
658f0cdd9c0SBrian Somers 
659f0cdd9c0SBrian Somers   if (r && rad->cx.fd != -1) {
660f0cdd9c0SBrian Somers     FD_SET(rad->cx.fd, r);
661f0cdd9c0SBrian Somers     if (*n < rad->cx.fd + 1)
662f0cdd9c0SBrian Somers       *n = rad->cx.fd + 1;
663f0cdd9c0SBrian Somers     log_Printf(LogTIMER, "Radius: fdset(r) %d\n", rad->cx.fd);
66482d6780cSBrian Somers     return 1;
665972a1bcfSBrian Somers   }
666972a1bcfSBrian Somers 
667f0cdd9c0SBrian Somers   return 0;
668f0cdd9c0SBrian Somers }
669f0cdd9c0SBrian Somers 
670f0cdd9c0SBrian Somers /*
6718e7bd08eSBrian Somers  * Behave as a struct fdescriptor (descriptor.h)
672f0cdd9c0SBrian Somers  */
673f0cdd9c0SBrian Somers static int
674f013f33eSBrian Somers radius_IsSet(struct fdescriptor *d, const fd_set *fdset)
675f0cdd9c0SBrian Somers {
676f0cdd9c0SBrian Somers   struct radius *r = descriptor2radius(d);
677f0cdd9c0SBrian Somers 
678f0cdd9c0SBrian Somers   return r && r->cx.fd != -1 && FD_ISSET(r->cx.fd, fdset);
679f0cdd9c0SBrian Somers }
680f0cdd9c0SBrian Somers 
681f0cdd9c0SBrian Somers /*
6828e7bd08eSBrian Somers  * Behave as a struct fdescriptor (descriptor.h)
683f0cdd9c0SBrian Somers  */
684f0cdd9c0SBrian Somers static int
685f013f33eSBrian Somers radius_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
686f0cdd9c0SBrian Somers {
687f0cdd9c0SBrian Somers   /* We never want to write here ! */
688f0cdd9c0SBrian Somers   log_Printf(LogALERT, "radius_Write: Internal error: Bad call !\n");
689f0cdd9c0SBrian Somers   return 0;
690f0cdd9c0SBrian Somers }
691f0cdd9c0SBrian Somers 
692f0cdd9c0SBrian Somers /*
693f0cdd9c0SBrian Somers  * Initialise ourselves
694f0cdd9c0SBrian Somers  */
695f0cdd9c0SBrian Somers void
696f0cdd9c0SBrian Somers radius_Init(struct radius *r)
697f0cdd9c0SBrian Somers {
698f0cdd9c0SBrian Somers   r->desc.type = RADIUS_DESCRIPTOR;
699f0cdd9c0SBrian Somers   r->desc.UpdateSet = radius_UpdateSet;
700f0cdd9c0SBrian Somers   r->desc.IsSet = radius_IsSet;
701f0cdd9c0SBrian Somers   r->desc.Read = radius_Read;
702f0cdd9c0SBrian Somers   r->desc.Write = radius_Write;
703ff8e577bSBrian Somers   r->cx.fd = -1;
704ff8e577bSBrian Somers   r->cx.rad = NULL;
705f0cdd9c0SBrian Somers   memset(&r->cx.timer, '\0', sizeof r->cx.timer);
706ff8e577bSBrian Somers   r->cx.auth = NULL;
707ff8e577bSBrian Somers   r->valid = 0;
708ff8e577bSBrian Somers   r->vj = 0;
709ff8e577bSBrian Somers   r->ip.s_addr = INADDR_ANY;
710ff8e577bSBrian Somers   r->mask.s_addr = INADDR_NONE;
711ff8e577bSBrian Somers   r->routes = NULL;
712ff8e577bSBrian Somers   r->mtu = DEF_MTU;
713a16061b2SBrian Somers   r->msrepstr = NULL;
714ff8e577bSBrian Somers   r->repstr = NULL;
7150fe74aa4SHajimu UMEMOTO #ifndef NOINET6
716ec3e98b8SHajimu UMEMOTO   r->ipv6prefix = NULL;
7170fe74aa4SHajimu UMEMOTO   r->ipv6routes = NULL;
7180fe74aa4SHajimu UMEMOTO #endif
719ff8e577bSBrian Somers   r->errstr = NULL;
7208fb5ef5aSBrian Somers   r->mppe.policy = 0;
7218fb5ef5aSBrian Somers   r->mppe.types = 0;
7228fb5ef5aSBrian Somers   r->mppe.recvkey = NULL;
7238fb5ef5aSBrian Somers   r->mppe.recvkeylen = 0;
7248fb5ef5aSBrian Somers   r->mppe.sendkey = NULL;
7258fb5ef5aSBrian Somers   r->mppe.sendkeylen = 0;
726ff8e577bSBrian Somers   *r->cfg.file = '\0';;
727794c9bbcSBrian Somers   log_Printf(LogDEBUG, "Radius: radius_Init\n");
728f0cdd9c0SBrian Somers }
729f0cdd9c0SBrian Somers 
730f0cdd9c0SBrian Somers /*
731f0cdd9c0SBrian Somers  * Forget everything and go back to initialised state.
732f0cdd9c0SBrian Somers  */
733f0cdd9c0SBrian Somers void
734f0cdd9c0SBrian Somers radius_Destroy(struct radius *r)
735f0cdd9c0SBrian Somers {
736f0cdd9c0SBrian Somers   r->valid = 0;
737794c9bbcSBrian Somers   log_Printf(LogDEBUG, "Radius: radius_Destroy\n");
738f0cdd9c0SBrian Somers   timer_Stop(&r->cx.timer);
739f0cdd9c0SBrian Somers   route_DeleteAll(&r->routes);
7400fe74aa4SHajimu UMEMOTO #ifndef NOINET6
7410fe74aa4SHajimu UMEMOTO   route_DeleteAll(&r->ipv6routes);
7420fe74aa4SHajimu UMEMOTO #endif
743bf1eaec5SBrian Somers   free(r->filterid);
744bf1eaec5SBrian Somers   r->filterid = NULL;
745a16061b2SBrian Somers   free(r->msrepstr);
746a16061b2SBrian Somers   r->msrepstr = NULL;
747ff8e577bSBrian Somers   free(r->repstr);
748ff8e577bSBrian Somers   r->repstr = NULL;
749ec3e98b8SHajimu UMEMOTO #ifndef NOINET6
750ec3e98b8SHajimu UMEMOTO   free(r->ipv6prefix);
751ec3e98b8SHajimu UMEMOTO   r->ipv6prefix = NULL;
752ec3e98b8SHajimu UMEMOTO #endif
753ff8e577bSBrian Somers   free(r->errstr);
754ff8e577bSBrian Somers   r->errstr = NULL;
7558fb5ef5aSBrian Somers   free(r->mppe.recvkey);
7568fb5ef5aSBrian Somers   r->mppe.recvkey = NULL;
7578fb5ef5aSBrian Somers   r->mppe.recvkeylen = 0;
7588fb5ef5aSBrian Somers   free(r->mppe.sendkey);
7598fb5ef5aSBrian Somers   r->mppe.sendkey = NULL;
7608fb5ef5aSBrian Somers   r->mppe.sendkeylen = 0;
761f0cdd9c0SBrian Somers   if (r->cx.fd != -1) {
762f0cdd9c0SBrian Somers     r->cx.fd = -1;
763f0cdd9c0SBrian Somers     rad_close(r->cx.rad);
764f0cdd9c0SBrian Somers   }
765f0cdd9c0SBrian Somers }
766f0cdd9c0SBrian Somers 
767de59e178SBrian Somers static int
768de59e178SBrian Somers radius_put_physical_details(struct rad_handle *rad, struct physical *p)
769de59e178SBrian Somers {
770de59e178SBrian Somers   int slot, type;
771de59e178SBrian Somers 
772de59e178SBrian Somers   type = RAD_VIRTUAL;
773de59e178SBrian Somers   if (p->handler)
774de59e178SBrian Somers     switch (p->handler->type) {
775de59e178SBrian Somers       case I4B_DEVICE:
776de59e178SBrian Somers         type = RAD_ISDN_SYNC;
777de59e178SBrian Somers         break;
778de59e178SBrian Somers 
779de59e178SBrian Somers       case TTY_DEVICE:
780de59e178SBrian Somers         type = RAD_ASYNC;
781de59e178SBrian Somers         break;
782de59e178SBrian Somers 
783de59e178SBrian Somers       case ETHER_DEVICE:
784de59e178SBrian Somers         type = RAD_ETHERNET;
785de59e178SBrian Somers         break;
786de59e178SBrian Somers 
787de59e178SBrian Somers       case TCP_DEVICE:
788de59e178SBrian Somers       case UDP_DEVICE:
789de59e178SBrian Somers       case EXEC_DEVICE:
790de59e178SBrian Somers       case ATM_DEVICE:
791de59e178SBrian Somers       case NG_DEVICE:
792de59e178SBrian Somers         type = RAD_VIRTUAL;
793de59e178SBrian Somers         break;
794de59e178SBrian Somers     }
795de59e178SBrian Somers 
796de59e178SBrian Somers   if (rad_put_int(rad, RAD_NAS_PORT_TYPE, type) != 0) {
797de59e178SBrian Somers     log_Printf(LogERROR, "rad_put: rad_put_int: %s\n", rad_strerror(rad));
798de59e178SBrian Somers     rad_close(rad);
799de59e178SBrian Somers     return 0;
800de59e178SBrian Somers   }
801de59e178SBrian Somers 
802de59e178SBrian Somers   if ((slot = physical_Slot(p)) >= 0)
803de59e178SBrian Somers     if (rad_put_int(rad, RAD_NAS_PORT, slot) != 0) {
804de59e178SBrian Somers       log_Printf(LogERROR, "rad_put: rad_put_int: %s\n", rad_strerror(rad));
805de59e178SBrian Somers       rad_close(rad);
806de59e178SBrian Somers       return 0;
807de59e178SBrian Somers     }
808de59e178SBrian Somers 
809de59e178SBrian Somers   return 1;
810de59e178SBrian Somers }
811de59e178SBrian Somers 
812f0cdd9c0SBrian Somers /*
813f0cdd9c0SBrian Somers  * Start an authentication request to the RADIUS server.
814f0cdd9c0SBrian Somers  */
815a16061b2SBrian Somers int
816f0cdd9c0SBrian Somers radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name,
817a16061b2SBrian Somers                     const char *key, int klen, const char *nchallenge,
818250be50bSBrian Somers                     int nclen)
819f0cdd9c0SBrian Somers {
820f0cdd9c0SBrian Somers   struct timeval tv;
821de59e178SBrian Somers   int got;
82226e6a622SBrian Somers   char hostname[MAXHOSTNAMELEN];
823aadbb4eaSBrian Somers #if 0
824f10f5203SBrian Somers   struct hostent *hp;
825f10f5203SBrian Somers   struct in_addr hostaddr;
8268fb5ef5aSBrian Somers #endif
827ff8e577bSBrian Somers #ifndef NODES
828a16061b2SBrian Somers   struct mschap_response msresp;
829a16061b2SBrian Somers   struct mschap2_response msresp2;
830250be50bSBrian Somers   const struct MSCHAPv2_resp *keyv2;
831ff8e577bSBrian Somers #endif
832f0cdd9c0SBrian Somers 
833f0cdd9c0SBrian Somers   if (!*r->cfg.file)
834a16061b2SBrian Somers     return 0;
835f0cdd9c0SBrian Somers 
836f0cdd9c0SBrian Somers   if (r->cx.fd != -1)
837f0cdd9c0SBrian Somers     /*
838f0cdd9c0SBrian Somers      * We assume that our name/key/challenge is the same as last time,
839f0cdd9c0SBrian Somers      * and just continue to wait for the RADIUS server(s).
840f0cdd9c0SBrian Somers      */
841a16061b2SBrian Somers     return 1;
842f0cdd9c0SBrian Somers 
843f0cdd9c0SBrian Somers   radius_Destroy(r);
844f0cdd9c0SBrian Somers 
845794c9bbcSBrian Somers   if ((r->cx.rad = rad_auth_open()) == NULL) {
846794c9bbcSBrian Somers     log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno));
847a16061b2SBrian Somers     return 0;
848f0cdd9c0SBrian Somers   }
849f0cdd9c0SBrian Somers 
850f0cdd9c0SBrian Somers   if (rad_config(r->cx.rad, r->cfg.file) != 0) {
851f0cdd9c0SBrian Somers     log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad));
852f0cdd9c0SBrian Somers     rad_close(r->cx.rad);
853a16061b2SBrian Somers     return 0;
854f0cdd9c0SBrian Somers   }
855f0cdd9c0SBrian Somers 
856f0cdd9c0SBrian Somers   if (rad_create_request(r->cx.rad, RAD_ACCESS_REQUEST) != 0) {
857f0cdd9c0SBrian Somers     log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad));
858f0cdd9c0SBrian Somers     rad_close(r->cx.rad);
859a16061b2SBrian Somers     return 0;
860f0cdd9c0SBrian Somers   }
861f0cdd9c0SBrian Somers 
8624dc4e1eeSBrian Somers   if (rad_put_string(r->cx.rad, RAD_USER_NAME, name) != 0 ||
863f0cdd9c0SBrian Somers       rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 ||
864f0cdd9c0SBrian Somers       rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) {
865f0cdd9c0SBrian Somers     log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
866f0cdd9c0SBrian Somers     rad_close(r->cx.rad);
867a16061b2SBrian Somers     return 0;
868f0cdd9c0SBrian Somers   }
869f0cdd9c0SBrian Somers 
870ff8e577bSBrian Somers   switch (authp->physical->link.lcp.want_auth) {
871ff8e577bSBrian Somers   case PROTO_PAP:
872ff8e577bSBrian Somers     /* We're talking PAP */
873ff8e577bSBrian Somers     if (rad_put_attr(r->cx.rad, RAD_USER_PASSWORD, key, klen) != 0) {
874ff8e577bSBrian Somers       log_Printf(LogERROR, "PAP: rad_put_string: %s\n",
875ff8e577bSBrian Somers                  rad_strerror(r->cx.rad));
876ff8e577bSBrian Somers       rad_close(r->cx.rad);
877a16061b2SBrian Somers       return 0;
878ff8e577bSBrian Somers     }
879ff8e577bSBrian Somers     break;
880ff8e577bSBrian Somers 
881ff8e577bSBrian Somers   case PROTO_CHAP:
882ff8e577bSBrian Somers     switch (authp->physical->link.lcp.want_authtype) {
883ff8e577bSBrian Somers     case 0x5:
88450ca6ec3SBrian Somers       if (rad_put_attr(r->cx.rad, RAD_CHAP_PASSWORD, key, klen) != 0 ||
885a16061b2SBrian Somers           rad_put_attr(r->cx.rad, RAD_CHAP_CHALLENGE, nchallenge, nclen) != 0) {
886f0cdd9c0SBrian Somers         log_Printf(LogERROR, "CHAP: rad_put_string: %s\n",
887f0cdd9c0SBrian Somers                    rad_strerror(r->cx.rad));
888f0cdd9c0SBrian Somers         rad_close(r->cx.rad);
889a16061b2SBrian Somers         return 0;
890f0cdd9c0SBrian Somers       }
891ff8e577bSBrian Somers       break;
892ff8e577bSBrian Somers 
893ff8e577bSBrian Somers #ifndef NODES
894ff8e577bSBrian Somers     case 0x80:
895ff8e577bSBrian Somers       if (klen != 50) {
896a16061b2SBrian Somers         log_Printf(LogERROR, "CHAP80: Unrecognised key length %d\n", klen);
897f0cdd9c0SBrian Somers         rad_close(r->cx.rad);
898a16061b2SBrian Somers         return 0;
899f0cdd9c0SBrian Somers       }
900a16061b2SBrian Somers 
901ff8e577bSBrian Somers       rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT,
902a16061b2SBrian Somers                           RAD_MICROSOFT_MS_CHAP_CHALLENGE, nchallenge, nclen);
903a16061b2SBrian Somers       msresp.ident = *key;
904a16061b2SBrian Somers       msresp.flags = 0x01;
905a16061b2SBrian Somers       memcpy(msresp.lm_response, key + 1, 24);
906a16061b2SBrian Somers       memcpy(msresp.nt_response, key + 25, 24);
907ff8e577bSBrian Somers       rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT,
908a16061b2SBrian Somers                           RAD_MICROSOFT_MS_CHAP_RESPONSE, &msresp,
909a16061b2SBrian Somers                           sizeof msresp);
910ff8e577bSBrian Somers       break;
911ff8e577bSBrian Somers 
912ff8e577bSBrian Somers     case 0x81:
913250be50bSBrian Somers       if (klen != sizeof(*keyv2) + 1) {
914a16061b2SBrian Somers         log_Printf(LogERROR, "CHAP81: Unrecognised key length %d\n", klen);
915a16061b2SBrian Somers         rad_close(r->cx.rad);
916a16061b2SBrian Somers         return 0;
917a16061b2SBrian Somers       }
918a16061b2SBrian Somers 
919250be50bSBrian Somers       keyv2 = (const struct MSCHAPv2_resp *)(key + 1);
920a16061b2SBrian Somers       rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT,
921a16061b2SBrian Somers                           RAD_MICROSOFT_MS_CHAP_CHALLENGE, nchallenge, nclen);
922a16061b2SBrian Somers       msresp2.ident = *key;
923250be50bSBrian Somers       msresp2.flags = keyv2->Flags;
924250be50bSBrian Somers       memcpy(msresp2.response, keyv2->NTResponse, sizeof msresp2.response);
925a16061b2SBrian Somers       memset(msresp2.reserved, '\0', sizeof msresp2.reserved);
926250be50bSBrian Somers       memcpy(msresp2.pchallenge, keyv2->PeerChallenge,
927250be50bSBrian Somers              sizeof msresp2.pchallenge);
928a16061b2SBrian Somers       rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT,
929a16061b2SBrian Somers                           RAD_MICROSOFT_MS_CHAP2_RESPONSE, &msresp2,
930a16061b2SBrian Somers                           sizeof msresp2);
931a16061b2SBrian Somers       break;
932ff8e577bSBrian Somers #endif
933ff8e577bSBrian Somers     default:
934ff8e577bSBrian Somers       log_Printf(LogERROR, "CHAP: Unrecognised type 0x%02x\n",
935ff8e577bSBrian Somers                  authp->physical->link.lcp.want_authtype);
936ff8e577bSBrian Somers       rad_close(r->cx.rad);
937a16061b2SBrian Somers       return 0;
938ff8e577bSBrian Somers     }
939ff8e577bSBrian Somers   }
940f0cdd9c0SBrian Somers 
941f10f5203SBrian Somers   if (gethostname(hostname, sizeof hostname) != 0)
942f10f5203SBrian Somers     log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno));
943f10f5203SBrian Somers   else {
944aadbb4eaSBrian Somers #if 0
945f10f5203SBrian Somers     if ((hp = gethostbyname(hostname)) != NULL) {
946f10f5203SBrian Somers       hostaddr.s_addr = *(u_long *)hp->h_addr;
947f10f5203SBrian Somers       if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) {
948f10f5203SBrian Somers         log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
949f10f5203SBrian Somers                    rad_strerror(r->cx.rad));
950f10f5203SBrian Somers         rad_close(r->cx.rad);
951a16061b2SBrian Somers         return 0;
952f10f5203SBrian Somers       }
953f10f5203SBrian Somers     }
954aadbb4eaSBrian Somers #endif
955f10f5203SBrian Somers     if (rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) {
956f10f5203SBrian Somers       log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
957f10f5203SBrian Somers                  rad_strerror(r->cx.rad));
958f10f5203SBrian Somers       rad_close(r->cx.rad);
959a16061b2SBrian Somers       return 0;
960f10f5203SBrian Somers     }
961f10f5203SBrian Somers   }
962f10f5203SBrian Somers 
963de59e178SBrian Somers   radius_put_physical_details(r->cx.rad, authp->physical);
964f10f5203SBrian Somers 
965c42627ffSBrian Somers   r->cx.auth = authp;
966f0cdd9c0SBrian Somers   if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv)))
967f0cdd9c0SBrian Somers     radius_Process(r, got);
968f0cdd9c0SBrian Somers   else {
969f0cdd9c0SBrian Somers     log_Printf(LogPHASE, "Radius: Request sent\n");
970f0cdd9c0SBrian Somers     log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout);
971f0cdd9c0SBrian Somers     r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
972f0cdd9c0SBrian Somers     r->cx.timer.func = radius_Timeout;
973c42627ffSBrian Somers     r->cx.timer.name = "radius auth";
974f0cdd9c0SBrian Somers     r->cx.timer.arg = r;
975f0cdd9c0SBrian Somers     timer_Start(&r->cx.timer);
976f0cdd9c0SBrian Somers   }
977a16061b2SBrian Somers 
978a16061b2SBrian Somers   return 1;
979f0cdd9c0SBrian Somers }
980f0cdd9c0SBrian Somers 
981cf7c10d0SHajimu UMEMOTO /* Fetch IP, netmask from IPCP */
982cf7c10d0SHajimu UMEMOTO void
983cf7c10d0SHajimu UMEMOTO radius_Account_Set_Ip(struct radacct *ac, struct in_addr *peer_ip,
984cf7c10d0SHajimu UMEMOTO 		      struct in_addr *netmask)
985cf7c10d0SHajimu UMEMOTO {
986cf7c10d0SHajimu UMEMOTO   ac->proto = PROTO_IPCP;
9872cc2a59dSHajimu UMEMOTO   memcpy(&ac->peer.ip.addr, peer_ip, sizeof(ac->peer.ip.addr));
9882cc2a59dSHajimu UMEMOTO   memcpy(&ac->peer.ip.mask, netmask, sizeof(ac->peer.ip.mask));
989cf7c10d0SHajimu UMEMOTO }
990cf7c10d0SHajimu UMEMOTO 
991cf7c10d0SHajimu UMEMOTO #ifndef NOINET6
992cf7c10d0SHajimu UMEMOTO /* Fetch interface-id from IPV6CP */
993cf7c10d0SHajimu UMEMOTO void
994cf7c10d0SHajimu UMEMOTO radius_Account_Set_Ipv6(struct radacct *ac, u_char *ifid)
995cf7c10d0SHajimu UMEMOTO {
996cf7c10d0SHajimu UMEMOTO   ac->proto = PROTO_IPV6CP;
9972cc2a59dSHajimu UMEMOTO   memcpy(&ac->peer.ipv6.ifid, ifid, sizeof(ac->peer.ipv6.ifid));
998cf7c10d0SHajimu UMEMOTO }
999cf7c10d0SHajimu UMEMOTO #endif
1000cf7c10d0SHajimu UMEMOTO 
1001f0cdd9c0SBrian Somers /*
1002794c9bbcSBrian Somers  * Send an accounting request to the RADIUS server
1003794c9bbcSBrian Somers  */
1004794c9bbcSBrian Somers void
1005794c9bbcSBrian Somers radius_Account(struct radius *r, struct radacct *ac, struct datalink *dl,
1006cf7c10d0SHajimu UMEMOTO                int acct_type, struct pppThroughput *stats)
1007794c9bbcSBrian Somers {
1008794c9bbcSBrian Somers   struct timeval tv;
1009de59e178SBrian Somers   int got;
101026e6a622SBrian Somers   char hostname[MAXHOSTNAMELEN];
1011aadbb4eaSBrian Somers #if 0
1012794c9bbcSBrian Somers   struct hostent *hp;
1013794c9bbcSBrian Somers   struct in_addr hostaddr;
10148fb5ef5aSBrian Somers #endif
1015794c9bbcSBrian Somers 
1016794c9bbcSBrian Somers   if (!*r->cfg.file)
1017794c9bbcSBrian Somers     return;
1018794c9bbcSBrian Somers 
1019794c9bbcSBrian Somers   if (r->cx.fd != -1)
1020794c9bbcSBrian Somers     /*
1021794c9bbcSBrian Somers      * We assume that our name/key/challenge is the same as last time,
1022794c9bbcSBrian Somers      * and just continue to wait for the RADIUS server(s).
1023794c9bbcSBrian Somers      */
1024794c9bbcSBrian Somers     return;
1025794c9bbcSBrian Somers 
10268fb5ef5aSBrian Somers   timer_Stop(&r->cx.timer);
1027794c9bbcSBrian Somers 
1028ba093e81SBrian Somers   if ((r->cx.rad = rad_acct_open()) == NULL) {
1029794c9bbcSBrian Somers     log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno));
1030794c9bbcSBrian Somers     return;
1031794c9bbcSBrian Somers   }
1032794c9bbcSBrian Somers 
1033794c9bbcSBrian Somers   if (rad_config(r->cx.rad, r->cfg.file) != 0) {
1034794c9bbcSBrian Somers     log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad));
1035794c9bbcSBrian Somers     rad_close(r->cx.rad);
1036794c9bbcSBrian Somers     return;
1037794c9bbcSBrian Somers   }
1038794c9bbcSBrian Somers 
1039794c9bbcSBrian Somers   if (rad_create_request(r->cx.rad, RAD_ACCOUNTING_REQUEST) != 0) {
1040794c9bbcSBrian Somers     log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad));
1041794c9bbcSBrian Somers     rad_close(r->cx.rad);
1042794c9bbcSBrian Somers     return;
1043794c9bbcSBrian Somers   }
1044794c9bbcSBrian Somers 
1045794c9bbcSBrian Somers   /* Grab some accounting data and initialize structure */
1046794c9bbcSBrian Somers   if (acct_type == RAD_START) {
1047794c9bbcSBrian Somers     ac->rad_parent = r;
1048794c9bbcSBrian Somers     /* Fetch username from datalink */
10494dc4e1eeSBrian Somers     strncpy(ac->user_name, dl->peer.authname, sizeof ac->user_name);
1050794c9bbcSBrian Somers     ac->user_name[AUTHLEN-1] = '\0';
1051794c9bbcSBrian Somers 
1052794c9bbcSBrian Somers     ac->authentic = 2;		/* Assume RADIUS verified auth data */
1053794c9bbcSBrian Somers 
1054794c9bbcSBrian Somers     /* Generate a session ID */
105512b5aabaSBrian Somers     snprintf(ac->session_id, sizeof ac->session_id, "%s%ld-%s%lu",
105612b5aabaSBrian Somers              dl->bundle->cfg.auth.name, (long)getpid(),
10574dc4e1eeSBrian Somers              dl->peer.authname, (unsigned long)stats->uptime);
1058794c9bbcSBrian Somers 
1059794c9bbcSBrian Somers     /* And grab our MP socket name */
1060794c9bbcSBrian Somers     snprintf(ac->multi_session_id, sizeof ac->multi_session_id, "%s",
1061794c9bbcSBrian Somers              dl->bundle->ncp.mp.active ?
1062794c9bbcSBrian Somers              dl->bundle->ncp.mp.server.socket.sun_path : "");
1063794c9bbcSBrian Somers   };
1064794c9bbcSBrian Somers 
1065794c9bbcSBrian Somers   if (rad_put_string(r->cx.rad, RAD_USER_NAME, ac->user_name) != 0 ||
1066794c9bbcSBrian Somers       rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 ||
1067cf7c10d0SHajimu UMEMOTO       rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) {
1068794c9bbcSBrian Somers     log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
1069794c9bbcSBrian Somers     rad_close(r->cx.rad);
1070794c9bbcSBrian Somers     return;
1071794c9bbcSBrian Somers   }
1072cf7c10d0SHajimu UMEMOTO   switch (ac->proto) {
1073cf7c10d0SHajimu UMEMOTO   case PROTO_IPCP:
10742cc2a59dSHajimu UMEMOTO     if (rad_put_addr(r->cx.rad, RAD_FRAMED_IP_ADDRESS,
10752cc2a59dSHajimu UMEMOTO 		     ac->peer.ip.addr) != 0 || \
10762cc2a59dSHajimu UMEMOTO 	rad_put_addr(r->cx.rad, RAD_FRAMED_IP_NETMASK,
10772cc2a59dSHajimu UMEMOTO 		     ac->peer.ip.mask) != 0) {
1078cf7c10d0SHajimu UMEMOTO       log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
1079cf7c10d0SHajimu UMEMOTO       rad_close(r->cx.rad);
1080cf7c10d0SHajimu UMEMOTO       return;
1081cf7c10d0SHajimu UMEMOTO     }
1082cf7c10d0SHajimu UMEMOTO     break;
1083cf7c10d0SHajimu UMEMOTO #ifndef NOINET6
1084cf7c10d0SHajimu UMEMOTO   case PROTO_IPV6CP:
10852cc2a59dSHajimu UMEMOTO     if (rad_put_attr(r->cx.rad, RAD_FRAMED_INTERFACE_ID, ac->peer.ipv6.ifid,
10862cc2a59dSHajimu UMEMOTO 		     sizeof(ac->peer.ipv6.ifid)) != 0) {
1087cf7c10d0SHajimu UMEMOTO       log_Printf(LogERROR, "rad_put_attr: %s\n", rad_strerror(r->cx.rad));
1088cf7c10d0SHajimu UMEMOTO       rad_close(r->cx.rad);
1089cf7c10d0SHajimu UMEMOTO       return;
1090cf7c10d0SHajimu UMEMOTO     }
1091ec3e98b8SHajimu UMEMOTO     if (r->ipv6prefix) {
1092ec3e98b8SHajimu UMEMOTO       /*
1093ec3e98b8SHajimu UMEMOTO        * Since PPP doesn't delegate an IPv6 prefix to a peer,
1094ec3e98b8SHajimu UMEMOTO        * Framed-IPv6-Prefix may be not used, actually.
1095ec3e98b8SHajimu UMEMOTO        */
1096ec3e98b8SHajimu UMEMOTO       if (rad_put_attr(r->cx.rad, RAD_FRAMED_IPV6_PREFIX, r->ipv6prefix,
1097ec3e98b8SHajimu UMEMOTO 		       sizeof(struct in6_addr) + 2) != 0) {
1098ec3e98b8SHajimu UMEMOTO 	log_Printf(LogERROR, "rad_put_attr: %s\n", rad_strerror(r->cx.rad));
1099ec3e98b8SHajimu UMEMOTO 	rad_close(r->cx.rad);
1100ec3e98b8SHajimu UMEMOTO 	return;
1101ec3e98b8SHajimu UMEMOTO       }
1102ec3e98b8SHajimu UMEMOTO     }
1103cf7c10d0SHajimu UMEMOTO     break;
1104cf7c10d0SHajimu UMEMOTO #endif
1105cf7c10d0SHajimu UMEMOTO   default:
1106cf7c10d0SHajimu UMEMOTO     /* We don't log any protocol specific information */
1107cf7c10d0SHajimu UMEMOTO     break;
1108cf7c10d0SHajimu UMEMOTO   }
1109794c9bbcSBrian Somers 
1110794c9bbcSBrian Somers   if (gethostname(hostname, sizeof hostname) != 0)
1111794c9bbcSBrian Somers     log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno));
1112794c9bbcSBrian Somers   else {
1113aadbb4eaSBrian Somers #if 0
1114794c9bbcSBrian Somers     if ((hp = gethostbyname(hostname)) != NULL) {
1115794c9bbcSBrian Somers       hostaddr.s_addr = *(u_long *)hp->h_addr;
1116794c9bbcSBrian Somers       if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) {
1117794c9bbcSBrian Somers         log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
1118794c9bbcSBrian Somers                    rad_strerror(r->cx.rad));
1119794c9bbcSBrian Somers         rad_close(r->cx.rad);
1120794c9bbcSBrian Somers         return;
1121794c9bbcSBrian Somers       }
1122794c9bbcSBrian Somers     }
1123aadbb4eaSBrian Somers #endif
1124794c9bbcSBrian Somers     if (rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) {
1125794c9bbcSBrian Somers       log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
1126794c9bbcSBrian Somers                  rad_strerror(r->cx.rad));
1127794c9bbcSBrian Somers       rad_close(r->cx.rad);
1128794c9bbcSBrian Somers       return;
1129794c9bbcSBrian Somers     }
1130794c9bbcSBrian Somers   }
1131794c9bbcSBrian Somers 
1132de59e178SBrian Somers   radius_put_physical_details(r->cx.rad, dl->physical);
1133794c9bbcSBrian Somers 
1134794c9bbcSBrian Somers   if (rad_put_int(r->cx.rad, RAD_ACCT_STATUS_TYPE, acct_type) != 0 ||
1135794c9bbcSBrian Somers       rad_put_string(r->cx.rad, RAD_ACCT_SESSION_ID, ac->session_id) != 0 ||
1136794c9bbcSBrian Somers       rad_put_string(r->cx.rad, RAD_ACCT_MULTI_SESSION_ID,
1137794c9bbcSBrian Somers                      ac->multi_session_id) != 0 ||
1138794c9bbcSBrian Somers       rad_put_int(r->cx.rad, RAD_ACCT_DELAY_TIME, 0) != 0) {
1139794c9bbcSBrian Somers /* XXX ACCT_DELAY_TIME should be increased each time a packet is waiting */
1140794c9bbcSBrian Somers     log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
1141794c9bbcSBrian Somers     rad_close(r->cx.rad);
1142794c9bbcSBrian Somers     return;
1143794c9bbcSBrian Somers   }
1144794c9bbcSBrian Somers 
1145794c9bbcSBrian Somers   if (acct_type == RAD_STOP)
1146794c9bbcSBrian Somers   /* Show some statistics */
1147794c9bbcSBrian Somers     if (rad_put_int(r->cx.rad, RAD_ACCT_INPUT_OCTETS, stats->OctetsIn) != 0 ||
1148794c9bbcSBrian Somers         rad_put_int(r->cx.rad, RAD_ACCT_INPUT_PACKETS, stats->PacketsIn) != 0 ||
1149794c9bbcSBrian Somers         rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_OCTETS, stats->OctetsOut) != 0 ||
1150794c9bbcSBrian Somers         rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_PACKETS, stats->PacketsOut)
1151794c9bbcSBrian Somers         != 0 ||
1152794c9bbcSBrian Somers         rad_put_int(r->cx.rad, RAD_ACCT_SESSION_TIME, throughput_uptime(stats))
1153794c9bbcSBrian Somers         != 0) {
1154794c9bbcSBrian Somers       log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
1155794c9bbcSBrian Somers       rad_close(r->cx.rad);
1156794c9bbcSBrian Somers       return;
1157794c9bbcSBrian Somers     }
1158794c9bbcSBrian Somers 
1159c42627ffSBrian Somers   r->cx.auth = NULL;			/* Not valid for accounting requests */
1160794c9bbcSBrian Somers   if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv)))
1161794c9bbcSBrian Somers     radius_Process(r, got);
1162794c9bbcSBrian Somers   else {
1163794c9bbcSBrian Somers     log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout);
1164794c9bbcSBrian Somers     r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
1165794c9bbcSBrian Somers     r->cx.timer.func = radius_Timeout;
1166c42627ffSBrian Somers     r->cx.timer.name = "radius acct";
1167794c9bbcSBrian Somers     r->cx.timer.arg = r;
1168794c9bbcSBrian Somers     timer_Start(&r->cx.timer);
1169794c9bbcSBrian Somers   }
1170794c9bbcSBrian Somers }
1171794c9bbcSBrian Somers 
1172794c9bbcSBrian Somers /*
1173f0cdd9c0SBrian Somers  * How do things look at the moment ?
1174f0cdd9c0SBrian Somers  */
1175972a1bcfSBrian Somers void
1176972a1bcfSBrian Somers radius_Show(struct radius *r, struct prompt *p)
1177972a1bcfSBrian Somers {
117874457d3dSBrian Somers   prompt_Printf(p, " Radius config:     %s",
117974457d3dSBrian Somers                 *r->cfg.file ? r->cfg.file : "none");
1180972a1bcfSBrian Somers   if (r->valid) {
1181972a1bcfSBrian Somers     prompt_Printf(p, "\n                IP: %s\n", inet_ntoa(r->ip));
1182972a1bcfSBrian Somers     prompt_Printf(p, "           Netmask: %s\n", inet_ntoa(r->mask));
1183972a1bcfSBrian Somers     prompt_Printf(p, "               MTU: %lu\n", r->mtu);
1184972a1bcfSBrian Somers     prompt_Printf(p, "                VJ: %sabled\n", r->vj ? "en" : "dis");
1185ff8e577bSBrian Somers     prompt_Printf(p, "           Message: %s\n", r->repstr ? r->repstr : "");
11868fb5ef5aSBrian Somers     prompt_Printf(p, "   MPPE Enc Policy: %s\n",
11878fb5ef5aSBrian Somers                   radius_policyname(r->mppe.policy));
11888fb5ef5aSBrian Somers     prompt_Printf(p, "    MPPE Enc Types: %s\n",
11898fb5ef5aSBrian Somers                   radius_typesname(r->mppe.types));
11908fb5ef5aSBrian Somers     prompt_Printf(p, "     MPPE Recv Key: %seceived\n",
11918fb5ef5aSBrian Somers                   r->mppe.recvkey ? "R" : "Not r");
11928fb5ef5aSBrian Somers     prompt_Printf(p, "     MPPE Send Key: %seceived\n",
11938fb5ef5aSBrian Somers                   r->mppe.sendkey ? "R" : "Not r");
1194a16061b2SBrian Somers     prompt_Printf(p, " MS-CHAP2-Response: %s\n",
1195a16061b2SBrian Somers                   r->msrepstr ? r->msrepstr : "");
1196ff8e577bSBrian Somers     prompt_Printf(p, "     Error Message: %s\n", r->errstr ? r->errstr : "");
1197972a1bcfSBrian Somers     if (r->routes)
1198972a1bcfSBrian Somers       route_ShowSticky(p, r->routes, "            Routes", 16);
11990fe74aa4SHajimu UMEMOTO #ifndef NOINET6
12000fe74aa4SHajimu UMEMOTO     if (r->ipv6routes)
12010fe74aa4SHajimu UMEMOTO       route_ShowSticky(p, r->ipv6routes, "            IPv6 Routes", 16);
12020fe74aa4SHajimu UMEMOTO #endif
1203972a1bcfSBrian Somers   } else
1204972a1bcfSBrian Somers     prompt_Printf(p, " (not authenticated)\n");
1205972a1bcfSBrian Somers }
1206