]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
add custom resolve callback handler
authorAlan T. DeKok <aland@freeradius.org>
Sat, 21 May 2022 14:20:03 +0000 (10:20 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Sat, 21 May 2022 14:28:43 +0000 (10:28 -0400)
src/lib/unlang/xlat_expr.c
src/lib/unlang/xlat_priv.h
src/lib/unlang/xlat_tokenize.c
src/tests/unit/xlat/purify.txt

index f7ac21b2c4dcceaf91e4bcc8c28f0361fab869b8..12911b81d20b74ae43520198bed8cee619077f49 100644 (file)
@@ -101,6 +101,72 @@ static fr_slen_t xlat_expr_print_binary(fr_sbuff_t *out, xlat_exp_t const *node,
        return fr_sbuff_used_total(out) - at_in;
 }
 
+static int xlat_expr_resolve_binary(xlat_exp_t *self, UNUSED void *inst, xlat_res_rules_t const *xr_rules)
+{
+       xlat_exp_t *arg1, *arg2;
+       xlat_exp_t *a, *b;
+       tmpl_res_rules_t        my_tr_rules;
+
+       arg1 = xlat_exp_head(self->call.args);
+       fr_assert(arg1);
+       fr_assert(arg1->type == XLAT_GROUP);
+
+       arg2 = xlat_exp_next(self->call.args, arg1);
+       fr_assert(arg2);
+       fr_assert(arg2->type == XLAT_GROUP);
+
+       a = xlat_exp_head(arg1->group);
+       b = xlat_exp_head(arg2->group);
+
+       /*
+        *      We have many things here, just call resolve recursively.
+        */
+       if (xlat_exp_next(arg1->group, a) || (xlat_exp_next(arg2->group, b))) {
+               return xlat_resolve(self->call.args, xr_rules);
+       }
+
+       /*
+        *      Anything else must get resolved at run time.
+        */
+       if ((a->type != XLAT_TMPL) || (b->type != XLAT_TMPL)) {
+               return xlat_resolve(self->call.args, xr_rules);
+       }
+
+       /*
+        *      The tr_rules should always contain dict_def
+        */
+       fr_assert(xr_rules); /* always set by xlat_resolve() */
+       if (xr_rules->tr_rules) {
+               my_tr_rules = *xr_rules->tr_rules;
+       } else {
+               my_tr_rules = (tmpl_res_rules_t) { };
+       }
+
+       /*
+        *      The LHS attribute dictates the enumv for the RHS one.
+        */
+       if (tmpl_contains_attr(a->vpt)) {
+               if (tmpl_resolve(a->vpt, &my_tr_rules) < 0) return -1;
+
+               my_tr_rules.enumv = tmpl_da(a->vpt);
+
+               return tmpl_resolve(b->vpt, &my_tr_rules);
+       }
+
+       if (tmpl_contains_attr(b->vpt)) {
+               if (tmpl_resolve(b->vpt, &my_tr_rules) < 0) return -1;
+
+               my_tr_rules.enumv = tmpl_da(b->vpt);
+
+               return tmpl_resolve(a->vpt, &my_tr_rules);
+       }
+
+       if (tmpl_resolve(a->vpt, xr_rules->tr_rules) < 0) return -1;
+
+       return tmpl_resolve(b->vpt, xr_rules->tr_rules);
+}
+
+
 static void xlat_func_append_arg(xlat_exp_t *head, xlat_exp_t *node)
 {
        xlat_exp_t *group;
@@ -484,6 +550,7 @@ do { \
        xlat_func_args(xlat, binary_op_xlat_args); \
        xlat_internal(xlat); \
        xlat_print_set(xlat, xlat_expr_print_binary); \
+       xlat_resolve_set(xlat, xlat_expr_resolve_binary); \
        xlat->token = _op; \
 } while (0)
 
index 8ace3051d6829cf76fc89933f41b51360392de50..356e9c371dea1960c0a19fef1853efcfa2485961 100644 (file)
@@ -39,6 +39,7 @@ extern "C" {
 #endif
 
 typedef fr_slen_t (*xlat_print_t)(fr_sbuff_t *in, xlat_exp_t const *self, void *inst, fr_sbuff_escape_rules_t const *e_rules);
+typedef int (*xlat_resolve_t)(xlat_exp_t *self, void *inst, xlat_res_rules_t const *xr_rules);
 
 typedef struct xlat_s {
        fr_rb_node_t            node;                   //!< Entry in the xlat function tree.
@@ -65,6 +66,7 @@ typedef struct xlat_s {
        void                    *thread_uctx;           //!< uctx to pass to instantiation functions.
 
        xlat_print_t            print;                  //!< function to call when printing
+       xlat_resolve_t          resolve;                //!< function to call when resolving
 
        xlat_flags_t            flags;                  //!< various flags
 
@@ -261,7 +263,7 @@ static inline void xlat_internal(xlat_t *xlat)
 
 /** Set a print routine for an xlat function.
  *
- * @param[in] xlat to mark as internal.
+ * @param[in] xlat to set
  */
 static inline void xlat_print_set(xlat_t *xlat, xlat_print_t func)
 {
@@ -269,6 +271,16 @@ static inline void xlat_print_set(xlat_t *xlat, xlat_print_t func)
 }
 
 
+/** Set a resolve routine for an xlat function.
+ *
+ * @param[in] xlat to set
+ */
+static inline void xlat_resolve_set(xlat_t *xlat, xlat_resolve_t func)
+{
+       xlat->resolve = func;
+}
+
+
 /** Walker callback for xlat_walk()
  *
  * @param[in] exp      being evaluated.
index 18f3e0a772df214b6bcf23862949d3cfc7932b10..52839155065bc973f086332be3b76972452a271f 100644 (file)
@@ -1656,7 +1656,13 @@ int xlat_resolve(xlat_exp_head_t *head, xlat_res_rules_t const *xr_rules)
                 *      A resolved function with unresolved args
                 */
                case XLAT_FUNC:
-                       if (xlat_resolve(node->call.args, xr_rules) < 0) return -1;
+                       if (node->call.func->resolve) {
+                               void *inst = node->call.inst ? node->call.inst->data : NULL;
+
+                               if (node->call.func->resolve(node, inst, xr_rules) < 0) return -1;
+                       } else {
+                               if (xlat_resolve(node->call.args, xr_rules) < 0) return -1;
+                       }
                        node->flags = node->call.func->flags;
                        xlat_flags_merge(&node->flags, &node->call.args->flags);
 
index 27e34b1fdf0f11cb86e1efd2d3dca78f42db9618..e758eba8dfc9d426829dcb9c5bbcd7f5e0c91a29 100644 (file)
@@ -48,8 +48,7 @@ match yes
 #  * the tokenizer needs to track offsets, so it can return the offset which cause the error.
 #
 xlat_purify &Service-Type == Framed-User
-#match (%{Service-Type} == Framed-User)
-match ERROR offset 1: Invalid attribute reference, missing '&' prefix: Failed resolving attribute in expansion: Framed-User
+match (%{Service-Type} == Framed-User)
 
 #xlat_purify 1 + (&Service-Type == Framed-User)
 #match (1 + (%{Service-Type} == Framed-User))
@@ -132,5 +131,20 @@ match yes
 xlat_purify 1 < 2 < 3
 match yes
 
+xlat_purify &Service-Type == 1
+match (%{Service-Type} == 1)
+
+#
+#  Convert the RHS to a simpler version
+#
+xlat_purify &Service-Type == (1 + 2)
+match (%{Service-Type} == 3)
+
+#
+#  This is so wrong...
+#
+xlat_purify &Reply-Message == "foo"
+match ERROR offset 1: Failed resolving attribute in expansion: Message
+
 count
-match 51
+match 57