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-2010
8 Copyright (C) Matthias Dieter Wallnöfer 2009-2010
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 * Component: ldb password_hash module
29 * Description: correctly handle AD password changes fields
31 * Author: Andrew Bartlett
32 * Author: Stefan Metzmacher
36 #include "libcli/ldap/ldap_ndr.h"
37 #include "ldb_module.h"
38 #include "librpc/gen_ndr/misc.h"
39 #include "librpc/gen_ndr/samr.h"
40 #include "libcli/auth/libcli_auth.h"
41 #include "libcli/security/security.h"
42 #include "system/kerberos.h"
43 #include "auth/kerberos/kerberos.h"
44 #include "system/time.h"
45 #include "dsdb/samdb/samdb.h"
46 #include "../libds/common/flags.h"
47 #include "dsdb/samdb/ldb_modules/password_modules.h"
48 #include "librpc/ndr/libndr.h"
49 #include "librpc/gen_ndr/ndr_drsblobs.h"
50 #include "../lib/crypto/crypto.h"
51 #include "param/param.h"
53 /* If we have decided there is a reason to work on this request, then
54 * setup all the password hash types correctly.
56 * If we haven't the hashes yet but the password given as plain-text (attributes
57 * 'unicodePwd', 'userPassword' and 'clearTextPassword') we have to check for
58 * the constraints. Once this is done, we calculate the password hashes.
60 * Notice: unlike the real AD which only supports the UTF16 special based
61 * 'unicodePwd' and the UTF8 based 'userPassword' plaintext attribute we
62 * understand also a UTF16 based 'clearTextPassword' one.
63 * The latter is also accessible through LDAP so it can also be set by external
64 * tools and scripts. But be aware that this isn't portable on non SAMBA 4 ADs!
66 * Also when the module receives only the password hashes (possible through
67 * specifying an internal LDB control - for security reasons) some checks are
68 * performed depending on the operation mode (see below) (e.g. if the password
69 * has been in use before if the password memory policy was activated).
71 * Attention: There is a difference between "modify" and "reset" operations
72 * (see MS-ADTS 3.1.1.3.1.5). If the client sends a "add" and "remove"
73 * operation for a password attribute we thread this as a "modify"; if it sends
74 * only a "replace" one we have an (administrative) reset.
76 * Finally, if the administrator has requested that a password history
77 * be maintained, then this should also be written out.
81 /* TODO: [consider always MS-ADTS 3.1.1.3.1.5]
82 * - Check for right connection encryption
85 /* Notice: Definition of "dsdb_control_password_change_status" moved into
89 struct ldb_module *module;
90 struct ldb_request *req;
92 struct ldb_request *dom_req;
93 struct ldb_reply *dom_res;
95 struct ldb_reply *search_res;
97 struct dsdb_control_password_change_status *status;
103 bool change_old_pw_checked;
107 struct setup_password_fields_io {
108 struct ph_context *ac;
110 struct smb_krb5_context *smb_krb5_context;
112 /* infos about the user account */
114 uint32_t userAccountControl;
116 const char *sAMAccountName;
117 const char *user_principal_name;
119 uint32_t restrictions;
122 /* new credentials and old given credentials */
123 struct setup_password_fields_given {
124 const struct ldb_val *cleartext_utf8;
125 const struct ldb_val *cleartext_utf16;
126 struct samr_Password *nt_hash;
127 struct samr_Password *lm_hash;
130 /* old credentials */
132 struct samr_Password *nt_hash;
133 struct samr_Password *lm_hash;
134 uint32_t nt_history_len;
135 struct samr_Password *nt_history;
136 uint32_t lm_history_len;
137 struct samr_Password *lm_history;
138 const struct ldb_val *supplemental;
139 struct supplementalCredentialsBlob scb;
142 /* generated credentials */
144 struct samr_Password *nt_hash;
145 struct samr_Password *lm_hash;
146 uint32_t nt_history_len;
147 struct samr_Password *nt_history;
148 uint32_t lm_history_len;
149 struct samr_Password *lm_history;
155 struct ldb_val supplemental;
160 /* Get the NT hash, and fill it in as an entry in the password history,
161 and specify it into io->g.nt_hash */
163 static int setup_nt_fields(struct setup_password_fields_io *io)
165 struct ldb_context *ldb;
168 io->g.nt_hash = io->n.nt_hash;
169 ldb = ldb_module_get_ctx(io->ac->module);
171 if (io->ac->status->domain_data.pwdHistoryLength == 0) {
175 /* We might not have an old NT password */
176 io->g.nt_history = talloc_array(io->ac,
177 struct samr_Password,
178 io->ac->status->domain_data.pwdHistoryLength);
179 if (!io->g.nt_history) {
181 return LDB_ERR_OPERATIONS_ERROR;
184 for (i = 0; i < MIN(io->ac->status->domain_data.pwdHistoryLength-1,
185 io->o.nt_history_len); i++) {
186 io->g.nt_history[i+1] = io->o.nt_history[i];
188 io->g.nt_history_len = i + 1;
191 io->g.nt_history[0] = *io->g.nt_hash;
194 * TODO: is this correct?
195 * the simular behavior is correct for the lm history case
197 E_md4hash("", io->g.nt_history[0].hash);
203 /* Get the LANMAN hash, and fill it in as an entry in the password history,
204 and specify it into io->g.lm_hash */
206 static int setup_lm_fields(struct setup_password_fields_io *io)
208 struct ldb_context *ldb;
211 io->g.lm_hash = io->n.lm_hash;
212 ldb = ldb_module_get_ctx(io->ac->module);
214 if (io->ac->status->domain_data.pwdHistoryLength == 0) {
218 /* We might not have an old NT password */
219 io->g.lm_history = talloc_array(io->ac,
220 struct samr_Password,
221 io->ac->status->domain_data.pwdHistoryLength);
222 if (!io->g.lm_history) {
224 return LDB_ERR_OPERATIONS_ERROR;
227 for (i = 0; i < MIN(io->ac->status->domain_data.pwdHistoryLength-1,
228 io->o.lm_history_len); i++) {
229 io->g.lm_history[i+1] = io->o.lm_history[i];
231 io->g.lm_history_len = i + 1;
234 io->g.lm_history[0] = *io->g.lm_hash;
236 E_deshash("", io->g.lm_history[0].hash);
242 static int setup_kerberos_keys(struct setup_password_fields_io *io)
244 struct ldb_context *ldb;
245 krb5_error_code krb5_ret;
246 Principal *salt_principal;
249 krb5_data cleartext_data;
251 ldb = ldb_module_get_ctx(io->ac->module);
252 cleartext_data.data = io->n.cleartext_utf8->data;
253 cleartext_data.length = io->n.cleartext_utf8->length;
255 /* Many, many thanks to lukeh@padl.com for this
256 * algorithm, described in his Nov 10 2004 mail to
257 * samba-technical@samba.org */
260 * Determine a salting principal
262 if (io->u.is_computer) {
266 name = strlower_talloc(io->ac, io->u.sAMAccountName);
269 return LDB_ERR_OPERATIONS_ERROR;
272 if (name[strlen(name)-1] == '$') {
273 name[strlen(name)-1] = '\0';
276 saltbody = talloc_asprintf(io->ac, "%s.%s", name,
277 io->ac->status->domain_data.dns_domain);
280 return LDB_ERR_OPERATIONS_ERROR;
283 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
285 io->ac->status->domain_data.realm,
286 "host", saltbody, NULL);
287 } else if (io->u.user_principal_name) {
288 char *user_principal_name;
291 user_principal_name = talloc_strdup(io->ac, io->u.user_principal_name);
292 if (!user_principal_name) {
294 return LDB_ERR_OPERATIONS_ERROR;
297 p = strchr(user_principal_name, '@');
302 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
304 io->ac->status->domain_data.realm,
305 user_principal_name, NULL);
307 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
309 io->ac->status->domain_data.realm,
310 io->u.sAMAccountName, NULL);
313 ldb_asprintf_errstring(ldb,
314 "setup_kerberos_keys: "
315 "generation of a salting principal failed: %s",
316 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
318 return LDB_ERR_OPERATIONS_ERROR;
322 * create salt from salt_principal
324 krb5_ret = krb5_get_pw_salt(io->smb_krb5_context->krb5_context,
325 salt_principal, &salt);
326 krb5_free_principal(io->smb_krb5_context->krb5_context, salt_principal);
328 ldb_asprintf_errstring(ldb,
329 "setup_kerberos_keys: "
330 "generation of krb5_salt failed: %s",
331 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
333 return LDB_ERR_OPERATIONS_ERROR;
335 /* create a talloc copy */
336 io->g.salt = talloc_strndup(io->ac,
337 (char *)salt.saltvalue.data,
338 salt.saltvalue.length);
339 krb5_free_salt(io->smb_krb5_context->krb5_context, salt);
342 return LDB_ERR_OPERATIONS_ERROR;
344 salt.saltvalue.data = discard_const(io->g.salt);
345 salt.saltvalue.length = strlen(io->g.salt);
348 * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of
349 * the salt and the cleartext password
351 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
352 ENCTYPE_AES256_CTS_HMAC_SHA1_96,
357 ldb_asprintf_errstring(ldb,
358 "setup_kerberos_keys: "
359 "generation of a aes256-cts-hmac-sha1-96 key failed: %s",
360 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
362 return LDB_ERR_OPERATIONS_ERROR;
364 io->g.aes_256 = data_blob_talloc(io->ac,
366 key.keyvalue.length);
367 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
368 if (!io->g.aes_256.data) {
370 return LDB_ERR_OPERATIONS_ERROR;
374 * create ENCTYPE_AES128_CTS_HMAC_SHA1_96 key out of
375 * the salt and the cleartext password
377 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
378 ENCTYPE_AES128_CTS_HMAC_SHA1_96,
383 ldb_asprintf_errstring(ldb,
384 "setup_kerberos_keys: "
385 "generation of a aes128-cts-hmac-sha1-96 key failed: %s",
386 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
388 return LDB_ERR_OPERATIONS_ERROR;
390 io->g.aes_128 = data_blob_talloc(io->ac,
392 key.keyvalue.length);
393 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
394 if (!io->g.aes_128.data) {
396 return LDB_ERR_OPERATIONS_ERROR;
400 * create ENCTYPE_DES_CBC_MD5 key out of
401 * the salt and the cleartext password
403 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
409 ldb_asprintf_errstring(ldb,
410 "setup_kerberos_keys: "
411 "generation of a des-cbc-md5 key failed: %s",
412 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
414 return LDB_ERR_OPERATIONS_ERROR;
416 io->g.des_md5 = data_blob_talloc(io->ac,
418 key.keyvalue.length);
419 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
420 if (!io->g.des_md5.data) {
422 return LDB_ERR_OPERATIONS_ERROR;
426 * create ENCTYPE_DES_CBC_CRC key out of
427 * the salt and the cleartext password
429 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
435 ldb_asprintf_errstring(ldb,
436 "setup_kerberos_keys: "
437 "generation of a des-cbc-crc key failed: %s",
438 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
440 return LDB_ERR_OPERATIONS_ERROR;
442 io->g.des_crc = data_blob_talloc(io->ac,
444 key.keyvalue.length);
445 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
446 if (!io->g.des_crc.data) {
448 return LDB_ERR_OPERATIONS_ERROR;
454 static int setup_primary_kerberos(struct setup_password_fields_io *io,
455 const struct supplementalCredentialsBlob *old_scb,
456 struct package_PrimaryKerberosBlob *pkb)
458 struct ldb_context *ldb;
459 struct package_PrimaryKerberosCtr3 *pkb3 = &pkb->ctr.ctr3;
460 struct supplementalCredentialsPackage *old_scp = NULL;
461 struct package_PrimaryKerberosBlob _old_pkb;
462 struct package_PrimaryKerberosCtr3 *old_pkb3 = NULL;
464 enum ndr_err_code ndr_err;
466 ldb = ldb_module_get_ctx(io->ac->module);
469 * prepare generation of keys
471 * ENCTYPE_DES_CBC_MD5
472 * ENCTYPE_DES_CBC_CRC
475 pkb3->salt.string = io->g.salt;
477 pkb3->keys = talloc_array(io->ac,
478 struct package_PrimaryKerberosKey3,
482 return LDB_ERR_OPERATIONS_ERROR;
485 pkb3->keys[0].keytype = ENCTYPE_DES_CBC_MD5;
486 pkb3->keys[0].value = &io->g.des_md5;
487 pkb3->keys[1].keytype = ENCTYPE_DES_CBC_CRC;
488 pkb3->keys[1].value = &io->g.des_crc;
490 /* initialize the old keys to zero */
491 pkb3->num_old_keys = 0;
492 pkb3->old_keys = NULL;
494 /* if there're no old keys, then we're done */
499 for (i=0; i < old_scb->sub.num_packages; i++) {
500 if (strcmp("Primary:Kerberos", old_scb->sub.packages[i].name) != 0) {
504 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
508 old_scp = &old_scb->sub.packages[i];
511 /* Primary:Kerberos element of supplementalCredentials */
515 blob = strhex_to_data_blob(io->ac, old_scp->data);
518 return LDB_ERR_OPERATIONS_ERROR;
521 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
522 ndr_err = ndr_pull_struct_blob(&blob, io->ac, &_old_pkb,
523 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
524 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
525 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
526 ldb_asprintf_errstring(ldb,
527 "setup_primary_kerberos: "
528 "failed to pull old package_PrimaryKerberosBlob: %s",
530 return LDB_ERR_OPERATIONS_ERROR;
533 if (_old_pkb.version != 3) {
534 ldb_asprintf_errstring(ldb,
535 "setup_primary_kerberos: "
536 "package_PrimaryKerberosBlob version[%u] expected[3]",
538 return LDB_ERR_OPERATIONS_ERROR;
541 old_pkb3 = &_old_pkb.ctr.ctr3;
544 /* if we didn't found the old keys we're done */
549 /* fill in the old keys */
550 pkb3->num_old_keys = old_pkb3->num_keys;
551 pkb3->old_keys = old_pkb3->keys;
556 static int setup_primary_kerberos_newer(struct setup_password_fields_io *io,
557 const struct supplementalCredentialsBlob *old_scb,
558 struct package_PrimaryKerberosBlob *pkb)
560 struct ldb_context *ldb;
561 struct package_PrimaryKerberosCtr4 *pkb4 = &pkb->ctr.ctr4;
562 struct supplementalCredentialsPackage *old_scp = NULL;
563 struct package_PrimaryKerberosBlob _old_pkb;
564 struct package_PrimaryKerberosCtr4 *old_pkb4 = NULL;
566 enum ndr_err_code ndr_err;
568 ldb = ldb_module_get_ctx(io->ac->module);
571 * prepare generation of keys
573 * ENCTYPE_AES256_CTS_HMAC_SHA1_96
574 * ENCTYPE_AES128_CTS_HMAC_SHA1_96
575 * ENCTYPE_DES_CBC_MD5
576 * ENCTYPE_DES_CBC_CRC
579 pkb4->salt.string = io->g.salt;
580 pkb4->default_iteration_count = 4096;
583 pkb4->keys = talloc_array(io->ac,
584 struct package_PrimaryKerberosKey4,
588 return LDB_ERR_OPERATIONS_ERROR;
591 pkb4->keys[0].iteration_count = 4096;
592 pkb4->keys[0].keytype = ENCTYPE_AES256_CTS_HMAC_SHA1_96;
593 pkb4->keys[0].value = &io->g.aes_256;
594 pkb4->keys[1].iteration_count = 4096;
595 pkb4->keys[1].keytype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
596 pkb4->keys[1].value = &io->g.aes_128;
597 pkb4->keys[2].iteration_count = 4096;
598 pkb4->keys[2].keytype = ENCTYPE_DES_CBC_MD5;
599 pkb4->keys[2].value = &io->g.des_md5;
600 pkb4->keys[3].iteration_count = 4096;
601 pkb4->keys[3].keytype = ENCTYPE_DES_CBC_CRC;
602 pkb4->keys[3].value = &io->g.des_crc;
604 /* initialize the old keys to zero */
605 pkb4->num_old_keys = 0;
606 pkb4->old_keys = NULL;
607 pkb4->num_older_keys = 0;
608 pkb4->older_keys = NULL;
610 /* if there're no old keys, then we're done */
615 for (i=0; i < old_scb->sub.num_packages; i++) {
616 if (strcmp("Primary:Kerberos-Newer-Keys", old_scb->sub.packages[i].name) != 0) {
620 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
624 old_scp = &old_scb->sub.packages[i];
627 /* Primary:Kerberos-Newer-Keys element of supplementalCredentials */
631 blob = strhex_to_data_blob(io->ac, old_scp->data);
634 return LDB_ERR_OPERATIONS_ERROR;
637 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
638 ndr_err = ndr_pull_struct_blob(&blob, io->ac,
640 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
641 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
642 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
643 ldb_asprintf_errstring(ldb,
644 "setup_primary_kerberos_newer: "
645 "failed to pull old package_PrimaryKerberosBlob: %s",
647 return LDB_ERR_OPERATIONS_ERROR;
650 if (_old_pkb.version != 4) {
651 ldb_asprintf_errstring(ldb,
652 "setup_primary_kerberos_newer: "
653 "package_PrimaryKerberosBlob version[%u] expected[4]",
655 return LDB_ERR_OPERATIONS_ERROR;
658 old_pkb4 = &_old_pkb.ctr.ctr4;
661 /* if we didn't found the old keys we're done */
666 /* fill in the old keys */
667 pkb4->num_old_keys = old_pkb4->num_keys;
668 pkb4->old_keys = old_pkb4->keys;
669 pkb4->num_older_keys = old_pkb4->num_old_keys;
670 pkb4->older_keys = old_pkb4->old_keys;
675 static int setup_primary_wdigest(struct setup_password_fields_io *io,
676 const struct supplementalCredentialsBlob *old_scb,
677 struct package_PrimaryWDigestBlob *pdb)
679 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
680 DATA_BLOB sAMAccountName;
681 DATA_BLOB sAMAccountName_l;
682 DATA_BLOB sAMAccountName_u;
683 const char *user_principal_name = io->u.user_principal_name;
684 DATA_BLOB userPrincipalName;
685 DATA_BLOB userPrincipalName_l;
686 DATA_BLOB userPrincipalName_u;
687 DATA_BLOB netbios_domain;
688 DATA_BLOB netbios_domain_l;
689 DATA_BLOB netbios_domain_u;
690 DATA_BLOB dns_domain;
691 DATA_BLOB dns_domain_l;
692 DATA_BLOB dns_domain_u;
704 * http://technet2.microsoft.com/WindowsServer/en/library/717b450c-f4a0-4cc9-86f4-cc0633aae5f91033.mspx?mfr=true
705 * for what precalculated hashes are supposed to be stored...
707 * I can't reproduce all values which should contain "Digest" as realm,
708 * am I doing something wrong or is w2k3 just broken...?
710 * W2K3 fills in following for a user:
712 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
713 * sAMAccountName: NewUser2Sam
714 * userPrincipalName: NewUser2Princ@sub1.w2k3.vmnet1.vm.base
716 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
717 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
718 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
719 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
720 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
721 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
722 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
723 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
724 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
725 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
726 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
727 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
728 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
729 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
730 * 221c55284451ae9b3aacaa2a3c86f10f => NewUser2Princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
731 * 74e1be668853d4324d38c07e2acfb8ea => (w2k3 has a bug here!) newuser2princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
732 * e1e244ab7f098e3ae1761be7f9229bbb => NEWUSER2PRINC@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
733 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
734 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
735 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
736 * 31dc704d3640335b2123d4ee28aa1f11 => ??? changes with NewUser2Sam => NewUser1Sam
737 * 36349f5cecd07320fb3bb0e119230c43 => ??? changes with NewUser2Sam => NewUser1Sam
738 * 12adf019d037fb535c01fd0608e78d9d => ??? changes with NewUser2Sam => NewUser1Sam
739 * 6feecf8e724906f3ee1105819c5105a1 => ??? changes with NewUser2Princ => NewUser1Princ
740 * 6c6911f3de6333422640221b9c51ff1f => ??? changes with NewUser2Princ => NewUser1Princ
741 * 4b279877e742895f9348ac67a8de2f69 => ??? changes with NewUser2Princ => NewUser1Princ
742 * db0c6bff069513e3ebb9870d29b57490 => ??? changes with NewUser2Sam => NewUser1Sam
743 * 45072621e56b1c113a4e04a8ff68cd0e => ??? changes with NewUser2Sam => NewUser1Sam
744 * 11d1220abc44a9c10cf91ef4a9c1de02 => ??? changes with NewUser2Sam => NewUser1Sam
746 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
747 * sAMAccountName: NewUser2Sam
749 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
750 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
751 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
752 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
753 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
754 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
755 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
756 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
757 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
758 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
759 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
760 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
761 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
762 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
763 * 8a140d30b6f0a5912735dc1e3bc993b4 => NewUser2Sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
764 * 86d95b2faae6cae4ec261e7fbaccf093 => (here w2k3 is correct) newuser2sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
765 * dfeff1493110220efcdfc6362e5f5450 => NEWUSER2SAM@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
766 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
767 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
768 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
769 * 31dc704d3640335b2123d4ee28aa1f11 => ???M1 changes with NewUser2Sam => NewUser1Sam
770 * 36349f5cecd07320fb3bb0e119230c43 => ???M1.L changes with newuser2sam => newuser1sam
771 * 12adf019d037fb535c01fd0608e78d9d => ???M1.U changes with NEWUSER2SAM => NEWUSER1SAM
772 * 569b4533f2d9e580211dd040e5e360a8 => ???M2 changes with NewUser2Princ => NewUser1Princ
773 * 52528bddf310a587c5d7e6a9ae2cbb20 => ???M2.L changes with newuser2princ => newuser1princ
774 * 4f629a4f0361289ca4255ab0f658fcd5 => ???M3 changes with NewUser2Princ => NewUser1Princ (doesn't depend on case of userPrincipal )
775 * db0c6bff069513e3ebb9870d29b57490 => ???M4 changes with NewUser2Sam => NewUser1Sam
776 * 45072621e56b1c113a4e04a8ff68cd0e => ???M5 changes with NewUser2Sam => NewUser1Sam (doesn't depend on case of sAMAccountName)
777 * 11d1220abc44a9c10cf91ef4a9c1de02 => ???M4.U changes with NEWUSER2SAM => NEWUSER1SAM
781 * sAMAccountName, netbios_domain
784 .user = &sAMAccountName,
785 .realm = &netbios_domain,
788 .user = &sAMAccountName_l,
789 .realm = &netbios_domain_l,
792 .user = &sAMAccountName_u,
793 .realm = &netbios_domain_u,
796 .user = &sAMAccountName,
797 .realm = &netbios_domain_u,
800 .user = &sAMAccountName,
801 .realm = &netbios_domain_l,
804 .user = &sAMAccountName_u,
805 .realm = &netbios_domain_l,
808 .user = &sAMAccountName_l,
809 .realm = &netbios_domain_u,
812 * sAMAccountName, dns_domain
815 .user = &sAMAccountName,
816 .realm = &dns_domain,
819 .user = &sAMAccountName_l,
820 .realm = &dns_domain_l,
823 .user = &sAMAccountName_u,
824 .realm = &dns_domain_u,
827 .user = &sAMAccountName,
828 .realm = &dns_domain_u,
831 .user = &sAMAccountName,
832 .realm = &dns_domain_l,
835 .user = &sAMAccountName_u,
836 .realm = &dns_domain_l,
839 .user = &sAMAccountName_l,
840 .realm = &dns_domain_u,
843 * userPrincipalName, no realm
846 .user = &userPrincipalName,
850 * NOTE: w2k3 messes this up, if the user has a real userPrincipalName,
851 * the fallback to the sAMAccountName based userPrincipalName is correct
853 .user = &userPrincipalName_l,
856 .user = &userPrincipalName_u,
859 * nt4dom\sAMAccountName, no realm
862 .user = &sAMAccountName,
863 .nt4dom = &netbios_domain
866 .user = &sAMAccountName_l,
867 .nt4dom = &netbios_domain_l
870 .user = &sAMAccountName_u,
871 .nt4dom = &netbios_domain_u
875 * the following ones are guessed depending on the technet2 article
876 * but not reproducable on a w2k3 server
878 /* sAMAccountName with "Digest" realm */
880 .user = &sAMAccountName,
884 .user = &sAMAccountName_l,
888 .user = &sAMAccountName_u,
891 /* userPrincipalName with "Digest" realm */
893 .user = &userPrincipalName,
897 .user = &userPrincipalName_l,
901 .user = &userPrincipalName_u,
904 /* nt4dom\\sAMAccountName with "Digest" realm */
906 .user = &sAMAccountName,
907 .nt4dom = &netbios_domain,
911 .user = &sAMAccountName_l,
912 .nt4dom = &netbios_domain_l,
916 .user = &sAMAccountName_u,
917 .nt4dom = &netbios_domain_u,
922 /* prepare DATA_BLOB's used in the combinations array */
923 sAMAccountName = data_blob_string_const(io->u.sAMAccountName);
924 sAMAccountName_l = data_blob_string_const(strlower_talloc(io->ac, io->u.sAMAccountName));
925 if (!sAMAccountName_l.data) {
927 return LDB_ERR_OPERATIONS_ERROR;
929 sAMAccountName_u = data_blob_string_const(strupper_talloc(io->ac, io->u.sAMAccountName));
930 if (!sAMAccountName_u.data) {
932 return LDB_ERR_OPERATIONS_ERROR;
935 /* if the user doesn't have a userPrincipalName, create one (with lower case realm) */
936 if (!user_principal_name) {
937 user_principal_name = talloc_asprintf(io->ac, "%s@%s",
938 io->u.sAMAccountName,
939 io->ac->status->domain_data.dns_domain);
940 if (!user_principal_name) {
942 return LDB_ERR_OPERATIONS_ERROR;
945 userPrincipalName = data_blob_string_const(user_principal_name);
946 userPrincipalName_l = data_blob_string_const(strlower_talloc(io->ac, user_principal_name));
947 if (!userPrincipalName_l.data) {
949 return LDB_ERR_OPERATIONS_ERROR;
951 userPrincipalName_u = data_blob_string_const(strupper_talloc(io->ac, user_principal_name));
952 if (!userPrincipalName_u.data) {
954 return LDB_ERR_OPERATIONS_ERROR;
957 netbios_domain = data_blob_string_const(io->ac->status->domain_data.netbios_domain);
958 netbios_domain_l = data_blob_string_const(strlower_talloc(io->ac,
959 io->ac->status->domain_data.netbios_domain));
960 if (!netbios_domain_l.data) {
962 return LDB_ERR_OPERATIONS_ERROR;
964 netbios_domain_u = data_blob_string_const(strupper_talloc(io->ac,
965 io->ac->status->domain_data.netbios_domain));
966 if (!netbios_domain_u.data) {
968 return LDB_ERR_OPERATIONS_ERROR;
971 dns_domain = data_blob_string_const(io->ac->status->domain_data.dns_domain);
972 dns_domain_l = data_blob_string_const(io->ac->status->domain_data.dns_domain);
973 dns_domain_u = data_blob_string_const(io->ac->status->domain_data.realm);
975 digest = data_blob_string_const("Digest");
977 delim = data_blob_string_const(":");
978 backslash = data_blob_string_const("\\");
980 pdb->num_hashes = ARRAY_SIZE(wdigest);
981 pdb->hashes = talloc_array(io->ac, struct package_PrimaryWDigestHash,
985 return LDB_ERR_OPERATIONS_ERROR;
988 for (i=0; i < ARRAY_SIZE(wdigest); i++) {
989 struct MD5Context md5;
991 if (wdigest[i].nt4dom) {
992 MD5Update(&md5, wdigest[i].nt4dom->data, wdigest[i].nt4dom->length);
993 MD5Update(&md5, backslash.data, backslash.length);
995 MD5Update(&md5, wdigest[i].user->data, wdigest[i].user->length);
996 MD5Update(&md5, delim.data, delim.length);
997 if (wdigest[i].realm) {
998 MD5Update(&md5, wdigest[i].realm->data, wdigest[i].realm->length);
1000 MD5Update(&md5, delim.data, delim.length);
1001 MD5Update(&md5, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length);
1002 MD5Final(pdb->hashes[i].hash, &md5);
1008 static int setup_supplemental_field(struct setup_password_fields_io *io)
1010 struct ldb_context *ldb;
1011 struct supplementalCredentialsBlob scb;
1012 struct supplementalCredentialsBlob _old_scb;
1013 struct supplementalCredentialsBlob *old_scb = NULL;
1014 /* Packages + (Kerberos-Newer-Keys, Kerberos, WDigest and CLEARTEXT) */
1015 uint32_t num_names = 0;
1016 const char *names[1+4];
1017 uint32_t num_packages = 0;
1018 struct supplementalCredentialsPackage packages[1+4];
1020 struct supplementalCredentialsPackage *pp = NULL;
1021 struct package_PackagesBlob pb;
1024 /* Primary:Kerberos-Newer-Keys */
1025 const char **nkn = NULL;
1026 struct supplementalCredentialsPackage *pkn = NULL;
1027 struct package_PrimaryKerberosBlob pknb;
1028 DATA_BLOB pknb_blob;
1030 /* Primary:Kerberos */
1031 const char **nk = NULL;
1032 struct supplementalCredentialsPackage *pk = NULL;
1033 struct package_PrimaryKerberosBlob pkb;
1036 /* Primary:WDigest */
1037 const char **nd = NULL;
1038 struct supplementalCredentialsPackage *pd = NULL;
1039 struct package_PrimaryWDigestBlob pdb;
1042 /* Primary:CLEARTEXT */
1043 const char **nc = NULL;
1044 struct supplementalCredentialsPackage *pc = NULL;
1045 struct package_PrimaryCLEARTEXTBlob pcb;
1049 enum ndr_err_code ndr_err;
1051 bool do_newer_keys = false;
1052 bool do_cleartext = false;
1054 ZERO_STRUCT(zero16);
1057 ldb = ldb_module_get_ctx(io->ac->module);
1059 if (!io->n.cleartext_utf8) {
1061 * when we don't have a cleartext password
1062 * we can't setup a supplementalCredential value
1067 /* if there's an old supplementaCredentials blob then parse it */
1068 if (io->o.supplemental) {
1069 ndr_err = ndr_pull_struct_blob_all(io->o.supplemental, io->ac,
1071 (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
1072 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1073 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1074 ldb_asprintf_errstring(ldb,
1075 "setup_supplemental_field: "
1076 "failed to pull old supplementalCredentialsBlob: %s",
1078 return LDB_ERR_OPERATIONS_ERROR;
1081 if (_old_scb.sub.signature == SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
1082 old_scb = &_old_scb;
1084 ldb_debug(ldb, LDB_DEBUG_ERROR,
1085 "setup_supplemental_field: "
1086 "supplementalCredentialsBlob signature[0x%04X] expected[0x%04X]",
1087 _old_scb.sub.signature, SUPPLEMENTAL_CREDENTIALS_SIGNATURE);
1090 /* Per MS-SAMR 3.1.1.8.11.6 we create AES keys if our domain functionality level is 2008 or higher */
1091 do_newer_keys = (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008);
1093 if (io->ac->status->domain_data.store_cleartext &&
1094 (io->u.userAccountControl & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) {
1095 do_cleartext = true;
1099 * The ordering is this
1101 * Primary:Kerberos-Newer-Keys (optional)
1104 * Primary:CLEARTEXT (optional)
1106 * And the 'Packages' package is insert before the last
1109 if (do_newer_keys) {
1110 /* Primary:Kerberos-Newer-Keys */
1111 nkn = &names[num_names++];
1112 pkn = &packages[num_packages++];
1115 /* Primary:Kerberos */
1116 nk = &names[num_names++];
1117 pk = &packages[num_packages++];
1119 if (!do_cleartext) {
1121 pp = &packages[num_packages++];
1124 /* Primary:WDigest */
1125 nd = &names[num_names++];
1126 pd = &packages[num_packages++];
1130 pp = &packages[num_packages++];
1132 /* Primary:CLEARTEXT */
1133 nc = &names[num_names++];
1134 pc = &packages[num_packages++];
1139 * setup 'Primary:Kerberos-Newer-Keys' element
1141 *nkn = "Kerberos-Newer-Keys";
1143 ret = setup_primary_kerberos_newer(io, old_scb, &pknb);
1144 if (ret != LDB_SUCCESS) {
1148 ndr_err = ndr_push_struct_blob(&pknb_blob, io->ac,
1150 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1151 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1152 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1153 ldb_asprintf_errstring(ldb,
1154 "setup_supplemental_field: "
1155 "failed to push package_PrimaryKerberosNeverBlob: %s",
1157 return LDB_ERR_OPERATIONS_ERROR;
1159 pknb_hexstr = data_blob_hex_string_upper(io->ac, &pknb_blob);
1162 return LDB_ERR_OPERATIONS_ERROR;
1164 pkn->name = "Primary:Kerberos-Newer-Keys";
1166 pkn->data = pknb_hexstr;
1170 * setup 'Primary:Kerberos' element
1174 ret = setup_primary_kerberos(io, old_scb, &pkb);
1175 if (ret != LDB_SUCCESS) {
1179 ndr_err = ndr_push_struct_blob(&pkb_blob, io->ac,
1181 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1182 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1183 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1184 ldb_asprintf_errstring(ldb,
1185 "setup_supplemental_field: "
1186 "failed to push package_PrimaryKerberosBlob: %s",
1188 return LDB_ERR_OPERATIONS_ERROR;
1190 pkb_hexstr = data_blob_hex_string_upper(io->ac, &pkb_blob);
1193 return LDB_ERR_OPERATIONS_ERROR;
1195 pk->name = "Primary:Kerberos";
1197 pk->data = pkb_hexstr;
1200 * setup 'Primary:WDigest' element
1204 ret = setup_primary_wdigest(io, old_scb, &pdb);
1205 if (ret != LDB_SUCCESS) {
1209 ndr_err = ndr_push_struct_blob(&pdb_blob, io->ac,
1211 (ndr_push_flags_fn_t)ndr_push_package_PrimaryWDigestBlob);
1212 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1213 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1214 ldb_asprintf_errstring(ldb,
1215 "setup_supplemental_field: "
1216 "failed to push package_PrimaryWDigestBlob: %s",
1218 return LDB_ERR_OPERATIONS_ERROR;
1220 pdb_hexstr = data_blob_hex_string_upper(io->ac, &pdb_blob);
1223 return LDB_ERR_OPERATIONS_ERROR;
1225 pd->name = "Primary:WDigest";
1227 pd->data = pdb_hexstr;
1230 * setup 'Primary:CLEARTEXT' element
1235 pcb.cleartext = *io->n.cleartext_utf16;
1237 ndr_err = ndr_push_struct_blob(&pcb_blob, io->ac,
1239 (ndr_push_flags_fn_t)ndr_push_package_PrimaryCLEARTEXTBlob);
1240 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1241 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1242 ldb_asprintf_errstring(ldb,
1243 "setup_supplemental_field: "
1244 "failed to push package_PrimaryCLEARTEXTBlob: %s",
1246 return LDB_ERR_OPERATIONS_ERROR;
1248 pcb_hexstr = data_blob_hex_string_upper(io->ac, &pcb_blob);
1251 return LDB_ERR_OPERATIONS_ERROR;
1253 pc->name = "Primary:CLEARTEXT";
1255 pc->data = pcb_hexstr;
1259 * setup 'Packages' element
1262 ndr_err = ndr_push_struct_blob(&pb_blob, io->ac,
1264 (ndr_push_flags_fn_t)ndr_push_package_PackagesBlob);
1265 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1266 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1267 ldb_asprintf_errstring(ldb,
1268 "setup_supplemental_field: "
1269 "failed to push package_PackagesBlob: %s",
1271 return LDB_ERR_OPERATIONS_ERROR;
1273 pb_hexstr = data_blob_hex_string_upper(io->ac, &pb_blob);
1276 return LDB_ERR_OPERATIONS_ERROR;
1278 pp->name = "Packages";
1280 pp->data = pb_hexstr;
1283 * setup 'supplementalCredentials' value
1286 scb.sub.num_packages = num_packages;
1287 scb.sub.packages = packages;
1289 ndr_err = ndr_push_struct_blob(&io->g.supplemental, io->ac,
1291 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
1292 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1293 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1294 ldb_asprintf_errstring(ldb,
1295 "setup_supplemental_field: "
1296 "failed to push supplementalCredentialsBlob: %s",
1298 return LDB_ERR_OPERATIONS_ERROR;
1304 static int setup_last_set_field(struct setup_password_fields_io *io)
1307 unix_to_nt_time(&io->g.last_set, time(NULL));
1312 static int setup_given_passwords(struct setup_password_fields_io *io,
1313 struct setup_password_fields_given *g)
1315 struct ldb_context *ldb;
1318 ldb = ldb_module_get_ctx(io->ac->module);
1320 if (g->cleartext_utf8) {
1321 char **cleartext_utf16_str;
1322 struct ldb_val *cleartext_utf16_blob;
1323 size_t converted_pw_len;
1325 cleartext_utf16_blob = talloc(io->ac, struct ldb_val);
1326 if (!cleartext_utf16_blob) {
1328 return LDB_ERR_OPERATIONS_ERROR;
1330 if (!convert_string_talloc(io->ac,
1332 g->cleartext_utf8->data,
1333 g->cleartext_utf8->length,
1334 (void *)&cleartext_utf16_str,
1335 &converted_pw_len, false)) {
1336 ldb_asprintf_errstring(ldb,
1337 "setup_password_fields: "
1338 "failed to generate UTF16 password from cleartext UTF8 password");
1339 return LDB_ERR_OPERATIONS_ERROR;
1341 *cleartext_utf16_blob = data_blob_const(cleartext_utf16_str,
1343 g->cleartext_utf16 = cleartext_utf16_blob;
1344 } else if (g->cleartext_utf16) {
1345 char *cleartext_utf8_str;
1346 struct ldb_val *cleartext_utf8_blob;
1347 size_t converted_pw_len;
1349 cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
1350 if (!cleartext_utf8_blob) {
1352 return LDB_ERR_OPERATIONS_ERROR;
1354 if (!convert_string_talloc(io->ac,
1355 CH_UTF16MUNGED, CH_UTF8,
1356 g->cleartext_utf16->data,
1357 g->cleartext_utf16->length,
1358 (void *)&cleartext_utf8_str,
1359 &converted_pw_len, false)) {
1360 /* We can't bail out entirely, as these unconvertable passwords are frustratingly valid */
1361 talloc_free(cleartext_utf8_blob);
1363 *cleartext_utf8_blob = data_blob_const(cleartext_utf8_str,
1365 g->cleartext_utf8 = cleartext_utf8_blob;
1369 if (g->cleartext_utf16) {
1370 struct samr_Password *nt_hash;
1372 nt_hash = talloc(io->ac, struct samr_Password);
1375 return LDB_ERR_OPERATIONS_ERROR;
1377 g->nt_hash = nt_hash;
1379 /* compute the new nt hash */
1380 mdfour(nt_hash->hash,
1381 g->cleartext_utf16->data,
1382 g->cleartext_utf16->length);
1385 if (g->cleartext_utf8 &&
1386 lp_lanman_auth(ldb_get_opaque(ldb, "loadparm"))) {
1387 struct samr_Password *lm_hash;
1389 lm_hash = talloc(io->ac, struct samr_Password);
1392 return LDB_ERR_OPERATIONS_ERROR;
1395 /* compute the new lm hash */
1396 ok = E_deshash((char *)g->cleartext_utf8->data, lm_hash->hash);
1398 g->lm_hash = lm_hash;
1400 talloc_free(lm_hash);
1407 static int setup_password_fields(struct setup_password_fields_io *io)
1409 struct ldb_context *ldb;
1412 ldb = ldb_module_get_ctx(io->ac->module);
1414 /* transform the old password (for password changes) */
1415 ret = setup_given_passwords(io, &io->og);
1416 if (ret != LDB_SUCCESS) {
1420 /* transform the new password */
1421 ret = setup_given_passwords(io, &io->n);
1422 if (ret != LDB_SUCCESS) {
1426 if (io->n.cleartext_utf8) {
1427 ret = setup_kerberos_keys(io);
1428 if (ret != LDB_SUCCESS) {
1433 ret = setup_nt_fields(io);
1434 if (ret != LDB_SUCCESS) {
1438 ret = setup_lm_fields(io);
1439 if (ret != LDB_SUCCESS) {
1443 ret = setup_supplemental_field(io);
1444 if (ret != LDB_SUCCESS) {
1448 ret = setup_last_set_field(io);
1449 if (ret != LDB_SUCCESS) {
1456 static int check_password_restrictions(struct setup_password_fields_io *io)
1458 struct ldb_context *ldb;
1460 enum samr_ValidationStatus stat;
1462 ldb = ldb_module_get_ctx(io->ac->module);
1464 /* First check the old password is correct, for password changes */
1465 if (!io->ac->pwd_reset && !io->ac->change_old_pw_checked) {
1466 /* we need to old nt or lm hash given by the client */
1467 if (!io->og.nt_hash && !io->og.lm_hash) {
1468 ldb_asprintf_errstring(ldb,
1469 "check_password_restrictions: "
1470 "You need to provide the old password "
1471 "in order to change your password!");
1472 return LDB_ERR_UNWILLING_TO_PERFORM;
1475 if (io->og.nt_hash) {
1476 if (!io->o.nt_hash) {
1477 ldb_asprintf_errstring(ldb,
1478 "check_password_restrictions: "
1479 "There's no old nt_hash, which is needed "
1480 "in order to change your password!");
1481 return LDB_ERR_UNWILLING_TO_PERFORM;
1484 /* The password modify through the NT hash is encouraged
1485 and has no problems at all */
1486 if (memcmp(io->og.nt_hash->hash, io->o.nt_hash->hash, 16) != 0) {
1487 ldb_asprintf_errstring(ldb,
1488 "check_password_restrictions: "
1489 "The old password specified doesn't match!");
1490 return LDB_ERR_UNWILLING_TO_PERFORM;
1492 } else if (io->og.lm_hash) {
1493 struct loadparm_context *lp_ctx =
1494 (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm");
1496 if (!lp_lanman_auth(lp_ctx)) {
1497 ldb_asprintf_errstring(ldb,
1498 "check_password_restrictions: "
1499 "The password change through the LM hash is deactivated!");
1500 return LDB_ERR_UNWILLING_TO_PERFORM;
1503 if (!io->o.lm_hash) {
1504 ldb_asprintf_errstring(ldb,
1505 "check_password_restrictions: "
1506 "There's no old lm_hash, which is needed "
1507 "in order to change your password!");
1508 return LDB_ERR_UNWILLING_TO_PERFORM;
1511 if (memcmp(io->og.lm_hash->hash, io->o.lm_hash->hash, 16) != 0) {
1512 ldb_asprintf_errstring(ldb,
1513 "check_password_restrictions: "
1514 "The old password specified doesn't match!");
1515 return LDB_ERR_UNWILLING_TO_PERFORM;
1520 if (io->u.restrictions == 0) {
1521 /* FIXME: Is this right? */
1526 * Fundamental password checks done by the call
1527 * "samdb_check_password".
1528 * It is also in use by "dcesrv_samr_ValidatePassword".
1530 if (io->n.cleartext_utf8 != NULL) {
1531 stat = samdb_check_password(io->n.cleartext_utf8,
1532 io->ac->status->domain_data.pwdProperties,
1533 io->ac->status->domain_data.minPwdLength);
1535 case SAMR_VALIDATION_STATUS_SUCCESS:
1536 /* perfect -> proceed! */
1539 case SAMR_VALIDATION_STATUS_PWD_TOO_SHORT:
1540 ldb_asprintf_errstring(ldb,
1541 "check_password_restrictions: "
1542 "the password is too short. It should be equal or longer than %i characters!",
1543 io->ac->status->domain_data.minPwdLength);
1545 io->ac->status->reject_reason = SAM_PWD_CHANGE_PASSWORD_TOO_SHORT;
1546 return LDB_ERR_CONSTRAINT_VIOLATION;
1548 case SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH:
1549 ldb_asprintf_errstring(ldb,
1550 "check_password_restrictions: "
1551 "the password does not meet the complexity criterias!");
1552 io->ac->status->reject_reason = SAM_PWD_CHANGE_NOT_COMPLEX;
1554 return LDB_ERR_CONSTRAINT_VIOLATION;
1557 ldb_asprintf_errstring(ldb,
1558 "check_password_restrictions: "
1559 "the password doesn't fit by a certain reason!");
1561 return LDB_ERR_CONSTRAINT_VIOLATION;
1565 if (io->ac->pwd_reset) {
1569 if (io->n.nt_hash) {
1572 /* checks the NT hash password history */
1573 for (i = 0; i < io->o.nt_history_len; i++) {
1574 ret = memcmp(io->n.nt_hash, io->o.nt_history[i].hash, 16);
1576 ldb_asprintf_errstring(ldb,
1577 "check_password_restrictions: "
1578 "the password was already used (in history)!");
1580 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
1582 return LDB_ERR_CONSTRAINT_VIOLATION;
1587 if (io->n.lm_hash) {
1590 /* checks the LM hash password history */
1591 for (i = 0; i < io->o.lm_history_len; i++) {
1592 ret = memcmp(io->n.nt_hash, io->o.lm_history[i].hash, 16);
1594 ldb_asprintf_errstring(ldb,
1595 "check_password_restrictions: "
1596 "the password was already used (in history)!");
1598 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
1600 return LDB_ERR_CONSTRAINT_VIOLATION;
1605 /* are all password changes disallowed? */
1606 if (io->ac->status->domain_data.pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1607 ldb_asprintf_errstring(ldb,
1608 "check_password_restrictions: "
1609 "password changes disabled!");
1610 return LDB_ERR_CONSTRAINT_VIOLATION;
1613 /* can this user change the password? */
1614 if (io->u.userAccountControl & UF_PASSWD_CANT_CHANGE) {
1615 ldb_asprintf_errstring(ldb,
1616 "check_password_restrictions: "
1617 "password can't be changed on this account!");
1618 return LDB_ERR_CONSTRAINT_VIOLATION;
1621 /* Password minimum age: yes, this is a minus. The ages are in negative 100nsec units! */
1622 if (io->u.pwdLastSet - io->ac->status->domain_data.minPwdAge > io->g.last_set) {
1623 ldb_asprintf_errstring(ldb,
1624 "check_password_restrictions: "
1625 "password is too young to change!");
1626 return LDB_ERR_CONSTRAINT_VIOLATION;
1632 static int setup_io(struct ph_context *ac,
1633 const struct ldb_message *orig_msg,
1634 const struct ldb_message *searched_msg,
1635 struct setup_password_fields_io *io)
1637 const struct ldb_val *quoted_utf16, *old_quoted_utf16, *lm_hash, *old_lm_hash;
1638 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1643 /* Some operations below require kerberos contexts */
1645 if (smb_krb5_init_context(ac,
1646 ldb_get_event_context(ldb),
1647 (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"),
1648 &io->smb_krb5_context) != 0) {
1649 return LDB_ERR_OPERATIONS_ERROR;
1654 io->u.userAccountControl = samdb_result_uint(searched_msg, "userAccountControl", 0);
1655 io->u.pwdLastSet = samdb_result_nttime(searched_msg, "pwdLastSet", 0);
1656 io->u.sAMAccountName = samdb_result_string(searched_msg, "sAMAccountName", NULL);
1657 io->u.user_principal_name = samdb_result_string(searched_msg, "userPrincipalName", NULL);
1658 io->u.is_computer = ldb_msg_check_string_attribute(searched_msg, "objectClass", "computer");
1660 if (io->u.sAMAccountName == NULL) {
1661 ldb_asprintf_errstring(ldb,
1662 "setup_io: sAMAccountName attribute is missing on %s for attempted password set/change",
1663 ldb_dn_get_linearized(searched_msg->dn));
1665 return LDB_ERR_CONSTRAINT_VIOLATION;
1668 /* Only non-trust accounts have restrictions (possibly this test is the
1669 * wrong way around, but we like to be restrictive if possible */
1670 io->u.restrictions = !(io->u.userAccountControl
1671 & (UF_INTERDOMAIN_TRUST_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT
1672 | UF_SERVER_TRUST_ACCOUNT));
1674 if ((io->u.userAccountControl & UF_PASSWD_NOTREQD) != 0) {
1675 /* see [MS-ADTS] 2.2.15 */
1676 io->u.restrictions = 0;
1679 ret = samdb_msg_find_old_and_new_ldb_val(orig_msg, "userPassword",
1680 &io->n.cleartext_utf8, &io->og.cleartext_utf8);
1681 if (ret != LDB_SUCCESS) {
1682 ldb_asprintf_errstring(ldb,
1684 "it's only allowed to set the old password once!");
1688 ret = samdb_msg_find_old_and_new_ldb_val(orig_msg, "clearTextPassword",
1689 &io->n.cleartext_utf16, &io->og.cleartext_utf16);
1690 if (ret != LDB_SUCCESS) {
1691 ldb_asprintf_errstring(ldb,
1693 "it's only allowed to set the old password once!");
1697 /* this rather strange looking piece of code is there to
1698 handle a ldap client setting a password remotely using the
1699 unicodePwd ldap field. The syntax is that the password is
1700 in UTF-16LE, with a " at either end. Unfortunately the
1701 unicodePwd field is also used to store the nt hashes
1702 internally in Samba, and is used in the nt hash format on
1703 the wire in DRS replication, so we have a single name for
1704 two distinct values. The code below leaves us with a small
1705 chance (less than 1 in 2^32) of a mixup, if someone manages
1706 to create a MD4 hash which starts and ends in 0x22 0x00, as
1707 that would then be treated as a UTF16 password rather than
1710 ret = samdb_msg_find_old_and_new_ldb_val(orig_msg, "unicodePwd",
1711 "ed_utf16, &old_quoted_utf16);
1712 if (ret != LDB_SUCCESS) {
1713 ldb_asprintf_errstring(ldb,
1715 "it's only allowed to set the old password once!");
1719 /* Checks and converts the actual "unicodePwd" attribute */
1721 quoted_utf16->length >= 4 &&
1722 quoted_utf16->data[0] == '"' &&
1723 quoted_utf16->data[1] == 0 &&
1724 quoted_utf16->data[quoted_utf16->length-2] == '"' &&
1725 quoted_utf16->data[quoted_utf16->length-1] == 0) {
1726 struct ldb_val *quoted_utf16_2;
1728 if (io->n.cleartext_utf16) {
1729 /* refuse the change if someone wants to change with
1730 with both UTF16 possibilities at the same time... */
1731 ldb_asprintf_errstring(ldb,
1733 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
1734 return LDB_ERR_UNWILLING_TO_PERFORM;
1738 * adapt the quoted UTF16 string to be a real
1741 quoted_utf16_2 = talloc(io->ac, struct ldb_val);
1742 if (quoted_utf16_2 == NULL) {
1744 return LDB_ERR_OPERATIONS_ERROR;
1747 quoted_utf16_2->data = quoted_utf16->data + 2;
1748 quoted_utf16_2->length = quoted_utf16->length-4;
1749 io->n.cleartext_utf16 = quoted_utf16_2;
1750 io->n.nt_hash = NULL;
1752 } else if (quoted_utf16) {
1753 /* We have only the hash available -> so no plaintext here */
1754 if (!ac->hash_values) {
1755 /* refuse the change if someone wants to change
1756 the hash without control specified... */
1757 ldb_asprintf_errstring(ldb,
1759 "it's not allowed to set the NT hash password directly'");
1760 /* this looks odd but this is what Windows does:
1761 returns "UNWILLING_TO_PERFORM" on wrong
1762 password sets and "CONSTRAINT_VIOLATION" on
1763 wrong password changes. */
1764 if (old_quoted_utf16 == NULL) {
1765 return LDB_ERR_UNWILLING_TO_PERFORM;
1768 return LDB_ERR_CONSTRAINT_VIOLATION;
1771 io->n.nt_hash = talloc(io->ac, struct samr_Password);
1772 memcpy(io->n.nt_hash->hash, quoted_utf16->data,
1773 MIN(quoted_utf16->length, sizeof(io->n.nt_hash->hash)));
1776 /* Checks and converts the previous "unicodePwd" attribute */
1777 if (old_quoted_utf16 &&
1778 old_quoted_utf16->length >= 4 &&
1779 old_quoted_utf16->data[0] == '"' &&
1780 old_quoted_utf16->data[1] == 0 &&
1781 old_quoted_utf16->data[old_quoted_utf16->length-2] == '"' &&
1782 old_quoted_utf16->data[old_quoted_utf16->length-1] == 0) {
1783 struct ldb_val *old_quoted_utf16_2;
1785 if (io->og.cleartext_utf16) {
1786 /* refuse the change if someone wants to change with
1787 both UTF16 possibilities at the same time... */
1788 ldb_asprintf_errstring(ldb,
1790 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
1791 return LDB_ERR_UNWILLING_TO_PERFORM;
1795 * adapt the quoted UTF16 string to be a real
1798 old_quoted_utf16_2 = talloc(io->ac, struct ldb_val);
1799 if (old_quoted_utf16_2 == NULL) {
1801 return LDB_ERR_OPERATIONS_ERROR;
1804 old_quoted_utf16_2->data = old_quoted_utf16->data + 2;
1805 old_quoted_utf16_2->length = old_quoted_utf16->length-4;
1807 io->og.cleartext_utf16 = old_quoted_utf16_2;
1808 io->og.nt_hash = NULL;
1809 } else if (old_quoted_utf16) {
1810 /* We have only the hash available -> so no plaintext here */
1811 if (!ac->hash_values) {
1812 /* refuse the change if someone wants to change
1813 the hash without control specified... */
1814 ldb_asprintf_errstring(ldb,
1816 "it's not allowed to set the NT hash password directly'");
1817 return LDB_ERR_UNWILLING_TO_PERFORM;
1820 io->og.nt_hash = talloc(io->ac, struct samr_Password);
1821 memcpy(io->og.nt_hash->hash, old_quoted_utf16->data,
1822 MIN(old_quoted_utf16->length, sizeof(io->og.nt_hash->hash)));
1825 /* Handles the "dBCSPwd" attribute (LM hash) */
1826 io->n.lm_hash = NULL; io->og.lm_hash = NULL;
1827 ret = samdb_msg_find_old_and_new_ldb_val(orig_msg, "dBCSPwd",
1828 &lm_hash, &old_lm_hash);
1829 if (ret != LDB_SUCCESS) {
1830 ldb_asprintf_errstring(ldb,
1832 "it's only allowed to set the old password once!");
1836 if (((lm_hash != NULL) || (old_lm_hash != NULL)) && (!ac->hash_values)) {
1837 /* refuse the change if someone wants to change the hash
1838 without control specified... */
1839 ldb_asprintf_errstring(ldb,
1841 "it's not allowed to set the LM hash password directly'");
1842 return LDB_ERR_UNWILLING_TO_PERFORM;
1844 if (lm_hash != NULL) {
1845 io->n.lm_hash = talloc(io->ac, struct samr_Password);
1846 memcpy(io->n.lm_hash->hash, lm_hash->data, MIN(lm_hash->length,
1847 sizeof(io->n.lm_hash->hash)));
1850 if (old_lm_hash != NULL) {
1851 io->og.lm_hash = talloc(io->ac, struct samr_Password);
1852 memcpy(io->og.lm_hash->hash, old_lm_hash->data, MIN(old_lm_hash->length,
1853 sizeof(io->og.lm_hash->hash)));
1856 /* refuse the change if someone wants to change the clear-
1857 text and supply his own hashes at the same time... */
1858 if ((io->n.cleartext_utf8 || io->n.cleartext_utf16)
1859 && (io->n.nt_hash || io->n.lm_hash)) {
1860 ldb_asprintf_errstring(ldb,
1862 "it's only allowed to set the password in form of cleartext attributes or as hashes");
1863 return LDB_ERR_UNWILLING_TO_PERFORM;
1866 /* refuse the change if someone wants to change the password
1867 using both plaintext methods (UTF8 and UTF16) at the same time... */
1868 if (io->n.cleartext_utf8 && io->n.cleartext_utf16) {
1869 ldb_asprintf_errstring(ldb,
1871 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
1872 return LDB_ERR_UNWILLING_TO_PERFORM;
1875 /* refuse the change if someone wants to compare against a plaintext
1876 or hash at the same time for a "password modify" operation... */
1877 if ((io->og.cleartext_utf8 || io->og.cleartext_utf16)
1878 && (io->og.nt_hash || io->og.lm_hash)) {
1879 ldb_asprintf_errstring(ldb,
1881 "it's only allowed to provide the old password in form of cleartext attributes or as hashes");
1882 return LDB_ERR_UNWILLING_TO_PERFORM;
1885 /* refuse the change if someone wants to compare against both
1886 * plaintexts at the same time for a "password modify" operation... */
1887 if (io->og.cleartext_utf8 && io->og.cleartext_utf16) {
1888 ldb_asprintf_errstring(ldb,
1890 "it's only allowed to provide the old cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
1891 return LDB_ERR_UNWILLING_TO_PERFORM;
1894 /* refuse the change if someone wants to compare against both
1895 * hashes at the same time for a "password modify" operation... */
1896 if (io->og.nt_hash && io->og.lm_hash) {
1897 ldb_asprintf_errstring(ldb,
1899 "it's only allowed to provide the old password in hash format as 'unicodePwd' or as 'dBCSPwd'");
1900 return LDB_ERR_UNWILLING_TO_PERFORM;
1903 /* Decides if we have a password modify or password reset operation */
1904 if (ac->req->operation == LDB_ADD) {
1905 /* On "add" we have only "password reset" */
1906 ac->pwd_reset = true;
1907 } else if (ac->req->operation == LDB_MODIFY) {
1908 if (io->og.cleartext_utf8 || io->og.cleartext_utf16
1909 || io->og.nt_hash || io->og.lm_hash
1910 || ac->change_old_pw_checked) {
1911 /* If we have an old password or the "change old
1912 * password checked" control specified then for sure it
1913 * is a user "password change" */
1914 ac->pwd_reset = false;
1916 /* Otherwise we have also here a "password reset" */
1917 ac->pwd_reset = true;
1920 /* this shouldn't happen */
1921 return LDB_ERR_OPERATIONS_ERROR;
1927 static struct ph_context *ph_init_context(struct ldb_module *module,
1928 struct ldb_request *req)
1930 struct ldb_context *ldb;
1931 struct ph_context *ac;
1933 ldb = ldb_module_get_ctx(module);
1935 ac = talloc_zero(req, struct ph_context);
1937 ldb_set_errstring(ldb, "Out of Memory");
1941 ac->module = module;
1947 static void ph_apply_controls(struct ph_context *ac)
1949 struct ldb_control *ctrl;
1951 ac->change_status = false;
1952 ctrl = ldb_request_get_control(ac->req,
1953 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID);
1955 ac->change_status = true;
1957 /* Mark the "change status" control as uncritical (done) */
1958 ctrl->critical = false;
1961 ac->hash_values = false;
1962 ctrl = ldb_request_get_control(ac->req,
1963 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID);
1965 ac->hash_values = true;
1967 /* Mark the "hash values" control as uncritical (done) */
1968 ctrl->critical = false;
1971 ac->change_old_pw_checked = false;
1972 ctrl = ldb_request_get_control(ac->req,
1973 DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID);
1975 ac->change_old_pw_checked = true;
1977 /* Mark the "change old password checked" control as uncritical
1979 ctrl->critical = false;
1983 static int ph_op_callback(struct ldb_request *req, struct ldb_reply *ares)
1985 struct ph_context *ac;
1987 ac = talloc_get_type(req->context, struct ph_context);
1990 return ldb_module_done(ac->req, NULL, NULL,
1991 LDB_ERR_OPERATIONS_ERROR);
1994 if (ares->type == LDB_REPLY_REFERRAL) {
1995 return ldb_module_send_referral(ac->req, ares->referral);
1998 if ((ares->error != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
1999 /* On success and trivial errors a status control is being
2000 * added (used for example by the "samdb_set_password" call) */
2001 ldb_reply_add_control(ares,
2002 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2007 if (ares->error != LDB_SUCCESS) {
2008 return ldb_module_done(ac->req, ares->controls,
2009 ares->response, ares->error);
2012 if (ares->type != LDB_REPLY_DONE) {
2014 return ldb_module_done(ac->req, NULL, NULL,
2015 LDB_ERR_OPERATIONS_ERROR);
2018 return ldb_module_done(ac->req, ares->controls,
2019 ares->response, ares->error);
2022 static int password_hash_add_do_add(struct ph_context *ac);
2023 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares);
2024 static int password_hash_mod_search_self(struct ph_context *ac);
2025 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares);
2026 static int password_hash_mod_do_mod(struct ph_context *ac);
2028 static int get_domain_data_callback(struct ldb_request *req,
2029 struct ldb_reply *ares)
2031 struct ldb_context *ldb;
2032 struct ph_context *ac;
2033 struct loadparm_context *lp_ctx;
2036 ac = talloc_get_type(req->context, struct ph_context);
2037 ldb = ldb_module_get_ctx(ac->module);
2040 ret = LDB_ERR_OPERATIONS_ERROR;
2043 if (ares->error != LDB_SUCCESS) {
2044 return ldb_module_done(ac->req, ares->controls,
2045 ares->response, ares->error);
2048 switch (ares->type) {
2049 case LDB_REPLY_ENTRY:
2050 if (ac->status != NULL) {
2053 ldb_set_errstring(ldb, "Too many results");
2054 ret = LDB_ERR_OPERATIONS_ERROR;
2058 /* Setup the "status" structure (used as control later) */
2059 ac->status = talloc_zero(ac->req,
2060 struct dsdb_control_password_change_status);
2061 if (ac->status == NULL) {
2065 ret = LDB_ERR_OPERATIONS_ERROR;
2069 /* Setup the "domain data" structure */
2070 ac->status->domain_data.pwdProperties = samdb_result_uint(ares->message, "pwdProperties", -1);
2071 ac->status->domain_data.pwdHistoryLength = samdb_result_uint(ares->message, "pwdHistoryLength", -1);
2072 ac->status->domain_data.maxPwdAge = samdb_result_int64(ares->message, "maxPwdAge", -1);
2073 ac->status->domain_data.minPwdAge = samdb_result_int64(ares->message, "minPwdAge", -1);
2074 ac->status->domain_data.minPwdLength = samdb_result_uint(ares->message, "minPwdLength", -1);
2075 ac->status->domain_data.store_cleartext =
2076 ac->status->domain_data.pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
2080 /* For a domain DN, this puts things in dotted notation */
2081 /* For builtin domains, this will give details for the host,
2082 * but that doesn't really matter, as it's just used for salt
2083 * and kerberos principals, which don't exist here */
2085 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2086 struct loadparm_context);
2088 ac->status->domain_data.dns_domain = lp_dnsdomain(lp_ctx);
2089 ac->status->domain_data.realm = lp_realm(lp_ctx);
2090 ac->status->domain_data.netbios_domain = lp_sam_name(lp_ctx);
2092 ac->status->reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2097 case LDB_REPLY_REFERRAL:
2103 case LDB_REPLY_DONE:
2105 /* call the next step */
2106 switch (ac->req->operation) {
2108 ret = password_hash_add_do_add(ac);
2112 ret = password_hash_mod_do_mod(ac);
2116 ret = LDB_ERR_OPERATIONS_ERROR;
2123 if (ret != LDB_SUCCESS) {
2124 struct ldb_reply *new_ares;
2126 new_ares = talloc_zero(ac->req, struct ldb_reply);
2127 if (new_ares == NULL) {
2129 return ldb_module_done(ac->req, NULL, NULL,
2130 LDB_ERR_OPERATIONS_ERROR);
2133 new_ares->error = ret;
2134 if ((ret != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
2135 /* On success and trivial errors a status control is being
2136 * added (used for example by the "samdb_set_password" call) */
2137 ldb_reply_add_control(new_ares,
2138 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2143 return ldb_module_done(ac->req, new_ares->controls,
2144 new_ares->response, new_ares->error);
2150 static int build_domain_data_request(struct ph_context *ac)
2152 /* attrs[] is returned from this function in
2153 ac->dom_req->op.search.attrs, so it must be static, as
2154 otherwise the compiler can put it on the stack */
2155 struct ldb_context *ldb;
2156 static const char * const attrs[] = { "pwdProperties",
2163 ldb = ldb_module_get_ctx(ac->module);
2165 return ldb_build_search_req(&ac->dom_req, ldb, ac,
2166 ldb_get_default_basedn(ldb),
2170 ac, get_domain_data_callback,
2174 static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
2176 struct ldb_context *ldb;
2177 struct ph_context *ac;
2178 struct ldb_message_element *userPasswordAttr, *clearTextPasswordAttr,
2182 ldb = ldb_module_get_ctx(module);
2184 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add\n");
2186 if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
2187 return ldb_next_request(module, req);
2190 /* If the caller is manipulating the local passwords directly, let them pass */
2191 if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
2192 req->op.add.message->dn) == 0) {
2193 return ldb_next_request(module, req);
2196 /* nobody must touch password histories and 'supplementalCredentials' */
2197 if (ldb_msg_find_element(req->op.add.message, "ntPwdHistory")) {
2198 return LDB_ERR_UNWILLING_TO_PERFORM;
2200 if (ldb_msg_find_element(req->op.add.message, "lmPwdHistory")) {
2201 return LDB_ERR_UNWILLING_TO_PERFORM;
2203 if (ldb_msg_find_element(req->op.add.message, "supplementalCredentials")) {
2204 return LDB_ERR_UNWILLING_TO_PERFORM;
2207 /* If no part of this touches the 'userPassword' OR 'clearTextPassword'
2208 * OR 'unicodePwd' OR 'dBCSPwd' we don't need to make any changes. */
2210 userPasswordAttr = ldb_msg_find_element(req->op.add.message, "userPassword");
2211 clearTextPasswordAttr = ldb_msg_find_element(req->op.add.message, "clearTextPassword");
2212 ntAttr = ldb_msg_find_element(req->op.add.message, "unicodePwd");
2213 lmAttr = ldb_msg_find_element(req->op.add.message, "dBCSPwd");
2215 if ((!userPasswordAttr) && (!clearTextPasswordAttr) && (!ntAttr) && (!lmAttr)) {
2216 return ldb_next_request(module, req);
2219 /* Make sure we are performing the password set action on a (for us)
2220 * valid object. Those are instances of either "user" and/or
2221 * "inetOrgPerson". Otherwise continue with the submodules. */
2222 if ((!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "user"))
2223 && (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "inetOrgPerson"))) {
2225 if (ldb_msg_find_element(req->op.add.message, "clearTextPassword") != NULL) {
2226 ldb_set_errstring(ldb,
2227 "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
2228 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2231 return ldb_next_request(module, req);
2234 ac = ph_init_context(module, req);
2236 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
2237 return LDB_ERR_OPERATIONS_ERROR;
2239 ph_apply_controls(ac);
2241 /* get user domain data */
2242 ret = build_domain_data_request(ac);
2243 if (ret != LDB_SUCCESS) {
2247 return ldb_next_request(module, ac->dom_req);
2250 static int password_hash_add_do_add(struct ph_context *ac)
2252 struct ldb_context *ldb;
2253 struct ldb_request *down_req;
2254 struct ldb_message *msg;
2255 struct setup_password_fields_io io;
2258 /* Prepare the internal data structure containing the passwords */
2259 ret = setup_io(ac, ac->req->op.add.message, ac->req->op.add.message, &io);
2260 if (ret != LDB_SUCCESS) {
2264 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
2266 return LDB_ERR_OPERATIONS_ERROR;
2269 /* remove attributes that we just read into 'io' (handle also superfluous
2270 * "password modify" trials - multiple attributes with the same name -
2271 * on add operations) */
2272 while (ldb_msg_find_element(msg, "userPassword") != NULL) {
2273 ldb_msg_remove_attr(msg, "userPassword");
2275 while (ldb_msg_find_element(msg, "clearTextPassword") != NULL) {
2276 ldb_msg_remove_attr(msg, "clearTextPassword");
2278 while (ldb_msg_find_element(msg, "unicodePwd") != NULL) {
2279 ldb_msg_remove_attr(msg, "unicodePwd");
2281 while (ldb_msg_find_element(msg, "dBCSPwd") != NULL) {
2282 ldb_msg_remove_attr(msg, "dBCSPwd");
2285 ldb_msg_remove_attr(msg, "pwdLastSet");
2287 ldb = ldb_module_get_ctx(ac->module);
2289 ret = setup_password_fields(&io);
2290 if (ret != LDB_SUCCESS) {
2294 ret = check_password_restrictions(&io);
2295 if (ret != LDB_SUCCESS) {
2300 ret = samdb_msg_add_hash(ldb, ac, msg,
2301 "unicodePwd", io.g.nt_hash);
2302 if (ret != LDB_SUCCESS) {
2307 ret = samdb_msg_add_hash(ldb, ac, msg,
2308 "dBCSPwd", io.g.lm_hash);
2309 if (ret != LDB_SUCCESS) {
2313 if (io.g.nt_history_len > 0) {
2314 ret = samdb_msg_add_hashes(ac, msg,
2317 io.g.nt_history_len);
2318 if (ret != LDB_SUCCESS) {
2322 if (io.g.lm_history_len > 0) {
2323 ret = samdb_msg_add_hashes(ac, msg,
2326 io.g.lm_history_len);
2327 if (ret != LDB_SUCCESS) {
2331 if (io.g.supplemental.length > 0) {
2332 ret = ldb_msg_add_value(msg, "supplementalCredentials",
2333 &io.g.supplemental, NULL);
2334 if (ret != LDB_SUCCESS) {
2338 ret = samdb_msg_add_uint64(ldb, ac, msg,
2341 if (ret != LDB_SUCCESS) {
2345 ret = ldb_build_add_req(&down_req, ldb, ac,
2350 if (ret != LDB_SUCCESS) {
2354 return ldb_next_request(ac->module, down_req);
2357 static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
2359 struct ldb_context *ldb;
2360 struct ph_context *ac;
2361 const char *passwordAttrs[] = { "userPassword", "clearTextPassword",
2362 "unicodePwd", "dBCSPwd", NULL }, **l;
2363 unsigned int attr_cnt, del_attr_cnt, add_attr_cnt, rep_attr_cnt;
2364 struct ldb_message_element *passwordAttr;
2365 struct ldb_message *msg;
2366 struct ldb_request *down_req;
2369 ldb = ldb_module_get_ctx(module);
2371 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
2373 if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
2374 return ldb_next_request(module, req);
2377 /* If the caller is manipulating the local passwords directly, let them pass */
2378 if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
2379 req->op.mod.message->dn) == 0) {
2380 return ldb_next_request(module, req);
2383 /* nobody must touch password histories and 'supplementalCredentials' */
2384 if (ldb_msg_find_element(req->op.mod.message, "ntPwdHistory")) {
2385 return LDB_ERR_UNWILLING_TO_PERFORM;
2387 if (ldb_msg_find_element(req->op.mod.message, "lmPwdHistory")) {
2388 return LDB_ERR_UNWILLING_TO_PERFORM;
2390 if (ldb_msg_find_element(req->op.mod.message, "supplementalCredentials")) {
2391 return LDB_ERR_UNWILLING_TO_PERFORM;
2394 /* If no part of this touches the 'userPassword' OR 'clearTextPassword'
2395 * OR 'unicodePwd' OR 'dBCSPwd' we don't need to make any changes.
2396 * For password changes/set there should be a 'delete' or a 'modify'
2397 * on these attributes. */
2399 for (l = passwordAttrs; *l != NULL; l++) {
2400 if (ldb_msg_find_element(req->op.mod.message, *l) != NULL) {
2404 if (attr_cnt == 0) {
2405 return ldb_next_request(module, req);
2408 ac = ph_init_context(module, req);
2410 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
2411 return LDB_ERR_OPERATIONS_ERROR;
2413 ph_apply_controls(ac);
2415 /* use a new message structure so that we can modify it */
2416 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2419 return LDB_ERR_OPERATIONS_ERROR;
2422 /* - check for single-valued password attributes
2423 * (if not return "CONSTRAINT_VIOLATION")
2424 * - check that for a password change operation one add and one delete
2426 * (if not return "CONSTRAINT_VIOLATION" or "UNWILLING_TO_PERFORM")
2427 * - check that a password change and a password set operation cannot
2429 * (if not return "UNWILLING_TO_PERFORM")
2430 * - remove all password attributes modifications from the first change
2431 * operation (anything without the passwords) - we will make the real
2432 * modification later */
2436 for (l = passwordAttrs; *l != NULL; l++) {
2437 while ((passwordAttr = ldb_msg_find_element(msg, *l)) != NULL) {
2438 if (passwordAttr->flags == LDB_FLAG_MOD_DELETE) {
2441 if (passwordAttr->flags == LDB_FLAG_MOD_ADD) {
2444 if (passwordAttr->flags == LDB_FLAG_MOD_REPLACE) {
2447 if ((passwordAttr->num_values != 1) &&
2448 (passwordAttr->flags != LDB_FLAG_MOD_REPLACE)) {
2450 ldb_asprintf_errstring(ldb,
2451 "'%s' attributes must have exactly one value!",
2453 return LDB_ERR_CONSTRAINT_VIOLATION;
2455 ldb_msg_remove_attr(msg, *l);
2458 if ((del_attr_cnt > 0) && (add_attr_cnt == 0)) {
2460 ldb_set_errstring(ldb,
2461 "Only the delete action for a password change specified!");
2462 return LDB_ERR_CONSTRAINT_VIOLATION;
2464 if ((del_attr_cnt == 0) && (add_attr_cnt > 0)) {
2466 ldb_set_errstring(ldb,
2467 "Only the add action for a password change specified!");
2468 return LDB_ERR_UNWILLING_TO_PERFORM;
2470 if ((del_attr_cnt > 1) || (add_attr_cnt > 1)) {
2472 ldb_set_errstring(ldb,
2473 "Only one delete and one add action for a password change allowed!");
2474 return LDB_ERR_UNWILLING_TO_PERFORM;
2476 if ((rep_attr_cnt > 0) && ((del_attr_cnt > 0) || (add_attr_cnt > 0))) {
2478 ldb_set_errstring(ldb,
2479 "Either a password change or a password set operation is allowed!");
2480 return LDB_ERR_UNWILLING_TO_PERFORM;
2483 /* if there was nothing else to be modified skip to next step */
2484 if (msg->num_elements == 0) {
2485 return password_hash_mod_search_self(ac);
2488 ret = ldb_build_mod_req(&down_req, ldb, ac,
2491 ac, ph_modify_callback,
2493 if (ret != LDB_SUCCESS) {
2497 return ldb_next_request(module, down_req);
2500 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
2502 struct ph_context *ac;
2504 ac = talloc_get_type(req->context, struct ph_context);
2507 return ldb_module_done(ac->req, NULL, NULL,
2508 LDB_ERR_OPERATIONS_ERROR);
2511 if (ares->type == LDB_REPLY_REFERRAL) {
2512 return ldb_module_send_referral(ac->req, ares->referral);
2515 if (ares->error != LDB_SUCCESS) {
2516 return ldb_module_done(ac->req, ares->controls,
2517 ares->response, ares->error);
2520 if (ares->type != LDB_REPLY_DONE) {
2522 return ldb_module_done(ac->req, NULL, NULL,
2523 LDB_ERR_OPERATIONS_ERROR);
2528 return password_hash_mod_search_self(ac);
2531 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
2533 struct ldb_context *ldb;
2534 struct ph_context *ac;
2537 ac = talloc_get_type(req->context, struct ph_context);
2538 ldb = ldb_module_get_ctx(ac->module);
2541 ret = LDB_ERR_OPERATIONS_ERROR;
2544 if (ares->error != LDB_SUCCESS) {
2545 return ldb_module_done(ac->req, ares->controls,
2546 ares->response, ares->error);
2549 /* we are interested only in the single reply (base search) */
2550 switch (ares->type) {
2551 case LDB_REPLY_ENTRY:
2552 /* Make sure we are performing the password change action on a
2553 * (for us) valid object. Those are instances of either "user"
2554 * and/or "inetOrgPerson". Otherwise continue with the
2556 if ((!ldb_msg_check_string_attribute(ares->message, "objectClass", "user"))
2557 && (!ldb_msg_check_string_attribute(ares->message, "objectClass", "inetOrgPerson"))) {
2560 if (ldb_msg_find_element(ac->req->op.mod.message, "clearTextPassword") != NULL) {
2561 ldb_set_errstring(ldb,
2562 "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
2563 ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
2567 ret = ldb_next_request(ac->module, ac->req);
2571 if (ac->search_res != NULL) {
2574 ldb_set_errstring(ldb, "Too many results");
2575 ret = LDB_ERR_OPERATIONS_ERROR;
2579 ac->search_res = talloc_steal(ac, ares);
2583 case LDB_REPLY_REFERRAL:
2584 /* ignore anything else for now */
2589 case LDB_REPLY_DONE:
2592 /* get user domain data */
2593 ret = build_domain_data_request(ac);
2594 if (ret != LDB_SUCCESS) {
2595 return ldb_module_done(ac->req, NULL, NULL, ret);
2598 ret = ldb_next_request(ac->module, ac->dom_req);
2603 if (ret != LDB_SUCCESS) {
2604 return ldb_module_done(ac->req, NULL, NULL, ret);
2610 static int password_hash_mod_search_self(struct ph_context *ac)
2612 struct ldb_context *ldb;
2613 static const char * const attrs[] = { "objectClass",
2614 "userAccountControl",
2618 "userPrincipalName",
2619 "supplementalCredentials",
2625 struct ldb_request *search_req;
2628 ldb = ldb_module_get_ctx(ac->module);
2630 ret = ldb_build_search_req(&search_req, ldb, ac,
2631 ac->req->op.mod.message->dn,
2636 ac, ph_mod_search_callback,
2639 if (ret != LDB_SUCCESS) {
2643 return ldb_next_request(ac->module, search_req);
2646 static int password_hash_mod_do_mod(struct ph_context *ac)
2648 struct ldb_context *ldb;
2649 struct ldb_request *mod_req;
2650 struct ldb_message *msg;
2651 const struct ldb_message *orig_msg, *searched_msg;
2652 struct setup_password_fields_io io;
2656 ldb = ldb_module_get_ctx(ac->module);
2658 /* use a new message structure so that we can modify it */
2659 msg = ldb_msg_new(ac);
2661 return LDB_ERR_OPERATIONS_ERROR;
2665 msg->dn = ac->req->op.mod.message->dn;
2667 orig_msg = ac->req->op.mod.message;
2668 searched_msg = ac->search_res->message;
2670 /* Prepare the internal data structure containing the passwords */
2671 ret = setup_io(ac, orig_msg, searched_msg, &io);
2672 if (ret != LDB_SUCCESS) {
2676 /* Get the old password from the database */
2677 status = samdb_result_passwords(io.ac,
2678 ldb_get_opaque(ldb, "loadparm"),
2679 discard_const_p(struct ldb_message, searched_msg),
2680 &io.o.lm_hash, &io.o.nt_hash);
2681 if (!NT_STATUS_IS_OK(status)) {
2682 return LDB_ERR_OPERATIONS_ERROR;
2685 io.o.nt_history_len = samdb_result_hashes(io.ac, searched_msg, "ntPwdHistory", &io.o.nt_history);
2686 io.o.lm_history_len = samdb_result_hashes(io.ac, searched_msg, "lmPwdHistory", &io.o.lm_history);
2687 io.o.supplemental = ldb_msg_find_ldb_val(searched_msg, "supplementalCredentials");
2689 ret = setup_password_fields(&io);
2690 if (ret != LDB_SUCCESS) {
2694 ret = check_password_restrictions(&io);
2695 if (ret != LDB_SUCCESS) {
2699 /* make sure we replace all the old attributes */
2700 ret = ldb_msg_add_empty(msg, "unicodePwd", LDB_FLAG_MOD_REPLACE, NULL);
2701 ret = ldb_msg_add_empty(msg, "dBCSPwd", LDB_FLAG_MOD_REPLACE, NULL);
2702 ret = ldb_msg_add_empty(msg, "ntPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
2703 ret = ldb_msg_add_empty(msg, "lmPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
2704 ret = ldb_msg_add_empty(msg, "supplementalCredentials", LDB_FLAG_MOD_REPLACE, NULL);
2705 ret = ldb_msg_add_empty(msg, "pwdLastSet", LDB_FLAG_MOD_REPLACE, NULL);
2708 ret = samdb_msg_add_hash(ldb, ac, msg,
2709 "unicodePwd", io.g.nt_hash);
2710 if (ret != LDB_SUCCESS) {
2715 ret = samdb_msg_add_hash(ldb, ac, msg,
2716 "dBCSPwd", io.g.lm_hash);
2717 if (ret != LDB_SUCCESS) {
2721 if (io.g.nt_history_len > 0) {
2722 ret = samdb_msg_add_hashes(ac, msg,
2725 io.g.nt_history_len);
2726 if (ret != LDB_SUCCESS) {
2730 if (io.g.lm_history_len > 0) {
2731 ret = samdb_msg_add_hashes(ac, msg,
2734 io.g.lm_history_len);
2735 if (ret != LDB_SUCCESS) {
2739 if (io.g.supplemental.length > 0) {
2740 ret = ldb_msg_add_value(msg, "supplementalCredentials",
2741 &io.g.supplemental, NULL);
2742 if (ret != LDB_SUCCESS) {
2746 ret = samdb_msg_add_uint64(ldb, ac, msg,
2749 if (ret != LDB_SUCCESS) {
2753 ret = ldb_build_mod_req(&mod_req, ldb, ac,
2758 if (ret != LDB_SUCCESS) {
2762 return ldb_next_request(ac->module, mod_req);
2765 _PUBLIC_ const struct ldb_module_ops ldb_password_hash_module_ops = {
2766 .name = "password_hash",
2767 .add = password_hash_add,
2768 .modify = password_hash_modify