handle OTP_RC_NEXTPASSCODE error from otpd-2.2.1+
[freeradius.git] / src / modules / rlm_radutmp / rlm_radutmp2.c
1 /*
2  * rlm_radutmp.c
3  *
4  * Version:     $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2000,2001,2002,2003,2004,2006  The FreeRADIUS server project
21  */
22
23 #include        <freeradius-devel/ident.h>
24 RCSID("$Id$")
25
26 #include        <freeradius-devel/radiusd.h>
27 #include        <freeradius-devel/radutmp.h>
28 #include        <freeradius-devel/modules.h>
29 #include        <freeradius-devel/rad_assert.h>
30
31 #include        <fcntl.h>
32 #include        <limits.h>
33
34 #include "config.h"
35
36 #define LOCK_LEN sizeof(struct radutmp)
37
38 static const char porttypes[] = "ASITX";
39
40 /*
41  *      Used for caching radutmp lookups in the accounting
42  *      component. The session (checksimul) component doesn't use it,
43  *      but probably should, though we're not sure how...
44  *
45  *      The intent here is to keep this structure as small as
46  *      possible, so that it doesn't take up too much memory.
47  */
48 typedef struct nas_port {
49         uint32_t                nas_address;
50         unsigned int            nas_port;
51         off_t                   offset;
52
53         struct nas_port         *next; /* for the free list */
54 } NAS_PORT;
55
56
57 /*
58  *      Per-file information.
59  *
60  *      Hmm... having multiple filenames managed by one instance
61  *      of the module makes it difficult for the module to do
62  *      simultaneous-use checking, without more code edits.
63  */
64 typedef struct radutmp_cache_t {
65         const char      *filename; /* for future reference */
66         time_t          last_used; /* for future reference */
67
68         rbtree_t        *nas_ports;
69         NAS_PORT        *free_offsets;
70         off_t           max_offset;
71         int             cached_file;
72         int             permission;
73 #ifdef HAVE_PTHREAD_H
74         pthread_mutex_t mutex;
75 #endif
76 } radutmp_cache_t;
77
78
79 /*
80  *      We cache the users, too, so that we only have to read radutmp
81  *      once.
82  */
83 typedef struct radutmp_simul_t {
84         char            login[sizeof(((struct radutmp *) NULL)->login) + 1];
85         int             simul_count;
86 } radutmp_simul_t;
87
88
89 /*
90  *      Data we store per module.
91  */
92 typedef struct rlm_radutmp_t {
93         char            *filename;
94         char            *username;
95         int             case_sensitive;
96         int             check_nas;
97         int             permission;
98         int             callerid_ok;
99
100         rbtree_t        *user_tree; /* for simultaneous-use */
101
102         /*
103          *      As the filenames can be dynamically translated,
104          *      we want to keep track of them in a separate data
105          *      structure, so that we can have per-file caches.
106          */
107         radutmp_cache_t cache;
108 } rlm_radutmp_t;
109
110 #ifndef HAVE_PTHREAD_H
111 /*
112  *      This is easier than ifdef's throughout the code.
113  */
114 #define pthread_mutex_init(_x, _y)
115 #define pthread_mutex_destroy(_x)
116 #define pthread_mutex_lock(_x)
117 #define pthread_mutex_unlock(_x)
118 #endif
119
120 static const CONF_PARSER module_config[] = {
121         { "filename", PW_TYPE_STRING_PTR,
122           offsetof(rlm_radutmp_t,filename), NULL,  RADUTMP },
123         { "username", PW_TYPE_STRING_PTR,
124           offsetof(rlm_radutmp_t,username), NULL,  "%{User-Name}"},
125         { "case_sensitive", PW_TYPE_BOOLEAN,
126           offsetof(rlm_radutmp_t,case_sensitive), NULL,  "yes"},
127         { "check_with_nas", PW_TYPE_BOOLEAN,
128           offsetof(rlm_radutmp_t,check_nas), NULL,  "yes"},
129         { "perm",     PW_TYPE_INTEGER,
130           offsetof(rlm_radutmp_t,permission), NULL,  "0644" },
131         { "callerid", PW_TYPE_BOOLEAN,
132           offsetof(rlm_radutmp_t,callerid_ok), NULL, "no" },
133         { NULL, -1, 0, NULL, NULL }             /* end the list */
134 };
135
136
137 /*
138  *      NAS PORT cmp
139  */
140 static int nas_port_cmp(const void *a, const void *b)
141 {
142         const NAS_PORT *one = a;
143         const NAS_PORT *two = b;
144
145         if (one->nas_address < two->nas_address) return -1;
146         if (one->nas_address > two->nas_address) return +1;
147
148         if (one->nas_port < two->nas_port) return -1;
149         if (one->nas_port > two->nas_port) return +1;
150
151         return 0;
152 }
153
154
155 /*
156  *      Compare two user names.
157  */
158 static int user_cmp(const void *a, const void *b)
159 {
160         const radutmp_simul_t *one = a;
161         const radutmp_simul_t *two = b;
162
163         return strcmp(one->login, two->login);
164 }
165
166
167 /*
168  *      Compare two user names, case insensitive.
169  */
170 static int user_case_cmp(const void *a, const void *b)
171 {
172         const radutmp_simul_t *one = a;
173         const radutmp_simul_t *two = b;
174
175         return strcasecmp(one->login, two->login);
176 }
177
178
179 /*
180  *      Detach.
181  */
182 static int radutmp_detach(void *instance)
183 {
184         NAS_PORT        *this, *next;
185         rlm_radutmp_t *inst = instance;
186
187         rbtree_free(inst->cache.nas_ports);
188
189         for (this = inst->cache.free_offsets;
190              this != NULL;
191              this = next) {
192                 next = this->next;
193                 free(this);
194         }
195
196         if (inst->cache.filename) free(inst->cache.filename);
197
198         pthread_mutex_destroy(&(inst->cache.mutex));
199
200
201         rbtree_free(inst->user_tree);
202
203         free(inst);
204         return 0;
205 }
206
207
208 /*
209  *      Instantiate.
210  */
211 static int radutmp_instantiate(CONF_SECTION *conf, void **instance)
212 {
213         rlm_radutmp_t *inst;
214
215         inst = rad_malloc(sizeof(*inst));
216         if (!inst) {
217                 return -1;
218         }
219         memset(inst, 0, sizeof(*inst));
220
221         if (cf_section_parse(conf, inst, module_config)) {
222                 radutmp_detach(inst);
223                 return -1;
224         }
225
226         inst->cache.nas_ports = rbtree_create(nas_port_cmp, free, 0);
227         if (!inst->cache.nas_ports) {
228                 radlog(L_ERR, "rlm_radutmp: Failed to create nas tree");
229                 radutmp_detach(inst);
230                 return -1;
231         }
232
233         pthread_mutex_init(&(inst->cache.mutex), NULL);
234         inst->cache.permission = inst->permission;
235
236         if (inst->case_sensitive) {
237                 inst->user_tree = rbtree_create(user_cmp, free, 0);
238         } else {
239                 inst->user_tree = rbtree_create(user_case_cmp, free, 0);
240         }
241         if (!inst->user_tree) {
242                 radlog(L_ERR, "rlm_radutmp: Failed to create user tree");
243                 radutmp_detach(inst);
244                 return -1;
245         }
246
247         *instance = inst;
248         return 0;
249 }
250
251
252 /*
253  *      Reset the cached entries.
254  */
255 static int cache_reset(rlm_radutmp_t *inst, radutmp_cache_t *cache)
256 {
257         NAS_PORT *this, *next;
258
259         /*
260          *      Cache is already reset, do nothing.
261          */
262         if ((rbtree_num_elements(cache->nas_ports) == 0) &&
263             (cache->free_offsets == NULL)) {
264                 DEBUG2("  rlm_radutmp: Not resetting the cache");
265                 return 1;
266         }
267         DEBUG2("  rlm_radutmp: Resetting the cache");
268
269         pthread_mutex_lock(&cache->mutex);
270
271         rbtree_free(inst->user_tree);
272
273         rbtree_free(cache->nas_ports);
274
275         for (this = cache->free_offsets;
276              this != NULL;
277              this = next) {
278                 next = this->next;
279                 free(this);
280         }
281         cache->free_offsets = NULL;
282
283         /*
284          *      Re-create the caches.
285          */
286         cache->nas_ports = rbtree_create(nas_port_cmp, free, 0);
287         if (!cache->nas_ports) {
288                 pthread_mutex_unlock(&cache->mutex);
289                 radlog(L_ERR, "rlm_radutmp: No memory");
290                 return 0;
291         }
292
293         cache->max_offset = 0;
294
295         cache->cached_file = 1;
296
297         if (inst->case_sensitive) {
298                 inst->user_tree = rbtree_create(user_cmp, free, 0);
299         } else {
300                 inst->user_tree = rbtree_create(user_case_cmp, free, 0);
301         }
302         if (!inst->user_tree) {
303                 pthread_mutex_unlock(&cache->mutex);
304                 radlog(L_ERR, "rlm_radutmp: No memory");
305                 return 0;
306         }
307
308         pthread_mutex_unlock(&cache->mutex);
309
310         return 1;
311 }
312
313
314 /*
315  *      Compare two offsets in a tree.
316  */
317 static int offset_cmp(const void *a, const void *b)
318 {
319         const NAS_PORT *one = a;
320         const NAS_PORT *two = b;
321
322         if (one->offset < two->offset) return -1;
323         if (one->offset > two->offset) return +1;
324
325         return 0;
326 }
327
328
329 /*
330  *      Data structure to use when walking the trees, for zap.
331  */
332 typedef struct offset_walk_t {
333         rlm_radutmp_t   *inst;
334         radutmp_cache_t *cache;
335         rbtree_t        *offset_tree;
336         uint32_t        nas_address;
337         int             fd;
338         time_t          now;
339 } offset_walk_t;
340
341
342 /*
343  *      Walk over the cache, finding entries with the matching NAS IP address.
344  */
345 static int nas_port_walk(void *context, void *data)
346 {
347         offset_walk_t   *walk = context;
348         NAS_PORT        *nas_port = data;
349
350         /*
351          *      Doesn't match, keep going.
352          */
353         if (walk->nas_address != nas_port->nas_address) return 0;
354
355         /*
356          *      Insert it into the offset tree, for later deletion.
357          */
358         if (rbtree_insert(walk->offset_tree, nas_port) != 1) {
359                 DEBUG2("  rlm_radumtp: Insertion failed in nas port walk.");
360                 return 1;
361         }
362
363         return 0;
364 }
365
366
367 /*
368  *      Walk through the offset tree, operating on the cache
369  */
370 static int offset_walk(void *context, void *data)
371 {
372         offset_walk_t   *walk = context;
373         NAS_PORT        *nas_port = data;
374         struct radutmp  utmp;
375         radutmp_simul_t *user, myUser;
376
377         /*
378          *      Seek to the entry, and possibly re-write it.
379          */
380         if (lseek(walk->fd, nas_port->offset, SEEK_SET) < 0) {
381                 rad_assert(0 == 1);
382         }
383
384         if (read(walk->fd, &utmp, sizeof(utmp)) != sizeof(utmp)) {
385                 rad_assert(0 == 1);
386         }
387
388         /*
389          *      If the entry in the file is NEWER than the reboot
390          *      packet, don't re-write it, and don't delete it.
391          */
392         if (utmp.time > walk->now) {
393                 return 0;
394         }
395
396         utmp.type = P_IDLE;
397         utmp.time = walk->now;
398
399         if (lseek(walk->fd, -(off_t)sizeof(utmp), SEEK_CUR) < 0) {
400                 radlog(L_ERR, "rlm_radutmp: offset_walk: failed in lseek: %s",
401                        strerror(errno));
402                 return 1;
403         }
404
405         write(walk->fd, &utmp, sizeof(utmp));
406
407         strlcpy(myUser.login, utmp.login, sizeof(myUser.login));
408         user = rbtree_finddata(walk->inst->user_tree, &myUser);
409         rad_assert(user != NULL);
410         rad_assert(user->simul_count > 0);
411         user->simul_count--;
412         if (user->simul_count == 0) {
413                 rbtree_deletebydata(walk->inst->user_tree, user);
414         }
415
416         if (rbtree_deletebydata(walk->cache->nas_ports, nas_port) == 0) {
417                 radlog(L_ERR, "rlm_radutmp: Failed to delete entry from cache");
418                 return 1;
419         }
420
421         /*
422          *      Insert the entry into the free list.
423          */
424         nas_port->next = walk->cache->free_offsets;
425         walk->cache->free_offsets = nas_port;
426
427         return 0;
428 }
429
430
431 /*
432  *      Zap all users on a NAS from the radutmp file.
433  */
434 static int radutmp_zap(rlm_radutmp_t *inst,
435                        radutmp_cache_t *cache,
436                        uint32_t nas_address,
437                        time_t now)
438 {
439         int             rcode;
440         rbtree_t        *offset_tree;
441         offset_walk_t   walk;
442
443         rad_assert(now != 0);
444
445         /*
446          *      If there's nothing in the file, do nothing,
447          *      but truncate the file, just to be safe.
448          */
449         if (rbtree_num_elements(cache->nas_ports) == 0) {
450                 truncate(cache->filename, (off_t) 0);
451                 DEBUG2("  rlm_radutmp: No entries in file.  Quenching zap.");
452                 return 1;
453         }
454
455         /*
456          *      Create the offset tree, as we want to delete utmp
457          *      entries starting from the start of the file, and we
458          *      can't delete nodes from an rbtree while we're walking
459          *      it.
460          */
461         offset_tree = rbtree_create(offset_cmp, NULL, 0);
462         if (!offset_tree) {
463                 radlog(L_ERR, "rlm_radutmp: Out of memory");
464                 return 0;
465         }
466
467         pthread_mutex_lock(&cache->mutex);
468
469         /*
470          *      Walk through the cache, finding entries for this NAS,
471          *      and add those entries to the offset tree.
472          */
473         memset(&walk, 0, sizeof(walk));
474         walk.inst = inst;
475         walk.offset_tree = offset_tree;
476         walk.nas_address = nas_address;
477         rcode = rbtree_walk(cache->nas_ports, PreOrder, nas_port_walk, &walk);
478         if (rcode != 0) {
479                 pthread_mutex_unlock(&cache->mutex);
480                 rbtree_free(offset_tree);
481                 radlog(L_ERR, "rlm_radutmp: Failed walking the cache.");
482                 return 0;
483         }
484
485         /*
486          *      If both trees have the same number of elements, then
487          *      don't do anything special, as UDP packets may be
488          *      received out of order, by several seconds.  The
489          *      "offset_walk" routine MAY NOT delete the entries, if
490          *      it sees that the entries in the file are newer than
491          *      the reboot packet.
492          */
493
494         /*
495          *      If there's nothing to do, don't do anything.
496          */
497         if (rbtree_num_elements(offset_tree) == 0) {
498                 DEBUG2("  rlm_radutmp: NAS IP %08x has no users recorded in file %s.",
499                        htonl(nas_address), cache->filename);
500                 pthread_mutex_unlock(&cache->mutex);
501                 rbtree_free(offset_tree);
502                 return 1;
503         }
504
505         /*
506          *      Open the file, to re-write only a few of the entries.
507          */
508         walk.fd = open(cache->filename, O_RDWR);
509         if (walk.fd < 0) {
510                 pthread_mutex_unlock(&cache->mutex);
511                 rbtree_free(offset_tree);
512                 radlog(L_ERR, "rlm_radutmp: Error accessing file %s: %s",
513                        cache->filename, strerror(errno));
514                 return 0;
515         }
516
517         /*
518          *      Lock the utmp file, prefer lockf() over flock().
519          *
520          *      FIXME: maybe we want to lock per-record?
521          */
522         rad_lockfd(walk.fd, LOCK_LEN);
523
524         /*
525          *      Walk through the offset tree, from start to finish,
526          *      deleting entries from the NAS tree, adding them to
527          *      the "free offset" cache, and lseek'ing to that offset
528          *      in the file, and clearing out the data.
529          */
530         walk.cache = cache;
531         walk.now = now;
532         rcode = rbtree_walk(offset_tree, InOrder, offset_walk, &walk);
533         rbtree_free(offset_tree);
534         if (rcode != 0) {
535                 radlog(L_ERR, "rlm_radutmp: Failed walking the offsets.");
536                 return 0;
537         }
538
539         close(walk.fd); /* and implicitly release the locks */
540
541         /*
542          *      Just to clean up the file.  If it's empty,
543          *      nuke everything.
544          */
545         if (rbtree_num_elements(cache->nas_ports) == 0) {
546                 NAS_PORT        *this, *next; /* too many copies of code */
547
548                 for (this = inst->cache.free_offsets;
549                      this != NULL;
550                      this = next) {
551                         next = this->next;
552                         free(this);
553                 }
554
555                 truncate(cache->filename, 0);
556                 rad_assert(rbtree_num_elements(inst->user_tree) == 0);
557         }
558
559         pthread_mutex_unlock(&cache->mutex);
560
561         return 1;
562 }
563
564
565 /*
566  *      Read a file, to cache all of its entries.
567  */
568 static int cache_file(rlm_radutmp_t *inst, radutmp_cache_t *cache)
569 {
570         int             fd;
571         int             read_size;
572         struct          stat buf;
573         struct          radutmp utmp;
574         NAS_PORT        **tail;
575
576         rad_assert(cache->max_offset == 0);
577         rad_assert(cache->free_offsets == NULL);
578
579         /*
580          *      Doesn't exist, we're fine.
581          */
582         if (stat(cache->filename, &buf) < 0) {
583                 if (errno == ENOENT) {
584                         cache->cached_file = 1;
585                         return 0;
586                 }
587                 radlog(L_ERR, "rlm_radutmp: Cannot stat %s: %s",
588                        cache->filename, strerror(errno));
589                 return 1;
590         }
591
592         /*
593          *      Nothing's there, we're OK.
594          */
595         if (buf.st_size == 0) {
596                 cache->cached_file = 1;
597                 return 0;
598         }
599
600         /*
601          *      Don't let others much around with our data.
602          */
603         pthread_mutex_lock(&cache->mutex);
604
605         /*
606          *      Read the file and cache it's entries.
607          */
608         fd = open(cache->filename, O_RDONLY, cache->permission);
609         if (fd < 0) {
610                 pthread_mutex_unlock(&cache->mutex);
611                 radlog(L_ERR, "rlm_radutmp: Error opening %s: %s",
612                        cache->filename, strerror(errno));
613                 return 1;
614         }
615
616         /*
617          *      Insert free entries into the tail, so that entries
618          *      get used from the start.
619          */
620         tail = &(cache->free_offsets);
621
622         /*
623          *      Don't lock the file, as we're only reading it.
624          */
625         do {
626                 read_size = read(fd, &utmp, sizeof(utmp));
627
628                 /*
629                  *      Read one record.
630                  */
631                 if (read_size == sizeof(utmp)) {
632                         radutmp_simul_t *user, myUser;
633                         NAS_PORT *nas_port = rad_malloc(sizeof(*nas_port));
634
635                         memset(nas_port, 0, sizeof(nas_port));
636                         nas_port->offset = cache->max_offset;
637                         cache->max_offset += sizeof(utmp);
638
639                         /*
640                          *      Idle.  Add it to the list of free
641                          *      offsets.
642                          */
643                         if (utmp.type == P_IDLE) {
644                                 *tail = nas_port;
645                                 tail = &(nas_port->next);
646                                 continue;
647                         }
648
649                         /*
650                          *      It's a login record,
651                          */
652                         nas_port->nas_address = utmp.nas_address;
653                         nas_port->nas_port = utmp.nas_port;
654
655                         if (!rbtree_insert(cache->nas_ports, nas_port)) {
656                                 rad_assert(0 == 1);
657                         }
658
659                         /*
660                          *      Adds a trailing \0, so myUser.login has
661                          *      an extra char allocated..
662                          */
663                         strlcpy(myUser.login, utmp.login, sizeof(myUser.login));
664                         user = rbtree_finddata(inst->user_tree, &myUser);
665                         if (user) {
666                                 user->simul_count++;
667                         } else {
668                                 /*
669                                  *      Allocate new entry, and add it
670                                  *      to the tree.
671                                  */
672                                 user = rad_malloc(sizeof(user));
673                                 strlcpy(user->login, utmp.login,
674                                         sizeof(user->login));
675                                 user->simul_count = 1;
676
677                                 if (!rbtree_insert(inst->user_tree, user)) {
678                                         rad_assert(0 == 1);
679                                 }
680                         }
681                         continue;
682                 }
683
684                 /*
685                  *      We've read a partial record.  WTF?
686                  */
687                 if (read_size != 0) {
688                         pthread_mutex_unlock(&cache->mutex);
689                         close(fd);
690                         radlog(L_ERR, "rlm_radutmp: Badly formed file %s",
691                                cache->filename);
692                         return 1;
693                 }
694
695                 /*
696                  *      Read nothing, stop.
697                  */
698         } while (read_size != 0);
699
700         pthread_mutex_unlock(&cache->mutex);
701         close(fd);              /* and release the lock. */
702         cache->cached_file = 1;
703
704         return 0;
705 }
706
707
708 /*
709  *      Store logins in the RADIUS utmp file.
710  */
711 static int radutmp_accounting(void *instance, REQUEST *request)
712 {
713         rlm_radutmp_t   *inst = instance;
714         struct radutmp  utmp, u;
715         VALUE_PAIR      *vp;
716         int             status = -1;
717         uint32_t        nas_address = 0;
718         uint32_t        framed_address = 0;
719         int             protocol = -1;
720         int             fd;
721         int             port_seen = 0;
722         char            buffer[256];
723         char            filename[1024];
724         char            ip_name[32]; /* 255.255.255.255 */
725         const char      *nas;
726         NAS_PORT        *nas_port, myPort;
727         radutmp_cache_t *cache;
728         int             read_size;
729         rbnode_t        *node;
730
731         /*
732          *      Which type is this.
733          */
734         if ((vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE)) == NULL) {
735                 radlog(L_ERR, "rlm_radutmp: No Accounting-Status-Type record.");
736                 return RLM_MODULE_NOOP;
737         }
738         status = vp->vp_integer;
739
740         /*
741          *      Look for weird reboot packets.
742          *
743          *      ComOS (up to and including 3.5.1b20) does not send
744          *      standard PW_STATUS_ACCOUNTING_* messages.
745          *
746          *      Check for:  o no Acct-Session-Time, or time of 0
747          *                  o Acct-Session-Id of "00000000".
748          *
749          *      We could also check for NAS-Port, that attribute
750          *      should NOT be present (but we don't right now).
751          */
752         if ((status != PW_STATUS_ACCOUNTING_ON) &&
753             (status != PW_STATUS_ACCOUNTING_OFF)) do {
754                 int check1 = 0;
755                 int check2 = 0;
756
757                 if ((vp = pairfind(request->packet->vps, PW_ACCT_SESSION_TIME))
758                      == NULL || vp->vp_date == 0)
759                         check1 = 1;
760                 if ((vp = pairfind(request->packet->vps, PW_ACCT_SESSION_ID))
761                      != NULL && vp->length == 8 &&
762                      memcmp(vp->vp_strvalue, "00000000", 8) == 0)
763                         check2 = 1;
764                 if (check1 == 0 || check2 == 0) {
765 #if 0 /* Cisco sometimes sends START records without username. */
766                         radlog(L_ERR, "rlm_radutmp: no username in record");
767                         return RLM_MODULE_FAIL;
768 #else
769                         break;
770 #endif
771                 }
772                 radlog(L_INFO, "rlm_radutmp: converting reboot records.");
773                 if (status == PW_STATUS_STOP)
774                         status = PW_STATUS_ACCOUNTING_OFF;
775                 if (status == PW_STATUS_START)
776                         status = PW_STATUS_ACCOUNTING_ON;
777         } while(0);
778
779         memset(&utmp, 0, sizeof(utmp));
780         utmp.porttype = 'A';
781
782         /*
783          *      First, find the interesting attributes.
784          */
785         for (vp = request->packet->vps; vp; vp = vp->next) {
786                 switch (vp->attribute) {
787                         case PW_LOGIN_IP_HOST:
788                         case PW_FRAMED_IP_ADDRESS:
789                                 framed_address = vp->vp_ipaddr;
790                                 utmp.framed_address = vp->vp_ipaddr;
791                                 break;
792                         case PW_FRAMED_PROTOCOL:
793                                 protocol = vp->vp_integer;
794                                 break;
795                         case PW_NAS_IP_ADDRESS:
796                                 nas_address = vp->vp_ipaddr;
797                                 utmp.nas_address = vp->vp_ipaddr;
798                                 break;
799                         case PW_NAS_PORT:
800                                 utmp.nas_port = vp->vp_integer;
801                                 port_seen = 1;
802                                 break;
803                         case PW_ACCT_DELAY_TIME:
804                                 utmp.delay = vp->vp_integer;
805                                 break;
806                         case PW_ACCT_SESSION_ID:
807                                 /*
808                                  *      If it's too big, only use the
809                                  *      last bit.
810                                  */
811                                 if (vp->length > sizeof(utmp.session_id)) {
812                                         int length = vp->length - sizeof(utmp.session_id);
813
814                                         /*
815                                          *      Ascend is br0ken - it
816                                          *      adds a \0 to the end
817                                          *      of any string.
818                                          *      Compensate.
819                                          */
820                                         if (vp->vp_strvalue[vp->length - 1] == 0) {
821                                                 length--;
822                                         }
823
824                                         memcpy(utmp.session_id,
825                                               vp->vp_strvalue + length,
826                                               sizeof(utmp.session_id));
827                                 } else {
828                                         memset(utmp.session_id, 0,
829                                                sizeof(utmp.session_id));
830                                         memcpy(utmp.session_id,
831                                                vp->vp_strvalue,
832                                                vp->length);
833                                 }
834                                 break;
835                         case PW_NAS_PORT_TYPE:
836                                 if (vp->vp_integer <= 4)
837                                         utmp.porttype = porttypes[vp->vp_integer];
838                                 break;
839                         case PW_CALLING_STATION_ID:
840                                 if(inst->callerid_ok)
841                                         strlcpy(utmp.caller_id,
842                                                 (char *)vp->vp_strvalue,
843                                                 sizeof(utmp.caller_id));
844                                 break;
845                 }
846         }
847
848         /*
849          *      If we didn't find out the NAS address, use the
850          *      originator's IP address.
851          */
852         if (nas_address == 0) {
853                 nas_address = request->packet->src_ipaddr;
854                 utmp.nas_address = nas_address;
855                 nas = client_name(nas_address); /* MUST be a valid client */
856
857         } else {                /* might be a client, might not be. */
858                 RADCLIENT *cl;
859
860                 /*
861                  *      Hack like 'client_name()', but with sane
862                  *      fall-back.
863                  */
864                 cl = client_find(nas_address);
865                 if (cl) {
866                         if (cl->shortname && cl->shortname[0]) {
867                                 nas = cl->shortname;
868                         } else {
869                                 nas = cl->longname;
870                         }
871                 } else {
872                         /*
873                          *      The NAS isn't a client, it's behind
874                          *      a proxy server.  In that case, just
875                          *      get the IP address.
876                          */
877                         nas = ip_ntoa(ip_name, nas_address);
878                 }
879         }
880
881         /*
882          *      Set the protocol field.
883          */
884         if (protocol == PW_PPP)
885                 utmp.proto = 'P';
886         else if (protocol == PW_SLIP)
887                 utmp.proto = 'S';
888         else
889                 utmp.proto = 'T';
890
891         utmp.time = request->timestamp - utmp.delay;
892
893         /*
894          *      Get the utmp filename, via xlat.
895          */
896         radius_xlat(filename, sizeof(filename), inst->filename, request, NULL);
897
898         /*
899          *      Future: look up filename in filename tree, to get
900          *      radutmp_cache_t pointer
901          */
902         cache = &inst->cache;
903
904         /*
905          *      For now, double-check the filename, to be sure it isn't
906          *      changing.
907          */
908         if (!cache->filename) {
909                 cache->filename = strdup(filename);
910                 rad_assert(cache->filename != NULL);
911
912         } else if (strcmp(cache->filename, filename) != 0) {
913                 radlog(L_ERR, "rlm_radutmp: We do not support dynamically named files.");
914                 return RLM_MODULE_FAIL;
915         }
916
917         /*
918          *      If the lookup failed, create a new one, and add it
919          *      to the filename tree, and cache the file, as below.
920          */
921
922         /*
923          *      For aging, in the future.
924          */
925         cache->last_used = request->timestamp;
926
927         /*
928          *      If we haven't already read the file, then read the
929          *      entire file, in order to cache its entries.
930          */
931         if (!cache->cached_file) {
932                 cache_file(inst, cache);
933         }
934
935         /*
936          *      See if this was a reboot.
937          *
938          *      Hmm... we may not want to zap all of the users when
939          *      the NAS comes up, because of issues with receiving
940          *      UDP packets out of order.
941          */
942         if (status == PW_STATUS_ACCOUNTING_ON && nas_address) {
943                 radlog(L_INFO, "rlm_radutmp: NAS %s restarted (Accounting-On packet seen)",
944                        nas);
945                 if (!radutmp_zap(inst, cache, nas_address, utmp.time)) {
946                         rad_assert(0 == 1);
947                 }
948                 return RLM_MODULE_OK;
949         }
950
951         if (status == PW_STATUS_ACCOUNTING_OFF && nas_address) {
952                 radlog(L_INFO, "rlm_radutmp: NAS %s rebooted (Accounting-Off packet seen)",
953                        nas);
954                 if (!radutmp_zap(inst, cache, nas_address, utmp.time)) {
955                         rad_assert(0 == 1);
956                 }
957                 return RLM_MODULE_OK;
958         }
959
960         /*
961          *      If we don't know this type of entry, then pretend we
962          *      succeeded.
963          */
964         if (status != PW_STATUS_START &&
965             status != PW_STATUS_STOP &&
966             status != PW_STATUS_ALIVE) {
967                 radlog(L_ERR, "rlm_radutmp: NAS %s port %u unknown packet type %d, ignoring it.",
968                        nas, utmp.nas_port, status);
969                 return RLM_MODULE_NOOP;
970         }
971
972         /*
973          *      Perhaps we don't want to store this record into
974          *      radutmp. We skip records:
975          *
976          *      - without a NAS-Port (telnet / tcp access)
977          *      - with the username "!root" (console admin login)
978          */
979         if (!port_seen) {
980                 DEBUG2("  rlm_radutmp: No NAS-Port in the packet.  Cannot do anything.");
981                 DEBUG2("  rlm_radumtp: WARNING: checkrad will probably not work!");
982                 return RLM_MODULE_NOOP;
983         }
984
985         /*
986          *      Translate the User-Name attribute, or whatever else
987          *      they told us to use.
988          */
989         *buffer = '\0';
990         radius_xlat(buffer, sizeof(buffer), inst->username, request, NULL);
991
992         /*
993          *      Don't log certain things...
994          */
995         if (strcmp(buffer, "!root") == 0) {
996                 DEBUG2("  rlm_radutmp: Not recording administrative user");
997
998                 return RLM_MODULE_NOOP;
999         }
1000         strlcpy(utmp.login, buffer, RUT_NAMESIZE);
1001
1002         /*
1003          *      First, try to open the file.  If it doesn't exist,
1004          *      nuke the existing caches, and try to create it.
1005          *
1006          *      FIXME: Create any intermediate directories, as
1007          *      appropriate.  See rlm_detail.
1008          */
1009         fd = open(cache->filename, O_RDWR, inst->permission);
1010         if (fd < 0) {
1011                 if (errno == ENOENT) {
1012                         DEBUG2("  rlm_radutmp: File %s doesn't exist, creating it.", cache->filename);
1013                         if (!cache_reset(inst, cache)) return RLM_MODULE_FAIL;
1014
1015                         /*
1016                          *      Try to create the file.
1017                          */
1018                         fd = open(cache->filename, O_RDWR | O_CREAT,
1019                                   inst->permission);
1020                 }
1021         } else {                /* exists, but may be empty */
1022                 struct stat buf;
1023
1024                 /*
1025                  *      If the file is empty, reset the cache.
1026                  */
1027                 if ((stat(cache->filename, &buf) == 0) &&
1028                     (buf.st_size == 0) &&
1029                     (!cache_reset(inst, cache))) {
1030                         return RLM_MODULE_FAIL;
1031                 }
1032                 DEBUG2("  rlm_radutmp: File %s was truncated.  Resetting cache.",
1033                        cache->filename);
1034         }
1035
1036         /*
1037          *      Error from creation, or error other than ENOENT: die.
1038          */
1039         if (fd < 0) {
1040                 radlog(L_ERR, "rlm_radutmp: Error accessing file %s: %s",
1041                        cache->filename, strerror(errno));
1042                 return RLM_MODULE_FAIL;
1043         }
1044
1045         /*
1046          *      OK.  Now that we've prepared everything we want to do,
1047          *      let's see if we've cached the entry.
1048          */
1049         myPort.nas_address = utmp.nas_address;
1050         myPort.nas_port = utmp.nas_port;
1051
1052         pthread_mutex_lock(&cache->mutex);
1053         node = rbtree_find(cache->nas_ports, &myPort);
1054         pthread_mutex_unlock(&cache->mutex);
1055
1056         if (node) {
1057                 nas_port = rbtree_node2data(cache->nas_ports, node);
1058 #if 0
1059
1060                 /*
1061                  *      stat the file, and get excited if it's been
1062                  *      truncated.
1063                  *
1064                  *      i.e wipe out the cache, and re-read the file.
1065                  */
1066
1067                 /*
1068                  *      Now find the new entry.
1069                  */
1070                 pthread_mutex_lock(&cache->mutex);
1071                 node = rbtree_find(cache->nas_ports, &myPort);
1072                 pthread_mutex_unlock(&cache->mutex);
1073 #endif
1074         }
1075
1076         if (!node) {
1077                 radutmp_simul_t *user;
1078
1079                 /*
1080                  *      Not found in the cache, and we're trying to
1081                  *      delete an existing record: ignore it.
1082                  */
1083                 if (status == PW_STATUS_STOP) {
1084                         DEBUG2("  rlm_radumtp: Logout entry for NAS %s port %u with no Login: ignoring it.",
1085                                nas, utmp.nas_port);
1086                         return RLM_MODULE_NOOP;
1087                 }
1088
1089                 pthread_mutex_lock(&cache->mutex);
1090
1091                 /*
1092                  *      It's a START or ALIVE.  Try to find a free
1093                  *      offset where we can store the new entry, or
1094                  *      create one, if one doesn't already exist.
1095                  */
1096                 if (!cache->free_offsets) {
1097                         cache->free_offsets = rad_malloc(sizeof(NAS_PORT));
1098                         memset(cache->free_offsets, 0,
1099                                sizeof(*(cache->free_offsets)));
1100                         cache->free_offsets->offset = cache->max_offset;
1101                         cache->max_offset += sizeof(u);
1102                 }
1103
1104                 /*
1105                  *      Grab the offset, and put it into the various
1106                  *      caches.
1107                  */
1108                 nas_port = cache->free_offsets;
1109                 cache->free_offsets = nas_port->next;
1110
1111                 nas_port->nas_address = nas_address;
1112                 nas_port->nas_port = utmp.nas_port;
1113
1114                 if (!rbtree_insert(cache->nas_ports, nas_port)) {
1115                         rad_assert(0 == 1);
1116                 }
1117
1118                 /*
1119                  *      Allocate new entry, and add it
1120                  *      to the tree.
1121                  */
1122                 user = rad_malloc(sizeof(user));
1123                 strlcpy(user->login, utmp.login,
1124                         sizeof(user->login));
1125                 user->simul_count = 1;
1126
1127                 if (!rbtree_insert(inst->user_tree, user)) {
1128                         rad_assert(0 == 1);
1129                 }
1130
1131                 pthread_mutex_unlock(&cache->mutex);
1132
1133         }
1134
1135         /*
1136          *      Entry was found, or newly created in the cache.
1137          *      Seek to the place in the file.
1138          */
1139         lseek(fd, nas_port->offset, SEEK_SET);
1140
1141         /*
1142          *      Lock the utmp file, prefer lockf() over flock().
1143          */
1144         rad_lockfd(fd, LOCK_LEN);
1145
1146         /*
1147          *      If it WAS found in the cache, double-check it against
1148          *      what is in the file.
1149          */
1150         if (node) {
1151                 /*
1152                  *      If we didn't read anything, then this entry
1153                  *      doesn't exist.
1154                  *
1155                  *      Similarly, if the entry in the file doesn't
1156                  *      match what we recall, then nuke the cache
1157                  *      entry.
1158                  */
1159                 read_size = read(fd, &u, sizeof(u));
1160                 if ((read_size < 0) ||
1161                     ((read_size > 0) && (read_size  != sizeof(u)))) {
1162                         /*
1163                          *      Bad read, or bad record.
1164                          */
1165                         radlog(L_ERR, "rlm_radutmp: Badly formed file %s",
1166                                cache->filename);
1167                         close(fd);
1168                         return RLM_MODULE_FAIL;
1169                 }
1170
1171                 rad_assert(read_size != 0);
1172
1173                 /*
1174                  *      We've read a record, go poke at it.
1175                  */
1176                 if (read_size > 0) {
1177                         /*
1178                          *      If these aren't true, then
1179                          *
1180                          *      a) we have cached a "logout" entry,
1181                          *         which we don't do.
1182                          *
1183                          *      b) we have cached the wrong NAS address
1184                          *
1185                          *      c) we have cached the wrong NAS port.
1186                          */
1187                         rad_assert(u.type == P_LOGIN);
1188                         rad_assert(u.nas_address == utmp.nas_address);
1189                         rad_assert(u.nas_port == utmp.nas_port);
1190
1191                         /*
1192                          *      An update for the same session.
1193                          */
1194                         if (strncmp(utmp.session_id, u.session_id,
1195                                     sizeof(u.session_id)) == 0) {
1196
1197                                 /*
1198                                  *      It's a duplicate start, so we
1199                                  *      don't bother writing it.
1200                                  */
1201                                 if (status == PW_STATUS_START) {
1202                                         DEBUG2("  rlm_radutmp: Login entry for NAS %s port %u duplicate, ignoring it.",
1203                                                nas, u.nas_port);
1204                                         close(fd);
1205                                         return RLM_MODULE_OK;
1206
1207
1208                                 /*
1209                                  *      ALIVE for this session, keep the
1210                                  *      original login time.
1211                                  */
1212                                 } else if (status == PW_STATUS_ALIVE) {
1213                                         utmp.time = u.time;
1214
1215                                 /*
1216                                  *      Stop: delete it from our cache.
1217                                  */
1218                                 } else if (status == PW_STATUS_STOP) {
1219                                         radutmp_simul_t *user, myUser;
1220
1221                                         pthread_mutex_lock(&cache->mutex);
1222                                         rbtree_deletebydata(cache->nas_ports,
1223                                                             nas_port);
1224
1225                                         strlcpy(myUser.login,
1226                                                 u.login, sizeof(myUser.login));
1227                                         user = rbtree_finddata(inst->user_tree,
1228                                                                &myUser);
1229                                         rad_assert(user != NULL);
1230                                         rad_assert(user->simul_count > 0);
1231
1232                                         user->simul_count--;
1233                                         if (user->simul_count == 0) {
1234                                                 rbtree_deletebydata(inst->user_tree, user);
1235                                         }
1236
1237                                         pthread_mutex_unlock(&cache->mutex);
1238
1239                                 } else {
1240                                         /*
1241                                          *      We don't know how to
1242                                          *      handle this.
1243                                          */
1244                                         rad_assert(0 == 1);
1245                                 }
1246
1247                         } else { /* session ID doesn't match */
1248                                 /*
1249                                  *      STOP for the right NAS & port,
1250                                  *      but the Acct-Session-Id is
1251                                  *      different.  This means that
1252                                  *      we missed the original "stop",
1253                                  *      and a new "start".
1254                                  */
1255                                 if (status == PW_STATUS_STOP) {
1256                                         radlog(L_ERR, "rlm_radutmp: Logout entry for NAS %s port %u has old Acct-Session-ID, ignoring it.",
1257                                                nas, u.nas_port);
1258                                         close(fd);
1259                                         return RLM_MODULE_OK;
1260                                 }
1261                         } /* checked session ID's */
1262                 }  /* else we haven't read anything from the file. */
1263         } /* else the entry wasn't cached, but could have been inserted */
1264
1265         /*
1266          *      Hmm... we may have received a start or alive packet
1267          *      AFTER a stop or nas-down, in that case, we want to
1268          *      discard the new packet.  However, the original code
1269          *      could over-write an idle record with a new login
1270          *      record for another NAS && port, so we won't worry
1271          *      about this case too much.
1272          */
1273
1274         /*
1275          *      Seek to where the entry is, and write it blindly.
1276          */
1277         lseek(fd, nas_port->offset, SEEK_SET); /* FIXME: err */
1278
1279         if (status != PW_STATUS_STOP) {
1280                 utmp.type = P_LOGIN;
1281                 rad_assert(nas_port != NULL); /* it WAS cached */
1282         } else {
1283                 /* FIXME: maybe assert that the entry was deleted... */
1284                 memcpy(&utmp, &u, sizeof(utmp));
1285                 utmp.type = P_IDLE;
1286         }
1287
1288         write(fd, &utmp, sizeof(utmp)); /* FIXME: err */
1289
1290         close(fd);      /* and implicitly release the locks */
1291
1292         return RLM_MODULE_OK;
1293 }
1294
1295 /*
1296  *      See if a user is already logged in. Sets request->simul_count
1297  *      to the current session count for this user and sets
1298  *      request->simul_mpp to 2 if it looks like a multilink attempt
1299  *      based on the requested IP address, otherwise leaves
1300  *      request->simul_mpp alone.
1301  *
1302  *      Check twice. If on the first pass the user exceeds his
1303  *      max. number of logins, do a second pass and validate all
1304  *      logins by querying the terminal server (using eg. SNMP).
1305  */
1306 static int radutmp_checksimul(void *instance, REQUEST *request)
1307 {
1308         struct radutmp  u;
1309         int             fd;
1310         VALUE_PAIR      *vp;
1311         uint32_t        ipno = 0;
1312         char            *call_num = NULL;
1313         int             rcode;
1314         rlm_radutmp_t   *inst = instance;
1315         char            login[256];
1316         char            filename[1024];
1317         radutmp_cache_t *cache;
1318         radutmp_simul_t *user, myUser;
1319
1320         /*
1321          *      Get the filename, via xlat.
1322          */
1323         radius_xlat(filename, sizeof(filename), inst->filename, request, NULL);
1324
1325         /*
1326          *      Future: look up filename in filename tree, to get
1327          *      radutmp_cache_t pointer
1328          */
1329         cache = &inst->cache;
1330
1331         /*
1332          *      For now, double-check the filename, to be sure it isn't
1333          *      changing.
1334          */
1335         if (!cache->filename) {
1336                 cache->filename = strdup(filename);
1337                 rad_assert(cache->filename != NULL);
1338
1339         } else if (strcmp(cache->filename, filename) != 0) {
1340                 radlog(L_ERR, "rlm_radutmp: We do not support dynamically named files.");
1341                 return RLM_MODULE_FAIL;
1342         }
1343
1344         *login = '\0';
1345         radius_xlat(login, sizeof(login), inst->username, request, NULL);
1346         if (!*login) {
1347                 return RLM_MODULE_NOOP;
1348         }
1349
1350         /*
1351          *      WTF?  This is probably wrong... we probably want to
1352          *      be able to check users across multiple session accounting
1353          *      methods.
1354          */
1355         request->simul_count = 0;
1356
1357         strlcpy(myUser.login, login, sizeof(myUser.login));
1358         pthread_mutex_lock(&inst->cache.mutex);
1359         user = rbtree_finddata(inst->user_tree, &myUser);
1360         if (user) request->simul_count = user->simul_count;
1361         user = NULL;            /* someone else may delete it */
1362         pthread_mutex_unlock(&inst->cache.mutex);
1363
1364         /*
1365          *      The number of users logged in is OK,
1366          *      OR, we've been told to not check the NAS.
1367          */
1368         if ((request->simul_count < request->simul_max) ||
1369             !inst->check_nas) {
1370                 return RLM_MODULE_OK;
1371         }
1372
1373         /*
1374          *      The user is logged in at least N times, and
1375          *      we're told to check the NAS.  In that case,
1376          *      we've got to read the file, and check each
1377          *      NAS port by hand.
1378          */
1379         if ((fd = open(cache->filename, O_RDWR)) < 0) {
1380                 /*
1381                  *      If the file doesn't exist, then no users
1382                  *      are logged in.
1383                  */
1384                 if (errno == ENOENT) {
1385                         request->simul_count = 0;
1386                         return RLM_MODULE_OK;
1387                 }
1388
1389                 /*
1390                  *      Error accessing the file.
1391                  */
1392                 radlog(L_ERR, "rlm_radumtp: Error accessing file %s: %s",
1393                        cache->filename, strerror(errno));
1394                 return RLM_MODULE_FAIL;
1395         }
1396
1397         /*
1398          *      Setup some stuff, like for MPP detection.
1399          */
1400         if ((vp = pairfind(request->packet->vps, PW_FRAMED_IP_ADDRESS)) != NULL)
1401                 ipno = vp->vp_ipaddr;
1402         if ((vp = pairfind(request->packet->vps, PW_CALLING_STATION_ID)) != NULL)
1403                 call_num = vp->vp_strvalue;
1404
1405         /*
1406          *      lock the file while reading/writing.
1407          */
1408         rad_lockfd(fd, LOCK_LEN);
1409
1410         /*
1411          *      FIXME: If we get a 'Start' for a user/nas/port which is
1412          *      listed, but for which we did NOT get a 'Stop', then
1413          *      it's not a duplicate session.  This happens with
1414          *      static IP's like DSL.
1415          */
1416         request->simul_count = 0;
1417         while (read(fd, &u, sizeof(u)) == sizeof(u)) {
1418                 if (((strncmp(login, u.login, RUT_NAMESIZE) == 0) ||
1419                      (!inst->case_sensitive &&
1420                       (strncasecmp(login, u.login, RUT_NAMESIZE) == 0))) &&
1421                     (u.type == P_LOGIN)) {
1422                         char session_id[sizeof(u.session_id) + 1];
1423                         char utmp_login[sizeof(u.login) + 1];
1424
1425                         strlcpy(session_id, u.session_id, sizeof(session_id));
1426
1427                         /*
1428                          *      The login name MAY fill the whole field,
1429                          *      and thus won't be zero-filled.
1430                          *
1431                          *      Note that we take the user name from
1432                          *      the utmp file, as that's the canonical
1433                          *      form.  The 'login' variable may contain
1434                          *      a string which is an upper/lowercase
1435                          *      version of u.login.  When we call the
1436                          *      routine to check the terminal server,
1437                          *      the NAS may be case sensitive.
1438                          *
1439                          *      e.g. We ask if "bob" is using a port,
1440                          *      and the NAS says "no", because "BOB"
1441                          *      is using the port.
1442                          */
1443                         strlcpy(utmp_login, u.login, sizeof(u.login));
1444
1445                         /*
1446                          *      rad_check_ts may take seconds
1447                          *      to return, and we don't want
1448                          *      to block everyone else while
1449                          *      that's happening.  */
1450                         rad_unlockfd(fd, LOCK_LEN);
1451                         rcode = rad_check_ts(u.nas_address, u.nas_port,
1452                                              utmp_login, session_id);
1453                         rad_lockfd(fd, LOCK_LEN);
1454
1455                         if (rcode == 0) {
1456                                 /*
1457                                  *      Stale record - zap it.
1458                                  *
1459                                  *      Hmm... this ends up calling
1460                                  *      the accounting section
1461                                  *      recursively...
1462                                  */
1463                                 session_zap(request, u.nas_address,
1464                                             u.nas_port, login, session_id,
1465                                             u.framed_address, u.proto,0);
1466                         }
1467                         else if (rcode == 1) {
1468                                 /*
1469                                  *      User is still logged in.
1470                                  */
1471                                 ++request->simul_count;
1472
1473                                 /*
1474                                  *      Does it look like a MPP attempt?
1475                                  */
1476                                 if (strchr("SCPA", u.proto) &&
1477                                     ipno && u.framed_address == ipno)
1478                                         request->simul_mpp = 2;
1479                                 else if (strchr("SCPA", u.proto) && call_num &&
1480                                         !strncmp(u.caller_id,call_num,16))
1481                                         request->simul_mpp = 2;
1482                         }
1483                         else {
1484                                 /*
1485                                  *      Failed to check the terminal
1486                                  *      server for duplicate logins:
1487                                  *      Return an error.
1488                                  */
1489                                 close(fd);
1490                                 radlog(L_ERR, "rlm_radutmp: Failed to check the terminal server for user '%s'.", utmp_login);
1491                                 return RLM_MODULE_FAIL;
1492                         }
1493                 }
1494         }
1495         close(fd);              /* and implicitly release the locks */
1496
1497         return RLM_MODULE_OK;
1498 }
1499
1500 /* globally exported name */
1501 module_t rlm_radutmp = {
1502   "radutmp",
1503   0,                            /* type: reserved */
1504   NULL,                         /* initialization */
1505   radutmp_instantiate,          /* instantiation */
1506   {
1507           NULL,                 /* authentication */
1508           NULL,                 /* authorization */
1509           NULL,                 /* preaccounting */
1510           radutmp_accounting,   /* accounting */
1511           radutmp_checksimul,   /* checksimul */
1512           NULL,                 /* pre-proxy */
1513           NULL,                 /* post-proxy */
1514           NULL                  /* post-auth */
1515   },
1516   radutmp_detach,               /* detach */
1517   NULL,                         /* destroy */
1518 };
1519