From de070ecae97f4b6e656890e76e2db7b5d0c8eafa Mon Sep 17 00:00:00 2001 From: "Alan T. DeKok" Date: Tue, 1 Jul 2025 12:55:17 -0400 Subject: [PATCH] allow xlats in triggers, and update tests to match --- src/lib/server/trigger.c | 61 +++++++++++-------- src/lib/unlang/xlat.c | 40 ++++++++++++ src/lib/unlang/xlat.h | 4 ++ .../active_directory/config/radiusd.conf | 2 +- .../persistent_search/config/radiusd.conf | 2 +- .../ldap_sync/rfc4533/config/radiusd.conf | 2 +- 6 files changed, 83 insertions(+), 28 deletions(-) diff --git a/src/lib/server/trigger.c b/src/lib/server/trigger.c index badb1811b5..6f70c88605 100644 --- a/src/lib/server/trigger.c +++ b/src/lib/server/trigger.c @@ -135,6 +135,8 @@ typedef struct { char *command; //!< Name of the trigger. xlat_exp_head_t *xlat; //!< xlat representation of the trigger args. fr_value_box_list_t args; //!< Arguments to pass to the trigger exec. + fr_value_box_list_t out; //!< result of the xlap (which we ignore) + unlang_result_t result; //!< the result of expansion fr_exec_state_t exec; //!< Used for asynchronous execution. fr_time_delta_t timeout; //!< How long the trigger has to run. @@ -370,31 +372,38 @@ int trigger_exec(unlang_interpret_t *intp, MEM(trigger = talloc_zero(request, fr_trigger_t)); fr_value_box_list_init(&trigger->args); + fr_value_box_list_init(&trigger->out); trigger->command = talloc_strdup(trigger, value); trigger->timeout = fr_time_delta_from_sec(5); /* @todo - Should be configurable? */ - slen = xlat_tokenize_argv(trigger, &trigger->xlat, - &FR_SBUFF_IN(trigger->command, talloc_array_length(trigger->command) - 1), - NULL, NULL, &(tmpl_rules_t) { + if (value[0] != '/') { + slen = unlang_xlat_push_string(trigger, &trigger->result, &trigger->out, request, value); + if (slen < 0) goto parse_error; /* can't be zero! */ + } else { + slen = xlat_tokenize_argv(trigger, &trigger->xlat, + &FR_SBUFF_IN(trigger->command, talloc_array_length(trigger->command) - 1), + NULL, NULL, &(tmpl_rules_t) { .attr = { .dict_def = request->local_dict, .list_def = request_attr_request, .allow_unresolved = false, }, - }, true); - if (slen <= 0) { - char *spaces, *text; + }, true); + if (slen <= 0) { + char *spaces, *text; - fr_canonicalize_error(trigger, &spaces, &text, slen, trigger->command); + parse_error: + fr_canonicalize_error(trigger, &spaces, &text, slen, trigger->command); - cf_log_err(cp, "Failed parsing trigger command"); - cf_log_err(cp, "%s", text); - cf_log_perr(cp, "%s^", spaces); + cf_log_err(cp, "Failed parsing trigger command"); + cf_log_err(cp, "%s", text); + cf_log_perr(cp, "%s^", spaces); - talloc_free(request); - talloc_free(spaces); - talloc_free(text); - return -1; + talloc_free(request); + talloc_free(spaces); + talloc_free(text); + return -1; + } } /* @@ -411,18 +420,20 @@ int trigger_exec(unlang_interpret_t *intp, } } - if (xlat_finalize(trigger->xlat, intp ? unlang_interpret_event_list(request) : main_loop_event_list()) < 0) { - fr_strerror_const("Failed performing ephemeral instantiation for xlat"); - talloc_free(request); - return -1; - } + if (trigger->xlat) { + if (xlat_finalize(trigger->xlat, intp ? unlang_interpret_event_list(request) : main_loop_event_list()) < 0) { + fr_strerror_const("Failed performing ephemeral instantiation for xlat"); + talloc_free(request); + return -1; + } - if (unlang_function_push(request, - trigger_run, - trigger_resume, - NULL, 0, - UNLANG_TOP_FRAME, - trigger) < 0) goto error; + if (unlang_function_push(request, + trigger_run, + trigger_resume, + NULL, 0, + UNLANG_TOP_FRAME, + trigger) < 0) goto error; + } if (!intp) { /* diff --git a/src/lib/unlang/xlat.c b/src/lib/unlang/xlat.c index a90773df51..e71db732f9 100644 --- a/src/lib/unlang/xlat.c +++ b/src/lib/unlang/xlat.c @@ -305,6 +305,46 @@ int unlang_xlat_push_node(TALLOC_CTX *ctx, unlang_result_t *p_result, fr_value_b return unlang_xlat_push_internal(ctx, p_result, out, request, NULL, node, UNLANG_TOP_FRAME); } +/** Tokenize a string,and push the resulting xlat onto the stack for evaluation + * + * @param[in] ctx To allocate value boxes and values in. + * @param[out] p_result If set, and execution succeeds, true will be written + * here. If execution fails, false will be written. + * @param[out] out Where to write the result of the expansion. + * @param[in] request to push xlat onto. + * @param[in] string to tokenize and evaluate. + * @return + * - 0 on success. + * - -1 on failure. + */ +int unlang_xlat_push_string(TALLOC_CTX *ctx, unlang_result_t *p_result, fr_value_box_list_t *out, + request_t *request, char const *string) +{ + fr_slen_t slen; + xlat_exp_head_t *xlat; + fr_event_list_t *el; + + el = unlang_interpret_event_list(request); + if (!el) el = main_loop_event_list(); + + slen = xlat_tokenize(ctx, &xlat, &FR_SBUFF_IN(string, strlen(string)), NULL, + &(tmpl_rules_t) { + .attr = { + .dict_def = request->local_dict, /* we can use local attributes */ + .list_def = request_attr_request, + }, + .xlat = { + .runtime_el = el, + }, + .at_runtime = true, + }); + if (slen <= 0) { + return slen; + } + + return unlang_xlat_push_internal(ctx, p_result, out, request, xlat, xlat_exp_head(xlat), UNLANG_TOP_FRAME); +} + static unlang_action_t unlang_xlat_repeat(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame) { unlang_frame_state_xlat_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_xlat_t); diff --git a/src/lib/unlang/xlat.h b/src/lib/unlang/xlat.h index 2c9c45e392..15a882b6df 100644 --- a/src/lib/unlang/xlat.h +++ b/src/lib/unlang/xlat.h @@ -506,6 +506,10 @@ int unlang_xlat_push(TALLOC_CTX *ctx, unlang_result_t *p_result, fr_value_box_l request_t *request, xlat_exp_head_t const *head, bool top_frame) CC_HINT(warn_unused_result); +int unlang_xlat_push_string(TALLOC_CTX *ctx, unlang_result_t *p_result, fr_value_box_list_t *out, + request_t *request, char const *string) + CC_HINT(warn_unused_result); + int unlang_xlat_eval(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *request, xlat_exp_head_t const *head) CC_HINT(warn_unused_result); diff --git a/src/tests/ldap_sync/active_directory/config/radiusd.conf b/src/tests/ldap_sync/active_directory/config/radiusd.conf index b42d7b0a75..d37a3c4c83 100644 --- a/src/tests/ldap_sync/active_directory/config/radiusd.conf +++ b/src/tests/ldap_sync/active_directory/config/radiusd.conf @@ -126,7 +126,7 @@ server test { } trigger { - start = "/usr/bin/touch ${run_dir}/sync_started" + start = %file.touch("${run_dir}/sync_started") } } diff --git a/src/tests/ldap_sync/persistent_search/config/radiusd.conf b/src/tests/ldap_sync/persistent_search/config/radiusd.conf index 7a419da29a..615fd0a524 100644 --- a/src/tests/ldap_sync/persistent_search/config/radiusd.conf +++ b/src/tests/ldap_sync/persistent_search/config/radiusd.conf @@ -145,7 +145,7 @@ server test { } trigger { - start = "/usr/bin/touch ${run_dir}/sync_started" + start = %file.touch("${run_dir}/sync_started") } } diff --git a/src/tests/ldap_sync/rfc4533/config/radiusd.conf b/src/tests/ldap_sync/rfc4533/config/radiusd.conf index c321cb2951..7a4268e60a 100644 --- a/src/tests/ldap_sync/rfc4533/config/radiusd.conf +++ b/src/tests/ldap_sync/rfc4533/config/radiusd.conf @@ -176,7 +176,7 @@ server test { } trigger { - start = "/usr/bin/touch ${run_dir}/sync_started" + start = %file.touch("${run_dir}/sync_started") } } -- 2.47.3