/*
* rlm_sqlippool.c rlm_sqlippool - FreeRADIUS SQL IP Pool Module
*
* Version: $Id: rlm_sqlippool.c,v 1.3.2.6 2007/07/17 18:46:32 pnixon Exp $
*
* 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 2002 Globe.Net Communications Limited
* Copyright 2006 The FreeRADIUS server project
* Copyright 2006 Suntel Communications
*/
#include "autoconf.h"
#include "libradius.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 <rlm_sql.h>
static const char rcsid[] = "$Id: rlm_sqlippool.c,v 1.3.2.6 2007/07/17 18:46:32 pnixon Exp $";
/*
* Define a structure for our module configuration.
*/
typedef struct rlm_sqlippool_t {
char *sql_instance_name;
int lease_duration;
SQL_INST *sql_inst;
char *pool_name;
/* 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 */
char *allocate_find; /* SQL query to find an unused IP */
char *allocate_update; /* SQL query to mark an IP as used */
char *allocate_commit; /* SQL query to commit */
char *allocate_rollback; /* SQL query to rollback */
/* Start sequence */
char *start_begin; /* SQL query to begin */
char *start_update; /* SQL query to update an IP entry */
char *start_commit; /* SQL query to commit */
char *start_rollback; /* SQL query to rollback */
/* Alive sequence */
char *alive_begin; /* SQL query to begin */
char *alive_update; /* SQL query to update an IP entry */
char *alive_commit; /* SQL query to commit */
char *alive_rollback; /* SQL query to rollback */
/* Stop sequence */
char *stop_begin; /* SQL query to begin */
char *stop_clear; /* SQL query to clear an IP */
char *stop_commit; /* SQL query to commit */
char *stop_rollback; /* SQL query to rollback */
/* On sequence */
char *on_begin; /* SQL query to begin */
char *on_clear; /* SQL query to clear an entire NAS */
char *on_commit; /* SQL query to commit */
char *on_rollback; /* SQL query to rollback */
/* Off sequence */
char *off_begin; /* SQL query to begin */
char *off_clear; /* SQL query to clear an entire NAS */
char *off_commit; /* SQL query to commit */
char *off_rollback; /* SQL query to rollback */
#ifdef HAVE_PTHREAD_H
pthread_mutex_t dlock;
long owner;
#endif
} rlm_sqlippool_t;
#ifndef HAVE_PTHREAD_H
/*
* This is easier than ifdef's throughout the code.
*/
#define pthread_mutex_init(_x, _y)
#define pthread_mutex_destroy(_x)
#define pthread_mutex_lock(_x)
#define pthread_mutex_unlock(_x)
#endif
/*
* 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[] = {
{"sql-instance-name",PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,sql_instance_name), NULL, "sql"},
{ "lease-duration", PW_TYPE_INTEGER, offsetof(rlm_sqlippool_t,lease_duration), NULL, "86400"},
{ "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, "BEGIN" },
{ "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" },
{ "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-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-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-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-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" },
{ NULL, -1, 0, NULL, NULL }
};
/*
* Replace %<whatever> in a string.
*
* %P pool_name
* %I param
* %J lease_duration
*
*/
static int sqlippool_expand(char * out, int outlen, const char * fmt, void * instance, char * param, int param_len)
{
rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
char *q;
const char *p;
char tmp[40]; /* For temporary storing of integers */
int openbraces;
openbraces = 0;
q = out;
for (p = fmt; *p ; p++) {
int freespace;
int c;
/* Calculate freespace in output */
freespace = outlen - (q - out);
if (freespace <= 1)
break;
c = *p;
if (c != '%' && c != '$' && c != '\\') {
/*
* We check if we're inside an open brace. If we are
* then we assume this brace is NOT literal, but is
* a closing brace and apply it
*/
if((c == '}') && openbraces) {
openbraces--;
continue;
}
*q++ = *p;
continue;
}
if (*++p == '\0')
break;
if (c == '\\') {
switch(*p) {
case '\\':
*q++ = '\\';
break;
case 't':
*q++ = '\t';
break;
case 'n':
*q++ = '\n';
break;
default:
*q++ = c;
*q++ = *p;
break;
}
}
else if (c == '%') {
switch(*p) {
case '%':
*q++ = *p;
break;
case 'P': /* pool name */
strNcpy(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);
q += strlen(q);
}
else {
memcpy(q, param, param_len);
q += param_len;
}
}
break;
case 'J': /* lease duration */
sprintf(tmp, "%d", data->lease_duration);
strNcpy(q, tmp, freespace);
q += strlen(q);
break;
default:
*q++ = '%';
*q++ = *p;
break;
}
}
}
*q = '\0';
#if 0
DEBUG2("sqlippool_expand: '%s'", out);
#endif
return strlen(out);
}
/*
* Query the database executing a command with no result rows
*/
static int sqlippool_command(const char * fmt, SQLSOCK * sqlsocket, void * instance, REQUEST * request, char * param, int param_len)
{
rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
char expansion[MAX_STRING_LEN * 4];
char query[MAX_STRING_LEN * 4];
sqlippool_expand(expansion, sizeof(expansion), fmt, instance, param, param_len);
/*
* Do an xlat on the provided string
*/
if (request) {
char sqlusername[MAX_STRING_LEN];
if(sql_set_user(data->sql_inst, request, sqlusername, NULL) < 0) {
return RLM_MODULE_FAIL;
}
if (!radius_xlat(query, sizeof(query), expansion, request, NULL)) {
radlog(L_ERR, "sqlippool_command: xlat failed.");
return 0;
}
}
else {
strcpy(query, expansion);
}
#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");
return 0;
}
(data->sql_inst->module->sql_finish_query)(sqlsocket, data->sql_inst->config);
return 0;
}
/*
* Query the database expecting a single result row
*/
static int sqlippool_query1(char * out, int outlen, const char * fmt, SQLSOCK * sqlsocket, void * instance, REQUEST * request, char * param, int param_len)
{
rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
char expansion[MAX_STRING_LEN * 4];
char query[MAX_STRING_LEN * 4];
SQL_ROW row;
int r;
sqlippool_expand(expansion, sizeof(expansion), fmt, instance, param, param_len);
/*
* Do an xlat on the provided string
*/
if (request) {
char sqlusername[MAX_STRING_LEN];
if(sql_set_user(data->sql_inst, request, sqlusername, NULL) < 0) {
return RLM_MODULE_FAIL;
}
if (!radius_xlat(query, sizeof(query), expansion, request, NULL)) {
radlog(L_ERR, "sqlippool_command: xlat failed.");
out[0] = '\0';
return 0;
}
}
else {
strcpy(query, expansion);
}
#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;
}
strncpy(out, row[0], r);
out[r] = '\0';
return r;
}
static int sqlippool_initialize_sql(void * instance)
{
rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
SQLSOCK * sqlsocket;
sqlsocket = sql_get_socket(data->sql_inst);
if (sqlsocket == NULL) {
DEBUG("rlm_sqlippool: cannot allocate sql connection for initialization sequence");
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 sqlippool_instantiate(CONF_SECTION * conf, void ** instance)
{
rlm_sqlippool_t * data;
char * pool_name = NULL;
/*
* Set up a storage area for instance data
*/
data = rad_malloc(sizeof(*data));
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);
return -1;
}
if (data->sql_instance_name == NULL || strlen(data->sql_instance_name) == 0) {
radlog(L_ERR, "rlm_sqlippool: the 'sql-instance-name' variable must be set.");
free(data);
exit(0);
}
/*
* Check that all the queries are in place
*/
if (data->allocate_clear == NULL || strlen(data->allocate_clear) == 0) {
radlog(L_ERR, "rlm_sqlippool: the 'allocate-clear' statement must be set.");
free(data);
exit(0);
}
if (data->allocate_find == NULL || strlen(data->allocate_find) == 0) {
radlog(L_ERR, "rlm_sqlippool: the 'allocate_find' statement must be set.");
free(data);
exit(0);
}
if (data->allocate_update == NULL || strlen(data->allocate_update) == 0) {
radlog(L_ERR, "rlm_sqlippool: the 'allocate_update' statement must be set.");
free(data);
exit(0);
}
if (data->start_update == NULL || strlen(data->start_update) == 0) {
radlog(L_ERR, "rlm_sqlippool: the 'start-update' statement must be set.");
free(data);
exit(0);
}
if (data->alive_update == NULL || strlen(data->alive_update) == 0) {
radlog(L_ERR, "rlm_sqlippool: the 'alive-update' statement must be set.");
free(data);
exit(0);
}
if (data->stop_clear == NULL || strlen(data->stop_clear) == 0) {
radlog(L_ERR, "rlm_sqlippool: the 'stop-clear' statement must be set.");
free(data);
exit(0);
}
if (data->on_clear == NULL || strlen(data->on_clear) == 0) {
radlog(L_ERR, "rlm_sqlippool: the 'on-clear' statement must be set.");
free(data);
exit(0);
}
if (data->off_clear == NULL || strlen(data->off_clear) == 0) {
radlog(L_ERR, "rlm_sqlippool: the 'off-clear' statement must be set.");
free(data);
exit(0);
}
pool_name = cf_section_name2(conf);
if (pool_name != NULL)
data->pool_name = strdup(pool_name);
else
data->pool_name = strdup("ippool");
if ( !(data->sql_inst = (SQL_INST *) (find_module_instance(data->sql_instance_name))->insthandle) )
{
radlog(L_ERR, "sqlippool_instantiate: failed to find sql instance named %s", data->sql_instance_name);
free(data);
exit(0);
}
sqlippool_initialize_sql(data);
pthread_mutex_init(&data->dlock, NULL);
*instance = data;
return 0;
}
/*
* Allocate an IP number from the pool.
*/
static int sqlippool_postauth(void *instance, REQUEST * request)
{
rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
char allocation[MAX_STRING_LEN];
int allocation_len;
uint32_t ip_allocation;
VALUE_PAIR * vp;
SQLSOCK * sqlsocket;
long self = (long) pthread_self();
/*
* If there is a Framed-IP-Address attribute in the reply do nothing
*/
if (pairfind(request->reply->vps, PW_FRAMED_IP_ADDRESS) != NULL) {
DEBUG("rlm_sqlippool: Framed-IP-Address already exists");
return RLM_MODULE_NOOP;
}
if ((vp = pairfind(request->config_items, PW_POOL_NAME)) != NULL) {
DEBUG("Value Of the Pool-Name is [%s] and its [%i] Chars \n", vp->strvalue, vp->length);
pthread_mutex_lock(&data->dlock);
strNcpy(data->pool_name, vp->strvalue, (vp->length + 1));
pthread_mutex_unlock(&data->dlock);
}
else {
DEBUG("rlm_sqlippool: missing pool_name");
return RLM_MODULE_NOOP;
}
if (pairfind(request->packet->vps, PW_NAS_IP_ADDRESS) == NULL) {
DEBUG("rlm_sqlippool: unknown NAS-IP-Address");
return RLM_MODULE_NOOP;
}
if (pairfind(request->packet->vps, PW_NAS_PORT) == NULL) {
DEBUG("rlm_sqlippool: unknown NAS-Port");
return RLM_MODULE_NOOP;
}
sqlsocket = sql_get_socket(data->sql_inst);
if (sqlsocket == NULL) {
DEBUG("rlm_sqlippool: cannot allocate sql connection");
return RLM_MODULE_NOOP;
}
/*
* BEGIN
*/
sqlippool_command(data->allocate_begin, sqlsocket, instance, request,
(char *) NULL, 0);
/*
* CLEAR
*/
sqlippool_command(data->allocate_clear, sqlsocket, instance, request,
(char *) NULL, 0);
/*
* FIND
*/
allocation_len = sqlippool_query1(allocation, sizeof(allocation),
data->allocate_find, sqlsocket, instance, request,
(char *) NULL, 0);
radlog(L_INFO,"rlm_sqlippool: ip=[%s] len=%d", allocation, allocation_len);
if (allocation_len == 0)
{
/*
* COMMIT
*/
sqlippool_command(data->allocate_commit, sqlsocket, instance, request,
(char *) NULL, 0);
DEBUG("rlm_sqlippool: IP number could not be allocated.");
sql_release_socket(data->sql_inst, sqlsocket);
return RLM_MODULE_NOTFOUND;
}
ip_allocation = ip_addr(allocation);
if (ip_allocation == INADDR_NONE)
{
/*
* COMMIT
*/
sqlippool_command(data->allocate_commit, sqlsocket, instance, request,
(char *) NULL, 0);
DEBUG("rlm_sqlippool: Invalid IP number [%s] returned from database query.", allocation);
sql_release_socket(data->sql_inst, sqlsocket);
return RLM_MODULE_NOOP;
}
/*
* UPDATE
*/
sqlippool_command(data->allocate_update, sqlsocket, instance, request,
allocation, allocation_len);
DEBUG("rlm_sqlippool: Allocated IP %s [%08x]", allocation, ip_allocation);
if ((vp = paircreate(PW_FRAMED_IP_ADDRESS, PW_TYPE_IPADDR)) == NULL) {
radlog(L_ERR|L_CONS, "no memory");
sql_release_socket(data->sql_inst, sqlsocket);
return RLM_MODULE_NOOP;
}
vp->lvalue = ip_allocation;
pairadd(&request->reply->vps, vp);
/*
* COMMIT
*/
sqlippool_command(data->allocate_commit, sqlsocket, instance, request,
(char *) NULL, 0);
sql_release_socket(data->sql_inst, sqlsocket);
return RLM_MODULE_OK;
}
static int sqlippool_accounting_start(void * instance, REQUEST * request)
{
rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
SQLSOCK * sqlsocket;
if (pairfind(request->packet->vps, PW_NAS_PORT) == NULL) {
DEBUG("rlm_ippool: Could not find port number in packet.");
return RLM_MODULE_NOOP;
}
if (pairfind(request->packet->vps, PW_NAS_IP_ADDRESS) == NULL) {
DEBUG("rlm_ippool: Could not find nas information in packet.");
return RLM_MODULE_NOOP;
}
sqlsocket = sql_get_socket(data->sql_inst);
if (sqlsocket == NULL) {
DEBUG("rlm_sqlippool: cannot allocate sql connection");
return RLM_MODULE_NOOP;
}
/*
* BEGIN
*/
sqlippool_command(data->start_begin, sqlsocket, instance, request,
(char *) NULL, 0);
/*
* UPDATE
*/
sqlippool_command(data->start_update, sqlsocket, instance, request,
(char *) NULL, 0);
/*
* COMMIT
*/
sqlippool_command(data->start_commit, sqlsocket, instance, request,
(char *) NULL, 0);
sql_release_socket(data->sql_inst, sqlsocket);
return RLM_MODULE_OK;
}
static int sqlippool_accounting_alive(void * instance, REQUEST * request)
{
rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
SQLSOCK * sqlsocket;
if (pairfind(request->packet->vps, PW_NAS_PORT) == NULL) {
DEBUG("rlm_ippool: Could not find port number in packet.");
return RLM_MODULE_NOOP;
}
if (pairfind(request->packet->vps, PW_NAS_IP_ADDRESS) == NULL) {
DEBUG("rlm_ippool: Could not find nas information in packet.");
return RLM_MODULE_NOOP;
}
sqlsocket = sql_get_socket(data->sql_inst);
if (sqlsocket == NULL) {
DEBUG("rlm_sqlippool: cannot allocate sql connection");
return RLM_MODULE_NOOP;
}
/*
* BEGIN
*/
sqlippool_command(data->alive_begin, sqlsocket, instance, request,
(char *) NULL, 0);
/*
* UPDATE
*/
sqlippool_command(data->alive_update, sqlsocket, instance, request,
(char *) NULL, 0);
/*
* COMMIT
*/
sqlippool_command(data->alive_commit, sqlsocket, instance, request,
(char *) NULL, 0);
sql_release_socket(data->sql_inst, sqlsocket);
return RLM_MODULE_OK;
}
static int sqlippool_accounting_stop(void * instance, REQUEST * request)
{
rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
SQLSOCK * sqlsocket;
if (pairfind(request->packet->vps, PW_NAS_PORT) == NULL) {
DEBUG("rlm_ippool: Could not find port number in packet.");
return RLM_MODULE_NOOP;
}
if (pairfind(request->packet->vps, PW_NAS_IP_ADDRESS) == NULL) {
DEBUG("rlm_ippool: Could not find nas information in packet.");
return RLM_MODULE_NOOP;
}
sqlsocket = sql_get_socket(data->sql_inst);
if (sqlsocket == NULL) {
DEBUG("rlm_sqlippool: cannot allocate sql connection");
return RLM_MODULE_NOOP;
}
/*
* BEGIN
*/
sqlippool_command(data->stop_begin, sqlsocket, instance, request,
(char *) NULL, 0);
/*
* CLEAR
*/
sqlippool_command(data->stop_clear, sqlsocket, instance, request,
(char *) NULL, 0);
/*
* COMMIT
*/
sqlippool_command(data->stop_commit, sqlsocket, instance, request,
(char *) NULL, 0);
sql_release_socket(data->sql_inst, sqlsocket);
return RLM_MODULE_OK;
}
static int sqlippool_accounting_on(void * instance, REQUEST * request)
{
rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
SQLSOCK * sqlsocket;
if (pairfind(request->packet->vps, PW_NAS_IP_ADDRESS) == NULL) {
DEBUG("rlm_ippool: Could not find nas information in packet.");
return RLM_MODULE_NOOP;
}
sqlsocket = sql_get_socket(data->sql_inst);
if (sqlsocket == NULL) {
DEBUG("rlm_sqlippool: cannot allocate sql connection");
return RLM_MODULE_NOOP;
}
/*
* BEGIN
*/
sqlippool_command(data->on_begin, sqlsocket, instance, request,
(char *) NULL, 0);
/*
* CLEAR
*/
sqlippool_command(data->on_clear, sqlsocket, instance, request,
(char *) NULL, 0);
/*
* COMMIT
*/
sqlippool_command(data->on_commit, sqlsocket, instance, request,
(char *) NULL, 0);
sql_release_socket(data->sql_inst, sqlsocket);
return RLM_MODULE_OK;
}
static int sqlippool_accounting_off(void * instance, REQUEST * request)
{
rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
SQLSOCK * sqlsocket;
if (pairfind(request->packet->vps, PW_NAS_IP_ADDRESS) == NULL) {
DEBUG("rlm_ippool: Could not find nas information in packet.");
return RLM_MODULE_NOOP;
}
sqlsocket = sql_get_socket(data->sql_inst);
if (sqlsocket == NULL) {
DEBUG("rlm_sqlippool: cannot allocate sql connection");
return RLM_MODULE_NOOP;
}
/*
* BEGIN
*/
sqlippool_command(data->off_begin, sqlsocket, instance, request,
(char *) NULL, 0);
/*
* CLEAR
*/
sqlippool_command(data->off_clear, sqlsocket, instance, request,
(char *) NULL, 0);
/*
* COMMIT
*/
sqlippool_command(data->off_commit, sqlsocket, instance, request,
(char *) NULL, 0);
sql_release_socket(data->sql_inst, sqlsocket);
return RLM_MODULE_OK;
}
/*
* Check for an Accounting-Stop
* If we find one and we have allocated an IP to this nas/port combination, deallocate it.
*/
static int sqlippool_accounting(void * instance, REQUEST * request)
{
VALUE_PAIR * vp;
int acct_status_type;
vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE);
if (vp == NULL) {
DEBUG("rlm_sqlippool: Could not find account status type in packet.");
return RLM_MODULE_NOOP;
}
acct_status_type = vp->lvalue;
switch (acct_status_type) {
case PW_STATUS_START:
return sqlippool_accounting_start(instance, request);
case PW_STATUS_ALIVE:
return sqlippool_accounting_alive(instance, request);
case PW_STATUS_STOP:
return sqlippool_accounting_stop(instance, request);
case PW_STATUS_ACCOUNTING_ON:
return sqlippool_accounting_on(instance, request);
case PW_STATUS_ACCOUNTING_OFF:
return sqlippool_accounting_off(instance, request);
default:
/* We don't care about any other accounting packet */
return RLM_MODULE_NOOP;
}
}
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->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;
}
/*
* 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_sqlippool = {
"SQL IP Pool",
RLM_TYPE_THREAD_SAFE, /* type */
NULL, /* initialization */
sqlippool_instantiate, /* instantiation */
{
NULL, /* authentication */
NULL, /* authorization */
NULL, /* preaccounting */
sqlippool_accounting, /* accounting */
NULL, /* checksimul */
NULL, /* pre-proxy */
NULL, /* post-proxy */
sqlippool_postauth /* post-auth */
},
sqlippool_detach, /* detach */
NULL, /* destroy */
};
syntax highlighted by Code2HTML, v. 0.9.1