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

📄 rlm_sql.c

📁 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.131.2.4 2005/08/31 12:49:52 nbk 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.131.2.4 2005/08/31 12:49:52 nbk 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 char *allowed_chars = NULL;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},	{"readclients", PW_TYPE_BOOLEAN,	 offsetof(SQL_CONFIG,do_clients), NULL, "no"},	{"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_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, ""},	{"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_table", PW_TYPE_STRING_PTR,	 offsetof(SQL_CONFIG,sql_postauth_table), NULL, "radpostauth"},	{"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}};/*********************************************************************** * 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);static int generate_sql_clients(SQL_INST *inst);static int sql_escape_func(char *out, int 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,		    RADIUS_ESCAPE_STRING func){	SQLSOCK *sqlsocket;	SQL_ROW row;	SQL_INST *inst = instance;	char querystr[MAX_QUERY_LEN];	char sqlusername[MAX_STRING_LEN];	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, 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,		       (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;}static int generate_sql_clients(SQL_INST *inst){	SQLSOCK *sqlsocket;	SQL_ROW row;	char querystr[MAX_QUERY_LEN];	RADCLIENT *c;	char *netmask;	unsigned int i = 0;		DEBUG("rlm_sql (%s): - generate_sql_clients",inst->config->xlat_name);	if (inst->config->sql_nas_table == NULL){		radlog(L_ERR, "rlm_sql (%s): sql_nas_table is NULL.",inst->config->xlat_name);		return -1;	}	snprintf(querystr,MAX_QUERY_LEN - 1,"SELECT * FROM %s",inst->config->sql_nas_table);	DEBUG("rlm_sql (%s): Query: %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,			(char *)(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;/* * Format: * Row1	Row2	Row3		Row4	Row5	Row6	Row7		Row8 * * id	nasname	shortname	type	ports	secret	community	description * */		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 (strlen(row[1]) >= sizeof(c->longname)){			radlog(L_ERR, "rlm_sql (%s): nasname of length %d is greater than the allowed maximum of %d",				inst->config->xlat_name,strlen(row[1]),sizeof(c->longname) - 1);			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 (strlen(row[2]) >= sizeof(c->shortname)){			radlog(L_ERR, "rlm_sql (%s): shortname of length %d is greater than the allowed maximum of %d",				inst->config->xlat_name,strlen(row[2]),sizeof(c->shortname) - 1);			continue;		}		if (row[3] && strlen(row[3]) >= sizeof(c->nastype)){			radlog(L_ERR, "rlm_sql (%s): nastype of length %d is greater than the allowed maximum of %d",				inst->config->xlat_name,strlen(row[3]),sizeof(c->nastype) - 1);			continue;		}		if (!row[5]){			radlog(L_ERR, "rlm_sql (%s): No secret found for row %s",inst->config->xlat_name,row[0]);			continue;		}		if (strlen(row[5]) >= sizeof(c->secret)){			radlog(L_ERR, "rlm_sql (%s): secret of length %d is greater than the allowed maximum of %d",				inst->config->xlat_name,strlen(row[5]),sizeof(c->secret) - 1);			continue;		}		DEBUG("rlm_sql (%s): Read entry nasname=%s,shortname=%s,secret=%s",inst->config->xlat_name,			row[1],row[2],row[5]);		c = rad_malloc(sizeof(RADCLIENT));		memset(c, 0, sizeof(RADCLIENT));		c->netmask = ~0;		netmask = strchr(row[1], '/');				/*		 *      Look for netmasks.		 */		c->netmask = ~0;		if (netmask) {			int mask_length;			mask_length = atoi(netmask + 1);			if ((mask_length < 0) || (mask_length > 32)) {				radlog(L_ERR, "rlm_sql (%s): Invalid value '%s' for IP network mask for nasname %s.",						inst->config->xlat_name, netmask + 1,row[1]);				free(c);				continue;			}			if (mask_length == 0) {				c->netmask = 0;			} else {				c->netmask = ~0 << (32 - mask_length);			}			*netmask = '\0';			c->netmask = htonl(c->netmask);		}		c->ipaddr = ip_getaddr(row[1]);		if (c->ipaddr == INADDR_NONE) {			radlog(L_CONS|L_ERR, "rlm_sql (%s): Failed to look up hostname %s",					inst->config->xlat_name, row[1]);			free(c);			continue;		}		/*		 *      Update the client name again...		 */		if (netmask) {			*netmask = '/';			c->ipaddr &= c->netmask;			strcpy(c->longname, row[1]);		} else {			ip_hostname(c->longname, sizeof(c->longname),					c->ipaddr);		}		strcpy((char *)c->secret, row[5]);		strcpy(c->shortname, row[2]);		if(row[3] != NULL)			strcpy(c->nastype, row[3]);		DEBUG("rlm_sql (%s): Adding client %s (%s) to clients list",inst->config->xlat_name,			c->longname,c->shortname);		c->next = mainconfig.clients;		mainconfig.clients = c;	}	(inst->module->sql_finish_select_query)(sqlsocket, inst->config);	sql_release_socket(inst, sqlsocket);	return 0;}/* *	Translate the SQL queries. */static int sql_escape_func(char *out, int outlen, const char *in){	int 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.

⌨️ 快捷键说明

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