]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Rremove the last legacy xlat function Closes #4321
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Wed, 1 Dec 2021 22:22:54 +0000 (16:22 -0600)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Wed, 1 Dec 2021 22:22:54 +0000 (16:22 -0600)
src/lib/unlang/xlat_builtin.c
src/lib/unlang/xlat_tokenize.c
src/tests/keywords/xlat-eval [moved from src/tests/keywords/xlat-xlat with 60% similarity]

index e078f9ceb27c5152ed461580f4386975a835cf5f..85e017eea0a9fdb08f942eb26f389d69c6352a34 100644 (file)
@@ -1563,58 +1563,111 @@ static xlat_action_t xlat_func_next_time(TALLOC_CTX *ctx, fr_dcursor_t *out,
                return XLAT_ACTION_FAIL;
        }
 
-       MEM(vb=fr_value_box_alloc_null(ctx));
+       MEM(vb = fr_value_box_alloc_null(ctx));
        fr_value_box_uint64(vb, NULL, (uint64_t)(mktime(local) - now), false);
        fr_dcursor_append(out, vb);
        return XLAT_ACTION_DONE;
 }
 
-/** xlat expand string attribute value
+typedef struct {
+       bool            last_success;
+       xlat_exp_t      *ex;
+} xlat_eval_rctx_t;
+
+/** Just serves to push the result up the stack
  *
- * @ingroup xlat_functions
  */
-static ssize_t xlat_func_xlat(TALLOC_CTX *ctx, char **out, size_t outlen,
-                             UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
-                             request_t *request, char const *fmt)
+static xlat_action_t xlat_eval_resume(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out,
+                                     xlat_ctx_t const *xctx,
+                                     UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
 {
-       ssize_t         slen;
-       fr_pair_t       *vp;
+       xlat_eval_rctx_t        *rctx = talloc_get_type_abort(xctx->rctx, xlat_eval_rctx_t);
+       xlat_action_t           *xa = rctx->last_success ? XLAT_ACTION_DONE : XLAT_ACTION_YIELD;
 
-       fr_skip_whitespace(fmt);
+       talloc_free(rctx);
 
-       if (outlen < 3) {
-       nothing:
-               return 0;
-       }
+       return xa;
+}
 
-       if ((xlat_fmt_get_vp(&vp, request, fmt) < 0) || !vp) goto nothing;
+static xlat_arg_parser_t const xlat_func_eval_arg = {
+       .required = true,
+       .concat = true,
+       .type = FR_TYPE_STRING
+};
 
-       RDEBUG2("EXPAND %s", fmt);
-       RINDENT();
+/** Dynamically evaluate an expansion string
+ *
+ * @ingroup xlat_functions
+ */
+static xlat_action_t xlat_func_eval(TALLOC_CTX *ctx, fr_dcursor_t *out,
+                                   UNUSED xlat_ctx_t const *xctx,
+                                   request_t *request, fr_value_box_list_t *in)
+{
+
+       xlat_flags_t            flags = {};
+       xlat_eval_rctx_t        *rctx;
+       fr_value_box_t          *arg = fr_dlist_head(in);
 
        /*
-        *      If it's a string, expand it again
+        *      These are escaping rules applied to the
+        *      input string. They're mostly here to
+        *      allow \% and \\ to work.
+        *
+        *      Everything else should be passed in as
+        *      unescaped data.
         */
-       if (vp->vp_type == FR_TYPE_STRING) {
-               slen = xlat_eval(*out, outlen, request, vp->vp_strvalue, NULL, NULL);
-               if (slen <= 0) return slen;
+       static fr_sbuff_unescape_rules_t const escape_rules = {
+               .name = "xlat",
+               .chr = '\\',
+               .subs = {
+                       ['%'] = '%',
+                       ['\\'] = '\\',
+               },
+               .do_hex = false,
+               .do_oct = false
+       };
+
+       MEM(rctx = talloc_zero(unlang_interpret_frame_talloc_ctx(request), xlat_eval_rctx_t));
+
        /*
-        *      If it's not a string, treat it as a literal value
+        *      Parse the input as a literal expansion
         */
-       } else {
-               slen = fr_value_box_aprint(ctx, out, &vp->data, NULL);
-               if (!*out) return -1;
+       if (xlat_tokenize_ephemeral(rctx,
+                                   &rctx->ex, unlang_interpret_event_list(request), &flags,
+                                   &FR_SBUFF_IN(arg->vb_strvalue, arg->vb_length),
+                                   &(fr_sbuff_parse_rules_t){ .escapes = &escape_rules },
+                                   &(tmpl_rules_t){
+                                       .allow_unknown = false,
+                                       .allow_unresolved = false,
+                                       .allow_foreign = false,
+                                       .dict_def = request->dict,
+                                       .at_runtime = true
+                                   }) < 0) {
+               RPEDEBUG("Failed parsing expansion");
+       error:
+               talloc_free(rctx);
+               return XLAT_ACTION_FAIL;
        }
 
-       REXDENT();
-       RDEBUG2("--> %s", *out);
+       /*
+        *      Call the resolution function so we produce
+        *      good errors about what function was
+        *      unresolved.
+        */
+       if (flags.needs_resolving &&
+           (xlat_resolve(&rctx->ex, &flags, &(xlat_res_rules_t){ .allow_unresolved = false }) < 0)) {
+               RPEDEBUG("Unresolved expansion functions in expansion");
+               goto error;
 
-       return slen;
-}
+       }
 
-/*
- *     Async xlat functions
- */
+       if (unlang_xlat_yield(request, xlat_eval_resume, NULL, rctx) != XLAT_ACTION_YIELD) goto error;
+
+       if (unlang_xlat_push(ctx, &rctx->last_success, out->dlist,
+                            request, rctx->ex, UNLANG_SUB_FRAME) < 0) goto error;
+
+       return XLAT_ACTION_PUSH_UNLANG;
+}
 
 static xlat_arg_parser_t const xlat_func_pad_args[] = {
        { .required = true, .type = FR_TYPE_STRING },
@@ -1623,7 +1676,6 @@ static xlat_arg_parser_t const xlat_func_pad_args[] = {
        XLAT_ARG_PARSER_TERMINATOR
 };
 
-
 /** lpad a string
  *
 @verbatim
@@ -3563,11 +3615,6 @@ int xlat_init(void)
         */
        if (xlat_protocol_init() < 0) return -1;
 
-#define XLAT_REGISTER(_x) xlat = xlat_register_legacy(NULL, STRINGIFY(_x), xlat_func_ ## _x, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN); \
-       xlat_internal(xlat);
-
-       XLAT_REGISTER(xlat);
-
        /*
         *      These are all "pure" functions.
         */
@@ -3649,6 +3696,7 @@ do { \
        XLAT_REGISTER_MONO("toupper", xlat_func_toupper, xlat_change_case_arg);
        XLAT_REGISTER_MONO("urlquote", xlat_func_urlquote, xlat_func_urlquote_arg);
        XLAT_REGISTER_MONO("urlunquote", xlat_func_urlunquote, xlat_func_urlunquote_arg);
+       XLAT_REGISTER_MONO("eval", xlat_func_eval, xlat_func_eval_arg);
 
 #undef XLAT_REGISTER_MONO
 #define XLAT_REGISTER_MONO(_xlat, _func, _arg) \
index 265316f50601b3245ab4d69690e763af7999a386..844c833f1b29c09cc1a65ae96e166f705070bdf2 100644 (file)
@@ -1309,7 +1309,7 @@ ssize_t xlat_print(fr_sbuff_t *out, xlat_exp_t const *head, fr_sbuff_escape_rule
  * @param[in] ctx      to allocate dynamic buffers in.
  * @param[out] head    the head of the xlat list / tree structure.
  * @param[in] el       for registering any I/O handlers.
- * @param[in] flags    that control evaluation and parsing.
+ * @param[out] flags   indicating the state of the ephemeral tree.
  * @param[in] in       the format string to expand.
  * @param[in] p_rules  from the encompassing grammar.
  * @param[in] t_rules  controlling how attribute references are parsed.
@@ -1325,15 +1325,20 @@ ssize_t xlat_tokenize_ephemeral(TALLOC_CTX *ctx, xlat_exp_t **head,
                                fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules)
 {
        fr_sbuff_t      our_in = FR_SBUFF(in);
+       tmpl_rules_t    our_t_rules = {};
        xlat_flags_t    tmp_flags = {};
 
        if (!flags) flags = &tmp_flags;
 
        *head = NULL;
 
+       if (t_rules) our_t_rules = *t_rules;
+
+       our_t_rules.runtime_el = el;
+
        fr_strerror_clear();    /* Clear error buffer */
        if (xlat_tokenize_string(ctx, head, flags, &our_in,
-                                 false, p_rules, t_rules) < 0) return -fr_sbuff_used(&our_in);
+                                false, p_rules, &our_t_rules) < 0) return -fr_sbuff_used(&our_in);
 
        /*
         *      Zero length expansion, return a zero length node.
similarity index 60%
rename from src/tests/keywords/xlat-xlat
rename to src/tests/keywords/xlat-eval
index e8c1f6208ecc6af4d955964e2ba9e3e71639c24a..d1114819d97a4119656f2c9b4232fad24e6c9010 100644 (file)
@@ -14,25 +14,32 @@ update request {
 #
 #  Verify non string types are treated as literals
 #
-if ("%{xlat:Tmp-Integer-0}" != 4) {
+if ("%{eval:%{Tmp-Integer-0}}" != 4) {
        test_fail
 }
 
-if ("%{xlat:Tmp-Integer-0[1]}" != 8) {
+if ("%{eval:%{Tmp-Integer-0[1]}}" != 8) {
        test_fail
 }
 
 #
 #  Check double expansion works
 #
-if ("%{xlat:Tmp-String-0}" != 'foo') {
+if ("%{eval:%{Tmp-String-0}}" != 'foo') {
        test_fail
 }
 
 #
 #  Using an attribute as a dynamic index for another attribute
 #
-if ("%{xlat:Tmp-String-1[%{Tmp-Integer-0[2]}]}" != 'bar') {
+if ("%{eval:\%{Tmp-String-1[%{Tmp-Integer-0[2]}]\}}" != 'bar') {
+       test_fail
+}
+
+#
+#  Check yielding works
+#
+if (<time_delta>"%(reschedule:)" > 1s) {
        test_fail
 }