#include <freeradius-devel/ident.h>
RCSID("$Id$")
#include "rlm_policy.h"
#ifdef HAVE_REGEX_H
#include <regex.h>
#endif
#define debug_evaluate if (0) printf
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 {
fprintf(fr_log_fp, "\"%s\"\n", assign->rhs);
}
}
break;
case POLICY_TYPE_CONDITIONAL:
{
const policy_condition_t *condition;
condition = (const policy_condition_t *) item;
fprintf(fr_log_fp, "(");
if (condition->sense) {
fprintf(fr_log_fp, "!");
}
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 {
fprintf(fr_log_fp, "\"%s\"", condition->lhs);
}
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 {
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);
}
#define POLICY_MAX_STACK 16
typedef struct policy_state_t {
rlm_policy_t *inst;
REQUEST *request;
int rcode;
int component;
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);
static int policy_stack_push(policy_state_t *state, const policy_item_t *item)
{
rad_assert(state->depth >= 0);
if (!item) return 1;
if (state->depth >= POLICY_MAX_STACK) {
return 0;
}
if (item->type == POLICY_TYPE_NAMED_POLICY) {
int i;
for (i = 0; i < state->depth; i++) {
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++;
return 1;
}
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];
if ((*pitem)->type == POLICY_TYPE_NAMED_POLICY) {
state->depth--;
goto redo;
}
if ((*pitem)->next) {
state->stack[state->depth - 1] = (*pitem)->next;
debug_evaluate("pop/push %d %p\n", state->depth - 1, *pitem);
} else {
state->depth--;
debug_evaluate("pop %d %p\n", state->depth, *pitem);
}
return 1;
}
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");
}
return 1;
}
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;;
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;
}
if (!vps) {
return NULL;
}
dattr = dict_attrbyname(p);
if (!dattr) {
fprintf(stderr, "No such attribute %s\n", p);
return NULL;
}
return pairfind(vps, dattr->attr);
}
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;
}
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:
if (this->compare != POLICY_LEX_L_BRACKET) {
if (this->lhs_type == POLICY_LEX_FUNCTION) {
rcode = policy_evaluate_name(state, this->lhs);
data = fr_int2str(policy_return_codes, rcode, "???");
strlcpy(lhs_buffer, data, sizeof(lhs_buffer));
} 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:
rcode = evaluate_condition(state, this->child);
break;
case POLICY_LEX_L_NOT:
rcode = evaluate_condition(state, this->child);
rcode = (rcode == FALSE);
break;
case POLICY_LEX_CMP_FALSE:
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:
if (this->lhs_type == POLICY_LEX_BARE_WORD) {
vp = find_vp(state->request, this->lhs);
rcode = (vp != NULL);
} else {
rcode = (data != NULL);
}
break;
default:
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);
if (!vp) {
rcode = FALSE;
break;
}
vp_prints_value(buffer, sizeof(buffer), vp, 0);
myvp = pairmake(vp->name, this->rhs, T_OP_EQ);
if (!myvp) return FALSE;
data = buffer;
compare = radius_callback_compare(state->request,
vp, myvp, NULL, NULL);
pairfree(&myvp);
} else {
fr_printf_log("CMP %s %s\n", lhs_buffer, this->rhs);
compare = strcmp(lhs_buffer, this->rhs);
}
debug_evaluate("CONDITION COMPARE %d\n", compare);
switch (this->compare) {
case POLICY_LEX_CMP_EQUALS:
rcode = (compare == 0);
break;
case POLICY_LEX_CMP_NOT_EQUALS:
rcode = (compare != 0);
break;
case POLICY_LEX_LT:
rcode = (compare < 0);
break;
case POLICY_LEX_GT:
rcode = (compare > 0);
break;
case POLICY_LEX_LE:
rcode =(compare <= 0);
break;
case POLICY_LEX_GE:
rcode = (compare >= 0);
break;
#ifdef HAVE_REGEX_H
case POLICY_LEX_RX_EQUALS:
{
int i;
regmatch_t rxmatch[REQUEST_MAX_REGEX + 1];
if (regcomp(®, this->rhs,
REG_EXTENDED) != 0) {
return FALSE;
}
rad_assert(data != NULL);
rcode = regexec(®, data,
REQUEST_MAX_REGEX + 1,
rxmatch, 0);
rcode = (rcode == 0);
regfree(®);
for (i = 0; i <= REQUEST_MAX_REGEX; i++) {
char *p;
char rxbuffer[256];
if (!rcode ||
(rxmatch[i].rm_so == -1)) {
p = request_data_get(state->request, state->request,
REQUEST_DATA_REGEX | i);
if (p) {
free(p);
continue;
}
break;
}
memcpy(rxbuffer,
data + rxmatch[i].rm_so,
rxmatch[i].rm_eo - rxmatch[i].rm_so);
rxbuffer[rxmatch[i].rm_eo - rxmatch[i].rm_so] = '\0';
p = strdup(rxbuffer);
request_data_add(state->request,
state->request,
REQUEST_DATA_REGEX | i,
p, free);
}
}
break;
case POLICY_LEX_RX_NOT_EQUALS:
regcomp(®, this->rhs, REG_EXTENDED|REG_NOSUB);
rad_assert(data != NULL);
rcode = regexec(®, data,
0, NULL, 0);
rcode = (rcode != 0);
regfree(®);
break;
#endif
default:
rcode = FALSE;
break;
}
break;
}
if (this->sense) rcode = (rcode == FALSE);
switch (this->child_condition) {
default:
return rcode;
case POLICY_LEX_L_AND:
if (!rcode) return rcode;
break;
case POLICY_LEX_L_OR:
if (rcode) return rcode;
break;
}
this = (const policy_condition_t *) this->child;
goto redo;
return 1;
}
static int evaluate_if(policy_state_t *state, const policy_item_t *item)
{
int rcode;
const policy_if_t *this;
this = (const policy_if_t *) item;
rcode = evaluate_condition(state, this->condition);
debug_evaluate("IF condition returned %s\n",
rcode ? "true" : "false");
if (rcode) {
rcode = policy_stack_push(state, this->if_true);
if (!rcode) return rcode;
} else if (this->if_false) {
rcode = policy_stack_push(state, this->if_false);
if (!rcode) return rcode;
}
return 1;;
}
static VALUE_PAIR *assign2vp(REQUEST *request,
const policy_assignment_t *assign)
{
VALUE_PAIR *vp;
FR_TOKEN operator = T_OP_EQ;
const char *value = assign->rhs;
char buffer[2048];
if ((assign->rhs_type == POLICY_LEX_DOUBLE_QUOTED_STRING) &&
(strchr(assign->rhs, '%') != NULL)) {
radius_xlat(buffer, sizeof(buffer), assign->rhs,
request, NULL);
value = buffer;
}
switch (assign->assign) {
case POLICY_LEX_ASSIGN:
operator = T_OP_EQ;
break;
case POLICY_LEX_SET_EQUALS:
operator = T_OP_SET;
break;
case POLICY_LEX_PLUS_EQUALS:
operator = T_OP_ADD;
break;
default:
fprintf(stderr, "Expected '=' for operator, not '%s' at line %d\n",
fr_int2str(rlm_policy_tokens,
assign->assign, "?"),
assign->item.lineno);
return NULL;
}
vp = pairmake(assign->lhs, value, operator);
if (!vp) {
fprintf(stderr, "Failed creating pair: %s %s\n", value, fr_strerror());
}
return vp;
}
static int evaluate_attr_list(policy_state_t *state, const policy_item_t *item)
{
const policy_attributes_t *this;
VALUE_PAIR **vps = NULL;
VALUE_PAIR *vp, *head, **tail;
const policy_item_t *attr;
policy_lex_t this_how;
this = (const policy_attributes_t *) item;
switch (this->where) {
case POLICY_RESERVED_CONTROL:
vps = &(state->request->config_items);
break;
case POLICY_RESERVED_REQUEST:
vps = &(state->request->packet->vps);
break;
case POLICY_RESERVED_REPLY:
vps = &(state->request->reply->vps);
break;
case POLICY_RESERVED_PROXY_REQUEST:
if (!state->request->proxy) return 0;
vps = &(state->request->proxy->vps);
break;
case POLICY_RESERVED_PROXY_REPLY:
if (!state->request->proxy_reply) return 0;
vps = &(state->request->proxy_reply->vps);
break;
default:
return 0;
}
head = NULL;
tail = &head;
for (attr = this->attributes; attr != NULL; attr = attr->next) {
if (attr->type != POLICY_TYPE_ASSIGNMENT) {
fprintf(stderr, "bad assignment in attribute list at line %d\n", attr->lineno);
pairfree(&head);
return 0;
}
vp = assign2vp(state->request, (const policy_assignment_t *) attr);
if (!vp) {
fprintf(stderr, "Failed to allocate VP\n");
pairfree(&head);
return 0;
}
*tail = vp;
tail = &(vp->next);
}
this_how = this->how;
retry_how:
switch (this_how) {
case POLICY_LEX_SET_EQUALS:
pairfree(vps);
*vps = head;
break;
case POLICY_LEX_AFTER_TAIL_ASSIGN:
pairmove(vps, &head);
pairfree(&head);
break;
case POLICY_LEX_ASSIGN:
pairmove(vps, &head);
pairfree(&head);
break;
case POLICY_LEX_BEFORE_HEAD_ASSIGN:
pairmove(&head, vps);
pairfree(vps);
*vps = head;
break;
case POLICY_LEX_AFTER_TAIL_EQUALS:
case POLICY_LEX_CONCAT_EQUALS:
pairadd(vps, head);
break;
case POLICY_LEX_BEFORE_HEAD_EQUALS:
pairadd(&head, *vps);
*vps = head;
break;
case POLICY_LEX_BEFORE_WHERE_EQUALS:
case POLICY_LEX_AFTER_WHERE_EQUALS:
case POLICY_LEX_BEFORE_WHERE_ASSIGN:
case POLICY_LEX_AFTER_WHERE_ASSIGN:
{
VALUE_PAIR *vpprev = NULL, *vpnext = NULL, *lvp;
for(lvp = *vps; lvp; vpprev = lvp, lvp = lvp->next) {
vpnext = lvp->next;
lvp->next = NULL;
if (evaluate_condition(state, this->where_loc))
break;
lvp->next = vpnext;
}
if (lvp) {
switch(this_how) {
case POLICY_LEX_BEFORE_WHERE_EQUALS:
case POLICY_LEX_BEFORE_WHERE_ASSIGN:
if (vpprev) {
lvp->next = vpnext;
vpnext = lvp;
vpprev->next = NULL;
lvp = vpprev;
}
default:
break;
}
switch(this_how) {
case POLICY_LEX_BEFORE_WHERE_EQUALS:
if (vpprev)
pairadd(&lvp, head);
else
*vps = lvp = head;
break;
case POLICY_LEX_AFTER_WHERE_EQUALS:
pairadd(&lvp, head);
break;
case POLICY_LEX_BEFORE_WHERE_ASSIGN:
if (vpprev) {
pairmove(&lvp, &head);
pairfree(&head);
}
else
*vps = lvp = head;
break;
case POLICY_LEX_AFTER_WHERE_ASSIGN:
pairmove(&lvp, &head);
pairfree(&head);
break;
default:
break;
}
for( ; lvp && lvp->next; lvp = lvp->next);
if (lvp)
lvp->next = vpnext;
break;
}
switch(this_how) {
case POLICY_LEX_BEFORE_WHERE_EQUALS:
this_how = POLICY_LEX_BEFORE_HEAD_EQUALS;
break;
case POLICY_LEX_AFTER_WHERE_EQUALS:
this_how = POLICY_LEX_AFTER_TAIL_EQUALS;
break;
case POLICY_LEX_BEFORE_WHERE_ASSIGN:
this_how = POLICY_LEX_BEFORE_HEAD_ASSIGN;
break;
case POLICY_LEX_AFTER_WHERE_ASSIGN:
this_how = POLICY_LEX_AFTER_TAIL_ASSIGN;
break;
default:
break;
}
goto retry_how;
}
default:
fprintf(stderr, "HUH?\n");
pairfree(&head);
return 0;
}
state->rcode = RLM_MODULE_UPDATED;
return 1;
}
static int evaluate_call(policy_state_t *state, const policy_item_t *item)
{
int rcode;
const policy_call_t *this;
const policy_named_t *policy;
this = (const policy_call_t *) item;
policy = rlm_policy_find(state->inst->policies, this->name);
if (!policy) return 0;
DEBUG2("rlm_policy: Evaluating policy %s", this->name);
rad_assert(policy->policy->type != POLICY_TYPE_BAD);
rad_assert(policy->policy->type < POLICY_TYPE_NUM_TYPES);
rcode = policy_stack_push(state, (const policy_item_t *) policy);
if (!rcode) {
return rcode;
}
rcode = policy_stack_push(state, policy->policy);
if (!rcode) {
return rcode;
}
return 1;
}
static int evaluate_return(policy_state_t *state, const policy_item_t *item)
{
const policy_return_t *this;
this = (const policy_return_t *) item;
state->rcode = this->rcode;
return 1;
}
static int evaluate_module(policy_state_t *state, const policy_item_t *item)
{
const policy_module_t *this;
this = (const policy_module_t *) item;
if (this->component != state->component) {
DEBUG2("rlm_policy: Cannot mix & match components");
return 0;
}
DEBUG2("rlm_policy: begin nested call");
state->rcode = modcall(this->component, this->mc, state->request);
DEBUG2("rlm_policy: end nested call");
return 1;
}
typedef int (*policy_evaluate_type_t)(policy_state_t *, const policy_item_t *);
static policy_evaluate_type_t evaluate_functions[POLICY_TYPE_NUM_TYPES] = {
NULL,
evaluate_if,
evaluate_condition,
evaluate_assignment,
evaluate_attr_list,
evaluate_print,
NULL,
evaluate_call,
evaluate_return,
evaluate_module
};
static int policy_evaluate_name(policy_state_t *state, const char *name)
{
int rcode;
const policy_item_t *this;
policy_named_t mypolicy, *policy;
mypolicy.name = name;
policy = rbtree_finddata(state->inst->policies, &mypolicy);
if (!policy) return RLM_MODULE_FAIL;
DEBUG2("rlm_policy: Evaluating policy %s", name);
rad_assert(policy->item.type != POLICY_TYPE_BAD);
rad_assert(policy->item.type < POLICY_TYPE_NUM_TYPES);
rcode = policy_stack_push(state, policy->policy);
if (!rcode) {
return RLM_MODULE_FAIL;
}
while (policy_stack_pop(state, &this)) {
rad_assert(this != NULL);
rad_assert(this->type != POLICY_TYPE_BAD);
rad_assert(this->type < POLICY_TYPE_NUM_TYPES);
debug_evaluate("Evaluating at line %d\n",
this->lineno);
rcode = (*evaluate_functions[this->type])(state,
this);
if (!rcode) {
return RLM_MODULE_FAIL;
}
}
return state->rcode;
}
int rlm_policy_evaluate(rlm_policy_t *inst, REQUEST *request, const char *name)
{
int rcode;
policy_state_t *state;
state = rad_malloc(sizeof(*state));
memset(state, 0, sizeof(*state));
state->request = request;
state->inst = inst;
state->rcode = RLM_MODULE_OK;
state->component = fr_str2int(policy_component_names, name,
RLM_COMPONENT_COUNT);
rcode = policy_evaluate_name(state, name);
free(state);
return rcode;
}