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