]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Validate arguments at tokenize time
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Tue, 16 Mar 2021 15:44:07 +0000 (15:44 +0000)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Tue, 16 Mar 2021 15:44:07 +0000 (15:44 +0000)
src/lib/unlang/xlat_eval.c
src/lib/unlang/xlat_priv.h
src/lib/unlang/xlat_tokenize.c

index 4782a452d7ea12f983d403ad5c30cbde1163c6c1..3e453f26e24454af8c132aaa8fe0d814cf8e32ba 100644 (file)
@@ -1039,7 +1039,8 @@ xlat_action_t xlat_frame_eval_repeat(TALLOC_CTX *ctx, fr_dcursor_t *out,
                        fr_value_box_list_init(&result_copy);
                        thread_inst = xlat_thread_instance_find(node);
 
-                       XLAT_DEBUG("** [%i] %s(func-async) - %%{%s:%pM}", unlang_interpret_stack_depth(request), __FUNCTION__,
+                       XLAT_DEBUG("** [%i] %s(func-async) - %%{%s:%pM}",
+                                  unlang_interpret_stack_depth(request), __FUNCTION__,
                                   node->fmt, result);
 
                        /*
@@ -1048,14 +1049,18 @@ xlat_action_t xlat_frame_eval_repeat(TALLOC_CTX *ctx, fr_dcursor_t *out,
                         */
                        if (RDEBUG_ENABLED2) fr_value_box_list_acopy(NULL, &result_copy, result);
 
-                       if (!fr_dlist_empty(result)) { fr_dlist_verify(result); }
+                       if (!fr_dlist_empty(result)) fr_dlist_verify(result);
+
                        xa = xlat_process_args(ctx, result, request, node->call.func->input_type, node->call.func->args);
                        if (xa == XLAT_ACTION_FAIL) {
                                if (RDEBUG_ENABLED2) fr_dlist_talloc_free(&result_copy);
-                               return (xa);
+                               return xa;
                        }
-                       xa = node->call.func->func.async(ctx, out, request, node->call.inst->data, thread_inst->data, result);
-                       if (!fr_dlist_empty(result)) { fr_dlist_verify(result); }
+
+                       xa = node->call.func->func.async(ctx, out, request,
+                                                        node->call.inst->data, thread_inst->data, result);
+
+                       if (!fr_dlist_empty(result)) fr_dlist_verify(result);
                        if (RDEBUG_ENABLED2) {
                                xlat_debug_log_expansion(request, *in, &result_copy);
                                fr_dlist_talloc_free(&result_copy);
index ef8a441ff598d52655377276da6efb7af05b30dc..19e7b3a6d4da4a61d19dc2c9cc1b69910b4ce75c 100644 (file)
@@ -111,8 +111,7 @@ typedef struct {
  * These nodes form a tree which represents one or more nested expansions.
  */
 struct xlat_exp {
-       char const      *fmt;           //!< The original format string.
-       size_t          len;            //!< Length of the format string.
+       char const      *fmt;           //!< The original format string (a talloced buffer).
        fr_token_t      quote;          //!< Type of quoting around XLAT_GROUP types.
 
        xlat_flags_t    flags;          //!< Flags that control resolution and evaluation.
index e566e7ce2fa33118f87658e0df1e27bf844583c6..ce8b5e914d2653472410c5c6d09d345e8dcf4e15 100644 (file)
@@ -325,6 +325,19 @@ static inline int xlat_tokenize_regex(TALLOC_CTX *ctx, xlat_exp_t **head, xlat_f
 }
 #endif
 
+static inline int xlat_validate_function_mono(xlat_exp_t *node)
+{
+       fr_assert(node->type == XLAT_FUNC_NORMAL);
+
+       if (node->call.func->args && node->call.func->args->required &&
+           (node->child->type == XLAT_LITERAL) && (talloc_array_length(node->child->fmt) == 1)) {
+               fr_strerror_const("Missing required input");
+               return -1;
+       }
+
+       return 0;
+}
+
 /** Parse an xlat function and its child argument
  *
  * Parses a function call string in the format
@@ -334,9 +347,9 @@ static inline int xlat_tokenize_regex(TALLOC_CTX *ctx, xlat_exp_t **head, xlat_f
  *     - 0 if the string was parsed into a function.
  *     - <0 on parse error.
  */
-static inline int xlat_tokenize_function_single_arg(TALLOC_CTX *ctx, xlat_exp_t **head,
-                                                   xlat_flags_t *flags, fr_sbuff_t *in,
-                                                   tmpl_rules_t const *rules)
+static inline int xlat_tokenize_function_mono(TALLOC_CTX *ctx, xlat_exp_t **head,
+                                             xlat_flags_t *flags, fr_sbuff_t *in,
+                                             tmpl_rules_t const *rules)
 {
        xlat_exp_t              *node;
        xlat_t                  *func;
@@ -408,6 +421,11 @@ static inline int xlat_tokenize_function_single_arg(TALLOC_CTX *ctx, xlat_exp_t
                goto error;
        }
 
+       /*
+        *      Check there's input if it's needed
+        */
+       if ((node->type == XLAT_FUNC_NORMAL) && (xlat_validate_function_mono(node) < 0)) goto error;
+
        if (!fr_sbuff_next_if_char(in, '}')) {
                fr_strerror_const("Missing closing brace");
                goto error;
@@ -419,6 +437,28 @@ static inline int xlat_tokenize_function_single_arg(TALLOC_CTX *ctx, xlat_exp_t
        return 0;
 }
 
+static inline int xlat_validate_function_args(xlat_exp_t *node)
+{
+       xlat_arg_parser_t const *arg_p;
+       xlat_exp_t              *child = node->child;
+
+       fr_assert(node->type == XLAT_FUNC_NORMAL);
+
+       for (arg_p = node->call.func->args; arg_p->type != FR_TYPE_NULL; arg_p++) {
+               if (!arg_p->required) break;
+
+               if (!child) {
+                       fr_strerror_printf("Missing required arg %u",
+                                          (unsigned int)(arg_p - node->call.func->args) + 1);
+                       return -1;
+               }
+
+               child = child->next;
+       }
+
+       return 0;
+}
+
 /** Parse an xlat function and its child arguments
  *
  * Parses a function call string in the format
@@ -428,9 +468,9 @@ static inline int xlat_tokenize_function_single_arg(TALLOC_CTX *ctx, xlat_exp_t
  *     - 0 if the string was parsed into a function.
  *     - <0 on parse error.
  */
-static inline int xlat_tokenize_function_multi_arg(TALLOC_CTX *ctx, xlat_exp_t **head,
-                                                  xlat_flags_t *flags, fr_sbuff_t *in,
-                                                  tmpl_rules_t const *rules)
+static inline int xlat_tokenize_function_args(TALLOC_CTX *ctx, xlat_exp_t **head,
+                                             xlat_flags_t *flags, fr_sbuff_t *in,
+                                             tmpl_rules_t const *rules)
 {
        xlat_exp_t              *node;
        xlat_t                  *func;
@@ -501,6 +541,11 @@ static inline int xlat_tokenize_function_multi_arg(TALLOC_CTX *ctx, xlat_exp_t *
                goto error;
        }
 
+       /*
+        *      Check we have all the required arguments
+        */
+       if ((node->type == XLAT_FUNC_NORMAL) && (xlat_validate_function_args(node) < 0)) goto error;
+
        if (!fr_sbuff_next_if_char(in, ')')) {
                fr_strerror_const("Missing closing brace");
                goto error;
@@ -767,7 +812,7 @@ static int xlat_tokenize_expansion(TALLOC_CTX *ctx, xlat_exp_t **head, xlat_flag
                fr_sbuff_set(in, &s_m);         /* backtrack */
                fr_sbuff_marker_release(&s_m);
 
-               ret = xlat_tokenize_function_single_arg(ctx, head, flags, in, t_rules);
+               ret = xlat_tokenize_function_mono(ctx, head, flags, in, t_rules);
                if (ret <= 0) return ret;
        }
                break;
@@ -921,7 +966,7 @@ static int xlat_tokenize_literal(TALLOC_CTX *ctx, xlat_exp_t **head, xlat_flags_
                if (fr_sbuff_adv_past_str_literal(in, "%(")) {
                        if (len == 0) TALLOC_FREE(node); /* Free the empty node */
 
-                       if (xlat_tokenize_function_multi_arg(ctx, &node, flags, in, t_rules) < 0) goto error;
+                       if (xlat_tokenize_function_args(ctx, &node, flags, in, t_rules) < 0) goto error;
                        fr_cursor_insert(&cursor, node);
                        node = NULL;
                        continue;
@@ -1614,6 +1659,23 @@ int xlat_resolve(xlat_exp_t **head, xlat_flags_t *flags, bool allow_unresolved)
                        xlat_exp_set_type(node, XLAT_FUNC);
                        node->call.func = func;
 
+                       /*
+                        *      Check input arguments of our freshly
+                        *      resolved function
+                        */
+                       switch (node->call.func->input_type) {
+                       case XLAT_INPUT_UNPROCESSED:
+                               break;
+
+                       case XLAT_INPUT_MONO:
+                               if (xlat_validate_function_mono(node) < 0) return -1;
+                               break;
+
+                       case XLAT_INPUT_ARGS:
+                               if (xlat_validate_function_args(node) < 0) return -1;
+                               break;
+                       }
+
                        /*
                         *      Reset node flags
                         */