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  *	$OpenBSD: radius.c,v 1.26 2005/07/17 19:13:25 brad Exp $
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 *
radius_policyname(int policy)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 *
radius_typesname(int types)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
demangle(struct radius * r,const void * mangled,size_t mlen,char ** buf,size_t * len)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   if ((*buf = malloc(*len)) == NULL) {
215     log_Printf(LogWARN, "demangle: Out of memory (%lu bytes)\n", (u_long)*len);
216     *len = 0;
217   } else
218     memcpy(*buf, P + 1, *len);
219 }
220 #endif
221 
222 /*
223  * rad_continue_send_request() has given us `got' (non-zero).  Deal with it.
224  */
225 static void
radius_Process(struct radius * r,int got)226 radius_Process(struct radius *r, int got)
227 {
228   char *argv[MAXARGS], *nuke;
229   struct bundle *bundle;
230   int argc, addrs, res, width;
231   size_t len;
232   struct ncprange dest;
233   struct ncpaddr gw;
234   const void *data;
235   const char *stype;
236   u_int32_t ipaddr, vendor;
237   struct in_addr ip;
238 
239   r->cx.fd = -1;		/* Stop select()ing */
240   stype = r->cx.auth ? "auth" : "acct";
241 
242   switch (got) {
243     case RAD_ACCESS_ACCEPT:
244       log_Printf(LogPHASE, "Radius(%s): ACCEPT received\n", stype);
245       if (!r->cx.auth) {
246         rad_close(r->cx.rad);
247         return;
248       }
249       break;
250 
251     case RAD_ACCESS_REJECT:
252       log_Printf(LogPHASE, "Radius(%s): REJECT received\n", stype);
253       if (!r->cx.auth) {
254         rad_close(r->cx.rad);
255         return;
256       }
257       break;
258 
259     case RAD_ACCESS_CHALLENGE:
260       /* we can't deal with this (for now) ! */
261       log_Printf(LogPHASE, "Radius: CHALLENGE received (can't handle yet)\n");
262       if (r->cx.auth)
263         auth_Failure(r->cx.auth);
264       rad_close(r->cx.rad);
265       return;
266 
267     case RAD_ACCOUNTING_RESPONSE:
268       log_Printf(LogPHASE, "Radius(%s): Accounting response received\n", stype);
269       if (r->cx.auth)
270         auth_Failure(r->cx.auth);		/* unexpected !!! */
271 
272       /* No further processing for accounting requests, please */
273       rad_close(r->cx.rad);
274       return;
275 
276     case -1:
277       log_Printf(LogPHASE, "radius(%s): %s\n", stype, rad_strerror(r->cx.rad));
278       if (r->cx.auth)
279         auth_Failure(r->cx.auth);
280       rad_close(r->cx.rad);
281       return;
282 
283     default:
284       log_Printf(LogERROR, "rad_send_request(%s): Failed %d: %s\n", stype,
285                  got, rad_strerror(r->cx.rad));
286       if (r->cx.auth)
287         auth_Failure(r->cx.auth);
288       rad_close(r->cx.rad);
289       return;
290   }
291 
292   /* Let's see what we've got in our reply */
293   r->ip.s_addr = r->mask.s_addr = INADDR_NONE;
294   r->mtu = 0;
295   r->vj = 0;
296   while ((res = rad_get_attr(r->cx.rad, &data, &len)) > 0) {
297     switch (res) {
298       case RAD_FRAMED_IP_ADDRESS:
299         r->ip = rad_cvt_addr(data);
300         log_Printf(LogPHASE, " IP %s\n", inet_ntoa(r->ip));
301         break;
302 
303       case RAD_FILTER_ID:
304         free(r->filterid);
305         if ((r->filterid = rad_cvt_string(data, len)) == NULL) {
306           log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
307           auth_Failure(r->cx.auth);
308           rad_close(r->cx.rad);
309           return;
310         }
311         log_Printf(LogPHASE, " Filter \"%s\"\n", r->filterid);
312         break;
313 
314       case RAD_SESSION_TIMEOUT:
315         r->sessiontime = rad_cvt_int(data);
316         log_Printf(LogPHASE, " Session-Timeout %lu\n", r->sessiontime);
317         break;
318 
319       case RAD_FRAMED_IP_NETMASK:
320         r->mask = rad_cvt_addr(data);
321         log_Printf(LogPHASE, " Netmask %s\n", inet_ntoa(r->mask));
322         break;
323 
324       case RAD_FRAMED_MTU:
325         r->mtu = rad_cvt_int(data);
326         log_Printf(LogPHASE, " MTU %lu\n", r->mtu);
327         break;
328 
329       case RAD_FRAMED_ROUTING:
330         /* Disabled for now - should we automatically set up some filters ? */
331         /* rad_cvt_int(data); */
332         /* bit 1 = Send routing packets */
333         /* bit 2 = Receive routing packets */
334         break;
335 
336       case RAD_FRAMED_COMPRESSION:
337         r->vj = rad_cvt_int(data) == 1 ? 1 : 0;
338         log_Printf(LogPHASE, " VJ %sabled\n", r->vj ? "en" : "dis");
339         break;
340 
341       case RAD_FRAMED_ROUTE:
342         /*
343          * We expect a string of the format ``dest[/bits] gw [metrics]''
344          * Any specified metrics are ignored.  MYADDR and HISADDR are
345          * understood for ``dest'' and ``gw'' and ``0.0.0.0'' is the same
346          * as ``HISADDR''.
347          */
348 
349         if ((nuke = rad_cvt_string(data, len)) == NULL) {
350           log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
351           auth_Failure(r->cx.auth);
352           rad_close(r->cx.rad);
353           return;
354         }
355 
356         log_Printf(LogPHASE, " Route: %s\n", nuke);
357         bundle = r->cx.auth->physical->dl->bundle;
358         ip.s_addr = INADDR_ANY;
359         ncprange_setip4host(&dest, ip);
360         argc = command_Interpret(nuke, strlen(nuke), argv);
361         if (argc < 0)
362           log_Printf(LogWARN, "radius: %s: Syntax error\n",
363                      argc == 1 ? argv[0] : "\"\"");
364         else if (argc < 2)
365           log_Printf(LogWARN, "radius: %s: Invalid route\n",
366                      argc == 1 ? argv[0] : "\"\"");
367         else if ((strcasecmp(argv[0], "default") != 0 &&
368                   !ncprange_aton(&dest, &bundle->ncp, argv[0])) ||
369                  !ncpaddr_aton(&gw, &bundle->ncp, argv[1]))
370           log_Printf(LogWARN, "radius: %s %s: Invalid route\n",
371                      argv[0], argv[1]);
372         else {
373           ncprange_getwidth(&dest, &width);
374           if (width == 32 && strchr(argv[0], '/') == NULL) {
375             /* No mask specified - use the natural mask */
376             ncprange_getip4addr(&dest, &ip);
377             ncprange_setip4mask(&dest, addr2mask(ip));
378           }
379           addrs = 0;
380 
381           if (!strncasecmp(argv[0], "HISADDR", 7))
382             addrs = ROUTE_DSTHISADDR;
383           else if (!strncasecmp(argv[0], "MYADDR", 6))
384             addrs = ROUTE_DSTMYADDR;
385 
386           if (ncpaddr_getip4addr(&gw, &ipaddr) && ipaddr == INADDR_ANY) {
387             addrs |= ROUTE_GWHISADDR;
388             ncpaddr_setip4(&gw, bundle->ncp.ipcp.peer_ip);
389           } else if (strcasecmp(argv[1], "HISADDR") == 0)
390             addrs |= ROUTE_GWHISADDR;
391 
392           route_Add(&r->routes, addrs, &dest, &gw);
393         }
394         free(nuke);
395         break;
396 
397       case RAD_REPLY_MESSAGE:
398         free(r->repstr);
399         if ((r->repstr = rad_cvt_string(data, len)) == NULL) {
400           log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
401           auth_Failure(r->cx.auth);
402           rad_close(r->cx.rad);
403           return;
404         }
405         log_Printf(LogPHASE, " Reply-Message \"%s\"\n", r->repstr);
406         break;
407 
408       case RAD_VENDOR_SPECIFIC:
409         if ((res = rad_get_vendor_attr(&vendor, &data, &len)) <= 0) {
410           log_Printf(LogERROR, "rad_get_vendor_attr: %s (failing!)\n",
411                      rad_strerror(r->cx.rad));
412           auth_Failure(r->cx.auth);
413           rad_close(r->cx.rad);
414           return;
415         }
416 
417 	switch (vendor) {
418           case RAD_VENDOR_MICROSOFT:
419             switch (res) {
420 #ifndef NODES
421               case RAD_MICROSOFT_MS_CHAP_ERROR:
422                 free(r->errstr);
423                 if (len == 0)
424                   r->errstr = NULL;
425                 else {
426                   if (len < 3 || ((const char *)data)[1] != '=') {
427                     /*
428                      * Only point at the String field if we don't think the
429                      * peer has misformatted the response.
430                      */
431 		    const char *foo = (const char *)data + 1;
432                     data = (const void *)foo;
433                     len--;
434                   } else
435                     log_Printf(LogWARN, "Warning: The MS-CHAP-Error "
436                                "attribute is mis-formatted.  Compensating\n");
437                   if ((r->errstr = rad_cvt_string((const char *)data,
438                                                   len)) == NULL) {
439                     log_Printf(LogERROR, "rad_cvt_string: %s\n",
440                                rad_strerror(r->cx.rad));
441                     auth_Failure(r->cx.auth);
442                     rad_close(r->cx.rad);
443                     return;
444                   }
445                   log_Printf(LogPHASE, " MS-CHAP-Error \"%s\"\n", r->errstr);
446                 }
447                 break;
448 
449               case RAD_MICROSOFT_MS_CHAP2_SUCCESS:
450                 free(r->msrepstr);
451                 if (len == 0)
452                   r->msrepstr = NULL;
453                 else {
454                   if (len < 3 || ((const char *)data)[1] != '=') {
455                     /*
456                      * Only point at the String field if we don't think the
457                      * peer has misformatted the response.
458                      */
459 		    const char *foo = (const char *)data + 1;
460                     data = (const void *)foo;
461                     len--;
462                   } else
463                     log_Printf(LogWARN, "Warning: The MS-CHAP2-Success "
464                                "attribute is mis-formatted.  Compensating\n");
465                   if ((r->msrepstr = rad_cvt_string((const char *)data,
466                                                     len)) == NULL) {
467                     log_Printf(LogERROR, "rad_cvt_string: %s\n",
468                                rad_strerror(r->cx.rad));
469                     auth_Failure(r->cx.auth);
470                     rad_close(r->cx.rad);
471                     return;
472                   }
473                   log_Printf(LogPHASE, " MS-CHAP2-Success \"%s\"\n",
474                              r->msrepstr);
475                 }
476                 break;
477 
478               case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY:
479                 r->mppe.policy = rad_cvt_int(data);
480                 log_Printf(LogPHASE, " MS-MPPE-Encryption-Policy %s\n",
481                            radius_policyname(r->mppe.policy));
482                 break;
483 
484               case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES:
485                 r->mppe.types = rad_cvt_int(data);
486                 log_Printf(LogPHASE, " MS-MPPE-Encryption-Types %s\n",
487                            radius_typesname(r->mppe.types));
488                 break;
489 
490               case RAD_MICROSOFT_MS_MPPE_RECV_KEY:
491                 free(r->mppe.recvkey);
492 		demangle(r, data, len, &r->mppe.recvkey, &r->mppe.recvkeylen);
493                 log_Printf(LogPHASE, " MS-MPPE-Recv-Key ********\n");
494                 break;
495 
496               case RAD_MICROSOFT_MS_MPPE_SEND_KEY:
497 		demangle(r, data, len, &r->mppe.sendkey, &r->mppe.sendkeylen);
498                 log_Printf(LogPHASE, " MS-MPPE-Send-Key ********\n");
499                 break;
500 #endif
501 
502               default:
503                 log_Printf(LogDEBUG, "Dropping MICROSOFT vendor specific "
504                            "RADIUS attribute %d\n", res);
505                 break;
506             }
507             break;
508 
509           default:
510             log_Printf(LogDEBUG, "Dropping vendor %lu RADIUS attribute %d\n",
511                        (unsigned long)vendor, res);
512             break;
513         }
514         break;
515 
516       default:
517         log_Printf(LogDEBUG, "Dropping RADIUS attribute %d\n", res);
518         break;
519     }
520   }
521 
522   if (res == -1) {
523     log_Printf(LogERROR, "rad_get_attr: %s (failing!)\n",
524                rad_strerror(r->cx.rad));
525     auth_Failure(r->cx.auth);
526   } else if (got == RAD_ACCESS_REJECT)
527     auth_Failure(r->cx.auth);
528   else {
529     r->valid = 1;
530     auth_Success(r->cx.auth);
531   }
532   rad_close(r->cx.rad);
533 }
534 
535 /*
536  * We've either timed out or select()ed on the read descriptor
537  */
538 static void
radius_Continue(struct radius * r,int sel)539 radius_Continue(struct radius *r, int sel)
540 {
541   struct timeval tv;
542   int got;
543 
544   timer_Stop(&r->cx.timer);
545   if ((got = rad_continue_send_request(r->cx.rad, sel, &r->cx.fd, &tv)) == 0) {
546     log_Printf(LogPHASE, "Radius: Request re-sent\n");
547     r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
548     timer_Start(&r->cx.timer);
549     return;
550   }
551 
552   radius_Process(r, got);
553 }
554 
555 /*
556  * Time to call rad_continue_send_request() - timed out.
557  */
558 static void
radius_Timeout(void * v)559 radius_Timeout(void *v)
560 {
561   radius_Continue((struct radius *)v, 0);
562 }
563 
564 /*
565  * Time to call rad_continue_send_request() - something to read.
566  */
567 static void
radius_Read(struct fdescriptor * d,struct bundle * bundle,const fd_set * fdset)568 radius_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
569 {
570   radius_Continue(descriptor2radius(d), 1);
571 }
572 
573 /*
574  * Behave as a struct fdescriptor (descriptor.h)
575  */
576 static int
radius_UpdateSet(struct fdescriptor * d,fd_set * r,fd_set * w,fd_set * e,int * n)577 radius_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
578 {
579   struct radius *rad = descriptor2radius(d);
580 
581   if (r && rad->cx.fd != -1) {
582     FD_SET(rad->cx.fd, r);
583     if (*n < rad->cx.fd + 1)
584       *n = rad->cx.fd + 1;
585     log_Printf(LogTIMER, "Radius: fdset(r) %d\n", rad->cx.fd);
586     return 1;
587   }
588 
589   return 0;
590 }
591 
592 /*
593  * Behave as a struct fdescriptor (descriptor.h)
594  */
595 static int
radius_IsSet(struct fdescriptor * d,const fd_set * fdset)596 radius_IsSet(struct fdescriptor *d, const fd_set *fdset)
597 {
598   struct radius *r = descriptor2radius(d);
599 
600   return r && r->cx.fd != -1 && FD_ISSET(r->cx.fd, fdset);
601 }
602 
603 /*
604  * Behave as a struct fdescriptor (descriptor.h)
605  */
606 static int
radius_Write(struct fdescriptor * d,struct bundle * bundle,const fd_set * fdset)607 radius_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
608 {
609   /* We never want to write here ! */
610   log_Printf(LogALERT, "radius_Write: Internal error: Bad call !\n");
611   return 0;
612 }
613 
614 /*
615  * Initialise ourselves
616  */
617 void
radius_Init(struct radius * r)618 radius_Init(struct radius *r)
619 {
620   r->desc.type = RADIUS_DESCRIPTOR;
621   r->desc.UpdateSet = radius_UpdateSet;
622   r->desc.IsSet = radius_IsSet;
623   r->desc.Read = radius_Read;
624   r->desc.Write = radius_Write;
625   r->cx.fd = -1;
626   r->cx.rad = NULL;
627   memset(&r->cx.timer, '\0', sizeof r->cx.timer);
628   r->cx.auth = NULL;
629   r->valid = 0;
630   r->vj = 0;
631   r->ip.s_addr = INADDR_ANY;
632   r->mask.s_addr = INADDR_NONE;
633   r->routes = NULL;
634   r->mtu = DEF_MTU;
635   r->msrepstr = NULL;
636   r->repstr = NULL;
637   r->errstr = NULL;
638   r->mppe.policy = 0;
639   r->mppe.types = 0;
640   r->mppe.recvkey = NULL;
641   r->mppe.recvkeylen = 0;
642   r->mppe.sendkey = NULL;
643   r->mppe.sendkeylen = 0;
644   *r->cfg.file = '\0';
645   log_Printf(LogDEBUG, "Radius: radius_Init\n");
646 }
647 
648 /*
649  * Forget everything and go back to initialised state.
650  */
651 void
radius_Destroy(struct radius * r)652 radius_Destroy(struct radius *r)
653 {
654   r->valid = 0;
655   log_Printf(LogDEBUG, "Radius: radius_Destroy\n");
656   timer_Stop(&r->cx.timer);
657   route_DeleteAll(&r->routes);
658   free(r->filterid);
659   r->filterid = NULL;
660   free(r->msrepstr);
661   r->msrepstr = NULL;
662   free(r->repstr);
663   r->repstr = NULL;
664   free(r->errstr);
665   r->errstr = NULL;
666   free(r->mppe.recvkey);
667   r->mppe.recvkey = NULL;
668   r->mppe.recvkeylen = 0;
669   free(r->mppe.sendkey);
670   r->mppe.sendkey = NULL;
671   r->mppe.sendkeylen = 0;
672   if (r->cx.fd != -1) {
673     r->cx.fd = -1;
674     rad_close(r->cx.rad);
675   }
676 }
677 
678 static int
radius_put_physical_details(struct rad_handle * rad,struct physical * p)679 radius_put_physical_details(struct rad_handle *rad, struct physical *p)
680 {
681   int slot, type;
682 
683   type = RAD_VIRTUAL;
684   if (p->handler)
685     switch (p->handler->type) {
686       case I4B_DEVICE:
687         type = RAD_ISDN_SYNC;
688         break;
689 
690       case TTY_DEVICE:
691         type = RAD_ASYNC;
692         break;
693 
694       case ETHER_DEVICE:
695         type = RAD_ETHERNET;
696         break;
697 
698       case TCP_DEVICE:
699       case UDP_DEVICE:
700       case EXEC_DEVICE:
701       case ATM_DEVICE:
702       case NG_DEVICE:
703         type = RAD_VIRTUAL;
704         break;
705     }
706 
707   if (rad_put_int(rad, RAD_NAS_PORT_TYPE, type) != 0) {
708     log_Printf(LogERROR, "rad_put: rad_put_int: %s\n", rad_strerror(rad));
709     rad_close(rad);
710     return 0;
711   }
712 
713   if ((slot = physical_Slot(p)) >= 0)
714     if (rad_put_int(rad, RAD_NAS_PORT, slot) != 0) {
715       log_Printf(LogERROR, "rad_put: rad_put_int: %s\n", rad_strerror(rad));
716       rad_close(rad);
717       return 0;
718     }
719 
720   return 1;
721 }
722 
723 /*
724  * Start an authentication request to the RADIUS server.
725  */
726 int
radius_Authenticate(struct radius * r,struct authinfo * authp,const char * name,const char * key,int klen,const char * nchallenge,int nclen)727 radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name,
728                     const char *key, int klen, const char *nchallenge,
729                     int nclen)
730 {
731   struct timeval tv;
732   int got;
733   char hostname[MAXHOSTNAMELEN];
734 #if 0
735   struct hostent *hp;
736   struct in_addr hostaddr;
737 #endif
738 #ifndef NODES
739   struct mschap_response msresp;
740   struct mschap2_response msresp2;
741   const struct MSCHAPv2_resp *keyv2;
742 #endif
743 
744   if (!*r->cfg.file)
745     return 0;
746 
747   if (r->cx.fd != -1)
748     /*
749      * We assume that our name/key/challenge is the same as last time,
750      * and just continue to wait for the RADIUS server(s).
751      */
752     return 1;
753 
754   radius_Destroy(r);
755 
756   if ((r->cx.rad = rad_auth_open()) == NULL) {
757     log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno));
758     return 0;
759   }
760 
761   if (rad_config(r->cx.rad, r->cfg.file) != 0) {
762     log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad));
763     rad_close(r->cx.rad);
764     return 0;
765   }
766 
767   if (rad_create_request(r->cx.rad, RAD_ACCESS_REQUEST) != 0) {
768     log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad));
769     rad_close(r->cx.rad);
770     return 0;
771   }
772 
773   if (rad_put_string(r->cx.rad, RAD_USER_NAME, name) != 0 ||
774       rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 ||
775       rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) {
776     log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
777     rad_close(r->cx.rad);
778     return 0;
779   }
780 
781   switch (authp->physical->link.lcp.want_auth) {
782   case PROTO_PAP:
783     /* We're talking PAP */
784     if (rad_put_attr(r->cx.rad, RAD_USER_PASSWORD, key, klen) != 0) {
785       log_Printf(LogERROR, "PAP: rad_put_string: %s\n",
786                  rad_strerror(r->cx.rad));
787       rad_close(r->cx.rad);
788       return 0;
789     }
790     break;
791 
792   case PROTO_CHAP:
793     switch (authp->physical->link.lcp.want_authtype) {
794     case 0x5:
795       if (rad_put_attr(r->cx.rad, RAD_CHAP_PASSWORD, key, klen) != 0 ||
796           rad_put_attr(r->cx.rad, RAD_CHAP_CHALLENGE, nchallenge, nclen) != 0) {
797         log_Printf(LogERROR, "CHAP: rad_put_string: %s\n",
798                    rad_strerror(r->cx.rad));
799         rad_close(r->cx.rad);
800         return 0;
801       }
802       break;
803 
804 #ifndef NODES
805     case 0x80:
806       if (klen != 50) {
807         log_Printf(LogERROR, "CHAP80: Unrecognised key length %d\n", klen);
808         rad_close(r->cx.rad);
809         return 0;
810       }
811 
812       rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT,
813                           RAD_MICROSOFT_MS_CHAP_CHALLENGE, nchallenge, nclen);
814       msresp.ident = *key;
815       msresp.flags = 0x01;
816       memcpy(msresp.lm_response, key + 1, 24);
817       memcpy(msresp.nt_response, key + 25, 24);
818       rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT,
819                           RAD_MICROSOFT_MS_CHAP_RESPONSE, &msresp,
820                           sizeof msresp);
821       break;
822 
823     case 0x81:
824       if (klen != sizeof(*keyv2) + 1) {
825         log_Printf(LogERROR, "CHAP81: Unrecognised key length %d\n", klen);
826         rad_close(r->cx.rad);
827         return 0;
828       }
829 
830       keyv2 = (const struct MSCHAPv2_resp *)(key + 1);
831       rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT,
832                           RAD_MICROSOFT_MS_CHAP_CHALLENGE, nchallenge, nclen);
833       msresp2.ident = *key;
834       msresp2.flags = keyv2->Flags;
835       memcpy(msresp2.response, keyv2->NTResponse, sizeof msresp2.response);
836       memset(msresp2.reserved, '\0', sizeof msresp2.reserved);
837       memcpy(msresp2.pchallenge, keyv2->PeerChallenge,
838              sizeof msresp2.pchallenge);
839       rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT,
840                           RAD_MICROSOFT_MS_CHAP2_RESPONSE, &msresp2,
841                           sizeof msresp2);
842       break;
843 #endif
844     default:
845       log_Printf(LogERROR, "CHAP: Unrecognised type 0x%02x\n",
846                  authp->physical->link.lcp.want_authtype);
847       rad_close(r->cx.rad);
848       return 0;
849     }
850   }
851 
852   if (gethostname(hostname, sizeof hostname) != 0)
853     log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno));
854   else {
855 #if 0
856     if ((hp = gethostbyname(hostname)) != NULL) {
857       hostaddr.s_addr = *(u_long *)hp->h_addr;
858       if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) {
859         log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
860                    rad_strerror(r->cx.rad));
861         rad_close(r->cx.rad);
862         return 0;
863       }
864     }
865 #endif
866     if (rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) {
867       log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
868                  rad_strerror(r->cx.rad));
869       rad_close(r->cx.rad);
870       return 0;
871     }
872   }
873 
874   radius_put_physical_details(r->cx.rad, authp->physical);
875 
876   r->cx.auth = authp;
877   if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv)))
878     radius_Process(r, got);
879   else {
880     log_Printf(LogPHASE, "Radius: Request sent\n");
881     log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout);
882     r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
883     r->cx.timer.func = radius_Timeout;
884     r->cx.timer.name = "radius auth";
885     r->cx.timer.arg = r;
886     timer_Start(&r->cx.timer);
887   }
888 
889   return 1;
890 }
891 
892 /*
893  * Send an accounting request to the RADIUS server
894  */
895 void
radius_Account(struct radius * r,struct radacct * ac,struct datalink * dl,int acct_type,struct in_addr * peer_ip,struct in_addr * netmask,struct pppThroughput * stats)896 radius_Account(struct radius *r, struct radacct *ac, struct datalink *dl,
897                int acct_type, struct in_addr *peer_ip, struct in_addr *netmask,
898                struct pppThroughput *stats)
899 {
900   struct timeval tv;
901   int got;
902   char hostname[MAXHOSTNAMELEN];
903 #if 0
904   struct hostent *hp;
905   struct in_addr hostaddr;
906 #endif
907 
908   if (!*r->cfg.file)
909     return;
910 
911   if (r->cx.fd != -1)
912     /*
913      * We assume that our name/key/challenge is the same as last time,
914      * and just continue to wait for the RADIUS server(s).
915      */
916     return;
917 
918   timer_Stop(&r->cx.timer);
919 
920   if ((r->cx.rad = rad_acct_open()) == NULL) {
921     log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno));
922     return;
923   }
924 
925   if (rad_config(r->cx.rad, r->cfg.file) != 0) {
926     log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad));
927     rad_close(r->cx.rad);
928     return;
929   }
930 
931   if (rad_create_request(r->cx.rad, RAD_ACCOUNTING_REQUEST) != 0) {
932     log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad));
933     rad_close(r->cx.rad);
934     return;
935   }
936 
937   /* Grab some accounting data and initialize structure */
938   if (acct_type == RAD_START) {
939     ac->rad_parent = r;
940     /* Fetch username from datalink */
941     strncpy(ac->user_name, dl->peer.authname, sizeof ac->user_name);
942     ac->user_name[AUTHLEN-1] = '\0';
943 
944     ac->authentic = 2;		/* Assume RADIUS verified auth data */
945 
946     /* Generate a session ID */
947     snprintf(ac->session_id, sizeof ac->session_id, "%s%ld-%s%lu",
948              dl->bundle->cfg.auth.name, (long)getpid(),
949              dl->peer.authname, (unsigned long)stats->uptime);
950 
951     /* And grab our MP socket name */
952     snprintf(ac->multi_session_id, sizeof ac->multi_session_id, "%s",
953              dl->bundle->ncp.mp.active ?
954              dl->bundle->ncp.mp.server.socket.sun_path : "");
955 
956     /* Fetch IP, netmask from IPCP */
957     memcpy(&ac->ip, peer_ip, sizeof(ac->ip));
958     memcpy(&ac->mask, netmask, sizeof(ac->mask));
959   };
960 
961   if (rad_put_string(r->cx.rad, RAD_USER_NAME, ac->user_name) != 0 ||
962       rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 ||
963       rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0 ||
964       rad_put_addr(r->cx.rad, RAD_FRAMED_IP_ADDRESS, ac->ip) != 0 ||
965       rad_put_addr(r->cx.rad, RAD_FRAMED_IP_NETMASK, ac->mask) != 0) {
966     log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
967     rad_close(r->cx.rad);
968     return;
969   }
970 
971   if (gethostname(hostname, sizeof hostname) != 0)
972     log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno));
973   else {
974 #if 0
975     if ((hp = gethostbyname(hostname)) != NULL) {
976       hostaddr.s_addr = *(u_long *)hp->h_addr;
977       if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) {
978         log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
979                    rad_strerror(r->cx.rad));
980         rad_close(r->cx.rad);
981         return;
982       }
983     }
984 #endif
985     if (rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) {
986       log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
987                  rad_strerror(r->cx.rad));
988       rad_close(r->cx.rad);
989       return;
990     }
991   }
992 
993   radius_put_physical_details(r->cx.rad, dl->physical);
994 
995   if (rad_put_int(r->cx.rad, RAD_ACCT_STATUS_TYPE, acct_type) != 0 ||
996       rad_put_string(r->cx.rad, RAD_ACCT_SESSION_ID, ac->session_id) != 0 ||
997       rad_put_string(r->cx.rad, RAD_ACCT_MULTI_SESSION_ID,
998                      ac->multi_session_id) != 0 ||
999       rad_put_int(r->cx.rad, RAD_ACCT_DELAY_TIME, 0) != 0) {
1000 /* XXX ACCT_DELAY_TIME should be increased each time a packet is waiting */
1001     log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
1002     rad_close(r->cx.rad);
1003     return;
1004   }
1005 
1006   if (acct_type == RAD_STOP)
1007   /* Show some statistics */
1008     if (rad_put_int(r->cx.rad, RAD_ACCT_INPUT_OCTETS, stats->OctetsIn) != 0 ||
1009         rad_put_int(r->cx.rad, RAD_ACCT_INPUT_PACKETS, stats->PacketsIn) != 0 ||
1010         rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_OCTETS, stats->OctetsOut) != 0 ||
1011         rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_PACKETS, stats->PacketsOut)
1012         != 0 ||
1013         rad_put_int(r->cx.rad, RAD_ACCT_SESSION_TIME, throughput_uptime(stats))
1014         != 0) {
1015       log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
1016       rad_close(r->cx.rad);
1017       return;
1018     }
1019 
1020   r->cx.auth = NULL;			/* Not valid for accounting requests */
1021   if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv)))
1022     radius_Process(r, got);
1023   else {
1024     log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout);
1025     r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
1026     r->cx.timer.func = radius_Timeout;
1027     r->cx.timer.name = "radius acct";
1028     r->cx.timer.arg = r;
1029     timer_Start(&r->cx.timer);
1030   }
1031 }
1032 
1033 /*
1034  * How do things look at the moment ?
1035  */
1036 void
radius_Show(struct radius * r,struct prompt * p)1037 radius_Show(struct radius *r, struct prompt *p)
1038 {
1039   prompt_Printf(p, " Radius config:     %s",
1040                 *r->cfg.file ? r->cfg.file : "none");
1041   if (r->valid) {
1042     prompt_Printf(p, "\n                IP: %s\n", inet_ntoa(r->ip));
1043     prompt_Printf(p, "           Netmask: %s\n", inet_ntoa(r->mask));
1044     prompt_Printf(p, "               MTU: %lu\n", r->mtu);
1045     prompt_Printf(p, "                VJ: %sabled\n", r->vj ? "en" : "dis");
1046     prompt_Printf(p, "           Message: %s\n", r->repstr ? r->repstr : "");
1047     prompt_Printf(p, "   MPPE Enc Policy: %s\n",
1048                   radius_policyname(r->mppe.policy));
1049     prompt_Printf(p, "    MPPE Enc Types: %s\n",
1050                   radius_typesname(r->mppe.types));
1051     prompt_Printf(p, "     MPPE Recv Key: %seceived\n",
1052                   r->mppe.recvkey ? "R" : "Not r");
1053     prompt_Printf(p, "     MPPE Send Key: %seceived\n",
1054                   r->mppe.sendkey ? "R" : "Not r");
1055     prompt_Printf(p, " MS-CHAP2-Response: %s\n",
1056                   r->msrepstr ? r->msrepstr : "");
1057     prompt_Printf(p, "     Error Message: %s\n", r->errstr ? r->errstr : "");
1058     if (r->routes)
1059       route_ShowSticky(p, r->routes, "            Routes", 16);
1060   } else
1061     prompt_Printf(p, " (not authenticated)\n");
1062 }
1063