From: Alan T. DeKok Date: Thu, 6 Jul 2023 13:01:50 +0000 (-0400) Subject: Cast nothing to string/octets yields empty string/octets X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f276de145e6d585ece9a144c92a0e8eb1d2623ef;p=thirdparty%2Ffreeradius-server.git Cast nothing to string/octets yields empty string/octets Because we want the following condition to work, when there is only one of attribute Tmp-Integer-0: if ("%{Tmp-String-0[2]}" == '') { // always runs! } i.e. expanding in a string context, a reference to an attribute which doesn't exist should result in an empty string, and not a condition failure of "can't create LHS of condition" --- diff --git a/src/lib/unlang/xlat_builtin.c b/src/lib/unlang/xlat_builtin.c index 9b54e7f0a99..0e972cda769 100644 --- a/src/lib/unlang/xlat_builtin.c +++ b/src/lib/unlang/xlat_builtin.c @@ -1374,7 +1374,7 @@ finish: static xlat_arg_parser_t const xlat_func_cast_args[] = { { .required = true, .single = true, .type = FR_TYPE_VOID }, - { .required = true, .type = FR_TYPE_VOID }, + { .type = FR_TYPE_VOID }, { .variadic = XLAT_ARG_VARIADIC_EMPTY_KEEP, .type = FR_TYPE_VOID }, XLAT_ARG_PARSER_TERMINATOR }; @@ -1425,6 +1425,25 @@ static xlat_action_t xlat_func_cast(TALLOC_CTX *ctx, fr_dcursor_t *out, } } + (void) fr_value_box_list_pop_head(args); + + /* + * When we cast nothing to a string / octets, the result is an empty string/octets. + */ + if (unlikely(!fr_value_box_list_head(args))) { + if ((type == FR_TYPE_STRING) || (type == FR_TYPE_OCTETS)) { + fr_value_box_t *dst; + + MEM(dst = fr_value_box_alloc(ctx, type, NULL, false)); + fr_dcursor_append(out, dst); + + return XLAT_ACTION_DONE; + } + + RDEBUG("No data for cast to '%s'", fr_type_to_str(type)); + return XLAT_ACTION_FAIL; + } + /* * Cast to string means *print* to string. */ @@ -1432,7 +1451,6 @@ static xlat_action_t xlat_func_cast(TALLOC_CTX *ctx, fr_dcursor_t *out, fr_sbuff_t *agg; fr_value_box_t *dst; - (void) fr_value_box_list_pop_head(args); talloc_free(name); FR_SBUFF_TALLOC_THREAD_LOCAL(&agg, 256, SIZE_MAX); @@ -1453,7 +1471,7 @@ static xlat_action_t xlat_func_cast(TALLOC_CTX *ctx, fr_dcursor_t *out, /* * Copy inputs to outputs, casting them along the way. */ - arg = name; + arg = NULL; while ((arg = fr_value_box_list_next(args, arg)) != NULL) { fr_value_box_t *vb, *p; diff --git a/src/tests/keywords/xlat-cond-missing b/src/tests/keywords/xlat-cond-missing new file mode 100644 index 00000000000..93ebc005f61 --- /dev/null +++ b/src/tests/keywords/xlat-cond-missing @@ -0,0 +1,23 @@ +&request += { + &Tmp-IP-Address-0 = 192.0.2.1 + &Tmp-IP-Address-0 = 192.0.2.2 + &Tmp-IP-Address-0 = 192.0.2.3 + &Tmp-IP-Address-0 = 192.0.2.4 +} + +if (%{Tmp-IP-Address-0[#]} != 4) { + test_fail +} + +# +# This expansion should succeed, and should result in an empty string. +# +# It's stupid to do this expansion. The admin should instead just check +# for the existence of the attribute. But... the syntax allows it, so +# it should work. +# +if !("%{Tmp-IP-Address-0[4]}" == '') { + test_fail +} + +success