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

📄 modcall.c

📁 使用最广泛的radius的linux的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * modcall.c * * Version:	$Id: modcall.c,v 1.99 2008/03/16 17:59: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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * Copyright 2000,2006  The FreeRADIUS server project */#include <freeradius-devel/ident.h>RCSID("$Id: modcall.c,v 1.99 2008/03/16 17:59:28 aland Exp $")#include <freeradius-devel/radiusd.h>#include <freeradius-devel/modpriv.h>#include <freeradius-devel/modcall.h>#include <freeradius-devel/rad_assert.h>/* mutually-recursive static functions need a prototype up front */static modcallable *do_compile_modgroup(modcallable *,					int, CONF_SECTION *,					int, int);/* Actions may be a positive integer (the highest one returned in the group * will be returned), or the keyword "return", represented here by * MOD_ACTION_RETURN, to cause an immediate return. * There's also the keyword "reject", represented here by MOD_ACTION_REJECT * to cause an immediate reject. */#define MOD_ACTION_RETURN  (-1)#define MOD_ACTION_REJECT  (-2)/* Here are our basic types: modcallable, modgroup, and modsingle. For an * explanation of what they are all about, see ../../doc/README.failover */struct modcallable {	modcallable *parent;	struct modcallable *next;	const char *name;	enum { MOD_SINGLE = 1, MOD_GROUP, MOD_LOAD_BALANCE, MOD_REDUNDANT_LOAD_BALANCE, MOD_IF, MOD_ELSE, MOD_ELSIF, MOD_UPDATE, MOD_SWITCH, MOD_CASE, MOD_POLICY, MOD_REFERENCE } type;	int method;	int actions[RLM_MODULE_NUMCODES];};#define GROUPTYPE_SIMPLE	0#define GROUPTYPE_REDUNDANT	1#define GROUPTYPE_APPEND	2#define GROUPTYPE_COUNT		3typedef struct {	modcallable mc;		/* self */	int grouptype;	/* after mc */	modcallable *children;	CONF_SECTION *cs;	VALUE_PAIR *vps;} modgroup;typedef struct {	modcallable mc;	module_instance_t *modinst;} modsingle;typedef struct {	modcallable mc;	const char *ref_name;	CONF_SECTION *ref_cs;} modref;static const FR_NAME_NUMBER grouptype_table[] = {	{ "", GROUPTYPE_SIMPLE },	{ "redundant ", GROUPTYPE_REDUNDANT },	{ "append ", GROUPTYPE_APPEND },	{ NULL, -1 }};/* Simple conversions: modsingle and modgroup are subclasses of modcallable, * so we often want to go back and forth between them. */static modsingle *mod_callabletosingle(modcallable *p){	rad_assert(p->type==MOD_SINGLE);	return (modsingle *)p;}static modgroup *mod_callabletogroup(modcallable *p){	rad_assert((p->type > MOD_SINGLE) && (p->type <= MOD_POLICY));	return (modgroup *)p;}static modcallable *mod_singletocallable(modsingle *p){	return (modcallable *)p;}static modcallable *mod_grouptocallable(modgroup *p){	return (modcallable *)p;}static modref *mod_callabletoref(modcallable *p){	rad_assert(p->type==MOD_REFERENCE);	return (modref *)p;}static modcallable *mod_reftocallable(modref *p){	return (modcallable *)p;}/* modgroups are grown by adding a modcallable to the end *//* FIXME: This is O(N^2) */static void add_child(modgroup *g, modcallable *c){	modcallable **head = &g->children;	modcallable *node = *head;	modcallable **last = head;	if (!c) return;	while (node) {		last = &node->next;		node = node->next;	}	rad_assert(c->next == NULL);	*last = c;	c->parent = mod_grouptocallable(g);}/* Here's where we recognize all of our keywords: first the rcodes, then the * actions */static const FR_NAME_NUMBER rcode_table[] = {	{ "reject",     RLM_MODULE_REJECT       },	{ "fail",       RLM_MODULE_FAIL         },	{ "ok",         RLM_MODULE_OK           },	{ "handled",    RLM_MODULE_HANDLED      },	{ "invalid",    RLM_MODULE_INVALID      },	{ "userlock",   RLM_MODULE_USERLOCK     },	{ "notfound",   RLM_MODULE_NOTFOUND     },	{ "noop",       RLM_MODULE_NOOP         },	{ "updated",    RLM_MODULE_UPDATED      },	{ NULL, 0 }};/* *	Compile action && rcode for later use. */static int compile_action(modcallable *c, CONF_PAIR *cp){	int action;	const char *attr, *value;	attr = cf_pair_attr(cp);	value = cf_pair_value(cp);	if (!value) return 0;	if (!strcasecmp(value, "return"))		action = MOD_ACTION_RETURN;	else if (!strcasecmp(value, "break"))		action = MOD_ACTION_RETURN;	else if (!strcasecmp(value, "reject"))		action = MOD_ACTION_REJECT;	else if (strspn(value, "0123456789")==strlen(value)) {		action = atoi(value);		/*		 *	Don't allow priority zero, for future use.		 */		if (action == 0) return 0;	} else {		cf_log_err(cf_pairtoitem(cp), "Unknown action '%s'.\n",			   value);		return 0;	}	if (strcasecmp(attr, "default") != 0) {		int rcode;		rcode = fr_str2int(rcode_table, attr, -1);		if (rcode < 0) {			cf_log_err(cf_pairtoitem(cp),				   "Unknown module rcode '%s'.\n",				   attr);			return 0;		}		c->actions[rcode] = action;	} else {		/* set all unset values to the default */		int i;		for (i = 0; i < RLM_MODULE_NUMCODES; i++) {			if (!c->actions[i]) c->actions[i] = action;		}	}	return 1;}/* Some short names for debugging output */static const char * const comp2str[] = {	"authenticate",	"authorize",	"preacct",	"accounting",	"session",	"pre-proxy",	"post-proxy",	"post-auth"};#ifdef HAVE_PTHREAD_H/* *	Lock the mutex for the module */static void safe_lock(module_instance_t *instance){	if (instance->mutex)		pthread_mutex_lock(instance->mutex);}/* *	Unlock the mutex for the module */static void safe_unlock(module_instance_t *instance){	if (instance->mutex)		pthread_mutex_unlock(instance->mutex);}#else/* *	No threads: these functions become NULL's. */#define safe_lock(foo)#define safe_unlock(foo)#endifstatic int call_modsingle(int component, modsingle *sp, REQUEST *request,			  int default_result){	int myresult = default_result;	DEBUG3("  modsingle[%s]: calling %s (%s) for request %d",	       comp2str[component], sp->modinst->name,	       sp->modinst->entry->name, request->number);	safe_lock(sp->modinst);	/*	 *	For logging unresponsive children.	 */	request->module = sp->modinst->name;	myresult = sp->modinst->entry->module->methods[component](			sp->modinst->insthandle, request);	request->module = "<server-core>";	safe_unlock(sp->modinst);	DEBUG3("  modsingle[%s]: returned from %s (%s) for request %d",	       comp2str[component], sp->modinst->name,	       sp->modinst->entry->name, request->number);	return myresult;}static int default_component_results[RLM_COMPONENT_COUNT] = {	RLM_MODULE_REJECT,	/* AUTH */	RLM_MODULE_NOTFOUND,	/* AUTZ */	RLM_MODULE_NOOP,	/* PREACCT */	RLM_MODULE_NOOP,	/* ACCT */	RLM_MODULE_FAIL,	/* SESS */	RLM_MODULE_NOOP,	/* PRE_PROXY */	RLM_MODULE_NOOP,	/* POST_PROXY */	RLM_MODULE_NOOP		/* POST_AUTH */};static const char *group_name[] = {	"",	"single",	"group",	"load-balance group",	"redundant-load-balance group",	"if",	"else",	"elsif",	"update",	"switch",	"case",	"policy"};static const char *modcall_spaces = "++++++++++++++++++++++++++++++++";#define MODCALL_STACK_MAX (32)/* *	Don't call the modules recursively.  Instead, do them *	iteratively, and manage the call stack ourselves. */typedef struct modcall_stack {	int pointer;	int priority[MODCALL_STACK_MAX];	int result[MODCALL_STACK_MAX];	modcallable *children[MODCALL_STACK_MAX];	modcallable *start[MODCALL_STACK_MAX];} modcall_stack;/* *	Call a module, iteratively, with a local stack, rather than *	recursively.  What did Paul Graham say about Lisp...? */int modcall(int component, modcallable *c, REQUEST *request){	int myresult;	modcall_stack stack;	modcallable *parent, *child;	modsingle *sp;	int if_taken, was_if;	if ((component < 0) || (component >= RLM_COMPONENT_COUNT)) {		return RLM_MODULE_FAIL;	}	stack.pointer = 0;	stack.priority[0] = 0;	stack.children[0] = c;	myresult = stack.result[0] = default_component_results[component];	was_if = if_taken = FALSE;	while (1) {		/*		 *	A module has taken too long to process the request,		 *	and we've been told to stop processing it.		 */		if ((request->master_state == REQUEST_STOP_PROCESSING) ||		    (request->parent &&		     (request->parent->master_state == REQUEST_STOP_PROCESSING))) {			myresult = RLM_MODULE_FAIL;			break;		}		child = stack.children[stack.pointer];		if (!child) {			myresult = stack.result[stack.pointer];			break;		}		parent = child->parent;		if ((child->type == MOD_ELSE) || (child->type == MOD_ELSIF)) {			myresult = stack.result[stack.pointer];			if (!was_if) { /* error */				DEBUG2("%.*s ... skipping %s for request %d: No preceding \"if\"",				       stack.pointer + 1, modcall_spaces,				       group_name[child->type],				       request->number);				goto unroll;			}			if (if_taken) {				DEBUG2("%.*s ... skipping %s for request %d: Preceding \"if\" was taken",				       stack.pointer + 1, modcall_spaces,				       group_name[child->type],				       request->number);				goto unroll;			}		}		/*		 *	"if" or "elsif".  Evaluate the condition.		 */		if ((child->type == MOD_IF) || (child->type == MOD_ELSIF)) {			int condition = TRUE;			const char *p = child->name;			DEBUG2("%.*s? %s %s",			       stack.pointer + 1, modcall_spaces,			       (child->type == MOD_IF) ? "if" : "elsif",			       child->name);			if (radius_evaluate_condition(request, myresult,						      0, &p, TRUE, &condition)) {				DEBUG2("%.*s? %s %s -> %s",				       stack.pointer + 1, modcall_spaces,				       (child->type == MOD_IF) ? "if" : "elsif",				       child->name, (condition != FALSE) ? "TRUE" : "FALSE");			} else {				/*				 *	This should never happen, the				 *	condition is checked when the				 *	module section is loaded.				 */				condition = FALSE;			}			if (!condition) {				stack.result[stack.pointer] = myresult;				stack.children[stack.pointer] = NULL;				was_if = TRUE;				if_taken = FALSE;				goto next_section;			} /* else process it as a simple group */		}		if (child->type == MOD_UPDATE) {			int rcode;			modgroup *g = mod_callabletogroup(child);			rcode = radius_update_attrlist(request, g->cs,						       g->vps, child->name);			if (rcode != RLM_MODULE_UPDATED) {				myresult = rcode;			}			goto handle_result;		}			if (child->type == MOD_REFERENCE) {			modref *mr = mod_callabletoref(child);			const char *server = request->server;			if (server == mr->ref_name) {				DEBUG("WARNING: Suppressing recursive call to server %s", server);				myresult = RLM_MODULE_NOOP;				goto handle_result;			}						request->server = mr->ref_name;			DEBUG("server %s { # nested call", mr->ref_name);			myresult = indexed_modcall(component, 0, request);			DEBUG("} # server %s with nested call", mr->ref_name);			request->server = server;			goto handle_result;		}		/*		 *	Child is a group that has children of it's own.		 */		if (child->type != MOD_SINGLE) {			int count = 1;			modcallable *p, *q, *null_case;			modgroup *g = mod_callabletogroup(child);			stack.pointer++;			/*			 *	Catastrophic error.  This SHOULD have			 *	been caught when we were reading in the			 *	conf files.			 *			 *	FIXME: Do so.			 */			if (stack.pointer >= MODCALL_STACK_MAX) {				radlog(L_ERR, "Internal sanity check failed: module stack is too deep");				exit(1);			}			stack.priority[stack.pointer] = 0;			stack.result[stack.pointer] = default_component_results[component];			switch (child->type) {				char buffer[1024];			case MOD_IF:			case MOD_ELSE:			case MOD_ELSIF:			case MOD_CASE:			case MOD_GROUP:			case MOD_POLICY: /* same as MOD_GROUP */				stack.children[stack.pointer] = g->children;				break;				/*				 *	See the "camel book" for why				 *	this works.				 *				 *	If (rand(0..n) < 1), pick the				 *	current realm.  We add a scale				 *	factor of 65536, to avoid				 *	floating point.				 */

⌨️ 快捷键说明

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