radius.c revision 116622
1/*
2 * Copyright 1999 Internet Business Solutions Ltd., Switzerland
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/usr.sbin/ppp/radius.c 116622 2003-06-20 16:15:59Z ume $
27 *
28 */
29
30#include <sys/param.h>
31
32#include <sys/socket.h>
33#include <netinet/in_systm.h>
34#include <netinet/in.h>
35#include <netinet/ip.h>
36#include <arpa/inet.h>
37#include <sys/un.h>
38#include <net/route.h>
39
40#ifdef LOCALRAD
41#include "radlib.h"
42#include "radlib_vs.h"
43#else
44#include <radlib.h>
45#include <radlib_vs.h>
46#endif
47
48#include <errno.h>
49#ifndef NODES
50#include <md5.h>
51#endif
52#include <stdarg.h>
53#include <stdio.h>
54#include <stdlib.h>
55#include <string.h>
56#include <sys/time.h>
57#include <termios.h>
58#include <unistd.h>
59#include <netdb.h>
60
61#include "layer.h"
62#include "defs.h"
63#include "log.h"
64#include "descriptor.h"
65#include "prompt.h"
66#include "timer.h"
67#include "fsm.h"
68#include "iplist.h"
69#include "slcompress.h"
70#include "throughput.h"
71#include "lqr.h"
72#include "hdlc.h"
73#include "mbuf.h"
74#include "ncpaddr.h"
75#include "ip.h"
76#include "ipcp.h"
77#include "ipv6cp.h"
78#include "route.h"
79#include "command.h"
80#include "filter.h"
81#include "lcp.h"
82#include "ccp.h"
83#include "link.h"
84#include "mp.h"
85#include "radius.h"
86#include "auth.h"
87#include "async.h"
88#include "physical.h"
89#include "chat.h"
90#include "cbcp.h"
91#include "chap.h"
92#include "datalink.h"
93#include "ncp.h"
94#include "bundle.h"
95#include "proto.h"
96
97#ifndef NODES
98struct mschap_response {
99  u_char ident;
100  u_char flags;
101  u_char lm_response[24];
102  u_char nt_response[24];
103};
104
105struct mschap2_response {
106  u_char ident;
107  u_char flags;
108  u_char pchallenge[16];
109  u_char reserved[8];
110  u_char response[24];
111};
112
113#define	AUTH_LEN	16
114#define	SALT_LEN	2
115#endif
116
117static const char *
118radius_policyname(int policy)
119{
120  switch(policy) {
121  case MPPE_POLICY_ALLOWED:
122    return "Allowed";
123  case MPPE_POLICY_REQUIRED:
124    return "Required";
125  }
126  return NumStr(policy, NULL, 0);
127}
128
129static const char *
130radius_typesname(int types)
131{
132  switch(types) {
133  case MPPE_TYPE_40BIT:
134    return "40 bit";
135  case MPPE_TYPE_128BIT:
136    return "128 bit";
137  case MPPE_TYPE_40BIT|MPPE_TYPE_128BIT:
138    return "40 or 128 bit";
139  }
140  return NumStr(types, NULL, 0);
141}
142
143#ifndef NODES
144static void
145demangle(struct radius *r, const void *mangled, size_t mlen,
146         char **buf, size_t *len)
147{
148  char R[AUTH_LEN];		/* variable names as per rfc2548 */
149  const char *S;
150  u_char b[16];
151  const u_char *A, *C;
152  MD5_CTX Context;
153  int Slen, i, Clen, Ppos;
154  u_char *P;
155
156  if (mlen % 16 != SALT_LEN) {
157    log_Printf(LogWARN, "Cannot interpret mangled data of length %ld\n",
158               (u_long)mlen);
159    *buf = NULL;
160    *len = 0;
161    return;
162  }
163
164  /* We need the RADIUS Request-Authenticator */
165  if (rad_request_authenticator(r->cx.rad, R, sizeof R) != AUTH_LEN) {
166    log_Printf(LogWARN, "Cannot obtain the RADIUS request authenticator\n");
167    *buf = NULL;
168    *len = 0;
169    return;
170  }
171
172  A = (const u_char *)mangled;			/* Salt comes first */
173  C = (const u_char *)mangled + SALT_LEN;	/* Then the ciphertext */
174  Clen = mlen - SALT_LEN;
175  S = rad_server_secret(r->cx.rad);		/* We need the RADIUS secret */
176  Slen = strlen(S);
177  P = alloca(Clen);				/* We derive our plaintext */
178
179  MD5Init(&Context);
180  MD5Update(&Context, S, Slen);
181  MD5Update(&Context, R, AUTH_LEN);
182  MD5Update(&Context, A, SALT_LEN);
183  MD5Final(b, &Context);
184  Ppos = 0;
185
186  while (Clen) {
187    Clen -= 16;
188
189    for (i = 0; i < 16; i++)
190      P[Ppos++] = C[i] ^ b[i];
191
192    if (Clen) {
193      MD5Init(&Context);
194      MD5Update(&Context, S, Slen);
195      MD5Update(&Context, C, 16);
196      MD5Final(b, &Context);
197    }
198
199    C += 16;
200  }
201
202  /*
203   * The resulting plain text consists of a one-byte length, the text and
204   * maybe some padding.
205   */
206  *len = *P;
207  if (*len > mlen - 1) {
208    log_Printf(LogWARN, "Mangled data seems to be garbage\n");
209    *buf = NULL;
210    *len = 0;
211    return;
212  }
213
214  *buf = malloc(*len);
215  memcpy(*buf, P + 1, *len);
216}
217#endif
218
219/* XXX: This should go into librarius. */
220#ifndef NOINET6
221static uint8_t *
222rad_cvt_ipv6prefix(const void *data, size_t len)
223{
224	const size_t ipv6len = sizeof(struct in6_addr) + 2;
225	uint8_t *s;
226
227	if (len > ipv6len)
228		return NULL;
229	s = malloc(ipv6len);
230	if (s != NULL) {
231		memset(s, 0, ipv6len);
232		memcpy(s, data, len);
233	}
234	return s;
235}
236#endif
237
238/*
239 * rad_continue_send_request() has given us `got' (non-zero).  Deal with it.
240 */
241static void
242radius_Process(struct radius *r, int got)
243{
244  char *argv[MAXARGS], *nuke;
245  struct bundle *bundle;
246  int argc, addrs, res, width;
247  size_t len;
248  struct ncprange dest;
249  struct ncpaddr gw;
250  const void *data;
251  const char *stype;
252  u_int32_t ipaddr, vendor;
253  struct in_addr ip;
254#ifndef NOINET6
255  uint8_t ipv6addr[INET6_ADDRSTRLEN];
256  struct in6_addr ip6;
257#endif
258
259  r->cx.fd = -1;		/* Stop select()ing */
260  stype = r->cx.auth ? "auth" : "acct";
261
262  switch (got) {
263    case RAD_ACCESS_ACCEPT:
264      log_Printf(LogPHASE, "Radius(%s): ACCEPT received\n", stype);
265      if (!r->cx.auth) {
266        rad_close(r->cx.rad);
267        return;
268      }
269      break;
270
271    case RAD_ACCESS_REJECT:
272      log_Printf(LogPHASE, "Radius(%s): REJECT received\n", stype);
273      if (!r->cx.auth) {
274        rad_close(r->cx.rad);
275        return;
276      }
277      break;
278
279    case RAD_ACCESS_CHALLENGE:
280      /* we can't deal with this (for now) ! */
281      log_Printf(LogPHASE, "Radius: CHALLENGE received (can't handle yet)\n");
282      if (r->cx.auth)
283        auth_Failure(r->cx.auth);
284      rad_close(r->cx.rad);
285      return;
286
287    case RAD_ACCOUNTING_RESPONSE:
288      log_Printf(LogPHASE, "Radius(%s): Accounting response received\n", stype);
289      if (r->cx.auth)
290        auth_Failure(r->cx.auth);		/* unexpected !!! */
291
292      /* No further processing for accounting requests, please */
293      rad_close(r->cx.rad);
294      return;
295
296    case -1:
297      log_Printf(LogPHASE, "radius(%s): %s\n", stype, rad_strerror(r->cx.rad));
298      if (r->cx.auth)
299        auth_Failure(r->cx.auth);
300      rad_close(r->cx.rad);
301      return;
302
303    default:
304      log_Printf(LogERROR, "rad_send_request(%s): Failed %d: %s\n", stype,
305                 got, rad_strerror(r->cx.rad));
306      if (r->cx.auth)
307        auth_Failure(r->cx.auth);
308      rad_close(r->cx.rad);
309      return;
310  }
311
312  /* Let's see what we've got in our reply */
313  r->ip.s_addr = r->mask.s_addr = INADDR_NONE;
314  r->mtu = 0;
315  r->vj = 0;
316  while ((res = rad_get_attr(r->cx.rad, &data, &len)) > 0) {
317    switch (res) {
318      case RAD_FRAMED_IP_ADDRESS:
319        r->ip = rad_cvt_addr(data);
320        log_Printf(LogPHASE, " IP %s\n", inet_ntoa(r->ip));
321        break;
322
323      case RAD_FILTER_ID:
324        free(r->filterid);
325        if ((r->filterid = rad_cvt_string(data, len)) == NULL) {
326          log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
327          auth_Failure(r->cx.auth);
328          rad_close(r->cx.rad);
329          return;
330        }
331        log_Printf(LogPHASE, " Filter \"%s\"\n", r->filterid);
332        break;
333
334      case RAD_SESSION_TIMEOUT:
335        r->sessiontime = rad_cvt_int(data);
336        log_Printf(LogPHASE, " Session-Timeout %lu\n", r->sessiontime);
337        break;
338
339      case RAD_FRAMED_IP_NETMASK:
340        r->mask = rad_cvt_addr(data);
341        log_Printf(LogPHASE, " Netmask %s\n", inet_ntoa(r->mask));
342        break;
343
344      case RAD_FRAMED_MTU:
345        r->mtu = rad_cvt_int(data);
346        log_Printf(LogPHASE, " MTU %lu\n", r->mtu);
347        break;
348
349      case RAD_FRAMED_ROUTING:
350        /* Disabled for now - should we automatically set up some filters ? */
351        /* rad_cvt_int(data); */
352        /* bit 1 = Send routing packets */
353        /* bit 2 = Receive routing packets */
354        break;
355
356      case RAD_FRAMED_COMPRESSION:
357        r->vj = rad_cvt_int(data) == 1 ? 1 : 0;
358        log_Printf(LogPHASE, " VJ %sabled\n", r->vj ? "en" : "dis");
359        break;
360
361      case RAD_FRAMED_ROUTE:
362        /*
363         * We expect a string of the format ``dest[/bits] gw [metrics]''
364         * Any specified metrics are ignored.  MYADDR and HISADDR are
365         * understood for ``dest'' and ``gw'' and ``0.0.0.0'' is the same
366         * as ``HISADDR''.
367         */
368
369        if ((nuke = rad_cvt_string(data, len)) == NULL) {
370          log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
371          auth_Failure(r->cx.auth);
372          rad_close(r->cx.rad);
373          return;
374        }
375
376        log_Printf(LogPHASE, " Route: %s\n", nuke);
377        bundle = r->cx.auth->physical->dl->bundle;
378        ip.s_addr = INADDR_ANY;
379        ncpaddr_setip4(&gw, ip);
380        ncprange_setip4host(&dest, ip);
381        argc = command_Interpret(nuke, strlen(nuke), argv);
382        if (argc < 0)
383          log_Printf(LogWARN, "radius: %s: Syntax error\n",
384                     argc == 1 ? argv[0] : "\"\"");
385        else if (argc < 2)
386          log_Printf(LogWARN, "radius: %s: Invalid route\n",
387                     argc == 1 ? argv[0] : "\"\"");
388        else if ((strcasecmp(argv[0], "default") != 0 &&
389                  !ncprange_aton(&dest, &bundle->ncp, argv[0])) ||
390                 !ncpaddr_aton(&gw, &bundle->ncp, argv[1]))
391          log_Printf(LogWARN, "radius: %s %s: Invalid route\n",
392                     argv[0], argv[1]);
393        else {
394          ncprange_getwidth(&dest, &width);
395          if (width == 32 && strchr(argv[0], '/') == NULL) {
396            /* No mask specified - use the natural mask */
397            ncprange_getip4addr(&dest, &ip);
398            ncprange_setip4mask(&dest, addr2mask(ip));
399          }
400          addrs = 0;
401
402          if (!strncasecmp(argv[0], "HISADDR", 7))
403            addrs = ROUTE_DSTHISADDR;
404          else if (!strncasecmp(argv[0], "MYADDR", 6))
405            addrs = ROUTE_DSTMYADDR;
406
407          if (ncpaddr_getip4addr(&gw, &ipaddr) && ipaddr == INADDR_ANY) {
408            addrs |= ROUTE_GWHISADDR;
409            ncpaddr_setip4(&gw, bundle->ncp.ipcp.peer_ip);
410          } else if (strcasecmp(argv[1], "HISADDR") == 0)
411            addrs |= ROUTE_GWHISADDR;
412
413          route_Add(&r->routes, addrs, &dest, &gw);
414        }
415        free(nuke);
416        break;
417
418      case RAD_REPLY_MESSAGE:
419        free(r->repstr);
420        if ((r->repstr = rad_cvt_string(data, len)) == NULL) {
421          log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
422          auth_Failure(r->cx.auth);
423          rad_close(r->cx.rad);
424          return;
425        }
426        log_Printf(LogPHASE, " Reply-Message \"%s\"\n", r->repstr);
427        break;
428
429#ifndef NOINET6
430      case RAD_FRAMED_IPV6_PREFIX:
431	free(r->ipv6prefix);
432        r->ipv6prefix = rad_cvt_ipv6prefix(data, len);
433	inet_ntop(AF_INET6, &r->ipv6prefix[2], ipv6addr, sizeof(ipv6addr));
434        log_Printf(LogPHASE, " IPv6 %s/%d\n", ipv6addr, r->ipv6prefix[1]);
435        break;
436
437      case RAD_FRAMED_IPV6_ROUTE:
438        /*
439         * We expect a string of the format ``dest[/bits] gw [metrics]''
440         * Any specified metrics are ignored.  MYADDR6 and HISADDR6 are
441         * understood for ``dest'' and ``gw'' and ``::'' is the same
442         * as ``HISADDR6''.
443         */
444
445        if ((nuke = rad_cvt_string(data, len)) == NULL) {
446          log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
447          auth_Failure(r->cx.auth);
448          rad_close(r->cx.rad);
449          return;
450        }
451
452        log_Printf(LogPHASE, " IPv6 Route: %s\n", nuke);
453        bundle = r->cx.auth->physical->dl->bundle;
454	ncpaddr_setip6(&gw, &in6addr_any);
455	ncprange_set(&dest, &gw, 0);
456        argc = command_Interpret(nuke, strlen(nuke), argv);
457        if (argc < 0)
458          log_Printf(LogWARN, "radius: %s: Syntax error\n",
459                     argc == 1 ? argv[0] : "\"\"");
460        else if (argc < 2)
461          log_Printf(LogWARN, "radius: %s: Invalid route\n",
462                     argc == 1 ? argv[0] : "\"\"");
463        else if ((strcasecmp(argv[0], "default") != 0 &&
464                  !ncprange_aton(&dest, &bundle->ncp, argv[0])) ||
465                 !ncpaddr_aton(&gw, &bundle->ncp, argv[1]))
466          log_Printf(LogWARN, "radius: %s %s: Invalid route\n",
467                     argv[0], argv[1]);
468        else {
469          addrs = 0;
470
471          if (!strncasecmp(argv[0], "HISADDR6", 8))
472            addrs = ROUTE_DSTHISADDR6;
473          else if (!strncasecmp(argv[0], "MYADDR6", 7))
474            addrs = ROUTE_DSTMYADDR6;
475
476          if (ncpaddr_getip6(&gw, &ip6) && IN6_IS_ADDR_UNSPECIFIED(&ip6)) {
477            addrs |= ROUTE_GWHISADDR6;
478            ncpaddr_copy(&gw, &bundle->ncp.ipv6cp.hisaddr);
479          } else if (strcasecmp(argv[1], "HISADDR6") == 0)
480            addrs |= ROUTE_GWHISADDR6;
481
482          route_Add(&r->ipv6routes, addrs, &dest, &gw);
483        }
484        free(nuke);
485        break;
486#endif
487
488      case RAD_VENDOR_SPECIFIC:
489        if ((res = rad_get_vendor_attr(&vendor, &data, &len)) <= 0) {
490          log_Printf(LogERROR, "rad_get_vendor_attr: %s (failing!)\n",
491                     rad_strerror(r->cx.rad));
492          auth_Failure(r->cx.auth);
493          rad_close(r->cx.rad);
494          return;
495        }
496
497	switch (vendor) {
498          case RAD_VENDOR_MICROSOFT:
499            switch (res) {
500#ifndef NODES
501              case RAD_MICROSOFT_MS_CHAP_ERROR:
502                free(r->errstr);
503                if (len == 0)
504                  r->errstr = NULL;
505                else {
506                  if (len < 3 || ((const char *)data)[1] != '=') {
507                    /*
508                     * Only point at the String field if we don't think the
509                     * peer has misformatted the response.
510                     */
511                    ((const char *)data)++;
512                    len--;
513                  } else
514                    log_Printf(LogWARN, "Warning: The MS-CHAP-Error "
515                               "attribute is mis-formatted.  Compensating\n");
516                  if ((r->errstr = rad_cvt_string((const char *)data,
517                                                  len)) == NULL) {
518                    log_Printf(LogERROR, "rad_cvt_string: %s\n",
519                               rad_strerror(r->cx.rad));
520                    auth_Failure(r->cx.auth);
521                    rad_close(r->cx.rad);
522                    return;
523                  }
524                  log_Printf(LogPHASE, " MS-CHAP-Error \"%s\"\n", r->errstr);
525                }
526                break;
527
528              case RAD_MICROSOFT_MS_CHAP2_SUCCESS:
529                free(r->msrepstr);
530                if (len == 0)
531                  r->msrepstr = NULL;
532                else {
533                  if (len < 3 || ((const char *)data)[1] != '=') {
534                    /*
535                     * Only point at the String field if we don't think the
536                     * peer has misformatted the response.
537                     */
538                    ((const char *)data)++;
539                    len--;
540                  } else
541                    log_Printf(LogWARN, "Warning: The MS-CHAP2-Success "
542                               "attribute is mis-formatted.  Compensating\n");
543                  if ((r->msrepstr = rad_cvt_string((const char *)data,
544                                                    len)) == NULL) {
545                    log_Printf(LogERROR, "rad_cvt_string: %s\n",
546                               rad_strerror(r->cx.rad));
547                    auth_Failure(r->cx.auth);
548                    rad_close(r->cx.rad);
549                    return;
550                  }
551                  log_Printf(LogPHASE, " MS-CHAP2-Success \"%s\"\n",
552                             r->msrepstr);
553                }
554                break;
555
556              case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY:
557                r->mppe.policy = rad_cvt_int(data);
558                log_Printf(LogPHASE, " MS-MPPE-Encryption-Policy %s\n",
559                           radius_policyname(r->mppe.policy));
560                break;
561
562              case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES:
563                r->mppe.types = rad_cvt_int(data);
564                log_Printf(LogPHASE, " MS-MPPE-Encryption-Types %s\n",
565                           radius_typesname(r->mppe.types));
566                break;
567
568              case RAD_MICROSOFT_MS_MPPE_RECV_KEY:
569                free(r->mppe.recvkey);
570		demangle(r, data, len, &r->mppe.recvkey, &r->mppe.recvkeylen);
571                log_Printf(LogPHASE, " MS-MPPE-Recv-Key ********\n");
572                break;
573
574              case RAD_MICROSOFT_MS_MPPE_SEND_KEY:
575		demangle(r, data, len, &r->mppe.sendkey, &r->mppe.sendkeylen);
576                log_Printf(LogPHASE, " MS-MPPE-Send-Key ********\n");
577                break;
578#endif
579
580              default:
581                log_Printf(LogDEBUG, "Dropping MICROSOFT vendor specific "
582                           "RADIUS attribute %d\n", res);
583                break;
584            }
585            break;
586
587          default:
588            log_Printf(LogDEBUG, "Dropping vendor %lu RADIUS attribute %d\n",
589                       (unsigned long)vendor, res);
590            break;
591        }
592        break;
593
594      default:
595        log_Printf(LogDEBUG, "Dropping RADIUS attribute %d\n", res);
596        break;
597    }
598  }
599
600  if (res == -1) {
601    log_Printf(LogERROR, "rad_get_attr: %s (failing!)\n",
602               rad_strerror(r->cx.rad));
603    auth_Failure(r->cx.auth);
604  } else if (got == RAD_ACCESS_REJECT)
605    auth_Failure(r->cx.auth);
606  else {
607    r->valid = 1;
608    auth_Success(r->cx.auth);
609  }
610  rad_close(r->cx.rad);
611}
612
613/*
614 * We've either timed out or select()ed on the read descriptor
615 */
616static void
617radius_Continue(struct radius *r, int sel)
618{
619  struct timeval tv;
620  int got;
621
622  timer_Stop(&r->cx.timer);
623  if ((got = rad_continue_send_request(r->cx.rad, sel, &r->cx.fd, &tv)) == 0) {
624    log_Printf(LogPHASE, "Radius: Request re-sent\n");
625    r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
626    timer_Start(&r->cx.timer);
627    return;
628  }
629
630  radius_Process(r, got);
631}
632
633/*
634 * Time to call rad_continue_send_request() - timed out.
635 */
636static void
637radius_Timeout(void *v)
638{
639  radius_Continue((struct radius *)v, 0);
640}
641
642/*
643 * Time to call rad_continue_send_request() - something to read.
644 */
645static void
646radius_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
647{
648  radius_Continue(descriptor2radius(d), 1);
649}
650
651/*
652 * Behave as a struct fdescriptor (descriptor.h)
653 */
654static int
655radius_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
656{
657  struct radius *rad = descriptor2radius(d);
658
659  if (r && rad->cx.fd != -1) {
660    FD_SET(rad->cx.fd, r);
661    if (*n < rad->cx.fd + 1)
662      *n = rad->cx.fd + 1;
663    log_Printf(LogTIMER, "Radius: fdset(r) %d\n", rad->cx.fd);
664    return 1;
665  }
666
667  return 0;
668}
669
670/*
671 * Behave as a struct fdescriptor (descriptor.h)
672 */
673static int
674radius_IsSet(struct fdescriptor *d, const fd_set *fdset)
675{
676  struct radius *r = descriptor2radius(d);
677
678  return r && r->cx.fd != -1 && FD_ISSET(r->cx.fd, fdset);
679}
680
681/*
682 * Behave as a struct fdescriptor (descriptor.h)
683 */
684static int
685radius_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
686{
687  /* We never want to write here ! */
688  log_Printf(LogALERT, "radius_Write: Internal error: Bad call !\n");
689  return 0;
690}
691
692/*
693 * Initialise ourselves
694 */
695void
696radius_Init(struct radius *r)
697{
698  r->desc.type = RADIUS_DESCRIPTOR;
699  r->desc.UpdateSet = radius_UpdateSet;
700  r->desc.IsSet = radius_IsSet;
701  r->desc.Read = radius_Read;
702  r->desc.Write = radius_Write;
703  r->cx.fd = -1;
704  r->cx.rad = NULL;
705  memset(&r->cx.timer, '\0', sizeof r->cx.timer);
706  r->cx.auth = NULL;
707  r->valid = 0;
708  r->vj = 0;
709  r->ip.s_addr = INADDR_ANY;
710  r->mask.s_addr = INADDR_NONE;
711  r->routes = NULL;
712  r->mtu = DEF_MTU;
713  r->msrepstr = NULL;
714  r->repstr = NULL;
715#ifndef NOINET6
716  r->ipv6prefix = NULL;
717  r->ipv6routes = NULL;
718#endif
719  r->errstr = NULL;
720  r->mppe.policy = 0;
721  r->mppe.types = 0;
722  r->mppe.recvkey = NULL;
723  r->mppe.recvkeylen = 0;
724  r->mppe.sendkey = NULL;
725  r->mppe.sendkeylen = 0;
726  *r->cfg.file = '\0';;
727  log_Printf(LogDEBUG, "Radius: radius_Init\n");
728}
729
730/*
731 * Forget everything and go back to initialised state.
732 */
733void
734radius_Destroy(struct radius *r)
735{
736  r->valid = 0;
737  log_Printf(LogDEBUG, "Radius: radius_Destroy\n");
738  timer_Stop(&r->cx.timer);
739  route_DeleteAll(&r->routes);
740#ifndef NOINET6
741  route_DeleteAll(&r->ipv6routes);
742#endif
743  free(r->filterid);
744  r->filterid = NULL;
745  free(r->msrepstr);
746  r->msrepstr = NULL;
747  free(r->repstr);
748  r->repstr = NULL;
749#ifndef NOINET6
750  free(r->ipv6prefix);
751  r->ipv6prefix = NULL;
752#endif
753  free(r->errstr);
754  r->errstr = NULL;
755  free(r->mppe.recvkey);
756  r->mppe.recvkey = NULL;
757  r->mppe.recvkeylen = 0;
758  free(r->mppe.sendkey);
759  r->mppe.sendkey = NULL;
760  r->mppe.sendkeylen = 0;
761  if (r->cx.fd != -1) {
762    r->cx.fd = -1;
763    rad_close(r->cx.rad);
764  }
765}
766
767static int
768radius_put_physical_details(struct rad_handle *rad, struct physical *p)
769{
770  int slot, type;
771
772  type = RAD_VIRTUAL;
773  if (p->handler)
774    switch (p->handler->type) {
775      case I4B_DEVICE:
776        type = RAD_ISDN_SYNC;
777        break;
778
779      case TTY_DEVICE:
780        type = RAD_ASYNC;
781        break;
782
783      case ETHER_DEVICE:
784        type = RAD_ETHERNET;
785        break;
786
787      case TCP_DEVICE:
788      case UDP_DEVICE:
789      case EXEC_DEVICE:
790      case ATM_DEVICE:
791      case NG_DEVICE:
792        type = RAD_VIRTUAL;
793        break;
794    }
795
796  if (rad_put_int(rad, RAD_NAS_PORT_TYPE, type) != 0) {
797    log_Printf(LogERROR, "rad_put: rad_put_int: %s\n", rad_strerror(rad));
798    rad_close(rad);
799    return 0;
800  }
801
802  if ((slot = physical_Slot(p)) >= 0)
803    if (rad_put_int(rad, RAD_NAS_PORT, slot) != 0) {
804      log_Printf(LogERROR, "rad_put: rad_put_int: %s\n", rad_strerror(rad));
805      rad_close(rad);
806      return 0;
807    }
808
809  return 1;
810}
811
812/*
813 * Start an authentication request to the RADIUS server.
814 */
815int
816radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name,
817                    const char *key, int klen, const char *nchallenge,
818                    int nclen)
819{
820  struct timeval tv;
821  int got;
822  char hostname[MAXHOSTNAMELEN];
823#if 0
824  struct hostent *hp;
825  struct in_addr hostaddr;
826#endif
827#ifndef NODES
828  struct mschap_response msresp;
829  struct mschap2_response msresp2;
830  const struct MSCHAPv2_resp *keyv2;
831#endif
832
833  if (!*r->cfg.file)
834    return 0;
835
836  if (r->cx.fd != -1)
837    /*
838     * We assume that our name/key/challenge is the same as last time,
839     * and just continue to wait for the RADIUS server(s).
840     */
841    return 1;
842
843  radius_Destroy(r);
844
845  if ((r->cx.rad = rad_auth_open()) == NULL) {
846    log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno));
847    return 0;
848  }
849
850  if (rad_config(r->cx.rad, r->cfg.file) != 0) {
851    log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad));
852    rad_close(r->cx.rad);
853    return 0;
854  }
855
856  if (rad_create_request(r->cx.rad, RAD_ACCESS_REQUEST) != 0) {
857    log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad));
858    rad_close(r->cx.rad);
859    return 0;
860  }
861
862  if (rad_put_string(r->cx.rad, RAD_USER_NAME, name) != 0 ||
863      rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 ||
864      rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) {
865    log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
866    rad_close(r->cx.rad);
867    return 0;
868  }
869
870  switch (authp->physical->link.lcp.want_auth) {
871  case PROTO_PAP:
872    /* We're talking PAP */
873    if (rad_put_attr(r->cx.rad, RAD_USER_PASSWORD, key, klen) != 0) {
874      log_Printf(LogERROR, "PAP: rad_put_string: %s\n",
875                 rad_strerror(r->cx.rad));
876      rad_close(r->cx.rad);
877      return 0;
878    }
879    break;
880
881  case PROTO_CHAP:
882    switch (authp->physical->link.lcp.want_authtype) {
883    case 0x5:
884      if (rad_put_attr(r->cx.rad, RAD_CHAP_PASSWORD, key, klen) != 0 ||
885          rad_put_attr(r->cx.rad, RAD_CHAP_CHALLENGE, nchallenge, nclen) != 0) {
886        log_Printf(LogERROR, "CHAP: rad_put_string: %s\n",
887                   rad_strerror(r->cx.rad));
888        rad_close(r->cx.rad);
889        return 0;
890      }
891      break;
892
893#ifndef NODES
894    case 0x80:
895      if (klen != 50) {
896        log_Printf(LogERROR, "CHAP80: Unrecognised key length %d\n", klen);
897        rad_close(r->cx.rad);
898        return 0;
899      }
900
901      rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT,
902                          RAD_MICROSOFT_MS_CHAP_CHALLENGE, nchallenge, nclen);
903      msresp.ident = *key;
904      msresp.flags = 0x01;
905      memcpy(msresp.lm_response, key + 1, 24);
906      memcpy(msresp.nt_response, key + 25, 24);
907      rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT,
908                          RAD_MICROSOFT_MS_CHAP_RESPONSE, &msresp,
909                          sizeof msresp);
910      break;
911
912    case 0x81:
913      if (klen != sizeof(*keyv2) + 1) {
914        log_Printf(LogERROR, "CHAP81: Unrecognised key length %d\n", klen);
915        rad_close(r->cx.rad);
916        return 0;
917      }
918
919      keyv2 = (const struct MSCHAPv2_resp *)(key + 1);
920      rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT,
921                          RAD_MICROSOFT_MS_CHAP_CHALLENGE, nchallenge, nclen);
922      msresp2.ident = *key;
923      msresp2.flags = keyv2->Flags;
924      memcpy(msresp2.response, keyv2->NTResponse, sizeof msresp2.response);
925      memset(msresp2.reserved, '\0', sizeof msresp2.reserved);
926      memcpy(msresp2.pchallenge, keyv2->PeerChallenge,
927             sizeof msresp2.pchallenge);
928      rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT,
929                          RAD_MICROSOFT_MS_CHAP2_RESPONSE, &msresp2,
930                          sizeof msresp2);
931      break;
932#endif
933    default:
934      log_Printf(LogERROR, "CHAP: Unrecognised type 0x%02x\n",
935                 authp->physical->link.lcp.want_authtype);
936      rad_close(r->cx.rad);
937      return 0;
938    }
939  }
940
941  if (gethostname(hostname, sizeof hostname) != 0)
942    log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno));
943  else {
944#if 0
945    if ((hp = gethostbyname(hostname)) != NULL) {
946      hostaddr.s_addr = *(u_long *)hp->h_addr;
947      if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) {
948        log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
949                   rad_strerror(r->cx.rad));
950        rad_close(r->cx.rad);
951        return 0;
952      }
953    }
954#endif
955    if (rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) {
956      log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
957                 rad_strerror(r->cx.rad));
958      rad_close(r->cx.rad);
959      return 0;
960    }
961  }
962
963  radius_put_physical_details(r->cx.rad, authp->physical);
964
965  r->cx.auth = authp;
966  if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv)))
967    radius_Process(r, got);
968  else {
969    log_Printf(LogPHASE, "Radius: Request sent\n");
970    log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout);
971    r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
972    r->cx.timer.func = radius_Timeout;
973    r->cx.timer.name = "radius auth";
974    r->cx.timer.arg = r;
975    timer_Start(&r->cx.timer);
976  }
977
978  return 1;
979}
980
981/* Fetch IP, netmask from IPCP */
982void
983radius_Account_Set_Ip(struct radacct *ac, struct in_addr *peer_ip,
984		      struct in_addr *netmask)
985{
986  ac->proto = PROTO_IPCP;
987  memcpy(&ac->ip.addr, peer_ip, sizeof(ac->ip.addr));
988  memcpy(&ac->ip.mask, netmask, sizeof(ac->ip.mask));
989}
990
991#ifndef NOINET6
992/* Fetch interface-id from IPV6CP */
993void
994radius_Account_Set_Ipv6(struct radacct *ac, u_char *ifid)
995{
996  ac->proto = PROTO_IPV6CP;
997  memcpy(&ac->ipv6.ifid, ifid, sizeof(ac->ipv6.ifid));
998}
999#endif
1000
1001/*
1002 * Send an accounting request to the RADIUS server
1003 */
1004void
1005radius_Account(struct radius *r, struct radacct *ac, struct datalink *dl,
1006               int acct_type, struct pppThroughput *stats)
1007{
1008  struct timeval tv;
1009  int got;
1010  char hostname[MAXHOSTNAMELEN];
1011#if 0
1012  struct hostent *hp;
1013  struct in_addr hostaddr;
1014#endif
1015
1016  if (!*r->cfg.file)
1017    return;
1018
1019  if (r->cx.fd != -1)
1020    /*
1021     * We assume that our name/key/challenge is the same as last time,
1022     * and just continue to wait for the RADIUS server(s).
1023     */
1024    return;
1025
1026  timer_Stop(&r->cx.timer);
1027
1028  if ((r->cx.rad = rad_acct_open()) == NULL) {
1029    log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno));
1030    return;
1031  }
1032
1033  if (rad_config(r->cx.rad, r->cfg.file) != 0) {
1034    log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad));
1035    rad_close(r->cx.rad);
1036    return;
1037  }
1038
1039  if (rad_create_request(r->cx.rad, RAD_ACCOUNTING_REQUEST) != 0) {
1040    log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad));
1041    rad_close(r->cx.rad);
1042    return;
1043  }
1044
1045  /* Grab some accounting data and initialize structure */
1046  if (acct_type == RAD_START) {
1047    ac->rad_parent = r;
1048    /* Fetch username from datalink */
1049    strncpy(ac->user_name, dl->peer.authname, sizeof ac->user_name);
1050    ac->user_name[AUTHLEN-1] = '\0';
1051
1052    ac->authentic = 2;		/* Assume RADIUS verified auth data */
1053
1054    /* Generate a session ID */
1055    snprintf(ac->session_id, sizeof ac->session_id, "%s%ld-%s%lu",
1056             dl->bundle->cfg.auth.name, (long)getpid(),
1057             dl->peer.authname, (unsigned long)stats->uptime);
1058
1059    /* And grab our MP socket name */
1060    snprintf(ac->multi_session_id, sizeof ac->multi_session_id, "%s",
1061             dl->bundle->ncp.mp.active ?
1062             dl->bundle->ncp.mp.server.socket.sun_path : "");
1063  };
1064
1065  if (rad_put_string(r->cx.rad, RAD_USER_NAME, ac->user_name) != 0 ||
1066      rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 ||
1067      rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) {
1068    log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
1069    rad_close(r->cx.rad);
1070    return;
1071  }
1072  switch (ac->proto) {
1073  case PROTO_IPCP:
1074    if (rad_put_addr(r->cx.rad, RAD_FRAMED_IP_ADDRESS, ac->ip.addr) != 0 ||
1075	rad_put_addr(r->cx.rad, RAD_FRAMED_IP_NETMASK, ac->ip.mask) != 0) {
1076      log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
1077      rad_close(r->cx.rad);
1078      return;
1079    }
1080    break;
1081#ifndef NOINET6
1082  case PROTO_IPV6CP:
1083    if (rad_put_attr(r->cx.rad, RAD_FRAMED_INTERFACE_ID, ac->ipv6.ifid,
1084		     sizeof(ac->ipv6.ifid)) != 0) {
1085      log_Printf(LogERROR, "rad_put_attr: %s\n", rad_strerror(r->cx.rad));
1086      rad_close(r->cx.rad);
1087      return;
1088    }
1089    if (r->ipv6prefix) {
1090      /*
1091       * Since PPP doesn't delegate an IPv6 prefix to a peer,
1092       * Framed-IPv6-Prefix may be not used, actually.
1093       */
1094      if (rad_put_attr(r->cx.rad, RAD_FRAMED_IPV6_PREFIX, r->ipv6prefix,
1095		       sizeof(struct in6_addr) + 2) != 0) {
1096	log_Printf(LogERROR, "rad_put_attr: %s\n", rad_strerror(r->cx.rad));
1097	rad_close(r->cx.rad);
1098	return;
1099      }
1100    }
1101    break;
1102#endif
1103  default:
1104    /* We don't log any protocol specific information */
1105    break;
1106  }
1107
1108  if (gethostname(hostname, sizeof hostname) != 0)
1109    log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno));
1110  else {
1111#if 0
1112    if ((hp = gethostbyname(hostname)) != NULL) {
1113      hostaddr.s_addr = *(u_long *)hp->h_addr;
1114      if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) {
1115        log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
1116                   rad_strerror(r->cx.rad));
1117        rad_close(r->cx.rad);
1118        return;
1119      }
1120    }
1121#endif
1122    if (rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) {
1123      log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
1124                 rad_strerror(r->cx.rad));
1125      rad_close(r->cx.rad);
1126      return;
1127    }
1128  }
1129
1130  radius_put_physical_details(r->cx.rad, dl->physical);
1131
1132  if (rad_put_int(r->cx.rad, RAD_ACCT_STATUS_TYPE, acct_type) != 0 ||
1133      rad_put_string(r->cx.rad, RAD_ACCT_SESSION_ID, ac->session_id) != 0 ||
1134      rad_put_string(r->cx.rad, RAD_ACCT_MULTI_SESSION_ID,
1135                     ac->multi_session_id) != 0 ||
1136      rad_put_int(r->cx.rad, RAD_ACCT_DELAY_TIME, 0) != 0) {
1137/* XXX ACCT_DELAY_TIME should be increased each time a packet is waiting */
1138    log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
1139    rad_close(r->cx.rad);
1140    return;
1141  }
1142
1143  if (acct_type == RAD_STOP)
1144  /* Show some statistics */
1145    if (rad_put_int(r->cx.rad, RAD_ACCT_INPUT_OCTETS, stats->OctetsIn) != 0 ||
1146        rad_put_int(r->cx.rad, RAD_ACCT_INPUT_PACKETS, stats->PacketsIn) != 0 ||
1147        rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_OCTETS, stats->OctetsOut) != 0 ||
1148        rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_PACKETS, stats->PacketsOut)
1149        != 0 ||
1150        rad_put_int(r->cx.rad, RAD_ACCT_SESSION_TIME, throughput_uptime(stats))
1151        != 0) {
1152      log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
1153      rad_close(r->cx.rad);
1154      return;
1155    }
1156
1157  r->cx.auth = NULL;			/* Not valid for accounting requests */
1158  if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv)))
1159    radius_Process(r, got);
1160  else {
1161    log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout);
1162    r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
1163    r->cx.timer.func = radius_Timeout;
1164    r->cx.timer.name = "radius acct";
1165    r->cx.timer.arg = r;
1166    timer_Start(&r->cx.timer);
1167  }
1168}
1169
1170/*
1171 * How do things look at the moment ?
1172 */
1173void
1174radius_Show(struct radius *r, struct prompt *p)
1175{
1176  prompt_Printf(p, " Radius config:     %s",
1177                *r->cfg.file ? r->cfg.file : "none");
1178  if (r->valid) {
1179    prompt_Printf(p, "\n                IP: %s\n", inet_ntoa(r->ip));
1180    prompt_Printf(p, "           Netmask: %s\n", inet_ntoa(r->mask));
1181    prompt_Printf(p, "               MTU: %lu\n", r->mtu);
1182    prompt_Printf(p, "                VJ: %sabled\n", r->vj ? "en" : "dis");
1183    prompt_Printf(p, "           Message: %s\n", r->repstr ? r->repstr : "");
1184    prompt_Printf(p, "   MPPE Enc Policy: %s\n",
1185                  radius_policyname(r->mppe.policy));
1186    prompt_Printf(p, "    MPPE Enc Types: %s\n",
1187                  radius_typesname(r->mppe.types));
1188    prompt_Printf(p, "     MPPE Recv Key: %seceived\n",
1189                  r->mppe.recvkey ? "R" : "Not r");
1190    prompt_Printf(p, "     MPPE Send Key: %seceived\n",
1191                  r->mppe.sendkey ? "R" : "Not r");
1192    prompt_Printf(p, " MS-CHAP2-Response: %s\n",
1193                  r->msrepstr ? r->msrepstr : "");
1194    prompt_Printf(p, "     Error Message: %s\n", r->errstr ? r->errstr : "");
1195    if (r->routes)
1196      route_ShowSticky(p, r->routes, "            Routes", 16);
1197#ifndef NOINET6
1198    if (r->ipv6routes)
1199      route_ShowSticky(p, r->ipv6routes, "            IPv6 Routes", 16);
1200#endif
1201  } else
1202    prompt_Printf(p, " (not authenticated)\n");
1203}
1204