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 "libcli/security/dom_sid.h"
39 #include "system/kerberos.h"
40 #include "auth/kerberos/kerberos.h"
41 #include "dsdb/samdb/samdb.h"
42 #include "dsdb/samdb/ldb_modules/util.h"
43 #include "dsdb/samdb/ldb_modules/password_modules.h"
44 #include "librpc/gen_ndr/ndr_drsblobs.h"
45 #include "lib/crypto/md4.h"
46 #include "lib/crypto/md5.h"
47 #include "param/param.h"
48 #include "lib/krb5_wrap/krb5_samba.h"
49 #include "auth/common_auth.h"
50 #include "lib/messaging/messaging.h"
57 /* If we have decided there is a reason to work on this request, then
58 * setup all the password hash types correctly.
60 * If we haven't the hashes yet but the password given as plain-text (attributes
61 * 'unicodePwd', 'userPassword' and 'clearTextPassword') we have to check for
62 * the constraints. Once this is done, we calculate the password hashes.
64 * Notice: unlike the real AD which only supports the UTF16 special based
65 * 'unicodePwd' and the UTF8 based 'userPassword' plaintext attribute we
66 * understand also a UTF16 based 'clearTextPassword' one.
67 * The latter is also accessible through LDAP so it can also be set by external
68 * tools and scripts. But be aware that this isn't portable on non SAMBA 4 ADs!
70 * Also when the module receives only the password hashes (possible through
71 * specifying an internal LDB control - for security reasons) some checks are
72 * performed depending on the operation mode (see below) (e.g. if the password
73 * has been in use before if the password memory policy was activated).
75 * Attention: There is a difference between "modify" and "reset" operations
76 * (see MS-ADTS 3.1.1.3.1.5). If the client sends a "add" and "remove"
77 * operation for a password attribute we thread this as a "modify"; if it sends
78 * only a "replace" one we have an (administrative) reset.
80 * Finally, if the administrator has requested that a password history
81 * be maintained, then this should also be written out.
85 /* TODO: [consider always MS-ADTS 3.1.1.3.1.5]
86 * - Check for right connection encryption
89 /* Notice: Definition of "dsdb_control_password_change_status" moved into
93 struct ldb_module *module;
94 struct ldb_request *req;
96 struct ldb_request *dom_req;
97 struct ldb_reply *dom_res;
99 struct ldb_reply *pso_res;
101 struct ldb_reply *search_res;
103 struct ldb_message *update_msg;
105 struct dsdb_control_password_change_status *status;
106 struct dsdb_control_password_change *change;
108 const char **gpg_key_ids;
114 bool update_password;
116 bool pwd_last_set_bypass;
117 bool pwd_last_set_default;
118 bool smartcard_reset;
119 const char **userPassword_schemes;
123 struct setup_password_fields_io {
124 struct ph_context *ac;
126 struct smb_krb5_context *smb_krb5_context;
128 /* info about the user account */
130 uint32_t userAccountControl;
132 const char *sAMAccountName;
133 const char *user_principal_name;
134 const char *displayName; /* full name */
136 uint32_t restrictions;
137 struct dom_sid *account_sid;
140 /* new credentials and old given credentials */
141 struct setup_password_fields_given {
142 const struct ldb_val *cleartext_utf8;
143 const struct ldb_val *cleartext_utf16;
144 struct samr_Password *nt_hash;
145 struct samr_Password *lm_hash;
148 /* old credentials */
150 struct samr_Password *nt_hash;
151 struct samr_Password *lm_hash;
152 uint32_t nt_history_len;
153 struct samr_Password *nt_history;
154 uint32_t lm_history_len;
155 struct samr_Password *lm_history;
156 const struct ldb_val *supplemental;
157 struct supplementalCredentialsBlob scb;
160 /* generated credentials */
162 struct samr_Password *nt_hash;
163 struct samr_Password *lm_hash;
164 uint32_t nt_history_len;
165 struct samr_Password *nt_history;
166 uint32_t lm_history_len;
167 struct samr_Password *lm_history;
173 struct ldb_val supplemental;
178 static int msg_find_old_and_new_pwd_val(const struct ldb_message *msg,
180 enum ldb_request_type operation,
181 const struct ldb_val **new_val,
182 const struct ldb_val **old_val);
184 static int password_hash_bypass(struct ldb_module *module, struct ldb_request *request)
186 struct ldb_context *ldb = ldb_module_get_ctx(module);
187 const struct ldb_message *msg;
188 struct ldb_message_element *nte;
189 struct ldb_message_element *lme;
190 struct ldb_message_element *nthe;
191 struct ldb_message_element *lmhe;
192 struct ldb_message_element *sce;
194 switch (request->operation) {
196 msg = request->op.add.message;
199 msg = request->op.mod.message;
202 return ldb_next_request(module, request);
205 /* nobody must touch password histories and 'supplementalCredentials' */
206 nte = dsdb_get_single_valued_attr(msg, "unicodePwd",
208 lme = dsdb_get_single_valued_attr(msg, "dBCSPwd",
210 nthe = dsdb_get_single_valued_attr(msg, "ntPwdHistory",
212 lmhe = dsdb_get_single_valued_attr(msg, "lmPwdHistory",
214 sce = dsdb_get_single_valued_attr(msg, "supplementalCredentials",
217 #define CHECK_HASH_ELEMENT(e, min, max) do {\
218 if (e && e->num_values) { \
219 unsigned int _count; \
220 if (e->num_values != 1) { \
221 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
222 "num_values != 1"); \
224 if ((e->values[0].length % 16) != 0) { \
225 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
226 "length % 16 != 0"); \
228 _count = e->values[0].length / 16; \
229 if (_count < min) { \
230 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
233 if (_count > max) { \
234 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
240 CHECK_HASH_ELEMENT(nte, 1, 1);
241 CHECK_HASH_ELEMENT(lme, 1, 1);
242 CHECK_HASH_ELEMENT(nthe, 1, INT32_MAX);
243 CHECK_HASH_ELEMENT(lmhe, 1, INT32_MAX);
245 if (sce && sce->num_values) {
246 enum ndr_err_code ndr_err;
247 struct supplementalCredentialsBlob *scb;
248 struct supplementalCredentialsPackage *scpp = NULL;
249 struct supplementalCredentialsPackage *scpk = NULL;
250 struct supplementalCredentialsPackage *scpkn = NULL;
251 struct supplementalCredentialsPackage *scpct = NULL;
252 DATA_BLOB scpbp = data_blob_null;
253 DATA_BLOB scpbk = data_blob_null;
254 DATA_BLOB scpbkn = data_blob_null;
255 DATA_BLOB scpbct = data_blob_null;
259 if (sce->num_values != 1) {
260 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
264 scb = talloc_zero(request, struct supplementalCredentialsBlob);
266 return ldb_module_oom(module);
269 ndr_err = ndr_pull_struct_blob_all(&sce->values[0], scb, scb,
270 (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
271 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
272 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
273 "ndr_pull_struct_blob_all");
276 if (scb->sub.num_packages < 2) {
277 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
281 for (i=0; i < scb->sub.num_packages; i++) {
284 subblob = strhex_to_data_blob(scb, scb->sub.packages[i].data);
285 if (subblob.data == NULL) {
286 return ldb_module_oom(module);
289 if (strcmp(scb->sub.packages[i].name, "Packages") == 0) {
291 return ldb_error(ldb,
292 LDB_ERR_CONSTRAINT_VIOLATION,
295 scpp = &scb->sub.packages[i];
299 if (strcmp(scb->sub.packages[i].name, "Primary:Kerberos") == 0) {
301 return ldb_error(ldb,
302 LDB_ERR_CONSTRAINT_VIOLATION,
303 "Primary:Kerberos twice");
305 scpk = &scb->sub.packages[i];
309 if (strcmp(scb->sub.packages[i].name, "Primary:Kerberos-Newer-Keys") == 0) {
311 return ldb_error(ldb,
312 LDB_ERR_CONSTRAINT_VIOLATION,
313 "Primary:Kerberos-Newer-Keys twice");
315 scpkn = &scb->sub.packages[i];
319 if (strcmp(scb->sub.packages[i].name, "Primary:CLEARTEXT") == 0) {
321 return ldb_error(ldb,
322 LDB_ERR_CONSTRAINT_VIOLATION,
323 "Primary:CLEARTEXT twice");
325 scpct = &scb->sub.packages[i];
330 data_blob_free(&subblob);
334 return ldb_error(ldb,
335 LDB_ERR_CONSTRAINT_VIOLATION,
336 "Primary:Packages missing");
341 * If Primary:Kerberos is missing w2k8r2 reboots
342 * when a password is changed.
344 return ldb_error(ldb,
345 LDB_ERR_CONSTRAINT_VIOLATION,
346 "Primary:Kerberos missing");
350 struct package_PackagesBlob *p;
353 p = talloc_zero(scb, struct package_PackagesBlob);
355 return ldb_module_oom(module);
358 ndr_err = ndr_pull_struct_blob(&scpbp, p, p,
359 (ndr_pull_flags_fn_t)ndr_pull_package_PackagesBlob);
360 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
361 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
362 "ndr_pull_struct_blob Packages");
365 if (p->names == NULL) {
366 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
367 "Packages names == NULL");
370 for (n = 0; p->names[n]; n++) {
374 if (scb->sub.num_packages != (n + 1)) {
375 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
376 "Packages num_packages != num_names + 1");
383 struct package_PrimaryKerberosBlob *k;
385 k = talloc_zero(scb, struct package_PrimaryKerberosBlob);
387 return ldb_module_oom(module);
390 ndr_err = ndr_pull_struct_blob(&scpbk, k, k,
391 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
392 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
393 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
394 "ndr_pull_struct_blob PrimaryKerberos");
397 if (k->version != 3) {
398 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
399 "PrimaryKerberos version != 3");
402 if (k->ctr.ctr3.salt.string == NULL) {
403 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
404 "PrimaryKerberos salt == NULL");
407 if (strlen(k->ctr.ctr3.salt.string) == 0) {
408 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
409 "PrimaryKerberos strlen(salt) == 0");
412 if (k->ctr.ctr3.num_keys != 2) {
413 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
414 "PrimaryKerberos num_keys != 2");
417 if (k->ctr.ctr3.num_old_keys > k->ctr.ctr3.num_keys) {
418 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
419 "PrimaryKerberos num_old_keys > num_keys");
422 if (k->ctr.ctr3.keys[0].keytype != ENCTYPE_DES_CBC_MD5) {
423 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
424 "PrimaryKerberos key[0] != DES_CBC_MD5");
426 if (k->ctr.ctr3.keys[1].keytype != ENCTYPE_DES_CBC_CRC) {
427 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
428 "PrimaryKerberos key[1] != DES_CBC_CRC");
431 if (k->ctr.ctr3.keys[0].value_len != 8) {
432 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
433 "PrimaryKerberos key[0] value_len != 8");
435 if (k->ctr.ctr3.keys[1].value_len != 8) {
436 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
437 "PrimaryKerberos key[1] value_len != 8");
440 for (i = 0; i < k->ctr.ctr3.num_old_keys; i++) {
441 if (k->ctr.ctr3.old_keys[i].keytype ==
442 k->ctr.ctr3.keys[i].keytype &&
443 k->ctr.ctr3.old_keys[i].value_len ==
444 k->ctr.ctr3.keys[i].value_len) {
448 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
449 "PrimaryKerberos old_keys type/value_len doesn't match");
456 struct package_PrimaryKerberosBlob *k;
458 k = talloc_zero(scb, struct package_PrimaryKerberosBlob);
460 return ldb_module_oom(module);
463 ndr_err = ndr_pull_struct_blob(&scpbkn, k, k,
464 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
465 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
466 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
467 "ndr_pull_struct_blob PrimaryKerberosNeverKeys");
470 if (k->version != 4) {
471 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
472 "KerberosNerverKeys version != 4");
475 if (k->ctr.ctr4.salt.string == NULL) {
476 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
477 "KerberosNewerKeys salt == NULL");
480 if (strlen(k->ctr.ctr4.salt.string) == 0) {
481 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
482 "KerberosNewerKeys strlen(salt) == 0");
485 if (k->ctr.ctr4.num_keys != 4) {
486 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
487 "KerberosNewerKeys num_keys != 2");
490 if (k->ctr.ctr4.num_old_keys > k->ctr.ctr4.num_keys) {
491 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
492 "KerberosNewerKeys num_old_keys > num_keys");
495 if (k->ctr.ctr4.num_older_keys > k->ctr.ctr4.num_old_keys) {
496 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
497 "KerberosNewerKeys num_older_keys > num_old_keys");
500 if (k->ctr.ctr4.keys[0].keytype != ENCTYPE_AES256_CTS_HMAC_SHA1_96) {
501 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
502 "KerberosNewerKeys key[0] != AES256");
504 if (k->ctr.ctr4.keys[1].keytype != ENCTYPE_AES128_CTS_HMAC_SHA1_96) {
505 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
506 "KerberosNewerKeys key[1] != AES128");
508 if (k->ctr.ctr4.keys[2].keytype != ENCTYPE_DES_CBC_MD5) {
509 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
510 "KerberosNewerKeys key[2] != DES_CBC_MD5");
512 if (k->ctr.ctr4.keys[3].keytype != ENCTYPE_DES_CBC_CRC) {
513 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
514 "KerberosNewerKeys key[3] != DES_CBC_CRC");
517 if (k->ctr.ctr4.keys[0].value_len != 32) {
518 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
519 "KerberosNewerKeys key[0] value_len != 32");
521 if (k->ctr.ctr4.keys[1].value_len != 16) {
522 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
523 "KerberosNewerKeys key[1] value_len != 16");
525 if (k->ctr.ctr4.keys[2].value_len != 8) {
526 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
527 "KerberosNewerKeys key[2] value_len != 8");
529 if (k->ctr.ctr4.keys[3].value_len != 8) {
530 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
531 "KerberosNewerKeys key[3] value_len != 8");
536 * Maybe we can check old and older keys here.
537 * But we need to do some tests, if the old keys
538 * can be taken from the PrimaryKerberos blob
539 * (with only des keys), when the domain was upgraded
547 struct package_PrimaryCLEARTEXTBlob *ct;
549 ct = talloc_zero(scb, struct package_PrimaryCLEARTEXTBlob);
551 return ldb_module_oom(module);
554 ndr_err = ndr_pull_struct_blob(&scpbct, ct, ct,
555 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryCLEARTEXTBlob);
556 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
557 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
558 "ndr_pull_struct_blob PrimaryCLEARTEXT");
561 if ((ct->cleartext.length % 2) != 0) {
562 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
563 "PrimaryCLEARTEXT length % 2 != 0");
569 ndr_err = ndr_push_struct_blob(&blob, scb, scb,
570 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
571 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
572 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
573 "ndr_pull_struct_blob_all");
576 if (sce->values[0].length != blob.length) {
577 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
578 "supplementalCredentialsBlob length differ");
581 if (memcmp(sce->values[0].data, blob.data, blob.length) != 0) {
582 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
583 "supplementalCredentialsBlob memcmp differ");
589 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_bypass - validated\n");
590 return ldb_next_request(module, request);
593 /* Get the NT hash, and fill it in as an entry in the password history,
594 and specify it into io->g.nt_hash */
596 static int setup_nt_fields(struct setup_password_fields_io *io)
598 struct ldb_context *ldb;
601 io->g.nt_hash = io->n.nt_hash;
602 ldb = ldb_module_get_ctx(io->ac->module);
604 if (io->ac->status->domain_data.pwdHistoryLength == 0) {
608 /* We might not have an old NT password */
609 io->g.nt_history = talloc_array(io->ac,
610 struct samr_Password,
611 io->ac->status->domain_data.pwdHistoryLength);
612 if (!io->g.nt_history) {
616 for (i = 0; i < MIN(io->ac->status->domain_data.pwdHistoryLength-1,
617 io->o.nt_history_len); i++) {
618 io->g.nt_history[i+1] = io->o.nt_history[i];
620 io->g.nt_history_len = i + 1;
623 io->g.nt_history[0] = *io->g.nt_hash;
626 * TODO: is this correct?
627 * the simular behavior is correct for the lm history case
629 E_md4hash("", io->g.nt_history[0].hash);
635 /* Get the LANMAN hash, and fill it in as an entry in the password history,
636 and specify it into io->g.lm_hash */
638 static int setup_lm_fields(struct setup_password_fields_io *io)
640 struct ldb_context *ldb;
643 io->g.lm_hash = io->n.lm_hash;
644 ldb = ldb_module_get_ctx(io->ac->module);
646 if (io->ac->status->domain_data.pwdHistoryLength == 0) {
650 /* We might not have an old LM password */
651 io->g.lm_history = talloc_array(io->ac,
652 struct samr_Password,
653 io->ac->status->domain_data.pwdHistoryLength);
654 if (!io->g.lm_history) {
658 for (i = 0; i < MIN(io->ac->status->domain_data.pwdHistoryLength-1,
659 io->o.lm_history_len); i++) {
660 io->g.lm_history[i+1] = io->o.lm_history[i];
662 io->g.lm_history_len = i + 1;
665 io->g.lm_history[0] = *io->g.lm_hash;
667 E_deshash("", io->g.lm_history[0].hash);
673 static int setup_kerberos_keys(struct setup_password_fields_io *io)
675 struct ldb_context *ldb;
676 krb5_error_code krb5_ret;
677 char *salt_principal = NULL;
678 char *salt_data = NULL;
681 krb5_data cleartext_data;
682 uint32_t uac_flags = 0;
684 ldb = ldb_module_get_ctx(io->ac->module);
685 cleartext_data.data = (char *)io->n.cleartext_utf8->data;
686 cleartext_data.length = io->n.cleartext_utf8->length;
688 uac_flags = io->u.userAccountControl & UF_ACCOUNT_TYPE_MASK;
689 krb5_ret = smb_krb5_salt_principal(io->ac->status->domain_data.realm,
690 io->u.sAMAccountName,
691 io->u.user_principal_name,
696 ldb_asprintf_errstring(ldb,
697 "setup_kerberos_keys: "
698 "generation of a salting principal failed: %s",
699 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
701 return LDB_ERR_OPERATIONS_ERROR;
705 * create salt from salt_principal
707 krb5_ret = smb_krb5_salt_principal2data(io->smb_krb5_context->krb5_context,
708 salt_principal, io->ac, &salt_data);
710 ldb_asprintf_errstring(ldb,
711 "setup_kerberos_keys: "
712 "generation of krb5_salt failed: %s",
713 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
715 return LDB_ERR_OPERATIONS_ERROR;
717 io->g.salt = salt_data;
719 /* now use the talloced copy of the salt */
720 salt.data = discard_const(io->g.salt);
721 salt.length = strlen(io->g.salt);
724 * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of
725 * the salt and the cleartext password
727 krb5_ret = smb_krb5_create_key_from_string(io->smb_krb5_context->krb5_context,
731 ENCTYPE_AES256_CTS_HMAC_SHA1_96,
734 ldb_asprintf_errstring(ldb,
735 "setup_kerberos_keys: "
736 "generation of a aes256-cts-hmac-sha1-96 key failed: %s",
737 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
739 return LDB_ERR_OPERATIONS_ERROR;
741 io->g.aes_256 = data_blob_talloc(io->ac,
743 KRB5_KEY_LENGTH(&key));
744 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
745 if (!io->g.aes_256.data) {
750 * create ENCTYPE_AES128_CTS_HMAC_SHA1_96 key out of
751 * the salt and the cleartext password
753 krb5_ret = smb_krb5_create_key_from_string(io->smb_krb5_context->krb5_context,
757 ENCTYPE_AES128_CTS_HMAC_SHA1_96,
760 ldb_asprintf_errstring(ldb,
761 "setup_kerberos_keys: "
762 "generation of a aes128-cts-hmac-sha1-96 key failed: %s",
763 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
765 return LDB_ERR_OPERATIONS_ERROR;
767 io->g.aes_128 = data_blob_talloc(io->ac,
769 KRB5_KEY_LENGTH(&key));
770 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
771 if (!io->g.aes_128.data) {
776 * create ENCTYPE_DES_CBC_MD5 key out of
777 * the salt and the cleartext password
779 krb5_ret = smb_krb5_create_key_from_string(io->smb_krb5_context->krb5_context,
786 ldb_asprintf_errstring(ldb,
787 "setup_kerberos_keys: "
788 "generation of a des-cbc-md5 key failed: %s",
789 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
791 return LDB_ERR_OPERATIONS_ERROR;
793 io->g.des_md5 = data_blob_talloc(io->ac,
795 KRB5_KEY_LENGTH(&key));
796 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
797 if (!io->g.des_md5.data) {
802 * create ENCTYPE_DES_CBC_CRC key out of
803 * the salt and the cleartext password
805 krb5_ret = smb_krb5_create_key_from_string(io->smb_krb5_context->krb5_context,
812 ldb_asprintf_errstring(ldb,
813 "setup_kerberos_keys: "
814 "generation of a des-cbc-crc key failed: %s",
815 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
817 return LDB_ERR_OPERATIONS_ERROR;
819 io->g.des_crc = data_blob_talloc(io->ac,
821 KRB5_KEY_LENGTH(&key));
822 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
823 if (!io->g.des_crc.data) {
830 static int setup_primary_kerberos(struct setup_password_fields_io *io,
831 const struct supplementalCredentialsBlob *old_scb,
832 struct package_PrimaryKerberosBlob *pkb)
834 struct ldb_context *ldb;
835 struct package_PrimaryKerberosCtr3 *pkb3 = &pkb->ctr.ctr3;
836 struct supplementalCredentialsPackage *old_scp = NULL;
837 struct package_PrimaryKerberosBlob _old_pkb;
838 struct package_PrimaryKerberosCtr3 *old_pkb3 = NULL;
840 enum ndr_err_code ndr_err;
842 ldb = ldb_module_get_ctx(io->ac->module);
845 * prepare generation of keys
847 * ENCTYPE_DES_CBC_MD5
848 * ENCTYPE_DES_CBC_CRC
851 pkb3->salt.string = io->g.salt;
853 pkb3->keys = talloc_array(io->ac,
854 struct package_PrimaryKerberosKey3,
860 pkb3->keys[0].keytype = ENCTYPE_DES_CBC_MD5;
861 pkb3->keys[0].value = &io->g.des_md5;
862 pkb3->keys[1].keytype = ENCTYPE_DES_CBC_CRC;
863 pkb3->keys[1].value = &io->g.des_crc;
865 /* initialize the old keys to zero */
866 pkb3->num_old_keys = 0;
867 pkb3->old_keys = NULL;
869 /* if there're no old keys, then we're done */
874 for (i=0; i < old_scb->sub.num_packages; i++) {
875 if (strcmp("Primary:Kerberos", old_scb->sub.packages[i].name) != 0) {
879 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
883 old_scp = &old_scb->sub.packages[i];
886 /* Primary:Kerberos element of supplementalCredentials */
890 blob = strhex_to_data_blob(io->ac, old_scp->data);
895 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
896 ndr_err = ndr_pull_struct_blob(&blob, io->ac, &_old_pkb,
897 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
898 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
899 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
900 ldb_asprintf_errstring(ldb,
901 "setup_primary_kerberos: "
902 "failed to pull old package_PrimaryKerberosBlob: %s",
904 return LDB_ERR_OPERATIONS_ERROR;
907 if (_old_pkb.version != 3) {
908 ldb_asprintf_errstring(ldb,
909 "setup_primary_kerberos: "
910 "package_PrimaryKerberosBlob version[%u] expected[3]",
912 return LDB_ERR_OPERATIONS_ERROR;
915 old_pkb3 = &_old_pkb.ctr.ctr3;
918 /* if we didn't found the old keys we're done */
923 /* fill in the old keys */
924 pkb3->num_old_keys = old_pkb3->num_keys;
925 pkb3->old_keys = old_pkb3->keys;
930 static int setup_primary_kerberos_newer(struct setup_password_fields_io *io,
931 const struct supplementalCredentialsBlob *old_scb,
932 struct package_PrimaryKerberosBlob *pkb)
934 struct ldb_context *ldb;
935 struct package_PrimaryKerberosCtr4 *pkb4 = &pkb->ctr.ctr4;
936 struct supplementalCredentialsPackage *old_scp = NULL;
937 struct package_PrimaryKerberosBlob _old_pkb;
938 struct package_PrimaryKerberosCtr4 *old_pkb4 = NULL;
940 enum ndr_err_code ndr_err;
942 ldb = ldb_module_get_ctx(io->ac->module);
945 * prepare generation of keys
947 * ENCTYPE_AES256_CTS_HMAC_SHA1_96
948 * ENCTYPE_AES128_CTS_HMAC_SHA1_96
949 * ENCTYPE_DES_CBC_MD5
950 * ENCTYPE_DES_CBC_CRC
953 pkb4->salt.string = io->g.salt;
954 pkb4->default_iteration_count = 4096;
957 pkb4->keys = talloc_array(io->ac,
958 struct package_PrimaryKerberosKey4,
964 pkb4->keys[0].iteration_count = 4096;
965 pkb4->keys[0].keytype = ENCTYPE_AES256_CTS_HMAC_SHA1_96;
966 pkb4->keys[0].value = &io->g.aes_256;
967 pkb4->keys[1].iteration_count = 4096;
968 pkb4->keys[1].keytype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
969 pkb4->keys[1].value = &io->g.aes_128;
970 pkb4->keys[2].iteration_count = 4096;
971 pkb4->keys[2].keytype = ENCTYPE_DES_CBC_MD5;
972 pkb4->keys[2].value = &io->g.des_md5;
973 pkb4->keys[3].iteration_count = 4096;
974 pkb4->keys[3].keytype = ENCTYPE_DES_CBC_CRC;
975 pkb4->keys[3].value = &io->g.des_crc;
977 /* initialize the old keys to zero */
978 pkb4->num_old_keys = 0;
979 pkb4->old_keys = NULL;
980 pkb4->num_older_keys = 0;
981 pkb4->older_keys = NULL;
983 /* if there're no old keys, then we're done */
988 for (i=0; i < old_scb->sub.num_packages; i++) {
989 if (strcmp("Primary:Kerberos-Newer-Keys", old_scb->sub.packages[i].name) != 0) {
993 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
997 old_scp = &old_scb->sub.packages[i];
1000 /* Primary:Kerberos-Newer-Keys element of supplementalCredentials */
1004 blob = strhex_to_data_blob(io->ac, old_scp->data);
1006 return ldb_oom(ldb);
1009 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
1010 ndr_err = ndr_pull_struct_blob(&blob, io->ac,
1012 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
1013 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1014 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1015 ldb_asprintf_errstring(ldb,
1016 "setup_primary_kerberos_newer: "
1017 "failed to pull old package_PrimaryKerberosBlob: %s",
1019 return LDB_ERR_OPERATIONS_ERROR;
1022 if (_old_pkb.version != 4) {
1023 ldb_asprintf_errstring(ldb,
1024 "setup_primary_kerberos_newer: "
1025 "package_PrimaryKerberosBlob version[%u] expected[4]",
1027 return LDB_ERR_OPERATIONS_ERROR;
1030 old_pkb4 = &_old_pkb.ctr.ctr4;
1033 /* if we didn't found the old keys we're done */
1038 /* fill in the old keys */
1039 pkb4->num_old_keys = old_pkb4->num_keys;
1040 pkb4->old_keys = old_pkb4->keys;
1041 pkb4->num_older_keys = old_pkb4->num_old_keys;
1042 pkb4->older_keys = old_pkb4->old_keys;
1047 static int setup_primary_wdigest(struct setup_password_fields_io *io,
1048 const struct supplementalCredentialsBlob *old_scb,
1049 struct package_PrimaryWDigestBlob *pdb)
1051 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1052 DATA_BLOB sAMAccountName;
1053 DATA_BLOB sAMAccountName_l;
1054 DATA_BLOB sAMAccountName_u;
1055 const char *user_principal_name = io->u.user_principal_name;
1056 DATA_BLOB userPrincipalName;
1057 DATA_BLOB userPrincipalName_l;
1058 DATA_BLOB userPrincipalName_u;
1059 DATA_BLOB netbios_domain;
1060 DATA_BLOB netbios_domain_l;
1061 DATA_BLOB netbios_domain_u;
1062 DATA_BLOB dns_domain;
1063 DATA_BLOB dns_domain_l;
1064 DATA_BLOB dns_domain_u;
1067 DATA_BLOB backslash;
1075 * See 3.1.1.8.11.3.1 WDIGEST_CREDENTIALS Construction
1076 * https://msdn.microsoft.com/en-us/library/cc245680.aspx
1077 * for what precalculated hashes are supposed to be stored...
1079 * I can't reproduce all values which should contain "Digest" as realm,
1080 * am I doing something wrong or is w2k3 just broken...?
1082 * W2K3 fills in following for a user:
1084 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
1085 * sAMAccountName: NewUser2Sam
1086 * userPrincipalName: NewUser2Princ@sub1.w2k3.vmnet1.vm.base
1088 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1089 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
1090 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
1091 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1092 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
1093 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
1094 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
1095 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1096 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1097 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1098 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1099 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1100 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1101 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1102 * 221c55284451ae9b3aacaa2a3c86f10f => NewUser2Princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1103 * 74e1be668853d4324d38c07e2acfb8ea => (w2k3 has a bug here!) newuser2princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1104 * e1e244ab7f098e3ae1761be7f9229bbb => NEWUSER2PRINC@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
1105 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
1106 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
1107 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
1108 * 31dc704d3640335b2123d4ee28aa1f11 => ??? changes with NewUser2Sam => NewUser1Sam
1109 * 36349f5cecd07320fb3bb0e119230c43 => ??? changes with NewUser2Sam => NewUser1Sam
1110 * 12adf019d037fb535c01fd0608e78d9d => ??? changes with NewUser2Sam => NewUser1Sam
1111 * 6feecf8e724906f3ee1105819c5105a1 => ??? changes with NewUser2Princ => NewUser1Princ
1112 * 6c6911f3de6333422640221b9c51ff1f => ??? changes with NewUser2Princ => NewUser1Princ
1113 * 4b279877e742895f9348ac67a8de2f69 => ??? changes with NewUser2Princ => NewUser1Princ
1114 * db0c6bff069513e3ebb9870d29b57490 => ??? changes with NewUser2Sam => NewUser1Sam
1115 * 45072621e56b1c113a4e04a8ff68cd0e => ??? changes with NewUser2Sam => NewUser1Sam
1116 * 11d1220abc44a9c10cf91ef4a9c1de02 => ??? changes with NewUser2Sam => NewUser1Sam
1118 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
1119 * sAMAccountName: NewUser2Sam
1121 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1122 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
1123 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
1124 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1125 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
1126 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
1127 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
1128 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1129 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1130 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1131 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1132 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1133 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1134 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1135 * 8a140d30b6f0a5912735dc1e3bc993b4 => NewUser2Sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1136 * 86d95b2faae6cae4ec261e7fbaccf093 => (here w2k3 is correct) newuser2sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1137 * dfeff1493110220efcdfc6362e5f5450 => NEWUSER2SAM@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
1138 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
1139 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
1140 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
1141 * 31dc704d3640335b2123d4ee28aa1f11 => ???M1 changes with NewUser2Sam => NewUser1Sam
1142 * 36349f5cecd07320fb3bb0e119230c43 => ???M1.L changes with newuser2sam => newuser1sam
1143 * 12adf019d037fb535c01fd0608e78d9d => ???M1.U changes with NEWUSER2SAM => NEWUSER1SAM
1144 * 569b4533f2d9e580211dd040e5e360a8 => ???M2 changes with NewUser2Princ => NewUser1Princ
1145 * 52528bddf310a587c5d7e6a9ae2cbb20 => ???M2.L changes with newuser2princ => newuser1princ
1146 * 4f629a4f0361289ca4255ab0f658fcd5 => ???M3 changes with NewUser2Princ => NewUser1Princ (doesn't depend on case of userPrincipal )
1147 * db0c6bff069513e3ebb9870d29b57490 => ???M4 changes with NewUser2Sam => NewUser1Sam
1148 * 45072621e56b1c113a4e04a8ff68cd0e => ???M5 changes with NewUser2Sam => NewUser1Sam (doesn't depend on case of sAMAccountName)
1149 * 11d1220abc44a9c10cf91ef4a9c1de02 => ???M4.U changes with NEWUSER2SAM => NEWUSER1SAM
1153 * sAMAccountName, netbios_domain
1156 .user = &sAMAccountName,
1157 .realm = &netbios_domain,
1160 .user = &sAMAccountName_l,
1161 .realm = &netbios_domain_l,
1164 .user = &sAMAccountName_u,
1165 .realm = &netbios_domain_u,
1168 .user = &sAMAccountName,
1169 .realm = &netbios_domain_u,
1172 .user = &sAMAccountName,
1173 .realm = &netbios_domain_l,
1176 .user = &sAMAccountName_u,
1177 .realm = &netbios_domain_l,
1180 .user = &sAMAccountName_l,
1181 .realm = &netbios_domain_u,
1184 * sAMAccountName, dns_domain
1187 * Windows preserves the case of the DNS domain,
1188 * Samba lower cases the domain at provision time
1189 * This means that for mixed case Domains, the WDigest08 hash
1190 * calculated by Samba differs from that calculated by Windows.
1191 * Until we get a real world use case this will remain a known
1192 * bug, as changing the case could have unforeseen impacts.
1196 .user = &sAMAccountName,
1197 .realm = &dns_domain,
1200 .user = &sAMAccountName_l,
1201 .realm = &dns_domain_l,
1204 .user = &sAMAccountName_u,
1205 .realm = &dns_domain_u,
1208 .user = &sAMAccountName,
1209 .realm = &dns_domain_u,
1212 .user = &sAMAccountName,
1213 .realm = &dns_domain_l,
1216 .user = &sAMAccountName_u,
1217 .realm = &dns_domain_l,
1220 .user = &sAMAccountName_l,
1221 .realm = &dns_domain_u,
1224 * userPrincipalName, no realm
1227 .user = &userPrincipalName,
1231 * NOTE: w2k3 messes this up, if the user has a real userPrincipalName,
1232 * the fallback to the sAMAccountName based userPrincipalName is correct
1234 .user = &userPrincipalName_l,
1237 .user = &userPrincipalName_u,
1240 * nt4dom\sAMAccountName, no realm
1243 .user = &sAMAccountName,
1244 .nt4dom = &netbios_domain
1247 .user = &sAMAccountName_l,
1248 .nt4dom = &netbios_domain_l
1251 .user = &sAMAccountName_u,
1252 .nt4dom = &netbios_domain_u
1256 * the following ones are guessed depending on the technet2 article
1257 * but not reproducable on a w2k3 server
1259 /* sAMAccountName with "Digest" realm */
1261 .user = &sAMAccountName,
1265 .user = &sAMAccountName_l,
1269 .user = &sAMAccountName_u,
1272 /* userPrincipalName with "Digest" realm */
1274 .user = &userPrincipalName,
1278 .user = &userPrincipalName_l,
1282 .user = &userPrincipalName_u,
1285 /* nt4dom\\sAMAccountName with "Digest" realm */
1287 .user = &sAMAccountName,
1288 .nt4dom = &netbios_domain,
1292 .user = &sAMAccountName_l,
1293 .nt4dom = &netbios_domain_l,
1297 .user = &sAMAccountName_u,
1298 .nt4dom = &netbios_domain_u,
1303 /* prepare DATA_BLOB's used in the combinations array */
1304 sAMAccountName = data_blob_string_const(io->u.sAMAccountName);
1305 sAMAccountName_l = data_blob_string_const(strlower_talloc(io->ac, io->u.sAMAccountName));
1306 if (!sAMAccountName_l.data) {
1307 return ldb_oom(ldb);
1309 sAMAccountName_u = data_blob_string_const(strupper_talloc(io->ac, io->u.sAMAccountName));
1310 if (!sAMAccountName_u.data) {
1311 return ldb_oom(ldb);
1314 /* if the user doesn't have a userPrincipalName, create one (with lower case realm) */
1315 if (!user_principal_name) {
1316 user_principal_name = talloc_asprintf(io->ac, "%s@%s",
1317 io->u.sAMAccountName,
1318 io->ac->status->domain_data.dns_domain);
1319 if (!user_principal_name) {
1320 return ldb_oom(ldb);
1323 userPrincipalName = data_blob_string_const(user_principal_name);
1324 userPrincipalName_l = data_blob_string_const(strlower_talloc(io->ac, user_principal_name));
1325 if (!userPrincipalName_l.data) {
1326 return ldb_oom(ldb);
1328 userPrincipalName_u = data_blob_string_const(strupper_talloc(io->ac, user_principal_name));
1329 if (!userPrincipalName_u.data) {
1330 return ldb_oom(ldb);
1333 netbios_domain = data_blob_string_const(io->ac->status->domain_data.netbios_domain);
1334 netbios_domain_l = data_blob_string_const(strlower_talloc(io->ac,
1335 io->ac->status->domain_data.netbios_domain));
1336 if (!netbios_domain_l.data) {
1337 return ldb_oom(ldb);
1339 netbios_domain_u = data_blob_string_const(strupper_talloc(io->ac,
1340 io->ac->status->domain_data.netbios_domain));
1341 if (!netbios_domain_u.data) {
1342 return ldb_oom(ldb);
1345 dns_domain = data_blob_string_const(io->ac->status->domain_data.dns_domain);
1346 dns_domain_l = data_blob_string_const(io->ac->status->domain_data.dns_domain);
1347 dns_domain_u = data_blob_string_const(io->ac->status->domain_data.realm);
1349 digest = data_blob_string_const("Digest");
1351 delim = data_blob_string_const(":");
1352 backslash = data_blob_string_const("\\");
1354 pdb->num_hashes = ARRAY_SIZE(wdigest);
1355 pdb->hashes = talloc_array(io->ac, struct package_PrimaryWDigestHash,
1358 return ldb_oom(ldb);
1361 for (i=0; i < ARRAY_SIZE(wdigest); i++) {
1364 if (wdigest[i].nt4dom) {
1365 MD5Update(&md5, wdigest[i].nt4dom->data, wdigest[i].nt4dom->length);
1366 MD5Update(&md5, backslash.data, backslash.length);
1368 MD5Update(&md5, wdigest[i].user->data, wdigest[i].user->length);
1369 MD5Update(&md5, delim.data, delim.length);
1370 if (wdigest[i].realm) {
1371 MD5Update(&md5, wdigest[i].realm->data, wdigest[i].realm->length);
1373 MD5Update(&md5, delim.data, delim.length);
1374 MD5Update(&md5, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length);
1375 MD5Final(pdb->hashes[i].hash, &md5);
1381 #define SHA_SALT_PERMITTED_CHARS "abcdefghijklmnopqrstuvwxyz" \
1382 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
1384 #define SHA_SALT_SIZE 16
1385 #define SHA_256_SCHEME "CryptSHA256"
1386 #define SHA_512_SCHEME "CryptSHA512"
1387 #define CRYPT "{CRYPT}"
1388 #define SHA_ID_LEN 3
1389 #define SHA_256_ALGORITHM_ID 5
1390 #define SHA_512_ALGORITHM_ID 6
1391 #define ROUNDS_PARAMETER "rounds="
1394 * Extract the crypt (3) algorithm number and number of hash rounds from the
1395 * supplied scheme string
1397 static bool parse_scheme(const char *scheme, int *algorithm, int *rounds) {
1399 const char *rp = NULL; /* Pointer to the 'rounds=' option */
1400 char digits[21]; /* digits extracted from the rounds option */
1401 int i = 0; /* loop index variable */
1403 if (strncasecmp(SHA_256_SCHEME, scheme, strlen(SHA_256_SCHEME)) == 0) {
1404 *algorithm = SHA_256_ALGORITHM_ID;
1405 } else if (strncasecmp(SHA_512_SCHEME, scheme, strlen(SHA_256_SCHEME))
1407 *algorithm = SHA_512_ALGORITHM_ID;
1412 rp = strcasestr(scheme, ROUNDS_PARAMETER);
1414 /* No options specified, use crypt default number of rounds */
1418 rp += strlen(ROUNDS_PARAMETER);
1419 for (i = 0; isdigit(rp[i]) && i < (sizeof(digits) - 1); i++) {
1423 *rounds = atoi(digits);
1428 * Calculate the password hash specified by scheme, and return it in
1431 static int setup_primary_userPassword_hash(
1433 struct setup_password_fields_io *io,
1435 struct package_PrimaryUserPasswordValue *hash_value)
1437 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1438 const char *salt = NULL; /* Randomly generated salt */
1439 const char *cmd = NULL; /* command passed to crypt */
1440 const char *hash = NULL; /* password hash generated by crypt */
1441 int algorithm = 0; /* crypt hash algorithm number */
1442 int rounds = 0; /* The number of hash rounds */
1443 DATA_BLOB *hash_blob = NULL;
1444 TALLOC_CTX *frame = talloc_stackframe();
1446 struct crypt_data crypt_data; /* working storage used by crypt */
1449 /* Genrate a random password salt */
1450 salt = generate_random_str_list(frame,
1452 SHA_SALT_PERMITTED_CHARS);
1455 return ldb_oom(ldb);
1458 /* determine the hashing algoritm and number of rounds*/
1459 if (!parse_scheme(scheme, &algorithm, &rounds)) {
1460 ldb_asprintf_errstring(
1462 "setup_primary_userPassword: Invalid scheme of [%s] "
1463 "specified for 'password hash userPassword schemes' in "
1467 return LDB_ERR_OPERATIONS_ERROR;
1469 hash_value->scheme = talloc_strdup(ctx, CRYPT);
1470 hash_value->scheme_len = strlen(CRYPT) + 1;
1472 /* generate the id/salt parameter used by crypt */
1474 cmd = talloc_asprintf(frame,
1480 cmd = talloc_asprintf(frame, "$%d$%s", algorithm, salt);
1484 * Relies on the assertion that cleartext_utf8->data is a zero
1485 * terminated UTF-8 string
1489 hash = crypt_r((char *)io->n.cleartext_utf8->data, cmd, &crypt_data);
1492 * No crypt_r falling back to crypt, which is NOT thread safe
1493 * Thread safety MT-Unsafe race:crypt
1495 hash = crypt((char *)io->n.cleartext_utf8->data, cmd);
1497 /* crypt_r and crypt may return a null pointer upon error depending on
1498 * how libcrypt was configured. POSIX specifies returning a null
1499 * pointer and setting errno. */
1500 if (hash == NULL || errno != 0) {
1502 int err = strerror_r(errno, buf, sizeof(buf));
1504 strlcpy(buf, "Unknown error", sizeof(buf)-1);
1506 ldb_asprintf_errstring(
1508 "setup_primary_userPassword: generation of a %s "
1509 "password hash failed: (%s)",
1513 return LDB_ERR_OPERATIONS_ERROR;
1516 hash_blob = talloc_zero(ctx, DATA_BLOB);
1518 if (hash_blob == NULL) {
1520 return ldb_oom(ldb);
1523 *hash_blob = data_blob_talloc(hash_blob,
1524 (const uint8_t *)hash,
1526 if (hash_blob->data == NULL) {
1528 return ldb_oom(ldb);
1530 hash_value->value = hash_blob;
1536 * Calculate the desired extra password hashes
1538 static int setup_primary_userPassword(
1539 struct setup_password_fields_io *io,
1540 const struct supplementalCredentialsBlob *old_scb,
1541 struct package_PrimaryUserPasswordBlob *p_userPassword_b)
1543 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1544 TALLOC_CTX *frame = talloc_stackframe();
1549 * Save the current nt_hash, use this to determine if the password
1550 * has been changed by windows. Which will invalidate the userPassword
1551 * hash. Note once NTLM-Strong-NOWTF becomes available it should be
1552 * used in preference to the NT password hash
1554 if (io->g.nt_hash == NULL) {
1555 ldb_asprintf_errstring(ldb,
1556 "No NT Hash, unable to calculate userPassword hashes");
1557 return LDB_ERR_UNWILLING_TO_PERFORM;
1559 p_userPassword_b->current_nt_hash = *io->g.nt_hash;
1562 * Determine the number of hashes
1563 * Note: that currently there is no limit on the number of hashes
1564 * no checking is done on the number of schemes specified
1565 * or for uniqueness.
1567 p_userPassword_b->num_hashes = 0;
1568 for (i = 0; io->ac->userPassword_schemes[i]; i++) {
1569 p_userPassword_b->num_hashes++;
1572 p_userPassword_b->hashes
1573 = talloc_array(io->ac,
1574 struct package_PrimaryUserPasswordValue,
1575 p_userPassword_b->num_hashes);
1576 if (p_userPassword_b->hashes == NULL) {
1578 return ldb_oom(ldb);
1581 for (i = 0; io->ac->userPassword_schemes[i]; i++) {
1582 ret = setup_primary_userPassword_hash(
1583 p_userPassword_b->hashes,
1585 io->ac->userPassword_schemes[i],
1586 &p_userPassword_b->hashes[i]);
1587 if (ret != LDB_SUCCESS) {
1596 static int setup_primary_samba_gpg(struct setup_password_fields_io *io,
1597 struct package_PrimarySambaGPGBlob *pgb)
1599 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1602 gpgme_ctx_t ctx = NULL;
1603 size_t num_keys = str_list_length(io->ac->gpg_key_ids);
1604 gpgme_key_t keys[num_keys+1];
1607 gpgme_data_t plain_data = NULL;
1608 gpgme_data_t crypt_data = NULL;
1609 size_t crypt_length = 0;
1610 char *crypt_mem = NULL;
1612 gret = gpgme_new(&ctx);
1613 if (gret != GPG_ERR_NO_ERROR) {
1614 ldb_debug(ldb, LDB_DEBUG_ERROR,
1615 "%s:%s: gret[%u] %s\n",
1616 __location__, __func__,
1617 gret, gpgme_strerror(gret));
1618 return ldb_module_operr(io->ac->module);
1621 gpgme_set_armor(ctx, 1);
1623 gret = gpgme_data_new_from_mem(&plain_data,
1624 (const char *)io->n.cleartext_utf16->data,
1625 io->n.cleartext_utf16->length,
1627 if (gret != GPG_ERR_NO_ERROR) {
1628 ldb_debug(ldb, LDB_DEBUG_ERROR,
1629 "%s:%s: gret[%u] %s\n",
1630 __location__, __func__,
1631 gret, gpgme_strerror(gret));
1633 return ldb_module_operr(io->ac->module);
1635 gret = gpgme_data_new(&crypt_data);
1636 if (gret != GPG_ERR_NO_ERROR) {
1637 ldb_debug(ldb, LDB_DEBUG_ERROR,
1638 "%s:%s: gret[%u] %s\n",
1639 __location__, __func__,
1640 gret, gpgme_strerror(gret));
1641 gpgme_data_release(plain_data);
1643 return ldb_module_operr(io->ac->module);
1646 for (ki = 0; ki < num_keys; ki++) {
1647 const char *key_id = io->ac->gpg_key_ids[ki];
1648 size_t len = strlen(key_id);
1653 ldb_debug(ldb, LDB_DEBUG_FATAL,
1654 "%s:%s: ki[%zu] key_id[%s] strlen < 16, "
1655 "please specify at least the 64bit key id\n",
1656 __location__, __func__,
1658 for (kr = 0; keys[kr] != NULL; kr++) {
1659 gpgme_key_release(keys[kr]);
1661 gpgme_data_release(crypt_data);
1662 gpgme_data_release(plain_data);
1664 return ldb_module_operr(io->ac->module);
1667 gret = gpgme_get_key(ctx, key_id, &keys[ki], 0 /* public key */);
1668 if (gret != GPG_ERR_NO_ERROR) {
1670 if (gpg_err_source(gret) == GPG_ERR_SOURCE_GPGME
1671 && gpg_err_code(gret) == GPG_ERR_EOF) {
1672 ldb_debug(ldb, LDB_DEBUG_ERROR,
1674 "'password hash gpg key ids': "
1675 "Public Key ID [%s] "
1676 "not found in keyring\n",
1680 ldb_debug(ldb, LDB_DEBUG_ERROR,
1681 "%s:%s: ki[%zu] key_id[%s] "
1683 __location__, __func__,
1685 gret, gpgme_strerror(gret));
1687 for (kr = 0; keys[kr] != NULL; kr++) {
1688 gpgme_key_release(keys[kr]);
1690 gpgme_data_release(crypt_data);
1691 gpgme_data_release(plain_data);
1693 return ldb_module_operr(io->ac->module);
1698 gret = gpgme_op_encrypt(ctx, keys,
1699 GPGME_ENCRYPT_ALWAYS_TRUST,
1700 plain_data, crypt_data);
1701 gpgme_data_release(plain_data);
1703 for (kr = 0; keys[kr] != NULL; kr++) {
1704 gpgme_key_release(keys[kr]);
1709 if (gret != GPG_ERR_NO_ERROR) {
1710 ldb_debug(ldb, LDB_DEBUG_ERROR,
1711 "%s:%s: gret[%u] %s\n",
1712 __location__, __func__,
1713 gret, gpgme_strerror(gret));
1714 gpgme_data_release(crypt_data);
1715 return ldb_module_operr(io->ac->module);
1718 crypt_mem = gpgme_data_release_and_get_mem(crypt_data, &crypt_length);
1720 if (crypt_mem == NULL) {
1721 return ldb_module_oom(io->ac->module);
1724 pgb->gpg_blob = data_blob_talloc(io->ac,
1725 (const uint8_t *)crypt_mem,
1727 gpgme_free(crypt_mem);
1730 if (pgb->gpg_blob.data == NULL) {
1731 return ldb_module_oom(io->ac->module);
1735 #else /* ENABLE_GPGME */
1736 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
1737 "You configured 'password hash gpg key ids', "
1738 "but GPGME support is missing. (%s:%d)",
1739 __FILE__, __LINE__);
1740 return LDB_ERR_UNWILLING_TO_PERFORM;
1741 #endif /* else ENABLE_GPGME */
1744 #define NUM_PACKAGES 6
1745 static int setup_supplemental_field(struct setup_password_fields_io *io)
1747 struct ldb_context *ldb;
1748 struct supplementalCredentialsBlob scb;
1749 struct supplementalCredentialsBlob *old_scb = NULL;
1752 * ( Kerberos-Newer-Keys, Kerberos,
1753 * WDigest, CLEARTEXT, userPassword, SambaGPG)
1755 uint32_t num_names = 0;
1756 const char *names[1+NUM_PACKAGES];
1757 uint32_t num_packages = 0;
1758 struct supplementalCredentialsPackage packages[1+NUM_PACKAGES];
1759 struct supplementalCredentialsPackage *pp = packages;
1761 enum ndr_err_code ndr_err;
1762 bool do_newer_keys = false;
1763 bool do_cleartext = false;
1764 bool do_samba_gpg = false;
1767 ZERO_STRUCT(packages);
1769 ldb = ldb_module_get_ctx(io->ac->module);
1771 if (!io->n.cleartext_utf8) {
1773 * when we don't have a cleartext password
1774 * we can't setup a supplementalCredential value
1779 /* if there's an old supplementaCredentials blob then use it */
1780 if (io->o.supplemental) {
1781 if (io->o.scb.sub.signature == SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
1782 old_scb = &io->o.scb;
1784 ldb_debug(ldb, LDB_DEBUG_ERROR,
1785 "setup_supplemental_field: "
1786 "supplementalCredentialsBlob "
1787 "signature[0x%04X] expected[0x%04X]",
1788 io->o.scb.sub.signature,
1789 SUPPLEMENTAL_CREDENTIALS_SIGNATURE);
1792 /* Per MS-SAMR 3.1.1.8.11.6 we create AES keys if our domain functionality level is 2008 or higher */
1797 * The ordering is this
1799 * Primary:Kerberos-Newer-Keys (optional)
1802 * Primary:CLEARTEXT (optional)
1803 * Primary:userPassword
1804 * Primary:SambaGPG (optional)
1806 * And the 'Packages' package is insert before the last
1809 * Note: it's important that Primary:SambaGPG is added as
1810 * the last element. This is the indication that it matches
1811 * the current password. When a password change happens on
1812 * a Windows DC, it will keep the old Primary:SambaGPG value,
1813 * but as the first element.
1815 do_newer_keys = (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008);
1816 if (do_newer_keys) {
1817 struct package_PrimaryKerberosBlob pknb;
1818 DATA_BLOB pknb_blob;
1821 * setup 'Primary:Kerberos-Newer-Keys' element
1823 names[num_names++] = "Kerberos-Newer-Keys";
1825 ret = setup_primary_kerberos_newer(io, old_scb, &pknb);
1826 if (ret != LDB_SUCCESS) {
1830 ndr_err = ndr_push_struct_blob(
1833 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1834 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1835 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1836 ldb_asprintf_errstring(
1838 "setup_supplemental_field: "
1840 "package_PrimaryKerberosNeverBlob: %s",
1842 return LDB_ERR_OPERATIONS_ERROR;
1844 pknb_hexstr = data_blob_hex_string_upper(io->ac, &pknb_blob);
1846 return ldb_oom(ldb);
1848 pp->name = "Primary:Kerberos-Newer-Keys";
1850 pp->data = pknb_hexstr;
1857 * setup 'Primary:Kerberos' element
1859 /* Primary:Kerberos */
1860 struct package_PrimaryKerberosBlob pkb;
1864 names[num_names++] = "Kerberos";
1866 ret = setup_primary_kerberos(io, old_scb, &pkb);
1867 if (ret != LDB_SUCCESS) {
1871 ndr_err = ndr_push_struct_blob(
1874 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1875 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1876 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1877 ldb_asprintf_errstring(
1879 "setup_supplemental_field: "
1880 "failed to push package_PrimaryKerberosBlob: %s",
1882 return LDB_ERR_OPERATIONS_ERROR;
1884 pkb_hexstr = data_blob_hex_string_upper(io->ac, &pkb_blob);
1886 return ldb_oom(ldb);
1888 pp->name = "Primary:Kerberos";
1890 pp->data = pkb_hexstr;
1897 * setup 'Primary:WDigest' element
1899 struct package_PrimaryWDigestBlob pdb;
1903 names[num_names++] = "WDigest";
1905 ret = setup_primary_wdigest(io, old_scb, &pdb);
1906 if (ret != LDB_SUCCESS) {
1910 ndr_err = ndr_push_struct_blob(
1913 (ndr_push_flags_fn_t)ndr_push_package_PrimaryWDigestBlob);
1914 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1915 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1916 ldb_asprintf_errstring(
1918 "setup_supplemental_field: "
1919 "failed to push package_PrimaryWDigestBlob: %s",
1921 return LDB_ERR_OPERATIONS_ERROR;
1923 pdb_hexstr = data_blob_hex_string_upper(io->ac, &pdb_blob);
1925 return ldb_oom(ldb);
1927 pp->name = "Primary:WDigest";
1929 pp->data = pdb_hexstr;
1935 * setup 'Primary:CLEARTEXT' element
1937 if (io->ac->status->domain_data.store_cleartext &&
1938 (io->u.userAccountControl & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) {
1939 do_cleartext = true;
1942 struct package_PrimaryCLEARTEXTBlob pcb;
1946 names[num_names++] = "CLEARTEXT";
1948 pcb.cleartext = *io->n.cleartext_utf16;
1950 ndr_err = ndr_push_struct_blob(
1953 (ndr_push_flags_fn_t)ndr_push_package_PrimaryCLEARTEXTBlob);
1954 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1955 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1956 ldb_asprintf_errstring(
1958 "setup_supplemental_field: "
1959 "failed to push package_PrimaryCLEARTEXTBlob: %s",
1961 return LDB_ERR_OPERATIONS_ERROR;
1963 pcb_hexstr = data_blob_hex_string_upper(io->ac, &pcb_blob);
1965 return ldb_oom(ldb);
1967 pp->name = "Primary:CLEARTEXT";
1969 pp->data = pcb_hexstr;
1974 if (io->ac->userPassword_schemes) {
1976 * setup 'Primary:userPassword' element
1978 struct package_PrimaryUserPasswordBlob
1980 DATA_BLOB p_userPassword_b_blob;
1981 char *p_userPassword_b_hexstr;
1983 names[num_names++] = "userPassword";
1985 ret = setup_primary_userPassword(io,
1988 if (ret != LDB_SUCCESS) {
1992 ndr_err = ndr_push_struct_blob(
1993 &p_userPassword_b_blob,
1996 (ndr_push_flags_fn_t)
1997 ndr_push_package_PrimaryUserPasswordBlob);
1998 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1999 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2000 ldb_asprintf_errstring(
2002 "setup_supplemental_field: failed to push "
2003 "package_PrimaryUserPasswordBlob: %s",
2005 return LDB_ERR_OPERATIONS_ERROR;
2007 p_userPassword_b_hexstr
2008 = data_blob_hex_string_upper(
2010 &p_userPassword_b_blob);
2011 if (!p_userPassword_b_hexstr) {
2012 return ldb_oom(ldb);
2014 pp->name = "Primary:userPassword";
2016 pp->data = p_userPassword_b_hexstr;
2022 * setup 'Primary:SambaGPG' element
2024 if (io->ac->gpg_key_ids != NULL) {
2025 do_samba_gpg = true;
2028 struct package_PrimarySambaGPGBlob pgb;
2032 names[num_names++] = "SambaGPG";
2034 ret = setup_primary_samba_gpg(io, &pgb);
2035 if (ret != LDB_SUCCESS) {
2039 ndr_err = ndr_push_struct_blob(&pgb_blob, io->ac, &pgb,
2040 (ndr_push_flags_fn_t)ndr_push_package_PrimarySambaGPGBlob);
2041 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2042 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2043 ldb_asprintf_errstring(ldb,
2044 "setup_supplemental_field: failed to "
2045 "push package_PrimarySambaGPGBlob: %s",
2047 return LDB_ERR_OPERATIONS_ERROR;
2049 pgb_hexstr = data_blob_hex_string_upper(io->ac, &pgb_blob);
2051 return ldb_oom(ldb);
2053 pp->name = "Primary:SambaGPG";
2055 pp->data = pgb_hexstr;
2061 * setup 'Packages' element
2064 struct package_PackagesBlob pb;
2069 ndr_err = ndr_push_struct_blob(
2072 (ndr_push_flags_fn_t)ndr_push_package_PackagesBlob);
2073 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2074 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2075 ldb_asprintf_errstring(
2077 "setup_supplemental_field: "
2078 "failed to push package_PackagesBlob: %s",
2080 return LDB_ERR_OPERATIONS_ERROR;
2082 pb_hexstr = data_blob_hex_string_upper(io->ac, &pb_blob);
2084 return ldb_oom(ldb);
2086 pp->name = "Packages";
2088 pp->data = pb_hexstr;
2091 * We don't increment pp so it's pointing to the last package
2096 * setup 'supplementalCredentials' value
2100 * The 'Packages' element needs to be the second last element
2101 * in supplementalCredentials
2103 struct supplementalCredentialsPackage temp;
2104 struct supplementalCredentialsPackage *prev;
2112 scb.sub.signature = SUPPLEMENTAL_CREDENTIALS_SIGNATURE;
2113 scb.sub.num_packages = num_packages;
2114 scb.sub.packages = packages;
2116 ndr_err = ndr_push_struct_blob(
2117 &io->g.supplemental, io->ac,
2119 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
2120 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2121 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2122 ldb_asprintf_errstring(
2124 "setup_supplemental_field: "
2125 "failed to push supplementalCredentialsBlob: %s",
2127 return LDB_ERR_OPERATIONS_ERROR;
2134 static int setup_last_set_field(struct setup_password_fields_io *io)
2136 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2137 const struct ldb_message *msg = NULL;
2138 struct timeval tv = { .tv_sec = 0 };
2139 const struct ldb_val *old_val = NULL;
2140 const struct ldb_val *new_val = NULL;
2143 switch (io->ac->req->operation) {
2145 msg = io->ac->req->op.add.message;
2148 msg = io->ac->req->op.mod.message;
2151 return LDB_ERR_OPERATIONS_ERROR;
2155 if (io->ac->pwd_last_set_bypass) {
2156 struct ldb_message_element *el1 = NULL;
2157 struct ldb_message_element *el2 = NULL;
2160 return LDB_ERR_CONSTRAINT_VIOLATION;
2163 el1 = dsdb_get_single_valued_attr(msg, "pwdLastSet",
2164 io->ac->req->operation);
2166 return LDB_ERR_CONSTRAINT_VIOLATION;
2168 el2 = ldb_msg_find_element(msg, "pwdLastSet");
2170 return LDB_ERR_CONSTRAINT_VIOLATION;
2173 return LDB_ERR_CONSTRAINT_VIOLATION;
2176 io->g.last_set = samdb_result_nttime(msg, "pwdLastSet", 0);
2180 ret = msg_find_old_and_new_pwd_val(msg, "pwdLastSet",
2181 io->ac->req->operation,
2182 &new_val, &old_val);
2183 if (ret != LDB_SUCCESS) {
2187 if (old_val != NULL && new_val == NULL) {
2188 ldb_set_errstring(ldb,
2189 "'pwdLastSet' deletion is not allowed!");
2190 return LDB_ERR_UNWILLING_TO_PERFORM;
2193 io->g.last_set = UINT64_MAX;
2194 if (new_val != NULL) {
2195 struct ldb_message *tmp_msg = NULL;
2197 tmp_msg = ldb_msg_new(io->ac);
2198 if (tmp_msg == NULL) {
2199 return ldb_module_oom(io->ac->module);
2202 if (old_val != NULL) {
2203 NTTIME old_last_set = 0;
2205 ret = ldb_msg_add_value(tmp_msg, "oldval",
2207 if (ret != LDB_SUCCESS) {
2211 old_last_set = samdb_result_nttime(tmp_msg,
2214 if (io->u.pwdLastSet != old_last_set) {
2215 return dsdb_module_werror(io->ac->module,
2216 LDB_ERR_NO_SUCH_ATTRIBUTE,
2217 WERR_DS_CANT_REM_MISSING_ATT_VAL,
2218 "setup_last_set_field: old pwdLastSet "
2219 "value not found!");
2223 ret = ldb_msg_add_value(tmp_msg, "newval",
2225 if (ret != LDB_SUCCESS) {
2229 io->g.last_set = samdb_result_nttime(tmp_msg,
2232 } else if (ldb_msg_find_element(msg, "pwdLastSet")) {
2233 ldb_set_errstring(ldb,
2234 "'pwdLastSet' deletion is not allowed!");
2235 return LDB_ERR_UNWILLING_TO_PERFORM;
2236 } else if (io->ac->smartcard_reset) {
2238 * adding UF_SMARTCARD_REQUIRED doesn't update
2239 * pwdLastSet implicitly.
2241 io->ac->update_lastset = false;
2244 /* only 0 or -1 (0xFFFFFFFFFFFFFFFF) are allowed */
2245 switch (io->g.last_set) {
2247 if (!io->ac->pwd_last_set_default) {
2250 if (!io->ac->update_password) {
2255 if (!io->ac->update_password &&
2256 io->u.pwdLastSet != 0 &&
2257 io->u.pwdLastSet != UINT64_MAX)
2260 * Just setting pwdLastSet to -1, while not changing
2261 * any password field has no effect if pwdLastSet
2262 * is already non-zero.
2264 io->ac->update_lastset = false;
2267 /* -1 means set it as now */
2269 io->g.last_set = timeval_to_nttime(&tv);
2272 return dsdb_module_werror(io->ac->module,
2274 WERR_INVALID_PARAMETER,
2275 "setup_last_set_field: "
2276 "pwdLastSet must be 0 or -1 only!");
2279 if (io->ac->req->operation == LDB_ADD) {
2281 * We always need to store the value on add
2287 if (io->g.last_set == io->u.pwdLastSet) {
2289 * Just setting pwdLastSet to 0, is no-op if it's already 0.
2291 io->ac->update_lastset = false;
2297 static int setup_given_passwords(struct setup_password_fields_io *io,
2298 struct setup_password_fields_given *g)
2300 struct ldb_context *ldb;
2303 ldb = ldb_module_get_ctx(io->ac->module);
2305 if (g->cleartext_utf8) {
2306 struct ldb_val *cleartext_utf16_blob;
2308 cleartext_utf16_blob = talloc(io->ac, struct ldb_val);
2309 if (!cleartext_utf16_blob) {
2310 return ldb_oom(ldb);
2312 if (!convert_string_talloc(io->ac,
2314 g->cleartext_utf8->data,
2315 g->cleartext_utf8->length,
2316 (void *)&cleartext_utf16_blob->data,
2317 &cleartext_utf16_blob->length)) {
2318 if (g->cleartext_utf8->length != 0) {
2319 talloc_free(cleartext_utf16_blob);
2320 ldb_asprintf_errstring(ldb,
2321 "setup_password_fields: "
2322 "failed to generate UTF16 password from cleartext UTF8 one for user '%s'!",
2323 io->u.sAMAccountName);
2324 return LDB_ERR_CONSTRAINT_VIOLATION;
2326 /* passwords with length "0" are valid! */
2327 cleartext_utf16_blob->data = NULL;
2328 cleartext_utf16_blob->length = 0;
2331 g->cleartext_utf16 = cleartext_utf16_blob;
2332 } else if (g->cleartext_utf16) {
2333 struct ldb_val *cleartext_utf8_blob;
2335 cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
2336 if (!cleartext_utf8_blob) {
2337 return ldb_oom(ldb);
2339 if (!convert_string_talloc(io->ac,
2340 CH_UTF16MUNGED, CH_UTF8,
2341 g->cleartext_utf16->data,
2342 g->cleartext_utf16->length,
2343 (void *)&cleartext_utf8_blob->data,
2344 &cleartext_utf8_blob->length)) {
2345 if (g->cleartext_utf16->length != 0) {
2346 /* We must bail out here, the input wasn't even
2347 * a multiple of 2 bytes */
2348 talloc_free(cleartext_utf8_blob);
2349 ldb_asprintf_errstring(ldb,
2350 "setup_password_fields: "
2351 "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)!",
2352 io->u.sAMAccountName);
2353 return LDB_ERR_CONSTRAINT_VIOLATION;
2355 /* passwords with length "0" are valid! */
2356 cleartext_utf8_blob->data = NULL;
2357 cleartext_utf8_blob->length = 0;
2360 g->cleartext_utf8 = cleartext_utf8_blob;
2363 if (g->cleartext_utf16) {
2364 struct samr_Password *nt_hash;
2366 nt_hash = talloc(io->ac, struct samr_Password);
2368 return ldb_oom(ldb);
2370 g->nt_hash = nt_hash;
2372 /* compute the new nt hash */
2373 mdfour(nt_hash->hash,
2374 g->cleartext_utf16->data,
2375 g->cleartext_utf16->length);
2378 if (g->cleartext_utf8) {
2379 struct samr_Password *lm_hash;
2381 lm_hash = talloc(io->ac, struct samr_Password);
2383 return ldb_oom(ldb);
2386 /* compute the new lm hash */
2387 ok = E_deshash((char *)g->cleartext_utf8->data, lm_hash->hash);
2389 g->lm_hash = lm_hash;
2391 talloc_free(lm_hash);
2398 static int setup_password_fields(struct setup_password_fields_io *io)
2400 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2401 struct loadparm_context *lp_ctx =
2402 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2403 struct loadparm_context);
2406 ret = setup_last_set_field(io);
2407 if (ret != LDB_SUCCESS) {
2411 if (!io->ac->update_password) {
2415 /* transform the old password (for password changes) */
2416 ret = setup_given_passwords(io, &io->og);
2417 if (ret != LDB_SUCCESS) {
2421 /* transform the new password */
2422 ret = setup_given_passwords(io, &io->n);
2423 if (ret != LDB_SUCCESS) {
2427 if (io->n.cleartext_utf8) {
2428 ret = setup_kerberos_keys(io);
2429 if (ret != LDB_SUCCESS) {
2434 ret = setup_nt_fields(io);
2435 if (ret != LDB_SUCCESS) {
2439 if (lpcfg_lanman_auth(lp_ctx)) {
2440 ret = setup_lm_fields(io);
2441 if (ret != LDB_SUCCESS) {
2445 io->g.lm_hash = NULL;
2446 io->g.lm_history_len = 0;
2449 ret = setup_supplemental_field(io);
2450 if (ret != LDB_SUCCESS) {
2457 static int setup_smartcard_reset(struct setup_password_fields_io *io)
2459 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2460 struct loadparm_context *lp_ctx = talloc_get_type(
2461 ldb_get_opaque(ldb, "loadparm"), struct loadparm_context);
2462 struct supplementalCredentialsBlob scb = { .__ndr_size = 0 };
2463 enum ndr_err_code ndr_err;
2465 if (!io->ac->smartcard_reset) {
2469 io->g.nt_hash = talloc(io->ac, struct samr_Password);
2470 if (io->g.nt_hash == NULL) {
2471 return ldb_module_oom(io->ac->module);
2473 generate_secret_buffer(io->g.nt_hash->hash,
2474 sizeof(io->g.nt_hash->hash));
2475 io->g.nt_history_len = 0;
2477 if (lpcfg_lanman_auth(lp_ctx)) {
2478 io->g.lm_hash = talloc(io->ac, struct samr_Password);
2479 if (io->g.lm_hash == NULL) {
2480 return ldb_module_oom(io->ac->module);
2482 generate_secret_buffer(io->g.lm_hash->hash,
2483 sizeof(io->g.lm_hash->hash));
2485 io->g.lm_hash = NULL;
2487 io->g.lm_history_len = 0;
2490 * We take the "old" value and store it
2491 * with num_packages = 0.
2493 * On "add" we have scb.sub.signature == 0, which
2496 * [0000] 00 00 00 00 00 00 00 00 00 00 00 00 00
2498 * On modify it's likely to be scb.sub.signature ==
2499 * SUPPLEMENTAL_CREDENTIALS_SIGNATURE (0x0050), which results in
2502 * [0000] 00 00 00 00 62 00 00 00 00 00 00 00 20 00 20 00
2503 * [0010] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2504 * [0020] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2505 * [0030] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2506 * [0040] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2507 * [0050] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2508 * [0060] 20 00 20 00 20 00 20 00 20 00 20 00 50 00 00
2510 * See https://bugzilla.samba.org/show_bug.cgi?id=11441
2511 * and ndr_{push,pull}_supplementalCredentialsSubBlob().
2514 scb.sub.num_packages = 0;
2517 * setup 'supplementalCredentials' value without packages
2519 ndr_err = ndr_push_struct_blob(&io->g.supplemental, io->ac,
2521 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
2522 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2523 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2524 ldb_asprintf_errstring(ldb,
2525 "setup_smartcard_reset: "
2526 "failed to push supplementalCredentialsBlob: %s",
2528 return LDB_ERR_OPERATIONS_ERROR;
2531 io->ac->update_password = true;
2535 static int make_error_and_update_badPwdCount(struct setup_password_fields_io *io, WERROR *werror)
2537 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2538 struct ldb_message *mod_msg = NULL;
2539 struct ldb_message *pso_msg = NULL;
2543 /* PSO search result is optional (NULL if no PSO applies) */
2544 if (io->ac->pso_res != NULL) {
2545 pso_msg = io->ac->pso_res->message;
2548 status = dsdb_update_bad_pwd_count(io->ac, ldb,
2549 io->ac->search_res->message,
2550 io->ac->dom_res->message,
2553 if (!NT_STATUS_IS_OK(status)) {
2557 if (mod_msg == NULL) {
2562 * OK, horrible semantics ahead.
2564 * - We need to abort any existing transaction
2565 * - create a transaction arround the badPwdCount update
2566 * - re-open the transaction so the upper layer
2567 * doesn't know what happened.
2569 * This is needed because returning an error to the upper
2570 * layer will cancel the transaction and undo the badPwdCount
2575 * Checking errors here is a bit pointless.
2576 * What can we do if we can't end the transaction?
2578 ret = ldb_next_del_trans(io->ac->module);
2579 if (ret != LDB_SUCCESS) {
2580 ldb_debug(ldb, LDB_DEBUG_FATAL,
2581 "Failed to abort transaction prior to update of badPwdCount of %s: %s",
2582 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2583 ldb_errstring(ldb));
2585 * just return the original error
2590 /* Likewise, what should we do if we can't open a new transaction? */
2591 ret = ldb_next_start_trans(io->ac->module);
2592 if (ret != LDB_SUCCESS) {
2593 ldb_debug(ldb, LDB_DEBUG_ERROR,
2594 "Failed to open transaction to update badPwdCount of %s: %s",
2595 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2596 ldb_errstring(ldb));
2598 * just return the original error
2603 ret = dsdb_module_modify(io->ac->module, mod_msg,
2604 DSDB_FLAG_NEXT_MODULE,
2606 if (ret != LDB_SUCCESS) {
2607 ldb_debug(ldb, LDB_DEBUG_ERROR,
2608 "Failed to update badPwdCount of %s: %s",
2609 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2610 ldb_errstring(ldb));
2612 * We can only ignore this...
2616 ret = ldb_next_end_trans(io->ac->module);
2617 if (ret != LDB_SUCCESS) {
2618 ldb_debug(ldb, LDB_DEBUG_ERROR,
2619 "Failed to close transaction to update badPwdCount of %s: %s",
2620 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2621 ldb_errstring(ldb));
2623 * We can only ignore this...
2627 ret = ldb_next_start_trans(io->ac->module);
2628 if (ret != LDB_SUCCESS) {
2629 ldb_debug(ldb, LDB_DEBUG_ERROR,
2630 "Failed to open transaction after update of badPwdCount of %s: %s",
2631 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2632 ldb_errstring(ldb));
2634 * We can only ignore this...
2639 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2640 *werror = WERR_INVALID_PASSWORD;
2641 ldb_asprintf_errstring(ldb,
2642 "%08X: %s - check_password_restrictions: "
2643 "The old password specified doesn't match!",
2649 static int check_password_restrictions(struct setup_password_fields_io *io, WERROR *werror)
2651 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2653 struct loadparm_context *lp_ctx =
2654 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2655 struct loadparm_context);
2657 *werror = WERR_INVALID_PARAMETER;
2659 if (!io->ac->update_password) {
2663 /* First check the old password is correct, for password changes */
2664 if (!io->ac->pwd_reset) {
2665 bool nt_hash_checked = false;
2667 /* we need the old nt or lm hash given by the client */
2668 if (!io->og.nt_hash && !io->og.lm_hash) {
2669 ldb_asprintf_errstring(ldb,
2670 "check_password_restrictions: "
2671 "You need to provide the old password in order "
2673 return LDB_ERR_UNWILLING_TO_PERFORM;
2676 /* The password modify through the NT hash is encouraged and
2677 has no problems at all */
2678 if (io->og.nt_hash) {
2679 if (!io->o.nt_hash || memcmp(io->og.nt_hash->hash, io->o.nt_hash->hash, 16) != 0) {
2680 return make_error_and_update_badPwdCount(io, werror);
2683 nt_hash_checked = true;
2686 /* But it is also possible to change a password by the LM hash
2687 * alone for compatibility reasons. This check is optional if
2688 * the NT hash was already checked - otherwise it's mandatory.
2689 * (as the SAMR operations request it). */
2690 if (io->og.lm_hash) {
2691 if ((!io->o.lm_hash && !nt_hash_checked)
2692 || (io->o.lm_hash && memcmp(io->og.lm_hash->hash, io->o.lm_hash->hash, 16) != 0)) {
2693 return make_error_and_update_badPwdCount(io, werror);
2698 if (io->u.restrictions == 0) {
2699 /* FIXME: Is this right? */
2703 /* Password minimum age: yes, this is a minus. The ages are in negative 100nsec units! */
2704 if ((io->u.pwdLastSet - io->ac->status->domain_data.minPwdAge > io->g.last_set) &&
2707 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2708 *werror = WERR_PASSWORD_RESTRICTION;
2709 ldb_asprintf_errstring(ldb,
2710 "%08X: %s - check_password_restrictions: "
2711 "password is too young to change!",
2718 * Fundamental password checks done by the call
2719 * "samdb_check_password".
2720 * It is also in use by "dcesrv_samr_ValidatePassword".
2722 if (io->n.cleartext_utf8 != NULL) {
2723 enum samr_ValidationStatus vstat;
2724 vstat = samdb_check_password(io->ac, lp_ctx,
2725 io->u.sAMAccountName,
2726 io->u.user_principal_name,
2728 io->n.cleartext_utf8,
2729 io->ac->status->domain_data.pwdProperties,
2730 io->ac->status->domain_data.minPwdLength);
2732 case SAMR_VALIDATION_STATUS_SUCCESS:
2733 /* perfect -> proceed! */
2736 case SAMR_VALIDATION_STATUS_PWD_TOO_SHORT:
2737 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2738 *werror = WERR_PASSWORD_RESTRICTION;
2739 ldb_asprintf_errstring(ldb,
2740 "%08X: %s - check_password_restrictions: "
2741 "the password is too short. It should be equal or longer than %u characters!",
2744 io->ac->status->domain_data.minPwdLength);
2745 io->ac->status->reject_reason = SAM_PWD_CHANGE_PASSWORD_TOO_SHORT;
2748 case SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH:
2749 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2750 *werror = WERR_PASSWORD_RESTRICTION;
2751 ldb_asprintf_errstring(ldb,
2752 "%08X: %s - check_password_restrictions: "
2753 "the password does not meet the complexity criteria!",
2756 io->ac->status->reject_reason = SAM_PWD_CHANGE_NOT_COMPLEX;
2760 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2761 *werror = WERR_PASSWORD_RESTRICTION;
2762 ldb_asprintf_errstring(ldb,
2763 "%08X: %s - check_password_restrictions: "
2764 "the password doesn't fit due to a miscellaneous restriction!",
2771 if (io->ac->pwd_reset) {
2776 if (io->n.nt_hash) {
2779 /* checks the NT hash password history */
2780 for (i = 0; i < io->o.nt_history_len; i++) {
2781 ret = memcmp(io->n.nt_hash, io->o.nt_history[i].hash, 16);
2783 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2784 *werror = WERR_PASSWORD_RESTRICTION;
2785 ldb_asprintf_errstring(ldb,
2786 "%08X: %s - check_password_restrictions: "
2787 "the password was already used (in history)!",
2790 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
2796 if (io->n.lm_hash) {
2799 /* checks the LM hash password history */
2800 for (i = 0; i < io->o.lm_history_len; i++) {
2801 ret = memcmp(io->n.lm_hash, io->o.lm_history[i].hash, 16);
2803 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2804 *werror = WERR_PASSWORD_RESTRICTION;
2805 ldb_asprintf_errstring(ldb,
2806 "%08X: %s - check_password_restrictions: "
2807 "the password was already used (in history)!",
2810 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
2816 /* are all password changes disallowed? */
2817 if (io->ac->status->domain_data.pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
2818 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2819 *werror = WERR_PASSWORD_RESTRICTION;
2820 ldb_asprintf_errstring(ldb,
2821 "%08X: %s - check_password_restrictions: "
2822 "password changes disabled!",
2828 /* can this user change the password? */
2829 if (io->u.userAccountControl & UF_PASSWD_CANT_CHANGE) {
2830 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2831 *werror = WERR_PASSWORD_RESTRICTION;
2832 ldb_asprintf_errstring(ldb,
2833 "%08X: %s - check_password_restrictions: "
2834 "password can't be changed on this account!",
2843 static int check_password_restrictions_and_log(struct setup_password_fields_io *io)
2846 int ret = check_password_restrictions(io, &werror);
2847 struct ph_context *ac = io->ac;
2849 * Password resets are not authentication events, and if the
2850 * upper layer checked the password and supplied the hash
2851 * values as proof, then this is also not an authentication
2852 * even at this layer (already logged). This is to log LDAP
2856 /* Do not record a failure in the auth log below in the success case */
2857 if (ret == LDB_SUCCESS) {
2861 if (ac->pwd_reset == false && ac->change == NULL) {
2862 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2863 struct imessaging_context *msg_ctx;
2864 struct loadparm_context *lp_ctx
2865 = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"),
2866 struct loadparm_context);
2867 NTSTATUS status = werror_to_ntstatus(werror);
2868 const char *domain_name = lpcfg_sam_name(lp_ctx);
2869 void *opaque_remote_address = NULL;
2871 * Forcing this via the NTLM auth structure is not ideal, but
2872 * it is the most practical option right now, and ensures the
2873 * logs are consistent, even if some elements are always NULL.
2875 struct auth_usersupplied_info ui = {
2876 .mapped_state = true,
2879 .account_name = io->u.sAMAccountName,
2880 .domain_name = domain_name,
2883 .account_name = io->u.sAMAccountName,
2884 .domain_name = domain_name,
2886 .service_description = "LDAP Password Change",
2887 .auth_description = "LDAP Modify",
2888 .password_type = "plaintext"
2891 opaque_remote_address = ldb_get_opaque(ldb,
2893 if (opaque_remote_address == NULL) {
2894 ldb_asprintf_errstring(ldb,
2895 "Failed to obtain remote address for "
2896 "the LDAP client while changing the "
2898 return LDB_ERR_OPERATIONS_ERROR;
2900 ui.remote_host = talloc_get_type(opaque_remote_address,
2901 struct tsocket_address);
2903 msg_ctx = imessaging_client_init(ac, lp_ctx,
2904 ldb_get_event_context(ldb));
2906 ldb_asprintf_errstring(ldb,
2907 "Failed to generate client messaging context in %s",
2908 lpcfg_imessaging_path(ac, lp_ctx));
2909 return LDB_ERR_OPERATIONS_ERROR;
2911 log_authentication_event(msg_ctx,
2917 io->u.sAMAccountName,
2925 static int update_final_msg(struct setup_password_fields_io *io)
2927 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2930 bool update_password = io->ac->update_password;
2931 bool update_scb = io->ac->update_password;
2934 * If we add a user without initial password,
2935 * we need to add replication meta data for
2936 * following attributes:
2942 * If we add a user with initial password or a
2943 * password is changed of an existing user,
2944 * we need to replace the following attributes
2945 * with a forced meta data update, e.g. also
2946 * when updating an empty attribute with an empty value:
2951 * - supplementalCredentials
2954 switch (io->ac->req->operation) {
2956 update_password = true;
2957 el_flags |= DSDB_FLAG_INTERNAL_FORCE_META_DATA;
2960 el_flags |= LDB_FLAG_MOD_REPLACE;
2961 el_flags |= DSDB_FLAG_INTERNAL_FORCE_META_DATA;
2964 return ldb_module_operr(io->ac->module);
2967 if (update_password) {
2968 ret = ldb_msg_add_empty(io->ac->update_msg,
2971 if (ret != LDB_SUCCESS) {
2974 ret = ldb_msg_add_empty(io->ac->update_msg,
2977 if (ret != LDB_SUCCESS) {
2980 ret = ldb_msg_add_empty(io->ac->update_msg,
2983 if (ret != LDB_SUCCESS) {
2986 ret = ldb_msg_add_empty(io->ac->update_msg,
2989 if (ret != LDB_SUCCESS) {
2994 ret = ldb_msg_add_empty(io->ac->update_msg,
2995 "supplementalCredentials",
2997 if (ret != LDB_SUCCESS) {
3001 if (io->ac->update_lastset) {
3002 ret = ldb_msg_add_empty(io->ac->update_msg,
3005 if (ret != LDB_SUCCESS) {
3010 if (io->g.nt_hash != NULL) {
3011 ret = samdb_msg_add_hash(ldb, io->ac,
3015 if (ret != LDB_SUCCESS) {
3019 if (io->g.lm_hash != NULL) {
3020 ret = samdb_msg_add_hash(ldb, io->ac,
3024 if (ret != LDB_SUCCESS) {
3028 if (io->g.nt_history_len > 0) {
3029 ret = samdb_msg_add_hashes(ldb, io->ac,
3033 io->g.nt_history_len);
3034 if (ret != LDB_SUCCESS) {
3038 if (io->g.lm_history_len > 0) {
3039 ret = samdb_msg_add_hashes(ldb, io->ac,
3043 io->g.lm_history_len);
3044 if (ret != LDB_SUCCESS) {
3048 if (io->g.supplemental.length > 0) {
3049 ret = ldb_msg_add_value(io->ac->update_msg,
3050 "supplementalCredentials",
3051 &io->g.supplemental, NULL);
3052 if (ret != LDB_SUCCESS) {
3056 if (io->ac->update_lastset) {
3057 ret = samdb_msg_add_uint64(ldb, io->ac,
3061 if (ret != LDB_SUCCESS) {
3070 * This is intended for use by the "password_hash" module since there
3071 * password changes can be specified through one message element with the
3072 * new password (to set) and another one with the old password (to unset).
3074 * The first which sets a password (new value) can have flags
3075 * (LDB_FLAG_MOD_ADD, LDB_FLAG_MOD_REPLACE) but also none (on "add" operations
3076 * for entries). The latter (old value) has always specified
3077 * LDB_FLAG_MOD_DELETE.
3079 * Returns LDB_ERR_CONSTRAINT_VIOLATION and LDB_ERR_UNWILLING_TO_PERFORM if
3080 * matching message elements are malformed in respect to the set/change rules.
3081 * Otherwise it returns LDB_SUCCESS.
3083 static int msg_find_old_and_new_pwd_val(const struct ldb_message *msg,
3085 enum ldb_request_type operation,
3086 const struct ldb_val **new_val,
3087 const struct ldb_val **old_val)
3098 for (i = 0; i < msg->num_elements; i++) {
3099 if (ldb_attr_cmp(msg->elements[i].name, name) != 0) {
3103 if ((operation == LDB_MODIFY) &&
3104 (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_DELETE)) {
3105 /* 0 values are allowed */
3106 if (msg->elements[i].num_values == 1) {
3107 *old_val = &msg->elements[i].values[0];
3108 } else if (msg->elements[i].num_values > 1) {
3109 return LDB_ERR_CONSTRAINT_VIOLATION;
3111 } else if ((operation == LDB_MODIFY) &&
3112 (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_REPLACE)) {
3113 if (msg->elements[i].num_values > 0) {
3114 *new_val = &msg->elements[i].values[msg->elements[i].num_values - 1];
3116 return LDB_ERR_UNWILLING_TO_PERFORM;
3119 /* Add operations and LDB_FLAG_MOD_ADD */
3120 if (msg->elements[i].num_values > 0) {
3121 *new_val = &msg->elements[i].values[msg->elements[i].num_values - 1];
3123 return LDB_ERR_CONSTRAINT_VIOLATION;
3131 static int setup_io(struct ph_context *ac,
3132 const struct ldb_message *client_msg,
3133 const struct ldb_message *existing_msg,
3134 struct setup_password_fields_io *io)
3136 const struct ldb_val *quoted_utf16, *old_quoted_utf16, *lm_hash, *old_lm_hash;
3137 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3138 struct loadparm_context *lp_ctx = talloc_get_type(
3139 ldb_get_opaque(ldb, "loadparm"), struct loadparm_context);
3141 const struct ldb_message *info_msg = NULL;
3142 struct dom_sid *account_sid = NULL;
3143 int rodc_krbtgt = 0;
3147 /* Some operations below require kerberos contexts */
3149 if (existing_msg != NULL) {
3151 * This is a modify operation
3153 info_msg = existing_msg;
3156 * This is an add operation
3158 info_msg = client_msg;
3161 ret = smb_krb5_init_context(ac,
3162 (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"),
3163 &io->smb_krb5_context);
3167 * In the special case of mit krb5.conf vs heimdal, the includedir
3168 * statement causes ret == 22 (KRB5_CONFIG_BADFORMAT) to be returned.
3169 * We look for this case so that we can give a more instructional
3170 * message to the administrator.
3172 if (ret == KRB5_CONFIG_BADFORMAT || ret == EINVAL) {
3173 ldb_asprintf_errstring(ldb, "Failed to setup krb5_context: %s - "
3174 "This could be due to an invalid krb5 configuration. "
3175 "Please check your system's krb5 configuration is correct.",
3176 error_message(ret));
3178 ldb_asprintf_errstring(ldb, "Failed to setup krb5_context: %s",
3179 error_message(ret));
3181 return LDB_ERR_OPERATIONS_ERROR;
3186 io->u.userAccountControl = ldb_msg_find_attr_as_uint(info_msg,
3187 "userAccountControl", 0);
3188 if (info_msg == existing_msg) {
3190 * We only take pwdLastSet from the existing object
3191 * otherwise we leave it as 0.
3193 * If no attribute is available, e.g. on deleted objects
3194 * we remember that as UINT64_MAX.
3196 io->u.pwdLastSet = samdb_result_nttime(info_msg, "pwdLastSet",
3199 io->u.sAMAccountName = ldb_msg_find_attr_as_string(info_msg,
3200 "sAMAccountName", NULL);
3201 io->u.user_principal_name = ldb_msg_find_attr_as_string(info_msg,
3202 "userPrincipalName", NULL);
3203 io->u.displayName = ldb_msg_find_attr_as_string(info_msg,
3204 "displayName", NULL);
3206 /* Ensure it has an objectSID too */
3207 io->u.account_sid = samdb_result_dom_sid(ac, info_msg, "objectSid");
3208 if (io->u.account_sid != NULL) {
3212 status = dom_sid_split_rid(account_sid, io->u.account_sid, NULL, &rid);
3213 if (NT_STATUS_IS_OK(status)) {
3214 if (rid == DOMAIN_RID_KRBTGT) {
3215 io->u.is_krbtgt = true;
3220 rodc_krbtgt = ldb_msg_find_attr_as_int(info_msg,
3221 "msDS-SecondaryKrbTgtNumber", 0);
3222 if (rodc_krbtgt != 0) {
3223 io->u.is_krbtgt = true;
3226 if (io->u.sAMAccountName == NULL) {
3227 ldb_asprintf_errstring(ldb,
3228 "setup_io: sAMAccountName attribute is missing on %s for attempted password set/change",
3229 ldb_dn_get_linearized(info_msg->dn));
3231 return LDB_ERR_CONSTRAINT_VIOLATION;
3234 if (io->u.userAccountControl & UF_INTERDOMAIN_TRUST_ACCOUNT) {
3235 struct ldb_control *permit_trust = ldb_request_get_control(ac->req,
3236 DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID);
3238 if (permit_trust == NULL) {
3239 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
3240 ldb_asprintf_errstring(ldb,
3241 "%08X: %s - setup_io: changing the interdomain trust password "
3242 "on %s not allowed via LDAP. Use LSA or NETLOGON",
3243 W_ERROR_V(WERR_ACCESS_DENIED),
3245 ldb_dn_get_linearized(info_msg->dn));
3250 /* Only non-trust accounts have restrictions (possibly this test is the
3251 * wrong way around, but we like to be restrictive if possible */
3252 io->u.restrictions = !(io->u.userAccountControl & UF_TRUST_ACCOUNT_MASK);
3254 if (io->u.is_krbtgt) {
3255 io->u.restrictions = 0;
3256 io->ac->status->domain_data.pwdHistoryLength =
3257 MAX(io->ac->status->domain_data.pwdHistoryLength, 3);
3260 if (ac->userPassword) {
3261 ret = msg_find_old_and_new_pwd_val(client_msg, "userPassword",
3263 &io->n.cleartext_utf8,
3264 &io->og.cleartext_utf8);
3265 if (ret != LDB_SUCCESS) {
3266 ldb_asprintf_errstring(ldb,
3268 "it's only allowed to set the old password once!");
3273 if (io->n.cleartext_utf8 != NULL) {
3274 struct ldb_val *cleartext_utf8_blob;
3277 cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
3278 if (!cleartext_utf8_blob) {
3279 return ldb_oom(ldb);
3282 *cleartext_utf8_blob = *io->n.cleartext_utf8;
3284 /* make sure we have a null terminated string */
3285 p = talloc_strndup(cleartext_utf8_blob,
3286 (const char *)io->n.cleartext_utf8->data,
3287 io->n.cleartext_utf8->length);
3288 if ((p == NULL) && (io->n.cleartext_utf8->length > 0)) {
3289 return ldb_oom(ldb);
3291 cleartext_utf8_blob->data = (uint8_t *)p;
3293 io->n.cleartext_utf8 = cleartext_utf8_blob;
3296 ret = msg_find_old_and_new_pwd_val(client_msg, "clearTextPassword",
3298 &io->n.cleartext_utf16,
3299 &io->og.cleartext_utf16);
3300 if (ret != LDB_SUCCESS) {
3301 ldb_asprintf_errstring(ldb,
3303 "it's only allowed to set the old password once!");
3307 /* this rather strange looking piece of code is there to
3308 handle a ldap client setting a password remotely using the
3309 unicodePwd ldap field. The syntax is that the password is
3310 in UTF-16LE, with a " at either end. Unfortunately the
3311 unicodePwd field is also used to store the nt hashes
3312 internally in Samba, and is used in the nt hash format on
3313 the wire in DRS replication, so we have a single name for
3314 two distinct values. The code below leaves us with a small
3315 chance (less than 1 in 2^32) of a mixup, if someone manages
3316 to create a MD4 hash which starts and ends in 0x22 0x00, as
3317 that would then be treated as a UTF16 password rather than
3320 ret = msg_find_old_and_new_pwd_val(client_msg, "unicodePwd",
3324 if (ret != LDB_SUCCESS) {
3325 ldb_asprintf_errstring(ldb,
3327 "it's only allowed to set the old password once!");
3331 /* Checks and converts the actual "unicodePwd" attribute */
3332 if (!ac->hash_values &&
3334 quoted_utf16->length >= 4 &&
3335 quoted_utf16->data[0] == '"' &&
3336 quoted_utf16->data[1] == 0 &&
3337 quoted_utf16->data[quoted_utf16->length-2] == '"' &&
3338 quoted_utf16->data[quoted_utf16->length-1] == 0) {
3339 struct ldb_val *quoted_utf16_2;
3341 if (io->n.cleartext_utf16) {
3342 /* refuse the change if someone wants to change with
3343 with both UTF16 possibilities at the same time... */
3344 ldb_asprintf_errstring(ldb,
3346 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
3347 return LDB_ERR_UNWILLING_TO_PERFORM;
3351 * adapt the quoted UTF16 string to be a real
3354 quoted_utf16_2 = talloc(io->ac, struct ldb_val);
3355 if (quoted_utf16_2 == NULL) {
3356 return ldb_oom(ldb);
3359 quoted_utf16_2->data = quoted_utf16->data + 2;
3360 quoted_utf16_2->length = quoted_utf16->length-4;
3361 io->n.cleartext_utf16 = quoted_utf16_2;
3362 io->n.nt_hash = NULL;
3364 } else if (quoted_utf16) {
3365 /* We have only the hash available -> so no plaintext here */
3366 if (!ac->hash_values) {
3367 /* refuse the change if someone wants to change
3368 the hash without control specified... */
3369 ldb_asprintf_errstring(ldb,
3371 "it's not allowed to set the NT hash password directly'");
3372 /* this looks odd but this is what Windows does:
3373 returns "UNWILLING_TO_PERFORM" on wrong
3374 password sets and "CONSTRAINT_VIOLATION" on
3375 wrong password changes. */
3376 if (old_quoted_utf16 == NULL) {
3377 return LDB_ERR_UNWILLING_TO_PERFORM;
3380 return LDB_ERR_CONSTRAINT_VIOLATION;
3383 io->n.nt_hash = talloc(io->ac, struct samr_Password);
3384 memcpy(io->n.nt_hash->hash, quoted_utf16->data,
3385 MIN(quoted_utf16->length, sizeof(io->n.nt_hash->hash)));
3388 /* Checks and converts the previous "unicodePwd" attribute */
3389 if (!ac->hash_values &&
3391 old_quoted_utf16->length >= 4 &&
3392 old_quoted_utf16->data[0] == '"' &&
3393 old_quoted_utf16->data[1] == 0 &&
3394 old_quoted_utf16->data[old_quoted_utf16->length-2] == '"' &&
3395 old_quoted_utf16->data[old_quoted_utf16->length-1] == 0) {
3396 struct ldb_val *old_quoted_utf16_2;
3398 if (io->og.cleartext_utf16) {
3399 /* refuse the change if someone wants to change with
3400 both UTF16 possibilities at the same time... */
3401 ldb_asprintf_errstring(ldb,
3403 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
3404 return LDB_ERR_UNWILLING_TO_PERFORM;
3408 * adapt the quoted UTF16 string to be a real
3411 old_quoted_utf16_2 = talloc(io->ac, struct ldb_val);
3412 if (old_quoted_utf16_2 == NULL) {
3413 return ldb_oom(ldb);
3416 old_quoted_utf16_2->data = old_quoted_utf16->data + 2;
3417 old_quoted_utf16_2->length = old_quoted_utf16->length-4;
3419 io->og.cleartext_utf16 = old_quoted_utf16_2;
3420 io->og.nt_hash = NULL;
3421 } else if (old_quoted_utf16) {
3422 /* We have only the hash available -> so no plaintext here */
3423 if (!ac->hash_values) {
3424 /* refuse the change if someone wants to change
3425 the hash without control specified... */
3426 ldb_asprintf_errstring(ldb,
3428 "it's not allowed to set the NT hash password directly'");
3429 return LDB_ERR_UNWILLING_TO_PERFORM;
3432 io->og.nt_hash = talloc(io->ac, struct samr_Password);
3433 memcpy(io->og.nt_hash->hash, old_quoted_utf16->data,
3434 MIN(old_quoted_utf16->length, sizeof(io->og.nt_hash->hash)));
3437 /* Handles the "dBCSPwd" attribute (LM hash) */
3438 io->n.lm_hash = NULL; io->og.lm_hash = NULL;
3439 ret = msg_find_old_and_new_pwd_val(client_msg, "dBCSPwd",
3441 &lm_hash, &old_lm_hash);
3442 if (ret != LDB_SUCCESS) {
3443 ldb_asprintf_errstring(ldb,
3445 "it's only allowed to set the old password once!");
3449 if (((lm_hash != NULL) || (old_lm_hash != NULL)) && (!ac->hash_values)) {
3450 /* refuse the change if someone wants to change the hash
3451 without control specified... */
3452 ldb_asprintf_errstring(ldb,
3454 "it's not allowed to set the LM hash password directly'");
3455 return LDB_ERR_UNWILLING_TO_PERFORM;
3458 if (lpcfg_lanman_auth(lp_ctx) && (lm_hash != NULL)) {
3459 io->n.lm_hash = talloc(io->ac, struct samr_Password);
3460 memcpy(io->n.lm_hash->hash, lm_hash->data, MIN(lm_hash->length,
3461 sizeof(io->n.lm_hash->hash)));
3463 if (lpcfg_lanman_auth(lp_ctx) && (old_lm_hash != NULL)) {
3464 io->og.lm_hash = talloc(io->ac, struct samr_Password);
3465 memcpy(io->og.lm_hash->hash, old_lm_hash->data, MIN(old_lm_hash->length,
3466 sizeof(io->og.lm_hash->hash)));
3470 * Handles the password change control if it's specified. It has the
3471 * precedance and overrides already specified old password values of
3472 * change requests (but that shouldn't happen since the control is
3473 * fully internal and only used in conjunction with replace requests!).
3475 if (ac->change != NULL) {
3476 io->og.nt_hash = NULL;
3477 if (ac->change->old_nt_pwd_hash != NULL) {
3478 io->og.nt_hash = talloc_memdup(io->ac,
3479 ac->change->old_nt_pwd_hash,
3480 sizeof(struct samr_Password));
3482 io->og.lm_hash = NULL;
3483 if (lpcfg_lanman_auth(lp_ctx) && (ac->change->old_lm_pwd_hash != NULL)) {
3484 io->og.lm_hash = talloc_memdup(io->ac,
3485 ac->change->old_lm_pwd_hash,
3486 sizeof(struct samr_Password));
3490 /* refuse the change if someone wants to change the clear-
3491 text and supply his own hashes at the same time... */
3492 if ((io->n.cleartext_utf8 || io->n.cleartext_utf16)
3493 && (io->n.nt_hash || io->n.lm_hash)) {
3494 ldb_asprintf_errstring(ldb,
3496 "it's only allowed to set the password in form of cleartext attributes or as hashes");
3497 return LDB_ERR_UNWILLING_TO_PERFORM;
3500 /* refuse the change if someone wants to change the password
3501 using both plaintext methods (UTF8 and UTF16) at the same time... */
3502 if (io->n.cleartext_utf8 && io->n.cleartext_utf16) {
3503 ldb_asprintf_errstring(ldb,
3505 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
3506 return LDB_ERR_UNWILLING_TO_PERFORM;
3509 /* refuse the change if someone tries to set/change the password by
3510 * the lanman hash alone and we've deactivated that mechanism. This
3511 * would end in an account without any password! */
3512 if (io->ac->update_password
3513 && (!io->n.cleartext_utf8) && (!io->n.cleartext_utf16)
3514 && (!io->n.nt_hash) && (!io->n.lm_hash)) {
3515 ldb_asprintf_errstring(ldb,
3517 "It's not possible to delete the password (changes using the LAN Manager hash alone could be deactivated)!");
3518 /* on "userPassword" and "clearTextPassword" we've to return
3519 * something different, since these are virtual attributes */
3520 if ((ldb_msg_find_element(client_msg, "userPassword") != NULL) ||
3521 (ldb_msg_find_element(client_msg, "clearTextPassword") != NULL)) {
3522 return LDB_ERR_CONSTRAINT_VIOLATION;
3524 return LDB_ERR_UNWILLING_TO_PERFORM;
3527 /* refuse the change if someone wants to compare against a plaintext
3528 or hash at the same time for a "password modify" operation... */
3529 if ((io->og.cleartext_utf8 || io->og.cleartext_utf16)
3530 && (io->og.nt_hash || io->og.lm_hash)) {
3531 ldb_asprintf_errstring(ldb,
3533 "it's only allowed to provide the old password in form of cleartext attributes or as hashes");
3534 return LDB_ERR_UNWILLING_TO_PERFORM;
3537 /* refuse the change if someone wants to compare against both
3538 * plaintexts at the same time for a "password modify" operation... */
3539 if (io->og.cleartext_utf8 && io->og.cleartext_utf16) {
3540 ldb_asprintf_errstring(ldb,
3542 "it's only allowed to provide the old cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
3543 return LDB_ERR_UNWILLING_TO_PERFORM;
3546 /* Decides if we have a password modify or password reset operation */
3547 if (ac->req->operation == LDB_ADD) {
3548 /* On "add" we have only "password reset" */
3549 ac->pwd_reset = true;
3550 } else if (ac->req->operation == LDB_MODIFY) {
3551 struct ldb_control *pav_ctrl = NULL;
3552 struct dsdb_control_password_acl_validation *pav = NULL;
3554 pav_ctrl = ldb_request_get_control(ac->req,
3555 DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
3556 if (pav_ctrl != NULL) {
3557 pav = talloc_get_type_abort(pav_ctrl->data,
3558 struct dsdb_control_password_acl_validation);
3561 if (pav == NULL && ac->update_password) {
3565 * If the DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID
3566 * control is missing, we require system access!
3568 ok = dsdb_module_am_system(ac->module);
3570 return ldb_module_operr(ac->module);
3576 * We assume what the acl module has validated.
3578 ac->pwd_reset = pav->pwd_reset;
3579 } else if (io->og.cleartext_utf8 || io->og.cleartext_utf16
3580 || io->og.nt_hash || io->og.lm_hash) {
3581 /* If we have an old password specified then for sure it
3582 * is a user "password change" */
3583 ac->pwd_reset = false;
3585 /* Otherwise we have also here a "password reset" */
3586 ac->pwd_reset = true;
3589 /* this shouldn't happen */
3590 return ldb_operr(ldb);
3593 if (io->u.is_krbtgt) {
3596 size_t diff = max - min;
3598 struct ldb_val *krbtgt_utf16 = NULL;
3600 if (!ac->pwd_reset) {
3601 return dsdb_module_werror(ac->module,
3602 LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS,
3603 WERR_DS_ATT_ALREADY_EXISTS,
3604 "Password change on krbtgt not permitted!");
3607 if (io->n.cleartext_utf16 == NULL) {
3608 return dsdb_module_werror(ac->module,
3609 LDB_ERR_UNWILLING_TO_PERFORM,
3610 WERR_DS_INVALID_ATTRIBUTE_SYNTAX,
3611 "Password reset on krbtgt requires UTF16!");
3615 * Instead of taking the callers value,
3616 * we just generate a new random value here.
3618 * Include null termination in the array.
3623 generate_random_buffer((uint8_t *)&tmp, sizeof(tmp));
3630 krbtgt_utf16 = talloc_zero(io->ac, struct ldb_val);
3631 if (krbtgt_utf16 == NULL) {
3632 return ldb_oom(ldb);
3635 *krbtgt_utf16 = data_blob_talloc_zero(krbtgt_utf16,
3637 if (krbtgt_utf16->data == NULL) {
3638 return ldb_oom(ldb);
3640 krbtgt_utf16->length = len * 2;
3641 generate_secret_buffer(krbtgt_utf16->data,
3642 krbtgt_utf16->length);
3643 io->n.cleartext_utf16 = krbtgt_utf16;
3646 if (existing_msg != NULL) {
3649 if (ac->pwd_reset) {
3650 /* Get the old password from the database */
3651 status = samdb_result_passwords_no_lockout(ac,
3657 /* Get the old password from the database */
3658 status = samdb_result_passwords(ac,
3665 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCOUNT_LOCKED_OUT)) {
3666 return dsdb_module_werror(ac->module,
3667 LDB_ERR_CONSTRAINT_VIOLATION,
3668 WERR_ACCOUNT_LOCKED_OUT,
3669 "Password change not permitted,"
3670 " account locked out!");
3673 if (!NT_STATUS_IS_OK(status)) {
3675 * This only happens if the database has gone weird,
3676 * not if we are just missing the passwords
3678 return ldb_operr(ldb);
3681 io->o.nt_history_len = samdb_result_hashes(ac, existing_msg,
3684 io->o.lm_history_len = samdb_result_hashes(ac, existing_msg,
3687 io->o.supplemental = ldb_msg_find_ldb_val(existing_msg,
3688 "supplementalCredentials");
3690 if (io->o.supplemental != NULL) {
3691 enum ndr_err_code ndr_err;
3693 ndr_err = ndr_pull_struct_blob_all(io->o.supplemental, io->ac,
3695 (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
3696 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3697 status = ndr_map_error2ntstatus(ndr_err);
3698 ldb_asprintf_errstring(ldb,
3699 "setup_io: failed to pull "
3700 "old supplementalCredentialsBlob: %s",
3702 return LDB_ERR_OPERATIONS_ERROR;
3710 static struct ph_context *ph_init_context(struct ldb_module *module,
3711 struct ldb_request *req,
3713 bool update_password)
3715 struct ldb_context *ldb;
3716 struct ph_context *ac;
3717 struct loadparm_context *lp_ctx = NULL;
3719 ldb = ldb_module_get_ctx(module);
3721 ac = talloc_zero(req, struct ph_context);
3723 ldb_set_errstring(ldb, "Out of Memory");
3727 ac->module = module;
3729 ac->userPassword = userPassword;
3730 ac->update_password = update_password;
3731 ac->update_lastset = true;
3733 lp_ctx = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"),
3734 struct loadparm_context);
3735 ac->gpg_key_ids = lpcfg_password_hash_gpg_key_ids(lp_ctx);
3736 ac->userPassword_schemes
3737 = lpcfg_password_hash_userpassword_schemes(lp_ctx);
3741 static void ph_apply_controls(struct ph_context *ac)
3743 struct ldb_control *ctrl;
3745 ac->change_status = false;
3746 ctrl = ldb_request_get_control(ac->req,
3747 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID);
3749 ac->change_status = true;
3751 /* Mark the "change status" control as uncritical (done) */
3752 ctrl->critical = false;
3755 ac->hash_values = false;
3756 ctrl = ldb_request_get_control(ac->req,
3757 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID);
3759 ac->hash_values = true;
3761 /* Mark the "hash values" control as uncritical (done) */
3762 ctrl->critical = false;
3765 ctrl = ldb_request_get_control(ac->req,
3766 DSDB_CONTROL_PASSWORD_CHANGE_OID);
3768 ac->change = (struct dsdb_control_password_change *) ctrl->data;
3770 /* Mark the "change" control as uncritical (done) */
3771 ctrl->critical = false;
3774 ac->pwd_last_set_bypass = false;
3775 ctrl = ldb_request_get_control(ac->req,
3776 DSDB_CONTROL_PASSWORD_BYPASS_LAST_SET_OID);
3778 ac->pwd_last_set_bypass = true;
3780 /* Mark the "bypass pwdLastSet" control as uncritical (done) */
3781 ctrl->critical = false;
3784 ac->pwd_last_set_default = false;
3785 ctrl = ldb_request_get_control(ac->req,
3786 DSDB_CONTROL_PASSWORD_DEFAULT_LAST_SET_OID);
3788 ac->pwd_last_set_default = true;
3790 /* Mark the "bypass pwdLastSet" control as uncritical (done) */
3791 ctrl->critical = false;
3794 ac->smartcard_reset = false;
3795 ctrl = ldb_request_get_control(ac->req,
3796 DSDB_CONTROL_PASSWORD_USER_ACCOUNT_CONTROL_OID);
3798 struct dsdb_control_password_user_account_control *uac = NULL;
3799 uint32_t added_flags = 0;
3801 uac = talloc_get_type_abort(ctrl->data,
3802 struct dsdb_control_password_user_account_control);
3804 added_flags = uac->new_flags & ~uac->old_flags;
3806 if (added_flags & UF_SMARTCARD_REQUIRED) {
3807 ac->smartcard_reset = true;
3810 /* Mark the "smartcard required" control as uncritical (done) */
3811 ctrl->critical = false;
3815 static int ph_op_callback(struct ldb_request *req, struct ldb_reply *ares)
3817 struct ph_context *ac;
3819 ac = talloc_get_type(req->context, struct ph_context);
3822 return ldb_module_done(ac->req, NULL, NULL,
3823 LDB_ERR_OPERATIONS_ERROR);
3826 if (ares->type == LDB_REPLY_REFERRAL) {
3827 return ldb_module_send_referral(ac->req, ares->referral);
3830 if ((ares->error != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
3831 /* On success and trivial errors a status control is being
3832 * added (used for example by the "samdb_set_password" call) */
3833 ldb_reply_add_control(ares,
3834 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
3839 if (ares->error != LDB_SUCCESS) {
3840 return ldb_module_done(ac->req, ares->controls,
3841 ares->response, ares->error);
3844 if (ares->type != LDB_REPLY_DONE) {
3846 return ldb_module_done(ac->req, NULL, NULL,
3847 LDB_ERR_OPERATIONS_ERROR);
3850 return ldb_module_done(ac->req, ares->controls,
3851 ares->response, ares->error);
3854 static int password_hash_add_do_add(struct ph_context *ac);
3855 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares);
3856 static int password_hash_mod_search_self(struct ph_context *ac);
3857 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares);
3858 static int password_hash_mod_do_mod(struct ph_context *ac);
3861 * LDB callback handler for searching for a user's PSO. Once we have all the
3862 * Password Settings that apply to the user, we can continue with the modify
3865 static int get_pso_data_callback(struct ldb_request *req,
3866 struct ldb_reply *ares)
3868 struct ldb_context *ldb = NULL;
3869 struct ph_context *ac = NULL;
3870 bool domain_complexity = true;
3871 bool pso_complexity = true;
3872 struct dsdb_user_pwd_settings *settings = NULL;
3873 int ret = LDB_SUCCESS;
3875 ac = talloc_get_type(req->context, struct ph_context);
3876 ldb = ldb_module_get_ctx(ac->module);
3879 ret = LDB_ERR_OPERATIONS_ERROR;
3882 if (ares->error != LDB_SUCCESS) {
3883 return ldb_module_done(ac->req, ares->controls,
3884 ares->response, ares->error);
3887 switch (ares->type) {
3888 case LDB_REPLY_ENTRY:
3890 /* check status was initialized by the domain query */
3891 if (ac->status == NULL) {
3893 ldb_set_errstring(ldb, "Uninitialized status");
3894 ret = LDB_ERR_OPERATIONS_ERROR;
3899 * use the PSO's values instead of the domain defaults (the PSO
3900 * attributes should always exist, but use the domain default
3901 * values as a fallback).
3903 settings = &ac->status->domain_data;
3904 settings->store_cleartext =
3905 ldb_msg_find_attr_as_bool(ares->message,
3906 "msDS-PasswordReversibleEncryptionEnabled",
3907 settings->store_cleartext);
3909 settings->pwdHistoryLength =
3910 ldb_msg_find_attr_as_uint(ares->message,
3911 "msDS-PasswordHistoryLength",
3912 settings->pwdHistoryLength);
3913 settings->maxPwdAge =
3914 ldb_msg_find_attr_as_int64(ares->message,
3915 "msDS-MaximumPasswordAge",
3916 settings->maxPwdAge);
3917 settings->minPwdAge =
3918 ldb_msg_find_attr_as_int64(ares->message,
3919 "msDS-MinimumPasswordAge",
3920 settings->minPwdAge);
3921 settings->minPwdLength =
3922 ldb_msg_find_attr_as_uint(ares->message,
3923 "msDS-MinimumPasswordLength",
3924 settings->minPwdLength);
3926 (settings->pwdProperties & DOMAIN_PASSWORD_COMPLEX);
3928 ldb_msg_find_attr_as_bool(ares->message,
3929 "msDS-PasswordComplexityEnabled",
3932 /* set or clear the complexity bit if required */
3933 if (pso_complexity && !domain_complexity) {
3934 settings->pwdProperties |= DOMAIN_PASSWORD_COMPLEX;
3935 } else if (domain_complexity && !pso_complexity) {
3936 settings->pwdProperties &= ~DOMAIN_PASSWORD_COMPLEX;
3939 if (ac->pso_res != NULL) {
3940 DBG_ERR("Too many PSO results for %s",
3941 ldb_dn_get_linearized(ac->search_res->message->dn));
3942 talloc_free(ac->pso_res);
3945 /* store the PSO result (we may need its lockout settings) */
3946 ac->pso_res = talloc_steal(ac, ares);
3950 case LDB_REPLY_REFERRAL:
3956 case LDB_REPLY_DONE:
3960 * perform the next step of the modify operation (this code
3961 * shouldn't get called in the 'user add' case)
3963 if (ac->req->operation == LDB_MODIFY) {
3964 ret = password_hash_mod_do_mod(ac);
3966 ret = LDB_ERR_OPERATIONS_ERROR;
3972 if (ret != LDB_SUCCESS) {
3973 struct ldb_reply *new_ares;
3975 new_ares = talloc_zero(ac->req, struct ldb_reply);
3976 if (new_ares == NULL) {
3978 return ldb_module_done(ac->req, NULL, NULL,
3979 LDB_ERR_OPERATIONS_ERROR);
3982 new_ares->error = ret;
3983 if ((ret != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
3984 /* On success and trivial errors a status control is being
3985 * added (used for example by the "samdb_set_password" call) */
3986 ldb_reply_add_control(new_ares,
3987 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
3992 return ldb_module_done(ac->req, new_ares->controls,
3993 new_ares->response, new_ares->error);
4000 * Builds and returns a search request to lookup up the PSO that applies to
4001 * the user in question. Returns NULL if no PSO applies, or could not be found
4003 static struct ldb_request * build_pso_data_request(struct ph_context *ac)
4005 /* attrs[] is returned from this function in
4006 pso_req->op.search.attrs, so it must be static, as
4007 otherwise the compiler can put it on the stack */
4008 static const char * const attrs[] = { "msDS-PasswordComplexityEnabled",
4009 "msDS-PasswordReversibleEncryptionEnabled",
4010 "msDS-PasswordHistoryLength",
4011 "msDS-MaximumPasswordAge",
4012 "msDS-MinimumPasswordAge",
4013 "msDS-MinimumPasswordLength",
4014 "msDS-LockoutThreshold",
4015 "msDS-LockoutObservationWindow",
4017 struct ldb_context *ldb = NULL;
4018 struct ldb_request *pso_req = NULL;
4019 struct ldb_dn *pso_dn = NULL;
4020 TALLOC_CTX *mem_ctx = ac;
4023 ldb = ldb_module_get_ctx(ac->module);
4025 /* if a PSO applies to the user, we need to lookup the PSO as well */
4026 pso_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, ac->search_res->message,
4027 "msDS-ResultantPSO");
4028 if (pso_dn == NULL) {
4032 ret = ldb_build_search_req(&pso_req, ldb, mem_ctx, pso_dn,
4033 LDB_SCOPE_BASE, NULL, attrs, NULL,
4034 ac, get_pso_data_callback,
4037 /* log errors, but continue with the default domain settings */
4038 if (ret != LDB_SUCCESS) {
4039 DBG_ERR("Error %d constructing PSO query for user %s", ret,
4040 ldb_dn_get_linearized(ac->search_res->message->dn));
4042 LDB_REQ_SET_LOCATION(pso_req);
4047 static int get_domain_data_callback(struct ldb_request *req,
4048 struct ldb_reply *ares)
4050 struct ldb_context *ldb;
4051 struct ph_context *ac;
4052 struct loadparm_context *lp_ctx;
4053 struct ldb_request *pso_req = NULL;
4054 int ret = LDB_SUCCESS;
4056 ac = talloc_get_type(req->context, struct ph_context);
4057 ldb = ldb_module_get_ctx(ac->module);
4060 ret = LDB_ERR_OPERATIONS_ERROR;
4063 if (ares->error != LDB_SUCCESS) {
4064 return ldb_module_done(ac->req, ares->controls,
4065 ares->response, ares->error);
4068 switch (ares->type) {
4069 case LDB_REPLY_ENTRY:
4070 if (ac->status != NULL) {
4073 ldb_set_errstring(ldb, "Too many results");
4074 ret = LDB_ERR_OPERATIONS_ERROR;
4078 /* Setup the "status" structure (used as control later) */
4079 ac->status = talloc_zero(ac->req,
4080 struct dsdb_control_password_change_status);
4081 if (ac->status == NULL) {
4085 ret = LDB_ERR_OPERATIONS_ERROR;
4089 /* Setup the "domain data" structure */
4090 ac->status->domain_data.pwdProperties =
4091 ldb_msg_find_attr_as_uint(ares->message, "pwdProperties", -1);
4092 ac->status->domain_data.pwdHistoryLength =
4093 ldb_msg_find_attr_as_uint(ares->message, "pwdHistoryLength", -1);
4094 ac->status->domain_data.maxPwdAge =
4095 ldb_msg_find_attr_as_int64(ares->message, "maxPwdAge", -1);
4096 ac->status->domain_data.minPwdAge =
4097 ldb_msg_find_attr_as_int64(ares->message, "minPwdAge", -1);
4098 ac->status->domain_data.minPwdLength =
4099 ldb_msg_find_attr_as_uint(ares->message, "minPwdLength", -1);
4100 ac->status->domain_data.store_cleartext =
4101 ac->status->domain_data.pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
4103 /* For a domain DN, this puts things in dotted notation */
4104 /* For builtin domains, this will give details for the host,
4105 * but that doesn't really matter, as it's just used for salt
4106 * and kerberos principals, which don't exist here */
4108 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
4109 struct loadparm_context);
4111 ac->status->domain_data.dns_domain = lpcfg_dnsdomain(lp_ctx);
4112 ac->status->domain_data.realm = lpcfg_realm(lp_ctx);
4113 ac->status->domain_data.netbios_domain = lpcfg_sam_name(lp_ctx);
4115 ac->status->reject_reason = SAM_PWD_CHANGE_NO_ERROR;
4117 if (ac->dom_res != NULL) {
4120 ldb_set_errstring(ldb, "Too many results");
4121 ret = LDB_ERR_OPERATIONS_ERROR;
4125 ac->dom_res = talloc_steal(ac, ares);
4129 case LDB_REPLY_REFERRAL:
4135 case LDB_REPLY_DONE:
4137 /* call the next step */
4138 switch (ac->req->operation) {
4140 ret = password_hash_add_do_add(ac);
4146 * The user may have an optional PSO applied. If so,
4147 * query the PSO to get the Fine-Grained Password Policy
4148 * for the user, before we perform the modify
4150 pso_req = build_pso_data_request(ac);
4151 if (pso_req != NULL) {
4152 ret = ldb_next_request(ac->module, pso_req);
4155 /* no PSO, so we can perform the modify now */
4156 ret = password_hash_mod_do_mod(ac);
4161 ret = LDB_ERR_OPERATIONS_ERROR;
4168 if (ret != LDB_SUCCESS) {
4169 struct ldb_reply *new_ares;
4171 new_ares = talloc_zero(ac->req, struct ldb_reply);
4172 if (new_ares == NULL) {
4174 return ldb_module_done(ac->req, NULL, NULL,
4175 LDB_ERR_OPERATIONS_ERROR);
4178 new_ares->error = ret;
4179 if ((ret != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
4180 /* On success and trivial errors a status control is being
4181 * added (used for example by the "samdb_set_password" call) */
4182 ldb_reply_add_control(new_ares,
4183 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
4188 return ldb_module_done(ac->req, new_ares->controls,
4189 new_ares->response, new_ares->error);
4195 static int build_domain_data_request(struct ph_context *ac)
4197 /* attrs[] is returned from this function in
4198 ac->dom_req->op.search.attrs, so it must be static, as
4199 otherwise the compiler can put it on the stack */
4200 struct ldb_context *ldb;
4201 static const char * const attrs[] = { "pwdProperties",
4207 "lockOutObservationWindow",
4211 ldb = ldb_module_get_ctx(ac->module);
4213 ret = ldb_build_search_req(&ac->dom_req, ldb, ac,
4214 ldb_get_default_basedn(ldb),
4218 ac, get_domain_data_callback,
4220 LDB_REQ_SET_LOCATION(ac->dom_req);
4224 static int password_hash_needed(struct ldb_module *module,
4225 struct ldb_request *req,
4226 struct ph_context **_ac)
4228 struct ldb_context *ldb = ldb_module_get_ctx(module);
4229 const char *operation = NULL;
4230 const struct ldb_message *msg = NULL;
4231 struct ph_context *ac = NULL;
4232 const char *passwordAttrs[] = {
4233 DSDB_PASSWORD_ATTRIBUTES,
4236 const char **a = NULL;
4237 unsigned int attr_cnt = 0;
4238 struct ldb_control *bypass = NULL;
4239 struct ldb_control *uac_ctrl = NULL;
4240 bool userPassword = dsdb_user_password_support(module, req, req);
4241 bool update_password = false;
4242 bool processing_needed = false;
4246 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_needed\n");
4248 switch (req->operation) {
4251 msg = req->op.add.message;
4254 operation = "modify";
4255 msg = req->op.mod.message;
4258 return ldb_next_request(module, req);
4261 if (ldb_dn_is_special(msg->dn)) { /* do not manipulate our control entries */
4262 return ldb_next_request(module, req);
4265 bypass = ldb_request_get_control(req,
4266 DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID);
4267 if (bypass != NULL) {
4268 /* Mark the "bypass" control as uncritical (done) */
4269 bypass->critical = false;
4270 ldb_debug(ldb, LDB_DEBUG_TRACE,
4271 "password_hash_needed(%s) (bypassing)\n",
4273 return password_hash_bypass(module, req);
4276 /* nobody must touch password histories and 'supplementalCredentials' */
4277 if (ldb_msg_find_element(msg, "ntPwdHistory")) {
4278 return LDB_ERR_UNWILLING_TO_PERFORM;
4280 if (ldb_msg_find_element(msg, "lmPwdHistory")) {
4281 return LDB_ERR_UNWILLING_TO_PERFORM;
4283 if (ldb_msg_find_element(msg, "supplementalCredentials")) {
4284 return LDB_ERR_UNWILLING_TO_PERFORM;
4288 * If no part of this touches the 'userPassword' OR 'clearTextPassword'
4289 * OR 'unicodePwd' OR 'dBCSPwd' we don't need to make any changes.
4290 * For password changes/set there should be a 'delete' or a 'modify'
4291 * on these attributes.
4293 for (a = passwordAttrs; *a != NULL; a++) {
4294 if ((!userPassword) && (ldb_attr_cmp(*a, "userPassword") == 0)) {
4298 if (ldb_msg_find_element(msg, *a) != NULL) {
4299 /* MS-ADTS 3.1.1.3.1.5.2 */
4300 if ((ldb_attr_cmp(*a, "userPassword") == 0) &&
4301 (dsdb_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
4302 return LDB_ERR_CONSTRAINT_VIOLATION;
4310 update_password = true;
4311 processing_needed = true;
4314 if (ldb_msg_find_element(msg, "pwdLastSet")) {
4315 processing_needed = true;
4318 uac_ctrl = ldb_request_get_control(req,
4319 DSDB_CONTROL_PASSWORD_USER_ACCOUNT_CONTROL_OID);
4320 if (uac_ctrl != NULL) {
4321 struct dsdb_control_password_user_account_control *uac = NULL;
4322 uint32_t added_flags = 0;
4324 uac = talloc_get_type_abort(uac_ctrl->data,
4325 struct dsdb_control_password_user_account_control);
4327 added_flags = uac->new_flags & ~uac->old_flags;
4329 if (added_flags & UF_SMARTCARD_REQUIRED) {
4330 processing_needed = true;
4334 if (!processing_needed) {
4335 return ldb_next_request(module, req);
4338 ac = ph_init_context(module, req, userPassword, update_password);
4340 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
4341 return ldb_operr(ldb);
4343 ph_apply_controls(ac);
4346 * Make a copy in order to apply our modifications
4347 * to the final update
4349 ac->update_msg = ldb_msg_copy_shallow(ac, msg);
4350 if (ac->update_msg == NULL) {
4351 return ldb_oom(ldb);
4355 * Remove all password related attributes.
4357 if (ac->userPassword) {
4358 ldb_msg_remove_attr(ac->update_msg, "userPassword");
4360 ldb_msg_remove_attr(ac->update_msg, "clearTextPassword");
4361 ldb_msg_remove_attr(ac->update_msg, "unicodePwd");
4362 ldb_msg_remove_attr(ac->update_msg, "ntPwdHistory");
4363 ldb_msg_remove_attr(ac->update_msg, "dBCSPwd");
4364 ldb_msg_remove_attr(ac->update_msg, "lmPwdHistory");
4365 ldb_msg_remove_attr(ac->update_msg, "supplementalCredentials");
4366 ldb_msg_remove_attr(ac->update_msg, "pwdLastSet");
4372 static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
4374 struct ldb_context *ldb = ldb_module_get_ctx(module);
4375 struct ph_context *ac = NULL;
4378 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add\n");
4380 ret = password_hash_needed(module, req, &ac);
4381 if (ret != LDB_SUCCESS) {
4388 /* Make sure we are performing the password set action on a (for us)
4389 * valid object. Those are instances of either "user" and/or
4390 * "inetOrgPerson". Otherwise continue with the submodules. */
4391 if ((!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "user"))
4392 && (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "inetOrgPerson"))) {
4396 if (ldb_msg_find_element(req->op.add.message, "clearTextPassword") != NULL) {
4397 ldb_set_errstring(ldb,
4398 "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
4399 return LDB_ERR_NO_SUCH_ATTRIBUTE;
4402 return ldb_next_request(module, req);
4405 /* get user domain data */
4406 ret = build_domain_data_request(ac);
4407 if (ret != LDB_SUCCESS) {
4411 return ldb_next_request(module, ac->dom_req);
4414 static int password_hash_add_do_add(struct ph_context *ac)
4416 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
4417 struct ldb_request *down_req;
4418 struct setup_password_fields_io io;
4421 /* Prepare the internal data structure containing the passwords */
4422 ret = setup_io(ac, ac->req->op.add.message, NULL, &io);
4423 if (ret != LDB_SUCCESS) {
4427 ret = setup_password_fields(&io);
4428 if (ret != LDB_SUCCESS) {
4432 ret = check_password_restrictions_and_log(&io);
4433 if (ret != LDB_SUCCESS) {
4437 ret = setup_smartcard_reset(&io);
4438 if (ret != LDB_SUCCESS) {
4442 ret = update_final_msg(&io);
4443 if (ret != LDB_SUCCESS) {
4447 ret = ldb_build_add_req(&down_req, ldb, ac,
4452 LDB_REQ_SET_LOCATION(down_req);
4453 if (ret != LDB_SUCCESS) {
4457 return ldb_next_request(ac->module, down_req);
4460 static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
4462 struct ldb_context *ldb = ldb_module_get_ctx(module);
4463 struct ph_context *ac = NULL;
4464 const char *passwordAttrs[] = {DSDB_PASSWORD_ATTRIBUTES, NULL}, **l;
4465 unsigned int del_attr_cnt, add_attr_cnt, rep_attr_cnt;
4466 struct ldb_message_element *passwordAttr;
4467 struct ldb_message *msg;
4468 struct ldb_request *down_req;
4469 struct ldb_control *restore = NULL;
4473 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
4475 ret = password_hash_needed(module, req, &ac);
4476 if (ret != LDB_SUCCESS) {
4483 /* use a new message structure so that we can modify it */
4484 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
4486 return ldb_oom(ldb);
4489 /* - check for single-valued password attributes
4490 * (if not return "CONSTRAINT_VIOLATION")
4491 * - check that for a password change operation one add and one delete
4493 * (if not return "CONSTRAINT_VIOLATION" or "UNWILLING_TO_PERFORM")
4494 * - check that a password change and a password set operation cannot
4496 * (if not return "UNWILLING_TO_PERFORM")
4497 * - remove all password attributes modifications from the first change
4498 * operation (anything without the passwords) - we will make the real
4499 * modification later */
4503 for (l = passwordAttrs; *l != NULL; l++) {
4504 if ((!ac->userPassword) &&
4505 (ldb_attr_cmp(*l, "userPassword") == 0)) {
4509 while ((passwordAttr = ldb_msg_find_element(msg, *l)) != NULL) {
4510 unsigned int mtype = LDB_FLAG_MOD_TYPE(passwordAttr->flags);
4511 unsigned int nvalues = passwordAttr->num_values;
4513 if (mtype == LDB_FLAG_MOD_DELETE) {
4516 if (mtype == LDB_FLAG_MOD_ADD) {
4519 if (mtype == LDB_FLAG_MOD_REPLACE) {
4522 if ((nvalues != 1) && (mtype == LDB_FLAG_MOD_ADD)) {
4524 ldb_asprintf_errstring(ldb,
4525 "'%s' attribute must have exactly one value on add operations!",
4527 return LDB_ERR_CONSTRAINT_VIOLATION;
4529 if ((nvalues > 1) && (mtype == LDB_FLAG_MOD_DELETE)) {
4531 ldb_asprintf_errstring(ldb,
4532 "'%s' attribute must have zero or one value(s) on delete operations!",
4534 return LDB_ERR_CONSTRAINT_VIOLATION;
4536 ldb_msg_remove_element(msg, passwordAttr);
4539 if ((del_attr_cnt == 0) && (add_attr_cnt > 0)) {
4541 ldb_set_errstring(ldb,
4542 "Only the add action for a password change specified!");
4543 return LDB_ERR_UNWILLING_TO_PERFORM;
4545 if ((del_attr_cnt > 1) || (add_attr_cnt > 1)) {
4547 ldb_set_errstring(ldb,
4548 "Only one delete and one add action for a password change allowed!");
4549 return LDB_ERR_UNWILLING_TO_PERFORM;
4551 if ((rep_attr_cnt > 0) && ((del_attr_cnt > 0) || (add_attr_cnt > 0))) {
4553 ldb_set_errstring(ldb,
4554 "Either a password change or a password set operation is allowed!");
4555 return LDB_ERR_UNWILLING_TO_PERFORM;
4558 restore = ldb_request_get_control(req,
4559 DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
4560 if (restore == NULL) {
4562 * A tomstone reanimation generates a double update
4565 * So we only remove it without the
4566 * DSDB_CONTROL_RESTORE_TOMBSTONE_OID control.
4568 ldb_msg_remove_attr(msg, "pwdLastSet");
4572 /* if there was nothing else to be modified skip to next step */
4573 if (msg->num_elements == 0) {
4574 return password_hash_mod_search_self(ac);
4578 * Now we apply all changes remaining in msg
4579 * and remove them from our final update_msg
4582 for (i = 0; i < msg->num_elements; i++) {
4583 ldb_msg_remove_attr(ac->update_msg,
4584 msg->elements[i].name);
4587 ret = ldb_build_mod_req(&down_req, ldb, ac,
4590 ac, ph_modify_callback,
4592 LDB_REQ_SET_LOCATION(down_req);
4593 if (ret != LDB_SUCCESS) {
4597 return ldb_next_request(module, down_req);
4600 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
4602 struct ph_context *ac;
4604 ac = talloc_get_type(req->context, struct ph_context);
4607 return ldb_module_done(ac->req, NULL, NULL,
4608 LDB_ERR_OPERATIONS_ERROR);
4611 if (ares->type == LDB_REPLY_REFERRAL) {
4612 return ldb_module_send_referral(ac->req, ares->referral);
4615 if (ares->error != LDB_SUCCESS) {
4616 return ldb_module_done(ac->req, ares->controls,
4617 ares->response, ares->error);
4620 if (ares->type != LDB_REPLY_DONE) {
4622 return ldb_module_done(ac->req, NULL, NULL,
4623 LDB_ERR_OPERATIONS_ERROR);
4628 return password_hash_mod_search_self(ac);
4631 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
4633 struct ldb_context *ldb;
4634 struct ph_context *ac;
4635 int ret = LDB_SUCCESS;
4637 ac = talloc_get_type(req->context, struct ph_context);
4638 ldb = ldb_module_get_ctx(ac->module);
4641 ret = LDB_ERR_OPERATIONS_ERROR;
4644 if (ares->error != LDB_SUCCESS) {
4645 return ldb_module_done(ac->req, ares->controls,
4646 ares->response, ares->error);
4649 /* we are interested only in the single reply (base search) */
4650 switch (ares->type) {
4651 case LDB_REPLY_ENTRY:
4652 /* Make sure we are performing the password change action on a
4653 * (for us) valid object. Those are instances of either "user"
4654 * and/or "inetOrgPerson". Otherwise continue with the
4656 if ((!ldb_msg_check_string_attribute(ares->message, "objectClass", "user"))
4657 && (!ldb_msg_check_string_attribute(ares->message, "objectClass", "inetOrgPerson"))) {
4660 if (ldb_msg_find_element(ac->req->op.mod.message, "clearTextPassword") != NULL) {
4661 ldb_set_errstring(ldb,
4662 "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
4663 ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
4667 ret = ldb_next_request(ac->module, ac->req);
4671 if (ac->search_res != NULL) {
4674 ldb_set_errstring(ldb, "Too many results");
4675 ret = LDB_ERR_OPERATIONS_ERROR;
4679 ac->search_res = talloc_steal(ac, ares);
4683 case LDB_REPLY_REFERRAL:
4684 /* ignore anything else for now */
4689 case LDB_REPLY_DONE:
4692 /* get user domain data */
4693 ret = build_domain_data_request(ac);
4694 if (ret != LDB_SUCCESS) {
4695 return ldb_module_done(ac->req, NULL, NULL, ret);
4698 ret = ldb_next_request(ac->module, ac->dom_req);
4703 if (ret != LDB_SUCCESS) {
4704 return ldb_module_done(ac->req, NULL, NULL, ret);
4710 static int password_hash_mod_search_self(struct ph_context *ac)
4712 struct ldb_context *ldb;
4713 static const char * const attrs[] = { "objectClass",
4714 "userAccountControl",
4715 "msDS-ResultantPSO",
4716 "msDS-User-Account-Control-Computed",
4720 "userPrincipalName",
4722 "supplementalCredentials",
4730 "msDS-SecondaryKrbTgtNumber",
4732 struct ldb_request *search_req;
4735 ldb = ldb_module_get_ctx(ac->module);
4737 ret = ldb_build_search_req(&search_req, ldb, ac,
4738 ac->req->op.mod.message->dn,
4743 ac, ph_mod_search_callback,
4745 LDB_REQ_SET_LOCATION(search_req);
4746 if (ret != LDB_SUCCESS) {
4750 return ldb_next_request(ac->module, search_req);
4753 static int password_hash_mod_do_mod(struct ph_context *ac)
4755 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
4756 struct ldb_request *mod_req;
4757 struct setup_password_fields_io io;
4760 /* Prepare the internal data structure containing the passwords */
4761 ret = setup_io(ac, ac->req->op.mod.message,
4762 ac->search_res->message, &io);
4763 if (ret != LDB_SUCCESS) {
4767 ret = setup_password_fields(&io);
4768 if (ret != LDB_SUCCESS) {
4772 ret = check_password_restrictions_and_log(&io);
4773 if (ret != LDB_SUCCESS) {
4777 ret = setup_smartcard_reset(&io);
4778 if (ret != LDB_SUCCESS) {
4782 ret = update_final_msg(&io);
4783 if (ret != LDB_SUCCESS) {
4787 ret = ldb_build_mod_req(&mod_req, ldb, ac,
4792 LDB_REQ_SET_LOCATION(mod_req);
4793 if (ret != LDB_SUCCESS) {
4797 return ldb_next_request(ac->module, mod_req);
4800 static const struct ldb_module_ops ldb_password_hash_module_ops = {
4801 .name = "password_hash",
4802 .add = password_hash_add,
4803 .modify = password_hash_modify
4806 int ldb_password_hash_module_init(const char *version)
4809 const char *gversion = NULL;
4810 #endif /* ENABLE_GPGME */
4812 LDB_MODULE_CHECK_VERSION(version);
4816 * Note: this sets a SIGPIPE handler
4817 * if none is active already. See:
4818 * https://www.gnupg.org/documentation/manuals/gpgme/Signal-Handling.html#Signal-Handling
4820 gversion = gpgme_check_version(GPGME_VERSION);
4821 if (gversion == NULL) {
4822 fprintf(stderr, "%s() in %s version[%s]: "
4823 "gpgme_check_version(%s) not available, "
4824 "gpgme_check_version(NULL) => '%s'\n",
4825 __func__, __FILE__, version,
4826 GPGME_VERSION, gpgme_check_version(NULL));
4827 return LDB_ERR_UNAVAILABLE;
4829 #endif /* ENABLE_GPGME */
4831 return ldb_register_module(&ldb_password_hash_module_ops);