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 = 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;
1691 switch (io->ac->req->operation) {
1693 msg = io->ac->req->op.add.message;
1696 msg = io->ac->req->op.mod.message;
1699 return LDB_ERR_OPERATIONS_ERROR;
1703 if (io->ac->pwd_last_set_bypass) {
1704 struct ldb_message_element *el;
1707 return LDB_ERR_CONSTRAINT_VIOLATION;
1710 el = ldb_msg_find_element(msg, "pwdLastSet");
1712 return LDB_ERR_CONSTRAINT_VIOLATION;
1715 io->g.last_set = samdb_result_nttime(msg, "pwdLastSet", 0);
1720 unix_to_nt_time(&io->g.last_set, time(NULL));
1725 static int setup_given_passwords(struct setup_password_fields_io *io,
1726 struct setup_password_fields_given *g)
1728 struct ldb_context *ldb;
1731 ldb = ldb_module_get_ctx(io->ac->module);
1733 if (g->cleartext_utf8) {
1734 struct ldb_val *cleartext_utf16_blob;
1736 cleartext_utf16_blob = talloc(io->ac, struct ldb_val);
1737 if (!cleartext_utf16_blob) {
1738 return ldb_oom(ldb);
1740 if (!convert_string_talloc(io->ac,
1742 g->cleartext_utf8->data,
1743 g->cleartext_utf8->length,
1744 (void *)&cleartext_utf16_blob->data,
1745 &cleartext_utf16_blob->length)) {
1746 if (g->cleartext_utf8->length != 0) {
1747 talloc_free(cleartext_utf16_blob);
1748 ldb_asprintf_errstring(ldb,
1749 "setup_password_fields: "
1750 "failed to generate UTF16 password from cleartext UTF8 one for user '%s'!",
1751 io->u.sAMAccountName);
1752 return LDB_ERR_CONSTRAINT_VIOLATION;
1754 /* passwords with length "0" are valid! */
1755 cleartext_utf16_blob->data = NULL;
1756 cleartext_utf16_blob->length = 0;
1759 g->cleartext_utf16 = cleartext_utf16_blob;
1760 } else if (g->cleartext_utf16) {
1761 struct ldb_val *cleartext_utf8_blob;
1763 cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
1764 if (!cleartext_utf8_blob) {
1765 return ldb_oom(ldb);
1767 if (!convert_string_talloc(io->ac,
1768 CH_UTF16MUNGED, CH_UTF8,
1769 g->cleartext_utf16->data,
1770 g->cleartext_utf16->length,
1771 (void *)&cleartext_utf8_blob->data,
1772 &cleartext_utf8_blob->length)) {
1773 if (g->cleartext_utf16->length != 0) {
1774 /* We must bail out here, the input wasn't even
1775 * a multiple of 2 bytes */
1776 talloc_free(cleartext_utf8_blob);
1777 ldb_asprintf_errstring(ldb,
1778 "setup_password_fields: "
1779 "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)!",
1780 io->u.sAMAccountName);
1781 return LDB_ERR_CONSTRAINT_VIOLATION;
1783 /* passwords with length "0" are valid! */
1784 cleartext_utf8_blob->data = NULL;
1785 cleartext_utf8_blob->length = 0;
1788 g->cleartext_utf8 = cleartext_utf8_blob;
1791 if (g->cleartext_utf16) {
1792 struct samr_Password *nt_hash;
1794 nt_hash = talloc(io->ac, struct samr_Password);
1796 return ldb_oom(ldb);
1798 g->nt_hash = nt_hash;
1800 /* compute the new nt hash */
1801 mdfour(nt_hash->hash,
1802 g->cleartext_utf16->data,
1803 g->cleartext_utf16->length);
1806 if (g->cleartext_utf8) {
1807 struct samr_Password *lm_hash;
1809 lm_hash = talloc(io->ac, struct samr_Password);
1811 return ldb_oom(ldb);
1814 /* compute the new lm hash */
1815 ok = E_deshash((char *)g->cleartext_utf8->data, lm_hash->hash);
1817 g->lm_hash = lm_hash;
1819 talloc_free(lm_hash);
1826 static int setup_password_fields(struct setup_password_fields_io *io)
1828 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1829 struct loadparm_context *lp_ctx =
1830 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
1831 struct loadparm_context);
1834 /* transform the old password (for password changes) */
1835 ret = setup_given_passwords(io, &io->og);
1836 if (ret != LDB_SUCCESS) {
1840 /* transform the new password */
1841 ret = setup_given_passwords(io, &io->n);
1842 if (ret != LDB_SUCCESS) {
1846 if (io->n.cleartext_utf8) {
1847 ret = setup_kerberos_keys(io);
1848 if (ret != LDB_SUCCESS) {
1853 ret = setup_nt_fields(io);
1854 if (ret != LDB_SUCCESS) {
1858 if (lpcfg_lanman_auth(lp_ctx)) {
1859 ret = setup_lm_fields(io);
1860 if (ret != LDB_SUCCESS) {
1864 io->g.lm_hash = NULL;
1865 io->g.lm_history_len = 0;
1868 ret = setup_supplemental_field(io);
1869 if (ret != LDB_SUCCESS) {
1873 ret = setup_last_set_field(io);
1874 if (ret != LDB_SUCCESS) {
1881 static int make_error_and_update_badPwdCount(struct setup_password_fields_io *io)
1883 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1884 struct ldb_message *mod_msg = NULL;
1888 status = dsdb_update_bad_pwd_count(io->ac, ldb,
1889 io->ac->search_res->message,
1890 io->ac->dom_res->message,
1892 if (!NT_STATUS_IS_OK(status)) {
1896 if (mod_msg == NULL) {
1901 * OK, horrible semantics ahead.
1903 * - We need to abort any existing transaction
1904 * - create a transaction arround the badPwdCount update
1905 * - re-open the transaction so the upper layer
1906 * doesn't know what happened.
1908 * This is needed because returning an error to the upper
1909 * layer will cancel the transaction and undo the badPwdCount
1914 * Checking errors here is a bit pointless.
1915 * What can we do if we can't end the transaction?
1917 ret = ldb_next_del_trans(io->ac->module);
1918 if (ret != LDB_SUCCESS) {
1919 ldb_debug(ldb, LDB_DEBUG_FATAL,
1920 "Failed to abort transaction prior to update of badPwdCount of %s: %s",
1921 ldb_dn_get_linearized(io->ac->search_res->message->dn),
1922 ldb_errstring(ldb));
1924 * just return the original error
1929 /* Likewise, what should we do if we can't open a new transaction? */
1930 ret = ldb_next_start_trans(io->ac->module);
1931 if (ret != LDB_SUCCESS) {
1932 ldb_debug(ldb, LDB_DEBUG_ERROR,
1933 "Failed to open transaction to update badPwdCount of %s: %s",
1934 ldb_dn_get_linearized(io->ac->search_res->message->dn),
1935 ldb_errstring(ldb));
1937 * just return the original error
1942 ret = dsdb_module_modify(io->ac->module, mod_msg,
1943 DSDB_FLAG_NEXT_MODULE,
1945 if (ret != LDB_SUCCESS) {
1946 ldb_debug(ldb, LDB_DEBUG_ERROR,
1947 "Failed to update badPwdCount of %s: %s",
1948 ldb_dn_get_linearized(io->ac->search_res->message->dn),
1949 ldb_errstring(ldb));
1951 * We can only ignore this...
1955 ret = ldb_next_end_trans(io->ac->module);
1956 if (ret != LDB_SUCCESS) {
1957 ldb_debug(ldb, LDB_DEBUG_ERROR,
1958 "Failed to close transaction to update badPwdCount of %s: %s",
1959 ldb_dn_get_linearized(io->ac->search_res->message->dn),
1960 ldb_errstring(ldb));
1962 * We can only ignore this...
1966 ret = ldb_next_start_trans(io->ac->module);
1967 if (ret != LDB_SUCCESS) {
1968 ldb_debug(ldb, LDB_DEBUG_ERROR,
1969 "Failed to open transaction after update of badPwdCount of %s: %s",
1970 ldb_dn_get_linearized(io->ac->search_res->message->dn),
1971 ldb_errstring(ldb));
1973 * We can only ignore this...
1978 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1979 ldb_asprintf_errstring(ldb,
1980 "%08X: %s - check_password_restrictions: "
1981 "The old password specified doesn't match!",
1982 W_ERROR_V(WERR_INVALID_PASSWORD),
1987 static int check_password_restrictions(struct setup_password_fields_io *io)
1989 struct ldb_context *ldb;
1992 ldb = ldb_module_get_ctx(io->ac->module);
1994 /* First check the old password is correct, for password changes */
1995 if (!io->ac->pwd_reset) {
1996 bool nt_hash_checked = false;
1998 /* we need the old nt or lm hash given by the client */
1999 if (!io->og.nt_hash && !io->og.lm_hash) {
2000 ldb_asprintf_errstring(ldb,
2001 "check_password_restrictions: "
2002 "You need to provide the old password in order "
2004 return LDB_ERR_UNWILLING_TO_PERFORM;
2007 /* The password modify through the NT hash is encouraged and
2008 has no problems at all */
2009 if (io->og.nt_hash) {
2010 if (!io->o.nt_hash || memcmp(io->og.nt_hash->hash, io->o.nt_hash->hash, 16) != 0) {
2011 return make_error_and_update_badPwdCount(io);
2014 nt_hash_checked = true;
2017 /* But it is also possible to change a password by the LM hash
2018 * alone for compatibility reasons. This check is optional if
2019 * the NT hash was already checked - otherwise it's mandatory.
2020 * (as the SAMR operations request it). */
2021 if (io->og.lm_hash) {
2022 if ((!io->o.lm_hash && !nt_hash_checked)
2023 || (io->o.lm_hash && memcmp(io->og.lm_hash->hash, io->o.lm_hash->hash, 16) != 0)) {
2024 return make_error_and_update_badPwdCount(io);
2029 if (io->u.restrictions == 0) {
2030 /* FIXME: Is this right? */
2034 /* Password minimum age: yes, this is a minus. The ages are in negative 100nsec units! */
2035 if ((io->u.pwdLastSet - io->ac->status->domain_data.minPwdAge > io->g.last_set) &&
2038 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2039 ldb_asprintf_errstring(ldb,
2040 "%08X: %s - check_password_restrictions: "
2041 "password is too young to change!",
2042 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2048 * Fundamental password checks done by the call
2049 * "samdb_check_password".
2050 * It is also in use by "dcesrv_samr_ValidatePassword".
2052 if (io->n.cleartext_utf8 != NULL) {
2053 enum samr_ValidationStatus vstat;
2054 vstat = samdb_check_password(io->n.cleartext_utf8,
2055 io->ac->status->domain_data.pwdProperties,
2056 io->ac->status->domain_data.minPwdLength);
2058 case SAMR_VALIDATION_STATUS_SUCCESS:
2059 /* perfect -> proceed! */
2062 case SAMR_VALIDATION_STATUS_PWD_TOO_SHORT:
2063 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2064 ldb_asprintf_errstring(ldb,
2065 "%08X: %s - check_password_restrictions: "
2066 "the password is too short. It should be equal or longer than %u characters!",
2067 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2069 io->ac->status->domain_data.minPwdLength);
2070 io->ac->status->reject_reason = SAM_PWD_CHANGE_PASSWORD_TOO_SHORT;
2073 case SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH:
2074 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2075 ldb_asprintf_errstring(ldb,
2076 "%08X: %s - check_password_restrictions: "
2077 "the password does not meet the complexity criteria!",
2078 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2080 io->ac->status->reject_reason = SAM_PWD_CHANGE_NOT_COMPLEX;
2084 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2085 ldb_asprintf_errstring(ldb,
2086 "%08X: %s - check_password_restrictions: "
2087 "the password doesn't fit by a certain reason!",
2088 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2094 if (io->ac->pwd_reset) {
2098 if (io->n.nt_hash) {
2101 /* checks the NT hash password history */
2102 for (i = 0; i < io->o.nt_history_len; i++) {
2103 ret = memcmp(io->n.nt_hash, io->o.nt_history[i].hash, 16);
2105 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2106 ldb_asprintf_errstring(ldb,
2107 "%08X: %s - check_password_restrictions: "
2108 "the password was already used (in history)!",
2109 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2111 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
2117 if (io->n.lm_hash) {
2120 /* checks the LM hash password history */
2121 for (i = 0; i < io->o.lm_history_len; i++) {
2122 ret = memcmp(io->n.lm_hash, io->o.lm_history[i].hash, 16);
2124 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2125 ldb_asprintf_errstring(ldb,
2126 "%08X: %s - check_password_restrictions: "
2127 "the password was already used (in history)!",
2128 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2130 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
2136 /* are all password changes disallowed? */
2137 if (io->ac->status->domain_data.pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
2138 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2139 ldb_asprintf_errstring(ldb,
2140 "%08X: %s - check_password_restrictions: "
2141 "password changes disabled!",
2142 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2147 /* can this user change the password? */
2148 if (io->u.userAccountControl & UF_PASSWD_CANT_CHANGE) {
2149 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2150 ldb_asprintf_errstring(ldb,
2151 "%08X: %s - check_password_restrictions: "
2152 "password can't be changed on this account!",
2153 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2162 * This is intended for use by the "password_hash" module since there
2163 * password changes can be specified through one message element with the
2164 * new password (to set) and another one with the old password (to unset).
2166 * The first which sets a password (new value) can have flags
2167 * (LDB_FLAG_MOD_ADD, LDB_FLAG_MOD_REPLACE) but also none (on "add" operations
2168 * for entries). The latter (old value) has always specified
2169 * LDB_FLAG_MOD_DELETE.
2171 * Returns LDB_ERR_CONSTRAINT_VIOLATION and LDB_ERR_UNWILLING_TO_PERFORM if
2172 * matching message elements are malformed in respect to the set/change rules.
2173 * Otherwise it returns LDB_SUCCESS.
2175 static int msg_find_old_and_new_pwd_val(const struct ldb_message *msg,
2177 enum ldb_request_type operation,
2178 const struct ldb_val **new_val,
2179 const struct ldb_val **old_val)
2190 for (i = 0; i < msg->num_elements; i++) {
2191 if (ldb_attr_cmp(msg->elements[i].name, name) != 0) {
2195 if ((operation == LDB_MODIFY) &&
2196 (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_DELETE)) {
2197 /* 0 values are allowed */
2198 if (msg->elements[i].num_values == 1) {
2199 *old_val = &msg->elements[i].values[0];
2200 } else if (msg->elements[i].num_values > 1) {
2201 return LDB_ERR_CONSTRAINT_VIOLATION;
2203 } else if ((operation == LDB_MODIFY) &&
2204 (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_REPLACE)) {
2205 if (msg->elements[i].num_values > 0) {
2206 *new_val = &msg->elements[i].values[msg->elements[i].num_values - 1];
2208 return LDB_ERR_UNWILLING_TO_PERFORM;
2211 /* Add operations and LDB_FLAG_MOD_ADD */
2212 if (msg->elements[i].num_values > 0) {
2213 *new_val = &msg->elements[i].values[msg->elements[i].num_values - 1];
2215 return LDB_ERR_CONSTRAINT_VIOLATION;
2223 static int setup_io(struct ph_context *ac,
2224 const struct ldb_message *orig_msg,
2225 const struct ldb_message *searched_msg,
2226 struct setup_password_fields_io *io)
2228 const struct ldb_val *quoted_utf16, *old_quoted_utf16, *lm_hash, *old_lm_hash;
2229 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2230 struct loadparm_context *lp_ctx =
2231 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2232 struct loadparm_context);
2237 /* Some operations below require kerberos contexts */
2239 if (smb_krb5_init_context(ac,
2240 (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"),
2241 &io->smb_krb5_context) != 0) {
2242 return ldb_operr(ldb);
2247 io->u.userAccountControl = ldb_msg_find_attr_as_uint(searched_msg,
2248 "userAccountControl", 0);
2249 io->u.pwdLastSet = samdb_result_nttime(searched_msg, "pwdLastSet", 0);
2250 io->u.sAMAccountName = ldb_msg_find_attr_as_string(searched_msg,
2251 "sAMAccountName", NULL);
2252 io->u.user_principal_name = ldb_msg_find_attr_as_string(searched_msg,
2253 "userPrincipalName", NULL);
2254 io->u.is_computer = ldb_msg_check_string_attribute(searched_msg, "objectClass", "computer");
2256 if (io->u.sAMAccountName == NULL) {
2257 ldb_asprintf_errstring(ldb,
2258 "setup_io: sAMAccountName attribute is missing on %s for attempted password set/change",
2259 ldb_dn_get_linearized(searched_msg->dn));
2261 return LDB_ERR_CONSTRAINT_VIOLATION;
2264 /* Only non-trust accounts have restrictions (possibly this test is the
2265 * wrong way around, but we like to be restrictive if possible */
2266 io->u.restrictions = !(io->u.userAccountControl
2267 & (UF_INTERDOMAIN_TRUST_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT
2268 | UF_SERVER_TRUST_ACCOUNT));
2270 if (ac->userPassword) {
2271 ret = msg_find_old_and_new_pwd_val(orig_msg, "userPassword",
2273 &io->n.cleartext_utf8,
2274 &io->og.cleartext_utf8);
2275 if (ret != LDB_SUCCESS) {
2276 ldb_asprintf_errstring(ldb,
2278 "it's only allowed to set the old password once!");
2283 if (io->n.cleartext_utf8 != NULL) {
2284 struct ldb_val *cleartext_utf8_blob;
2287 cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
2288 if (!cleartext_utf8_blob) {
2289 return ldb_oom(ldb);
2292 *cleartext_utf8_blob = *io->n.cleartext_utf8;
2294 /* make sure we have a null terminated string */
2295 p = talloc_strndup(cleartext_utf8_blob,
2296 (const char *)io->n.cleartext_utf8->data,
2297 io->n.cleartext_utf8->length);
2298 if ((p == NULL) && (io->n.cleartext_utf8->length > 0)) {
2299 return ldb_oom(ldb);
2301 cleartext_utf8_blob->data = (uint8_t *)p;
2303 io->n.cleartext_utf8 = cleartext_utf8_blob;
2306 ret = msg_find_old_and_new_pwd_val(orig_msg, "clearTextPassword",
2308 &io->n.cleartext_utf16,
2309 &io->og.cleartext_utf16);
2310 if (ret != LDB_SUCCESS) {
2311 ldb_asprintf_errstring(ldb,
2313 "it's only allowed to set the old password once!");
2317 /* this rather strange looking piece of code is there to
2318 handle a ldap client setting a password remotely using the
2319 unicodePwd ldap field. The syntax is that the password is
2320 in UTF-16LE, with a " at either end. Unfortunately the
2321 unicodePwd field is also used to store the nt hashes
2322 internally in Samba, and is used in the nt hash format on
2323 the wire in DRS replication, so we have a single name for
2324 two distinct values. The code below leaves us with a small
2325 chance (less than 1 in 2^32) of a mixup, if someone manages
2326 to create a MD4 hash which starts and ends in 0x22 0x00, as
2327 that would then be treated as a UTF16 password rather than
2330 ret = msg_find_old_and_new_pwd_val(orig_msg, "unicodePwd",
2334 if (ret != LDB_SUCCESS) {
2335 ldb_asprintf_errstring(ldb,
2337 "it's only allowed to set the old password once!");
2341 /* Checks and converts the actual "unicodePwd" attribute */
2342 if (!ac->hash_values &&
2344 quoted_utf16->length >= 4 &&
2345 quoted_utf16->data[0] == '"' &&
2346 quoted_utf16->data[1] == 0 &&
2347 quoted_utf16->data[quoted_utf16->length-2] == '"' &&
2348 quoted_utf16->data[quoted_utf16->length-1] == 0) {
2349 struct ldb_val *quoted_utf16_2;
2351 if (io->n.cleartext_utf16) {
2352 /* refuse the change if someone wants to change with
2353 with both UTF16 possibilities at the same time... */
2354 ldb_asprintf_errstring(ldb,
2356 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
2357 return LDB_ERR_UNWILLING_TO_PERFORM;
2361 * adapt the quoted UTF16 string to be a real
2364 quoted_utf16_2 = talloc(io->ac, struct ldb_val);
2365 if (quoted_utf16_2 == NULL) {
2366 return ldb_oom(ldb);
2369 quoted_utf16_2->data = quoted_utf16->data + 2;
2370 quoted_utf16_2->length = quoted_utf16->length-4;
2371 io->n.cleartext_utf16 = quoted_utf16_2;
2372 io->n.nt_hash = NULL;
2374 } else if (quoted_utf16) {
2375 /* We have only the hash available -> so no plaintext here */
2376 if (!ac->hash_values) {
2377 /* refuse the change if someone wants to change
2378 the hash without control specified... */
2379 ldb_asprintf_errstring(ldb,
2381 "it's not allowed to set the NT hash password directly'");
2382 /* this looks odd but this is what Windows does:
2383 returns "UNWILLING_TO_PERFORM" on wrong
2384 password sets and "CONSTRAINT_VIOLATION" on
2385 wrong password changes. */
2386 if (old_quoted_utf16 == NULL) {
2387 return LDB_ERR_UNWILLING_TO_PERFORM;
2390 return LDB_ERR_CONSTRAINT_VIOLATION;
2393 io->n.nt_hash = talloc(io->ac, struct samr_Password);
2394 memcpy(io->n.nt_hash->hash, quoted_utf16->data,
2395 MIN(quoted_utf16->length, sizeof(io->n.nt_hash->hash)));
2398 /* Checks and converts the previous "unicodePwd" attribute */
2399 if (!ac->hash_values &&
2401 old_quoted_utf16->length >= 4 &&
2402 old_quoted_utf16->data[0] == '"' &&
2403 old_quoted_utf16->data[1] == 0 &&
2404 old_quoted_utf16->data[old_quoted_utf16->length-2] == '"' &&
2405 old_quoted_utf16->data[old_quoted_utf16->length-1] == 0) {
2406 struct ldb_val *old_quoted_utf16_2;
2408 if (io->og.cleartext_utf16) {
2409 /* refuse the change if someone wants to change with
2410 both UTF16 possibilities at the same time... */
2411 ldb_asprintf_errstring(ldb,
2413 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
2414 return LDB_ERR_UNWILLING_TO_PERFORM;
2418 * adapt the quoted UTF16 string to be a real
2421 old_quoted_utf16_2 = talloc(io->ac, struct ldb_val);
2422 if (old_quoted_utf16_2 == NULL) {
2423 return ldb_oom(ldb);
2426 old_quoted_utf16_2->data = old_quoted_utf16->data + 2;
2427 old_quoted_utf16_2->length = old_quoted_utf16->length-4;
2429 io->og.cleartext_utf16 = old_quoted_utf16_2;
2430 io->og.nt_hash = NULL;
2431 } else if (old_quoted_utf16) {
2432 /* We have only the hash available -> so no plaintext here */
2433 if (!ac->hash_values) {
2434 /* refuse the change if someone wants to change
2435 the hash without control specified... */
2436 ldb_asprintf_errstring(ldb,
2438 "it's not allowed to set the NT hash password directly'");
2439 return LDB_ERR_UNWILLING_TO_PERFORM;
2442 io->og.nt_hash = talloc(io->ac, struct samr_Password);
2443 memcpy(io->og.nt_hash->hash, old_quoted_utf16->data,
2444 MIN(old_quoted_utf16->length, sizeof(io->og.nt_hash->hash)));
2447 /* Handles the "dBCSPwd" attribute (LM hash) */
2448 io->n.lm_hash = NULL; io->og.lm_hash = NULL;
2449 ret = msg_find_old_and_new_pwd_val(orig_msg, "dBCSPwd",
2451 &lm_hash, &old_lm_hash);
2452 if (ret != LDB_SUCCESS) {
2453 ldb_asprintf_errstring(ldb,
2455 "it's only allowed to set the old password once!");
2459 if (((lm_hash != NULL) || (old_lm_hash != NULL)) && (!ac->hash_values)) {
2460 /* refuse the change if someone wants to change the hash
2461 without control specified... */
2462 ldb_asprintf_errstring(ldb,
2464 "it's not allowed to set the LM hash password directly'");
2465 return LDB_ERR_UNWILLING_TO_PERFORM;
2468 if (lpcfg_lanman_auth(lp_ctx) && (lm_hash != NULL)) {
2469 io->n.lm_hash = talloc(io->ac, struct samr_Password);
2470 memcpy(io->n.lm_hash->hash, lm_hash->data, MIN(lm_hash->length,
2471 sizeof(io->n.lm_hash->hash)));
2473 if (lpcfg_lanman_auth(lp_ctx) && (old_lm_hash != NULL)) {
2474 io->og.lm_hash = talloc(io->ac, struct samr_Password);
2475 memcpy(io->og.lm_hash->hash, old_lm_hash->data, MIN(old_lm_hash->length,
2476 sizeof(io->og.lm_hash->hash)));
2480 * Handles the password change control if it's specified. It has the
2481 * precedance and overrides already specified old password values of
2482 * change requests (but that shouldn't happen since the control is
2483 * fully internal and only used in conjunction with replace requests!).
2485 if (ac->change != NULL) {
2486 io->og.nt_hash = NULL;
2487 if (ac->change->old_nt_pwd_hash != NULL) {
2488 io->og.nt_hash = talloc_memdup(io->ac,
2489 ac->change->old_nt_pwd_hash,
2490 sizeof(struct samr_Password));
2492 io->og.lm_hash = NULL;
2493 if (lpcfg_lanman_auth(lp_ctx) && (ac->change->old_lm_pwd_hash != NULL)) {
2494 io->og.lm_hash = talloc_memdup(io->ac,
2495 ac->change->old_lm_pwd_hash,
2496 sizeof(struct samr_Password));
2500 /* refuse the change if someone wants to change the clear-
2501 text and supply his own hashes at the same time... */
2502 if ((io->n.cleartext_utf8 || io->n.cleartext_utf16)
2503 && (io->n.nt_hash || io->n.lm_hash)) {
2504 ldb_asprintf_errstring(ldb,
2506 "it's only allowed to set the password in form of cleartext attributes or as hashes");
2507 return LDB_ERR_UNWILLING_TO_PERFORM;
2510 /* refuse the change if someone wants to change the password
2511 using both plaintext methods (UTF8 and UTF16) at the same time... */
2512 if (io->n.cleartext_utf8 && io->n.cleartext_utf16) {
2513 ldb_asprintf_errstring(ldb,
2515 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
2516 return LDB_ERR_UNWILLING_TO_PERFORM;
2519 /* refuse the change if someone tries to set/change the password by
2520 * the lanman hash alone and we've deactivated that mechanism. This
2521 * would end in an account without any password! */
2522 if ((!io->n.cleartext_utf8) && (!io->n.cleartext_utf16)
2523 && (!io->n.nt_hash) && (!io->n.lm_hash)) {
2524 ldb_asprintf_errstring(ldb,
2526 "It' not possible to delete the password (changes using the LAN Manager hash alone could be deactivated)!");
2527 /* on "userPassword" and "clearTextPassword" we've to return
2528 * something different, since these are virtual attributes */
2529 if ((ldb_msg_find_element(orig_msg, "userPassword") != NULL) ||
2530 (ldb_msg_find_element(orig_msg, "clearTextPassword") != NULL)) {
2531 return LDB_ERR_CONSTRAINT_VIOLATION;
2533 return LDB_ERR_UNWILLING_TO_PERFORM;
2536 /* refuse the change if someone wants to compare against a plaintext
2537 or hash at the same time for a "password modify" operation... */
2538 if ((io->og.cleartext_utf8 || io->og.cleartext_utf16)
2539 && (io->og.nt_hash || io->og.lm_hash)) {
2540 ldb_asprintf_errstring(ldb,
2542 "it's only allowed to provide the old password in form of cleartext attributes or as hashes");
2543 return LDB_ERR_UNWILLING_TO_PERFORM;
2546 /* refuse the change if someone wants to compare against both
2547 * plaintexts at the same time for a "password modify" operation... */
2548 if (io->og.cleartext_utf8 && io->og.cleartext_utf16) {
2549 ldb_asprintf_errstring(ldb,
2551 "it's only allowed to provide the old cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
2552 return LDB_ERR_UNWILLING_TO_PERFORM;
2555 /* Decides if we have a password modify or password reset operation */
2556 if (ac->req->operation == LDB_ADD) {
2557 /* On "add" we have only "password reset" */
2558 ac->pwd_reset = true;
2559 } else if (ac->req->operation == LDB_MODIFY) {
2560 if (io->og.cleartext_utf8 || io->og.cleartext_utf16
2561 || io->og.nt_hash || io->og.lm_hash) {
2562 /* If we have an old password specified then for sure it
2563 * is a user "password change" */
2564 ac->pwd_reset = false;
2566 /* Otherwise we have also here a "password reset" */
2567 ac->pwd_reset = true;
2570 /* this shouldn't happen */
2571 return ldb_operr(ldb);
2577 static struct ph_context *ph_init_context(struct ldb_module *module,
2578 struct ldb_request *req,
2581 struct ldb_context *ldb;
2582 struct ph_context *ac;
2584 ldb = ldb_module_get_ctx(module);
2586 ac = talloc_zero(req, struct ph_context);
2588 ldb_set_errstring(ldb, "Out of Memory");
2592 ac->module = module;
2594 ac->userPassword = userPassword;
2599 static void ph_apply_controls(struct ph_context *ac)
2601 struct ldb_control *ctrl;
2603 ac->change_status = false;
2604 ctrl = ldb_request_get_control(ac->req,
2605 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID);
2607 ac->change_status = true;
2609 /* Mark the "change status" control as uncritical (done) */
2610 ctrl->critical = false;
2613 ac->hash_values = false;
2614 ctrl = ldb_request_get_control(ac->req,
2615 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID);
2617 ac->hash_values = true;
2619 /* Mark the "hash values" control as uncritical (done) */
2620 ctrl->critical = false;
2623 ctrl = ldb_request_get_control(ac->req,
2624 DSDB_CONTROL_PASSWORD_CHANGE_OID);
2626 ac->change = (struct dsdb_control_password_change *) ctrl->data;
2628 /* Mark the "change" control as uncritical (done) */
2629 ctrl->critical = false;
2632 ac->pwd_last_set_bypass = false;
2633 ctrl = ldb_request_get_control(ac->req,
2634 DSDB_CONTROL_PASSWORD_BYPASS_LAST_SET_OID);
2636 ac->pwd_last_set_bypass = true;
2638 /* Mark the "bypass pwdLastSet" control as uncritical (done) */
2639 ctrl->critical = false;
2643 static int ph_op_callback(struct ldb_request *req, struct ldb_reply *ares)
2645 struct ph_context *ac;
2647 ac = talloc_get_type(req->context, struct ph_context);
2650 return ldb_module_done(ac->req, NULL, NULL,
2651 LDB_ERR_OPERATIONS_ERROR);
2654 if (ares->type == LDB_REPLY_REFERRAL) {
2655 return ldb_module_send_referral(ac->req, ares->referral);
2658 if ((ares->error != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
2659 /* On success and trivial errors a status control is being
2660 * added (used for example by the "samdb_set_password" call) */
2661 ldb_reply_add_control(ares,
2662 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2667 if (ares->error != LDB_SUCCESS) {
2668 return ldb_module_done(ac->req, ares->controls,
2669 ares->response, ares->error);
2672 if (ares->type != LDB_REPLY_DONE) {
2674 return ldb_module_done(ac->req, NULL, NULL,
2675 LDB_ERR_OPERATIONS_ERROR);
2678 return ldb_module_done(ac->req, ares->controls,
2679 ares->response, ares->error);
2682 static int password_hash_add_do_add(struct ph_context *ac);
2683 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares);
2684 static int password_hash_mod_search_self(struct ph_context *ac);
2685 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares);
2686 static int password_hash_mod_do_mod(struct ph_context *ac);
2688 static int get_domain_data_callback(struct ldb_request *req,
2689 struct ldb_reply *ares)
2691 struct ldb_context *ldb;
2692 struct ph_context *ac;
2693 struct loadparm_context *lp_ctx;
2694 int ret = LDB_SUCCESS;
2696 ac = talloc_get_type(req->context, struct ph_context);
2697 ldb = ldb_module_get_ctx(ac->module);
2700 ret = LDB_ERR_OPERATIONS_ERROR;
2703 if (ares->error != LDB_SUCCESS) {
2704 return ldb_module_done(ac->req, ares->controls,
2705 ares->response, ares->error);
2708 switch (ares->type) {
2709 case LDB_REPLY_ENTRY:
2710 if (ac->status != NULL) {
2713 ldb_set_errstring(ldb, "Too many results");
2714 ret = LDB_ERR_OPERATIONS_ERROR;
2718 /* Setup the "status" structure (used as control later) */
2719 ac->status = talloc_zero(ac->req,
2720 struct dsdb_control_password_change_status);
2721 if (ac->status == NULL) {
2725 ret = LDB_ERR_OPERATIONS_ERROR;
2729 /* Setup the "domain data" structure */
2730 ac->status->domain_data.pwdProperties =
2731 ldb_msg_find_attr_as_uint(ares->message, "pwdProperties", -1);
2732 ac->status->domain_data.pwdHistoryLength =
2733 ldb_msg_find_attr_as_uint(ares->message, "pwdHistoryLength", -1);
2734 ac->status->domain_data.maxPwdAge =
2735 ldb_msg_find_attr_as_int64(ares->message, "maxPwdAge", -1);
2736 ac->status->domain_data.minPwdAge =
2737 ldb_msg_find_attr_as_int64(ares->message, "minPwdAge", -1);
2738 ac->status->domain_data.minPwdLength =
2739 ldb_msg_find_attr_as_uint(ares->message, "minPwdLength", -1);
2740 ac->status->domain_data.store_cleartext =
2741 ac->status->domain_data.pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
2743 /* For a domain DN, this puts things in dotted notation */
2744 /* For builtin domains, this will give details for the host,
2745 * but that doesn't really matter, as it's just used for salt
2746 * and kerberos principals, which don't exist here */
2748 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2749 struct loadparm_context);
2751 ac->status->domain_data.dns_domain = lpcfg_dnsdomain(lp_ctx);
2752 ac->status->domain_data.realm = lpcfg_realm(lp_ctx);
2753 ac->status->domain_data.netbios_domain = lpcfg_sam_name(lp_ctx);
2755 ac->status->reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2757 if (ac->dom_res != NULL) {
2760 ldb_set_errstring(ldb, "Too many results");
2761 ret = LDB_ERR_OPERATIONS_ERROR;
2765 ac->dom_res = talloc_steal(ac, ares);
2769 case LDB_REPLY_REFERRAL:
2775 case LDB_REPLY_DONE:
2777 /* call the next step */
2778 switch (ac->req->operation) {
2780 ret = password_hash_add_do_add(ac);
2784 ret = password_hash_mod_do_mod(ac);
2788 ret = LDB_ERR_OPERATIONS_ERROR;
2795 if (ret != LDB_SUCCESS) {
2796 struct ldb_reply *new_ares;
2798 new_ares = talloc_zero(ac->req, struct ldb_reply);
2799 if (new_ares == NULL) {
2801 return ldb_module_done(ac->req, NULL, NULL,
2802 LDB_ERR_OPERATIONS_ERROR);
2805 new_ares->error = ret;
2806 if ((ret != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
2807 /* On success and trivial errors a status control is being
2808 * added (used for example by the "samdb_set_password" call) */
2809 ldb_reply_add_control(new_ares,
2810 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2815 return ldb_module_done(ac->req, new_ares->controls,
2816 new_ares->response, new_ares->error);
2822 static int build_domain_data_request(struct ph_context *ac)
2824 /* attrs[] is returned from this function in
2825 ac->dom_req->op.search.attrs, so it must be static, as
2826 otherwise the compiler can put it on the stack */
2827 struct ldb_context *ldb;
2828 static const char * const attrs[] = { "pwdProperties",
2834 "lockOutObservationWindow",
2838 ldb = ldb_module_get_ctx(ac->module);
2840 ret = ldb_build_search_req(&ac->dom_req, ldb, ac,
2841 ldb_get_default_basedn(ldb),
2845 ac, get_domain_data_callback,
2847 LDB_REQ_SET_LOCATION(ac->dom_req);
2851 static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
2853 struct ldb_context *ldb;
2854 struct ph_context *ac;
2855 struct ldb_message_element *userPasswordAttr, *clearTextPasswordAttr,
2858 struct ldb_control *bypass = NULL;
2859 bool userPassword = dsdb_user_password_support(module, req, req);
2861 ldb = ldb_module_get_ctx(module);
2863 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add\n");
2865 if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
2866 return ldb_next_request(module, req);
2869 bypass = ldb_request_get_control(req,
2870 DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID);
2871 if (bypass != NULL) {
2872 /* Mark the "bypass" control as uncritical (done) */
2873 bypass->critical = false;
2874 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add (bypassing)\n");
2875 return password_hash_bypass(module, req);
2878 /* nobody must touch password histories and 'supplementalCredentials' */
2879 if (ldb_msg_find_element(req->op.add.message, "ntPwdHistory")) {
2880 return LDB_ERR_UNWILLING_TO_PERFORM;
2882 if (ldb_msg_find_element(req->op.add.message, "lmPwdHistory")) {
2883 return LDB_ERR_UNWILLING_TO_PERFORM;
2885 if (ldb_msg_find_element(req->op.add.message, "supplementalCredentials")) {
2886 return LDB_ERR_UNWILLING_TO_PERFORM;
2889 /* If no part of this touches the 'userPassword' OR 'clearTextPassword'
2890 * OR 'unicodePwd' OR 'dBCSPwd' we don't need to make any changes. */
2892 userPasswordAttr = NULL;
2894 userPasswordAttr = ldb_msg_find_element(req->op.add.message,
2896 /* MS-ADTS 3.1.1.3.1.5.2 */
2897 if ((userPasswordAttr != NULL) &&
2898 (dsdb_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
2899 return LDB_ERR_CONSTRAINT_VIOLATION;
2902 clearTextPasswordAttr = ldb_msg_find_element(req->op.add.message, "clearTextPassword");
2903 ntAttr = ldb_msg_find_element(req->op.add.message, "unicodePwd");
2904 lmAttr = ldb_msg_find_element(req->op.add.message, "dBCSPwd");
2906 if ((!userPasswordAttr) && (!clearTextPasswordAttr) && (!ntAttr) && (!lmAttr)) {
2907 return ldb_next_request(module, req);
2910 /* Make sure we are performing the password set action on a (for us)
2911 * valid object. Those are instances of either "user" and/or
2912 * "inetOrgPerson". Otherwise continue with the submodules. */
2913 if ((!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "user"))
2914 && (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "inetOrgPerson"))) {
2916 if (ldb_msg_find_element(req->op.add.message, "clearTextPassword") != NULL) {
2917 ldb_set_errstring(ldb,
2918 "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
2919 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2922 return ldb_next_request(module, req);
2925 ac = ph_init_context(module, req, userPassword);
2927 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
2928 return ldb_operr(ldb);
2930 ph_apply_controls(ac);
2932 /* get user domain data */
2933 ret = build_domain_data_request(ac);
2934 if (ret != LDB_SUCCESS) {
2938 return ldb_next_request(module, ac->dom_req);
2941 static int password_hash_add_do_add(struct ph_context *ac)
2943 struct ldb_context *ldb;
2944 struct ldb_request *down_req;
2945 struct ldb_message *msg;
2946 struct setup_password_fields_io io;
2949 /* Prepare the internal data structure containing the passwords */
2950 ret = setup_io(ac, ac->req->op.add.message, ac->req->op.add.message, &io);
2951 if (ret != LDB_SUCCESS) {
2955 ldb = ldb_module_get_ctx(ac->module);
2957 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
2959 return ldb_operr(ldb);
2962 /* remove attributes that we just read into 'io' */
2963 if (ac->userPassword) {
2964 ldb_msg_remove_attr(msg, "userPassword");
2966 ldb_msg_remove_attr(msg, "clearTextPassword");
2967 ldb_msg_remove_attr(msg, "unicodePwd");
2968 ldb_msg_remove_attr(msg, "dBCSPwd");
2969 ldb_msg_remove_attr(msg, "pwdLastSet");
2971 ret = setup_password_fields(&io);
2972 if (ret != LDB_SUCCESS) {
2976 ret = check_password_restrictions(&io);
2977 if (ret != LDB_SUCCESS) {
2982 ret = samdb_msg_add_hash(ldb, ac, msg,
2983 "unicodePwd", io.g.nt_hash);
2984 if (ret != LDB_SUCCESS) {
2989 ret = samdb_msg_add_hash(ldb, ac, msg,
2990 "dBCSPwd", io.g.lm_hash);
2991 if (ret != LDB_SUCCESS) {
2995 if (io.g.nt_history_len > 0) {
2996 ret = samdb_msg_add_hashes(ldb, ac, msg,
2999 io.g.nt_history_len);
3000 if (ret != LDB_SUCCESS) {
3004 if (io.g.lm_history_len > 0) {
3005 ret = samdb_msg_add_hashes(ldb, ac, msg,
3008 io.g.lm_history_len);
3009 if (ret != LDB_SUCCESS) {
3013 if (io.g.supplemental.length > 0) {
3014 ret = ldb_msg_add_value(msg, "supplementalCredentials",
3015 &io.g.supplemental, NULL);
3016 if (ret != LDB_SUCCESS) {
3020 ret = samdb_msg_add_uint64(ldb, ac, msg,
3023 if (ret != LDB_SUCCESS) {
3027 ret = ldb_build_add_req(&down_req, ldb, ac,
3032 LDB_REQ_SET_LOCATION(down_req);
3033 if (ret != LDB_SUCCESS) {
3037 return ldb_next_request(ac->module, down_req);
3040 static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
3042 struct ldb_context *ldb;
3043 struct ph_context *ac;
3044 const char *passwordAttrs[] = { "userPassword", "clearTextPassword",
3045 "unicodePwd", "dBCSPwd", NULL }, **l;
3046 unsigned int attr_cnt, del_attr_cnt, add_attr_cnt, rep_attr_cnt;
3047 struct ldb_message_element *passwordAttr;
3048 struct ldb_message *msg;
3049 struct ldb_request *down_req;
3051 struct ldb_control *bypass = NULL;
3052 bool userPassword = dsdb_user_password_support(module, req, req);
3054 ldb = ldb_module_get_ctx(module);
3056 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
3058 if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
3059 return ldb_next_request(module, req);
3062 bypass = ldb_request_get_control(req,
3063 DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID);
3064 if (bypass != NULL) {
3065 /* Mark the "bypass" control as uncritical (done) */
3066 bypass->critical = false;
3067 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify (bypassing)\n");
3068 return password_hash_bypass(module, req);
3071 /* nobody must touch password histories and 'supplementalCredentials' */
3072 if (ldb_msg_find_element(req->op.mod.message, "ntPwdHistory")) {
3073 return LDB_ERR_UNWILLING_TO_PERFORM;
3075 if (ldb_msg_find_element(req->op.mod.message, "lmPwdHistory")) {
3076 return LDB_ERR_UNWILLING_TO_PERFORM;
3078 if (ldb_msg_find_element(req->op.mod.message, "supplementalCredentials")) {
3079 return LDB_ERR_UNWILLING_TO_PERFORM;
3082 /* If no part of this touches the 'userPassword' OR 'clearTextPassword'
3083 * OR 'unicodePwd' OR 'dBCSPwd' we don't need to make any changes.
3084 * For password changes/set there should be a 'delete' or a 'modify'
3085 * on these attributes. */
3087 for (l = passwordAttrs; *l != NULL; l++) {
3088 if ((!userPassword) && (ldb_attr_cmp(*l, "userPassword") == 0)) {
3092 if (ldb_msg_find_element(req->op.mod.message, *l) != NULL) {
3093 /* MS-ADTS 3.1.1.3.1.5.2 */
3094 if ((ldb_attr_cmp(*l, "userPassword") == 0) &&
3095 (dsdb_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
3096 return LDB_ERR_CONSTRAINT_VIOLATION;
3102 if (attr_cnt == 0) {
3103 return ldb_next_request(module, req);
3106 ac = ph_init_context(module, req, userPassword);
3108 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
3109 return ldb_operr(ldb);
3111 ph_apply_controls(ac);
3113 /* use a new message structure so that we can modify it */
3114 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3116 return ldb_oom(ldb);
3119 /* - check for single-valued password attributes
3120 * (if not return "CONSTRAINT_VIOLATION")
3121 * - check that for a password change operation one add and one delete
3123 * (if not return "CONSTRAINT_VIOLATION" or "UNWILLING_TO_PERFORM")
3124 * - check that a password change and a password set operation cannot
3126 * (if not return "UNWILLING_TO_PERFORM")
3127 * - remove all password attributes modifications from the first change
3128 * operation (anything without the passwords) - we will make the real
3129 * modification later */
3133 for (l = passwordAttrs; *l != NULL; l++) {
3134 if ((!ac->userPassword) &&
3135 (ldb_attr_cmp(*l, "userPassword") == 0)) {
3139 while ((passwordAttr = ldb_msg_find_element(msg, *l)) != NULL) {
3140 if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_DELETE) {
3143 if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_ADD) {
3146 if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_REPLACE) {
3149 if ((passwordAttr->num_values != 1) &&
3150 (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_ADD)) {
3152 ldb_asprintf_errstring(ldb,
3153 "'%s' attribute must have exactly one value on add operations!",
3155 return LDB_ERR_CONSTRAINT_VIOLATION;
3157 if ((passwordAttr->num_values > 1) &&
3158 (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_DELETE)) {
3160 ldb_asprintf_errstring(ldb,
3161 "'%s' attribute must have zero or one value(s) on delete operations!",
3163 return LDB_ERR_CONSTRAINT_VIOLATION;
3165 ldb_msg_remove_element(msg, passwordAttr);
3168 if ((del_attr_cnt == 0) && (add_attr_cnt > 0)) {
3170 ldb_set_errstring(ldb,
3171 "Only the add action for a password change specified!");
3172 return LDB_ERR_UNWILLING_TO_PERFORM;
3174 if ((del_attr_cnt > 1) || (add_attr_cnt > 1)) {
3176 ldb_set_errstring(ldb,
3177 "Only one delete and one add action for a password change allowed!");
3178 return LDB_ERR_UNWILLING_TO_PERFORM;
3180 if ((rep_attr_cnt > 0) && ((del_attr_cnt > 0) || (add_attr_cnt > 0))) {
3182 ldb_set_errstring(ldb,
3183 "Either a password change or a password set operation is allowed!");
3184 return LDB_ERR_UNWILLING_TO_PERFORM;
3187 /* if there was nothing else to be modified skip to next step */
3188 if (msg->num_elements == 0) {
3189 return password_hash_mod_search_self(ac);
3192 ret = ldb_build_mod_req(&down_req, ldb, ac,
3195 ac, ph_modify_callback,
3197 LDB_REQ_SET_LOCATION(down_req);
3198 if (ret != LDB_SUCCESS) {
3202 return ldb_next_request(module, down_req);
3205 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
3207 struct ph_context *ac;
3209 ac = talloc_get_type(req->context, struct ph_context);
3212 return ldb_module_done(ac->req, NULL, NULL,
3213 LDB_ERR_OPERATIONS_ERROR);
3216 if (ares->type == LDB_REPLY_REFERRAL) {
3217 return ldb_module_send_referral(ac->req, ares->referral);
3220 if (ares->error != LDB_SUCCESS) {
3221 return ldb_module_done(ac->req, ares->controls,
3222 ares->response, ares->error);
3225 if (ares->type != LDB_REPLY_DONE) {
3227 return ldb_module_done(ac->req, NULL, NULL,
3228 LDB_ERR_OPERATIONS_ERROR);
3233 return password_hash_mod_search_self(ac);
3236 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
3238 struct ldb_context *ldb;
3239 struct ph_context *ac;
3240 int ret = LDB_SUCCESS;
3242 ac = talloc_get_type(req->context, struct ph_context);
3243 ldb = ldb_module_get_ctx(ac->module);
3246 ret = LDB_ERR_OPERATIONS_ERROR;
3249 if (ares->error != LDB_SUCCESS) {
3250 return ldb_module_done(ac->req, ares->controls,
3251 ares->response, ares->error);
3254 /* we are interested only in the single reply (base search) */
3255 switch (ares->type) {
3256 case LDB_REPLY_ENTRY:
3257 /* Make sure we are performing the password change action on a
3258 * (for us) valid object. Those are instances of either "user"
3259 * and/or "inetOrgPerson". Otherwise continue with the
3261 if ((!ldb_msg_check_string_attribute(ares->message, "objectClass", "user"))
3262 && (!ldb_msg_check_string_attribute(ares->message, "objectClass", "inetOrgPerson"))) {
3265 if (ldb_msg_find_element(ac->req->op.mod.message, "clearTextPassword") != NULL) {
3266 ldb_set_errstring(ldb,
3267 "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
3268 ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
3272 ret = ldb_next_request(ac->module, ac->req);
3276 if (ac->search_res != NULL) {
3279 ldb_set_errstring(ldb, "Too many results");
3280 ret = LDB_ERR_OPERATIONS_ERROR;
3284 ac->search_res = talloc_steal(ac, ares);
3288 case LDB_REPLY_REFERRAL:
3289 /* ignore anything else for now */
3294 case LDB_REPLY_DONE:
3297 /* get user domain data */
3298 ret = build_domain_data_request(ac);
3299 if (ret != LDB_SUCCESS) {
3300 return ldb_module_done(ac->req, NULL, NULL, ret);
3303 ret = ldb_next_request(ac->module, ac->dom_req);
3308 if (ret != LDB_SUCCESS) {
3309 return ldb_module_done(ac->req, NULL, NULL, ret);
3315 static int password_hash_mod_search_self(struct ph_context *ac)
3317 struct ldb_context *ldb;
3318 static const char * const attrs[] = { "objectClass",
3319 "userAccountControl",
3320 "msDS-User-Account-Control-Computed",
3324 "userPrincipalName",
3325 "supplementalCredentials",
3334 struct ldb_request *search_req;
3337 ldb = ldb_module_get_ctx(ac->module);
3339 ret = ldb_build_search_req(&search_req, ldb, ac,
3340 ac->req->op.mod.message->dn,
3345 ac, ph_mod_search_callback,
3347 LDB_REQ_SET_LOCATION(search_req);
3348 if (ret != LDB_SUCCESS) {
3352 return ldb_next_request(ac->module, search_req);
3355 static int password_hash_mod_do_mod(struct ph_context *ac)
3357 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3358 struct loadparm_context *lp_ctx =
3359 talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3360 struct loadparm_context);
3361 struct ldb_request *mod_req;
3362 struct ldb_message *msg;
3363 const struct ldb_message *orig_msg, *searched_msg;
3364 struct setup_password_fields_io io;
3368 /* use a new message structure so that we can modify it */
3369 msg = ldb_msg_new(ac);
3371 return ldb_operr(ldb);
3375 msg->dn = ac->req->op.mod.message->dn;
3377 orig_msg = ac->req->op.mod.message;
3378 searched_msg = ac->search_res->message;
3380 /* Prepare the internal data structure containing the passwords */
3381 ret = setup_io(ac, orig_msg, searched_msg, &io);
3382 if (ret != LDB_SUCCESS) {
3386 if (io.ac->pwd_reset) {
3387 /* Get the old password from the database */
3388 status = samdb_result_passwords_no_lockout(io.ac,
3390 discard_const_p(struct ldb_message, searched_msg),
3394 /* Get the old password from the database */
3395 status = samdb_result_passwords(io.ac,
3397 discard_const_p(struct ldb_message, searched_msg),
3398 &io.o.lm_hash, &io.o.nt_hash);
3401 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCOUNT_LOCKED_OUT)) {
3402 ldb_asprintf_errstring(ldb,
3403 "%08X: check_password: "
3404 "Password change not permitted, account locked out!",
3405 W_ERROR_V(WERR_ACCOUNT_LOCKED_OUT));
3406 return LDB_ERR_CONSTRAINT_VIOLATION;
3409 if (!NT_STATUS_IS_OK(status)) {
3411 * This only happens if the database has gone weird,
3412 * not if we are just missing the passwords
3414 return ldb_operr(ldb);
3417 io.o.nt_history_len = samdb_result_hashes(io.ac, searched_msg, "ntPwdHistory", &io.o.nt_history);
3418 io.o.lm_history_len = samdb_result_hashes(io.ac, searched_msg, "lmPwdHistory", &io.o.lm_history);
3419 io.o.supplemental = ldb_msg_find_ldb_val(searched_msg, "supplementalCredentials");
3421 ret = setup_password_fields(&io);
3422 if (ret != LDB_SUCCESS) {
3426 ret = check_password_restrictions(&io);
3427 if (ret != LDB_SUCCESS) {
3431 /* make sure we replace all the old attributes */
3432 ret = ldb_msg_add_empty(msg, "unicodePwd", LDB_FLAG_MOD_REPLACE, NULL);
3433 ret = ldb_msg_add_empty(msg, "dBCSPwd", LDB_FLAG_MOD_REPLACE, NULL);
3434 ret = ldb_msg_add_empty(msg, "ntPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
3435 ret = ldb_msg_add_empty(msg, "lmPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
3436 ret = ldb_msg_add_empty(msg, "supplementalCredentials", LDB_FLAG_MOD_REPLACE, NULL);
3437 ret = ldb_msg_add_empty(msg, "pwdLastSet", LDB_FLAG_MOD_REPLACE, NULL);
3440 ret = samdb_msg_add_hash(ldb, ac, msg,
3441 "unicodePwd", io.g.nt_hash);
3442 if (ret != LDB_SUCCESS) {
3447 ret = samdb_msg_add_hash(ldb, ac, msg,
3448 "dBCSPwd", io.g.lm_hash);
3449 if (ret != LDB_SUCCESS) {
3453 if (io.g.nt_history_len > 0) {
3454 ret = samdb_msg_add_hashes(ldb, ac, msg,
3457 io.g.nt_history_len);
3458 if (ret != LDB_SUCCESS) {
3462 if (io.g.lm_history_len > 0) {
3463 ret = samdb_msg_add_hashes(ldb, ac, msg,
3466 io.g.lm_history_len);
3467 if (ret != LDB_SUCCESS) {
3471 if (io.g.supplemental.length > 0) {
3472 ret = ldb_msg_add_value(msg, "supplementalCredentials",
3473 &io.g.supplemental, NULL);
3474 if (ret != LDB_SUCCESS) {
3478 ret = samdb_msg_add_uint64(ldb, ac, msg,
3481 if (ret != LDB_SUCCESS) {
3485 ret = ldb_build_mod_req(&mod_req, ldb, ac,
3490 LDB_REQ_SET_LOCATION(mod_req);
3491 if (ret != LDB_SUCCESS) {
3495 return ldb_next_request(ac->module, mod_req);
3498 static const struct ldb_module_ops ldb_password_hash_module_ops = {
3499 .name = "password_hash",
3500 .add = password_hash_add,
3501 .modify = password_hash_modify
3504 int ldb_password_hash_module_init(const char *version)
3506 LDB_MODULE_CHECK_VERSION(version);
3507 return ldb_register_module(&ldb_password_hash_module_ops);