📄 rlm_sqlippool.c
字号:
/* * 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); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -