]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
remove old condition code
authorAlan T. DeKok <aland@freeradius.org>
Mon, 28 Aug 2023 14:20:26 +0000 (10:20 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Mon, 28 Aug 2023 14:20:26 +0000 (10:20 -0400)
17 files changed:
src/bin/unit_test_attribute.c
src/lib/server/base.h
src/lib/server/cf_file.c
src/lib/server/cond.h [deleted file]
src/lib/server/cond_eval.c [deleted file]
src/lib/server/cond_eval.h [deleted file]
src/lib/server/cond_tokenize.c [deleted file]
src/lib/server/connection.c
src/lib/server/libfreeradius-server.mk
src/lib/server/main_config.c
src/lib/server/map.c
src/lib/server/module.c
src/lib/server/virtual_servers.c
src/lib/unlang/compile.c
src/lib/unlang/module.c
src/lib/unlang/unlang_priv.h
src/tests/unit/condition/base.txt

index 51e5856ffb1096caf58116e79476eebf44bae1eb..e896a03a20c79bd7fdc0ef3eab3dd34ac8fe9b48 100644 (file)
@@ -31,7 +31,6 @@ typedef struct request_s request_t;
 #include <freeradius-devel/server/cf_parse.h>
 #include <freeradius-devel/server/cf_util.h>
 #include <freeradius-devel/server/command.h>
-#include <freeradius-devel/server/cond.h>
 #include <freeradius-devel/server/dependency.h>
 #include <freeradius-devel/server/dl_module.h>
 #include <freeradius-devel/server/log.h>
index 75d325ba8aa9843c55f7e2587a67feadb271f65c..37e11fb50eb1676b678b1837dd5741b40a1a9e51 100644 (file)
@@ -33,7 +33,6 @@ RCSIDH(base_h, "$Id$")
 #include <freeradius-devel/server/client.h>
 #include <freeradius-devel/server/command.h>
 #include <freeradius-devel/server/components.h>
-#include <freeradius-devel/server/cond_eval.h>
 #include <freeradius-devel/server/connection.h>
 #include <freeradius-devel/server/dependency.h>
 #include <freeradius-devel/server/dl_module.h>
@@ -52,7 +51,6 @@ RCSIDH(base_h, "$Id$")
 #include <freeradius-devel/server/paircmp.h>
 #include <freeradius-devel/server/pairmove.h>
 #include <freeradius-devel/server/password.h>
-#include <freeradius-devel/server/cond.h>
 #include <freeradius-devel/server/pool.h>
 #include <freeradius-devel/server/protocol.h>
 #include <freeradius-devel/server/regex.h>
index f995a5b8238307aa72e312ed2863c29e4699074f..ea216618f51d570f99a6f8a28ca0e6a46554d358 100644 (file)
@@ -32,7 +32,6 @@ RCSID("$Id$")
 
 #include <freeradius-devel/server/cf_file.h>
 #include <freeradius-devel/server/cf_priv.h>
-#include <freeradius-devel/server/cond.h>
 #include <freeradius-devel/server/log.h>
 #include <freeradius-devel/server/tmpl.h>
 #include <freeradius-devel/server/util.h>
@@ -3043,20 +3042,18 @@ int cf_section_write(FILE *fp, CONF_SECTION *cs, int depth)
         *      cf_data_find(cs, CF_DATA_TYPE_UNLANG, "if");
         */
        if (cs->name2) {
-               fr_cond_t *c;
-
                fputs(" ", fp);
 
+#if 0
                c = cf_data_value(cf_data_find(cs, fr_cond_t, NULL));
                if (c) {
                        char buffer[1024];
 
                        cond_print(&FR_SBUFF_OUT(buffer, sizeof(buffer)), c);
                        fprintf(fp, "(%s)", buffer);
-
-               } else {        /* dump the string as-is */
+               } else
+#endif
                        cf_string_write(fp, cs->name2, strlen(cs->name2), cs->name2_quote);
-               }
        }
 
        fputs(" {\n", fp);
diff --git a/src/lib/server/cond.h b/src/lib/server/cond.h
deleted file mode 100644 (file)
index 1bdbe6e..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-#pragma once
-/*
- *  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
- */
-
-/**
- * $Id$
- *
- * @file lib/server/cond.h
- * @brief Condition parser API
- *
- * @copyright 2013 Alan DeKok (aland@freeradius.org)
- */
-RCSIDH(cond_h, "$Id$")
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <freeradius-devel/server/tmpl.h>
-#include <freeradius-devel/server/map.h>
-
-#ifndef RADIUSD_H
-/*
- *     Also defined in radiusd.h for radius_evalute_cond()
- */
-typedef struct fr_cond_s fr_cond_t;
-#endif
-
-extern fr_table_num_sorted_t const cond_logical_op_table[];
-extern size_t cond_logical_op_table_len;
-
-extern fr_table_num_sorted_t const cond_cmp_op_table[];
-extern size_t cond_cmp_op_table_len;
-
-extern fr_table_num_sorted_t const cond_quote_table[];
-extern size_t cond_quote_table_len;
-
-typedef enum {
-       COND_TYPE_INVALID = 0,
-       COND_TYPE_TRUE,
-       COND_TYPE_FALSE,
-       COND_TYPE_TMPL,
-       COND_TYPE_RCODE,
-       COND_TYPE_MAP,
-       COND_TYPE_AND,
-       COND_TYPE_OR,
-       COND_TYPE_CHILD
-} fr_cond_type_t;
-
-typedef enum {
-       PASS2_FIXUP_NONE = 0,
-       PASS2_FIXUP_ATTR,
-       PASS2_FIXUP_TYPE,
-       PASS2_PAIRCOMPARE
-} fr_cond_pass2_t;
-
-/*
- *     Allow for the following structures:
- *
- *     FOO                     no OP, RHS is NULL
- *     FOO OP BAR
- *     (COND)                  no LHS/RHS, child is COND, child OP is true
- *     (!(COND))               no LHS/RHS, child is COND, child OP is NOT
- *     (COND1 OP COND2)        no LHS/RHS, next is COND2, next OP is OP
- */
-struct fr_cond_s {
-       fr_cond_type_t          type;
-
-       union {
-               map_t                   *map;           //!< Binary expression.
-               tmpl_t                  *vpt;           //!< Unary expression.
-               fr_cond_t               *child;         //!< Nested condition.
-               rlm_rcode_t             rcode;          //!< Rcode check.   We handle this outside of
-                                                       ///< tmpls as it doesn't apply anywhere else.
-       } data;
-
-       bool                    async_required; //!< is async required?
-       bool                    negate;         //!< Invert the result of the expression.
-       fr_cond_pass2_t         pass2_fixup;
-
-       fr_cond_t               *parent;
-       fr_cond_t               *next;
-};
-
-typedef struct {
-       fr_cond_t       *cond;
-} fr_cond_iter_t;
-
-ssize_t        fr_cond_tokenize(CONF_SECTION *cs, fr_cond_t **head, tmpl_rules_t const *rules, fr_sbuff_t *in, bool flag) CC_HINT(nonnull(1,2,4));
-
-int    fr_cond_promote_types(fr_cond_t *c, fr_sbuff_t *in, fr_sbuff_marker_t *m_lhs, fr_sbuff_marker_t *m_rhs, bool flag) CC_HINT(nonnull(1));
-
-ssize_t        cond_print(fr_sbuff_t *out, fr_cond_t const *c);
-
-fr_cond_t *fr_cond_iter_init(fr_cond_iter_t *iter, fr_cond_t *head);
-fr_cond_t *fr_cond_iter_next(fr_cond_iter_t *iter);
-
-void fr_cond_async_update(fr_cond_t *cond);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/src/lib/server/cond_eval.c b/src/lib/server/cond_eval.c
deleted file mode 100644 (file)
index e6464e5..0000000
+++ /dev/null
@@ -1,1120 +0,0 @@
-/*
- *   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
- */
-
-/**
- * $Id$
- *
- * @file src/lib/server/cond_eval.c
- * @brief Evaluate complex conditions
- *
- * @copyright 2007 The FreeRADIUS server project
- * @copyright 2007 Alan DeKok (aland@deployingradius.com)
- */
-RCSID("$Id$")
-
-#include <freeradius-devel/server/cond.h>
-#include <freeradius-devel/server/cond_eval.h>
-#include <freeradius-devel/server/module.h>
-#include <freeradius-devel/server/paircmp.h>
-#include <freeradius-devel/server/regex.h>
-#include <freeradius-devel/server/tmpl_dcursor.h>
-#include <freeradius-devel/util/debug.h>
-#include <freeradius-devel/util/print.h>
-
-#include <ctype.h>
-
-#ifdef WITH_EVAL_DEBUG
-#  define EVAL_DEBUG(fmt, ...) printf("EVAL: ");fr_fprintf(stdout, fmt, ## __VA_ARGS__);printf("\n");fflush(stdout)
-#else
-#  define EVAL_DEBUG(...)
-#endif
-
-static int cond_realize_tmpl(request_t *request,
-                            fr_value_box_t **out, fr_value_box_t **to_free,
-                            tmpl_t *in, tmpl_t *other, fr_value_box_t *async);
-
-/** Map keywords to #fr_pair_list_t values
- */
-static fr_table_num_sorted_t const cond_type_table[] = {
-       { L("child"),           COND_TYPE_CHILD         },
-       { L("tmpl"),            COND_TYPE_TMPL          },
-       { L("false"),           COND_TYPE_FALSE         },
-       { L("invalid"),         COND_TYPE_INVALID       },
-       { L("map"),             COND_TYPE_MAP           },
-       { L("true"),            COND_TYPE_TRUE          },
-};
-static size_t cond_type_table_len = NUM_ELEMENTS(cond_type_table);
-
-static fr_table_num_sorted_t const cond_pass2_table[] = {
-       { L("none"),            PASS2_FIXUP_NONE        },
-       { L("attr"),            PASS2_FIXUP_ATTR        },
-       { L("type"),            PASS2_FIXUP_TYPE        },
-       { L("paircompre"),      PASS2_PAIRCOMPARE       },
-};
-static size_t cond_pass2_table_len = NUM_ELEMENTS(cond_pass2_table);
-
-
-/** Debug function to dump a cond structure
- *
- */
-void cond_debug(fr_cond_t const *cond)
-{
-       fr_cond_t const *c;
-
-       for (c = cond; c; c =c->next) {
-               INFO("cond %s (%p)", fr_table_str_by_value(cond_type_table, c->type, "<INVALID>"), cond);
-               INFO("\tnegate : %s", c->negate ? "true" : "false");
-               INFO("\tfixup  : %s", fr_table_str_by_value(cond_pass2_table, c->pass2_fixup, "<INVALID>"));
-
-               switch (c->type) {
-               case COND_TYPE_MAP:
-                       INFO("lhs (");
-                       tmpl_debug(c->data.map->lhs);
-                       INFO(")");
-                       INFO("rhs (");
-                       tmpl_debug(c->data.map->rhs);
-                       INFO(")");
-                       break;
-
-               case COND_TYPE_RCODE:
-                       INFO("\trcode  : %s", fr_table_str_by_value(rcode_table, c->data.rcode, ""));
-                       break;
-
-               case COND_TYPE_TMPL:
-                       tmpl_debug(c->data.vpt);
-                       break;
-
-               case COND_TYPE_CHILD:
-                       INFO("child (");
-                       cond_debug(c->data.child);
-                       INFO(")");
-                       break;
-
-               case COND_TYPE_AND:
-                       INFO("&& ");
-                       break;
-
-               case COND_TYPE_OR:
-                       INFO("|| ");
-                       break;
-
-               default:
-                       break;
-               }
-       }
-}
-
-/** Evaluate a template
- *
- * Converts a tmpl_t to a boolean value.
- *
- * @param[in] request the request_t
- * @param[in] in the template to evaluate
- * @param[in] async the asynchronously evaluated value box, for XLAT and EXEC
- * @return
- *     - 0 for "no match"
- *     - 1 for "match".
- */
-static bool cond_eval_tmpl(request_t *request, tmpl_t const *in, fr_value_box_t *async)
-{
-       int rcode = false;
-       fr_pair_t *vp = NULL;
-       fr_value_box_t *box, *box_free;
-       tmpl_t *vpt;
-
-       box = box_free = NULL;
-       memcpy(&vpt, &in, sizeof(in)); /* const issues */
-
-       switch (vpt->type) {
-       case TMPL_TYPE_ATTR:
-               /*
-                *      No cast means that it's an existence check.
-                */
-               if (fr_type_is_null(tmpl_rules_cast(vpt))) {
-                       return (tmpl_find_vp(NULL, request, vpt) == 0);
-               }
-
-               /*
-                *      Cast means that we cast the attribute to a
-                *      particular type.
-                */
-               if (tmpl_find_vp(&vp, request, vpt) < 0) {
-                       return false;
-               }
-
-               MEM(box = fr_value_box_alloc_null(request));
-               box_free = box;
-
-               if (fr_value_box_cast(box, box, tmpl_rules_cast(vpt), NULL, &vp->data) < 0) {
-                       RPEDEBUG("Failed casting %pV to type %s", box,
-                                fr_type_to_str(tmpl_rules_cast(vpt)));
-                       goto done;
-               }
-               break;
-
-       case TMPL_TYPE_XLAT:
-       case TMPL_TYPE_EXEC:
-               /*
-                *      Realize and cast the tmpl.
-                */
-               if (cond_realize_tmpl(request, &box, &box_free, vpt, NULL, async) < 0) {
-                       return false;
-               }
-
-               /*
-                *      Old-style: zero length strings are false.
-                *      Other strings are true.
-                *
-                *      We don't yet have xlats returning lists of
-                *      value boxes, so there's an assert.
-                */
-               if (fr_type_is_null(tmpl_rules_cast(vpt))) {
-                       switch (box->type) {
-                       case FR_TYPE_STRING:
-                       case FR_TYPE_OCTETS:
-                               rcode = (box->vb_length > 0);
-                               goto done;
-
-                               /*
-                                *      Not yet handled.
-                                */
-                       default:
-                               fr_assert(0);
-                               return false;
-                       }
-               }
-               break;
-
-               /*
-                *      Everything else MUST have been forbidden, or
-                *      already realized to a COND_TYPE_TRUE/FALSE.
-                */
-       default:
-               fr_assert(0);
-               EVAL_DEBUG("FAIL %d", __LINE__);
-               goto done;
-       }
-
-       /*
-        *      If it's already a bool, just use that.
-        *
-        *      Otherwise cast the data to bool.  This cast lets the
-        *      value code figure out what is false and what is true.
-        */
-       if (box->type == FR_TYPE_BOOL) {
-               rcode = box->vb_bool;
-
-       } else {
-               fr_value_box_t out;
-
-               fr_value_box_init_null(&out);
-               if (fr_value_box_cast(request, &out, FR_TYPE_BOOL, NULL, box) < 0) {
-                       talloc_free(box_free);
-                       return -1;
-               }
-
-               rcode = out.vb_bool;
-               fr_value_box_clear(&out);
-       }
-
-done:
-       talloc_free(box_free);
-       return rcode;
-}
-
-
-#ifdef HAVE_REGEX
-/** Perform a regular expressions comparison between two operands
- *
- * @param[in] request          The current request.
- * @param[in] subject          to executed regex against.
- * @param[in,out] preg         Pointer to pre-compiled or runtime-compiled
- *                             regular expression.  In the case of runtime-compiled
- *                             the pattern may be stolen by the `regex_sub_to_request`
- *                             function as the original pattern is needed to resolve
- *                             capture groups.
- *                             The caller should only free the `regex_t *` if it
- *                             compiled it, and the pointer has not been set to NULL
- *                             when this function returns.
- * @return
- *     - -1 on failure.
- *     - 0 for "no match".
- *     - 1 for "match".
- */
-static int cond_do_regex(request_t *request, fr_value_box_t const *subject, regex_t **preg)
-{
-       uint32_t        subcaptures;
-       int             ret;
-
-       fr_regmatch_t   *regmatch;
-
-       if (!fr_cond_assert(subject != NULL)) return -1;
-       if (!fr_cond_assert(subject->type == FR_TYPE_STRING)) return -1;
-
-       EVAL_DEBUG("CMP WITH REGEX");
-
-       subcaptures = regex_subcapture_count(*preg);
-       if (!subcaptures) subcaptures = REQUEST_MAX_REGEX + 1;  /* +1 for %{0} (whole match) capture group */
-       MEM(regmatch = regex_match_data_alloc(NULL, subcaptures));
-
-       /*
-        *      Evaluate the expression
-        */
-       ret = regex_exec(*preg, subject->vb_strvalue, subject->vb_length, regmatch);
-       switch (ret) {
-       case 0:
-               EVAL_DEBUG("CLEARING SUBCAPTURES");
-               regex_sub_to_request(request, NULL, NULL);      /* clear out old entries */
-               break;
-
-       case 1:
-               EVAL_DEBUG("SETTING SUBCAPTURES");
-               regex_sub_to_request(request, preg, &regmatch);
-               break;
-
-       case -1:
-               EVAL_DEBUG("REGEX ERROR");
-               RPEDEBUG("regex failed");
-               break;
-
-       default:
-               break;
-       }
-
-       talloc_free(regmatch);  /* free if not consumed */
-
-       return ret;
-}
-#endif
-
-static size_t regex_escape(UNUSED request_t *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
-{
-       char *p = out;
-
-       while (*in && (outlen >= 2)) {
-               switch (*in) {
-               case '\\':
-               case '.':
-               case '*':
-               case '+':
-               case '?':
-               case '|':
-               case '^':
-               case '$':
-               case '[':       /* we don't list close braces */
-               case '{':
-               case '(':
-                       if (outlen < 3) goto done;
-
-                       *(p++) = '\\';
-                       outlen--;
-                       FALL_THROUGH;
-
-               default:
-                       *(p++) = *(in++);
-                       outlen--;
-                       break;
-               }
-       }
-
-done:
-       *(p++) = '\0';
-       return p - out;
-}
-
-/** Turn a raw #tmpl_t into #fr_value_box_t, mostly.
- *
- *  It does nothing for lists, attributes, and precompiled regexes.
- *
- *  For #TMPL_TYPE_DATA, it returns the raw data, which MUST NOT have
- *  a cast, and which MUST have the correct data type.
- *
- *  For everything else (exec, xlat, regex-xlat), it evaluates the
- *  tmpl, and returns a "realized" #fr_value_box_t.  That box can then
- *  be used for comparisons, with minimal extra processing.
- */
-static int cond_realize_tmpl(request_t *request,
-                            fr_value_box_t **out, fr_value_box_t **to_free,
-                            tmpl_t *in, tmpl_t *other, /* both really should be 'const' */
-                            fr_value_box_t *async)
-{
-       fr_value_box_t          *box;
-       xlat_escape_legacy_t    escape = NULL;
-
-       *out = *to_free = NULL;
-
-       switch (in->type) {
-       /*
-        *      These are handled elsewhere.
-        */
-#ifdef HAVE_REGEX
-       case TMPL_TYPE_REGEX:
-               fr_assert(!async);
-               return 0;
-#endif
-
-       case TMPL_TYPE_ATTR:
-               /*
-                *      fast path?  If there's only one attribute, AND
-                *      tmpl_attr_tail_num is a simple number, then just find
-                *      that attribute.  This fast path should ideally
-                *      avoid all of the cost of setting up the
-                *      cursors?
-                */
-               fr_assert(!async);
-               return 0;
-
-       /*
-        *      Return the raw data, which MUST already have been
-        *      converted to the correct thing.
-        */
-       case TMPL_TYPE_DATA:
-               fr_assert((fr_type_is_null(tmpl_rules_cast(in))) || (tmpl_rules_cast(in) == tmpl_value_type(in)));
-               *out = tmpl_value(in);
-               fr_assert(!async);
-               return 0;
-
-#ifdef HAVE_REGEX
-       case TMPL_TYPE_REGEX_XLAT:
-               escape = regex_escape;
-               FALL_THROUGH;
-#endif
-
-       case TMPL_TYPE_EXEC:
-       case TMPL_TYPE_XLAT:
-       {
-               ssize_t         ret;
-               fr_type_t       cast_type;
-               fr_dict_attr_t const *da = NULL;
-
-               /*
-                *      We can't be TMPL_TYPE_ATTR or TMPL_TYPE_DATA,
-                *      because that was caught above.
-                *
-                *      So we look for an explicit cast, and if we
-                *      don't find that, then the *other* side MUST
-                *      have an explicit data type.
-                */
-               if (tmpl_rules_cast(in) != FR_TYPE_NULL) {
-                       cast_type = tmpl_rules_cast(in);
-
-               } else if (!other) {
-                       cast_type = FR_TYPE_STRING;
-
-               } else if (tmpl_rules_cast(other)) {
-                       cast_type = tmpl_rules_cast(other);
-
-               } else if (tmpl_is_attr(other)) {
-                       da = tmpl_attr_tail_da(other);
-                       cast_type = da->type;
-
-               } else if (tmpl_is_data(other)) {
-                       cast_type = tmpl_value_type(other);
-
-               } else {
-                       cast_type = FR_TYPE_STRING;
-               }
-
-               if (!async) {
-                       box = NULL;
-                       ret = tmpl_aexpand(request, &box, request, in, escape, NULL);
-                       if (ret < 0) {
-                               if (cast_type != FR_TYPE_STRING) return -1;
-
-                               box = fr_value_box_alloc(request, FR_TYPE_STRING, NULL);
-                               if (!box) return -1;
-                       }
-
-                       fr_assert(box != NULL);
-                       *out = *to_free = box;
-
-               } else {
-                       *out = box = async;
-                       *to_free = NULL;
-               }
-
-               if (cast_type != box->type) {
-                       if (fr_value_box_cast_in_place(box, box, cast_type, da) < 0) {
-                               *out = *to_free = NULL;
-                               RPEDEBUG("Failed casting!");
-                               return -1;
-                       }
-               }
-
-               return 0;
-       }
-
-       default:
-               break;
-       }
-
-       /*
-        *      Other tmpl type, return an error.
-        */
-       fr_assert(0);
-       return -1;
-}
-
-
-static int cond_realize_attr(request_t *request, fr_value_box_t **realized, fr_value_box_t *box,
-                            tmpl_t *vpt, fr_pair_t *vp, fr_dict_attr_t const *da)
-{
-       fr_type_t cast_type;
-
-       /*
-        *      Sometimes we're casting to a type with enums.  If so,
-        *      use that.
-        */
-       if (da) {
-               cast_type = da->type;
-
-       } else if (tmpl_rules_cast(vpt) != FR_TYPE_NULL) {
-               /*
-                *      If there's an explicit cast, use that.
-                */
-               cast_type = tmpl_rules_cast(vpt);
-
-       } else {
-               /*
-                *      Otherwise the VP is already of the correct type.
-                */
-               goto dont_cast;
-       }
-
-       /*
-        *      No casting needed.  Just return the data.
-        */
-       if (cast_type == vp->vp_type) {
-       dont_cast:
-               *realized = &vp->data;
-               return 0;
-       }
-
-       fr_value_box_init_null(box);
-       if (fr_value_box_cast(request, box, cast_type, da, &vp->data) < 0) {
-               if (request) RPEDEBUG("Failed casting %pV to type %s", &vp->data,
-                                     fr_type_to_str(tmpl_rules_cast(vpt)));
-               return -1;
-       }
-
-       *realized = box;
-       return 0;
-}
-
-static bool cond_compare_attrs(request_t *request, fr_value_box_t *lhs, map_t const *map)
-{
-       int                     rcode;
-       fr_pair_t               *vp;
-       fr_dcursor_t            cursor;
-       tmpl_dcursor_ctx_t      cc;
-       fr_value_box_t          *rhs, rhs_cast;
-       fr_dict_attr_t const    *da = NULL;
-
-       if (tmpl_is_attr(map->lhs) && fr_type_is_null(tmpl_rules_cast(map->lhs))) da = tmpl_attr_tail_da(map->lhs);
-
-       fr_assert(lhs != NULL);
-       rhs = NULL;             /* shut up clang scan */
-       fr_value_box_init_null(&rhs_cast);
-
-       for (vp = tmpl_dcursor_init(&rcode, request, &cc, &cursor, request, map->rhs);
-            vp;
-            vp = fr_dcursor_next(&cursor)) {
-               if (cond_realize_attr(request, &rhs, &rhs_cast, map->rhs, vp, da) < 0) {
-                       RPEDEBUG("Failed realizing RHS %pV", &vp->data);
-                       if (rhs == &rhs_cast) fr_value_box_clear(&rhs_cast);
-                       rcode = -1;
-                       break;
-               }
-
-               fr_assert(rhs && (lhs->type == rhs->type));
-
-               rcode = fr_value_box_cmp_op(map->op, lhs, rhs);
-
-               if (rhs == &rhs_cast) fr_value_box_clear(&rhs_cast);
-               if (rcode != 0) break;
-       }
-
-       tmpl_dcursor_clear(&cc);
-       return (rcode == 1);
-}
-
-static bool cond_compare_virtual(request_t *request, map_t const *map)
-{
-       int                     rcode;
-       fr_pair_t               *vp;
-       fr_value_box_t          *rhs, rhs_cast;
-       fr_dcursor_t            cursor;
-       tmpl_dcursor_ctx_t      cc;
-
-       fr_assert(tmpl_is_attr(map->lhs));
-       fr_assert(tmpl_is_attr(map->rhs));
-
-       rhs = NULL;             /* shut up clang scan */
-       fr_value_box_init_null(&rhs_cast);
-
-       for (vp = tmpl_dcursor_init(&rcode, request, &cc, &cursor, request, map->rhs);
-            vp;
-            vp = fr_dcursor_next(&cursor)) {
-               if (cond_realize_attr(request, &rhs, &rhs_cast, map->rhs, vp, NULL) < 0) {
-                       RPEDEBUG("Failed realizing RHS %pV", &vp->data);
-                       if (rhs == &rhs_cast) fr_value_box_clear(&rhs_cast);
-                       rcode = -1;
-                       break;
-               }
-
-               rcode = paircmp_virtual(request, tmpl_attr_tail_da(map->lhs), map->op, rhs);
-               rcode = (rcode == 0) ? 1 : 0;
-               if (rhs == &rhs_cast) fr_value_box_clear(&rhs_cast);
-               if (rcode != 0) break;
-       }
-
-       tmpl_dcursor_clear(&cc);
-       return (rcode == 1);
-}
-
-/** Evaluate a map
- *
- * @param[in] request the request_t
- * @param[in] c the condition to evaluate
- * @param[in] async_lhs the asynchronously evaluated value box, for XLAT and EXEC
- * @param[in] async_rhs the asynchronously evaluated value box, for XLAT and EXEC
- * @return
- *     - false for no match (including "not found")
- *     - true for match
- */
-static bool cond_eval_map(request_t *request, fr_cond_t const *c,
-                        fr_value_box_t *async_lhs, fr_value_box_t *async_rhs)
-{
-       int             rcode = 0;
-       map_t const     *map = c->data.map;
-
-       fr_value_box_t *lhs, *lhs_free;
-       fr_value_box_t *rhs, *rhs_free;
-       regex_t         *preg, *preg_free;
-
-#ifndef NDEBUG
-       /*
-        *      At this point, all tmpls MUST have been resolved.
-        */
-       fr_assert(!tmpl_is_unresolved(c->data.map->lhs));
-       fr_assert(!tmpl_is_unresolved(c->data.map->rhs));
-#endif
-
-       EVAL_DEBUG(">>> MAP TYPES LHS: %s, RHS: %s",
-                  tmpl_type_to_str(map->lhs->type),
-                  tmpl_type_to_str(map->rhs->type));
-#ifdef WITH_EVAL_DEBUG
-       tmpl_debug(map->lhs);
-       tmpl_debug(map->rhs);
-#endif
-
-       MAP_VERIFY(map);
-       preg = preg_free = NULL;
-
-       /*
-        *      Realize the LHS of a condition.
-        */
-       if (cond_realize_tmpl(request, &lhs, &lhs_free, map->lhs, map->rhs, async_lhs) < 0) {
-               fr_strerror_const("Failed evaluating left side of condition");
-               return false;
-       }
-
-       /*
-        *      Realize the RHS of a condition.
-        */
-       if (cond_realize_tmpl(request, &rhs, &rhs_free, map->rhs, map->lhs, async_rhs) < 0) {
-               fr_strerror_const("Failed evaluating right side of condition");
-               return false;
-       }
-
-       /*
-        *      Precompile the regular expressions.
-        */
-       if (map->op == T_OP_REG_EQ) {
-               if (tmpl_is_regex(map->rhs)) {
-                       if (!fr_cond_assert(!rhs)) goto done;
-
-                       preg = tmpl_regex(map->rhs);
-               } else {
-                       ssize_t slen;
-
-                       if (!fr_cond_assert(rhs && tmpl_contains_regex(map->rhs))) goto done;
-
-                       slen = regex_compile(request, &preg_free, rhs->vb_strvalue, rhs->vb_length,
-                                            tmpl_regex_flags(map->rhs), true, true);
-                       if (slen <= 0) {
-                               REMARKER(rhs->vb_strvalue, -slen, "%s", fr_strerror());
-                               EVAL_DEBUG("FAIL %d", __LINE__);
-                               return false;
-                       }
-                       preg = preg_free;
-               }
-
-               /*
-                *      We have a value on the LHS.  Just go do that.
-                */
-               if (lhs) {
-                       rcode = cond_do_regex(request, lhs, &preg);
-                       goto done;
-               }
-
-               /*
-                *      Otherwise loop over the LHS attribute / list.
-                */
-               goto check_attrs;
-       }
-
-       /*
-        *      We have both left and right sides as #fr_value_box_t,
-        *      we can just evaluate the comparison here.
-        *
-        *      This is largely just cond_cmp_values() ...
-        */
-       if (lhs && rhs) {
-               rcode = fr_value_box_cmp_op(map->op, lhs, rhs);
-               goto done;
-       }
-
-       /*
-        *      LHS is a virtual attribute.  The RHS MUST be data, not
-        *      an attribute or a list.
-        */
-       if (c->pass2_fixup == PASS2_PAIRCOMPARE) {
-               fr_assert(tmpl_is_attr(map->lhs));
-
-               if (map->op == T_OP_REG_EQ) {
-                       fr_strerror_const("Virtual attributes cannot be used with regular expressions");
-                       return false;
-               }
-
-               /*
-                *      &LDAP-Group == &Filter-Id
-                */
-               if (tmpl_is_attr(map->rhs)) {
-                       fr_assert(!lhs);
-                       fr_assert(!rhs);
-
-                       rcode = cond_compare_virtual(request, map);
-                       goto done;
-               }
-
-               /*
-                *      Forbid bad things.
-                */
-               if (!rhs) {
-                       fr_strerror_const("Invalid comparison for virtual attribute");
-                       return false;
-               }
-
-               /*
-                *      Do JUST the virtual attribute comparison.
-                *      Skip all of the rest of the complexity of paircmp().
-                */
-               rcode = paircmp_virtual(request, tmpl_attr_tail_da(map->lhs), c->data.map->op, rhs);
-               rcode = (rcode == 0) ? 1 : 0;
-               goto done;
-       }
-
-check_attrs:
-       switch (map->lhs->type) {
-       /*
-        *      LHS is an attribute or list
-        */
-       case TMPL_TYPE_ATTR:
-       {
-               fr_pair_t               *vp;
-               fr_dcursor_t            cursor;
-               tmpl_dcursor_ctx_t      cc;
-
-               fr_assert(!lhs);
-
-               for (vp = tmpl_dcursor_init(&rcode, request, &cc, &cursor, request, map->lhs);
-                    vp;
-                    vp = fr_dcursor_next(&cursor)) {
-                       fr_value_box_t lhs_cast;
-
-                       /*
-                        *      Take the value box directly from the
-                        *      attribute, _unless_ there's a cast.
-                        */
-                       if (cond_realize_attr(request, &lhs, &lhs_cast, map->lhs, vp, NULL) < 0) {
-                               rcode = -1;
-                               goto done;
-                       }
-                       fr_assert(lhs != NULL);
-
-                       /*
-                        *      Now that we have a realized LHS, we
-                        *      can do a regex comparison, using the
-                        *      precompiled regex.
-                        */
-                       if (map->op == T_OP_REG_EQ) {
-                               rcode = cond_do_regex(request, lhs, &preg);
-                               goto next;
-                       }
-
-                       /*
-                        *      We have a realized RHS.  Just do the
-                        *      comparisons with the value boxes.
-                        *
-                        *      Realizing the LHS means that we've
-                        *      either used the VP data as-is, or cast
-                        *      it to the correct data type.
-                        */
-                       if (rhs) {
-                               fr_assert(lhs->type == rhs->type);
-                               rcode = fr_value_box_cmp_op(map->op, lhs, rhs);
-                               goto next;
-                       }
-
-                       /*
-                        *      And we're left with attribute
-                        *      comparisons.  We've got to find the
-                        *      attribute on the RHS, and do the
-                        *      comparisons.
-                        *
-                        *      This comparison means looping over all
-                        *      matching attributes.  We're already
-                        *      many layers deep of indentation, so
-                        *      just dump this code into a separate
-                        *      function.
-                        */
-                       fr_assert(tmpl_is_attr(map->rhs));
-
-                       rcode = cond_compare_attrs(request, lhs, map);
-
-               next:
-                       if (lhs == &lhs_cast) fr_value_box_clear(&lhs_cast);
-                       lhs = NULL;
-                       if (rcode != 0) goto done;
-                       continue;
-               }
-
-               tmpl_dcursor_clear(&cc);
-       }
-               break;
-
-       default:
-               fr_assert(0);
-               rcode = -1;
-               break;
-       }
-
-       EVAL_DEBUG("<<<");
-
-done:
-       talloc_free(lhs_free);
-       talloc_free(rhs_free);
-
-       /*
-        *      Capture groups may have grabbed preg and put it into
-        *      request data, in which case we don't free it.
-        */
-       if (preg) talloc_free(preg_free);
-       return (rcode == 1);
-}
-
-
-/** Evaluate a fr_cond_t;
- *
- * @param[in] request the request_t
- * @param[in] modreturn the previous module return code
- * @param[in] c the condition to evaluate
- * @return
- *     - false for "no match", including "not found"
- *     - true for "match"
- */
-bool cond_eval(request_t *request, rlm_rcode_t modreturn, fr_cond_t const *c)
-{
-       int rcode = false;
-
-#ifdef WITH_EVAL_DEBUG
-       char buffer[1024];
-
-       cond_print(&FR_SBUFF_OUT(buffer, sizeof(buffer)), c);
-       EVAL_DEBUG("%s", buffer);
-#endif
-
-       while (c) {
-               switch (c->type) {
-               case COND_TYPE_TMPL:
-                       rcode = cond_eval_tmpl(request, c->data.vpt, NULL);
-                       break;
-
-               case COND_TYPE_RCODE:
-                       rcode = (c->data.rcode == modreturn);
-                       break;
-
-               case COND_TYPE_MAP:
-                       rcode = cond_eval_map(request, c, NULL, NULL);
-                       break;
-
-               case COND_TYPE_CHILD:
-                       c = c->data.child;
-                       continue;
-
-               case COND_TYPE_TRUE:
-                       rcode = true;
-                       break;
-
-               case COND_TYPE_FALSE:
-                       rcode = false;
-                       break;
-               default:
-                       EVAL_DEBUG("FAIL %d", __LINE__);
-                       return false;
-               }
-
-               /*
-                *      Errors are "no match".
-                */
-               if (rcode < 0) return false;
-
-               if (c->negate) rcode = !rcode;
-
-               /*
-                *      We've fallen off of the end of this evaluation
-                *      string.  Go back up to the parent, and then to
-                *      the next sibling of the parent.
-                *
-                *      Do this repeatedly until we have a c->next
-                */
-               while (!c->next) {
-return_to_parent:
-                       c = c->parent;
-                       if (!c) goto done;
-               }
-
-               /*
-                *      Do short-circuit evaluations.
-                */
-               switch (c->next->type) {
-               case COND_TYPE_AND:
-                       if (!rcode) goto return_to_parent;
-
-                       c = c->next->next; /* skip the && */
-                       break;
-
-               case COND_TYPE_OR:
-                       if (rcode) goto return_to_parent;
-
-                       c = c->next->next; /* skip the || */
-                       break;
-
-               default:
-                       fr_assert(0);
-                       c = c->next;
-                       break;
-               }
-       }
-
-done:
-       if (rcode < 0) {
-               EVAL_DEBUG("FAIL %d", __LINE__);
-       }
-       return (rcode == 1);
-}
-
-/** Asynchronous evaluation of conditions.
- *
- * The caller is expected to clear the structure, and then set
- *     a->ctx = talloc ctx for ephemeral value boxes
- *     a->state = COND_EVAL_STATE_INIT
- *     a->c = condition to evaluate
- *     a->modreturn the module return code before the condition
- *     a->result = true
- *
- * On return, the caller checks a->state
- *
- * COND_EVAL_STATE_EXPAND - a->tmpl_lhs and/or a->tmpl_rhs are
- * asynchronous templates which need to be pushed onto the unlang
- * stack in order to be evaluated.  The evaluation results should go
- * into a->vb_lhs and a->vb_rhs, respectively.  The caller should then
- * set a->state = COND_EVAL_STATE_EVAL, and call the function again to
- * evaluate the results.
- *
- * COND_EVAL_STATE_DONE - the result of the condition is in a->result.
- *
- * @param[in] request the request to evaluate
- * @param[in,out] a the asynchronous data structure to evaluate
- * @return
- *     - <0 on error
- *     - 0 on success
- */
-int cond_eval_async(request_t *request, fr_cond_async_t *a)
-{
-       int rcode;
-       fr_cond_t const *c;
-
-       if (!request || !a || !a->c) return -1;
-
-redo:
-       c = a->c;
-
-       if (a->state == COND_EVAL_STATE_INIT) {
-               while (c->type == COND_TYPE_CHILD) {
-                       c = c->data.child;
-               }
-
-               /*
-                *      Evaluate synchronous conditions as quickly as
-                *      possible.
-                */
-               if (!c->async_required) {
-                       a->result = cond_eval(request, a->modreturn, a->c);
-                       goto return_to_parent;
-               }
-
-               switch (c->type) {
-               case COND_TYPE_TMPL:
-                       fr_assert(tmpl_async_required(c->data.vpt));
-                       a->tmpl_lhs = c->data.vpt;
-                       a->tmpl_rhs = NULL;
-                       break;
-
-               case COND_TYPE_MAP:
-                       a->tmpl_lhs = tmpl_async_required(c->data.map->lhs) ? c->data.map->lhs : NULL;
-                       a->tmpl_rhs = tmpl_async_required(c->data.map->rhs) ? c->data.map->rhs : NULL;
-
-                       fr_assert(a->tmpl_lhs || a->tmpl_rhs);
-                       break;
-
-               default:
-                       fr_assert(0);
-                       return -1;
-               }
-
-               /*
-                *      Tell the caller to expand the tmpls.
-                *
-                *      The caller should then set
-                *
-                *              a->state = COND_EVAL_STATE_EVAL
-                *
-                *      in order to tell us that we need to evaluate
-                *      the expanded tmpls.
-                */
-               a->state = COND_EVAL_STATE_EXPAND;
-               return 0;
-       } /* INIT state */
-
-       if (a->state == COND_EVAL_STATE_EVAL) {
-               switch (c->type) {
-               case COND_TYPE_TMPL:
-                       fr_assert(a->vb_lhs);
-                       rcode = cond_eval_tmpl(request, c->data.vpt, a->vb_lhs);
-                       a->result = (rcode == 1);
-                       break;
-
-               case COND_TYPE_MAP:
-                       fr_assert(a->vb_lhs || a->vb_rhs);
-
-                       rcode = cond_eval_map(request, c, a->vb_lhs, a->vb_rhs);
-                       a->result = (rcode == 1);
-                       break;
-
-               default:
-                       fr_assert(0);
-                       return -1;
-               }
-
-               TALLOC_FREE(a->vb_lhs);
-               TALLOC_FREE(a->vb_rhs);
-               a->tmpl_lhs = a->tmpl_rhs = NULL;
-
-               if (c->negate) a->result = !a->result;
-       } /* EVAL state */
-
-       /*
-        *      We've fallen off of the end of this evaluation
-        *      string.  Go back up to the parent, and then to
-        *      the next sibling of the parent.
-        *
-        *      Do this repeatedly until we have a c->next.
-        */
-       while (!c->next) {
-return_to_parent:
-               c = c->parent;
-               if (!c) {
-                       a->state = COND_EVAL_STATE_DONE;
-                       return 0;
-               }
-       }
-       c = c->next;
-
-       /*
-        *      Do short-circuit evaluations.
-        */
-       switch (c->type) {
-       case COND_TYPE_AND:
-               if (!a->result) goto return_to_parent;
-
-               fr_assert(c->next != NULL);
-               c = c->next; /* skip the && */
-               break;
-
-       case COND_TYPE_OR:
-               if (a->result) goto return_to_parent;
-
-               fr_assert(c->next != NULL);
-               c = c->next; /* skip the || */
-               break;
-
-       default:
-               fr_assert(0);
-               break;
-       }
-
-       /*
-        *      We now have a new condition which needs to be
-        *      evaluated.  Go back to figuring out if it's async or
-        *      not.
-        */
-       a->c = c;
-       a->state = COND_EVAL_STATE_INIT;
-       goto redo;
-}
-
-/** Evaluate a map as if it is a condition.
- *
- */
-bool fr_cond_eval_map(request_t *request, map_t const *map)
-{
-       fr_cond_t cond;
-
-       memset(&cond, 0, sizeof(cond));
-
-       /*
-        *      Convert !* and =* to existence checks.
-        */
-       switch (map->op) {
-       case T_OP_CMP_FALSE:
-               cond.negate = true;
-               FALL_THROUGH;
-
-       case T_OP_CMP_TRUE:
-               cond.type = COND_TYPE_TMPL;
-               cond.data.vpt = UNCONST(tmpl_t *, map->lhs);
-               break;
-
-       default:
-               cond.type = COND_TYPE_MAP;
-               cond.data.map = UNCONST(map_t *, map);
-               break;
-       }
-
-       return cond_eval(request, RLM_MODULE_NOOP, &cond);
-}
diff --git a/src/lib/server/cond_eval.h b/src/lib/server/cond_eval.h
deleted file mode 100644 (file)
index f754249..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-#pragma once
-/*
- *  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
- */
-
-/**
- * $Id$
- *
- * @file lib/server/cond_eval.h
- * @brief Structures and prototypes for the condition evaluation code
- *
- * @copyright 2007 The FreeRADIUS server project
- * @copyright 2007 Alan DeKok (aland@deployingradius.com)
- */
-RCSIDH(cond_eval_h, "$Id$")
-
-#include <freeradius-devel/server/request.h>
-#include <freeradius-devel/server/map.h>
-#include <freeradius-devel/util/value.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* evaluate.c */
-typedef struct fr_cond_s fr_cond_t;
-
-void   cond_debug(fr_cond_t const *cond);
-
-bool   cond_eval(request_t *request, rlm_rcode_t modreturn, fr_cond_t const *c);
-
-typedef struct {
-       TALLOC_CTX      *ctx;           //!< for intermediate value boxes
-       fr_cond_t const *c;             //!< the current condition being evaluated
-       rlm_rcode_t     modreturn;      //!< the previous module return code;
-
-       tmpl_t const    *tmpl_lhs;      //!< the LHS async template to evaluate
-       tmpl_t const    *tmpl_rhs;      //!< the RHS async template to evaluate
-
-       fr_value_box_t  *vb_lhs;        //!< the output of the LHS async evaluation
-       fr_value_box_t  *vb_rhs;        //!< the output of the RHS async evaluation
-
-       enum {
-               COND_EVAL_STATE_INVALID = 0,
-               COND_EVAL_STATE_INIT,
-               COND_EVAL_STATE_EXPAND,
-               COND_EVAL_STATE_EVAL,
-               COND_EVAL_STATE_DONE,
-       } state;
-
-       bool            result;         //!< the final conditional result
-} fr_cond_async_t;
-
-int cond_eval_async(request_t *request, fr_cond_async_t *a);
-
-bool fr_cond_eval_map(request_t *request, map_t const *map);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/src/lib/server/cond_tokenize.c b/src/lib/server/cond_tokenize.c
deleted file mode 100644 (file)
index 9ba70e6..0000000
+++ /dev/null
@@ -1,1599 +0,0 @@
-/*
- *   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
- */
-
-/**
- * $Id$
- *
- * @file src/lib/server/cond_tokenize.c
- * @brief Parse complex conditions
- *
- * @copyright 2013 Alan DeKok (aland@freeradius.org)
- */
-RCSID("$Id$")
-
-#include <freeradius-devel/server/base.h>
-#include <freeradius-devel/server/cond_eval.h>
-#include <freeradius-devel/server/cond.h>
-#include <freeradius-devel/util/debug.h>
-#include <freeradius-devel/protocol/freeradius/freeradius.internal.h>
-
-#include <ctype.h>
-
-static fr_table_num_sorted_t const allowed_return_codes[] = {
-       { L("fail"),            1 },
-       { L("handled"),         1 },
-       { L("invalid"),         1 },
-       { L("noop"),            1 },
-       { L("notfound"),        1 },
-       { L("ok"),              1 },
-       { L("reject"),          1 },
-       { L("updated"),         1 },
-       { L("disallow"),        1 }
-};
-static size_t allowed_return_codes_len = NUM_ELEMENTS(allowed_return_codes);
-
-fr_table_num_sorted_t const cond_quote_table[] = {
-       { L("\""),      T_DOUBLE_QUOTED_STRING  },      /* Don't re-order, backslash throws off ordering */
-       { L("'"),       T_SINGLE_QUOTED_STRING  },
-       { L("/"),       T_SOLIDUS_QUOTED_STRING },
-       { L("`"),       T_BACK_QUOTED_STRING    }
-};
-size_t cond_quote_table_len = NUM_ELEMENTS(cond_quote_table);
-
-fr_table_num_sorted_t const cond_logical_op_table[] = {
-       { L("&&"),      COND_TYPE_AND           },
-       { L("||"),      COND_TYPE_OR            }
-};
-size_t cond_logical_op_table_len = NUM_ELEMENTS(cond_logical_op_table);
-
-fr_table_num_sorted_t const cond_cmp_op_table[] = {
-       { L("!*"),      T_OP_CMP_FALSE          },
-       { L("!="),      T_OP_NE                 },
-       { L("!~"),      T_OP_REG_NE             },
-       { L(":="),      T_OP_SET                },
-       { L("<"),       T_OP_LT                 },
-       { L("<="),      T_OP_LE                 },
-       { L("="),       T_OP_EQ                 },
-       { L("=*"),      T_OP_CMP_TRUE           },
-       { L("=="),      T_OP_CMP_EQ             },
-       { L("=~"),      T_OP_REG_EQ             },
-       { L(">"),       T_OP_GT                 },
-       { L(">="),      T_OP_GE                 }
-};
-size_t cond_cmp_op_table_len = NUM_ELEMENTS(cond_cmp_op_table);
-
-/*
- *     This file shouldn't use any functions from the server core.
- */
-ssize_t cond_print(fr_sbuff_t *out, fr_cond_t const *in)
-{
-       fr_sbuff_t              our_out = FR_SBUFF(out);
-       fr_cond_t const         *c = in;
-
-       while (c) {
-               if (c->negate) FR_SBUFF_IN_CHAR_RETURN(&our_out, '!');
-
-               switch (c->type) {
-               case COND_TYPE_TMPL:
-                       fr_assert(c->data.vpt != NULL);
-                       FR_SBUFF_RETURN(tmpl_print_quoted, &our_out, c->data.vpt, TMPL_ATTR_REF_PREFIX_YES);
-                       break;
-
-               case COND_TYPE_RCODE:
-                       fr_assert(c->data.rcode != RLM_MODULE_NOT_SET);
-                       FR_SBUFF_IN_STRCPY_RETURN(&our_out, fr_table_str_by_value(rcode_table, c->data.rcode, ""));
-                       break;
-
-               case COND_TYPE_MAP:
-                       FR_SBUFF_RETURN(map_print, &our_out, c->data.map);
-                       break;
-
-               case COND_TYPE_CHILD:
-                       FR_SBUFF_IN_CHAR_RETURN(&our_out, '(');
-                       FR_SBUFF_RETURN(cond_print, &our_out, c->data.child);
-                       FR_SBUFF_IN_CHAR_RETURN(&our_out, ')');
-                       break;
-
-               case COND_TYPE_AND:
-                       FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, " && ");
-                       break;
-
-               case COND_TYPE_OR:
-                       FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, " || ");
-                       break;
-
-               case COND_TYPE_TRUE:
-                       FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "true");
-                       break;
-
-               case COND_TYPE_FALSE:
-                       FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "false");
-                       break;
-
-               default:
-                       break;
-               }
-
-               c = c->next;
-       }
-
-       fr_sbuff_terminate(&our_out);
-       FR_SBUFF_SET_RETURN(out, &our_out);
-}
-
-
-static int cond_cast_tmpl(tmpl_t *vpt, fr_type_t type, tmpl_t *other)
-{
-       fr_dict_attr_t const *da;
-
-       fr_assert(type != FR_TYPE_NULL);
-       fr_assert(type < FR_TYPE_TLV);
-
-       if (tmpl_is_attr(vpt)) {
-               (void) tmpl_cast_set(vpt, type);
-               return 0;
-
-       } else if (!tmpl_is_data(vpt) && !tmpl_is_unresolved(vpt)) {
-               /*
-                *      Nothing to do.
-                */
-               return 0;
-
-       } else if (tmpl_value_type(vpt) == type) {
-#if 0
-               /*
-                *      The parser will parse "256" as a 16-bit
-                *      integer.  If that's being compared to an 8-bit
-                *      type, then fr_type_promote() will promote that
-                *      8-bit integer to 16-bits.
-                *
-                *      However... if the 8-bit data type comes from
-                *      an attribute, then we know at compile time
-                *      that the value won't fit.  So we should issue
-                *      a compile-time error.
-                *
-                *      As a result, we call the cast below, even if
-                *      the type of the value matches the type we're
-                *      going to cast.
-                */
-               if (tmpl_is_attr(other)) {
-                       // double check it?
-               }
-#endif
-
-//             (void) tmpl_cast_set(vpt, FR_TYPE_NULL);
-               return 0;
-       }
-
-       /*
-        *      Allow enumerated values like "PPP" for
-        *      Framed-Protocol, which is an integer data type.
-        */
-       if (tmpl_is_attr(other)) {
-               da = tmpl_attr_tail_da(other);
-       } else {
-               da = NULL;
-       }
-
-       fr_strerror_clear();
-
-       if (tmpl_cast_in_place(vpt, type, da) < 0) {
-               return -1;
-       }
-
-       /*
-        *      The result has to be data, AND of the correct type.
-        *      Which means we no longer need the cast.
-        */
-       fr_assert(tmpl_is_data(vpt));
-       fr_assert_msg(fr_type_is_null(tmpl_rules_cast(vpt)) || (tmpl_rules_cast(vpt) == tmpl_value_type(vpt)),
-                     "Cast mismatch, target was %s, but output was %s",
-                     fr_type_to_str(tmpl_rules_cast(vpt)),
-                     fr_type_to_str(tmpl_value_type(vpt)));
-       (void) tmpl_cast_set(vpt, FR_TYPE_NULL);
-       return 0;
-}
-
-
-/** Promote the types in a FOO OP BAR comparison.
- *
- */
-int fr_cond_promote_types(fr_cond_t *c, fr_sbuff_t *in, fr_sbuff_marker_t *m_lhs, fr_sbuff_marker_t *m_rhs, bool simple_parse)
-{
-       fr_type_t lhs_type, rhs_type;
-       fr_type_t cast_type;
-
-#ifdef HAVE_REGEX
-       /*
-        *      Regular expressions have their own casting rules.
-        */
-       if (tmpl_contains_regex(c->data.map->rhs)) {
-               fr_assert((c->data.map->op == T_OP_REG_EQ) || (c->data.map->op == T_OP_REG_NE));
-               fr_assert(fr_type_is_null(tmpl_rules_cast(c->data.map->rhs)));
-
-               /*
-                *      Can't use casts with regular expressions, on
-                *      LHS or RHS.  Instead, the regular expression
-                *      returns a true/false match.
-                *
-                *      It's OK to have a redundant cast to string on
-                *      the LHS.  We also allow a cast to octets, in
-                *      which case we do a binary regex comparison.
-                *
-                *      @todo - ensure that the regex interpreter is
-                *      binary-safe!
-                */
-               cast_type = tmpl_rules_cast(c->data.map->lhs);
-               if (cast_type != FR_TYPE_NULL) {
-                       if ((cast_type != FR_TYPE_STRING) &&
-                           (cast_type != FR_TYPE_OCTETS)) {
-                               fr_strerror_const("Casts cannot be used with regular expressions");
-                               if (in) fr_sbuff_set(in, m_lhs);
-                               return -1;
-                       }
-               } else {
-                       cast_type = FR_TYPE_STRING;
-               }
-
-               /*
-                *      Ensure that the data is cast appropriately.
-                */
-               if (tmpl_is_unresolved(c->data.map->lhs) || tmpl_is_data(c->data.map->lhs)) {
-                       if (tmpl_cast_in_place(c->data.map->lhs, FR_TYPE_STRING, NULL) < 0) {
-                               if (in) fr_sbuff_set(in, m_lhs);
-                               return -1;
-                       }
-
-                       (void) tmpl_cast_set(c->data.map->lhs, FR_TYPE_NULL);
-               }
-
-               /*
-                *      Force a cast to 'string', so the conditional
-                *      evaluator has less work to do.
-                */
-               (void) tmpl_cast_set(c->data.map->lhs, cast_type);
-               return 0;
-       }
-#endif
-
-       /*
-        *      Rewrite the map so that the attribute being evaluated
-        *      is on the LHS.  This exchange makes cond_eval() easier
-        *      to implement, as it doesn't have to check both sides
-        *      for attributes.
-        */
-       if (tmpl_is_attr(c->data.map->rhs) &&
-           !tmpl_contains_attr(c->data.map->lhs)) { /* also unresolved attributes! */
-               tmpl_t *tmp;
-               fr_sbuff_marker_t *m_tmp;
-
-               tmp = c->data.map->rhs;
-               c->data.map->rhs = c->data.map->lhs;
-               c->data.map->lhs = tmp;
-
-               m_tmp = m_rhs;
-               m_rhs = m_lhs;
-               m_lhs = m_tmp;
-
-               switch (c->data.map->op) {
-               case T_OP_CMP_EQ:
-               case T_OP_NE:
-                       /* do nothing */
-                       break;
-
-               case T_OP_LE:
-                       c->data.map->op = T_OP_GE;
-                       break;
-
-               case T_OP_LT:
-                       c->data.map->op = T_OP_GT;
-                       break;
-
-               case T_OP_GE:
-                       c->data.map->op = T_OP_LE;
-                       break;
-
-               case T_OP_GT:
-                       c->data.map->op = T_OP_LT;
-                       break;
-
-               default:
-                       fr_strerror_printf("%s: Internal sanity check failed", __FUNCTION__);
-                       return -1;
-               }
-       }
-
-       /*
-        *      Figure out the type of the LHS.
-        */
-       if (tmpl_rules_cast(c->data.map->lhs) != FR_TYPE_NULL) {
-               lhs_type = tmpl_rules_cast(c->data.map->lhs);
-               /*
-                *      Two explicit casts MUST be the same, otherwise
-                *      it's an error.
-                *
-                *      We only do type promotion when at least one
-                *      data type is implicitly specified.
-                */
-               if (tmpl_rules_cast(c->data.map->rhs) != FR_TYPE_NULL) {
-                       if (tmpl_rules_cast(c->data.map->rhs) != lhs_type) {
-                               fr_strerror_printf("Incompatible casts '%s' and '%s'",
-                                                  fr_type_to_str(tmpl_rules_cast(c->data.map->rhs)),
-                                                  fr_type_to_str(lhs_type));
-                               if (in) fr_sbuff_set(in, fr_sbuff_start(in));
-                               return -1;
-                       }
-
-                       return 0;
-               }
-
-       } else if (tmpl_is_data(c->data.map->lhs)) {
-               /*
-                *      Choose the data type which was parsed.
-                */
-               lhs_type = tmpl_value_type(c->data.map->lhs);
-
-       } else if (tmpl_is_attr(c->data.map->lhs)) {
-               /*
-                *      Choose the attribute type which was parsed.
-                */
-               lhs_type = tmpl_attr_tail_da(c->data.map->lhs)->type;
-
-       } else if (tmpl_is_exec(c->data.map->lhs)) {
-               lhs_type = FR_TYPE_STRING;
-
-       } else if (tmpl_is_xlat(c->data.map->lhs) && (c->data.map->lhs->quote != T_BARE_WORD)) {
-               /*
-                *      bare xlats return a list of typed value-boxes.
-                *      We don't know those types until run-time.
-                */
-               lhs_type = FR_TYPE_STRING;
-
-       } else {
-#ifdef HAVE_REGEX
-               fr_assert(!tmpl_is_regex(c->data.map->lhs));
-#endif
-
-               lhs_type = FR_TYPE_NULL;
-       }
-
-       /*
-        *      Figure out the type of the RHS.
-        */
-       if (tmpl_rules_cast(c->data.map->rhs) != FR_TYPE_NULL) {
-               rhs_type = tmpl_rules_cast(c->data.map->rhs);
-
-       } else if (tmpl_is_data(c->data.map->rhs)) {
-               rhs_type = tmpl_value_type(c->data.map->rhs);
-
-               /*
-                *      If we have ATTR op DATA, then ensure that the
-                *      data type we choose is the one from the
-                *      attribute, because that's what limits the
-                *      range of the RHS data.
-                */
-               if (fr_type_is_numeric(lhs_type) && tmpl_is_attr(c->data.map->lhs)) rhs_type = lhs_type;
-
-       } else if (tmpl_is_attr(c->data.map->rhs)) {
-               rhs_type = tmpl_attr_tail_da(c->data.map->rhs)->type;
-
-       } else if (tmpl_is_exec(c->data.map->rhs)) {
-               rhs_type = FR_TYPE_STRING;
-
-       } else if (tmpl_is_xlat(c->data.map->rhs) && (c->data.map->rhs->quote != T_BARE_WORD)) {
-               /*
-                *      bare xlats return a list of typed value-boxes.
-                *      We don't know those types until run-time.
-                */
-               rhs_type = FR_TYPE_STRING;
-
-       } else {
-               rhs_type = FR_TYPE_NULL;
-
-               /*
-                *      Both sides are have unresolved issues.  Leave
-                *      them alone...
-                */
-               if (fr_type_is_null(lhs_type)) {
-                       /*
-                        *      If we still have unresolved data, then
-                        *      ensure that they are converted to
-                        *      strings.
-                        */
-                       if ((c->pass2_fixup == PASS2_FIXUP_NONE) &&
-                           tmpl_is_unresolved(c->data.map->lhs) && tmpl_is_unresolved(c->data.map->rhs)) {
-                               if (tmpl_cast_in_place(c->data.map->lhs, FR_TYPE_STRING, NULL) < 0) return -1;
-                               if (tmpl_cast_in_place(c->data.map->rhs, FR_TYPE_STRING, NULL) < 0) return -1;
-                       }
-
-                       return 0;
-               }
-       }
-
-       /*
-        *      Both types are identical.  Ensure that LHS / RHS are
-        *      cast as appropriate.
-        */
-       if (lhs_type == rhs_type) {
-               cast_type = lhs_type;
-               goto set_types;
-       }
-
-       /*
-        *      Only one side has a known data type.  Cast the other
-        *      side to it.
-        *
-        *      Note that we don't check the return code for
-        *      tmpl_cast_set().  If one side is an unresolved
-        *      attribute, then the cast will fail.  Which is fine,
-        *      because we will just check it again after the pass2
-        *      fixups.
-        */
-       if (!fr_type_is_null(lhs_type) && fr_type_is_null(rhs_type)) {
-               cast_type = lhs_type;
-               goto set_types;
-       }
-
-       if (!fr_type_is_null(rhs_type) && fr_type_is_null(lhs_type)) {
-               cast_type = rhs_type;
-               goto set_types;
-       }
-
-       cast_type = fr_type_promote(lhs_type, rhs_type);
-       if (!fr_cond_assert_msg(cast_type != FR_TYPE_NULL, "%s", fr_strerror())) return -1;
-
-set_types:
-       /*
-        *      If the caller is doing comparisons with prefixes, then
-        *      update the cast to an IP prefix.  But only if they're
-        *      not comparing IP addresses by value.  <sigh> We should
-        *      really have separate "set membership" operators.
-        */
-       if (((cast_type == FR_TYPE_IPV4_ADDR) || (cast_type == FR_TYPE_IPV6_ADDR)) &&
-           (lhs_type != rhs_type)) {
-               switch (c->data.map->op) {
-               default:
-                       break;
-
-               case T_OP_LT:
-               case T_OP_LE:
-               case T_OP_GT:
-               case T_OP_GE:
-                       if (cast_type == FR_TYPE_IPV4_ADDR) {
-                               cast_type = FR_TYPE_IPV4_PREFIX;
-                       } else {
-                               cast_type = FR_TYPE_IPV6_PREFIX;
-                       }
-                       break;
-               }
-       }
-
-       /*
-        *      Skip casting.
-        */
-       if (simple_parse) return 0;
-
-       /*
-        *      Cast both sides to the promoted type.
-        */
-       if (cond_cast_tmpl(c->data.map->lhs, cast_type, c->data.map->rhs) < 0) {
-               if (in) fr_sbuff_set(in, m_lhs);
-               return -1;
-       }
-
-       if (cond_cast_tmpl(c->data.map->rhs, cast_type, c->data.map->lhs) < 0) {
-               if (in) fr_sbuff_set(in, m_rhs);
-               return -1;
-       }
-
-       return 0;
-}
-
-/** Normalise one level of a condition
- *
- *     This function is called after every individual condition is
- *     tokenized.  As a result, this function does not need to
- *     recurse.  Instead, it just looks at itself, and it's immediate
- *     children for optimizations
- */
-static int cond_normalise(TALLOC_CTX *ctx, fr_token_t lhs_type, fr_cond_t **c_out)
-{
-       fr_cond_t *c = *c_out;
-       fr_cond_t *next;
-
-       /*
-        *      Normalize the condition before returning.
-        *
-        *      We convert maps to literals.  Then literals to
-        *      true/false statements.  Then true/false ||/&& followed
-        *      by other conditions to just conditions.
-        *
-        *      Order is important.  The more complex cases are
-        *      converted to simpler ones, from the most complex cases
-        *      to the simplest ones.
-        */
-
-       /*
-        *      Do some limited normalizations here.
-        */
-       if (c->type == COND_TYPE_CHILD) {
-               fr_cond_t *child = c->data.child;
-
-               /*
-                *      ((FOO)) --> (FOO)
-                *      !(!(FOO)) --> FOO
-                */
-               if (!c->next && !child->next) {
-                       if ((child->type == COND_TYPE_CHILD) ||
-                           (child->type == COND_TYPE_TRUE) ||
-                           (child->type == COND_TYPE_FALSE)) {
-                               (void) talloc_steal(ctx, child);
-                               child->parent = c->parent;
-                               child->negate = (c->negate != child->negate);
-
-                               talloc_free(c);
-                               c = child;
-                       }
-               }
-
-               /*
-                *      No further optimizations are possible, so we
-                *      just check for and/or short-circuit.
-                */
-                goto check_short_circuit;
-       }
-
-       /*
-        *      Normalise the equality checks.
-        *
-        *      This doesn't make a lot of difference, but it does
-        *      help fix !* and =*, which are horrible hacks.
-        */
-       if (c->type == COND_TYPE_MAP) switch (c->data.map->op) {
-               /*
-                *      !FOO !~ BAR --> FOO =~ BAR
-                *
-                *      FOO !~ BAR --> !FOO =~ BAR
-                */
-               case T_OP_REG_NE:
-                       if (c->negate) {
-                               c->negate = false;
-                               c->data.map->op = T_OP_REG_EQ;
-                       } else {
-                               c->negate = true;
-                               c->data.map->op = T_OP_REG_EQ;
-                       }
-                       break;
-
-               /*
-                *      !FOO != BAR --> FOO == BAR
-                *
-                *      This next one catches "LDAP-Group != foo",
-                *      which doesn't work as-is, but this hack fixes
-                *      it.
-                *
-                *      FOO != BAR --> !FOO == BAR
-                */
-               case T_OP_NE:
-                       if (c->negate) {
-                               c->negate = false;
-                               c->data.map->op = T_OP_CMP_EQ;
-                       } else {
-                               c->negate = true;
-                               c->data.map->op = T_OP_CMP_EQ;
-                       }
-                       break;
-
-               /*
-                *      Don't do any other re-writing.
-                */
-               default:
-                       break;
-       }
-
-       /*
-        *      Do compile-time evaluation of literals.  That way it
-        *      does not need to be done at run-time.
-        */
-       if (c->type == COND_TYPE_MAP) {
-               /*
-                *      Both are data (IP address, integer, etc.)
-                *
-                *      We can do the evaluation here, so that it
-                *      doesn't need to be done at run time
-                */
-               if (tmpl_is_data(c->data.map->lhs) &&
-                   tmpl_is_data(c->data.map->rhs)) {
-                       bool rcode;
-
-                       fr_assert(c->next == NULL);
-
-                       rcode = cond_eval(NULL, RLM_MODULE_NOOP, c);
-                       TALLOC_FREE(c->data.map);
-
-                       if (rcode) {
-                               c->type = COND_TYPE_TRUE;
-                       } else {
-                               c->type = COND_TYPE_FALSE;
-                       }
-
-                       c->negate = false;
-                       goto check_true; /* it's no longer a map */
-               }
-
-               c->async_required = tmpl_async_required(c->data.map->lhs) || tmpl_async_required(c->data.map->rhs);
-       }
-
-       /*
-        *      Existence checks.  We short-circuit static strings,
-        *      too.
-        *
-        *      FIXME: the data types should be in the template, too.
-        *      So that we know where a literal came from.
-        *
-        *      "foo" is NOT the same as 'foo' or a bare foo.
-        */
-       if (c->type == COND_TYPE_TMPL) {
-               switch (c->data.vpt->type) {
-               case TMPL_TYPE_XLAT:
-               case TMPL_TYPE_XLAT_UNRESOLVED:
-               case TMPL_TYPE_ATTR:
-               case TMPL_TYPE_ATTR_UNRESOLVED:
-               case TMPL_TYPE_EXEC:
-                       break;
-
-               /*
-                *      'true' and 'false' are special strings
-                *      which mean themselves.
-                *
-                *      For integers, 0 is false, all other
-                *      integers are true.
-                *
-                *      For strings, '' and "" are false.
-                *      'foo' and "foo" are true.
-                *
-                *      The str2tmpl function takes care of
-                *      marking "%{foo}" as TMPL_TYPE_XLAT_UNRESOLVED, so
-                *      the strings here are fixed at compile
-                *      time.
-                *
-                *      `exec` and "%{...}" are left alone.
-                *
-                *      Bare words must be module return
-                *      codes.
-                */
-               case TMPL_TYPE_UNRESOLVED:
-               check_bool:
-                       if (!*c->data.vpt->name) {
-                               c->type = COND_TYPE_FALSE;
-                               TALLOC_FREE(c->data.vpt);
-
-                       } else if ((lhs_type == T_SINGLE_QUOTED_STRING) ||
-                                  (lhs_type == T_DOUBLE_QUOTED_STRING)) {
-                               c->type = COND_TYPE_TRUE;
-                               TALLOC_FREE(c->data.vpt);
-
-                       } else if (lhs_type == T_BARE_WORD) {
-                               int rcode;
-                               bool zeros = true;
-                               char const *q;
-
-                               for (q = c->data.vpt->name;
-                                    *q != '\0';
-                                    q++) {
-                                       if (!isdigit((uint8_t) *q)) {
-                                               break;
-                                       }
-                                       if (*q != '0') zeros = false;
-                               }
-
-                               /*
-                                *      It's all digits, and therefore
-                                *      'false' if zero, and 'true' otherwise.
-                                */
-                               if (!*q) {
-                                       if (zeros) {
-                                               c->type = COND_TYPE_FALSE;
-                                       } else {
-                                               c->type = COND_TYPE_TRUE;
-                                       }
-                                       TALLOC_FREE(c->data.vpt);
-                                       break;
-                               }
-
-                               /*
-                                *      Allow &Foo-Bar where Foo-Bar is an attribute
-                                *      defined by a module.
-                                */
-                               if (c->pass2_fixup == PASS2_FIXUP_ATTR) {
-                                       break;
-                               }
-
-                               rcode = fr_table_value_by_str(allowed_return_codes, c->data.vpt->name, 0);
-                               if (!rcode) {
-                                       fr_strerror_const("Expected a module return code");
-                                       return -1;
-                               }
-                       }
-
-                       /*
-                        *      Else lhs_type==T_INVALID, and this
-                        *      node was made by promoting a child
-                        *      which had already been normalized.
-                        */
-                       break;
-
-               case TMPL_TYPE_DATA:
-                       if (lhs_type != T_BARE_WORD) goto check_bool;
-
-               {
-                       fr_value_box_t res;
-
-                       if (fr_value_box_cast(NULL, &res, FR_TYPE_BOOL, NULL, tmpl_value(c->data.vpt)) < 0) return -1;
-                       c->type = res.vb_bool ? COND_TYPE_TRUE : COND_TYPE_FALSE;
-                       TALLOC_FREE(c->data.vpt);
-               }
-                       break;
-
-               default:
-                       fr_assert_fail("%s: Internal sanity check failed", __FUNCTION__);
-                       return -1;
-               }
-
-               if (c->type == COND_TYPE_TMPL) {
-                       c->async_required = tmpl_async_required(c->data.vpt);
-               }
-       }
-
-       /*
-        *      !TRUE -> FALSE
-        */
-check_true:
-       if (c->type == COND_TYPE_TRUE) {
-               if (c->negate) {
-                       c->negate = false;
-                       c->type = COND_TYPE_FALSE;
-               }
-       }
-
-       /*
-        *      !FALSE -> TRUE
-        */
-       if (c->type == COND_TYPE_FALSE) {
-               if (c->negate) {
-                       c->negate = false;
-                       c->type = COND_TYPE_TRUE;
-               }
-       }
-
-       /*
-        *      We now do short-circuit evaluation of && and ||.
-        */
-
-check_short_circuit:
-       if (!c->next) goto done;
-
-       /*
-        *      true && FOO --> FOO
-        */
-       if ((c->type == COND_TYPE_TRUE) &&
-           (c->next->type == COND_TYPE_AND)) {
-               goto hoist_grandchild;
-       }
-
-       /*
-        *      false && FOO --> false
-        */
-       if ((c->type == COND_TYPE_FALSE) &&
-           (c->next->type == COND_TYPE_AND)) {
-               goto drop_child;
-       }
-
-       /*
-        *      false || FOO --> FOO
-        */
-       if ((c->type == COND_TYPE_FALSE) &&
-            (c->next->type == COND_TYPE_OR)) {
-       hoist_grandchild:
-               next = talloc_steal(ctx, c->next->next);
-               talloc_free(c->next);
-               talloc_free(c);
-               c = next;
-               goto done;      /* we've already called normalise for FOO */
-       }
-
-       /*
-        *      true || FOO --> true
-        */
-       if ((c->type == COND_TYPE_TRUE) &&
-            (c->next->type == COND_TYPE_OR)) {
-
-       drop_child:
-               TALLOC_FREE(c->next);
-               goto done;      /* we don't need to normalise a boolean */
-       }
-
-       /*
-        *      the short-circuit operators don't call normalise, so
-        *      we have to check for that, too.
-        */
-       next = c->next;
-       if (!next->next) goto done;
-
-       /*
-        *      FOO && true --> FOO
-        */
-       if ((next->type == COND_TYPE_AND) &&
-           (next->next->type == COND_TYPE_TRUE)) {
-               goto drop_next_child;
-       }
-
-       /*
-        *      FOO && false --> false
-        */
-       if ((next->type == COND_TYPE_AND) &&
-           (next->next->type == COND_TYPE_FALSE)) {
-               goto hoist_next_grandchild;
-       }
-
-       /*
-        *      FOO || false --> FOO
-        */
-       if ((next->type == COND_TYPE_OR) &&
-            (next->next->type == COND_TYPE_FALSE)) {
-       drop_next_child:
-               TALLOC_FREE(c->next);
-               goto done;
-       }
-
-       /*
-        *      FOO || true --> true
-        */
-       if ((next->type == COND_TYPE_OR) &&
-            (next->next->type == COND_TYPE_TRUE)) {
-       hoist_next_grandchild:
-               next = talloc_steal(ctx, next->next);
-               talloc_free(c->next);
-               c = next;
-       }
-
-done:
-       *c_out = c;
-       return 0;
-}
-
-static CC_HINT(nonnull) int cond_forbid_groups(tmpl_t *vpt, fr_sbuff_t *in, fr_sbuff_marker_t *m_lhs)
-{
-       if (!tmpl_is_attr(vpt) || tmpl_attr_tail_is_unresolved(vpt)) return 0;
-
-       if (tmpl_is_list(vpt)) {
-               fr_strerror_const("Cannot use list references in condition");
-               fr_sbuff_set(in, m_lhs);
-               return -1;
-       }
-
-       switch (tmpl_attr_tail_da(vpt)->type) {
-       case FR_TYPE_LEAF:
-               break;
-
-       default:
-               fr_strerror_const("Nesting types such as groups or TLVs cannot "
-                                 "be used in condition comparisons");
-               fr_sbuff_set(in, m_lhs);
-               return -1;
-       }
-
-       return 0;
-}
-
-static fr_slen_t cond_tokenize_operand(fr_cond_t *c, tmpl_t **out,
-                                      fr_sbuff_marker_t *opd_start, fr_sbuff_t *in,
-                                      tmpl_rules_t const *t_rules, bool simple_parse)
-{
-       fr_sbuff_term_t const           bareword_terminals =
-                                       FR_SBUFF_TERMS(
-                                               L(""),                  /* Hack for EOF */
-                                               L("\t"),
-                                               L("\n"),
-                                               L(" "),
-                                               L("!*"),
-                                               L("!="),
-                                               L("!~"),
-                                               L("&&"),                /* Logical operator */
-                                               L(")"),                 /* Close condition/sub-condition */
-                                               L("+="),
-                                               L("-="),
-                                               L(":="),
-                                               L("<"),
-                                               L("<="),
-                                               L("=*"),
-                                               L("=="),
-                                               L("=~"),
-                                               L(">"),
-                                               L(">="),
-                                               L("||"),                /* Logical operator */
-                                       );
-
-       fr_sbuff_t                      our_in = FR_SBUFF(in);
-       fr_sbuff_marker_t               m;
-       tmpl_t                          *vpt;
-       fr_token_t                      type;
-       fr_type_t                       cast = FR_TYPE_NULL;
-       fr_sbuff_parse_rules_t          tmp_p_rules;
-       fr_sbuff_parse_rules_t const    *p_rules;
-       fr_slen_t                       slen;
-       tmpl_rules_t                    our_t_rules = *t_rules;
-
-       *out = NULL;
-
-       /*
-        *      Parse (optional) cast
-        */
-       if (tmpl_cast_from_substr(&our_t_rules, &our_in) < 0) FR_SBUFF_ERROR_RETURN(&our_in);
-
-       fr_sbuff_adv_past_whitespace(&our_in, SIZE_MAX, NULL);
-       fr_sbuff_marker(&m, &our_in);
-
-       /*
-        *      Check for quoting
-        */
-       fr_sbuff_out_by_longest_prefix(&slen, &type, cond_quote_table, &our_in, T_BARE_WORD);
-       switch (type) {
-       default:
-       case T_BARE_WORD:
-               tmp_p_rules = (fr_sbuff_parse_rules_t){         /* Stack allocated due to CL scope */
-                       .terminals = &bareword_terminals,
-                       .escapes = NULL
-               };
-               p_rules = &tmp_p_rules;
-               break;
-
-       case T_BACK_QUOTED_STRING:
-       case T_DOUBLE_QUOTED_STRING:
-       case T_SINGLE_QUOTED_STRING:
-#ifdef HAVE_REGEX
-       case T_SOLIDUS_QUOTED_STRING:
-#endif
-               p_rules = value_parse_rules_quoted[type];
-               break;
-#ifndef HAVE_REGEX
-       case T_SOLIDUS_QUOTED_STRING:
-               fr_strerror_const("Compiled without support for regexes");
-               fr_sbuff_set(&our_in, &m);
-               fr_sbuff_advance(&our_in, 1);
-               goto error;
-#endif
-       }
-
-       slen = tmpl_afrom_substr(c, &vpt, &our_in, type, p_rules, &our_t_rules);
-       if (slen < 0) {
-       error:
-               talloc_free(vpt);
-               FR_SBUFF_ERROR_RETURN(&our_in);
-       }
-
-       if ((type != T_BARE_WORD) && !fr_sbuff_next_if_char(&our_in, fr_token_quote[type])) { /* Quoting */
-               fr_strerror_const("Unterminated string");
-               fr_sbuff_set(&our_in, &m);
-               goto error;
-       }
-
-#ifdef HAVE_REGEX
-       /*
-        *      Parse the regex flags
-        *
-        *      The quote parsing we performed for the RHS
-        *      earlier means out buffer should be sitting
-        *      at the start of the flags.
-        */
-       if (type == T_SOLIDUS_QUOTED_STRING) {
-               if (cast != FR_TYPE_NULL) {
-                       fr_strerror_const("Casts cannot be used with regular expressions");
-                       fr_sbuff_set(&our_in, &m);
-                       goto error;
-               }
-
-               if (!tmpl_contains_regex(vpt)) {
-                       fr_strerror_const("Expected regex");
-                       fr_sbuff_set(&our_in, &m);
-                       goto error;
-               }
-
-               if (tmpl_regex_flags_substr(vpt, &our_in, &bareword_terminals) < 0) goto error;
-
-               /*
-                *      We've now got the expressions and
-                *      the flags.  Try to compile the
-                *      regex.
-                */
-               if (!simple_parse && tmpl_is_regex_uncompiled(vpt)) {
-                       if (tmpl_regex_compile(vpt, true) < 0) {
-                               fr_sbuff_set(&our_in, &m);      /* Reset to start of expression */
-                               goto error;
-                       }
-               }
-       }
-#endif
-
-       /*
-        *      Sanity check for nested types
-        */
-       if (tmpl_is_attr(vpt) && (tmpl_attr_unknown_add(vpt) < 0)) {
-               fr_strerror_printf("Failed defining attribute %s", tmpl_attr_tail_da(vpt)->name);
-               fr_sbuff_set(&our_in, &m);
-               goto error;
-       }
-
-       if (tmpl_is_unresolved(vpt) &&
-           ((type == T_BACK_QUOTED_STRING) || (type == T_SINGLE_QUOTED_STRING) || (type == T_DOUBLE_QUOTED_STRING))) {
-               if (tmpl_cast_in_place(vpt, FR_TYPE_STRING, NULL) < 0) {
-                       fr_sbuff_set(&our_in, &m);
-                       goto error;
-               }
-       }
-
-       if (tmpl_is_attr_unresolved(vpt)) c->pass2_fixup = PASS2_FIXUP_ATTR;
-
-       *out = vpt;
-
-       fr_sbuff_marker(opd_start, in);
-       fr_sbuff_set(opd_start, &m);
-
-       FR_SBUFF_SET_RETURN(in, &our_in);
-}
-
-/** Tokenize a conditional check
- *
- *  @param[in] ctx     talloc ctx
- *  @param[out] out    pointer to the returned condition structure
- *  @param[in] cs      our configuration section
- *  @param[in] in      the start of the string to process.  Should be "(..."
- *  @param[in] brace   look for a closing brace (how many deep we are)
- *  @param[in] t_rules for attribute parsing
- *  @param[in] simple_parse    temporary hack
- *  @return
- *     - Length of the string skipped.
- *     - < 0 (the offset to the offending error) on error.
- */
-static fr_slen_t cond_tokenize(TALLOC_CTX *ctx, fr_cond_t **out,
-                              CONF_SECTION *cs, fr_sbuff_t *in, int brace,
-                              tmpl_rules_t const *t_rules, bool simple_parse)
-{
-       fr_sbuff_t              our_in = FR_SBUFF(in);
-       ssize_t                 slen;
-       fr_cond_t               *c;
-
-       tmpl_t                  *lhs = NULL;
-       fr_token_t              op;
-       fr_cond_type_t          cond_op;
-
-       fr_sbuff_marker_t       m_lhs, m_lhs_cast, m_op, m_rhs, m_rhs_cast;
-
-       MEM(c = talloc_zero(ctx, fr_cond_t));
-
-       fr_sbuff_adv_past_whitespace(&our_in, SIZE_MAX, NULL);
-       if (!fr_sbuff_extend(&our_in)) {
-               fr_strerror_const("Empty condition is invalid");
-       error:
-               talloc_free(c);
-               FR_SBUFF_ERROR_RETURN(&our_in);
-       }
-
-       /*
-        *      !COND
-        */
-       if (fr_sbuff_next_if_char(&our_in, '!')) {
-               c->negate = true;
-               fr_sbuff_adv_past_whitespace(&our_in, SIZE_MAX, NULL);
-
-               /*
-                *  Just for stupidity
-                */
-               if (fr_sbuff_is_char(&our_in, '!')) {
-                       fr_strerror_const("Double negation is invalid");
-                       goto error;
-               }
-       }
-
-       /*
-        *      (COND)
-        */
-       if (fr_sbuff_next_if_char(&our_in, '(')) {
-               /*
-                *      We've already eaten one layer of
-                *      brackets.  Go recurse to get more.
-                */
-               c->type = COND_TYPE_CHILD;
-
-               /*
-                *      Children are allocated from the parent.
-                */
-               if (cond_tokenize(c, &c->data.child, cs, &our_in, brace + 1, t_rules, simple_parse) < 0) goto error;
-
-               if (!c->data.child) {
-                       fr_strerror_const("Empty condition is invalid");
-                       goto error;
-               }
-
-               fr_sbuff_adv_past_whitespace(&our_in, SIZE_MAX, NULL);
-               goto closing_brace;
-       }
-
-       /*
-        *      We didn't see anything special.  The condition must be one of
-        *
-        *      FOO
-        *      FOO OP BAR
-        */
-
-       /*
-        *      Grab the LHS
-        */
-       fr_sbuff_marker(&m_lhs_cast, &our_in);
-
-       /*
-        *      Check to see if this is an rcode operand.  These are
-        *      common enough and specific enough to conditions that
-        *      we handle them in the condition code specifically.
-        *
-        *      Unary barewords can only be rcodes, so anything that's
-        *      not a rcode an rcode is an error.
-        */
-       {
-               rlm_rcode_t rcode;
-               size_t match_len;
-
-               fr_sbuff_out_by_longest_prefix(&match_len, &rcode, rcode_table, &our_in, RLM_MODULE_NOT_SET);
-               if (rcode != RLM_MODULE_NOT_SET) {
-                       c->type = COND_TYPE_RCODE;
-                       c->data.rcode = rcode;
-
-                       fr_sbuff_adv_past_whitespace(&our_in, SIZE_MAX, NULL);
-                       goto closing_brace;
-               }
-       }
-
-       if (cond_tokenize_operand(c, &lhs, &m_lhs, &our_in, t_rules, simple_parse) < 0) goto error;
-
-#ifdef HAVE_REGEX
-       /*
-        *      LHS can't have regex.  We can't use regex as a unary
-        *      existence check.
-        */
-       if (tmpl_contains_regex(lhs)) {
-               fr_strerror_const("Unexpected regular expression");
-               fr_sbuff_set(&our_in, &m_lhs);
-               goto error;
-       }
-#endif
-
-       /*
-        *      We may (or not) have an operator
-        */
-       fr_sbuff_adv_past_whitespace(&our_in, SIZE_MAX, NULL);
-
-       /*
-        *      What's found directly after the LHS token determines
-        *      what type of expression this is.
-        */
-
-       /*
-        *      Closing curly brace - end of sub-expression
-        */
-       if (fr_sbuff_is_char(&our_in, ')')) {
-               if (fr_sbuff_used_total(&our_in) == 0) {
-                       fr_strerror_const("Empty string is invalid");
-                       goto error;
-               }
-
-               /*
-                *      don't skip the brace.  We'll look for it later.
-                */
-               goto unary;
-
-       } else if (fr_sbuff_is_char(&our_in, '&') || fr_sbuff_is_char(&our_in, '|')) {
-               /*
-                *      FOO && ...
-                *      FOO || ...
-                *
-                *      end of sub-expression.
-                */
-               goto unary;
-
-       } else if (!fr_sbuff_extend(&our_in)) {
-               /*
-                *      FOO - Existence check at EOF
-                */
-               if (brace) {
-                       fr_strerror_const("Missing closing brace");
-                       goto error;
-               }
-
-       unary:
-               if (tmpl_rules_cast(lhs) != FR_TYPE_NULL) {
-                       fr_strerror_const("Cannot do cast for existence check");
-                       fr_sbuff_set(&our_in, &m_lhs_cast);
-                       goto error;
-               }
-
-               c->type = COND_TYPE_TMPL;
-               c->data.vpt = lhs;
-
-               goto closing_brace;
-       }
-
-       /*
-        *      We now have LHS OP RHS.  So the LHS can't be a group,
-        *      list, or nested thing.
-        */
-       if (cond_forbid_groups(lhs, &our_in, &m_lhs) < 0) goto error;
-
-       /*
-        *      Check for any other operator
-        */
-       fr_sbuff_marker(&m_op, &our_in);
-       fr_sbuff_out_by_longest_prefix(&slen, &op, cond_cmp_op_table, &our_in, 0);
-       if (slen == 0) {
-               fr_strerror_const("Invalid operator");
-               goto error;
-       }
-       fr_sbuff_adv_past_whitespace(&our_in, SIZE_MAX, NULL);
-
-       {
-               map_t   *map;
-               tmpl_t  *rhs;
-
-               /*
-                *      The next thing should now be a comparison operator.
-                */
-               c->type = COND_TYPE_MAP;
-
-               switch (op) {
-               case T_OP_CMP_FALSE:
-               case T_OP_CMP_TRUE:
-                       fr_strerror_printf("Invalid operator %s",
-                                          fr_table_str_by_value(cond_cmp_op_table, op, "<INVALID>"));
-                       fr_sbuff_set(&our_in, &m_op);
-                       goto error;
-
-               default:
-                       break;
-               }
-
-               if (!fr_sbuff_extend(&our_in)) {
-                       fr_strerror_const("Expected text after operator");
-                       goto error;
-               }
-
-               MEM(c->data.map = map = talloc_zero(c, map_t));
-
-               /*
-                *      Grab the RHS
-                */
-               fr_sbuff_marker(&m_rhs_cast, &our_in);
-               if (cond_tokenize_operand(c, &rhs, &m_rhs, &our_in, t_rules, simple_parse) < 0) goto error;
-
-               /*
-                *      Groups can't be on the RHS of a comparison, either
-                */
-               if (cond_forbid_groups(rhs, &our_in, &m_rhs) < 0) goto error;
-
-               *map = (map_t) {
-                       .ci = cf_section_to_item(cs),
-                       .lhs = lhs,
-                       .op = op,
-                       .rhs = rhs
-               };
-
-#ifdef HAVE_REGEX
-               /*
-                *      LHS can't have regex.  We can't use regex as a unary
-                *      existence check.
-                */
-               if (tmpl_contains_regex(rhs) &&
-                   !((op == T_OP_REG_EQ) || (op == T_OP_REG_NE))) {
-                       fr_strerror_const("Unexpected regular expression");
-                       fr_sbuff_set(&our_in, &m_rhs);
-                       goto error;
-               }
-
-               /*
-                *      =~ and !~ MUST have regular expression on the
-                *      RHS.
-                */
-               if ((op == T_OP_REG_EQ) || (op == T_OP_REG_NE)) {
-                       if (!tmpl_contains_regex(rhs)) {
-                               fr_strerror_const("Expected regular expression");
-                               fr_sbuff_set(&our_in, &m_rhs);
-                               goto error;
-                       }
-               }
-#endif
-
-               fr_sbuff_adv_past_whitespace(&our_in, SIZE_MAX, NULL);
-
-               /*
-                *      Promote the data types to the appropriate
-                *      values.
-                */
-               if (fr_cond_promote_types(c, &our_in, &m_lhs, &m_rhs, simple_parse) < 0) {
-                       goto error;
-               }
-       } /* parse OP RHS */
-
-closing_brace:
-
-       /*
-        *      Recurse to parse the next condition.
-        */
-
-       /*
-        *      ...COND)
-        */
-       if (fr_sbuff_is_char(&our_in, ')')) {
-               if (!brace) {
-                       fr_strerror_const("Unexpected closing brace");
-                       goto error;
-               }
-               fr_sbuff_advance(&our_in, 1);
-               fr_sbuff_adv_past_whitespace(&our_in, SIZE_MAX, NULL);
-               goto done;
-       }
-
-       /*
-        *      End of string is allowed, unless we're still looking
-        *      for closing braces.
-        */
-       if (!fr_sbuff_extend(&our_in)) {
-               if (brace) {
-                       fr_strerror_const("Missing closing brace");
-                       goto error;
-               }
-               goto done;
-       }
-
-       /*
-        *      We've parsed all of the condition, stop.
-        */
-       if (brace == 0) {
-               if (fr_sbuff_is_space(&our_in)) goto done;
-
-               /*
-                *      Open a section, it's OK to be done.
-                */
-               if (fr_sbuff_is_char(&our_in, '{')) goto done;
-       }
-
-       fr_sbuff_out_by_longest_prefix(&slen, &cond_op, cond_logical_op_table,
-                                      &our_in, COND_TYPE_INVALID);
-       if (slen == 0) {
-               /*
-                *      Peek ahead to give slightly better error messages.
-                */
-               if (fr_sbuff_is_char(&our_in, '=')) {
-                       fr_strerror_const("Invalid location for operator");
-
-               } else if (fr_sbuff_is_char(&our_in, '!')) {
-                       fr_strerror_const("Invalid location for negation");
-
-               } else {
-                       fr_strerror_const("Expected closing brace or logical operator");
-               }
-               goto error;
-       }
-
-       /*
-        *      We have a short-circuit condition, create it.
-        */
-       if (cond_op != COND_TYPE_INVALID) {
-               fr_cond_t *child;
-
-               /*
-                *      This node is talloc parented by the previous
-                *      condition.
-                */
-               MEM(child = talloc_zero(c, fr_cond_t));
-               child->type = cond_op;
-
-               /*
-                *      siblings are allocated from their older
-                *      siblings.
-                */
-               if (cond_tokenize(child, &child->next, cs, &our_in, brace, t_rules, simple_parse) < 0) goto error;
-               c->next = child;
-               goto done;
-       }
-
-       /*
-        *      May still be looking for a closing brace.
-        *
-        *      siblings are allocated from their older
-        *      siblings.
-        */
-       if (cond_tokenize(c, &c->next, cs, &our_in, brace, t_rules, simple_parse) < 0) goto error;
-
-done:
-       if (cond_normalise(ctx, lhs ? lhs->quote : T_INVALID, &c) < 0) {
-               talloc_free(c);
-               fr_sbuff_set_to_start(&our_in);
-               FR_SBUFF_ERROR_RETURN(&our_in);
-       }
-
-       *out = c;
-
-       FR_SBUFF_SET_RETURN(in, &our_in);
-}
-
-/*
- *     Normalisation will restructure the conditional tree, including
- *     removing and/or rearranging the parents.  So we reparent
- *     everything after the full normalization has run.
- */
-static void cond_reparent(fr_cond_t *c, fr_cond_t *parent)
-{
-       while (c) {
-               c->parent = parent;
-
-               if (c->type == COND_TYPE_CHILD) cond_reparent(c->data.child, c);
-
-               if (parent) parent->async_required |= c->async_required;
-
-               c = c->next;
-       }
-}
-
-/** Tokenize a conditional check
- *
- * @param[in] cs       current CONF_SECTION and talloc ctx
- * @param[out] head    the parsed condition structure
- * @param[in] rules    for parsing operands.
- * @param[in] in       the start of the string to process.
- * @param[in] simple_parse     temporary hack
- * @return
- *     - Length of the string skipped.
- *     - < 0 (the offset to the offending error) on error.
- */
-ssize_t fr_cond_tokenize(CONF_SECTION *cs, fr_cond_t **head, tmpl_rules_t const *rules, fr_sbuff_t *in, bool simple_parse)
-{
-       ssize_t slen;
-       fr_sbuff_t our_in = FR_SBUFF(in);
-
-       *head = NULL;
-
-       slen = cond_tokenize(cs, head, cs, &our_in, 0, rules, simple_parse);
-       if (slen <= 0) return slen;
-
-       /*
-        *      Now that everything has been normalized, reparent the children.
-        */
-       if (*head) {
-               fr_cond_t *c = *head;
-
-               /*
-                *      (FOO) -> FOO
-                *      !(!(FOO)) -> FOO
-                */
-               if ((c->type == COND_TYPE_CHILD) && !c->next) {
-                       if (!c->negate || !c->data.child->next) {
-                               fr_cond_t *child = c->data.child;
-                               (void) talloc_steal(cs, child);
-                               child->parent = c->parent;
-                               child->negate = (c->negate != child->negate);
-
-                               talloc_free(c);
-                               *head = child;
-                       }
-               }
-
-               cond_reparent(*head, NULL);
-       }
-
-       FR_SBUFF_SET_RETURN(in, &our_in);
-}
-
-/** Initialise a cond iterator
- *
- * Will return the first leaf condition node.
- *
- * @param[out] iter    to initialise.
- * @param[in] head     the root of the condition structure.
- * @return The first leaf condition node.
- */
-fr_cond_t *fr_cond_iter_init(fr_cond_iter_t *iter, fr_cond_t *head)
-{
-       fr_cond_t *c;
-
-       for (c = head; c->type == COND_TYPE_CHILD; c = c->data.child);  /* Deepest condition */
-
-       return iter->cond = c;
-}
-
-/** Get the next leaf condition node
- *
- * @param[in] iter     to iterate over.
- * @return The next leaf condition node.
- */
-fr_cond_t *fr_cond_iter_next(fr_cond_iter_t *iter)
-{
-       fr_cond_t *c;
-
-       /*
-        *      Walk up the tree, maybe...
-        */
-       for (c = iter->cond; c; c = c->parent) {
-               if (!c->next) continue; /* Done with this level */
-               for (c = c->next; c->type == COND_TYPE_CHILD; c = c->data.child);       /* down we go... */
-               break;
-       }
-
-       return iter->cond = c;
-}
-
-/** Update the condition with "is async required".
- *
- *  This is done only by the compiler, in pass2, after is has resolved
- *  all of the various TMPLs.  Note that we MUST walk over the entire
- *  condition, as tmpl_async_required() returns "true" for unresolved
- *  TMPLs.  Which means that if the TMPL is resolved to a synchronous
- *  one, then the flag will be set.  So we have to clear the flag, and
- *  then set it again ourselves.
- */
-void fr_cond_async_update(fr_cond_t *c)
-{
-       while (c) {
-               c->async_required = false;
-
-               switch (c->type) {
-               case COND_TYPE_INVALID:
-               case COND_TYPE_RCODE:
-               case COND_TYPE_AND:
-               case COND_TYPE_OR:
-               case COND_TYPE_TRUE:
-               case COND_TYPE_FALSE:
-                       break;
-
-               case COND_TYPE_TMPL:
-                       c->async_required = tmpl_async_required(c->data.vpt);
-                       break;
-
-               case COND_TYPE_MAP:
-                       c->async_required = tmpl_async_required(c->data.map->lhs) || tmpl_async_required(c->data.map->rhs);
-                       break;
-
-               case COND_TYPE_CHILD:
-                       c = c->data.child;
-                       continue;
-
-               }
-
-               /*
-                *      Mark up the parent, too.  If any of the
-                *      children are async, then the parent is async,
-                *      too.
-                */
-               if (c->parent) c->parent->async_required |= c->async_required;
-
-               /*
-                *      Go up if there's no sibling, or to the next
-                *      sibling if it exists.
-                */
-               while (!c->next) {
-                       c = c->parent;
-                       if (!c) return;
-               }
-               c = c->next;
-       }
-}
index 19b418ba10087e3737ffaf1f53c0ec5f847bc819..8ddc32eae3cc8e86c7447b4431c2b3c57fd25fad 100644 (file)
@@ -28,7 +28,6 @@ typedef struct fr_connection_s fr_connection_t;
 #define _CONNECTION_PRIVATE 1
 #include <freeradius-devel/server/connection.h>
 
-#include <freeradius-devel/server/cond_eval.h>
 #include <freeradius-devel/server/log.h>
 #include <freeradius-devel/server/trigger.h>
 
index 0e948d46eb2cccce47adfdee86a3bc0d54127d85..474275033ca10f825f4f2664ee9dc73383392bbd 100644 (file)
@@ -8,8 +8,6 @@ SOURCES := \
        cf_util.c \
        client.c \
        command.c \
-       cond_eval.c \
-       cond_tokenize.c \
        connection.c \
        dependency.c \
        dl_module.c \
@@ -67,7 +65,7 @@ LOG_ID_LIB    := 1
 
 # different pieces of this library
 $(call DEFINE_LOG_ID_SECTION,config,   1,cf_file.c cf_parse.c cf_util.c)
-$(call DEFINE_LOG_ID_SECTION,conditions,2,conf_eval.c cond_tokenize.c)
+# 2 was the old conditions
 $(call DEFINE_LOG_ID_SECTION,exec,     3,exec.c exec_legacy.c)
 $(call DEFINE_LOG_ID_SECTION,modules,  4,dl_module.c module.c module_rlm.c method.c)
 $(call DEFINE_LOG_ID_SECTION,map,      5,map.c map_proc.c map_async.c)
index 77bc604301ae7badcc34d0d3d5470fbe5a8d081b..c0961e73f46b841b9e89b25714e82a2869cba715 100644 (file)
@@ -29,7 +29,6 @@ RCSID("$Id$")
 #include <freeradius-devel/server/cf_file.h>
 #include <freeradius-devel/server/cf_util.h>
 #include <freeradius-devel/server/client.h>
-#include <freeradius-devel/server/cond.h>
 #include <freeradius-devel/server/dependency.h>
 #include <freeradius-devel/server/main_config.h>
 #include <freeradius-devel/server/map_proc.h>
index dd05cc21d960924efad73409ffb0e03f0d286ae9..e741274a58e75dc7a06a4c324a6253fc8975bc70 100644 (file)
@@ -28,7 +28,6 @@
 
 RCSID("$Id$")
 
-#include <freeradius-devel/server/cond.h>
 #include <freeradius-devel/server/exec.h>
 #include <freeradius-devel/server/exec_legacy.h>
 #include <freeradius-devel/server/map.h>
@@ -46,6 +45,15 @@ RCSID("$Id$")
 
 #include <ctype.h>
 
+static fr_table_num_sorted_t const cond_quote_table[] = {
+       { L("\""),      T_DOUBLE_QUOTED_STRING  },      /* Don't re-order, backslash throws off ordering */
+       { L("'"),       T_SINGLE_QUOTED_STRING  },
+       { L("/"),       T_SOLIDUS_QUOTED_STRING },
+       { L("`"),       T_BACK_QUOTED_STRING    }
+};
+static size_t cond_quote_table_len = NUM_ELEMENTS(cond_quote_table);
+
+
 #ifdef DEBUG_MAP
 static void map_dump(request_t *request, map_t const *map)
 {
index 341e33cc4c10bc1d3a89544cf8063a468c3dc97b..47079acd7aa2ccf190aef2acfc2666ccb8891c6d 100644 (file)
@@ -30,7 +30,6 @@ RCSID("$Id$")
 
 #include <freeradius-devel/server/base.h>
 #include <freeradius-devel/server/cf_file.h>
-#include <freeradius-devel/server/cond.h>
 #include <freeradius-devel/server/modpriv.h>
 #include <freeradius-devel/server/module_rlm.h>
 #include <freeradius-devel/server/radmin.h>
index 875d53d7f3be639f99e327d1140d44dcad4ad390..f2b1f8f5896bf6f6d991be81dd972a888114e2b0 100644 (file)
@@ -30,7 +30,6 @@ RCSID("$Id$")
 #include <freeradius-devel/protocol/freeradius/freeradius.internal.h>
 #include <freeradius-devel/server/base.h>
 #include <freeradius-devel/server/command.h>
-#include <freeradius-devel/server/cond.h>
 #include <freeradius-devel/server/dl_module.h>
 #include <freeradius-devel/server/global_lib.h>
 #include <freeradius-devel/server/modpriv.h>
index 6922d302391f41acd7b6962447a078369973ec9c..7c4b1fa8322d121167f744d0e3be3b0067c09937 100644 (file)
@@ -3452,7 +3452,7 @@ static unlang_t *compile_if(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF
                .len = sizeof(unlang_cond_t),
                .type_name = "unlang_cond_t",
                .pool_headers = 1 + 1 + (TMPL_POOL_DEF_HEADERS * 2),
-               .pool_len = sizeof(fr_cond_t) + sizeof(map_t) + (TMPL_POOL_DEF_LEN * 2)
+               .pool_len = sizeof(map_t) + (TMPL_POOL_DEF_LEN * 2)
        };
 
        return compile_if_subsection(parent, unlang_ctx, cs, &if_ext);
@@ -3465,7 +3465,7 @@ static unlang_t *compile_elsif(unlang_t *parent, unlang_compile_t *unlang_ctx, C
                .len = sizeof(unlang_cond_t),
                .type_name = "unlang_cond_t",
                .pool_headers = 1 + 1 + (TMPL_POOL_DEF_HEADERS * 2),
-               .pool_len = sizeof(fr_cond_t) + sizeof(map_t) + (TMPL_POOL_DEF_LEN * 2)
+               .pool_len = sizeof(map_t) + (TMPL_POOL_DEF_LEN * 2)
        };
 
        return compile_if_subsection(parent, unlang_ctx, cs, &elsif_ext);
index 721bae353187dda9736af96f5f1aa65c600431a6..0f75ed8522882a6ae7a53ea6d00f892c38941624 100644 (file)
@@ -26,7 +26,6 @@
 
 RCSID("$Id$")
 
-#include <freeradius-devel/server/cond.h>
 #include <freeradius-devel/server/modpriv.h>
 #include <freeradius-devel/server/request_data.h>
 #include <freeradius-devel/server/rcode.h>
index d4c2f4727c6973d43892aee05abf1cf3aae7a401..61a8ea98a5efcfe7eebbba2983cb72d0afc23f3f 100644 (file)
@@ -26,7 +26,6 @@
  * @copyright 2016-2019 The FreeRADIUS server project
  */
 #include <freeradius-devel/server/cf_util.h> /* Need CONF_* definitions */
-#include <freeradius-devel/server/cond_eval.h>
 #include <freeradius-devel/server/map_proc.h>
 #include <freeradius-devel/server/modpriv.h>
 #include <freeradius-devel/util/debug.h>
index a41f4e8e929eddb23071b5b8affe576b740c2bdf..f12f9189d262aae4b0248d6746bfcc104e9bacaa 100644 (file)
@@ -649,7 +649,7 @@ match &reply.
 #  and empty strings
 #
 #  @todo - disabled due to moving cf_expand_variables() from
-#  cond_tokenize() to cf_file.c.  The new xlat expression parser
+#  the condition parser to cf_file.c.  The new xlat expression parser
 #  will *not* optimize this at parse time, but *will* optimize
 #  this at purification time.
 #