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 ldb_message *update_msg;
94 struct dsdb_control_password_change_status *status;
95 struct dsdb_control_password_change *change;
101 bool update_password;
103 bool pwd_last_set_bypass;
107 struct setup_password_fields_io {
108 struct ph_context *ac;
110 struct smb_krb5_context *smb_krb5_context;
112 /* infos about the user account */
114 uint32_t userAccountControl;
116 const char *sAMAccountName;
117 const char *user_principal_name;
119 uint32_t restrictions;
122 /* new credentials and old given credentials */
123 struct setup_password_fields_given {
124 const struct ldb_val *cleartext_utf8;
125 const struct ldb_val *cleartext_utf16;
126 struct samr_Password *nt_hash;
127 struct samr_Password *lm_hash;
130 /* old credentials */
132 struct samr_Password *nt_hash;
133 struct samr_Password *lm_hash;
134 uint32_t nt_history_len;
135 struct samr_Password *nt_history;
136 uint32_t lm_history_len;
137 struct samr_Password *lm_history;
138 const struct ldb_val *supplemental;
139 struct supplementalCredentialsBlob scb;
142 /* generated credentials */
144 struct samr_Password *nt_hash;
145 struct samr_Password *lm_hash;
146 uint32_t nt_history_len;
147 struct samr_Password *nt_history;
148 uint32_t lm_history_len;
149 struct samr_Password *lm_history;
155 struct ldb_val supplemental;
160 static int password_hash_bypass(struct ldb_module *module, struct ldb_request *request)
162 struct ldb_context *ldb = ldb_module_get_ctx(module);
163 const struct ldb_message *msg;
164 struct ldb_message_element *nte;
165 struct ldb_message_element *lme;
166 struct ldb_message_element *nthe;
167 struct ldb_message_element *lmhe;
168 struct ldb_message_element *sce;
170 switch (request->operation) {
172 msg = request->op.add.message;
175 msg = request->op.mod.message;
178 return ldb_next_request(module, request);
181 /* nobody must touch password histories and 'supplementalCredentials' */
182 nte = dsdb_get_single_valued_attr(msg, "unicodePwd",
184 lme = dsdb_get_single_valued_attr(msg, "dBCSPwd",
186 nthe = dsdb_get_single_valued_attr(msg, "ntPwdHistory",
188 lmhe = dsdb_get_single_valued_attr(msg, "lmPwdHistory",
190 sce = dsdb_get_single_valued_attr(msg, "supplementalCredentials",
193 #define CHECK_HASH_ELEMENT(e, min, max) do {\
194 if (e && e->num_values) { \
195 unsigned int _count; \
196 if (e->num_values != 1) { \
197 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
198 "num_values != 1"); \
200 if ((e->values[0].length % 16) != 0) { \
201 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
202 "length % 16 != 0"); \
204 _count = e->values[0].length / 16; \
205 if (_count < min) { \
206 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
209 if (_count > max) { \
210 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
216 CHECK_HASH_ELEMENT(nte, 1, 1);
217 CHECK_HASH_ELEMENT(lme, 1, 1);
218 CHECK_HASH_ELEMENT(nthe, 1, INT32_MAX);
219 CHECK_HASH_ELEMENT(lmhe, 1, INT32_MAX);
221 if (sce && sce->num_values) {
222 enum ndr_err_code ndr_err;
223 struct supplementalCredentialsBlob *scb;
224 struct supplementalCredentialsPackage *scpp = NULL;
225 struct supplementalCredentialsPackage *scpk = NULL;
226 struct supplementalCredentialsPackage *scpkn = NULL;
227 struct supplementalCredentialsPackage *scpct = NULL;
228 DATA_BLOB scpbp = data_blob_null;
229 DATA_BLOB scpbk = data_blob_null;
230 DATA_BLOB scpbkn = data_blob_null;
231 DATA_BLOB scpbct = data_blob_null;
235 if (sce->num_values != 1) {
236 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
240 scb = talloc_zero(request, struct supplementalCredentialsBlob);
242 return ldb_module_oom(module);
245 ndr_err = ndr_pull_struct_blob_all(&sce->values[0], scb, scb,
246 (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
247 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
248 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
249 "ndr_pull_struct_blob_all");
252 if (scb->sub.num_packages < 2) {
253 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
257 for (i=0; i < scb->sub.num_packages; i++) {
260 subblob = strhex_to_data_blob(scb, scb->sub.packages[i].data);
261 if (subblob.data == NULL) {
262 return ldb_module_oom(module);
265 if (strcmp(scb->sub.packages[i].name, "Packages") == 0) {
267 return ldb_error(ldb,
268 LDB_ERR_CONSTRAINT_VIOLATION,
271 scpp = &scb->sub.packages[i];
275 if (strcmp(scb->sub.packages[i].name, "Primary:Kerberos") == 0) {
277 return ldb_error(ldb,
278 LDB_ERR_CONSTRAINT_VIOLATION,
279 "Primary:Kerberos twice");
281 scpk = &scb->sub.packages[i];
285 if (strcmp(scb->sub.packages[i].name, "Primary:Kerberos-Newer-Keys") == 0) {
287 return ldb_error(ldb,
288 LDB_ERR_CONSTRAINT_VIOLATION,
289 "Primary:Kerberos-Newer-Keys twice");
291 scpkn = &scb->sub.packages[i];
295 if (strcmp(scb->sub.packages[i].name, "Primary:CLEARTEXT") == 0) {
297 return ldb_error(ldb,
298 LDB_ERR_CONSTRAINT_VIOLATION,
299 "Primary:CLEARTEXT twice");
301 scpct = &scb->sub.packages[i];
306 data_blob_free(&subblob);
310 return ldb_error(ldb,
311 LDB_ERR_CONSTRAINT_VIOLATION,
312 "Primary:Packages missing");
317 * If Primary:Kerberos is missing w2k8r2 reboots
318 * when a password is changed.
320 return ldb_error(ldb,
321 LDB_ERR_CONSTRAINT_VIOLATION,
322 "Primary:Kerberos missing");
326 struct package_PackagesBlob *p;
329 p = talloc_zero(scb, struct package_PackagesBlob);
331 return ldb_module_oom(module);
334 ndr_err = ndr_pull_struct_blob(&scpbp, p, p,
335 (ndr_pull_flags_fn_t)ndr_pull_package_PackagesBlob);
336 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
337 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
338 "ndr_pull_struct_blob Packages");
341 if (p->names == NULL) {
342 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
343 "Packages names == NULL");
346 for (n = 0; p->names[n]; n++) {
350 if (scb->sub.num_packages != (n + 1)) {
351 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
352 "Packages num_packages != num_names + 1");
359 struct package_PrimaryKerberosBlob *k;
361 k = talloc_zero(scb, struct package_PrimaryKerberosBlob);
363 return ldb_module_oom(module);
366 ndr_err = ndr_pull_struct_blob(&scpbk, k, k,
367 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
368 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
369 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
370 "ndr_pull_struct_blob PrimaryKerberos");
373 if (k->version != 3) {
374 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
375 "PrimaryKerberos version != 3");
378 if (k->ctr.ctr3.salt.string == NULL) {
379 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
380 "PrimaryKerberos salt == NULL");
383 if (strlen(k->ctr.ctr3.salt.string) == 0) {
384 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
385 "PrimaryKerberos strlen(salt) == 0");
388 if (k->ctr.ctr3.num_keys != 2) {
389 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
390 "PrimaryKerberos num_keys != 2");
393 if (k->ctr.ctr3.num_old_keys > k->ctr.ctr3.num_keys) {
394 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
395 "PrimaryKerberos num_old_keys > num_keys");
398 if (k->ctr.ctr3.keys[0].keytype != ENCTYPE_DES_CBC_MD5) {
399 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
400 "PrimaryKerberos key[0] != DES_CBC_MD5");
402 if (k->ctr.ctr3.keys[1].keytype != ENCTYPE_DES_CBC_CRC) {
403 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
404 "PrimaryKerberos key[1] != DES_CBC_CRC");
407 if (k->ctr.ctr3.keys[0].value_len != 8) {
408 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
409 "PrimaryKerberos key[0] value_len != 8");
411 if (k->ctr.ctr3.keys[1].value_len != 8) {
412 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
413 "PrimaryKerberos key[1] value_len != 8");
416 for (i = 0; i < k->ctr.ctr3.num_old_keys; i++) {
417 if (k->ctr.ctr3.old_keys[i].keytype ==
418 k->ctr.ctr3.keys[i].keytype &&
419 k->ctr.ctr3.old_keys[i].value_len ==
420 k->ctr.ctr3.keys[i].value_len) {
424 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
425 "PrimaryKerberos old_keys type/value_len doesn't match");
432 struct package_PrimaryKerberosBlob *k;
434 k = talloc_zero(scb, struct package_PrimaryKerberosBlob);
436 return ldb_module_oom(module);
439 ndr_err = ndr_pull_struct_blob(&scpbkn, k, k,
440 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
441 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
442 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
443 "ndr_pull_struct_blob PrimaryKerberosNeverKeys");
446 if (k->version != 4) {
447 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
448 "KerberosNerverKeys version != 4");
451 if (k->ctr.ctr4.salt.string == NULL) {
452 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
453 "KerberosNewerKeys salt == NULL");
456 if (strlen(k->ctr.ctr4.salt.string) == 0) {
457 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
458 "KerberosNewerKeys strlen(salt) == 0");
461 if (k->ctr.ctr4.num_keys != 4) {
462 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
463 "KerberosNewerKeys num_keys != 2");
466 if (k->ctr.ctr4.num_old_keys > k->ctr.ctr4.num_keys) {
467 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
468 "KerberosNewerKeys num_old_keys > num_keys");
471 if (k->ctr.ctr4.num_older_keys > k->ctr.ctr4.num_old_keys) {
472 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
473 "KerberosNewerKeys num_older_keys > num_old_keys");
476 if (k->ctr.ctr4.keys[0].keytype != ENCTYPE_AES256_CTS_HMAC_SHA1_96) {
477 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
478 "KerberosNewerKeys key[0] != AES256");
480 if (k->ctr.ctr4.keys[1].keytype != ENCTYPE_AES128_CTS_HMAC_SHA1_96) {
481 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
482 "KerberosNewerKeys key[1] != AES128");
484 if (k->ctr.ctr4.keys[2].keytype != ENCTYPE_DES_CBC_MD5) {
485 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
486 "KerberosNewerKeys key[2] != DES_CBC_MD5");
488 if (k->ctr.ctr4.keys[3].keytype != ENCTYPE_DES_CBC_CRC) {
489 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
490 "KerberosNewerKeys key[3] != DES_CBC_CRC");
493 if (k->ctr.ctr4.keys[0].value_len != 32) {
494 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
495 "KerberosNewerKeys key[0] value_len != 32");
497 if (k->ctr.ctr4.keys[1].value_len != 16) {
498 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
499 "KerberosNewerKeys key[1] value_len != 16");
501 if (k->ctr.ctr4.keys[2].value_len != 8) {
502 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
503 "KerberosNewerKeys key[2] value_len != 8");
505 if (k->ctr.ctr4.keys[3].value_len != 8) {
506 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
507 "KerberosNewerKeys key[3] value_len != 8");
512 * Maybe we can check old and older keys here.
513 * But we need to do some tests, if the old keys
514 * can be taken from the PrimaryKerberos blob
515 * (with only des keys), when the domain was upgraded
523 struct package_PrimaryCLEARTEXTBlob *ct;
525 ct = talloc_zero(scb, struct package_PrimaryCLEARTEXTBlob);
527 return ldb_module_oom(module);
530 ndr_err = ndr_pull_struct_blob(&scpbct, ct, ct,
531 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryCLEARTEXTBlob);
532 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
533 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
534 "ndr_pull_struct_blob PrimaryCLEARTEXT");
537 if ((ct->cleartext.length % 2) != 0) {
538 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
539 "PrimaryCLEARTEXT length % 2 != 0");
545 ndr_err = ndr_push_struct_blob(&blob, scb, scb,
546 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
547 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
548 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
549 "ndr_pull_struct_blob_all");
552 if (sce->values[0].length != blob.length) {
553 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
554 "supplementalCredentialsBlob length differ");
557 if (memcmp(sce->values[0].data, blob.data, blob.length) != 0) {
558 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
559 "supplementalCredentialsBlob memcmp differ");
565 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_bypass - validated\n");
566 return ldb_next_request(module, request);
569 /* Get the NT hash, and fill it in as an entry in the password history,
570 and specify it into io->g.nt_hash */
572 static int setup_nt_fields(struct setup_password_fields_io *io)
574 struct ldb_context *ldb;
577 io->g.nt_hash = io->n.nt_hash;
578 ldb = ldb_module_get_ctx(io->ac->module);
580 if (io->ac->status->domain_data.pwdHistoryLength == 0) {
584 /* We might not have an old NT password */
585 io->g.nt_history = talloc_array(io->ac,
586 struct samr_Password,
587 io->ac->status->domain_data.pwdHistoryLength);
588 if (!io->g.nt_history) {
592 for (i = 0; i < MIN(io->ac->status->domain_data.pwdHistoryLength-1,
593 io->o.nt_history_len); i++) {
594 io->g.nt_history[i+1] = io->o.nt_history[i];
596 io->g.nt_history_len = i + 1;
599 io->g.nt_history[0] = *io->g.nt_hash;
602 * TODO: is this correct?
603 * the simular behavior is correct for the lm history case
605 E_md4hash("", io->g.nt_history[0].hash);
611 /* Get the LANMAN hash, and fill it in as an entry in the password history,
612 and specify it into io->g.lm_hash */
614 static int setup_lm_fields(struct setup_password_fields_io *io)
616 struct ldb_context *ldb;
619 io->g.lm_hash = io->n.lm_hash;
620 ldb = ldb_module_get_ctx(io->ac->module);
622 if (io->ac->status->domain_data.pwdHistoryLength == 0) {
626 /* We might not have an old LM password */
627 io->g.lm_history = talloc_array(io->ac,
628 struct samr_Password,
629 io->ac->status->domain_data.pwdHistoryLength);
630 if (!io->g.lm_history) {
634 for (i = 0; i < MIN(io->ac->status->domain_data.pwdHistoryLength-1,
635 io->o.lm_history_len); i++) {
636 io->g.lm_history[i+1] = io->o.lm_history[i];
638 io->g.lm_history_len = i + 1;
641 io->g.lm_history[0] = *io->g.lm_hash;
643 E_deshash("", io->g.lm_history[0].hash);
649 static int setup_kerberos_keys(struct setup_password_fields_io *io)
651 struct ldb_context *ldb;
652 krb5_error_code krb5_ret;
653 krb5_principal salt_principal;
656 krb5_data cleartext_data;
658 ldb = ldb_module_get_ctx(io->ac->module);
659 cleartext_data.data = (char *)io->n.cleartext_utf8->data;
660 cleartext_data.length = io->n.cleartext_utf8->length;
662 /* Many, many thanks to lukeh@padl.com for this
663 * algorithm, described in his Nov 10 2004 mail to
664 * samba-technical@lists.samba.org */
667 * Determine a salting principal
669 if (io->u.is_computer) {
673 name = strlower_talloc(io->ac, io->u.sAMAccountName);
678 if (name[strlen(name)-1] == '$') {
679 name[strlen(name)-1] = '\0';
682 saltbody = talloc_asprintf(io->ac, "%s.%s", name,
683 io->ac->status->domain_data.dns_domain);
688 krb5_ret = smb_krb5_make_principal(io->smb_krb5_context->krb5_context,
690 io->ac->status->domain_data.realm,
691 "host", saltbody, NULL);
692 } else if (io->u.user_principal_name) {
693 char *user_principal_name;
696 user_principal_name = talloc_strdup(io->ac, io->u.user_principal_name);
697 if (!user_principal_name) {
701 p = strchr(user_principal_name, '@');
706 krb5_ret = smb_krb5_make_principal(io->smb_krb5_context->krb5_context,
708 io->ac->status->domain_data.realm,
709 user_principal_name, NULL);
711 krb5_ret = smb_krb5_make_principal(io->smb_krb5_context->krb5_context,
713 io->ac->status->domain_data.realm,
714 io->u.sAMAccountName, NULL);
717 ldb_asprintf_errstring(ldb,
718 "setup_kerberos_keys: "
719 "generation of a salting principal failed: %s",
720 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
722 return LDB_ERR_OPERATIONS_ERROR;
726 * create salt from salt_principal
728 krb5_ret = smb_krb5_get_pw_salt(io->smb_krb5_context->krb5_context,
729 salt_principal, &salt);
730 krb5_free_principal(io->smb_krb5_context->krb5_context, salt_principal);
732 ldb_asprintf_errstring(ldb,
733 "setup_kerberos_keys: "
734 "generation of krb5_salt failed: %s",
735 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
737 return LDB_ERR_OPERATIONS_ERROR;
739 /* create a talloc copy */
740 io->g.salt = talloc_strndup(io->ac,
743 kerberos_free_data_contents(io->smb_krb5_context->krb5_context, &salt);
747 /* now use the talloced copy of the salt */
748 salt.data = discard_const(io->g.salt);
749 salt.length = strlen(io->g.salt);
752 * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of
753 * the salt and the cleartext password
755 krb5_ret = smb_krb5_create_key_from_string(io->smb_krb5_context->krb5_context,
759 ENCTYPE_AES256_CTS_HMAC_SHA1_96,
762 ldb_asprintf_errstring(ldb,
763 "setup_kerberos_keys: "
764 "generation of a aes256-cts-hmac-sha1-96 key failed: %s",
765 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
767 return LDB_ERR_OPERATIONS_ERROR;
769 io->g.aes_256 = data_blob_talloc(io->ac,
771 KRB5_KEY_LENGTH(&key));
772 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
773 if (!io->g.aes_256.data) {
778 * create ENCTYPE_AES128_CTS_HMAC_SHA1_96 key out of
779 * the salt and the cleartext password
781 krb5_ret = smb_krb5_create_key_from_string(io->smb_krb5_context->krb5_context,
785 ENCTYPE_AES128_CTS_HMAC_SHA1_96,
788 ldb_asprintf_errstring(ldb,
789 "setup_kerberos_keys: "
790 "generation of a aes128-cts-hmac-sha1-96 key failed: %s",
791 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
793 return LDB_ERR_OPERATIONS_ERROR;
795 io->g.aes_128 = data_blob_talloc(io->ac,
797 KRB5_KEY_LENGTH(&key));
798 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
799 if (!io->g.aes_128.data) {
804 * create ENCTYPE_DES_CBC_MD5 key out of
805 * the salt and the cleartext password
807 krb5_ret = smb_krb5_create_key_from_string(io->smb_krb5_context->krb5_context,
814 ldb_asprintf_errstring(ldb,
815 "setup_kerberos_keys: "
816 "generation of a des-cbc-md5 key failed: %s",
817 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
819 return LDB_ERR_OPERATIONS_ERROR;
821 io->g.des_md5 = data_blob_talloc(io->ac,
823 KRB5_KEY_LENGTH(&key));
824 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
825 if (!io->g.des_md5.data) {
830 * create ENCTYPE_DES_CBC_CRC key out of
831 * the salt and the cleartext password
833 krb5_ret = smb_krb5_create_key_from_string(io->smb_krb5_context->krb5_context,
840 ldb_asprintf_errstring(ldb,
841 "setup_kerberos_keys: "
842 "generation of a des-cbc-crc key failed: %s",
843 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
845 return LDB_ERR_OPERATIONS_ERROR;
847 io->g.des_crc = data_blob_talloc(io->ac,
849 KRB5_KEY_LENGTH(&key));
850 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
851 if (!io->g.des_crc.data) {
858 static int setup_primary_kerberos(struct setup_password_fields_io *io,
859 const struct supplementalCredentialsBlob *old_scb,
860 struct package_PrimaryKerberosBlob *pkb)
862 struct ldb_context *ldb;
863 struct package_PrimaryKerberosCtr3 *pkb3 = &pkb->ctr.ctr3;
864 struct supplementalCredentialsPackage *old_scp = NULL;
865 struct package_PrimaryKerberosBlob _old_pkb;
866 struct package_PrimaryKerberosCtr3 *old_pkb3 = NULL;
868 enum ndr_err_code ndr_err;
870 ldb = ldb_module_get_ctx(io->ac->module);
873 * prepare generation of keys
875 * ENCTYPE_DES_CBC_MD5
876 * ENCTYPE_DES_CBC_CRC
879 pkb3->salt.string = io->g.salt;
881 pkb3->keys = talloc_array(io->ac,
882 struct package_PrimaryKerberosKey3,
888 pkb3->keys[0].keytype = ENCTYPE_DES_CBC_MD5;
889 pkb3->keys[0].value = &io->g.des_md5;
890 pkb3->keys[1].keytype = ENCTYPE_DES_CBC_CRC;
891 pkb3->keys[1].value = &io->g.des_crc;
893 /* initialize the old keys to zero */
894 pkb3->num_old_keys = 0;
895 pkb3->old_keys = NULL;
897 /* if there're no old keys, then we're done */
902 for (i=0; i < old_scb->sub.num_packages; i++) {
903 if (strcmp("Primary:Kerberos", old_scb->sub.packages[i].name) != 0) {
907 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
911 old_scp = &old_scb->sub.packages[i];
914 /* Primary:Kerberos element of supplementalCredentials */
918 blob = strhex_to_data_blob(io->ac, old_scp->data);
923 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
924 ndr_err = ndr_pull_struct_blob(&blob, io->ac, &_old_pkb,
925 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
926 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
927 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
928 ldb_asprintf_errstring(ldb,
929 "setup_primary_kerberos: "
930 "failed to pull old package_PrimaryKerberosBlob: %s",
932 return LDB_ERR_OPERATIONS_ERROR;
935 if (_old_pkb.version != 3) {
936 ldb_asprintf_errstring(ldb,
937 "setup_primary_kerberos: "
938 "package_PrimaryKerberosBlob version[%u] expected[3]",
940 return LDB_ERR_OPERATIONS_ERROR;
943 old_pkb3 = &_old_pkb.ctr.ctr3;
946 /* if we didn't found the old keys we're done */
951 /* fill in the old keys */
952 pkb3->num_old_keys = old_pkb3->num_keys;
953 pkb3->old_keys = old_pkb3->keys;
958 static int setup_primary_kerberos_newer(struct setup_password_fields_io *io,
959 const struct supplementalCredentialsBlob *old_scb,
960 struct package_PrimaryKerberosBlob *pkb)
962 struct ldb_context *ldb;
963 struct package_PrimaryKerberosCtr4 *pkb4 = &pkb->ctr.ctr4;
964 struct supplementalCredentialsPackage *old_scp = NULL;
965 struct package_PrimaryKerberosBlob _old_pkb;
966 struct package_PrimaryKerberosCtr4 *old_pkb4 = NULL;
968 enum ndr_err_code ndr_err;
970 ldb = ldb_module_get_ctx(io->ac->module);
973 * prepare generation of keys
975 * ENCTYPE_AES256_CTS_HMAC_SHA1_96
976 * ENCTYPE_AES128_CTS_HMAC_SHA1_96
977 * ENCTYPE_DES_CBC_MD5
978 * ENCTYPE_DES_CBC_CRC
981 pkb4->salt.string = io->g.salt;
982 pkb4->default_iteration_count = 4096;
985 pkb4->keys = talloc_array(io->ac,
986 struct package_PrimaryKerberosKey4,
992 pkb4->keys[0].iteration_count = 4096;
993 pkb4->keys[0].keytype = ENCTYPE_AES256_CTS_HMAC_SHA1_96;
994 pkb4->keys[0].value = &io->g.aes_256;
995 pkb4->keys[1].iteration_count = 4096;
996 pkb4->keys[1].keytype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
997 pkb4->keys[1].value = &io->g.aes_128;
998 pkb4->keys[2].iteration_count = 4096;
999 pkb4->keys[2].keytype = ENCTYPE_DES_CBC_MD5;
1000 pkb4->keys[2].value = &io->g.des_md5;
1001 pkb4->keys[3].iteration_count = 4096;
1002 pkb4->keys[3].keytype = ENCTYPE_DES_CBC_CRC;
1003 pkb4->keys[3].value = &io->g.des_crc;
1005 /* initialize the old keys to zero */
1006 pkb4->num_old_keys = 0;
1007 pkb4->old_keys = NULL;
1008 pkb4->num_older_keys = 0;
1009 pkb4->older_keys = NULL;
1011 /* if there're no old keys, then we're done */
1016 for (i=0; i < old_scb->sub.num_packages; i++) {
1017 if (strcmp("Primary:Kerberos-Newer-Keys", old_scb->sub.packages[i].name) != 0) {
1021 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
1025 old_scp = &old_scb->sub.packages[i];
1028 /* Primary:Kerberos-Newer-Keys element of supplementalCredentials */
1032 blob = strhex_to_data_blob(io->ac, old_scp->data);
1034 return ldb_oom(ldb);
1037 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
1038 ndr_err = ndr_pull_struct_blob(&blob, io->ac,
1040 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
1041 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1042 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1043 ldb_asprintf_errstring(ldb,
1044 "setup_primary_kerberos_newer: "
1045 "failed to pull old package_PrimaryKerberosBlob: %s",
1047 return LDB_ERR_OPERATIONS_ERROR;
1050 if (_old_pkb.version != 4) {
1051 ldb_asprintf_errstring(ldb,
1052 "setup_primary_kerberos_newer: "
1053 "package_PrimaryKerberosBlob version[%u] expected[4]",
1055 return LDB_ERR_OPERATIONS_ERROR;
1058 old_pkb4 = &_old_pkb.ctr.ctr4;
1061 /* if we didn't found the old keys we're done */
1066 /* fill in the old keys */
1067 pkb4->num_old_keys = old_pkb4->num_keys;
1068 pkb4->old_keys = old_pkb4->keys;
1069 pkb4->num_older_keys = old_pkb4->num_old_keys;
1070 pkb4->older_keys = old_pkb4->old_keys;
1075 static int setup_primary_wdigest(struct setup_password_fields_io *io,
1076 const struct supplementalCredentialsBlob *old_scb,
1077 struct package_PrimaryWDigestBlob *pdb)
1079 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1080 DATA_BLOB sAMAccountName;
1081 DATA_BLOB sAMAccountName_l;
1082 DATA_BLOB sAMAccountName_u;
1083 const char *user_principal_name = io->u.user_principal_name;
1084 DATA_BLOB userPrincipalName;
1085 DATA_BLOB userPrincipalName_l;
1086 DATA_BLOB userPrincipalName_u;
1087 DATA_BLOB netbios_domain;
1088 DATA_BLOB netbios_domain_l;
1089 DATA_BLOB netbios_domain_u;
1090 DATA_BLOB dns_domain;
1091 DATA_BLOB dns_domain_l;
1092 DATA_BLOB dns_domain_u;
1095 DATA_BLOB backslash;
1104 * http://technet2.microsoft.com/WindowsServer/en/library/717b450c-f4a0-4cc9-86f4-cc0633aae5f91033.mspx?mfr=true
1105 * for what precalculated hashes are supposed to be stored...
1107 * I can't reproduce all values which should contain "Digest" as realm,
1108 * am I doing something wrong or is w2k3 just broken...?
1110 * W2K3 fills in following for a user:
1112 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
1113 * sAMAccountName: NewUser2Sam
1114 * userPrincipalName: NewUser2Princ@sub1.w2k3.vmnet1.vm.base
1116 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1117 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
1118 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
1119 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1120 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
1121 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
1122 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
1123 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1124 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1125 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1126 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1127 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1128 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1129 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1130 * 221c55284451ae9b3aacaa2a3c86f10f => NewUser2Princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1131 * 74e1be668853d4324d38c07e2acfb8ea => (w2k3 has a bug here!) newuser2princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1132 * e1e244ab7f098e3ae1761be7f9229bbb => NEWUSER2PRINC@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
1133 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
1134 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
1135 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
1136 * 31dc704d3640335b2123d4ee28aa1f11 => ??? changes with NewUser2Sam => NewUser1Sam
1137 * 36349f5cecd07320fb3bb0e119230c43 => ??? changes with NewUser2Sam => NewUser1Sam
1138 * 12adf019d037fb535c01fd0608e78d9d => ??? changes with NewUser2Sam => NewUser1Sam
1139 * 6feecf8e724906f3ee1105819c5105a1 => ??? changes with NewUser2Princ => NewUser1Princ
1140 * 6c6911f3de6333422640221b9c51ff1f => ??? changes with NewUser2Princ => NewUser1Princ
1141 * 4b279877e742895f9348ac67a8de2f69 => ??? changes with NewUser2Princ => NewUser1Princ
1142 * db0c6bff069513e3ebb9870d29b57490 => ??? changes with NewUser2Sam => NewUser1Sam
1143 * 45072621e56b1c113a4e04a8ff68cd0e => ??? changes with NewUser2Sam => NewUser1Sam
1144 * 11d1220abc44a9c10cf91ef4a9c1de02 => ??? changes with NewUser2Sam => NewUser1Sam
1146 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
1147 * sAMAccountName: NewUser2Sam
1149 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1150 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
1151 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
1152 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1153 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
1154 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
1155 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
1156 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1157 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1158 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1159 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1160 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1161 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1162 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1163 * 8a140d30b6f0a5912735dc1e3bc993b4 => NewUser2Sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1164 * 86d95b2faae6cae4ec261e7fbaccf093 => (here w2k3 is correct) newuser2sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1165 * dfeff1493110220efcdfc6362e5f5450 => NEWUSER2SAM@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
1166 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
1167 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
1168 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
1169 * 31dc704d3640335b2123d4ee28aa1f11 => ???M1 changes with NewUser2Sam => NewUser1Sam
1170 * 36349f5cecd07320fb3bb0e119230c43 => ???M1.L changes with newuser2sam => newuser1sam
1171 * 12adf019d037fb535c01fd0608e78d9d => ???M1.U changes with NEWUSER2SAM => NEWUSER1SAM
1172 * 569b4533f2d9e580211dd040e5e360a8 => ???M2 changes with NewUser2Princ => NewUser1Princ
1173 * 52528bddf310a587c5d7e6a9ae2cbb20 => ???M2.L changes with newuser2princ => newuser1princ
1174 * 4f629a4f0361289ca4255ab0f658fcd5 => ???M3 changes with NewUser2Princ => NewUser1Princ (doesn't depend on case of userPrincipal )
1175 * db0c6bff069513e3ebb9870d29b57490 => ???M4 changes with NewUser2Sam => NewUser1Sam
1176 * 45072621e56b1c113a4e04a8ff68cd0e => ???M5 changes with NewUser2Sam => NewUser1Sam (doesn't depend on case of sAMAccountName)
1177 * 11d1220abc44a9c10cf91ef4a9c1de02 => ???M4.U changes with NEWUSER2SAM => NEWUSER1SAM
1181 * sAMAccountName, netbios_domain
1184 .user = &sAMAccountName,
1185 .realm = &netbios_domain,
1188 .user = &sAMAccountName_l,
1189 .realm = &netbios_domain_l,
1192 .user = &sAMAccountName_u,
1193 .realm = &netbios_domain_u,
1196 .user = &sAMAccountName,
1197 .realm = &netbios_domain_u,
1200 .user = &sAMAccountName,
1201 .realm = &netbios_domain_l,
1204 .user = &sAMAccountName_u,
1205 .realm = &netbios_domain_l,
1208 .user = &sAMAccountName_l,
1209 .realm = &netbios_domain_u,
1212 * sAMAccountName, dns_domain
1215 .user = &sAMAccountName,
1216 .realm = &dns_domain,
1219 .user = &sAMAccountName_l,
1220 .realm = &dns_domain_l,
1223 .user = &sAMAccountName_u,
1224 .realm = &dns_domain_u,
1227 .user = &sAMAccountName,
1228 .realm = &dns_domain_u,
1231 .user = &sAMAccountName,
1232 .realm = &dns_domain_l,
1235 .user = &sAMAccountName_u,
1236 .realm = &dns_domain_l,
1239 .user = &sAMAccountName_l,
1240 .realm = &dns_domain_u,
1243 * userPrincipalName, no realm
1246 .user = &userPrincipalName,
1250 * NOTE: w2k3 messes this up, if the user has a real userPrincipalName,
1251 * the fallback to the sAMAccountName based userPrincipalName is correct
1253 .user = &userPrincipalName_l,
1256 .user = &userPrincipalName_u,
1259 * nt4dom\sAMAccountName, no realm
1262 .user = &sAMAccountName,
1263 .nt4dom = &netbios_domain
1266 .user = &sAMAccountName_l,
1267 .nt4dom = &netbios_domain_l
1270 .user = &sAMAccountName_u,
1271 .nt4dom = &netbios_domain_u
1275 * the following ones are guessed depending on the technet2 article
1276 * but not reproducable on a w2k3 server
1278 /* sAMAccountName with "Digest" realm */
1280 .user = &sAMAccountName,
1284 .user = &sAMAccountName_l,
1288 .user = &sAMAccountName_u,
1291 /* userPrincipalName with "Digest" realm */
1293 .user = &userPrincipalName,
1297 .user = &userPrincipalName_l,
1301 .user = &userPrincipalName_u,
1304 /* nt4dom\\sAMAccountName with "Digest" realm */
1306 .user = &sAMAccountName,
1307 .nt4dom = &netbios_domain,
1311 .user = &sAMAccountName_l,
1312 .nt4dom = &netbios_domain_l,
1316 .user = &sAMAccountName_u,
1317 .nt4dom = &netbios_domain_u,
1322 /* prepare DATA_BLOB's used in the combinations array */
1323 sAMAccountName = data_blob_string_const(io->u.sAMAccountName);
1324 sAMAccountName_l = data_blob_string_const(strlower_talloc(io->ac, io->u.sAMAccountName));
1325 if (!sAMAccountName_l.data) {
1326 return ldb_oom(ldb);
1328 sAMAccountName_u = data_blob_string_const(strupper_talloc(io->ac, io->u.sAMAccountName));
1329 if (!sAMAccountName_u.data) {
1330 return ldb_oom(ldb);
1333 /* if the user doesn't have a userPrincipalName, create one (with lower case realm) */
1334 if (!user_principal_name) {
1335 user_principal_name = talloc_asprintf(io->ac, "%s@%s",
1336 io->u.sAMAccountName,
1337 io->ac->status->domain_data.dns_domain);
1338 if (!user_principal_name) {
1339 return ldb_oom(ldb);
1342 userPrincipalName = data_blob_string_const(user_principal_name);
1343 userPrincipalName_l = data_blob_string_const(strlower_talloc(io->ac, user_principal_name));
1344 if (!userPrincipalName_l.data) {
1345 return ldb_oom(ldb);
1347 userPrincipalName_u = data_blob_string_const(strupper_talloc(io->ac, user_principal_name));
1348 if (!userPrincipalName_u.data) {
1349 return ldb_oom(ldb);
1352 netbios_domain = data_blob_string_const(io->ac->status->domain_data.netbios_domain);
1353 netbios_domain_l = data_blob_string_const(strlower_talloc(io->ac,
1354 io->ac->status->domain_data.netbios_domain));
1355 if (!netbios_domain_l.data) {
1356 return ldb_oom(ldb);
1358 netbios_domain_u = data_blob_string_const(strupper_talloc(io->ac,
1359 io->ac->status->domain_data.netbios_domain));
1360 if (!netbios_domain_u.data) {
1361 return ldb_oom(ldb);
1364 dns_domain = data_blob_string_const(io->ac->status->domain_data.dns_domain);
1365 dns_domain_l = data_blob_string_const(io->ac->status->domain_data.dns_domain);
1366 dns_domain_u = data_blob_string_const(io->ac->status->domain_data.realm);
1368 digest = data_blob_string_const("Digest");
1370 delim = data_blob_string_const(":");
1371 backslash = data_blob_string_const("\\");
1373 pdb->num_hashes = ARRAY_SIZE(wdigest);
1374 pdb->hashes = talloc_array(io->ac, struct package_PrimaryWDigestHash,
1377 return ldb_oom(ldb);
1380 for (i=0; i < ARRAY_SIZE(wdigest); i++) {
1383 if (wdigest[i].nt4dom) {
1384 MD5Update(&md5, wdigest[i].nt4dom->data, wdigest[i].nt4dom->length);
1385 MD5Update(&md5, backslash.data, backslash.length);
1387 MD5Update(&md5, wdigest[i].user->data, wdigest[i].user->length);
1388 MD5Update(&md5, delim.data, delim.length);
1389 if (wdigest[i].realm) {
1390 MD5Update(&md5, wdigest[i].realm->data, wdigest[i].realm->length);
1392 MD5Update(&md5, delim.data, delim.length);
1393 MD5Update(&md5, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length);
1394 MD5Final(pdb->hashes[i].hash, &md5);
1400 static int setup_supplemental_field(struct setup_password_fields_io *io)
1402 struct ldb_context *ldb;
1403 struct supplementalCredentialsBlob scb;
1404 struct supplementalCredentialsBlob *old_scb = NULL;
1405 /* Packages + (Kerberos-Newer-Keys, Kerberos, WDigest and CLEARTEXT) */
1406 uint32_t num_names = 0;
1407 const char *names[1+4];
1408 uint32_t num_packages = 0;
1409 struct supplementalCredentialsPackage packages[1+4];
1411 struct supplementalCredentialsPackage *pp = NULL;
1412 struct package_PackagesBlob pb;
1415 /* Primary:Kerberos-Newer-Keys */
1416 const char **nkn = NULL;
1417 struct supplementalCredentialsPackage *pkn = NULL;
1418 struct package_PrimaryKerberosBlob pknb;
1419 DATA_BLOB pknb_blob;
1421 /* Primary:Kerberos */
1422 const char **nk = NULL;
1423 struct supplementalCredentialsPackage *pk = NULL;
1424 struct package_PrimaryKerberosBlob pkb;
1427 /* Primary:WDigest */
1428 const char **nd = NULL;
1429 struct supplementalCredentialsPackage *pd = NULL;
1430 struct package_PrimaryWDigestBlob pdb;
1433 /* Primary:CLEARTEXT */
1434 const char **nc = NULL;
1435 struct supplementalCredentialsPackage *pc = NULL;
1436 struct package_PrimaryCLEARTEXTBlob pcb;
1440 enum ndr_err_code ndr_err;
1442 bool do_newer_keys = false;
1443 bool do_cleartext = false;
1445 ZERO_STRUCT(zero16);
1448 ldb = ldb_module_get_ctx(io->ac->module);
1450 if (!io->n.cleartext_utf8) {
1452 * when we don't have a cleartext password
1453 * we can't setup a supplementalCredential value
1458 /* if there's an old supplementaCredentials blob then use it */
1459 if (io->o.supplemental) {
1460 if (io->o.scb.sub.signature == SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
1461 old_scb = &io->o.scb;
1463 ldb_debug(ldb, LDB_DEBUG_ERROR,
1464 "setup_supplemental_field: "
1465 "supplementalCredentialsBlob "
1466 "signature[0x%04X] expected[0x%04X]",
1467 io->o.scb.sub.signature,
1468 SUPPLEMENTAL_CREDENTIALS_SIGNATURE);
1471 /* Per MS-SAMR 3.1.1.8.11.6 we create AES keys if our domain functionality level is 2008 or higher */
1472 do_newer_keys = (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008);
1474 if (io->ac->status->domain_data.store_cleartext &&
1475 (io->u.userAccountControl & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) {
1476 do_cleartext = true;
1480 * The ordering is this
1482 * Primary:Kerberos-Newer-Keys (optional)
1485 * Primary:CLEARTEXT (optional)
1487 * And the 'Packages' package is insert before the last
1490 if (do_newer_keys) {
1491 /* Primary:Kerberos-Newer-Keys */
1492 nkn = &names[num_names++];
1493 pkn = &packages[num_packages++];
1496 /* Primary:Kerberos */
1497 nk = &names[num_names++];
1498 pk = &packages[num_packages++];
1500 if (!do_cleartext) {
1502 pp = &packages[num_packages++];
1505 /* Primary:WDigest */
1506 nd = &names[num_names++];
1507 pd = &packages[num_packages++];
1511 pp = &packages[num_packages++];
1513 /* Primary:CLEARTEXT */
1514 nc = &names[num_names++];
1515 pc = &packages[num_packages++];
1520 * setup 'Primary:Kerberos-Newer-Keys' element
1522 *nkn = "Kerberos-Newer-Keys";
1524 ret = setup_primary_kerberos_newer(io, old_scb, &pknb);
1525 if (ret != LDB_SUCCESS) {
1529 ndr_err = ndr_push_struct_blob(&pknb_blob, io->ac,
1531 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1532 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1533 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1534 ldb_asprintf_errstring(ldb,
1535 "setup_supplemental_field: "
1536 "failed to push package_PrimaryKerberosNeverBlob: %s",
1538 return LDB_ERR_OPERATIONS_ERROR;
1540 pknb_hexstr = data_blob_hex_string_upper(io->ac, &pknb_blob);
1542 return ldb_oom(ldb);
1544 pkn->name = "Primary:Kerberos-Newer-Keys";
1546 pkn->data = pknb_hexstr;
1550 * setup 'Primary:Kerberos' element
1554 ret = setup_primary_kerberos(io, old_scb, &pkb);
1555 if (ret != LDB_SUCCESS) {
1559 ndr_err = ndr_push_struct_blob(&pkb_blob, io->ac,
1561 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1562 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1563 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1564 ldb_asprintf_errstring(ldb,
1565 "setup_supplemental_field: "
1566 "failed to push package_PrimaryKerberosBlob: %s",
1568 return LDB_ERR_OPERATIONS_ERROR;
1570 pkb_hexstr = data_blob_hex_string_upper(io->ac, &pkb_blob);
1572 return ldb_oom(ldb);
1574 pk->name = "Primary:Kerberos";
1576 pk->data = pkb_hexstr;
1579 * setup 'Primary:WDigest' element
1583 ret = setup_primary_wdigest(io, old_scb, &pdb);
1584 if (ret != LDB_SUCCESS) {
1588 ndr_err = ndr_push_struct_blob(&pdb_blob, io->ac,
1590 (ndr_push_flags_fn_t)ndr_push_package_PrimaryWDigestBlob);
1591 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1592 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1593 ldb_asprintf_errstring(ldb,
1594 "setup_supplemental_field: "
1595 "failed to push package_PrimaryWDigestBlob: %s",
1597 return LDB_ERR_OPERATIONS_ERROR;
1599 pdb_hexstr = data_blob_hex_string_upper(io->ac, &pdb_blob);
1601 return ldb_oom(ldb);
1603 pd->name = "Primary:WDigest";
1605 pd->data = pdb_hexstr;
1608 * setup 'Primary:CLEARTEXT' element
1613 pcb.cleartext = *io->n.cleartext_utf16;
1615 ndr_err = ndr_push_struct_blob(&pcb_blob, io->ac,
1617 (ndr_push_flags_fn_t)ndr_push_package_PrimaryCLEARTEXTBlob);
1618 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1619 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1620 ldb_asprintf_errstring(ldb,
1621 "setup_supplemental_field: "
1622 "failed to push package_PrimaryCLEARTEXTBlob: %s",
1624 return LDB_ERR_OPERATIONS_ERROR;
1626 pcb_hexstr = data_blob_hex_string_upper(io->ac, &pcb_blob);
1628 return ldb_oom(ldb);
1630 pc->name = "Primary:CLEARTEXT";
1632 pc->data = pcb_hexstr;
1636 * setup 'Packages' element
1639 ndr_err = ndr_push_struct_blob(&pb_blob, io->ac,
1641 (ndr_push_flags_fn_t)ndr_push_package_PackagesBlob);
1642 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1643 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1644 ldb_asprintf_errstring(ldb,
1645 "setup_supplemental_field: "
1646 "failed to push package_PackagesBlob: %s",
1648 return LDB_ERR_OPERATIONS_ERROR;
1650 pb_hexstr = data_blob_hex_string_upper(io->ac, &pb_blob);
1652 return ldb_oom(ldb);
1654 pp->name = "Packages";
1656 pp->data = pb_hexstr;
1659 * setup 'supplementalCredentials' value
1662 scb.sub.num_packages = num_packages;
1663 scb.sub.packages = packages;
1665 ndr_err = ndr_push_struct_blob(&io->g.supplemental, io->ac,
1667 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
1668 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1669 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1670 ldb_asprintf_errstring(ldb,
1671 "setup_supplemental_field: "
1672 "failed to push supplementalCredentialsBlob: %s",
1674 return LDB_ERR_OPERATIONS_ERROR;
1680 static int setup_last_set_field(struct setup_password_fields_io *io)
1682 const struct ldb_message *msg = NULL;
1683 struct timeval tv = { .tv_sec = 0 };
1685 switch (io->ac->req->operation) {
1687 msg = io->ac->req->op.add.message;
1690 msg = io->ac->req->op.mod.message;
1693 return LDB_ERR_OPERATIONS_ERROR;
1697 if (io->ac->pwd_last_set_bypass) {
1698 struct ldb_message_element *el;
1701 return LDB_ERR_CONSTRAINT_VIOLATION;
1704 el = ldb_msg_find_element(msg, "pwdLastSet");
1706 return LDB_ERR_CONSTRAINT_VIOLATION;
1709 io->g.last_set = samdb_result_nttime(msg, "pwdLastSet", 0);
1715 io->g.last_set = timeval_to_nttime(&tv);
1720 static int setup_given_passwords(struct setup_password_fields_io *io,
1721 struct setup_password_fields_given *g)
1723 struct ldb_context *ldb;
1726 ldb = ldb_module_get_ctx(io->ac->module);
1728 if (g->cleartext_utf8) {
1729 struct ldb_val *cleartext_utf16_blob;
1731 cleartext_utf16_blob = talloc(io->ac, struct ldb_val);
1732 if (!cleartext_utf16_blob) {
1733 return ldb_oom(ldb);
1735 if (!convert_string_talloc(io->ac,
1737 g->cleartext_utf8->data,
1738 g->cleartext_utf8->length,
1739 (void *)&cleartext_utf16_blob->data,
1740 &cleartext_utf16_blob->length)) {
1741 if (g->cleartext_utf8->length != 0) {
1742 talloc_free(cleartext_utf16_blob);
1743 ldb_asprintf_errstring(ldb,
1744 "setup_password_fields: "
1745 "failed to generate UTF16 password from cleartext UTF8 one for user '%s'!",
1746 io->u.sAMAccountName);
1747 return LDB_ERR_CONSTRAINT_VIOLATION;
1749 /* passwords with length "0" are valid! */
1750 cleartext_utf16_blob->data = NULL;
1751 cleartext_utf16_blob->length = 0;
1754 g->cleartext_utf16 = cleartext_utf16_blob;
1755 } else if (g->cleartext_utf16) {
1756 struct ldb_val *cleartext_utf8_blob;
1758 cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
1759 if (!cleartext_utf8_blob) {
1760 return ldb_oom(ldb);
1762 if (!convert_string_talloc(io->ac,
1763 CH_UTF16MUNGED, CH_UTF8,
1764 g->cleartext_utf16->data,
1765 g->cleartext_utf16->length,
1766 (void *)&cleartext_utf8_blob->data,
1767 &cleartext_utf8_blob->length)) {
1768 if (g->cleartext_utf16->length != 0) {
1769 /* We must bail out here, the input wasn't even
1770 * a multiple of 2 bytes */
1771 talloc_free(cleartext_utf8_blob);
1772 ldb_asprintf_errstring(ldb,
1773 "setup_password_fields: "
1774 "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)!",
1775 io->u.sAMAccountName);
1776 return LDB_ERR_CONSTRAINT_VIOLATION;
1778 /* passwords with length "0" are valid! */
1779 cleartext_utf8_blob->data = NULL;
1780 cleartext_utf8_blob->length = 0;
1783 g->cleartext_utf8 = cleartext_utf8_blob;
1786 if (g->cleartext_utf16) {
1787 struct samr_Password *nt_hash;
1789 nt_hash = talloc(io->ac, struct samr_Password);
1791 return ldb_oom(ldb);
1793 g->nt_hash = nt_hash;
1795 /* compute the new nt hash */
1796 mdfour(nt_hash->hash,
1797 g->cleartext_utf16->data,
1798 g->cleartext_utf16->length);
1801 if (g->cleartext_utf8) {
1802 struct samr_Password *lm_hash;
1804 lm_hash = talloc(io->ac, struct samr_Password);
1806 return ldb_oom(ldb);
1809 /* compute the new lm hash */
1810 ok = E_deshash((char *)g->cleartext_utf8->data, lm_hash->hash);
1812 g->lm_hash = lm_hash;
1814 talloc_free(lm_hash);
1821 static int setup_password_fields(struct setup_password_fields_io *io)
1823 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1824 struct loadparm_context *lp_ctx =
1825 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
1826 struct loadparm_context);
1829 /* transform the old password (for password changes) */
1830 ret = setup_given_passwords(io, &io->og);
1831 if (ret != LDB_SUCCESS) {
1835 /* transform the new password */
1836 ret = setup_given_passwords(io, &io->n);
1837 if (ret != LDB_SUCCESS) {
1841 if (io->n.cleartext_utf8) {
1842 ret = setup_kerberos_keys(io);
1843 if (ret != LDB_SUCCESS) {
1848 ret = setup_nt_fields(io);
1849 if (ret != LDB_SUCCESS) {
1853 if (lpcfg_lanman_auth(lp_ctx)) {
1854 ret = setup_lm_fields(io);
1855 if (ret != LDB_SUCCESS) {
1859 io->g.lm_hash = NULL;
1860 io->g.lm_history_len = 0;
1863 ret = setup_supplemental_field(io);
1864 if (ret != LDB_SUCCESS) {
1868 ret = setup_last_set_field(io);
1869 if (ret != LDB_SUCCESS) {
1876 static int make_error_and_update_badPwdCount(struct setup_password_fields_io *io)
1878 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1879 struct ldb_message *mod_msg = NULL;
1883 status = dsdb_update_bad_pwd_count(io->ac, ldb,
1884 io->ac->search_res->message,
1885 io->ac->dom_res->message,
1887 if (!NT_STATUS_IS_OK(status)) {
1891 if (mod_msg == NULL) {
1896 * OK, horrible semantics ahead.
1898 * - We need to abort any existing transaction
1899 * - create a transaction arround the badPwdCount update
1900 * - re-open the transaction so the upper layer
1901 * doesn't know what happened.
1903 * This is needed because returning an error to the upper
1904 * layer will cancel the transaction and undo the badPwdCount
1909 * Checking errors here is a bit pointless.
1910 * What can we do if we can't end the transaction?
1912 ret = ldb_next_del_trans(io->ac->module);
1913 if (ret != LDB_SUCCESS) {
1914 ldb_debug(ldb, LDB_DEBUG_FATAL,
1915 "Failed to abort transaction prior to update of badPwdCount of %s: %s",
1916 ldb_dn_get_linearized(io->ac->search_res->message->dn),
1917 ldb_errstring(ldb));
1919 * just return the original error
1924 /* Likewise, what should we do if we can't open a new transaction? */
1925 ret = ldb_next_start_trans(io->ac->module);
1926 if (ret != LDB_SUCCESS) {
1927 ldb_debug(ldb, LDB_DEBUG_ERROR,
1928 "Failed to open transaction to update badPwdCount of %s: %s",
1929 ldb_dn_get_linearized(io->ac->search_res->message->dn),
1930 ldb_errstring(ldb));
1932 * just return the original error
1937 ret = dsdb_module_modify(io->ac->module, mod_msg,
1938 DSDB_FLAG_NEXT_MODULE,
1940 if (ret != LDB_SUCCESS) {
1941 ldb_debug(ldb, LDB_DEBUG_ERROR,
1942 "Failed to update badPwdCount of %s: %s",
1943 ldb_dn_get_linearized(io->ac->search_res->message->dn),
1944 ldb_errstring(ldb));
1946 * We can only ignore this...
1950 ret = ldb_next_end_trans(io->ac->module);
1951 if (ret != LDB_SUCCESS) {
1952 ldb_debug(ldb, LDB_DEBUG_ERROR,
1953 "Failed to close transaction to update badPwdCount of %s: %s",
1954 ldb_dn_get_linearized(io->ac->search_res->message->dn),
1955 ldb_errstring(ldb));
1957 * We can only ignore this...
1961 ret = ldb_next_start_trans(io->ac->module);
1962 if (ret != LDB_SUCCESS) {
1963 ldb_debug(ldb, LDB_DEBUG_ERROR,
1964 "Failed to open transaction after update of badPwdCount of %s: %s",
1965 ldb_dn_get_linearized(io->ac->search_res->message->dn),
1966 ldb_errstring(ldb));
1968 * We can only ignore this...
1973 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1974 ldb_asprintf_errstring(ldb,
1975 "%08X: %s - check_password_restrictions: "
1976 "The old password specified doesn't match!",
1977 W_ERROR_V(WERR_INVALID_PASSWORD),
1982 static int check_password_restrictions(struct setup_password_fields_io *io)
1984 struct ldb_context *ldb;
1987 ldb = ldb_module_get_ctx(io->ac->module);
1989 /* First check the old password is correct, for password changes */
1990 if (!io->ac->pwd_reset) {
1991 bool nt_hash_checked = false;
1993 /* we need the old nt or lm hash given by the client */
1994 if (!io->og.nt_hash && !io->og.lm_hash) {
1995 ldb_asprintf_errstring(ldb,
1996 "check_password_restrictions: "
1997 "You need to provide the old password in order "
1999 return LDB_ERR_UNWILLING_TO_PERFORM;
2002 /* The password modify through the NT hash is encouraged and
2003 has no problems at all */
2004 if (io->og.nt_hash) {
2005 if (!io->o.nt_hash || memcmp(io->og.nt_hash->hash, io->o.nt_hash->hash, 16) != 0) {
2006 return make_error_and_update_badPwdCount(io);
2009 nt_hash_checked = true;
2012 /* But it is also possible to change a password by the LM hash
2013 * alone for compatibility reasons. This check is optional if
2014 * the NT hash was already checked - otherwise it's mandatory.
2015 * (as the SAMR operations request it). */
2016 if (io->og.lm_hash) {
2017 if ((!io->o.lm_hash && !nt_hash_checked)
2018 || (io->o.lm_hash && memcmp(io->og.lm_hash->hash, io->o.lm_hash->hash, 16) != 0)) {
2019 return make_error_and_update_badPwdCount(io);
2024 if (io->u.restrictions == 0) {
2025 /* FIXME: Is this right? */
2029 /* Password minimum age: yes, this is a minus. The ages are in negative 100nsec units! */
2030 if ((io->u.pwdLastSet - io->ac->status->domain_data.minPwdAge > io->g.last_set) &&
2033 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2034 ldb_asprintf_errstring(ldb,
2035 "%08X: %s - check_password_restrictions: "
2036 "password is too young to change!",
2037 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2043 * Fundamental password checks done by the call
2044 * "samdb_check_password".
2045 * It is also in use by "dcesrv_samr_ValidatePassword".
2047 if (io->n.cleartext_utf8 != NULL) {
2048 enum samr_ValidationStatus vstat;
2049 vstat = samdb_check_password(io->n.cleartext_utf8,
2050 io->ac->status->domain_data.pwdProperties,
2051 io->ac->status->domain_data.minPwdLength);
2053 case SAMR_VALIDATION_STATUS_SUCCESS:
2054 /* perfect -> proceed! */
2057 case SAMR_VALIDATION_STATUS_PWD_TOO_SHORT:
2058 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2059 ldb_asprintf_errstring(ldb,
2060 "%08X: %s - check_password_restrictions: "
2061 "the password is too short. It should be equal or longer than %u characters!",
2062 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2064 io->ac->status->domain_data.minPwdLength);
2065 io->ac->status->reject_reason = SAM_PWD_CHANGE_PASSWORD_TOO_SHORT;
2068 case SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH:
2069 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2070 ldb_asprintf_errstring(ldb,
2071 "%08X: %s - check_password_restrictions: "
2072 "the password does not meet the complexity criteria!",
2073 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2075 io->ac->status->reject_reason = SAM_PWD_CHANGE_NOT_COMPLEX;
2079 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2080 ldb_asprintf_errstring(ldb,
2081 "%08X: %s - check_password_restrictions: "
2082 "the password doesn't fit by a certain reason!",
2083 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2089 if (io->ac->pwd_reset) {
2093 if (io->n.nt_hash) {
2096 /* checks the NT hash password history */
2097 for (i = 0; i < io->o.nt_history_len; i++) {
2098 ret = memcmp(io->n.nt_hash, io->o.nt_history[i].hash, 16);
2100 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2101 ldb_asprintf_errstring(ldb,
2102 "%08X: %s - check_password_restrictions: "
2103 "the password was already used (in history)!",
2104 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2106 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
2112 if (io->n.lm_hash) {
2115 /* checks the LM hash password history */
2116 for (i = 0; i < io->o.lm_history_len; i++) {
2117 ret = memcmp(io->n.lm_hash, io->o.lm_history[i].hash, 16);
2119 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2120 ldb_asprintf_errstring(ldb,
2121 "%08X: %s - check_password_restrictions: "
2122 "the password was already used (in history)!",
2123 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2125 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
2131 /* are all password changes disallowed? */
2132 if (io->ac->status->domain_data.pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
2133 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2134 ldb_asprintf_errstring(ldb,
2135 "%08X: %s - check_password_restrictions: "
2136 "password changes disabled!",
2137 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2142 /* can this user change the password? */
2143 if (io->u.userAccountControl & UF_PASSWD_CANT_CHANGE) {
2144 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2145 ldb_asprintf_errstring(ldb,
2146 "%08X: %s - check_password_restrictions: "
2147 "password can't be changed on this account!",
2148 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2156 static int update_final_msg(struct setup_password_fields_io *io)
2158 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2162 if (io->ac->req->operation == LDB_MODIFY) {
2163 el_flags |= LDB_FLAG_MOD_REPLACE;
2166 /* make sure we replace all the old attributes */
2167 if (io->ac->update_password && el_flags != 0) {
2168 ret = ldb_msg_add_empty(io->ac->update_msg,
2171 if (ret != LDB_SUCCESS) {
2174 ret = ldb_msg_add_empty(io->ac->update_msg,
2177 if (ret != LDB_SUCCESS) {
2180 ret = ldb_msg_add_empty(io->ac->update_msg,
2183 if (ret != LDB_SUCCESS) {
2186 ret = ldb_msg_add_empty(io->ac->update_msg,
2189 if (ret != LDB_SUCCESS) {
2192 ret = ldb_msg_add_empty(io->ac->update_msg,
2193 "supplementalCredentials",
2195 if (ret != LDB_SUCCESS) {
2199 if (io->ac->update_lastset && el_flags != 0) {
2200 ret = ldb_msg_add_empty(io->ac->update_msg,
2203 if (ret != LDB_SUCCESS) {
2208 if (io->g.nt_hash != NULL) {
2209 ret = samdb_msg_add_hash(ldb, io->ac,
2213 if (ret != LDB_SUCCESS) {
2217 if (io->g.lm_hash != NULL) {
2218 ret = samdb_msg_add_hash(ldb, io->ac,
2222 if (ret != LDB_SUCCESS) {
2226 if (io->g.nt_history_len > 0) {
2227 ret = samdb_msg_add_hashes(ldb, io->ac,
2231 io->g.nt_history_len);
2232 if (ret != LDB_SUCCESS) {
2236 if (io->g.lm_history_len > 0) {
2237 ret = samdb_msg_add_hashes(ldb, io->ac,
2241 io->g.lm_history_len);
2242 if (ret != LDB_SUCCESS) {
2246 if (io->g.supplemental.length > 0) {
2247 ret = ldb_msg_add_value(io->ac->update_msg,
2248 "supplementalCredentials",
2249 &io->g.supplemental, NULL);
2250 if (ret != LDB_SUCCESS) {
2254 ret = samdb_msg_add_uint64(ldb, io->ac,
2258 if (ret != LDB_SUCCESS) {
2266 * This is intended for use by the "password_hash" module since there
2267 * password changes can be specified through one message element with the
2268 * new password (to set) and another one with the old password (to unset).
2270 * The first which sets a password (new value) can have flags
2271 * (LDB_FLAG_MOD_ADD, LDB_FLAG_MOD_REPLACE) but also none (on "add" operations
2272 * for entries). The latter (old value) has always specified
2273 * LDB_FLAG_MOD_DELETE.
2275 * Returns LDB_ERR_CONSTRAINT_VIOLATION and LDB_ERR_UNWILLING_TO_PERFORM if
2276 * matching message elements are malformed in respect to the set/change rules.
2277 * Otherwise it returns LDB_SUCCESS.
2279 static int msg_find_old_and_new_pwd_val(const struct ldb_message *msg,
2281 enum ldb_request_type operation,
2282 const struct ldb_val **new_val,
2283 const struct ldb_val **old_val)
2294 for (i = 0; i < msg->num_elements; i++) {
2295 if (ldb_attr_cmp(msg->elements[i].name, name) != 0) {
2299 if ((operation == LDB_MODIFY) &&
2300 (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_DELETE)) {
2301 /* 0 values are allowed */
2302 if (msg->elements[i].num_values == 1) {
2303 *old_val = &msg->elements[i].values[0];
2304 } else if (msg->elements[i].num_values > 1) {
2305 return LDB_ERR_CONSTRAINT_VIOLATION;
2307 } else if ((operation == LDB_MODIFY) &&
2308 (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_REPLACE)) {
2309 if (msg->elements[i].num_values > 0) {
2310 *new_val = &msg->elements[i].values[msg->elements[i].num_values - 1];
2312 return LDB_ERR_UNWILLING_TO_PERFORM;
2315 /* Add operations and LDB_FLAG_MOD_ADD */
2316 if (msg->elements[i].num_values > 0) {
2317 *new_val = &msg->elements[i].values[msg->elements[i].num_values - 1];
2319 return LDB_ERR_CONSTRAINT_VIOLATION;
2327 static int setup_io(struct ph_context *ac,
2328 const struct ldb_message *client_msg,
2329 const struct ldb_message *existing_msg,
2330 struct setup_password_fields_io *io)
2332 const struct ldb_val *quoted_utf16, *old_quoted_utf16, *lm_hash, *old_lm_hash;
2333 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2334 struct loadparm_context *lp_ctx = talloc_get_type(
2335 ldb_get_opaque(ldb, "loadparm"), struct loadparm_context);
2337 const struct ldb_message *info_msg = NULL;
2341 /* Some operations below require kerberos contexts */
2343 if (existing_msg != NULL) {
2345 * This is a modify operation
2347 info_msg = existing_msg;
2350 * This is an add operation
2352 info_msg = client_msg;
2355 if (smb_krb5_init_context(ac,
2356 (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"),
2357 &io->smb_krb5_context) != 0) {
2358 return ldb_operr(ldb);
2363 io->u.userAccountControl = ldb_msg_find_attr_as_uint(info_msg,
2364 "userAccountControl", 0);
2365 if (info_msg == existing_msg) {
2367 * We only take pwdLastSet from the existing object
2368 * otherwise we leave it as 0.
2370 io->u.pwdLastSet = samdb_result_nttime(info_msg, "pwdLastSet", 0);
2372 io->u.sAMAccountName = ldb_msg_find_attr_as_string(info_msg,
2373 "sAMAccountName", NULL);
2374 io->u.user_principal_name = ldb_msg_find_attr_as_string(info_msg,
2375 "userPrincipalName", NULL);
2376 io->u.is_computer = ldb_msg_check_string_attribute(info_msg, "objectClass", "computer");
2378 if (io->u.sAMAccountName == NULL) {
2379 ldb_asprintf_errstring(ldb,
2380 "setup_io: sAMAccountName attribute is missing on %s for attempted password set/change",
2381 ldb_dn_get_linearized(info_msg->dn));
2383 return LDB_ERR_CONSTRAINT_VIOLATION;
2386 if (io->u.userAccountControl & UF_INTERDOMAIN_TRUST_ACCOUNT) {
2387 struct ldb_control *permit_trust = ldb_request_get_control(ac->req,
2388 DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID);
2390 if (permit_trust == NULL) {
2391 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2392 ldb_asprintf_errstring(ldb,
2393 "%08X: %s - setup_io: changing the interdomain trust password "
2394 "on %s not allowed via LDAP. Use LSA or NETLOGON",
2395 W_ERROR_V(WERR_ACCESS_DENIED),
2397 ldb_dn_get_linearized(info_msg->dn));
2402 /* Only non-trust accounts have restrictions (possibly this test is the
2403 * wrong way around, but we like to be restrictive if possible */
2404 io->u.restrictions = !(io->u.userAccountControl
2405 & (UF_INTERDOMAIN_TRUST_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT
2406 | UF_SERVER_TRUST_ACCOUNT));
2408 if (ac->userPassword) {
2409 ret = msg_find_old_and_new_pwd_val(client_msg, "userPassword",
2411 &io->n.cleartext_utf8,
2412 &io->og.cleartext_utf8);
2413 if (ret != LDB_SUCCESS) {
2414 ldb_asprintf_errstring(ldb,
2416 "it's only allowed to set the old password once!");
2421 if (io->n.cleartext_utf8 != NULL) {
2422 struct ldb_val *cleartext_utf8_blob;
2425 cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
2426 if (!cleartext_utf8_blob) {
2427 return ldb_oom(ldb);
2430 *cleartext_utf8_blob = *io->n.cleartext_utf8;
2432 /* make sure we have a null terminated string */
2433 p = talloc_strndup(cleartext_utf8_blob,
2434 (const char *)io->n.cleartext_utf8->data,
2435 io->n.cleartext_utf8->length);
2436 if ((p == NULL) && (io->n.cleartext_utf8->length > 0)) {
2437 return ldb_oom(ldb);
2439 cleartext_utf8_blob->data = (uint8_t *)p;
2441 io->n.cleartext_utf8 = cleartext_utf8_blob;
2444 ret = msg_find_old_and_new_pwd_val(client_msg, "clearTextPassword",
2446 &io->n.cleartext_utf16,
2447 &io->og.cleartext_utf16);
2448 if (ret != LDB_SUCCESS) {
2449 ldb_asprintf_errstring(ldb,
2451 "it's only allowed to set the old password once!");
2455 /* this rather strange looking piece of code is there to
2456 handle a ldap client setting a password remotely using the
2457 unicodePwd ldap field. The syntax is that the password is
2458 in UTF-16LE, with a " at either end. Unfortunately the
2459 unicodePwd field is also used to store the nt hashes
2460 internally in Samba, and is used in the nt hash format on
2461 the wire in DRS replication, so we have a single name for
2462 two distinct values. The code below leaves us with a small
2463 chance (less than 1 in 2^32) of a mixup, if someone manages
2464 to create a MD4 hash which starts and ends in 0x22 0x00, as
2465 that would then be treated as a UTF16 password rather than
2468 ret = msg_find_old_and_new_pwd_val(client_msg, "unicodePwd",
2472 if (ret != LDB_SUCCESS) {
2473 ldb_asprintf_errstring(ldb,
2475 "it's only allowed to set the old password once!");
2479 /* Checks and converts the actual "unicodePwd" attribute */
2480 if (!ac->hash_values &&
2482 quoted_utf16->length >= 4 &&
2483 quoted_utf16->data[0] == '"' &&
2484 quoted_utf16->data[1] == 0 &&
2485 quoted_utf16->data[quoted_utf16->length-2] == '"' &&
2486 quoted_utf16->data[quoted_utf16->length-1] == 0) {
2487 struct ldb_val *quoted_utf16_2;
2489 if (io->n.cleartext_utf16) {
2490 /* refuse the change if someone wants to change with
2491 with both UTF16 possibilities at the same time... */
2492 ldb_asprintf_errstring(ldb,
2494 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
2495 return LDB_ERR_UNWILLING_TO_PERFORM;
2499 * adapt the quoted UTF16 string to be a real
2502 quoted_utf16_2 = talloc(io->ac, struct ldb_val);
2503 if (quoted_utf16_2 == NULL) {
2504 return ldb_oom(ldb);
2507 quoted_utf16_2->data = quoted_utf16->data + 2;
2508 quoted_utf16_2->length = quoted_utf16->length-4;
2509 io->n.cleartext_utf16 = quoted_utf16_2;
2510 io->n.nt_hash = NULL;
2512 } else if (quoted_utf16) {
2513 /* We have only the hash available -> so no plaintext here */
2514 if (!ac->hash_values) {
2515 /* refuse the change if someone wants to change
2516 the hash without control specified... */
2517 ldb_asprintf_errstring(ldb,
2519 "it's not allowed to set the NT hash password directly'");
2520 /* this looks odd but this is what Windows does:
2521 returns "UNWILLING_TO_PERFORM" on wrong
2522 password sets and "CONSTRAINT_VIOLATION" on
2523 wrong password changes. */
2524 if (old_quoted_utf16 == NULL) {
2525 return LDB_ERR_UNWILLING_TO_PERFORM;
2528 return LDB_ERR_CONSTRAINT_VIOLATION;
2531 io->n.nt_hash = talloc(io->ac, struct samr_Password);
2532 memcpy(io->n.nt_hash->hash, quoted_utf16->data,
2533 MIN(quoted_utf16->length, sizeof(io->n.nt_hash->hash)));
2536 /* Checks and converts the previous "unicodePwd" attribute */
2537 if (!ac->hash_values &&
2539 old_quoted_utf16->length >= 4 &&
2540 old_quoted_utf16->data[0] == '"' &&
2541 old_quoted_utf16->data[1] == 0 &&
2542 old_quoted_utf16->data[old_quoted_utf16->length-2] == '"' &&
2543 old_quoted_utf16->data[old_quoted_utf16->length-1] == 0) {
2544 struct ldb_val *old_quoted_utf16_2;
2546 if (io->og.cleartext_utf16) {
2547 /* refuse the change if someone wants to change with
2548 both UTF16 possibilities at the same time... */
2549 ldb_asprintf_errstring(ldb,
2551 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
2552 return LDB_ERR_UNWILLING_TO_PERFORM;
2556 * adapt the quoted UTF16 string to be a real
2559 old_quoted_utf16_2 = talloc(io->ac, struct ldb_val);
2560 if (old_quoted_utf16_2 == NULL) {
2561 return ldb_oom(ldb);
2564 old_quoted_utf16_2->data = old_quoted_utf16->data + 2;
2565 old_quoted_utf16_2->length = old_quoted_utf16->length-4;
2567 io->og.cleartext_utf16 = old_quoted_utf16_2;
2568 io->og.nt_hash = NULL;
2569 } else if (old_quoted_utf16) {
2570 /* We have only the hash available -> so no plaintext here */
2571 if (!ac->hash_values) {
2572 /* refuse the change if someone wants to change
2573 the hash without control specified... */
2574 ldb_asprintf_errstring(ldb,
2576 "it's not allowed to set the NT hash password directly'");
2577 return LDB_ERR_UNWILLING_TO_PERFORM;
2580 io->og.nt_hash = talloc(io->ac, struct samr_Password);
2581 memcpy(io->og.nt_hash->hash, old_quoted_utf16->data,
2582 MIN(old_quoted_utf16->length, sizeof(io->og.nt_hash->hash)));
2585 /* Handles the "dBCSPwd" attribute (LM hash) */
2586 io->n.lm_hash = NULL; io->og.lm_hash = NULL;
2587 ret = msg_find_old_and_new_pwd_val(client_msg, "dBCSPwd",
2589 &lm_hash, &old_lm_hash);
2590 if (ret != LDB_SUCCESS) {
2591 ldb_asprintf_errstring(ldb,
2593 "it's only allowed to set the old password once!");
2597 if (((lm_hash != NULL) || (old_lm_hash != NULL)) && (!ac->hash_values)) {
2598 /* refuse the change if someone wants to change the hash
2599 without control specified... */
2600 ldb_asprintf_errstring(ldb,
2602 "it's not allowed to set the LM hash password directly'");
2603 return LDB_ERR_UNWILLING_TO_PERFORM;
2606 if (lpcfg_lanman_auth(lp_ctx) && (lm_hash != NULL)) {
2607 io->n.lm_hash = talloc(io->ac, struct samr_Password);
2608 memcpy(io->n.lm_hash->hash, lm_hash->data, MIN(lm_hash->length,
2609 sizeof(io->n.lm_hash->hash)));
2611 if (lpcfg_lanman_auth(lp_ctx) && (old_lm_hash != NULL)) {
2612 io->og.lm_hash = talloc(io->ac, struct samr_Password);
2613 memcpy(io->og.lm_hash->hash, old_lm_hash->data, MIN(old_lm_hash->length,
2614 sizeof(io->og.lm_hash->hash)));
2618 * Handles the password change control if it's specified. It has the
2619 * precedance and overrides already specified old password values of
2620 * change requests (but that shouldn't happen since the control is
2621 * fully internal and only used in conjunction with replace requests!).
2623 if (ac->change != NULL) {
2624 io->og.nt_hash = NULL;
2625 if (ac->change->old_nt_pwd_hash != NULL) {
2626 io->og.nt_hash = talloc_memdup(io->ac,
2627 ac->change->old_nt_pwd_hash,
2628 sizeof(struct samr_Password));
2630 io->og.lm_hash = NULL;
2631 if (lpcfg_lanman_auth(lp_ctx) && (ac->change->old_lm_pwd_hash != NULL)) {
2632 io->og.lm_hash = talloc_memdup(io->ac,
2633 ac->change->old_lm_pwd_hash,
2634 sizeof(struct samr_Password));
2638 /* refuse the change if someone wants to change the clear-
2639 text and supply his own hashes at the same time... */
2640 if ((io->n.cleartext_utf8 || io->n.cleartext_utf16)
2641 && (io->n.nt_hash || io->n.lm_hash)) {
2642 ldb_asprintf_errstring(ldb,
2644 "it's only allowed to set the password in form of cleartext attributes or as hashes");
2645 return LDB_ERR_UNWILLING_TO_PERFORM;
2648 /* refuse the change if someone wants to change the password
2649 using both plaintext methods (UTF8 and UTF16) at the same time... */
2650 if (io->n.cleartext_utf8 && io->n.cleartext_utf16) {
2651 ldb_asprintf_errstring(ldb,
2653 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
2654 return LDB_ERR_UNWILLING_TO_PERFORM;
2657 /* refuse the change if someone tries to set/change the password by
2658 * the lanman hash alone and we've deactivated that mechanism. This
2659 * would end in an account without any password! */
2660 if ((!io->n.cleartext_utf8) && (!io->n.cleartext_utf16)
2661 && (!io->n.nt_hash) && (!io->n.lm_hash)) {
2662 ldb_asprintf_errstring(ldb,
2664 "It's not possible to delete the password (changes using the LAN Manager hash alone could be deactivated)!");
2665 /* on "userPassword" and "clearTextPassword" we've to return
2666 * something different, since these are virtual attributes */
2667 if ((ldb_msg_find_element(client_msg, "userPassword") != NULL) ||
2668 (ldb_msg_find_element(client_msg, "clearTextPassword") != NULL)) {
2669 return LDB_ERR_CONSTRAINT_VIOLATION;
2671 return LDB_ERR_UNWILLING_TO_PERFORM;
2674 /* refuse the change if someone wants to compare against a plaintext
2675 or hash at the same time for a "password modify" operation... */
2676 if ((io->og.cleartext_utf8 || io->og.cleartext_utf16)
2677 && (io->og.nt_hash || io->og.lm_hash)) {
2678 ldb_asprintf_errstring(ldb,
2680 "it's only allowed to provide the old password in form of cleartext attributes or as hashes");
2681 return LDB_ERR_UNWILLING_TO_PERFORM;
2684 /* refuse the change if someone wants to compare against both
2685 * plaintexts at the same time for a "password modify" operation... */
2686 if (io->og.cleartext_utf8 && io->og.cleartext_utf16) {
2687 ldb_asprintf_errstring(ldb,
2689 "it's only allowed to provide the old cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
2690 return LDB_ERR_UNWILLING_TO_PERFORM;
2693 /* Decides if we have a password modify or password reset operation */
2694 if (ac->req->operation == LDB_ADD) {
2695 /* On "add" we have only "password reset" */
2696 ac->pwd_reset = true;
2697 } else if (ac->req->operation == LDB_MODIFY) {
2698 if (io->og.cleartext_utf8 || io->og.cleartext_utf16
2699 || io->og.nt_hash || io->og.lm_hash) {
2700 /* If we have an old password specified then for sure it
2701 * is a user "password change" */
2702 ac->pwd_reset = false;
2704 /* Otherwise we have also here a "password reset" */
2705 ac->pwd_reset = true;
2708 /* this shouldn't happen */
2709 return ldb_operr(ldb);
2712 if (existing_msg != NULL) {
2715 if (ac->pwd_reset) {
2716 /* Get the old password from the database */
2717 status = samdb_result_passwords_no_lockout(ac,
2723 /* Get the old password from the database */
2724 status = samdb_result_passwords(ac,
2731 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCOUNT_LOCKED_OUT)) {
2732 return dsdb_module_werror(ac->module,
2733 LDB_ERR_CONSTRAINT_VIOLATION,
2734 WERR_ACCOUNT_LOCKED_OUT,
2735 "Password change not permitted,"
2736 " account locked out!");
2739 if (!NT_STATUS_IS_OK(status)) {
2741 * This only happens if the database has gone weird,
2742 * not if we are just missing the passwords
2744 return ldb_operr(ldb);
2747 io->o.nt_history_len = samdb_result_hashes(ac, existing_msg,
2750 io->o.lm_history_len = samdb_result_hashes(ac, existing_msg,
2753 io->o.supplemental = ldb_msg_find_ldb_val(existing_msg,
2754 "supplementalCredentials");
2756 if (io->o.supplemental != NULL) {
2757 enum ndr_err_code ndr_err;
2759 ndr_err = ndr_pull_struct_blob_all(io->o.supplemental, io->ac,
2761 (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
2762 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2763 status = ndr_map_error2ntstatus(ndr_err);
2764 ldb_asprintf_errstring(ldb,
2765 "setup_io: failed to pull "
2766 "old supplementalCredentialsBlob: %s",
2768 return LDB_ERR_OPERATIONS_ERROR;
2776 static struct ph_context *ph_init_context(struct ldb_module *module,
2777 struct ldb_request *req,
2779 bool update_password)
2781 struct ldb_context *ldb;
2782 struct ph_context *ac;
2784 ldb = ldb_module_get_ctx(module);
2786 ac = talloc_zero(req, struct ph_context);
2788 ldb_set_errstring(ldb, "Out of Memory");
2792 ac->module = module;
2794 ac->userPassword = userPassword;
2795 ac->update_password = update_password;
2796 ac->update_lastset = true;
2801 static void ph_apply_controls(struct ph_context *ac)
2803 struct ldb_control *ctrl;
2805 ac->change_status = false;
2806 ctrl = ldb_request_get_control(ac->req,
2807 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID);
2809 ac->change_status = true;
2811 /* Mark the "change status" control as uncritical (done) */
2812 ctrl->critical = false;
2815 ac->hash_values = false;
2816 ctrl = ldb_request_get_control(ac->req,
2817 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID);
2819 ac->hash_values = true;
2821 /* Mark the "hash values" control as uncritical (done) */
2822 ctrl->critical = false;
2825 ctrl = ldb_request_get_control(ac->req,
2826 DSDB_CONTROL_PASSWORD_CHANGE_OID);
2828 ac->change = (struct dsdb_control_password_change *) ctrl->data;
2830 /* Mark the "change" control as uncritical (done) */
2831 ctrl->critical = false;
2834 ac->pwd_last_set_bypass = false;
2835 ctrl = ldb_request_get_control(ac->req,
2836 DSDB_CONTROL_PASSWORD_BYPASS_LAST_SET_OID);
2838 ac->pwd_last_set_bypass = true;
2840 /* Mark the "bypass pwdLastSet" control as uncritical (done) */
2841 ctrl->critical = false;
2845 static int ph_op_callback(struct ldb_request *req, struct ldb_reply *ares)
2847 struct ph_context *ac;
2849 ac = talloc_get_type(req->context, struct ph_context);
2852 return ldb_module_done(ac->req, NULL, NULL,
2853 LDB_ERR_OPERATIONS_ERROR);
2856 if (ares->type == LDB_REPLY_REFERRAL) {
2857 return ldb_module_send_referral(ac->req, ares->referral);
2860 if ((ares->error != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
2861 /* On success and trivial errors a status control is being
2862 * added (used for example by the "samdb_set_password" call) */
2863 ldb_reply_add_control(ares,
2864 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2869 if (ares->error != LDB_SUCCESS) {
2870 return ldb_module_done(ac->req, ares->controls,
2871 ares->response, ares->error);
2874 if (ares->type != LDB_REPLY_DONE) {
2876 return ldb_module_done(ac->req, NULL, NULL,
2877 LDB_ERR_OPERATIONS_ERROR);
2880 return ldb_module_done(ac->req, ares->controls,
2881 ares->response, ares->error);
2884 static int password_hash_add_do_add(struct ph_context *ac);
2885 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares);
2886 static int password_hash_mod_search_self(struct ph_context *ac);
2887 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares);
2888 static int password_hash_mod_do_mod(struct ph_context *ac);
2890 static int get_domain_data_callback(struct ldb_request *req,
2891 struct ldb_reply *ares)
2893 struct ldb_context *ldb;
2894 struct ph_context *ac;
2895 struct loadparm_context *lp_ctx;
2896 int ret = LDB_SUCCESS;
2898 ac = talloc_get_type(req->context, struct ph_context);
2899 ldb = ldb_module_get_ctx(ac->module);
2902 ret = LDB_ERR_OPERATIONS_ERROR;
2905 if (ares->error != LDB_SUCCESS) {
2906 return ldb_module_done(ac->req, ares->controls,
2907 ares->response, ares->error);
2910 switch (ares->type) {
2911 case LDB_REPLY_ENTRY:
2912 if (ac->status != NULL) {
2915 ldb_set_errstring(ldb, "Too many results");
2916 ret = LDB_ERR_OPERATIONS_ERROR;
2920 /* Setup the "status" structure (used as control later) */
2921 ac->status = talloc_zero(ac->req,
2922 struct dsdb_control_password_change_status);
2923 if (ac->status == NULL) {
2927 ret = LDB_ERR_OPERATIONS_ERROR;
2931 /* Setup the "domain data" structure */
2932 ac->status->domain_data.pwdProperties =
2933 ldb_msg_find_attr_as_uint(ares->message, "pwdProperties", -1);
2934 ac->status->domain_data.pwdHistoryLength =
2935 ldb_msg_find_attr_as_uint(ares->message, "pwdHistoryLength", -1);
2936 ac->status->domain_data.maxPwdAge =
2937 ldb_msg_find_attr_as_int64(ares->message, "maxPwdAge", -1);
2938 ac->status->domain_data.minPwdAge =
2939 ldb_msg_find_attr_as_int64(ares->message, "minPwdAge", -1);
2940 ac->status->domain_data.minPwdLength =
2941 ldb_msg_find_attr_as_uint(ares->message, "minPwdLength", -1);
2942 ac->status->domain_data.store_cleartext =
2943 ac->status->domain_data.pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
2945 /* For a domain DN, this puts things in dotted notation */
2946 /* For builtin domains, this will give details for the host,
2947 * but that doesn't really matter, as it's just used for salt
2948 * and kerberos principals, which don't exist here */
2950 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2951 struct loadparm_context);
2953 ac->status->domain_data.dns_domain = lpcfg_dnsdomain(lp_ctx);
2954 ac->status->domain_data.realm = lpcfg_realm(lp_ctx);
2955 ac->status->domain_data.netbios_domain = lpcfg_sam_name(lp_ctx);
2957 ac->status->reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2959 if (ac->dom_res != NULL) {
2962 ldb_set_errstring(ldb, "Too many results");
2963 ret = LDB_ERR_OPERATIONS_ERROR;
2967 ac->dom_res = talloc_steal(ac, ares);
2971 case LDB_REPLY_REFERRAL:
2977 case LDB_REPLY_DONE:
2979 /* call the next step */
2980 switch (ac->req->operation) {
2982 ret = password_hash_add_do_add(ac);
2986 ret = password_hash_mod_do_mod(ac);
2990 ret = LDB_ERR_OPERATIONS_ERROR;
2997 if (ret != LDB_SUCCESS) {
2998 struct ldb_reply *new_ares;
3000 new_ares = talloc_zero(ac->req, struct ldb_reply);
3001 if (new_ares == NULL) {
3003 return ldb_module_done(ac->req, NULL, NULL,
3004 LDB_ERR_OPERATIONS_ERROR);
3007 new_ares->error = ret;
3008 if ((ret != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
3009 /* On success and trivial errors a status control is being
3010 * added (used for example by the "samdb_set_password" call) */
3011 ldb_reply_add_control(new_ares,
3012 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
3017 return ldb_module_done(ac->req, new_ares->controls,
3018 new_ares->response, new_ares->error);
3024 static int build_domain_data_request(struct ph_context *ac)
3026 /* attrs[] is returned from this function in
3027 ac->dom_req->op.search.attrs, so it must be static, as
3028 otherwise the compiler can put it on the stack */
3029 struct ldb_context *ldb;
3030 static const char * const attrs[] = { "pwdProperties",
3036 "lockOutObservationWindow",
3040 ldb = ldb_module_get_ctx(ac->module);
3042 ret = ldb_build_search_req(&ac->dom_req, ldb, ac,
3043 ldb_get_default_basedn(ldb),
3047 ac, get_domain_data_callback,
3049 LDB_REQ_SET_LOCATION(ac->dom_req);
3053 static int password_hash_needed(struct ldb_module *module,
3054 struct ldb_request *req,
3055 struct ph_context **_ac)
3057 struct ldb_context *ldb = ldb_module_get_ctx(module);
3058 const char *operation = NULL;
3059 const struct ldb_message *msg = NULL;
3060 struct ph_context *ac = NULL;
3061 const char *passwordAttrs[] = {
3063 "clearTextPassword",
3068 const char **a = NULL;
3069 unsigned int attr_cnt = 0;
3070 struct ldb_control *bypass = NULL;
3071 bool userPassword = dsdb_user_password_support(module, req, req);
3072 bool update_password = false;
3076 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_needed\n");
3078 switch (req->operation) {
3081 msg = req->op.add.message;
3084 operation = "modify";
3085 msg = req->op.mod.message;
3088 return ldb_next_request(module, req);
3091 if (ldb_dn_is_special(msg->dn)) { /* do not manipulate our control entries */
3092 return ldb_next_request(module, req);
3095 bypass = ldb_request_get_control(req,
3096 DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID);
3097 if (bypass != NULL) {
3098 /* Mark the "bypass" control as uncritical (done) */
3099 bypass->critical = false;
3100 ldb_debug(ldb, LDB_DEBUG_TRACE,
3101 "password_hash_needed(%s) (bypassing)\n",
3103 return password_hash_bypass(module, req);
3106 /* nobody must touch password histories and 'supplementalCredentials' */
3107 if (ldb_msg_find_element(msg, "ntPwdHistory")) {
3108 return LDB_ERR_UNWILLING_TO_PERFORM;
3110 if (ldb_msg_find_element(msg, "lmPwdHistory")) {
3111 return LDB_ERR_UNWILLING_TO_PERFORM;
3113 if (ldb_msg_find_element(msg, "supplementalCredentials")) {
3114 return LDB_ERR_UNWILLING_TO_PERFORM;
3118 * If no part of this touches the 'userPassword' OR 'clearTextPassword'
3119 * OR 'unicodePwd' OR 'dBCSPwd' we don't need to make any changes.
3120 * For password changes/set there should be a 'delete' or a 'modify'
3121 * on these attributes.
3123 for (a = passwordAttrs; *a != NULL; a++) {
3124 if ((!userPassword) && (ldb_attr_cmp(*a, "userPassword") == 0)) {
3128 if (ldb_msg_find_element(msg, *a) != NULL) {
3129 /* MS-ADTS 3.1.1.3.1.5.2 */
3130 if ((ldb_attr_cmp(*a, "userPassword") == 0) &&
3131 (dsdb_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
3132 return LDB_ERR_CONSTRAINT_VIOLATION;
3140 update_password = true;
3143 if (!update_password) {
3144 return ldb_next_request(module, req);
3147 ac = ph_init_context(module, req, userPassword, update_password);
3149 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
3150 return ldb_operr(ldb);
3152 ph_apply_controls(ac);
3155 * Make a copy in order to apply our modifications
3156 * to the final update
3158 ac->update_msg = ldb_msg_copy_shallow(ac, msg);
3159 if (ac->update_msg == NULL) {
3160 return ldb_oom(ldb);
3164 * Remove all password related attributes.
3166 if (ac->userPassword) {
3167 ldb_msg_remove_attr(ac->update_msg, "userPassword");
3169 ldb_msg_remove_attr(ac->update_msg, "clearTextPassword");
3170 ldb_msg_remove_attr(ac->update_msg, "unicodePwd");
3171 ldb_msg_remove_attr(ac->update_msg, "ntPwdHistory");
3172 ldb_msg_remove_attr(ac->update_msg, "dBCSPwd");
3173 ldb_msg_remove_attr(ac->update_msg, "lmPwdHistory");
3174 ldb_msg_remove_attr(ac->update_msg, "supplementalCredentials");
3175 ldb_msg_remove_attr(ac->update_msg, "pwdLastSet");
3181 static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
3183 struct ldb_context *ldb = ldb_module_get_ctx(module);
3184 struct ph_context *ac = NULL;
3187 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add\n");
3189 ret = password_hash_needed(module, req, &ac);
3190 if (ret != LDB_SUCCESS) {
3197 /* Make sure we are performing the password set action on a (for us)
3198 * valid object. Those are instances of either "user" and/or
3199 * "inetOrgPerson". Otherwise continue with the submodules. */
3200 if ((!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "user"))
3201 && (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "inetOrgPerson"))) {
3205 if (ldb_msg_find_element(req->op.add.message, "clearTextPassword") != NULL) {
3206 ldb_set_errstring(ldb,
3207 "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
3208 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3211 return ldb_next_request(module, req);
3214 /* get user domain data */
3215 ret = build_domain_data_request(ac);
3216 if (ret != LDB_SUCCESS) {
3220 return ldb_next_request(module, ac->dom_req);
3223 static int password_hash_add_do_add(struct ph_context *ac)
3225 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3226 struct ldb_request *down_req;
3227 struct setup_password_fields_io io;
3230 /* Prepare the internal data structure containing the passwords */
3231 ret = setup_io(ac, ac->req->op.add.message, NULL, &io);
3232 if (ret != LDB_SUCCESS) {
3236 ret = setup_password_fields(&io);
3237 if (ret != LDB_SUCCESS) {
3241 ret = check_password_restrictions(&io);
3242 if (ret != LDB_SUCCESS) {
3246 ret = update_final_msg(&io);
3247 if (ret != LDB_SUCCESS) {
3251 ret = ldb_build_add_req(&down_req, ldb, ac,
3256 LDB_REQ_SET_LOCATION(down_req);
3257 if (ret != LDB_SUCCESS) {
3261 return ldb_next_request(ac->module, down_req);
3264 static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
3266 struct ldb_context *ldb = ldb_module_get_ctx(module);
3267 struct ph_context *ac = NULL;
3268 const char *passwordAttrs[] = { "userPassword", "clearTextPassword",
3269 "unicodePwd", "dBCSPwd", NULL }, **l;
3270 unsigned int del_attr_cnt, add_attr_cnt, rep_attr_cnt;
3271 struct ldb_message_element *passwordAttr;
3272 struct ldb_message *msg;
3273 struct ldb_request *down_req;
3277 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
3279 ret = password_hash_needed(module, req, &ac);
3280 if (ret != LDB_SUCCESS) {
3287 /* use a new message structure so that we can modify it */
3288 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3290 return ldb_oom(ldb);
3293 /* - check for single-valued password attributes
3294 * (if not return "CONSTRAINT_VIOLATION")
3295 * - check that for a password change operation one add and one delete
3297 * (if not return "CONSTRAINT_VIOLATION" or "UNWILLING_TO_PERFORM")
3298 * - check that a password change and a password set operation cannot
3300 * (if not return "UNWILLING_TO_PERFORM")
3301 * - remove all password attributes modifications from the first change
3302 * operation (anything without the passwords) - we will make the real
3303 * modification later */
3307 for (l = passwordAttrs; *l != NULL; l++) {
3308 if ((!ac->userPassword) &&
3309 (ldb_attr_cmp(*l, "userPassword") == 0)) {
3313 while ((passwordAttr = ldb_msg_find_element(msg, *l)) != NULL) {
3314 if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_DELETE) {
3317 if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_ADD) {
3320 if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_REPLACE) {
3323 if ((passwordAttr->num_values != 1) &&
3324 (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_ADD)) {
3326 ldb_asprintf_errstring(ldb,
3327 "'%s' attribute must have exactly one value on add operations!",
3329 return LDB_ERR_CONSTRAINT_VIOLATION;
3331 if ((passwordAttr->num_values > 1) &&
3332 (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_DELETE)) {
3334 ldb_asprintf_errstring(ldb,
3335 "'%s' attribute must have zero or one value(s) on delete operations!",
3337 return LDB_ERR_CONSTRAINT_VIOLATION;
3339 ldb_msg_remove_element(msg, passwordAttr);
3342 if ((del_attr_cnt == 0) && (add_attr_cnt > 0)) {
3344 ldb_set_errstring(ldb,
3345 "Only the add action for a password change specified!");
3346 return LDB_ERR_UNWILLING_TO_PERFORM;
3348 if ((del_attr_cnt > 1) || (add_attr_cnt > 1)) {
3350 ldb_set_errstring(ldb,
3351 "Only one delete and one add action for a password change allowed!");
3352 return LDB_ERR_UNWILLING_TO_PERFORM;
3354 if ((rep_attr_cnt > 0) && ((del_attr_cnt > 0) || (add_attr_cnt > 0))) {
3356 ldb_set_errstring(ldb,
3357 "Either a password change or a password set operation is allowed!");
3358 return LDB_ERR_UNWILLING_TO_PERFORM;
3361 /* if there was nothing else to be modified skip to next step */
3362 if (msg->num_elements == 0) {
3363 return password_hash_mod_search_self(ac);
3367 * Now we apply all changes remaining in msg
3368 * and remove them from our final update_msg
3371 for (i = 0; i < msg->num_elements; i++) {
3372 ldb_msg_remove_attr(ac->update_msg,
3373 msg->elements[i].name);
3376 ret = ldb_build_mod_req(&down_req, ldb, ac,
3379 ac, ph_modify_callback,
3381 LDB_REQ_SET_LOCATION(down_req);
3382 if (ret != LDB_SUCCESS) {
3386 return ldb_next_request(module, down_req);
3389 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
3391 struct ph_context *ac;
3393 ac = talloc_get_type(req->context, struct ph_context);
3396 return ldb_module_done(ac->req, NULL, NULL,
3397 LDB_ERR_OPERATIONS_ERROR);
3400 if (ares->type == LDB_REPLY_REFERRAL) {
3401 return ldb_module_send_referral(ac->req, ares->referral);
3404 if (ares->error != LDB_SUCCESS) {
3405 return ldb_module_done(ac->req, ares->controls,
3406 ares->response, ares->error);
3409 if (ares->type != LDB_REPLY_DONE) {
3411 return ldb_module_done(ac->req, NULL, NULL,
3412 LDB_ERR_OPERATIONS_ERROR);
3417 return password_hash_mod_search_self(ac);
3420 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
3422 struct ldb_context *ldb;
3423 struct ph_context *ac;
3424 int ret = LDB_SUCCESS;
3426 ac = talloc_get_type(req->context, struct ph_context);
3427 ldb = ldb_module_get_ctx(ac->module);
3430 ret = LDB_ERR_OPERATIONS_ERROR;
3433 if (ares->error != LDB_SUCCESS) {
3434 return ldb_module_done(ac->req, ares->controls,
3435 ares->response, ares->error);
3438 /* we are interested only in the single reply (base search) */
3439 switch (ares->type) {
3440 case LDB_REPLY_ENTRY:
3441 /* Make sure we are performing the password change action on a
3442 * (for us) valid object. Those are instances of either "user"
3443 * and/or "inetOrgPerson". Otherwise continue with the
3445 if ((!ldb_msg_check_string_attribute(ares->message, "objectClass", "user"))
3446 && (!ldb_msg_check_string_attribute(ares->message, "objectClass", "inetOrgPerson"))) {
3449 if (ldb_msg_find_element(ac->req->op.mod.message, "clearTextPassword") != NULL) {
3450 ldb_set_errstring(ldb,
3451 "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
3452 ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
3456 ret = ldb_next_request(ac->module, ac->req);
3460 if (ac->search_res != NULL) {
3463 ldb_set_errstring(ldb, "Too many results");
3464 ret = LDB_ERR_OPERATIONS_ERROR;
3468 ac->search_res = talloc_steal(ac, ares);
3472 case LDB_REPLY_REFERRAL:
3473 /* ignore anything else for now */
3478 case LDB_REPLY_DONE:
3481 /* get user domain data */
3482 ret = build_domain_data_request(ac);
3483 if (ret != LDB_SUCCESS) {
3484 return ldb_module_done(ac->req, NULL, NULL, ret);
3487 ret = ldb_next_request(ac->module, ac->dom_req);
3492 if (ret != LDB_SUCCESS) {
3493 return ldb_module_done(ac->req, NULL, NULL, ret);
3499 static int password_hash_mod_search_self(struct ph_context *ac)
3501 struct ldb_context *ldb;
3502 static const char * const attrs[] = { "objectClass",
3503 "userAccountControl",
3504 "msDS-User-Account-Control-Computed",
3508 "userPrincipalName",
3509 "supplementalCredentials",
3518 struct ldb_request *search_req;
3521 ldb = ldb_module_get_ctx(ac->module);
3523 ret = ldb_build_search_req(&search_req, ldb, ac,
3524 ac->req->op.mod.message->dn,
3529 ac, ph_mod_search_callback,
3531 LDB_REQ_SET_LOCATION(search_req);
3532 if (ret != LDB_SUCCESS) {
3536 return ldb_next_request(ac->module, search_req);
3539 static int password_hash_mod_do_mod(struct ph_context *ac)
3541 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3542 struct ldb_request *mod_req;
3543 struct setup_password_fields_io io;
3546 /* Prepare the internal data structure containing the passwords */
3547 ret = setup_io(ac, ac->req->op.mod.message,
3548 ac->search_res->message, &io);
3549 if (ret != LDB_SUCCESS) {
3553 ret = setup_password_fields(&io);
3554 if (ret != LDB_SUCCESS) {
3558 ret = check_password_restrictions(&io);
3559 if (ret != LDB_SUCCESS) {
3563 ret = update_final_msg(&io);
3564 if (ret != LDB_SUCCESS) {
3568 ret = ldb_build_mod_req(&mod_req, ldb, ac,
3573 LDB_REQ_SET_LOCATION(mod_req);
3574 if (ret != LDB_SUCCESS) {
3578 return ldb_next_request(ac->module, mod_req);
3581 static const struct ldb_module_ops ldb_password_hash_module_ops = {
3582 .name = "password_hash",
3583 .add = password_hash_add,
3584 .modify = password_hash_modify
3587 int ldb_password_hash_module_init(const char *version)
3589 LDB_MODULE_CHECK_VERSION(version);
3590 return ldb_register_module(&ldb_password_hash_module_ops);