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 <sys/socket.h>
32 #include <netinet/in_systm.h>
33 #include <netinet/in.h>
34 #include <netinet/ip.h>
35 #include <arpa/inet.h>
37 #include <net/route.h>
58 #include "descriptor.h"
63 #include "slcompress.h"
64 #include "throughput.h"
91 * rad_continue_send_request() has given us `got' (non-zero). Deal with it.
94 radius_Process(struct radius *r, int got)
96 char *argv[MAXARGS], *nuke;
97 struct bundle *bundle;
98 int argc, addrs, width;
100 struct ncprange dest;
107 r->cx.fd = -1; /* Stop select()ing */
108 stype = r->cx.auth ? "auth" : "acct";
111 case RAD_ACCESS_ACCEPT:
112 log_Printf(LogPHASE, "Radius(%s): ACCEPT received\n", stype);
114 rad_close(r->cx.rad);
119 case RAD_ACCESS_REJECT:
120 log_Printf(LogPHASE, "Radius(%s): REJECT received\n", stype);
122 auth_Failure(r->cx.auth);
123 rad_close(r->cx.rad);
126 case RAD_ACCESS_CHALLENGE:
127 /* we can't deal with this (for now) ! */
128 log_Printf(LogPHASE, "Radius: CHALLENGE received (can't handle yet)\n");
130 auth_Failure(r->cx.auth);
131 rad_close(r->cx.rad);
134 case RAD_ACCOUNTING_RESPONSE:
135 log_Printf(LogPHASE, "Radius(%s): Accounting response received\n", stype);
137 auth_Failure(r->cx.auth); /* unexpected !!! */
139 /* No further processing for accounting requests, please */
140 rad_close(r->cx.rad);
144 log_Printf(LogPHASE, "radius(%s): %s\n", stype, rad_strerror(r->cx.rad));
146 auth_Failure(r->cx.auth);
147 rad_close(r->cx.rad);
151 log_Printf(LogERROR, "rad_send_request(%s): Failed %d: %s\n", stype,
152 got, rad_strerror(r->cx.rad));
154 auth_Failure(r->cx.auth);
155 rad_close(r->cx.rad);
159 /* So we've been accepted ! Let's see what we've got in our reply :-I */
160 r->ip.s_addr = r->mask.s_addr = INADDR_NONE;
163 while ((got = rad_get_attr(r->cx.rad, &data, &len)) > 0) {
165 case RAD_FRAMED_IP_ADDRESS:
166 r->ip = rad_cvt_addr(data);
167 log_Printf(LogPHASE, " IP %s\n", inet_ntoa(r->ip));
170 case RAD_FRAMED_IP_NETMASK:
171 r->mask = rad_cvt_addr(data);
172 log_Printf(LogPHASE, " Netmask %s\n", inet_ntoa(r->mask));
176 r->mtu = rad_cvt_int(data);
177 log_Printf(LogPHASE, " MTU %lu\n", r->mtu);
180 case RAD_FRAMED_ROUTING:
181 /* Disabled for now - should we automatically set up some filters ? */
182 /* rad_cvt_int(data); */
183 /* bit 1 = Send routing packets */
184 /* bit 2 = Receive routing packets */
187 case RAD_FRAMED_COMPRESSION:
188 r->vj = rad_cvt_int(data) == 1 ? 1 : 0;
189 log_Printf(LogPHASE, " VJ %sabled\n", r->vj ? "en" : "dis");
192 case RAD_FRAMED_ROUTE:
194 * We expect a string of the format ``dest[/bits] gw [metrics]''
195 * Any specified metrics are ignored. MYADDR and HISADDR are
196 * understood for ``dest'' and ``gw'' and ``0.0.0.0'' is the same
200 if ((nuke = rad_cvt_string(data, len)) == NULL) {
201 log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
202 rad_close(r->cx.rad);
206 log_Printf(LogPHASE, " Route: %s\n", nuke);
207 bundle = r->cx.auth->physical->dl->bundle;
208 ip.s_addr = INADDR_ANY;
209 ncprange_setip4host(&dest, ip);
210 argc = command_Interpret(nuke, strlen(nuke), argv);
212 log_Printf(LogWARN, "radius: %s: Syntax error\n",
213 argc == 1 ? argv[0] : "\"\"");
215 log_Printf(LogWARN, "radius: %s: Invalid route\n",
216 argc == 1 ? argv[0] : "\"\"");
217 else if ((strcasecmp(argv[0], "default") != 0 &&
218 !ncprange_aton(&dest, &bundle->ncp, argv[0])) ||
219 !ncpaddr_aton(&gw, &bundle->ncp, argv[1]))
220 log_Printf(LogWARN, "radius: %s %s: Invalid route\n",
223 ncprange_getwidth(&dest, &width);
224 if (width == 32 && strchr(argv[0], '/') == NULL) {
225 /* No mask specified - use the natural mask */
226 ncprange_getip4addr(&dest, &ip);
227 ncprange_setip4mask(&dest, addr2mask(ip));
231 if (!strncasecmp(argv[0], "HISADDR", 7))
232 addrs = ROUTE_DSTHISADDR;
233 else if (!strncasecmp(argv[0], "MYADDR", 6))
234 addrs = ROUTE_DSTMYADDR;
236 if (ncpaddr_getip4addr(&gw, &ipaddr) && ipaddr == INADDR_ANY) {
237 addrs |= ROUTE_GWHISADDR;
238 ncpaddr_setip4(&gw, bundle->ncp.ipcp.peer_ip);
239 } else if (strcasecmp(argv[1], "HISADDR") == 0)
240 addrs |= ROUTE_GWHISADDR;
242 route_Add(&r->routes, addrs, &dest, &gw);
250 log_Printf(LogERROR, "rad_get_attr: %s (failing!)\n",
251 rad_strerror(r->cx.rad));
252 auth_Failure(r->cx.auth);
253 rad_close(r->cx.rad);
256 auth_Success(r->cx.auth);
257 rad_close(r->cx.rad);
262 * We've either timed out or select()ed on the read descriptor
265 radius_Continue(struct radius *r, int sel)
270 timer_Stop(&r->cx.timer);
271 if ((got = rad_continue_send_request(r->cx.rad, sel, &r->cx.fd, &tv)) == 0) {
272 log_Printf(LogPHASE, "Radius: Request re-sent\n");
273 r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
274 timer_Start(&r->cx.timer);
278 radius_Process(r, got);
282 * Time to call rad_continue_send_request() - timed out.
285 radius_Timeout(void *v)
287 radius_Continue((struct radius *)v, 0);
291 * Time to call rad_continue_send_request() - something to read.
294 radius_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
296 radius_Continue(descriptor2radius(d), 1);
300 * Behave as a struct fdescriptor (descriptor.h)
303 radius_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
305 struct radius *rad = descriptor2radius(d);
307 if (r && rad->cx.fd != -1) {
308 FD_SET(rad->cx.fd, r);
309 if (*n < rad->cx.fd + 1)
311 log_Printf(LogTIMER, "Radius: fdset(r) %d\n", rad->cx.fd);
319 * Behave as a struct fdescriptor (descriptor.h)
322 radius_IsSet(struct fdescriptor *d, const fd_set *fdset)
324 struct radius *r = descriptor2radius(d);
326 return r && r->cx.fd != -1 && FD_ISSET(r->cx.fd, fdset);
330 * Behave as a struct fdescriptor (descriptor.h)
333 radius_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
335 /* We never want to write here ! */
336 log_Printf(LogALERT, "radius_Write: Internal error: Bad call !\n");
341 * Initialise ourselves
344 radius_Init(struct radius *r)
348 *r->cfg.file = '\0';;
349 r->desc.type = RADIUS_DESCRIPTOR;
350 r->desc.UpdateSet = radius_UpdateSet;
351 r->desc.IsSet = radius_IsSet;
352 r->desc.Read = radius_Read;
353 r->desc.Write = radius_Write;
354 memset(&r->cx.timer, '\0', sizeof r->cx.timer);
355 log_Printf(LogDEBUG, "Radius: radius_Init\n");
359 * Forget everything and go back to initialised state.
362 radius_Destroy(struct radius *r)
365 log_Printf(LogDEBUG, "Radius: radius_Destroy\n");
366 timer_Stop(&r->cx.timer);
367 route_DeleteAll(&r->routes);
368 if (r->cx.fd != -1) {
370 rad_close(r->cx.rad);
375 * Start an authentication request to the RADIUS server.
378 radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name,
379 const char *key, int klen, const char *challenge, int clen)
384 char hostname[MAXHOSTNAMELEN];
386 struct in_addr hostaddr;
393 * We assume that our name/key/challenge is the same as last time,
394 * and just continue to wait for the RADIUS server(s).
400 if ((r->cx.rad = rad_auth_open()) == NULL) {
401 log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno));
405 if (rad_config(r->cx.rad, r->cfg.file) != 0) {
406 log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad));
407 rad_close(r->cx.rad);
411 if (rad_create_request(r->cx.rad, RAD_ACCESS_REQUEST) != 0) {
412 log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad));
413 rad_close(r->cx.rad);
417 if (rad_put_string(r->cx.rad, RAD_USER_NAME, name) != 0 ||
418 rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 ||
419 rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) {
420 log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
421 rad_close(r->cx.rad);
425 if (challenge != NULL) {
426 /* We're talking CHAP */
427 if (rad_put_attr(r->cx.rad, RAD_CHAP_PASSWORD, key, klen) != 0 ||
428 rad_put_attr(r->cx.rad, RAD_CHAP_CHALLENGE, challenge, clen) != 0) {
429 log_Printf(LogERROR, "CHAP: rad_put_string: %s\n",
430 rad_strerror(r->cx.rad));
431 rad_close(r->cx.rad);
434 } else if (rad_put_attr(r->cx.rad, RAD_USER_PASSWORD, key, klen) != 0) {
435 /* We're talking PAP */
436 log_Printf(LogERROR, "PAP: rad_put_string: %s\n", rad_strerror(r->cx.rad));
437 rad_close(r->cx.rad);
441 if (gethostname(hostname, sizeof hostname) != 0)
442 log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno));
444 if ((hp = gethostbyname(hostname)) != NULL) {
445 hostaddr.s_addr = *(u_long *)hp->h_addr;
446 if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) {
447 log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
448 rad_strerror(r->cx.rad));
449 rad_close(r->cx.rad);
453 if (rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) {
454 log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
455 rad_strerror(r->cx.rad));
456 rad_close(r->cx.rad);
461 if (authp->physical->handler &&
462 authp->physical->handler->type == TTY_DEVICE) {
464 for (slot = 1; (ttyp = getttyent()); ++slot)
465 if (!strcmp(ttyp->ty_name, authp->physical->name.base)) {
466 if(rad_put_int(r->cx.rad, RAD_NAS_PORT, slot) != 0) {
467 log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
468 rad_strerror(r->cx.rad));
469 rad_close(r->cx.rad);
480 if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv)))
481 radius_Process(r, got);
483 log_Printf(LogPHASE, "Radius: Request sent\n");
484 log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout);
485 r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
486 r->cx.timer.func = radius_Timeout;
487 r->cx.timer.name = "radius auth";
489 timer_Start(&r->cx.timer);
494 * Send an accounting request to the RADIUS server
497 radius_Account(struct radius *r, struct radacct *ac, struct datalink *dl,
498 int acct_type, struct in_addr *peer_ip, struct in_addr *netmask,
499 struct pppThroughput *stats)
504 char hostname[MAXHOSTNAMELEN];
506 struct in_addr hostaddr;
513 * We assume that our name/key/challenge is the same as last time,
514 * and just continue to wait for the RADIUS server(s).
520 if ((r->cx.rad = rad_acct_open()) == NULL) {
521 log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno));
525 if (rad_config(r->cx.rad, r->cfg.file) != 0) {
526 log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad));
527 rad_close(r->cx.rad);
531 if (rad_create_request(r->cx.rad, RAD_ACCOUNTING_REQUEST) != 0) {
532 log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad));
533 rad_close(r->cx.rad);
537 /* Grab some accounting data and initialize structure */
538 if (acct_type == RAD_START) {
540 /* Fetch username from datalink */
541 strncpy(ac->user_name, dl->peer.authname, sizeof ac->user_name);
542 ac->user_name[AUTHLEN-1] = '\0';
544 ac->authentic = 2; /* Assume RADIUS verified auth data */
546 /* Generate a session ID */
547 snprintf(ac->session_id, sizeof ac->session_id, "%s%d-%s%lu",
548 dl->bundle->cfg.auth.name, (int)getpid(),
549 dl->peer.authname, (unsigned long)stats->uptime);
551 /* And grab our MP socket name */
552 snprintf(ac->multi_session_id, sizeof ac->multi_session_id, "%s",
553 dl->bundle->ncp.mp.active ?
554 dl->bundle->ncp.mp.server.socket.sun_path : "");
556 /* Fetch IP, netmask from IPCP */
557 memcpy(&ac->ip, peer_ip, sizeof(ac->ip));
558 memcpy(&ac->mask, netmask, sizeof(ac->mask));
561 if (rad_put_string(r->cx.rad, RAD_USER_NAME, ac->user_name) != 0 ||
562 rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 ||
563 rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0 ||
564 rad_put_addr(r->cx.rad, RAD_FRAMED_IP_ADDRESS, ac->ip) != 0 ||
565 rad_put_addr(r->cx.rad, RAD_FRAMED_IP_NETMASK, ac->mask) != 0) {
566 log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
567 rad_close(r->cx.rad);
571 if (gethostname(hostname, sizeof hostname) != 0)
572 log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno));
574 if ((hp = gethostbyname(hostname)) != NULL) {
575 hostaddr.s_addr = *(u_long *)hp->h_addr;
576 if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) {
577 log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
578 rad_strerror(r->cx.rad));
579 rad_close(r->cx.rad);
583 if (rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) {
584 log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
585 rad_strerror(r->cx.rad));
586 rad_close(r->cx.rad);
591 if (dl->physical->handler &&
592 dl->physical->handler->type == TTY_DEVICE) {
594 for (slot = 1; (ttyp = getttyent()); ++slot)
595 if (!strcmp(ttyp->ty_name, dl->physical->name.base)) {
596 if(rad_put_int(r->cx.rad, RAD_NAS_PORT, slot) != 0) {
597 log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
598 rad_strerror(r->cx.rad));
599 rad_close(r->cx.rad);
608 if (rad_put_int(r->cx.rad, RAD_ACCT_STATUS_TYPE, acct_type) != 0 ||
609 rad_put_string(r->cx.rad, RAD_ACCT_SESSION_ID, ac->session_id) != 0 ||
610 rad_put_string(r->cx.rad, RAD_ACCT_MULTI_SESSION_ID,
611 ac->multi_session_id) != 0 ||
612 rad_put_int(r->cx.rad, RAD_ACCT_DELAY_TIME, 0) != 0) {
613 /* XXX ACCT_DELAY_TIME should be increased each time a packet is waiting */
614 log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
615 rad_close(r->cx.rad);
619 if (acct_type == RAD_STOP)
620 /* Show some statistics */
621 if (rad_put_int(r->cx.rad, RAD_ACCT_INPUT_OCTETS, stats->OctetsIn) != 0 ||
622 rad_put_int(r->cx.rad, RAD_ACCT_INPUT_PACKETS, stats->PacketsIn) != 0 ||
623 rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_OCTETS, stats->OctetsOut) != 0 ||
624 rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_PACKETS, stats->PacketsOut)
626 rad_put_int(r->cx.rad, RAD_ACCT_SESSION_TIME, throughput_uptime(stats))
628 log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
629 rad_close(r->cx.rad);
633 r->cx.auth = NULL; /* Not valid for accounting requests */
634 if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv)))
635 radius_Process(r, got);
637 log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout);
638 r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
639 r->cx.timer.func = radius_Timeout;
640 r->cx.timer.name = "radius acct";
642 timer_Start(&r->cx.timer);
647 * How do things look at the moment ?
650 radius_Show(struct radius *r, struct prompt *p)
652 prompt_Printf(p, " Radius config: %s",
653 *r->cfg.file ? r->cfg.file : "none");
655 prompt_Printf(p, "\n IP: %s\n", inet_ntoa(r->ip));
656 prompt_Printf(p, " Netmask: %s\n", inet_ntoa(r->mask));
657 prompt_Printf(p, " MTU: %lu\n", r->mtu);
658 prompt_Printf(p, " VJ: %sabled\n", r->vj ? "en" : "dis");
660 route_ShowSticky(p, r->routes, " Routes", 16);
662 prompt_Printf(p, " (not authenticated)\n");