2 * evaluate.c Evaluate a policy language
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2004 Alan DeKok <aland@ox.org>
21 * Copyright 2006 The FreeRADIUS server project
24 #include <freeradius-devel/ident.h>
27 #include "rlm_policy.h"
33 #define debug_evaluate if (0) printf
36 * Print stuff we've parsed
38 static void policy_print(const policy_item_t *item, int indent)
41 if (indent) printf("%*s", indent, " ");
49 if (indent) printf("%*s", indent, " ");
50 printf("[BAD STATEMENT]");
53 case POLICY_TYPE_PRINT:
54 if (indent) printf("%*s", indent, " ");
56 const policy_print_t *this;
58 this = (const policy_print_t *) item;
60 if (this->rhs_type == POLICY_LEX_BARE_WORD) {
61 printf("print %s\n", this->rhs);
63 printf("print \"%s\"\n", this->rhs);
68 case POLICY_TYPE_ASSIGNMENT:
70 const policy_assignment_t *assign;
72 assign = (const policy_assignment_t *) item;
73 if (indent) printf("%*s", indent, " ");
75 printf("\t%s %s ", assign->lhs,
76 fr_int2str(rlm_policy_tokens,
77 assign->assign, "?"));
78 if (assign->rhs_type == POLICY_LEX_BARE_WORD) {
79 printf("%s\n", assign->rhs);
84 printf("\"%s\"\n", assign->rhs);
89 case POLICY_TYPE_CONDITIONAL: /* no indentation here */
91 const policy_condition_t *condition;
93 condition = (const policy_condition_t *) item;
100 if (condition->compare == POLICY_LEX_L_BRACKET) {
101 policy_print(condition->child, indent);
106 if (condition->compare == POLICY_LEX_L_NOT) {
108 policy_print(condition->child, indent);
113 if (condition->compare == POLICY_LEX_CMP_TRUE) {
114 printf("%s)", condition->lhs);
118 if (condition->lhs_type == POLICY_LEX_FUNCTION) {
119 printf("%s()", condition->lhs);
123 * and move all of this logic
126 printf("\"%s\"", condition->lhs);
130 * We always print this condition.
132 printf(" %s ", fr_int2str(rlm_policy_tokens,
135 if (condition->rhs_type == POLICY_LEX_BARE_WORD) {
136 printf("%s", condition->rhs);
140 * and move all of this logic
143 printf("\"%s\"", condition->rhs);
147 if ((condition->child_condition != POLICY_LEX_BAD) &&
148 (condition->child_condition != POLICY_LEX_BARE_WORD)) {
149 printf(" %s ", fr_int2str(rlm_policy_tokens, condition->child_condition, "?"));
150 policy_print(condition->child, indent);
157 const policy_if_t *statement;
159 statement = (const policy_if_t *) item;
161 if (indent) printf("%*s", indent, " ");
163 policy_print(statement->condition, indent);
165 policy_print(statement->if_true, indent + 1);
166 if (indent) printf("%*s", indent, " ");
167 if (statement->if_false) {
169 if (statement->if_false->type == POLICY_TYPE_ASSIGNMENT) {
171 policy_print(statement->if_false, indent + 1);
172 if (indent) printf("%*s", indent, " ");
175 policy_print(statement->if_false, indent + 1);
183 case POLICY_TYPE_ATTRIBUTE_LIST:
185 const policy_attributes_t *this;
187 this = (const policy_attributes_t *) item;
189 if (indent) printf("%*s", indent, " ");
191 fr_int2str(policy_reserved_words,
193 fr_int2str(rlm_policy_tokens,
195 policy_print(this->attributes, indent + 1);
196 if (indent) printf("%*s", indent, " ");
201 case POLICY_TYPE_NAMED_POLICY:
203 const policy_named_t *this;
205 this = (const policy_named_t *) item;
206 if (indent) printf("%*s", indent, " ");
207 printf("policy %s {\n", this->name);
208 policy_print(this->policy, indent + 1);
209 if (indent) printf("%*s", indent, " ");
214 case POLICY_TYPE_CALL:
216 const policy_call_t *this;
218 this = (const policy_call_t *) item;
219 if (indent) printf("%*s", indent, " ");
220 printf("call %s\n", this->name);
224 case POLICY_TYPE_RETURN:
226 const policy_return_t *this;
228 this = (const policy_return_t *) item;
229 if (indent) printf("%*s", indent, " ");
230 printf("return %s\n",
231 fr_int2str(policy_return_codes,
232 this->rcode, "???"));
236 case POLICY_TYPE_MODULE:
238 const policy_module_t *this;
240 this = (const policy_module_t *) item;
241 if (indent) printf("%*s", indent, " ");
242 printf("module %s <stuff>\n",
243 fr_int2str(policy_component_names,
244 this->component, "???"));
249 if (indent) printf("%*s", indent, " ");
260 void rlm_policy_print(const policy_item_t *item)
262 printf("----------------------------------------------------------\n");
263 policy_print(item, 0);
264 printf("----------------------------------------------------------\n");
268 * Internal stack of things to do. This lets us have function
271 * Yes, we should learn lex, yacc, etc.
273 #define POLICY_MAX_STACK 16
274 typedef struct policy_state_t {
276 REQUEST *request; /* so it's not passed on the C stack */
277 int rcode; /* for functions, etc. */
278 int component; /* for calling other modules */
280 const policy_item_t *stack[POLICY_MAX_STACK];
284 static int policy_evaluate_name(policy_state_t *state, const char *name);
287 * Push an item onto the state.
289 static int policy_stack_push(policy_state_t *state, const policy_item_t *item)
291 rad_assert(state->depth >= 0);
294 * Asked to push nothing. Don't push it.
299 * State is full. Die.
301 if (state->depth >= POLICY_MAX_STACK) {
306 * Walk back up the stack, looking for previous ocurrances
307 * of this name. If found, we have infinite recursion,
308 * which we stop dead in the water!
310 * This isn't strictly necessary right now, as we look up
311 * policies by name when they're first referenced. This
312 * means that ALL references are backwards (to the start
313 * of the file), which means that there are no circular
316 if (item->type == POLICY_TYPE_NAMED_POLICY) {
319 for (i = 0; i < state->depth; i++) {
321 * Check for circular references, by seeing
322 * if the function is already on the stack.
324 * Hmmm... do we want to do this for any type?
326 if (state->stack[i] == item) {
327 debug_evaluate("Circular call to policy %s\n",
328 ((const policy_named_t *) item)->name);
334 debug_evaluate("push %d %p\n", state->depth, item);
336 state->stack[state->depth] = item;
337 state->depth++; /* points to unused entry */
344 * Pop an item from the state.
346 static int policy_stack_pop(policy_state_t *state, const policy_item_t **pitem)
348 rad_assert(pitem != NULL);
349 rad_assert(state->depth >= 0);
352 if (state->depth == 0) {
357 *pitem = state->stack[state->depth - 1];
360 * Named policies are on the stack for catching recursion.
362 if ((*pitem)->type == POLICY_TYPE_NAMED_POLICY) {
368 * Process the whole item list.
370 if ((*pitem)->next) {
371 state->stack[state->depth - 1] = (*pitem)->next;
372 debug_evaluate("pop/push %d %p\n", state->depth - 1, *pitem);
374 state->depth--; /* points to unused entry */
375 debug_evaluate("pop %d %p\n", state->depth, *pitem);
383 * Evaluate a print statement
385 static int evaluate_print(policy_state_t *state, const policy_item_t *item)
387 const policy_print_t *this;
389 this = (const policy_print_t *) item;
391 if (this->rhs_type == POLICY_LEX_BARE_WORD) {
392 printf("%s\n", this->rhs);
396 radius_xlat(buffer, sizeof(buffer), this->rhs,
397 state->request, NULL);
398 printf("%s", buffer);
402 * Doesn't change state->rcode
409 * Return a VALUE_PAIR, given an attribute name.
411 * FIXME: Have it return the N'th one, too, like
414 * The amount of duplicated code is getting annoying...
416 static VALUE_PAIR *find_vp(REQUEST *request, const char *name)
419 const DICT_ATTR *dattr;
423 vps = request->packet->vps;;
426 * FIXME: use names from reserved word list?
428 if (strncasecmp(name, "request:", 8) == 0) {
430 } else if (strncasecmp(name, "reply:", 6) == 0) {
432 vps = request->reply->vps;
433 } else if (strncasecmp(name, "proxy-request:", 14) == 0) {
435 if (request->proxy) {
436 vps = request->proxy->vps;
438 } else if (strncasecmp(name, "proxy-reply:", 12) == 0) {
440 if (request->proxy_reply) {
441 vps = request->proxy_reply->vps;
443 } else if (strncasecmp(name, "control:", 8) == 0) {
445 vps = request->config_items;
446 } /* else it must be a bare attribute name */
452 dattr = dict_attrbyname(p);
454 fprintf(stderr, "No such attribute %s\n", p);
455 return NULL; /* no such attribute */
458 return pairfind(vps, dattr->attr);
463 * Evaluate an assignment
465 * Not really used much...
467 static int evaluate_assignment(policy_state_t *state, const policy_item_t *item)
469 const policy_assignment_t *this;
471 const DICT_ATTR *dattr;
474 this = (const policy_assignment_t *) item;
476 rad_assert(this->lhs != NULL);
477 rad_assert(this->rhs != NULL);
480 dattr = dict_attrbyname(this->lhs);
482 fprintf(stderr, "HUH?\n");
492 * Evaluate a condition
494 static int evaluate_condition(policy_state_t *state, const policy_item_t *item)
497 const policy_condition_t *this;
498 VALUE_PAIR *vp = NULL;
499 const char *data = NULL;
505 char lhs_buffer[2048];
507 this = (const policy_condition_t *) item;
511 * FIXME: Don't always do this...
513 if (this->compare != POLICY_LEX_L_BRACKET) {
514 if (this->lhs_type == POLICY_LEX_FUNCTION) {
516 * We can't call evaluate_call here,
517 * because that just pushes stuff onto
518 * the stack, and we want to actually
519 * evaluate all of it...
521 rcode = policy_evaluate_name(state, this->lhs);
522 data = fr_int2str(policy_return_codes, rcode, "???");
523 strlcpy(lhs_buffer, data, sizeof(lhs_buffer)); /* FIXME: yuck */
524 } else if (this->lhs_type == POLICY_LEX_DOUBLE_QUOTED_STRING) {
525 if (radius_xlat(lhs_buffer, sizeof(lhs_buffer), this->lhs,
526 state->request, NULL) > 0) {
532 switch (this->compare) {
533 case POLICY_LEX_L_BRACKET: /* nested brackets are a special case */
534 rcode = evaluate_condition(state, this->child);
537 case POLICY_LEX_L_NOT:
538 rcode = evaluate_condition(state, this->child);
539 rcode = (rcode == FALSE); /* reverse sense of test */
542 case POLICY_LEX_CMP_FALSE: /* non-existence */
543 if (this->lhs_type == POLICY_LEX_BARE_WORD) {
544 vp = find_vp(state->request, this->lhs);
545 rcode = (vp == NULL);
547 rcode = (data == NULL);
551 case POLICY_LEX_CMP_TRUE: /* existence */
552 if (this->lhs_type == POLICY_LEX_BARE_WORD) {
553 vp = find_vp(state->request, this->lhs);
554 rcode = (vp != NULL);
556 rcode = (data != NULL);
560 default: /* process other comparisons */
561 if ((this->compare != POLICY_LEX_CMP_EQUALS) &&
563 (this->compare != POLICY_LEX_RX_EQUALS) &&
564 (this->compare != POLICY_LEX_RX_NOT_EQUALS) &&
566 (this->compare != POLICY_LEX_LT) &&
567 (this->compare != POLICY_LEX_GT) &&
568 (this->compare != POLICY_LEX_LE) &&
569 (this->compare != POLICY_LEX_GE) &&
570 (this->compare != POLICY_LEX_CMP_NOT_EQUALS)) {
571 fprintf(stderr, "%d: bad comparison\n",
576 if (this->lhs_type == POLICY_LEX_BARE_WORD) {
579 vp = find_vp(state->request, this->lhs);
582 * A op B always returns FALSE if A doesn't
585 if (!vp) return FALSE; /* not in the request */
588 * FIXME: Move sanity checks to
589 * post-parse code, so we don't do
590 * it on every packet.
592 vp_prints_value(buffer, sizeof(buffer), vp, 0);
593 myvp = pairmake(vp->name, this->rhs, T_OP_EQ);
594 if (!myvp) return FALSE; /* memory failure */
598 * FIXME: What to do about comparisons
599 * where vp doesn't exist? Right now,
600 * "simplepaircmp" returns -1, which is
601 * probably a bad idea. it should
602 * instead take an operator, a pointer to
603 * the comparison result, and return
604 * "true/false" for "comparions
605 * succeeded/failed", which are different
606 * error codes than "comparison is less
607 * than, equal to, or greater than zero".
609 compare = radius_callback_compare(state->request,
610 vp, myvp, NULL, NULL);
615 * FIXME: Do something for RHS type?
617 printf("CMP %s %s\n", lhs_buffer, this->rhs);
618 compare = strcmp(lhs_buffer, this->rhs);
621 debug_evaluate("CONDITION COMPARE %d\n", compare);
623 switch (this->compare) {
624 case POLICY_LEX_CMP_EQUALS:
625 rcode = (compare == 0);
628 case POLICY_LEX_CMP_NOT_EQUALS:
629 rcode = (compare != 0);
633 rcode = (compare < 0);
637 rcode = (compare > 0);
641 rcode =(compare <= 0);
645 rcode = (compare >= 0);
649 case POLICY_LEX_RX_EQUALS:
650 { /* FIXME: copied from src/main/valuepair.c */
652 regmatch_t rxmatch[REQUEST_MAX_REGEX + 1];
655 * Include substring matches.
657 if (regcomp(®, this->rhs,
658 REG_EXTENDED) != 0) {
661 rad_assert(data != NULL);
662 rcode = regexec(®, data,
663 REQUEST_MAX_REGEX + 1,
665 rcode = (rcode == 0);
669 * Add %{0}, %{1}, etc.
671 for (i = 0; i <= REQUEST_MAX_REGEX; i++) {
676 * Didn't match: delete old
677 * match, if it existed.
680 (rxmatch[i].rm_so == -1)) {
681 p = request_data_get(state->request, state->request,
682 REQUEST_DATA_REGEX | i);
696 * Copy substring into buffer.
699 data + rxmatch[i].rm_so,
700 rxmatch[i].rm_eo - rxmatch[i].rm_so);
701 rxbuffer[rxmatch[i].rm_eo - rxmatch[i].rm_so] = '\0';
704 * Copy substring, and add it to
707 * Note that we don't check
708 * for out of memory, which is
709 * the only error we can get...
711 p = strdup(rxbuffer);
712 request_data_add(state->request,
714 REQUEST_DATA_REGEX | i,
721 case POLICY_LEX_RX_NOT_EQUALS:
722 regcomp(®, this->rhs, REG_EXTENDED|REG_NOSUB);
723 rad_assert(data != NULL);
724 rcode = regexec(®, data,
726 rcode = (rcode != 0);
729 #endif /* HAVE_REGEX_H */
733 } /* switch over comparison operators */
734 break; /* default from first switch over compare */
740 switch (this->child_condition) {
744 case POLICY_LEX_L_AND:
745 if (!rcode) return rcode; /* FALSE && x == FALSE */
748 case POLICY_LEX_L_OR:
749 if (rcode) return rcode; /* TRUE && x == TRUE */
756 this = (const policy_condition_t *) this->child;
759 return 1; /* should never reach here */
764 * Evaluate an 'if' statement
766 static int evaluate_if(policy_state_t *state, const policy_item_t *item)
769 const policy_if_t *this;
771 this = (const policy_if_t *) item;
774 * evaluate_condition calls itself recursively.
775 * We should probably allocate a new state, instead.
777 rcode = evaluate_condition(state, this->condition);
778 debug_evaluate("IF condition returned %s\n",
779 rcode ? "true" : "false");
781 rcode = policy_stack_push(state, this->if_true);
782 if (!rcode) return rcode;
783 } else if (this->if_false) {
784 rcode = policy_stack_push(state, this->if_false);
785 if (!rcode) return rcode;
789 * 'if' can fail, if the block it's processing fails.
796 * Make a VALUE_PAIR from a policy_assignment_t*
798 * The assignment operator has to be '='.
800 static VALUE_PAIR *assign2vp(REQUEST *request,
801 const policy_assignment_t *assign)
804 FR_TOKEN operator = T_OP_EQ;
805 const char *value = assign->rhs;
808 if ((assign->rhs_type == POLICY_LEX_DOUBLE_QUOTED_STRING) &&
809 (strchr(assign->rhs, '%') != NULL)) {
810 radius_xlat(buffer, sizeof(buffer), assign->rhs,
816 * This is crappy.. fix it.
818 switch (assign->assign) {
819 case POLICY_LEX_ASSIGN:
823 case POLICY_LEX_SET_EQUALS:
827 case POLICY_LEX_PLUS_EQUALS:
832 fprintf(stderr, "Expected '=' for operator, not '%s' at line %d\n",
833 fr_int2str(rlm_policy_tokens,
834 assign->assign, "?"),
835 assign->item.lineno);
839 vp = pairmake(assign->lhs, value, operator);
841 fprintf(stderr, "SHIT: %s %s\n", value, librad_errstr);
849 * Evaluate a 'packet .= {attrs}' statement
851 static int evaluate_attr_list(policy_state_t *state, const policy_item_t *item)
853 const policy_attributes_t *this;
854 VALUE_PAIR **vps = NULL;
855 VALUE_PAIR *vp, *head, **tail;
856 const policy_item_t *attr;
857 policy_lex_t this_how;
859 this = (const policy_attributes_t *) item;
861 switch (this->where) {
862 case POLICY_RESERVED_CONTROL:
863 vps = &(state->request->config_items);
866 case POLICY_RESERVED_REQUEST:
867 vps = &(state->request->packet->vps);
870 case POLICY_RESERVED_REPLY:
871 vps = &(state->request->reply->vps);
874 case POLICY_RESERVED_PROXY_REQUEST:
875 if (!state->request->proxy) return 0; /* FIXME: print error */
876 vps = &(state->request->proxy->vps);
879 case POLICY_RESERVED_PROXY_REPLY:
880 if (!state->request->proxy_reply) return 0; /* FIXME: print error */
881 vps = &(state->request->proxy_reply->vps);
891 for (attr = this->attributes; attr != NULL; attr = attr->next) {
892 if (attr->type != POLICY_TYPE_ASSIGNMENT) {
893 fprintf(stderr, "bad assignment in attribute list at line %d\n", attr->lineno);
898 vp = assign2vp(state->request, (const policy_assignment_t *) attr);
900 fprintf(stderr, "Failed to allocate VP\n");
908 this_how = this->how;
911 case POLICY_LEX_SET_EQUALS: /* dangerous: removes all previous things! */
916 case POLICY_LEX_AFTER_TAIL_ASSIGN:
917 pairmove(vps, &head);
921 case POLICY_LEX_ASSIGN: /* 'union' */
922 pairmove(vps, &head);
926 case POLICY_LEX_BEFORE_HEAD_ASSIGN:
927 pairmove(&head, &vps);
932 case POLICY_LEX_AFTER_TAIL_EQUALS:
933 case POLICY_LEX_CONCAT_EQUALS:
937 case POLICY_LEX_BEFORE_HEAD_EQUALS:
938 pairadd(&head, *vps);
942 case POLICY_LEX_BEFORE_WHERE_EQUALS:
943 case POLICY_LEX_AFTER_WHERE_EQUALS:
944 case POLICY_LEX_BEFORE_WHERE_ASSIGN:
945 case POLICY_LEX_AFTER_WHERE_ASSIGN:
948 VALUE_PAIR *vpprev = NULL, *vpnext = NULL, *lvp;
950 for(lvp = *vps; lvp; vpprev = lvp, lvp = lvp->next) {
953 if (evaluate_condition(state, this->where_loc))
960 case POLICY_LEX_BEFORE_WHERE_EQUALS:
961 case POLICY_LEX_BEFORE_WHERE_ASSIGN:
968 default: /* always reached */
973 case POLICY_LEX_BEFORE_WHERE_EQUALS:
979 case POLICY_LEX_AFTER_WHERE_EQUALS:
982 case POLICY_LEX_BEFORE_WHERE_ASSIGN:
984 pairmove(&lvp, &head);
990 case POLICY_LEX_AFTER_WHERE_ASSIGN:
991 pairmove(&lvp, &head);
994 default:/*never reached*/
997 for( ; lvp && lvp->next; lvp = lvp->next);
1004 case POLICY_LEX_BEFORE_WHERE_EQUALS:
1005 this_how = POLICY_LEX_BEFORE_HEAD_EQUALS;
1007 case POLICY_LEX_AFTER_WHERE_EQUALS:
1008 this_how = POLICY_LEX_AFTER_TAIL_EQUALS;
1010 case POLICY_LEX_BEFORE_WHERE_ASSIGN:
1011 this_how = POLICY_LEX_BEFORE_HEAD_ASSIGN;
1013 case POLICY_LEX_AFTER_WHERE_ASSIGN:
1014 this_how = POLICY_LEX_AFTER_TAIL_ASSIGN;
1016 default: /*never reached*/
1024 fprintf(stderr, "HUH?\n");
1029 state->rcode = RLM_MODULE_UPDATED; /* we did stuff */
1036 * Evaluate a reference call to a module.
1038 static int evaluate_call(policy_state_t *state, const policy_item_t *item)
1041 const policy_call_t *this;
1042 const policy_named_t *policy;
1044 this = (const policy_call_t *) item;
1046 policy = rlm_policy_find(state->inst->policies, this->name);
1047 if (!policy) return 0; /* not found... */
1049 DEBUG2("rlm_policy: Evaluating policy %s", this->name);
1051 rad_assert(policy->policy->type != POLICY_TYPE_BAD);
1052 rad_assert(policy->policy->type < POLICY_TYPE_NUM_TYPES);
1055 * Push the name of the function onto the stack,
1056 * so that we can catch recursive calls.
1058 * The "pop" function will skip over it when it sees it.
1060 rcode = policy_stack_push(state, (const policy_item_t *) policy);
1066 * Push it onto the stack. Other code will take care of
1069 rcode = policy_stack_push(state, policy->policy);
1079 * Evaluate a return statement
1081 static int evaluate_return(policy_state_t *state, const policy_item_t *item)
1083 const policy_return_t *this;
1085 this = (const policy_return_t *) item;
1086 state->rcode = this->rcode;
1088 return 1; /* we succeeded */
1093 * Evaluate a module statement
1095 static int evaluate_module(policy_state_t *state, const policy_item_t *item)
1097 const policy_module_t *this;
1099 this = (const policy_module_t *) item;
1102 * Just to be paranoid. Maybe we want to loosen this
1103 * restriction in the future?
1105 if (this->component != state->component) {
1106 DEBUG2("rlm_policy: Cannot mix & match components");
1110 DEBUG2("rlm_policy: begin nested call");
1111 state->rcode = modcall(this->component, this->mc, state->request);
1112 DEBUG2("rlm_policy: end nested call");
1114 return 1; /* we succeeded */
1119 * State machine stuff.
1121 typedef int (*policy_evaluate_type_t)(policy_state_t *, const policy_item_t *);
1125 * MUST be kept in sync with policy_type_t
1127 static policy_evaluate_type_t evaluate_functions[POLICY_TYPE_NUM_TYPES] = {
1128 NULL, /* POLICY_TYPE_BAD */
1131 evaluate_assignment,
1134 NULL, /* define a named policy.. */
1142 * Evaluate a policy, keyed by name.
1144 static int policy_evaluate_name(policy_state_t *state, const char *name)
1147 const policy_item_t *this;
1148 policy_named_t mypolicy, *policy;
1150 mypolicy.name = name;
1151 policy = rbtree_finddata(state->inst->policies, &mypolicy);
1152 if (!policy) return RLM_MODULE_FAIL;
1154 DEBUG2("rlm_policy: Evaluating policy %s", name);
1156 rad_assert(policy->item.type != POLICY_TYPE_BAD);
1157 rad_assert(policy->item.type < POLICY_TYPE_NUM_TYPES);
1159 rcode = policy_stack_push(state, policy->policy);
1161 return RLM_MODULE_FAIL;
1165 * FIXME: Look for magic keywords like "return",
1166 * where the packet gets accepted/rejected/whatever
1168 while (policy_stack_pop(state, &this)) {
1169 rad_assert(this != NULL);
1170 rad_assert(this->type != POLICY_TYPE_BAD);
1171 rad_assert(this->type < POLICY_TYPE_NUM_TYPES);
1173 debug_evaluate("Evaluating at line %d\n",
1175 rcode = (*evaluate_functions[this->type])(state,
1178 return RLM_MODULE_FAIL;
1180 } /* loop until the stack is empty */
1182 return state->rcode;
1187 * Evaluate, which is pretty close to print, but we look at what
1190 int rlm_policy_evaluate(rlm_policy_t *inst, REQUEST *request, const char *name)
1193 policy_state_t *state;
1195 state = rad_malloc(sizeof(*state));
1196 memset(state, 0, sizeof(*state));
1197 state->request = request;
1199 state->rcode = RLM_MODULE_OK;
1200 state->component = fr_str2int(policy_component_names, name,
1201 RLM_COMPONENT_COUNT);
1203 rcode = policy_evaluate_name(state, name);
1207 return rcode; /* evaluated OK. */