radius.c revision 116586
1/* 2 * Copyright 1999 Internet Business Solutions Ltd., Switzerland 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: head/usr.sbin/ppp/radius.c 116586 2003-06-19 18:19:31Z ume $ 27 * 28 */ 29 30#include <sys/param.h> 31 32#include <sys/socket.h> 33#include <netinet/in_systm.h> 34#include <netinet/in.h> 35#include <netinet/ip.h> 36#include <arpa/inet.h> 37#include <sys/un.h> 38#include <net/route.h> 39 40#ifdef LOCALRAD 41#include "radlib.h" 42#include "radlib_vs.h" 43#else 44#include <radlib.h> 45#include <radlib_vs.h> 46#endif 47 48#include <errno.h> 49#ifndef NODES 50#include <md5.h> 51#endif 52#include <stdarg.h> 53#include <stdio.h> 54#include <stdlib.h> 55#include <string.h> 56#include <sys/time.h> 57#include <termios.h> 58#include <unistd.h> 59#include <netdb.h> 60 61#include "layer.h" 62#include "defs.h" 63#include "log.h" 64#include "descriptor.h" 65#include "prompt.h" 66#include "timer.h" 67#include "fsm.h" 68#include "iplist.h" 69#include "slcompress.h" 70#include "throughput.h" 71#include "lqr.h" 72#include "hdlc.h" 73#include "mbuf.h" 74#include "ncpaddr.h" 75#include "ip.h" 76#include "ipcp.h" 77#include "ipv6cp.h" 78#include "route.h" 79#include "command.h" 80#include "filter.h" 81#include "lcp.h" 82#include "ccp.h" 83#include "link.h" 84#include "mp.h" 85#include "radius.h" 86#include "auth.h" 87#include "async.h" 88#include "physical.h" 89#include "chat.h" 90#include "cbcp.h" 91#include "chap.h" 92#include "datalink.h" 93#include "ncp.h" 94#include "bundle.h" 95#include "proto.h" 96 97#ifndef NODES 98struct mschap_response { 99 u_char ident; 100 u_char flags; 101 u_char lm_response[24]; 102 u_char nt_response[24]; 103}; 104 105struct mschap2_response { 106 u_char ident; 107 u_char flags; 108 u_char pchallenge[16]; 109 u_char reserved[8]; 110 u_char response[24]; 111}; 112 113#define AUTH_LEN 16 114#define SALT_LEN 2 115#endif 116 117static const char * 118radius_policyname(int policy) 119{ 120 switch(policy) { 121 case MPPE_POLICY_ALLOWED: 122 return "Allowed"; 123 case MPPE_POLICY_REQUIRED: 124 return "Required"; 125 } 126 return NumStr(policy, NULL, 0); 127} 128 129static const char * 130radius_typesname(int types) 131{ 132 switch(types) { 133 case MPPE_TYPE_40BIT: 134 return "40 bit"; 135 case MPPE_TYPE_128BIT: 136 return "128 bit"; 137 case MPPE_TYPE_40BIT|MPPE_TYPE_128BIT: 138 return "40 or 128 bit"; 139 } 140 return NumStr(types, NULL, 0); 141} 142 143#ifndef NODES 144static void 145demangle(struct radius *r, const void *mangled, size_t mlen, 146 char **buf, size_t *len) 147{ 148 char R[AUTH_LEN]; /* variable names as per rfc2548 */ 149 const char *S; 150 u_char b[16]; 151 const u_char *A, *C; 152 MD5_CTX Context; 153 int Slen, i, Clen, Ppos; 154 u_char *P; 155 156 if (mlen % 16 != SALT_LEN) { 157 log_Printf(LogWARN, "Cannot interpret mangled data of length %ld\n", 158 (u_long)mlen); 159 *buf = NULL; 160 *len = 0; 161 return; 162 } 163 164 /* We need the RADIUS Request-Authenticator */ 165 if (rad_request_authenticator(r->cx.rad, R, sizeof R) != AUTH_LEN) { 166 log_Printf(LogWARN, "Cannot obtain the RADIUS request authenticator\n"); 167 *buf = NULL; 168 *len = 0; 169 return; 170 } 171 172 A = (const u_char *)mangled; /* Salt comes first */ 173 C = (const u_char *)mangled + SALT_LEN; /* Then the ciphertext */ 174 Clen = mlen - SALT_LEN; 175 S = rad_server_secret(r->cx.rad); /* We need the RADIUS secret */ 176 Slen = strlen(S); 177 P = alloca(Clen); /* We derive our plaintext */ 178 179 MD5Init(&Context); 180 MD5Update(&Context, S, Slen); 181 MD5Update(&Context, R, AUTH_LEN); 182 MD5Update(&Context, A, SALT_LEN); 183 MD5Final(b, &Context); 184 Ppos = 0; 185 186 while (Clen) { 187 Clen -= 16; 188 189 for (i = 0; i < 16; i++) 190 P[Ppos++] = C[i] ^ b[i]; 191 192 if (Clen) { 193 MD5Init(&Context); 194 MD5Update(&Context, S, Slen); 195 MD5Update(&Context, C, 16); 196 MD5Final(b, &Context); 197 } 198 199 C += 16; 200 } 201 202 /* 203 * The resulting plain text consists of a one-byte length, the text and 204 * maybe some padding. 205 */ 206 *len = *P; 207 if (*len > mlen - 1) { 208 log_Printf(LogWARN, "Mangled data seems to be garbage\n"); 209 *buf = NULL; 210 *len = 0; 211 return; 212 } 213 214 *buf = malloc(*len); 215 memcpy(*buf, P + 1, *len); 216} 217#endif 218 219/* 220 * rad_continue_send_request() has given us `got' (non-zero). Deal with it. 221 */ 222static void 223radius_Process(struct radius *r, int got) 224{ 225 char *argv[MAXARGS], *nuke; 226 struct bundle *bundle; 227 int argc, addrs, res, width; 228 size_t len; 229 struct ncprange dest; 230 struct ncpaddr gw; 231 const void *data; 232 const char *stype; 233 u_int32_t ipaddr, vendor; 234 struct in_addr ip; 235#ifndef NOINET6 236 struct in6_addr ip6; 237#endif 238 239 r->cx.fd = -1; /* Stop select()ing */ 240 stype = r->cx.auth ? "auth" : "acct"; 241 242 switch (got) { 243 case RAD_ACCESS_ACCEPT: 244 log_Printf(LogPHASE, "Radius(%s): ACCEPT received\n", stype); 245 if (!r->cx.auth) { 246 rad_close(r->cx.rad); 247 return; 248 } 249 break; 250 251 case RAD_ACCESS_REJECT: 252 log_Printf(LogPHASE, "Radius(%s): REJECT received\n", stype); 253 if (!r->cx.auth) { 254 rad_close(r->cx.rad); 255 return; 256 } 257 break; 258 259 case RAD_ACCESS_CHALLENGE: 260 /* we can't deal with this (for now) ! */ 261 log_Printf(LogPHASE, "Radius: CHALLENGE received (can't handle yet)\n"); 262 if (r->cx.auth) 263 auth_Failure(r->cx.auth); 264 rad_close(r->cx.rad); 265 return; 266 267 case RAD_ACCOUNTING_RESPONSE: 268 log_Printf(LogPHASE, "Radius(%s): Accounting response received\n", stype); 269 if (r->cx.auth) 270 auth_Failure(r->cx.auth); /* unexpected !!! */ 271 272 /* No further processing for accounting requests, please */ 273 rad_close(r->cx.rad); 274 return; 275 276 case -1: 277 log_Printf(LogPHASE, "radius(%s): %s\n", stype, rad_strerror(r->cx.rad)); 278 if (r->cx.auth) 279 auth_Failure(r->cx.auth); 280 rad_close(r->cx.rad); 281 return; 282 283 default: 284 log_Printf(LogERROR, "rad_send_request(%s): Failed %d: %s\n", stype, 285 got, rad_strerror(r->cx.rad)); 286 if (r->cx.auth) 287 auth_Failure(r->cx.auth); 288 rad_close(r->cx.rad); 289 return; 290 } 291 292 /* Let's see what we've got in our reply */ 293 r->ip.s_addr = r->mask.s_addr = INADDR_NONE; 294 r->mtu = 0; 295 r->vj = 0; 296 while ((res = rad_get_attr(r->cx.rad, &data, &len)) > 0) { 297 switch (res) { 298 case RAD_FRAMED_IP_ADDRESS: 299 r->ip = rad_cvt_addr(data); 300 log_Printf(LogPHASE, " IP %s\n", inet_ntoa(r->ip)); 301 break; 302 303 case RAD_FILTER_ID: 304 free(r->filterid); 305 if ((r->filterid = rad_cvt_string(data, len)) == NULL) { 306 log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); 307 auth_Failure(r->cx.auth); 308 rad_close(r->cx.rad); 309 return; 310 } 311 log_Printf(LogPHASE, " Filter \"%s\"\n", r->filterid); 312 break; 313 314 case RAD_SESSION_TIMEOUT: 315 r->sessiontime = rad_cvt_int(data); 316 log_Printf(LogPHASE, " Session-Timeout %lu\n", r->sessiontime); 317 break; 318 319 case RAD_FRAMED_IP_NETMASK: 320 r->mask = rad_cvt_addr(data); 321 log_Printf(LogPHASE, " Netmask %s\n", inet_ntoa(r->mask)); 322 break; 323 324 case RAD_FRAMED_MTU: 325 r->mtu = rad_cvt_int(data); 326 log_Printf(LogPHASE, " MTU %lu\n", r->mtu); 327 break; 328 329 case RAD_FRAMED_ROUTING: 330 /* Disabled for now - should we automatically set up some filters ? */ 331 /* rad_cvt_int(data); */ 332 /* bit 1 = Send routing packets */ 333 /* bit 2 = Receive routing packets */ 334 break; 335 336 case RAD_FRAMED_COMPRESSION: 337 r->vj = rad_cvt_int(data) == 1 ? 1 : 0; 338 log_Printf(LogPHASE, " VJ %sabled\n", r->vj ? "en" : "dis"); 339 break; 340 341 case RAD_FRAMED_ROUTE: 342 /* 343 * We expect a string of the format ``dest[/bits] gw [metrics]'' 344 * Any specified metrics are ignored. MYADDR and HISADDR are 345 * understood for ``dest'' and ``gw'' and ``0.0.0.0'' is the same 346 * as ``HISADDR''. 347 */ 348 349 if ((nuke = rad_cvt_string(data, len)) == NULL) { 350 log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); 351 auth_Failure(r->cx.auth); 352 rad_close(r->cx.rad); 353 return; 354 } 355 356 log_Printf(LogPHASE, " Route: %s\n", nuke); 357 bundle = r->cx.auth->physical->dl->bundle; 358 ip.s_addr = INADDR_ANY; 359 ncpaddr_setip4(&gw, ip); 360 ncprange_setip4host(&dest, ip); 361 argc = command_Interpret(nuke, strlen(nuke), argv); 362 if (argc < 0) 363 log_Printf(LogWARN, "radius: %s: Syntax error\n", 364 argc == 1 ? argv[0] : "\"\""); 365 else if (argc < 2) 366 log_Printf(LogWARN, "radius: %s: Invalid route\n", 367 argc == 1 ? argv[0] : "\"\""); 368 else if ((strcasecmp(argv[0], "default") != 0 && 369 !ncprange_aton(&dest, &bundle->ncp, argv[0])) || 370 !ncpaddr_aton(&gw, &bundle->ncp, argv[1])) 371 log_Printf(LogWARN, "radius: %s %s: Invalid route\n", 372 argv[0], argv[1]); 373 else { 374 ncprange_getwidth(&dest, &width); 375 if (width == 32 && strchr(argv[0], '/') == NULL) { 376 /* No mask specified - use the natural mask */ 377 ncprange_getip4addr(&dest, &ip); 378 ncprange_setip4mask(&dest, addr2mask(ip)); 379 } 380 addrs = 0; 381 382 if (!strncasecmp(argv[0], "HISADDR", 7)) 383 addrs = ROUTE_DSTHISADDR; 384 else if (!strncasecmp(argv[0], "MYADDR", 6)) 385 addrs = ROUTE_DSTMYADDR; 386 387 if (ncpaddr_getip4addr(&gw, &ipaddr) && ipaddr == INADDR_ANY) { 388 addrs |= ROUTE_GWHISADDR; 389 ncpaddr_setip4(&gw, bundle->ncp.ipcp.peer_ip); 390 } else if (strcasecmp(argv[1], "HISADDR") == 0) 391 addrs |= ROUTE_GWHISADDR; 392 393 route_Add(&r->routes, addrs, &dest, &gw); 394 } 395 free(nuke); 396 break; 397 398 case RAD_REPLY_MESSAGE: 399 free(r->repstr); 400 if ((r->repstr = rad_cvt_string(data, len)) == NULL) { 401 log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); 402 auth_Failure(r->cx.auth); 403 rad_close(r->cx.rad); 404 return; 405 } 406 log_Printf(LogPHASE, " Reply-Message \"%s\"\n", r->repstr); 407 break; 408 409#ifndef NOINET6 410 case RAD_FRAMED_IPV6_ROUTE: 411 /* 412 * We expect a string of the format ``dest[/bits] gw [metrics]'' 413 * Any specified metrics are ignored. MYADDR6 and HISADDR6 are 414 * understood for ``dest'' and ``gw'' and ``::'' is the same 415 * as ``HISADDR6''. 416 */ 417 418 if ((nuke = rad_cvt_string(data, len)) == NULL) { 419 log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); 420 auth_Failure(r->cx.auth); 421 rad_close(r->cx.rad); 422 return; 423 } 424 425 log_Printf(LogPHASE, " IPv6 Route: %s\n", nuke); 426 bundle = r->cx.auth->physical->dl->bundle; 427 ncpaddr_setip6(&gw, &in6addr_any); 428 ncprange_set(&dest, &gw, 0); 429 argc = command_Interpret(nuke, strlen(nuke), argv); 430 if (argc < 0) 431 log_Printf(LogWARN, "radius: %s: Syntax error\n", 432 argc == 1 ? argv[0] : "\"\""); 433 else if (argc < 2) 434 log_Printf(LogWARN, "radius: %s: Invalid route\n", 435 argc == 1 ? argv[0] : "\"\""); 436 else if ((strcasecmp(argv[0], "default") != 0 && 437 !ncprange_aton(&dest, &bundle->ncp, argv[0])) || 438 !ncpaddr_aton(&gw, &bundle->ncp, argv[1])) 439 log_Printf(LogWARN, "radius: %s %s: Invalid route\n", 440 argv[0], argv[1]); 441 else { 442 addrs = 0; 443 444 if (!strncasecmp(argv[0], "HISADDR6", 8)) 445 addrs = ROUTE_DSTHISADDR6; 446 else if (!strncasecmp(argv[0], "MYADDR6", 7)) 447 addrs = ROUTE_DSTMYADDR6; 448 449 if (ncpaddr_getip6(&gw, &ip6) && IN6_IS_ADDR_UNSPECIFIED(&ip6)) { 450 addrs |= ROUTE_GWHISADDR6; 451 ncpaddr_copy(&gw, &bundle->ncp.ipv6cp.hisaddr); 452 } else if (strcasecmp(argv[1], "HISADDR6") == 0) 453 addrs |= ROUTE_GWHISADDR6; 454 455 route_Add(&r->ipv6routes, addrs, &dest, &gw); 456 } 457 free(nuke); 458 break; 459#endif 460 461 case RAD_VENDOR_SPECIFIC: 462 if ((res = rad_get_vendor_attr(&vendor, &data, &len)) <= 0) { 463 log_Printf(LogERROR, "rad_get_vendor_attr: %s (failing!)\n", 464 rad_strerror(r->cx.rad)); 465 auth_Failure(r->cx.auth); 466 rad_close(r->cx.rad); 467 return; 468 } 469 470 switch (vendor) { 471 case RAD_VENDOR_MICROSOFT: 472 switch (res) { 473#ifndef NODES 474 case RAD_MICROSOFT_MS_CHAP_ERROR: 475 free(r->errstr); 476 if (len == 0) 477 r->errstr = NULL; 478 else { 479 if (len < 3 || ((const char *)data)[1] != '=') { 480 /* 481 * Only point at the String field if we don't think the 482 * peer has misformatted the response. 483 */ 484 ((const char *)data)++; 485 len--; 486 } else 487 log_Printf(LogWARN, "Warning: The MS-CHAP-Error " 488 "attribute is mis-formatted. Compensating\n"); 489 if ((r->errstr = rad_cvt_string((const char *)data, 490 len)) == NULL) { 491 log_Printf(LogERROR, "rad_cvt_string: %s\n", 492 rad_strerror(r->cx.rad)); 493 auth_Failure(r->cx.auth); 494 rad_close(r->cx.rad); 495 return; 496 } 497 log_Printf(LogPHASE, " MS-CHAP-Error \"%s\"\n", r->errstr); 498 } 499 break; 500 501 case RAD_MICROSOFT_MS_CHAP2_SUCCESS: 502 free(r->msrepstr); 503 if (len == 0) 504 r->msrepstr = NULL; 505 else { 506 if (len < 3 || ((const char *)data)[1] != '=') { 507 /* 508 * Only point at the String field if we don't think the 509 * peer has misformatted the response. 510 */ 511 ((const char *)data)++; 512 len--; 513 } else 514 log_Printf(LogWARN, "Warning: The MS-CHAP2-Success " 515 "attribute is mis-formatted. Compensating\n"); 516 if ((r->msrepstr = rad_cvt_string((const char *)data, 517 len)) == NULL) { 518 log_Printf(LogERROR, "rad_cvt_string: %s\n", 519 rad_strerror(r->cx.rad)); 520 auth_Failure(r->cx.auth); 521 rad_close(r->cx.rad); 522 return; 523 } 524 log_Printf(LogPHASE, " MS-CHAP2-Success \"%s\"\n", 525 r->msrepstr); 526 } 527 break; 528 529 case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY: 530 r->mppe.policy = rad_cvt_int(data); 531 log_Printf(LogPHASE, " MS-MPPE-Encryption-Policy %s\n", 532 radius_policyname(r->mppe.policy)); 533 break; 534 535 case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES: 536 r->mppe.types = rad_cvt_int(data); 537 log_Printf(LogPHASE, " MS-MPPE-Encryption-Types %s\n", 538 radius_typesname(r->mppe.types)); 539 break; 540 541 case RAD_MICROSOFT_MS_MPPE_RECV_KEY: 542 free(r->mppe.recvkey); 543 demangle(r, data, len, &r->mppe.recvkey, &r->mppe.recvkeylen); 544 log_Printf(LogPHASE, " MS-MPPE-Recv-Key ********\n"); 545 break; 546 547 case RAD_MICROSOFT_MS_MPPE_SEND_KEY: 548 demangle(r, data, len, &r->mppe.sendkey, &r->mppe.sendkeylen); 549 log_Printf(LogPHASE, " MS-MPPE-Send-Key ********\n"); 550 break; 551#endif 552 553 default: 554 log_Printf(LogDEBUG, "Dropping MICROSOFT vendor specific " 555 "RADIUS attribute %d\n", res); 556 break; 557 } 558 break; 559 560 default: 561 log_Printf(LogDEBUG, "Dropping vendor %lu RADIUS attribute %d\n", 562 (unsigned long)vendor, res); 563 break; 564 } 565 break; 566 567 default: 568 log_Printf(LogDEBUG, "Dropping RADIUS attribute %d\n", res); 569 break; 570 } 571 } 572 573 if (res == -1) { 574 log_Printf(LogERROR, "rad_get_attr: %s (failing!)\n", 575 rad_strerror(r->cx.rad)); 576 auth_Failure(r->cx.auth); 577 } else if (got == RAD_ACCESS_REJECT) 578 auth_Failure(r->cx.auth); 579 else { 580 r->valid = 1; 581 auth_Success(r->cx.auth); 582 } 583 rad_close(r->cx.rad); 584} 585 586/* 587 * We've either timed out or select()ed on the read descriptor 588 */ 589static void 590radius_Continue(struct radius *r, int sel) 591{ 592 struct timeval tv; 593 int got; 594 595 timer_Stop(&r->cx.timer); 596 if ((got = rad_continue_send_request(r->cx.rad, sel, &r->cx.fd, &tv)) == 0) { 597 log_Printf(LogPHASE, "Radius: Request re-sent\n"); 598 r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS; 599 timer_Start(&r->cx.timer); 600 return; 601 } 602 603 radius_Process(r, got); 604} 605 606/* 607 * Time to call rad_continue_send_request() - timed out. 608 */ 609static void 610radius_Timeout(void *v) 611{ 612 radius_Continue((struct radius *)v, 0); 613} 614 615/* 616 * Time to call rad_continue_send_request() - something to read. 617 */ 618static void 619radius_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 620{ 621 radius_Continue(descriptor2radius(d), 1); 622} 623 624/* 625 * Behave as a struct fdescriptor (descriptor.h) 626 */ 627static int 628radius_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 629{ 630 struct radius *rad = descriptor2radius(d); 631 632 if (r && rad->cx.fd != -1) { 633 FD_SET(rad->cx.fd, r); 634 if (*n < rad->cx.fd + 1) 635 *n = rad->cx.fd + 1; 636 log_Printf(LogTIMER, "Radius: fdset(r) %d\n", rad->cx.fd); 637 return 1; 638 } 639 640 return 0; 641} 642 643/* 644 * Behave as a struct fdescriptor (descriptor.h) 645 */ 646static int 647radius_IsSet(struct fdescriptor *d, const fd_set *fdset) 648{ 649 struct radius *r = descriptor2radius(d); 650 651 return r && r->cx.fd != -1 && FD_ISSET(r->cx.fd, fdset); 652} 653 654/* 655 * Behave as a struct fdescriptor (descriptor.h) 656 */ 657static int 658radius_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 659{ 660 /* We never want to write here ! */ 661 log_Printf(LogALERT, "radius_Write: Internal error: Bad call !\n"); 662 return 0; 663} 664 665/* 666 * Initialise ourselves 667 */ 668void 669radius_Init(struct radius *r) 670{ 671 r->desc.type = RADIUS_DESCRIPTOR; 672 r->desc.UpdateSet = radius_UpdateSet; 673 r->desc.IsSet = radius_IsSet; 674 r->desc.Read = radius_Read; 675 r->desc.Write = radius_Write; 676 r->cx.fd = -1; 677 r->cx.rad = NULL; 678 memset(&r->cx.timer, '\0', sizeof r->cx.timer); 679 r->cx.auth = NULL; 680 r->valid = 0; 681 r->vj = 0; 682 r->ip.s_addr = INADDR_ANY; 683 r->mask.s_addr = INADDR_NONE; 684 r->routes = NULL; 685 r->mtu = DEF_MTU; 686 r->msrepstr = NULL; 687 r->repstr = NULL; 688#ifndef NOINET6 689 r->ipv6routes = NULL; 690#endif 691 r->errstr = NULL; 692 r->mppe.policy = 0; 693 r->mppe.types = 0; 694 r->mppe.recvkey = NULL; 695 r->mppe.recvkeylen = 0; 696 r->mppe.sendkey = NULL; 697 r->mppe.sendkeylen = 0; 698 *r->cfg.file = '\0';; 699 log_Printf(LogDEBUG, "Radius: radius_Init\n"); 700} 701 702/* 703 * Forget everything and go back to initialised state. 704 */ 705void 706radius_Destroy(struct radius *r) 707{ 708 r->valid = 0; 709 log_Printf(LogDEBUG, "Radius: radius_Destroy\n"); 710 timer_Stop(&r->cx.timer); 711 route_DeleteAll(&r->routes); 712#ifndef NOINET6 713 route_DeleteAll(&r->ipv6routes); 714#endif 715 free(r->filterid); 716 r->filterid = NULL; 717 free(r->msrepstr); 718 r->msrepstr = NULL; 719 free(r->repstr); 720 r->repstr = NULL; 721 free(r->errstr); 722 r->errstr = NULL; 723 free(r->mppe.recvkey); 724 r->mppe.recvkey = NULL; 725 r->mppe.recvkeylen = 0; 726 free(r->mppe.sendkey); 727 r->mppe.sendkey = NULL; 728 r->mppe.sendkeylen = 0; 729 if (r->cx.fd != -1) { 730 r->cx.fd = -1; 731 rad_close(r->cx.rad); 732 } 733} 734 735static int 736radius_put_physical_details(struct rad_handle *rad, struct physical *p) 737{ 738 int slot, type; 739 740 type = RAD_VIRTUAL; 741 if (p->handler) 742 switch (p->handler->type) { 743 case I4B_DEVICE: 744 type = RAD_ISDN_SYNC; 745 break; 746 747 case TTY_DEVICE: 748 type = RAD_ASYNC; 749 break; 750 751 case ETHER_DEVICE: 752 type = RAD_ETHERNET; 753 break; 754 755 case TCP_DEVICE: 756 case UDP_DEVICE: 757 case EXEC_DEVICE: 758 case ATM_DEVICE: 759 case NG_DEVICE: 760 type = RAD_VIRTUAL; 761 break; 762 } 763 764 if (rad_put_int(rad, RAD_NAS_PORT_TYPE, type) != 0) { 765 log_Printf(LogERROR, "rad_put: rad_put_int: %s\n", rad_strerror(rad)); 766 rad_close(rad); 767 return 0; 768 } 769 770 if ((slot = physical_Slot(p)) >= 0) 771 if (rad_put_int(rad, RAD_NAS_PORT, slot) != 0) { 772 log_Printf(LogERROR, "rad_put: rad_put_int: %s\n", rad_strerror(rad)); 773 rad_close(rad); 774 return 0; 775 } 776 777 return 1; 778} 779 780/* 781 * Start an authentication request to the RADIUS server. 782 */ 783int 784radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name, 785 const char *key, int klen, const char *nchallenge, 786 int nclen) 787{ 788 struct timeval tv; 789 int got; 790 char hostname[MAXHOSTNAMELEN]; 791#if 0 792 struct hostent *hp; 793 struct in_addr hostaddr; 794#endif 795#ifndef NODES 796 struct mschap_response msresp; 797 struct mschap2_response msresp2; 798 const struct MSCHAPv2_resp *keyv2; 799#endif 800 801 if (!*r->cfg.file) 802 return 0; 803 804 if (r->cx.fd != -1) 805 /* 806 * We assume that our name/key/challenge is the same as last time, 807 * and just continue to wait for the RADIUS server(s). 808 */ 809 return 1; 810 811 radius_Destroy(r); 812 813 if ((r->cx.rad = rad_auth_open()) == NULL) { 814 log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno)); 815 return 0; 816 } 817 818 if (rad_config(r->cx.rad, r->cfg.file) != 0) { 819 log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad)); 820 rad_close(r->cx.rad); 821 return 0; 822 } 823 824 if (rad_create_request(r->cx.rad, RAD_ACCESS_REQUEST) != 0) { 825 log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad)); 826 rad_close(r->cx.rad); 827 return 0; 828 } 829 830 if (rad_put_string(r->cx.rad, RAD_USER_NAME, name) != 0 || 831 rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 || 832 rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) { 833 log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 834 rad_close(r->cx.rad); 835 return 0; 836 } 837 838 switch (authp->physical->link.lcp.want_auth) { 839 case PROTO_PAP: 840 /* We're talking PAP */ 841 if (rad_put_attr(r->cx.rad, RAD_USER_PASSWORD, key, klen) != 0) { 842 log_Printf(LogERROR, "PAP: rad_put_string: %s\n", 843 rad_strerror(r->cx.rad)); 844 rad_close(r->cx.rad); 845 return 0; 846 } 847 break; 848 849 case PROTO_CHAP: 850 switch (authp->physical->link.lcp.want_authtype) { 851 case 0x5: 852 if (rad_put_attr(r->cx.rad, RAD_CHAP_PASSWORD, key, klen) != 0 || 853 rad_put_attr(r->cx.rad, RAD_CHAP_CHALLENGE, nchallenge, nclen) != 0) { 854 log_Printf(LogERROR, "CHAP: rad_put_string: %s\n", 855 rad_strerror(r->cx.rad)); 856 rad_close(r->cx.rad); 857 return 0; 858 } 859 break; 860 861#ifndef NODES 862 case 0x80: 863 if (klen != 50) { 864 log_Printf(LogERROR, "CHAP80: Unrecognised key length %d\n", klen); 865 rad_close(r->cx.rad); 866 return 0; 867 } 868 869 rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT, 870 RAD_MICROSOFT_MS_CHAP_CHALLENGE, nchallenge, nclen); 871 msresp.ident = *key; 872 msresp.flags = 0x01; 873 memcpy(msresp.lm_response, key + 1, 24); 874 memcpy(msresp.nt_response, key + 25, 24); 875 rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT, 876 RAD_MICROSOFT_MS_CHAP_RESPONSE, &msresp, 877 sizeof msresp); 878 break; 879 880 case 0x81: 881 if (klen != sizeof(*keyv2) + 1) { 882 log_Printf(LogERROR, "CHAP81: Unrecognised key length %d\n", klen); 883 rad_close(r->cx.rad); 884 return 0; 885 } 886 887 keyv2 = (const struct MSCHAPv2_resp *)(key + 1); 888 rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT, 889 RAD_MICROSOFT_MS_CHAP_CHALLENGE, nchallenge, nclen); 890 msresp2.ident = *key; 891 msresp2.flags = keyv2->Flags; 892 memcpy(msresp2.response, keyv2->NTResponse, sizeof msresp2.response); 893 memset(msresp2.reserved, '\0', sizeof msresp2.reserved); 894 memcpy(msresp2.pchallenge, keyv2->PeerChallenge, 895 sizeof msresp2.pchallenge); 896 rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT, 897 RAD_MICROSOFT_MS_CHAP2_RESPONSE, &msresp2, 898 sizeof msresp2); 899 break; 900#endif 901 default: 902 log_Printf(LogERROR, "CHAP: Unrecognised type 0x%02x\n", 903 authp->physical->link.lcp.want_authtype); 904 rad_close(r->cx.rad); 905 return 0; 906 } 907 } 908 909 if (gethostname(hostname, sizeof hostname) != 0) 910 log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno)); 911 else { 912#if 0 913 if ((hp = gethostbyname(hostname)) != NULL) { 914 hostaddr.s_addr = *(u_long *)hp->h_addr; 915 if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) { 916 log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 917 rad_strerror(r->cx.rad)); 918 rad_close(r->cx.rad); 919 return 0; 920 } 921 } 922#endif 923 if (rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) { 924 log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 925 rad_strerror(r->cx.rad)); 926 rad_close(r->cx.rad); 927 return 0; 928 } 929 } 930 931 radius_put_physical_details(r->cx.rad, authp->physical); 932 933 r->cx.auth = authp; 934 if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv))) 935 radius_Process(r, got); 936 else { 937 log_Printf(LogPHASE, "Radius: Request sent\n"); 938 log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout); 939 r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS; 940 r->cx.timer.func = radius_Timeout; 941 r->cx.timer.name = "radius auth"; 942 r->cx.timer.arg = r; 943 timer_Start(&r->cx.timer); 944 } 945 946 return 1; 947} 948 949/* 950 * Send an accounting request to the RADIUS server 951 */ 952void 953radius_Account(struct radius *r, struct radacct *ac, struct datalink *dl, 954 int acct_type, struct in_addr *peer_ip, struct in_addr *netmask, 955 struct pppThroughput *stats) 956{ 957 struct timeval tv; 958 int got; 959 char hostname[MAXHOSTNAMELEN]; 960#if 0 961 struct hostent *hp; 962 struct in_addr hostaddr; 963#endif 964 965 if (!*r->cfg.file) 966 return; 967 968 if (r->cx.fd != -1) 969 /* 970 * We assume that our name/key/challenge is the same as last time, 971 * and just continue to wait for the RADIUS server(s). 972 */ 973 return; 974 975 timer_Stop(&r->cx.timer); 976 977 if ((r->cx.rad = rad_acct_open()) == NULL) { 978 log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno)); 979 return; 980 } 981 982 if (rad_config(r->cx.rad, r->cfg.file) != 0) { 983 log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad)); 984 rad_close(r->cx.rad); 985 return; 986 } 987 988 if (rad_create_request(r->cx.rad, RAD_ACCOUNTING_REQUEST) != 0) { 989 log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad)); 990 rad_close(r->cx.rad); 991 return; 992 } 993 994 /* Grab some accounting data and initialize structure */ 995 if (acct_type == RAD_START) { 996 ac->rad_parent = r; 997 /* Fetch username from datalink */ 998 strncpy(ac->user_name, dl->peer.authname, sizeof ac->user_name); 999 ac->user_name[AUTHLEN-1] = '\0'; 1000 1001 ac->authentic = 2; /* Assume RADIUS verified auth data */ 1002 1003 /* Generate a session ID */ 1004 snprintf(ac->session_id, sizeof ac->session_id, "%s%ld-%s%lu", 1005 dl->bundle->cfg.auth.name, (long)getpid(), 1006 dl->peer.authname, (unsigned long)stats->uptime); 1007 1008 /* And grab our MP socket name */ 1009 snprintf(ac->multi_session_id, sizeof ac->multi_session_id, "%s", 1010 dl->bundle->ncp.mp.active ? 1011 dl->bundle->ncp.mp.server.socket.sun_path : ""); 1012 1013 /* Fetch IP, netmask from IPCP */ 1014 memcpy(&ac->ip, peer_ip, sizeof(ac->ip)); 1015 memcpy(&ac->mask, netmask, sizeof(ac->mask)); 1016 }; 1017 1018 if (rad_put_string(r->cx.rad, RAD_USER_NAME, ac->user_name) != 0 || 1019 rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 || 1020 rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0 || 1021 rad_put_addr(r->cx.rad, RAD_FRAMED_IP_ADDRESS, ac->ip) != 0 || 1022 rad_put_addr(r->cx.rad, RAD_FRAMED_IP_NETMASK, ac->mask) != 0) { 1023 log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 1024 rad_close(r->cx.rad); 1025 return; 1026 } 1027 1028 if (gethostname(hostname, sizeof hostname) != 0) 1029 log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno)); 1030 else { 1031#if 0 1032 if ((hp = gethostbyname(hostname)) != NULL) { 1033 hostaddr.s_addr = *(u_long *)hp->h_addr; 1034 if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) { 1035 log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 1036 rad_strerror(r->cx.rad)); 1037 rad_close(r->cx.rad); 1038 return; 1039 } 1040 } 1041#endif 1042 if (rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) { 1043 log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 1044 rad_strerror(r->cx.rad)); 1045 rad_close(r->cx.rad); 1046 return; 1047 } 1048 } 1049 1050 radius_put_physical_details(r->cx.rad, dl->physical); 1051 1052 if (rad_put_int(r->cx.rad, RAD_ACCT_STATUS_TYPE, acct_type) != 0 || 1053 rad_put_string(r->cx.rad, RAD_ACCT_SESSION_ID, ac->session_id) != 0 || 1054 rad_put_string(r->cx.rad, RAD_ACCT_MULTI_SESSION_ID, 1055 ac->multi_session_id) != 0 || 1056 rad_put_int(r->cx.rad, RAD_ACCT_DELAY_TIME, 0) != 0) { 1057/* XXX ACCT_DELAY_TIME should be increased each time a packet is waiting */ 1058 log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 1059 rad_close(r->cx.rad); 1060 return; 1061 } 1062 1063 if (acct_type == RAD_STOP) 1064 /* Show some statistics */ 1065 if (rad_put_int(r->cx.rad, RAD_ACCT_INPUT_OCTETS, stats->OctetsIn) != 0 || 1066 rad_put_int(r->cx.rad, RAD_ACCT_INPUT_PACKETS, stats->PacketsIn) != 0 || 1067 rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_OCTETS, stats->OctetsOut) != 0 || 1068 rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_PACKETS, stats->PacketsOut) 1069 != 0 || 1070 rad_put_int(r->cx.rad, RAD_ACCT_SESSION_TIME, throughput_uptime(stats)) 1071 != 0) { 1072 log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 1073 rad_close(r->cx.rad); 1074 return; 1075 } 1076 1077 r->cx.auth = NULL; /* Not valid for accounting requests */ 1078 if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv))) 1079 radius_Process(r, got); 1080 else { 1081 log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout); 1082 r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS; 1083 r->cx.timer.func = radius_Timeout; 1084 r->cx.timer.name = "radius acct"; 1085 r->cx.timer.arg = r; 1086 timer_Start(&r->cx.timer); 1087 } 1088} 1089 1090/* 1091 * How do things look at the moment ? 1092 */ 1093void 1094radius_Show(struct radius *r, struct prompt *p) 1095{ 1096 prompt_Printf(p, " Radius config: %s", 1097 *r->cfg.file ? r->cfg.file : "none"); 1098 if (r->valid) { 1099 prompt_Printf(p, "\n IP: %s\n", inet_ntoa(r->ip)); 1100 prompt_Printf(p, " Netmask: %s\n", inet_ntoa(r->mask)); 1101 prompt_Printf(p, " MTU: %lu\n", r->mtu); 1102 prompt_Printf(p, " VJ: %sabled\n", r->vj ? "en" : "dis"); 1103 prompt_Printf(p, " Message: %s\n", r->repstr ? r->repstr : ""); 1104 prompt_Printf(p, " MPPE Enc Policy: %s\n", 1105 radius_policyname(r->mppe.policy)); 1106 prompt_Printf(p, " MPPE Enc Types: %s\n", 1107 radius_typesname(r->mppe.types)); 1108 prompt_Printf(p, " MPPE Recv Key: %seceived\n", 1109 r->mppe.recvkey ? "R" : "Not r"); 1110 prompt_Printf(p, " MPPE Send Key: %seceived\n", 1111 r->mppe.sendkey ? "R" : "Not r"); 1112 prompt_Printf(p, " MS-CHAP2-Response: %s\n", 1113 r->msrepstr ? r->msrepstr : ""); 1114 prompt_Printf(p, " Error Message: %s\n", r->errstr ? r->errstr : ""); 1115 if (r->routes) 1116 route_ShowSticky(p, r->routes, " Routes", 16); 1117#ifndef NOINET6 1118 if (r->ipv6routes) 1119 route_ShowSticky(p, r->ipv6routes, " IPv6 Routes", 16); 1120#endif 1121 } else 1122 prompt_Printf(p, " (not authenticated)\n"); 1123} 1124