radius.c revision 67133
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 67133 2000-10-15 01:05:57Z 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_acct_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