From: Arran Cudbard-Bell Date: Sun, 4 Apr 2021 19:20:24 +0000 (+0100) Subject: Rework xlat code to produce FR_TYPE_NULL boxes X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=64eb93aea2ad6328db39ef92b88ae2fe3fc0ba29;p=thirdparty%2Ffreeradius-server.git Rework xlat code to produce FR_TYPE_NULL boxes --- diff --git a/src/lib/unlang/xlat_builtin.c b/src/lib/unlang/xlat_builtin.c index de1f55d1e3..3e9a3f1a8a 100644 --- a/src/lib/unlang/xlat_builtin.c +++ b/src/lib/unlang/xlat_builtin.c @@ -801,8 +801,7 @@ static xlat_action_t xlat_func_debug(TALLOC_CTX *ctx, fr_dcursor_t *out, /* * Assume we just want to get the current value and NOT set it to 0 */ - if (!in_head) - goto done; + if (in_head->type == FR_TYPE_NULL) goto done; level = in_head->vb_int8; if (level == 0) { @@ -1403,7 +1402,7 @@ static xlat_action_t xlat_func_lpad(UNUSED TALLOC_CTX *ctx, fr_dcursor_t *out, /* * Fill is optional */ - if (fill) { + if (fill->type != FR_TYPE_NULL) { fill_str = fill->vb_strvalue; fill_len = talloc_array_length(fill_str) - 1; } @@ -1485,7 +1484,7 @@ static xlat_action_t xlat_func_rpad(UNUSED TALLOC_CTX *ctx, fr_dcursor_t *out, /* * Fill is optional */ - if (fill) { + if (fill->type != FR_TYPE_NULL) { fill_str = fill->vb_strvalue; fill_len = talloc_array_length(fill_str) - 1; } diff --git a/src/lib/unlang/xlat_eval.c b/src/lib/unlang/xlat_eval.c index fd099ab761..7aa23cdc0d 100644 --- a/src/lib/unlang/xlat_eval.c +++ b/src/lib/unlang/xlat_eval.c @@ -402,6 +402,12 @@ xlat_action_t xlat_process_args(TALLOC_CTX *ctx, fr_value_box_list_t *list, requ REDEBUG("Missing required argument %u", (unsigned int)((arg_p - args) + 1)); return XLAT_ACTION_FAIL; } + + /* + * Add a placeholder 'null' box + */ + MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_NULL, NULL, false)); + fr_dlist_insert_tail(list, vb); return XLAT_ACTION_DONE; } @@ -425,8 +431,20 @@ xlat_action_t xlat_process_args(TALLOC_CTX *ctx, fr_value_box_list_t *list, requ * argument with the head of the group. */ if (arg_p->single || arg_p->concat) { - fr_dlist_replace(list, vb, fr_dlist_pop_head(&vb->vb_group)); - talloc_free(vb); + /* + * If the group is empty, convert + * it to a null box to maintain + * correct ordering in the argument + * list. + */ + if (fr_dlist_empty(&vb->vb_group)) { + fr_value_box_t *prev = fr_dlist_remove(list, vb); + fr_value_box_init_null(vb); + fr_dlist_insert_after(list, prev, vb); + } else { + fr_dlist_replace(list, vb, fr_dlist_pop_head(&vb->vb_group)); + talloc_free(vb); + } } if (arg_p->variadic) { @@ -1366,6 +1384,7 @@ xlat_action_t xlat_frame_eval(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_exp_t con case XLAT_GROUP: XLAT_DEBUG("** [%i] %s(child) - %%{%s ...}", unlang_interpret_stack_depth(request), __FUNCTION__, node->fmt); + if (!node->child) return XLAT_ACTION_DONE; /* * Hand back the child node to the caller diff --git a/src/lib/unlang/xlat_tokenize.c b/src/lib/unlang/xlat_tokenize.c index 9237238164..ebc510c34a 100644 --- a/src/lib/unlang/xlat_tokenize.c +++ b/src/lib/unlang/xlat_tokenize.c @@ -1022,35 +1022,11 @@ static int xlat_tokenize_literal(TALLOC_CTX *ctx, xlat_exp_t **head, xlat_flags_ goto error; } /* - * We're parsing the string *containing* the xlat - * expansions. + * Empty input, emit no arguments */ - } else { - /* If we have an empty node, finish building it and - * emit it. - * - * We're about to return, and it's a useful - * indication to the caller that this wasn't a parse - * error but just an empty string. - */ - if (len == 0) { - /* - * This isn't the only node in the sequence - * don't emit an empty trailing literal. - */ - if (*head) { - talloc_free(node); - break; - } - - xlat_exp_set_type(node, XLAT_LITERAL); - xlat_exp_set_name_buffer_shallow(node, str); - - XLAT_DEBUG("LITERAL <-- (empty)"); - node->flags.needs_async = false; /* literals are always true */ - xlat_flags_merge(flags, &node->flags); - fr_cursor_insert(&cursor, node); - } + } else if (len == 0) { + talloc_free(node); + XLAT_DEBUG("LITERAL <-- (empty)"); } break; } @@ -1303,13 +1279,16 @@ ssize_t xlat_tokenize_ephemeral(TALLOC_CTX *ctx, xlat_exp_t **head, xlat_flags_t *head = NULL; fr_strerror_clear(); /* Clear error buffer */ - if (xlat_tokenize_literal(ctx, head, flags, - &our_in, false, p_rules, t_rules) < 0) return -fr_sbuff_used(&our_in); + if (xlat_tokenize_literal(ctx, head, flags, &our_in, + false, p_rules, t_rules) < 0) return -fr_sbuff_used(&our_in); /* * Zero length expansion, return a zero length node. */ - if (fr_sbuff_used(&our_in) == 0) *head = xlat_exp_alloc(ctx, XLAT_LITERAL, "", 0); + if (!*head) { + *head = xlat_exp_alloc(ctx, XLAT_LITERAL, "", 0); + return 0; + } /* * Create ephemeral instance data for the xlat @@ -1522,8 +1501,16 @@ ssize_t xlat_tokenize(TALLOC_CTX *ctx, xlat_exp_t **head, xlat_flags_t *flags, f fr_strerror_clear(); /* Clear error buffer */ - if (xlat_tokenize_literal(ctx, head, flags, - &our_in, false, p_rules, t_rules) < 0) return -fr_sbuff_used(&our_in); + if (xlat_tokenize_literal(ctx, head, flags, &our_in, + false, p_rules, t_rules) < 0) return -fr_sbuff_used(&our_in); + + /* + * Zero length expansion, return a zero length node. + */ + if (!*head) { + *head = xlat_exp_alloc(ctx, XLAT_LITERAL, "", 0); + return fr_sbuff_set(in, &our_in); + } /* * Add nodes that need to be bootstrapped to diff --git a/src/lib/util/value.c b/src/lib/util/value.c index 9c2cb0828e..303349ef11 100644 --- a/src/lib/util/value.c +++ b/src/lib/util/value.c @@ -168,7 +168,7 @@ size_t fr_value_box_type_table_len = NUM_ELEMENTS(fr_value_box_type_table); #define network_min_size(_x) (fr_value_box_network_sizes[_x][0]) #define network_max_size(_x) (fr_value_box_network_sizes[_x][1]) static size_t const fr_value_box_network_sizes[FR_TYPE_MAX + 1][2] = { - [FR_TYPE_NULL] = {~0, 0}, + [FR_TYPE_NULL] = {~0, 0}, [FR_TYPE_STRING] = {0, ~0}, [FR_TYPE_OCTETS] = {0, ~0}, diff --git a/src/modules/rlm_client/rlm_client.c b/src/modules/rlm_client/rlm_client.c index dd040b1c43..8649a069b3 100644 --- a/src/modules/rlm_client/rlm_client.c +++ b/src/modules/rlm_client/rlm_client.c @@ -234,7 +234,7 @@ static xlat_action_t xlat_client(TALLOC_CTX *ctx, fr_dcursor_t *out, request_t * fr_value_box_t *client_ip = fr_dlist_next(in, field); fr_value_box_t *vb; - if (client_ip) { + if (!fr_box_is_null(client_ip)) { if (fr_inet_pton(&ip, client_ip->vb_strvalue, -1, AF_UNSPEC, false, true) < 0) { RDEBUG("Invalid client IP address \"%s\"", client_ip->vb_strvalue); return XLAT_ACTION_FAIL; diff --git a/src/tests/keywords/debug b/src/tests/keywords/debug new file mode 100644 index 0000000000..3d5c447d8a --- /dev/null +++ b/src/tests/keywords/debug @@ -0,0 +1,34 @@ +# +# PRE: update if +# + +update request { + &Tmp-Integer-0 := "%(debug:4)" +} + +# Check debug level is now 4 +if ("%(debug:3)" != 4) { + test_fail +} + +# Call with NULL arg, should report current level +if ("%(debug:%{Tmp-String-8})" != 3) { + test_fail +} + +# ...and again +if ("%(debug:%{Tmp-String-8})" != 3) { + test_fail +} + +# ...and again +if ("%(debug:)" != 3) { + test_fail +} + +# ...and again +if ("%(debug:)" != 3) { + test_fail +} + +success