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

📄 rlm_sqlcounter.c

📁 使用最广泛的radius的linux的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
	return counter - check->vp_integer;}/* *	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 sqlcounter_instantiate(CONF_SECTION *conf, void **instance){	rlm_sqlcounter_t *data;	DICT_ATTR *dattr;	ATTR_FLAGS flags;	time_t now;	char buffer[MAX_STRING_LEN];	/*	 *	Set up a storage area for instance data	 */	data = rad_malloc(sizeof(*data));	if (!data) {		radlog(L_ERR, "rlm_sqlcounter: Not enough memory.");		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) {		radlog(L_ERR, "rlm_sqlcounter: Unable to parse parameters.");		sqlcounter_detach(data);		return -1;	}	/*	 *	No query, die.	 */	if (data->query == NULL) {		radlog(L_ERR, "rlm_sqlcounter: 'query' must be set.");		sqlcounter_detach(data);		return -1;	}	/*	 *	Safe characters list for sql queries. Everything else is	 *	replaced with their mime-encoded equivalents.	 */	allowed_chars = data->allowed_chars;	/*	 *	Discover the attribute number of the key.	 */	if (data->key_name == NULL) {		radlog(L_ERR, "rlm_sqlcounter: 'key' must be set.");		sqlcounter_detach(data);		return -1;	}	sql_escape_func(buffer, sizeof(buffer), data->key_name);	if (strcmp(buffer, data->key_name) != 0) {		radlog(L_ERR, "rlm_sqlcounter: The value for option 'key' is too long or contains unsafe characters.");		sqlcounter_detach(data);		return -1;	}	dattr = dict_attrbyname(data->key_name);	if (dattr == NULL) {		radlog(L_ERR, "rlm_sqlcounter: No such attribute %s",				data->key_name);		sqlcounter_detach(data);		return -1;	}	data->key_attr = dattr->attr;	/*	 *	Discover the attribute number of the reply.	 *	If not set, set it to Session-Timeout	 *	for backward compatibility.	 */	if (data->reply_name == NULL) {		DEBUG2("rlm_sqlcounter: Reply attribute set to Session-Timeout.");		data->reply_attr = PW_SESSION_TIMEOUT;		data->reply_name = strdup("Session-Timeout");	}	else {		dattr = dict_attrbyname(data->reply_name);		if (dattr == NULL) {			radlog(L_ERR, "rlm_sqlcounter: No such attribute %s",			       data->reply_name);			sqlcounter_detach(data);			return -1;		}		data->reply_attr = dattr->attr;		DEBUG2("rlm_sqlcounter: Reply attribute %s is number %d",		       data->reply_name, dattr->attr);	}	/*	 *	Check the "sqlmod-inst" option.	 */	if (data->sqlmod_inst == NULL) {		radlog(L_ERR, "rlm_sqlcounter: 'sqlmod-inst' must be set.");		sqlcounter_detach(data);		return -1;	}	sql_escape_func(buffer, sizeof(buffer), data->sqlmod_inst);	if (strcmp(buffer, data->sqlmod_inst) != 0) {		radlog(L_ERR, "rlm_sqlcounter: The value for option 'sqlmod-inst' is too long or contains unsafe characters.");		sqlcounter_detach(data);		return -1;	}	/*	 *  Create a new attribute for the counter.	 */	if (data->counter_name == NULL) {		radlog(L_ERR, "rlm_sqlcounter: 'counter-name' must be set.");		sqlcounter_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_sqlcounter: Failed to create counter attribute %s",				data->counter_name);		sqlcounter_detach(data);		return -1;	}	data->dict_attr = dattr->attr;	DEBUG2("rlm_sqlcounter: 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_sqlcounter: 'check-name' must be set.");		sqlcounter_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_sqlcounter: Failed to create check attribute %s",				data->check_name);		sqlcounter_detach(data);		return -1;	}	DEBUG2("rlm_sqlcounter: Check attribute %s is number %d",			data->check_name, dattr->attr);	/*	 *  Discover the end of the current time period.	 */	if (data->reset == NULL) {		radlog(L_ERR, "rlm_sqlcounter: 'reset' must be set.");		sqlcounter_detach(data);		return -1;	}	now = time(NULL);	data->reset_time = 0;	if (find_next_reset(data,now) == -1) {		radlog(L_ERR, "rlm_sqlcounter: Failed to find the next reset time.");		sqlcounter_detach(data);		return -1;	}	/*	 *  Discover the beginning of the current time period.	 */	data->last_reset = 0;	if (find_prev_reset(data,now) == -1) {		radlog(L_ERR, "rlm_sqlcounter: Failed to find the previous reset time.");		sqlcounter_detach(data);		return -1;	}	/*	 *	Register the counter comparison operation.	 */	paircompare_register(data->dict_attr, 0, sqlcounter_cmp, data);	*instance = data;	return 0;}/* *	Find the named user in this modules database.  Create the set *	of attribute-value pairs to check and reply with for this user *	from the database. The authentication code only needs to check *	the password, the rest is done here. */static int sqlcounter_authorize(void *instance, REQUEST *request){	rlm_sqlcounter_t *data = (rlm_sqlcounter_t *) instance;	int ret=RLM_MODULE_NOOP;	unsigned int counter;	DICT_ATTR *dattr;	VALUE_PAIR *key_vp, *check_vp;	VALUE_PAIR *reply_item;	char msg[128];	char querystr[MAX_QUERY_LEN];	char responsestr[MAX_QUERY_LEN];	/* quiet the compiler */	instance = instance;	request = request;	/*	 *	Before doing anything else, see if we have to reset	 *	the counters.	 */	if (data->reset_time && (data->reset_time <= request->timestamp)) {		/*		 *	Re-set the next time and prev_time for this counters range		 */		data->last_reset = data->reset_time;		find_next_reset(data,request->timestamp);	}	/*	 *      Look for the key.  User-Name is special.  It means	 *      The REAL username, after stripping.	 */	DEBUG2("rlm_sqlcounter: Entering module authorize code");	key_vp = (data->key_attr == PW_USER_NAME) ? request->username : pairfind(request->packet->vps, data->key_attr);	if (key_vp == NULL) {		DEBUG2("rlm_sqlcounter: Could not find Key value pair");		return ret;	}	/*	 *      Look for the check item	 */	if ((dattr = dict_attrbyname(data->check_name)) == NULL) {		return ret;	}	/* DEBUG2("rlm_sqlcounter: Found Check item attribute %d", dattr->attr); */	if ((check_vp= pairfind(request->config_items, dattr->attr)) == NULL) {		DEBUG2("rlm_sqlcounter: Could not find Check item value pair");		return ret;	}	/* 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, request, sql_escape_func);	/* third, wrap query with sql module & 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, request, sql_escape_func);	if (sscanf(querystr, "%u", &counter) != 1) {		DEBUG2("rlm_sqlcounter: No integer found in string \"%s\"",		       querystr);		return RLM_MODULE_NOOP;	}	/*	 * Check if check item > counter	 */	if (check_vp->vp_integer > counter) {		unsigned int res = check_vp->lvalue - counter;		DEBUG2("rlm_sqlcounter: Check item is greater than query result");		/*		 *	We are assuming that simultaneous-use=1. But		 *	even if that does not happen then our user		 *	could login at max for 2*max-usage-time Is		 *	that acceptable?		 */		/*		 *	User is allowed, but set Session-Timeout.		 *	Stolen from main/auth.c		 */		/*		 *	If we are near a reset then add the next		 *	limit, so that the user will not need to		 *	login again		 */		if (data->reset_time &&		    (res >= (data->reset_time - request->timestamp))) {			res = data->reset_time - request->timestamp;			res += check_vp->vp_integer;		}		if ((reply_item = pairfind(request->reply->vps, data->reply_attr)) != NULL) {			if (reply_item->vp_integer > res)				reply_item->vp_integer = res;		} else {			reply_item = radius_paircreate(request,						       &request->reply->vps,						       data->reply_attr,						       PW_TYPE_INTEGER);			reply_item->vp_integer = res;		}		ret=RLM_MODULE_OK;		DEBUG2("rlm_sqlcounter: Authorized user %s, check_item=%u, counter=%u",				key_vp->vp_strvalue,check_vp->vp_integer,counter);		DEBUG2("rlm_sqlcounter: Sent Reply-Item for user %s, Type=%s, value=%u",				key_vp->vp_strvalue,data->reply_name,reply_item->vp_integer);	}	else{		char module_fmsg[MAX_STRING_LEN];		VALUE_PAIR *module_fmsg_vp;		DEBUG2("rlm_sqlcounter: (Check item - counter) is less than zero");		/*		 * User is denied access, send back a reply message		 */		snprintf(msg, sizeof(msg), "Your maximum %s usage time has been reached", data->reset);		reply_item=pairmake("Reply-Message", msg, T_OP_EQ);		pairadd(&request->reply->vps, reply_item);		snprintf(module_fmsg, sizeof(module_fmsg), "rlm_sqlcounter: Maximum %s usage time reached", data->reset);		module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);		pairadd(&request->packet->vps, module_fmsg_vp);		ret=RLM_MODULE_REJECT;		DEBUG2("rlm_sqlcounter: Rejected user %s, check_item=%u, counter=%u",				key_vp->vp_strvalue,check_vp->vp_integer,counter);	}	return ret;}static int sqlcounter_detach(void *instance){	int i;	char **p;	rlm_sqlcounter_t *inst = (rlm_sqlcounter_t *)instance;	allowed_chars = NULL;	paircompare_unregister(inst->dict_attr, sqlcounter_cmp);	/*	 *	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;	}	free(inst);	return 0;}/* *	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_sqlcounter = {	RLM_MODULE_INIT,	"SQL Counter",	RLM_TYPE_THREAD_SAFE,		/* type */	sqlcounter_instantiate,		/* instantiation */	sqlcounter_detach,		/* detach */	{		NULL,			/* authentication */		sqlcounter_authorize, 	/* authorization */		NULL,			/* preaccounting */		NULL,			/* accounting */		NULL,			/* checksimul */		NULL,			/* pre-proxy */		NULL,			/* post-proxy */		NULL			/* post-auth */	},};

⌨️ 快捷键说明

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