4 Copyright (C) Simo Sorce 2004-2008
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2006
6 Copyright (C) Andrew Tridgell 2004
7 Copyright (C) Stefan Metzmacher 2007-2010
8 Copyright (C) Matthias Dieter Wallnöfer 2009-2010
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 * Component: ldb password_hash module
29 * Description: correctly handle AD password changes fields
31 * Author: Andrew Bartlett
32 * Author: Stefan Metzmacher
36 #include "ldb_module.h"
37 #include "libcli/auth/libcli_auth.h"
38 #include "system/kerberos.h"
39 #include "auth/kerberos/kerberos.h"
40 #include "dsdb/samdb/samdb.h"
41 #include "dsdb/samdb/ldb_modules/util.h"
42 #include "dsdb/samdb/ldb_modules/password_modules.h"
43 #include "librpc/gen_ndr/ndr_drsblobs.h"
44 #include "../lib/crypto/crypto.h"
45 #include "param/param.h"
46 #include "lib/krb5_wrap/krb5_samba.h"
53 /* If we have decided there is a reason to work on this request, then
54 * setup all the password hash types correctly.
56 * If we haven't the hashes yet but the password given as plain-text (attributes
57 * 'unicodePwd', 'userPassword' and 'clearTextPassword') we have to check for
58 * the constraints. Once this is done, we calculate the password hashes.
60 * Notice: unlike the real AD which only supports the UTF16 special based
61 * 'unicodePwd' and the UTF8 based 'userPassword' plaintext attribute we
62 * understand also a UTF16 based 'clearTextPassword' one.
63 * The latter is also accessible through LDAP so it can also be set by external
64 * tools and scripts. But be aware that this isn't portable on non SAMBA 4 ADs!
66 * Also when the module receives only the password hashes (possible through
67 * specifying an internal LDB control - for security reasons) some checks are
68 * performed depending on the operation mode (see below) (e.g. if the password
69 * has been in use before if the password memory policy was activated).
71 * Attention: There is a difference between "modify" and "reset" operations
72 * (see MS-ADTS 3.1.1.3.1.5). If the client sends a "add" and "remove"
73 * operation for a password attribute we thread this as a "modify"; if it sends
74 * only a "replace" one we have an (administrative) reset.
76 * Finally, if the administrator has requested that a password history
77 * be maintained, then this should also be written out.
81 /* TODO: [consider always MS-ADTS 3.1.1.3.1.5]
82 * - Check for right connection encryption
85 /* Notice: Definition of "dsdb_control_password_change_status" moved into
89 struct ldb_module *module;
90 struct ldb_request *req;
92 struct ldb_request *dom_req;
93 struct ldb_reply *dom_res;
95 struct ldb_reply *search_res;
97 struct ldb_message *update_msg;
99 struct dsdb_control_password_change_status *status;
100 struct dsdb_control_password_change *change;
102 const char **gpg_key_ids;
108 bool update_password;
110 bool pwd_last_set_bypass;
111 bool pwd_last_set_default;
112 bool smartcard_reset;
116 struct setup_password_fields_io {
117 struct ph_context *ac;
119 struct smb_krb5_context *smb_krb5_context;
121 /* infos about the user account */
123 uint32_t userAccountControl;
125 const char *sAMAccountName;
126 const char *user_principal_name;
128 uint32_t restrictions;
131 /* new credentials and old given credentials */
132 struct setup_password_fields_given {
133 const struct ldb_val *cleartext_utf8;
134 const struct ldb_val *cleartext_utf16;
135 struct samr_Password *nt_hash;
136 struct samr_Password *lm_hash;
139 /* old credentials */
141 struct samr_Password *nt_hash;
142 struct samr_Password *lm_hash;
143 uint32_t nt_history_len;
144 struct samr_Password *nt_history;
145 uint32_t lm_history_len;
146 struct samr_Password *lm_history;
147 const struct ldb_val *supplemental;
148 struct supplementalCredentialsBlob scb;
151 /* generated credentials */
153 struct samr_Password *nt_hash;
154 struct samr_Password *lm_hash;
155 uint32_t nt_history_len;
156 struct samr_Password *nt_history;
157 uint32_t lm_history_len;
158 struct samr_Password *lm_history;
164 struct ldb_val supplemental;
169 static int msg_find_old_and_new_pwd_val(const struct ldb_message *msg,
171 enum ldb_request_type operation,
172 const struct ldb_val **new_val,
173 const struct ldb_val **old_val);
175 static int password_hash_bypass(struct ldb_module *module, struct ldb_request *request)
177 struct ldb_context *ldb = ldb_module_get_ctx(module);
178 const struct ldb_message *msg;
179 struct ldb_message_element *nte;
180 struct ldb_message_element *lme;
181 struct ldb_message_element *nthe;
182 struct ldb_message_element *lmhe;
183 struct ldb_message_element *sce;
185 switch (request->operation) {
187 msg = request->op.add.message;
190 msg = request->op.mod.message;
193 return ldb_next_request(module, request);
196 /* nobody must touch password histories and 'supplementalCredentials' */
197 nte = dsdb_get_single_valued_attr(msg, "unicodePwd",
199 lme = dsdb_get_single_valued_attr(msg, "dBCSPwd",
201 nthe = dsdb_get_single_valued_attr(msg, "ntPwdHistory",
203 lmhe = dsdb_get_single_valued_attr(msg, "lmPwdHistory",
205 sce = dsdb_get_single_valued_attr(msg, "supplementalCredentials",
208 #define CHECK_HASH_ELEMENT(e, min, max) do {\
209 if (e && e->num_values) { \
210 unsigned int _count; \
211 if (e->num_values != 1) { \
212 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
213 "num_values != 1"); \
215 if ((e->values[0].length % 16) != 0) { \
216 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
217 "length % 16 != 0"); \
219 _count = e->values[0].length / 16; \
220 if (_count < min) { \
221 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
224 if (_count > max) { \
225 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
231 CHECK_HASH_ELEMENT(nte, 1, 1);
232 CHECK_HASH_ELEMENT(lme, 1, 1);
233 CHECK_HASH_ELEMENT(nthe, 1, INT32_MAX);
234 CHECK_HASH_ELEMENT(lmhe, 1, INT32_MAX);
236 if (sce && sce->num_values) {
237 enum ndr_err_code ndr_err;
238 struct supplementalCredentialsBlob *scb;
239 struct supplementalCredentialsPackage *scpp = NULL;
240 struct supplementalCredentialsPackage *scpk = NULL;
241 struct supplementalCredentialsPackage *scpkn = NULL;
242 struct supplementalCredentialsPackage *scpct = NULL;
243 DATA_BLOB scpbp = data_blob_null;
244 DATA_BLOB scpbk = data_blob_null;
245 DATA_BLOB scpbkn = data_blob_null;
246 DATA_BLOB scpbct = data_blob_null;
250 if (sce->num_values != 1) {
251 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
255 scb = talloc_zero(request, struct supplementalCredentialsBlob);
257 return ldb_module_oom(module);
260 ndr_err = ndr_pull_struct_blob_all(&sce->values[0], scb, scb,
261 (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
262 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
263 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
264 "ndr_pull_struct_blob_all");
267 if (scb->sub.num_packages < 2) {
268 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
272 for (i=0; i < scb->sub.num_packages; i++) {
275 subblob = strhex_to_data_blob(scb, scb->sub.packages[i].data);
276 if (subblob.data == NULL) {
277 return ldb_module_oom(module);
280 if (strcmp(scb->sub.packages[i].name, "Packages") == 0) {
282 return ldb_error(ldb,
283 LDB_ERR_CONSTRAINT_VIOLATION,
286 scpp = &scb->sub.packages[i];
290 if (strcmp(scb->sub.packages[i].name, "Primary:Kerberos") == 0) {
292 return ldb_error(ldb,
293 LDB_ERR_CONSTRAINT_VIOLATION,
294 "Primary:Kerberos twice");
296 scpk = &scb->sub.packages[i];
300 if (strcmp(scb->sub.packages[i].name, "Primary:Kerberos-Newer-Keys") == 0) {
302 return ldb_error(ldb,
303 LDB_ERR_CONSTRAINT_VIOLATION,
304 "Primary:Kerberos-Newer-Keys twice");
306 scpkn = &scb->sub.packages[i];
310 if (strcmp(scb->sub.packages[i].name, "Primary:CLEARTEXT") == 0) {
312 return ldb_error(ldb,
313 LDB_ERR_CONSTRAINT_VIOLATION,
314 "Primary:CLEARTEXT twice");
316 scpct = &scb->sub.packages[i];
321 data_blob_free(&subblob);
325 return ldb_error(ldb,
326 LDB_ERR_CONSTRAINT_VIOLATION,
327 "Primary:Packages missing");
332 * If Primary:Kerberos is missing w2k8r2 reboots
333 * when a password is changed.
335 return ldb_error(ldb,
336 LDB_ERR_CONSTRAINT_VIOLATION,
337 "Primary:Kerberos missing");
341 struct package_PackagesBlob *p;
344 p = talloc_zero(scb, struct package_PackagesBlob);
346 return ldb_module_oom(module);
349 ndr_err = ndr_pull_struct_blob(&scpbp, p, p,
350 (ndr_pull_flags_fn_t)ndr_pull_package_PackagesBlob);
351 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
352 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
353 "ndr_pull_struct_blob Packages");
356 if (p->names == NULL) {
357 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
358 "Packages names == NULL");
361 for (n = 0; p->names[n]; n++) {
365 if (scb->sub.num_packages != (n + 1)) {
366 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
367 "Packages num_packages != num_names + 1");
374 struct package_PrimaryKerberosBlob *k;
376 k = talloc_zero(scb, struct package_PrimaryKerberosBlob);
378 return ldb_module_oom(module);
381 ndr_err = ndr_pull_struct_blob(&scpbk, k, k,
382 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
383 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
384 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
385 "ndr_pull_struct_blob PrimaryKerberos");
388 if (k->version != 3) {
389 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
390 "PrimaryKerberos version != 3");
393 if (k->ctr.ctr3.salt.string == NULL) {
394 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
395 "PrimaryKerberos salt == NULL");
398 if (strlen(k->ctr.ctr3.salt.string) == 0) {
399 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
400 "PrimaryKerberos strlen(salt) == 0");
403 if (k->ctr.ctr3.num_keys != 2) {
404 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
405 "PrimaryKerberos num_keys != 2");
408 if (k->ctr.ctr3.num_old_keys > k->ctr.ctr3.num_keys) {
409 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
410 "PrimaryKerberos num_old_keys > num_keys");
413 if (k->ctr.ctr3.keys[0].keytype != ENCTYPE_DES_CBC_MD5) {
414 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
415 "PrimaryKerberos key[0] != DES_CBC_MD5");
417 if (k->ctr.ctr3.keys[1].keytype != ENCTYPE_DES_CBC_CRC) {
418 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
419 "PrimaryKerberos key[1] != DES_CBC_CRC");
422 if (k->ctr.ctr3.keys[0].value_len != 8) {
423 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
424 "PrimaryKerberos key[0] value_len != 8");
426 if (k->ctr.ctr3.keys[1].value_len != 8) {
427 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
428 "PrimaryKerberos key[1] value_len != 8");
431 for (i = 0; i < k->ctr.ctr3.num_old_keys; i++) {
432 if (k->ctr.ctr3.old_keys[i].keytype ==
433 k->ctr.ctr3.keys[i].keytype &&
434 k->ctr.ctr3.old_keys[i].value_len ==
435 k->ctr.ctr3.keys[i].value_len) {
439 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
440 "PrimaryKerberos old_keys type/value_len doesn't match");
447 struct package_PrimaryKerberosBlob *k;
449 k = talloc_zero(scb, struct package_PrimaryKerberosBlob);
451 return ldb_module_oom(module);
454 ndr_err = ndr_pull_struct_blob(&scpbkn, k, k,
455 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
456 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
457 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
458 "ndr_pull_struct_blob PrimaryKerberosNeverKeys");
461 if (k->version != 4) {
462 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
463 "KerberosNerverKeys version != 4");
466 if (k->ctr.ctr4.salt.string == NULL) {
467 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
468 "KerberosNewerKeys salt == NULL");
471 if (strlen(k->ctr.ctr4.salt.string) == 0) {
472 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
473 "KerberosNewerKeys strlen(salt) == 0");
476 if (k->ctr.ctr4.num_keys != 4) {
477 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
478 "KerberosNewerKeys num_keys != 2");
481 if (k->ctr.ctr4.num_old_keys > k->ctr.ctr4.num_keys) {
482 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
483 "KerberosNewerKeys num_old_keys > num_keys");
486 if (k->ctr.ctr4.num_older_keys > k->ctr.ctr4.num_old_keys) {
487 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
488 "KerberosNewerKeys num_older_keys > num_old_keys");
491 if (k->ctr.ctr4.keys[0].keytype != ENCTYPE_AES256_CTS_HMAC_SHA1_96) {
492 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
493 "KerberosNewerKeys key[0] != AES256");
495 if (k->ctr.ctr4.keys[1].keytype != ENCTYPE_AES128_CTS_HMAC_SHA1_96) {
496 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
497 "KerberosNewerKeys key[1] != AES128");
499 if (k->ctr.ctr4.keys[2].keytype != ENCTYPE_DES_CBC_MD5) {
500 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
501 "KerberosNewerKeys key[2] != DES_CBC_MD5");
503 if (k->ctr.ctr4.keys[3].keytype != ENCTYPE_DES_CBC_CRC) {
504 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
505 "KerberosNewerKeys key[3] != DES_CBC_CRC");
508 if (k->ctr.ctr4.keys[0].value_len != 32) {
509 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
510 "KerberosNewerKeys key[0] value_len != 32");
512 if (k->ctr.ctr4.keys[1].value_len != 16) {
513 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
514 "KerberosNewerKeys key[1] value_len != 16");
516 if (k->ctr.ctr4.keys[2].value_len != 8) {
517 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
518 "KerberosNewerKeys key[2] value_len != 8");
520 if (k->ctr.ctr4.keys[3].value_len != 8) {
521 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
522 "KerberosNewerKeys key[3] value_len != 8");
527 * Maybe we can check old and older keys here.
528 * But we need to do some tests, if the old keys
529 * can be taken from the PrimaryKerberos blob
530 * (with only des keys), when the domain was upgraded
538 struct package_PrimaryCLEARTEXTBlob *ct;
540 ct = talloc_zero(scb, struct package_PrimaryCLEARTEXTBlob);
542 return ldb_module_oom(module);
545 ndr_err = ndr_pull_struct_blob(&scpbct, ct, ct,
546 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryCLEARTEXTBlob);
547 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
548 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
549 "ndr_pull_struct_blob PrimaryCLEARTEXT");
552 if ((ct->cleartext.length % 2) != 0) {
553 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
554 "PrimaryCLEARTEXT length % 2 != 0");
560 ndr_err = ndr_push_struct_blob(&blob, scb, scb,
561 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
562 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
563 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
564 "ndr_pull_struct_blob_all");
567 if (sce->values[0].length != blob.length) {
568 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
569 "supplementalCredentialsBlob length differ");
572 if (memcmp(sce->values[0].data, blob.data, blob.length) != 0) {
573 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
574 "supplementalCredentialsBlob memcmp differ");
580 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_bypass - validated\n");
581 return ldb_next_request(module, request);
584 /* Get the NT hash, and fill it in as an entry in the password history,
585 and specify it into io->g.nt_hash */
587 static int setup_nt_fields(struct setup_password_fields_io *io)
589 struct ldb_context *ldb;
592 io->g.nt_hash = io->n.nt_hash;
593 ldb = ldb_module_get_ctx(io->ac->module);
595 if (io->ac->status->domain_data.pwdHistoryLength == 0) {
599 /* We might not have an old NT password */
600 io->g.nt_history = talloc_array(io->ac,
601 struct samr_Password,
602 io->ac->status->domain_data.pwdHistoryLength);
603 if (!io->g.nt_history) {
607 for (i = 0; i < MIN(io->ac->status->domain_data.pwdHistoryLength-1,
608 io->o.nt_history_len); i++) {
609 io->g.nt_history[i+1] = io->o.nt_history[i];
611 io->g.nt_history_len = i + 1;
614 io->g.nt_history[0] = *io->g.nt_hash;
617 * TODO: is this correct?
618 * the simular behavior is correct for the lm history case
620 E_md4hash("", io->g.nt_history[0].hash);
626 /* Get the LANMAN hash, and fill it in as an entry in the password history,
627 and specify it into io->g.lm_hash */
629 static int setup_lm_fields(struct setup_password_fields_io *io)
631 struct ldb_context *ldb;
634 io->g.lm_hash = io->n.lm_hash;
635 ldb = ldb_module_get_ctx(io->ac->module);
637 if (io->ac->status->domain_data.pwdHistoryLength == 0) {
641 /* We might not have an old LM password */
642 io->g.lm_history = talloc_array(io->ac,
643 struct samr_Password,
644 io->ac->status->domain_data.pwdHistoryLength);
645 if (!io->g.lm_history) {
649 for (i = 0; i < MIN(io->ac->status->domain_data.pwdHistoryLength-1,
650 io->o.lm_history_len); i++) {
651 io->g.lm_history[i+1] = io->o.lm_history[i];
653 io->g.lm_history_len = i + 1;
656 io->g.lm_history[0] = *io->g.lm_hash;
658 E_deshash("", io->g.lm_history[0].hash);
664 static int setup_kerberos_keys(struct setup_password_fields_io *io)
666 struct ldb_context *ldb;
667 krb5_error_code krb5_ret;
668 krb5_principal salt_principal;
671 krb5_data cleartext_data;
673 ldb = ldb_module_get_ctx(io->ac->module);
674 cleartext_data.data = (char *)io->n.cleartext_utf8->data;
675 cleartext_data.length = io->n.cleartext_utf8->length;
677 /* Many, many thanks to lukeh@padl.com for this
678 * algorithm, described in his Nov 10 2004 mail to
679 * samba-technical@lists.samba.org */
682 * Determine a salting principal
684 if (io->u.is_computer) {
688 name = strlower_talloc(io->ac, io->u.sAMAccountName);
693 if (name[strlen(name)-1] == '$') {
694 name[strlen(name)-1] = '\0';
697 saltbody = talloc_asprintf(io->ac, "%s.%s", name,
698 io->ac->status->domain_data.dns_domain);
703 krb5_ret = smb_krb5_make_principal(io->smb_krb5_context->krb5_context,
705 io->ac->status->domain_data.realm,
706 "host", saltbody, NULL);
707 } else if (io->u.user_principal_name) {
708 char *user_principal_name;
711 user_principal_name = talloc_strdup(io->ac, io->u.user_principal_name);
712 if (!user_principal_name) {
716 p = strchr(user_principal_name, '@');
721 krb5_ret = smb_krb5_make_principal(io->smb_krb5_context->krb5_context,
723 io->ac->status->domain_data.realm,
724 user_principal_name, NULL);
726 krb5_ret = smb_krb5_make_principal(io->smb_krb5_context->krb5_context,
728 io->ac->status->domain_data.realm,
729 io->u.sAMAccountName, NULL);
732 ldb_asprintf_errstring(ldb,
733 "setup_kerberos_keys: "
734 "generation of a salting principal failed: %s",
735 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
737 return LDB_ERR_OPERATIONS_ERROR;
741 * create salt from salt_principal
743 krb5_ret = smb_krb5_get_pw_salt(io->smb_krb5_context->krb5_context,
744 salt_principal, &salt);
745 krb5_free_principal(io->smb_krb5_context->krb5_context, salt_principal);
747 ldb_asprintf_errstring(ldb,
748 "setup_kerberos_keys: "
749 "generation of krb5_salt failed: %s",
750 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
752 return LDB_ERR_OPERATIONS_ERROR;
754 /* create a talloc copy */
755 io->g.salt = talloc_strndup(io->ac,
758 smb_krb5_free_data_contents(io->smb_krb5_context->krb5_context, &salt);
762 /* now use the talloced copy of the salt */
763 salt.data = discard_const(io->g.salt);
764 salt.length = strlen(io->g.salt);
767 * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of
768 * the salt and the cleartext password
770 krb5_ret = smb_krb5_create_key_from_string(io->smb_krb5_context->krb5_context,
774 ENCTYPE_AES256_CTS_HMAC_SHA1_96,
777 ldb_asprintf_errstring(ldb,
778 "setup_kerberos_keys: "
779 "generation of a aes256-cts-hmac-sha1-96 key failed: %s",
780 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
782 return LDB_ERR_OPERATIONS_ERROR;
784 io->g.aes_256 = data_blob_talloc(io->ac,
786 KRB5_KEY_LENGTH(&key));
787 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
788 if (!io->g.aes_256.data) {
793 * create ENCTYPE_AES128_CTS_HMAC_SHA1_96 key out of
794 * the salt and the cleartext password
796 krb5_ret = smb_krb5_create_key_from_string(io->smb_krb5_context->krb5_context,
800 ENCTYPE_AES128_CTS_HMAC_SHA1_96,
803 ldb_asprintf_errstring(ldb,
804 "setup_kerberos_keys: "
805 "generation of a aes128-cts-hmac-sha1-96 key failed: %s",
806 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
808 return LDB_ERR_OPERATIONS_ERROR;
810 io->g.aes_128 = data_blob_talloc(io->ac,
812 KRB5_KEY_LENGTH(&key));
813 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
814 if (!io->g.aes_128.data) {
819 * create ENCTYPE_DES_CBC_MD5 key out of
820 * the salt and the cleartext password
822 krb5_ret = smb_krb5_create_key_from_string(io->smb_krb5_context->krb5_context,
829 ldb_asprintf_errstring(ldb,
830 "setup_kerberos_keys: "
831 "generation of a des-cbc-md5 key failed: %s",
832 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
834 return LDB_ERR_OPERATIONS_ERROR;
836 io->g.des_md5 = data_blob_talloc(io->ac,
838 KRB5_KEY_LENGTH(&key));
839 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
840 if (!io->g.des_md5.data) {
845 * create ENCTYPE_DES_CBC_CRC key out of
846 * the salt and the cleartext password
848 krb5_ret = smb_krb5_create_key_from_string(io->smb_krb5_context->krb5_context,
855 ldb_asprintf_errstring(ldb,
856 "setup_kerberos_keys: "
857 "generation of a des-cbc-crc key failed: %s",
858 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
860 return LDB_ERR_OPERATIONS_ERROR;
862 io->g.des_crc = data_blob_talloc(io->ac,
864 KRB5_KEY_LENGTH(&key));
865 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
866 if (!io->g.des_crc.data) {
873 static int setup_primary_kerberos(struct setup_password_fields_io *io,
874 const struct supplementalCredentialsBlob *old_scb,
875 struct package_PrimaryKerberosBlob *pkb)
877 struct ldb_context *ldb;
878 struct package_PrimaryKerberosCtr3 *pkb3 = &pkb->ctr.ctr3;
879 struct supplementalCredentialsPackage *old_scp = NULL;
880 struct package_PrimaryKerberosBlob _old_pkb;
881 struct package_PrimaryKerberosCtr3 *old_pkb3 = NULL;
883 enum ndr_err_code ndr_err;
885 ldb = ldb_module_get_ctx(io->ac->module);
888 * prepare generation of keys
890 * ENCTYPE_DES_CBC_MD5
891 * ENCTYPE_DES_CBC_CRC
894 pkb3->salt.string = io->g.salt;
896 pkb3->keys = talloc_array(io->ac,
897 struct package_PrimaryKerberosKey3,
903 pkb3->keys[0].keytype = ENCTYPE_DES_CBC_MD5;
904 pkb3->keys[0].value = &io->g.des_md5;
905 pkb3->keys[1].keytype = ENCTYPE_DES_CBC_CRC;
906 pkb3->keys[1].value = &io->g.des_crc;
908 /* initialize the old keys to zero */
909 pkb3->num_old_keys = 0;
910 pkb3->old_keys = NULL;
912 /* if there're no old keys, then we're done */
917 for (i=0; i < old_scb->sub.num_packages; i++) {
918 if (strcmp("Primary:Kerberos", old_scb->sub.packages[i].name) != 0) {
922 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
926 old_scp = &old_scb->sub.packages[i];
929 /* Primary:Kerberos element of supplementalCredentials */
933 blob = strhex_to_data_blob(io->ac, old_scp->data);
938 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
939 ndr_err = ndr_pull_struct_blob(&blob, io->ac, &_old_pkb,
940 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
941 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
942 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
943 ldb_asprintf_errstring(ldb,
944 "setup_primary_kerberos: "
945 "failed to pull old package_PrimaryKerberosBlob: %s",
947 return LDB_ERR_OPERATIONS_ERROR;
950 if (_old_pkb.version != 3) {
951 ldb_asprintf_errstring(ldb,
952 "setup_primary_kerberos: "
953 "package_PrimaryKerberosBlob version[%u] expected[3]",
955 return LDB_ERR_OPERATIONS_ERROR;
958 old_pkb3 = &_old_pkb.ctr.ctr3;
961 /* if we didn't found the old keys we're done */
966 /* fill in the old keys */
967 pkb3->num_old_keys = old_pkb3->num_keys;
968 pkb3->old_keys = old_pkb3->keys;
973 static int setup_primary_kerberos_newer(struct setup_password_fields_io *io,
974 const struct supplementalCredentialsBlob *old_scb,
975 struct package_PrimaryKerberosBlob *pkb)
977 struct ldb_context *ldb;
978 struct package_PrimaryKerberosCtr4 *pkb4 = &pkb->ctr.ctr4;
979 struct supplementalCredentialsPackage *old_scp = NULL;
980 struct package_PrimaryKerberosBlob _old_pkb;
981 struct package_PrimaryKerberosCtr4 *old_pkb4 = NULL;
983 enum ndr_err_code ndr_err;
985 ldb = ldb_module_get_ctx(io->ac->module);
988 * prepare generation of keys
990 * ENCTYPE_AES256_CTS_HMAC_SHA1_96
991 * ENCTYPE_AES128_CTS_HMAC_SHA1_96
992 * ENCTYPE_DES_CBC_MD5
993 * ENCTYPE_DES_CBC_CRC
996 pkb4->salt.string = io->g.salt;
997 pkb4->default_iteration_count = 4096;
1000 pkb4->keys = talloc_array(io->ac,
1001 struct package_PrimaryKerberosKey4,
1004 return ldb_oom(ldb);
1007 pkb4->keys[0].iteration_count = 4096;
1008 pkb4->keys[0].keytype = ENCTYPE_AES256_CTS_HMAC_SHA1_96;
1009 pkb4->keys[0].value = &io->g.aes_256;
1010 pkb4->keys[1].iteration_count = 4096;
1011 pkb4->keys[1].keytype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
1012 pkb4->keys[1].value = &io->g.aes_128;
1013 pkb4->keys[2].iteration_count = 4096;
1014 pkb4->keys[2].keytype = ENCTYPE_DES_CBC_MD5;
1015 pkb4->keys[2].value = &io->g.des_md5;
1016 pkb4->keys[3].iteration_count = 4096;
1017 pkb4->keys[3].keytype = ENCTYPE_DES_CBC_CRC;
1018 pkb4->keys[3].value = &io->g.des_crc;
1020 /* initialize the old keys to zero */
1021 pkb4->num_old_keys = 0;
1022 pkb4->old_keys = NULL;
1023 pkb4->num_older_keys = 0;
1024 pkb4->older_keys = NULL;
1026 /* if there're no old keys, then we're done */
1031 for (i=0; i < old_scb->sub.num_packages; i++) {
1032 if (strcmp("Primary:Kerberos-Newer-Keys", old_scb->sub.packages[i].name) != 0) {
1036 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
1040 old_scp = &old_scb->sub.packages[i];
1043 /* Primary:Kerberos-Newer-Keys element of supplementalCredentials */
1047 blob = strhex_to_data_blob(io->ac, old_scp->data);
1049 return ldb_oom(ldb);
1052 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
1053 ndr_err = ndr_pull_struct_blob(&blob, io->ac,
1055 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
1056 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1057 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1058 ldb_asprintf_errstring(ldb,
1059 "setup_primary_kerberos_newer: "
1060 "failed to pull old package_PrimaryKerberosBlob: %s",
1062 return LDB_ERR_OPERATIONS_ERROR;
1065 if (_old_pkb.version != 4) {
1066 ldb_asprintf_errstring(ldb,
1067 "setup_primary_kerberos_newer: "
1068 "package_PrimaryKerberosBlob version[%u] expected[4]",
1070 return LDB_ERR_OPERATIONS_ERROR;
1073 old_pkb4 = &_old_pkb.ctr.ctr4;
1076 /* if we didn't found the old keys we're done */
1081 /* fill in the old keys */
1082 pkb4->num_old_keys = old_pkb4->num_keys;
1083 pkb4->old_keys = old_pkb4->keys;
1084 pkb4->num_older_keys = old_pkb4->num_old_keys;
1085 pkb4->older_keys = old_pkb4->old_keys;
1090 static int setup_primary_wdigest(struct setup_password_fields_io *io,
1091 const struct supplementalCredentialsBlob *old_scb,
1092 struct package_PrimaryWDigestBlob *pdb)
1094 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1095 DATA_BLOB sAMAccountName;
1096 DATA_BLOB sAMAccountName_l;
1097 DATA_BLOB sAMAccountName_u;
1098 const char *user_principal_name = io->u.user_principal_name;
1099 DATA_BLOB userPrincipalName;
1100 DATA_BLOB userPrincipalName_l;
1101 DATA_BLOB userPrincipalName_u;
1102 DATA_BLOB netbios_domain;
1103 DATA_BLOB netbios_domain_l;
1104 DATA_BLOB netbios_domain_u;
1105 DATA_BLOB dns_domain;
1106 DATA_BLOB dns_domain_l;
1107 DATA_BLOB dns_domain_u;
1110 DATA_BLOB backslash;
1119 * http://technet2.microsoft.com/WindowsServer/en/library/717b450c-f4a0-4cc9-86f4-cc0633aae5f91033.mspx?mfr=true
1120 * for what precalculated hashes are supposed to be stored...
1122 * I can't reproduce all values which should contain "Digest" as realm,
1123 * am I doing something wrong or is w2k3 just broken...?
1125 * W2K3 fills in following for a user:
1127 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
1128 * sAMAccountName: NewUser2Sam
1129 * userPrincipalName: NewUser2Princ@sub1.w2k3.vmnet1.vm.base
1131 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1132 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
1133 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
1134 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1135 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
1136 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
1137 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
1138 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1139 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1140 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1141 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1142 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1143 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1144 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1145 * 221c55284451ae9b3aacaa2a3c86f10f => NewUser2Princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1146 * 74e1be668853d4324d38c07e2acfb8ea => (w2k3 has a bug here!) newuser2princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1147 * e1e244ab7f098e3ae1761be7f9229bbb => NEWUSER2PRINC@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
1148 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
1149 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
1150 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
1151 * 31dc704d3640335b2123d4ee28aa1f11 => ??? changes with NewUser2Sam => NewUser1Sam
1152 * 36349f5cecd07320fb3bb0e119230c43 => ??? changes with NewUser2Sam => NewUser1Sam
1153 * 12adf019d037fb535c01fd0608e78d9d => ??? changes with NewUser2Sam => NewUser1Sam
1154 * 6feecf8e724906f3ee1105819c5105a1 => ??? changes with NewUser2Princ => NewUser1Princ
1155 * 6c6911f3de6333422640221b9c51ff1f => ??? changes with NewUser2Princ => NewUser1Princ
1156 * 4b279877e742895f9348ac67a8de2f69 => ??? changes with NewUser2Princ => NewUser1Princ
1157 * db0c6bff069513e3ebb9870d29b57490 => ??? changes with NewUser2Sam => NewUser1Sam
1158 * 45072621e56b1c113a4e04a8ff68cd0e => ??? changes with NewUser2Sam => NewUser1Sam
1159 * 11d1220abc44a9c10cf91ef4a9c1de02 => ??? changes with NewUser2Sam => NewUser1Sam
1161 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
1162 * sAMAccountName: NewUser2Sam
1164 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1165 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
1166 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
1167 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1168 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
1169 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
1170 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
1171 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1172 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1173 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1174 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1175 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1176 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1177 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1178 * 8a140d30b6f0a5912735dc1e3bc993b4 => NewUser2Sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1179 * 86d95b2faae6cae4ec261e7fbaccf093 => (here w2k3 is correct) newuser2sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1180 * dfeff1493110220efcdfc6362e5f5450 => NEWUSER2SAM@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
1181 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
1182 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
1183 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
1184 * 31dc704d3640335b2123d4ee28aa1f11 => ???M1 changes with NewUser2Sam => NewUser1Sam
1185 * 36349f5cecd07320fb3bb0e119230c43 => ???M1.L changes with newuser2sam => newuser1sam
1186 * 12adf019d037fb535c01fd0608e78d9d => ???M1.U changes with NEWUSER2SAM => NEWUSER1SAM
1187 * 569b4533f2d9e580211dd040e5e360a8 => ???M2 changes with NewUser2Princ => NewUser1Princ
1188 * 52528bddf310a587c5d7e6a9ae2cbb20 => ???M2.L changes with newuser2princ => newuser1princ
1189 * 4f629a4f0361289ca4255ab0f658fcd5 => ???M3 changes with NewUser2Princ => NewUser1Princ (doesn't depend on case of userPrincipal )
1190 * db0c6bff069513e3ebb9870d29b57490 => ???M4 changes with NewUser2Sam => NewUser1Sam
1191 * 45072621e56b1c113a4e04a8ff68cd0e => ???M5 changes with NewUser2Sam => NewUser1Sam (doesn't depend on case of sAMAccountName)
1192 * 11d1220abc44a9c10cf91ef4a9c1de02 => ???M4.U changes with NEWUSER2SAM => NEWUSER1SAM
1196 * sAMAccountName, netbios_domain
1199 .user = &sAMAccountName,
1200 .realm = &netbios_domain,
1203 .user = &sAMAccountName_l,
1204 .realm = &netbios_domain_l,
1207 .user = &sAMAccountName_u,
1208 .realm = &netbios_domain_u,
1211 .user = &sAMAccountName,
1212 .realm = &netbios_domain_u,
1215 .user = &sAMAccountName,
1216 .realm = &netbios_domain_l,
1219 .user = &sAMAccountName_u,
1220 .realm = &netbios_domain_l,
1223 .user = &sAMAccountName_l,
1224 .realm = &netbios_domain_u,
1227 * sAMAccountName, dns_domain
1230 .user = &sAMAccountName,
1231 .realm = &dns_domain,
1234 .user = &sAMAccountName_l,
1235 .realm = &dns_domain_l,
1238 .user = &sAMAccountName_u,
1239 .realm = &dns_domain_u,
1242 .user = &sAMAccountName,
1243 .realm = &dns_domain_u,
1246 .user = &sAMAccountName,
1247 .realm = &dns_domain_l,
1250 .user = &sAMAccountName_u,
1251 .realm = &dns_domain_l,
1254 .user = &sAMAccountName_l,
1255 .realm = &dns_domain_u,
1258 * userPrincipalName, no realm
1261 .user = &userPrincipalName,
1265 * NOTE: w2k3 messes this up, if the user has a real userPrincipalName,
1266 * the fallback to the sAMAccountName based userPrincipalName is correct
1268 .user = &userPrincipalName_l,
1271 .user = &userPrincipalName_u,
1274 * nt4dom\sAMAccountName, no realm
1277 .user = &sAMAccountName,
1278 .nt4dom = &netbios_domain
1281 .user = &sAMAccountName_l,
1282 .nt4dom = &netbios_domain_l
1285 .user = &sAMAccountName_u,
1286 .nt4dom = &netbios_domain_u
1290 * the following ones are guessed depending on the technet2 article
1291 * but not reproducable on a w2k3 server
1293 /* sAMAccountName with "Digest" realm */
1295 .user = &sAMAccountName,
1299 .user = &sAMAccountName_l,
1303 .user = &sAMAccountName_u,
1306 /* userPrincipalName with "Digest" realm */
1308 .user = &userPrincipalName,
1312 .user = &userPrincipalName_l,
1316 .user = &userPrincipalName_u,
1319 /* nt4dom\\sAMAccountName with "Digest" realm */
1321 .user = &sAMAccountName,
1322 .nt4dom = &netbios_domain,
1326 .user = &sAMAccountName_l,
1327 .nt4dom = &netbios_domain_l,
1331 .user = &sAMAccountName_u,
1332 .nt4dom = &netbios_domain_u,
1337 /* prepare DATA_BLOB's used in the combinations array */
1338 sAMAccountName = data_blob_string_const(io->u.sAMAccountName);
1339 sAMAccountName_l = data_blob_string_const(strlower_talloc(io->ac, io->u.sAMAccountName));
1340 if (!sAMAccountName_l.data) {
1341 return ldb_oom(ldb);
1343 sAMAccountName_u = data_blob_string_const(strupper_talloc(io->ac, io->u.sAMAccountName));
1344 if (!sAMAccountName_u.data) {
1345 return ldb_oom(ldb);
1348 /* if the user doesn't have a userPrincipalName, create one (with lower case realm) */
1349 if (!user_principal_name) {
1350 user_principal_name = talloc_asprintf(io->ac, "%s@%s",
1351 io->u.sAMAccountName,
1352 io->ac->status->domain_data.dns_domain);
1353 if (!user_principal_name) {
1354 return ldb_oom(ldb);
1357 userPrincipalName = data_blob_string_const(user_principal_name);
1358 userPrincipalName_l = data_blob_string_const(strlower_talloc(io->ac, user_principal_name));
1359 if (!userPrincipalName_l.data) {
1360 return ldb_oom(ldb);
1362 userPrincipalName_u = data_blob_string_const(strupper_talloc(io->ac, user_principal_name));
1363 if (!userPrincipalName_u.data) {
1364 return ldb_oom(ldb);
1367 netbios_domain = data_blob_string_const(io->ac->status->domain_data.netbios_domain);
1368 netbios_domain_l = data_blob_string_const(strlower_talloc(io->ac,
1369 io->ac->status->domain_data.netbios_domain));
1370 if (!netbios_domain_l.data) {
1371 return ldb_oom(ldb);
1373 netbios_domain_u = data_blob_string_const(strupper_talloc(io->ac,
1374 io->ac->status->domain_data.netbios_domain));
1375 if (!netbios_domain_u.data) {
1376 return ldb_oom(ldb);
1379 dns_domain = data_blob_string_const(io->ac->status->domain_data.dns_domain);
1380 dns_domain_l = data_blob_string_const(io->ac->status->domain_data.dns_domain);
1381 dns_domain_u = data_blob_string_const(io->ac->status->domain_data.realm);
1383 digest = data_blob_string_const("Digest");
1385 delim = data_blob_string_const(":");
1386 backslash = data_blob_string_const("\\");
1388 pdb->num_hashes = ARRAY_SIZE(wdigest);
1389 pdb->hashes = talloc_array(io->ac, struct package_PrimaryWDigestHash,
1392 return ldb_oom(ldb);
1395 for (i=0; i < ARRAY_SIZE(wdigest); i++) {
1398 if (wdigest[i].nt4dom) {
1399 MD5Update(&md5, wdigest[i].nt4dom->data, wdigest[i].nt4dom->length);
1400 MD5Update(&md5, backslash.data, backslash.length);
1402 MD5Update(&md5, wdigest[i].user->data, wdigest[i].user->length);
1403 MD5Update(&md5, delim.data, delim.length);
1404 if (wdigest[i].realm) {
1405 MD5Update(&md5, wdigest[i].realm->data, wdigest[i].realm->length);
1407 MD5Update(&md5, delim.data, delim.length);
1408 MD5Update(&md5, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length);
1409 MD5Final(pdb->hashes[i].hash, &md5);
1415 static int setup_primary_samba_gpg(struct setup_password_fields_io *io,
1416 struct package_PrimarySambaGPGBlob *pgb)
1418 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1421 gpgme_ctx_t ctx = NULL;
1422 size_t num_keys = str_list_length(io->ac->gpg_key_ids);
1423 gpgme_key_t keys[num_keys+1];
1426 gpgme_data_t plain_data = NULL;
1427 gpgme_data_t crypt_data = NULL;
1428 size_t crypt_length = 0;
1429 char *crypt_mem = NULL;
1431 gret = gpgme_new(&ctx);
1432 if (gret != GPG_ERR_NO_ERROR) {
1433 ldb_debug(ldb, LDB_DEBUG_ERROR,
1434 "%s:%s: gret[%u] %s\n",
1435 __location__, __func__,
1436 gret, gpgme_strerror(gret));
1437 return ldb_module_operr(io->ac->module);
1440 gpgme_set_armor(ctx, 1);
1442 gret = gpgme_data_new_from_mem(&plain_data,
1443 (const char *)io->n.cleartext_utf16->data,
1444 io->n.cleartext_utf16->length,
1446 if (gret != GPG_ERR_NO_ERROR) {
1447 ldb_debug(ldb, LDB_DEBUG_ERROR,
1448 "%s:%s: gret[%u] %s\n",
1449 __location__, __func__,
1450 gret, gpgme_strerror(gret));
1452 return ldb_module_operr(io->ac->module);
1454 gret = gpgme_data_new(&crypt_data);
1455 if (gret != GPG_ERR_NO_ERROR) {
1456 ldb_debug(ldb, LDB_DEBUG_ERROR,
1457 "%s:%s: gret[%u] %s\n",
1458 __location__, __func__,
1459 gret, gpgme_strerror(gret));
1460 gpgme_data_release(plain_data);
1462 return ldb_module_operr(io->ac->module);
1465 for (ki = 0; ki < num_keys; ki++) {
1466 const char *key_id = io->ac->gpg_key_ids[ki];
1467 size_t len = strlen(key_id);
1472 ldb_debug(ldb, LDB_DEBUG_FATAL,
1473 "%s:%s: ki[%zu] key_id[%s] strlen < 16, "
1474 "please specifiy at least the 64bit key id\n",
1475 __location__, __func__,
1477 for (kr = 0; keys[kr] != NULL; kr++) {
1478 gpgme_key_release(keys[kr]);
1480 gpgme_data_release(crypt_data);
1481 gpgme_data_release(plain_data);
1483 return ldb_module_operr(io->ac->module);
1486 gret = gpgme_get_key(ctx, key_id, &keys[ki], 0 /* public key */);
1487 if (gret != GPG_ERR_NO_ERROR) {
1489 ldb_debug(ldb, LDB_DEBUG_ERROR,
1490 "%s:%s: ki[%zu] key_id[%s] gret[%u] %s\n",
1491 __location__, __func__,
1493 gret, gpgme_strerror(gret));
1494 for (kr = 0; keys[kr] != NULL; kr++) {
1495 gpgme_key_release(keys[kr]);
1497 gpgme_data_release(crypt_data);
1498 gpgme_data_release(plain_data);
1500 return ldb_module_operr(io->ac->module);
1505 gret = gpgme_op_encrypt(ctx, keys,
1506 GPGME_ENCRYPT_ALWAYS_TRUST,
1507 plain_data, crypt_data);
1508 gpgme_data_release(plain_data);
1510 for (kr = 0; keys[kr] != NULL; kr++) {
1511 gpgme_key_release(keys[kr]);
1516 if (gret != GPG_ERR_NO_ERROR) {
1517 ldb_debug(ldb, LDB_DEBUG_ERROR,
1518 "%s:%s: gret[%u] %s\n",
1519 __location__, __func__,
1520 gret, gpgme_strerror(gret));
1521 gpgme_data_release(crypt_data);
1522 return ldb_module_operr(io->ac->module);
1525 crypt_mem = gpgme_data_release_and_get_mem(crypt_data, &crypt_length);
1527 if (crypt_mem == NULL) {
1528 return ldb_module_oom(io->ac->module);
1531 pgb->gpg_blob = data_blob_talloc(io->ac,
1532 (const uint8_t *)crypt_mem,
1534 gpgme_free(crypt_mem);
1537 if (pgb->gpg_blob.data == NULL) {
1538 return ldb_module_oom(io->ac->module);
1542 #else /* ENABLE_GPGME */
1543 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
1544 "You configured 'password hash gpg key ids', "
1545 "but GPGME support is missing. (%s:%d)",
1546 __FILE__, __LINE__);
1547 return LDB_ERR_UNWILLING_TO_PERFORM;
1548 #endif /* else ENABLE_GPGME */
1551 static int setup_supplemental_field(struct setup_password_fields_io *io)
1553 struct ldb_context *ldb;
1554 struct supplementalCredentialsBlob scb;
1555 struct supplementalCredentialsBlob *old_scb = NULL;
1556 /* Packages + (Kerberos-Newer-Keys, Kerberos, WDigest, CLEARTEXT, SambaGPG) */
1557 uint32_t num_names = 0;
1558 const char *names[1+5];
1559 uint32_t num_packages = 0;
1560 struct supplementalCredentialsPackage packages[1+5];
1562 struct supplementalCredentialsPackage *pp = NULL;
1563 struct package_PackagesBlob pb;
1566 /* Primary:Kerberos-Newer-Keys */
1567 const char **nkn = NULL;
1568 struct supplementalCredentialsPackage *pkn = NULL;
1569 struct package_PrimaryKerberosBlob pknb;
1570 DATA_BLOB pknb_blob;
1572 /* Primary:Kerberos */
1573 const char **nk = NULL;
1574 struct supplementalCredentialsPackage *pk = NULL;
1575 struct package_PrimaryKerberosBlob pkb;
1578 /* Primary:WDigest */
1579 const char **nd = NULL;
1580 struct supplementalCredentialsPackage *pd = NULL;
1581 struct package_PrimaryWDigestBlob pdb;
1584 /* Primary:CLEARTEXT */
1585 const char **nc = NULL;
1586 struct supplementalCredentialsPackage *pc = NULL;
1587 struct package_PrimaryCLEARTEXTBlob pcb;
1590 /* Primary:SambaGPG */
1591 const char **ng = NULL;
1592 struct supplementalCredentialsPackage *pg = NULL;
1593 struct package_PrimarySambaGPGBlob pgb;
1597 enum ndr_err_code ndr_err;
1599 bool do_newer_keys = false;
1600 bool do_cleartext = false;
1601 bool do_samba_gpg = false;
1603 ZERO_STRUCT(zero16);
1605 ZERO_STRUCT(packages);
1607 ldb = ldb_module_get_ctx(io->ac->module);
1609 if (!io->n.cleartext_utf8) {
1611 * when we don't have a cleartext password
1612 * we can't setup a supplementalCredential value
1617 /* if there's an old supplementaCredentials blob then use it */
1618 if (io->o.supplemental) {
1619 if (io->o.scb.sub.signature == SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
1620 old_scb = &io->o.scb;
1622 ldb_debug(ldb, LDB_DEBUG_ERROR,
1623 "setup_supplemental_field: "
1624 "supplementalCredentialsBlob "
1625 "signature[0x%04X] expected[0x%04X]",
1626 io->o.scb.sub.signature,
1627 SUPPLEMENTAL_CREDENTIALS_SIGNATURE);
1630 /* Per MS-SAMR 3.1.1.8.11.6 we create AES keys if our domain functionality level is 2008 or higher */
1631 do_newer_keys = (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008);
1633 if (io->ac->status->domain_data.store_cleartext &&
1634 (io->u.userAccountControl & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) {
1635 do_cleartext = true;
1638 if (io->ac->gpg_key_ids != NULL) {
1639 do_samba_gpg = true;
1643 * The ordering is this
1645 * Primary:Kerberos-Newer-Keys (optional)
1648 * Primary:CLEARTEXT (optional)
1649 * Primary:SambaGPG (optional)
1651 * And the 'Packages' package is insert before the last
1654 * Note: it's important that Primary:SambaGPG is added as
1655 * the last element. This is the indication that it matches
1656 * the current password. When a password change happens on
1657 * a Windows DC, it will keep the old Primary:SambaGPG value,
1658 * but as the first element.
1660 if (do_newer_keys) {
1661 /* Primary:Kerberos-Newer-Keys */
1662 nkn = &names[num_names++];
1663 pkn = &packages[num_packages++];
1666 /* Primary:Kerberos */
1667 nk = &names[num_names++];
1668 pk = &packages[num_packages++];
1670 if (!do_cleartext && !do_samba_gpg) {
1672 pp = &packages[num_packages++];
1675 /* Primary:WDigest */
1676 nd = &names[num_names++];
1677 pd = &packages[num_packages++];
1680 if (!do_samba_gpg) {
1682 pp = &packages[num_packages++];
1685 /* Primary:CLEARTEXT */
1686 nc = &names[num_names++];
1687 pc = &packages[num_packages++];
1692 pp = &packages[num_packages++];
1694 /* Primary:SambaGPG */
1695 ng = &names[num_names++];
1696 pg = &packages[num_packages++];
1701 * setup 'Primary:Kerberos-Newer-Keys' element
1703 *nkn = "Kerberos-Newer-Keys";
1705 ret = setup_primary_kerberos_newer(io, old_scb, &pknb);
1706 if (ret != LDB_SUCCESS) {
1710 ndr_err = ndr_push_struct_blob(&pknb_blob, io->ac,
1712 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1713 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1714 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1715 ldb_asprintf_errstring(ldb,
1716 "setup_supplemental_field: "
1717 "failed to push package_PrimaryKerberosNeverBlob: %s",
1719 return LDB_ERR_OPERATIONS_ERROR;
1721 pknb_hexstr = data_blob_hex_string_upper(io->ac, &pknb_blob);
1723 return ldb_oom(ldb);
1725 pkn->name = "Primary:Kerberos-Newer-Keys";
1727 pkn->data = pknb_hexstr;
1731 * setup 'Primary:Kerberos' element
1735 ret = setup_primary_kerberos(io, old_scb, &pkb);
1736 if (ret != LDB_SUCCESS) {
1740 ndr_err = ndr_push_struct_blob(&pkb_blob, io->ac,
1742 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1743 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1744 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1745 ldb_asprintf_errstring(ldb,
1746 "setup_supplemental_field: "
1747 "failed to push package_PrimaryKerberosBlob: %s",
1749 return LDB_ERR_OPERATIONS_ERROR;
1751 pkb_hexstr = data_blob_hex_string_upper(io->ac, &pkb_blob);
1753 return ldb_oom(ldb);
1755 pk->name = "Primary:Kerberos";
1757 pk->data = pkb_hexstr;
1760 * setup 'Primary:WDigest' element
1764 ret = setup_primary_wdigest(io, old_scb, &pdb);
1765 if (ret != LDB_SUCCESS) {
1769 ndr_err = ndr_push_struct_blob(&pdb_blob, io->ac,
1771 (ndr_push_flags_fn_t)ndr_push_package_PrimaryWDigestBlob);
1772 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1773 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1774 ldb_asprintf_errstring(ldb,
1775 "setup_supplemental_field: "
1776 "failed to push package_PrimaryWDigestBlob: %s",
1778 return LDB_ERR_OPERATIONS_ERROR;
1780 pdb_hexstr = data_blob_hex_string_upper(io->ac, &pdb_blob);
1782 return ldb_oom(ldb);
1784 pd->name = "Primary:WDigest";
1786 pd->data = pdb_hexstr;
1789 * setup 'Primary:CLEARTEXT' element
1794 pcb.cleartext = *io->n.cleartext_utf16;
1796 ndr_err = ndr_push_struct_blob(&pcb_blob, io->ac,
1798 (ndr_push_flags_fn_t)ndr_push_package_PrimaryCLEARTEXTBlob);
1799 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1800 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1801 ldb_asprintf_errstring(ldb,
1802 "setup_supplemental_field: "
1803 "failed to push package_PrimaryCLEARTEXTBlob: %s",
1805 return LDB_ERR_OPERATIONS_ERROR;
1807 pcb_hexstr = data_blob_hex_string_upper(io->ac, &pcb_blob);
1809 return ldb_oom(ldb);
1811 pc->name = "Primary:CLEARTEXT";
1813 pc->data = pcb_hexstr;
1817 * setup 'Primary:SambaGPG' element
1822 ret = setup_primary_samba_gpg(io, &pgb);
1823 if (ret != LDB_SUCCESS) {
1827 ndr_err = ndr_push_struct_blob(&pgb_blob, io->ac, &pgb,
1828 (ndr_push_flags_fn_t)ndr_push_package_PrimarySambaGPGBlob);
1829 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1830 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1831 ldb_asprintf_errstring(ldb,
1832 "setup_supplemental_field: failed to "
1833 "push package_PrimarySambaGPGBlob: %s",
1835 return LDB_ERR_OPERATIONS_ERROR;
1837 pgb_hexstr = data_blob_hex_string_upper(io->ac, &pgb_blob);
1839 return ldb_oom(ldb);
1841 pg->name = "Primary:SambaGPG";
1843 pg->data = pgb_hexstr;
1847 * setup 'Packages' element
1850 ndr_err = ndr_push_struct_blob(&pb_blob, io->ac,
1852 (ndr_push_flags_fn_t)ndr_push_package_PackagesBlob);
1853 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1854 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1855 ldb_asprintf_errstring(ldb,
1856 "setup_supplemental_field: "
1857 "failed to push package_PackagesBlob: %s",
1859 return LDB_ERR_OPERATIONS_ERROR;
1861 pb_hexstr = data_blob_hex_string_upper(io->ac, &pb_blob);
1863 return ldb_oom(ldb);
1865 pp->name = "Packages";
1867 pp->data = pb_hexstr;
1870 * setup 'supplementalCredentials' value
1873 scb.sub.signature = SUPPLEMENTAL_CREDENTIALS_SIGNATURE;
1874 scb.sub.num_packages = num_packages;
1875 scb.sub.packages = packages;
1877 ndr_err = ndr_push_struct_blob(&io->g.supplemental, io->ac,
1879 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
1880 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1881 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1882 ldb_asprintf_errstring(ldb,
1883 "setup_supplemental_field: "
1884 "failed to push supplementalCredentialsBlob: %s",
1886 return LDB_ERR_OPERATIONS_ERROR;
1892 static int setup_last_set_field(struct setup_password_fields_io *io)
1894 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1895 const struct ldb_message *msg = NULL;
1896 struct timeval tv = { .tv_sec = 0 };
1897 const struct ldb_val *old_val = NULL;
1898 const struct ldb_val *new_val = NULL;
1901 switch (io->ac->req->operation) {
1903 msg = io->ac->req->op.add.message;
1906 msg = io->ac->req->op.mod.message;
1909 return LDB_ERR_OPERATIONS_ERROR;
1913 if (io->ac->pwd_last_set_bypass) {
1914 struct ldb_message_element *el1 = NULL;
1915 struct ldb_message_element *el2 = NULL;
1918 return LDB_ERR_CONSTRAINT_VIOLATION;
1921 el1 = dsdb_get_single_valued_attr(msg, "pwdLastSet",
1922 io->ac->req->operation);
1924 return LDB_ERR_CONSTRAINT_VIOLATION;
1926 el2 = ldb_msg_find_element(msg, "pwdLastSet");
1928 return LDB_ERR_CONSTRAINT_VIOLATION;
1931 return LDB_ERR_CONSTRAINT_VIOLATION;
1934 io->g.last_set = samdb_result_nttime(msg, "pwdLastSet", 0);
1938 ret = msg_find_old_and_new_pwd_val(msg, "pwdLastSet",
1939 io->ac->req->operation,
1940 &new_val, &old_val);
1941 if (ret != LDB_SUCCESS) {
1945 if (old_val != NULL && new_val == NULL) {
1946 ldb_set_errstring(ldb,
1947 "'pwdLastSet' deletion is not allowed!");
1948 return LDB_ERR_UNWILLING_TO_PERFORM;
1951 io->g.last_set = UINT64_MAX;
1952 if (new_val != NULL) {
1953 struct ldb_message *tmp_msg = NULL;
1955 tmp_msg = ldb_msg_new(io->ac);
1956 if (tmp_msg == NULL) {
1957 return ldb_module_oom(io->ac->module);
1960 if (old_val != NULL) {
1961 NTTIME old_last_set = 0;
1963 ret = ldb_msg_add_value(tmp_msg, "oldval",
1965 if (ret != LDB_SUCCESS) {
1969 old_last_set = samdb_result_nttime(tmp_msg,
1972 if (io->u.pwdLastSet != old_last_set) {
1973 return dsdb_module_werror(io->ac->module,
1974 LDB_ERR_NO_SUCH_ATTRIBUTE,
1975 WERR_DS_CANT_REM_MISSING_ATT_VAL,
1976 "setup_last_set_field: old pwdLastSet "
1977 "value not found!");
1981 ret = ldb_msg_add_value(tmp_msg, "newval",
1983 if (ret != LDB_SUCCESS) {
1987 io->g.last_set = samdb_result_nttime(tmp_msg,
1990 } else if (ldb_msg_find_element(msg, "pwdLastSet")) {
1991 ldb_set_errstring(ldb,
1992 "'pwdLastSet' deletion is not allowed!");
1993 return LDB_ERR_UNWILLING_TO_PERFORM;
1994 } else if (io->ac->smartcard_reset) {
1996 * adding UF_SMARTCARD_REQUIRED doesn't update
1997 * pwdLastSet implicitly.
1999 io->ac->update_lastset = false;
2002 /* only 0 or -1 (0xFFFFFFFFFFFFFFFF) are allowed */
2003 switch (io->g.last_set) {
2005 if (!io->ac->pwd_last_set_default) {
2008 if (!io->ac->update_password) {
2013 if (!io->ac->update_password &&
2014 io->u.pwdLastSet != 0 &&
2015 io->u.pwdLastSet != UINT64_MAX)
2018 * Just setting pwdLastSet to -1, while not changing
2019 * any password field has no effect if pwdLastSet
2020 * is already non-zero.
2022 io->ac->update_lastset = false;
2025 /* -1 means set it as now */
2027 io->g.last_set = timeval_to_nttime(&tv);
2030 return dsdb_module_werror(io->ac->module,
2033 "setup_last_set_field: "
2034 "pwdLastSet must be 0 or -1 only!");
2037 if (io->ac->req->operation == LDB_ADD) {
2039 * We always need to store the value on add
2045 if (io->g.last_set == io->u.pwdLastSet) {
2047 * Just setting pwdLastSet to 0, is no-op if it's already 0.
2049 io->ac->update_lastset = false;
2055 static int setup_given_passwords(struct setup_password_fields_io *io,
2056 struct setup_password_fields_given *g)
2058 struct ldb_context *ldb;
2061 ldb = ldb_module_get_ctx(io->ac->module);
2063 if (g->cleartext_utf8) {
2064 struct ldb_val *cleartext_utf16_blob;
2066 cleartext_utf16_blob = talloc(io->ac, struct ldb_val);
2067 if (!cleartext_utf16_blob) {
2068 return ldb_oom(ldb);
2070 if (!convert_string_talloc(io->ac,
2072 g->cleartext_utf8->data,
2073 g->cleartext_utf8->length,
2074 (void *)&cleartext_utf16_blob->data,
2075 &cleartext_utf16_blob->length)) {
2076 if (g->cleartext_utf8->length != 0) {
2077 talloc_free(cleartext_utf16_blob);
2078 ldb_asprintf_errstring(ldb,
2079 "setup_password_fields: "
2080 "failed to generate UTF16 password from cleartext UTF8 one for user '%s'!",
2081 io->u.sAMAccountName);
2082 return LDB_ERR_CONSTRAINT_VIOLATION;
2084 /* passwords with length "0" are valid! */
2085 cleartext_utf16_blob->data = NULL;
2086 cleartext_utf16_blob->length = 0;
2089 g->cleartext_utf16 = cleartext_utf16_blob;
2090 } else if (g->cleartext_utf16) {
2091 struct ldb_val *cleartext_utf8_blob;
2093 cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
2094 if (!cleartext_utf8_blob) {
2095 return ldb_oom(ldb);
2097 if (!convert_string_talloc(io->ac,
2098 CH_UTF16MUNGED, CH_UTF8,
2099 g->cleartext_utf16->data,
2100 g->cleartext_utf16->length,
2101 (void *)&cleartext_utf8_blob->data,
2102 &cleartext_utf8_blob->length)) {
2103 if (g->cleartext_utf16->length != 0) {
2104 /* We must bail out here, the input wasn't even
2105 * a multiple of 2 bytes */
2106 talloc_free(cleartext_utf8_blob);
2107 ldb_asprintf_errstring(ldb,
2108 "setup_password_fields: "
2109 "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)!",
2110 io->u.sAMAccountName);
2111 return LDB_ERR_CONSTRAINT_VIOLATION;
2113 /* passwords with length "0" are valid! */
2114 cleartext_utf8_blob->data = NULL;
2115 cleartext_utf8_blob->length = 0;
2118 g->cleartext_utf8 = cleartext_utf8_blob;
2121 if (g->cleartext_utf16) {
2122 struct samr_Password *nt_hash;
2124 nt_hash = talloc(io->ac, struct samr_Password);
2126 return ldb_oom(ldb);
2128 g->nt_hash = nt_hash;
2130 /* compute the new nt hash */
2131 mdfour(nt_hash->hash,
2132 g->cleartext_utf16->data,
2133 g->cleartext_utf16->length);
2136 if (g->cleartext_utf8) {
2137 struct samr_Password *lm_hash;
2139 lm_hash = talloc(io->ac, struct samr_Password);
2141 return ldb_oom(ldb);
2144 /* compute the new lm hash */
2145 ok = E_deshash((char *)g->cleartext_utf8->data, lm_hash->hash);
2147 g->lm_hash = lm_hash;
2149 talloc_free(lm_hash);
2156 static int setup_password_fields(struct setup_password_fields_io *io)
2158 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2159 struct loadparm_context *lp_ctx =
2160 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2161 struct loadparm_context);
2164 ret = setup_last_set_field(io);
2165 if (ret != LDB_SUCCESS) {
2169 if (!io->ac->update_password) {
2173 /* transform the old password (for password changes) */
2174 ret = setup_given_passwords(io, &io->og);
2175 if (ret != LDB_SUCCESS) {
2179 /* transform the new password */
2180 ret = setup_given_passwords(io, &io->n);
2181 if (ret != LDB_SUCCESS) {
2185 if (io->n.cleartext_utf8) {
2186 ret = setup_kerberos_keys(io);
2187 if (ret != LDB_SUCCESS) {
2192 ret = setup_nt_fields(io);
2193 if (ret != LDB_SUCCESS) {
2197 if (lpcfg_lanman_auth(lp_ctx)) {
2198 ret = setup_lm_fields(io);
2199 if (ret != LDB_SUCCESS) {
2203 io->g.lm_hash = NULL;
2204 io->g.lm_history_len = 0;
2207 ret = setup_supplemental_field(io);
2208 if (ret != LDB_SUCCESS) {
2215 static int setup_smartcard_reset(struct setup_password_fields_io *io)
2217 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2218 struct loadparm_context *lp_ctx = talloc_get_type(
2219 ldb_get_opaque(ldb, "loadparm"), struct loadparm_context);
2220 struct supplementalCredentialsBlob scb = { .__ndr_size = 0 };
2221 enum ndr_err_code ndr_err;
2223 if (!io->ac->smartcard_reset) {
2227 io->g.nt_hash = talloc(io->ac, struct samr_Password);
2228 if (io->g.nt_hash == NULL) {
2229 return ldb_module_oom(io->ac->module);
2231 generate_secret_buffer(io->g.nt_hash->hash,
2232 sizeof(io->g.nt_hash->hash));
2233 io->g.nt_history_len = 0;
2235 if (lpcfg_lanman_auth(lp_ctx)) {
2236 io->g.lm_hash = talloc(io->ac, struct samr_Password);
2237 if (io->g.lm_hash == NULL) {
2238 return ldb_module_oom(io->ac->module);
2240 generate_secret_buffer(io->g.lm_hash->hash,
2241 sizeof(io->g.lm_hash->hash));
2243 io->g.lm_hash = NULL;
2245 io->g.lm_history_len = 0;
2248 * We take the "old" value and store it
2249 * with num_packages = 0.
2251 * On "add" we have scb.sub.signature == 0, which
2254 * [0000] 00 00 00 00 00 00 00 00 00 00 00 00 00
2256 * On modify it's likely to be scb.sub.signature ==
2257 * SUPPLEMENTAL_CREDENTIALS_SIGNATURE (0x0050), which results in
2260 * [0000] 00 00 00 00 62 00 00 00 00 00 00 00 20 00 20 00
2261 * [0010] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2262 * [0020] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2263 * [0030] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2264 * [0040] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2265 * [0050] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2266 * [0060] 20 00 20 00 20 00 20 00 20 00 20 00 50 00 00
2268 * See https://bugzilla.samba.org/show_bug.cgi?id=11441
2269 * and ndr_{push,pull}_supplementalCredentialsSubBlob().
2272 scb.sub.num_packages = 0;
2275 * setup 'supplementalCredentials' value without packages
2277 ndr_err = ndr_push_struct_blob(&io->g.supplemental, io->ac,
2279 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
2280 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2281 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2282 ldb_asprintf_errstring(ldb,
2283 "setup_smartcard_reset: "
2284 "failed to push supplementalCredentialsBlob: %s",
2286 return LDB_ERR_OPERATIONS_ERROR;
2289 io->ac->update_password = true;
2293 static int make_error_and_update_badPwdCount(struct setup_password_fields_io *io)
2295 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2296 struct ldb_message *mod_msg = NULL;
2300 status = dsdb_update_bad_pwd_count(io->ac, ldb,
2301 io->ac->search_res->message,
2302 io->ac->dom_res->message,
2304 if (!NT_STATUS_IS_OK(status)) {
2308 if (mod_msg == NULL) {
2313 * OK, horrible semantics ahead.
2315 * - We need to abort any existing transaction
2316 * - create a transaction arround the badPwdCount update
2317 * - re-open the transaction so the upper layer
2318 * doesn't know what happened.
2320 * This is needed because returning an error to the upper
2321 * layer will cancel the transaction and undo the badPwdCount
2326 * Checking errors here is a bit pointless.
2327 * What can we do if we can't end the transaction?
2329 ret = ldb_next_del_trans(io->ac->module);
2330 if (ret != LDB_SUCCESS) {
2331 ldb_debug(ldb, LDB_DEBUG_FATAL,
2332 "Failed to abort transaction prior to update of badPwdCount of %s: %s",
2333 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2334 ldb_errstring(ldb));
2336 * just return the original error
2341 /* Likewise, what should we do if we can't open a new transaction? */
2342 ret = ldb_next_start_trans(io->ac->module);
2343 if (ret != LDB_SUCCESS) {
2344 ldb_debug(ldb, LDB_DEBUG_ERROR,
2345 "Failed to open transaction to update badPwdCount of %s: %s",
2346 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2347 ldb_errstring(ldb));
2349 * just return the original error
2354 ret = dsdb_module_modify(io->ac->module, mod_msg,
2355 DSDB_FLAG_NEXT_MODULE,
2357 if (ret != LDB_SUCCESS) {
2358 ldb_debug(ldb, LDB_DEBUG_ERROR,
2359 "Failed to update badPwdCount of %s: %s",
2360 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2361 ldb_errstring(ldb));
2363 * We can only ignore this...
2367 ret = ldb_next_end_trans(io->ac->module);
2368 if (ret != LDB_SUCCESS) {
2369 ldb_debug(ldb, LDB_DEBUG_ERROR,
2370 "Failed to close transaction to update badPwdCount of %s: %s",
2371 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2372 ldb_errstring(ldb));
2374 * We can only ignore this...
2378 ret = ldb_next_start_trans(io->ac->module);
2379 if (ret != LDB_SUCCESS) {
2380 ldb_debug(ldb, LDB_DEBUG_ERROR,
2381 "Failed to open transaction after update of badPwdCount of %s: %s",
2382 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2383 ldb_errstring(ldb));
2385 * We can only ignore this...
2390 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2391 ldb_asprintf_errstring(ldb,
2392 "%08X: %s - check_password_restrictions: "
2393 "The old password specified doesn't match!",
2394 W_ERROR_V(WERR_INVALID_PASSWORD),
2399 static int check_password_restrictions(struct setup_password_fields_io *io)
2401 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2403 struct loadparm_context *lp_ctx =
2404 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2405 struct loadparm_context);
2407 if (!io->ac->update_password) {
2411 /* First check the old password is correct, for password changes */
2412 if (!io->ac->pwd_reset) {
2413 bool nt_hash_checked = false;
2415 /* we need the old nt or lm hash given by the client */
2416 if (!io->og.nt_hash && !io->og.lm_hash) {
2417 ldb_asprintf_errstring(ldb,
2418 "check_password_restrictions: "
2419 "You need to provide the old password in order "
2421 return LDB_ERR_UNWILLING_TO_PERFORM;
2424 /* The password modify through the NT hash is encouraged and
2425 has no problems at all */
2426 if (io->og.nt_hash) {
2427 if (!io->o.nt_hash || memcmp(io->og.nt_hash->hash, io->o.nt_hash->hash, 16) != 0) {
2428 return make_error_and_update_badPwdCount(io);
2431 nt_hash_checked = true;
2434 /* But it is also possible to change a password by the LM hash
2435 * alone for compatibility reasons. This check is optional if
2436 * the NT hash was already checked - otherwise it's mandatory.
2437 * (as the SAMR operations request it). */
2438 if (io->og.lm_hash) {
2439 if ((!io->o.lm_hash && !nt_hash_checked)
2440 || (io->o.lm_hash && memcmp(io->og.lm_hash->hash, io->o.lm_hash->hash, 16) != 0)) {
2441 return make_error_and_update_badPwdCount(io);
2446 if (io->u.restrictions == 0) {
2447 /* FIXME: Is this right? */
2451 /* Password minimum age: yes, this is a minus. The ages are in negative 100nsec units! */
2452 if ((io->u.pwdLastSet - io->ac->status->domain_data.minPwdAge > io->g.last_set) &&
2455 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2456 ldb_asprintf_errstring(ldb,
2457 "%08X: %s - check_password_restrictions: "
2458 "password is too young to change!",
2459 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2465 * Fundamental password checks done by the call
2466 * "samdb_check_password".
2467 * It is also in use by "dcesrv_samr_ValidatePassword".
2469 if (io->n.cleartext_utf8 != NULL) {
2470 enum samr_ValidationStatus vstat;
2471 vstat = samdb_check_password(io->ac, lp_ctx,
2472 io->n.cleartext_utf8,
2473 io->ac->status->domain_data.pwdProperties,
2474 io->ac->status->domain_data.minPwdLength);
2476 case SAMR_VALIDATION_STATUS_SUCCESS:
2477 /* perfect -> proceed! */
2480 case SAMR_VALIDATION_STATUS_PWD_TOO_SHORT:
2481 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2482 ldb_asprintf_errstring(ldb,
2483 "%08X: %s - check_password_restrictions: "
2484 "the password is too short. It should be equal or longer than %u characters!",
2485 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2487 io->ac->status->domain_data.minPwdLength);
2488 io->ac->status->reject_reason = SAM_PWD_CHANGE_PASSWORD_TOO_SHORT;
2491 case SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH:
2492 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2493 ldb_asprintf_errstring(ldb,
2494 "%08X: %s - check_password_restrictions: "
2495 "the password does not meet the complexity criteria!",
2496 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2498 io->ac->status->reject_reason = SAM_PWD_CHANGE_NOT_COMPLEX;
2502 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2503 ldb_asprintf_errstring(ldb,
2504 "%08X: %s - check_password_restrictions: "
2505 "the password doesn't fit due to a miscellaneous restriction!",
2506 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2512 if (io->ac->pwd_reset) {
2516 if (io->n.nt_hash) {
2519 /* checks the NT hash password history */
2520 for (i = 0; i < io->o.nt_history_len; i++) {
2521 ret = memcmp(io->n.nt_hash, io->o.nt_history[i].hash, 16);
2523 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2524 ldb_asprintf_errstring(ldb,
2525 "%08X: %s - check_password_restrictions: "
2526 "the password was already used (in history)!",
2527 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2529 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
2535 if (io->n.lm_hash) {
2538 /* checks the LM hash password history */
2539 for (i = 0; i < io->o.lm_history_len; i++) {
2540 ret = memcmp(io->n.lm_hash, io->o.lm_history[i].hash, 16);
2542 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2543 ldb_asprintf_errstring(ldb,
2544 "%08X: %s - check_password_restrictions: "
2545 "the password was already used (in history)!",
2546 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2548 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
2554 /* are all password changes disallowed? */
2555 if (io->ac->status->domain_data.pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
2556 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2557 ldb_asprintf_errstring(ldb,
2558 "%08X: %s - check_password_restrictions: "
2559 "password changes disabled!",
2560 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2565 /* can this user change the password? */
2566 if (io->u.userAccountControl & UF_PASSWD_CANT_CHANGE) {
2567 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2568 ldb_asprintf_errstring(ldb,
2569 "%08X: %s - check_password_restrictions: "
2570 "password can't be changed on this account!",
2571 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2579 static int update_final_msg(struct setup_password_fields_io *io)
2581 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2584 bool update_password = io->ac->update_password;
2585 bool update_scb = io->ac->update_password;
2588 * If we add a user without initial password,
2589 * we need to add replication meta data for
2590 * following attributes:
2596 * If we add a user with initial password or a
2597 * password is changed of an existing user,
2598 * we need to replace the following attributes
2599 * with a forced meta data update, e.g. also
2600 * when updating an empty attribute with an empty value:
2605 * - supplementalCredentials
2608 switch (io->ac->req->operation) {
2610 update_password = true;
2611 el_flags |= DSDB_FLAG_INTERNAL_FORCE_META_DATA;
2614 el_flags |= LDB_FLAG_MOD_REPLACE;
2615 el_flags |= DSDB_FLAG_INTERNAL_FORCE_META_DATA;
2618 return ldb_module_operr(io->ac->module);
2621 if (update_password) {
2622 ret = ldb_msg_add_empty(io->ac->update_msg,
2625 if (ret != LDB_SUCCESS) {
2628 ret = ldb_msg_add_empty(io->ac->update_msg,
2631 if (ret != LDB_SUCCESS) {
2634 ret = ldb_msg_add_empty(io->ac->update_msg,
2637 if (ret != LDB_SUCCESS) {
2640 ret = ldb_msg_add_empty(io->ac->update_msg,
2643 if (ret != LDB_SUCCESS) {
2648 ret = ldb_msg_add_empty(io->ac->update_msg,
2649 "supplementalCredentials",
2651 if (ret != LDB_SUCCESS) {
2655 if (io->ac->update_lastset) {
2656 ret = ldb_msg_add_empty(io->ac->update_msg,
2659 if (ret != LDB_SUCCESS) {
2664 if (io->g.nt_hash != NULL) {
2665 ret = samdb_msg_add_hash(ldb, io->ac,
2669 if (ret != LDB_SUCCESS) {
2673 if (io->g.lm_hash != NULL) {
2674 ret = samdb_msg_add_hash(ldb, io->ac,
2678 if (ret != LDB_SUCCESS) {
2682 if (io->g.nt_history_len > 0) {
2683 ret = samdb_msg_add_hashes(ldb, io->ac,
2687 io->g.nt_history_len);
2688 if (ret != LDB_SUCCESS) {
2692 if (io->g.lm_history_len > 0) {
2693 ret = samdb_msg_add_hashes(ldb, io->ac,
2697 io->g.lm_history_len);
2698 if (ret != LDB_SUCCESS) {
2702 if (io->g.supplemental.length > 0) {
2703 ret = ldb_msg_add_value(io->ac->update_msg,
2704 "supplementalCredentials",
2705 &io->g.supplemental, NULL);
2706 if (ret != LDB_SUCCESS) {
2710 if (io->ac->update_lastset) {
2711 ret = samdb_msg_add_uint64(ldb, io->ac,
2715 if (ret != LDB_SUCCESS) {
2724 * This is intended for use by the "password_hash" module since there
2725 * password changes can be specified through one message element with the
2726 * new password (to set) and another one with the old password (to unset).
2728 * The first which sets a password (new value) can have flags
2729 * (LDB_FLAG_MOD_ADD, LDB_FLAG_MOD_REPLACE) but also none (on "add" operations
2730 * for entries). The latter (old value) has always specified
2731 * LDB_FLAG_MOD_DELETE.
2733 * Returns LDB_ERR_CONSTRAINT_VIOLATION and LDB_ERR_UNWILLING_TO_PERFORM if
2734 * matching message elements are malformed in respect to the set/change rules.
2735 * Otherwise it returns LDB_SUCCESS.
2737 static int msg_find_old_and_new_pwd_val(const struct ldb_message *msg,
2739 enum ldb_request_type operation,
2740 const struct ldb_val **new_val,
2741 const struct ldb_val **old_val)
2752 for (i = 0; i < msg->num_elements; i++) {
2753 if (ldb_attr_cmp(msg->elements[i].name, name) != 0) {
2757 if ((operation == LDB_MODIFY) &&
2758 (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_DELETE)) {
2759 /* 0 values are allowed */
2760 if (msg->elements[i].num_values == 1) {
2761 *old_val = &msg->elements[i].values[0];
2762 } else if (msg->elements[i].num_values > 1) {
2763 return LDB_ERR_CONSTRAINT_VIOLATION;
2765 } else if ((operation == LDB_MODIFY) &&
2766 (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_REPLACE)) {
2767 if (msg->elements[i].num_values > 0) {
2768 *new_val = &msg->elements[i].values[msg->elements[i].num_values - 1];
2770 return LDB_ERR_UNWILLING_TO_PERFORM;
2773 /* Add operations and LDB_FLAG_MOD_ADD */
2774 if (msg->elements[i].num_values > 0) {
2775 *new_val = &msg->elements[i].values[msg->elements[i].num_values - 1];
2777 return LDB_ERR_CONSTRAINT_VIOLATION;
2785 static int setup_io(struct ph_context *ac,
2786 const struct ldb_message *client_msg,
2787 const struct ldb_message *existing_msg,
2788 struct setup_password_fields_io *io)
2790 const struct ldb_val *quoted_utf16, *old_quoted_utf16, *lm_hash, *old_lm_hash;
2791 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2792 struct loadparm_context *lp_ctx = talloc_get_type(
2793 ldb_get_opaque(ldb, "loadparm"), struct loadparm_context);
2795 const struct ldb_message *info_msg = NULL;
2799 /* Some operations below require kerberos contexts */
2801 if (existing_msg != NULL) {
2803 * This is a modify operation
2805 info_msg = existing_msg;
2808 * This is an add operation
2810 info_msg = client_msg;
2813 if (smb_krb5_init_context(ac,
2814 (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"),
2815 &io->smb_krb5_context) != 0) {
2816 return ldb_operr(ldb);
2821 io->u.userAccountControl = ldb_msg_find_attr_as_uint(info_msg,
2822 "userAccountControl", 0);
2823 if (info_msg == existing_msg) {
2825 * We only take pwdLastSet from the existing object
2826 * otherwise we leave it as 0.
2828 * If no attribute is available, e.g. on deleted objects
2829 * we remember that as UINT64_MAX.
2831 io->u.pwdLastSet = samdb_result_nttime(info_msg, "pwdLastSet",
2834 io->u.sAMAccountName = ldb_msg_find_attr_as_string(info_msg,
2835 "sAMAccountName", NULL);
2836 io->u.user_principal_name = ldb_msg_find_attr_as_string(info_msg,
2837 "userPrincipalName", NULL);
2838 io->u.is_computer = ldb_msg_check_string_attribute(info_msg, "objectClass", "computer");
2840 if (io->u.sAMAccountName == NULL) {
2841 ldb_asprintf_errstring(ldb,
2842 "setup_io: sAMAccountName attribute is missing on %s for attempted password set/change",
2843 ldb_dn_get_linearized(info_msg->dn));
2845 return LDB_ERR_CONSTRAINT_VIOLATION;
2848 if (io->u.userAccountControl & UF_INTERDOMAIN_TRUST_ACCOUNT) {
2849 struct ldb_control *permit_trust = ldb_request_get_control(ac->req,
2850 DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID);
2852 if (permit_trust == NULL) {
2853 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2854 ldb_asprintf_errstring(ldb,
2855 "%08X: %s - setup_io: changing the interdomain trust password "
2856 "on %s not allowed via LDAP. Use LSA or NETLOGON",
2857 W_ERROR_V(WERR_ACCESS_DENIED),
2859 ldb_dn_get_linearized(info_msg->dn));
2864 /* Only non-trust accounts have restrictions (possibly this test is the
2865 * wrong way around, but we like to be restrictive if possible */
2866 io->u.restrictions = !(io->u.userAccountControl
2867 & (UF_INTERDOMAIN_TRUST_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT
2868 | UF_SERVER_TRUST_ACCOUNT));
2870 if (ac->userPassword) {
2871 ret = msg_find_old_and_new_pwd_val(client_msg, "userPassword",
2873 &io->n.cleartext_utf8,
2874 &io->og.cleartext_utf8);
2875 if (ret != LDB_SUCCESS) {
2876 ldb_asprintf_errstring(ldb,
2878 "it's only allowed to set the old password once!");
2883 if (io->n.cleartext_utf8 != NULL) {
2884 struct ldb_val *cleartext_utf8_blob;
2887 cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
2888 if (!cleartext_utf8_blob) {
2889 return ldb_oom(ldb);
2892 *cleartext_utf8_blob = *io->n.cleartext_utf8;
2894 /* make sure we have a null terminated string */
2895 p = talloc_strndup(cleartext_utf8_blob,
2896 (const char *)io->n.cleartext_utf8->data,
2897 io->n.cleartext_utf8->length);
2898 if ((p == NULL) && (io->n.cleartext_utf8->length > 0)) {
2899 return ldb_oom(ldb);
2901 cleartext_utf8_blob->data = (uint8_t *)p;
2903 io->n.cleartext_utf8 = cleartext_utf8_blob;
2906 ret = msg_find_old_and_new_pwd_val(client_msg, "clearTextPassword",
2908 &io->n.cleartext_utf16,
2909 &io->og.cleartext_utf16);
2910 if (ret != LDB_SUCCESS) {
2911 ldb_asprintf_errstring(ldb,
2913 "it's only allowed to set the old password once!");
2917 /* this rather strange looking piece of code is there to
2918 handle a ldap client setting a password remotely using the
2919 unicodePwd ldap field. The syntax is that the password is
2920 in UTF-16LE, with a " at either end. Unfortunately the
2921 unicodePwd field is also used to store the nt hashes
2922 internally in Samba, and is used in the nt hash format on
2923 the wire in DRS replication, so we have a single name for
2924 two distinct values. The code below leaves us with a small
2925 chance (less than 1 in 2^32) of a mixup, if someone manages
2926 to create a MD4 hash which starts and ends in 0x22 0x00, as
2927 that would then be treated as a UTF16 password rather than
2930 ret = msg_find_old_and_new_pwd_val(client_msg, "unicodePwd",
2934 if (ret != LDB_SUCCESS) {
2935 ldb_asprintf_errstring(ldb,
2937 "it's only allowed to set the old password once!");
2941 /* Checks and converts the actual "unicodePwd" attribute */
2942 if (!ac->hash_values &&
2944 quoted_utf16->length >= 4 &&
2945 quoted_utf16->data[0] == '"' &&
2946 quoted_utf16->data[1] == 0 &&
2947 quoted_utf16->data[quoted_utf16->length-2] == '"' &&
2948 quoted_utf16->data[quoted_utf16->length-1] == 0) {
2949 struct ldb_val *quoted_utf16_2;
2951 if (io->n.cleartext_utf16) {
2952 /* refuse the change if someone wants to change with
2953 with both UTF16 possibilities at the same time... */
2954 ldb_asprintf_errstring(ldb,
2956 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
2957 return LDB_ERR_UNWILLING_TO_PERFORM;
2961 * adapt the quoted UTF16 string to be a real
2964 quoted_utf16_2 = talloc(io->ac, struct ldb_val);
2965 if (quoted_utf16_2 == NULL) {
2966 return ldb_oom(ldb);
2969 quoted_utf16_2->data = quoted_utf16->data + 2;
2970 quoted_utf16_2->length = quoted_utf16->length-4;
2971 io->n.cleartext_utf16 = quoted_utf16_2;
2972 io->n.nt_hash = NULL;
2974 } else if (quoted_utf16) {
2975 /* We have only the hash available -> so no plaintext here */
2976 if (!ac->hash_values) {
2977 /* refuse the change if someone wants to change
2978 the hash without control specified... */
2979 ldb_asprintf_errstring(ldb,
2981 "it's not allowed to set the NT hash password directly'");
2982 /* this looks odd but this is what Windows does:
2983 returns "UNWILLING_TO_PERFORM" on wrong
2984 password sets and "CONSTRAINT_VIOLATION" on
2985 wrong password changes. */
2986 if (old_quoted_utf16 == NULL) {
2987 return LDB_ERR_UNWILLING_TO_PERFORM;
2990 return LDB_ERR_CONSTRAINT_VIOLATION;
2993 io->n.nt_hash = talloc(io->ac, struct samr_Password);
2994 memcpy(io->n.nt_hash->hash, quoted_utf16->data,
2995 MIN(quoted_utf16->length, sizeof(io->n.nt_hash->hash)));
2998 /* Checks and converts the previous "unicodePwd" attribute */
2999 if (!ac->hash_values &&
3001 old_quoted_utf16->length >= 4 &&
3002 old_quoted_utf16->data[0] == '"' &&
3003 old_quoted_utf16->data[1] == 0 &&
3004 old_quoted_utf16->data[old_quoted_utf16->length-2] == '"' &&
3005 old_quoted_utf16->data[old_quoted_utf16->length-1] == 0) {
3006 struct ldb_val *old_quoted_utf16_2;
3008 if (io->og.cleartext_utf16) {
3009 /* refuse the change if someone wants to change with
3010 both UTF16 possibilities at the same time... */
3011 ldb_asprintf_errstring(ldb,
3013 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
3014 return LDB_ERR_UNWILLING_TO_PERFORM;
3018 * adapt the quoted UTF16 string to be a real
3021 old_quoted_utf16_2 = talloc(io->ac, struct ldb_val);
3022 if (old_quoted_utf16_2 == NULL) {
3023 return ldb_oom(ldb);
3026 old_quoted_utf16_2->data = old_quoted_utf16->data + 2;
3027 old_quoted_utf16_2->length = old_quoted_utf16->length-4;
3029 io->og.cleartext_utf16 = old_quoted_utf16_2;
3030 io->og.nt_hash = NULL;
3031 } else if (old_quoted_utf16) {
3032 /* We have only the hash available -> so no plaintext here */
3033 if (!ac->hash_values) {
3034 /* refuse the change if someone wants to change
3035 the hash without control specified... */
3036 ldb_asprintf_errstring(ldb,
3038 "it's not allowed to set the NT hash password directly'");
3039 return LDB_ERR_UNWILLING_TO_PERFORM;
3042 io->og.nt_hash = talloc(io->ac, struct samr_Password);
3043 memcpy(io->og.nt_hash->hash, old_quoted_utf16->data,
3044 MIN(old_quoted_utf16->length, sizeof(io->og.nt_hash->hash)));
3047 /* Handles the "dBCSPwd" attribute (LM hash) */
3048 io->n.lm_hash = NULL; io->og.lm_hash = NULL;
3049 ret = msg_find_old_and_new_pwd_val(client_msg, "dBCSPwd",
3051 &lm_hash, &old_lm_hash);
3052 if (ret != LDB_SUCCESS) {
3053 ldb_asprintf_errstring(ldb,
3055 "it's only allowed to set the old password once!");
3059 if (((lm_hash != NULL) || (old_lm_hash != NULL)) && (!ac->hash_values)) {
3060 /* refuse the change if someone wants to change the hash
3061 without control specified... */
3062 ldb_asprintf_errstring(ldb,
3064 "it's not allowed to set the LM hash password directly'");
3065 return LDB_ERR_UNWILLING_TO_PERFORM;
3068 if (lpcfg_lanman_auth(lp_ctx) && (lm_hash != NULL)) {
3069 io->n.lm_hash = talloc(io->ac, struct samr_Password);
3070 memcpy(io->n.lm_hash->hash, lm_hash->data, MIN(lm_hash->length,
3071 sizeof(io->n.lm_hash->hash)));
3073 if (lpcfg_lanman_auth(lp_ctx) && (old_lm_hash != NULL)) {
3074 io->og.lm_hash = talloc(io->ac, struct samr_Password);
3075 memcpy(io->og.lm_hash->hash, old_lm_hash->data, MIN(old_lm_hash->length,
3076 sizeof(io->og.lm_hash->hash)));
3080 * Handles the password change control if it's specified. It has the
3081 * precedance and overrides already specified old password values of
3082 * change requests (but that shouldn't happen since the control is
3083 * fully internal and only used in conjunction with replace requests!).
3085 if (ac->change != NULL) {
3086 io->og.nt_hash = NULL;
3087 if (ac->change->old_nt_pwd_hash != NULL) {
3088 io->og.nt_hash = talloc_memdup(io->ac,
3089 ac->change->old_nt_pwd_hash,
3090 sizeof(struct samr_Password));
3092 io->og.lm_hash = NULL;
3093 if (lpcfg_lanman_auth(lp_ctx) && (ac->change->old_lm_pwd_hash != NULL)) {
3094 io->og.lm_hash = talloc_memdup(io->ac,
3095 ac->change->old_lm_pwd_hash,
3096 sizeof(struct samr_Password));
3100 /* refuse the change if someone wants to change the clear-
3101 text and supply his own hashes at the same time... */
3102 if ((io->n.cleartext_utf8 || io->n.cleartext_utf16)
3103 && (io->n.nt_hash || io->n.lm_hash)) {
3104 ldb_asprintf_errstring(ldb,
3106 "it's only allowed to set the password in form of cleartext attributes or as hashes");
3107 return LDB_ERR_UNWILLING_TO_PERFORM;
3110 /* refuse the change if someone wants to change the password
3111 using both plaintext methods (UTF8 and UTF16) at the same time... */
3112 if (io->n.cleartext_utf8 && io->n.cleartext_utf16) {
3113 ldb_asprintf_errstring(ldb,
3115 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
3116 return LDB_ERR_UNWILLING_TO_PERFORM;
3119 /* refuse the change if someone tries to set/change the password by
3120 * the lanman hash alone and we've deactivated that mechanism. This
3121 * would end in an account without any password! */
3122 if (io->ac->update_password
3123 && (!io->n.cleartext_utf8) && (!io->n.cleartext_utf16)
3124 && (!io->n.nt_hash) && (!io->n.lm_hash)) {
3125 ldb_asprintf_errstring(ldb,
3127 "It's not possible to delete the password (changes using the LAN Manager hash alone could be deactivated)!");
3128 /* on "userPassword" and "clearTextPassword" we've to return
3129 * something different, since these are virtual attributes */
3130 if ((ldb_msg_find_element(client_msg, "userPassword") != NULL) ||
3131 (ldb_msg_find_element(client_msg, "clearTextPassword") != NULL)) {
3132 return LDB_ERR_CONSTRAINT_VIOLATION;
3134 return LDB_ERR_UNWILLING_TO_PERFORM;
3137 /* refuse the change if someone wants to compare against a plaintext
3138 or hash at the same time for a "password modify" operation... */
3139 if ((io->og.cleartext_utf8 || io->og.cleartext_utf16)
3140 && (io->og.nt_hash || io->og.lm_hash)) {
3141 ldb_asprintf_errstring(ldb,
3143 "it's only allowed to provide the old password in form of cleartext attributes or as hashes");
3144 return LDB_ERR_UNWILLING_TO_PERFORM;
3147 /* refuse the change if someone wants to compare against both
3148 * plaintexts at the same time for a "password modify" operation... */
3149 if (io->og.cleartext_utf8 && io->og.cleartext_utf16) {
3150 ldb_asprintf_errstring(ldb,
3152 "it's only allowed to provide the old cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
3153 return LDB_ERR_UNWILLING_TO_PERFORM;
3156 /* Decides if we have a password modify or password reset operation */
3157 if (ac->req->operation == LDB_ADD) {
3158 /* On "add" we have only "password reset" */
3159 ac->pwd_reset = true;
3160 } else if (ac->req->operation == LDB_MODIFY) {
3161 if (io->og.cleartext_utf8 || io->og.cleartext_utf16
3162 || io->og.nt_hash || io->og.lm_hash) {
3163 /* If we have an old password specified then for sure it
3164 * is a user "password change" */
3165 ac->pwd_reset = false;
3167 /* Otherwise we have also here a "password reset" */
3168 ac->pwd_reset = true;
3171 /* this shouldn't happen */
3172 return ldb_operr(ldb);
3175 if (existing_msg != NULL) {
3178 if (ac->pwd_reset) {
3179 /* Get the old password from the database */
3180 status = samdb_result_passwords_no_lockout(ac,
3186 /* Get the old password from the database */
3187 status = samdb_result_passwords(ac,
3194 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCOUNT_LOCKED_OUT)) {
3195 return dsdb_module_werror(ac->module,
3196 LDB_ERR_CONSTRAINT_VIOLATION,
3197 WERR_ACCOUNT_LOCKED_OUT,
3198 "Password change not permitted,"
3199 " account locked out!");
3202 if (!NT_STATUS_IS_OK(status)) {
3204 * This only happens if the database has gone weird,
3205 * not if we are just missing the passwords
3207 return ldb_operr(ldb);
3210 io->o.nt_history_len = samdb_result_hashes(ac, existing_msg,
3213 io->o.lm_history_len = samdb_result_hashes(ac, existing_msg,
3216 io->o.supplemental = ldb_msg_find_ldb_val(existing_msg,
3217 "supplementalCredentials");
3219 if (io->o.supplemental != NULL) {
3220 enum ndr_err_code ndr_err;
3222 ndr_err = ndr_pull_struct_blob_all(io->o.supplemental, io->ac,
3224 (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
3225 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3226 status = ndr_map_error2ntstatus(ndr_err);
3227 ldb_asprintf_errstring(ldb,
3228 "setup_io: failed to pull "
3229 "old supplementalCredentialsBlob: %s",
3231 return LDB_ERR_OPERATIONS_ERROR;
3239 static struct ph_context *ph_init_context(struct ldb_module *module,
3240 struct ldb_request *req,
3242 bool update_password)
3244 struct ldb_context *ldb;
3245 struct ph_context *ac;
3246 struct loadparm_context *lp_ctx = NULL;
3248 ldb = ldb_module_get_ctx(module);
3250 ac = talloc_zero(req, struct ph_context);
3252 ldb_set_errstring(ldb, "Out of Memory");
3256 ac->module = module;
3258 ac->userPassword = userPassword;
3259 ac->update_password = update_password;
3260 ac->update_lastset = true;
3262 lp_ctx = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"),
3263 struct loadparm_context);
3264 ac->gpg_key_ids = lpcfg_password_hash_gpg_key_ids(lp_ctx);
3269 static void ph_apply_controls(struct ph_context *ac)
3271 struct ldb_control *ctrl;
3273 ac->change_status = false;
3274 ctrl = ldb_request_get_control(ac->req,
3275 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID);
3277 ac->change_status = true;
3279 /* Mark the "change status" control as uncritical (done) */
3280 ctrl->critical = false;
3283 ac->hash_values = false;
3284 ctrl = ldb_request_get_control(ac->req,
3285 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID);
3287 ac->hash_values = true;
3289 /* Mark the "hash values" control as uncritical (done) */
3290 ctrl->critical = false;
3293 ctrl = ldb_request_get_control(ac->req,
3294 DSDB_CONTROL_PASSWORD_CHANGE_OID);
3296 ac->change = (struct dsdb_control_password_change *) ctrl->data;
3298 /* Mark the "change" control as uncritical (done) */
3299 ctrl->critical = false;
3302 ac->pwd_last_set_bypass = false;
3303 ctrl = ldb_request_get_control(ac->req,
3304 DSDB_CONTROL_PASSWORD_BYPASS_LAST_SET_OID);
3306 ac->pwd_last_set_bypass = true;
3308 /* Mark the "bypass pwdLastSet" control as uncritical (done) */
3309 ctrl->critical = false;
3312 ac->pwd_last_set_default = false;
3313 ctrl = ldb_request_get_control(ac->req,
3314 DSDB_CONTROL_PASSWORD_DEFAULT_LAST_SET_OID);
3316 ac->pwd_last_set_default = true;
3318 /* Mark the "bypass pwdLastSet" control as uncritical (done) */
3319 ctrl->critical = false;
3322 ac->smartcard_reset = false;
3323 ctrl = ldb_request_get_control(ac->req,
3324 DSDB_CONTROL_PASSWORD_USER_ACCOUNT_CONTROL_OID);
3326 struct dsdb_control_password_user_account_control *uac = NULL;
3327 uint32_t added_flags = 0;
3329 uac = talloc_get_type_abort(ctrl->data,
3330 struct dsdb_control_password_user_account_control);
3332 added_flags = uac->new_flags & ~uac->old_flags;
3334 if (added_flags & UF_SMARTCARD_REQUIRED) {
3335 ac->smartcard_reset = true;
3338 /* Mark the "smartcard required" control as uncritical (done) */
3339 ctrl->critical = false;
3343 static int ph_op_callback(struct ldb_request *req, struct ldb_reply *ares)
3345 struct ph_context *ac;
3347 ac = talloc_get_type(req->context, struct ph_context);
3350 return ldb_module_done(ac->req, NULL, NULL,
3351 LDB_ERR_OPERATIONS_ERROR);
3354 if (ares->type == LDB_REPLY_REFERRAL) {
3355 return ldb_module_send_referral(ac->req, ares->referral);
3358 if ((ares->error != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
3359 /* On success and trivial errors a status control is being
3360 * added (used for example by the "samdb_set_password" call) */
3361 ldb_reply_add_control(ares,
3362 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
3367 if (ares->error != LDB_SUCCESS) {
3368 return ldb_module_done(ac->req, ares->controls,
3369 ares->response, ares->error);
3372 if (ares->type != LDB_REPLY_DONE) {
3374 return ldb_module_done(ac->req, NULL, NULL,
3375 LDB_ERR_OPERATIONS_ERROR);
3378 return ldb_module_done(ac->req, ares->controls,
3379 ares->response, ares->error);
3382 static int password_hash_add_do_add(struct ph_context *ac);
3383 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares);
3384 static int password_hash_mod_search_self(struct ph_context *ac);
3385 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares);
3386 static int password_hash_mod_do_mod(struct ph_context *ac);
3388 static int get_domain_data_callback(struct ldb_request *req,
3389 struct ldb_reply *ares)
3391 struct ldb_context *ldb;
3392 struct ph_context *ac;
3393 struct loadparm_context *lp_ctx;
3394 int ret = LDB_SUCCESS;
3396 ac = talloc_get_type(req->context, struct ph_context);
3397 ldb = ldb_module_get_ctx(ac->module);
3400 ret = LDB_ERR_OPERATIONS_ERROR;
3403 if (ares->error != LDB_SUCCESS) {
3404 return ldb_module_done(ac->req, ares->controls,
3405 ares->response, ares->error);
3408 switch (ares->type) {
3409 case LDB_REPLY_ENTRY:
3410 if (ac->status != NULL) {
3413 ldb_set_errstring(ldb, "Too many results");
3414 ret = LDB_ERR_OPERATIONS_ERROR;
3418 /* Setup the "status" structure (used as control later) */
3419 ac->status = talloc_zero(ac->req,
3420 struct dsdb_control_password_change_status);
3421 if (ac->status == NULL) {
3425 ret = LDB_ERR_OPERATIONS_ERROR;
3429 /* Setup the "domain data" structure */
3430 ac->status->domain_data.pwdProperties =
3431 ldb_msg_find_attr_as_uint(ares->message, "pwdProperties", -1);
3432 ac->status->domain_data.pwdHistoryLength =
3433 ldb_msg_find_attr_as_uint(ares->message, "pwdHistoryLength", -1);
3434 ac->status->domain_data.maxPwdAge =
3435 ldb_msg_find_attr_as_int64(ares->message, "maxPwdAge", -1);
3436 ac->status->domain_data.minPwdAge =
3437 ldb_msg_find_attr_as_int64(ares->message, "minPwdAge", -1);
3438 ac->status->domain_data.minPwdLength =
3439 ldb_msg_find_attr_as_uint(ares->message, "minPwdLength", -1);
3440 ac->status->domain_data.store_cleartext =
3441 ac->status->domain_data.pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
3443 /* For a domain DN, this puts things in dotted notation */
3444 /* For builtin domains, this will give details for the host,
3445 * but that doesn't really matter, as it's just used for salt
3446 * and kerberos principals, which don't exist here */
3448 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3449 struct loadparm_context);
3451 ac->status->domain_data.dns_domain = lpcfg_dnsdomain(lp_ctx);
3452 ac->status->domain_data.realm = lpcfg_realm(lp_ctx);
3453 ac->status->domain_data.netbios_domain = lpcfg_sam_name(lp_ctx);
3455 ac->status->reject_reason = SAM_PWD_CHANGE_NO_ERROR;
3457 if (ac->dom_res != NULL) {
3460 ldb_set_errstring(ldb, "Too many results");
3461 ret = LDB_ERR_OPERATIONS_ERROR;
3465 ac->dom_res = talloc_steal(ac, ares);
3469 case LDB_REPLY_REFERRAL:
3475 case LDB_REPLY_DONE:
3477 /* call the next step */
3478 switch (ac->req->operation) {
3480 ret = password_hash_add_do_add(ac);
3484 ret = password_hash_mod_do_mod(ac);
3488 ret = LDB_ERR_OPERATIONS_ERROR;
3495 if (ret != LDB_SUCCESS) {
3496 struct ldb_reply *new_ares;
3498 new_ares = talloc_zero(ac->req, struct ldb_reply);
3499 if (new_ares == NULL) {
3501 return ldb_module_done(ac->req, NULL, NULL,
3502 LDB_ERR_OPERATIONS_ERROR);
3505 new_ares->error = ret;
3506 if ((ret != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
3507 /* On success and trivial errors a status control is being
3508 * added (used for example by the "samdb_set_password" call) */
3509 ldb_reply_add_control(new_ares,
3510 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
3515 return ldb_module_done(ac->req, new_ares->controls,
3516 new_ares->response, new_ares->error);
3522 static int build_domain_data_request(struct ph_context *ac)
3524 /* attrs[] is returned from this function in
3525 ac->dom_req->op.search.attrs, so it must be static, as
3526 otherwise the compiler can put it on the stack */
3527 struct ldb_context *ldb;
3528 static const char * const attrs[] = { "pwdProperties",
3534 "lockOutObservationWindow",
3538 ldb = ldb_module_get_ctx(ac->module);
3540 ret = ldb_build_search_req(&ac->dom_req, ldb, ac,
3541 ldb_get_default_basedn(ldb),
3545 ac, get_domain_data_callback,
3547 LDB_REQ_SET_LOCATION(ac->dom_req);
3551 static int password_hash_needed(struct ldb_module *module,
3552 struct ldb_request *req,
3553 struct ph_context **_ac)
3555 struct ldb_context *ldb = ldb_module_get_ctx(module);
3556 const char *operation = NULL;
3557 const struct ldb_message *msg = NULL;
3558 struct ph_context *ac = NULL;
3559 const char *passwordAttrs[] = {
3561 "clearTextPassword",
3566 const char **a = NULL;
3567 unsigned int attr_cnt = 0;
3568 struct ldb_control *bypass = NULL;
3569 struct ldb_control *uac_ctrl = NULL;
3570 bool userPassword = dsdb_user_password_support(module, req, req);
3571 bool update_password = false;
3572 bool processing_needed = false;
3576 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_needed\n");
3578 switch (req->operation) {
3581 msg = req->op.add.message;
3584 operation = "modify";
3585 msg = req->op.mod.message;
3588 return ldb_next_request(module, req);
3591 if (ldb_dn_is_special(msg->dn)) { /* do not manipulate our control entries */
3592 return ldb_next_request(module, req);
3595 bypass = ldb_request_get_control(req,
3596 DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID);
3597 if (bypass != NULL) {
3598 /* Mark the "bypass" control as uncritical (done) */
3599 bypass->critical = false;
3600 ldb_debug(ldb, LDB_DEBUG_TRACE,
3601 "password_hash_needed(%s) (bypassing)\n",
3603 return password_hash_bypass(module, req);
3606 /* nobody must touch password histories and 'supplementalCredentials' */
3607 if (ldb_msg_find_element(msg, "ntPwdHistory")) {
3608 return LDB_ERR_UNWILLING_TO_PERFORM;
3610 if (ldb_msg_find_element(msg, "lmPwdHistory")) {
3611 return LDB_ERR_UNWILLING_TO_PERFORM;
3613 if (ldb_msg_find_element(msg, "supplementalCredentials")) {
3614 return LDB_ERR_UNWILLING_TO_PERFORM;
3618 * If no part of this touches the 'userPassword' OR 'clearTextPassword'
3619 * OR 'unicodePwd' OR 'dBCSPwd' we don't need to make any changes.
3620 * For password changes/set there should be a 'delete' or a 'modify'
3621 * on these attributes.
3623 for (a = passwordAttrs; *a != NULL; a++) {
3624 if ((!userPassword) && (ldb_attr_cmp(*a, "userPassword") == 0)) {
3628 if (ldb_msg_find_element(msg, *a) != NULL) {
3629 /* MS-ADTS 3.1.1.3.1.5.2 */
3630 if ((ldb_attr_cmp(*a, "userPassword") == 0) &&
3631 (dsdb_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
3632 return LDB_ERR_CONSTRAINT_VIOLATION;
3640 update_password = true;
3641 processing_needed = true;
3644 if (ldb_msg_find_element(msg, "pwdLastSet")) {
3645 processing_needed = true;
3648 uac_ctrl = ldb_request_get_control(req,
3649 DSDB_CONTROL_PASSWORD_USER_ACCOUNT_CONTROL_OID);
3650 if (uac_ctrl != NULL) {
3651 struct dsdb_control_password_user_account_control *uac = NULL;
3652 uint32_t added_flags = 0;
3654 uac = talloc_get_type_abort(uac_ctrl->data,
3655 struct dsdb_control_password_user_account_control);
3657 added_flags = uac->new_flags & ~uac->old_flags;
3659 if (added_flags & UF_SMARTCARD_REQUIRED) {
3660 processing_needed = true;
3664 if (!processing_needed) {
3665 return ldb_next_request(module, req);
3668 ac = ph_init_context(module, req, userPassword, update_password);
3670 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
3671 return ldb_operr(ldb);
3673 ph_apply_controls(ac);
3676 * Make a copy in order to apply our modifications
3677 * to the final update
3679 ac->update_msg = ldb_msg_copy_shallow(ac, msg);
3680 if (ac->update_msg == NULL) {
3681 return ldb_oom(ldb);
3685 * Remove all password related attributes.
3687 if (ac->userPassword) {
3688 ldb_msg_remove_attr(ac->update_msg, "userPassword");
3690 ldb_msg_remove_attr(ac->update_msg, "clearTextPassword");
3691 ldb_msg_remove_attr(ac->update_msg, "unicodePwd");
3692 ldb_msg_remove_attr(ac->update_msg, "ntPwdHistory");
3693 ldb_msg_remove_attr(ac->update_msg, "dBCSPwd");
3694 ldb_msg_remove_attr(ac->update_msg, "lmPwdHistory");
3695 ldb_msg_remove_attr(ac->update_msg, "supplementalCredentials");
3696 ldb_msg_remove_attr(ac->update_msg, "pwdLastSet");
3702 static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
3704 struct ldb_context *ldb = ldb_module_get_ctx(module);
3705 struct ph_context *ac = NULL;
3708 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add\n");
3710 ret = password_hash_needed(module, req, &ac);
3711 if (ret != LDB_SUCCESS) {
3718 /* Make sure we are performing the password set action on a (for us)
3719 * valid object. Those are instances of either "user" and/or
3720 * "inetOrgPerson". Otherwise continue with the submodules. */
3721 if ((!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "user"))
3722 && (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "inetOrgPerson"))) {
3726 if (ldb_msg_find_element(req->op.add.message, "clearTextPassword") != NULL) {
3727 ldb_set_errstring(ldb,
3728 "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
3729 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3732 return ldb_next_request(module, req);
3735 /* get user domain data */
3736 ret = build_domain_data_request(ac);
3737 if (ret != LDB_SUCCESS) {
3741 return ldb_next_request(module, ac->dom_req);
3744 static int password_hash_add_do_add(struct ph_context *ac)
3746 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3747 struct ldb_request *down_req;
3748 struct setup_password_fields_io io;
3751 /* Prepare the internal data structure containing the passwords */
3752 ret = setup_io(ac, ac->req->op.add.message, NULL, &io);
3753 if (ret != LDB_SUCCESS) {
3757 ret = setup_password_fields(&io);
3758 if (ret != LDB_SUCCESS) {
3762 ret = check_password_restrictions(&io);
3763 if (ret != LDB_SUCCESS) {
3767 ret = setup_smartcard_reset(&io);
3768 if (ret != LDB_SUCCESS) {
3772 ret = update_final_msg(&io);
3773 if (ret != LDB_SUCCESS) {
3777 ret = ldb_build_add_req(&down_req, ldb, ac,
3782 LDB_REQ_SET_LOCATION(down_req);
3783 if (ret != LDB_SUCCESS) {
3787 return ldb_next_request(ac->module, down_req);
3790 static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
3792 struct ldb_context *ldb = ldb_module_get_ctx(module);
3793 struct ph_context *ac = NULL;
3794 const char *passwordAttrs[] = { "userPassword", "clearTextPassword",
3795 "unicodePwd", "dBCSPwd", NULL }, **l;
3796 unsigned int del_attr_cnt, add_attr_cnt, rep_attr_cnt;
3797 struct ldb_message_element *passwordAttr;
3798 struct ldb_message *msg;
3799 struct ldb_request *down_req;
3800 struct ldb_control *restore = NULL;
3804 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
3806 ret = password_hash_needed(module, req, &ac);
3807 if (ret != LDB_SUCCESS) {
3814 /* use a new message structure so that we can modify it */
3815 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3817 return ldb_oom(ldb);
3820 /* - check for single-valued password attributes
3821 * (if not return "CONSTRAINT_VIOLATION")
3822 * - check that for a password change operation one add and one delete
3824 * (if not return "CONSTRAINT_VIOLATION" or "UNWILLING_TO_PERFORM")
3825 * - check that a password change and a password set operation cannot
3827 * (if not return "UNWILLING_TO_PERFORM")
3828 * - remove all password attributes modifications from the first change
3829 * operation (anything without the passwords) - we will make the real
3830 * modification later */
3834 for (l = passwordAttrs; *l != NULL; l++) {
3835 if ((!ac->userPassword) &&
3836 (ldb_attr_cmp(*l, "userPassword") == 0)) {
3840 while ((passwordAttr = ldb_msg_find_element(msg, *l)) != NULL) {
3841 if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_DELETE) {
3844 if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_ADD) {
3847 if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_REPLACE) {
3850 if ((passwordAttr->num_values != 1) &&
3851 (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_ADD)) {
3853 ldb_asprintf_errstring(ldb,
3854 "'%s' attribute must have exactly one value on add operations!",
3856 return LDB_ERR_CONSTRAINT_VIOLATION;
3858 if ((passwordAttr->num_values > 1) &&
3859 (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_DELETE)) {
3861 ldb_asprintf_errstring(ldb,
3862 "'%s' attribute must have zero or one value(s) on delete operations!",
3864 return LDB_ERR_CONSTRAINT_VIOLATION;
3866 ldb_msg_remove_element(msg, passwordAttr);
3869 if ((del_attr_cnt == 0) && (add_attr_cnt > 0)) {
3871 ldb_set_errstring(ldb,
3872 "Only the add action for a password change specified!");
3873 return LDB_ERR_UNWILLING_TO_PERFORM;
3875 if ((del_attr_cnt > 1) || (add_attr_cnt > 1)) {
3877 ldb_set_errstring(ldb,
3878 "Only one delete and one add action for a password change allowed!");
3879 return LDB_ERR_UNWILLING_TO_PERFORM;
3881 if ((rep_attr_cnt > 0) && ((del_attr_cnt > 0) || (add_attr_cnt > 0))) {
3883 ldb_set_errstring(ldb,
3884 "Either a password change or a password set operation is allowed!");
3885 return LDB_ERR_UNWILLING_TO_PERFORM;
3888 restore = ldb_request_get_control(req,
3889 DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
3890 if (restore == NULL) {
3892 * A tomstone reanimation generates a double update
3895 * So we only remove it without the
3896 * DSDB_CONTROL_RESTORE_TOMBSTONE_OID control.
3898 ldb_msg_remove_attr(msg, "pwdLastSet");
3902 /* if there was nothing else to be modified skip to next step */
3903 if (msg->num_elements == 0) {
3904 return password_hash_mod_search_self(ac);
3908 * Now we apply all changes remaining in msg
3909 * and remove them from our final update_msg
3912 for (i = 0; i < msg->num_elements; i++) {
3913 ldb_msg_remove_attr(ac->update_msg,
3914 msg->elements[i].name);
3917 ret = ldb_build_mod_req(&down_req, ldb, ac,
3920 ac, ph_modify_callback,
3922 LDB_REQ_SET_LOCATION(down_req);
3923 if (ret != LDB_SUCCESS) {
3927 return ldb_next_request(module, down_req);
3930 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
3932 struct ph_context *ac;
3934 ac = talloc_get_type(req->context, struct ph_context);
3937 return ldb_module_done(ac->req, NULL, NULL,
3938 LDB_ERR_OPERATIONS_ERROR);
3941 if (ares->type == LDB_REPLY_REFERRAL) {
3942 return ldb_module_send_referral(ac->req, ares->referral);
3945 if (ares->error != LDB_SUCCESS) {
3946 return ldb_module_done(ac->req, ares->controls,
3947 ares->response, ares->error);
3950 if (ares->type != LDB_REPLY_DONE) {
3952 return ldb_module_done(ac->req, NULL, NULL,
3953 LDB_ERR_OPERATIONS_ERROR);
3958 return password_hash_mod_search_self(ac);
3961 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
3963 struct ldb_context *ldb;
3964 struct ph_context *ac;
3965 int ret = LDB_SUCCESS;
3967 ac = talloc_get_type(req->context, struct ph_context);
3968 ldb = ldb_module_get_ctx(ac->module);
3971 ret = LDB_ERR_OPERATIONS_ERROR;
3974 if (ares->error != LDB_SUCCESS) {
3975 return ldb_module_done(ac->req, ares->controls,
3976 ares->response, ares->error);
3979 /* we are interested only in the single reply (base search) */
3980 switch (ares->type) {
3981 case LDB_REPLY_ENTRY:
3982 /* Make sure we are performing the password change action on a
3983 * (for us) valid object. Those are instances of either "user"
3984 * and/or "inetOrgPerson". Otherwise continue with the
3986 if ((!ldb_msg_check_string_attribute(ares->message, "objectClass", "user"))
3987 && (!ldb_msg_check_string_attribute(ares->message, "objectClass", "inetOrgPerson"))) {
3990 if (ldb_msg_find_element(ac->req->op.mod.message, "clearTextPassword") != NULL) {
3991 ldb_set_errstring(ldb,
3992 "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
3993 ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
3997 ret = ldb_next_request(ac->module, ac->req);
4001 if (ac->search_res != NULL) {
4004 ldb_set_errstring(ldb, "Too many results");
4005 ret = LDB_ERR_OPERATIONS_ERROR;
4009 ac->search_res = talloc_steal(ac, ares);
4013 case LDB_REPLY_REFERRAL:
4014 /* ignore anything else for now */
4019 case LDB_REPLY_DONE:
4022 /* get user domain data */
4023 ret = build_domain_data_request(ac);
4024 if (ret != LDB_SUCCESS) {
4025 return ldb_module_done(ac->req, NULL, NULL, ret);
4028 ret = ldb_next_request(ac->module, ac->dom_req);
4033 if (ret != LDB_SUCCESS) {
4034 return ldb_module_done(ac->req, NULL, NULL, ret);
4040 static int password_hash_mod_search_self(struct ph_context *ac)
4042 struct ldb_context *ldb;
4043 static const char * const attrs[] = { "objectClass",
4044 "userAccountControl",
4045 "msDS-User-Account-Control-Computed",
4049 "userPrincipalName",
4050 "supplementalCredentials",
4059 struct ldb_request *search_req;
4062 ldb = ldb_module_get_ctx(ac->module);
4064 ret = ldb_build_search_req(&search_req, ldb, ac,
4065 ac->req->op.mod.message->dn,
4070 ac, ph_mod_search_callback,
4072 LDB_REQ_SET_LOCATION(search_req);
4073 if (ret != LDB_SUCCESS) {
4077 return ldb_next_request(ac->module, search_req);
4080 static int password_hash_mod_do_mod(struct ph_context *ac)
4082 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
4083 struct ldb_request *mod_req;
4084 struct setup_password_fields_io io;
4087 /* Prepare the internal data structure containing the passwords */
4088 ret = setup_io(ac, ac->req->op.mod.message,
4089 ac->search_res->message, &io);
4090 if (ret != LDB_SUCCESS) {
4094 ret = setup_password_fields(&io);
4095 if (ret != LDB_SUCCESS) {
4099 ret = check_password_restrictions(&io);
4100 if (ret != LDB_SUCCESS) {
4104 ret = setup_smartcard_reset(&io);
4105 if (ret != LDB_SUCCESS) {
4109 ret = update_final_msg(&io);
4110 if (ret != LDB_SUCCESS) {
4114 ret = ldb_build_mod_req(&mod_req, ldb, ac,
4119 LDB_REQ_SET_LOCATION(mod_req);
4120 if (ret != LDB_SUCCESS) {
4124 return ldb_next_request(ac->module, mod_req);
4127 static const struct ldb_module_ops ldb_password_hash_module_ops = {
4128 .name = "password_hash",
4129 .add = password_hash_add,
4130 .modify = password_hash_modify
4133 int ldb_password_hash_module_init(const char *version)
4136 const char *gversion = NULL;
4137 #endif /* ENABLE_GPGME */
4139 LDB_MODULE_CHECK_VERSION(version);
4143 * Note: this sets a SIGPIPE handler
4144 * if none is active already. See:
4145 * https://www.gnupg.org/documentation/manuals/gpgme/Signal-Handling.html#Signal-Handling
4147 gversion = gpgme_check_version(GPGME_VERSION);
4148 if (gversion == NULL) {
4149 fprintf(stderr, "%s() in %s version[%s]: "
4150 "gpgme_check_version(%s) not available, "
4151 "gpgme_check_version(NULL) => '%s'\n",
4152 __func__, __FILE__, version,
4153 GPGME_VERSION, gpgme_check_version(NULL));
4154 return LDB_ERR_UNAVAILABLE;
4156 #endif /* ENABLE_GPGME */
4158 return ldb_register_module(&ldb_password_hash_module_ops);