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