radius.c revision 65178
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 65178 2000-08-28 22:44:54Z brian $ 27 * 28 */ 29 30#include <sys/param.h> 31#include <sys/socket.h> 32#include <netinet/in_systm.h> 33#include <netinet/in.h> 34#include <netinet/ip.h> 35#include <arpa/inet.h> 36#include <sys/un.h> 37#include <net/route.h> 38 39#ifdef LOCALRAD 40#include "radlib.h" 41#else 42#include <radlib.h> 43#endif 44 45#include <errno.h> 46#include <stdio.h> 47#include <stdlib.h> 48#include <string.h> 49#include <sys/time.h> 50#include <termios.h> 51#include <ttyent.h> 52#include <unistd.h> 53#include <netdb.h> 54 55#include "layer.h" 56#include "defs.h" 57#include "log.h" 58#include "descriptor.h" 59#include "prompt.h" 60#include "timer.h" 61#include "fsm.h" 62#include "iplist.h" 63#include "slcompress.h" 64#include "throughput.h" 65#include "lqr.h" 66#include "hdlc.h" 67#include "mbuf.h" 68#include "ipcp.h" 69#include "route.h" 70#include "command.h" 71#include "filter.h" 72#include "lcp.h" 73#include "ccp.h" 74#include "link.h" 75#include "mp.h" 76#include "radius.h" 77#include "auth.h" 78#include "async.h" 79#include "physical.h" 80#include "chat.h" 81#include "cbcp.h" 82#include "chap.h" 83#include "datalink.h" 84#include "bundle.h" 85 86/* 87 * rad_continue_send_request() has given us `got' (non-zero). Deal with it. 88 */ 89static void 90radius_Process(struct radius *r, int got) 91{ 92 char *argv[MAXARGS], *nuke; 93 struct bundle *bundle; 94 int argc, addrs; 95 size_t len; 96 struct in_range dest; 97 struct in_addr gw; 98 const void *data; 99 100 r->cx.fd = -1; /* Stop select()ing */ 101 102 switch (got) { 103 case RAD_ACCESS_ACCEPT: 104 log_Printf(LogPHASE, "Radius: ACCEPT received\n"); 105 break; 106 107 case RAD_ACCESS_REJECT: 108 log_Printf(LogPHASE, "Radius: REJECT received\n"); 109 auth_Failure(r->cx.auth); 110 rad_close(r->cx.rad); 111 return; 112 113 case RAD_ACCESS_CHALLENGE: 114 /* we can't deal with this (for now) ! */ 115 log_Printf(LogPHASE, "Radius: CHALLENGE received (can't handle yet)\n"); 116 auth_Failure(r->cx.auth); 117 rad_close(r->cx.rad); 118 return; 119 120 case RAD_ACCOUNTING_RESPONSE: 121 log_Printf(LogPHASE, "Radius: Accounting response received\n"); 122 /* No further processing for accounting requests, please */ 123 rad_close(r->cx.rad); 124 return; 125 126 case -1: 127 log_Printf(LogPHASE, "radius: %s\n", rad_strerror(r->cx.rad)); 128 auth_Failure(r->cx.auth); 129 rad_close(r->cx.rad); 130 return; 131 132 default: 133 log_Printf(LogERROR, "rad_send_request: Failed %d: %s\n", 134 got, rad_strerror(r->cx.rad)); 135 auth_Failure(r->cx.auth); 136 rad_close(r->cx.rad); 137 return; 138 } 139 140 /* So we've been accepted ! Let's see what we've got in our reply :-I */ 141 r->ip.s_addr = r->mask.s_addr = INADDR_NONE; 142 r->mtu = 0; 143 r->vj = 0; 144 while ((got = rad_get_attr(r->cx.rad, &data, &len)) > 0) { 145 switch (got) { 146 case RAD_FRAMED_IP_ADDRESS: 147 r->ip = rad_cvt_addr(data); 148 log_Printf(LogPHASE, " IP %s\n", inet_ntoa(r->ip)); 149 break; 150 151 case RAD_FRAMED_IP_NETMASK: 152 r->mask = rad_cvt_addr(data); 153 log_Printf(LogPHASE, " Netmask %s\n", inet_ntoa(r->mask)); 154 break; 155 156 case RAD_FRAMED_MTU: 157 r->mtu = rad_cvt_int(data); 158 log_Printf(LogPHASE, " MTU %lu\n", r->mtu); 159 break; 160 161 case RAD_FRAMED_ROUTING: 162 /* Disabled for now - should we automatically set up some filters ? */ 163 /* rad_cvt_int(data); */ 164 /* bit 1 = Send routing packets */ 165 /* bit 2 = Receive routing packets */ 166 break; 167 168 case RAD_FRAMED_COMPRESSION: 169 r->vj = rad_cvt_int(data) == 1 ? 1 : 0; 170 log_Printf(LogPHASE, " VJ %sabled\n", r->vj ? "en" : "dis"); 171 break; 172 173 case RAD_FRAMED_ROUTE: 174 /* 175 * We expect a string of the format ``dest[/bits] gw [metrics]'' 176 * Any specified metrics are ignored. MYADDR and HISADDR are 177 * understood for ``dest'' and ``gw'' and ``0.0.0.0'' is the same 178 * as ``HISADDR''. 179 */ 180 181 if ((nuke = rad_cvt_string(data, len)) == NULL) { 182 log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); 183 rad_close(r->cx.rad); 184 return; 185 } 186 187 log_Printf(LogPHASE, " Route: %s\n", nuke); 188 bundle = r->cx.auth->physical->dl->bundle; 189 dest.ipaddr.s_addr = dest.mask.s_addr = INADDR_ANY; 190 dest.width = 0; 191 argc = command_Interpret(nuke, strlen(nuke), argv); 192 if (argc < 0) 193 log_Printf(LogWARN, "radius: %s: Syntax error\n", 194 argc == 1 ? argv[0] : "\"\""); 195 else if (argc < 2) 196 log_Printf(LogWARN, "radius: %s: Invalid route\n", 197 argc == 1 ? argv[0] : "\"\""); 198 else if ((strcasecmp(argv[0], "default") != 0 && 199 !ParseAddr(&bundle->ncp.ipcp, argv[0], &dest.ipaddr, 200 &dest.mask, &dest.width)) || 201 !ParseAddr(&bundle->ncp.ipcp, argv[1], &gw, NULL, NULL)) 202 log_Printf(LogWARN, "radius: %s %s: Invalid route\n", 203 argv[0], argv[1]); 204 else { 205 if (dest.width == 32 && strchr(argv[0], '/') == NULL) 206 /* No mask specified - use the natural mask */ 207 dest.mask = addr2mask(dest.ipaddr); 208 addrs = 0; 209 210 if (!strncasecmp(argv[0], "HISADDR", 7)) 211 addrs = ROUTE_DSTHISADDR; 212 else if (!strncasecmp(argv[0], "MYADDR", 6)) 213 addrs = ROUTE_DSTMYADDR; 214 215 if (gw.s_addr == INADDR_ANY) { 216 addrs |= ROUTE_GWHISADDR; 217 gw = bundle->ncp.ipcp.peer_ip; 218 } else if (strcasecmp(argv[1], "HISADDR") == 0) 219 addrs |= ROUTE_GWHISADDR; 220 221 route_Add(&r->routes, addrs, dest.ipaddr, dest.mask, gw); 222 } 223 free(nuke); 224 break; 225 } 226 } 227 228 if (got == -1) { 229 log_Printf(LogERROR, "rad_get_attr: %s (failing!)\n", 230 rad_strerror(r->cx.rad)); 231 auth_Failure(r->cx.auth); 232 rad_close(r->cx.rad); 233 } else { 234 r->valid = 1; 235 auth_Success(r->cx.auth); 236 rad_close(r->cx.rad); 237 } 238} 239 240/* 241 * We've either timed out or select()ed on the read descriptor 242 */ 243static void 244radius_Continue(struct radius *r, int sel) 245{ 246 struct timeval tv; 247 int got; 248 249 timer_Stop(&r->cx.timer); 250 if ((got = rad_continue_send_request(r->cx.rad, sel, &r->cx.fd, &tv)) == 0) { 251 log_Printf(LogPHASE, "Radius: Request re-sent\n"); 252 r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS; 253 timer_Start(&r->cx.timer); 254 return; 255 } 256 257 radius_Process(r, got); 258} 259 260/* 261 * Time to call rad_continue_send_request() - timed out. 262 */ 263static void 264radius_Timeout(void *v) 265{ 266 radius_Continue((struct radius *)v, 0); 267} 268 269/* 270 * Time to call rad_continue_send_request() - something to read. 271 */ 272static void 273radius_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 274{ 275 radius_Continue(descriptor2radius(d), 1); 276} 277 278/* 279 * Behave as a struct fdescriptor (descriptor.h) 280 */ 281static int 282radius_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 283{ 284 struct radius *rad = descriptor2radius(d); 285 286 if (r && rad->cx.fd != -1) { 287 FD_SET(rad->cx.fd, r); 288 if (*n < rad->cx.fd + 1) 289 *n = rad->cx.fd + 1; 290 log_Printf(LogTIMER, "Radius: fdset(r) %d\n", rad->cx.fd); 291 return 1; 292 } 293 294 return 0; 295} 296 297/* 298 * Behave as a struct fdescriptor (descriptor.h) 299 */ 300static int 301radius_IsSet(struct fdescriptor *d, const fd_set *fdset) 302{ 303 struct radius *r = descriptor2radius(d); 304 305 return r && r->cx.fd != -1 && FD_ISSET(r->cx.fd, fdset); 306} 307 308/* 309 * Behave as a struct fdescriptor (descriptor.h) 310 */ 311static int 312radius_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 313{ 314 /* We never want to write here ! */ 315 log_Printf(LogALERT, "radius_Write: Internal error: Bad call !\n"); 316 return 0; 317} 318 319/* 320 * Initialise ourselves 321 */ 322void 323radius_Init(struct radius *r) 324{ 325 r->valid = 0; 326 r->cx.fd = -1; 327 *r->cfg.file = '\0';; 328 r->desc.type = RADIUS_DESCRIPTOR; 329 r->desc.UpdateSet = radius_UpdateSet; 330 r->desc.IsSet = radius_IsSet; 331 r->desc.Read = radius_Read; 332 r->desc.Write = radius_Write; 333 memset(&r->cx.timer, '\0', sizeof r->cx.timer); 334 log_Printf(LogDEBUG, "Radius: radius_Init\n"); 335} 336 337/* 338 * Forget everything and go back to initialised state. 339 */ 340void 341radius_Destroy(struct radius *r) 342{ 343 r->valid = 0; 344 log_Printf(LogDEBUG, "Radius: radius_Destroy\n"); 345 timer_Stop(&r->cx.timer); 346 route_DeleteAll(&r->routes); 347 if (r->cx.fd != -1) { 348 r->cx.fd = -1; 349 rad_close(r->cx.rad); 350 } 351} 352 353/* 354 * Start an authentication request to the RADIUS server. 355 */ 356void 357radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name, 358 const char *key, const char *challenge) 359{ 360 struct ttyent *ttyp; 361 struct timeval tv; 362 int got, slot; 363 char hostname[MAXHOSTNAMELEN]; 364 struct hostent *hp; 365 struct in_addr hostaddr; 366 367 if (!*r->cfg.file) 368 return; 369 370 if (r->cx.fd != -1) 371 /* 372 * We assume that our name/key/challenge is the same as last time, 373 * and just continue to wait for the RADIUS server(s). 374 */ 375 return; 376 377 radius_Destroy(r); 378 379 if ((r->cx.rad = rad_auth_open()) == NULL) { 380 log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno)); 381 return; 382 } 383 384 if (rad_config(r->cx.rad, r->cfg.file) != 0) { 385 log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad)); 386 rad_close(r->cx.rad); 387 return; 388 } 389 390 if (rad_create_request(r->cx.rad, RAD_ACCESS_REQUEST) != 0) { 391 log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad)); 392 rad_close(r->cx.rad); 393 return; 394 } 395 396 if (rad_put_string(r->cx.rad, RAD_USER_NAME, name) != 0 || 397 rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 || 398 rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) { 399 log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 400 rad_close(r->cx.rad); 401 return; 402 } 403 404 if (challenge != NULL) { 405 /* We're talking CHAP */ 406 if (rad_put_string(r->cx.rad, RAD_CHAP_PASSWORD, key) != 0 || 407 rad_put_string(r->cx.rad, RAD_CHAP_CHALLENGE, challenge) != 0) { 408 log_Printf(LogERROR, "CHAP: rad_put_string: %s\n", 409 rad_strerror(r->cx.rad)); 410 rad_close(r->cx.rad); 411 return; 412 } 413 } else if (rad_put_string(r->cx.rad, RAD_USER_PASSWORD, key) != 0) { 414 /* We're talking PAP */ 415 log_Printf(LogERROR, "PAP: rad_put_string: %s\n", rad_strerror(r->cx.rad)); 416 rad_close(r->cx.rad); 417 return; 418 } 419 420 if (gethostname(hostname, sizeof hostname) != 0) 421 log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno)); 422 else { 423 if ((hp = gethostbyname(hostname)) != NULL) { 424 hostaddr.s_addr = *(u_long *)hp->h_addr; 425 if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) { 426 log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 427 rad_strerror(r->cx.rad)); 428 rad_close(r->cx.rad); 429 return; 430 } 431 } 432 if (rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) { 433 log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 434 rad_strerror(r->cx.rad)); 435 rad_close(r->cx.rad); 436 return; 437 } 438 } 439 440 if (authp->physical->handler && 441 authp->physical->handler->type == TTY_DEVICE) { 442 setttyent(); 443 for (slot = 1; (ttyp = getttyent()); ++slot) 444 if (!strcmp(ttyp->ty_name, authp->physical->name.base)) { 445 if(rad_put_int(r->cx.rad, RAD_NAS_PORT, slot) != 0) { 446 log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 447 rad_strerror(r->cx.rad)); 448 rad_close(r->cx.rad); 449 endttyent(); 450 return; 451 } 452 break; 453 } 454 endttyent(); 455 } 456 457 458 if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv))) 459 radius_Process(r, got); 460 else { 461 log_Printf(LogPHASE, "Radius: Request sent\n"); 462 log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout); 463 r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS; 464 r->cx.timer.func = radius_Timeout; 465 r->cx.timer.name = "radius"; 466 r->cx.timer.arg = r; 467 r->cx.auth = authp; 468 timer_Start(&r->cx.timer); 469 } 470} 471 472/* 473 * Send an accounting request to the RADIUS server 474 */ 475void 476radius_Account(struct radius *r, struct radacct *ac, struct datalink *dl, 477 int acct_type, struct in_addr *peer_ip, struct in_addr *netmask, 478 struct pppThroughput *stats) 479{ 480 struct ttyent *ttyp; 481 struct timeval tv; 482 int got, slot; 483 char hostname[MAXHOSTNAMELEN]; 484 struct hostent *hp; 485 struct in_addr hostaddr; 486 487 if (!*r->cfg.file) 488 return; 489 490 if (r->cx.fd != -1) 491 /* 492 * We assume that our name/key/challenge is the same as last time, 493 * and just continue to wait for the RADIUS server(s). 494 */ 495 return; 496 497 radius_Destroy(r); 498 499 if ((r->cx.rad = rad_auth_open()) == NULL) { 500 log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno)); 501 return; 502 } 503 504 if (rad_config(r->cx.rad, r->cfg.file) != 0) { 505 log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad)); 506 rad_close(r->cx.rad); 507 return; 508 } 509 510 if (rad_create_request(r->cx.rad, RAD_ACCOUNTING_REQUEST) != 0) { 511 log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad)); 512 rad_close(r->cx.rad); 513 return; 514 } 515 516 /* Grab some accounting data and initialize structure */ 517 if (acct_type == RAD_START) { 518 ac->rad_parent = r; 519 /* Fetch username from datalink */ 520 strncpy(ac->user_name, dl->peer.authname, sizeof ac->user_name); 521 ac->user_name[AUTHLEN-1] = '\0'; 522 523 ac->authentic = 2; /* Assume RADIUS verified auth data */ 524 525 /* Generate a session ID */ 526 snprintf(ac->session_id, sizeof ac->session_id, "%s%d-%s%lu", 527 dl->bundle->cfg.auth.name, (int)getpid(), 528 dl->peer.authname, (unsigned long)stats->uptime); 529 530 /* And grab our MP socket name */ 531 snprintf(ac->multi_session_id, sizeof ac->multi_session_id, "%s", 532 dl->bundle->ncp.mp.active ? 533 dl->bundle->ncp.mp.server.socket.sun_path : ""); 534 535 /* Fetch IP, netmask from IPCP */ 536 memcpy(&ac->ip, peer_ip, sizeof(ac->ip)); 537 memcpy(&ac->mask, netmask, sizeof(ac->mask)); 538 }; 539 540 if (rad_put_string(r->cx.rad, RAD_USER_NAME, ac->user_name) != 0 || 541 rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 || 542 rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0 || 543 rad_put_addr(r->cx.rad, RAD_FRAMED_IP_ADDRESS, ac->ip) != 0 || 544 rad_put_addr(r->cx.rad, RAD_FRAMED_IP_NETMASK, ac->mask) != 0) { 545 log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 546 rad_close(r->cx.rad); 547 return; 548 } 549 550 if (gethostname(hostname, sizeof hostname) != 0) 551 log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno)); 552 else { 553 if ((hp = gethostbyname(hostname)) != NULL) { 554 hostaddr.s_addr = *(u_long *)hp->h_addr; 555 if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) { 556 log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 557 rad_strerror(r->cx.rad)); 558 rad_close(r->cx.rad); 559 return; 560 } 561 } 562 if (rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) { 563 log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 564 rad_strerror(r->cx.rad)); 565 rad_close(r->cx.rad); 566 return; 567 } 568 } 569 570 if (dl->physical->handler && 571 dl->physical->handler->type == TTY_DEVICE) { 572 setttyent(); 573 for (slot = 1; (ttyp = getttyent()); ++slot) 574 if (!strcmp(ttyp->ty_name, dl->physical->name.base)) { 575 if(rad_put_int(r->cx.rad, RAD_NAS_PORT, slot) != 0) { 576 log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 577 rad_strerror(r->cx.rad)); 578 rad_close(r->cx.rad); 579 endttyent(); 580 return; 581 } 582 break; 583 } 584 endttyent(); 585 } 586 587 if (rad_put_int(r->cx.rad, RAD_ACCT_STATUS_TYPE, acct_type) != 0 || 588 rad_put_string(r->cx.rad, RAD_ACCT_SESSION_ID, ac->session_id) != 0 || 589 rad_put_string(r->cx.rad, RAD_ACCT_MULTI_SESSION_ID, 590 ac->multi_session_id) != 0 || 591 rad_put_int(r->cx.rad, RAD_ACCT_DELAY_TIME, 0) != 0) { 592/* XXX ACCT_DELAY_TIME should be increased each time a packet is waiting */ 593 log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 594 rad_close(r->cx.rad); 595 return; 596 } 597 598 if (acct_type == RAD_STOP) 599 /* Show some statistics */ 600 if (rad_put_int(r->cx.rad, RAD_ACCT_INPUT_OCTETS, stats->OctetsIn) != 0 || 601 rad_put_int(r->cx.rad, RAD_ACCT_INPUT_PACKETS, stats->PacketsIn) != 0 || 602 rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_OCTETS, stats->OctetsOut) != 0 || 603 rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_PACKETS, stats->PacketsOut) 604 != 0 || 605 rad_put_int(r->cx.rad, RAD_ACCT_SESSION_TIME, throughput_uptime(stats)) 606 != 0) { 607 log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 608 rad_close(r->cx.rad); 609 return; 610 } 611 612 if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv))) 613 radius_Process(r, got); 614 else { 615 log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout); 616 r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS; 617 r->cx.timer.func = radius_Timeout; 618 r->cx.timer.name = "radius"; 619 r->cx.timer.arg = r; 620 r->cx.auth = NULL; /* Not valid for accounting requests */ 621 timer_Start(&r->cx.timer); 622 } 623} 624 625/* 626 * How do things look at the moment ? 627 */ 628void 629radius_Show(struct radius *r, struct prompt *p) 630{ 631 prompt_Printf(p, " Radius config: %s", *r->cfg.file ? r->cfg.file : "none"); 632 if (r->valid) { 633 prompt_Printf(p, "\n IP: %s\n", inet_ntoa(r->ip)); 634 prompt_Printf(p, " Netmask: %s\n", inet_ntoa(r->mask)); 635 prompt_Printf(p, " MTU: %lu\n", r->mtu); 636 prompt_Printf(p, " VJ: %sabled\n", r->vj ? "en" : "dis"); 637 if (r->routes) 638 route_ShowSticky(p, r->routes, " Routes", 16); 639 } else 640 prompt_Printf(p, " (not authenticated)\n"); 641} 642