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