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

📄 rlm_sqlcounter.c

📁 使用最广泛的radius的linux的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * rlm_sqlcounter.c * * Version:  $Id: rlm_sqlcounter.c,v 1.39 2008/04/20 14:19:46 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * Copyright 2001,2006  The FreeRADIUS server project * Copyright 2001  Alan DeKok <aland@ox.org> *//* This module is based directly on the rlm_counter module */#include <freeradius-devel/ident.h>RCSID("$Id: rlm_sqlcounter.c,v 1.39 2008/04/20 14:19:46 aland Exp $")#include <freeradius-devel/radiusd.h>#include <freeradius-devel/modules.h>#include <ctype.h>#define MAX_QUERY_LEN 1024static int sqlcounter_detach(void *instance);/* *	Note: When your counter spans more than 1 period (ie 3 months *	or 2 weeks), this module probably does NOT do what you want! It *	calculates the range of dates to count across by first calculating *	the End of the Current period and then subtracting the number of *	periods you specify from that to determine the beginning of the *	range. * *	For example, if you specify a 3 month counter and today is June 15th, *	the end of the current period is June 30. Subtracting 3 months from *	that gives April 1st. So, the counter will sum radacct entries from *	April 1st to June 30. Then, next month, it will sum entries from *	May 1st to July 31st. * *	To fix this behavior, we need to add some way of storing the Next *	Reset Time. *//* *	Define a structure for our module configuration. * *	These variables do not need to be in a structure, but it's *	a lot cleaner to do so, and a pointer to the structure can *	be used as the instance handle. */typedef struct rlm_sqlcounter_t {	char *counter_name;  	/* Daily-Session-Time */	char *check_name;  	/* Max-Daily-Session */	char *reply_name;  	/* Session-Timeout */	char *key_name;  	/* User-Name */	char *sqlmod_inst;	/* instance of SQL module to use, usually just 'sql' */	char *query;		/* SQL query to retrieve current session time */	char *reset;  		/* daily, weekly, monthly, never or user defined */	char *allowed_chars;	/* safe characters list for SQL queries */	time_t reset_time;	time_t last_reset;	int  key_attr;		/* attribute number for key field */	int  dict_attr;		/* attribute number for the counter. */	int  reply_attr;	/* attribute number for the reply */} rlm_sqlcounter_t;/* *	A mapping of configuration file names to internal variables. * *	Note that the string is dynamically allocated, so it MUST *	be freed.  When the configuration file parse re-reads the string, *	it free's the old one, and strdup's the new one, placing the pointer *	to the strdup'd string into 'config.string'.  This gets around *	buffer over-flows. */static const CONF_PARSER module_config[] = {  { "counter-name", PW_TYPE_STRING_PTR, offsetof(rlm_sqlcounter_t,counter_name), NULL,  NULL },  { "check-name", PW_TYPE_STRING_PTR, offsetof(rlm_sqlcounter_t,check_name), NULL, NULL },  { "reply-name", PW_TYPE_STRING_PTR, offsetof(rlm_sqlcounter_t,reply_name), NULL, NULL },  { "key", PW_TYPE_STRING_PTR, offsetof(rlm_sqlcounter_t,key_name), NULL, NULL },  { "sqlmod-inst", PW_TYPE_STRING_PTR, offsetof(rlm_sqlcounter_t,sqlmod_inst), NULL, NULL },  { "query", PW_TYPE_STRING_PTR, offsetof(rlm_sqlcounter_t,query), NULL, NULL },  { "reset", PW_TYPE_STRING_PTR, offsetof(rlm_sqlcounter_t,reset), NULL,  NULL },  { "safe-characters", PW_TYPE_STRING_PTR, offsetof(rlm_sqlcounter_t,allowed_chars), NULL, "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"},  { NULL, -1, 0, NULL, NULL }};static char *allowed_chars = NULL;/* *	Translate the SQL queries. */static size_t sql_escape_func(char *out, size_t 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;}static int find_next_reset(rlm_sqlcounter_t *data, time_t timeval){	int ret = 0;	size_t len;	unsigned int num = 1;	char last = '\0';	struct tm *tm, s_tm;	char sCurrentTime[40], sNextTime[40];	tm = localtime_r(&timeval, &s_tm);	len = strftime(sCurrentTime, sizeof(sCurrentTime), "%Y-%m-%d %H:%M:%S", tm);	if (len == 0) *sCurrentTime = '\0';	tm->tm_sec = tm->tm_min = 0;	if (data->reset == NULL)		return -1;	if (isdigit((int) data->reset[0])){		len = strlen(data->reset);		if (len == 0)			return -1;		last = data->reset[len - 1];		if (!isalpha((int) last))			last = 'd';		num = atoi(data->reset);		DEBUG("rlm_sqlcounter: num=%d, last=%c",num,last);	}	if (strcmp(data->reset, "hourly") == 0 || last == 'h') {		/*		 *  Round up to the next nearest hour.		 */		tm->tm_hour += num;		data->reset_time = mktime(tm);	} else if (strcmp(data->reset, "daily") == 0 || last == 'd') {		/*		 *  Round up to the next nearest day.		 */		tm->tm_hour = 0;		tm->tm_mday += num;		data->reset_time = mktime(tm);	} else if (strcmp(data->reset, "weekly") == 0 || last == 'w') {		/*		 *  Round up to the next nearest week.		 */		tm->tm_hour = 0;		tm->tm_mday += (7 - tm->tm_wday) +(7*(num-1));		data->reset_time = mktime(tm);	} else if (strcmp(data->reset, "monthly") == 0 || last == 'm') {		tm->tm_hour = 0;		tm->tm_mday = 1;		tm->tm_mon += num;		data->reset_time = mktime(tm);	} else if (strcmp(data->reset, "never") == 0) {		data->reset_time = 0;	} else {		radlog(L_ERR, "rlm_sqlcounter: Unknown reset timer \"%s\"",			data->reset);		return -1;	}	len = strftime(sNextTime, sizeof(sNextTime),"%Y-%m-%d %H:%M:%S",tm);	if (len == 0) *sNextTime = '\0';	DEBUG2("rlm_sqlcounter: Current Time: %li [%s], Next reset %li [%s]",		timeval, sCurrentTime, data->reset_time, sNextTime);	return ret;}/*  I don't believe that this routine handles Daylight Saving Time adjustments    properly.  Any suggestions?*/static int find_prev_reset(rlm_sqlcounter_t *data, time_t timeval){	int ret = 0;	size_t len;	unsigned int num = 1;	char last = '\0';	struct tm *tm, s_tm;	char sCurrentTime[40], sPrevTime[40];	tm = localtime_r(&timeval, &s_tm);	len = strftime(sCurrentTime, sizeof(sCurrentTime), "%Y-%m-%d %H:%M:%S", tm);	if (len == 0) *sCurrentTime = '\0';	tm->tm_sec = tm->tm_min = 0;	if (data->reset == NULL)		return -1;	if (isdigit((int) data->reset[0])){		len = strlen(data->reset);		if (len == 0)			return -1;		last = data->reset[len - 1];		if (!isalpha((int) last))			last = 'd';		num = atoi(data->reset);		DEBUG("rlm_sqlcounter: num=%d, last=%c",num,last);	}	if (strcmp(data->reset, "hourly") == 0 || last == 'h') {		/*		 *  Round down to the prev nearest hour.		 */		tm->tm_hour -= num - 1;		data->last_reset = mktime(tm);	} else if (strcmp(data->reset, "daily") == 0 || last == 'd') {		/*		 *  Round down to the prev nearest day.		 */		tm->tm_hour = 0;		tm->tm_mday -= num - 1;		data->last_reset = mktime(tm);	} else if (strcmp(data->reset, "weekly") == 0 || last == 'w') {		/*		 *  Round down to the prev nearest week.		 */		tm->tm_hour = 0;		tm->tm_mday -= (7 - tm->tm_wday) +(7*(num-1));		data->last_reset = mktime(tm);	} else if (strcmp(data->reset, "monthly") == 0 || last == 'm') {		tm->tm_hour = 0;		tm->tm_mday = 1;		tm->tm_mon -= num - 1;		data->last_reset = mktime(tm);	} else if (strcmp(data->reset, "never") == 0) {		data->reset_time = 0;	} else {		radlog(L_ERR, "rlm_sqlcounter: Unknown reset timer \"%s\"",			data->reset);		return -1;	}	len = strftime(sPrevTime, sizeof(sPrevTime), "%Y-%m-%d %H:%M:%S", tm);	if (len == 0) *sPrevTime = '\0';	DEBUG2("rlm_sqlcounter: Current Time: %li [%s], Prev reset %li [%s]",	       timeval, sCurrentTime, data->last_reset, sPrevTime);	return ret;}/* *	Replace %<whatever> in a string. * *	%b	last_reset *	%e	reset_time *	%k	key_name *	%S	sqlmod_inst * */static int sqlcounter_expand(char *out, int outlen, const char *fmt, void *instance){	rlm_sqlcounter_t *data = (rlm_sqlcounter_t *) instance;	int c,freespace;	const char *p;	char *q;	char tmpdt[40]; /* For temporary storing of dates */	int openbraces=0;	q = out;	for (p = fmt; *p ; p++) {	/* Calculate freespace in output */	freespace = outlen - (q - out);		if (freespace <= 1)			break;		c = *p;		if ((c != '%') && (c != '$') && (c != '\\')) {			/*			 * We check if we're inside an open brace.  If we are			 * then we assume this brace is NOT literal, but is			 * a closing brace and apply it			 */			if((c == '}') && openbraces) {				openbraces--;				continue;			}			*q++ = *p;			continue;		}		if (*++p == '\0') break;		if (c == '\\') switch(*p) {			case '\\':				*q++ = *p;				break;			case 't':				*q++ = '\t';				break;			case 'n':				*q++ = '\n';				break;			default:				*q++ = c;				*q++ = *p;				break;		} else if (c == '%') switch(*p) {			case '%':				*q++ = *p;			case 'b': /* last_reset */				snprintf(tmpdt, sizeof(tmpdt), "%lu", data->last_reset);				strlcpy(q, tmpdt, freespace);				q += strlen(q);				break;			case 'e': /* reset_time */				snprintf(tmpdt, sizeof(tmpdt), "%lu", data->reset_time);				strlcpy(q, tmpdt, freespace);				q += strlen(q);				break;			case 'k': /* Key Name */				strlcpy(q, data->key_name, freespace);				q += strlen(q);				break;			case 'S': /* SQL module instance */				strlcpy(q, data->sqlmod_inst, freespace);				q += strlen(q);				break;			default:				*q++ = '%';				*q++ = *p;				break;		}	}	*q = '\0';	DEBUG2("sqlcounter_expand:  '%s'", out);	return strlen(out);}/* *	See if the counter matches. */static int sqlcounter_cmp(void *instance, REQUEST *req,			  UNUSED VALUE_PAIR *request, VALUE_PAIR *check,			  VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs){	rlm_sqlcounter_t *data = (rlm_sqlcounter_t *) instance;	int counter;	char querystr[MAX_QUERY_LEN];	char responsestr[MAX_QUERY_LEN];	check_pairs = check_pairs; /* shut the compiler up */	reply_pairs = reply_pairs;	/* first, expand %k, %b and %e in query */	sqlcounter_expand(querystr, MAX_QUERY_LEN, data->query, instance);	/* second, xlat any request attribs in query */	radius_xlat(responsestr, MAX_QUERY_LEN, querystr, req, sql_escape_func);	/* third, wrap query with sql module call & expand */	snprintf(querystr, sizeof(querystr), "%%{%%S:%s}", responsestr);	sqlcounter_expand(responsestr, MAX_QUERY_LEN, querystr, instance);	/* Finally, xlat resulting SQL query */	radius_xlat(querystr, MAX_QUERY_LEN, responsestr, req, sql_escape_func);	counter = atoi(querystr);

⌨️ 快捷键说明

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