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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * Copyright 2004 Alan DeKok <aland@ox.org>
23 #include "rlm_policy.h"
31 #define debug_evaluate if (0) printf
34 * Print stuff we've parsed
36 static void policy_print(const policy_item_t *item, int indent)
39 if (indent) printf("%*s", indent, " ");
47 if (indent) printf("%*s", indent, " ");
48 printf("[BAD STATEMENT]");
51 case POLICY_TYPE_PRINT:
52 if (indent) printf("%*s", indent, " ");
54 const policy_print_t *this;
56 this = (const policy_print_t *) item;
58 if (this->rhs_type == POLICY_LEX_BARE_WORD) {
59 printf("print %s\n", this->rhs);
61 printf("print \"%s\"\n", this->rhs);
66 case POLICY_TYPE_ASSIGNMENT:
68 const policy_assignment_t *assign;
70 assign = (const policy_assignment_t *) item;
71 if (indent) printf("%*s", indent, " ");
73 printf("\t%s %s ", assign->lhs,
74 lrad_int2str(rlm_policy_tokens,
75 assign->assign, "?"));
76 if (assign->rhs_type == POLICY_LEX_BARE_WORD) {
77 printf("%s\n", assign->rhs);
82 printf("\"%s\"\n", assign->rhs);
87 case POLICY_TYPE_CONDITIONAL: /* no indentation here */
89 const policy_condition_t *condition;
91 condition = (const policy_condition_t *) item;
98 if (condition->compare == POLICY_LEX_L_BRACKET) {
99 policy_print(condition->child, indent);
104 if (condition->compare == POLICY_LEX_L_NOT) {
106 policy_print(condition->child, indent);
111 if (condition->compare == POLICY_LEX_CMP_TRUE) {
112 printf("%s)", condition->lhs);
116 if (condition->lhs_type == POLICY_LEX_FUNCTION) {
117 printf("%s()", condition->lhs);
121 * and move all of this logic
124 printf("\"%s\"", condition->lhs);
128 * We always print this condition.
130 printf(" %s ", lrad_int2str(rlm_policy_tokens,
133 if (condition->rhs_type == POLICY_LEX_BARE_WORD) {
134 printf("%s", condition->rhs);
138 * and move all of this logic
141 printf("\"%s\"", condition->rhs);
145 if ((condition->child_condition != POLICY_LEX_BAD) &&
146 (condition->child_condition != POLICY_LEX_BARE_WORD)) {
147 printf(" %s ", lrad_int2str(rlm_policy_tokens, condition->child_condition, "?"));
148 policy_print(condition->child, indent);
155 const policy_if_t *statement;
157 statement = (const policy_if_t *) item;
159 if (indent) printf("%*s", indent, " ");
161 policy_print(statement->condition, indent);
163 policy_print(statement->if_true, indent + 1);
164 if (indent) printf("%*s", indent, " ");
165 if (statement->if_false) {
167 if (statement->if_false->type == POLICY_TYPE_ASSIGNMENT) {
169 policy_print(statement->if_false, indent + 1);
170 if (indent) printf("%*s", indent, " ");
173 policy_print(statement->if_false, indent + 1);
181 case POLICY_TYPE_ATTRIBUTE_LIST:
183 const policy_attributes_t *this;
185 this = (const policy_attributes_t *) item;
187 if (indent) printf("%*s", indent, " ");
189 lrad_int2str(policy_reserved_words,
191 lrad_int2str(rlm_policy_tokens,
193 policy_print(this->attributes, indent + 1);
194 if (indent) printf("%*s", indent, " ");
199 case POLICY_TYPE_NAMED_POLICY:
201 const policy_named_t *this;
203 this = (const policy_named_t *) item;
204 if (indent) printf("%*s", indent, " ");
205 printf("policy %s {\n", this->name);
206 policy_print(this->policy, indent + 1);
207 if (indent) printf("%*s", indent, " ");
212 case POLICY_TYPE_CALL:
214 const policy_call_t *this;
216 this = (const policy_call_t *) item;
217 if (indent) printf("%*s", indent, " ");
218 printf("call %s\n", this->name);
222 case POLICY_TYPE_RETURN:
224 const policy_return_t *this;
226 this = (const policy_return_t *) item;
227 if (indent) printf("%*s", indent, " ");
228 printf("return %s\n",
229 lrad_int2str(policy_return_codes,
230 this->rcode, "???"));
235 if (indent) printf("%*s", indent, " ");
246 void rlm_policy_print(const policy_item_t *item)
248 printf("----------------------------------------------------------\n");
249 policy_print(item, 0);
250 printf("----------------------------------------------------------\n");
254 * Internal stack of things to do. This lets us have function
257 * Yes, we should learn lex, yacc, etc.
259 #define POLICY_MAX_STACK 16
260 typedef struct policy_state_t {
262 REQUEST *request; /* so it's not passed on the C stack */
263 int rcode; /* for functions, etc. */
265 const policy_item_t *stack[POLICY_MAX_STACK];
269 static int policy_evaluate_name(policy_state_t *state, const char *name);
272 * Push an item onto the state.
274 static int policy_stack_push(policy_state_t *state, const policy_item_t *item)
276 rad_assert(state->depth >= 0);
279 * Asked to push nothing. Don't push it.
284 * State is full. Die.
286 if (state->depth >= POLICY_MAX_STACK) {
291 * Walk back up the stack, looking for previous ocurrances
292 * of this name. If found, we have infinite recursion,
293 * which we stop dead in the water!
295 * This isn't strictly necessary right now, as we look up
296 * policies by name when they're first referenced. This
297 * means that ALL references are backwards (to the start
298 * of the file), which means that there are no circular
301 if (item->type == POLICY_TYPE_NAMED_POLICY) {
304 for (i = 0; i < state->depth; i++) {
306 * Check for circular references, by seeing
307 * if the function is already on the stack.
309 * Hmmm... do we want to do this for any type?
311 if (state->stack[i] == item) {
312 debug_evaluate("Circular call to policy %s\n",
313 ((const policy_named_t *) item)->name);
319 debug_evaluate("push %d %p\n", state->depth, item);
321 state->stack[state->depth] = item;
322 state->depth++; /* points to unused entry */
329 * Pop an item from the state.
331 static int policy_stack_pop(policy_state_t *state, const policy_item_t **pitem)
333 rad_assert(pitem != NULL);
334 rad_assert(state->depth >= 0);
337 if (state->depth == 0) {
342 *pitem = state->stack[state->depth - 1];
345 * Named policies are on the stack for catching recursion.
347 if ((*pitem)->type == POLICY_TYPE_NAMED_POLICY) {
352 * Process the whole item list.
354 if ((*pitem)->next) {
355 state->stack[state->depth - 1] = (*pitem)->next;
356 debug_evaluate("pop/push %d %p\n", state->depth - 1, *pitem);
358 state->depth--; /* points to unused entry */
359 debug_evaluate("pop %d %p\n", state->depth, *pitem);
367 * Evaluate a print statement
369 static int evaluate_print(policy_state_t *state, const policy_item_t *item)
371 const policy_print_t *this;
373 this = (const policy_print_t *) item;
375 if (this->rhs_type == POLICY_LEX_BARE_WORD) {
376 printf("%s\n", this->rhs);
380 radius_xlat(buffer, sizeof(buffer), this->rhs,
381 state->request, NULL);
382 printf("%s", buffer);
386 * Doesn't change state->rcode
393 * Return a VALUE_PAIR, given an attribute name.
395 * FIXME: Have it return the N'th one, too, like
398 * The amount of duplicated code is getting annoying...
400 static VALUE_PAIR *find_vp(REQUEST *request, const char *name)
403 const DICT_ATTR *dattr;
407 vps = request->packet->vps;;
410 * FIXME: use names from reserved word list?
412 if (strncasecmp(name, "request:", 8) == 0) {
414 } else if (strncasecmp(name, "reply:", 6) == 0) {
416 vps = request->reply->vps;
417 } else if (strncasecmp(name, "proxy-request:", 14) == 0) {
419 if (request->proxy) {
420 vps = request->proxy->vps;
422 } else if (strncasecmp(name, "proxy-reply:", 12) == 0) {
424 if (request->proxy_reply) {
425 vps = request->proxy_reply->vps;
427 } else if (strncasecmp(name, "control:", 8) == 0) {
429 vps = request->config_items;
430 } /* else it must be a bare attribute name */
436 dattr = dict_attrbyname(p);
438 fprintf(stderr, "No such attribute %s\n", p);
439 return NULL; /* no such attribute */
442 return pairfind(vps, dattr->attr);
447 * Evaluate an assignment
449 * Not really used much...
451 static int evaluate_assignment(policy_state_t *state, const policy_item_t *item)
453 const policy_assignment_t *this;
454 const DICT_ATTR *dattr;
456 this = (const policy_assignment_t *) item;
458 rad_assert(this->lhs != NULL);
459 rad_assert(this->rhs != NULL);
462 dattr = dict_attrbyname(this->lhs);
464 fprintf(stderr, "HUH?\n");
474 * Evaluate a condition
476 static int evaluate_condition(policy_state_t *state, const policy_item_t *item)
479 const policy_condition_t *this;
481 const char *data = NULL;
487 char lhs_buffer[2048];
489 this = (const policy_condition_t *) item;
493 * FIXME: Don't always do this...
495 if (this->compare != POLICY_LEX_L_BRACKET) {
496 if (this->lhs_type == POLICY_LEX_FUNCTION) {
498 * We can't call evaluate_call here,
499 * because that just pushes stuff onto
500 * the stack, and we want to actually
501 * evaluate all of it...
503 rcode = policy_evaluate_name(state, this->lhs);
504 data = lrad_int2str(policy_return_codes, rcode, "???");
505 strNcpy(lhs_buffer, data, sizeof(lhs_buffer)); /* FIXME: yuck */
506 } else if (this->lhs_type == POLICY_LEX_DOUBLE_QUOTED_STRING) {
507 if (radius_xlat(lhs_buffer, sizeof(lhs_buffer), this->lhs,
508 state->request, NULL) > 0) {
514 switch (this->compare) {
515 case POLICY_LEX_L_BRACKET: /* nested brackets are a special case */
516 rcode = evaluate_condition(state, this->child);
519 case POLICY_LEX_L_NOT:
520 rcode = evaluate_condition(state, this->child);
521 rcode = (rcode == FALSE); /* reverse sense of test */
524 case POLICY_LEX_CMP_TRUE: /* existence */
525 if (this->lhs_type == POLICY_LEX_BARE_WORD) {
526 vp = find_vp(state->request, this->lhs);
527 rcode = (vp != NULL);
529 rcode = (data != NULL);
533 default: /* process other comparisons */
534 if ((this->compare != POLICY_LEX_CMP_EQUALS) &&
536 (this->compare != POLICY_LEX_RX_EQUALS) &&
537 (this->compare != POLICY_LEX_RX_NOT_EQUALS) &&
539 (this->compare != POLICY_LEX_LT) &&
540 (this->compare != POLICY_LEX_GT) &&
541 (this->compare != POLICY_LEX_LE) &&
542 (this->compare != POLICY_LEX_GE) &&
543 (this->compare != POLICY_LEX_CMP_NOT_EQUALS)) {
544 fprintf(stderr, "%d: bad comparison\n",
549 if (this->lhs_type == POLICY_LEX_BARE_WORD) {
553 vp = find_vp(state->request, this->lhs);
555 * FIXME: Move sanity checks to
556 * post-parse code, so we don't do
557 * it on every packet.
560 vp_prints_value(buffer, sizeof(buffer), vp, 0);
561 myvp = pairmake(vp->name, this->rhs, T_OP_EQ);
564 myvp = pairmake(this->lhs, this->rhs, T_OP_EQ);
572 * FIXME: What to do about comparisons
573 * where vp doesn't exist? Right now,
574 * "simplepaircmp" returns -1, which is
575 * probably a bad idea. it should
576 * instead take an operator, a pointer to
577 * the comparison result, and return
578 * "true/false" for "comparions
579 * succeeded/failed", which are different
580 * error codes than "comparison is less
581 * than, equal to, or greater than zero".
583 compare = simplepaircmp(state->request,
589 * FIXME: Do something for RHS type?
591 printf("CMP %s %s\n", lhs_buffer, this->rhs);
592 compare = strcmp(lhs_buffer, this->rhs);
595 debug_evaluate("CONDITION COMPARE %d\n", compare);
597 switch (this->compare) {
598 case POLICY_LEX_CMP_EQUALS:
599 rcode = (compare == 0);
602 case POLICY_LEX_CMP_NOT_EQUALS:
603 rcode = (compare != 0);
607 rcode = (compare < 0);
611 rcode = (compare > 0);
615 rcode =(compare <= 0);
619 rcode = (compare >= 0);
623 case POLICY_LEX_RX_EQUALS:
624 { /* FIXME: copied from src/main/valuepair.c */
626 regmatch_t rxmatch[REQUEST_MAX_REGEX + 1];
629 * Include substring matches.
631 if (regcomp(®, this->rhs,
632 REG_EXTENDED) != 0) {
635 rad_assert(data != NULL);
636 rcode = regexec(®, data,
637 REQUEST_MAX_REGEX + 1,
639 rcode = (rcode == 0);
643 * Add %{0}, %{1}, etc.
645 for (i = 0; i <= REQUEST_MAX_REGEX; i++) {
650 * Didn't match: delete old
651 * match, if it existed.
654 (rxmatch[i].rm_so == -1)) {
655 p = request_data_get(state->request, state->request,
656 REQUEST_DATA_REGEX | i);
670 * Copy substring into buffer.
673 data + rxmatch[i].rm_so,
674 rxmatch[i].rm_eo - rxmatch[i].rm_so);
675 rxbuffer[rxmatch[i].rm_eo - rxmatch[i].rm_so] = '\0';
678 * Copy substring, and add it to
681 * Note that we don't check
682 * for out of memory, which is
683 * the only error we can get...
685 p = strdup(rxbuffer);
686 request_data_add(state->request,
688 REQUEST_DATA_REGEX | i,
695 case POLICY_LEX_RX_NOT_EQUALS:
696 regcomp(®, this->rhs, REG_EXTENDED|REG_NOSUB);
697 rad_assert(data != NULL);
698 rcode = regexec(®, data,
700 rcode = (rcode != 0);
703 #endif /* HAVE_REGEX_H */
707 } /* switch over comparison operators */
708 break; /* default from first switch over compare */
714 switch (this->child_condition) {
718 case POLICY_LEX_L_AND:
719 if (!rcode) return rcode; /* FALSE && x == FALSE */
722 case POLICY_LEX_L_OR:
723 if (rcode) return rcode; /* TRUE && x == TRUE */
730 this = (const policy_condition_t *) this->child;
733 return 1; /* should never reach here */
738 * Evaluate an 'if' statement
740 static int evaluate_if(policy_state_t *state, const policy_item_t *item)
743 const policy_if_t *this;
745 this = (const policy_if_t *) item;
748 * evaluate_condition calls itself recursively.
749 * We should probably allocate a new state, instead.
751 rcode = evaluate_condition(state, this->condition);
752 debug_evaluate("IF condition returned %s\n",
753 rcode ? "true" : "false");
755 rcode = policy_stack_push(state, this->if_true);
756 if (!rcode) return rcode;
757 } else if (this->if_false) {
758 rcode = policy_stack_push(state, this->if_false);
759 if (!rcode) return rcode;
763 * 'if' can fail, if the block it's processing fails.
770 * Make a VALUE_PAIR from a policy_assignment_t*
772 * The assignment operator has to be '='.
774 static VALUE_PAIR *assign2vp(REQUEST *request,
775 const policy_assignment_t *assign)
778 LRAD_TOKEN operator = T_OP_EQ;
779 const char *value = assign->rhs;
782 if ((assign->rhs_type == POLICY_LEX_DOUBLE_QUOTED_STRING) &&
783 (strchr(assign->rhs, '%') != NULL)) {
784 radius_xlat(buffer, sizeof(buffer), assign->rhs,
790 * This is crappy.. fix it.
792 switch (assign->assign) {
793 case POLICY_LEX_ASSIGN:
797 case POLICY_LEX_SET_EQUALS:
801 case POLICY_LEX_PLUS_EQUALS:
806 fprintf(stderr, "Expected '=' for operator, not '%s' at line %d\n",
807 lrad_int2str(rlm_policy_tokens,
808 assign->assign, "?"),
809 assign->item.lineno);
813 vp = pairmake(assign->lhs, value, operator);
815 fprintf(stderr, "SHIT: %s %s\n", value, librad_errstr);
823 * Evaluate a 'packet .= {attrs}' statement
825 static int evaluate_attr_list(policy_state_t *state, const policy_item_t *item)
827 const policy_attributes_t *this;
828 VALUE_PAIR **vps = NULL;
829 VALUE_PAIR *vp, *head, **tail;
830 const policy_item_t *attr;
832 this = (const policy_attributes_t *) item;
834 switch (this->where) {
835 case POLICY_RESERVED_CONTROL:
836 vps = &(state->request->config_items);
839 case POLICY_RESERVED_REQUEST:
840 vps = &(state->request->packet->vps);
843 case POLICY_RESERVED_REPLY:
844 vps = &(state->request->reply->vps);
847 case POLICY_RESERVED_PROXY_REQUEST:
848 if (!state->request->proxy) return 0; /* FIXME: print error */
849 vps = &(state->request->proxy->vps);
852 case POLICY_RESERVED_PROXY_REPLY:
853 if (!state->request->proxy_reply) return 0; /* FIXME: print error */
854 vps = &(state->request->proxy_reply->vps);
864 for (attr = this->attributes; attr != NULL; attr = attr->next) {
865 if (attr->type != POLICY_TYPE_ASSIGNMENT) {
866 fprintf(stderr, "bad assignment in attribute list at line %d\n", attr->lineno);
871 vp = assign2vp(state->request, (const policy_assignment_t *) attr);
873 fprintf(stderr, "Failed to allocate VP\n");
882 case POLICY_LEX_SET_EQUALS: /* dangerous: removes all previous things! */
887 case POLICY_LEX_ASSIGN: /* 'union' */
888 pairmove(vps, &head);
892 case POLICY_LEX_CONCAT_EQUALS:
897 fprintf(stderr, "HUH?\n");
902 state->rcode = RLM_MODULE_UPDATED; /* we did stuff */
909 * Evaluate a reference call to a module.
911 static int evaluate_call(policy_state_t *state, const policy_item_t *item)
914 const policy_call_t *this;
915 const policy_named_t *policy;
917 this = (const policy_call_t *) item;
919 policy = rlm_policy_find(state->inst->policies, this->name);
920 if (!policy) return 0; /* not found... */
922 DEBUG2("rlm_policy: Evaluating policy %s", this->name);
924 rad_assert(policy->policy->type != POLICY_TYPE_BAD);
925 rad_assert(policy->policy->type < POLICY_TYPE_NUM_TYPES);
928 * Push the name of the function onto the stack,
929 * so that we can catch recursive calls.
931 * The "pop" function will skip over it when it sees it.
933 rcode = policy_stack_push(state, (const policy_item_t *) policy);
939 * Push it onto the stack. Other code will take care of
942 rcode = policy_stack_push(state, policy->policy);
952 * Evaluate a return statement
954 static int evaluate_return(policy_state_t *state, const policy_item_t *item)
956 const policy_return_t *this;
958 this = (const policy_return_t *) item;
959 state->rcode = this->rcode;
961 return 1; /* we succeeded */
966 * State machine stuff.
968 typedef int (*policy_evaluate_type_t)(policy_state_t *, const policy_item_t *);
972 * MUST be kept in sync with policy_type_t
974 static policy_evaluate_type_t evaluate_functions[POLICY_TYPE_NUM_TYPES] = {
975 NULL, /* POLICY_TYPE_BAD */
981 NULL, /* define a named policy.. */
988 * Evaluate a policy, keyed by name.
990 static int policy_evaluate_name(policy_state_t *state, const char *name)
993 const policy_item_t *this;
994 policy_named_t mypolicy, *policy;
996 mypolicy.name = name;
997 policy = rbtree_finddata(state->inst->policies, &mypolicy);
998 if (!policy) return RLM_MODULE_FAIL;
1000 DEBUG2("rlm_policy: Evaluating policy %s", name);
1002 rad_assert(policy->item.type != POLICY_TYPE_BAD);
1003 rad_assert(policy->item.type < POLICY_TYPE_NUM_TYPES);
1005 rcode = policy_stack_push(state, policy->policy);
1007 return RLM_MODULE_FAIL;
1011 * FIXME: Look for magic keywords like "return",
1012 * where the packet gets accepted/rejected/whatever
1014 while (policy_stack_pop(state, &this)) {
1015 rad_assert(this != NULL);
1016 rad_assert(this->type != POLICY_TYPE_BAD);
1017 rad_assert(this->type < POLICY_TYPE_NUM_TYPES);
1019 debug_evaluate("Evaluating at line %d\n",
1021 rcode = (*evaluate_functions[this->type])(state,
1024 return RLM_MODULE_FAIL;
1026 } /* loop until the stack is empty */
1028 return state->rcode;
1033 * Evaluate, which is pretty close to print, but we look at what
1036 int rlm_policy_evaluate(rlm_policy_t *inst, REQUEST *request, const char *name)
1039 policy_state_t *state;
1041 state = rad_malloc(sizeof(*state));
1042 memset(state, 0, sizeof(*state));
1043 state->request = request;
1045 state->rcode = RLM_MODULE_OK;
1047 rcode = policy_evaluate_name(state, name);
1051 return rcode; /* evaluated OK. */