From: Alan T. DeKok Date: Mon, 14 Nov 2022 15:34:04 +0000 (-0500) Subject: allow tmpls as arguments for timeout X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=93af43cff4311fb3ecff8f4bc37d6ecc45bc5292;p=thirdparty%2Ffreeradius-server.git allow tmpls as arguments for timeout --- diff --git a/src/lib/unlang/compile.c b/src/lib/unlang/compile.c index ab314ecabfd..246d29a88a7 100644 --- a/src/lib/unlang/compile.c +++ b/src/lib/unlang/compile.c @@ -2741,6 +2741,8 @@ static unlang_t *compile_timeout(unlang_t *parent, unlang_compile_t *unlang_ctx, unlang_group_t *g; unlang_timeout_t *gext; fr_time_delta_t timeout; + tmpl_t *vpt = NULL; + fr_token_t token; static unlang_ext_t const timeout_ext = { .type = UNLANG_TYPE_TIMEOUT, @@ -2764,11 +2766,74 @@ static unlang_t *compile_timeout(unlang_t *parent, unlang_compile_t *unlang_ctx, gext = unlang_group_to_timeout(g); - if (fr_time_delta_from_str(&timeout, name2, strlen(name2), FR_TIME_RES_SEC) < 0) { - cf_log_err(cs, "Failed parsing time delta %s - %s", - name2, fr_strerror()); - return NULL; + token = cf_section_name2_quote(cs); + + if ((token == T_BARE_WORD) && isdigit((int) *name2)) { + if (fr_time_delta_from_str(&timeout, name2, strlen(name2), FR_TIME_RES_SEC) < 0) { + cf_log_err(cs, "Failed parsing time delta %s - %s", + name2, fr_strerror()); + return NULL; + } + } else { + ssize_t slen; + tmpl_rules_t t_rules; + + /* + * We don't allow unknown attributes here. + */ + t_rules = *(unlang_ctx->rules); + t_rules.attr.allow_unknown = false; + RULES_VERIFY(&t_rules); + + slen = tmpl_afrom_substr(gext, &vpt, + &FR_SBUFF_IN(name2, strlen(name2)), + token, + NULL, + &t_rules); + if (!vpt) { + char *spaces, *text; + + fr_canonicalize_error(cs, &spaces, &text, slen, fr_strerror()); + + cf_log_err(cs, "Syntax error"); + cf_log_err(cs, "%s", name2); + cf_log_err(cs, "%s^ %s", spaces, text); + + talloc_free(g); + talloc_free(spaces); + talloc_free(text); + + return NULL; + } + + /* + * Fixup the tmpl so that we know it's somewhat sane. + */ + if (!pass2_fixup_tmpl(gext, &vpt, cf_section_to_item(cs), unlang_ctx->rules->attr.dict_def)) { + error: + talloc_free(g); + return NULL; + } + + if (tmpl_is_list(vpt)) { + cf_log_err(cs, "Cannot use list as argument for 'timeout' statement"); + goto error; + } + + if (tmpl_contains_regex(vpt)) { + cf_log_err(cs, "Cannot use regular expression as argument for 'timeout' statement"); + goto error; + } + + /* + * Attribute or data MUST be cast to TIME_DELTA. + */ + if (tmpl_cast_set(vpt, FR_TYPE_TIME_DELTA) < 0) { + cf_log_perr(cs, "Failed setting cast type"); + goto error; + } } + /* * Compile the contents of a "timeout". */ @@ -2778,6 +2843,7 @@ static unlang_t *compile_timeout(unlang_t *parent, unlang_compile_t *unlang_ctx, g = unlang_generic_to_group(c); gext = unlang_group_to_timeout(g); gext->timeout = timeout; + gext->vpt = vpt; return c; } diff --git a/src/lib/unlang/timeout.c b/src/lib/unlang/timeout.c index ac67167c165..65995c6468e 100644 --- a/src/lib/unlang/timeout.c +++ b/src/lib/unlang/timeout.c @@ -30,9 +30,12 @@ RCSID("$Id$") typedef struct { bool success; int depth; + fr_time_delta_t timeout; request_t *request; rindent_t indent; fr_event_timer_t const *ev; + + fr_value_box_list_t result; } unlang_frame_state_timeout_t; static void unlang_timeout_handler(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, void *ctx) @@ -69,27 +72,18 @@ static unlang_action_t unlang_timeout_resume_done(UNUSED rlm_rcode_t *p_result, return UNLANG_ACTION_CALCULATE_RESULT; } - -static unlang_action_t unlang_timeout(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame) +static unlang_action_t unlang_timeout_set(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame) { - unlang_group_t *g; - unlang_timeout_t *gext; unlang_frame_state_timeout_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_timeout_t); - fr_time_t timeout; - unlang_stack_t *stack = request->stack; - - g = unlang_generic_to_group(frame->instruction); - gext = unlang_group_to_timeout(g); - - state->depth = stack->depth; - state->request = request; + unlang_group_t *g; + fr_time_t timeout; /* * Save current indentation for the error path. */ RINDENT_SAVE(&state->indent, request); - timeout = fr_time_add(fr_time(), gext->timeout); + timeout = fr_time_add(fr_time(), state->timeout); if (fr_event_timer_at(state, unlang_interpret_event_list(request), &state->ev, timeout, unlang_timeout_handler, state) < 0) { @@ -97,6 +91,8 @@ static unlang_action_t unlang_timeout(rlm_rcode_t *p_result, request_t *request, goto fail; } + g = unlang_generic_to_group(frame->instruction); + if (unlang_interpret_push(request, g->children, frame->result, UNLANG_NEXT_STOP, UNLANG_SUB_FRAME) < 0) { fail: *p_result = RLM_MODULE_FAIL; @@ -109,6 +105,46 @@ static unlang_action_t unlang_timeout(rlm_rcode_t *p_result, request_t *request, return UNLANG_ACTION_PUSHED_CHILD; } +static unlang_action_t unlang_timeout_xlat_done(UNUSED rlm_rcode_t *p_result, UNUSED request_t *request, unlang_stack_frame_t *frame) +{ + unlang_frame_state_timeout_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_timeout_t); + fr_value_box_t *box = fr_dlist_head(&state->result); + + /* + * compile_timeout() ensures that the tmpl is cast to time_delta, so we don't have to do any more work here. + */ + state->timeout = box->vb_time_delta; + + return unlang_timeout_set(p_result, request, frame); +} + +static unlang_action_t unlang_timeout(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame) +{ + unlang_group_t *g; + unlang_timeout_t *gext; + unlang_frame_state_timeout_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_timeout_t); + unlang_stack_t *stack = request->stack; + + g = unlang_generic_to_group(frame->instruction); + gext = unlang_group_to_timeout(g); + + state->depth = stack->depth; + state->request = request; + + if (!gext->vpt) { + state->timeout = gext->timeout; + return unlang_timeout_set(p_result, request, frame); + } + + fr_value_box_list_init(&state->result); + + if (unlang_tmpl_push(state, &state->result, request, gext->vpt, NULL) < 0) return UNLANG_ACTION_FAIL; + + frame_repeat(frame, unlang_timeout_xlat_done); + + return UNLANG_ACTION_PUSHED_CHILD; +} + void unlang_timeout_init(void) { diff --git a/src/lib/unlang/timeout_priv.h b/src/lib/unlang/timeout_priv.h index 7c953e06e9a..1a741d1c302 100644 --- a/src/lib/unlang/timeout_priv.h +++ b/src/lib/unlang/timeout_priv.h @@ -30,6 +30,7 @@ extern "C" { typedef struct { unlang_group_t group; + tmpl_t *vpt; fr_time_delta_t timeout; } unlang_timeout_t; diff --git a/src/tests/keywords/timeout b/src/tests/keywords/timeout index 5582388900e..278860f1490 100644 --- a/src/tests/keywords/timeout +++ b/src/tests/keywords/timeout @@ -8,6 +8,18 @@ redundant { timeout 0.01s { &Tmp-Float-0 := "%(delay_10s:0.1)" + test_fail + } + + group { + success + } +} + +redundant { + timeout "0.01" { + &Tmp-Float-0 := "%(delay_10s:0.1)" + test_fail } group {