]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
add and use tmpl_rules_child_init()
authorAlan T. DeKok <aland@freeradius.org>
Sun, 7 Aug 2022 20:44:34 +0000 (16:44 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Mon, 8 Aug 2022 21:25:19 +0000 (17:25 -0400)
which initializes a tmpl_rules_t from a parent tmpl_rules_t, and
a tmpl_t which is a structural attribute.  We want to be able to
parse child attributes in the context of the parent.  So that
the user doesn't have to specify the entire list

src/lib/server/map.c
src/lib/server/tmpl.h
src/lib/server/tmpl_tokenize.c
src/tests/keywords/call
src/tests/keywords/call-empty
src/tests/keywords/edit-list-remove-reply [new file with mode: 0644]

index 90b7d1f509124cc05316eda50a5cdd7246f5d5a7..716fee8395e21b7801978ab6ffad877dc1587d59 100644 (file)
@@ -106,6 +106,7 @@ int map_afrom_cp(TALLOC_CTX *ctx, map_t **out, map_t *parent, CONF_PAIR *cp,
        fr_dict_attr_t const *da;
        tmpl_rules_t    my_rhs_rules;
        tmpl_rules_t const *rhs_rules = input_rhs_rules;
+       TALLOC_CTX      *child_ctx = NULL;
 
        *out = NULL;
 
@@ -130,6 +131,7 @@ int map_afrom_cp(TALLOC_CTX *ctx, map_t **out, map_t *parent, CONF_PAIR *cp,
                fr_assert(lhs_rules->attr.list_as_attr); /* so we don't worry about list_def? */
        }
 
+       MEM(child_ctx = talloc(map, uint8_t));
 
        /*
         *      LHS may be an expansion (that expands to an attribute reference)
@@ -173,47 +175,13 @@ int map_afrom_cp(TALLOC_CTX *ctx, map_t **out, map_t *parent, CONF_PAIR *cp,
                }
 
                /*
-                *      The caller wants the RHS attributes to be parsed in the context of the LHS.
+                *      The caller wants the RHS attributes to be
+                *      parsed in the context of the LHS, but only if
+                *      the LHS attribute was a group / structural attribute.
                 */
-               if (!input_rhs_rules && lhs_rules->attr.list_as_attr && tmpl_is_attr(map->lhs)) {
-                       da = tmpl_da(map->lhs);
-
-                       /*
-                        *      LHS is a leaf.  We must parse the RHS as a full attribute reference (or raw
-                        *      data).
-                        */
-                       if (!fr_type_structural[da->type]) {
-                               break;
-                       }
-
-                       my_rhs_rules = *lhs_rules;
-                       my_rhs_rules.parent = lhs_rules;
+               if (!input_rhs_rules && lhs_rules->attr.list_as_attr) {
+                       tmpl_rules_child_init(child_ctx, &my_rhs_rules, lhs_rules, map->lhs);
                        rhs_rules = &my_rhs_rules;
-
-                       /*
-                        *      struct, tlv, VSA, etc. have their children in the parent attribute.
-                        */
-                       if (da->type != FR_TYPE_GROUP) {
-                               my_rhs_rules.attr.parent = da;
-
-                       } else {
-                               fr_dict_attr_t const *ref = fr_dict_attr_ref(da);
-                               fr_dict_t const *dict = fr_dict_by_da(ref);
-
-                               /*
-                                *      Groups live within their parent dictionary.
-                                *
-                                *      If we're swapping away from internal to a different dictionary, then
-                                *      allow that.
-                                *
-                                *      If we're swapping TO an internal dictionary, then leave well enough alone.
-                                */
-                               if (((my_rhs_rules.attr.dict_def == fr_dict_internal()) && (dict != my_rhs_rules.attr.dict_def)) ||
-                                   (dict != fr_dict_internal())) {
-                                       my_rhs_rules.attr.dict_def = dict;
-                                       my_rhs_rules.attr.parent = ref;
-                               }
-                       }
                }
                break;
        }
@@ -224,7 +192,7 @@ int map_afrom_cp(TALLOC_CTX *ctx, map_t **out, map_t *parent, CONF_PAIR *cp,
        type = cf_pair_value_quote(cp);
        p_rules = value_parse_rules_unquoted[type]; /* We're not searching for quotes */
        if (type == T_DOUBLE_QUOTED_STRING || type == T_BACK_QUOTED_STRING) {
-               slen = fr_sbuff_out_aunescape_until(map, &unescaped_value,
+               slen = fr_sbuff_out_aunescape_until(child_ctx, &unescaped_value,
                                &FR_SBUFF_IN(value, talloc_array_length(value) - 1), SIZE_MAX, p_rules->terminals, p_rules->escapes);
                if (slen < 0) {
                        marker_subject = value;
@@ -245,7 +213,6 @@ int map_afrom_cp(TALLOC_CTX *ctx, map_t **out, map_t *parent, CONF_PAIR *cp,
                marker_subject = value;
                goto marker;
        }
-       TALLOC_FREE(unescaped_value);
 
        if (!map->rhs) {
                cf_log_perr(cp, "Failed parsing RHS");
@@ -280,13 +247,14 @@ int map_afrom_cp(TALLOC_CTX *ctx, map_t **out, map_t *parent, CONF_PAIR *cp,
        }
 
        MAP_VERIFY(map);
+       TALLOC_FREE(child_ctx);
 
        *out = map;
 
        return 0;
 
 error:
-       talloc_free(unescaped_value);
+       TALLOC_FREE(child_ctx);
        talloc_free(map);
        return -1;
 }
@@ -857,8 +825,25 @@ do_children:
                         *      is used as the parsing context of the
                         *      inner section.
                         */
-                       our_lhs_rules.attr.parent = tmpl_da(map->lhs);
                        our_lhs_rules.attr.prefix = TMPL_ATTR_REF_PREFIX_NO;
+                       our_lhs_rules.attr.parent = tmpl_da(map->lhs);
+
+                       /*
+                        *      Groups MAY change dictionaries.  If so, then swap the dictionary and the parent.
+                        */
+                       if (our_lhs_rules.attr.parent->type == FR_TYPE_GROUP) {
+                               fr_dict_attr_t const *ref;
+                               fr_dict_t const *dict, *internal;
+
+                               ref = fr_dict_attr_ref(our_lhs_rules.attr.parent);
+                               dict = fr_dict_by_da(ref);
+                               internal = fr_dict_internal();
+
+                               if ((dict != internal) && (dict != our_lhs_rules.attr.dict_def)) {
+                                       our_lhs_rules.attr.dict_def = dict;
+                                       our_lhs_rules.attr.parent = ref;
+                               }
+                       }
 
                        /*
                         *      This prints out any relevant error
index 29d1922fb6c2fbbc46b6beb95117b748c8c919e2..35fda42d19438b72f38fba7b36b1a8735b9651bf 100644 (file)
@@ -1152,6 +1152,8 @@ fr_pair_t         *tmpl_get_list(request_t *request, tmpl_t const *vpt) CC_HINT(nonnull
 
 int                    tmpl_value_list_insert_tail(fr_value_box_list_t *list, fr_value_box_t *vb, tmpl_t const *vpt) CC_HINT(nonnull);
 
+void                   tmpl_rules_child_init(TALLOC_CTX *ctx, tmpl_rules_t *out, tmpl_rules_t const *parent, tmpl_t *vpt) CC_HINT(nonnull);
+
 int                    tmpl_global_init(void);
 void                   tmpl_global_free(void);
 
index 16d7c25de8987ddf19dc20514ea320ace7b1fa02..010e23d6afddcbfc4f1ac98610d7a439adc740e8 100644 (file)
@@ -2163,7 +2163,7 @@ ssize_t tmpl_afrom_attr_substr(TALLOC_CTX *ctx, tmpl_attr_error_t *err,
         *
         *      Eventually we'll remove TMPL_TYPE_LIST
         */
-       if (tmpl_attr_list_num_elements(&vpt->data.attribute.ar) == 0) {
+       if (!t_attr_rules->list_as_attr && (tmpl_attr_list_num_elements(&vpt->data.attribute.ar) == 0)) {
                tmpl_attr_t *ar;
 
                MEM(ar = talloc_zero(vpt, tmpl_attr_t));
@@ -5460,3 +5460,62 @@ bool tmpl_async_required(tmpl_t const *vpt)
                return false;
        }
 }
+
+/** Initialize a set of rules from a parent set of rules, and a parsed tmpl_t
+ *
+ */
+void tmpl_rules_child_init(TALLOC_CTX *ctx, tmpl_rules_t *out, tmpl_rules_t const *parent, tmpl_t *vpt)
+{
+       fr_dict_attr_t const *da;
+       fr_dict_attr_t const *ref;
+       fr_dict_t const *dict, *internal;
+
+       *out = *parent;
+       out->parent = parent;
+
+       if (!tmpl_is_attr(vpt)) return;
+
+       da = tmpl_da(vpt);
+
+       /*
+        *      The input tmpl is a leaf.  We must parse the child as
+        *      a normal attribute reference (as with the parent tmpl).
+        */
+       if (!fr_type_structural[da->type]) {
+               return;
+       }
+
+       if (vpt->rules.attr.request_def) {
+               tmpl_request_ref_list_acopy(ctx, &out->attr.request_def, vpt->rules.attr.request_def);
+       }
+       out->attr.list_def = tmpl_list(vpt);
+
+       /*
+        *      Parse the child attributes in the context of the parent struct / tlv / whatever.
+        */
+       if (da->type != FR_TYPE_GROUP) {
+               out->attr.dict_def = fr_dict_by_da(da);
+               out->attr.parent = da;
+               return;
+       }
+
+       ref = fr_dict_attr_ref(da);
+       dict = fr_dict_by_da(ref);
+       internal = fr_dict_internal();
+
+       /*
+        *      Groups MAY change dictionaries.  If so, then swap the dictionary and the parent.
+        */
+       if ((dict != internal) && (dict != out->attr.dict_def)) {
+               out->attr.dict_def = dict;
+               out->attr.parent = ref;
+       }
+
+       /*
+        *      Otherwise the reference is swapping FROM a protocol
+        *      dictionary TO the internal dictionary, and TO an
+        *      internal group.  We fall back to leaving well enough
+        *      alone, and leave things as-is.  This allows internal
+        *      grouping attributes to appear anywhere.
+        */
+}
index 3ffeaa0e4c69cdfd83c18911699d645961a12917..79a6ea0dbd123f1d8584872cc5bd977531170c5c 100644 (file)
@@ -19,9 +19,6 @@ if (&reply.Reply-Message[1] != "call second post") {
        test_fail
 }
 
-#
-#  @todo - The LHS SHOULD set the default context for the RHS.
-#
-&reply -= &reply.Reply-Message
+&reply -= &Reply-Message[*]
 
 success
index 703510e1f2338e5b251357ea8d92b4e723c7e0e4..de8a0b7320c09a68ad3c91e8f1c661e06450a8d8 100644 (file)
@@ -14,9 +14,6 @@ if (&reply.Reply-Message[0] != "call second") {
        test_fail
 }
 
-#
-#  @todo - The LHS SHOULD set the default context for the RHS.
-#
-&reply -= &reply.Reply-Message
+&reply -= &Reply-Message
 
 success
diff --git a/src/tests/keywords/edit-list-remove-reply b/src/tests/keywords/edit-list-remove-reply
new file mode 100644 (file)
index 0000000..ae439f1
--- /dev/null
@@ -0,0 +1,16 @@
+&reply.Reply-Message := "foo"
+if (!&reply.Reply-Message) {
+       test_fail
+}
+
+#
+#  The default list here is the LHS list, not "request".
+#
+&reply -= &Reply-Message[*]
+
+#  Does not exist
+if (&reply.Reply-Message) {
+       test_fail
+}
+
+success