Make NAS port unsigned
[freeradius.git] / src / modules / rlm_radutmp / rlm_radutmp.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * Copyright 2000  The FreeRADIUS server project
21  * FIXME add copyrights
22  */
23
24 #include        "autoconf.h"
25
26 #include        <sys/types.h>
27 #include        <stdio.h>
28 #include        <string.h>
29 #include        <stdlib.h>
30 #include        <unistd.h>
31 #include        <fcntl.h>
32 #include        <time.h>
33 #include        <errno.h>
34 #include        <limits.h>
35
36 #include "config.h"
37
38 #include        "radiusd.h"
39 #include        "radutmp.h"
40 #include        "modules.h"
41
42 #define LOCK_LEN sizeof(struct radutmp)
43
44 static const char porttypes[] = "ASITX";
45
46 /*
47  *      used for caching radutmp lookups in the accounting component. The
48  *      session (checksimul) component doesn't use it, but probably should.
49  */
50 typedef struct nas_port {
51         uint32_t                nasaddr;
52         unsigned int    port;
53         off_t                   offset;
54         struct nas_port         *next;
55 } NAS_PORT;
56
57 typedef struct rlm_radutmp_t {
58         NAS_PORT        *nas_port_list;
59         char            *filename;
60         char            *username;
61         int             case_sensitive;
62         int             check_nas;
63         int             permission;
64         int             callerid_ok;
65 } rlm_radutmp_t;
66
67 static CONF_PARSER module_config[] = {
68         { "filename", PW_TYPE_STRING_PTR,
69           offsetof(rlm_radutmp_t,filename), NULL,  RADUTMP },
70         { "username", PW_TYPE_STRING_PTR,
71           offsetof(rlm_radutmp_t,username), NULL,  "%{User-Name}"},
72         { "case_sensitive", PW_TYPE_BOOLEAN,
73           offsetof(rlm_radutmp_t,case_sensitive), NULL,  "yes"},
74         { "check_with_nas", PW_TYPE_BOOLEAN,
75           offsetof(rlm_radutmp_t,check_nas), NULL,  "yes"},
76         { "perm",     PW_TYPE_INTEGER,
77           offsetof(rlm_radutmp_t,permission), NULL,  "0644" },
78         { "callerid", PW_TYPE_BOOLEAN,
79           offsetof(rlm_radutmp_t,callerid_ok), NULL, "no" },
80         { NULL, -1, 0, NULL, NULL }             /* end the list */
81 };
82
83 static int radutmp_instantiate(CONF_SECTION *conf, void **instance)
84 {
85         rlm_radutmp_t *inst;
86
87         inst = rad_malloc(sizeof(*inst));
88
89         if (cf_section_parse(conf, inst, module_config)) {
90                 free(inst);
91                 return -1;
92         }
93
94         inst->nas_port_list = NULL;
95         *instance = inst;
96         return 0;
97 }
98
99
100 /*
101  *      Detach.
102  */
103 static int radutmp_detach(void *instance)
104 {
105         NAS_PORT *p, *next;
106         rlm_radutmp_t *inst = instance;
107
108         for (p = inst->nas_port_list ; p ; p=next) {
109                 next = p->next;
110                 free(p);
111         }
112         free(inst->filename);
113         free(inst);
114         return 0;
115 }
116
117 /*
118  *      Zap all users on a NAS from the radutmp file.
119  */
120 static int radutmp_zap(rlm_radutmp_t *inst,
121                        const char *filename,
122                        uint32_t nasaddr,
123                        time_t t)
124 {
125         struct radutmp  u;
126         int             fd;
127
128         if (t == 0) time(&t);
129
130         fd = open(filename, O_RDWR);
131         if (fd < 0) {
132                 radlog(L_ERR, "rlm_radutmp: Error accessing file %s: %s",
133                        filename, strerror(errno));
134                 return RLM_MODULE_FAIL;
135         }
136
137         /*
138          *      Lock the utmp file, prefer lockf() over flock().
139          */
140         rad_lockfd(fd, LOCK_LEN);
141         
142         /*
143          *      Find the entry for this NAS / portno combination.
144          */
145         while (read(fd, &u, sizeof(u)) == sizeof(u)) {
146           if ((nasaddr != 0 && nasaddr != u.nas_address) ||
147               u.type != P_LOGIN)
148             continue;
149           /*
150            *    Match. Zap it.
151            */
152           if (lseek(fd, -(off_t)sizeof(u), SEEK_CUR) < 0) {
153             radlog(L_ERR, "rlm_radutmp: radutmp_zap: negative lseek!");
154             lseek(fd, (off_t)0, SEEK_SET);
155           }
156           u.type = P_IDLE;
157           u.time = t;
158           write(fd, &u, sizeof(u));
159         }
160         close(fd);      /* and implicitely release the locks */
161
162         return 0;
163 }
164
165 /*
166  *      Lookup a NAS_PORT in the nas_port_list
167  */
168 static NAS_PORT *nas_port_find(NAS_PORT *nas_port_list, uint32_t nasaddr, unsigned int port)
169 {
170         NAS_PORT        *cl;
171
172         for(cl = nas_port_list; cl; cl = cl->next)
173                 if (nasaddr == cl->nasaddr &&
174                         port == cl->port)
175                         break;
176         return cl;
177 }
178
179
180 /*
181  *      Store logins in the RADIUS utmp file.
182  */
183 static int radutmp_accounting(void *instance, REQUEST *request)
184 {
185         struct radutmp  ut, u;
186         VALUE_PAIR      *vp;
187         int             status = -1;
188         uint32_t        nas_address = 0;
189         uint32_t        framed_address = 0;
190         int             protocol = -1;
191         time_t          t;
192         int             fd;
193         int             just_an_update = 0;
194         int             port_seen = 0;
195         int             nas_port_type = 0;
196         int             off;
197         rlm_radutmp_t   *inst = instance;
198         char            buffer[256];
199         char            filename[1024];
200         char            ip_name[32]; /* 255.255.255.255 */
201         const char      *nas;
202         NAS_PORT        *cache;
203         int             r;
204
205         /*
206          *      Which type is this.
207          */
208         if ((vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE)) == NULL) {
209                 radlog(L_ERR, "rlm_radutmp: No Accounting-Status-Type record.");
210                 return RLM_MODULE_NOOP;
211         }
212         status = vp->lvalue;
213
214         /*
215          *      Look for weird reboot packets.
216          *
217          *      ComOS (up to and including 3.5.1b20) does not send
218          *      standard PW_STATUS_ACCOUNTING_XXX messages.
219          *
220          *      Check for:  o no Acct-Session-Time, or time of 0
221          *                  o Acct-Session-Id of "00000000".
222          *
223          *      We could also check for NAS-Port, that attribute
224          *      should NOT be present (but we don't right now).
225          */
226         if ((status != PW_STATUS_ACCOUNTING_ON) &&
227             (status != PW_STATUS_ACCOUNTING_OFF)) do {
228                 int check1 = 0;
229                 int check2 = 0;
230
231                 if ((vp = pairfind(request->packet->vps, PW_ACCT_SESSION_TIME))
232                      == NULL || vp->lvalue == 0)
233                         check1 = 1;
234                 if ((vp = pairfind(request->packet->vps, PW_ACCT_SESSION_ID))
235                      != NULL && vp->length == 8 &&
236                      memcmp(vp->strvalue, "00000000", 8) == 0)
237                         check2 = 1;
238                 if (check1 == 0 || check2 == 0) {
239 #if 0 /* Cisco sometimes sends START records without username. */
240                         radlog(L_ERR, "rlm_radutmp: no username in record");
241                         return RLM_MODULE_FAIL;
242 #else
243                         break;
244 #endif
245                 }
246                 radlog(L_INFO, "rlm_radutmp: converting reboot records.");
247                 if (status == PW_STATUS_STOP)
248                         status = PW_STATUS_ACCOUNTING_OFF;
249                 if (status == PW_STATUS_START)
250                         status = PW_STATUS_ACCOUNTING_ON;
251         } while(0);
252
253         time(&t);
254         memset(&ut, 0, sizeof(ut));
255         ut.porttype = 'A';
256
257         /*
258          *      First, find the interesting attributes.
259          */
260         for (vp = request->packet->vps; vp; vp = vp->next) {
261                 switch (vp->attribute) {
262                         case PW_LOGIN_IP_HOST:
263                         case PW_FRAMED_IP_ADDRESS:
264                                 framed_address = vp->lvalue;
265                                 ut.framed_address = vp->lvalue;
266                                 break;
267                         case PW_FRAMED_PROTOCOL:
268                                 protocol = vp->lvalue;
269                                 break;
270                         case PW_NAS_IP_ADDRESS:
271                                 nas_address = vp->lvalue;
272                                 ut.nas_address = vp->lvalue;
273                                 break;
274                         case PW_NAS_PORT:
275                                 ut.nas_port = vp->lvalue;
276                                 port_seen = 1;
277                                 break;
278                         case PW_ACCT_DELAY_TIME:
279                                 ut.delay = vp->lvalue;
280                                 break;
281                         case PW_ACCT_SESSION_ID:
282                                 /*
283                                  *      If length > 8, only store the
284                                  *      last 8 bytes.
285                                  */
286                                 off = vp->length - sizeof(ut.session_id);
287                                 /*
288                                  *      Ascend is br0ken - it adds a \0
289                                  *      to the end of any string.
290                                  *      Compensate.
291                                  */
292                                 if (vp->length > 0 &&
293                                     vp->strvalue[vp->length - 1] == 0)
294                                         off--;
295                                 if (off < 0) off = 0;
296                                 memcpy(ut.session_id, vp->strvalue + off,
297                                         sizeof(ut.session_id));
298                                 break;
299                         case PW_NAS_PORT_TYPE:
300                                 if (vp->lvalue >= 0 && vp->lvalue <= 4)
301                                         ut.porttype = porttypes[vp->lvalue];
302                                 nas_port_type = vp->lvalue;
303                                 break;
304                         case PW_CALLING_STATION_ID:
305                                 if(inst->callerid_ok)
306                                         strNcpy(ut.caller_id,
307                                                 (char *)vp->strvalue,
308                                                 sizeof(ut.caller_id));
309                                 break;
310                 }
311         }
312
313         /*
314          *      If we didn't find out the NAS address, use the
315          *      originator's IP address.
316          */
317         if (nas_address == 0) {
318                 nas_address = request->packet->src_ipaddr;
319                 ut.nas_address = nas_address;
320                 nas = client_name(nas_address); /* MUST be a valid client */
321
322         } else {                /* might be a client, might not be. */
323                 RADCLIENT *cl;
324
325                 /*
326                  *      Hack like 'client_name()', but with sane
327                  *      fall-back.
328                  */
329                 cl = client_find(nas_address);
330                 if (cl) {
331                         if (cl->shortname[0]) {
332                                 nas = cl->shortname;
333                         } else {
334                                 nas = cl->longname;
335                         }
336                 } else {
337                         /*
338                          *      The NAS isn't a client, it's behind
339                          *      a proxy server.  In that case, just
340                          *      get the IP address.
341                          */
342                         nas = ip_ntoa(ip_name, nas_address);
343                 }
344         }
345
346         /*
347          *      Set the protocol field.
348          */
349         if (protocol == PW_PPP)
350                 ut.proto = 'P';
351         else if (protocol == PW_SLIP)
352                 ut.proto = 'S';
353         else
354                 ut.proto = 'T';
355         ut.time = t - ut.delay;
356
357         /*
358          *      Get the utmp filename, via xlat.
359          */
360         radius_xlat(filename, sizeof(filename), inst->filename, request, NULL);
361
362         /*
363          *      See if this was a reboot.
364          *
365          *      Hmm... we may not want to zap all of the users when
366          *      the NAS comes up, because of issues with receiving
367          *      UDP packets out of order.
368          */
369         if (status == PW_STATUS_ACCOUNTING_ON && nas_address) {
370                 radlog(L_INFO, "rlm_radutmp: NAS %s restarted (Accounting-On packet seen)",
371                        nas);
372                 radutmp_zap(inst, filename, nas_address, ut.time);
373                 return RLM_MODULE_OK;
374         }
375
376         if (status == PW_STATUS_ACCOUNTING_OFF && nas_address) {
377                 radlog(L_INFO, "rlm_radutmp: NAS %s rebooted (Accounting-Off packet seen)",
378                        nas);
379                 radutmp_zap(inst, filename, nas_address, ut.time);
380                 return RLM_MODULE_OK;
381         }
382
383         /*
384          *      If we don't know this type of entry pretend we succeeded.
385          */
386         if (status != PW_STATUS_START &&
387             status != PW_STATUS_STOP &&
388             status != PW_STATUS_ALIVE) {
389                 radlog(L_ERR, "rlm_radutmp: NAS %s port %u unknown packet type %d)",
390                        nas, ut.nas_port, status);
391                 return RLM_MODULE_NOOP;
392         }
393
394         /*
395          *      Translate the User-Name attribute, or whatever else
396          *      they told us to use.
397          */
398         *buffer = '\0';
399         radius_xlat(buffer, sizeof(buffer), inst->username, request, NULL);
400
401         /*
402          *  Copy the previous translated user name.
403          */
404         strncpy(ut.login, buffer, RUT_NAMESIZE);
405
406         /*
407          *      Perhaps we don't want to store this record into
408          *      radutmp. We skip records:
409          *
410          *      - without a NAS-Port (telnet / tcp access)
411          *      - with the username "!root" (console admin login)
412          */
413         if (!port_seen) {
414                 DEBUG2("  rlm_radutmp: No NAS-Port seen.  Cannot do anything.");
415                 DEBUG2("  rlm_radumtp: WARNING: checkrad will probably not work!");
416                 return RLM_MODULE_NOOP;
417         }
418
419         if (strncmp(ut.login, "!root", RUT_NAMESIZE) == 0) {
420                 DEBUG2("  rlm_radutmp: Not recording administrative user");
421
422                 return RLM_MODULE_NOOP;
423         }
424
425         /*
426          *      Enter into the radutmp file.
427          */
428         fd = open(filename, O_RDWR|O_CREAT, inst->permission);
429         if (fd < 0) {
430                 radlog(L_ERR, "rlm_radutmp: Error accessing file %s: %s",
431                        filename, strerror(errno));
432                 return RLM_MODULE_FAIL;
433         }
434
435         /*
436          *      Lock the utmp file, prefer lockf() over flock().
437          */
438         rad_lockfd(fd, LOCK_LEN);
439         
440         /*
441          *      Find the entry for this NAS / portno combination.
442          */
443         if ((cache = nas_port_find(inst->nas_port_list, ut.nas_address,
444                                    ut.nas_port)) != NULL) {
445                 lseek(fd, (off_t)cache->offset, SEEK_SET);
446         }
447         
448         r = 0;
449         off = 0;
450         while (read(fd, &u, sizeof(u)) == sizeof(u)) {
451                 off += sizeof(u);
452                 if (u.nas_address != ut.nas_address ||
453                     u.nas_port    != ut.nas_port)
454                         continue;
455                 
456                 if (status == PW_STATUS_STOP &&
457                     strncmp(ut.session_id, u.session_id,
458                             sizeof(u.session_id)) != 0) {
459                         /*
460                          *      Don't complain if this is not a
461                          *      login record (some clients can
462                          *      send _only_ logout records).
463                          */
464                         if (u.type == P_LOGIN)
465                                 radlog(L_ERR, "rlm_radutmp: Logout entry for NAS %s port %u has wrong ID",
466                                        nas, u.nas_port);
467                         r = -1;
468                         break;
469                 }
470                 
471                 if (status == PW_STATUS_START &&
472                     strncmp(ut.session_id, u.session_id,
473                             sizeof(u.session_id)) == 0  &&
474                     u.time >= ut.time) {
475                         if (u.type == P_LOGIN) {
476                                 radlog(L_INFO, "rlm_radutmp: Login entry for NAS %s port %u duplicate",
477                                        nas, u.nas_port);
478                                 r = -1;
479                                 break;
480                         }
481                         radlog(L_ERR, "rlm_radutmp: Login entry for NAS %s port %u wrong order",
482                                nas, u.nas_port);
483                         r = -1;
484                         break;
485                 }
486                 
487                 /*
488                  *      FIXME: the ALIVE record could need
489                  *      some more checking, but anyway I'd
490                  *      rather rewrite this mess -- miquels.
491                  */
492                 if (status == PW_STATUS_ALIVE &&
493                     strncmp(ut.session_id, u.session_id,
494                             sizeof(u.session_id)) == 0  &&
495                     u.type == P_LOGIN) {
496                         /*
497                          *      Keep the original login time.
498                          */
499                         ut.time = u.time;
500                         if (u.login[0] != 0)
501                                 just_an_update = 1;
502                 }
503                 
504                 if (lseek(fd, -(off_t)sizeof(u), SEEK_CUR) < 0) {
505                         radlog(L_ERR, "rlm_radutmp: negative lseek!");
506                         lseek(fd, (off_t)0, SEEK_SET);
507                         off = 0;
508                 } else
509                         off -= sizeof(u);
510                 r = 1;
511                 break;
512         } /* read the file until we find a match */
513
514         /*
515          *      Found the entry, do start/update it with
516          *      the information from the packet.
517          */
518         if (r >= 0 &&  (status == PW_STATUS_START ||
519                         status == PW_STATUS_ALIVE)) {
520                 /*
521                  *      Remember where the entry was, because it's
522                  *      easier than searching through the entire file.
523                  */
524                 if (cache == NULL) {
525                         cache = rad_malloc(sizeof(NAS_PORT));
526                         cache->nasaddr = ut.nas_address;
527                         cache->port = ut.nas_port;
528                         cache->offset = off;
529                         cache->next = inst->nas_port_list;
530                         inst->nas_port_list = cache;
531                 }
532                 
533                 ut.type = P_LOGIN;
534                 write(fd, &ut, sizeof(u));
535         }
536         
537         /*
538          *      The user has logged off, delete the entry by
539          *      re-writing it in place.
540          */
541         if (status == PW_STATUS_STOP) {
542                 if (r > 0) {
543                         u.type = P_IDLE;
544                         u.time = ut.time;
545                         u.delay = ut.delay;
546                         write(fd, &u, sizeof(u));
547                 } else if (r == 0) {
548                         radlog(L_ERR, "rlm_radutmp: Logout for NAS %s port %u, but no Login record",
549                                nas, ut.nas_port);
550                         r = -1;
551                 }
552         }
553         close(fd);      /* and implicitely release the locks */
554
555         return RLM_MODULE_OK;
556 }
557
558 /*
559  *      See if a user is already logged in. Sets request->simul_count to the
560  *      current session count for this user and sets request->simul_mpp to 2
561  *      if it looks like a multilink attempt based on the requested IP
562  *      address, otherwise leaves request->simul_mpp alone.
563  *
564  *      Check twice. If on the first pass the user exceeds his
565  *      max. number of logins, do a second pass and validate all
566  *      logins by querying the terminal server (using eg. SNMP).
567  */
568 static int radutmp_checksimul(void *instance, REQUEST *request)
569 {
570         struct radutmp  u;
571         int             fd;
572         VALUE_PAIR      *vp;
573         uint32_t        ipno = 0;
574         char            *call_num = NULL;
575         int             rcode;
576         rlm_radutmp_t   *inst = instance;
577         char            login[256];
578         char            filename[1024];
579
580         /*
581          *      Get the filename, via xlat.
582          */
583         radius_xlat(filename, sizeof(filename), inst->filename, request, NULL);
584
585         if ((fd = open(filename, O_RDWR)) < 0) {
586                 /*
587                  *      If the file doesn't exist, then no users
588                  *      are logged in.
589                  */
590                 if (errno == ENOENT) {
591                         request->simul_count=0;
592                         return RLM_MODULE_OK;
593                 }
594
595                 /*
596                  *      Error accessing the file.
597                  */
598                 radlog(L_ERR, "rlm_radumtp: Error accessing file %s: %s",
599                        filename, strerror(errno));
600                 return RLM_MODULE_FAIL;
601         }
602
603         *login = '\0';
604         radius_xlat(login, sizeof(login), inst->username, request, NULL);
605         if (!*login) {
606                 return RLM_MODULE_NOOP;
607         }
608
609         /*
610          *      WTF?  This is probably wrong... we probably want to
611          *      be able to check users across multiple session accounting
612          *      methods.
613          */
614         request->simul_count = 0;
615
616         /*
617          *      Loop over utmp, counting how many people MAY be logged in.
618          */
619         while (read(fd, &u, sizeof(u)) == sizeof(u)) {
620                 if (((strncmp(login, u.login, RUT_NAMESIZE) == 0) ||
621                      (!inst->case_sensitive &&
622                       (strncasecmp(login, u.login, RUT_NAMESIZE) == 0))) &&
623                     (u.type == P_LOGIN)) {
624                         ++request->simul_count;
625                 }
626         }
627
628         /*
629          *      The number of users logged in is OK,
630          *      OR, we've been told to not check the NAS.
631          */
632         if ((request->simul_count < request->simul_max) ||
633             !inst->check_nas) {
634                 close(fd);
635                 return RLM_MODULE_OK;
636         }
637         lseek(fd, (off_t)0, SEEK_SET);
638
639         /*
640          *      Setup some stuff, like for MPP detection.
641          */
642         if ((vp = pairfind(request->packet->vps, PW_FRAMED_IP_ADDRESS)) != NULL)
643                 ipno = vp->lvalue;
644         if ((vp = pairfind(request->packet->vps, PW_CALLING_STATION_ID)) != NULL)
645                 call_num = vp->strvalue;        
646
647         /*
648          *      lock the file while reading/writing.
649          */
650         rad_lockfd(fd, LOCK_LEN);
651
652         /*
653          *      FIXME: If we get a 'Start' for a user/nas/port which is
654          *      listed, but for which we did NOT get a 'Stop', then
655          *      it's not a duplicate session.  This happens with
656          *      static IP's like DSL.
657          */
658         request->simul_count = 0;
659         while (read(fd, &u, sizeof(u)) == sizeof(u)) {
660                 if (((strncmp(login, u.login, RUT_NAMESIZE) == 0) ||
661                      (!inst->case_sensitive &&
662                       (strncasecmp(login, u.login, RUT_NAMESIZE) == 0))) &&
663                     (u.type == P_LOGIN)) {
664                         char session_id[sizeof(u.session_id) + 1];
665                         char utmp_login[sizeof(u.login) + 1];
666
667                         strNcpy(session_id, u.session_id, sizeof(session_id));
668
669                         /*
670                          *      The login name MAY fill the whole field,
671                          *      and thus won't be zero-filled.
672                          *
673                          *      Note that we take the user name from
674                          *      the utmp file, as that's the canonical
675                          *      form.  The 'login' variable may contain
676                          *      a string which is an upper/lowercase
677                          *      version of u.login.  When we call the
678                          *      routine to check the terminal server,
679                          *      the NAS may be case sensitive.
680                          *
681                          *      e.g. We ask if "bob" is using a port,
682                          *      and the NAS says "no", because "BOB"
683                          *      is using the port.
684                          */
685                         strNcpy(utmp_login, u.login, sizeof(u.login));
686
687                         /*
688                          *      rad_check_ts may take seconds
689                          *      to return, and we don't want
690                          *      to block everyone else while
691                          *      that's happening.  */
692                         rad_unlockfd(fd, LOCK_LEN);
693                         rcode = rad_check_ts(u.nas_address, u.nas_port,
694                                              utmp_login, session_id);
695                         rad_lockfd(fd, LOCK_LEN);
696                         
697                         /*
698                          *      Failed to check the terminal server for
699                          *      duplicate logins: Return an error.
700                          */
701                         if (rcode < 0) {
702                                 close(fd);
703                                 return RLM_MODULE_FAIL;
704                         }
705
706                         if (rcode == 1) {
707                                 ++request->simul_count;
708
709                                 /*
710                                  *      Does it look like a MPP attempt?
711                                  */
712                                 if (strchr("SCPA", u.proto) &&
713                                     ipno && u.framed_address == ipno)
714                                         request->simul_mpp = 2;
715                                 else if (strchr("SCPA", u.proto) && call_num &&
716                                         !strncmp(u.caller_id,call_num,16))
717                                         request->simul_mpp = 2;
718                         }
719                         else {
720                                 /*
721                                  *      False record - zap it.
722                                  */
723                                 session_zap(request->packet->sockfd,
724                                             u.nas_address, u.nas_port, login,
725                                             session_id, u.framed_address,
726                                             u.proto, 0);
727                         }
728                 }
729         }
730         close(fd);              /* and implicitely release the locks */
731
732         return RLM_MODULE_OK;
733 }
734
735 /* globally exported name */
736 module_t rlm_radutmp = {
737   "radutmp",
738   0,                            /* type: reserved */
739   NULL,                         /* initialization */
740   radutmp_instantiate,          /* instantiation */
741   {
742           NULL,                 /* authentication */
743           NULL,                 /* authorization */
744           NULL,                 /* preaccounting */
745           radutmp_accounting,   /* accounting */
746           radutmp_checksimul,   /* checksimul */
747           NULL,                 /* pre-proxy */
748           NULL,                 /* post-proxy */
749           NULL                  /* post-auth */
750   },
751   radutmp_detach,               /* detach */
752   NULL,                         /* destroy */
753 };
754