radius.c revision 58038
143313Sbrian/* 243313Sbrian * Copyright 1999 Internet Business Solutions Ltd., Switzerland 343313Sbrian * All rights reserved. 443313Sbrian * 543313Sbrian * Redistribution and use in source and binary forms, with or without 643313Sbrian * modification, are permitted provided that the following conditions 743313Sbrian * are met: 843313Sbrian * 1. Redistributions of source code must retain the above copyright 943313Sbrian * notice, this list of conditions and the following disclaimer. 1043313Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1143313Sbrian * notice, this list of conditions and the following disclaimer in the 1243313Sbrian * documentation and/or other materials provided with the distribution. 1343313Sbrian * 1443313Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1543313Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1643313Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1743313Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1843313Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1943313Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2043313Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2143313Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2243313Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2343313Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2443313Sbrian * SUCH DAMAGE. 2543313Sbrian * 2650479Speter * $FreeBSD: head/usr.sbin/ppp/radius.c 58038 2000-03-14 01:47:07Z brian $ 2743313Sbrian * 2843313Sbrian */ 2943313Sbrian 3043313Sbrian#include <sys/param.h> 3158032Sbrian#include <sys/socket.h> 3243313Sbrian#include <netinet/in_systm.h> 3343313Sbrian#include <netinet/in.h> 3443313Sbrian#include <netinet/ip.h> 3543313Sbrian#include <arpa/inet.h> 3643313Sbrian#include <sys/un.h> 3758032Sbrian#include <net/route.h> 3843313Sbrian 3958037Sbrian#ifdef LOCALRAD 4058037Sbrian#include "radlib.h" 4158037Sbrian#else 4258037Sbrian#include <radlib.h> 4358037Sbrian#endif 4458037Sbrian 4543313Sbrian#include <errno.h> 4643313Sbrian#include <stdio.h> 4743313Sbrian#include <stdlib.h> 4843313Sbrian#include <string.h> 4943693Sbrian#include <sys/time.h> 5043313Sbrian#include <termios.h> 5150840Sbrian#include <ttyent.h> 5250840Sbrian#include <unistd.h> 5350840Sbrian#include <netdb.h> 5443313Sbrian 5546686Sbrian#include "layer.h" 5643313Sbrian#include "defs.h" 5743313Sbrian#include "log.h" 5843313Sbrian#include "descriptor.h" 5943313Sbrian#include "prompt.h" 6043313Sbrian#include "timer.h" 6143313Sbrian#include "fsm.h" 6243313Sbrian#include "iplist.h" 6343313Sbrian#include "slcompress.h" 6443313Sbrian#include "throughput.h" 6543313Sbrian#include "lqr.h" 6643313Sbrian#include "hdlc.h" 6743313Sbrian#include "mbuf.h" 6843313Sbrian#include "ipcp.h" 6943313Sbrian#include "route.h" 7043313Sbrian#include "command.h" 7143313Sbrian#include "filter.h" 7243313Sbrian#include "lcp.h" 7343313Sbrian#include "ccp.h" 7443313Sbrian#include "link.h" 7543313Sbrian#include "mp.h" 7643313Sbrian#include "radius.h" 7743693Sbrian#include "auth.h" 7843693Sbrian#include "async.h" 7943693Sbrian#include "physical.h" 8043693Sbrian#include "chat.h" 8143693Sbrian#include "cbcp.h" 8243693Sbrian#include "chap.h" 8343693Sbrian#include "datalink.h" 8443313Sbrian#include "bundle.h" 8543313Sbrian 8643693Sbrian/* 8743693Sbrian * rad_continue_send_request() has given us `got' (non-zero). Deal with it. 8843693Sbrian */ 8943693Sbrianstatic void 9043693Sbrianradius_Process(struct radius *r, int got) 9143313Sbrian{ 9243313Sbrian char *argv[MAXARGS], *nuke; 9343693Sbrian struct bundle *bundle; 9445910Sbrian int argc, addrs; 9545910Sbrian size_t len; 9643313Sbrian struct in_range dest; 9743313Sbrian struct in_addr gw; 9843693Sbrian const void *data; 9943313Sbrian 10043693Sbrian r->cx.fd = -1; /* Stop select()ing */ 10143313Sbrian 10243313Sbrian switch (got) { 10343313Sbrian case RAD_ACCESS_ACCEPT: 10443693Sbrian log_Printf(LogPHASE, "Radius: ACCEPT received\n"); 10543313Sbrian break; 10643313Sbrian 10743693Sbrian case RAD_ACCESS_REJECT: 10843693Sbrian log_Printf(LogPHASE, "Radius: REJECT received\n"); 10943693Sbrian auth_Failure(r->cx.auth); 11043693Sbrian rad_close(r->cx.rad); 11143693Sbrian return; 11243693Sbrian 11343313Sbrian case RAD_ACCESS_CHALLENGE: 11443313Sbrian /* we can't deal with this (for now) ! */ 11543693Sbrian log_Printf(LogPHASE, "Radius: CHALLENGE received (can't handle yet)\n"); 11643693Sbrian auth_Failure(r->cx.auth); 11743693Sbrian rad_close(r->cx.rad); 11843693Sbrian return; 11943313Sbrian 12043313Sbrian case -1: 12143693Sbrian log_Printf(LogPHASE, "radius: %s\n", rad_strerror(r->cx.rad)); 12243693Sbrian auth_Failure(r->cx.auth); 12343693Sbrian rad_close(r->cx.rad); 12443693Sbrian return; 12543313Sbrian 12643313Sbrian default: 12743313Sbrian log_Printf(LogERROR, "rad_send_request: Failed %d: %s\n", 12843693Sbrian got, rad_strerror(r->cx.rad)); 12943693Sbrian auth_Failure(r->cx.auth); 13043693Sbrian rad_close(r->cx.rad); 13143693Sbrian return; 13243313Sbrian } 13343313Sbrian 13443313Sbrian /* So we've been accepted ! Let's see what we've got in our reply :-I */ 13543313Sbrian r->ip.s_addr = r->mask.s_addr = INADDR_NONE; 13643313Sbrian r->mtu = 0; 13743313Sbrian r->vj = 0; 13843693Sbrian while ((got = rad_get_attr(r->cx.rad, &data, &len)) > 0) { 13943313Sbrian switch (got) { 14043313Sbrian case RAD_FRAMED_IP_ADDRESS: 14143313Sbrian r->ip = rad_cvt_addr(data); 14243693Sbrian log_Printf(LogPHASE, " IP %s\n", inet_ntoa(r->ip)); 14343313Sbrian break; 14443313Sbrian 14543313Sbrian case RAD_FRAMED_IP_NETMASK: 14643313Sbrian r->mask = rad_cvt_addr(data); 14743693Sbrian log_Printf(LogPHASE, " Netmask %s\n", inet_ntoa(r->mask)); 14843313Sbrian break; 14943313Sbrian 15043313Sbrian case RAD_FRAMED_MTU: 15143313Sbrian r->mtu = rad_cvt_int(data); 15243693Sbrian log_Printf(LogPHASE, " MTU %lu\n", r->mtu); 15343313Sbrian break; 15443313Sbrian 15543313Sbrian case RAD_FRAMED_ROUTING: 15643313Sbrian /* Disabled for now - should we automatically set up some filters ? */ 15743313Sbrian /* rad_cvt_int(data); */ 15843313Sbrian /* bit 1 = Send routing packets */ 15943313Sbrian /* bit 2 = Receive routing packets */ 16043313Sbrian break; 16143313Sbrian 16243313Sbrian case RAD_FRAMED_COMPRESSION: 16343313Sbrian r->vj = rad_cvt_int(data) == 1 ? 1 : 0; 16443693Sbrian log_Printf(LogPHASE, " VJ %sabled\n", r->vj ? "en" : "dis"); 16543313Sbrian break; 16643313Sbrian 16743313Sbrian case RAD_FRAMED_ROUTE: 16843313Sbrian /* 16943313Sbrian * We expect a string of the format ``dest[/bits] gw [metrics]'' 17043313Sbrian * Any specified metrics are ignored. MYADDR and HISADDR are 17143313Sbrian * understood for ``dest'' and ``gw'' and ``0.0.0.0'' is the same 17243313Sbrian * as ``HISADDR''. 17343313Sbrian */ 17443313Sbrian 17543313Sbrian if ((nuke = rad_cvt_string(data, len)) == NULL) { 17643693Sbrian log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); 17743693Sbrian rad_close(r->cx.rad); 17843693Sbrian return; 17943313Sbrian } 18043313Sbrian 18143693Sbrian log_Printf(LogPHASE, " Route: %s\n", nuke); 18243693Sbrian bundle = r->cx.auth->physical->dl->bundle; 18343313Sbrian dest.ipaddr.s_addr = dest.mask.s_addr = INADDR_ANY; 18443313Sbrian dest.width = 0; 18543313Sbrian argc = command_Interpret(nuke, strlen(nuke), argv); 18654914Sbrian if (argc < 0) 18754914Sbrian log_Printf(LogWARN, "radius: %s: Syntax error\n", 18854914Sbrian argc == 1 ? argv[0] : "\"\""); 18954914Sbrian else if (argc < 2) 19043313Sbrian log_Printf(LogWARN, "radius: %s: Invalid route\n", 19143313Sbrian argc == 1 ? argv[0] : "\"\""); 19243313Sbrian else if ((strcasecmp(argv[0], "default") != 0 && 19343313Sbrian !ParseAddr(&bundle->ncp.ipcp, argv[0], &dest.ipaddr, 19443313Sbrian &dest.mask, &dest.width)) || 19543313Sbrian !ParseAddr(&bundle->ncp.ipcp, argv[1], &gw, NULL, NULL)) 19643313Sbrian log_Printf(LogWARN, "radius: %s %s: Invalid route\n", 19743313Sbrian argv[0], argv[1]); 19843313Sbrian else { 19943313Sbrian if (dest.width == 32 && strchr(argv[0], '/') == NULL) 20043313Sbrian /* No mask specified - use the natural mask */ 20144455Sbrian dest.mask = addr2mask(dest.ipaddr); 20243313Sbrian addrs = 0; 20343313Sbrian 20443313Sbrian if (!strncasecmp(argv[0], "HISADDR", 7)) 20543313Sbrian addrs = ROUTE_DSTHISADDR; 20643313Sbrian else if (!strncasecmp(argv[0], "MYADDR", 6)) 20743313Sbrian addrs = ROUTE_DSTMYADDR; 20843313Sbrian 20943313Sbrian if (gw.s_addr == INADDR_ANY) { 21043313Sbrian addrs |= ROUTE_GWHISADDR; 21143313Sbrian gw = bundle->ncp.ipcp.peer_ip; 21243313Sbrian } else if (strcasecmp(argv[1], "HISADDR") == 0) 21343313Sbrian addrs |= ROUTE_GWHISADDR; 21443313Sbrian 21543313Sbrian route_Add(&r->routes, addrs, dest.ipaddr, dest.mask, gw); 21643313Sbrian } 21743313Sbrian free(nuke); 21843313Sbrian break; 21943313Sbrian } 22043313Sbrian } 22143313Sbrian 22243313Sbrian if (got == -1) { 22343693Sbrian log_Printf(LogERROR, "rad_get_attr: %s (failing!)\n", 22443693Sbrian rad_strerror(r->cx.rad)); 22543693Sbrian auth_Failure(r->cx.auth); 22643693Sbrian rad_close(r->cx.rad); 22743693Sbrian } else { 22843693Sbrian r->valid = 1; 22943693Sbrian auth_Success(r->cx.auth); 23043693Sbrian rad_close(r->cx.rad); 23143313Sbrian } 23243693Sbrian} 23343313Sbrian 23443693Sbrian/* 23558038Sbrian * We've either timed out or select()ed on the read descriptor 23643693Sbrian */ 23743693Sbrianstatic void 23843693Sbrianradius_Continue(struct radius *r, int sel) 23943693Sbrian{ 24043693Sbrian struct timeval tv; 24143693Sbrian int got; 24243313Sbrian 24343693Sbrian timer_Stop(&r->cx.timer); 24443693Sbrian if ((got = rad_continue_send_request(r->cx.rad, sel, &r->cx.fd, &tv)) == 0) { 24543693Sbrian log_Printf(LogPHASE, "Radius: Request re-sent\n"); 24643693Sbrian r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS; 24743693Sbrian timer_Start(&r->cx.timer); 24843693Sbrian return; 24943693Sbrian } 25043693Sbrian 25143693Sbrian radius_Process(r, got); 25243313Sbrian} 25343313Sbrian 25443693Sbrian/* 25543693Sbrian * Time to call rad_continue_send_request() - timed out. 25643693Sbrian */ 25743693Sbrianstatic void 25843693Sbrianradius_Timeout(void *v) 25943693Sbrian{ 26043693Sbrian radius_Continue((struct radius *)v, 0); 26143693Sbrian} 26243693Sbrian 26343693Sbrian/* 26443693Sbrian * Time to call rad_continue_send_request() - something to read. 26543693Sbrian */ 26643693Sbrianstatic void 26758028Sbrianradius_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 26843693Sbrian{ 26943693Sbrian radius_Continue(descriptor2radius(d), 1); 27043693Sbrian} 27143693Sbrian 27243693Sbrian/* 27358038Sbrian * Behave as a struct fdescriptor (descriptor.h) 27443693Sbrian */ 27543693Sbrianstatic int 27658028Sbrianradius_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 27743693Sbrian{ 27843693Sbrian struct radius *rad = descriptor2radius(d); 27943693Sbrian 28043693Sbrian if (r && rad->cx.fd != -1) { 28143693Sbrian FD_SET(rad->cx.fd, r); 28243693Sbrian if (*n < rad->cx.fd + 1) 28343693Sbrian *n = rad->cx.fd + 1; 28443693Sbrian log_Printf(LogTIMER, "Radius: fdset(r) %d\n", rad->cx.fd); 28543693Sbrian return 1; 28643693Sbrian } 28743693Sbrian 28843693Sbrian return 0; 28943693Sbrian} 29043693Sbrian 29143693Sbrian/* 29258038Sbrian * Behave as a struct fdescriptor (descriptor.h) 29343693Sbrian */ 29443693Sbrianstatic int 29558028Sbrianradius_IsSet(struct fdescriptor *d, const fd_set *fdset) 29643693Sbrian{ 29743693Sbrian struct radius *r = descriptor2radius(d); 29843693Sbrian 29943693Sbrian return r && r->cx.fd != -1 && FD_ISSET(r->cx.fd, fdset); 30043693Sbrian} 30143693Sbrian 30243693Sbrian/* 30358038Sbrian * Behave as a struct fdescriptor (descriptor.h) 30443693Sbrian */ 30543693Sbrianstatic int 30658028Sbrianradius_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 30743693Sbrian{ 30843693Sbrian /* We never want to write here ! */ 30943693Sbrian log_Printf(LogALERT, "radius_Write: Internal error: Bad call !\n"); 31043693Sbrian return 0; 31143693Sbrian} 31243693Sbrian 31343693Sbrian/* 31443693Sbrian * Initialise ourselves 31543693Sbrian */ 31643313Sbrianvoid 31743693Sbrianradius_Init(struct radius *r) 31843693Sbrian{ 31943693Sbrian r->valid = 0; 32043693Sbrian r->cx.fd = -1; 32143693Sbrian *r->cfg.file = '\0';; 32243693Sbrian r->desc.type = RADIUS_DESCRIPTOR; 32343693Sbrian r->desc.UpdateSet = radius_UpdateSet; 32443693Sbrian r->desc.IsSet = radius_IsSet; 32543693Sbrian r->desc.Read = radius_Read; 32643693Sbrian r->desc.Write = radius_Write; 32743693Sbrian memset(&r->cx.timer, '\0', sizeof r->cx.timer); 32843693Sbrian} 32943693Sbrian 33043693Sbrian/* 33143693Sbrian * Forget everything and go back to initialised state. 33243693Sbrian */ 33343693Sbrianvoid 33443693Sbrianradius_Destroy(struct radius *r) 33543693Sbrian{ 33643693Sbrian r->valid = 0; 33743693Sbrian timer_Stop(&r->cx.timer); 33843693Sbrian route_DeleteAll(&r->routes); 33943693Sbrian if (r->cx.fd != -1) { 34043693Sbrian r->cx.fd = -1; 34143693Sbrian rad_close(r->cx.rad); 34243693Sbrian } 34343693Sbrian} 34443693Sbrian 34543693Sbrian/* 34643693Sbrian * Start an authentication request to the RADIUS server. 34743693Sbrian */ 34843693Sbrianvoid 34943693Sbrianradius_Authenticate(struct radius *r, struct authinfo *authp, const char *name, 35043693Sbrian const char *key, const char *challenge) 35143693Sbrian{ 35250840Sbrian struct ttyent *ttyp; 35343693Sbrian struct timeval tv; 35450840Sbrian int got, slot; 35550840Sbrian char hostname[MAXHOSTNAMELEN]; 35650840Sbrian struct hostent *hp; 35750840Sbrian struct in_addr hostaddr; 35843693Sbrian 35943693Sbrian if (!*r->cfg.file) 36043693Sbrian return; 36143693Sbrian 36243693Sbrian if (r->cx.fd != -1) 36343693Sbrian /* 36443693Sbrian * We assume that our name/key/challenge is the same as last time, 36543693Sbrian * and just continue to wait for the RADIUS server(s). 36643693Sbrian */ 36743693Sbrian return; 36843693Sbrian 36943693Sbrian radius_Destroy(r); 37043693Sbrian 37143693Sbrian if ((r->cx.rad = rad_open()) == NULL) { 37243693Sbrian log_Printf(LogERROR, "rad_open: %s\n", strerror(errno)); 37343693Sbrian return; 37443693Sbrian } 37543693Sbrian 37643693Sbrian if (rad_config(r->cx.rad, r->cfg.file) != 0) { 37743693Sbrian log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad)); 37843693Sbrian rad_close(r->cx.rad); 37943693Sbrian return; 38043693Sbrian } 38143693Sbrian 38243693Sbrian if (rad_create_request(r->cx.rad, RAD_ACCESS_REQUEST) != 0) { 38343693Sbrian log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad)); 38443693Sbrian rad_close(r->cx.rad); 38543693Sbrian return; 38643693Sbrian } 38743693Sbrian 38843693Sbrian if (rad_put_string(r->cx.rad, RAD_USER_NAME, name) != 0 || 38943693Sbrian rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 || 39043693Sbrian rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) { 39143693Sbrian log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 39243693Sbrian rad_close(r->cx.rad); 39343693Sbrian return; 39443693Sbrian } 39543693Sbrian 39643693Sbrian if (challenge != NULL) { 39743693Sbrian /* We're talking CHAP */ 39843693Sbrian if (rad_put_string(r->cx.rad, RAD_CHAP_PASSWORD, key) != 0 || 39943693Sbrian rad_put_string(r->cx.rad, RAD_CHAP_CHALLENGE, challenge) != 0) { 40043693Sbrian log_Printf(LogERROR, "CHAP: rad_put_string: %s\n", 40143693Sbrian rad_strerror(r->cx.rad)); 40243693Sbrian rad_close(r->cx.rad); 40343693Sbrian return; 40443693Sbrian } 40543693Sbrian } else if (rad_put_string(r->cx.rad, RAD_USER_PASSWORD, key) != 0) { 40643693Sbrian /* We're talking PAP */ 40743693Sbrian log_Printf(LogERROR, "PAP: rad_put_string: %s\n", rad_strerror(r->cx.rad)); 40843693Sbrian rad_close(r->cx.rad); 40943693Sbrian return; 41043693Sbrian } 41143693Sbrian 41250840Sbrian if (gethostname(hostname, sizeof hostname) != 0) 41350840Sbrian log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno)); 41450840Sbrian else { 41550840Sbrian if ((hp = gethostbyname(hostname)) != NULL) { 41650840Sbrian hostaddr.s_addr = *(u_long *)hp->h_addr; 41750840Sbrian if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) { 41850840Sbrian log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 41950840Sbrian rad_strerror(r->cx.rad)); 42050840Sbrian rad_close(r->cx.rad); 42150840Sbrian return; 42250840Sbrian } 42350840Sbrian } 42450840Sbrian if (rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) { 42550840Sbrian log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 42650840Sbrian rad_strerror(r->cx.rad)); 42750840Sbrian rad_close(r->cx.rad); 42850840Sbrian return; 42950840Sbrian } 43050840Sbrian } 43150840Sbrian 43250840Sbrian if (authp->physical->handler && 43350840Sbrian authp->physical->handler->type == TTY_DEVICE) { 43450840Sbrian setttyent(); 43550840Sbrian for (slot = 1; (ttyp = getttyent()); ++slot) 43650840Sbrian if (!strcmp(ttyp->ty_name, authp->physical->name.base)) { 43750840Sbrian if(rad_put_int(r->cx.rad, RAD_NAS_PORT, slot) != 0) { 43850840Sbrian log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 43950840Sbrian rad_strerror(r->cx.rad)); 44050840Sbrian rad_close(r->cx.rad); 44150840Sbrian endttyent(); 44250840Sbrian return; 44350840Sbrian } 44450840Sbrian break; 44550840Sbrian } 44650840Sbrian endttyent(); 44750840Sbrian } 44850840Sbrian 44950840Sbrian 45043693Sbrian if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv))) 45143693Sbrian radius_Process(r, got); 45243693Sbrian else { 45343693Sbrian log_Printf(LogPHASE, "Radius: Request sent\n"); 45443693Sbrian log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout); 45543693Sbrian r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS; 45643693Sbrian r->cx.timer.func = radius_Timeout; 45743693Sbrian r->cx.timer.name = "radius"; 45843693Sbrian r->cx.timer.arg = r; 45943693Sbrian r->cx.auth = authp; 46043693Sbrian timer_Start(&r->cx.timer); 46143693Sbrian } 46243693Sbrian} 46343693Sbrian 46443693Sbrian/* 46543693Sbrian * How do things look at the moment ? 46643693Sbrian */ 46743693Sbrianvoid 46843313Sbrianradius_Show(struct radius *r, struct prompt *p) 46943313Sbrian{ 47043313Sbrian prompt_Printf(p, " Radius config: %s", *r->cfg.file ? r->cfg.file : "none"); 47143313Sbrian if (r->valid) { 47243313Sbrian prompt_Printf(p, "\n IP: %s\n", inet_ntoa(r->ip)); 47343313Sbrian prompt_Printf(p, " Netmask: %s\n", inet_ntoa(r->mask)); 47443313Sbrian prompt_Printf(p, " MTU: %lu\n", r->mtu); 47543313Sbrian prompt_Printf(p, " VJ: %sabled\n", r->vj ? "en" : "dis"); 47643313Sbrian if (r->routes) 47743313Sbrian route_ShowSticky(p, r->routes, " Routes", 16); 47843313Sbrian } else 47943313Sbrian prompt_Printf(p, " (not authenticated)\n"); 48043313Sbrian} 481