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

📄 evaluate.c

📁 使用最广泛的radius的linux的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * evaluate.c		Evaluate a policy language * * Version:	$Id: evaluate.c,v 1.20 2008/03/07 10:03:35 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 2004  Alan DeKok <aland@ox.org> * Copyright 2006  The FreeRADIUS server project */#include <freeradius-devel/ident.h>RCSID("$Id: evaluate.c,v 1.20 2008/03/07 10:03:35 aland Exp $")#include "rlm_policy.h"#ifdef HAVE_REGEX_H#include <regex.h>#endif#define debug_evaluate if (0) printf/* *	Print stuff we've parsed */static void policy_print(const policy_item_t *item, int indent){	if (!item) {		if (indent) fprintf(fr_log_fp, "%*s", indent, " ");		fprintf(fr_log_fp, "[NULL]\n");		return;	}	while (item) {		switch (item->type) {		case POLICY_TYPE_BAD:			if (indent) fprintf(fr_log_fp, "%*s", indent, " ");			fprintf(fr_log_fp, "[BAD STATEMENT]");			break;		case POLICY_TYPE_PRINT:			if (indent) fprintf(fr_log_fp, "%*s", indent, " ");			{				const policy_print_t *this;				this = (const policy_print_t *) item;				if (this->rhs_type == POLICY_LEX_BARE_WORD) {					fprintf(fr_log_fp, "print %s\n", this->rhs);				} else {					fprintf(fr_log_fp, "print \"%s\"\n", this->rhs);				}			}			break;		case POLICY_TYPE_ASSIGNMENT:			{				const policy_assignment_t *assign;				assign = (const policy_assignment_t *) item;				if (indent) fprintf(fr_log_fp, "%*s", indent, " ");				fprintf(fr_log_fp, "\t%s %s ", assign->lhs,				       fr_int2str(rlm_policy_tokens,						    assign->assign, "?"));				if (assign->rhs_type == POLICY_LEX_BARE_WORD) {					fprintf(fr_log_fp, "%s\n", assign->rhs);				} else {					/*					 *	FIXME: escape "					 */					fprintf(fr_log_fp, "\"%s\"\n", assign->rhs);				}			}			break;		case POLICY_TYPE_CONDITIONAL: /* no indentation here */			{				const policy_condition_t *condition;				condition = (const policy_condition_t *) item;				fprintf(fr_log_fp, "(");				if (condition->sense) {					fprintf(fr_log_fp, "!");				}				/*				 *	Nested conditions.				 */				if (condition->compare == POLICY_LEX_L_BRACKET) {					policy_print(condition->child, indent);					fprintf(fr_log_fp, ")");					break;				}				if (condition->compare == POLICY_LEX_L_NOT) {					fprintf(fr_log_fp, "!");					policy_print(condition->child, indent);					fprintf(fr_log_fp, ")");					break;				}				if (condition->compare == POLICY_LEX_CMP_TRUE) {					fprintf(fr_log_fp, "%s)", condition->lhs);					break;				}				if (condition->lhs_type == POLICY_LEX_FUNCTION) {					fprintf(fr_log_fp, "%s()", condition->lhs);				} else {					/*					 *	FIXME: escape ",					 *	and move all of this logic					 *	to a function.					 */					fprintf(fr_log_fp, "\"%s\"", condition->lhs);				}				/*				 *	We always print this condition.				 */				fprintf(fr_log_fp, " %s ", fr_int2str(rlm_policy_tokens,							    condition->compare,							    "?"));				if (condition->rhs_type == POLICY_LEX_BARE_WORD) {					fprintf(fr_log_fp, "%s", condition->rhs);				} else {					/*					 *	FIXME: escape ",					 *	and move all of this logic					 *	to a function.					 */					fprintf(fr_log_fp, "\"%s\"", condition->rhs);				}				fprintf(fr_log_fp, ")");				if ((condition->child_condition != POLICY_LEX_BAD) &&				    (condition->child_condition != POLICY_LEX_BARE_WORD)) {					fprintf(fr_log_fp, " %s ", fr_int2str(rlm_policy_tokens, condition->child_condition, "?"));					policy_print(condition->child, indent);				}			}			break;		case POLICY_TYPE_IF:			{				const policy_if_t *statement;				statement = (const policy_if_t *) item;				if (indent) fprintf(fr_log_fp, "%*s", indent, " ");				fprintf(fr_log_fp, "if ");				policy_print(statement->condition, indent);				fprintf(fr_log_fp, " {\n");				policy_print(statement->if_true, indent + 1);				if (indent) fprintf(fr_log_fp, "%*s", indent, " ");				if (statement->if_false) {					fprintf(fr_log_fp, "} else ");					if (statement->if_false->type == POLICY_TYPE_ASSIGNMENT) {						fprintf(fr_log_fp, " { ");						policy_print(statement->if_false, indent + 1);						if (indent) fprintf(fr_log_fp, "%*s", indent, " ");						fprintf(fr_log_fp, " }");					} else {						policy_print(statement->if_false, indent + 1);					}				} else {					fprintf(fr_log_fp, "}\n");				}			}			break;		case POLICY_TYPE_ATTRIBUTE_LIST:			{				const policy_attributes_t *this;				this = (const policy_attributes_t *) item;				if (indent) fprintf(fr_log_fp, "%*s", indent, " ");				fprintf(fr_log_fp, "%s %s {\n",				       fr_int2str(policy_reserved_words,						    this->where, "?"),				       fr_int2str(rlm_policy_tokens,						    this->how, "?"));				policy_print(this->attributes, indent + 1);				if (indent) fprintf(fr_log_fp, "%*s", indent, " ");				fprintf(fr_log_fp, "}\n");			}			break;		case POLICY_TYPE_NAMED_POLICY:			{				const policy_named_t *this;				this = (const policy_named_t *) item;				if (indent) fprintf(fr_log_fp, "%*s", indent, " ");				fprintf(fr_log_fp, "policy %s {\n", this->name);				policy_print(this->policy, indent + 1);				if (indent) fprintf(fr_log_fp, "%*s", indent, " ");				fprintf(fr_log_fp, "}\n");			}			break;		case POLICY_TYPE_CALL:			{				const policy_call_t *this;				this = (const policy_call_t *) item;				if (indent) fprintf(fr_log_fp, "%*s", indent, " ");				fprintf(fr_log_fp, "call %s\n", this->name);			}			break;		case POLICY_TYPE_RETURN:			{				const policy_return_t *this;				this = (const policy_return_t *) item;				if (indent) fprintf(fr_log_fp, "%*s", indent, " ");				fprintf(fr_log_fp, "return %s\n",				       fr_int2str(policy_return_codes,						    this->rcode, "???"));			}			break;		case POLICY_TYPE_MODULE:			{				const policy_module_t *this;				this = (const policy_module_t *) item;				if (indent) fprintf(fr_log_fp, "%*s", indent, " ");				fprintf(fr_log_fp, "module %s <stuff>\n",				       fr_int2str(policy_component_names,						    this->component, "???"));			}			break;		default:			if (indent) fprintf(fr_log_fp, "%*s", indent, " ");			fprintf(fr_log_fp, "[HUH?]\n");			break;		}		item = item->next;	}}void rlm_policy_print(const policy_item_t *item){	if (!fr_log_fp) return;	fprintf(fr_log_fp, "# rlm_policy \n");	policy_print(item, 0);}/* *	Internal stack of things to do.  This lets us have function *	calls... * *	Yes, we should learn lex, yacc, etc. */#define POLICY_MAX_STACK 16typedef struct policy_state_t {	rlm_policy_t	*inst;	REQUEST		*request; /* so it's not passed on the C stack */	int		rcode;	/* for functions, etc. */	int		component; /* for calling other modules */	int		depth;	const policy_item_t *stack[POLICY_MAX_STACK];} policy_state_t;static int policy_evaluate_name(policy_state_t *state, const char *name);/* *	Push an item onto the state. */static int policy_stack_push(policy_state_t *state, const policy_item_t *item){	rad_assert(state->depth >= 0);	/*	 *	Asked to push nothing.  Don't push it.	 */	if (!item) return 1;	/*	 *	State is full.  Die.	 */	if (state->depth >= POLICY_MAX_STACK) {		return 0;	}	/*	 *	Walk back up the stack, looking for previous ocurrances	 *	of this name.  If found, we have infinite recursion,	 *	which we stop dead in the water!	 *	 *	This isn't strictly necessary right now, as we look up	 *	policies by name when they're first referenced.  This	 *	means that ALL references are backwards (to the start	 *	of the file), which means that there are no circular	 *	references.	 */	if (item->type == POLICY_TYPE_NAMED_POLICY) {		int i;		for (i = 0; i < state->depth; i++) {			/*			 *	Check for circular references, by seeing			 *	if the function is already on the stack.			 *			 *	Hmmm... do we want to do this for any type?			 */			if (state->stack[i] == item) {				debug_evaluate("Circular call to policy %s\n",					       ((const policy_named_t *) item)->name);				return 0;			}		}	}	debug_evaluate("push %d %p\n", state->depth, item);	state->stack[state->depth] = item;	state->depth++;		/* points to unused entry */	return 1;}/* *	Pop an item from the state. */static int policy_stack_pop(policy_state_t *state, const policy_item_t **pitem){	rad_assert(pitem != NULL);	rad_assert(state->depth >= 0); redo:	if (state->depth == 0) {		*pitem = NULL;		return 0;	}	*pitem = state->stack[state->depth - 1];	/*	 *	Named policies are on the stack for catching recursion.	 */	if ((*pitem)->type == POLICY_TYPE_NAMED_POLICY) {		state->depth--;		goto redo;	}	/*	 *	Process the whole item list.	 */	if ((*pitem)->next) {		state->stack[state->depth - 1] = (*pitem)->next;		debug_evaluate("pop/push %d %p\n", state->depth - 1, *pitem);	} else {		state->depth--;		/* points to unused entry */		debug_evaluate("pop %d %p\n", state->depth, *pitem);	}	return 1;}/* *	Evaluate a print statement */static int evaluate_print(policy_state_t *state, const policy_item_t *item){	const policy_print_t *this;	if (!fr_log_fp) return 1;	this = (const policy_print_t *) item;	if (this->rhs_type == POLICY_LEX_BARE_WORD) {		fprintf(fr_log_fp, "%s\n", this->rhs);	} else {		char buffer[1024];		radius_xlat(buffer, sizeof(buffer), this->rhs,			    state->request, NULL);		fprintf(fr_log_fp, "%s", buffer);		if (!strchr(buffer, '\n')) fprintf(fr_log_fp, "\n");	}	/*	 *	Doesn't change state->rcode	 */	return 1;}/* *	Return a VALUE_PAIR, given an attribute name. * *	FIXME: Have it return the N'th one, too, like *	doc/variables.txt? * *	The amount of duplicated code is getting annoying... */static VALUE_PAIR *find_vp(REQUEST *request, const char *name){	const char *p;	const DICT_ATTR *dattr;	VALUE_PAIR *vps;	p = name;	vps = request->packet->vps;;	/*	 *	FIXME: use names from reserved word list?	 */	if (strncasecmp(name, "request:", 8) == 0) {		p += 8;	} else if (strncasecmp(name, "reply:", 6) == 0) {		p += 6;		vps = request->reply->vps;	} else if (strncasecmp(name, "proxy-request:", 14) == 0) {		p += 14;		if (request->proxy) {			vps = request->proxy->vps;		}	} else if (strncasecmp(name, "proxy-reply:", 12) == 0) {		p += 12;		if (request->proxy_reply) {			vps = request->proxy_reply->vps;		}	} else if (strncasecmp(name, "control:", 8) == 0) {		p += 8;		vps = request->config_items;	} /* else it must be a bare attribute name */	if (!vps) {		return NULL;	}	dattr = dict_attrbyname(p);	if (!dattr) {		fprintf(stderr, "No such attribute %s\n", p);		return NULL;	/* no such attribute */	}	return pairfind(vps, dattr->attr);}/* *	Evaluate an assignment * *	Not really used much... */static int evaluate_assignment(UNUSED policy_state_t *state, const policy_item_t *item){	const policy_assignment_t *this;#if 0	const DICT_ATTR *dattr;#endif	this = (const policy_assignment_t *) item;	rad_assert(this->lhs != NULL);	rad_assert(this->rhs != NULL);#if 0	dattr = dict_attrbyname(this->lhs);	if (!dattr) {		fprintf(stderr, "HUH?\n");		return 0;	}#endif	return 1;}/* *	Evaluate a condition */static int evaluate_condition(policy_state_t *state, const policy_item_t *item){	int rcode;	const policy_condition_t *this;	VALUE_PAIR *vp = NULL;	const char *data = NULL;	int compare;#ifdef HAVE_REGEX_H	regex_t reg;#endif	char buffer[256];	char lhs_buffer[2048];	this = (const policy_condition_t *) item; redo:	/*	 *	FIXME: Don't always do this...	 */	if (this->compare != POLICY_LEX_L_BRACKET) {		if (this->lhs_type == POLICY_LEX_FUNCTION) {			/*			 *	We can't call evaluate_call here,			 *	because that just pushes stuff onto			 *	the stack, and we want to actually			 *	evaluate all of it...			 */			rcode = policy_evaluate_name(state, this->lhs);			data = fr_int2str(policy_return_codes, rcode, "???");			strlcpy(lhs_buffer, data, sizeof(lhs_buffer)); /* FIXME: yuck */		} else if (this->lhs_type == POLICY_LEX_DOUBLE_QUOTED_STRING) {			if (radius_xlat(lhs_buffer, sizeof(lhs_buffer), this->lhs,					state->request, NULL) > 0) {				data = lhs_buffer;			}		}	}	switch (this->compare) {	case POLICY_LEX_L_BRACKET: /* nested brackets are a special case */		rcode = evaluate_condition(state, this->child);		break;	case POLICY_LEX_L_NOT:		rcode = evaluate_condition(state, this->child);		rcode = (rcode == FALSE); /* reverse sense of test */		break;	case POLICY_LEX_CMP_FALSE: /* non-existence */		if (this->lhs_type == POLICY_LEX_BARE_WORD) {			vp = find_vp(state->request, this->lhs);			rcode = (vp == NULL);		} else {			rcode = (data == NULL);		}		break;	case POLICY_LEX_CMP_TRUE: /* existence */		if (this->lhs_type == POLICY_LEX_BARE_WORD) {			vp = find_vp(state->request, this->lhs);			rcode = (vp != NULL);		} else {			rcode = (data != NULL);		}		break;	default:		/* process other comparisons */		if ((this->compare != POLICY_LEX_CMP_EQUALS) &&#ifdef HAVE_REGEX_H		    (this->compare != POLICY_LEX_RX_EQUALS) &&		    (this->compare != POLICY_LEX_RX_NOT_EQUALS) &&#endif		    (this->compare != POLICY_LEX_LT) &&		    (this->compare != POLICY_LEX_GT) &&		    (this->compare != POLICY_LEX_LE) &&		    (this->compare != POLICY_LEX_GE) &&		    (this->compare != POLICY_LEX_CMP_NOT_EQUALS)) {			fprintf(stderr, "%d: bad comparison\n",				this->item.lineno);			return FALSE;		}		if (this->lhs_type == POLICY_LEX_BARE_WORD) {			VALUE_PAIR *myvp;			vp = find_vp(state->request, this->lhs);			/*			 *	A op B is FALSE if A doesn't			 *	exist.			 */			if (!vp) {				rcode = FALSE;				break;			}			/*			 *	FIXME: Move sanity checks to			 *	post-parse code, so we don't do			 *	it on every packet.			 */			vp_prints_value(buffer, sizeof(buffer), vp, 0);			myvp = pairmake(vp->name, this->rhs, T_OP_EQ);			if (!myvp) return FALSE; /* memory failure */			data = buffer;			/*			 *	FIXME: What to do about comparisons			 *	where vp doesn't exist?  Right now,			 *	"simplepaircmp" returns -1, which is			 *	probably a bad idea.  it should

⌨️ 快捷键说明

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