]> git.ozlabs.org Git - ppp.git/blob - pppd/plugins/radius/radius.c
67d18fdea774048b30aca9835ae826c82e03225c
[ppp.git] / pppd / plugins / radius / radius.c
1 /***********************************************************************
2 *
3 * radius.c
4 *
5 * RADIUS plugin for pppd.  Performs PAP, CHAP, MS-CHAP, MS-CHAPv2
6 * authentication using RADIUS.
7 *
8 * Copyright (C) 2002 Roaring Penguin Software Inc.
9 *
10 * Based on a patch for ipppd, which is:
11 *    Copyright (C) 1996, Matjaz Godec <gody@elgo.si>
12 *    Copyright (C) 1996, Lars Fenneberg <in5y050@public.uni-hamburg.de>
13 *    Copyright (C) 1997, Miguel A.L. Paraz <map@iphil.net>
14 *
15 * Uses radiusclient library, which is:
16 *    Copyright (C) 1995,1996,1997,1998 Lars Fenneberg <lf@elemental.net>
17 *    Copyright (C) 2002 Roaring Penguin Software Inc.
18 *
19 * MPPE support is by Ralf Hofmann, <ralf.hofmann@elvido.net>, with
20 * modification from Frank Cusack, <frank@google.com>.
21 *
22 * This plugin may be distributed according to the terms of the GNU
23 * General Public License, version 2 or (at your option) any later version.
24 *
25 ***********************************************************************/
26 static char const RCSID[] =
27 "$Id: radius.c,v 1.23 2004/03/26 13:27:17 kad Exp $";
28
29 #include "pppd.h"
30 #include "chap-new.h"
31 #ifdef CHAPMS
32 #include "chap_ms.h"
33 #ifdef MPPE
34 #include "md5.h"
35 #endif
36 #endif
37 #include "radiusclient.h"
38 #include "fsm.h"
39 #include "ipcp.h"
40 #include <syslog.h>
41 #include <sys/types.h>
42 #include <sys/time.h>
43 #include <string.h>
44
45 #define BUF_LEN 1024
46
47 #define MD5_HASH_SIZE   16
48
49 static char *config_file = NULL;
50 static int add_avp(char **);
51 static struct avpopt {
52     char *vpstr;
53     struct avpopt *next;
54 } *avpopt = NULL;
55 static bool portnummap = 0;
56
57 static option_t Options[] = {
58     { "radius-config-file", o_string, &config_file },
59     { "avpair", o_special, add_avp },
60     { "map-to-ttyname", o_bool, &portnummap,
61         "Set Radius NAS-Port attribute value via libradiusclient library", OPT_PRIO | 1 },
62     { "map-to-ifname", o_bool, &portnummap,
63         "Set Radius NAS-Port attribute to number as in interface name (Default)", OPT_PRIOSUB | 0 },
64     { NULL }
65 };
66
67 static int radius_secret_check(void);
68 static int radius_pap_auth(char *user,
69                            char *passwd,
70                            char **msgp,
71                            struct wordlist **paddrs,
72                            struct wordlist **popts);
73 static int radius_chap_verify(char *user, char *ourname, int id,
74                               struct chap_digest_type *digest,
75                               unsigned char *challenge,
76                               unsigned char *response,
77                               unsigned char *message, int message_space);
78
79 static void radius_ip_up(void *opaque, int arg);
80 static void radius_ip_down(void *opaque, int arg);
81 static void make_username_realm(char *user);
82 static int radius_setparams(VALUE_PAIR *vp, char *msg, REQUEST_INFO *req_info,
83                             struct chap_digest_type *digest,
84                             unsigned char *challenge,
85                             char *message, int message_space);
86 static void radius_choose_ip(u_int32_t *addrp);
87 static int radius_init(char *msg);
88 static int get_client_port(char *ifname);
89 static int radius_allowed_address(u_int32_t addr);
90 static void radius_acct_interim(void *);
91 #ifdef MPPE
92 static int radius_setmppekeys(VALUE_PAIR *vp, REQUEST_INFO *req_info,
93                               unsigned char *);
94 static int radius_setmppekeys2(VALUE_PAIR *vp, REQUEST_INFO *req_info);
95 #endif
96
97 #ifndef MAXSESSIONID
98 #define MAXSESSIONID 32
99 #endif
100
101 #ifndef MAXCLASSLEN
102 #define MAXCLASSLEN 500
103 #endif
104
105 struct radius_state {
106     int accounting_started;
107     int initialized;
108     int client_port;
109     int choose_ip;
110     int any_ip_addr_ok;
111     int done_chap_once;
112     u_int32_t ip_addr;
113     char user[MAXNAMELEN];
114     char config_file[MAXPATHLEN];
115     char session_id[MAXSESSIONID + 1];
116     time_t start_time;
117     int acct_interim_interval;
118     SERVER *authserver;         /* Authentication server to use */
119     SERVER *acctserver;         /* Accounting server to use */
120     int class_len;
121     char class[MAXCLASSLEN];
122     VALUE_PAIR *avp;    /* Additional (user supplied) vp's to send to server */
123 };
124
125 void (*radius_attributes_hook)(VALUE_PAIR *) = NULL;
126
127 /* The pre_auth_hook MAY set authserver and acctserver if it wants.
128    In that case, they override the values in the radiusclient.conf file */
129 void (*radius_pre_auth_hook)(char const *user,
130                              SERVER **authserver,
131                              SERVER **acctserver) = NULL;
132
133 static struct radius_state rstate;
134
135 char pppd_version[] = VERSION;
136
137 /**********************************************************************
138 * %FUNCTION: plugin_init
139 * %ARGUMENTS:
140 *  None
141 * %RETURNS:
142 *  Nothing
143 * %DESCRIPTION:
144 *  Initializes RADIUS plugin.
145 ***********************************************************************/
146 void
147 plugin_init(void)
148 {
149     pap_check_hook = radius_secret_check;
150     pap_auth_hook = radius_pap_auth;
151
152     chap_check_hook = radius_secret_check;
153     chap_verify_hook = radius_chap_verify;
154
155     ip_choose_hook = radius_choose_ip;
156     allowed_address_hook = radius_allowed_address;
157
158     add_notifier(&ip_up_notifier, radius_ip_up, NULL);
159     add_notifier(&ip_down_notifier, radius_ip_down, NULL);
160
161     memset(&rstate, 0, sizeof(rstate));
162
163     strlcpy(rstate.config_file, "/etc/radiusclient/radiusclient.conf",
164             sizeof(rstate.config_file));
165
166     add_options(Options);
167
168     info("RADIUS plugin initialized.");
169 }
170
171 /**********************************************************************
172 * %FUNCTION: add_avp
173 * %ARGUMENTS:
174 *  argv -- the <attribute=value> pair to add
175 * %RETURNS:
176 *  1
177 * %DESCRIPTION:
178 *  Adds an av pair to be passed on to the RADIUS server on each request.
179 ***********************************************************************/
180 static int
181 add_avp(char **argv)
182 {
183     struct avpopt *p = malloc(sizeof(struct avpopt));
184
185     /* Append to a list of vp's for later parsing */
186     p->vpstr = strdup(*argv);
187     p->next = avpopt;
188     avpopt = p;
189
190     return 1;
191 }
192
193 /**********************************************************************
194 * %FUNCTION: radius_secret_check
195 * %ARGUMENTS:
196 *  None
197 * %RETURNS:
198 *  1 -- we are ALWAYS willing to supply a secret. :-)
199 * %DESCRIPTION:
200 * Tells pppd that we will try to authenticate the peer, and not to
201 * worry about looking in /etc/ppp/*-secrets
202 ***********************************************************************/
203 static int
204 radius_secret_check(void)
205 {
206     return 1;
207 }
208
209 /**********************************************************************
210 * %FUNCTION: radius_choose_ip
211 * %ARGUMENTS:
212 *  addrp -- where to store the IP address
213 * %RETURNS:
214 *  Nothing
215 * %DESCRIPTION:
216 *  If RADIUS server has specified an IP address, it is stored in *addrp.
217 ***********************************************************************/
218 static void
219 radius_choose_ip(u_int32_t *addrp)
220 {
221     if (rstate.choose_ip) {
222         *addrp = rstate.ip_addr;
223     }
224 }
225
226 /**********************************************************************
227 * %FUNCTION: radius_pap_auth
228 * %ARGUMENTS:
229 *  user -- user-name of peer
230 *  passwd -- password supplied by peer
231 *  msgp -- Message which will be sent in PAP response
232 *  paddrs -- set to a list of possible peer IP addresses
233 *  popts -- set to a list of additional pppd options
234 * %RETURNS:
235 *  1 if we can authenticate, -1 if we cannot.
236 * %DESCRIPTION:
237 * Performs PAP authentication using RADIUS
238 ***********************************************************************/
239 static int
240 radius_pap_auth(char *user,
241                 char *passwd,
242                 char **msgp,
243                 struct wordlist **paddrs,
244                 struct wordlist **popts)
245 {
246     VALUE_PAIR *send, *received;
247     UINT4 av_type;
248     int result;
249     static char radius_msg[BUF_LEN];
250
251     radius_msg[0] = 0;
252     *msgp = radius_msg;
253
254     if (radius_init(radius_msg) < 0) {
255         return 0;
256     }
257
258     /* Put user with potentially realm added in rstate.user */
259     make_username_realm(user);
260
261     if (radius_pre_auth_hook) {
262         radius_pre_auth_hook(rstate.user,
263                              &rstate.authserver,
264                              &rstate.acctserver);
265     }
266
267     send = NULL;
268     received = NULL;
269
270     /* Hack... the "port" is the ppp interface number.  Should really be
271        the tty */
272     rstate.client_port = get_client_port(portnummap ? devnam : ifname);
273
274     av_type = PW_FRAMED;
275     rc_avpair_add(&send, PW_SERVICE_TYPE, &av_type, 0, VENDOR_NONE);
276
277     av_type = PW_PPP;
278     rc_avpair_add(&send, PW_FRAMED_PROTOCOL, &av_type, 0, VENDOR_NONE);
279
280     rc_avpair_add(&send, PW_USER_NAME, rstate.user , 0, VENDOR_NONE);
281     rc_avpair_add(&send, PW_USER_PASSWORD, passwd, 0, VENDOR_NONE);
282     if (*remote_number) {
283         rc_avpair_add(&send, PW_CALLING_STATION_ID, remote_number, 0,
284                        VENDOR_NONE);
285     }
286
287     /* Add user specified vp's */
288     if (rstate.avp)
289         rc_avpair_insert(&send, NULL, rc_avpair_copy(rstate.avp));
290
291     if (rstate.authserver) {
292         result = rc_auth_using_server(rstate.authserver,
293                                       rstate.client_port, send,
294                                       &received, radius_msg, NULL);
295     } else {
296         result = rc_auth(rstate.client_port, send, &received, radius_msg, NULL);
297     }
298
299     if (result == OK_RC) {
300         if (radius_setparams(received, radius_msg, NULL, NULL, NULL, NULL, 0) < 0) {
301             result = ERROR_RC;
302         }
303     }
304
305     /* free value pairs */
306     rc_avpair_free(received);
307     rc_avpair_free(send);
308
309     return (result == OK_RC) ? 1 : 0;
310 }
311
312 /**********************************************************************
313 * %FUNCTION: radius_chap_verify
314 * %ARGUMENTS:
315 *  user -- name of the peer
316 *  ourname -- name for this machine
317 *  id -- the ID byte in the challenge
318 *  digest -- points to the structure representing the digest type
319 *  challenge -- the challenge string we sent (length in first byte)
320 *  response -- the response (hash) the peer sent back (length in 1st byte)
321 *  message -- space for a message to be returned to the peer
322 *  message_space -- number of bytes available at *message.
323 * %RETURNS:
324 *  1 if the response is good, 0 if it is bad
325 * %DESCRIPTION:
326 * Performs CHAP, MS-CHAP and MS-CHAPv2 authentication using RADIUS.
327 ***********************************************************************/
328 static int
329 radius_chap_verify(char *user, char *ourname, int id,
330                    struct chap_digest_type *digest,
331                    unsigned char *challenge, unsigned char *response,
332                    unsigned char *message, int message_space)
333 {
334     VALUE_PAIR *send, *received;
335     UINT4 av_type;
336     static char radius_msg[BUF_LEN];
337     int result;
338     int challenge_len, response_len;
339     u_char cpassword[MAX_RESPONSE_LEN + 1];
340 #ifdef MPPE
341     /* Need the RADIUS secret and Request Authenticator to decode MPPE */
342     REQUEST_INFO request_info, *req_info = &request_info;
343 #else
344     REQUEST_INFO *req_info = NULL;
345 #endif
346
347     challenge_len = *challenge++;
348     response_len = *response++;
349
350     radius_msg[0] = 0;
351
352     if (radius_init(radius_msg) < 0) {
353         error("%s", radius_msg);
354         return 0;
355     }
356
357     /* return error for types we can't handle */
358     if ((digest->code != CHAP_MD5)
359 #ifdef CHAPMS
360         && (digest->code != CHAP_MICROSOFT)
361         && (digest->code != CHAP_MICROSOFT_V2)
362 #endif
363         ) {
364         error("RADIUS: Challenge type %u unsupported", digest->code);
365         return 0;
366     }
367
368     /* Put user with potentially realm added in rstate.user */
369     if (!rstate.done_chap_once) {
370         make_username_realm(user);
371         rstate.client_port = get_client_port (portnummap ? devnam : ifname);
372         if (radius_pre_auth_hook) {
373             radius_pre_auth_hook(rstate.user,
374                                  &rstate.authserver,
375                                  &rstate.acctserver);
376         }
377     }
378
379     send = received = NULL;
380
381     av_type = PW_FRAMED;
382     rc_avpair_add (&send, PW_SERVICE_TYPE, &av_type, 0, VENDOR_NONE);
383
384     av_type = PW_PPP;
385     rc_avpair_add (&send, PW_FRAMED_PROTOCOL, &av_type, 0, VENDOR_NONE);
386
387     rc_avpair_add (&send, PW_USER_NAME, rstate.user , 0, VENDOR_NONE);
388
389     /*
390      * add the challenge and response fields
391      */
392     switch (digest->code) {
393     case CHAP_MD5:
394         /* CHAP-Challenge and CHAP-Password */
395         if (response_len != MD5_HASH_SIZE)
396             return 0;
397         cpassword[0] = id;
398         memcpy(&cpassword[1], response, MD5_HASH_SIZE);
399
400         rc_avpair_add(&send, PW_CHAP_CHALLENGE,
401                       challenge, challenge_len, VENDOR_NONE);
402         rc_avpair_add(&send, PW_CHAP_PASSWORD,
403                       cpassword, MD5_HASH_SIZE + 1, VENDOR_NONE);
404         break;
405
406 #ifdef CHAPMS
407     case CHAP_MICROSOFT:
408     {
409         /* MS-CHAP-Challenge and MS-CHAP-Response */
410         MS_ChapResponse *rmd = (MS_ChapResponse *) response;
411         u_char *p = cpassword;
412
413         if (response_len != MS_CHAP_RESPONSE_LEN)
414             return 0;
415         *p++ = id;
416         /* The idiots use a different field order in RADIUS than PPP */
417         memcpy(p, rmd->UseNT, sizeof(rmd->UseNT));
418         p += sizeof(rmd->UseNT);
419         memcpy(p, rmd->LANManResp, sizeof(rmd->LANManResp));
420         p += sizeof(rmd->LANManResp);
421         memcpy(p, rmd->NTResp, sizeof(rmd->NTResp));
422
423         rc_avpair_add(&send, PW_MS_CHAP_CHALLENGE,
424                       challenge, challenge_len, VENDOR_MICROSOFT);
425         rc_avpair_add(&send, PW_MS_CHAP_RESPONSE,
426                       cpassword, MS_CHAP_RESPONSE_LEN + 1, VENDOR_MICROSOFT);
427         break;
428     }
429
430     case CHAP_MICROSOFT_V2:
431     {
432         /* MS-CHAP-Challenge and MS-CHAP2-Response */
433         MS_Chap2Response *rmd = (MS_Chap2Response *) response;
434         u_char *p = cpassword;
435
436         if (response_len != MS_CHAP2_RESPONSE_LEN)
437             return 0;
438         *p++ = id;
439         /* The idiots use a different field order in RADIUS than PPP */
440         memcpy(p, rmd->Flags, sizeof(rmd->Flags));
441         p += sizeof(rmd->Flags);
442         memcpy(p, rmd->PeerChallenge, sizeof(rmd->PeerChallenge));
443         p += sizeof(rmd->PeerChallenge);
444         memcpy(p, rmd->Reserved, sizeof(rmd->Reserved));
445         p += sizeof(rmd->Reserved);
446         memcpy(p, rmd->NTResp, sizeof(rmd->NTResp));
447
448         rc_avpair_add(&send, PW_MS_CHAP_CHALLENGE,
449                       challenge, challenge_len, VENDOR_MICROSOFT);
450         rc_avpair_add(&send, PW_MS_CHAP2_RESPONSE,
451                       cpassword, MS_CHAP2_RESPONSE_LEN + 1, VENDOR_MICROSOFT);
452         break;
453     }
454 #endif
455     }
456
457     if (*remote_number) {
458         rc_avpair_add(&send, PW_CALLING_STATION_ID, remote_number, 0,
459                        VENDOR_NONE);
460     }
461
462     /* Add user specified vp's */
463     if (rstate.avp)
464         rc_avpair_insert(&send, NULL, rc_avpair_copy(rstate.avp));
465
466     /*
467      * make authentication with RADIUS server
468      */
469
470     if (rstate.authserver) {
471         result = rc_auth_using_server(rstate.authserver,
472                                       rstate.client_port, send,
473                                       &received, radius_msg, req_info);
474     } else {
475         result = rc_auth(rstate.client_port, send, &received, radius_msg,
476                          req_info);
477     }
478
479     if (result == OK_RC) {
480         if (!rstate.done_chap_once) {
481             if (radius_setparams(received, radius_msg, req_info, digest,
482                                  challenge, message, message_space) < 0) {
483                 error("%s", radius_msg);
484                 result = ERROR_RC;
485             } else {
486                 rstate.done_chap_once = 1;
487             }
488         }
489     }
490
491     rc_avpair_free(received);
492     rc_avpair_free (send);
493     return (result == OK_RC);
494 }
495
496 /**********************************************************************
497 * %FUNCTION: make_username_realm
498 * %ARGUMENTS:
499 *  user -- the user given to pppd
500 * %RETURNS:
501 *  Nothing
502 * %DESCRIPTION:
503 *  Copies user into rstate.user.  If it lacks a realm (no "@domain" part),
504 * then the default realm from the radiusclient config file is added.
505 ***********************************************************************/
506 static void
507 make_username_realm(char *user)
508 {
509     char *default_realm;
510
511     if ( user != NULL ) {
512         strlcpy(rstate.user, user, sizeof(rstate.user));
513     }  else {
514         rstate.user[0] = 0;
515     }
516
517     default_realm = rc_conf_str("default_realm");
518
519     if (!strchr(rstate.user, '@') &&
520         default_realm &&
521         (*default_realm != '\0')) {
522         strlcat(rstate.user, "@", sizeof(rstate.user));
523         strlcat(rstate.user, default_realm, sizeof(rstate.user));
524     }
525 }
526
527 /**********************************************************************
528 * %FUNCTION: radius_setparams
529 * %ARGUMENTS:
530 *  vp -- received value-pairs
531 *  msg -- buffer in which to place error message.  Holds up to BUF_LEN chars
532 * %RETURNS:
533 *  >= 0 on success; -1 on failure
534 * %DESCRIPTION:
535 *  Parses attributes sent by RADIUS server and sets them in pppd.
536 ***********************************************************************/
537 static int
538 radius_setparams(VALUE_PAIR *vp, char *msg, REQUEST_INFO *req_info,
539                  struct chap_digest_type *digest, unsigned char *challenge,
540                  char *message, int message_space)
541 {
542     u_int32_t remote;
543     int ms_chap2_success = 0;
544 #ifdef MPPE
545     int mppe_enc_keys = 0;      /* whether or not these were received */
546     int mppe_enc_policy = 0;
547     int mppe_enc_types = 0;
548 #endif
549
550     /* Send RADIUS attributes to anyone else who might be interested */
551     if (radius_attributes_hook) {
552         (*radius_attributes_hook)(vp);
553     }
554
555     /*
556      * service type (if not framed then quit),
557      * new IP address (RADIUS can define static IP for some users),
558      */
559
560     while (vp) {
561         if (vp->vendorcode == VENDOR_NONE) {
562             switch (vp->attribute) {
563             case PW_SERVICE_TYPE:
564                 /* check for service type       */
565                 /* if not FRAMED then exit      */
566                 if (vp->lvalue != PW_FRAMED) {
567                     slprintf(msg, BUF_LEN, "RADIUS: wrong service type %ld for %s",
568                              vp->lvalue, rstate.user);
569                     return -1;
570                 }
571                 break;
572
573             case PW_FRAMED_PROTOCOL:
574                 /* check for framed protocol type       */
575                 /* if not PPP then also exit            */
576                 if (vp->lvalue != PW_PPP) {
577                     slprintf(msg, BUF_LEN, "RADIUS: wrong framed protocol %ld for %s",
578                              vp->lvalue, rstate.user);
579                     return -1;
580                 }
581                 break;
582
583             case PW_SESSION_TIMEOUT:
584                 /* Session timeout */
585                 maxconnect = vp->lvalue;
586                 break;
587 #ifdef MAXOCTETS
588             case PW_SESSION_OCTETS_LIMIT:
589                 /* Session traffic limit */
590                 maxoctets = vp->lvalue;
591                 break;
592             case PW_OCTETS_DIRECTION:
593                 /* Session traffic limit direction check */
594                 maxoctets_dir = ( vp->lvalue > 4 ) ? 0 : vp->lvalue ;
595                 break;
596 #endif
597             case PW_ACCT_INTERIM_INTERVAL:
598                 /* Send accounting updates every few seconds */
599                 rstate.acct_interim_interval = vp->lvalue;
600                 /* RFC says it MUST NOT be less than 60 seconds */
601                 /* We use "0" to signify not sending updates */
602                 if (rstate.acct_interim_interval &&
603                     rstate.acct_interim_interval < 60) {
604                     rstate.acct_interim_interval = 60;
605                 }
606                 break;
607             case PW_FRAMED_IP_ADDRESS:
608                 /* seting up remote IP addresses */
609                 remote = vp->lvalue;
610                 if (remote == 0xffffffff) {
611                     /* 0xffffffff means user should be allowed to select one */
612                     rstate.any_ip_addr_ok = 1;
613                 } else if (remote != 0xfffffffe) {
614                     /* 0xfffffffe means NAS should select an ip address */
615                     remote = htonl(vp->lvalue);
616                     if (bad_ip_adrs (remote)) {
617                         slprintf(msg, BUF_LEN, "RADIUS: bad remote IP address %I for %s",
618                                  remote, rstate.user);
619                         return -1;
620                     }
621                     rstate.choose_ip = 1;
622                     rstate.ip_addr = remote;
623                 }
624                 break;
625             case PW_CLASS:
626                 /* Save Class attribute to pass it in accounting request */
627                 if (vp->lvalue <= MAXCLASSLEN) {
628                     rstate.class_len=vp->lvalue;
629                     memcpy(rstate.class, vp->strvalue, rstate.class_len);
630                 } /* else too big for our buffer - ignore it */
631                 break;
632             }
633
634
635 #ifdef CHAPMS
636         } else if (vp->vendorcode == VENDOR_MICROSOFT) {
637             switch (vp->attribute) {
638             case PW_MS_CHAP2_SUCCESS:
639                 if ((vp->lvalue != 43) || strncmp(vp->strvalue + 1, "S=", 2)) {
640                     slprintf(msg,BUF_LEN,"RADIUS: bad MS-CHAP2-Success packet");
641                     return -1;
642                 }
643                 if (message != NULL)
644                     strlcpy(message, vp->strvalue + 1, message_space);
645                 ms_chap2_success = 1;
646                 break;
647
648 #ifdef MPPE
649             case PW_MS_CHAP_MPPE_KEYS:
650                 if (radius_setmppekeys(vp, req_info, challenge) < 0) {
651                     slprintf(msg, BUF_LEN,
652                              "RADIUS: bad MS-CHAP-MPPE-Keys attribute");
653                     return -1;
654                 }
655                 mppe_enc_keys = 1;
656                 break;
657
658             case PW_MS_MPPE_SEND_KEY:
659             case PW_MS_MPPE_RECV_KEY:
660                 if (radius_setmppekeys2(vp, req_info) < 0) {
661                     slprintf(msg, BUF_LEN,
662                              "RADIUS: bad MS-MPPE-%s-Key attribute",
663                              (vp->attribute == PW_MS_MPPE_SEND_KEY)?
664                              "Send": "Recv");
665                     return -1;
666                 }
667                 mppe_enc_keys = 1;
668                 break;
669
670             case PW_MS_MPPE_ENCRYPTION_POLICY:
671                 mppe_enc_policy = vp->lvalue;   /* save for later */
672                 break;
673
674             case PW_MS_MPPE_ENCRYPTION_TYPES:
675                 mppe_enc_types = vp->lvalue;    /* save for later */
676                 break;
677
678 #endif /* MPPE */
679 #if 0
680             case PW_MS_PRIMARY_DNS_SERVER:
681             case PW_MS_SECONDARY_DNS_SERVER:
682             case PW_MS_PRIMARY_NBNS_SERVER:
683             case PW_MS_SECONDARY_NBNS_SERVER:
684                 break;
685 #endif
686             }
687 #endif /* CHAPMS */
688         }
689         vp = vp->next;
690     }
691
692     /* Require a valid MS-CHAP2-SUCCESS for MS-CHAPv2 auth */
693     if (digest && (digest->code == CHAP_MICROSOFT_V2) && !ms_chap2_success)
694         return -1;
695
696 #ifdef MPPE
697     /*
698      * Require both policy and key attributes to indicate a valid key.
699      * Note that if the policy value was '0' we don't set the key!
700      */
701     if (mppe_enc_policy && mppe_enc_keys) {
702         mppe_keys_set = 1;
703         /* Set/modify allowed encryption types. */
704         if (mppe_enc_types)
705             set_mppe_enc_types(mppe_enc_policy, mppe_enc_types);
706     }
707 #endif
708
709     return 0;
710 }
711
712 #ifdef MPPE
713 /**********************************************************************
714 * %FUNCTION: radius_setmppekeys
715 * %ARGUMENTS:
716 *  vp -- value pair holding MS-CHAP-MPPE-KEYS attribute
717 *  req_info -- radius request information used for encryption
718 * %RETURNS:
719 *  >= 0 on success; -1 on failure
720 * %DESCRIPTION:
721 *  Decrypt the "key" provided by the RADIUS server for MPPE encryption.
722 *  See RFC 2548.
723 ***********************************************************************/
724 static int
725 radius_setmppekeys(VALUE_PAIR *vp, REQUEST_INFO *req_info,
726                    unsigned char *challenge)
727 {
728     int i;
729     MD5_CTX Context;
730     u_char  plain[32];
731     u_char  buf[16];
732
733     if (vp->lvalue != 32) {
734         error("RADIUS: Incorrect attribute length (%d) for MS-CHAP-MPPE-Keys",
735               vp->lvalue);
736         return -1;
737     }
738
739     memcpy(plain, vp->strvalue, sizeof(plain));
740
741     MD5Init(&Context);
742     MD5Update(&Context, req_info->secret, strlen(req_info->secret));
743     MD5Update(&Context, req_info->request_vector, AUTH_VECTOR_LEN);
744     MD5Final(buf, &Context);
745
746     for (i = 0; i < 16; i++)
747         plain[i] ^= buf[i];
748
749     MD5Init(&Context);
750     MD5Update(&Context, req_info->secret, strlen(req_info->secret));
751     MD5Update(&Context, vp->strvalue, 16);
752     MD5Final(buf, &Context);
753
754     for(i = 0; i < 16; i++)
755         plain[i + 16] ^= buf[i];
756
757     /*
758      * Annoying.  The "key" returned is just the NTPasswordHashHash, which
759      * the NAS (us) doesn't need; we only need the start key.  So we have
760      * to generate the start key, sigh.  NB: We do not support the LM-Key.
761      */
762     mppe_set_keys(challenge, &plain[8]);
763
764     return 0;    
765 }
766
767 /**********************************************************************
768 * %FUNCTION: radius_setmppekeys2
769 * %ARGUMENTS:
770 *  vp -- value pair holding MS-MPPE-SEND-KEY or MS-MPPE-RECV-KEY attribute
771 *  req_info -- radius request information used for encryption
772 * %RETURNS:
773 *  >= 0 on success; -1 on failure
774 * %DESCRIPTION:
775 *  Decrypt the key provided by the RADIUS server for MPPE encryption.
776 *  See RFC 2548.
777 ***********************************************************************/
778 static int
779 radius_setmppekeys2(VALUE_PAIR *vp, REQUEST_INFO *req_info)
780 {
781     int i;
782     MD5_CTX Context;
783     u_char  *salt = vp->strvalue;
784     u_char  *crypt = vp->strvalue + 2;
785     u_char  plain[32];
786     u_char  buf[MD5_HASH_SIZE];
787     char    *type = "Send";
788
789     if (vp->attribute == PW_MS_MPPE_RECV_KEY)
790         type = "Recv";
791
792     if (vp->lvalue != 34) {
793         error("RADIUS: Incorrect attribute length (%d) for MS-MPPE-%s-Key",
794               vp->lvalue, type);
795         return -1;
796     }
797
798     if ((salt[0] & 0x80) == 0) {
799         error("RADIUS: Illegal salt value for MS-MPPE-%s-Key attribute", type);
800         return -1;
801     }
802
803     memcpy(plain, crypt, 32);
804
805     MD5Init(&Context);
806     MD5Update(&Context, req_info->secret, strlen(req_info->secret));
807     MD5Update(&Context, req_info->request_vector, AUTH_VECTOR_LEN);
808     MD5Update(&Context, salt, 2);
809     MD5Final(buf, &Context);
810
811     for (i = 0; i < 16; i++)
812         plain[i] ^= buf[i];
813
814     if (plain[0] != sizeof(mppe_send_key) /* 16 */) {
815         error("RADIUS: Incorrect key length (%d) for MS-MPPE-%s-Key attribute",
816               (int) plain[0], type);
817         return -1;
818     }
819
820     MD5Init(&Context);
821     MD5Update(&Context, req_info->secret, strlen(req_info->secret));
822     MD5Update(&Context, crypt, 16);
823     MD5Final(buf, &Context);
824
825     plain[16] ^= buf[0]; /* only need the first byte */
826
827     if (vp->attribute == PW_MS_MPPE_SEND_KEY)
828         memcpy(mppe_send_key, plain + 1, 16);
829     else
830         memcpy(mppe_recv_key, plain + 1, 16);
831
832     return 0;
833 }
834 #endif /* MPPE */
835
836 /**********************************************************************
837 * %FUNCTION: radius_acct_start
838 * %ARGUMENTS:
839 *  None
840 * %RETURNS:
841 *  Nothing
842 * %DESCRIPTION:
843 *  Sends a "start" accounting message to the RADIUS server.
844 ***********************************************************************/
845 static void
846 radius_acct_start(void)
847 {
848     UINT4 av_type;
849     int result;
850     VALUE_PAIR *send = NULL;
851     ipcp_options *ho = &ipcp_hisoptions[0];
852     u_int32_t hisaddr;
853
854     if (!rstate.initialized) {
855         return;
856     }
857
858     rstate.start_time = time(NULL);
859
860     strncpy(rstate.session_id, rc_mksid(), sizeof(rstate.session_id));
861
862     rc_avpair_add(&send, PW_ACCT_SESSION_ID,
863                    rstate.session_id, 0, VENDOR_NONE);
864     rc_avpair_add(&send, PW_USER_NAME,
865                    rstate.user, 0, VENDOR_NONE);
866
867     if (rstate.class_len > 0)
868         rc_avpair_add(&send, PW_CLASS,
869                       rstate.class, rstate.class_len, VENDOR_NONE);
870
871     av_type = PW_STATUS_START;
872     rc_avpair_add(&send, PW_ACCT_STATUS_TYPE, &av_type, 0, VENDOR_NONE);
873
874     av_type = PW_FRAMED;
875     rc_avpair_add(&send, PW_SERVICE_TYPE, &av_type, 0, VENDOR_NONE);
876
877     av_type = PW_PPP;
878     rc_avpair_add(&send, PW_FRAMED_PROTOCOL, &av_type, 0, VENDOR_NONE);
879
880     if (*remote_number) {
881         rc_avpair_add(&send, PW_CALLING_STATION_ID,
882                        remote_number, 0, VENDOR_NONE);
883     }
884
885     av_type = PW_RADIUS;
886     rc_avpair_add(&send, PW_ACCT_AUTHENTIC, &av_type, 0, VENDOR_NONE);
887
888
889     av_type = using_pty ? PW_VIRTUAL : PW_ASYNC;
890     rc_avpair_add(&send, PW_NAS_PORT_TYPE, &av_type, 0, VENDOR_NONE);
891
892     hisaddr = ho->hisaddr;
893     av_type = htonl(hisaddr);
894     rc_avpair_add(&send, PW_FRAMED_IP_ADDRESS , &av_type , 0, VENDOR_NONE);
895
896     /* Add user specified vp's */
897     if (rstate.avp)
898         rc_avpair_insert(&send, NULL, rc_avpair_copy(rstate.avp));
899
900     if (rstate.acctserver) {
901         result = rc_acct_using_server(rstate.acctserver,
902                                       rstate.client_port, send);
903     } else {
904         result = rc_acct(rstate.client_port, send);
905     }
906
907     rc_avpair_free(send);
908
909     if (result != OK_RC) {
910         /* RADIUS server could be down so make this a warning */
911         syslog(LOG_WARNING,
912                 "Accounting START failed for %s", rstate.user);
913     } else {
914         rstate.accounting_started = 1;
915         /* Kick off periodic accounting reports */
916         if (rstate.acct_interim_interval) {
917             TIMEOUT(radius_acct_interim, NULL, rstate.acct_interim_interval);
918         }
919     }
920 }
921
922 /**********************************************************************
923 * %FUNCTION: radius_acct_stop
924 * %ARGUMENTS:
925 *  None
926 * %RETURNS:
927 *  Nothing
928 * %DESCRIPTION:
929 *  Sends a "stop" accounting message to the RADIUS server.
930 ***********************************************************************/
931 static void
932 radius_acct_stop(void)
933 {
934     UINT4 av_type;
935     VALUE_PAIR *send = NULL;
936     ipcp_options *ho = &ipcp_hisoptions[0];
937     u_int32_t hisaddr;
938     int result;
939
940     if (!rstate.initialized) {
941         return;
942     }
943
944     if (!rstate.accounting_started) {
945         return;
946     }
947
948     rstate.accounting_started = 0;
949     rc_avpair_add(&send, PW_ACCT_SESSION_ID, rstate.session_id,
950                    0, VENDOR_NONE);
951
952     rc_avpair_add(&send, PW_USER_NAME, rstate.user, 0, VENDOR_NONE);
953
954     av_type = PW_STATUS_STOP;
955     rc_avpair_add(&send, PW_ACCT_STATUS_TYPE, &av_type, 0, VENDOR_NONE);
956
957     av_type = PW_FRAMED;
958     rc_avpair_add(&send, PW_SERVICE_TYPE, &av_type, 0, VENDOR_NONE);
959
960     av_type = PW_PPP;
961     rc_avpair_add(&send, PW_FRAMED_PROTOCOL, &av_type, 0, VENDOR_NONE);
962
963     av_type = PW_RADIUS;
964     rc_avpair_add(&send, PW_ACCT_AUTHENTIC, &av_type, 0, VENDOR_NONE);
965
966
967     if (link_stats_valid) {
968         av_type = link_connect_time;
969         rc_avpair_add(&send, PW_ACCT_SESSION_TIME, &av_type, 0, VENDOR_NONE);
970
971         av_type = link_stats.bytes_out;
972         rc_avpair_add(&send, PW_ACCT_OUTPUT_OCTETS, &av_type, 0, VENDOR_NONE);
973
974         av_type = link_stats.bytes_in;
975         rc_avpair_add(&send, PW_ACCT_INPUT_OCTETS, &av_type, 0, VENDOR_NONE);
976
977         av_type = link_stats.pkts_out;
978         rc_avpair_add(&send, PW_ACCT_OUTPUT_PACKETS, &av_type, 0, VENDOR_NONE);
979
980         av_type = link_stats.pkts_in;
981         rc_avpair_add(&send, PW_ACCT_INPUT_PACKETS, &av_type, 0, VENDOR_NONE);
982     }
983
984     if (*remote_number) {
985         rc_avpair_add(&send, PW_CALLING_STATION_ID,
986                        remote_number, 0, VENDOR_NONE);
987     }
988
989     av_type = using_pty ? PW_VIRTUAL : PW_ASYNC;
990     rc_avpair_add(&send, PW_NAS_PORT_TYPE, &av_type, 0, VENDOR_NONE);
991
992     av_type = PW_NAS_ERROR;
993     switch( status ) {
994         case EXIT_OK:
995         case EXIT_USER_REQUEST:
996             av_type = PW_USER_REQUEST;
997             break;
998
999         case EXIT_HANGUP:
1000         case EXIT_PEER_DEAD:
1001         case EXIT_CONNECT_FAILED:
1002             av_type = PW_LOST_CARRIER;
1003             break;
1004
1005         case EXIT_INIT_FAILED:
1006         case EXIT_OPEN_FAILED:
1007         case EXIT_LOCK_FAILED:
1008         case EXIT_PTYCMD_FAILED:
1009             av_type = PW_PORT_ERROR;
1010             break;
1011
1012         case EXIT_PEER_AUTH_FAILED:
1013         case EXIT_AUTH_TOPEER_FAILED:
1014         case EXIT_NEGOTIATION_FAILED:
1015         case EXIT_CNID_AUTH_FAILED:
1016             av_type = PW_SERVICE_UNAVAILABLE;
1017             break;
1018
1019         case EXIT_IDLE_TIMEOUT:
1020             av_type = PW_ACCT_IDLE_TIMEOUT;
1021             break;
1022
1023         case EXIT_CONNECT_TIME:
1024             av_type = PW_ACCT_SESSION_TIMEOUT;
1025             break;
1026             
1027 #ifdef MAXOCTETS
1028         case EXIT_TRAFFIC_LIMIT:
1029             av_type = PW_NAS_REQUEST;
1030             break;
1031 #endif
1032
1033         default:
1034             av_type = PW_NAS_ERROR;
1035             break;
1036     }
1037     rc_avpair_add(&send, PW_ACCT_TERMINATE_CAUSE, &av_type, 0, VENDOR_NONE);
1038
1039     hisaddr = ho->hisaddr;
1040     av_type = htonl(hisaddr);
1041     rc_avpair_add(&send, PW_FRAMED_IP_ADDRESS , &av_type , 0, VENDOR_NONE);
1042
1043     /* Add user specified vp's */
1044     if (rstate.avp)
1045         rc_avpair_insert(&send, NULL, rc_avpair_copy(rstate.avp));
1046
1047     if (rstate.acctserver) {
1048         result = rc_acct_using_server(rstate.acctserver,
1049                                       rstate.client_port, send);
1050     } else {
1051         result = rc_acct(rstate.client_port, send);
1052     }
1053
1054     if (result != OK_RC) {
1055         /* RADIUS server could be down so make this a warning */
1056         syslog(LOG_WARNING,
1057                 "Accounting STOP failed for %s", rstate.user);
1058     }
1059     rc_avpair_free(send);
1060 }
1061
1062 /**********************************************************************
1063 * %FUNCTION: radius_acct_interim
1064 * %ARGUMENTS:
1065 *  None
1066 * %RETURNS:
1067 *  Nothing
1068 * %DESCRIPTION:
1069 *  Sends an interim accounting message to the RADIUS server
1070 ***********************************************************************/
1071 static void
1072 radius_acct_interim(void *ignored)
1073 {
1074     UINT4 av_type;
1075     VALUE_PAIR *send = NULL;
1076     ipcp_options *ho = &ipcp_hisoptions[0];
1077     u_int32_t hisaddr;
1078     int result;
1079
1080     if (!rstate.initialized) {
1081         return;
1082     }
1083
1084     if (!rstate.accounting_started) {
1085         return;
1086     }
1087
1088     rc_avpair_add(&send, PW_ACCT_SESSION_ID, rstate.session_id,
1089                    0, VENDOR_NONE);
1090
1091     rc_avpair_add(&send, PW_USER_NAME, rstate.user, 0, VENDOR_NONE);
1092
1093     av_type = PW_STATUS_ALIVE;
1094     rc_avpair_add(&send, PW_ACCT_STATUS_TYPE, &av_type, 0, VENDOR_NONE);
1095
1096     av_type = PW_FRAMED;
1097     rc_avpair_add(&send, PW_SERVICE_TYPE, &av_type, 0, VENDOR_NONE);
1098
1099     av_type = PW_PPP;
1100     rc_avpair_add(&send, PW_FRAMED_PROTOCOL, &av_type, 0, VENDOR_NONE);
1101
1102     av_type = PW_RADIUS;
1103     rc_avpair_add(&send, PW_ACCT_AUTHENTIC, &av_type, 0, VENDOR_NONE);
1104
1105     /* Update link stats */
1106     update_link_stats(0);
1107
1108     if (link_stats_valid) {
1109         link_stats_valid = 0; /* Force later code to update */
1110
1111         av_type = link_connect_time;
1112         rc_avpair_add(&send, PW_ACCT_SESSION_TIME, &av_type, 0, VENDOR_NONE);
1113
1114         av_type = link_stats.bytes_out;
1115         rc_avpair_add(&send, PW_ACCT_OUTPUT_OCTETS, &av_type, 0, VENDOR_NONE);
1116
1117         av_type = link_stats.bytes_in;
1118         rc_avpair_add(&send, PW_ACCT_INPUT_OCTETS, &av_type, 0, VENDOR_NONE);
1119
1120         av_type = link_stats.pkts_out;
1121         rc_avpair_add(&send, PW_ACCT_OUTPUT_PACKETS, &av_type, 0, VENDOR_NONE);
1122
1123         av_type = link_stats.pkts_in;
1124         rc_avpair_add(&send, PW_ACCT_INPUT_PACKETS, &av_type, 0, VENDOR_NONE);
1125     }
1126
1127     if (*remote_number) {
1128         rc_avpair_add(&send, PW_CALLING_STATION_ID,
1129                        remote_number, 0, VENDOR_NONE);
1130     }
1131
1132     av_type = using_pty ? PW_VIRTUAL : PW_ASYNC;
1133     rc_avpair_add(&send, PW_NAS_PORT_TYPE, &av_type, 0, VENDOR_NONE);
1134
1135     hisaddr = ho->hisaddr;
1136     av_type = htonl(hisaddr);
1137     rc_avpair_add(&send, PW_FRAMED_IP_ADDRESS , &av_type , 0, VENDOR_NONE);
1138
1139     /* Add user specified vp's */
1140     if (rstate.avp)
1141         rc_avpair_insert(&send, NULL, rc_avpair_copy(rstate.avp));
1142
1143     if (rstate.acctserver) {
1144         result = rc_acct_using_server(rstate.acctserver,
1145                                       rstate.client_port, send);
1146     } else {
1147         result = rc_acct(rstate.client_port, send);
1148     }
1149
1150     if (result != OK_RC) {
1151         /* RADIUS server could be down so make this a warning */
1152         syslog(LOG_WARNING,
1153                 "Interim accounting failed for %s", rstate.user);
1154     }
1155     rc_avpair_free(send);
1156
1157     /* Schedule another one */
1158     TIMEOUT(radius_acct_interim, NULL, rstate.acct_interim_interval);
1159 }
1160
1161 /**********************************************************************
1162 * %FUNCTION: radius_ip_up
1163 * %ARGUMENTS:
1164 *  opaque -- ignored
1165 *  arg -- ignored
1166 * %RETURNS:
1167 *  Nothing
1168 * %DESCRIPTION:
1169 *  Called when IPCP is up.  We'll do a start-accounting record.
1170 ***********************************************************************/
1171 static void
1172 radius_ip_up(void *opaque, int arg)
1173 {
1174     radius_acct_start();
1175 }
1176
1177 /**********************************************************************
1178 * %FUNCTION: radius_ip_down
1179 * %ARGUMENTS:
1180 *  opaque -- ignored
1181 *  arg -- ignored
1182 * %RETURNS:
1183 *  Nothing
1184 * %DESCRIPTION:
1185 *  Called when IPCP is down.  We'll do a stop-accounting record.
1186 ***********************************************************************/
1187 static void
1188 radius_ip_down(void *opaque, int arg)
1189 {
1190     radius_acct_stop();
1191 }
1192
1193 /**********************************************************************
1194 * %FUNCTION: radius_init
1195 * %ARGUMENTS:
1196 *  msg -- buffer of size BUF_LEN for error message
1197 * %RETURNS:
1198 *  negative on failure; non-negative on success
1199 * %DESCRIPTION:
1200 *  Initializes radiusclient library
1201 ***********************************************************************/
1202 static int
1203 radius_init(char *msg)
1204 {
1205     if (rstate.initialized) {
1206         return 0;
1207     }
1208
1209     if (config_file && *config_file) {
1210         strlcpy(rstate.config_file, config_file, MAXPATHLEN-1);
1211     }
1212
1213     rstate.initialized = 1;
1214
1215     if (rc_read_config(rstate.config_file) != 0) {
1216         slprintf(msg, BUF_LEN, "RADIUS: Can't read config file %s",
1217                  rstate.config_file);
1218         return -1;
1219     }
1220
1221     if (rc_read_dictionary(rc_conf_str("dictionary")) != 0) {
1222         slprintf(msg, BUF_LEN, "RADIUS: Can't read dictionary file %s",
1223                  rc_conf_str("dictionary"));
1224         return -1;
1225     }
1226
1227     if (rc_read_mapfile(rc_conf_str("mapfile")) != 0)   {
1228         slprintf(msg, BUF_LEN, "RADIUS: Can't read map file %s",
1229                  rc_conf_str("mapfile"));
1230         return -1;
1231     }
1232
1233     /* Add av pairs saved during option parsing */
1234     while (avpopt) {
1235         struct avpopt *n = avpopt->next;
1236
1237         rc_avpair_parse(avpopt->vpstr, &rstate.avp);
1238         free(avpopt->vpstr);
1239         free(avpopt);
1240         avpopt = n;
1241     }
1242     return 0;
1243 }
1244
1245 /**********************************************************************
1246 * %FUNCTION: get_client_port
1247 * %ARGUMENTS:
1248 *  ifname -- PPP interface name (e.g. "ppp7")
1249 * %RETURNS:
1250 *  The NAS port number (e.g. 7)
1251 * %DESCRIPTION:
1252 *  Extracts the port number from the interface name
1253 ***********************************************************************/
1254 static int
1255 get_client_port(char *ifname)
1256 {
1257     int port;
1258     if (sscanf(ifname, "ppp%d", &port) == 1) {
1259         return port;
1260     }
1261     return rc_map2id(ifname);
1262 }
1263
1264 /**********************************************************************
1265 * %FUNCTION: radius_allowed_address
1266 * %ARGUMENTS:
1267 *  addr -- IP address
1268 * %RETURNS:
1269 *  1 if we're allowed to use that IP address; 0 if not; -1 if we do
1270 *  not know.
1271 ***********************************************************************/
1272 static int
1273 radius_allowed_address(u_int32_t addr)
1274 {
1275     ipcp_options *wo = &ipcp_wantoptions[0];
1276
1277     if (!rstate.choose_ip) {
1278         /* If RADIUS server said any address is OK, then fine... */
1279         if (rstate.any_ip_addr_ok) {
1280             return 1;
1281         }
1282
1283         /* Sigh... if an address was supplied for remote host in pppd
1284            options, it has to match that.  */
1285         if (wo->hisaddr != 0 && wo->hisaddr == addr) {
1286             return 1;
1287         }
1288
1289         return 0;
1290     }
1291     if (addr == rstate.ip_addr) return 1;
1292     return 0;
1293 }
1294
1295 /* Useful for other plugins */
1296 char *radius_logged_in_user(void)
1297 {
1298     return rstate.user;
1299 }