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