[Pkg-samba-maint] [Git][samba-team/samba][bullseye] 3 commits: 3 patchsets from upstream to fix security issues

Michael Tokarev (@mjt) gitlab at salsa.debian.org
Thu Aug 4 15:47:53 BST 2022



Michael Tokarev pushed to branch bullseye at Debian Samba Team / samba


Commits:
9625d0a6 by Michael Tokarev at 2022-08-01T17:44:42+03:00
3 patchsets from upstream to fix security issues

CVE-2022-32742-bug-15085-4.13.patch
kpasswd_bugs_v15_4-13.patch
ldb-memory-bug-15096-4.13-v3.patch

- - - - -
faf96dd2 by Michael Tokarev at 2022-08-01T17:47:57+03:00
d/control: require libldb-dev >= 2.2.3-2~deb11u2

- - - - -
ff19901e by Michael Tokarev at 2022-08-04T15:09:57+03:00
update changelog; upload 4.13.13+dfsg-1~deb11u5 to bullseye-security

- - - - -


6 changed files:

- debian/changelog
- debian/control
- + debian/patches/CVE-2022-32742-bug-15085-4.13.patch
- + debian/patches/kpasswd_bugs_v15_4-13.patch
- + debian/patches/ldb-memory-bug-15096-4.13-v3.patch
- debian/patches/series


Changes:

=====================================
debian/changelog
=====================================
@@ -1,3 +1,31 @@
+samba (2:4.13.13+dfsg-1~deb11u5) bullseye-security; urgency=medium
+
+  * 3 patches:
+    - CVE-2022-32742-bug-15085-4.13.patch
+    - kpasswd_bugs_v15_4-13.patch
+    - ldb-memory-bug-15096-4.13-v3.patch
+    fixing:
+    o CVE-2022-2031: Samba AD users can bypass certain restrictions associated
+      with changing passwords.
+      https://www.samba.org/samba/security/CVE-2022-2031.html
+    o CVE-2022-32742: Server memory information leak via SMB1.
+      https://www.samba.org/samba/security/CVE-2022-32742.html
+    o CVE-2022-32744: Samba AD users can forge password change requests
+      for any user.
+      https://www.samba.org/samba/security/CVE-2022-32744.html
+    o CVE-2022-32745: Samba AD users can crash the server process with an LDAP
+      add or modify request.
+      https://www.samba.org/samba/security/CVE-2022-32745.html
+    o CVE-2022-32746: Samba AD users can induce a use-after-free in the server
+      process with an LDAP add or modify request.
+      https://www.samba.org/samba/security/CVE-2022-32746.html
+   * Closes: #1016449, CVE-2022-2031 CVE-2022-32742, CVE-2022-32744,
+     CVE-2022-32745, CVE-2022-32746
+   * Build-Depend on libldb-dev >= 2.2.3-2~deb11u2
+     (which includes the new symbols in libldb used by this update)
+
+ -- Michael Tokarev <mjt at tls.msk.ru>  Mon, 01 Aug 2022 17:48:14 +0300
+
 samba (2:4.13.13+dfsg-1~deb11u4) bullseye-proposed-updates; urgency=medium
 
   * fix the order of everything during build by exporting PYTHONHASHSEED=1


=====================================
debian/control
=====================================
@@ -32,7 +32,7 @@ Build-Depends: bison,
                libicu-dev,
                libjansson-dev,
                libldap2-dev,
-               libldb-dev (>= 2:2.2.3~),
+               libldb-dev (>= 2:2.2.3-2~deb11u2~),
                libncurses5-dev,
                libpam0g-dev,
                libparse-yapp-perl,


=====================================
debian/patches/CVE-2022-32742-bug-15085-4.13.patch
=====================================
@@ -0,0 +1,198 @@
+From 89cbbcbc9b59e64c04fea0f965de16428847fc92 Mon Sep 17 00:00:00 2001
+From: Jeremy Allison <jra at samba.org>
+Date: Tue, 7 Jun 2022 09:40:45 -0700
+Subject: [PATCH 1/2] CVE-2022-32742: s4: torture: Add raw.write.bad-write
+ test.
+
+Reproduces the test code in:
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15085
+
+Add knownfail.
+
+Signed-off-by: Jeremy Allison <jra at samba.org>
+Reviewed-by: David Disseldorp <ddiss at samba.org>
+---
+ source4/torture/raw/write.c    | 89 ++++++++++++++++++++++++++++++++++
+ 1 file changed, 89 insertions(+)
+ create mode 100644 selftest/knownfail.d/bad-write
+
+diff --git a/source4/torture/raw/write.c b/source4/torture/raw/write.c
+index 0a2f50f425b..661485bb548 100644
+--- a/source4/torture/raw/write.c
++++ b/source4/torture/raw/write.c
+@@ -25,6 +25,7 @@
+ #include "libcli/libcli.h"
+ #include "torture/util.h"
+ #include "torture/raw/proto.h"
++#include "libcli/raw/raw_proto.h"
+ 
+ #define CHECK_STATUS(status, correct) do { \
+ 	if (!NT_STATUS_EQUAL(status, correct)) { \
+@@ -694,6 +695,93 @@ done:
+ 	return ret;
+ }
+ 
++/*
++  test a deliberately bad SMB1 write.
++*/
++static bool test_bad_write(struct torture_context *tctx,
++		       struct smbcli_state *cli)
++{
++	bool ret = false;
++	int fnum = -1;
++	struct smbcli_request *req = NULL;
++	const char *fname = BASEDIR "\\badwrite.txt";
++	bool ok = false;
++
++	if (!torture_setup_dir(cli, BASEDIR)) {
++		torture_fail(tctx, "failed to setup basedir");
++	}
++
++	torture_comment(tctx, "Testing RAW_BAD_WRITE\n");
++
++	fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
++	if (fnum == -1) {
++		torture_fail_goto(tctx,
++			done,
++			talloc_asprintf(tctx,
++				"Failed to create %s - %s\n",
++				fname,
++				smbcli_errstr(cli->tree)));
++	}
++
++	req = smbcli_request_setup(cli->tree,
++				   SMBwrite,
++				   5,
++				   0);
++	if (req == NULL) {
++		torture_fail_goto(tctx,
++			done,
++			talloc_asprintf(tctx, "talloc fail\n"));
++	}
++
++	SSVAL(req->out.vwv, VWV(0), fnum);
++	SSVAL(req->out.vwv, VWV(1), 65535); /* bad write length. */
++	SIVAL(req->out.vwv, VWV(2), 0); /* offset */
++	SSVAL(req->out.vwv, VWV(4), 0); /* remaining. */
++
++        if (!smbcli_request_send(req)) {
++		torture_fail_goto(tctx,
++			done,
++			talloc_asprintf(tctx, "Send failed\n"));
++        }
++
++        if (!smbcli_request_receive(req)) {
++		torture_fail_goto(tctx,
++			done,
++			talloc_asprintf(tctx, "Reveive failed\n"));
++	}
++
++	/*
++	 * Check for expected error codes.
++	 * ntvfs returns NT_STATUS_UNSUCCESSFUL.
++	 */
++	ok = (NT_STATUS_EQUAL(req->status, NT_STATUS_INVALID_PARAMETER) ||
++	     NT_STATUS_EQUAL(req->status, NT_STATUS_UNSUCCESSFUL));
++
++	if (!ok) {
++		torture_fail_goto(tctx,
++			done,
++			talloc_asprintf(tctx,
++				"Should have returned "
++				"NT_STATUS_INVALID_PARAMETER or "
++				"NT_STATUS_UNSUCCESSFUL "
++				"got %s\n",
++				nt_errstr(req->status)));
++        }
++
++	ret = true;
++
++done:
++	if (req != NULL) {
++		smbcli_request_destroy(req);
++	}
++	if (fnum != -1) {
++		smbcli_close(cli->tree, fnum);
++	}
++	smb_raw_exit(cli->session);
++	smbcli_deltree(cli->tree, BASEDIR);
++	return ret;
++}
++
+ /*
+    basic testing of write calls
+ */
+@@ -705,6 +793,7 @@ struct torture_suite *torture_raw_write(TALLOC_CTX *mem_ctx)
+ 	torture_suite_add_1smb_test(suite, "write unlock", test_writeunlock);
+ 	torture_suite_add_1smb_test(suite, "write close", test_writeclose);
+ 	torture_suite_add_1smb_test(suite, "writex", test_writex);
++	torture_suite_add_1smb_test(suite, "bad-write", test_bad_write);
+ 
+ 	return suite;
+ }
+-- 
+2.35.0
+
+
+From 31337a4b005685ae68d44fbd01ec20e5ffaea974 Mon Sep 17 00:00:00 2001
+From: Jeremy Allison <jra at samba.org>
+Date: Wed, 8 Jun 2022 13:50:51 -0700
+Subject: [PATCH 2/2] CVE-2022-32742: s3: smbd: Harden the smbreq_bufrem()
+ macro.
+
+Fixes the raw.write.bad-write test.
+
+NB. We need the two (==0) changes in source3/smbd/reply.c
+as the gcc optimizer now knows that the return from
+smbreq_bufrem() can never be less than zero.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15085
+
+Remove knownfail.
+
+Signed-off-by: Jeremy Allison <jra at samba.org>
+Reviewed-by: David Disseldorp <ddiss at samba.org>
+---
+ source3/include/smb_macros.h   | 2 +-
+ source3/smbd/reply.c           | 4 ++--
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/source3/include/smb_macros.h b/source3/include/smb_macros.h
+index 68abe83dcbc..aa6de2a56aa 100644
+--- a/source3/include/smb_macros.h
++++ b/source3/include/smb_macros.h
+@@ -148,7 +148,7 @@
+ 
+ /* the remaining number of bytes in smb buffer 'buf' from pointer 'p'. */
+ #define smb_bufrem(buf, p) (smb_buflen(buf)-PTR_DIFF(p, smb_buf(buf)))
+-#define smbreq_bufrem(req, p) (req->buflen - PTR_DIFF(p, req->buf))
++#define smbreq_bufrem(req, p) ((req)->buflen < PTR_DIFF((p), (req)->buf) ? 0 : (req)->buflen - PTR_DIFF((p), (req)->buf))
+ 
+ 
+ /* Note that chain_size must be available as an extern int to this macro. */
+diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
+index a0da2910350..bdcf3dce66a 100644
+--- a/source3/smbd/reply.c
++++ b/source3/smbd/reply.c
+@@ -415,7 +415,7 @@ size_t srvstr_get_path_req_wcard(TALLOC_CTX *mem_ctx, struct smb_request *req,
+ {
+ 	ssize_t bufrem = smbreq_bufrem(req, src);
+ 
+-	if (bufrem < 0) {
++	if (bufrem == 0) {
+ 		*err = NT_STATUS_INVALID_PARAMETER;
+ 		return 0;
+ 	}
+@@ -464,7 +464,7 @@ size_t srvstr_pull_req_talloc(TALLOC_CTX *ctx, struct smb_request *req,
+ {
+ 	ssize_t bufrem = smbreq_bufrem(req, src);
+ 
+-	if (bufrem < 0) {
++	if (bufrem == 0) {
+ 		return 0;
+ 	}
+ 
+-- 
+2.35.0
+


=====================================
debian/patches/kpasswd_bugs_v15_4-13.patch
=====================================
The diff for this file was not included because it is too large.

=====================================
debian/patches/ldb-memory-bug-15096-4.13-v3.patch
=====================================
@@ -0,0 +1,2341 @@
+From e9b06385e8799fc2e414aa1535250714a37f09db Mon Sep 17 00:00:00 2001
+From: Joseph Sutton <josephsutton at catalyst.net.nz>
+Date: Tue, 14 Jun 2022 21:09:53 +1200
+Subject: [PATCH 01/18] CVE-2022-32746 s4/dsdb/objectclass_attrs: Fix typo
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15009
+
+Signed-off-by: Joseph Sutton <josephsutton at catalyst.net.nz>
+---
+ source4/dsdb/samdb/ldb_modules/objectclass_attrs.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c b/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c
+index 0b9725e2767..c90e547afe2 100644
+--- a/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c
++++ b/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c
+@@ -261,7 +261,7 @@ static int attr_handler(struct oc_context *ac)
+ 												LDB_CONTROL_AS_SYSTEM_OID);
+ 					if (!dsdb_module_am_system(ac->module) && !as_system) {
+ 						ldb_asprintf_errstring(ldb,
+-								       "objectclass_attrs: attribute '%s' on entry '%s' must can only be modified as system",
++								       "objectclass_attrs: attribute '%s' on entry '%s' can only be modified as system",
+ 								       msg->elements[i].name,
+ 								       ldb_dn_get_linearized(msg->dn));
+ 						return LDB_ERR_CONSTRAINT_VIOLATION;
+-- 
+2.35.0
+
+
+From 6b94861159b6e5fc7b83063bfd413f144c438df5 Mon Sep 17 00:00:00 2001
+From: Joseph Sutton <josephsutton at catalyst.net.nz>
+Date: Tue, 21 Jun 2022 15:37:15 +1200
+Subject: [PATCH 02/18] CVE-2022-32746 s4:dsdb:tests: Add test for deleting a
+ disallowed SPN
+
+If an account has an SPN that requires Write Property to set, we should
+still be able to delete it with just Validated Write.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15009
+
+Signed-off-by: Joseph Sutton <josephsutton at catalyst.net.nz>
+---
+ source4/dsdb/tests/python/acl.py    | 26 ++++++++++++++++++++++++++
+ 1 file changed, 26 insertions(+)
+
+diff --git a/source4/dsdb/tests/python/acl.py b/source4/dsdb/tests/python/acl.py
+index 53acb99c296..a3c42b00a08 100755
+--- a/source4/dsdb/tests/python/acl.py
++++ b/source4/dsdb/tests/python/acl.py
+@@ -2286,6 +2286,32 @@ class AclSPNTests(AclTests):
+         else:
+             self.fail(f'able to add disallowed SPN {not_allowed_spn}')
+ 
++    def test_delete_disallowed_spn(self):
++        # Grant Validated-SPN property.
++        mod = f'(OA;;SW;{security.GUID_DRS_VALIDATE_SPN};;{self.user_sid1})'
++        self.sd_utils.dacl_add_ace(self.computerdn, mod)
++
++        spn_base = f'HOST/{self.computername}'
++
++        not_allowed_spn = f'{spn_base}/{self.dcctx.get_domain_name()}'
++
++        # Add a disallowed SPN as admin.
++        msg = Message(Dn(self.ldb_admin, self.computerdn))
++        msg['servicePrincipalName'] = MessageElement(not_allowed_spn,
++                                                     FLAG_MOD_ADD,
++                                                     'servicePrincipalName')
++        self.ldb_admin.modify(msg)
++
++        # Ensure we are able to delete a disallowed SPN.
++        msg = Message(Dn(self.ldb_user1, self.computerdn))
++        msg['servicePrincipalName'] = MessageElement(not_allowed_spn,
++                                                     FLAG_MOD_DELETE,
++                                                     'servicePrincipalName')
++        try:
++            self.ldb_user1.modify(msg)
++        except LdbError:
++            self.fail(f'unable to delete disallowed SPN {not_allowed_spn}')
++
+ 
+ # tests SEC_ADS_LIST vs. SEC_ADS_LIST_OBJECT
+ @DynamicTestCase
+-- 
+2.35.0
+
+
+From 28b87fdfefa965d955b0e9467b08692b972e40eb Mon Sep 17 00:00:00 2001
+From: Joseph Sutton <josephsutton at catalyst.net.nz>
+Date: Tue, 21 Jun 2022 14:41:02 +1200
+Subject: [PATCH 03/18] CVE-2022-32746 s4/dsdb/partition: Fix LDB flags
+ comparison
+
+LDB_FLAG_MOD_* values are not actually flags, and the previous
+comparison was equivalent to
+
+(req_msg->elements[el_idx].flags & LDB_FLAG_MOD_MASK) != 0
+
+which is true whenever any of the LDB_FLAG_MOD_* values are set. Correct
+the expression to what it was probably intended to be.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15009
+
+Signed-off-by: Joseph Sutton <josephsutton at catalyst.net.nz>
+---
+ source4/dsdb/samdb/ldb_modules/partition.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/source4/dsdb/samdb/ldb_modules/partition.c b/source4/dsdb/samdb/ldb_modules/partition.c
+index 2544a106d13..2d90ca5d1b3 100644
+--- a/source4/dsdb/samdb/ldb_modules/partition.c
++++ b/source4/dsdb/samdb/ldb_modules/partition.c
+@@ -493,8 +493,8 @@ static int partition_copy_all_callback_action(
+ 			 * them here too
+ 			 */
+ 			for (el_idx=0; el_idx < req_msg->num_elements; el_idx++) {
+-				if (req_msg->elements[el_idx].flags & LDB_FLAG_MOD_DELETE
+-				    || ((req_msg->elements[el_idx].flags & LDB_FLAG_MOD_REPLACE) &&
++				if (LDB_FLAG_MOD_TYPE(req_msg->elements[el_idx].flags) == LDB_FLAG_MOD_DELETE
++				    || ((LDB_FLAG_MOD_TYPE(req_msg->elements[el_idx].flags) == LDB_FLAG_MOD_REPLACE) &&
+ 					req_msg->elements[el_idx].num_values == 0)) {
+ 					if (ldb_msg_find_element(modify_msg,
+ 								 req_msg->elements[el_idx].name) != NULL) {
+-- 
+2.35.0
+
+
+From 1fb5b08537f230e6ef02b7dfae1de802810c96b0 Mon Sep 17 00:00:00 2001
+From: Joseph Sutton <josephsutton at catalyst.net.nz>
+Date: Tue, 21 Jun 2022 14:49:51 +1200
+Subject: [PATCH 04/18] CVE-2022-32746 s4:torture: Fix LDB flags comparison
+
+LDB_FLAG_MOD_* values are not actually flags, and the previous
+comparison was equivalent to
+
+(el->flags & LDB_FLAG_MOD_MASK) == 0
+
+which is only true if none of the LDB_FLAG_MOD_* values are set. Correct
+the expression to what it was probably intended to be.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15009
+
+Signed-off-by: Joseph Sutton <josephsutton at catalyst.net.nz>
+---
+ source4/torture/drs/rpc/dssync.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/source4/torture/drs/rpc/dssync.c b/source4/torture/drs/rpc/dssync.c
+index 6a8a8b5492b..53b9c000a06 100644
+--- a/source4/torture/drs/rpc/dssync.c
++++ b/source4/torture/drs/rpc/dssync.c
+@@ -525,7 +525,9 @@ static bool test_analyse_objects(struct torture_context *tctx,
+ 				el = &new_msg->elements[idx];
+ 				a = dsdb_attribute_by_lDAPDisplayName(ldap_schema,
+ 				                                      el->name);
+-				if (!(el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE))) {
++				if (LDB_FLAG_MOD_TYPE(el->flags) != LDB_FLAG_MOD_ADD &&
++				    LDB_FLAG_MOD_TYPE(el->flags) != LDB_FLAG_MOD_REPLACE)
++				{
+ 					/* DRS only value */
+ 					is_warning = false;
+ 				} else if (a->linkID & 1) {
+-- 
+2.35.0
+
+
+From f5c0790ba29ce67c3633b8b6b3c645544d57ac73 Mon Sep 17 00:00:00 2001
+From: Joseph Sutton <josephsutton at catalyst.net.nz>
+Date: Tue, 21 Jun 2022 15:22:47 +1200
+Subject: [PATCH 05/18] CVE-2022-32746 s4/dsdb/acl: Fix LDB flags comparison
+
+LDB_FLAG_MOD_* values are not actually flags, and the previous
+comparison was equivalent to
+
+(el->flags & LDB_FLAG_MOD_MASK) == 0
+
+which is only true if none of the LDB_FLAG_MOD_* values are set, so we
+would not successfully return if the element was a DELETE. Correct the
+expression to what it was intended to be.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15009
+
+Signed-off-by: Joseph Sutton <josephsutton at catalyst.net.nz>
+---
+ source4/dsdb/samdb/ldb_modules/acl.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/source4/dsdb/samdb/ldb_modules/acl.c b/source4/dsdb/samdb/ldb_modules/acl.c
+index 712724909e3..2fd01c587af 100644
+--- a/source4/dsdb/samdb/ldb_modules/acl.c
++++ b/source4/dsdb/samdb/ldb_modules/acl.c
+@@ -731,8 +731,9 @@ static int acl_check_spn(TALLOC_CTX *mem_ctx,
+ 		 * If not add or replace (eg delete),
+ 		 * return success
+ 		 */
+-		if ((el->flags
+-		     & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE)) == 0) {
++		if (LDB_FLAG_MOD_TYPE(el->flags) != LDB_FLAG_MOD_ADD &&
++		    LDB_FLAG_MOD_TYPE(el->flags) != LDB_FLAG_MOD_REPLACE)
++		{
+ 			talloc_free(tmp_ctx);
+ 			return LDB_SUCCESS;
+ 		}
+-- 
+2.35.0
+
+
+From 07b8a1d0899f016bb313eb1b961c0fe04330ab19 Mon Sep 17 00:00:00 2001
+From: Joseph Sutton <josephsutton at catalyst.net.nz>
+Date: Wed, 16 Feb 2022 12:43:52 +1300
+Subject: [PATCH 06/18] CVE-2022-32746 ldb:rdn_name: Use LDB_FLAG_MOD_TYPE()
+ for flags equality check
+
+Now unrelated flags will no longer affect the result.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15009
+
+Signed-off-by: Joseph Sutton <josephsutton at catalyst.net.nz>
+---
+ lib/ldb/modules/rdn_name.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/lib/ldb/modules/rdn_name.c b/lib/ldb/modules/rdn_name.c
+index e69ad9315ae..25cffe07591 100644
+--- a/lib/ldb/modules/rdn_name.c
++++ b/lib/ldb/modules/rdn_name.c
+@@ -545,7 +545,7 @@ static int rdn_name_modify(struct ldb_module *module, struct ldb_request *req)
+ 	if (e != NULL) {
+ 		ldb_asprintf_errstring(ldb, "Modify of 'distinguishedName' on %s not permitted, must use 'rename' operation instead",
+ 				       ldb_dn_get_linearized(req->op.mod.message->dn));
+-		if (e->flags == LDB_FLAG_MOD_REPLACE) {
++		if (LDB_FLAG_MOD_TYPE(e->flags) == LDB_FLAG_MOD_REPLACE) {
+ 			return LDB_ERR_CONSTRAINT_VIOLATION;
+ 		} else {
+ 			return LDB_ERR_UNWILLING_TO_PERFORM;
+-- 
+2.35.0
+
+
+From 2a7b8e6b737c8b3842781807090fd4e7bb339200 Mon Sep 17 00:00:00 2001
+From: Joseph Sutton <josephsutton at catalyst.net.nz>
+Date: Tue, 14 Jun 2022 19:49:19 +1200
+Subject: [PATCH 07/18] CVE-2022-32746 s4/dsdb/repl_meta_data: Use
+ LDB_FLAG_MOD_TYPE() for flags equality check
+
+Now unrelated flags will no longer affect the result.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15009
+
+Signed-off-by: Joseph Sutton <josephsutton at catalyst.net.nz>
+---
+ source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
+index 870185ee1d3..e7020f588e5 100644
+--- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
++++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
+@@ -3523,7 +3523,7 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
+ 			return ldb_module_operr(module);
+ 		}
+ 
+-		if (req->op.mod.message->elements[0].flags != LDB_FLAG_MOD_REPLACE) {
++		if (LDB_FLAG_MOD_TYPE(req->op.mod.message->elements[0].flags) != LDB_FLAG_MOD_REPLACE) {
+ 			return ldb_module_operr(module);
+ 		}
+ 
+@@ -3556,11 +3556,11 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
+ 			return ldb_module_operr(module);
+ 		}
+ 
+-		if (req->op.mod.message->elements[0].flags != LDB_FLAG_MOD_DELETE) {
++		if (LDB_FLAG_MOD_TYPE(req->op.mod.message->elements[0].flags) != LDB_FLAG_MOD_DELETE) {
+ 			return ldb_module_operr(module);
+ 		}
+ 
+-		if (req->op.mod.message->elements[1].flags != LDB_FLAG_MOD_ADD) {
++		if (LDB_FLAG_MOD_TYPE(req->op.mod.message->elements[1].flags) != LDB_FLAG_MOD_ADD) {
+ 			return ldb_module_operr(module);
+ 		}
+ 
+@@ -3643,7 +3643,7 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
+ 			return ldb_module_operr(module);
+ 		}
+ 
+-		if (msg->elements[0].flags != LDB_FLAG_MOD_ADD) {
++		if (LDB_FLAG_MOD_TYPE(msg->elements[0].flags) != LDB_FLAG_MOD_ADD) {
+ 			talloc_free(ac);
+ 			return ldb_module_operr(module);
+ 		}
+-- 
+2.35.0
+
+
+From 51d40e420f0d306fe4b3ea326b6a57988311e60d Mon Sep 17 00:00:00 2001
+From: Joseph Sutton <josephsutton at catalyst.net.nz>
+Date: Tue, 14 Jun 2022 21:11:33 +1200
+Subject: [PATCH 08/18] CVE-2022-32746 s4/dsdb/tombstone_reanimate: Use
+ LDB_FLAG_MOD_TYPE() for flags equality check
+
+Now unrelated flags will no longer affect the result.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15009
+
+Signed-off-by: Joseph Sutton <josephsutton at catalyst.net.nz>
+---
+ source4/dsdb/samdb/ldb_modules/tombstone_reanimate.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/source4/dsdb/samdb/ldb_modules/tombstone_reanimate.c b/source4/dsdb/samdb/ldb_modules/tombstone_reanimate.c
+index 64e05195798..5f8911c66be 100644
+--- a/source4/dsdb/samdb/ldb_modules/tombstone_reanimate.c
++++ b/source4/dsdb/samdb/ldb_modules/tombstone_reanimate.c
+@@ -104,7 +104,7 @@ static bool is_tombstone_reanimate_request(struct ldb_request *req,
+ 	if (el_dn == NULL) {
+ 		return false;
+ 	}
+-	if (el_dn->flags != LDB_FLAG_MOD_REPLACE) {
++	if (LDB_FLAG_MOD_TYPE(el_dn->flags) != LDB_FLAG_MOD_REPLACE) {
+ 		return false;
+ 	}
+ 	if (el_dn->num_values != 1) {
+@@ -117,7 +117,7 @@ static bool is_tombstone_reanimate_request(struct ldb_request *req,
+ 		return false;
+ 	}
+ 
+-	if (el_deleted->flags != LDB_FLAG_MOD_DELETE) {
++	if (LDB_FLAG_MOD_TYPE(el_deleted->flags) != LDB_FLAG_MOD_DELETE) {
+ 		return false;
+ 	}
+ 
+-- 
+2.35.0
+
+
+From f59fb058ebb38ce91bf191b5cd888145b4776f42 Mon Sep 17 00:00:00 2001
+From: Joseph Sutton <josephsutton at catalyst.net.nz>
+Date: Tue, 14 Jun 2022 21:12:39 +1200
+Subject: [PATCH 09/18] CVE-2022-32746 s4/registry: Use LDB_FLAG_MOD_TYPE() for
+ flags equality check
+
+Now unrelated flags will no longer affect the result.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15009
+
+Signed-off-by: Joseph Sutton <josephsutton at catalyst.net.nz>
+---
+ source4/lib/registry/ldb.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/source4/lib/registry/ldb.c b/source4/lib/registry/ldb.c
+index c0b13e0d4ce..ab5a0f3a128 100644
+--- a/source4/lib/registry/ldb.c
++++ b/source4/lib/registry/ldb.c
+@@ -856,7 +856,7 @@ static WERROR ldb_set_value(struct hive_key *parent,
+ 
+ 	/* Try first a "modify" and if this doesn't work do try an "add" */
+ 	for (i = 0; i < msg->num_elements; i++) {
+-		if (msg->elements[i].flags != LDB_FLAG_MOD_DELETE) {
++		if (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) != LDB_FLAG_MOD_DELETE) {
+ 			msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
+ 		}
+ 	}
+-- 
+2.35.0
+
+
+From 37a606628f14d585ea12e1dd4e680dda92ce4620 Mon Sep 17 00:00:00 2001
+From: Joseph Sutton <josephsutton at catalyst.net.nz>
+Date: Mon, 21 Feb 2022 16:10:32 +1300
+Subject: [PATCH 10/18] CVE-2022-32746 ldb: Add flag to mark message element
+ values as shared
+
+When making a shallow copy of an ldb message, mark the message elements
+of the copy as sharing their values with the message elements in the
+original message.
+
+This flag value will be heeded in the next commit.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15009
+
+Signed-off-by: Joseph Sutton <josephsutton at catalyst.net.nz>
+---
+ lib/ldb/common/ldb_msg.c     | 43 +++++++++++++++++++++++++++++++-----
+ lib/ldb/include/ldb_module.h |  6 +++++
+ 2 files changed, 43 insertions(+), 6 deletions(-)
+
+diff --git a/lib/ldb/common/ldb_msg.c b/lib/ldb/common/ldb_msg.c
+index 57dfc5a04c2..2a9ce384bb9 100644
+--- a/lib/ldb/common/ldb_msg.c
++++ b/lib/ldb/common/ldb_msg.c
+@@ -833,11 +833,7 @@ void ldb_msg_sort_elements(struct ldb_message *msg)
+ 		       ldb_msg_element_compare_name);
+ }
+ 
+-/*
+-  shallow copy a message - copying only the elements array so that the caller
+-  can safely add new elements without changing the message
+-*/
+-struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
++static struct ldb_message *ldb_msg_copy_shallow_impl(TALLOC_CTX *mem_ctx,
+ 					 const struct ldb_message *msg)
+ {
+ 	struct ldb_message *msg2;
+@@ -863,6 +859,35 @@ failed:
+ 	return NULL;
+ }
+ 
++/*
++  shallow copy a message - copying only the elements array so that the caller
++  can safely add new elements without changing the message
++*/
++struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
++					 const struct ldb_message *msg)
++{
++	struct ldb_message *msg2;
++	unsigned int i;
++
++	msg2 = ldb_msg_copy_shallow_impl(mem_ctx, msg);
++	if (msg2 == NULL) {
++		return NULL;
++	}
++
++	for (i = 0; i < msg2->num_elements; ++i) {
++		/*
++		 * Mark this message's elements as sharing their values with the
++		 * original message, so that we don't inadvertently modify or
++		 * free them. We don't mark the original message element as
++		 * shared, so the original message element should not be
++		 * modified or freed while the shallow copy lives.
++		 */
++		struct ldb_message_element *el = &msg2->elements[i];
++		el->flags |= LDB_FLAG_INTERNAL_SHARED_VALUES;
++	}
++
++        return msg2;
++}
+ 
+ /*
+   copy a message, allocating new memory for all parts
+@@ -873,7 +898,7 @@ struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
+ 	struct ldb_message *msg2;
+ 	unsigned int i, j;
+ 
+-	msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
++	msg2 = ldb_msg_copy_shallow_impl(mem_ctx, msg);
+ 	if (msg2 == NULL) return NULL;
+ 
+ 	if (msg2->dn != NULL) {
+@@ -894,6 +919,12 @@ struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
+ 				goto failed;
+ 			}
+ 		}
++
++                /*
++                 * Since we copied this element's values, we can mark them as
++                 * not shared.
++		 */
++		el->flags &= ~LDB_FLAG_INTERNAL_SHARED_VALUES;
+ 	}
+ 
+ 	return msg2;
+diff --git a/lib/ldb/include/ldb_module.h b/lib/ldb/include/ldb_module.h
+index 8c1e5ee7936..4c7c85a17f0 100644
+--- a/lib/ldb/include/ldb_module.h
++++ b/lib/ldb/include/ldb_module.h
+@@ -96,6 +96,12 @@ struct ldb_module;
+  */
+ #define LDB_FLAG_INTERNAL_FORCE_UNIQUE_INDEX 0x100
+ 
++/*
++ * indicates that this element's values are shared with another element (for
++ * example, in a shallow copy of an ldb_message) and should not be freed
++ */
++#define LDB_FLAG_INTERNAL_SHARED_VALUES 0x200
++
+ /* an extended match rule that always fails to match */
+ #define SAMBA_LDAP_MATCH_ALWAYS_FALSE "1.3.6.1.4.1.7165.4.5.1"
+ 
+-- 
+2.35.0
+
+
+From e71ad28101f0703a80873b11459d0c9cef8fad5a Mon Sep 17 00:00:00 2001
+From: Joseph Sutton <josephsutton at catalyst.net.nz>
+Date: Wed, 16 Feb 2022 12:35:13 +1300
+Subject: [PATCH 11/18] CVE-2022-32746 ldb: Ensure shallow copy modifications
+ do not affect original message
+
+Using the newly added ldb flag, we can now detect when a message has
+been shallow-copied so that its elements share their values with the
+original message elements. Then when adding values to the copied
+message, we now make a copy of the shared values array first.
+
+This should prevent a use-after-free that occurred in LDB modules when
+new values were added to a shallow copy of a message by calling
+talloc_realloc() on the original values array, invalidating the 'values'
+pointer in the original message element. The original values pointer can
+later be used in the database audit logging module which logs database
+requests, and potentially cause a crash.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15009
+
+Signed-off-by: Joseph Sutton <josephsutton at catalyst.net.nz>
+---
+ lib/ldb/common/ldb_msg.c   | 52 ++++++++++++++++++++++++++++++++------
+ lib/ldb/include/ldb.h      |  6 +++++
+ source4/dsdb/common/util.c | 20 +++++----------
+ 3 files changed, 56 insertions(+), 22 deletions(-)
+
+diff --git a/lib/ldb/common/ldb_msg.c b/lib/ldb/common/ldb_msg.c
+index 2a9ce384bb9..44d3b29e9a7 100644
+--- a/lib/ldb/common/ldb_msg.c
++++ b/lib/ldb/common/ldb_msg.c
+@@ -417,6 +417,47 @@ int ldb_msg_add(struct ldb_message *msg,
+ 	return LDB_SUCCESS;
+ }
+ 
++/*
++ * add a value to a message element
++ */
++int ldb_msg_element_add_value(TALLOC_CTX *mem_ctx,
++			      struct ldb_message_element *el,
++			      const struct ldb_val *val)
++{
++	struct ldb_val *vals;
++
++	if (el->flags & LDB_FLAG_INTERNAL_SHARED_VALUES) {
++		/*
++		 * Another message is using this message element's values array,
++		 * so we don't want to make any modifications to the original
++		 * message, or potentially invalidate its own values by calling
++		 * talloc_realloc(). Make a copy instead.
++		 */
++		el->flags &= ~LDB_FLAG_INTERNAL_SHARED_VALUES;
++
++		vals = talloc_array(mem_ctx, struct ldb_val,
++				    el->num_values + 1);
++		if (vals == NULL) {
++			return LDB_ERR_OPERATIONS_ERROR;
++		}
++
++		if (el->values != NULL) {
++			memcpy(vals, el->values, el->num_values * sizeof(struct ldb_val));
++		}
++	} else {
++		vals = talloc_realloc(mem_ctx, el->values, struct ldb_val,
++				      el->num_values + 1);
++		if (vals == NULL) {
++			return LDB_ERR_OPERATIONS_ERROR;
++		}
++	}
++	el->values = vals;
++	el->values[el->num_values] = *val;
++	el->num_values++;
++
++	return LDB_SUCCESS;
++}
++
+ /*
+   add a value to a message
+ */
+@@ -426,7 +467,6 @@ int ldb_msg_add_value(struct ldb_message *msg,
+ 		      struct ldb_message_element **return_el)
+ {
+ 	struct ldb_message_element *el;
+-	struct ldb_val *vals;
+ 	int ret;
+ 
+ 	el = ldb_msg_find_element(msg, attr_name);
+@@ -437,14 +477,10 @@ int ldb_msg_add_value(struct ldb_message *msg,
+ 		}
+ 	}
+ 
+-	vals = talloc_realloc(msg->elements, el->values, struct ldb_val,
+-			      el->num_values+1);
+-	if (!vals) {
+-		return LDB_ERR_OPERATIONS_ERROR;
++	ret = ldb_msg_element_add_value(msg->elements, el, val);
++	if (ret != LDB_SUCCESS) {
++		return ret;
+ 	}
+-	el->values = vals;
+-	el->values[el->num_values] = *val;
+-	el->num_values++;
+ 
+ 	if (return_el) {
+ 		*return_el = el;
+diff --git a/lib/ldb/include/ldb.h b/lib/ldb/include/ldb.h
+index f5f02c9a344..45b91cd5810 100644
+--- a/lib/ldb/include/ldb.h
++++ b/lib/ldb/include/ldb.h
+@@ -1980,6 +1980,12 @@ int ldb_msg_add_empty(struct ldb_message *msg,
+ 		int flags,
+ 		struct ldb_message_element **return_el);
+ 
++/**
++   add a value to a message element
++*/
++int ldb_msg_element_add_value(TALLOC_CTX *mem_ctx,
++			      struct ldb_message_element *el,
++			      const struct ldb_val *val);
+ /**
+    add a element to a ldb_message
+ */
+diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c
+index 62e04d08003..38d12c1c2b1 100644
+--- a/source4/dsdb/common/util.c
++++ b/source4/dsdb/common/util.c
+@@ -812,7 +812,7 @@ int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
+ 			 const char *value)
+ {
+ 	struct ldb_message_element *el;
+-	struct ldb_val val, *vals;
++	struct ldb_val val;
+ 	char *v;
+ 	unsigned int i;
+ 	bool found = false;
+@@ -847,14 +847,10 @@ int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
+ 		}
+ 	}
+ 
+-	vals = talloc_realloc(msg->elements, el->values, struct ldb_val,
+-			      el->num_values + 1);
+-	if (vals == NULL) {
++	ret = ldb_msg_element_add_value(msg->elements, el, &val);
++	if (ret != LDB_SUCCESS) {
+ 		return ldb_oom(sam_ldb);
+ 	}
+-	el->values = vals;
+-	el->values[el->num_values] = val;
+-	++(el->num_values);
+ 
+ 	return LDB_SUCCESS;
+ }
+@@ -868,7 +864,7 @@ int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
+ 			 const char *value)
+ {
+ 	struct ldb_message_element *el;
+-	struct ldb_val val, *vals;
++	struct ldb_val val;
+ 	char *v;
+ 	unsigned int i;
+ 	bool found = false;
+@@ -903,14 +899,10 @@ int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
+ 		}
+ 	}
+ 
+-	vals = talloc_realloc(msg->elements, el->values, struct ldb_val,
+-			      el->num_values + 1);
+-	if (vals == NULL) {
++	ret = ldb_msg_element_add_value(msg->elements, el, &val);
++	if (ret != LDB_SUCCESS) {
+ 		return ldb_oom(sam_ldb);
+ 	}
+-	el->values = vals;
+-	el->values[el->num_values] = val;
+-	++(el->num_values);
+ 
+ 	return LDB_SUCCESS;
+ }
+-- 
+2.35.0
+
+
+From a5d537e7b8b0ce292dcfe2093a54becaba6c3464 Mon Sep 17 00:00:00 2001
+From: Joseph Sutton <josephsutton at catalyst.net.nz>
+Date: Wed, 16 Feb 2022 16:30:03 +1300
+Subject: [PATCH 12/18] CVE-2022-32746 ldb: Add functions for appending to an
+ ldb_message
+
+Currently, there are many places where we use ldb_msg_add_empty() to add
+an empty element to a message, and then call ldb_msg_add_value() or
+similar to add values to that element. However, this performs an
+unnecessary search of the message's elements to locate the new element.
+Moreover, if an element with the same attribute name already exists
+earlier in the message, the values will be added to that element,
+instead of to the intended newly added element.
+
+A similar pattern exists where we add values to a message, and then call
+ldb_msg_find_element() to locate that message element and sets its flags
+to (e.g.) LDB_FLAG_MOD_REPLACE. This also performs an unnecessary
+search, and may locate the wrong message element for setting the flags.
+
+To avoid these problems, add functions for appending a value to a
+message, so that a particular value can be added to the end of a message
+in a single operation.
+
+For ADD requests, it is important that no two message elements share the
+same attribute name, otherwise things will break. (Normally,
+ldb_msg_normalize() is called before processing the request to help
+ensure this.) Thus, we must be careful not to append an attribute to an
+ADD message, unless we are sure (e.g. through ldb_msg_find_element())
+that an existing element for that attribute is not present.
+
+These functions will be used in the next commit.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15009
+
+Signed-off-by: Joseph Sutton <josephsutton at catalyst.net.nz>
+---
+ lib/ldb/common/ldb_msg.c | 165 ++++++++++++++++++++++++++++++++++++++-
+ lib/ldb/include/ldb.h    |  24 ++++++
+ 2 files changed, 185 insertions(+), 4 deletions(-)
+
+diff --git a/lib/ldb/common/ldb_msg.c b/lib/ldb/common/ldb_msg.c
+index 44d3b29e9a7..9cd7998e21c 100644
+--- a/lib/ldb/common/ldb_msg.c
++++ b/lib/ldb/common/ldb_msg.c
+@@ -509,12 +509,15 @@ int ldb_msg_add_steal_value(struct ldb_message *msg,
+ 
+ 
+ /*
+-  add a string element to a message
++  add a string element to a message, specifying flags
+ */
+-int ldb_msg_add_string(struct ldb_message *msg,
+-		       const char *attr_name, const char *str)
++int ldb_msg_add_string_flags(struct ldb_message *msg,
++			     const char *attr_name, const char *str,
++			     int flags)
+ {
+ 	struct ldb_val val;
++	int ret;
++	struct ldb_message_element *el = NULL;
+ 
+ 	val.data = discard_const_p(uint8_t, str);
+ 	val.length = strlen(str);
+@@ -524,7 +527,25 @@ int ldb_msg_add_string(struct ldb_message *msg,
+ 		return LDB_SUCCESS;
+ 	}
+ 
+-	return ldb_msg_add_value(msg, attr_name, &val, NULL);
++	ret = ldb_msg_add_value(msg, attr_name, &val, &el);
++	if (ret != LDB_SUCCESS) {
++		return ret;
++	}
++
++	if (flags != 0) {
++		el->flags = flags;
++	}
++
++	return LDB_SUCCESS;
++}
++
++/*
++  add a string element to a message
++*/
++int ldb_msg_add_string(struct ldb_message *msg,
++		       const char *attr_name, const char *str)
++{
++	return ldb_msg_add_string_flags(msg, attr_name, str, 0);
+ }
+ 
+ /*
+@@ -586,6 +607,142 @@ int ldb_msg_add_fmt(struct ldb_message *msg,
+ 	return ldb_msg_add_steal_value(msg, attr_name, &val);
+ }
+ 
++static int ldb_msg_append_value_impl(struct ldb_message *msg,
++				     const char *attr_name,
++				     const struct ldb_val *val,
++				     int flags,
++				     struct ldb_message_element **return_el)
++{
++	struct ldb_message_element *el = NULL;
++	int ret;
++
++	ret = ldb_msg_add_empty(msg, attr_name, flags, &el);
++	if (ret != LDB_SUCCESS) {
++		return ret;
++	}
++
++	ret = ldb_msg_element_add_value(msg->elements, el, val);
++	if (ret != LDB_SUCCESS) {
++		return ret;
++	}
++
++	if (return_el != NULL) {
++		*return_el = el;
++	}
++
++	return LDB_SUCCESS;
++}
++
++/*
++  append a value to a message
++*/
++int ldb_msg_append_value(struct ldb_message *msg,
++			 const char *attr_name,
++			 const struct ldb_val *val,
++			 int flags)
++{
++	return ldb_msg_append_value_impl(msg, attr_name, val, flags, NULL);
++}
++
++/*
++  append a value to a message, stealing it into the 'right' place
++*/
++int ldb_msg_append_steal_value(struct ldb_message *msg,
++			       const char *attr_name,
++			       struct ldb_val *val,
++			       int flags)
++{
++	int ret;
++	struct ldb_message_element *el = NULL;
++
++	ret = ldb_msg_append_value_impl(msg, attr_name, val, flags, &el);
++	if (ret == LDB_SUCCESS) {
++		talloc_steal(el->values, val->data);
++	}
++	return ret;
++}
++
++/*
++  append a string element to a message, stealing it into the 'right' place
++*/
++int ldb_msg_append_steal_string(struct ldb_message *msg,
++				const char *attr_name, char *str,
++				int flags)
++{
++	struct ldb_val val;
++
++	val.data = (uint8_t *)str;
++	val.length = strlen(str);
++
++	if (val.length == 0) {
++		/* allow empty strings as non-existent attributes */
++		return LDB_SUCCESS;
++	}
++
++	return ldb_msg_append_steal_value(msg, attr_name, &val, flags);
++}
++
++/*
++  append a string element to a message
++*/
++int ldb_msg_append_string(struct ldb_message *msg,
++			  const char *attr_name, const char *str, int flags)
++{
++	struct ldb_val val;
++
++	val.data = discard_const_p(uint8_t, str);
++	val.length = strlen(str);
++
++	if (val.length == 0) {
++		/* allow empty strings as non-existent attributes */
++		return LDB_SUCCESS;
++	}
++
++	return ldb_msg_append_value(msg, attr_name, &val, flags);
++}
++
++/*
++  append a DN element to a message
++  WARNING: this uses the linearized string from the dn, and does not
++  copy the string.
++*/
++int ldb_msg_append_linearized_dn(struct ldb_message *msg, const char *attr_name,
++				 struct ldb_dn *dn, int flags)
++{
++	char *str = ldb_dn_alloc_linearized(msg, dn);
++
++	if (str == NULL) {
++		/* we don't want to have unknown DNs added */
++		return LDB_ERR_OPERATIONS_ERROR;
++	}
++
++	return ldb_msg_append_steal_string(msg, attr_name, str, flags);
++}
++
++/*
++  append a printf formatted element to a message
++*/
++int ldb_msg_append_fmt(struct ldb_message *msg, int flags,
++		       const char *attr_name, const char *fmt, ...)
++{
++	struct ldb_val val;
++	va_list ap;
++	char *str = NULL;
++
++	va_start(ap, fmt);
++	str = talloc_vasprintf(msg, fmt, ap);
++	va_end(ap);
++
++	if (str == NULL) {
++		return LDB_ERR_OPERATIONS_ERROR;
++	}
++
++	val.data   = (uint8_t *)str;
++	val.length = strlen(str);
++
++	return ldb_msg_append_steal_value(msg, attr_name, &val, flags);
++}
++
+ /*
+   compare two ldb_message_element structures
+   assumes case sensitive comparison
+diff --git a/lib/ldb/include/ldb.h b/lib/ldb/include/ldb.h
+index 45b91cd5810..0c3dbc3f22d 100644
+--- a/lib/ldb/include/ldb.h
++++ b/lib/ldb/include/ldb.h
+@@ -2001,12 +2001,36 @@ int ldb_msg_add_steal_value(struct ldb_message *msg,
+ 		      struct ldb_val *val);
+ int ldb_msg_add_steal_string(struct ldb_message *msg,
+ 			     const char *attr_name, char *str);
++int ldb_msg_add_string_flags(struct ldb_message *msg,
++			     const char *attr_name, const char *str,
++			     int flags);
+ int ldb_msg_add_string(struct ldb_message *msg,
+ 		       const char *attr_name, const char *str);
+ int ldb_msg_add_linearized_dn(struct ldb_message *msg, const char *attr_name,
+ 			      struct ldb_dn *dn);
+ int ldb_msg_add_fmt(struct ldb_message *msg,
+ 		    const char *attr_name, const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
++/**
++   append a element to a ldb_message
++*/
++int ldb_msg_append_value(struct ldb_message *msg,
++			 const char *attr_name,
++			 const struct ldb_val *val,
++			 int flags);
++int ldb_msg_append_steal_value(struct ldb_message *msg,
++			       const char *attr_name,
++			       struct ldb_val *val,
++			       int flags);
++int ldb_msg_append_steal_string(struct ldb_message *msg,
++				const char *attr_name, char *str,
++				int flags);
++int ldb_msg_append_string(struct ldb_message *msg,
++			  const char *attr_name, const char *str,
++			  int flags);
++int ldb_msg_append_linearized_dn(struct ldb_message *msg, const char *attr_name,
++				 struct ldb_dn *dn, int flags);
++int ldb_msg_append_fmt(struct ldb_message *msg, int flags,
++		       const char *attr_name, const char *fmt, ...) PRINTF_ATTRIBUTE(4,5);
+ 
+ /**
+    compare two message elements - return 0 on match
+-- 
+2.35.0
+
+
+From 884513d579ecb858e9fce5677d7314e82fcee4f2 Mon Sep 17 00:00:00 2001
+From: Joseph Sutton <josephsutton at catalyst.net.nz>
+Date: Mon, 21 Feb 2022 16:27:37 +1300
+Subject: [PATCH 13/18] CVE-2022-32746 ldb: Make use of functions for appending
+ to an ldb_message
+
+This aims to minimise usage of the error-prone pattern of searching for
+a just-added message element in order to make modifications to it (and
+potentially finding the wrong element).
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15009
+
+Signed-off-by: Joseph Sutton <josephsutton at catalyst.net.nz>
+---
+ lib/ldb/ldb_map/ldb_map.c                     |   5 +-
+ lib/ldb/ldb_map/ldb_map_inbound.c             |   9 +-
+ lib/ldb/modules/rdn_name.c                    |  22 +---
+ source3/passdb/pdb_samba_dsdb.c               |  14 +--
+ source4/dns_server/dnsserver_common.c         |  12 +-
+ source4/dsdb/common/util.c                    | 114 ++++++++++++++----
+ source4/dsdb/samdb/ldb_modules/descriptor.c   |  10 +-
+ source4/dsdb/samdb/ldb_modules/objectguid.c   |  20 +--
+ .../dsdb/samdb/ldb_modules/partition_init.c   |  14 +--
+ .../dsdb/samdb/ldb_modules/repl_meta_data.c   |  24 +---
+ source4/dsdb/samdb/ldb_modules/samldb.c       |  78 +++++-------
+ .../samdb/ldb_modules/tombstone_reanimate.c   |  12 +-
+ source4/nbt_server/wins/winsdb.c              |  13 +-
+ source4/rpc_server/lsa/dcesrv_lsa.c           |  55 +++------
+ source4/winbind/idmap.c                       |  10 +-
+ 15 files changed, 183 insertions(+), 229 deletions(-)
+
+diff --git a/lib/ldb/ldb_map/ldb_map.c b/lib/ldb/ldb_map/ldb_map.c
+index b453dff80d2..c7b0c228631 100644
+--- a/lib/ldb/ldb_map/ldb_map.c
++++ b/lib/ldb/ldb_map/ldb_map.c
+@@ -946,10 +946,7 @@ struct ldb_request *map_build_fixup_req(struct map_context *ac,
+ 	if ( ! dn || ! ldb_dn_validate(msg->dn)) {
+ 		goto failed;
+ 	}
+-	if (ldb_msg_add_empty(msg, IS_MAPPED, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
+-		goto failed;
+-	}
+-	if (ldb_msg_add_string(msg, IS_MAPPED, dn) != 0) {
++	if (ldb_msg_append_string(msg, IS_MAPPED, dn, LDB_FLAG_MOD_REPLACE) != 0) {
+ 		goto failed;
+ 	}
+ 
+diff --git a/lib/ldb/ldb_map/ldb_map_inbound.c b/lib/ldb/ldb_map/ldb_map_inbound.c
+index 324295737da..50b9427c26c 100644
+--- a/lib/ldb/ldb_map/ldb_map_inbound.c
++++ b/lib/ldb/ldb_map/ldb_map_inbound.c
+@@ -569,12 +569,9 @@ static int map_modify_do_local(struct map_context *ac)
+ 		/* No local record present, add it instead */
+ 		/* Add local 'IS_MAPPED' */
+ 		/* TODO: use GUIDs here instead */
+-		if (ldb_msg_add_empty(ac->local_msg, IS_MAPPED,
+-					LDB_FLAG_MOD_ADD, NULL) != 0) {
+-			return LDB_ERR_OPERATIONS_ERROR;
+-		}
+-		ret = ldb_msg_add_linearized_dn(ac->local_msg, IS_MAPPED,
+-						ac->remote_req->op.mod.message->dn);
++		ret = ldb_msg_append_linearized_dn(ac->local_msg, IS_MAPPED,
++						   ac->remote_req->op.mod.message->dn,
++						   LDB_FLAG_MOD_ADD);
+ 		if (ret != 0) {
+ 			return LDB_ERR_OPERATIONS_ERROR;
+ 		}
+diff --git a/lib/ldb/modules/rdn_name.c b/lib/ldb/modules/rdn_name.c
+index 25cffe07591..3cb62bf567b 100644
+--- a/lib/ldb/modules/rdn_name.c
++++ b/lib/ldb/modules/rdn_name.c
+@@ -308,16 +308,10 @@ static int rdn_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
+ 	}
+ 	rdn_val = ldb_val_dup(msg, rdn_val_p);
+ 
+-	if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
++	if (ldb_msg_append_value(msg, rdn_name, &rdn_val, LDB_FLAG_MOD_REPLACE) != 0) {
+ 		goto error;
+ 	}
+-	if (ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL) != 0) {
+-		goto error;
+-	}
+-	if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
+-		goto error;
+-	}
+-	if (ldb_msg_add_value(msg, "name", &rdn_val, NULL) != 0) {
++	if (ldb_msg_append_value(msg, "name", &rdn_val, LDB_FLAG_MOD_REPLACE) != 0) {
+ 		goto error;
+ 	}
+ 
+@@ -466,11 +460,7 @@ static int rdn_name_modify(struct ldb_module *module, struct ldb_request *req)
+ 		if (ret != 0) {
+ 			return ldb_module_oom(module);
+ 		}
+-		ret = ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_ADD, NULL);
+-		if (ret != 0) {
+-			return ldb_module_oom(module);
+-		}
+-		ret = ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL);
++		ret = ldb_msg_append_value(msg, rdn_name, &rdn_val, LDB_FLAG_MOD_ADD);
+ 		if (ret != 0) {
+ 			return ldb_module_oom(module);
+ 		}
+@@ -479,11 +469,7 @@ static int rdn_name_modify(struct ldb_module *module, struct ldb_request *req)
+ 		if (ret != 0) {
+ 			return ldb_module_oom(module);
+ 		}
+-		ret = ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_ADD, NULL);
+-		if (ret != 0) {
+-			return ldb_module_oom(module);
+-		}
+-		ret = ldb_msg_add_value(msg, "name", &rdn_val, NULL);
++		ret = ldb_msg_append_value(msg, "name", &rdn_val, LDB_FLAG_MOD_ADD);
+ 		if (ret != 0) {
+ 			return ldb_module_oom(module);
+ 		}
+diff --git a/source3/passdb/pdb_samba_dsdb.c b/source3/passdb/pdb_samba_dsdb.c
+index 276bda88efc..a9a04e1f097 100644
+--- a/source3/passdb/pdb_samba_dsdb.c
++++ b/source3/passdb/pdb_samba_dsdb.c
+@@ -2855,18 +2855,10 @@ static bool pdb_samba_dsdb_set_trusteddom_pw(struct pdb_methods *m,
+ 	}
+ 
+ 	msg->num_elements = 0;
+-	ret = ldb_msg_add_empty(msg, "trustAuthOutgoing",
+-				LDB_FLAG_MOD_REPLACE, NULL);
++	ret = ldb_msg_append_value(msg, "trustAuthOutgoing",
++				   &new_val, LDB_FLAG_MOD_REPLACE);
+ 	if (ret != LDB_SUCCESS) {
+-		DEBUG(0, ("ldb_msg_add_empty() failed\n"));
+-		TALLOC_FREE(tmp_ctx);
+-		ldb_transaction_cancel(state->ldb);
+-		return false;
+-	}
+-	ret = ldb_msg_add_value(msg, "trustAuthOutgoing",
+-				&new_val, NULL);
+-	if (ret != LDB_SUCCESS) {
+-		DEBUG(0, ("ldb_msg_add_value() failed\n"));
++		DEBUG(0, ("ldb_msg_append_value() failed\n"));
+ 		TALLOC_FREE(tmp_ctx);
+ 		ldb_transaction_cancel(state->ldb);
+ 		return false;
+diff --git a/source4/dns_server/dnsserver_common.c b/source4/dns_server/dnsserver_common.c
+index 8635d075be8..afc9387466c 100644
+--- a/source4/dns_server/dnsserver_common.c
++++ b/source4/dns_server/dnsserver_common.c
+@@ -1090,15 +1090,9 @@ WERROR dns_common_replace(struct ldb_context *samdb,
+ 	}
+ 
+ 	if (was_tombstoned || become_tombstoned) {
+-		ret = ldb_msg_add_empty(msg, "dNSTombstoned",
+-					LDB_FLAG_MOD_REPLACE, NULL);
+-		if (ret != LDB_SUCCESS) {
+-			werr = DNS_ERR(SERVER_FAILURE);
+-			goto exit;
+-		}
+-
+-		ret = ldb_msg_add_fmt(msg, "dNSTombstoned", "%s",
+-				      become_tombstoned ? "TRUE" : "FALSE");
++		ret = ldb_msg_append_fmt(msg, LDB_FLAG_MOD_REPLACE,
++					 "dNSTombstoned", "%s",
++					 become_tombstoned ? "TRUE" : "FALSE");
+ 		if (ret != LDB_SUCCESS) {
+ 			werr = DNS_ERR(SERVER_FAILURE);
+ 			goto exit;
+diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c
+index 38d12c1c2b1..dc2edb6d730 100644
+--- a/source4/dsdb/common/util.c
++++ b/source4/dsdb/common/util.c
+@@ -920,6 +920,16 @@ int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct l
+ 	return ldb_msg_add_string(msg, attr_name, s);
+ }
+ 
++int samdb_msg_add_int_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
++			    const char *attr_name, int v, int flags)
++{
++	const char *s = talloc_asprintf(mem_ctx, "%d", v);
++	if (s == NULL) {
++		return ldb_oom(sam_ldb);
++	}
++	return ldb_msg_add_string_flags(msg, attr_name, s, flags);
++}
++
+ /*
+  * Add an unsigned int element to a message
+  *
+@@ -938,6 +948,12 @@ int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct
+ 	return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, (int)v);
+ }
+ 
++int samdb_msg_add_uint_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
++			     const char *attr_name, unsigned int v, int flags)
++{
++	return samdb_msg_add_int_flags(sam_ldb, mem_ctx, msg, attr_name, (int)v, flags);
++}
++
+ /*
+   add a (signed) int64_t element to a message
+ */
+@@ -969,6 +985,68 @@ int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struc
+ 	return samdb_msg_add_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v);
+ }
+ 
++/*
++  append a int element to a message
++*/
++int samdb_msg_append_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
++		      const char *attr_name, int v, int flags)
++{
++	const char *s = talloc_asprintf(mem_ctx, "%d", v);
++	if (s == NULL) {
++		return ldb_oom(sam_ldb);
++	}
++	return ldb_msg_append_string(msg, attr_name, s, flags);
++}
++
++/*
++ * Append an unsigned int element to a message
++ *
++ * The issue here is that we have not yet first cast to int32_t explicitly,
++ * before we cast to an signed int to printf() into the %d or cast to a
++ * int64_t before we then cast to a long long to printf into a %lld.
++ *
++ * There are *no* unsigned integers in Active Directory LDAP, even the RID
++ * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
++ * (See the schema, and the syntax definitions in schema_syntax.c).
++ *
++ */
++int samdb_msg_append_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
++			  const char *attr_name, unsigned int v, int flags)
++{
++	return samdb_msg_append_int(sam_ldb, mem_ctx, msg, attr_name, (int)v, flags);
++}
++
++/*
++  append a (signed) int64_t element to a message
++*/
++int samdb_msg_append_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
++			   const char *attr_name, int64_t v, int flags)
++{
++	const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
++	if (s == NULL) {
++		return ldb_oom(sam_ldb);
++	}
++	return ldb_msg_append_string(msg, attr_name, s, flags);
++}
++
++/*
++ * Append an unsigned int64_t (uint64_t) element to a message
++ *
++ * The issue here is that we have not yet first cast to int32_t explicitly,
++ * before we cast to an signed int to printf() into the %d or cast to a
++ * int64_t before we then cast to a long long to printf into a %lld.
++ *
++ * There are *no* unsigned integers in Active Directory LDAP, even the RID
++ * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
++ * (See the schema, and the syntax definitions in schema_syntax.c).
++ *
++ */
++int samdb_msg_append_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
++			    const char *attr_name, uint64_t v, int flags)
++{
++	return samdb_msg_append_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v, flags);
++}
++
+ /*
+   add a samr_Password element to a message
+ */
+@@ -2810,15 +2888,8 @@ NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
+ 		tdo_msg->num_elements = 0;
+ 		TALLOC_FREE(tdo_msg->elements);
+ 
+-		ret = ldb_msg_add_empty(tdo_msg, "trustAuthIncoming",
+-					LDB_FLAG_MOD_REPLACE, NULL);
+-		if (ret != LDB_SUCCESS) {
+-			ldb_transaction_cancel(ldb);
+-			TALLOC_FREE(frame);
+-			return NT_STATUS_NO_MEMORY;
+-		}
+-		ret = ldb_msg_add_value(tdo_msg, "trustAuthIncoming",
+-					&new_val, NULL);
++		ret = ldb_msg_append_value(tdo_msg, "trustAuthIncoming",
++					   &new_val, LDB_FLAG_MOD_REPLACE);
+ 		if (ret != LDB_SUCCESS) {
+ 			ldb_transaction_cancel(ldb);
+ 			TALLOC_FREE(frame);
+@@ -3183,6 +3254,7 @@ int dsdb_find_guid_by_dn(struct ldb_context *ldb,
+ /*
+  adds the given GUID to the given ldb_message. This value is added
+  for the given attr_name (may be either "objectGUID" or "parentGUID").
++ This function is used in processing 'add' requests.
+  */
+ int dsdb_msg_add_guid(struct ldb_message *msg,
+ 		struct GUID *guid,
+@@ -5652,7 +5724,8 @@ int dsdb_user_obj_set_defaults(struct ldb_context *ldb,
+ }
+ 
+ /**
+- * Sets 'sAMAccountType on user object based on userAccountControl
++ * Sets 'sAMAccountType on user object based on userAccountControl.
++ * This function is used in processing both 'add' and 'modify' requests.
+  * @param ldb Current ldb_context
+  * @param usr_obj ldb_message representing User object
+  * @param user_account_control Value for userAccountControl flags
+@@ -5664,21 +5737,19 @@ int dsdb_user_obj_set_account_type(struct ldb_context *ldb, struct ldb_message *
+ {
+ 	int ret;
+ 	uint32_t account_type;
+-	struct ldb_message_element *el;
+ 
+ 	account_type = ds_uf2atype(user_account_control);
+ 	if (account_type == 0) {
+ 		ldb_set_errstring(ldb, "dsdb: Unrecognized account type!");
+ 		return LDB_ERR_UNWILLING_TO_PERFORM;
+ 	}
+-	ret = samdb_msg_add_uint(ldb, usr_obj, usr_obj,
+-				 "sAMAccountType",
+-				 account_type);
++	ret = samdb_msg_add_uint_flags(ldb, usr_obj, usr_obj,
++				       "sAMAccountType",
++				       account_type,
++				       LDB_FLAG_MOD_REPLACE);
+ 	if (ret != LDB_SUCCESS) {
+ 		return ret;
+ 	}
+-	el = ldb_msg_find_element(usr_obj, "sAMAccountType");
+-	el->flags = LDB_FLAG_MOD_REPLACE;
+ 
+ 	if (account_type_p) {
+ 		*account_type_p = account_type;
+@@ -5688,7 +5759,8 @@ int dsdb_user_obj_set_account_type(struct ldb_context *ldb, struct ldb_message *
+ }
+ 
+ /**
+- * Determine and set primaryGroupID based on userAccountControl value
++ * Determine and set primaryGroupID based on userAccountControl value.
++ * This function is used in processing both 'add' and 'modify' requests.
+  * @param ldb Current ldb_context
+  * @param usr_obj ldb_message representing User object
+  * @param user_account_control Value for userAccountControl flags
+@@ -5700,17 +5772,15 @@ int dsdb_user_obj_set_primary_group_id(struct ldb_context *ldb, struct ldb_messa
+ {
+ 	int ret;
+ 	uint32_t rid;
+-	struct ldb_message_element *el;
+ 
+ 	rid = ds_uf2prim_group_rid(user_account_control);
+ 
+-	ret = samdb_msg_add_uint(ldb, usr_obj, usr_obj,
+-				 "primaryGroupID", rid);
++	ret = samdb_msg_add_uint_flags(ldb, usr_obj, usr_obj,
++				       "primaryGroupID", rid,
++				       LDB_FLAG_MOD_REPLACE);
+ 	if (ret != LDB_SUCCESS) {
+ 		return ret;
+ 	}
+-	el = ldb_msg_find_element(usr_obj, "primaryGroupID");
+-	el->flags = LDB_FLAG_MOD_REPLACE;
+ 
+ 	if (group_rid_p) {
+ 		*group_rid_p = rid;
+diff --git a/source4/dsdb/samdb/ldb_modules/descriptor.c b/source4/dsdb/samdb/ldb_modules/descriptor.c
+index daa08c2ebc7..4b01961dcb0 100644
+--- a/source4/dsdb/samdb/ldb_modules/descriptor.c
++++ b/source4/dsdb/samdb/ldb_modules/descriptor.c
+@@ -857,14 +857,8 @@ static int descriptor_modify(struct ldb_module *module, struct ldb_request *req)
+ 			return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
+ 		}
+ 
+-		ret = ldb_msg_add_empty(msg, "nTSecurityDescriptor",
+-					LDB_FLAG_MOD_REPLACE,
+-					&sd_element);
+-		if (ret != LDB_SUCCESS) {
+-			return ldb_oom(ldb);
+-		}
+-		ret = ldb_msg_add_value(msg, "nTSecurityDescriptor",
+-					sd, NULL);
++		ret = ldb_msg_append_value(msg, "nTSecurityDescriptor",
++					   sd, LDB_FLAG_MOD_REPLACE);
+ 		if (ret != LDB_SUCCESS) {
+ 			return ldb_oom(ldb);
+ 		}
+diff --git a/source4/dsdb/samdb/ldb_modules/objectguid.c b/source4/dsdb/samdb/ldb_modules/objectguid.c
+index bc3260cf0d8..0fe995a5763 100644
+--- a/source4/dsdb/samdb/ldb_modules/objectguid.c
++++ b/source4/dsdb/samdb/ldb_modules/objectguid.c
+@@ -41,7 +41,6 @@
+ */
+ static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
+ {
+-	struct ldb_message_element *el;
+ 	char *s;
+ 	int ret;
+ 
+@@ -54,16 +53,13 @@ static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
+ 		return LDB_ERR_OPERATIONS_ERROR;
+ 	}
+ 
+-	ret = ldb_msg_add_string(msg, attr, s);
++	/* always set as replace. This works because on add ops, the flag
++	   is ignored */
++	ret = ldb_msg_append_string(msg, attr, s, LDB_FLAG_MOD_REPLACE);
+ 	if (ret != LDB_SUCCESS) {
+ 		return ret;
+ 	}
+ 
+-	el = ldb_msg_find_element(msg, attr);
+-	/* always set as replace. This works because on add ops, the flag
+-	   is ignored */
+-	el->flags = LDB_FLAG_MOD_REPLACE;
+-
+ 	return LDB_SUCCESS;
+ }
+ 
+@@ -73,23 +69,19 @@ static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
+ static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
+ 			      const char *attr, uint64_t v)
+ {
+-	struct ldb_message_element *el;
+ 	int ret;
+ 
+ 	if (ldb_msg_find_element(msg, attr) != NULL) {
+ 		return LDB_SUCCESS;
+ 	}
+ 
+-	ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
++	/* always set as replace. This works because on add ops, the flag
++	   is ignored */
++	ret = samdb_msg_append_uint64(ldb, msg, msg, attr, v, LDB_FLAG_MOD_REPLACE);
+ 	if (ret != LDB_SUCCESS) {
+ 		return ret;
+ 	}
+ 
+-	el = ldb_msg_find_element(msg, attr);
+-	/* always set as replace. This works because on add ops, the flag
+-	   is ignored */
+-	el->flags = LDB_FLAG_MOD_REPLACE;
+-
+ 	return LDB_SUCCESS;
+ }
+ 
+diff --git a/source4/dsdb/samdb/ldb_modules/partition_init.c b/source4/dsdb/samdb/ldb_modules/partition_init.c
+index 58c65ccedd0..484b5bffb27 100644
+--- a/source4/dsdb/samdb/ldb_modules/partition_init.c
++++ b/source4/dsdb/samdb/ldb_modules/partition_init.c
+@@ -742,10 +742,6 @@ int partition_create(struct ldb_module *module, struct ldb_request *req)
+ 		}
+ 		
+ 		mod_msg->dn = ldb_dn_new(mod_msg, ldb, DSDB_PARTITION_DN);
+-		ret = ldb_msg_add_empty(mod_msg, DSDB_PARTITION_ATTR, LDB_FLAG_MOD_ADD, NULL);
+-		if (ret != LDB_SUCCESS) {
+-			return ret;
+-		}
+ 		
+ 		casefold_dn = ldb_dn_get_casefold(dn);
+ 		
+@@ -785,18 +781,16 @@ int partition_create(struct ldb_module *module, struct ldb_request *req)
+ 		}
+ 		partition_record = talloc_asprintf(mod_msg, "%s:%s", casefold_dn, filename);
+ 
+-		ret = ldb_msg_add_steal_string(mod_msg, DSDB_PARTITION_ATTR, partition_record);
++		ret = ldb_msg_append_steal_string(mod_msg, DSDB_PARTITION_ATTR, partition_record,
++						  LDB_FLAG_MOD_ADD);
+ 		if (ret != LDB_SUCCESS) {
+ 			return ret;
+ 		}
+ 
+ 		if (ldb_request_get_control(req, DSDB_CONTROL_PARTIAL_REPLICA)) {
+ 			/* this new partition is a partial replica */
+-			ret = ldb_msg_add_empty(mod_msg, "partialReplica", LDB_FLAG_MOD_ADD, NULL);
+-			if (ret != LDB_SUCCESS) {
+-				return ret;
+-			}
+-			ret = ldb_msg_add_fmt(mod_msg, "partialReplica", "%s", ldb_dn_get_linearized(dn));
++			ret = ldb_msg_append_fmt(mod_msg, LDB_FLAG_MOD_ADD,
++						 "partialReplica", "%s", ldb_dn_get_linearized(dn));
+ 			if (ret != LDB_SUCCESS) {
+ 				return ret;
+ 			}
+diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
+index e7020f588e5..dcfbfdb7fc7 100644
+--- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
++++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
+@@ -3886,22 +3886,12 @@ static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *are
+ 				       ldb_operr(ldb));
+ 	}
+ 
+-	if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
++	if (ldb_msg_append_value(msg, rdn_name, rdn_val, LDB_FLAG_MOD_REPLACE) != 0) {
+ 		talloc_free(ares);
+ 		return ldb_module_done(ac->req, NULL, NULL,
+ 				       ldb_oom(ldb));
+ 	}
+-	if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
+-		talloc_free(ares);
+-		return ldb_module_done(ac->req, NULL, NULL,
+-				       ldb_oom(ldb));
+-	}
+-	if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
+-		talloc_free(ares);
+-		return ldb_module_done(ac->req, NULL, NULL,
+-				       ldb_oom(ldb));
+-	}
+-	if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
++	if (ldb_msg_append_value(msg, "name", rdn_val, LDB_FLAG_MOD_REPLACE) != 0) {
+ 		talloc_free(ares);
+ 		return ldb_module_done(ac->req, NULL, NULL,
+ 				       ldb_oom(ldb));
+@@ -5159,16 +5149,10 @@ static int replmd_name_modify(struct replmd_replicated_request *ar,
+ 		goto failed;
+ 	}
+ 
+-	if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
++	if (ldb_msg_append_value(msg, rdn_name, rdn_val, LDB_FLAG_MOD_REPLACE) != 0) {
+ 		goto failed;
+ 	}
+-	if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
+-		goto failed;
+-	}
+-	if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
+-		goto failed;
+-	}
+-	if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
++	if (ldb_msg_append_value(msg, "name", rdn_val, LDB_FLAG_MOD_REPLACE) != 0) {
+ 		goto failed;
+ 	}
+ 
+diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c
+index a219446bba7..b9677442e3f 100644
+--- a/source4/dsdb/samdb/ldb_modules/samldb.c
++++ b/source4/dsdb/samdb/ldb_modules/samldb.c
+@@ -1100,14 +1100,11 @@ static int samldb_rodc_add(struct samldb_ctx *ac)
+ 	return LDB_ERR_OTHER;
+ 
+ found:
+-	ret = ldb_msg_add_empty(ac->msg, "msDS-SecondaryKrbTgtNumber",
+-				LDB_FLAG_INTERNAL_DISABLE_VALIDATION, NULL);
+-	if (ret != LDB_SUCCESS) {
+-		return ldb_operr(ldb);
+-	}
+ 
+-	ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg,
+-				 "msDS-SecondaryKrbTgtNumber", krbtgt_number);
++	ldb_msg_remove_attr(ac->msg, "msDS-SecondaryKrbTgtNumber");
++	ret = samdb_msg_append_uint(ldb, ac->msg, ac->msg,
++				    "msDS-SecondaryKrbTgtNumber", krbtgt_number,
++				    LDB_FLAG_INTERNAL_DISABLE_VALIDATION);
+ 	if (ret != LDB_SUCCESS) {
+ 		return ldb_operr(ldb);
+ 	}
+@@ -1789,7 +1786,7 @@ static int samldb_objectclass_trigger(struct samldb_ctx *ac)
+ 	struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
+ 	void *skip_allocate_sids = ldb_get_opaque(ldb,
+ 						  "skip_allocate_sids");
+-	struct ldb_message_element *el, *el2;
++	struct ldb_message_element *el;
+ 	struct dom_sid *sid;
+ 	int ret;
+ 
+@@ -1923,23 +1920,17 @@ static int samldb_objectclass_trigger(struct samldb_ctx *ac)
+ 		/* "isCriticalSystemObject" might be set */
+ 		if (user_account_control &
+ 		    (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) {
+-			ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject",
+-						 "TRUE");
++			ret = ldb_msg_add_string_flags(ac->msg, "isCriticalSystemObject",
++						       "TRUE", LDB_FLAG_MOD_REPLACE);
+ 			if (ret != LDB_SUCCESS) {
+ 				return ret;
+ 			}
+-			el2 = ldb_msg_find_element(ac->msg,
+-						   "isCriticalSystemObject");
+-			el2->flags = LDB_FLAG_MOD_REPLACE;
+ 		} else if (user_account_control & UF_WORKSTATION_TRUST_ACCOUNT) {
+-			ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject",
+-						 "FALSE");
++			ret = ldb_msg_add_string_flags(ac->msg, "isCriticalSystemObject",
++						       "FALSE", LDB_FLAG_MOD_REPLACE);
+ 			if (ret != LDB_SUCCESS) {
+ 				return ret;
+ 			}
+-			el2 = ldb_msg_find_element(ac->msg,
+-						   "isCriticalSystemObject");
+-			el2->flags = LDB_FLAG_MOD_REPLACE;
+ 		}
+ 
+ 		/* Step 1.4: "userAccountControl" -> "primaryGroupID" mapping */
+@@ -2015,14 +2006,13 @@ static int samldb_objectclass_trigger(struct samldb_ctx *ac)
+ 				ldb_set_errstring(ldb, "samldb: Unrecognized account type!");
+ 				return LDB_ERR_UNWILLING_TO_PERFORM;
+ 			}
+-			ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg,
+-						 "sAMAccountType",
+-						 account_type);
++			ret = samdb_msg_add_uint_flags(ldb, ac->msg, ac->msg,
++						       "sAMAccountType",
++						       account_type,
++						       LDB_FLAG_MOD_REPLACE);
+ 			if (ret != LDB_SUCCESS) {
+ 				return ret;
+ 			}
+-			el2 = ldb_msg_find_element(ac->msg, "sAMAccountType");
+-			el2->flags = LDB_FLAG_MOD_REPLACE;
+ 		}
+ 		break;
+ 	}
+@@ -2940,26 +2930,23 @@ static int samldb_user_account_control_change(struct samldb_ctx *ac)
+ 	}
+ 
+ 	if (old_atype != new_atype) {
+-		ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg,
+-					 "sAMAccountType", new_atype);
++		ret = samdb_msg_append_uint(ldb, ac->msg, ac->msg,
++					    "sAMAccountType", new_atype,
++					    LDB_FLAG_MOD_REPLACE);
+ 		if (ret != LDB_SUCCESS) {
+ 			return ret;
+ 		}
+-		el = ldb_msg_find_element(ac->msg, "sAMAccountType");
+-		el->flags = LDB_FLAG_MOD_REPLACE;
+ 	}
+ 
+ 	/* As per MS-SAMR 3.1.1.8.10 these flags have not to be set */
+ 	if ((clear_uac & UF_LOCKOUT) && (old_lockoutTime != 0)) {
+ 		/* "lockoutTime" reset as per MS-SAMR 3.1.1.8.10 */
+ 		ldb_msg_remove_attr(ac->msg, "lockoutTime");
+-		ret = samdb_msg_add_uint64(ldb, ac->msg, ac->msg, "lockoutTime",
+-					   (NTTIME)0);
++		ret = samdb_msg_append_uint64(ldb, ac->msg, ac->msg, "lockoutTime",
++					      (NTTIME)0, LDB_FLAG_MOD_REPLACE);
+ 		if (ret != LDB_SUCCESS) {
+ 			return ret;
+ 		}
+-		el = ldb_msg_find_element(ac->msg, "lockoutTime");
+-		el->flags = LDB_FLAG_MOD_REPLACE;
+ 	}
+ 
+ 	/*
+@@ -2970,14 +2957,12 @@ static int samldb_user_account_control_change(struct samldb_ctx *ac)
+ 	 * creating the attribute.
+ 	 */
+ 	if (old_is_critical != new_is_critical || old_atype != new_atype) {
+-		ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject",
+-					 new_is_critical ? "TRUE": "FALSE");
++		ret = ldb_msg_append_string(ac->msg, "isCriticalSystemObject",
++					    new_is_critical ? "TRUE": "FALSE",
++					    LDB_FLAG_MOD_REPLACE);
+ 		if (ret != LDB_SUCCESS) {
+ 			return ret;
+ 		}
+-		el = ldb_msg_find_element(ac->msg,
+-					   "isCriticalSystemObject");
+-		el->flags = LDB_FLAG_MOD_REPLACE;
+ 	}
+ 
+ 	if (!ldb_msg_find_element(ac->msg, "primaryGroupID") &&
+@@ -2990,14 +2975,12 @@ static int samldb_user_account_control_change(struct samldb_ctx *ac)
+ 			}
+ 		}
+ 
+-		ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg,
+-					 "primaryGroupID", new_pgrid);
++		ret = samdb_msg_append_uint(ldb, ac->msg, ac->msg,
++					    "primaryGroupID", new_pgrid,
++					    LDB_FLAG_MOD_REPLACE);
+ 		if (ret != LDB_SUCCESS) {
+ 			return ret;
+ 		}
+-		el = ldb_msg_find_element(ac->msg,
+-					   "primaryGroupID");
+-		el->flags = LDB_FLAG_MOD_REPLACE;
+ 	}
+ 
+ 	/* Propagate eventual "userAccountControl" attribute changes */
+@@ -3200,13 +3183,12 @@ static int samldb_lockout_time(struct samldb_ctx *ac)
+ 
+ 	/* lockoutTime == 0 resets badPwdCount */
+ 	ldb_msg_remove_attr(ac->msg, "badPwdCount");
+-	ret = samdb_msg_add_int(ldb, ac->msg, ac->msg,
+-				"badPwdCount", 0);
++	ret = samdb_msg_append_int(ldb, ac->msg, ac->msg,
++				   "badPwdCount", 0,
++				   LDB_FLAG_MOD_REPLACE);
+ 	if (ret != LDB_SUCCESS) {
+ 		return ret;
+ 	}
+-	el = ldb_msg_find_element(ac->msg, "badPwdCount");
+-	el->flags = LDB_FLAG_MOD_REPLACE;
+ 
+ 	return LDB_SUCCESS;
+ }
+@@ -3304,13 +3286,11 @@ static int samldb_group_type_change(struct samldb_ctx *ac)
+ 		ldb_set_errstring(ldb, "samldb: Unrecognized account type!");
+ 		return LDB_ERR_UNWILLING_TO_PERFORM;
+ 	}
+-	ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, "sAMAccountType",
+-				 account_type);
++	ret = samdb_msg_append_uint(ldb, ac->msg, ac->msg, "sAMAccountType",
++				    account_type, LDB_FLAG_MOD_REPLACE);
+ 	if (ret != LDB_SUCCESS) {
+ 		return ret;
+ 	}
+-	el = ldb_msg_find_element(ac->msg, "sAMAccountType");
+-	el->flags = LDB_FLAG_MOD_REPLACE;
+ 
+ 	return LDB_SUCCESS;
+ }
+diff --git a/source4/dsdb/samdb/ldb_modules/tombstone_reanimate.c b/source4/dsdb/samdb/ldb_modules/tombstone_reanimate.c
+index 5f8911c66be..99c5955e9e7 100644
+--- a/source4/dsdb/samdb/ldb_modules/tombstone_reanimate.c
++++ b/source4/dsdb/samdb/ldb_modules/tombstone_reanimate.c
+@@ -294,14 +294,13 @@ static int tr_prepare_attributes(struct tr_context *ac)
+ 			return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
+ 					 "reanimate: Unrecognized account type!");
+ 		}
+-		ret = samdb_msg_add_uint(ldb, ac->mod_msg, ac->mod_msg,
+-					 "sAMAccountType", account_type);
++		ret = samdb_msg_append_uint(ldb, ac->mod_msg, ac->mod_msg,
++					    "sAMAccountType", account_type,
++					    LDB_FLAG_MOD_REPLACE);
+ 		if (ret != LDB_SUCCESS) {
+ 			return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
+ 					 "reanimate: Failed to add sAMAccountType to restored object.");
+ 		}
+-		el = ldb_msg_find_element(ac->mod_msg, "sAMAccountType");
+-		el->flags = LDB_FLAG_MOD_REPLACE;
+ 
+ 		/* Default values set by Windows */
+ 		ret = samdb_find_or_add_attribute(ldb, ac->mod_msg,
+@@ -324,12 +323,11 @@ static int tr_prepare_attributes(struct tr_context *ac)
+ 			return ret;
+ 		}
+ 
+-		ret = ldb_msg_add_string(ac->mod_msg, "objectCategory", value);
++		ret = ldb_msg_append_string(ac->mod_msg, "objectCategory", value,
++					    LDB_FLAG_MOD_ADD);
+ 		if (ret != LDB_SUCCESS) {
+ 			return ret;
+ 		}
+-		el = ldb_msg_find_element(ac->mod_msg, "objectCategory");
+-		el->flags = LDB_FLAG_MOD_ADD;
+ 	}
+ 
+ 	return LDB_SUCCESS;
+diff --git a/source4/nbt_server/wins/winsdb.c b/source4/nbt_server/wins/winsdb.c
+index be1d8ba8050..bb205d66111 100644
+--- a/source4/nbt_server/wins/winsdb.c
++++ b/source4/nbt_server/wins/winsdb.c
+@@ -99,13 +99,11 @@ uint64_t winsdb_set_maxVersion(struct winsdb_handle *h, uint64_t newMaxVersion)
+ 	msg->dn = dn;
+ 
+ 
+-	ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
++	ret = ldb_msg_append_string(msg, "objectClass", "winsMaxVersion",
++				    LDB_FLAG_MOD_REPLACE);
+ 	if (ret != LDB_SUCCESS) goto failed;
+-	ret = ldb_msg_add_string(msg, "objectClass", "winsMaxVersion");
+-	if (ret != LDB_SUCCESS) goto failed;
+-	ret = ldb_msg_add_empty(msg, "maxVersion", LDB_FLAG_MOD_REPLACE, NULL);
+-	if (ret != LDB_SUCCESS) goto failed;
+-	ret = ldb_msg_add_fmt(msg, "maxVersion", "%llu", (long long)newMaxVersion);
++	ret = ldb_msg_append_fmt(msg, LDB_FLAG_MOD_REPLACE,
++				 "maxVersion", "%llu", (long long)newMaxVersion);
+ 	if (ret != LDB_SUCCESS) goto failed;
+ 
+ 	ret = ldb_modify(wins_db, msg);
+@@ -776,8 +774,7 @@ static struct ldb_message *winsdb_message(struct ldb_context *ldb,
+ 		ret |= ldb_msg_add_winsdb_addr(msg, rec, "address", rec->addresses[i]);
+ 	}
+ 	if (rec->registered_by) {
+-		ret |= ldb_msg_add_empty(msg, "registeredBy", 0, NULL);
+-		ret |= ldb_msg_add_string(msg, "registeredBy", rec->registered_by);
++		ret |= ldb_msg_append_string(msg, "registeredBy", rec->registered_by, 0);
+ 	}
+ 	if (ret != LDB_SUCCESS) goto failed;
+ 	return msg;
+diff --git a/source4/rpc_server/lsa/dcesrv_lsa.c b/source4/rpc_server/lsa/dcesrv_lsa.c
+index 8333cb149b6..930145099e0 100644
+--- a/source4/rpc_server/lsa/dcesrv_lsa.c
++++ b/source4/rpc_server/lsa/dcesrv_lsa.c
+@@ -1757,12 +1757,7 @@ static NTSTATUS update_uint32_t_value(TALLOC_CTX *mem_ctx,
+ 		goto done;
+ 	}
+ 
+-	ret = ldb_msg_add_empty(dest, attribute, flags, NULL);
+-	if (ret != LDB_SUCCESS) {
+-		return NT_STATUS_NO_MEMORY;
+-	}
+-
+-	ret = samdb_msg_add_uint(sam_ldb, dest, dest, attribute, value);
++	ret = samdb_msg_append_uint(sam_ldb, dest, dest, attribute, value, flags);
+ 	if (ret != LDB_SUCCESS) {
+ 		return NT_STATUS_NO_MEMORY;
+ 	}
+@@ -1853,13 +1848,7 @@ static NTSTATUS update_trust_user(TALLOC_CTX *mem_ctx,
+ 			continue;
+ 		}
+ 
+-		ret = ldb_msg_add_empty(msg, attribute,
+-					LDB_FLAG_MOD_REPLACE, NULL);
+-		if (ret != LDB_SUCCESS) {
+-			return NT_STATUS_NO_MEMORY;
+-		}
+-
+-		ret = ldb_msg_add_value(msg, attribute, &v, NULL);
++		ret = ldb_msg_append_value(msg, attribute, &v, LDB_FLAG_MOD_REPLACE);
+ 		if (ret != LDB_SUCCESS) {
+ 			return NT_STATUS_NO_MEMORY;
+ 		}
+@@ -2145,28 +2134,30 @@ static NTSTATUS setInfoTrustedDomain_base(struct dcesrv_call_state *dce_call,
+ 	}
+ 
+ 	if (add_incoming || del_incoming) {
+-		ret = ldb_msg_add_empty(msg, "trustAuthIncoming",
+-					LDB_FLAG_MOD_REPLACE, NULL);
+-		if (ret != LDB_SUCCESS) {
+-			return NT_STATUS_NO_MEMORY;
+-		}
+ 		if (add_incoming) {
+-			ret = ldb_msg_add_value(msg, "trustAuthIncoming",
+-						&trustAuthIncoming, NULL);
++			ret = ldb_msg_append_value(msg, "trustAuthIncoming",
++						   &trustAuthIncoming, LDB_FLAG_MOD_REPLACE);
++			if (ret != LDB_SUCCESS) {
++				return NT_STATUS_NO_MEMORY;
++			}
++		} else {
++			ret = ldb_msg_add_empty(msg, "trustAuthIncoming",
++						LDB_FLAG_MOD_REPLACE, NULL);
+ 			if (ret != LDB_SUCCESS) {
+ 				return NT_STATUS_NO_MEMORY;
+ 			}
+ 		}
+ 	}
+ 	if (add_outgoing || del_outgoing) {
+-		ret = ldb_msg_add_empty(msg, "trustAuthOutgoing",
+-					LDB_FLAG_MOD_REPLACE, NULL);
+-		if (ret != LDB_SUCCESS) {
+-			return NT_STATUS_NO_MEMORY;
+-		}
+ 		if (add_outgoing) {
+-			ret = ldb_msg_add_value(msg, "trustAuthOutgoing",
+-						&trustAuthOutgoing, NULL);
++			ret = ldb_msg_append_value(msg, "trustAuthOutgoing",
++						   &trustAuthOutgoing, LDB_FLAG_MOD_REPLACE);
++			if (ret != LDB_SUCCESS) {
++				return NT_STATUS_NO_MEMORY;
++			}
++		} else {
++			ret = ldb_msg_add_empty(msg, "trustAuthOutgoing",
++						LDB_FLAG_MOD_REPLACE, NULL);
+ 			if (ret != LDB_SUCCESS) {
+ 				return NT_STATUS_NO_MEMORY;
+ 			}
+@@ -4614,14 +4605,8 @@ static NTSTATUS dcesrv_lsa_lsaRSetForestTrustInformation(struct dcesrv_call_stat
+ 		goto done;
+ 	}
+ 
+-	ret = ldb_msg_add_empty(msg, "msDS-TrustForestTrustInfo",
+-				LDB_FLAG_MOD_REPLACE, NULL);
+-	if (ret != LDB_SUCCESS) {
+-		status = NT_STATUS_NO_MEMORY;
+-		goto done;
+-	}
+-	ret = ldb_msg_add_value(msg, "msDS-TrustForestTrustInfo",
+-				&ft_blob, NULL);
++	ret = ldb_msg_append_value(msg, "msDS-TrustForestTrustInfo",
++				   &ft_blob, LDB_FLAG_MOD_REPLACE);
+ 	if (ret != LDB_SUCCESS) {
+ 		status = NT_STATUS_NO_MEMORY;
+ 		goto done;
+diff --git a/source4/winbind/idmap.c b/source4/winbind/idmap.c
+index c4039be473a..c6375f8357a 100644
+--- a/source4/winbind/idmap.c
++++ b/source4/winbind/idmap.c
+@@ -672,14 +672,8 @@ static NTSTATUS idmap_sid_to_xid(struct idmap_context *idmap_ctx,
+ 		vals[1].data = (uint8_t *)hwm_string;
+ 		vals[1].length = strlen(hwm_string);
+ 	} else {
+-		ret = ldb_msg_add_empty(hwm_msg, "xidNumber", LDB_FLAG_MOD_ADD,
+-					NULL);
+-		if (ret != LDB_SUCCESS) {
+-			status = NT_STATUS_NONE_MAPPED;
+-			goto failed;
+-		}
+-
+-		ret = ldb_msg_add_string(hwm_msg, "xidNumber", hwm_string);
++		ret = ldb_msg_append_string(hwm_msg, "xidNumber", hwm_string,
++					    LDB_FLAG_MOD_ADD);
+ 		if (ret != LDB_SUCCESS)
+ 		{
+ 			status = NT_STATUS_NONE_MAPPED;
+-- 
+2.35.0
+
+
+From 11a8dcfd4802a14e33d5d704dce1c1216029eebe Mon Sep 17 00:00:00 2001
+From: Andrew Bartlett <abartlet at samba.org>
+Date: Tue, 14 Jun 2022 15:43:26 +1200
+Subject: [PATCH 14/18] CVE-2022-32746 ldb: Release LDB 2.2.4
+
+* CVE-2022-32746 Use-after-free occurring in database audit logging module (bug 15009)
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15009
+
+Signed-off-by: Andrew Bartlett <abartlet at samba.org>
+---
+ lib/ldb/ABI/ldb-2.2.4.sigs        | 291 ++++++++++++++++++++++++++++++
+ lib/ldb/ABI/pyldb-util-2.2.4.sigs |   3 +
+ lib/ldb/wscript                   |   2 +-
+ 3 files changed, 295 insertions(+), 1 deletion(-)
+ create mode 100644 lib/ldb/ABI/ldb-2.2.4.sigs
+ create mode 100644 lib/ldb/ABI/pyldb-util-2.2.4.sigs
+
+diff --git a/lib/ldb/ABI/ldb-2.2.4.sigs b/lib/ldb/ABI/ldb-2.2.4.sigs
+new file mode 100644
+index 00000000000..40388d9e330
+--- /dev/null
++++ b/lib/ldb/ABI/ldb-2.2.4.sigs
+@@ -0,0 +1,291 @@
++ldb_add: int (struct ldb_context *, const struct ldb_message *)
++ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
++ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
++ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
++ldb_attr_dn: int (const char *)
++ldb_attr_in_list: int (const char * const *, const char *)
++ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
++ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
++ldb_base64_decode: int (char *)
++ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
++ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
++ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
++ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
++ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
++ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
++ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
++ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
++ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
++ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
++ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
++ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
++ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
++ldb_check_critical_controls: int (struct ldb_control **)
++ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
++ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
++ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
++ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
++ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
++ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
++ldb_debug_add: void (struct ldb_context *, const char *, ...)
++ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
++ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
++ldb_delete: int (struct ldb_context *, struct ldb_dn *)
++ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
++ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
++ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
++ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
++ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
++ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
++ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
++ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
++ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
++ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
++ldb_dn_check_special: bool (struct ldb_dn *, const char *)
++ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
++ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
++ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
++ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
++ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
++ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
++ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
++ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
++ldb_dn_get_casefold: const char *(struct ldb_dn *)
++ldb_dn_get_comp_num: int (struct ldb_dn *)
++ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
++ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
++ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
++ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
++ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
++ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
++ldb_dn_get_linearized: const char *(struct ldb_dn *)
++ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
++ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
++ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
++ldb_dn_has_extended: bool (struct ldb_dn *)
++ldb_dn_is_null: bool (struct ldb_dn *)
++ldb_dn_is_special: bool (struct ldb_dn *)
++ldb_dn_is_valid: bool (struct ldb_dn *)
++ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
++ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
++ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
++ldb_dn_minimise: bool (struct ldb_dn *)
++ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
++ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
++ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
++ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
++ldb_dn_remove_extended_components: void (struct ldb_dn *)
++ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
++ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
++ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
++ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
++ldb_dn_validate: bool (struct ldb_dn *)
++ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
++ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
++ldb_errstring: const char *(struct ldb_context *)
++ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
++ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
++ldb_filter_attrs: int (struct ldb_context *, const struct ldb_message *, const char * const *, struct ldb_message *)
++ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
++ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
++ldb_get_create_perms: unsigned int (struct ldb_context *)
++ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
++ldb_get_event_context: struct tevent_context *(struct ldb_context *)
++ldb_get_flags: unsigned int (struct ldb_context *)
++ldb_get_opaque: void *(struct ldb_context *, const char *)
++ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
++ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
++ldb_global_init: int (void)
++ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
++ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
++ldb_handle_use_global_event_context: void (struct ldb_handle *)
++ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
++ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
++ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
++ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
++ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
++ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
++ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
++ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
++ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
++ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
++ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
++ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
++ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
++ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
++ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
++ldb_load_modules: int (struct ldb_context *, const char **)
++ldb_map_add: int (struct ldb_module *, struct ldb_request *)
++ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
++ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
++ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
++ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
++ldb_map_search: int (struct ldb_module *, struct ldb_request *)
++ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
++ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
++ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
++ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
++ldb_mod_register_control: int (struct ldb_module *, const char *)
++ldb_modify: int (struct ldb_context *, const struct ldb_message *)
++ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
++ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
++ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
++ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
++ldb_module_flags: uint32_t (struct ldb_context *)
++ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
++ldb_module_get_name: const char *(struct ldb_module *)
++ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
++ldb_module_get_private: void *(struct ldb_module *)
++ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
++ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
++ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
++ldb_module_next: struct ldb_module *(struct ldb_module *)
++ldb_module_popt_options: struct poptOption **(struct ldb_context *)
++ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
++ldb_module_send_referral: int (struct ldb_request *, char *)
++ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
++ldb_module_set_private: void (struct ldb_module *, void *)
++ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
++ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
++ldb_modules_load: int (const char *, const char *)
++ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
++ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
++ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
++ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
++ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
++ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
++ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
++ldb_msg_add_string_flags: int (struct ldb_message *, const char *, const char *, int)
++ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
++ldb_msg_append_fmt: int (struct ldb_message *, int, const char *, const char *, ...)
++ldb_msg_append_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *, int)
++ldb_msg_append_steal_string: int (struct ldb_message *, const char *, char *, int)
++ldb_msg_append_steal_value: int (struct ldb_message *, const char *, struct ldb_val *, int)
++ldb_msg_append_string: int (struct ldb_message *, const char *, const char *, int)
++ldb_msg_append_value: int (struct ldb_message *, const char *, const struct ldb_val *, int)
++ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
++ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
++ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
++ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
++ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
++ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
++ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
++ldb_msg_element_add_value: int (TALLOC_CTX *, struct ldb_message_element *, const struct ldb_val *)
++ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
++ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
++ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
++ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
++ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
++ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
++ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
++ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
++ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
++ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
++ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
++ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
++ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
++ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
++ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
++ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
++ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
++ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
++ldb_msg_remove_attr: void (struct ldb_message *, const char *)
++ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
++ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
++ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
++ldb_msg_sort_elements: void (struct ldb_message *)
++ldb_next_del_trans: int (struct ldb_module *)
++ldb_next_end_trans: int (struct ldb_module *)
++ldb_next_init: int (struct ldb_module *)
++ldb_next_prepare_commit: int (struct ldb_module *)
++ldb_next_read_lock: int (struct ldb_module *)
++ldb_next_read_unlock: int (struct ldb_module *)
++ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
++ldb_next_request: int (struct ldb_module *, struct ldb_request *)
++ldb_next_start_trans: int (struct ldb_module *)
++ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
++ldb_options_copy: const char **(TALLOC_CTX *, const char **)
++ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
++ldb_options_get: const char **(struct ldb_context *)
++ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *, uint32_t)
++ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
++ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
++ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
++ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
++ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
++ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
++ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
++ldb_register_backend: int (const char *, ldb_connect_fn, bool)
++ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
++ldb_register_hook: int (ldb_hook_fn)
++ldb_register_module: int (const struct ldb_module_ops *)
++ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
++ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
++ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
++ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
++ldb_req_is_untrusted: bool (struct ldb_request *)
++ldb_req_location: const char *(struct ldb_request *)
++ldb_req_mark_trusted: void (struct ldb_request *)
++ldb_req_mark_untrusted: void (struct ldb_request *)
++ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
++ldb_req_set_location: void (struct ldb_request *, const char *)
++ldb_request: int (struct ldb_context *, struct ldb_request *)
++ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
++ldb_request_done: int (struct ldb_request *, int)
++ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
++ldb_request_get_status: int (struct ldb_request *)
++ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
++ldb_request_set_state: void (struct ldb_request *, int)
++ldb_reset_err_string: void (struct ldb_context *)
++ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
++ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
++ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
++ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
++ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
++ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
++ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
++ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
++ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
++ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
++ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
++ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
++ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
++ldb_set_create_perms: void (struct ldb_context *, unsigned int)
++ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
++ldb_set_debug_stderr: int (struct ldb_context *)
++ldb_set_default_dns: void (struct ldb_context *)
++ldb_set_errstring: void (struct ldb_context *, const char *)
++ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
++ldb_set_flags: void (struct ldb_context *, unsigned int)
++ldb_set_modules_dir: void (struct ldb_context *, const char *)
++ldb_set_opaque: int (struct ldb_context *, const char *, void *)
++ldb_set_require_private_event_context: void (struct ldb_context *)
++ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
++ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
++ldb_set_utf8_default: void (struct ldb_context *)
++ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
++ldb_setup_wellknown_attributes: int (struct ldb_context *)
++ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
++ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
++ldb_strerror: const char *(int)
++ldb_string_to_time: time_t (const char *)
++ldb_string_utc_to_time: time_t (const char *)
++ldb_timestring: char *(TALLOC_CTX *, time_t)
++ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
++ldb_transaction_cancel: int (struct ldb_context *)
++ldb_transaction_cancel_noerr: int (struct ldb_context *)
++ldb_transaction_commit: int (struct ldb_context *)
++ldb_transaction_prepare_commit: int (struct ldb_context *)
++ldb_transaction_start: int (struct ldb_context *)
++ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
++ldb_unpack_data_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, unsigned int)
++ldb_unpack_get_format: int (const struct ldb_val *, uint32_t *)
++ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
++ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
++ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
++ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
++ldb_val_string_cmp: int (const struct ldb_val *, const char *)
++ldb_val_to_time: int (const struct ldb_val *, time_t *)
++ldb_valid_attr_name: int (const char *)
++ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
++ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
+diff --git a/lib/ldb/ABI/pyldb-util-2.2.4.sigs b/lib/ldb/ABI/pyldb-util-2.2.4.sigs
+new file mode 100644
+index 00000000000..164a806b2ff
+--- /dev/null
++++ b/lib/ldb/ABI/pyldb-util-2.2.4.sigs
+@@ -0,0 +1,3 @@
++pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
++pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
++pyldb_check_type: bool (PyObject *, const char *)
+diff --git a/lib/ldb/wscript b/lib/ldb/wscript
+index 57dfdd6fe6b..216cd70f9fa 100644
+--- a/lib/ldb/wscript
++++ b/lib/ldb/wscript
+@@ -2,7 +2,7 @@
+ 
+ APPNAME = 'ldb'
+ # For Samba 4.13.x
+-VERSION = '2.2.3'
++VERSION = '2.2.4'
+ 
+ import sys, os
+ 
+-- 
+2.35.0
+
+
+From d72aeda6a2e7ba8374eee7d193b315bf3374641c Mon Sep 17 00:00:00 2001
+From: Joseph Sutton <josephsutton at catalyst.net.nz>
+Date: Wed, 16 Feb 2022 17:03:10 +1300
+Subject: [PATCH 15/18] CVE-2022-32745 s4/dsdb/samldb: Check for empty values
+ array
+
+This avoids potentially trying to access the first element of an empty
+array.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15008
+
+Signed-off-by: Joseph Sutton <josephsutton at catalyst.net.nz>
+---
+ source4/dsdb/samdb/ldb_modules/samldb.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c
+index b9677442e3f..c68ffa298c3 100644
+--- a/source4/dsdb/samdb/ldb_modules/samldb.c
++++ b/source4/dsdb/samdb/ldb_modules/samldb.c
+@@ -748,7 +748,7 @@ static int samldb_schema_add_handle_linkid(struct samldb_ctx *ac)
+ 		return ret;
+ 	}
+ 
+-	if (el == NULL) {
++	if (el == NULL || el->num_values == 0) {
+ 		return LDB_SUCCESS;
+ 	}
+ 
+@@ -916,7 +916,7 @@ static int samldb_schema_add_handle_mapiid(struct samldb_ctx *ac)
+ 		return ret;
+ 	}
+ 
+-	if (el == NULL) {
++	if (el == NULL || el->num_values == 0) {
+ 		return LDB_SUCCESS;
+ 	}
+ 
+-- 
+2.35.0
+
+
+From c402505add4c8f249abc6f5031e7cfada8882d78 Mon Sep 17 00:00:00 2001
+From: Joseph Sutton <josephsutton at catalyst.net.nz>
+Date: Thu, 17 Feb 2022 11:11:53 +1300
+Subject: [PATCH 16/18] CVE-2022-32745 s4/dsdb/util: Use correct value for loop
+ count limit
+
+Currently, we can crash the server by sending a large number of values
+of a specific attribute (such as sAMAccountName) spread across a few
+message elements. If val_count is larger than the total number of
+elements, we get an access beyond the elements array.
+
+Similarly, we can include unrelated message elements prior to the
+message elements of the attribute in question, so that not all of the
+attribute's values are copied into the returned elements values array.
+This can cause the server to access uninitialised data, likely resulting
+in a crash or unexpected behaviour.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15008
+
+Signed-off-by: Joseph Sutton <josephsutton at catalyst.net.nz>
+---
+ source4/dsdb/samdb/ldb_modules/util.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/source4/dsdb/samdb/ldb_modules/util.c b/source4/dsdb/samdb/ldb_modules/util.c
+index 4c67873643a..5d418efcd52 100644
+--- a/source4/dsdb/samdb/ldb_modules/util.c
++++ b/source4/dsdb/samdb/ldb_modules/util.c
+@@ -1544,7 +1544,7 @@ int dsdb_get_expected_new_values(TALLOC_CTX *mem_ctx,
+ 
+ 	v = _el->values;
+ 
+-	for (i = 0; i < val_count; i++) {
++	for (i = 0; i < msg->num_elements; i++) {
+ 		if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
+ 			if ((operation == LDB_MODIFY) &&
+ 			    (LDB_FLAG_MOD_TYPE(msg->elements[i].flags)
+-- 
+2.35.0
+
+
+From 46da0b33a77a99ead5bdda0c375c665dd724c94b Mon Sep 17 00:00:00 2001
+From: Joseph Sutton <josephsutton at catalyst.net.nz>
+Date: Thu, 17 Feb 2022 11:13:38 +1300
+Subject: [PATCH 17/18] CVE-2022-32745 s4/dsdb/util: Don't call memcpy() with a
+ NULL pointer
+
+Doing so is undefined behaviour.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15008
+
+Signed-off-by: Joseph Sutton <josephsutton at catalyst.net.nz>
+---
+ source4/dsdb/samdb/ldb_modules/util.c | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+diff --git a/source4/dsdb/samdb/ldb_modules/util.c b/source4/dsdb/samdb/ldb_modules/util.c
+index 5d418efcd52..af412f55f98 100644
+--- a/source4/dsdb/samdb/ldb_modules/util.c
++++ b/source4/dsdb/samdb/ldb_modules/util.c
+@@ -1546,15 +1546,19 @@ int dsdb_get_expected_new_values(TALLOC_CTX *mem_ctx,
+ 
+ 	for (i = 0; i < msg->num_elements; i++) {
+ 		if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
++			const struct ldb_message_element *tmp_el = &msg->elements[i];
+ 			if ((operation == LDB_MODIFY) &&
+-			    (LDB_FLAG_MOD_TYPE(msg->elements[i].flags)
++			    (LDB_FLAG_MOD_TYPE(tmp_el->flags)
+ 						== LDB_FLAG_MOD_DELETE)) {
+ 				continue;
+ 			}
++			if (tmp_el->values == NULL || tmp_el->num_values == 0) {
++				continue;
++			}
+ 			memcpy(v,
+-			       msg->elements[i].values,
+-			       msg->elements[i].num_values);
+-			v += msg->elements[i].num_values;
++			       tmp_el->values,
++			       tmp_el->num_values);
++			v += tmp_el->num_values;
+ 		}
+ 	}
+ 
+-- 
+2.35.0
+
+
+From 38afcdacd8b43cee6860b58beece8f7ab4c5441c Mon Sep 17 00:00:00 2001
+From: Joseph Sutton <josephsutton at catalyst.net.nz>
+Date: Fri, 3 Jun 2022 16:16:31 +1200
+Subject: [PATCH 18/18] CVE-2022-32745 s4/dsdb/util: Correctly copy values into
+ message element
+
+To use memcpy(), we need to specify the number of bytes to copy, rather
+than the number of ldb_val structures.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15008
+
+Signed-off-by: Joseph Sutton <josephsutton at catalyst.net.nz>
+---
+ source4/dsdb/samdb/ldb_modules/util.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/source4/dsdb/samdb/ldb_modules/util.c b/source4/dsdb/samdb/ldb_modules/util.c
+index af412f55f98..5ccbb1b4360 100644
+--- a/source4/dsdb/samdb/ldb_modules/util.c
++++ b/source4/dsdb/samdb/ldb_modules/util.c
+@@ -1557,7 +1557,7 @@ int dsdb_get_expected_new_values(TALLOC_CTX *mem_ctx,
+ 			}
+ 			memcpy(v,
+ 			       tmp_el->values,
+-			       tmp_el->num_values);
++			       tmp_el->num_values * sizeof(*v));
+ 			v += tmp_el->num_values;
+ 		}
+ 	}
+-- 
+2.35.0
+


=====================================
debian/patches/series
=====================================
@@ -299,3 +299,6 @@ bug1005642-s3-lib-In-create_clock_itime-use-timespec_current-cl.patch
 bug1005642-s3-includes-Make-the-comments-describing-itime-consi.patch
 bug998423-s3-mdssvc-Correctly-disconnect-the-VFS-connection-in.patch
 bug998423-s3-smbd-In-create_conn_struct_cwd-don-t-TALLOC_FREE-.patch
+CVE-2022-32742-bug-15085-4.13.patch
+ldb-memory-bug-15096-4.13-v3.patch
+kpasswd_bugs_v15_4-13.patch



View it on GitLab: https://salsa.debian.org/samba-team/samba/-/compare/b8f5b1969afb25555636a2ca3c0f29895377e8c2...ff19901eda4c985c1dc0df6e926d58dd8b060ddc

-- 
View it on GitLab: https://salsa.debian.org/samba-team/samba/-/compare/b8f5b1969afb25555636a2ca3c0f29895377e8c2...ff19901eda4c985c1dc0df6e926d58dd8b060ddc
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-samba-maint/attachments/20220804/0079e9d7/attachment-0001.htm>


More information about the Pkg-samba-maint mailing list