4 Copyright (C) Simo Sorce 2004-2008
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2006
6 Copyright (C) Andrew Tridgell 2004
7 Copyright (C) Stefan Metzmacher 2007
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 * Component: ldb password_hash module
28 * Description: correctly update hash values based on changes to userPassword and friends
30 * Author: Andrew Bartlett
31 * Author: Stefan Metzmacher
35 #include "libcli/ldap/ldap_ndr.h"
36 #include "ldb_module.h"
37 #include "librpc/gen_ndr/misc.h"
38 #include "librpc/gen_ndr/samr.h"
39 #include "libcli/auth/libcli_auth.h"
40 #include "libcli/security/security.h"
41 #include "system/kerberos.h"
42 #include "auth/kerberos/kerberos.h"
43 #include "system/time.h"
44 #include "dsdb/samdb/samdb.h"
45 #include "dsdb/common/flags.h"
46 #include "dsdb/samdb/ldb_modules/password_modules.h"
47 #include "librpc/ndr/libndr.h"
48 #include "librpc/gen_ndr/ndr_drsblobs.h"
49 #include "../lib/crypto/crypto.h"
50 #include "param/param.h"
52 /* If we have decided there is reason to work on this request, then
53 * setup all the password hash types correctly.
55 * If the administrator doesn't want the userPassword stored (set in the
56 * domain and per-account policies) then we must strip that out before
57 * we do the first operation.
59 * Once this is done (which could update anything at all), we
60 * calculate the password hashes.
62 * This function must not only update the unicodePwd, dBCSPwd and
63 * supplementalCredentials fields, it must also atomicly increment the
64 * msDS-KeyVersionNumber. We should be in a transaction, so all this
65 * should be quite safe...
67 * Finally, if the administrator has requested that a password history
68 * be maintained, then this should also be written out.
74 struct ldb_module *module;
75 struct ldb_request *req;
77 struct ldb_request *dom_req;
78 struct ldb_reply *dom_res;
80 struct ldb_reply *search_res;
82 struct dom_sid *domain_sid;
83 struct domain_data *domain;
89 uint_t pwdHistoryLength;
95 struct setup_password_fields_io {
96 struct ph_context *ac;
97 struct domain_data *domain;
98 struct smb_krb5_context *smb_krb5_context;
100 /* infos about the user account */
102 uint32_t user_account_control;
103 const char *sAMAccountName;
104 const char *user_principal_name;
108 /* new credentials */
110 const struct ldb_val *cleartext_utf8;
111 const struct ldb_val *cleartext_utf16;
112 struct ldb_val quoted_utf16;
113 struct samr_Password *nt_hash;
114 struct samr_Password *lm_hash;
117 /* old credentials */
119 uint32_t nt_history_len;
120 struct samr_Password *nt_history;
121 uint32_t lm_history_len;
122 struct samr_Password *lm_history;
123 const struct ldb_val *supplemental;
124 struct supplementalCredentialsBlob scb;
128 /* generated credentials */
130 struct samr_Password *nt_hash;
131 struct samr_Password *lm_hash;
132 uint32_t nt_history_len;
133 struct samr_Password *nt_history;
134 uint32_t lm_history_len;
135 struct samr_Password *lm_history;
141 struct ldb_val supplemental;
147 /* Get the NT hash, and fill it in as an entry in the password history,
148 and specify it into io->g.nt_hash */
150 static int setup_nt_fields(struct setup_password_fields_io *io)
152 struct ldb_context *ldb;
155 io->g.nt_hash = io->n.nt_hash;
156 ldb = ldb_module_get_ctx(io->ac->module);
158 if (io->domain->pwdHistoryLength == 0) {
162 /* We might not have an old NT password */
163 io->g.nt_history = talloc_array(io->ac,
164 struct samr_Password,
165 io->domain->pwdHistoryLength);
166 if (!io->g.nt_history) {
168 return LDB_ERR_OPERATIONS_ERROR;
171 for (i = 0; i < MIN(io->domain->pwdHistoryLength-1, io->o.nt_history_len); i++) {
172 io->g.nt_history[i+1] = io->o.nt_history[i];
174 io->g.nt_history_len = i + 1;
177 io->g.nt_history[0] = *io->g.nt_hash;
180 * TODO: is this correct?
181 * the simular behavior is correct for the lm history case
183 E_md4hash("", io->g.nt_history[0].hash);
189 /* Get the LANMAN hash, and fill it in as an entry in the password history,
190 and specify it into io->g.lm_hash */
192 static int setup_lm_fields(struct setup_password_fields_io *io)
194 struct ldb_context *ldb;
197 io->g.lm_hash = io->n.lm_hash;
198 ldb = ldb_module_get_ctx(io->ac->module);
200 if (io->domain->pwdHistoryLength == 0) {
204 /* We might not have an old NT password */
205 io->g.lm_history = talloc_array(io->ac,
206 struct samr_Password,
207 io->domain->pwdHistoryLength);
208 if (!io->g.lm_history) {
210 return LDB_ERR_OPERATIONS_ERROR;
213 for (i = 0; i < MIN(io->domain->pwdHistoryLength-1, io->o.lm_history_len); i++) {
214 io->g.lm_history[i+1] = io->o.lm_history[i];
216 io->g.lm_history_len = i + 1;
219 io->g.lm_history[0] = *io->g.lm_hash;
221 E_deshash("", io->g.lm_history[0].hash);
227 static int setup_kerberos_keys(struct setup_password_fields_io *io)
229 struct ldb_context *ldb;
230 krb5_error_code krb5_ret;
231 Principal *salt_principal;
234 krb5_data cleartext_data;
236 ldb = ldb_module_get_ctx(io->ac->module);
237 cleartext_data.data = io->n.cleartext_utf8->data;
238 cleartext_data.length = io->n.cleartext_utf8->length;
240 /* Many, many thanks to lukeh@padl.com for this
241 * algorithm, described in his Nov 10 2004 mail to
242 * samba-technical@samba.org */
245 * Determine a salting principal
247 if (io->u.is_computer) {
251 name = talloc_strdup(io->ac, io->u.sAMAccountName);
254 return LDB_ERR_OPERATIONS_ERROR;
257 if (name[strlen(name)-1] == '$') {
258 name[strlen(name)-1] = '\0';
261 saltbody = talloc_asprintf(io->ac, "%s.%s", name, io->domain->dns_domain);
264 return LDB_ERR_OPERATIONS_ERROR;
267 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
269 io->domain->realm, "host",
271 } else if (io->u.user_principal_name) {
272 char *user_principal_name;
275 user_principal_name = talloc_strdup(io->ac, io->u.user_principal_name);
276 if (!user_principal_name) {
278 return LDB_ERR_OPERATIONS_ERROR;
281 p = strchr(user_principal_name, '@');
286 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
288 io->domain->realm, user_principal_name,
291 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
293 io->domain->realm, io->u.sAMAccountName,
297 ldb_asprintf_errstring(ldb,
298 "setup_kerberos_keys: "
299 "generation of a salting principal failed: %s",
300 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
301 return LDB_ERR_OPERATIONS_ERROR;
305 * create salt from salt_principal
307 krb5_ret = krb5_get_pw_salt(io->smb_krb5_context->krb5_context,
308 salt_principal, &salt);
309 krb5_free_principal(io->smb_krb5_context->krb5_context, salt_principal);
311 ldb_asprintf_errstring(ldb,
312 "setup_kerberos_keys: "
313 "generation of krb5_salt failed: %s",
314 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
315 return LDB_ERR_OPERATIONS_ERROR;
317 /* create a talloc copy */
318 io->g.salt = talloc_strndup(io->ac,
320 salt.saltvalue.length);
321 krb5_free_salt(io->smb_krb5_context->krb5_context, salt);
324 return LDB_ERR_OPERATIONS_ERROR;
326 salt.saltvalue.data = discard_const(io->g.salt);
327 salt.saltvalue.length = strlen(io->g.salt);
330 * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of
331 * the salt and the cleartext password
333 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
334 ENCTYPE_AES256_CTS_HMAC_SHA1_96,
339 ldb_asprintf_errstring(ldb,
340 "setup_kerberos_keys: "
341 "generation of a aes256-cts-hmac-sha1-96 key failed: %s",
342 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
343 return LDB_ERR_OPERATIONS_ERROR;
345 io->g.aes_256 = data_blob_talloc(io->ac,
347 key.keyvalue.length);
348 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
349 if (!io->g.aes_256.data) {
351 return LDB_ERR_OPERATIONS_ERROR;
355 * create ENCTYPE_AES128_CTS_HMAC_SHA1_96 key out of
356 * the salt and the cleartext password
358 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
359 ENCTYPE_AES128_CTS_HMAC_SHA1_96,
364 ldb_asprintf_errstring(ldb,
365 "setup_kerberos_keys: "
366 "generation of a aes128-cts-hmac-sha1-96 key failed: %s",
367 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
368 return LDB_ERR_OPERATIONS_ERROR;
370 io->g.aes_128 = data_blob_talloc(io->ac,
372 key.keyvalue.length);
373 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
374 if (!io->g.aes_128.data) {
376 return LDB_ERR_OPERATIONS_ERROR;
380 * create ENCTYPE_DES_CBC_MD5 key out of
381 * the salt and the cleartext password
383 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
389 ldb_asprintf_errstring(ldb,
390 "setup_kerberos_keys: "
391 "generation of a des-cbc-md5 key failed: %s",
392 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
393 return LDB_ERR_OPERATIONS_ERROR;
395 io->g.des_md5 = data_blob_talloc(io->ac,
397 key.keyvalue.length);
398 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
399 if (!io->g.des_md5.data) {
401 return LDB_ERR_OPERATIONS_ERROR;
405 * create ENCTYPE_DES_CBC_CRC key out of
406 * the salt and the cleartext password
408 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
414 ldb_asprintf_errstring(ldb,
415 "setup_kerberos_keys: "
416 "generation of a des-cbc-crc key failed: %s",
417 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
418 return LDB_ERR_OPERATIONS_ERROR;
420 io->g.des_crc = data_blob_talloc(io->ac,
422 key.keyvalue.length);
423 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
424 if (!io->g.des_crc.data) {
426 return LDB_ERR_OPERATIONS_ERROR;
432 static int setup_primary_kerberos(struct setup_password_fields_io *io,
433 const struct supplementalCredentialsBlob *old_scb,
434 struct package_PrimaryKerberosBlob *pkb)
436 struct ldb_context *ldb;
437 struct package_PrimaryKerberosCtr3 *pkb3 = &pkb->ctr.ctr3;
438 struct supplementalCredentialsPackage *old_scp = NULL;
439 struct package_PrimaryKerberosBlob _old_pkb;
440 struct package_PrimaryKerberosCtr3 *old_pkb3 = NULL;
442 enum ndr_err_code ndr_err;
444 ldb = ldb_module_get_ctx(io->ac->module);
447 * prepare generation of keys
449 * ENCTYPE_DES_CBC_MD5
450 * ENCTYPE_DES_CBC_CRC
453 pkb3->salt.string = io->g.salt;
455 pkb3->keys = talloc_array(io->ac,
456 struct package_PrimaryKerberosKey3,
460 return LDB_ERR_OPERATIONS_ERROR;
463 pkb3->keys[0].keytype = ENCTYPE_DES_CBC_MD5;
464 pkb3->keys[0].value = &io->g.des_md5;
465 pkb3->keys[1].keytype = ENCTYPE_DES_CBC_CRC;
466 pkb3->keys[1].value = &io->g.des_crc;
468 /* initialize the old keys to zero */
469 pkb3->num_old_keys = 0;
470 pkb3->old_keys = NULL;
472 /* if there're no old keys, then we're done */
477 for (i=0; i < old_scb->sub.num_packages; i++) {
478 if (strcmp("Primary:Kerberos", old_scb->sub.packages[i].name) != 0) {
482 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
486 old_scp = &old_scb->sub.packages[i];
489 /* Primary:Kerberos element of supplementalCredentials */
493 blob = strhex_to_data_blob(io->ac, old_scp->data);
496 return LDB_ERR_OPERATIONS_ERROR;
499 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
500 ndr_err = ndr_pull_struct_blob(&blob, io->ac, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &_old_pkb,
501 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
502 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
503 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
504 ldb_asprintf_errstring(ldb,
505 "setup_primary_kerberos: "
506 "failed to pull old package_PrimaryKerberosBlob: %s",
508 return LDB_ERR_OPERATIONS_ERROR;
511 if (_old_pkb.version != 3) {
512 ldb_asprintf_errstring(ldb,
513 "setup_primary_kerberos: "
514 "package_PrimaryKerberosBlob version[%u] expected[3]",
516 return LDB_ERR_OPERATIONS_ERROR;
519 old_pkb3 = &_old_pkb.ctr.ctr3;
522 /* if we didn't found the old keys we're done */
527 /* fill in the old keys */
528 pkb3->num_old_keys = old_pkb3->num_keys;
529 pkb3->old_keys = old_pkb3->keys;
534 static int setup_primary_kerberos_newer(struct setup_password_fields_io *io,
535 const struct supplementalCredentialsBlob *old_scb,
536 struct package_PrimaryKerberosBlob *pkb)
538 struct ldb_context *ldb;
539 struct package_PrimaryKerberosCtr4 *pkb4 = &pkb->ctr.ctr4;
540 struct supplementalCredentialsPackage *old_scp = NULL;
541 struct package_PrimaryKerberosBlob _old_pkb;
542 struct package_PrimaryKerberosCtr4 *old_pkb4 = NULL;
544 enum ndr_err_code ndr_err;
546 ldb = ldb_module_get_ctx(io->ac->module);
549 * prepare generation of keys
551 * ENCTYPE_AES256_CTS_HMAC_SHA1_96
552 * ENCTYPE_AES128_CTS_HMAC_SHA1_96
553 * ENCTYPE_DES_CBC_MD5
554 * ENCTYPE_DES_CBC_CRC
557 pkb4->salt.string = io->g.salt;
558 pkb4->default_iteration_count = 4096;
561 pkb4->keys = talloc_array(io->ac,
562 struct package_PrimaryKerberosKey4,
566 return LDB_ERR_OPERATIONS_ERROR;
569 pkb4->keys[0].iteration_count = 4096;
570 pkb4->keys[0].keytype = ENCTYPE_AES256_CTS_HMAC_SHA1_96;
571 pkb4->keys[0].value = &io->g.aes_256;
572 pkb4->keys[1].iteration_count = 4096;
573 pkb4->keys[1].keytype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
574 pkb4->keys[1].value = &io->g.aes_128;
575 pkb4->keys[2].iteration_count = 4096;
576 pkb4->keys[2].keytype = ENCTYPE_DES_CBC_MD5;
577 pkb4->keys[2].value = &io->g.des_md5;
578 pkb4->keys[3].iteration_count = 4096;
579 pkb4->keys[3].keytype = ENCTYPE_DES_CBC_CRC;
580 pkb4->keys[3].value = &io->g.des_crc;
582 /* initialize the old keys to zero */
583 pkb4->num_old_keys = 0;
584 pkb4->old_keys = NULL;
585 pkb4->num_older_keys = 0;
586 pkb4->older_keys = NULL;
588 /* if there're no old keys, then we're done */
593 for (i=0; i < old_scb->sub.num_packages; i++) {
594 if (strcmp("Primary:Kerberos-Newer-Keys", old_scb->sub.packages[i].name) != 0) {
598 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
602 old_scp = &old_scb->sub.packages[i];
605 /* Primary:Kerberos-Newer-Keys element of supplementalCredentials */
609 blob = strhex_to_data_blob(io->ac, old_scp->data);
612 return LDB_ERR_OPERATIONS_ERROR;
615 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
616 ndr_err = ndr_pull_struct_blob(&blob, io->ac,
617 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
619 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
620 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
621 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
622 ldb_asprintf_errstring(ldb,
623 "setup_primary_kerberos_newer: "
624 "failed to pull old package_PrimaryKerberosBlob: %s",
626 return LDB_ERR_OPERATIONS_ERROR;
629 if (_old_pkb.version != 4) {
630 ldb_asprintf_errstring(ldb,
631 "setup_primary_kerberos_newer: "
632 "package_PrimaryKerberosBlob version[%u] expected[4]",
634 return LDB_ERR_OPERATIONS_ERROR;
637 old_pkb4 = &_old_pkb.ctr.ctr4;
640 /* if we didn't found the old keys we're done */
645 /* fill in the old keys */
646 pkb4->num_old_keys = old_pkb4->num_keys;
647 pkb4->old_keys = old_pkb4->keys;
648 pkb4->num_older_keys = old_pkb4->num_old_keys;
649 pkb4->older_keys = old_pkb4->old_keys;
654 static int setup_primary_wdigest(struct setup_password_fields_io *io,
655 const struct supplementalCredentialsBlob *old_scb,
656 struct package_PrimaryWDigestBlob *pdb)
658 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
659 DATA_BLOB sAMAccountName;
660 DATA_BLOB sAMAccountName_l;
661 DATA_BLOB sAMAccountName_u;
662 const char *user_principal_name = io->u.user_principal_name;
663 DATA_BLOB userPrincipalName;
664 DATA_BLOB userPrincipalName_l;
665 DATA_BLOB userPrincipalName_u;
666 DATA_BLOB netbios_domain;
667 DATA_BLOB netbios_domain_l;
668 DATA_BLOB netbios_domain_u;
669 DATA_BLOB dns_domain;
670 DATA_BLOB dns_domain_l;
671 DATA_BLOB dns_domain_u;
683 * http://technet2.microsoft.com/WindowsServer/en/library/717b450c-f4a0-4cc9-86f4-cc0633aae5f91033.mspx?mfr=true
684 * for what precalculated hashes are supposed to be stored...
686 * I can't reproduce all values which should contain "Digest" as realm,
687 * am I doing something wrong or is w2k3 just broken...?
689 * W2K3 fills in following for a user:
691 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
692 * sAMAccountName: NewUser2Sam
693 * userPrincipalName: NewUser2Princ@sub1.w2k3.vmnet1.vm.base
695 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
696 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
697 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
698 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
699 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
700 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
701 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
702 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
703 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
704 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
705 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
706 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
707 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
708 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
709 * 221c55284451ae9b3aacaa2a3c86f10f => NewUser2Princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
710 * 74e1be668853d4324d38c07e2acfb8ea => (w2k3 has a bug here!) newuser2princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
711 * e1e244ab7f098e3ae1761be7f9229bbb => NEWUSER2PRINC@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
712 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
713 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
714 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
715 * 31dc704d3640335b2123d4ee28aa1f11 => ??? changes with NewUser2Sam => NewUser1Sam
716 * 36349f5cecd07320fb3bb0e119230c43 => ??? changes with NewUser2Sam => NewUser1Sam
717 * 12adf019d037fb535c01fd0608e78d9d => ??? changes with NewUser2Sam => NewUser1Sam
718 * 6feecf8e724906f3ee1105819c5105a1 => ??? changes with NewUser2Princ => NewUser1Princ
719 * 6c6911f3de6333422640221b9c51ff1f => ??? changes with NewUser2Princ => NewUser1Princ
720 * 4b279877e742895f9348ac67a8de2f69 => ??? changes with NewUser2Princ => NewUser1Princ
721 * db0c6bff069513e3ebb9870d29b57490 => ??? changes with NewUser2Sam => NewUser1Sam
722 * 45072621e56b1c113a4e04a8ff68cd0e => ??? changes with NewUser2Sam => NewUser1Sam
723 * 11d1220abc44a9c10cf91ef4a9c1de02 => ??? changes with NewUser2Sam => NewUser1Sam
725 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
726 * sAMAccountName: NewUser2Sam
728 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
729 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
730 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
731 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
732 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
733 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
734 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
735 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
736 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
737 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
738 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
739 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
740 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
741 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
742 * 8a140d30b6f0a5912735dc1e3bc993b4 => NewUser2Sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
743 * 86d95b2faae6cae4ec261e7fbaccf093 => (here w2k3 is correct) newuser2sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
744 * dfeff1493110220efcdfc6362e5f5450 => NEWUSER2SAM@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
745 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
746 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
747 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
748 * 31dc704d3640335b2123d4ee28aa1f11 => ???M1 changes with NewUser2Sam => NewUser1Sam
749 * 36349f5cecd07320fb3bb0e119230c43 => ???M1.L changes with newuser2sam => newuser1sam
750 * 12adf019d037fb535c01fd0608e78d9d => ???M1.U changes with NEWUSER2SAM => NEWUSER1SAM
751 * 569b4533f2d9e580211dd040e5e360a8 => ???M2 changes with NewUser2Princ => NewUser1Princ
752 * 52528bddf310a587c5d7e6a9ae2cbb20 => ???M2.L changes with newuser2princ => newuser1princ
753 * 4f629a4f0361289ca4255ab0f658fcd5 => ???M3 changes with NewUser2Princ => NewUser1Princ (doesn't depend on case of userPrincipal )
754 * db0c6bff069513e3ebb9870d29b57490 => ???M4 changes with NewUser2Sam => NewUser1Sam
755 * 45072621e56b1c113a4e04a8ff68cd0e => ???M5 changes with NewUser2Sam => NewUser1Sam (doesn't depend on case of sAMAccountName)
756 * 11d1220abc44a9c10cf91ef4a9c1de02 => ???M4.U changes with NEWUSER2SAM => NEWUSER1SAM
760 * sAMAccountName, netbios_domain
763 .user = &sAMAccountName,
764 .realm = &netbios_domain,
767 .user = &sAMAccountName_l,
768 .realm = &netbios_domain_l,
771 .user = &sAMAccountName_u,
772 .realm = &netbios_domain_u,
775 .user = &sAMAccountName,
776 .realm = &netbios_domain_u,
779 .user = &sAMAccountName,
780 .realm = &netbios_domain_l,
783 .user = &sAMAccountName_u,
784 .realm = &netbios_domain_l,
787 .user = &sAMAccountName_l,
788 .realm = &netbios_domain_u,
791 * sAMAccountName, dns_domain
794 .user = &sAMAccountName,
795 .realm = &dns_domain,
798 .user = &sAMAccountName_l,
799 .realm = &dns_domain_l,
802 .user = &sAMAccountName_u,
803 .realm = &dns_domain_u,
806 .user = &sAMAccountName,
807 .realm = &dns_domain_u,
810 .user = &sAMAccountName,
811 .realm = &dns_domain_l,
814 .user = &sAMAccountName_u,
815 .realm = &dns_domain_l,
818 .user = &sAMAccountName_l,
819 .realm = &dns_domain_u,
822 * userPrincipalName, no realm
825 .user = &userPrincipalName,
829 * NOTE: w2k3 messes this up, if the user has a real userPrincipalName,
830 * the fallback to the sAMAccountName based userPrincipalName is correct
832 .user = &userPrincipalName_l,
835 .user = &userPrincipalName_u,
838 * nt4dom\sAMAccountName, no realm
841 .user = &sAMAccountName,
842 .nt4dom = &netbios_domain
845 .user = &sAMAccountName_l,
846 .nt4dom = &netbios_domain_l
849 .user = &sAMAccountName_u,
850 .nt4dom = &netbios_domain_u
854 * the following ones are guessed depending on the technet2 article
855 * but not reproducable on a w2k3 server
857 /* sAMAccountName with "Digest" realm */
859 .user = &sAMAccountName,
863 .user = &sAMAccountName_l,
867 .user = &sAMAccountName_u,
870 /* userPrincipalName with "Digest" realm */
872 .user = &userPrincipalName,
876 .user = &userPrincipalName_l,
880 .user = &userPrincipalName_u,
883 /* nt4dom\\sAMAccountName with "Digest" realm */
885 .user = &sAMAccountName,
886 .nt4dom = &netbios_domain,
890 .user = &sAMAccountName_l,
891 .nt4dom = &netbios_domain_l,
895 .user = &sAMAccountName_u,
896 .nt4dom = &netbios_domain_u,
901 /* prepare DATA_BLOB's used in the combinations array */
902 sAMAccountName = data_blob_string_const(io->u.sAMAccountName);
903 sAMAccountName_l = data_blob_string_const(strlower_talloc(io->ac, io->u.sAMAccountName));
904 if (!sAMAccountName_l.data) {
906 return LDB_ERR_OPERATIONS_ERROR;
908 sAMAccountName_u = data_blob_string_const(strupper_talloc(io->ac, io->u.sAMAccountName));
909 if (!sAMAccountName_u.data) {
911 return LDB_ERR_OPERATIONS_ERROR;
914 /* if the user doesn't have a userPrincipalName, create one (with lower case realm) */
915 if (!user_principal_name) {
916 user_principal_name = talloc_asprintf(io->ac, "%s@%s",
917 io->u.sAMAccountName,
918 io->domain->dns_domain);
919 if (!user_principal_name) {
921 return LDB_ERR_OPERATIONS_ERROR;
924 userPrincipalName = data_blob_string_const(user_principal_name);
925 userPrincipalName_l = data_blob_string_const(strlower_talloc(io->ac, user_principal_name));
926 if (!userPrincipalName_l.data) {
928 return LDB_ERR_OPERATIONS_ERROR;
930 userPrincipalName_u = data_blob_string_const(strupper_talloc(io->ac, user_principal_name));
931 if (!userPrincipalName_u.data) {
933 return LDB_ERR_OPERATIONS_ERROR;
936 netbios_domain = data_blob_string_const(io->domain->netbios_domain);
937 netbios_domain_l = data_blob_string_const(strlower_talloc(io->ac, io->domain->netbios_domain));
938 if (!netbios_domain_l.data) {
940 return LDB_ERR_OPERATIONS_ERROR;
942 netbios_domain_u = data_blob_string_const(strupper_talloc(io->ac, io->domain->netbios_domain));
943 if (!netbios_domain_u.data) {
945 return LDB_ERR_OPERATIONS_ERROR;
948 dns_domain = data_blob_string_const(io->domain->dns_domain);
949 dns_domain_l = data_blob_string_const(io->domain->dns_domain);
950 dns_domain_u = data_blob_string_const(io->domain->realm);
952 digest = data_blob_string_const("Digest");
954 delim = data_blob_string_const(":");
955 backslash = data_blob_string_const("\\");
957 pdb->num_hashes = ARRAY_SIZE(wdigest);
958 pdb->hashes = talloc_array(io->ac, struct package_PrimaryWDigestHash, pdb->num_hashes);
961 return LDB_ERR_OPERATIONS_ERROR;
964 for (i=0; i < ARRAY_SIZE(wdigest); i++) {
965 struct MD5Context md5;
967 if (wdigest[i].nt4dom) {
968 MD5Update(&md5, wdigest[i].nt4dom->data, wdigest[i].nt4dom->length);
969 MD5Update(&md5, backslash.data, backslash.length);
971 MD5Update(&md5, wdigest[i].user->data, wdigest[i].user->length);
972 MD5Update(&md5, delim.data, delim.length);
973 if (wdigest[i].realm) {
974 MD5Update(&md5, wdigest[i].realm->data, wdigest[i].realm->length);
976 MD5Update(&md5, delim.data, delim.length);
977 MD5Update(&md5, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length);
978 MD5Final(pdb->hashes[i].hash, &md5);
984 static int setup_supplemental_field(struct setup_password_fields_io *io)
986 struct ldb_context *ldb;
987 struct supplementalCredentialsBlob scb;
988 struct supplementalCredentialsBlob _old_scb;
989 struct supplementalCredentialsBlob *old_scb = NULL;
990 /* Packages + (Kerberos-Newer-Keys, Kerberos, WDigest and CLEARTEXT) */
991 uint32_t num_names = 0;
992 const char *names[1+4];
993 uint32_t num_packages = 0;
994 struct supplementalCredentialsPackage packages[1+4];
996 struct supplementalCredentialsPackage *pp = NULL;
997 struct package_PackagesBlob pb;
1000 /* Primary:Kerberos-Newer-Keys */
1001 const char **nkn = NULL;
1002 struct supplementalCredentialsPackage *pkn = NULL;
1003 struct package_PrimaryKerberosBlob pknb;
1004 DATA_BLOB pknb_blob;
1006 /* Primary:Kerberos */
1007 const char **nk = NULL;
1008 struct supplementalCredentialsPackage *pk = NULL;
1009 struct package_PrimaryKerberosBlob pkb;
1012 /* Primary:WDigest */
1013 const char **nd = NULL;
1014 struct supplementalCredentialsPackage *pd = NULL;
1015 struct package_PrimaryWDigestBlob pdb;
1018 /* Primary:CLEARTEXT */
1019 const char **nc = NULL;
1020 struct supplementalCredentialsPackage *pc = NULL;
1021 struct package_PrimaryCLEARTEXTBlob pcb;
1025 enum ndr_err_code ndr_err;
1027 bool do_newer_keys = false;
1028 bool do_cleartext = false;
1030 ZERO_STRUCT(zero16);
1033 ldb = ldb_module_get_ctx(io->ac->module);
1035 if (!io->n.cleartext_utf8) {
1037 * when we don't have a cleartext password
1038 * we can't setup a supplementalCredential value
1043 /* if there's an old supplementaCredentials blob then parse it */
1044 if (io->o.supplemental) {
1045 ndr_err = ndr_pull_struct_blob_all(io->o.supplemental, io->ac,
1046 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1048 (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
1049 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1050 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1051 ldb_asprintf_errstring(ldb,
1052 "setup_supplemental_field: "
1053 "failed to pull old supplementalCredentialsBlob: %s",
1055 return LDB_ERR_OPERATIONS_ERROR;
1058 if (_old_scb.sub.signature == SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
1059 old_scb = &_old_scb;
1061 ldb_debug(ldb, LDB_DEBUG_ERROR,
1062 "setup_supplemental_field: "
1063 "supplementalCredentialsBlob signature[0x%04X] expected[0x%04X]",
1064 _old_scb.sub.signature, SUPPLEMENTAL_CREDENTIALS_SIGNATURE);
1068 /* TODO: do the correct check for this, it maybe depends on the functional level? */
1069 do_newer_keys = lp_parm_bool(ldb_get_opaque(ldb, "loadparm"),
1070 NULL, "password_hash", "create_aes_key", false);
1072 if (io->domain->store_cleartext &&
1073 (io->u.user_account_control & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) {
1074 do_cleartext = true;
1078 * The ordering is this
1080 * Primary:Kerberos-Newer-Keys (optional)
1083 * Primary:CLEARTEXT (optional)
1085 * And the 'Packages' package is insert before the last
1088 if (do_newer_keys) {
1089 /* Primary:Kerberos-Newer-Keys */
1090 nkn = &names[num_names++];
1091 pkn = &packages[num_packages++];
1094 /* Primary:Kerberos */
1095 nk = &names[num_names++];
1096 pk = &packages[num_packages++];
1098 if (!do_cleartext) {
1100 pp = &packages[num_packages++];
1103 /* Primary:WDigest */
1104 nd = &names[num_names++];
1105 pd = &packages[num_packages++];
1109 pp = &packages[num_packages++];
1111 /* Primary:CLEARTEXT */
1112 nc = &names[num_names++];
1113 pc = &packages[num_packages++];
1118 * setup 'Primary:Kerberos-Newer-Keys' element
1120 *nkn = "Kerberos-Newer-Keys";
1122 ret = setup_primary_kerberos_newer(io, old_scb, &pknb);
1123 if (ret != LDB_SUCCESS) {
1127 ndr_err = ndr_push_struct_blob(&pknb_blob, io->ac,
1128 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1130 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1131 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1132 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1133 ldb_asprintf_errstring(ldb,
1134 "setup_supplemental_field: "
1135 "failed to push package_PrimaryKerberosNeverBlob: %s",
1137 return LDB_ERR_OPERATIONS_ERROR;
1139 pknb_hexstr = data_blob_hex_string(io->ac, &pknb_blob);
1142 return LDB_ERR_OPERATIONS_ERROR;
1144 pkn->name = "Primary:Kerberos-Newer-Keys";
1146 pkn->data = pknb_hexstr;
1150 * setup 'Primary:Kerberos' element
1154 ret = setup_primary_kerberos(io, old_scb, &pkb);
1155 if (ret != LDB_SUCCESS) {
1159 ndr_err = ndr_push_struct_blob(&pkb_blob, io->ac,
1160 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1162 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1163 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1164 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1165 ldb_asprintf_errstring(ldb,
1166 "setup_supplemental_field: "
1167 "failed to push package_PrimaryKerberosBlob: %s",
1169 return LDB_ERR_OPERATIONS_ERROR;
1171 pkb_hexstr = data_blob_hex_string(io->ac, &pkb_blob);
1174 return LDB_ERR_OPERATIONS_ERROR;
1176 pk->name = "Primary:Kerberos";
1178 pk->data = pkb_hexstr;
1181 * setup 'Primary:WDigest' element
1185 ret = setup_primary_wdigest(io, old_scb, &pdb);
1186 if (ret != LDB_SUCCESS) {
1190 ndr_err = ndr_push_struct_blob(&pdb_blob, io->ac,
1191 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1193 (ndr_push_flags_fn_t)ndr_push_package_PrimaryWDigestBlob);
1194 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1195 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1196 ldb_asprintf_errstring(ldb,
1197 "setup_supplemental_field: "
1198 "failed to push package_PrimaryWDigestBlob: %s",
1200 return LDB_ERR_OPERATIONS_ERROR;
1202 pdb_hexstr = data_blob_hex_string(io->ac, &pdb_blob);
1205 return LDB_ERR_OPERATIONS_ERROR;
1207 pd->name = "Primary:WDigest";
1209 pd->data = pdb_hexstr;
1212 * setup 'Primary:CLEARTEXT' element
1217 pcb.cleartext = *io->n.cleartext_utf16;
1219 ndr_err = ndr_push_struct_blob(&pcb_blob, io->ac,
1220 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1222 (ndr_push_flags_fn_t)ndr_push_package_PrimaryCLEARTEXTBlob);
1223 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1224 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1225 ldb_asprintf_errstring(ldb,
1226 "setup_supplemental_field: "
1227 "failed to push package_PrimaryCLEARTEXTBlob: %s",
1229 return LDB_ERR_OPERATIONS_ERROR;
1231 pcb_hexstr = data_blob_hex_string(io->ac, &pcb_blob);
1234 return LDB_ERR_OPERATIONS_ERROR;
1236 pc->name = "Primary:CLEARTEXT";
1238 pc->data = pcb_hexstr;
1242 * setup 'Packages' element
1245 ndr_err = ndr_push_struct_blob(&pb_blob, io->ac,
1246 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1248 (ndr_push_flags_fn_t)ndr_push_package_PackagesBlob);
1249 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1250 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1251 ldb_asprintf_errstring(ldb,
1252 "setup_supplemental_field: "
1253 "failed to push package_PackagesBlob: %s",
1255 return LDB_ERR_OPERATIONS_ERROR;
1257 pb_hexstr = data_blob_hex_string(io->ac, &pb_blob);
1260 return LDB_ERR_OPERATIONS_ERROR;
1262 pp->name = "Packages";
1264 pp->data = pb_hexstr;
1267 * setup 'supplementalCredentials' value
1270 scb.sub.num_packages = num_packages;
1271 scb.sub.packages = packages;
1273 ndr_err = ndr_push_struct_blob(&io->g.supplemental, io->ac,
1274 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1276 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
1277 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1278 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1279 ldb_asprintf_errstring(ldb,
1280 "setup_supplemental_field: "
1281 "failed to push supplementalCredentialsBlob: %s",
1283 return LDB_ERR_OPERATIONS_ERROR;
1289 static int setup_last_set_field(struct setup_password_fields_io *io)
1292 unix_to_nt_time(&io->g.last_set, time(NULL));
1297 static int setup_kvno_field(struct setup_password_fields_io *io)
1299 /* increment by one */
1300 io->g.kvno = io->o.kvno + 1;
1305 static int setup_password_fields(struct setup_password_fields_io *io)
1307 struct ldb_context *ldb;
1310 ssize_t converted_pw_len;
1312 ldb = ldb_module_get_ctx(io->ac->module);
1315 * refuse the change if someone want to change the cleartext
1316 * and supply his own hashes at the same time...
1318 if ((io->n.cleartext_utf8 || io->n.cleartext_utf16) && (io->n.nt_hash || io->n.lm_hash)) {
1319 ldb_asprintf_errstring(ldb,
1320 "setup_password_fields: "
1321 "it's only allowed to set the cleartext password or the password hashes");
1322 return LDB_ERR_UNWILLING_TO_PERFORM;
1325 if (io->n.cleartext_utf8 && io->n.cleartext_utf16) {
1326 ldb_asprintf_errstring(ldb,
1327 "setup_password_fields: "
1328 "it's only allowed to set the cleartext password as userPassword or clearTextPasssword, not both at once");
1329 return LDB_ERR_UNWILLING_TO_PERFORM;
1332 if (io->n.cleartext_utf8) {
1333 char **cleartext_utf16_str;
1334 struct ldb_val *cleartext_utf16_blob;
1335 io->n.cleartext_utf16 = cleartext_utf16_blob = talloc(io->ac, struct ldb_val);
1336 if (!io->n.cleartext_utf16) {
1338 return LDB_ERR_OPERATIONS_ERROR;
1340 converted_pw_len = convert_string_talloc_convenience(io->ac, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1341 CH_UTF8, CH_UTF16, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length,
1342 (void **)&cleartext_utf16_str);
1343 if (converted_pw_len == -1) {
1344 ldb_asprintf_errstring(ldb,
1345 "setup_password_fields: "
1346 "failed to generate UTF16 password from cleartext UTF8 password");
1347 return LDB_ERR_OPERATIONS_ERROR;
1349 *cleartext_utf16_blob = data_blob_const(cleartext_utf16_str, converted_pw_len);
1350 } else if (io->n.cleartext_utf16) {
1351 char *cleartext_utf8_str;
1352 struct ldb_val *cleartext_utf8_blob;
1353 io->n.cleartext_utf8 = cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
1354 if (!io->n.cleartext_utf8) {
1356 return LDB_ERR_OPERATIONS_ERROR;
1358 converted_pw_len = convert_string_talloc_convenience(io->ac, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1359 CH_UTF16MUNGED, CH_UTF8, io->n.cleartext_utf16->data, io->n.cleartext_utf16->length,
1360 (void **)&cleartext_utf8_str);
1361 if (converted_pw_len == -1) {
1362 /* We can't bail out entirely, as these unconvertable passwords are frustratingly valid */
1363 io->n.cleartext_utf8 = NULL;
1364 talloc_free(cleartext_utf8_blob);
1366 *cleartext_utf8_blob = data_blob_const(cleartext_utf8_str, converted_pw_len);
1368 if (io->n.cleartext_utf16) {
1369 struct samr_Password *nt_hash;
1370 nt_hash = talloc(io->ac, struct samr_Password);
1373 return LDB_ERR_OPERATIONS_ERROR;
1375 io->n.nt_hash = nt_hash;
1377 /* compute the new nt hash */
1378 mdfour(nt_hash->hash, io->n.cleartext_utf16->data, io->n.cleartext_utf16->length);
1381 if (io->n.cleartext_utf8) {
1382 struct samr_Password *lm_hash;
1383 char *cleartext_unix;
1384 converted_pw_len = convert_string_talloc_convenience(io->ac, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1385 CH_UTF8, CH_UNIX, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length,
1386 (void **)&cleartext_unix);
1387 if (converted_pw_len != -1) {
1388 lm_hash = talloc(io->ac, struct samr_Password);
1391 return LDB_ERR_OPERATIONS_ERROR;
1394 /* compute the new lm hash. */
1395 ok = E_deshash((char *)cleartext_unix, lm_hash->hash);
1397 io->n.lm_hash = lm_hash;
1399 talloc_free(lm_hash->hash);
1403 ret = setup_kerberos_keys(io);
1409 ret = setup_nt_fields(io);
1414 ret = setup_lm_fields(io);
1419 ret = setup_supplemental_field(io);
1424 ret = setup_last_set_field(io);
1429 ret = setup_kvno_field(io);
1437 static struct ph_context *ph_init_context(struct ldb_module *module,
1438 struct ldb_request *req)
1440 struct ldb_context *ldb;
1441 struct ph_context *ac;
1443 ldb = ldb_module_get_ctx(module);
1445 ac = talloc_zero(req, struct ph_context);
1447 ldb_set_errstring(ldb, "Out of Memory");
1451 ac->module = module;
1457 static int ph_op_callback(struct ldb_request *req, struct ldb_reply *ares)
1459 struct ph_context *ac;
1461 ac = talloc_get_type(req->context, struct ph_context);
1464 return ldb_module_done(ac->req, NULL, NULL,
1465 LDB_ERR_OPERATIONS_ERROR);
1467 if (ares->error != LDB_SUCCESS) {
1468 return ldb_module_done(ac->req, ares->controls,
1469 ares->response, ares->error);
1472 if (ares->type != LDB_REPLY_DONE) {
1474 return ldb_module_done(ac->req, NULL, NULL,
1475 LDB_ERR_OPERATIONS_ERROR);
1478 return ldb_module_done(ac->req, ares->controls,
1479 ares->response, ares->error);
1482 static int password_hash_add_do_add(struct ph_context *ac);
1483 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares);
1484 static int password_hash_mod_search_self(struct ph_context *ac);
1485 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares);
1486 static int password_hash_mod_do_mod(struct ph_context *ac);
1488 static int get_domain_data_callback(struct ldb_request *req,
1489 struct ldb_reply *ares)
1491 struct ldb_context *ldb;
1492 struct domain_data *data;
1493 struct ph_context *ac;
1498 ac = talloc_get_type(req->context, struct ph_context);
1499 ldb = ldb_module_get_ctx(ac->module);
1502 return ldb_module_done(ac->req, NULL, NULL,
1503 LDB_ERR_OPERATIONS_ERROR);
1505 if (ares->error != LDB_SUCCESS) {
1506 return ldb_module_done(ac->req, ares->controls,
1507 ares->response, ares->error);
1510 switch (ares->type) {
1511 case LDB_REPLY_ENTRY:
1512 if (ac->domain != NULL) {
1513 ldb_set_errstring(ldb, "Too many results");
1514 return ldb_module_done(ac->req, NULL, NULL,
1515 LDB_ERR_OPERATIONS_ERROR);
1518 data = talloc_zero(ac, struct domain_data);
1520 return ldb_module_done(ac->req, NULL, NULL,
1521 LDB_ERR_OPERATIONS_ERROR);
1524 data->pwdProperties = samdb_result_uint(ares->message, "pwdProperties", 0);
1525 data->store_cleartext = data->pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
1526 data->pwdHistoryLength = samdb_result_uint(ares->message, "pwdHistoryLength", 0);
1528 /* For a domain DN, this puts things in dotted notation */
1529 /* For builtin domains, this will give details for the host,
1530 * but that doesn't really matter, as it's just used for salt
1531 * and kerberos principals, which don't exist here */
1533 tmp = ldb_dn_canonical_string(data, ares->message->dn);
1535 return ldb_module_done(ac->req, NULL, NULL,
1536 LDB_ERR_OPERATIONS_ERROR);
1539 /* But it puts a trailing (or just before 'builtin') / on things, so kill that */
1540 p = strchr(tmp, '/');
1545 data->dns_domain = strlower_talloc(data, tmp);
1546 if (data->dns_domain == NULL) {
1548 return ldb_module_done(ac->req, NULL, NULL,
1549 LDB_ERR_OPERATIONS_ERROR);
1551 data->realm = strupper_talloc(data, tmp);
1552 if (data->realm == NULL) {
1554 return ldb_module_done(ac->req, NULL, NULL,
1555 LDB_ERR_OPERATIONS_ERROR);
1557 /* FIXME: NetbIOS name is *always* the first domain component ?? -SSS */
1558 p = strchr(tmp, '.');
1562 data->netbios_domain = strupper_talloc(data, tmp);
1563 if (data->netbios_domain == NULL) {
1565 return ldb_module_done(ac->req, NULL, NULL,
1566 LDB_ERR_OPERATIONS_ERROR);
1573 case LDB_REPLY_DONE:
1575 /* call the next step */
1576 switch (ac->req->operation) {
1578 ret = password_hash_add_do_add(ac);
1582 ret = password_hash_mod_do_mod(ac);
1586 ret = LDB_ERR_OPERATIONS_ERROR;
1589 if (ret != LDB_SUCCESS) {
1590 return ldb_module_done(ac->req, NULL, NULL, ret);
1593 case LDB_REPLY_REFERRAL:
1602 static int build_domain_data_request(struct ph_context *ac)
1604 /* attrs[] is returned from this function in
1605 ac->dom_req->op.search.attrs, so it must be static, as
1606 otherwise the compiler can put it on the stack */
1607 struct ldb_context *ldb;
1608 static const char * const attrs[] = { "pwdProperties", "pwdHistoryLength", NULL };
1611 ldb = ldb_module_get_ctx(ac->module);
1613 filter = talloc_asprintf(ac,
1614 "(&(objectSid=%s)(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain)))",
1615 ldap_encode_ndr_dom_sid(ac, ac->domain_sid));
1616 if (filter == NULL) {
1618 return LDB_ERR_OPERATIONS_ERROR;
1621 return ldb_build_search_req(&ac->dom_req, ldb, ac,
1622 ldb_get_default_basedn(ldb),
1626 ac, get_domain_data_callback,
1630 static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
1632 struct ldb_context *ldb;
1633 struct ph_context *ac;
1634 struct ldb_message_element *sambaAttr;
1635 struct ldb_message_element *clearTextPasswordAttr;
1636 struct ldb_message_element *ntAttr;
1637 struct ldb_message_element *lmAttr;
1640 ldb = ldb_module_get_ctx(module);
1642 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add\n");
1644 if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
1645 return ldb_next_request(module, req);
1648 /* If the caller is manipulating the local passwords directly, let them pass */
1649 if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
1650 req->op.add.message->dn) == 0) {
1651 return ldb_next_request(module, req);
1654 /* nobody must touch these fields */
1655 if (ldb_msg_find_element(req->op.add.message, "ntPwdHistory")) {
1656 return LDB_ERR_UNWILLING_TO_PERFORM;
1658 if (ldb_msg_find_element(req->op.add.message, "lmPwdHistory")) {
1659 return LDB_ERR_UNWILLING_TO_PERFORM;
1661 if (ldb_msg_find_element(req->op.add.message, "supplementalCredentials")) {
1662 return LDB_ERR_UNWILLING_TO_PERFORM;
1665 /* If no part of this ADD touches the userPassword, or the NT
1666 * or LM hashes, then we don't need to make any changes. */
1668 sambaAttr = ldb_msg_find_element(req->op.mod.message, "userPassword");
1669 clearTextPasswordAttr = ldb_msg_find_element(req->op.mod.message, "clearTextPassword");
1670 ntAttr = ldb_msg_find_element(req->op.mod.message, "unicodePwd");
1671 lmAttr = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
1673 if ((!sambaAttr) && (!clearTextPasswordAttr) && (!ntAttr) && (!lmAttr)) {
1674 return ldb_next_request(module, req);
1677 /* if it is not an entry of type person its an error */
1678 /* TODO: remove this when userPassword will be in schema */
1679 if (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "person")) {
1680 ldb_set_errstring(ldb, "Cannot set a password on entry that does not have objectClass 'person'");
1681 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1684 /* check userPassword is single valued here */
1685 /* TODO: remove this when userPassword will be single valued in schema */
1686 if (sambaAttr && sambaAttr->num_values > 1) {
1687 ldb_set_errstring(ldb, "mupltiple values for userPassword not allowed!\n");
1688 return LDB_ERR_CONSTRAINT_VIOLATION;
1690 if (clearTextPasswordAttr && clearTextPasswordAttr->num_values > 1) {
1691 ldb_set_errstring(ldb, "mupltiple values for clearTextPassword not allowed!\n");
1692 return LDB_ERR_CONSTRAINT_VIOLATION;
1695 if (ntAttr && (ntAttr->num_values > 1)) {
1696 ldb_set_errstring(ldb, "mupltiple values for unicodePwd not allowed!\n");
1697 return LDB_ERR_CONSTRAINT_VIOLATION;
1699 if (lmAttr && (lmAttr->num_values > 1)) {
1700 ldb_set_errstring(ldb, "mupltiple values for dBCSPwd not allowed!\n");
1701 return LDB_ERR_CONSTRAINT_VIOLATION;
1704 if (sambaAttr && sambaAttr->num_values == 0) {
1705 ldb_set_errstring(ldb, "userPassword must have a value!\n");
1706 return LDB_ERR_CONSTRAINT_VIOLATION;
1709 if (clearTextPasswordAttr && clearTextPasswordAttr->num_values == 0) {
1710 ldb_set_errstring(ldb, "clearTextPassword must have a value!\n");
1711 return LDB_ERR_CONSTRAINT_VIOLATION;
1714 if (ntAttr && (ntAttr->num_values == 0)) {
1715 ldb_set_errstring(ldb, "unicodePwd must have a value!\n");
1716 return LDB_ERR_CONSTRAINT_VIOLATION;
1718 if (lmAttr && (lmAttr->num_values == 0)) {
1719 ldb_set_errstring(ldb, "dBCSPwd must have a value!\n");
1720 return LDB_ERR_CONSTRAINT_VIOLATION;
1723 ac = ph_init_context(module, req);
1725 return LDB_ERR_OPERATIONS_ERROR;
1728 /* get user domain data */
1729 ac->domain_sid = samdb_result_sid_prefix(ac, req->op.add.message, "objectSid");
1730 if (ac->domain_sid == NULL) {
1731 ldb_debug(ldb, LDB_DEBUG_ERROR,
1732 "can't handle entry with missing objectSid!\n");
1733 return LDB_ERR_OPERATIONS_ERROR;
1736 ret = build_domain_data_request(ac);
1737 if (ret != LDB_SUCCESS) {
1741 return ldb_next_request(module, ac->dom_req);
1744 static int password_hash_add_do_add(struct ph_context *ac)
1746 struct ldb_context *ldb;
1747 struct ldb_request *down_req;
1748 struct smb_krb5_context *smb_krb5_context;
1749 struct ldb_message *msg;
1750 struct setup_password_fields_io io;
1753 ldb = ldb_module_get_ctx(ac->module);
1755 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
1757 return LDB_ERR_OPERATIONS_ERROR;
1760 /* Some operations below require kerberos contexts */
1761 if (smb_krb5_init_context(ac,
1762 ldb_get_event_context(ldb),
1763 (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"),
1764 &smb_krb5_context) != 0) {
1765 return LDB_ERR_OPERATIONS_ERROR;
1770 io.domain = ac->domain;
1771 io.smb_krb5_context = smb_krb5_context;
1773 io.u.user_account_control = samdb_result_uint(msg, "userAccountControl", 0);
1774 io.u.sAMAccountName = samdb_result_string(msg, "samAccountName", NULL);
1775 io.u.user_principal_name = samdb_result_string(msg, "userPrincipalName", NULL);
1776 io.u.is_computer = ldb_msg_check_string_attribute(msg, "objectClass", "computer");
1778 io.n.cleartext_utf8 = ldb_msg_find_ldb_val(msg, "userPassword");
1779 io.n.cleartext_utf16 = ldb_msg_find_ldb_val(msg, "clearTextPassword");
1780 io.n.nt_hash = samdb_result_hash(io.ac, msg, "unicodePwd");
1781 io.n.lm_hash = samdb_result_hash(io.ac, msg, "dBCSPwd");
1783 /* remove attributes */
1784 if (io.n.cleartext_utf8) ldb_msg_remove_attr(msg, "userPassword");
1785 if (io.n.cleartext_utf16) ldb_msg_remove_attr(msg, "clearTextPassword");
1786 if (io.n.nt_hash) ldb_msg_remove_attr(msg, "unicodePwd");
1787 if (io.n.lm_hash) ldb_msg_remove_attr(msg, "dBCSPwd");
1788 ldb_msg_remove_attr(msg, "pwdLastSet");
1789 io.o.kvno = samdb_result_uint(msg, "msDs-KeyVersionNumber", 1) - 1;
1790 ldb_msg_remove_attr(msg, "msDs-KeyVersionNumber");
1792 ret = setup_password_fields(&io);
1793 if (ret != LDB_SUCCESS) {
1798 ret = samdb_msg_add_hash(ldb, ac, msg,
1799 "unicodePwd", io.g.nt_hash);
1800 if (ret != LDB_SUCCESS) {
1805 ret = samdb_msg_add_hash(ldb, ac, msg,
1806 "dBCSPwd", io.g.lm_hash);
1807 if (ret != LDB_SUCCESS) {
1811 if (io.g.nt_history_len > 0) {
1812 ret = samdb_msg_add_hashes(ac, msg,
1815 io.g.nt_history_len);
1816 if (ret != LDB_SUCCESS) {
1820 if (io.g.lm_history_len > 0) {
1821 ret = samdb_msg_add_hashes(ac, msg,
1824 io.g.lm_history_len);
1825 if (ret != LDB_SUCCESS) {
1829 if (io.g.supplemental.length > 0) {
1830 ret = ldb_msg_add_value(msg, "supplementalCredentials",
1831 &io.g.supplemental, NULL);
1832 if (ret != LDB_SUCCESS) {
1836 ret = samdb_msg_add_uint64(ldb, ac, msg,
1839 if (ret != LDB_SUCCESS) {
1842 ret = samdb_msg_add_uint(ldb, ac, msg,
1843 "msDs-KeyVersionNumber",
1845 if (ret != LDB_SUCCESS) {
1849 ret = ldb_build_add_req(&down_req, ldb, ac,
1854 if (ret != LDB_SUCCESS) {
1858 return ldb_next_request(ac->module, down_req);
1861 static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
1863 struct ldb_context *ldb;
1864 struct ph_context *ac;
1865 struct ldb_message_element *sambaAttr;
1866 struct ldb_message_element *clearTextAttr;
1867 struct ldb_message_element *ntAttr;
1868 struct ldb_message_element *lmAttr;
1869 struct ldb_message *msg;
1870 struct ldb_request *down_req;
1873 ldb = ldb_module_get_ctx(module);
1875 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
1877 if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
1878 return ldb_next_request(module, req);
1881 /* If the caller is manipulating the local passwords directly, let them pass */
1882 if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
1883 req->op.mod.message->dn) == 0) {
1884 return ldb_next_request(module, req);
1887 /* nobody must touch password Histories */
1888 if (ldb_msg_find_element(req->op.add.message, "ntPwdHistory")) {
1889 return LDB_ERR_UNWILLING_TO_PERFORM;
1891 if (ldb_msg_find_element(req->op.add.message, "lmPwdHistory")) {
1892 return LDB_ERR_UNWILLING_TO_PERFORM;
1894 if (ldb_msg_find_element(req->op.add.message, "supplementalCredentials")) {
1895 return LDB_ERR_UNWILLING_TO_PERFORM;
1898 sambaAttr = ldb_msg_find_element(req->op.mod.message, "userPassword");
1899 clearTextAttr = ldb_msg_find_element(req->op.mod.message, "clearTextPassword");
1900 ntAttr = ldb_msg_find_element(req->op.mod.message, "unicodePwd");
1901 lmAttr = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
1903 /* If no part of this touches the userPassword OR
1904 * clearTextPassword OR unicodePwd and/or dBCSPwd, then we
1905 * don't need to make any changes. For password changes/set
1906 * there should be a 'delete' or a 'modify' on this
1908 if ((!sambaAttr) && (!clearTextAttr) && (!ntAttr) && (!lmAttr)) {
1909 return ldb_next_request(module, req);
1912 /* check passwords are single valued here */
1913 /* TODO: remove this when passwords will be single valued in schema */
1914 if (sambaAttr && (sambaAttr->num_values > 1)) {
1915 return LDB_ERR_CONSTRAINT_VIOLATION;
1917 if (clearTextAttr && (clearTextAttr->num_values > 1)) {
1918 return LDB_ERR_CONSTRAINT_VIOLATION;
1920 if (ntAttr && (ntAttr->num_values > 1)) {
1921 return LDB_ERR_CONSTRAINT_VIOLATION;
1923 if (lmAttr && (lmAttr->num_values > 1)) {
1924 return LDB_ERR_CONSTRAINT_VIOLATION;
1927 ac = ph_init_context(module, req);
1929 return LDB_ERR_OPERATIONS_ERROR;
1932 /* use a new message structure so that we can modify it */
1933 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
1936 return LDB_ERR_OPERATIONS_ERROR;
1939 /* - remove any modification to the password from the first commit
1940 * we will make the real modification later */
1941 if (sambaAttr) ldb_msg_remove_attr(msg, "userPassword");
1942 if (clearTextAttr) ldb_msg_remove_attr(msg, "clearTextPassword");
1943 if (ntAttr) ldb_msg_remove_attr(msg, "unicodePwd");
1944 if (lmAttr) ldb_msg_remove_attr(msg, "dBCSPwd");
1946 /* if there was nothing else to be modified skip to next step */
1947 if (msg->num_elements == 0) {
1948 return password_hash_mod_search_self(ac);
1951 ret = ldb_build_mod_req(&down_req, ldb, ac,
1954 ac, ph_modify_callback,
1956 if (ret != LDB_SUCCESS) {
1960 return ldb_next_request(module, down_req);
1963 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
1965 struct ph_context *ac;
1968 ac = talloc_get_type(req->context, struct ph_context);
1971 return ldb_module_done(ac->req, NULL, NULL,
1972 LDB_ERR_OPERATIONS_ERROR);
1974 if (ares->error != LDB_SUCCESS) {
1975 return ldb_module_done(ac->req, ares->controls,
1976 ares->response, ares->error);
1979 if (ares->type != LDB_REPLY_DONE) {
1981 return ldb_module_done(ac->req, NULL, NULL,
1982 LDB_ERR_OPERATIONS_ERROR);
1985 ret = password_hash_mod_search_self(ac);
1986 if (ret != LDB_SUCCESS) {
1987 return ldb_module_done(ac->req, NULL, NULL, ret);
1994 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
1996 struct ldb_context *ldb;
1997 struct ph_context *ac;
2000 ac = talloc_get_type(req->context, struct ph_context);
2001 ldb = ldb_module_get_ctx(ac->module);
2004 return ldb_module_done(ac->req, NULL, NULL,
2005 LDB_ERR_OPERATIONS_ERROR);
2007 if (ares->error != LDB_SUCCESS) {
2008 return ldb_module_done(ac->req, ares->controls,
2009 ares->response, ares->error);
2012 /* we are interested only in the single reply (base search) */
2013 switch (ares->type) {
2014 case LDB_REPLY_ENTRY:
2016 if (ac->search_res != NULL) {
2017 ldb_set_errstring(ldb, "Too many results");
2019 return ldb_module_done(ac->req, NULL, NULL,
2020 LDB_ERR_OPERATIONS_ERROR);
2023 /* if it is not an entry of type person this is an error */
2024 /* TODO: remove this when sambaPassword will be in schema */
2025 if (!ldb_msg_check_string_attribute(ares->message, "objectClass", "person")) {
2026 ldb_set_errstring(ldb, "Object class violation");
2028 return ldb_module_done(ac->req, NULL, NULL,
2029 LDB_ERR_OBJECT_CLASS_VIOLATION);
2032 ac->search_res = talloc_steal(ac, ares);
2035 case LDB_REPLY_DONE:
2037 /* get object domain sid */
2038 ac->domain_sid = samdb_result_sid_prefix(ac,
2039 ac->search_res->message,
2041 if (ac->domain_sid == NULL) {
2042 ldb_debug(ldb, LDB_DEBUG_ERROR,
2043 "can't handle entry without objectSid!\n");
2044 return ldb_module_done(ac->req, NULL, NULL,
2045 LDB_ERR_OPERATIONS_ERROR);
2048 /* get user domain data */
2049 ret = build_domain_data_request(ac);
2050 if (ret != LDB_SUCCESS) {
2051 return ldb_module_done(ac->req, NULL, NULL,ret);
2054 return ldb_next_request(ac->module, ac->dom_req);
2056 case LDB_REPLY_REFERRAL:
2057 /*ignore anything else for now */
2065 static int password_hash_mod_search_self(struct ph_context *ac)
2067 struct ldb_context *ldb;
2068 static const char * const attrs[] = { "userAccountControl", "lmPwdHistory",
2070 "objectSid", "msDS-KeyVersionNumber",
2071 "objectClass", "userPrincipalName",
2073 "dBCSPwd", "unicodePwd",
2074 "supplementalCredentials",
2076 struct ldb_request *search_req;
2079 ldb = ldb_module_get_ctx(ac->module);
2081 ret = ldb_build_search_req(&search_req, ldb, ac,
2082 ac->req->op.mod.message->dn,
2087 ac, ph_mod_search_callback,
2090 if (ret != LDB_SUCCESS) {
2094 return ldb_next_request(ac->module, search_req);
2097 static int password_hash_mod_do_mod(struct ph_context *ac)
2099 struct ldb_context *ldb;
2100 struct ldb_request *mod_req;
2101 struct smb_krb5_context *smb_krb5_context;
2102 struct ldb_message *msg;
2103 struct ldb_message *orig_msg;
2104 struct ldb_message *searched_msg;
2105 struct setup_password_fields_io io;
2106 const struct ldb_val *quoted_utf16;
2109 ldb = ldb_module_get_ctx(ac->module);
2111 /* use a new message structure so that we can modify it */
2112 msg = ldb_msg_new(ac);
2114 return LDB_ERR_OPERATIONS_ERROR;
2118 msg->dn = ac->req->op.mod.message->dn;
2120 /* Some operations below require kerberos contexts */
2121 if (smb_krb5_init_context(ac,
2122 ldb_get_event_context(ldb),
2123 (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"),
2124 &smb_krb5_context) != 0) {
2125 return LDB_ERR_OPERATIONS_ERROR;
2128 orig_msg = discard_const(ac->req->op.mod.message);
2129 searched_msg = ac->search_res->message;
2133 io.domain = ac->domain;
2134 io.smb_krb5_context = smb_krb5_context;
2136 io.u.user_account_control = samdb_result_uint(searched_msg, "userAccountControl", 0);
2137 io.u.sAMAccountName = samdb_result_string(searched_msg, "samAccountName", NULL);
2138 io.u.user_principal_name = samdb_result_string(searched_msg, "userPrincipalName", NULL);
2139 io.u.is_computer = ldb_msg_check_string_attribute(searched_msg, "objectClass", "computer");
2141 io.n.cleartext_utf8 = ldb_msg_find_ldb_val(orig_msg, "userPassword");
2142 io.n.cleartext_utf16 = ldb_msg_find_ldb_val(orig_msg, "clearTextPassword");
2144 /* this rather strange looking piece of code is there to
2145 handle a ldap client setting a password remotely using the
2146 unicodePwd ldap field. The syntax is that the password is
2147 in UTF-16LE, with a " at either end. Unfortunately the
2148 unicodePwd field is also used to store the nt hashes
2149 internally in Samba, and is used in the nt hash format on
2150 the wire in DRS replication, so we have a single name for
2151 two distinct values. The code below leaves us with a small
2152 chance (less than 1 in 2^32) of a mixup, if someone manages
2153 to create a MD4 hash which starts and ends in 0x22 0x00, as
2154 that would then be treated as a UTF16 password rather than
2156 quoted_utf16 = ldb_msg_find_ldb_val(orig_msg, "unicodePwd");
2158 quoted_utf16->length >= 4 &&
2159 quoted_utf16->data[0] == '"' &&
2160 quoted_utf16->data[1] == 0 &&
2161 quoted_utf16->data[quoted_utf16->length-2] == '"' &&
2162 quoted_utf16->data[quoted_utf16->length-1] == 0) {
2163 io.n.quoted_utf16.data = talloc_memdup(orig_msg, quoted_utf16->data+2, quoted_utf16->length-4);
2164 io.n.quoted_utf16.length = quoted_utf16->length-4;
2165 io.n.cleartext_utf16 = &io.n.quoted_utf16;
2166 io.n.nt_hash = NULL;
2168 io.n.nt_hash = samdb_result_hash(io.ac, orig_msg, "unicodePwd");
2171 io.n.lm_hash = samdb_result_hash(io.ac, orig_msg, "dBCSPwd");
2173 io.o.kvno = samdb_result_uint(searched_msg, "msDs-KeyVersionNumber", 0);
2174 io.o.nt_history_len = samdb_result_hashes(io.ac, searched_msg, "ntPwdHistory", &io.o.nt_history);
2175 io.o.lm_history_len = samdb_result_hashes(io.ac, searched_msg, "lmPwdHistory", &io.o.lm_history);
2176 io.o.supplemental = ldb_msg_find_ldb_val(searched_msg, "supplementalCredentials");
2178 ret = setup_password_fields(&io);
2179 if (ret != LDB_SUCCESS) {
2183 /* make sure we replace all the old attributes */
2184 ret = ldb_msg_add_empty(msg, "unicodePwd", LDB_FLAG_MOD_REPLACE, NULL);
2185 ret = ldb_msg_add_empty(msg, "dBCSPwd", LDB_FLAG_MOD_REPLACE, NULL);
2186 ret = ldb_msg_add_empty(msg, "ntPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
2187 ret = ldb_msg_add_empty(msg, "lmPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
2188 ret = ldb_msg_add_empty(msg, "supplementalCredentials", LDB_FLAG_MOD_REPLACE, NULL);
2189 ret = ldb_msg_add_empty(msg, "pwdLastSet", LDB_FLAG_MOD_REPLACE, NULL);
2190 ret = ldb_msg_add_empty(msg, "msDs-KeyVersionNumber", LDB_FLAG_MOD_REPLACE, NULL);
2193 ret = samdb_msg_add_hash(ldb, ac, msg,
2194 "unicodePwd", io.g.nt_hash);
2195 if (ret != LDB_SUCCESS) {
2200 ret = samdb_msg_add_hash(ldb, ac, msg,
2201 "dBCSPwd", io.g.lm_hash);
2202 if (ret != LDB_SUCCESS) {
2206 if (io.g.nt_history_len > 0) {
2207 ret = samdb_msg_add_hashes(ac, msg,
2210 io.g.nt_history_len);
2211 if (ret != LDB_SUCCESS) {
2215 if (io.g.lm_history_len > 0) {
2216 ret = samdb_msg_add_hashes(ac, msg,
2219 io.g.lm_history_len);
2220 if (ret != LDB_SUCCESS) {
2224 if (io.g.supplemental.length > 0) {
2225 ret = ldb_msg_add_value(msg, "supplementalCredentials",
2226 &io.g.supplemental, NULL);
2227 if (ret != LDB_SUCCESS) {
2231 ret = samdb_msg_add_uint64(ldb, ac, msg,
2234 if (ret != LDB_SUCCESS) {
2237 ret = samdb_msg_add_uint(ldb, ac, msg,
2238 "msDs-KeyVersionNumber",
2240 if (ret != LDB_SUCCESS) {
2244 ret = ldb_build_mod_req(&mod_req, ldb, ac,
2249 if (ret != LDB_SUCCESS) {
2253 return ldb_next_request(ac->module, mod_req);
2256 _PUBLIC_ const struct ldb_module_ops ldb_password_hash_module_ops = {
2257 .name = "password_hash",
2258 .add = password_hash_add,
2259 .modify = password_hash_modify,