[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