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