From: Arran Cudbard-Bell Date: Tue, 16 Mar 2021 15:44:07 +0000 (+0000) Subject: Validate arguments at tokenize time X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f08c9b96f777d492318d727aaa50d6415d84d977;p=thirdparty%2Ffreeradius-server.git Validate arguments at tokenize time --- diff --git a/src/lib/unlang/xlat_eval.c b/src/lib/unlang/xlat_eval.c index 4782a452d7e..3e453f26e24 100644 --- a/src/lib/unlang/xlat_eval.c +++ b/src/lib/unlang/xlat_eval.c @@ -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); diff --git a/src/lib/unlang/xlat_priv.h b/src/lib/unlang/xlat_priv.h index ef8a441ff59..19e7b3a6d4d 100644 --- a/src/lib/unlang/xlat_priv.h +++ b/src/lib/unlang/xlat_priv.h @@ -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. diff --git a/src/lib/unlang/xlat_tokenize.c b/src/lib/unlang/xlat_tokenize.c index e566e7ce2fa..ce8b5e914d2 100644 --- a/src/lib/unlang/xlat_tokenize.c +++ b/src/lib/unlang/xlat_tokenize.c @@ -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 */