[SCM] Samba Shared Repository - branch master updated - c35b0d9ab5d01e37cb06d02083a329e18ae59566

Andrew Bartlett abartlet at samba.org
Fri Oct 17 04:58:41 GMT 2008


The branch, master has been updated
       via  c35b0d9ab5d01e37cb06d02083a329e18ae59566 (commit)
       via  4fb64f13d5101c960a7a234ff2b0b79283de5589 (commit)
       via  85919c34f4ca1a762cc1c2696309240f4694bd93 (commit)
       via  99315a19be4d28146e18dac7104ee2d18b798a48 (commit)
       via  7c88ea8aadfc2be0726cbe555543cfab8804c470 (commit)
       via  fc54ca014b21b655b643697475c6a0c05e773fc4 (commit)
       via  004bbbcd3b2d3799fc088d46e4c6258dfa27c2d5 (commit)
      from  c783d8a32e4d958aec6d943d0fa3de2e7d3a68c2 (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit c35b0d9ab5d01e37cb06d02083a329e18ae59566
Merge: 4fb64f13d5101c960a7a234ff2b0b79283de5589 c783d8a32e4d958aec6d943d0fa3de2e7d3a68c2
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Fri Oct 17 15:57:07 2008 +1100

    Merge branch 'master' of ssh://git.samba.org/data/git/samba into master-devel

commit 4fb64f13d5101c960a7a234ff2b0b79283de5589
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Fri Oct 17 14:06:33 2008 +1100

    Add a test to RPC-NETLOGON for random machine account passwords.
    
    Andrew Bartlett

commit 85919c34f4ca1a762cc1c2696309240f4694bd93
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Fri Oct 17 13:00:24 2008 +1100

    Improve RPC-SAMR tests to check random passwords
    
    By random I don't mean 'nice stream of ASCII chars, but pure random
    passwords containing invalid UTF16 sequences etc.
    
    Andrew Bartlett

commit 99315a19be4d28146e18dac7104ee2d18b798a48
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Fri Oct 17 12:41:02 2008 +1100

    Fix errrors in new password handling code found by RPC-SAMR.
    
    I'm very glad we have such a comprehensive testsuite for the SAMR
    password change process, as it makes this a much easier task to get
    right.
    
    Andrew Bartlett

commit 7c88ea8aadfc2be0726cbe555543cfab8804c470
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Thu Oct 16 12:48:16 2008 +1100

    Create a 'straight paper path' for UTF16 passwords.
    
    This uses a virtual attribute 'clearTextPassword' (name chosen to
    match references in MS-SAMR) that contains the length-limited blob
    containing an allegidly UTF16 password.  This ensures we do no
    validation or filtering of the password before we get a chance to MD4
    it.  We can then do the required munging into UTF8, and in future
    implement the rules Microsoft has provided us with for invalid inputs.
    
    All layers in the process now deal with the strings as length-limited
    inputs, incluing the krb5 string2key calls.
    
    This commit also includes a small change to samdb_result_passwords()
    to ensure that LM passwords are not returned to the application logic
    if LM authentication is disabled.
    
    The objectClass module has been modified to allow the
    clearTextPassword attribute to pass down the stack.
    
    Andrew Bartlett

commit fc54ca014b21b655b643697475c6a0c05e773fc4
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Thu Oct 16 12:31:19 2008 +1100

    Move the password_hash module up the module stack.
    
    This makes it operate in all partitions (minor), but more importantly
    places it above some other modules that implement some extra schema
    checks.  (The linked_attributes module objects to unknown attributes,
    which inclues clearTextPassword, which we need internally but is not
    in the schema).
    
    Andrew Bartlett

commit 004bbbcd3b2d3799fc088d46e4c6258dfa27c2d5
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Thu Oct 16 12:26:03 2008 +1100

    Assert that the server provides allowedAttributes (etc) on each entry
    
    This attribute is critical for the operation of nearly all the
    Microsoft Mangement Console tools
    
    Andrew Bartlett

-----------------------------------------------------------------------

Summary of changes:
 source4/auth/ntlm/auth_sam.c                   |    2 +-
 source4/dsdb/common/util.c                     |   88 ++++++-----
 source4/dsdb/samdb/ldb_modules/objectclass.c   |   12 +-
 source4/dsdb/samdb/ldb_modules/password_hash.c |  195 ++++++++++++++++--------
 source4/kdc/kpasswdd.c                         |   37 +++--
 source4/lib/ldb/tests/python/ldap.py           |    8 +-
 source4/libcli/auth/smbencrypt.c               |   55 +++++++-
 source4/librpc/idl/drsblobs.idl                |    2 +-
 source4/rpc_server/lsa/dcesrv_lsa.c            |   21 +--
 source4/rpc_server/netlogon/dcerpc_netlogon.c  |   27 ++--
 source4/rpc_server/samr/samr_password.c        |   99 ++++++++-----
 source4/scripting/python/samba/provision.py    |    3 +-
 source4/torture/rpc/netlogon.c                 |   71 +++++++--
 source4/torture/rpc/samr.c                     |  178 +++++++++++++++++++++-
 14 files changed, 598 insertions(+), 200 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source4/auth/ntlm/auth_sam.c b/source4/auth/ntlm/auth_sam.c
index ac36d4f..7842910 100644
--- a/source4/auth/ntlm/auth_sam.c
+++ b/source4/auth/ntlm/auth_sam.c
@@ -248,7 +248,7 @@ static NTSTATUS authsam_authenticate(struct auth_context *auth_context,
 		}
 	}
 
-	nt_status = samdb_result_passwords(mem_ctx, msgs[0], &lm_pwd, &nt_pwd);
+	nt_status = samdb_result_passwords(mem_ctx, auth_context->lp_ctx, msgs[0], &lm_pwd, &nt_pwd);
 	NT_STATUS_NOT_OK_RETURN(nt_status);
 
 	nt_status = authsam_password_ok(auth_context, mem_ctx, 
diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c
index 5b93efb..6a6f370 100644
--- a/source4/dsdb/common/util.c
+++ b/source4/dsdb/common/util.c
@@ -26,6 +26,7 @@
 #include "ldb.h"
 #include "ldb_errors.h"
 #include "../lib/util/util_ldb.h"
+#include "../lib/crypto/crypto.h"
 #include "dsdb/samdb/samdb.h"
 #include "libcli/security/security.h"
 #include "librpc/gen_ndr/ndr_security.h"
@@ -571,7 +572,7 @@ uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
 	return count;
 }
 
-NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg, 
+NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_message *msg, 
 				struct samr_Password **lm_pwd, struct samr_Password **nt_pwd) 
 {
 	struct samr_Password *lmPwdHash, *ntPwdHash;
@@ -587,14 +588,21 @@ NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
 		}
 	}
 	if (lm_pwd) {
-		int num_lm;
-		num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
-		if (num_lm == 0) {
-			*lm_pwd = NULL;
-		} else if (num_lm > 1) {
-			return NT_STATUS_INTERNAL_DB_CORRUPTION;
+		/* Ensure that if we have turned off LM
+		 * authentication, that we never use the LM hash, even
+		 * if we store it */
+		if (lp_lanman_auth(lp_ctx)) {
+			int num_lm;
+			num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
+			if (num_lm == 0) {
+				*lm_pwd = NULL;
+			} else if (num_lm > 1) {
+				return NT_STATUS_INTERNAL_DB_CORRUPTION;
+			} else {
+				*lm_pwd = &lmPwdHash[0];
+			}
 		} else {
-			*lm_pwd = &lmPwdHash[0];
+			*lm_pwd = NULL;
 		}
 	}
 	return NT_STATUS_OK;
@@ -1531,7 +1539,7 @@ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
 			    struct ldb_dn *user_dn,
 			    struct ldb_dn *domain_dn,
 			    struct ldb_message *mod,
-			    const char *new_pass,
+			    const DATA_BLOB *new_password,
 			    struct samr_Password *lmNewHash, 
 			    struct samr_Password *ntNewHash,
 			    bool user_change,
@@ -1632,40 +1640,47 @@ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
 		*_dominfo = dominfo;
 	}
 
-	if (restrictions && new_pass) {
-
+	if (restrictions && new_password) {
+		char *new_pass;
+		
 		/* check the various password restrictions */
-		if (restrictions && minPwdLength > strlen_m(new_pass)) {
+		if (restrictions && minPwdLength > utf16_len_n(new_password->data, new_password->length) / 2) {
 			if (reject_reason) {
 				*reject_reason = SAMR_REJECT_TOO_SHORT;
 			}
 			return NT_STATUS_PASSWORD_RESTRICTION;
 		}
+
+		/* Create the NT hash */
+		mdfour(local_ntNewHash.hash, new_password->data, new_password->length);
 		
-		/* possibly check password complexity */
-		if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
-		    !samdb_password_complexity_ok(new_pass)) {
-			if (reject_reason) {
-				*reject_reason = SAMR_REJECT_COMPLEXITY;
+		ntNewHash = &local_ntNewHash;
+
+		/* Only check complexity if we can convert it at all.  Assuming unconvertable passwords are 'strong' */
+		if (convert_string_talloc(mem_ctx, lp_iconv_convenience(ldb_get_opaque(ctx, "loadparm")), 
+					  CH_UTF16, CH_UNIX, 
+					  new_password->data, new_password->length, 
+					  (void **)&new_pass) != -1) {
+			
+			
+			/* possibly check password complexity */
+			if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
+			    !samdb_password_complexity_ok(new_pass)) {
+				if (reject_reason) {
+					*reject_reason = SAMR_REJECT_COMPLEXITY;
+				}
+				return NT_STATUS_PASSWORD_RESTRICTION;
 			}
-			return NT_STATUS_PASSWORD_RESTRICTION;
-		}
-		
-		/* compute the new nt and lm hashes */
-		if (E_deshash(new_pass, local_lmNewHash.hash)) {
-			lmNewHash = &local_lmNewHash;
-		}
-		if (!E_md4hash(new_pass, local_ntNewHash.hash)) {
-			/* If we can't convert this password to UCS2, then we should not accept it */
-			if (reject_reason) {
-				*reject_reason = SAMR_REJECT_OTHER;
+			
+			/* compute the new lm hashes (for checking history - case insenitivly!) */
+			if (E_deshash(new_pass, local_lmNewHash.hash)) {
+				lmNewHash = &local_lmNewHash;
 			}
-			return NT_STATUS_PASSWORD_RESTRICTION;
+			
 		}
-		ntNewHash = &local_ntNewHash;
 	}
 
-	if (user_change) {
+	if (restrictions && user_change) {
 		/* are all password changes disallowed? */
 		if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
 			if (reject_reason) {
@@ -1731,16 +1746,15 @@ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
 
 	/* the password is acceptable. Start forming the new fields */
-	if (new_pass) {
-		/* if we know the cleartext, then only set it.
+	if (new_password) {
+		/* if we know the cleartext UTF16 password, then set it.
 		 * Modules in ldb will set all the appropriate
 		 * hashes */
-		CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod, 
-					       "userPassword", new_pass));
+		CHECK_RET(ldb_msg_add_value(mod, "clearTextPassword", new_password, NULL));
 	} else {
 		/* We don't have the cleartext, so delete the old one
 		 * and set what we have of the hashes */
-		CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "userPassword"));
+		CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "clearTextPassword"));
 
 		if (lmNewHash) {
 			CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
@@ -1769,7 +1783,7 @@ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
 */
 NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
 				const struct dom_sid *user_sid,
-				const char *new_pass,
+				const DATA_BLOB *new_pass,
 				struct samr_Password *lmNewHash, 
 				struct samr_Password *ntNewHash,
 				bool user_change,
diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c
index e610c35..7d00851 100644
--- a/source4/dsdb/samdb/ldb_modules/objectclass.c
+++ b/source4/dsdb/samdb/ldb_modules/objectclass.c
@@ -382,11 +382,17 @@ static int fix_attributes(struct ldb_context *ldb, const struct dsdb_schema *sch
 	int i;
 	for (i=0; i < msg->num_elements; i++) {
 		const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(schema, msg->elements[i].name);
+		/* Add in a very special case for 'clearTextPassword',
+		 * which is used for internal processing only, and is
+		 * not presented in the schema */
 		if (!attribute) {
-			ldb_asprintf_errstring(ldb, "attribute %s is not a valid attribute in schema", msg->elements[i].name);
-			return LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE;
+			if (strcasecmp(msg->elements[i].name, "clearTextPassword") != 0) {
+				ldb_asprintf_errstring(ldb, "attribute %s is not a valid attribute in schema", msg->elements[i].name);
+				return LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE;
+			}
+		} else {
+			msg->elements[i].name = attribute->lDAPDisplayName;
 		}
-		msg->elements[i].name = attribute->lDAPDisplayName;
 	}
 
 	return LDB_SUCCESS;
diff --git a/source4/dsdb/samdb/ldb_modules/password_hash.c b/source4/dsdb/samdb/ldb_modules/password_hash.c
index e36de3c..c4451d1 100644
--- a/source4/dsdb/samdb/ldb_modules/password_hash.c
+++ b/source4/dsdb/samdb/ldb_modules/password_hash.c
@@ -109,7 +109,8 @@ struct setup_password_fields_io {
 
 	/* new credentials */
 	struct {
-		const char *cleartext;
+		const struct ldb_val *cleartext_utf8;
+		const struct ldb_val *cleartext_utf16;
 		struct samr_Password *nt_hash;
 		struct samr_Password *lm_hash;
 	} n;
@@ -144,6 +145,9 @@ struct setup_password_fields_io {
 	} g;
 };
 
+/* Get the NT hash, and fill it in as an entry in the password history, 
+   and specify it into io->g.nt_hash */
+
 static int setup_nt_fields(struct setup_password_fields_io *io)
 {
 	uint32_t i;
@@ -181,6 +185,9 @@ static int setup_nt_fields(struct setup_password_fields_io *io)
 	return LDB_SUCCESS;
 }
 
+/* Get the LANMAN hash, and fill it in as an entry in the password history, 
+   and specify it into io->g.lm_hash */
+
 static int setup_lm_fields(struct setup_password_fields_io *io)
 {
 	uint32_t i;
@@ -220,6 +227,10 @@ static int setup_kerberos_keys(struct setup_password_fields_io *io)
 	Principal *salt_principal;
 	krb5_salt salt;
 	krb5_keyblock key;
+	krb5_data cleartext_data;
+
+	cleartext_data.data = io->n.cleartext_utf8->data;
+	cleartext_data.length = io->n.cleartext_utf8->length;
 
 	/* Many, many thanks to lukeh at padl.com for this
 	 * algorithm, described in his Nov 10 2004 mail to
@@ -314,11 +325,11 @@ static int setup_kerberos_keys(struct setup_password_fields_io *io)
 	 * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of
 	 * the salt and the cleartext password
 	 */
-	krb5_ret = krb5_string_to_key_salt(io->smb_krb5_context->krb5_context,
-					   ENCTYPE_AES256_CTS_HMAC_SHA1_96,
-					   io->n.cleartext,
-					   salt,
-					   &key);
+	krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
+						ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+						cleartext_data,
+						salt,
+						&key);
 	if (krb5_ret) {
 		ldb_asprintf_errstring(io->ac->module->ldb,
 				       "setup_kerberos_keys: "
@@ -339,11 +350,11 @@ static int setup_kerberos_keys(struct setup_password_fields_io *io)
 	 * create ENCTYPE_AES128_CTS_HMAC_SHA1_96 key out of
 	 * the salt and the cleartext password
 	 */
-	krb5_ret = krb5_string_to_key_salt(io->smb_krb5_context->krb5_context,
-					   ENCTYPE_AES128_CTS_HMAC_SHA1_96,
-					   io->n.cleartext,
-					   salt,
-					   &key);
+	krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
+						ENCTYPE_AES128_CTS_HMAC_SHA1_96,
+						cleartext_data,
+						salt,
+						&key);
 	if (krb5_ret) {
 		ldb_asprintf_errstring(io->ac->module->ldb,
 				       "setup_kerberos_keys: "
@@ -364,11 +375,11 @@ static int setup_kerberos_keys(struct setup_password_fields_io *io)
 	 * create ENCTYPE_DES_CBC_MD5 key out of
 	 * the salt and the cleartext password
 	 */
-	krb5_ret = krb5_string_to_key_salt(io->smb_krb5_context->krb5_context,
-					   ENCTYPE_DES_CBC_MD5,
-					   io->n.cleartext,
-					   salt,
-					   &key);
+	krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
+						ENCTYPE_DES_CBC_MD5,
+						cleartext_data,
+						salt,
+						&key);
 	if (krb5_ret) {
 		ldb_asprintf_errstring(io->ac->module->ldb,
 				       "setup_kerberos_keys: "
@@ -389,11 +400,11 @@ static int setup_kerberos_keys(struct setup_password_fields_io *io)
 	 * create ENCTYPE_DES_CBC_CRC key out of
 	 * the salt and the cleartext password
 	 */
-	krb5_ret = krb5_string_to_key_salt(io->smb_krb5_context->krb5_context,
-					   ENCTYPE_DES_CBC_CRC,
-					   io->n.cleartext,
-					   salt,
-					   &key);
+	krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
+						ENCTYPE_DES_CBC_CRC,
+						cleartext_data,
+						salt,
+						&key);
 	if (krb5_ret) {
 		ldb_asprintf_errstring(io->ac->module->ldb,
 				       "setup_kerberos_keys: "
@@ -648,7 +659,6 @@ static int setup_primary_wdigest(struct setup_password_fields_io *io,
 	DATA_BLOB dns_domain;
 	DATA_BLOB dns_domain_l;
 	DATA_BLOB dns_domain_u;
-	DATA_BLOB cleartext;
 	DATA_BLOB digest;
 	DATA_BLOB delim;
 	DATA_BLOB backslash;
@@ -929,8 +939,6 @@ static int setup_primary_wdigest(struct setup_password_fields_io *io,
 	dns_domain_l		= data_blob_string_const(io->domain->dns_domain);
 	dns_domain_u		= data_blob_string_const(io->domain->realm);
 
-	cleartext		= data_blob_string_const(io->n.cleartext);
-
 	digest			= data_blob_string_const("Digest");
 
 	delim			= data_blob_string_const(":");
@@ -956,7 +964,7 @@ static int setup_primary_wdigest(struct setup_password_fields_io *io,
 			MD5Update(&md5, wdigest[i].realm->data, wdigest[i].realm->length);
 		}
 		MD5Update(&md5, delim.data, delim.length);
-		MD5Update(&md5, cleartext.data, cleartext.length);
+		MD5Update(&md5, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length);
 		MD5Final(pdb->hashes[i].hash, &md5);
 	}
 
@@ -1011,7 +1019,7 @@ static int setup_supplemental_field(struct setup_password_fields_io *io)
 	ZERO_STRUCT(zero16);
 	ZERO_STRUCT(names);
 
-	if (!io->n.cleartext) {
+	if (!io->n.cleartext_utf8) {
 		/* 
 		 * when we don't have a cleartext password
 		 * we can't setup a supplementalCredential value
@@ -1193,7 +1201,7 @@ static int setup_supplemental_field(struct setup_password_fields_io *io)
 	if (pc) {
 		*nc		= "CLEARTEXT";
 
-		pcb.cleartext	= io->n.cleartext;
+		pcb.cleartext	= *io->n.cleartext_utf16;
 
 		ndr_err = ndr_push_struct_blob(&pcb_blob, io->ac, 
 					       lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
@@ -1285,58 +1293,97 @@ static int setup_password_fields(struct setup_password_fields_io *io)
 {
 	bool ok;
 	int ret;
-
+	ssize_t converted_pw_len;
+		
 	/*
 	 * refuse the change if someone want to change the cleartext
 	 * and supply his own hashes at the same time...
 	 */
-	if (io->n.cleartext && (io->n.nt_hash || io->n.lm_hash)) {
+	if ((io->n.cleartext_utf8 || io->n.cleartext_utf16) && (io->n.nt_hash || io->n.lm_hash)) {
 		ldb_asprintf_errstring(io->ac->module->ldb,
 				       "setup_password_fields: "
 				       "it's only allowed to set the cleartext password or the password hashes");
 		return LDB_ERR_UNWILLING_TO_PERFORM;
 	}
-
-	if (io->n.cleartext) {
-		struct samr_Password *hash;
-
-		hash = talloc(io->ac, struct samr_Password);
-		if (!hash) {
+	
+	if (io->n.cleartext_utf8 && io->n.cleartext_utf16) {
+		ldb_asprintf_errstring(io->ac->module->ldb,
+				       "setup_password_fields: "
+				       "it's only allowed to set the cleartext password as userPassword or clearTextPasssword, not both at once");
+		return LDB_ERR_UNWILLING_TO_PERFORM;
+	}
+	
+	if (io->n.cleartext_utf8) {
+		char **cleartext_utf16_str;
+		struct ldb_val *cleartext_utf16_blob;
+		io->n.cleartext_utf16 = cleartext_utf16_blob = talloc(io->ac, struct ldb_val);
+		if (!io->n.cleartext_utf16) {
 			ldb_oom(io->ac->module->ldb);
 			return LDB_ERR_OPERATIONS_ERROR;
 		}
-
-		/* compute the new nt hash */
-		ok = E_md4hash(io->n.cleartext, hash->hash);
-		if (ok) {
-			io->n.nt_hash = hash;
-		} else {
+		converted_pw_len = convert_string_talloc(io->ac, lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")), 
+							 CH_UTF8, CH_UTF16, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length, 
+							 (void **)&cleartext_utf16_str);
+		if (converted_pw_len == -1) {
 			ldb_asprintf_errstring(io->ac->module->ldb,
 					       "setup_password_fields: "
-					       "failed to generate nthash from cleartext password");
+					       "failed to generate UTF16 password from cleartext UTF8 password");
+			return LDB_ERR_OPERATIONS_ERROR;
+		}
+		*cleartext_utf16_blob = data_blob_const(cleartext_utf16_str, converted_pw_len);
+	} else if (io->n.cleartext_utf16) {
+		char *cleartext_utf8_str;
+		struct ldb_val *cleartext_utf8_blob;
+		io->n.cleartext_utf8 = cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
+		if (!io->n.cleartext_utf8) {
+			ldb_oom(io->ac->module->ldb);
 			return LDB_ERR_OPERATIONS_ERROR;
 		}
+		converted_pw_len = convert_string_talloc(io->ac, lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")), 
+							 CH_UTF16, CH_UTF8, io->n.cleartext_utf16->data, io->n.cleartext_utf16->length, 
+							 (void **)&cleartext_utf8_str);
+		if (converted_pw_len == -1) {
+			/* We can't bail out entirely, as these unconvertable passwords are frustratingly valid */
+			io->n.cleartext_utf8 = NULL;	
+			talloc_free(cleartext_utf8_blob);
+		}
+		*cleartext_utf8_blob = data_blob_const(cleartext_utf8_str, converted_pw_len);
 	}
-
-	if (io->n.cleartext) {
-		struct samr_Password *hash;
-
-		hash = talloc(io->ac, struct samr_Password);
-		if (!hash) {
+	if (io->n.cleartext_utf16) {
+		struct samr_Password *nt_hash;
+		nt_hash = talloc(io->ac, struct samr_Password);
+		if (!nt_hash) {
 			ldb_oom(io->ac->module->ldb);
 			return LDB_ERR_OPERATIONS_ERROR;
 		}
+		io->n.nt_hash = nt_hash;
 
-		/* compute the new lm hash */
-		ok = E_deshash(io->n.cleartext, hash->hash);
-		if (ok) {
-			io->n.lm_hash = hash;
-		} else {
-			talloc_free(hash->hash);
-		}
+		/* compute the new nt hash */
+		mdfour(nt_hash->hash, io->n.cleartext_utf16->data, io->n.cleartext_utf16->length);
 	}
 
-	if (io->n.cleartext) {
+	if (io->n.cleartext_utf8) {
+		struct samr_Password *lm_hash;
+		char *cleartext_unix;
+		converted_pw_len = convert_string_talloc(io->ac, lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")), 
+							 CH_UTF8, CH_UNIX, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length, 
+							 (void **)&cleartext_unix);
+		if (converted_pw_len != -1) {
+			lm_hash = talloc(io->ac, struct samr_Password);
+			if (!lm_hash) {
+				ldb_oom(io->ac->module->ldb);
+				return LDB_ERR_OPERATIONS_ERROR;
+			}
+			
+			/* compute the new lm hash.   */
+			ok = E_deshash((char *)cleartext_unix, lm_hash->hash);
+			if (ok) {
+				io->n.lm_hash = lm_hash;
+			} else {
+				talloc_free(lm_hash->hash);
+			}
+		}
+
 		ret = setup_kerberos_keys(io);
 		if (ret != 0) {
 			return ret;
@@ -1560,6 +1607,7 @@ static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
 {
 	struct ph_context *ac;
 	struct ldb_message_element *sambaAttr;
+	struct ldb_message_element *clearTextPasswordAttr;
 	struct ldb_message_element *ntAttr;
 	struct ldb_message_element *lmAttr;
 	int ret;
@@ -1591,6 +1639,7 @@ static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
 	 * or LM hashes, then we don't need to make any changes.  */
 
 	sambaAttr = ldb_msg_find_element(req->op.mod.message, "userPassword");
+	clearTextPasswordAttr = ldb_msg_find_element(req->op.mod.message, "clearTextPassword");
 	ntAttr = ldb_msg_find_element(req->op.mod.message, "unicodePwd");
 	lmAttr = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
 
@@ -1611,6 +1660,10 @@ static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
 		ldb_set_errstring(module->ldb, "mupltiple values for userPassword not allowed!\n");
 		return LDB_ERR_CONSTRAINT_VIOLATION;


-- 
Samba Shared Repository


More information about the samba-cvs mailing list