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));
172 if ((r->filterid = rad_cvt_string(data, len)) == NULL) {
173 log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
174 rad_close(r->cx.rad);
177 log_Printf(LogPHASE, " Filter \"%s\"\n", r->filterid);
180 case RAD_SESSION_TIMEOUT:
181 r->sessiontime = rad_cvt_int(data);
182 log_Printf(LogPHASE, " Session-Timeout %lu\n", r->sessiontime);
185 case RAD_FRAMED_IP_NETMASK:
186 r->mask = rad_cvt_addr(data);
187 log_Printf(LogPHASE, " Netmask %s\n", inet_ntoa(r->mask));
191 r->mtu = rad_cvt_int(data);
192 log_Printf(LogPHASE, " MTU %lu\n", r->mtu);
195 case RAD_FRAMED_ROUTING:
196 /* Disabled for now - should we automatically set up some filters ? */
197 /* rad_cvt_int(data); */
198 /* bit 1 = Send routing packets */
199 /* bit 2 = Receive routing packets */
202 case RAD_FRAMED_COMPRESSION:
203 r->vj = rad_cvt_int(data) == 1 ? 1 : 0;
204 log_Printf(LogPHASE, " VJ %sabled\n", r->vj ? "en" : "dis");
207 case RAD_FRAMED_ROUTE:
209 * We expect a string of the format ``dest[/bits] gw [metrics]''
210 * Any specified metrics are ignored. MYADDR and HISADDR are
211 * understood for ``dest'' and ``gw'' and ``0.0.0.0'' is the same
215 if ((nuke = rad_cvt_string(data, len)) == NULL) {
216 log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
217 rad_close(r->cx.rad);
221 log_Printf(LogPHASE, " Route: %s\n", nuke);
222 bundle = r->cx.auth->physical->dl->bundle;
223 ip.s_addr = INADDR_ANY;
224 ncprange_setip4host(&dest, ip);
225 argc = command_Interpret(nuke, strlen(nuke), argv);
227 log_Printf(LogWARN, "radius: %s: Syntax error\n",
228 argc == 1 ? argv[0] : "\"\"");
230 log_Printf(LogWARN, "radius: %s: Invalid route\n",
231 argc == 1 ? argv[0] : "\"\"");
232 else if ((strcasecmp(argv[0], "default") != 0 &&
233 !ncprange_aton(&dest, &bundle->ncp, argv[0])) ||
234 !ncpaddr_aton(&gw, &bundle->ncp, argv[1]))
235 log_Printf(LogWARN, "radius: %s %s: Invalid route\n",
238 ncprange_getwidth(&dest, &width);
239 if (width == 32 && strchr(argv[0], '/') == NULL) {
240 /* No mask specified - use the natural mask */
241 ncprange_getip4addr(&dest, &ip);
242 ncprange_setip4mask(&dest, addr2mask(ip));
246 if (!strncasecmp(argv[0], "HISADDR", 7))
247 addrs = ROUTE_DSTHISADDR;
248 else if (!strncasecmp(argv[0], "MYADDR", 6))
249 addrs = ROUTE_DSTMYADDR;
251 if (ncpaddr_getip4addr(&gw, &ipaddr) && ipaddr == INADDR_ANY) {
252 addrs |= ROUTE_GWHISADDR;
253 ncpaddr_setip4(&gw, bundle->ncp.ipcp.peer_ip);
254 } else if (strcasecmp(argv[1], "HISADDR") == 0)
255 addrs |= ROUTE_GWHISADDR;
257 route_Add(&r->routes, addrs, &dest, &gw);
265 log_Printf(LogERROR, "rad_get_attr: %s (failing!)\n",
266 rad_strerror(r->cx.rad));
267 auth_Failure(r->cx.auth);
268 rad_close(r->cx.rad);
271 auth_Success(r->cx.auth);
272 rad_close(r->cx.rad);
277 * We've either timed out or select()ed on the read descriptor
280 radius_Continue(struct radius *r, int sel)
285 timer_Stop(&r->cx.timer);
286 if ((got = rad_continue_send_request(r->cx.rad, sel, &r->cx.fd, &tv)) == 0) {
287 log_Printf(LogPHASE, "Radius: Request re-sent\n");
288 r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
289 timer_Start(&r->cx.timer);
293 radius_Process(r, got);
297 * Time to call rad_continue_send_request() - timed out.
300 radius_Timeout(void *v)
302 radius_Continue((struct radius *)v, 0);
306 * Time to call rad_continue_send_request() - something to read.
309 radius_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
311 radius_Continue(descriptor2radius(d), 1);
315 * Behave as a struct fdescriptor (descriptor.h)
318 radius_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
320 struct radius *rad = descriptor2radius(d);
322 if (r && rad->cx.fd != -1) {
323 FD_SET(rad->cx.fd, r);
324 if (*n < rad->cx.fd + 1)
326 log_Printf(LogTIMER, "Radius: fdset(r) %d\n", rad->cx.fd);
334 * Behave as a struct fdescriptor (descriptor.h)
337 radius_IsSet(struct fdescriptor *d, const fd_set *fdset)
339 struct radius *r = descriptor2radius(d);
341 return r && r->cx.fd != -1 && FD_ISSET(r->cx.fd, fdset);
345 * Behave as a struct fdescriptor (descriptor.h)
348 radius_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
350 /* We never want to write here ! */
351 log_Printf(LogALERT, "radius_Write: Internal error: Bad call !\n");
356 * Initialise ourselves
359 radius_Init(struct radius *r)
363 *r->cfg.file = '\0';;
364 r->desc.type = RADIUS_DESCRIPTOR;
365 r->desc.UpdateSet = radius_UpdateSet;
366 r->desc.IsSet = radius_IsSet;
367 r->desc.Read = radius_Read;
368 r->desc.Write = radius_Write;
369 memset(&r->cx.timer, '\0', sizeof r->cx.timer);
370 log_Printf(LogDEBUG, "Radius: radius_Init\n");
374 * Forget everything and go back to initialised state.
377 radius_Destroy(struct radius *r)
380 log_Printf(LogDEBUG, "Radius: radius_Destroy\n");
381 timer_Stop(&r->cx.timer);
382 route_DeleteAll(&r->routes);
385 if (r->cx.fd != -1) {
387 rad_close(r->cx.rad);
392 * Start an authentication request to the RADIUS server.
395 radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name,
396 const char *key, int klen, const char *challenge, int clen)
401 char hostname[MAXHOSTNAMELEN];
403 struct in_addr hostaddr;
410 * We assume that our name/key/challenge is the same as last time,
411 * and just continue to wait for the RADIUS server(s).
417 if ((r->cx.rad = rad_auth_open()) == NULL) {
418 log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno));
422 if (rad_config(r->cx.rad, r->cfg.file) != 0) {
423 log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad));
424 rad_close(r->cx.rad);
428 if (rad_create_request(r->cx.rad, RAD_ACCESS_REQUEST) != 0) {
429 log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad));
430 rad_close(r->cx.rad);
434 if (rad_put_string(r->cx.rad, RAD_USER_NAME, name) != 0 ||
435 rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 ||
436 rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) {
437 log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
438 rad_close(r->cx.rad);
442 if (challenge != NULL) {
443 /* We're talking CHAP */
444 if (rad_put_attr(r->cx.rad, RAD_CHAP_PASSWORD, key, klen) != 0 ||
445 rad_put_attr(r->cx.rad, RAD_CHAP_CHALLENGE, challenge, clen) != 0) {
446 log_Printf(LogERROR, "CHAP: rad_put_string: %s\n",
447 rad_strerror(r->cx.rad));
448 rad_close(r->cx.rad);
451 } else if (rad_put_attr(r->cx.rad, RAD_USER_PASSWORD, key, klen) != 0) {
452 /* We're talking PAP */
453 log_Printf(LogERROR, "PAP: rad_put_string: %s\n", rad_strerror(r->cx.rad));
454 rad_close(r->cx.rad);
458 if (gethostname(hostname, sizeof hostname) != 0)
459 log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno));
461 if ((hp = gethostbyname(hostname)) != NULL) {
462 hostaddr.s_addr = *(u_long *)hp->h_addr;
463 if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) {
464 log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
465 rad_strerror(r->cx.rad));
466 rad_close(r->cx.rad);
470 if (rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) {
471 log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
472 rad_strerror(r->cx.rad));
473 rad_close(r->cx.rad);
478 if (authp->physical->handler &&
479 authp->physical->handler->type == TTY_DEVICE) {
481 for (slot = 1; (ttyp = getttyent()); ++slot)
482 if (!strcmp(ttyp->ty_name, authp->physical->name.base)) {
483 if (rad_put_int(r->cx.rad, RAD_NAS_PORT, slot) != 0) {
484 log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
485 rad_strerror(r->cx.rad));
486 rad_close(r->cx.rad);
497 if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv)))
498 radius_Process(r, got);
500 log_Printf(LogPHASE, "Radius: Request sent\n");
501 log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout);
502 r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
503 r->cx.timer.func = radius_Timeout;
504 r->cx.timer.name = "radius auth";
506 timer_Start(&r->cx.timer);
511 * Send an accounting request to the RADIUS server
514 radius_Account(struct radius *r, struct radacct *ac, struct datalink *dl,
515 int acct_type, struct in_addr *peer_ip, struct in_addr *netmask,
516 struct pppThroughput *stats)
521 char hostname[MAXHOSTNAMELEN];
523 struct in_addr hostaddr;
530 * We assume that our name/key/challenge is the same as last time,
531 * and just continue to wait for the RADIUS server(s).
537 if ((r->cx.rad = rad_acct_open()) == NULL) {
538 log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno));
542 if (rad_config(r->cx.rad, r->cfg.file) != 0) {
543 log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad));
544 rad_close(r->cx.rad);
548 if (rad_create_request(r->cx.rad, RAD_ACCOUNTING_REQUEST) != 0) {
549 log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad));
550 rad_close(r->cx.rad);
554 /* Grab some accounting data and initialize structure */
555 if (acct_type == RAD_START) {
557 /* Fetch username from datalink */
558 strncpy(ac->user_name, dl->peer.authname, sizeof ac->user_name);
559 ac->user_name[AUTHLEN-1] = '\0';
561 ac->authentic = 2; /* Assume RADIUS verified auth data */
563 /* Generate a session ID */
564 snprintf(ac->session_id, sizeof ac->session_id, "%s%d-%s%lu",
565 dl->bundle->cfg.auth.name, (int)getpid(),
566 dl->peer.authname, (unsigned long)stats->uptime);
568 /* And grab our MP socket name */
569 snprintf(ac->multi_session_id, sizeof ac->multi_session_id, "%s",
570 dl->bundle->ncp.mp.active ?
571 dl->bundle->ncp.mp.server.socket.sun_path : "");
573 /* Fetch IP, netmask from IPCP */
574 memcpy(&ac->ip, peer_ip, sizeof(ac->ip));
575 memcpy(&ac->mask, netmask, sizeof(ac->mask));
578 if (rad_put_string(r->cx.rad, RAD_USER_NAME, ac->user_name) != 0 ||
579 rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 ||
580 rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0 ||
581 rad_put_addr(r->cx.rad, RAD_FRAMED_IP_ADDRESS, ac->ip) != 0 ||
582 rad_put_addr(r->cx.rad, RAD_FRAMED_IP_NETMASK, ac->mask) != 0) {
583 log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
584 rad_close(r->cx.rad);
588 if (gethostname(hostname, sizeof hostname) != 0)
589 log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno));
591 if ((hp = gethostbyname(hostname)) != NULL) {
592 hostaddr.s_addr = *(u_long *)hp->h_addr;
593 if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) {
594 log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
595 rad_strerror(r->cx.rad));
596 rad_close(r->cx.rad);
600 if (rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) {
601 log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
602 rad_strerror(r->cx.rad));
603 rad_close(r->cx.rad);
608 if (dl->physical->handler &&
609 dl->physical->handler->type == TTY_DEVICE) {
611 for (slot = 1; (ttyp = getttyent()); ++slot)
612 if (!strcmp(ttyp->ty_name, dl->physical->name.base)) {
613 if (rad_put_int(r->cx.rad, RAD_NAS_PORT, slot) != 0) {
614 log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
615 rad_strerror(r->cx.rad));
616 rad_close(r->cx.rad);
625 if (rad_put_int(r->cx.rad, RAD_ACCT_STATUS_TYPE, acct_type) != 0 ||
626 rad_put_string(r->cx.rad, RAD_ACCT_SESSION_ID, ac->session_id) != 0 ||
627 rad_put_string(r->cx.rad, RAD_ACCT_MULTI_SESSION_ID,
628 ac->multi_session_id) != 0 ||
629 rad_put_int(r->cx.rad, RAD_ACCT_DELAY_TIME, 0) != 0) {
630 /* XXX ACCT_DELAY_TIME should be increased each time a packet is waiting */
631 log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
632 rad_close(r->cx.rad);
636 if (acct_type == RAD_STOP)
637 /* Show some statistics */
638 if (rad_put_int(r->cx.rad, RAD_ACCT_INPUT_OCTETS, stats->OctetsIn) != 0 ||
639 rad_put_int(r->cx.rad, RAD_ACCT_INPUT_PACKETS, stats->PacketsIn) != 0 ||
640 rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_OCTETS, stats->OctetsOut) != 0 ||
641 rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_PACKETS, stats->PacketsOut)
643 rad_put_int(r->cx.rad, RAD_ACCT_SESSION_TIME, throughput_uptime(stats))
645 log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
646 rad_close(r->cx.rad);
650 r->cx.auth = NULL; /* Not valid for accounting requests */
651 if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv)))
652 radius_Process(r, got);
654 log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout);
655 r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
656 r->cx.timer.func = radius_Timeout;
657 r->cx.timer.name = "radius acct";
659 timer_Start(&r->cx.timer);
664 * How do things look at the moment ?
667 radius_Show(struct radius *r, struct prompt *p)
669 prompt_Printf(p, " Radius config: %s",
670 *r->cfg.file ? r->cfg.file : "none");
672 prompt_Printf(p, "\n IP: %s\n", inet_ntoa(r->ip));
673 prompt_Printf(p, " Netmask: %s\n", inet_ntoa(r->mask));
674 prompt_Printf(p, " MTU: %lu\n", r->mtu);
675 prompt_Printf(p, " VJ: %sabled\n", r->vj ? "en" : "dis");
677 route_ShowSticky(p, r->routes, " Routes", 16);
679 prompt_Printf(p, " (not authenticated)\n");