Updated API for 2.2
[freeradius.git] / src / modules / rlm_counter / rlm_counter.c
index 3c35628..d5ed5d2 100644 (file)
  *
  *   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
+ *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  *
- * Copyright 2001  The FreeRADIUS server project
+ * Copyright 2001,2006  The FreeRADIUS server project
  * Copyright 2001  Alan DeKok <aland@ox.org>
  * Copyright 2001-3  Kostas Kalevras <kkalev@noc.ntua.gr>
  */
 
-#include "config.h"
-#include "autoconf.h"
-#include "libradius.h"
+#include <freeradius-devel/ident.h>
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
 #include <ctype.h>
 
-#include "radiusd.h"
-#include "modules.h"
-#include "conffile.h"
+#include "config.h"
 
 #include <gdbm.h>
-#include <time.h>
 
 #ifdef NEEDS_GDBM_SYNC
 #      define GDBM_SYNCOPT GDBM_SYNC
@@ -56,8 +52,6 @@
 
 #define UNIQUEID_MAX_LEN 32
 
-static const char rcsid[] = "$Id$";
-
 /*
  *     Define a structure for our module configuration.
  *
@@ -70,16 +64,16 @@ typedef struct rlm_counter_t {
        char *reset;            /* daily, weekly, monthly, never or user defined */
        char *key_name;         /* User-Name */
        char *count_attribute;  /* Acct-Session-Time */
-       char *return_attribute; /* Session-Timeout */
        char *counter_name;     /* Daily-Session-Time */
        char *check_name;       /* Daily-Max-Session */
+       char *reply_name;       /* Session-Timeout */
        char *service_type;     /* Service-Type to search for */
        int cache_size;
        int service_val;
        int key_attr;
        int count_attr;
-       int return_attr;
        int check_attr;
+       int reply_attr;
        time_t reset_time;      /* The time of the next reset. */
        time_t last_reset;      /* The time of the last reset. */
        int dict_attr;          /* attribute number for the counter. */
@@ -119,9 +113,9 @@ static const CONF_PARSER module_config[] = {
   { "key", PW_TYPE_STRING_PTR, offsetof(rlm_counter_t,key_name), NULL, NULL },
   { "reset", PW_TYPE_STRING_PTR, offsetof(rlm_counter_t,reset), NULL,  NULL },
   { "count-attribute", PW_TYPE_STRING_PTR, offsetof(rlm_counter_t,count_attribute), NULL, NULL },
-  { "return-attribute", PW_TYPE_STRING_PTR, offsetof(rlm_counter_t,return_attribute), NULL, NULL },
   { "counter-name", PW_TYPE_STRING_PTR, offsetof(rlm_counter_t,counter_name), NULL,  NULL },
   { "check-name", PW_TYPE_STRING_PTR, offsetof(rlm_counter_t,check_name), NULL, NULL },
+  { "reply-name", PW_TYPE_STRING_PTR, offsetof(rlm_counter_t,reply_name), NULL, NULL },
   { "allowed-servicetype", PW_TYPE_STRING_PTR, offsetof(rlm_counter_t,service_type),NULL, NULL },
   { "cache-size", PW_TYPE_INTEGER, offsetof(rlm_counter_t,cache_size), NULL, "1000" },
   { NULL, -1, 0, NULL, NULL }
@@ -151,12 +145,12 @@ static int counter_cmp(void *instance,
        /*
         *      Find the key attribute.
         */
-       key_vp = pairfind(request, data->key_attr);
+       key_vp = pairfind(request, data->key_attr, 0);
        if (key_vp == NULL) {
                return RLM_MODULE_NOOP;
        }
 
-       key_datum.dptr = key_vp->strvalue;
+       key_datum.dptr = key_vp->vp_strvalue;
        key_datum.dsize = key_vp->length;
 
        count_datum = gdbm_fetch(data->gdbm, key_datum);
@@ -167,7 +161,7 @@ static int counter_cmp(void *instance,
        memcpy(&counter, count_datum.dptr, sizeof(rad_counter));
        free(count_datum.dptr);
 
-       return counter.user_counter - check->lvalue;
+       return counter.user_counter - check->vp_integer;
 }
 
 
@@ -244,21 +238,21 @@ static int reset_db(rlm_counter_t *data)
 
 static int find_next_reset(rlm_counter_t *data, time_t timeval)
 {
-       int ret=0;
-       unsigned int num=1;
-       char last = 0;
+       int ret = 0;
+       size_t len;
+       unsigned int num = 1;
+       char last = '\0';
        struct tm *tm, s_tm;
        char sCurrentTime[40], sNextTime[40];
 
        tm = localtime_r(&timeval, &s_tm);
-       strftime(sCurrentTime, sizeof(sCurrentTime),"%Y-%m-%d %H:%M:%S",tm);
+       len = strftime(sCurrentTime, sizeof(sCurrentTime), "%Y-%m-%d %H:%M:%S", tm);
+       if (len == 0) *sCurrentTime = '\0';
        tm->tm_sec = tm->tm_min = 0;
 
        if (data->reset == NULL)
                return -1;
        if (isdigit((int) data->reset[0])){
-               unsigned int len=0;
-
                len = strlen(data->reset);
                if (len == 0)
                        return -1;
@@ -300,9 +294,11 @@ static int find_next_reset(rlm_counter_t *data, time_t timeval)
                        data->reset);
                return -1;
        }
-       strftime(sNextTime, sizeof(sNextTime),"%Y-%m-%d %H:%M:%S",tm);
-       DEBUG2("rlm_counter: Current Time: %d [%s], Next reset %d [%s]",
-               (int)timeval,sCurrentTime,(int)data->reset_time,sNextTime);
+
+       len = strftime(sNextTime, sizeof(sNextTime), "%Y-%m-%d %H:%M:%S", tm);
+       if (len == 0) *sNextTime = '\0';
+       DEBUG2("rlm_counter: Current Time: %li [%s], Next reset %li [%s]",
+               timeval, sCurrentTime, data->reset_time, sNextTime);
 
        return ret;
 }
@@ -387,25 +383,25 @@ static int counter_instantiate(CONF_SECTION *conf, void **instance)
        data->count_attr = dattr->attr;
 
        /*
-        * Discover the attribute number of the return attribute.
+        * Discover the attribute number of the reply attribute.
         */
-       if (data->return_attribute != NULL) {
-               dattr = dict_attrbyname(data->return_attribute);
+       if (data->reply_name != NULL) {
+               dattr = dict_attrbyname(data->reply_name);
                if (dattr == NULL) {
                        radlog(L_ERR, "rlm_counter: No such attribute %s",
-                                       data->return_attribute);
+                                       data->reply_name);
                        counter_detach(data);
                        return -1;
                }
                if (dattr->type != PW_TYPE_INTEGER) {
-                       radlog(L_ERR, "rlm_counter: Return attribute %s is not of type integer",
-                               data->return_attribute);
+                       radlog(L_ERR, "rlm_counter: Reply attribute %s is not of type integer",
+                               data->reply_name);
                        counter_detach(data);
                        return -1;
                }
-               data->return_attr = dattr->attr;
+               data->reply_attr = dattr->attr;
        }
-       
+
 
        /*
         *  Create a new attribute for the counter.
@@ -417,7 +413,7 @@ static int counter_instantiate(CONF_SECTION *conf, void **instance)
        }
 
        memset(&flags, 0, sizeof(flags));
-       dict_addattr(data->counter_name, 0, PW_TYPE_INTEGER, -1, flags);
+       dict_addattr(data->counter_name, -1, 0, PW_TYPE_INTEGER, flags);
        dattr = dict_attrbyname(data->counter_name);
        if (dattr == NULL) {
                radlog(L_ERR, "rlm_counter: Failed to create counter attribute %s",
@@ -451,7 +447,7 @@ static int counter_instantiate(CONF_SECTION *conf, void **instance)
         * Find the attribute for the allowed protocol
         */
        if (data->service_type != NULL) {
-               if ((dval = dict_valbyname(PW_SERVICE_TYPE, data->service_type)) == NULL) {
+               if ((dval = dict_valbyname(PW_SERVICE_TYPE, 0, data->service_type)) == NULL) {
                        radlog(L_ERR, "rlm_counter: Failed to find attribute number for %s",
                                        data->service_type);
                        counter_detach(data);
@@ -576,8 +572,8 @@ static int counter_accounting(void *instance, REQUEST *request)
        int acctstatustype = 0;
        time_t diff;
 
-       if ((key_vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE)) != NULL)
-               acctstatustype = key_vp->lvalue;
+       if ((key_vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE, 0)) != NULL)
+               acctstatustype = key_vp->vp_integer;
        else {
                DEBUG("rlm_counter: Could not find account status type in packet.");
                return RLM_MODULE_NOOP;
@@ -586,9 +582,9 @@ static int counter_accounting(void *instance, REQUEST *request)
                DEBUG("rlm_counter: We only run on Accounting-Stop packets.");
                return RLM_MODULE_NOOP;
        }
-       uniqueid_vp = pairfind(request->packet->vps, PW_ACCT_UNIQUE_SESSION_ID);
+       uniqueid_vp = pairfind(request->packet->vps, PW_ACCT_UNIQUE_SESSION_ID, 0);
        if (uniqueid_vp != NULL)
-               DEBUG("rlm_counter: Packet Unique ID = '%s'",uniqueid_vp->strvalue);
+               DEBUG("rlm_counter: Packet Unique ID = '%s'",uniqueid_vp->vp_strvalue);
 
        /*
         *      Before doing anything else, see if we have to reset
@@ -610,11 +606,11 @@ static int counter_accounting(void *instance, REQUEST *request)
         * Check if we need to watch out for a specific service-type. If yes then check it
         */
        if (data->service_type != NULL) {
-               if ((proto_vp = pairfind(request->packet->vps, PW_SERVICE_TYPE)) == NULL){
+               if ((proto_vp = pairfind(request->packet->vps, PW_SERVICE_TYPE, 0)) == NULL){
                        DEBUG("rlm_counter: Could not find Service-Type attribute in the request. Returning NOOP.");
                        return RLM_MODULE_NOOP;
                }
-               if ((unsigned)proto_vp->lvalue != data->service_val){
+               if ((unsigned)proto_vp->vp_integer != data->service_val){
                        DEBUG("rlm_counter: This Service-Type is not allowed. Returning NOOP.");
                        return RLM_MODULE_NOOP;
                }
@@ -623,10 +619,10 @@ static int counter_accounting(void *instance, REQUEST *request)
         * Check if request->timestamp - {Acct-Delay-Time} < last_reset
         * If yes reject the packet since it is very old
         */
-       key_vp = pairfind(request->packet->vps, PW_ACCT_DELAY_TIME);
+       key_vp = pairfind(request->packet->vps, PW_ACCT_DELAY_TIME, 0);
        if (key_vp != NULL){
-               if (key_vp->lvalue != 0 &&
-                   (request->timestamp - key_vp->lvalue) < data->last_reset){
+               if (key_vp->vp_integer != 0 &&
+                   (request->timestamp - key_vp->vp_integer) < data->last_reset){
                        DEBUG("rlm_counter: This packet is too old. Returning NOOP.");
                        return RLM_MODULE_NOOP;
                }
@@ -638,7 +634,7 @@ static int counter_accounting(void *instance, REQUEST *request)
         *      Look for the key.  User-Name is special.  It means
         *      The REAL username, after stripping.
         */
-       key_vp = (data->key_attr == PW_USER_NAME) ? request->username : pairfind(request->packet->vps, data->key_attr);
+       key_vp = (data->key_attr == PW_USER_NAME) ? request->username : pairfind(request->packet->vps, data->key_attr, 0);
        if (key_vp == NULL){
                DEBUG("rlm_counter: Could not find the key-attribute in the request. Returning NOOP.");
                return RLM_MODULE_NOOP;
@@ -647,16 +643,16 @@ static int counter_accounting(void *instance, REQUEST *request)
        /*
         *      Look for the attribute to use as a counter.
         */
-       count_vp = pairfind(request->packet->vps, data->count_attr);
+       count_vp = pairfind(request->packet->vps, data->count_attr, 0);
        if (count_vp == NULL){
                DEBUG("rlm_counter: Could not find the count-attribute in the request.");
                return RLM_MODULE_NOOP;
        }
 
-       key_datum.dptr = key_vp->strvalue;
+       key_datum.dptr = key_vp->vp_strvalue;
        key_datum.dsize = key_vp->length;
 
-       DEBUG("rlm_counter: Searching the database for key '%s'",key_vp->strvalue);
+       DEBUG("rlm_counter: Searching the database for key '%s'",key_vp->vp_strvalue);
        pthread_mutex_lock(&data->mutex);
        count_datum = gdbm_fetch(data->gdbm, key_datum);
        pthread_mutex_unlock(&data->mutex);
@@ -664,7 +660,8 @@ static int counter_accounting(void *instance, REQUEST *request)
                DEBUG("rlm_counter: Could not find the requested key in the database.");
                counter.user_counter = 0;
                if (uniqueid_vp != NULL)
-                       strncpy(counter.uniqueid,uniqueid_vp->strvalue,UNIQUEID_MAX_LEN - 1);
+                       strlcpy(counter.uniqueid,uniqueid_vp->vp_strvalue,
+                               sizeof(counter.uniqueid));
                else
                        memset((char *)counter.uniqueid,0,UNIQUEID_MAX_LEN);
        }
@@ -676,13 +673,14 @@ static int counter_accounting(void *instance, REQUEST *request)
                        DEBUG("rlm_counter: Counter Unique ID = '%s'",counter.uniqueid);
                if (uniqueid_vp != NULL){
                        if (counter.uniqueid != NULL &&
-                               strncmp(uniqueid_vp->strvalue,counter.uniqueid, UNIQUEID_MAX_LEN - 1) == 0){
+                               strncmp(uniqueid_vp->vp_strvalue,counter.uniqueid, UNIQUEID_MAX_LEN - 1) == 0){
                                DEBUG("rlm_counter: Unique IDs for user match. Droping the request.");
                                return RLM_MODULE_NOOP;
                        }
-                       strncpy(counter.uniqueid,uniqueid_vp->strvalue,UNIQUEID_MAX_LEN - 1);
+                       strlcpy(counter.uniqueid,uniqueid_vp->vp_strvalue,
+                               sizeof(counter.uniqueid));
                }
-               DEBUG("rlm_counter: User=%s, Counter=%d.",request->username->strvalue,counter.user_counter);
+               DEBUG("rlm_counter: User=%s, Counter=%d.",request->username->vp_strvalue,counter.user_counter);
        }
 
        if (data->count_attr == PW_ACCT_SESSION_TIME) {
@@ -697,14 +695,14 @@ static int counter_accounting(void *instance, REQUEST *request)
                 *      day). That is the right thing
                 */
                diff = request->timestamp - data->last_reset;
-               counter.user_counter += (count_vp->lvalue < diff) ? count_vp->lvalue : diff;
+               counter.user_counter += (count_vp->vp_integer < diff) ? count_vp->vp_integer : diff;
 
        } else if (count_vp->type == PW_TYPE_INTEGER) {
                /*
                 *      Integers get counted, without worrying about
                 *      reset dates.
                 */
-               counter.user_counter += count_vp->lvalue;
+               counter.user_counter += count_vp->vp_integer;
 
        } else {
                /*
@@ -714,7 +712,7 @@ static int counter_accounting(void *instance, REQUEST *request)
                counter.user_counter++;
        }
 
-       DEBUG("rlm_counter: User=%s, New Counter=%d.",request->username->strvalue,counter.user_counter);
+       DEBUG("rlm_counter: User=%s, New Counter=%d.",request->username->vp_strvalue,counter.user_counter);
        count_datum.dptr = (char *) &counter;
        count_datum.dsize = sizeof(rad_counter);
 
@@ -776,7 +774,7 @@ static int counter_authorize(void *instance, REQUEST *request)
         *      The REAL username, after stripping.
         */
        DEBUG2("rlm_counter: Entering module authorize code");
-       key_vp = (data->key_attr == PW_USER_NAME) ? request->username : pairfind(request->packet->vps, data->key_attr);
+       key_vp = (data->key_attr == PW_USER_NAME) ? request->username : pairfind(request->packet->vps, data->key_attr, 0);
        if (key_vp == NULL) {
                DEBUG2("rlm_counter: Could not find Key value pair");
                return ret;
@@ -785,12 +783,12 @@ static int counter_authorize(void *instance, REQUEST *request)
        /*
         *      Look for the check item
         */
-       if ((check_vp= pairfind(request->config_items, data->check_attr)) == NULL) {
+       if ((check_vp= pairfind(request->config_items, data->check_attr, 0)) == NULL) {
                DEBUG2("rlm_counter: Could not find Check item value pair");
                return ret;
        }
 
-       key_datum.dptr = key_vp->strvalue;
+       key_datum.dptr = key_vp->vp_strvalue;
        key_datum.dsize = key_vp->length;
 
 
@@ -800,7 +798,7 @@ static int counter_authorize(void *instance, REQUEST *request)
 
        counter.user_counter = 0;
 
-       DEBUG("rlm_counter: Searching the database for key '%s'",key_vp->strvalue);
+       DEBUG("rlm_counter: Searching the database for key '%s'",key_vp->vp_strvalue);
        pthread_mutex_lock(&data->mutex);
        count_datum = gdbm_fetch(data->gdbm, key_datum);
        pthread_mutex_unlock(&data->mutex);
@@ -815,8 +813,8 @@ static int counter_authorize(void *instance, REQUEST *request)
        /*
         * Check if check item > counter
         */
-       DEBUG("rlm_counter: Check item = %d, Count = %d",check_vp->lvalue,counter.user_counter);
-       res=check_vp->lvalue - counter.user_counter;
+       DEBUG("rlm_counter: Check item = %d, Count = %d",check_vp->vp_integer,counter.user_counter);
+       res=check_vp->vp_integer - counter.user_counter;
        if (res > 0) {
                DEBUG("rlm_counter: res is greater than zero");
                if (data->count_attr == PW_ACCT_SESSION_TIME) {
@@ -847,33 +845,25 @@ static int counter_authorize(void *instance, REQUEST *request)
                        if (data->reset_time && (
                                res >= (data->reset_time - request->timestamp))) {
                                res = data->reset_time - request->timestamp;
-                               res += check_vp->lvalue;
+                               res += check_vp->vp_integer;
                        }
 
-                       if ((reply_item = pairfind(request->reply->vps, PW_SESSION_TIMEOUT)) != NULL) {
-                               if (reply_item->lvalue > res)
-                                       reply_item->lvalue = res;
+                       if ((reply_item = pairfind(request->reply->vps, PW_SESSION_TIMEOUT, 0)) != NULL) {
+                               if (reply_item->vp_integer > res)
+                                       reply_item->vp_integer = res;
                        } else {
-                               if ((reply_item = paircreate(PW_SESSION_TIMEOUT, PW_TYPE_INTEGER)) == NULL) {
-                                       radlog(L_ERR|L_CONS, "no memory");
-                                       return RLM_MODULE_NOOP;
-                               }
-                               reply_item->lvalue = res;
-                               pairadd(&request->reply->vps, reply_item);
+                               reply_item = radius_paircreate(request, &request->reply->vps, PW_SESSION_TIMEOUT, 0, PW_TYPE_INTEGER);
+                               reply_item->vp_integer = res;
                        }
                }
-               else if (data->return_attr) {
-                       if ((reply_item = pairfind(request->reply->vps, data->return_attr)) != NULL) {
-                               if (reply_item->lvalue > res)
-                                       reply_item->lvalue = res;
+               else if (data->reply_attr) {
+                       if ((reply_item = pairfind(request->reply->vps, data->reply_attr, 0)) != NULL) {
+                               if (reply_item->vp_integer > res)
+                                       reply_item->vp_integer = res;
                        }
                        else {
-                               if ((reply_item = paircreate(data->return_attr, PW_TYPE_INTEGER)) == NULL) {
-                                       radlog(L_ERR|L_CONS, "no memory");
-                                       return RLM_MODULE_NOOP;
-                               }
-                               reply_item->lvalue = res;
-                               pairadd(&request->reply->vps, reply_item);
+                               reply_item = radius_paircreate(request, &request->reply->vps, data->reply_attr, 0, PW_TYPE_INTEGER);
+                               reply_item->vp_integer = res;
                        }
                }
 
@@ -881,9 +871,9 @@ static int counter_authorize(void *instance, REQUEST *request)
 
                DEBUG2("rlm_counter: (Check item - counter) is greater than zero");
                DEBUG2("rlm_counter: Authorized user %s, check_item=%d, counter=%d",
-                               key_vp->strvalue,check_vp->lvalue,counter.user_counter);
+                               key_vp->vp_strvalue,check_vp->vp_integer,counter.user_counter);
                DEBUG2("rlm_counter: Sent Reply-Item for user %s, Type=Session-Timeout, value=%d",
-                               key_vp->strvalue,res);
+                               key_vp->vp_strvalue,res);
        }
        else{
                char module_fmsg[MAX_STRING_LEN];
@@ -903,7 +893,7 @@ static int counter_authorize(void *instance, REQUEST *request)
                ret=RLM_MODULE_REJECT;
 
                DEBUG2("rlm_counter: Rejected user %s, check_item=%d, counter=%d",
-                               key_vp->strvalue,check_vp->lvalue,counter.user_counter);
+                               key_vp->vp_strvalue,check_vp->vp_integer,counter.user_counter);
        }
 
        return ret;
@@ -916,13 +906,6 @@ static int counter_detach(void *instance)
        paircompare_unregister(data->dict_attr, counter_cmp);
        if (data->gdbm)
                gdbm_close(data->gdbm);
-       free(data->filename);
-       free(data->reset);
-       free(data->key_name);
-       free(data->count_attribute);
-       free(data->counter_name);
-       free(data->check_name);
-       free(data->service_type);
        pthread_mutex_destroy(&data->mutex);
 
        free(instance);
@@ -939,10 +922,11 @@ static int counter_detach(void *instance)
  *     is single-threaded.
  */
 module_t rlm_counter = {
-       "Counter",
+        RLM_MODULE_INIT,
+       "counter",
        RLM_TYPE_THREAD_SAFE,           /* type */
-       NULL,                           /* initialization */
        counter_instantiate,            /* instantiation */
+       counter_detach,                 /* detach */
        {
                NULL,                   /* authentication */
                counter_authorize,      /* authorization */
@@ -953,6 +937,4 @@ module_t rlm_counter = {
                NULL,                   /* post-proxy */
                NULL                    /* post-auth */
        },
-       counter_detach,                 /* detach */
-       NULL,                           /* destroy */
 };