143313Sbrian/*
243313Sbrian * Copyright 1999 Internet Business Solutions Ltd., Switzerland
343313Sbrian * All rights reserved.
443313Sbrian *
543313Sbrian * Redistribution and use in source and binary forms, with or without
643313Sbrian * modification, are permitted provided that the following conditions
743313Sbrian * are met:
843313Sbrian * 1. Redistributions of source code must retain the above copyright
943313Sbrian *    notice, this list of conditions and the following disclaimer.
1043313Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1143313Sbrian *    notice, this list of conditions and the following disclaimer in the
1243313Sbrian *    documentation and/or other materials provided with the distribution.
1343313Sbrian *
1443313Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1543313Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1643313Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1743313Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1843313Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1943313Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2043313Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2143313Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2243313Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2343313Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2443313Sbrian * SUCH DAMAGE.
2543313Sbrian *
2650479Speter * $FreeBSD$
2743313Sbrian *
2843313Sbrian */
2943313Sbrian
30129457Sdds#include <stdint.h>
3143313Sbrian#include <sys/param.h>
3298132Sbrian
33140905Sbrian#include <sys/select.h>
3458032Sbrian#include <sys/socket.h>
3543313Sbrian#include <netinet/in_systm.h>
3643313Sbrian#include <netinet/in.h>
3743313Sbrian#include <netinet/ip.h>
3843313Sbrian#include <arpa/inet.h>
3943313Sbrian#include <sys/un.h>
4058032Sbrian#include <net/route.h>
4143313Sbrian
4258037Sbrian#ifdef LOCALRAD
4358037Sbrian#include "radlib.h"
4496324Sbrian#include "radlib_vs.h"
4558037Sbrian#else
4658037Sbrian#include <radlib.h>
4796324Sbrian#include <radlib_vs.h>
4858037Sbrian#endif
4958037Sbrian
5043313Sbrian#include <errno.h>
5198132Sbrian#ifndef NODES
5298132Sbrian#include <md5.h>
5398132Sbrian#endif
54102500Sbrian#include <stdarg.h>
5543313Sbrian#include <stdio.h>
5643313Sbrian#include <stdlib.h>
5743313Sbrian#include <string.h>
5843693Sbrian#include <sys/time.h>
5943313Sbrian#include <termios.h>
6050840Sbrian#include <unistd.h>
6150840Sbrian#include <netdb.h>
6243313Sbrian
6346686Sbrian#include "layer.h"
6443313Sbrian#include "defs.h"
6543313Sbrian#include "log.h"
6643313Sbrian#include "descriptor.h"
6743313Sbrian#include "prompt.h"
6843313Sbrian#include "timer.h"
6943313Sbrian#include "fsm.h"
7043313Sbrian#include "iplist.h"
7143313Sbrian#include "slcompress.h"
7243313Sbrian#include "throughput.h"
7343313Sbrian#include "lqr.h"
7443313Sbrian#include "hdlc.h"
7543313Sbrian#include "mbuf.h"
7681634Sbrian#include "ncpaddr.h"
7781634Sbrian#include "ip.h"
7843313Sbrian#include "ipcp.h"
7981634Sbrian#include "ipv6cp.h"
8043313Sbrian#include "route.h"
8143313Sbrian#include "command.h"
8243313Sbrian#include "filter.h"
8343313Sbrian#include "lcp.h"
8443313Sbrian#include "ccp.h"
8543313Sbrian#include "link.h"
8643313Sbrian#include "mp.h"
8743313Sbrian#include "radius.h"
8843693Sbrian#include "auth.h"
8943693Sbrian#include "async.h"
9043693Sbrian#include "physical.h"
9143693Sbrian#include "chat.h"
9243693Sbrian#include "cbcp.h"
9343693Sbrian#include "chap.h"
9443693Sbrian#include "datalink.h"
9581634Sbrian#include "ncp.h"
9643313Sbrian#include "bundle.h"
9796324Sbrian#include "proto.h"
98169986Snovel#include "iface.h"
9943313Sbrian
10096324Sbrian#ifndef NODES
10196730Sbrianstruct mschap_response {
10296324Sbrian  u_char ident;
10396324Sbrian  u_char flags;
10496324Sbrian  u_char lm_response[24];
10596324Sbrian  u_char nt_response[24];
10696324Sbrian};
10796730Sbrian
10896730Sbrianstruct mschap2_response {
10996730Sbrian  u_char ident;
11096730Sbrian  u_char flags;
11196730Sbrian  u_char pchallenge[16];
11296730Sbrian  u_char reserved[8];
11396730Sbrian  u_char response[24];
11496730Sbrian};
11598132Sbrian
11698132Sbrian#define	AUTH_LEN	16
11798132Sbrian#define	SALT_LEN	2
11896324Sbrian#endif
11996324Sbrian
12098132Sbrianstatic const char *
12198132Sbrianradius_policyname(int policy)
12298132Sbrian{
12398132Sbrian  switch(policy) {
12498132Sbrian  case MPPE_POLICY_ALLOWED:
12598132Sbrian    return "Allowed";
12698132Sbrian  case MPPE_POLICY_REQUIRED:
12798132Sbrian    return "Required";
12898132Sbrian  }
12998132Sbrian  return NumStr(policy, NULL, 0);
13098132Sbrian}
13198132Sbrian
13298132Sbrianstatic const char *
13398132Sbrianradius_typesname(int types)
13498132Sbrian{
13598132Sbrian  switch(types) {
13698132Sbrian  case MPPE_TYPE_40BIT:
13798132Sbrian    return "40 bit";
13898132Sbrian  case MPPE_TYPE_128BIT:
13998132Sbrian    return "128 bit";
14098132Sbrian  case MPPE_TYPE_40BIT|MPPE_TYPE_128BIT:
14198132Sbrian    return "40 or 128 bit";
14298132Sbrian  }
14398132Sbrian  return NumStr(types, NULL, 0);
14498132Sbrian}
14598132Sbrian
14698132Sbrian#ifndef NODES
14798132Sbrianstatic void
14898132Sbriandemangle(struct radius *r, const void *mangled, size_t mlen,
14998132Sbrian         char **buf, size_t *len)
15098132Sbrian{
15198132Sbrian  char R[AUTH_LEN];		/* variable names as per rfc2548 */
15298132Sbrian  const char *S;
15398132Sbrian  u_char b[16];
15498132Sbrian  const u_char *A, *C;
15598132Sbrian  MD5_CTX Context;
15698132Sbrian  int Slen, i, Clen, Ppos;
15798132Sbrian  u_char *P;
15898132Sbrian
15998132Sbrian  if (mlen % 16 != SALT_LEN) {
16098132Sbrian    log_Printf(LogWARN, "Cannot interpret mangled data of length %ld\n",
16198132Sbrian               (u_long)mlen);
16298132Sbrian    *buf = NULL;
16398132Sbrian    *len = 0;
16498132Sbrian    return;
16598132Sbrian  }
16698132Sbrian
16798132Sbrian  /* We need the RADIUS Request-Authenticator */
16898132Sbrian  if (rad_request_authenticator(r->cx.rad, R, sizeof R) != AUTH_LEN) {
16998132Sbrian    log_Printf(LogWARN, "Cannot obtain the RADIUS request authenticator\n");
17098132Sbrian    *buf = NULL;
17198132Sbrian    *len = 0;
17298132Sbrian    return;
17398132Sbrian  }
17498132Sbrian
17598132Sbrian  A = (const u_char *)mangled;			/* Salt comes first */
17698132Sbrian  C = (const u_char *)mangled + SALT_LEN;	/* Then the ciphertext */
17798132Sbrian  Clen = mlen - SALT_LEN;
17898132Sbrian  S = rad_server_secret(r->cx.rad);		/* We need the RADIUS secret */
17998132Sbrian  Slen = strlen(S);
18098132Sbrian  P = alloca(Clen);				/* We derive our plaintext */
18198132Sbrian
18298132Sbrian  MD5Init(&Context);
18398132Sbrian  MD5Update(&Context, S, Slen);
18498132Sbrian  MD5Update(&Context, R, AUTH_LEN);
18598132Sbrian  MD5Update(&Context, A, SALT_LEN);
18698132Sbrian  MD5Final(b, &Context);
18798132Sbrian  Ppos = 0;
18898132Sbrian
18998132Sbrian  while (Clen) {
19098132Sbrian    Clen -= 16;
19198132Sbrian
19298132Sbrian    for (i = 0; i < 16; i++)
19398132Sbrian      P[Ppos++] = C[i] ^ b[i];
19498132Sbrian
19598132Sbrian    if (Clen) {
19698132Sbrian      MD5Init(&Context);
19798132Sbrian      MD5Update(&Context, S, Slen);
19898132Sbrian      MD5Update(&Context, C, 16);
19998132Sbrian      MD5Final(b, &Context);
20098132Sbrian    }
20198132Sbrian
20298132Sbrian    C += 16;
20398132Sbrian  }
20498132Sbrian
20598132Sbrian  /*
20698132Sbrian   * The resulting plain text consists of a one-byte length, the text and
20798132Sbrian   * maybe some padding.
20898132Sbrian   */
20998132Sbrian  *len = *P;
21098132Sbrian  if (*len > mlen - 1) {
21198132Sbrian    log_Printf(LogWARN, "Mangled data seems to be garbage\n");
21298132Sbrian    *buf = NULL;
21398132Sbrian    *len = 0;
21498132Sbrian    return;
21598132Sbrian  }
21698132Sbrian
217136375Sbrian  if ((*buf = malloc(*len)) == NULL) {
218136375Sbrian    log_Printf(LogWARN, "demangle: Out of memory (%lu bytes)\n", (u_long)*len);
219136375Sbrian    *len = 0;
220136375Sbrian  } else
221136375Sbrian    memcpy(*buf, P + 1, *len);
22298132Sbrian}
22398132Sbrian#endif
22498132Sbrian
225116622Sume/* XXX: This should go into librarius. */
226116622Sume#ifndef NOINET6
227116622Sumestatic uint8_t *
228116622Sumerad_cvt_ipv6prefix(const void *data, size_t len)
229116622Sume{
230116622Sume	const size_t ipv6len = sizeof(struct in6_addr) + 2;
231116622Sume	uint8_t *s;
232116622Sume
233116622Sume	if (len > ipv6len)
234116622Sume		return NULL;
235116622Sume	s = malloc(ipv6len);
236116622Sume	if (s != NULL) {
237116622Sume		memset(s, 0, ipv6len);
238116622Sume		memcpy(s, data, len);
239116622Sume	}
240116622Sume	return s;
241116622Sume}
242116622Sume#endif
243116622Sume
24443693Sbrian/*
24543693Sbrian * rad_continue_send_request() has given us `got' (non-zero).  Deal with it.
24643693Sbrian */
24743693Sbrianstatic void
24843693Sbrianradius_Process(struct radius *r, int got)
24943313Sbrian{
25043313Sbrian  char *argv[MAXARGS], *nuke;
25143693Sbrian  struct bundle *bundle;
25296324Sbrian  int argc, addrs, res, width;
25345910Sbrian  size_t len;
25481634Sbrian  struct ncprange dest;
25581634Sbrian  struct ncpaddr gw;
25643693Sbrian  const void *data;
25771972Sbrian  const char *stype;
25896324Sbrian  u_int32_t ipaddr, vendor;
25981634Sbrian  struct in_addr ip;
260116586Sume#ifndef NOINET6
261116622Sume  uint8_t ipv6addr[INET6_ADDRSTRLEN];
262116586Sume  struct in6_addr ip6;
263116586Sume#endif
26443313Sbrian
26543693Sbrian  r->cx.fd = -1;		/* Stop select()ing */
26671972Sbrian  stype = r->cx.auth ? "auth" : "acct";
26743313Sbrian
26843313Sbrian  switch (got) {
26943313Sbrian    case RAD_ACCESS_ACCEPT:
270132273Sbrian      log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
271132273Sbrian		 "Radius(%s): ACCEPT received\n", stype);
27271972Sbrian      if (!r->cx.auth) {
27371972Sbrian        rad_close(r->cx.rad);
27471972Sbrian        return;
27571972Sbrian      }
27643313Sbrian      break;
27743313Sbrian
27843693Sbrian    case RAD_ACCESS_REJECT:
279132273Sbrian      log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
280132273Sbrian		 "Radius(%s): REJECT received\n", stype);
28196324Sbrian      if (!r->cx.auth) {
28296324Sbrian        rad_close(r->cx.rad);
28396324Sbrian        return;
28496324Sbrian      }
28596324Sbrian      break;
28643693Sbrian
28743313Sbrian    case RAD_ACCESS_CHALLENGE:
28843313Sbrian      /* we can't deal with this (for now) ! */
289132273Sbrian      log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
290132273Sbrian		 "Radius: CHALLENGE received (can't handle yet)\n");
29171972Sbrian      if (r->cx.auth)
29271972Sbrian        auth_Failure(r->cx.auth);
29343693Sbrian      rad_close(r->cx.rad);
29443693Sbrian      return;
29543313Sbrian
29665178Sbrian    case RAD_ACCOUNTING_RESPONSE:
297132273Sbrian      /*
298132273Sbrian       * It's probably not ideal to log this at PHASE level as we'll see
299132273Sbrian       * too much stuff going to the log when ``set rad_alive'' is used.
300132273Sbrian       * So we differ from older behaviour (ppp version 3.1 and before)
301132273Sbrian       * and just log accounting responses to LogRADIUS.
302132273Sbrian       */
303132273Sbrian      log_Printf(LogRADIUS, "Radius(%s): Accounting response received\n",
304132273Sbrian		 stype);
30571972Sbrian      if (r->cx.auth)
30671972Sbrian        auth_Failure(r->cx.auth);		/* unexpected !!! */
30771972Sbrian
30865178Sbrian      /* No further processing for accounting requests, please */
30965178Sbrian      rad_close(r->cx.rad);
31065178Sbrian      return;
31165178Sbrian
31243313Sbrian    case -1:
313132273Sbrian      log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
314132273Sbrian		 "radius(%s): %s\n", stype, rad_strerror(r->cx.rad));
31571972Sbrian      if (r->cx.auth)
31671972Sbrian        auth_Failure(r->cx.auth);
31743693Sbrian      rad_close(r->cx.rad);
31843693Sbrian      return;
31943313Sbrian
32043313Sbrian    default:
32171972Sbrian      log_Printf(LogERROR, "rad_send_request(%s): Failed %d: %s\n", stype,
32243693Sbrian                 got, rad_strerror(r->cx.rad));
32371972Sbrian      if (r->cx.auth)
32471972Sbrian        auth_Failure(r->cx.auth);
32543693Sbrian      rad_close(r->cx.rad);
32643693Sbrian      return;
32743313Sbrian  }
32843313Sbrian
32996324Sbrian  /* Let's see what we've got in our reply */
33043313Sbrian  r->ip.s_addr = r->mask.s_addr = INADDR_NONE;
33143313Sbrian  r->mtu = 0;
33243313Sbrian  r->vj = 0;
33396324Sbrian  while ((res = rad_get_attr(r->cx.rad, &data, &len)) > 0) {
33496324Sbrian    switch (res) {
33543313Sbrian      case RAD_FRAMED_IP_ADDRESS:
33643313Sbrian        r->ip = rad_cvt_addr(data);
337132273Sbrian	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
338132273Sbrian		   " IP %s\n", inet_ntoa(r->ip));
33943313Sbrian        break;
34043313Sbrian
34196153Sbrian      case RAD_FILTER_ID:
34296153Sbrian        free(r->filterid);
34396153Sbrian        if ((r->filterid = rad_cvt_string(data, len)) == NULL) {
34496153Sbrian          log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
34596324Sbrian          auth_Failure(r->cx.auth);
34696153Sbrian          rad_close(r->cx.rad);
34796153Sbrian          return;
34896153Sbrian        }
349132273Sbrian	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
350132273Sbrian		   " Filter \"%s\"\n", r->filterid);
35196153Sbrian        break;
35296153Sbrian
35396153Sbrian      case RAD_SESSION_TIMEOUT:
35496153Sbrian        r->sessiontime = rad_cvt_int(data);
355132273Sbrian	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
356132273Sbrian		   " Session-Timeout %lu\n", r->sessiontime);
35796153Sbrian        break;
35896153Sbrian
35943313Sbrian      case RAD_FRAMED_IP_NETMASK:
36043313Sbrian        r->mask = rad_cvt_addr(data);
361132273Sbrian	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
362132273Sbrian		   " Netmask %s\n", inet_ntoa(r->mask));
36343313Sbrian        break;
36443313Sbrian
36543313Sbrian      case RAD_FRAMED_MTU:
36643313Sbrian        r->mtu = rad_cvt_int(data);
367132273Sbrian	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
368132273Sbrian		   " MTU %lu\n", r->mtu);
36943313Sbrian        break;
37043313Sbrian
37143313Sbrian      case RAD_FRAMED_ROUTING:
37243313Sbrian        /* Disabled for now - should we automatically set up some filters ? */
37343313Sbrian        /* rad_cvt_int(data); */
37443313Sbrian        /* bit 1 = Send routing packets */
37543313Sbrian        /* bit 2 = Receive routing packets */
37643313Sbrian        break;
37743313Sbrian
37843313Sbrian      case RAD_FRAMED_COMPRESSION:
37943313Sbrian        r->vj = rad_cvt_int(data) == 1 ? 1 : 0;
380132273Sbrian	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
381132273Sbrian		   " VJ %sabled\n", r->vj ? "en" : "dis");
38243313Sbrian        break;
38343313Sbrian
38443313Sbrian      case RAD_FRAMED_ROUTE:
38543313Sbrian        /*
38643313Sbrian         * We expect a string of the format ``dest[/bits] gw [metrics]''
38743313Sbrian         * Any specified metrics are ignored.  MYADDR and HISADDR are
38843313Sbrian         * understood for ``dest'' and ``gw'' and ``0.0.0.0'' is the same
38943313Sbrian         * as ``HISADDR''.
39043313Sbrian         */
39143313Sbrian
39243313Sbrian        if ((nuke = rad_cvt_string(data, len)) == NULL) {
39343693Sbrian          log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
39496324Sbrian          auth_Failure(r->cx.auth);
39543693Sbrian          rad_close(r->cx.rad);
39643693Sbrian          return;
39743313Sbrian        }
39843313Sbrian
399132273Sbrian	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
400132273Sbrian		   " Route: %s\n", nuke);
40143693Sbrian        bundle = r->cx.auth->physical->dl->bundle;
40281634Sbrian        ip.s_addr = INADDR_ANY;
403116586Sume        ncpaddr_setip4(&gw, ip);
40481634Sbrian        ncprange_setip4host(&dest, ip);
40543313Sbrian        argc = command_Interpret(nuke, strlen(nuke), argv);
40654914Sbrian        if (argc < 0)
40754914Sbrian          log_Printf(LogWARN, "radius: %s: Syntax error\n",
40854914Sbrian                     argc == 1 ? argv[0] : "\"\"");
40954914Sbrian        else if (argc < 2)
41043313Sbrian          log_Printf(LogWARN, "radius: %s: Invalid route\n",
41143313Sbrian                     argc == 1 ? argv[0] : "\"\"");
41243313Sbrian        else if ((strcasecmp(argv[0], "default") != 0 &&
41381634Sbrian                  !ncprange_aton(&dest, &bundle->ncp, argv[0])) ||
41481634Sbrian                 !ncpaddr_aton(&gw, &bundle->ncp, argv[1]))
41543313Sbrian          log_Printf(LogWARN, "radius: %s %s: Invalid route\n",
41643313Sbrian                     argv[0], argv[1]);
41743313Sbrian        else {
41881634Sbrian          ncprange_getwidth(&dest, &width);
41981634Sbrian          if (width == 32 && strchr(argv[0], '/') == NULL) {
42043313Sbrian            /* No mask specified - use the natural mask */
42181634Sbrian            ncprange_getip4addr(&dest, &ip);
42281634Sbrian            ncprange_setip4mask(&dest, addr2mask(ip));
42381634Sbrian          }
42443313Sbrian          addrs = 0;
42543313Sbrian
42643313Sbrian          if (!strncasecmp(argv[0], "HISADDR", 7))
42743313Sbrian            addrs = ROUTE_DSTHISADDR;
42843313Sbrian          else if (!strncasecmp(argv[0], "MYADDR", 6))
42943313Sbrian            addrs = ROUTE_DSTMYADDR;
43043313Sbrian
43181634Sbrian          if (ncpaddr_getip4addr(&gw, &ipaddr) && ipaddr == INADDR_ANY) {
43243313Sbrian            addrs |= ROUTE_GWHISADDR;
43381634Sbrian            ncpaddr_setip4(&gw, bundle->ncp.ipcp.peer_ip);
43443313Sbrian          } else if (strcasecmp(argv[1], "HISADDR") == 0)
43543313Sbrian            addrs |= ROUTE_GWHISADDR;
43643313Sbrian
43781634Sbrian          route_Add(&r->routes, addrs, &dest, &gw);
43843313Sbrian        }
43943313Sbrian        free(nuke);
44043313Sbrian        break;
44196324Sbrian
44296324Sbrian      case RAD_REPLY_MESSAGE:
44396324Sbrian        free(r->repstr);
44496324Sbrian        if ((r->repstr = rad_cvt_string(data, len)) == NULL) {
44596324Sbrian          log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
44696324Sbrian          auth_Failure(r->cx.auth);
44796324Sbrian          rad_close(r->cx.rad);
44896324Sbrian          return;
44996324Sbrian        }
450132273Sbrian	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
451132273Sbrian		   " Reply-Message \"%s\"\n", r->repstr);
45296324Sbrian        break;
45396324Sbrian
454116586Sume#ifndef NOINET6
455116622Sume      case RAD_FRAMED_IPV6_PREFIX:
456116622Sume	free(r->ipv6prefix);
457167147Sume	if ((r->ipv6prefix = rad_cvt_ipv6prefix(data, len)) == NULL) {
458167147Sume	  log_Printf(LogERROR, "rad_cvt_ipv6prefix: %s\n",
459167147Sume		     "Malformed attribute in response");
460167147Sume	  auth_Failure(r->cx.auth);
461167147Sume	  rad_close(r->cx.rad);
462167147Sume	  return;
463167147Sume	}
464116622Sume	inet_ntop(AF_INET6, &r->ipv6prefix[2], ipv6addr, sizeof(ipv6addr));
465132273Sbrian	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
466132273Sbrian		   " IPv6 %s/%d\n", ipv6addr, r->ipv6prefix[1]);
467116622Sume        break;
468116622Sume
469116586Sume      case RAD_FRAMED_IPV6_ROUTE:
470116586Sume        /*
471116586Sume         * We expect a string of the format ``dest[/bits] gw [metrics]''
472116586Sume         * Any specified metrics are ignored.  MYADDR6 and HISADDR6 are
473116586Sume         * understood for ``dest'' and ``gw'' and ``::'' is the same
474116586Sume         * as ``HISADDR6''.
475116586Sume         */
476116586Sume
477116586Sume        if ((nuke = rad_cvt_string(data, len)) == NULL) {
478116586Sume          log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
479116586Sume          auth_Failure(r->cx.auth);
480116586Sume          rad_close(r->cx.rad);
481116586Sume          return;
482116586Sume        }
483116586Sume
484132273Sbrian	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
485132273Sbrian		   " IPv6 Route: %s\n", nuke);
486116586Sume        bundle = r->cx.auth->physical->dl->bundle;
487116586Sume	ncpaddr_setip6(&gw, &in6addr_any);
488116586Sume	ncprange_set(&dest, &gw, 0);
489116586Sume        argc = command_Interpret(nuke, strlen(nuke), argv);
490116586Sume        if (argc < 0)
491116586Sume          log_Printf(LogWARN, "radius: %s: Syntax error\n",
492116586Sume                     argc == 1 ? argv[0] : "\"\"");
493116586Sume        else if (argc < 2)
494116586Sume          log_Printf(LogWARN, "radius: %s: Invalid route\n",
495116586Sume                     argc == 1 ? argv[0] : "\"\"");
496116586Sume        else if ((strcasecmp(argv[0], "default") != 0 &&
497116586Sume                  !ncprange_aton(&dest, &bundle->ncp, argv[0])) ||
498116586Sume                 !ncpaddr_aton(&gw, &bundle->ncp, argv[1]))
499116586Sume          log_Printf(LogWARN, "radius: %s %s: Invalid route\n",
500116586Sume                     argv[0], argv[1]);
501116586Sume        else {
502116586Sume          addrs = 0;
503116586Sume
504116586Sume          if (!strncasecmp(argv[0], "HISADDR6", 8))
505116586Sume            addrs = ROUTE_DSTHISADDR6;
506116586Sume          else if (!strncasecmp(argv[0], "MYADDR6", 7))
507116586Sume            addrs = ROUTE_DSTMYADDR6;
508116586Sume
509116586Sume          if (ncpaddr_getip6(&gw, &ip6) && IN6_IS_ADDR_UNSPECIFIED(&ip6)) {
510116586Sume            addrs |= ROUTE_GWHISADDR6;
511116586Sume            ncpaddr_copy(&gw, &bundle->ncp.ipv6cp.hisaddr);
512116586Sume          } else if (strcasecmp(argv[1], "HISADDR6") == 0)
513116586Sume            addrs |= ROUTE_GWHISADDR6;
514116586Sume
515116586Sume          route_Add(&r->ipv6routes, addrs, &dest, &gw);
516116586Sume        }
517116586Sume        free(nuke);
518116586Sume        break;
519116586Sume#endif
520116586Sume
52196324Sbrian      case RAD_VENDOR_SPECIFIC:
52296324Sbrian        if ((res = rad_get_vendor_attr(&vendor, &data, &len)) <= 0) {
52396324Sbrian          log_Printf(LogERROR, "rad_get_vendor_attr: %s (failing!)\n",
52496324Sbrian                     rad_strerror(r->cx.rad));
52596324Sbrian          auth_Failure(r->cx.auth);
52696324Sbrian          rad_close(r->cx.rad);
52796324Sbrian          return;
52896324Sbrian        }
52996324Sbrian
53096324Sbrian	switch (vendor) {
53196324Sbrian          case RAD_VENDOR_MICROSOFT:
53296324Sbrian            switch (res) {
53398132Sbrian#ifndef NODES
53496324Sbrian              case RAD_MICROSOFT_MS_CHAP_ERROR:
53596324Sbrian                free(r->errstr);
53698149Sbrian                if (len == 0)
53798149Sbrian                  r->errstr = NULL;
53898149Sbrian                else {
53998712Sbrian                  if (len < 3 || ((const char *)data)[1] != '=') {
54098712Sbrian                    /*
54198712Sbrian                     * Only point at the String field if we don't think the
54298712Sbrian                     * peer has misformatted the response.
54398712Sbrian                     */
544132790Skan                    data = (const char *)data + 1;
54598712Sbrian                    len--;
54698967Sbrian                  } else
54798967Sbrian                    log_Printf(LogWARN, "Warning: The MS-CHAP-Error "
54898967Sbrian                               "attribute is mis-formatted.  Compensating\n");
54998712Sbrian                  if ((r->errstr = rad_cvt_string((const char *)data,
55098712Sbrian                                                  len)) == NULL) {
55198149Sbrian                    log_Printf(LogERROR, "rad_cvt_string: %s\n",
55298149Sbrian                               rad_strerror(r->cx.rad));
55398149Sbrian                    auth_Failure(r->cx.auth);
55498149Sbrian                    rad_close(r->cx.rad);
55598149Sbrian                    return;
55698149Sbrian                  }
557132273Sbrian		  log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
558132273Sbrian			     " MS-CHAP-Error \"%s\"\n", r->errstr);
55996324Sbrian                }
56096324Sbrian                break;
56196730Sbrian
56296730Sbrian              case RAD_MICROSOFT_MS_CHAP2_SUCCESS:
56396730Sbrian                free(r->msrepstr);
56498149Sbrian                if (len == 0)
56598149Sbrian                  r->msrepstr = NULL;
56698149Sbrian                else {
56798712Sbrian                  if (len < 3 || ((const char *)data)[1] != '=') {
56898712Sbrian                    /*
56998712Sbrian                     * Only point at the String field if we don't think the
57098712Sbrian                     * peer has misformatted the response.
57198712Sbrian                     */
572132790Skan                    data = (const char *)data + 1;
57398712Sbrian                    len--;
57498967Sbrian                  } else
57598967Sbrian                    log_Printf(LogWARN, "Warning: The MS-CHAP2-Success "
57698967Sbrian                               "attribute is mis-formatted.  Compensating\n");
57798712Sbrian                  if ((r->msrepstr = rad_cvt_string((const char *)data,
57898712Sbrian                                                    len)) == NULL) {
57998149Sbrian                    log_Printf(LogERROR, "rad_cvt_string: %s\n",
58098149Sbrian                               rad_strerror(r->cx.rad));
58198149Sbrian                    auth_Failure(r->cx.auth);
58298149Sbrian                    rad_close(r->cx.rad);
58398149Sbrian                    return;
58498149Sbrian                  }
585132273Sbrian		  log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
586132273Sbrian			     " MS-CHAP2-Success \"%s\"\n", r->msrepstr);
58796730Sbrian                }
58896730Sbrian                break;
58998243Sbrian
59098132Sbrian              case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY:
59198132Sbrian                r->mppe.policy = rad_cvt_int(data);
592132273Sbrian		log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
593132273Sbrian			   " MS-MPPE-Encryption-Policy %s\n",
59498132Sbrian                           radius_policyname(r->mppe.policy));
59598132Sbrian                break;
59698132Sbrian
59798132Sbrian              case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES:
59898132Sbrian                r->mppe.types = rad_cvt_int(data);
599132273Sbrian		log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
600132273Sbrian			   " MS-MPPE-Encryption-Types %s\n",
60198132Sbrian                           radius_typesname(r->mppe.types));
60298132Sbrian                break;
60398132Sbrian
60498132Sbrian              case RAD_MICROSOFT_MS_MPPE_RECV_KEY:
60598132Sbrian                free(r->mppe.recvkey);
60698132Sbrian		demangle(r, data, len, &r->mppe.recvkey, &r->mppe.recvkeylen);
607132273Sbrian		log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
608132273Sbrian			   " MS-MPPE-Recv-Key ********\n");
60998132Sbrian                break;
61098132Sbrian
61198132Sbrian              case RAD_MICROSOFT_MS_MPPE_SEND_KEY:
61298132Sbrian		demangle(r, data, len, &r->mppe.sendkey, &r->mppe.sendkeylen);
613132273Sbrian		log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
614132273Sbrian			   " MS-MPPE-Send-Key ********\n");
61598132Sbrian                break;
61698132Sbrian#endif
61798132Sbrian
61896324Sbrian              default:
61996324Sbrian                log_Printf(LogDEBUG, "Dropping MICROSOFT vendor specific "
62096324Sbrian                           "RADIUS attribute %d\n", res);
62196324Sbrian                break;
62296324Sbrian            }
62396324Sbrian            break;
62496324Sbrian
62596324Sbrian          default:
62696324Sbrian            log_Printf(LogDEBUG, "Dropping vendor %lu RADIUS attribute %d\n",
62796324Sbrian                       (unsigned long)vendor, res);
62896324Sbrian            break;
62996324Sbrian        }
63096324Sbrian        break;
63196324Sbrian
63296324Sbrian      default:
63396324Sbrian        log_Printf(LogDEBUG, "Dropping RADIUS attribute %d\n", res);
63496324Sbrian        break;
63543313Sbrian    }
63643313Sbrian  }
63743313Sbrian
63896324Sbrian  if (res == -1) {
63943693Sbrian    log_Printf(LogERROR, "rad_get_attr: %s (failing!)\n",
64043693Sbrian               rad_strerror(r->cx.rad));
64143693Sbrian    auth_Failure(r->cx.auth);
64296324Sbrian  } else if (got == RAD_ACCESS_REJECT)
64396324Sbrian    auth_Failure(r->cx.auth);
64496324Sbrian  else {
64543693Sbrian    r->valid = 1;
64643693Sbrian    auth_Success(r->cx.auth);
64743313Sbrian  }
64896324Sbrian  rad_close(r->cx.rad);
64943693Sbrian}
65043313Sbrian
65143693Sbrian/*
65258038Sbrian * We've either timed out or select()ed on the read descriptor
65343693Sbrian */
65443693Sbrianstatic void
65543693Sbrianradius_Continue(struct radius *r, int sel)
65643693Sbrian{
65743693Sbrian  struct timeval tv;
65843693Sbrian  int got;
65943313Sbrian
66043693Sbrian  timer_Stop(&r->cx.timer);
66143693Sbrian  if ((got = rad_continue_send_request(r->cx.rad, sel, &r->cx.fd, &tv)) == 0) {
662132273Sbrian    log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
663132273Sbrian	       "Radius: Request re-sent\n");
66443693Sbrian    r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
66543693Sbrian    timer_Start(&r->cx.timer);
66643693Sbrian    return;
66743693Sbrian  }
66843693Sbrian
66943693Sbrian  radius_Process(r, got);
67043313Sbrian}
67143313Sbrian
67243693Sbrian/*
67343693Sbrian * Time to call rad_continue_send_request() - timed out.
67443693Sbrian */
67543693Sbrianstatic void
67643693Sbrianradius_Timeout(void *v)
67743693Sbrian{
67843693Sbrian  radius_Continue((struct radius *)v, 0);
67943693Sbrian}
68043693Sbrian
68143693Sbrian/*
68243693Sbrian * Time to call rad_continue_send_request() - something to read.
68343693Sbrian */
68443693Sbrianstatic void
685134789Sbrianradius_Read(struct fdescriptor *d, struct bundle *bundle __unused,
686134789Sbrian	    const fd_set *fdset __unused)
68743693Sbrian{
68843693Sbrian  radius_Continue(descriptor2radius(d), 1);
68943693Sbrian}
69043693Sbrian
69143693Sbrian/*
692140905Sbrian * Flush any pending transactions
693140905Sbrian */
694140905Sbrianvoid
695140905Sbrianradius_Flush(struct radius *r)
696140905Sbrian{
697140905Sbrian  struct timeval tv;
698140905Sbrian  fd_set s;
699140905Sbrian
700140905Sbrian  while (r->cx.fd != -1) {
701140905Sbrian    FD_ZERO(&s);
702140905Sbrian    FD_SET(r->cx.fd, &s);
703140905Sbrian    tv.tv_sec = 0;
704140905Sbrian    tv.tv_usec = TICKUNIT;
705140905Sbrian    select(r->cx.fd + 1, &s, NULL, NULL, &tv);
706140905Sbrian    radius_Continue(r, 1);
707140905Sbrian  }
708140905Sbrian}
709140905Sbrian
710140905Sbrian/*
71158038Sbrian * Behave as a struct fdescriptor (descriptor.h)
71243693Sbrian */
71343693Sbrianstatic int
714134789Sbrianradius_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w __unused,
715134789Sbrian		 fd_set *e __unused, int *n)
71643693Sbrian{
71743693Sbrian  struct radius *rad = descriptor2radius(d);
71843693Sbrian
71943693Sbrian  if (r && rad->cx.fd != -1) {
72043693Sbrian    FD_SET(rad->cx.fd, r);
72143693Sbrian    if (*n < rad->cx.fd + 1)
72243693Sbrian      *n = rad->cx.fd + 1;
72343693Sbrian    log_Printf(LogTIMER, "Radius: fdset(r) %d\n", rad->cx.fd);
72443693Sbrian    return 1;
72543693Sbrian  }
72643693Sbrian
72743693Sbrian  return 0;
72843693Sbrian}
72943693Sbrian
73043693Sbrian/*
73158038Sbrian * Behave as a struct fdescriptor (descriptor.h)
73243693Sbrian */
73343693Sbrianstatic int
73458028Sbrianradius_IsSet(struct fdescriptor *d, const fd_set *fdset)
73543693Sbrian{
73643693Sbrian  struct radius *r = descriptor2radius(d);
73743693Sbrian
73843693Sbrian  return r && r->cx.fd != -1 && FD_ISSET(r->cx.fd, fdset);
73943693Sbrian}
74043693Sbrian
74143693Sbrian/*
74258038Sbrian * Behave as a struct fdescriptor (descriptor.h)
74343693Sbrian */
74443693Sbrianstatic int
745134789Sbrianradius_Write(struct fdescriptor *d __unused, struct bundle *bundle __unused,
746134789Sbrian	     const fd_set *fdset __unused)
74743693Sbrian{
74843693Sbrian  /* We never want to write here ! */
74943693Sbrian  log_Printf(LogALERT, "radius_Write: Internal error: Bad call !\n");
75043693Sbrian  return 0;
75143693Sbrian}
75243693Sbrian
75343693Sbrian/*
75443693Sbrian * Initialise ourselves
75543693Sbrian */
75643313Sbrianvoid
75743693Sbrianradius_Init(struct radius *r)
75843693Sbrian{
75943693Sbrian  r->desc.type = RADIUS_DESCRIPTOR;
76043693Sbrian  r->desc.UpdateSet = radius_UpdateSet;
76143693Sbrian  r->desc.IsSet = radius_IsSet;
76243693Sbrian  r->desc.Read = radius_Read;
76343693Sbrian  r->desc.Write = radius_Write;
76496324Sbrian  r->cx.fd = -1;
76596324Sbrian  r->cx.rad = NULL;
76643693Sbrian  memset(&r->cx.timer, '\0', sizeof r->cx.timer);
76796324Sbrian  r->cx.auth = NULL;
76896324Sbrian  r->valid = 0;
76996324Sbrian  r->vj = 0;
77096324Sbrian  r->ip.s_addr = INADDR_ANY;
77196324Sbrian  r->mask.s_addr = INADDR_NONE;
77296324Sbrian  r->routes = NULL;
77396324Sbrian  r->mtu = DEF_MTU;
77496730Sbrian  r->msrepstr = NULL;
77596324Sbrian  r->repstr = NULL;
776116586Sume#ifndef NOINET6
777116622Sume  r->ipv6prefix = NULL;
778116586Sume  r->ipv6routes = NULL;
779116586Sume#endif
78096324Sbrian  r->errstr = NULL;
78198132Sbrian  r->mppe.policy = 0;
78298132Sbrian  r->mppe.types = 0;
78398132Sbrian  r->mppe.recvkey = NULL;
78498132Sbrian  r->mppe.recvkeylen = 0;
78598132Sbrian  r->mppe.sendkey = NULL;
78698132Sbrian  r->mppe.sendkeylen = 0;
787241844Seadler  *r->cfg.file = '\0';
78865178Sbrian  log_Printf(LogDEBUG, "Radius: radius_Init\n");
78943693Sbrian}
79043693Sbrian
79143693Sbrian/*
79243693Sbrian * Forget everything and go back to initialised state.
79343693Sbrian */
79443693Sbrianvoid
79543693Sbrianradius_Destroy(struct radius *r)
79643693Sbrian{
79743693Sbrian  r->valid = 0;
79865178Sbrian  log_Printf(LogDEBUG, "Radius: radius_Destroy\n");
79943693Sbrian  timer_Stop(&r->cx.timer);
80043693Sbrian  route_DeleteAll(&r->routes);
801116586Sume#ifndef NOINET6
802116586Sume  route_DeleteAll(&r->ipv6routes);
803116586Sume#endif
80496153Sbrian  free(r->filterid);
80596153Sbrian  r->filterid = NULL;
80696730Sbrian  free(r->msrepstr);
80796730Sbrian  r->msrepstr = NULL;
80896324Sbrian  free(r->repstr);
80996324Sbrian  r->repstr = NULL;
810116622Sume#ifndef NOINET6
811116622Sume  free(r->ipv6prefix);
812116622Sume  r->ipv6prefix = NULL;
813116622Sume#endif
81496324Sbrian  free(r->errstr);
81596324Sbrian  r->errstr = NULL;
81698132Sbrian  free(r->mppe.recvkey);
81798132Sbrian  r->mppe.recvkey = NULL;
81898132Sbrian  r->mppe.recvkeylen = 0;
81998132Sbrian  free(r->mppe.sendkey);
82098132Sbrian  r->mppe.sendkey = NULL;
82198132Sbrian  r->mppe.sendkeylen = 0;
82243693Sbrian  if (r->cx.fd != -1) {
82343693Sbrian    r->cx.fd = -1;
82443693Sbrian    rad_close(r->cx.rad);
82543693Sbrian  }
82643693Sbrian}
82743693Sbrian
82896582Sbrianstatic int
829169986Snovelradius_put_physical_details(struct radius *rad, struct physical *p)
83096582Sbrian{
83196582Sbrian  int slot, type;
83296582Sbrian
83396582Sbrian  type = RAD_VIRTUAL;
83496582Sbrian  if (p->handler)
83596582Sbrian    switch (p->handler->type) {
83696582Sbrian      case I4B_DEVICE:
83796582Sbrian        type = RAD_ISDN_SYNC;
83896582Sbrian        break;
83996582Sbrian
84096582Sbrian      case TTY_DEVICE:
84196582Sbrian        type = RAD_ASYNC;
84296582Sbrian        break;
84396582Sbrian
84496582Sbrian      case ETHER_DEVICE:
84596582Sbrian        type = RAD_ETHERNET;
84696582Sbrian        break;
84796582Sbrian
84896582Sbrian      case TCP_DEVICE:
84996582Sbrian      case UDP_DEVICE:
85096582Sbrian      case EXEC_DEVICE:
85196582Sbrian      case ATM_DEVICE:
85296582Sbrian      case NG_DEVICE:
85396582Sbrian        type = RAD_VIRTUAL;
85496582Sbrian        break;
85596582Sbrian    }
85696582Sbrian
857169986Snovel  if (rad_put_int(rad->cx.rad, RAD_NAS_PORT_TYPE, type) != 0) {
858169986Snovel    log_Printf(LogERROR, "rad_put: rad_put_int: %s\n", rad_strerror(rad->cx.rad));
859169986Snovel    rad_close(rad->cx.rad);
86096582Sbrian    return 0;
86196582Sbrian  }
86296582Sbrian
863169986Snovel  switch (rad->port_id_type) {
864169986Snovel    case RPI_PID:
865169986Snovel      slot = (int)getpid();
866169986Snovel      break;
867169986Snovel    case RPI_IFNUM:
868169986Snovel      slot = p->dl->bundle->iface->index;
869169986Snovel      break;
870169986Snovel    case RPI_TUNNUM:
871169986Snovel      slot = p->dl->bundle->unit;
872169986Snovel      break;
873169986Snovel    case RPI_DEFAULT:
874169986Snovel    default:
875169986Snovel      slot = physical_Slot(p);
876169986Snovel      break;
877169986Snovel  }
878169986Snovel
879169986Snovel  if (slot >= 0)
880169986Snovel    if (rad_put_int(rad->cx.rad, RAD_NAS_PORT, slot) != 0) {
881169986Snovel      log_Printf(LogERROR, "rad_put: rad_put_int: %s\n", rad_strerror(rad->cx.rad));
882169986Snovel      rad_close(rad->cx.rad);
88396582Sbrian      return 0;
88496582Sbrian    }
88596582Sbrian
88696582Sbrian  return 1;
88796582Sbrian}
88896582Sbrian
88943693Sbrian/*
89043693Sbrian * Start an authentication request to the RADIUS server.
89143693Sbrian */
89296730Sbrianint
89343693Sbrianradius_Authenticate(struct radius *r, struct authinfo *authp, const char *name,
89496730Sbrian                    const char *key, int klen, const char *nchallenge,
89598311Sbrian                    int nclen)
89643693Sbrian{
897134789Sbrian  char hostname[MAXHOSTNAMELEN];
89843693Sbrian  struct timeval tv;
899134789Sbrian  const char *what = "questionable";	/* silence warnings! */
900134789Sbrian  char *mac_addr;
90196582Sbrian  int got;
90250840Sbrian  struct hostent *hp;
90398132Sbrian  struct in_addr hostaddr;
90496324Sbrian#ifndef NODES
90596730Sbrian  struct mschap_response msresp;
90696730Sbrian  struct mschap2_response msresp2;
90798311Sbrian  const struct MSCHAPv2_resp *keyv2;
90896324Sbrian#endif
90943693Sbrian
91043693Sbrian  if (!*r->cfg.file)
91196730Sbrian    return 0;
91243693Sbrian
91343693Sbrian  if (r->cx.fd != -1)
91443693Sbrian    /*
91543693Sbrian     * We assume that our name/key/challenge is the same as last time,
91643693Sbrian     * and just continue to wait for the RADIUS server(s).
91743693Sbrian     */
91896730Sbrian    return 1;
91943693Sbrian
92043693Sbrian  radius_Destroy(r);
92143693Sbrian
92265178Sbrian  if ((r->cx.rad = rad_auth_open()) == NULL) {
92365178Sbrian    log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno));
92496730Sbrian    return 0;
92543693Sbrian  }
92643693Sbrian
92743693Sbrian  if (rad_config(r->cx.rad, r->cfg.file) != 0) {
92843693Sbrian    log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad));
92943693Sbrian    rad_close(r->cx.rad);
93096730Sbrian    return 0;
93143693Sbrian  }
93243693Sbrian
93343693Sbrian  if (rad_create_request(r->cx.rad, RAD_ACCESS_REQUEST) != 0) {
93443693Sbrian    log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad));
93543693Sbrian    rad_close(r->cx.rad);
93696730Sbrian    return 0;
93743693Sbrian  }
93843693Sbrian
93999418Sbrian  if (rad_put_string(r->cx.rad, RAD_USER_NAME, name) != 0 ||
94043693Sbrian      rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 ||
94143693Sbrian      rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) {
94243693Sbrian    log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
94343693Sbrian    rad_close(r->cx.rad);
94496730Sbrian    return 0;
94543693Sbrian  }
94643693Sbrian
94796324Sbrian  switch (authp->physical->link.lcp.want_auth) {
94896324Sbrian  case PROTO_PAP:
94996324Sbrian    /* We're talking PAP */
95096324Sbrian    if (rad_put_attr(r->cx.rad, RAD_USER_PASSWORD, key, klen) != 0) {
95196324Sbrian      log_Printf(LogERROR, "PAP: rad_put_string: %s\n",
95243693Sbrian                 rad_strerror(r->cx.rad));
95343693Sbrian      rad_close(r->cx.rad);
95496730Sbrian      return 0;
95543693Sbrian    }
956132273Sbrian    what = "PAP";
95796324Sbrian    break;
95896324Sbrian
95996324Sbrian  case PROTO_CHAP:
96096324Sbrian    switch (authp->physical->link.lcp.want_authtype) {
96196324Sbrian    case 0x5:
96296324Sbrian      if (rad_put_attr(r->cx.rad, RAD_CHAP_PASSWORD, key, klen) != 0 ||
96396730Sbrian          rad_put_attr(r->cx.rad, RAD_CHAP_CHALLENGE, nchallenge, nclen) != 0) {
96496324Sbrian        log_Printf(LogERROR, "CHAP: rad_put_string: %s\n",
96596324Sbrian                   rad_strerror(r->cx.rad));
96696324Sbrian        rad_close(r->cx.rad);
96796730Sbrian        return 0;
96896324Sbrian      }
969132273Sbrian      what = "CHAP";
97096324Sbrian      break;
97196324Sbrian
97296324Sbrian#ifndef NODES
97396324Sbrian    case 0x80:
97496324Sbrian      if (klen != 50) {
97596730Sbrian        log_Printf(LogERROR, "CHAP80: Unrecognised key length %d\n", klen);
97696324Sbrian        rad_close(r->cx.rad);
97796730Sbrian        return 0;
97896324Sbrian      }
97996730Sbrian
98096324Sbrian      rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT,
98196730Sbrian                          RAD_MICROSOFT_MS_CHAP_CHALLENGE, nchallenge, nclen);
98296730Sbrian      msresp.ident = *key;
98396730Sbrian      msresp.flags = 0x01;
98496730Sbrian      memcpy(msresp.lm_response, key + 1, 24);
98596730Sbrian      memcpy(msresp.nt_response, key + 25, 24);
98696324Sbrian      rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT,
98796730Sbrian                          RAD_MICROSOFT_MS_CHAP_RESPONSE, &msresp,
98896730Sbrian                          sizeof msresp);
989132273Sbrian      what = "MSCHAP";
99096324Sbrian      break;
99196324Sbrian
99296324Sbrian    case 0x81:
99398311Sbrian      if (klen != sizeof(*keyv2) + 1) {
99496730Sbrian        log_Printf(LogERROR, "CHAP81: Unrecognised key length %d\n", klen);
99596730Sbrian        rad_close(r->cx.rad);
99696730Sbrian        return 0;
99796730Sbrian      }
99896730Sbrian
99998311Sbrian      keyv2 = (const struct MSCHAPv2_resp *)(key + 1);
100096730Sbrian      rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT,
100196730Sbrian                          RAD_MICROSOFT_MS_CHAP_CHALLENGE, nchallenge, nclen);
100296730Sbrian      msresp2.ident = *key;
100398311Sbrian      msresp2.flags = keyv2->Flags;
100498311Sbrian      memcpy(msresp2.response, keyv2->NTResponse, sizeof msresp2.response);
100596730Sbrian      memset(msresp2.reserved, '\0', sizeof msresp2.reserved);
100698311Sbrian      memcpy(msresp2.pchallenge, keyv2->PeerChallenge,
100798311Sbrian             sizeof msresp2.pchallenge);
100896730Sbrian      rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT,
100996730Sbrian                          RAD_MICROSOFT_MS_CHAP2_RESPONSE, &msresp2,
101096730Sbrian                          sizeof msresp2);
1011132273Sbrian      what = "MSCHAPv2";
101296730Sbrian      break;
101396324Sbrian#endif
101496324Sbrian    default:
101598243Sbrian      log_Printf(LogERROR, "CHAP: Unrecognised type 0x%02x\n",
101696324Sbrian                 authp->physical->link.lcp.want_authtype);
101796324Sbrian      rad_close(r->cx.rad);
101896730Sbrian      return 0;
101996324Sbrian    }
102043693Sbrian  }
102143693Sbrian
102250840Sbrian  if (gethostname(hostname, sizeof hostname) != 0)
102350840Sbrian    log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno));
102450840Sbrian  else {
1025138198Sbrian    if (Enabled(authp->physical->dl->bundle, OPT_NAS_IP_ADDRESS) &&
1026138198Sbrian        (hp = gethostbyname(hostname)) != NULL) {
102750840Sbrian      hostaddr.s_addr = *(u_long *)hp->h_addr;
102850840Sbrian      if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) {
102950840Sbrian        log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
103050840Sbrian                   rad_strerror(r->cx.rad));
103150840Sbrian        rad_close(r->cx.rad);
103296730Sbrian        return 0;
103350840Sbrian      }
103450840Sbrian    }
1035138198Sbrian    if (Enabled(authp->physical->dl->bundle, OPT_NAS_IDENTIFIER) &&
1036138198Sbrian        rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) {
103750840Sbrian      log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
103850840Sbrian                 rad_strerror(r->cx.rad));
103950840Sbrian      rad_close(r->cx.rad);
104096730Sbrian      return 0;
104150840Sbrian    }
104250840Sbrian  }
104350840Sbrian
1044131122Sbrian  if ((mac_addr = getenv("HISMACADDR")) != NULL &&
1045131122Sbrian      rad_put_string(r->cx.rad, RAD_CALLING_STATION_ID, mac_addr) != 0) {
1046131122Sbrian    log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
1047131122Sbrian    rad_close(r->cx.rad);
1048134789Sbrian    return 0;
1049131122Sbrian  }
1050131122Sbrian
1051169986Snovel  radius_put_physical_details(r, authp->physical);
105250840Sbrian
1053132273Sbrian  log_Printf(LogRADIUS, "Radius(auth): %s data sent for %s\n", what, name);
1054132273Sbrian
105571972Sbrian  r->cx.auth = authp;
105643693Sbrian  if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv)))
105743693Sbrian    radius_Process(r, got);
105843693Sbrian  else {
1059132273Sbrian    log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
1060132273Sbrian	       "Radius: Request sent\n");
106143693Sbrian    log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout);
106243693Sbrian    r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
106343693Sbrian    r->cx.timer.func = radius_Timeout;
106471972Sbrian    r->cx.timer.name = "radius auth";
106543693Sbrian    r->cx.timer.arg = r;
106643693Sbrian    timer_Start(&r->cx.timer);
106743693Sbrian  }
106896730Sbrian
106996730Sbrian  return 1;
107043693Sbrian}
107143693Sbrian
1072116588Sume/* Fetch IP, netmask from IPCP */
1073116588Sumevoid
1074116588Sumeradius_Account_Set_Ip(struct radacct *ac, struct in_addr *peer_ip,
1075116588Sume		      struct in_addr *netmask)
1076116588Sume{
1077116588Sume  ac->proto = PROTO_IPCP;
1078116990Sume  memcpy(&ac->peer.ip.addr, peer_ip, sizeof(ac->peer.ip.addr));
1079116990Sume  memcpy(&ac->peer.ip.mask, netmask, sizeof(ac->peer.ip.mask));
1080116588Sume}
1081116588Sume
1082116588Sume#ifndef NOINET6
1083116588Sume/* Fetch interface-id from IPV6CP */
1084116588Sumevoid
1085116588Sumeradius_Account_Set_Ipv6(struct radacct *ac, u_char *ifid)
1086116588Sume{
1087116588Sume  ac->proto = PROTO_IPV6CP;
1088116990Sume  memcpy(&ac->peer.ipv6.ifid, ifid, sizeof(ac->peer.ipv6.ifid));
1089116588Sume}
1090116588Sume#endif
1091116588Sume
109243693Sbrian/*
109365178Sbrian * Send an accounting request to the RADIUS server
109465178Sbrian */
109565178Sbrianvoid
109698243Sbrianradius_Account(struct radius *r, struct radacct *ac, struct datalink *dl,
1097116588Sume               int acct_type, struct pppThroughput *stats)
109865178Sbrian{
109965178Sbrian  struct timeval tv;
110096582Sbrian  int got;
110174049Sbrian  char hostname[MAXHOSTNAMELEN];
1102131122Sbrian  char *mac_addr;
110365178Sbrian  struct hostent *hp;
110498132Sbrian  struct in_addr hostaddr;
110565178Sbrian
110665178Sbrian  if (!*r->cfg.file)
110765178Sbrian    return;
110865178Sbrian
110965178Sbrian  if (r->cx.fd != -1)
111065178Sbrian    /*
111165178Sbrian     * We assume that our name/key/challenge is the same as last time,
111265178Sbrian     * and just continue to wait for the RADIUS server(s).
111365178Sbrian     */
111465178Sbrian    return;
111565178Sbrian
111698132Sbrian  timer_Stop(&r->cx.timer);
111765178Sbrian
111867133Sbrian  if ((r->cx.rad = rad_acct_open()) == NULL) {
111965178Sbrian    log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno));
112065178Sbrian    return;
112165178Sbrian  }
112265178Sbrian
112365178Sbrian  if (rad_config(r->cx.rad, r->cfg.file) != 0) {
112465178Sbrian    log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad));
112565178Sbrian    rad_close(r->cx.rad);
112665178Sbrian    return;
112765178Sbrian  }
112865178Sbrian
112965178Sbrian  if (rad_create_request(r->cx.rad, RAD_ACCOUNTING_REQUEST) != 0) {
113065178Sbrian    log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad));
113165178Sbrian    rad_close(r->cx.rad);
113265178Sbrian    return;
113365178Sbrian  }
113465178Sbrian
113565178Sbrian  /* Grab some accounting data and initialize structure */
113665178Sbrian  if (acct_type == RAD_START) {
113765178Sbrian    ac->rad_parent = r;
113865178Sbrian    /* Fetch username from datalink */
113999418Sbrian    strncpy(ac->user_name, dl->peer.authname, sizeof ac->user_name);
114065178Sbrian    ac->user_name[AUTHLEN-1] = '\0';
114165178Sbrian
114265178Sbrian    ac->authentic = 2;		/* Assume RADIUS verified auth data */
114398243Sbrian
114465178Sbrian    /* Generate a session ID */
114597904Sbrian    snprintf(ac->session_id, sizeof ac->session_id, "%s%ld-%s%lu",
114697904Sbrian             dl->bundle->cfg.auth.name, (long)getpid(),
114799418Sbrian             dl->peer.authname, (unsigned long)stats->uptime);
114865178Sbrian
114965178Sbrian    /* And grab our MP socket name */
115065178Sbrian    snprintf(ac->multi_session_id, sizeof ac->multi_session_id, "%s",
115165178Sbrian             dl->bundle->ncp.mp.active ?
115265178Sbrian             dl->bundle->ncp.mp.server.socket.sun_path : "");
115365178Sbrian  };
115465178Sbrian
115565178Sbrian  if (rad_put_string(r->cx.rad, RAD_USER_NAME, ac->user_name) != 0 ||
115665178Sbrian      rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 ||
1157116588Sume      rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) {
115865178Sbrian    log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
115965178Sbrian    rad_close(r->cx.rad);
116065178Sbrian    return;
116165178Sbrian  }
1162116588Sume  switch (ac->proto) {
1163116588Sume  case PROTO_IPCP:
1164116990Sume    if (rad_put_addr(r->cx.rad, RAD_FRAMED_IP_ADDRESS,
1165132151Sbrian		     ac->peer.ip.addr) != 0 ||
1166116990Sume	rad_put_addr(r->cx.rad, RAD_FRAMED_IP_NETMASK,
1167116990Sume		     ac->peer.ip.mask) != 0) {
1168116588Sume      log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
1169116588Sume      rad_close(r->cx.rad);
1170116588Sume      return;
1171116588Sume    }
1172116588Sume    break;
1173116588Sume#ifndef NOINET6
1174116588Sume  case PROTO_IPV6CP:
1175116990Sume    if (rad_put_attr(r->cx.rad, RAD_FRAMED_INTERFACE_ID, ac->peer.ipv6.ifid,
1176116990Sume		     sizeof(ac->peer.ipv6.ifid)) != 0) {
1177116588Sume      log_Printf(LogERROR, "rad_put_attr: %s\n", rad_strerror(r->cx.rad));
1178116588Sume      rad_close(r->cx.rad);
1179116588Sume      return;
1180116588Sume    }
1181116622Sume    if (r->ipv6prefix) {
1182116622Sume      /*
1183116622Sume       * Since PPP doesn't delegate an IPv6 prefix to a peer,
1184116622Sume       * Framed-IPv6-Prefix may be not used, actually.
1185116622Sume       */
1186116622Sume      if (rad_put_attr(r->cx.rad, RAD_FRAMED_IPV6_PREFIX, r->ipv6prefix,
1187116622Sume		       sizeof(struct in6_addr) + 2) != 0) {
1188116622Sume	log_Printf(LogERROR, "rad_put_attr: %s\n", rad_strerror(r->cx.rad));
1189116622Sume	rad_close(r->cx.rad);
1190116622Sume	return;
1191116622Sume      }
1192116622Sume    }
1193116588Sume    break;
1194116588Sume#endif
1195116588Sume  default:
1196116588Sume    /* We don't log any protocol specific information */
1197116588Sume    break;
1198116588Sume  }
119965178Sbrian
1200131122Sbrian  if ((mac_addr = getenv("HISMACADDR")) != NULL &&
1201131122Sbrian      rad_put_string(r->cx.rad, RAD_CALLING_STATION_ID, mac_addr) != 0) {
1202131122Sbrian    log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
1203131122Sbrian    rad_close(r->cx.rad);
1204131122Sbrian    return;
1205131122Sbrian  }
1206131122Sbrian
120765178Sbrian  if (gethostname(hostname, sizeof hostname) != 0)
120865178Sbrian    log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno));
120965178Sbrian  else {
1210138198Sbrian    if (Enabled(dl->bundle, OPT_NAS_IP_ADDRESS) &&
1211138198Sbrian        (hp = gethostbyname(hostname)) != NULL) {
121265178Sbrian      hostaddr.s_addr = *(u_long *)hp->h_addr;
121365178Sbrian      if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) {
121465178Sbrian        log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
121565178Sbrian                   rad_strerror(r->cx.rad));
121665178Sbrian        rad_close(r->cx.rad);
121765178Sbrian        return;
121865178Sbrian      }
121965178Sbrian    }
1220138198Sbrian    if (Enabled(dl->bundle, OPT_NAS_IDENTIFIER) &&
1221138198Sbrian        rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) {
122265178Sbrian      log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
122365178Sbrian                 rad_strerror(r->cx.rad));
122465178Sbrian      rad_close(r->cx.rad);
122565178Sbrian      return;
122665178Sbrian    }
122765178Sbrian  }
122865178Sbrian
1229169986Snovel  radius_put_physical_details(r, dl->physical);
123065178Sbrian
123165178Sbrian  if (rad_put_int(r->cx.rad, RAD_ACCT_STATUS_TYPE, acct_type) != 0 ||
123298243Sbrian      rad_put_string(r->cx.rad, RAD_ACCT_SESSION_ID, ac->session_id) != 0 ||
123365178Sbrian      rad_put_string(r->cx.rad, RAD_ACCT_MULTI_SESSION_ID,
123465178Sbrian                     ac->multi_session_id) != 0 ||
123598243Sbrian      rad_put_int(r->cx.rad, RAD_ACCT_DELAY_TIME, 0) != 0) {
123665178Sbrian/* XXX ACCT_DELAY_TIME should be increased each time a packet is waiting */
123765178Sbrian    log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
123865178Sbrian    rad_close(r->cx.rad);
123965178Sbrian    return;
124065178Sbrian  }
124165178Sbrian
1242132273Sbrian  if (acct_type == RAD_STOP || acct_type == RAD_ALIVE)
1243132273Sbrian    /* Show some statistics */
1244129457Sdds    if (rad_put_int(r->cx.rad, RAD_ACCT_INPUT_OCTETS, stats->OctetsIn % UINT32_MAX) != 0 ||
1245129457Sdds        rad_put_int(r->cx.rad, RAD_ACCT_INPUT_GIGAWORDS, stats->OctetsIn / UINT32_MAX) != 0 ||
124665178Sbrian        rad_put_int(r->cx.rad, RAD_ACCT_INPUT_PACKETS, stats->PacketsIn) != 0 ||
1247129457Sdds        rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_OCTETS, stats->OctetsOut % UINT32_MAX) != 0 ||
1248129457Sdds        rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_GIGAWORDS, stats->OctetsOut / UINT32_MAX) != 0 ||
124965178Sbrian        rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_PACKETS, stats->PacketsOut)
125065178Sbrian        != 0 ||
125165178Sbrian        rad_put_int(r->cx.rad, RAD_ACCT_SESSION_TIME, throughput_uptime(stats))
125265178Sbrian        != 0) {
125365178Sbrian      log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
125465178Sbrian      rad_close(r->cx.rad);
125565178Sbrian      return;
125665178Sbrian    }
125765178Sbrian
1258132273Sbrian  if (log_IsKept(LogPHASE) || log_IsKept(LogRADIUS)) {
1259134789Sbrian    const char *what;
1260132273Sbrian    int level;
1261132273Sbrian
1262132273Sbrian    switch (acct_type) {
1263132273Sbrian    case RAD_START:
1264132273Sbrian      what = "START";
1265132273Sbrian      level = log_IsKept(LogPHASE) ? LogPHASE : LogRADIUS;
1266132273Sbrian      break;
1267132273Sbrian    case RAD_STOP:
1268132273Sbrian      what = "STOP";
1269132273Sbrian      level = log_IsKept(LogPHASE) ? LogPHASE : LogRADIUS;
1270132273Sbrian      break;
1271132273Sbrian    case RAD_ALIVE:
1272132273Sbrian      what = "ALIVE";
1273132273Sbrian      level = LogRADIUS;
1274132273Sbrian      break;
1275132273Sbrian    default:
1276132273Sbrian      what = "<unknown>";
1277132273Sbrian      level = log_IsKept(LogPHASE) ? LogPHASE : LogRADIUS;
1278132273Sbrian      break;
1279132273Sbrian    }
1280132273Sbrian    log_Printf(level, "Radius(acct): %s data sent\n", what);
1281132273Sbrian  }
1282132273Sbrian
128371972Sbrian  r->cx.auth = NULL;			/* Not valid for accounting requests */
128465178Sbrian  if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv)))
128565178Sbrian    radius_Process(r, got);
128665178Sbrian  else {
128765178Sbrian    log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout);
128865178Sbrian    r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
128965178Sbrian    r->cx.timer.func = radius_Timeout;
129071972Sbrian    r->cx.timer.name = "radius acct";
129165178Sbrian    r->cx.timer.arg = r;
129265178Sbrian    timer_Start(&r->cx.timer);
129365178Sbrian  }
129465178Sbrian}
129565178Sbrian
129665178Sbrian/*
129743693Sbrian * How do things look at the moment ?
129843693Sbrian */
129943693Sbrianvoid
130043313Sbrianradius_Show(struct radius *r, struct prompt *p)
130143313Sbrian{
130271657Sbrian  prompt_Printf(p, " Radius config:     %s",
130371657Sbrian                *r->cfg.file ? r->cfg.file : "none");
130443313Sbrian  if (r->valid) {
130571657Sbrian    prompt_Printf(p, "\n                IP: %s\n", inet_ntoa(r->ip));
130671657Sbrian    prompt_Printf(p, "           Netmask: %s\n", inet_ntoa(r->mask));
130771657Sbrian    prompt_Printf(p, "               MTU: %lu\n", r->mtu);
130871657Sbrian    prompt_Printf(p, "                VJ: %sabled\n", r->vj ? "en" : "dis");
130996324Sbrian    prompt_Printf(p, "           Message: %s\n", r->repstr ? r->repstr : "");
131098132Sbrian    prompt_Printf(p, "   MPPE Enc Policy: %s\n",
131198132Sbrian                  radius_policyname(r->mppe.policy));
131298132Sbrian    prompt_Printf(p, "    MPPE Enc Types: %s\n",
131398132Sbrian                  radius_typesname(r->mppe.types));
131498132Sbrian    prompt_Printf(p, "     MPPE Recv Key: %seceived\n",
131598132Sbrian                  r->mppe.recvkey ? "R" : "Not r");
131698132Sbrian    prompt_Printf(p, "     MPPE Send Key: %seceived\n",
131798132Sbrian                  r->mppe.sendkey ? "R" : "Not r");
131896730Sbrian    prompt_Printf(p, " MS-CHAP2-Response: %s\n",
131996730Sbrian                  r->msrepstr ? r->msrepstr : "");
132096324Sbrian    prompt_Printf(p, "     Error Message: %s\n", r->errstr ? r->errstr : "");
132143313Sbrian    if (r->routes)
132271657Sbrian      route_ShowSticky(p, r->routes, "            Routes", 16);
1323116586Sume#ifndef NOINET6
1324116586Sume    if (r->ipv6routes)
1325116586Sume      route_ShowSticky(p, r->ipv6routes, "            IPv6 Routes", 16);
1326116586Sume#endif
132743313Sbrian  } else
132843313Sbrian    prompt_Printf(p, " (not authenticated)\n");
132943313Sbrian}
1330132273Sbrian
1331132273Sbrianstatic void
1332132273Sbrianradius_alive(void *v)
1333132273Sbrian{
1334132273Sbrian  struct bundle *bundle = (struct bundle *)v;
1335132273Sbrian
1336132273Sbrian  timer_Stop(&bundle->radius.alive.timer);
1337132273Sbrian  bundle->radius.alive.timer.load = bundle->radius.alive.interval * SECTICKS;
1338132273Sbrian  if (bundle->radius.alive.timer.load) {
1339132273Sbrian    radius_Account(&bundle->radius, &bundle->radacct,
1340132273Sbrian                   bundle->links, RAD_ALIVE, &bundle->ncp.ipcp.throughput);
1341132273Sbrian    timer_Start(&bundle->radius.alive.timer);
1342132273Sbrian  }
1343132273Sbrian}
1344132273Sbrian
1345132273Sbrianvoid
1346132273Sbrianradius_StartTimer(struct bundle *bundle)
1347132273Sbrian{
1348132273Sbrian  if (bundle->radius.cfg.file && bundle->radius.alive.interval) {
1349132273Sbrian    bundle->radius.alive.timer.func = radius_alive;
1350132273Sbrian    bundle->radius.alive.timer.name = "radius alive";
1351132273Sbrian    bundle->radius.alive.timer.load = bundle->radius.alive.interval * SECTICKS;
1352132273Sbrian    bundle->radius.alive.timer.arg = bundle;
1353132273Sbrian    radius_alive(bundle);
1354132273Sbrian  }
1355132273Sbrian}
1356132273Sbrian
1357132273Sbrianvoid
1358132273Sbrianradius_StopTimer(struct radius *r)
1359132273Sbrian{
1360132273Sbrian  timer_Stop(&r->alive.timer);
1361132273Sbrian}
1362