From: Arran Cudbard-Bell Date: Wed, 1 Dec 2021 23:11:49 +0000 (-0600) Subject: Remove legacy xlat function infrastructure X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f1085653ba394c8b9f4b0cd5741a612f0032272d;p=thirdparty%2Ffreeradius-server.git Remove legacy xlat function infrastructure --- diff --git a/src/lib/unlang/xlat.h b/src/lib/unlang/xlat.h index d019d39ec73..f5d8e559551 100644 --- a/src/lib/unlang/xlat.h +++ b/src/lib/unlang/xlat.h @@ -264,30 +264,6 @@ typedef int (*xlat_detach_t)(xlat_inst_ctx_t const *xctx); */ typedef int (*xlat_thread_detach_t)(xlat_thread_inst_ctx_t const *xctx); -/** legacy xlat callback function - * - * Should write the result of expanding the fmt string to the output buffer. - * - * If a outlen > 0 was provided to #xlat_register_legacy, out will point to a talloced - * buffer of that size, which the result should be written to. - * - * If outlen is 0, then the function should allocate its own buffer, in the - * context of the request. - * - * @param[in] ctx to allocate any dynamic buffers in. - * @param[in,out] out Where to write either a pointer to a new buffer, - * or data to an existing buffer. - * @param[in] outlen Length of pre-allocated buffer, or 0 if function should - * allocate its own buffer. - * @param[in] mod_inst Instance data provided by the xlat that registered the xlat. - * @param[in] xlat_inst Instance data created by the xlat instantiation function. - * @param[in] request The current request. - * @param[in] fmt string to expand. - */ -typedef ssize_t (*xlat_func_legacy_t)(TALLOC_CTX *ctx, char **out, size_t outlen, - void const *mod_inst, void const *xlat_inst, - request_t *request, char const *fmt); - typedef size_t (*xlat_escape_legacy_t)(request_t *request, char *out, size_t outlen, char const *in, void *arg); int xlat_fmt_get_vp(fr_pair_t **out, request_t *request, char const *name); @@ -348,14 +324,6 @@ bool xlat_to_string(TALLOC_CTX *ctx, char **str, xlat_exp_t **head); int xlat_resolve(xlat_exp_t **head, xlat_flags_t *flags, xlat_res_rules_t const *xr_rules); - -#define XLAT_DEFAULT_BUF_LEN 2048 - -xlat_t *xlat_register_legacy(void *mod_inst, char const *name, - xlat_func_legacy_t func, xlat_escape_legacy_t escape, - xlat_instantiate_t instantiate, size_t inst_size, - size_t buf_len); - xlat_t *xlat_register_module(TALLOC_CTX *ctx, module_inst_ctx_t const *mctx, char const *name, xlat_func_t func, xlat_flags_t const *flags); xlat_t *xlat_register(TALLOC_CTX *ctx, char const *name, xlat_func_t func, xlat_flags_t const *flags) CC_HINT(nonnull(2)); diff --git a/src/lib/unlang/xlat_builtin.c b/src/lib/unlang/xlat_builtin.c index cbbe740d245..cbe75799339 100644 --- a/src/lib/unlang/xlat_builtin.c +++ b/src/lib/unlang/xlat_builtin.c @@ -150,81 +150,6 @@ static void _xlat_func_tree_free(void *xlat) talloc_free(xlat); } - -/** Register an old style xlat function - * - * @note No new legacy xlat functions should be added to the server. - * Each one added creates additional work later for a member - * of the development team to fix the function to conform to - * the new API. - * - * @param[in] mod_inst Instance of module that's registering the xlat function. - * @param[in] name xlat name. - * @param[in] func xlat function to be called. - * @param[in] escape function to sanitize any sub expansions passed to the xlat function. - * @param[in] instantiate function to pre-parse any xlat specific data. - * @param[in] inst_size sizeof() this xlat's instance data. - * @param[in] buf_len Size of the output buffer to allocate when calling the function. - * May be 0 if the function allocates its own buffer. - * @return - * - A handle for the newly registered xlat function on success. - * - NULL on failure. - */ -xlat_t *xlat_register_legacy(void *mod_inst, char const *name, - xlat_func_legacy_t func, xlat_escape_legacy_t escape, - xlat_instantiate_t instantiate, size_t inst_size, - size_t buf_len) -{ - xlat_t *c; - bool is_new = false; - - if (!xlat_root && (xlat_init() < 0)) return NULL; - - if (!*name) { - ERROR("%s: Invalid xlat name", __FUNCTION__); - return NULL; - } - - /* - * If it already exists, replace the instance. - */ - c = fr_rb_find(xlat_root, &(xlat_t){ .name = name }); - if (c) { - if (c->internal) { - ERROR("%s: Cannot re-define internal expansion %s", __FUNCTION__, name); - return NULL; - } - /* - * Doesn't exist. Create it. - */ - } else { - c = talloc_zero(xlat_root, xlat_t); - c->name = talloc_typed_strdup(c, name); - talloc_set_destructor(c, _xlat_func_talloc_free); - is_new = true; - } - - c->func.sync = func; - c->type = XLAT_FUNC_LEGACY; - c->buf_len = buf_len; - c->escape = escape; - c->mod_inst = mod_inst; - c->instantiate = instantiate; - c->inst_size = inst_size; - - DEBUG3("%s: %s", __FUNCTION__, c->name); - - if (is_new && (fr_rb_replace(NULL, xlat_root, c) < 0)) { - ERROR("Failed inserting xlat registration for %s", - c->name); - talloc_free(c); - return NULL; - } - - return c; -} - - /** Register an xlat function for a module * * @param[in] ctx Used to automate deregistration of the xlat fnction. @@ -263,12 +188,12 @@ xlat_t *xlat_register_module(TALLOC_CTX *ctx, module_inst_ctx_t const *mctx, return NULL; } - if ((c->type != XLAT_FUNC_NORMAL) || (c->flags.needs_async != flags->needs_async)) { + if (c->flags.needs_async != flags->needs_async) { ERROR("%s: Cannot change async capability of %s", __FUNCTION__, name); return NULL; } - if (c->func.async != func) { + if (c->func != func) { ERROR("%s: Cannot change callback function for %s", __FUNCTION__, name); return NULL; } @@ -286,11 +211,8 @@ xlat_t *xlat_register_module(TALLOC_CTX *ctx, module_inst_ctx_t const *mctx, } *c = (xlat_t){ .name = talloc_typed_strdup(c, name), - .func = { - .async = func - }, + .func = func, .mctx = our_mctx, - .type = XLAT_FUNC_NORMAL, .flags = *flags, .input_type = XLAT_INPUT_UNPROCESSED /* set default - will be overridden if args are registered */ }; @@ -881,11 +803,6 @@ static int xlat_redundant_instantiate(xlat_inst_ctx_t const *xctx) * These xlats wrap the xlat methods of the modules in a redundant section, * emulating the behaviour of a redundant section, but over xlats. * - * @todo - make xlat_register_legacy() take ASYNC / SYNC / UNKNOWN. We may - * need "unknown" here in order to properly handle the children, which - * we don't know are async-safe or not. For now, it's best to assume - * that all xlat's in a redundant block are module calls, and are not async-safe - * * @return * - 0 on success. * - -1 on error. diff --git a/src/lib/unlang/xlat_eval.c b/src/lib/unlang/xlat_eval.c index 280364ea30e..4e0f2675ff0 100644 --- a/src/lib/unlang/xlat_eval.c +++ b/src/lib/unlang/xlat_eval.c @@ -1016,130 +1016,71 @@ xlat_action_t xlat_frame_eval_repeat(TALLOC_CTX *ctx, fr_dcursor_t *out, switch (node->type) { case XLAT_FUNC: - switch (node->call.func->type) { - case XLAT_FUNC_LEGACY: - { - fr_value_box_t *value; - char *str = NULL; - char *result_str = NULL; - ssize_t slen; - - if (!fr_dlist_empty(result)) { - VALUE_BOX_TALLOC_LIST_VERIFY(result); - result_str = fr_value_box_list_aprint(NULL, result, NULL, NULL); - if (!result_str) return XLAT_ACTION_FAIL; - } else { - result_str = talloc_typed_strdup(NULL, ""); - } + { + xlat_action_t xa; + xlat_thread_inst_t *t; + fr_value_box_list_t result_copy; - MEM(value = fr_value_box_alloc_null(ctx)); - if (node->call.func->buf_len > 0) { - fr_value_box_bstr_alloc(value, &str, value, NULL, node->call.func->buf_len, false); - } + t = xlat_thread_instance_find(node); + fr_assert(t); - XLAT_DEBUG("** [%i] %s(func) - %%{%s:%pV}", unlang_interpret_stack_depth(request), __FUNCTION__, - node->fmt, - fr_box_strvalue_len(result_str, talloc_array_length(result_str) - 1)); + XLAT_DEBUG("** [%i] %s(func-async) - %%%c%s:%pM%c", + unlang_interpret_stack_depth(request), __FUNCTION__, + (node->call.func->input_type == XLAT_INPUT_ARGS) ? '(' : '{', + node->fmt, result, + (node->call.func->input_type == XLAT_INPUT_ARGS) ? ')' : '}'); - slen = node->call.func->func.sync(value, &str, node->call.func->buf_len, - node->call.func->mod_inst, NULL, request, result_str); - xlat_debug_log_expansion(request, *in, result); - if (slen < 0) { - talloc_free(value); - talloc_free(result_str); - return XLAT_ACTION_FAIL; - } - if (slen == 0) { /* Zero length result */ - talloc_free(result_str); - talloc_free(value); - break; - } - (void)talloc_get_type_abort(str, char); /* Check output buffer is sane */ + VALUE_BOX_TALLOC_LIST_VERIFY(result); - /* - * Shrink the buffer - */ - if (node->call.func->buf_len > 0) { - if (slen > 0) fr_value_box_bstr_realloc(value, &str, value, slen); - } else { - fr_value_box_bstrdup_buffer_shallow(NULL, value, NULL, str, false); - } + /* + * Always need to init and free the + * copy list as debug level could change + * when the xlat function executes. + */ + fr_value_box_list_init(&result_copy); - VALUE_BOX_VERIFY(value); - fr_dcursor_append(out, value); /* Append the result of the expansion */ - talloc_free(result_str); - xlat_debug_log_result(request, value); + /* + * Need to copy the input list in case + * the async function mucks with it. + */ + if (RDEBUG_ENABLED2) fr_value_box_list_acopy(NULL, &result_copy, result); + xa = xlat_process_args(ctx, result, request, node->call.func->input_type, node->call.func->args); + if (xa == XLAT_ACTION_FAIL) { + fr_dlist_talloc_free(&result_copy); + return xa; } - break; - - case XLAT_FUNC_NORMAL: - { - xlat_action_t xa; - xlat_thread_inst_t *t; - fr_value_box_list_t result_copy; - - t = xlat_thread_instance_find(node); - fr_assert(t); - - XLAT_DEBUG("** [%i] %s(func-async) - %%%c%s:%pM%c", - unlang_interpret_stack_depth(request), __FUNCTION__, - (node->call.func->input_type == XLAT_INPUT_ARGS) ? '(' : '{', - node->fmt, result, - (node->call.func->input_type == XLAT_INPUT_ARGS) ? ')' : '}'); - - VALUE_BOX_TALLOC_LIST_VERIFY(result); - - /* - * Always need to init and free the - * copy list as debug level could change - * when the xlat function executes. - */ - fr_value_box_list_init(&result_copy); - - /* - * Need to copy the input list in case - * the async function mucks with it. - */ - if (RDEBUG_ENABLED2) fr_value_box_list_acopy(NULL, &result_copy, result); - xa = xlat_process_args(ctx, result, request, node->call.func->input_type, node->call.func->args); - if (xa == XLAT_ACTION_FAIL) { - fr_dlist_talloc_free(&result_copy); - return xa; - } - VALUE_BOX_TALLOC_LIST_VERIFY(result); + VALUE_BOX_TALLOC_LIST_VERIFY(result); - xa = node->call.func->func.async(ctx, out, - XLAT_CTX(node->call.inst->data, t->data, t->mctx, NULL), - request, result); - VALUE_BOX_TALLOC_LIST_VERIFY(result); + xa = node->call.func->func(ctx, out, + XLAT_CTX(node->call.inst->data, t->data, t->mctx, NULL), + request, result); + VALUE_BOX_TALLOC_LIST_VERIFY(result); - if (RDEBUG_ENABLED2) xlat_debug_log_expansion(request, *in, &result_copy); - fr_dlist_talloc_free(&result_copy); + if (RDEBUG_ENABLED2) xlat_debug_log_expansion(request, *in, &result_copy); + fr_dlist_talloc_free(&result_copy); - switch (xa) { - case XLAT_ACTION_FAIL: - return xa; + switch (xa) { + case XLAT_ACTION_FAIL: + return xa; - case XLAT_ACTION_PUSH_CHILD: - RDEBUG3(" -- CHILD"); - return xa; + case XLAT_ACTION_PUSH_CHILD: + RDEBUG3(" -- CHILD"); + return xa; - case XLAT_ACTION_PUSH_UNLANG: - RDEBUG3(" -- UNLANG"); - return xa; + case XLAT_ACTION_PUSH_UNLANG: + RDEBUG3(" -- UNLANG"); + return xa; - case XLAT_ACTION_YIELD: - RDEBUG3(" -- YIELD"); - return xa; + case XLAT_ACTION_YIELD: + RDEBUG3(" -- YIELD"); + return xa; - case XLAT_ACTION_DONE: /* Process the result */ - fr_dcursor_next(out); - xlat_debug_log_result(request, fr_dcursor_current(out)); - break; - } + case XLAT_ACTION_DONE: /* Process the result */ + fr_dcursor_next(out); + xlat_debug_log_result(request, fr_dcursor_current(out)); break; } - } + } break; case XLAT_ALTERNATE: @@ -1311,30 +1252,13 @@ xlat_action_t xlat_frame_eval(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_exp_t con case XLAT_VIRTUAL: { - char *str = NULL; - ssize_t slen; - XLAT_DEBUG("** [%i] %s(virtual) - %%{%s}", unlang_interpret_stack_depth(request), __FUNCTION__, node->fmt); xlat_debug_log_expansion(request, node, NULL); - if (node->call.func->type == XLAT_FUNC_NORMAL) { - node->call.func->func.async(ctx, out, - XLAT_CTX(node->call.func->uctx, NULL, NULL, NULL), - request, NULL); - } else { - MEM(value = fr_value_box_alloc_null(ctx)); - slen = node->call.func->func.sync(value, &str, node->call.func->buf_len, node->call.func->mod_inst, - NULL, request, NULL); - if (slen < 0) { - talloc_free(value); - goto fail; - } - if (slen == 0) continue; - - fr_value_box_bstrdup_buffer_shallow(NULL, value, NULL, str, false); - fr_dcursor_append(out, value); - } + xa = node->call.func->func(ctx, out, + XLAT_CTX(node->call.func->uctx, NULL, NULL, NULL), + request, NULL); fr_dcursor_next(out); xlat_debug_log_result(request, fr_dcursor_current(out)); @@ -1437,8 +1361,7 @@ static char *xlat_sync_eval(TALLOC_CTX *ctx, request_t *request, xlat_exp_t cons int lvl) { ssize_t slen; - char *str = NULL, *child; - char const *p; + char *str = NULL; fr_value_box_t string, *value; fr_value_box_list_t head; fr_dcursor_t cursor; @@ -1523,171 +1446,83 @@ static char *xlat_sync_eval(TALLOC_CTX *ctx, request_t *request, xlat_exp_t cons break; case XLAT_VIRTUAL: - XLAT_DEBUG("xlat_sync_eval VIRTUAL"); - + { /* * Temporary hack to use the new API */ - if (node->call.func->type == XLAT_FUNC_NORMAL) { - fr_value_box_list_t result; - xlat_action_t action; - fr_dcursor_t out; - TALLOC_CTX *pool = talloc_new(NULL); - - fr_value_box_list_init (&result); - fr_dcursor_init(&out, &result); - - action = node->call.func->func.async(ctx, &out, - XLAT_CTX(node->call.func->uctx, NULL, NULL, NULL), - request, NULL); - if (action == XLAT_ACTION_FAIL) { + fr_value_box_list_t result; + xlat_action_t action; + fr_dcursor_t out; + TALLOC_CTX *pool = talloc_new(NULL); + + XLAT_DEBUG("xlat_sync_eval VIRTUAL"); + + fr_value_box_list_init (&result); + fr_dcursor_init(&out, &result); + + action = node->call.func->func(ctx, &out, + XLAT_CTX(node->call.func->uctx, NULL, NULL, NULL), + request, NULL); + if (action == XLAT_ACTION_FAIL) { + talloc_free(pool); + return NULL; + } + if (!fr_dlist_empty(&result)) { + str = fr_value_box_list_aprint(ctx, &result, NULL, &fr_value_escape_double); + if (!str) { + RPEDEBUG("Failed concatenating xlat result string"); talloc_free(pool); return NULL; } - if (!fr_dlist_empty(&result)) { - str = fr_value_box_list_aprint(ctx, &result, NULL, &fr_value_escape_double); - if (!str) { - RPEDEBUG("Failed concatenating xlat result string"); - talloc_free(pool); - return NULL; - } - } else { - str = talloc_strdup(ctx, ""); - } - talloc_free(pool); /* Memory should be in new ctx */ - break; - } - - if (node->call.func->buf_len > 0) { - str = talloc_array(ctx, char, node->call.func->buf_len); - str[0] = '\0'; /* Be sure the string is \0 terminated */ - } - slen = node->call.func->func.sync(ctx, &str, node->call.func->buf_len, node->call.func->mod_inst, NULL, request, NULL); - if (slen < 0) { - talloc_free(str); - return NULL; + } else { + str = talloc_strdup(ctx, ""); } + talloc_free(pool); /* Memory should be in new ctx */ + } break; case XLAT_FUNC: + { + fr_value_box_list_t result; + TALLOC_CTX *pool = talloc_new(NULL); + XLAT_DEBUG("xlat_sync_eval MODULE"); + fr_value_box_list_init(&result); /* - * Temporary hack to use the new API. - * - * Will not handle yields. + * Use the unlang stack to evaluate + * the async xlat up until the point + * that it needs to yield. */ - if (node->call.func->type == XLAT_FUNC_NORMAL) { - fr_value_box_list_t result; - TALLOC_CTX *pool = talloc_new(NULL); - fr_value_box_list_init(&result); - /* - * Use the unlang stack to evaluate - * the async xlat up until the point - * that it needs to yield. - */ - if (unlang_xlat_push(pool, NULL, &result, request, node, true) < 0) { - talloc_free(pool); - return NULL; - } - - switch (unlang_interpret_synchronous(unlang_interpret_event_list(request), request)) { - default: - break; - - case RLM_MODULE_REJECT: - case RLM_MODULE_FAIL: - RPEDEBUG("xlat evaluation failed"); - talloc_free(pool); - return NULL; - } + if (unlang_xlat_push(pool, NULL, &result, request, node, true) < 0) { + talloc_free(pool); + return NULL; + } - if (!fr_dlist_empty(&result)) { - str = fr_value_box_list_aprint(ctx, &result, NULL, &fr_value_escape_double); - if (!str) { - RPEDEBUG("Failed concatenating xlat result string"); - talloc_free(pool); - return NULL; - } - } else { - str = talloc_strdup(ctx, ""); - } - talloc_free(pool); /* Memory should be in new ctx */ - return str; - } else if (node->child) { - if (xlat_process(ctx, &child, request, - node->child, node->call.func->escape, node->call.func->mod_inst) == 0) { - return NULL; - } + switch (unlang_interpret_synchronous(unlang_interpret_event_list(request), request)) { + default: + break; - XLAT_DEBUG("%.*sEXPAND mod %s %s", lvl, xlat_spaces, node->fmt, node->child->fmt); - } else { - XLAT_DEBUG("%.*sEXPAND mod %s", lvl, xlat_spaces, node->fmt); - child = talloc_typed_strdup(ctx, ""); + case RLM_MODULE_REJECT: + case RLM_MODULE_FAIL: + RPEDEBUG("xlat evaluation failed"); + talloc_free(pool); + return NULL; } - XLAT_DEBUG("%.*s ---> %s", lvl, xlat_spaces, child); - - /* - * Smash \n --> CR. - * - * The OUTPUT of xlat is a "raw" string. The INPUT is a printable string. - * - * This is really the reverse of fr_snprint(). - */ - if (*child) { - fr_type_t type; - fr_value_box_t data; - - type = FR_TYPE_STRING; - if (fr_value_box_from_str(ctx, &data, type, NULL, - child, talloc_array_length(child) - 1, - &fr_value_unescape_double, false) < 0) { - talloc_free(child); + if (!fr_dlist_empty(&result)) { + str = fr_value_box_list_aprint(ctx, &result, NULL, &fr_value_escape_double); + if (!str) { + RPEDEBUG("Failed concatenating xlat result string"); + talloc_free(pool); return NULL; } - - talloc_free(child); - child = data.datum.ptr; - } else { - char *q; - - p = q = child; - while (*p) { - if (*p == '\\') switch (p[1]) { - default: - *(q++) = p[1]; - p += 2; - continue; - - case 'n': - *(q++) = '\n'; - p += 2; - continue; - - case 't': - *(q++) = '\t'; - p += 2; - continue; - } - - *(q++) = *(p++); - } - *q = '\0'; - } - - if (node->call.func->buf_len > 0) { - str = talloc_array(ctx, char, node->call.func->buf_len); - str[0] = '\0'; /* Be sure the string is \0 terminated */ + str = talloc_strdup(ctx, ""); } - slen = node->call.func->func.sync(ctx, &str, node->call.func->buf_len, node->call.func->mod_inst, NULL, request, child); - talloc_free(child); - if (slen < 0) { - talloc_free(str); - return NULL; - } - break; + talloc_free(pool); /* Memory should be in new ctx */ + } + return str; #ifdef HAVE_REGEX case XLAT_REGEX: @@ -1811,7 +1646,7 @@ static ssize_t xlat_process(TALLOC_CTX *ctx, char **out, request_t *request, xla * Break here to avoid nodes being evaluated multiple times * and parts of strings being duplicated. */ - if ((node->type == XLAT_FUNC) && (node->call.func->type == XLAT_FUNC_NORMAL)) { + if (node->type == XLAT_FUNC) { i++; break; } diff --git a/src/lib/unlang/xlat_priv.h b/src/lib/unlang/xlat_priv.h index 67349e3bcbf..621a16f8511 100644 --- a/src/lib/unlang/xlat_priv.h +++ b/src/lib/unlang/xlat_priv.h @@ -36,24 +36,10 @@ extern "C" { # define XLAT_DEBUG(...) #endif -/** Function types - * - */ -typedef enum { - XLAT_FUNC_LEGACY, //!< Ingests and excretes strings. - XLAT_FUNC_NORMAL //!< Ingests and excretes value boxes (and may yield) -} xlat_func_legacy_type_t; - typedef struct xlat_s { fr_rb_node_t node; //!< Entry in the xlat function tree. char const *name; //!< Name of xlat function. - - union { - xlat_func_legacy_t sync; //!< synchronous xlat function (async safe). - xlat_func_t async; //!< async xlat function (async unsafe). - } func; - xlat_func_legacy_type_t type; //!< Type of xlat function. - + xlat_func_t func; //!< async xlat function (async unsafe). bool internal; //!< If true, cannot be redefined. module_inst_ctx_t const *mctx; //!< Original module instantiation ctx if this @@ -74,9 +60,7 @@ typedef struct xlat_s { xlat_flags_t flags; //!< various flags - size_t buf_len; //!< Length of output buffer to pre-allocate. void *mod_inst; //!< Module instance passed to xlat - xlat_escape_legacy_t escape; //!< Escape function to apply to dynamic input to func. xlat_input_type_t input_type; //!< Type of input used. xlat_arg_parser_t const *args; //!< Definition of args consumed. } xlat_t;