From: Arran Cudbard-Bell Date: Tue, 27 Jun 2023 19:09:50 +0000 (-0400) Subject: xlat: Concat output boxes from tmpl evaluation when the tmpl was originally quoted X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2431bbe6c0ef70ff9f04e19c1174b206fdad956c;p=thirdparty%2Ffreeradius-server.git xlat: Concat output boxes from tmpl evaluation when the tmpl was originally quoted Add regression tests for compound rlm_files keys --- diff --git a/src/lib/server/tmpl.h b/src/lib/server/tmpl.h index 3fe9269f8c3..d9e3355a882 100644 --- a/src/lib/server/tmpl.h +++ b/src/lib/server/tmpl.h @@ -1326,7 +1326,7 @@ int tmpl_eval_pair(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *reque int tmpl_eval(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *request, tmpl_t const *vpt); -int tmpl_eval_cast(TALLOC_CTX *ctx, fr_value_box_list_t *out, tmpl_t const *vpt); +int tmpl_eval_cast_in_place(fr_value_box_list_t *out, tmpl_t const *vpt); /** @} */ ssize_t tmpl_preparse(char const **out, size_t *outlen, char const *in, size_t inlen, diff --git a/src/lib/server/tmpl_eval.c b/src/lib/server/tmpl_eval.c index 8d7f25b75f1..a5213a59c95 100644 --- a/src/lib/server/tmpl_eval.c +++ b/src/lib/server/tmpl_eval.c @@ -38,6 +38,8 @@ RCSID("$Id$") #include #include #include +#include +#include static fr_dict_t const *dict_freeradius; static fr_dict_t const *dict_radius; @@ -1224,7 +1226,7 @@ done: fr_value_box_list_init(&list); fr_value_box_list_insert_tail(&list, value); - if (tmpl_eval_cast(ctx, &list, vpt) < 0) { + if (tmpl_eval_cast_in_place(&list, vpt) < 0) { fr_value_box_list_talloc_free(&list); return -1; }; @@ -1362,7 +1364,7 @@ done: * Evaluate casts if necessary. */ if (ret == 0) { - if (tmpl_eval_cast(ctx, &list, vpt) < 0) { + if (tmpl_eval_cast_in_place(&list, vpt) < 0) { fr_value_box_list_talloc_free(&list); ret = -1; goto fail; @@ -1445,7 +1447,7 @@ done: fr_value_box_list_init(&list); fr_value_box_list_insert_tail(&list, value); - if (tmpl_eval_cast(ctx, &list, vpt) < 0) { + if (tmpl_eval_cast_in_place(&list, vpt) < 0) { fr_value_box_list_talloc_free(&list); return -1; }; @@ -1458,76 +1460,80 @@ done: /** Casts a value or list of values according to the tmpl * - * @param[in] ctx to allocate boxed value, and buffers in. * @param[in,out] list Where to write the boxed value. * @param[in] vpt Representing the attribute. * @return * - <0 the cast failed * - 0 we successfully evaluated the tmpl */ -int tmpl_eval_cast(TALLOC_CTX *ctx, fr_value_box_list_t *list, tmpl_t const *vpt) +int tmpl_eval_cast_in_place(fr_value_box_list_t *list, tmpl_t const *vpt) { fr_type_t cast = tmpl_rules_cast(vpt); - fr_value_box_t *vb; - bool tainted = false; - ssize_t slen, vlen; - fr_sbuff_t *agg; - if (cast == FR_TYPE_NULL) return 0; + if (fr_type_is_structural(cast)) { + fr_strerror_printf("Cannot cast to structural type '%s'", fr_type_to_str(cast)); + return -1; + } /* - * Apply a cast to the results if required. + * Quoting around the tmpl means everything + * needs to be concatenated, either as a string + * or octets string. */ - vb = fr_value_box_list_head(list); - if (!vb) return 0; + switch (vpt->quote) { + case T_DOUBLE_QUOTED_STRING: + case T_SINGLE_QUOTED_STRING: + case T_SOLIDUS_QUOTED_STRING: + case T_BACK_QUOTED_STRING: + { + ssize_t slen; + fr_value_box_t *vb; - switch (cast) { - default: - /* - * One box, we cast it as the destination type. - * - * Many boxes, turn them into strings, and try to parse it as the - * output type. - */ - if (!fr_value_box_list_next(list, vb)) { - return fr_value_box_cast_in_place(vb, vb, cast, NULL); - } - FALL_THROUGH; + vb = fr_value_box_list_head(list); + if (!vb) return 0; /* - * Strings aren't *cast* to the output. They're *printed* to the output. + * Convert directly to concatenated octets + * don't go through a string representation + * first. */ - case FR_TYPE_STRING: - FR_SBUFF_TALLOC_THREAD_LOCAL(&agg, 256, 256); + if (fr_type_is_octets((cast))) { + return fr_value_box_list_concat_in_place(vb, vb, list, FR_TYPE_OCTETS, + FR_VALUE_BOX_LIST_FREE_BOX, true, SIZE_MAX); + } - slen = fr_value_box_list_concat_as_string(&tainted, agg, list, NULL, 0, - (cast == FR_TYPE_STRING) ? &fr_value_escape_double : NULL, - FR_VALUE_BOX_LIST_FREE_BOX, true, true); + slen = fr_value_box_list_concat_in_place(vb, vb, list, FR_TYPE_STRING, + FR_VALUE_BOX_LIST_FREE_BOX, true, SIZE_MAX); if (slen < 0) return -1; - MEM(vb = fr_value_box_alloc_null(ctx)); - vlen = fr_value_box_from_str(vb, vb, cast, NULL, - fr_sbuff_start(agg), fr_sbuff_used(agg), - NULL, tainted); - if ((vlen < 0) || (slen != vlen)) return -1; - - fr_value_box_list_insert_tail(list, vb); + /* + * If there's no cast, or it's a cast to + * a string, we're done! + * + * Otherwise we now need to re-cast the + * result. + */ + if (fr_type_is_null(cast) || fr_type_is_string(cast)) return 0; + } break; - case FR_TYPE_OCTETS: - return fr_value_box_list_concat_in_place(vb, vb, list, cast, - FR_VALUE_BOX_LIST_FREE_BOX, true, SIZE_MAX); - case FR_TYPE_STRUCTURAL: - fr_strerror_printf("Cannot cast to structural type '%s'", - fr_type_to_str(cast)); - return -1; + default: + break; } + if (fr_type_is_null(cast)) return 0; + + /* + * Quoting above handled all concatenation, + * we now need to handle potentially + * multivalued lists. + */ + fr_value_box_list_foreach_safe(list, vb) { + if (fr_value_box_cast_in_place(vb, vb, cast, NULL) < 0) return -1; + }} return 0; } - - int tmpl_global_init(void) { fr_dict_attr_t *da; diff --git a/src/lib/unlang/tmpl.c b/src/lib/unlang/tmpl.c index cd56a7e103c..b38a4cd0dd7 100644 --- a/src/lib/unlang/tmpl.c +++ b/src/lib/unlang/tmpl.c @@ -79,7 +79,7 @@ static unlang_action_t unlang_tmpl_resume(rlm_rcode_t *p_result, request_t *requ unlang_frame_state_tmpl_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_tmpl_t); unlang_tmpl_t *ut = unlang_generic_to_tmpl(frame->instruction); - if (tmpl_eval_cast(request, &state->list, ut->tmpl) < 0) { + if (tmpl_eval_cast_in_place(&state->list, ut->tmpl) < 0) { RPEDEBUG("Failed casting expansion"); *p_result = RLM_MODULE_FAIL; return UNLANG_ACTION_CALCULATE_RESULT; diff --git a/src/lib/unlang/xlat_eval.c b/src/lib/unlang/xlat_eval.c index a00da575fcd..db37245f7b0 100644 --- a/src/lib/unlang/xlat_eval.c +++ b/src/lib/unlang/xlat_eval.c @@ -1051,7 +1051,7 @@ xlat_action_t xlat_frame_eval_repeat(TALLOC_CTX *ctx, fr_dcursor_t *out, case XLAT_TMPL: fr_assert(tmpl_is_exec(node->vpt)); - if (tmpl_eval_cast(ctx, result, node->vpt) < 0) { + if (tmpl_eval_cast_in_place(result, node->vpt) < 0) { fr_value_box_list_talloc_free(result); return XLAT_ACTION_FAIL; } @@ -1176,7 +1176,7 @@ xlat_action_t xlat_frame_eval(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_exp_head_ /* * Cast the results if necessary. */ - if (tmpl_eval_cast(ctx, &result, node->vpt) < 0) goto fail; + if (tmpl_eval_cast_in_place(&result, node->vpt) < 0) goto fail; fr_value_box_list_move((fr_value_box_list_t *)out->dlist, &result); continue; diff --git a/src/tests/keywords/xlat-string b/src/tests/keywords/xlat-string index b8116bc1a24..a8d861eaec5 100644 --- a/src/tests/keywords/xlat-string +++ b/src/tests/keywords/xlat-string @@ -17,33 +17,10 @@ &Tmp-String-3 = "%{string:%{Tmp-Octets-3}}" } -# -# Cast of octets to string is the octets *printed* to a string, just -# like every other data type. If we want to *convert* the octets to -# a string, we have to use "%{string:...}" -# -if (!((string)&Tmp-Octets-0 == "0x5c5c")) { - test_fail -} - -# -# And the printed "0x5c5c" is not equivalent to the octet string -# -if ((string)&Tmp-Octets-0 == 0x5c5c) { - test_fail -} - if (!(&Tmp-String-0 == "\\\\")) { test_fail } -# -# These are now defined to be different. -# -if ((string)&Tmp-Octets-0 == "%{string:%{Tmp-Octets-0}}") { - test_fail -} - # # Test interpolation between string expansions and strings # diff --git a/src/tests/modules/files/compound_key b/src/tests/modules/files/compound_key new file mode 100644 index 00000000000..3f491f279c2 --- /dev/null +++ b/src/tests/modules/files/compound_key @@ -0,0 +1 @@ +test0:test1 Tmp-String-0 := 'matched' diff --git a/src/tests/modules/files/compound_key.unlang b/src/tests/modules/files/compound_key.unlang new file mode 100644 index 00000000000..beedfe54598 --- /dev/null +++ b/src/tests/modules/files/compound_key.unlang @@ -0,0 +1,13 @@ +&Tmp-String-0 := 'test0' +&Tmp-String-1 := 'test1' + +compound_key +if (!ok) { + test_fail +} + +if (!(&control.Tmp-String-0 == 'matched')) { + test_fail +} + +test_pass diff --git a/src/tests/modules/files/module.conf b/src/tests/modules/files/module.conf index 17eca16b843..21a75fdaf22 100644 --- a/src/tests/modules/files/module.conf +++ b/src/tests/modules/files/module.conf @@ -17,3 +17,8 @@ files subnet2 { key = &FreeRADIUS-Client-IP-Prefix filename = $ENV{MODULE_TEST_DIR}/subnet2 } + +files compound_key { + key = "%{Tmp-String-0}:%{Tmp-String-1}" + filename = $ENV{MODULE_TEST_DIR}/compound_key +}