From: Alan T. DeKok Date: Wed, 19 Jan 2022 20:39:38 +0000 (-0500) Subject: first pass of xlat_purify_expr() X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5559796368911a1ccc2181eb50b99d402d1a75e7;p=thirdparty%2Ffreeradius-server.git first pass of xlat_purify_expr() which only works on expressions and comparisons, and then only some of the time. And then only if it's asked to. --- diff --git a/src/lib/unlang/xlat_expr.c b/src/lib/unlang/xlat_expr.c index e122b36ba0..e661c9df7f 100644 --- a/src/lib/unlang/xlat_expr.c +++ b/src/lib/unlang/xlat_expr.c @@ -76,12 +76,6 @@ RCSID("$Id$") * run time. */ -static xlat_arg_parser_t const cast_xlat_args[] = { - { .required = true, .type = FR_TYPE_INT32 }, - { .required = true, .type = FR_TYPE_VOID }, - XLAT_ARG_PARSER_TERMINATOR -}; - /* * @todo - Call this function for && / ||. The casting rules for expressions / conditions are slightly * different than fr_value_box_cast(). Largely because that function is used to parse configuration @@ -93,6 +87,10 @@ static void cast_to_bool(fr_value_box_t *out, fr_value_box_t const *in) fr_value_box_init(out, FR_TYPE_BOOL, NULL, false); switch (in->type) { + case FR_TYPE_BOOL: + out->vb_bool = in->vb_bool; + break; + case FR_TYPE_STRING: case FR_TYPE_OCTETS: out->vb_bool = (in->vb_length > 0); @@ -114,6 +112,112 @@ static void cast_to_bool(fr_value_box_t *out, fr_value_box_t const *in) } } +/** Basic purify, but only for expressions and comparisons. + * + */ +static int xlat_purify_expr(xlat_exp_t *node, xlat_t *func) +{ + int rcode = -1; + xlat_exp_t *child; + fr_value_box_t *dst = NULL, *box; + xlat_arg_parser_t const *arg; + xlat_action_t xa; + fr_value_box_list_t input, output; + fr_dcursor_t cursor; + + if (!func || (node->type != XLAT_FUNC)) return 0; + + if (!node->flags.pure) return 0; + + if (!func->internal) return 0; + + if (func->token == T_INVALID) return 0; + + /* + * @todo - for &&, ||, check only the LHS operation. If + * it satisfies the criteria, then reparent the next + * child, free the "node" node, and return the child. + */ + + /* + * A child isn't a value-box. We leave it alone. + */ + for (child = node->child; child != NULL; child = child->next) { + if (child->type != XLAT_BOX) return 0; + } + + fr_value_box_list_init(&input); + fr_value_box_list_init(&output); + + /* + * Loop over the boxes, checking func->args, too. We + * have to cast the box to the correct data type (or copy + * it), and then add the box to the source list. + */ + for (child = node->child, arg = func->args; + child != NULL; + child = child->next, arg++) { + MEM(box = fr_value_box_alloc_null(node)); + + if ((arg->type != FR_TYPE_VOID) && (arg->type != box->type)) { + if (fr_value_box_cast(node, box, arg->type, NULL, &child->data) < 0) goto fail; + + } else if (fr_value_box_copy(node, box, &child->data) < 0) { + fail: + talloc_free(box); + goto cleanup; + } + + /* + * cast / copy over-writes the list fields. + */ + fr_dlist_insert_tail(&input, box); + } + + /* + * We then call the function, and change the node type to + * XLAT_BOX, and copy the value there. If there are any + * issues, we return an error, and the caller assumes + * that the error is accessible via fr_strerror(). + */ + fr_dcursor_init(&cursor, &output); + + xa = func->func(node, &cursor, NULL, NULL, &input); + if (xa == XLAT_ACTION_FAIL) { + goto cleanup; + } + + while ((child = node->child) != NULL) { + node->child = child->next; + talloc_free(child); + } + + dst = fr_dcursor_head(&cursor); + fr_assert(dst != NULL); + fr_assert(fr_dcursor_next(&cursor) == NULL); + + xlat_exp_set_type(node, XLAT_BOX); + (void) fr_value_box_copy(node, &node->data, dst); + + rcode = 0; + +cleanup: + while ((box = fr_dlist_head(&input)) != NULL) { + fr_dlist_remove(&input, box); + talloc_free(box); + } + + talloc_free(dst); + + return rcode; +} + +static xlat_arg_parser_t const cast_xlat_args[] = { + { .required = true, .type = FR_TYPE_INT32 }, + { .required = true, .type = FR_TYPE_VOID }, + XLAT_ARG_PARSER_TERMINATOR +}; + static xlat_action_t xlat_func_cast(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, fr_value_box_list_t *in) @@ -1054,6 +1158,16 @@ redo: xlat_flags_merge(&node->flags, &lhs->flags); xlat_flags_merge(&node->flags, &rhs->flags); + /* + * Purify things in place, where we can. + */ + if (flags->pure) { + if (xlat_purify_expr(node, func) < 0) { + talloc_free(node); + FR_SBUFF_ERROR_RETURN(&in); /* @todo m_lhs ? */ + } + } + lhs = node; goto redo; }