Removed the policy module.
authorAlan T. DeKok <aland@freeradius.org>
Sat, 16 Feb 2013 16:16:13 +0000 (11:16 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Sat, 16 Feb 2013 16:47:34 +0000 (11:47 -0500)
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

raddb/mods-available/policy [deleted file]
raddb/policy.txt [deleted file]
src/modules/rlm_policy/Makefile [deleted file]
src/modules/rlm_policy/all.mk [deleted file]
src/modules/rlm_policy/evaluate.c [deleted file]
src/modules/rlm_policy/parse.c [deleted file]
src/modules/rlm_policy/rlm_policy.c [deleted file]
src/modules/rlm_policy/rlm_policy.h [deleted file]

diff --git a/raddb/mods-available/policy b/raddb/mods-available/policy
deleted file mode 100644 (file)
index 9b1b111..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-# -*- 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
-}
-
diff --git a/raddb/policy.txt b/raddb/policy.txt
deleted file mode 100755 (executable)
index 1f62c55..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-#
-#      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"
-               }
-       }
-}
diff --git a/src/modules/rlm_policy/Makefile b/src/modules/rlm_policy/Makefile
deleted file mode 100644 (file)
index 808d84a..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#
-# 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)
diff --git a/src/modules/rlm_policy/all.mk b/src/modules/rlm_policy/all.mk
deleted file mode 100644 (file)
index 4b24e77..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-TARGET         := rlm_policy.a
-SOURCES                := rlm_policy.c parse.c evaluate.c
diff --git a/src/modules/rlm_policy/evaluate.c b/src/modules/rlm_policy/evaluate.c
deleted file mode 100644 (file)
index 1af085c..0000000
+++ /dev/null
@@ -1,1226 +0,0 @@
-/*
- * 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(&reg, this->rhs,
-                                   REG_EXTENDED) != 0) {
-                               /* FIXME: print error */
-                               return FALSE;
-                       }
-                       rad_assert(data != NULL);
-                       rcode = regexec(&reg, data,
-                                       REQUEST_MAX_REGEX + 1,
-                                       rxmatch, 0);
-                       rcode = (rcode == 0);
-                       regfree(&reg);
-
-                       /*
-                        *      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(&reg, this->rhs, REG_EXTENDED|REG_NOSUB);
-                       rad_assert(data != NULL);
-                       rcode = regexec(&reg, data,
-                                       0, NULL, 0);
-                       rcode = (rcode != 0);
-                       regfree(&reg);
-                               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. */
-}
diff --git a/src/modules/rlm_policy/parse.c b/src/modules/rlm_policy/parse.c
deleted file mode 100644 (file)
index 55bc8b3..0000000
+++ /dev/null
@@ -1,1707 +0,0 @@
-/*
- * 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;
-}
-
diff --git a/src/modules/rlm_policy/rlm_policy.c b/src/modules/rlm_policy/rlm_policy.c
deleted file mode 100644 (file)
index 9917eaa..0000000
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- *   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
-       },
-};
diff --git a/src/modules/rlm_policy/rlm_policy.h b/src/modules/rlm_policy/rlm_policy.h
deleted file mode 100644 (file)
index e5e8e18..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * 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 */