xref: /freebsd/usr.sbin/ppp/radius.c (revision 12b5aaba3974df2eb28cf0844f3a767f5aea06ea)
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"
41ff8e577bSBrian Somers #include "radlib_vs.h"
4210e629b9SBrian Somers #else
43972a1bcfSBrian Somers #include <radlib.h>
44ff8e577bSBrian Somers #include <radlib_vs.h>
4510e629b9SBrian Somers #endif
4610e629b9SBrian Somers 
4710e629b9SBrian Somers #include <errno.h>
48972a1bcfSBrian Somers #include <stdio.h>
49972a1bcfSBrian Somers #include <stdlib.h>
50972a1bcfSBrian Somers #include <string.h>
51f0cdd9c0SBrian Somers #include <sys/time.h>
52972a1bcfSBrian Somers #include <termios.h>
53f10f5203SBrian Somers #include <unistd.h>
54f10f5203SBrian Somers #include <netdb.h>
55972a1bcfSBrian Somers 
565d9e6103SBrian Somers #include "layer.h"
57972a1bcfSBrian Somers #include "defs.h"
58972a1bcfSBrian Somers #include "log.h"
59972a1bcfSBrian Somers #include "descriptor.h"
60972a1bcfSBrian Somers #include "prompt.h"
61972a1bcfSBrian Somers #include "timer.h"
62972a1bcfSBrian Somers #include "fsm.h"
63972a1bcfSBrian Somers #include "iplist.h"
64972a1bcfSBrian Somers #include "slcompress.h"
65972a1bcfSBrian Somers #include "throughput.h"
66972a1bcfSBrian Somers #include "lqr.h"
67972a1bcfSBrian Somers #include "hdlc.h"
68972a1bcfSBrian Somers #include "mbuf.h"
6930949fd4SBrian Somers #include "ncpaddr.h"
7030949fd4SBrian Somers #include "ip.h"
71972a1bcfSBrian Somers #include "ipcp.h"
7230949fd4SBrian Somers #include "ipv6cp.h"
73972a1bcfSBrian Somers #include "route.h"
74972a1bcfSBrian Somers #include "command.h"
75972a1bcfSBrian Somers #include "filter.h"
76972a1bcfSBrian Somers #include "lcp.h"
77972a1bcfSBrian Somers #include "ccp.h"
78972a1bcfSBrian Somers #include "link.h"
79972a1bcfSBrian Somers #include "mp.h"
80972a1bcfSBrian Somers #include "radius.h"
81f0cdd9c0SBrian Somers #include "auth.h"
82f0cdd9c0SBrian Somers #include "async.h"
83f0cdd9c0SBrian Somers #include "physical.h"
84f0cdd9c0SBrian Somers #include "chat.h"
85f0cdd9c0SBrian Somers #include "cbcp.h"
86f0cdd9c0SBrian Somers #include "chap.h"
87f0cdd9c0SBrian Somers #include "datalink.h"
8830949fd4SBrian Somers #include "ncp.h"
89972a1bcfSBrian Somers #include "bundle.h"
90ff8e577bSBrian Somers #include "proto.h"
91ff8e577bSBrian Somers 
92ff8e577bSBrian Somers #ifndef NODES
93a16061b2SBrian Somers struct mschap_response {
94ff8e577bSBrian Somers   u_char ident;
95ff8e577bSBrian Somers   u_char flags;
96ff8e577bSBrian Somers   u_char lm_response[24];
97ff8e577bSBrian Somers   u_char nt_response[24];
98ff8e577bSBrian Somers };
99a16061b2SBrian Somers 
100a16061b2SBrian Somers struct mschap2_response {
101a16061b2SBrian Somers   u_char ident;
102a16061b2SBrian Somers   u_char flags;
103a16061b2SBrian Somers   u_char pchallenge[16];
104a16061b2SBrian Somers   u_char reserved[8];
105a16061b2SBrian Somers   u_char response[24];
106a16061b2SBrian Somers };
107ff8e577bSBrian Somers #endif
108972a1bcfSBrian Somers 
109f0cdd9c0SBrian Somers /*
110f0cdd9c0SBrian Somers  * rad_continue_send_request() has given us `got' (non-zero).  Deal with it.
111f0cdd9c0SBrian Somers  */
112f0cdd9c0SBrian Somers static void
113f0cdd9c0SBrian Somers radius_Process(struct radius *r, int got)
114972a1bcfSBrian Somers {
115972a1bcfSBrian Somers   char *argv[MAXARGS], *nuke;
116f0cdd9c0SBrian Somers   struct bundle *bundle;
117ff8e577bSBrian Somers   int argc, addrs, res, width;
11828e610e3SBrian Somers   size_t len;
11930949fd4SBrian Somers   struct ncprange dest;
12030949fd4SBrian Somers   struct ncpaddr gw;
121f0cdd9c0SBrian Somers   const void *data;
122c42627ffSBrian Somers   const char *stype;
123ff8e577bSBrian Somers   u_int32_t ipaddr, vendor;
12430949fd4SBrian Somers   struct in_addr ip;
125972a1bcfSBrian Somers 
126f0cdd9c0SBrian Somers   r->cx.fd = -1;		/* Stop select()ing */
127c42627ffSBrian Somers   stype = r->cx.auth ? "auth" : "acct";
128972a1bcfSBrian Somers 
129972a1bcfSBrian Somers   switch (got) {
130972a1bcfSBrian Somers     case RAD_ACCESS_ACCEPT:
131c42627ffSBrian Somers       log_Printf(LogPHASE, "Radius(%s): ACCEPT received\n", stype);
132c42627ffSBrian Somers       if (!r->cx.auth) {
133c42627ffSBrian Somers         rad_close(r->cx.rad);
134c42627ffSBrian Somers         return;
135c42627ffSBrian Somers       }
136972a1bcfSBrian Somers       break;
137972a1bcfSBrian Somers 
138f0cdd9c0SBrian Somers     case RAD_ACCESS_REJECT:
139c42627ffSBrian Somers       log_Printf(LogPHASE, "Radius(%s): REJECT received\n", stype);
140ff8e577bSBrian Somers       if (!r->cx.auth) {
141f0cdd9c0SBrian Somers         rad_close(r->cx.rad);
142f0cdd9c0SBrian Somers         return;
143ff8e577bSBrian Somers       }
144ff8e577bSBrian Somers       break;
145f0cdd9c0SBrian Somers 
146972a1bcfSBrian Somers     case RAD_ACCESS_CHALLENGE:
147972a1bcfSBrian Somers       /* we can't deal with this (for now) ! */
148f0cdd9c0SBrian Somers       log_Printf(LogPHASE, "Radius: CHALLENGE received (can't handle yet)\n");
149c42627ffSBrian Somers       if (r->cx.auth)
150f0cdd9c0SBrian Somers         auth_Failure(r->cx.auth);
151f0cdd9c0SBrian Somers       rad_close(r->cx.rad);
152f0cdd9c0SBrian Somers       return;
153972a1bcfSBrian Somers 
154794c9bbcSBrian Somers     case RAD_ACCOUNTING_RESPONSE:
155c42627ffSBrian Somers       log_Printf(LogPHASE, "Radius(%s): Accounting response received\n", stype);
156c42627ffSBrian Somers       if (r->cx.auth)
157c42627ffSBrian Somers         auth_Failure(r->cx.auth);		/* unexpected !!! */
158c42627ffSBrian Somers 
159794c9bbcSBrian Somers       /* No further processing for accounting requests, please */
160794c9bbcSBrian Somers       rad_close(r->cx.rad);
161794c9bbcSBrian Somers       return;
162794c9bbcSBrian Somers 
163972a1bcfSBrian Somers     case -1:
164c42627ffSBrian Somers       log_Printf(LogPHASE, "radius(%s): %s\n", stype, rad_strerror(r->cx.rad));
165c42627ffSBrian Somers       if (r->cx.auth)
166f0cdd9c0SBrian Somers         auth_Failure(r->cx.auth);
167f0cdd9c0SBrian Somers       rad_close(r->cx.rad);
168f0cdd9c0SBrian Somers       return;
169972a1bcfSBrian Somers 
170972a1bcfSBrian Somers     default:
171c42627ffSBrian Somers       log_Printf(LogERROR, "rad_send_request(%s): Failed %d: %s\n", stype,
172f0cdd9c0SBrian Somers                  got, rad_strerror(r->cx.rad));
173c42627ffSBrian Somers       if (r->cx.auth)
174f0cdd9c0SBrian Somers         auth_Failure(r->cx.auth);
175f0cdd9c0SBrian Somers       rad_close(r->cx.rad);
176f0cdd9c0SBrian Somers       return;
177972a1bcfSBrian Somers   }
178972a1bcfSBrian Somers 
179ff8e577bSBrian Somers   /* Let's see what we've got in our reply */
180972a1bcfSBrian Somers   r->ip.s_addr = r->mask.s_addr = INADDR_NONE;
181972a1bcfSBrian Somers   r->mtu = 0;
182972a1bcfSBrian Somers   r->vj = 0;
183ff8e577bSBrian Somers   while ((res = rad_get_attr(r->cx.rad, &data, &len)) > 0) {
184ff8e577bSBrian Somers     switch (res) {
185972a1bcfSBrian Somers       case RAD_FRAMED_IP_ADDRESS:
186972a1bcfSBrian Somers         r->ip = rad_cvt_addr(data);
187f0cdd9c0SBrian Somers         log_Printf(LogPHASE, " IP %s\n", inet_ntoa(r->ip));
188972a1bcfSBrian Somers         break;
189972a1bcfSBrian Somers 
190bf1eaec5SBrian Somers       case RAD_FILTER_ID:
191bf1eaec5SBrian Somers         free(r->filterid);
192bf1eaec5SBrian Somers         if ((r->filterid = rad_cvt_string(data, len)) == NULL) {
193bf1eaec5SBrian Somers           log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
194ff8e577bSBrian Somers           auth_Failure(r->cx.auth);
195bf1eaec5SBrian Somers           rad_close(r->cx.rad);
196bf1eaec5SBrian Somers           return;
197bf1eaec5SBrian Somers         }
198bf1eaec5SBrian Somers         log_Printf(LogPHASE, " Filter \"%s\"\n", r->filterid);
199bf1eaec5SBrian Somers         break;
200bf1eaec5SBrian Somers 
201bf1eaec5SBrian Somers       case RAD_SESSION_TIMEOUT:
202bf1eaec5SBrian Somers         r->sessiontime = rad_cvt_int(data);
203bf1eaec5SBrian Somers         log_Printf(LogPHASE, " Session-Timeout %lu\n", r->sessiontime);
204bf1eaec5SBrian Somers         break;
205bf1eaec5SBrian Somers 
206972a1bcfSBrian Somers       case RAD_FRAMED_IP_NETMASK:
207972a1bcfSBrian Somers         r->mask = rad_cvt_addr(data);
208f0cdd9c0SBrian Somers         log_Printf(LogPHASE, " Netmask %s\n", inet_ntoa(r->mask));
209972a1bcfSBrian Somers         break;
210972a1bcfSBrian Somers 
211972a1bcfSBrian Somers       case RAD_FRAMED_MTU:
212972a1bcfSBrian Somers         r->mtu = rad_cvt_int(data);
213f0cdd9c0SBrian Somers         log_Printf(LogPHASE, " MTU %lu\n", r->mtu);
214972a1bcfSBrian Somers         break;
215972a1bcfSBrian Somers 
216972a1bcfSBrian Somers       case RAD_FRAMED_ROUTING:
217972a1bcfSBrian Somers         /* Disabled for now - should we automatically set up some filters ? */
218972a1bcfSBrian Somers         /* rad_cvt_int(data); */
219972a1bcfSBrian Somers         /* bit 1 = Send routing packets */
220972a1bcfSBrian Somers         /* bit 2 = Receive routing packets */
221972a1bcfSBrian Somers         break;
222972a1bcfSBrian Somers 
223972a1bcfSBrian Somers       case RAD_FRAMED_COMPRESSION:
224972a1bcfSBrian Somers         r->vj = rad_cvt_int(data) == 1 ? 1 : 0;
225f0cdd9c0SBrian Somers         log_Printf(LogPHASE, " VJ %sabled\n", r->vj ? "en" : "dis");
226972a1bcfSBrian Somers         break;
227972a1bcfSBrian Somers 
228972a1bcfSBrian Somers       case RAD_FRAMED_ROUTE:
229972a1bcfSBrian Somers         /*
230972a1bcfSBrian Somers          * We expect a string of the format ``dest[/bits] gw [metrics]''
231972a1bcfSBrian Somers          * Any specified metrics are ignored.  MYADDR and HISADDR are
232972a1bcfSBrian Somers          * understood for ``dest'' and ``gw'' and ``0.0.0.0'' is the same
233972a1bcfSBrian Somers          * as ``HISADDR''.
234972a1bcfSBrian Somers          */
235972a1bcfSBrian Somers 
236972a1bcfSBrian Somers         if ((nuke = rad_cvt_string(data, len)) == NULL) {
237f0cdd9c0SBrian Somers           log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
238ff8e577bSBrian Somers           auth_Failure(r->cx.auth);
239f0cdd9c0SBrian Somers           rad_close(r->cx.rad);
240f0cdd9c0SBrian Somers           return;
241972a1bcfSBrian Somers         }
242972a1bcfSBrian Somers 
243f0cdd9c0SBrian Somers         log_Printf(LogPHASE, " Route: %s\n", nuke);
244f0cdd9c0SBrian Somers         bundle = r->cx.auth->physical->dl->bundle;
24530949fd4SBrian Somers         ip.s_addr = INADDR_ANY;
24630949fd4SBrian Somers         ncprange_setip4host(&dest, ip);
247972a1bcfSBrian Somers         argc = command_Interpret(nuke, strlen(nuke), argv);
248c39aa54eSBrian Somers         if (argc < 0)
249c39aa54eSBrian Somers           log_Printf(LogWARN, "radius: %s: Syntax error\n",
250c39aa54eSBrian Somers                      argc == 1 ? argv[0] : "\"\"");
251c39aa54eSBrian Somers         else if (argc < 2)
252972a1bcfSBrian Somers           log_Printf(LogWARN, "radius: %s: Invalid route\n",
253972a1bcfSBrian Somers                      argc == 1 ? argv[0] : "\"\"");
254972a1bcfSBrian Somers         else if ((strcasecmp(argv[0], "default") != 0 &&
25530949fd4SBrian Somers                   !ncprange_aton(&dest, &bundle->ncp, argv[0])) ||
25630949fd4SBrian Somers                  !ncpaddr_aton(&gw, &bundle->ncp, argv[1]))
257972a1bcfSBrian Somers           log_Printf(LogWARN, "radius: %s %s: Invalid route\n",
258972a1bcfSBrian Somers                      argv[0], argv[1]);
259972a1bcfSBrian Somers         else {
26030949fd4SBrian Somers           ncprange_getwidth(&dest, &width);
26130949fd4SBrian Somers           if (width == 32 && strchr(argv[0], '/') == NULL) {
262972a1bcfSBrian Somers             /* No mask specified - use the natural mask */
26330949fd4SBrian Somers             ncprange_getip4addr(&dest, &ip);
26430949fd4SBrian Somers             ncprange_setip4mask(&dest, addr2mask(ip));
26530949fd4SBrian Somers           }
266972a1bcfSBrian Somers           addrs = 0;
267972a1bcfSBrian Somers 
268972a1bcfSBrian Somers           if (!strncasecmp(argv[0], "HISADDR", 7))
269972a1bcfSBrian Somers             addrs = ROUTE_DSTHISADDR;
270972a1bcfSBrian Somers           else if (!strncasecmp(argv[0], "MYADDR", 6))
271972a1bcfSBrian Somers             addrs = ROUTE_DSTMYADDR;
272972a1bcfSBrian Somers 
27330949fd4SBrian Somers           if (ncpaddr_getip4addr(&gw, &ipaddr) && ipaddr == INADDR_ANY) {
274972a1bcfSBrian Somers             addrs |= ROUTE_GWHISADDR;
27530949fd4SBrian Somers             ncpaddr_setip4(&gw, bundle->ncp.ipcp.peer_ip);
276972a1bcfSBrian Somers           } else if (strcasecmp(argv[1], "HISADDR") == 0)
277972a1bcfSBrian Somers             addrs |= ROUTE_GWHISADDR;
278972a1bcfSBrian Somers 
27930949fd4SBrian Somers           route_Add(&r->routes, addrs, &dest, &gw);
280972a1bcfSBrian Somers         }
281972a1bcfSBrian Somers         free(nuke);
282972a1bcfSBrian Somers         break;
283972a1bcfSBrian Somers 
284ff8e577bSBrian Somers       case RAD_REPLY_MESSAGE:
285ff8e577bSBrian Somers         free(r->repstr);
286ff8e577bSBrian Somers         if ((r->repstr = rad_cvt_string(data, len)) == NULL) {
287ff8e577bSBrian Somers           log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
288ff8e577bSBrian Somers           auth_Failure(r->cx.auth);
289ff8e577bSBrian Somers           rad_close(r->cx.rad);
290ff8e577bSBrian Somers           return;
291ff8e577bSBrian Somers         }
292ff8e577bSBrian Somers         log_Printf(LogPHASE, " Reply-Message \"%s\"\n", r->repstr);
293ff8e577bSBrian Somers         break;
294ff8e577bSBrian Somers 
295ff8e577bSBrian Somers       case RAD_VENDOR_SPECIFIC:
296ff8e577bSBrian Somers         if ((res = rad_get_vendor_attr(&vendor, &data, &len)) <= 0) {
297ff8e577bSBrian Somers           log_Printf(LogERROR, "rad_get_vendor_attr: %s (failing!)\n",
298f0cdd9c0SBrian Somers                      rad_strerror(r->cx.rad));
299f0cdd9c0SBrian Somers           auth_Failure(r->cx.auth);
300f0cdd9c0SBrian Somers           rad_close(r->cx.rad);
301ff8e577bSBrian Somers           return;
302ff8e577bSBrian Somers         }
303ff8e577bSBrian Somers 
304ff8e577bSBrian Somers 	switch (vendor) {
305ff8e577bSBrian Somers           case RAD_VENDOR_MICROSOFT:
306ff8e577bSBrian Somers             switch (res) {
307ff8e577bSBrian Somers               case RAD_MICROSOFT_MS_CHAP_ERROR:
308ff8e577bSBrian Somers                 free(r->errstr);
309ff8e577bSBrian Somers                 if ((r->errstr = rad_cvt_string(data, len)) == NULL) {
310ff8e577bSBrian Somers                   log_Printf(LogERROR, "rad_cvt_string: %s\n",
311ff8e577bSBrian Somers                              rad_strerror(r->cx.rad));
312ff8e577bSBrian Somers                   auth_Failure(r->cx.auth);
313ff8e577bSBrian Somers                   rad_close(r->cx.rad);
314ff8e577bSBrian Somers                   return;
315ff8e577bSBrian Somers                 }
316ff8e577bSBrian Somers                 log_Printf(LogPHASE, " MS-CHAP-Error \"%s\"\n", r->errstr);
317ff8e577bSBrian Somers                 break;
318ff8e577bSBrian Somers 
319a16061b2SBrian Somers               case RAD_MICROSOFT_MS_CHAP2_SUCCESS:
320a16061b2SBrian Somers                 free(r->msrepstr);
321a16061b2SBrian Somers                 if ((r->msrepstr = rad_cvt_string(data, len)) == NULL) {
322a16061b2SBrian Somers                   log_Printf(LogERROR, "rad_cvt_string: %s\n",
323a16061b2SBrian Somers                              rad_strerror(r->cx.rad));
324a16061b2SBrian Somers                   auth_Failure(r->cx.auth);
325a16061b2SBrian Somers                   rad_close(r->cx.rad);
326a16061b2SBrian Somers                   return;
327a16061b2SBrian Somers                 }
328a16061b2SBrian Somers                 log_Printf(LogPHASE, " MS-CHAP2-Success \"%s\"\n", r->msrepstr);
329a16061b2SBrian Somers                 break;
330a16061b2SBrian Somers 
331ff8e577bSBrian Somers               default:
332ff8e577bSBrian Somers                 log_Printf(LogDEBUG, "Dropping MICROSOFT vendor specific "
333ff8e577bSBrian Somers                            "RADIUS attribute %d\n", res);
334ff8e577bSBrian Somers                 break;
335ff8e577bSBrian Somers             }
336ff8e577bSBrian Somers             break;
337ff8e577bSBrian Somers 
338ff8e577bSBrian Somers           default:
339ff8e577bSBrian Somers             log_Printf(LogDEBUG, "Dropping vendor %lu RADIUS attribute %d\n",
340ff8e577bSBrian Somers                        (unsigned long)vendor, res);
341ff8e577bSBrian Somers             break;
342ff8e577bSBrian Somers         }
343ff8e577bSBrian Somers         break;
344ff8e577bSBrian Somers 
345ff8e577bSBrian Somers       default:
346ff8e577bSBrian Somers         log_Printf(LogDEBUG, "Dropping RADIUS attribute %d\n", res);
347ff8e577bSBrian Somers         break;
348ff8e577bSBrian Somers     }
349ff8e577bSBrian Somers   }
350ff8e577bSBrian Somers 
351ff8e577bSBrian Somers   if (res == -1) {
352ff8e577bSBrian Somers     log_Printf(LogERROR, "rad_get_attr: %s (failing!)\n",
353ff8e577bSBrian Somers                rad_strerror(r->cx.rad));
354ff8e577bSBrian Somers     auth_Failure(r->cx.auth);
355ff8e577bSBrian Somers   } else if (got == RAD_ACCESS_REJECT)
356ff8e577bSBrian Somers     auth_Failure(r->cx.auth);
357ff8e577bSBrian Somers   else {
358f0cdd9c0SBrian Somers     r->valid = 1;
359f0cdd9c0SBrian Somers     auth_Success(r->cx.auth);
360f0cdd9c0SBrian Somers   }
361ff8e577bSBrian Somers   rad_close(r->cx.rad);
362972a1bcfSBrian Somers }
363972a1bcfSBrian Somers 
364f0cdd9c0SBrian Somers /*
3658e7bd08eSBrian Somers  * We've either timed out or select()ed on the read descriptor
366f0cdd9c0SBrian Somers  */
367f0cdd9c0SBrian Somers static void
368f0cdd9c0SBrian Somers radius_Continue(struct radius *r, int sel)
369f0cdd9c0SBrian Somers {
370f0cdd9c0SBrian Somers   struct timeval tv;
371f0cdd9c0SBrian Somers   int got;
372972a1bcfSBrian Somers 
373f0cdd9c0SBrian Somers   timer_Stop(&r->cx.timer);
374f0cdd9c0SBrian Somers   if ((got = rad_continue_send_request(r->cx.rad, sel, &r->cx.fd, &tv)) == 0) {
375f0cdd9c0SBrian Somers     log_Printf(LogPHASE, "Radius: Request re-sent\n");
376f0cdd9c0SBrian Somers     r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
377f0cdd9c0SBrian Somers     timer_Start(&r->cx.timer);
378f0cdd9c0SBrian Somers     return;
379f0cdd9c0SBrian Somers   }
380f0cdd9c0SBrian Somers 
381f0cdd9c0SBrian Somers   radius_Process(r, got);
382f0cdd9c0SBrian Somers }
383f0cdd9c0SBrian Somers 
384f0cdd9c0SBrian Somers /*
385f0cdd9c0SBrian Somers  * Time to call rad_continue_send_request() - timed out.
386f0cdd9c0SBrian Somers  */
387f0cdd9c0SBrian Somers static void
388f0cdd9c0SBrian Somers radius_Timeout(void *v)
389f0cdd9c0SBrian Somers {
390f0cdd9c0SBrian Somers   radius_Continue((struct radius *)v, 0);
391f0cdd9c0SBrian Somers }
392f0cdd9c0SBrian Somers 
393f0cdd9c0SBrian Somers /*
394f0cdd9c0SBrian Somers  * Time to call rad_continue_send_request() - something to read.
395f0cdd9c0SBrian Somers  */
396f0cdd9c0SBrian Somers static void
397f013f33eSBrian Somers radius_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
398f0cdd9c0SBrian Somers {
399f0cdd9c0SBrian Somers   radius_Continue(descriptor2radius(d), 1);
400f0cdd9c0SBrian Somers }
401f0cdd9c0SBrian Somers 
402f0cdd9c0SBrian Somers /*
4038e7bd08eSBrian Somers  * Behave as a struct fdescriptor (descriptor.h)
404f0cdd9c0SBrian Somers  */
405f0cdd9c0SBrian Somers static int
406f013f33eSBrian Somers radius_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
407f0cdd9c0SBrian Somers {
408f0cdd9c0SBrian Somers   struct radius *rad = descriptor2radius(d);
409f0cdd9c0SBrian Somers 
410f0cdd9c0SBrian Somers   if (r && rad->cx.fd != -1) {
411f0cdd9c0SBrian Somers     FD_SET(rad->cx.fd, r);
412f0cdd9c0SBrian Somers     if (*n < rad->cx.fd + 1)
413f0cdd9c0SBrian Somers       *n = rad->cx.fd + 1;
414f0cdd9c0SBrian Somers     log_Printf(LogTIMER, "Radius: fdset(r) %d\n", rad->cx.fd);
41582d6780cSBrian Somers     return 1;
416972a1bcfSBrian Somers   }
417972a1bcfSBrian Somers 
418f0cdd9c0SBrian Somers   return 0;
419f0cdd9c0SBrian Somers }
420f0cdd9c0SBrian Somers 
421f0cdd9c0SBrian Somers /*
4228e7bd08eSBrian Somers  * Behave as a struct fdescriptor (descriptor.h)
423f0cdd9c0SBrian Somers  */
424f0cdd9c0SBrian Somers static int
425f013f33eSBrian Somers radius_IsSet(struct fdescriptor *d, const fd_set *fdset)
426f0cdd9c0SBrian Somers {
427f0cdd9c0SBrian Somers   struct radius *r = descriptor2radius(d);
428f0cdd9c0SBrian Somers 
429f0cdd9c0SBrian Somers   return r && r->cx.fd != -1 && FD_ISSET(r->cx.fd, fdset);
430f0cdd9c0SBrian Somers }
431f0cdd9c0SBrian Somers 
432f0cdd9c0SBrian Somers /*
4338e7bd08eSBrian Somers  * Behave as a struct fdescriptor (descriptor.h)
434f0cdd9c0SBrian Somers  */
435f0cdd9c0SBrian Somers static int
436f013f33eSBrian Somers radius_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
437f0cdd9c0SBrian Somers {
438f0cdd9c0SBrian Somers   /* We never want to write here ! */
439f0cdd9c0SBrian Somers   log_Printf(LogALERT, "radius_Write: Internal error: Bad call !\n");
440f0cdd9c0SBrian Somers   return 0;
441f0cdd9c0SBrian Somers }
442f0cdd9c0SBrian Somers 
443f0cdd9c0SBrian Somers /*
444f0cdd9c0SBrian Somers  * Initialise ourselves
445f0cdd9c0SBrian Somers  */
446f0cdd9c0SBrian Somers void
447f0cdd9c0SBrian Somers radius_Init(struct radius *r)
448f0cdd9c0SBrian Somers {
449f0cdd9c0SBrian Somers   r->desc.type = RADIUS_DESCRIPTOR;
450f0cdd9c0SBrian Somers   r->desc.UpdateSet = radius_UpdateSet;
451f0cdd9c0SBrian Somers   r->desc.IsSet = radius_IsSet;
452f0cdd9c0SBrian Somers   r->desc.Read = radius_Read;
453f0cdd9c0SBrian Somers   r->desc.Write = radius_Write;
454ff8e577bSBrian Somers   r->cx.fd = -1;
455ff8e577bSBrian Somers   r->cx.rad = NULL;
456f0cdd9c0SBrian Somers   memset(&r->cx.timer, '\0', sizeof r->cx.timer);
457ff8e577bSBrian Somers   r->cx.auth = NULL;
458ff8e577bSBrian Somers   r->valid = 0;
459ff8e577bSBrian Somers   r->vj = 0;
460ff8e577bSBrian Somers   r->ip.s_addr = INADDR_ANY;
461ff8e577bSBrian Somers   r->mask.s_addr = INADDR_NONE;
462ff8e577bSBrian Somers   r->routes = NULL;
463ff8e577bSBrian Somers   r->mtu = DEF_MTU;
464a16061b2SBrian Somers   r->msrepstr = NULL;
465ff8e577bSBrian Somers   r->repstr = NULL;
466ff8e577bSBrian Somers   r->errstr = NULL;
467ff8e577bSBrian Somers   *r->cfg.file = '\0';;
468794c9bbcSBrian Somers   log_Printf(LogDEBUG, "Radius: radius_Init\n");
469f0cdd9c0SBrian Somers }
470f0cdd9c0SBrian Somers 
471f0cdd9c0SBrian Somers /*
472f0cdd9c0SBrian Somers  * Forget everything and go back to initialised state.
473f0cdd9c0SBrian Somers  */
474f0cdd9c0SBrian Somers void
475f0cdd9c0SBrian Somers radius_Destroy(struct radius *r)
476f0cdd9c0SBrian Somers {
477f0cdd9c0SBrian Somers   r->valid = 0;
478794c9bbcSBrian Somers   log_Printf(LogDEBUG, "Radius: radius_Destroy\n");
479f0cdd9c0SBrian Somers   timer_Stop(&r->cx.timer);
480f0cdd9c0SBrian Somers   route_DeleteAll(&r->routes);
481bf1eaec5SBrian Somers   free(r->filterid);
482bf1eaec5SBrian Somers   r->filterid = NULL;
483a16061b2SBrian Somers   free(r->msrepstr);
484a16061b2SBrian Somers   r->msrepstr = NULL;
485ff8e577bSBrian Somers   free(r->repstr);
486ff8e577bSBrian Somers   r->repstr = NULL;
487ff8e577bSBrian Somers   free(r->errstr);
488ff8e577bSBrian Somers   r->errstr = NULL;
489f0cdd9c0SBrian Somers   if (r->cx.fd != -1) {
490f0cdd9c0SBrian Somers     r->cx.fd = -1;
491f0cdd9c0SBrian Somers     rad_close(r->cx.rad);
492f0cdd9c0SBrian Somers   }
493f0cdd9c0SBrian Somers }
494f0cdd9c0SBrian Somers 
495de59e178SBrian Somers static int
496de59e178SBrian Somers radius_put_physical_details(struct rad_handle *rad, struct physical *p)
497de59e178SBrian Somers {
498de59e178SBrian Somers   int slot, type;
499de59e178SBrian Somers 
500de59e178SBrian Somers   type = RAD_VIRTUAL;
501de59e178SBrian Somers   if (p->handler)
502de59e178SBrian Somers     switch (p->handler->type) {
503de59e178SBrian Somers       case I4B_DEVICE:
504de59e178SBrian Somers         type = RAD_ISDN_SYNC;
505de59e178SBrian Somers         break;
506de59e178SBrian Somers 
507de59e178SBrian Somers       case TTY_DEVICE:
508de59e178SBrian Somers         type = RAD_ASYNC;
509de59e178SBrian Somers         break;
510de59e178SBrian Somers 
511de59e178SBrian Somers       case ETHER_DEVICE:
512de59e178SBrian Somers         type = RAD_ETHERNET;
513de59e178SBrian Somers         break;
514de59e178SBrian Somers 
515de59e178SBrian Somers       case TCP_DEVICE:
516de59e178SBrian Somers       case UDP_DEVICE:
517de59e178SBrian Somers       case EXEC_DEVICE:
518de59e178SBrian Somers       case ATM_DEVICE:
519de59e178SBrian Somers       case NG_DEVICE:
520de59e178SBrian Somers         type = RAD_VIRTUAL;
521de59e178SBrian Somers         break;
522de59e178SBrian Somers     }
523de59e178SBrian Somers 
524de59e178SBrian Somers   if (rad_put_int(rad, RAD_NAS_PORT_TYPE, type) != 0) {
525de59e178SBrian Somers     log_Printf(LogERROR, "rad_put: rad_put_int: %s\n", rad_strerror(rad));
526de59e178SBrian Somers     rad_close(rad);
527de59e178SBrian Somers     return 0;
528de59e178SBrian Somers   }
529de59e178SBrian Somers 
530de59e178SBrian Somers   if ((slot = physical_Slot(p)) >= 0)
531de59e178SBrian Somers     if (rad_put_int(rad, RAD_NAS_PORT, slot) != 0) {
532de59e178SBrian Somers       log_Printf(LogERROR, "rad_put: rad_put_int: %s\n", rad_strerror(rad));
533de59e178SBrian Somers       rad_close(rad);
534de59e178SBrian Somers       return 0;
535de59e178SBrian Somers     }
536de59e178SBrian Somers 
537de59e178SBrian Somers   return 1;
538de59e178SBrian Somers }
539de59e178SBrian Somers 
540f0cdd9c0SBrian Somers /*
541f0cdd9c0SBrian Somers  * Start an authentication request to the RADIUS server.
542f0cdd9c0SBrian Somers  */
543a16061b2SBrian Somers int
544f0cdd9c0SBrian Somers radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name,
545a16061b2SBrian Somers                     const char *key, int klen, const char *nchallenge,
546a16061b2SBrian Somers                     int nclen, const char *pchallenge, int pclen)
547f0cdd9c0SBrian Somers {
548f0cdd9c0SBrian Somers   struct timeval tv;
549de59e178SBrian Somers   int got;
55026e6a622SBrian Somers   char hostname[MAXHOSTNAMELEN];
551aadbb4eaSBrian Somers #if 0
552f10f5203SBrian Somers   struct hostent *hp;
553aadbb4eaSBrian Somers #endif
554f10f5203SBrian Somers   struct in_addr hostaddr;
555ff8e577bSBrian Somers #ifndef NODES
556a16061b2SBrian Somers   struct mschap_response msresp;
557a16061b2SBrian Somers   struct mschap2_response msresp2;
558ff8e577bSBrian Somers #endif
559f0cdd9c0SBrian Somers 
560f0cdd9c0SBrian Somers   if (!*r->cfg.file)
561a16061b2SBrian Somers     return 0;
562f0cdd9c0SBrian Somers 
563f0cdd9c0SBrian Somers   if (r->cx.fd != -1)
564f0cdd9c0SBrian Somers     /*
565f0cdd9c0SBrian Somers      * We assume that our name/key/challenge is the same as last time,
566f0cdd9c0SBrian Somers      * and just continue to wait for the RADIUS server(s).
567f0cdd9c0SBrian Somers      */
568a16061b2SBrian Somers     return 1;
569f0cdd9c0SBrian Somers 
570f0cdd9c0SBrian Somers   radius_Destroy(r);
571f0cdd9c0SBrian Somers 
572794c9bbcSBrian Somers   if ((r->cx.rad = rad_auth_open()) == NULL) {
573794c9bbcSBrian Somers     log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno));
574a16061b2SBrian Somers     return 0;
575f0cdd9c0SBrian Somers   }
576f0cdd9c0SBrian Somers 
577f0cdd9c0SBrian Somers   if (rad_config(r->cx.rad, r->cfg.file) != 0) {
578f0cdd9c0SBrian Somers     log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad));
579f0cdd9c0SBrian Somers     rad_close(r->cx.rad);
580a16061b2SBrian Somers     return 0;
581f0cdd9c0SBrian Somers   }
582f0cdd9c0SBrian Somers 
583f0cdd9c0SBrian Somers   if (rad_create_request(r->cx.rad, RAD_ACCESS_REQUEST) != 0) {
584f0cdd9c0SBrian Somers     log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad));
585f0cdd9c0SBrian Somers     rad_close(r->cx.rad);
586a16061b2SBrian Somers     return 0;
587f0cdd9c0SBrian Somers   }
588f0cdd9c0SBrian Somers 
589f0cdd9c0SBrian Somers   if (rad_put_string(r->cx.rad, RAD_USER_NAME, name) != 0 ||
590f0cdd9c0SBrian Somers       rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 ||
591f0cdd9c0SBrian Somers       rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) {
592f0cdd9c0SBrian Somers     log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
593f0cdd9c0SBrian Somers     rad_close(r->cx.rad);
594a16061b2SBrian Somers     return 0;
595f0cdd9c0SBrian Somers   }
596f0cdd9c0SBrian Somers 
597ff8e577bSBrian Somers   switch (authp->physical->link.lcp.want_auth) {
598ff8e577bSBrian Somers   case PROTO_PAP:
599ff8e577bSBrian Somers     /* We're talking PAP */
600ff8e577bSBrian Somers     if (rad_put_attr(r->cx.rad, RAD_USER_PASSWORD, key, klen) != 0) {
601ff8e577bSBrian Somers       log_Printf(LogERROR, "PAP: rad_put_string: %s\n",
602ff8e577bSBrian Somers                  rad_strerror(r->cx.rad));
603ff8e577bSBrian Somers       rad_close(r->cx.rad);
604a16061b2SBrian Somers       return 0;
605ff8e577bSBrian Somers     }
606ff8e577bSBrian Somers     break;
607ff8e577bSBrian Somers 
608ff8e577bSBrian Somers   case PROTO_CHAP:
609ff8e577bSBrian Somers     switch (authp->physical->link.lcp.want_authtype) {
610ff8e577bSBrian Somers     case 0x5:
61150ca6ec3SBrian Somers       if (rad_put_attr(r->cx.rad, RAD_CHAP_PASSWORD, key, klen) != 0 ||
612a16061b2SBrian Somers           rad_put_attr(r->cx.rad, RAD_CHAP_CHALLENGE, nchallenge, nclen) != 0) {
613f0cdd9c0SBrian Somers         log_Printf(LogERROR, "CHAP: rad_put_string: %s\n",
614f0cdd9c0SBrian Somers                    rad_strerror(r->cx.rad));
615f0cdd9c0SBrian Somers         rad_close(r->cx.rad);
616a16061b2SBrian Somers         return 0;
617f0cdd9c0SBrian Somers       }
618ff8e577bSBrian Somers       break;
619ff8e577bSBrian Somers 
620ff8e577bSBrian Somers #ifndef NODES
621ff8e577bSBrian Somers     case 0x80:
622ff8e577bSBrian Somers       if (klen != 50) {
623a16061b2SBrian Somers         log_Printf(LogERROR, "CHAP80: Unrecognised key length %d\n", klen);
624f0cdd9c0SBrian Somers         rad_close(r->cx.rad);
625a16061b2SBrian Somers         return 0;
626f0cdd9c0SBrian Somers       }
627a16061b2SBrian Somers 
628ff8e577bSBrian Somers       rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT,
629a16061b2SBrian Somers                           RAD_MICROSOFT_MS_CHAP_CHALLENGE, nchallenge, nclen);
630a16061b2SBrian Somers       msresp.ident = *key;
631a16061b2SBrian Somers       msresp.flags = 0x01;
632a16061b2SBrian Somers       memcpy(msresp.lm_response, key + 1, 24);
633a16061b2SBrian Somers       memcpy(msresp.nt_response, key + 25, 24);
634ff8e577bSBrian Somers       rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT,
635a16061b2SBrian Somers                           RAD_MICROSOFT_MS_CHAP_RESPONSE, &msresp,
636a16061b2SBrian Somers                           sizeof msresp);
637ff8e577bSBrian Somers       break;
638ff8e577bSBrian Somers 
639ff8e577bSBrian Somers     case 0x81:
640a16061b2SBrian Somers       if (klen != 50) {
641a16061b2SBrian Somers         log_Printf(LogERROR, "CHAP81: Unrecognised key length %d\n", klen);
642a16061b2SBrian Somers         rad_close(r->cx.rad);
643a16061b2SBrian Somers         return 0;
644a16061b2SBrian Somers       }
645a16061b2SBrian Somers 
646a16061b2SBrian Somers       if (pclen != sizeof msresp2.pchallenge) {
647a16061b2SBrian Somers         log_Printf(LogERROR, "CHAP81: Unrecognised peer challenge length %d\n",
648a16061b2SBrian Somers                    pclen);
649a16061b2SBrian Somers         rad_close(r->cx.rad);
650a16061b2SBrian Somers         return 0;
651a16061b2SBrian Somers       }
652a16061b2SBrian Somers 
653a16061b2SBrian Somers       rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT,
654a16061b2SBrian Somers                           RAD_MICROSOFT_MS_CHAP_CHALLENGE, nchallenge, nclen);
655a16061b2SBrian Somers       msresp2.ident = *key;
656a16061b2SBrian Somers       msresp2.flags = 0x00;
657a16061b2SBrian Somers       memcpy(msresp2.response, key + 25, 24);
658a16061b2SBrian Somers       memset(msresp2.reserved, '\0', sizeof msresp2.reserved);
659a16061b2SBrian Somers       memcpy(msresp2.pchallenge, pchallenge, pclen);
660a16061b2SBrian Somers       rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT,
661a16061b2SBrian Somers                           RAD_MICROSOFT_MS_CHAP2_RESPONSE, &msresp2,
662a16061b2SBrian Somers                           sizeof msresp2);
663a16061b2SBrian Somers       break;
664ff8e577bSBrian Somers #endif
665ff8e577bSBrian Somers     default:
666ff8e577bSBrian Somers       log_Printf(LogERROR, "CHAP: Unrecognised type 0x%02x\n",
667ff8e577bSBrian Somers                  authp->physical->link.lcp.want_authtype);
668ff8e577bSBrian Somers       rad_close(r->cx.rad);
669a16061b2SBrian Somers       return 0;
670ff8e577bSBrian Somers     }
671ff8e577bSBrian Somers   }
672f0cdd9c0SBrian Somers 
673f10f5203SBrian Somers   if (gethostname(hostname, sizeof hostname) != 0)
674f10f5203SBrian Somers     log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno));
675f10f5203SBrian Somers   else {
676aadbb4eaSBrian Somers #if 0
677f10f5203SBrian Somers     if ((hp = gethostbyname(hostname)) != NULL) {
678f10f5203SBrian Somers       hostaddr.s_addr = *(u_long *)hp->h_addr;
679f10f5203SBrian Somers       if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) {
680f10f5203SBrian Somers         log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
681f10f5203SBrian Somers                    rad_strerror(r->cx.rad));
682f10f5203SBrian Somers         rad_close(r->cx.rad);
683a16061b2SBrian Somers         return 0;
684f10f5203SBrian Somers       }
685f10f5203SBrian Somers     }
686aadbb4eaSBrian Somers #endif
687f10f5203SBrian Somers     if (rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) {
688f10f5203SBrian Somers       log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
689f10f5203SBrian Somers                  rad_strerror(r->cx.rad));
690f10f5203SBrian Somers       rad_close(r->cx.rad);
691a16061b2SBrian Somers       return 0;
692f10f5203SBrian Somers     }
693f10f5203SBrian Somers   }
694f10f5203SBrian Somers 
695de59e178SBrian Somers   radius_put_physical_details(r->cx.rad, authp->physical);
696f10f5203SBrian Somers 
697c42627ffSBrian Somers   r->cx.auth = authp;
698f0cdd9c0SBrian Somers   if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv)))
699f0cdd9c0SBrian Somers     radius_Process(r, got);
700f0cdd9c0SBrian Somers   else {
701f0cdd9c0SBrian Somers     log_Printf(LogPHASE, "Radius: Request sent\n");
702f0cdd9c0SBrian Somers     log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout);
703f0cdd9c0SBrian Somers     r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
704f0cdd9c0SBrian Somers     r->cx.timer.func = radius_Timeout;
705c42627ffSBrian Somers     r->cx.timer.name = "radius auth";
706f0cdd9c0SBrian Somers     r->cx.timer.arg = r;
707f0cdd9c0SBrian Somers     timer_Start(&r->cx.timer);
708f0cdd9c0SBrian Somers   }
709a16061b2SBrian Somers 
710a16061b2SBrian Somers   return 1;
711f0cdd9c0SBrian Somers }
712f0cdd9c0SBrian Somers 
713f0cdd9c0SBrian Somers /*
714794c9bbcSBrian Somers  * Send an accounting request to the RADIUS server
715794c9bbcSBrian Somers  */
716794c9bbcSBrian Somers void
717794c9bbcSBrian Somers radius_Account(struct radius *r, struct radacct *ac, struct datalink *dl,
718794c9bbcSBrian Somers                int acct_type, struct in_addr *peer_ip, struct in_addr *netmask,
719794c9bbcSBrian Somers                struct pppThroughput *stats)
720794c9bbcSBrian Somers {
721794c9bbcSBrian Somers   struct timeval tv;
722de59e178SBrian Somers   int got;
72326e6a622SBrian Somers   char hostname[MAXHOSTNAMELEN];
724aadbb4eaSBrian Somers #if 0
725794c9bbcSBrian Somers   struct hostent *hp;
726aadbb4eaSBrian Somers #endif
727794c9bbcSBrian Somers   struct in_addr hostaddr;
728794c9bbcSBrian Somers 
729794c9bbcSBrian Somers   if (!*r->cfg.file)
730794c9bbcSBrian Somers     return;
731794c9bbcSBrian Somers 
732794c9bbcSBrian Somers   if (r->cx.fd != -1)
733794c9bbcSBrian Somers     /*
734794c9bbcSBrian Somers      * We assume that our name/key/challenge is the same as last time,
735794c9bbcSBrian Somers      * and just continue to wait for the RADIUS server(s).
736794c9bbcSBrian Somers      */
737794c9bbcSBrian Somers     return;
738794c9bbcSBrian Somers 
739794c9bbcSBrian Somers   radius_Destroy(r);
740794c9bbcSBrian Somers 
741ba093e81SBrian Somers   if ((r->cx.rad = rad_acct_open()) == NULL) {
742794c9bbcSBrian Somers     log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno));
743794c9bbcSBrian Somers     return;
744794c9bbcSBrian Somers   }
745794c9bbcSBrian Somers 
746794c9bbcSBrian Somers   if (rad_config(r->cx.rad, r->cfg.file) != 0) {
747794c9bbcSBrian Somers     log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad));
748794c9bbcSBrian Somers     rad_close(r->cx.rad);
749794c9bbcSBrian Somers     return;
750794c9bbcSBrian Somers   }
751794c9bbcSBrian Somers 
752794c9bbcSBrian Somers   if (rad_create_request(r->cx.rad, RAD_ACCOUNTING_REQUEST) != 0) {
753794c9bbcSBrian Somers     log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad));
754794c9bbcSBrian Somers     rad_close(r->cx.rad);
755794c9bbcSBrian Somers     return;
756794c9bbcSBrian Somers   }
757794c9bbcSBrian Somers 
758794c9bbcSBrian Somers   /* Grab some accounting data and initialize structure */
759794c9bbcSBrian Somers   if (acct_type == RAD_START) {
760794c9bbcSBrian Somers     ac->rad_parent = r;
761794c9bbcSBrian Somers     /* Fetch username from datalink */
762794c9bbcSBrian Somers     strncpy(ac->user_name, dl->peer.authname, sizeof ac->user_name);
763794c9bbcSBrian Somers     ac->user_name[AUTHLEN-1] = '\0';
764794c9bbcSBrian Somers 
765794c9bbcSBrian Somers     ac->authentic = 2;		/* Assume RADIUS verified auth data */
766794c9bbcSBrian Somers 
767794c9bbcSBrian Somers     /* Generate a session ID */
76812b5aabaSBrian Somers     snprintf(ac->session_id, sizeof ac->session_id, "%s%ld-%s%lu",
76912b5aabaSBrian Somers              dl->bundle->cfg.auth.name, (long)getpid(),
770794c9bbcSBrian Somers              dl->peer.authname, (unsigned long)stats->uptime);
771794c9bbcSBrian Somers 
772794c9bbcSBrian Somers     /* And grab our MP socket name */
773794c9bbcSBrian Somers     snprintf(ac->multi_session_id, sizeof ac->multi_session_id, "%s",
774794c9bbcSBrian Somers              dl->bundle->ncp.mp.active ?
775794c9bbcSBrian Somers              dl->bundle->ncp.mp.server.socket.sun_path : "");
776794c9bbcSBrian Somers 
777794c9bbcSBrian Somers     /* Fetch IP, netmask from IPCP */
778794c9bbcSBrian Somers     memcpy(&ac->ip, peer_ip, sizeof(ac->ip));
779794c9bbcSBrian Somers     memcpy(&ac->mask, netmask, sizeof(ac->mask));
780794c9bbcSBrian Somers   };
781794c9bbcSBrian Somers 
782794c9bbcSBrian Somers   if (rad_put_string(r->cx.rad, RAD_USER_NAME, ac->user_name) != 0 ||
783794c9bbcSBrian Somers       rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 ||
784794c9bbcSBrian Somers       rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0 ||
785794c9bbcSBrian Somers       rad_put_addr(r->cx.rad, RAD_FRAMED_IP_ADDRESS, ac->ip) != 0 ||
786794c9bbcSBrian Somers       rad_put_addr(r->cx.rad, RAD_FRAMED_IP_NETMASK, ac->mask) != 0) {
787794c9bbcSBrian Somers     log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
788794c9bbcSBrian Somers     rad_close(r->cx.rad);
789794c9bbcSBrian Somers     return;
790794c9bbcSBrian Somers   }
791794c9bbcSBrian Somers 
792794c9bbcSBrian Somers   if (gethostname(hostname, sizeof hostname) != 0)
793794c9bbcSBrian Somers     log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno));
794794c9bbcSBrian Somers   else {
795aadbb4eaSBrian Somers #if 0
796794c9bbcSBrian Somers     if ((hp = gethostbyname(hostname)) != NULL) {
797794c9bbcSBrian Somers       hostaddr.s_addr = *(u_long *)hp->h_addr;
798794c9bbcSBrian Somers       if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) {
799794c9bbcSBrian Somers         log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
800794c9bbcSBrian Somers                    rad_strerror(r->cx.rad));
801794c9bbcSBrian Somers         rad_close(r->cx.rad);
802794c9bbcSBrian Somers         return;
803794c9bbcSBrian Somers       }
804794c9bbcSBrian Somers     }
805aadbb4eaSBrian Somers #endif
806794c9bbcSBrian Somers     if (rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) {
807794c9bbcSBrian Somers       log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
808794c9bbcSBrian Somers                  rad_strerror(r->cx.rad));
809794c9bbcSBrian Somers       rad_close(r->cx.rad);
810794c9bbcSBrian Somers       return;
811794c9bbcSBrian Somers     }
812794c9bbcSBrian Somers   }
813794c9bbcSBrian Somers 
814de59e178SBrian Somers   radius_put_physical_details(r->cx.rad, dl->physical);
815794c9bbcSBrian Somers 
816794c9bbcSBrian Somers   if (rad_put_int(r->cx.rad, RAD_ACCT_STATUS_TYPE, acct_type) != 0 ||
817794c9bbcSBrian Somers       rad_put_string(r->cx.rad, RAD_ACCT_SESSION_ID, ac->session_id) != 0 ||
818794c9bbcSBrian Somers       rad_put_string(r->cx.rad, RAD_ACCT_MULTI_SESSION_ID,
819794c9bbcSBrian Somers                      ac->multi_session_id) != 0 ||
820794c9bbcSBrian Somers       rad_put_int(r->cx.rad, RAD_ACCT_DELAY_TIME, 0) != 0) {
821794c9bbcSBrian Somers /* XXX ACCT_DELAY_TIME should be increased each time a packet is waiting */
822794c9bbcSBrian Somers     log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
823794c9bbcSBrian Somers     rad_close(r->cx.rad);
824794c9bbcSBrian Somers     return;
825794c9bbcSBrian Somers   }
826794c9bbcSBrian Somers 
827794c9bbcSBrian Somers   if (acct_type == RAD_STOP)
828794c9bbcSBrian Somers   /* Show some statistics */
829794c9bbcSBrian Somers     if (rad_put_int(r->cx.rad, RAD_ACCT_INPUT_OCTETS, stats->OctetsIn) != 0 ||
830794c9bbcSBrian Somers         rad_put_int(r->cx.rad, RAD_ACCT_INPUT_PACKETS, stats->PacketsIn) != 0 ||
831794c9bbcSBrian Somers         rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_OCTETS, stats->OctetsOut) != 0 ||
832794c9bbcSBrian Somers         rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_PACKETS, stats->PacketsOut)
833794c9bbcSBrian Somers         != 0 ||
834794c9bbcSBrian Somers         rad_put_int(r->cx.rad, RAD_ACCT_SESSION_TIME, throughput_uptime(stats))
835794c9bbcSBrian Somers         != 0) {
836794c9bbcSBrian Somers       log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
837794c9bbcSBrian Somers       rad_close(r->cx.rad);
838794c9bbcSBrian Somers       return;
839794c9bbcSBrian Somers     }
840794c9bbcSBrian Somers 
841c42627ffSBrian Somers   r->cx.auth = NULL;			/* Not valid for accounting requests */
842794c9bbcSBrian Somers   if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv)))
843794c9bbcSBrian Somers     radius_Process(r, got);
844794c9bbcSBrian Somers   else {
845794c9bbcSBrian Somers     log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout);
846794c9bbcSBrian Somers     r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
847794c9bbcSBrian Somers     r->cx.timer.func = radius_Timeout;
848c42627ffSBrian Somers     r->cx.timer.name = "radius acct";
849794c9bbcSBrian Somers     r->cx.timer.arg = r;
850794c9bbcSBrian Somers     timer_Start(&r->cx.timer);
851794c9bbcSBrian Somers   }
852794c9bbcSBrian Somers }
853794c9bbcSBrian Somers 
854794c9bbcSBrian Somers /*
855f0cdd9c0SBrian Somers  * How do things look at the moment ?
856f0cdd9c0SBrian Somers  */
857972a1bcfSBrian Somers void
858972a1bcfSBrian Somers radius_Show(struct radius *r, struct prompt *p)
859972a1bcfSBrian Somers {
86074457d3dSBrian Somers   prompt_Printf(p, " Radius config:     %s",
86174457d3dSBrian Somers                 *r->cfg.file ? r->cfg.file : "none");
862972a1bcfSBrian Somers   if (r->valid) {
863972a1bcfSBrian Somers     prompt_Printf(p, "\n                IP: %s\n", inet_ntoa(r->ip));
864972a1bcfSBrian Somers     prompt_Printf(p, "           Netmask: %s\n", inet_ntoa(r->mask));
865972a1bcfSBrian Somers     prompt_Printf(p, "               MTU: %lu\n", r->mtu);
866972a1bcfSBrian Somers     prompt_Printf(p, "                VJ: %sabled\n", r->vj ? "en" : "dis");
867ff8e577bSBrian Somers     prompt_Printf(p, "           Message: %s\n", r->repstr ? r->repstr : "");
868a16061b2SBrian Somers     prompt_Printf(p, " MS-CHAP2-Response: %s\n",
869a16061b2SBrian Somers                   r->msrepstr ? r->msrepstr : "");
870ff8e577bSBrian Somers     prompt_Printf(p, "     Error Message: %s\n", r->errstr ? r->errstr : "");
871972a1bcfSBrian Somers     if (r->routes)
872972a1bcfSBrian Somers       route_ShowSticky(p, r->routes, "            Routes", 16);
873972a1bcfSBrian Somers   } else
874972a1bcfSBrian Somers     prompt_Printf(p, " (not authenticated)\n");
875972a1bcfSBrian Somers }
876