/*
- * rlm_sql.c SQL Module
- * Main SQL module file. Most ICRADIUS code is located in sql.c
- *
- * 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
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * This program is is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 if the
+ * License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file rlm_sql.c
+ * @brief Implements SQL 'users' file, and SQL accounting.
*
- * Copyright 2000,2006 The FreeRADIUS server project
- * Copyright 2000 Mike Machado <mike@innercite.com>
- * Copyright 2000 Alan DeKok <aland@ox.org>
+ * @copyright 2012 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2000,2006 The FreeRADIUS server project
+ * @copyright 2000 Mike Machado <mike@innercite.com>
+ * @copyright 2000 Alan DeKok <aland@ox.org>
*/
-
#include <freeradius-devel/ident.h>
RCSID("$Id$")
+#include <ctype.h>
+
#include <freeradius-devel/radiusd.h>
#include <freeradius-devel/modules.h>
+#include <freeradius-devel/token.h>
#include <freeradius-devel/rad_assert.h>
#include <sys/stat.h>
#include "rlm_sql.h"
-static char *allowed_chars = NULL;
+static const CONF_PARSER acct_section_config[] = {
+ {"reference", PW_TYPE_STRING_PTR,
+ offsetof(sql_acct_section_t, reference), NULL, ".query"},
+
+ {"logfile", PW_TYPE_STRING_PTR,
+ offsetof(sql_acct_section_t, logfile), NULL, NULL},
+ {NULL, -1, 0, NULL, NULL}
+};
static const CONF_PARSER module_config[] = {
- {"driver",PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,sql_driver), NULL, "mysql"},
- {"server",PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,sql_server), NULL, "localhost"},
- {"port",PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,sql_port), NULL, ""},
+ {"driver", PW_TYPE_STRING_PTR,
+ offsetof(rlm_sql_config_t,sql_driver), NULL, "mysql"},
+ {"server", PW_TYPE_STRING_PTR,
+ offsetof(rlm_sql_config_t,sql_server), NULL, "localhost"},
+ {"port", PW_TYPE_STRING_PTR,
+ offsetof(rlm_sql_config_t,sql_port), NULL, ""},
{"login", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,sql_login), NULL, ""},
+ offsetof(rlm_sql_config_t,sql_login), NULL, ""},
{"password", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,sql_password), NULL, ""},
+ offsetof(rlm_sql_config_t,sql_password), NULL, ""},
{"radius_db", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,sql_db), NULL, "radius"},
+ offsetof(rlm_sql_config_t,sql_db), NULL, "radius"},
+ {"filename", PW_TYPE_FILENAME, /* for sqlite */
+ offsetof(rlm_sql_config_t,sql_file), NULL, NULL},
{"read_groups", PW_TYPE_BOOLEAN,
- offsetof(SQL_CONFIG,read_groups), NULL, "yes"},
- {"sqltrace", PW_TYPE_BOOLEAN,
- offsetof(SQL_CONFIG,sqltrace), NULL, "no"},
- {"sqltracefile", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,tracefile), NULL, SQLTRACEFILE},
+ offsetof(rlm_sql_config_t,read_groups), NULL, "yes"},
{"readclients", PW_TYPE_BOOLEAN,
- offsetof(SQL_CONFIG,do_clients), NULL, "no"},
+ offsetof(rlm_sql_config_t,do_clients), NULL, "no"},
{"deletestalesessions", PW_TYPE_BOOLEAN,
- offsetof(SQL_CONFIG,deletestalesessions), NULL, "yes"},
- {"num_sql_socks", PW_TYPE_INTEGER,
- offsetof(SQL_CONFIG,num_sql_socks), NULL, "5"},
- {"lifetime", PW_TYPE_INTEGER,
- offsetof(SQL_CONFIG,lifetime), NULL, "0"},
- {"max_queries", PW_TYPE_INTEGER,
- offsetof(SQL_CONFIG,max_queries), NULL, "0"},
+ offsetof(rlm_sql_config_t,deletestalesessions), NULL, "yes"},
{"sql_user_name", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,query_user), NULL, ""},
+ offsetof(rlm_sql_config_t,query_user), NULL, ""},
+ {"logfile", PW_TYPE_STRING_PTR,
+ offsetof(rlm_sql_config_t,logfile), NULL, NULL},
{"default_user_profile", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,default_profile), NULL, ""},
+ offsetof(rlm_sql_config_t,default_profile), NULL, ""},
{"nas_query", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,nas_query), NULL, "SELECT id,nasname,shortname,type,secret FROM nas"},
+ offsetof(rlm_sql_config_t,nas_query), NULL,
+ "SELECT id,nasname,shortname,type,secret FROM nas"},
{"authorize_check_query", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,authorize_check_query), NULL, ""},
+ offsetof(rlm_sql_config_t,authorize_check_query), NULL, ""},
{"authorize_reply_query", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,authorize_reply_query), NULL, NULL},
+ offsetof(rlm_sql_config_t,authorize_reply_query), NULL, NULL},
{"authorize_group_check_query", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,authorize_group_check_query), NULL, ""},
+ offsetof(rlm_sql_config_t,authorize_group_check_query), NULL, ""},
{"authorize_group_reply_query", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,authorize_group_reply_query), NULL, ""},
- {"accounting_onoff_query", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,accounting_onoff_query), NULL, ""},
- {"accounting_update_query", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,accounting_update_query), NULL, ""},
- {"accounting_update_query_alt", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,accounting_update_query_alt), NULL, ""},
- {"accounting_start_query", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,accounting_start_query), NULL, ""},
- {"accounting_start_query_alt", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,accounting_start_query_alt), NULL, ""},
- {"accounting_stop_query", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,accounting_stop_query), NULL, ""},
- {"accounting_stop_query_alt", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,accounting_stop_query_alt), NULL, ""},
+ offsetof(rlm_sql_config_t,authorize_group_reply_query), NULL, ""},
{"group_membership_query", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,groupmemb_query), NULL, NULL},
- {"connect_failure_retry_delay", PW_TYPE_INTEGER,
- offsetof(SQL_CONFIG,connect_failure_retry_delay), NULL, "60"},
+ offsetof(rlm_sql_config_t,groupmemb_query), NULL, NULL},
+#ifdef WITH_SESSION_MGMT
{"simul_count_query", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,simul_count_query), NULL, ""},
+ offsetof(rlm_sql_config_t,simul_count_query), NULL, ""},
{"simul_verify_query", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,simul_verify_query), NULL, ""},
- {"postauth_query", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,postauth_query), NULL, ""},
+ offsetof(rlm_sql_config_t,simul_verify_query), NULL, ""},
+#endif
{"safe-characters", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,allowed_chars), NULL,
+ offsetof(rlm_sql_config_t,allowed_chars), NULL,
"@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"},
/*
* This only works for a few drivers.
*/
{"query_timeout", PW_TYPE_INTEGER,
- offsetof(SQL_CONFIG,query_timeout), NULL, NULL},
+ offsetof(rlm_sql_config_t,query_timeout), NULL, NULL},
{NULL, -1, 0, NULL, NULL}
};
static int fallthrough(VALUE_PAIR *vp)
{
VALUE_PAIR *tmp;
- tmp = pairfind(vp, PW_FALL_THROUGH);
+ tmp = pairfind(vp, PW_FALL_THROUGH, 0, TAG_ANY);
return tmp ? tmp->vp_integer : 0;
}
-
-
/*
* Yucky prototype.
*/
-static int generate_sql_clients(SQL_INST *inst);
-static size_t sql_escape_func(char *out, size_t outlen, const char *in);
+static int generate_sql_clients(rlm_sql_t *inst);
+static size_t sql_escape_func(REQUEST *, char *out, size_t outlen, const char *in, void *arg);
/*
- * sql xlat function. Right now only SELECTs are supported. Only
- * the first element of the SELECT result will be used.
+ * SQL xlat function
*
- * For other statements (insert, update, delete, etc.), the
- * number of affected rows will be returned.
+ * For selects the first value of the first column will be returned,
+ * for inserts, updates and deletes the number of rows afftected will be
+ * returned instead.
*/
-static int sql_xlat(void *instance, REQUEST *request,
- char *fmt, char *out, size_t freespace,
- UNUSED RADIUS_ESCAPE_STRING func)
+static size_t sql_xlat(void *instance, REQUEST *request,
+ const char *fmt, char *out, size_t freespace)
{
- SQLSOCK *sqlsocket;
- SQL_ROW row;
- SQL_INST *inst = instance;
+ rlm_sql_handle_t *handle;
+ rlm_sql_row_t row;
+ rlm_sql_t *inst = instance;
char querystr[MAX_QUERY_LEN];
- char sqlusername[MAX_STRING_LEN];
size_t ret = 0;
RDEBUG("sql_xlat");
* We could search the string fmt for SQL-User-Name to see if this is
* needed or not
*/
- sql_set_user(inst, request, sqlusername, NULL);
+ sql_set_user(inst, request, NULL);
/*
* Do an xlat on the provided string (nice recursive operation).
*/
- if (!radius_xlat(querystr, sizeof(querystr), fmt, request, sql_escape_func)) {
+ if (!radius_xlat(querystr, sizeof(querystr), fmt, request, sql_escape_func, inst)) {
radlog(L_ERR, "rlm_sql (%s): xlat failed.",
inst->config->xlat_name);
return 0;
}
- query_log(request, inst,querystr);
- sqlsocket = sql_get_socket(inst);
- if (sqlsocket == NULL)
+ handle = sql_get_socket(inst);
+ if (handle == NULL)
return 0;
+ rlm_sql_query_log(inst, request, NULL, querystr);
+
/*
* If the query starts with any of the following prefixes,
* then return the number of rows affected
int numaffected;
char buffer[21]; /* 64bit max is 20 decimal chars + null byte */
- if (rlm_sql_query(sqlsocket,inst,querystr)) {
- radlog(L_ERR, "rlm_sql (%s): database query error, %s: %s",
- inst->config->xlat_name, querystr,
- (inst->module->sql_error)(sqlsocket,
- inst->config));
- sql_release_socket(inst,sqlsocket);
+ if (rlm_sql_query(&handle,inst,querystr)) {
+ sql_release_socket(inst,handle);
+
return 0;
}
- numaffected = (inst->module->sql_affected_rows)(sqlsocket,
+ numaffected = (inst->module->sql_affected_rows)(handle,
inst->config);
if (numaffected < 1) {
RDEBUG("rlm_sql (%s): SQL query affected no rows",
if (ret >= freespace){
RDEBUG("rlm_sql (%s): Can't write result, insufficient string space",
inst->config->xlat_name);
- (inst->module->sql_finish_query)(sqlsocket,
+ (inst->module->sql_finish_query)(handle,
inst->config);
- sql_release_socket(inst,sqlsocket);
+ sql_release_socket(inst,handle);
return 0;
}
memcpy(out, buffer, ret + 1); /* we did bounds checking above */
- (inst->module->sql_finish_query)(sqlsocket, inst->config);
- sql_release_socket(inst,sqlsocket);
+ (inst->module->sql_finish_query)(handle, inst->config);
+ sql_release_socket(inst,handle);
return ret;
} /* else it's a SELECT statement */
- if (rlm_sql_select_query(sqlsocket,inst,querystr)){
- radlog(L_ERR, "rlm_sql (%s): database query error, %s: %s",
- inst->config->xlat_name,querystr,
- (inst->module->sql_error)(sqlsocket, inst->config));
- sql_release_socket(inst,sqlsocket);
+ if (rlm_sql_select_query(&handle,inst,querystr)){
+ sql_release_socket(inst,handle);
return 0;
}
- ret = rlm_sql_fetch_row(sqlsocket, inst);
-
+ ret = rlm_sql_fetch_row(&handle, inst);
if (ret) {
RDEBUG("SQL query did not succeed");
- (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
- sql_release_socket(inst,sqlsocket);
+ (inst->module->sql_finish_select_query)(handle, inst->config);
+ sql_release_socket(inst,handle);
return 0;
}
- row = sqlsocket->row;
+ row = handle->row;
if (row == NULL) {
RDEBUG("SQL query did not return any results");
- (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
- sql_release_socket(inst,sqlsocket);
+ (inst->module->sql_finish_select_query)(handle, inst->config);
+ sql_release_socket(inst,handle);
return 0;
}
if (row[0] == NULL){
- RDEBUG("row[0] returned NULL");
- (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
- sql_release_socket(inst,sqlsocket);
+ RDEBUG("Null value in first column");
+ (inst->module->sql_finish_select_query)(handle, inst->config);
+ sql_release_socket(inst,handle);
return 0;
}
ret = strlen(row[0]);
if (ret >= freespace){
RDEBUG("Insufficient string space");
- (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
- sql_release_socket(inst,sqlsocket);
+ (inst->module->sql_finish_select_query)(handle, inst->config);
+ sql_release_socket(inst,handle);
return 0;
}
RDEBUG("sql_xlat finished");
- (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
- sql_release_socket(inst,sqlsocket);
+ (inst->module->sql_finish_select_query)(handle, inst->config);
+ sql_release_socket(inst,handle);
return ret;
}
-static int generate_sql_clients(SQL_INST *inst)
+static int generate_sql_clients(rlm_sql_t *inst)
{
- SQLSOCK *sqlsocket;
- SQL_ROW row;
+ rlm_sql_handle_t *handle;
+ rlm_sql_row_t row;
char querystr[MAX_QUERY_LEN];
RADCLIENT *c;
char *prefix_ptr = NULL;
DEBUG("rlm_sql (%s) in generate_sql_clients: query is %s",
inst->config->xlat_name, querystr);
- sqlsocket = sql_get_socket(inst);
- if (sqlsocket == NULL)
+ handle = sql_get_socket(inst);
+ if (handle == NULL)
return -1;
- if (rlm_sql_select_query(sqlsocket,inst,querystr)){
- radlog(L_ERR, "rlm_sql (%s): database query error, %s: %s",
- inst->config->xlat_name,querystr,
- (inst->module->sql_error)(sqlsocket, inst->config));
- sql_release_socket(inst,sqlsocket);
+ if (rlm_sql_select_query(&handle,inst,querystr)){
return -1;
}
- while(rlm_sql_fetch_row(sqlsocket, inst) == 0) {
+ while(rlm_sql_fetch_row(&handle, inst) == 0) {
i++;
- row = sqlsocket->row;
+ row = handle->row;
if (row == NULL)
break;
- /*
- * The return data for each row MUST be in the following order:
- *
- * 0. Row ID (currently unused)
- * 1. Name (or IP address)
- * 2. Shortname
- * 3. Type
- * 4. Secret
- * 5. Virtual Server (optional)
- */
+ /*
+ * The return data for each row MUST be in the following order:
+ *
+ * 0. Row ID (currently unused)
+ * 1. Name (or IP address)
+ * 2. Shortname
+ * 3. Type
+ * 4. Secret
+ * 5. Virtual Server (optional)
+ */
if (!row[0]){
radlog(L_ERR, "rlm_sql (%s): No row id found on pass %d",inst->config->xlat_name,i);
continue;
DEBUG("rlm_sql (%s): Read entry nasname=%s,shortname=%s,secret=%s",inst->config->xlat_name,
row[1],row[2],row[4]);
- c = rad_malloc(sizeof(*c));
- memset(c, 0, sizeof(*c));
+ c = talloc_zero(inst, RADCLIENT);
#ifdef WITH_DYNAMIC_CLIENTS
c->dynamic = 1;
if ((c->prefix < 0) || (c->prefix > 128)) {
radlog(L_ERR, "rlm_sql (%s): Invalid Prefix value '%s' for IP.",
inst->config->xlat_name, prefix_ptr + 1);
- free(c);
+ talloc_free(c);
continue;
}
/* Replace '/' with '\0' */
* Always get the numeric representation of IP
*/
if (ip_hton(row[1], AF_UNSPEC, &c->ipaddr) < 0) {
- radlog(L_CONS|L_ERR, "rlm_sql (%s): Failed to look up hostname %s: %s",
+ radlog(L_ERR, "rlm_sql (%s): Failed to look up hostname %s: %s",
inst->config->xlat_name,
row[1], fr_strerror());
- free(c);
+ talloc_free(c);
continue;
} else {
char buffer[256];
ip_ntoh(&c->ipaddr, buffer, sizeof(buffer));
- c->longname = strdup(buffer);
+ c->longname = talloc_strdup(c, buffer);
}
if (c->prefix < 0) switch (c->ipaddr.af) {
/*
* Other values (secret, shortname, nastype, virtual_server)
*/
- c->secret = strdup(row[4]);
- c->shortname = strdup(row[2]);
+ c->secret = talloc_strdup(c, row[4]);
+ c->shortname = talloc_strdup(c, row[2]);
if(row[3] != NULL)
c->nastype = strdup(row[3]);
- numf = (inst->module->sql_num_fields)(sqlsocket, inst->config);
- if ((numf > 5) && (row[5] != NULL)) c->server = strdup(row[5]);
+ numf = (inst->module->sql_num_fields)(handle, inst->config);
+ if ((numf > 5) && (row[5] != NULL) && *row[5]) c->server = strdup(row[5]);
DEBUG("rlm_sql (%s): Adding client %s (%s, server=%s) to clients list",
inst->config->xlat_name,
c->longname,c->shortname, c->server ? c->server : "<none>");
if (!client_add(NULL, c)) {
+ sql_release_socket(inst, handle);
DEBUG("rlm_sql (%s): Failed to add client %s (%s) to clients list. Maybe there's a duplicate?",
inst->config->xlat_name,
c->longname,c->shortname);
return -1;
}
}
- (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
- sql_release_socket(inst, sqlsocket);
+ (inst->module->sql_finish_select_query)(handle, inst->config);
+ sql_release_socket(inst, handle);
return 0;
}
/*
* Translate the SQL queries.
*/
-static size_t sql_escape_func(char *out, size_t outlen, const char *in)
+static size_t sql_escape_func(UNUSED REQUEST *request, char *out, size_t outlen,
+ const char *in, void *arg)
{
+ rlm_sql_t *inst = arg;
size_t len = 0;
while (in[0]) {
* mime-encoded equivalents.
*/
if ((in[0] < 32) ||
- strchr(allowed_chars, *in) == NULL) {
+ strchr(inst->config->allowed_chars, *in) == NULL) {
/*
* Only 3 or less bytes available.
*/
* escape it twice. (it will make things wrong if we have an
* escape candidate character in the username)
*/
-int sql_set_user(SQL_INST *inst, REQUEST *request, char *sqlusername, const char *username)
+int sql_set_user(rlm_sql_t *inst, REQUEST *request, const char *username)
{
- VALUE_PAIR *vp=NULL;
- char tmpuser[MAX_STRING_LEN];
-
- tmpuser[0] = '\0';
- sqlusername[0]= '\0';
-
- /* Remove any user attr we added previously */
- pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
+ char buffer[254];
+ VALUE_PAIR *vp = NULL;
+ const char *sqluser;
+ size_t len;
if (username != NULL) {
- strlcpy(tmpuser, username, sizeof(tmpuser));
- } else if (strlen(inst->config->query_user)) {
- radius_xlat(tmpuser, sizeof(tmpuser), inst->config->query_user, request, NULL);
+ sqluser = username;
+ } else if (*inst->config->query_user) {
+ sqluser = inst->config->query_user;
} else {
return 0;
}
-
- strlcpy(sqlusername, tmpuser, MAX_STRING_LEN);
- RDEBUG2("sql_set_user escaped user --> '%s'", sqlusername);
- vp = radius_pairmake(request, &request->packet->vps,
- "SQL-User-Name", NULL, 0);
- if (!vp) {
- radlog(L_ERR, "%s", fr_strerror());
+
+ len = radius_xlat(buffer, sizeof(buffer), sqluser, request, NULL, NULL);
+ if (!len) {
return -1;
}
-
- strlcpy(vp->vp_strvalue, tmpuser, sizeof(vp->vp_strvalue));
+
+ vp = pairalloc(NULL, inst->sql_user);
+ vp->op = T_OP_SET;
+
+ strlcpy(vp->vp_strvalue, buffer, sizeof(vp->vp_strvalue));
vp->length = strlen(vp->vp_strvalue);
+ pairadd(&request->packet->vps, vp);
- return 0;
+ RDEBUG2("SQL-User-Name updated");
+ return 0;
}
-static void sql_grouplist_free (SQL_GROUPLIST **group_list)
+static void sql_grouplist_free (rlm_sql_grouplist_t **group_list)
{
- SQL_GROUPLIST *last;
+ rlm_sql_grouplist_t *last;
while(*group_list) {
last = *group_list;
}
-static int sql_get_grouplist (SQL_INST *inst, SQLSOCK *sqlsocket, REQUEST *request, SQL_GROUPLIST **group_list)
+static int sql_get_grouplist (rlm_sql_t *inst, rlm_sql_handle_t *handle, REQUEST *request, rlm_sql_grouplist_t **group_list)
{
char querystr[MAX_QUERY_LEN];
int num_groups = 0;
- SQL_ROW row;
- SQL_GROUPLIST *group_list_tmp;
+ rlm_sql_row_t row;
+ rlm_sql_grouplist_t *group_list_tmp;
/* NOTE: sql_set_user should have been run before calling this function */
(inst->config->groupmemb_query[0] == 0))
return 0;
- if (!radius_xlat(querystr, sizeof(querystr), inst->config->groupmemb_query, request, sql_escape_func)) {
+ if (!radius_xlat(querystr, sizeof(querystr), inst->config->groupmemb_query, request, sql_escape_func, inst)) {
radlog_request(L_ERR, 0, request, "xlat \"%s\" failed.",
inst->config->groupmemb_query);
return -1;
}
- if (rlm_sql_select_query(sqlsocket, inst, querystr) < 0) {
- radlog_request(L_ERR, 0, request,
- "database query error, %s: %s",
- querystr,
- (inst->module->sql_error)(sqlsocket,inst->config));
+ if (rlm_sql_select_query(&handle, inst, querystr) < 0) {
return -1;
}
- while (rlm_sql_fetch_row(sqlsocket, inst) == 0) {
- row = sqlsocket->row;
+ while (rlm_sql_fetch_row(&handle, inst) == 0) {
+ row = handle->row;
if (row == NULL)
break;
if (row[0] == NULL){
RDEBUG("row[0] returned NULL");
- (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
+ (inst->module->sql_finish_select_query)(handle, inst->config);
sql_grouplist_free(group_list);
return -1;
}
if (*group_list == NULL) {
- *group_list = rad_malloc(sizeof(SQL_GROUPLIST));
+ *group_list = rad_malloc(sizeof(rlm_sql_grouplist_t));
group_list_tmp = *group_list;
} else {
rad_assert(group_list_tmp != NULL);
- group_list_tmp->next = rad_malloc(sizeof(SQL_GROUPLIST));
+ group_list_tmp->next = rad_malloc(sizeof(rlm_sql_grouplist_t));
group_list_tmp = group_list_tmp->next;
}
group_list_tmp->next = NULL;
strlcpy(group_list_tmp->groupname, row[0], MAX_STRING_LEN);
}
- (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
+ (inst->module->sql_finish_select_query)(handle, inst->config);
return num_groups;
}
static int sql_groupcmp(void *instance, REQUEST *request, VALUE_PAIR *request_vp, VALUE_PAIR *check,
VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
{
- SQLSOCK *sqlsocket;
- SQL_INST *inst = instance;
- char sqlusername[MAX_STRING_LEN];
- SQL_GROUPLIST *group_list, *group_list_tmp;
+ rlm_sql_handle_t *handle;
+ rlm_sql_t *inst = instance;
+ rlm_sql_grouplist_t *group_list, *group_list_tmp;
check_pairs = check_pairs;
reply_pairs = reply_pairs;
request_vp = request_vp;
RDEBUG("sql_groupcmp");
- if (!check || !check->vp_strvalue || !check->length){
+ if (!check || !check->length){
RDEBUG("sql_groupcmp: Illegal group name");
return 1;
}
return 1;
}
/*
- * Set, escape, and check the user attr here
+ * Set, escape, and check the user attr here
*/
- if (sql_set_user(inst, request, sqlusername, NULL) < 0)
+ if (sql_set_user(inst, request, NULL) < 0)
return 1;
/*
* Get a socket for this lookup
*/
- sqlsocket = sql_get_socket(inst);
- if (sqlsocket == NULL) {
- /* Remove the username we (maybe) added above */
- pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
+ handle = sql_get_socket(inst);
+ if (handle == NULL) {
return 1;
}
/*
* Get the list of groups this user is a member of
*/
- if (sql_get_grouplist(inst, sqlsocket, request, &group_list) < 0) {
+ if (sql_get_grouplist(inst, handle, request, &group_list) < 0) {
radlog_request(L_ERR, 0, request,
"Error getting group membership");
- /* Remove the username we (maybe) added above */
- pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
- sql_release_socket(inst, sqlsocket);
+ sql_release_socket(inst, handle);
return 1;
}
check->vp_strvalue);
/* Free the grouplist */
sql_grouplist_free(&group_list);
- /* Remove the username we (maybe) added above */
- pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
- sql_release_socket(inst, sqlsocket);
+ sql_release_socket(inst, handle);
return 0;
}
}
/* Free the grouplist */
sql_grouplist_free(&group_list);
- /* Remove the username we (maybe) added above */
- pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
- sql_release_socket(inst,sqlsocket);
+ sql_release_socket(inst,handle);
RDEBUG("sql_groupcmp finished: User is NOT a member of group %s",
check->vp_strvalue);
-static int rlm_sql_process_groups(SQL_INST *inst, REQUEST *request, SQLSOCK *sqlsocket, int *dofallthrough)
+static int rlm_sql_process_groups(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t *handle, int *dofallthrough)
{
VALUE_PAIR *check_tmp = NULL;
VALUE_PAIR *reply_tmp = NULL;
- SQL_GROUPLIST *group_list, *group_list_tmp;
+ rlm_sql_grouplist_t *group_list, *group_list_tmp;
VALUE_PAIR *sql_group = NULL;
char querystr[MAX_QUERY_LEN];
int found = 0;
/*
* Get the list of groups this user is a member of
*/
- if (sql_get_grouplist(inst, sqlsocket, request, &group_list) < 0) {
+ if (sql_get_grouplist(inst, handle, request, &group_list) < 0) {
radlog_request(L_ERR, 0, request, "Error retrieving group list");
return -1;
}
if (!sql_group) {
radlog_request(L_ERR, 0, request,
"Error creating Sql-Group attribute");
+ sql_grouplist_free(&group_list);
return -1;
}
pairadd(&request->packet->vps, sql_group);
- if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_check_query, request, sql_escape_func)) {
+ if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_check_query, request, sql_escape_func, inst)) {
radlog_request(L_ERR, 0, request,
"Error generating query; rejecting user");
/* Remove the grouup we added above */
- pairdelete(&request->packet->vps, PW_SQL_GROUP);
+ pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY);
+ sql_grouplist_free(&group_list);
return -1;
}
- rows = sql_getvpdata(inst, sqlsocket, &check_tmp, querystr);
+ rows = sql_getvpdata(inst, &handle, &check_tmp, querystr);
if (rows < 0) {
radlog_request(L_ERR, 0, request, "Error retrieving check pairs for group %s",
group_list_tmp->groupname);
/* Remove the grouup we added above */
- pairdelete(&request->packet->vps, PW_SQL_GROUP);
+ pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY);
pairfree(&check_tmp);
+ sql_grouplist_free(&group_list);
return -1;
} else if (rows > 0) {
/*
/*
* Now get the reply pairs since the paircompare matched
*/
- if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_reply_query, request, sql_escape_func)) {
+ if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_reply_query, request, sql_escape_func, inst)) {
radlog_request(L_ERR, 0, request, "Error generating query; rejecting user");
/* Remove the grouup we added above */
- pairdelete(&request->packet->vps, PW_SQL_GROUP);
+ pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY);
pairfree(&check_tmp);
+ sql_grouplist_free(&group_list);
return -1;
}
- if (sql_getvpdata(inst, sqlsocket, &reply_tmp, querystr) < 0) {
+ if (sql_getvpdata(inst, &handle, &reply_tmp, querystr) < 0) {
radlog_request(L_ERR, 0, request, "Error retrieving reply pairs for group %s",
group_list_tmp->groupname);
/* Remove the grouup we added above */
- pairdelete(&request->packet->vps, PW_SQL_GROUP);
+ pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY);
pairfree(&check_tmp);
pairfree(&reply_tmp);
+ sql_grouplist_free(&group_list);
return -1;
}
*dofallthrough = fallthrough(reply_tmp);
- pairxlatmove(request, &request->reply->vps, &reply_tmp);
- pairxlatmove(request, &request->config_items, &check_tmp);
+ radius_xlat_move(request, &request->reply->vps, &reply_tmp);
+ radius_xlat_move(request, &request->config_items, &check_tmp);
}
} else {
/*
/*
* Now get the reply pairs since the paircompare matched
*/
- if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_reply_query, request, sql_escape_func)) {
+ if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_reply_query, request, sql_escape_func, inst)) {
radlog_request(L_ERR, 0, request, "Error generating query; rejecting user");
/* Remove the grouup we added above */
- pairdelete(&request->packet->vps, PW_SQL_GROUP);
+ pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY);
pairfree(&check_tmp);
+ sql_grouplist_free(&group_list);
return -1;
}
- if (sql_getvpdata(inst, sqlsocket, &reply_tmp, querystr) < 0) {
+ if (sql_getvpdata(inst, &handle, &reply_tmp, querystr) < 0) {
radlog_request(L_ERR, 0, request, "Error retrieving reply pairs for group %s",
group_list_tmp->groupname);
/* Remove the grouup we added above */
- pairdelete(&request->packet->vps, PW_SQL_GROUP);
+ pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY);
pairfree(&check_tmp);
pairfree(&reply_tmp);
+ sql_grouplist_free(&group_list);
return -1;
}
*dofallthrough = fallthrough(reply_tmp);
- pairxlatmove(request, &request->reply->vps, &reply_tmp);
- pairxlatmove(request, &request->config_items, &check_tmp);
+ radius_xlat_move(request, &request->reply->vps, &reply_tmp);
+ radius_xlat_move(request, &request->config_items, &check_tmp);
}
/*
* Delete the Sql-Group we added above
* And clear out the pairlists
*/
- pairdelete(&request->packet->vps, PW_SQL_GROUP);
+ pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY);
pairfree(&check_tmp);
pairfree(&reply_tmp);
}
static int rlm_sql_detach(void *instance)
{
- SQL_INST *inst = instance;
+ rlm_sql_t *inst = instance;
paircompare_unregister(PW_SQL_GROUP, sql_groupcmp);
-
+
if (inst->config) {
- int i;
-
- if (inst->sqlpool) {
- sql_poolfree(inst);
- }
+ if (inst->pool) sql_poolfree(inst);
if (inst->config->xlat_name) {
- xlat_unregister(inst->config->xlat_name,(RAD_XLAT_FUNC)sql_xlat);
- free(inst->config->xlat_name);
- }
-
- /*
- * Free up dynamically allocated string pointers.
- */
- for (i = 0; module_config[i].name != NULL; i++) {
- char **p;
- if (module_config[i].type != PW_TYPE_STRING_PTR) {
- continue;
- }
-
- /*
- * Treat 'config' as an opaque array of bytes,
- * and take the offset into it. There's a
- * (char*) pointer at that offset, and we want
- * to point to it.
- */
- p = (char **) (((char *)inst->config) + module_config[i].offset);
- if (!*p) { /* nothing allocated */
- continue;
- }
- free(*p);
- *p = NULL;
+ xlat_unregister(inst->config->xlat_name, sql_xlat, instance);
}
- /*
- * Catch multiple instances of the module.
- */
- if (allowed_chars == inst->config->allowed_chars) {
- allowed_chars = NULL;
- }
- free(inst->config);
- inst->config = NULL;
}
if (inst->handle) {
lt_dlclose(inst->handle); /* ignore any errors */
#endif
}
- free(inst);
return 0;
}
-static int rlm_sql_instantiate(CONF_SECTION * conf, void **instance)
+
+static int parse_sub_section(CONF_SECTION *parent,
+ rlm_sql_t *inst,
+ sql_acct_section_t **config,
+ rlm_components_t comp)
{
- SQL_INST *inst;
- const char *xlat_name;
+ CONF_SECTION *cs;
+
+ const char *name = section_type_value[comp].section;
+
+ cs = cf_section_sub_find(parent, name);
+ if (!cs) {
+ radlog(L_INFO, "rlm_sql (%s): Couldn't find configuration for "
+ "%s, will return NOOP for calls from this section",
+ inst->config->xlat_name, name);
+
+ return 0;
+ }
+
+ *config = talloc_zero(parent, sql_acct_section_t);
+ if (cf_section_parse(cs, *config, acct_section_config) < 0) {
+ radlog(L_ERR, "rlm_sql (%s): Couldn't find configuration for "
+ "%s, will return NOOP for calls from this section",
+ inst->config->xlat_name, name);
+ return -1;
+ }
+
+ (*config)->cs = cs;
- inst = rad_malloc(sizeof(SQL_INST));
- memset(inst, 0, sizeof(SQL_INST));
+ return 0;
+}
- inst->config = rad_malloc(sizeof(SQL_CONFIG));
- memset(inst->config, 0, sizeof(SQL_CONFIG));
+static int rlm_sql_instantiate(CONF_SECTION *conf, void **instance)
+{
+ rlm_sql_t *inst;
+ const char *xlat_name;
+ *instance = inst = talloc_zero(conf, rlm_sql_t);
+ if (!inst) return -1;
+
/*
- * Export these methods, too. This avoids RTDL_GLOBAL.
+ * Cache the SQL-User-Name DICT_ATTR, so we can be slightly
+ * more efficient about creating SQL-User-Name attributes.
*/
- inst->sql_set_user = sql_set_user;
- inst->sql_get_socket = sql_get_socket;
- inst->sql_release_socket = sql_release_socket;
- inst->sql_escape_func = sql_escape_func;
- inst->sql_query = rlm_sql_query;
- inst->sql_select_query = rlm_sql_select_query;
- inst->sql_fetch_row = rlm_sql_fetch_row;
+ inst->sql_user = dict_attrbyname("SQL-User-Name");
+ if (!inst->sql_user) return -1;
/*
- * If the configuration parameters can't be parsed, then
- * fail.
+ * Export these methods, too. This avoids RTDL_GLOBAL.
*/
- if (cf_section_parse(conf, inst->config, module_config) < 0) {
- rlm_sql_detach(inst);
- return -1;
- }
+ inst->sql_set_user = sql_set_user;
+ inst->sql_get_socket = sql_get_socket;
+ inst->sql_release_socket = sql_release_socket;
+ inst->sql_escape_func = sql_escape_func;
+ inst->sql_query = rlm_sql_query;
+ inst->sql_select_query = rlm_sql_select_query;
+ inst->sql_fetch_row = rlm_sql_fetch_row;
+
+ inst->config = talloc_zero(inst, rlm_sql_config_t);
+ inst->cs = conf;
xlat_name = cf_section_name2(conf);
- if (xlat_name == NULL)
+ if (xlat_name == NULL) {
xlat_name = cf_section_name1(conf);
- if (xlat_name){
- inst->config->xlat_name = strdup(xlat_name);
- xlat_register(xlat_name, (RAD_XLAT_FUNC)sql_xlat, inst);
+ } else {
+ char *group_name;
+ const DICT_ATTR *dattr;
+ ATTR_FLAGS flags;
+
+ /*
+ * Allocate room for <instance>-SQL-Group
+ */
+ group_name = talloc_asprintf(inst, "%s-SQL-Group", xlat_name);
+ DEBUG("rlm_sql (%s): Creating new attribute %s",
+ xlat_name, group_name);
+
+ memset(&flags, 0, sizeof(flags));
+ if (dict_addattr(group_name, -1, 0, PW_TYPE_STRING, flags) < 0) {
+ radlog(L_ERR, "rlm_sql (%s): Failed to create "
+ "attribute %s: %s", xlat_name, group_name,
+ fr_strerror());
+ return -1;
+ }
+
+ dattr = dict_attrbyname(group_name);
+ if (!dattr) {
+ radlog(L_ERR, "rlm_sql (%s): Failed to create "
+ "attribute %s", xlat_name, group_name);
+ return -1;
+ }
+
+ if (inst->config->groupmemb_query &&
+ inst->config->groupmemb_query[0]) {
+ DEBUG("rlm_sql (%s): Registering sql_groupcmp for %s",
+ xlat_name, group_name);
+ paircompare_register(dattr->attr, PW_USER_NAME,
+ sql_groupcmp, inst);
+ }
}
+
+ rad_assert(xlat_name);
- if (inst->config->num_sql_socks > MAX_SQL_SOCKS) {
- radlog(L_ERR, "rlm_sql (%s): sql_instantiate: number of sqlsockets cannot exceed MAX_SQL_SOCKS, %d",
- inst->config->xlat_name, MAX_SQL_SOCKS);
- rlm_sql_detach(inst);
+ /*
+ * Register the SQL xlat function
+ */
+ inst->config->xlat_name = talloc_strdup(inst->config, xlat_name);
+ xlat_register(xlat_name, sql_xlat, inst);
+
+ /*
+ * If the configuration parameters can't be parsed, then fail.
+ */
+ if ((cf_section_parse(conf, inst->config, module_config) < 0) ||
+ (parse_sub_section(conf, inst,
+ &inst->config->accounting,
+ RLM_COMPONENT_ACCT) < 0) ||
+ (parse_sub_section(conf, inst,
+ &inst->config->postauth,
+ RLM_COMPONENT_POST_AUTH) < 0)) {
+ radlog(L_ERR, "rlm_sql (%s): Failed parsing configuration",
+ inst->config->xlat_name);
return -1;
}
-
+
/*
* Sanity check for crazy people.
*/
if (strncmp(inst->config->sql_driver, "rlm_sql_", 8) != 0) {
- radlog(L_ERR, "\"%s\" is NOT an SQL driver!",
- inst->config->sql_driver);
- rlm_sql_detach(inst);
+ radlog(L_ERR, "rlm_sql (%s): \"%s\" is NOT an SQL driver!",
+ inst->config->xlat_name, inst->config->sql_driver);
return -1;
}
+ /*
+ * Load the appropriate driver for our database
+ */
inst->handle = lt_dlopenext(inst->config->sql_driver);
if (inst->handle == NULL) {
radlog(L_ERR, "Could not link driver %s: %s",
inst->config->sql_driver,
lt_dlerror());
- radlog(L_ERR, "Make sure it (and all its dependent libraries!) are in the search path of your system's ld.");
- rlm_sql_detach(inst);
+ radlog(L_ERR, "Make sure it (and all its dependent libraries!)"
+ "are in the search path of your system's ld.");
return -1;
}
- inst->module = (rlm_sql_module_t *) lt_dlsym(inst->handle, inst->config->sql_driver);
+ inst->module = (rlm_sql_module_t *) lt_dlsym(inst->handle,
+ inst->config->sql_driver);
if (!inst->module) {
radlog(L_ERR, "Could not link symbol %s: %s",
inst->config->sql_driver,
lt_dlerror());
- rlm_sql_detach(inst);
return -1;
}
radlog(L_INFO, "rlm_sql (%s): Driver %s (module %s) loaded and linked",
inst->config->xlat_name, inst->config->sql_driver,
inst->module->name);
+
+ /*
+ * Initialise the connection pool for this instance
+ */
radlog(L_INFO, "rlm_sql (%s): Attempting to connect to %s@%s:%s/%s",
inst->config->xlat_name, inst->config->sql_login,
inst->config->sql_server, inst->config->sql_port,
inst->config->sql_db);
+
+ if (sql_init_socketpool(inst) < 0) return -1;
- if (sql_init_socketpool(inst) < 0) {
- rlm_sql_detach(inst);
- return -1;
+ if (inst->config->groupmemb_query &&
+ inst->config->groupmemb_query[0]) {
+ paircompare_register(PW_SQL_GROUP, PW_USER_NAME, sql_groupcmp, inst);
}
- paircompare_register(PW_SQL_GROUP, PW_USER_NAME, sql_groupcmp, inst);
-
- if (inst->config->do_clients){
+ if (inst->config->do_clients) {
if (generate_sql_clients(inst) == -1){
radlog(L_ERR, "Failed to load clients from SQL.");
- rlm_sql_detach(inst);
return -1;
}
}
- allowed_chars = inst->config->allowed_chars;
-
- *instance = inst;
return RLM_MODULE_OK;
}
-static int rlm_sql_authorize(void *instance, REQUEST * request)
+static rlm_rcode_t rlm_sql_authorize(void *instance, REQUEST * request)
{
+ int ret = RLM_MODULE_NOTFOUND;
+
+ rlm_sql_t *inst = instance;
+ rlm_sql_handle_t *handle;
+
VALUE_PAIR *check_tmp = NULL;
VALUE_PAIR *reply_tmp = NULL;
VALUE_PAIR *user_profile = NULL;
- int found = 0;
+
int dofallthrough = 1;
int rows;
- SQLSOCK *sqlsocket;
- SQL_INST *inst = instance;
- char querystr[MAX_QUERY_LEN];
- char sqlusername[MAX_STRING_LEN];
- /*
- * the profile username is used as the sqlusername during
- * profile checking so that we don't overwrite the orignal
- * sqlusername string
- */
- char profileusername[MAX_STRING_LEN];
-
- /*
- * Set, escape, and check the user attr here
- */
- if (sql_set_user(inst, request, sqlusername, NULL) < 0)
- return RLM_MODULE_FAIL;
+ char querystr[MAX_QUERY_LEN];
/*
- * reserve a socket
+ * Set, escape, and check the user attr here
*/
- sqlsocket = sql_get_socket(inst);
- if (sqlsocket == NULL) {
- /* Remove the username we (maybe) added above */
- pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
+ if (sql_set_user(inst, request, NULL) < 0)
return RLM_MODULE_FAIL;
- }
-
/*
- * After this point, ALL 'return's MUST release the SQL socket!
+ * Reserve a socket
+ *
+ * After this point use goto error or goto release to cleanup sockets
+ * temporary pairlists and temporary attributes.
*/
+ handle = sql_get_socket(inst);
+ if (handle == NULL)
+ goto error;
/*
- * Alright, start by getting the specific entry for the user
+ * Query the check table to find any conditions associated with
+ * this user/realm/whatever...
*/
- if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_check_query, request, sql_escape_func)) {
- radlog_request(L_ERR, 0, request, "Error generating query; rejecting user");
- sql_release_socket(inst, sqlsocket);
- /* Remove the username we (maybe) added above */
- pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
- return RLM_MODULE_FAIL;
- }
- rows = sql_getvpdata(inst, sqlsocket, &check_tmp, querystr);
- if (rows < 0) {
- radlog_request(L_ERR, 0, request, "SQL query error; rejecting user");
- sql_release_socket(inst, sqlsocket);
- /* Remove the username we (maybe) added above */
- pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
- pairfree(&check_tmp);
- return RLM_MODULE_FAIL;
- } else if (rows > 0) {
+ if (inst->config->authorize_check_query &&
+ *inst->config->authorize_check_query) {
+ if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_check_query, request, sql_escape_func, inst)) {
+ radlog_request(L_ERR, 0, request, "Error generating query; rejecting user");
+
+ goto error;
+ }
+
+ rows = sql_getvpdata(inst, &handle, &check_tmp, querystr);
+ if (rows < 0) {
+ radlog_request(L_ERR, 0, request, "SQL query error; rejecting user");
+
+ goto error;
+ }
+
/*
- * Only do this if *some* check pairs were returned
+ * Only do this if *some* check pairs were returned
*/
- if (paircompare(request, request->packet->vps, check_tmp, &request->reply->vps) == 0) {
- found = 1;
+ if ((rows > 0) &&
+ (paircompare(request, request->packet->vps, check_tmp, &request->reply->vps) == 0)) {
RDEBUG2("User found in radcheck table");
+
+ radius_xlat_move(request, &request->config_items, &check_tmp);
+
+ ret = RLM_MODULE_OK;
+ }
+
+ /*
+ * We only process reply table items if check conditions
+ * were verified
+ */
+ else
+ goto skipreply;
+ }
+
+ if (inst->config->authorize_reply_query &&
+ *inst->config->authorize_reply_query) {
+ /*
+ * Now get the reply pairs since the paircompare matched
+ */
+ if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_reply_query, request, sql_escape_func, inst)) {
+ radlog_request(L_ERR, 0, request, "Error generating query; rejecting user");
+
+ goto error;
+ }
+
+ rows = sql_getvpdata(inst, &handle, &reply_tmp, querystr);
+ if (rows < 0) {
+ radlog_request(L_ERR, 0, request, "SQL query error; rejecting user");
- if (inst->config->authorize_reply_query &&
- *inst->config->authorize_reply_query) {
-
- /*
- * Now get the reply pairs since the paircompare matched
- */
- if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_reply_query, request, sql_escape_func)) {
- radlog_request(L_ERR, 0, request, "Error generating query; rejecting user");
- sql_release_socket(inst, sqlsocket);
- /* Remove the username we (maybe) added above */
- pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
- pairfree(&check_tmp);
- return RLM_MODULE_FAIL;
- }
- if (sql_getvpdata(inst, sqlsocket, &reply_tmp, querystr) < 0) {
- radlog_request(L_ERR, 0, request, "SQL query error; rejecting user");
- sql_release_socket(inst, sqlsocket);
- /* Remove the username we (maybe) added above */
- pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
- pairfree(&check_tmp);
- pairfree(&reply_tmp);
- return RLM_MODULE_FAIL;
- }
-
+ goto error;
+ }
+
+ if (rows > 0) {
if (!inst->config->read_groups)
dofallthrough = fallthrough(reply_tmp);
- pairxlatmove(request, &request->reply->vps, &reply_tmp);
- }
- pairxlatmove(request, &request->config_items, &check_tmp);
+
+ radius_xlat_move(request, &request->reply->vps, &reply_tmp);
+
+ ret = RLM_MODULE_OK;
}
}
+
+ skipreply:
/*
- * Clear out the pairlists
+ * Clear out the pairlists
*/
pairfree(&check_tmp);
pairfree(&reply_tmp);
/*
- * dofallthrough is set to 1 by default so that if the user information
- * is not found, we will still process groups. If the user information,
- * however, *is* found, Fall-Through must be set in order to process
- * the groups as well
+ * dofallthrough is set to 1 by default so that if the user information
+ * is not found, we will still process groups. If the user information,
+ * however, *is* found, Fall-Through must be set in order to process
+ * the groups as well.
*/
if (dofallthrough) {
- rows = rlm_sql_process_groups(inst, request, sqlsocket, &dofallthrough);
+ rows = rlm_sql_process_groups(inst, request, handle, &dofallthrough);
if (rows < 0) {
radlog_request(L_ERR, 0, request, "Error processing groups; rejecting user");
- sql_release_socket(inst, sqlsocket);
- /* Remove the username we (maybe) added above */
- pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
- return RLM_MODULE_FAIL;
- } else if (rows > 0) {
- found = 1;
+
+ goto error;
}
+
+ if (rows > 0)
+ ret = RLM_MODULE_OK;
}
/*
- * repeat the above process with the default profile or User-Profile
+ * Repeat the above process with the default profile or User-Profile
*/
if (dofallthrough) {
- int profile_found = 0;
/*
- * Check for a default_profile or for a User-Profile.
- */
- user_profile = pairfind(request->config_items, PW_USER_PROFILE);
- if (inst->config->default_profile[0] != 0 || user_profile != NULL){
- char *profile = inst->config->default_profile;
-
- if (user_profile != NULL)
- profile = user_profile->vp_strvalue;
- if (profile && strlen(profile)){
- RDEBUG("Checking profile %s", profile);
- if (sql_set_user(inst, request, profileusername, profile) < 0) {
- radlog_request(L_ERR, 0, request, "Error setting profile; rejecting user");
- sql_release_socket(inst, sqlsocket);
- /* Remove the username we (maybe) added above */
- pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
- return RLM_MODULE_FAIL;
- } else {
- profile_found = 1;
- }
- }
- }
+ * Check for a default_profile or for a User-Profile.
+ */
+ user_profile = pairfind(request->config_items, PW_USER_PROFILE, 0, TAG_ANY);
+
+ const char *profile = user_profile ?
+ user_profile->vp_strvalue :
+ inst->config->default_profile;
+
+ if (!profile || !*profile)
+ goto release;
+
+ RDEBUG("Checking profile %s", profile);
+
+ if (sql_set_user(inst, request, profile) < 0) {
+ radlog_request(L_ERR, 0, request, "Error setting profile; rejecting user");
- if (profile_found) {
- rows = rlm_sql_process_groups(inst, request, sqlsocket, &dofallthrough);
- if (rows < 0) {
- radlog_request(L_ERR, 0, request, "Error processing profile groups; rejecting user");
- sql_release_socket(inst, sqlsocket);
- /* Remove the username we (maybe) added above */
- pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
- return RLM_MODULE_FAIL;
- } else if (rows > 0) {
- found = 1;
- }
+ goto error;
}
- }
-
- /* Remove the username we (maybe) added above */
- pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
- sql_release_socket(inst, sqlsocket);
+
+ rows = rlm_sql_process_groups(inst, request, handle, &dofallthrough);
+ if (rows < 0) {
+ radlog_request(L_ERR, 0, request, "Error processing profile groups; rejecting user");
- if (!found) {
- RDEBUG("User %s not found", sqlusername);
- return RLM_MODULE_NOTFOUND;
- } else {
- return RLM_MODULE_OK;
+ goto error;
+ }
+
+ if (rows > 0)
+ ret = RLM_MODULE_OK;
}
+
+ goto release;
+
+ error:
+ ret = RLM_MODULE_FAIL;
+
+ release:
+ sql_release_socket(inst, handle);
+
+ pairfree(&check_tmp);
+ pairfree(&reply_tmp);
+
+ return ret;
}
/*
- * Accounting: save the account data to our sql table
+ * Generic function for failing between a bunch of queries.
+ *
+ * Uses the same principle as rlm_linelog, expanding the 'reference' config
+ * item using xlat to figure out what query it should execute.
+ *
+ * If the reference matches multiple config items, and a query fails or
+ * doesn't update any rows, the next matching config item is used.
+ *
*/
-static int rlm_sql_accounting(void *instance, REQUEST * request) {
-
- SQLSOCK *sqlsocket = NULL;
- VALUE_PAIR *pair;
- SQL_INST *inst = instance;
+static int acct_redundant(rlm_sql_t *inst, REQUEST *request,
+ sql_acct_section_t *section)
+{
int ret = RLM_MODULE_OK;
- int numaffected = 0;
- int acctstatustype = 0;
- char querystr[MAX_QUERY_LEN];
- char logstr[MAX_QUERY_LEN];
- char sqlusername[MAX_STRING_LEN];
-#ifdef CISCO_ACCOUNTING_HACK
- int acctsessiontime = 0;
-#endif
+ rlm_sql_handle_t *handle = NULL;
+ int sql_ret;
+ int numaffected = 0;
+
+ CONF_ITEM *item;
+ CONF_PAIR *pair;
+ const char *attr = NULL;
+ const char *value;
+
+ char path[MAX_STRING_LEN];
+ char querystr[MAX_QUERY_LEN];
+
+ char *p = path;
+
+ rad_assert(section);
+
+ if (section->reference[0] != '.')
+ *p++ = '.';
+
+ if (!radius_xlat(p, (sizeof(path) - (p - path)) - 1,
+ section->reference, request, NULL, NULL))
+ return RLM_MODULE_FAIL;
- memset(querystr, 0, MAX_QUERY_LEN);
+ item = cf_reference_item(NULL, section->cs, path);
+ if (!item)
+ return RLM_MODULE_FAIL;
- /*
- * Find the Acct Status Type
- */
- if ((pair = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE)) != NULL) {
- acctstatustype = pair->vp_integer;
- } else {
- radius_xlat(logstr, sizeof(logstr), "packet has no accounting status type. [user '%{User-Name}', nas '%{NAS-IP-Address}']", request, NULL);
- radlog_request(L_ERR, 0, request, "%s", logstr);
- return RLM_MODULE_INVALID;
+ if (cf_item_is_section(item)){
+ radlog(L_ERR, "Sections are not supported as references");
+
+ return RLM_MODULE_FAIL;
}
+
+ pair = cf_itemtopair(item);
+ attr = cf_pair_attr(pair);
+
+ RDEBUG2("Using query template '%s'", attr);
+
+ handle = sql_get_socket(inst);
+ if (handle == NULL)
+ return RLM_MODULE_FAIL;
+
+ sql_set_user(inst, request, NULL);
+
+ while (TRUE) {
+ value = cf_pair_value(pair);
+ if (!value) {
+ RDEBUG("Ignoring null query");
+ ret = RLM_MODULE_NOOP;
+
+ goto release;
+ }
+
+ radius_xlat(querystr, sizeof(querystr), value, request,
+ sql_escape_func, inst);
+ if (!*querystr) {
+ RDEBUG("Ignoring null query");
+ ret = RLM_MODULE_NOOP;
+
+ goto release;
+ }
+
+ rlm_sql_query_log(inst, request, section, querystr);
+
+ /*
+ * If rlm_sql_query cannot use the socket it'll try and
+ * reconnect. Reconnecting will automatically release
+ * the current socket, and try to select a new one.
+ *
+ * If we get SQL_DOWN it means all connections in the pool
+ * were exhausted, and we couldn't create a new connection,
+ * so we do not need to call sql_release_socket.
+ */
+ sql_ret = rlm_sql_query(&handle, inst, querystr);
+ if (sql_ret == SQL_DOWN)
+ return RLM_MODULE_FAIL;
+
+ rad_assert(handle);
+
+ /*
+ * Assume all other errors are incidental, and just meant our
+ * operation failed and its not a client or SQL syntax error.
+ */
+ if (sql_ret == 0) {
+ numaffected = (inst->module->sql_affected_rows)
+ (handle, inst->config);
+ if (numaffected > 0)
+ break;
+
+ RDEBUG("No records updated");
+ }
- switch (acctstatustype) {
- /*
- * The Terminal server informed us that it was rebooted
- * STOP all records from this NAS
- */
- case PW_STATUS_ACCOUNTING_ON:
- case PW_STATUS_ACCOUNTING_OFF:
- RDEBUG("Received Acct On/Off packet");
- radius_xlat(querystr, sizeof(querystr), inst->config->accounting_onoff_query, request, sql_escape_func);
- query_log(request, inst, querystr);
-
- sqlsocket = sql_get_socket(inst);
- if (sqlsocket == NULL)
- return(RLM_MODULE_FAIL);
- if (*querystr) { /* non-empty query */
- if (rlm_sql_query(sqlsocket, inst, querystr)) {
- radlog_request(L_ERR, 0, request, "Couldn't update SQL accounting for Acct On/Off packet - %s",
- (inst->module->sql_error)(sqlsocket, inst->config));
- ret = RLM_MODULE_FAIL;
- }
- (inst->module->sql_finish_query)(sqlsocket, inst->config);
- }
-
- break;
-
- /*
- * Got an update accounting packet
- */
- case PW_STATUS_ALIVE:
-
- /*
- * Set, escape, and check the user attr here
- */
- sql_set_user(inst, request, sqlusername, NULL);
-
- radius_xlat(querystr, sizeof(querystr), inst->config->accounting_update_query, request, sql_escape_func);
- query_log(request, inst, querystr);
-
- sqlsocket = sql_get_socket(inst);
- if (sqlsocket == NULL)
- return(RLM_MODULE_FAIL);
- if (*querystr) { /* non-empty query */
- if (rlm_sql_query(sqlsocket, inst, querystr)) {
- radlog_request(L_ERR, 0, request, "Couldn't update SQL accounting ALIVE record - %s",
- (inst->module->sql_error)(sqlsocket, inst->config));
- ret = RLM_MODULE_FAIL;
- }
- else {
- numaffected = (inst->module->sql_affected_rows)(sqlsocket, inst->config);
- if (numaffected < 1) {
-
- /*
- * If our update above didn't match anything
- * we assume it's because we haven't seen a
- * matching Start record. So we have to
- * insert this update rather than do an update
- */
- radius_xlat(querystr, sizeof(querystr), inst->config->accounting_update_query_alt, request, sql_escape_func);
- query_log(request, inst, querystr);
- if (*querystr) { /* non-empty query */
- if (rlm_sql_query(sqlsocket, inst, querystr)) {
- radlog_request(L_ERR, 0, request, "Couldn't insert SQL accounting ALIVE record - %s",
- (inst->module->sql_error)(sqlsocket, inst->config));
- ret = RLM_MODULE_FAIL;
- }
- (inst->module->sql_finish_query)(sqlsocket, inst->config);
- }
- }
- }
- (inst->module->sql_finish_query)(sqlsocket, inst->config);
- }
- break;
-
- /*
- * Got accounting start packet
- */
- case PW_STATUS_START:
-
- /*
- * Set, escape, and check the user attr here
- */
- sql_set_user(inst, request, sqlusername, NULL);
-
- radius_xlat(querystr, sizeof(querystr), inst->config->accounting_start_query, request, sql_escape_func);
- query_log(request, inst, querystr);
-
- sqlsocket = sql_get_socket(inst);
- if (sqlsocket == NULL)
- return(RLM_MODULE_FAIL);
- if (*querystr) { /* non-empty query */
- if (rlm_sql_query(sqlsocket, inst, querystr)) {
- radlog_request(L_ERR, 0, request, "Couldn't insert SQL accounting START record - %s",
- (inst->module->sql_error)(sqlsocket, inst->config));
-
- /*
- * We failed the insert above. It's probably because
- * the stop record came before the start. We try
- * our alternate query now (typically an UPDATE)
- */
- radius_xlat(querystr, sizeof(querystr), inst->config->accounting_start_query_alt, request, sql_escape_func);
- query_log(request, inst, querystr);
-
- if (*querystr) { /* non-empty query */
- if (rlm_sql_query(sqlsocket, inst, querystr)) {
- radlog_request(L_ERR, 0, request, "Couldn't update SQL accounting START record - %s",
- (inst->module->sql_error)(sqlsocket, inst->config));
- ret = RLM_MODULE_FAIL;
- }
- (inst->module->sql_finish_query)(sqlsocket, inst->config);
- }
- }
- (inst->module->sql_finish_query)(sqlsocket, inst->config);
- }
- break;
-
- /*
- * Got accounting stop packet
- */
- case PW_STATUS_STOP:
+ (inst->module->sql_finish_query)(handle, inst->config);
+
+ /*
+ * We assume all entries with the same name form a redundant
+ * set of queries.
+ */
+ pair = cf_pair_find_next(section->cs, pair, attr);
+
+ if (!pair) {
+ RDEBUG("No additional queries configured");
+
+ ret = RLM_MODULE_NOOP;
+
+ goto release;
+ }
- /*
- * Set, escape, and check the user attr here
- */
- sql_set_user(inst, request, sqlusername, NULL);
-
- radius_xlat(querystr, sizeof(querystr), inst->config->accounting_stop_query, request, sql_escape_func);
- query_log(request, inst, querystr);
-
- sqlsocket = sql_get_socket(inst);
- if (sqlsocket == NULL)
- return(RLM_MODULE_FAIL);
- if (*querystr) { /* non-empty query */
- if (rlm_sql_query(sqlsocket, inst, querystr)) {
- radlog_request(L_ERR, 0, request, "Couldn't update SQL accounting STOP record - %s",
- (inst->module->sql_error)(sqlsocket, inst->config));
- ret = RLM_MODULE_FAIL;
- }
- else {
- numaffected = (inst->module->sql_affected_rows)(sqlsocket, inst->config);
- if (numaffected < 1) {
- /*
- * If our update above didn't match anything
- * we assume it's because we haven't seen a
- * matching Start record. So we have to
- * insert this stop rather than do an update
- */
-#ifdef CISCO_ACCOUNTING_HACK
- /*
- * If stop but zero session length AND no previous
- * session found, drop it as in invalid packet
- * This is to fix CISCO's aaa from filling our
- * table with bogus crap
- */
- if ((pair = pairfind(request->packet->vps, PW_ACCT_SESSION_TIME)) != NULL)
- acctsessiontime = pair->vp_integer;
-
- if (acctsessiontime <= 0) {
- radius_xlat(logstr, sizeof(logstr), "stop packet with zero session length. [user '%{User-Name}', nas '%{NAS-IP-Address}']", request, NULL);
- radlog_request(L_ERR, 0, request, "%s", logstr);
- sql_release_socket(inst, sqlsocket);
- ret = RLM_MODULE_NOOP;
- }
-#endif
+ RDEBUG("Trying next query...");
+ }
+
+ (inst->module->sql_finish_query)(handle, inst->config);
- radius_xlat(querystr, sizeof(querystr), inst->config->accounting_stop_query_alt, request, sql_escape_func);
- query_log(request, inst, querystr);
+ release:
+ sql_release_socket(inst, handle);
- if (*querystr) { /* non-empty query */
- if (rlm_sql_query(sqlsocket, inst, querystr)) {
- radlog_request(L_ERR, 0, request, "Couldn't insert SQL accounting STOP record - %s",
+ return ret;
+}
- (inst->module->sql_error)(sqlsocket, inst->config));
- ret = RLM_MODULE_FAIL;
- }
- (inst->module->sql_finish_query)(sqlsocket, inst->config);
- }
- }
- }
- (inst->module->sql_finish_query)(sqlsocket, inst->config);
- }
- break;
+#ifdef WITH_ACCOUNTING
- /*
- * Anything else is ignored.
- */
- default:
- RDEBUG("Unsupported Acct-Status-Type = %d",
- acctstatustype);
- return RLM_MODULE_NOOP;
- break;
+/*
+ * Accounting: Insert or update session data in our sql table
+ */
+static rlm_rcode_t rlm_sql_accounting(void *instance, REQUEST * request) {
+ rlm_sql_t *inst = instance;
+ if (inst->config->accounting) {
+ return acct_redundant(inst, request, inst->config->accounting);
}
-
- sql_release_socket(inst, sqlsocket);
-
- return ret;
+
+ return RLM_MODULE_NOOP;
}
+#endif
+#ifdef WITH_SESSION_MGMT
/*
* See if a user is already logged in. Sets request->simul_count to the
* current session count for this user.
* logins by querying the terminal server (using eg. SNMP).
*/
-static int rlm_sql_checksimul(void *instance, REQUEST * request) {
- SQLSOCK *sqlsocket;
- SQL_INST *inst = instance;
- SQL_ROW row;
+static rlm_rcode_t rlm_sql_checksimul(void *instance, REQUEST * request) {
+ rlm_sql_handle_t *handle;
+ rlm_sql_t *inst = instance;
+ rlm_sql_row_t row;
char querystr[MAX_QUERY_LEN];
- char sqlusername[MAX_STRING_LEN];
int check = 0;
uint32_t ipno = 0;
char *call_num = NULL;
}
if((request->username == NULL) || (request->username->length == 0)) {
- radlog_request(L_ERR, 0, request, "Zero Length username not permitted\n");
+ radlog_request(L_ERR, 0, request,
+ "Zero Length username not permitted\n");
return RLM_MODULE_INVALID;
}
- if(sql_set_user(inst, request, sqlusername, NULL) < 0)
+ if(sql_set_user(inst, request, NULL) < 0)
return RLM_MODULE_FAIL;
- radius_xlat(querystr, sizeof(querystr), inst->config->simul_count_query, request, sql_escape_func);
+ radius_xlat(querystr, sizeof(querystr), inst->config->simul_count_query, request, sql_escape_func, inst);
/* initialize the sql socket */
- sqlsocket = sql_get_socket(inst);
- if(sqlsocket == NULL)
+ handle = sql_get_socket(inst);
+ if(handle == NULL)
return RLM_MODULE_FAIL;
- if(rlm_sql_select_query(sqlsocket, inst, querystr)) {
- radlog(L_ERR, "rlm_sql (%s) sql_checksimul: Database query failed", inst->config->xlat_name);
- sql_release_socket(inst, sqlsocket);
+ if(rlm_sql_select_query(&handle, inst, querystr)) {
+ sql_release_socket(inst, handle);
return RLM_MODULE_FAIL;
}
- ret = rlm_sql_fetch_row(sqlsocket, inst);
-
+ ret = rlm_sql_fetch_row(&handle, inst);
if (ret != 0) {
- (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
- sql_release_socket(inst, sqlsocket);
+ (inst->module->sql_finish_select_query)(handle, inst->config);
+ sql_release_socket(inst, handle);
return RLM_MODULE_FAIL;
}
- row = sqlsocket->row;
+ row = handle->row;
if (row == NULL) {
- (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
- sql_release_socket(inst, sqlsocket);
+ (inst->module->sql_finish_select_query)(handle, inst->config);
+ sql_release_socket(inst, handle);
return RLM_MODULE_FAIL;
}
request->simul_count = atoi(row[0]);
- (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
+ (inst->module->sql_finish_select_query)(handle, inst->config);
if(request->simul_count < request->simul_max) {
- sql_release_socket(inst, sqlsocket);
+ sql_release_socket(inst, handle);
return RLM_MODULE_OK;
}
*/
if (!inst->config->simul_verify_query ||
(inst->config->simul_verify_query[0] == '\0')) {
- sql_release_socket(inst, sqlsocket);
+ sql_release_socket(inst, handle);
return RLM_MODULE_OK;
}
- radius_xlat(querystr, sizeof(querystr), inst->config->simul_verify_query, request, sql_escape_func);
- if(rlm_sql_select_query(sqlsocket, inst, querystr)) {
- radlog_request(L_ERR, 0, request, "Database query error");
- sql_release_socket(inst, sqlsocket);
+ radius_xlat(querystr, sizeof(querystr), inst->config->simul_verify_query, request, sql_escape_func, inst);
+ if(rlm_sql_select_query(&handle, inst, querystr)) {
+ sql_release_socket(inst, handle);
return RLM_MODULE_FAIL;
}
*/
request->simul_count = 0;
- if ((vp = pairfind(request->packet->vps, PW_FRAMED_IP_ADDRESS)) != NULL)
+ if ((vp = pairfind(request->packet->vps, PW_FRAMED_IP_ADDRESS, 0, TAG_ANY)) != NULL)
ipno = vp->vp_ipaddr;
- if ((vp = pairfind(request->packet->vps, PW_CALLING_STATION_ID)) != NULL)
+ if ((vp = pairfind(request->packet->vps, PW_CALLING_STATION_ID, 0, TAG_ANY)) != NULL)
call_num = vp->vp_strvalue;
- while (rlm_sql_fetch_row(sqlsocket, inst) == 0) {
- row = sqlsocket->row;
+ while (rlm_sql_fetch_row(&handle, inst) == 0) {
+ row = handle->row;
if (row == NULL)
break;
if (!row[2]){
- (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
- sql_release_socket(inst, sqlsocket);
+ (inst->module->sql_finish_select_query)(handle, inst->config);
+ sql_release_socket(inst, handle);
RDEBUG("Cannot zap stale entry. No username present in entry.", inst->config->xlat_name);
return RLM_MODULE_FAIL;
}
if (!row[1]){
- (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
- sql_release_socket(inst, sqlsocket);
+ (inst->module->sql_finish_select_query)(handle, inst->config);
+ sql_release_socket(inst, handle);
RDEBUG("Cannot zap stale entry. No session id in entry.", inst->config->xlat_name);
return RLM_MODULE_FAIL;
}
* Failed to check the terminal server for
* duplicate logins: return an error.
*/
- (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
- sql_release_socket(inst, sqlsocket);
+ (inst->module->sql_finish_select_query)(handle, inst->config);
+ sql_release_socket(inst, handle);
radlog_request(L_ERR, 0, request, "Failed to check the terminal server for user '%s'.", row[2]);
return RLM_MODULE_FAIL;
}
}
- (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
- sql_release_socket(inst, sqlsocket);
+ (inst->module->sql_finish_select_query)(handle, inst->config);
+ sql_release_socket(inst, handle);
/*
* The Auth module apparently looks at request->simul_count,
*/
return RLM_MODULE_OK;
}
+#endif
/*
- * Execute postauth_query after authentication
+ * Postauth: Write a record of the authentication attempt
*/
-static int rlm_sql_postauth(void *instance, REQUEST *request) {
- SQLSOCK *sqlsocket = NULL;
- SQL_INST *inst = instance;
- char querystr[MAX_QUERY_LEN];
- char sqlusername[MAX_STRING_LEN];
-
- if(sql_set_user(inst, request, sqlusername, NULL) < 0)
- return RLM_MODULE_FAIL;
-
- /* If postauth_query is not defined, we stop here */
- if (!inst->config->postauth_query ||
- (inst->config->postauth_query[0] == '\0'))
- return RLM_MODULE_NOOP;
-
- /* Expand variables in the query */
- memset(querystr, 0, MAX_QUERY_LEN);
- radius_xlat(querystr, sizeof(querystr), inst->config->postauth_query,
- request, sql_escape_func);
- query_log(request, inst, querystr);
- DEBUG2("rlm_sql (%s) in sql_postauth: query is %s",
- inst->config->xlat_name, querystr);
-
- /* Initialize the sql socket */
- sqlsocket = sql_get_socket(inst);
- if (sqlsocket == NULL)
- return RLM_MODULE_FAIL;
-
- /* Process the query */
- if (rlm_sql_query(sqlsocket, inst, querystr)) {
- radlog(L_ERR, "rlm_sql (%s) in sql_postauth: Database query error - %s",
- inst->config->xlat_name,
- (inst->module->sql_error)(sqlsocket, inst->config));
- sql_release_socket(inst, sqlsocket);
- return RLM_MODULE_FAIL;
+static rlm_rcode_t rlm_sql_postauth(void *instance, REQUEST * request) {
+ rlm_sql_t *inst = instance;
+
+ if (inst->config->postauth) {
+ return acct_redundant(inst, request, inst->config->postauth);
}
- (inst->module->sql_finish_query)(sqlsocket, inst->config);
-
- sql_release_socket(inst, sqlsocket);
- return RLM_MODULE_OK;
+
+ return RLM_MODULE_NOOP;
}
+/*
+ * Execute postauth_query after authentication
+ */
+
+
/* globally exported name */
module_t rlm_sql = {
RLM_MODULE_INIT,
NULL, /* authentication */
rlm_sql_authorize, /* authorization */
NULL, /* preaccounting */
+#ifdef WITH_ACCOUNTING
rlm_sql_accounting, /* accounting */
+#else
+ NULL,
+#endif
+#ifdef WITH_SESSION_MGMT
rlm_sql_checksimul, /* checksimul */
+#else
+ NULL,
+#endif
NULL, /* pre-proxy */
NULL, /* post-proxy */
rlm_sql_postauth /* post-auth */