xref: /freebsd/usr.sbin/ppp/radius.c (revision c42627ffffa34588e9dc2f74bad5d17749a56a6c)
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>
316b457978SBrian Somers #include <sys/socket.h>
32972a1bcfSBrian Somers #include <netinet/in_systm.h>
33972a1bcfSBrian Somers #include <netinet/in.h>
34972a1bcfSBrian Somers #include <netinet/ip.h>
35972a1bcfSBrian Somers #include <arpa/inet.h>
36972a1bcfSBrian Somers #include <sys/un.h>
376b457978SBrian Somers #include <net/route.h>
38972a1bcfSBrian Somers 
3910e629b9SBrian Somers #ifdef LOCALRAD
4010e629b9SBrian Somers #include "radlib.h"
4110e629b9SBrian Somers #else
42972a1bcfSBrian Somers #include <radlib.h>
4310e629b9SBrian Somers #endif
4410e629b9SBrian Somers 
4510e629b9SBrian Somers #include <errno.h>
46972a1bcfSBrian Somers #include <stdio.h>
47972a1bcfSBrian Somers #include <stdlib.h>
48972a1bcfSBrian Somers #include <string.h>
49f0cdd9c0SBrian Somers #include <sys/time.h>
50972a1bcfSBrian Somers #include <termios.h>
51f10f5203SBrian Somers #include <ttyent.h>
52f10f5203SBrian Somers #include <unistd.h>
53f10f5203SBrian Somers #include <netdb.h>
54972a1bcfSBrian Somers 
555d9e6103SBrian Somers #include "layer.h"
56972a1bcfSBrian Somers #include "defs.h"
57972a1bcfSBrian Somers #include "log.h"
58972a1bcfSBrian Somers #include "descriptor.h"
59972a1bcfSBrian Somers #include "prompt.h"
60972a1bcfSBrian Somers #include "timer.h"
61972a1bcfSBrian Somers #include "fsm.h"
62972a1bcfSBrian Somers #include "iplist.h"
63972a1bcfSBrian Somers #include "slcompress.h"
64972a1bcfSBrian Somers #include "throughput.h"
65972a1bcfSBrian Somers #include "lqr.h"
66972a1bcfSBrian Somers #include "hdlc.h"
67972a1bcfSBrian Somers #include "mbuf.h"
68972a1bcfSBrian Somers #include "ipcp.h"
69972a1bcfSBrian Somers #include "route.h"
70972a1bcfSBrian Somers #include "command.h"
71972a1bcfSBrian Somers #include "filter.h"
72972a1bcfSBrian Somers #include "lcp.h"
73972a1bcfSBrian Somers #include "ccp.h"
74972a1bcfSBrian Somers #include "link.h"
75972a1bcfSBrian Somers #include "mp.h"
76972a1bcfSBrian Somers #include "radius.h"
77f0cdd9c0SBrian Somers #include "auth.h"
78f0cdd9c0SBrian Somers #include "async.h"
79f0cdd9c0SBrian Somers #include "physical.h"
80f0cdd9c0SBrian Somers #include "chat.h"
81f0cdd9c0SBrian Somers #include "cbcp.h"
82f0cdd9c0SBrian Somers #include "chap.h"
83f0cdd9c0SBrian Somers #include "datalink.h"
84972a1bcfSBrian Somers #include "bundle.h"
85972a1bcfSBrian Somers 
86f0cdd9c0SBrian Somers /*
87f0cdd9c0SBrian Somers  * rad_continue_send_request() has given us `got' (non-zero).  Deal with it.
88f0cdd9c0SBrian Somers  */
89f0cdd9c0SBrian Somers static void
90f0cdd9c0SBrian Somers radius_Process(struct radius *r, int got)
91972a1bcfSBrian Somers {
92972a1bcfSBrian Somers   char *argv[MAXARGS], *nuke;
93f0cdd9c0SBrian Somers   struct bundle *bundle;
9428e610e3SBrian Somers   int argc, addrs;
9528e610e3SBrian Somers   size_t len;
96972a1bcfSBrian Somers   struct in_range dest;
97972a1bcfSBrian Somers   struct in_addr gw;
98f0cdd9c0SBrian Somers   const void *data;
99c42627ffSBrian Somers   const char *stype;
100972a1bcfSBrian Somers 
101f0cdd9c0SBrian Somers   r->cx.fd = -1;		/* Stop select()ing */
102c42627ffSBrian Somers   stype = r->cx.auth ? "auth" : "acct";
103972a1bcfSBrian Somers 
104972a1bcfSBrian Somers   switch (got) {
105972a1bcfSBrian Somers     case RAD_ACCESS_ACCEPT:
106c42627ffSBrian Somers       log_Printf(LogPHASE, "Radius(%s): ACCEPT received\n", stype);
107c42627ffSBrian Somers       if (!r->cx.auth) {
108c42627ffSBrian Somers         rad_close(r->cx.rad);
109c42627ffSBrian Somers         return;
110c42627ffSBrian Somers       }
111972a1bcfSBrian Somers       break;
112972a1bcfSBrian Somers 
113f0cdd9c0SBrian Somers     case RAD_ACCESS_REJECT:
114c42627ffSBrian Somers       log_Printf(LogPHASE, "Radius(%s): REJECT received\n", stype);
115c42627ffSBrian Somers       if (r->cx.auth)
116f0cdd9c0SBrian Somers         auth_Failure(r->cx.auth);
117f0cdd9c0SBrian Somers       rad_close(r->cx.rad);
118f0cdd9c0SBrian Somers       return;
119f0cdd9c0SBrian Somers 
120972a1bcfSBrian Somers     case RAD_ACCESS_CHALLENGE:
121972a1bcfSBrian Somers       /* we can't deal with this (for now) ! */
122f0cdd9c0SBrian Somers       log_Printf(LogPHASE, "Radius: CHALLENGE received (can't handle yet)\n");
123c42627ffSBrian Somers       if (r->cx.auth)
124f0cdd9c0SBrian Somers         auth_Failure(r->cx.auth);
125f0cdd9c0SBrian Somers       rad_close(r->cx.rad);
126f0cdd9c0SBrian Somers       return;
127972a1bcfSBrian Somers 
128794c9bbcSBrian Somers     case RAD_ACCOUNTING_RESPONSE:
129c42627ffSBrian Somers       log_Printf(LogPHASE, "Radius(%s): Accounting response received\n", stype);
130c42627ffSBrian Somers       if (r->cx.auth)
131c42627ffSBrian Somers         auth_Failure(r->cx.auth);		/* unexpected !!! */
132c42627ffSBrian Somers 
133794c9bbcSBrian Somers       /* No further processing for accounting requests, please */
134794c9bbcSBrian Somers       rad_close(r->cx.rad);
135794c9bbcSBrian Somers       return;
136794c9bbcSBrian Somers 
137972a1bcfSBrian Somers     case -1:
138c42627ffSBrian Somers       log_Printf(LogPHASE, "radius(%s): %s\n", stype, rad_strerror(r->cx.rad));
139c42627ffSBrian Somers       if (r->cx.auth)
140f0cdd9c0SBrian Somers         auth_Failure(r->cx.auth);
141f0cdd9c0SBrian Somers       rad_close(r->cx.rad);
142f0cdd9c0SBrian Somers       return;
143972a1bcfSBrian Somers 
144972a1bcfSBrian Somers     default:
145c42627ffSBrian Somers       log_Printf(LogERROR, "rad_send_request(%s): Failed %d: %s\n", stype,
146f0cdd9c0SBrian Somers                  got, rad_strerror(r->cx.rad));
147c42627ffSBrian Somers       if (r->cx.auth)
148f0cdd9c0SBrian Somers         auth_Failure(r->cx.auth);
149f0cdd9c0SBrian Somers       rad_close(r->cx.rad);
150f0cdd9c0SBrian Somers       return;
151972a1bcfSBrian Somers   }
152972a1bcfSBrian Somers 
153972a1bcfSBrian Somers   /* So we've been accepted !  Let's see what we've got in our reply :-I */
154972a1bcfSBrian Somers   r->ip.s_addr = r->mask.s_addr = INADDR_NONE;
155972a1bcfSBrian Somers   r->mtu = 0;
156972a1bcfSBrian Somers   r->vj = 0;
157f0cdd9c0SBrian Somers   while ((got = rad_get_attr(r->cx.rad, &data, &len)) > 0) {
158972a1bcfSBrian Somers     switch (got) {
159972a1bcfSBrian Somers       case RAD_FRAMED_IP_ADDRESS:
160972a1bcfSBrian Somers         r->ip = rad_cvt_addr(data);
161f0cdd9c0SBrian Somers         log_Printf(LogPHASE, "        IP %s\n", inet_ntoa(r->ip));
162972a1bcfSBrian Somers         break;
163972a1bcfSBrian Somers 
164972a1bcfSBrian Somers       case RAD_FRAMED_IP_NETMASK:
165972a1bcfSBrian Somers         r->mask = rad_cvt_addr(data);
166f0cdd9c0SBrian Somers         log_Printf(LogPHASE, "        Netmask %s\n", inet_ntoa(r->mask));
167972a1bcfSBrian Somers         break;
168972a1bcfSBrian Somers 
169972a1bcfSBrian Somers       case RAD_FRAMED_MTU:
170972a1bcfSBrian Somers         r->mtu = rad_cvt_int(data);
171f0cdd9c0SBrian Somers         log_Printf(LogPHASE, "        MTU %lu\n", r->mtu);
172972a1bcfSBrian Somers         break;
173972a1bcfSBrian Somers 
174972a1bcfSBrian Somers       case RAD_FRAMED_ROUTING:
175972a1bcfSBrian Somers         /* Disabled for now - should we automatically set up some filters ? */
176972a1bcfSBrian Somers         /* rad_cvt_int(data); */
177972a1bcfSBrian Somers         /* bit 1 = Send routing packets */
178972a1bcfSBrian Somers         /* bit 2 = Receive routing packets */
179972a1bcfSBrian Somers         break;
180972a1bcfSBrian Somers 
181972a1bcfSBrian Somers       case RAD_FRAMED_COMPRESSION:
182972a1bcfSBrian Somers         r->vj = rad_cvt_int(data) == 1 ? 1 : 0;
183f0cdd9c0SBrian Somers         log_Printf(LogPHASE, "        VJ %sabled\n", r->vj ? "en" : "dis");
184972a1bcfSBrian Somers         break;
185972a1bcfSBrian Somers 
186972a1bcfSBrian Somers       case RAD_FRAMED_ROUTE:
187972a1bcfSBrian Somers         /*
188972a1bcfSBrian Somers          * We expect a string of the format ``dest[/bits] gw [metrics]''
189972a1bcfSBrian Somers          * Any specified metrics are ignored.  MYADDR and HISADDR are
190972a1bcfSBrian Somers          * understood for ``dest'' and ``gw'' and ``0.0.0.0'' is the same
191972a1bcfSBrian Somers          * as ``HISADDR''.
192972a1bcfSBrian Somers          */
193972a1bcfSBrian Somers 
194972a1bcfSBrian Somers         if ((nuke = rad_cvt_string(data, len)) == NULL) {
195f0cdd9c0SBrian Somers           log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
196f0cdd9c0SBrian Somers           rad_close(r->cx.rad);
197f0cdd9c0SBrian Somers           return;
198972a1bcfSBrian Somers         }
199972a1bcfSBrian Somers 
200f0cdd9c0SBrian Somers         log_Printf(LogPHASE, "        Route: %s\n", nuke);
201f0cdd9c0SBrian Somers         bundle = r->cx.auth->physical->dl->bundle;
202972a1bcfSBrian Somers         dest.ipaddr.s_addr = dest.mask.s_addr = INADDR_ANY;
203972a1bcfSBrian Somers         dest.width = 0;
204972a1bcfSBrian Somers         argc = command_Interpret(nuke, strlen(nuke), argv);
205c39aa54eSBrian Somers         if (argc < 0)
206c39aa54eSBrian Somers           log_Printf(LogWARN, "radius: %s: Syntax error\n",
207c39aa54eSBrian Somers                      argc == 1 ? argv[0] : "\"\"");
208c39aa54eSBrian Somers         else if (argc < 2)
209972a1bcfSBrian Somers           log_Printf(LogWARN, "radius: %s: Invalid route\n",
210972a1bcfSBrian Somers                      argc == 1 ? argv[0] : "\"\"");
211972a1bcfSBrian Somers         else if ((strcasecmp(argv[0], "default") != 0 &&
212972a1bcfSBrian Somers                   !ParseAddr(&bundle->ncp.ipcp, argv[0], &dest.ipaddr,
213972a1bcfSBrian Somers                              &dest.mask, &dest.width)) ||
214972a1bcfSBrian Somers                  !ParseAddr(&bundle->ncp.ipcp, argv[1], &gw, NULL, NULL))
215972a1bcfSBrian Somers           log_Printf(LogWARN, "radius: %s %s: Invalid route\n",
216972a1bcfSBrian Somers                      argv[0], argv[1]);
217972a1bcfSBrian Somers         else {
218972a1bcfSBrian Somers           if (dest.width == 32 && strchr(argv[0], '/') == NULL)
219972a1bcfSBrian Somers             /* No mask specified - use the natural mask */
220bc76350eSBrian Somers             dest.mask = addr2mask(dest.ipaddr);
221972a1bcfSBrian Somers           addrs = 0;
222972a1bcfSBrian Somers 
223972a1bcfSBrian Somers           if (!strncasecmp(argv[0], "HISADDR", 7))
224972a1bcfSBrian Somers             addrs = ROUTE_DSTHISADDR;
225972a1bcfSBrian Somers           else if (!strncasecmp(argv[0], "MYADDR", 6))
226972a1bcfSBrian Somers             addrs = ROUTE_DSTMYADDR;
227972a1bcfSBrian Somers 
228972a1bcfSBrian Somers           if (gw.s_addr == INADDR_ANY) {
229972a1bcfSBrian Somers             addrs |= ROUTE_GWHISADDR;
230972a1bcfSBrian Somers             gw = bundle->ncp.ipcp.peer_ip;
231972a1bcfSBrian Somers           } else if (strcasecmp(argv[1], "HISADDR") == 0)
232972a1bcfSBrian Somers             addrs |= ROUTE_GWHISADDR;
233972a1bcfSBrian Somers 
234972a1bcfSBrian Somers           route_Add(&r->routes, addrs, dest.ipaddr, dest.mask, gw);
235972a1bcfSBrian Somers         }
236972a1bcfSBrian Somers         free(nuke);
237972a1bcfSBrian Somers         break;
238972a1bcfSBrian Somers     }
239972a1bcfSBrian Somers   }
240972a1bcfSBrian Somers 
241972a1bcfSBrian Somers   if (got == -1) {
242f0cdd9c0SBrian Somers     log_Printf(LogERROR, "rad_get_attr: %s (failing!)\n",
243f0cdd9c0SBrian Somers                rad_strerror(r->cx.rad));
244f0cdd9c0SBrian Somers     auth_Failure(r->cx.auth);
245f0cdd9c0SBrian Somers     rad_close(r->cx.rad);
246f0cdd9c0SBrian Somers   } else {
247f0cdd9c0SBrian Somers     r->valid = 1;
248f0cdd9c0SBrian Somers     auth_Success(r->cx.auth);
249f0cdd9c0SBrian Somers     rad_close(r->cx.rad);
250f0cdd9c0SBrian Somers   }
251972a1bcfSBrian Somers }
252972a1bcfSBrian Somers 
253f0cdd9c0SBrian Somers /*
2548e7bd08eSBrian Somers  * We've either timed out or select()ed on the read descriptor
255f0cdd9c0SBrian Somers  */
256f0cdd9c0SBrian Somers static void
257f0cdd9c0SBrian Somers radius_Continue(struct radius *r, int sel)
258f0cdd9c0SBrian Somers {
259f0cdd9c0SBrian Somers   struct timeval tv;
260f0cdd9c0SBrian Somers   int got;
261972a1bcfSBrian Somers 
262f0cdd9c0SBrian Somers   timer_Stop(&r->cx.timer);
263f0cdd9c0SBrian Somers   if ((got = rad_continue_send_request(r->cx.rad, sel, &r->cx.fd, &tv)) == 0) {
264f0cdd9c0SBrian Somers     log_Printf(LogPHASE, "Radius: Request re-sent\n");
265f0cdd9c0SBrian Somers     r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
266f0cdd9c0SBrian Somers     timer_Start(&r->cx.timer);
267f0cdd9c0SBrian Somers     return;
268f0cdd9c0SBrian Somers   }
269f0cdd9c0SBrian Somers 
270f0cdd9c0SBrian Somers   radius_Process(r, got);
271f0cdd9c0SBrian Somers }
272f0cdd9c0SBrian Somers 
273f0cdd9c0SBrian Somers /*
274f0cdd9c0SBrian Somers  * Time to call rad_continue_send_request() - timed out.
275f0cdd9c0SBrian Somers  */
276f0cdd9c0SBrian Somers static void
277f0cdd9c0SBrian Somers radius_Timeout(void *v)
278f0cdd9c0SBrian Somers {
279f0cdd9c0SBrian Somers   radius_Continue((struct radius *)v, 0);
280f0cdd9c0SBrian Somers }
281f0cdd9c0SBrian Somers 
282f0cdd9c0SBrian Somers /*
283f0cdd9c0SBrian Somers  * Time to call rad_continue_send_request() - something to read.
284f0cdd9c0SBrian Somers  */
285f0cdd9c0SBrian Somers static void
286f013f33eSBrian Somers radius_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
287f0cdd9c0SBrian Somers {
288f0cdd9c0SBrian Somers   radius_Continue(descriptor2radius(d), 1);
289f0cdd9c0SBrian Somers }
290f0cdd9c0SBrian Somers 
291f0cdd9c0SBrian Somers /*
2928e7bd08eSBrian Somers  * Behave as a struct fdescriptor (descriptor.h)
293f0cdd9c0SBrian Somers  */
294f0cdd9c0SBrian Somers static int
295f013f33eSBrian Somers radius_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
296f0cdd9c0SBrian Somers {
297f0cdd9c0SBrian Somers   struct radius *rad = descriptor2radius(d);
298f0cdd9c0SBrian Somers 
299f0cdd9c0SBrian Somers   if (r && rad->cx.fd != -1) {
300f0cdd9c0SBrian Somers     FD_SET(rad->cx.fd, r);
301f0cdd9c0SBrian Somers     if (*n < rad->cx.fd + 1)
302f0cdd9c0SBrian Somers       *n = rad->cx.fd + 1;
303f0cdd9c0SBrian Somers     log_Printf(LogTIMER, "Radius: fdset(r) %d\n", rad->cx.fd);
30482d6780cSBrian Somers     return 1;
305972a1bcfSBrian Somers   }
306972a1bcfSBrian Somers 
307f0cdd9c0SBrian Somers   return 0;
308f0cdd9c0SBrian Somers }
309f0cdd9c0SBrian Somers 
310f0cdd9c0SBrian Somers /*
3118e7bd08eSBrian Somers  * Behave as a struct fdescriptor (descriptor.h)
312f0cdd9c0SBrian Somers  */
313f0cdd9c0SBrian Somers static int
314f013f33eSBrian Somers radius_IsSet(struct fdescriptor *d, const fd_set *fdset)
315f0cdd9c0SBrian Somers {
316f0cdd9c0SBrian Somers   struct radius *r = descriptor2radius(d);
317f0cdd9c0SBrian Somers 
318f0cdd9c0SBrian Somers   return r && r->cx.fd != -1 && FD_ISSET(r->cx.fd, fdset);
319f0cdd9c0SBrian Somers }
320f0cdd9c0SBrian Somers 
321f0cdd9c0SBrian Somers /*
3228e7bd08eSBrian Somers  * Behave as a struct fdescriptor (descriptor.h)
323f0cdd9c0SBrian Somers  */
324f0cdd9c0SBrian Somers static int
325f013f33eSBrian Somers radius_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
326f0cdd9c0SBrian Somers {
327f0cdd9c0SBrian Somers   /* We never want to write here ! */
328f0cdd9c0SBrian Somers   log_Printf(LogALERT, "radius_Write: Internal error: Bad call !\n");
329f0cdd9c0SBrian Somers   return 0;
330f0cdd9c0SBrian Somers }
331f0cdd9c0SBrian Somers 
332f0cdd9c0SBrian Somers /*
333f0cdd9c0SBrian Somers  * Initialise ourselves
334f0cdd9c0SBrian Somers  */
335f0cdd9c0SBrian Somers void
336f0cdd9c0SBrian Somers radius_Init(struct radius *r)
337f0cdd9c0SBrian Somers {
338f0cdd9c0SBrian Somers   r->valid = 0;
339f0cdd9c0SBrian Somers   r->cx.fd = -1;
340f0cdd9c0SBrian Somers   *r->cfg.file = '\0';;
341f0cdd9c0SBrian Somers   r->desc.type = RADIUS_DESCRIPTOR;
342f0cdd9c0SBrian Somers   r->desc.UpdateSet = radius_UpdateSet;
343f0cdd9c0SBrian Somers   r->desc.IsSet = radius_IsSet;
344f0cdd9c0SBrian Somers   r->desc.Read = radius_Read;
345f0cdd9c0SBrian Somers   r->desc.Write = radius_Write;
346f0cdd9c0SBrian Somers   memset(&r->cx.timer, '\0', sizeof r->cx.timer);
347794c9bbcSBrian Somers   log_Printf(LogDEBUG, "Radius: radius_Init\n");
348f0cdd9c0SBrian Somers }
349f0cdd9c0SBrian Somers 
350f0cdd9c0SBrian Somers /*
351f0cdd9c0SBrian Somers  * Forget everything and go back to initialised state.
352f0cdd9c0SBrian Somers  */
353f0cdd9c0SBrian Somers void
354f0cdd9c0SBrian Somers radius_Destroy(struct radius *r)
355f0cdd9c0SBrian Somers {
356f0cdd9c0SBrian Somers   r->valid = 0;
357794c9bbcSBrian Somers   log_Printf(LogDEBUG, "Radius: radius_Destroy\n");
358f0cdd9c0SBrian Somers   timer_Stop(&r->cx.timer);
359f0cdd9c0SBrian Somers   route_DeleteAll(&r->routes);
360f0cdd9c0SBrian Somers   if (r->cx.fd != -1) {
361f0cdd9c0SBrian Somers     r->cx.fd = -1;
362f0cdd9c0SBrian Somers     rad_close(r->cx.rad);
363f0cdd9c0SBrian Somers   }
364f0cdd9c0SBrian Somers }
365f0cdd9c0SBrian Somers 
366f0cdd9c0SBrian Somers /*
367f0cdd9c0SBrian Somers  * Start an authentication request to the RADIUS server.
368f0cdd9c0SBrian Somers  */
369f0cdd9c0SBrian Somers void
370f0cdd9c0SBrian Somers radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name,
371f0cdd9c0SBrian Somers                     const char *key, const char *challenge)
372f0cdd9c0SBrian Somers {
373f10f5203SBrian Somers   struct ttyent *ttyp;
374f0cdd9c0SBrian Somers   struct timeval tv;
375f10f5203SBrian Somers   int got, slot;
376f10f5203SBrian Somers   char hostname[MAXHOSTNAMELEN];
377f10f5203SBrian Somers   struct hostent *hp;
378f10f5203SBrian Somers   struct in_addr hostaddr;
379f0cdd9c0SBrian Somers 
380f0cdd9c0SBrian Somers   if (!*r->cfg.file)
381f0cdd9c0SBrian Somers     return;
382f0cdd9c0SBrian Somers 
383f0cdd9c0SBrian Somers   if (r->cx.fd != -1)
384f0cdd9c0SBrian Somers     /*
385f0cdd9c0SBrian Somers      * We assume that our name/key/challenge is the same as last time,
386f0cdd9c0SBrian Somers      * and just continue to wait for the RADIUS server(s).
387f0cdd9c0SBrian Somers      */
388f0cdd9c0SBrian Somers     return;
389f0cdd9c0SBrian Somers 
390f0cdd9c0SBrian Somers   radius_Destroy(r);
391f0cdd9c0SBrian Somers 
392794c9bbcSBrian Somers   if ((r->cx.rad = rad_auth_open()) == NULL) {
393794c9bbcSBrian Somers     log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno));
394f0cdd9c0SBrian Somers     return;
395f0cdd9c0SBrian Somers   }
396f0cdd9c0SBrian Somers 
397f0cdd9c0SBrian Somers   if (rad_config(r->cx.rad, r->cfg.file) != 0) {
398f0cdd9c0SBrian Somers     log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad));
399f0cdd9c0SBrian Somers     rad_close(r->cx.rad);
400f0cdd9c0SBrian Somers     return;
401f0cdd9c0SBrian Somers   }
402f0cdd9c0SBrian Somers 
403f0cdd9c0SBrian Somers   if (rad_create_request(r->cx.rad, RAD_ACCESS_REQUEST) != 0) {
404f0cdd9c0SBrian Somers     log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad));
405f0cdd9c0SBrian Somers     rad_close(r->cx.rad);
406f0cdd9c0SBrian Somers     return;
407f0cdd9c0SBrian Somers   }
408f0cdd9c0SBrian Somers 
409f0cdd9c0SBrian Somers   if (rad_put_string(r->cx.rad, RAD_USER_NAME, name) != 0 ||
410f0cdd9c0SBrian Somers       rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 ||
411f0cdd9c0SBrian Somers       rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) {
412f0cdd9c0SBrian Somers     log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
413f0cdd9c0SBrian Somers     rad_close(r->cx.rad);
414f0cdd9c0SBrian Somers     return;
415f0cdd9c0SBrian Somers   }
416f0cdd9c0SBrian Somers 
417f0cdd9c0SBrian Somers   if (challenge != NULL) {
418f0cdd9c0SBrian Somers     /* We're talking CHAP */
419f0cdd9c0SBrian Somers     if (rad_put_string(r->cx.rad, RAD_CHAP_PASSWORD, key) != 0 ||
420f0cdd9c0SBrian Somers         rad_put_string(r->cx.rad, RAD_CHAP_CHALLENGE, challenge) != 0) {
421f0cdd9c0SBrian Somers       log_Printf(LogERROR, "CHAP: rad_put_string: %s\n",
422f0cdd9c0SBrian Somers                  rad_strerror(r->cx.rad));
423f0cdd9c0SBrian Somers       rad_close(r->cx.rad);
424f0cdd9c0SBrian Somers       return;
425f0cdd9c0SBrian Somers     }
426f0cdd9c0SBrian Somers   } else if (rad_put_string(r->cx.rad, RAD_USER_PASSWORD, key) != 0) {
427f0cdd9c0SBrian Somers     /* We're talking PAP */
428f0cdd9c0SBrian Somers     log_Printf(LogERROR, "PAP: rad_put_string: %s\n", rad_strerror(r->cx.rad));
429f0cdd9c0SBrian Somers     rad_close(r->cx.rad);
430f0cdd9c0SBrian Somers     return;
431f0cdd9c0SBrian Somers   }
432f0cdd9c0SBrian Somers 
433f10f5203SBrian Somers   if (gethostname(hostname, sizeof hostname) != 0)
434f10f5203SBrian Somers     log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno));
435f10f5203SBrian Somers   else {
436f10f5203SBrian Somers     if ((hp = gethostbyname(hostname)) != NULL) {
437f10f5203SBrian Somers       hostaddr.s_addr = *(u_long *)hp->h_addr;
438f10f5203SBrian Somers       if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) {
439f10f5203SBrian Somers         log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
440f10f5203SBrian Somers                    rad_strerror(r->cx.rad));
441f10f5203SBrian Somers         rad_close(r->cx.rad);
442f10f5203SBrian Somers         return;
443f10f5203SBrian Somers       }
444f10f5203SBrian Somers     }
445f10f5203SBrian Somers     if (rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) {
446f10f5203SBrian Somers       log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
447f10f5203SBrian Somers                  rad_strerror(r->cx.rad));
448f10f5203SBrian Somers       rad_close(r->cx.rad);
449f10f5203SBrian Somers       return;
450f10f5203SBrian Somers     }
451f10f5203SBrian Somers   }
452f10f5203SBrian Somers 
453f10f5203SBrian Somers   if (authp->physical->handler &&
454f10f5203SBrian Somers       authp->physical->handler->type == TTY_DEVICE) {
455f10f5203SBrian Somers     setttyent();
456f10f5203SBrian Somers     for (slot = 1; (ttyp = getttyent()); ++slot)
457f10f5203SBrian Somers       if (!strcmp(ttyp->ty_name, authp->physical->name.base)) {
458f10f5203SBrian Somers         if(rad_put_int(r->cx.rad, RAD_NAS_PORT, slot) != 0) {
459f10f5203SBrian Somers           log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
460f10f5203SBrian Somers                       rad_strerror(r->cx.rad));
461f10f5203SBrian Somers           rad_close(r->cx.rad);
462f10f5203SBrian Somers           endttyent();
463f10f5203SBrian Somers           return;
464f10f5203SBrian Somers         }
465f10f5203SBrian Somers         break;
466f10f5203SBrian Somers       }
467f10f5203SBrian Somers     endttyent();
468f10f5203SBrian Somers   }
469f10f5203SBrian Somers 
470f10f5203SBrian Somers 
471c42627ffSBrian Somers   r->cx.auth = authp;
472f0cdd9c0SBrian Somers   if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv)))
473f0cdd9c0SBrian Somers     radius_Process(r, got);
474f0cdd9c0SBrian Somers   else {
475f0cdd9c0SBrian Somers     log_Printf(LogPHASE, "Radius: Request sent\n");
476f0cdd9c0SBrian Somers     log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout);
477f0cdd9c0SBrian Somers     r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
478f0cdd9c0SBrian Somers     r->cx.timer.func = radius_Timeout;
479c42627ffSBrian Somers     r->cx.timer.name = "radius auth";
480f0cdd9c0SBrian Somers     r->cx.timer.arg = r;
481f0cdd9c0SBrian Somers     timer_Start(&r->cx.timer);
482f0cdd9c0SBrian Somers   }
483f0cdd9c0SBrian Somers }
484f0cdd9c0SBrian Somers 
485f0cdd9c0SBrian Somers /*
486794c9bbcSBrian Somers  * Send an accounting request to the RADIUS server
487794c9bbcSBrian Somers  */
488794c9bbcSBrian Somers void
489794c9bbcSBrian Somers radius_Account(struct radius *r, struct radacct *ac, struct datalink *dl,
490794c9bbcSBrian Somers                int acct_type, struct in_addr *peer_ip, struct in_addr *netmask,
491794c9bbcSBrian Somers                struct pppThroughput *stats)
492794c9bbcSBrian Somers {
493794c9bbcSBrian Somers   struct ttyent *ttyp;
494794c9bbcSBrian Somers   struct timeval tv;
495794c9bbcSBrian Somers   int got, slot;
496794c9bbcSBrian Somers   char hostname[MAXHOSTNAMELEN];
497794c9bbcSBrian Somers   struct hostent *hp;
498794c9bbcSBrian Somers   struct in_addr hostaddr;
499794c9bbcSBrian Somers 
500794c9bbcSBrian Somers   if (!*r->cfg.file)
501794c9bbcSBrian Somers     return;
502794c9bbcSBrian Somers 
503794c9bbcSBrian Somers   if (r->cx.fd != -1)
504794c9bbcSBrian Somers     /*
505794c9bbcSBrian Somers      * We assume that our name/key/challenge is the same as last time,
506794c9bbcSBrian Somers      * and just continue to wait for the RADIUS server(s).
507794c9bbcSBrian Somers      */
508794c9bbcSBrian Somers     return;
509794c9bbcSBrian Somers 
510794c9bbcSBrian Somers   radius_Destroy(r);
511794c9bbcSBrian Somers 
512ba093e81SBrian Somers   if ((r->cx.rad = rad_acct_open()) == NULL) {
513794c9bbcSBrian Somers     log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno));
514794c9bbcSBrian Somers     return;
515794c9bbcSBrian Somers   }
516794c9bbcSBrian Somers 
517794c9bbcSBrian Somers   if (rad_config(r->cx.rad, r->cfg.file) != 0) {
518794c9bbcSBrian Somers     log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad));
519794c9bbcSBrian Somers     rad_close(r->cx.rad);
520794c9bbcSBrian Somers     return;
521794c9bbcSBrian Somers   }
522794c9bbcSBrian Somers 
523794c9bbcSBrian Somers   if (rad_create_request(r->cx.rad, RAD_ACCOUNTING_REQUEST) != 0) {
524794c9bbcSBrian Somers     log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad));
525794c9bbcSBrian Somers     rad_close(r->cx.rad);
526794c9bbcSBrian Somers     return;
527794c9bbcSBrian Somers   }
528794c9bbcSBrian Somers 
529794c9bbcSBrian Somers   /* Grab some accounting data and initialize structure */
530794c9bbcSBrian Somers   if (acct_type == RAD_START) {
531794c9bbcSBrian Somers     ac->rad_parent = r;
532794c9bbcSBrian Somers     /* Fetch username from datalink */
533794c9bbcSBrian Somers     strncpy(ac->user_name, dl->peer.authname, sizeof ac->user_name);
534794c9bbcSBrian Somers     ac->user_name[AUTHLEN-1] = '\0';
535794c9bbcSBrian Somers 
536794c9bbcSBrian Somers     ac->authentic = 2;		/* Assume RADIUS verified auth data */
537794c9bbcSBrian Somers 
538794c9bbcSBrian Somers     /* Generate a session ID */
539794c9bbcSBrian Somers     snprintf(ac->session_id, sizeof ac->session_id, "%s%d-%s%lu",
540794c9bbcSBrian Somers              dl->bundle->cfg.auth.name, (int)getpid(),
541794c9bbcSBrian Somers              dl->peer.authname, (unsigned long)stats->uptime);
542794c9bbcSBrian Somers 
543794c9bbcSBrian Somers     /* And grab our MP socket name */
544794c9bbcSBrian Somers     snprintf(ac->multi_session_id, sizeof ac->multi_session_id, "%s",
545794c9bbcSBrian Somers              dl->bundle->ncp.mp.active ?
546794c9bbcSBrian Somers              dl->bundle->ncp.mp.server.socket.sun_path : "");
547794c9bbcSBrian Somers 
548794c9bbcSBrian Somers     /* Fetch IP, netmask from IPCP */
549794c9bbcSBrian Somers     memcpy(&ac->ip, peer_ip, sizeof(ac->ip));
550794c9bbcSBrian Somers     memcpy(&ac->mask, netmask, sizeof(ac->mask));
551794c9bbcSBrian Somers   };
552794c9bbcSBrian Somers 
553794c9bbcSBrian Somers   if (rad_put_string(r->cx.rad, RAD_USER_NAME, ac->user_name) != 0 ||
554794c9bbcSBrian Somers       rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 ||
555794c9bbcSBrian Somers       rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0 ||
556794c9bbcSBrian Somers       rad_put_addr(r->cx.rad, RAD_FRAMED_IP_ADDRESS, ac->ip) != 0 ||
557794c9bbcSBrian Somers       rad_put_addr(r->cx.rad, RAD_FRAMED_IP_NETMASK, ac->mask) != 0) {
558794c9bbcSBrian Somers     log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
559794c9bbcSBrian Somers     rad_close(r->cx.rad);
560794c9bbcSBrian Somers     return;
561794c9bbcSBrian Somers   }
562794c9bbcSBrian Somers 
563794c9bbcSBrian Somers   if (gethostname(hostname, sizeof hostname) != 0)
564794c9bbcSBrian Somers     log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno));
565794c9bbcSBrian Somers   else {
566794c9bbcSBrian Somers     if ((hp = gethostbyname(hostname)) != NULL) {
567794c9bbcSBrian Somers       hostaddr.s_addr = *(u_long *)hp->h_addr;
568794c9bbcSBrian Somers       if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) {
569794c9bbcSBrian Somers         log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
570794c9bbcSBrian Somers                    rad_strerror(r->cx.rad));
571794c9bbcSBrian Somers         rad_close(r->cx.rad);
572794c9bbcSBrian Somers         return;
573794c9bbcSBrian Somers       }
574794c9bbcSBrian Somers     }
575794c9bbcSBrian Somers     if (rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) {
576794c9bbcSBrian Somers       log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
577794c9bbcSBrian Somers                  rad_strerror(r->cx.rad));
578794c9bbcSBrian Somers       rad_close(r->cx.rad);
579794c9bbcSBrian Somers       return;
580794c9bbcSBrian Somers     }
581794c9bbcSBrian Somers   }
582794c9bbcSBrian Somers 
583794c9bbcSBrian Somers   if (dl->physical->handler &&
584794c9bbcSBrian Somers       dl->physical->handler->type == TTY_DEVICE) {
585794c9bbcSBrian Somers     setttyent();
586794c9bbcSBrian Somers     for (slot = 1; (ttyp = getttyent()); ++slot)
587794c9bbcSBrian Somers       if (!strcmp(ttyp->ty_name, dl->physical->name.base)) {
588794c9bbcSBrian Somers         if(rad_put_int(r->cx.rad, RAD_NAS_PORT, slot) != 0) {
589794c9bbcSBrian Somers           log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
590794c9bbcSBrian Somers                       rad_strerror(r->cx.rad));
591794c9bbcSBrian Somers           rad_close(r->cx.rad);
592794c9bbcSBrian Somers           endttyent();
593794c9bbcSBrian Somers           return;
594794c9bbcSBrian Somers         }
595794c9bbcSBrian Somers         break;
596794c9bbcSBrian Somers       }
597794c9bbcSBrian Somers     endttyent();
598794c9bbcSBrian Somers   }
599794c9bbcSBrian Somers 
600794c9bbcSBrian Somers   if (rad_put_int(r->cx.rad, RAD_ACCT_STATUS_TYPE, acct_type) != 0 ||
601794c9bbcSBrian Somers       rad_put_string(r->cx.rad, RAD_ACCT_SESSION_ID, ac->session_id) != 0 ||
602794c9bbcSBrian Somers       rad_put_string(r->cx.rad, RAD_ACCT_MULTI_SESSION_ID,
603794c9bbcSBrian Somers                      ac->multi_session_id) != 0 ||
604794c9bbcSBrian Somers       rad_put_int(r->cx.rad, RAD_ACCT_DELAY_TIME, 0) != 0) {
605794c9bbcSBrian Somers /* XXX ACCT_DELAY_TIME should be increased each time a packet is waiting */
606794c9bbcSBrian Somers     log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
607794c9bbcSBrian Somers     rad_close(r->cx.rad);
608794c9bbcSBrian Somers     return;
609794c9bbcSBrian Somers   }
610794c9bbcSBrian Somers 
611794c9bbcSBrian Somers   if (acct_type == RAD_STOP)
612794c9bbcSBrian Somers   /* Show some statistics */
613794c9bbcSBrian Somers     if (rad_put_int(r->cx.rad, RAD_ACCT_INPUT_OCTETS, stats->OctetsIn) != 0 ||
614794c9bbcSBrian Somers         rad_put_int(r->cx.rad, RAD_ACCT_INPUT_PACKETS, stats->PacketsIn) != 0 ||
615794c9bbcSBrian Somers         rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_OCTETS, stats->OctetsOut) != 0 ||
616794c9bbcSBrian Somers         rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_PACKETS, stats->PacketsOut)
617794c9bbcSBrian Somers         != 0 ||
618794c9bbcSBrian Somers         rad_put_int(r->cx.rad, RAD_ACCT_SESSION_TIME, throughput_uptime(stats))
619794c9bbcSBrian Somers         != 0) {
620794c9bbcSBrian Somers       log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
621794c9bbcSBrian Somers       rad_close(r->cx.rad);
622794c9bbcSBrian Somers       return;
623794c9bbcSBrian Somers     }
624794c9bbcSBrian Somers 
625c42627ffSBrian Somers   r->cx.auth = NULL;			/* Not valid for accounting requests */
626794c9bbcSBrian Somers   if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv)))
627794c9bbcSBrian Somers     radius_Process(r, got);
628794c9bbcSBrian Somers   else {
629794c9bbcSBrian Somers     log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout);
630794c9bbcSBrian Somers     r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
631794c9bbcSBrian Somers     r->cx.timer.func = radius_Timeout;
632c42627ffSBrian Somers     r->cx.timer.name = "radius acct";
633794c9bbcSBrian Somers     r->cx.timer.arg = r;
634794c9bbcSBrian Somers     timer_Start(&r->cx.timer);
635794c9bbcSBrian Somers   }
636794c9bbcSBrian Somers }
637794c9bbcSBrian Somers 
638794c9bbcSBrian Somers /*
639f0cdd9c0SBrian Somers  * How do things look at the moment ?
640f0cdd9c0SBrian Somers  */
641972a1bcfSBrian Somers void
642972a1bcfSBrian Somers radius_Show(struct radius *r, struct prompt *p)
643972a1bcfSBrian Somers {
64474457d3dSBrian Somers   prompt_Printf(p, " Radius config:     %s",
64574457d3dSBrian Somers                 *r->cfg.file ? r->cfg.file : "none");
646972a1bcfSBrian Somers   if (r->valid) {
647972a1bcfSBrian Somers     prompt_Printf(p, "\n                IP: %s\n", inet_ntoa(r->ip));
648972a1bcfSBrian Somers     prompt_Printf(p, "           Netmask: %s\n", inet_ntoa(r->mask));
649972a1bcfSBrian Somers     prompt_Printf(p, "               MTU: %lu\n", r->mtu);
650972a1bcfSBrian Somers     prompt_Printf(p, "                VJ: %sabled\n", r->vj ? "en" : "dis");
651972a1bcfSBrian Somers     if (r->routes)
652972a1bcfSBrian Somers       route_ShowSticky(p, r->routes, "            Routes", 16);
653972a1bcfSBrian Somers   } else
654972a1bcfSBrian Somers     prompt_Printf(p, " (not authenticated)\n");
655972a1bcfSBrian Somers }
656