From 51bc79f85a8d63ed5428c2975f60094157dda2e5 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet@samba.org>
Date: Tue, 12 Sep 2023 12:28:49 +1200
Subject: [PATCH 29/30] CVE-2023-42670 s3-rpc_server: Strictly refuse to start
 RPC servers in conflict with AD DC

Just as we refuse to start NETLOGON except on the DC, we must refuse
to start all of the RPC services that are provided by the AD DC.

Most critically of course this applies to netlogon, lsa and samr.

This avoids the supression of these services being the result of a
runtime epmapper lookup, as if that fails these services can disrupt
service to end users by listening on the same socket as the AD DC
servers.

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

Signed-off-by: Andrew Bartlett <abartlet@samba.org>

Conflict: NA
Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch
[PATCH 29/30] CVE-2023-42670 s3-rpc_server: Strictly refuse to start
 RPC servers in conflict with AD DC
---
 source3/rpc_server/rpcd_classic.c  | 45 ++++++++++++++++++++++++++----
 source3/rpc_server/rpcd_epmapper.c | 33 ++++++++++++++++++++--
 source3/rpc_server/rpcd_lsad.c     | 21 ++++++++++++++
 source3/rpc_server/rpcd_rpcecho.c  | 33 ++++++++++++++++++++--
 4 files changed, 122 insertions(+), 10 deletions(-)

diff --git a/source3/rpc_server/rpcd_classic.c b/source3/rpc_server/rpcd_classic.c
index 4f6164c814c..8494af575ec 100644
--- a/source3/rpc_server/rpcd_classic.c
+++ b/source3/rpc_server/rpcd_classic.c
@@ -42,14 +42,34 @@ static size_t classic_interfaces(
 	static const struct ndr_interface_table *ifaces[] = {
 		&ndr_table_srvsvc,
 		&ndr_table_netdfs,
-		&ndr_table_wkssvc,
+		&ndr_table_initshutdown,
 		&ndr_table_svcctl,
 		&ndr_table_ntsvcs,
 		&ndr_table_eventlog,
-		&ndr_table_initshutdown,
+		/*
+		 * This last item is truncated from the list by the
+		 * num_ifaces -= 1 below.  Take care when adding new
+		 * services.
+		 */
+		&ndr_table_wkssvc,
 	};
+	size_t num_ifaces = ARRAY_SIZE(ifaces);
+
+	switch(lp_server_role()) {
+	case ROLE_ACTIVE_DIRECTORY_DC:
+		/*
+		 * On the AD DC wkssvc is provided by the 'samba'
+		 * binary from source4/
+		 */
+		num_ifaces -= 1;
+		break;
+	default:
+		break;
+	}
+
 	*pifaces = ifaces;
-	return ARRAY_SIZE(ifaces);
+	return num_ifaces;
+
 }
 
 static size_t classic_servers(
@@ -58,15 +78,28 @@ static size_t classic_servers(
 	void *private_data)
 {
 	static const struct dcesrv_endpoint_server *ep_servers[7] = { NULL };
+	size_t num_servers = ARRAY_SIZE(ep_servers);
 	bool ok;
 
 	ep_servers[0] = srvsvc_get_ep_server();
 	ep_servers[1] = netdfs_get_ep_server();
-	ep_servers[2] = wkssvc_get_ep_server();
+	ep_servers[2] = initshutdown_get_ep_server();
 	ep_servers[3] = svcctl_get_ep_server();
 	ep_servers[4] = ntsvcs_get_ep_server();
 	ep_servers[5] = eventlog_get_ep_server();
-	ep_servers[6] = initshutdown_get_ep_server();
+	ep_servers[6] = wkssvc_get_ep_server();
+
+	switch(lp_server_role()) {
+	case ROLE_ACTIVE_DIRECTORY_DC:
+		/*
+		 * On the AD DC wkssvc is provided by the 'samba'
+		 * binary from source4/
+		 */
+		num_servers -= 1;
+		break;
+	default:
+		break;
+	}
 
 	ok = secrets_init();
 	if (!ok) {
@@ -85,7 +118,7 @@ static size_t classic_servers(
 	mangle_reset_cache();
 
 	*_ep_servers = ep_servers;
-	return ARRAY_SIZE(ep_servers);
+	return num_servers;
 }
 
 int main(int argc, const char *argv[])
diff --git a/source3/rpc_server/rpcd_epmapper.c b/source3/rpc_server/rpcd_epmapper.c
index 950ba7ec12a..455179ccfba 100644
--- a/source3/rpc_server/rpcd_epmapper.c
+++ b/source3/rpc_server/rpcd_epmapper.c
@@ -19,6 +19,8 @@
 #include "rpc_worker.h"
 #include "librpc/gen_ndr/ndr_epmapper.h"
 #include "librpc/gen_ndr/ndr_epmapper_scompat.h"
+#include "param/loadparm.h"
+#include "libds/common/roles.h"
 
 static size_t epmapper_interfaces(
 	const struct ndr_interface_table ***pifaces,
@@ -27,8 +29,22 @@ static size_t epmapper_interfaces(
 	static const struct ndr_interface_table *ifaces[] = {
 		&ndr_table_epmapper,
 	};
+	size_t num_ifaces = ARRAY_SIZE(ifaces);
+
+	switch(lp_server_role()) {
+	case ROLE_ACTIVE_DIRECTORY_DC:
+		/*
+		 * On the AD DC epmapper is provided by the 'samba'
+		 * binary from source4/
+		 */
+		num_ifaces = 0;
+		break;
+	default:
+		break;
+	}
+
 	*pifaces = ifaces;
-	return ARRAY_SIZE(ifaces);
+	return num_ifaces;
 }
 
 static size_t epmapper_servers(
@@ -37,11 +53,24 @@ static size_t epmapper_servers(
 	void *private_data)
 {
 	static const struct dcesrv_endpoint_server *ep_servers[] = { NULL };
+	size_t num_servers = ARRAY_SIZE(ep_servers);
 
 	ep_servers[0] = epmapper_get_ep_server();
 
+	switch(lp_server_role()) {
+	case ROLE_ACTIVE_DIRECTORY_DC:
+		/*
+		 * On the AD DC epmapper is provided by the 'samba'
+		 * binary from source4/
+		 */
+		num_servers = 0;
+		break;
+	default:
+		break;
+	}
+
 	*_ep_servers = ep_servers;
-	return ARRAY_SIZE(ep_servers);
+	return num_servers;
 }
 
 int main(int argc, const char *argv[])
diff --git a/source3/rpc_server/rpcd_lsad.c b/source3/rpc_server/rpcd_lsad.c
index 3ca0ed43fdd..b0e021493e7 100644
--- a/source3/rpc_server/rpcd_lsad.c
+++ b/source3/rpc_server/rpcd_lsad.c
@@ -36,6 +36,11 @@ static size_t lsad_interfaces(
 		&ndr_table_lsarpc,
 		&ndr_table_samr,
 		&ndr_table_dssetup,
+		/*
+		 * This last item is truncated from the list by the
+		 * num_ifaces -= 1 below for the fileserver.  Take
+		 * care when adding new services.
+		 */
 		&ndr_table_netlogon,
 	};
 	size_t num_ifaces = ARRAY_SIZE(ifaces);
@@ -46,6 +51,14 @@ static size_t lsad_interfaces(
 		/* no netlogon for non-dc */
 		num_ifaces -= 1;
 		break;
+	case ROLE_ACTIVE_DIRECTORY_DC:
+		/*
+		 * All these services are provided by the 'samba'
+		 * binary from source4, not this code which is the
+		 * source3 / NT4-like "classic" DC implementation
+		 */
+		num_ifaces = 0;
+		break;
 	default:
 		break;
 	}
@@ -80,6 +93,14 @@ static size_t lsad_servers(
 		/* no netlogon for non-dc */
 		num_servers -= 1;
 		break;
+	case ROLE_ACTIVE_DIRECTORY_DC:
+		/*
+		 * All these services are provided by the 'samba'
+		 * binary from source4, not this code which is the
+		 * source3 / NT4-like "classic" DC implementation
+		 */
+		num_servers = 0;
+		break;
 	default:
 		break;
 	}
diff --git a/source3/rpc_server/rpcd_rpcecho.c b/source3/rpc_server/rpcd_rpcecho.c
index 9176039819f..37391f563db 100644
--- a/source3/rpc_server/rpcd_rpcecho.c
+++ b/source3/rpc_server/rpcd_rpcecho.c
@@ -19,6 +19,8 @@
 #include "rpc_worker.h"
 #include "librpc/gen_ndr/ndr_echo.h"
 #include "librpc/gen_ndr/ndr_echo_scompat.h"
+#include "param/loadparm.h"
+#include "libds/common/roles.h"
 
 static size_t rpcecho_interfaces(
 	const struct ndr_interface_table ***pifaces,
@@ -27,8 +29,22 @@ static size_t rpcecho_interfaces(
 	static const struct ndr_interface_table *ifaces[] = {
 		&ndr_table_rpcecho,
 	};
+	size_t num_ifaces = ARRAY_SIZE(ifaces);
+
+	switch(lp_server_role()) {
+	case ROLE_ACTIVE_DIRECTORY_DC:
+		/*
+		 * On the AD DC rpcecho is provided by the 'samba'
+		 * binary from source4/
+		 */
+		num_ifaces = 0;
+		break;
+	default:
+		break;
+	}
+
 	*pifaces = ifaces;
-	return ARRAY_SIZE(ifaces);
+	return num_ifaces;
 }
 
 static size_t rpcecho_servers(
@@ -37,11 +53,24 @@ static size_t rpcecho_servers(
 	void *private_data)
 {
 	static const struct dcesrv_endpoint_server *ep_servers[1] = { NULL };
+	size_t num_servers = ARRAY_SIZE(ep_servers);
 
 	ep_servers[0] = rpcecho_get_ep_server();
 
+	switch(lp_server_role()) {
+	case ROLE_ACTIVE_DIRECTORY_DC:
+		/*
+		 * On the AD DC rpcecho is provided by the 'samba'
+		 * binary from source4/
+		 */
+		num_servers = 0;
+		break;
+	default:
+		break;
+	}
+
 	*_ep_servers = ep_servers;
-	return ARRAY_SIZE(ep_servers);
+	return num_servers;
 }
 
 int main(int argc, const char *argv[])
-- 
2.34.1
