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