From: Alan T. DeKok Date: Sun, 1 Oct 2023 12:54:20 +0000 (-0400) Subject: allow expressions in %{...} xlats X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=aa81ffb3851012490a62e8797f16cd526e0ec963;p=thirdparty%2Ffreeradius-server.git allow expressions in %{...} xlats --- diff --git a/src/lib/unlang/xlat_eval.c b/src/lib/unlang/xlat_eval.c index fc138c698c6..e2edaf0dabf 100644 --- a/src/lib/unlang/xlat_eval.c +++ b/src/lib/unlang/xlat_eval.c @@ -1197,7 +1197,7 @@ xlat_action_t xlat_frame_eval(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_exp_head_ if (tmpl_eval_pair(ctx, &result, request, node->vpt) < 0) goto fail; - } else if (tmpl_is_exec(node->vpt)) { /* exec only */ + } else if (tmpl_is_exec(node->vpt) || tmpl_is_xlat(node->vpt)) { xlat_exec_rctx_t *rctx; /* diff --git a/src/lib/unlang/xlat_tokenize.c b/src/lib/unlang/xlat_tokenize.c index d3b92f00455..99633070714 100644 --- a/src/lib/unlang/xlat_tokenize.c +++ b/src/lib/unlang/xlat_tokenize.c @@ -906,6 +906,13 @@ done: return 0; } +static bool const tmpl_attr_allowed_chars[UINT8_MAX + 1] = { + SBUFF_CHAR_CLASS_ALPHA_NUM, + ['-'] = true, ['/'] = true, ['_'] = true, // fr_dict_attr_allowed_chars + ['.'] = true, ['*'] = true, ['#'] = true, + ['['] = true, [']'] = true, // tmpls and attribute arrays +}; + int xlat_tokenize_expansion(xlat_exp_head_t *head, fr_sbuff_t *in, tmpl_rules_t const *t_rules) { @@ -962,6 +969,71 @@ int xlat_tokenize_expansion(xlat_exp_head_t *head, fr_sbuff_t *in, } #endif /* HAVE_REGEX */ + /* + * See if it's an old-style function name. + */ + fr_sbuff_marker(&s_m, in); + len = fr_sbuff_adv_past_allowed(in, SIZE_MAX, xlat_func_chars, NULL); + if (fr_sbuff_is_char(in, ':')) { + if (!len) goto missing_function; + goto check_for_attr; + } + + /* + * See if it's an attribute reference, with possible array stuff. + */ + len += fr_sbuff_adv_past_allowed(in, SIZE_MAX, tmpl_attr_allowed_chars, NULL); + if (fr_sbuff_is_char(in, '}')) { + if (!len) goto empty_disallowed; + goto check_for_attr; + } + + if (!fr_sbuff_extend(in)) { + fr_strerror_const("Missing closing brace"); + fr_sbuff_marker_release(&s_m); + return -1; + } + + /* + * It must be an expression. + * + * We wrap the xlat in a tmpl, so that the result is just a value, and not wrapped in another + * XLAT_GROUP, which turns into a wrapper of FR_TYPE_GROUP in the value-box. + */ + { + int ret; + char *fmt; + xlat_exp_t *node; + xlat_exp_head_t *child; + + fr_sbuff_set(in, &s_m); /* backtrack to the start of the expression */ + + MEM(node = xlat_exp_alloc(head, XLAT_TMPL, NULL, 0)); + MEM(node->vpt = tmpl_alloc(node, TMPL_TYPE_XLAT, T_BARE_WORD, "", 1)); + + ret = xlat_tokenize_expression(node->vpt, &child, in, &attr_p_rules, t_rules); + if (ret <= 0) { + talloc_free(node); + return ret; + } + + if (!fr_sbuff_next_if_char(in, '}')) { + fr_strerror_const("Missing closing brace"); + return -1; + } + + MEM(fmt = talloc_bstrndup(node, fr_sbuff_current(&s_m), fr_sbuff_behind(&s_m))); + xlat_exp_set_name_buffer_shallow(node, fmt); + tmpl_set_name_shallow(node->vpt, T_BARE_WORD, fmt, fr_sbuff_behind(&s_m)); + + tmpl_set_xlat(node->vpt, child); + xlat_exp_insert_tail(head, node); + return ret; + } + +check_for_attr: + fr_sbuff_set(in, &s_m); /* backtrack */ + /* * %{Attr-Name} * %{Attr-Name[#]} @@ -993,10 +1065,12 @@ int xlat_tokenize_expansion(xlat_exp_head_t *head, fr_sbuff_t *in, if (len == 0) { switch (hint) { case '}': + empty_disallowed: fr_strerror_const("Empty expression is invalid"); return -1; case ':': + missing_function: fr_strerror_const("Missing expansion function"); return -1; diff --git a/src/tests/keywords/expand-expr b/src/tests/keywords/expand-expr new file mode 100644 index 00000000000..6f4d2f36e1b --- /dev/null +++ b/src/tests/keywords/expand-expr @@ -0,0 +1,20 @@ +uint32 foo +uint32 bar +uint32 baz +uint32 none + +&foo = 1 +&bar = 2 + +&baz := %{&foo + &bar} + +if !(&baz == 3) { + test_fail +} + +&baz := %{&none || &foo} +if !(&baz == &foo) { + test_fail +} + +success diff --git a/src/tests/unit/xlat/base.txt b/src/tests/unit/xlat/base.txt index 63706b75d66..4bbe2bc0d7b 100644 --- a/src/tests/unit/xlat/base.txt +++ b/src/tests/unit/xlat/base.txt @@ -237,19 +237,19 @@ xlat %{[baz} match ERROR offset 3: Missing attribute name xlat %{ } -match ERROR offset 3: Invalid char ' ' in expression +match ERROR offset 4: No operand found. Expected &ref, literal, 'quoted literal', "%{expansion}", or enum value xlat %{\t} -match ERROR offset 3: Invalid attribute name +match ERROR offset 3: No operand found. Expected &ref, literal, 'quoted literal', "%{expansion}", or enum value xlat %{\n} -match ERROR offset 3: Invalid attribute name +match ERROR offset 3: No operand found. Expected &ref, literal, 'quoted literal', "%{expansion}", or enum value xlat %{foo } -match ERROR offset 6: Invalid char ' ' in expression +match ERROR offset 7: Unexpected text - attribute names must prefixed with '&' xlat %{foo bar} -match ERROR offset 6: Invalid char ' ' in expression +match ERROR offset 7: Invalid operator xlat %{test: match ERROR offset 8: Missing closing brace @@ -294,8 +294,12 @@ xlat_argv /bin/sh "foo bar" "%{User-Name} %{Filter-Id}" match [0]{ /bin/sh }, [1]{ foo bar }, [2]{ %{User-Name} %{Filter-Id} } # and errors +# +# @todo - we should really be unescaping the input in the sbuff, OR passing in the terminals +# to xlat_tokenize_expansion() +# xlat_argv /bin/sh "foo bar" "%{User-Name} %{Filter-Id" -match ERROR offset 45: Missing closing brace +match ERROR offset 44: Unexpected text after enum value. Expected operator # and text immediately after a variable expansion xlat_argv echo hello %{Tmp-String-0}:1234 world