⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rlm_sql.c

📁 freeradius-server-2.1.3.tar.gz安装源文件
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * 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 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * 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 <freeradius-devel/radiusd.h>#include <freeradius-devel/modules.h>#include <freeradius-devel/rad_assert.h>#include <ltdl.h>#include <sys/stat.h>#include "rlm_sql.h"static char *allowed_chars = 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, ""},	{"login", PW_TYPE_STRING_PTR,	 offsetof(SQL_CONFIG,sql_login), NULL, ""},	{"password", PW_TYPE_STRING_PTR,	 offsetof(SQL_CONFIG,sql_password), NULL, ""},	{"radius_db", PW_TYPE_STRING_PTR,	 offsetof(SQL_CONFIG,sql_db), NULL, "radius"},	{"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},	{"readclients", PW_TYPE_BOOLEAN,	 offsetof(SQL_CONFIG,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"},	{"sql_user_name", PW_TYPE_STRING_PTR,	 offsetof(SQL_CONFIG,query_user), NULL, ""},	{"default_user_profile", PW_TYPE_STRING_PTR,	 offsetof(SQL_CONFIG,default_profile), NULL, ""},	{"nas_query", PW_TYPE_STRING_PTR,	 offsetof(SQL_CONFIG,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, ""},	{"authorize_reply_query", PW_TYPE_STRING_PTR,	 offsetof(SQL_CONFIG,authorize_reply_query), NULL, NULL},	{"authorize_group_check_query", PW_TYPE_STRING_PTR,	 offsetof(SQL_CONFIG,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, ""},	{"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"},	{"simul_count_query", PW_TYPE_STRING_PTR,	 offsetof(SQL_CONFIG,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, ""},	{"safe-characters", PW_TYPE_STRING_PTR,	 offsetof(SQL_CONFIG,allowed_chars), NULL,	"@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"},	{NULL, -1, 0, NULL, NULL}};/* *	Fall-Through checking function from rlm_files.c */static int fallthrough(VALUE_PAIR *vp){	VALUE_PAIR *tmp;	tmp = pairfind(vp, PW_FALL_THROUGH);	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);/* *	sql xlat function. Right now only SELECTs are supported. Only *	the first element of the SELECT result will be used. */static int sql_xlat(void *instance, REQUEST *request,		    char *fmt, char *out, size_t freespace,		    UNUSED RADIUS_ESCAPE_STRING func){	SQLSOCK *sqlsocket;	SQL_ROW row;	SQL_INST *inst = instance;	char querystr[MAX_QUERY_LEN];	char sqlusername[MAX_STRING_LEN];	size_t ret = 0;	RDEBUG("sql_xlat");	/*         * Add SQL-User-Name attribute just in case it is needed         *  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);	/*	 * Do an xlat on the provided string (nice recursive operation).	 */	if (!radius_xlat(querystr, sizeof(querystr), fmt, request, sql_escape_func)) {		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)		return 0;	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);		return 0;	}	ret = rlm_sql_fetch_row(sqlsocket, inst);	if (ret) {		RDEBUG("SQL query did not succeed");		(inst->module->sql_finish_select_query)(sqlsocket, inst->config);		sql_release_socket(inst,sqlsocket);		return 0;	}	row = sqlsocket->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);		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);		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);		return 0;	}	strlcpy(out,row[0],freespace);	RDEBUG("sql_xlat finished");	(inst->module->sql_finish_select_query)(sqlsocket, inst->config);	sql_release_socket(inst,sqlsocket);	return ret;}static int generate_sql_clients(SQL_INST *inst){	SQLSOCK *sqlsocket;	SQL_ROW row;	char querystr[MAX_QUERY_LEN];	RADCLIENT *c;	char *prefix_ptr = NULL;	unsigned int i = 0;	int numf = 0;	DEBUG("rlm_sql (%s): Processing generate_sql_clients",	      inst->config->xlat_name);	/* NAS query isn't xlat'ed */	strlcpy(querystr, inst->config->nas_query, sizeof(querystr));	DEBUG("rlm_sql (%s) in generate_sql_clients: query is %s",	      inst->config->xlat_name, querystr);	sqlsocket = sql_get_socket(inst);	if (sqlsocket == 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);		return -1;	}	while(rlm_sql_fetch_row(sqlsocket, inst) == 0) {		i++;		row = sqlsocket->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)	 */		if (!row[0]){			radlog(L_ERR, "rlm_sql (%s): No row id found on pass %d",inst->config->xlat_name,i);			continue;		}		if (!row[1]){			radlog(L_ERR, "rlm_sql (%s): No nasname found for row %s",inst->config->xlat_name,row[0]);			continue;		}		if (!row[2]){			radlog(L_ERR, "rlm_sql (%s): No short name found for row %s",inst->config->xlat_name,row[0]);			continue;		}		if (!row[4]){			radlog(L_ERR, "rlm_sql (%s): No secret found for row %s",inst->config->xlat_name,row[0]);			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));#ifdef WITH_DYNAMIC_CLIENTS		c->dynamic = 1;#endif		/*		 *	Look for prefixes		 */		c->prefix = -1;		prefix_ptr = strchr(row[1], '/');		if (prefix_ptr) {			c->prefix = atoi(prefix_ptr + 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);				continue;			}			/* Replace '/' with '\0' */			*prefix_ptr = '\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",			       inst->config->xlat_name,			       row[1], fr_strerror());			free(c);			continue;		} else {			char buffer[256];			ip_ntoh(&c->ipaddr, buffer, sizeof(buffer));			c->longname = strdup(buffer);		}		if (c->prefix < 0) switch (c->ipaddr.af) {		case AF_INET:			c->prefix = 32;			break;		case AF_INET6:			c->prefix = 128;			break;		default:			break;		}		/*		 *	Other values (secret, shortname, nastype, virtual_server)		 */		c->secret = strdup(row[4]);		c->shortname = strdup(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]);		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)) {			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);			client_free(c);			return -1;		}	}	(inst->module->sql_finish_select_query)(sqlsocket, inst->config);	sql_release_socket(inst, sqlsocket);	return 0;}/* *	Translate the SQL queries. */static size_t sql_escape_func(char *out, size_t outlen, const char *in){	size_t len = 0;	while (in[0]) {		/*		 *	Non-printable characters get replaced with their		 *	mime-encoded equivalents.		 */		if ((in[0] < 32) ||		    strchr(allowed_chars, *in) == NULL) {			/*			 *	Only 3 or less bytes available.			 */			if (outlen <= 3) {				break;			}			snprintf(out, outlen, "=%02X", (unsigned char) in[0]);			in++;			out += 3;			outlen -= 3;			len += 3;			continue;		}		/*		 *	Only one byte left.		 */		if (outlen <= 1) {			break;		}		/*		 *	Allowed character.		 */		*out = *in;		out++;		in++;		outlen--;		len++;	}	*out = '\0';	return len;}/* *	Set the SQL user name. * *	We don't call the escape function here. The resulting string *	will be escaped later in the queries xlat so we don't need to *	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){	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);	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);	} 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());		return -1;	}	strlcpy(vp->vp_strvalue, tmpuser, sizeof(vp->vp_strvalue));	vp->length = strlen(vp->vp_strvalue);	return 0;}static void sql_grouplist_free (SQL_GROUPLIST **group_list){	SQL_GROUPLIST *last;	while(*group_list) {		last = *group_list;		*group_list = (*group_list)->next;		free(last);	}}static int sql_get_grouplist (SQL_INST *inst, SQLSOCK *sqlsocket, REQUEST *request, SQL_GROUPLIST **group_list){	char    querystr[MAX_QUERY_LEN];	int     num_groups = 0;	SQL_ROW row;	SQL_GROUPLIST   *group_list_tmp;	/* NOTE: sql_set_user should have been run before calling this function */	group_list_tmp = *group_list = NULL;	if (!inst->config->groupmemb_query ||	    (inst->config->groupmemb_query[0] == 0))		return 0;	if (!radius_xlat(querystr, sizeof(querystr), inst->config->groupmemb_query, request, sql_escape_func)) {		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));		return -1;	}	while (rlm_sql_fetch_row(sqlsocket, inst) == 0) {		row = sqlsocket->row;		if (row == NULL)			break;		if (row[0] == NULL){			RDEBUG("row[0] returned NULL");			(inst->module->sql_finish_select_query)(sqlsocket, inst->config);			sql_grouplist_free(group_list);			return -1;		}		if (*group_list == NULL) {			*group_list = rad_malloc(sizeof(SQL_GROUPLIST));			group_list_tmp = *group_list;		} else {			group_list_tmp->next = rad_malloc(sizeof(SQL_GROUPLIST));			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);	return num_groups;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -