Move the Login-Time,Current-Time,Expiration attribute handling to separate
authorkkalev <kkalev>
Mon, 9 Aug 2004 15:31:05 +0000 (15:31 +0000)
committerkkalev <kkalev>
Mon, 9 Aug 2004 15:31:05 +0000 (15:31 +0000)
modules, rlm_logintime and rlm_expiration. Move timestr.c to rlm_logintime.
Update makefiles and radiusd.conf

raddb/radiusd.conf.in
src/main/Makefile.in
src/main/auth.c
src/main/valuepair.c
src/modules/rlm_expiration/Makefile [new file with mode: 0644]
src/modules/rlm_expiration/rlm_expiration.c [new file with mode: 0644]
src/modules/rlm_logintime/Makefile [new file with mode: 0644]
src/modules/rlm_logintime/rlm_logintime.c [new file with mode: 0644]
src/modules/rlm_logintime/timestr.c [moved from src/main/timestr.c with 100% similarity]
src/modules/stable

index 692c22e..5bf6799 100644 (file)
@@ -1375,6 +1375,46 @@ $INCLUDE ${confdir}/eap.conf
        }
 
        #
+       # The expiration module. This handles the Expiration attribute
+       # It should be included in the *end* of the authorize section
+       # in order to handle user Expiration. It should also be included
+       # in the instantiate section in order to register the Expiration
+       # compare function
+       #
+       expiration {
+               #
+               # The Reply-Message which will be sent back in case the
+               # account has expired. Dynamic substitution is supported
+               #
+               reply-message = "Password Has Expired\r\n" 
+#              reply-message = "Your account has expired, %{User-Name}\r\n"
+       }
+
+       #
+       # The logintime module. Handles the Login-Time and Current-Time attributes.
+       # It should be included in the *end* of the authorize section
+       # in order to handle Login-Time checks. It should also be included in
+       # the instantiate section in order to register the Current-Time compare
+       # function.
+       # If the user is allowed to logon a Session-Timeout is calculated based on the
+       # remaining time.
+       #
+       logintime {
+               #
+               # The Reply-Message which will be sent back in case the account
+               # is calling outside of the allowed timespan. Dynamic substitution is
+               # supported.
+               #
+               reply-message = "You are calling outside your allowed timespan\r\n"
+#              reply-message = "Outside allowed timespan (%{check:Login-Time}), %{User-Name}\r\n"
+               #
+               # The minimum timeout (in seconds) a user is allowed to have. If the calculated
+               # timeout is lower we don't allow the logon. Some NASes do not handle
+               # values lower than 60 seconds well.
+               #
+               minimum-timeout = 60
+       }
+       #
        #  Execute external programs
        #
        #  This module is useful only for 'xlat'.  To use it,
index 8d5c937..f9500bc 100644 (file)
@@ -5,7 +5,7 @@
 include ../../Make.inc
 
 SERVER_OBJS    = radiusd.o files.o util.o acct.o nas.o log.o valuepair.o \
-                 version.o proxy.o exec.o auth.o timestr.o conffile.o \
+                 version.o proxy.o exec.o auth.o conffile.o \
                  modules.o modcall.o session.o xlat.o threads.o smux.o \
                  radius_snmp.o client.o request_list.o mainconfig.o
 INCLUDES       = ../include/radiusd.h ../include/radius.h ../include/libradius.h ../include/conf.h ../include/autoconf.h
@@ -82,9 +82,6 @@ conffile.o: conffile.c $(INCLUDES) ../include/modules.h
 mainconfig.o: mainconfig.c $(INCLUDES) ../include/modules.h
        $(LIBTOOL) --mode=compile $(CC) $(CFLAGS) -c mainconfig.c
 
-timestr.o: timestr.c $(INCLUDES)
-       $(LIBTOOL) --mode=compile $(CC) $(CFLAGS) -c timestr.c
-
 modules.o:  modules.c $(INCLUDES)
        $(LIBTOOL) --mode=compile $(CC) $(CFLAGS) $(VFLAGS) $(INCLTDL) -c modules.c
 
index ec3b3ff..2188406 100644 (file)
@@ -60,45 +60,6 @@ char *auth_name(char *buf, size_t buflen, REQUEST *request, int do_cli) {
 }
 
 
-/*
- *     Check if account has expired, and if user may login now.
- */
-static int check_expiration(REQUEST *request)
-{
-       int result;
-       VALUE_PAIR *check_item = request->config_items;
-
-       result = 0;
-       while (result == 0 && check_item != NULL) {
-
-               /*
-                *      Check expiration date if we are doing password aging.
-                */
-               if (check_item->attribute == PW_EXPIRATION) {
-                       /*
-                        *      Has this user's password expired?
-                        *
-                        *      If so, remove ALL reply attributes,
-                        *      and add our own Reply-Message, saying
-                        *      why they're being rejected.
-                        */
-                       if (check_item->lvalue < (unsigned) time(NULL)) {
-                               VALUE_PAIR *vp;
-
-                               result = -1;
-                               vp = pairmake("Reply-Message",
-                                               "Password Has Expired\r\n",
-                                               T_OP_ADD);
-                               pairfree(&request->reply->vps);
-                               request->reply->vps = vp;
-                               break;
-                       }
-               }
-               check_item = check_item->next;
-       }
-       return result;
-}
-
 
 /*
  * Make sure user/pass are clean
@@ -613,8 +574,6 @@ autz_redo:
         *      Validate the user
         */
        do {
-               if ((result = check_expiration(request)) < 0)
-                               break;
                result = rad_check_password(request);
                if (result > 0) {
                        /* don't reply! */
@@ -716,65 +675,6 @@ autz_redo:
                }
        }
 
-       if (result >= 0 &&
-           (check_item = pairfind(request->config_items, PW_LOGIN_TIME)) != NULL) {
-
-               /*
-                *      Authentication is OK. Now see if this
-                *      user may login at this time of the day.
-                */
-               r = timestr_match((char *)check_item->strvalue,
-                                 request->timestamp);
-
-               if (r == 0) {   /* unlimited */
-                       /*
-                        *      Do nothing: login-time is OK.
-                        */
-
-                       /*
-                        *      Session-Timeout needs to be at least
-                        *      60 seconds, some terminal servers
-                        *      ignore smaller values.
-                        */
-               } else if (r < 60) {
-                       /*
-                        *      User called outside allowed time interval.
-                        */
-                       result = -1;
-                       user_msg = "You are calling outside your allowed timespan\r\n";
-
-                       request->reply->code = PW_AUTHENTICATION_REJECT;
-                       pairfree(&request->reply->vps);
-
-                       tmp = pairmake("Reply-Message", user_msg, T_OP_SET);
-                       request->reply->vps = tmp;
-
-                       snprintf(logstr, sizeof(logstr), "Outside allowed timespan (time allowed %s)",
-                                check_item->strvalue);
-                       rad_authlog(logstr, request, 1);
-
-               } else if (r > 0) {
-
-                       /*
-                        *      User is allowed, but set Session-Timeout.
-                        */
-                       if ((reply_item = pairfind(request->reply->vps,
-                                       PW_SESSION_TIMEOUT)) != NULL) {
-                               if (reply_item->lvalue > (unsigned) r)
-                                       reply_item->lvalue = r;
-                       } else {
-                               if ((reply_item = paircreate(
-                                               PW_SESSION_TIMEOUT,
-                                               PW_TYPE_INTEGER)) == NULL) {
-                                       radlog(L_ERR|L_CONS, "no memory");
-                                       exit(1);
-                               }
-                               reply_item->lvalue = r;
-                               pairadd(&request->reply->vps, reply_item);
-                       }
-               }
-       }
-
        /*
         *      Result should be >= 0 here - if not, it means the user
         *      is rejected, so we overwrite the Post-Auth-Type with
index eebe3d5..403f9ed 100644 (file)
@@ -599,29 +599,6 @@ static int presufcmp(void *instance,
 
 
 /*
- *     Compare the current time to a range.
- */
-static int timecmp(void *instance,
-                  REQUEST *req,
-                  VALUE_PAIR *request, VALUE_PAIR *check,
-       VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
-{
-       instance = instance;
-       request = request;      /* shut the compiler up */
-       check_pairs = check_pairs;
-       reply_pairs = reply_pairs;
-
-       /*
-        *      If there's a request, use that timestamp.
-        */
-       if (timestr_match((char *)check->strvalue,
-                         req ? req->timestamp : time(NULL)) >= 0) {
-               return 0;
-       }
-       return -1;
-}
-
-/*
  *     Matches if there is NO SUCH ATTRIBUTE as the one named
  *     in check->strvalue.  If there IS such an attribute, it
  *     doesn't match.
@@ -666,32 +643,6 @@ static int attrcmp(void *instance,
 }
 
 /*
- *     Compare the expiration date.
- */
-static int expirecmp(void *instance, REQUEST *req UNUSED,
-                    VALUE_PAIR *request, VALUE_PAIR *check,
-                    VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
-{
-       time_t now;
-
-       instance = instance;
-       request = request;      /* shut the compiler up */
-       check_pairs = check_pairs;
-       reply_pairs = reply_pairs;
-
-       /*
-        *  FIXME!  This should be request->timestamp!
-        */
-       now = time(NULL);
-
-       if (now <= (signed)check->lvalue) {
-               return 0;
-       }
-
-       return +1;
-}
-
-/*
  *     Compare the request packet type.
  */
 static int packetcmp(void *instance UNUSED, REQUEST *req,
@@ -733,9 +684,7 @@ void pair_builtincompare_init(void)
        paircompare_register(PW_PREFIX, PW_USER_NAME, presufcmp, NULL);
        paircompare_register(PW_SUFFIX, PW_USER_NAME, presufcmp, NULL);
        paircompare_register(PW_CONNECT_RATE, PW_CONNECT_INFO, connectcmp, NULL);
-       paircompare_register(PW_CURRENT_TIME, 0, timecmp, NULL);
        paircompare_register(PW_NO_SUCH_ATTRIBUTE, 0, attrcmp, NULL);
-       paircompare_register(PW_EXPIRATION, 0, expirecmp, NULL);
        paircompare_register(PW_PACKET_TYPE, 0, packetcmp, NULL);
        paircompare_register(PW_RESPONSE_PACKET_TYPE, 0, responsecmp, NULL);
 }
diff --git a/src/modules/rlm_expiration/Makefile b/src/modules/rlm_expiration/Makefile
new file mode 100644 (file)
index 0000000..77a5aad
--- /dev/null
@@ -0,0 +1,4 @@
+TARGET  = rlm_expiration
+SRCS    = rlm_expiration.c
+
+include ../rules.mak
diff --git a/src/modules/rlm_expiration/rlm_expiration.c b/src/modules/rlm_expiration/rlm_expiration.c
new file mode 100644 (file)
index 0000000..490ae6b
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * rlm_expiration.c
+ *
+ * Version:  $Id$
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Copyright 2001  The FreeRADIUS server project
+ * Copyright 2004  Kostas Kalevras <kkalev@noc.ntua.gr>
+ */
+
+#include "autoconf.h"
+#include "libradius.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "radiusd.h"
+#include "modules.h"
+#include "conffile.h"
+
+
+static const char rcsid[] = "$Id$";
+
+/*
+ *     Define a structure for our module configuration.
+ *
+ *     These variables do not need to be in a structure, but it's
+ *     a lot cleaner to do so, and a pointer to the structure can
+ *     be used as the instance handle.
+ */
+typedef struct rlm_expiration_t {
+       char *msg;              /* The Reply-Message passed back to the user if the account is expired */
+} rlm_expiration_t;
+
+/*
+ *     A mapping of configuration file names to internal variables.
+ *
+ *     Note that the string is dynamically allocated, so it MUST
+ *     be freed.  When the configuration file parse re-reads the string,
+ *     it free's the old one, and strdup's the new one, placing the pointer
+ *     to the strdup'd string into 'config.string'.  This gets around
+ *     buffer over-flows.
+ */
+static CONF_PARSER module_config[] = {
+  { "reply-message", PW_TYPE_STRING_PTR, offsetof(rlm_expiration_t,msg), NULL, "Password Has Expired\r\n"},
+  { NULL, -1, 0, NULL, NULL }
+};
+
+static int expiration_detach(void *instance);
+
+/*              
+ *      Check if account has expired, and if user may login now.
+ */              
+static int expiration_authorize(void *instance, REQUEST *request)
+{
+       rlm_expiration_t *data = (rlm_expiration_t *)instance;
+       VALUE_PAIR *check_item = NULL;
+       char msg[MAX_STRING_LEN];
+
+       if ((check_item = pairfind(request->config_items, PW_EXPIRATION)) != NULL){
+               /*
+               *      Has this user's password expired?
+               *
+               *      If so, remove ALL reply attributes,
+               *      and add our own Reply-Message, saying
+               *      why they're being rejected.
+               */
+               DEBUG("rlm_expiration: Checking Expiration time: '%s'",check_item->strvalue);
+               if (check_item->lvalue < (unsigned) time(NULL)) {
+                       char logstr[MAX_STRING_LEN];
+                       VALUE_PAIR *module_fmsg_vp;
+
+                       DEBUG("rlm_expiration: Account has expired");
+
+                       if (data->msg){
+                               VALUE_PAIR *vp;
+
+                               if (!radius_xlat(msg, sizeof(msg), data->msg, request, NULL)) {
+                                       radlog(L_ERR, "rlm_expiration: xlat failed.");
+                                       return RLM_MODULE_FAIL;
+                               }
+
+                               vp = pairmake("Reply-Message", msg, T_OP_ADD);
+                               pairfree(&request->reply->vps);
+                               request->reply->vps = vp;
+                       }
+                        snprintf(logstr, sizeof(logstr), "Account has expired [Expiration %s]",check_item->strvalue);
+                        module_fmsg_vp = pairmake("Module-Failure-Message", logstr, T_OP_EQ);
+                        pairadd(&request->packet->vps, module_fmsg_vp);
+
+                       return RLM_MODULE_USERLOCK;
+               }
+       }
+       else
+               return RLM_MODULE_NOOP;
+
+       return RLM_MODULE_OK;
+}
+
+/*
+ *      Compare the expiration date.
+ */
+static int expirecmp(void *instance, REQUEST *req,
+               VALUE_PAIR *request, VALUE_PAIR *check,
+               VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
+{
+       time_t now = 0;
+       instance = instance;
+       request = request;      /* shut the compiler up */
+       check_pairs = check_pairs;
+       reply_pairs = reply_pairs;
+
+       now = (req) ? req->timestamp : time(NULL);
+  
+       if (now <= (signed)check->lvalue)
+               return 0;
+       return +1;
+}
+
+
+/*
+ *     Do any per-module initialization that is separate to each
+ *     configured instance of the module.  e.g. set up connections
+ *     to external databases, read configuration files, set up
+ *     dictionary entries, etc.
+ *
+ *     If configuration information is given in the config section
+ *     that must be referenced in later calls, store a handle to it
+ *     in *instance otherwise put a null pointer there.
+ */
+static int expiration_instantiate(CONF_SECTION *conf, void **instance)
+{
+       rlm_expiration_t *data;
+
+       /*
+        *      Set up a storage area for instance data
+        */
+       data = rad_malloc(sizeof(*data));
+       if (!data) {
+               radlog(L_ERR, "rlm_expiration: rad_malloc() failed.");
+               return -1;
+       }
+       memset(data, 0, sizeof(*data));
+
+       /*
+        *      If the configuration parameters can't be parsed, then
+        *      fail.
+        */
+       if (cf_section_parse(conf, data, module_config) < 0) {
+               free(data);
+               radlog(L_ERR, "rlm_expiration: Configuration parsing failed.");
+               return -1;
+       }
+
+       /*
+        * If we are passed an empty reply-message don't use it
+        */
+       if (!strlen(data->msg)){
+               free(data->msg);
+               data->msg = NULL;
+       }
+
+       /*
+        * Register the expiration comparison operation.
+        */
+       paircompare_register(PW_EXPIRATION, 0, expirecmp, data);
+
+       *instance = data;
+
+       return 0;
+}
+
+static int expiration_detach(void *instance)
+{
+       rlm_expiration_t *data = (rlm_expiration_t *) instance;
+
+       paircompare_unregister(PW_CURRENT_TIME, expirecmp);
+       if (data->msg)
+               free(data->msg);
+       free(instance);
+       return 0;
+}
+
+/*
+ *     The module name should be the only globally exported symbol.
+ *     That is, everything else should be 'static'.
+ *
+ *     If the module needs to temporarily modify it's instantiation
+ *     data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
+ *     The server will then take care of ensuring that the module
+ *     is single-threaded.
+ */
+module_t rlm_expiration = {
+       "Expiration",
+       RLM_TYPE_THREAD_SAFE,           /* type */
+       NULL,                           /* initialization */
+       expiration_instantiate,         /* instantiation */
+       {
+               NULL,                   /* authentication */
+               expiration_authorize,   /* authorization */
+               NULL,                   /* preaccounting */
+               NULL,                   /* accounting */
+               NULL,                   /* checksimul */
+               NULL,                   /* pre-proxy */
+               NULL,                   /* post-proxy */
+               NULL                    /* post-auth */
+       },
+       expiration_detach,              /* detach */
+       NULL,                           /* destroy */
+};
diff --git a/src/modules/rlm_logintime/Makefile b/src/modules/rlm_logintime/Makefile
new file mode 100644 (file)
index 0000000..0706c20
--- /dev/null
@@ -0,0 +1,4 @@
+TARGET  = rlm_logintime
+SRCS    = rlm_logintime.c timestr.c
+
+include ../rules.mak
diff --git a/src/modules/rlm_logintime/rlm_logintime.c b/src/modules/rlm_logintime/rlm_logintime.c
new file mode 100644 (file)
index 0000000..e91882f
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * rlm_logintime.c
+ *
+ * Version:  $Id$
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Copyright 2001  The FreeRADIUS server project
+ * Copyright 2004  Kostas Kalevras <kkalev@noc.ntua.gr>
+ */
+
+#include "autoconf.h"
+#include "libradius.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "radiusd.h"
+#include "modules.h"
+#include "conffile.h"
+
+
+static const char rcsid[] = "$Id$";
+
+/*
+ *     Define a structure for our module configuration.
+ *
+ *     These variables do not need to be in a structure, but it's
+ *     a lot cleaner to do so, and a pointer to the structure can
+ *     be used as the instance handle.
+ */
+typedef struct rlm_logintime_t {
+       char *msg;              /* The Reply-Message passed back to the user 
+                                * if the account is outside allowed timestamp */
+       int min_time;
+} rlm_logintime_t;
+
+/*
+ *     A mapping of configuration file names to internal variables.
+ *
+ *     Note that the string is dynamically allocated, so it MUST
+ *     be freed.  When the configuration file parse re-reads the string,
+ *     it free's the old one, and strdup's the new one, placing the pointer
+ *     to the strdup'd string into 'config.string'.  This gets around
+ *     buffer over-flows.
+ */
+static CONF_PARSER module_config[] = {
+  { "reply-message", PW_TYPE_STRING_PTR, offsetof(rlm_logintime_t,msg), NULL, 
+       "You are calling outside your allowed timespan\r\n"},
+  { "minimum-timeout", PW_TYPE_INTEGER, offsetof(rlm_logintime_t,min_time), NULL, "60" },
+  { NULL, -1, 0, NULL, NULL }
+};
+
+static int logintime_detach(void *instance);
+
+/*
+ *      Compare the current time to a range.
+ */
+static int timecmp(void *instance,
+               REQUEST *req,
+               VALUE_PAIR *request, VALUE_PAIR *check,
+               VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
+{ 
+       instance = instance;
+       request = request;      /* shut the compiler up */
+       check_pairs = check_pairs;
+       reply_pairs = reply_pairs;
+  
+       /*
+        *      If there's a request, use that timestamp.       
+        */
+       if (timestr_match((char *)check->strvalue,
+       req ? req->timestamp : time(NULL)) >= 0)
+               return 0;
+
+       return -1;
+}
+
+/*              
+ *      Check if account has expired, and if user may login now.
+ */              
+static int logintime_authorize(void *instance, REQUEST *request)
+{
+       rlm_logintime_t *data = (rlm_logintime_t *)instance;
+       VALUE_PAIR *check_item = NULL;
+       int r;
+
+       if ((check_item = pairfind(request->config_items, PW_LOGIN_TIME)) != NULL) {
+               /*
+                *      Authentication is OK. Now see if this
+                *      user may login at this time of the day.
+                */
+               DEBUG("rlm_logintime: Checking Login-Time: '%s'",check_item->strvalue);
+               r = timestr_match((char *)check_item->strvalue,
+               request->timestamp);
+               if (r == 0) {   /* unlimited */
+                       /*
+                        *      Do nothing: login-time is OK.
+                        */
+
+               /*
+                *      Session-Timeout needs to be at least
+                *      60 seconds, some terminal servers
+                *      ignore smaller values.
+                */
+                       DEBUG("rlm_logintime: timestr returned unlimited");
+               } else if (r < data->min_time) {
+                       char logstr[MAX_STRING_LEN];
+                       VALUE_PAIR *module_fmsg_vp;
+
+                       /*
+                        *      User called outside allowed time interval.
+                        */
+               
+                       DEBUG("rlm_logintime: timestr returned reject");
+                       if (data->msg){
+                               char msg[MAX_STRING_LEN];
+                               VALUE_PAIR *tmp;
+
+                               if (!radius_xlat(msg, sizeof(msg), data->msg, request, NULL)) {
+                                       radlog(L_ERR, "rlm_logintime: xlat failed.");
+                                       return RLM_MODULE_FAIL;
+                               }
+                               pairfree(&request->reply->vps);
+                               tmp = pairmake("Reply-Message", msg, T_OP_SET);
+                               request->reply->vps = tmp;
+                       }
+
+                       snprintf(logstr, sizeof(logstr), "Outside allowed timespan (time allowed %s)",
+                       check_item->strvalue);
+                       module_fmsg_vp = pairmake("Module-Failure-Message", logstr, T_OP_EQ);
+                       pairadd(&request->packet->vps, module_fmsg_vp);
+
+                       return RLM_MODULE_REJECT;
+
+               } else if (r > 0) {
+                       VALUE_PAIR *reply_item;
+
+                       /*
+                        *      User is allowed, but set Session-Timeout.
+                        */
+                       DEBUG("rlm_logintime: timestr returned accept");
+                       if ((reply_item = pairfind(request->reply->vps, PW_SESSION_TIMEOUT)) != NULL) {
+                               if (reply_item->lvalue > (unsigned) r)
+                                       reply_item->lvalue = r;
+                       } else {
+                               if ((reply_item = paircreate( PW_SESSION_TIMEOUT, PW_TYPE_INTEGER)) == NULL) {
+                                       radlog(L_ERR|L_CONS, "no memory");
+                                       return RLM_MODULE_FAIL;
+                               }
+                               reply_item->lvalue = r;
+                               pairadd(&request->reply->vps, reply_item);
+                       }
+                       DEBUG("rlm_logintime: Session-Timeout set to: %d",r);
+               }
+       }
+       else
+               return RLM_MODULE_NOOP;
+
+       return RLM_MODULE_OK;
+}
+
+
+/*
+ *     Do any per-module initialization that is separate to each
+ *     configured instance of the module.  e.g. set up connections
+ *     to external databases, read configuration files, set up
+ *     dictionary entries, etc.
+ *
+ *     If configuration information is given in the config section
+ *     that must be referenced in later calls, store a handle to it
+ *     in *instance otherwise put a null pointer there.
+ */
+static int logintime_instantiate(CONF_SECTION *conf, void **instance)
+{
+       rlm_logintime_t *data;
+
+       /*
+        *      Set up a storage area for instance data
+        */
+       data = rad_malloc(sizeof(*data));
+       if (!data) {
+               radlog(L_ERR, "rlm_logintime: rad_malloc() failed.");
+               return -1;
+       }
+       memset(data, 0, sizeof(*data));
+
+       /*
+        *      If the configuration parameters can't be parsed, then
+        *      fail.
+        */
+       if (cf_section_parse(conf, data, module_config) < 0) {
+               free(data);
+               radlog(L_ERR, "rlm_logintime: Configuration parsing failed.");
+               return -1;
+       }
+
+       /*
+        * If we are passed an empty reply-message don't use it
+        */
+       if (!strlen(data->msg)){
+               free(data->msg);
+               data->msg = NULL;
+       }
+
+       if (data->min_time == 0){
+               radlog(L_ERR, "rlm_logintime: Minimum timeout should be non zero.");
+               free(data->msg);
+               free(data);
+               return -1;
+       }
+
+       /*
+        * Register a Current-Time comparison function
+        */
+       paircompare_register(PW_CURRENT_TIME, 0, timecmp, data);
+
+       *instance = data;
+
+       return 0;
+}
+
+static int logintime_detach(void *instance)
+{
+       rlm_logintime_t *data = (rlm_logintime_t *) instance;
+
+       paircompare_unregister(PW_CURRENT_TIME, timecmp);
+       if (data->msg)
+               free(data->msg);
+       free(instance);
+       return 0;
+}
+
+/*
+ *     The module name should be the only globally exported symbol.
+ *     That is, everything else should be 'static'.
+ *
+ *     If the module needs to temporarily modify it's instantiation
+ *     data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
+ *     The server will then take care of ensuring that the module
+ *     is single-threaded.
+ */
+module_t rlm_logintime = {
+       "Login Time",
+       RLM_TYPE_THREAD_SAFE,           /* type */
+       NULL,                           /* initialization */
+       logintime_instantiate,          /* instantiation */
+       {
+               NULL,                   /* authentication */
+               logintime_authorize,    /* authorization */
+               NULL,                   /* preaccounting */
+               NULL,                   /* accounting */
+               NULL,                   /* checksimul */
+               NULL,                   /* pre-proxy */
+               NULL,                   /* post-proxy */
+               NULL                    /* post-auth */
+       },
+       logintime_detach,               /* detach */
+       NULL,                           /* destroy */
+};
index 39fa68b..698504e 100644 (file)
@@ -11,12 +11,14 @@ rlm_detail
 rlm_digest
 rlm_eap
 rlm_exec
+rlm_expiration
 rlm_expr
 rlm_fastusers
 rlm_files
 rlm_ippool
 rlm_krb5
 rlm_ldap
+rlm_logintime
 rlm_mschap
 rlm_ns_mta_md5
 rlm_pam