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