xref: /freebsd/usr.sbin/ppp/radius.c (revision 77a0943ded95b9e6438f7db70c4a28e4d93946d4)
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$
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  */
89 static void
90 radius_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  */
243 static void
244 radius_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  */
263 static void
264 radius_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  */
272 static void
273 radius_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  */
281 static int
282 radius_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  */
300 static int
301 radius_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  */
311 static int
312 radius_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  */
322 void
323 radius_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  */
340 void
341 radius_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  */
356 void
357 radius_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  */
475 void
476 radius_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  */
628 void
629 radius_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