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/crypto.h"
46 #include "param/param.h"
47 #include "lib/krb5_wrap/krb5_samba.h"
48 #include "auth/common_auth.h"
49 #include "lib/messaging/messaging.h"
56 /* If we have decided there is a reason to work on this request, then
57 * setup all the password hash types correctly.
59 * If we haven't the hashes yet but the password given as plain-text (attributes
60 * 'unicodePwd', 'userPassword' and 'clearTextPassword') we have to check for
61 * the constraints. Once this is done, we calculate the password hashes.
63 * Notice: unlike the real AD which only supports the UTF16 special based
64 * 'unicodePwd' and the UTF8 based 'userPassword' plaintext attribute we
65 * understand also a UTF16 based 'clearTextPassword' one.
66 * The latter is also accessible through LDAP so it can also be set by external
67 * tools and scripts. But be aware that this isn't portable on non SAMBA 4 ADs!
69 * Also when the module receives only the password hashes (possible through
70 * specifying an internal LDB control - for security reasons) some checks are
71 * performed depending on the operation mode (see below) (e.g. if the password
72 * has been in use before if the password memory policy was activated).
74 * Attention: There is a difference between "modify" and "reset" operations
75 * (see MS-ADTS 3.1.1.3.1.5). If the client sends a "add" and "remove"
76 * operation for a password attribute we thread this as a "modify"; if it sends
77 * only a "replace" one we have an (administrative) reset.
79 * Finally, if the administrator has requested that a password history
80 * be maintained, then this should also be written out.
84 /* TODO: [consider always MS-ADTS 3.1.1.3.1.5]
85 * - Check for right connection encryption
88 /* Notice: Definition of "dsdb_control_password_change_status" moved into
92 struct ldb_module *module;
93 struct ldb_request *req;
95 struct ldb_request *dom_req;
96 struct ldb_reply *dom_res;
98 struct ldb_reply *search_res;
100 struct ldb_message *update_msg;
102 struct dsdb_control_password_change_status *status;
103 struct dsdb_control_password_change *change;
105 const char **gpg_key_ids;
111 bool update_password;
113 bool pwd_last_set_bypass;
114 bool pwd_last_set_default;
115 bool smartcard_reset;
116 const char **userPassword_schemes;
120 struct setup_password_fields_io {
121 struct ph_context *ac;
123 struct smb_krb5_context *smb_krb5_context;
125 /* info about the user account */
127 uint32_t userAccountControl;
129 const char *sAMAccountName;
130 const char *user_principal_name;
133 uint32_t restrictions;
134 struct dom_sid *account_sid;
137 /* new credentials and old given credentials */
138 struct setup_password_fields_given {
139 const struct ldb_val *cleartext_utf8;
140 const struct ldb_val *cleartext_utf16;
141 struct samr_Password *nt_hash;
142 struct samr_Password *lm_hash;
145 /* old credentials */
147 struct samr_Password *nt_hash;
148 struct samr_Password *lm_hash;
149 uint32_t nt_history_len;
150 struct samr_Password *nt_history;
151 uint32_t lm_history_len;
152 struct samr_Password *lm_history;
153 const struct ldb_val *supplemental;
154 struct supplementalCredentialsBlob scb;
157 /* generated credentials */
159 struct samr_Password *nt_hash;
160 struct samr_Password *lm_hash;
161 uint32_t nt_history_len;
162 struct samr_Password *nt_history;
163 uint32_t lm_history_len;
164 struct samr_Password *lm_history;
170 struct ldb_val supplemental;
175 static int msg_find_old_and_new_pwd_val(const struct ldb_message *msg,
177 enum ldb_request_type operation,
178 const struct ldb_val **new_val,
179 const struct ldb_val **old_val);
181 static int password_hash_bypass(struct ldb_module *module, struct ldb_request *request)
183 struct ldb_context *ldb = ldb_module_get_ctx(module);
184 const struct ldb_message *msg;
185 struct ldb_message_element *nte;
186 struct ldb_message_element *lme;
187 struct ldb_message_element *nthe;
188 struct ldb_message_element *lmhe;
189 struct ldb_message_element *sce;
191 switch (request->operation) {
193 msg = request->op.add.message;
196 msg = request->op.mod.message;
199 return ldb_next_request(module, request);
202 /* nobody must touch password histories and 'supplementalCredentials' */
203 nte = dsdb_get_single_valued_attr(msg, "unicodePwd",
205 lme = dsdb_get_single_valued_attr(msg, "dBCSPwd",
207 nthe = dsdb_get_single_valued_attr(msg, "ntPwdHistory",
209 lmhe = dsdb_get_single_valued_attr(msg, "lmPwdHistory",
211 sce = dsdb_get_single_valued_attr(msg, "supplementalCredentials",
214 #define CHECK_HASH_ELEMENT(e, min, max) do {\
215 if (e && e->num_values) { \
216 unsigned int _count; \
217 if (e->num_values != 1) { \
218 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
219 "num_values != 1"); \
221 if ((e->values[0].length % 16) != 0) { \
222 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
223 "length % 16 != 0"); \
225 _count = e->values[0].length / 16; \
226 if (_count < min) { \
227 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
230 if (_count > max) { \
231 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
237 CHECK_HASH_ELEMENT(nte, 1, 1);
238 CHECK_HASH_ELEMENT(lme, 1, 1);
239 CHECK_HASH_ELEMENT(nthe, 1, INT32_MAX);
240 CHECK_HASH_ELEMENT(lmhe, 1, INT32_MAX);
242 if (sce && sce->num_values) {
243 enum ndr_err_code ndr_err;
244 struct supplementalCredentialsBlob *scb;
245 struct supplementalCredentialsPackage *scpp = NULL;
246 struct supplementalCredentialsPackage *scpk = NULL;
247 struct supplementalCredentialsPackage *scpkn = NULL;
248 struct supplementalCredentialsPackage *scpct = NULL;
249 DATA_BLOB scpbp = data_blob_null;
250 DATA_BLOB scpbk = data_blob_null;
251 DATA_BLOB scpbkn = data_blob_null;
252 DATA_BLOB scpbct = data_blob_null;
256 if (sce->num_values != 1) {
257 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
261 scb = talloc_zero(request, struct supplementalCredentialsBlob);
263 return ldb_module_oom(module);
266 ndr_err = ndr_pull_struct_blob_all(&sce->values[0], scb, scb,
267 (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
268 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
269 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
270 "ndr_pull_struct_blob_all");
273 if (scb->sub.num_packages < 2) {
274 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
278 for (i=0; i < scb->sub.num_packages; i++) {
281 subblob = strhex_to_data_blob(scb, scb->sub.packages[i].data);
282 if (subblob.data == NULL) {
283 return ldb_module_oom(module);
286 if (strcmp(scb->sub.packages[i].name, "Packages") == 0) {
288 return ldb_error(ldb,
289 LDB_ERR_CONSTRAINT_VIOLATION,
292 scpp = &scb->sub.packages[i];
296 if (strcmp(scb->sub.packages[i].name, "Primary:Kerberos") == 0) {
298 return ldb_error(ldb,
299 LDB_ERR_CONSTRAINT_VIOLATION,
300 "Primary:Kerberos twice");
302 scpk = &scb->sub.packages[i];
306 if (strcmp(scb->sub.packages[i].name, "Primary:Kerberos-Newer-Keys") == 0) {
308 return ldb_error(ldb,
309 LDB_ERR_CONSTRAINT_VIOLATION,
310 "Primary:Kerberos-Newer-Keys twice");
312 scpkn = &scb->sub.packages[i];
316 if (strcmp(scb->sub.packages[i].name, "Primary:CLEARTEXT") == 0) {
318 return ldb_error(ldb,
319 LDB_ERR_CONSTRAINT_VIOLATION,
320 "Primary:CLEARTEXT twice");
322 scpct = &scb->sub.packages[i];
327 data_blob_free(&subblob);
331 return ldb_error(ldb,
332 LDB_ERR_CONSTRAINT_VIOLATION,
333 "Primary:Packages missing");
338 * If Primary:Kerberos is missing w2k8r2 reboots
339 * when a password is changed.
341 return ldb_error(ldb,
342 LDB_ERR_CONSTRAINT_VIOLATION,
343 "Primary:Kerberos missing");
347 struct package_PackagesBlob *p;
350 p = talloc_zero(scb, struct package_PackagesBlob);
352 return ldb_module_oom(module);
355 ndr_err = ndr_pull_struct_blob(&scpbp, p, p,
356 (ndr_pull_flags_fn_t)ndr_pull_package_PackagesBlob);
357 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
358 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
359 "ndr_pull_struct_blob Packages");
362 if (p->names == NULL) {
363 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
364 "Packages names == NULL");
367 for (n = 0; p->names[n]; n++) {
371 if (scb->sub.num_packages != (n + 1)) {
372 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
373 "Packages num_packages != num_names + 1");
380 struct package_PrimaryKerberosBlob *k;
382 k = talloc_zero(scb, struct package_PrimaryKerberosBlob);
384 return ldb_module_oom(module);
387 ndr_err = ndr_pull_struct_blob(&scpbk, k, k,
388 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
389 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
390 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
391 "ndr_pull_struct_blob PrimaryKerberos");
394 if (k->version != 3) {
395 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
396 "PrimaryKerberos version != 3");
399 if (k->ctr.ctr3.salt.string == NULL) {
400 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
401 "PrimaryKerberos salt == NULL");
404 if (strlen(k->ctr.ctr3.salt.string) == 0) {
405 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
406 "PrimaryKerberos strlen(salt) == 0");
409 if (k->ctr.ctr3.num_keys != 2) {
410 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
411 "PrimaryKerberos num_keys != 2");
414 if (k->ctr.ctr3.num_old_keys > k->ctr.ctr3.num_keys) {
415 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
416 "PrimaryKerberos num_old_keys > num_keys");
419 if (k->ctr.ctr3.keys[0].keytype != ENCTYPE_DES_CBC_MD5) {
420 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
421 "PrimaryKerberos key[0] != DES_CBC_MD5");
423 if (k->ctr.ctr3.keys[1].keytype != ENCTYPE_DES_CBC_CRC) {
424 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
425 "PrimaryKerberos key[1] != DES_CBC_CRC");
428 if (k->ctr.ctr3.keys[0].value_len != 8) {
429 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
430 "PrimaryKerberos key[0] value_len != 8");
432 if (k->ctr.ctr3.keys[1].value_len != 8) {
433 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
434 "PrimaryKerberos key[1] value_len != 8");
437 for (i = 0; i < k->ctr.ctr3.num_old_keys; i++) {
438 if (k->ctr.ctr3.old_keys[i].keytype ==
439 k->ctr.ctr3.keys[i].keytype &&
440 k->ctr.ctr3.old_keys[i].value_len ==
441 k->ctr.ctr3.keys[i].value_len) {
445 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
446 "PrimaryKerberos old_keys type/value_len doesn't match");
453 struct package_PrimaryKerberosBlob *k;
455 k = talloc_zero(scb, struct package_PrimaryKerberosBlob);
457 return ldb_module_oom(module);
460 ndr_err = ndr_pull_struct_blob(&scpbkn, k, k,
461 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
462 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
463 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
464 "ndr_pull_struct_blob PrimaryKerberosNeverKeys");
467 if (k->version != 4) {
468 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
469 "KerberosNerverKeys version != 4");
472 if (k->ctr.ctr4.salt.string == NULL) {
473 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
474 "KerberosNewerKeys salt == NULL");
477 if (strlen(k->ctr.ctr4.salt.string) == 0) {
478 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
479 "KerberosNewerKeys strlen(salt) == 0");
482 if (k->ctr.ctr4.num_keys != 4) {
483 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
484 "KerberosNewerKeys num_keys != 2");
487 if (k->ctr.ctr4.num_old_keys > k->ctr.ctr4.num_keys) {
488 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
489 "KerberosNewerKeys num_old_keys > num_keys");
492 if (k->ctr.ctr4.num_older_keys > k->ctr.ctr4.num_old_keys) {
493 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
494 "KerberosNewerKeys num_older_keys > num_old_keys");
497 if (k->ctr.ctr4.keys[0].keytype != ENCTYPE_AES256_CTS_HMAC_SHA1_96) {
498 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
499 "KerberosNewerKeys key[0] != AES256");
501 if (k->ctr.ctr4.keys[1].keytype != ENCTYPE_AES128_CTS_HMAC_SHA1_96) {
502 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
503 "KerberosNewerKeys key[1] != AES128");
505 if (k->ctr.ctr4.keys[2].keytype != ENCTYPE_DES_CBC_MD5) {
506 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
507 "KerberosNewerKeys key[2] != DES_CBC_MD5");
509 if (k->ctr.ctr4.keys[3].keytype != ENCTYPE_DES_CBC_CRC) {
510 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
511 "KerberosNewerKeys key[3] != DES_CBC_CRC");
514 if (k->ctr.ctr4.keys[0].value_len != 32) {
515 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
516 "KerberosNewerKeys key[0] value_len != 32");
518 if (k->ctr.ctr4.keys[1].value_len != 16) {
519 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
520 "KerberosNewerKeys key[1] value_len != 16");
522 if (k->ctr.ctr4.keys[2].value_len != 8) {
523 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
524 "KerberosNewerKeys key[2] value_len != 8");
526 if (k->ctr.ctr4.keys[3].value_len != 8) {
527 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
528 "KerberosNewerKeys key[3] value_len != 8");
533 * Maybe we can check old and older keys here.
534 * But we need to do some tests, if the old keys
535 * can be taken from the PrimaryKerberos blob
536 * (with only des keys), when the domain was upgraded
544 struct package_PrimaryCLEARTEXTBlob *ct;
546 ct = talloc_zero(scb, struct package_PrimaryCLEARTEXTBlob);
548 return ldb_module_oom(module);
551 ndr_err = ndr_pull_struct_blob(&scpbct, ct, ct,
552 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryCLEARTEXTBlob);
553 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
554 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
555 "ndr_pull_struct_blob PrimaryCLEARTEXT");
558 if ((ct->cleartext.length % 2) != 0) {
559 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
560 "PrimaryCLEARTEXT length % 2 != 0");
566 ndr_err = ndr_push_struct_blob(&blob, scb, scb,
567 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
568 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
569 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
570 "ndr_pull_struct_blob_all");
573 if (sce->values[0].length != blob.length) {
574 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
575 "supplementalCredentialsBlob length differ");
578 if (memcmp(sce->values[0].data, blob.data, blob.length) != 0) {
579 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
580 "supplementalCredentialsBlob memcmp differ");
586 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_bypass - validated\n");
587 return ldb_next_request(module, request);
590 /* Get the NT hash, and fill it in as an entry in the password history,
591 and specify it into io->g.nt_hash */
593 static int setup_nt_fields(struct setup_password_fields_io *io)
595 struct ldb_context *ldb;
598 io->g.nt_hash = io->n.nt_hash;
599 ldb = ldb_module_get_ctx(io->ac->module);
601 if (io->ac->status->domain_data.pwdHistoryLength == 0) {
605 /* We might not have an old NT password */
606 io->g.nt_history = talloc_array(io->ac,
607 struct samr_Password,
608 io->ac->status->domain_data.pwdHistoryLength);
609 if (!io->g.nt_history) {
613 for (i = 0; i < MIN(io->ac->status->domain_data.pwdHistoryLength-1,
614 io->o.nt_history_len); i++) {
615 io->g.nt_history[i+1] = io->o.nt_history[i];
617 io->g.nt_history_len = i + 1;
620 io->g.nt_history[0] = *io->g.nt_hash;
623 * TODO: is this correct?
624 * the simular behavior is correct for the lm history case
626 E_md4hash("", io->g.nt_history[0].hash);
632 /* Get the LANMAN hash, and fill it in as an entry in the password history,
633 and specify it into io->g.lm_hash */
635 static int setup_lm_fields(struct setup_password_fields_io *io)
637 struct ldb_context *ldb;
640 io->g.lm_hash = io->n.lm_hash;
641 ldb = ldb_module_get_ctx(io->ac->module);
643 if (io->ac->status->domain_data.pwdHistoryLength == 0) {
647 /* We might not have an old LM password */
648 io->g.lm_history = talloc_array(io->ac,
649 struct samr_Password,
650 io->ac->status->domain_data.pwdHistoryLength);
651 if (!io->g.lm_history) {
655 for (i = 0; i < MIN(io->ac->status->domain_data.pwdHistoryLength-1,
656 io->o.lm_history_len); i++) {
657 io->g.lm_history[i+1] = io->o.lm_history[i];
659 io->g.lm_history_len = i + 1;
662 io->g.lm_history[0] = *io->g.lm_hash;
664 E_deshash("", io->g.lm_history[0].hash);
670 static int setup_kerberos_keys(struct setup_password_fields_io *io)
672 struct ldb_context *ldb;
673 krb5_error_code krb5_ret;
674 krb5_principal salt_principal;
677 krb5_data cleartext_data;
679 ldb = ldb_module_get_ctx(io->ac->module);
680 cleartext_data.data = (char *)io->n.cleartext_utf8->data;
681 cleartext_data.length = io->n.cleartext_utf8->length;
683 /* Many, many thanks to lukeh@padl.com for this
684 * algorithm, described in his Nov 10 2004 mail to
685 * samba-technical@lists.samba.org */
688 * Determine a salting principal
690 if (io->u.is_computer) {
694 name = strlower_talloc(io->ac, io->u.sAMAccountName);
699 if (name[strlen(name)-1] == '$') {
700 name[strlen(name)-1] = '\0';
703 saltbody = talloc_asprintf(io->ac, "%s.%s", name,
704 io->ac->status->domain_data.dns_domain);
709 krb5_ret = smb_krb5_make_principal(io->smb_krb5_context->krb5_context,
711 io->ac->status->domain_data.realm,
712 "host", saltbody, NULL);
713 } else if (io->u.user_principal_name) {
714 char *user_principal_name;
717 user_principal_name = talloc_strdup(io->ac, io->u.user_principal_name);
718 if (!user_principal_name) {
722 p = strchr(user_principal_name, '@');
727 krb5_ret = smb_krb5_make_principal(io->smb_krb5_context->krb5_context,
729 io->ac->status->domain_data.realm,
730 user_principal_name, NULL);
732 krb5_ret = smb_krb5_make_principal(io->smb_krb5_context->krb5_context,
734 io->ac->status->domain_data.realm,
735 io->u.sAMAccountName, NULL);
738 ldb_asprintf_errstring(ldb,
739 "setup_kerberos_keys: "
740 "generation of a salting principal failed: %s",
741 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
743 return LDB_ERR_OPERATIONS_ERROR;
747 * create salt from salt_principal
749 krb5_ret = smb_krb5_get_pw_salt(io->smb_krb5_context->krb5_context,
750 salt_principal, &salt);
751 krb5_free_principal(io->smb_krb5_context->krb5_context, salt_principal);
753 ldb_asprintf_errstring(ldb,
754 "setup_kerberos_keys: "
755 "generation of krb5_salt failed: %s",
756 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
758 return LDB_ERR_OPERATIONS_ERROR;
760 /* create a talloc copy */
761 io->g.salt = talloc_strndup(io->ac,
764 smb_krb5_free_data_contents(io->smb_krb5_context->krb5_context, &salt);
768 /* now use the talloced copy of the salt */
769 salt.data = discard_const(io->g.salt);
770 salt.length = strlen(io->g.salt);
773 * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of
774 * the salt and the cleartext password
776 krb5_ret = smb_krb5_create_key_from_string(io->smb_krb5_context->krb5_context,
780 ENCTYPE_AES256_CTS_HMAC_SHA1_96,
783 ldb_asprintf_errstring(ldb,
784 "setup_kerberos_keys: "
785 "generation of a aes256-cts-hmac-sha1-96 key failed: %s",
786 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
788 return LDB_ERR_OPERATIONS_ERROR;
790 io->g.aes_256 = data_blob_talloc(io->ac,
792 KRB5_KEY_LENGTH(&key));
793 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
794 if (!io->g.aes_256.data) {
799 * create ENCTYPE_AES128_CTS_HMAC_SHA1_96 key out of
800 * the salt and the cleartext password
802 krb5_ret = smb_krb5_create_key_from_string(io->smb_krb5_context->krb5_context,
806 ENCTYPE_AES128_CTS_HMAC_SHA1_96,
809 ldb_asprintf_errstring(ldb,
810 "setup_kerberos_keys: "
811 "generation of a aes128-cts-hmac-sha1-96 key failed: %s",
812 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
814 return LDB_ERR_OPERATIONS_ERROR;
816 io->g.aes_128 = data_blob_talloc(io->ac,
818 KRB5_KEY_LENGTH(&key));
819 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
820 if (!io->g.aes_128.data) {
825 * create ENCTYPE_DES_CBC_MD5 key out of
826 * the salt and the cleartext password
828 krb5_ret = smb_krb5_create_key_from_string(io->smb_krb5_context->krb5_context,
835 ldb_asprintf_errstring(ldb,
836 "setup_kerberos_keys: "
837 "generation of a des-cbc-md5 key failed: %s",
838 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
840 return LDB_ERR_OPERATIONS_ERROR;
842 io->g.des_md5 = data_blob_talloc(io->ac,
844 KRB5_KEY_LENGTH(&key));
845 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
846 if (!io->g.des_md5.data) {
851 * create ENCTYPE_DES_CBC_CRC key out of
852 * the salt and the cleartext password
854 krb5_ret = smb_krb5_create_key_from_string(io->smb_krb5_context->krb5_context,
861 ldb_asprintf_errstring(ldb,
862 "setup_kerberos_keys: "
863 "generation of a des-cbc-crc key failed: %s",
864 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
866 return LDB_ERR_OPERATIONS_ERROR;
868 io->g.des_crc = data_blob_talloc(io->ac,
870 KRB5_KEY_LENGTH(&key));
871 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
872 if (!io->g.des_crc.data) {
879 static int setup_primary_kerberos(struct setup_password_fields_io *io,
880 const struct supplementalCredentialsBlob *old_scb,
881 struct package_PrimaryKerberosBlob *pkb)
883 struct ldb_context *ldb;
884 struct package_PrimaryKerberosCtr3 *pkb3 = &pkb->ctr.ctr3;
885 struct supplementalCredentialsPackage *old_scp = NULL;
886 struct package_PrimaryKerberosBlob _old_pkb;
887 struct package_PrimaryKerberosCtr3 *old_pkb3 = NULL;
889 enum ndr_err_code ndr_err;
891 ldb = ldb_module_get_ctx(io->ac->module);
894 * prepare generation of keys
896 * ENCTYPE_DES_CBC_MD5
897 * ENCTYPE_DES_CBC_CRC
900 pkb3->salt.string = io->g.salt;
902 pkb3->keys = talloc_array(io->ac,
903 struct package_PrimaryKerberosKey3,
909 pkb3->keys[0].keytype = ENCTYPE_DES_CBC_MD5;
910 pkb3->keys[0].value = &io->g.des_md5;
911 pkb3->keys[1].keytype = ENCTYPE_DES_CBC_CRC;
912 pkb3->keys[1].value = &io->g.des_crc;
914 /* initialize the old keys to zero */
915 pkb3->num_old_keys = 0;
916 pkb3->old_keys = NULL;
918 /* if there're no old keys, then we're done */
923 for (i=0; i < old_scb->sub.num_packages; i++) {
924 if (strcmp("Primary:Kerberos", old_scb->sub.packages[i].name) != 0) {
928 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
932 old_scp = &old_scb->sub.packages[i];
935 /* Primary:Kerberos element of supplementalCredentials */
939 blob = strhex_to_data_blob(io->ac, old_scp->data);
944 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
945 ndr_err = ndr_pull_struct_blob(&blob, io->ac, &_old_pkb,
946 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
947 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
948 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
949 ldb_asprintf_errstring(ldb,
950 "setup_primary_kerberos: "
951 "failed to pull old package_PrimaryKerberosBlob: %s",
953 return LDB_ERR_OPERATIONS_ERROR;
956 if (_old_pkb.version != 3) {
957 ldb_asprintf_errstring(ldb,
958 "setup_primary_kerberos: "
959 "package_PrimaryKerberosBlob version[%u] expected[3]",
961 return LDB_ERR_OPERATIONS_ERROR;
964 old_pkb3 = &_old_pkb.ctr.ctr3;
967 /* if we didn't found the old keys we're done */
972 /* fill in the old keys */
973 pkb3->num_old_keys = old_pkb3->num_keys;
974 pkb3->old_keys = old_pkb3->keys;
979 static int setup_primary_kerberos_newer(struct setup_password_fields_io *io,
980 const struct supplementalCredentialsBlob *old_scb,
981 struct package_PrimaryKerberosBlob *pkb)
983 struct ldb_context *ldb;
984 struct package_PrimaryKerberosCtr4 *pkb4 = &pkb->ctr.ctr4;
985 struct supplementalCredentialsPackage *old_scp = NULL;
986 struct package_PrimaryKerberosBlob _old_pkb;
987 struct package_PrimaryKerberosCtr4 *old_pkb4 = NULL;
989 enum ndr_err_code ndr_err;
991 ldb = ldb_module_get_ctx(io->ac->module);
994 * prepare generation of keys
996 * ENCTYPE_AES256_CTS_HMAC_SHA1_96
997 * ENCTYPE_AES128_CTS_HMAC_SHA1_96
998 * ENCTYPE_DES_CBC_MD5
999 * ENCTYPE_DES_CBC_CRC
1002 pkb4->salt.string = io->g.salt;
1003 pkb4->default_iteration_count = 4096;
1006 pkb4->keys = talloc_array(io->ac,
1007 struct package_PrimaryKerberosKey4,
1010 return ldb_oom(ldb);
1013 pkb4->keys[0].iteration_count = 4096;
1014 pkb4->keys[0].keytype = ENCTYPE_AES256_CTS_HMAC_SHA1_96;
1015 pkb4->keys[0].value = &io->g.aes_256;
1016 pkb4->keys[1].iteration_count = 4096;
1017 pkb4->keys[1].keytype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
1018 pkb4->keys[1].value = &io->g.aes_128;
1019 pkb4->keys[2].iteration_count = 4096;
1020 pkb4->keys[2].keytype = ENCTYPE_DES_CBC_MD5;
1021 pkb4->keys[2].value = &io->g.des_md5;
1022 pkb4->keys[3].iteration_count = 4096;
1023 pkb4->keys[3].keytype = ENCTYPE_DES_CBC_CRC;
1024 pkb4->keys[3].value = &io->g.des_crc;
1026 /* initialize the old keys to zero */
1027 pkb4->num_old_keys = 0;
1028 pkb4->old_keys = NULL;
1029 pkb4->num_older_keys = 0;
1030 pkb4->older_keys = NULL;
1032 /* if there're no old keys, then we're done */
1037 for (i=0; i < old_scb->sub.num_packages; i++) {
1038 if (strcmp("Primary:Kerberos-Newer-Keys", old_scb->sub.packages[i].name) != 0) {
1042 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
1046 old_scp = &old_scb->sub.packages[i];
1049 /* Primary:Kerberos-Newer-Keys element of supplementalCredentials */
1053 blob = strhex_to_data_blob(io->ac, old_scp->data);
1055 return ldb_oom(ldb);
1058 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
1059 ndr_err = ndr_pull_struct_blob(&blob, io->ac,
1061 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
1062 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1063 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1064 ldb_asprintf_errstring(ldb,
1065 "setup_primary_kerberos_newer: "
1066 "failed to pull old package_PrimaryKerberosBlob: %s",
1068 return LDB_ERR_OPERATIONS_ERROR;
1071 if (_old_pkb.version != 4) {
1072 ldb_asprintf_errstring(ldb,
1073 "setup_primary_kerberos_newer: "
1074 "package_PrimaryKerberosBlob version[%u] expected[4]",
1076 return LDB_ERR_OPERATIONS_ERROR;
1079 old_pkb4 = &_old_pkb.ctr.ctr4;
1082 /* if we didn't found the old keys we're done */
1087 /* fill in the old keys */
1088 pkb4->num_old_keys = old_pkb4->num_keys;
1089 pkb4->old_keys = old_pkb4->keys;
1090 pkb4->num_older_keys = old_pkb4->num_old_keys;
1091 pkb4->older_keys = old_pkb4->old_keys;
1096 static int setup_primary_wdigest(struct setup_password_fields_io *io,
1097 const struct supplementalCredentialsBlob *old_scb,
1098 struct package_PrimaryWDigestBlob *pdb)
1100 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1101 DATA_BLOB sAMAccountName;
1102 DATA_BLOB sAMAccountName_l;
1103 DATA_BLOB sAMAccountName_u;
1104 const char *user_principal_name = io->u.user_principal_name;
1105 DATA_BLOB userPrincipalName;
1106 DATA_BLOB userPrincipalName_l;
1107 DATA_BLOB userPrincipalName_u;
1108 DATA_BLOB netbios_domain;
1109 DATA_BLOB netbios_domain_l;
1110 DATA_BLOB netbios_domain_u;
1111 DATA_BLOB dns_domain;
1112 DATA_BLOB dns_domain_l;
1113 DATA_BLOB dns_domain_u;
1116 DATA_BLOB backslash;
1124 * See 3.1.1.8.11.3.1 WDIGEST_CREDENTIALS Construction
1125 * https://msdn.microsoft.com/en-us/library/cc245680.aspx
1126 * for what precalculated hashes are supposed to be stored...
1128 * I can't reproduce all values which should contain "Digest" as realm,
1129 * am I doing something wrong or is w2k3 just broken...?
1131 * W2K3 fills in following for a user:
1133 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
1134 * sAMAccountName: NewUser2Sam
1135 * userPrincipalName: NewUser2Princ@sub1.w2k3.vmnet1.vm.base
1137 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1138 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
1139 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
1140 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1141 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
1142 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
1143 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
1144 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1145 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1146 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1147 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1148 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1149 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1150 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1151 * 221c55284451ae9b3aacaa2a3c86f10f => NewUser2Princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1152 * 74e1be668853d4324d38c07e2acfb8ea => (w2k3 has a bug here!) newuser2princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1153 * e1e244ab7f098e3ae1761be7f9229bbb => NEWUSER2PRINC@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
1154 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
1155 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
1156 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
1157 * 31dc704d3640335b2123d4ee28aa1f11 => ??? changes with NewUser2Sam => NewUser1Sam
1158 * 36349f5cecd07320fb3bb0e119230c43 => ??? changes with NewUser2Sam => NewUser1Sam
1159 * 12adf019d037fb535c01fd0608e78d9d => ??? changes with NewUser2Sam => NewUser1Sam
1160 * 6feecf8e724906f3ee1105819c5105a1 => ??? changes with NewUser2Princ => NewUser1Princ
1161 * 6c6911f3de6333422640221b9c51ff1f => ??? changes with NewUser2Princ => NewUser1Princ
1162 * 4b279877e742895f9348ac67a8de2f69 => ??? changes with NewUser2Princ => NewUser1Princ
1163 * db0c6bff069513e3ebb9870d29b57490 => ??? changes with NewUser2Sam => NewUser1Sam
1164 * 45072621e56b1c113a4e04a8ff68cd0e => ??? changes with NewUser2Sam => NewUser1Sam
1165 * 11d1220abc44a9c10cf91ef4a9c1de02 => ??? changes with NewUser2Sam => NewUser1Sam
1167 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
1168 * sAMAccountName: NewUser2Sam
1170 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1171 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
1172 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
1173 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1174 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
1175 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
1176 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
1177 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1178 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1179 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1180 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1181 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1182 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1183 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1184 * 8a140d30b6f0a5912735dc1e3bc993b4 => NewUser2Sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1185 * 86d95b2faae6cae4ec261e7fbaccf093 => (here w2k3 is correct) newuser2sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1186 * dfeff1493110220efcdfc6362e5f5450 => NEWUSER2SAM@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
1187 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
1188 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
1189 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
1190 * 31dc704d3640335b2123d4ee28aa1f11 => ???M1 changes with NewUser2Sam => NewUser1Sam
1191 * 36349f5cecd07320fb3bb0e119230c43 => ???M1.L changes with newuser2sam => newuser1sam
1192 * 12adf019d037fb535c01fd0608e78d9d => ???M1.U changes with NEWUSER2SAM => NEWUSER1SAM
1193 * 569b4533f2d9e580211dd040e5e360a8 => ???M2 changes with NewUser2Princ => NewUser1Princ
1194 * 52528bddf310a587c5d7e6a9ae2cbb20 => ???M2.L changes with newuser2princ => newuser1princ
1195 * 4f629a4f0361289ca4255ab0f658fcd5 => ???M3 changes with NewUser2Princ => NewUser1Princ (doesn't depend on case of userPrincipal )
1196 * db0c6bff069513e3ebb9870d29b57490 => ???M4 changes with NewUser2Sam => NewUser1Sam
1197 * 45072621e56b1c113a4e04a8ff68cd0e => ???M5 changes with NewUser2Sam => NewUser1Sam (doesn't depend on case of sAMAccountName)
1198 * 11d1220abc44a9c10cf91ef4a9c1de02 => ???M4.U changes with NEWUSER2SAM => NEWUSER1SAM
1202 * sAMAccountName, netbios_domain
1205 .user = &sAMAccountName,
1206 .realm = &netbios_domain,
1209 .user = &sAMAccountName_l,
1210 .realm = &netbios_domain_l,
1213 .user = &sAMAccountName_u,
1214 .realm = &netbios_domain_u,
1217 .user = &sAMAccountName,
1218 .realm = &netbios_domain_u,
1221 .user = &sAMAccountName,
1222 .realm = &netbios_domain_l,
1225 .user = &sAMAccountName_u,
1226 .realm = &netbios_domain_l,
1229 .user = &sAMAccountName_l,
1230 .realm = &netbios_domain_u,
1233 * sAMAccountName, dns_domain
1236 * Windows preserves the case of the DNS domain,
1237 * Samba lower cases the domain at provision time
1238 * This means that for mixed case Domains, the WDigest08 hash
1239 * calculated by Samba differs from that calculated by Windows.
1240 * Until we get a real world use case this will remain a known
1241 * bug, as changing the case could have unforeseen impacts.
1245 .user = &sAMAccountName,
1246 .realm = &dns_domain,
1249 .user = &sAMAccountName_l,
1250 .realm = &dns_domain_l,
1253 .user = &sAMAccountName_u,
1254 .realm = &dns_domain_u,
1257 .user = &sAMAccountName,
1258 .realm = &dns_domain_u,
1261 .user = &sAMAccountName,
1262 .realm = &dns_domain_l,
1265 .user = &sAMAccountName_u,
1266 .realm = &dns_domain_l,
1269 .user = &sAMAccountName_l,
1270 .realm = &dns_domain_u,
1273 * userPrincipalName, no realm
1276 .user = &userPrincipalName,
1280 * NOTE: w2k3 messes this up, if the user has a real userPrincipalName,
1281 * the fallback to the sAMAccountName based userPrincipalName is correct
1283 .user = &userPrincipalName_l,
1286 .user = &userPrincipalName_u,
1289 * nt4dom\sAMAccountName, no realm
1292 .user = &sAMAccountName,
1293 .nt4dom = &netbios_domain
1296 .user = &sAMAccountName_l,
1297 .nt4dom = &netbios_domain_l
1300 .user = &sAMAccountName_u,
1301 .nt4dom = &netbios_domain_u
1305 * the following ones are guessed depending on the technet2 article
1306 * but not reproducable on a w2k3 server
1308 /* sAMAccountName with "Digest" realm */
1310 .user = &sAMAccountName,
1314 .user = &sAMAccountName_l,
1318 .user = &sAMAccountName_u,
1321 /* userPrincipalName with "Digest" realm */
1323 .user = &userPrincipalName,
1327 .user = &userPrincipalName_l,
1331 .user = &userPrincipalName_u,
1334 /* nt4dom\\sAMAccountName with "Digest" realm */
1336 .user = &sAMAccountName,
1337 .nt4dom = &netbios_domain,
1341 .user = &sAMAccountName_l,
1342 .nt4dom = &netbios_domain_l,
1346 .user = &sAMAccountName_u,
1347 .nt4dom = &netbios_domain_u,
1352 /* prepare DATA_BLOB's used in the combinations array */
1353 sAMAccountName = data_blob_string_const(io->u.sAMAccountName);
1354 sAMAccountName_l = data_blob_string_const(strlower_talloc(io->ac, io->u.sAMAccountName));
1355 if (!sAMAccountName_l.data) {
1356 return ldb_oom(ldb);
1358 sAMAccountName_u = data_blob_string_const(strupper_talloc(io->ac, io->u.sAMAccountName));
1359 if (!sAMAccountName_u.data) {
1360 return ldb_oom(ldb);
1363 /* if the user doesn't have a userPrincipalName, create one (with lower case realm) */
1364 if (!user_principal_name) {
1365 user_principal_name = talloc_asprintf(io->ac, "%s@%s",
1366 io->u.sAMAccountName,
1367 io->ac->status->domain_data.dns_domain);
1368 if (!user_principal_name) {
1369 return ldb_oom(ldb);
1372 userPrincipalName = data_blob_string_const(user_principal_name);
1373 userPrincipalName_l = data_blob_string_const(strlower_talloc(io->ac, user_principal_name));
1374 if (!userPrincipalName_l.data) {
1375 return ldb_oom(ldb);
1377 userPrincipalName_u = data_blob_string_const(strupper_talloc(io->ac, user_principal_name));
1378 if (!userPrincipalName_u.data) {
1379 return ldb_oom(ldb);
1382 netbios_domain = data_blob_string_const(io->ac->status->domain_data.netbios_domain);
1383 netbios_domain_l = data_blob_string_const(strlower_talloc(io->ac,
1384 io->ac->status->domain_data.netbios_domain));
1385 if (!netbios_domain_l.data) {
1386 return ldb_oom(ldb);
1388 netbios_domain_u = data_blob_string_const(strupper_talloc(io->ac,
1389 io->ac->status->domain_data.netbios_domain));
1390 if (!netbios_domain_u.data) {
1391 return ldb_oom(ldb);
1394 dns_domain = data_blob_string_const(io->ac->status->domain_data.dns_domain);
1395 dns_domain_l = data_blob_string_const(io->ac->status->domain_data.dns_domain);
1396 dns_domain_u = data_blob_string_const(io->ac->status->domain_data.realm);
1398 digest = data_blob_string_const("Digest");
1400 delim = data_blob_string_const(":");
1401 backslash = data_blob_string_const("\\");
1403 pdb->num_hashes = ARRAY_SIZE(wdigest);
1404 pdb->hashes = talloc_array(io->ac, struct package_PrimaryWDigestHash,
1407 return ldb_oom(ldb);
1410 for (i=0; i < ARRAY_SIZE(wdigest); i++) {
1413 if (wdigest[i].nt4dom) {
1414 MD5Update(&md5, wdigest[i].nt4dom->data, wdigest[i].nt4dom->length);
1415 MD5Update(&md5, backslash.data, backslash.length);
1417 MD5Update(&md5, wdigest[i].user->data, wdigest[i].user->length);
1418 MD5Update(&md5, delim.data, delim.length);
1419 if (wdigest[i].realm) {
1420 MD5Update(&md5, wdigest[i].realm->data, wdigest[i].realm->length);
1422 MD5Update(&md5, delim.data, delim.length);
1423 MD5Update(&md5, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length);
1424 MD5Final(pdb->hashes[i].hash, &md5);
1430 #define SHA_SALT_PERMITTED_CHARS "abcdefghijklmnopqrstuvwxyz" \
1431 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
1433 #define SHA_SALT_SIZE 16
1434 #define SHA_256_SCHEME "CryptSHA256"
1435 #define SHA_512_SCHEME "CryptSHA512"
1436 #define CRYPT "{CRYPT}"
1437 #define SHA_ID_LEN 3
1438 #define SHA_256_ALGORITHM_ID 5
1439 #define SHA_512_ALGORITHM_ID 6
1440 #define ROUNDS_PARAMETER "rounds="
1443 * Extract the crypt (3) algorithm number and number of hash rounds from the
1444 * supplied scheme string
1446 static bool parse_scheme(const char *scheme, int *algorithm, int *rounds) {
1448 const char *rp = NULL; /* Pointer to the 'rounds=' option */
1449 char digits[21]; /* digits extracted from the rounds option */
1450 int i = 0; /* loop index variable */
1452 if (strncasecmp(SHA_256_SCHEME, scheme, strlen(SHA_256_SCHEME)) == 0) {
1453 *algorithm = SHA_256_ALGORITHM_ID;
1454 } else if (strncasecmp(SHA_512_SCHEME, scheme, strlen(SHA_256_SCHEME))
1456 *algorithm = SHA_512_ALGORITHM_ID;
1461 rp = strcasestr(scheme, ROUNDS_PARAMETER);
1463 /* No options specified, use crypt default number of rounds */
1467 rp += strlen(ROUNDS_PARAMETER);
1468 for (i = 0; isdigit(rp[i]) && i < (sizeof(digits) - 1); i++) {
1472 *rounds = atoi(digits);
1477 * Calculate the password hash specified by scheme, and return it in
1480 static int setup_primary_userPassword_hash(
1482 struct setup_password_fields_io *io,
1484 struct package_PrimaryUserPasswordValue *hash_value)
1486 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1487 const char *salt = NULL; /* Randomly generated salt */
1488 const char *cmd = NULL; /* command passed to crypt */
1489 const char *hash = NULL; /* password hash generated by crypt */
1490 int algorithm = 0; /* crypt hash algorithm number */
1491 int rounds = 0; /* The number of hash rounds */
1492 DATA_BLOB *hash_blob = NULL;
1493 TALLOC_CTX *frame = talloc_stackframe();
1495 struct crypt_data crypt_data; /* working storage used by crypt */
1498 /* Genrate a random password salt */
1499 salt = generate_random_str_list(frame,
1501 SHA_SALT_PERMITTED_CHARS);
1504 return ldb_oom(ldb);
1507 /* determine the hashing algoritm and number of rounds*/
1508 if (!parse_scheme(scheme, &algorithm, &rounds)) {
1509 ldb_asprintf_errstring(
1511 "setup_primary_userPassword: Invalid scheme of [%s] "
1512 "specified for 'password hash userPassword schemes' in "
1516 return LDB_ERR_OPERATIONS_ERROR;
1518 hash_value->scheme = talloc_strdup(ctx, CRYPT);
1519 hash_value->scheme_len = strlen(CRYPT) + 1;
1521 /* generate the id/salt parameter used by crypt */
1523 cmd = talloc_asprintf(frame,
1529 cmd = talloc_asprintf(frame, "$%d$%s", algorithm, salt);
1533 * Relies on the assertion that cleartext_utf8->data is a zero
1534 * terminated UTF-8 string
1537 hash = crypt_r((char *)io->n.cleartext_utf8->data, cmd, &crypt_data);
1540 * No crypt_r falling back to crypt, which is NOT thread safe
1541 * Thread safety MT-Unsafe race:crypt
1543 hash = crypt((char *)io->n.cleartext_utf8->data, cmd);
1547 int err = strerror_r(errno, buf, sizeof(buf));
1549 strlcpy(buf, "Unknown error", sizeof(buf)-1);
1551 ldb_asprintf_errstring(
1553 "setup_primary_userPassword: generation of a %s "
1554 "password hash failed: (%s)",
1558 return LDB_ERR_OPERATIONS_ERROR;
1561 hash_blob = talloc_zero(ctx, DATA_BLOB);
1563 if (hash_blob == NULL) {
1565 return ldb_oom(ldb);
1568 *hash_blob = data_blob_talloc(hash_blob,
1569 (const uint8_t *)hash,
1571 if (hash_blob->data == NULL) {
1573 return ldb_oom(ldb);
1575 hash_value->value = hash_blob;
1581 * Calculate the desired extra password hashes
1583 static int setup_primary_userPassword(
1584 struct setup_password_fields_io *io,
1585 const struct supplementalCredentialsBlob *old_scb,
1586 struct package_PrimaryUserPasswordBlob *p_userPassword_b)
1588 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1589 TALLOC_CTX *frame = talloc_stackframe();
1594 * Save the current nt_hash, use this to determine if the password
1595 * has been changed by windows. Which will invalidate the userPassword
1596 * hash. Note once NTLM-Strong-NOWTF becomes available it should be
1597 * used in preference to the NT password hash
1599 if (io->g.nt_hash == NULL) {
1600 ldb_asprintf_errstring(ldb,
1601 "No NT Hash, unable to calculate userPassword hashes");
1602 return LDB_ERR_UNWILLING_TO_PERFORM;
1604 p_userPassword_b->current_nt_hash = *io->g.nt_hash;
1607 * Determine the number of hashes
1608 * Note: that currently there is no limit on the number of hashes
1609 * no checking is done on the number of schemes specified
1610 * or for uniqueness.
1612 p_userPassword_b->num_hashes = 0;
1613 for (i = 0; io->ac->userPassword_schemes[i]; i++) {
1614 p_userPassword_b->num_hashes++;
1617 p_userPassword_b->hashes
1618 = talloc_array(io->ac,
1619 struct package_PrimaryUserPasswordValue,
1620 p_userPassword_b->num_hashes);
1621 if (p_userPassword_b->hashes == NULL) {
1623 return ldb_oom(ldb);
1626 for (i = 0; io->ac->userPassword_schemes[i]; i++) {
1627 ret = setup_primary_userPassword_hash(
1628 p_userPassword_b->hashes,
1630 io->ac->userPassword_schemes[i],
1631 &p_userPassword_b->hashes[i]);
1632 if (ret != LDB_SUCCESS) {
1641 static int setup_primary_samba_gpg(struct setup_password_fields_io *io,
1642 struct package_PrimarySambaGPGBlob *pgb)
1644 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1647 gpgme_ctx_t ctx = NULL;
1648 size_t num_keys = str_list_length(io->ac->gpg_key_ids);
1649 gpgme_key_t keys[num_keys+1];
1652 gpgme_data_t plain_data = NULL;
1653 gpgme_data_t crypt_data = NULL;
1654 size_t crypt_length = 0;
1655 char *crypt_mem = NULL;
1657 gret = gpgme_new(&ctx);
1658 if (gret != GPG_ERR_NO_ERROR) {
1659 ldb_debug(ldb, LDB_DEBUG_ERROR,
1660 "%s:%s: gret[%u] %s\n",
1661 __location__, __func__,
1662 gret, gpgme_strerror(gret));
1663 return ldb_module_operr(io->ac->module);
1666 gpgme_set_armor(ctx, 1);
1668 gret = gpgme_data_new_from_mem(&plain_data,
1669 (const char *)io->n.cleartext_utf16->data,
1670 io->n.cleartext_utf16->length,
1672 if (gret != GPG_ERR_NO_ERROR) {
1673 ldb_debug(ldb, LDB_DEBUG_ERROR,
1674 "%s:%s: gret[%u] %s\n",
1675 __location__, __func__,
1676 gret, gpgme_strerror(gret));
1678 return ldb_module_operr(io->ac->module);
1680 gret = gpgme_data_new(&crypt_data);
1681 if (gret != GPG_ERR_NO_ERROR) {
1682 ldb_debug(ldb, LDB_DEBUG_ERROR,
1683 "%s:%s: gret[%u] %s\n",
1684 __location__, __func__,
1685 gret, gpgme_strerror(gret));
1686 gpgme_data_release(plain_data);
1688 return ldb_module_operr(io->ac->module);
1691 for (ki = 0; ki < num_keys; ki++) {
1692 const char *key_id = io->ac->gpg_key_ids[ki];
1693 size_t len = strlen(key_id);
1698 ldb_debug(ldb, LDB_DEBUG_FATAL,
1699 "%s:%s: ki[%zu] key_id[%s] strlen < 16, "
1700 "please specify at least the 64bit key id\n",
1701 __location__, __func__,
1703 for (kr = 0; keys[kr] != NULL; kr++) {
1704 gpgme_key_release(keys[kr]);
1706 gpgme_data_release(crypt_data);
1707 gpgme_data_release(plain_data);
1709 return ldb_module_operr(io->ac->module);
1712 gret = gpgme_get_key(ctx, key_id, &keys[ki], 0 /* public key */);
1713 if (gret != GPG_ERR_NO_ERROR) {
1715 ldb_debug(ldb, LDB_DEBUG_ERROR,
1716 "%s:%s: ki[%zu] key_id[%s] gret[%u] %s\n",
1717 __location__, __func__,
1719 gret, gpgme_strerror(gret));
1720 for (kr = 0; keys[kr] != NULL; kr++) {
1721 gpgme_key_release(keys[kr]);
1723 gpgme_data_release(crypt_data);
1724 gpgme_data_release(plain_data);
1726 return ldb_module_operr(io->ac->module);
1731 gret = gpgme_op_encrypt(ctx, keys,
1732 GPGME_ENCRYPT_ALWAYS_TRUST,
1733 plain_data, crypt_data);
1734 gpgme_data_release(plain_data);
1736 for (kr = 0; keys[kr] != NULL; kr++) {
1737 gpgme_key_release(keys[kr]);
1742 if (gret != GPG_ERR_NO_ERROR) {
1743 ldb_debug(ldb, LDB_DEBUG_ERROR,
1744 "%s:%s: gret[%u] %s\n",
1745 __location__, __func__,
1746 gret, gpgme_strerror(gret));
1747 gpgme_data_release(crypt_data);
1748 return ldb_module_operr(io->ac->module);
1751 crypt_mem = gpgme_data_release_and_get_mem(crypt_data, &crypt_length);
1753 if (crypt_mem == NULL) {
1754 return ldb_module_oom(io->ac->module);
1757 pgb->gpg_blob = data_blob_talloc(io->ac,
1758 (const uint8_t *)crypt_mem,
1760 gpgme_free(crypt_mem);
1763 if (pgb->gpg_blob.data == NULL) {
1764 return ldb_module_oom(io->ac->module);
1768 #else /* ENABLE_GPGME */
1769 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
1770 "You configured 'password hash gpg key ids', "
1771 "but GPGME support is missing. (%s:%d)",
1772 __FILE__, __LINE__);
1773 return LDB_ERR_UNWILLING_TO_PERFORM;
1774 #endif /* else ENABLE_GPGME */
1777 #define NUM_PACKAGES 6
1778 static int setup_supplemental_field(struct setup_password_fields_io *io)
1780 struct ldb_context *ldb;
1781 struct supplementalCredentialsBlob scb;
1782 struct supplementalCredentialsBlob *old_scb = NULL;
1785 * ( Kerberos-Newer-Keys, Kerberos,
1786 * WDigest, CLEARTEXT, userPassword, SambaGPG)
1788 uint32_t num_names = 0;
1789 const char *names[1+NUM_PACKAGES];
1790 uint32_t num_packages = 0;
1791 struct supplementalCredentialsPackage packages[1+NUM_PACKAGES];
1792 struct supplementalCredentialsPackage *pp = packages;
1794 enum ndr_err_code ndr_err;
1795 bool do_newer_keys = false;
1796 bool do_cleartext = false;
1797 bool do_samba_gpg = false;
1800 ZERO_STRUCT(packages);
1802 ldb = ldb_module_get_ctx(io->ac->module);
1804 if (!io->n.cleartext_utf8) {
1806 * when we don't have a cleartext password
1807 * we can't setup a supplementalCredential value
1812 /* if there's an old supplementaCredentials blob then use it */
1813 if (io->o.supplemental) {
1814 if (io->o.scb.sub.signature == SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
1815 old_scb = &io->o.scb;
1817 ldb_debug(ldb, LDB_DEBUG_ERROR,
1818 "setup_supplemental_field: "
1819 "supplementalCredentialsBlob "
1820 "signature[0x%04X] expected[0x%04X]",
1821 io->o.scb.sub.signature,
1822 SUPPLEMENTAL_CREDENTIALS_SIGNATURE);
1825 /* Per MS-SAMR 3.1.1.8.11.6 we create AES keys if our domain functionality level is 2008 or higher */
1830 * The ordering is this
1832 * Primary:Kerberos-Newer-Keys (optional)
1835 * Primary:CLEARTEXT (optional)
1836 * Primary:userPassword
1837 * Primary:SambaGPG (optional)
1839 * And the 'Packages' package is insert before the last
1842 * Note: it's important that Primary:SambaGPG is added as
1843 * the last element. This is the indication that it matches
1844 * the current password. When a password change happens on
1845 * a Windows DC, it will keep the old Primary:SambaGPG value,
1846 * but as the first element.
1848 do_newer_keys = (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008);
1849 if (do_newer_keys) {
1850 struct package_PrimaryKerberosBlob pknb;
1851 DATA_BLOB pknb_blob;
1854 * setup 'Primary:Kerberos-Newer-Keys' element
1856 names[num_names++] = "Kerberos-Newer-Keys";
1858 ret = setup_primary_kerberos_newer(io, old_scb, &pknb);
1859 if (ret != LDB_SUCCESS) {
1863 ndr_err = ndr_push_struct_blob(
1866 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1867 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1868 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1869 ldb_asprintf_errstring(
1871 "setup_supplemental_field: "
1873 "package_PrimaryKerberosNeverBlob: %s",
1875 return LDB_ERR_OPERATIONS_ERROR;
1877 pknb_hexstr = data_blob_hex_string_upper(io->ac, &pknb_blob);
1879 return ldb_oom(ldb);
1881 pp->name = "Primary:Kerberos-Newer-Keys";
1883 pp->data = pknb_hexstr;
1890 * setup 'Primary:Kerberos' element
1892 /* Primary:Kerberos */
1893 struct package_PrimaryKerberosBlob pkb;
1897 names[num_names++] = "Kerberos";
1899 ret = setup_primary_kerberos(io, old_scb, &pkb);
1900 if (ret != LDB_SUCCESS) {
1904 ndr_err = ndr_push_struct_blob(
1907 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1908 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1909 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1910 ldb_asprintf_errstring(
1912 "setup_supplemental_field: "
1913 "failed to push package_PrimaryKerberosBlob: %s",
1915 return LDB_ERR_OPERATIONS_ERROR;
1917 pkb_hexstr = data_blob_hex_string_upper(io->ac, &pkb_blob);
1919 return ldb_oom(ldb);
1921 pp->name = "Primary:Kerberos";
1923 pp->data = pkb_hexstr;
1930 * setup 'Primary:WDigest' element
1932 struct package_PrimaryWDigestBlob pdb;
1936 names[num_names++] = "WDigest";
1938 ret = setup_primary_wdigest(io, old_scb, &pdb);
1939 if (ret != LDB_SUCCESS) {
1943 ndr_err = ndr_push_struct_blob(
1946 (ndr_push_flags_fn_t)ndr_push_package_PrimaryWDigestBlob);
1947 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1948 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1949 ldb_asprintf_errstring(
1951 "setup_supplemental_field: "
1952 "failed to push package_PrimaryWDigestBlob: %s",
1954 return LDB_ERR_OPERATIONS_ERROR;
1956 pdb_hexstr = data_blob_hex_string_upper(io->ac, &pdb_blob);
1958 return ldb_oom(ldb);
1960 pp->name = "Primary:WDigest";
1962 pp->data = pdb_hexstr;
1968 * setup 'Primary:CLEARTEXT' element
1970 if (io->ac->status->domain_data.store_cleartext &&
1971 (io->u.userAccountControl & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) {
1972 do_cleartext = true;
1975 struct package_PrimaryCLEARTEXTBlob pcb;
1979 names[num_names++] = "CLEARTEXT";
1981 pcb.cleartext = *io->n.cleartext_utf16;
1983 ndr_err = ndr_push_struct_blob(
1986 (ndr_push_flags_fn_t)ndr_push_package_PrimaryCLEARTEXTBlob);
1987 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1988 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1989 ldb_asprintf_errstring(
1991 "setup_supplemental_field: "
1992 "failed to push package_PrimaryCLEARTEXTBlob: %s",
1994 return LDB_ERR_OPERATIONS_ERROR;
1996 pcb_hexstr = data_blob_hex_string_upper(io->ac, &pcb_blob);
1998 return ldb_oom(ldb);
2000 pp->name = "Primary:CLEARTEXT";
2002 pp->data = pcb_hexstr;
2007 if (io->ac->userPassword_schemes) {
2009 * setup 'Primary:userPassword' element
2011 struct package_PrimaryUserPasswordBlob
2013 DATA_BLOB p_userPassword_b_blob;
2014 char *p_userPassword_b_hexstr;
2016 names[num_names++] = "userPassword";
2018 ret = setup_primary_userPassword(io,
2021 if (ret != LDB_SUCCESS) {
2025 ndr_err = ndr_push_struct_blob(
2026 &p_userPassword_b_blob,
2029 (ndr_push_flags_fn_t)
2030 ndr_push_package_PrimaryUserPasswordBlob);
2031 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2032 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2033 ldb_asprintf_errstring(
2035 "setup_supplemental_field: failed to push "
2036 "package_PrimaryUserPasswordBlob: %s",
2038 return LDB_ERR_OPERATIONS_ERROR;
2040 p_userPassword_b_hexstr
2041 = data_blob_hex_string_upper(
2043 &p_userPassword_b_blob);
2044 if (!p_userPassword_b_hexstr) {
2045 return ldb_oom(ldb);
2047 pp->name = "Primary:userPassword";
2049 pp->data = p_userPassword_b_hexstr;
2055 * setup 'Primary:SambaGPG' element
2057 if (io->ac->gpg_key_ids != NULL) {
2058 do_samba_gpg = true;
2061 struct package_PrimarySambaGPGBlob pgb;
2065 names[num_names++] = "SambaGPG";
2067 ret = setup_primary_samba_gpg(io, &pgb);
2068 if (ret != LDB_SUCCESS) {
2072 ndr_err = ndr_push_struct_blob(&pgb_blob, io->ac, &pgb,
2073 (ndr_push_flags_fn_t)ndr_push_package_PrimarySambaGPGBlob);
2074 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2075 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2076 ldb_asprintf_errstring(ldb,
2077 "setup_supplemental_field: failed to "
2078 "push package_PrimarySambaGPGBlob: %s",
2080 return LDB_ERR_OPERATIONS_ERROR;
2082 pgb_hexstr = data_blob_hex_string_upper(io->ac, &pgb_blob);
2084 return ldb_oom(ldb);
2086 pp->name = "Primary:SambaGPG";
2088 pp->data = pgb_hexstr;
2094 * setup 'Packages' element
2097 struct package_PackagesBlob pb;
2102 ndr_err = ndr_push_struct_blob(
2105 (ndr_push_flags_fn_t)ndr_push_package_PackagesBlob);
2106 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2107 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2108 ldb_asprintf_errstring(
2110 "setup_supplemental_field: "
2111 "failed to push package_PackagesBlob: %s",
2113 return LDB_ERR_OPERATIONS_ERROR;
2115 pb_hexstr = data_blob_hex_string_upper(io->ac, &pb_blob);
2117 return ldb_oom(ldb);
2119 pp->name = "Packages";
2121 pp->data = pb_hexstr;
2124 * We don't increment pp so it's pointing to the last package
2129 * setup 'supplementalCredentials' value
2133 * The 'Packages' element needs to be the second last element
2134 * in supplementalCredentials
2136 struct supplementalCredentialsPackage temp;
2137 struct supplementalCredentialsPackage *prev;
2145 scb.sub.signature = SUPPLEMENTAL_CREDENTIALS_SIGNATURE;
2146 scb.sub.num_packages = num_packages;
2147 scb.sub.packages = packages;
2149 ndr_err = ndr_push_struct_blob(
2150 &io->g.supplemental, io->ac,
2152 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
2153 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2154 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2155 ldb_asprintf_errstring(
2157 "setup_supplemental_field: "
2158 "failed to push supplementalCredentialsBlob: %s",
2160 return LDB_ERR_OPERATIONS_ERROR;
2167 static int setup_last_set_field(struct setup_password_fields_io *io)
2169 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2170 const struct ldb_message *msg = NULL;
2171 struct timeval tv = { .tv_sec = 0 };
2172 const struct ldb_val *old_val = NULL;
2173 const struct ldb_val *new_val = NULL;
2176 switch (io->ac->req->operation) {
2178 msg = io->ac->req->op.add.message;
2181 msg = io->ac->req->op.mod.message;
2184 return LDB_ERR_OPERATIONS_ERROR;
2188 if (io->ac->pwd_last_set_bypass) {
2189 struct ldb_message_element *el1 = NULL;
2190 struct ldb_message_element *el2 = NULL;
2193 return LDB_ERR_CONSTRAINT_VIOLATION;
2196 el1 = dsdb_get_single_valued_attr(msg, "pwdLastSet",
2197 io->ac->req->operation);
2199 return LDB_ERR_CONSTRAINT_VIOLATION;
2201 el2 = ldb_msg_find_element(msg, "pwdLastSet");
2203 return LDB_ERR_CONSTRAINT_VIOLATION;
2206 return LDB_ERR_CONSTRAINT_VIOLATION;
2209 io->g.last_set = samdb_result_nttime(msg, "pwdLastSet", 0);
2213 ret = msg_find_old_and_new_pwd_val(msg, "pwdLastSet",
2214 io->ac->req->operation,
2215 &new_val, &old_val);
2216 if (ret != LDB_SUCCESS) {
2220 if (old_val != NULL && new_val == NULL) {
2221 ldb_set_errstring(ldb,
2222 "'pwdLastSet' deletion is not allowed!");
2223 return LDB_ERR_UNWILLING_TO_PERFORM;
2226 io->g.last_set = UINT64_MAX;
2227 if (new_val != NULL) {
2228 struct ldb_message *tmp_msg = NULL;
2230 tmp_msg = ldb_msg_new(io->ac);
2231 if (tmp_msg == NULL) {
2232 return ldb_module_oom(io->ac->module);
2235 if (old_val != NULL) {
2236 NTTIME old_last_set = 0;
2238 ret = ldb_msg_add_value(tmp_msg, "oldval",
2240 if (ret != LDB_SUCCESS) {
2244 old_last_set = samdb_result_nttime(tmp_msg,
2247 if (io->u.pwdLastSet != old_last_set) {
2248 return dsdb_module_werror(io->ac->module,
2249 LDB_ERR_NO_SUCH_ATTRIBUTE,
2250 WERR_DS_CANT_REM_MISSING_ATT_VAL,
2251 "setup_last_set_field: old pwdLastSet "
2252 "value not found!");
2256 ret = ldb_msg_add_value(tmp_msg, "newval",
2258 if (ret != LDB_SUCCESS) {
2262 io->g.last_set = samdb_result_nttime(tmp_msg,
2265 } else if (ldb_msg_find_element(msg, "pwdLastSet")) {
2266 ldb_set_errstring(ldb,
2267 "'pwdLastSet' deletion is not allowed!");
2268 return LDB_ERR_UNWILLING_TO_PERFORM;
2269 } else if (io->ac->smartcard_reset) {
2271 * adding UF_SMARTCARD_REQUIRED doesn't update
2272 * pwdLastSet implicitly.
2274 io->ac->update_lastset = false;
2277 /* only 0 or -1 (0xFFFFFFFFFFFFFFFF) are allowed */
2278 switch (io->g.last_set) {
2280 if (!io->ac->pwd_last_set_default) {
2283 if (!io->ac->update_password) {
2288 if (!io->ac->update_password &&
2289 io->u.pwdLastSet != 0 &&
2290 io->u.pwdLastSet != UINT64_MAX)
2293 * Just setting pwdLastSet to -1, while not changing
2294 * any password field has no effect if pwdLastSet
2295 * is already non-zero.
2297 io->ac->update_lastset = false;
2300 /* -1 means set it as now */
2302 io->g.last_set = timeval_to_nttime(&tv);
2305 return dsdb_module_werror(io->ac->module,
2307 WERR_INVALID_PARAMETER,
2308 "setup_last_set_field: "
2309 "pwdLastSet must be 0 or -1 only!");
2312 if (io->ac->req->operation == LDB_ADD) {
2314 * We always need to store the value on add
2320 if (io->g.last_set == io->u.pwdLastSet) {
2322 * Just setting pwdLastSet to 0, is no-op if it's already 0.
2324 io->ac->update_lastset = false;
2330 static int setup_given_passwords(struct setup_password_fields_io *io,
2331 struct setup_password_fields_given *g)
2333 struct ldb_context *ldb;
2336 ldb = ldb_module_get_ctx(io->ac->module);
2338 if (g->cleartext_utf8) {
2339 struct ldb_val *cleartext_utf16_blob;
2341 cleartext_utf16_blob = talloc(io->ac, struct ldb_val);
2342 if (!cleartext_utf16_blob) {
2343 return ldb_oom(ldb);
2345 if (!convert_string_talloc(io->ac,
2347 g->cleartext_utf8->data,
2348 g->cleartext_utf8->length,
2349 (void *)&cleartext_utf16_blob->data,
2350 &cleartext_utf16_blob->length)) {
2351 if (g->cleartext_utf8->length != 0) {
2352 talloc_free(cleartext_utf16_blob);
2353 ldb_asprintf_errstring(ldb,
2354 "setup_password_fields: "
2355 "failed to generate UTF16 password from cleartext UTF8 one for user '%s'!",
2356 io->u.sAMAccountName);
2357 return LDB_ERR_CONSTRAINT_VIOLATION;
2359 /* passwords with length "0" are valid! */
2360 cleartext_utf16_blob->data = NULL;
2361 cleartext_utf16_blob->length = 0;
2364 g->cleartext_utf16 = cleartext_utf16_blob;
2365 } else if (g->cleartext_utf16) {
2366 struct ldb_val *cleartext_utf8_blob;
2368 cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
2369 if (!cleartext_utf8_blob) {
2370 return ldb_oom(ldb);
2372 if (!convert_string_talloc(io->ac,
2373 CH_UTF16MUNGED, CH_UTF8,
2374 g->cleartext_utf16->data,
2375 g->cleartext_utf16->length,
2376 (void *)&cleartext_utf8_blob->data,
2377 &cleartext_utf8_blob->length)) {
2378 if (g->cleartext_utf16->length != 0) {
2379 /* We must bail out here, the input wasn't even
2380 * a multiple of 2 bytes */
2381 talloc_free(cleartext_utf8_blob);
2382 ldb_asprintf_errstring(ldb,
2383 "setup_password_fields: "
2384 "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)!",
2385 io->u.sAMAccountName);
2386 return LDB_ERR_CONSTRAINT_VIOLATION;
2388 /* passwords with length "0" are valid! */
2389 cleartext_utf8_blob->data = NULL;
2390 cleartext_utf8_blob->length = 0;
2393 g->cleartext_utf8 = cleartext_utf8_blob;
2396 if (g->cleartext_utf16) {
2397 struct samr_Password *nt_hash;
2399 nt_hash = talloc(io->ac, struct samr_Password);
2401 return ldb_oom(ldb);
2403 g->nt_hash = nt_hash;
2405 /* compute the new nt hash */
2406 mdfour(nt_hash->hash,
2407 g->cleartext_utf16->data,
2408 g->cleartext_utf16->length);
2411 if (g->cleartext_utf8) {
2412 struct samr_Password *lm_hash;
2414 lm_hash = talloc(io->ac, struct samr_Password);
2416 return ldb_oom(ldb);
2419 /* compute the new lm hash */
2420 ok = E_deshash((char *)g->cleartext_utf8->data, lm_hash->hash);
2422 g->lm_hash = lm_hash;
2424 talloc_free(lm_hash);
2431 static int setup_password_fields(struct setup_password_fields_io *io)
2433 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2434 struct loadparm_context *lp_ctx =
2435 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2436 struct loadparm_context);
2439 ret = setup_last_set_field(io);
2440 if (ret != LDB_SUCCESS) {
2444 if (!io->ac->update_password) {
2448 /* transform the old password (for password changes) */
2449 ret = setup_given_passwords(io, &io->og);
2450 if (ret != LDB_SUCCESS) {
2454 /* transform the new password */
2455 ret = setup_given_passwords(io, &io->n);
2456 if (ret != LDB_SUCCESS) {
2460 if (io->n.cleartext_utf8) {
2461 ret = setup_kerberos_keys(io);
2462 if (ret != LDB_SUCCESS) {
2467 ret = setup_nt_fields(io);
2468 if (ret != LDB_SUCCESS) {
2472 if (lpcfg_lanman_auth(lp_ctx)) {
2473 ret = setup_lm_fields(io);
2474 if (ret != LDB_SUCCESS) {
2478 io->g.lm_hash = NULL;
2479 io->g.lm_history_len = 0;
2482 ret = setup_supplemental_field(io);
2483 if (ret != LDB_SUCCESS) {
2490 static int setup_smartcard_reset(struct setup_password_fields_io *io)
2492 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2493 struct loadparm_context *lp_ctx = talloc_get_type(
2494 ldb_get_opaque(ldb, "loadparm"), struct loadparm_context);
2495 struct supplementalCredentialsBlob scb = { .__ndr_size = 0 };
2496 enum ndr_err_code ndr_err;
2498 if (!io->ac->smartcard_reset) {
2502 io->g.nt_hash = talloc(io->ac, struct samr_Password);
2503 if (io->g.nt_hash == NULL) {
2504 return ldb_module_oom(io->ac->module);
2506 generate_secret_buffer(io->g.nt_hash->hash,
2507 sizeof(io->g.nt_hash->hash));
2508 io->g.nt_history_len = 0;
2510 if (lpcfg_lanman_auth(lp_ctx)) {
2511 io->g.lm_hash = talloc(io->ac, struct samr_Password);
2512 if (io->g.lm_hash == NULL) {
2513 return ldb_module_oom(io->ac->module);
2515 generate_secret_buffer(io->g.lm_hash->hash,
2516 sizeof(io->g.lm_hash->hash));
2518 io->g.lm_hash = NULL;
2520 io->g.lm_history_len = 0;
2523 * We take the "old" value and store it
2524 * with num_packages = 0.
2526 * On "add" we have scb.sub.signature == 0, which
2529 * [0000] 00 00 00 00 00 00 00 00 00 00 00 00 00
2531 * On modify it's likely to be scb.sub.signature ==
2532 * SUPPLEMENTAL_CREDENTIALS_SIGNATURE (0x0050), which results in
2535 * [0000] 00 00 00 00 62 00 00 00 00 00 00 00 20 00 20 00
2536 * [0010] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2537 * [0020] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2538 * [0030] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2539 * [0040] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2540 * [0050] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2541 * [0060] 20 00 20 00 20 00 20 00 20 00 20 00 50 00 00
2543 * See https://bugzilla.samba.org/show_bug.cgi?id=11441
2544 * and ndr_{push,pull}_supplementalCredentialsSubBlob().
2547 scb.sub.num_packages = 0;
2550 * setup 'supplementalCredentials' value without packages
2552 ndr_err = ndr_push_struct_blob(&io->g.supplemental, io->ac,
2554 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
2555 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2556 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2557 ldb_asprintf_errstring(ldb,
2558 "setup_smartcard_reset: "
2559 "failed to push supplementalCredentialsBlob: %s",
2561 return LDB_ERR_OPERATIONS_ERROR;
2564 io->ac->update_password = true;
2568 static int make_error_and_update_badPwdCount(struct setup_password_fields_io *io, WERROR *werror)
2570 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2571 struct ldb_message *mod_msg = NULL;
2575 status = dsdb_update_bad_pwd_count(io->ac, ldb,
2576 io->ac->search_res->message,
2577 io->ac->dom_res->message,
2579 if (!NT_STATUS_IS_OK(status)) {
2583 if (mod_msg == NULL) {
2588 * OK, horrible semantics ahead.
2590 * - We need to abort any existing transaction
2591 * - create a transaction arround the badPwdCount update
2592 * - re-open the transaction so the upper layer
2593 * doesn't know what happened.
2595 * This is needed because returning an error to the upper
2596 * layer will cancel the transaction and undo the badPwdCount
2601 * Checking errors here is a bit pointless.
2602 * What can we do if we can't end the transaction?
2604 ret = ldb_next_del_trans(io->ac->module);
2605 if (ret != LDB_SUCCESS) {
2606 ldb_debug(ldb, LDB_DEBUG_FATAL,
2607 "Failed to abort transaction prior to update of badPwdCount of %s: %s",
2608 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2609 ldb_errstring(ldb));
2611 * just return the original error
2616 /* Likewise, what should we do if we can't open a new transaction? */
2617 ret = ldb_next_start_trans(io->ac->module);
2618 if (ret != LDB_SUCCESS) {
2619 ldb_debug(ldb, LDB_DEBUG_ERROR,
2620 "Failed to open transaction to update badPwdCount of %s: %s",
2621 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2622 ldb_errstring(ldb));
2624 * just return the original error
2629 ret = dsdb_module_modify(io->ac->module, mod_msg,
2630 DSDB_FLAG_NEXT_MODULE,
2632 if (ret != LDB_SUCCESS) {
2633 ldb_debug(ldb, LDB_DEBUG_ERROR,
2634 "Failed to update badPwdCount of %s: %s",
2635 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2636 ldb_errstring(ldb));
2638 * We can only ignore this...
2642 ret = ldb_next_end_trans(io->ac->module);
2643 if (ret != LDB_SUCCESS) {
2644 ldb_debug(ldb, LDB_DEBUG_ERROR,
2645 "Failed to close transaction to update badPwdCount of %s: %s",
2646 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2647 ldb_errstring(ldb));
2649 * We can only ignore this...
2653 ret = ldb_next_start_trans(io->ac->module);
2654 if (ret != LDB_SUCCESS) {
2655 ldb_debug(ldb, LDB_DEBUG_ERROR,
2656 "Failed to open transaction after update of badPwdCount of %s: %s",
2657 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2658 ldb_errstring(ldb));
2660 * We can only ignore this...
2665 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2666 *werror = WERR_INVALID_PASSWORD;
2667 ldb_asprintf_errstring(ldb,
2668 "%08X: %s - check_password_restrictions: "
2669 "The old password specified doesn't match!",
2675 static int check_password_restrictions(struct setup_password_fields_io *io, WERROR *werror)
2677 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2679 struct loadparm_context *lp_ctx =
2680 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2681 struct loadparm_context);
2683 *werror = WERR_INVALID_PARAMETER;
2685 if (!io->ac->update_password) {
2689 /* First check the old password is correct, for password changes */
2690 if (!io->ac->pwd_reset) {
2691 bool nt_hash_checked = false;
2693 /* we need the old nt or lm hash given by the client */
2694 if (!io->og.nt_hash && !io->og.lm_hash) {
2695 ldb_asprintf_errstring(ldb,
2696 "check_password_restrictions: "
2697 "You need to provide the old password in order "
2699 return LDB_ERR_UNWILLING_TO_PERFORM;
2702 /* The password modify through the NT hash is encouraged and
2703 has no problems at all */
2704 if (io->og.nt_hash) {
2705 if (!io->o.nt_hash || memcmp(io->og.nt_hash->hash, io->o.nt_hash->hash, 16) != 0) {
2706 return make_error_and_update_badPwdCount(io, werror);
2709 nt_hash_checked = true;
2712 /* But it is also possible to change a password by the LM hash
2713 * alone for compatibility reasons. This check is optional if
2714 * the NT hash was already checked - otherwise it's mandatory.
2715 * (as the SAMR operations request it). */
2716 if (io->og.lm_hash) {
2717 if ((!io->o.lm_hash && !nt_hash_checked)
2718 || (io->o.lm_hash && memcmp(io->og.lm_hash->hash, io->o.lm_hash->hash, 16) != 0)) {
2719 return make_error_and_update_badPwdCount(io, werror);
2724 if (io->u.restrictions == 0) {
2725 /* FIXME: Is this right? */
2729 /* Password minimum age: yes, this is a minus. The ages are in negative 100nsec units! */
2730 if ((io->u.pwdLastSet - io->ac->status->domain_data.minPwdAge > io->g.last_set) &&
2733 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2734 *werror = WERR_PASSWORD_RESTRICTION;
2735 ldb_asprintf_errstring(ldb,
2736 "%08X: %s - check_password_restrictions: "
2737 "password is too young to change!",
2744 * Fundamental password checks done by the call
2745 * "samdb_check_password".
2746 * It is also in use by "dcesrv_samr_ValidatePassword".
2748 if (io->n.cleartext_utf8 != NULL) {
2749 enum samr_ValidationStatus vstat;
2750 vstat = samdb_check_password(io->ac, lp_ctx,
2751 io->n.cleartext_utf8,
2752 io->ac->status->domain_data.pwdProperties,
2753 io->ac->status->domain_data.minPwdLength);
2755 case SAMR_VALIDATION_STATUS_SUCCESS:
2756 /* perfect -> proceed! */
2759 case SAMR_VALIDATION_STATUS_PWD_TOO_SHORT:
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 is too short. It should be equal or longer than %u characters!",
2767 io->ac->status->domain_data.minPwdLength);
2768 io->ac->status->reject_reason = SAM_PWD_CHANGE_PASSWORD_TOO_SHORT;
2771 case SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH:
2772 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2773 *werror = WERR_PASSWORD_RESTRICTION;
2774 ldb_asprintf_errstring(ldb,
2775 "%08X: %s - check_password_restrictions: "
2776 "the password does not meet the complexity criteria!",
2779 io->ac->status->reject_reason = SAM_PWD_CHANGE_NOT_COMPLEX;
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 doesn't fit due to a miscellaneous restriction!",
2794 if (io->ac->pwd_reset) {
2799 if (io->n.nt_hash) {
2802 /* checks the NT hash password history */
2803 for (i = 0; i < io->o.nt_history_len; i++) {
2804 ret = memcmp(io->n.nt_hash, io->o.nt_history[i].hash, 16);
2806 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2807 *werror = WERR_PASSWORD_RESTRICTION;
2808 ldb_asprintf_errstring(ldb,
2809 "%08X: %s - check_password_restrictions: "
2810 "the password was already used (in history)!",
2813 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
2819 if (io->n.lm_hash) {
2822 /* checks the LM hash password history */
2823 for (i = 0; i < io->o.lm_history_len; i++) {
2824 ret = memcmp(io->n.lm_hash, io->o.lm_history[i].hash, 16);
2826 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2827 *werror = WERR_PASSWORD_RESTRICTION;
2828 ldb_asprintf_errstring(ldb,
2829 "%08X: %s - check_password_restrictions: "
2830 "the password was already used (in history)!",
2833 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
2839 /* are all password changes disallowed? */
2840 if (io->ac->status->domain_data.pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
2841 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2842 *werror = WERR_PASSWORD_RESTRICTION;
2843 ldb_asprintf_errstring(ldb,
2844 "%08X: %s - check_password_restrictions: "
2845 "password changes disabled!",
2851 /* can this user change the password? */
2852 if (io->u.userAccountControl & UF_PASSWD_CANT_CHANGE) {
2853 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2854 *werror = WERR_PASSWORD_RESTRICTION;
2855 ldb_asprintf_errstring(ldb,
2856 "%08X: %s - check_password_restrictions: "
2857 "password can't be changed on this account!",
2866 static int check_password_restrictions_and_log(struct setup_password_fields_io *io)
2869 int ret = check_password_restrictions(io, &werror);
2870 struct ph_context *ac = io->ac;
2872 * Password resets are not authentication events, and if the
2873 * upper layer checked the password and supplied the hash
2874 * values as proof, then this is also not an authentication
2875 * even at this layer (already logged). This is to log LDAP
2879 /* Do not record a failure in the auth log below in the success case */
2880 if (ret == LDB_SUCCESS) {
2884 if (ac->pwd_reset == false && ac->change == NULL) {
2885 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2886 struct imessaging_context *msg_ctx;
2887 struct loadparm_context *lp_ctx
2888 = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"),
2889 struct loadparm_context);
2890 NTSTATUS status = werror_to_ntstatus(werror);
2891 const char *domain_name = lpcfg_sam_name(lp_ctx);
2892 void *opaque_remote_address = NULL;
2894 * Forcing this via the NTLM auth structure is not ideal, but
2895 * it is the most practical option right now, and ensures the
2896 * logs are consistent, even if some elements are always NULL.
2898 struct auth_usersupplied_info ui = {
2899 .mapped_state = true,
2902 .account_name = io->u.sAMAccountName,
2903 .domain_name = domain_name,
2906 .account_name = io->u.sAMAccountName,
2907 .domain_name = domain_name,
2909 .service_description = "LDAP Password Change",
2910 .auth_description = "LDAP Modify",
2911 .password_type = "plaintext"
2914 opaque_remote_address = ldb_get_opaque(ldb,
2916 if (opaque_remote_address == NULL) {
2917 ldb_asprintf_errstring(ldb,
2918 "Failed to obtain remote address for "
2919 "the LDAP client while changing the "
2921 return LDB_ERR_OPERATIONS_ERROR;
2923 ui.remote_host = talloc_get_type(opaque_remote_address,
2924 struct tsocket_address);
2926 msg_ctx = imessaging_client_init(ac, lp_ctx,
2927 ldb_get_event_context(ldb));
2929 ldb_asprintf_errstring(ldb,
2930 "Failed to generate client messaging context in %s",
2931 lpcfg_imessaging_path(ac, lp_ctx));
2932 return LDB_ERR_OPERATIONS_ERROR;
2934 log_authentication_event(msg_ctx,
2939 io->u.sAMAccountName,
2947 static int update_final_msg(struct setup_password_fields_io *io)
2949 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2952 bool update_password = io->ac->update_password;
2953 bool update_scb = io->ac->update_password;
2956 * If we add a user without initial password,
2957 * we need to add replication meta data for
2958 * following attributes:
2964 * If we add a user with initial password or a
2965 * password is changed of an existing user,
2966 * we need to replace the following attributes
2967 * with a forced meta data update, e.g. also
2968 * when updating an empty attribute with an empty value:
2973 * - supplementalCredentials
2976 switch (io->ac->req->operation) {
2978 update_password = true;
2979 el_flags |= DSDB_FLAG_INTERNAL_FORCE_META_DATA;
2982 el_flags |= LDB_FLAG_MOD_REPLACE;
2983 el_flags |= DSDB_FLAG_INTERNAL_FORCE_META_DATA;
2986 return ldb_module_operr(io->ac->module);
2989 if (update_password) {
2990 ret = ldb_msg_add_empty(io->ac->update_msg,
2993 if (ret != LDB_SUCCESS) {
2996 ret = ldb_msg_add_empty(io->ac->update_msg,
2999 if (ret != LDB_SUCCESS) {
3002 ret = ldb_msg_add_empty(io->ac->update_msg,
3005 if (ret != LDB_SUCCESS) {
3008 ret = ldb_msg_add_empty(io->ac->update_msg,
3011 if (ret != LDB_SUCCESS) {
3016 ret = ldb_msg_add_empty(io->ac->update_msg,
3017 "supplementalCredentials",
3019 if (ret != LDB_SUCCESS) {
3023 if (io->ac->update_lastset) {
3024 ret = ldb_msg_add_empty(io->ac->update_msg,
3027 if (ret != LDB_SUCCESS) {
3032 if (io->g.nt_hash != NULL) {
3033 ret = samdb_msg_add_hash(ldb, io->ac,
3037 if (ret != LDB_SUCCESS) {
3041 if (io->g.lm_hash != NULL) {
3042 ret = samdb_msg_add_hash(ldb, io->ac,
3046 if (ret != LDB_SUCCESS) {
3050 if (io->g.nt_history_len > 0) {
3051 ret = samdb_msg_add_hashes(ldb, io->ac,
3055 io->g.nt_history_len);
3056 if (ret != LDB_SUCCESS) {
3060 if (io->g.lm_history_len > 0) {
3061 ret = samdb_msg_add_hashes(ldb, io->ac,
3065 io->g.lm_history_len);
3066 if (ret != LDB_SUCCESS) {
3070 if (io->g.supplemental.length > 0) {
3071 ret = ldb_msg_add_value(io->ac->update_msg,
3072 "supplementalCredentials",
3073 &io->g.supplemental, NULL);
3074 if (ret != LDB_SUCCESS) {
3078 if (io->ac->update_lastset) {
3079 ret = samdb_msg_add_uint64(ldb, io->ac,
3083 if (ret != LDB_SUCCESS) {
3092 * This is intended for use by the "password_hash" module since there
3093 * password changes can be specified through one message element with the
3094 * new password (to set) and another one with the old password (to unset).
3096 * The first which sets a password (new value) can have flags
3097 * (LDB_FLAG_MOD_ADD, LDB_FLAG_MOD_REPLACE) but also none (on "add" operations
3098 * for entries). The latter (old value) has always specified
3099 * LDB_FLAG_MOD_DELETE.
3101 * Returns LDB_ERR_CONSTRAINT_VIOLATION and LDB_ERR_UNWILLING_TO_PERFORM if
3102 * matching message elements are malformed in respect to the set/change rules.
3103 * Otherwise it returns LDB_SUCCESS.
3105 static int msg_find_old_and_new_pwd_val(const struct ldb_message *msg,
3107 enum ldb_request_type operation,
3108 const struct ldb_val **new_val,
3109 const struct ldb_val **old_val)
3120 for (i = 0; i < msg->num_elements; i++) {
3121 if (ldb_attr_cmp(msg->elements[i].name, name) != 0) {
3125 if ((operation == LDB_MODIFY) &&
3126 (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_DELETE)) {
3127 /* 0 values are allowed */
3128 if (msg->elements[i].num_values == 1) {
3129 *old_val = &msg->elements[i].values[0];
3130 } else if (msg->elements[i].num_values > 1) {
3131 return LDB_ERR_CONSTRAINT_VIOLATION;
3133 } else if ((operation == LDB_MODIFY) &&
3134 (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_REPLACE)) {
3135 if (msg->elements[i].num_values > 0) {
3136 *new_val = &msg->elements[i].values[msg->elements[i].num_values - 1];
3138 return LDB_ERR_UNWILLING_TO_PERFORM;
3141 /* Add operations and LDB_FLAG_MOD_ADD */
3142 if (msg->elements[i].num_values > 0) {
3143 *new_val = &msg->elements[i].values[msg->elements[i].num_values - 1];
3145 return LDB_ERR_CONSTRAINT_VIOLATION;
3153 static int setup_io(struct ph_context *ac,
3154 const struct ldb_message *client_msg,
3155 const struct ldb_message *existing_msg,
3156 struct setup_password_fields_io *io)
3158 const struct ldb_val *quoted_utf16, *old_quoted_utf16, *lm_hash, *old_lm_hash;
3159 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3160 struct loadparm_context *lp_ctx = talloc_get_type(
3161 ldb_get_opaque(ldb, "loadparm"), struct loadparm_context);
3163 const struct ldb_message *info_msg = NULL;
3164 struct dom_sid *account_sid = NULL;
3165 int rodc_krbtgt = 0;
3169 /* Some operations below require kerberos contexts */
3171 if (existing_msg != NULL) {
3173 * This is a modify operation
3175 info_msg = existing_msg;
3178 * This is an add operation
3180 info_msg = client_msg;
3183 if (smb_krb5_init_context(ac,
3184 (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"),
3185 &io->smb_krb5_context) != 0) {
3186 return ldb_operr(ldb);
3191 io->u.userAccountControl = ldb_msg_find_attr_as_uint(info_msg,
3192 "userAccountControl", 0);
3193 if (info_msg == existing_msg) {
3195 * We only take pwdLastSet from the existing object
3196 * otherwise we leave it as 0.
3198 * If no attribute is available, e.g. on deleted objects
3199 * we remember that as UINT64_MAX.
3201 io->u.pwdLastSet = samdb_result_nttime(info_msg, "pwdLastSet",
3204 io->u.sAMAccountName = ldb_msg_find_attr_as_string(info_msg,
3205 "sAMAccountName", NULL);
3206 io->u.user_principal_name = ldb_msg_find_attr_as_string(info_msg,
3207 "userPrincipalName", NULL);
3208 io->u.is_computer = ldb_msg_check_string_attribute(info_msg, "objectClass", "computer");
3210 /* Ensure it has an objectSID too */
3211 io->u.account_sid = samdb_result_dom_sid(ac, info_msg, "objectSid");
3212 if (io->u.account_sid != NULL) {
3216 status = dom_sid_split_rid(account_sid, io->u.account_sid, NULL, &rid);
3217 if (NT_STATUS_IS_OK(status)) {
3218 if (rid == DOMAIN_RID_KRBTGT) {
3219 io->u.is_krbtgt = true;
3224 rodc_krbtgt = ldb_msg_find_attr_as_int(info_msg,
3225 "msDS-SecondaryKrbTgtNumber", 0);
3226 if (rodc_krbtgt != 0) {
3227 io->u.is_krbtgt = true;
3230 if (io->u.sAMAccountName == NULL) {
3231 ldb_asprintf_errstring(ldb,
3232 "setup_io: sAMAccountName attribute is missing on %s for attempted password set/change",
3233 ldb_dn_get_linearized(info_msg->dn));
3235 return LDB_ERR_CONSTRAINT_VIOLATION;
3238 if (io->u.userAccountControl & UF_INTERDOMAIN_TRUST_ACCOUNT) {
3239 struct ldb_control *permit_trust = ldb_request_get_control(ac->req,
3240 DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID);
3242 if (permit_trust == NULL) {
3243 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
3244 ldb_asprintf_errstring(ldb,
3245 "%08X: %s - setup_io: changing the interdomain trust password "
3246 "on %s not allowed via LDAP. Use LSA or NETLOGON",
3247 W_ERROR_V(WERR_ACCESS_DENIED),
3249 ldb_dn_get_linearized(info_msg->dn));
3254 /* Only non-trust accounts have restrictions (possibly this test is the
3255 * wrong way around, but we like to be restrictive if possible */
3256 io->u.restrictions = !(io->u.userAccountControl
3257 & (UF_INTERDOMAIN_TRUST_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT
3258 | UF_SERVER_TRUST_ACCOUNT));
3260 if (io->u.is_krbtgt) {
3261 io->u.restrictions = 0;
3262 io->ac->status->domain_data.pwdHistoryLength =
3263 MAX(io->ac->status->domain_data.pwdHistoryLength, 3);
3266 if (ac->userPassword) {
3267 ret = msg_find_old_and_new_pwd_val(client_msg, "userPassword",
3269 &io->n.cleartext_utf8,
3270 &io->og.cleartext_utf8);
3271 if (ret != LDB_SUCCESS) {
3272 ldb_asprintf_errstring(ldb,
3274 "it's only allowed to set the old password once!");
3279 if (io->n.cleartext_utf8 != NULL) {
3280 struct ldb_val *cleartext_utf8_blob;
3283 cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
3284 if (!cleartext_utf8_blob) {
3285 return ldb_oom(ldb);
3288 *cleartext_utf8_blob = *io->n.cleartext_utf8;
3290 /* make sure we have a null terminated string */
3291 p = talloc_strndup(cleartext_utf8_blob,
3292 (const char *)io->n.cleartext_utf8->data,
3293 io->n.cleartext_utf8->length);
3294 if ((p == NULL) && (io->n.cleartext_utf8->length > 0)) {
3295 return ldb_oom(ldb);
3297 cleartext_utf8_blob->data = (uint8_t *)p;
3299 io->n.cleartext_utf8 = cleartext_utf8_blob;
3302 ret = msg_find_old_and_new_pwd_val(client_msg, "clearTextPassword",
3304 &io->n.cleartext_utf16,
3305 &io->og.cleartext_utf16);
3306 if (ret != LDB_SUCCESS) {
3307 ldb_asprintf_errstring(ldb,
3309 "it's only allowed to set the old password once!");
3313 /* this rather strange looking piece of code is there to
3314 handle a ldap client setting a password remotely using the
3315 unicodePwd ldap field. The syntax is that the password is
3316 in UTF-16LE, with a " at either end. Unfortunately the
3317 unicodePwd field is also used to store the nt hashes
3318 internally in Samba, and is used in the nt hash format on
3319 the wire in DRS replication, so we have a single name for
3320 two distinct values. The code below leaves us with a small
3321 chance (less than 1 in 2^32) of a mixup, if someone manages
3322 to create a MD4 hash which starts and ends in 0x22 0x00, as
3323 that would then be treated as a UTF16 password rather than
3326 ret = msg_find_old_and_new_pwd_val(client_msg, "unicodePwd",
3330 if (ret != LDB_SUCCESS) {
3331 ldb_asprintf_errstring(ldb,
3333 "it's only allowed to set the old password once!");
3337 /* Checks and converts the actual "unicodePwd" attribute */
3338 if (!ac->hash_values &&
3340 quoted_utf16->length >= 4 &&
3341 quoted_utf16->data[0] == '"' &&
3342 quoted_utf16->data[1] == 0 &&
3343 quoted_utf16->data[quoted_utf16->length-2] == '"' &&
3344 quoted_utf16->data[quoted_utf16->length-1] == 0) {
3345 struct ldb_val *quoted_utf16_2;
3347 if (io->n.cleartext_utf16) {
3348 /* refuse the change if someone wants to change with
3349 with both UTF16 possibilities at the same time... */
3350 ldb_asprintf_errstring(ldb,
3352 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
3353 return LDB_ERR_UNWILLING_TO_PERFORM;
3357 * adapt the quoted UTF16 string to be a real
3360 quoted_utf16_2 = talloc(io->ac, struct ldb_val);
3361 if (quoted_utf16_2 == NULL) {
3362 return ldb_oom(ldb);
3365 quoted_utf16_2->data = quoted_utf16->data + 2;
3366 quoted_utf16_2->length = quoted_utf16->length-4;
3367 io->n.cleartext_utf16 = quoted_utf16_2;
3368 io->n.nt_hash = NULL;
3370 } else if (quoted_utf16) {
3371 /* We have only the hash available -> so no plaintext here */
3372 if (!ac->hash_values) {
3373 /* refuse the change if someone wants to change
3374 the hash without control specified... */
3375 ldb_asprintf_errstring(ldb,
3377 "it's not allowed to set the NT hash password directly'");
3378 /* this looks odd but this is what Windows does:
3379 returns "UNWILLING_TO_PERFORM" on wrong
3380 password sets and "CONSTRAINT_VIOLATION" on
3381 wrong password changes. */
3382 if (old_quoted_utf16 == NULL) {
3383 return LDB_ERR_UNWILLING_TO_PERFORM;
3386 return LDB_ERR_CONSTRAINT_VIOLATION;
3389 io->n.nt_hash = talloc(io->ac, struct samr_Password);
3390 memcpy(io->n.nt_hash->hash, quoted_utf16->data,
3391 MIN(quoted_utf16->length, sizeof(io->n.nt_hash->hash)));
3394 /* Checks and converts the previous "unicodePwd" attribute */
3395 if (!ac->hash_values &&
3397 old_quoted_utf16->length >= 4 &&
3398 old_quoted_utf16->data[0] == '"' &&
3399 old_quoted_utf16->data[1] == 0 &&
3400 old_quoted_utf16->data[old_quoted_utf16->length-2] == '"' &&
3401 old_quoted_utf16->data[old_quoted_utf16->length-1] == 0) {
3402 struct ldb_val *old_quoted_utf16_2;
3404 if (io->og.cleartext_utf16) {
3405 /* refuse the change if someone wants to change with
3406 both UTF16 possibilities at the same time... */
3407 ldb_asprintf_errstring(ldb,
3409 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
3410 return LDB_ERR_UNWILLING_TO_PERFORM;
3414 * adapt the quoted UTF16 string to be a real
3417 old_quoted_utf16_2 = talloc(io->ac, struct ldb_val);
3418 if (old_quoted_utf16_2 == NULL) {
3419 return ldb_oom(ldb);
3422 old_quoted_utf16_2->data = old_quoted_utf16->data + 2;
3423 old_quoted_utf16_2->length = old_quoted_utf16->length-4;
3425 io->og.cleartext_utf16 = old_quoted_utf16_2;
3426 io->og.nt_hash = NULL;
3427 } else if (old_quoted_utf16) {
3428 /* We have only the hash available -> so no plaintext here */
3429 if (!ac->hash_values) {
3430 /* refuse the change if someone wants to change
3431 the hash without control specified... */
3432 ldb_asprintf_errstring(ldb,
3434 "it's not allowed to set the NT hash password directly'");
3435 return LDB_ERR_UNWILLING_TO_PERFORM;
3438 io->og.nt_hash = talloc(io->ac, struct samr_Password);
3439 memcpy(io->og.nt_hash->hash, old_quoted_utf16->data,
3440 MIN(old_quoted_utf16->length, sizeof(io->og.nt_hash->hash)));
3443 /* Handles the "dBCSPwd" attribute (LM hash) */
3444 io->n.lm_hash = NULL; io->og.lm_hash = NULL;
3445 ret = msg_find_old_and_new_pwd_val(client_msg, "dBCSPwd",
3447 &lm_hash, &old_lm_hash);
3448 if (ret != LDB_SUCCESS) {
3449 ldb_asprintf_errstring(ldb,
3451 "it's only allowed to set the old password once!");
3455 if (((lm_hash != NULL) || (old_lm_hash != NULL)) && (!ac->hash_values)) {
3456 /* refuse the change if someone wants to change the hash
3457 without control specified... */
3458 ldb_asprintf_errstring(ldb,
3460 "it's not allowed to set the LM hash password directly'");
3461 return LDB_ERR_UNWILLING_TO_PERFORM;
3464 if (lpcfg_lanman_auth(lp_ctx) && (lm_hash != NULL)) {
3465 io->n.lm_hash = talloc(io->ac, struct samr_Password);
3466 memcpy(io->n.lm_hash->hash, lm_hash->data, MIN(lm_hash->length,
3467 sizeof(io->n.lm_hash->hash)));
3469 if (lpcfg_lanman_auth(lp_ctx) && (old_lm_hash != NULL)) {
3470 io->og.lm_hash = talloc(io->ac, struct samr_Password);
3471 memcpy(io->og.lm_hash->hash, old_lm_hash->data, MIN(old_lm_hash->length,
3472 sizeof(io->og.lm_hash->hash)));
3476 * Handles the password change control if it's specified. It has the
3477 * precedance and overrides already specified old password values of
3478 * change requests (but that shouldn't happen since the control is
3479 * fully internal and only used in conjunction with replace requests!).
3481 if (ac->change != NULL) {
3482 io->og.nt_hash = NULL;
3483 if (ac->change->old_nt_pwd_hash != NULL) {
3484 io->og.nt_hash = talloc_memdup(io->ac,
3485 ac->change->old_nt_pwd_hash,
3486 sizeof(struct samr_Password));
3488 io->og.lm_hash = NULL;
3489 if (lpcfg_lanman_auth(lp_ctx) && (ac->change->old_lm_pwd_hash != NULL)) {
3490 io->og.lm_hash = talloc_memdup(io->ac,
3491 ac->change->old_lm_pwd_hash,
3492 sizeof(struct samr_Password));
3496 /* refuse the change if someone wants to change the clear-
3497 text and supply his own hashes at the same time... */
3498 if ((io->n.cleartext_utf8 || io->n.cleartext_utf16)
3499 && (io->n.nt_hash || io->n.lm_hash)) {
3500 ldb_asprintf_errstring(ldb,
3502 "it's only allowed to set the password in form of cleartext attributes or as hashes");
3503 return LDB_ERR_UNWILLING_TO_PERFORM;
3506 /* refuse the change if someone wants to change the password
3507 using both plaintext methods (UTF8 and UTF16) at the same time... */
3508 if (io->n.cleartext_utf8 && io->n.cleartext_utf16) {
3509 ldb_asprintf_errstring(ldb,
3511 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
3512 return LDB_ERR_UNWILLING_TO_PERFORM;
3515 /* refuse the change if someone tries to set/change the password by
3516 * the lanman hash alone and we've deactivated that mechanism. This
3517 * would end in an account without any password! */
3518 if (io->ac->update_password
3519 && (!io->n.cleartext_utf8) && (!io->n.cleartext_utf16)
3520 && (!io->n.nt_hash) && (!io->n.lm_hash)) {
3521 ldb_asprintf_errstring(ldb,
3523 "It's not possible to delete the password (changes using the LAN Manager hash alone could be deactivated)!");
3524 /* on "userPassword" and "clearTextPassword" we've to return
3525 * something different, since these are virtual attributes */
3526 if ((ldb_msg_find_element(client_msg, "userPassword") != NULL) ||
3527 (ldb_msg_find_element(client_msg, "clearTextPassword") != NULL)) {
3528 return LDB_ERR_CONSTRAINT_VIOLATION;
3530 return LDB_ERR_UNWILLING_TO_PERFORM;
3533 /* refuse the change if someone wants to compare against a plaintext
3534 or hash at the same time for a "password modify" operation... */
3535 if ((io->og.cleartext_utf8 || io->og.cleartext_utf16)
3536 && (io->og.nt_hash || io->og.lm_hash)) {
3537 ldb_asprintf_errstring(ldb,
3539 "it's only allowed to provide the old password in form of cleartext attributes or as hashes");
3540 return LDB_ERR_UNWILLING_TO_PERFORM;
3543 /* refuse the change if someone wants to compare against both
3544 * plaintexts at the same time for a "password modify" operation... */
3545 if (io->og.cleartext_utf8 && io->og.cleartext_utf16) {
3546 ldb_asprintf_errstring(ldb,
3548 "it's only allowed to provide the old cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
3549 return LDB_ERR_UNWILLING_TO_PERFORM;
3552 /* Decides if we have a password modify or password reset operation */
3553 if (ac->req->operation == LDB_ADD) {
3554 /* On "add" we have only "password reset" */
3555 ac->pwd_reset = true;
3556 } else if (ac->req->operation == LDB_MODIFY) {
3557 if (io->og.cleartext_utf8 || io->og.cleartext_utf16
3558 || io->og.nt_hash || io->og.lm_hash) {
3559 /* If we have an old password specified then for sure it
3560 * is a user "password change" */
3561 ac->pwd_reset = false;
3563 /* Otherwise we have also here a "password reset" */
3564 ac->pwd_reset = true;
3567 /* this shouldn't happen */
3568 return ldb_operr(ldb);
3571 if (io->u.is_krbtgt) {
3574 size_t diff = max - min;
3576 struct ldb_val *krbtgt_utf16 = NULL;
3578 if (!ac->pwd_reset) {
3579 return dsdb_module_werror(ac->module,
3580 LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS,
3581 WERR_DS_ATT_ALREADY_EXISTS,
3582 "Password change on krbtgt not permitted!");
3585 if (io->n.cleartext_utf16 == NULL) {
3586 return dsdb_module_werror(ac->module,
3587 LDB_ERR_UNWILLING_TO_PERFORM,
3588 WERR_DS_INVALID_ATTRIBUTE_SYNTAX,
3589 "Password reset on krbtgt requires UTF16!");
3593 * Instead of taking the callers value,
3594 * we just generate a new random value here.
3596 * Include null termination in the array.
3601 generate_random_buffer((uint8_t *)&tmp, sizeof(tmp));
3608 krbtgt_utf16 = talloc_zero(io->ac, struct ldb_val);
3609 if (krbtgt_utf16 == NULL) {
3610 return ldb_oom(ldb);
3613 *krbtgt_utf16 = data_blob_talloc_zero(krbtgt_utf16,
3615 if (krbtgt_utf16->data == NULL) {
3616 return ldb_oom(ldb);
3618 krbtgt_utf16->length = len * 2;
3619 generate_secret_buffer(krbtgt_utf16->data,
3620 krbtgt_utf16->length);
3621 io->n.cleartext_utf16 = krbtgt_utf16;
3624 if (existing_msg != NULL) {
3627 if (ac->pwd_reset) {
3628 /* Get the old password from the database */
3629 status = samdb_result_passwords_no_lockout(ac,
3635 /* Get the old password from the database */
3636 status = samdb_result_passwords(ac,
3643 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCOUNT_LOCKED_OUT)) {
3644 return dsdb_module_werror(ac->module,
3645 LDB_ERR_CONSTRAINT_VIOLATION,
3646 WERR_ACCOUNT_LOCKED_OUT,
3647 "Password change not permitted,"
3648 " account locked out!");
3651 if (!NT_STATUS_IS_OK(status)) {
3653 * This only happens if the database has gone weird,
3654 * not if we are just missing the passwords
3656 return ldb_operr(ldb);
3659 io->o.nt_history_len = samdb_result_hashes(ac, existing_msg,
3662 io->o.lm_history_len = samdb_result_hashes(ac, existing_msg,
3665 io->o.supplemental = ldb_msg_find_ldb_val(existing_msg,
3666 "supplementalCredentials");
3668 if (io->o.supplemental != NULL) {
3669 enum ndr_err_code ndr_err;
3671 ndr_err = ndr_pull_struct_blob_all(io->o.supplemental, io->ac,
3673 (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
3674 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3675 status = ndr_map_error2ntstatus(ndr_err);
3676 ldb_asprintf_errstring(ldb,
3677 "setup_io: failed to pull "
3678 "old supplementalCredentialsBlob: %s",
3680 return LDB_ERR_OPERATIONS_ERROR;
3688 static struct ph_context *ph_init_context(struct ldb_module *module,
3689 struct ldb_request *req,
3691 bool update_password)
3693 struct ldb_context *ldb;
3694 struct ph_context *ac;
3695 struct loadparm_context *lp_ctx = NULL;
3697 ldb = ldb_module_get_ctx(module);
3699 ac = talloc_zero(req, struct ph_context);
3701 ldb_set_errstring(ldb, "Out of Memory");
3705 ac->module = module;
3707 ac->userPassword = userPassword;
3708 ac->update_password = update_password;
3709 ac->update_lastset = true;
3711 lp_ctx = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"),
3712 struct loadparm_context);
3713 ac->gpg_key_ids = lpcfg_password_hash_gpg_key_ids(lp_ctx);
3714 ac->userPassword_schemes
3715 = lpcfg_password_hash_userpassword_schemes(lp_ctx);
3719 static void ph_apply_controls(struct ph_context *ac)
3721 struct ldb_control *ctrl;
3723 ac->change_status = false;
3724 ctrl = ldb_request_get_control(ac->req,
3725 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID);
3727 ac->change_status = true;
3729 /* Mark the "change status" control as uncritical (done) */
3730 ctrl->critical = false;
3733 ac->hash_values = false;
3734 ctrl = ldb_request_get_control(ac->req,
3735 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID);
3737 ac->hash_values = true;
3739 /* Mark the "hash values" control as uncritical (done) */
3740 ctrl->critical = false;
3743 ctrl = ldb_request_get_control(ac->req,
3744 DSDB_CONTROL_PASSWORD_CHANGE_OID);
3746 ac->change = (struct dsdb_control_password_change *) ctrl->data;
3748 /* Mark the "change" control as uncritical (done) */
3749 ctrl->critical = false;
3752 ac->pwd_last_set_bypass = false;
3753 ctrl = ldb_request_get_control(ac->req,
3754 DSDB_CONTROL_PASSWORD_BYPASS_LAST_SET_OID);
3756 ac->pwd_last_set_bypass = true;
3758 /* Mark the "bypass pwdLastSet" control as uncritical (done) */
3759 ctrl->critical = false;
3762 ac->pwd_last_set_default = false;
3763 ctrl = ldb_request_get_control(ac->req,
3764 DSDB_CONTROL_PASSWORD_DEFAULT_LAST_SET_OID);
3766 ac->pwd_last_set_default = true;
3768 /* Mark the "bypass pwdLastSet" control as uncritical (done) */
3769 ctrl->critical = false;
3772 ac->smartcard_reset = false;
3773 ctrl = ldb_request_get_control(ac->req,
3774 DSDB_CONTROL_PASSWORD_USER_ACCOUNT_CONTROL_OID);
3776 struct dsdb_control_password_user_account_control *uac = NULL;
3777 uint32_t added_flags = 0;
3779 uac = talloc_get_type_abort(ctrl->data,
3780 struct dsdb_control_password_user_account_control);
3782 added_flags = uac->new_flags & ~uac->old_flags;
3784 if (added_flags & UF_SMARTCARD_REQUIRED) {
3785 ac->smartcard_reset = true;
3788 /* Mark the "smartcard required" control as uncritical (done) */
3789 ctrl->critical = false;
3793 static int ph_op_callback(struct ldb_request *req, struct ldb_reply *ares)
3795 struct ph_context *ac;
3797 ac = talloc_get_type(req->context, struct ph_context);
3800 return ldb_module_done(ac->req, NULL, NULL,
3801 LDB_ERR_OPERATIONS_ERROR);
3804 if (ares->type == LDB_REPLY_REFERRAL) {
3805 return ldb_module_send_referral(ac->req, ares->referral);
3808 if ((ares->error != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
3809 /* On success and trivial errors a status control is being
3810 * added (used for example by the "samdb_set_password" call) */
3811 ldb_reply_add_control(ares,
3812 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
3817 if (ares->error != LDB_SUCCESS) {
3818 return ldb_module_done(ac->req, ares->controls,
3819 ares->response, ares->error);
3822 if (ares->type != LDB_REPLY_DONE) {
3824 return ldb_module_done(ac->req, NULL, NULL,
3825 LDB_ERR_OPERATIONS_ERROR);
3828 return ldb_module_done(ac->req, ares->controls,
3829 ares->response, ares->error);
3832 static int password_hash_add_do_add(struct ph_context *ac);
3833 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares);
3834 static int password_hash_mod_search_self(struct ph_context *ac);
3835 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares);
3836 static int password_hash_mod_do_mod(struct ph_context *ac);
3838 static int get_domain_data_callback(struct ldb_request *req,
3839 struct ldb_reply *ares)
3841 struct ldb_context *ldb;
3842 struct ph_context *ac;
3843 struct loadparm_context *lp_ctx;
3844 int ret = LDB_SUCCESS;
3846 ac = talloc_get_type(req->context, struct ph_context);
3847 ldb = ldb_module_get_ctx(ac->module);
3850 ret = LDB_ERR_OPERATIONS_ERROR;
3853 if (ares->error != LDB_SUCCESS) {
3854 return ldb_module_done(ac->req, ares->controls,
3855 ares->response, ares->error);
3858 switch (ares->type) {
3859 case LDB_REPLY_ENTRY:
3860 if (ac->status != NULL) {
3863 ldb_set_errstring(ldb, "Too many results");
3864 ret = LDB_ERR_OPERATIONS_ERROR;
3868 /* Setup the "status" structure (used as control later) */
3869 ac->status = talloc_zero(ac->req,
3870 struct dsdb_control_password_change_status);
3871 if (ac->status == NULL) {
3875 ret = LDB_ERR_OPERATIONS_ERROR;
3879 /* Setup the "domain data" structure */
3880 ac->status->domain_data.pwdProperties =
3881 ldb_msg_find_attr_as_uint(ares->message, "pwdProperties", -1);
3882 ac->status->domain_data.pwdHistoryLength =
3883 ldb_msg_find_attr_as_uint(ares->message, "pwdHistoryLength", -1);
3884 ac->status->domain_data.maxPwdAge =
3885 ldb_msg_find_attr_as_int64(ares->message, "maxPwdAge", -1);
3886 ac->status->domain_data.minPwdAge =
3887 ldb_msg_find_attr_as_int64(ares->message, "minPwdAge", -1);
3888 ac->status->domain_data.minPwdLength =
3889 ldb_msg_find_attr_as_uint(ares->message, "minPwdLength", -1);
3890 ac->status->domain_data.store_cleartext =
3891 ac->status->domain_data.pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
3893 /* For a domain DN, this puts things in dotted notation */
3894 /* For builtin domains, this will give details for the host,
3895 * but that doesn't really matter, as it's just used for salt
3896 * and kerberos principals, which don't exist here */
3898 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3899 struct loadparm_context);
3901 ac->status->domain_data.dns_domain = lpcfg_dnsdomain(lp_ctx);
3902 ac->status->domain_data.realm = lpcfg_realm(lp_ctx);
3903 ac->status->domain_data.netbios_domain = lpcfg_sam_name(lp_ctx);
3905 ac->status->reject_reason = SAM_PWD_CHANGE_NO_ERROR;
3907 if (ac->dom_res != NULL) {
3910 ldb_set_errstring(ldb, "Too many results");
3911 ret = LDB_ERR_OPERATIONS_ERROR;
3915 ac->dom_res = talloc_steal(ac, ares);
3919 case LDB_REPLY_REFERRAL:
3925 case LDB_REPLY_DONE:
3927 /* call the next step */
3928 switch (ac->req->operation) {
3930 ret = password_hash_add_do_add(ac);
3934 ret = password_hash_mod_do_mod(ac);
3938 ret = LDB_ERR_OPERATIONS_ERROR;
3945 if (ret != LDB_SUCCESS) {
3946 struct ldb_reply *new_ares;
3948 new_ares = talloc_zero(ac->req, struct ldb_reply);
3949 if (new_ares == NULL) {
3951 return ldb_module_done(ac->req, NULL, NULL,
3952 LDB_ERR_OPERATIONS_ERROR);
3955 new_ares->error = ret;
3956 if ((ret != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
3957 /* On success and trivial errors a status control is being
3958 * added (used for example by the "samdb_set_password" call) */
3959 ldb_reply_add_control(new_ares,
3960 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
3965 return ldb_module_done(ac->req, new_ares->controls,
3966 new_ares->response, new_ares->error);
3972 static int build_domain_data_request(struct ph_context *ac)
3974 /* attrs[] is returned from this function in
3975 ac->dom_req->op.search.attrs, so it must be static, as
3976 otherwise the compiler can put it on the stack */
3977 struct ldb_context *ldb;
3978 static const char * const attrs[] = { "pwdProperties",
3984 "lockOutObservationWindow",
3988 ldb = ldb_module_get_ctx(ac->module);
3990 ret = ldb_build_search_req(&ac->dom_req, ldb, ac,
3991 ldb_get_default_basedn(ldb),
3995 ac, get_domain_data_callback,
3997 LDB_REQ_SET_LOCATION(ac->dom_req);
4001 static int password_hash_needed(struct ldb_module *module,
4002 struct ldb_request *req,
4003 struct ph_context **_ac)
4005 struct ldb_context *ldb = ldb_module_get_ctx(module);
4006 const char *operation = NULL;
4007 const struct ldb_message *msg = NULL;
4008 struct ph_context *ac = NULL;
4009 const char *passwordAttrs[] = {
4011 "clearTextPassword",
4016 const char **a = NULL;
4017 unsigned int attr_cnt = 0;
4018 struct ldb_control *bypass = NULL;
4019 struct ldb_control *uac_ctrl = NULL;
4020 bool userPassword = dsdb_user_password_support(module, req, req);
4021 bool update_password = false;
4022 bool processing_needed = false;
4026 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_needed\n");
4028 switch (req->operation) {
4031 msg = req->op.add.message;
4034 operation = "modify";
4035 msg = req->op.mod.message;
4038 return ldb_next_request(module, req);
4041 if (ldb_dn_is_special(msg->dn)) { /* do not manipulate our control entries */
4042 return ldb_next_request(module, req);
4045 bypass = ldb_request_get_control(req,
4046 DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID);
4047 if (bypass != NULL) {
4048 /* Mark the "bypass" control as uncritical (done) */
4049 bypass->critical = false;
4050 ldb_debug(ldb, LDB_DEBUG_TRACE,
4051 "password_hash_needed(%s) (bypassing)\n",
4053 return password_hash_bypass(module, req);
4056 /* nobody must touch password histories and 'supplementalCredentials' */
4057 if (ldb_msg_find_element(msg, "ntPwdHistory")) {
4058 return LDB_ERR_UNWILLING_TO_PERFORM;
4060 if (ldb_msg_find_element(msg, "lmPwdHistory")) {
4061 return LDB_ERR_UNWILLING_TO_PERFORM;
4063 if (ldb_msg_find_element(msg, "supplementalCredentials")) {
4064 return LDB_ERR_UNWILLING_TO_PERFORM;
4068 * If no part of this touches the 'userPassword' OR 'clearTextPassword'
4069 * OR 'unicodePwd' OR 'dBCSPwd' we don't need to make any changes.
4070 * For password changes/set there should be a 'delete' or a 'modify'
4071 * on these attributes.
4073 for (a = passwordAttrs; *a != NULL; a++) {
4074 if ((!userPassword) && (ldb_attr_cmp(*a, "userPassword") == 0)) {
4078 if (ldb_msg_find_element(msg, *a) != NULL) {
4079 /* MS-ADTS 3.1.1.3.1.5.2 */
4080 if ((ldb_attr_cmp(*a, "userPassword") == 0) &&
4081 (dsdb_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
4082 return LDB_ERR_CONSTRAINT_VIOLATION;
4090 update_password = true;
4091 processing_needed = true;
4094 if (ldb_msg_find_element(msg, "pwdLastSet")) {
4095 processing_needed = true;
4098 uac_ctrl = ldb_request_get_control(req,
4099 DSDB_CONTROL_PASSWORD_USER_ACCOUNT_CONTROL_OID);
4100 if (uac_ctrl != NULL) {
4101 struct dsdb_control_password_user_account_control *uac = NULL;
4102 uint32_t added_flags = 0;
4104 uac = talloc_get_type_abort(uac_ctrl->data,
4105 struct dsdb_control_password_user_account_control);
4107 added_flags = uac->new_flags & ~uac->old_flags;
4109 if (added_flags & UF_SMARTCARD_REQUIRED) {
4110 processing_needed = true;
4114 if (!processing_needed) {
4115 return ldb_next_request(module, req);
4118 ac = ph_init_context(module, req, userPassword, update_password);
4120 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
4121 return ldb_operr(ldb);
4123 ph_apply_controls(ac);
4126 * Make a copy in order to apply our modifications
4127 * to the final update
4129 ac->update_msg = ldb_msg_copy_shallow(ac, msg);
4130 if (ac->update_msg == NULL) {
4131 return ldb_oom(ldb);
4135 * Remove all password related attributes.
4137 if (ac->userPassword) {
4138 ldb_msg_remove_attr(ac->update_msg, "userPassword");
4140 ldb_msg_remove_attr(ac->update_msg, "clearTextPassword");
4141 ldb_msg_remove_attr(ac->update_msg, "unicodePwd");
4142 ldb_msg_remove_attr(ac->update_msg, "ntPwdHistory");
4143 ldb_msg_remove_attr(ac->update_msg, "dBCSPwd");
4144 ldb_msg_remove_attr(ac->update_msg, "lmPwdHistory");
4145 ldb_msg_remove_attr(ac->update_msg, "supplementalCredentials");
4146 ldb_msg_remove_attr(ac->update_msg, "pwdLastSet");
4152 static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
4154 struct ldb_context *ldb = ldb_module_get_ctx(module);
4155 struct ph_context *ac = NULL;
4158 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add\n");
4160 ret = password_hash_needed(module, req, &ac);
4161 if (ret != LDB_SUCCESS) {
4168 /* Make sure we are performing the password set action on a (for us)
4169 * valid object. Those are instances of either "user" and/or
4170 * "inetOrgPerson". Otherwise continue with the submodules. */
4171 if ((!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "user"))
4172 && (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "inetOrgPerson"))) {
4176 if (ldb_msg_find_element(req->op.add.message, "clearTextPassword") != NULL) {
4177 ldb_set_errstring(ldb,
4178 "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
4179 return LDB_ERR_NO_SUCH_ATTRIBUTE;
4182 return ldb_next_request(module, req);
4185 /* get user domain data */
4186 ret = build_domain_data_request(ac);
4187 if (ret != LDB_SUCCESS) {
4191 return ldb_next_request(module, ac->dom_req);
4194 static int password_hash_add_do_add(struct ph_context *ac)
4196 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
4197 struct ldb_request *down_req;
4198 struct setup_password_fields_io io;
4201 /* Prepare the internal data structure containing the passwords */
4202 ret = setup_io(ac, ac->req->op.add.message, NULL, &io);
4203 if (ret != LDB_SUCCESS) {
4207 ret = setup_password_fields(&io);
4208 if (ret != LDB_SUCCESS) {
4212 ret = check_password_restrictions_and_log(&io);
4213 if (ret != LDB_SUCCESS) {
4217 ret = setup_smartcard_reset(&io);
4218 if (ret != LDB_SUCCESS) {
4222 ret = update_final_msg(&io);
4223 if (ret != LDB_SUCCESS) {
4227 ret = ldb_build_add_req(&down_req, ldb, ac,
4232 LDB_REQ_SET_LOCATION(down_req);
4233 if (ret != LDB_SUCCESS) {
4237 return ldb_next_request(ac->module, down_req);
4240 static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
4242 struct ldb_context *ldb = ldb_module_get_ctx(module);
4243 struct ph_context *ac = NULL;
4244 const char *passwordAttrs[] = { "userPassword", "clearTextPassword",
4245 "unicodePwd", "dBCSPwd", NULL }, **l;
4246 unsigned int del_attr_cnt, add_attr_cnt, rep_attr_cnt;
4247 struct ldb_message_element *passwordAttr;
4248 struct ldb_message *msg;
4249 struct ldb_request *down_req;
4250 struct ldb_control *restore = NULL;
4254 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
4256 ret = password_hash_needed(module, req, &ac);
4257 if (ret != LDB_SUCCESS) {
4264 /* use a new message structure so that we can modify it */
4265 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
4267 return ldb_oom(ldb);
4270 /* - check for single-valued password attributes
4271 * (if not return "CONSTRAINT_VIOLATION")
4272 * - check that for a password change operation one add and one delete
4274 * (if not return "CONSTRAINT_VIOLATION" or "UNWILLING_TO_PERFORM")
4275 * - check that a password change and a password set operation cannot
4277 * (if not return "UNWILLING_TO_PERFORM")
4278 * - remove all password attributes modifications from the first change
4279 * operation (anything without the passwords) - we will make the real
4280 * modification later */
4284 for (l = passwordAttrs; *l != NULL; l++) {
4285 if ((!ac->userPassword) &&
4286 (ldb_attr_cmp(*l, "userPassword") == 0)) {
4290 while ((passwordAttr = ldb_msg_find_element(msg, *l)) != NULL) {
4291 if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_DELETE) {
4294 if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_ADD) {
4297 if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_REPLACE) {
4300 if ((passwordAttr->num_values != 1) &&
4301 (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_ADD)) {
4303 ldb_asprintf_errstring(ldb,
4304 "'%s' attribute must have exactly one value on add operations!",
4306 return LDB_ERR_CONSTRAINT_VIOLATION;
4308 if ((passwordAttr->num_values > 1) &&
4309 (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_DELETE)) {
4311 ldb_asprintf_errstring(ldb,
4312 "'%s' attribute must have zero or one value(s) on delete operations!",
4314 return LDB_ERR_CONSTRAINT_VIOLATION;
4316 ldb_msg_remove_element(msg, passwordAttr);
4319 if ((del_attr_cnt == 0) && (add_attr_cnt > 0)) {
4321 ldb_set_errstring(ldb,
4322 "Only the add action for a password change specified!");
4323 return LDB_ERR_UNWILLING_TO_PERFORM;
4325 if ((del_attr_cnt > 1) || (add_attr_cnt > 1)) {
4327 ldb_set_errstring(ldb,
4328 "Only one delete and one add action for a password change allowed!");
4329 return LDB_ERR_UNWILLING_TO_PERFORM;
4331 if ((rep_attr_cnt > 0) && ((del_attr_cnt > 0) || (add_attr_cnt > 0))) {
4333 ldb_set_errstring(ldb,
4334 "Either a password change or a password set operation is allowed!");
4335 return LDB_ERR_UNWILLING_TO_PERFORM;
4338 restore = ldb_request_get_control(req,
4339 DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
4340 if (restore == NULL) {
4342 * A tomstone reanimation generates a double update
4345 * So we only remove it without the
4346 * DSDB_CONTROL_RESTORE_TOMBSTONE_OID control.
4348 ldb_msg_remove_attr(msg, "pwdLastSet");
4352 /* if there was nothing else to be modified skip to next step */
4353 if (msg->num_elements == 0) {
4354 return password_hash_mod_search_self(ac);
4358 * Now we apply all changes remaining in msg
4359 * and remove them from our final update_msg
4362 for (i = 0; i < msg->num_elements; i++) {
4363 ldb_msg_remove_attr(ac->update_msg,
4364 msg->elements[i].name);
4367 ret = ldb_build_mod_req(&down_req, ldb, ac,
4370 ac, ph_modify_callback,
4372 LDB_REQ_SET_LOCATION(down_req);
4373 if (ret != LDB_SUCCESS) {
4377 return ldb_next_request(module, down_req);
4380 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
4382 struct ph_context *ac;
4384 ac = talloc_get_type(req->context, struct ph_context);
4387 return ldb_module_done(ac->req, NULL, NULL,
4388 LDB_ERR_OPERATIONS_ERROR);
4391 if (ares->type == LDB_REPLY_REFERRAL) {
4392 return ldb_module_send_referral(ac->req, ares->referral);
4395 if (ares->error != LDB_SUCCESS) {
4396 return ldb_module_done(ac->req, ares->controls,
4397 ares->response, ares->error);
4400 if (ares->type != LDB_REPLY_DONE) {
4402 return ldb_module_done(ac->req, NULL, NULL,
4403 LDB_ERR_OPERATIONS_ERROR);
4408 return password_hash_mod_search_self(ac);
4411 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
4413 struct ldb_context *ldb;
4414 struct ph_context *ac;
4415 int ret = LDB_SUCCESS;
4417 ac = talloc_get_type(req->context, struct ph_context);
4418 ldb = ldb_module_get_ctx(ac->module);
4421 ret = LDB_ERR_OPERATIONS_ERROR;
4424 if (ares->error != LDB_SUCCESS) {
4425 return ldb_module_done(ac->req, ares->controls,
4426 ares->response, ares->error);
4429 /* we are interested only in the single reply (base search) */
4430 switch (ares->type) {
4431 case LDB_REPLY_ENTRY:
4432 /* Make sure we are performing the password change action on a
4433 * (for us) valid object. Those are instances of either "user"
4434 * and/or "inetOrgPerson". Otherwise continue with the
4436 if ((!ldb_msg_check_string_attribute(ares->message, "objectClass", "user"))
4437 && (!ldb_msg_check_string_attribute(ares->message, "objectClass", "inetOrgPerson"))) {
4440 if (ldb_msg_find_element(ac->req->op.mod.message, "clearTextPassword") != NULL) {
4441 ldb_set_errstring(ldb,
4442 "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
4443 ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
4447 ret = ldb_next_request(ac->module, ac->req);
4451 if (ac->search_res != NULL) {
4454 ldb_set_errstring(ldb, "Too many results");
4455 ret = LDB_ERR_OPERATIONS_ERROR;
4459 ac->search_res = talloc_steal(ac, ares);
4463 case LDB_REPLY_REFERRAL:
4464 /* ignore anything else for now */
4469 case LDB_REPLY_DONE:
4472 /* get user domain data */
4473 ret = build_domain_data_request(ac);
4474 if (ret != LDB_SUCCESS) {
4475 return ldb_module_done(ac->req, NULL, NULL, ret);
4478 ret = ldb_next_request(ac->module, ac->dom_req);
4483 if (ret != LDB_SUCCESS) {
4484 return ldb_module_done(ac->req, NULL, NULL, ret);
4490 static int password_hash_mod_search_self(struct ph_context *ac)
4492 struct ldb_context *ldb;
4493 static const char * const attrs[] = { "objectClass",
4494 "userAccountControl",
4495 "msDS-User-Account-Control-Computed",
4499 "userPrincipalName",
4500 "supplementalCredentials",
4508 "msDS-SecondaryKrbTgtNumber",
4510 struct ldb_request *search_req;
4513 ldb = ldb_module_get_ctx(ac->module);
4515 ret = ldb_build_search_req(&search_req, ldb, ac,
4516 ac->req->op.mod.message->dn,
4521 ac, ph_mod_search_callback,
4523 LDB_REQ_SET_LOCATION(search_req);
4524 if (ret != LDB_SUCCESS) {
4528 return ldb_next_request(ac->module, search_req);
4531 static int password_hash_mod_do_mod(struct ph_context *ac)
4533 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
4534 struct ldb_request *mod_req;
4535 struct setup_password_fields_io io;
4538 /* Prepare the internal data structure containing the passwords */
4539 ret = setup_io(ac, ac->req->op.mod.message,
4540 ac->search_res->message, &io);
4541 if (ret != LDB_SUCCESS) {
4545 ret = setup_password_fields(&io);
4546 if (ret != LDB_SUCCESS) {
4550 ret = check_password_restrictions_and_log(&io);
4551 if (ret != LDB_SUCCESS) {
4555 ret = setup_smartcard_reset(&io);
4556 if (ret != LDB_SUCCESS) {
4560 ret = update_final_msg(&io);
4561 if (ret != LDB_SUCCESS) {
4565 ret = ldb_build_mod_req(&mod_req, ldb, ac,
4570 LDB_REQ_SET_LOCATION(mod_req);
4571 if (ret != LDB_SUCCESS) {
4575 return ldb_next_request(ac->module, mod_req);
4578 static const struct ldb_module_ops ldb_password_hash_module_ops = {
4579 .name = "password_hash",
4580 .add = password_hash_add,
4581 .modify = password_hash_modify
4584 int ldb_password_hash_module_init(const char *version)
4587 const char *gversion = NULL;
4588 #endif /* ENABLE_GPGME */
4590 LDB_MODULE_CHECK_VERSION(version);
4594 * Note: this sets a SIGPIPE handler
4595 * if none is active already. See:
4596 * https://www.gnupg.org/documentation/manuals/gpgme/Signal-Handling.html#Signal-Handling
4598 gversion = gpgme_check_version(GPGME_VERSION);
4599 if (gversion == NULL) {
4600 fprintf(stderr, "%s() in %s version[%s]: "
4601 "gpgme_check_version(%s) not available, "
4602 "gpgme_check_version(NULL) => '%s'\n",
4603 __func__, __FILE__, version,
4604 GPGME_VERSION, gpgme_check_version(NULL));
4605 return LDB_ERR_UNAVAILABLE;
4607 #endif /* ENABLE_GPGME */
4609 return ldb_register_module(&ldb_password_hash_module_ops);