]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
parse &attr[%{&foo - 1}]
authorAlan T. DeKok <aland@freeradius.org>
Sun, 1 Sep 2024 13:41:16 +0000 (09:41 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Sun, 1 Sep 2024 13:41:16 +0000 (09:41 -0400)
and ensure that things we parse but don't (yet) support are run-time
errors.

src/lib/server/tmpl.h
src/lib/server/tmpl_dcursor.c
src/lib/server/tmpl_tokenize.c

index 8531d582e06abc85e6a4e278d89dc93e916c3c36..4dae92676a0b90bdfa791db2dc4d8c0b582f7067 100644 (file)
@@ -414,6 +414,7 @@ typedef enum {
        TMPL_ATTR_FILTER_TYPE_INDEX,                    //!< Filter is an index type.
        TMPL_ATTR_FILTER_TYPE_CONDITION,                //!< Filter is a condition
        TMPL_ATTR_FILTER_TYPE_TMPL,                     //!< Filter is a tmpl
+       TMPL_ATTR_FILTER_TYPE_EXPR,                     //!< Filter is an expression
 } tmpl_attr_filter_type_t;
 
 typedef struct {
@@ -428,6 +429,7 @@ typedef struct {
        union {
                xlat_exp_head_t         _CONST *cond;           //!< xlat condition
                tmpl_t                  _CONST *tmpl;           //!< tmpl
+               xlat_exp_head_t         _CONST *expr;           //!< xlat expression
        };
 } tmpl_attr_filter_t;
 
@@ -518,12 +520,14 @@ FR_DLIST_FUNCS(tmpl_request_list, tmpl_request_t, entry)
 #define ar_num                         filter.num
 #define ar_cond                                filter.cond
 #define ar_tmpl                                filter.tmpl
+#define ar_expr                                filter.expr
 #define ar_filter_type                 filter.type
 
 #define ar_filter_is_none(_ar)         ((_ar)->ar_filter_type == TMPL_ATTR_FILTER_TYPE_NONE)
 #define ar_filter_is_num(_ar)          ((_ar)->ar_filter_type == TMPL_ATTR_FILTER_TYPE_INDEX)
 #define ar_filter_is_cond(_ar)         ((_ar)->ar_filter_type == TMPL_ATTR_FILTER_TYPE_CONDITION)
 #define ar_filter_is_tmpl(_ar)         ((_ar)->ar_filter_type == TMPL_ATTR_FILTER_TYPE_TMPL)
+#define ar_filter_is_expr(_ar)         ((_ar)->ar_filter_type == TMPL_ATTR_FILTER_TYPE_EXPR)
 /** @} */
 
 /** A source or sink of value data.
index b67f5261f39728e3109850800dc13a5ee79b8499..18f1d13d7a1629c94a1b286a599276c2da47f1d5 100644 (file)
@@ -174,8 +174,16 @@ fr_pair_t *_tmpl_cursor_eval(fr_pair_t *curr, tmpl_dcursor_ctx_t *cc)
         */
        if (ar_filter_is_none(ar)) {
                num = 0;
+
+       } else if (!ar_filter_is_num(ar)) {
+               request_t *request = cc->request;
+
+               RDEBUG("Attribute filter is unsupported");
+               vp = NULL;
+               pop = true;
+               goto done;
+
        } else {
-               fr_assert(ar_filter_is_num(ar));
                num = ar->ar_num;
        }
 
index 6a8a0df3c4cce99d42a9ae7668a4b4fff62acbe0..dfe6d48677cd3dbd30f2494392ab3da0d6b5fcaf 100644 (file)
@@ -1464,11 +1464,52 @@ static fr_slen_t tmpl_attr_parse_filter(tmpl_attr_error_t *err, tmpl_attr_t *ar,
                slen = xlat_tokenize_condition(ar, &ar->ar_cond, &tmp, &p_rules, &t_rules);
                if (slen < 0) goto error;
 
+               fr_assert(!xlat_impure_func(ar->ar_cond));
+
                ar->ar_filter_type = TMPL_ATTR_FILTER_TYPE_CONDITION;
                fr_sbuff_set(&our_name, &tmp);  /* Advance name _AFTER_ doing checks */
                break;
        }
 
+       case '%':               /* ${...} expansion */
+       {
+               fr_sbuff_t tmp = FR_SBUFF(&our_name);
+               fr_slen_t slen;
+               tmpl_rules_t t_rules;
+               fr_sbuff_parse_rules_t p_rules;
+               fr_sbuff_term_t const filter_terminals = FR_SBUFF_TERMS(L("]"));
+
+               if (!fr_sbuff_is_str(&our_name, "%{", 2)) {
+                       fr_strerror_const("Invalid expression in attribute index");
+                       goto error;
+               }
+
+               tmp = FR_SBUFF(&our_name);
+               t_rules = (tmpl_rules_t) {};
+               t_rules.attr = *at_rules;
+
+               p_rules = (fr_sbuff_parse_rules_t) {
+                       .terminals = &filter_terminals,
+                       .escapes = NULL
+               };
+
+               /*
+                *      Check if it's an expression.
+                */
+               slen = xlat_tokenize_expression(ar, &ar->ar_cond, &tmp, &p_rules, &t_rules);
+               if (slen < 0) goto error;
+
+               if (xlat_impure_func(ar->ar_expr)) {
+                       fr_strerror_const("Expression in attribute index cannot depend on functions which call external databases");
+                       goto error;
+               }
+
+               ar->ar_filter_type = TMPL_ATTR_FILTER_TYPE_EXPR;
+
+               fr_sbuff_set(&our_name, &tmp);  /* Advance name _AFTER_ doing checks */
+               break;
+       }
+
        case 'n':
                /*
                 *      [n] is the last one
@@ -1514,7 +1555,7 @@ static fr_slen_t tmpl_attr_parse_filter(tmpl_attr_error_t *err, tmpl_attr_t *ar,
                if (slen <= 0) goto error;
 
                if (!tmpl_is_attr(ar->ar_tmpl)) {
-                       fr_strerror_printf("Invalid array index");
+                       fr_strerror_const("Invalid array index");
                        goto error;
                }
 
@@ -1525,7 +1566,7 @@ static fr_slen_t tmpl_attr_parse_filter(tmpl_attr_error_t *err, tmpl_attr_t *ar,
                 *      For matching therefore, we really need to have a way to define "self".
                 */
                if (!fr_type_numeric[tmpl_attr_tail_da(ar->ar_tmpl)->type]) {
-                       fr_strerror_printf("Invalid data type for array index (must be numeric)");
+                       fr_strerror_const("Invalid data type for array index (must be numeric)");
                        goto error;
                }