]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
allow tmpls as arguments for timeout
authorAlan T. DeKok <aland@freeradius.org>
Mon, 14 Nov 2022 15:34:04 +0000 (10:34 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Mon, 14 Nov 2022 20:01:05 +0000 (15:01 -0500)
src/lib/unlang/compile.c
src/lib/unlang/timeout.c
src/lib/unlang/timeout_priv.h
src/tests/keywords/timeout

index ab314ecabfd57feed7aa22e75e3c4d2fad390291..246d29a88a7bcf92f8fd751086bf9883b7c39c24 100644 (file)
@@ -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;
 }
index ac67167c165385ae56697222a3678c0702cd105f..65995c6468ef060519fe18f650dc414b370006e3 100644 (file)
@@ -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)
 {
index 7c953e06e9ae95814f9d1185233df124ac42786d..1a741d1c302e023c56a0625c7ff63e91d3e8bba2 100644 (file)
@@ -30,6 +30,7 @@ extern "C" {
 
 typedef struct {
        unlang_group_t  group;
+       tmpl_t          *vpt;
        fr_time_delta_t timeout;
 } unlang_timeout_t;
 
index 5582388900e05548ec7034ffef4ffd03bf75ca9c..278860f1490b0864bf78f32efbef6cd8e9dd07e9 100644 (file)
@@ -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 {