From 6b76bc7339addb14884c2d6ddb20c559c7fbe07d Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Thu, 9 Jun 2022 19:32:30 +1200
Subject: [PATCH 14/15] CVE-2022-32743 s4:rpc_server/common: Add
 dcesrv_samdb_connect_session_info()

This function allows us to connect to samdb as a particular user by
passing in that user's session info.

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

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
---
 source4/rpc_server/common/common.h      |  1 +
 source4/rpc_server/common/server_info.c | 65 ++++++++++++++++++++-------------
 2 files changed, 40 insertions(+), 26 deletions(-)

diff --git a/source4/rpc_server/common/common.h b/source4/rpc_server/common/common.h
index 7d2f8c5..b57ddf2 100644
--- a/source4/rpc_server/common/common.h
+++ b/source4/rpc_server/common/common.h
@@ -30,6 +30,7 @@ struct dcesrv_context;
 struct dcesrv_call_state;
 struct ndr_interface_table;
 struct ncacn_packet;
+struct auth_session_info;
 
 struct dcerpc_server_info { 
 	const char *domain_name;
diff --git a/source4/rpc_server/common/server_info.c b/source4/rpc_server/common/server_info.c
index a2af376..34228c3 100644
--- a/source4/rpc_server/common/server_info.c
+++ b/source4/rpc_server/common/server_info.c
@@ -190,48 +190,44 @@ bool dcesrv_common_validate_share_name(TALLOC_CTX *mem_ctx, const char *share_na
 	return true;
 }
 
-static struct ldb_context *dcesrv_samdb_connect_common(
+/*
+ * call_session_info is session info for samdb. call_audit_session_info is for
+ * auditing and may be NULL.
+ */
+struct ldb_context *dcesrv_samdb_connect_session_info(
 	TALLOC_CTX *mem_ctx,
 	struct dcesrv_call_state *dce_call,
-	bool as_system)
+	const struct auth_session_info *call_session_info,
+	const struct auth_session_info *call_audit_session_info)
 {
 	struct ldb_context *samdb = NULL;
-	struct auth_session_info *system_session_info = NULL;
-	const struct auth_session_info *call_session_info =
-		dcesrv_call_session_info(dce_call);
 	struct auth_session_info *user_session_info = NULL;
-	struct auth_session_info *ldb_session_info = NULL;
 	struct auth_session_info *audit_session_info = NULL;
 	struct tsocket_address *remote_address = NULL;
 
-	if (as_system) {
-		system_session_info = system_session(dce_call->conn->dce_ctx->lp_ctx);
-		if (system_session_info == NULL) {
-			return NULL;
-		}
-	}
-
 	user_session_info = copy_session_info(mem_ctx, call_session_info);
 	if (user_session_info == NULL) {
 		return NULL;
 	}
 
+	if (call_audit_session_info != NULL) {
+		audit_session_info = copy_session_info(mem_ctx, call_audit_session_info);
+		if (audit_session_info == NULL) {
+			talloc_free(user_session_info);
+			return NULL;
+		}
+	}
+
 	if (dce_call->conn->remote_address != NULL) {
 		remote_address = tsocket_address_copy(dce_call->conn->remote_address,
 						      user_session_info);
 		if (remote_address == NULL) {
+			TALLOC_FREE(audit_session_info);
+			talloc_free(user_session_info);
 			return NULL;
 		}
 	}
 
-	if (system_session_info != NULL) {
-		ldb_session_info = system_session_info;
-		audit_session_info = user_session_info;
-	} else {
-		ldb_session_info = user_session_info;
-		audit_session_info = NULL;
-	}
-
 	/*
 	 * We need to make sure every argument
 	 * stays arround for the lifetime of 'samdb',
@@ -253,10 +249,11 @@ static struct ldb_context *dcesrv_samdb_connect_common(
 		mem_ctx,
 		dce_call->event_ctx,
 		dce_call->conn->dce_ctx->lp_ctx,
-		ldb_session_info,
+		user_session_info,
 		remote_address,
 		0);
 	if (samdb == NULL) {
+		TALLOC_FREE(audit_session_info);
 		talloc_free(user_session_info);
 		return NULL;
 	}
@@ -265,6 +262,8 @@ static struct ldb_context *dcesrv_samdb_connect_common(
 	if (audit_session_info != NULL) {
 		int ret;
 
+		talloc_steal(samdb, audit_session_info);
+
 		ret = ldb_set_opaque(samdb,
 				     DSDB_NETWORK_SESSION_INFO,
 				     audit_session_info);
@@ -288,8 +287,18 @@ struct ldb_context *dcesrv_samdb_connect_as_system(
 	TALLOC_CTX *mem_ctx,
 	struct dcesrv_call_state *dce_call)
 {
-	return dcesrv_samdb_connect_common(mem_ctx, dce_call,
-					   true /* as_system */);
+	const struct auth_session_info *system_session_info = NULL;
+	const struct auth_session_info *call_session_info = NULL;
+
+	system_session_info = system_session(dce_call->conn->dce_ctx->lp_ctx);
+	if (system_session_info == NULL) {
+		return NULL;
+	}
+
+	call_session_info = dcesrv_call_session_info(dce_call);
+
+	return dcesrv_samdb_connect_session_info(mem_ctx, dce_call,
+						 system_session_info, call_session_info);
 }
 
 /*
@@ -301,6 +310,10 @@ struct ldb_context *dcesrv_samdb_connect_as_user(
 	TALLOC_CTX *mem_ctx,
 	struct dcesrv_call_state *dce_call)
 {
-	return dcesrv_samdb_connect_common(mem_ctx, dce_call,
-					   false /* not as_system */);
+	const struct auth_session_info *call_session_info = NULL;
+
+	call_session_info = dcesrv_call_session_info(dce_call);
+
+	return dcesrv_samdb_connect_session_info(mem_ctx, dce_call,
+						 call_session_info, NULL);
 }
-- 
1.8.3.1

