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