X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Frlm_policy%2Fevaluate.c;h=3c1a000c6fffc3f1284c72c9fd3a88e90fadf36d;hb=9960563934a7da222528a1d82224aecc207c8aa8;hp=672c8d9eb3706078ca8fa23c62a3cc1241ceaa51;hpb=567141bb40400ffea46635d423dd29ad48d3d771;p=freeradius.git diff --git a/src/modules/rlm_policy/evaluate.c b/src/modules/rlm_policy/evaluate.c index 672c8d9..3c1a000 100644 --- a/src/modules/rlm_policy/evaluate.c +++ b/src/modules/rlm_policy/evaluate.c @@ -15,14 +15,16 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * Copyright 2004 Alan DeKok + * Copyright 2006 The FreeRADIUS server project */ -#include "rlm_policy.h" +#include +RCSID("$Id$") -#include "modules.h" +#include "rlm_policy.h" #ifdef HAVE_REGEX_H #include @@ -36,50 +38,50 @@ static void policy_print(const policy_item_t *item, int indent) { if (!item) { - if (indent) printf("%*s", indent, " "); - printf("[NULL]\n"); + 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) printf("%*s", indent, " "); - printf("[BAD STATEMENT]"); + if (indent) fprintf(fr_log_fp, "%*s", indent, " "); + fprintf(fr_log_fp, "[BAD STATEMENT]"); break; - + case POLICY_TYPE_PRINT: - if (indent) printf("%*s", indent, " "); + 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) { - printf("print %s\n", this->rhs); + fprintf(fr_log_fp, "print %s\n", this->rhs); } else { - printf("print \"%s\"\n", this->rhs); + 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) printf("%*s", indent, " "); + if (indent) fprintf(fr_log_fp, "%*s", indent, " "); - printf("\t%s %s ", assign->lhs, - lrad_int2str(rlm_policy_tokens, + fprintf(fr_log_fp, "\t%s %s ", assign->lhs, + fr_int2str(rlm_policy_tokens, assign->assign, "?")); if (assign->rhs_type == POLICY_LEX_BARE_WORD) { - printf("%s\n", assign->rhs); + fprintf(fr_log_fp, "%s\n", assign->rhs); } else { /* * FIXME: escape " */ - printf("\"%s\"\n", assign->rhs); + fprintf(fr_log_fp, "\"%s\"\n", assign->rhs); } } break; @@ -90,60 +92,65 @@ static void policy_print(const policy_item_t *item, int indent) condition = (const policy_condition_t *) item; - printf("("); + 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); - printf(")"); + fprintf(fr_log_fp, ")"); break; } if (condition->compare == POLICY_LEX_L_NOT) { - printf("!"); + fprintf(fr_log_fp, "!"); policy_print(condition->child, indent); - printf(")"); + fprintf(fr_log_fp, ")"); break; } if (condition->compare == POLICY_LEX_CMP_TRUE) { - printf("%s)", condition->lhs); + fprintf(fr_log_fp, "%s)", condition->lhs); break; } - if (condition->lhs_type == POLICY_LEX_BARE_WORD) { - printf("%s", condition->lhs); + 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. */ - printf("\"%s\"", condition->lhs); + fprintf(fr_log_fp, "\"%s\"", condition->lhs); } /* * We always print this condition. */ - printf(" %s ", lrad_int2str(rlm_policy_tokens, + fprintf(fr_log_fp, " %s ", fr_int2str(rlm_policy_tokens, condition->compare, "?")); if (condition->rhs_type == POLICY_LEX_BARE_WORD) { - printf("%s", condition->rhs); + fprintf(fr_log_fp, "%s", condition->rhs); } else { /* * FIXME: escape ", * and move all of this logic * to a function. */ - printf("\"%s\"", condition->rhs); + fprintf(fr_log_fp, "\"%s\"", condition->rhs); } - printf(")"); - - if (condition->child_condition != POLICY_LEX_BAD) { - printf(" %s ", lrad_int2str(rlm_policy_tokens, condition->child_condition, "?")); + 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); } } @@ -155,24 +162,24 @@ static void policy_print(const policy_item_t *item, int indent) statement = (const policy_if_t *) item; - if (indent) printf("%*s", indent, " "); - printf("if "); + if (indent) fprintf(fr_log_fp, "%*s", indent, " "); + fprintf(fr_log_fp, "if "); policy_print(statement->condition, indent); - printf(" {\n"); + fprintf(fr_log_fp, " {\n"); policy_print(statement->if_true, indent + 1); - if (indent) printf("%*s", indent, " "); + if (indent) fprintf(fr_log_fp, "%*s", indent, " "); if (statement->if_false) { - printf("} else "); + fprintf(fr_log_fp, "} else "); if (statement->if_false->type == POLICY_TYPE_ASSIGNMENT) { - printf(" { "); + fprintf(fr_log_fp, " { "); policy_print(statement->if_false, indent + 1); - if (indent) printf("%*s", indent, " "); - printf(" }"); + if (indent) fprintf(fr_log_fp, "%*s", indent, " "); + fprintf(fr_log_fp, " }"); } else { policy_print(statement->if_false, indent + 1); } } else { - printf("}\n"); + fprintf(fr_log_fp, "}\n"); } } break; @@ -183,15 +190,15 @@ static void policy_print(const policy_item_t *item, int indent) this = (const policy_attributes_t *) item; - if (indent) printf("%*s", indent, " "); - printf("%s %s {\n", - lrad_int2str(policy_reserved_words, + if (indent) fprintf(fr_log_fp, "%*s", indent, " "); + fprintf(fr_log_fp, "%s %s {\n", + fr_int2str(policy_reserved_words, this->where, "?"), - lrad_int2str(rlm_policy_tokens, + fr_int2str(rlm_policy_tokens, this->how, "?")); policy_print(this->attributes, indent + 1); - if (indent) printf("%*s", indent, " "); - printf("}\n"); + if (indent) fprintf(fr_log_fp, "%*s", indent, " "); + fprintf(fr_log_fp, "}\n"); } break; @@ -200,11 +207,11 @@ static void policy_print(const policy_item_t *item, int indent) const policy_named_t *this; this = (const policy_named_t *) item; - if (indent) printf("%*s", indent, " "); - printf("policy %s {\n", this->name); + 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) printf("%*s", indent, " "); - printf("}\n"); + if (indent) fprintf(fr_log_fp, "%*s", indent, " "); + fprintf(fr_log_fp, "}\n"); } break; @@ -213,16 +220,40 @@ static void policy_print(const policy_item_t *item, int indent) const policy_call_t *this; this = (const policy_call_t *) item; - if (indent) printf("%*s", indent, " "); - printf("call %s\n", this->name); + 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 \n", + fr_int2str(policy_component_names, + this->component, "???")); } break; default: - if (indent) printf("%*s", indent, " "); - printf("[HUH?]\n"); + if (indent) fprintf(fr_log_fp, "%*s", indent, " "); + fprintf(fr_log_fp, "[HUH?]\n"); break; - + } item = item->next; @@ -232,34 +263,31 @@ static void policy_print(const policy_item_t *item, int indent) void rlm_policy_print(const policy_item_t *item) { - printf("----------------------------------------------------------\n"); + if (!fr_log_fp) return; + + fprintf(fr_log_fp, "# rlm_policy \n"); policy_print(item, 0); - printf("----------------------------------------------------------\n"); } /* - * Internal stack of things to do. - * - * When a function is about to be pushed onto the stack, we walk - * backwards through the stack, and ensure that the function is - * not already there. This prevents infinite recursion. + * Internal stack of things to do. This lets us have function + * calls... * - * This means that we NEVER pop functions. Rather, we push the - * function, and then immediately push it's first element. - * - * When we've finished popping all of the elements, we pop the - * function, realize it's a function, ignore it, and pop one more - * entry. + * Yes, we should learn lex, yacc, etc. */ #define POLICY_MAX_STACK 16 typedef struct policy_state_t { rlm_policy_t *inst; - int depth; 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. */ @@ -325,6 +353,7 @@ 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; @@ -333,6 +362,14 @@ static int policy_stack_pop(policy_state_t *state, const policy_item_t **pitem) *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) { @@ -354,18 +391,25 @@ 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) { - printf("%s\n", this->rhs); + fprintf(fr_log_fp, "%s\n", this->rhs); } else { char buffer[1024]; radius_xlat(buffer, sizeof(buffer), this->rhs, state->request, NULL); - printf("%s", buffer); + fprintf(fr_log_fp, "%s", buffer); + if (!strchr(buffer, '\n')) fprintf(fr_log_fp, "\n"); } + /* + * Doesn't change state->rcode + */ + return 1; } @@ -394,6 +438,7 @@ static VALUE_PAIR *find_vp(REQUEST *request, const char *name) } else if (strncasecmp(name, "reply:", 6) == 0) { p += 6; vps = request->reply->vps; +#ifdef WITH_PROXY } else if (strncasecmp(name, "proxy-request:", 14) == 0) { p += 14; if (request->proxy) { @@ -404,6 +449,7 @@ static VALUE_PAIR *find_vp(REQUEST *request, const char *name) if (request->proxy_reply) { vps = request->proxy_reply->vps; } +#endif } else if (strncasecmp(name, "control:", 8) == 0) { p += 8; vps = request->config_items; @@ -419,17 +465,21 @@ static VALUE_PAIR *find_vp(REQUEST *request, const char *name) return NULL; /* no such attribute */ } - return pairfind(vps, dattr->attr); + return pairfind(vps, dattr->attr, dattr->vendor); } /* * Evaluate an assignment + * + * Not really used much... */ -static int evaluate_assignment(policy_state_t *state, const policy_item_t *item) +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; @@ -455,8 +505,8 @@ static int evaluate_condition(policy_state_t *state, const policy_item_t *item) { int rcode; const policy_condition_t *this; - VALUE_PAIR *vp; - char *data = NULL; + VALUE_PAIR *vp = NULL; + const char *data = NULL; int compare; #ifdef HAVE_REGEX_H regex_t reg; @@ -470,14 +520,25 @@ static int evaluate_condition(policy_state_t *state, const policy_item_t *item) /* * FIXME: Don't always do this... */ - if ((this->compare != POLICY_LEX_L_BRACKET) && - (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; + 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); @@ -488,6 +549,15 @@ static int evaluate_condition(policy_state_t *state, const policy_item_t *item) 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); @@ -516,24 +586,26 @@ static int evaluate_condition(policy_state_t *state, const policy_item_t *item) 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. */ - if (vp) { - vp_prints_value(buffer, sizeof(buffer), vp, 0); - myvp = pairmake(vp->name, this->rhs, T_OP_EQ); - } else { - buffer[0] = '\0'; - myvp = pairmake(this->lhs, this->rhs, T_OP_EQ); - } + 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; - if (!myvp) { - return FALSE; - } /* * FIXME: What to do about comparisons @@ -547,56 +619,57 @@ static int evaluate_condition(policy_state_t *state, const policy_item_t *item) * error codes than "comparison is less * than, equal to, or greater than zero". */ - compare = simplepaircmp(state->request, - vp, myvp); + compare = radius_callback_compare(state->request, + vp, myvp, NULL, NULL); pairfree(&myvp); - + } else { /* * FIXME: Do something for RHS type? */ - printf("CMP %s %s\n", lhs_buffer, this->rhs); + 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: { /* FIXME: copied from src/main/valuepair.c */ int i; regmatch_t rxmatch[REQUEST_MAX_REGEX + 1]; - + /* * Include substring matches. */ if (regcomp(®, this->rhs, REG_EXTENDED) != 0) { + /* FIXME: print error */ return FALSE; } rad_assert(data != NULL); @@ -605,14 +678,14 @@ static int evaluate_condition(policy_state_t *state, const policy_item_t *item) rxmatch, 0); rcode = (rcode == 0); regfree(®); - + /* * Add %{0}, %{1}, etc. */ for (i = 0; i <= REQUEST_MAX_REGEX; i++) { char *p; char rxbuffer[256]; - + /* * Didn't match: delete old * match, if it existed. @@ -625,14 +698,14 @@ static int evaluate_condition(policy_state_t *state, const policy_item_t *item) free(p); continue; } - + /* * No previous match * to delete, stop. */ break; } - + /* * Copy substring into buffer. */ @@ -640,7 +713,7 @@ static int evaluate_condition(policy_state_t *state, const policy_item_t *item) data + rxmatch[i].rm_so, rxmatch[i].rm_eo - rxmatch[i].rm_so); rxbuffer[rxmatch[i].rm_eo - rxmatch[i].rm_so] = '\0'; - + /* * Copy substring, and add it to * the request. @@ -655,10 +728,10 @@ static int evaluate_condition(policy_state_t *state, const policy_item_t *item) REQUEST_DATA_REGEX | i, p, free); } - + } break; - + case POLICY_LEX_RX_NOT_EQUALS: regcomp(®, this->rhs, REG_EXTENDED|REG_NOSUB); rad_assert(data != NULL); @@ -675,6 +748,8 @@ static int evaluate_condition(policy_state_t *state, const policy_item_t *item) break; /* default from first switch over compare */ } + if (this->sense) rcode = (rcode == FALSE); /* reverse sense of test */ + /* * No trailing &&, || */ @@ -742,7 +817,7 @@ static VALUE_PAIR *assign2vp(REQUEST *request, const policy_assignment_t *assign) { VALUE_PAIR *vp; - LRAD_TOKEN operator = T_OP_EQ; + FR_TOKEN operator = T_OP_EQ; const char *value = assign->rhs; char buffer[2048]; @@ -764,22 +839,22 @@ static VALUE_PAIR *assign2vp(REQUEST *request, 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", - lrad_int2str(rlm_policy_tokens, + fr_int2str(rlm_policy_tokens, assign->assign, "?"), assign->item.lineno); return NULL; } - + vp = pairmake(assign->lhs, value, operator); if (!vp) { - fprintf(stderr, "SHIT: %s %s\n", value, librad_errstr); + fprintf(stderr, "Failed creating pair: %s %s\n", value, fr_strerror()); } return vp; @@ -795,6 +870,7 @@ static int evaluate_attr_list(policy_state_t *state, const policy_item_t *item) 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; @@ -811,6 +887,7 @@ static int evaluate_attr_list(policy_state_t *state, const policy_item_t *item) vps = &(state->request->reply->vps); break; +#ifdef WITH_PROXY case POLICY_RESERVED_PROXY_REQUEST: if (!state->request->proxy) return 0; /* FIXME: print error */ vps = &(state->request->proxy->vps); @@ -820,6 +897,7 @@ static int evaluate_attr_list(policy_state_t *state, const policy_item_t *item) if (!state->request->proxy_reply) return 0; /* FIXME: print error */ vps = &(state->request->proxy_reply->vps); break; +#endif default: return 0; @@ -845,33 +923,135 @@ static int evaluate_attr_list(policy_state_t *state, const policy_item_t *item) tail = &(vp->next); } - switch (this->how) { + this_how = this->how; + retry_how: + switch (this_how) { case POLICY_LEX_SET_EQUALS: /* dangerous: removes all previous things! */ pairfree(vps); *vps = head; break; + case POLICY_LEX_AFTER_TAIL_ASSIGN: + pairmove(vps, &head); + pairfree(&head); + break; + case POLICY_LEX_ASSIGN: /* 'union' */ 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: + /* find location*/ + { + 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: /* always reached */ + 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:/*never reached*/ + 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: /*never reached*/ + break; + } + goto retry_how; + } + /* FALL-THROUGH */ + default: fprintf(stderr, "HUH?\n"); pairfree(&head); return 0; } + state->rcode = RLM_MODULE_UPDATED; /* we did stuff */ + return 1; } /* - * Evaluate an 'call foo' statement + * Evaluate a reference call to a module. */ static int evaluate_call(policy_state_t *state, const policy_item_t *item) { @@ -883,13 +1063,24 @@ static int evaluate_call(policy_state_t *state, const policy_item_t *item) policy = rlm_policy_find(state->inst->policies, this->name); if (!policy) return 0; /* not found... */ - + 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); /* + * Push the name of the function onto the stack, + * so that we can catch recursive calls. + * + * The "pop" function will skip over it when it sees it. + */ + rcode = policy_stack_push(state, (const policy_item_t *) policy); + if (!rcode) { + return rcode; + } + + /* * Push it onto the stack. Other code will take care of * calling it. */ @@ -898,15 +1089,47 @@ static int evaluate_call(policy_state_t *state, const policy_item_t *item) return rcode; } + return 1; +} + + +/* + * Evaluate a return statement + */ +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; /* we succeeded */ +} + + +/* + * Evaluate a module statement + */ +static int evaluate_module(policy_state_t *state, const policy_item_t *item) +{ + const policy_module_t *this; + + this = (const policy_module_t *) item; + /* - * Function calls always succeed? - * - * FIXME: Push the function name, etc. onto the stack, - * so we can check for infinite recursion above, and - * so we can also check for return codes from functions - * we call... + * Just to be paranoid. Maybe we want to loosen this + * restriction in the future? */ - return 1; + 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; /* we succeeded */ } @@ -927,7 +1150,9 @@ static policy_evaluate_type_t evaluate_functions[POLICY_TYPE_NUM_TYPES] = { evaluate_attr_list, evaluate_print, NULL, /* define a named policy.. */ - evaluate_call + evaluate_call, + evaluate_return, + evaluate_module }; @@ -939,16 +1164,16 @@ 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; @@ -962,7 +1187,7 @@ static int policy_evaluate_name(policy_state_t *state, const char *name) 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, @@ -972,7 +1197,7 @@ static int policy_evaluate_name(policy_state_t *state, const char *name) } } /* loop until the stack is empty */ - return RLM_MODULE_OK; + return state->rcode; } @@ -989,6 +1214,9 @@ int rlm_policy_evaluate(rlm_policy_t *inst, REQUEST *request, const char *name) 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);