2 * Copyright 1999 Internet Business Solutions Ltd., Switzerland
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
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>
51 #include "descriptor.h"
56 #include "slcompress.h"
57 #include "throughput.h"
80 * rad_continue_send_request() has given us `got' (non-zero). Deal with it.
83 radius_Process(struct radius *r, int got)
85 char *argv[MAXARGS], *nuke;
86 struct bundle *bundle;
93 r->cx.fd = -1; /* Stop select()ing */
96 case RAD_ACCESS_ACCEPT:
97 log_Printf(LogPHASE, "Radius: ACCEPT received\n");
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);
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);
114 log_Printf(LogPHASE, "radius: %s\n", rad_strerror(r->cx.rad));
115 auth_Failure(r->cx.auth);
116 rad_close(r->cx.rad);
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);
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;
131 while ((got = rad_get_attr(r->cx.rad, &data, &len)) > 0) {
133 case RAD_FRAMED_IP_ADDRESS:
134 r->ip = rad_cvt_addr(data);
135 log_Printf(LogPHASE, " IP %s\n", inet_ntoa(r->ip));
138 case RAD_FRAMED_IP_NETMASK:
139 r->mask = rad_cvt_addr(data);
140 log_Printf(LogPHASE, " Netmask %s\n", inet_ntoa(r->mask));
144 r->mtu = rad_cvt_int(data);
145 log_Printf(LogPHASE, " MTU %lu\n", r->mtu);
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 */
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");
160 case RAD_FRAMED_ROUTE:
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
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);
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;
178 argc = command_Interpret(nuke, strlen(nuke), argv);
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",
189 if (dest.width == 32 && strchr(argv[0], '/') == NULL)
190 /* No mask specified - use the natural mask */
191 dest.mask = addr2mask(dest.ipaddr);
194 if (!strncasecmp(argv[0], "HISADDR", 7))
195 addrs = ROUTE_DSTHISADDR;
196 else if (!strncasecmp(argv[0], "MYADDR", 6))
197 addrs = ROUTE_DSTMYADDR;
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;
205 route_Add(&r->routes, addrs, dest.ipaddr, dest.mask, gw);
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);
219 auth_Success(r->cx.auth);
220 rad_close(r->cx.rad);
225 * We've either timed out or select()ed on the read descriptor
228 radius_Continue(struct radius *r, int sel)
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);
241 radius_Process(r, got);
245 * Time to call rad_continue_send_request() - timed out.
248 radius_Timeout(void *v)
250 radius_Continue((struct radius *)v, 0);
254 * Time to call rad_continue_send_request() - something to read.
257 radius_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
259 radius_Continue(descriptor2radius(d), 1);
263 * Behave as a struct descriptor (descriptor.h)
266 radius_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
268 struct radius *rad = descriptor2radius(d);
270 if (r && rad->cx.fd != -1) {
271 FD_SET(rad->cx.fd, r);
272 if (*n < rad->cx.fd + 1)
274 log_Printf(LogTIMER, "Radius: fdset(r) %d\n", rad->cx.fd);
282 * Behave as a struct descriptor (descriptor.h)
285 radius_IsSet(struct descriptor *d, const fd_set *fdset)
287 struct radius *r = descriptor2radius(d);
289 return r && r->cx.fd != -1 && FD_ISSET(r->cx.fd, fdset);
293 * Behave as a struct descriptor (descriptor.h)
296 radius_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
298 /* We never want to write here ! */
299 log_Printf(LogALERT, "radius_Write: Internal error: Bad call !\n");
304 * Initialise ourselves
307 radius_Init(struct radius *r)
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);
321 * Forget everything and go back to initialised state.
324 radius_Destroy(struct radius *r)
327 timer_Stop(&r->cx.timer);
328 route_DeleteAll(&r->routes);
329 if (r->cx.fd != -1) {
331 rad_close(r->cx.rad);
336 * Start an authentication request to the RADIUS server.
339 radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name,
340 const char *key, const char *challenge)
345 char hostname[MAXHOSTNAMELEN];
347 struct in_addr hostaddr;
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).
361 if ((r->cx.rad = rad_open()) == NULL) {
362 log_Printf(LogERROR, "rad_open: %s\n", strerror(errno));
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);
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);
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);
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);
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);
402 if (gethostname(hostname, sizeof hostname) != 0)
403 log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno));
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);
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);
422 if (authp->physical->handler &&
423 authp->physical->handler->type == TTY_DEVICE) {
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);
440 if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv)))
441 radius_Process(r, got);
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";
450 timer_Start(&r->cx.timer);
455 * How do things look at the moment ?
458 radius_Show(struct radius *r, struct prompt *p)
460 prompt_Printf(p, " Radius config: %s", *r->cfg.file ? r->cfg.file : "none");
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");
467 route_ShowSticky(p, r->routes, " Routes", 16);
469 prompt_Printf(p, " (not authenticated)\n");