summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2009-07-09 14:53:26 +1000
committerAndrew Bartlett <abartlet@samba.org>2009-07-09 14:56:14 +1000
commit2481ce89427ef38b47fb29d16c15b77e9d2c20b9 (patch)
treebd71b508f409250a09f65005bc98b7d685f8fe62
parent2c873c43534d61cd411b5c8d56425fd9c2ddd128 (diff)
downloadsamba-2481ce89427ef38b47fb29d16c15b77e9d2c20b9.tar.gz
samba-2481ce89427ef38b47fb29d16c15b77e9d2c20b9.tar.bz2
samba-2481ce89427ef38b47fb29d16c15b77e9d2c20b9.zip
s4:dsdb Allow unicodePwd to be set when adding a user
Windows 7 sets it's join password using the unicodePwd attribute (as a quoted, utf16 string), and does so during the LDAPAdd of the object. Previously, this code only handled unicodePwd for modifies. Andrew Bartlett
-rw-r--r--source4/dsdb/samdb/ldb_modules/password_hash.c169
1 files changed, 84 insertions, 85 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/password_hash.c b/source4/dsdb/samdb/ldb_modules/password_hash.c
index 5a9926b6d1..44b7ef91e9 100644
--- a/source4/dsdb/samdb/ldb_modules/password_hash.c
+++ b/source4/dsdb/samdb/ldb_modules/password_hash.c
@@ -1432,6 +1432,67 @@ static int setup_password_fields(struct setup_password_fields_io *io)
return LDB_SUCCESS;
}
+static int setup_io(struct ph_context *ac,
+ const struct ldb_message *new_msg,
+ const struct ldb_message *searched_msg,
+ struct setup_password_fields_io *io)
+{
+ const struct ldb_val *quoted_utf16;
+ struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
+
+ ZERO_STRUCTP(io);
+
+ /* Some operations below require kerberos contexts */
+ if (smb_krb5_init_context(ac,
+ ldb_get_event_context(ldb),
+ (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"),
+ &io->smb_krb5_context) != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ io->ac = ac;
+ io->domain = ac->domain;
+
+ io->u.user_account_control = samdb_result_uint(searched_msg, "userAccountControl", 0);
+ io->u.sAMAccountName = samdb_result_string(searched_msg, "samAccountName", NULL);
+ 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_utf8 = ldb_msg_find_ldb_val(new_msg, "userPassword");
+ io->n.cleartext_utf16 = ldb_msg_find_ldb_val(new_msg, "clearTextPassword");
+
+ /* this rather strange looking piece of code is there to
+ handle a ldap client setting a password remotely using the
+ unicodePwd ldap field. The syntax is that the password is
+ in UTF-16LE, with a " at either end. Unfortunately the
+ unicodePwd field is also used to store the nt hashes
+ internally in Samba, and is used in the nt hash format on
+ the wire in DRS replication, so we have a single name for
+ two distinct values. The code below leaves us with a small
+ chance (less than 1 in 2^32) of a mixup, if someone manages
+ to create a MD4 hash which starts and ends in 0x22 0x00, as
+ that would then be treated as a UTF16 password rather than
+ a nthash */
+ quoted_utf16 = ldb_msg_find_ldb_val(new_msg, "unicodePwd");
+ if (quoted_utf16 &&
+ quoted_utf16->length >= 4 &&
+ quoted_utf16->data[0] == '"' &&
+ quoted_utf16->data[1] == 0 &&
+ quoted_utf16->data[quoted_utf16->length-2] == '"' &&
+ quoted_utf16->data[quoted_utf16->length-1] == 0) {
+ io->n.quoted_utf16.data = talloc_memdup(io->ac, quoted_utf16->data+2, quoted_utf16->length-4);
+ io->n.quoted_utf16.length = quoted_utf16->length-4;
+ io->n.cleartext_utf16 = &io->n.quoted_utf16;
+ io->n.nt_hash = NULL;
+ } else {
+ io->n.nt_hash = samdb_result_hash(io->ac, new_msg, "unicodePwd");
+ }
+
+ io->n.lm_hash = samdb_result_hash(io->ac, new_msg, "dBCSPwd");
+
+ return LDB_SUCCESS;
+}
+
static struct ph_context *ph_init_context(struct ldb_module *module,
struct ldb_request *req)
{
@@ -1743,50 +1804,32 @@ static int password_hash_add_do_add(struct ph_context *ac)
{
struct ldb_context *ldb;
struct ldb_request *down_req;
- struct smb_krb5_context *smb_krb5_context;
struct ldb_message *msg;
struct setup_password_fields_io io;
int ret;
- ldb = ldb_module_get_ctx(ac->module);
+ /* Prepare the internal data structure containing the passwords */
+ ret = setup_io(ac, ac->req->op.add.message, ac->req->op.add.message, &io);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
if (msg == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
- /* Some operations below require kerberos contexts */
- if (smb_krb5_init_context(ac,
- ldb_get_event_context(ldb),
- (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"),
- &smb_krb5_context) != 0) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- ZERO_STRUCT(io);
- io.ac = ac;
- io.domain = ac->domain;
- io.smb_krb5_context = smb_krb5_context;
-
- io.u.user_account_control = samdb_result_uint(msg, "userAccountControl", 0);
- io.u.sAMAccountName = samdb_result_string(msg, "samAccountName", NULL);
- 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_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_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");
+ /* remove attributes that we just read into 'io' */
+ ldb_msg_remove_attr(msg, "userPassword");
+ ldb_msg_remove_attr(msg, "clearTextPassword");
+ ldb_msg_remove_attr(msg, "unicodePwd");
+ ldb_msg_remove_attr(msg, "dBCSPwd");
ldb_msg_remove_attr(msg, "pwdLastSet");
io.o.kvno = samdb_result_uint(msg, "msDs-KeyVersionNumber", 1) - 1;
ldb_msg_remove_attr(msg, "msDs-KeyVersionNumber");
+ ldb = ldb_module_get_ctx(ac->module);
+
ret = setup_password_fields(&io);
if (ret != LDB_SUCCESS) {
return ret;
@@ -2096,12 +2139,9 @@ static int password_hash_mod_do_mod(struct ph_context *ac)
{
struct ldb_context *ldb;
struct ldb_request *mod_req;
- struct smb_krb5_context *smb_krb5_context;
struct ldb_message *msg;
- struct ldb_message *orig_msg;
- struct ldb_message *searched_msg;
+ const struct ldb_message *searched_msg;
struct setup_password_fields_io io;
- const struct ldb_val *quoted_utf16;
int ret;
ldb = ldb_module_get_ctx(ac->module);
@@ -2115,59 +2155,18 @@ static int password_hash_mod_do_mod(struct ph_context *ac)
/* modify dn */
msg->dn = ac->req->op.mod.message->dn;
- /* Some operations below require kerberos contexts */
- if (smb_krb5_init_context(ac,
- ldb_get_event_context(ldb),
- (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"),
- &smb_krb5_context) != 0) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- orig_msg = discard_const(ac->req->op.mod.message);
- searched_msg = ac->search_res->message;
-
- ZERO_STRUCT(io);
- io.ac = ac;
- io.domain = ac->domain;
- io.smb_krb5_context = smb_krb5_context;
-
- io.u.user_account_control = samdb_result_uint(searched_msg, "userAccountControl", 0);
- io.u.sAMAccountName = samdb_result_string(searched_msg, "samAccountName", NULL);
- 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_utf8 = ldb_msg_find_ldb_val(orig_msg, "userPassword");
- io.n.cleartext_utf16 = ldb_msg_find_ldb_val(orig_msg, "clearTextPassword");
-
- /* this rather strange looking piece of code is there to
- handle a ldap client setting a password remotely using the
- unicodePwd ldap field. The syntax is that the password is
- in UTF-16LE, with a " at either end. Unfortunately the
- unicodePwd field is also used to store the nt hashes
- internally in Samba, and is used in the nt hash format on
- the wire in DRS replication, so we have a single name for
- two distinct values. The code below leaves us with a small
- chance (less than 1 in 2^32) of a mixup, if someone manages
- to create a MD4 hash which starts and ends in 0x22 0x00, as
- that would then be treated as a UTF16 password rather than
- a nthash */
- quoted_utf16 = ldb_msg_find_ldb_val(orig_msg, "unicodePwd");
- if (quoted_utf16 &&
- quoted_utf16->length >= 4 &&
- quoted_utf16->data[0] == '"' &&
- quoted_utf16->data[1] == 0 &&
- quoted_utf16->data[quoted_utf16->length-2] == '"' &&
- quoted_utf16->data[quoted_utf16->length-1] == 0) {
- io.n.quoted_utf16.data = talloc_memdup(orig_msg, quoted_utf16->data+2, quoted_utf16->length-4);
- io.n.quoted_utf16.length = quoted_utf16->length-4;
- io.n.cleartext_utf16 = &io.n.quoted_utf16;
- io.n.nt_hash = NULL;
- } else {
- io.n.nt_hash = samdb_result_hash(io.ac, orig_msg, "unicodePwd");
+ /* Prepare the internal data structure containing the passwords */
+ ret = setup_io(ac,
+ ac->req->op.mod.message,
+ ac->search_res->message,
+ &io);
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
+
+ searched_msg = ac->search_res->message;
- io.n.lm_hash = samdb_result_hash(io.ac, orig_msg, "dBCSPwd");
-
+ /* Fill in some final details (only relevent once the password has been set) */
io.o.kvno = samdb_result_uint(searched_msg, "msDs-KeyVersionNumber", 0);
io.o.nt_history_len = samdb_result_hashes(io.ac, searched_msg, "ntPwdHistory", &io.o.nt_history);
io.o.lm_history_len = samdb_result_hashes(io.ac, searched_msg, "lmPwdHistory", &io.o.lm_history);