[Patches] Fixes for machine password problems [bug #12262]

Stefan Metzmacher metze at samba.org
Mon Feb 20 19:08:36 UTC 2017


Hi,

here's some patches to fix problem with the random passwords
winbindd sets every week (by default).
https://bugzilla.samba.org/show_bug.cgi?id=12262

In Samba 4.2 we only used ascii passwords, but with 4.3
we're using random unicode passwords. This causes
a lot of trouble if someone uses "unix charset != utf8".
But also with unix charset = utf8 it can sometimes happen
that kerberos authentication start to fail if
the password uses code points > 0xffff.

Please review and push:-)

Thanks!
metze

PS: As future improvement we could calculate the
ENCTYPE_ARCFOUR_HMAC in smb_krb5_create_key_from_string()
ourself using E_md4hash(). In the long run we may also
store the precalculated hashes when we change the password
and then use them for the servers in memory keytab
and as a client use this in memory keytab for kinit,
then we could use true random utf16 buffers like microsoft.
-------------- next part --------------
From 4ddb6ade9153c8389b55f828c4b66d268e43405f Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 18 Jan 2017 19:02:21 +0000
Subject: [PATCH 01/21] libcli/auth: check E_md4hash() result in
 netlogon_creds_cli_ServerPasswordSet_send()

We need to make sure we can convert the given string to an nthash.

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 libcli/auth/netlogon_creds_cli.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
index b97d60e..93ec1bf 100644
--- a/libcli/auth/netlogon_creds_cli.c
+++ b/libcli/auth/netlogon_creds_cli.c
@@ -1747,7 +1747,11 @@ struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx
 	/*
 	 * netr_ServerPasswordSet
 	 */
-	E_md4hash(new_password, state->samr_password.hash);
+	ok = E_md4hash(new_password, state->samr_password.hash);
+	if (!ok) {
+		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+		return tevent_req_post(req, ev);
+	}
 
 	/*
 	 * netr_ServerPasswordSet2
-- 
1.9.1


From bc82fc95172ba177cc954af87acd776fa90d2d55 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 9 Feb 2017 21:47:52 +0100
Subject: [PATCH 02/21] libcli/auth: add netlogon_creds_cli_debug_string()

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 libcli/auth/netlogon_creds_cli.c | 8 ++++++++
 libcli/auth/netlogon_creds_cli.h | 4 ++++
 2 files changed, 12 insertions(+)

diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
index 93ec1bf..d55142e 100644
--- a/libcli/auth/netlogon_creds_cli.c
+++ b/libcli/auth/netlogon_creds_cli.c
@@ -484,6 +484,14 @@ NTSTATUS netlogon_creds_cli_context_tmp(const char *client_computer,
 	return NT_STATUS_OK;
 }
 
+char *netlogon_creds_cli_debug_string(
+		const struct netlogon_creds_cli_context *context,
+		TALLOC_CTX *mem_ctx)
+{
+	return talloc_asprintf(mem_ctx, "netlogon_creds_cli:%s",
+			       context->db.key_name);
+}
+
 enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
 		struct netlogon_creds_cli_context *context)
 {
diff --git a/libcli/auth/netlogon_creds_cli.h b/libcli/auth/netlogon_creds_cli.h
index 006367a..949e03b 100644
--- a/libcli/auth/netlogon_creds_cli.h
+++ b/libcli/auth/netlogon_creds_cli.h
@@ -52,6 +52,10 @@ NTSTATUS netlogon_creds_cli_context_tmp(const char *client_computer,
 				TALLOC_CTX *mem_ctx,
 				struct netlogon_creds_cli_context **_context);
 
+char *netlogon_creds_cli_debug_string(
+		const struct netlogon_creds_cli_context *context,
+		TALLOC_CTX *mem_ctx);
+
 enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
 		struct netlogon_creds_cli_context *context);
 
-- 
1.9.1


From 3bf0fe2dcd1a5f5bf60951e29a084aa03d36c946 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 23 Aug 2016 09:30:05 +0200
Subject: [PATCH 03/21] lib/util: add generate_random_machine_password()
 function

It generates more random password for the use as machine password,
restricted to codepoints <= 0xFFFF in order to be compatible
with MIT krb5 and Heimdal.

Note: the fallback to ascii if 'unix charset' is not 'utf8'.

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 lib/util/genrand_util.c | 168 +++++++++++++++++++++++++++++++++++++++++++++++-
 lib/util/samba_util.h   |  32 ++++++++-
 2 files changed, 198 insertions(+), 2 deletions(-)

diff --git a/lib/util/genrand_util.c b/lib/util/genrand_util.c
index fbd9998..76b7cd9 100644
--- a/lib/util/genrand_util.c
+++ b/lib/util/genrand_util.c
@@ -210,7 +210,7 @@ again:
 }
 
 /**
- * Generate a random text password.
+ * Generate a random text password (based on printable ascii characters).
  */
 
 _PUBLIC_ char *generate_random_password(TALLOC_CTX *mem_ctx, size_t min, size_t max)
@@ -258,6 +258,172 @@ again:
 }
 
 /**
+ * Generate a random machine password (based on random utf16 characters,
+ * converted to utf8). min must be at least 14, max must be at most 255.
+ *
+ * If 'unix charset' is not utf8, the password consist of random ascii
+ * values!
+ */
+
+_PUBLIC_ char *generate_random_machine_password(TALLOC_CTX *mem_ctx, size_t min, size_t max)
+{
+	TALLOC_CTX *frame = NULL;
+	struct generate_random_machine_password_state {
+		uint8_t password_buffer[256 * 2];
+		uint8_t tmp;
+	} *state;
+	char *new_pw = NULL;
+	size_t len = max;
+	char *utf8_pw = NULL;
+	size_t utf8_len = 0;
+	char *unix_pw = NULL;
+	size_t unix_len = 0;
+	size_t diff;
+	size_t i;
+	bool ok;
+	int cmp;
+
+	if (max > 255) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	if (min < 14) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	if (min > max) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	frame = talloc_stackframe_pool(2048);
+	state = talloc_zero(frame, struct generate_random_machine_password_state);
+
+	diff = max - min;
+
+	if (diff > 0) {
+		size_t tmp;
+
+		generate_random_buffer((uint8_t *)&tmp, sizeof(tmp));
+
+		tmp %= diff;
+
+		len = min + tmp;
+	}
+
+	/*
+	 * Create a random machine account password
+	 * We create a random buffer and convert that to utf8.
+	 * This is similar to what windows is doing.
+	 *
+	 * In future we may store the raw random buffer,
+	 * but for now we need to pass the password as
+	 * char pointer through some layers.
+	 *
+	 * As most kerberos keys are derived from the
+	 * utf8 password we need to fallback to
+	 * ASCII passwords if "unix charset" is not utf8.
+	 */
+	generate_secret_buffer(state->password_buffer, len * 2);
+	for (i = 0; i < len; i++) {
+		size_t idx = i*2;
+		uint16_t c;
+
+		/*
+		 * both MIT krb5 and HEIMDAL only
+		 * handle codepoints up to 0xffff.
+		 *
+		 * It means we need to avoid
+		 * 0xD800 - 0xDBFF (high surrogate)
+		 * and
+		 * 0xDC00 - 0xDFFF (low surrogate)
+		 * in the random utf16 data.
+		 *
+		 * 55296 0xD800 0154000 0b1101100000000000
+		 * 57343 0xDFFF 0157777 0b1101111111111111
+		 * 8192  0x2000  020000   0b10000000000000
+		 *
+		 * The above values show that we can check
+		 * for 0xD800 and just add 0x2000 to avoid
+		 * the surrogate ranges.
+		 *
+		 * The rest will be handled by CH_UTF16MUNGED
+		 * see utf16_munged_pull().
+		 */
+		c = SVAL(state->password_buffer, idx);
+		if (c & 0xD800) {
+			c |= 0x2000;
+		}
+		SSVAL(state->password_buffer, idx, c);
+	}
+	ok = convert_string_talloc(frame,
+				   CH_UTF16MUNGED, CH_UTF8,
+				   state->password_buffer, len * 2,
+				   (void *)&utf8_pw, &utf8_len);
+	if (!ok) {
+		DEBUG(0, ("%s: convert_string_talloc() failed\n",
+			  __func__));
+		TALLOC_FREE(frame);
+		return NULL;
+	}
+
+	ok = convert_string_talloc(frame,
+				   CH_UTF16MUNGED, CH_UNIX,
+				   state->password_buffer, len * 2,
+				   (void *)&unix_pw, &unix_len);
+	if (!ok) {
+		goto ascii_fallback;
+	}
+
+	if (utf8_len != unix_len) {
+		goto ascii_fallback;
+	}
+
+	cmp = memcmp((const uint8_t *)utf8_pw,
+		     (const uint8_t *)unix_pw,
+		     utf8_len);
+	if (cmp != 0) {
+		goto ascii_fallback;
+	}
+
+	new_pw = talloc_strdup(mem_ctx, utf8_pw);
+	if (new_pw == NULL) {
+		TALLOC_FREE(frame);
+		return NULL;
+	}
+	talloc_set_name_const(new_pw, __func__);
+	TALLOC_FREE(frame);
+	return new_pw;
+
+ascii_fallback:
+	for (i = 0; i < len; i++) {
+		/*
+		 * truncate to ascii
+		 */
+		state->tmp = state->password_buffer[i] & 0x7f;
+		if (state->tmp == 0) {
+			state->tmp = state->password_buffer[i] >> 1;
+		}
+		if (state->tmp == 0) {
+			state->tmp = 0x01;
+		}
+		state->password_buffer[i] = state->tmp;
+	}
+	state->password_buffer[i] = '\0';
+
+	new_pw = talloc_strdup(mem_ctx, (const char *)state->password_buffer);
+	if (new_pw == NULL) {
+		TALLOC_FREE(frame);
+		return NULL;
+	}
+	talloc_set_name_const(new_pw, __func__);
+	TALLOC_FREE(frame);
+	return new_pw;
+}
+
+/**
  * Generate an array of unique text strings all of the same length.
  * The returned string will be allocated.
  * Returns NULL if the number of unique combinations cannot be created.
diff --git a/lib/util/samba_util.h b/lib/util/samba_util.h
index 8aa8eba..7a74617 100644
--- a/lib/util/samba_util.h
+++ b/lib/util/samba_util.h
@@ -97,11 +97,41 @@ _PUBLIC_ uint32_t generate_random(void);
 _PUBLIC_ bool check_password_quality(const char *s);
 
 /**
- * Generate a random text password.
+ * Generate a random text password (based on printable ascii characters).
+ * This function is designed to provide a password that
+ * meats the complexity requirements of UF_NORMAL_ACCOUNT objects
+ * and they should be human readable and writeable on any keyboard layout.
+ *
+ * Characters used are:
+ * ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,@$%&!?:;<=>()[]~
  */
 _PUBLIC_ char *generate_random_password(TALLOC_CTX *mem_ctx, size_t min, size_t max);
 
 /**
+ * Generate a random machine password
+ *
+ * min and max are the number of utf16 characters used
+ * to generate on utf8 compatible password.
+ *
+ * Note: if 'unix charset' is not 'utf8' (the default)
+ * then each utf16 character is only filled with
+ * values from 0x01 to 0x7f (ascii values without 0x00).
+ * This is important as the password neets to be
+ * a valid value as utf8 string and at the same time
+ * a valid value in the 'unix charset'.
+ *
+ * If 'unix charset' is 'utf8' (the default) then
+ * each utf16 character is a random value from 0x0000
+ * 0xFFFF (exluding the surrogate ranges from 0xD800-0xDFFF)
+ * while the translation from CH_UTF16MUNGED
+ * to CH_UTF8 replaces invalid values (see utf16_munged_pull()).
+ *
+ * Note: these passwords may not pass the complexity requirements
+ * for UF_NORMAL_ACCOUNT objects (except krbtgt accounts).
+ */
+_PUBLIC_ char *generate_random_machine_password(TALLOC_CTX *mem_ctx, size_t min, size_t max);
+
+/**
  Use the random number generator to generate a random string.
 **/
 _PUBLIC_ char *generate_random_str_list(TALLOC_CTX *mem_ctx, size_t len, const char *list);
-- 
1.9.1


From 4a209ebbccf4b8f19a41855dbae1ab9147c18e83 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 18 Jan 2017 19:57:30 +0100
Subject: [PATCH 04/21] s3:libsmb: let trust_pw_change() debug more verbose
 information

Password changes caused much trouble in the past, so we better debug
them at log level 0 and may see them also in the syslog.

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/libsmb/trusts_util.c | 29 +++++++++++++++++++++--------
 1 file changed, 21 insertions(+), 8 deletions(-)

diff --git a/source3/libsmb/trusts_util.c b/source3/libsmb/trusts_util.c
index c56949e..a3cabd4 100644
--- a/source3/libsmb/trusts_util.c
+++ b/source3/libsmb/trusts_util.c
@@ -54,6 +54,7 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 			 bool force)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
+	const char *context_name = NULL;
 	struct trust_pw_change_state *state;
 	struct cli_credentials *creds = NULL;
 	const struct samr_Password *current_nt_hash = NULL;
@@ -181,6 +182,12 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 		return NT_STATUS_OK;
 	}
 
+	context_name = netlogon_creds_cli_debug_string(context, talloc_tos());
+	if (context_name == NULL) {
+		TALLOC_FREE(frame);
+		return NT_STATUS_NO_MEMORY;
+	}
+
 	/*
 	 * Create a random machine account password
 	 * We create a random buffer and convert that to utf8.
@@ -215,12 +222,16 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 					 *current_nt_hash,
 					 previous_nt_hash);
 	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(0, ("netlogon_creds_cli_auth for domain %s - %s!\n",
-			  domain, nt_errstr(status)));
+		DEBUG(0, ("netlogon_creds_cli_auth(%s) failed for old password - %s!\n",
+			  context_name, nt_errstr(status)));
 		TALLOC_FREE(frame);
 		return status;
 	}
 
+	DEBUG(0,("%s : %s(%s): Verified old password remotely using %s\n",
+		 current_timestring(talloc_tos(), false),
+		 __func__, domain, context_name));
+
 	/*
 	 * Return the result of trying to write the new password
 	 * back into the trust account file.
@@ -260,22 +271,24 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 		break;
 	}
 
-	DEBUG(1,("%s : %s(%s): Changed password locally\n",
+	DEBUG(0,("%s : %s(%s): Changed password locally\n",
 		 current_timestring(talloc_tos(), false), __func__, domain));
 
 	status = netlogon_creds_cli_ServerPasswordSet(context, b,
 						      new_trust_passwd,
 						      new_trust_version);
 	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(0,("%s : %s(%s) remote password change set failed - %s\n",
-			 current_timestring(talloc_tos(), false), __func__,
-			 domain, nt_errstr(status)));
+		DEBUG(0,("%s : %s(%s) remote password change set with %s failed - %s\n",
+			 current_timestring(talloc_tos(), false),
+			 __func__, domain, context_name,
+			 nt_errstr(status)));
 		TALLOC_FREE(frame);
 		return status;
 	}
 
-	DEBUG(1,("%s : %s(%s): Changed password remotely.\n",
-		 current_timestring(talloc_tos(), false), __func__, domain));
+	DEBUG(0,("%s : %s(%s): Changed password remotely using %s\n",
+		 current_timestring(talloc_tos(), false),
+		 __func__, domain, context_name));
 
 	TALLOC_FREE(frame);
 	return NT_STATUS_OK;
-- 
1.9.1


From 58fde532382978a9dcddbc4adbb4f4b158394d6c Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 9 Feb 2017 22:53:52 +0100
Subject: [PATCH 05/21] s3:libsmb: let trust_pw_change() verify the new
 password at the end.

We should notice problems as early as possible, it makes no
sense to keep things working for a while and later find out
the we lost our trust relationship with our domain.

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/libsmb/trusts_util.c | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/source3/libsmb/trusts_util.c b/source3/libsmb/trusts_util.c
index a3cabd4..4b784c1 100644
--- a/source3/libsmb/trusts_util.c
+++ b/source3/libsmb/trusts_util.c
@@ -290,6 +290,39 @@ 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);
+	if (!ok) {
+		DEBUG(0, ("cli_credentials_set_password failed for domain %s!\n",
+			  domain));
+		TALLOC_FREE(frame);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	current_nt_hash = cli_credentials_get_nt_hash(creds, frame);
+	if (current_nt_hash == NULL) {
+		DEBUG(0, ("cli_credentials_get_nt_hash failed for domain %s!\n",
+			  domain));
+		TALLOC_FREE(frame);
+		return NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE;
+	}
+
+	/*
+	 * Now we verify the new password.
+	 */
+	status = netlogon_creds_cli_auth(context, b,
+					 *current_nt_hash,
+					 NULL); /* previous_nt_hash */
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(0, ("netlogon_creds_cli_auth(%s) failed for new password - %s!\n",
+			  context_name, nt_errstr(status)));
+		TALLOC_FREE(frame);
+		return status;
+	}
+
+	DEBUG(0,("%s : %s(%s): Verified new password remotely using %s\n",
+		 current_timestring(talloc_tos(), false),
+		 __func__, domain, context_name));
+
 	TALLOC_FREE(frame);
 	return NT_STATUS_OK;
 }
-- 
1.9.1


From d223d3cb64b5c799364e5d4bb7f03c48c250fd49 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 23 Aug 2016 12:12:35 +0200
Subject: [PATCH 06/21] s3:libsmb: add trust_pw_new_value() helper function

This generates a new trust password based on the secure channel type
and lp_security().

NT4 really has a limit of 28 UTF16 bytes.

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/include/proto.h      |  3 +++
 source3/libsmb/trusts_util.c | 56 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 59 insertions(+)

diff --git a/source3/include/proto.h b/source3/include/proto.h
index b3d3ca0..e6d4284 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -862,6 +862,9 @@ void update_trustdom_cache( void );
 struct netlogon_creds_cli_context;
 struct messaging_context;
 struct dcerpc_binding_handle;
+char *trust_pw_new_value(TALLOC_CTX *mem_ctx,
+			 enum netr_SchannelType sec_channel_type,
+			 int security);
 NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 			 struct messaging_context *msg_ctx,
 			 struct dcerpc_binding_handle *b,
diff --git a/source3/libsmb/trusts_util.c b/source3/libsmb/trusts_util.c
index 4b784c1..efe8098 100644
--- a/source3/libsmb/trusts_util.c
+++ b/source3/libsmb/trusts_util.c
@@ -47,6 +47,62 @@ static int trust_pw_change_state_destructor(struct trust_pw_change_state *state)
 	return 0;
 }
 
+char *trust_pw_new_value(TALLOC_CTX *mem_ctx,
+			 enum netr_SchannelType sec_channel_type,
+			 int security)
+{
+	/*
+	 * use secure defaults.
+	 */
+	size_t min = 128;
+	size_t max = 255;
+
+	switch (sec_channel_type) {
+	case SEC_CHAN_WKSTA:
+	case SEC_CHAN_BDC:
+		if (security == SEC_DOMAIN) {
+			/*
+			 * The maximum length of a trust account password.
+			 * Used when we randomly create it, 15 char passwords
+			 * exceed NT4's max password length.
+			 */
+			min = 14;
+			max = 14;
+		}
+		break;
+	case SEC_CHAN_DNS_DOMAIN:
+		/*
+		 * new_len * 2 = 498 bytes is the largest possible length
+		 * NL_PASSWORD_VERSION consumes the rest of the possible 512 bytes
+		 * and a confounder with at least 2 bytes is required.
+		 *
+		 * Windows uses new_len = 120 => 240 bytes (utf16)
+		 */
+		min = 120;
+		max = 120;
+		break;
+		/* fall through */
+	case SEC_CHAN_DOMAIN:
+		/*
+		 * The maximum length of a trust account password.
+		 * Used when we randomly create it, 15 char passwords
+		 * exceed NT4's max password length.
+		 */
+		min = 14;
+		max = 14;
+		break;
+	default:
+		break;
+	}
+
+	/*
+	 * Create a random machine account password
+	 * We create a random buffer and convert that to utf8.
+	 * This is similar to what windows is doing.
+	 */
+	return generate_random_machine_password(mem_ctx, min, max);
+}
+
 NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 			 struct messaging_context *msg_ctx,
 			 struct dcerpc_binding_handle *b,
-- 
1.9.1


From eff60f69b697336188c472a3bf9d16cfa639fa27 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 23 Aug 2016 12:12:35 +0200
Subject: [PATCH 07/21] s3:libsmb: use trust_pw_new_value() in
 trust_pw_change()

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/libsmb/trusts_util.c | 25 ++++---------------------
 1 file changed, 4 insertions(+), 21 deletions(-)

diff --git a/source3/libsmb/trusts_util.c b/source3/libsmb/trusts_util.c
index efe8098..2cc6264 100644
--- a/source3/libsmb/trusts_util.c
+++ b/source3/libsmb/trusts_util.c
@@ -122,10 +122,7 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 	struct timeval g_timeout = { 0, };
 	int timeout = 0;
 	struct timeval tv = { 0, };
-	size_t new_len = DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH;
-	uint8_t new_password_buffer[256 * 2] = { 0, };
 	char *new_trust_passwd = NULL;
-	size_t len = 0;
 	uint32_t new_version = 0;
 	uint32_t *new_trust_version = NULL;
 	NTSTATUS status;
@@ -191,16 +188,6 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 	case SEC_CHAN_BDC:
 		break;
 	case SEC_CHAN_DNS_DOMAIN:
-		/*
-		 * new_len * 2 = 498 bytes is the largest possible length
-		 * NL_PASSWORD_VERSION consumes the rest of the possible 512 bytes
-		 * and a confounder with at least 2 bytes is required.
-		 *
-		 * Windows uses new_len = 120 => 240 bytes.
-		 */
-		new_len = 120;
-
-		/* fall through */
 	case SEC_CHAN_DOMAIN:
 		status = pdb_get_trusted_domain(frame, domain, &td);
 		if (!NT_STATUS_IS_OK(status)) {
@@ -249,14 +236,10 @@ 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.
 	 */
-	generate_secret_buffer(new_password_buffer, new_len * 2);
-	ok = convert_string_talloc(frame,
-				   CH_UTF16MUNGED, CH_UTF8,
-				   new_password_buffer, new_len * 2,
-				   (void *)&new_trust_passwd, &len);
-	ZERO_STRUCT(new_password_buffer);
-	if (!ok) {
-		DEBUG(0, ("convert_string_talloc failed\n"));
+	new_trust_passwd = trust_pw_new_value(frame, sec_channel_type,
+					      lp_security());
+	if (new_trust_passwd == NULL) {
+		DEBUG(0, ("trust_pw_new_value() failed\n"));
 		TALLOC_FREE(frame);
 		return NT_STATUS_NO_MEMORY;
 	}
-- 
1.9.1


From 7a03f4531752d1d43a08d75fdc8203dda25c243f Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 23 Aug 2016 10:38:58 +0200
Subject: [PATCH 08/21] s3:libads: use trust_pw_new_value() for krb5 machine
 passwords

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/libads/util.c | 9 ++++++---
 source3/wscript_build | 1 +
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/source3/libads/util.c b/source3/libads/util.c
index 2e22bca..b0754be 100644
--- a/source3/libads/util.c
+++ b/source3/libads/util.c
@@ -35,9 +35,12 @@ ADS_STATUS ads_change_trust_account_password(ADS_STRUCT *ads, char *host_princip
 		return ADS_ERROR_SYSTEM(ENOENT);
 	}
 
-	new_password = generate_random_password(talloc_tos(),
-				DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH,
-				DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
+	new_password = trust_pw_new_value(talloc_tos(), SEC_CHAN_WKSTA, SEC_ADS);
+	if (new_password == NULL) {
+		ret = ADS_ERROR_SYSTEM(errno);
+		DEBUG(1,("Failed to generate machine password\n"));
+		goto failed;
+	}
 
 	ret = kerberos_set_password(ads->auth.kdc_server, host_principal, password, host_principal, new_password, ads->auth.time_offset);
 
diff --git a/source3/wscript_build b/source3/wscript_build
index 8c9a15b..9903624 100644
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -553,6 +553,7 @@ bld.SAMBA3_LIBRARY('ads',
                         libsmb
                         DCUTIL
                         smbldap
+                        trusts_util
                         ''',
                    private_library=True)
 
-- 
1.9.1


From 774511e0b294376cb2ccd8882e3ff5697b231b4a Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 23 Aug 2016 12:09:57 +0200
Subject: [PATCH 09/21] s3:libnet_join: make use of trust_pw_new_value()

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/libnet/libnet_join.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
index 8275a7c..4d00ef6 100644
--- a/source3/libnet/libnet_join.c
+++ b/source3/libnet/libnet_join.c
@@ -1138,9 +1138,11 @@ static NTSTATUS libnet_join_joindomain_rpc_unsecure(TALLOC_CTX *mem_ctx,
 	}
 
 	if (!r->in.machine_password) {
-		r->in.machine_password = generate_random_password(mem_ctx,
-				DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH,
-				DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
+		int security = r->in.ads ? SEC_ADS : SEC_DOMAIN;
+
+		r->in.machine_password = trust_pw_new_value(mem_ctx,
+						r->in.secure_channel_type,
+						security);
 		if (r->in.machine_password == NULL) {
 			TALLOC_FREE(frame);
 			return NT_STATUS_NO_MEMORY;
@@ -1233,9 +1235,11 @@ static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
 	}
 
 	if (!r->in.machine_password) {
-		r->in.machine_password = generate_random_password(mem_ctx,
-				DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH,
-				DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
+		int security = r->in.ads ? SEC_ADS : SEC_DOMAIN;
+
+		r->in.machine_password = trust_pw_new_value(mem_ctx,
+						r->in.secure_channel_type,
+						security);
 		NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
 	}
 
-- 
1.9.1


From bc0bb39df49fbf5ad99acc4dd45fca4c9e8fdc9c Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 23 Aug 2016 10:42:30 +0200
Subject: [PATCH 10/21] s3:net_rpc_trust: make use of trust_pw_new_value()

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/utils/net_rpc_trust.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/source3/utils/net_rpc_trust.c b/source3/utils/net_rpc_trust.c
index 5e58103..5c13e06 100644
--- a/source3/utils/net_rpc_trust.c
+++ b/source3/utils/net_rpc_trust.c
@@ -518,9 +518,9 @@ static int rpc_trust_common(struct net_context *net_ctx, int argc,
 			}
 
 			DEBUG(0, ("Using random trust password.\n"));
-			trust_pw = generate_random_password(mem_ctx,
-					DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH,
-					DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
+			trust_pw = trust_pw_new_value(mem_ctx,
+						      SEC_CHAN_DOMAIN,
+						      SEC_DOMAIN);
 			if (trust_pw == NULL) {
 				DEBUG(0, ("generate_random_password failed.\n"));
 				goto done;
-- 
1.9.1


From 99897b5217d49afbdc3f508f77a44fec64915f96 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 23 Aug 2016 12:41:48 +0200
Subject: [PATCH 11/21] s3:include: remove unused
 DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/include/smb.h | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/source3/include/smb.h b/source3/include/smb.h
index 7de47c8..24a73e57 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -732,12 +732,6 @@ struct node_status_extra {
 
 #define SAFE_NETBIOS_CHARS ". -_"
 
-/* The maximum length of a trust account password.
-   Used when we randomly create it, 15 char passwords
-   exceed NT4's max password length */
-
-#define DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH 14
-
 #define PORT_NONE	0
 #ifndef LDAP_PORT
 #define LDAP_PORT	389
-- 
1.9.1


From 9a7168e7493a29991655734f8f2b416925b831bd Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 23 Aug 2016 12:41:48 +0200
Subject: [PATCH 12/21] s4:libcli/raw: remove unused
 DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/libcli/raw/smb.h | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/source4/libcli/raw/smb.h b/source4/libcli/raw/smb.h
index 5bde657..d770fa5 100644
--- a/source4/libcli/raw/smb.h
+++ b/source4/libcli/raw/smb.h
@@ -297,13 +297,6 @@
 
 #define UID_FIELD_INVALID 0
 
-/* The maximum length of a trust account password.
-   Used when we randomly create it, 15 char passwords
-   exceed NT4's max password length */
-
-#define DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH 14
-
-
 /*
   filesystem attribute bits
 */
-- 
1.9.1


From 19b9aa4d5fb9dfbe9a3c02106f10964c3453d440 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 13 Feb 2017 19:35:54 +0100
Subject: [PATCH 13/21] s4:libnet: make use of
 generate_random_machine_password()

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/libnet/libnet_vampire.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source4/libnet/libnet_vampire.c b/source4/libnet/libnet_vampire.c
index 91d951f..f74f9bb 100644
--- a/source4/libnet/libnet_vampire.c
+++ b/source4/libnet/libnet_vampire.c
@@ -160,7 +160,7 @@ NTSTATUS libnet_vampire_cb_prepare_db(void *private_data,
 	settings.realm = s->realm;
 	settings.domain = s->domain_name;
 	settings.server_dn_str = p->dest_dsa->server_dn_str;
-	settings.machine_password = generate_random_password(s, 16, 255);
+	settings.machine_password = generate_random_machine_password(s, 128, 255);
 	settings.targetdir = s->targetdir;
 	settings.use_ntvfs = true;
 	status = provision_bare(s, s->lp_ctx, &settings, &result);
-- 
1.9.1


From 60d1f21ef6e99998ae7fb61d06d22781f850fd78 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 13 Feb 2017 19:01:21 +0100
Subject: [PATCH 14/21] s4:dsdb: autogenerate a random utf16 buffer for krbtgt
 password resets.

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/dsdb/samdb/ldb_modules/password_hash.c | 84 ++++++++++++++++++++++++++
 source4/dsdb/samdb/ldb_modules/samldb.c        | 25 +++-----
 2 files changed, 94 insertions(+), 15 deletions(-)

diff --git a/source4/dsdb/samdb/ldb_modules/password_hash.c b/source4/dsdb/samdb/ldb_modules/password_hash.c
index 9b772a8..bd29377 100644
--- a/source4/dsdb/samdb/ldb_modules/password_hash.c
+++ b/source4/dsdb/samdb/ldb_modules/password_hash.c
@@ -35,6 +35,7 @@
 #include "includes.h"
 #include "ldb_module.h"
 #include "libcli/auth/libcli_auth.h"
+#include "libcli/security/dom_sid.h"
 #include "system/kerberos.h"
 #include "auth/kerberos/kerberos.h"
 #include "dsdb/samdb/samdb.h"
@@ -125,6 +126,7 @@ struct setup_password_fields_io {
 		const char *sAMAccountName;
 		const char *user_principal_name;
 		bool is_computer;
+		bool is_krbtgt;
 		uint32_t restrictions;
 	} u;
 
@@ -2793,6 +2795,8 @@ static int setup_io(struct ph_context *ac,
 		ldb_get_opaque(ldb, "loadparm"), struct loadparm_context);
 	int ret;
 	const struct ldb_message *info_msg = NULL;
+	struct dom_sid *account_sid = NULL;
+	int rodc_krbtgt = 0;
 
 	ZERO_STRUCTP(io);
 
@@ -2837,6 +2841,26 @@ static int setup_io(struct ph_context *ac,
 								      "userPrincipalName", NULL);
 	io->u.is_computer		= ldb_msg_check_string_attribute(info_msg, "objectClass", "computer");
 
+	/* Ensure it has an objectSID too */
+	account_sid = samdb_result_dom_sid(ac, info_msg, "objectSid");
+	if (account_sid != NULL) {
+		NTSTATUS status;
+		uint32_t rid = 0;
+
+		status = dom_sid_split_rid(account_sid, account_sid, NULL, &rid);
+		if (NT_STATUS_IS_OK(status)) {
+			if (rid == DOMAIN_RID_KRBTGT) {
+				io->u.is_krbtgt = true;
+			}
+		}
+	}
+
+	rodc_krbtgt = ldb_msg_find_attr_as_int(info_msg,
+			"msDS-SecondaryKrbTgtNumber", 0);
+	if (rodc_krbtgt != 0) {
+		io->u.is_krbtgt = true;
+	}
+
 	if (io->u.sAMAccountName == NULL) {
 		ldb_asprintf_errstring(ldb,
 				       "setup_io: sAMAccountName attribute is missing on %s for attempted password set/change",
@@ -2867,6 +2891,12 @@ static int setup_io(struct ph_context *ac,
 		& (UF_INTERDOMAIN_TRUST_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT
 			| UF_SERVER_TRUST_ACCOUNT));
 
+	if (io->u.is_krbtgt) {
+		io->u.restrictions = 0;
+		io->ac->status->domain_data.pwdHistoryLength =
+			MAX(io->ac->status->domain_data.pwdHistoryLength, 3);
+	}
+
 	if (ac->userPassword) {
 		ret = msg_find_old_and_new_pwd_val(client_msg, "userPassword",
 						   ac->req->operation,
@@ -3172,6 +3202,59 @@ static int setup_io(struct ph_context *ac,
 		return ldb_operr(ldb);
 	}
 
+	if (io->u.is_krbtgt) {
+		size_t min = 196;
+		size_t max = 255;
+		size_t diff = max - min;
+		size_t len = max;
+		struct ldb_val *krbtgt_utf16 = NULL;
+
+		if (!ac->pwd_reset) {
+			return dsdb_module_werror(ac->module,
+					LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS,
+					WERR_DS_ATT_ALREADY_EXISTS,
+					"Password change on krbtgt not permitted!");
+		}
+
+		if (io->n.cleartext_utf16 == NULL) {
+			return dsdb_module_werror(ac->module,
+					LDB_ERR_UNWILLING_TO_PERFORM,
+					WERR_DS_INVALID_ATTRIBUTE_SYNTAX,
+					"Password reset on krbtgt requires UTF16!");
+		}
+
+		/*
+		 * Instead of taking the callers value,
+		 * we just generate a new random value here.
+		 *
+		 * Include null termination in the array.
+		 */
+		if (diff > 0) {
+			size_t tmp;
+
+			generate_random_buffer((uint8_t *)&tmp, sizeof(tmp));
+
+			tmp %= diff;
+
+			len = min + tmp;
+		}
+
+		krbtgt_utf16 = talloc_zero(io->ac, struct ldb_val);
+		if (krbtgt_utf16 == NULL) {
+			return ldb_oom(ldb);
+		}
+
+		*krbtgt_utf16 = data_blob_talloc_zero(krbtgt_utf16,
+						      (len+1)*2);
+		if (krbtgt_utf16->data == NULL) {
+			return ldb_oom(ldb);
+		}
+		krbtgt_utf16->length = len * 2;
+		generate_secret_buffer(krbtgt_utf16->data,
+				       krbtgt_utf16->length);
+		io->n.cleartext_utf16 = krbtgt_utf16;
+	}
+
 	if (existing_msg != NULL) {
 		NTSTATUS status;
 
@@ -4055,6 +4138,7 @@ static int password_hash_mod_search_self(struct ph_context *ac)
 					      "badPasswordTime",
 					      "badPwdCount",
 					      "lockoutTime",
+					      "msDS-SecondaryKrbTgtNumber",
 					      NULL };
 	struct ldb_request *search_req;
 	int ret;
diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c
index ea43ccc..2c47ff1 100644
--- a/source4/dsdb/samdb/ldb_modules/samldb.c
+++ b/source4/dsdb/samdb/ldb_modules/samldb.c
@@ -664,7 +664,6 @@ static int samldb_rodc_add(struct samldb_ctx *ac)
 	struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
 	uint32_t krbtgt_number, i_start, i;
 	int ret;
-	char *newpass;
 	struct ldb_val newpass_utf16;
 
 	/* find a unused msDC-SecondaryKrbTgtNumber */
@@ -710,21 +709,17 @@ found:
 		return ldb_operr(ldb);
 	}
 
-	newpass = generate_random_password(ac->msg, 128, 255);
-	if (newpass == NULL) {
-		return ldb_operr(ldb);
-	}
-
-	if (!convert_string_talloc(ac,
-				   CH_UNIX, CH_UTF16,
-				   newpass, strlen(newpass),
-				   (void *)&newpass_utf16.data,
-				   &newpass_utf16.length)) {
-		ldb_asprintf_errstring(ldb,
-				       "samldb_rodc_add: "
-				       "failed to generate UTF16 password from random password");
-		return LDB_ERR_OPERATIONS_ERROR;
+	newpass_utf16 = data_blob_talloc_zero(ac->module, 256);
+	if (newpass_utf16.data == NULL) {
+		return ldb_oom(ldb);
 	}
+	/*
+	 * Note that the password_hash module will ignore
+	 * this value and use it's own generate_secret_buffer()
+	 * that's why we can just use generate_random_buffer()
+	 * here.
+	 */
+	generate_random_buffer(newpass_utf16.data, newpass_utf16.length);
 	ret = ldb_msg_add_steal_value(ac->msg, "clearTextPassword", &newpass_utf16);
 	if (ret != LDB_SUCCESS) {
 		return ldb_operr(ldb);
-- 
1.9.1


From a9db138d1a0b0db44cae6d8538dadd58309aa574 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 17 Feb 2017 00:10:12 +0100
Subject: [PATCH 15/21] python/samba: provision_dns_add_samba.ldif expects
 utf-16-le passwords

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 python/samba/join.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/python/samba/join.py b/python/samba/join.py
index 058fa08..6485468 100644
--- a/python/samba/join.py
+++ b/python/samba/join.py
@@ -708,7 +708,7 @@ class dc_join(object):
                                                                 {"DNSDOMAIN": ctx.dnsdomain,
                                                                  "DOMAINDN": ctx.base_dn,
                                                                  "HOSTNAME" : ctx.myname,
-                                                                 "DNSPASS_B64": b64encode(ctx.dnspass),
+                                                                 "DNSPASS_B64": b64encode(ctx.dnspass.encode('utf-16-le')),
                                                                  "DNSNAME" : ctx.dnshostname}))
             for changetype, msg in recs:
                 assert changetype == ldb.CHANGETYPE_NONE
-- 
1.9.1


From fe880743d811a109d701d0f1649c8501cccb5546 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 13 Feb 2017 22:34:06 +0100
Subject: [PATCH 16/21] python/samba: use an explicit .encode('utf-8') where we
 expect utf8 passwords

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 python/samba/join.py               | 2 +-
 python/samba/netcmd/user.py        | 2 +-
 python/samba/provision/__init__.py | 2 +-
 python/samba/provision/sambadns.py | 2 +-
 python/samba/samdb.py              | 2 +-
 5 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/python/samba/join.py b/python/samba/join.py
index 6485468..01c2260 100644
--- a/python/samba/join.py
+++ b/python/samba/join.py
@@ -880,7 +880,7 @@ class dc_join(object):
                 repl_creds.guess(ctx.lp)
                 repl_creds.set_kerberos_state(DONT_USE_KERBEROS)
                 repl_creds.set_username(ctx.samname)
-                repl_creds.set_password(ctx.acct_pass)
+                repl_creds.set_password(ctx.acct_pass.encode('utf-8'))
             else:
                 repl_creds = ctx.creds
 
diff --git a/python/samba/netcmd/user.py b/python/samba/netcmd/user.py
index 4358170..f007ee5 100644
--- a/python/samba/netcmd/user.py
+++ b/python/samba/netcmd/user.py
@@ -683,7 +683,7 @@ class cmd_user_password(Command):
                 self.outf.write("Sorry, passwords do not match.\n")
 
         try:
-            net.change_password(password)
+            net.change_password(password.encode('utf-8'))
         except Exception, msg:
             # FIXME: catch more specific exception
             raise CommandError("Failed to change password : %s" % msg)
diff --git a/python/samba/provision/__init__.py b/python/samba/provision/__init__.py
index 3187b65..ad269aa 100644
--- a/python/samba/provision/__init__.py
+++ b/python/samba/provision/__init__.py
@@ -877,7 +877,7 @@ def secretsdb_self_join(secretsdb, domain,
         msg["msDS-KeyVersionNumber"] = [str(key_version_number)]
         msg["privateKeytab"] = ["secrets.keytab"]
 
-    msg["secret"] = [machinepass]
+    msg["secret"] = [machinepass.encode('utf-8')]
     msg["samAccountName"] = ["%s$" % netbiosname]
     msg["secureChannelType"] = [str(secure_channel_type)]
     if domainsid is not None:
diff --git a/python/samba/provision/sambadns.py b/python/samba/provision/sambadns.py
index df4673b..2c69dd4 100644
--- a/python/samba/provision/sambadns.py
+++ b/python/samba/provision/sambadns.py
@@ -661,7 +661,7 @@ def secretsdb_setup_dns(secretsdb, names, private_dir, realm,
             "REALM": realm,
             "DNSDOMAIN": dnsdomain,
             "DNS_KEYTAB": dns_keytab_path,
-            "DNSPASS_B64": b64encode(dnspass),
+            "DNSPASS_B64": b64encode(dnspass.encode('utf-8')),
             "KEY_VERSION_NUMBER": str(key_version_number),
             "HOSTNAME": names.hostname,
             "DNSNAME" : '%s.%s' % (
diff --git a/python/samba/samdb.py b/python/samba/samdb.py
index eabe363..19dd8e9 100644
--- a/python/samba/samdb.py
+++ b/python/samba/samdb.py
@@ -503,7 +503,7 @@ member: %s
             if len(res) > 1:
                 raise Exception('Matched %u multiple users with filter "%s"' % (len(res), search_filter))
             user_dn = res[0].dn
-            pw = unicode('"' + password + '"', 'utf-8').encode('utf-16-le')
+            pw = unicode('"' + password.encode('utf-8') + '"', 'utf-8').encode('utf-16-le')
             setpw = """
 dn: %s
 changetype: modify
-- 
1.9.1


From 2d41b65ced3522b0ecc8cb7afda828811af7b661 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 23 Aug 2016 09:35:50 +0200
Subject: [PATCH 17/21] pyglue: add generate_random_machine_password() wrapper

We use PyUnicode_FromString() (which is available from 2.6)
because we really have non-ascii strings.

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 python/pyglue.c          | 26 +++++++++++++++++++++++++-
 python/samba/__init__.py |  1 +
 2 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/python/pyglue.c b/python/pyglue.c
index dbe7eb4..0e80ba6 100644
--- a/python/pyglue.c
+++ b/python/pyglue.c
@@ -60,6 +60,23 @@ static PyObject *py_generate_random_password(PyObject *self, PyObject *args)
 	return ret;
 }
 
+static PyObject *py_generate_random_machine_password(PyObject *self, PyObject *args)
+{
+	int min, max;
+	PyObject *ret;
+	char *retstr;
+	if (!PyArg_ParseTuple(args, "ii", &min, &max))
+		return NULL;
+
+	retstr = generate_random_machine_password(NULL, min, max);
+	if (retstr == NULL) {
+		return NULL;
+	}
+	ret = PyUnicode_FromString(retstr);
+	talloc_free(retstr);
+	return ret;
+}
+
 static PyObject *py_unix2nttime(PyObject *self, PyObject *args)
 {
 	time_t t;
@@ -261,7 +278,14 @@ static PyMethodDef py_misc_methods[] = {
 		"Generate random string with specified length." },
 	{ "generate_random_password", (PyCFunction)py_generate_random_password,
 		METH_VARARGS, "generate_random_password(min, max) -> string\n"
-		"Generate random password with a length >= min and <= max." },
+		"Generate random password (based on printable ascii characters) "
+		"with a length >= min and <= max." },
+	{ "generate_random_machine_password", (PyCFunction)py_generate_random_machine_password,
+		METH_VARARGS, "generate_random_machine_password(min, max) -> string\n"
+		"Generate random password "
+		"(based on random utf16 characters converted to utf8 or "
+		"random ascii characters if 'unix charset' is not 'utf8')"
+		"with a length >= min (at least 14) and <= max (at most 255)." },
 	{ "unix2nttime", (PyCFunction)py_unix2nttime, METH_VARARGS,
 		"unix2nttime(timestamp) -> nttime" },
 	{ "nttime2unix", (PyCFunction)py_nttime2unix, METH_VARARGS,
diff --git a/python/samba/__init__.py b/python/samba/__init__.py
index 5f91531..19d5e38 100644
--- a/python/samba/__init__.py
+++ b/python/samba/__init__.py
@@ -396,6 +396,7 @@ nttime2string = _glue.nttime2string
 nttime2unix = _glue.nttime2unix
 unix2nttime = _glue.unix2nttime
 generate_random_password = _glue.generate_random_password
+generate_random_machine_password = _glue.generate_random_machine_password
 strcasecmp_m = _glue.strcasecmp_m
 strstr_m = _glue.strstr_m
 is_ntvfs_fileserver_built = _glue.is_ntvfs_fileserver_built
-- 
1.9.1


From 865916a11713d1dc78e63cedc46ade03248b1898 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 23 Aug 2016 12:27:19 +0200
Subject: [PATCH 18/21] samba-tool:domain: use
 generate_random_machine_password() for trusted domains

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 python/samba/join.py          |  3 ++-
 python/samba/netcmd/domain.py | 29 +++++------------------------
 2 files changed, 7 insertions(+), 25 deletions(-)

diff --git a/python/samba/join.py b/python/samba/join.py
index 01c2260..b998997 100644
--- a/python/samba/join.py
+++ b/python/samba/join.py
@@ -1330,7 +1330,8 @@ def join_subdomain(logger=None, server=None, creds=None, lp=None, site=None,
     ctx.domsid = security.random_sid()
     ctx.acct_dn = None
     ctx.dnshostname = "%s.%s" % (ctx.myname.lower(), ctx.dnsdomain)
-    ctx.trustdom_pass = samba.generate_random_password(128, 128)
+    # Windows uses 240 bytes as UTF16 so we do
+    ctx.trustdom_pass = samba.generate_random_machine_password(120, 120)
 
     ctx.userAccountControl = samba.dsdb.UF_SERVER_TRUST_ACCOUNT | samba.dsdb.UF_TRUSTED_FOR_DELEGATION
 
diff --git a/python/samba/netcmd/domain.py b/python/samba/netcmd/domain.py
index 24bf4fc..de8d537 100644
--- a/python/samba/netcmd/domain.py
+++ b/python/samba/netcmd/domain.py
@@ -2265,33 +2265,14 @@ class cmd_domain_trust_create(DomainTrustCommand):
             # needs to pass the NL_PASSWORD_VERSION structure within the
             # 512 bytes and a 2 bytes confounder is required.
             #
-            def random_trust_secret(length, use_aes_keys=True):
-                secret = [0] * length
-
-                pw1 = samba.generate_random_password(length/2, length/2)
-                if not use_aes_keys:
-                    # With arcfour-hmac-md5 we have to use valid utf16
-                    # in order to generate the correct pre-auth key
-                    # based on a utf8 password.
-                    #
-                    # We can remove this once our client libraries
-                    # support using the correct NTHASH.
-                    return string_to_byte_array(pw1.encode('utf-16-le'))
-
-                # We mix characters from generate_random_password
-                # with random numbers from random.randint()
-                for i in range(len(secret)):
-                    if len(pw1) > i:
-                        secret[i] = ord(pw1[i])
-                    else:
-                        secret[i] = random.randint(0, 255)
-
-                return secret
+            def random_trust_secret(length):
+                pw = samba.generate_random_machine_password(length/2, length/2)
+                return string_to_byte_array(pw.encode('utf-16-le'))
 
             if local_trust_info.trust_direction & lsa.LSA_TRUST_DIRECTION_INBOUND:
-                incoming_secret = random_trust_secret(240, use_aes_keys=use_aes_keys)
+                incoming_secret = random_trust_secret(240)
             if local_trust_info.trust_direction & lsa.LSA_TRUST_DIRECTION_OUTBOUND:
-                outgoing_secret = random_trust_secret(240, use_aes_keys=use_aes_keys)
+                outgoing_secret = random_trust_secret(240)
 
             remote_policy_access |= lsa.LSA_POLICY_TRUST_ADMIN
             remote_policy_access |= lsa.LSA_POLICY_CREATE_SECRET
-- 
1.9.1


From 91bcdf41a3ca7131ebb885e09c65171591276603 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 23 Aug 2016 12:37:37 +0200
Subject: [PATCH 19/21] samba-tool:domain: use
 generate_random_machine_password() for machine passwords

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 python/samba/join.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/python/samba/join.py b/python/samba/join.py
index b998997..9b211ac 100644
--- a/python/samba/join.py
+++ b/python/samba/join.py
@@ -105,7 +105,7 @@ class dc_join(object):
         if machinepass is not None:
             ctx.acct_pass = machinepass
         else:
-            ctx.acct_pass = samba.generate_random_password(32, 40)
+            ctx.acct_pass = samba.generate_random_machine_password(128, 255)
 
         ctx.dnsdomain = ctx.samdb.domain_dns_name()
         if clone_only:
@@ -684,7 +684,7 @@ class dc_join(object):
                     pass
                 ctx.net.set_password(account_name=ctx.samname,
                                      domain_name=ctx.domain_name,
-                                     newpassword=ctx.acct_pass)
+                                     newpassword=ctx.acct_pass.encode('utf-8'))
 
             res = ctx.samdb.search(base=ctx.acct_dn, scope=ldb.SCOPE_BASE,
                                    attrs=["msDS-KeyVersionNumber"])
-- 
1.9.1


From 0941141f39dac83a4ce1de876cab99088b64db73 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 23 Aug 2016 12:40:24 +0200
Subject: [PATCH 20/21] samba-tool:provision: use
 generate_random_machine_password() for machine passwords

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 python/samba/provision/__init__.py | 4 ++--
 python/samba/upgradehelpers.py     | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/python/samba/provision/__init__.py b/python/samba/provision/__init__.py
index ad269aa..81bbb0c 100644
--- a/python/samba/provision/__init__.py
+++ b/python/samba/provision/__init__.py
@@ -1768,9 +1768,9 @@ def provision_fill(samdb, secrets_ldb, logger, names, paths,
         invocationid = str(uuid.uuid4())
 
     if krbtgtpass is None:
-        krbtgtpass = samba.generate_random_password(128, 255)
+        krbtgtpass = samba.generate_random_machine_password(128, 255)
     if machinepass is None:
-        machinepass  = samba.generate_random_password(128, 255)
+        machinepass = samba.generate_random_machine_password(128, 255)
     if dnspass is None:
         dnspass = samba.generate_random_password(128, 255)
 
diff --git a/python/samba/upgradehelpers.py b/python/samba/upgradehelpers.py
index 9b2c1c2..99ffe28 100644
--- a/python/samba/upgradehelpers.py
+++ b/python/samba/upgradehelpers.py
@@ -573,7 +573,7 @@ def update_machine_account_password(samdb, secrets_ldb, names):
         assert(len(res) == 1)
 
         msg = ldb.Message(res[0].dn)
-        machinepass = samba.generate_random_password(128, 255)
+        machinepass = samba.generate_random_machine_password(128, 255)
         mputf16 = machinepass.encode('utf-16-le')
         msg["clearTextPassword"] = ldb.MessageElement(mputf16,
                                                 ldb.FLAG_MOD_REPLACE,
@@ -648,7 +648,7 @@ def update_krbtgt_account_password(samdb, names):
     assert(len(res) == 1)
 
     msg = ldb.Message(res[0].dn)
-    machinepass = samba.generate_random_password(128, 255)
+    machinepass = samba.generate_random_machine_password(128, 255)
     mputf16 = machinepass.encode('utf-16-le')
     msg["clearTextPassword"] = ldb.MessageElement(mputf16,
                                                   ldb.FLAG_MOD_REPLACE,
-- 
1.9.1


From 5ab85408d28a7f52c950b07188cb392a825550f4 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 13 Feb 2017 19:37:09 +0100
Subject: [PATCH 21/21] s4:scripting: use generate_random_machine_password()
 for machine passwords

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/scripting/bin/renamedc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source4/scripting/bin/renamedc b/source4/scripting/bin/renamedc
index 4494401..f14a837 100755
--- a/source4/scripting/bin/renamedc
+++ b/source4/scripting/bin/renamedc
@@ -95,7 +95,7 @@ if __name__ == '__main__':
 
     # Then change password and samaccountname and dnshostname
     msg = ldb.Message(newdn)
-    machinepass = samba.generate_random_password(128, 255)
+    machinepass = samba.generate_random_machine_password(128, 255)
     mputf16 = machinepass.encode('utf-16-le')
 
     account = "%s$" % opts.newname.upper()
-- 
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/20170220/eeee7562/signature.sig>


More information about the samba-technical mailing list