]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
added cond_realize_tmpl()
authorAlan T. DeKok <aland@freeradius.org>
Mon, 11 Jan 2021 03:38:22 +0000 (22:38 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Mon, 11 Jan 2021 03:53:22 +0000 (22:53 -0500)
which does a bit more than the previous code in order to
realize a tmpl

commented out for now, but all of the tests pass

src/lib/server/cond_eval.c

index df432a2a03c586b61c59a3ae05ff3938073923db..8b95d0b0899235d4d0946c6e5c975599253600d3 100644 (file)
@@ -393,6 +393,126 @@ done:
        return p - out;
 }
 
+//#undef WITH_REALIZE_TMPL
+#define WITH_REALIZE_TMPL
+
+#ifdef WITH_REALIZE_TMPL
+/** Turn a raw #tmpl_t into #fr_value_data_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          *box;
+       xlat_escape_legacy_t    escape = NULL;
+
+       *out = *to_free = NULL;
+
+       switch (in->type) {
+       /*
+        *      These are handled elsewhere.
+        */
+       case TMPL_TYPE_LIST:
+#ifdef HAVE_REGEX
+       case TMPL_TYPE_REGEX:
+#endif
+               return 0;
+
+       case TMPL_TYPE_ATTR:
+               /*
+                *      fast path?  If there's only one attribute, AND
+                *      tmpl_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?
+                */
+               return 0;
+
+       /*
+        *      Return the raw data, which MUST already have been
+        *      converted to the correct thing.
+        */
+       case TMPL_TYPE_DATA:
+               fr_assert((in->cast == FR_TYPE_INVALID) || (in->cast == tmpl_value_type(in)));
+               *out = tmpl_value(in);
+               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;
+
+               box = NULL;
+               ret = tmpl_aexpand(request, &box, request, in, escape, NULL);
+               if (ret < 0) return ret;
+
+               fr_assert(box != 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 (in->cast != FR_TYPE_INVALID) {
+                       cast_type = in->cast;
+
+               } else if (other->cast) {
+                       cast_type = other->cast;
+
+               } else if (tmpl_is_attr(other)) {
+                       da = tmpl_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 (cast_type != box->type) {
+                       if (fr_value_box_cast_in_place(box, box, cast_type, da) < 0) {
+                               return -1;
+                       }
+               }
+
+               *out = *to_free = box;
+               return 0;
+       }
+
+       default:
+               break;
+       }
+
+       /*
+        *      Other tmpl type, return an error.
+        */
+       fr_assert(0);
+       return -1;
+}
+#endif /* WITH_REALIZE_TMP */
+
+
 /** Convert both operands to the same type
  *
  * If casting is successful, we call cond_cmp_values to do the comparison
@@ -611,9 +731,13 @@ finish:
 int cond_eval_map(request_t *request, UNUSED int depth, fr_cond_t const *c)
 {
        int rcode = 0;
-
        map_t const *map = c->data.map;
 
+#ifdef WITH_REALIZE_TMPL
+       fr_value_box_t *lhs, *lhs_free;
+       fr_value_box_t *rhs, *rhs_free;
+#endif
+
 #ifndef NDEBUG
        /*
         *      At this point, all tmpls MUST have been resolved.
@@ -628,6 +752,56 @@ int cond_eval_map(request_t *request, UNUSED int depth, fr_cond_t const *c)
 
        MAP_VERIFY(map);
 
+#ifdef WITH_REALIZE_TMPL
+       /*
+        *      Realize the LHS of a condition.
+        */
+       if (cond_realize_tmpl(request, &lhs, &lhs_free, map->lhs, map->rhs) < 0) {
+               fr_strerror_const("Failed evaluating left side of condition");
+               return -1;
+       }
+
+       /*
+        *      Realize the RHS of a condition.
+        */
+       if (cond_realize_tmpl(request, &rhs, &rhs_free, map->rhs, map->lhs) < 0) {
+               fr_strerror_const("Failed evaluating right side of condition");
+               return -1;
+       }
+
+       /*
+        *      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) {
+               if (map->op != T_OP_REG_EQ) {
+                       fr_assert(map->op != T_OP_REG_NE); /* must be ! ... =~ ... */
+                       rcode = fr_value_box_cmp_op(map->op, lhs, rhs);
+               } else {
+                       rcode = cond_do_regex(request, c, lhs, rhs);
+               }
+
+               talloc_free(lhs_free);
+               talloc_free(rhs_free);
+               return rcode;
+       }
+
+       /*
+        *      @todo - check for LHS list / attr, and loop over it,
+        *      calling the appropriate function.  We have "realized"
+        *      the LHS for all other tmpl types.
+        *
+        *      Inside of the loop, we check for RHS list / attr /
+        *      data / regex, and call the appropriate comparison
+        *      function.
+        */
+
+       talloc_free(lhs_free);
+       talloc_free(rhs_free);
+#endif /* WITH_REALIZE_TMPL */
+
        switch (map->lhs->type) {
        /*
         *      LHS is an attribute or list