[PATCH] Preparatory patches for winbindd and trusts

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


Hi!

Attached is a preparatory patchset from my winbindd-trusts branch [1], that
prepares winbindd for a possible later change to remove trust enumeration.

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 75353ab12d5f34656bbac824ae189fcc1fc21168 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sat, 9 Dec 2017 19:27:22 +0100
Subject: [PATCH 01/28] s3/torture: fix an error message

Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 source3/torture/pdbtest.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source3/torture/pdbtest.c b/source3/torture/pdbtest.c
index 9e2a7423e27..adbd982ab44 100644
--- a/source3/torture/pdbtest.c
+++ b/source3/torture/pdbtest.c
@@ -501,7 +501,7 @@ static bool test_trusted_domains(TALLOC_CTX *ctx,
 
 	rv = pdb->get_trusted_domain(pdb, ctx, TRUST_DOM, &new_td);
 	if (!NT_STATUS_IS_OK(rv)) {
-		fprintf(stderr, "Error in set_trusted_domain %s\n",
+		fprintf(stderr, "Error in get_trusted_domain %s\n",
 				get_friendly_nt_error_msg(rv));
 		*error = true;
 	}
-- 
2.13.6


From 7f8f90c71c76f07ffae00e2fa160e4ca262b4908 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Fri, 1 Dec 2017 07:58:07 +0100
Subject: [PATCH 02/28] s3/rpc_client: fix overly long lines

Just long lines cleanup, no further changes. Best viewed with git show -w.

Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 source3/rpc_client/cli_netlogon.h | 52 ++++++++++++++++++++-------------------
 1 file changed, 27 insertions(+), 25 deletions(-)

diff --git a/source3/rpc_client/cli_netlogon.h b/source3/rpc_client/cli_netlogon.h
index da562e056d3..db8eb502029 100644
--- a/source3/rpc_client/cli_netlogon.h
+++ b/source3/rpc_client/cli_netlogon.h
@@ -59,30 +59,32 @@ NTSTATUS rpccli_connect_netlogon(
 	bool force_reauth,
 	struct cli_credentials *trust_creds,
 	struct rpc_pipe_client **_rpccli);
-NTSTATUS rpccli_netlogon_password_logon(struct netlogon_creds_cli_context *creds,
-					struct dcerpc_binding_handle *binding_handle,
-					TALLOC_CTX *mem_ctx,
-					uint32_t logon_parameters,
-					const char *domain,
-					const char *username,
-					const char *password,
-					const char *workstation,
-					enum netr_LogonInfoClass logon_type,
-					uint8_t *authoritative,
-					uint32_t *flags,
-					struct netr_SamInfo3 **info3);
-NTSTATUS rpccli_netlogon_network_logon(struct netlogon_creds_cli_context *creds,
-				       struct dcerpc_binding_handle *binding_handle,
-				       TALLOC_CTX *mem_ctx,
-				       uint32_t logon_parameters,
-				       const char *username,
-				       const char *domain,
-				       const char *workstation,
-				       const uint8_t chal[8],
-				       DATA_BLOB lm_response,
-				       DATA_BLOB nt_response,
-				       uint8_t *authoritative,
-				       uint32_t *flags,
-				       struct netr_SamInfo3 **info3);
+NTSTATUS rpccli_netlogon_password_logon(
+	struct netlogon_creds_cli_context *creds,
+	struct dcerpc_binding_handle *binding_handle,
+	TALLOC_CTX *mem_ctx,
+	uint32_t logon_parameters,
+	const char *domain,
+	const char *username,
+	const char *password,
+	const char *workstation,
+	enum netr_LogonInfoClass logon_type,
+	uint8_t *authoritative,
+	uint32_t *flags,
+	struct netr_SamInfo3 **info3);
+NTSTATUS rpccli_netlogon_network_logon(
+	struct netlogon_creds_cli_context *creds,
+	struct dcerpc_binding_handle *binding_handle,
+	TALLOC_CTX *mem_ctx,
+	uint32_t logon_parameters,
+	const char *username,
+	const char *domain,
+	const char *workstation,
+	const uint8_t chal[8],
+	DATA_BLOB lm_response,
+	DATA_BLOB nt_response,
+	uint8_t *authoritative,
+	uint32_t *flags,
+	struct netr_SamInfo3 **info3);
 
 #endif /* _RPC_CLIENT_CLI_NETLOGON_H_ */
-- 
2.13.6


From 02122e075d3be576cf68d7eb2295fd5e5472ab83 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Fri, 1 Dec 2017 07:59:50 +0100
Subject: [PATCH 03/28] winbindd: fix overly long lines

Just another long lines cleanup. Best viewed with git show -w.

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

diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c
index abd208a515f..54bf5e86a62 100644
--- a/source3/winbindd/winbindd_pam.c
+++ b/source3/winbindd/winbindd_pam.c
@@ -1443,32 +1443,34 @@ static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain,
 				  "domain [%s]\n", domainname);
 			result = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
 		} else if (interactive) {
-			result = rpccli_netlogon_password_logon(domain->conn.netlogon_creds_ctx,
-								netlogon_pipe->binding_handle,
-								mem_ctx,
-								logon_parameters,
-								domainname,
-								username,
-								password,
-								workstation,
-								NetlogonInteractiveInformation,
-								authoritative,
-								flags,
-								info3);
+			result = rpccli_netlogon_password_logon(
+				domain->conn.netlogon_creds_ctx,
+				netlogon_pipe->binding_handle,
+				mem_ctx,
+				logon_parameters,
+				domainname,
+				username,
+				password,
+				workstation,
+				NetlogonInteractiveInformation,
+				authoritative,
+				flags,
+				info3);
 		} else {
-			result = rpccli_netlogon_network_logon(domain->conn.netlogon_creds_ctx,
-							netlogon_pipe->binding_handle,
-							mem_ctx,
-							logon_parameters,
-							username,
-							domainname,
-							workstation,
-							chal,
-							lm_response,
-							nt_response,
-							authoritative,
-							flags,
-							info3);
+			result = rpccli_netlogon_network_logon(
+				domain->conn.netlogon_creds_ctx,
+				netlogon_pipe->binding_handle,
+				mem_ctx,
+				logon_parameters,
+				username,
+				domainname,
+				workstation,
+				chal,
+				lm_response,
+				nt_response,
+				authoritative,
+				flags,
+				info3);
 		}
 
 		/*
-- 
2.13.6


From 1502c3e1b9ad1f3a55b79c49b5e6cf9da642eced Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Fri, 1 Dec 2017 10:32:41 +0100
Subject: [PATCH 04/28] winbindd: remove a space

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

diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c
index 54bf5e86a62..6cbd14e91ef 100644
--- a/source3/winbindd/winbindd_pam.c
+++ b/source3/winbindd/winbindd_pam.c
@@ -1620,7 +1620,7 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon(TALLOC_CTX *mem_ctx,
 			&authoritative,
 			info3);
 
-		/* 
+		/*
 		 * We need to try the remote NETLOGON server if this is
 		 * not authoritative (for example on the RODC).
 		 */
-- 
2.13.6


From 2a5fd68c0c78ffc86aadc942f0a477ff06124ce2 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Fri, 1 Dec 2017 11:40:47 +0100
Subject: [PATCH 05/28] winbindd: remove an else branch

No change in behaviour.

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

diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c
index 6cbd14e91ef..7ec3e5a4e1e 100644
--- a/source3/winbindd/winbindd_pam.c
+++ b/source3/winbindd/winbindd_pam.c
@@ -1797,10 +1797,11 @@ enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
 		if (NT_STATUS_IS_OK(result)) {
 			DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
 			goto process_result;
-		} else {
-			DEBUG(10,("winbindd_dual_pam_auth_kerberos failed: %s\n", nt_errstr(result)));
 		}
 
+		DBG_DEBUG("winbindd_dual_pam_auth_kerberos failed: %s\n",
+			  nt_errstr(result));
+
 		if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
 		    NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
 		    NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
-- 
2.13.6


From 8b8ff7ca2ab49810a83db46265cca90002aa5b32 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Fri, 1 Dec 2017 12:23:50 +0100
Subject: [PATCH 06/28] winbindd: simplify if condition in
 find_domain_from_name_noinit()

No change in behaviour.

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

diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c
index b3439d078a3..62eff4a563f 100644
--- a/source3/winbindd/winbindd_util.c
+++ b/source3/winbindd/winbindd_util.c
@@ -936,9 +936,13 @@ struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
 	/* Search through list */
 
 	for (domain = domain_list(); domain != NULL; domain = domain->next) {
-		if (strequal(domain_name, domain->name) ||
-		    (domain->alt_name != NULL &&
-		     strequal(domain_name, domain->alt_name))) {
+		if (strequal(domain_name, domain->name)) {
+			return domain;
+		}
+		if (domain->alt_name == NULL) {
+			continue;
+		}
+		if (strequal(domain_name, domain->alt_name)) {
 			return domain;
 		}
 	}
-- 
2.13.6


From 557e7214ac2e0c0700819beb70410fedd3ad60bb Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Fri, 1 Dec 2017 08:26:59 +0100
Subject: [PATCH 07/28] winbindd: prevent long lines in a later commit

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

diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c
index 7ec3e5a4e1e..b6d5b05491b 100644
--- a/source3/winbindd/winbindd_pam.c
+++ b/source3/winbindd/winbindd_pam.c
@@ -1540,12 +1540,13 @@ static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain,
 	return result;
 }
 
-static NTSTATUS winbindd_dual_pam_auth_samlogon(TALLOC_CTX *mem_ctx,
-						struct winbindd_domain *domain,
-						const char *user,
-						const char *pass,
-						uint32_t request_flags,
-						struct netr_SamInfo3 **info3)
+static NTSTATUS winbindd_dual_pam_auth_samlogon(
+	TALLOC_CTX *mem_ctx,
+	struct winbindd_domain *domain,
+	const char *user,
+	const char *pass,
+	uint32_t request_flags,
+	struct netr_SamInfo3 **info3)
 {
 
 	uchar chal[8];
-- 
2.13.6


From e6e1a1ca89de8324f67fd44d95271642cd8d436c Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sat, 2 Dec 2017 22:35:36 +0100
Subject: [PATCH 08/28] s3/rpc_client: move copy_netr_SamInfo3() to
 util_netlogon

The next commit will add an additional caller that in rpc_client and I
don't want to pull in AUTH_COMMON. The natural place to consolidate
netlogon related helper functions seems to be util_netlogon.c which
already has copy_netr_SamBaseInfo().

No change in behaviour.

Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 source3/auth/auth_util.c           |  1 +
 source3/auth/proto.h               |  2 --
 source3/auth/server_info.c         | 42 --------------------------------------
 source3/rpc_client/util_netlogon.c | 41 +++++++++++++++++++++++++++++++++++++
 source3/rpc_client/util_netlogon.h |  2 ++
 source3/winbindd/winbindd_pam.c    |  1 +
 6 files changed, 45 insertions(+), 44 deletions(-)

diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c
index 464fe25abcc..5bb5a69dfa7 100644
--- a/source3/auth/auth_util.c
+++ b/source3/auth/auth_util.c
@@ -36,6 +36,7 @@
 #include "../librpc/gen_ndr/idmap.h"
 #include "lib/param/loadparm.h"
 #include "../lib/tsocket/tsocket.h"
+#include "rpc_client/util_netlogon.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_AUTH
diff --git a/source3/auth/proto.h b/source3/auth/proto.h
index 996b432f18c..e7746701022 100644
--- a/source3/auth/proto.h
+++ b/source3/auth/proto.h
@@ -322,8 +322,6 @@ NTSTATUS passwd_to_SamInfo3(TALLOC_CTX *mem_ctx,
 			    const struct passwd *pwd,
 			    struct netr_SamInfo3 **pinfo3,
 			    struct extra_auth_info *extra);
-struct netr_SamInfo3 *copy_netr_SamInfo3(TALLOC_CTX *mem_ctx,
-					 const struct netr_SamInfo3 *orig);
 
 /* The following definitions come from auth/pampass.c  */
 
diff --git a/source3/auth/server_info.c b/source3/auth/server_info.c
index 8461d2089f2..20d43d237fa 100644
--- a/source3/auth/server_info.c
+++ b/source3/auth/server_info.c
@@ -711,45 +711,3 @@ NTSTATUS passwd_to_SamInfo3(TALLOC_CTX *mem_ctx,
 
 	return status;
 }
-
-#undef RET_NOMEM
-
-#define RET_NOMEM(ptr) do { \
-	if (!ptr) { \
-		TALLOC_FREE(info3); \
-		return NULL; \
-	} } while(0)
-
-struct netr_SamInfo3 *copy_netr_SamInfo3(TALLOC_CTX *mem_ctx,
-					 const struct netr_SamInfo3 *orig)
-{
-	struct netr_SamInfo3 *info3;
-	unsigned int i;
-	NTSTATUS status;
-
-	info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
-	if (!info3) return NULL;
-
-	status = copy_netr_SamBaseInfo(info3, &orig->base, &info3->base);
-	if (!NT_STATUS_IS_OK(status)) {
-		TALLOC_FREE(info3);
-		return NULL;
-	}
-
-	if (orig->sidcount) {
-		info3->sidcount = orig->sidcount;
-		info3->sids = talloc_array(info3, struct netr_SidAttr,
-					   orig->sidcount);
-		RET_NOMEM(info3->sids);
-		for (i = 0; i < orig->sidcount; i++) {
-			info3->sids[i].sid = dom_sid_dup(info3->sids,
-							    orig->sids[i].sid);
-			RET_NOMEM(info3->sids[i].sid);
-			info3->sids[i].attributes =
-				orig->sids[i].attributes;
-		}
-	}
-
-	return info3;
-}
-
diff --git a/source3/rpc_client/util_netlogon.c b/source3/rpc_client/util_netlogon.c
index d22078be332..ee2b590b751 100644
--- a/source3/rpc_client/util_netlogon.c
+++ b/source3/rpc_client/util_netlogon.c
@@ -61,3 +61,44 @@ NTSTATUS copy_netr_SamBaseInfo(TALLOC_CTX *mem_ctx,
 
 	return NT_STATUS_OK;
 }
+
+#undef RET_NOMEM
+
+#define RET_NOMEM(ptr) do { \
+	if (!ptr) { \
+		TALLOC_FREE(info3); \
+		return NULL; \
+	} } while(0)
+
+struct netr_SamInfo3 *copy_netr_SamInfo3(TALLOC_CTX *mem_ctx,
+					 const struct netr_SamInfo3 *orig)
+{
+	struct netr_SamInfo3 *info3;
+	unsigned int i;
+	NTSTATUS status;
+
+	info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
+	if (!info3) return NULL;
+
+	status = copy_netr_SamBaseInfo(info3, &orig->base, &info3->base);
+	if (!NT_STATUS_IS_OK(status)) {
+		TALLOC_FREE(info3);
+		return NULL;
+	}
+
+	if (orig->sidcount) {
+		info3->sidcount = orig->sidcount;
+		info3->sids = talloc_array(info3, struct netr_SidAttr,
+					   orig->sidcount);
+		RET_NOMEM(info3->sids);
+		for (i = 0; i < orig->sidcount; i++) {
+			info3->sids[i].sid = dom_sid_dup(info3->sids,
+							    orig->sids[i].sid);
+			RET_NOMEM(info3->sids[i].sid);
+			info3->sids[i].attributes =
+				orig->sids[i].attributes;
+		}
+	}
+
+	return info3;
+}
diff --git a/source3/rpc_client/util_netlogon.h b/source3/rpc_client/util_netlogon.h
index cea9787acb6..9e717dfe689 100644
--- a/source3/rpc_client/util_netlogon.h
+++ b/source3/rpc_client/util_netlogon.h
@@ -25,5 +25,7 @@
 NTSTATUS copy_netr_SamBaseInfo(TALLOC_CTX *mem_ctx,
 			       const struct netr_SamBaseInfo *in,
 			       struct netr_SamBaseInfo *out);
+struct netr_SamInfo3 *copy_netr_SamInfo3(TALLOC_CTX *mem_ctx,
+					 const struct netr_SamInfo3 *orig);
 
 #endif /* _RPC_CLIENT_UTIL_NETLOGON_H_ */
diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c
index b6d5b05491b..43060ee32ca 100644
--- a/source3/winbindd/winbindd_pam.c
+++ b/source3/winbindd/winbindd_pam.c
@@ -43,6 +43,7 @@
 #include "librpc/crypto/gse_krb5.h"
 #include "lib/afs/afs_funcs.h"
 #include "libsmb/samlogon_cache.h"
+#include "rpc_client/util_netlogon.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_WINBIND
-- 
2.13.6


From 8176e6f89670ce3810ed873954d1d8e46c9dd477 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sat, 2 Dec 2017 22:04:47 +0100
Subject: [PATCH 09/28] s3/rpc_client: in map_validation_to_info3() make a deep
 copy

In later commits we want to map a validation to info3 without modifying
the validation data. Otherwise no change in behaviour.

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

diff --git a/source3/rpc_client/cli_netlogon.c b/source3/rpc_client/cli_netlogon.c
index a67b6928ebf..573ecd70457 100644
--- a/source3/rpc_client/cli_netlogon.c
+++ b/source3/rpc_client/cli_netlogon.c
@@ -453,6 +453,7 @@ static NTSTATUS map_validation_to_info3(TALLOC_CTX *mem_ctx,
 					struct netr_SamInfo3 **info3_p)
 {
 	struct netr_SamInfo3 *info3;
+	struct netr_SamInfo6 *info6 = NULL;
 	NTSTATUS status;
 
 	if (validation == NULL) {
@@ -465,25 +466,54 @@ static NTSTATUS map_validation_to_info3(TALLOC_CTX *mem_ctx,
 			return NT_STATUS_INVALID_PARAMETER;
 		}
 
-		info3 = talloc_move(mem_ctx, &validation->sam3);
+		info3 = copy_netr_SamInfo3(mem_ctx, validation->sam3);
+		if (info3 == NULL) {
+			return NT_STATUS_NO_MEMORY;
+		}
 		break;
 	case 6:
 		if (validation->sam6 == NULL) {
 			return NT_STATUS_INVALID_PARAMETER;
 		}
+		info6 = validation->sam6;
 
 		info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
 		if (info3 == NULL) {
 			return NT_STATUS_NO_MEMORY;
 		}
-		status = copy_netr_SamBaseInfo(info3, &validation->sam6->base, &info3->base);
+
+		status = copy_netr_SamBaseInfo(info3,
+					       &info6->base,
+					       &info3->base);
 		if (!NT_STATUS_IS_OK(status)) {
 			TALLOC_FREE(info3);
 			return status;
 		}
 
-		info3->sidcount = validation->sam6->sidcount;
-		info3->sids = talloc_move(info3, &validation->sam6->sids);
+		if (validation->sam6->sidcount > 0) {
+			int i;
+
+			info3->sidcount = info6->sidcount;
+
+			info3->sids = talloc_array(info3,
+						   struct netr_SidAttr,
+						   info3->sidcount);
+			if (info3->sids == NULL) {
+				TALLOC_FREE(info3);
+				return NT_STATUS_NO_MEMORY;
+			}
+
+			for (i = 0; i < info3->sidcount; i++) {
+				info3->sids[i].sid = dom_sid_dup(
+					info3->sids, info6->sids[i].sid);
+				if (info3->sids[i].sid == NULL) {
+					TALLOC_FREE(info3);
+					return NT_STATUS_NO_MEMORY;
+				}
+				info3->sids[i].attributes =
+					info6->sids[i].attributes;
+			}
+		}
 		break;
 	default:
 		return NT_STATUS_BAD_VALIDATION_CLASS;
-- 
2.13.6


From 601f5734e4c8fabf0f70bae2e828fc2367b0c5f5 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 30 Nov 2017 23:19:07 +0100
Subject: [PATCH 10/28] s3/rpc_client: make map_validation_to_info3() public
 and move to util_netlogon

Will be needed in the next commit.

Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 source3/rpc_client/cli_netlogon.c  | 77 --------------------------------------
 source3/rpc_client/util_netlogon.c | 77 ++++++++++++++++++++++++++++++++++++++
 source3/rpc_client/util_netlogon.h |  4 ++
 3 files changed, 81 insertions(+), 77 deletions(-)

diff --git a/source3/rpc_client/cli_netlogon.c b/source3/rpc_client/cli_netlogon.c
index 573ecd70457..67c87354e69 100644
--- a/source3/rpc_client/cli_netlogon.c
+++ b/source3/rpc_client/cli_netlogon.c
@@ -447,83 +447,6 @@ NTSTATUS rpccli_connect_netlogon(
 	return status;
 }
 
-static NTSTATUS map_validation_to_info3(TALLOC_CTX *mem_ctx,
-					uint16_t validation_level,
-					union netr_Validation *validation,
-					struct netr_SamInfo3 **info3_p)
-{
-	struct netr_SamInfo3 *info3;
-	struct netr_SamInfo6 *info6 = NULL;
-	NTSTATUS status;
-
-	if (validation == NULL) {
-		return NT_STATUS_INVALID_PARAMETER;
-	}
-
-	switch (validation_level) {
-	case 3:
-		if (validation->sam3 == NULL) {
-			return NT_STATUS_INVALID_PARAMETER;
-		}
-
-		info3 = copy_netr_SamInfo3(mem_ctx, validation->sam3);
-		if (info3 == NULL) {
-			return NT_STATUS_NO_MEMORY;
-		}
-		break;
-	case 6:
-		if (validation->sam6 == NULL) {
-			return NT_STATUS_INVALID_PARAMETER;
-		}
-		info6 = validation->sam6;
-
-		info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
-		if (info3 == NULL) {
-			return NT_STATUS_NO_MEMORY;
-		}
-
-		status = copy_netr_SamBaseInfo(info3,
-					       &info6->base,
-					       &info3->base);
-		if (!NT_STATUS_IS_OK(status)) {
-			TALLOC_FREE(info3);
-			return status;
-		}
-
-		if (validation->sam6->sidcount > 0) {
-			int i;
-
-			info3->sidcount = info6->sidcount;
-
-			info3->sids = talloc_array(info3,
-						   struct netr_SidAttr,
-						   info3->sidcount);
-			if (info3->sids == NULL) {
-				TALLOC_FREE(info3);
-				return NT_STATUS_NO_MEMORY;
-			}
-
-			for (i = 0; i < info3->sidcount; i++) {
-				info3->sids[i].sid = dom_sid_dup(
-					info3->sids, info6->sids[i].sid);
-				if (info3->sids[i].sid == NULL) {
-					TALLOC_FREE(info3);
-					return NT_STATUS_NO_MEMORY;
-				}
-				info3->sids[i].attributes =
-					info6->sids[i].attributes;
-			}
-		}
-		break;
-	default:
-		return NT_STATUS_BAD_VALIDATION_CLASS;
-	}
-
-	*info3_p = info3;
-
-	return NT_STATUS_OK;
-}
-
 /* Logon domain user */
 
 NTSTATUS rpccli_netlogon_password_logon(
diff --git a/source3/rpc_client/util_netlogon.c b/source3/rpc_client/util_netlogon.c
index ee2b590b751..0e600d681e9 100644
--- a/source3/rpc_client/util_netlogon.c
+++ b/source3/rpc_client/util_netlogon.c
@@ -102,3 +102,80 @@ struct netr_SamInfo3 *copy_netr_SamInfo3(TALLOC_CTX *mem_ctx,
 
 	return info3;
 }
+
+NTSTATUS map_validation_to_info3(TALLOC_CTX *mem_ctx,
+				 uint16_t validation_level,
+				 union netr_Validation *validation,
+				 struct netr_SamInfo3 **info3_p)
+{
+	struct netr_SamInfo3 *info3;
+	struct netr_SamInfo6 *info6 = NULL;
+	NTSTATUS status;
+
+	if (validation == NULL) {
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
+	switch (validation_level) {
+	case 3:
+		if (validation->sam3 == NULL) {
+			return NT_STATUS_INVALID_PARAMETER;
+		}
+
+		info3 = copy_netr_SamInfo3(mem_ctx, validation->sam3);
+		if (info3 == NULL) {
+			return NT_STATUS_NO_MEMORY;
+		}
+		break;
+	case 6:
+		if (validation->sam6 == NULL) {
+			return NT_STATUS_INVALID_PARAMETER;
+		}
+		info6 = validation->sam6;
+
+		info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
+		if (info3 == NULL) {
+			return NT_STATUS_NO_MEMORY;
+		}
+
+		status = copy_netr_SamBaseInfo(info3,
+					       &info6->base,
+					       &info3->base);
+		if (!NT_STATUS_IS_OK(status)) {
+			TALLOC_FREE(info3);
+			return status;
+		}
+
+		if (validation->sam6->sidcount > 0) {
+			int i;
+
+			info3->sidcount = info6->sidcount;
+
+			info3->sids = talloc_array(info3,
+						   struct netr_SidAttr,
+						   info3->sidcount);
+			if (info3->sids == NULL) {
+				TALLOC_FREE(info3);
+				return NT_STATUS_NO_MEMORY;
+			}
+
+			for (i = 0; i < info3->sidcount; i++) {
+				info3->sids[i].sid = dom_sid_dup(
+					info3->sids, info6->sids[i].sid);
+				if (info3->sids[i].sid == NULL) {
+					TALLOC_FREE(info3);
+					return NT_STATUS_NO_MEMORY;
+				}
+				info3->sids[i].attributes =
+					info6->sids[i].attributes;
+			}
+		}
+		break;
+	default:
+		return NT_STATUS_BAD_VALIDATION_CLASS;
+	}
+
+	*info3_p = info3;
+
+	return NT_STATUS_OK;
+}
diff --git a/source3/rpc_client/util_netlogon.h b/source3/rpc_client/util_netlogon.h
index 9e717dfe689..a89e043d5af 100644
--- a/source3/rpc_client/util_netlogon.h
+++ b/source3/rpc_client/util_netlogon.h
@@ -27,5 +27,9 @@ NTSTATUS copy_netr_SamBaseInfo(TALLOC_CTX *mem_ctx,
 			       struct netr_SamBaseInfo *out);
 struct netr_SamInfo3 *copy_netr_SamInfo3(TALLOC_CTX *mem_ctx,
 					 const struct netr_SamInfo3 *orig);
+NTSTATUS map_validation_to_info3(TALLOC_CTX *mem_ctx,
+				 uint16_t validation_level,
+				 union netr_Validation *validation,
+				 struct netr_SamInfo3 **info3_p);
 
 #endif /* _RPC_CLIENT_UTIL_NETLOGON_H_ */
-- 
2.13.6


From ec26fec7e6ef0848003dc5419a22089c149a574a Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 11 Dec 2017 15:18:58 +0100
Subject: [PATCH 11/28] s3/rpc_client: add map_info3_to_validation()

Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 source3/rpc_client/util_netlogon.c | 23 +++++++++++++++++++++++
 source3/rpc_client/util_netlogon.h |  4 ++++
 2 files changed, 27 insertions(+)

diff --git a/source3/rpc_client/util_netlogon.c b/source3/rpc_client/util_netlogon.c
index 0e600d681e9..ac804f84196 100644
--- a/source3/rpc_client/util_netlogon.c
+++ b/source3/rpc_client/util_netlogon.c
@@ -179,3 +179,26 @@ NTSTATUS map_validation_to_info3(TALLOC_CTX *mem_ctx,
 
 	return NT_STATUS_OK;
 }
+
+NTSTATUS map_info3_to_validation(TALLOC_CTX *mem_ctx,
+				 struct netr_SamInfo3 *info3,
+				 uint16_t *_validation_level,
+				 union netr_Validation **_validation)
+{
+	union netr_Validation *validation = NULL;
+
+	validation = talloc_zero(mem_ctx, union netr_Validation);
+	if (validation == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	validation->sam3 = copy_netr_SamInfo3(mem_ctx, info3);
+	if (validation->sam3 == NULL) {
+		TALLOC_FREE(validation);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	* _validation_level = 3;
+	*_validation = validation;
+	return NT_STATUS_OK;
+}
diff --git a/source3/rpc_client/util_netlogon.h b/source3/rpc_client/util_netlogon.h
index a89e043d5af..80c7bff99d1 100644
--- a/source3/rpc_client/util_netlogon.h
+++ b/source3/rpc_client/util_netlogon.h
@@ -31,5 +31,9 @@ NTSTATUS map_validation_to_info3(TALLOC_CTX *mem_ctx,
 				 uint16_t validation_level,
 				 union netr_Validation *validation,
 				 struct netr_SamInfo3 **info3_p);
+NTSTATUS map_info3_to_validation(TALLOC_CTX *mem_ctx,
+				 struct netr_SamInfo3 *info3,
+				 uint16_t *_validation_level,
+				 union netr_Validation **_validation);
 
 #endif /* _RPC_CLIENT_UTIL_NETLOGON_H_ */
-- 
2.13.6


From 5ce9b2097736e1dc74c1c02fb895a15f4294549c Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 30 Nov 2017 23:35:40 +0100
Subject: [PATCH 12/28] s3/rpc_client: return validation from rpccli_netlogon
 functions

Return the validation info instead of the already mapped info3. Higher
layers need info6 if available, this is the first step in passing the
unmapped info up to callers.

Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 source3/rpc_client/cli_netlogon.c | 27 ++++++++++-----------------
 source3/rpc_client/cli_netlogon.h |  8 +++++---
 source3/rpcclient/cmd_netlogon.c  | 14 +++++++++++++-
 source3/winbindd/winbindd_pam.c   | 24 +++++++++++++++++++++---
 4 files changed, 49 insertions(+), 24 deletions(-)

diff --git a/source3/rpc_client/cli_netlogon.c b/source3/rpc_client/cli_netlogon.c
index 67c87354e69..800b995215c 100644
--- a/source3/rpc_client/cli_netlogon.c
+++ b/source3/rpc_client/cli_netlogon.c
@@ -461,7 +461,8 @@ NTSTATUS rpccli_netlogon_password_logon(
 	enum netr_LogonInfoClass logon_type,
 	uint8_t *authoritative,
 	uint32_t *flags,
-	struct netr_SamInfo3 **info3)
+	uint16_t *_validation_level,
+	union netr_Validation **_validation)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -572,7 +573,7 @@ NTSTATUS rpccli_netlogon_password_logon(
 						  binding_handle,
 						  logon_type,
 						  logon,
-						  frame,
+						  mem_ctx,
 						  &validation_level,
 						  &validation,
 						  authoritative,
@@ -582,14 +583,9 @@ NTSTATUS rpccli_netlogon_password_logon(
 		return status;
 	}
 
-	status = map_validation_to_info3(mem_ctx,
-					 validation_level, validation,
-					 info3);
 	TALLOC_FREE(frame);
-	if (!NT_STATUS_IS_OK(status)) {
-		return status;
-	}
-
+	*_validation_level = validation_level;
+	*_validation = validation;
 
 	return NT_STATUS_OK;
 }
@@ -614,7 +610,8 @@ NTSTATUS rpccli_netlogon_network_logon(
 	DATA_BLOB nt_response,
 	uint8_t *authoritative,
 	uint32_t *flags,
-	struct netr_SamInfo3 **info3)
+	uint16_t *_validation_level,
+	union netr_Validation **_validation)
 {
 	NTSTATUS status;
 	const char *workstation_name_slash;
@@ -625,7 +622,7 @@ NTSTATUS rpccli_netlogon_network_logon(
 	struct netr_ChallengeResponse lm;
 	struct netr_ChallengeResponse nt;
 
-	*info3 = NULL;
+	*_validation = NULL;
 
 	ZERO_STRUCT(lm);
 	ZERO_STRUCT(nt);
@@ -686,12 +683,8 @@ NTSTATUS rpccli_netlogon_network_logon(
 		return status;
 	}
 
-	status = map_validation_to_info3(mem_ctx,
-					 validation_level, validation,
-					 info3);
-	if (!NT_STATUS_IS_OK(status)) {
-		return status;
-	}
+	*_validation_level = validation_level;
+	*_validation = validation;
 
 	return NT_STATUS_OK;
 }
diff --git a/source3/rpc_client/cli_netlogon.h b/source3/rpc_client/cli_netlogon.h
index db8eb502029..d31bdee461f 100644
--- a/source3/rpc_client/cli_netlogon.h
+++ b/source3/rpc_client/cli_netlogon.h
@@ -71,9 +71,10 @@ NTSTATUS rpccli_netlogon_password_logon(
 	enum netr_LogonInfoClass logon_type,
 	uint8_t *authoritative,
 	uint32_t *flags,
-	struct netr_SamInfo3 **info3);
+	uint16_t *_validation_level,
+	union netr_Validation **_validation);
 NTSTATUS rpccli_netlogon_network_logon(
-	struct netlogon_creds_cli_context *creds,
+	struct netlogon_creds_cli_context *creds_ctx,
 	struct dcerpc_binding_handle *binding_handle,
 	TALLOC_CTX *mem_ctx,
 	uint32_t logon_parameters,
@@ -85,6 +86,7 @@ NTSTATUS rpccli_netlogon_network_logon(
 	DATA_BLOB nt_response,
 	uint8_t *authoritative,
 	uint32_t *flags,
-	struct netr_SamInfo3 **info3);
+	uint16_t *_validation_level,
+	union netr_Validation **_validation);
 
 #endif /* _RPC_CLIENT_CLI_NETLOGON_H_ */
diff --git a/source3/rpcclient/cmd_netlogon.c b/source3/rpcclient/cmd_netlogon.c
index 2d6a0829a57..8d62ef7e095 100644
--- a/source3/rpcclient/cmd_netlogon.c
+++ b/source3/rpcclient/cmd_netlogon.c
@@ -27,6 +27,7 @@
 #include "rpc_client/cli_netlogon.h"
 #include "secrets.h"
 #include "../libcli/auth/netlogon_creds_cli.h"
+#include "rpc_client/util_netlogon.h"
 
 static WERROR cmd_netlogon_logon_ctrl2(struct rpc_pipe_client *cli,
 				       TALLOC_CTX *mem_ctx, int argc,
@@ -497,6 +498,8 @@ static NTSTATUS cmd_netlogon_sam_logon(struct rpc_pipe_client *cli,
 	struct netr_SamInfo3 *info3 = NULL;
 	uint8_t authoritative = 0;
 	uint32_t flags = 0;
+	uint16_t validation_level;
+	union netr_Validation *validation = NULL;
 
 	/* Check arguments */
 
@@ -536,10 +539,19 @@ static NTSTATUS cmd_netlogon_sam_logon(struct rpc_pipe_client *cli,
 						logon_type,
 						&authoritative,
 						&flags,
-						&info3);
+						&validation_level,
+						&validation);
 	if (!NT_STATUS_IS_OK(result))
 		goto done;
 
+	result = map_validation_to_info3(mem_ctx,
+					 validation_level,
+					 validation,
+					 &info3);
+	if (!NT_STATUS_IS_OK(result)) {
+		return result;
+	}
+
  done:
 	return result;
 }
diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c
index 43060ee32ca..42c4aef878c 100644
--- a/source3/winbindd/winbindd_pam.c
+++ b/source3/winbindd/winbindd_pam.c
@@ -1379,6 +1379,8 @@ static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain,
 	int netr_attempts = 0;
 	bool retry = false;
 	NTSTATUS result;
+	uint16_t validation_level;
+	union netr_Validation *validation = NULL;
 
 	do {
 		struct rpc_pipe_client *netlogon_pipe;
@@ -1456,7 +1458,8 @@ static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain,
 				NetlogonInteractiveInformation,
 				authoritative,
 				flags,
-				info3);
+				&validation_level,
+				&validation);
 		} else {
 			result = rpccli_netlogon_network_logon(
 				domain->conn.netlogon_creds_ctx,
@@ -1471,7 +1474,8 @@ static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain,
 				nt_response,
 				authoritative,
 				flags,
-				info3);
+				&validation_level,
+				&validation);
 		}
 
 		/*
@@ -1538,7 +1542,21 @@ static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain,
 			domainname));
 		invalidate_cm_connection(domain);
 	}
-	return result;
+
+	if (!NT_STATUS_IS_OK(result)) {
+		return result;
+	}
+
+	result = map_validation_to_info3(mem_ctx,
+					 validation_level,
+					 validation,
+					 info3);
+	TALLOC_FREE(validation);
+	if (!NT_STATUS_IS_OK(result)) {
+		return result;
+	}
+
+	return NT_STATUS_OK;
 }
 
 static NTSTATUS winbindd_dual_pam_auth_samlogon(
-- 
2.13.6


From 46451d2b24549c68d189e8de4fc3edb98a708c17 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Tue, 9 Jan 2018 16:58:06 +0100
Subject: [PATCH 13/28] winbindd: remove a redundant check from
 winbindd_dual_pam_auth_samlogon

result is already checked a few lines above.

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

diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c
index 42c4aef878c..bb5bab21209 100644
--- a/source3/winbindd/winbindd_pam.c
+++ b/source3/winbindd/winbindd_pam.c
@@ -1673,7 +1673,8 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon(
 	 * caller, we look up the account flags ourselves - gd */
 
 	if ((request_flags & WBFLAG_PAM_INFO3_TEXT) &&
-	    NT_STATUS_IS_OK(result) && (my_info3->base.acct_flags == 0)) {
+	    (my_info3->base.acct_flags == 0))
+	{
 
 		struct rpc_pipe_client *samr_pipe;
 		struct policy_handle samr_domain_handle, user_pol;
-- 
2.13.6


From 871c805855f52f2fc25f90fd582bf9c44da36e22 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 11 Dec 2017 23:26:38 +0100
Subject: [PATCH 14/28] winbindd: let winbind_samlogon_retry_loop return
 validation info

Return the validation info instead of the already mapped info3. Higher
layers need info6 if available, this is the first step in passing the
unmapped info up to callers.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/winbindd/winbindd_pam.c | 43 ++++++++++++++++++++++++++++-------------
 1 file changed, 30 insertions(+), 13 deletions(-)

diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c
index bb5bab21209..80a612479cf 100644
--- a/source3/winbindd/winbindd_pam.c
+++ b/source3/winbindd/winbindd_pam.c
@@ -1373,7 +1373,8 @@ static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain,
 					    bool interactive,
 					    uint8_t *authoritative,
 					    uint32_t *flags,
-					    struct netr_SamInfo3 **info3)
+					    uint16_t *_validation_level,
+					    union netr_Validation **_validation)
 {
 	int attempts = 0;
 	int netr_attempts = 0;
@@ -1385,7 +1386,6 @@ static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain,
 	do {
 		struct rpc_pipe_client *netlogon_pipe;
 
-		ZERO_STRUCTP(info3);
 		retry = false;
 
 		result = cm_connect_netlogon(domain, &netlogon_pipe);
@@ -1547,15 +1547,8 @@ static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain,
 		return result;
 	}
 
-	result = map_validation_to_info3(mem_ctx,
-					 validation_level,
-					 validation,
-					 info3);
-	TALLOC_FREE(validation);
-	if (!NT_STATUS_IS_OK(result)) {
-		return result;
-	}
-
+	*_validation_level = validation_level;
+	*_validation = validation;
 	return NT_STATUS_OK;
 }
 
@@ -1577,6 +1570,8 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon(
 	struct netr_SamInfo3 *my_info3 = NULL;
 	uint8_t authoritative = 0;
 	uint32_t flags = 0;
+	uint16_t validation_level;
+	union netr_Validation *validation = NULL;
 
 	*info3 = NULL;
 
@@ -1663,11 +1658,21 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon(
 					     true, /* interactive */
 					     &authoritative,
 					     &flags,
-					     &my_info3);
+					     &validation_level,
+					     &validation);
 	if (!NT_STATUS_IS_OK(result)) {
 		goto done;
 	}
 
+	result = map_validation_to_info3(mem_ctx,
+                                        validation_level,
+                                        validation,
+                                        &my_info3);
+	TALLOC_FREE(validation);
+	if (!NT_STATUS_IS_OK(result)) {
+		return result;
+	}
+
 	/* handle the case where a NT4 DC does not fill in the acct_flags in
 	 * the samlogon reply info3. When accurate info3 is required by the
 	 * caller, we look up the account flags ourselves - gd */
@@ -2031,6 +2036,8 @@ NTSTATUS winbind_dual_SamLogon(struct winbindd_domain *domain,
 			       uint32_t *flags,
 			       struct netr_SamInfo3 **info3)
 {
+	uint16_t validation_level;
+	union netr_Validation *validation = NULL;
 	NTSTATUS result;
 
 	/*
@@ -2079,11 +2086,21 @@ NTSTATUS winbind_dual_SamLogon(struct winbindd_domain *domain,
 					     false, /* interactive */
 					     authoritative,
 					     flags,
-					     info3);
+					     &validation_level,
+					     &validation);
 	if (!NT_STATUS_IS_OK(result)) {
 		goto done;
 	}
 
+	result = map_validation_to_info3(mem_ctx,
+					 validation_level,
+					 validation,
+					 info3);
+	TALLOC_FREE(validation);
+	if (!NT_STATUS_IS_OK(result)) {
+		return result;
+	}
+
 process_result:
 
 	if (NT_STATUS_IS_OK(result)) {
-- 
2.13.6


From 4433021042ca81c1026618645660cf3359cd39c9 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 11 Dec 2017 15:54:36 +0100
Subject: [PATCH 15/28] winbindd: let winbindd_dual_pam_auth_samlogon() return
 validation info

Pass up validation info instead of info3. No change in behaviour.

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

diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c
index 80a612479cf..05b3355cadd 100644
--- a/source3/winbindd/winbindd_pam.c
+++ b/source3/winbindd/winbindd_pam.c
@@ -1558,7 +1558,8 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon(
 	const char *user,
 	const char *pass,
 	uint32_t request_flags,
-	struct netr_SamInfo3 **info3)
+	uint16_t *_validation_level,
+	union netr_Validation **_validation)
 {
 
 	uchar chal[8];
@@ -1567,13 +1568,11 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon(
 	unsigned char local_nt_response[24];
 	fstring name_domain, name_user;
 	NTSTATUS result;
-	struct netr_SamInfo3 *my_info3 = NULL;
 	uint8_t authoritative = 0;
 	uint32_t flags = 0;
 	uint16_t validation_level;
 	union netr_Validation *validation = NULL;
-
-	*info3 = NULL;
+	struct netr_SamBaseInfo *base_info = NULL;
 
 	DEBUG(10,("winbindd_dual_pam_auth_samlogon\n"));
 
@@ -1592,6 +1591,7 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon(
 	 */
 	if (strequal(domain->name, get_global_sam_name())) {
 		DATA_BLOB chal_blob = data_blob_const(chal, sizeof(chal));
+		struct netr_SamInfo3 *info3 = NULL;
 
 		/* do password magic */
 
@@ -1629,11 +1629,21 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon(
 		}
 
 		result = winbindd_dual_auth_passdb(
-			mem_ctx, 0, name_domain, name_user,
+			talloc_tos(), 0, name_domain, name_user,
 			&chal_blob, &lm_resp, &nt_resp,
 			true, /* interactive */
 			&authoritative,
-			info3);
+			&info3);
+		if (NT_STATUS_IS_OK(result)) {
+			result = map_info3_to_validation(mem_ctx,
+							 info3,
+							 &validation_level,
+							 &validation);
+			TALLOC_FREE(info3);
+			if (!NT_STATUS_IS_OK(result)) {
+				goto done;
+			}
+		}
 
 		/*
 		 * We need to try the remote NETLOGON server if this is
@@ -1664,23 +1674,25 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon(
 		goto done;
 	}
 
-	result = map_validation_to_info3(mem_ctx,
-                                        validation_level,
-                                        validation,
-                                        &my_info3);
-	TALLOC_FREE(validation);
-	if (!NT_STATUS_IS_OK(result)) {
-		return result;
-	}
-
 	/* handle the case where a NT4 DC does not fill in the acct_flags in
 	 * the samlogon reply info3. When accurate info3 is required by the
 	 * caller, we look up the account flags ourselves - gd */
 
+	switch (validation_level) {
+	case 3:
+		base_info = &validation->sam3->base;
+		break;
+	case 6:
+		base_info = &validation->sam6->base;
+		break;
+	default:
+		DBG_ERR("Bad validation level %d", (int)validation_level);
+		result = NT_STATUS_INTERNAL_ERROR;
+		goto done;
+	}
 	if ((request_flags & WBFLAG_PAM_INFO3_TEXT) &&
-	    (my_info3->base.acct_flags == 0))
+	    (base_info->acct_flags == 0))
 	{
-
 		struct rpc_pipe_client *samr_pipe;
 		struct policy_handle samr_domain_handle, user_pol;
 		union samr_UserInfo *info = NULL;
@@ -1702,7 +1714,7 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon(
 		status_tmp = dcerpc_samr_OpenUser(b, mem_ctx,
 						  &samr_domain_handle,
 						  MAXIMUM_ALLOWED_ACCESS,
-						  my_info3->base.rid,
+						  base_info->rid,
 						  &user_pol,
 						  &result_tmp);
 
@@ -1738,15 +1750,18 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon(
 			goto done;
 		}
 
-		my_info3->base.acct_flags = acct_flags;
+		base_info->acct_flags = acct_flags;
 
 		DEBUG(10,("successfully retrieved acct_flags 0x%x\n", acct_flags));
 
 		dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
 	}
 
-	*info3 = my_info3;
 done:
+	if (NT_STATUS_IS_OK(result)) {
+		*_validation_level = validation_level;
+		*_validation = validation;
+	}
 	return result;
 }
 
@@ -1864,18 +1879,47 @@ enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
 sam_logon:
 	/* Check for Samlogon authentication */
 	if (domain->online) {
+		uint16_t validation_level;
+		union netr_Validation *validation = NULL;
+		struct netr_SamBaseInfo *base_info = NULL;
+
 		result = winbindd_dual_pam_auth_samlogon(
 			state->mem_ctx, domain,
 			state->request->data.auth.user,
 			state->request->data.auth.pass,
 			state->request->flags,
-			&info3);
+			&validation_level,
+			&validation);
 
 		if (NT_STATUS_IS_OK(result)) {
 			DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
+
+			switch (validation_level) {
+			case 3:
+				base_info = &validation->sam3->base;
+				break;
+			case 6:
+				base_info = &validation->sam6->base;
+				break;
+			default:
+				DBG_ERR("Bad validation level %d\n",
+					validation_level);
+				result = NT_STATUS_INTERNAL_ERROR;
+				goto done;
+			}
+
 			/* add the Krb5 err if we have one */
 			if ( NT_STATUS_EQUAL(krb5_result, NT_STATUS_TIME_DIFFERENCE_AT_DC ) ) {
-				info3->base.user_flags |= LOGON_KRB5_FAIL_CLOCK_SKEW;
+				base_info->user_flags |= LOGON_KRB5_FAIL_CLOCK_SKEW;
+			}
+
+			result = map_validation_to_info3(state->mem_ctx,
+							 validation_level,
+							 validation,
+							 &info3);
+			TALLOC_FREE(validation);
+			if (!NT_STATUS_IS_OK(result)) {
+				goto done;
 			}
 			goto process_result;
 		}
-- 
2.13.6


From 36d2586cd7863533a8eb8c6433ed5f69d5d7051c Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Fri, 1 Dec 2017 23:11:44 +0100
Subject: [PATCH 16/28] winbindd: remove a space in winbind_dual_SamLogon

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

diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c
index 05b3355cadd..222dee6bace 100644
--- a/source3/winbindd/winbindd_pam.c
+++ b/source3/winbindd/winbindd_pam.c
@@ -2106,7 +2106,7 @@ NTSTATUS winbind_dual_SamLogon(struct winbindd_domain *domain,
 			authoritative,
 			info3);
 
-		/* 
+		/*
 		 * We need to try the remote NETLOGON server if this is
 		 * not authoritative.
 		 */
-- 
2.13.6


From fc27f9989c053b0c58dd2d4b34632ed4bf43da97 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 11 Dec 2017 16:25:35 +0100
Subject: [PATCH 17/28] winbindd: let winbind_dual_SamLogon return validation

Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 source3/winbindd/winbindd_dual_srv.c | 20 +++++++-
 source3/winbindd/winbindd_pam.c      | 99 ++++++++++++++++++++++++++----------
 source3/winbindd/winbindd_proto.h    |  3 +-
 3 files changed, 92 insertions(+), 30 deletions(-)

diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c
index 81fcf855847..c76531ddb5d 100644
--- a/source3/winbindd/winbindd_dual_srv.c
+++ b/source3/winbindd/winbindd_dual_srv.c
@@ -33,6 +33,8 @@
 #include "../libcli/auth/netlogon_creds_cli.h"
 #include "passdb.h"
 #include "../source4/dsdb/samdb/samdb.h"
+#include "rpc_client/cli_netlogon.h"
+#include "rpc_client/util_netlogon.h"
 
 void _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r)
 {
@@ -868,6 +870,8 @@ NTSTATUS _winbind_SamLogon(struct pipes_struct *p,
 	NTSTATUS status;
 	DATA_BLOB lm_response, nt_response;
 	uint32_t flags = 0;
+	uint16_t validation_level;
+	union netr_Validation *validation = NULL;
 
 	domain = wb_child_domain();
 	if (domain == NULL) {
@@ -896,8 +900,20 @@ NTSTATUS _winbind_SamLogon(struct pipes_struct *p,
 				       &r->out.authoritative,
 				       true,
 				       &flags,
-				       &r->out.validation.sam3);
-	return status;
+				       &validation_level,
+				       &validation);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+	status = map_validation_to_info3(p->mem_ctx,
+					 validation_level,
+					 validation,
+					 &r->out.validation.sam3);
+	TALLOC_FREE(validation);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+	return NT_STATUS_OK;
 }
 
 static WERROR _winbind_LogonControl_REDISCOVER(struct pipes_struct *p,
diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c
index 222dee6bace..56c2d3a7455 100644
--- a/source3/winbindd/winbindd_pam.c
+++ b/source3/winbindd/winbindd_pam.c
@@ -2078,7 +2078,8 @@ NTSTATUS winbind_dual_SamLogon(struct winbindd_domain *domain,
 			       uint8_t *authoritative,
 			       bool skip_sam,
 			       uint32_t *flags,
-			       struct netr_SamInfo3 **info3)
+			       uint16_t *_validation_level,
+			       union netr_Validation **_validation)
 {
 	uint16_t validation_level;
 	union netr_Validation *validation = NULL;
@@ -2096,15 +2097,26 @@ NTSTATUS winbind_dual_SamLogon(struct winbindd_domain *domain,
 	if (!skip_sam && strequal(domain->name, get_global_sam_name())) {
 		DATA_BLOB chal_blob = data_blob_const(
 			chal, 8);
+		struct netr_SamInfo3 *info3 = NULL;
 
 		result = winbindd_dual_auth_passdb(
-			mem_ctx,
+			talloc_tos(),
 			logon_parameters,
 			name_domain, name_user,
 			&chal_blob, &lm_response, &nt_response,
 			false, /* interactive */
 			authoritative,
-			info3);
+			&info3);
+		if (NT_STATUS_IS_OK(result)) {
+			result = map_info3_to_validation(mem_ctx,
+							 info3,
+							 &validation_level,
+							 &validation);
+			TALLOC_FREE(info3);
+			if (!NT_STATUS_IS_OK(result)) {
+				goto done;
+			}
+		}
 
 		/*
 		 * We need to try the remote NETLOGON server if this is
@@ -2136,46 +2148,62 @@ NTSTATUS winbind_dual_SamLogon(struct winbindd_domain *domain,
 		goto done;
 	}
 
-	result = map_validation_to_info3(mem_ctx,
-					 validation_level,
-					 validation,
-					 info3);
-	TALLOC_FREE(validation);
-	if (!NT_STATUS_IS_OK(result)) {
-		return result;
-	}
-
 process_result:
 
 	if (NT_STATUS_IS_OK(result)) {
 		struct dom_sid user_sid;
+		TALLOC_CTX *base_ctx = NULL;
+		struct netr_SamBaseInfo *base_info = NULL;
+		struct netr_SamInfo3 *info3 = NULL;
+
+		switch (validation_level) {
+		case 3:
+			base_ctx = validation->sam3;
+			base_info = &validation->sam3->base;
+			break;
+		case 6:
+			base_ctx = validation->sam6;
+			base_info = &validation->sam6->base;
+			break;
+		default:
+			result = NT_STATUS_INTERNAL_ERROR;
+			goto done;
+		}
 
-		sid_compose(&user_sid, (*info3)->base.domain_sid,
-			    (*info3)->base.rid);
+		sid_compose(&user_sid, base_info->domain_sid, base_info->rid);
 
-		if ((*info3)->base.full_name.string == NULL) {
+		if (base_info->full_name.string == NULL) {
 			struct netr_SamInfo3 *cached_info3;
 
 			cached_info3 = netsamlogon_cache_get(mem_ctx,
 							     &user_sid);
 			if (cached_info3 != NULL &&
-			    cached_info3->base.full_name.string != NULL) {
-				(*info3)->base.full_name.string =
-					talloc_strdup(*info3,
-						      cached_info3->base.full_name.string);
+			    cached_info3->base.full_name.string != NULL)
+			{
+				base_info->full_name.string = talloc_strdup(
+					base_ctx,
+					cached_info3->base.full_name.string);
 			} else {
 
 				/* this might fail so we don't check the return code */
 				wcache_query_user_fullname(domain,
-						*info3,
+						base_ctx,
 						&user_sid,
-						&(*info3)->base.full_name.string);
+						&base_info->full_name.string);
 			}
 		}
 
+		result = map_validation_to_info3(talloc_tos(),
+						 validation_level,
+						 validation,
+						 &info3);
+		if (!NT_STATUS_IS_OK(result)) {
+			goto done;
+		}
 		wcache_invalidate_samlogon(find_domain_from_name(name_domain),
 					   &user_sid);
-		netsamlogon_cache_store(name_user, *info3);
+		netsamlogon_cache_store(name_user, info3);
+		TALLOC_FREE(info3);
 	}
 
 done:
@@ -2192,20 +2220,26 @@ NTSTATUS winbind_dual_SamLogon(struct winbindd_domain *domain,
 	       name_user,
 	       nt_errstr(result)));
 
-	return result;
+	if (!NT_STATUS_IS_OK(result)) {
+		return result;
+	}
+
+	*_validation_level = validation_level;
+	*_validation = validation;
+	return NT_STATUS_OK;
 }
 
 enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
 						 struct winbindd_cli_state *state)
 {
 	NTSTATUS result;
-	struct netr_SamInfo3 *info3 = NULL;
 	const char *name_user = NULL;
 	const char *name_domain = NULL;
 	const char *workstation;
 	uint8_t authoritative = 0;
 	uint32_t flags = 0;
-
+	uint16_t validation_level;
+	union netr_Validation *validation = NULL;
 	DATA_BLOB lm_resp, nt_resp;
 
 	/* This is child-only, so no check for privileged access is needed
@@ -2260,15 +2294,26 @@ enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
 				       &authoritative,
 				       false,
 				       &flags,
-				       &info3);
+				       &validation_level,
+				       &validation);
 	if (!NT_STATUS_IS_OK(result)) {
 		state->response->data.auth.authoritative = authoritative;
 		goto done;
 	}
 
 	if (NT_STATUS_IS_OK(result)) {
-		/* Check if the user is in the right group */
+		struct netr_SamInfo3 *info3 = NULL;
+
+		result = map_validation_to_info3(state->mem_ctx,
+						 validation_level,
+						 validation,
+						 &info3);
+		TALLOC_FREE(validation);
+		if (!NT_STATUS_IS_OK(result)) {
+			goto done;
+		}
 
+		/* Check if the user is in the right group */
 		result = check_info3_in_group(
 			info3,
 			state->request->data.auth_crap.require_membership_of_sid);
diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h
index cf01337aaad..ee8bd6d552d 100644
--- a/source3/winbindd/winbindd_proto.h
+++ b/source3/winbindd/winbindd_proto.h
@@ -430,7 +430,8 @@ NTSTATUS winbind_dual_SamLogon(struct winbindd_domain *domain,
 			       uint8_t *authoritative,
 			       bool skip_sam,
 			       uint32_t *flags,
-			       struct netr_SamInfo3 **info3);
+			       uint16_t *_validation_level,
+			       union netr_Validation **_validation);
 
 /* The following definitions come from winbindd/winbindd_util.c  */
 
-- 
2.13.6


From 415bc5e6b96373738bb5a1c1c63ae9e08c176b81 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Tue, 9 Jan 2018 18:57:53 +0100
Subject: [PATCH 18/28] winbindd: simplify an if condition in
 winbindd_dual_pam_auth

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

diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c
index 56c2d3a7455..3ae4174185d 100644
--- a/source3/winbindd/winbindd_pam.c
+++ b/source3/winbindd/winbindd_pam.c
@@ -1949,13 +1949,11 @@ enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
 
 		result = winbindd_dual_pam_auth_cached(domain, state, &info3);
 
-		if (NT_STATUS_IS_OK(result)) {
-			DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
-			goto process_result;
-		} else {
+		if (!NT_STATUS_IS_OK(result)) {
 			DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result)));
 			goto done;
 		}
+		DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
 	}
 
 process_result:
-- 
2.13.6


From 486c6d92c4f2fc0568a14328dcb815749a8c5084 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sat, 2 Dec 2017 10:27:12 +0100
Subject: [PATCH 19/28] winbindd: pass down validation to append_auth_data()

Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 source3/winbindd/winbindd_pam.c           | 105 ++++++++++++++++++++++--------
 source3/winbindd/winbindd_pam_auth_crap.c |  23 ++++++-
 source3/winbindd/winbindd_proto.h         |   3 +-
 3 files changed, 101 insertions(+), 30 deletions(-)

diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c
index 3ae4174185d..887a4ee6c9c 100644
--- a/source3/winbindd/winbindd_pam.c
+++ b/source3/winbindd/winbindd_pam.c
@@ -851,12 +851,22 @@ bool check_request_flags(uint32_t flags)
 NTSTATUS append_auth_data(TALLOC_CTX *mem_ctx,
 			  struct winbindd_response *resp,
 			  uint32_t request_flags,
-			  struct netr_SamInfo3 *info3,
+			  uint16_t validation_level,
+			  union netr_Validation *validation,
 			  const char *name_domain,
 			  const char *name_user)
 {
+	struct netr_SamInfo3 *info3 = NULL;
 	NTSTATUS result;
 
+	result = map_validation_to_info3(talloc_tos(),
+					 validation_level,
+					 validation,
+					 &info3);
+	if (!NT_STATUS_IS_OK(result)) {
+		return result;
+	}
+
 	if (request_flags & WBFLAG_PAM_USER_SESSION_KEY) {
 		memcpy(resp->data.auth.user_session_key,
 		       info3->base.key.key,
@@ -877,6 +887,7 @@ NTSTATUS append_auth_data(TALLOC_CTX *mem_ctx,
 		if (!NT_STATUS_IS_OK(result)) {
 			DEBUG(10,("Failed to append Unix Username: %s\n",
 				nt_errstr(result)));
+			TALLOC_FREE(info3);
 			return result;
 		}
 	}
@@ -888,6 +899,7 @@ NTSTATUS append_auth_data(TALLOC_CTX *mem_ctx,
 		if (!NT_STATUS_IS_OK(result)) {
 			DEBUG(10,("Failed to append INFO3 (NDR): %s\n",
 				nt_errstr(result)));
+			TALLOC_FREE(info3);
 			return result;
 		}
 	}
@@ -897,6 +909,7 @@ NTSTATUS append_auth_data(TALLOC_CTX *mem_ctx,
 		if (!NT_STATUS_IS_OK(result)) {
 			DEBUG(10,("Failed to append INFO3 (TXT): %s\n",
 				nt_errstr(result)));
+			TALLOC_FREE(info3);
 			return result;
 		}
 	}
@@ -907,10 +920,12 @@ NTSTATUS append_auth_data(TALLOC_CTX *mem_ctx,
 		if (!NT_STATUS_IS_OK(result)) {
 			DEBUG(10,("Failed to append AFS token: %s\n",
 				nt_errstr(result)));
+			TALLOC_FREE(info3);
 			return result;
 		}
 	}
 
+	TALLOC_FREE(info3);
 	return NT_STATUS_OK;
 }
 
@@ -1773,7 +1788,8 @@ enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
 	fstring name_domain, name_user;
 	char *mapped_user;
 	fstring domain_user;
-	struct netr_SamInfo3 *info3 = NULL;
+	uint16_t validation_level;
+	union netr_Validation *validation = NULL;
 	NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
 
 	/* Ensure null termination */
@@ -1829,6 +1845,7 @@ enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
 
 	/* Check for Kerberos authentication */
 	if (domain->online && (state->request->flags & WBFLAG_PAM_KRB5)) {
+		struct netr_SamInfo3 *info3 = NULL;
 
 		result = winbindd_dual_pam_auth_kerberos(domain, state, &info3);
 		/* save for later */
@@ -1837,6 +1854,16 @@ enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
 
 		if (NT_STATUS_IS_OK(result)) {
 			DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
+
+			result = map_info3_to_validation(state->mem_ctx,
+							 info3,
+							 &validation_level,
+							 &validation);
+			TALLOC_FREE(info3);
+			if (!NT_STATUS_IS_OK(result)) {
+				DBG_ERR("map_info3_to_validation failed\n");
+				goto done;
+			}
 			goto process_result;
 		}
 
@@ -1879,8 +1906,6 @@ enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
 sam_logon:
 	/* Check for Samlogon authentication */
 	if (domain->online) {
-		uint16_t validation_level;
-		union netr_Validation *validation = NULL;
 		struct netr_SamBaseInfo *base_info = NULL;
 
 		result = winbindd_dual_pam_auth_samlogon(
@@ -1913,14 +1938,6 @@ enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
 				base_info->user_flags |= LOGON_KRB5_FAIL_CLOCK_SKEW;
 			}
 
-			result = map_validation_to_info3(state->mem_ctx,
-							 validation_level,
-							 validation,
-							 &info3);
-			TALLOC_FREE(validation);
-			if (!NT_STATUS_IS_OK(result)) {
-				goto done;
-			}
 			goto process_result;
 		}
 
@@ -1946,6 +1963,7 @@ enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
 	/* Check for Cached logons */
 	if (!domain->online && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN) &&
 	    lp_winbind_offline_logon()) {
+		struct netr_SamInfo3 *info3 = NULL;
 
 		result = winbindd_dual_pam_auth_cached(domain, state, &info3);
 
@@ -1954,44 +1972,74 @@ enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
 			goto done;
 		}
 		DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
+
+		result = map_info3_to_validation(state->mem_ctx,
+						 info3,
+						 &validation_level,
+						 &validation);
+		TALLOC_FREE(info3);
+		if (!NT_STATUS_IS_OK(result)) {
+			DBG_ERR("map_info3_to_validation failed\n");
+			goto done;
+		}
 	}
 
 process_result:
 
 	if (NT_STATUS_IS_OK(result)) {
-
 		struct dom_sid user_sid;
+		TALLOC_CTX *base_ctx = NULL;
+		struct netr_SamBaseInfo *base_info = NULL;
+		struct netr_SamInfo3 *info3 = NULL;
 
-		/* In all codepaths where result == NT_STATUS_OK info3 must have
-		   been initialized. */
-		if (!info3) {
+		switch (validation_level) {
+		case 3:
+			base_ctx = validation->sam3;
+			base_info = &validation->sam3->base;
+			break;
+		case 6:
+			base_ctx = validation->sam6;
+			base_info = &validation->sam6->base;
+			break;
+		default:
 			result = NT_STATUS_INTERNAL_ERROR;
 			goto done;
 		}
 
-		sid_compose(&user_sid, info3->base.domain_sid,
-			    info3->base.rid);
+		sid_compose(&user_sid, base_info->domain_sid, base_info->rid);
 
-		if (info3->base.full_name.string == NULL) {
+		if (base_info->full_name.string == NULL) {
 			struct netr_SamInfo3 *cached_info3;
 
 			cached_info3 = netsamlogon_cache_get(state->mem_ctx,
 							     &user_sid);
 			if (cached_info3 != NULL &&
 			    cached_info3->base.full_name.string != NULL) {
-				info3->base.full_name.string =
-					talloc_strdup(info3,
-						      cached_info3->base.full_name.string);
+				base_info->full_name.string = talloc_strdup(
+					base_ctx,
+					cached_info3->base.full_name.string);
+				if (base_info->full_name.string == NULL) {
+					result = NT_STATUS_NO_MEMORY;
+					goto done;
+				}
 			} else {
 
 				/* this might fail so we don't check the return code */
 				wcache_query_user_fullname(domain,
-						info3,
+						base_ctx,
 						&user_sid,
-						&info3->base.full_name.string);
+						&base_info->full_name.string);
 			}
 		}
 
+		result = map_validation_to_info3(talloc_tos(),
+						 validation_level,
+						 validation,
+						 &info3);
+		if (!NT_STATUS_IS_OK(result)) {
+			goto done;
+		}
+
 		wcache_invalidate_samlogon(find_domain_from_name(name_domain),
 					   &user_sid);
 		netsamlogon_cache_store(name_user, info3);
@@ -2018,7 +2066,9 @@ enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
 		}
 
 		result = append_auth_data(state->mem_ctx, state->response,
-					  state->request->flags, info3,
+					  state->request->flags,
+					  validation_level,
+					  validation,
 					  name_domain, name_user);
 		if (!NT_STATUS_IS_OK(result)) {
 			goto done;
@@ -2306,7 +2356,6 @@ enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
 						 validation_level,
 						 validation,
 						 &info3);
-		TALLOC_FREE(validation);
 		if (!NT_STATUS_IS_OK(result)) {
 			goto done;
 		}
@@ -2324,7 +2373,9 @@ enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
 		}
 
 		result = append_auth_data(state->mem_ctx, state->response,
-					  state->request->flags, info3,
+					  state->request->flags,
+					  validation_level,
+					  validation,
 					  name_domain, name_user);
 		if (!NT_STATUS_IS_OK(result)) {
 			goto done;
diff --git a/source3/winbindd/winbindd_pam_auth_crap.c b/source3/winbindd/winbindd_pam_auth_crap.c
index cfeafbcfda8..695ee1d0864 100644
--- a/source3/winbindd/winbindd_pam_auth_crap.c
+++ b/source3/winbindd/winbindd_pam_auth_crap.c
@@ -19,6 +19,7 @@
 
 #include "includes.h"
 #include "winbindd.h"
+#include "rpc_client/util_netlogon.h"
 
 struct winbindd_pam_auth_crap_state {
 	struct winbindd_response *response;
@@ -132,8 +133,26 @@ NTSTATUS winbindd_pam_auth_crap_recv(struct tevent_req *req,
 	}
 
 	if (state->flags & WBFLAG_PAM_AUTH_PAC) {
-		return append_auth_data(response, response, state->flags,
-					state->info3, NULL, NULL);
+		uint16_t validation_level;
+		union netr_Validation *validation = NULL;
+
+		status = map_info3_to_validation(talloc_tos(),
+						 state->info3,
+						 &validation_level,
+						 &validation);
+		if (!NT_STATUS_IS_OK(status)) {
+			return status;
+		}
+
+		status = append_auth_data(response,
+					response,
+					state->flags,
+					validation_level,
+					validation,
+					NULL, NULL);
+		TALLOC_FREE(validation);
+		return status;
+
 	}
 
 	*response = *state->response;
diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h
index ee8bd6d552d..8af79324c69 100644
--- a/source3/winbindd/winbindd_proto.h
+++ b/source3/winbindd/winbindd_proto.h
@@ -400,7 +400,8 @@ bool check_request_flags(uint32_t flags);
 NTSTATUS append_auth_data(TALLOC_CTX *mem_ctx,
 			  struct winbindd_response *resp,
 			  uint32_t request_flags,
-			  struct netr_SamInfo3 *info3,
+			  uint16_t validation_level,
+			  union netr_Validation *validation,
 			  const char *name_domain,
 			  const char *name_user);
 uid_t get_uid_from_request(struct winbindd_request *request);
-- 
2.13.6


From db266169805f696dc6d7434cafe30bccb70c2135 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sat, 2 Dec 2017 10:34:15 +0100
Subject: [PATCH 20/28] winbindd: pass validation in append_info3_as_txt

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

diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c
index 887a4ee6c9c..07ce549de4f 100644
--- a/source3/winbindd/winbindd_pam.c
+++ b/source3/winbindd/winbindd_pam.c
@@ -52,10 +52,21 @@
 
 static NTSTATUS append_info3_as_txt(TALLOC_CTX *mem_ctx,
 				    struct winbindd_response *resp,
-				    struct netr_SamInfo3 *info3)
+				    uint16_t validation_level,
+				    union netr_Validation *validation)
 {
+	struct netr_SamInfo3 *info3 = NULL;
 	char *ex;
 	uint32_t i;
+	NTSTATUS status;
+
+	status = map_validation_to_info3(talloc_tos(),
+					 validation_level,
+					 validation,
+					 &info3);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
 
 	resp->data.auth.info3.logon_time =
 		nt_time_to_unix(info3->base.logon_time);
@@ -102,25 +113,37 @@ static NTSTATUS append_info3_as_txt(TALLOC_CTX *mem_ctx,
 		info3->base.logon_domain.string);
 
 	ex = talloc_strdup(mem_ctx, "");
-	NT_STATUS_HAVE_NO_MEMORY(ex);
+	if (ex == NULL) {
+		TALLOC_FREE(info3);
+		return NT_STATUS_NO_MEMORY;
+	}
 
 	for (i=0; i < info3->base.groups.count; i++) {
 		ex = talloc_asprintf_append_buffer(ex, "0x%08X:0x%08X\n",
 						   info3->base.groups.rids[i].rid,
 						   info3->base.groups.rids[i].attributes);
-		NT_STATUS_HAVE_NO_MEMORY(ex);
+		if (ex == NULL) {
+			TALLOC_FREE(info3);
+			return NT_STATUS_NO_MEMORY;
+		}
 	}
 
 	for (i=0; i < info3->sidcount; i++) {
 		char *sid;
 
 		sid = dom_sid_string(mem_ctx, info3->sids[i].sid);
-		NT_STATUS_HAVE_NO_MEMORY(sid);
+		if (sid == NULL) {
+			TALLOC_FREE(info3);
+			return NT_STATUS_NO_MEMORY;
+		}
 
 		ex = talloc_asprintf_append_buffer(ex, "%s:0x%08X\n",
 						   sid,
 						   info3->sids[i].attributes);
-		NT_STATUS_HAVE_NO_MEMORY(ex);
+		if (ex == NULL) {
+			TALLOC_FREE(info3);
+			return NT_STATUS_NO_MEMORY;
+		}
 
 		talloc_free(sid);
 	}
@@ -128,6 +151,7 @@ static NTSTATUS append_info3_as_txt(TALLOC_CTX *mem_ctx,
 	resp->extra_data.data = ex;
 	resp->length += talloc_get_size(ex);
 
+	TALLOC_FREE(info3);
 	return NT_STATUS_OK;
 }
 
@@ -905,7 +929,9 @@ NTSTATUS append_auth_data(TALLOC_CTX *mem_ctx,
 	}
 
 	if (request_flags & WBFLAG_PAM_INFO3_TEXT) {
-		result = append_info3_as_txt(mem_ctx, resp, info3);
+		result = append_info3_as_txt(mem_ctx, resp,
+					     validation_level,
+					     validation);
 		if (!NT_STATUS_IS_OK(result)) {
 			DEBUG(10,("Failed to append INFO3 (TXT): %s\n",
 				nt_errstr(result)));
-- 
2.13.6


From 4b637ed597eb5cd6d5d9ac0877fd426fcbe2d390 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 10 Jan 2018 10:20:46 +0100
Subject: [PATCH 21/28] nsswitch: add "validation_level" and "info6" to
 winbindd_response

Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 nsswitch/winbind_struct_protocol.h | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/nsswitch/winbind_struct_protocol.h b/nsswitch/winbind_struct_protocol.h
index 9100dbcf6ea..3f3ebd0b66d 100644
--- a/nsswitch/winbind_struct_protocol.h
+++ b/nsswitch/winbind_struct_protocol.h
@@ -59,8 +59,9 @@ typedef char fstring[FSTRING_LEN];
  *     removed WINBINDD_GID_TO_SID
  *     removed WINBINDD_UID_TO_SID
  * 29: added "authoritative" to response.data.auth
+ * 30: added "validation_level" and "info6" to response.data.auth
  */
-#define WINBIND_INTERFACE_VERSION 29
+#define WINBIND_INTERFACE_VERSION 30
 
 /* Have to deal with time_t being 4 or 8 bytes due to structure alignment.
    On a 64bit Linux box, we have to support a constant structure size
@@ -434,7 +435,8 @@ struct winbindd_response {
 			fstring krb5ccname;
 			uint32_t reject_reason;
 			uint8_t authoritative;
-			uint8_t padding[3];
+			uint8_t padding[1];
+			uint16_t validation_level;
 			struct policy_settings {
 				uint32_t min_length_password;
 				uint32_t password_history;
@@ -468,6 +470,10 @@ struct winbindd_response {
 				fstring logon_srv;
 				fstring logon_dom;
 			} info3;
+			struct info6_text {
+				fstring dns_domainname;
+				fstring principal_name;
+			} info6;
 			fstring unix_username;
 		} auth;
 		struct {
-- 
2.13.6


From b945a109b762a6463fee14cfc37ef26e66b9c8b4 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Fri, 1 Dec 2017 23:26:33 +0100
Subject: [PATCH 22/28] nsswitch: fill out wbcAuthUserInfo user_principal and
 dns_domain_name from info6

Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 nsswitch/libwbclient/wbc_pam.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/nsswitch/libwbclient/wbc_pam.c b/nsswitch/libwbclient/wbc_pam.c
index c31220ae7eb..e4cd2963012 100644
--- a/nsswitch/libwbclient/wbc_pam.c
+++ b/nsswitch/libwbclient/wbc_pam.c
@@ -100,12 +100,22 @@ static wbcErr wbc_create_auth_info(const struct winbindd_response *resp,
 
 	i->account_name	= strdup(resp->data.auth.info3.user_name);
 	BAIL_ON_PTR_ERROR(i->account_name, wbc_status);
-	i->user_principal= NULL;
+	if (resp->data.auth.validation_level == 6) {
+		i->user_principal = strdup(resp->data.auth.info6.principal_name);
+		BAIL_ON_PTR_ERROR(i->user_principal, wbc_status);
+	} else {
+		i->user_principal = NULL;
+	}
 	i->full_name	= strdup(resp->data.auth.info3.full_name);
 	BAIL_ON_PTR_ERROR(i->full_name, wbc_status);
 	i->domain_name	= strdup(resp->data.auth.info3.logon_dom);
 	BAIL_ON_PTR_ERROR(i->domain_name, wbc_status);
-	i->dns_domain_name= NULL;
+	if (resp->data.auth.validation_level == 6) {
+		i->dns_domain_name = strdup(resp->data.auth.info6.dns_domainname);
+		BAIL_ON_PTR_ERROR(i->dns_domain_name, wbc_status);
+	} else {
+		i->dns_domain_name = NULL;
+	}
 
 	i->acct_flags	= resp->data.auth.info3.acct_flags;
 	memcpy(i->user_session_key,
-- 
2.13.6


From 41dd27476c38b44ad175191129c1b53e6e1f56c1 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sat, 2 Dec 2017 10:34:28 +0100
Subject: [PATCH 23/28] winbindd: set info6 data in append_info3_as_txt

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

diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c
index 07ce549de4f..de3e3f5cc81 100644
--- a/source3/winbindd/winbindd_pam.c
+++ b/source3/winbindd/winbindd_pam.c
@@ -112,6 +112,14 @@ static NTSTATUS append_info3_as_txt(TALLOC_CTX *mem_ctx,
 	fstrcpy(resp->data.auth.info3.logon_dom,
 		info3->base.logon_domain.string);
 
+	resp->data.auth.validation_level = validation_level;
+	if (validation_level == 6) {
+		fstrcpy(resp->data.auth.info6.dns_domainname,
+			validation->sam6->dns_domainname.string);
+		fstrcpy(resp->data.auth.info6.principal_name,
+			validation->sam6->principal_name.string);
+	}
+
 	ex = talloc_strdup(mem_ctx, "");
 	if (ex == NULL) {
 		TALLOC_FREE(info3);
-- 
2.13.6


From 73ccd798075fef440cf622ae5c632f6af8e30261 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Fri, 15 Dec 2017 21:09:15 +0100
Subject: [PATCH 24/28] winbindd: enforce valid SID in
 add_trusted_domain_from_tdc()

It's the callers responsibility to ensure we get a valid SID. Adding
half-baked domains with only partially valid data is a recipe for
desaster.

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

diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c
index 62eff4a563f..cac6ba5373d 100644
--- a/source3/winbindd/winbindd_util.c
+++ b/source3/winbindd/winbindd_util.c
@@ -153,7 +153,8 @@ add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc)
 	const struct dom_sid *sid = &tdc->sid;
 
 	if (is_null_sid(sid)) {
-		sid = NULL;
+		DBG_ERR("Got null SID for domain [%s]\n", domain_name);
+		return NULL;
 	}
 
 	ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
@@ -187,24 +188,12 @@ add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc)
 			}
 		}
 
-		if (sid != NULL) {
-			if (dom_sid_equal(sid, &domain->sid)) {
-				break;
-			}
+		if (dom_sid_equal(sid, &domain->sid)) {
+			break;
 		}
 	}
 
 	if (domain != NULL) {
-		/*
-		 * We found a match on domain->name or
-		 * domain->alt_name. Possibly update the SID
-		 * if the stored SID was the NULL SID
-		 * and return the matching entry.
-		 */
-		if ((sid != NULL)
-		    && dom_sid_equal(&domain->sid, &global_sid_NULL)) {
-			sid_copy( &domain->sid, sid );
-		}
 		return domain;
 	}
 
@@ -244,12 +233,10 @@ add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc)
 	domain->online = is_internal_domain(sid);
 	domain->check_online_timeout = 0;
 	domain->dc_probe_pid = (pid_t)-1;
-	if (sid != NULL) {
-		sid_copy(&domain->sid, sid);
-	}
 	domain->domain_flags = tdc->trust_flags;
 	domain->domain_type = tdc->trust_type;
 	domain->domain_trust_attribs = tdc->trust_attribs;
+	sid_copy(&domain->sid, sid);
 
 	/* Is this our primary domain ? */
 	if (role == ROLE_DOMAIN_MEMBER) {
-- 
2.13.6


From dfcb0d7c9a0b721f6da024678b93c08f23a6fa28 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Fri, 15 Dec 2017 21:13:52 +0100
Subject: [PATCH 25/28] winbindd: only use NetBIOS name when searching domain
 list in add_trusted_domain_from_tdc()

Unique key for domains is the NetBIOS name, period. If the the caller
passes a domain name that matches a different domains DNS name or vice
versa, that is an error. The same applies to SIDs.

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

diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c
index cac6ba5373d..37725cf67fe 100644
--- a/source3/winbindd/winbindd_util.c
+++ b/source3/winbindd/winbindd_util.c
@@ -174,22 +174,58 @@ add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc)
 	/* We can't call domain_list() as this function is called from
 	   init_domain_list() and we'll get stuck in a loop. */
 	for (domain = _domain_list; domain; domain = domain->next) {
-		if (strequal(domain_name, domain->name) ||
-		    strequal(domain_name, domain->alt_name))
-		{
+		if (strequal(domain_name, domain->name)) {
 			break;
 		}
+	}
+
+	if (domain != NULL) {
+		struct winbindd_domain *check_domain = NULL;
+
+		for (check_domain = _domain_list;
+		     check_domain != NULL;
+		     check_domain = check_domain->next)
+		{
+			if (check_domain == domain) {
+				continue;
+			}
 
-		if (alternative_name) {
-			if (strequal(alternative_name, domain->name) ||
-			    strequal(alternative_name, domain->alt_name))
-			{
+			if (dom_sid_equal(&check_domain->sid, sid)) {
 				break;
 			}
 		}
 
-		if (dom_sid_equal(sid, &domain->sid)) {
-			break;
+		if (check_domain != NULL) {
+			DBG_ERR("SID [%s] already used by domain [%s], "
+				"expected [%s]\n",
+				sid_string_dbg(sid), check_domain->name,
+				domain->name);
+			return NULL;
+		}
+	}
+
+	if ((domain != NULL) && (alternative_name != NULL)) {
+		struct winbindd_domain *check_domain = NULL;
+
+		for (check_domain = _domain_list;
+		     check_domain != NULL;
+		     check_domain = check_domain->next)
+		{
+			if (check_domain == domain) {
+				continue;
+			}
+
+			if (strequal(check_domain->alt_name, alternative_name)) {
+				break;
+			}
+		}
+
+		if (check_domain != NULL) {
+			DBG_ERR("DNS name [%s] used by domain [%s], "
+				"expected [%s]\n",
+				alternative_name, check_domain->name,
+				domain->name);
+			return NULL;
 		}
 	}
 
-- 
2.13.6


From 31932b50628aa36ca20383d08ab27860e5457b94 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 10 Jan 2018 12:14:57 +0100
Subject: [PATCH 26/28] winbindd: rename alternative_name to dns_name

This reduces the diff in the following commit.

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

diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c
index 37725cf67fe..0f9690888a8 100644
--- a/source3/winbindd/winbindd_util.c
+++ b/source3/winbindd/winbindd_util.c
@@ -146,7 +146,7 @@ static struct winbindd_domain *
 add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc)
 {
 	struct winbindd_domain *domain;
-	const char *alternative_name = NULL;
+	const char *dns_name = NULL;
 	const char **ignored_domains, **dom;
 	int role = lp_server_role();
 	const char *domain_name = tdc->domain_name;
@@ -168,7 +168,7 @@ add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc)
 	/* use alt_name if available to allow DNS lookups */
 
 	if (tdc->dns_name && *tdc->dns_name) {
-		alternative_name = tdc->dns_name;
+		dns_name = tdc->dns_name;
 	}
 
 	/* We can't call domain_list() as this function is called from
@@ -204,7 +204,7 @@ add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc)
 		}
 	}
 
-	if ((domain != NULL) && (alternative_name != NULL)) {
+	if ((domain != NULL) && (dns_name != NULL)) {
 		struct winbindd_domain *check_domain = NULL;
 
 		for (check_domain = _domain_list;
@@ -215,7 +215,7 @@ add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc)
 				continue;
 			}
 
-			if (strequal(check_domain->alt_name, alternative_name)) {
+			if (strequal(check_domain->alt_name, dns_name)) {
 				break;
 			}
 		}
@@ -223,7 +223,7 @@ add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc)
 		if (check_domain != NULL) {
 			DBG_ERR("DNS name [%s] used by domain [%s], "
 				"expected [%s]\n",
-				alternative_name, check_domain->name,
+				dns_name, check_domain->name,
 				domain->name);
 			return NULL;
 		}
@@ -253,8 +253,8 @@ add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc)
 		return NULL;
 	}
 
-	if (alternative_name) {
-		domain->alt_name = talloc_strdup(domain, alternative_name);
+	if (dns_name != NULL) {
+		domain->alt_name = talloc_strdup(domain, dns_name);
 		if (domain->alt_name == NULL) {
 			TALLOC_FREE(domain);
 			return NULL;
-- 
2.13.6


From 1d08bedb4a52e2e79ed637b4095d7d5a3a7fdbcf Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 10 Jan 2018 12:14:57 +0100
Subject: [PATCH 27/28] winbindd: initialize some stack pointers to NULL

This reduces the diff in the following commit.

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

diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c
index 0f9690888a8..9c602de250a 100644
--- a/source3/winbindd/winbindd_util.c
+++ b/source3/winbindd/winbindd_util.c
@@ -145,9 +145,10 @@ add_trusted_domain(const char *domain_name, const char *alt_name,
 static struct winbindd_domain *
 add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc)
 {
-	struct winbindd_domain *domain;
+	struct winbindd_domain *domain = NULL;
 	const char *dns_name = NULL;
-	const char **ignored_domains, **dom;
+	const char **ignored_domains = NULL;
+	const char **dom = NULL;
 	int role = lp_server_role();
 	const char *domain_name = tdc->domain_name;
 	const struct dom_sid *sid = &tdc->sid;
-- 
2.13.6


From daa3145ea6fca820d3cfa5ef7061b3ffced13bcd Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sat, 16 Dec 2017 11:34:23 +0100
Subject: [PATCH 28/28] winbindd: rework add_trusted_domain(), replacing
 add_trusted_domain_from_tdc()

This extends add_trusted_domain() to be a the one true one-stop function
to add winbindd domain.

add_trusted_domain_from_tdc() used a struct winbindd_tdc_domain to fill
in the winbindd domain which made it hard to track which attributes
would be required and which are optional.

Pair-programmed-with: Stefan Metzmacher <metze at samba.org>

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

diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c
index 9c602de250a..c45d6acb0ad 100644
--- a/source3/winbindd/winbindd_util.c
+++ b/source3/winbindd/winbindd_util.c
@@ -36,9 +36,6 @@
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_WINBIND
 
-static struct winbindd_domain *
-add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc);
-
 /**
  * @file winbindd_util.c
  *
@@ -122,58 +119,36 @@ static bool is_in_internal_domain(const struct dom_sid *sid)
    If the domain already exists in the list,
    return it and don't re-initialize.  */
 
-static struct winbindd_domain *
-add_trusted_domain(const char *domain_name, const char *alt_name,
-		   const struct dom_sid *sid)
-{
-	struct winbindd_tdc_domain tdc;
-
-	ZERO_STRUCT(tdc);
-
-	tdc.domain_name = domain_name;
-	tdc.dns_name = alt_name;
-	if (sid) {
-		sid_copy(&tdc.sid, sid);
-	}
-
-	return add_trusted_domain_from_tdc(&tdc);
-}
-
-/* Add a trusted domain out of a trusted domain cache
-   entry
-*/
-static struct winbindd_domain *
-add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc)
+static NTSTATUS add_trusted_domain(const char *domain_name,
+				   const char *dns_name,
+				   const struct dom_sid *sid,
+				   uint32_t trust_type,
+				   uint32_t trust_flags,
+				   uint32_t trust_attribs,
+				   struct winbindd_domain **_d)
 {
 	struct winbindd_domain *domain = NULL;
-	const char *dns_name = NULL;
 	const char **ignored_domains = NULL;
 	const char **dom = NULL;
 	int role = lp_server_role();
-	const char *domain_name = tdc->domain_name;
-	const struct dom_sid *sid = &tdc->sid;
 
 	if (is_null_sid(sid)) {
 		DBG_ERR("Got null SID for domain [%s]\n", domain_name);
-		return NULL;
+		return NT_STATUS_INVALID_PARAMETER;
 	}
 
 	ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
 	for (dom=ignored_domains; dom && *dom; dom++) {
 		if (gen_fnmatch(*dom, domain_name) == 0) {
 			DEBUG(2,("Ignoring domain '%s'\n", domain_name));
-			return NULL;
+			return NT_STATUS_NO_SUCH_DOMAIN;
 		}
 	}
 
-	/* use alt_name if available to allow DNS lookups */
-
-	if (tdc->dns_name && *tdc->dns_name) {
-		dns_name = tdc->dns_name;
-	}
-
-	/* We can't call domain_list() as this function is called from
-	   init_domain_list() and we'll get stuck in a loop. */
+	/*
+	 * We can't call domain_list() as this function is called from
+	 * init_domain_list() and we'll get stuck in a loop.
+	 */
 	for (domain = _domain_list; domain; domain = domain->next) {
 		if (strequal(domain_name, domain->name)) {
 			break;
@@ -201,7 +176,7 @@ add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc)
 				"expected [%s]\n",
 				sid_string_dbg(sid), check_domain->name,
 				domain->name);
-			return NULL;
+			return NT_STATUS_INVALID_PARAMETER;
 		}
 	}
 
@@ -226,18 +201,19 @@ add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc)
 				"expected [%s]\n",
 				dns_name, check_domain->name,
 				domain->name);
-			return NULL;
+			return NT_STATUS_INVALID_PARAMETER;
 		}
 	}
 
 	if (domain != NULL) {
-		return domain;
+		*_d = domain;
+		return NT_STATUS_OK;
 	}
 
 	/* Create new domain entry */
 	domain = talloc_zero(NULL, struct winbindd_domain);
 	if (domain == NULL) {
-		return NULL;
+		return NT_STATUS_NO_MEMORY;
 	}
 
 	domain->children = talloc_zero_array(domain,
@@ -245,20 +221,20 @@ add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc)
 					     lp_winbind_max_domain_connections());
 	if (domain->children == NULL) {
 		TALLOC_FREE(domain);
-		return NULL;
+		return NT_STATUS_NO_MEMORY;
 	}
 
 	domain->name = talloc_strdup(domain, domain_name);
 	if (domain->name == NULL) {
 		TALLOC_FREE(domain);
-		return NULL;
+		return NT_STATUS_NO_MEMORY;
 	}
 
 	if (dns_name != NULL) {
 		domain->alt_name = talloc_strdup(domain, dns_name);
 		if (domain->alt_name == NULL) {
 			TALLOC_FREE(domain);
-			return NULL;
+			return NT_STATUS_NO_MEMORY;
 		}
 	}
 
@@ -270,9 +246,9 @@ add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc)
 	domain->online = is_internal_domain(sid);
 	domain->check_online_timeout = 0;
 	domain->dc_probe_pid = (pid_t)-1;
-	domain->domain_flags = tdc->trust_flags;
-	domain->domain_type = tdc->trust_type;
-	domain->domain_trust_attribs = tdc->trust_attribs;
+	domain->domain_flags = trust_flags;
+	domain->domain_type = trust_type;
+	domain->domain_trust_attribs = trust_attribs;
 	sid_copy(&domain->sid, sid);
 
 	/* Is this our primary domain ? */
@@ -302,11 +278,12 @@ add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc)
 
 	setup_domain_child(domain);
 
-	DEBUG(2,
-	      ("Added domain %s %s %s\n", domain->name, domain->alt_name,
-	       !is_null_sid(&domain->sid) ? sid_string_dbg(&domain->sid) : ""));
+	DBG_NOTICE("Added domain [%s] [%s] [%s]\n",
+		   domain->name, domain->alt_name,
+		   sid_string_dbg(&domain->sid));
 
-	return domain;
+	*_d = domain;
+	return NT_STATUS_OK;
 }
 
 bool domain_is_forest_root(const struct winbindd_domain *domain)
@@ -362,9 +339,9 @@ static void trustdom_list_done(struct tevent_req *req)
 	struct winbindd_response *response;
 	int res, err;
 	char *p;
-	struct winbindd_tdc_domain trust_params = {0};
 	ptrdiff_t extra_len;
 	bool within_forest = false;
+	NTSTATUS status;
 
 	/*
 	 * Only when we enumerate our primary domain
@@ -398,12 +375,16 @@ static void trustdom_list_done(struct tevent_req *req)
 	p = (char *)response->extra_data.data;
 
 	while ((p - (char *)response->extra_data.data) < extra_len) {
-		char *q, *sidstr, *alt_name;
+		struct winbindd_domain *domain = NULL;
+		char *name, *q, *sidstr, *alt_name;
+		struct dom_sid sid;
+		uint32_t trust_type;
+		uint32_t trust_attribs;
+		uint32_t trust_flags;
 
 		DBG_DEBUG("parsing response line '%s'\n", p);
 
-		ZERO_STRUCT(trust_params);
-		trust_params.domain_name = p;
+		name = p;
 
 		alt_name = strchr(p, '\\');
 		if (alt_name == NULL) {
@@ -424,8 +405,8 @@ static void trustdom_list_done(struct tevent_req *req)
 		sidstr += 1;
 
 		/* use the real alt_name if we have one, else pass in NULL */
-		if (!strequal(alt_name, "(null)")) {
-			trust_params.dns_name = alt_name;
+		if (strequal(alt_name, "(null)")) {
+			alt_name = NULL;
 		}
 
 		q = strtok(sidstr, "\\");
@@ -434,7 +415,7 @@ static void trustdom_list_done(struct tevent_req *req)
 			break;
 		}
 
-		if (!string_to_sid(&trust_params.sid, sidstr)) {
+		if (!string_to_sid(&sid, sidstr)) {
 			DEBUG(0, ("Got invalid trustdom response\n"));
 			break;
 		}
@@ -445,7 +426,7 @@ static void trustdom_list_done(struct tevent_req *req)
 			break;
 		}
 
-		trust_params.trust_flags = (uint32_t)strtoul(q, NULL, 10);
+		trust_flags = (uint32_t)strtoul(q, NULL, 10);
 
 		q = strtok(NULL, "\\");
 		if (q == NULL) {
@@ -453,7 +434,7 @@ static void trustdom_list_done(struct tevent_req *req)
 			break;
 		}
 
-		trust_params.trust_type = (uint32_t)strtoul(q, NULL, 10);
+		trust_type = (uint32_t)strtoul(q, NULL, 10);
 
 		q = strtok(NULL, "\n");
 		if (q == NULL) {
@@ -461,14 +442,14 @@ static void trustdom_list_done(struct tevent_req *req)
 			break;
 		}
 
-		trust_params.trust_attribs = (uint32_t)strtoul(q, NULL, 10);
+		trust_attribs = (uint32_t)strtoul(q, NULL, 10);
 
 		if (!within_forest) {
-			trust_params.trust_flags &= ~NETR_TRUST_FLAG_IN_FOREST;
+			trust_flags &= ~NETR_TRUST_FLAG_IN_FOREST;
 		}
 
 		if (!state->domain->primary) {
-			trust_params.trust_flags &= ~NETR_TRUST_FLAG_PRIMARY;
+			trust_flags &= ~NETR_TRUST_FLAG_PRIMARY;
 		}
 
 		/*
@@ -477,7 +458,20 @@ static void trustdom_list_done(struct tevent_req *req)
 		 * This is important because we need the SID for sibling
 		 * domains.
 		 */
-		(void)add_trusted_domain_from_tdc(&trust_params);
+		status = add_trusted_domain(name,
+					    alt_name,
+					    &sid,
+					    trust_type,
+					    trust_flags,
+					    trust_attribs,
+					    &domain);
+		if (!NT_STATUS_IS_OK(status) &&
+		    !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
+		{
+			DBG_NOTICE("add_trusted_domain returned %s\n",
+				   nt_errstr(status));
+			return;
+		}
 
 		p = q + strlen(q) + 1;
 	}
@@ -520,6 +514,7 @@ static void rescan_forest_root_trusts( void )
 	struct winbindd_tdc_domain *dom_list = NULL;
         size_t num_trusts = 0;
 	int i;
+	NTSTATUS status;
 
 	/* The only transitive trusts supported by Windows 2003 AD are
 	   (a) Parent-Child, (b) Tree-Root, and (c) Forest.   The
@@ -544,11 +539,23 @@ static void rescan_forest_root_trusts( void )
 		/* Here's the forest root */
 
 		d = find_domain_from_name_noinit( dom_list[i].domain_name );
-
-		if ( !d ) {
-			d = add_trusted_domain_from_tdc(&dom_list[i]);
+		if (d == NULL) {
+			status = add_trusted_domain(dom_list[i].domain_name,
+						    dom_list[i].dns_name,
+						    &dom_list[i].sid,
+						    dom_list[i].trust_type,
+						    dom_list[i].trust_flags,
+						    dom_list[i].trust_attribs,
+						    &d);
+
+			if (!NT_STATUS_IS_OK(status) &&
+			    NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
+			{
+				DBG_ERR("add_trusted_domain returned %s\n",
+					nt_errstr(status));
+				return;
+			}
 		}
-
 		if (d == NULL) {
 			continue;
 		}
@@ -582,6 +589,7 @@ static void rescan_forest_trusts( void )
 	struct winbindd_tdc_domain *dom_list = NULL;
         size_t num_trusts = 0;
 	int i;
+	NTSTATUS status;
 
 	/* The only transitive trusts supported by Windows 2003 AD are
 	   (a) Parent-Child, (b) Tree-Root, and (c) Forest.   The
@@ -611,8 +619,23 @@ static void rescan_forest_trusts( void )
 			/* add the trusted domain if we don't know
 			   about it */
 
-			if ( !d ) {
-				d = add_trusted_domain_from_tdc(&dom_list[i]);
+			if (d == NULL) {
+				status = add_trusted_domain(
+					dom_list[i].domain_name,
+					dom_list[i].dns_name,
+					&dom_list[i].sid,
+					type,
+					flags,
+					attribs,
+					&d);
+				if (!NT_STATUS_IS_OK(status) &&
+				    NT_STATUS_EQUAL(status,
+						    NT_STATUS_NO_SUCH_DOMAIN))
+				{
+					DBG_ERR("add_trusted_domain: %s\n",
+						nt_errstr(status));
+					return;
+				}
 			}
 
 			if (d == NULL) {
@@ -716,6 +739,8 @@ static void wb_imsg_new_trusted_domain(struct imessaging_context *msg,
 	struct lsa_TrustDomainInfoInfoEx info;
 	enum ndr_err_code ndr_err;
 	struct winbindd_domain *d = NULL;
+	uint32_t trust_flags = 0;
+	NTSTATUS status;
 
 	DEBUG(5, ("wb_imsg_new_trusted_domain\n"));
 
@@ -737,36 +762,31 @@ static void wb_imsg_new_trusted_domain(struct imessaging_context *msg,
 		return;
 	}
 
-	d = add_trusted_domain(info.netbios_name.string,
-			       info.domain_name.string,
-			       info.sid);
-	if (d == NULL) {
-		TALLOC_FREE(frame);
-		return;
-	}
-
-	if (d->internal) {
-		TALLOC_FREE(frame);
-		return;
-	}
-
-	if (d->primary) {
-		TALLOC_FREE(frame);
-		return;
-	}
-
 	if (info.trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
-		d->domain_flags |= NETR_TRUST_FLAG_INBOUND;
+		trust_flags |= NETR_TRUST_FLAG_INBOUND;
 	}
 	if (info.trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
-		d->domain_flags |= NETR_TRUST_FLAG_OUTBOUND;
+		trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
 	}
 	if (info.trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
-		d->domain_flags |= NETR_TRUST_FLAG_IN_FOREST;
+		trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
+	}
+
+	status = add_trusted_domain(info.netbios_name.string,
+				    info.domain_name.string,
+				    info.sid,
+				    info.trust_type,
+				    trust_flags,
+				    info.trust_attributes,
+				    &d);
+	if (!NT_STATUS_IS_OK(status) &&
+	    !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
+	{
+		DBG_NOTICE("add_trusted_domain returned %s\n",
+			   nt_errstr(status));
+		TALLOC_FREE(frame);
+		return;
 	}
-	d->domain_type = info.trust_type;
-	d->domain_trust_attribs = info.trust_attributes;
-
 	TALLOC_FREE(frame);
 }
 
@@ -818,6 +838,7 @@ bool init_domain_list(void)
 {
 	int role = lp_server_role();
 	struct pdb_domain_info *pdb_domain_info = NULL;
+	struct winbindd_domain *domain =  NULL;
 	NTSTATUS status;
 
 	/* Free existing list */
@@ -825,7 +846,18 @@ bool init_domain_list(void)
 
 	/* BUILTIN domain */
 
-	(void)add_trusted_domain("BUILTIN", NULL, &global_sid_Builtin);
+	status = add_trusted_domain("BUILTIN",
+				    NULL,
+				    &global_sid_Builtin,
+				    LSA_TRUST_TYPE_DOWNLEVEL,
+				    0, /* trust_flags */
+				    0, /* trust_attribs */
+				    &domain);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_ERR("add_trusted_domain BUILTIN returned %s\n",
+			nt_errstr(status));
+		return false;
+	}
 
 	/* Local SAM */
 
@@ -841,7 +873,8 @@ bool init_domain_list(void)
 	pdb_domain_info = pdb_get_domain_info(talloc_tos());
 
 	if ( role == ROLE_ACTIVE_DIRECTORY_DC ) {
-		struct winbindd_domain *domain;
+		uint32_t trust_flags;
+		bool is_root;
 		enum netr_SchannelType sec_chan_type;
 		const char *account_name;
 		struct samr_Password current_nt_hash;
@@ -852,13 +885,29 @@ bool init_domain_list(void)
 				"domain info from sam.ldb\n"));
 			return false;
 		}
-		domain = add_trusted_domain(pdb_domain_info->name,
-					pdb_domain_info->dns_domain,
-					&pdb_domain_info->sid);
+
+		trust_flags = NETR_TRUST_FLAG_PRIMARY;
+		trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
+		trust_flags |= NETR_TRUST_FLAG_NATIVE;
+		trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
+
+		is_root = strequal(pdb_domain_info->dns_domain,
+				   pdb_domain_info->dns_forest);
+		if (is_root) {
+			trust_flags |= NETR_TRUST_FLAG_TREEROOT;
+		}
+
+		status = add_trusted_domain(pdb_domain_info->name,
+					    pdb_domain_info->dns_domain,
+					    &pdb_domain_info->sid,
+					    LSA_TRUST_TYPE_UPLEVEL,
+					    trust_flags,
+					    LSA_TRUST_ATTRIBUTE_WITHIN_FOREST,
+					    &domain);
 		TALLOC_FREE(pdb_domain_info);
-		if (domain == NULL) {
-			DEBUG(0, ("Failed to add our own, local AD "
-				"domain to winbindd's internal list\n"));
+		if (!NT_STATUS_IS_OK(status)) {
+			DBG_ERR("Failed to add our own, local AD "
+				"domain to winbindd's internal list\n");
 			return false;
 		}
 
@@ -902,31 +951,64 @@ bool init_domain_list(void)
 		}
 
 	} else {
-		(void)add_trusted_domain(get_global_sam_name(), NULL,
-					 get_global_sam_sid());
+		uint32_t trust_flags;
+
+		trust_flags = NETR_TRUST_FLAG_OUTBOUND;
+		if (role != ROLE_DOMAIN_MEMBER) {
+			trust_flags |= NETR_TRUST_FLAG_PRIMARY;
+		}
+
+		status = add_trusted_domain(get_global_sam_name(),
+					    NULL,
+					    get_global_sam_sid(),
+					    LSA_TRUST_TYPE_DOWNLEVEL,
+					    trust_flags,
+					    0, /* trust_attribs */
+					    &domain);
+		if (!NT_STATUS_IS_OK(status)) {
+			DBG_ERR("Failed to add local SAM to "
+				"domain to winbindd's internal list\n");
+			return false;
+		}
 	}
 	/* Add ourselves as the first entry. */
 
 	if ( role == ROLE_DOMAIN_MEMBER ) {
-		struct winbindd_domain *domain;
 		struct dom_sid our_sid;
+		uint32_t trust_type;
 
 		if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
 			DEBUG(0, ("Could not fetch our SID - did we join?\n"));
 			return False;
 		}
 
-		domain = add_trusted_domain(lp_workgroup(), lp_realm(),
-					    &our_sid);
-		if (domain) {
-			/* 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);
+		if (lp_realm() != NULL) {
+			trust_type = LSA_TRUST_TYPE_UPLEVEL;
+		} else {
+			trust_type = LSA_TRUST_TYPE_DOWNLEVEL;
+		}
+
+		status = add_trusted_domain(lp_workgroup(),
+					    lp_realm(),
+					    &our_sid,
+					    trust_type,
+					    NETR_TRUST_FLAG_PRIMARY|
+					    NETR_TRUST_FLAG_OUTBOUND,
+					    0, /* trust_attribs */
+					    &domain);
+		if (!NT_STATUS_IS_OK(status)) {
+			DBG_ERR("Failed to add local SAM to "
+				"domain to winbindd's internal list\n");
+			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,
-- 
2.13.6



More information about the samba-technical mailing list