]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
allow multiple selectors for leaf attributes
authorAlan T. DeKok <aland@freeradius.org>
Thu, 1 Sep 2022 22:06:31 +0000 (18:06 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Thu, 15 Sep 2022 18:41:11 +0000 (14:41 -0400)
src/lib/unlang/edit.c
src/tests/keywords/edit-list

index 779154a4597f7575e70fdcff3bc075efed23fcc6..6517b5529171c73f9d4732ecbaafb7b18bb9dd84 100644 (file)
@@ -263,6 +263,8 @@ static int apply_edits_to_list(request_t *request, edit_map_t *current)
        bool copy_vps = true;
        int rcode;
        map_t const *map = current->map;
+       tmpl_dcursor_ctx_t cc;
+       fr_dcursor_t cursor;
 
        fr_assert(current->lhs.vp != NULL);
 
@@ -354,77 +356,68 @@ static int apply_edits_to_list(request_t *request, edit_map_t *current)
                return remove_vps(request, current);
        }
 
-       /*
-        *      Find the RHS attribute / list.
-        */
-       if (tmpl_find_vp(&vp, request, current->rhs.vpt) < 0) {
-               REDEBUG("%s[%d] Failed to find %s for %s %s ...", MAP_INFO,
-                       current->rhs.vpt->name, map->lhs->name, fr_tokens[map->op]);
-               return -1;
-       }
-
        fr_assert(current->lhs.vp != NULL);
 
        /*
-        *      As a special operation, allow "list OP attr", which
-        *      treats the RHS as a one-member list.
+        *      Allow selectors, at least for leaf attributes.
         */
-       if (fr_type_is_leaf(vp->vp_type)) {
-               fr_pair_t *vp_copy;
+       vp = tmpl_dcursor_init(NULL, request, &cc, &cursor, request, current->rhs.vpt);
+       if (!vp) {
+               REDEBUG("%s[%d] Failed to find attribute reference %s", MAP_INFO, current->rhs.vpt->name);
+               return -1;
+       }
 
-               vp_copy = fr_pair_copy(request, vp);
-               if (!vp_copy) return -1;
+       if (fr_type_is_structural(vp->vp_type)) {
+               tmpl_dcursor_clear(&cc);
 
-               fr_assert(fr_pair_list_empty(&current->rhs.pair_list));
+               if (tmpl_num(current->rhs.vpt) == NUM_ALL) {
+                       REDEBUG("%s[%d] Wildcard structural for %s is not yet implemented.", MAP_INFO, current->rhs.vpt->name);
+                       return -1;
+               }
 
-               fr_pair_append(&current->rhs.pair_list, vp_copy);
-               children = &current->rhs.pair_list;
-               copy_vps = false;
+               children = &vp->vp_group;
+               copy_vps = true;
+               goto apply_list;
+       }
 
-       } else {
-               /*
-                *      List to list operations should be compatible.
-                */
-               fr_assert(fr_type_is_structural(vp->vp_type));
+       fr_pair_list_init(&current->rhs.pair_list);
+       while (vp) {
+               fr_pair_t *copy;
 
-               /*
-                *      Forbid copying incompatible structs, TLVs, groups,
-                *      etc.
-                */
-               if (!fr_dict_attr_compatible(current->lhs.vp->da, vp->da)) {
-                       REDEBUG("%s[%d] Attribute data types are not compatible (%s vs %s)", MAP_INFO,
-                              current->lhs.vp->da->name, vp->da->name);
+               copy = fr_pair_copy(request, vp);
+               if (!copy) {
+                       fr_pair_list_free(&current->rhs.pair_list);
+                       tmpl_dcursor_clear(&cc);
                        return -1;
                }
+               fr_pair_append(&current->rhs.pair_list, copy);
 
-               children = &vp->vp_group; /* and copy_vps for any VP we edit */
+               vp = fr_dcursor_next(&cursor);
        }
+       tmpl_dcursor_clear(&cc);
+
+       children = &current->rhs.pair_list;
+       copy_vps = false;
 
        /*
         *      Apply structural thingies!
         */
 apply_list:
-       if (current->rhs.vpt) {
-               RDEBUG2("%s %s %s", current->lhs.vpt->name, fr_tokens[map->op], current->rhs.vpt->name);
-
-       } else {
-               fr_assert(children != NULL);
+       fr_assert(children != NULL);
 
+       /*
+        *      Print the children before we do the modifications.
+        */
+       RDEBUG2("%s %s {", current->lhs.vpt->name, fr_tokens[map->op]);
+       if (fr_debug_lvl >= L_DBG_LVL_2) {
+               RINDENT();
                /*
-                *      Print the children before we do the modifications.
+                *      @todo - this logs at INFO level, and doesn't log the operators.
                 */
-               RDEBUG2("%s %s {", current->lhs.vpt->name, fr_tokens[map->op]);
-               if (fr_debug_lvl >= L_DBG_LVL_2) {
-                       RINDENT();
-                       /*
-                        *      @todo - this logs at INFO level, and doesn't log the operators.
-                        */
-                       xlat_debug_attr_list(request, children);
-                       REXDENT();
-               }
-
-               RDEBUG2("}");
+               xlat_debug_attr_list(request, children);
+               REXDENT();
        }
+       RDEBUG2("}");
 
        rcode = fr_edit_list_apply_list_assignment(current->el, current->lhs.vp, map->op, children, copy_vps);
        if (rcode < 0) RPERROR("Failed performing list %s operation", fr_tokens[map->op]);
index 4152614ac1da72cfffc38c32fee69838ba1e4b9d..997b89c301172cab1c8cdcb833b2a460849a38b3 100644 (file)
@@ -32,4 +32,13 @@ if (!&Tmp-String-0[0]) {
        test_fail
 }
 
+&request -= &Tmp-String-0[*]
+&control.Tmp-String-0 := { "a", "b", "c", "d" }
+
+&request += &control.Tmp-String-0[*]
+if (%{request.Tmp-String-0[#]} != 4) {
+       test_fail
+}
+
+
 success