summaryrefslogtreecommitdiff
path: root/source4/dsdb
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2008-10-16 12:48:16 +1100
committerAndrew Bartlett <abartlet@samba.org>2008-10-16 12:48:16 +1100
commit7c88ea8aadfc2be0726cbe555543cfab8804c470 (patch)
tree56f84c94f69e06880c6ad416117f0a1d7e7f5882 /source4/dsdb
parentfc54ca014b21b655b643697475c6a0c05e773fc4 (diff)
downloadsamba-7c88ea8aadfc2be0726cbe555543cfab8804c470.tar.gz
samba-7c88ea8aadfc2be0726cbe555543cfab8804c470.tar.bz2
samba-7c88ea8aadfc2be0726cbe555543cfab8804c470.zip
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
Diffstat (limited to 'source4/dsdb')
-rw-r--r--source4/dsdb/common/util.c88
-rw-r--r--source4/dsdb/samdb/ldb_modules/objectclass.c12
-rw-r--r--source4/dsdb/samdb/ldb_modules/password_hash.c195
3 files changed, 192 insertions, 103 deletions
diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c
index 5b93efb316..0a87c5ffe1 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 e610c358f6..7d00851792 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 e36de3c5c4..c4451d1355 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@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;
}
+ if (clearTextPasswordAttr && clearTextPasswordAttr->num_values > 1) {
+ ldb_set_errstring(module->ldb, "mupltiple values for clearTextPassword not allowed!\n");
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
if (ntAttr && (ntAttr->num_values > 1)) {
ldb_set_errstring(module->ldb, "mupltiple values for unicodePwd not allowed!\n");
@@ -1626,6 +1679,11 @@ static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
return LDB_ERR_CONSTRAINT_VIOLATION;
}
+ if (clearTextPasswordAttr && clearTextPasswordAttr->num_values == 0) {
+ ldb_set_errstring(module->ldb, "clearTextPassword must have a value!\n");
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+
if (ntAttr && (ntAttr->num_values == 0)) {
ldb_set_errstring(module->ldb, "unicodePwd must have a value!\n");
return LDB_ERR_CONSTRAINT_VIOLATION;
@@ -1687,12 +1745,14 @@ static int password_hash_add_do_add(struct ph_context *ac) {
io.u.user_principal_name = samdb_result_string(msg, "userPrincipalName", NULL);
io.u.is_computer = ldb_msg_check_string_attribute(msg, "objectClass", "computer");
- io.n.cleartext = samdb_result_string(msg, "userPassword", NULL);
+ io.n.cleartext_utf8 = ldb_msg_find_ldb_val(msg, "userPassword");
+ io.n.cleartext_utf16 = ldb_msg_find_ldb_val(msg, "clearTextPassword");
io.n.nt_hash = samdb_result_hash(io.ac, msg, "unicodePwd");
io.n.lm_hash = samdb_result_hash(io.ac, msg, "dBCSPwd");
/* remove attributes */
- if (io.n.cleartext) ldb_msg_remove_attr(msg, "userPassword");
+ if (io.n.cleartext_utf8) ldb_msg_remove_attr(msg, "userPassword");
+ if (io.n.cleartext_utf16) ldb_msg_remove_attr(msg, "clearTextPassword");
if (io.n.nt_hash) ldb_msg_remove_attr(msg, "unicodePwd");
if (io.n.lm_hash) ldb_msg_remove_attr(msg, "dBCSPwd");
ldb_msg_remove_attr(msg, "pwdLastSet");
@@ -1772,6 +1832,7 @@ static int password_hash_modify(struct ldb_module *module, struct ldb_request *r
{
struct ph_context *ac;
struct ldb_message_element *sambaAttr;
+ struct ldb_message_element *clearTextAttr;
struct ldb_message_element *ntAttr;
struct ldb_message_element *lmAttr;
struct ldb_message *msg;
@@ -1802,13 +1863,16 @@ static int password_hash_modify(struct ldb_module *module, struct ldb_request *r
}
sambaAttr = ldb_msg_find_element(req->op.mod.message, "userPassword");
+ clearTextAttr = 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");
- /* If no part of this touches the userPassword OR unicodePwd and/or dBCSPwd, then we don't
- * need to make any changes. For password changes/set there should
- * be a 'delete' or a 'modify' on this attribute. */
- if ((!sambaAttr) && (!ntAttr) && (!lmAttr)) {
+ /* If no part of this touches the userPassword OR
+ * clearTextPassword OR unicodePwd and/or dBCSPwd, then we
+ * don't need to make any changes. For password changes/set
+ * there should be a 'delete' or a 'modify' on this
+ * attribute. */
+ if ((!sambaAttr) && (!clearTextAttr) && (!ntAttr) && (!lmAttr)) {
return ldb_next_request(module, req);
}
@@ -1817,6 +1881,9 @@ static int password_hash_modify(struct ldb_module *module, struct ldb_request *r
if (sambaAttr && (sambaAttr->num_values > 1)) {
return LDB_ERR_CONSTRAINT_VIOLATION;
}
+ if (clearTextAttr && (clearTextAttr->num_values > 1)) {
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
if (ntAttr && (ntAttr->num_values > 1)) {
return LDB_ERR_CONSTRAINT_VIOLATION;
}
@@ -1839,6 +1906,7 @@ static int password_hash_modify(struct ldb_module *module, struct ldb_request *r
/* - remove any modification to the password from the first commit
* we will make the real modification later */
if (sambaAttr) ldb_msg_remove_attr(msg, "userPassword");
+ if (clearTextAttr) ldb_msg_remove_attr(msg, "clearTextPassword");
if (ntAttr) ldb_msg_remove_attr(msg, "unicodePwd");
if (lmAttr) ldb_msg_remove_attr(msg, "dBCSPwd");
@@ -2028,7 +2096,8 @@ static int password_hash_mod_do_mod(struct ph_context *ac) {
io.u.user_principal_name = samdb_result_string(searched_msg, "userPrincipalName", NULL);
io.u.is_computer = ldb_msg_check_string_attribute(searched_msg, "objectClass", "computer");
- io.n.cleartext = samdb_result_string(orig_msg, "userPassword", NULL);
+ io.n.cleartext_utf8 = ldb_msg_find_ldb_val(orig_msg, "userPassword");
+ io.n.cleartext_utf16 = ldb_msg_find_ldb_val(orig_msg, "clearTextPassword");
io.n.nt_hash = samdb_result_hash(io.ac, orig_msg, "unicodePwd");
io.n.lm_hash = samdb_result_hash(io.ac, orig_msg, "dBCSPwd");