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

📄 modcall.c

📁 新的radius程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * modcall.c * * Version:	$Id: modcall.c,v 1.22.2.1.2.4 2007/06/12 09:31:45 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 2000  The FreeRADIUS server project */#include <stdlib.h>#include <string.h>#include <stdarg.h>#include "radiusd.h"#include "rad_assert.h"#include "conffile.h"#include "modpriv.h"#include "modules.h"#include "modcall.h"/* mutually-recursive static functions need a prototype up front */static modcallable *do_compile_modgroup(int, CONF_SECTION *, const char *,		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 {	struct modcallable *next;	const char *name;	int actions[RLM_MODULE_NUMCODES];	enum { MOD_SINGLE, MOD_GROUP, MOD_LOAD_BALANCE, MOD_REDUNDANT_LOAD_BALANCE  } type;};#define GROUPTYPE_SIMPLE	0#define GROUPTYPE_REDUNDANT	1#define GROUPTYPE_APPEND	2#define GROUPTYPE_COUNT		3typedef struct {	modcallable mc;	int grouptype;	modcallable *children;} modgroup;typedef struct {	modcallable mc;	module_instance_t *modinst;} modsingle;static const LRAD_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_GROUP) ||		   (p->type==MOD_LOAD_BALANCE) ||		   (p->type==MOD_REDUNDANT_LOAD_BALANCE));	return (modgroup *)p;}static modcallable *mod_singletocallable(modsingle *p){	return (modcallable *)p;}static modcallable *mod_grouptocallable(modgroup *p){	return (modcallable *)p;}/* modgroups are grown by adding a modcallable to the end */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;}/* Here's where we recognize all of our keywords: first the rcodes, then the * actions */static const LRAD_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, const char *attr, const char *value,			  const char *filename, int lineno){	int rcode, action;	rcode = lrad_str2int(rcode_table, attr, -1);	if (rcode < 0) {		radlog(L_ERR|L_CONS,		       "%s[%d] Unknown module rcode '%s'.\n",		       filename, lineno, attr);		return 0;	}	if (!strcasecmp(value, "return"))		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 {		radlog(L_ERR|L_CONS,		       "%s[%d] Unknown action '%s'.\n",		       filename, lineno, value);		return 0;	}	c->actions[rcode] = action;	return 1;}#if 0static const char *action2str(int action){	static char buf[32];	if(action==MOD_ACTION_RETURN)		return "return";	if(action==MOD_ACTION_REJECT)		return "reject";	snprintf(buf, sizeof buf, "%d", action);	return buf;}#endif/* Some short names for debugging output */static const char *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);	request->component = comp2str[component];	request->module = sp->modinst->entry->name;	safe_lock(sp->modinst);	myresult = sp->modinst->entry->module->methods[component](			sp->modinst->insthandle, request);	safe_unlock(sp->modinst);	request->module = "<server core>";	DEBUG3("  modsingle[%s]: returned from %s (%s) for request %d",	       comp2str[component], sp->modinst->name,	       sp->modinst->entry->name, request->number);	return myresult;}/* *	Helper function for call_modgroup, and call_modredundantloadbalance * *	Returns 0 for "stop", and "1" for continue. */static int call_one(int component, modcallable *p, REQUEST *request,		    int *priority, int *result){	int r;#ifdef RAD_REQUEST_OPTION_STOP_NOW	/*	 *	A module has taken too long to process the request,	 *	and we've been told to stop processing it.	 */	if (request->options & RAD_REQUEST_OPTION_STOP_NOW) {		*result = RLM_MODULE_FAIL;		return 0;	}#endif		/* Call this child by recursing into modcall */	r = modcall(component, p, request);	#if 0	DEBUG2("%s: action for %s is %s",	       comp2str[component], lrad_int2str(rcode_table, r, "??"),	       action2str(p->actions[r]));#endif		/*	 * 	Find an action to go with the child's result. If it is	 * 	"return", break out of the loop so the rest of the	 * 	children in the list will be skipped.	 */	if (p->actions[r] == MOD_ACTION_RETURN) {		*result = r;		return 0;	}		/* If "reject" break out of the loop and return reject */	if (p->actions[r] == MOD_ACTION_REJECT) {		*result = RLM_MODULE_REJECT;		return 0;	}		/*	 *	Otherwise, the action is a number, the preference	 *	level of this return code. If no higher preference has	 *	been seen yet, remember this one	 . */	if (p->actions[r] >= *priority) {		*result = r;		*priority = p->actions[r];	}		return 1;}static int call_modgroup(int component, modgroup *g, REQUEST *request,			 int default_result){	int myresult = default_result;	int priority = 0;	/* default result has lowest priority  */	modcallable *p;	/*	 *	Catch people who have issues.	 */	if (!g->children) {		DEBUG2("  WARNING! Asked to process empty group.  Returning %s.", lrad_int2str(rcode_table, myresult, "??"));		return default_result;	}	/* Loop over the children */	for (p = g->children; p; p = p->next) {		if (!call_one(component, p, request, &priority, &myresult)) {			break;		}	}	return myresult;}static int call_modloadbalance(int component, modgroup *g, REQUEST *request,			       int default_result){	int count = 1;	modcallable *p, *child = NULL;	/*	 *	Catch people who have issues.	 */	if (!g->children) {		DEBUG2("  WARNING! Asked to process empty load-balance group.  Returning %s.", lrad_int2str(rcode_table, default_result, "??"));		return default_result;	}	/*	 *	Pick a random child.	 */	/* Loop over the children */	for(p = g->children; p; p = p->next) {		if (!child) {			child = p;			count = 1;			continue;		}		/*		 *	Keep track of how many load balancing servers		 *	we've gone through.		 */		count++;		/*		 *	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.		 */		if ((count * (lrad_rand() & 0xffff)) < (uint32_t) 0x10000) {			child = p;		}	}	rad_assert(child != NULL);	/* Call the chosen child by recursing into modcall */	return modcall(component, child, request);}/* *	For more than 2 modules with redundancy + load balancing *	across all of them, layering the "redundant" and *	"load-balance" groups gets too complicated.  As a result, we *	implement a special function to do this. */static int call_modredundantloadbalance(int component, modgroup *g, REQUEST *request,					int default_result){	int count = 1;	int myresult = default_result;	int priority = 0;	/* default result has lowest priority  */	modcallable *p, *child = NULL;	/*	 *	Catch people who have issues.	 */	if (!g->children) {		DEBUG2("  WARNING! Asked to process empty redundant-load-balance group.  Returning %s.", lrad_int2str(rcode_table, default_result, "??"));		return default_result;	}	/*	 *	Pick a random child.	 */	/* Loop over the children */	for(p = g->children; p; p = p->next) {		if (!child) {			child = p;			count = 1;			continue;

⌨️ 快捷键说明

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