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