[PATCH] More preparatory patches for winbindd and trusts

Ralph Böhme slow at samba.org
Wed Jan 10 19:59:35 UTC 2018


Hi!

Attached is another preparatory patchset from my winbindd-trusts branch [1],
this one should be applied on-top of the previous patchset.
                                        
Patches are already reviewed by metze. I'm currently running a final private                                        
autobuild. If that passes and no-one objects, I will push later.

-slow

[1] https://git.samba.org/?p=slow/samba.git;a=shortlog;h=refs/heads/trusts

-- 
Ralph Boehme, Samba Team       https://samba.org/
Samba Developer, SerNet GmbH   https://sernet.de/en/samba/
-------------- next part --------------
From 87dbf842cbfee593c9b25b1d20010ee582935f17 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 29 Nov 2017 15:10:38 +0100
Subject: [PATCH 01/23] winbindd: remember the secure_channel_type in
 winbindd_domain

This way we have an indication of non direct trusts with
SEC_CHAN_NULL.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/winbindd/winbindd.h      |  1 +
 source3/winbindd/winbindd_util.c | 24 ++++++++++++++++++++++++
 2 files changed, 25 insertions(+)

diff --git a/source3/winbindd/winbindd.h b/source3/winbindd/winbindd.h
index 396f7f7946e..682040fd1a7 100644
--- a/source3/winbindd/winbindd.h
+++ b/source3/winbindd/winbindd.h
@@ -139,6 +139,7 @@ struct winbindd_domain {
 	char *alt_name;                        /* alt Domain name, if any (FQDN for ADS) */
 	char *forest_name;                     /* Name of the AD forest we're in */
 	struct dom_sid sid;                           /* SID for this domain */
+	enum netr_SchannelType secure_channel_type;
 	uint32_t domain_flags;                   /* Domain flags from netlogon.h */
 	uint32_t domain_type;                    /* Domain type from netlogon.h */
 	uint32_t domain_trust_attribs;           /* Trust attribs from netlogon.h */
diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c
index c45d6acb0ad..3b8fae141bb 100644
--- a/source3/winbindd/winbindd_util.c
+++ b/source3/winbindd/winbindd_util.c
@@ -125,6 +125,7 @@ static NTSTATUS add_trusted_domain(const char *domain_name,
 				   uint32_t trust_type,
 				   uint32_t trust_flags,
 				   uint32_t trust_attribs,
+				   enum netr_SchannelType secure_channel_type,
 				   struct winbindd_domain **_d)
 {
 	struct winbindd_domain *domain = NULL;
@@ -240,6 +241,7 @@ static NTSTATUS add_trusted_domain(const char *domain_name,
 
 	domain->backend = NULL;
 	domain->internal = is_internal_domain(sid);
+	domain->secure_channel_type = secure_channel_type;
 	domain->sequence_number = DOM_SEQUENCE_NONE;
 	domain->last_seq_check = 0;
 	domain->initialized = false;
@@ -249,6 +251,7 @@ static NTSTATUS add_trusted_domain(const char *domain_name,
 	domain->domain_flags = trust_flags;
 	domain->domain_type = trust_type;
 	domain->domain_trust_attribs = trust_attribs;
+	domain->secure_channel_type = secure_channel_type;
 	sid_copy(&domain->sid, sid);
 
 	/* Is this our primary domain ? */
@@ -464,6 +467,7 @@ static void trustdom_list_done(struct tevent_req *req)
 					    trust_type,
 					    trust_flags,
 					    trust_attribs,
+					    SEC_CHAN_NULL,
 					    &domain);
 		if (!NT_STATUS_IS_OK(status) &&
 		    !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
@@ -546,6 +550,7 @@ static void rescan_forest_root_trusts( void )
 						    dom_list[i].trust_type,
 						    dom_list[i].trust_flags,
 						    dom_list[i].trust_attribs,
+						    SEC_CHAN_NULL,
 						    &d);
 
 			if (!NT_STATUS_IS_OK(status) &&
@@ -627,6 +632,7 @@ static void rescan_forest_trusts( void )
 					type,
 					flags,
 					attribs,
+					SEC_CHAN_NULL,
 					&d);
 				if (!NT_STATUS_IS_OK(status) &&
 				    NT_STATUS_EQUAL(status,
@@ -736,6 +742,7 @@ static void wb_imsg_new_trusted_domain(struct imessaging_context *msg,
 				       DATA_BLOB *data)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
+	enum netr_SchannelType secure_channel_type = SEC_CHAN_DOMAIN;
 	struct lsa_TrustDomainInfoInfoEx info;
 	enum ndr_err_code ndr_err;
 	struct winbindd_domain *d = NULL;
@@ -762,6 +769,9 @@ static void wb_imsg_new_trusted_domain(struct imessaging_context *msg,
 		return;
 	}
 
+	if (info.trust_type == LSA_TRUST_TYPE_UPLEVEL) {
+		secure_channel_type = SEC_CHAN_DNS_DOMAIN;
+	}
 	if (info.trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
 		trust_flags |= NETR_TRUST_FLAG_INBOUND;
 	}
@@ -778,6 +788,7 @@ static void wb_imsg_new_trusted_domain(struct imessaging_context *msg,
 				    info.trust_type,
 				    trust_flags,
 				    info.trust_attributes,
+				    secure_channel_type,
 				    &d);
 	if (!NT_STATUS_IS_OK(status) &&
 	    !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
@@ -852,6 +863,7 @@ bool init_domain_list(void)
 				    LSA_TRUST_TYPE_DOWNLEVEL,
 				    0, /* trust_flags */
 				    0, /* trust_attribs */
+				    SEC_CHAN_LOCAL,
 				    &domain);
 	if (!NT_STATUS_IS_OK(status)) {
 		DBG_ERR("add_trusted_domain BUILTIN returned %s\n",
@@ -903,6 +915,7 @@ bool init_domain_list(void)
 					    LSA_TRUST_TYPE_UPLEVEL,
 					    trust_flags,
 					    LSA_TRUST_ATTRIBUTE_WITHIN_FOREST,
+					    SEC_CHAN_BDC,
 					    &domain);
 		TALLOC_FREE(pdb_domain_info);
 		if (!NT_STATUS_IS_OK(status)) {
@@ -946,24 +959,34 @@ bool init_domain_list(void)
 				return false;
 			}
 		}
+
+		domain->secure_channel_type = sec_chan_type;
 		if (sec_chan_type == SEC_CHAN_RODC) {
 			domain->rodc = true;
 		}
 
 	} else {
 		uint32_t trust_flags;
+		enum netr_SchannelType secure_channel_type;
 
 		trust_flags = NETR_TRUST_FLAG_OUTBOUND;
 		if (role != ROLE_DOMAIN_MEMBER) {
 			trust_flags |= NETR_TRUST_FLAG_PRIMARY;
 		}
 
+		if (role > ROLE_DOMAIN_MEMBER) {
+			secure_channel_type = SEC_CHAN_BDC;
+		} else {
+			secure_channel_type = SEC_CHAN_LOCAL;
+		}
+
 		status = add_trusted_domain(get_global_sam_name(),
 					    NULL,
 					    get_global_sam_sid(),
 					    LSA_TRUST_TYPE_DOWNLEVEL,
 					    trust_flags,
 					    0, /* trust_attribs */
+					    secure_channel_type,
 					    &domain);
 		if (!NT_STATUS_IS_OK(status)) {
 			DBG_ERR("Failed to add local SAM to "
@@ -995,6 +1018,7 @@ bool init_domain_list(void)
 					    NETR_TRUST_FLAG_PRIMARY|
 					    NETR_TRUST_FLAG_OUTBOUND,
 					    0, /* trust_attribs */
+					    SEC_CHAN_WKSTA,
 					    &domain);
 		if (!NT_STATUS_IS_OK(status)) {
 			DBG_ERR("Failed to add local SAM to "
-- 
2.13.6


From 4c44de52d75c4ff723a0cf2c888729d39a7baff3 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 29 Nov 2017 15:23:36 +0100
Subject: [PATCH 02/23] winbindd: add find_trust_from_{name,sid}_noinit()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/winbindd/winbindd_proto.h |  2 ++
 source3/winbindd/winbindd_util.c  | 44 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 46 insertions(+)

diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h
index 8af79324c69..dd6767a02ab 100644
--- a/source3/winbindd/winbindd_proto.h
+++ b/source3/winbindd/winbindd_proto.h
@@ -445,8 +445,10 @@ enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domai
 						   struct winbindd_cli_state *state);
 bool init_domain_list(void);
 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name);
+struct winbindd_domain *find_trust_from_name_noinit(const char *domain_name);
 struct winbindd_domain *find_domain_from_name(const char *domain_name);
 struct winbindd_domain *find_domain_from_sid_noinit(const struct dom_sid *sid);
+struct winbindd_domain *find_trust_from_sid_noinit(const struct dom_sid *sid);
 struct winbindd_domain *find_domain_from_sid(const struct dom_sid *sid);
 struct winbindd_domain *find_our_domain(void);
 struct winbindd_domain *find_lookup_domain_from_sid(const struct dom_sid *sid);
diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c
index 3b8fae141bb..9c8e39f79c1 100644
--- a/source3/winbindd/winbindd_util.c
+++ b/source3/winbindd/winbindd_util.c
@@ -1082,6 +1082,28 @@ struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
 	return NULL;
 }
 
+/**
+ * Given a domain name, return the struct winbindd domain if it's a direct
+ * outgoing trust
+ *
+ * @return The domain structure for the named domain, if it is a direct outgoing trust
+ */
+struct winbindd_domain *find_trust_from_name_noinit(const char *domain_name)
+{
+	struct winbindd_domain *domain = NULL;
+
+	domain = find_domain_from_name_noinit(domain_name);
+	if (domain == NULL) {
+		return NULL;
+	}
+
+	if (domain->secure_channel_type != SEC_CHAN_NULL) {
+		return domain;
+	}
+
+	return NULL;
+}
+
 struct winbindd_domain *find_domain_from_name(const char *domain_name)
 {
 	struct winbindd_domain *domain;
@@ -1115,6 +1137,28 @@ struct winbindd_domain *find_domain_from_sid_noinit(const struct dom_sid *sid)
 	return NULL;
 }
 
+/**
+ * Given a domain sid, return the struct winbindd domain if it's a direct
+ * outgoing trust
+ *
+ * @return The domain structure for the specified domain, if it is a direct outgoing trust
+ */
+struct winbindd_domain *find_trust_from_sid_noinit(const struct dom_sid *sid)
+{
+	struct winbindd_domain *domain = NULL;
+
+	domain = find_domain_from_sid_noinit(sid);
+	if (domain == NULL) {
+		return NULL;
+	}
+
+	if (domain->secure_channel_type != SEC_CHAN_NULL) {
+		return domain;
+	}
+
+	return NULL;
+}
+
 /* Given a domain sid, return the struct winbindd domain info for it */
 
 struct winbindd_domain *find_domain_from_sid(const struct dom_sid *sid)
-- 
2.13.6


From d5d84ca59faaefd7cf8c22ced8dd59be47fa3e19 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 30 Nov 2017 13:04:56 +0100
Subject: [PATCH 03/23] winbindd: use find_trust_from_name_noinit when we
 require a direct trust

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/winbindd/winbindd_irpc.c    | 2 +-
 source3/winbindd/winbindd_misc.c    | 2 +-
 source3/winbindd/winbindd_ping_dc.c | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/source3/winbindd/winbindd_irpc.c b/source3/winbindd/winbindd_irpc.c
index d0d68c89411..4101469ad99 100644
--- a/source3/winbindd/winbindd_irpc.c
+++ b/source3/winbindd/winbindd_irpc.c
@@ -282,7 +282,7 @@ static NTSTATUS wb_irpc_GetForestTrustInformation(struct irpc_message *msg,
 		return NT_STATUS_OK;
 	}
 
-	domain = find_domain_from_name_noinit(req->in.trusted_domain_name);
+	domain = find_trust_from_name_noinit(req->in.trusted_domain_name);
 	if (domain == NULL) {
 		req->out.result = WERR_NO_SUCH_DOMAIN;
 		return NT_STATUS_OK;
diff --git a/source3/winbindd/winbindd_misc.c b/source3/winbindd/winbindd_misc.c
index 6cf33420768..c80e7844bc2 100644
--- a/source3/winbindd/winbindd_misc.c
+++ b/source3/winbindd/winbindd_misc.c
@@ -336,7 +336,7 @@ void winbindd_dc_info(struct winbindd_cli_state *cli)
 		  cli->request->domain_name));
 
 	if (cli->request->domain_name[0] != '\0') {
-		domain = find_domain_from_name_noinit(
+		domain = find_trust_from_name_noinit(
 			cli->request->domain_name);
 		if (domain == NULL) {
 			DEBUG(10, ("Could not find domain %s\n",
diff --git a/source3/winbindd/winbindd_ping_dc.c b/source3/winbindd/winbindd_ping_dc.c
index 05e84020625..a6cea79ee2a 100644
--- a/source3/winbindd/winbindd_ping_dc.c
+++ b/source3/winbindd/winbindd_ping_dc.c
@@ -47,7 +47,7 @@ struct tevent_req *winbindd_ping_dc_send(TALLOC_CTX *mem_ctx,
 		/* preserve old behavior, when no domain name is given */
 		domain = find_our_domain();
 	} else {
-		domain = find_domain_from_name_noinit(request->domain_name);
+		domain = find_trust_from_name_noinit(request->domain_name);
 	}
 	if (domain == NULL) {
 		tevent_req_nterror(req, NT_STATUS_NO_SUCH_DOMAIN);
-- 
2.13.6


From 846570273b3fe5fbd1ef27f64bae9f3dacc8aae5 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 11 Dec 2017 07:56:02 +0100
Subject: [PATCH 04/23] s3/torture/pdbtest: creating a trusted domain requires
 a valid SID

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/torture/pdbtest.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/source3/torture/pdbtest.c b/source3/torture/pdbtest.c
index adbd982ab44..71b5c61fc58 100644
--- a/source3/torture/pdbtest.c
+++ b/source3/torture/pdbtest.c
@@ -450,6 +450,7 @@ static bool test_trusted_domains(TALLOC_CTX *ctx,
 	struct trustAuthInOutBlob taiob;
 	struct AuthenticationInformation aia;
 	enum ndr_err_code ndr_err;
+	bool ok;
 
 	td = talloc_zero(ctx ,struct pdb_trusted_domain);
 	if (!td) {
@@ -463,6 +464,11 @@ static bool test_trusted_domains(TALLOC_CTX *ctx,
 		fprintf(stderr, "talloc failed\n");
 		return false;
 	}
+	ok = dom_sid_parse("S-1-5-21-123-456-789", &td->security_identifier);
+	if (!ok) {
+		fprintf(stderr, "dom_sid_parse S-1-5-21-123-456-789 failed\n");
+		return false;
+	}
 
 	td->trust_auth_incoming = data_blob_null;
 
-- 
2.13.6


From 3e3e656949a474018c82adffe708c854389d36b0 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 11 Dec 2017 07:56:40 +0100
Subject: [PATCH 05/23] s3/torture/pdbtest: delete trusted domain at test end

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/torture/pdbtest.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/source3/torture/pdbtest.c b/source3/torture/pdbtest.c
index 71b5c61fc58..64bc45e6a7c 100644
--- a/source3/torture/pdbtest.c
+++ b/source3/torture/pdbtest.c
@@ -526,6 +526,13 @@ static bool test_trusted_domains(TALLOC_CTX *ctx,
 		*error = true;
 	}
 
+	rv = pdb->del_trusted_domain(pdb, TRUST_DOM);
+	if (!NT_STATUS_IS_OK(rv)) {
+		fprintf(stderr, "Error in del_trusted_domain %s\n",
+				get_friendly_nt_error_msg(rv));
+		*error = true;
+	}
+
 	return true;
 }
 
-- 
2.13.6


From 288137472cc76e91468a99d3b1a8215fbcf4d20a Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 1 Dec 2017 08:33:51 +0100
Subject: [PATCH 06/23] s4:dsdb: add dsdb_trust_search_tdo_by_sid() helper
 function

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source4/dsdb/common/util_trusts.c | 65 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 65 insertions(+)

diff --git a/source4/dsdb/common/util_trusts.c b/source4/dsdb/common/util_trusts.c
index a083d869f6e..1534829199b 100644
--- a/source4/dsdb/common/util_trusts.c
+++ b/source4/dsdb/common/util_trusts.c
@@ -33,6 +33,7 @@
 #include "libds/common/flag_mapping.h"
 #include "../lib/util/dlinklist.h"
 #include "../lib/crypto/crypto.h"
+#include "libcli/ldap/ldap_ndr.h"
 
 NTSTATUS dsdb_trust_forest_info_from_lsa(TALLOC_CTX *mem_ctx,
 				const struct lsa_ForestTrustInformation *lfti,
@@ -2567,6 +2568,70 @@ NTSTATUS dsdb_trust_search_tdo_by_type(struct ldb_context *sam_ctx,
 	return NT_STATUS_OK;
 }
 
+NTSTATUS dsdb_trust_search_tdo_by_sid(struct ldb_context *sam_ctx,
+				      const struct dom_sid *sid,
+				      const char * const *attrs,
+				      TALLOC_CTX *mem_ctx,
+				      struct ldb_message **msg)
+{
+	TALLOC_CTX *frame = talloc_stackframe();
+	int ret;
+	struct ldb_dn *system_dn = NULL;
+	char *encoded_sid = NULL;
+	char *filter = NULL;
+
+	*msg = NULL;
+
+	if (sid == NULL) {
+		TALLOC_FREE(frame);
+		return NT_STATUS_INVALID_PARAMETER_MIX;
+	}
+
+	encoded_sid = ldap_encode_ndr_dom_sid(frame, sid);
+	if (encoded_sid == NULL) {
+		TALLOC_FREE(frame);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	system_dn = ldb_dn_copy(frame, ldb_get_default_basedn(sam_ctx));
+	if (system_dn == NULL) {
+		TALLOC_FREE(frame);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	if (!ldb_dn_add_child_fmt(system_dn, "CN=System")) {
+		TALLOC_FREE(frame);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	filter = talloc_asprintf(frame,
+				"(&"
+				  "(objectClass=trustedDomain)"
+				  "(securityIdentifier=%s)"
+				")",
+				encoded_sid);
+	if (filter == NULL) {
+		TALLOC_FREE(frame);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	ret = dsdb_search_one(sam_ctx, mem_ctx, msg,
+			      system_dn,
+			      LDB_SCOPE_ONELEVEL, attrs,
+			      DSDB_SEARCH_NO_GLOBAL_CATALOG,
+			      "%s", filter);
+	if (ret != LDB_SUCCESS) {
+		NTSTATUS status = dsdb_ldb_err_to_ntstatus(ret);
+		DEBUG(3, ("Failed to search for %s: %s - %s\n",
+			  filter, nt_errstr(status), ldb_errstring(sam_ctx)));
+		TALLOC_FREE(frame);
+		return status;
+	}
+
+	TALLOC_FREE(frame);
+	return NT_STATUS_OK;
+}
+
 NTSTATUS dsdb_trust_get_incoming_passwords(struct ldb_message *msg,
 					   TALLOC_CTX *mem_ctx,
 					   struct samr_Password **_current,
-- 
2.13.6


From b7d91a46e857dada59810ec8ebf96aa24f18e5de Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 1 Dec 2017 07:59:59 +0100
Subject: [PATCH 07/23] pdb_samba_dsdb: implement
 pdb_samba_dsdb_enum_trusteddoms()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/passdb/pdb_samba_dsdb.c | 86 +++++++++++++++++++++++++++++++++++++++--
 1 file changed, 82 insertions(+), 4 deletions(-)

diff --git a/source3/passdb/pdb_samba_dsdb.c b/source3/passdb/pdb_samba_dsdb.c
index 58168d843aa..d70a867505d 100644
--- a/source3/passdb/pdb_samba_dsdb.c
+++ b/source3/passdb/pdb_samba_dsdb.c
@@ -2878,11 +2878,89 @@ static bool pdb_samba_dsdb_del_trusteddom_pw(struct pdb_methods *m,
 
 static NTSTATUS pdb_samba_dsdb_enum_trusteddoms(struct pdb_methods *m,
 					 TALLOC_CTX *mem_ctx,
-					 uint32_t *num_domains,
-					 struct trustdom_info ***domains)
+					 uint32_t *_num_domains,
+					 struct trustdom_info ***_domains)
 {
-	*num_domains = 0;
-	*domains = NULL;
+	struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+		m->private_data, struct pdb_samba_dsdb_state);
+	TALLOC_CTX *tmp_ctx = talloc_stackframe();
+	const char * const attrs[] = {
+		"securityIdentifier",
+		"flatName",
+		"trustDirection",
+		NULL
+	};
+	struct ldb_result *res = NULL;
+	unsigned int i;
+	struct trustdom_info **domains = NULL;
+	NTSTATUS status;
+	uint32_t di = 0;
+
+	*_num_domains = 0;
+	*_domains = NULL;
+
+	status = dsdb_trust_search_tdos(state->ldb, NULL,
+					attrs, tmp_ctx, &res);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_ERR("dsdb_trust_search_tdos() - %s ", nt_errstr(status));
+		TALLOC_FREE(tmp_ctx);
+		return status;
+	}
+
+	if (res->count == 0) {
+		TALLOC_FREE(tmp_ctx);
+		return NT_STATUS_OK;
+	}
+
+	domains = talloc_zero_array(tmp_ctx, struct trustdom_info *,
+				    res->count);
+	if (domains == NULL) {
+		TALLOC_FREE(tmp_ctx);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	for (i = 0; i < res->count; i++) {
+		struct ldb_message *msg = res->msgs[i];
+		struct trustdom_info *d = NULL;
+		const char *name = NULL;
+		struct dom_sid *sid = NULL;
+		uint32_t direction;
+
+		d = talloc_zero(domains, struct trustdom_info);
+		if (d == NULL) {
+			TALLOC_FREE(tmp_ctx);
+			return NT_STATUS_NO_MEMORY;
+		}
+
+		name = ldb_msg_find_attr_as_string(msg, "flatName", NULL);
+		if (name == NULL) {
+			TALLOC_FREE(tmp_ctx);
+			return NT_STATUS_INTERNAL_DB_CORRUPTION;
+		}
+		sid = samdb_result_dom_sid(msg, msg, "securityIdentifier");
+		if (sid == NULL) {
+			continue;
+		}
+
+		direction = ldb_msg_find_attr_as_uint(msg, "trustDirection", 0);
+		if (!(direction & LSA_TRUST_DIRECTION_OUTBOUND)) {
+			continue;
+		}
+
+		d->name = talloc_strdup(d, name);
+		if (d->name == NULL) {
+			TALLOC_FREE(tmp_ctx);
+			return NT_STATUS_NO_MEMORY;
+		}
+		d->sid = *sid;
+
+		domains[di++] = d;
+	}
+
+	talloc_realloc(domains, domains, struct trustdom_info *, di);
+	*_domains = talloc_move(mem_ctx, &domains);
+	*_num_domains = di;
+	TALLOC_FREE(tmp_ctx);
 	return NT_STATUS_OK;
 }
 
-- 
2.13.6


From f5ba51e84c10af3e59eae1b96e2a770a757a15ca Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 1 Dec 2017 08:41:29 +0100
Subject: [PATCH 08/23] pdb_samba_dsdb: implement PDB_CAP_TRUSTED_DOMAINS_EX
 related functions

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/passdb/pdb_samba_dsdb.c | 284 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 284 insertions(+)

diff --git a/source3/passdb/pdb_samba_dsdb.c b/source3/passdb/pdb_samba_dsdb.c
index d70a867505d..e629416974a 100644
--- a/source3/passdb/pdb_samba_dsdb.c
+++ b/source3/passdb/pdb_samba_dsdb.c
@@ -2964,6 +2964,285 @@ static NTSTATUS pdb_samba_dsdb_enum_trusteddoms(struct pdb_methods *m,
 	return NT_STATUS_OK;
 }
 
+static NTSTATUS pdb_samba_dsdb_msg_to_trusted_domain(const struct ldb_message *msg,
+						TALLOC_CTX *mem_ctx,
+						struct pdb_trusted_domain **_d)
+{
+	struct pdb_trusted_domain *d = NULL;
+	const char *str = NULL;
+	struct dom_sid *sid = NULL;
+	const struct ldb_val *val = NULL;
+	uint64_t val64;
+
+	*_d = NULL;
+
+	d = talloc_zero(mem_ctx, struct pdb_trusted_domain);
+	if (d == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	str = ldb_msg_find_attr_as_string(msg, "flatName", NULL);
+	if (str == NULL) {
+		TALLOC_FREE(d);
+		return NT_STATUS_INTERNAL_DB_CORRUPTION;
+	}
+	d->netbios_name = talloc_strdup(d, str);
+	if (d->netbios_name == NULL) {
+		TALLOC_FREE(d);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	str = ldb_msg_find_attr_as_string(msg, "trustPartner", NULL);
+	if (str != NULL) {
+		d->domain_name = talloc_strdup(d, str);
+		if (d->domain_name == NULL) {
+			TALLOC_FREE(d);
+			return NT_STATUS_NO_MEMORY;
+		}
+	}
+
+	sid = samdb_result_dom_sid(d, msg, "securityIdentifier");
+	if (sid != NULL) {
+		d->security_identifier = *sid;
+		TALLOC_FREE(sid);
+	}
+
+	val = ldb_msg_find_ldb_val(msg, "trustAuthOutgoing");
+	if (val != NULL) {
+		d->trust_auth_outgoing = data_blob_dup_talloc(d, *val);
+		if (d->trust_auth_outgoing.data == NULL) {
+			TALLOC_FREE(d);
+			return NT_STATUS_NO_MEMORY;
+		}
+	}
+	val = ldb_msg_find_ldb_val(msg, "trustAuthIncoming");
+	if (val != NULL) {
+		d->trust_auth_incoming = data_blob_dup_talloc(d, *val);
+		if (d->trust_auth_incoming.data == NULL) {
+			TALLOC_FREE(d);
+			return NT_STATUS_NO_MEMORY;
+		}
+	}
+
+	d->trust_direction = ldb_msg_find_attr_as_uint(msg, "trustDirection", 0);
+	d->trust_type = ldb_msg_find_attr_as_uint(msg, "trustType", 0);
+	d->trust_attributes = ldb_msg_find_attr_as_uint(msg, "trustAttributes", 0);
+
+	val64 = ldb_msg_find_attr_as_uint64(msg, "trustPosixOffset", UINT64_MAX);
+	if (val64 != UINT64_MAX) {
+		d->trust_posix_offset = talloc(d, uint32_t);
+		if (d->trust_posix_offset == NULL) {
+			TALLOC_FREE(d);
+			return NT_STATUS_NO_MEMORY;
+		}
+		*d->trust_posix_offset = (uint32_t)val64;
+	}
+
+	val64 = ldb_msg_find_attr_as_uint64(msg, "msDS-SupportedEncryptionTypes", UINT64_MAX);
+	if (val64 != UINT64_MAX) {
+		d->supported_enc_type = talloc(d, uint32_t);
+		if (d->supported_enc_type == NULL) {
+			TALLOC_FREE(d);
+			return NT_STATUS_NO_MEMORY;
+		}
+		*d->supported_enc_type = (uint32_t)val64;
+	}
+
+	val = ldb_msg_find_ldb_val(msg, "msDS-TrustForestTrustInfo");
+	if (val != NULL) {
+		d->trust_forest_trust_info = data_blob_dup_talloc(d, *val);
+		if (d->trust_forest_trust_info.data == NULL) {
+			TALLOC_FREE(d);
+			return NT_STATUS_NO_MEMORY;
+		}
+	}
+
+	*_d = d;
+	return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba_dsdb_get_trusted_domain(struct pdb_methods *m,
+						  TALLOC_CTX *mem_ctx,
+						  const char *domain,
+						  struct pdb_trusted_domain **td)
+{
+	struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+		m->private_data, struct pdb_samba_dsdb_state);
+	TALLOC_CTX *tmp_ctx = talloc_stackframe();
+	const char * const attrs[] = {
+		"securityIdentifier",
+		"flatName",
+		"trustPartner",
+		"trustAuthOutgoing",
+		"trustAuthIncoming",
+		"trustAttributes",
+		"trustDirection",
+		"trustType",
+		"trustPosixOffset",
+		"msDS-SupportedEncryptionTypes",
+		"msDS-TrustForestTrustInfo",
+		NULL
+	};
+	struct ldb_message *msg = NULL;
+	struct pdb_trusted_domain *d = NULL;
+	NTSTATUS status;
+
+	status = dsdb_trust_search_tdo(state->ldb, domain, NULL,
+				       attrs, tmp_ctx, &msg);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_ERR("dsdb_trust_search_tdo(%s) - %s ",
+			domain, nt_errstr(status));
+		TALLOC_FREE(tmp_ctx);
+		return status;
+	}
+
+	status = pdb_samba_dsdb_msg_to_trusted_domain(msg, mem_ctx, &d);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_ERR("pdb_samba_dsdb_msg_to_trusted_domain(%s) - %s ",
+			domain, nt_errstr(status));
+		TALLOC_FREE(tmp_ctx);
+		return status;
+	}
+
+	*td = d;
+	TALLOC_FREE(tmp_ctx);
+	return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba_dsdb_get_trusted_domain_by_sid(struct pdb_methods *m,
+							 TALLOC_CTX *mem_ctx,
+							 struct dom_sid *sid,
+							 struct pdb_trusted_domain **td)
+{
+	struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+		m->private_data, struct pdb_samba_dsdb_state);
+	TALLOC_CTX *tmp_ctx = talloc_stackframe();
+	const char * const attrs[] = {
+		"securityIdentifier",
+		"flatName",
+		"trustPartner",
+		"trustAuthOutgoing",
+		"trustAuthIncoming",
+		"trustAttributes",
+		"trustDirection",
+		"trustType",
+		"trustPosixOffset",
+		"msDS-SupportedEncryptionTypes",
+		"msDS-TrustForestTrustInfo",
+		NULL
+	};
+	struct ldb_message *msg = NULL;
+	struct pdb_trusted_domain *d = NULL;
+	NTSTATUS status;
+
+	status = dsdb_trust_search_tdo_by_sid(state->ldb, sid,
+					      attrs, tmp_ctx, &msg);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_ERR("dsdb_trust_search_tdo_by_sid(%s) - %s ",
+			dom_sid_string(tmp_ctx, sid), nt_errstr(status));
+		TALLOC_FREE(tmp_ctx);
+		return status;
+	}
+
+	status = pdb_samba_dsdb_msg_to_trusted_domain(msg, mem_ctx, &d);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_ERR("pdb_samba_dsdb_msg_to_trusted_domain(%s) - %s ",
+			dom_sid_string(tmp_ctx, sid), nt_errstr(status));
+		TALLOC_FREE(tmp_ctx);
+		return status;
+	}
+
+	*td = d;
+	TALLOC_FREE(tmp_ctx);
+	return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba_dsdb_set_trusted_domain(struct pdb_methods *methods,
+						  const char* domain,
+						  const struct pdb_trusted_domain *td)
+{
+	return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS pdb_samba_dsdb_del_trusted_domain(struct pdb_methods *methods,
+						  const char *domain)
+{
+	return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS pdb_samba_dsdb_enum_trusted_domains(struct pdb_methods *m,
+						    TALLOC_CTX *mem_ctx,
+						    uint32_t *_num_domains,
+						    struct pdb_trusted_domain ***_domains)
+{
+	struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+		m->private_data, struct pdb_samba_dsdb_state);
+	TALLOC_CTX *tmp_ctx = talloc_stackframe();
+	const char * const attrs[] = {
+		"securityIdentifier",
+		"flatName",
+		"trustPartner",
+		"trustAuthOutgoing",
+		"trustAuthIncoming",
+		"trustAttributes",
+		"trustDirection",
+		"trustType",
+		"trustPosixOffset",
+		"msDS-SupportedEncryptionTypes",
+		"msDS-TrustForestTrustInfo",
+		NULL
+	};
+	struct ldb_result *res = NULL;
+	unsigned int i;
+	struct pdb_trusted_domain **domains = NULL;
+	NTSTATUS status;
+	uint32_t di = 0;
+
+	*_num_domains = 0;
+	*_domains = NULL;
+
+	status = dsdb_trust_search_tdos(state->ldb, NULL,
+					attrs, tmp_ctx, &res);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_ERR("dsdb_trust_search_tdos() - %s ", nt_errstr(status));
+		TALLOC_FREE(tmp_ctx);
+		return status;
+	}
+
+	if (res->count == 0) {
+		TALLOC_FREE(tmp_ctx);
+		return NT_STATUS_OK;
+	}
+
+	domains = talloc_zero_array(tmp_ctx, struct pdb_trusted_domain *,
+				    res->count);
+	if (domains == NULL) {
+		TALLOC_FREE(tmp_ctx);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	for (i = 0; i < res->count; i++) {
+		struct ldb_message *msg = res->msgs[i];
+		struct pdb_trusted_domain *d = NULL;
+
+		status = pdb_samba_dsdb_msg_to_trusted_domain(msg, domains, &d);
+		if (!NT_STATUS_IS_OK(status)) {
+			DBG_ERR("pdb_samba_dsdb_msg_to_trusted_domain() - %s ",
+				nt_errstr(status));
+			TALLOC_FREE(tmp_ctx);
+			return status;
+		}
+
+		domains[di++] = d;
+	}
+
+	talloc_realloc(domains, domains, struct pdb_trusted_domain *, di);
+	*_domains = talloc_move(mem_ctx, &domains);
+	*_num_domains = di;
+	TALLOC_FREE(tmp_ctx);
+	return NT_STATUS_OK;
+}
+
 static bool pdb_samba_dsdb_is_responsible_for_wellknown(struct pdb_methods *m)
 {
 	return true;
@@ -3025,6 +3304,11 @@ static void pdb_samba_dsdb_init_methods(struct pdb_methods *m)
 	m->set_trusteddom_pw = pdb_samba_dsdb_set_trusteddom_pw;
 	m->del_trusteddom_pw = pdb_samba_dsdb_del_trusteddom_pw;
 	m->enum_trusteddoms = pdb_samba_dsdb_enum_trusteddoms;
+	m->get_trusted_domain = pdb_samba_dsdb_get_trusted_domain;
+	m->get_trusted_domain_by_sid = pdb_samba_dsdb_get_trusted_domain_by_sid;
+	m->set_trusted_domain = pdb_samba_dsdb_set_trusted_domain;
+	m->del_trusted_domain = pdb_samba_dsdb_del_trusted_domain;
+	m->enum_trusted_domains = pdb_samba_dsdb_enum_trusted_domains;
 	m->is_responsible_for_wellknown =
 				pdb_samba_dsdb_is_responsible_for_wellknown;
 	m->is_responsible_for_everything_else =
-- 
2.13.6


From 6be8aee4f3ecc4c13b404b9c3c130f7754d8ba49 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sun, 10 Dec 2017 20:03:37 +0100
Subject: [PATCH 09/23] pdb_samba_dsdb: implement
 pdb_samba_dsdb_set_trusted_domain

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/passdb/pdb_samba_dsdb.c | 390 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 389 insertions(+), 1 deletion(-)

diff --git a/source3/passdb/pdb_samba_dsdb.c b/source3/passdb/pdb_samba_dsdb.c
index e629416974a..a325c4e551f 100644
--- a/source3/passdb/pdb_samba_dsdb.c
+++ b/source3/passdb/pdb_samba_dsdb.c
@@ -40,6 +40,7 @@
 #include "source4/auth/auth_sam.h"
 #include "auth/credentials/credentials.h"
 #include "lib/util/base64.h"
+#include "libcli/ldap/ldap_ndr.h"
 
 struct pdb_samba_dsdb_state {
 	struct tevent_context *ev;
@@ -3157,11 +3158,398 @@ static NTSTATUS pdb_samba_dsdb_get_trusted_domain_by_sid(struct pdb_methods *m,
 	return NT_STATUS_OK;
 }
 
+static NTSTATUS add_trust_user(TALLOC_CTX *mem_ctx,
+			       struct ldb_context *sam_ldb,
+			       struct ldb_dn *base_dn,
+			       const char *netbios_name,
+			       struct trustAuthInOutBlob *taiob)
+{
+	struct ldb_request *req = NULL;
+	struct ldb_message *msg = NULL;
+	struct ldb_dn *dn = NULL;
+	uint32_t i;
+	int ret;
+	bool ok;
+
+	dn = ldb_dn_copy(mem_ctx, base_dn);
+	if (dn == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	ok = ldb_dn_add_child_fmt(dn, "cn=%s$,cn=users", netbios_name);
+	if (!ok) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	msg = ldb_msg_new(mem_ctx);
+	if (msg == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	msg->dn = dn;
+
+	ret = ldb_msg_add_string(msg, "objectClass", "user");
+	if (ret != LDB_SUCCESS) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	ret = ldb_msg_add_fmt(msg, "samAccountName", "%s$", netbios_name);
+	if (ret != LDB_SUCCESS) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	ret = samdb_msg_add_uint(sam_ldb, msg, msg, "userAccountControl",
+				 UF_INTERDOMAIN_TRUST_ACCOUNT);
+	if (ret != LDB_SUCCESS) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	for (i = 0; i < taiob->count; i++) {
+		struct AuthenticationInformation *auth_info =
+			&taiob->current.array[i];
+		const char *attribute = NULL;
+		struct ldb_val v;
+
+		switch (taiob->current.array[i].AuthType) {
+		case TRUST_AUTH_TYPE_NT4OWF:
+			attribute = "unicodePwd";
+			v.data = (uint8_t *)&auth_info->AuthInfo.nt4owf.password;
+			v.length = 16;
+			break;
+
+		case TRUST_AUTH_TYPE_CLEAR:
+			attribute = "clearTextPassword";
+			v.data = auth_info->AuthInfo.clear.password;
+			v.length = auth_info->AuthInfo.clear.size;
+			break;
+
+		default:
+			continue;
+		}
+
+		ret = ldb_msg_add_value(msg, attribute, &v, NULL);
+		if (ret != LDB_SUCCESS) {
+			return NT_STATUS_NO_MEMORY;
+		}
+	}
+
+	/* create the trusted_domain user account */
+	ret = ldb_build_add_req(&req, sam_ldb, mem_ctx, msg, NULL, NULL,
+				ldb_op_default_callback, NULL);
+	if (ret != LDB_SUCCESS) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	ret = ldb_request_add_control(
+		req, DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID,
+		false, NULL);
+	if (ret != LDB_SUCCESS) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	ret = dsdb_autotransaction_request(sam_ldb, req);
+	if (ret != LDB_SUCCESS) {
+		DEBUG(0,("Failed to create user record %s: %s\n",
+			 ldb_dn_get_linearized(msg->dn),
+			 ldb_errstring(sam_ldb)));
+
+		switch (ret) {
+		case LDB_ERR_ENTRY_ALREADY_EXISTS:
+			return NT_STATUS_DOMAIN_EXISTS;
+		case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
+			return NT_STATUS_ACCESS_DENIED;
+		default:
+			return NT_STATUS_INTERNAL_DB_CORRUPTION;
+		}
+	}
+
+	return NT_STATUS_OK;
+}
+
 static NTSTATUS pdb_samba_dsdb_set_trusted_domain(struct pdb_methods *methods,
 						  const char* domain,
 						  const struct pdb_trusted_domain *td)
 {
-	return NT_STATUS_NOT_IMPLEMENTED;
+	struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+		methods->private_data, struct pdb_samba_dsdb_state);
+	TALLOC_CTX *tmp_ctx = talloc_stackframe();
+	bool in_txn = false;
+	struct ldb_dn *base_dn = NULL;
+	struct ldb_message *msg = NULL;
+	const char *attrs[] = {
+		NULL
+	};
+	char *netbios_encoded = NULL;
+	char *dns_encoded = NULL;
+	struct dom_sid *tmp_sid1;
+	struct dom_sid *tmp_sid2;
+	uint32_t tmp_rid;
+	char *sid_encoded = NULL;
+	int ret;
+	struct trustAuthInOutBlob taiob;
+	enum ndr_err_code ndr_err;
+	NTSTATUS status;
+	bool ok;
+
+	base_dn = ldb_dn_copy(tmp_ctx, ldb_get_default_basedn(state->ldb));
+	if (base_dn == NULL) {
+		TALLOC_FREE(tmp_ctx);
+		status = NT_STATUS_NO_MEMORY;
+		goto out;
+	}
+	/*
+	 * We expect S-1-5-21-A-B-C, but we don't
+	 * allow S-1-5-21-0-0-0 as this is used
+	 * for claims and compound identities.
+	 *
+	 * So we call dom_sid_split_rid() 3 times
+	 * and compare the result to S-1-5-21
+	 */
+	status = dom_sid_split_rid(tmp_ctx,
+				   &td->security_identifier,
+				   &tmp_sid1, &tmp_rid);
+	if (!NT_STATUS_IS_OK(status)) {
+		goto out;
+	}
+	status = dom_sid_split_rid(tmp_ctx, tmp_sid1, &tmp_sid2, &tmp_rid);
+	if (!NT_STATUS_IS_OK(status)) {
+		goto out;
+	}
+	status = dom_sid_split_rid(tmp_ctx, tmp_sid2, &tmp_sid1, &tmp_rid);
+	if (!NT_STATUS_IS_OK(status)) {
+		goto out;
+	}
+	ok = dom_sid_parse("S-1-5-21", tmp_sid2);
+	if (!ok) {
+		status = NT_STATUS_INTERNAL_ERROR;
+		goto out;
+	}
+	ok = dom_sid_equal(tmp_sid1, tmp_sid2);
+	if (!ok) {
+		status = NT_STATUS_INVALID_PARAMETER;
+		goto out;
+	}
+	ok = dom_sid_parse("S-1-5-21-0-0-0", tmp_sid2);
+	if (!ok) {
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+	ok = !dom_sid_equal(&td->security_identifier, tmp_sid2);
+	if (!ok) {
+		status = NT_STATUS_INVALID_PARAMETER;
+		goto out;
+	}
+
+	if (strequal(td->netbios_name, "BUILTIN")) {
+		status = NT_STATUS_INVALID_PARAMETER;
+		goto out;
+	}
+	if (strequal(td->domain_name, "BUILTIN")) {
+		status = NT_STATUS_INVALID_PARAMETER;
+		goto out;
+	}
+
+	dns_encoded = ldb_binary_encode_string(tmp_ctx, td->domain_name);
+	if (dns_encoded == NULL) {
+		status = NT_STATUS_NO_MEMORY;
+		goto out;
+	}
+	netbios_encoded = ldb_binary_encode_string(tmp_ctx, td->netbios_name);
+	if (netbios_encoded == NULL) {
+		status =NT_STATUS_NO_MEMORY;
+		goto out;
+	}
+	sid_encoded = ldap_encode_ndr_dom_sid(tmp_ctx, &td->security_identifier);
+	if (sid_encoded == NULL) {
+		status = NT_STATUS_NO_MEMORY;
+		goto out;
+	}
+
+	ok = samdb_is_pdc(state->ldb);
+	if (!ok) {
+		DBG_ERR("Adding TDO is only allowed on a PDC.\n");
+		TALLOC_FREE(tmp_ctx);
+		status = NT_STATUS_INVALID_DOMAIN_ROLE;
+		goto out;
+	}
+
+	status = dsdb_trust_search_tdo(state->ldb,
+				       td->netbios_name,
+				       td->domain_name,
+				       attrs,
+				       tmp_ctx,
+				       &msg);
+	if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+		DBG_ERR("dsdb_trust_search_tdo returned %s\n",
+			nt_errstr(status));
+		status = NT_STATUS_INVALID_DOMAIN_STATE;
+		goto out;
+	}
+
+	ret = ldb_transaction_start(state->ldb);
+	if (ret != LDB_SUCCESS) {
+		status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+		goto out;
+	}
+	in_txn = true;
+
+	msg = ldb_msg_new(tmp_ctx);
+	if (msg == NULL) {
+		status = NT_STATUS_NO_MEMORY;
+		goto out;
+	}
+
+	msg->dn = ldb_dn_copy(tmp_ctx, base_dn);
+
+	ok = ldb_dn_add_child_fmt(msg->dn, "cn=%s,cn=System", td->domain_name);
+	if (!ok) {
+		status = NT_STATUS_NO_MEMORY;
+		goto out;
+	}
+
+	ret = ldb_msg_add_string(msg, "objectClass", "trustedDomain");
+	if (ret != LDB_SUCCESS) {
+		status = NT_STATUS_NO_MEMORY;
+		goto out;
+	}
+
+	ret = ldb_msg_add_string(msg, "flatname", td->netbios_name);
+	if (ret != LDB_SUCCESS) {
+		status = NT_STATUS_NO_MEMORY;
+		goto out;
+	}
+
+	ret = ldb_msg_add_string(msg, "trustPartner", td->domain_name);
+	if (ret != LDB_SUCCESS) {
+		status = NT_STATUS_NO_MEMORY;
+		goto out;
+	}
+
+	ret = samdb_msg_add_dom_sid(state->ldb,
+				    tmp_ctx,
+				    msg,
+				    "securityIdentifier",
+				    &td->security_identifier);
+	if (ret != LDB_SUCCESS) {
+		status = NT_STATUS_NO_MEMORY;
+		goto out;
+	}
+
+	ret = samdb_msg_add_int(state->ldb,
+				tmp_ctx,
+				msg,
+				"trustType",
+				td->trust_type);
+	if (ret != LDB_SUCCESS) {
+		status = NT_STATUS_NO_MEMORY;
+		goto out;
+	}
+
+	ret = samdb_msg_add_int(state->ldb,
+				tmp_ctx,
+				msg,
+				"trustAttributes",
+				td->trust_attributes);
+	if (ret != LDB_SUCCESS) {
+		status =NT_STATUS_NO_MEMORY;
+		goto out;
+	}
+
+	ret = samdb_msg_add_int(state->ldb,
+				tmp_ctx,
+				msg,
+				"trustDirection",
+				td->trust_direction);
+	if (ret != LDB_SUCCESS) {
+		status = NT_STATUS_NO_MEMORY;
+		goto out;
+	}
+
+	if (td->trust_auth_incoming.data != NULL) {
+		ret = ldb_msg_add_value(msg,
+					"trustAuthIncoming",
+					&td->trust_auth_incoming,
+					NULL);
+		if (ret != LDB_SUCCESS) {
+			status = NT_STATUS_NO_MEMORY;
+			goto out;
+		}
+	}
+	if (td->trust_auth_outgoing.data != NULL) {
+		ret = ldb_msg_add_value(msg,
+					"trustAuthOutgoing",
+					&td->trust_auth_outgoing,
+					NULL);
+		if (ret != LDB_SUCCESS) {
+			status = NT_STATUS_NO_MEMORY;
+			goto out;
+		}
+	}
+
+	/* create the trusted_domain */
+	ret = ldb_add(state->ldb, msg);
+	switch (ret) {
+	case  LDB_SUCCESS:
+		break;
+
+	case  LDB_ERR_ENTRY_ALREADY_EXISTS:
+		DBG_ERR("Failed to create trusted domain record %s: %s\n",
+			ldb_dn_get_linearized(msg->dn),
+			ldb_errstring(state->ldb));
+		status = NT_STATUS_DOMAIN_EXISTS;
+		goto out;
+
+	case  LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
+		DBG_ERR("Failed to create trusted domain record %s: %s\n",
+			ldb_dn_get_linearized(msg->dn),
+			ldb_errstring(state->ldb));
+		status = NT_STATUS_ACCESS_DENIED;
+		goto out;
+
+	default:
+		DBG_ERR("Failed to create trusted domain record %s: %s\n",
+			ldb_dn_get_linearized(msg->dn),
+			ldb_errstring(state->ldb));
+		status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+		goto out;
+	}
+
+	ndr_err = ndr_pull_struct_blob(
+		&td->trust_auth_outgoing,
+		tmp_ctx,
+		&taiob,
+		(ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
+	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+		status = ndr_map_error2ntstatus(ndr_err);
+		goto out;
+	}
+
+	if (td->trust_direction == LSA_TRUST_DIRECTION_INBOUND) {
+		status = add_trust_user(tmp_ctx,
+					state->ldb,
+					base_dn,
+					td->netbios_name,
+					&taiob);
+		if (!NT_STATUS_IS_OK(status)) {
+			goto out;
+		}
+	}
+
+	ret = ldb_transaction_commit(state->ldb);
+	if (ret != LDB_SUCCESS) {
+		return NT_STATUS_INTERNAL_DB_CORRUPTION;
+	}
+	in_txn = false;
+
+	/*
+	 * TODO: Notify winbindd that we have a new trust
+	 */
+
+	status = NT_STATUS_OK;
+
+out:
+	if (in_txn) {
+		ldb_transaction_cancel(state->ldb);
+	}
+	TALLOC_FREE(tmp_ctx);
+	return status;
 }
 
 static NTSTATUS pdb_samba_dsdb_del_trusted_domain(struct pdb_methods *methods,
-- 
2.13.6


From 905ddd8067ae612d2cd5ab7115da33527466b262 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 11 Dec 2017 07:57:27 +0100
Subject: [PATCH 10/23] pdb_samba_dsdb: implement
 pdb_samba_dsdb_del_trusted_domain

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/passdb/pdb_samba_dsdb.c | 119 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 118 insertions(+), 1 deletion(-)

diff --git a/source3/passdb/pdb_samba_dsdb.c b/source3/passdb/pdb_samba_dsdb.c
index a325c4e551f..97fba0e7f89 100644
--- a/source3/passdb/pdb_samba_dsdb.c
+++ b/source3/passdb/pdb_samba_dsdb.c
@@ -41,6 +41,7 @@
 #include "auth/credentials/credentials.h"
 #include "lib/util/base64.h"
 #include "libcli/ldap/ldap_ndr.h"
+#include "lib/util/util_ldb.h"
 
 struct pdb_samba_dsdb_state {
 	struct tevent_context *ev;
@@ -3552,10 +3553,126 @@ static NTSTATUS pdb_samba_dsdb_set_trusted_domain(struct pdb_methods *methods,
 	return status;
 }
 
+static NTSTATUS delete_trust_user(TALLOC_CTX *mem_ctx,
+				  struct pdb_samba_dsdb_state *state,
+				  const char *trust_user)
+{
+	const char *attrs[] = { "userAccountControl", NULL };
+	struct ldb_message **msgs;
+	uint32_t uac;
+	int ret;
+
+	ret = gendb_search(state->ldb,
+			   mem_ctx,
+			   ldb_get_default_basedn(state->ldb),
+			   &msgs,
+			   attrs,
+			   "samAccountName=%s$",
+			   trust_user);
+	if (ret > 1) {
+		return NT_STATUS_INTERNAL_DB_CORRUPTION;
+	}
+
+	if (ret == 0) {
+		return NT_STATUS_OK;
+	}
+
+	uac = ldb_msg_find_attr_as_uint(msgs[0],
+					"userAccountControl",
+					0);
+	if (!(uac & UF_INTERDOMAIN_TRUST_ACCOUNT)) {
+		return NT_STATUS_OBJECT_NAME_COLLISION;
+	}
+
+	ret = ldb_delete(state->ldb, msgs[0]->dn);
+	switch (ret) {
+	case LDB_SUCCESS:
+		break;
+	case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
+		return NT_STATUS_ACCESS_DENIED;
+	default:
+		return NT_STATUS_INTERNAL_DB_CORRUPTION;
+	}
+
+	return NT_STATUS_OK;
+}
+
 static NTSTATUS pdb_samba_dsdb_del_trusted_domain(struct pdb_methods *methods,
 						  const char *domain)
 {
-	return NT_STATUS_NOT_IMPLEMENTED;
+	struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+		methods->private_data, struct pdb_samba_dsdb_state);
+	TALLOC_CTX *tmp_ctx = talloc_stackframe();
+	struct pdb_trusted_domain *td = NULL;
+	struct ldb_dn *tdo_dn = NULL;
+	bool in_txn = false;
+	NTSTATUS status;
+	int ret;
+	bool ok;
+
+	status = pdb_samba_dsdb_get_trusted_domain(methods,
+						   tmp_ctx,
+						   domain,
+						   &td);
+	if (!NT_STATUS_IS_OK(status)) {
+		if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+			DBG_ERR("Searching TDO for %s returned %s\n",
+				domain, nt_errstr(status));
+			return status;
+		}
+		DBG_NOTICE("No TDO object for %s\n", domain);
+		return NT_STATUS_OK;
+	}
+
+	tdo_dn = ldb_dn_copy(tmp_ctx, ldb_get_default_basedn(state->ldb));
+	if (tdo_dn == NULL) {
+		status = NT_STATUS_NO_MEMORY;
+		goto out;
+	}
+
+	ok = ldb_dn_add_child_fmt(tdo_dn, "cn=%s,cn=System", domain);
+	if (!ok) {
+		TALLOC_FREE(tmp_ctx);
+		status = NT_STATUS_NO_MEMORY;
+		goto out;
+	}
+
+	ret = ldb_transaction_start(state->ldb);
+	if (ret != LDB_SUCCESS) {
+		status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+		goto out;
+	}
+	in_txn = true;
+
+	ret = ldb_delete(state->ldb, tdo_dn);
+	if (ret != LDB_SUCCESS) {
+		status = NT_STATUS_INVALID_HANDLE;
+		goto out;
+	}
+
+	if (td->trust_direction == LSA_TRUST_DIRECTION_INBOUND) {
+		status = delete_trust_user(tmp_ctx, state, domain);
+		if (!NT_STATUS_IS_OK(status)) {
+			goto out;
+		}
+	}
+
+	ret = ldb_transaction_commit(state->ldb);
+	if (ret != LDB_SUCCESS) {
+		status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+		goto out;
+	}
+	in_txn = false;
+
+	status = NT_STATUS_OK;
+
+out:
+	if (in_txn) {
+		ldb_transaction_cancel(state->ldb);
+	}
+	TALLOC_FREE(tmp_ctx);
+
+	return status;
 }
 
 static NTSTATUS pdb_samba_dsdb_enum_trusted_domains(struct pdb_methods *m,
-- 
2.13.6


From 9e10df93201360fbbe632a857841881e4f307b07 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Tue, 19 Dec 2017 23:44:00 +0100
Subject: [PATCH 11/23] pdb_samba_dsdb: set PDB_CAP_TRUSTED_DOMAINS_EX

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/passdb/pdb_samba_dsdb.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source3/passdb/pdb_samba_dsdb.c b/source3/passdb/pdb_samba_dsdb.c
index 97fba0e7f89..16a7a85bdfd 100644
--- a/source3/passdb/pdb_samba_dsdb.c
+++ b/source3/passdb/pdb_samba_dsdb.c
@@ -2134,7 +2134,7 @@ static bool pdb_samba_dsdb_sid_to_id(struct pdb_methods *m, const struct dom_sid
 
 static uint32_t pdb_samba_dsdb_capabilities(struct pdb_methods *m)
 {
-	return PDB_CAP_STORE_RIDS | PDB_CAP_ADS;
+	return PDB_CAP_STORE_RIDS | PDB_CAP_ADS | PDB_CAP_TRUSTED_DOMAINS_EX;
 }
 
 static bool pdb_samba_dsdb_new_rid(struct pdb_methods *m, uint32_t *rid)
-- 
2.13.6


From e298a70dd297b6673552c72cbfb9cc36a324f8fe Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 29 Nov 2017 15:55:12 +0100
Subject: [PATCH 12/23] winbindd: load the trusted domains on a DC already in
 init_domain_list()

We should do that in the parent as early as possible.
Similar to our primary domain, which is also a direct trust.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 source3/winbindd/winbindd_util.c | 175 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 175 insertions(+)

diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c
index 9c8e39f79c1..2f145cdd48a 100644
--- a/source3/winbindd/winbindd_util.c
+++ b/source3/winbindd/winbindd_util.c
@@ -30,6 +30,7 @@
 #include "passdb.h"
 #include "source4/lib/messaging/messaging.h"
 #include "librpc/gen_ndr/ndr_lsa.h"
+#include "librpc/gen_ndr/ndr_drsblobs.h"
 #include "auth/credentials/credentials.h"
 #include "libsmb/samlogon_cache.h"
 
@@ -1035,6 +1036,180 @@ bool init_domain_list(void)
 
 	}
 
+	if (IS_DC && (pdb_capabilities() & PDB_CAP_TRUSTED_DOMAINS_EX)) {
+		uint32_t num_domains = 0;
+		struct pdb_trusted_domain **domains = NULL;
+		uint32_t i;
+
+		status = pdb_enum_trusted_domains(talloc_tos(), &num_domains, &domains);
+		if (!NT_STATUS_IS_OK(status)) {
+			DBG_ERR("pdb_enum_trusted_domains() failed - %s\n",
+				nt_errstr(status));
+			return false;
+		}
+
+		for (i = 0; i < num_domains; i++) {
+			enum netr_SchannelType sec_chan_type = SEC_CHAN_DOMAIN;
+			uint32_t trust_flags = 0;
+
+			if (domains[i]->trust_type == LSA_TRUST_TYPE_UPLEVEL) {
+				sec_chan_type = SEC_CHAN_DNS_DOMAIN;
+			}
+
+			if (!(domains[i]->trust_direction & LSA_TRUST_DIRECTION_OUTBOUND)) {
+				sec_chan_type = SEC_CHAN_NULL;
+			}
+
+			if (domains[i]->trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
+				trust_flags |= NETR_TRUST_FLAG_INBOUND;
+			}
+			if (domains[i]->trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
+				trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
+			}
+			if (domains[i]->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
+				trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
+			}
+
+			status = add_trusted_domain(domains[i]->netbios_name,
+						    domains[i]->domain_name,
+						    &domains[i]->security_identifier,
+						    domains[i]->trust_type,
+						    trust_flags,
+						    domains[i]->trust_attributes,
+						    sec_chan_type,
+						    &domain);
+			if (!NT_STATUS_IS_OK(status)) {
+				DBG_NOTICE("add_trusted_domain returned %s\n",
+					   nt_errstr(status));
+				return false;
+			}
+
+			if (domains[i]->trust_type == LSA_TRUST_TYPE_UPLEVEL) {
+				domain->active_directory = true;
+			}
+			domain->domain_type = domains[i]->trust_type;
+			domain->domain_trust_attribs = domains[i]->trust_attributes;
+
+			if (sec_chan_type != SEC_CHAN_NULL) {
+				/* Even in the parent winbindd we'll need to
+				   talk to the DC, so try and see if we can
+				   contact it. Theoretically this isn't neccessary
+				   as the init_dc_connection() in init_child_recv()
+				   will do this, but we can start detecting the DC
+				   early here. */
+				set_domain_online_request(domain);
+			}
+		}
+
+		for (i = 0; i < num_domains; i++) {
+			struct ForestTrustInfo fti;
+			uint32_t fi;
+			enum ndr_err_code ndr_err;
+
+			if (domains[i]->trust_type != LSA_TRUST_TYPE_UPLEVEL) {
+				continue;
+			}
+
+			if (!(domains[i]->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
+				continue;
+			}
+
+			if (domains[i]->trust_forest_trust_info.length == 0) {
+				continue;
+			}
+
+			ndr_err = ndr_pull_struct_blob_all(
+					&domains[i]->trust_forest_trust_info,
+					talloc_tos(), &fti,
+					(ndr_pull_flags_fn_t)ndr_pull_ForestTrustInfo);
+			if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+				DBG_ERR("ndr_pull_ForestTrustInfo(%s) - %s\n",
+					domains[i]->netbios_name,
+					ndr_map_error2string(ndr_err));
+				return false;
+			}
+
+			for (fi = 0; fi < fti.count; fi++) {
+				struct ForestTrustInfoRecord *rec =
+					&fti.records[fi].record;
+				struct ForestTrustDataDomainInfo *drec = NULL;
+
+				if (rec->type != FOREST_TRUST_DOMAIN_INFO) {
+					continue;
+				}
+				drec = &rec->data.info;
+
+				if (rec->flags & LSA_NB_DISABLED_MASK) {
+					continue;
+				}
+
+				if (rec->flags & LSA_SID_DISABLED_MASK) {
+					continue;
+				}
+
+				/*
+				 * TODO:
+				 * also try to find a matching
+				 * LSA_TLN_DISABLED_MASK ???
+				 */
+
+				domain = find_domain_from_name_noinit(drec->netbios_name.string);
+				if (domain != NULL) {
+					continue;
+				}
+
+				status = add_trusted_domain(drec->netbios_name.string,
+							    drec->dns_name.string,
+							    &drec->sid,
+							    LSA_TRUST_TYPE_UPLEVEL,
+							    NETR_TRUST_FLAG_OUTBOUND,
+							    0,
+							    SEC_CHAN_NULL,
+							    &domain);
+				if (!NT_STATUS_IS_OK(status)) {
+					DBG_NOTICE("add_trusted_domain returned %s\n",
+						   nt_errstr(status));
+					return false;
+				}
+			}
+		}
+	} else if (IS_DC) {
+		uint32_t num_domains = 0;
+		struct trustdom_info **domains = NULL;
+		uint32_t i;
+
+		status = pdb_enum_trusteddoms(talloc_tos(), &num_domains, &domains);
+		if (!NT_STATUS_IS_OK(status)) {
+			DBG_ERR("pdb_enum_trusteddoms() failed - %s\n",
+				nt_errstr(status));
+			return false;
+		}
+
+		for (i = 0; i < num_domains; i++) {
+			status = add_trusted_domain(domains[i]->name,
+						    NULL,
+						    &domains[i]->sid,
+						    LSA_TRUST_TYPE_DOWNLEVEL,
+						    NETR_TRUST_FLAG_OUTBOUND,
+						    0,
+						    SEC_CHAN_DOMAIN,
+						    &domain);
+			if (!NT_STATUS_IS_OK(status)) {
+				DBG_NOTICE("add_trusted_domain returned %s\n",
+					   nt_errstr(status));
+				return false;
+			}
+
+			/* Even in the parent winbindd we'll need to
+			   talk to the DC, so try and see if we can
+			   contact it. Theoretically this isn't neccessary
+			   as the init_dc_connection() in init_child_recv()
+			   will do this, but we can start detecting the DC
+			   early here. */
+			set_domain_online_request(domain);
+		}
+	}
+
 	status = imessaging_register(winbind_imessaging_context(), NULL,
 				     MSG_WINBIND_NEW_TRUSTED_DOMAIN,
 				     wb_imsg_new_trusted_domain);
-- 
2.13.6


From cab6a9a446cd215a4d8dbbfe675f125ebed71fc7 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 13 Dec 2017 17:08:10 +0100
Subject: [PATCH 13/23] winbindd: add find_default_route_domain()

On a member server this is just our primary domain. The logic for DCs is
not yet implemented, on a DC of a child-domain in a forrest this would
be the parent domain.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/winbindd/winbindd_proto.h | 1 +
 source3/winbindd/winbindd_util.c  | 9 +++++++++
 2 files changed, 10 insertions(+)

diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h
index dd6767a02ab..5ab1e8fd590 100644
--- a/source3/winbindd/winbindd_proto.h
+++ b/source3/winbindd/winbindd_proto.h
@@ -451,6 +451,7 @@ struct winbindd_domain *find_domain_from_sid_noinit(const struct dom_sid *sid);
 struct winbindd_domain *find_trust_from_sid_noinit(const struct dom_sid *sid);
 struct winbindd_domain *find_domain_from_sid(const struct dom_sid *sid);
 struct winbindd_domain *find_our_domain(void);
+struct winbindd_domain *find_default_route_domain(void);
 struct winbindd_domain *find_lookup_domain_from_sid(const struct dom_sid *sid);
 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name);
 bool parse_domain_user(const char *domuser, fstring domain, fstring user);
diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c
index 2f145cdd48a..dd3206c01f4 100644
--- a/source3/winbindd/winbindd_util.c
+++ b/source3/winbindd/winbindd_util.c
@@ -1366,6 +1366,15 @@ struct winbindd_domain *find_our_domain(void)
 	return NULL;
 }
 
+struct winbindd_domain *find_default_route_domain(void)
+{
+	if (!IS_DC) {
+		return find_our_domain();
+	}
+	DBG_ERR("Routing logic not yet implemented on a DC");
+	return NULL;
+}
+
 /* Find the appropriate domain to lookup a name or SID */
 
 struct winbindd_domain *find_lookup_domain_from_sid(const struct dom_sid *sid)
-- 
2.13.6


From c347902a1d052ad1ea63f4533071ad362369c770 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 13 Dec 2017 17:11:25 +0100
Subject: [PATCH 14/23] winbindd: add set_routing_domain()

---
 source3/winbindd/winbindd.h       |  1 +
 source3/winbindd/winbindd_proto.h |  2 ++
 source3/winbindd/winbindd_util.c  | 34 ++++++++++++++++++++++++++++++++++
 3 files changed, 37 insertions(+)

diff --git a/source3/winbindd/winbindd.h b/source3/winbindd/winbindd.h
index 682040fd1a7..b60094bafcd 100644
--- a/source3/winbindd/winbindd.h
+++ b/source3/winbindd/winbindd.h
@@ -143,6 +143,7 @@ struct winbindd_domain {
 	uint32_t domain_flags;                   /* Domain flags from netlogon.h */
 	uint32_t domain_type;                    /* Domain type from netlogon.h */
 	uint32_t domain_trust_attribs;           /* Trust attribs from netlogon.h */
+	const struct winbindd_domain *routing_domain;
 	bool initialized;		       /* Did we already ask for the domain mode? */
 	bool native_mode;                      /* is this a win2k domain in native mode ? */
 	bool active_directory;                 /* is this a win2k active directory ? */
diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h
index 5ab1e8fd590..4ab52a42ba5 100644
--- a/source3/winbindd/winbindd_proto.h
+++ b/source3/winbindd/winbindd_proto.h
@@ -438,6 +438,8 @@ NTSTATUS winbind_dual_SamLogon(struct winbindd_domain *domain,
 
 struct winbindd_domain *domain_list(void);
 struct winbindd_domain *wb_next_domain(struct winbindd_domain *domain);
+bool set_routing_domain(struct winbindd_domain *domain,
+			const struct winbindd_domain *routing_domain);
 bool domain_is_forest_root(const struct winbindd_domain *domain);
 void rescan_trusted_domains(struct tevent_context *ev, struct tevent_timer *te,
 			    struct timeval now, void *private_data);
diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c
index dd3206c01f4..fb1793d250a 100644
--- a/source3/winbindd/winbindd_util.c
+++ b/source3/winbindd/winbindd_util.c
@@ -290,6 +290,19 @@ static NTSTATUS add_trusted_domain(const char *domain_name,
 	return NT_STATUS_OK;
 }
 
+bool set_routing_domain(struct winbindd_domain *domain,
+			const struct winbindd_domain *routing_domain)
+{
+	if (domain->routing_domain == NULL) {
+		domain->routing_domain = routing_domain;
+		return true;
+	}
+	if (domain->routing_domain != routing_domain) {
+		return false;
+	}
+	return true;
+}
+
 bool domain_is_forest_root(const struct winbindd_domain *domain)
 {
 	const uint32_t fr_flags =
@@ -1105,6 +1118,8 @@ bool init_domain_list(void)
 			struct ForestTrustInfo fti;
 			uint32_t fi;
 			enum ndr_err_code ndr_err;
+			struct winbindd_domain *routing_domain = NULL;
+			bool ok;
 
 			if (domains[i]->trust_type != LSA_TRUST_TYPE_UPLEVEL) {
 				continue;
@@ -1118,6 +1133,14 @@ bool init_domain_list(void)
 				continue;
 			}
 
+			routing_domain = find_domain_from_name_noinit(
+				domains[i]->netbios_name);
+			if (routing_domain == NULL) {
+				DBG_ERR("Can't find winbindd domain [%s]\n",
+					domains[i]->netbios_name);
+				return false;
+			}
+
 			ndr_err = ndr_pull_struct_blob_all(
 					&domains[i]->trust_forest_trust_info,
 					talloc_tos(), &fti,
@@ -1171,6 +1194,17 @@ bool init_domain_list(void)
 						   nt_errstr(status));
 					return false;
 				}
+				if (domain == NULL) {
+					continue;
+				}
+				ok = set_routing_domain(domain, routing_domain);
+				if (!ok) {
+					DBG_ERR("set_routing_domain on [%s] to "
+						"[%s] failed\n",
+						domain->name,
+						routing_domain->name);
+					return false;
+				}
 			}
 		}
 	} else if (IS_DC) {
-- 
2.13.6


From 1cdbd1ae9692879f3ec875e106d00e1f9bce163c Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 29 Nov 2017 10:10:38 +0100
Subject: [PATCH 15/23] winbindd: add add_trusted_domain_from_auth

Function to add a new trusted domain to the domain list and TDC after an
successfull authentication. On Member servers only, not on DCs though.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/winbindd/winbindd_proto.h |  3 +++
 source3/winbindd/winbindd_util.c  | 55 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 58 insertions(+)

diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h
index 4ab52a42ba5..39cdef54531 100644
--- a/source3/winbindd/winbindd_proto.h
+++ b/source3/winbindd/winbindd_proto.h
@@ -440,6 +440,9 @@ struct winbindd_domain *domain_list(void);
 struct winbindd_domain *wb_next_domain(struct winbindd_domain *domain);
 bool set_routing_domain(struct winbindd_domain *domain,
 			const struct winbindd_domain *routing_domain);
+bool add_trusted_domain_from_auth(uint16_t validation_level,
+				  struct info3_text *info3,
+				  struct info6_text *info6);
 bool domain_is_forest_root(const struct winbindd_domain *domain);
 void rescan_trusted_domains(struct tevent_context *ev, struct tevent_timer *te,
 			    struct timeval now, void *private_data);
diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c
index fb1793d250a..2a975220ad0 100644
--- a/source3/winbindd/winbindd_util.c
+++ b/source3/winbindd/winbindd_util.c
@@ -303,6 +303,61 @@ bool set_routing_domain(struct winbindd_domain *domain,
 	return true;
 }
 
+bool add_trusted_domain_from_auth(uint16_t validation_level,
+				  struct info3_text *info3,
+				  struct info6_text *info6)
+{
+	struct winbindd_domain *domain = NULL;
+	struct dom_sid domain_sid;
+	const char *dns_domainname = NULL;
+	NTSTATUS status;
+	bool ok;
+
+	/*
+	 * We got a successfull auth from a domain that might not yet be in our
+	 * domain list. If we're a member we trust our DC who authenticated the
+	 * user from that domain and add the domain to our list on-the-fly. If
+	 * we're a DC we rely on configured trusts and don't add on-the-fly.
+	 */
+
+	if (IS_DC) {
+		return true;
+	}
+
+	ok = dom_sid_parse(info3->dom_sid, &domain_sid);
+	if (!ok) {
+		DBG_NOTICE("dom_sid_parse [%s] failed\n", info3->dom_sid);
+		return false;
+	}
+
+	if (validation_level == 6) {
+		dns_domainname = &info6->dns_domainname[0];
+	}
+
+	status = add_trusted_domain(info3->logon_dom,
+				    dns_domainname,
+				    &domain_sid,
+				    0,
+				    NETR_TRUST_FLAG_OUTBOUND,
+				    0,
+				    SEC_CHAN_NULL,
+				    &domain);
+	if (!NT_STATUS_IS_OK(status) &&
+	    !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
+	{
+		DBG_DEBUG("Adding domain [%s] with sid [%s] failed\n",
+			  info3->logon_dom, info3->dom_sid);
+		return false;
+	}
+
+	ok = set_routing_domain(domain, find_default_route_domain());
+	if (!ok) {
+		return false;
+	}
+
+	return true;
+}
+
 bool domain_is_forest_root(const struct winbindd_domain *domain)
 {
 	const uint32_t fr_flags =
-- 
2.13.6


From 3b91a39c3aa3e30ed2b6e7031e606633183a1377 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 29 Nov 2017 10:55:25 +0100
Subject: [PATCH 16/23] winbindd: use add_trusted_domain_from_auth

After a successfully authentication, ensure we have the users domain in our
domain list and the TDC.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/winbindd/winbindd_pam_auth.c      | 15 +++++++++++++++
 source3/winbindd/winbindd_pam_auth_crap.c | 24 +++++++++++++++++++++---
 2 files changed, 36 insertions(+), 3 deletions(-)

diff --git a/source3/winbindd/winbindd_pam_auth.c b/source3/winbindd/winbindd_pam_auth.c
index 7ff44888975..b35a17cf319 100644
--- a/source3/winbindd/winbindd_pam_auth.c
+++ b/source3/winbindd/winbindd_pam_auth.c
@@ -19,6 +19,7 @@
 
 #include "includes.h"
 #include "winbindd.h"
+#include "libcli/security/dom_sid.h"
 
 struct winbindd_pam_auth_state {
 	struct winbindd_request *request;
@@ -127,6 +128,20 @@ NTSTATUS winbindd_pam_auth_recv(struct tevent_req *req,
 		return status;
 	}
 
+	if (state->request->flags & WBFLAG_PAM_INFO3_TEXT) {
+		bool ok;
+
+		ok = add_trusted_domain_from_auth(
+			state->response->data.auth.validation_level,
+			&state->response->data.auth.info3,
+			&state->response->data.auth.info6);
+		if (!ok) {
+			DBG_ERR("add_trusted_domain_from_auth failed\n");
+			set_auth_errors(response, NT_STATUS_LOGON_FAILURE);
+			return NT_STATUS_LOGON_FAILURE;
+		}
+	}
+
 	if (state->request->flags & WBFLAG_PAM_CACHED_LOGIN) {
 
 		/* Store in-memory creds for single-signon using ntlm_auth. */
diff --git a/source3/winbindd/winbindd_pam_auth_crap.c b/source3/winbindd/winbindd_pam_auth_crap.c
index 695ee1d0864..eb4087b1c2c 100644
--- a/source3/winbindd/winbindd_pam_auth_crap.c
+++ b/source3/winbindd/winbindd_pam_auth_crap.c
@@ -20,6 +20,7 @@
 #include "includes.h"
 #include "winbindd.h"
 #include "rpc_client/util_netlogon.h"
+#include "libcli/security/dom_sid.h"
 
 struct winbindd_pam_auth_crap_state {
 	struct winbindd_response *response;
@@ -46,10 +47,11 @@ struct tevent_req *winbindd_pam_auth_crap_send(
 		return NULL;
 	}
 
-	if (request->flags & WBFLAG_PAM_AUTH_PAC) {
+	state->flags = request->flags;
+
+	if (state->flags & WBFLAG_PAM_AUTH_PAC) {
 		NTSTATUS status;
 
-		state->flags = request->flags;
 		status = winbindd_pam_auth_pac_send(cli, &state->info3);
 		if (NT_STATUS_IS_OK(status)) {
 			/* Defer filling out response to recv */
@@ -132,7 +134,7 @@ NTSTATUS winbindd_pam_auth_crap_recv(struct tevent_req *req,
 		return status;
 	}
 
-	if (state->flags & WBFLAG_PAM_AUTH_PAC) {
+	if (state->flags & WBFLAG_PAM_AUTH_PAC)	{
 		uint16_t validation_level;
 		union netr_Validation *validation = NULL;
 
@@ -155,6 +157,22 @@ NTSTATUS winbindd_pam_auth_crap_recv(struct tevent_req *req,
 
 	}
 
+ 	if (NT_STATUS_IS_OK(NT_STATUS(state->response->data.auth.nt_status)) &&
+	    (state->flags & WBFLAG_PAM_INFO3_TEXT))
+	{
+		bool ok;
+
+		ok = add_trusted_domain_from_auth(
+			state->response->data.auth.validation_level,
+			&state->response->data.auth.info3,
+			&state->response->data.auth.info6);
+		if (!ok) {
+			DBG_ERR("add_trusted_domain_from_auth failed\n");
+			set_auth_errors(response, NT_STATUS_LOGON_FAILURE);
+			return NT_STATUS_LOGON_FAILURE;
+		}
+	}
+
 	*response = *state->response;
 	response->result = WINBINDD_PENDING;
 	state->response = talloc_move(response, &state->response);
-- 
2.13.6


From c605a0c9c0444e8b68aac32b45229e9e8359f411 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Tue, 28 Nov 2017 17:32:59 +0100
Subject: [PATCH 17/23] winbindd: transitive trust logic in
 trust_is_transitive()

trust_is_transitive() currently defaults to transitive=true, unless
LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE, LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN or
LSA_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL trust attribute is set.

This is not correct, for the trust to be transative,
LSA_TRUST_ATTRIBUTE_WITHIN_FOREST or LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE must
be set.

Logic taken from dsdb_trust_routing_by_name().

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/winbindd/winbindd_misc.c | 32 +++++++++++++++++++++++++++-----
 1 file changed, 27 insertions(+), 5 deletions(-)

diff --git a/source3/winbindd/winbindd_misc.c b/source3/winbindd/winbindd_misc.c
index c80e7844bc2..51c8799de32 100644
--- a/source3/winbindd/winbindd_misc.c
+++ b/source3/winbindd/winbindd_misc.c
@@ -78,11 +78,33 @@ static bool trust_is_outbound(struct winbindd_tdc_domain *domain)
 
 static bool trust_is_transitive(struct winbindd_tdc_domain *domain)
 {
-	if ((domain->trust_attribs == LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE) ||
-	    (domain->trust_attribs == LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) ||
-	    (domain->trust_attribs == LSA_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL))
-		return False;
-	return True;
+	bool transitive = false;
+
+	/*
+	 * Beware: order matters
+	 */
+
+	if (domain->trust_attribs & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
+		transitive = true;
+	}
+
+	if (domain->trust_attribs & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
+		transitive = true;
+	}
+
+	if (domain->trust_attribs & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE) {
+		transitive = false;
+	}
+
+	if (domain->trust_attribs & LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) {
+		transitive = false;
+	}
+
+	if (domain->trust_flags & NETR_TRUST_FLAG_PRIMARY) {
+		transitive = true;
+	}
+
+	return transitive;
 }
 
 void winbindd_list_trusted_domains(struct winbindd_cli_state *state)
-- 
2.13.6


From fd9b95bb9c8441d3d658ad0e110549f33d99efd4 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Tue, 28 Nov 2017 17:44:41 +0100
Subject: [PATCH 18/23] winbindd: fix trust_is_inbound()

A trust is only inbound if NETR_TRUST_FLAG_INBOUND is set. Trust flags = 0x0
does not imply an inbound trust, nor does NETR_TRUST_FLAG_IN_FOREST.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/winbindd/winbindd_misc.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/source3/winbindd/winbindd_misc.c b/source3/winbindd/winbindd_misc.c
index 51c8799de32..051e9515f31 100644
--- a/source3/winbindd/winbindd_misc.c
+++ b/source3/winbindd/winbindd_misc.c
@@ -60,11 +60,10 @@ static const char *get_trust_type_string(struct winbindd_tdc_domain *domain)
 
 static bool trust_is_inbound(struct winbindd_tdc_domain *domain)
 {
-	return (domain->trust_flags == 0x0) ||
-	    ((domain->trust_flags & NETR_TRUST_FLAG_IN_FOREST) ==
-            NETR_TRUST_FLAG_IN_FOREST) ||           		
-	    ((domain->trust_flags & NETR_TRUST_FLAG_INBOUND) ==
-	    NETR_TRUST_FLAG_INBOUND);      	
+	if (domain->trust_flags & NETR_TRUST_FLAG_INBOUND) {
+		return true;
+	}
+	return false;
 }
 
 static bool trust_is_outbound(struct winbindd_tdc_domain *domain)
-- 
2.13.6


From 47d51f3ecf7395ee56a4cbaf63c8dbe1d2aba4d4 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Tue, 28 Nov 2017 17:46:03 +0100
Subject: [PATCH 19/23] winbindd: fix trust_is_oubound()

A trust is only inbound if NETR_TRUST_FLAG_OUTBOUND is set. Trust flags = 0x0
does not imply an outbound trust, nor does NETR_TRUST_FLAG_IN_FOREST.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/winbindd/winbindd_misc.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/source3/winbindd/winbindd_misc.c b/source3/winbindd/winbindd_misc.c
index 051e9515f31..d2741cb6b6f 100644
--- a/source3/winbindd/winbindd_misc.c
+++ b/source3/winbindd/winbindd_misc.c
@@ -68,11 +68,10 @@ static bool trust_is_inbound(struct winbindd_tdc_domain *domain)
 
 static bool trust_is_outbound(struct winbindd_tdc_domain *domain)
 {
-	return (domain->trust_flags == 0x0) ||
-	    ((domain->trust_flags & NETR_TRUST_FLAG_IN_FOREST) ==
-            NETR_TRUST_FLAG_IN_FOREST) ||           		
-	    ((domain->trust_flags & NETR_TRUST_FLAG_OUTBOUND) ==
-	    NETR_TRUST_FLAG_OUTBOUND);      	
+	if (domain->trust_flags & NETR_TRUST_FLAG_OUTBOUND) {
+		return true;
+	}
+	return false;
 }
 
 static bool trust_is_transitive(struct winbindd_tdc_domain *domain)
-- 
2.13.6


From 75b76c200e12af5bd37b05dda53ae40136ee4891 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Tue, 19 Dec 2017 17:26:46 +0100
Subject: [PATCH 20/23] libwbclient: add trust routing and more trust-types

This adds the struct member and the defines, the implementation comes
later.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 nsswitch/libwbclient/wbclient.h | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/nsswitch/libwbclient/wbclient.h b/nsswitch/libwbclient/wbclient.h
index ed97a673739..81a6a6a069b 100644
--- a/nsswitch/libwbclient/wbclient.h
+++ b/nsswitch/libwbclient/wbclient.h
@@ -187,6 +187,7 @@ struct wbcDomainInfo {
 	uint32_t domain_flags;
 	uint32_t trust_flags;
 	uint32_t trust_type;
+	char *trust_routing;
 };
 
 /* wbcDomainInfo->domain_flags */
@@ -209,6 +210,12 @@ struct wbcDomainInfo {
 #define WBC_DOMINFO_TRUSTTYPE_FOREST     0x00000001
 #define WBC_DOMINFO_TRUSTTYPE_IN_FOREST  0x00000002
 #define WBC_DOMINFO_TRUSTTYPE_EXTERNAL   0x00000003
+#define WBC_DOMINFO_TRUSTTYPE_LOCAL      0x00000004
+#define WBC_DOMINFO_TRUSTTYPE_WKSTA      0x00000005
+#define WBC_DOMINFO_TRUSTTYPE_RWDC       0x00000006
+#define WBC_DOMINFO_TRUSTTYPE_RODC       0x00000007
+#define WBC_DOMINFO_TRUSTTYPE_PDC        0x00000008
+
 
 /**
  * @brief Generic Blob
-- 
2.13.6


From 4427f4d4f7a5757a886a98cb3a769bd828d379e2 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 13 Dec 2017 16:02:22 +0100
Subject: [PATCH 21/23] wbinfo: support for local, workstation and routed trust
 types

Prepare wbinfo for additional trust types and trust routing.

This also modifies the output line for a "None" trust type by skipping
the transitivity and direction -- that just doesn't make sense without a
trust.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 nsswitch/wbinfo.c | 21 ++++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/nsswitch/wbinfo.c b/nsswitch/wbinfo.c
index 9cd299a2174..54d5758aa6c 100644
--- a/nsswitch/wbinfo.c
+++ b/nsswitch/wbinfo.c
@@ -536,7 +536,26 @@ static bool wbinfo_list_domains(bool list_all_domains, bool verbose)
 
 		switch(domain_list[i].trust_type) {
 		case WBC_DOMINFO_TRUSTTYPE_NONE:
-			d_printf("None        ");
+			if (domain_list[i].trust_routing != NULL) {
+				d_printf("%s\n", domain_list[i].trust_routing);
+			} else {
+				d_printf("None\n");
+			}
+			continue;
+		case WBC_DOMINFO_TRUSTTYPE_LOCAL:
+			d_printf("Local\n");
+			continue;
+		case WBC_DOMINFO_TRUSTTYPE_RWDC:
+			d_printf("RWDC\n");
+			continue;
+		case WBC_DOMINFO_TRUSTTYPE_RODC:
+			d_printf("RODC\n");
+			continue;
+		case WBC_DOMINFO_TRUSTTYPE_PDC:
+			d_printf("PDC\n");
+			continue;
+		case WBC_DOMINFO_TRUSTTYPE_WKSTA:
+			d_printf("Workstation ");
 			break;
 		case WBC_DOMINFO_TRUSTTYPE_FOREST:
 			d_printf("Forest      ");
-- 
2.13.6


From 1faad25ac4a2b811a9c8f71c7626af9c7621e69b Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 13 Dec 2017 16:01:50 +0100
Subject: [PATCH 22/23] libwbclient: add more trust types

Prepare libwbclient for additional trust types and trust routing.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 nsswitch/libwbclient/wbc_util.c | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/nsswitch/libwbclient/wbc_util.c b/nsswitch/libwbclient/wbc_util.c
index 3dab0a2de1b..ecfcaa0fb60 100644
--- a/nsswitch/libwbclient/wbc_util.c
+++ b/nsswitch/libwbclient/wbc_util.c
@@ -455,8 +455,22 @@ static wbcErr process_domain_info_string(struct wbcDomainInfo *info,
 	*s = '\0';
 	s++;
 
-	if (strcmp(r, "None") == 0) {
+	if (strcmp(r, "Local") == 0) {
 		info->trust_type = WBC_DOMINFO_TRUSTTYPE_NONE;
+	} else if (strncmp(r, "Routed", strlen("Routed")) == 0) {
+		info->trust_type = WBC_DOMINFO_TRUSTTYPE_NONE;
+		info->trust_routing = strdup(r);
+		BAIL_ON_PTR_ERROR(info->trust_routing, wbc_status);
+	} else if (strcmp(r, "Local") == 0) {
+		info->trust_type = WBC_DOMINFO_TRUSTTYPE_LOCAL;
+	} else if (strcmp(r, "Workstation") == 0) {
+		info->trust_type = WBC_DOMINFO_TRUSTTYPE_WKSTA;
+	} else if (strcmp(r, "RWDC") == 0) {
+		info->trust_type = WBC_DOMINFO_TRUSTTYPE_RWDC;
+	} else if (strcmp(r, "RODC") == 0) {
+		info->trust_type = WBC_DOMINFO_TRUSTTYPE_RODC;
+	} else if (strcmp(r, "PDC") == 0) {
+		info->trust_type = WBC_DOMINFO_TRUSTTYPE_PDC;
 	} else if (strcmp(r, "External") == 0) {
 		info->trust_type = WBC_DOMINFO_TRUSTTYPE_EXTERNAL;
 	} else if (strcmp(r, "Forest") == 0) {
-- 
2.13.6


From 6840a7d887ffbf9450ddaa8709902c3d23d2eca6 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 13 Dec 2017 08:53:16 +0100
Subject: [PATCH 23/23] winbindd: add more trust types to get_trust_type_string
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Add support for the following trust types: "Local", "Workstation",
"RWDC", "RODC"´and "Routed (via ...)".

Where we previously returned "None" this now returns "Routed (via ...)",
otherwise (hopefully) no change in behaviour.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/winbindd/winbindd_misc.c | 159 ++++++++++++++++++++++++++++++++-------
 1 file changed, 133 insertions(+), 26 deletions(-)

diff --git a/source3/winbindd/winbindd_misc.c b/source3/winbindd/winbindd_misc.c
index d2741cb6b6f..964190e7c62 100644
--- a/source3/winbindd/winbindd_misc.c
+++ b/source3/winbindd/winbindd_misc.c
@@ -27,35 +27,133 @@
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_WINBIND
 
-/* Constants and helper functions for determining domain trust types */
+static char *get_trust_type_string(TALLOC_CTX *mem_ctx,
+				   struct winbindd_tdc_domain *tdc,
+				   struct winbindd_domain *domain)
+{
+	enum netr_SchannelType secure_channel_type = SEC_CHAN_NULL;
+	char *s = NULL;
 
-enum trust_type {
-	EXTERNAL = 0,
-	FOREST,
-	IN_FOREST,
-	NONE,
-};
+	if (domain != NULL) {
+		secure_channel_type = domain->secure_channel_type;
+	}
 
-const char *trust_type_strings[] = {"External", 
-				    "Forest", 
-				    "In Forest",
-				    "None"};
+	switch (secure_channel_type) {
+	case SEC_CHAN_NULL: {
+		if (domain == NULL) {
+			DBG_ERR("Missing domain [%s]\n",
+				tdc->domain_name);
+			return NULL;
+		}
+		if (domain->routing_domain == NULL) {
+			DBG_ERR("Missing routing for domain [%s]\n",
+				tdc->domain_name);
+			return NULL;
+		}
+		s = talloc_asprintf(mem_ctx, "Routed (via %s)",
+				    domain->routing_domain->name);
+		if (s == NULL) {
+			return NULL;
+		}
+		break;
+	}
 
-static enum trust_type get_trust_type(struct winbindd_tdc_domain *domain)
-{
-	if (domain->trust_attribs == LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN)
-		return EXTERNAL;
-	else if (domain->trust_attribs == LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)
-		return FOREST;
-	else if (((domain->trust_flags & NETR_TRUST_FLAG_IN_FOREST) == NETR_TRUST_FLAG_IN_FOREST) &&
-	    ((domain->trust_flags & NETR_TRUST_FLAG_PRIMARY) == 0x0))
-		return IN_FOREST;
-	return NONE;	
-}
+	case SEC_CHAN_LOCAL:
+		s = talloc_strdup(mem_ctx, "Local");
+		if (s == NULL) {
+			return NULL;
+		}
+		break;
 
-static const char *get_trust_type_string(struct winbindd_tdc_domain *domain)
-{
-	return trust_type_strings[get_trust_type(domain)];
+	case SEC_CHAN_WKSTA:
+		s = talloc_strdup(mem_ctx, "Workstation");
+		if (s == NULL) {
+			return NULL;
+		}
+		break;
+
+	case SEC_CHAN_BDC: {
+		int role = lp_server_role();
+
+		if (role == ROLE_DOMAIN_PDC) {
+			s = talloc_strdup(mem_ctx, "PDC");
+			if (s == NULL) {
+				return NULL;
+			}
+			break;
+		}
+
+		if (role == ROLE_DOMAIN_BDC) {
+			s = talloc_strdup(mem_ctx, "BDC");
+			if (s == NULL) {
+				return NULL;
+			}
+			break;
+		}
+
+		s = talloc_strdup(mem_ctx, "RWDC");
+		if (s == NULL) {
+			return NULL;
+		}
+		break;
+	}
+
+	case SEC_CHAN_RODC:
+		s = talloc_strdup(mem_ctx, "RODC");
+		if (s == NULL) {
+			return NULL;
+		}
+		break;
+
+	case SEC_CHAN_DNS_DOMAIN:
+		if (tdc->trust_attribs & LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) {
+			s = talloc_strdup(mem_ctx, "External");
+			if (s == NULL) {
+				return NULL;
+			}
+			break;
+		}
+		if (tdc->trust_attribs & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
+			s = talloc_strdup(mem_ctx, "In Forest");
+			if (s == NULL) {
+				return NULL;
+			}
+			break;
+		}
+		if (tdc->trust_attribs & LSA_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL) {
+			s = talloc_strdup(mem_ctx, "External");
+			if (s == NULL) {
+				return NULL;
+			}
+			break;
+		}
+		if (tdc->trust_attribs & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
+			s = talloc_strdup(mem_ctx, "Forest");
+			if (s == NULL) {
+				return NULL;
+			}
+			break;
+		}
+		s = talloc_strdup(mem_ctx, "External");
+		if (s == NULL) {
+			return NULL;
+		}
+		break;
+
+	case SEC_CHAN_DOMAIN:
+		s = talloc_strdup(mem_ctx, "External");
+		if (s == NULL) {
+			return NULL;
+		}
+		break;
+
+	default:
+		DBG_ERR("Unhandled secure_channel_type %d for domain[%s]\n",
+			secure_channel_type, tdc->domain_name);
+		return NULL;
+	}
+
+	return s;
 }
 
 static bool trust_is_inbound(struct winbindd_tdc_domain *domain)
@@ -131,23 +229,32 @@ void winbindd_list_trusted_domains(struct winbindd_cli_state *state)
 		struct winbindd_domain *domain;
 		bool is_online = true;		
 		struct winbindd_tdc_domain *d = NULL;
+		char *trust_type = NULL;
 
 		d = &dom_list[i];
 		domain = find_domain_from_name_noinit(d->domain_name);
 		if (domain) {
 			is_online = domain->online;
 		}
+
+		trust_type = get_trust_type_string(talloc_tos(), d, domain);
+		if (trust_type == NULL) {
+			continue;
+		}
+
 		extra_data = talloc_asprintf_append_buffer(
 			extra_data,
 			"%s\\%s\\%s\\%s\\%s\\%s\\%s\\%s\n",
 			d->domain_name,
 			d->dns_name ? d->dns_name : "",
 			sid_string_talloc(state->mem_ctx, &d->sid),
-			get_trust_type_string(d),
+			trust_type,
 			trust_is_transitive(d) ? "Yes" : "No",
 			trust_is_inbound(d) ? "Yes" : "No",
 			trust_is_outbound(d) ? "Yes" : "No",
 			is_online ? "Online" : "Offline" );
+
+		TALLOC_FREE(trust_type);
 	}
 
 	state->response->data.num_entries = num_domains;
-- 
2.13.6



More information about the samba-technical mailing list