From b29b10e48ee351c19cb7a0e9766718fa1715f747 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vlendec@samba.org>
Date: Sun, 26 Dec 2004 17:30:27 +0000
Subject: r4366: Fix ldb_modify_internal: Adding values to an existing
 attribute you could end up with a corrupt data structure on disk, namely with
 two attribute structures for the same attribute name.

Volker
(This used to be commit 284044b5b20102894a8128f84ab41d59cfcc9285)
---
 source4/lib/ldb/ldb_tdb/ldb_tdb.c | 45 +++++++++++++++++++++++++++++++--------
 1 file changed, 36 insertions(+), 9 deletions(-)

(limited to 'source4/lib/ldb')

diff --git a/source4/lib/ldb/ldb_tdb/ldb_tdb.c b/source4/lib/ldb/ldb_tdb/ldb_tdb.c
index 5bceab0f13..179b205097 100644
--- a/source4/lib/ldb/ldb_tdb/ldb_tdb.c
+++ b/source4/lib/ldb/ldb_tdb/ldb_tdb.c
@@ -513,24 +513,51 @@ int ltdb_modify_internal(struct ldb_module *module, const struct ldb_message *ms
 	}
 
 	for (i=0;i<msg->num_elements;i++) {
+		struct ldb_message_element *el = &msg->elements[i];
+		struct ldb_message_element *el2;
+		struct ldb_val *vals;
+
 		switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
 
 		case LDB_FLAG_MOD_ADD:
 			/* add this element to the message. fail if it
 			   already exists */
-			ret = find_element(&msg2, msg->elements[i].name);
-			if (ret != -1) {
-				for (j=0;j<msg->elements[i].num_values;j++) {
-					if (ldb_msg_find_val(&msg2.elements[ret], 
-							     &msg->elements[i].values[j])) {
-						ltdb->last_err_string = "Type or value exists";
-						goto failed;
-					}
+			ret = find_element(&msg2, el->name);
+
+			if (ret == -1) {
+				if (msg_add_element(ldb, &msg2, el) != 0) {
+					goto failed;
+				}
+				continue;
+			}
+
+			el2 = &msg2.elements[ret];
+
+			/* An attribute with this name already exists, add all
+			 * values if they don't already exist. */
+
+			for (j=0;j<el->num_values;j++) {
+				if (ldb_msg_find_val(el2, &el->values[j])) {
+					ltdb->last_err_string =
+						"Type or value exists";
+					goto failed;
 				}
 			}
-			if (msg_add_element(ldb, &msg2, &msg->elements[i]) != 0) {
+
+		        vals = ldb_realloc_p(ldb, el2->values, struct ldb_val,
+					     el2->num_values + el->num_values);
+
+			if (vals == NULL)
 				goto failed;
+
+			for (j=0;j<el->num_values;j++) {
+				vals[el2->num_values + j] =
+					ldb_val_dup(ldb, &el->values[j]);
 			}
+
+			el2->values = vals;
+			el2->num_values += el->num_values;
+
 			break;
 
 		case LDB_FLAG_MOD_REPLACE:
-- 
cgit