From b5f78492628a06013354f76521cb153ab7d8e0d5 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Wed, 24 Jun 2026 14:01:32 +0200
Subject: [PATCH 22/23] CVE-2026-58221: s4:dsdb: let rootdse_filter_operations()
 reject untrusted operations on special DNs

Without this authenticated (also non-admin) users write internal meta
data leading to admin privileges.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=16147

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
---
 source4/dsdb/samdb/ldb_modules/rootdse.c      | 55 ++++++++++++++++++-
 .../samdb/ldb_modules/wscript_build_server    |  2 +-
 2 files changed, 54 insertions(+), 3 deletions(-)

diff --git a/source4/dsdb/samdb/ldb_modules/rootdse.c b/source4/dsdb/samdb/ldb_modules/rootdse.c
index 7541a2cf376..9cc8477b8f8 100644
--- a/source4/dsdb/samdb/ldb_modules/rootdse.c
+++ b/source4/dsdb/samdb/ldb_modules/rootdse.c
@@ -28,6 +28,7 @@
 #include "dsdb/samdb/samdb.h"
 #include "version.h"
 #include "dsdb/samdb/ldb_modules/util.h"
+#include "dsdb/samdb/ldb_modules/audit_util_proto.h"
 #include "libcli/security/security.h"
 #include "librpc/ndr/libndr.h"
 #include "auth/auth.h"
@@ -746,18 +747,68 @@ static int rootdse_filter_controls(struct ldb_module *module, struct ldb_request
 	return LDB_SUCCESS;
 }
 
-/* Ensure that anonymous users are not allowed to make anything other than rootDSE search operations */
-
+/*
+ * Ensure that anonymous users are not allowed to make anything other than
+ * rootDSE search operations and special dns like @MODULES are not allowed
+ * over an untrusted connection.
+ */
 static int rootdse_filter_operations(struct ldb_module *module, struct ldb_request *req)
 {
 	struct auth_session_info *session_info;
 	struct rootdse_private_data *priv = talloc_get_type(ldb_module_get_private(module), struct rootdse_private_data);
 	bool is_untrusted = ldb_req_is_untrusted(req);
 	bool is_anonymous = true;
+	struct ldb_dn *dn = NULL;
+	struct ldb_dn *dn2 = NULL;
+
 	if (is_untrusted == false) {
 		return LDB_SUCCESS;
 	}
 
+	switch (req->operation) {
+	case LDB_SEARCH:
+		dn = req->op.search.base;
+		break;
+	case LDB_ADD:
+		dn = req->op.add.message->dn;
+		break;
+	case LDB_MODIFY:
+		dn = req->op.mod.message->dn;
+		break;
+	case LDB_DELETE:
+		dn = req->op.del.dn;
+		break;
+	case LDB_RENAME:
+		dn = req->op.rename.olddn;
+		dn2 = req->op.rename.newdn;
+		break;
+	case LDB_EXTENDED:
+		break;
+	case LDB_REQ_REGISTER_CONTROL:
+	case LDB_REQ_REGISTER_PARTITION:
+		ldb_set_errstring(ldb_module_get_ctx(module), "Invalid OP");
+		return LDB_ERR_OPERATIONS_ERROR;
+	}
+
+	if (ldb_dn_is_special(dn)) {
+		struct ldb_reply reply = { .error = LDB_ERR_OPERATIONS_ERROR, };
+
+		D_ERR("CVE-2026-58221-ATTACK: %s\n",
+			dsdb_audit_operation_human_readable(req, module, req, &reply));
+
+		ldb_set_errstring(ldb_module_get_ctx(module), "Invalid DN");
+		return LDB_ERR_OPERATIONS_ERROR;
+	}
+	if (ldb_dn_is_special(dn2)) {
+		struct ldb_reply reply = { .error = LDB_ERR_OPERATIONS_ERROR, };
+
+		D_ERR("CVE-2026-58221-ATTACK: %s\n",
+			dsdb_audit_operation_human_readable(req, module, req, &reply));
+
+		ldb_set_errstring(ldb_module_get_ctx(module), "Invalid DN");
+		return LDB_ERR_OPERATIONS_ERROR;
+	}
+
 	session_info = (struct auth_session_info *)ldb_get_opaque(
 		ldb_module_get_ctx(module),
 		DSDB_SESSION_INFO);
diff --git a/source4/dsdb/samdb/ldb_modules/wscript_build_server b/source4/dsdb/samdb/ldb_modules/wscript_build_server
index 800ed2954c4..7582b64a938 100644
--- a/source4/dsdb/samdb/ldb_modules/wscript_build_server
+++ b/source4/dsdb/samdb/ldb_modules/wscript_build_server
@@ -185,7 +185,7 @@ bld.SAMBA_MODULE('ldb_rootdse',
 	init_function='ldb_rootdse_module_init',
 	module_init_name='ldb_init_module',
 	internal_module=False,
-	deps='talloc samdb MESSAGING samba-security DSDB_MODULE_HELPERS RPC_NDR_IRPC'
+	deps='talloc samdb MESSAGING samba-security DSDB_MODULE_HELPERS DSDB_MODULE_HELPERS_AUDIT RPC_NDR_IRPC'
 	)
 
 
-- 
2.43.0


