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;
98 struct dsdb_control_password_change *change;
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) {
183 for (i = 0; i < MIN(io->ac->status->domain_data.pwdHistoryLength-1,
184 io->o.nt_history_len); i++) {
185 io->g.nt_history[i+1] = io->o.nt_history[i];
187 io->g.nt_history_len = i + 1;
190 io->g.nt_history[0] = *io->g.nt_hash;
193 * TODO: is this correct?
194 * the simular behavior is correct for the lm history case
196 E_md4hash("", io->g.nt_history[0].hash);
202 /* Get the LANMAN hash, and fill it in as an entry in the password history,
203 and specify it into io->g.lm_hash */
205 static int setup_lm_fields(struct setup_password_fields_io *io)
207 struct ldb_context *ldb;
210 io->g.lm_hash = io->n.lm_hash;
211 ldb = ldb_module_get_ctx(io->ac->module);
213 if (io->ac->status->domain_data.pwdHistoryLength == 0) {
217 /* We might not have an old LM password */
218 io->g.lm_history = talloc_array(io->ac,
219 struct samr_Password,
220 io->ac->status->domain_data.pwdHistoryLength);
221 if (!io->g.lm_history) {
225 for (i = 0; i < MIN(io->ac->status->domain_data.pwdHistoryLength-1,
226 io->o.lm_history_len); i++) {
227 io->g.lm_history[i+1] = io->o.lm_history[i];
229 io->g.lm_history_len = i + 1;
232 io->g.lm_history[0] = *io->g.lm_hash;
234 E_deshash("", io->g.lm_history[0].hash);
240 static int setup_kerberos_keys(struct setup_password_fields_io *io)
242 struct ldb_context *ldb;
243 krb5_error_code krb5_ret;
244 Principal *salt_principal;
247 krb5_data cleartext_data;
249 ldb = ldb_module_get_ctx(io->ac->module);
250 cleartext_data.data = io->n.cleartext_utf8->data;
251 cleartext_data.length = io->n.cleartext_utf8->length;
253 /* Many, many thanks to lukeh@padl.com for this
254 * algorithm, described in his Nov 10 2004 mail to
255 * samba-technical@samba.org */
258 * Determine a salting principal
260 if (io->u.is_computer) {
264 name = strlower_talloc(io->ac, io->u.sAMAccountName);
269 if (name[strlen(name)-1] == '$') {
270 name[strlen(name)-1] = '\0';
273 saltbody = talloc_asprintf(io->ac, "%s.%s", name,
274 io->ac->status->domain_data.dns_domain);
279 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
281 io->ac->status->domain_data.realm,
282 "host", saltbody, NULL);
283 } else if (io->u.user_principal_name) {
284 char *user_principal_name;
287 user_principal_name = talloc_strdup(io->ac, io->u.user_principal_name);
288 if (!user_principal_name) {
292 p = strchr(user_principal_name, '@');
297 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
299 io->ac->status->domain_data.realm,
300 user_principal_name, NULL);
302 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
304 io->ac->status->domain_data.realm,
305 io->u.sAMAccountName, NULL);
308 ldb_asprintf_errstring(ldb,
309 "setup_kerberos_keys: "
310 "generation of a salting principal failed: %s",
311 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
313 return LDB_ERR_OPERATIONS_ERROR;
317 * create salt from salt_principal
319 krb5_ret = krb5_get_pw_salt(io->smb_krb5_context->krb5_context,
320 salt_principal, &salt);
321 krb5_free_principal(io->smb_krb5_context->krb5_context, salt_principal);
323 ldb_asprintf_errstring(ldb,
324 "setup_kerberos_keys: "
325 "generation of krb5_salt failed: %s",
326 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
328 return LDB_ERR_OPERATIONS_ERROR;
330 /* create a talloc copy */
331 io->g.salt = talloc_strndup(io->ac,
332 (char *)salt.saltvalue.data,
333 salt.saltvalue.length);
334 krb5_free_salt(io->smb_krb5_context->krb5_context, salt);
338 salt.saltvalue.data = discard_const(io->g.salt);
339 salt.saltvalue.length = strlen(io->g.salt);
342 * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of
343 * the salt and the cleartext password
345 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
346 ENCTYPE_AES256_CTS_HMAC_SHA1_96,
351 ldb_asprintf_errstring(ldb,
352 "setup_kerberos_keys: "
353 "generation of a aes256-cts-hmac-sha1-96 key failed: %s",
354 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
356 return LDB_ERR_OPERATIONS_ERROR;
358 io->g.aes_256 = data_blob_talloc(io->ac,
360 key.keyvalue.length);
361 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
362 if (!io->g.aes_256.data) {
367 * create ENCTYPE_AES128_CTS_HMAC_SHA1_96 key out of
368 * the salt and the cleartext password
370 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
371 ENCTYPE_AES128_CTS_HMAC_SHA1_96,
376 ldb_asprintf_errstring(ldb,
377 "setup_kerberos_keys: "
378 "generation of a aes128-cts-hmac-sha1-96 key failed: %s",
379 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
381 return LDB_ERR_OPERATIONS_ERROR;
383 io->g.aes_128 = data_blob_talloc(io->ac,
385 key.keyvalue.length);
386 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
387 if (!io->g.aes_128.data) {
392 * create ENCTYPE_DES_CBC_MD5 key out of
393 * the salt and the cleartext password
395 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
401 ldb_asprintf_errstring(ldb,
402 "setup_kerberos_keys: "
403 "generation of a des-cbc-md5 key failed: %s",
404 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
406 return LDB_ERR_OPERATIONS_ERROR;
408 io->g.des_md5 = data_blob_talloc(io->ac,
410 key.keyvalue.length);
411 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
412 if (!io->g.des_md5.data) {
417 * create ENCTYPE_DES_CBC_CRC key out of
418 * the salt and the cleartext password
420 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
426 ldb_asprintf_errstring(ldb,
427 "setup_kerberos_keys: "
428 "generation of a des-cbc-crc key failed: %s",
429 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
431 return LDB_ERR_OPERATIONS_ERROR;
433 io->g.des_crc = data_blob_talloc(io->ac,
435 key.keyvalue.length);
436 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
437 if (!io->g.des_crc.data) {
444 static int setup_primary_kerberos(struct setup_password_fields_io *io,
445 const struct supplementalCredentialsBlob *old_scb,
446 struct package_PrimaryKerberosBlob *pkb)
448 struct ldb_context *ldb;
449 struct package_PrimaryKerberosCtr3 *pkb3 = &pkb->ctr.ctr3;
450 struct supplementalCredentialsPackage *old_scp = NULL;
451 struct package_PrimaryKerberosBlob _old_pkb;
452 struct package_PrimaryKerberosCtr3 *old_pkb3 = NULL;
454 enum ndr_err_code ndr_err;
456 ldb = ldb_module_get_ctx(io->ac->module);
459 * prepare generation of keys
461 * ENCTYPE_DES_CBC_MD5
462 * ENCTYPE_DES_CBC_CRC
465 pkb3->salt.string = io->g.salt;
467 pkb3->keys = talloc_array(io->ac,
468 struct package_PrimaryKerberosKey3,
474 pkb3->keys[0].keytype = ENCTYPE_DES_CBC_MD5;
475 pkb3->keys[0].value = &io->g.des_md5;
476 pkb3->keys[1].keytype = ENCTYPE_DES_CBC_CRC;
477 pkb3->keys[1].value = &io->g.des_crc;
479 /* initialize the old keys to zero */
480 pkb3->num_old_keys = 0;
481 pkb3->old_keys = NULL;
483 /* if there're no old keys, then we're done */
488 for (i=0; i < old_scb->sub.num_packages; i++) {
489 if (strcmp("Primary:Kerberos", old_scb->sub.packages[i].name) != 0) {
493 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
497 old_scp = &old_scb->sub.packages[i];
500 /* Primary:Kerberos element of supplementalCredentials */
504 blob = strhex_to_data_blob(io->ac, old_scp->data);
509 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
510 ndr_err = ndr_pull_struct_blob(&blob, io->ac, &_old_pkb,
511 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
512 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
513 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
514 ldb_asprintf_errstring(ldb,
515 "setup_primary_kerberos: "
516 "failed to pull old package_PrimaryKerberosBlob: %s",
518 return LDB_ERR_OPERATIONS_ERROR;
521 if (_old_pkb.version != 3) {
522 ldb_asprintf_errstring(ldb,
523 "setup_primary_kerberos: "
524 "package_PrimaryKerberosBlob version[%u] expected[3]",
526 return LDB_ERR_OPERATIONS_ERROR;
529 old_pkb3 = &_old_pkb.ctr.ctr3;
532 /* if we didn't found the old keys we're done */
537 /* fill in the old keys */
538 pkb3->num_old_keys = old_pkb3->num_keys;
539 pkb3->old_keys = old_pkb3->keys;
544 static int setup_primary_kerberos_newer(struct setup_password_fields_io *io,
545 const struct supplementalCredentialsBlob *old_scb,
546 struct package_PrimaryKerberosBlob *pkb)
548 struct ldb_context *ldb;
549 struct package_PrimaryKerberosCtr4 *pkb4 = &pkb->ctr.ctr4;
550 struct supplementalCredentialsPackage *old_scp = NULL;
551 struct package_PrimaryKerberosBlob _old_pkb;
552 struct package_PrimaryKerberosCtr4 *old_pkb4 = NULL;
554 enum ndr_err_code ndr_err;
556 ldb = ldb_module_get_ctx(io->ac->module);
559 * prepare generation of keys
561 * ENCTYPE_AES256_CTS_HMAC_SHA1_96
562 * ENCTYPE_AES128_CTS_HMAC_SHA1_96
563 * ENCTYPE_DES_CBC_MD5
564 * ENCTYPE_DES_CBC_CRC
567 pkb4->salt.string = io->g.salt;
568 pkb4->default_iteration_count = 4096;
571 pkb4->keys = talloc_array(io->ac,
572 struct package_PrimaryKerberosKey4,
578 pkb4->keys[0].iteration_count = 4096;
579 pkb4->keys[0].keytype = ENCTYPE_AES256_CTS_HMAC_SHA1_96;
580 pkb4->keys[0].value = &io->g.aes_256;
581 pkb4->keys[1].iteration_count = 4096;
582 pkb4->keys[1].keytype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
583 pkb4->keys[1].value = &io->g.aes_128;
584 pkb4->keys[2].iteration_count = 4096;
585 pkb4->keys[2].keytype = ENCTYPE_DES_CBC_MD5;
586 pkb4->keys[2].value = &io->g.des_md5;
587 pkb4->keys[3].iteration_count = 4096;
588 pkb4->keys[3].keytype = ENCTYPE_DES_CBC_CRC;
589 pkb4->keys[3].value = &io->g.des_crc;
591 /* initialize the old keys to zero */
592 pkb4->num_old_keys = 0;
593 pkb4->old_keys = NULL;
594 pkb4->num_older_keys = 0;
595 pkb4->older_keys = NULL;
597 /* if there're no old keys, then we're done */
602 for (i=0; i < old_scb->sub.num_packages; i++) {
603 if (strcmp("Primary:Kerberos-Newer-Keys", old_scb->sub.packages[i].name) != 0) {
607 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
611 old_scp = &old_scb->sub.packages[i];
614 /* Primary:Kerberos-Newer-Keys element of supplementalCredentials */
618 blob = strhex_to_data_blob(io->ac, old_scp->data);
623 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
624 ndr_err = ndr_pull_struct_blob(&blob, io->ac,
626 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
627 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
628 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
629 ldb_asprintf_errstring(ldb,
630 "setup_primary_kerberos_newer: "
631 "failed to pull old package_PrimaryKerberosBlob: %s",
633 return LDB_ERR_OPERATIONS_ERROR;
636 if (_old_pkb.version != 4) {
637 ldb_asprintf_errstring(ldb,
638 "setup_primary_kerberos_newer: "
639 "package_PrimaryKerberosBlob version[%u] expected[4]",
641 return LDB_ERR_OPERATIONS_ERROR;
644 old_pkb4 = &_old_pkb.ctr.ctr4;
647 /* if we didn't found the old keys we're done */
652 /* fill in the old keys */
653 pkb4->num_old_keys = old_pkb4->num_keys;
654 pkb4->old_keys = old_pkb4->keys;
655 pkb4->num_older_keys = old_pkb4->num_old_keys;
656 pkb4->older_keys = old_pkb4->old_keys;
661 static int setup_primary_wdigest(struct setup_password_fields_io *io,
662 const struct supplementalCredentialsBlob *old_scb,
663 struct package_PrimaryWDigestBlob *pdb)
665 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
666 DATA_BLOB sAMAccountName;
667 DATA_BLOB sAMAccountName_l;
668 DATA_BLOB sAMAccountName_u;
669 const char *user_principal_name = io->u.user_principal_name;
670 DATA_BLOB userPrincipalName;
671 DATA_BLOB userPrincipalName_l;
672 DATA_BLOB userPrincipalName_u;
673 DATA_BLOB netbios_domain;
674 DATA_BLOB netbios_domain_l;
675 DATA_BLOB netbios_domain_u;
676 DATA_BLOB dns_domain;
677 DATA_BLOB dns_domain_l;
678 DATA_BLOB dns_domain_u;
690 * http://technet2.microsoft.com/WindowsServer/en/library/717b450c-f4a0-4cc9-86f4-cc0633aae5f91033.mspx?mfr=true
691 * for what precalculated hashes are supposed to be stored...
693 * I can't reproduce all values which should contain "Digest" as realm,
694 * am I doing something wrong or is w2k3 just broken...?
696 * W2K3 fills in following for a user:
698 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
699 * sAMAccountName: NewUser2Sam
700 * userPrincipalName: NewUser2Princ@sub1.w2k3.vmnet1.vm.base
702 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
703 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
704 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
705 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
706 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
707 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
708 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
709 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
710 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
711 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
712 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
713 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
714 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
715 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
716 * 221c55284451ae9b3aacaa2a3c86f10f => NewUser2Princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
717 * 74e1be668853d4324d38c07e2acfb8ea => (w2k3 has a bug here!) newuser2princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
718 * e1e244ab7f098e3ae1761be7f9229bbb => NEWUSER2PRINC@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
719 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
720 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
721 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
722 * 31dc704d3640335b2123d4ee28aa1f11 => ??? changes with NewUser2Sam => NewUser1Sam
723 * 36349f5cecd07320fb3bb0e119230c43 => ??? changes with NewUser2Sam => NewUser1Sam
724 * 12adf019d037fb535c01fd0608e78d9d => ??? changes with NewUser2Sam => NewUser1Sam
725 * 6feecf8e724906f3ee1105819c5105a1 => ??? changes with NewUser2Princ => NewUser1Princ
726 * 6c6911f3de6333422640221b9c51ff1f => ??? changes with NewUser2Princ => NewUser1Princ
727 * 4b279877e742895f9348ac67a8de2f69 => ??? changes with NewUser2Princ => NewUser1Princ
728 * db0c6bff069513e3ebb9870d29b57490 => ??? changes with NewUser2Sam => NewUser1Sam
729 * 45072621e56b1c113a4e04a8ff68cd0e => ??? changes with NewUser2Sam => NewUser1Sam
730 * 11d1220abc44a9c10cf91ef4a9c1de02 => ??? changes with NewUser2Sam => NewUser1Sam
732 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
733 * sAMAccountName: NewUser2Sam
735 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
736 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
737 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
738 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
739 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
740 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
741 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
742 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
743 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
744 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
745 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
746 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
747 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
748 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
749 * 8a140d30b6f0a5912735dc1e3bc993b4 => NewUser2Sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
750 * 86d95b2faae6cae4ec261e7fbaccf093 => (here w2k3 is correct) newuser2sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
751 * dfeff1493110220efcdfc6362e5f5450 => NEWUSER2SAM@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
752 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
753 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
754 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
755 * 31dc704d3640335b2123d4ee28aa1f11 => ???M1 changes with NewUser2Sam => NewUser1Sam
756 * 36349f5cecd07320fb3bb0e119230c43 => ???M1.L changes with newuser2sam => newuser1sam
757 * 12adf019d037fb535c01fd0608e78d9d => ???M1.U changes with NEWUSER2SAM => NEWUSER1SAM
758 * 569b4533f2d9e580211dd040e5e360a8 => ???M2 changes with NewUser2Princ => NewUser1Princ
759 * 52528bddf310a587c5d7e6a9ae2cbb20 => ???M2.L changes with newuser2princ => newuser1princ
760 * 4f629a4f0361289ca4255ab0f658fcd5 => ???M3 changes with NewUser2Princ => NewUser1Princ (doesn't depend on case of userPrincipal )
761 * db0c6bff069513e3ebb9870d29b57490 => ???M4 changes with NewUser2Sam => NewUser1Sam
762 * 45072621e56b1c113a4e04a8ff68cd0e => ???M5 changes with NewUser2Sam => NewUser1Sam (doesn't depend on case of sAMAccountName)
763 * 11d1220abc44a9c10cf91ef4a9c1de02 => ???M4.U changes with NEWUSER2SAM => NEWUSER1SAM
767 * sAMAccountName, netbios_domain
770 .user = &sAMAccountName,
771 .realm = &netbios_domain,
774 .user = &sAMAccountName_l,
775 .realm = &netbios_domain_l,
778 .user = &sAMAccountName_u,
779 .realm = &netbios_domain_u,
782 .user = &sAMAccountName,
783 .realm = &netbios_domain_u,
786 .user = &sAMAccountName,
787 .realm = &netbios_domain_l,
790 .user = &sAMAccountName_u,
791 .realm = &netbios_domain_l,
794 .user = &sAMAccountName_l,
795 .realm = &netbios_domain_u,
798 * sAMAccountName, dns_domain
801 .user = &sAMAccountName,
802 .realm = &dns_domain,
805 .user = &sAMAccountName_l,
806 .realm = &dns_domain_l,
809 .user = &sAMAccountName_u,
810 .realm = &dns_domain_u,
813 .user = &sAMAccountName,
814 .realm = &dns_domain_u,
817 .user = &sAMAccountName,
818 .realm = &dns_domain_l,
821 .user = &sAMAccountName_u,
822 .realm = &dns_domain_l,
825 .user = &sAMAccountName_l,
826 .realm = &dns_domain_u,
829 * userPrincipalName, no realm
832 .user = &userPrincipalName,
836 * NOTE: w2k3 messes this up, if the user has a real userPrincipalName,
837 * the fallback to the sAMAccountName based userPrincipalName is correct
839 .user = &userPrincipalName_l,
842 .user = &userPrincipalName_u,
845 * nt4dom\sAMAccountName, no realm
848 .user = &sAMAccountName,
849 .nt4dom = &netbios_domain
852 .user = &sAMAccountName_l,
853 .nt4dom = &netbios_domain_l
856 .user = &sAMAccountName_u,
857 .nt4dom = &netbios_domain_u
861 * the following ones are guessed depending on the technet2 article
862 * but not reproducable on a w2k3 server
864 /* sAMAccountName with "Digest" realm */
866 .user = &sAMAccountName,
870 .user = &sAMAccountName_l,
874 .user = &sAMAccountName_u,
877 /* userPrincipalName with "Digest" realm */
879 .user = &userPrincipalName,
883 .user = &userPrincipalName_l,
887 .user = &userPrincipalName_u,
890 /* nt4dom\\sAMAccountName with "Digest" realm */
892 .user = &sAMAccountName,
893 .nt4dom = &netbios_domain,
897 .user = &sAMAccountName_l,
898 .nt4dom = &netbios_domain_l,
902 .user = &sAMAccountName_u,
903 .nt4dom = &netbios_domain_u,
908 /* prepare DATA_BLOB's used in the combinations array */
909 sAMAccountName = data_blob_string_const(io->u.sAMAccountName);
910 sAMAccountName_l = data_blob_string_const(strlower_talloc(io->ac, io->u.sAMAccountName));
911 if (!sAMAccountName_l.data) {
914 sAMAccountName_u = data_blob_string_const(strupper_talloc(io->ac, io->u.sAMAccountName));
915 if (!sAMAccountName_u.data) {
919 /* if the user doesn't have a userPrincipalName, create one (with lower case realm) */
920 if (!user_principal_name) {
921 user_principal_name = talloc_asprintf(io->ac, "%s@%s",
922 io->u.sAMAccountName,
923 io->ac->status->domain_data.dns_domain);
924 if (!user_principal_name) {
928 userPrincipalName = data_blob_string_const(user_principal_name);
929 userPrincipalName_l = data_blob_string_const(strlower_talloc(io->ac, user_principal_name));
930 if (!userPrincipalName_l.data) {
933 userPrincipalName_u = data_blob_string_const(strupper_talloc(io->ac, user_principal_name));
934 if (!userPrincipalName_u.data) {
938 netbios_domain = data_blob_string_const(io->ac->status->domain_data.netbios_domain);
939 netbios_domain_l = data_blob_string_const(strlower_talloc(io->ac,
940 io->ac->status->domain_data.netbios_domain));
941 if (!netbios_domain_l.data) {
944 netbios_domain_u = data_blob_string_const(strupper_talloc(io->ac,
945 io->ac->status->domain_data.netbios_domain));
946 if (!netbios_domain_u.data) {
950 dns_domain = data_blob_string_const(io->ac->status->domain_data.dns_domain);
951 dns_domain_l = data_blob_string_const(io->ac->status->domain_data.dns_domain);
952 dns_domain_u = data_blob_string_const(io->ac->status->domain_data.realm);
954 digest = data_blob_string_const("Digest");
956 delim = data_blob_string_const(":");
957 backslash = data_blob_string_const("\\");
959 pdb->num_hashes = ARRAY_SIZE(wdigest);
960 pdb->hashes = talloc_array(io->ac, struct package_PrimaryWDigestHash,
966 for (i=0; i < ARRAY_SIZE(wdigest); i++) {
967 struct MD5Context md5;
969 if (wdigest[i].nt4dom) {
970 MD5Update(&md5, wdigest[i].nt4dom->data, wdigest[i].nt4dom->length);
971 MD5Update(&md5, backslash.data, backslash.length);
973 MD5Update(&md5, wdigest[i].user->data, wdigest[i].user->length);
974 MD5Update(&md5, delim.data, delim.length);
975 if (wdigest[i].realm) {
976 MD5Update(&md5, wdigest[i].realm->data, wdigest[i].realm->length);
978 MD5Update(&md5, delim.data, delim.length);
979 MD5Update(&md5, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length);
980 MD5Final(pdb->hashes[i].hash, &md5);
986 static int setup_supplemental_field(struct setup_password_fields_io *io)
988 struct ldb_context *ldb;
989 struct supplementalCredentialsBlob scb;
990 struct supplementalCredentialsBlob _old_scb;
991 struct supplementalCredentialsBlob *old_scb = NULL;
992 /* Packages + (Kerberos-Newer-Keys, Kerberos, WDigest and CLEARTEXT) */
993 uint32_t num_names = 0;
994 const char *names[1+4];
995 uint32_t num_packages = 0;
996 struct supplementalCredentialsPackage packages[1+4];
998 struct supplementalCredentialsPackage *pp = NULL;
999 struct package_PackagesBlob pb;
1002 /* Primary:Kerberos-Newer-Keys */
1003 const char **nkn = NULL;
1004 struct supplementalCredentialsPackage *pkn = NULL;
1005 struct package_PrimaryKerberosBlob pknb;
1006 DATA_BLOB pknb_blob;
1008 /* Primary:Kerberos */
1009 const char **nk = NULL;
1010 struct supplementalCredentialsPackage *pk = NULL;
1011 struct package_PrimaryKerberosBlob pkb;
1014 /* Primary:WDigest */
1015 const char **nd = NULL;
1016 struct supplementalCredentialsPackage *pd = NULL;
1017 struct package_PrimaryWDigestBlob pdb;
1020 /* Primary:CLEARTEXT */
1021 const char **nc = NULL;
1022 struct supplementalCredentialsPackage *pc = NULL;
1023 struct package_PrimaryCLEARTEXTBlob pcb;
1027 enum ndr_err_code ndr_err;
1029 bool do_newer_keys = false;
1030 bool do_cleartext = false;
1032 ZERO_STRUCT(zero16);
1035 ldb = ldb_module_get_ctx(io->ac->module);
1037 if (!io->n.cleartext_utf8) {
1039 * when we don't have a cleartext password
1040 * we can't setup a supplementalCredential value
1045 /* if there's an old supplementaCredentials blob then parse it */
1046 if (io->o.supplemental) {
1047 ndr_err = ndr_pull_struct_blob_all(io->o.supplemental, io->ac,
1049 (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
1050 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1051 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1052 ldb_asprintf_errstring(ldb,
1053 "setup_supplemental_field: "
1054 "failed to pull old supplementalCredentialsBlob: %s",
1056 return LDB_ERR_OPERATIONS_ERROR;
1059 if (_old_scb.sub.signature == SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
1060 old_scb = &_old_scb;
1062 ldb_debug(ldb, LDB_DEBUG_ERROR,
1063 "setup_supplemental_field: "
1064 "supplementalCredentialsBlob signature[0x%04X] expected[0x%04X]",
1065 _old_scb.sub.signature, SUPPLEMENTAL_CREDENTIALS_SIGNATURE);
1068 /* Per MS-SAMR 3.1.1.8.11.6 we create AES keys if our domain functionality level is 2008 or higher */
1069 do_newer_keys = (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008);
1071 if (io->ac->status->domain_data.store_cleartext &&
1072 (io->u.userAccountControl & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) {
1073 do_cleartext = true;
1077 * The ordering is this
1079 * Primary:Kerberos-Newer-Keys (optional)
1082 * Primary:CLEARTEXT (optional)
1084 * And the 'Packages' package is insert before the last
1087 if (do_newer_keys) {
1088 /* Primary:Kerberos-Newer-Keys */
1089 nkn = &names[num_names++];
1090 pkn = &packages[num_packages++];
1093 /* Primary:Kerberos */
1094 nk = &names[num_names++];
1095 pk = &packages[num_packages++];
1097 if (!do_cleartext) {
1099 pp = &packages[num_packages++];
1102 /* Primary:WDigest */
1103 nd = &names[num_names++];
1104 pd = &packages[num_packages++];
1108 pp = &packages[num_packages++];
1110 /* Primary:CLEARTEXT */
1111 nc = &names[num_names++];
1112 pc = &packages[num_packages++];
1117 * setup 'Primary:Kerberos-Newer-Keys' element
1119 *nkn = "Kerberos-Newer-Keys";
1121 ret = setup_primary_kerberos_newer(io, old_scb, &pknb);
1122 if (ret != LDB_SUCCESS) {
1126 ndr_err = ndr_push_struct_blob(&pknb_blob, io->ac,
1128 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1129 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1130 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1131 ldb_asprintf_errstring(ldb,
1132 "setup_supplemental_field: "
1133 "failed to push package_PrimaryKerberosNeverBlob: %s",
1135 return LDB_ERR_OPERATIONS_ERROR;
1137 pknb_hexstr = data_blob_hex_string_upper(io->ac, &pknb_blob);
1139 return ldb_oom(ldb);
1141 pkn->name = "Primary:Kerberos-Newer-Keys";
1143 pkn->data = pknb_hexstr;
1147 * setup 'Primary:Kerberos' element
1151 ret = setup_primary_kerberos(io, old_scb, &pkb);
1152 if (ret != LDB_SUCCESS) {
1156 ndr_err = ndr_push_struct_blob(&pkb_blob, io->ac,
1158 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1159 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1160 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1161 ldb_asprintf_errstring(ldb,
1162 "setup_supplemental_field: "
1163 "failed to push package_PrimaryKerberosBlob: %s",
1165 return LDB_ERR_OPERATIONS_ERROR;
1167 pkb_hexstr = data_blob_hex_string_upper(io->ac, &pkb_blob);
1169 return ldb_oom(ldb);
1171 pk->name = "Primary:Kerberos";
1173 pk->data = pkb_hexstr;
1176 * setup 'Primary:WDigest' element
1180 ret = setup_primary_wdigest(io, old_scb, &pdb);
1181 if (ret != LDB_SUCCESS) {
1185 ndr_err = ndr_push_struct_blob(&pdb_blob, io->ac,
1187 (ndr_push_flags_fn_t)ndr_push_package_PrimaryWDigestBlob);
1188 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1189 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1190 ldb_asprintf_errstring(ldb,
1191 "setup_supplemental_field: "
1192 "failed to push package_PrimaryWDigestBlob: %s",
1194 return LDB_ERR_OPERATIONS_ERROR;
1196 pdb_hexstr = data_blob_hex_string_upper(io->ac, &pdb_blob);
1198 return ldb_oom(ldb);
1200 pd->name = "Primary:WDigest";
1202 pd->data = pdb_hexstr;
1205 * setup 'Primary:CLEARTEXT' element
1210 pcb.cleartext = *io->n.cleartext_utf16;
1212 ndr_err = ndr_push_struct_blob(&pcb_blob, io->ac,
1214 (ndr_push_flags_fn_t)ndr_push_package_PrimaryCLEARTEXTBlob);
1215 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1216 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1217 ldb_asprintf_errstring(ldb,
1218 "setup_supplemental_field: "
1219 "failed to push package_PrimaryCLEARTEXTBlob: %s",
1221 return LDB_ERR_OPERATIONS_ERROR;
1223 pcb_hexstr = data_blob_hex_string_upper(io->ac, &pcb_blob);
1225 return ldb_oom(ldb);
1227 pc->name = "Primary:CLEARTEXT";
1229 pc->data = pcb_hexstr;
1233 * setup 'Packages' element
1236 ndr_err = ndr_push_struct_blob(&pb_blob, io->ac,
1238 (ndr_push_flags_fn_t)ndr_push_package_PackagesBlob);
1239 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1240 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1241 ldb_asprintf_errstring(ldb,
1242 "setup_supplemental_field: "
1243 "failed to push package_PackagesBlob: %s",
1245 return LDB_ERR_OPERATIONS_ERROR;
1247 pb_hexstr = data_blob_hex_string_upper(io->ac, &pb_blob);
1249 return ldb_oom(ldb);
1251 pp->name = "Packages";
1253 pp->data = pb_hexstr;
1256 * setup 'supplementalCredentials' value
1259 scb.sub.num_packages = num_packages;
1260 scb.sub.packages = packages;
1262 ndr_err = ndr_push_struct_blob(&io->g.supplemental, io->ac,
1264 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
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 supplementalCredentialsBlob: %s",
1271 return LDB_ERR_OPERATIONS_ERROR;
1277 static int setup_last_set_field(struct setup_password_fields_io *io)
1280 unix_to_nt_time(&io->g.last_set, time(NULL));
1285 static int setup_given_passwords(struct setup_password_fields_io *io,
1286 struct setup_password_fields_given *g)
1288 struct ldb_context *ldb;
1291 ldb = ldb_module_get_ctx(io->ac->module);
1293 if (g->cleartext_utf8) {
1294 char **cleartext_utf16_str;
1295 struct ldb_val *cleartext_utf16_blob;
1296 size_t converted_pw_len;
1298 cleartext_utf16_blob = talloc(io->ac, struct ldb_val);
1299 if (!cleartext_utf16_blob) {
1300 return ldb_oom(ldb);
1302 if (!convert_string_talloc(io->ac,
1304 g->cleartext_utf8->data,
1305 g->cleartext_utf8->length,
1306 (void *)&cleartext_utf16_str,
1307 &converted_pw_len, false)) {
1308 ldb_asprintf_errstring(ldb,
1309 "setup_password_fields: "
1310 "failed to generate UTF16 password from cleartext UTF8 password");
1311 return LDB_ERR_OPERATIONS_ERROR;
1313 *cleartext_utf16_blob = data_blob_const(cleartext_utf16_str,
1315 g->cleartext_utf16 = cleartext_utf16_blob;
1316 } else if (g->cleartext_utf16) {
1317 char *cleartext_utf8_str;
1318 struct ldb_val *cleartext_utf8_blob;
1319 size_t converted_pw_len;
1321 cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
1322 if (!cleartext_utf8_blob) {
1323 return ldb_oom(ldb);
1325 if (!convert_string_talloc(io->ac,
1326 CH_UTF16MUNGED, CH_UTF8,
1327 g->cleartext_utf16->data,
1328 g->cleartext_utf16->length,
1329 (void *)&cleartext_utf8_str,
1330 &converted_pw_len, false)) {
1331 /* We can't bail out entirely, as these unconvertable passwords are frustratingly valid */
1332 talloc_free(cleartext_utf8_blob);
1334 *cleartext_utf8_blob = data_blob_const(cleartext_utf8_str,
1336 g->cleartext_utf8 = cleartext_utf8_blob;
1340 if (g->cleartext_utf16) {
1341 struct samr_Password *nt_hash;
1343 nt_hash = talloc(io->ac, struct samr_Password);
1345 return ldb_oom(ldb);
1347 g->nt_hash = nt_hash;
1349 /* compute the new nt hash */
1350 mdfour(nt_hash->hash,
1351 g->cleartext_utf16->data,
1352 g->cleartext_utf16->length);
1355 if (g->cleartext_utf8) {
1356 struct samr_Password *lm_hash;
1358 lm_hash = talloc(io->ac, struct samr_Password);
1360 return ldb_oom(ldb);
1363 /* compute the new lm hash */
1364 ok = E_deshash((char *)g->cleartext_utf8->data, lm_hash->hash);
1366 g->lm_hash = lm_hash;
1368 talloc_free(lm_hash);
1375 static int setup_password_fields(struct setup_password_fields_io *io)
1377 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1378 struct loadparm_context *lp_ctx =
1379 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
1380 struct loadparm_context);
1383 /* transform the old password (for password changes) */
1384 ret = setup_given_passwords(io, &io->og);
1385 if (ret != LDB_SUCCESS) {
1389 /* transform the new password */
1390 ret = setup_given_passwords(io, &io->n);
1391 if (ret != LDB_SUCCESS) {
1395 if (io->n.cleartext_utf8) {
1396 ret = setup_kerberos_keys(io);
1397 if (ret != LDB_SUCCESS) {
1402 ret = setup_nt_fields(io);
1403 if (ret != LDB_SUCCESS) {
1407 if (lpcfg_lanman_auth(lp_ctx)) {
1408 ret = setup_lm_fields(io);
1409 if (ret != LDB_SUCCESS) {
1413 io->g.lm_hash = NULL;
1414 io->g.lm_history_len = 0;
1417 ret = setup_supplemental_field(io);
1418 if (ret != LDB_SUCCESS) {
1422 ret = setup_last_set_field(io);
1423 if (ret != LDB_SUCCESS) {
1430 static int check_password_restrictions(struct setup_password_fields_io *io)
1432 struct ldb_context *ldb;
1434 enum samr_ValidationStatus stat;
1436 ldb = ldb_module_get_ctx(io->ac->module);
1438 /* First check the old password is correct, for password changes */
1439 if (!io->ac->pwd_reset) {
1440 bool nt_hash_checked = false;
1442 /* we need the old nt or lm hash given by the client */
1443 if (!io->og.nt_hash && !io->og.lm_hash) {
1444 ldb_asprintf_errstring(ldb,
1445 "check_password_restrictions: "
1446 "You need to provide the old password in order "
1448 return LDB_ERR_UNWILLING_TO_PERFORM;
1451 /* The password modify through the NT hash is encouraged and
1452 has no problems at all */
1453 if (io->og.nt_hash) {
1454 if (!io->o.nt_hash) {
1455 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1456 ldb_asprintf_errstring(ldb,
1457 "%08X: %s - check_password_restrictions: "
1458 "There's no old nt_hash, which is needed "
1459 "in order to change your password!",
1460 W_ERROR_V(WERR_INVALID_PASSWORD),
1465 if (memcmp(io->og.nt_hash->hash, io->o.nt_hash->hash, 16) != 0) {
1466 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1467 ldb_asprintf_errstring(ldb,
1468 "%08X: %s - check_password_restrictions: "
1469 "The old password specified doesn't match!",
1470 W_ERROR_V(WERR_INVALID_PASSWORD),
1475 nt_hash_checked = true;
1478 /* But it is also possible to change a password by the LM hash
1479 * alone for compatibility reasons. This check is optional if
1480 * the NT hash was already checked - otherwise it's mandatory.
1481 * (as the SAMR operations request it). */
1482 if (io->og.lm_hash) {
1483 if (!io->o.lm_hash && !nt_hash_checked) {
1484 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1485 ldb_asprintf_errstring(ldb,
1486 "%08X: %s - check_password_restrictions: "
1487 "There's no old lm_hash, which is needed "
1488 "in order to change your password!",
1489 W_ERROR_V(WERR_INVALID_PASSWORD),
1494 if (io->o.lm_hash &&
1495 memcmp(io->og.lm_hash->hash, io->o.lm_hash->hash, 16) != 0) {
1496 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1497 ldb_asprintf_errstring(ldb,
1498 "%08X: %s - check_password_restrictions: "
1499 "The old password specified doesn't match!",
1500 W_ERROR_V(WERR_INVALID_PASSWORD),
1507 if (io->u.restrictions == 0) {
1508 /* FIXME: Is this right? */
1513 * Fundamental password checks done by the call
1514 * "samdb_check_password".
1515 * It is also in use by "dcesrv_samr_ValidatePassword".
1517 if (io->n.cleartext_utf8 != NULL) {
1518 stat = samdb_check_password(io->n.cleartext_utf8,
1519 io->ac->status->domain_data.pwdProperties,
1520 io->ac->status->domain_data.minPwdLength);
1522 case SAMR_VALIDATION_STATUS_SUCCESS:
1523 /* perfect -> proceed! */
1526 case SAMR_VALIDATION_STATUS_PWD_TOO_SHORT:
1527 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1528 ldb_asprintf_errstring(ldb,
1529 "%08X: %s - check_password_restrictions: "
1530 "the password is too short. It should be equal or longer than %u characters!",
1531 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
1533 io->ac->status->domain_data.minPwdLength);
1534 io->ac->status->reject_reason = SAM_PWD_CHANGE_PASSWORD_TOO_SHORT;
1537 case SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH:
1538 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1539 ldb_asprintf_errstring(ldb,
1540 "%08X: %s - check_password_restrictions: "
1541 "the password does not meet the complexity criterias!",
1542 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
1544 io->ac->status->reject_reason = SAM_PWD_CHANGE_NOT_COMPLEX;
1548 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1549 ldb_asprintf_errstring(ldb,
1550 "%08X: %s - check_password_restrictions: "
1551 "the password doesn't fit by a certain reason!",
1552 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
1558 if (io->ac->pwd_reset) {
1562 if (io->n.nt_hash) {
1565 /* checks the NT hash password history */
1566 for (i = 0; i < io->o.nt_history_len; i++) {
1567 ret = memcmp(io->n.nt_hash, io->o.nt_history[i].hash, 16);
1569 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1570 ldb_asprintf_errstring(ldb,
1571 "%08X: %s - check_password_restrictions: "
1572 "the password was already used (in history)!",
1573 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
1575 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
1581 if (io->n.lm_hash) {
1584 /* checks the LM hash password history */
1585 for (i = 0; i < io->o.lm_history_len; i++) {
1586 ret = memcmp(io->n.nt_hash, io->o.lm_history[i].hash, 16);
1588 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1589 ldb_asprintf_errstring(ldb,
1590 "%08X: %s - check_password_restrictions: "
1591 "the password was already used (in history)!",
1592 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
1594 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
1600 /* are all password changes disallowed? */
1601 if (io->ac->status->domain_data.pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1602 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1603 ldb_asprintf_errstring(ldb,
1604 "%08X: %s - check_password_restrictions: "
1605 "password changes disabled!",
1606 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
1611 /* can this user change the password? */
1612 if (io->u.userAccountControl & UF_PASSWD_CANT_CHANGE) {
1613 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1614 ldb_asprintf_errstring(ldb,
1615 "%08X: %s - check_password_restrictions: "
1616 "password can't be changed on this account!",
1617 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
1622 /* Password minimum age: yes, this is a minus. The ages are in negative 100nsec units! */
1623 if (io->u.pwdLastSet - io->ac->status->domain_data.minPwdAge > io->g.last_set) {
1624 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1625 ldb_asprintf_errstring(ldb,
1626 "%08X: %s - check_password_restrictions: "
1627 "password is too young to change!",
1628 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
1636 static int setup_io(struct ph_context *ac,
1637 const struct ldb_message *orig_msg,
1638 const struct ldb_message *searched_msg,
1639 struct setup_password_fields_io *io)
1641 const struct ldb_val *quoted_utf16, *old_quoted_utf16, *lm_hash, *old_lm_hash;
1642 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1643 struct loadparm_context *lp_ctx =
1644 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
1645 struct loadparm_context);
1650 /* Some operations below require kerberos contexts */
1652 if (smb_krb5_init_context(ac,
1653 ldb_get_event_context(ldb),
1654 (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"),
1655 &io->smb_krb5_context) != 0) {
1656 return ldb_operr(ldb);
1661 io->u.userAccountControl = ldb_msg_find_attr_as_uint(searched_msg,
1662 "userAccountControl", 0);
1663 io->u.pwdLastSet = samdb_result_nttime(searched_msg, "pwdLastSet", 0);
1664 io->u.sAMAccountName = ldb_msg_find_attr_as_string(searched_msg,
1665 "sAMAccountName", NULL);
1666 io->u.user_principal_name = ldb_msg_find_attr_as_string(searched_msg,
1667 "userPrincipalName", NULL);
1668 io->u.is_computer = ldb_msg_check_string_attribute(searched_msg, "objectClass", "computer");
1670 if (io->u.sAMAccountName == NULL) {
1671 ldb_asprintf_errstring(ldb,
1672 "setup_io: sAMAccountName attribute is missing on %s for attempted password set/change",
1673 ldb_dn_get_linearized(searched_msg->dn));
1675 return LDB_ERR_CONSTRAINT_VIOLATION;
1678 /* Only non-trust accounts have restrictions (possibly this test is the
1679 * wrong way around, but we like to be restrictive if possible */
1680 io->u.restrictions = !(io->u.userAccountControl
1681 & (UF_INTERDOMAIN_TRUST_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT
1682 | UF_SERVER_TRUST_ACCOUNT));
1684 if ((io->u.userAccountControl & UF_PASSWD_NOTREQD) != 0) {
1685 /* see [MS-ADTS] 2.2.15 */
1686 io->u.restrictions = 0;
1689 ret = samdb_msg_find_old_and_new_ldb_val(orig_msg, "userPassword",
1691 &io->n.cleartext_utf8,
1692 &io->og.cleartext_utf8);
1693 if (ret != LDB_SUCCESS) {
1694 ldb_asprintf_errstring(ldb,
1696 "it's only allowed to set the old password once!");
1700 ret = samdb_msg_find_old_and_new_ldb_val(orig_msg, "clearTextPassword",
1702 &io->n.cleartext_utf16,
1703 &io->og.cleartext_utf16);
1704 if (ret != LDB_SUCCESS) {
1705 ldb_asprintf_errstring(ldb,
1707 "it's only allowed to set the old password once!");
1711 /* this rather strange looking piece of code is there to
1712 handle a ldap client setting a password remotely using the
1713 unicodePwd ldap field. The syntax is that the password is
1714 in UTF-16LE, with a " at either end. Unfortunately the
1715 unicodePwd field is also used to store the nt hashes
1716 internally in Samba, and is used in the nt hash format on
1717 the wire in DRS replication, so we have a single name for
1718 two distinct values. The code below leaves us with a small
1719 chance (less than 1 in 2^32) of a mixup, if someone manages
1720 to create a MD4 hash which starts and ends in 0x22 0x00, as
1721 that would then be treated as a UTF16 password rather than
1724 ret = samdb_msg_find_old_and_new_ldb_val(orig_msg, "unicodePwd",
1728 if (ret != LDB_SUCCESS) {
1729 ldb_asprintf_errstring(ldb,
1731 "it's only allowed to set the old password once!");
1735 /* Checks and converts the actual "unicodePwd" attribute */
1737 quoted_utf16->length >= 4 &&
1738 quoted_utf16->data[0] == '"' &&
1739 quoted_utf16->data[1] == 0 &&
1740 quoted_utf16->data[quoted_utf16->length-2] == '"' &&
1741 quoted_utf16->data[quoted_utf16->length-1] == 0) {
1742 struct ldb_val *quoted_utf16_2;
1744 if (io->n.cleartext_utf16) {
1745 /* refuse the change if someone wants to change with
1746 with both UTF16 possibilities at the same time... */
1747 ldb_asprintf_errstring(ldb,
1749 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
1750 return LDB_ERR_UNWILLING_TO_PERFORM;
1754 * adapt the quoted UTF16 string to be a real
1757 quoted_utf16_2 = talloc(io->ac, struct ldb_val);
1758 if (quoted_utf16_2 == NULL) {
1759 return ldb_oom(ldb);
1762 quoted_utf16_2->data = quoted_utf16->data + 2;
1763 quoted_utf16_2->length = quoted_utf16->length-4;
1764 io->n.cleartext_utf16 = quoted_utf16_2;
1765 io->n.nt_hash = NULL;
1767 } else if (quoted_utf16) {
1768 /* We have only the hash available -> so no plaintext here */
1769 if (!ac->hash_values) {
1770 /* refuse the change if someone wants to change
1771 the hash without control specified... */
1772 ldb_asprintf_errstring(ldb,
1774 "it's not allowed to set the NT hash password directly'");
1775 /* this looks odd but this is what Windows does:
1776 returns "UNWILLING_TO_PERFORM" on wrong
1777 password sets and "CONSTRAINT_VIOLATION" on
1778 wrong password changes. */
1779 if (old_quoted_utf16 == NULL) {
1780 return LDB_ERR_UNWILLING_TO_PERFORM;
1783 return LDB_ERR_CONSTRAINT_VIOLATION;
1786 io->n.nt_hash = talloc(io->ac, struct samr_Password);
1787 memcpy(io->n.nt_hash->hash, quoted_utf16->data,
1788 MIN(quoted_utf16->length, sizeof(io->n.nt_hash->hash)));
1791 /* Checks and converts the previous "unicodePwd" attribute */
1792 if (old_quoted_utf16 &&
1793 old_quoted_utf16->length >= 4 &&
1794 old_quoted_utf16->data[0] == '"' &&
1795 old_quoted_utf16->data[1] == 0 &&
1796 old_quoted_utf16->data[old_quoted_utf16->length-2] == '"' &&
1797 old_quoted_utf16->data[old_quoted_utf16->length-1] == 0) {
1798 struct ldb_val *old_quoted_utf16_2;
1800 if (io->og.cleartext_utf16) {
1801 /* refuse the change if someone wants to change with
1802 both UTF16 possibilities at the same time... */
1803 ldb_asprintf_errstring(ldb,
1805 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
1806 return LDB_ERR_UNWILLING_TO_PERFORM;
1810 * adapt the quoted UTF16 string to be a real
1813 old_quoted_utf16_2 = talloc(io->ac, struct ldb_val);
1814 if (old_quoted_utf16_2 == NULL) {
1815 return ldb_oom(ldb);
1818 old_quoted_utf16_2->data = old_quoted_utf16->data + 2;
1819 old_quoted_utf16_2->length = old_quoted_utf16->length-4;
1821 io->og.cleartext_utf16 = old_quoted_utf16_2;
1822 io->og.nt_hash = NULL;
1823 } else if (old_quoted_utf16) {
1824 /* We have only the hash available -> so no plaintext here */
1825 if (!ac->hash_values) {
1826 /* refuse the change if someone wants to change
1827 the hash without control specified... */
1828 ldb_asprintf_errstring(ldb,
1830 "it's not allowed to set the NT hash password directly'");
1831 return LDB_ERR_UNWILLING_TO_PERFORM;
1834 io->og.nt_hash = talloc(io->ac, struct samr_Password);
1835 memcpy(io->og.nt_hash->hash, old_quoted_utf16->data,
1836 MIN(old_quoted_utf16->length, sizeof(io->og.nt_hash->hash)));
1839 /* Handles the "dBCSPwd" attribute (LM hash) */
1840 io->n.lm_hash = NULL; io->og.lm_hash = NULL;
1841 ret = samdb_msg_find_old_and_new_ldb_val(orig_msg, "dBCSPwd",
1843 &lm_hash, &old_lm_hash);
1844 if (ret != LDB_SUCCESS) {
1845 ldb_asprintf_errstring(ldb,
1847 "it's only allowed to set the old password once!");
1851 if (((lm_hash != NULL) || (old_lm_hash != NULL)) && (!ac->hash_values)) {
1852 /* refuse the change if someone wants to change the hash
1853 without control specified... */
1854 ldb_asprintf_errstring(ldb,
1856 "it's not allowed to set the LM hash password directly'");
1857 return LDB_ERR_UNWILLING_TO_PERFORM;
1860 if (lpcfg_lanman_auth(lp_ctx) && (lm_hash != NULL)) {
1861 io->n.lm_hash = talloc(io->ac, struct samr_Password);
1862 memcpy(io->n.lm_hash->hash, lm_hash->data, MIN(lm_hash->length,
1863 sizeof(io->n.lm_hash->hash)));
1865 if (lpcfg_lanman_auth(lp_ctx) && (old_lm_hash != NULL)) {
1866 io->og.lm_hash = talloc(io->ac, struct samr_Password);
1867 memcpy(io->og.lm_hash->hash, old_lm_hash->data, MIN(old_lm_hash->length,
1868 sizeof(io->og.lm_hash->hash)));
1872 * Handles the password change control if it's specified. It has the
1873 * precedance and overrides already specified old password values of
1874 * change requests (but that shouldn't happen since the control is
1875 * fully internal and only used in conjunction with replace requests!).
1877 if (ac->change != NULL) {
1878 io->og.nt_hash = NULL;
1879 if (ac->change->old_nt_pwd_hash != NULL) {
1880 io->og.nt_hash = talloc_memdup(io->ac,
1881 ac->change->old_nt_pwd_hash,
1882 sizeof(struct samr_Password));
1884 io->og.lm_hash = NULL;
1885 if (lpcfg_lanman_auth(lp_ctx) && (ac->change->old_lm_pwd_hash != NULL)) {
1886 io->og.lm_hash = talloc_memdup(io->ac,
1887 ac->change->old_lm_pwd_hash,
1888 sizeof(struct samr_Password));
1892 /* refuse the change if someone wants to change the clear-
1893 text and supply his own hashes at the same time... */
1894 if ((io->n.cleartext_utf8 || io->n.cleartext_utf16)
1895 && (io->n.nt_hash || io->n.lm_hash)) {
1896 ldb_asprintf_errstring(ldb,
1898 "it's only allowed to set the password in form of cleartext attributes or as hashes");
1899 return LDB_ERR_UNWILLING_TO_PERFORM;
1902 /* refuse the change if someone wants to change the password
1903 using both plaintext methods (UTF8 and UTF16) at the same time... */
1904 if (io->n.cleartext_utf8 && io->n.cleartext_utf16) {
1905 ldb_asprintf_errstring(ldb,
1907 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
1908 return LDB_ERR_UNWILLING_TO_PERFORM;
1911 /* refuse the change if someone tries to set/change the password by
1912 * the lanman hash alone and we've deactivated that mechanism. This
1913 * would end in an account without any password! */
1914 if ((!io->n.cleartext_utf8) && (!io->n.cleartext_utf16)
1915 && (!io->n.nt_hash) && (!io->n.lm_hash)) {
1916 ldb_asprintf_errstring(ldb,
1918 "It' not possible to delete the password (changes using the LAN Manager hash alone could be deactivated)!");
1919 /* on "userPassword" and "clearTextPassword" we've to return
1920 * something different, since these are virtual attributes */
1921 if ((ldb_msg_find_element(orig_msg, "userPassword") != NULL) ||
1922 (ldb_msg_find_element(orig_msg, "clearTextPassword") != NULL)) {
1923 return LDB_ERR_CONSTRAINT_VIOLATION;
1925 return LDB_ERR_UNWILLING_TO_PERFORM;
1928 /* refuse the change if someone wants to compare against a plaintext
1929 or hash at the same time for a "password modify" operation... */
1930 if ((io->og.cleartext_utf8 || io->og.cleartext_utf16)
1931 && (io->og.nt_hash || io->og.lm_hash)) {
1932 ldb_asprintf_errstring(ldb,
1934 "it's only allowed to provide the old password in form of cleartext attributes or as hashes");
1935 return LDB_ERR_UNWILLING_TO_PERFORM;
1938 /* refuse the change if someone wants to compare against both
1939 * plaintexts at the same time for a "password modify" operation... */
1940 if (io->og.cleartext_utf8 && io->og.cleartext_utf16) {
1941 ldb_asprintf_errstring(ldb,
1943 "it's only allowed to provide the old cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
1944 return LDB_ERR_UNWILLING_TO_PERFORM;
1947 /* Decides if we have a password modify or password reset operation */
1948 if (ac->req->operation == LDB_ADD) {
1949 /* On "add" we have only "password reset" */
1950 ac->pwd_reset = true;
1951 } else if (ac->req->operation == LDB_MODIFY) {
1952 if (io->og.cleartext_utf8 || io->og.cleartext_utf16
1953 || io->og.nt_hash || io->og.lm_hash) {
1954 /* If we have an old password specified then for sure it
1955 * is a user "password change" */
1956 ac->pwd_reset = false;
1958 /* Otherwise we have also here a "password reset" */
1959 ac->pwd_reset = true;
1962 /* this shouldn't happen */
1963 return ldb_operr(ldb);
1969 static struct ph_context *ph_init_context(struct ldb_module *module,
1970 struct ldb_request *req)
1972 struct ldb_context *ldb;
1973 struct ph_context *ac;
1975 ldb = ldb_module_get_ctx(module);
1977 ac = talloc_zero(req, struct ph_context);
1979 ldb_set_errstring(ldb, "Out of Memory");
1983 ac->module = module;
1989 static void ph_apply_controls(struct ph_context *ac)
1991 struct ldb_control *ctrl;
1993 ac->change_status = false;
1994 ctrl = ldb_request_get_control(ac->req,
1995 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID);
1997 ac->change_status = true;
1999 /* Mark the "change status" control as uncritical (done) */
2000 ctrl->critical = false;
2003 ac->hash_values = false;
2004 ctrl = ldb_request_get_control(ac->req,
2005 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID);
2007 ac->hash_values = true;
2009 /* Mark the "hash values" control as uncritical (done) */
2010 ctrl->critical = false;
2013 ctrl = ldb_request_get_control(ac->req,
2014 DSDB_CONTROL_PASSWORD_CHANGE_OID);
2016 ac->change = (struct dsdb_control_password_change *) ctrl->data;
2018 /* Mark the "change" control as uncritical (done) */
2019 ctrl->critical = false;
2023 static int ph_op_callback(struct ldb_request *req, struct ldb_reply *ares)
2025 struct ph_context *ac;
2027 ac = talloc_get_type(req->context, struct ph_context);
2030 return ldb_module_done(ac->req, NULL, NULL,
2031 LDB_ERR_OPERATIONS_ERROR);
2034 if (ares->type == LDB_REPLY_REFERRAL) {
2035 return ldb_module_send_referral(ac->req, ares->referral);
2038 if ((ares->error != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
2039 /* On success and trivial errors a status control is being
2040 * added (used for example by the "samdb_set_password" call) */
2041 ldb_reply_add_control(ares,
2042 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2047 if (ares->error != LDB_SUCCESS) {
2048 return ldb_module_done(ac->req, ares->controls,
2049 ares->response, ares->error);
2052 if (ares->type != LDB_REPLY_DONE) {
2054 return ldb_module_done(ac->req, NULL, NULL,
2055 LDB_ERR_OPERATIONS_ERROR);
2058 return ldb_module_done(ac->req, ares->controls,
2059 ares->response, ares->error);
2062 static int password_hash_add_do_add(struct ph_context *ac);
2063 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares);
2064 static int password_hash_mod_search_self(struct ph_context *ac);
2065 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares);
2066 static int password_hash_mod_do_mod(struct ph_context *ac);
2068 static int get_domain_data_callback(struct ldb_request *req,
2069 struct ldb_reply *ares)
2071 struct ldb_context *ldb;
2072 struct ph_context *ac;
2073 struct loadparm_context *lp_ctx;
2076 ac = talloc_get_type(req->context, struct ph_context);
2077 ldb = ldb_module_get_ctx(ac->module);
2080 ret = LDB_ERR_OPERATIONS_ERROR;
2083 if (ares->error != LDB_SUCCESS) {
2084 return ldb_module_done(ac->req, ares->controls,
2085 ares->response, ares->error);
2088 switch (ares->type) {
2089 case LDB_REPLY_ENTRY:
2090 if (ac->status != NULL) {
2093 ldb_set_errstring(ldb, "Too many results");
2094 ret = LDB_ERR_OPERATIONS_ERROR;
2098 /* Setup the "status" structure (used as control later) */
2099 ac->status = talloc_zero(ac->req,
2100 struct dsdb_control_password_change_status);
2101 if (ac->status == NULL) {
2105 ret = LDB_ERR_OPERATIONS_ERROR;
2109 /* Setup the "domain data" structure */
2110 ac->status->domain_data.pwdProperties =
2111 ldb_msg_find_attr_as_uint(ares->message, "pwdProperties", -1);
2112 ac->status->domain_data.pwdHistoryLength =
2113 ldb_msg_find_attr_as_uint(ares->message, "pwdHistoryLength", -1);
2114 ac->status->domain_data.maxPwdAge =
2115 ldb_msg_find_attr_as_int64(ares->message, "maxPwdAge", -1);
2116 ac->status->domain_data.minPwdAge =
2117 ldb_msg_find_attr_as_int64(ares->message, "minPwdAge", -1);
2118 ac->status->domain_data.minPwdLength =
2119 ldb_msg_find_attr_as_uint(ares->message, "minPwdLength", -1);
2120 ac->status->domain_data.store_cleartext =
2121 ac->status->domain_data.pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
2125 /* For a domain DN, this puts things in dotted notation */
2126 /* For builtin domains, this will give details for the host,
2127 * but that doesn't really matter, as it's just used for salt
2128 * and kerberos principals, which don't exist here */
2130 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2131 struct loadparm_context);
2133 ac->status->domain_data.dns_domain = lpcfg_dnsdomain(lp_ctx);
2134 ac->status->domain_data.realm = lpcfg_realm(lp_ctx);
2135 ac->status->domain_data.netbios_domain = lpcfg_sam_name(lp_ctx);
2137 ac->status->reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2142 case LDB_REPLY_REFERRAL:
2148 case LDB_REPLY_DONE:
2150 /* call the next step */
2151 switch (ac->req->operation) {
2153 ret = password_hash_add_do_add(ac);
2157 ret = password_hash_mod_do_mod(ac);
2161 ret = LDB_ERR_OPERATIONS_ERROR;
2168 if (ret != LDB_SUCCESS) {
2169 struct ldb_reply *new_ares;
2171 new_ares = talloc_zero(ac->req, struct ldb_reply);
2172 if (new_ares == NULL) {
2174 return ldb_module_done(ac->req, NULL, NULL,
2175 LDB_ERR_OPERATIONS_ERROR);
2178 new_ares->error = ret;
2179 if ((ret != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
2180 /* On success and trivial errors a status control is being
2181 * added (used for example by the "samdb_set_password" call) */
2182 ldb_reply_add_control(new_ares,
2183 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2188 return ldb_module_done(ac->req, new_ares->controls,
2189 new_ares->response, new_ares->error);
2195 static int build_domain_data_request(struct ph_context *ac)
2197 /* attrs[] is returned from this function in
2198 ac->dom_req->op.search.attrs, so it must be static, as
2199 otherwise the compiler can put it on the stack */
2200 struct ldb_context *ldb;
2201 static const char * const attrs[] = { "pwdProperties",
2209 ldb = ldb_module_get_ctx(ac->module);
2211 ret = ldb_build_search_req(&ac->dom_req, ldb, ac,
2212 ldb_get_default_basedn(ldb),
2216 ac, get_domain_data_callback,
2218 LDB_REQ_SET_LOCATION(ac->dom_req);
2222 static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
2224 struct ldb_context *ldb;
2225 struct ph_context *ac;
2226 struct ldb_message_element *userPasswordAttr, *clearTextPasswordAttr,
2229 struct ldb_control *bypass = NULL;
2231 ldb = ldb_module_get_ctx(module);
2233 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add\n");
2235 if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
2236 return ldb_next_request(module, req);
2239 /* If the caller is manipulating the local passwords directly, let them pass */
2240 if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
2241 req->op.add.message->dn) == 0) {
2242 return ldb_next_request(module, req);
2245 bypass = ldb_request_get_control(req,
2246 DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID);
2247 if (bypass != NULL) {
2248 /* Mark the "bypass" control as uncritical (done) */
2249 bypass->critical = false;
2250 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add (bypassing)\n");
2251 return ldb_next_request(module, req);
2254 /* nobody must touch password histories and 'supplementalCredentials' */
2255 if (ldb_msg_find_element(req->op.add.message, "ntPwdHistory")) {
2256 return LDB_ERR_UNWILLING_TO_PERFORM;
2258 if (ldb_msg_find_element(req->op.add.message, "lmPwdHistory")) {
2259 return LDB_ERR_UNWILLING_TO_PERFORM;
2261 if (ldb_msg_find_element(req->op.add.message, "supplementalCredentials")) {
2262 return LDB_ERR_UNWILLING_TO_PERFORM;
2265 /* If no part of this touches the 'userPassword' OR 'clearTextPassword'
2266 * OR 'unicodePwd' OR 'dBCSPwd' we don't need to make any changes. */
2268 userPasswordAttr = ldb_msg_find_element(req->op.add.message, "userPassword");
2269 clearTextPasswordAttr = ldb_msg_find_element(req->op.add.message, "clearTextPassword");
2270 ntAttr = ldb_msg_find_element(req->op.add.message, "unicodePwd");
2271 lmAttr = ldb_msg_find_element(req->op.add.message, "dBCSPwd");
2273 if ((!userPasswordAttr) && (!clearTextPasswordAttr) && (!ntAttr) && (!lmAttr)) {
2274 return ldb_next_request(module, req);
2277 /* Make sure we are performing the password set action on a (for us)
2278 * valid object. Those are instances of either "user" and/or
2279 * "inetOrgPerson". Otherwise continue with the submodules. */
2280 if ((!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "user"))
2281 && (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "inetOrgPerson"))) {
2283 if (ldb_msg_find_element(req->op.add.message, "clearTextPassword") != NULL) {
2284 ldb_set_errstring(ldb,
2285 "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
2286 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2289 return ldb_next_request(module, req);
2292 ac = ph_init_context(module, req);
2294 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
2295 return ldb_operr(ldb);
2297 ph_apply_controls(ac);
2299 /* get user domain data */
2300 ret = build_domain_data_request(ac);
2301 if (ret != LDB_SUCCESS) {
2305 return ldb_next_request(module, ac->dom_req);
2308 static int password_hash_add_do_add(struct ph_context *ac)
2310 struct ldb_context *ldb;
2311 struct ldb_request *down_req;
2312 struct ldb_message *msg;
2313 struct setup_password_fields_io io;
2316 /* Prepare the internal data structure containing the passwords */
2317 ret = setup_io(ac, ac->req->op.add.message, ac->req->op.add.message, &io);
2318 if (ret != LDB_SUCCESS) {
2322 ldb = ldb_module_get_ctx(ac->module);
2324 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
2326 return ldb_operr(ldb);
2329 /* remove attributes that we just read into 'io' */
2330 ldb_msg_remove_attr(msg, "userPassword");
2331 ldb_msg_remove_attr(msg, "clearTextPassword");
2332 ldb_msg_remove_attr(msg, "unicodePwd");
2333 ldb_msg_remove_attr(msg, "dBCSPwd");
2334 ldb_msg_remove_attr(msg, "pwdLastSet");
2336 ret = setup_password_fields(&io);
2337 if (ret != LDB_SUCCESS) {
2341 ret = check_password_restrictions(&io);
2342 if (ret != LDB_SUCCESS) {
2347 ret = samdb_msg_add_hash(ldb, ac, msg,
2348 "unicodePwd", io.g.nt_hash);
2349 if (ret != LDB_SUCCESS) {
2354 ret = samdb_msg_add_hash(ldb, ac, msg,
2355 "dBCSPwd", io.g.lm_hash);
2356 if (ret != LDB_SUCCESS) {
2360 if (io.g.nt_history_len > 0) {
2361 ret = samdb_msg_add_hashes(ldb, ac, msg,
2364 io.g.nt_history_len);
2365 if (ret != LDB_SUCCESS) {
2369 if (io.g.lm_history_len > 0) {
2370 ret = samdb_msg_add_hashes(ldb, ac, msg,
2373 io.g.lm_history_len);
2374 if (ret != LDB_SUCCESS) {
2378 if (io.g.supplemental.length > 0) {
2379 ret = ldb_msg_add_value(msg, "supplementalCredentials",
2380 &io.g.supplemental, NULL);
2381 if (ret != LDB_SUCCESS) {
2385 ret = samdb_msg_add_uint64(ldb, ac, msg,
2388 if (ret != LDB_SUCCESS) {
2392 ret = ldb_build_add_req(&down_req, ldb, ac,
2397 LDB_REQ_SET_LOCATION(down_req);
2398 if (ret != LDB_SUCCESS) {
2402 return ldb_next_request(ac->module, down_req);
2405 static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
2407 struct ldb_context *ldb;
2408 struct ph_context *ac;
2409 const char *passwordAttrs[] = { "userPassword", "clearTextPassword",
2410 "unicodePwd", "dBCSPwd", NULL }, **l;
2411 unsigned int attr_cnt, del_attr_cnt, add_attr_cnt, rep_attr_cnt;
2412 struct ldb_message_element *passwordAttr;
2413 struct ldb_message *msg;
2414 struct ldb_request *down_req;
2416 struct ldb_control *bypass = NULL;
2418 ldb = ldb_module_get_ctx(module);
2420 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
2422 if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
2423 return ldb_next_request(module, req);
2426 /* If the caller is manipulating the local passwords directly, let them pass */
2427 if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
2428 req->op.mod.message->dn) == 0) {
2429 return ldb_next_request(module, req);
2432 bypass = ldb_request_get_control(req,
2433 DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID);
2434 if (bypass != NULL) {
2435 /* Mark the "bypass" control as uncritical (done) */
2436 bypass->critical = false;
2437 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify (bypassing)\n");
2438 return ldb_next_request(module, req);
2441 /* nobody must touch password histories and 'supplementalCredentials' */
2442 if (ldb_msg_find_element(req->op.mod.message, "ntPwdHistory")) {
2443 return LDB_ERR_UNWILLING_TO_PERFORM;
2445 if (ldb_msg_find_element(req->op.mod.message, "lmPwdHistory")) {
2446 return LDB_ERR_UNWILLING_TO_PERFORM;
2448 if (ldb_msg_find_element(req->op.mod.message, "supplementalCredentials")) {
2449 return LDB_ERR_UNWILLING_TO_PERFORM;
2452 /* If no part of this touches the 'userPassword' OR 'clearTextPassword'
2453 * OR 'unicodePwd' OR 'dBCSPwd' we don't need to make any changes.
2454 * For password changes/set there should be a 'delete' or a 'modify'
2455 * on these attributes. */
2457 for (l = passwordAttrs; *l != NULL; l++) {
2458 if (ldb_msg_find_element(req->op.mod.message, *l) != NULL) {
2462 if (attr_cnt == 0) {
2463 return ldb_next_request(module, req);
2466 ac = ph_init_context(module, req);
2468 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
2469 return ldb_operr(ldb);
2471 ph_apply_controls(ac);
2473 /* use a new message structure so that we can modify it */
2474 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2476 return ldb_oom(ldb);
2479 /* - check for single-valued password attributes
2480 * (if not return "CONSTRAINT_VIOLATION")
2481 * - check that for a password change operation one add and one delete
2483 * (if not return "CONSTRAINT_VIOLATION" or "UNWILLING_TO_PERFORM")
2484 * - check that a password change and a password set operation cannot
2486 * (if not return "UNWILLING_TO_PERFORM")
2487 * - remove all password attributes modifications from the first change
2488 * operation (anything without the passwords) - we will make the real
2489 * modification later */
2493 for (l = passwordAttrs; *l != NULL; l++) {
2494 while ((passwordAttr = ldb_msg_find_element(msg, *l)) != NULL) {
2495 if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_DELETE) {
2498 if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_ADD) {
2501 if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_REPLACE) {
2504 if ((passwordAttr->num_values != 1) &&
2505 (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_ADD)) {
2507 ldb_asprintf_errstring(ldb,
2508 "'%s' attribute must have exactly one value on add operations!",
2510 return LDB_ERR_CONSTRAINT_VIOLATION;
2512 if ((passwordAttr->num_values > 1) &&
2513 (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_DELETE)) {
2515 ldb_asprintf_errstring(ldb,
2516 "'%s' attribute must have zero or one value(s) on delete operations!",
2518 return LDB_ERR_CONSTRAINT_VIOLATION;
2520 ldb_msg_remove_element(msg, passwordAttr);
2523 if ((del_attr_cnt == 0) && (add_attr_cnt > 0)) {
2525 ldb_set_errstring(ldb,
2526 "Only the add action for a password change specified!");
2527 return LDB_ERR_UNWILLING_TO_PERFORM;
2529 if ((del_attr_cnt > 1) || (add_attr_cnt > 1)) {
2531 ldb_set_errstring(ldb,
2532 "Only one delete and one add action for a password change allowed!");
2533 return LDB_ERR_UNWILLING_TO_PERFORM;
2535 if ((rep_attr_cnt > 0) && ((del_attr_cnt > 0) || (add_attr_cnt > 0))) {
2537 ldb_set_errstring(ldb,
2538 "Either a password change or a password set operation is allowed!");
2539 return LDB_ERR_UNWILLING_TO_PERFORM;
2542 /* if there was nothing else to be modified skip to next step */
2543 if (msg->num_elements == 0) {
2544 return password_hash_mod_search_self(ac);
2547 ret = ldb_build_mod_req(&down_req, ldb, ac,
2550 ac, ph_modify_callback,
2552 LDB_REQ_SET_LOCATION(down_req);
2553 if (ret != LDB_SUCCESS) {
2557 return ldb_next_request(module, down_req);
2560 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
2562 struct ph_context *ac;
2564 ac = talloc_get_type(req->context, struct ph_context);
2567 return ldb_module_done(ac->req, NULL, NULL,
2568 LDB_ERR_OPERATIONS_ERROR);
2571 if (ares->type == LDB_REPLY_REFERRAL) {
2572 return ldb_module_send_referral(ac->req, ares->referral);
2575 if (ares->error != LDB_SUCCESS) {
2576 return ldb_module_done(ac->req, ares->controls,
2577 ares->response, ares->error);
2580 if (ares->type != LDB_REPLY_DONE) {
2582 return ldb_module_done(ac->req, NULL, NULL,
2583 LDB_ERR_OPERATIONS_ERROR);
2588 return password_hash_mod_search_self(ac);
2591 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
2593 struct ldb_context *ldb;
2594 struct ph_context *ac;
2597 ac = talloc_get_type(req->context, struct ph_context);
2598 ldb = ldb_module_get_ctx(ac->module);
2601 ret = LDB_ERR_OPERATIONS_ERROR;
2604 if (ares->error != LDB_SUCCESS) {
2605 return ldb_module_done(ac->req, ares->controls,
2606 ares->response, ares->error);
2609 /* we are interested only in the single reply (base search) */
2610 switch (ares->type) {
2611 case LDB_REPLY_ENTRY:
2612 /* Make sure we are performing the password change action on a
2613 * (for us) valid object. Those are instances of either "user"
2614 * and/or "inetOrgPerson". Otherwise continue with the
2616 if ((!ldb_msg_check_string_attribute(ares->message, "objectClass", "user"))
2617 && (!ldb_msg_check_string_attribute(ares->message, "objectClass", "inetOrgPerson"))) {
2620 if (ldb_msg_find_element(ac->req->op.mod.message, "clearTextPassword") != NULL) {
2621 ldb_set_errstring(ldb,
2622 "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
2623 ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
2627 ret = ldb_next_request(ac->module, ac->req);
2631 if (ac->search_res != NULL) {
2634 ldb_set_errstring(ldb, "Too many results");
2635 ret = LDB_ERR_OPERATIONS_ERROR;
2639 ac->search_res = talloc_steal(ac, ares);
2643 case LDB_REPLY_REFERRAL:
2644 /* ignore anything else for now */
2649 case LDB_REPLY_DONE:
2652 /* get user domain data */
2653 ret = build_domain_data_request(ac);
2654 if (ret != LDB_SUCCESS) {
2655 return ldb_module_done(ac->req, NULL, NULL, ret);
2658 ret = ldb_next_request(ac->module, ac->dom_req);
2663 if (ret != LDB_SUCCESS) {
2664 return ldb_module_done(ac->req, NULL, NULL, ret);
2670 static int password_hash_mod_search_self(struct ph_context *ac)
2672 struct ldb_context *ldb;
2673 static const char * const attrs[] = { "objectClass",
2674 "userAccountControl",
2678 "userPrincipalName",
2679 "supplementalCredentials",
2685 struct ldb_request *search_req;
2688 ldb = ldb_module_get_ctx(ac->module);
2690 ret = ldb_build_search_req(&search_req, ldb, ac,
2691 ac->req->op.mod.message->dn,
2696 ac, ph_mod_search_callback,
2698 LDB_REQ_SET_LOCATION(search_req);
2699 if (ret != LDB_SUCCESS) {
2703 return ldb_next_request(ac->module, search_req);
2706 static int password_hash_mod_do_mod(struct ph_context *ac)
2708 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2709 struct loadparm_context *lp_ctx =
2710 talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2711 struct loadparm_context);
2712 struct ldb_request *mod_req;
2713 struct ldb_message *msg;
2714 const struct ldb_message *orig_msg, *searched_msg;
2715 struct setup_password_fields_io io;
2719 /* use a new message structure so that we can modify it */
2720 msg = ldb_msg_new(ac);
2722 return ldb_operr(ldb);
2726 msg->dn = ac->req->op.mod.message->dn;
2728 orig_msg = ac->req->op.mod.message;
2729 searched_msg = ac->search_res->message;
2731 /* Prepare the internal data structure containing the passwords */
2732 ret = setup_io(ac, orig_msg, searched_msg, &io);
2733 if (ret != LDB_SUCCESS) {
2737 /* Get the old password from the database */
2738 status = samdb_result_passwords(io.ac,
2740 discard_const_p(struct ldb_message, searched_msg),
2741 &io.o.lm_hash, &io.o.nt_hash);
2742 if (!NT_STATUS_IS_OK(status)) {
2743 return ldb_operr(ldb);
2746 io.o.nt_history_len = samdb_result_hashes(io.ac, searched_msg, "ntPwdHistory", &io.o.nt_history);
2747 io.o.lm_history_len = samdb_result_hashes(io.ac, searched_msg, "lmPwdHistory", &io.o.lm_history);
2748 io.o.supplemental = ldb_msg_find_ldb_val(searched_msg, "supplementalCredentials");
2750 ret = setup_password_fields(&io);
2751 if (ret != LDB_SUCCESS) {
2755 ret = check_password_restrictions(&io);
2756 if (ret != LDB_SUCCESS) {
2760 /* make sure we replace all the old attributes */
2761 ret = ldb_msg_add_empty(msg, "unicodePwd", LDB_FLAG_MOD_REPLACE, NULL);
2762 ret = ldb_msg_add_empty(msg, "dBCSPwd", LDB_FLAG_MOD_REPLACE, NULL);
2763 ret = ldb_msg_add_empty(msg, "ntPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
2764 ret = ldb_msg_add_empty(msg, "lmPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
2765 ret = ldb_msg_add_empty(msg, "supplementalCredentials", LDB_FLAG_MOD_REPLACE, NULL);
2766 ret = ldb_msg_add_empty(msg, "pwdLastSet", LDB_FLAG_MOD_REPLACE, NULL);
2769 ret = samdb_msg_add_hash(ldb, ac, msg,
2770 "unicodePwd", io.g.nt_hash);
2771 if (ret != LDB_SUCCESS) {
2776 ret = samdb_msg_add_hash(ldb, ac, msg,
2777 "dBCSPwd", io.g.lm_hash);
2778 if (ret != LDB_SUCCESS) {
2782 if (io.g.nt_history_len > 0) {
2783 ret = samdb_msg_add_hashes(ldb, ac, msg,
2786 io.g.nt_history_len);
2787 if (ret != LDB_SUCCESS) {
2791 if (io.g.lm_history_len > 0) {
2792 ret = samdb_msg_add_hashes(ldb, ac, msg,
2795 io.g.lm_history_len);
2796 if (ret != LDB_SUCCESS) {
2800 if (io.g.supplemental.length > 0) {
2801 ret = ldb_msg_add_value(msg, "supplementalCredentials",
2802 &io.g.supplemental, NULL);
2803 if (ret != LDB_SUCCESS) {
2807 ret = samdb_msg_add_uint64(ldb, ac, msg,
2810 if (ret != LDB_SUCCESS) {
2814 ret = ldb_build_mod_req(&mod_req, ldb, ac,
2819 LDB_REQ_SET_LOCATION(mod_req);
2820 if (ret != LDB_SUCCESS) {
2824 return ldb_next_request(ac->module, mod_req);
2827 static const struct ldb_module_ops ldb_password_hash_module_ops = {
2828 .name = "password_hash",
2829 .add = password_hash_add,
2830 .modify = password_hash_modify
2833 int ldb_password_hash_module_init(const char *version)
2835 LDB_MODULE_CHECK_VERSION(version);
2836 return ldb_register_module(&ldb_password_hash_module_ops);