[Patches Part1] winbindd changes the local password and gets NT_STATUS_WRONG_PASSWORD for the remote change (bug #12782)

Stefan Metzmacher metze at samba.org
Mon Jun 26 06:18:55 UTC 2017


Hi,

here're preparation patches in order to fix
https://bugzilla.samba.org/show_bug.cgi?id=12782
winbindd changes the local password and gets NT_STATUS_WRONG_PASSWORD
for the remote change

Most patches are already review by Andreas, I guess he'll do the rest
also todays.

Part2 with the fix will follow.

metze
-------------- next part --------------
From 27860e65ddf89c86b066d1109866ff389471ab11 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 12 Jun 2017 18:58:49 +0200
Subject: [PATCH 01/44] pidl:NDR/Parser: add missing {start,end}_flags() to
 ParseElementPrint()

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm b/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm
index 7a73126..6739b5f 100644
--- a/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm
+++ b/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm
@@ -848,8 +848,10 @@ sub ParseElementPrint($$$$$)
 	my $cur_depth = 0;
 	my $ignore_depth = 0xFFFF;
 
+	$self->start_flags($e, $ndr);
 	if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE}) {
 		$self->pidl("ndr_print_$e->{REPRESENTATION_TYPE}($ndr, \"$e->{NAME}\", $var_name);");
+		$self->end_flags($e, $ndr);
 		return;
 	}
 
@@ -944,6 +946,8 @@ sub ParseElementPrint($$$$$)
 			$self->pidl("$ndr->depth--;");
 		}
 	}
+
+	$self->end_flags($e, $ndr);
 }
 
 #####################################################################
-- 
1.9.1


From e8fc751ef3ba2307147da5977621535eb08465fe Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 12 Jun 2017 15:22:42 +0200
Subject: [PATCH 02/44] librpc/ndr: align the definition of LIBNDR_STRING_FLAGS
 with currently defined flags

The range included the unused (1<<14) before.

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 librpc/ndr/libndr.h | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/librpc/ndr/libndr.h b/librpc/ndr/libndr.h
index d6e2e37..049a35f 100644
--- a/librpc/ndr/libndr.h
+++ b/librpc/ndr/libndr.h
@@ -125,7 +125,19 @@ struct ndr_print {
 #define LIBNDR_FLAG_STR_CHARLEN		(1<<11)
 #define LIBNDR_FLAG_STR_UTF8		(1<<12)
 #define LIBNDR_FLAG_STR_RAW8		(1<<13)
-#define LIBNDR_STRING_FLAGS		(0x7FFC)
+#define LIBNDR_STRING_FLAGS		(0 | \
+		LIBNDR_FLAG_STR_ASCII | \
+		LIBNDR_FLAG_STR_LEN4 | \
+		LIBNDR_FLAG_STR_SIZE4 | \
+		LIBNDR_FLAG_STR_NOTERM | \
+		LIBNDR_FLAG_STR_NULLTERM | \
+		LIBNDR_FLAG_STR_SIZE2 | \
+		LIBNDR_FLAG_STR_BYTESIZE | \
+		LIBNDR_FLAG_STR_CONFORMANT | \
+		LIBNDR_FLAG_STR_CHARLEN | \
+		LIBNDR_FLAG_STR_UTF8 | \
+		LIBNDR_FLAG_STR_RAW8 | \
+		0)
 
 /* Disable string token compression  */
 #define LIBNDR_FLAG_NO_COMPRESSION	(1<<15)
-- 
1.9.1


From 91366809015531a4d2172ee369798c2387760db3 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 12 Jun 2017 17:58:20 +0200
Subject: [PATCH 03/44] librpc/ndr: add LIBNDR_FLAG_IS_SECRET handling

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 librpc/ndr/libndr.h    | 10 ++++++++++
 librpc/ndr/ndr.c       | 23 +++++++++++++++++++++++
 librpc/ndr/ndr_basic.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 77 insertions(+)

diff --git a/librpc/ndr/libndr.h b/librpc/ndr/libndr.h
index 049a35f..072fd66 100644
--- a/librpc/ndr/libndr.h
+++ b/librpc/ndr/libndr.h
@@ -109,6 +109,7 @@ struct ndr_print {
 	void (*print)(struct ndr_print *, const char *, ...) PRINTF_ATTRIBUTE(2,3);
 	void *private_data;
 	bool no_newline;
+	bool print_secrets;
 };
 
 #define LIBNDR_FLAG_BIGENDIAN  (1<<0)
@@ -139,6 +140,12 @@ struct ndr_print {
 		LIBNDR_FLAG_STR_RAW8 | \
 		0)
 
+/*
+ * Mark an element as SECRET, it won't be printed by
+ * via ndr_print* unless NDR_PRINT_SECRETS is specified.
+ */
+#define LIBNDR_FLAG_IS_SECRET		(1<<14)
+
 /* Disable string token compression  */
 #define LIBNDR_FLAG_NO_COMPRESSION	(1<<15)
 
@@ -210,6 +217,9 @@ struct ndr_print {
 #define NDR_PRINT_OUT_STRING(ctx, type, p) NDR_PRINT_FUNCTION_STRING(ctx, type, NDR_OUT, p)
 #define NDR_PRINT_IN_STRING(ctx, type, p) NDR_PRINT_FUNCTION_STRING(ctx, type, NDR_IN | NDR_SET_VALUES, p)
 
+#define NDR_HIDE_SECRET(ndr) \
+	(unlikely(((ndr)->flags & LIBNDR_FLAG_IS_SECRET) && !(ndr)->print_secrets))
+
 #define NDR_BE(ndr) (unlikely(((ndr)->flags & (LIBNDR_FLAG_BIGENDIAN|LIBNDR_FLAG_LITTLE_ENDIAN)) == LIBNDR_FLAG_BIGENDIAN))
 
 enum ndr_err_code {
diff --git a/librpc/ndr/ndr.c b/librpc/ndr/ndr.c
index 1c49c9a..0f55cf9 100644
--- a/librpc/ndr/ndr.c
+++ b/librpc/ndr/ndr.c
@@ -399,6 +399,12 @@ _PUBLIC_ void ndr_print_debugc(int dbgc_class, ndr_print_fn_t fn, const char *na
 	ndr->print = ndr_print_debugc_helper;
 	ndr->depth = 1;
 	ndr->flags = 0;
+#ifdef DEBUG_PASSWORD
+	if (CHECK_DEBUGLVL(100)) {
+		ndr->print_secrets = true;
+	}
+#endif
+
 	fn(ndr, name, ptr);
 	talloc_free(ndr);
 }
@@ -417,6 +423,12 @@ _PUBLIC_ void ndr_print_debug(ndr_print_fn_t fn, const char *name, void *ptr)
 	ndr->print = ndr_print_debug_helper;
 	ndr->depth = 1;
 	ndr->flags = 0;
+#ifdef DEBUG_PASSWORD
+	if (CHECK_DEBUGLVL(100)) {
+		ndr->print_secrets = true;
+	}
+#endif
+
 	fn(ndr, name, ptr);
 	talloc_free(ndr);
 }
@@ -435,6 +447,12 @@ _PUBLIC_ void ndr_print_union_debug(ndr_print_fn_t fn, const char *name, uint32_
 	ndr->print = ndr_print_debug_helper;
 	ndr->depth = 1;
 	ndr->flags = 0;
+#ifdef DEBUG_PASSWORD
+	if (CHECK_DEBUGLVL(100)) {
+		ndr->print_secrets = true;
+	}
+#endif
+
 	ndr_print_set_switch_value(ndr, ptr, level);
 	fn(ndr, name, ptr);
 	talloc_free(ndr);
@@ -454,6 +472,11 @@ _PUBLIC_ void ndr_print_function_debug(ndr_print_function_t fn, const char *name
 	ndr->print = ndr_print_debug_helper;
 	ndr->depth = 1;
 	ndr->flags = 0;
+#ifdef DEBUG_PASSWORD
+	if (CHECK_DEBUGLVL(100)) {
+		ndr->print_secrets = true;
+	}
+#endif
 
 	fn(ndr, name, flags, ptr);
 	talloc_free(ndr);
diff --git a/librpc/ndr/ndr_basic.c b/librpc/ndr/ndr_basic.c
index b532cc5..c874f34 100644
--- a/librpc/ndr/ndr_basic.c
+++ b/librpc/ndr/ndr_basic.c
@@ -1064,41 +1064,73 @@ _PUBLIC_ void ndr_print_bitmap_flag(struct ndr_print *ndr, size_t size, const ch
 
 _PUBLIC_ void ndr_print_int8(struct ndr_print *ndr, const char *name, int8_t v)
 {
+	if (NDR_HIDE_SECRET(ndr)) {
+		ndr->print(ndr, "%-25s: <REDACTED SECRET VALUE>", name);
+		return;
+	}
 	ndr->print(ndr, "%-25s: %d", name, v);
 }
 
 _PUBLIC_ void ndr_print_uint8(struct ndr_print *ndr, const char *name, uint8_t v)
 {
+	if (NDR_HIDE_SECRET(ndr)) {
+		ndr->print(ndr, "%-25s: <REDACTED SECRET VALUE>", name);
+		return;
+	}
 	ndr->print(ndr, "%-25s: 0x%02x (%u)", name, v, v);
 }
 
 _PUBLIC_ void ndr_print_int16(struct ndr_print *ndr, const char *name, int16_t v)
 {
+	if (NDR_HIDE_SECRET(ndr)) {
+		ndr->print(ndr, "%-25s: <REDACTED SECRET VALUE>", name);
+		return;
+	}
 	ndr->print(ndr, "%-25s: %d", name, v);
 }
 
 _PUBLIC_ void ndr_print_uint16(struct ndr_print *ndr, const char *name, uint16_t v)
 {
+	if (NDR_HIDE_SECRET(ndr)) {
+		ndr->print(ndr, "%-25s: <REDACTED SECRET VALUE>", name);
+		return;
+	}
 	ndr->print(ndr, "%-25s: 0x%04x (%u)", name, v, v);
 }
 
 _PUBLIC_ void ndr_print_int32(struct ndr_print *ndr, const char *name, int32_t v)
 {
+	if (NDR_HIDE_SECRET(ndr)) {
+		ndr->print(ndr, "%-25s: <REDACTED SECRET VALUE>", name);
+		return;
+	}
 	ndr->print(ndr, "%-25s: %d", name, v);
 }
 
 _PUBLIC_ void ndr_print_uint32(struct ndr_print *ndr, const char *name, uint32_t v)
 {
+	if (NDR_HIDE_SECRET(ndr)) {
+		ndr->print(ndr, "%-25s: <REDACTED SECRET VALUE>", name);
+		return;
+	}
 	ndr->print(ndr, "%-25s: 0x%08x (%u)", name, v, v);
 }
 
 _PUBLIC_ void ndr_print_int3264(struct ndr_print *ndr, const char *name, int32_t v)
 {
+	if (NDR_HIDE_SECRET(ndr)) {
+		ndr->print(ndr, "%-25s: <REDACTED SECRET VALUE>", name);
+		return;
+	}
 	ndr->print(ndr, "%-25s: %d", name, v);
 }
 
 _PUBLIC_ void ndr_print_uint3264(struct ndr_print *ndr, const char *name, uint32_t v)
 {
+	if (NDR_HIDE_SECRET(ndr)) {
+		ndr->print(ndr, "%-25s: <REDACTED SECRET VALUE>", name);
+		return;
+	}
 	ndr->print(ndr, "%-25s: 0x%08x (%u)", name, v, v);
 }
 
@@ -1114,6 +1146,10 @@ _PUBLIC_ void ndr_print_udlongr(struct ndr_print *ndr, const char *name, uint64_
 
 _PUBLIC_ void ndr_print_dlong(struct ndr_print *ndr, const char *name, int64_t v)
 {
+	if (NDR_HIDE_SECRET(ndr)) {
+		ndr->print(ndr, "%-25s: <REDACTED SECRET VALUE>", name);
+		return;
+	}
 	ndr->print(ndr, "%-25s: 0x%016llx (%lld)", name, (unsigned long long)v, (long long)v);
 }
 
@@ -1203,6 +1239,11 @@ _PUBLIC_ void ndr_print_array_uint8(struct ndr_print *ndr, const char *name,
 		return;
 	}
 
+	if (NDR_HIDE_SECRET(ndr)) {
+		ndr->print(ndr, "%s: ARRAY(%d): <REDACTED SECRET VALUES>", name, count);
+		return;
+	}
+
 	if (count <= _ONELINE_LIMIT && (ndr->flags & LIBNDR_PRINT_ARRAY_HEX)) {
 		char s[(_ONELINE_LIMIT + 1) * 2];
 		for (i=0;i<count;i++) {
@@ -1243,6 +1284,9 @@ static void ndr_print_dump_data_cb(const char *buf, void *private_data)
  */
 static void ndr_dump_data(struct ndr_print *ndr, const uint8_t *buf, int len)
 {
+	if (NDR_HIDE_SECRET(ndr)) {
+		return;
+	}
 	ndr->no_newline = true;
 	dump_data_cb(buf, len, true, ndr_print_dump_data_cb, ndr);
 	ndr->no_newline = false;
-- 
1.9.1


From 67945d309b04297306806840f1a7af0e09b20ecf Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 12 Jun 2017 17:58:46 +0200
Subject: [PATCH 04/44] idl_types.h: add NDR_SECRET shortcut

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 librpc/idl/idl_types.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/librpc/idl/idl_types.h b/librpc/idl/idl_types.h
index 72a5d85..2d063de 100644
--- a/librpc/idl/idl_types.h
+++ b/librpc/idl/idl_types.h
@@ -52,6 +52,12 @@
 */
 #define NDR_PAHEX LIBNDR_PRINT_ARRAY_HEX
 
+/*
+ * Mark an element as SECRET, it won't be printed by
+ * via ndr_print* unless NDR_PRINT_SECRETS is specified.
+ */
+#define NDR_SECRET LIBNDR_FLAG_IS_SECRET
+
 #define NDR_RELATIVE_REVERSE LIBNDR_FLAG_RELATIVE_REVERSE
 #define NDR_NO_RELATIVE_REVERSE LIBNDR_FLAG_NO_RELATIVE_REVERSE
 
-- 
1.9.1


From 27ae9633681b503209b664961a35b70f3fdb006c Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 17 May 2017 15:05:51 +0200
Subject: [PATCH 05/44] s3:librpc: let NDR_SECRETS depend on NDR_SECURITY

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/librpc/wscript_build | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source3/librpc/wscript_build b/source3/librpc/wscript_build
index 2445859..1d8c17b 100644
--- a/source3/librpc/wscript_build
+++ b/source3/librpc/wscript_build
@@ -27,7 +27,7 @@ bld.SAMBA3_SUBSYSTEM('NDR_LEASES_DB',
 
 bld.SAMBA3_SUBSYSTEM('NDR_SECRETS',
 	source='gen_ndr/ndr_secrets.c',
-	public_deps='ndr'
+	public_deps='ndr NDR_SECURITY'
 	)
 
 bld.SAMBA3_SUBSYSTEM('NDR_PERFCOUNT',
-- 
1.9.1


From dc6cbbd924b28b03fd37d6a39d4a4b0e53c376a4 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 17 May 2017 16:13:37 +0200
Subject: [PATCH 06/44] s3:libads: remove unused
 kerberos_secrets_store_salting_principal()

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/libads/kerberos.c       | 72 -----------------------------------------
 source3/libads/kerberos_proto.h |  3 --
 2 files changed, 75 deletions(-)

diff --git a/source3/libads/kerberos.c b/source3/libads/kerberos.c
index 13c48ca..b4bd768 100644
--- a/source3/libads/kerberos.c
+++ b/source3/libads/kerberos.c
@@ -434,78 +434,6 @@ int create_kerberos_key_from_string(krb5_context context,
 }
 
 /************************************************************************
- Routine to set the salting principal for this service.  Active
- Directory may use a non-obvious principal name to generate the salt
- when it determines the key to use for encrypting tickets for a service,
- and hopefully we detected that when we joined the domain.
- Setting principal to NULL deletes this entry.
- ************************************************************************/
-
-bool kerberos_secrets_store_salting_principal(const char *service,
-					      int enctype,
-					      const char *principal)
-{
-	char *key = NULL;
-	bool ret = False;
-	krb5_context context = NULL;
-	krb5_principal princ = NULL;
-	char *princ_s = NULL;
-	char *unparsed_name = NULL;
-	krb5_error_code code;
-
-	if (((code = krb5_init_context(&context)) != 0) || (context == NULL)) {
-		DEBUG(5, ("kerberos_secrets_store_salting_pricipal: kdb5_init_context failed: %s\n",
-			  error_message(code)));
-		return False;
-	}
-	if (strchr_m(service, '@')) {
-		if (asprintf(&princ_s, "%s", service) == -1) {
-			goto out;
-		}
-	} else {
-		if (asprintf(&princ_s, "%s@%s", service, lp_realm()) == -1) {
-			goto out;
-		}
-	}
-
-	if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
-		goto out;
-	}
-	if (smb_krb5_unparse_name(talloc_tos(), context, princ, &unparsed_name) != 0) {
-		goto out;
-	}
-
-	if (asprintf(&key, "%s/%s/enctype=%d",
-		     SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype)
-	    == -1) {
-		goto out;
-	}
-
-	if ((principal != NULL) && (strlen(principal) > 0)) {
-		ret = secrets_store(key, principal, strlen(principal) + 1);
-	} else {
-		ret = secrets_delete(key);
-	}
-
- out:
-
-	SAFE_FREE(key);
-	SAFE_FREE(princ_s);
-	TALLOC_FREE(unparsed_name);
-
-	if (princ) {
-		krb5_free_principal(context, princ);
-	}
-
-	if (context) {
-		krb5_free_context(context);
-	}
-
-	return ret;
-}
-
-
-/************************************************************************
 ************************************************************************/
 
 int kerberos_kinit_password(const char *principal,
diff --git a/source3/libads/kerberos_proto.h b/source3/libads/kerberos_proto.h
index 7c56672..8917d63 100644
--- a/source3/libads/kerberos_proto.h
+++ b/source3/libads/kerberos_proto.h
@@ -62,9 +62,6 @@ char *kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
 					       const char *host_princ_s,
 					       int enctype);
 
-bool kerberos_secrets_store_salting_principal(const char *service,
-					      int enctype,
-					      const char *principal);
 int kerberos_kinit_password(const char *principal,
 			    const char *password,
 			    int time_offset,
-- 
1.9.1


From 7d3ecdbbc340af6028202630c20cacf1c207b9ec Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 17 May 2017 17:13:02 +0200
Subject: [PATCH 07/44] krb5_wrap: add smb_krb5_salt_principal()

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 lib/krb5_wrap/krb5_samba.c | 120 +++++++++++++++++++++++++++++++++++++++++++++
 lib/krb5_wrap/krb5_samba.h |   6 +++
 2 files changed, 126 insertions(+)

diff --git a/lib/krb5_wrap/krb5_samba.c b/lib/krb5_wrap/krb5_samba.c
index 0c8b402..15322172 100644
--- a/lib/krb5_wrap/krb5_samba.c
+++ b/lib/krb5_wrap/krb5_samba.c
@@ -422,6 +422,126 @@ int smb_krb5_get_pw_salt(krb5_context context,
 #error UNKNOWN_SALT_FUNCTIONS
 #endif
 
+/**
+ * @brief This constructs the salt principal used by active directory
+ *
+ * Most Kerberos encryption types require a salt in order to
+ * calculate the long term private key for user/computer object
+ * based on a password.
+ *
+ * The returned _salt_principal is a string in forms like this:
+ * - host/somehost.example.com at EXAMPLE.COM
+ * - SomeAccount at EXAMPLE.COM
+ * - SomePrincipal at EXAMPLE.COM
+ *
+ * This is not the form that's used as salt, it's just
+ * the human readable form.
+ *
+ * @param[in]  realm              The realm the user/computer is added too.
+ *
+ * @param[in]  sAMAccountName     The sAMAccountName attribute of the object.
+ *
+ * @param[in]  userPrincipalName  The userPrincipalName attribute of the object
+ *                                or NULL is not available.
+ *
+ * @param[in]  is_computer        The indication of the object includes
+ *                                objectClass=computer.
+ *
+ * @param[in]  mem_ctx            The TALLOC_CTX to allocate _salt_principal.
+ *
+ * @param[out]  _salt_principal   The resulting principal as string.
+ *
+ * @retval 0 Success; otherwise - Kerberos error codes
+ */
+int smb_krb5_salt_principal(const char *realm,
+			    const char *sAMAccountName,
+			    const char *userPrincipalName,
+			    bool is_computer,
+			    TALLOC_CTX *mem_ctx,
+			    char **_salt_principal)
+{
+	TALLOC_CTX *frame = talloc_stackframe();
+	char *upper_realm = NULL;
+	const char *principal = NULL;
+	int principal_len = 0;
+
+	*_salt_principal = NULL;
+
+	if (sAMAccountName == NULL) {
+		TALLOC_FREE(frame);
+		return EINVAL;
+	}
+
+	if (realm == NULL) {
+		TALLOC_FREE(frame);
+		return EINVAL;
+	}
+
+	upper_realm = strupper_talloc(frame, realm);
+	if (upper_realm == NULL) {
+		TALLOC_FREE(frame);
+		return ENOMEM;
+	}
+
+	/* Many, many thanks to lukeh at padl.com for this
+	 * algorithm, described in his Nov 10 2004 mail to
+	 * samba-technical at lists.samba.org */
+
+	/*
+	 * Determine a salting principal
+	 */
+	if (is_computer) {
+		int computer_len = 0;
+		char *tmp = NULL;
+
+		computer_len = strlen(sAMAccountName);
+		if (sAMAccountName[computer_len-1] == '$') {
+			computer_len -= 1;
+		}
+
+		tmp = talloc_asprintf(frame, "host/%*.*s.%s",
+				      computer_len, computer_len,
+				      sAMAccountName, realm);
+		if (tmp == NULL) {
+			TALLOC_FREE(frame);
+			return ENOMEM;
+		}
+
+		principal = strlower_talloc(frame, tmp);
+		TALLOC_FREE(tmp);
+		if (principal == NULL) {
+			TALLOC_FREE(frame);
+			return ENOMEM;
+		}
+		principal_len = strlen(principal);
+
+	} else if (userPrincipalName != NULL) {
+		char *p;
+
+		principal = userPrincipalName;
+		p = strchr(principal, '@');
+		if (p != NULL) {
+			principal_len = PTR_DIFF(p, principal);
+		} else {
+			principal_len = strlen(principal);
+		}
+	} else {
+		principal = sAMAccountName;
+		principal_len = strlen(principal);
+	}
+
+	*_salt_principal = talloc_asprintf(mem_ctx, "%*.*s@%s",
+					   principal_len, principal_len,
+					   principal, upper_realm);
+	if (*_salt_principal == NULL) {
+		TALLOC_FREE(frame);
+		return ENOMEM;
+	}
+
+	TALLOC_FREE(frame);
+	return 0;
+}
+
 #if defined(HAVE_KRB5_GET_PERMITTED_ENCTYPES)
 /**
  * @brief Get a list of encryption types allowed for session keys
diff --git a/lib/krb5_wrap/krb5_samba.h b/lib/krb5_wrap/krb5_samba.h
index 6927349..daaae3f 100644
--- a/lib/krb5_wrap/krb5_samba.h
+++ b/lib/krb5_wrap/krb5_samba.h
@@ -350,6 +350,12 @@ krb5_error_code ms_suptypes_to_ietf_enctypes(TALLOC_CTX *mem_ctx,
 int smb_krb5_get_pw_salt(krb5_context context,
 			 krb5_const_principal host_princ,
 			 krb5_data *psalt);
+int smb_krb5_salt_principal(const char *realm,
+			    const char *sAMAccountName,
+			    const char *userPrincipalName,
+			    bool is_computer,
+			    TALLOC_CTX *mem_ctx,
+			    char **_salt_principal);
 
 int smb_krb5_create_key_from_string(krb5_context context,
 				    krb5_const_principal host_princ,
-- 
1.9.1


From 721a048bd9f1fe2dedb57b5b10dc88a05e894ebe Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 18 May 2017 11:32:46 +0200
Subject: [PATCH 08/44] krb5_wrap: add smb_krb5_salt_principal2data()

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 lib/krb5_wrap/krb5_samba.c | 69 +++++++++++++++++++++++++++++++++++++++++++++-
 lib/krb5_wrap/krb5_samba.h |  4 +++
 2 files changed, 72 insertions(+), 1 deletion(-)

diff --git a/lib/krb5_wrap/krb5_samba.c b/lib/krb5_wrap/krb5_samba.c
index 15322172..fcde9f5 100644
--- a/lib/krb5_wrap/krb5_samba.c
+++ b/lib/krb5_wrap/krb5_samba.c
@@ -435,7 +435,8 @@ int smb_krb5_get_pw_salt(krb5_context context,
  * - SomePrincipal at EXAMPLE.COM
  *
  * This is not the form that's used as salt, it's just
- * the human readable form.
+ * the human readable form. It needs to be converted by
+ * smb_krb5_salt_principal2data().
  *
  * @param[in]  realm              The realm the user/computer is added too.
  *
@@ -452,6 +453,8 @@ int smb_krb5_get_pw_salt(krb5_context context,
  * @param[out]  _salt_principal   The resulting principal as string.
  *
  * @retval 0 Success; otherwise - Kerberos error codes
+ *
+ * @see smb_krb5_salt_principal2data
  */
 int smb_krb5_salt_principal(const char *realm,
 			    const char *sAMAccountName,
@@ -542,6 +545,70 @@ int smb_krb5_salt_principal(const char *realm,
 	return 0;
 }
 
+/**
+ * @brief Converts the salt principal string into the salt data blob
+ *
+ * This function takes a salt_principal as string in forms like this:
+ * - host/somehost.example.com at EXAMPLE.COM
+ * - SomeAccount at EXAMPLE.COM
+ * - SomePrincipal at EXAMPLE.COM
+ *
+ * It generates values like:
+ * - EXAMPLE.COMhost/somehost.example.com
+ * - EXAMPLE.COMSomeAccount
+ * - EXAMPLE.COMSomePrincipal
+ *
+ * @param[in]  realm              The realm the user/computer is added too.
+ *
+ * @param[in]  sAMAccountName     The sAMAccountName attribute of the object.
+ *
+ * @param[in]  userPrincipalName  The userPrincipalName attribute of the object
+ *                                or NULL is not available.
+ *
+ * @param[in]  is_computer        The indication of the object includes
+ *                                objectClass=computer.
+ *
+ * @param[in]  mem_ctx            The TALLOC_CTX to allocate _salt_principal.
+ *
+ * @param[out]  _salt_principal   The resulting principal as string.
+ *
+ * @retval 0 Success; otherwise - Kerberos error codes
+ *
+ * @see smb_krb5_salt_principal
+ */
+int smb_krb5_salt_principal2data(krb5_context context,
+				 const char *salt_principal,
+				 TALLOC_CTX *mem_ctx,
+				 char **_salt_data)
+{
+	krb5_error_code ret;
+	krb5_principal salt_princ = NULL;
+	krb5_data salt;
+
+	*_salt_data = NULL;
+
+	ret = krb5_parse_name(context, salt_principal, &salt_princ);
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = smb_krb5_get_pw_salt(context, salt_princ, &salt);
+	krb5_free_principal(context, salt_princ);
+	if (ret != 0) {
+		return ret;
+	}
+
+	*_salt_data = talloc_strndup(mem_ctx,
+				     (char *)salt.data,
+				     salt.length);
+	smb_krb5_free_data_contents(context, &salt);
+	if (*_salt_data == NULL) {
+		return ENOMEM;
+	}
+
+	return 0;
+}
+
 #if defined(HAVE_KRB5_GET_PERMITTED_ENCTYPES)
 /**
  * @brief Get a list of encryption types allowed for session keys
diff --git a/lib/krb5_wrap/krb5_samba.h b/lib/krb5_wrap/krb5_samba.h
index daaae3f..315d3c3 100644
--- a/lib/krb5_wrap/krb5_samba.h
+++ b/lib/krb5_wrap/krb5_samba.h
@@ -356,6 +356,10 @@ int smb_krb5_salt_principal(const char *realm,
 			    bool is_computer,
 			    TALLOC_CTX *mem_ctx,
 			    char **_salt_principal);
+int smb_krb5_salt_principal2data(krb5_context context,
+				 const char *salt_principal,
+				 TALLOC_CTX *mem_ctx,
+				 char **_salt_data);
 
 int smb_krb5_create_key_from_string(krb5_context context,
 				    krb5_const_principal host_princ,
-- 
1.9.1


From ca8203f8e404a236dbffc8d21f71dae9539bcfc8 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 17 May 2017 12:42:04 +0200
Subject: [PATCH 09/44] s3:libnet_join: remove dead code from
 libnet_join_connect_ads()

username[strlen(username)] is *always* '\0'!

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/libnet/libnet_join.c | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
index 4d00ef6..e33c383 100644
--- a/source3/libnet/libnet_join.c
+++ b/source3/libnet/libnet_join.c
@@ -195,16 +195,11 @@ static ADS_STATUS libnet_join_connect_ads(TALLOC_CTX *mem_ctx,
 		    r->in.machine_password == NULL) {
 			return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
 		}
-		username = talloc_strdup(mem_ctx, r->in.machine_name);
+		username = talloc_asprintf(mem_ctx, "%s$",
+					   r->in.machine_name);
 		if (username == NULL) {
 			return ADS_ERROR(LDAP_NO_MEMORY);
 		}
-		if (username[strlen(username)] != '$') {
-			username = talloc_asprintf(username, "%s$", username);
-			if (username == NULL) {
-				return ADS_ERROR(LDAP_NO_MEMORY);
-			}
-		}
 		password = r->in.machine_password;
 		ccname = "MEMORY:libnet_join_machine_creds";
 	} else {
-- 
1.9.1


From 7b3371cb2ff06ae86277c9baf988a405ba7dc4e7 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 17 May 2017 13:53:19 +0200
Subject: [PATCH 10/44] s3:libnet_join: calculate r->out.account_name in
 libnet_join_pre_processing()

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/libnet/libnet_join.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
index e33c383..1e290d7 100644
--- a/source3/libnet/libnet_join.c
+++ b/source3/libnet/libnet_join.c
@@ -1122,7 +1122,6 @@ static NTSTATUS libnet_join_joindomain_rpc_unsecure(TALLOC_CTX *mem_ctx,
 	struct rpc_pipe_client *netlogon_pipe = NULL;
 	struct netlogon_creds_cli_context *netlogon_creds = NULL;
 	struct samr_Password current_nt_hash;
-	const char *account_name = NULL;
 	NTSTATUS status;
 
 	status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon,
@@ -1147,16 +1146,9 @@ static NTSTATUS libnet_join_joindomain_rpc_unsecure(TALLOC_CTX *mem_ctx,
 	/* according to WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED */
 	E_md4hash(r->in.admin_password, current_nt_hash.hash);
 
-	account_name = talloc_asprintf(frame, "%s$",
-				       r->in.machine_name);
-	if (account_name == NULL) {
-		TALLOC_FREE(frame);
-		return NT_STATUS_NO_MEMORY;
-	}
-
 	status = rpccli_create_netlogon_creds(netlogon_pipe->desthost,
 					      r->in.domain_name,
-					      account_name,
+					      r->out.account_name,
 					      r->in.secure_channel_type,
 					      r->in.msg_ctx,
 					      frame,
@@ -2111,6 +2103,14 @@ static WERROR libnet_join_pre_processing(TALLOC_CTX *mem_ctx,
 		return WERR_INVALID_PARAMETER;
         }
 
+	r->out.account_name = talloc_asprintf(mem_ctx, "%s$",
+				       r->in.machine_name);
+	if (r->out.account_name == NULL) {
+		libnet_join_set_error_string(mem_ctx, r,
+			"Unable to construct r->out.account_name");
+		return WERR_NOT_ENOUGH_MEMORY;
+	}
+
 	if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
 				    &r->in.domain_name,
 				    &r->in.dc_name)) {
-- 
1.9.1


From f12b4c58c33464169c51e9bfaac42e705a3c0af9 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 17 May 2017 15:45:22 +0200
Subject: [PATCH 11/44] s3:libnet_join.idl: return the domain_guid in
 libnet_JoinCtx

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/librpc/idl/libnet_join.idl | 1 +
 1 file changed, 1 insertion(+)

diff --git a/source3/librpc/idl/libnet_join.idl b/source3/librpc/idl/libnet_join.idl
index 63ea1df..fc7b66c 100644
--- a/source3/librpc/idl/libnet_join.idl
+++ b/source3/librpc/idl/libnet_join.idl
@@ -49,6 +49,7 @@ interface libnetjoin
 		[out] string dns_domain_name,
 		[out] string forest_name,
 		[out] string dn,
+		[out] GUID domain_guid,
 		[out] dom_sid *domain_sid,
 		[out] boolean8 modified_config,
 		[out] string error_string,
-- 
1.9.1


From dd2dc9afdf175b4d186b74ead11d90b23f165700 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 17 May 2017 15:45:22 +0200
Subject: [PATCH 12/44] s3:libnet_join: remember the domain_guid for AD domains

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/libnet/libnet_join.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
index 1e290d7..37645a7 100644
--- a/source3/libnet/libnet_join.c
+++ b/source3/libnet/libnet_join.c
@@ -1080,6 +1080,7 @@ static NTSTATUS libnet_join_lookup_dc_rpc(TALLOC_CTX *mem_ctx,
 		r->out.netbios_domain_name = info->dns.name.string;
 		r->out.dns_domain_name = info->dns.dns_domain.string;
 		r->out.forest_name = info->dns.dns_forest.string;
+		r->out.domain_guid = info->dns.domain_guid;
 		r->out.domain_sid = dom_sid_dup(mem_ctx, info->dns.sid);
 		NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
 	}
-- 
1.9.1


From 55a5d64f82245218ba6b920c9d892e2828387a4a Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 18 May 2017 15:38:26 +0200
Subject: [PATCH 13/44] s3:libnet_join.idl: add krb5_salt to libnet_JoinCtx

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/librpc/idl/libnet_join.idl | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/source3/librpc/idl/libnet_join.idl b/source3/librpc/idl/libnet_join.idl
index fc7b66c..e45034d 100644
--- a/source3/librpc/idl/libnet_join.idl
+++ b/source3/librpc/idl/libnet_join.idl
@@ -54,7 +54,8 @@ interface libnetjoin
 		[out] boolean8 modified_config,
 		[out] string error_string,
 		[out] boolean8 domain_is_ad,
-		[out] uint32 set_encryption_types
+		[out] uint32 set_encryption_types,
+		[out] string krb5_salt
 		);
 
 	[nopush,nopull,noopnum] WERROR libnet_UnjoinCtx(
-- 
1.9.1


From 4e6b214d5be2221fb256fb41e473996bf77cc34d Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 18 May 2017 15:40:25 +0200
Subject: [PATCH 14/44] s3:libnet_join: remember r->out.krb5_salt in
 libnet_join_derive_salting_principal()

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/libnet/libnet_join.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
index 37645a7..a5e863a 100644
--- a/source3/libnet/libnet_join.c
+++ b/source3/libnet/libnet_join.c
@@ -864,6 +864,7 @@ static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
 		}
 	}
 
+	r->out.krb5_salt = salt;
 	return kerberos_secrets_store_des_salt(salt);
 }
 
-- 
1.9.1


From 09f100444c684de8abc783164d5eeeebb3f639e4 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 18 May 2017 15:48:49 +0200
Subject: [PATCH 15/44] s3:libnet_join: move kerberos_secrets_store_des_salt()
 out of libnet_join_derive_salting_principal()

We should separate the calculation and the storing steps.

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/libnet/libnet_join.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
index a5e863a..780c26c 100644
--- a/source3/libnet/libnet_join.c
+++ b/source3/libnet/libnet_join.c
@@ -865,7 +865,7 @@ static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
 	}
 
 	r->out.krb5_salt = salt;
-	return kerberos_secrets_store_des_salt(salt);
+	return true;
 }
 
 /****************************************************************
@@ -964,6 +964,17 @@ static ADS_STATUS libnet_join_post_processing_ads(TALLOC_CTX *mem_ctx,
 		return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
 	}
 
+	if (r->out.krb5_salt != NULL) {
+		bool ok;
+
+		ok = kerberos_secrets_store_des_salt(r->out.krb5_salt);
+		if (!ok) {
+			libnet_join_set_error_string(mem_ctx, r,
+				"failed to store krb5_salt");
+			return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
+		}
+	}
+
 	if (!libnet_join_create_keytab(mem_ctx, r)) {
 		libnet_join_set_error_string(mem_ctx, r,
 			"failed to create kerberos keytab");
-- 
1.9.1


From 31ae020bd7f222d26737c326a2deabfe8c1c7292 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 18 May 2017 15:50:49 +0200
Subject: [PATCH 16/44] s3:libnet_join: split libnet_join_post_processing_ads()
 into modify/sync

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/libnet/libnet_join.c | 24 +++++++++++++++++++++---
 1 file changed, 21 insertions(+), 3 deletions(-)

diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
index 780c26c..7493ac8 100644
--- a/source3/libnet/libnet_join.c
+++ b/source3/libnet/libnet_join.c
@@ -871,8 +871,8 @@ static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
 /****************************************************************
 ****************************************************************/
 
-static ADS_STATUS libnet_join_post_processing_ads(TALLOC_CTX *mem_ctx,
-						  struct libnet_JoinCtx *r)
+static ADS_STATUS libnet_join_post_processing_ads_modify(TALLOC_CTX *mem_ctx,
+							 struct libnet_JoinCtx *r)
 {
 	ADS_STATUS status;
 	bool need_etype_update = false;
@@ -964,6 +964,12 @@ static ADS_STATUS libnet_join_post_processing_ads(TALLOC_CTX *mem_ctx,
 		return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
 	}
 
+	return ADS_SUCCESS;
+}
+
+static ADS_STATUS libnet_join_post_processing_ads_sync(TALLOC_CTX *mem_ctx,
+							struct libnet_JoinCtx *r)
+{
 	if (r->out.krb5_salt != NULL) {
 		bool ok;
 
@@ -2214,6 +2220,18 @@ static WERROR libnet_join_post_processing(TALLOC_CTX *mem_ctx,
 		return WERR_OK;
 	}
 
+#ifdef HAVE_ADS
+	if (r->out.domain_is_ad &&
+	    !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
+		ADS_STATUS ads_status;
+
+		ads_status  = libnet_join_post_processing_ads_modify(mem_ctx, r);
+		if (!ADS_ERR_OK(ads_status)) {
+			return WERR_GEN_FAILURE;
+		}
+	}
+#endif /* HAVE_ADS */
+
 	saf_join_store(r->out.netbios_domain_name, r->in.dc_name);
 	if (r->out.dns_domain_name) {
 		saf_join_store(r->out.dns_domain_name, r->in.dc_name);
@@ -2224,7 +2242,7 @@ static WERROR libnet_join_post_processing(TALLOC_CTX *mem_ctx,
 	    !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
 		ADS_STATUS ads_status;
 
-		ads_status  = libnet_join_post_processing_ads(mem_ctx, r);
+		ads_status  = libnet_join_post_processing_ads_sync(mem_ctx, r);
 		if (!ADS_ERR_OK(ads_status)) {
 			return WERR_GEN_FAILURE;
 		}
-- 
1.9.1


From 744c79de916e038482c32531318d957944041d88 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 18 May 2017 15:52:59 +0200
Subject: [PATCH 17/44] s3:libnet_join: call do_JoinConfig() after we did
 remote changes on the server

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/libnet/libnet_join.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
index 7493ac8..5e4a0d3 100644
--- a/source3/libnet/libnet_join.c
+++ b/source3/libnet/libnet_join.c
@@ -2211,12 +2211,12 @@ static WERROR libnet_join_post_processing(TALLOC_CTX *mem_ctx,
 		return r->out.result;
 	}
 
-	werr = do_JoinConfig(r);
-	if (!W_ERROR_IS_OK(werr)) {
-		return werr;
-	}
-
 	if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
+		werr = do_JoinConfig(r);
+		if (!W_ERROR_IS_OK(werr)) {
+			return werr;
+		}
+
 		return WERR_OK;
 	}
 
@@ -2237,6 +2237,11 @@ static WERROR libnet_join_post_processing(TALLOC_CTX *mem_ctx,
 		saf_join_store(r->out.dns_domain_name, r->in.dc_name);
 	}
 
+	werr = do_JoinConfig(r);
+	if (!W_ERROR_IS_OK(werr)) {
+		return werr;
+	}
+
 #ifdef HAVE_ADS
 	if (r->out.domain_is_ad &&
 	    !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
-- 
1.9.1


From cc73d9100018ca26a3d0ecf3e55b63bbf34e6c70 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 18 May 2017 15:59:00 +0200
Subject: [PATCH 18/44] s3:libnet_join: move
 libnet_join_joindomain_store_secrets() to libnet_join_post_processing()

We should not store the secrets before we did all remote changes
(except the optional dns updates).

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/libnet/libnet_join.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
index 5e4a0d3..56bddf5 100644
--- a/source3/libnet/libnet_join.c
+++ b/source3/libnet/libnet_join.c
@@ -2237,6 +2237,10 @@ static WERROR libnet_join_post_processing(TALLOC_CTX *mem_ctx,
 		saf_join_store(r->out.dns_domain_name, r->in.dc_name);
 	}
 
+	if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
+		return WERR_NERR_SETUPNOTJOINED;
+	}
+
 	werr = do_JoinConfig(r);
 	if (!W_ERROR_IS_OK(werr)) {
 		return werr;
@@ -2628,11 +2632,6 @@ static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
 		goto done;
 	}
 
-	if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
-		werr = WERR_NERR_SETUPNOTJOINED;
-		goto done;
-	}
-
 	werr = WERR_OK;
 
  done:
-- 
1.9.1


From 20b804ed33d2c5460a52faa12ac09847a54e238c Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 18 May 2017 16:02:44 +0200
Subject: [PATCH 19/44] s3:libnet_join: move kerberos_secrets_store_des_salt()
 to libnet_join_joindomain_store_secrets()

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/libnet/libnet_join.c | 21 ++++++++++-----------
 1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
index 56bddf5..7669c2e 100644
--- a/source3/libnet/libnet_join.c
+++ b/source3/libnet/libnet_join.c
@@ -970,17 +970,6 @@ static ADS_STATUS libnet_join_post_processing_ads_modify(TALLOC_CTX *mem_ctx,
 static ADS_STATUS libnet_join_post_processing_ads_sync(TALLOC_CTX *mem_ctx,
 							struct libnet_JoinCtx *r)
 {
-	if (r->out.krb5_salt != NULL) {
-		bool ok;
-
-		ok = kerberos_secrets_store_des_salt(r->out.krb5_salt);
-		if (!ok) {
-			libnet_join_set_error_string(mem_ctx, r,
-				"failed to store krb5_salt");
-			return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
-		}
-	}
-
 	if (!libnet_join_create_keytab(mem_ctx, r)) {
 		libnet_join_set_error_string(mem_ctx, r,
 			"failed to create kerberos keytab");
@@ -1013,6 +1002,16 @@ static bool libnet_join_joindomain_store_secrets(TALLOC_CTX *mem_ctx,
 		return false;
 	}
 
+	if (r->out.krb5_salt != NULL) {
+		bool ok;
+
+		ok = kerberos_secrets_store_des_salt(r->out.krb5_salt);
+		if (!ok) {
+			DEBUG(1,("Failed to save krb5 salt\n"));
+			return false;
+		}
+	}
+
 	return true;
 }
 
-- 
1.9.1


From b2076aaf02104bc23032d3bb68cffb3e233df706 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 19 May 2017 16:01:55 +0200
Subject: [PATCH 20/44] s3:libads: remove
 kerberos_secrets_fetch_salting_principal() fallback

The handling for per encryption type salts was removed in
Samba 3.0.23a (Jul 21, 2006). It's very unlikely that someone
has such an installation that got constantly upgraded over 10 years
with an automatic password change nor rejoin. It also means
that the KDC only has salt-less arcfour-hmac-md5 key together
with the salted des keys. So there would only be a problem
if the client whould try to use a des key to contact the smb server.

Having this legacy code adds quite some complexity for no
good reason.

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/libads/kerberos.c | 37 ++++---------------------------------
 1 file changed, 4 insertions(+), 33 deletions(-)

diff --git a/source3/libads/kerberos.c b/source3/libads/kerberos.c
index b4bd768..ba2311b 100644
--- a/source3/libads/kerberos.c
+++ b/source3/libads/kerberos.c
@@ -273,27 +273,6 @@ int ads_kdestroy(const char *cc_name)
 }
 
 /************************************************************************
- Routine to fetch the salting principal for a service.  Active
- Directory may use a non-obvious principal name to generate the salt
- when it determines the key to use for encrypting tickets for a service,
- and hopefully we detected that when we joined the domain.
- ************************************************************************/
-
-static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
-{
-	char *key = NULL;
-	char *ret = NULL;
-
-	if (asprintf(&key, "%s/%s/enctype=%d",
-		     SECRETS_SALTING_PRINCIPAL, service, enctype) == -1) {
-		return NULL;
-	}
-	ret = (char *)secrets_fetch(key, NULL);
-	SAFE_FREE(key);
-	return ret;
-}
-
-/************************************************************************
  Return the standard DES salt key
 ************************************************************************/
 
@@ -372,10 +351,8 @@ char* kerberos_secrets_fetch_des_salt( void )
 }
 
 /************************************************************************
- Routine to get the salting principal for this service.  This is 
- maintained for backwards compatibilty with releases prior to 3.0.24.
- Since we store the salting principal string only at join, we may have 
- to look for the older tdb keys.  Caller must free if return is not null.
+ Routine to get the salting principal for this service.
+ Caller must free if return is not null.
  ************************************************************************/
 
 char *kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
@@ -387,14 +364,8 @@ char *kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
 
 	salt_princ_s = kerberos_secrets_fetch_des_salt();
 	if (salt_princ_s == NULL) {
-
-		/* look under the old key.  If this fails, just use the standard key */
-		salt_princ_s = kerberos_secrets_fetch_salting_principal(host_princ_s,
-									enctype);
-		if (salt_princ_s == NULL) {
-			/* fall back to host/machine.realm at REALM */
-			salt_princ_s = kerberos_standard_des_salt();
-		}
+		/* fall back to host/machine.realm at REALM */
+		salt_princ_s = kerberos_standard_des_salt();
 	}
 
 	return salt_princ_s;
-- 
1.9.1


From 274e7de0cd92a61d61c63ca7c2beab05e7695987 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 19 May 2017 16:15:34 +0200
Subject: [PATCH 21/44] s3:libads: provide a simpler
 kerberos_fetch_salt_princ() function

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/libads/kerberos.c       | 11 ++++++++---
 source3/libads/kerberos_proto.h |  1 +
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/source3/libads/kerberos.c b/source3/libads/kerberos.c
index ba2311b..a307286 100644
--- a/source3/libads/kerberos.c
+++ b/source3/libads/kerberos.c
@@ -355,9 +355,7 @@ char* kerberos_secrets_fetch_des_salt( void )
  Caller must free if return is not null.
  ************************************************************************/
 
-char *kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
-					       const char *host_princ_s,
-					       int enctype)
+char *kerberos_secrets_fetch_salt_princ(void)
 {
 	char *salt_princ_s;
 	/* lookup new key first */
@@ -371,6 +369,13 @@ char *kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
 	return salt_princ_s;
 }
 
+char *kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
+					       const char *host_princ_s,
+					       int enctype)
+{
+	return kerberos_secrets_fetch_salt_princ();
+}
+
 int create_kerberos_key_from_string(krb5_context context,
 					krb5_principal host_princ,
 					krb5_principal salt_princ,
diff --git a/source3/libads/kerberos_proto.h b/source3/libads/kerberos_proto.h
index 8917d63..6a6e269 100644
--- a/source3/libads/kerberos_proto.h
+++ b/source3/libads/kerberos_proto.h
@@ -61,6 +61,7 @@ bool kerberos_secrets_store_des_salt( const char* salt );
 char *kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
 					       const char *host_princ_s,
 					       int enctype);
+char *kerberos_secrets_fetch_salt_princ(void);
 
 int kerberos_kinit_password(const char *principal,
 			    const char *password,
-- 
1.9.1


From 377d65075900b7bc53709360d80b97cc6be3cc40 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 19 May 2017 16:28:42 +0200
Subject: [PATCH 22/44] s3:gse_krb5: simplify fill_keytab_from_password() by
 using kerberos_fetch_salt_princ()

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/librpc/crypto/gse_krb5.c | 40 ++++++++++++++--------------------------
 1 file changed, 14 insertions(+), 26 deletions(-)

diff --git a/source3/librpc/crypto/gse_krb5.c b/source3/librpc/crypto/gse_krb5.c
index 703d1b4..c0b6322 100644
--- a/source3/librpc/crypto/gse_krb5.c
+++ b/source3/librpc/crypto/gse_krb5.c
@@ -122,6 +122,8 @@ static krb5_error_code fill_keytab_from_password(krb5_context krbctx,
 	krb5_enctype *enctypes;
 	krb5_keytab_entry kt_entry;
 	unsigned int i;
+	krb5_principal salt_princ = NULL;
+	char *salt_princ_s = NULL;
 
 	ret = smb_krb5_get_allowed_etypes(krbctx, &enctypes);
 	if (ret) {
@@ -130,11 +132,19 @@ static krb5_error_code fill_keytab_from_password(krb5_context krbctx,
 		return ret;
 	}
 
+	salt_princ_s = kerberos_secrets_fetch_salt_princ();
+	if (salt_princ_s == NULL) {
+		ret = ENOMEM;
+		goto out;
+	}
+	ret = krb5_parse_name(krbctx, salt_princ_s, &salt_princ);
+	SAFE_FREE(salt_princ_s);
+	if (ret != 0) {
+		goto out;
+	}
+
 	for (i = 0; enctypes[i]; i++) {
 		krb5_keyblock *key = NULL;
-		krb5_principal salt_princ = NULL;
-		char *salt_princ_s;
-		char *princ_s;
 		int rc;
 
 		if (!(key = SMB_MALLOC_P(krb5_keyblock))) {
@@ -142,28 +152,6 @@ static krb5_error_code fill_keytab_from_password(krb5_context krbctx,
 			goto out;
 		}
 
-		ret = krb5_unparse_name(krbctx, princ, &princ_s);
-		if (ret != 0) {
-			SAFE_FREE(key);
-			continue;
-		}
-
-		salt_princ_s = kerberos_fetch_salt_princ_for_host_princ(krbctx,
-									princ_s,
-									enctypes[i]);
-		SAFE_FREE(princ_s);
-		if (salt_princ_s == NULL) {
-			SAFE_FREE(key);
-			continue;
-		}
-
-		ret = krb5_parse_name(krbctx, salt_princ_s, &salt_princ);
-		SAFE_FREE(salt_princ_s);
-		if (ret != 0) {
-			SAFE_FREE(key);
-			continue;
-		}
-
 		rc = create_kerberos_key_from_string(krbctx,
 						     princ,
 						     salt_princ,
@@ -171,7 +159,6 @@ static krb5_error_code fill_keytab_from_password(krb5_context krbctx,
 						     key,
 						     enctypes[i],
 						     false);
-		krb5_free_principal(krbctx, salt_princ);
 		if (rc != 0) {
 			DEBUG(10, ("Failed to create key for enctype %d "
 				   "(error: %s)\n",
@@ -199,6 +186,7 @@ static krb5_error_code fill_keytab_from_password(krb5_context krbctx,
 	ret = 0;
 
 out:
+	krb5_free_principal(krbctx, salt_princ);
 	SAFE_FREE(enctypes);
 	return ret;
 }
-- 
1.9.1


From 067de5276d67bcc5c96ceeed9275cc7fe1d1397c Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 19 May 2017 17:04:36 +0200
Subject: [PATCH 23/44] s3:libnet: make use of
 kerberos_secrets_fetch_salt_princ()

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/libnet/libnet_keytab.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/source3/libnet/libnet_keytab.c b/source3/libnet/libnet_keytab.c
index 9aefac1..1b5ac67 100644
--- a/source3/libnet/libnet_keytab.c
+++ b/source3/libnet/libnet_keytab.c
@@ -241,9 +241,7 @@ static krb5_error_code libnet_keytab_add_entry(krb5_context context,
 
 	keyp = KRB5_KT_KEY(&kt_entry);
 
-	salt_princ_s = kerberos_fetch_salt_princ_for_host_princ(context,
-								princ_s,
-								enctype);
+	salt_princ_s = kerberos_secrets_fetch_salt_princ();
 	if (salt_princ_s == NULL) {
 		ret = KRB5KRB_ERR_GENERIC;
 		goto done;
-- 
1.9.1


From 58301a2534acf1536d41c365dd61d073c5105dab Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 19 May 2017 17:08:24 +0200
Subject: [PATCH 24/44] s3:libads: make use of
 kerberos_secrets_fetch_salt_princ() in ads_keytab_add_entry()

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/libads/kerberos_keytab.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/source3/libads/kerberos_keytab.c b/source3/libads/kerberos_keytab.c
index 96df10f..ff12ec0 100644
--- a/source3/libads/kerberos_keytab.c
+++ b/source3/libads/kerberos_keytab.c
@@ -237,10 +237,14 @@ int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc)
 		goto out;
 	}
 
+	salt_princ_s = kerberos_secrets_fetch_salt_princ();
+	if (salt_princ_s == NULL) {
+		DBG_WARNING("kerberos_secrets_fetch_salt_princ() failed\n");
+		ret = -1;
+		goto out;
+	}
+
 	for (i = 0; enctypes[i]; i++) {
-		salt_princ_s = kerberos_fetch_salt_princ_for_host_princ(context,
-									princ_s,
-									enctypes[i]);
 
 		/* add the fqdn principal to the keytab */
 		ret = smb_krb5_kt_add_entry(context,
@@ -254,7 +258,6 @@ int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc)
 					    false);
 		if (ret) {
 			DEBUG(1, (__location__ ": Failed to add entry to keytab\n"));
-			SAFE_FREE(salt_princ_s);
 			goto out;
 		}
 
@@ -272,14 +275,13 @@ int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc)
 			if (ret) {
 				DEBUG(1, (__location__
 					  ": Failed to add short entry to keytab\n"));
-				SAFE_FREE(salt_princ_s);
 				goto out;
 			}
 		}
-		SAFE_FREE(salt_princ_s);
 	}
 
 out:
+	SAFE_FREE(salt_princ_s);
 	TALLOC_FREE(tmpctx);
 
 	if (keytab) {
-- 
1.9.1


From ff1ea20501665b4911488be37dad85b0ff906b37 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 19 May 2017 17:09:20 +0200
Subject: [PATCH 25/44] s3:libads: remove unused
 kerberos_fetch_salt_princ_for_host_princ()

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/libads/kerberos.c       | 7 -------
 source3/libads/kerberos_proto.h | 3 ---
 2 files changed, 10 deletions(-)

diff --git a/source3/libads/kerberos.c b/source3/libads/kerberos.c
index a307286..6cfbca6 100644
--- a/source3/libads/kerberos.c
+++ b/source3/libads/kerberos.c
@@ -369,13 +369,6 @@ char *kerberos_secrets_fetch_salt_princ(void)
 	return salt_princ_s;
 }
 
-char *kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
-					       const char *host_princ_s,
-					       int enctype)
-{
-	return kerberos_secrets_fetch_salt_princ();
-}
-
 int create_kerberos_key_from_string(krb5_context context,
 					krb5_principal host_princ,
 					krb5_principal salt_princ,
diff --git a/source3/libads/kerberos_proto.h b/source3/libads/kerberos_proto.h
index 6a6e269..e481d1d 100644
--- a/source3/libads/kerberos_proto.h
+++ b/source3/libads/kerberos_proto.h
@@ -58,9 +58,6 @@ int kerberos_kinit_password_ext(const char *principal,
 int ads_kdestroy(const char *cc_name);
 char* kerberos_standard_des_salt( void );
 bool kerberos_secrets_store_des_salt( const char* salt );
-char *kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
-					       const char *host_princ_s,
-					       int enctype);
 char *kerberos_secrets_fetch_salt_princ(void);
 
 int kerberos_kinit_password(const char *principal,
-- 
1.9.1


From 8883cfa94737b98d02b1974c270d613f45d0193a Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 19 May 2017 17:17:00 +0200
Subject: [PATCH 26/44] s3:secrets: move kerberos_secrets_*salt related
 functions to machine_account_secrets.c

These don't use any krb5_context related functions and they just
work on secrets.tdb, so they really belong to machine_account_secrets.c.

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/include/secrets.h                |  4 ++
 source3/libads/kerberos.c                | 97 --------------------------------
 source3/libads/kerberos_proto.h          |  3 -
 source3/libnet/libnet_keytab.c           |  1 +
 source3/passdb/machine_account_secrets.c | 96 +++++++++++++++++++++++++++++++
 5 files changed, 101 insertions(+), 100 deletions(-)

diff --git a/source3/include/secrets.h b/source3/include/secrets.h
index f397129..c40a951 100644
--- a/source3/include/secrets.h
+++ b/source3/include/secrets.h
@@ -133,6 +133,10 @@ bool secrets_store_machine_pw_sync(const char *pass, const char *oldpass, const
 				   uint32_t secure_channel,
 				   bool delete_join);
 
+char* kerberos_standard_des_salt( void );
+bool kerberos_secrets_store_des_salt( const char* salt );
+char *kerberos_secrets_fetch_salt_princ(void);
+
 /* The following definitions come from passdb/secrets_lsa.c  */
 NTSTATUS lsa_secret_get(TALLOC_CTX *mem_ctx,
 			const char *secret_name,
diff --git a/source3/libads/kerberos.c b/source3/libads/kerberos.c
index 6cfbca6..cfb09a7 100644
--- a/source3/libads/kerberos.c
+++ b/source3/libads/kerberos.c
@@ -272,103 +272,6 @@ int ads_kdestroy(const char *cc_name)
 	return code;
 }
 
-/************************************************************************
- Return the standard DES salt key
-************************************************************************/
-
-char* kerberos_standard_des_salt( void )
-{
-	fstring salt;
-
-	fstr_sprintf( salt, "host/%s.%s@", lp_netbios_name(), lp_realm() );
-	(void)strlower_m( salt );
-	fstrcat( salt, lp_realm() );
-
-	return SMB_STRDUP( salt );
-}
-
-/************************************************************************
-************************************************************************/
-
-static char* des_salt_key( void )
-{
-	char *key;
-
-	if (asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL,
-		     lp_realm()) == -1) {
-		return NULL;
-	}
-
-	return key;
-}
-
-/************************************************************************
-************************************************************************/
-
-bool kerberos_secrets_store_des_salt( const char* salt )
-{
-	char* key;
-	bool ret;
-
-	if ( (key = des_salt_key()) == NULL ) {
-		DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
-		return False;
-	}
-
-	if ( !salt ) {
-		DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
-		secrets_delete( key );
-		return True;
-	}
-
-	DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
-
-	ret = secrets_store( key, salt, strlen(salt)+1 );
-
-	SAFE_FREE( key );
-
-	return ret;
-}
-
-/************************************************************************
-************************************************************************/
-
-static
-char* kerberos_secrets_fetch_des_salt( void )
-{
-	char *salt, *key;
-
-	if ( (key = des_salt_key()) == NULL ) {
-		DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
-		return NULL;
-	}
-
-	salt = (char*)secrets_fetch( key, NULL );
-
-	SAFE_FREE( key );
-
-	return salt;
-}
-
-/************************************************************************
- Routine to get the salting principal for this service.
- Caller must free if return is not null.
- ************************************************************************/
-
-char *kerberos_secrets_fetch_salt_princ(void)
-{
-	char *salt_princ_s;
-	/* lookup new key first */
-
-	salt_princ_s = kerberos_secrets_fetch_des_salt();
-	if (salt_princ_s == NULL) {
-		/* fall back to host/machine.realm at REALM */
-		salt_princ_s = kerberos_standard_des_salt();
-	}
-
-	return salt_princ_s;
-}
-
 int create_kerberos_key_from_string(krb5_context context,
 					krb5_principal host_princ,
 					krb5_principal salt_princ,
diff --git a/source3/libads/kerberos_proto.h b/source3/libads/kerberos_proto.h
index e481d1d..f92cabd 100644
--- a/source3/libads/kerberos_proto.h
+++ b/source3/libads/kerberos_proto.h
@@ -56,9 +56,6 @@ int kerberos_kinit_password_ext(const char *principal,
 				time_t renewable_time,
 				NTSTATUS *ntstatus);
 int ads_kdestroy(const char *cc_name);
-char* kerberos_standard_des_salt( void );
-bool kerberos_secrets_store_des_salt( const char* salt );
-char *kerberos_secrets_fetch_salt_princ(void);
 
 int kerberos_kinit_password(const char *principal,
 			    const char *password,
diff --git a/source3/libnet/libnet_keytab.c b/source3/libnet/libnet_keytab.c
index 1b5ac67..c76e7b2 100644
--- a/source3/libnet/libnet_keytab.c
+++ b/source3/libnet/libnet_keytab.c
@@ -22,6 +22,7 @@
 #include "includes.h"
 #include "smb_krb5.h"
 #include "ads.h"
+#include "secrets.h"
 #include "libnet/libnet_keytab.h"
 
 #ifdef HAVE_KRB5
diff --git a/source3/passdb/machine_account_secrets.c b/source3/passdb/machine_account_secrets.c
index 3f097ab..3f6d6b6 100644
--- a/source3/passdb/machine_account_secrets.c
+++ b/source3/passdb/machine_account_secrets.c
@@ -553,6 +553,102 @@ bool secrets_store_machine_pw_sync(const char *pass, const char *oldpass, const
 	return ret;
 }
 
+/************************************************************************
+ Return the standard DES salt key
+************************************************************************/
+
+char* kerberos_standard_des_salt( void )
+{
+	fstring salt;
+
+	fstr_sprintf( salt, "host/%s.%s@", lp_netbios_name(), lp_realm() );
+	(void)strlower_m( salt );
+	fstrcat( salt, lp_realm() );
+
+	return SMB_STRDUP( salt );
+}
+
+/************************************************************************
+************************************************************************/
+
+static char* des_salt_key( void )
+{
+	char *key;
+
+	if (asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL,
+		     lp_realm()) == -1) {
+		return NULL;
+	}
+
+	return key;
+}
+
+/************************************************************************
+************************************************************************/
+
+bool kerberos_secrets_store_des_salt( const char* salt )
+{
+	char* key;
+	bool ret;
+
+	if ( (key = des_salt_key()) == NULL ) {
+		DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
+		return False;
+	}
+
+	if ( !salt ) {
+		DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
+		secrets_delete( key );
+		return True;
+	}
+
+	DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
+
+	ret = secrets_store( key, salt, strlen(salt)+1 );
+
+	SAFE_FREE( key );
+
+	return ret;
+}
+
+/************************************************************************
+************************************************************************/
+
+static
+char* kerberos_secrets_fetch_des_salt( void )
+{
+	char *salt, *key;
+
+	if ( (key = des_salt_key()) == NULL ) {
+		DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
+		return NULL;
+	}
+
+	salt = (char*)secrets_fetch( key, NULL );
+
+	SAFE_FREE( key );
+
+	return salt;
+}
+
+/************************************************************************
+ Routine to get the salting principal for this service.
+ Caller must free if return is not null.
+ ************************************************************************/
+
+char *kerberos_secrets_fetch_salt_princ(void)
+{
+	char *salt_princ_s;
+	/* lookup new key first */
+
+	salt_princ_s = kerberos_secrets_fetch_des_salt();
+	if (salt_princ_s == NULL) {
+		/* fall back to host/machine.realm at REALM */
+		salt_princ_s = kerberos_standard_des_salt();
+	}
+
+	return salt_princ_s;
+}
 
 /************************************************************************
  Routine to fetch the previous plaintext machine account password for a realm
-- 
1.9.1


From 948fe8bca8a5f449b41cde52b6dd1f852077f6af Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 22 May 2017 11:38:12 +0200
Subject: [PATCH 27/44] s3:secrets: rework des_salt_key() to take the realm as
 argument

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/passdb/machine_account_secrets.c | 25 +++++++++++++------------
 1 file changed, 13 insertions(+), 12 deletions(-)

diff --git a/source3/passdb/machine_account_secrets.c b/source3/passdb/machine_account_secrets.c
index 3f6d6b6..114bed6 100644
--- a/source3/passdb/machine_account_secrets.c
+++ b/source3/passdb/machine_account_secrets.c
@@ -571,16 +571,15 @@ char* kerberos_standard_des_salt( void )
 /************************************************************************
 ************************************************************************/
 
-static char* des_salt_key( void )
+static char *des_salt_key(const char *realm)
 {
-	char *key;
-
-	if (asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL,
-		     lp_realm()) == -1) {
-		return NULL;
-	}
+	char *keystr;
 
-	return key;
+	keystr = talloc_asprintf_strupper_m(talloc_tos(), "%s/DES/%s",
+					    SECRETS_SALTING_PRINCIPAL,
+					    realm);
+	SMB_ASSERT(keystr != NULL);
+	return keystr;
 }
 
 /************************************************************************
@@ -591,7 +590,8 @@ bool kerberos_secrets_store_des_salt( const char* salt )
 	char* key;
 	bool ret;
 
-	if ( (key = des_salt_key()) == NULL ) {
+	key = des_salt_key(lp_realm());
+	if (key == NULL) {
 		DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
 		return False;
 	}
@@ -606,7 +606,7 @@ bool kerberos_secrets_store_des_salt( const char* salt )
 
 	ret = secrets_store( key, salt, strlen(salt)+1 );
 
-	SAFE_FREE( key );
+	TALLOC_FREE(key);
 
 	return ret;
 }
@@ -619,14 +619,15 @@ char* kerberos_secrets_fetch_des_salt( void )
 {
 	char *salt, *key;
 
-	if ( (key = des_salt_key()) == NULL ) {
+	key = des_salt_key(lp_realm());
+	if (key == NULL) {
 		DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
 		return NULL;
 	}
 
 	salt = (char*)secrets_fetch( key, NULL );
 
-	SAFE_FREE( key );
+	TALLOC_FREE(key);
 
 	return salt;
 }
-- 
1.9.1


From ac0dd4e1a2ca0f6a030e535785b8689e7bc0b9ac Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 22 May 2017 12:10:45 +0200
Subject: [PATCH 28/44] s3:secrets: split out a domain_guid_keystr() function

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/passdb/machine_account_secrets.c | 24 ++++++++++++++----------
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/source3/passdb/machine_account_secrets.c b/source3/passdb/machine_account_secrets.c
index 114bed6..060babf 100644
--- a/source3/passdb/machine_account_secrets.c
+++ b/source3/passdb/machine_account_secrets.c
@@ -51,6 +51,16 @@ static const char *domain_sid_keystr(const char *domain)
 	return keystr;
 }
 
+static const char *domain_guid_keystr(const char *domain)
+{
+	char *keystr;
+
+	keystr = talloc_asprintf_strupper_m(talloc_tos(), "%s/%s",
+					    SECRETS_DOMAIN_GUID, domain);
+	SMB_ASSERT(keystr != NULL);
+	return keystr;
+}
+
 static const char *protect_ids_keystr(const char *domain)
 {
 	char *keystr;
@@ -139,7 +149,7 @@ bool secrets_fetch_domain_sid(const char *domain, struct dom_sid  *sid)
 bool secrets_store_domain_guid(const char *domain, struct GUID *guid)
 {
 	char *protect_ids;
-	fstring key;
+	const char *key;
 
 	protect_ids = secrets_fetch(protect_ids_keystr(domain), NULL);
 	if (protect_ids) {
@@ -152,24 +162,18 @@ bool secrets_store_domain_guid(const char *domain, struct GUID *guid)
 	}
 	SAFE_FREE(protect_ids);
 
-	slprintf(key, sizeof(key)-1, "%s/%s", SECRETS_DOMAIN_GUID, domain);
-	if (!strupper_m(key)) {
-		return false;
-	}
+	key = domain_guid_keystr(domain);
 	return secrets_store(key, guid, sizeof(struct GUID));
 }
 
 bool secrets_fetch_domain_guid(const char *domain, struct GUID *guid)
 {
 	struct GUID *dyn_guid;
-	fstring key;
+	const char *key;
 	size_t size = 0;
 	struct GUID new_guid;
 
-	slprintf(key, sizeof(key)-1, "%s/%s", SECRETS_DOMAIN_GUID, domain);
-	if (!strupper_m(key)) {
-		return false;
-	}
+	key = domain_guid_keystr(domain);
 	dyn_guid = (struct GUID *)secrets_fetch(key, &size);
 
 	if (!dyn_guid) {
-- 
1.9.1


From ba24628832057f185ca9cb47b05212b61246ebb9 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 21 Jun 2017 19:38:15 +0200
Subject: [PATCH 29/44] s3:secrets: add some const to
 secrets_store_domain_guid()

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/include/secrets.h                | 2 +-
 source3/passdb/machine_account_secrets.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/source3/include/secrets.h b/source3/include/secrets.h
index c40a951..6f74494 100644
--- a/source3/include/secrets.h
+++ b/source3/include/secrets.h
@@ -95,7 +95,7 @@ bool secrets_mark_domain_protected(const char *domain);
 bool secrets_clear_domain_protection(const char *domain);
 bool secrets_store_domain_sid(const char *domain, const struct dom_sid  *sid);
 bool secrets_fetch_domain_sid(const char *domain, struct dom_sid  *sid);
-bool secrets_store_domain_guid(const char *domain, struct GUID *guid);
+bool secrets_store_domain_guid(const char *domain, const struct GUID *guid);
 bool secrets_fetch_domain_guid(const char *domain, struct GUID *guid);
 enum netr_SchannelType get_default_sec_channel(void);
 bool secrets_fetch_trust_account_password_legacy(const char *domain,
diff --git a/source3/passdb/machine_account_secrets.c b/source3/passdb/machine_account_secrets.c
index 060babf..7d31734 100644
--- a/source3/passdb/machine_account_secrets.c
+++ b/source3/passdb/machine_account_secrets.c
@@ -146,7 +146,7 @@ bool secrets_fetch_domain_sid(const char *domain, struct dom_sid  *sid)
 	return True;
 }
 
-bool secrets_store_domain_guid(const char *domain, struct GUID *guid)
+bool secrets_store_domain_guid(const char *domain, const struct GUID *guid)
 {
 	char *protect_ids;
 	const char *key;
-- 
1.9.1


From 829de40a54051a57345438567c2338a93abd95d5 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 22 May 2017 12:18:33 +0200
Subject: [PATCH 30/44] s3:secrets: make use of des_salt_key() in
 secrets_store_machine_pw_sync()

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/passdb/machine_account_secrets.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/source3/passdb/machine_account_secrets.c b/source3/passdb/machine_account_secrets.c
index 7d31734..369f774 100644
--- a/source3/passdb/machine_account_secrets.c
+++ b/source3/passdb/machine_account_secrets.c
@@ -34,6 +34,8 @@
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_PASSDB
 
+static char *des_salt_key(const char *realm);
+
 /**
  * Form a key for fetching the domain sid
  *
@@ -545,11 +547,7 @@ bool secrets_store_machine_pw_sync(const char *pass, const char *oldpass, const
 	}
 
 	if (realm && salting_principal) {
-		char *key = talloc_asprintf(frame, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL, realm);
-		if (!key) {
-			TALLOC_FREE(frame);
-			return false;
-		}
+		char *key = des_salt_key(realm);
 		ret = secrets_store(key, salting_principal, strlen(salting_principal)+1 );
 	}
 
-- 
1.9.1


From cfdf343f69f75a365fff67ee69f0a4d86c7e4262 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 20 Jun 2017 13:07:15 +0200
Subject: [PATCH 31/44] s3:secrets: rename secrets_delete() to
 secrets_delete_entry()

secrets_delete_entry() fails if the key doesn't exist.

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/include/secrets.h                |  2 +-
 source3/passdb/machine_account_secrets.c | 16 ++++++++--------
 source3/passdb/secrets.c                 |  6 +++---
 source3/passdb/secrets_lsa.c             |  2 +-
 source3/utils/net.c                      |  6 +++---
 5 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/source3/include/secrets.h b/source3/include/secrets.h
index 6f74494..e7f87a9 100644
--- a/source3/include/secrets.h
+++ b/source3/include/secrets.h
@@ -88,7 +88,7 @@ struct db_context *secrets_db_ctx(void);
 void secrets_shutdown(void);
 void *secrets_fetch(const char *key, size_t *size);
 bool secrets_store(const char *key, const void *data, size_t size);
-bool secrets_delete(const char *key);
+bool secrets_delete_entry(const char *key);
 
 /* The following definitions come from passdb/machine_account_secrets.c */
 bool secrets_mark_domain_protected(const char *domain);
diff --git a/source3/passdb/machine_account_secrets.c b/source3/passdb/machine_account_secrets.c
index 369f774..7f19c65 100644
--- a/source3/passdb/machine_account_secrets.c
+++ b/source3/passdb/machine_account_secrets.c
@@ -92,7 +92,7 @@ bool secrets_clear_domain_protection(const char *domain)
 	
 	if (protection) {
 		SAFE_FREE(protection);
-		ret = secrets_delete(protect_ids_keystr(domain));
+		ret = secrets_delete_entry(protect_ids_keystr(domain));
 		if (!ret) {
 			DEBUG(0, ("Failed to remove Domain IDs protection\n"));
 		}
@@ -381,7 +381,7 @@ static bool secrets_delete_prev_machine_password(const char *domain)
 		return true;
 	}
 	SAFE_FREE(oldpass);
-	return secrets_delete(machine_prev_password_keystr(domain));
+	return secrets_delete_entry(machine_prev_password_keystr(domain));
 }
 
 /************************************************************************
@@ -394,13 +394,13 @@ bool secrets_delete_machine_password_ex(const char *domain)
 	if (!secrets_delete_prev_machine_password(domain)) {
 		return false;
 	}
-	if (!secrets_delete(machine_password_keystr(domain))) {
+	if (!secrets_delete_entry(machine_password_keystr(domain))) {
 		return false;
 	}
-	if (!secrets_delete(machine_sec_channel_type_keystr(domain))) {
+	if (!secrets_delete_entry(machine_sec_channel_type_keystr(domain))) {
 		return false;
 	}
-	return secrets_delete(machine_last_change_time_keystr(domain));
+	return secrets_delete_entry(machine_last_change_time_keystr(domain));
 }
 
 /************************************************************************
@@ -409,7 +409,7 @@ bool secrets_delete_machine_password_ex(const char *domain)
 
 bool secrets_delete_domain_sid(const char *domain)
 {
-	return secrets_delete(domain_sid_keystr(domain));
+	return secrets_delete_entry(domain_sid_keystr(domain));
 }
 
 /************************************************************************
@@ -514,7 +514,7 @@ bool secrets_store_machine_pw_sync(const char *pass, const char *oldpass, const
 		value = secrets_fetch(machine_sec_channel_type_keystr(domain), NULL);
 		if (value) {
 			SAFE_FREE(value);
-			ret = secrets_delete(machine_sec_channel_type_keystr(domain));
+			ret = secrets_delete_entry(machine_sec_channel_type_keystr(domain));
 			if (!ret) {
 				TALLOC_FREE(frame);
 				return ret;
@@ -600,7 +600,7 @@ bool kerberos_secrets_store_des_salt( const char* salt )
 
 	if ( !salt ) {
 		DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
-		secrets_delete( key );
+		secrets_delete_entry( key );
 		return True;
 	}
 
diff --git a/source3/passdb/secrets.c b/source3/passdb/secrets.c
index 0ddee99..3c3b6b9 100644
--- a/source3/passdb/secrets.c
+++ b/source3/passdb/secrets.c
@@ -146,7 +146,7 @@ bool secrets_store(const char *key, const void *data, size_t size)
 
 /* delete a secets database entry
  */
-bool secrets_delete(const char *key)
+bool secrets_delete_entry(const char *key)
 {
 	NTSTATUS status;
 	if (!secrets_init()) {
@@ -277,7 +277,7 @@ bool secrets_store_trusted_domain_password(const char* domain, const char* pwd,
 
 bool trusted_domain_password_delete(const char *domain)
 {
-	return secrets_delete(trustdom_keystr(domain));
+	return secrets_delete_entry(trustdom_keystr(domain));
 }
 
 bool secrets_store_ldap_pw(const char* dn, char* pw)
@@ -359,7 +359,7 @@ bool fetch_ldap_pw(char **dn, char** pw)
 			SAFE_FREE(*dn);
 			return False;
 		}
-		if (!secrets_delete(old_style_key)) {
+		if (!secrets_delete_entry(old_style_key)) {
 			DEBUG(0,("fetch_ldap_pw: old ldap secret could not be deleted!\n"));
 		}
 
diff --git a/source3/passdb/secrets_lsa.c b/source3/passdb/secrets_lsa.c
index a40942c..3ebaac4 100644
--- a/source3/passdb/secrets_lsa.c
+++ b/source3/passdb/secrets_lsa.c
@@ -223,7 +223,7 @@ NTSTATUS lsa_secret_delete(const char *secret_name)
 		return status;
 	}
 
-	if (!secrets_delete(key)) {
+	if (!secrets_delete_entry(key)) {
 		talloc_free(key);
 		return NT_STATUS_ACCESS_DENIED;
 	}
diff --git a/source3/utils/net.c b/source3/utils/net.c
index 34884f0..97d582f 100644
--- a/source3/utils/net.c
+++ b/source3/utils/net.c
@@ -156,9 +156,9 @@ static int net_setauthuser(struct net_context *c, int argc, const char **argv)
 				    "        Delete the auth user setting.\n"));
 			return 1;
 		}
-		secrets_delete(SECRETS_AUTH_USER);
-		secrets_delete(SECRETS_AUTH_DOMAIN);
-		secrets_delete(SECRETS_AUTH_PASSWORD);
+		secrets_delete_entry(SECRETS_AUTH_USER);
+		secrets_delete_entry(SECRETS_AUTH_DOMAIN);
+		secrets_delete_entry(SECRETS_AUTH_PASSWORD);
 		return 0;
 	}
 
-- 
1.9.1


From e7e90fa41059bab5529798c8ad79fc5b9ae8b586 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 22 May 2017 12:21:37 +0200
Subject: [PATCH 32/44] s3:secrets: re-add secrets_delete() helper to simplify
 deleting optional keys

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/include/secrets.h |  1 +
 source3/passdb/secrets.c  | 19 +++++++++++++++++++
 2 files changed, 20 insertions(+)

diff --git a/source3/include/secrets.h b/source3/include/secrets.h
index e7f87a9..548003f 100644
--- a/source3/include/secrets.h
+++ b/source3/include/secrets.h
@@ -89,6 +89,7 @@ void secrets_shutdown(void);
 void *secrets_fetch(const char *key, size_t *size);
 bool secrets_store(const char *key, const void *data, size_t size);
 bool secrets_delete_entry(const char *key);
+bool secrets_delete(const char *key);
 
 /* The following definitions come from passdb/machine_account_secrets.c */
 bool secrets_mark_domain_protected(const char *domain);
diff --git a/source3/passdb/secrets.c b/source3/passdb/secrets.c
index 3c3b6b9..7533d6b 100644
--- a/source3/passdb/secrets.c
+++ b/source3/passdb/secrets.c
@@ -158,6 +158,25 @@ bool secrets_delete_entry(const char *key)
 	return NT_STATUS_IS_OK(status);
 }
 
+/*
+ * Deletes the key if it exists.
+ */
+bool secrets_delete(const char *key)
+{
+	bool exists;
+
+	if (!secrets_init()) {
+		return false;
+	}
+
+	exists = dbwrap_exists(db_ctx, string_tdb_data(key));
+	if (!exists) {
+		return true;
+	}
+
+	return secrets_delete_entry(key);
+}
+
 /**
  * Form a key for fetching a trusted domain password
  *
-- 
1.9.1


From 9e286e5666152027f382eec1c089e2b8aee87484 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 22 May 2017 12:21:37 +0200
Subject: [PATCH 33/44] s3:secrets: make use of secrets_delete() in
 secrets_store_machine_pw_sync()

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/passdb/machine_account_secrets.c | 19 +++++--------------
 1 file changed, 5 insertions(+), 14 deletions(-)

diff --git a/source3/passdb/machine_account_secrets.c b/source3/passdb/machine_account_secrets.c
index 7f19c65..6b89e25 100644
--- a/source3/passdb/machine_account_secrets.c
+++ b/source3/passdb/machine_account_secrets.c
@@ -478,7 +478,6 @@ bool secrets_store_machine_pw_sync(const char *pass, const char *oldpass, const
 	uint8_t last_change_time_store[4];
 	TALLOC_CTX *frame = talloc_stackframe();
 	uint8_t sec_channel_bytes[4];
-	void *value;
 
 	if (delete_join) {
 		secrets_delete_machine_password_ex(domain);
@@ -496,11 +495,7 @@ bool secrets_store_machine_pw_sync(const char *pass, const char *oldpass, const
 	if (oldpass) {
 		ret = secrets_store(machine_prev_password_keystr(domain), oldpass, strlen(oldpass)+1);
 	} else {
-		value = secrets_fetch_prev_machine_password(domain);
-		if (value) {
-			SAFE_FREE(value);
-			ret = secrets_delete_prev_machine_password(domain);
-		}
+		ret = secrets_delete(machine_prev_password_keystr(domain));
 	}
 	if (!ret) {
 		TALLOC_FREE(frame);
@@ -511,14 +506,10 @@ bool secrets_store_machine_pw_sync(const char *pass, const char *oldpass, const
 		/* We delete this and instead have the read code fall back to
 		 * a default based on server role, as our caller can't specify
 		 * this with any more certainty */
-		value = secrets_fetch(machine_sec_channel_type_keystr(domain), NULL);
-		if (value) {
-			SAFE_FREE(value);
-			ret = secrets_delete_entry(machine_sec_channel_type_keystr(domain));
-			if (!ret) {
-				TALLOC_FREE(frame);
-				return ret;
-			}
+		ret = secrets_delete(machine_sec_channel_type_keystr(domain));
+		if (!ret) {
+			TALLOC_FREE(frame);
+			return ret;
 		}
 	} else {
 		SIVAL(&sec_channel_bytes, 0, secure_channel_type);
-- 
1.9.1


From a06245e42c421b0950ede8ab3dce3e4ca3e325eb Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 22 May 2017 12:27:45 +0200
Subject: [PATCH 34/44] s3:secrets: let secrets_store_machine_pw_sync() delete
 the des_salt_key when there's no value

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/passdb/machine_account_secrets.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/source3/passdb/machine_account_secrets.c b/source3/passdb/machine_account_secrets.c
index 6b89e25..c3a760b 100644
--- a/source3/passdb/machine_account_secrets.c
+++ b/source3/passdb/machine_account_secrets.c
@@ -537,9 +537,16 @@ bool secrets_store_machine_pw_sync(const char *pass, const char *oldpass, const
 		return ret;
 	}
 
-	if (realm && salting_principal) {
+	if (realm != NULL) {
 		char *key = des_salt_key(realm);
-		ret = secrets_store(key, salting_principal, strlen(salting_principal)+1 );
+
+		if (salting_principal != NULL) {
+			ret = secrets_store(key,
+					    salting_principal,
+					    strlen(salting_principal)+1);
+		} else {
+			ret = secrets_delete(key);
+		}
 	}
 
 	TALLOC_FREE(frame);
-- 
1.9.1


From 1e2d1b84e2a564cd71982680ed823be2f7be318c Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 24 May 2017 06:44:32 +0200
Subject: [PATCH 35/44] s3:secrets: replace
 secrets_delete_prev_machine_password() by secrets_delete()

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/passdb/machine_account_secrets.c | 16 +---------------
 1 file changed, 1 insertion(+), 15 deletions(-)

diff --git a/source3/passdb/machine_account_secrets.c b/source3/passdb/machine_account_secrets.c
index c3a760b..2457ac7 100644
--- a/source3/passdb/machine_account_secrets.c
+++ b/source3/passdb/machine_account_secrets.c
@@ -371,27 +371,13 @@ bool secrets_fetch_trust_account_password(const char *domain, uint8_t ret_pwd[16
 }
 
 /************************************************************************
- Routine to delete the old plaintext machine account password if any
-************************************************************************/
-
-static bool secrets_delete_prev_machine_password(const char *domain)
-{
-	char *oldpass = (char *)secrets_fetch(machine_prev_password_keystr(domain), NULL);
-	if (oldpass == NULL) {
-		return true;
-	}
-	SAFE_FREE(oldpass);
-	return secrets_delete_entry(machine_prev_password_keystr(domain));
-}
-
-/************************************************************************
  Routine to delete the plaintext machine account password, old password,
  sec channel type and last change time from secrets database
 ************************************************************************/
 
 bool secrets_delete_machine_password_ex(const char *domain)
 {
-	if (!secrets_delete_prev_machine_password(domain)) {
+	if (!secrets_delete(machine_prev_password_keystr(domain))) {
 		return false;
 	}
 	if (!secrets_delete_entry(machine_password_keystr(domain))) {
-- 
1.9.1


From b608d098b995136d742849fe513aeca3c7b7fe31 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 22 May 2017 12:31:01 +0200
Subject: [PATCH 36/44] s3:secrets: rewrite
 secrets_delete_machine_password_ex() using helper variables

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/passdb/machine_account_secrets.c | 26 ++++++++++++++++++++++----
 1 file changed, 22 insertions(+), 4 deletions(-)

diff --git a/source3/passdb/machine_account_secrets.c b/source3/passdb/machine_account_secrets.c
index 2457ac7..56a9442 100644
--- a/source3/passdb/machine_account_secrets.c
+++ b/source3/passdb/machine_account_secrets.c
@@ -377,16 +377,34 @@ bool secrets_fetch_trust_account_password(const char *domain, uint8_t ret_pwd[16
 
 bool secrets_delete_machine_password_ex(const char *domain)
 {
-	if (!secrets_delete(machine_prev_password_keystr(domain))) {
+	const char *tmpkey = NULL;
+	bool ok;
+
+	tmpkey = machine_prev_password_keystr(domain);
+	ok = secrets_delete(tmpkey);
+	if (!ok) {
+		return false;
+	}
+
+	tmpkey = machine_password_keystr(domain);
+	ok = secrets_delete_entry(tmpkey);
+	if (!ok) {
 		return false;
 	}
-	if (!secrets_delete_entry(machine_password_keystr(domain))) {
+
+	tmpkey = machine_sec_channel_type_keystr(domain);
+	ok = secrets_delete_entry(tmpkey);
+	if (!ok) {
 		return false;
 	}
-	if (!secrets_delete_entry(machine_sec_channel_type_keystr(domain))) {
+
+	tmpkey = machine_last_change_time_keystr(domain);
+	ok = secrets_delete_entry(tmpkey);
+	if (!ok) {
 		return false;
 	}
-	return secrets_delete_entry(machine_last_change_time_keystr(domain));
+
+	return true;
 }
 
 /************************************************************************
-- 
1.9.1


From 26448c7fa7393349728c0b5c74e17e0a994c9ebf Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 22 May 2017 12:40:05 +0200
Subject: [PATCH 37/44] s3:secrets: let secrets_delete_machine_password_ex()
 remove SID and GUID too

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/libnet/libnet_join.c             |  4 ----
 source3/passdb/machine_account_secrets.c | 16 +++++++++++++---
 2 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
index 7669c2e..9a2f227 100644
--- a/source3/libnet/libnet_join.c
+++ b/source3/libnet/libnet_join.c
@@ -1705,10 +1705,6 @@ static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX *mem_ctx,
 		return false;
 	}
 
-	if (!secrets_delete_domain_sid(lp_workgroup())) {
-		return false;
-	}
-
 	return true;
 }
 
diff --git a/source3/passdb/machine_account_secrets.c b/source3/passdb/machine_account_secrets.c
index 56a9442..06e42f2 100644
--- a/source3/passdb/machine_account_secrets.c
+++ b/source3/passdb/machine_account_secrets.c
@@ -371,8 +371,7 @@ bool secrets_fetch_trust_account_password(const char *domain, uint8_t ret_pwd[16
 }
 
 /************************************************************************
- Routine to delete the plaintext machine account password, old password,
- sec channel type and last change time from secrets database
+ Routine to delete all information related to the domain joined machine.
 ************************************************************************/
 
 bool secrets_delete_machine_password_ex(const char *domain)
@@ -380,6 +379,12 @@ bool secrets_delete_machine_password_ex(const char *domain)
 	const char *tmpkey = NULL;
 	bool ok;
 
+	tmpkey = domain_guid_keystr(domain);
+	ok = secrets_delete(tmpkey);
+	if (!ok) {
+		return false;
+	}
+
 	tmpkey = machine_prev_password_keystr(domain);
 	ok = secrets_delete(tmpkey);
 	if (!ok) {
@@ -404,6 +409,12 @@ bool secrets_delete_machine_password_ex(const char *domain)
 		return false;
 	}
 
+	tmpkey = domain_sid_keystr(domain);
+	ok = secrets_delete_entry(tmpkey);
+	if (!ok) {
+		return false;
+	}
+
 	return true;
 }
 
@@ -485,7 +496,6 @@ bool secrets_store_machine_pw_sync(const char *pass, const char *oldpass, const
 
 	if (delete_join) {
 		secrets_delete_machine_password_ex(domain);
-		secrets_delete_domain_sid(domain);
 		TALLOC_FREE(frame);
 		return true;
 	}
-- 
1.9.1


From a6fdce88dac25795913fe2f9fe7e13b0d34c74e5 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 22 May 2017 12:44:31 +0200
Subject: [PATCH 38/44] s3:secrets: let secrets_delete_machine_password_ex()
 also remove the des_salt key

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/include/secrets.h                |  2 +-
 source3/libnet/libnet_join.c             |  9 ++++-----
 source3/passdb/machine_account_secrets.c | 12 ++++++++++--
 3 files changed, 15 insertions(+), 8 deletions(-)

diff --git a/source3/include/secrets.h b/source3/include/secrets.h
index 548003f..fc8e118 100644
--- a/source3/include/secrets.h
+++ b/source3/include/secrets.h
@@ -110,7 +110,7 @@ bool secrets_fetch_trusted_domain_password(const char *domain, char** pwd,
                                            struct dom_sid  *sid, time_t *pass_last_set_time);
 bool secrets_store_trusted_domain_password(const char* domain, const char* pwd,
                                            const struct dom_sid  *sid);
-bool secrets_delete_machine_password_ex(const char *domain);
+bool secrets_delete_machine_password_ex(const char *domain, const char *realm);
 bool secrets_delete_domain_sid(const char *domain);
 bool secrets_store_machine_password(const char *pass, const char *domain, enum netr_SchannelType sec_channel);
 char *secrets_fetch_prev_machine_password(const char *domain);
diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
index 9a2f227..ecae4c5 100644
--- a/source3/libnet/libnet_join.c
+++ b/source3/libnet/libnet_join.c
@@ -1701,11 +1701,10 @@ static WERROR libnet_join_post_verify(TALLOC_CTX *mem_ctx,
 static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX *mem_ctx,
 						    struct libnet_UnjoinCtx *r)
 {
-	if (!secrets_delete_machine_password_ex(lp_workgroup())) {
-		return false;
-	}
-
-	return true;
+	/*
+	 * TODO: use values from 'struct libnet_UnjoinCtx' ?
+	 */
+	return secrets_delete_machine_password_ex(lp_workgroup(), lp_realm());
 }
 
 /****************************************************************
diff --git a/source3/passdb/machine_account_secrets.c b/source3/passdb/machine_account_secrets.c
index 06e42f2..70a8277 100644
--- a/source3/passdb/machine_account_secrets.c
+++ b/source3/passdb/machine_account_secrets.c
@@ -374,11 +374,19 @@ bool secrets_fetch_trust_account_password(const char *domain, uint8_t ret_pwd[16
  Routine to delete all information related to the domain joined machine.
 ************************************************************************/
 
-bool secrets_delete_machine_password_ex(const char *domain)
+bool secrets_delete_machine_password_ex(const char *domain, const char *realm)
 {
 	const char *tmpkey = NULL;
 	bool ok;
 
+	if (realm != NULL) {
+		tmpkey = des_salt_key(domain);
+		ok = secrets_delete(tmpkey);
+		if (!ok) {
+			return false;
+		}
+	}
+
 	tmpkey = domain_guid_keystr(domain);
 	ok = secrets_delete(tmpkey);
 	if (!ok) {
@@ -495,7 +503,7 @@ bool secrets_store_machine_pw_sync(const char *pass, const char *oldpass, const
 	uint8_t sec_channel_bytes[4];
 
 	if (delete_join) {
-		secrets_delete_machine_password_ex(domain);
+		secrets_delete_machine_password_ex(domain, realm);
 		TALLOC_FREE(frame);
 		return true;
 	}
-- 
1.9.1


From 06418547273b76c177828487e95c4a29789f6bc4 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 24 May 2017 05:56:32 +0200
Subject: [PATCH 39/44] s3:secrets: use secrets_delete for all keys in
 secrets_delete_machine_password_ex()

We just want all values to be removed at the end, it doesn't matter
if they didn't existed before.

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/passdb/machine_account_secrets.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/source3/passdb/machine_account_secrets.c b/source3/passdb/machine_account_secrets.c
index 70a8277..9a96a3f 100644
--- a/source3/passdb/machine_account_secrets.c
+++ b/source3/passdb/machine_account_secrets.c
@@ -400,25 +400,25 @@ bool secrets_delete_machine_password_ex(const char *domain, const char *realm)
 	}
 
 	tmpkey = machine_password_keystr(domain);
-	ok = secrets_delete_entry(tmpkey);
+	ok = secrets_delete(tmpkey);
 	if (!ok) {
 		return false;
 	}
 
 	tmpkey = machine_sec_channel_type_keystr(domain);
-	ok = secrets_delete_entry(tmpkey);
+	ok = secrets_delete(tmpkey);
 	if (!ok) {
 		return false;
 	}
 
 	tmpkey = machine_last_change_time_keystr(domain);
-	ok = secrets_delete_entry(tmpkey);
+	ok = secrets_delete(tmpkey);
 	if (!ok) {
 		return false;
 	}
 
 	tmpkey = domain_sid_keystr(domain);
-	ok = secrets_delete_entry(tmpkey);
+	ok = secrets_delete(tmpkey);
 	if (!ok) {
 		return false;
 	}
-- 
1.9.1


From 32bc2dce5aa74255f98091e81e459f56aa97adff Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 22 May 2017 15:36:29 +0200
Subject: [PATCH 40/44] s3:trusts_util: pass dcname to trust_pw_change()

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/include/proto.h              | 1 +
 source3/libsmb/trusts_util.c         | 1 +
 source3/rpcclient/cmd_netlogon.c     | 2 ++
 source3/utils/net_rpc.c              | 8 ++++++++
 source3/winbindd/winbindd_dual.c     | 1 +
 source3/winbindd/winbindd_dual_srv.c | 2 ++
 6 files changed, 15 insertions(+)

diff --git a/source3/include/proto.h b/source3/include/proto.h
index 121c9eb..45841dc 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -853,6 +853,7 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 			 struct messaging_context *msg_ctx,
 			 struct dcerpc_binding_handle *b,
 			 const char *domain,
+			 const char *dcname,
 			 bool force);
 
 /* The following definitions come from param/loadparm.c  */
diff --git a/source3/libsmb/trusts_util.c b/source3/libsmb/trusts_util.c
index 2cc6264..47b79b7 100644
--- a/source3/libsmb/trusts_util.c
+++ b/source3/libsmb/trusts_util.c
@@ -107,6 +107,7 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 			 struct messaging_context *msg_ctx,
 			 struct dcerpc_binding_handle *b,
 			 const char *domain,
+			 const char *dcname,
 			 bool force)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
diff --git a/source3/rpcclient/cmd_netlogon.c b/source3/rpcclient/cmd_netlogon.c
index 29d3096..4488ec2 100644
--- a/source3/rpcclient/cmd_netlogon.c
+++ b/source3/rpcclient/cmd_netlogon.c
@@ -835,6 +835,7 @@ static NTSTATUS cmd_netlogon_change_trust_pw(struct rpc_pipe_client *cli,
 					     const char **argv)
 {
         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+	const char *dcname = cli->desthost;
 
         /* Check arguments */
 
@@ -847,6 +848,7 @@ static NTSTATUS cmd_netlogon_change_trust_pw(struct rpc_pipe_client *cli,
 				 rpcclient_msg_ctx,
 				 cli->binding_handle,
 				 lp_workgroup(),
+				 dcname,
 				 true); /* force */
 	if (!NT_STATUS_IS_OK(result))
 		goto done;
diff --git a/source3/utils/net_rpc.c b/source3/utils/net_rpc.c
index 7059ebd..80536e5 100644
--- a/source3/utils/net_rpc.c
+++ b/source3/utils/net_rpc.c
@@ -279,11 +279,19 @@ static NTSTATUS rpc_changetrustpw_internals(struct net_context *c,
 					const char **argv)
 {
 	NTSTATUS status;
+	const char *dcname = NULL;
+
+	if (cli == NULL) {
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	dcname = smbXcli_conn_remote_name(cli->conn);
 
 	status = trust_pw_change(c->netlogon_creds,
 				 c->msg_ctx,
 				 pipe_hnd->binding_handle,
 				 c->opt_target_workgroup,
+				 dcname,
 				 true); /* force */
 	if (!NT_STATUS_IS_OK(status)) {
 		d_fprintf(stderr, _("Failed to change machine account password: %s\n"),
diff --git a/source3/winbindd/winbindd_dual.c b/source3/winbindd/winbindd_dual.c
index c389e00..8636ccd 100644
--- a/source3/winbindd/winbindd_dual.c
+++ b/source3/winbindd/winbindd_dual.c
@@ -1095,6 +1095,7 @@ static void machine_password_change_handler(struct tevent_context *ctx,
 				 msg_ctx,
 				 netlogon_pipe->binding_handle,
 				 child->domain->name,
+				 child->domain->dcname,
 				 false); /* force */
 
 	DEBUG(10, ("machine_password_change_handler: "
diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c
index ff4c93d..5e953e7 100644
--- a/source3/winbindd/winbindd_dual_srv.c
+++ b/source3/winbindd/winbindd_dual_srv.c
@@ -734,6 +734,7 @@ NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
 				 msg_ctx,
 				 netlogon_pipe->binding_handle,
 				 domain->name,
+				 domain->dcname,
 				 true); /* force */
 
 	/* Pass back result code - zero for success, other values for
@@ -1416,6 +1417,7 @@ reconnect:
 
 	status = trust_pw_change(domain->conn.netlogon_creds,
 				 msg_ctx, b, domain->name,
+				 domain->dcname,
 				 true); /* force */
 	if (!NT_STATUS_IS_OK(status)) {
 		if (!retry && dcerpc_binding_handle_is_connected(b)) {
-- 
1.9.1


From f1d98c91b62f406b45e773111d04c8e6a07fcd39 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 22 May 2017 20:44:40 +0200
Subject: [PATCH 41/44] libcli/auth: pass an array of nt_hashes to
 netlogon_creds_cli_auth*()

This way the caller can pass more than 2 hashes and can only
know which hash was used for a successful connection.

We allow up to 4 hashes (next, current, old, older).

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 libcli/auth/netlogon_creds_cli.c  | 58 +++++++++++++++++++++++++--------------
 libcli/auth/netlogon_creds_cli.h  | 12 ++++----
 source3/libsmb/trusts_util.c      | 19 +++++++++----
 source3/rpc_client/cli_netlogon.c | 15 ++++++++--
 4 files changed, 71 insertions(+), 33 deletions(-)

diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
index fcab814..fabb265 100644
--- a/libcli/auth/netlogon_creds_cli.c
+++ b/libcli/auth/netlogon_creds_cli.c
@@ -943,9 +943,10 @@ struct netlogon_creds_cli_auth_state {
 	struct tevent_context *ev;
 	struct netlogon_creds_cli_context *context;
 	struct dcerpc_binding_handle *binding_handle;
-	struct samr_Password current_nt_hash;
-	struct samr_Password previous_nt_hash;
-	struct samr_Password used_nt_hash;
+	uint8_t num_nt_hashes;
+	uint8_t idx_nt_hashes;
+	const struct samr_Password * const *nt_hashes;
+	const struct samr_Password *used_nt_hash;
 	char *srv_name_slash;
 	uint32_t current_flags;
 	struct netr_Credential client_challenge;
@@ -957,7 +958,6 @@ struct netlogon_creds_cli_auth_state {
 	bool try_auth3;
 	bool try_auth2;
 	bool require_auth2;
-	bool try_previous_nt_hash;
 	struct netlogon_creds_cli_locked_state *locked_state;
 };
 
@@ -968,8 +968,8 @@ struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
 				struct tevent_context *ev,
 				struct netlogon_creds_cli_context *context,
 				struct dcerpc_binding_handle *b,
-				struct samr_Password current_nt_hash,
-				const struct samr_Password *previous_nt_hash)
+				uint8_t num_nt_hashes,
+				const struct samr_Password * const *nt_hashes)
 {
 	struct tevent_req *req;
 	struct netlogon_creds_cli_auth_state *state;
@@ -985,12 +985,19 @@ struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
 	state->ev = ev;
 	state->context = context;
 	state->binding_handle = b;
-	state->current_nt_hash = current_nt_hash;
-	if (previous_nt_hash != NULL) {
-		state->previous_nt_hash = *previous_nt_hash;
-		state->try_previous_nt_hash = true;
+	if (num_nt_hashes < 1) {
+		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+		return tevent_req_post(req, ev);
+	}
+	if (num_nt_hashes > 4) {
+		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+		return tevent_req_post(req, ev);
 	}
 
+	state->num_nt_hashes = num_nt_hashes;
+	state->idx_nt_hashes = 0;
+	state->nt_hashes = nt_hashes;
+
 	if (context->db.locked_state != NULL) {
 		tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
 		return tevent_req_post(req, ev);
@@ -1020,7 +1027,7 @@ struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
 		state->require_auth2 = true;
 	}
 
-	state->used_nt_hash = state->current_nt_hash;
+	state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
 	state->current_flags = context->client.proposed_flags;
 
 	if (context->db.g_ctx != NULL) {
@@ -1142,7 +1149,7 @@ static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
 						  state->context->client.type,
 						  &state->client_challenge,
 						  &state->server_challenge,
-						  &state->used_nt_hash,
+						  state->used_nt_hash,
 						  &state->client_credential,
 						  state->current_flags);
 	if (tevent_req_nomem(state->creds, req)) {
@@ -1284,7 +1291,8 @@ static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
 			return;
 		}
 
-		if (!state->try_previous_nt_hash) {
+		state->idx_nt_hashes += 1;
+		if (state->idx_nt_hashes >= state->num_nt_hashes) {
 			/*
 			 * we already retried, giving up...
 			 */
@@ -1295,8 +1303,7 @@ static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
 		/*
 		 * lets retry with the old nt hash.
 		 */
-		state->try_previous_nt_hash = false;
-		state->used_nt_hash = state->previous_nt_hash;
+		state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
 		state->current_flags = state->context->client.proposed_flags;
 		netlogon_creds_cli_auth_challenge_start(req);
 		return;
@@ -1331,43 +1338,52 @@ static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
 	tevent_req_done(req);
 }
 
-NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req)
+NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
+				      uint8_t *idx_nt_hashes)
 {
+	struct netlogon_creds_cli_auth_state *state =
+		tevent_req_data(req,
+		struct netlogon_creds_cli_auth_state);
 	NTSTATUS status;
 
+	*idx_nt_hashes = 0;
+
 	if (tevent_req_is_nterror(req, &status)) {
 		tevent_req_received(req);
 		return status;
 	}
 
+	*idx_nt_hashes = state->idx_nt_hashes;
 	tevent_req_received(req);
 	return NT_STATUS_OK;
 }
 
 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
 				 struct dcerpc_binding_handle *b,
-				 struct samr_Password current_nt_hash,
-				 const struct samr_Password *previous_nt_hash)
+				 uint8_t num_nt_hashes,
+				 const struct samr_Password * const *nt_hashes,
+				 uint8_t *idx_nt_hashes)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	struct tevent_context *ev;
 	struct tevent_req *req;
 	NTSTATUS status = NT_STATUS_NO_MEMORY;
 
+	*idx_nt_hashes = 0;
+
 	ev = samba_tevent_context_init(frame);
 	if (ev == NULL) {
 		goto fail;
 	}
 	req = netlogon_creds_cli_auth_send(frame, ev, context, b,
-					   current_nt_hash,
-					   previous_nt_hash);
+					   num_nt_hashes, nt_hashes);
 	if (req == NULL) {
 		goto fail;
 	}
 	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
 		goto fail;
 	}
-	status = netlogon_creds_cli_auth_recv(req);
+	status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
  fail:
 	TALLOC_FREE(frame);
 	return status;
diff --git a/libcli/auth/netlogon_creds_cli.h b/libcli/auth/netlogon_creds_cli.h
index 7c737dd..dc27420 100644
--- a/libcli/auth/netlogon_creds_cli.h
+++ b/libcli/auth/netlogon_creds_cli.h
@@ -84,13 +84,15 @@ struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
 				struct tevent_context *ev,
 				struct netlogon_creds_cli_context *context,
 				struct dcerpc_binding_handle *b,
-				struct samr_Password current_nt_hash,
-				const struct samr_Password *previous_nt_hash);
-NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req);
+				uint8_t num_nt_hashes,
+				const struct samr_Password * const *nt_hashes);
+NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
+				      uint8_t *idx_nt_hashes);
 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
 				 struct dcerpc_binding_handle *b,
-				 struct samr_Password current_nt_hash,
-				 const struct samr_Password *previous_nt_hash);
+				 uint8_t num_nt_hashes,
+				 const struct samr_Password * const *nt_hashes,
+				 uint8_t *idx_nt_hashes);
 
 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
 				struct tevent_context *ev,
diff --git a/source3/libsmb/trusts_util.c b/source3/libsmb/trusts_util.c
index 47b79b7..128beb7 100644
--- a/source3/libsmb/trusts_util.c
+++ b/source3/libsmb/trusts_util.c
@@ -115,7 +115,9 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 	struct trust_pw_change_state *state;
 	struct cli_credentials *creds = NULL;
 	const struct samr_Password *current_nt_hash = NULL;
-	const struct samr_Password *previous_nt_hash = NULL;
+	uint8_t num_nt_hashes = 0;
+	const struct samr_Password *nt_hashes[1] = { NULL, };
+	uint8_t idx_nt_hashes = 0;
 	enum netr_SchannelType sec_channel_type = SEC_CHAN_NULL;
 	time_t pass_last_set_time;
 	uint32_t old_version = 0;
@@ -245,6 +247,9 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 		return NT_STATUS_NO_MEMORY;
 	}
 
+	nt_hashes[0] = current_nt_hash;
+	num_nt_hashes = 1;
+
 	/*
 	 * We could use cli_credentials_get_old_nt_hash(creds, frame) to
 	 * set previous_nt_hash.
@@ -259,8 +264,9 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 	 * local secrets before doing the change.
 	 */
 	status = netlogon_creds_cli_auth(context, b,
-					 *current_nt_hash,
-					 previous_nt_hash);
+					 num_nt_hashes,
+					 nt_hashes,
+					 &idx_nt_hashes);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0, ("netlogon_creds_cli_auth(%s) failed for old password - %s!\n",
 			  context_name, nt_errstr(status)));
@@ -349,9 +355,12 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 	/*
 	 * Now we verify the new password.
 	 */
+	nt_hashes[0] = current_nt_hash;
+	num_nt_hashes = 1;
 	status = netlogon_creds_cli_auth(context, b,
-					 *current_nt_hash,
-					 NULL); /* previous_nt_hash */
+					 num_nt_hashes,
+					 nt_hashes,
+					 &idx_nt_hashes);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0, ("netlogon_creds_cli_auth(%s) failed for new password - %s!\n",
 			  context_name, nt_errstr(status)));
diff --git a/source3/rpc_client/cli_netlogon.c b/source3/rpc_client/cli_netlogon.c
index 634c78b..d17c6c0 100644
--- a/source3/rpc_client/cli_netlogon.c
+++ b/source3/rpc_client/cli_netlogon.c
@@ -160,6 +160,9 @@ NTSTATUS rpccli_setup_netlogon_creds(struct cli_state *cli,
 	TALLOC_CTX *frame = talloc_stackframe();
 	struct rpc_pipe_client *netlogon_pipe = NULL;
 	struct netlogon_creds_CredentialState *creds = NULL;
+	uint8_t num_nt_hashes = 0;
+	const struct samr_Password *nt_hashes[2] = { NULL, NULL };
+	uint8_t idx_nt_hashes = 0;
 	NTSTATUS status;
 
 	status = netlogon_creds_cli_get(netlogon_creds,
@@ -196,10 +199,18 @@ NTSTATUS rpccli_setup_netlogon_creds(struct cli_state *cli,
 	}
 	talloc_steal(frame, netlogon_pipe);
 
+	nt_hashes[0] = &current_nt_hash;
+	num_nt_hashes = 1;
+	if (previous_nt_hash != NULL) {
+		nt_hashes[1] = previous_nt_hash;
+		num_nt_hashes = 2;
+	}
+
 	status = netlogon_creds_cli_auth(netlogon_creds,
 					 netlogon_pipe->binding_handle,
-					 current_nt_hash,
-					 previous_nt_hash);
+					 num_nt_hashes,
+					 nt_hashes,
+					 &idx_nt_hashes);
 	if (!NT_STATUS_IS_OK(status)) {
 		TALLOC_FREE(frame);
 		return status;
-- 
1.9.1


From 6e316efecc2d9de0908f91d80500501dcd34d040 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 13 Jun 2017 11:17:03 +0200
Subject: [PATCH 42/44] libcli/auth: add const to set_pw_in_buffer()

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 libcli/auth/proto.h      | 2 +-
 libcli/auth/smbencrypt.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcli/auth/proto.h b/libcli/auth/proto.h
index cc9ae33..a03f45e 100644
--- a/libcli/auth/proto.h
+++ b/libcli/auth/proto.h
@@ -187,7 +187,7 @@ void encode_or_decode_arc4_passwd_buffer(unsigned char pw_buf[532], const DATA_B
  encode a password buffer with an already unicode password.  The
  rest of the buffer is filled with random data to make it harder to attack.
 ************************************************************/
-bool set_pw_in_buffer(uint8_t buffer[516], DATA_BLOB *password);
+bool set_pw_in_buffer(uint8_t buffer[516], const DATA_BLOB *password);
 
 /***********************************************************
  decode a password buffer
diff --git a/libcli/auth/smbencrypt.c b/libcli/auth/smbencrypt.c
index ebf6812..afd9286 100644
--- a/libcli/auth/smbencrypt.c
+++ b/libcli/auth/smbencrypt.c
@@ -804,7 +804,7 @@ void encode_or_decode_arc4_passwd_buffer(unsigned char pw_buf[532], const DATA_B
  encode a password buffer with an already unicode password.  The
  rest of the buffer is filled with random data to make it harder to attack.
 ************************************************************/
-bool set_pw_in_buffer(uint8_t buffer[516], DATA_BLOB *password)
+bool set_pw_in_buffer(uint8_t buffer[516], const DATA_BLOB *password)
 {
 	if (password->length > 512) {
 		return false;
-- 
1.9.1


From 5d3ef424c91f649f73cb5687dd3029311db65816 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 13 Jun 2017 11:18:37 +0200
Subject: [PATCH 43/44] libcli/auth: pass the cleartext blob to
 netlogon_creds_cli_ServerPasswordSet*()

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 libcli/auth/netlogon_creds_cli.c | 20 +++++++++++---------
 libcli/auth/netlogon_creds_cli.h |  4 ++--
 source3/libnet/libnet_join.c     | 19 ++++++++++++++++++-
 source3/libsmb/trusts_util.c     | 39 ++++++++++++++++++++++++++++++++-------
 4 files changed, 63 insertions(+), 19 deletions(-)

diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
index fabb265..367bf6c 100644
--- a/libcli/auth/netlogon_creds_cli.c
+++ b/libcli/auth/netlogon_creds_cli.c
@@ -37,6 +37,7 @@
 #include "source3/include/messages.h"
 #include "source3/include/g_lock.h"
 #include "libds/common/roles.h"
+#include "lib/crypto/crypto.h"
 
 struct netlogon_creds_cli_locked_state;
 
@@ -1751,7 +1752,7 @@ struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx
 				struct tevent_context *ev,
 				struct netlogon_creds_cli_context *context,
 				struct dcerpc_binding_handle *b,
-				const char *new_password,
+				const DATA_BLOB *new_password,
 				const uint32_t *new_version)
 {
 	struct tevent_req *req;
@@ -1769,20 +1770,21 @@ struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx
 	state->context = context;
 	state->binding_handle = b;
 
-	/*
-	 * netr_ServerPasswordSet
-	 */
-	ok = E_md4hash(new_password, state->samr_password.hash);
-	if (!ok) {
+	if (new_password->length < 14) {
 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
 		return tevent_req_post(req, ev);
 	}
 
 	/*
+	 * netr_ServerPasswordSet
+	 */
+	mdfour(state->samr_password.hash, new_password->data, new_password->length);
+
+	/*
 	 * netr_ServerPasswordSet2
 	 */
-	ok = encode_pw_buffer(state->samr_crypt_password.data,
-			      new_password, STR_UNICODE);
+	ok = set_pw_in_buffer(state->samr_crypt_password.data,
+			      new_password);
 	if (!ok) {
 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
 		return tevent_req_post(req, ev);
@@ -2052,7 +2054,7 @@ NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
 				struct netlogon_creds_cli_context *context,
 				struct dcerpc_binding_handle *b,
-				const char *new_password,
+				const DATA_BLOB *new_password,
 				const uint32_t *new_version)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
diff --git a/libcli/auth/netlogon_creds_cli.h b/libcli/auth/netlogon_creds_cli.h
index dc27420..cecb0e6 100644
--- a/libcli/auth/netlogon_creds_cli.h
+++ b/libcli/auth/netlogon_creds_cli.h
@@ -106,13 +106,13 @@ struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx
 				struct tevent_context *ev,
 				struct netlogon_creds_cli_context *context,
 				struct dcerpc_binding_handle *b,
-				const char *new_password,
+				const DATA_BLOB *new_password,
 				const uint32_t *new_version);
 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req);
 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
 				struct netlogon_creds_cli_context *context,
 				struct dcerpc_binding_handle *b,
-				const char *new_password,
+				const DATA_BLOB *new_password,
 				const uint32_t *new_version);
 
 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
index ecae4c5..99bba2a 100644
--- a/source3/libnet/libnet_join.c
+++ b/source3/libnet/libnet_join.c
@@ -1140,6 +1140,9 @@ static NTSTATUS libnet_join_joindomain_rpc_unsecure(TALLOC_CTX *mem_ctx,
 	struct rpc_pipe_client *netlogon_pipe = NULL;
 	struct netlogon_creds_cli_context *netlogon_creds = NULL;
 	struct samr_Password current_nt_hash;
+	size_t len = 0;
+	bool ok;
+	DATA_BLOB new_trust_blob = data_blob_null;
 	NTSTATUS status;
 
 	status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon,
@@ -1186,9 +1189,23 @@ static NTSTATUS libnet_join_joindomain_rpc_unsecure(TALLOC_CTX *mem_ctx,
 		return status;
 	}
 
+	len = strlen(r->in.machine_password);
+	ok = convert_string_talloc(frame, CH_UNIX, CH_UTF16,
+				   r->in.machine_password, len,
+				   (void **)&new_trust_blob.data,
+				   &new_trust_blob.length);
+	if (!ok) {
+		status = NT_STATUS_UNMAPPABLE_CHARACTER;
+		if (errno == ENOMEM) {
+			status = NT_STATUS_NO_MEMORY;
+		}
+		TALLOC_FREE(frame);
+		return status;
+	}
+
 	status = netlogon_creds_cli_ServerPasswordSet(netlogon_creds,
 						      netlogon_pipe->binding_handle,
-						      r->in.machine_password,
+						      &new_trust_blob,
 						      NULL); /* new_version */
 	if (!NT_STATUS_IS_OK(status)) {
 		TALLOC_FREE(frame);
diff --git a/source3/libsmb/trusts_util.c b/source3/libsmb/trusts_util.c
index 128beb7..5bc8005 100644
--- a/source3/libsmb/trusts_util.c
+++ b/source3/libsmb/trusts_util.c
@@ -125,7 +125,9 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 	struct timeval g_timeout = { 0, };
 	int timeout = 0;
 	struct timeval tv = { 0, };
-	char *new_trust_passwd = NULL;
+	char *new_trust_pw_str = NULL;
+	size_t len = 0;
+	DATA_BLOB new_trust_pw_blob = data_blob_null;
 	uint32_t new_version = 0;
 	uint32_t *new_trust_version = NULL;
 	NTSTATUS status;
@@ -239,14 +241,31 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 	 * We create a random buffer and convert that to utf8.
 	 * This is similar to what windows is doing.
 	 */
-	new_trust_passwd = trust_pw_new_value(frame, sec_channel_type,
+	new_trust_pw_str = trust_pw_new_value(frame, sec_channel_type,
 					      lp_security());
-	if (new_trust_passwd == NULL) {
+	if (new_trust_pw_str == NULL) {
 		DEBUG(0, ("trust_pw_new_value() failed\n"));
 		TALLOC_FREE(frame);
 		return NT_STATUS_NO_MEMORY;
 	}
 
+	len = strlen(new_trust_pw_str);
+	ok = convert_string_talloc(frame, CH_UNIX, CH_UTF16,
+				   new_trust_pw_str, len,
+				   (void **)&new_trust_pw_blob.data,
+				   &new_trust_pw_blob.length);
+	if (!ok) {
+		status = NT_STATUS_UNMAPPABLE_CHARACTER;
+		if (errno == ENOMEM) {
+			status = NT_STATUS_NO_MEMORY;
+		}
+		DBG_ERR("convert_string_talloc(CH_UTF16MUNGED, CH_UNIX) "
+			"failed for of %s - %s\n",
+			domain, nt_errstr(status));
+		TALLOC_FREE(frame);
+		return status;
+	}
+
 	nt_hashes[0] = current_nt_hash;
 	num_nt_hashes = 1;
 
@@ -287,13 +306,16 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 
 	case SEC_CHAN_WKSTA:
 	case SEC_CHAN_BDC:
-		ok = secrets_store_machine_password(new_trust_passwd, domain, sec_channel_type);
+		ok = secrets_store_machine_password(new_trust_pw_str,
+						    domain,
+						    sec_channel_type);
 		if (!ok) {
 			DEBUG(0, ("secrets_store_machine_password failed for domain %s!\n",
 				  domain));
 			TALLOC_FREE(frame);
 			return NT_STATUS_INTERNAL_DB_CORRUPTION;
 		}
+		TALLOC_FREE(new_trust_pw_str);
 		break;
 
 	case SEC_CHAN_DNS_DOMAIN:
@@ -302,7 +324,7 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 		 * we need to get the sid first for the
 		 * pdb_set_trusteddom_pw call
 		 */
-		ok = pdb_set_trusteddom_pw(domain, new_trust_passwd,
+		ok = pdb_set_trusteddom_pw(domain, new_trust_pw_str,
 					   &td->security_identifier);
 		if (!ok) {
 			DEBUG(0, ("pdb_set_trusteddom_pw() failed for domain %s!\n",
@@ -310,6 +332,7 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 			TALLOC_FREE(frame);
 			return NT_STATUS_INTERNAL_DB_CORRUPTION;
 		}
+		TALLOC_FREE(new_trust_pw_str);
 		break;
 
 	default:
@@ -321,7 +344,7 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 		 current_timestring(talloc_tos(), false), __func__, domain));
 
 	status = netlogon_creds_cli_ServerPasswordSet(context, b,
-						      new_trust_passwd,
+						      &new_trust_pw_blob,
 						      new_trust_version);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0,("%s : %s(%s) remote password change set with %s failed - %s\n",
@@ -336,7 +359,9 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 		 current_timestring(talloc_tos(), false),
 		 __func__, domain, context_name));
 
-	ok = cli_credentials_set_password(creds, new_trust_passwd, CRED_SPECIFIED);
+	ok = cli_credentials_set_utf16_password(creds,
+						&new_trust_pw_blob,
+						CRED_SPECIFIED);
 	if (!ok) {
 		DEBUG(0, ("cli_credentials_set_password failed for domain %s!\n",
 			  domain));
-- 
1.9.1


From 4531cc985cdd2d7d8f8ba2490af252ed358bd987 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 21 Jun 2017 21:30:39 +0200
Subject: [PATCH 44/44] s3:trusts_util: also pass the previous_nt_hash to
 netlogon_creds_cli_auth()

Even in the case where only the password is known to the server, we should
try to leave a valid authentication behind.

We have better ways to indentify which password worked than only using
the current one.

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/libsmb/trusts_util.c | 43 +++++++++++++++++++++++++++++++------------
 1 file changed, 31 insertions(+), 12 deletions(-)

diff --git a/source3/libsmb/trusts_util.c b/source3/libsmb/trusts_util.c
index 5bc8005..ff7f256 100644
--- a/source3/libsmb/trusts_util.c
+++ b/source3/libsmb/trusts_util.c
@@ -115,9 +115,12 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 	struct trust_pw_change_state *state;
 	struct cli_credentials *creds = NULL;
 	const struct samr_Password *current_nt_hash = NULL;
+	const struct samr_Password *previous_nt_hash = NULL;
 	uint8_t num_nt_hashes = 0;
-	const struct samr_Password *nt_hashes[1] = { NULL, };
+	uint8_t idx = 0;
+	const struct samr_Password *nt_hashes[1+1] = { NULL, };
 	uint8_t idx_nt_hashes = 0;
+	uint8_t idx_current = UINT8_MAX;
 	enum netr_SchannelType sec_channel_type = SEC_CHAN_NULL;
 	time_t pass_last_set_time;
 	uint32_t old_version = 0;
@@ -181,6 +184,7 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 		TALLOC_FREE(frame);
 		return NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE;
 	}
+	previous_nt_hash = cli_credentials_get_old_nt_hash(creds, frame);
 
 	old_version = cli_credentials_get_kvno(creds);
 	pass_last_set_time = cli_credentials_get_password_last_changed_time(creds);
@@ -266,15 +270,19 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 		return status;
 	}
 
-	nt_hashes[0] = current_nt_hash;
-	num_nt_hashes = 1;
+	idx_current = idx;
+	nt_hashes[idx++] = current_nt_hash;
+	if (previous_nt_hash != NULL) {
+		nt_hashes[idx++] = previous_nt_hash;
+	}
+	num_nt_hashes = idx;
+
+	DEBUG(0,("%s : %s(%s): Verifying passwords remotely %s.\n",
+		 current_timestring(talloc_tos(), false),
+		 __func__, domain, context_name));
 
 	/*
-	 * We could use cli_credentials_get_old_nt_hash(creds, frame) to
-	 * set previous_nt_hash.
-	 *
-	 * But we want to check if the dc has our current password and only do
-	 * a change if that's the case. So we keep previous_nt_hash = NULL.
+	 * Check which password the dc knows about.
 	 *
 	 * TODO:
 	 * If the previous password is the only password in common with the dc,
@@ -287,12 +295,21 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 					 nt_hashes,
 					 &idx_nt_hashes);
 	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(0, ("netlogon_creds_cli_auth(%s) failed for old password - %s!\n",
-			  context_name, nt_errstr(status)));
+		DEBUG(0, ("netlogon_creds_cli_auth(%s) failed for old passwords (%u) - %s!\n",
+			  context_name, num_nt_hashes, nt_errstr(status)));
 		TALLOC_FREE(frame);
 		return status;
 	}
 
+	if (idx_nt_hashes != idx_current) {
+		DEBUG(0,("%s : %s(%s): Verified older password remotely "
+			 "skip changing %s\n",
+			 current_timestring(talloc_tos(), false),
+			 __func__, domain, context_name));
+		TALLOC_FREE(frame);
+		return NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE;
+	}
+
 	DEBUG(0,("%s : %s(%s): Verified old password remotely using %s\n",
 		 current_timestring(talloc_tos(), false),
 		 __func__, domain, context_name));
@@ -380,8 +397,10 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 	/*
 	 * Now we verify the new password.
 	 */
-	nt_hashes[0] = current_nt_hash;
-	num_nt_hashes = 1;
+	idx = 0;
+	idx_current = idx;
+	nt_hashes[idx++] = current_nt_hash;
+	num_nt_hashes = idx;
 	status = netlogon_creds_cli_auth(context, b,
 					 num_nt_hashes,
 					 nt_hashes,
-- 
1.9.1

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: OpenPGP digital signature
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20170626/c7ba81b1/signature.sig>


More information about the samba-technical mailing list