Nearly all of its functionality is handled by unlang.
What isn't handled is very esoteric. It's better for people
to use Perl or (upcoming) lua module
+++ /dev/null
-# -*- text -*-
-#
-# $Id$
-
-#
-# Module implementing a DIFFERENT policy language.
-# The syntax here is NOT "unlang", but something else.
-#
-# See the "raddb/policy.txt" file for documentation and examples.
-# There isn't much else in the way of documentation, sorry.
-#
-policy {
- # The only configuration item is a filename containing
- # the policies to execute.
- #
- # When "policy" is listed in a section (e.g. "authorize"),
- # it will run a policy named for that section.
- #
- filename = ${confdir}/policy.txt
-}
-
+++ /dev/null
-#
-# Sample of a policy language for rlm_policy.
-#
-# This is NOT the "unlang" policy, and has NO RELATION to "unlang"!
-# The syntax is different, and the functionality is different.
-#
-
-# As of 2.0.0, the new configuration "un-language" is better
-# tested, has more features, and is better integrated into the
-# server than the rlm_policy module. rlm_policy is deprecated,
-# and will likely be removed in a future release.
-#
-# There is no documentation other than this file.
-#
-# The syntax is odd, but it sort of works.
-#
-# A number of sites are using it in production servers,
-# so it appears to be stable. However, we cannot answer
-# questions about it, because we use "unlang", instead of
-# this file.
-#
-# $Id$
-#
-# Debugging statements
-#
-#debug print_tokens # as we're parsing this file
-debug print_policy # once the file has been parsed
-
-# Using this requires code edits to rlm_policy/evaluate.c
-#debug evaluate # print limited information during evaluation
-
-#
-# A named policy.
-#
-policy 3pm {
-if (Time-Of-Day < "15:00") {
- #
- # The general form of edits to the attribute lists:
- #
- # name s-operator {
- # Attribute-Name = Value
- # }
- #
- # name is: request, reply, control, proxy-request, proxy-reply
- #
- # s-operator is operator for section, not attributes:
- #
- # = append, using operators from attributes
- # .= append attributes, ignoring operators from attributes
- # ^= add to head of list
- # ^== add BEFORE matching attribute
- # ^. append
- # ^.= append BEFORE matching attribute
- # $= add AFTER (same as =)
- # $== add AFTER matching attribute
- # $. add after (same as .=)
- # $.= add after matching
- #
- # If the above explanation confuses you, don't ask. Try various
- # configurations to see what happens. The results are difficult
- # to explain, but easy to understand once you see them in action.
- #
- # The "matching attribute" text above refers to the syntax:
- #
- # name s-operator (match) {
- # Attribute-Name = Value
- # }
- #
- # Where "match" is something like: User-Name == "bob"
- #
- # This lets you insert/edit/update attributes by selected
- # position, which can be useful.
- #
- reply .= {
- # Use ARAP-Password for testing because it's an attribute
- # no one cares about.
- ARAP-Password = "< 15:00"
- }
-}
-
-}
-
-#
-# A named policy, executed during the "authorize" phase,
-# because it's named "authorize".
-#
-policy authorize {
- if (CHAP-Password) {
- if (!CHAP-Challenge) {
- print "Adding CHAP-Challenge = %{request:Packet-Authentication-Vector}\n"
-
- #
- # Append all attributes to the specified list.
- # The per-attribute operators MUST be '='
- #
- request .= {
- CHAP-Challenge = "%{request:Packet-Authentication-Vector}"
- }
- }
-
- #
- # Use per-attribute operators to do override, replace, etc.
- # It's "control", not "check items", because "check items"
- # is a hold-over from the "users" file, and we no longer like that.
- #
- control = {
- Auth-Type := CHAP
- }
- }
-
-#
-# This could just as well be "%{ldap: query...}" =~ ...
-#
-# if ("%{User-Name}" =~ "^(b)") {
-# reply .= {
-# Arap-Password = "Hello, %{1}"
-# }
-# }
-
- #
- # Execute "3pm", as if it was in-line here.
- #
-# call 3pm
-}
-
-######################################################################
-#
-# The following entries are for example purposes only.
-#
-
-# Insert the attribute at the top of the list.
-#
-#reply ^= {
-# Attribute1 += "Value1"
-#}
-
-
-# Insert attribute1 before Attribute2 if found, otherwise it behaves
-# like ^=
-#reply ^== ( Attribute2 == "Value2" ) {
-# Attribute1 += "Value1"
-#}
-
-# ^. and ^.= have the same difference as .= and =
-# namely they append the attribute list instead of looking at the
-# attribute operators.
-#
-# Otherwise they are the same.
-
-# Motivation:
-#
-# Cisco NAS's will kick users who assign a VRF after assigning an IP
-# address. The VRF must come first.
-#
-# A sample policy to fix this is:
-#
-policy add_inter_vrf {
- #
- # If there's a matching lcp:...,
- # then add the vrf entry before it.
- #
- reply ^== ( reply:Cisco-Avpair =~ "lcp:interface-config") {
- Cisco-Avpair += "lcp:interface-config=ip vrf forwarding CHL-PRIVATE"
- }
-
- #
- # If there's no ip address thingy,
- # add ip unnumbered after the vrf stuff.
- #
- if (!reply:Cisco-Avpair =~ "lcp:interface-config=ip address.*") {
- reply $== (reply:Cisco-AVpair == "lcp:interface-config=ip vrf forwarding CHL-PRIVATE") {
- Cisco-Avpair += "lcp:interface-config=ip unnumbered l10"
- }
- }
-
- #
- # No IP address assigned through RADIUS, tell the Cisco
- # NAS to assign it from it's own private IP pool.
- #
- if (!reply:Framed-IP-Address =* "") {
- reply = {
- Cisco-Avpair += "ip:addr-pool=privatepool"
- }
- }
-}
+++ /dev/null
-#
-# Makefile
-#
-# Version: $Id$
-#
-
-TARGET = rlm_policy
-SRCS = rlm_policy.c parse.c evaluate.c
-HEADERS = rlm_policy.h
-RLM_CFLAGS =
-RLM_LIBS =
-
-include ../rules.mak
-
-$(LT_OBJS): $(HEADERS)
+++ /dev/null
-TARGET := rlm_policy.a
-SOURCES := rlm_policy.c parse.c evaluate.c
+++ /dev/null
-/*
- * evaluate.c Evaluate a policy language
- *
- * Version: $Id$
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- *
- * Copyright 2004 Alan DeKok <aland@ox.org>
- * Copyright 2006 The FreeRADIUS server project
- */
-
-#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
-
-/*
- * Print stuff we've parsed
- */
-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 {
- /*
- * FIXME: escape "
- */
- fprintf(fr_log_fp, "\"%s\"\n", assign->rhs);
- }
- }
- break;
-
- case POLICY_TYPE_CONDITIONAL: /* no indentation here */
- {
- const policy_condition_t *condition;
-
- condition = (const policy_condition_t *) item;
-
- 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);
- 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 {
- /*
- * FIXME: escape ",
- * and move all of this logic
- * to a function.
- */
- fprintf(fr_log_fp, "\"%s\"", condition->lhs);
- }
-
- /*
- * We always print this condition.
- */
- 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 {
- /*
- * FIXME: escape ",
- * and move all of this logic
- * to a function.
- */
- 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);
-}
-
-/*
- * Internal stack of things to do. This lets us have function
- * calls...
- *
- * Yes, we should learn lex, yacc, etc.
- */
-#define POLICY_MAX_STACK 16
-typedef struct policy_state_t {
- rlm_policy_t *inst;
- 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.
- */
-static int policy_stack_push(policy_state_t *state, const policy_item_t *item)
-{
- rad_assert(state->depth >= 0);
-
- /*
- * Asked to push nothing. Don't push it.
- */
- if (!item) return 1;
-
- /*
- * State is full. Die.
- */
- if (state->depth >= POLICY_MAX_STACK) {
- return 0;
- }
-
- /*
- * Walk back up the stack, looking for previous ocurrances
- * of this name. If found, we have infinite recursion,
- * which we stop dead in the water!
- *
- * This isn't strictly necessary right now, as we look up
- * policies by name when they're first referenced. This
- * means that ALL references are backwards (to the start
- * of the file), which means that there are no circular
- * references.
- */
- if (item->type == POLICY_TYPE_NAMED_POLICY) {
- int i;
-
- for (i = 0; i < state->depth; i++) {
- /*
- * Check for circular references, by seeing
- * if the function is already on the stack.
- *
- * Hmmm... do we want to do this for any type?
- */
- 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++; /* points to unused entry */
-
- return 1;
-}
-
-
-/*
- * Pop an item from the state.
- */
-static int policy_stack_pop(policy_state_t *state, const policy_item_t **item)
-{
- rad_assert(item != NULL);
- rad_assert(state->depth >= 0);
-
- redo:
- if (state->depth == 0) {
- *item = NULL;
- return 0;
- }
-
- *item = state->stack[state->depth - 1];
-
- /*
- * Named policies are on the stack for catching recursion.
- */
- if ((*item)->type == POLICY_TYPE_NAMED_POLICY) {
- state->depth--;
- goto redo;
- }
-
- /*
- * Process the whole item list.
- */
- if ((*item)->next) {
- state->stack[state->depth - 1] = (*item)->next;
- debug_evaluate("pop/push %d %p\n", state->depth - 1, *item);
- } else {
- state->depth--; /* points to unused entry */
- debug_evaluate("pop %d %p\n", state->depth, *item);
- }
-
- return 1;
-}
-
-
-/*
- * Evaluate a print statement
- */
-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, NULL);
- fprintf(fr_log_fp, "%s", buffer);
- if (!strchr(buffer, '\n')) fprintf(fr_log_fp, "\n");
- }
-
- /*
- * Doesn't change state->rcode
- */
-
- return 1;
-}
-
-/*
- * Return a VALUE_PAIR, given an attribute name.
- *
- * FIXME: Have it return the N'th one, too, like
- * doc/variables.txt?
- *
- * The amount of duplicated code is getting annoying...
- */
-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;;
-
- /*
- * FIXME: use names from reserved word list?
- */
- if (strncasecmp(name, "request:", 8) == 0) {
- p += 8;
- } 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) {
- vps = request->proxy->vps;
- }
- } else if (strncasecmp(name, "proxy-reply:", 12) == 0) {
- p += 12;
- if (request->proxy_reply) {
- vps = request->proxy_reply->vps;
- }
-#endif
- } else if (strncasecmp(name, "control:", 8) == 0) {
- p += 8;
- vps = request->config_items;
- } /* else it must be a bare attribute name */
-
- if (!vps) {
- return NULL;
- }
-
- dattr = dict_attrbyname(p);
- if (!dattr) {
- fprintf(stderr, "No such attribute %s\n", p);
- return NULL; /* no such attribute */
- }
-
- return pairfind(vps, dattr->attr, dattr->vendor, TAG_ANY);
-}
-
-
-/*
- * Evaluate an assignment
- *
- * Not really used much...
- */
-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;
-}
-
-
-/*
- * Evaluate a condition
- */
-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:
- /*
- * FIXME: Don't always do this...
- */
- 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, 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);
- break;
-
- case POLICY_LEX_L_NOT:
- rcode = evaluate_condition(state, this->child);
- 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);
- rcode = (vp != NULL);
- } else {
- rcode = (data != NULL);
- }
- break;
-
- default: /* process other comparisons */
- 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);
-
- /*
- * 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.
- */
- 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;
-
- /*
- * FIXME: What to do about comparisons
- * where vp doesn't exist? Right now,
- * "simplepaircmp" returns -1, which is
- * probably a bad idea. it should
- * 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 op = 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, NULL);
- value = buffer;
- }
-
- /*
- * This is crappy.. fix it.
- */
- switch (assign->assign) {
- case POLICY_LEX_ASSIGN:
- op = T_OP_EQ;
- break;
-
- case POLICY_LEX_SET_EQUALS:
- op = T_OP_SET;
- break;
-
- case POLICY_LEX_PLUS_EQUALS:
- op = 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, op);
- if (!vp) {
- fprintf(stderr, "Failed creating pair: %s %s\n", value, fr_strerror());
- }
-
- 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;
-
-#ifdef WITH_PROXY
- 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;
-#endif
-
- 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. */
-}
+++ /dev/null
-/*
- * parse.c Parse a policy language
- *
- * Version: $Id$
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- *
- * Copyright 2004 Alan DeKok <aland@ox.org>
- * Copyright 2006 The FreeRADIUS server project
- */
-
-#include <freeradius-devel/ident.h>
-RCSID("$Id$")
-
-#include "rlm_policy.h"
-
-#ifdef HAVE_DIRENT_H
-#include <dirent.h>
-
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#endif
-
-#include <freeradius-devel/modules.h>
-
-const FR_NAME_NUMBER policy_return_codes[] = {
- { "reject", RLM_MODULE_REJECT },
- { "fail", RLM_MODULE_FAIL },
- { "ok", RLM_MODULE_OK },
- { "handled", RLM_MODULE_HANDLED },
- { "invalid", RLM_MODULE_INVALID },
- { "userlock", RLM_MODULE_USERLOCK },
- { "notfound", RLM_MODULE_NOTFOUND },
- { "noop", RLM_MODULE_NOOP },
- { "updated", RLM_MODULE_UPDATED },
- { NULL, RLM_MODULE_NUMCODES }
-};
-
-/*
- * Explanations of what the lexical tokens are.
- */
-static const FR_NAME_NUMBER policy_explanations[] = {
- { "invalid input", POLICY_LEX_BAD },
- { "end of file", POLICY_LEX_EOF },
- { "end of line", POLICY_LEX_EOL },
- { "whitespace", POLICY_LEX_WHITESPACE },
- { "hash mark", POLICY_LEX_HASH },
- { "left bracket", POLICY_LEX_L_BRACKET },
- { "right bracket", POLICY_LEX_R_BRACKET },
- { "{", POLICY_LEX_LC_BRACKET },
- { "}", POLICY_LEX_RC_BRACKET },
- { "comma", POLICY_LEX_COMMA },
- { "logical AND", POLICY_LEX_L_AND },
- { "logical OR", POLICY_LEX_L_OR },
- { "AND", POLICY_LEX_AND },
- { "OR", POLICY_LEX_OR },
- { "logical NOT", POLICY_LEX_L_NOT },
- { "assignment", POLICY_LEX_ASSIGN },
- { "comparison", POLICY_LEX_CMP_EQUALS },
- { "comparison", POLICY_LEX_CMP_NOT_EQUALS },
- { "comparison", POLICY_LEX_LT },
- { "comparison", POLICY_LEX_GT },
- { "comparison", POLICY_LEX_LE },
- { "comparison", POLICY_LEX_GT },
- { "comparison", POLICY_LEX_RX_EQUALS },
- { "comparison", POLICY_LEX_RX_NOT_EQUALS },
- { "double quoted string", POLICY_LEX_DOUBLE_QUOTED_STRING },
- { "single quoted string", POLICY_LEX_SINGLE_QUOTED_STRING },
- { "back quoted string", POLICY_LEX_BACK_QUOTED_STRING },
- { "bare word", POLICY_LEX_BARE_WORD },
-
- { NULL, -1 }
-};
-
-
-const FR_NAME_NUMBER rlm_policy_tokens[] = {
- { "EOF", POLICY_LEX_EOF },
- { "#", POLICY_LEX_HASH },
- { "(", POLICY_LEX_L_BRACKET },
- { ")", POLICY_LEX_R_BRACKET },
- { "{", POLICY_LEX_LC_BRACKET },
- { "}", POLICY_LEX_RC_BRACKET },
- { ",", POLICY_LEX_COMMA },
- { "&&", POLICY_LEX_L_AND },
- { "||", POLICY_LEX_L_OR },
- { "&", POLICY_LEX_AND },
- { "|", POLICY_LEX_OR },
- { "!", POLICY_LEX_L_NOT },
- { "=", POLICY_LEX_ASSIGN },
- { "==", POLICY_LEX_CMP_EQUALS },
- { "!=", POLICY_LEX_CMP_NOT_EQUALS },
- { "=*", POLICY_LEX_CMP_TRUE },
- { "!*", POLICY_LEX_CMP_FALSE },
- { "<", POLICY_LEX_LT },
- { ">", POLICY_LEX_GT },
- { "<=", POLICY_LEX_LE },
- { ">=", POLICY_LEX_GT },
- { "=~", POLICY_LEX_RX_EQUALS },
- { "!~", POLICY_LEX_RX_NOT_EQUALS },
- { "^=", POLICY_LEX_BEFORE_HEAD_ASSIGN },
- { "^==", POLICY_LEX_BEFORE_WHERE_ASSIGN },
- { "^.", POLICY_LEX_BEFORE_HEAD_EQUALS },
- { "^.=", POLICY_LEX_BEFORE_WHERE_EQUALS },
- { "$=", POLICY_LEX_AFTER_TAIL_ASSIGN },
- { "$==", POLICY_LEX_AFTER_WHERE_ASSIGN },
- { "$.", POLICY_LEX_AFTER_TAIL_EQUALS },
- { "$.=", POLICY_LEX_AFTER_WHERE_EQUALS },
- { ".=", POLICY_LEX_CONCAT_EQUALS },
- { ":=", POLICY_LEX_SET_EQUALS },
- { "double quoted string", POLICY_LEX_DOUBLE_QUOTED_STRING },
- { "single quoted string", POLICY_LEX_SINGLE_QUOTED_STRING },
- { "back quoted string", POLICY_LEX_BACK_QUOTED_STRING },
- { "bare word", POLICY_LEX_BARE_WORD },
-
- { NULL, -1 }
-};
-
-
-/*
- * Hand-coded lexical analysis of a string.
- * Handed input string, updates token, possible a decoded
- * string in buffer, and returns the pointer to the next token.
- *
- * Lexical tokens cannot cross a string boundary.
- */
-static const char *policy_lex_string(const char *input,
- policy_lex_t *token,
- char *buffer, size_t buflen)
-{
- rad_assert(input != NULL);
-
- switch (*input) {
- case '\0':
- *token = POLICY_LEX_EOL;
- return NULL; /* nothing more to do */
-
- case ' ':
- case '\t':
- case '\r':
- case '\n':
- /*
- * Skip over all of the whitespace in one swell foop.
- */
- *token = POLICY_LEX_WHITESPACE;
- while ((*input == ' ') || (*input == '\t') ||
- (*input == '\r') || (*input == '\n')) input++;
- return input; /* point to next non-whitespace character */
-
- case '#': /* ignore everything to the end of the line */
- *token = POLICY_LEX_EOL;
- return NULL;
-
- case '(':
- *token = POLICY_LEX_L_BRACKET;
- return input + 1;
-
- case ')':
- *token = POLICY_LEX_R_BRACKET;
- return input + 1;
-
- case '{':
- *token = POLICY_LEX_LC_BRACKET;
- return input + 1;
-
- case '}':
- *token = POLICY_LEX_RC_BRACKET;
- return input + 1;
-
- case ',':
- *token = POLICY_LEX_COMMA;
- return input + 1;
-
- case '+':
- switch (input[1]) {
- case '=':
- *token = POLICY_LEX_PLUS_EQUALS;
- input++;
- break;
-
- default:
- *token = POLICY_LEX_PLUS;
- break;
- }
- return input + 1;
-
- case '-':
- switch (input[1]) {
- case '=':
- *token = POLICY_LEX_MINUS_EQUALS;
- input++;
- break;
-
- default:
- *token = POLICY_LEX_MINUS;
- break;
- }
- return input + 1;
-
- case '.':
- if (input[1] == '=') {
- *token = POLICY_LEX_CONCAT_EQUALS;
- return input + 2;
- }
- *token = POLICY_LEX_BAD;
- return input + 1;
-
- case '^':
- if (input[1] == '.' ) {
- if (input[2] == '=') {
- *token = POLICY_LEX_BEFORE_WHERE_EQUALS;
- return input + 3;
- }
- else {
- *token = POLICY_LEX_BEFORE_HEAD_EQUALS;
- return input + 2;
- }
- }
- else if (input[1] == '=') {
- if (input[2] == '=') {
- *token = POLICY_LEX_BEFORE_WHERE_ASSIGN;
- return input + 3;
- }
- else {
- *token = POLICY_LEX_BEFORE_HEAD_ASSIGN;
- return input + 2;
- }
- }
-
- *token = POLICY_LEX_BAD;
- return input + 1;
-
- case '$':
- if (input[1] == '.' ) {
- if (input[2] == '=') {
- *token = POLICY_LEX_AFTER_WHERE_EQUALS;
- return input + 3;
- }
- else {
- *token = POLICY_LEX_AFTER_TAIL_EQUALS;
- return input + 2;
- }
- }
- else if (input[1] == '=') {
- if (input[2] == '=') {
- *token = POLICY_LEX_AFTER_WHERE_ASSIGN;
- return input + 3;
- }
- else {
- *token = POLICY_LEX_AFTER_TAIL_ASSIGN;
- return input + 2;
- }
- }
-
- *token = POLICY_LEX_BAD;
- return input + 1;
-
- case ':':
- if (input[1] == '=') {
- *token = POLICY_LEX_SET_EQUALS;
- return input + 2;
- }
- *token = POLICY_LEX_BAD;
- return input + 1;
-
- case '&':
- switch (input[1]) {
- case '&':
- *token = POLICY_LEX_L_AND;
- input++;
- break;
-
- case '=':
- *token = POLICY_LEX_AND_EQUALS;
- input++;
- break;
-
- default:
- *token = POLICY_LEX_AND;
- }
- return input + 1;
-
- case '|':
- switch (input[1]) {
- case '|':
- *token = POLICY_LEX_L_OR;
- input++;
- break;
-
- case '=':
- *token = POLICY_LEX_OR_EQUALS;
- input++;
- break;
-
- default:
- *token = POLICY_LEX_OR;
- }
- return input + 1;
-
- case '!':
- switch (input[1]) {
- case '=':
- input++;
- *token = POLICY_LEX_CMP_NOT_EQUALS;
- break;
-
- case '~':
- input++;
- *token = POLICY_LEX_RX_NOT_EQUALS;
- break;
-
- case '*':
- input++;
- *token = POLICY_LEX_CMP_FALSE;
- break;
-
- default:
- *token = POLICY_LEX_L_NOT;
- }
- return input + 1;
-
- case '=':
- switch (input[1]) {
- case '=':
- input++;
- *token = POLICY_LEX_CMP_EQUALS;
- break;
-
- case '~':
- input++;
- *token = POLICY_LEX_RX_EQUALS;
- break;
-
- case '*':
- input++;
- *token = POLICY_LEX_CMP_TRUE;
- break;
-
- default:
- *token = POLICY_LEX_ASSIGN;
- }
- return input + 1;
-
- case '<':
- if (input[1] == '=') {
- input++;
- *token = POLICY_LEX_LE;
- } else {
- *token = POLICY_LEX_LT;
- }
- return input + 1;
-
- case '>':
- if (input[1] == '=') {
- input++;
- *token = POLICY_LEX_GE;
- } else {
- *token = POLICY_LEX_GT;
- }
- return input + 1;
-
- case '"':
- if (!buffer || (buflen < 2)) {
- *token = POLICY_LEX_BAD;
- return input + 1;
- }
-
- input++;
- while (*input != '"') {
- /*
- * Strings can't pass EOL.
- */
- if (!*input) {
- return POLICY_LEX_BAD;
- }
-
- /*
- * FIXME: Embedded quotes?
- */
- *(buffer++) = *(input++);
- buflen--;
-
- /*
- * FIXME: Print more warnings?
- */
- if (buflen == 1) {
- break;
- }
- }
- *buffer = '\0';
-
- *token = POLICY_LEX_DOUBLE_QUOTED_STRING;
- return input + 1; /* skip trailing '"' */
-
- default: /* bare word */
- break;
- }
-
- /*
- * It's a bare word, with nowhere to put it. Die.
- */
- if (!buffer) {
- *token = POLICY_LEX_BAD;
- return input + 1;
- }
-
- /*
- * Getting one character is stupid.
- */
- if (buflen < 2) {
- *token = POLICY_LEX_BAD;
- return input + 1;
- }
-
- /*
- * Bare words are [-a-zA-Z0-9.]+
- */
- while (*input) {
- if (!(((*input >= '0') && (*input <= '9')) ||
- ((*input >= 'a') && (*input <= 'z')) ||
- ((*input >= 'A') && (*input <= 'Z')) ||
- (*input == '-') || (*input == '.') ||
- (*input == ':') || (*input == '_'))) {
- break;
- }
- *(buffer++) = *(input++);
- buflen--;
-
- /*
- * FIXME: Print more warnings?
- */
- if (buflen == 1) {
- break;
- }
- }
- *buffer = '\0';
-
- *token = POLICY_LEX_BARE_WORD;
- return input;
-}
-
-
-/*
- * We want to lexically analyze a file, so we need a wrapper
- * around the lexical analysis of strings.
- */
-typedef struct policy_lex_file_t {
- FILE *fp;
- const char *parse;
- const char *filename;
- int lineno;
- int debug;
- rbtree_t *policies;
- policy_lex_t token;
- char buffer[1024];
-} policy_lex_file_t;
-
-
-#define POLICY_LEX_FLAG_RETURN_EOL (1 << 0)
-#define POLICY_LEX_FLAG_PEEK (1 << 1)
-#define POLICY_LEX_FLAG_PRINT_TOKEN (1 << 2)
-
-#define debug_tokens if ((lexer->debug & POLICY_DEBUG_PRINT_TOKENS) && fr_log_fp) fr_printf_log
-
-
-/*
- * Function to return a token saying what it read, and possibly
- * a buffer of the quoted string or bare word.
- */
-static policy_lex_t policy_lex_file(policy_lex_file_t *lexer,
- int flags,
- char *mystring, size_t mystringlen)
-{
- policy_lex_t token = POLICY_LEX_BARE_WORD; /* to prime it */
-
- if (lexer->debug & POLICY_DEBUG_PRINT_TOKENS) {
- flags |= POLICY_LEX_FLAG_PRINT_TOKEN;
- }
-
- if (!lexer->fp) {
- return POLICY_LEX_EOF;
- }
-
- /*
- * Starting off, the buffer needs to be primed.
- */
- if (!lexer->parse) {
- lexer->parse = fgets(lexer->buffer,
- sizeof(lexer->buffer),
- lexer->fp);
-
- if (!lexer->parse) {
- return POLICY_LEX_EOF;
- }
-
- lexer->lineno = 1;
- } /* buffer is primed, read stuff */
-
- if (lexer->token != POLICY_LEX_BAD) {
- token = lexer->token;
- lexer->token = POLICY_LEX_BAD;
- return token;
- }
-
- /*
- * Ignore whitespace, and keep filling the buffer
- */
- while (lexer->parse) {
- const char *next;
-
- next = policy_lex_string(lexer->parse, &token,
- mystring, mystringlen);
- switch (token) {
- case POLICY_LEX_WHITESPACE: /* skip whitespace */
- lexer->parse = next;
- continue;
-
- case POLICY_LEX_EOL: /* read another line */
- lexer->parse = fgets(lexer->buffer,
- sizeof(lexer->buffer),
- lexer->fp);
- lexer->lineno++;
- if (flags & POLICY_LEX_FLAG_RETURN_EOL) {
- return POLICY_LEX_EOL;
- }
- break; /* read another token */
-
- default: /* return the token */
- if (!(flags & POLICY_LEX_FLAG_PEEK)) {
- lexer->parse = next;
- }
- if (flags & POLICY_LEX_FLAG_PRINT_TOKEN) {
- debug_tokens("[%s token %s] ",
- (flags & POLICY_LEX_FLAG_PEEK) ? "peek " : "",
- fr_int2str(rlm_policy_tokens,
- token, "?"));
- }
- return token;
- break;
- }
- } /* loop until EOF */
-
- /*
- * Close it for the user.
- */
- fclose(lexer->fp);
- lexer->fp = NULL;
-
- return POLICY_LEX_EOF;
-}
-
-
-/*
- * Push a token back onto the input.
- *
- * FIXME: Push words, too?
- */
-static int policy_lex_push_token(policy_lex_file_t *lexer,
- policy_lex_t token)
-{
- if (lexer->token != POLICY_LEX_BAD) {
- rad_assert(0 == 1);
- return 0;
- }
-
- lexer->token = token;
- return 1;
-}
-
-
-/*
- * Forward declarations.
- */
-static int parse_block(policy_lex_file_t *lexer, policy_item_t **tail);
-
-
-/*
- * Map reserved words to tokens, and vice versa.
- */
-const FR_NAME_NUMBER policy_reserved_words[] = {
- { "if", POLICY_RESERVED_IF },
- { "else", POLICY_RESERVED_ELSE },
- { "debug", POLICY_RESERVED_DEBUG },
- { "print", POLICY_RESERVED_PRINT },
- { "policy", POLICY_RESERVED_POLICY },
- { "control", POLICY_RESERVED_CONTROL },
- { "request", POLICY_RESERVED_REQUEST },
- { "reply", POLICY_RESERVED_REPLY },
- { "proxy-request", POLICY_RESERVED_PROXY_REQUEST },
- { "proxy-reply", POLICY_RESERVED_PROXY_REPLY },
- { "include", POLICY_RESERVED_INCLUDE },
- { "return", POLICY_RESERVED_RETURN },
- { "module", POLICY_RESERVED_MODULE },
- { NULL, POLICY_RESERVED_UNKNOWN }
-};
-
-
-/*
- * Simplifies some later coding
- */
-static int policy_lex_str2int(policy_lex_file_t *lexer,
- const FR_NAME_NUMBER *table, int default_value)
-{
- policy_lex_t token;
- char buffer[256];
-
- token = policy_lex_file(lexer, 0, buffer, sizeof(buffer));
- if (token != POLICY_LEX_BARE_WORD) {
- fprintf(stderr, "%s[%d]: Unexpected token\n",
- lexer->filename, lexer->lineno);
- return default_value;
- }
-
- return fr_str2int(table, buffer, default_value);
-}
-
-
-/*
- * print foo
- * print "foo"
- */
-static int parse_print(policy_lex_file_t *lexer, policy_item_t **tail)
-{
- policy_lex_t token;
- char mystring[1024];
- policy_print_t *this;
-
- debug_tokens("[PRINT] ");
-
- this = rad_malloc(sizeof(*this));
- memset(this, 0, sizeof(*this));
-
- this->item.type = POLICY_TYPE_PRINT;
- this->item.lineno = lexer->lineno;
-
- token = policy_lex_file(lexer, 0, mystring, sizeof(mystring));
- if ((token != POLICY_LEX_BARE_WORD) &&
- (token != POLICY_LEX_DOUBLE_QUOTED_STRING)) {
- fprintf(stderr, "%s[%d]: Bad print command\n",
- lexer->filename, lexer->lineno);
- rlm_policy_free_item((policy_item_t *) this);
- return 0;
- }
-
- this->rhs_type = token;
- this->rhs = strdup(mystring);
-
- *tail = (policy_item_t *) this;
-
- return 1;
-}
-
-
-/*
- * (foo == bar), with nested conditionals.
- */
-static int parse_condition(policy_lex_file_t *lexer, policy_item_t **tail)
-{
- int rcode, seen_not = FALSE;
- policy_lex_t token, compare;
- char lhs[256], rhs[256];
- policy_condition_t *this;
-
- token = policy_lex_file(lexer, 0, lhs, sizeof(lhs));
- if (token != POLICY_LEX_L_BRACKET) {
- fprintf(stderr, "%s[%d]: Expected '(', got \"%s\"\n",
- lexer->filename, lexer->lineno,
- fr_int2str(rlm_policy_tokens, token, lhs));
- return 0;
- }
-
- this = rad_malloc(sizeof(*this));
- memset(this, 0, sizeof(*this));
-
- this->item.type = POLICY_TYPE_CONDITIONAL;
- this->item.lineno = lexer->lineno;
-
- redo:
- token = policy_lex_file(lexer, 0, lhs, sizeof(lhs));
- switch (token) {
- case POLICY_LEX_L_BRACKET:
- if (!policy_lex_push_token(lexer, token)) {
- rlm_policy_free_item((policy_item_t *) this);
- return 0;
- }
-
- this->compare = POLICY_LEX_L_BRACKET;
- this->child_condition = POLICY_LEX_L_BRACKET;
- rcode = parse_condition(lexer, &(this->child));
- if (!rcode) {
- rlm_policy_free_item((policy_item_t *) this);
- return rcode;
- }
- break;
-
- case POLICY_LEX_L_NOT:
- if (seen_not) {
- fprintf(stderr, "%s[%d]: Syntax error at \"!!\"\n",
- lexer->filename, lexer->lineno);
- rlm_policy_free_item((policy_item_t *) this);
- return 0;
- }
-
- debug_tokens("[NOT] ");
-
- token = policy_lex_file(lexer, POLICY_LEX_FLAG_PEEK, NULL, 0);
- if (token != POLICY_LEX_L_BRACKET) {
- seen_not = this->sense = 1;
- goto redo;
- }
-
- this->compare = POLICY_LEX_L_NOT;
- rcode = parse_condition(lexer, &(this->child));
- if (!rcode) {
- rlm_policy_free_item((policy_item_t *) this);
- return rcode;
- }
- break;
-
- case POLICY_LEX_BARE_WORD:
- this->lhs_type = token;
- token = policy_lex_file(lexer, POLICY_LEX_FLAG_PEEK, NULL, 0);
- if (token == POLICY_LEX_L_BRACKET) {
- debug_tokens("[IF-CALL %s] ", lhs);
-
- /*
- * Function call.
- */
- if (rlm_policy_find(lexer->policies, lhs) == NULL) {
- fprintf(stderr, "%s[%d]: Undefined function \"%s\"\n",
- lexer->filename, lexer->lineno,
- lhs);
- rlm_policy_free_item((policy_item_t *) this);
- return 0;
-
- }
-
- /*
- * this->lhs set up below, after "check"
- */
- this->lhs_type = POLICY_LEX_FUNCTION;
-
- /*
- * Copied from parse_call
- */
- token = policy_lex_file(lexer, 0, NULL, 0);
- if (token != POLICY_LEX_L_BRACKET) {
- fprintf(stderr, "%s[%d]: Expected left bracket, got \"%s\"\n",
- lexer->filename, lexer->lineno,
- fr_int2str(rlm_policy_tokens, token, "?"));
- rlm_policy_free_item((policy_item_t *) this);
- return 0;
- }
-
- token = policy_lex_file(lexer, 0, NULL, 0);
- if (token != POLICY_LEX_R_BRACKET) {
- fprintf(stderr, "%s[%d]: Expected right bracket, got \"%s\"\n",
- lexer->filename, lexer->lineno,
- fr_int2str(rlm_policy_tokens, token, "?"));
- rlm_policy_free_item((policy_item_t *) this);
- return 0;
- }
- } /* else it's a comparison? */
- goto check;
-
- case POLICY_LEX_DOUBLE_QUOTED_STRING:
- this->lhs_type = token;
-
- /*
- * Got word. May just be test for existence.
- */
- check:
- token = policy_lex_file(lexer, POLICY_LEX_FLAG_PEEK, NULL, 0);
- if (token == POLICY_LEX_R_BRACKET) {
- debug_tokens("[TEST %s] ", lhs);
- this->lhs = strdup(lhs);
- this->compare = POLICY_LEX_CMP_TRUE;
- break;
- }
-
- compare = policy_lex_file(lexer, 0, rhs, sizeof(rhs));
- switch (compare) {
- case POLICY_LEX_CMP_EQUALS:
- case POLICY_LEX_CMP_NOT_EQUALS:
- case POLICY_LEX_RX_EQUALS:
- case POLICY_LEX_RX_NOT_EQUALS:
- case POLICY_LEX_CMP_TRUE:
- case POLICY_LEX_CMP_FALSE:
- case POLICY_LEX_LT:
- case POLICY_LEX_GT:
- case POLICY_LEX_LE:
- case POLICY_LEX_GE:
- break;
-
- default:
- fprintf(stderr, "%s[%d]: Invalid operator \"%s\"\n",
- lexer->filename, lexer->lineno,
- fr_int2str(rlm_policy_tokens, compare, rhs));
- rlm_policy_free_item((policy_item_t *) this);
- return 0;
- }
-
- token = policy_lex_file(lexer, 0, rhs, sizeof(rhs));
- if ((token != POLICY_LEX_BARE_WORD) &&
- (token != POLICY_LEX_DOUBLE_QUOTED_STRING)) {
- fprintf(stderr, "%s[%d]: Unexpected rhs token\n",
- lexer->filename, lexer->lineno);
- rlm_policy_free_item((policy_item_t *) this);
- return 0;
- }
- debug_tokens("[COMPARE (%s %s %s)] ",
- lhs, fr_int2str(rlm_policy_tokens, compare, "?"), rhs);
- this->lhs = strdup(lhs);
- this->compare = compare;
- this->rhs_type = token;
- this->rhs = strdup(rhs);
- break;
-
- default:
- fprintf(stderr, "%s[%d]: Unexpected lhs token\n",
- lexer->filename, lexer->lineno);
- rlm_policy_free_item((policy_item_t *) this);
- return 0;
- }
-
- token = policy_lex_file(lexer, 0, NULL, 0);
- if (token != POLICY_LEX_R_BRACKET) {
- fprintf(stderr, "%s[%d]: Expected ')', got \"%s\"\n",
- lexer->filename, lexer->lineno,
- fr_int2str(rlm_policy_tokens, token, "?"));
- rlm_policy_free_item((policy_item_t *) this);
- return 0;
- }
-
- /*
- * After the end of condition, we MAY have && or ||
- */
- token = policy_lex_file(lexer, POLICY_LEX_FLAG_PEEK, NULL, 0);
- if ((token == POLICY_LEX_L_AND) || (token == POLICY_LEX_L_OR)) {
- token = policy_lex_file(lexer, 0, NULL, 0); /* skip over it */
- debug_tokens("[%s] ",
- fr_int2str(rlm_policy_tokens, token, "?"));
- this->child_condition = token;
- rcode = parse_condition(lexer, &(this->child));
- if (!rcode) {
- rlm_policy_free_item((policy_item_t *) this);
- return 0;
- }
- }
-
- *tail = (policy_item_t *) this;
-
- return 1;
-}
-
-
-/*
- * if (...) {...}
- * if (...) {...} else {...}
- * if (...) {...} else if ...
- */
-static int parse_if(policy_lex_file_t *lexer, policy_item_t **tail)
-{
- int rcode;
- policy_lex_t token;
- char mystring[256];
- policy_if_t *this;
-
- debug_tokens("[IF] ");
-
- this = rad_malloc(sizeof(*this));
- memset(this, 0, sizeof(*this));
-
- this->item.type = POLICY_TYPE_IF;
- this->item.lineno = lexer->lineno;
-
- rcode = parse_condition(lexer, &(this->condition));
- if (!rcode) {
- rlm_policy_free_item((policy_item_t *) this);
- return rcode;
- }
-
- rcode = parse_block(lexer, &(this->if_true));
- if (!rcode) {
- rlm_policy_free_item((policy_item_t *) this);
- return rcode;
- }
-
- token = policy_lex_file(lexer, POLICY_LEX_FLAG_PEEK,
- mystring, sizeof(mystring));
- if ((token == POLICY_LEX_BARE_WORD) &&
- (fr_str2int(policy_reserved_words, mystring,
- POLICY_RESERVED_UNKNOWN) == POLICY_RESERVED_ELSE)) {
- debug_tokens("[ELSE] ");
- token = policy_lex_file(lexer, 0, mystring, sizeof(mystring));
- rad_assert(token == POLICY_LEX_BARE_WORD);
-
- token = policy_lex_file(lexer, POLICY_LEX_FLAG_PEEK,
- mystring, sizeof(mystring));
- if ((token == POLICY_LEX_BARE_WORD) &&
- (fr_str2int(policy_reserved_words, mystring,
- POLICY_RESERVED_UNKNOWN) == POLICY_RESERVED_IF)) {
- token = policy_lex_file(lexer, 0,
- mystring, sizeof(mystring));
- rad_assert(token == POLICY_LEX_BARE_WORD);
- rcode = parse_if(lexer, &(this->if_false));
- } else {
- rcode = parse_block(lexer, &(this->if_false));
- }
- if (!rcode) {
- rlm_policy_free_item((policy_item_t *) this);
- return rcode;
- }
- }
-
- debug_tokens("\n");
-
- /*
- * Empty "if" condition, don't even bother remembering
- * it.
- */
- if (!this->if_true && !this->if_false) {
- debug_tokens("Discarding empty \"if\" statement at line %d\n",
- this->item.lineno);
- rlm_policy_free_item((policy_item_t *) this);
- return 1;
- }
-
- *tail = (policy_item_t *) this;
-
- return 1;
-}
-
-
-/*
- * Parse a reference to a named policy "foo()"
- */
-static int parse_call(policy_lex_file_t *lexer, policy_item_t **tail,
- const char *name)
-{
- policy_lex_t token;
- policy_call_t *this;
-
- debug_tokens("[CALL] ");
-
- token = policy_lex_file(lexer, 0, NULL, 0);
- if (token != POLICY_LEX_L_BRACKET) {
- fprintf(stderr, "%s[%d]: Expected left bracket, got \"%s\"\n",
- lexer->filename, lexer->lineno,
- fr_int2str(rlm_policy_tokens, token, "?"));
- return 0;
- }
-
- token = policy_lex_file(lexer, 0, NULL, 0);
- if (token != POLICY_LEX_R_BRACKET) {
- fprintf(stderr, "%s[%d]: Expected right bracket, got \"%s\"\n",
- lexer->filename, lexer->lineno,
- fr_int2str(rlm_policy_tokens, token, "?"));
- return 0;
- }
-
- this = rad_malloc(sizeof(*this));
- memset(this, 0, sizeof(*this));
-
- this->item.type = POLICY_TYPE_CALL;
- this->item.lineno = lexer->lineno;
-
- this->name = strdup(name);
-
- *tail = (policy_item_t *) this;
-
- return 1;
-}
-
-
-/*
- * Edit/update/replace an attribute list
- */
-static int parse_attribute_block(policy_lex_file_t *lexer,
- policy_item_t **tail,
- policy_reserved_word_t where)
-{
- policy_lex_t token;
- policy_attributes_t *this;
- char buffer[32];
-
- this = rad_malloc(sizeof(*this));
- if (!this) {
- return 0;
- }
- memset(this, 0, sizeof(*this));
- this->item.type = POLICY_TYPE_ATTRIBUTE_LIST;
- this->item.lineno = lexer->lineno;
- this->where = where;
-
- token = policy_lex_file(lexer, 0, buffer, sizeof(buffer));
- this->how = token;
-
- switch (token) {
- case POLICY_LEX_BEFORE_WHERE_EQUALS:
- case POLICY_LEX_AFTER_WHERE_EQUALS:
- case POLICY_LEX_BEFORE_WHERE_ASSIGN:
- case POLICY_LEX_AFTER_WHERE_ASSIGN:
- if (!parse_condition(lexer, &(this->where_loc))) {
- rlm_policy_free_item((policy_item_t *)this);
- return 0;
- }
- break;
- case POLICY_LEX_BEFORE_HEAD_EQUALS:
- case POLICY_LEX_AFTER_TAIL_EQUALS:
- case POLICY_LEX_BEFORE_HEAD_ASSIGN:
- case POLICY_LEX_AFTER_TAIL_ASSIGN:
- case POLICY_LEX_ASSIGN:
- case POLICY_LEX_SET_EQUALS:
- case POLICY_LEX_CONCAT_EQUALS:
- break;
-
- default:
- fprintf(stderr, "%s[%d]: Unexpected token %s\n",
- lexer->filename, lexer->lineno,
- fr_int2str(rlm_policy_tokens, token, "?"));
- rlm_policy_free_item((policy_item_t *)this);
- return 0; /* unknown */
- }
-
- if (!parse_block(lexer, &(this->attributes))) {
- rlm_policy_free_item((policy_item_t *) this);
- return 0;
- }
-
- *tail = (policy_item_t *) this;
- return 1;
-}
-
-
-/*
- * Parse a return statement.
- */
-static int parse_return(policy_lex_file_t *lexer, policy_item_t **tail)
-{
- int rcode;
- policy_lex_t token;
- policy_return_t *this;
-
- rcode = policy_lex_str2int(lexer, policy_return_codes,
- RLM_MODULE_NUMCODES);
- if (rcode == RLM_MODULE_NUMCODES) {
- fprintf(stderr, "%s[%d]: Invalid return code\n",
- lexer->filename, lexer->lineno);
- return 0;
- }
-
- /*
- * Look for more sutff
- */
- token = policy_lex_file(lexer, POLICY_LEX_FLAG_PEEK,
- NULL, sizeof(0));
- if (token != POLICY_LEX_RC_BRACKET) {
- fprintf(stderr, "%s[%d]: return statement must be the last statement in a policy.\n",
- lexer->filename, lexer->lineno);
- return 0;
- }
-
- this = rad_malloc(sizeof(*this));
- memset(this, 0, sizeof(*this));
-
- this->item.type = POLICY_TYPE_RETURN;
- this->item.lineno = lexer->lineno;
- this->rcode = rcode;
-
- *tail = (policy_item_t *) this;
-
- return 1;
-}
-
-
-const FR_NAME_NUMBER policy_component_names[] = {
- { "authenticate", RLM_COMPONENT_AUTH },
- { "authorize", RLM_COMPONENT_AUTZ },
- { "preacct", RLM_COMPONENT_PREACCT },
- { "accounting", RLM_COMPONENT_ACCT },
- { "session", RLM_COMPONENT_SESS },
- { "pre-proxy", RLM_COMPONENT_PRE_PROXY },
- { "post-proxy", RLM_COMPONENT_POST_PROXY },
- { "post-auth", RLM_COMPONENT_POST_AUTH },
-#ifdef WITH_COA
- { "recv-coa", RLM_COMPONENT_RECV_COA },
- { "send-coa", RLM_COMPONENT_SEND_COA },
-#endif
- { NULL, RLM_COMPONENT_COUNT }
-};
-
-/*
- * Parse a module statement.
- */
-static int parse_module(policy_lex_file_t *lexer, policy_item_t **tail)
-{
- int component;
- policy_lex_t token;
- policy_module_t *this;
- char *p;
- const char *section_name;
- char filename[1024];
- char buffer[2048];
- CONF_SECTION *cs, *subcs;
- modcallable *mc;
-
- /*
- * And the filename
- */
- token = policy_lex_file(lexer, 0, filename, sizeof(filename));
- if (token != POLICY_LEX_DOUBLE_QUOTED_STRING) {
- fprintf(stderr, "%s[%d]: Expected filename, got \"%s\"\n",
- lexer->filename, lexer->lineno,
- fr_int2str(rlm_policy_tokens, token, "?"));
- return 0;
- }
-
- /*
- * See if we're including all of the files in a subdirectory.
- */
- strlcpy(buffer, lexer->filename, sizeof(buffer));
- p = strrchr(buffer, '/');
- if (p) {
- strlcpy(p + 1, filename, sizeof(buffer) - 1 - (p - buffer));
- } else {
- snprintf(buffer, sizeof(buffer), "%s/%s",
- radius_dir, filename);
- }
-
- /*
- * Include section calling a module.
- */
- debug_tokens("including module section from file %s\n", buffer);
- cs = cf_file_read(buffer);
- if (!cs) {
- return 0; /* it prints out error messages */
- }
-
- /*
- * The outer section is called "main", and can be ignored.
- * It should be a section, so there should be a subsection.
- */
- subcs = cf_subsection_find_next(cs, NULL, NULL);
- if (!subcs) {
- fprintf(stderr, "%s[%d]: Expected section containing modules\n",
- lexer->filename, lexer->lineno);
- cf_section_free(&cs);
- return 0;
- }
-
- section_name = cf_section_name1(subcs);
- rad_assert(section_name != NULL);
- component = fr_str2int(policy_component_names, section_name,
- RLM_COMPONENT_COUNT);
- if (component == RLM_COMPONENT_COUNT) {
- fprintf(stderr, "%s[%d]: Invalid section name \"%s\"\n",
- lexer->filename, lexer->lineno, section_name);
- cf_section_free(&cs);
- return 0;
- }
-
- /*
- * Compile the module entry.
- */
- mc = compile_modgroup(NULL, component, subcs);
- if (!mc) {
- cf_section_free(&cs);
- return 0; /* more often results in calling exit... */
- }
-
- this = rad_malloc(sizeof(*this));
- memset(this, 0, sizeof(*this));
-
- this->item.type = POLICY_TYPE_MODULE;
- this->item.lineno = lexer->lineno;
- this->component = component;
- this->cs = cs;
- this->mc = mc;
-
- *tail = (policy_item_t *) this;
-
- return 1;
-}
-
-
-/*
- * Parse one statement. 'foo = bar', or 'if (...) {...}', or '{...}',
- * and so on.
- */
-static int parse_statement(policy_lex_file_t *lexer, policy_item_t **tail)
-{
- int rcode;
- policy_reserved_word_t reserved;
- policy_lex_t token, assign;
- char lhs[256], rhs[256];
- policy_assignment_t *this;
-
- /*
- * See what kind of token we have.
- */
- token = policy_lex_file(lexer, 0, lhs, sizeof(lhs));
- switch (token) {
- case POLICY_LEX_LC_BRACKET:
- rcode = parse_block(lexer, tail);
- if (!rcode) {
- return 0;
- }
- break;
-
- case POLICY_LEX_BARE_WORD:
- reserved = fr_str2int(policy_reserved_words,
- lhs,
- POLICY_RESERVED_UNKNOWN);
- switch (reserved) {
- case POLICY_RESERVED_IF:
- if (parse_if(lexer, tail)) {
- return 1;
- }
- return 0;
- break;
-
- case POLICY_RESERVED_CONTROL:
- case POLICY_RESERVED_REQUEST:
- case POLICY_RESERVED_REPLY:
- case POLICY_RESERVED_PROXY_REQUEST:
- case POLICY_RESERVED_PROXY_REPLY:
- if (parse_attribute_block(lexer, tail,
- reserved))
- return 1;
- return 0;
- break;
-
- case POLICY_RESERVED_PRINT:
- if (parse_print(lexer, tail)) {
- return 1;
- }
- return 0;
- break;
-
- case POLICY_RESERVED_RETURN:
- if (parse_return(lexer, tail)) {
- return 1;
- }
- return 0;
- break;
-
- case POLICY_RESERVED_MODULE:
- if (parse_module(lexer, tail)) {
- return 1;
- }
- return 0;
- break;
-
- case POLICY_RESERVED_UNKNOWN: /* wasn't a reserved word */
- /*
- * Is a named policy, parse the reference to it.
- */
- if (rlm_policy_find(lexer->policies, lhs) != NULL) {
- if (!parse_call(lexer, tail, lhs)) {
- return 0;
- }
- return 1;
- }
-
- {
- const DICT_ATTR *dattr;
-
- /*
- * Bare words MUST be dictionary attributes
- */
-
- dattr = dict_attrbyname(lhs);
- if (!dattr) {
- fprintf(stderr, "%s[%d]: Expected attribute name, got \"%s\"\n",
- lexer->filename, lexer->lineno, lhs);
- return 0;
- }
- debug_tokens("%s[%d]: Got attribute %s\n",
- lexer->filename, lexer->lineno,
- lhs);
- }
- break;
-
- default:
- fprintf(stderr, "%s[%d]: Unexpected reserved word \"%s\"\n",
- lexer->filename, lexer->lineno, lhs);
- return 0;
- } /* switch over reserved words */
- break;
-
- /*
- * Return from nested blocks.
- */
- case POLICY_LEX_RC_BRACKET:
- policy_lex_push_token(lexer, token);
- return 2; /* magic */
-
- case POLICY_LEX_EOF: /* nothing more to do */
- return 3;
-
- default:
- fprintf(stderr, "%s[%d]: Unexpected %s\n",
- lexer->filename, lexer->lineno,
- fr_int2str(policy_explanations,
- token, "string"));
- break;
- }
-
- /*
- * Parse a bare statement.
- */
- assign = policy_lex_file(lexer, 0, rhs, sizeof(rhs));
- switch (assign) {
- case POLICY_LEX_ASSIGN:
- case POLICY_LEX_SET_EQUALS:
- case POLICY_LEX_AND_EQUALS:
- case POLICY_LEX_OR_EQUALS:
- case POLICY_LEX_PLUS_EQUALS:
- break;
-
- default:
- fprintf(stderr, "%s[%d]: Unexpected assign %s\n",
- lexer->filename, lexer->lineno,
- fr_int2str(policy_explanations,
- assign, "string"));
- return 0;
- }
-
- this = rad_malloc(sizeof(*this));
- memset(this, 0, sizeof(*this));
-
- this->item.type = POLICY_TYPE_ASSIGNMENT;
- this->item.lineno = lexer->lineno;
-
- token = policy_lex_file(lexer, 0, rhs, sizeof(rhs));
- if ((token != POLICY_LEX_BARE_WORD) &&
- (token != POLICY_LEX_DOUBLE_QUOTED_STRING)) {
- fprintf(stderr, "%s[%d]: Unexpected rhs %s\n",
- lexer->filename, lexer->lineno,
- fr_int2str(policy_explanations,
- token, "string"));
- rlm_policy_free_item((policy_item_t *) this);
- return 0;
- }
- this->rhs_type = token;
- this->rhs = strdup(rhs);
-
- token = policy_lex_file(lexer, POLICY_LEX_FLAG_RETURN_EOL,
- rhs, sizeof(rhs));
- if (token != POLICY_LEX_EOL) {
- fprintf(stderr, "%s[%d]: Expected EOL\n",
- lexer->filename, lexer->lineno);
- rlm_policy_free_item((policy_item_t *) this);
- return 0;
- }
- debug_tokens("[ASSIGN %s %s %s]\n",
- lhs, fr_int2str(rlm_policy_tokens, assign, "?"), rhs);
-
- /*
- * Fill in the assignment struct
- */
- this->lhs = strdup(lhs);
- this->assign = assign;
-
- *tail = (policy_item_t *) this;
-
- return 1;
-}
-
-
-/*
- * Parse block of statements. The block has already been checked
- * to begin with a '{'.
- */
-static int parse_block(policy_lex_file_t *lexer, policy_item_t **tail)
-{
- int rcode;
- policy_lex_t token;
-
- debug_tokens("[BLOCK] ");
-
- token = policy_lex_file(lexer, 0, NULL, 0);
- if (token != POLICY_LEX_LC_BRACKET) {
- fprintf(stderr, "%s[%d]: Expected '{'\n",
- lexer->filename, lexer->lineno);
- return 0;
- }
-
- while ((rcode = parse_statement(lexer, tail)) != 0) {
- if (rcode == 2) {
- token = policy_lex_file(lexer, 0, NULL, 0);
- if (token != POLICY_LEX_RC_BRACKET) {
- fprintf(stderr, "%s[%d]: Expected '}'\n",
- lexer->filename, lexer->lineno);
- return 0;
- }
- return 1;
- }
- rad_assert(*tail != NULL);
- /* parse_statement must fill this in */
- while (*tail) tail = &((*tail)->next);
- }
- debug_tokens("\n");
-
- /*
- * Parse statement failed.
- */
- return 0;
-}
-
-
-/*
- * Parse debugging statements
- */
-static int parse_debug(policy_lex_file_t *lexer)
-{
- int rcode = 0;
- policy_lex_t token;
- char buffer[32];
-
- token = policy_lex_file(lexer, 0, buffer, sizeof(buffer));
- if (token != POLICY_LEX_BARE_WORD) {
- fprintf(stderr, "%s[%d]: Bad debug command\n",
- lexer->filename, lexer->lineno);
- return 0;
- }
-
- if (strcasecmp(buffer, "none") == 0) {
- lexer->debug = POLICY_DEBUG_NONE;
- rcode = 1;
-
- } else if (strcasecmp(buffer, "peek") == 0) {
- lexer->debug |= POLICY_DEBUG_PEEK;
- rcode = 1;
-
- } else if (strcasecmp(buffer, "print_tokens") == 0) {
- lexer->debug |= POLICY_DEBUG_PRINT_TOKENS;
- rcode = 1;
-
- } else if (strcasecmp(buffer, "print_policy") == 0) {
- lexer->debug |= POLICY_DEBUG_PRINT_POLICY;
- rcode = 1;
-
- } else if (strcasecmp(buffer, "evaluate") == 0) {
- lexer->debug |= POLICY_DEBUG_EVALUATE;
- rcode = 1;
- }
-
- if (rcode) {
- token = policy_lex_file(lexer, POLICY_LEX_FLAG_RETURN_EOL,
- NULL, 0);
- if (token != POLICY_LEX_EOL) {
- fprintf(stderr, "%s[%d]: Expected EOL\n",
- lexer->filename, lexer->lineno);
- return 0;
- }
- } else {
- fprintf(stderr, "%s[%d]: Bad debug command \"%s\"\n",
- lexer->filename, lexer->lineno, buffer);
- return 0;
- }
-
- return 1;
-}
-
-
-/*
- * Parse a named policy "policy foo {...}"
- */
-static int parse_named_policy(policy_lex_file_t *lexer)
-{
- int rcode;
- policy_lex_t token;
- char mystring[256];
- policy_named_t *this;
- const DICT_ATTR *dattr;
-
- debug_tokens("[POLICY] ");
-
- this = rad_malloc(sizeof(*this));
- memset(this, 0, sizeof(*this));
-
- this->item.type = POLICY_TYPE_NAMED_POLICY;
- this->item.lineno = lexer->lineno;
-
- token = policy_lex_file(lexer, 0, mystring, sizeof(mystring));
- if (token != POLICY_LEX_BARE_WORD) {
- fprintf(stderr, "%s[%d]: Expected policy name, got \"%s\"\n",
- lexer->filename, lexer->lineno,
- fr_int2str(rlm_policy_tokens, token, "?"));
- rlm_policy_free_item((policy_item_t *) this);
- return 0;
- }
-
- dattr = dict_attrbyname(mystring);
- if (dattr) {
- fprintf(stderr, "%s[%d]: Invalid policy name \"%s\": it is already defined as a dictionary attribute\n",
- lexer->filename, lexer->lineno, mystring);
- rlm_policy_free_item((policy_item_t *) this);
- return 0;
- }
-
- this->name = strdup(mystring);
- rcode = parse_block(lexer, &(this->policy));
- if (!rcode) {
- rlm_policy_free_item((policy_item_t *) this);
- return rcode;
- }
-
- /*
- * And insert it into the tree of policies.
- *
- * For now, policy names aren't scoped, they're global.
- */
- if (!rlm_policy_insert(lexer->policies, this)) {
- radlog(L_ERR, "Failed to insert policy \"%s\"", this->name);
- rlm_policy_free_item((policy_item_t *) this);
- return 0;
- }
-
- if ((lexer->debug & POLICY_DEBUG_PRINT_POLICY) != 0) {
- rlm_policy_print((policy_item_t *) this);
- }
-
- return 1;
-}
-
-
-/*
- * Parse an "include filename" statement
- *
- * FIXME: Tie this file into the CONF_SECTION for HUP handling!
- */
-static int parse_include(policy_lex_file_t *lexer)
-{
- char *p;
- policy_lex_t token;
- char filename[1024];
- char buffer[2048];
-
- token = policy_lex_file(lexer, 0, filename, sizeof(filename));
- if (token != POLICY_LEX_DOUBLE_QUOTED_STRING) {
- fprintf(stderr, "%s[%d]: Expected filename, got \"%s\"\n",
- lexer->filename, lexer->lineno,
- fr_int2str(rlm_policy_tokens, token, "?"));
- return 0;
- }
-
- /*
- * See if we're including all of the files in a subdirectory.
- */
- strlcpy(buffer, lexer->filename, sizeof(buffer));
- p = strrchr(buffer, '/');
- if (p) {
- strlcpy(p + 1, filename, sizeof(buffer) - 1 - (p - buffer));
-
-#ifdef HAVE_DIRENT_H
- p = strrchr(p + 1, '/');
- if (p && !p[1]) {
- DIR *dir;
- struct dirent *dp;
-
- p++;
-
- dir = opendir(buffer);
- if (!dir) {
- fprintf(stderr, "%s[%d]: Error opening %s:%s\n",
- lexer->filename, lexer->lineno,
- buffer, strerror(errno));
- return 0;
- }
-
- /*
- * Read the directory, ignoring "." files.
- */
- while ((dp = readdir(dir)) != NULL) {
- struct stat buf;
-
- if (dp->d_name[0] == '.') continue;
- if (strchr(dp->d_name, '~') != NULL) continue;
-
- strlcpy(p, dp->d_name,
- sizeof(buffer) - (p - buffer));
-
- if ((stat(buffer, &buf) != 0) ||
- S_ISDIR(buf.st_mode)) continue;
-
- debug_tokens("\nincluding file %s\n", buffer);
- if (!rlm_policy_parse(lexer->policies, buffer)) {
- closedir(dir);
- return 0;
- }
- }
- closedir(dir);
- return 1;
- } /* else it must have been a normalx file */
-#endif
- } else {
- snprintf(buffer, sizeof(buffer), "%s/%s",
- radius_dir, filename);
- }
-
- /*
- * Handle one include file.
- */
- debug_tokens("\nincluding file %s\n", buffer);
- if (!rlm_policy_parse(lexer->policies, buffer)) {
- return 0;
- }
-
- return 1;
-}
-
-
-/*
- * Parse data from a file into a policy language.
- */
-int rlm_policy_parse(rbtree_t *policies, const char *filename)
-{
- FILE *fp;
- policy_lex_t token;
- policy_lex_file_t mylexer, *lexer = NULL;
- char buffer[32];
-
- fp = fopen(filename, "r");
- if (!fp) {
- fprintf(stderr, "Failed to open %s: %s\n",
- filename, strerror(errno));
- return 0;
- }
-
- lexer = &mylexer;
- memset(lexer, 0, sizeof(*lexer));
- lexer->filename = filename;
- lexer->fp = fp;
- lexer->token = POLICY_LEX_BAD;
- lexer->parse = NULL; /* initial input */
- lexer->policies = policies;
-
- do {
- int reserved;
-
- token = policy_lex_file(lexer, 0, buffer, sizeof(buffer));
- switch (token) {
- case POLICY_LEX_BARE_WORD:
- reserved = fr_str2int(policy_reserved_words,
- buffer,
- POLICY_RESERVED_UNKNOWN);
- switch (reserved) {
- case POLICY_RESERVED_POLICY:
- if (!parse_named_policy(lexer)) {
- return 0;
- }
- break;
-
- case POLICY_RESERVED_INCLUDE:
- if (!parse_include(lexer)) {
- return 0;
- }
- break;
-
- case POLICY_RESERVED_DEBUG:
- if (!parse_debug(lexer)) {
- return 0;
- }
- break;
-
- default:
- fprintf(stderr, "%s[%d]: Unexpected word \"%s\"\n",
- lexer->filename, lexer->lineno,
- buffer);
- return 0;
- break;
- } /* switch over reserved words */
-
- case POLICY_LEX_EOF:
- break;
-
- default:
- fprintf(stderr, "%s[%d]: Illegal input\n",
- lexer->filename, lexer->lineno);
- return 0;
- }
- } while (token != POLICY_LEX_EOF);
-
- if (((lexer->debug & POLICY_DEBUG_PRINT_POLICY) != 0) && fr_log_fp) {
- fprintf(fr_log_fp, "# rlm_policy \n");
- }
-
- debug_tokens("--------------------------------------------------\n");
-
- return 1;
-}
-
+++ /dev/null
-/*
- * This program is is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2 if the
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-/**
- * $Id$
- * @file rlm_policy.c
- * @brief Implements a policy language (which is defunct as should not be used).
- *
- * @copyright 2004 Alan DeKok <aland@ox.org>
- * @copyright 2006 The FreeRADIUS server project
- */
-#include <freeradius-devel/ident.h>
-RCSID("$Id$")
-
-#include <freeradius-devel/radiusd.h>
-#include <freeradius-devel/modules.h>
-
-#include "rlm_policy.h"
-
-/*
- * A mapping of configuration file names to internal variables.
- *
- * Note that the string is dynamically allocated, so it MUST
- * be freed. When the configuration file parse re-reads the string,
- * it free's the old one, and strdup's the new one, placing the pointer
- * to the strdup'd string into 'config.string'. This gets around
- * buffer over-flows.
- */
-static const CONF_PARSER module_config[] = {
- { "filename", PW_TYPE_FILENAME,
- offsetof(rlm_policy_t,filename), NULL, "${confdir}/policy.txt"},
-
- { NULL, -1, 0, NULL, NULL } /* end the list */
-};
-
-
-/*
- * Callbacks for red-black trees.
- */
-static int policyname_cmp(const void *a, const void *b)
-{
- return strcmp(((const policy_named_t *)a)->name,
- ((const policy_named_t *)b)->name);
-}
-
-
-/*
- * Detach a policy.
- */
-static int policy_detach(void *instance)
-{
- rlm_policy_t *inst = instance;
-
- if (inst->policies) rbtree_free(inst->policies);
- free(instance);
- return 0;
-}
-
-/*
- * Do any per-module initialization that is separate to each
- * configured instance of the module. e.g. set up connections
- * to external databases, read configuration files, set up
- * dictionary entries, etc.
- *
- * If configuration information is given in the config section
- * that must be referenced in later calls, store a handle to it
- * in *instance otherwise put a null pointer there.
- */
-static int policy_instantiate(CONF_SECTION *conf, void **instance)
-{
- rlm_policy_t *inst;
-
- /*
- * Set up a storage area for instance data
- */
- inst = rad_malloc(sizeof(*inst));
- if (!inst) {
- return -1;
- }
- memset(inst, 0, sizeof(*inst));
-
- /*
- * If the configuration parameters can't be parsed, then
- * fail.
- */
- if (cf_section_parse(conf, inst, module_config) < 0) {
- policy_detach(inst);
- return -1;
- }
-
- inst->policies = rbtree_create(policyname_cmp,
- (void (*)(void *)) rlm_policy_free_item,
- 0);
- if (!inst->policies) {
- policy_detach(inst);
- return -1;
- }
-
- /*
- * Parse the policy from the file.
- */
- if (!rlm_policy_parse(inst->policies, inst->filename)) {
- policy_detach(inst);
- return -1;
- }
-
- *instance = inst;
-
- return 0;
-}
-
-
-/*
- * Insert a named policy into a list.
- */
-int rlm_policy_insert(rbtree_t *head, policy_named_t *policy)
-{
- if (!rbtree_insert(head, policy)) {
- return 0;
- }
-
- return 1;
-}
-
-
-/*
- * Find a named policy
- */
-policy_named_t *rlm_policy_find(rbtree_t *head, const char *name)
-{
- policy_named_t mypolicy;
-
- mypolicy.name = name;
-
- return rbtree_finddata(head, &mypolicy);
-}
-
-
-/*
- * Find the named user in this modules database. Create the set
- * of attribute-value pairs to check and reply with for this user
- * from the database. The authentication code only needs to check
- * the password, the rest is done here.
- */
-static rlm_rcode_t policy_authorize(void *instance, REQUEST *request)
-{
- return rlm_policy_evaluate((rlm_policy_t *) instance, request,
- "authorize");
-}
-
-
-static rlm_rcode_t policy_preacct(void *instance, REQUEST *request)
-{
- return rlm_policy_evaluate((rlm_policy_t *) instance, request,
- "preacct");
-}
-
-static rlm_rcode_t policy_accounting(void *instance, REQUEST *request)
-{
- return rlm_policy_evaluate((rlm_policy_t *) instance, request,
- "accounting");
-}
-
-static rlm_rcode_t policy_post_auth(void *instance, REQUEST *request)
-{
- return rlm_policy_evaluate((rlm_policy_t *) instance, request,
- "post-auth");
-}
-
-static rlm_rcode_t policy_pre_proxy(void *instance, REQUEST *request)
-{
- return rlm_policy_evaluate((rlm_policy_t *) instance, request,
- "pre-proxy");
-}
-
-static rlm_rcode_t policy_post_proxy(void *instance, REQUEST *request)
-{
- return rlm_policy_evaluate((rlm_policy_t *) instance, request,
- "post-proxy");
-}
-
-#ifdef WITH_COA
-static rlm_rcode_t policy_recv_coa(void *instance, REQUEST *request)
-{
- return rlm_policy_evaluate((rlm_policy_t *) instance, request,
- "recv-coa");
-}
-static rlm_rcode_t policy_send_coa(void *instance, REQUEST *request)
-{
- return rlm_policy_evaluate((rlm_policy_t *) instance, request,
- "send-coa");
-}
-#endif
-
-/*
- * The "free" functions are here, for no particular reason.
- */
-void rlm_policy_free_item(policy_item_t *item)
-{
- while (item) {
- policy_item_t *next = item->next;
-
- switch (item->type) {
- default:
- case POLICY_TYPE_BAD:
- break;
-
- case POLICY_TYPE_ASSIGNMENT:
- {
- policy_assignment_t *this;
-
- this = (policy_assignment_t *) item;
- if (this->lhs) free(this->lhs);
- if (this->rhs) free(this->rhs);
- }
- break;
-
- case POLICY_TYPE_CONDITIONAL:
- {
- policy_condition_t *this;
-
- this = (policy_condition_t *) item;
- if (this->lhs) free(this->lhs);
- if (this->rhs) free(this->rhs);
-
- if (this->child) {
- rlm_policy_free_item(this->child);
- this->child = NULL;
- }
- }
- break;
-
- case POLICY_TYPE_IF:
- {
- policy_if_t *this;
-
- this = (policy_if_t *) item;
- if (this->condition) {
- rlm_policy_free_item(this->condition);
- this->condition = NULL;
- }
- if (this->if_true) {
- rlm_policy_free_item(this->if_true);
- this->if_true = NULL;
- }
- if (this->if_false) {
- rlm_policy_free_item(this->if_false);
- this->if_false = NULL;
- }
- }
- break;
-
- case POLICY_TYPE_ATTRIBUTE_LIST:
- {
- policy_attributes_t *this;
-
- this = (policy_attributes_t *) item;
- rlm_policy_free_item(this->attributes);
- }
- break;
-
- case POLICY_TYPE_NAMED_POLICY:
- {
- policy_named_t *this;
-
- this = (policy_named_t *) item;
- rad_assert(this->name != NULL);
- rad_cfree(this->name);
- rlm_policy_free_item(this->policy);
- }
- break;
-
- case POLICY_TYPE_CALL:
- {
- policy_call_t *this;
-
- this = (policy_call_t *) item;
- rad_cfree(this->name);
- }
- break;
-
- case POLICY_TYPE_RETURN:
- break; /* do nothing */
-
- case POLICY_TYPE_MODULE:
- {
- policy_module_t *this;
-
- this = (policy_module_t *) item;
- if (this->cs) cf_section_free(&this->cs);
- if (this->mc) modcallable_free(&this->mc);
- }
- break;
- } /* switch over type */
- item->next = NULL; /* for debugging & sanity checks */
- item->type = POLICY_TYPE_BAD;
- free(item);
-
- item = next;
- }
-}
-
-
-/*
- * The module name should be the only globally exported symbol.
- * That is, everything else should be 'static'.
- *
- * If the module needs to temporarily modify it's instantiation
- * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
- * The server will then take care of ensuring that the module
- * is single-threaded.
- */
-module_t rlm_policy = {
- RLM_MODULE_INIT,
- "policy",
- RLM_TYPE_CHECK_CONFIG_SAFE | RLM_TYPE_HUP_SAFE, /* type */
- policy_instantiate, /* instantiation */
- policy_detach, /* detach */
- {
- NULL, /* authentication */
- policy_authorize, /* authorization */
- policy_preacct, /* preaccounting */
- policy_accounting, /* accounting */
- NULL, /* checksimul */
- policy_pre_proxy, /* pre-proxy */
- policy_post_proxy, /* post-proxy */
- policy_post_auth /* post-auth */
-#ifdef WITH_COA
- , policy_recv_coa,
- policy_send_coa
-#endif
- },
-};
+++ /dev/null
-/*
- * rlm_policy.h Header file for policy module
- *
- * Version: $Id$
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- *
- * Copyright 2004 Alan DeKok <aland@freeradius.org>
- * Copyright 2006 The FreeRADIUS server project
- */
-#ifndef _RLM_POLICY_H
-#define _RLM_POLICY_H
-
-#include <freeradius-devel/ident.h>
-RCSIDH(rlm_policy_h, "$Id$")
-
-#include <freeradius-devel/radiusd.h>
-#include <freeradius-devel/modules.h>
-#include <freeradius-devel/modcall.h>
-#include <freeradius-devel/rad_assert.h>
-
-/*
- * Internal lexer.
- */
-typedef enum policy_lex_t {
- POLICY_LEX_BAD = 0,
- POLICY_LEX_EOF, /* end of the file/input */
- POLICY_LEX_EOL, /* end of the line */
- POLICY_LEX_WHITESPACE,
- POLICY_LEX_HASH,
- POLICY_LEX_L_BRACKET,
- POLICY_LEX_R_BRACKET,
- POLICY_LEX_LC_BRACKET, /* left curly bracket */
- POLICY_LEX_RC_BRACKET, /* right curly bracket */
- POLICY_LEX_COMMA,
- POLICY_LEX_L_AND, /* logical AND */
- POLICY_LEX_L_OR, /* logical OR */
- POLICY_LEX_AND, /* bit-wise AND */
- POLICY_LEX_OR, /* bit-wise OR */
- POLICY_LEX_L_NOT,
- POLICY_LEX_PLUS, /* + */
- POLICY_LEX_MINUS, /* - */
- POLICY_LEX_ASSIGN, /* = */
- POLICY_LEX_CMP_EQUALS,
- POLICY_LEX_CMP_NOT_EQUALS,
- POLICY_LEX_CMP_TRUE,
- POLICY_LEX_CMP_FALSE,
- POLICY_LEX_LT,
- POLICY_LEX_GT,
- POLICY_LEX_LE,
- POLICY_LEX_GE,
- POLICY_LEX_RX_EQUALS,
- POLICY_LEX_RX_NOT_EQUALS,
- POLICY_LEX_SET_EQUALS, /* := */
- POLICY_LEX_AND_EQUALS, /* &= */
- POLICY_LEX_OR_EQUALS, /* |= */
- POLICY_LEX_PLUS_EQUALS, /* += */
- POLICY_LEX_MINUS_EQUALS, /* -= */
- POLICY_LEX_CONCAT_EQUALS, /* .= */
- POLICY_LEX_VARIABLE, /* %{foo} */
- POLICY_LEX_FUNCTION, /* Hmmm... */
- POLICY_LEX_BEFORE_HEAD_ASSIGN, /* ^= */
- POLICY_LEX_BEFORE_WHERE_ASSIGN, /* ^== */
- POLICY_LEX_BEFORE_HEAD_EQUALS, /* ^. */
- POLICY_LEX_BEFORE_WHERE_EQUALS, /* ^.= */
- POLICY_LEX_AFTER_TAIL_ASSIGN, /* $= */
- POLICY_LEX_AFTER_WHERE_ASSIGN, /* $== */
- POLICY_LEX_AFTER_TAIL_EQUALS, /* $. */
- POLICY_LEX_AFTER_WHERE_EQUALS, /* $.= */
- POLICY_LEX_DOUBLE_QUOTED_STRING,
- POLICY_LEX_SINGLE_QUOTED_STRING,
- POLICY_LEX_BACK_QUOTED_STRING,
- POLICY_LEX_BARE_WORD
-} policy_lex_t;
-
-typedef enum policy_type_t {
- POLICY_TYPE_BAD = 0,
- POLICY_TYPE_IF,
- POLICY_TYPE_CONDITIONAL,
- POLICY_TYPE_ASSIGNMENT,
- POLICY_TYPE_ATTRIBUTE_LIST,
- POLICY_TYPE_PRINT,
- POLICY_TYPE_NAMED_POLICY,
- POLICY_TYPE_CALL,
- POLICY_TYPE_RETURN,
- POLICY_TYPE_MODULE,
- POLICY_TYPE_NUM_TYPES
-} policy_type_t;
-
-
-/*
- * For our policy language, we want to have some reserved words.
- */
-typedef enum policy_reserved_word_t {
- POLICY_RESERVED_UNKNOWN = 0,
- POLICY_RESERVED_CONTROL,
- POLICY_RESERVED_REQUEST,
- POLICY_RESERVED_REPLY,
- POLICY_RESERVED_PROXY_REQUEST,
- POLICY_RESERVED_PROXY_REPLY,
- POLICY_RESERVED_IF,
- POLICY_RESERVED_ELSE,
- POLICY_RESERVED_DEBUG,
- POLICY_RESERVED_PRINT,
- POLICY_RESERVED_POLICY,
- POLICY_RESERVED_INCLUDE,
- POLICY_RESERVED_RETURN,
- POLICY_RESERVED_MODULE,
- POLICY_RESERVED_NUM_WORDS
-} policy_reserved_word_t;
-
-
-#define POLICY_DEBUG_NONE 0
-#define POLICY_DEBUG_PEEK (1 << 0)
-#define POLICY_DEBUG_PRINT_TOKENS (1 << 1)
-#define POLICY_DEBUG_PRINT_POLICY (1 << 2)
-#define POLICY_DEBUG_EVALUATE (1 << 3)
-
-/*
- * A policy item
- */
-typedef struct policy_item_t {
- struct policy_item_t *next;
- policy_type_t type;
- int lineno;
-} policy_item_t;
-
-
-/*
- * A list of attributes to add/replace/whatever in a packet.
- */
-typedef struct policy_print_t {
- policy_item_t item;
- policy_lex_t rhs_type;
- const char *rhs;
-} policy_print_t;
-
-
-/*
- * A list of attributes to add/replace/whatever in a packet.
- */
-typedef struct policy_attributes_t {
- policy_item_t item;
- policy_reserved_word_t where; /* where to do it */
- policy_lex_t how; /* how to do */
- policy_item_t *attributes; /* things to do */
- policy_item_t *where_loc; /* search for location in list*/
- /* FIXME: VALUE_PAIR *vps; */
-} policy_attributes_t;
-
-
-/*
- * Holds a named policy
- */
-typedef struct policy_named_t {
- policy_item_t item;
- const char *name;
- policy_item_t *policy;
-} policy_named_t;
-
-
-/*
- * Reference to a named policy
- */
-typedef struct policy_call_t {
- policy_item_t item;
- const char *name;
-} policy_call_t;
-
-
-/*
- * Hold a return code
- */
-typedef struct policy_return_t {
- policy_item_t item;
- int rcode;
-} policy_return_t;
-
-
-/*
- * Holds an assignment.
- */
-typedef struct policy_assignment_t {
- policy_item_t item;
- char *lhs;
- policy_lex_t assign; /* operator for the assignment */
- policy_lex_t rhs_type;
- char *rhs;
-} policy_assignment_t;
-
-
-/*
- * Condition
- */
-typedef struct policy_condition_t {
- policy_item_t item;
-
- policy_lex_t lhs_type;
- char *lhs;
- policy_lex_t compare;
- policy_lex_t rhs_type; /* bare word, quoted string, etc. */
- char *rhs;
- int sense; /* whether to flip match or not */
-
- policy_lex_t child_condition;
- policy_item_t *child;
-} policy_condition_t;
-
-
-/*
- * Holds an "if" statement. The "else" may be a block, or another "if"
- */
-typedef struct policy_if_t {
- policy_item_t item;
- policy_item_t *condition;
- policy_item_t *if_true;
- policy_item_t *if_false; /* assignment, or other 'if' */
-} policy_if_t;
-
-
-/*
- * Holds a reference to calling other modules... wild.
- */
-typedef struct policy_module_t {
- policy_item_t item;
- int component; /* authorize, authenticate, etc. */
- CONF_SECTION *cs;
- modcallable *mc;
-} policy_module_t;
-
-
-/*
- * Define a structure for our module configuration.
- *
- * These variables do not need to be in a structure, but it's
- * a lot cleaner to do so, and a pointer to the structure can
- * be used as the instance handle.
- */
-typedef struct rlm_policy_t {
- char *filename;
- rbtree_t *policies;
-} rlm_policy_t;
-
-
-/*
- * Functions.
- */
-extern const FR_NAME_NUMBER rlm_policy_tokens[];
-extern const FR_NAME_NUMBER policy_reserved_words[];
-extern const FR_NAME_NUMBER policy_return_codes[];
-extern const FR_NAME_NUMBER policy_component_names[];
-
-extern int rlm_policy_insert(rbtree_t *head, policy_named_t *policy);
-extern policy_named_t *rlm_policy_find(rbtree_t *head, const char *name);
-
-extern int rlm_policy_parse(rbtree_t *policies, const char *filename);
-extern void rlm_policy_free_item(policy_item_t *item);
-extern void rlm_policy_print(const policy_item_t *item);
-extern int rlm_policy_evaluate(rlm_policy_t *inst, REQUEST *request,
- const char *name);
-
-#endif /* _RLM_POLICY_H */