]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
xlat: Concat output boxes from tmpl evaluation when the tmpl was originally quoted
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Tue, 27 Jun 2023 19:09:50 +0000 (15:09 -0400)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Tue, 27 Jun 2023 21:07:54 +0000 (17:07 -0400)
Add regression tests for compound rlm_files keys

src/lib/server/tmpl.h
src/lib/server/tmpl_eval.c
src/lib/unlang/tmpl.c
src/lib/unlang/xlat_eval.c
src/tests/keywords/xlat-string
src/tests/modules/files/compound_key [new file with mode: 0644]
src/tests/modules/files/compound_key.unlang [new file with mode: 0644]
src/tests/modules/files/module.conf

index 3fe9269f8c33ddd0465d0ec601e64568cee82576..d9e3355a8829c2ceaf097cc24fcd1a0a8005ca5f 100644 (file)
@@ -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,
index 8d7f25b75f1de00fe482480584cc8641d38d567d..a5213a59c95bd72cea7e3ba4bcc6a5bfc1f2f95a 100644 (file)
@@ -38,6 +38,8 @@ RCSID("$Id$")
 #include <freeradius-devel/util/proto.h>
 #include <freeradius-devel/util/value.h>
 #include <freeradius-devel/util/edit.h>
+#include <freeradius-devel/util/token.h>
+#include <freeradius-devel/util/types.h>
 
 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;
index cd56a7e103c227cb58e767fe2ac24fba118df6ca..b38a4cd0dd70068d0f7a203a80f113344448995b 100644 (file)
@@ -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;
index a00da575fcdedecf0fb3384377bc820b41f74aab..db37245f7b01b5c4b3c1f74b641c9778e5ac6691 100644 (file)
@@ -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;
index b8116bc1a2409468dc8f590ceabb9601f2146e5c..a8d861eaec58d78e79a71a008fa601ccf813c5c2 100644 (file)
        &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 (file)
index 0000000..3f491f2
--- /dev/null
@@ -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 (file)
index 0000000..beedfe5
--- /dev/null
@@ -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
index 17eca16b843d7b90e83f7d9b781491d9828164ee..21a75fdaf221646582886ae9c4c7c189698b9f79 100644 (file)
@@ -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
+}