]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/ppp/radius.c
This commit was generated by cvs2svn to compensate for changes in r60573,
[FreeBSD/FreeBSD.git] / usr.sbin / ppp / radius.c
1 /*
2  * Copyright 1999 Internet Business Solutions Ltd., Switzerland
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  *
28  */
29
30 #include <sys/param.h>
31 #include <sys/socket.h>
32 #include <netinet/in_systm.h>
33 #include <netinet/in.h>
34 #include <netinet/ip.h>
35 #include <arpa/inet.h>
36 #include <sys/un.h>
37 #include <net/route.h>
38
39 #ifdef LOCALRAD
40 #include "radlib.h"
41 #else
42 #include <radlib.h>
43 #endif
44
45 #include <errno.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <sys/time.h>
50 #include <termios.h>
51 #include <ttyent.h>
52 #include <unistd.h>
53 #include <netdb.h>
54
55 #include "layer.h"
56 #include "defs.h"
57 #include "log.h"
58 #include "descriptor.h"
59 #include "prompt.h"
60 #include "timer.h"
61 #include "fsm.h"
62 #include "iplist.h"
63 #include "slcompress.h"
64 #include "throughput.h"
65 #include "lqr.h"
66 #include "hdlc.h"
67 #include "mbuf.h"
68 #include "ipcp.h"
69 #include "route.h"
70 #include "command.h"
71 #include "filter.h"
72 #include "lcp.h"
73 #include "ccp.h"
74 #include "link.h"
75 #include "mp.h"
76 #include "radius.h"
77 #include "auth.h"
78 #include "async.h"
79 #include "physical.h"
80 #include "chat.h"
81 #include "cbcp.h"
82 #include "chap.h"
83 #include "datalink.h"
84 #include "bundle.h"
85
86 /*
87  * rad_continue_send_request() has given us `got' (non-zero).  Deal with it.
88  */
89 static void
90 radius_Process(struct radius *r, int got)
91 {
92   char *argv[MAXARGS], *nuke;
93   struct bundle *bundle;
94   int argc, addrs;
95   size_t len;
96   struct in_range dest;
97   struct in_addr gw;
98   const void *data;
99
100   r->cx.fd = -1;                /* Stop select()ing */
101
102   switch (got) {
103     case RAD_ACCESS_ACCEPT:
104       log_Printf(LogPHASE, "Radius: ACCEPT received\n");
105       break;
106
107     case RAD_ACCESS_REJECT:
108       log_Printf(LogPHASE, "Radius: REJECT received\n");
109       auth_Failure(r->cx.auth);
110       rad_close(r->cx.rad);
111       return;
112
113     case RAD_ACCESS_CHALLENGE:
114       /* we can't deal with this (for now) ! */
115       log_Printf(LogPHASE, "Radius: CHALLENGE received (can't handle yet)\n");
116       auth_Failure(r->cx.auth);
117       rad_close(r->cx.rad);
118       return;
119
120     case -1:
121       log_Printf(LogPHASE, "radius: %s\n", rad_strerror(r->cx.rad));
122       auth_Failure(r->cx.auth);
123       rad_close(r->cx.rad);
124       return;
125
126     default:
127       log_Printf(LogERROR, "rad_send_request: Failed %d: %s\n",
128                  got, rad_strerror(r->cx.rad));
129       auth_Failure(r->cx.auth);
130       rad_close(r->cx.rad);
131       return;
132   }
133
134   /* So we've been accepted !  Let's see what we've got in our reply :-I */
135   r->ip.s_addr = r->mask.s_addr = INADDR_NONE;
136   r->mtu = 0;
137   r->vj = 0;
138   while ((got = rad_get_attr(r->cx.rad, &data, &len)) > 0) {
139     switch (got) {
140       case RAD_FRAMED_IP_ADDRESS:
141         r->ip = rad_cvt_addr(data);
142         log_Printf(LogPHASE, "        IP %s\n", inet_ntoa(r->ip));
143         break;
144
145       case RAD_FRAMED_IP_NETMASK:
146         r->mask = rad_cvt_addr(data);
147         log_Printf(LogPHASE, "        Netmask %s\n", inet_ntoa(r->mask));
148         break;
149
150       case RAD_FRAMED_MTU:
151         r->mtu = rad_cvt_int(data);
152         log_Printf(LogPHASE, "        MTU %lu\n", r->mtu);
153         break;
154
155       case RAD_FRAMED_ROUTING:
156         /* Disabled for now - should we automatically set up some filters ? */
157         /* rad_cvt_int(data); */
158         /* bit 1 = Send routing packets */
159         /* bit 2 = Receive routing packets */
160         break;
161
162       case RAD_FRAMED_COMPRESSION:
163         r->vj = rad_cvt_int(data) == 1 ? 1 : 0;
164         log_Printf(LogPHASE, "        VJ %sabled\n", r->vj ? "en" : "dis");
165         break;
166
167       case RAD_FRAMED_ROUTE:
168         /*
169          * We expect a string of the format ``dest[/bits] gw [metrics]''
170          * Any specified metrics are ignored.  MYADDR and HISADDR are
171          * understood for ``dest'' and ``gw'' and ``0.0.0.0'' is the same
172          * as ``HISADDR''.
173          */
174
175         if ((nuke = rad_cvt_string(data, len)) == NULL) {
176           log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
177           rad_close(r->cx.rad);
178           return;
179         }
180
181         log_Printf(LogPHASE, "        Route: %s\n", nuke);
182         bundle = r->cx.auth->physical->dl->bundle;
183         dest.ipaddr.s_addr = dest.mask.s_addr = INADDR_ANY;
184         dest.width = 0;
185         argc = command_Interpret(nuke, strlen(nuke), argv);
186         if (argc < 0)
187           log_Printf(LogWARN, "radius: %s: Syntax error\n",
188                      argc == 1 ? argv[0] : "\"\"");
189         else if (argc < 2)
190           log_Printf(LogWARN, "radius: %s: Invalid route\n",
191                      argc == 1 ? argv[0] : "\"\"");
192         else if ((strcasecmp(argv[0], "default") != 0 &&
193                   !ParseAddr(&bundle->ncp.ipcp, argv[0], &dest.ipaddr,
194                              &dest.mask, &dest.width)) ||
195                  !ParseAddr(&bundle->ncp.ipcp, argv[1], &gw, NULL, NULL))
196           log_Printf(LogWARN, "radius: %s %s: Invalid route\n",
197                      argv[0], argv[1]);
198         else {
199           if (dest.width == 32 && strchr(argv[0], '/') == NULL)
200             /* No mask specified - use the natural mask */
201             dest.mask = addr2mask(dest.ipaddr);
202           addrs = 0;
203
204           if (!strncasecmp(argv[0], "HISADDR", 7))
205             addrs = ROUTE_DSTHISADDR;
206           else if (!strncasecmp(argv[0], "MYADDR", 6))
207             addrs = ROUTE_DSTMYADDR;
208
209           if (gw.s_addr == INADDR_ANY) {
210             addrs |= ROUTE_GWHISADDR;
211             gw = bundle->ncp.ipcp.peer_ip;
212           } else if (strcasecmp(argv[1], "HISADDR") == 0)
213             addrs |= ROUTE_GWHISADDR;
214
215           route_Add(&r->routes, addrs, dest.ipaddr, dest.mask, gw);
216         }
217         free(nuke);
218         break;
219     }
220   }
221
222   if (got == -1) {
223     log_Printf(LogERROR, "rad_get_attr: %s (failing!)\n",
224                rad_strerror(r->cx.rad));
225     auth_Failure(r->cx.auth);
226     rad_close(r->cx.rad);
227   } else {
228     r->valid = 1;
229     auth_Success(r->cx.auth);
230     rad_close(r->cx.rad);
231   }
232 }
233
234 /*
235  * We've either timed out or select()ed on the read descriptor
236  */
237 static void
238 radius_Continue(struct radius *r, int sel)
239 {
240   struct timeval tv;
241   int got;
242
243   timer_Stop(&r->cx.timer);
244   if ((got = rad_continue_send_request(r->cx.rad, sel, &r->cx.fd, &tv)) == 0) {
245     log_Printf(LogPHASE, "Radius: Request re-sent\n");
246     r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
247     timer_Start(&r->cx.timer);
248     return;
249   }
250
251   radius_Process(r, got);
252 }
253
254 /*
255  * Time to call rad_continue_send_request() - timed out.
256  */
257 static void
258 radius_Timeout(void *v)
259 {
260   radius_Continue((struct radius *)v, 0);
261 }
262
263 /*
264  * Time to call rad_continue_send_request() - something to read.
265  */
266 static void
267 radius_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
268 {
269   radius_Continue(descriptor2radius(d), 1);
270 }
271
272 /*
273  * Behave as a struct fdescriptor (descriptor.h)
274  */
275 static int
276 radius_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
277 {
278   struct radius *rad = descriptor2radius(d);
279
280   if (r && rad->cx.fd != -1) {
281     FD_SET(rad->cx.fd, r);
282     if (*n < rad->cx.fd + 1)
283       *n = rad->cx.fd + 1;
284     log_Printf(LogTIMER, "Radius: fdset(r) %d\n", rad->cx.fd);
285     return 1;
286   }
287
288   return 0;
289 }
290
291 /*
292  * Behave as a struct fdescriptor (descriptor.h)
293  */
294 static int
295 radius_IsSet(struct fdescriptor *d, const fd_set *fdset)
296 {
297   struct radius *r = descriptor2radius(d);
298
299   return r && r->cx.fd != -1 && FD_ISSET(r->cx.fd, fdset);
300 }
301
302 /*
303  * Behave as a struct fdescriptor (descriptor.h)
304  */
305 static int
306 radius_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
307 {
308   /* We never want to write here ! */
309   log_Printf(LogALERT, "radius_Write: Internal error: Bad call !\n");
310   return 0;
311 }
312
313 /*
314  * Initialise ourselves
315  */
316 void
317 radius_Init(struct radius *r)
318 {
319   r->valid = 0;
320   r->cx.fd = -1;
321   *r->cfg.file = '\0';;
322   r->desc.type = RADIUS_DESCRIPTOR;
323   r->desc.UpdateSet = radius_UpdateSet;
324   r->desc.IsSet = radius_IsSet;
325   r->desc.Read = radius_Read;
326   r->desc.Write = radius_Write;
327   memset(&r->cx.timer, '\0', sizeof r->cx.timer);
328 }
329
330 /*
331  * Forget everything and go back to initialised state.
332  */
333 void
334 radius_Destroy(struct radius *r)
335 {
336   r->valid = 0;
337   timer_Stop(&r->cx.timer);
338   route_DeleteAll(&r->routes);
339   if (r->cx.fd != -1) {
340     r->cx.fd = -1;
341     rad_close(r->cx.rad);
342   }
343 }
344
345 /*
346  * Start an authentication request to the RADIUS server.
347  */
348 void
349 radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name,
350                     const char *key, const char *challenge)
351 {
352   struct ttyent *ttyp;
353   struct timeval tv;
354   int got, slot;
355   char hostname[MAXHOSTNAMELEN];
356   struct hostent *hp;
357   struct in_addr hostaddr;
358
359   if (!*r->cfg.file)
360     return;
361
362   if (r->cx.fd != -1)
363     /*
364      * We assume that our name/key/challenge is the same as last time,
365      * and just continue to wait for the RADIUS server(s).
366      */
367     return;
368
369   radius_Destroy(r);
370
371   if ((r->cx.rad = rad_open()) == NULL) {
372     log_Printf(LogERROR, "rad_open: %s\n", strerror(errno));
373     return;
374   }
375
376   if (rad_config(r->cx.rad, r->cfg.file) != 0) {
377     log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad));
378     rad_close(r->cx.rad);
379     return;
380   }
381
382   if (rad_create_request(r->cx.rad, RAD_ACCESS_REQUEST) != 0) {
383     log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad));
384     rad_close(r->cx.rad);
385     return;
386   }
387
388   if (rad_put_string(r->cx.rad, RAD_USER_NAME, name) != 0 ||
389       rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 ||
390       rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) {
391     log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
392     rad_close(r->cx.rad);
393     return;
394   }
395
396   if (challenge != NULL) {
397     /* We're talking CHAP */
398     if (rad_put_string(r->cx.rad, RAD_CHAP_PASSWORD, key) != 0 ||
399         rad_put_string(r->cx.rad, RAD_CHAP_CHALLENGE, challenge) != 0) {
400       log_Printf(LogERROR, "CHAP: rad_put_string: %s\n",
401                  rad_strerror(r->cx.rad));
402       rad_close(r->cx.rad);
403       return;
404     }
405   } else if (rad_put_string(r->cx.rad, RAD_USER_PASSWORD, key) != 0) {
406     /* We're talking PAP */
407     log_Printf(LogERROR, "PAP: rad_put_string: %s\n", rad_strerror(r->cx.rad));
408     rad_close(r->cx.rad);
409     return;
410   }
411
412   if (gethostname(hostname, sizeof hostname) != 0)
413     log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno));
414   else {
415     if ((hp = gethostbyname(hostname)) != NULL) {
416       hostaddr.s_addr = *(u_long *)hp->h_addr;
417       if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) {
418         log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
419                    rad_strerror(r->cx.rad));
420         rad_close(r->cx.rad);
421         return;
422       }
423     }
424     if (rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) {
425       log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
426                  rad_strerror(r->cx.rad));
427       rad_close(r->cx.rad);
428       return;
429     }
430   }
431
432   if (authp->physical->handler &&
433       authp->physical->handler->type == TTY_DEVICE) {
434     setttyent();
435     for (slot = 1; (ttyp = getttyent()); ++slot)
436       if (!strcmp(ttyp->ty_name, authp->physical->name.base)) {
437         if(rad_put_int(r->cx.rad, RAD_NAS_PORT, slot) != 0) {
438           log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
439                       rad_strerror(r->cx.rad));
440           rad_close(r->cx.rad);
441           endttyent();
442           return;
443         }
444         break;
445       }
446     endttyent();
447   }
448
449
450   if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv)))
451     radius_Process(r, got);
452   else {
453     log_Printf(LogPHASE, "Radius: Request sent\n");
454     log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout);
455     r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
456     r->cx.timer.func = radius_Timeout;
457     r->cx.timer.name = "radius";
458     r->cx.timer.arg = r;
459     r->cx.auth = authp;
460     timer_Start(&r->cx.timer);
461   }
462 }
463
464 /*
465  * How do things look at the moment ?
466  */
467 void
468 radius_Show(struct radius *r, struct prompt *p)
469 {
470   prompt_Printf(p, " Radius config: %s", *r->cfg.file ? r->cfg.file : "none");
471   if (r->valid) {
472     prompt_Printf(p, "\n            IP: %s\n", inet_ntoa(r->ip));
473     prompt_Printf(p, "       Netmask: %s\n", inet_ntoa(r->mask));
474     prompt_Printf(p, "           MTU: %lu\n", r->mtu);
475     prompt_Printf(p, "            VJ: %sabled\n", r->vj ? "en" : "dis");
476     if (r->routes)
477       route_ShowSticky(p, r->routes, "        Routes", 16);
478   } else
479     prompt_Printf(p, " (not authenticated)\n");
480 }