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