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

📄 rlm_counter.c

📁 radius服务器
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * rlm_counter.c * * Version:  $Id: rlm_counter.c,v 1.43 2004/02/26 19:04:28 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 2001  The FreeRADIUS server project * Copyright 2001  Alan DeKok <aland@ox.org> * Copyright 2001-3  Kostas Kalevras <kkalev@noc.ntua.gr> */#include "config.h"#include "autoconf.h"#include "libradius.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include "radiusd.h"#include "modules.h"#include "conffile.h"#include <gdbm.h>#include <time.h>#ifdef NEEDS_GDBM_SYNC#	define GDBM_SYNCOPT GDBM_SYNC#else#	define GDBM_SYNCOPT 0#endif#ifdef GDBM_NOLOCK#define GDBM_COUNTER_OPTS (GDBM_SYNCOPT | GDBM_NOLOCK)#else#define GDBM_COUNTER_OPTS (GDBM_SYNCOPT)#endif#ifndef HAVE_GDBM_FDESC#define gdbm_fdesc(foo) (-1)#endif#define UNIQUEID_MAX_LEN 32static const char rcsid[] = "$Id: rlm_counter.c,v 1.43 2004/02/26 19:04:28 aland Exp $";/* *	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_counter_t {	char *filename;		/* name of the database file */	char *reset;		/* daily, weekly, monthly, never or user defined */	char *key_name;		/* User-Name */	char *count_attribute;	/* Acct-Session-Time */	char *counter_name;	/* Daily-Session-Time */	char *check_name;	/* Daily-Max-Session */	char *service_type;	/* Service-Type to search for */	int cache_size;	int service_val;	int key_attr;	int count_attr;	int check_attr;	time_t reset_time;	/* The time of the next reset. */	time_t last_reset;	/* The time of the last reset. */	int dict_attr;		/* attribute number for the counter. */	GDBM_FILE gdbm;		/* The gdbm file handle */#ifdef HAVE_PTHREAD_H	pthread_mutex_t mutex;	/* A mutex to lock the gdbm file for only one reader/writer */#endif} rlm_counter_t;#ifndef HAVE_PTHREAD_H/* *	This is a lot simpler than putting ifdef's around *	every use of the pthread functions. */#define pthread_mutex_lock(a)#define pthread_mutex_unlock(a)#define pthread_mutex_init(a,b)#define pthread_mutex_destroy(a)#endiftypedef struct rad_counter {	unsigned int user_counter;	char uniqueid[UNIQUEID_MAX_LEN];} rad_counter;/* *	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 CONF_PARSER module_config[] = {  { "filename", PW_TYPE_STRING_PTR, offsetof(rlm_counter_t,filename), NULL, NULL },  { "key", PW_TYPE_STRING_PTR, offsetof(rlm_counter_t,key_name), NULL, NULL },  { "reset", PW_TYPE_STRING_PTR, offsetof(rlm_counter_t,reset), NULL,  NULL },  { "count-attribute", PW_TYPE_STRING_PTR, offsetof(rlm_counter_t,count_attribute), NULL, NULL },  { "counter-name", PW_TYPE_STRING_PTR, offsetof(rlm_counter_t,counter_name), NULL,  NULL },  { "check-name", PW_TYPE_STRING_PTR, offsetof(rlm_counter_t,check_name), NULL, NULL },  { "allowed-servicetype", PW_TYPE_STRING_PTR, offsetof(rlm_counter_t,service_type),NULL, NULL },  { "cache-size", PW_TYPE_INTEGER, offsetof(rlm_counter_t,cache_size), NULL, "1000" },  { NULL, -1, 0, NULL, NULL }};static int counter_detach(void *instance);/* *	See if the counter matches. */static int counter_cmp(void *instance,		       REQUEST *req UNUSED,		       VALUE_PAIR *request, VALUE_PAIR *check,		       VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs){	rlm_counter_t *data = (rlm_counter_t *) instance;	datum key_datum;	datum count_datum;	VALUE_PAIR *key_vp;	rad_counter counter;	check_pairs = check_pairs; /* shut the compiler up */	reply_pairs = reply_pairs;	req = req;	/*	 *	Find the key attribute.	 */	key_vp = pairfind(request, data->key_attr);	if (key_vp == NULL) {		return RLM_MODULE_NOOP;	}	key_datum.dptr = key_vp->strvalue;	key_datum.dsize = key_vp->length;	count_datum = gdbm_fetch(data->gdbm, key_datum);	if (count_datum.dptr == NULL) {		return -1;	}	memcpy(&counter, count_datum.dptr, sizeof(rad_counter));	free(count_datum.dptr);	return counter.user_counter - check->lvalue;}static int add_defaults(rlm_counter_t *data){	datum key_datum;	datum time_datum;	const char *default1 = "DEFAULT1";	const char *default2 = "DEFAULT2";	DEBUG2("rlm_counter: add_defaults: Start");	key_datum.dptr = (char *) default1;	key_datum.dsize = strlen(default1);	time_datum.dptr = (char *) &data->reset_time;	time_datum.dsize = sizeof(time_t);	if (gdbm_store(data->gdbm, key_datum, time_datum, GDBM_REPLACE) < 0){		radlog(L_ERR, "rlm_counter: Failed storing data to %s: %s",				data->filename, gdbm_strerror(gdbm_errno));		return RLM_MODULE_FAIL;	}	DEBUG2("rlm_counter: DEFAULT1 set to %d",(int)data->reset_time);	key_datum.dptr = (char *) default2;	key_datum.dsize = strlen(default2);	time_datum.dptr = (char *) &data->last_reset;	time_datum.dsize = sizeof(time_t);	if (gdbm_store(data->gdbm, key_datum, time_datum, GDBM_REPLACE) < 0){		radlog(L_ERR, "rlm_counter: Failed storing data to %s: %s",				data->filename, gdbm_strerror(gdbm_errno));		return RLM_MODULE_FAIL;	}	DEBUG2("rlm_counter: DEFAULT2 set to %d",(int)data->last_reset);	DEBUG2("rlm_counter: add_defaults: End");	return RLM_MODULE_OK;}static int reset_db(rlm_counter_t *data){	int cache_size = data->cache_size;	int ret;	DEBUG2("rlm_counter: reset_db: Closing database");	gdbm_close(data->gdbm);	/*	 *	Open a completely new database.	 */	data->gdbm = gdbm_open(data->filename, sizeof(int),			GDBM_NEWDB | GDBM_COUNTER_OPTS, 0600, NULL);	if (data->gdbm == NULL) {		radlog(L_ERR, "rlm_counter: Failed to open file %s: %s",				data->filename, strerror(errno));		return RLM_MODULE_FAIL;	}	if (gdbm_setopt(data->gdbm, GDBM_CACHESIZE, &cache_size, sizeof(int)) == -1)		radlog(L_ERR, "rlm_counter: Failed to set cache size");	DEBUG2("rlm_counter: reset_db: Opened new database");	/*	 * Add defaults	 */	ret = add_defaults(data);	if (ret != RLM_MODULE_OK)		return ret;	DEBUG2("rlm_counter: reset_db ended");	return RLM_MODULE_OK;}static int find_next_reset(rlm_counter_t *data, time_t timeval){	int ret=0;	unsigned int num=1;	char last = 0;	struct tm *tm, s_tm;	char sCurrentTime[40], sNextTime[40];	tm = localtime_r(&timeval, &s_tm);	strftime(sCurrentTime, sizeof(sCurrentTime),"%Y-%m-%d %H:%M:%S",tm);	tm->tm_sec = tm->tm_min = 0;	if (data->reset == NULL)		return -1;	if (isdigit((int) data->reset[0])){		unsigned int len=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_counter: 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_counter: Unknown reset timer \"%s\"",			data->reset);		return -1;	}	strftime(sNextTime, sizeof(sNextTime),"%Y-%m-%d %H:%M:%S",tm);	DEBUG2("rlm_counter: Current Time: %d [%s], Next reset %d [%s]",		(int)timeval,sCurrentTime,(int)data->reset_time,sNextTime);	return ret;}/* *	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 counter_instantiate(CONF_SECTION *conf, void **instance){	rlm_counter_t *data;	DICT_ATTR *dattr;	DICT_VALUE *dval;	ATTR_FLAGS flags;	time_t now;	int cache_size;	int ret;	datum key_datum;	datum time_datum;	const char *default1 = "DEFAULT1";	const char *default2 = "DEFAULT2";	/*	 *	Set up a storage area for instance data	 */	data = rad_malloc(sizeof(*data));	if (!data) {		radlog(L_ERR, "rlm_counter: rad_malloc() failed.");		return -1;	}	memset(data, 0, sizeof(*data));	/*	 *	If the configuration parameters can't be parsed, then	 *	fail.	 */	if (cf_section_parse(conf, data, module_config) < 0) {		free(data);		return -1;	}	cache_size = data->cache_size;	/*	 *	Discover the attribute number of the key.	 */	if (data->key_name == NULL) {		radlog(L_ERR, "rlm_counter: 'key' must be set.");		counter_detach(data);		return -1;	}	dattr = dict_attrbyname(data->key_name);	if (dattr == NULL) {		radlog(L_ERR, "rlm_counter: No such attribute %s",				data->key_name);		counter_detach(data);		return -1;	}	data->key_attr = dattr->attr;	/*	 *	Discover the attribute number of the counter.	 */	if (data->count_attribute == NULL) {		radlog(L_ERR, "rlm_counter: 'count-attribute' must be set.");		counter_detach(data);		return -1;	}	dattr = dict_attrbyname(data->count_attribute);	if (dattr == NULL) {		radlog(L_ERR, "rlm_counter: No such attribute %s",				data->count_attribute);		counter_detach(data);		return -1;	}	data->count_attr = dattr->attr;	/*	 *  Create a new attribute for the counter.	 */	if (data->counter_name == NULL) {		radlog(L_ERR, "rlm_counter: 'counter-name' must be set.");		counter_detach(data);		return -1;	}	memset(&flags, 0, sizeof(flags));	dict_addattr(data->counter_name, 0, PW_TYPE_INTEGER, -1, flags);	dattr = dict_attrbyname(data->counter_name);	if (dattr == NULL) {		radlog(L_ERR, "rlm_counter: Failed to create counter attribute %s",				data->counter_name);		counter_detach(data);		return -1;	}	data->dict_attr = dattr->attr;	DEBUG2("rlm_counter: Counter attribute %s is number %d",			data->counter_name, data->dict_attr);	/*	 * Create a new attribute for the check item.	 */	if (data->check_name == NULL) {		radlog(L_ERR, "rlm_counter: 'check-name' must be set.");		counter_detach(data);		return -1;	}	dict_addattr(data->check_name, 0, PW_TYPE_INTEGER, -1, flags);	dattr = dict_attrbyname(data->check_name);	if (dattr == NULL) {		radlog(L_ERR, "rlm_counter: Failed to create check attribute %s",				data->counter_name);		counter_detach(data);		return -1;	}	data->check_attr = dattr->attr;	/*	 * Find the attribute for the allowed protocol	 */	if (data->service_type != NULL) {		if ((dval = dict_valbyname(PW_SERVICE_TYPE, data->service_type)) == NULL) {			radlog(L_ERR, "rlm_counter: Failed to find attribute number for %s",					data->service_type);			counter_detach(data);			return -1;		}		data->service_val = dval->value;	}	/*	 * Find when to reset the database.	 */	if (data->reset == NULL) {		radlog(L_ERR, "rlm_counter: 'reset' must be set.");		counter_detach(data);		return -1;	}	now = time(NULL);	data->reset_time = 0;	data->last_reset = now;	if (find_next_reset(data,now) == -1){		radlog(L_ERR, "rlm_counter: find_next_reset() returned -1. Exiting.");		counter_detach(data);		return -1;	}	if (data->filename == NULL) {		radlog(L_ERR, "rlm_counter: 'filename' must be set.");		counter_detach(data);

⌨️ 快捷键说明

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