📄 evaluate.c
字号:
* instead take an operator, a pointer to * the comparison result, and return * "true/false" for "comparions * succeeded/failed", which are different * error codes than "comparison is less * than, equal to, or greater than zero". */ compare = radius_callback_compare(state->request, vp, myvp, NULL, NULL); pairfree(&myvp); } else { /* * FIXME: Do something for RHS type? */ 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); rcode = regexec(®, data, REQUEST_MAX_REGEX + 1, 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. */ if (!rcode || (rxmatch[i].rm_so == -1)) { p = request_data_get(state->request, state->request, REQUEST_DATA_REGEX | i); if (p) { free(p); continue; } /* * No previous match * to delete, stop. */ break; } /* * Copy substring into buffer. */ 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'; /* * Copy substring, and add it to * the request. * * Note that we don't check * for out of memory, which is * the only error we can get... */ 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 /* HAVE_REGEX_H */ default: rcode = FALSE; break; } /* switch over comparison operators */ break; /* default from first switch over compare */ } if (this->sense) rcode = (rcode == FALSE); /* reverse sense of test */ /* * No trailing &&, || */ switch (this->child_condition) { default: return rcode; case POLICY_LEX_L_AND: if (!rcode) return rcode; /* FALSE && x == FALSE */ break; case POLICY_LEX_L_OR: if (rcode) return rcode; /* TRUE && x == TRUE */ break; } /* * Tail recursion. */ this = (const policy_condition_t *) this->child; goto redo; return 1; /* should never reach here */}/* * Evaluate an 'if' statement */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; /* * evaluate_condition calls itself recursively. * We should probably allocate a new state, instead. */ 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; } /* * 'if' can fail, if the block it's processing fails. */ return 1;;}/* * Make a VALUE_PAIR from a policy_assignment_t* * * The assignment operator has to be '='. */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; } /* * This is crappy.. fix it. */ 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, librad_errstr); } return vp;}/* * Evaluate a 'packet .= {attrs}' statement */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; /* FIXME: print error */ vps = &(state->request->proxy->vps); break; case POLICY_RESERVED_PROXY_REPLY: if (!state->request->proxy_reply) return 0; /* FIXME: print error */ 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: /* 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 a reference call to a module. */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; /* 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. */ rcode = policy_stack_push(state, policy->policy); if (!rcode) { 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; /* * Just to be paranoid. Maybe we want to loosen this * restriction in the future? */ 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 */}/* * State machine stuff. */typedef int (*policy_evaluate_type_t)(policy_state_t *, const policy_item_t *);/* * MUST be kept in sync with policy_type_t */static policy_evaluate_type_t evaluate_functions[POLICY_TYPE_NUM_TYPES] = { NULL, /* POLICY_TYPE_BAD */ evaluate_if, evaluate_condition, evaluate_assignment, evaluate_attr_list, evaluate_print, NULL, /* define a named policy.. */ evaluate_call, evaluate_return, evaluate_module};/* * Evaluate a policy, keyed by name. */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; } /* * FIXME: Look for magic keywords like "return", * where the packet gets accepted/rejected/whatever */ 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; } } /* loop until the stack is empty */ return state->rcode;}/* * Evaluate, which is pretty close to print, but we look at what * we're printing. */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; /* evaluated OK. */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -