Massively cleaned up #include's, so they're in a consistent
[freeradius.git] / src / modules / rlm_sqlippool / rlm_sqlippool.c
index b7f80de..39b5a58 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  rlm_sqlippool.c     rlm_sqlippool - FreeRADIUS SQL IP Pool Module
  *
- * Version:     $Id$
+ * 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
  * Copyright 2006  Suntel Communications
  */
 
-#include "autoconf.h"
-#include "libradius.h"
+#include <freeradius-devel/ident.h>
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
 #include <ctype.h>
-#include <netinet/in.h>
 
-#include "radiusd.h"
-#include "modules.h"
-#include "conffile.h"
-#include "modpriv.h"
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/modpriv.h>
 
 #include <rlm_sql.h>
 
-static const char rcsid[] = "$Id$";
-
 /*
  *     Define a structure for our module configuration.
  */
@@ -52,14 +46,11 @@ typedef struct rlm_sqlippool_t {
 
        char *pool_name;
 
-                               /* Initialization sequence */
-       char *init_begin;       /* SQL query to begin */
-       char *init_query;       /* SQL query to select records */
-       char *init_delete;      /* SQL query to delete records */
-       char *init_insert;      /* SQL query to insert records */
-       char *init_commit;      /* SQL query to commit */
-       char *init_rollback;    /* SQL query to rollback */
-
+       /* We ended up removing the init 
+          queries so that its up to user
+          to create the db structure and put the required
+          information in there                 
+       */
                                /* Allocation sequence */
        char *allocate_begin;   /* SQL query to begin */
        char *allocate_clear;   /* SQL query to clear an IP */
@@ -68,6 +59,8 @@ typedef struct rlm_sqlippool_t {
        char *allocate_commit;  /* SQL query to commit */
        char *allocate_rollback; /* SQL query to rollback */
 
+       char *pool_check;       /* Query to check for the existence of the pool */
+
                                /* Start sequence */
        char *start_begin;      /* SQL query to begin */
        char *start_update;     /* SQL query to update an IP entry */
@@ -97,6 +90,17 @@ typedef struct rlm_sqlippool_t {
        char *off_clear;        /* SQL query to clear an entire NAS */
        char *off_commit;       /* SQL query to commit */
        char *off_rollback;     /* SQL query to rollback */
+       
+                               /* Logging Section */
+       char *log_exists;       /* There was an ip address already assigned */
+       char *log_success;      /* We successfully allocated ip address from pool */
+       char *log_clear;        /* We successfully deallocated ip address from pool */
+       char *log_failed;       /* Failed to allocate ip from the pool */
+       char *log_nopool;       /* There was no Framed-IP-Address but also no Pool-Name */
+
+                               /* Reserved to handle 255.255.255.254 Requests */
+       char *defaultpool;      /* Default Pool-Name if there is non in the check items */
+
 } rlm_sqlippool_t;
 
 /*
@@ -113,38 +117,50 @@ static CONF_PARSER module_config[] = {
 
   { "lease-duration", PW_TYPE_INTEGER, offsetof(rlm_sqlippool_t,lease_duration), NULL, "86400"},
 
-  { "allocate-begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,allocate_begin), NULL, "BEGIN" },
+  { "pool-name"            , PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t, pool_name), NULL, ""},
+
+  { "allocate-begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,allocate_begin), NULL, "START TRANSACTION" },
   { "allocate-clear", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,allocate_clear), NULL, "" },
   { "allocate-find", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,allocate_find), NULL, "" },
   { "allocate-update", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,allocate_update), NULL, "" },
   { "allocate-commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,allocate_commit), NULL, "COMMIT" },
   { "allocate-rollback", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,allocate_rollback), NULL, "ROLLBACK" },
 
-  { "start-begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,start_begin), NULL, "BEGIN" },
+  { "pool-check", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,pool_check), NULL, "" },
+
+  { "start-begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,start_begin), NULL, "START TRANSACTION" },
   { "start-update", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,start_update), NULL, "" },
   { "start-commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,start_commit), NULL, "COMMIT" },
   { "start-rollback", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,start_rollback), NULL, "ROLLBACK" },
 
-  { "alive-begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,alive_begin), NULL, "BEGIN" },
+  { "alive-begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,alive_begin), NULL, "START TRANSACTION" },
   { "alive-update", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,alive_update), NULL, "" },
   { "alive-commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,alive_commit), NULL, "COMMIT" },
   { "alive-rollback", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,alive_rollback), NULL, "ROLLBACK" },
 
-  { "stop-begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,stop_begin), NULL, "BEGIN" },
+  { "stop-begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,stop_begin), NULL, "START TRANSACTION" },
   { "stop-clear", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,stop_clear), NULL, "" },
   { "stop-commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,stop_commit), NULL, "COMMIT" },
   { "stop-rollback", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,stop_rollback), NULL, "ROLLBACK" },
 
-  { "on-begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,on_begin), NULL, "BEGIN" },
+  { "on-begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,on_begin), NULL, "START TRANSACTION" },
   { "on-clear", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,on_clear), NULL, "" },
   { "on-commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,on_commit), NULL, "COMMIT" },
   { "on-rollback", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,on_rollback), NULL, "ROLLBACK" },
 
-  { "off-begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,off_begin), NULL, "BEGIN" },
+  { "off-begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,off_begin), NULL, "START TRANSACTION" },
   { "off-clear", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,off_clear), NULL, "" },
   { "off-commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,off_commit), NULL, "COMMIT" },
   { "off-rollback", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,off_rollback), NULL, "ROLLBACK" },
 
+  { "sqlippool_log_exists", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t, log_exists), NULL, "" },
+  { "sqlippool_log_success", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t, log_success), NULL, "" },
+  { "sqlippool_log_clear", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t, log_clear), NULL, "" },
+  { "sqlippool_log_failed", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t, log_failed), NULL, "" },
+  { "sqlippool_log_nopool", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t, log_nopool), NULL, "" },
+
+  { "defaultpool", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t, defaultpool), NULL, "main_pool" },
+
   { NULL, -1, 0, NULL, NULL }
 };
 
@@ -216,13 +232,13 @@ static int sqlippool_expand(char * out, int outlen, const char * fmt, void * ins
                                *q++ = *p;
                                break;
                        case 'P': /* pool name */
-                               strNcpy(q, data->pool_name, freespace); 
+                               strlcpy(q, data->pool_name, freespace); 
                                q += strlen(q);
                                break;
                        case 'I': /* IP address */
                                if (param && param_len > 0) {
                                        if (param_len > freespace) {
-                                               strNcpy(q, param, freespace);
+                                               strlcpy(q, param, freespace);
                                                q += strlen(q);
                                        }
                                        else {
@@ -233,7 +249,7 @@ static int sqlippool_expand(char * out, int outlen, const char * fmt, void * ins
                                break;
                        case 'J': /* lease duration */
                                sprintf(tmp, "%d", data->lease_duration);
-                               strNcpy(q, tmp, freespace); 
+                               strlcpy(q, tmp, freespace); 
                                q += strlen(q);
                                break;
                        default:
@@ -268,7 +284,7 @@ static int sqlippool_command(const char * fmt, SQLSOCK * sqlsocket, void * insta
         */
        if (request) {
                if (!radius_xlat(query, sizeof(query), expansion, request, NULL)) {
-                       radlog(L_ERR, "sqlippool_command: xlat failed.");
+                       radlog(L_ERR, "sqlippool_command: xlat failed on: '%s'", query);
                        return 0;
                }
        }
@@ -279,14 +295,12 @@ static int sqlippool_command(const char * fmt, SQLSOCK * sqlsocket, void * insta
 #if 0
        DEBUG2("sqlippool_command: '%s'", query);
 #endif
-
        if (rlm_sql_query(sqlsocket, data->sql_inst, query)){
-               radlog(L_ERR, "sqlippool_command: database query error");
+               radlog(L_ERR, "sqlippool_command: database query error in: '%s'", query);
                return 0;
        }
 
        (data->sql_inst->module->sql_finish_query)(sqlsocket, data->sql_inst->config);
-
        return 0;
 }
 
@@ -299,7 +313,7 @@ static int sqlippool_query1(char * out, int outlen, const char * fmt, SQLSOCK *
        char expansion[MAX_STRING_LEN * 4];
        char query[MAX_STRING_LEN * 4];
        SQL_ROW row;
-       int r;
+       int rlen, retval = 0;
 
        sqlippool_expand(expansion, sizeof(expansion), fmt, instance, param, param_len);
 
@@ -320,46 +334,27 @@ static int sqlippool_query1(char * out, int outlen, const char * fmt, SQLSOCK *
 #if 0
        DEBUG2("sqlippool_query1: '%s'", query);
 #endif
-
        if (rlm_sql_select_query(sqlsocket, data->sql_inst, query)){
                radlog(L_ERR, "sqlippool_query1: database query error");
                out[0] = '\0';
                return 0;
        }
 
-       r = rlm_sql_fetch_row(sqlsocket, data->sql_inst);
-       (data->sql_inst->module->sql_finish_select_query)(sqlsocket, data->sql_inst->config);
-
-       if (r) {
-               DEBUG("sqlippool_query1: SQL query did not succeed");
-               out[0] = '\0';
-               return 0;
-       }
-
-       row = sqlsocket->row;
-       if (row == NULL) {
-               DEBUG("sqlippool_query1: SQL query did not return any results");
-               out[0] = '\0';
-               return 0;
-       }
-
-       if (row[0] == NULL){
-               DEBUG("sqlippool_query1: row[0] returned NULL");
-               out[0] = '\0';
-               return 0;
-       }
-
-       r = strlen(row[0]);
-       if (r >= outlen){
-               DEBUG("sqlippool_query1: insufficient string space");
-               out[0] = '\0';
-               return 0;
-       }
+       out[0] = '\0';
 
-       strncpy(out, row[0], r);
-       out[r] = '\0';
+       if (!rlm_sql_fetch_row(sqlsocket, data->sql_inst)) {
+               if (sqlsocket->row) {
+                       if (sqlsocket->row[0]) {
+                               if ((rlen = strlen(sqlsocket->row[0])) < outlen) {
+                                       strcpy(out, sqlsocket->row[0]);
+                                       retval = rlen;
+                               } else DEBUG("sqlippool_query1: insufficient string space");
+                       } else DEBUG("sqlippool_query1: row[0] returned NULL");
+               } else DEBUG("sqlippool_query1: SQL query did not return any results");
+       } else DEBUG("sqlippool_query1: SQL query did not succeed");
 
-       return r;
+       (data->sql_inst->module->sql_finish_select_query)(sqlsocket, data->sql_inst->config);
+       return retval;
 }
 
 static int sqlippool_initialize_sql(void * instance)
@@ -472,7 +467,7 @@ static int sqlippool_instantiate(CONF_SECTION * conf, void ** instance)
        else
                data->pool_name = strdup("ippool");
 
-       if ( !(data->sql_inst = (SQL_INST *) (find_module_instance(data->sql_instance_name))->insthandle) )
+       if ( !(data->sql_inst = (SQL_INST *) (find_module_instance(cf_section_find("modules"), data->sql_instance_name))->insthandle) )
        {
                radlog(L_ERR, "sqlippool_instantiate: failed to find sql instance named %s", data->sql_instance_name);
                free(data);
@@ -480,11 +475,23 @@ static int sqlippool_instantiate(CONF_SECTION * conf, void ** instance)
        }
 
        sqlippool_initialize_sql(data);
-
        *instance = data;
        return 0;
 }
 
+
+/*
+ * if we have something to log, then we log it
+ * otherwise we return the retcode as soon as possible 
+ */
+static int do_logging(char *str, int retcode)
+{
+       if (strlen(str))
+               radlog(L_INFO,"%s", str);       
+       return retcode;
+}
+
+
 /*
  *     Allocate an IP number from the pool.
  */
@@ -496,21 +503,32 @@ static int sqlippool_postauth(void *instance, REQUEST * request)
        uint32_t ip_allocation;
        VALUE_PAIR * vp;
        SQLSOCK * sqlsocket;
+       lrad_ipaddr_t ipaddr;
+
+       VALUE_PAIR *callingsid;
+       VALUE_PAIR *pair;
+
+       int do_callingsid = 0;
+       int do_calledsid = 0;
+
+       char    logstr[MAX_STRING_LEN];
 
        /*
         * If there is a Framed-IP-Address attribute in the reply do nothing
         */
        if (pairfind(request->reply->vps, PW_FRAMED_IP_ADDRESS) != NULL) {
+               /* We already have a Framed-IP-Address */
+               radius_xlat(logstr, sizeof(logstr), data->log_exists, request, NULL);
                DEBUG("rlm_sqlippool: Framed-IP-Address already exists");
-               return RLM_MODULE_NOOP;
-       }
 
-       if ((vp = pairfind(request->config_items, PW_POOL_NAME)) != NULL) {
-               strcpy(data->pool_name, vp->strvalue);
+               return do_logging(logstr, RLM_MODULE_NOOP);
        }
-       else {
-               DEBUG("rlm_sqlippool: missing pool_name");
-               return RLM_MODULE_NOOP;
+
+       if (pairfind(request->config_items, PW_POOL_NAME) == NULL) {
+               DEBUG("rlm_sqlippool: We Dont have Pool-Name in check items.. Lets do nothing..");
+               radius_xlat(logstr, sizeof(logstr), data->log_nopool, request, NULL);
+
+               return do_logging(logstr, RLM_MODULE_NOOP);
        }
        
        if (pairfind(request->packet->vps, PW_NAS_IP_ADDRESS) == NULL) {
@@ -526,7 +544,7 @@ static int sqlippool_postauth(void *instance, REQUEST * request)
        sqlsocket = sql_get_socket(data->sql_inst);
        if (sqlsocket == NULL) {
                DEBUG("rlm_sqlippool: cannot allocate sql connection");
-               return RLM_MODULE_NOOP;
+               return RLM_MODULE_FAIL;
        }
 
        /*
@@ -547,7 +565,6 @@ static int sqlippool_postauth(void *instance, REQUEST * request)
        allocation_len = sqlippool_query1(allocation, sizeof(allocation),
                                          data->allocate_find, sqlsocket, instance, request,
                                          (char *) NULL, 0);
-       DEBUG("rlm_sqlippool: ip=[%s] len=%d", allocation, allocation_len);
 
        if (allocation_len == 0)
        {       
@@ -557,24 +574,58 @@ static int sqlippool_postauth(void *instance, REQUEST * request)
                sqlippool_command(data->allocate_commit, sqlsocket, instance, request,
                                  (char *) NULL, 0);
 
-               DEBUG("rlm_sqlippool: IP number could not be allocated.");
+               /*
+                * Should we perform pool-check ?
+                */ 
+               if (data->pool_check && *data->pool_check) {
+
+                       /*
+                        * Ok, so the allocate-find query found nothing ...
+                        * Let's check if the pool exists at all
+                        */
+                       allocation_len = sqlippool_query1(allocation, sizeof(allocation),
+                                                data->pool_check, sqlsocket, instance, request,
+                                               (char *) NULL, 0);
+
+                       sql_release_socket(data->sql_inst, sqlsocket);
+
+                       if (allocation_len) {
+
+                               /*
+                                * Pool exists after all... So, the failure to allocate
+                                * the IP address was most likely due to the depletion 
+                                * of the pool. In that case, we should return NOTFOUND
+                                */
+                               DEBUG("rlm_sqlippool: IP address could not be allocated.");
+                               radius_xlat(logstr, sizeof(logstr), data->log_failed, request, NULL);
+                               return do_logging(logstr, RLM_MODULE_NOTFOUND);
+
+                       }
+                       /*
+                        * Pool doesn't exist in the table. It may be handled by some 
+                        * other instance of sqlippool, so we should just ignore
+                        * this allocation failure and return NOOP
+                        */
+                       DEBUG("rlm_sqlippool: IP address could not be allocated as not pool exists with that name.");
+                       return RLM_MODULE_NOOP;
+               
+               }
+               
                sql_release_socket(data->sql_inst, sqlsocket);
-               return RLM_MODULE_NOOP;
-       }
 
-       ip_allocation = ip_addr(allocation);
-       if (ip_allocation == INADDR_NONE)
-       {
-               /*
-                * Invalid IP number - run INIT-DELETE and complain
-                */
+               DEBUG("rlm_sqlippool: IP address could not be allocated.");
+               radius_xlat(logstr, sizeof(logstr), data->log_failed, request, NULL);
 
-               /*
-                * INIT_DELETE
-                */
-               sqlippool_command(data->init_delete, sqlsocket, instance, NULL,
-                                 allocation, allocation_len);
+               return do_logging(logstr, RLM_MODULE_NOOP);
+       }
 
+       
+       /*
+        *  FIXME: Make it work with the ipv6 addresses
+        */
+       if ((ip_hton(allocation, AF_INET, &ipaddr) < 0) ||
+           ((ip_allocation = ipaddr.ipaddr.ip4addr.s_addr) == INADDR_NONE))
+       {
                /*
                 * COMMIT
                 */
@@ -583,7 +634,9 @@ static int sqlippool_postauth(void *instance, REQUEST * request)
 
                DEBUG("rlm_sqlippool: Invalid IP number [%s] returned from database query.", allocation);
                sql_release_socket(data->sql_inst, sqlsocket);
-               return RLM_MODULE_NOOP;
+               radius_xlat(logstr, sizeof(logstr), data->log_failed, request, NULL);   
+               
+               return do_logging(logstr, RLM_MODULE_NOOP);
        }
 
        /*
@@ -609,7 +662,9 @@ static int sqlippool_postauth(void *instance, REQUEST * request)
                          (char *) NULL, 0);
 
        sql_release_socket(data->sql_inst, sqlsocket);
-       return RLM_MODULE_OK;
+       radius_xlat(logstr, sizeof(logstr), data->log_success, request, NULL);
+
+       return do_logging(logstr, RLM_MODULE_OK);
 }
 
 static int sqlippool_accounting_start(void * instance, REQUEST * request)
@@ -702,6 +757,8 @@ static int sqlippool_accounting_alive(void * instance, REQUEST * request)
 
 static int sqlippool_accounting_stop(void * instance, REQUEST * request)
 {
+       char    logstr[MAX_STRING_LEN];
+
        rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
        SQLSOCK * sqlsocket;
 
@@ -740,8 +797,9 @@ static int sqlippool_accounting_stop(void * instance, REQUEST * request)
                          (char *) NULL, 0);
 
        sql_release_socket(data->sql_inst, sqlsocket);
+       radius_xlat(logstr, sizeof(logstr), data->log_clear, request, NULL);
 
-       return RLM_MODULE_OK;
+       return do_logging(logstr, RLM_MODULE_OK);
 }
 
 static int sqlippool_accounting_on(void * instance, REQUEST * request)
@@ -864,48 +922,6 @@ static int sqlippool_detach(void *instance)
 {
        rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
 
-       free(data->sql_instance_name);
-       free(data->pool_name);
-
-       free(data->init_begin);
-       free(data->init_query);
-       free(data->init_delete);
-       free(data->init_insert);
-       free(data->init_commit);
-       free(data->init_rollback);
-
-       free(data->allocate_begin);
-       free(data->allocate_clear);
-       free(data->allocate_find);
-       free(data->allocate_update);
-       free(data->allocate_commit);
-       free(data->allocate_rollback);
-
-       free(data->start_begin);
-       free(data->start_update);
-       free(data->start_commit);
-       free(data->start_rollback);
-
-       free(data->alive_begin);
-       free(data->alive_update);
-       free(data->alive_commit);
-       free(data->alive_rollback);
-
-       free(data->stop_begin);
-       free(data->stop_clear);
-       free(data->stop_commit);
-       free(data->stop_rollback);
-
-       free(data->on_begin);
-       free(data->on_clear);
-       free(data->on_commit);
-       free(data->on_rollback);
-
-       free(data->off_begin);
-       free(data->off_clear);
-       free(data->off_commit);
-       free(data->off_rollback);
-
        return 0;
 }
 
@@ -919,10 +935,11 @@ static int sqlippool_detach(void *instance)
  *     is single-threaded.
  */
 module_t rlm_sqlippool = {
+       RLM_MODULE_INIT,
        "SQL IP Pool",  
        RLM_TYPE_THREAD_SAFE,           /* type */
-       NULL,                           /* initialization */
        sqlippool_instantiate,          /* instantiation */
+       sqlippool_detach,               /* detach */
        {
                NULL,                   /* authentication */
                NULL,                   /* authorization */
@@ -933,6 +950,4 @@ module_t rlm_sqlippool = {
                NULL,                   /* post-proxy */
                sqlippool_postauth      /* post-auth */
        },
-       sqlippool_detach,               /* detach */
-       NULL,                           /* destroy */
 };