]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
ensure that list is empty before merge / union / etc.
authorAlan T. DeKok <aland@freeradius.org>
Fri, 29 Jul 2022 16:15:06 +0000 (12:15 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Fri, 29 Jul 2022 16:15:06 +0000 (12:15 -0400)
Those operations sort their inputs *without* tracking those changes
in the edit list.  So if there are already edits in the list, the
sort will break the ability to undo things.

As a result, we forbid behavior which we know will result in wrong
outcomes.

src/lib/util/edit.c

index 0a8954a8cd33c9c8121a2a1c86b181dd0d1e5c36..9d1a4bbb8b2afd828165e5247fd0b7bd3f02260b 100644 (file)
@@ -117,6 +117,12 @@ typedef struct {
        fr_pair_list_t  *list;          //!< list to ignore (never dereferenced)
 } fr_edit_ignore_t;
 
+
+static bool fr_edit_list_empty(fr_edit_list_t *el)
+{
+       return fr_dlist_empty(&el->undo) && fr_dlist_empty(&el->ignore) && fr_pair_list_empty(&el->deleted_pairs);
+}
+
 /** Undo one particular edit.
  */
 static int edit_undo(fr_edit_t *e)
@@ -1333,21 +1339,33 @@ int fr_edit_list_apply_list_assignment(fr_edit_list_t *el, fr_pair_t *dst, fr_to
        case T_OP_AND_EQ:
                if (&dst->children == src) return 0; /* A INTERSECTION A == A */
 
+               if (!fr_edit_list_empty(el)) {
+               not_empty:
+                       fr_strerror_printf("Failed to perform %s - undo list is not empty", fr_tokens[op]);
+                       return -1;
+               }
+
                return list_intersection(el, dst, src);
 
        case T_OP_OR_EQ:
                if (&dst->children == src) return 0; /* A UNION A == A */
 
+               if (!fr_edit_list_empty(el)) goto not_empty;
+
                return list_union(el, dst, src, copy);
 
        case T_OP_GE:
                if (&dst->children == src) return 0; /* A MERGE A == A */
 
+               if (!fr_edit_list_empty(el)) goto not_empty;
+
                return list_merge_lhs(el, dst, src, copy);
 
        case T_OP_LE:
                if (&dst->children == src) return 0; /* A MERGE A == A */
 
+               if (!fr_edit_list_empty(el)) goto not_empty;
+
                return list_merge_rhs(el, dst, src, copy);
 
        default: