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

📄 rlm_sql_log.c

📁 新的radius程序
💻 C
字号:
/* *  rlm_sql_log.c	Append the SQL queries in a log file which *			is read later by the radsqlrelay program * *  Version:    $Id: rlm_sql_log.c,v 1.3.2.2 2005/12/12 17:44:35 nbk Exp $ * *  Author:     Nicolas Baradakis <nicolas.baradakis@cegetel.net> * *  Copyright (C) 2005 Cegetel * *  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 */#include "autoconf.h"#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#include <sys/stat.h>#include "libradius.h"#include "radiusd.h"#include "modules.h"#include "conffile.h"static const char rcsid[] = "$Id: rlm_sql_log.c,v 1.3.2.2 2005/12/12 17:44:35 nbk Exp $";static int sql_log_instantiate(CONF_SECTION *conf, void **instance);static int sql_log_detach(void *instance);static int sql_log_accounting(void *instance, REQUEST *request);static int sql_log_postauth(void *instance, REQUEST *request);#define MAX_QUERY_LEN 4096/* *	Define a structure for our module configuration. */typedef struct rlm_sql_log_t {	char		*name;	char		*path;	char		*postauth_query;	char		*sql_user_name;	char		*allowed_chars;	CONF_SECTION	*conf_section;} rlm_sql_log_t;/* *	A mapping of configuration file names to internal variables. */static const CONF_PARSER module_config[] = {	{"path", PW_TYPE_STRING_PTR,	 offsetof(rlm_sql_log_t,path), NULL, "${radacctdir}/sql-relay"},	{"Post-Auth", PW_TYPE_STRING_PTR,	 offsetof(rlm_sql_log_t,postauth_query), NULL, ""},	{"sql_user_name", PW_TYPE_STRING_PTR,	 offsetof(rlm_sql_log_t,sql_user_name), NULL, ""},	{"safe-characters", PW_TYPE_STRING_PTR,	 offsetof(rlm_sql_log_t,allowed_chars), NULL,	"@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"},	{ NULL, -1, 0, NULL, NULL }	/* end the list */};static char *allowed_chars = NULL;/* *	Do any per-module initialization that is separate to each *	configured instance of the module.  e.g. set up connections *	to external databases, read configuration files, set up *	dictionary entries, etc. * *	If configuration information is given in the config section *	that must be referenced in later calls, store a handle to it *	in *instance otherwise put a null pointer there. */static int sql_log_instantiate(CONF_SECTION *conf, void **instance){	const char	*name;	rlm_sql_log_t	*inst;        /*         *      Set up a storage area for instance data.         */        inst = calloc(1, sizeof(rlm_sql_log_t));        if (inst == NULL) {                radlog(L_ERR, "rlm_sql_log: Not enough memory");                return -1;        }	/*	 *      Get the name of the current section in the conf file.	 */	name = cf_section_name2(conf);	if (name == NULL)		name = cf_section_name1(conf);	if (name == NULL)		name = "sql_log";	inst->name = strdup(name);	/*	 *	If the configuration parameters can't be parsed,	 *	then fail.	 */	if (cf_section_parse(conf, inst, module_config) < 0) {		radlog(L_ERR, "rlm_sql_log (%s): Unable to parse parameters",		       inst->name);		sql_log_detach(inst);		return -1;	}	inst->conf_section = conf;	allowed_chars = inst->allowed_chars;	*instance = inst;	return 0;}/* *	Say goodbye to the cruel world. */static int sql_log_detach(void *instance){	int i;	char **p;	rlm_sql_log_t *inst = (rlm_sql_log_t *)instance;	if (inst->name) {		free(inst->name);		inst->name = NULL;	}	/*	 *	Free up dynamically allocated string pointers.	 */	for (i = 0; module_config[i].name != NULL; i++) {		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) + module_config[i].offset);		if (!*p) { /* nothing allocated */			continue;		}		free(*p);		*p = NULL;	}	allowed_chars = NULL;	free(inst);	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;}/* *	Add the 'SQL-User-Name' attribute to the packet. */static int sql_set_user(rlm_sql_log_t *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 (inst->sql_user_name[0] != '\0') {		radius_xlat(tmpuser, sizeof(tmpuser), inst->sql_user_name,			    request, NULL);	} else {		return 0;	}	if (tmpuser[0] != '\0') {		strNcpy(sqlusername, tmpuser, sizeof(tmpuser));		DEBUG2("rlm_sql_log (%s): sql_set_user escaped user --> '%s'",		       inst->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;}/* *	Replace %<whatever> in the query. */static int sql_xlat_query(rlm_sql_log_t *inst, REQUEST *request, const char *query, char *xlat_query, size_t len){	char	sqlusername[MAX_STRING_LEN];	/* If query is not defined, we stop here */	if (query[0] == '\0')		return RLM_MODULE_NOOP;	/* Add attribute 'SQL-User-Name' */	if (sql_set_user(inst, request, sqlusername, NULL) <0) {		radlog(L_ERR, "rlm_sql_log (%s): Couldn't add SQL-User-Name attribute",			       inst->name);		return RLM_MODULE_FAIL;	}	/* Expand variables in the query */	xlat_query[0] = '\0';	radius_xlat(xlat_query, len, query, request, sql_escape_func);	if (xlat_query[0] == '\0') {		radlog(L_ERR, "rlm_sql_log (%s): Couldn't xlat the query %s",		       inst->name, query);		return RLM_MODULE_FAIL;	}	return RLM_MODULE_OK;}/* *	The Perl version of radsqlrelay uses fcntl locks. */static int setlock(int fd){	struct flock fl;	memset(&fl, 0, sizeof(fl));	fl.l_start = 0;	fl.l_len = 0;	fl.l_type = F_WRLCK;	fl.l_whence = SEEK_SET;	return fcntl(fd, F_SETLKW, &fl);}/* *	Write the line into file (with lock) */static int sql_log_write(rlm_sql_log_t *inst, REQUEST *request, const char *line){	int fd;	FILE *fp;	int locked = 0;	struct stat st;	char path[MAX_STRING_LEN];	path[0] = '\0';	radius_xlat(path, sizeof(path), inst->path, request, NULL);	if (path[0] == '\0')		return RLM_MODULE_FAIL;	while (!locked) {		if ((fd = open(path, O_WRONLY | O_APPEND | O_CREAT, 0666)) < 0) {			radlog(L_ERR, "rlm_sql_log (%s): Couldn't open file %s: %s",			       inst->name, path, strerror(errno));			return RLM_MODULE_FAIL;		}		if (setlock(fd) != 0) {			radlog(L_ERR, "rlm_sql_log (%s): Couldn't lock file %s: %s",			       inst->name, path, strerror(errno));			close(fd);			return RLM_MODULE_FAIL;		}		if (fstat(fd, &st) != 0) {			radlog(L_ERR, "rlm_sql_log (%s): Couldn't stat file %s: %s",			       inst->name, path, strerror(errno));			close(fd);			return RLM_MODULE_FAIL;		}		if (st.st_nlink == 0) {			DEBUG("rlm_sql_log (%s): File %s removed by another program, retrying",			      inst->name, path);			close(fd);			continue;		}		locked = 1;	}	if ((fp = fdopen(fd, "a")) == NULL) {		radlog(L_ERR, "rlm_sql_log (%s): Couldn't associate a stream with file %s: %s",		       inst->name, path, strerror(errno));		close(fd);		return RLM_MODULE_FAIL;	}	fputs(line, fp);	putc('\n', fp);	fclose(fp);	/* and unlock */	return RLM_MODULE_OK;}/* *	Write accounting information to this module's database. */static int sql_log_accounting(void *instance, REQUEST *request){	int		ret;	char		querystr[MAX_QUERY_LEN];	char		*cfquery;	rlm_sql_log_t	*inst = (rlm_sql_log_t *)instance;	VALUE_PAIR	*pair;	DICT_VALUE	*dval;	CONF_PAIR	*cp;	DEBUG("rlm_sql_log (%s): Processing sql_log_accounting", inst->name);	/* Find the Acct Status Type. */	if ((pair = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE)) == NULL) {		radlog(L_ERR, "rlm_sql_log (%s): Packet has no account status type",		       inst->name);		return RLM_MODULE_INVALID;	}	/* Search the query in conf section of the module */	if ((dval = dict_valbyattr(PW_ACCT_STATUS_TYPE, pair->lvalue)) == NULL) {		radlog(L_ERR, "rlm_sql_log (%s): Unsupported Acct-Status-Type = %d",		       inst->name, pair->lvalue);		return RLM_MODULE_NOOP;	}	if ((cp = cf_pair_find(inst->conf_section, dval->name)) == NULL) {		DEBUG("rlm_sql_log (%s): Couldn't find an entry %s in the config section",		      inst->name, dval->name);		return RLM_MODULE_NOOP;	}	cfquery = cf_pair_value(cp);	/* Xlat the query */	ret = sql_xlat_query(inst, request, cfquery, querystr, sizeof(querystr));	if (ret != RLM_MODULE_OK)		return ret;	/* Write query into sql-relay file */	return sql_log_write(inst, request, querystr);}/* *	Write post-auth information to this module's database. */static int sql_log_postauth(void *instance, REQUEST *request){	int		ret;	char		querystr[MAX_QUERY_LEN];	rlm_sql_log_t	*inst = (rlm_sql_log_t *)instance;	DEBUG("rlm_sql_log (%s): Processing sql_log_postauth", inst->name);	/* Xlat the query */	ret = sql_xlat_query(inst, request, inst->postauth_query,			     querystr, sizeof(querystr));	if (ret != RLM_MODULE_OK)		return ret;	/* Write query into sql-relay file */	return sql_log_write(inst, request, querystr);}/* *	The module name should be the only globally exported symbol. *	That is, everything else should be 'static'. * *	If the module needs to temporarily modify it's instantiation *	data, the type should be changed to RLM_TYPE_THREAD_UNSAFE. *	The server will then take care of ensuring that the module *	is single-threaded. */module_t rlm_sql_log = {	"sql_log",	RLM_TYPE_THREAD_SAFE,		/* type */	NULL,				/* initialization */	sql_log_instantiate,		/* instantiation */	{		NULL,			/* authentication */		NULL,			/* authorization */		NULL,			/* preaccounting */		sql_log_accounting,	/* accounting */		NULL,			/* checksimul */		NULL,			/* pre-proxy */		NULL,			/* post-proxy */		sql_log_postauth	/* post-auth */	},	sql_log_detach,			/* detach */	NULL,				/* destroy */};

⌨️ 快捷键说明

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