📄 rlm_sqlippool.c
字号:
/* * rlm_sqlippool.c rlm_sqlippool - FreeRADIUS SQL IP Pool Module * * Version: $Id: rlm_sqlippool.c,v 1.38 2008/04/28 12:25:23 aland 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 <freeradius-devel/ident.h>RCSID("$Id: rlm_sqlippool.c,v 1.38 2008/04/28 12:25:23 aland Exp $")#include <freeradius-devel/radiusd.h>#include <ctype.h>#include <freeradius-devel/modules.h>#include <freeradius-devel/modpriv.h>#include <rlm_sql.h>/* * 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 */ 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 */ 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 */ /* 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 none in the check items */} rlm_sqlippool_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[] = { {"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, "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" }, { "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, "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, "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, "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, "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 }};/* * 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 */ 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 != '\\') { *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 */ strlcpy(q, data->pool_name, freespace); q += strlen(q); break; case 'I': /* IP address */ if (param && param_len > 0) { if (param_len > freespace) { strlcpy(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); strlcpy(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 on: '%s'", query); 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 in: '%s'", query); 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]; int rlen, retval = 0; 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; } out[0] = '\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"); } (data->sql_inst->module->sql_finish_select_query)(sqlsocket, data->sql_inst->config); return retval;}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;}static int sqlippool_detach(void *instance){ free(instance); return 0;}/* * 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){ module_instance_t *modinst; rlm_sqlippool_t * data; const 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."); sqlippool_detach(data); return -1; } /* * 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."); sqlippool_detach(data); return -1; } if ((data->allocate_find == NULL) || (strlen(data->allocate_find) == 0)) { radlog(L_ERR, "rlm_sqlippool: the 'allocate_find' statement must be set."); sqlippool_detach(data); return -1; } if ((data->allocate_update == NULL) || (strlen(data->allocate_update) == 0)) { radlog(L_ERR, "rlm_sqlippool: the 'allocate_update' statement must be set."); sqlippool_detach(data); return -1; } if ((data->start_update == NULL) || (strlen(data->start_update) == 0)) { radlog(L_ERR, "rlm_sqlippool: the 'start-update' statement must be set."); sqlippool_detach(data); return -1; } if ((data->alive_update == NULL) ||
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -