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 .user = &sAMAccountName,
1237 .realm = &dns_domain,
1240 .user = &sAMAccountName_l,
1241 .realm = &dns_domain_l,
1244 .user = &sAMAccountName_u,
1245 .realm = &dns_domain_u,
1248 .user = &sAMAccountName,
1249 .realm = &dns_domain_u,
1252 .user = &sAMAccountName,
1253 .realm = &dns_domain_l,
1256 .user = &sAMAccountName_u,
1257 .realm = &dns_domain_l,
1260 .user = &sAMAccountName_l,
1261 .realm = &dns_domain_u,
1264 * userPrincipalName, no realm
1267 .user = &userPrincipalName,
1271 * NOTE: w2k3 messes this up, if the user has a real userPrincipalName,
1272 * the fallback to the sAMAccountName based userPrincipalName is correct
1274 .user = &userPrincipalName_l,
1277 .user = &userPrincipalName_u,
1280 * nt4dom\sAMAccountName, no realm
1283 .user = &sAMAccountName,
1284 .nt4dom = &netbios_domain
1287 .user = &sAMAccountName_l,
1288 .nt4dom = &netbios_domain_l
1291 .user = &sAMAccountName_u,
1292 .nt4dom = &netbios_domain_u
1296 * the following ones are guessed depending on the technet2 article
1297 * but not reproducable on a w2k3 server
1299 /* sAMAccountName with "Digest" realm */
1301 .user = &sAMAccountName,
1305 .user = &sAMAccountName_l,
1309 .user = &sAMAccountName_u,
1312 /* userPrincipalName with "Digest" realm */
1314 .user = &userPrincipalName,
1318 .user = &userPrincipalName_l,
1322 .user = &userPrincipalName_u,
1325 /* nt4dom\\sAMAccountName with "Digest" realm */
1327 .user = &sAMAccountName,
1328 .nt4dom = &netbios_domain,
1332 .user = &sAMAccountName_l,
1333 .nt4dom = &netbios_domain_l,
1337 .user = &sAMAccountName_u,
1338 .nt4dom = &netbios_domain_u,
1343 /* prepare DATA_BLOB's used in the combinations array */
1344 sAMAccountName = data_blob_string_const(io->u.sAMAccountName);
1345 sAMAccountName_l = data_blob_string_const(strlower_talloc(io->ac, io->u.sAMAccountName));
1346 if (!sAMAccountName_l.data) {
1347 return ldb_oom(ldb);
1349 sAMAccountName_u = data_blob_string_const(strupper_talloc(io->ac, io->u.sAMAccountName));
1350 if (!sAMAccountName_u.data) {
1351 return ldb_oom(ldb);
1354 /* if the user doesn't have a userPrincipalName, create one (with lower case realm) */
1355 if (!user_principal_name) {
1356 user_principal_name = talloc_asprintf(io->ac, "%s@%s",
1357 io->u.sAMAccountName,
1358 io->ac->status->domain_data.dns_domain);
1359 if (!user_principal_name) {
1360 return ldb_oom(ldb);
1363 userPrincipalName = data_blob_string_const(user_principal_name);
1364 userPrincipalName_l = data_blob_string_const(strlower_talloc(io->ac, user_principal_name));
1365 if (!userPrincipalName_l.data) {
1366 return ldb_oom(ldb);
1368 userPrincipalName_u = data_blob_string_const(strupper_talloc(io->ac, user_principal_name));
1369 if (!userPrincipalName_u.data) {
1370 return ldb_oom(ldb);
1373 netbios_domain = data_blob_string_const(io->ac->status->domain_data.netbios_domain);
1374 netbios_domain_l = data_blob_string_const(strlower_talloc(io->ac,
1375 io->ac->status->domain_data.netbios_domain));
1376 if (!netbios_domain_l.data) {
1377 return ldb_oom(ldb);
1379 netbios_domain_u = data_blob_string_const(strupper_talloc(io->ac,
1380 io->ac->status->domain_data.netbios_domain));
1381 if (!netbios_domain_u.data) {
1382 return ldb_oom(ldb);
1385 dns_domain = data_blob_string_const(io->ac->status->domain_data.dns_domain);
1386 dns_domain_l = data_blob_string_const(io->ac->status->domain_data.dns_domain);
1387 dns_domain_u = data_blob_string_const(io->ac->status->domain_data.realm);
1389 digest = data_blob_string_const("Digest");
1391 delim = data_blob_string_const(":");
1392 backslash = data_blob_string_const("\\");
1394 pdb->num_hashes = ARRAY_SIZE(wdigest);
1395 pdb->hashes = talloc_array(io->ac, struct package_PrimaryWDigestHash,
1398 return ldb_oom(ldb);
1401 for (i=0; i < ARRAY_SIZE(wdigest); i++) {
1404 if (wdigest[i].nt4dom) {
1405 MD5Update(&md5, wdigest[i].nt4dom->data, wdigest[i].nt4dom->length);
1406 MD5Update(&md5, backslash.data, backslash.length);
1408 MD5Update(&md5, wdigest[i].user->data, wdigest[i].user->length);
1409 MD5Update(&md5, delim.data, delim.length);
1410 if (wdigest[i].realm) {
1411 MD5Update(&md5, wdigest[i].realm->data, wdigest[i].realm->length);
1413 MD5Update(&md5, delim.data, delim.length);
1414 MD5Update(&md5, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length);
1415 MD5Final(pdb->hashes[i].hash, &md5);
1421 #define SHA_SALT_PERMITTED_CHARS "abcdefghijklmnopqrstuvwxyz" \
1422 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
1424 #define SHA_SALT_SIZE 16
1425 #define SHA_256_SCHEME "CryptSHA256"
1426 #define SHA_512_SCHEME "CryptSHA512"
1427 #define CRYPT "{CRYPT}"
1428 #define SHA_ID_LEN 3
1429 #define SHA_256_ALGORITHM_ID 5
1430 #define SHA_512_ALGORITHM_ID 6
1431 #define ROUNDS_PARAMETER "rounds="
1434 * Extract the crypt (3) algorithm number and number of hash rounds from the
1435 * supplied scheme string
1437 static bool parse_scheme(const char *scheme, int *algorithm, int *rounds) {
1439 const char *rp = NULL; /* Pointer to the 'rounds=' option */
1440 char digits[21]; /* digits extracted from the rounds option */
1441 int i = 0; /* loop index variable */
1443 if (strncasecmp(SHA_256_SCHEME, scheme, strlen(SHA_256_SCHEME)) == 0) {
1444 *algorithm = SHA_256_ALGORITHM_ID;
1445 } else if (strncasecmp(SHA_512_SCHEME, scheme, strlen(SHA_256_SCHEME))
1447 *algorithm = SHA_512_ALGORITHM_ID;
1452 rp = strcasestr(scheme, ROUNDS_PARAMETER);
1454 /* No options specified, use crypt default number of rounds */
1458 rp += strlen(ROUNDS_PARAMETER);
1459 for (i = 0; isdigit(rp[i]) && i < (sizeof(digits) - 1); i++) {
1463 *rounds = atoi(digits);
1468 * Calculate the password hash specified by scheme, and return it in
1471 static int setup_primary_userPassword_hash(
1473 struct setup_password_fields_io *io,
1475 struct package_PrimaryUserPasswordValue *hash_value)
1477 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1478 const char *salt = NULL; /* Randomly generated salt */
1479 const char *cmd = NULL; /* command passed to crypt */
1480 const char *hash = NULL; /* password hash generated by crypt */
1481 struct crypt_data crypt_data; /* working storage used by crypt */
1482 int algorithm = 0; /* crypt hash algorithm number */
1483 int rounds = 0; /* The number of hash rounds */
1484 DATA_BLOB *hash_blob = NULL;
1485 TALLOC_CTX *frame = talloc_stackframe();
1487 /* Genrate a random password salt */
1488 salt = generate_random_str_list(frame,
1490 SHA_SALT_PERMITTED_CHARS);
1493 return ldb_oom(ldb);
1496 /* determine the hashing algoritm and number of rounds*/
1497 if (!parse_scheme(scheme, &algorithm, &rounds)) {
1498 ldb_asprintf_errstring(
1500 "setup_primary_userPassword: Invalid scheme of [%s] "
1501 "specified for 'password hash userPassword schemes' in "
1505 return LDB_ERR_OPERATIONS_ERROR;
1507 hash_value->scheme = talloc_strdup(ctx, CRYPT);
1508 hash_value->scheme_len = strlen(CRYPT) + 1;
1510 /* generate the id/salt parameter used by crypt */
1512 cmd = talloc_asprintf(frame,
1518 cmd = talloc_asprintf(frame, "$%d$%s", algorithm, salt);
1522 * Relies on the assertion that cleartext_utf8->data is a zero
1523 * terminated UTF-8 string
1525 hash = crypt_r((char *)io->n.cleartext_utf8->data, cmd, &crypt_data);
1528 ldb_asprintf_errstring(
1530 "setup_primary_userPassword: generation of a %s "
1531 "password hash failed: (%s)",
1533 strerror_r(errno, buf, sizeof(buf)));
1535 return LDB_ERR_OPERATIONS_ERROR;
1538 hash_blob = talloc_zero(ctx, DATA_BLOB);
1540 if (hash_blob == NULL) {
1542 return ldb_oom(ldb);
1545 *hash_blob = data_blob_talloc(hash_blob,
1546 (const uint8_t *)hash,
1548 if (hash_blob->data == NULL) {
1550 return ldb_oom(ldb);
1552 hash_value->value = hash_blob;
1558 * Calculate the desired extra password hashes
1560 static int setup_primary_userPassword(
1561 struct setup_password_fields_io *io,
1562 const struct supplementalCredentialsBlob *old_scb,
1563 struct package_PrimaryUserPasswordBlob *p_userPassword_b)
1565 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1566 TALLOC_CTX *frame = talloc_stackframe();
1571 * Save the current nt_hash, use this to determine if the password
1572 * has been changed by windows. Which will invalidate the userPassword
1573 * hash. Note once NTLM-Strong-NOWTF becomes available it should be
1574 * used in preference to the NT password hash
1576 if (io->g.nt_hash == NULL) {
1577 ldb_asprintf_errstring(ldb,
1578 "No NT Hash, unable to calculate userPassword hashes");
1579 return LDB_ERR_UNWILLING_TO_PERFORM;
1581 p_userPassword_b->current_nt_hash = *io->g.nt_hash;
1584 * Determine the number of hashes
1585 * Note: that currently there is no limit on the number of hashes
1586 * no checking is done on the number of schemes specified
1587 * or for uniqueness.
1589 p_userPassword_b->num_hashes = 0;
1590 for (i = 0; io->ac->userPassword_schemes[i]; i++) {
1591 p_userPassword_b->num_hashes++;
1594 p_userPassword_b->hashes
1595 = talloc_array(io->ac,
1596 struct package_PrimaryUserPasswordValue,
1597 p_userPassword_b->num_hashes);
1598 if (p_userPassword_b->hashes == NULL) {
1600 return ldb_oom(ldb);
1603 for (i = 0; io->ac->userPassword_schemes[i]; i++) {
1604 ret = setup_primary_userPassword_hash(
1605 p_userPassword_b->hashes,
1607 io->ac->userPassword_schemes[i],
1608 &p_userPassword_b->hashes[i]);
1609 if (ret != LDB_SUCCESS) {
1618 static int setup_primary_samba_gpg(struct setup_password_fields_io *io,
1619 struct package_PrimarySambaGPGBlob *pgb)
1621 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1624 gpgme_ctx_t ctx = NULL;
1625 size_t num_keys = str_list_length(io->ac->gpg_key_ids);
1626 gpgme_key_t keys[num_keys+1];
1629 gpgme_data_t plain_data = NULL;
1630 gpgme_data_t crypt_data = NULL;
1631 size_t crypt_length = 0;
1632 char *crypt_mem = NULL;
1634 gret = gpgme_new(&ctx);
1635 if (gret != GPG_ERR_NO_ERROR) {
1636 ldb_debug(ldb, LDB_DEBUG_ERROR,
1637 "%s:%s: gret[%u] %s\n",
1638 __location__, __func__,
1639 gret, gpgme_strerror(gret));
1640 return ldb_module_operr(io->ac->module);
1643 gpgme_set_armor(ctx, 1);
1645 gret = gpgme_data_new_from_mem(&plain_data,
1646 (const char *)io->n.cleartext_utf16->data,
1647 io->n.cleartext_utf16->length,
1649 if (gret != GPG_ERR_NO_ERROR) {
1650 ldb_debug(ldb, LDB_DEBUG_ERROR,
1651 "%s:%s: gret[%u] %s\n",
1652 __location__, __func__,
1653 gret, gpgme_strerror(gret));
1655 return ldb_module_operr(io->ac->module);
1657 gret = gpgme_data_new(&crypt_data);
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 gpgme_data_release(plain_data);
1665 return ldb_module_operr(io->ac->module);
1668 for (ki = 0; ki < num_keys; ki++) {
1669 const char *key_id = io->ac->gpg_key_ids[ki];
1670 size_t len = strlen(key_id);
1675 ldb_debug(ldb, LDB_DEBUG_FATAL,
1676 "%s:%s: ki[%zu] key_id[%s] strlen < 16, "
1677 "please specify at least the 64bit key id\n",
1678 __location__, __func__,
1680 for (kr = 0; keys[kr] != NULL; kr++) {
1681 gpgme_key_release(keys[kr]);
1683 gpgme_data_release(crypt_data);
1684 gpgme_data_release(plain_data);
1686 return ldb_module_operr(io->ac->module);
1689 gret = gpgme_get_key(ctx, key_id, &keys[ki], 0 /* public key */);
1690 if (gret != GPG_ERR_NO_ERROR) {
1692 ldb_debug(ldb, LDB_DEBUG_ERROR,
1693 "%s:%s: ki[%zu] key_id[%s] gret[%u] %s\n",
1694 __location__, __func__,
1696 gret, gpgme_strerror(gret));
1697 for (kr = 0; keys[kr] != NULL; kr++) {
1698 gpgme_key_release(keys[kr]);
1700 gpgme_data_release(crypt_data);
1701 gpgme_data_release(plain_data);
1703 return ldb_module_operr(io->ac->module);
1708 gret = gpgme_op_encrypt(ctx, keys,
1709 GPGME_ENCRYPT_ALWAYS_TRUST,
1710 plain_data, crypt_data);
1711 gpgme_data_release(plain_data);
1713 for (kr = 0; keys[kr] != NULL; kr++) {
1714 gpgme_key_release(keys[kr]);
1719 if (gret != GPG_ERR_NO_ERROR) {
1720 ldb_debug(ldb, LDB_DEBUG_ERROR,
1721 "%s:%s: gret[%u] %s\n",
1722 __location__, __func__,
1723 gret, gpgme_strerror(gret));
1724 gpgme_data_release(crypt_data);
1725 return ldb_module_operr(io->ac->module);
1728 crypt_mem = gpgme_data_release_and_get_mem(crypt_data, &crypt_length);
1730 if (crypt_mem == NULL) {
1731 return ldb_module_oom(io->ac->module);
1734 pgb->gpg_blob = data_blob_talloc(io->ac,
1735 (const uint8_t *)crypt_mem,
1737 gpgme_free(crypt_mem);
1740 if (pgb->gpg_blob.data == NULL) {
1741 return ldb_module_oom(io->ac->module);
1745 #else /* ENABLE_GPGME */
1746 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
1747 "You configured 'password hash gpg key ids', "
1748 "but GPGME support is missing. (%s:%d)",
1749 __FILE__, __LINE__);
1750 return LDB_ERR_UNWILLING_TO_PERFORM;
1751 #endif /* else ENABLE_GPGME */
1754 #define NUM_PACKAGES 6
1755 static int setup_supplemental_field(struct setup_password_fields_io *io)
1757 struct ldb_context *ldb;
1758 struct supplementalCredentialsBlob scb;
1759 struct supplementalCredentialsBlob *old_scb = NULL;
1762 * ( Kerberos-Newer-Keys, Kerberos,
1763 * WDigest, CLEARTEXT, userPassword, SambaGPG)
1765 uint32_t num_names = 0;
1766 const char *names[1+NUM_PACKAGES];
1767 uint32_t num_packages = 0;
1768 struct supplementalCredentialsPackage packages[1+NUM_PACKAGES];
1769 struct supplementalCredentialsPackage *pp = packages;
1771 enum ndr_err_code ndr_err;
1772 bool do_newer_keys = false;
1773 bool do_cleartext = false;
1774 bool do_samba_gpg = false;
1777 ZERO_STRUCT(packages);
1779 ldb = ldb_module_get_ctx(io->ac->module);
1781 if (!io->n.cleartext_utf8) {
1783 * when we don't have a cleartext password
1784 * we can't setup a supplementalCredential value
1789 /* if there's an old supplementaCredentials blob then use it */
1790 if (io->o.supplemental) {
1791 if (io->o.scb.sub.signature == SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
1792 old_scb = &io->o.scb;
1794 ldb_debug(ldb, LDB_DEBUG_ERROR,
1795 "setup_supplemental_field: "
1796 "supplementalCredentialsBlob "
1797 "signature[0x%04X] expected[0x%04X]",
1798 io->o.scb.sub.signature,
1799 SUPPLEMENTAL_CREDENTIALS_SIGNATURE);
1802 /* Per MS-SAMR 3.1.1.8.11.6 we create AES keys if our domain functionality level is 2008 or higher */
1807 * The ordering is this
1809 * Primary:Kerberos-Newer-Keys (optional)
1812 * Primary:CLEARTEXT (optional)
1813 * Primary:userPassword
1814 * Primary:SambaGPG (optional)
1816 * And the 'Packages' package is insert before the last
1819 * Note: it's important that Primary:SambaGPG is added as
1820 * the last element. This is the indication that it matches
1821 * the current password. When a password change happens on
1822 * a Windows DC, it will keep the old Primary:SambaGPG value,
1823 * but as the first element.
1825 do_newer_keys = (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008);
1826 if (do_newer_keys) {
1827 struct package_PrimaryKerberosBlob pknb;
1828 DATA_BLOB pknb_blob;
1831 * setup 'Primary:Kerberos-Newer-Keys' element
1833 names[num_names++] = "Kerberos-Newer-Keys";
1835 ret = setup_primary_kerberos_newer(io, old_scb, &pknb);
1836 if (ret != LDB_SUCCESS) {
1840 ndr_err = ndr_push_struct_blob(
1843 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1844 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1845 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1846 ldb_asprintf_errstring(
1848 "setup_supplemental_field: "
1850 "package_PrimaryKerberosNeverBlob: %s",
1852 return LDB_ERR_OPERATIONS_ERROR;
1854 pknb_hexstr = data_blob_hex_string_upper(io->ac, &pknb_blob);
1856 return ldb_oom(ldb);
1858 pp->name = "Primary:Kerberos-Newer-Keys";
1860 pp->data = pknb_hexstr;
1867 * setup 'Primary:Kerberos' element
1869 /* Primary:Kerberos */
1870 struct package_PrimaryKerberosBlob pkb;
1874 names[num_names++] = "Kerberos";
1876 ret = setup_primary_kerberos(io, old_scb, &pkb);
1877 if (ret != LDB_SUCCESS) {
1881 ndr_err = ndr_push_struct_blob(
1884 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1885 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1886 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1887 ldb_asprintf_errstring(
1889 "setup_supplemental_field: "
1890 "failed to push package_PrimaryKerberosBlob: %s",
1892 return LDB_ERR_OPERATIONS_ERROR;
1894 pkb_hexstr = data_blob_hex_string_upper(io->ac, &pkb_blob);
1896 return ldb_oom(ldb);
1898 pp->name = "Primary:Kerberos";
1900 pp->data = pkb_hexstr;
1907 * setup 'Primary:WDigest' element
1909 struct package_PrimaryWDigestBlob pdb;
1913 names[num_names++] = "WDigest";
1915 ret = setup_primary_wdigest(io, old_scb, &pdb);
1916 if (ret != LDB_SUCCESS) {
1920 ndr_err = ndr_push_struct_blob(
1923 (ndr_push_flags_fn_t)ndr_push_package_PrimaryWDigestBlob);
1924 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1925 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1926 ldb_asprintf_errstring(
1928 "setup_supplemental_field: "
1929 "failed to push package_PrimaryWDigestBlob: %s",
1931 return LDB_ERR_OPERATIONS_ERROR;
1933 pdb_hexstr = data_blob_hex_string_upper(io->ac, &pdb_blob);
1935 return ldb_oom(ldb);
1937 pp->name = "Primary:WDigest";
1939 pp->data = pdb_hexstr;
1945 * setup 'Primary:CLEARTEXT' element
1947 if (io->ac->status->domain_data.store_cleartext &&
1948 (io->u.userAccountControl & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) {
1949 do_cleartext = true;
1952 struct package_PrimaryCLEARTEXTBlob pcb;
1956 names[num_names++] = "CLEARTEXT";
1958 pcb.cleartext = *io->n.cleartext_utf16;
1960 ndr_err = ndr_push_struct_blob(
1963 (ndr_push_flags_fn_t)ndr_push_package_PrimaryCLEARTEXTBlob);
1964 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1965 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1966 ldb_asprintf_errstring(
1968 "setup_supplemental_field: "
1969 "failed to push package_PrimaryCLEARTEXTBlob: %s",
1971 return LDB_ERR_OPERATIONS_ERROR;
1973 pcb_hexstr = data_blob_hex_string_upper(io->ac, &pcb_blob);
1975 return ldb_oom(ldb);
1977 pp->name = "Primary:CLEARTEXT";
1979 pp->data = pcb_hexstr;
1984 if (io->ac->userPassword_schemes) {
1986 * setup 'Primary:userPassword' element
1988 struct package_PrimaryUserPasswordBlob
1990 DATA_BLOB p_userPassword_b_blob;
1991 char *p_userPassword_b_hexstr;
1993 names[num_names++] = "userPassword";
1995 ret = setup_primary_userPassword(io,
1998 if (ret != LDB_SUCCESS) {
2002 ndr_err = ndr_push_struct_blob(
2003 &p_userPassword_b_blob,
2006 (ndr_push_flags_fn_t)
2007 ndr_push_package_PrimaryUserPasswordBlob);
2008 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2009 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2010 ldb_asprintf_errstring(
2012 "setup_supplemental_field: failed to push "
2013 "package_PrimaryUserPasswordBlob: %s",
2015 return LDB_ERR_OPERATIONS_ERROR;
2017 p_userPassword_b_hexstr
2018 = data_blob_hex_string_upper(
2020 &p_userPassword_b_blob);
2021 if (!p_userPassword_b_hexstr) {
2022 return ldb_oom(ldb);
2024 pp->name = "Primary:userPassword";
2026 pp->data = p_userPassword_b_hexstr;
2032 * setup 'Primary:SambaGPG' element
2034 if (io->ac->gpg_key_ids != NULL) {
2035 do_samba_gpg = true;
2038 struct package_PrimarySambaGPGBlob pgb;
2042 names[num_names++] = "SambaGPG";
2044 ret = setup_primary_samba_gpg(io, &pgb);
2045 if (ret != LDB_SUCCESS) {
2049 ndr_err = ndr_push_struct_blob(&pgb_blob, io->ac, &pgb,
2050 (ndr_push_flags_fn_t)ndr_push_package_PrimarySambaGPGBlob);
2051 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2052 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2053 ldb_asprintf_errstring(ldb,
2054 "setup_supplemental_field: failed to "
2055 "push package_PrimarySambaGPGBlob: %s",
2057 return LDB_ERR_OPERATIONS_ERROR;
2059 pgb_hexstr = data_blob_hex_string_upper(io->ac, &pgb_blob);
2061 return ldb_oom(ldb);
2063 pp->name = "Primary:SambaGPG";
2065 pp->data = pgb_hexstr;
2071 * setup 'Packages' element
2074 struct package_PackagesBlob pb;
2079 ndr_err = ndr_push_struct_blob(
2082 (ndr_push_flags_fn_t)ndr_push_package_PackagesBlob);
2083 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2084 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2085 ldb_asprintf_errstring(
2087 "setup_supplemental_field: "
2088 "failed to push package_PackagesBlob: %s",
2090 return LDB_ERR_OPERATIONS_ERROR;
2092 pb_hexstr = data_blob_hex_string_upper(io->ac, &pb_blob);
2094 return ldb_oom(ldb);
2096 pp->name = "Packages";
2098 pp->data = pb_hexstr;
2101 * We don't increment pp so it's pointing to the last package
2106 * setup 'supplementalCredentials' value
2110 * The 'Packages' element needs to be the second last element
2111 * in supplementalCredentials
2113 struct supplementalCredentialsPackage temp;
2114 struct supplementalCredentialsPackage *prev;
2122 scb.sub.signature = SUPPLEMENTAL_CREDENTIALS_SIGNATURE;
2123 scb.sub.num_packages = num_packages;
2124 scb.sub.packages = packages;
2126 ndr_err = ndr_push_struct_blob(
2127 &io->g.supplemental, io->ac,
2129 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
2130 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2131 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2132 ldb_asprintf_errstring(
2134 "setup_supplemental_field: "
2135 "failed to push supplementalCredentialsBlob: %s",
2137 return LDB_ERR_OPERATIONS_ERROR;
2144 static int setup_last_set_field(struct setup_password_fields_io *io)
2146 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2147 const struct ldb_message *msg = NULL;
2148 struct timeval tv = { .tv_sec = 0 };
2149 const struct ldb_val *old_val = NULL;
2150 const struct ldb_val *new_val = NULL;
2153 switch (io->ac->req->operation) {
2155 msg = io->ac->req->op.add.message;
2158 msg = io->ac->req->op.mod.message;
2161 return LDB_ERR_OPERATIONS_ERROR;
2165 if (io->ac->pwd_last_set_bypass) {
2166 struct ldb_message_element *el1 = NULL;
2167 struct ldb_message_element *el2 = NULL;
2170 return LDB_ERR_CONSTRAINT_VIOLATION;
2173 el1 = dsdb_get_single_valued_attr(msg, "pwdLastSet",
2174 io->ac->req->operation);
2176 return LDB_ERR_CONSTRAINT_VIOLATION;
2178 el2 = ldb_msg_find_element(msg, "pwdLastSet");
2180 return LDB_ERR_CONSTRAINT_VIOLATION;
2183 return LDB_ERR_CONSTRAINT_VIOLATION;
2186 io->g.last_set = samdb_result_nttime(msg, "pwdLastSet", 0);
2190 ret = msg_find_old_and_new_pwd_val(msg, "pwdLastSet",
2191 io->ac->req->operation,
2192 &new_val, &old_val);
2193 if (ret != LDB_SUCCESS) {
2197 if (old_val != NULL && new_val == NULL) {
2198 ldb_set_errstring(ldb,
2199 "'pwdLastSet' deletion is not allowed!");
2200 return LDB_ERR_UNWILLING_TO_PERFORM;
2203 io->g.last_set = UINT64_MAX;
2204 if (new_val != NULL) {
2205 struct ldb_message *tmp_msg = NULL;
2207 tmp_msg = ldb_msg_new(io->ac);
2208 if (tmp_msg == NULL) {
2209 return ldb_module_oom(io->ac->module);
2212 if (old_val != NULL) {
2213 NTTIME old_last_set = 0;
2215 ret = ldb_msg_add_value(tmp_msg, "oldval",
2217 if (ret != LDB_SUCCESS) {
2221 old_last_set = samdb_result_nttime(tmp_msg,
2224 if (io->u.pwdLastSet != old_last_set) {
2225 return dsdb_module_werror(io->ac->module,
2226 LDB_ERR_NO_SUCH_ATTRIBUTE,
2227 WERR_DS_CANT_REM_MISSING_ATT_VAL,
2228 "setup_last_set_field: old pwdLastSet "
2229 "value not found!");
2233 ret = ldb_msg_add_value(tmp_msg, "newval",
2235 if (ret != LDB_SUCCESS) {
2239 io->g.last_set = samdb_result_nttime(tmp_msg,
2242 } else if (ldb_msg_find_element(msg, "pwdLastSet")) {
2243 ldb_set_errstring(ldb,
2244 "'pwdLastSet' deletion is not allowed!");
2245 return LDB_ERR_UNWILLING_TO_PERFORM;
2246 } else if (io->ac->smartcard_reset) {
2248 * adding UF_SMARTCARD_REQUIRED doesn't update
2249 * pwdLastSet implicitly.
2251 io->ac->update_lastset = false;
2254 /* only 0 or -1 (0xFFFFFFFFFFFFFFFF) are allowed */
2255 switch (io->g.last_set) {
2257 if (!io->ac->pwd_last_set_default) {
2260 if (!io->ac->update_password) {
2265 if (!io->ac->update_password &&
2266 io->u.pwdLastSet != 0 &&
2267 io->u.pwdLastSet != UINT64_MAX)
2270 * Just setting pwdLastSet to -1, while not changing
2271 * any password field has no effect if pwdLastSet
2272 * is already non-zero.
2274 io->ac->update_lastset = false;
2277 /* -1 means set it as now */
2279 io->g.last_set = timeval_to_nttime(&tv);
2282 return dsdb_module_werror(io->ac->module,
2284 WERR_INVALID_PARAMETER,
2285 "setup_last_set_field: "
2286 "pwdLastSet must be 0 or -1 only!");
2289 if (io->ac->req->operation == LDB_ADD) {
2291 * We always need to store the value on add
2297 if (io->g.last_set == io->u.pwdLastSet) {
2299 * Just setting pwdLastSet to 0, is no-op if it's already 0.
2301 io->ac->update_lastset = false;
2307 static int setup_given_passwords(struct setup_password_fields_io *io,
2308 struct setup_password_fields_given *g)
2310 struct ldb_context *ldb;
2313 ldb = ldb_module_get_ctx(io->ac->module);
2315 if (g->cleartext_utf8) {
2316 struct ldb_val *cleartext_utf16_blob;
2318 cleartext_utf16_blob = talloc(io->ac, struct ldb_val);
2319 if (!cleartext_utf16_blob) {
2320 return ldb_oom(ldb);
2322 if (!convert_string_talloc(io->ac,
2324 g->cleartext_utf8->data,
2325 g->cleartext_utf8->length,
2326 (void *)&cleartext_utf16_blob->data,
2327 &cleartext_utf16_blob->length)) {
2328 if (g->cleartext_utf8->length != 0) {
2329 talloc_free(cleartext_utf16_blob);
2330 ldb_asprintf_errstring(ldb,
2331 "setup_password_fields: "
2332 "failed to generate UTF16 password from cleartext UTF8 one for user '%s'!",
2333 io->u.sAMAccountName);
2334 return LDB_ERR_CONSTRAINT_VIOLATION;
2336 /* passwords with length "0" are valid! */
2337 cleartext_utf16_blob->data = NULL;
2338 cleartext_utf16_blob->length = 0;
2341 g->cleartext_utf16 = cleartext_utf16_blob;
2342 } else if (g->cleartext_utf16) {
2343 struct ldb_val *cleartext_utf8_blob;
2345 cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
2346 if (!cleartext_utf8_blob) {
2347 return ldb_oom(ldb);
2349 if (!convert_string_talloc(io->ac,
2350 CH_UTF16MUNGED, CH_UTF8,
2351 g->cleartext_utf16->data,
2352 g->cleartext_utf16->length,
2353 (void *)&cleartext_utf8_blob->data,
2354 &cleartext_utf8_blob->length)) {
2355 if (g->cleartext_utf16->length != 0) {
2356 /* We must bail out here, the input wasn't even
2357 * a multiple of 2 bytes */
2358 talloc_free(cleartext_utf8_blob);
2359 ldb_asprintf_errstring(ldb,
2360 "setup_password_fields: "
2361 "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)!",
2362 io->u.sAMAccountName);
2363 return LDB_ERR_CONSTRAINT_VIOLATION;
2365 /* passwords with length "0" are valid! */
2366 cleartext_utf8_blob->data = NULL;
2367 cleartext_utf8_blob->length = 0;
2370 g->cleartext_utf8 = cleartext_utf8_blob;
2373 if (g->cleartext_utf16) {
2374 struct samr_Password *nt_hash;
2376 nt_hash = talloc(io->ac, struct samr_Password);
2378 return ldb_oom(ldb);
2380 g->nt_hash = nt_hash;
2382 /* compute the new nt hash */
2383 mdfour(nt_hash->hash,
2384 g->cleartext_utf16->data,
2385 g->cleartext_utf16->length);
2388 if (g->cleartext_utf8) {
2389 struct samr_Password *lm_hash;
2391 lm_hash = talloc(io->ac, struct samr_Password);
2393 return ldb_oom(ldb);
2396 /* compute the new lm hash */
2397 ok = E_deshash((char *)g->cleartext_utf8->data, lm_hash->hash);
2399 g->lm_hash = lm_hash;
2401 talloc_free(lm_hash);
2408 static int setup_password_fields(struct setup_password_fields_io *io)
2410 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2411 struct loadparm_context *lp_ctx =
2412 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2413 struct loadparm_context);
2416 ret = setup_last_set_field(io);
2417 if (ret != LDB_SUCCESS) {
2421 if (!io->ac->update_password) {
2425 /* transform the old password (for password changes) */
2426 ret = setup_given_passwords(io, &io->og);
2427 if (ret != LDB_SUCCESS) {
2431 /* transform the new password */
2432 ret = setup_given_passwords(io, &io->n);
2433 if (ret != LDB_SUCCESS) {
2437 if (io->n.cleartext_utf8) {
2438 ret = setup_kerberos_keys(io);
2439 if (ret != LDB_SUCCESS) {
2444 ret = setup_nt_fields(io);
2445 if (ret != LDB_SUCCESS) {
2449 if (lpcfg_lanman_auth(lp_ctx)) {
2450 ret = setup_lm_fields(io);
2451 if (ret != LDB_SUCCESS) {
2455 io->g.lm_hash = NULL;
2456 io->g.lm_history_len = 0;
2459 ret = setup_supplemental_field(io);
2460 if (ret != LDB_SUCCESS) {
2467 static int setup_smartcard_reset(struct setup_password_fields_io *io)
2469 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2470 struct loadparm_context *lp_ctx = talloc_get_type(
2471 ldb_get_opaque(ldb, "loadparm"), struct loadparm_context);
2472 struct supplementalCredentialsBlob scb = { .__ndr_size = 0 };
2473 enum ndr_err_code ndr_err;
2475 if (!io->ac->smartcard_reset) {
2479 io->g.nt_hash = talloc(io->ac, struct samr_Password);
2480 if (io->g.nt_hash == NULL) {
2481 return ldb_module_oom(io->ac->module);
2483 generate_secret_buffer(io->g.nt_hash->hash,
2484 sizeof(io->g.nt_hash->hash));
2485 io->g.nt_history_len = 0;
2487 if (lpcfg_lanman_auth(lp_ctx)) {
2488 io->g.lm_hash = talloc(io->ac, struct samr_Password);
2489 if (io->g.lm_hash == NULL) {
2490 return ldb_module_oom(io->ac->module);
2492 generate_secret_buffer(io->g.lm_hash->hash,
2493 sizeof(io->g.lm_hash->hash));
2495 io->g.lm_hash = NULL;
2497 io->g.lm_history_len = 0;
2500 * We take the "old" value and store it
2501 * with num_packages = 0.
2503 * On "add" we have scb.sub.signature == 0, which
2506 * [0000] 00 00 00 00 00 00 00 00 00 00 00 00 00
2508 * On modify it's likely to be scb.sub.signature ==
2509 * SUPPLEMENTAL_CREDENTIALS_SIGNATURE (0x0050), which results in
2512 * [0000] 00 00 00 00 62 00 00 00 00 00 00 00 20 00 20 00
2513 * [0010] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2514 * [0020] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2515 * [0030] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2516 * [0040] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2517 * [0050] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2518 * [0060] 20 00 20 00 20 00 20 00 20 00 20 00 50 00 00
2520 * See https://bugzilla.samba.org/show_bug.cgi?id=11441
2521 * and ndr_{push,pull}_supplementalCredentialsSubBlob().
2524 scb.sub.num_packages = 0;
2527 * setup 'supplementalCredentials' value without packages
2529 ndr_err = ndr_push_struct_blob(&io->g.supplemental, io->ac,
2531 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
2532 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2533 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2534 ldb_asprintf_errstring(ldb,
2535 "setup_smartcard_reset: "
2536 "failed to push supplementalCredentialsBlob: %s",
2538 return LDB_ERR_OPERATIONS_ERROR;
2541 io->ac->update_password = true;
2545 static int make_error_and_update_badPwdCount(struct setup_password_fields_io *io, WERROR *werror)
2547 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2548 struct ldb_message *mod_msg = NULL;
2552 status = dsdb_update_bad_pwd_count(io->ac, ldb,
2553 io->ac->search_res->message,
2554 io->ac->dom_res->message,
2556 if (!NT_STATUS_IS_OK(status)) {
2560 if (mod_msg == NULL) {
2565 * OK, horrible semantics ahead.
2567 * - We need to abort any existing transaction
2568 * - create a transaction arround the badPwdCount update
2569 * - re-open the transaction so the upper layer
2570 * doesn't know what happened.
2572 * This is needed because returning an error to the upper
2573 * layer will cancel the transaction and undo the badPwdCount
2578 * Checking errors here is a bit pointless.
2579 * What can we do if we can't end the transaction?
2581 ret = ldb_next_del_trans(io->ac->module);
2582 if (ret != LDB_SUCCESS) {
2583 ldb_debug(ldb, LDB_DEBUG_FATAL,
2584 "Failed to abort transaction prior to update of badPwdCount of %s: %s",
2585 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2586 ldb_errstring(ldb));
2588 * just return the original error
2593 /* Likewise, what should we do if we can't open a new transaction? */
2594 ret = ldb_next_start_trans(io->ac->module);
2595 if (ret != LDB_SUCCESS) {
2596 ldb_debug(ldb, LDB_DEBUG_ERROR,
2597 "Failed to open transaction to update badPwdCount of %s: %s",
2598 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2599 ldb_errstring(ldb));
2601 * just return the original error
2606 ret = dsdb_module_modify(io->ac->module, mod_msg,
2607 DSDB_FLAG_NEXT_MODULE,
2609 if (ret != LDB_SUCCESS) {
2610 ldb_debug(ldb, LDB_DEBUG_ERROR,
2611 "Failed to update badPwdCount of %s: %s",
2612 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2613 ldb_errstring(ldb));
2615 * We can only ignore this...
2619 ret = ldb_next_end_trans(io->ac->module);
2620 if (ret != LDB_SUCCESS) {
2621 ldb_debug(ldb, LDB_DEBUG_ERROR,
2622 "Failed to close transaction to update badPwdCount of %s: %s",
2623 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2624 ldb_errstring(ldb));
2626 * We can only ignore this...
2630 ret = ldb_next_start_trans(io->ac->module);
2631 if (ret != LDB_SUCCESS) {
2632 ldb_debug(ldb, LDB_DEBUG_ERROR,
2633 "Failed to open transaction after update of badPwdCount of %s: %s",
2634 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2635 ldb_errstring(ldb));
2637 * We can only ignore this...
2642 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2643 *werror = WERR_INVALID_PASSWORD;
2644 ldb_asprintf_errstring(ldb,
2645 "%08X: %s - check_password_restrictions: "
2646 "The old password specified doesn't match!",
2652 static int check_password_restrictions(struct setup_password_fields_io *io, WERROR *werror)
2654 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2656 struct loadparm_context *lp_ctx =
2657 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2658 struct loadparm_context);
2660 *werror = WERR_INVALID_PARAMETER;
2662 if (!io->ac->update_password) {
2666 /* First check the old password is correct, for password changes */
2667 if (!io->ac->pwd_reset) {
2668 bool nt_hash_checked = false;
2670 /* we need the old nt or lm hash given by the client */
2671 if (!io->og.nt_hash && !io->og.lm_hash) {
2672 ldb_asprintf_errstring(ldb,
2673 "check_password_restrictions: "
2674 "You need to provide the old password in order "
2676 return LDB_ERR_UNWILLING_TO_PERFORM;
2679 /* The password modify through the NT hash is encouraged and
2680 has no problems at all */
2681 if (io->og.nt_hash) {
2682 if (!io->o.nt_hash || memcmp(io->og.nt_hash->hash, io->o.nt_hash->hash, 16) != 0) {
2683 return make_error_and_update_badPwdCount(io, werror);
2686 nt_hash_checked = true;
2689 /* But it is also possible to change a password by the LM hash
2690 * alone for compatibility reasons. This check is optional if
2691 * the NT hash was already checked - otherwise it's mandatory.
2692 * (as the SAMR operations request it). */
2693 if (io->og.lm_hash) {
2694 if ((!io->o.lm_hash && !nt_hash_checked)
2695 || (io->o.lm_hash && memcmp(io->og.lm_hash->hash, io->o.lm_hash->hash, 16) != 0)) {
2696 return make_error_and_update_badPwdCount(io, werror);
2701 if (io->u.restrictions == 0) {
2702 /* FIXME: Is this right? */
2706 /* Password minimum age: yes, this is a minus. The ages are in negative 100nsec units! */
2707 if ((io->u.pwdLastSet - io->ac->status->domain_data.minPwdAge > io->g.last_set) &&
2710 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2711 *werror = WERR_PASSWORD_RESTRICTION;
2712 ldb_asprintf_errstring(ldb,
2713 "%08X: %s - check_password_restrictions: "
2714 "password is too young to change!",
2721 * Fundamental password checks done by the call
2722 * "samdb_check_password".
2723 * It is also in use by "dcesrv_samr_ValidatePassword".
2725 if (io->n.cleartext_utf8 != NULL) {
2726 enum samr_ValidationStatus vstat;
2727 vstat = samdb_check_password(io->ac, lp_ctx,
2728 io->n.cleartext_utf8,
2729 io->ac->status->domain_data.pwdProperties,
2730 io->ac->status->domain_data.minPwdLength);
2732 case SAMR_VALIDATION_STATUS_SUCCESS:
2733 /* perfect -> proceed! */
2736 case SAMR_VALIDATION_STATUS_PWD_TOO_SHORT:
2737 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2738 *werror = WERR_PASSWORD_RESTRICTION;
2739 ldb_asprintf_errstring(ldb,
2740 "%08X: %s - check_password_restrictions: "
2741 "the password is too short. It should be equal or longer than %u characters!",
2744 io->ac->status->domain_data.minPwdLength);
2745 io->ac->status->reject_reason = SAM_PWD_CHANGE_PASSWORD_TOO_SHORT;
2748 case SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH:
2749 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2750 *werror = WERR_PASSWORD_RESTRICTION;
2751 ldb_asprintf_errstring(ldb,
2752 "%08X: %s - check_password_restrictions: "
2753 "the password does not meet the complexity criteria!",
2756 io->ac->status->reject_reason = SAM_PWD_CHANGE_NOT_COMPLEX;
2760 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2761 *werror = WERR_PASSWORD_RESTRICTION;
2762 ldb_asprintf_errstring(ldb,
2763 "%08X: %s - check_password_restrictions: "
2764 "the password doesn't fit due to a miscellaneous restriction!",
2771 if (io->ac->pwd_reset) {
2776 if (io->n.nt_hash) {
2779 /* checks the NT hash password history */
2780 for (i = 0; i < io->o.nt_history_len; i++) {
2781 ret = memcmp(io->n.nt_hash, io->o.nt_history[i].hash, 16);
2783 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2784 *werror = WERR_PASSWORD_RESTRICTION;
2785 ldb_asprintf_errstring(ldb,
2786 "%08X: %s - check_password_restrictions: "
2787 "the password was already used (in history)!",
2790 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
2796 if (io->n.lm_hash) {
2799 /* checks the LM hash password history */
2800 for (i = 0; i < io->o.lm_history_len; i++) {
2801 ret = memcmp(io->n.lm_hash, io->o.lm_history[i].hash, 16);
2803 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2804 *werror = WERR_PASSWORD_RESTRICTION;
2805 ldb_asprintf_errstring(ldb,
2806 "%08X: %s - check_password_restrictions: "
2807 "the password was already used (in history)!",
2810 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
2816 /* are all password changes disallowed? */
2817 if (io->ac->status->domain_data.pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
2818 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2819 *werror = WERR_PASSWORD_RESTRICTION;
2820 ldb_asprintf_errstring(ldb,
2821 "%08X: %s - check_password_restrictions: "
2822 "password changes disabled!",
2828 /* can this user change the password? */
2829 if (io->u.userAccountControl & UF_PASSWD_CANT_CHANGE) {
2830 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2831 *werror = WERR_PASSWORD_RESTRICTION;
2832 ldb_asprintf_errstring(ldb,
2833 "%08X: %s - check_password_restrictions: "
2834 "password can't be changed on this account!",
2843 static int check_password_restrictions_and_log(struct setup_password_fields_io *io)
2846 int ret = check_password_restrictions(io, &werror);
2847 struct ph_context *ac = io->ac;
2849 * Password resets are not authentication events, and if the
2850 * upper layer checked the password and supplied the hash
2851 * values as proof, then this is also not an authentication
2852 * even at this layer (already logged). This is to log LDAP
2856 /* Do not record a failure in the auth log below in the success case */
2857 if (ret == LDB_SUCCESS) {
2861 if (ac->pwd_reset == false && ac->change == NULL) {
2862 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2863 struct imessaging_context *msg_ctx;
2864 struct loadparm_context *lp_ctx
2865 = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"),
2866 struct loadparm_context);
2867 NTSTATUS status = werror_to_ntstatus(werror);
2868 const char *domain_name = lpcfg_sam_name(lp_ctx);
2869 void *opaque_remote_address = NULL;
2871 * Forcing this via the NTLM auth structure is not ideal, but
2872 * it is the most practical option right now, and ensures the
2873 * logs are consistent, even if some elements are always NULL.
2875 struct auth_usersupplied_info ui = {
2876 .mapped_state = true,
2879 .account_name = io->u.sAMAccountName,
2880 .domain_name = domain_name,
2883 .account_name = io->u.sAMAccountName,
2884 .domain_name = domain_name,
2886 .service_description = "LDAP Password Change",
2887 .auth_description = "LDAP Modify",
2888 .password_type = "plaintext"
2891 opaque_remote_address = ldb_get_opaque(ldb,
2893 if (opaque_remote_address == NULL) {
2894 ldb_asprintf_errstring(ldb,
2895 "Failed to obtain remote address for "
2896 "the LDAP client while changing the "
2898 return LDB_ERR_OPERATIONS_ERROR;
2900 ui.remote_host = talloc_get_type(opaque_remote_address,
2901 struct tsocket_address);
2903 msg_ctx = imessaging_client_init(ac, lp_ctx,
2904 ldb_get_event_context(ldb));
2906 ldb_asprintf_errstring(ldb,
2907 "Failed to generate client messaging context in %s",
2908 lpcfg_imessaging_path(ac, lp_ctx));
2909 return LDB_ERR_OPERATIONS_ERROR;
2911 log_authentication_event(msg_ctx,
2916 io->u.sAMAccountName,
2924 static int update_final_msg(struct setup_password_fields_io *io)
2926 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2929 bool update_password = io->ac->update_password;
2930 bool update_scb = io->ac->update_password;
2933 * If we add a user without initial password,
2934 * we need to add replication meta data for
2935 * following attributes:
2941 * If we add a user with initial password or a
2942 * password is changed of an existing user,
2943 * we need to replace the following attributes
2944 * with a forced meta data update, e.g. also
2945 * when updating an empty attribute with an empty value:
2950 * - supplementalCredentials
2953 switch (io->ac->req->operation) {
2955 update_password = true;
2956 el_flags |= DSDB_FLAG_INTERNAL_FORCE_META_DATA;
2959 el_flags |= LDB_FLAG_MOD_REPLACE;
2960 el_flags |= DSDB_FLAG_INTERNAL_FORCE_META_DATA;
2963 return ldb_module_operr(io->ac->module);
2966 if (update_password) {
2967 ret = ldb_msg_add_empty(io->ac->update_msg,
2970 if (ret != LDB_SUCCESS) {
2973 ret = ldb_msg_add_empty(io->ac->update_msg,
2976 if (ret != LDB_SUCCESS) {
2979 ret = ldb_msg_add_empty(io->ac->update_msg,
2982 if (ret != LDB_SUCCESS) {
2985 ret = ldb_msg_add_empty(io->ac->update_msg,
2988 if (ret != LDB_SUCCESS) {
2993 ret = ldb_msg_add_empty(io->ac->update_msg,
2994 "supplementalCredentials",
2996 if (ret != LDB_SUCCESS) {
3000 if (io->ac->update_lastset) {
3001 ret = ldb_msg_add_empty(io->ac->update_msg,
3004 if (ret != LDB_SUCCESS) {
3009 if (io->g.nt_hash != NULL) {
3010 ret = samdb_msg_add_hash(ldb, io->ac,
3014 if (ret != LDB_SUCCESS) {
3018 if (io->g.lm_hash != NULL) {
3019 ret = samdb_msg_add_hash(ldb, io->ac,
3023 if (ret != LDB_SUCCESS) {
3027 if (io->g.nt_history_len > 0) {
3028 ret = samdb_msg_add_hashes(ldb, io->ac,
3032 io->g.nt_history_len);
3033 if (ret != LDB_SUCCESS) {
3037 if (io->g.lm_history_len > 0) {
3038 ret = samdb_msg_add_hashes(ldb, io->ac,
3042 io->g.lm_history_len);
3043 if (ret != LDB_SUCCESS) {
3047 if (io->g.supplemental.length > 0) {
3048 ret = ldb_msg_add_value(io->ac->update_msg,
3049 "supplementalCredentials",
3050 &io->g.supplemental, NULL);
3051 if (ret != LDB_SUCCESS) {
3055 if (io->ac->update_lastset) {
3056 ret = samdb_msg_add_uint64(ldb, io->ac,
3060 if (ret != LDB_SUCCESS) {
3069 * This is intended for use by the "password_hash" module since there
3070 * password changes can be specified through one message element with the
3071 * new password (to set) and another one with the old password (to unset).
3073 * The first which sets a password (new value) can have flags
3074 * (LDB_FLAG_MOD_ADD, LDB_FLAG_MOD_REPLACE) but also none (on "add" operations
3075 * for entries). The latter (old value) has always specified
3076 * LDB_FLAG_MOD_DELETE.
3078 * Returns LDB_ERR_CONSTRAINT_VIOLATION and LDB_ERR_UNWILLING_TO_PERFORM if
3079 * matching message elements are malformed in respect to the set/change rules.
3080 * Otherwise it returns LDB_SUCCESS.
3082 static int msg_find_old_and_new_pwd_val(const struct ldb_message *msg,
3084 enum ldb_request_type operation,
3085 const struct ldb_val **new_val,
3086 const struct ldb_val **old_val)
3097 for (i = 0; i < msg->num_elements; i++) {
3098 if (ldb_attr_cmp(msg->elements[i].name, name) != 0) {
3102 if ((operation == LDB_MODIFY) &&
3103 (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_DELETE)) {
3104 /* 0 values are allowed */
3105 if (msg->elements[i].num_values == 1) {
3106 *old_val = &msg->elements[i].values[0];
3107 } else if (msg->elements[i].num_values > 1) {
3108 return LDB_ERR_CONSTRAINT_VIOLATION;
3110 } else if ((operation == LDB_MODIFY) &&
3111 (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_REPLACE)) {
3112 if (msg->elements[i].num_values > 0) {
3113 *new_val = &msg->elements[i].values[msg->elements[i].num_values - 1];
3115 return LDB_ERR_UNWILLING_TO_PERFORM;
3118 /* Add operations and LDB_FLAG_MOD_ADD */
3119 if (msg->elements[i].num_values > 0) {
3120 *new_val = &msg->elements[i].values[msg->elements[i].num_values - 1];
3122 return LDB_ERR_CONSTRAINT_VIOLATION;
3130 static int setup_io(struct ph_context *ac,
3131 const struct ldb_message *client_msg,
3132 const struct ldb_message *existing_msg,
3133 struct setup_password_fields_io *io)
3135 const struct ldb_val *quoted_utf16, *old_quoted_utf16, *lm_hash, *old_lm_hash;
3136 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3137 struct loadparm_context *lp_ctx = talloc_get_type(
3138 ldb_get_opaque(ldb, "loadparm"), struct loadparm_context);
3140 const struct ldb_message *info_msg = NULL;
3141 struct dom_sid *account_sid = NULL;
3142 int rodc_krbtgt = 0;
3146 /* Some operations below require kerberos contexts */
3148 if (existing_msg != NULL) {
3150 * This is a modify operation
3152 info_msg = existing_msg;
3155 * This is an add operation
3157 info_msg = client_msg;
3160 if (smb_krb5_init_context(ac,
3161 (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"),
3162 &io->smb_krb5_context) != 0) {
3163 return ldb_operr(ldb);
3168 io->u.userAccountControl = ldb_msg_find_attr_as_uint(info_msg,
3169 "userAccountControl", 0);
3170 if (info_msg == existing_msg) {
3172 * We only take pwdLastSet from the existing object
3173 * otherwise we leave it as 0.
3175 * If no attribute is available, e.g. on deleted objects
3176 * we remember that as UINT64_MAX.
3178 io->u.pwdLastSet = samdb_result_nttime(info_msg, "pwdLastSet",
3181 io->u.sAMAccountName = ldb_msg_find_attr_as_string(info_msg,
3182 "sAMAccountName", NULL);
3183 io->u.user_principal_name = ldb_msg_find_attr_as_string(info_msg,
3184 "userPrincipalName", NULL);
3185 io->u.is_computer = ldb_msg_check_string_attribute(info_msg, "objectClass", "computer");
3187 /* Ensure it has an objectSID too */
3188 io->u.account_sid = samdb_result_dom_sid(ac, info_msg, "objectSid");
3189 if (io->u.account_sid != NULL) {
3193 status = dom_sid_split_rid(account_sid, io->u.account_sid, NULL, &rid);
3194 if (NT_STATUS_IS_OK(status)) {
3195 if (rid == DOMAIN_RID_KRBTGT) {
3196 io->u.is_krbtgt = true;
3201 rodc_krbtgt = ldb_msg_find_attr_as_int(info_msg,
3202 "msDS-SecondaryKrbTgtNumber", 0);
3203 if (rodc_krbtgt != 0) {
3204 io->u.is_krbtgt = true;
3207 if (io->u.sAMAccountName == NULL) {
3208 ldb_asprintf_errstring(ldb,
3209 "setup_io: sAMAccountName attribute is missing on %s for attempted password set/change",
3210 ldb_dn_get_linearized(info_msg->dn));
3212 return LDB_ERR_CONSTRAINT_VIOLATION;
3215 if (io->u.userAccountControl & UF_INTERDOMAIN_TRUST_ACCOUNT) {
3216 struct ldb_control *permit_trust = ldb_request_get_control(ac->req,
3217 DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID);
3219 if (permit_trust == NULL) {
3220 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
3221 ldb_asprintf_errstring(ldb,
3222 "%08X: %s - setup_io: changing the interdomain trust password "
3223 "on %s not allowed via LDAP. Use LSA or NETLOGON",
3224 W_ERROR_V(WERR_ACCESS_DENIED),
3226 ldb_dn_get_linearized(info_msg->dn));
3231 /* Only non-trust accounts have restrictions (possibly this test is the
3232 * wrong way around, but we like to be restrictive if possible */
3233 io->u.restrictions = !(io->u.userAccountControl
3234 & (UF_INTERDOMAIN_TRUST_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT
3235 | UF_SERVER_TRUST_ACCOUNT));
3237 if (io->u.is_krbtgt) {
3238 io->u.restrictions = 0;
3239 io->ac->status->domain_data.pwdHistoryLength =
3240 MAX(io->ac->status->domain_data.pwdHistoryLength, 3);
3243 if (ac->userPassword) {
3244 ret = msg_find_old_and_new_pwd_val(client_msg, "userPassword",
3246 &io->n.cleartext_utf8,
3247 &io->og.cleartext_utf8);
3248 if (ret != LDB_SUCCESS) {
3249 ldb_asprintf_errstring(ldb,
3251 "it's only allowed to set the old password once!");
3256 if (io->n.cleartext_utf8 != NULL) {
3257 struct ldb_val *cleartext_utf8_blob;
3260 cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
3261 if (!cleartext_utf8_blob) {
3262 return ldb_oom(ldb);
3265 *cleartext_utf8_blob = *io->n.cleartext_utf8;
3267 /* make sure we have a null terminated string */
3268 p = talloc_strndup(cleartext_utf8_blob,
3269 (const char *)io->n.cleartext_utf8->data,
3270 io->n.cleartext_utf8->length);
3271 if ((p == NULL) && (io->n.cleartext_utf8->length > 0)) {
3272 return ldb_oom(ldb);
3274 cleartext_utf8_blob->data = (uint8_t *)p;
3276 io->n.cleartext_utf8 = cleartext_utf8_blob;
3279 ret = msg_find_old_and_new_pwd_val(client_msg, "clearTextPassword",
3281 &io->n.cleartext_utf16,
3282 &io->og.cleartext_utf16);
3283 if (ret != LDB_SUCCESS) {
3284 ldb_asprintf_errstring(ldb,
3286 "it's only allowed to set the old password once!");
3290 /* this rather strange looking piece of code is there to
3291 handle a ldap client setting a password remotely using the
3292 unicodePwd ldap field. The syntax is that the password is
3293 in UTF-16LE, with a " at either end. Unfortunately the
3294 unicodePwd field is also used to store the nt hashes
3295 internally in Samba, and is used in the nt hash format on
3296 the wire in DRS replication, so we have a single name for
3297 two distinct values. The code below leaves us with a small
3298 chance (less than 1 in 2^32) of a mixup, if someone manages
3299 to create a MD4 hash which starts and ends in 0x22 0x00, as
3300 that would then be treated as a UTF16 password rather than
3303 ret = msg_find_old_and_new_pwd_val(client_msg, "unicodePwd",
3307 if (ret != LDB_SUCCESS) {
3308 ldb_asprintf_errstring(ldb,
3310 "it's only allowed to set the old password once!");
3314 /* Checks and converts the actual "unicodePwd" attribute */
3315 if (!ac->hash_values &&
3317 quoted_utf16->length >= 4 &&
3318 quoted_utf16->data[0] == '"' &&
3319 quoted_utf16->data[1] == 0 &&
3320 quoted_utf16->data[quoted_utf16->length-2] == '"' &&
3321 quoted_utf16->data[quoted_utf16->length-1] == 0) {
3322 struct ldb_val *quoted_utf16_2;
3324 if (io->n.cleartext_utf16) {
3325 /* refuse the change if someone wants to change with
3326 with both UTF16 possibilities at the same time... */
3327 ldb_asprintf_errstring(ldb,
3329 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
3330 return LDB_ERR_UNWILLING_TO_PERFORM;
3334 * adapt the quoted UTF16 string to be a real
3337 quoted_utf16_2 = talloc(io->ac, struct ldb_val);
3338 if (quoted_utf16_2 == NULL) {
3339 return ldb_oom(ldb);
3342 quoted_utf16_2->data = quoted_utf16->data + 2;
3343 quoted_utf16_2->length = quoted_utf16->length-4;
3344 io->n.cleartext_utf16 = quoted_utf16_2;
3345 io->n.nt_hash = NULL;
3347 } else if (quoted_utf16) {
3348 /* We have only the hash available -> so no plaintext here */
3349 if (!ac->hash_values) {
3350 /* refuse the change if someone wants to change
3351 the hash without control specified... */
3352 ldb_asprintf_errstring(ldb,
3354 "it's not allowed to set the NT hash password directly'");
3355 /* this looks odd but this is what Windows does:
3356 returns "UNWILLING_TO_PERFORM" on wrong
3357 password sets and "CONSTRAINT_VIOLATION" on
3358 wrong password changes. */
3359 if (old_quoted_utf16 == NULL) {
3360 return LDB_ERR_UNWILLING_TO_PERFORM;
3363 return LDB_ERR_CONSTRAINT_VIOLATION;
3366 io->n.nt_hash = talloc(io->ac, struct samr_Password);
3367 memcpy(io->n.nt_hash->hash, quoted_utf16->data,
3368 MIN(quoted_utf16->length, sizeof(io->n.nt_hash->hash)));
3371 /* Checks and converts the previous "unicodePwd" attribute */
3372 if (!ac->hash_values &&
3374 old_quoted_utf16->length >= 4 &&
3375 old_quoted_utf16->data[0] == '"' &&
3376 old_quoted_utf16->data[1] == 0 &&
3377 old_quoted_utf16->data[old_quoted_utf16->length-2] == '"' &&
3378 old_quoted_utf16->data[old_quoted_utf16->length-1] == 0) {
3379 struct ldb_val *old_quoted_utf16_2;
3381 if (io->og.cleartext_utf16) {
3382 /* refuse the change if someone wants to change with
3383 both UTF16 possibilities at the same time... */
3384 ldb_asprintf_errstring(ldb,
3386 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
3387 return LDB_ERR_UNWILLING_TO_PERFORM;
3391 * adapt the quoted UTF16 string to be a real
3394 old_quoted_utf16_2 = talloc(io->ac, struct ldb_val);
3395 if (old_quoted_utf16_2 == NULL) {
3396 return ldb_oom(ldb);
3399 old_quoted_utf16_2->data = old_quoted_utf16->data + 2;
3400 old_quoted_utf16_2->length = old_quoted_utf16->length-4;
3402 io->og.cleartext_utf16 = old_quoted_utf16_2;
3403 io->og.nt_hash = NULL;
3404 } else if (old_quoted_utf16) {
3405 /* We have only the hash available -> so no plaintext here */
3406 if (!ac->hash_values) {
3407 /* refuse the change if someone wants to change
3408 the hash without control specified... */
3409 ldb_asprintf_errstring(ldb,
3411 "it's not allowed to set the NT hash password directly'");
3412 return LDB_ERR_UNWILLING_TO_PERFORM;
3415 io->og.nt_hash = talloc(io->ac, struct samr_Password);
3416 memcpy(io->og.nt_hash->hash, old_quoted_utf16->data,
3417 MIN(old_quoted_utf16->length, sizeof(io->og.nt_hash->hash)));
3420 /* Handles the "dBCSPwd" attribute (LM hash) */
3421 io->n.lm_hash = NULL; io->og.lm_hash = NULL;
3422 ret = msg_find_old_and_new_pwd_val(client_msg, "dBCSPwd",
3424 &lm_hash, &old_lm_hash);
3425 if (ret != LDB_SUCCESS) {
3426 ldb_asprintf_errstring(ldb,
3428 "it's only allowed to set the old password once!");
3432 if (((lm_hash != NULL) || (old_lm_hash != NULL)) && (!ac->hash_values)) {
3433 /* refuse the change if someone wants to change the hash
3434 without control specified... */
3435 ldb_asprintf_errstring(ldb,
3437 "it's not allowed to set the LM hash password directly'");
3438 return LDB_ERR_UNWILLING_TO_PERFORM;
3441 if (lpcfg_lanman_auth(lp_ctx) && (lm_hash != NULL)) {
3442 io->n.lm_hash = talloc(io->ac, struct samr_Password);
3443 memcpy(io->n.lm_hash->hash, lm_hash->data, MIN(lm_hash->length,
3444 sizeof(io->n.lm_hash->hash)));
3446 if (lpcfg_lanman_auth(lp_ctx) && (old_lm_hash != NULL)) {
3447 io->og.lm_hash = talloc(io->ac, struct samr_Password);
3448 memcpy(io->og.lm_hash->hash, old_lm_hash->data, MIN(old_lm_hash->length,
3449 sizeof(io->og.lm_hash->hash)));
3453 * Handles the password change control if it's specified. It has the
3454 * precedance and overrides already specified old password values of
3455 * change requests (but that shouldn't happen since the control is
3456 * fully internal and only used in conjunction with replace requests!).
3458 if (ac->change != NULL) {
3459 io->og.nt_hash = NULL;
3460 if (ac->change->old_nt_pwd_hash != NULL) {
3461 io->og.nt_hash = talloc_memdup(io->ac,
3462 ac->change->old_nt_pwd_hash,
3463 sizeof(struct samr_Password));
3465 io->og.lm_hash = NULL;
3466 if (lpcfg_lanman_auth(lp_ctx) && (ac->change->old_lm_pwd_hash != NULL)) {
3467 io->og.lm_hash = talloc_memdup(io->ac,
3468 ac->change->old_lm_pwd_hash,
3469 sizeof(struct samr_Password));
3473 /* refuse the change if someone wants to change the clear-
3474 text and supply his own hashes at the same time... */
3475 if ((io->n.cleartext_utf8 || io->n.cleartext_utf16)
3476 && (io->n.nt_hash || io->n.lm_hash)) {
3477 ldb_asprintf_errstring(ldb,
3479 "it's only allowed to set the password in form of cleartext attributes or as hashes");
3480 return LDB_ERR_UNWILLING_TO_PERFORM;
3483 /* refuse the change if someone wants to change the password
3484 using both plaintext methods (UTF8 and UTF16) at the same time... */
3485 if (io->n.cleartext_utf8 && io->n.cleartext_utf16) {
3486 ldb_asprintf_errstring(ldb,
3488 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
3489 return LDB_ERR_UNWILLING_TO_PERFORM;
3492 /* refuse the change if someone tries to set/change the password by
3493 * the lanman hash alone and we've deactivated that mechanism. This
3494 * would end in an account without any password! */
3495 if (io->ac->update_password
3496 && (!io->n.cleartext_utf8) && (!io->n.cleartext_utf16)
3497 && (!io->n.nt_hash) && (!io->n.lm_hash)) {
3498 ldb_asprintf_errstring(ldb,
3500 "It's not possible to delete the password (changes using the LAN Manager hash alone could be deactivated)!");
3501 /* on "userPassword" and "clearTextPassword" we've to return
3502 * something different, since these are virtual attributes */
3503 if ((ldb_msg_find_element(client_msg, "userPassword") != NULL) ||
3504 (ldb_msg_find_element(client_msg, "clearTextPassword") != NULL)) {
3505 return LDB_ERR_CONSTRAINT_VIOLATION;
3507 return LDB_ERR_UNWILLING_TO_PERFORM;
3510 /* refuse the change if someone wants to compare against a plaintext
3511 or hash at the same time for a "password modify" operation... */
3512 if ((io->og.cleartext_utf8 || io->og.cleartext_utf16)
3513 && (io->og.nt_hash || io->og.lm_hash)) {
3514 ldb_asprintf_errstring(ldb,
3516 "it's only allowed to provide the old password in form of cleartext attributes or as hashes");
3517 return LDB_ERR_UNWILLING_TO_PERFORM;
3520 /* refuse the change if someone wants to compare against both
3521 * plaintexts at the same time for a "password modify" operation... */
3522 if (io->og.cleartext_utf8 && io->og.cleartext_utf16) {
3523 ldb_asprintf_errstring(ldb,
3525 "it's only allowed to provide the old cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
3526 return LDB_ERR_UNWILLING_TO_PERFORM;
3529 /* Decides if we have a password modify or password reset operation */
3530 if (ac->req->operation == LDB_ADD) {
3531 /* On "add" we have only "password reset" */
3532 ac->pwd_reset = true;
3533 } else if (ac->req->operation == LDB_MODIFY) {
3534 if (io->og.cleartext_utf8 || io->og.cleartext_utf16
3535 || io->og.nt_hash || io->og.lm_hash) {
3536 /* If we have an old password specified then for sure it
3537 * is a user "password change" */
3538 ac->pwd_reset = false;
3540 /* Otherwise we have also here a "password reset" */
3541 ac->pwd_reset = true;
3544 /* this shouldn't happen */
3545 return ldb_operr(ldb);
3548 if (io->u.is_krbtgt) {
3551 size_t diff = max - min;
3553 struct ldb_val *krbtgt_utf16 = NULL;
3555 if (!ac->pwd_reset) {
3556 return dsdb_module_werror(ac->module,
3557 LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS,
3558 WERR_DS_ATT_ALREADY_EXISTS,
3559 "Password change on krbtgt not permitted!");
3562 if (io->n.cleartext_utf16 == NULL) {
3563 return dsdb_module_werror(ac->module,
3564 LDB_ERR_UNWILLING_TO_PERFORM,
3565 WERR_DS_INVALID_ATTRIBUTE_SYNTAX,
3566 "Password reset on krbtgt requires UTF16!");
3570 * Instead of taking the callers value,
3571 * we just generate a new random value here.
3573 * Include null termination in the array.
3578 generate_random_buffer((uint8_t *)&tmp, sizeof(tmp));
3585 krbtgt_utf16 = talloc_zero(io->ac, struct ldb_val);
3586 if (krbtgt_utf16 == NULL) {
3587 return ldb_oom(ldb);
3590 *krbtgt_utf16 = data_blob_talloc_zero(krbtgt_utf16,
3592 if (krbtgt_utf16->data == NULL) {
3593 return ldb_oom(ldb);
3595 krbtgt_utf16->length = len * 2;
3596 generate_secret_buffer(krbtgt_utf16->data,
3597 krbtgt_utf16->length);
3598 io->n.cleartext_utf16 = krbtgt_utf16;
3601 if (existing_msg != NULL) {
3604 if (ac->pwd_reset) {
3605 /* Get the old password from the database */
3606 status = samdb_result_passwords_no_lockout(ac,
3612 /* Get the old password from the database */
3613 status = samdb_result_passwords(ac,
3620 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCOUNT_LOCKED_OUT)) {
3621 return dsdb_module_werror(ac->module,
3622 LDB_ERR_CONSTRAINT_VIOLATION,
3623 WERR_ACCOUNT_LOCKED_OUT,
3624 "Password change not permitted,"
3625 " account locked out!");
3628 if (!NT_STATUS_IS_OK(status)) {
3630 * This only happens if the database has gone weird,
3631 * not if we are just missing the passwords
3633 return ldb_operr(ldb);
3636 io->o.nt_history_len = samdb_result_hashes(ac, existing_msg,
3639 io->o.lm_history_len = samdb_result_hashes(ac, existing_msg,
3642 io->o.supplemental = ldb_msg_find_ldb_val(existing_msg,
3643 "supplementalCredentials");
3645 if (io->o.supplemental != NULL) {
3646 enum ndr_err_code ndr_err;
3648 ndr_err = ndr_pull_struct_blob_all(io->o.supplemental, io->ac,
3650 (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
3651 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3652 status = ndr_map_error2ntstatus(ndr_err);
3653 ldb_asprintf_errstring(ldb,
3654 "setup_io: failed to pull "
3655 "old supplementalCredentialsBlob: %s",
3657 return LDB_ERR_OPERATIONS_ERROR;
3665 static struct ph_context *ph_init_context(struct ldb_module *module,
3666 struct ldb_request *req,
3668 bool update_password)
3670 struct ldb_context *ldb;
3671 struct ph_context *ac;
3672 struct loadparm_context *lp_ctx = NULL;
3674 ldb = ldb_module_get_ctx(module);
3676 ac = talloc_zero(req, struct ph_context);
3678 ldb_set_errstring(ldb, "Out of Memory");
3682 ac->module = module;
3684 ac->userPassword = userPassword;
3685 ac->update_password = update_password;
3686 ac->update_lastset = true;
3688 lp_ctx = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"),
3689 struct loadparm_context);
3690 ac->gpg_key_ids = lpcfg_password_hash_gpg_key_ids(lp_ctx);
3691 ac->userPassword_schemes
3692 = lpcfg_password_hash_userpassword_schemes(lp_ctx);
3696 static void ph_apply_controls(struct ph_context *ac)
3698 struct ldb_control *ctrl;
3700 ac->change_status = false;
3701 ctrl = ldb_request_get_control(ac->req,
3702 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID);
3704 ac->change_status = true;
3706 /* Mark the "change status" control as uncritical (done) */
3707 ctrl->critical = false;
3710 ac->hash_values = false;
3711 ctrl = ldb_request_get_control(ac->req,
3712 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID);
3714 ac->hash_values = true;
3716 /* Mark the "hash values" control as uncritical (done) */
3717 ctrl->critical = false;
3720 ctrl = ldb_request_get_control(ac->req,
3721 DSDB_CONTROL_PASSWORD_CHANGE_OID);
3723 ac->change = (struct dsdb_control_password_change *) ctrl->data;
3725 /* Mark the "change" control as uncritical (done) */
3726 ctrl->critical = false;
3729 ac->pwd_last_set_bypass = false;
3730 ctrl = ldb_request_get_control(ac->req,
3731 DSDB_CONTROL_PASSWORD_BYPASS_LAST_SET_OID);
3733 ac->pwd_last_set_bypass = true;
3735 /* Mark the "bypass pwdLastSet" control as uncritical (done) */
3736 ctrl->critical = false;
3739 ac->pwd_last_set_default = false;
3740 ctrl = ldb_request_get_control(ac->req,
3741 DSDB_CONTROL_PASSWORD_DEFAULT_LAST_SET_OID);
3743 ac->pwd_last_set_default = true;
3745 /* Mark the "bypass pwdLastSet" control as uncritical (done) */
3746 ctrl->critical = false;
3749 ac->smartcard_reset = false;
3750 ctrl = ldb_request_get_control(ac->req,
3751 DSDB_CONTROL_PASSWORD_USER_ACCOUNT_CONTROL_OID);
3753 struct dsdb_control_password_user_account_control *uac = NULL;
3754 uint32_t added_flags = 0;
3756 uac = talloc_get_type_abort(ctrl->data,
3757 struct dsdb_control_password_user_account_control);
3759 added_flags = uac->new_flags & ~uac->old_flags;
3761 if (added_flags & UF_SMARTCARD_REQUIRED) {
3762 ac->smartcard_reset = true;
3765 /* Mark the "smartcard required" control as uncritical (done) */
3766 ctrl->critical = false;
3770 static int ph_op_callback(struct ldb_request *req, struct ldb_reply *ares)
3772 struct ph_context *ac;
3774 ac = talloc_get_type(req->context, struct ph_context);
3777 return ldb_module_done(ac->req, NULL, NULL,
3778 LDB_ERR_OPERATIONS_ERROR);
3781 if (ares->type == LDB_REPLY_REFERRAL) {
3782 return ldb_module_send_referral(ac->req, ares->referral);
3785 if ((ares->error != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
3786 /* On success and trivial errors a status control is being
3787 * added (used for example by the "samdb_set_password" call) */
3788 ldb_reply_add_control(ares,
3789 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
3794 if (ares->error != LDB_SUCCESS) {
3795 return ldb_module_done(ac->req, ares->controls,
3796 ares->response, ares->error);
3799 if (ares->type != LDB_REPLY_DONE) {
3801 return ldb_module_done(ac->req, NULL, NULL,
3802 LDB_ERR_OPERATIONS_ERROR);
3805 return ldb_module_done(ac->req, ares->controls,
3806 ares->response, ares->error);
3809 static int password_hash_add_do_add(struct ph_context *ac);
3810 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares);
3811 static int password_hash_mod_search_self(struct ph_context *ac);
3812 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares);
3813 static int password_hash_mod_do_mod(struct ph_context *ac);
3815 static int get_domain_data_callback(struct ldb_request *req,
3816 struct ldb_reply *ares)
3818 struct ldb_context *ldb;
3819 struct ph_context *ac;
3820 struct loadparm_context *lp_ctx;
3821 int ret = LDB_SUCCESS;
3823 ac = talloc_get_type(req->context, struct ph_context);
3824 ldb = ldb_module_get_ctx(ac->module);
3827 ret = LDB_ERR_OPERATIONS_ERROR;
3830 if (ares->error != LDB_SUCCESS) {
3831 return ldb_module_done(ac->req, ares->controls,
3832 ares->response, ares->error);
3835 switch (ares->type) {
3836 case LDB_REPLY_ENTRY:
3837 if (ac->status != NULL) {
3840 ldb_set_errstring(ldb, "Too many results");
3841 ret = LDB_ERR_OPERATIONS_ERROR;
3845 /* Setup the "status" structure (used as control later) */
3846 ac->status = talloc_zero(ac->req,
3847 struct dsdb_control_password_change_status);
3848 if (ac->status == NULL) {
3852 ret = LDB_ERR_OPERATIONS_ERROR;
3856 /* Setup the "domain data" structure */
3857 ac->status->domain_data.pwdProperties =
3858 ldb_msg_find_attr_as_uint(ares->message, "pwdProperties", -1);
3859 ac->status->domain_data.pwdHistoryLength =
3860 ldb_msg_find_attr_as_uint(ares->message, "pwdHistoryLength", -1);
3861 ac->status->domain_data.maxPwdAge =
3862 ldb_msg_find_attr_as_int64(ares->message, "maxPwdAge", -1);
3863 ac->status->domain_data.minPwdAge =
3864 ldb_msg_find_attr_as_int64(ares->message, "minPwdAge", -1);
3865 ac->status->domain_data.minPwdLength =
3866 ldb_msg_find_attr_as_uint(ares->message, "minPwdLength", -1);
3867 ac->status->domain_data.store_cleartext =
3868 ac->status->domain_data.pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
3870 /* For a domain DN, this puts things in dotted notation */
3871 /* For builtin domains, this will give details for the host,
3872 * but that doesn't really matter, as it's just used for salt
3873 * and kerberos principals, which don't exist here */
3875 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3876 struct loadparm_context);
3878 ac->status->domain_data.dns_domain = lpcfg_dnsdomain(lp_ctx);
3879 ac->status->domain_data.realm = lpcfg_realm(lp_ctx);
3880 ac->status->domain_data.netbios_domain = lpcfg_sam_name(lp_ctx);
3882 ac->status->reject_reason = SAM_PWD_CHANGE_NO_ERROR;
3884 if (ac->dom_res != NULL) {
3887 ldb_set_errstring(ldb, "Too many results");
3888 ret = LDB_ERR_OPERATIONS_ERROR;
3892 ac->dom_res = talloc_steal(ac, ares);
3896 case LDB_REPLY_REFERRAL:
3902 case LDB_REPLY_DONE:
3904 /* call the next step */
3905 switch (ac->req->operation) {
3907 ret = password_hash_add_do_add(ac);
3911 ret = password_hash_mod_do_mod(ac);
3915 ret = LDB_ERR_OPERATIONS_ERROR;
3922 if (ret != LDB_SUCCESS) {
3923 struct ldb_reply *new_ares;
3925 new_ares = talloc_zero(ac->req, struct ldb_reply);
3926 if (new_ares == NULL) {
3928 return ldb_module_done(ac->req, NULL, NULL,
3929 LDB_ERR_OPERATIONS_ERROR);
3932 new_ares->error = ret;
3933 if ((ret != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
3934 /* On success and trivial errors a status control is being
3935 * added (used for example by the "samdb_set_password" call) */
3936 ldb_reply_add_control(new_ares,
3937 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
3942 return ldb_module_done(ac->req, new_ares->controls,
3943 new_ares->response, new_ares->error);
3949 static int build_domain_data_request(struct ph_context *ac)
3951 /* attrs[] is returned from this function in
3952 ac->dom_req->op.search.attrs, so it must be static, as
3953 otherwise the compiler can put it on the stack */
3954 struct ldb_context *ldb;
3955 static const char * const attrs[] = { "pwdProperties",
3961 "lockOutObservationWindow",
3965 ldb = ldb_module_get_ctx(ac->module);
3967 ret = ldb_build_search_req(&ac->dom_req, ldb, ac,
3968 ldb_get_default_basedn(ldb),
3972 ac, get_domain_data_callback,
3974 LDB_REQ_SET_LOCATION(ac->dom_req);
3978 static int password_hash_needed(struct ldb_module *module,
3979 struct ldb_request *req,
3980 struct ph_context **_ac)
3982 struct ldb_context *ldb = ldb_module_get_ctx(module);
3983 const char *operation = NULL;
3984 const struct ldb_message *msg = NULL;
3985 struct ph_context *ac = NULL;
3986 const char *passwordAttrs[] = {
3988 "clearTextPassword",
3993 const char **a = NULL;
3994 unsigned int attr_cnt = 0;
3995 struct ldb_control *bypass = NULL;
3996 struct ldb_control *uac_ctrl = NULL;
3997 bool userPassword = dsdb_user_password_support(module, req, req);
3998 bool update_password = false;
3999 bool processing_needed = false;
4003 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_needed\n");
4005 switch (req->operation) {
4008 msg = req->op.add.message;
4011 operation = "modify";
4012 msg = req->op.mod.message;
4015 return ldb_next_request(module, req);
4018 if (ldb_dn_is_special(msg->dn)) { /* do not manipulate our control entries */
4019 return ldb_next_request(module, req);
4022 bypass = ldb_request_get_control(req,
4023 DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID);
4024 if (bypass != NULL) {
4025 /* Mark the "bypass" control as uncritical (done) */
4026 bypass->critical = false;
4027 ldb_debug(ldb, LDB_DEBUG_TRACE,
4028 "password_hash_needed(%s) (bypassing)\n",
4030 return password_hash_bypass(module, req);
4033 /* nobody must touch password histories and 'supplementalCredentials' */
4034 if (ldb_msg_find_element(msg, "ntPwdHistory")) {
4035 return LDB_ERR_UNWILLING_TO_PERFORM;
4037 if (ldb_msg_find_element(msg, "lmPwdHistory")) {
4038 return LDB_ERR_UNWILLING_TO_PERFORM;
4040 if (ldb_msg_find_element(msg, "supplementalCredentials")) {
4041 return LDB_ERR_UNWILLING_TO_PERFORM;
4045 * If no part of this touches the 'userPassword' OR 'clearTextPassword'
4046 * OR 'unicodePwd' OR 'dBCSPwd' we don't need to make any changes.
4047 * For password changes/set there should be a 'delete' or a 'modify'
4048 * on these attributes.
4050 for (a = passwordAttrs; *a != NULL; a++) {
4051 if ((!userPassword) && (ldb_attr_cmp(*a, "userPassword") == 0)) {
4055 if (ldb_msg_find_element(msg, *a) != NULL) {
4056 /* MS-ADTS 3.1.1.3.1.5.2 */
4057 if ((ldb_attr_cmp(*a, "userPassword") == 0) &&
4058 (dsdb_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
4059 return LDB_ERR_CONSTRAINT_VIOLATION;
4067 update_password = true;
4068 processing_needed = true;
4071 if (ldb_msg_find_element(msg, "pwdLastSet")) {
4072 processing_needed = true;
4075 uac_ctrl = ldb_request_get_control(req,
4076 DSDB_CONTROL_PASSWORD_USER_ACCOUNT_CONTROL_OID);
4077 if (uac_ctrl != NULL) {
4078 struct dsdb_control_password_user_account_control *uac = NULL;
4079 uint32_t added_flags = 0;
4081 uac = talloc_get_type_abort(uac_ctrl->data,
4082 struct dsdb_control_password_user_account_control);
4084 added_flags = uac->new_flags & ~uac->old_flags;
4086 if (added_flags & UF_SMARTCARD_REQUIRED) {
4087 processing_needed = true;
4091 if (!processing_needed) {
4092 return ldb_next_request(module, req);
4095 ac = ph_init_context(module, req, userPassword, update_password);
4097 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
4098 return ldb_operr(ldb);
4100 ph_apply_controls(ac);
4103 * Make a copy in order to apply our modifications
4104 * to the final update
4106 ac->update_msg = ldb_msg_copy_shallow(ac, msg);
4107 if (ac->update_msg == NULL) {
4108 return ldb_oom(ldb);
4112 * Remove all password related attributes.
4114 if (ac->userPassword) {
4115 ldb_msg_remove_attr(ac->update_msg, "userPassword");
4117 ldb_msg_remove_attr(ac->update_msg, "clearTextPassword");
4118 ldb_msg_remove_attr(ac->update_msg, "unicodePwd");
4119 ldb_msg_remove_attr(ac->update_msg, "ntPwdHistory");
4120 ldb_msg_remove_attr(ac->update_msg, "dBCSPwd");
4121 ldb_msg_remove_attr(ac->update_msg, "lmPwdHistory");
4122 ldb_msg_remove_attr(ac->update_msg, "supplementalCredentials");
4123 ldb_msg_remove_attr(ac->update_msg, "pwdLastSet");
4129 static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
4131 struct ldb_context *ldb = ldb_module_get_ctx(module);
4132 struct ph_context *ac = NULL;
4135 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add\n");
4137 ret = password_hash_needed(module, req, &ac);
4138 if (ret != LDB_SUCCESS) {
4145 /* Make sure we are performing the password set action on a (for us)
4146 * valid object. Those are instances of either "user" and/or
4147 * "inetOrgPerson". Otherwise continue with the submodules. */
4148 if ((!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "user"))
4149 && (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "inetOrgPerson"))) {
4153 if (ldb_msg_find_element(req->op.add.message, "clearTextPassword") != NULL) {
4154 ldb_set_errstring(ldb,
4155 "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
4156 return LDB_ERR_NO_SUCH_ATTRIBUTE;
4159 return ldb_next_request(module, req);
4162 /* get user domain data */
4163 ret = build_domain_data_request(ac);
4164 if (ret != LDB_SUCCESS) {
4168 return ldb_next_request(module, ac->dom_req);
4171 static int password_hash_add_do_add(struct ph_context *ac)
4173 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
4174 struct ldb_request *down_req;
4175 struct setup_password_fields_io io;
4178 /* Prepare the internal data structure containing the passwords */
4179 ret = setup_io(ac, ac->req->op.add.message, NULL, &io);
4180 if (ret != LDB_SUCCESS) {
4184 ret = setup_password_fields(&io);
4185 if (ret != LDB_SUCCESS) {
4189 ret = check_password_restrictions_and_log(&io);
4190 if (ret != LDB_SUCCESS) {
4194 ret = setup_smartcard_reset(&io);
4195 if (ret != LDB_SUCCESS) {
4199 ret = update_final_msg(&io);
4200 if (ret != LDB_SUCCESS) {
4204 ret = ldb_build_add_req(&down_req, ldb, ac,
4209 LDB_REQ_SET_LOCATION(down_req);
4210 if (ret != LDB_SUCCESS) {
4214 return ldb_next_request(ac->module, down_req);
4217 static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
4219 struct ldb_context *ldb = ldb_module_get_ctx(module);
4220 struct ph_context *ac = NULL;
4221 const char *passwordAttrs[] = { "userPassword", "clearTextPassword",
4222 "unicodePwd", "dBCSPwd", NULL }, **l;
4223 unsigned int del_attr_cnt, add_attr_cnt, rep_attr_cnt;
4224 struct ldb_message_element *passwordAttr;
4225 struct ldb_message *msg;
4226 struct ldb_request *down_req;
4227 struct ldb_control *restore = NULL;
4231 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
4233 ret = password_hash_needed(module, req, &ac);
4234 if (ret != LDB_SUCCESS) {
4241 /* use a new message structure so that we can modify it */
4242 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
4244 return ldb_oom(ldb);
4247 /* - check for single-valued password attributes
4248 * (if not return "CONSTRAINT_VIOLATION")
4249 * - check that for a password change operation one add and one delete
4251 * (if not return "CONSTRAINT_VIOLATION" or "UNWILLING_TO_PERFORM")
4252 * - check that a password change and a password set operation cannot
4254 * (if not return "UNWILLING_TO_PERFORM")
4255 * - remove all password attributes modifications from the first change
4256 * operation (anything without the passwords) - we will make the real
4257 * modification later */
4261 for (l = passwordAttrs; *l != NULL; l++) {
4262 if ((!ac->userPassword) &&
4263 (ldb_attr_cmp(*l, "userPassword") == 0)) {
4267 while ((passwordAttr = ldb_msg_find_element(msg, *l)) != NULL) {
4268 if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_DELETE) {
4271 if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_ADD) {
4274 if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_REPLACE) {
4277 if ((passwordAttr->num_values != 1) &&
4278 (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_ADD)) {
4280 ldb_asprintf_errstring(ldb,
4281 "'%s' attribute must have exactly one value on add operations!",
4283 return LDB_ERR_CONSTRAINT_VIOLATION;
4285 if ((passwordAttr->num_values > 1) &&
4286 (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_DELETE)) {
4288 ldb_asprintf_errstring(ldb,
4289 "'%s' attribute must have zero or one value(s) on delete operations!",
4291 return LDB_ERR_CONSTRAINT_VIOLATION;
4293 ldb_msg_remove_element(msg, passwordAttr);
4296 if ((del_attr_cnt == 0) && (add_attr_cnt > 0)) {
4298 ldb_set_errstring(ldb,
4299 "Only the add action for a password change specified!");
4300 return LDB_ERR_UNWILLING_TO_PERFORM;
4302 if ((del_attr_cnt > 1) || (add_attr_cnt > 1)) {
4304 ldb_set_errstring(ldb,
4305 "Only one delete and one add action for a password change allowed!");
4306 return LDB_ERR_UNWILLING_TO_PERFORM;
4308 if ((rep_attr_cnt > 0) && ((del_attr_cnt > 0) || (add_attr_cnt > 0))) {
4310 ldb_set_errstring(ldb,
4311 "Either a password change or a password set operation is allowed!");
4312 return LDB_ERR_UNWILLING_TO_PERFORM;
4315 restore = ldb_request_get_control(req,
4316 DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
4317 if (restore == NULL) {
4319 * A tomstone reanimation generates a double update
4322 * So we only remove it without the
4323 * DSDB_CONTROL_RESTORE_TOMBSTONE_OID control.
4325 ldb_msg_remove_attr(msg, "pwdLastSet");
4329 /* if there was nothing else to be modified skip to next step */
4330 if (msg->num_elements == 0) {
4331 return password_hash_mod_search_self(ac);
4335 * Now we apply all changes remaining in msg
4336 * and remove them from our final update_msg
4339 for (i = 0; i < msg->num_elements; i++) {
4340 ldb_msg_remove_attr(ac->update_msg,
4341 msg->elements[i].name);
4344 ret = ldb_build_mod_req(&down_req, ldb, ac,
4347 ac, ph_modify_callback,
4349 LDB_REQ_SET_LOCATION(down_req);
4350 if (ret != LDB_SUCCESS) {
4354 return ldb_next_request(module, down_req);
4357 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
4359 struct ph_context *ac;
4361 ac = talloc_get_type(req->context, struct ph_context);
4364 return ldb_module_done(ac->req, NULL, NULL,
4365 LDB_ERR_OPERATIONS_ERROR);
4368 if (ares->type == LDB_REPLY_REFERRAL) {
4369 return ldb_module_send_referral(ac->req, ares->referral);
4372 if (ares->error != LDB_SUCCESS) {
4373 return ldb_module_done(ac->req, ares->controls,
4374 ares->response, ares->error);
4377 if (ares->type != LDB_REPLY_DONE) {
4379 return ldb_module_done(ac->req, NULL, NULL,
4380 LDB_ERR_OPERATIONS_ERROR);
4385 return password_hash_mod_search_self(ac);
4388 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
4390 struct ldb_context *ldb;
4391 struct ph_context *ac;
4392 int ret = LDB_SUCCESS;
4394 ac = talloc_get_type(req->context, struct ph_context);
4395 ldb = ldb_module_get_ctx(ac->module);
4398 ret = LDB_ERR_OPERATIONS_ERROR;
4401 if (ares->error != LDB_SUCCESS) {
4402 return ldb_module_done(ac->req, ares->controls,
4403 ares->response, ares->error);
4406 /* we are interested only in the single reply (base search) */
4407 switch (ares->type) {
4408 case LDB_REPLY_ENTRY:
4409 /* Make sure we are performing the password change action on a
4410 * (for us) valid object. Those are instances of either "user"
4411 * and/or "inetOrgPerson". Otherwise continue with the
4413 if ((!ldb_msg_check_string_attribute(ares->message, "objectClass", "user"))
4414 && (!ldb_msg_check_string_attribute(ares->message, "objectClass", "inetOrgPerson"))) {
4417 if (ldb_msg_find_element(ac->req->op.mod.message, "clearTextPassword") != NULL) {
4418 ldb_set_errstring(ldb,
4419 "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
4420 ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
4424 ret = ldb_next_request(ac->module, ac->req);
4428 if (ac->search_res != NULL) {
4431 ldb_set_errstring(ldb, "Too many results");
4432 ret = LDB_ERR_OPERATIONS_ERROR;
4436 ac->search_res = talloc_steal(ac, ares);
4440 case LDB_REPLY_REFERRAL:
4441 /* ignore anything else for now */
4446 case LDB_REPLY_DONE:
4449 /* get user domain data */
4450 ret = build_domain_data_request(ac);
4451 if (ret != LDB_SUCCESS) {
4452 return ldb_module_done(ac->req, NULL, NULL, ret);
4455 ret = ldb_next_request(ac->module, ac->dom_req);
4460 if (ret != LDB_SUCCESS) {
4461 return ldb_module_done(ac->req, NULL, NULL, ret);
4467 static int password_hash_mod_search_self(struct ph_context *ac)
4469 struct ldb_context *ldb;
4470 static const char * const attrs[] = { "objectClass",
4471 "userAccountControl",
4472 "msDS-User-Account-Control-Computed",
4476 "userPrincipalName",
4477 "supplementalCredentials",
4485 "msDS-SecondaryKrbTgtNumber",
4487 struct ldb_request *search_req;
4490 ldb = ldb_module_get_ctx(ac->module);
4492 ret = ldb_build_search_req(&search_req, ldb, ac,
4493 ac->req->op.mod.message->dn,
4498 ac, ph_mod_search_callback,
4500 LDB_REQ_SET_LOCATION(search_req);
4501 if (ret != LDB_SUCCESS) {
4505 return ldb_next_request(ac->module, search_req);
4508 static int password_hash_mod_do_mod(struct ph_context *ac)
4510 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
4511 struct ldb_request *mod_req;
4512 struct setup_password_fields_io io;
4515 /* Prepare the internal data structure containing the passwords */
4516 ret = setup_io(ac, ac->req->op.mod.message,
4517 ac->search_res->message, &io);
4518 if (ret != LDB_SUCCESS) {
4522 ret = setup_password_fields(&io);
4523 if (ret != LDB_SUCCESS) {
4527 ret = check_password_restrictions_and_log(&io);
4528 if (ret != LDB_SUCCESS) {
4532 ret = setup_smartcard_reset(&io);
4533 if (ret != LDB_SUCCESS) {
4537 ret = update_final_msg(&io);
4538 if (ret != LDB_SUCCESS) {
4542 ret = ldb_build_mod_req(&mod_req, ldb, ac,
4547 LDB_REQ_SET_LOCATION(mod_req);
4548 if (ret != LDB_SUCCESS) {
4552 return ldb_next_request(ac->module, mod_req);
4555 static const struct ldb_module_ops ldb_password_hash_module_ops = {
4556 .name = "password_hash",
4557 .add = password_hash_add,
4558 .modify = password_hash_modify
4561 int ldb_password_hash_module_init(const char *version)
4564 const char *gversion = NULL;
4565 #endif /* ENABLE_GPGME */
4567 LDB_MODULE_CHECK_VERSION(version);
4571 * Note: this sets a SIGPIPE handler
4572 * if none is active already. See:
4573 * https://www.gnupg.org/documentation/manuals/gpgme/Signal-Handling.html#Signal-Handling
4575 gversion = gpgme_check_version(GPGME_VERSION);
4576 if (gversion == NULL) {
4577 fprintf(stderr, "%s() in %s version[%s]: "
4578 "gpgme_check_version(%s) not available, "
4579 "gpgme_check_version(NULL) => '%s'\n",
4580 __func__, __FILE__, version,
4581 GPGME_VERSION, gpgme_check_version(NULL));
4582 return LDB_ERR_UNAVAILABLE;
4584 #endif /* ENABLE_GPGME */
4586 return ldb_register_module(&ldb_password_hash_module_ops);