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