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

📄 rlm_sql.c

📁 RADIUS 服务器介绍 RADIUS服务器支持标准的RADIUS协议
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * rlm_sql.c		SQL Module * 		Main SQL module file. Most ICRADIUS code is located in sql.c * * Version:	$Id: rlm_sql.c,v 1.116 2003/07/04 19:16:12 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 2000  The FreeRADIUS server project * Copyright 2000  Mike Machado <mike@innercite.com> * Copyright 2000  Alan DeKok <aland@ox.org> */static const char rcsid[] =	"$Id: rlm_sql.c,v 1.116 2003/07/04 19:16:12 aland Exp $";#include "autoconf.h"#include <stdio.h>#include <sys/stat.h>#include <stdlib.h>#include <time.h>#include <unistd.h>#include <sys/types.h>#include <sys/wait.h>#include <string.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include "radiusd.h"#include "modules.h"#include "conffile.h"#include "rlm_sql.h"#include "rad_assert.h"static 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"},	{"acct_table", PW_TYPE_STRING_PTR, offsetof(SQL_CONFIG,sql_acct_table), NULL, "radacct"},	{"acct_table2", PW_TYPE_STRING_PTR, offsetof(SQL_CONFIG,sql_acct_table2), NULL, "radacct"},	{"authcheck_table", PW_TYPE_STRING_PTR, offsetof(SQL_CONFIG,sql_authcheck_table), NULL, "radcheck"},	{"authreply_table", PW_TYPE_STRING_PTR, offsetof(SQL_CONFIG,sql_authreply_table), NULL, "radreply"},	{"groupcheck_table", PW_TYPE_STRING_PTR, offsetof(SQL_CONFIG,sql_groupcheck_table), NULL, "radgroupcheck"},	{"groupreply_table", PW_TYPE_STRING_PTR, offsetof(SQL_CONFIG,sql_groupreply_table), NULL, "radgroupreply"},	{"usergroup_table", PW_TYPE_STRING_PTR, offsetof(SQL_CONFIG,sql_usergroup_table), NULL, "usergroup"},	{"nas_table", PW_TYPE_STRING_PTR, offsetof(SQL_CONFIG,sql_nas_table), NULL, "nas"},	{"dict_table", PW_TYPE_STRING_PTR, offsetof(SQL_CONFIG,sql_dict_table), NULL, "dictionary"},	{"sqltrace", PW_TYPE_BOOLEAN, offsetof(SQL_CONFIG,sqltrace), NULL, "no"},	{"sqltracefile", PW_TYPE_STRING_PTR, offsetof(SQL_CONFIG,tracefile), NULL, SQLTRACEFILE},	{"deletestalesessions", PW_TYPE_BOOLEAN, offsetof(SQL_CONFIG,deletestalesessions), NULL, "no"},	{"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, ""},	{"query_on_not_found", PW_TYPE_BOOLEAN, offsetof(SQL_CONFIG,query_on_not_found), NULL, "no"},	{"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, ""},	{"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_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, ""},	{"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, ""},	{NULL, -1, 0, NULL, NULL}};/*********************************************************************** * start of main routines ***********************************************************************/static int rlm_sql_init(void) {	/*	 * FIXME:	 * We should put the sqlsocket array here once	 * the module code is reworked to not unload	 * modules on HUP.  This way we can have	 * persistant connections.  -jcarneal	 */	return 0;}/* *	Yucky prototype. */static int sql_set_user(SQL_INST *inst, REQUEST *request, char *sqlusername, const char *username);/* *	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, int freespace,		    RADIUS_ESCAPE_STRING func){	SQLSOCK *sqlsocket;	SQL_ROW row;	SQL_INST *inst = instance;	char querystr[MAX_QUERY_LEN];	char sqlusername[2 * MAX_STRING_LEN + 10];	int ret = 0;	DEBUG("rlm_sql (%s): - sql_xlat", inst->config->xlat_name);	/*         * 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, 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,		       (char *)(inst->module->sql_error)(sqlsocket, inst->config));		sql_release_socket(inst,sqlsocket);		return 0;	}	ret = rlm_sql_fetch_row(sqlsocket, inst);	if (ret) {		DEBUG("rlm_sql (%s): SQL query did not succeed",		      inst->config->xlat_name);		(inst->module->sql_finish_select_query)(sqlsocket, inst->config);		sql_release_socket(inst,sqlsocket);		return 0;	}	row = sqlsocket->row;	if (row == NULL) {		DEBUG("rlm_sql (%s): SQL query did not return any results",		      inst->config->xlat_name);		(inst->module->sql_finish_select_query)(sqlsocket, inst->config);		sql_release_socket(inst,sqlsocket);		return 0;	}	if (row[0] == NULL){		DEBUG("rlm_sql (%s): row[0] returned NULL",		      inst->config->xlat_name);		(inst->module->sql_finish_select_query)(sqlsocket, inst->config);		sql_release_socket(inst,sqlsocket);		return 0;	}	ret = strlen(row[0]);	if (ret > freespace){		DEBUG("rlm_sql (%s): sql_xlat:: Insufficient string space",		      inst->config->xlat_name);		(inst->module->sql_finish_select_query)(sqlsocket, inst->config);		sql_release_socket(inst,sqlsocket);		return 0;	}	strncpy(out,row[0],ret);	DEBUG("rlm_sql (%s): - sql_xlat finished",	      inst->config->xlat_name);	(inst->module->sql_finish_select_query)(sqlsocket, inst->config);	sql_release_socket(inst,sqlsocket);	return ret;}/* *	Translate the SQL queries. */static int sql_escape_func(char *out, int outlen, const char *in){	int len = 0;		while (in[0]) {		/*		 *  Only one byte left.		 */		if (outlen <= 1) {			break;		}				/*		 *	Non-printable characters get replaced with their		 *	mime-encoded equivalents.		 */		if ((in[0] < 32) ||		    strchr("@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: =/", *in) == NULL) {			snprintf(out, outlen, "=%02X", (unsigned char) in[0]);			in++;			out += 3;			outlen -= 3;			len += 3;			continue;		}				/*		 *	Else it's a nice character.		 */		*out = *in;		out++;		in++;		outlen--;		len++;	}	*out = '\0';	return len;}/* *	Set the SQl user name. */static 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) {		strNcpy(tmpuser, username, MAX_STRING_LEN);	} else if (strlen(inst->config->query_user)) {		radius_xlat(tmpuser, sizeof(tmpuser), inst->config->query_user, request, sql_escape_func);	} else {		return 0;	}	if (*tmpuser) {		strNcpy(sqlusername, tmpuser, sizeof(tmpuser));		DEBUG2("rlm_sql (%s): sql_set_user escaped user --> '%s'",		       inst->config->xlat_name, sqlusername);		vp = pairmake("SQL-User-Name", sqlusername, 0);		if (vp == NULL) {			radlog(L_ERR, "%s", librad_errstr);			return -1;		}		pairadd(&request->packet->vps, vp);		return 0;	}	return -1;}/* * sql groupcmp function. That way we can do group comparisons (in the users file for example) * with the group memberships reciding in sql * The group membership query should only return one element which is the username. The returned * username will then be checked with the passed check string. */static int sql_groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request, VALUE_PAIR *check,			VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs){	SQLSOCK *sqlsocket;	SQL_ROW row;	SQL_INST *inst = instance;	char querystr[MAX_QUERY_LEN];	char sqlusername[2 * MAX_STRING_LEN + 10];	check_pairs = check_pairs;	reply_pairs = reply_pairs;	DEBUG("rlm_sql (%s): - sql_groupcmp", inst->config->xlat_name);	if (!check || !check->strvalue || !check->length){		DEBUG("rlm_sql (%s): sql_groupcmp: Illegal group name",		      inst->config->xlat_name);		return 1;	}	if (req == NULL){		DEBUG("rlm_sql (%s): sql_groupcmp: NULL request",		      inst->config->xlat_name);		return 1;	}	if (inst->config->groupmemb_query[0] == 0)		return 1;	/*	 * Set, escape, and check the user attr here	 */	if (sql_set_user(inst, req, sqlusername, 0) < 0)		return 1;	if (!radius_xlat(querystr, sizeof(querystr), inst->config->groupmemb_query, req, NULL)){		radlog(L_ERR, "rlm_sql (%s): xlat failed.",		       inst->config->xlat_name);		/* Remove the username we (maybe) added above */		pairdelete(&req->packet->vps, PW_SQL_USER_NAME);		return 1;	}	/* Remove the username we (maybe) added above */	pairdelete(&req->packet->vps, PW_SQL_USER_NAME);	sqlsocket = sql_get_socket(inst);	if (sqlsocket == NULL)		return 1;	if ((inst->module->sql_select_query)(sqlsocket,inst->config,querystr) <0){		radlog(L_ERR, "rlm_sql (%s): database query error, %s: %s",		       inst->config->xlat_name,querystr,		       (char *)(inst->module->sql_error)(sqlsocket,inst->config));		sql_release_socket(inst,sqlsocket);		return 1;	}	while (rlm_sql_fetch_row(sqlsocket, inst) == 0) {		row = sqlsocket->row;		if (row == NULL)			break;

⌨️ 快捷键说明

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