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 "ldb_module.h"
37 #include "libcli/auth/libcli_auth.h"
38 #include "system/kerberos.h"
39 #include "auth/kerberos/kerberos.h"
40 #include "dsdb/samdb/samdb.h"
41 #include "dsdb/samdb/ldb_modules/util.h"
42 #include "dsdb/samdb/ldb_modules/password_modules.h"
43 #include "librpc/gen_ndr/ndr_drsblobs.h"
44 #include "../lib/crypto/crypto.h"
45 #include "param/param.h"
46 #include "lib/krb5_wrap/krb5_samba.h"
48 /* If we have decided there is a reason to work on this request, then
49 * setup all the password hash types correctly.
51 * If we haven't the hashes yet but the password given as plain-text (attributes
52 * 'unicodePwd', 'userPassword' and 'clearTextPassword') we have to check for
53 * the constraints. Once this is done, we calculate the password hashes.
55 * Notice: unlike the real AD which only supports the UTF16 special based
56 * 'unicodePwd' and the UTF8 based 'userPassword' plaintext attribute we
57 * understand also a UTF16 based 'clearTextPassword' one.
58 * The latter is also accessible through LDAP so it can also be set by external
59 * tools and scripts. But be aware that this isn't portable on non SAMBA 4 ADs!
61 * Also when the module receives only the password hashes (possible through
62 * specifying an internal LDB control - for security reasons) some checks are
63 * performed depending on the operation mode (see below) (e.g. if the password
64 * has been in use before if the password memory policy was activated).
66 * Attention: There is a difference between "modify" and "reset" operations
67 * (see MS-ADTS 3.1.1.3.1.5). If the client sends a "add" and "remove"
68 * operation for a password attribute we thread this as a "modify"; if it sends
69 * only a "replace" one we have an (administrative) reset.
71 * Finally, if the administrator has requested that a password history
72 * be maintained, then this should also be written out.
76 /* TODO: [consider always MS-ADTS 3.1.1.3.1.5]
77 * - Check for right connection encryption
80 /* Notice: Definition of "dsdb_control_password_change_status" moved into
84 struct ldb_module *module;
85 struct ldb_request *req;
87 struct ldb_request *dom_req;
88 struct ldb_reply *dom_res;
90 struct ldb_reply *search_res;
92 struct dsdb_control_password_change_status *status;
93 struct dsdb_control_password_change *change;
99 bool pwd_last_set_bypass;
103 struct setup_password_fields_io {
104 struct ph_context *ac;
106 struct smb_krb5_context *smb_krb5_context;
108 /* infos about the user account */
110 uint32_t userAccountControl;
112 const char *sAMAccountName;
113 const char *user_principal_name;
115 uint32_t restrictions;
118 /* new credentials and old given credentials */
119 struct setup_password_fields_given {
120 const struct ldb_val *cleartext_utf8;
121 const struct ldb_val *cleartext_utf16;
122 struct samr_Password *nt_hash;
123 struct samr_Password *lm_hash;
126 /* old credentials */
128 struct samr_Password *nt_hash;
129 struct samr_Password *lm_hash;
130 uint32_t nt_history_len;
131 struct samr_Password *nt_history;
132 uint32_t lm_history_len;
133 struct samr_Password *lm_history;
134 const struct ldb_val *supplemental;
135 struct supplementalCredentialsBlob scb;
138 /* generated credentials */
140 struct samr_Password *nt_hash;
141 struct samr_Password *lm_hash;
142 uint32_t nt_history_len;
143 struct samr_Password *nt_history;
144 uint32_t lm_history_len;
145 struct samr_Password *lm_history;
151 struct ldb_val supplemental;
156 static int password_hash_bypass(struct ldb_module *module, struct ldb_request *request)
158 struct ldb_context *ldb = ldb_module_get_ctx(module);
159 const struct ldb_message *msg;
160 struct ldb_message_element *nte;
161 struct ldb_message_element *lme;
162 struct ldb_message_element *nthe;
163 struct ldb_message_element *lmhe;
164 struct ldb_message_element *sce;
166 switch (request->operation) {
168 msg = request->op.add.message;
171 msg = request->op.mod.message;
174 return ldb_next_request(module, request);
177 /* nobody must touch password histories and 'supplementalCredentials' */
178 nte = dsdb_get_single_valued_attr(msg, "unicodePwd",
180 lme = dsdb_get_single_valued_attr(msg, "dBCSPwd",
182 nthe = dsdb_get_single_valued_attr(msg, "ntPwdHistory",
184 lmhe = dsdb_get_single_valued_attr(msg, "lmPwdHistory",
186 sce = dsdb_get_single_valued_attr(msg, "supplementalCredentials",
189 #define CHECK_HASH_ELEMENT(e, min, max) do {\
190 if (e && e->num_values) { \
191 unsigned int _count; \
192 if (e->num_values != 1) { \
193 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
194 "num_values != 1"); \
196 if ((e->values[0].length % 16) != 0) { \
197 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
198 "length % 16 != 0"); \
200 _count = e->values[0].length / 16; \
201 if (_count < min) { \
202 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
205 if (_count > max) { \
206 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
212 CHECK_HASH_ELEMENT(nte, 1, 1);
213 CHECK_HASH_ELEMENT(lme, 1, 1);
214 CHECK_HASH_ELEMENT(nthe, 1, INT32_MAX);
215 CHECK_HASH_ELEMENT(lmhe, 1, INT32_MAX);
217 if (sce && sce->num_values) {
218 enum ndr_err_code ndr_err;
219 struct supplementalCredentialsBlob *scb;
220 struct supplementalCredentialsPackage *scpp = NULL;
221 struct supplementalCredentialsPackage *scpk = NULL;
222 struct supplementalCredentialsPackage *scpkn = NULL;
223 struct supplementalCredentialsPackage *scpct = NULL;
224 DATA_BLOB scpbp = data_blob_null;
225 DATA_BLOB scpbk = data_blob_null;
226 DATA_BLOB scpbkn = data_blob_null;
227 DATA_BLOB scpbct = data_blob_null;
231 if (sce->num_values != 1) {
232 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
236 scb = talloc_zero(request, struct supplementalCredentialsBlob);
238 return ldb_module_oom(module);
241 ndr_err = ndr_pull_struct_blob_all(&sce->values[0], scb, scb,
242 (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
243 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
244 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
245 "ndr_pull_struct_blob_all");
248 if (scb->sub.num_packages < 2) {
249 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
253 for (i=0; i < scb->sub.num_packages; i++) {
256 subblob = strhex_to_data_blob(scb, scb->sub.packages[i].data);
257 if (subblob.data == NULL) {
258 return ldb_module_oom(module);
261 if (strcmp(scb->sub.packages[i].name, "Packages") == 0) {
263 return ldb_error(ldb,
264 LDB_ERR_CONSTRAINT_VIOLATION,
267 scpp = &scb->sub.packages[i];
271 if (strcmp(scb->sub.packages[i].name, "Primary:Kerberos") == 0) {
273 return ldb_error(ldb,
274 LDB_ERR_CONSTRAINT_VIOLATION,
275 "Primary:Kerberos twice");
277 scpk = &scb->sub.packages[i];
281 if (strcmp(scb->sub.packages[i].name, "Primary:Kerberos-Newer-Keys") == 0) {
283 return ldb_error(ldb,
284 LDB_ERR_CONSTRAINT_VIOLATION,
285 "Primary:Kerberos-Newer-Keys twice");
287 scpkn = &scb->sub.packages[i];
291 if (strcmp(scb->sub.packages[i].name, "Primary:CLEARTEXT") == 0) {
293 return ldb_error(ldb,
294 LDB_ERR_CONSTRAINT_VIOLATION,
295 "Primary:CLEARTEXT twice");
297 scpct = &scb->sub.packages[i];
302 data_blob_free(&subblob);
306 return ldb_error(ldb,
307 LDB_ERR_CONSTRAINT_VIOLATION,
308 "Primary:Packages missing");
313 * If Primary:Kerberos is missing w2k8r2 reboots
314 * when a password is changed.
316 return ldb_error(ldb,
317 LDB_ERR_CONSTRAINT_VIOLATION,
318 "Primary:Kerberos missing");
322 struct package_PackagesBlob *p;
325 p = talloc_zero(scb, struct package_PackagesBlob);
327 return ldb_module_oom(module);
330 ndr_err = ndr_pull_struct_blob(&scpbp, p, p,
331 (ndr_pull_flags_fn_t)ndr_pull_package_PackagesBlob);
332 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
333 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
334 "ndr_pull_struct_blob Packages");
337 if (p->names == NULL) {
338 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
339 "Packages names == NULL");
342 for (n = 0; p->names[n]; n++) {
346 if (scb->sub.num_packages != (n + 1)) {
347 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
348 "Packages num_packages != num_names + 1");
355 struct package_PrimaryKerberosBlob *k;
357 k = talloc_zero(scb, struct package_PrimaryKerberosBlob);
359 return ldb_module_oom(module);
362 ndr_err = ndr_pull_struct_blob(&scpbk, k, k,
363 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
364 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
365 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
366 "ndr_pull_struct_blob PrimaryKerberos");
369 if (k->version != 3) {
370 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
371 "PrimaryKerberos version != 3");
374 if (k->ctr.ctr3.salt.string == NULL) {
375 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
376 "PrimaryKerberos salt == NULL");
379 if (strlen(k->ctr.ctr3.salt.string) == 0) {
380 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
381 "PrimaryKerberos strlen(salt) == 0");
384 if (k->ctr.ctr3.num_keys != 2) {
385 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
386 "PrimaryKerberos num_keys != 2");
389 if (k->ctr.ctr3.num_old_keys > k->ctr.ctr3.num_keys) {
390 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
391 "PrimaryKerberos num_old_keys > num_keys");
394 if (k->ctr.ctr3.keys[0].keytype != ENCTYPE_DES_CBC_MD5) {
395 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
396 "PrimaryKerberos key[0] != DES_CBC_MD5");
398 if (k->ctr.ctr3.keys[1].keytype != ENCTYPE_DES_CBC_CRC) {
399 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
400 "PrimaryKerberos key[1] != DES_CBC_CRC");
403 if (k->ctr.ctr3.keys[0].value_len != 8) {
404 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
405 "PrimaryKerberos key[0] value_len != 8");
407 if (k->ctr.ctr3.keys[1].value_len != 8) {
408 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
409 "PrimaryKerberos key[1] value_len != 8");
412 for (i = 0; i < k->ctr.ctr3.num_old_keys; i++) {
413 if (k->ctr.ctr3.old_keys[i].keytype ==
414 k->ctr.ctr3.keys[i].keytype &&
415 k->ctr.ctr3.old_keys[i].value_len ==
416 k->ctr.ctr3.keys[i].value_len) {
420 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
421 "PrimaryKerberos old_keys type/value_len doesn't match");
428 struct package_PrimaryKerberosBlob *k;
430 k = talloc_zero(scb, struct package_PrimaryKerberosBlob);
432 return ldb_module_oom(module);
435 ndr_err = ndr_pull_struct_blob(&scpbkn, k, k,
436 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
437 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
438 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
439 "ndr_pull_struct_blob PrimaryKerberosNeverKeys");
442 if (k->version != 4) {
443 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
444 "KerberosNerverKeys version != 4");
447 if (k->ctr.ctr4.salt.string == NULL) {
448 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
449 "KerberosNewerKeys salt == NULL");
452 if (strlen(k->ctr.ctr4.salt.string) == 0) {
453 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
454 "KerberosNewerKeys strlen(salt) == 0");
457 if (k->ctr.ctr4.num_keys != 4) {
458 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
459 "KerberosNewerKeys num_keys != 2");
462 if (k->ctr.ctr4.num_old_keys > k->ctr.ctr4.num_keys) {
463 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
464 "KerberosNewerKeys num_old_keys > num_keys");
467 if (k->ctr.ctr4.num_older_keys > k->ctr.ctr4.num_old_keys) {
468 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
469 "KerberosNewerKeys num_older_keys > num_old_keys");
472 if (k->ctr.ctr4.keys[0].keytype != ENCTYPE_AES256_CTS_HMAC_SHA1_96) {
473 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
474 "KerberosNewerKeys key[0] != AES256");
476 if (k->ctr.ctr4.keys[1].keytype != ENCTYPE_AES128_CTS_HMAC_SHA1_96) {
477 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
478 "KerberosNewerKeys key[1] != AES128");
480 if (k->ctr.ctr4.keys[2].keytype != ENCTYPE_DES_CBC_MD5) {
481 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
482 "KerberosNewerKeys key[2] != DES_CBC_MD5");
484 if (k->ctr.ctr4.keys[3].keytype != ENCTYPE_DES_CBC_CRC) {
485 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
486 "KerberosNewerKeys key[3] != DES_CBC_CRC");
489 if (k->ctr.ctr4.keys[0].value_len != 32) {
490 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
491 "KerberosNewerKeys key[0] value_len != 32");
493 if (k->ctr.ctr4.keys[1].value_len != 16) {
494 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
495 "KerberosNewerKeys key[1] value_len != 16");
497 if (k->ctr.ctr4.keys[2].value_len != 8) {
498 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
499 "KerberosNewerKeys key[2] value_len != 8");
501 if (k->ctr.ctr4.keys[3].value_len != 8) {
502 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
503 "KerberosNewerKeys key[3] value_len != 8");
508 * Maybe we can check old and older keys here.
509 * But we need to do some tests, if the old keys
510 * can be taken from the PrimaryKerberos blob
511 * (with only des keys), when the domain was upgraded
519 struct package_PrimaryCLEARTEXTBlob *ct;
521 ct = talloc_zero(scb, struct package_PrimaryCLEARTEXTBlob);
523 return ldb_module_oom(module);
526 ndr_err = ndr_pull_struct_blob(&scpbct, ct, ct,
527 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryCLEARTEXTBlob);
528 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
529 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
530 "ndr_pull_struct_blob PrimaryCLEARTEXT");
533 if ((ct->cleartext.length % 2) != 0) {
534 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
535 "PrimaryCLEARTEXT length % 2 != 0");
541 ndr_err = ndr_push_struct_blob(&blob, scb, scb,
542 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
543 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
544 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
545 "ndr_pull_struct_blob_all");
548 if (sce->values[0].length != blob.length) {
549 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
550 "supplementalCredentialsBlob length differ");
553 if (memcmp(sce->values[0].data, blob.data, blob.length) != 0) {
554 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
555 "supplementalCredentialsBlob memcmp differ");
561 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_bypass - validated\n");
562 return ldb_next_request(module, request);
565 /* Get the NT hash, and fill it in as an entry in the password history,
566 and specify it into io->g.nt_hash */
568 static int setup_nt_fields(struct setup_password_fields_io *io)
570 struct ldb_context *ldb;
573 io->g.nt_hash = io->n.nt_hash;
574 ldb = ldb_module_get_ctx(io->ac->module);
576 if (io->ac->status->domain_data.pwdHistoryLength == 0) {
580 /* We might not have an old NT password */
581 io->g.nt_history = talloc_array(io->ac,
582 struct samr_Password,
583 io->ac->status->domain_data.pwdHistoryLength);
584 if (!io->g.nt_history) {
588 for (i = 0; i < MIN(io->ac->status->domain_data.pwdHistoryLength-1,
589 io->o.nt_history_len); i++) {
590 io->g.nt_history[i+1] = io->o.nt_history[i];
592 io->g.nt_history_len = i + 1;
595 io->g.nt_history[0] = *io->g.nt_hash;
598 * TODO: is this correct?
599 * the simular behavior is correct for the lm history case
601 E_md4hash("", io->g.nt_history[0].hash);
607 /* Get the LANMAN hash, and fill it in as an entry in the password history,
608 and specify it into io->g.lm_hash */
610 static int setup_lm_fields(struct setup_password_fields_io *io)
612 struct ldb_context *ldb;
615 io->g.lm_hash = io->n.lm_hash;
616 ldb = ldb_module_get_ctx(io->ac->module);
618 if (io->ac->status->domain_data.pwdHistoryLength == 0) {
622 /* We might not have an old LM password */
623 io->g.lm_history = talloc_array(io->ac,
624 struct samr_Password,
625 io->ac->status->domain_data.pwdHistoryLength);
626 if (!io->g.lm_history) {
630 for (i = 0; i < MIN(io->ac->status->domain_data.pwdHistoryLength-1,
631 io->o.lm_history_len); i++) {
632 io->g.lm_history[i+1] = io->o.lm_history[i];
634 io->g.lm_history_len = i + 1;
637 io->g.lm_history[0] = *io->g.lm_hash;
639 E_deshash("", io->g.lm_history[0].hash);
645 static int setup_kerberos_keys(struct setup_password_fields_io *io)
647 struct ldb_context *ldb;
648 krb5_error_code krb5_ret;
649 krb5_principal salt_principal;
652 krb5_data cleartext_data;
654 ldb = ldb_module_get_ctx(io->ac->module);
655 cleartext_data.data = (char *)io->n.cleartext_utf8->data;
656 cleartext_data.length = io->n.cleartext_utf8->length;
658 /* Many, many thanks to lukeh@padl.com for this
659 * algorithm, described in his Nov 10 2004 mail to
660 * samba-technical@lists.samba.org */
663 * Determine a salting principal
665 if (io->u.is_computer) {
669 name = strlower_talloc(io->ac, io->u.sAMAccountName);
674 if (name[strlen(name)-1] == '$') {
675 name[strlen(name)-1] = '\0';
678 saltbody = talloc_asprintf(io->ac, "%s.%s", name,
679 io->ac->status->domain_data.dns_domain);
684 krb5_ret = smb_krb5_make_principal(io->smb_krb5_context->krb5_context,
686 io->ac->status->domain_data.realm,
687 "host", saltbody, NULL);
688 } else if (io->u.user_principal_name) {
689 char *user_principal_name;
692 user_principal_name = talloc_strdup(io->ac, io->u.user_principal_name);
693 if (!user_principal_name) {
697 p = strchr(user_principal_name, '@');
702 krb5_ret = smb_krb5_make_principal(io->smb_krb5_context->krb5_context,
704 io->ac->status->domain_data.realm,
705 user_principal_name, NULL);
707 krb5_ret = smb_krb5_make_principal(io->smb_krb5_context->krb5_context,
709 io->ac->status->domain_data.realm,
710 io->u.sAMAccountName, NULL);
713 ldb_asprintf_errstring(ldb,
714 "setup_kerberos_keys: "
715 "generation of a salting principal failed: %s",
716 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
718 return LDB_ERR_OPERATIONS_ERROR;
722 * create salt from salt_principal
724 krb5_ret = smb_krb5_get_pw_salt(io->smb_krb5_context->krb5_context,
725 salt_principal, &salt);
726 krb5_free_principal(io->smb_krb5_context->krb5_context, salt_principal);
728 ldb_asprintf_errstring(ldb,
729 "setup_kerberos_keys: "
730 "generation of krb5_salt failed: %s",
731 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
733 return LDB_ERR_OPERATIONS_ERROR;
735 /* create a talloc copy */
736 io->g.salt = talloc_strndup(io->ac,
739 kerberos_free_data_contents(io->smb_krb5_context->krb5_context, &salt);
743 /* now use the talloced copy of the salt */
744 salt.data = discard_const(io->g.salt);
745 salt.length = strlen(io->g.salt);
748 * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of
749 * the salt and the cleartext password
751 krb5_ret = smb_krb5_create_key_from_string(io->smb_krb5_context->krb5_context,
755 ENCTYPE_AES256_CTS_HMAC_SHA1_96,
758 ldb_asprintf_errstring(ldb,
759 "setup_kerberos_keys: "
760 "generation of a aes256-cts-hmac-sha1-96 key failed: %s",
761 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
763 return LDB_ERR_OPERATIONS_ERROR;
765 io->g.aes_256 = data_blob_talloc(io->ac,
767 KRB5_KEY_LENGTH(&key));
768 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
769 if (!io->g.aes_256.data) {
774 * create ENCTYPE_AES128_CTS_HMAC_SHA1_96 key out of
775 * the salt and the cleartext password
777 krb5_ret = smb_krb5_create_key_from_string(io->smb_krb5_context->krb5_context,
781 ENCTYPE_AES128_CTS_HMAC_SHA1_96,
784 ldb_asprintf_errstring(ldb,
785 "setup_kerberos_keys: "
786 "generation of a aes128-cts-hmac-sha1-96 key failed: %s",
787 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
789 return LDB_ERR_OPERATIONS_ERROR;
791 io->g.aes_128 = data_blob_talloc(io->ac,
793 KRB5_KEY_LENGTH(&key));
794 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
795 if (!io->g.aes_128.data) {
800 * create ENCTYPE_DES_CBC_MD5 key out of
801 * the salt and the cleartext password
803 krb5_ret = smb_krb5_create_key_from_string(io->smb_krb5_context->krb5_context,
810 ldb_asprintf_errstring(ldb,
811 "setup_kerberos_keys: "
812 "generation of a des-cbc-md5 key failed: %s",
813 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
815 return LDB_ERR_OPERATIONS_ERROR;
817 io->g.des_md5 = data_blob_talloc(io->ac,
819 KRB5_KEY_LENGTH(&key));
820 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
821 if (!io->g.des_md5.data) {
826 * create ENCTYPE_DES_CBC_CRC key out of
827 * the salt and the cleartext password
829 krb5_ret = smb_krb5_create_key_from_string(io->smb_krb5_context->krb5_context,
836 ldb_asprintf_errstring(ldb,
837 "setup_kerberos_keys: "
838 "generation of a des-cbc-crc key failed: %s",
839 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
841 return LDB_ERR_OPERATIONS_ERROR;
843 io->g.des_crc = data_blob_talloc(io->ac,
845 KRB5_KEY_LENGTH(&key));
846 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
847 if (!io->g.des_crc.data) {
854 static int setup_primary_kerberos(struct setup_password_fields_io *io,
855 const struct supplementalCredentialsBlob *old_scb,
856 struct package_PrimaryKerberosBlob *pkb)
858 struct ldb_context *ldb;
859 struct package_PrimaryKerberosCtr3 *pkb3 = &pkb->ctr.ctr3;
860 struct supplementalCredentialsPackage *old_scp = NULL;
861 struct package_PrimaryKerberosBlob _old_pkb;
862 struct package_PrimaryKerberosCtr3 *old_pkb3 = NULL;
864 enum ndr_err_code ndr_err;
866 ldb = ldb_module_get_ctx(io->ac->module);
869 * prepare generation of keys
871 * ENCTYPE_DES_CBC_MD5
872 * ENCTYPE_DES_CBC_CRC
875 pkb3->salt.string = io->g.salt;
877 pkb3->keys = talloc_array(io->ac,
878 struct package_PrimaryKerberosKey3,
884 pkb3->keys[0].keytype = ENCTYPE_DES_CBC_MD5;
885 pkb3->keys[0].value = &io->g.des_md5;
886 pkb3->keys[1].keytype = ENCTYPE_DES_CBC_CRC;
887 pkb3->keys[1].value = &io->g.des_crc;
889 /* initialize the old keys to zero */
890 pkb3->num_old_keys = 0;
891 pkb3->old_keys = NULL;
893 /* if there're no old keys, then we're done */
898 for (i=0; i < old_scb->sub.num_packages; i++) {
899 if (strcmp("Primary:Kerberos", old_scb->sub.packages[i].name) != 0) {
903 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
907 old_scp = &old_scb->sub.packages[i];
910 /* Primary:Kerberos element of supplementalCredentials */
914 blob = strhex_to_data_blob(io->ac, old_scp->data);
919 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
920 ndr_err = ndr_pull_struct_blob(&blob, io->ac, &_old_pkb,
921 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
922 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
923 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
924 ldb_asprintf_errstring(ldb,
925 "setup_primary_kerberos: "
926 "failed to pull old package_PrimaryKerberosBlob: %s",
928 return LDB_ERR_OPERATIONS_ERROR;
931 if (_old_pkb.version != 3) {
932 ldb_asprintf_errstring(ldb,
933 "setup_primary_kerberos: "
934 "package_PrimaryKerberosBlob version[%u] expected[3]",
936 return LDB_ERR_OPERATIONS_ERROR;
939 old_pkb3 = &_old_pkb.ctr.ctr3;
942 /* if we didn't found the old keys we're done */
947 /* fill in the old keys */
948 pkb3->num_old_keys = old_pkb3->num_keys;
949 pkb3->old_keys = old_pkb3->keys;
954 static int setup_primary_kerberos_newer(struct setup_password_fields_io *io,
955 const struct supplementalCredentialsBlob *old_scb,
956 struct package_PrimaryKerberosBlob *pkb)
958 struct ldb_context *ldb;
959 struct package_PrimaryKerberosCtr4 *pkb4 = &pkb->ctr.ctr4;
960 struct supplementalCredentialsPackage *old_scp = NULL;
961 struct package_PrimaryKerberosBlob _old_pkb;
962 struct package_PrimaryKerberosCtr4 *old_pkb4 = NULL;
964 enum ndr_err_code ndr_err;
966 ldb = ldb_module_get_ctx(io->ac->module);
969 * prepare generation of keys
971 * ENCTYPE_AES256_CTS_HMAC_SHA1_96
972 * ENCTYPE_AES128_CTS_HMAC_SHA1_96
973 * ENCTYPE_DES_CBC_MD5
974 * ENCTYPE_DES_CBC_CRC
977 pkb4->salt.string = io->g.salt;
978 pkb4->default_iteration_count = 4096;
981 pkb4->keys = talloc_array(io->ac,
982 struct package_PrimaryKerberosKey4,
988 pkb4->keys[0].iteration_count = 4096;
989 pkb4->keys[0].keytype = ENCTYPE_AES256_CTS_HMAC_SHA1_96;
990 pkb4->keys[0].value = &io->g.aes_256;
991 pkb4->keys[1].iteration_count = 4096;
992 pkb4->keys[1].keytype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
993 pkb4->keys[1].value = &io->g.aes_128;
994 pkb4->keys[2].iteration_count = 4096;
995 pkb4->keys[2].keytype = ENCTYPE_DES_CBC_MD5;
996 pkb4->keys[2].value = &io->g.des_md5;
997 pkb4->keys[3].iteration_count = 4096;
998 pkb4->keys[3].keytype = ENCTYPE_DES_CBC_CRC;
999 pkb4->keys[3].value = &io->g.des_crc;
1001 /* initialize the old keys to zero */
1002 pkb4->num_old_keys = 0;
1003 pkb4->old_keys = NULL;
1004 pkb4->num_older_keys = 0;
1005 pkb4->older_keys = NULL;
1007 /* if there're no old keys, then we're done */
1012 for (i=0; i < old_scb->sub.num_packages; i++) {
1013 if (strcmp("Primary:Kerberos-Newer-Keys", old_scb->sub.packages[i].name) != 0) {
1017 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
1021 old_scp = &old_scb->sub.packages[i];
1024 /* Primary:Kerberos-Newer-Keys element of supplementalCredentials */
1028 blob = strhex_to_data_blob(io->ac, old_scp->data);
1030 return ldb_oom(ldb);
1033 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
1034 ndr_err = ndr_pull_struct_blob(&blob, io->ac,
1036 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
1037 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1038 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1039 ldb_asprintf_errstring(ldb,
1040 "setup_primary_kerberos_newer: "
1041 "failed to pull old package_PrimaryKerberosBlob: %s",
1043 return LDB_ERR_OPERATIONS_ERROR;
1046 if (_old_pkb.version != 4) {
1047 ldb_asprintf_errstring(ldb,
1048 "setup_primary_kerberos_newer: "
1049 "package_PrimaryKerberosBlob version[%u] expected[4]",
1051 return LDB_ERR_OPERATIONS_ERROR;
1054 old_pkb4 = &_old_pkb.ctr.ctr4;
1057 /* if we didn't found the old keys we're done */
1062 /* fill in the old keys */
1063 pkb4->num_old_keys = old_pkb4->num_keys;
1064 pkb4->old_keys = old_pkb4->keys;
1065 pkb4->num_older_keys = old_pkb4->num_old_keys;
1066 pkb4->older_keys = old_pkb4->old_keys;
1071 static int setup_primary_wdigest(struct setup_password_fields_io *io,
1072 const struct supplementalCredentialsBlob *old_scb,
1073 struct package_PrimaryWDigestBlob *pdb)
1075 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1076 DATA_BLOB sAMAccountName;
1077 DATA_BLOB sAMAccountName_l;
1078 DATA_BLOB sAMAccountName_u;
1079 const char *user_principal_name = io->u.user_principal_name;
1080 DATA_BLOB userPrincipalName;
1081 DATA_BLOB userPrincipalName_l;
1082 DATA_BLOB userPrincipalName_u;
1083 DATA_BLOB netbios_domain;
1084 DATA_BLOB netbios_domain_l;
1085 DATA_BLOB netbios_domain_u;
1086 DATA_BLOB dns_domain;
1087 DATA_BLOB dns_domain_l;
1088 DATA_BLOB dns_domain_u;
1091 DATA_BLOB backslash;
1100 * http://technet2.microsoft.com/WindowsServer/en/library/717b450c-f4a0-4cc9-86f4-cc0633aae5f91033.mspx?mfr=true
1101 * for what precalculated hashes are supposed to be stored...
1103 * I can't reproduce all values which should contain "Digest" as realm,
1104 * am I doing something wrong or is w2k3 just broken...?
1106 * W2K3 fills in following for a user:
1108 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
1109 * sAMAccountName: NewUser2Sam
1110 * userPrincipalName: NewUser2Princ@sub1.w2k3.vmnet1.vm.base
1112 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1113 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
1114 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
1115 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1116 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
1117 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
1118 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
1119 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1120 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1121 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1122 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1123 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1124 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1125 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1126 * 221c55284451ae9b3aacaa2a3c86f10f => NewUser2Princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1127 * 74e1be668853d4324d38c07e2acfb8ea => (w2k3 has a bug here!) newuser2princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1128 * e1e244ab7f098e3ae1761be7f9229bbb => NEWUSER2PRINC@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
1129 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
1130 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
1131 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
1132 * 31dc704d3640335b2123d4ee28aa1f11 => ??? changes with NewUser2Sam => NewUser1Sam
1133 * 36349f5cecd07320fb3bb0e119230c43 => ??? changes with NewUser2Sam => NewUser1Sam
1134 * 12adf019d037fb535c01fd0608e78d9d => ??? changes with NewUser2Sam => NewUser1Sam
1135 * 6feecf8e724906f3ee1105819c5105a1 => ??? changes with NewUser2Princ => NewUser1Princ
1136 * 6c6911f3de6333422640221b9c51ff1f => ??? changes with NewUser2Princ => NewUser1Princ
1137 * 4b279877e742895f9348ac67a8de2f69 => ??? changes with NewUser2Princ => NewUser1Princ
1138 * db0c6bff069513e3ebb9870d29b57490 => ??? changes with NewUser2Sam => NewUser1Sam
1139 * 45072621e56b1c113a4e04a8ff68cd0e => ??? changes with NewUser2Sam => NewUser1Sam
1140 * 11d1220abc44a9c10cf91ef4a9c1de02 => ??? changes with NewUser2Sam => NewUser1Sam
1142 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
1143 * sAMAccountName: NewUser2Sam
1145 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1146 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
1147 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
1148 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1149 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
1150 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
1151 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
1152 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1153 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1154 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1155 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1156 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1157 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1158 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1159 * 8a140d30b6f0a5912735dc1e3bc993b4 => NewUser2Sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1160 * 86d95b2faae6cae4ec261e7fbaccf093 => (here w2k3 is correct) newuser2sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1161 * dfeff1493110220efcdfc6362e5f5450 => NEWUSER2SAM@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
1162 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
1163 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
1164 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
1165 * 31dc704d3640335b2123d4ee28aa1f11 => ???M1 changes with NewUser2Sam => NewUser1Sam
1166 * 36349f5cecd07320fb3bb0e119230c43 => ???M1.L changes with newuser2sam => newuser1sam
1167 * 12adf019d037fb535c01fd0608e78d9d => ???M1.U changes with NEWUSER2SAM => NEWUSER1SAM
1168 * 569b4533f2d9e580211dd040e5e360a8 => ???M2 changes with NewUser2Princ => NewUser1Princ
1169 * 52528bddf310a587c5d7e6a9ae2cbb20 => ???M2.L changes with newuser2princ => newuser1princ
1170 * 4f629a4f0361289ca4255ab0f658fcd5 => ???M3 changes with NewUser2Princ => NewUser1Princ (doesn't depend on case of userPrincipal )
1171 * db0c6bff069513e3ebb9870d29b57490 => ???M4 changes with NewUser2Sam => NewUser1Sam
1172 * 45072621e56b1c113a4e04a8ff68cd0e => ???M5 changes with NewUser2Sam => NewUser1Sam (doesn't depend on case of sAMAccountName)
1173 * 11d1220abc44a9c10cf91ef4a9c1de02 => ???M4.U changes with NEWUSER2SAM => NEWUSER1SAM
1177 * sAMAccountName, netbios_domain
1180 .user = &sAMAccountName,
1181 .realm = &netbios_domain,
1184 .user = &sAMAccountName_l,
1185 .realm = &netbios_domain_l,
1188 .user = &sAMAccountName_u,
1189 .realm = &netbios_domain_u,
1192 .user = &sAMAccountName,
1193 .realm = &netbios_domain_u,
1196 .user = &sAMAccountName,
1197 .realm = &netbios_domain_l,
1200 .user = &sAMAccountName_u,
1201 .realm = &netbios_domain_l,
1204 .user = &sAMAccountName_l,
1205 .realm = &netbios_domain_u,
1208 * sAMAccountName, dns_domain
1211 .user = &sAMAccountName,
1212 .realm = &dns_domain,
1215 .user = &sAMAccountName_l,
1216 .realm = &dns_domain_l,
1219 .user = &sAMAccountName_u,
1220 .realm = &dns_domain_u,
1223 .user = &sAMAccountName,
1224 .realm = &dns_domain_u,
1227 .user = &sAMAccountName,
1228 .realm = &dns_domain_l,
1231 .user = &sAMAccountName_u,
1232 .realm = &dns_domain_l,
1235 .user = &sAMAccountName_l,
1236 .realm = &dns_domain_u,
1239 * userPrincipalName, no realm
1242 .user = &userPrincipalName,
1246 * NOTE: w2k3 messes this up, if the user has a real userPrincipalName,
1247 * the fallback to the sAMAccountName based userPrincipalName is correct
1249 .user = &userPrincipalName_l,
1252 .user = &userPrincipalName_u,
1255 * nt4dom\sAMAccountName, no realm
1258 .user = &sAMAccountName,
1259 .nt4dom = &netbios_domain
1262 .user = &sAMAccountName_l,
1263 .nt4dom = &netbios_domain_l
1266 .user = &sAMAccountName_u,
1267 .nt4dom = &netbios_domain_u
1271 * the following ones are guessed depending on the technet2 article
1272 * but not reproducable on a w2k3 server
1274 /* sAMAccountName with "Digest" realm */
1276 .user = &sAMAccountName,
1280 .user = &sAMAccountName_l,
1284 .user = &sAMAccountName_u,
1287 /* userPrincipalName with "Digest" realm */
1289 .user = &userPrincipalName,
1293 .user = &userPrincipalName_l,
1297 .user = &userPrincipalName_u,
1300 /* nt4dom\\sAMAccountName with "Digest" realm */
1302 .user = &sAMAccountName,
1303 .nt4dom = &netbios_domain,
1307 .user = &sAMAccountName_l,
1308 .nt4dom = &netbios_domain_l,
1312 .user = &sAMAccountName_u,
1313 .nt4dom = &netbios_domain_u,
1318 /* prepare DATA_BLOB's used in the combinations array */
1319 sAMAccountName = data_blob_string_const(io->u.sAMAccountName);
1320 sAMAccountName_l = data_blob_string_const(strlower_talloc(io->ac, io->u.sAMAccountName));
1321 if (!sAMAccountName_l.data) {
1322 return ldb_oom(ldb);
1324 sAMAccountName_u = data_blob_string_const(strupper_talloc(io->ac, io->u.sAMAccountName));
1325 if (!sAMAccountName_u.data) {
1326 return ldb_oom(ldb);
1329 /* if the user doesn't have a userPrincipalName, create one (with lower case realm) */
1330 if (!user_principal_name) {
1331 user_principal_name = talloc_asprintf(io->ac, "%s@%s",
1332 io->u.sAMAccountName,
1333 io->ac->status->domain_data.dns_domain);
1334 if (!user_principal_name) {
1335 return ldb_oom(ldb);
1338 userPrincipalName = data_blob_string_const(user_principal_name);
1339 userPrincipalName_l = data_blob_string_const(strlower_talloc(io->ac, user_principal_name));
1340 if (!userPrincipalName_l.data) {
1341 return ldb_oom(ldb);
1343 userPrincipalName_u = data_blob_string_const(strupper_talloc(io->ac, user_principal_name));
1344 if (!userPrincipalName_u.data) {
1345 return ldb_oom(ldb);
1348 netbios_domain = data_blob_string_const(io->ac->status->domain_data.netbios_domain);
1349 netbios_domain_l = data_blob_string_const(strlower_talloc(io->ac,
1350 io->ac->status->domain_data.netbios_domain));
1351 if (!netbios_domain_l.data) {
1352 return ldb_oom(ldb);
1354 netbios_domain_u = data_blob_string_const(strupper_talloc(io->ac,
1355 io->ac->status->domain_data.netbios_domain));
1356 if (!netbios_domain_u.data) {
1357 return ldb_oom(ldb);
1360 dns_domain = data_blob_string_const(io->ac->status->domain_data.dns_domain);
1361 dns_domain_l = data_blob_string_const(io->ac->status->domain_data.dns_domain);
1362 dns_domain_u = data_blob_string_const(io->ac->status->domain_data.realm);
1364 digest = data_blob_string_const("Digest");
1366 delim = data_blob_string_const(":");
1367 backslash = data_blob_string_const("\\");
1369 pdb->num_hashes = ARRAY_SIZE(wdigest);
1370 pdb->hashes = talloc_array(io->ac, struct package_PrimaryWDigestHash,
1373 return ldb_oom(ldb);
1376 for (i=0; i < ARRAY_SIZE(wdigest); i++) {
1379 if (wdigest[i].nt4dom) {
1380 MD5Update(&md5, wdigest[i].nt4dom->data, wdigest[i].nt4dom->length);
1381 MD5Update(&md5, backslash.data, backslash.length);
1383 MD5Update(&md5, wdigest[i].user->data, wdigest[i].user->length);
1384 MD5Update(&md5, delim.data, delim.length);
1385 if (wdigest[i].realm) {
1386 MD5Update(&md5, wdigest[i].realm->data, wdigest[i].realm->length);
1388 MD5Update(&md5, delim.data, delim.length);
1389 MD5Update(&md5, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length);
1390 MD5Final(pdb->hashes[i].hash, &md5);
1396 static int setup_supplemental_field(struct setup_password_fields_io *io)
1398 struct ldb_context *ldb;
1399 struct supplementalCredentialsBlob scb;
1400 struct supplementalCredentialsBlob _old_scb;
1401 struct supplementalCredentialsBlob *old_scb = NULL;
1402 /* Packages + (Kerberos-Newer-Keys, Kerberos, WDigest and CLEARTEXT) */
1403 uint32_t num_names = 0;
1404 const char *names[1+4];
1405 uint32_t num_packages = 0;
1406 struct supplementalCredentialsPackage packages[1+4];
1408 struct supplementalCredentialsPackage *pp = NULL;
1409 struct package_PackagesBlob pb;
1412 /* Primary:Kerberos-Newer-Keys */
1413 const char **nkn = NULL;
1414 struct supplementalCredentialsPackage *pkn = NULL;
1415 struct package_PrimaryKerberosBlob pknb;
1416 DATA_BLOB pknb_blob;
1418 /* Primary:Kerberos */
1419 const char **nk = NULL;
1420 struct supplementalCredentialsPackage *pk = NULL;
1421 struct package_PrimaryKerberosBlob pkb;
1424 /* Primary:WDigest */
1425 const char **nd = NULL;
1426 struct supplementalCredentialsPackage *pd = NULL;
1427 struct package_PrimaryWDigestBlob pdb;
1430 /* Primary:CLEARTEXT */
1431 const char **nc = NULL;
1432 struct supplementalCredentialsPackage *pc = NULL;
1433 struct package_PrimaryCLEARTEXTBlob pcb;
1437 enum ndr_err_code ndr_err;
1439 bool do_newer_keys = false;
1440 bool do_cleartext = false;
1442 ZERO_STRUCT(zero16);
1445 ldb = ldb_module_get_ctx(io->ac->module);
1447 if (!io->n.cleartext_utf8) {
1449 * when we don't have a cleartext password
1450 * we can't setup a supplementalCredential value
1455 /* if there's an old supplementaCredentials blob then parse it */
1456 if (io->o.supplemental) {
1457 ndr_err = ndr_pull_struct_blob_all(io->o.supplemental, io->ac,
1459 (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
1460 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1461 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1462 ldb_asprintf_errstring(ldb,
1463 "setup_supplemental_field: "
1464 "failed to pull old supplementalCredentialsBlob: %s",
1466 return LDB_ERR_OPERATIONS_ERROR;
1469 if (_old_scb.sub.signature == SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
1470 old_scb = &_old_scb;
1472 ldb_debug(ldb, LDB_DEBUG_ERROR,
1473 "setup_supplemental_field: "
1474 "supplementalCredentialsBlob signature[0x%04X] expected[0x%04X]",
1475 _old_scb.sub.signature, SUPPLEMENTAL_CREDENTIALS_SIGNATURE);
1478 /* Per MS-SAMR 3.1.1.8.11.6 we create AES keys if our domain functionality level is 2008 or higher */
1479 do_newer_keys = (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008);
1481 if (io->ac->status->domain_data.store_cleartext &&
1482 (io->u.userAccountControl & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) {
1483 do_cleartext = true;
1487 * The ordering is this
1489 * Primary:Kerberos-Newer-Keys (optional)
1492 * Primary:CLEARTEXT (optional)
1494 * And the 'Packages' package is insert before the last
1497 if (do_newer_keys) {
1498 /* Primary:Kerberos-Newer-Keys */
1499 nkn = &names[num_names++];
1500 pkn = &packages[num_packages++];
1503 /* Primary:Kerberos */
1504 nk = &names[num_names++];
1505 pk = &packages[num_packages++];
1507 if (!do_cleartext) {
1509 pp = &packages[num_packages++];
1512 /* Primary:WDigest */
1513 nd = &names[num_names++];
1514 pd = &packages[num_packages++];
1518 pp = &packages[num_packages++];
1520 /* Primary:CLEARTEXT */
1521 nc = &names[num_names++];
1522 pc = &packages[num_packages++];
1527 * setup 'Primary:Kerberos-Newer-Keys' element
1529 *nkn = "Kerberos-Newer-Keys";
1531 ret = setup_primary_kerberos_newer(io, old_scb, &pknb);
1532 if (ret != LDB_SUCCESS) {
1536 ndr_err = ndr_push_struct_blob(&pknb_blob, io->ac,
1538 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1539 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1540 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1541 ldb_asprintf_errstring(ldb,
1542 "setup_supplemental_field: "
1543 "failed to push package_PrimaryKerberosNeverBlob: %s",
1545 return LDB_ERR_OPERATIONS_ERROR;
1547 pknb_hexstr = data_blob_hex_string_upper(io->ac, &pknb_blob);
1549 return ldb_oom(ldb);
1551 pkn->name = "Primary:Kerberos-Newer-Keys";
1553 pkn->data = pknb_hexstr;
1557 * setup 'Primary:Kerberos' element
1561 ret = setup_primary_kerberos(io, old_scb, &pkb);
1562 if (ret != LDB_SUCCESS) {
1566 ndr_err = ndr_push_struct_blob(&pkb_blob, io->ac,
1568 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1569 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1570 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1571 ldb_asprintf_errstring(ldb,
1572 "setup_supplemental_field: "
1573 "failed to push package_PrimaryKerberosBlob: %s",
1575 return LDB_ERR_OPERATIONS_ERROR;
1577 pkb_hexstr = data_blob_hex_string_upper(io->ac, &pkb_blob);
1579 return ldb_oom(ldb);
1581 pk->name = "Primary:Kerberos";
1583 pk->data = pkb_hexstr;
1586 * setup 'Primary:WDigest' element
1590 ret = setup_primary_wdigest(io, old_scb, &pdb);
1591 if (ret != LDB_SUCCESS) {
1595 ndr_err = ndr_push_struct_blob(&pdb_blob, io->ac,
1597 (ndr_push_flags_fn_t)ndr_push_package_PrimaryWDigestBlob);
1598 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1599 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1600 ldb_asprintf_errstring(ldb,
1601 "setup_supplemental_field: "
1602 "failed to push package_PrimaryWDigestBlob: %s",
1604 return LDB_ERR_OPERATIONS_ERROR;
1606 pdb_hexstr = data_blob_hex_string_upper(io->ac, &pdb_blob);
1608 return ldb_oom(ldb);
1610 pd->name = "Primary:WDigest";
1612 pd->data = pdb_hexstr;
1615 * setup 'Primary:CLEARTEXT' element
1620 pcb.cleartext = *io->n.cleartext_utf16;
1622 ndr_err = ndr_push_struct_blob(&pcb_blob, io->ac,
1624 (ndr_push_flags_fn_t)ndr_push_package_PrimaryCLEARTEXTBlob);
1625 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1626 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1627 ldb_asprintf_errstring(ldb,
1628 "setup_supplemental_field: "
1629 "failed to push package_PrimaryCLEARTEXTBlob: %s",
1631 return LDB_ERR_OPERATIONS_ERROR;
1633 pcb_hexstr = data_blob_hex_string_upper(io->ac, &pcb_blob);
1635 return ldb_oom(ldb);
1637 pc->name = "Primary:CLEARTEXT";
1639 pc->data = pcb_hexstr;
1643 * setup 'Packages' element
1646 ndr_err = ndr_push_struct_blob(&pb_blob, io->ac,
1648 (ndr_push_flags_fn_t)ndr_push_package_PackagesBlob);
1649 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1650 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1651 ldb_asprintf_errstring(ldb,
1652 "setup_supplemental_field: "
1653 "failed to push package_PackagesBlob: %s",
1655 return LDB_ERR_OPERATIONS_ERROR;
1657 pb_hexstr = data_blob_hex_string_upper(io->ac, &pb_blob);
1659 return ldb_oom(ldb);
1661 pp->name = "Packages";
1663 pp->data = pb_hexstr;
1666 * setup 'supplementalCredentials' value
1669 scb.sub.num_packages = num_packages;
1670 scb.sub.packages = packages;
1672 ndr_err = ndr_push_struct_blob(&io->g.supplemental, io->ac,
1674 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
1675 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1676 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1677 ldb_asprintf_errstring(ldb,
1678 "setup_supplemental_field: "
1679 "failed to push supplementalCredentialsBlob: %s",
1681 return LDB_ERR_OPERATIONS_ERROR;
1687 static int setup_last_set_field(struct setup_password_fields_io *io)
1689 const struct ldb_message *msg = NULL;
1690 struct timeval tv = { .tv_sec = 0 };
1692 switch (io->ac->req->operation) {
1694 msg = io->ac->req->op.add.message;
1697 msg = io->ac->req->op.mod.message;
1700 return LDB_ERR_OPERATIONS_ERROR;
1704 if (io->ac->pwd_last_set_bypass) {
1705 struct ldb_message_element *el;
1708 return LDB_ERR_CONSTRAINT_VIOLATION;
1711 el = ldb_msg_find_element(msg, "pwdLastSet");
1713 return LDB_ERR_CONSTRAINT_VIOLATION;
1716 io->g.last_set = samdb_result_nttime(msg, "pwdLastSet", 0);
1722 io->g.last_set = timeval_to_nttime(&tv);
1727 static int setup_given_passwords(struct setup_password_fields_io *io,
1728 struct setup_password_fields_given *g)
1730 struct ldb_context *ldb;
1733 ldb = ldb_module_get_ctx(io->ac->module);
1735 if (g->cleartext_utf8) {
1736 struct ldb_val *cleartext_utf16_blob;
1738 cleartext_utf16_blob = talloc(io->ac, struct ldb_val);
1739 if (!cleartext_utf16_blob) {
1740 return ldb_oom(ldb);
1742 if (!convert_string_talloc(io->ac,
1744 g->cleartext_utf8->data,
1745 g->cleartext_utf8->length,
1746 (void *)&cleartext_utf16_blob->data,
1747 &cleartext_utf16_blob->length)) {
1748 if (g->cleartext_utf8->length != 0) {
1749 talloc_free(cleartext_utf16_blob);
1750 ldb_asprintf_errstring(ldb,
1751 "setup_password_fields: "
1752 "failed to generate UTF16 password from cleartext UTF8 one for user '%s'!",
1753 io->u.sAMAccountName);
1754 return LDB_ERR_CONSTRAINT_VIOLATION;
1756 /* passwords with length "0" are valid! */
1757 cleartext_utf16_blob->data = NULL;
1758 cleartext_utf16_blob->length = 0;
1761 g->cleartext_utf16 = cleartext_utf16_blob;
1762 } else if (g->cleartext_utf16) {
1763 struct ldb_val *cleartext_utf8_blob;
1765 cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
1766 if (!cleartext_utf8_blob) {
1767 return ldb_oom(ldb);
1769 if (!convert_string_talloc(io->ac,
1770 CH_UTF16MUNGED, CH_UTF8,
1771 g->cleartext_utf16->data,
1772 g->cleartext_utf16->length,
1773 (void *)&cleartext_utf8_blob->data,
1774 &cleartext_utf8_blob->length)) {
1775 if (g->cleartext_utf16->length != 0) {
1776 /* We must bail out here, the input wasn't even
1777 * a multiple of 2 bytes */
1778 talloc_free(cleartext_utf8_blob);
1779 ldb_asprintf_errstring(ldb,
1780 "setup_password_fields: "
1781 "failed to generate UTF8 password from cleartext UTF 16 one for user '%s' - the latter had odd length (length must be a multiple of 2)!",
1782 io->u.sAMAccountName);
1783 return LDB_ERR_CONSTRAINT_VIOLATION;
1785 /* passwords with length "0" are valid! */
1786 cleartext_utf8_blob->data = NULL;
1787 cleartext_utf8_blob->length = 0;
1790 g->cleartext_utf8 = cleartext_utf8_blob;
1793 if (g->cleartext_utf16) {
1794 struct samr_Password *nt_hash;
1796 nt_hash = talloc(io->ac, struct samr_Password);
1798 return ldb_oom(ldb);
1800 g->nt_hash = nt_hash;
1802 /* compute the new nt hash */
1803 mdfour(nt_hash->hash,
1804 g->cleartext_utf16->data,
1805 g->cleartext_utf16->length);
1808 if (g->cleartext_utf8) {
1809 struct samr_Password *lm_hash;
1811 lm_hash = talloc(io->ac, struct samr_Password);
1813 return ldb_oom(ldb);
1816 /* compute the new lm hash */
1817 ok = E_deshash((char *)g->cleartext_utf8->data, lm_hash->hash);
1819 g->lm_hash = lm_hash;
1821 talloc_free(lm_hash);
1828 static int setup_password_fields(struct setup_password_fields_io *io)
1830 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1831 struct loadparm_context *lp_ctx =
1832 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
1833 struct loadparm_context);
1836 /* transform the old password (for password changes) */
1837 ret = setup_given_passwords(io, &io->og);
1838 if (ret != LDB_SUCCESS) {
1842 /* transform the new password */
1843 ret = setup_given_passwords(io, &io->n);
1844 if (ret != LDB_SUCCESS) {
1848 if (io->n.cleartext_utf8) {
1849 ret = setup_kerberos_keys(io);
1850 if (ret != LDB_SUCCESS) {
1855 ret = setup_nt_fields(io);
1856 if (ret != LDB_SUCCESS) {
1860 if (lpcfg_lanman_auth(lp_ctx)) {
1861 ret = setup_lm_fields(io);
1862 if (ret != LDB_SUCCESS) {
1866 io->g.lm_hash = NULL;
1867 io->g.lm_history_len = 0;
1870 ret = setup_supplemental_field(io);
1871 if (ret != LDB_SUCCESS) {
1875 ret = setup_last_set_field(io);
1876 if (ret != LDB_SUCCESS) {
1883 static int make_error_and_update_badPwdCount(struct setup_password_fields_io *io)
1885 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1886 struct ldb_message *mod_msg = NULL;
1890 status = dsdb_update_bad_pwd_count(io->ac, ldb,
1891 io->ac->search_res->message,
1892 io->ac->dom_res->message,
1894 if (!NT_STATUS_IS_OK(status)) {
1898 if (mod_msg == NULL) {
1903 * OK, horrible semantics ahead.
1905 * - We need to abort any existing transaction
1906 * - create a transaction arround the badPwdCount update
1907 * - re-open the transaction so the upper layer
1908 * doesn't know what happened.
1910 * This is needed because returning an error to the upper
1911 * layer will cancel the transaction and undo the badPwdCount
1916 * Checking errors here is a bit pointless.
1917 * What can we do if we can't end the transaction?
1919 ret = ldb_next_del_trans(io->ac->module);
1920 if (ret != LDB_SUCCESS) {
1921 ldb_debug(ldb, LDB_DEBUG_FATAL,
1922 "Failed to abort transaction prior to update of badPwdCount of %s: %s",
1923 ldb_dn_get_linearized(io->ac->search_res->message->dn),
1924 ldb_errstring(ldb));
1926 * just return the original error
1931 /* Likewise, what should we do if we can't open a new transaction? */
1932 ret = ldb_next_start_trans(io->ac->module);
1933 if (ret != LDB_SUCCESS) {
1934 ldb_debug(ldb, LDB_DEBUG_ERROR,
1935 "Failed to open transaction to update badPwdCount of %s: %s",
1936 ldb_dn_get_linearized(io->ac->search_res->message->dn),
1937 ldb_errstring(ldb));
1939 * just return the original error
1944 ret = dsdb_module_modify(io->ac->module, mod_msg,
1945 DSDB_FLAG_NEXT_MODULE,
1947 if (ret != LDB_SUCCESS) {
1948 ldb_debug(ldb, LDB_DEBUG_ERROR,
1949 "Failed to update badPwdCount of %s: %s",
1950 ldb_dn_get_linearized(io->ac->search_res->message->dn),
1951 ldb_errstring(ldb));
1953 * We can only ignore this...
1957 ret = ldb_next_end_trans(io->ac->module);
1958 if (ret != LDB_SUCCESS) {
1959 ldb_debug(ldb, LDB_DEBUG_ERROR,
1960 "Failed to close transaction to update badPwdCount of %s: %s",
1961 ldb_dn_get_linearized(io->ac->search_res->message->dn),
1962 ldb_errstring(ldb));
1964 * We can only ignore this...
1968 ret = ldb_next_start_trans(io->ac->module);
1969 if (ret != LDB_SUCCESS) {
1970 ldb_debug(ldb, LDB_DEBUG_ERROR,
1971 "Failed to open transaction after update of badPwdCount of %s: %s",
1972 ldb_dn_get_linearized(io->ac->search_res->message->dn),
1973 ldb_errstring(ldb));
1975 * We can only ignore this...
1980 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1981 ldb_asprintf_errstring(ldb,
1982 "%08X: %s - check_password_restrictions: "
1983 "The old password specified doesn't match!",
1984 W_ERROR_V(WERR_INVALID_PASSWORD),
1989 static int check_password_restrictions(struct setup_password_fields_io *io)
1991 struct ldb_context *ldb;
1994 ldb = ldb_module_get_ctx(io->ac->module);
1996 /* First check the old password is correct, for password changes */
1997 if (!io->ac->pwd_reset) {
1998 bool nt_hash_checked = false;
2000 /* we need the old nt or lm hash given by the client */
2001 if (!io->og.nt_hash && !io->og.lm_hash) {
2002 ldb_asprintf_errstring(ldb,
2003 "check_password_restrictions: "
2004 "You need to provide the old password in order "
2006 return LDB_ERR_UNWILLING_TO_PERFORM;
2009 /* The password modify through the NT hash is encouraged and
2010 has no problems at all */
2011 if (io->og.nt_hash) {
2012 if (!io->o.nt_hash || memcmp(io->og.nt_hash->hash, io->o.nt_hash->hash, 16) != 0) {
2013 return make_error_and_update_badPwdCount(io);
2016 nt_hash_checked = true;
2019 /* But it is also possible to change a password by the LM hash
2020 * alone for compatibility reasons. This check is optional if
2021 * the NT hash was already checked - otherwise it's mandatory.
2022 * (as the SAMR operations request it). */
2023 if (io->og.lm_hash) {
2024 if ((!io->o.lm_hash && !nt_hash_checked)
2025 || (io->o.lm_hash && memcmp(io->og.lm_hash->hash, io->o.lm_hash->hash, 16) != 0)) {
2026 return make_error_and_update_badPwdCount(io);
2031 if (io->u.restrictions == 0) {
2032 /* FIXME: Is this right? */
2036 /* Password minimum age: yes, this is a minus. The ages are in negative 100nsec units! */
2037 if ((io->u.pwdLastSet - io->ac->status->domain_data.minPwdAge > io->g.last_set) &&
2040 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2041 ldb_asprintf_errstring(ldb,
2042 "%08X: %s - check_password_restrictions: "
2043 "password is too young to change!",
2044 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2050 * Fundamental password checks done by the call
2051 * "samdb_check_password".
2052 * It is also in use by "dcesrv_samr_ValidatePassword".
2054 if (io->n.cleartext_utf8 != NULL) {
2055 enum samr_ValidationStatus vstat;
2056 vstat = samdb_check_password(io->n.cleartext_utf8,
2057 io->ac->status->domain_data.pwdProperties,
2058 io->ac->status->domain_data.minPwdLength);
2060 case SAMR_VALIDATION_STATUS_SUCCESS:
2061 /* perfect -> proceed! */
2064 case SAMR_VALIDATION_STATUS_PWD_TOO_SHORT:
2065 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2066 ldb_asprintf_errstring(ldb,
2067 "%08X: %s - check_password_restrictions: "
2068 "the password is too short. It should be equal or longer than %u characters!",
2069 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2071 io->ac->status->domain_data.minPwdLength);
2072 io->ac->status->reject_reason = SAM_PWD_CHANGE_PASSWORD_TOO_SHORT;
2075 case SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH:
2076 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2077 ldb_asprintf_errstring(ldb,
2078 "%08X: %s - check_password_restrictions: "
2079 "the password does not meet the complexity criteria!",
2080 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2082 io->ac->status->reject_reason = SAM_PWD_CHANGE_NOT_COMPLEX;
2086 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2087 ldb_asprintf_errstring(ldb,
2088 "%08X: %s - check_password_restrictions: "
2089 "the password doesn't fit by a certain reason!",
2090 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2096 if (io->ac->pwd_reset) {
2100 if (io->n.nt_hash) {
2103 /* checks the NT hash password history */
2104 for (i = 0; i < io->o.nt_history_len; i++) {
2105 ret = memcmp(io->n.nt_hash, io->o.nt_history[i].hash, 16);
2107 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2108 ldb_asprintf_errstring(ldb,
2109 "%08X: %s - check_password_restrictions: "
2110 "the password was already used (in history)!",
2111 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2113 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
2119 if (io->n.lm_hash) {
2122 /* checks the LM hash password history */
2123 for (i = 0; i < io->o.lm_history_len; i++) {
2124 ret = memcmp(io->n.lm_hash, io->o.lm_history[i].hash, 16);
2126 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2127 ldb_asprintf_errstring(ldb,
2128 "%08X: %s - check_password_restrictions: "
2129 "the password was already used (in history)!",
2130 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2132 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
2138 /* are all password changes disallowed? */
2139 if (io->ac->status->domain_data.pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
2140 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2141 ldb_asprintf_errstring(ldb,
2142 "%08X: %s - check_password_restrictions: "
2143 "password changes disabled!",
2144 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2149 /* can this user change the password? */
2150 if (io->u.userAccountControl & UF_PASSWD_CANT_CHANGE) {
2151 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2152 ldb_asprintf_errstring(ldb,
2153 "%08X: %s - check_password_restrictions: "
2154 "password can't be changed on this account!",
2155 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2163 static int update_final_msg(struct setup_password_fields_io *io,
2164 struct ldb_message *msg)
2166 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2169 if (io->g.nt_hash != NULL) {
2170 ret = samdb_msg_add_hash(ldb, io->ac, msg,
2173 if (ret != LDB_SUCCESS) {
2177 if (io->g.lm_hash != NULL) {
2178 ret = samdb_msg_add_hash(ldb, io->ac, msg,
2181 if (ret != LDB_SUCCESS) {
2185 if (io->g.nt_history_len > 0) {
2186 ret = samdb_msg_add_hashes(ldb, io->ac, msg,
2189 io->g.nt_history_len);
2190 if (ret != LDB_SUCCESS) {
2194 if (io->g.lm_history_len > 0) {
2195 ret = samdb_msg_add_hashes(ldb, io->ac, msg,
2198 io->g.lm_history_len);
2199 if (ret != LDB_SUCCESS) {
2203 if (io->g.supplemental.length > 0) {
2204 ret = ldb_msg_add_value(msg, "supplementalCredentials",
2205 &io->g.supplemental, NULL);
2206 if (ret != LDB_SUCCESS) {
2210 ret = samdb_msg_add_uint64(ldb, io->ac, msg,
2213 if (ret != LDB_SUCCESS) {
2221 * This is intended for use by the "password_hash" module since there
2222 * password changes can be specified through one message element with the
2223 * new password (to set) and another one with the old password (to unset).
2225 * The first which sets a password (new value) can have flags
2226 * (LDB_FLAG_MOD_ADD, LDB_FLAG_MOD_REPLACE) but also none (on "add" operations
2227 * for entries). The latter (old value) has always specified
2228 * LDB_FLAG_MOD_DELETE.
2230 * Returns LDB_ERR_CONSTRAINT_VIOLATION and LDB_ERR_UNWILLING_TO_PERFORM if
2231 * matching message elements are malformed in respect to the set/change rules.
2232 * Otherwise it returns LDB_SUCCESS.
2234 static int msg_find_old_and_new_pwd_val(const struct ldb_message *msg,
2236 enum ldb_request_type operation,
2237 const struct ldb_val **new_val,
2238 const struct ldb_val **old_val)
2249 for (i = 0; i < msg->num_elements; i++) {
2250 if (ldb_attr_cmp(msg->elements[i].name, name) != 0) {
2254 if ((operation == LDB_MODIFY) &&
2255 (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_DELETE)) {
2256 /* 0 values are allowed */
2257 if (msg->elements[i].num_values == 1) {
2258 *old_val = &msg->elements[i].values[0];
2259 } else if (msg->elements[i].num_values > 1) {
2260 return LDB_ERR_CONSTRAINT_VIOLATION;
2262 } else if ((operation == LDB_MODIFY) &&
2263 (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_REPLACE)) {
2264 if (msg->elements[i].num_values > 0) {
2265 *new_val = &msg->elements[i].values[msg->elements[i].num_values - 1];
2267 return LDB_ERR_UNWILLING_TO_PERFORM;
2270 /* Add operations and LDB_FLAG_MOD_ADD */
2271 if (msg->elements[i].num_values > 0) {
2272 *new_val = &msg->elements[i].values[msg->elements[i].num_values - 1];
2274 return LDB_ERR_CONSTRAINT_VIOLATION;
2282 static int setup_io(struct ph_context *ac,
2283 const struct ldb_message *client_msg,
2284 const struct ldb_message *existing_msg,
2285 struct setup_password_fields_io *io)
2287 const struct ldb_val *quoted_utf16, *old_quoted_utf16, *lm_hash, *old_lm_hash;
2288 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2289 struct loadparm_context *lp_ctx = talloc_get_type(
2290 ldb_get_opaque(ldb, "loadparm"), struct loadparm_context);
2292 const struct ldb_message *info_msg = NULL;
2296 /* Some operations below require kerberos contexts */
2298 if (existing_msg != NULL) {
2300 * This is a modify operation
2302 info_msg = existing_msg;
2305 * This is an add operation
2307 info_msg = client_msg;
2310 if (smb_krb5_init_context(ac,
2311 (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"),
2312 &io->smb_krb5_context) != 0) {
2313 return ldb_operr(ldb);
2318 io->u.userAccountControl = ldb_msg_find_attr_as_uint(info_msg,
2319 "userAccountControl", 0);
2320 io->u.pwdLastSet = samdb_result_nttime(info_msg, "pwdLastSet", 0);
2321 io->u.sAMAccountName = ldb_msg_find_attr_as_string(info_msg,
2322 "sAMAccountName", NULL);
2323 io->u.user_principal_name = ldb_msg_find_attr_as_string(info_msg,
2324 "userPrincipalName", NULL);
2325 io->u.is_computer = ldb_msg_check_string_attribute(info_msg, "objectClass", "computer");
2327 if (io->u.sAMAccountName == NULL) {
2328 ldb_asprintf_errstring(ldb,
2329 "setup_io: sAMAccountName attribute is missing on %s for attempted password set/change",
2330 ldb_dn_get_linearized(info_msg->dn));
2332 return LDB_ERR_CONSTRAINT_VIOLATION;
2335 if (io->u.userAccountControl & UF_INTERDOMAIN_TRUST_ACCOUNT) {
2336 struct ldb_control *permit_trust = ldb_request_get_control(ac->req,
2337 DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID);
2339 if (permit_trust == NULL) {
2340 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2341 ldb_asprintf_errstring(ldb,
2342 "%08X: %s - setup_io: changing the interdomain trust password "
2343 "on %s not allowed via LDAP. Use LSA or NETLOGON",
2344 W_ERROR_V(WERR_ACCESS_DENIED),
2346 ldb_dn_get_linearized(info_msg->dn));
2351 /* Only non-trust accounts have restrictions (possibly this test is the
2352 * wrong way around, but we like to be restrictive if possible */
2353 io->u.restrictions = !(io->u.userAccountControl
2354 & (UF_INTERDOMAIN_TRUST_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT
2355 | UF_SERVER_TRUST_ACCOUNT));
2357 if (ac->userPassword) {
2358 ret = msg_find_old_and_new_pwd_val(client_msg, "userPassword",
2360 &io->n.cleartext_utf8,
2361 &io->og.cleartext_utf8);
2362 if (ret != LDB_SUCCESS) {
2363 ldb_asprintf_errstring(ldb,
2365 "it's only allowed to set the old password once!");
2370 if (io->n.cleartext_utf8 != NULL) {
2371 struct ldb_val *cleartext_utf8_blob;
2374 cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
2375 if (!cleartext_utf8_blob) {
2376 return ldb_oom(ldb);
2379 *cleartext_utf8_blob = *io->n.cleartext_utf8;
2381 /* make sure we have a null terminated string */
2382 p = talloc_strndup(cleartext_utf8_blob,
2383 (const char *)io->n.cleartext_utf8->data,
2384 io->n.cleartext_utf8->length);
2385 if ((p == NULL) && (io->n.cleartext_utf8->length > 0)) {
2386 return ldb_oom(ldb);
2388 cleartext_utf8_blob->data = (uint8_t *)p;
2390 io->n.cleartext_utf8 = cleartext_utf8_blob;
2393 ret = msg_find_old_and_new_pwd_val(client_msg, "clearTextPassword",
2395 &io->n.cleartext_utf16,
2396 &io->og.cleartext_utf16);
2397 if (ret != LDB_SUCCESS) {
2398 ldb_asprintf_errstring(ldb,
2400 "it's only allowed to set the old password once!");
2404 /* this rather strange looking piece of code is there to
2405 handle a ldap client setting a password remotely using the
2406 unicodePwd ldap field. The syntax is that the password is
2407 in UTF-16LE, with a " at either end. Unfortunately the
2408 unicodePwd field is also used to store the nt hashes
2409 internally in Samba, and is used in the nt hash format on
2410 the wire in DRS replication, so we have a single name for
2411 two distinct values. The code below leaves us with a small
2412 chance (less than 1 in 2^32) of a mixup, if someone manages
2413 to create a MD4 hash which starts and ends in 0x22 0x00, as
2414 that would then be treated as a UTF16 password rather than
2417 ret = msg_find_old_and_new_pwd_val(client_msg, "unicodePwd",
2421 if (ret != LDB_SUCCESS) {
2422 ldb_asprintf_errstring(ldb,
2424 "it's only allowed to set the old password once!");
2428 /* Checks and converts the actual "unicodePwd" attribute */
2429 if (!ac->hash_values &&
2431 quoted_utf16->length >= 4 &&
2432 quoted_utf16->data[0] == '"' &&
2433 quoted_utf16->data[1] == 0 &&
2434 quoted_utf16->data[quoted_utf16->length-2] == '"' &&
2435 quoted_utf16->data[quoted_utf16->length-1] == 0) {
2436 struct ldb_val *quoted_utf16_2;
2438 if (io->n.cleartext_utf16) {
2439 /* refuse the change if someone wants to change with
2440 with both UTF16 possibilities at the same time... */
2441 ldb_asprintf_errstring(ldb,
2443 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
2444 return LDB_ERR_UNWILLING_TO_PERFORM;
2448 * adapt the quoted UTF16 string to be a real
2451 quoted_utf16_2 = talloc(io->ac, struct ldb_val);
2452 if (quoted_utf16_2 == NULL) {
2453 return ldb_oom(ldb);
2456 quoted_utf16_2->data = quoted_utf16->data + 2;
2457 quoted_utf16_2->length = quoted_utf16->length-4;
2458 io->n.cleartext_utf16 = quoted_utf16_2;
2459 io->n.nt_hash = NULL;
2461 } else if (quoted_utf16) {
2462 /* We have only the hash available -> so no plaintext here */
2463 if (!ac->hash_values) {
2464 /* refuse the change if someone wants to change
2465 the hash without control specified... */
2466 ldb_asprintf_errstring(ldb,
2468 "it's not allowed to set the NT hash password directly'");
2469 /* this looks odd but this is what Windows does:
2470 returns "UNWILLING_TO_PERFORM" on wrong
2471 password sets and "CONSTRAINT_VIOLATION" on
2472 wrong password changes. */
2473 if (old_quoted_utf16 == NULL) {
2474 return LDB_ERR_UNWILLING_TO_PERFORM;
2477 return LDB_ERR_CONSTRAINT_VIOLATION;
2480 io->n.nt_hash = talloc(io->ac, struct samr_Password);
2481 memcpy(io->n.nt_hash->hash, quoted_utf16->data,
2482 MIN(quoted_utf16->length, sizeof(io->n.nt_hash->hash)));
2485 /* Checks and converts the previous "unicodePwd" attribute */
2486 if (!ac->hash_values &&
2488 old_quoted_utf16->length >= 4 &&
2489 old_quoted_utf16->data[0] == '"' &&
2490 old_quoted_utf16->data[1] == 0 &&
2491 old_quoted_utf16->data[old_quoted_utf16->length-2] == '"' &&
2492 old_quoted_utf16->data[old_quoted_utf16->length-1] == 0) {
2493 struct ldb_val *old_quoted_utf16_2;
2495 if (io->og.cleartext_utf16) {
2496 /* refuse the change if someone wants to change with
2497 both UTF16 possibilities at the same time... */
2498 ldb_asprintf_errstring(ldb,
2500 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
2501 return LDB_ERR_UNWILLING_TO_PERFORM;
2505 * adapt the quoted UTF16 string to be a real
2508 old_quoted_utf16_2 = talloc(io->ac, struct ldb_val);
2509 if (old_quoted_utf16_2 == NULL) {
2510 return ldb_oom(ldb);
2513 old_quoted_utf16_2->data = old_quoted_utf16->data + 2;
2514 old_quoted_utf16_2->length = old_quoted_utf16->length-4;
2516 io->og.cleartext_utf16 = old_quoted_utf16_2;
2517 io->og.nt_hash = NULL;
2518 } else if (old_quoted_utf16) {
2519 /* We have only the hash available -> so no plaintext here */
2520 if (!ac->hash_values) {
2521 /* refuse the change if someone wants to change
2522 the hash without control specified... */
2523 ldb_asprintf_errstring(ldb,
2525 "it's not allowed to set the NT hash password directly'");
2526 return LDB_ERR_UNWILLING_TO_PERFORM;
2529 io->og.nt_hash = talloc(io->ac, struct samr_Password);
2530 memcpy(io->og.nt_hash->hash, old_quoted_utf16->data,
2531 MIN(old_quoted_utf16->length, sizeof(io->og.nt_hash->hash)));
2534 /* Handles the "dBCSPwd" attribute (LM hash) */
2535 io->n.lm_hash = NULL; io->og.lm_hash = NULL;
2536 ret = msg_find_old_and_new_pwd_val(client_msg, "dBCSPwd",
2538 &lm_hash, &old_lm_hash);
2539 if (ret != LDB_SUCCESS) {
2540 ldb_asprintf_errstring(ldb,
2542 "it's only allowed to set the old password once!");
2546 if (((lm_hash != NULL) || (old_lm_hash != NULL)) && (!ac->hash_values)) {
2547 /* refuse the change if someone wants to change the hash
2548 without control specified... */
2549 ldb_asprintf_errstring(ldb,
2551 "it's not allowed to set the LM hash password directly'");
2552 return LDB_ERR_UNWILLING_TO_PERFORM;
2555 if (lpcfg_lanman_auth(lp_ctx) && (lm_hash != NULL)) {
2556 io->n.lm_hash = talloc(io->ac, struct samr_Password);
2557 memcpy(io->n.lm_hash->hash, lm_hash->data, MIN(lm_hash->length,
2558 sizeof(io->n.lm_hash->hash)));
2560 if (lpcfg_lanman_auth(lp_ctx) && (old_lm_hash != NULL)) {
2561 io->og.lm_hash = talloc(io->ac, struct samr_Password);
2562 memcpy(io->og.lm_hash->hash, old_lm_hash->data, MIN(old_lm_hash->length,
2563 sizeof(io->og.lm_hash->hash)));
2567 * Handles the password change control if it's specified. It has the
2568 * precedance and overrides already specified old password values of
2569 * change requests (but that shouldn't happen since the control is
2570 * fully internal and only used in conjunction with replace requests!).
2572 if (ac->change != NULL) {
2573 io->og.nt_hash = NULL;
2574 if (ac->change->old_nt_pwd_hash != NULL) {
2575 io->og.nt_hash = talloc_memdup(io->ac,
2576 ac->change->old_nt_pwd_hash,
2577 sizeof(struct samr_Password));
2579 io->og.lm_hash = NULL;
2580 if (lpcfg_lanman_auth(lp_ctx) && (ac->change->old_lm_pwd_hash != NULL)) {
2581 io->og.lm_hash = talloc_memdup(io->ac,
2582 ac->change->old_lm_pwd_hash,
2583 sizeof(struct samr_Password));
2587 /* refuse the change if someone wants to change the clear-
2588 text and supply his own hashes at the same time... */
2589 if ((io->n.cleartext_utf8 || io->n.cleartext_utf16)
2590 && (io->n.nt_hash || io->n.lm_hash)) {
2591 ldb_asprintf_errstring(ldb,
2593 "it's only allowed to set the password in form of cleartext attributes or as hashes");
2594 return LDB_ERR_UNWILLING_TO_PERFORM;
2597 /* refuse the change if someone wants to change the password
2598 using both plaintext methods (UTF8 and UTF16) at the same time... */
2599 if (io->n.cleartext_utf8 && io->n.cleartext_utf16) {
2600 ldb_asprintf_errstring(ldb,
2602 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
2603 return LDB_ERR_UNWILLING_TO_PERFORM;
2606 /* refuse the change if someone tries to set/change the password by
2607 * the lanman hash alone and we've deactivated that mechanism. This
2608 * would end in an account without any password! */
2609 if ((!io->n.cleartext_utf8) && (!io->n.cleartext_utf16)
2610 && (!io->n.nt_hash) && (!io->n.lm_hash)) {
2611 ldb_asprintf_errstring(ldb,
2613 "It's not possible to delete the password (changes using the LAN Manager hash alone could be deactivated)!");
2614 /* on "userPassword" and "clearTextPassword" we've to return
2615 * something different, since these are virtual attributes */
2616 if ((ldb_msg_find_element(client_msg, "userPassword") != NULL) ||
2617 (ldb_msg_find_element(client_msg, "clearTextPassword") != NULL)) {
2618 return LDB_ERR_CONSTRAINT_VIOLATION;
2620 return LDB_ERR_UNWILLING_TO_PERFORM;
2623 /* refuse the change if someone wants to compare against a plaintext
2624 or hash at the same time for a "password modify" operation... */
2625 if ((io->og.cleartext_utf8 || io->og.cleartext_utf16)
2626 && (io->og.nt_hash || io->og.lm_hash)) {
2627 ldb_asprintf_errstring(ldb,
2629 "it's only allowed to provide the old password in form of cleartext attributes or as hashes");
2630 return LDB_ERR_UNWILLING_TO_PERFORM;
2633 /* refuse the change if someone wants to compare against both
2634 * plaintexts at the same time for a "password modify" operation... */
2635 if (io->og.cleartext_utf8 && io->og.cleartext_utf16) {
2636 ldb_asprintf_errstring(ldb,
2638 "it's only allowed to provide the old cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
2639 return LDB_ERR_UNWILLING_TO_PERFORM;
2642 /* Decides if we have a password modify or password reset operation */
2643 if (ac->req->operation == LDB_ADD) {
2644 /* On "add" we have only "password reset" */
2645 ac->pwd_reset = true;
2646 } else if (ac->req->operation == LDB_MODIFY) {
2647 if (io->og.cleartext_utf8 || io->og.cleartext_utf16
2648 || io->og.nt_hash || io->og.lm_hash) {
2649 /* If we have an old password specified then for sure it
2650 * is a user "password change" */
2651 ac->pwd_reset = false;
2653 /* Otherwise we have also here a "password reset" */
2654 ac->pwd_reset = true;
2657 /* this shouldn't happen */
2658 return ldb_operr(ldb);
2664 static struct ph_context *ph_init_context(struct ldb_module *module,
2665 struct ldb_request *req,
2668 struct ldb_context *ldb;
2669 struct ph_context *ac;
2671 ldb = ldb_module_get_ctx(module);
2673 ac = talloc_zero(req, struct ph_context);
2675 ldb_set_errstring(ldb, "Out of Memory");
2679 ac->module = module;
2681 ac->userPassword = userPassword;
2686 static void ph_apply_controls(struct ph_context *ac)
2688 struct ldb_control *ctrl;
2690 ac->change_status = false;
2691 ctrl = ldb_request_get_control(ac->req,
2692 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID);
2694 ac->change_status = true;
2696 /* Mark the "change status" control as uncritical (done) */
2697 ctrl->critical = false;
2700 ac->hash_values = false;
2701 ctrl = ldb_request_get_control(ac->req,
2702 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID);
2704 ac->hash_values = true;
2706 /* Mark the "hash values" control as uncritical (done) */
2707 ctrl->critical = false;
2710 ctrl = ldb_request_get_control(ac->req,
2711 DSDB_CONTROL_PASSWORD_CHANGE_OID);
2713 ac->change = (struct dsdb_control_password_change *) ctrl->data;
2715 /* Mark the "change" control as uncritical (done) */
2716 ctrl->critical = false;
2719 ac->pwd_last_set_bypass = false;
2720 ctrl = ldb_request_get_control(ac->req,
2721 DSDB_CONTROL_PASSWORD_BYPASS_LAST_SET_OID);
2723 ac->pwd_last_set_bypass = true;
2725 /* Mark the "bypass pwdLastSet" control as uncritical (done) */
2726 ctrl->critical = false;
2730 static int ph_op_callback(struct ldb_request *req, struct ldb_reply *ares)
2732 struct ph_context *ac;
2734 ac = talloc_get_type(req->context, struct ph_context);
2737 return ldb_module_done(ac->req, NULL, NULL,
2738 LDB_ERR_OPERATIONS_ERROR);
2741 if (ares->type == LDB_REPLY_REFERRAL) {
2742 return ldb_module_send_referral(ac->req, ares->referral);
2745 if ((ares->error != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
2746 /* On success and trivial errors a status control is being
2747 * added (used for example by the "samdb_set_password" call) */
2748 ldb_reply_add_control(ares,
2749 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2754 if (ares->error != LDB_SUCCESS) {
2755 return ldb_module_done(ac->req, ares->controls,
2756 ares->response, ares->error);
2759 if (ares->type != LDB_REPLY_DONE) {
2761 return ldb_module_done(ac->req, NULL, NULL,
2762 LDB_ERR_OPERATIONS_ERROR);
2765 return ldb_module_done(ac->req, ares->controls,
2766 ares->response, ares->error);
2769 static int password_hash_add_do_add(struct ph_context *ac);
2770 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares);
2771 static int password_hash_mod_search_self(struct ph_context *ac);
2772 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares);
2773 static int password_hash_mod_do_mod(struct ph_context *ac);
2775 static int get_domain_data_callback(struct ldb_request *req,
2776 struct ldb_reply *ares)
2778 struct ldb_context *ldb;
2779 struct ph_context *ac;
2780 struct loadparm_context *lp_ctx;
2781 int ret = LDB_SUCCESS;
2783 ac = talloc_get_type(req->context, struct ph_context);
2784 ldb = ldb_module_get_ctx(ac->module);
2787 ret = LDB_ERR_OPERATIONS_ERROR;
2790 if (ares->error != LDB_SUCCESS) {
2791 return ldb_module_done(ac->req, ares->controls,
2792 ares->response, ares->error);
2795 switch (ares->type) {
2796 case LDB_REPLY_ENTRY:
2797 if (ac->status != NULL) {
2800 ldb_set_errstring(ldb, "Too many results");
2801 ret = LDB_ERR_OPERATIONS_ERROR;
2805 /* Setup the "status" structure (used as control later) */
2806 ac->status = talloc_zero(ac->req,
2807 struct dsdb_control_password_change_status);
2808 if (ac->status == NULL) {
2812 ret = LDB_ERR_OPERATIONS_ERROR;
2816 /* Setup the "domain data" structure */
2817 ac->status->domain_data.pwdProperties =
2818 ldb_msg_find_attr_as_uint(ares->message, "pwdProperties", -1);
2819 ac->status->domain_data.pwdHistoryLength =
2820 ldb_msg_find_attr_as_uint(ares->message, "pwdHistoryLength", -1);
2821 ac->status->domain_data.maxPwdAge =
2822 ldb_msg_find_attr_as_int64(ares->message, "maxPwdAge", -1);
2823 ac->status->domain_data.minPwdAge =
2824 ldb_msg_find_attr_as_int64(ares->message, "minPwdAge", -1);
2825 ac->status->domain_data.minPwdLength =
2826 ldb_msg_find_attr_as_uint(ares->message, "minPwdLength", -1);
2827 ac->status->domain_data.store_cleartext =
2828 ac->status->domain_data.pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
2830 /* For a domain DN, this puts things in dotted notation */
2831 /* For builtin domains, this will give details for the host,
2832 * but that doesn't really matter, as it's just used for salt
2833 * and kerberos principals, which don't exist here */
2835 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2836 struct loadparm_context);
2838 ac->status->domain_data.dns_domain = lpcfg_dnsdomain(lp_ctx);
2839 ac->status->domain_data.realm = lpcfg_realm(lp_ctx);
2840 ac->status->domain_data.netbios_domain = lpcfg_sam_name(lp_ctx);
2842 ac->status->reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2844 if (ac->dom_res != NULL) {
2847 ldb_set_errstring(ldb, "Too many results");
2848 ret = LDB_ERR_OPERATIONS_ERROR;
2852 ac->dom_res = talloc_steal(ac, ares);
2856 case LDB_REPLY_REFERRAL:
2862 case LDB_REPLY_DONE:
2864 /* call the next step */
2865 switch (ac->req->operation) {
2867 ret = password_hash_add_do_add(ac);
2871 ret = password_hash_mod_do_mod(ac);
2875 ret = LDB_ERR_OPERATIONS_ERROR;
2882 if (ret != LDB_SUCCESS) {
2883 struct ldb_reply *new_ares;
2885 new_ares = talloc_zero(ac->req, struct ldb_reply);
2886 if (new_ares == NULL) {
2888 return ldb_module_done(ac->req, NULL, NULL,
2889 LDB_ERR_OPERATIONS_ERROR);
2892 new_ares->error = ret;
2893 if ((ret != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
2894 /* On success and trivial errors a status control is being
2895 * added (used for example by the "samdb_set_password" call) */
2896 ldb_reply_add_control(new_ares,
2897 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2902 return ldb_module_done(ac->req, new_ares->controls,
2903 new_ares->response, new_ares->error);
2909 static int build_domain_data_request(struct ph_context *ac)
2911 /* attrs[] is returned from this function in
2912 ac->dom_req->op.search.attrs, so it must be static, as
2913 otherwise the compiler can put it on the stack */
2914 struct ldb_context *ldb;
2915 static const char * const attrs[] = { "pwdProperties",
2921 "lockOutObservationWindow",
2925 ldb = ldb_module_get_ctx(ac->module);
2927 ret = ldb_build_search_req(&ac->dom_req, ldb, ac,
2928 ldb_get_default_basedn(ldb),
2932 ac, get_domain_data_callback,
2934 LDB_REQ_SET_LOCATION(ac->dom_req);
2938 static int password_hash_needed(struct ldb_module *module,
2939 struct ldb_request *req,
2940 struct ph_context **_ac)
2942 struct ldb_context *ldb = ldb_module_get_ctx(module);
2943 const char *operation = NULL;
2944 const struct ldb_message *msg = NULL;
2945 struct ph_context *ac = NULL;
2946 const char *passwordAttrs[] = {
2948 "clearTextPassword",
2953 const char **a = NULL;
2954 unsigned int attr_cnt = 0;
2955 struct ldb_control *bypass = NULL;
2956 bool userPassword = dsdb_user_password_support(module, req, req);
2960 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_needed\n");
2962 switch (req->operation) {
2965 msg = req->op.add.message;
2968 operation = "modify";
2969 msg = req->op.mod.message;
2972 return ldb_next_request(module, req);
2975 if (ldb_dn_is_special(msg->dn)) { /* do not manipulate our control entries */
2976 return ldb_next_request(module, req);
2979 bypass = ldb_request_get_control(req,
2980 DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID);
2981 if (bypass != NULL) {
2982 /* Mark the "bypass" control as uncritical (done) */
2983 bypass->critical = false;
2984 ldb_debug(ldb, LDB_DEBUG_TRACE,
2985 "password_hash_needed(%s) (bypassing)\n",
2987 return password_hash_bypass(module, req);
2990 /* nobody must touch password histories and 'supplementalCredentials' */
2991 if (ldb_msg_find_element(msg, "ntPwdHistory")) {
2992 return LDB_ERR_UNWILLING_TO_PERFORM;
2994 if (ldb_msg_find_element(msg, "lmPwdHistory")) {
2995 return LDB_ERR_UNWILLING_TO_PERFORM;
2997 if (ldb_msg_find_element(msg, "supplementalCredentials")) {
2998 return LDB_ERR_UNWILLING_TO_PERFORM;
3002 * If no part of this touches the 'userPassword' OR 'clearTextPassword'
3003 * OR 'unicodePwd' OR 'dBCSPwd' we don't need to make any changes.
3004 * For password changes/set there should be a 'delete' or a 'modify'
3005 * on these attributes.
3007 for (a = passwordAttrs; *a != NULL; a++) {
3008 if ((!userPassword) && (ldb_attr_cmp(*a, "userPassword") == 0)) {
3012 if (ldb_msg_find_element(msg, *a) != NULL) {
3013 /* MS-ADTS 3.1.1.3.1.5.2 */
3014 if ((ldb_attr_cmp(*a, "userPassword") == 0) &&
3015 (dsdb_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
3016 return LDB_ERR_CONSTRAINT_VIOLATION;
3023 if (attr_cnt == 0) {
3024 return ldb_next_request(module, req);
3027 ac = ph_init_context(module, req, userPassword);
3029 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
3030 return ldb_operr(ldb);
3032 ph_apply_controls(ac);
3038 static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
3040 struct ldb_context *ldb = ldb_module_get_ctx(module);
3041 struct ph_context *ac = NULL;
3044 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add\n");
3046 ret = password_hash_needed(module, req, &ac);
3047 if (ret != LDB_SUCCESS) {
3054 /* Make sure we are performing the password set action on a (for us)
3055 * valid object. Those are instances of either "user" and/or
3056 * "inetOrgPerson". Otherwise continue with the submodules. */
3057 if ((!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "user"))
3058 && (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "inetOrgPerson"))) {
3062 if (ldb_msg_find_element(req->op.add.message, "clearTextPassword") != NULL) {
3063 ldb_set_errstring(ldb,
3064 "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
3065 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3068 return ldb_next_request(module, req);
3071 /* get user domain data */
3072 ret = build_domain_data_request(ac);
3073 if (ret != LDB_SUCCESS) {
3077 return ldb_next_request(module, ac->dom_req);
3080 static int password_hash_add_do_add(struct ph_context *ac)
3082 struct ldb_context *ldb;
3083 struct ldb_request *down_req;
3084 struct ldb_message *msg;
3085 struct setup_password_fields_io io;
3088 /* Prepare the internal data structure containing the passwords */
3089 ret = setup_io(ac, ac->req->op.add.message, NULL, &io);
3090 if (ret != LDB_SUCCESS) {
3094 ldb = ldb_module_get_ctx(ac->module);
3096 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
3098 return ldb_operr(ldb);
3101 /* remove attributes that we just read into 'io' */
3102 if (ac->userPassword) {
3103 ldb_msg_remove_attr(msg, "userPassword");
3105 ldb_msg_remove_attr(msg, "clearTextPassword");
3106 ldb_msg_remove_attr(msg, "unicodePwd");
3107 ldb_msg_remove_attr(msg, "dBCSPwd");
3108 ldb_msg_remove_attr(msg, "pwdLastSet");
3110 ret = setup_password_fields(&io);
3111 if (ret != LDB_SUCCESS) {
3115 ret = check_password_restrictions(&io);
3116 if (ret != LDB_SUCCESS) {
3120 ret = update_final_msg(&io, msg);
3121 if (ret != LDB_SUCCESS) {
3125 ret = ldb_build_add_req(&down_req, ldb, ac,
3130 LDB_REQ_SET_LOCATION(down_req);
3131 if (ret != LDB_SUCCESS) {
3135 return ldb_next_request(ac->module, down_req);
3138 static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
3140 struct ldb_context *ldb = ldb_module_get_ctx(module);
3141 struct ph_context *ac = NULL;
3142 const char *passwordAttrs[] = { "userPassword", "clearTextPassword",
3143 "unicodePwd", "dBCSPwd", NULL }, **l;
3144 unsigned int del_attr_cnt, add_attr_cnt, rep_attr_cnt;
3145 struct ldb_message_element *passwordAttr;
3146 struct ldb_message *msg;
3147 struct ldb_request *down_req;
3150 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
3152 ret = password_hash_needed(module, req, &ac);
3153 if (ret != LDB_SUCCESS) {
3160 /* use a new message structure so that we can modify it */
3161 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3163 return ldb_oom(ldb);
3166 /* - check for single-valued password attributes
3167 * (if not return "CONSTRAINT_VIOLATION")
3168 * - check that for a password change operation one add and one delete
3170 * (if not return "CONSTRAINT_VIOLATION" or "UNWILLING_TO_PERFORM")
3171 * - check that a password change and a password set operation cannot
3173 * (if not return "UNWILLING_TO_PERFORM")
3174 * - remove all password attributes modifications from the first change
3175 * operation (anything without the passwords) - we will make the real
3176 * modification later */
3180 for (l = passwordAttrs; *l != NULL; l++) {
3181 if ((!ac->userPassword) &&
3182 (ldb_attr_cmp(*l, "userPassword") == 0)) {
3186 while ((passwordAttr = ldb_msg_find_element(msg, *l)) != NULL) {
3187 if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_DELETE) {
3190 if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_ADD) {
3193 if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_REPLACE) {
3196 if ((passwordAttr->num_values != 1) &&
3197 (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_ADD)) {
3199 ldb_asprintf_errstring(ldb,
3200 "'%s' attribute must have exactly one value on add operations!",
3202 return LDB_ERR_CONSTRAINT_VIOLATION;
3204 if ((passwordAttr->num_values > 1) &&
3205 (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_DELETE)) {
3207 ldb_asprintf_errstring(ldb,
3208 "'%s' attribute must have zero or one value(s) on delete operations!",
3210 return LDB_ERR_CONSTRAINT_VIOLATION;
3212 ldb_msg_remove_element(msg, passwordAttr);
3215 if ((del_attr_cnt == 0) && (add_attr_cnt > 0)) {
3217 ldb_set_errstring(ldb,
3218 "Only the add action for a password change specified!");
3219 return LDB_ERR_UNWILLING_TO_PERFORM;
3221 if ((del_attr_cnt > 1) || (add_attr_cnt > 1)) {
3223 ldb_set_errstring(ldb,
3224 "Only one delete and one add action for a password change allowed!");
3225 return LDB_ERR_UNWILLING_TO_PERFORM;
3227 if ((rep_attr_cnt > 0) && ((del_attr_cnt > 0) || (add_attr_cnt > 0))) {
3229 ldb_set_errstring(ldb,
3230 "Either a password change or a password set operation is allowed!");
3231 return LDB_ERR_UNWILLING_TO_PERFORM;
3234 /* if there was nothing else to be modified skip to next step */
3235 if (msg->num_elements == 0) {
3236 return password_hash_mod_search_self(ac);
3239 ret = ldb_build_mod_req(&down_req, ldb, ac,
3242 ac, ph_modify_callback,
3244 LDB_REQ_SET_LOCATION(down_req);
3245 if (ret != LDB_SUCCESS) {
3249 return ldb_next_request(module, down_req);
3252 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
3254 struct ph_context *ac;
3256 ac = talloc_get_type(req->context, struct ph_context);
3259 return ldb_module_done(ac->req, NULL, NULL,
3260 LDB_ERR_OPERATIONS_ERROR);
3263 if (ares->type == LDB_REPLY_REFERRAL) {
3264 return ldb_module_send_referral(ac->req, ares->referral);
3267 if (ares->error != LDB_SUCCESS) {
3268 return ldb_module_done(ac->req, ares->controls,
3269 ares->response, ares->error);
3272 if (ares->type != LDB_REPLY_DONE) {
3274 return ldb_module_done(ac->req, NULL, NULL,
3275 LDB_ERR_OPERATIONS_ERROR);
3280 return password_hash_mod_search_self(ac);
3283 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
3285 struct ldb_context *ldb;
3286 struct ph_context *ac;
3287 int ret = LDB_SUCCESS;
3289 ac = talloc_get_type(req->context, struct ph_context);
3290 ldb = ldb_module_get_ctx(ac->module);
3293 ret = LDB_ERR_OPERATIONS_ERROR;
3296 if (ares->error != LDB_SUCCESS) {
3297 return ldb_module_done(ac->req, ares->controls,
3298 ares->response, ares->error);
3301 /* we are interested only in the single reply (base search) */
3302 switch (ares->type) {
3303 case LDB_REPLY_ENTRY:
3304 /* Make sure we are performing the password change action on a
3305 * (for us) valid object. Those are instances of either "user"
3306 * and/or "inetOrgPerson". Otherwise continue with the
3308 if ((!ldb_msg_check_string_attribute(ares->message, "objectClass", "user"))
3309 && (!ldb_msg_check_string_attribute(ares->message, "objectClass", "inetOrgPerson"))) {
3312 if (ldb_msg_find_element(ac->req->op.mod.message, "clearTextPassword") != NULL) {
3313 ldb_set_errstring(ldb,
3314 "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
3315 ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
3319 ret = ldb_next_request(ac->module, ac->req);
3323 if (ac->search_res != NULL) {
3326 ldb_set_errstring(ldb, "Too many results");
3327 ret = LDB_ERR_OPERATIONS_ERROR;
3331 ac->search_res = talloc_steal(ac, ares);
3335 case LDB_REPLY_REFERRAL:
3336 /* ignore anything else for now */
3341 case LDB_REPLY_DONE:
3344 /* get user domain data */
3345 ret = build_domain_data_request(ac);
3346 if (ret != LDB_SUCCESS) {
3347 return ldb_module_done(ac->req, NULL, NULL, ret);
3350 ret = ldb_next_request(ac->module, ac->dom_req);
3355 if (ret != LDB_SUCCESS) {
3356 return ldb_module_done(ac->req, NULL, NULL, ret);
3362 static int password_hash_mod_search_self(struct ph_context *ac)
3364 struct ldb_context *ldb;
3365 static const char * const attrs[] = { "objectClass",
3366 "userAccountControl",
3367 "msDS-User-Account-Control-Computed",
3371 "userPrincipalName",
3372 "supplementalCredentials",
3381 struct ldb_request *search_req;
3384 ldb = ldb_module_get_ctx(ac->module);
3386 ret = ldb_build_search_req(&search_req, ldb, ac,
3387 ac->req->op.mod.message->dn,
3392 ac, ph_mod_search_callback,
3394 LDB_REQ_SET_LOCATION(search_req);
3395 if (ret != LDB_SUCCESS) {
3399 return ldb_next_request(ac->module, search_req);
3402 static int password_hash_mod_do_mod(struct ph_context *ac)
3404 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3405 struct loadparm_context *lp_ctx =
3406 talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3407 struct loadparm_context);
3408 struct ldb_request *mod_req;
3409 struct ldb_message *msg;
3410 const struct ldb_message *searched_msg;
3411 struct setup_password_fields_io io;
3415 /* use a new message structure so that we can modify it */
3416 msg = ldb_msg_new(ac);
3418 return ldb_operr(ldb);
3422 msg->dn = ac->req->op.mod.message->dn;
3424 searched_msg = ac->search_res->message;
3426 /* Prepare the internal data structure containing the passwords */
3427 ret = setup_io(ac, ac->req->op.mod.message,
3428 ac->search_res->message, &io);
3429 if (ret != LDB_SUCCESS) {
3433 if (io.ac->pwd_reset) {
3434 /* Get the old password from the database */
3435 status = samdb_result_passwords_no_lockout(io.ac,
3437 discard_const_p(struct ldb_message, searched_msg),
3441 /* Get the old password from the database */
3442 status = samdb_result_passwords(io.ac,
3444 discard_const_p(struct ldb_message, searched_msg),
3445 &io.o.lm_hash, &io.o.nt_hash);
3448 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCOUNT_LOCKED_OUT)) {
3449 ldb_asprintf_errstring(ldb,
3450 "%08X: check_password: "
3451 "Password change not permitted, account locked out!",
3452 W_ERROR_V(WERR_ACCOUNT_LOCKED_OUT));
3453 return LDB_ERR_CONSTRAINT_VIOLATION;
3456 if (!NT_STATUS_IS_OK(status)) {
3458 * This only happens if the database has gone weird,
3459 * not if we are just missing the passwords
3461 return ldb_operr(ldb);
3464 io.o.nt_history_len = samdb_result_hashes(io.ac, searched_msg, "ntPwdHistory", &io.o.nt_history);
3465 io.o.lm_history_len = samdb_result_hashes(io.ac, searched_msg, "lmPwdHistory", &io.o.lm_history);
3466 io.o.supplemental = ldb_msg_find_ldb_val(searched_msg, "supplementalCredentials");
3468 ret = setup_password_fields(&io);
3469 if (ret != LDB_SUCCESS) {
3473 ret = check_password_restrictions(&io);
3474 if (ret != LDB_SUCCESS) {
3478 /* make sure we replace all the old attributes */
3479 ret = ldb_msg_add_empty(msg, "unicodePwd", LDB_FLAG_MOD_REPLACE, NULL);
3480 ret = ldb_msg_add_empty(msg, "dBCSPwd", LDB_FLAG_MOD_REPLACE, NULL);
3481 ret = ldb_msg_add_empty(msg, "ntPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
3482 ret = ldb_msg_add_empty(msg, "lmPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
3483 ret = ldb_msg_add_empty(msg, "supplementalCredentials", LDB_FLAG_MOD_REPLACE, NULL);
3484 ret = ldb_msg_add_empty(msg, "pwdLastSet", LDB_FLAG_MOD_REPLACE, NULL);
3486 ret = update_final_msg(&io, msg);
3487 if (ret != LDB_SUCCESS) {
3491 ret = ldb_build_mod_req(&mod_req, ldb, ac,
3496 LDB_REQ_SET_LOCATION(mod_req);
3497 if (ret != LDB_SUCCESS) {
3501 return ldb_next_request(ac->module, mod_req);
3504 static const struct ldb_module_ops ldb_password_hash_module_ops = {
3505 .name = "password_hash",
3506 .add = password_hash_add,
3507 .modify = password_hash_modify
3510 int ldb_password_hash_module_init(const char *version)
3512 LDB_MODULE_CHECK_VERSION(version);
3513 return ldb_register_module(&ldb_password_hash_module_ops);