xref: /freebsd/usr.sbin/ppp/radius.c (revision 7660b554bc59a07be0431c17e0e33815818baa69)
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$
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
98 struct mschap_response {
99   u_char ident;
100   u_char flags;
101   u_char lm_response[24];
102   u_char nt_response[24];
103 };
104 
105 struct 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 
117 static const char *
118 radius_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 
129 static const char *
130 radius_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
144 static void
145 demangle(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
221 static uint8_t *
222 rad_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  */
241 static void
242 radius_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  */
616 static void
617 radius_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  */
636 static void
637 radius_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  */
645 static void
646 radius_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  */
654 static int
655 radius_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  */
673 static int
674 radius_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  */
684 static int
685 radius_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  */
695 void
696 radius_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  */
733 void
734 radius_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 
767 static int
768 radius_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  */
815 int
816 radius_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 */
982 void
983 radius_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->peer.ip.addr, peer_ip, sizeof(ac->peer.ip.addr));
988   memcpy(&ac->peer.ip.mask, netmask, sizeof(ac->peer.ip.mask));
989 }
990 
991 #ifndef NOINET6
992 /* Fetch interface-id from IPV6CP */
993 void
994 radius_Account_Set_Ipv6(struct radacct *ac, u_char *ifid)
995 {
996   ac->proto = PROTO_IPV6CP;
997   memcpy(&ac->peer.ipv6.ifid, ifid, sizeof(ac->peer.ipv6.ifid));
998 }
999 #endif
1000 
1001 /*
1002  * Send an accounting request to the RADIUS server
1003  */
1004 void
1005 radius_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,
1075 		     ac->peer.ip.addr) != 0 || \
1076 	rad_put_addr(r->cx.rad, RAD_FRAMED_IP_NETMASK,
1077 		     ac->peer.ip.mask) != 0) {
1078       log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
1079       rad_close(r->cx.rad);
1080       return;
1081     }
1082     break;
1083 #ifndef NOINET6
1084   case PROTO_IPV6CP:
1085     if (rad_put_attr(r->cx.rad, RAD_FRAMED_INTERFACE_ID, ac->peer.ipv6.ifid,
1086 		     sizeof(ac->peer.ipv6.ifid)) != 0) {
1087       log_Printf(LogERROR, "rad_put_attr: %s\n", rad_strerror(r->cx.rad));
1088       rad_close(r->cx.rad);
1089       return;
1090     }
1091     if (r->ipv6prefix) {
1092       /*
1093        * Since PPP doesn't delegate an IPv6 prefix to a peer,
1094        * Framed-IPv6-Prefix may be not used, actually.
1095        */
1096       if (rad_put_attr(r->cx.rad, RAD_FRAMED_IPV6_PREFIX, r->ipv6prefix,
1097 		       sizeof(struct in6_addr) + 2) != 0) {
1098 	log_Printf(LogERROR, "rad_put_attr: %s\n", rad_strerror(r->cx.rad));
1099 	rad_close(r->cx.rad);
1100 	return;
1101       }
1102     }
1103     break;
1104 #endif
1105   default:
1106     /* We don't log any protocol specific information */
1107     break;
1108   }
1109 
1110   if (gethostname(hostname, sizeof hostname) != 0)
1111     log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno));
1112   else {
1113 #if 0
1114     if ((hp = gethostbyname(hostname)) != NULL) {
1115       hostaddr.s_addr = *(u_long *)hp->h_addr;
1116       if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) {
1117         log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
1118                    rad_strerror(r->cx.rad));
1119         rad_close(r->cx.rad);
1120         return;
1121       }
1122     }
1123 #endif
1124     if (rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) {
1125       log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
1126                  rad_strerror(r->cx.rad));
1127       rad_close(r->cx.rad);
1128       return;
1129     }
1130   }
1131 
1132   radius_put_physical_details(r->cx.rad, dl->physical);
1133 
1134   if (rad_put_int(r->cx.rad, RAD_ACCT_STATUS_TYPE, acct_type) != 0 ||
1135       rad_put_string(r->cx.rad, RAD_ACCT_SESSION_ID, ac->session_id) != 0 ||
1136       rad_put_string(r->cx.rad, RAD_ACCT_MULTI_SESSION_ID,
1137                      ac->multi_session_id) != 0 ||
1138       rad_put_int(r->cx.rad, RAD_ACCT_DELAY_TIME, 0) != 0) {
1139 /* XXX ACCT_DELAY_TIME should be increased each time a packet is waiting */
1140     log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
1141     rad_close(r->cx.rad);
1142     return;
1143   }
1144 
1145   if (acct_type == RAD_STOP)
1146   /* Show some statistics */
1147     if (rad_put_int(r->cx.rad, RAD_ACCT_INPUT_OCTETS, stats->OctetsIn) != 0 ||
1148         rad_put_int(r->cx.rad, RAD_ACCT_INPUT_PACKETS, stats->PacketsIn) != 0 ||
1149         rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_OCTETS, stats->OctetsOut) != 0 ||
1150         rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_PACKETS, stats->PacketsOut)
1151         != 0 ||
1152         rad_put_int(r->cx.rad, RAD_ACCT_SESSION_TIME, throughput_uptime(stats))
1153         != 0) {
1154       log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
1155       rad_close(r->cx.rad);
1156       return;
1157     }
1158 
1159   r->cx.auth = NULL;			/* Not valid for accounting requests */
1160   if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv)))
1161     radius_Process(r, got);
1162   else {
1163     log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout);
1164     r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
1165     r->cx.timer.func = radius_Timeout;
1166     r->cx.timer.name = "radius acct";
1167     r->cx.timer.arg = r;
1168     timer_Start(&r->cx.timer);
1169   }
1170 }
1171 
1172 /*
1173  * How do things look at the moment ?
1174  */
1175 void
1176 radius_Show(struct radius *r, struct prompt *p)
1177 {
1178   prompt_Printf(p, " Radius config:     %s",
1179                 *r->cfg.file ? r->cfg.file : "none");
1180   if (r->valid) {
1181     prompt_Printf(p, "\n                IP: %s\n", inet_ntoa(r->ip));
1182     prompt_Printf(p, "           Netmask: %s\n", inet_ntoa(r->mask));
1183     prompt_Printf(p, "               MTU: %lu\n", r->mtu);
1184     prompt_Printf(p, "                VJ: %sabled\n", r->vj ? "en" : "dis");
1185     prompt_Printf(p, "           Message: %s\n", r->repstr ? r->repstr : "");
1186     prompt_Printf(p, "   MPPE Enc Policy: %s\n",
1187                   radius_policyname(r->mppe.policy));
1188     prompt_Printf(p, "    MPPE Enc Types: %s\n",
1189                   radius_typesname(r->mppe.types));
1190     prompt_Printf(p, "     MPPE Recv Key: %seceived\n",
1191                   r->mppe.recvkey ? "R" : "Not r");
1192     prompt_Printf(p, "     MPPE Send Key: %seceived\n",
1193                   r->mppe.sendkey ? "R" : "Not r");
1194     prompt_Printf(p, " MS-CHAP2-Response: %s\n",
1195                   r->msrepstr ? r->msrepstr : "");
1196     prompt_Printf(p, "     Error Message: %s\n", r->errstr ? r->errstr : "");
1197     if (r->routes)
1198       route_ShowSticky(p, r->routes, "            Routes", 16);
1199 #ifndef NOINET6
1200     if (r->ipv6routes)
1201       route_ShowSticky(p, r->ipv6routes, "            IPv6 Routes", 16);
1202 #endif
1203   } else
1204     prompt_Printf(p, " (not authenticated)\n");
1205 }
1206