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