From ed1542b9f37734bc77906c4ba49ea6ea3be09af8 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Thu, 10 Sep 2020 17:13:14 +0200
Subject: [PATCH 026/266] CVE-2020-25717 wb_sids2xids: build state->idmap_doms
 based on wb_parent_idmap_config

In future we'll try to avoid wb_lookupsids_send() and only call
it if needed.

The domain name passed should be only relevant to find the correct
idmap backend, and these should all be available in
wb_parent_idmap_config as it was created before the idmap child was forked.

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

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Gary Lockyer <gary@catalyst.net.nz>

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

(cherry picked from commit c55f4f37589130a0d8952489da175bbcf53f6748)
---
 source3/winbindd/wb_sids2xids.c | 101 +++++++++++++++++++-------------
 1 file changed, 61 insertions(+), 40 deletions(-)

Conflict:lookup_sids --> non_cached
lookup_count --> num_non_cached
li --> i
delete 'uint32_t ai = state->tmp_idx[i]'
state->all_ids.ids[i] --> &state->ids.ids[i]
add 't->xid.id = UINT32_MAX;
t->xid.type = t->type;'
type_hint --> type
Reference:https://git.samba.org/samba.git/?p=samba.git;a=patch;h=ed1542b9f37734bc77906c4ba49ea6ea3be09af8

diff --git a/source3/winbindd/wb_sids2xids.c b/source3/winbindd/wb_sids2xids.c
index 21bf5f901f3..3a3d47abbe5 100644
--- a/source3/winbindd/wb_sids2xids.c
+++ b/source3/winbindd/wb_sids2xids.c
@@ -193,6 +193,7 @@ static void wb_sids2xids_idmap_setup_done(struct tevent_req *subreq)
 	struct wb_sids2xids_state *state = tevent_req_data(
 		req, struct wb_sids2xids_state);
 	NTSTATUS status;
+	uint32_t i;
 
 	status = wb_parent_idmap_setup_recv(subreq, &state->cfg);
 	TALLOC_FREE(subreq);
@@ -201,6 +202,66 @@ static void wb_sids2xids_idmap_setup_done(struct tevent_req *subreq)
 	}
 	SMB_ASSERT(state->cfg->num_doms > 0);
 
+	/*
+	 * Now we build a list with all domain
+	 * with non cached entries
+	 */
+	for (i=0; i<state->num_sids; i++) {
+		struct wbint_TransID *t = &state->ids.ids[i];
+		struct dom_sid domain_sid;
+		const char *domain_name = NULL;
+		int domain_index;
+		uint32_t rid = 0;
+		uint32_t di;
+
+		if (t->domain_index == UINT32_MAX) {
+			/* ignore already filled entries */
+			continue;
+		}
+
+		sid_copy(&domain_sid, &state->sids[i]);
+		sid_split_rid(&domain_sid, &rid);
+
+		for (di = 0; di < state->cfg->num_doms; di++) {
+			struct wb_parent_idmap_config_dom *dom =
+				&state->cfg->doms[di];
+			bool match;
+
+			match = dom_sid_equal(&domain_sid,
+					      &dom->sid);
+			if (!match) {
+				continue;
+			}
+
+			domain_name = dom->name;
+			break;
+		}
+		if (domain_name == NULL) {
+			struct winbindd_domain *wb_domain = NULL;
+
+			/*
+			 * Try to fill the name if we already know it
+			 */
+			wb_domain = find_domain_from_sid_noinit(&state->sids[i]);
+			if (wb_domain != NULL) {
+				domain_name = wb_domain->name;
+			}
+		}
+		if (domain_name == NULL) {
+			domain_name = "";
+		}
+
+		domain_index = init_lsa_ref_domain_list(state,
+							&state->idmap_doms,
+							domain_name,
+							&domain_sid);
+		if (domain_index == -1) {
+			tevent_req_oom(req);
+			return;
+		}
+		t->domain_index = domain_index;
+	}
+
 	subreq = wb_lookupsids_send(state,
 				    state->ev,
 				    state->non_cached,
@@ -251,51 +312,11 @@ static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq)
 	}
 
 	for (i=0; i<state->num_non_cached; i++) {
-		const struct dom_sid *sid = &state->non_cached[i];
-		struct dom_sid dom_sid;
 		struct lsa_TranslatedName *n = &names->names[i];
 		struct wbint_TransID *t = &state->ids.ids[i];
-		int domain_index;
-		const char *domain_name = NULL;
-
-		if (n->sid_index != UINT32_MAX) {
-			const struct lsa_DomainInfo *info;
-			bool match;
-
-			info = &domains->domains[n->sid_index];
-			match = dom_sid_in_domain(info->sid, sid);
-			if (match) {
-				domain_name = info->name.string;
-			}
-		}
-		if (domain_name == NULL) {
-			struct winbindd_domain *wb_domain = NULL;
-
-			/*
-			 * This is needed to handle Samba DCs
-			 * which always return sid_index == UINT32_MAX for
-			 * unknown sids.
-			 */
-			wb_domain = find_domain_from_sid_noinit(sid);
-			if (wb_domain != NULL) {
-				domain_name = wb_domain->name;
-			}
-		}
-		if (domain_name == NULL) {
-			domain_name = "";
-		}
 
-		sid_copy(&dom_sid, sid);
-		sid_split_rid(&dom_sid, &t->rid);
 		t->type = lsa_SidType_to_id_type(n->sid_type);
-		domain_index = init_lsa_ref_domain_list(
-			state, &state->idmap_doms, domain_name, &dom_sid);
-		if (domain_index == -1) {
-			tevent_req_oom(req);
-			return;
-		}
-		t->domain_index = domain_index;

 		t->xid.id = UINT32_MAX;
 		t->xid.type = t->type;
 	}
-- 
2.23.0

