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"
47 /* If we have decided there is a reason to work on this request, then
48 * setup all the password hash types correctly.
50 * If we haven't the hashes yet but the password given as plain-text (attributes
51 * 'unicodePwd', 'userPassword' and 'clearTextPassword') we have to check for
52 * the constraints. Once this is done, we calculate the password hashes.
54 * Notice: unlike the real AD which only supports the UTF16 special based
55 * 'unicodePwd' and the UTF8 based 'userPassword' plaintext attribute we
56 * understand also a UTF16 based 'clearTextPassword' one.
57 * The latter is also accessible through LDAP so it can also be set by external
58 * tools and scripts. But be aware that this isn't portable on non SAMBA 4 ADs!
60 * Also when the module receives only the password hashes (possible through
61 * specifying an internal LDB control - for security reasons) some checks are
62 * performed depending on the operation mode (see below) (e.g. if the password
63 * has been in use before if the password memory policy was activated).
65 * Attention: There is a difference between "modify" and "reset" operations
66 * (see MS-ADTS 3.1.1.3.1.5). If the client sends a "add" and "remove"
67 * operation for a password attribute we thread this as a "modify"; if it sends
68 * only a "replace" one we have an (administrative) reset.
70 * Finally, if the administrator has requested that a password history
71 * be maintained, then this should also be written out.
75 /* TODO: [consider always MS-ADTS 3.1.1.3.1.5]
76 * - Check for right connection encryption
79 /* Notice: Definition of "dsdb_control_password_change_status" moved into
83 struct ldb_module *module;
84 struct ldb_request *req;
86 struct ldb_request *dom_req;
87 struct ldb_reply *dom_res;
89 struct ldb_reply *search_res;
91 struct dsdb_control_password_change_status *status;
92 struct dsdb_control_password_change *change;
98 bool pwd_last_set_bypass;
102 struct setup_password_fields_io {
103 struct ph_context *ac;
105 struct smb_krb5_context *smb_krb5_context;
107 /* infos about the user account */
109 uint32_t userAccountControl;
111 const char *sAMAccountName;
112 const char *user_principal_name;
114 uint32_t restrictions;
117 /* new credentials and old given credentials */
118 struct setup_password_fields_given {
119 const struct ldb_val *cleartext_utf8;
120 const struct ldb_val *cleartext_utf16;
121 struct samr_Password *nt_hash;
122 struct samr_Password *lm_hash;
125 /* old credentials */
127 struct samr_Password *nt_hash;
128 struct samr_Password *lm_hash;
129 uint32_t nt_history_len;
130 struct samr_Password *nt_history;
131 uint32_t lm_history_len;
132 struct samr_Password *lm_history;
133 const struct ldb_val *supplemental;
134 struct supplementalCredentialsBlob scb;
137 /* generated credentials */
139 struct samr_Password *nt_hash;
140 struct samr_Password *lm_hash;
141 uint32_t nt_history_len;
142 struct samr_Password *nt_history;
143 uint32_t lm_history_len;
144 struct samr_Password *lm_history;
150 struct ldb_val supplemental;
155 static int password_hash_bypass(struct ldb_module *module, struct ldb_request *request)
157 struct ldb_context *ldb = ldb_module_get_ctx(module);
158 const struct ldb_message *msg;
159 struct ldb_message_element *nte;
160 struct ldb_message_element *lme;
161 struct ldb_message_element *nthe;
162 struct ldb_message_element *lmhe;
163 struct ldb_message_element *sce;
165 switch (request->operation) {
167 msg = request->op.add.message;
170 msg = request->op.mod.message;
173 return ldb_next_request(module, request);
176 /* nobody must touch password histories and 'supplementalCredentials' */
177 nte = dsdb_get_single_valued_attr(msg, "unicodePwd",
179 lme = dsdb_get_single_valued_attr(msg, "dBCSPwd",
181 nthe = dsdb_get_single_valued_attr(msg, "ntPwdHistory",
183 lmhe = dsdb_get_single_valued_attr(msg, "lmPwdHistory",
185 sce = dsdb_get_single_valued_attr(msg, "supplementalCredentials",
188 #define CHECK_HASH_ELEMENT(e, min, max) do {\
189 if (e && e->num_values) { \
190 unsigned int _count; \
191 if (e->num_values != 1) { \
192 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
193 "num_values != 1"); \
195 if ((e->values[0].length % 16) != 0) { \
196 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
197 "length % 16 != 0"); \
199 _count = e->values[0].length / 16; \
200 if (_count < min) { \
201 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
204 if (_count > max) { \
205 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
211 CHECK_HASH_ELEMENT(nte, 1, 1);
212 CHECK_HASH_ELEMENT(lme, 1, 1);
213 CHECK_HASH_ELEMENT(nthe, 1, INT32_MAX);
214 CHECK_HASH_ELEMENT(lmhe, 1, INT32_MAX);
216 if (sce && sce->num_values) {
217 enum ndr_err_code ndr_err;
218 struct supplementalCredentialsBlob *scb;
219 struct supplementalCredentialsPackage *scpp = NULL;
220 struct supplementalCredentialsPackage *scpk = NULL;
221 struct supplementalCredentialsPackage *scpkn = NULL;
222 struct supplementalCredentialsPackage *scpct = NULL;
223 DATA_BLOB scpbp = data_blob_null;
224 DATA_BLOB scpbk = data_blob_null;
225 DATA_BLOB scpbkn = data_blob_null;
226 DATA_BLOB scpbct = data_blob_null;
230 if (sce->num_values != 1) {
231 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
235 scb = talloc_zero(request, struct supplementalCredentialsBlob);
237 return ldb_module_oom(module);
240 ndr_err = ndr_pull_struct_blob_all(&sce->values[0], scb, scb,
241 (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
242 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
243 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
244 "ndr_pull_struct_blob_all");
247 if (scb->sub.num_packages < 2) {
248 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
252 for (i=0; i < scb->sub.num_packages; i++) {
255 subblob = strhex_to_data_blob(scb, scb->sub.packages[i].data);
256 if (subblob.data == NULL) {
257 return ldb_module_oom(module);
260 if (strcmp(scb->sub.packages[i].name, "Packages") == 0) {
262 return ldb_error(ldb,
263 LDB_ERR_CONSTRAINT_VIOLATION,
266 scpp = &scb->sub.packages[i];
270 if (strcmp(scb->sub.packages[i].name, "Primary:Kerberos") == 0) {
272 return ldb_error(ldb,
273 LDB_ERR_CONSTRAINT_VIOLATION,
274 "Primary:Kerberos twice");
276 scpk = &scb->sub.packages[i];
280 if (strcmp(scb->sub.packages[i].name, "Primary:Kerberos-Newer-Keys") == 0) {
282 return ldb_error(ldb,
283 LDB_ERR_CONSTRAINT_VIOLATION,
284 "Primary:Kerberos-Newer-Keys twice");
286 scpkn = &scb->sub.packages[i];
290 if (strcmp(scb->sub.packages[i].name, "Primary:CLEARTEXT") == 0) {
292 return ldb_error(ldb,
293 LDB_ERR_CONSTRAINT_VIOLATION,
294 "Primary:CLEARTEXT twice");
296 scpct = &scb->sub.packages[i];
301 data_blob_free(&subblob);
305 struct package_PackagesBlob *p;
308 p = talloc_zero(scb, struct package_PackagesBlob);
310 return ldb_module_oom(module);
313 ndr_err = ndr_pull_struct_blob(&scpbp, p, p,
314 (ndr_pull_flags_fn_t)ndr_pull_package_PackagesBlob);
315 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
316 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
317 "ndr_pull_struct_blob Packages");
320 if (p->names == NULL) {
321 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
322 "Packages names == NULL");
325 for (n = 0; p->names[n]; n++) {
329 if (scb->sub.num_packages != (n + 1)) {
330 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
331 "Packages num_packages != num_names + 1");
338 struct package_PrimaryKerberosBlob *k;
340 k = talloc_zero(scb, struct package_PrimaryKerberosBlob);
342 return ldb_module_oom(module);
345 ndr_err = ndr_pull_struct_blob(&scpbk, k, k,
346 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
347 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
348 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
349 "ndr_pull_struct_blob PrimaryKerberos");
352 if (k->version != 3) {
353 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
354 "PrimaryKerberos version != 3");
357 if (k->ctr.ctr3.salt.string == NULL) {
358 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
359 "PrimaryKerberos salt == NULL");
362 if (strlen(k->ctr.ctr3.salt.string) == 0) {
363 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
364 "PrimaryKerberos strlen(salt) == 0");
367 if (k->ctr.ctr3.num_keys != 2) {
368 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
369 "PrimaryKerberos num_keys != 2");
372 if (k->ctr.ctr3.num_old_keys > k->ctr.ctr3.num_keys) {
373 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
374 "PrimaryKerberos num_old_keys > num_keys");
377 if (k->ctr.ctr3.keys[0].keytype != ENCTYPE_DES_CBC_MD5) {
378 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
379 "PrimaryKerberos key[0] != DES_CBC_MD5");
381 if (k->ctr.ctr3.keys[1].keytype != ENCTYPE_DES_CBC_CRC) {
382 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
383 "PrimaryKerberos key[1] != DES_CBC_CRC");
386 if (k->ctr.ctr3.keys[0].value_len != 8) {
387 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
388 "PrimaryKerberos key[0] value_len != 8");
390 if (k->ctr.ctr3.keys[1].value_len != 8) {
391 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
392 "PrimaryKerberos key[1] value_len != 8");
395 for (i = 0; i < k->ctr.ctr3.num_old_keys; i++) {
396 if (k->ctr.ctr3.old_keys[i].keytype ==
397 k->ctr.ctr3.keys[i].keytype &&
398 k->ctr.ctr3.old_keys[i].value_len ==
399 k->ctr.ctr3.keys[i].value_len) {
403 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
404 "PrimaryKerberos old_keys type/value_len doesn't match");
411 struct package_PrimaryKerberosBlob *k;
413 k = talloc_zero(scb, struct package_PrimaryKerberosBlob);
415 return ldb_module_oom(module);
418 ndr_err = ndr_pull_struct_blob(&scpbkn, k, k,
419 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
420 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
421 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
422 "ndr_pull_struct_blob PrimaryKerberosNeverKeys");
425 if (k->version != 4) {
426 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
427 "KerberosNerverKeys version != 4");
430 if (k->ctr.ctr4.salt.string == NULL) {
431 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
432 "KerberosNewerKeys salt == NULL");
435 if (strlen(k->ctr.ctr4.salt.string) == 0) {
436 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
437 "KerberosNewerKeys strlen(salt) == 0");
440 if (k->ctr.ctr4.num_keys != 4) {
441 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
442 "KerberosNewerKeys num_keys != 2");
445 if (k->ctr.ctr4.num_old_keys > k->ctr.ctr4.num_keys) {
446 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
447 "KerberosNewerKeys num_old_keys > num_keys");
450 if (k->ctr.ctr4.num_older_keys > k->ctr.ctr4.num_old_keys) {
451 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
452 "KerberosNewerKeys num_older_keys > num_old_keys");
455 if (k->ctr.ctr4.keys[0].keytype != ENCTYPE_AES256_CTS_HMAC_SHA1_96) {
456 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
457 "KerberosNewerKeys key[0] != AES256");
459 if (k->ctr.ctr4.keys[1].keytype != ENCTYPE_AES128_CTS_HMAC_SHA1_96) {
460 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
461 "KerberosNewerKeys key[1] != AES128");
463 if (k->ctr.ctr4.keys[2].keytype != ENCTYPE_DES_CBC_MD5) {
464 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
465 "KerberosNewerKeys key[2] != DES_CBC_MD5");
467 if (k->ctr.ctr4.keys[3].keytype != ENCTYPE_DES_CBC_CRC) {
468 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
469 "KerberosNewerKeys key[3] != DES_CBC_CRC");
472 if (k->ctr.ctr4.keys[0].value_len != 32) {
473 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
474 "KerberosNewerKeys key[0] value_len != 32");
476 if (k->ctr.ctr4.keys[1].value_len != 16) {
477 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
478 "KerberosNewerKeys key[1] value_len != 16");
480 if (k->ctr.ctr4.keys[2].value_len != 8) {
481 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
482 "KerberosNewerKeys key[2] value_len != 8");
484 if (k->ctr.ctr4.keys[3].value_len != 8) {
485 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
486 "KerberosNewerKeys key[3] value_len != 8");
491 * Maybe we can check old and older keys here.
492 * But we need to do some tests, if the old keys
493 * can be taken from the PrimaryKerberos blob
494 * (with only des keys), when the domain was upgraded
502 struct package_PrimaryCLEARTEXTBlob *ct;
504 ct = talloc_zero(scb, struct package_PrimaryCLEARTEXTBlob);
506 return ldb_module_oom(module);
509 ndr_err = ndr_pull_struct_blob(&scpbct, ct, ct,
510 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryCLEARTEXTBlob);
511 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
512 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
513 "ndr_pull_struct_blob PrimaryCLEARTEXT");
516 if ((ct->cleartext.length % 2) != 0) {
517 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
518 "PrimaryCLEARTEXT length % 2 != 0");
524 ndr_err = ndr_push_struct_blob(&blob, scb, scb,
525 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
526 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
527 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
528 "ndr_pull_struct_blob_all");
531 if (sce->values[0].length != blob.length) {
532 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
533 "supplementalCredentialsBlob length differ");
536 if (memcmp(sce->values[0].data, blob.data, blob.length) != 0) {
537 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
538 "supplementalCredentialsBlob memcmp differ");
544 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_bypass - validated\n");
545 return ldb_next_request(module, request);
548 /* Get the NT hash, and fill it in as an entry in the password history,
549 and specify it into io->g.nt_hash */
551 static int setup_nt_fields(struct setup_password_fields_io *io)
553 struct ldb_context *ldb;
556 io->g.nt_hash = io->n.nt_hash;
557 ldb = ldb_module_get_ctx(io->ac->module);
559 if (io->ac->status->domain_data.pwdHistoryLength == 0) {
563 /* We might not have an old NT password */
564 io->g.nt_history = talloc_array(io->ac,
565 struct samr_Password,
566 io->ac->status->domain_data.pwdHistoryLength);
567 if (!io->g.nt_history) {
571 for (i = 0; i < MIN(io->ac->status->domain_data.pwdHistoryLength-1,
572 io->o.nt_history_len); i++) {
573 io->g.nt_history[i+1] = io->o.nt_history[i];
575 io->g.nt_history_len = i + 1;
578 io->g.nt_history[0] = *io->g.nt_hash;
581 * TODO: is this correct?
582 * the simular behavior is correct for the lm history case
584 E_md4hash("", io->g.nt_history[0].hash);
590 /* Get the LANMAN hash, and fill it in as an entry in the password history,
591 and specify it into io->g.lm_hash */
593 static int setup_lm_fields(struct setup_password_fields_io *io)
595 struct ldb_context *ldb;
598 io->g.lm_hash = io->n.lm_hash;
599 ldb = ldb_module_get_ctx(io->ac->module);
601 if (io->ac->status->domain_data.pwdHistoryLength == 0) {
605 /* We might not have an old LM password */
606 io->g.lm_history = talloc_array(io->ac,
607 struct samr_Password,
608 io->ac->status->domain_data.pwdHistoryLength);
609 if (!io->g.lm_history) {
613 for (i = 0; i < MIN(io->ac->status->domain_data.pwdHistoryLength-1,
614 io->o.lm_history_len); i++) {
615 io->g.lm_history[i+1] = io->o.lm_history[i];
617 io->g.lm_history_len = i + 1;
620 io->g.lm_history[0] = *io->g.lm_hash;
622 E_deshash("", io->g.lm_history[0].hash);
628 static int setup_kerberos_keys(struct setup_password_fields_io *io)
630 struct ldb_context *ldb;
631 krb5_error_code krb5_ret;
632 Principal *salt_principal;
635 krb5_data cleartext_data;
637 ldb = ldb_module_get_ctx(io->ac->module);
638 cleartext_data.data = io->n.cleartext_utf8->data;
639 cleartext_data.length = io->n.cleartext_utf8->length;
641 /* Many, many thanks to lukeh@padl.com for this
642 * algorithm, described in his Nov 10 2004 mail to
643 * samba-technical@samba.org */
646 * Determine a salting principal
648 if (io->u.is_computer) {
652 name = strlower_talloc(io->ac, io->u.sAMAccountName);
657 if (name[strlen(name)-1] == '$') {
658 name[strlen(name)-1] = '\0';
661 saltbody = talloc_asprintf(io->ac, "%s.%s", name,
662 io->ac->status->domain_data.dns_domain);
667 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
669 io->ac->status->domain_data.realm,
670 "host", saltbody, NULL);
671 } else if (io->u.user_principal_name) {
672 char *user_principal_name;
675 user_principal_name = talloc_strdup(io->ac, io->u.user_principal_name);
676 if (!user_principal_name) {
680 p = strchr(user_principal_name, '@');
685 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
687 io->ac->status->domain_data.realm,
688 user_principal_name, NULL);
690 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
692 io->ac->status->domain_data.realm,
693 io->u.sAMAccountName, NULL);
696 ldb_asprintf_errstring(ldb,
697 "setup_kerberos_keys: "
698 "generation of a salting principal failed: %s",
699 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
701 return LDB_ERR_OPERATIONS_ERROR;
705 * create salt from salt_principal
707 krb5_ret = krb5_get_pw_salt(io->smb_krb5_context->krb5_context,
708 salt_principal, &salt);
709 krb5_free_principal(io->smb_krb5_context->krb5_context, salt_principal);
711 ldb_asprintf_errstring(ldb,
712 "setup_kerberos_keys: "
713 "generation of krb5_salt failed: %s",
714 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
716 return LDB_ERR_OPERATIONS_ERROR;
718 /* create a talloc copy */
719 io->g.salt = talloc_strndup(io->ac,
720 (char *)salt.saltvalue.data,
721 salt.saltvalue.length);
722 krb5_free_salt(io->smb_krb5_context->krb5_context, salt);
726 salt.saltvalue.data = discard_const(io->g.salt);
727 salt.saltvalue.length = strlen(io->g.salt);
730 * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of
731 * the salt and the cleartext password
733 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
734 ENCTYPE_AES256_CTS_HMAC_SHA1_96,
739 ldb_asprintf_errstring(ldb,
740 "setup_kerberos_keys: "
741 "generation of a aes256-cts-hmac-sha1-96 key failed: %s",
742 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
744 return LDB_ERR_OPERATIONS_ERROR;
746 io->g.aes_256 = data_blob_talloc(io->ac,
748 key.keyvalue.length);
749 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
750 if (!io->g.aes_256.data) {
755 * create ENCTYPE_AES128_CTS_HMAC_SHA1_96 key out of
756 * the salt and the cleartext password
758 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
759 ENCTYPE_AES128_CTS_HMAC_SHA1_96,
764 ldb_asprintf_errstring(ldb,
765 "setup_kerberos_keys: "
766 "generation of a aes128-cts-hmac-sha1-96 key failed: %s",
767 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
769 return LDB_ERR_OPERATIONS_ERROR;
771 io->g.aes_128 = data_blob_talloc(io->ac,
773 key.keyvalue.length);
774 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
775 if (!io->g.aes_128.data) {
780 * create ENCTYPE_DES_CBC_MD5 key out of
781 * the salt and the cleartext password
783 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
789 ldb_asprintf_errstring(ldb,
790 "setup_kerberos_keys: "
791 "generation of a des-cbc-md5 key failed: %s",
792 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
794 return LDB_ERR_OPERATIONS_ERROR;
796 io->g.des_md5 = data_blob_talloc(io->ac,
798 key.keyvalue.length);
799 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
800 if (!io->g.des_md5.data) {
805 * create ENCTYPE_DES_CBC_CRC key out of
806 * the salt and the cleartext password
808 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
814 ldb_asprintf_errstring(ldb,
815 "setup_kerberos_keys: "
816 "generation of a des-cbc-crc key failed: %s",
817 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
819 return LDB_ERR_OPERATIONS_ERROR;
821 io->g.des_crc = data_blob_talloc(io->ac,
823 key.keyvalue.length);
824 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
825 if (!io->g.des_crc.data) {
832 static int setup_primary_kerberos(struct setup_password_fields_io *io,
833 const struct supplementalCredentialsBlob *old_scb,
834 struct package_PrimaryKerberosBlob *pkb)
836 struct ldb_context *ldb;
837 struct package_PrimaryKerberosCtr3 *pkb3 = &pkb->ctr.ctr3;
838 struct supplementalCredentialsPackage *old_scp = NULL;
839 struct package_PrimaryKerberosBlob _old_pkb;
840 struct package_PrimaryKerberosCtr3 *old_pkb3 = NULL;
842 enum ndr_err_code ndr_err;
844 ldb = ldb_module_get_ctx(io->ac->module);
847 * prepare generation of keys
849 * ENCTYPE_DES_CBC_MD5
850 * ENCTYPE_DES_CBC_CRC
853 pkb3->salt.string = io->g.salt;
855 pkb3->keys = talloc_array(io->ac,
856 struct package_PrimaryKerberosKey3,
862 pkb3->keys[0].keytype = ENCTYPE_DES_CBC_MD5;
863 pkb3->keys[0].value = &io->g.des_md5;
864 pkb3->keys[1].keytype = ENCTYPE_DES_CBC_CRC;
865 pkb3->keys[1].value = &io->g.des_crc;
867 /* initialize the old keys to zero */
868 pkb3->num_old_keys = 0;
869 pkb3->old_keys = NULL;
871 /* if there're no old keys, then we're done */
876 for (i=0; i < old_scb->sub.num_packages; i++) {
877 if (strcmp("Primary:Kerberos", old_scb->sub.packages[i].name) != 0) {
881 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
885 old_scp = &old_scb->sub.packages[i];
888 /* Primary:Kerberos element of supplementalCredentials */
892 blob = strhex_to_data_blob(io->ac, old_scp->data);
897 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
898 ndr_err = ndr_pull_struct_blob(&blob, io->ac, &_old_pkb,
899 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
900 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
901 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
902 ldb_asprintf_errstring(ldb,
903 "setup_primary_kerberos: "
904 "failed to pull old package_PrimaryKerberosBlob: %s",
906 return LDB_ERR_OPERATIONS_ERROR;
909 if (_old_pkb.version != 3) {
910 ldb_asprintf_errstring(ldb,
911 "setup_primary_kerberos: "
912 "package_PrimaryKerberosBlob version[%u] expected[3]",
914 return LDB_ERR_OPERATIONS_ERROR;
917 old_pkb3 = &_old_pkb.ctr.ctr3;
920 /* if we didn't found the old keys we're done */
925 /* fill in the old keys */
926 pkb3->num_old_keys = old_pkb3->num_keys;
927 pkb3->old_keys = old_pkb3->keys;
932 static int setup_primary_kerberos_newer(struct setup_password_fields_io *io,
933 const struct supplementalCredentialsBlob *old_scb,
934 struct package_PrimaryKerberosBlob *pkb)
936 struct ldb_context *ldb;
937 struct package_PrimaryKerberosCtr4 *pkb4 = &pkb->ctr.ctr4;
938 struct supplementalCredentialsPackage *old_scp = NULL;
939 struct package_PrimaryKerberosBlob _old_pkb;
940 struct package_PrimaryKerberosCtr4 *old_pkb4 = NULL;
942 enum ndr_err_code ndr_err;
944 ldb = ldb_module_get_ctx(io->ac->module);
947 * prepare generation of keys
949 * ENCTYPE_AES256_CTS_HMAC_SHA1_96
950 * ENCTYPE_AES128_CTS_HMAC_SHA1_96
951 * ENCTYPE_DES_CBC_MD5
952 * ENCTYPE_DES_CBC_CRC
955 pkb4->salt.string = io->g.salt;
956 pkb4->default_iteration_count = 4096;
959 pkb4->keys = talloc_array(io->ac,
960 struct package_PrimaryKerberosKey4,
966 pkb4->keys[0].iteration_count = 4096;
967 pkb4->keys[0].keytype = ENCTYPE_AES256_CTS_HMAC_SHA1_96;
968 pkb4->keys[0].value = &io->g.aes_256;
969 pkb4->keys[1].iteration_count = 4096;
970 pkb4->keys[1].keytype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
971 pkb4->keys[1].value = &io->g.aes_128;
972 pkb4->keys[2].iteration_count = 4096;
973 pkb4->keys[2].keytype = ENCTYPE_DES_CBC_MD5;
974 pkb4->keys[2].value = &io->g.des_md5;
975 pkb4->keys[3].iteration_count = 4096;
976 pkb4->keys[3].keytype = ENCTYPE_DES_CBC_CRC;
977 pkb4->keys[3].value = &io->g.des_crc;
979 /* initialize the old keys to zero */
980 pkb4->num_old_keys = 0;
981 pkb4->old_keys = NULL;
982 pkb4->num_older_keys = 0;
983 pkb4->older_keys = NULL;
985 /* if there're no old keys, then we're done */
990 for (i=0; i < old_scb->sub.num_packages; i++) {
991 if (strcmp("Primary:Kerberos-Newer-Keys", old_scb->sub.packages[i].name) != 0) {
995 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
999 old_scp = &old_scb->sub.packages[i];
1002 /* Primary:Kerberos-Newer-Keys element of supplementalCredentials */
1006 blob = strhex_to_data_blob(io->ac, old_scp->data);
1008 return ldb_oom(ldb);
1011 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
1012 ndr_err = ndr_pull_struct_blob(&blob, io->ac,
1014 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
1015 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1016 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1017 ldb_asprintf_errstring(ldb,
1018 "setup_primary_kerberos_newer: "
1019 "failed to pull old package_PrimaryKerberosBlob: %s",
1021 return LDB_ERR_OPERATIONS_ERROR;
1024 if (_old_pkb.version != 4) {
1025 ldb_asprintf_errstring(ldb,
1026 "setup_primary_kerberos_newer: "
1027 "package_PrimaryKerberosBlob version[%u] expected[4]",
1029 return LDB_ERR_OPERATIONS_ERROR;
1032 old_pkb4 = &_old_pkb.ctr.ctr4;
1035 /* if we didn't found the old keys we're done */
1040 /* fill in the old keys */
1041 pkb4->num_old_keys = old_pkb4->num_keys;
1042 pkb4->old_keys = old_pkb4->keys;
1043 pkb4->num_older_keys = old_pkb4->num_old_keys;
1044 pkb4->older_keys = old_pkb4->old_keys;
1049 static int setup_primary_wdigest(struct setup_password_fields_io *io,
1050 const struct supplementalCredentialsBlob *old_scb,
1051 struct package_PrimaryWDigestBlob *pdb)
1053 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1054 DATA_BLOB sAMAccountName;
1055 DATA_BLOB sAMAccountName_l;
1056 DATA_BLOB sAMAccountName_u;
1057 const char *user_principal_name = io->u.user_principal_name;
1058 DATA_BLOB userPrincipalName;
1059 DATA_BLOB userPrincipalName_l;
1060 DATA_BLOB userPrincipalName_u;
1061 DATA_BLOB netbios_domain;
1062 DATA_BLOB netbios_domain_l;
1063 DATA_BLOB netbios_domain_u;
1064 DATA_BLOB dns_domain;
1065 DATA_BLOB dns_domain_l;
1066 DATA_BLOB dns_domain_u;
1069 DATA_BLOB backslash;
1078 * http://technet2.microsoft.com/WindowsServer/en/library/717b450c-f4a0-4cc9-86f4-cc0633aae5f91033.mspx?mfr=true
1079 * for what precalculated hashes are supposed to be stored...
1081 * I can't reproduce all values which should contain "Digest" as realm,
1082 * am I doing something wrong or is w2k3 just broken...?
1084 * W2K3 fills in following for a user:
1086 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
1087 * sAMAccountName: NewUser2Sam
1088 * userPrincipalName: NewUser2Princ@sub1.w2k3.vmnet1.vm.base
1090 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1091 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
1092 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
1093 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1094 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
1095 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
1096 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
1097 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1098 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1099 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1100 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1101 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1102 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1103 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1104 * 221c55284451ae9b3aacaa2a3c86f10f => NewUser2Princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1105 * 74e1be668853d4324d38c07e2acfb8ea => (w2k3 has a bug here!) newuser2princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1106 * e1e244ab7f098e3ae1761be7f9229bbb => NEWUSER2PRINC@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
1107 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
1108 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
1109 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
1110 * 31dc704d3640335b2123d4ee28aa1f11 => ??? changes with NewUser2Sam => NewUser1Sam
1111 * 36349f5cecd07320fb3bb0e119230c43 => ??? changes with NewUser2Sam => NewUser1Sam
1112 * 12adf019d037fb535c01fd0608e78d9d => ??? changes with NewUser2Sam => NewUser1Sam
1113 * 6feecf8e724906f3ee1105819c5105a1 => ??? changes with NewUser2Princ => NewUser1Princ
1114 * 6c6911f3de6333422640221b9c51ff1f => ??? changes with NewUser2Princ => NewUser1Princ
1115 * 4b279877e742895f9348ac67a8de2f69 => ??? changes with NewUser2Princ => NewUser1Princ
1116 * db0c6bff069513e3ebb9870d29b57490 => ??? changes with NewUser2Sam => NewUser1Sam
1117 * 45072621e56b1c113a4e04a8ff68cd0e => ??? changes with NewUser2Sam => NewUser1Sam
1118 * 11d1220abc44a9c10cf91ef4a9c1de02 => ??? changes with NewUser2Sam => NewUser1Sam
1120 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
1121 * sAMAccountName: NewUser2Sam
1123 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1124 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
1125 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
1126 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1127 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
1128 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
1129 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
1130 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1131 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1132 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1133 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1134 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1135 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1136 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1137 * 8a140d30b6f0a5912735dc1e3bc993b4 => NewUser2Sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1138 * 86d95b2faae6cae4ec261e7fbaccf093 => (here w2k3 is correct) newuser2sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1139 * dfeff1493110220efcdfc6362e5f5450 => NEWUSER2SAM@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
1140 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
1141 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
1142 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
1143 * 31dc704d3640335b2123d4ee28aa1f11 => ???M1 changes with NewUser2Sam => NewUser1Sam
1144 * 36349f5cecd07320fb3bb0e119230c43 => ???M1.L changes with newuser2sam => newuser1sam
1145 * 12adf019d037fb535c01fd0608e78d9d => ???M1.U changes with NEWUSER2SAM => NEWUSER1SAM
1146 * 569b4533f2d9e580211dd040e5e360a8 => ???M2 changes with NewUser2Princ => NewUser1Princ
1147 * 52528bddf310a587c5d7e6a9ae2cbb20 => ???M2.L changes with newuser2princ => newuser1princ
1148 * 4f629a4f0361289ca4255ab0f658fcd5 => ???M3 changes with NewUser2Princ => NewUser1Princ (doesn't depend on case of userPrincipal )
1149 * db0c6bff069513e3ebb9870d29b57490 => ???M4 changes with NewUser2Sam => NewUser1Sam
1150 * 45072621e56b1c113a4e04a8ff68cd0e => ???M5 changes with NewUser2Sam => NewUser1Sam (doesn't depend on case of sAMAccountName)
1151 * 11d1220abc44a9c10cf91ef4a9c1de02 => ???M4.U changes with NEWUSER2SAM => NEWUSER1SAM
1155 * sAMAccountName, netbios_domain
1158 .user = &sAMAccountName,
1159 .realm = &netbios_domain,
1162 .user = &sAMAccountName_l,
1163 .realm = &netbios_domain_l,
1166 .user = &sAMAccountName_u,
1167 .realm = &netbios_domain_u,
1170 .user = &sAMAccountName,
1171 .realm = &netbios_domain_u,
1174 .user = &sAMAccountName,
1175 .realm = &netbios_domain_l,
1178 .user = &sAMAccountName_u,
1179 .realm = &netbios_domain_l,
1182 .user = &sAMAccountName_l,
1183 .realm = &netbios_domain_u,
1186 * sAMAccountName, dns_domain
1189 .user = &sAMAccountName,
1190 .realm = &dns_domain,
1193 .user = &sAMAccountName_l,
1194 .realm = &dns_domain_l,
1197 .user = &sAMAccountName_u,
1198 .realm = &dns_domain_u,
1201 .user = &sAMAccountName,
1202 .realm = &dns_domain_u,
1205 .user = &sAMAccountName,
1206 .realm = &dns_domain_l,
1209 .user = &sAMAccountName_u,
1210 .realm = &dns_domain_l,
1213 .user = &sAMAccountName_l,
1214 .realm = &dns_domain_u,
1217 * userPrincipalName, no realm
1220 .user = &userPrincipalName,
1224 * NOTE: w2k3 messes this up, if the user has a real userPrincipalName,
1225 * the fallback to the sAMAccountName based userPrincipalName is correct
1227 .user = &userPrincipalName_l,
1230 .user = &userPrincipalName_u,
1233 * nt4dom\sAMAccountName, no realm
1236 .user = &sAMAccountName,
1237 .nt4dom = &netbios_domain
1240 .user = &sAMAccountName_l,
1241 .nt4dom = &netbios_domain_l
1244 .user = &sAMAccountName_u,
1245 .nt4dom = &netbios_domain_u
1249 * the following ones are guessed depending on the technet2 article
1250 * but not reproducable on a w2k3 server
1252 /* sAMAccountName with "Digest" realm */
1254 .user = &sAMAccountName,
1258 .user = &sAMAccountName_l,
1262 .user = &sAMAccountName_u,
1265 /* userPrincipalName with "Digest" realm */
1267 .user = &userPrincipalName,
1271 .user = &userPrincipalName_l,
1275 .user = &userPrincipalName_u,
1278 /* nt4dom\\sAMAccountName with "Digest" realm */
1280 .user = &sAMAccountName,
1281 .nt4dom = &netbios_domain,
1285 .user = &sAMAccountName_l,
1286 .nt4dom = &netbios_domain_l,
1290 .user = &sAMAccountName_u,
1291 .nt4dom = &netbios_domain_u,
1296 /* prepare DATA_BLOB's used in the combinations array */
1297 sAMAccountName = data_blob_string_const(io->u.sAMAccountName);
1298 sAMAccountName_l = data_blob_string_const(strlower_talloc(io->ac, io->u.sAMAccountName));
1299 if (!sAMAccountName_l.data) {
1300 return ldb_oom(ldb);
1302 sAMAccountName_u = data_blob_string_const(strupper_talloc(io->ac, io->u.sAMAccountName));
1303 if (!sAMAccountName_u.data) {
1304 return ldb_oom(ldb);
1307 /* if the user doesn't have a userPrincipalName, create one (with lower case realm) */
1308 if (!user_principal_name) {
1309 user_principal_name = talloc_asprintf(io->ac, "%s@%s",
1310 io->u.sAMAccountName,
1311 io->ac->status->domain_data.dns_domain);
1312 if (!user_principal_name) {
1313 return ldb_oom(ldb);
1316 userPrincipalName = data_blob_string_const(user_principal_name);
1317 userPrincipalName_l = data_blob_string_const(strlower_talloc(io->ac, user_principal_name));
1318 if (!userPrincipalName_l.data) {
1319 return ldb_oom(ldb);
1321 userPrincipalName_u = data_blob_string_const(strupper_talloc(io->ac, user_principal_name));
1322 if (!userPrincipalName_u.data) {
1323 return ldb_oom(ldb);
1326 netbios_domain = data_blob_string_const(io->ac->status->domain_data.netbios_domain);
1327 netbios_domain_l = data_blob_string_const(strlower_talloc(io->ac,
1328 io->ac->status->domain_data.netbios_domain));
1329 if (!netbios_domain_l.data) {
1330 return ldb_oom(ldb);
1332 netbios_domain_u = data_blob_string_const(strupper_talloc(io->ac,
1333 io->ac->status->domain_data.netbios_domain));
1334 if (!netbios_domain_u.data) {
1335 return ldb_oom(ldb);
1338 dns_domain = data_blob_string_const(io->ac->status->domain_data.dns_domain);
1339 dns_domain_l = data_blob_string_const(io->ac->status->domain_data.dns_domain);
1340 dns_domain_u = data_blob_string_const(io->ac->status->domain_data.realm);
1342 digest = data_blob_string_const("Digest");
1344 delim = data_blob_string_const(":");
1345 backslash = data_blob_string_const("\\");
1347 pdb->num_hashes = ARRAY_SIZE(wdigest);
1348 pdb->hashes = talloc_array(io->ac, struct package_PrimaryWDigestHash,
1351 return ldb_oom(ldb);
1354 for (i=0; i < ARRAY_SIZE(wdigest); i++) {
1355 struct MD5Context md5;
1357 if (wdigest[i].nt4dom) {
1358 MD5Update(&md5, wdigest[i].nt4dom->data, wdigest[i].nt4dom->length);
1359 MD5Update(&md5, backslash.data, backslash.length);
1361 MD5Update(&md5, wdigest[i].user->data, wdigest[i].user->length);
1362 MD5Update(&md5, delim.data, delim.length);
1363 if (wdigest[i].realm) {
1364 MD5Update(&md5, wdigest[i].realm->data, wdigest[i].realm->length);
1366 MD5Update(&md5, delim.data, delim.length);
1367 MD5Update(&md5, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length);
1368 MD5Final(pdb->hashes[i].hash, &md5);
1374 static int setup_supplemental_field(struct setup_password_fields_io *io)
1376 struct ldb_context *ldb;
1377 struct supplementalCredentialsBlob scb;
1378 struct supplementalCredentialsBlob _old_scb;
1379 struct supplementalCredentialsBlob *old_scb = NULL;
1380 /* Packages + (Kerberos-Newer-Keys, Kerberos, WDigest and CLEARTEXT) */
1381 uint32_t num_names = 0;
1382 const char *names[1+4];
1383 uint32_t num_packages = 0;
1384 struct supplementalCredentialsPackage packages[1+4];
1386 struct supplementalCredentialsPackage *pp = NULL;
1387 struct package_PackagesBlob pb;
1390 /* Primary:Kerberos-Newer-Keys */
1391 const char **nkn = NULL;
1392 struct supplementalCredentialsPackage *pkn = NULL;
1393 struct package_PrimaryKerberosBlob pknb;
1394 DATA_BLOB pknb_blob;
1396 /* Primary:Kerberos */
1397 const char **nk = NULL;
1398 struct supplementalCredentialsPackage *pk = NULL;
1399 struct package_PrimaryKerberosBlob pkb;
1402 /* Primary:WDigest */
1403 const char **nd = NULL;
1404 struct supplementalCredentialsPackage *pd = NULL;
1405 struct package_PrimaryWDigestBlob pdb;
1408 /* Primary:CLEARTEXT */
1409 const char **nc = NULL;
1410 struct supplementalCredentialsPackage *pc = NULL;
1411 struct package_PrimaryCLEARTEXTBlob pcb;
1415 enum ndr_err_code ndr_err;
1417 bool do_newer_keys = false;
1418 bool do_cleartext = false;
1420 ZERO_STRUCT(zero16);
1423 ldb = ldb_module_get_ctx(io->ac->module);
1425 if (!io->n.cleartext_utf8) {
1427 * when we don't have a cleartext password
1428 * we can't setup a supplementalCredential value
1433 /* if there's an old supplementaCredentials blob then parse it */
1434 if (io->o.supplemental) {
1435 ndr_err = ndr_pull_struct_blob_all(io->o.supplemental, io->ac,
1437 (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
1438 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1439 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1440 ldb_asprintf_errstring(ldb,
1441 "setup_supplemental_field: "
1442 "failed to pull old supplementalCredentialsBlob: %s",
1444 return LDB_ERR_OPERATIONS_ERROR;
1447 if (_old_scb.sub.signature == SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
1448 old_scb = &_old_scb;
1450 ldb_debug(ldb, LDB_DEBUG_ERROR,
1451 "setup_supplemental_field: "
1452 "supplementalCredentialsBlob signature[0x%04X] expected[0x%04X]",
1453 _old_scb.sub.signature, SUPPLEMENTAL_CREDENTIALS_SIGNATURE);
1456 /* Per MS-SAMR 3.1.1.8.11.6 we create AES keys if our domain functionality level is 2008 or higher */
1457 do_newer_keys = (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008);
1459 if (io->ac->status->domain_data.store_cleartext &&
1460 (io->u.userAccountControl & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) {
1461 do_cleartext = true;
1465 * The ordering is this
1467 * Primary:Kerberos-Newer-Keys (optional)
1470 * Primary:CLEARTEXT (optional)
1472 * And the 'Packages' package is insert before the last
1475 if (do_newer_keys) {
1476 /* Primary:Kerberos-Newer-Keys */
1477 nkn = &names[num_names++];
1478 pkn = &packages[num_packages++];
1481 /* Primary:Kerberos */
1482 nk = &names[num_names++];
1483 pk = &packages[num_packages++];
1485 if (!do_cleartext) {
1487 pp = &packages[num_packages++];
1490 /* Primary:WDigest */
1491 nd = &names[num_names++];
1492 pd = &packages[num_packages++];
1496 pp = &packages[num_packages++];
1498 /* Primary:CLEARTEXT */
1499 nc = &names[num_names++];
1500 pc = &packages[num_packages++];
1505 * setup 'Primary:Kerberos-Newer-Keys' element
1507 *nkn = "Kerberos-Newer-Keys";
1509 ret = setup_primary_kerberos_newer(io, old_scb, &pknb);
1510 if (ret != LDB_SUCCESS) {
1514 ndr_err = ndr_push_struct_blob(&pknb_blob, io->ac,
1516 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1517 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1518 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1519 ldb_asprintf_errstring(ldb,
1520 "setup_supplemental_field: "
1521 "failed to push package_PrimaryKerberosNeverBlob: %s",
1523 return LDB_ERR_OPERATIONS_ERROR;
1525 pknb_hexstr = data_blob_hex_string_upper(io->ac, &pknb_blob);
1527 return ldb_oom(ldb);
1529 pkn->name = "Primary:Kerberos-Newer-Keys";
1531 pkn->data = pknb_hexstr;
1535 * setup 'Primary:Kerberos' element
1539 ret = setup_primary_kerberos(io, old_scb, &pkb);
1540 if (ret != LDB_SUCCESS) {
1544 ndr_err = ndr_push_struct_blob(&pkb_blob, io->ac,
1546 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1547 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1548 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1549 ldb_asprintf_errstring(ldb,
1550 "setup_supplemental_field: "
1551 "failed to push package_PrimaryKerberosBlob: %s",
1553 return LDB_ERR_OPERATIONS_ERROR;
1555 pkb_hexstr = data_blob_hex_string_upper(io->ac, &pkb_blob);
1557 return ldb_oom(ldb);
1559 pk->name = "Primary:Kerberos";
1561 pk->data = pkb_hexstr;
1564 * setup 'Primary:WDigest' element
1568 ret = setup_primary_wdigest(io, old_scb, &pdb);
1569 if (ret != LDB_SUCCESS) {
1573 ndr_err = ndr_push_struct_blob(&pdb_blob, io->ac,
1575 (ndr_push_flags_fn_t)ndr_push_package_PrimaryWDigestBlob);
1576 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1577 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1578 ldb_asprintf_errstring(ldb,
1579 "setup_supplemental_field: "
1580 "failed to push package_PrimaryWDigestBlob: %s",
1582 return LDB_ERR_OPERATIONS_ERROR;
1584 pdb_hexstr = data_blob_hex_string_upper(io->ac, &pdb_blob);
1586 return ldb_oom(ldb);
1588 pd->name = "Primary:WDigest";
1590 pd->data = pdb_hexstr;
1593 * setup 'Primary:CLEARTEXT' element
1598 pcb.cleartext = *io->n.cleartext_utf16;
1600 ndr_err = ndr_push_struct_blob(&pcb_blob, io->ac,
1602 (ndr_push_flags_fn_t)ndr_push_package_PrimaryCLEARTEXTBlob);
1603 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1604 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1605 ldb_asprintf_errstring(ldb,
1606 "setup_supplemental_field: "
1607 "failed to push package_PrimaryCLEARTEXTBlob: %s",
1609 return LDB_ERR_OPERATIONS_ERROR;
1611 pcb_hexstr = data_blob_hex_string_upper(io->ac, &pcb_blob);
1613 return ldb_oom(ldb);
1615 pc->name = "Primary:CLEARTEXT";
1617 pc->data = pcb_hexstr;
1621 * setup 'Packages' element
1624 ndr_err = ndr_push_struct_blob(&pb_blob, io->ac,
1626 (ndr_push_flags_fn_t)ndr_push_package_PackagesBlob);
1627 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1628 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1629 ldb_asprintf_errstring(ldb,
1630 "setup_supplemental_field: "
1631 "failed to push package_PackagesBlob: %s",
1633 return LDB_ERR_OPERATIONS_ERROR;
1635 pb_hexstr = data_blob_hex_string_upper(io->ac, &pb_blob);
1637 return ldb_oom(ldb);
1639 pp->name = "Packages";
1641 pp->data = pb_hexstr;
1644 * setup 'supplementalCredentials' value
1647 scb.sub.num_packages = num_packages;
1648 scb.sub.packages = packages;
1650 ndr_err = ndr_push_struct_blob(&io->g.supplemental, io->ac,
1652 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
1653 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1654 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1655 ldb_asprintf_errstring(ldb,
1656 "setup_supplemental_field: "
1657 "failed to push supplementalCredentialsBlob: %s",
1659 return LDB_ERR_OPERATIONS_ERROR;
1665 static int setup_last_set_field(struct setup_password_fields_io *io)
1667 const struct ldb_message *msg = NULL;
1669 switch (io->ac->req->operation) {
1671 msg = io->ac->req->op.add.message;
1674 msg = io->ac->req->op.mod.message;
1678 if (io->ac->pwd_last_set_bypass) {
1679 struct ldb_message_element *el;
1682 return LDB_ERR_CONSTRAINT_VIOLATION;
1685 el = ldb_msg_find_element(msg, "pwdLastSet");
1687 return LDB_ERR_CONSTRAINT_VIOLATION;
1690 io->g.last_set = samdb_result_nttime(msg, "pwdLastSet", 0);
1695 unix_to_nt_time(&io->g.last_set, time(NULL));
1700 static int setup_given_passwords(struct setup_password_fields_io *io,
1701 struct setup_password_fields_given *g)
1703 struct ldb_context *ldb;
1706 ldb = ldb_module_get_ctx(io->ac->module);
1708 if (g->cleartext_utf8) {
1709 struct ldb_val *cleartext_utf16_blob;
1711 cleartext_utf16_blob = talloc(io->ac, struct ldb_val);
1712 if (!cleartext_utf16_blob) {
1713 return ldb_oom(ldb);
1715 if (!convert_string_talloc(io->ac,
1717 g->cleartext_utf8->data,
1718 g->cleartext_utf8->length,
1719 (void *)&cleartext_utf16_blob->data,
1720 &cleartext_utf16_blob->length)) {
1721 if (g->cleartext_utf8->length != 0) {
1722 talloc_free(cleartext_utf16_blob);
1723 ldb_asprintf_errstring(ldb,
1724 "setup_password_fields: "
1725 "failed to generate UTF16 password from cleartext UTF8 one for user '%s'!",
1726 io->u.sAMAccountName);
1727 return LDB_ERR_CONSTRAINT_VIOLATION;
1729 /* passwords with length "0" are valid! */
1730 cleartext_utf16_blob->data = NULL;
1731 cleartext_utf16_blob->length = 0;
1734 g->cleartext_utf16 = cleartext_utf16_blob;
1735 } else if (g->cleartext_utf16) {
1736 struct ldb_val *cleartext_utf8_blob;
1738 cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
1739 if (!cleartext_utf8_blob) {
1740 return ldb_oom(ldb);
1742 if (!convert_string_talloc(io->ac,
1743 CH_UTF16MUNGED, CH_UTF8,
1744 g->cleartext_utf16->data,
1745 g->cleartext_utf16->length,
1746 (void *)&cleartext_utf8_blob->data,
1747 &cleartext_utf8_blob->length)) {
1748 if (g->cleartext_utf16->length != 0) {
1749 /* We must bail out here, the input wasn't even
1750 * a multiple of 2 bytes */
1751 talloc_free(cleartext_utf8_blob);
1752 ldb_asprintf_errstring(ldb,
1753 "setup_password_fields: "
1754 "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)!",
1755 io->u.sAMAccountName);
1756 return LDB_ERR_CONSTRAINT_VIOLATION;
1758 /* passwords with length "0" are valid! */
1759 cleartext_utf8_blob->data = NULL;
1760 cleartext_utf8_blob->length = 0;
1763 g->cleartext_utf8 = cleartext_utf8_blob;
1766 if (g->cleartext_utf16) {
1767 struct samr_Password *nt_hash;
1769 nt_hash = talloc(io->ac, struct samr_Password);
1771 return ldb_oom(ldb);
1773 g->nt_hash = nt_hash;
1775 /* compute the new nt hash */
1776 mdfour(nt_hash->hash,
1777 g->cleartext_utf16->data,
1778 g->cleartext_utf16->length);
1781 if (g->cleartext_utf8) {
1782 struct samr_Password *lm_hash;
1784 lm_hash = talloc(io->ac, struct samr_Password);
1786 return ldb_oom(ldb);
1789 /* compute the new lm hash */
1790 ok = E_deshash((char *)g->cleartext_utf8->data, lm_hash->hash);
1792 g->lm_hash = lm_hash;
1794 talloc_free(lm_hash);
1801 static int setup_password_fields(struct setup_password_fields_io *io)
1803 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1804 struct loadparm_context *lp_ctx =
1805 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
1806 struct loadparm_context);
1809 /* transform the old password (for password changes) */
1810 ret = setup_given_passwords(io, &io->og);
1811 if (ret != LDB_SUCCESS) {
1815 /* transform the new password */
1816 ret = setup_given_passwords(io, &io->n);
1817 if (ret != LDB_SUCCESS) {
1821 if (io->n.cleartext_utf8) {
1822 ret = setup_kerberos_keys(io);
1823 if (ret != LDB_SUCCESS) {
1828 ret = setup_nt_fields(io);
1829 if (ret != LDB_SUCCESS) {
1833 if (lpcfg_lanman_auth(lp_ctx)) {
1834 ret = setup_lm_fields(io);
1835 if (ret != LDB_SUCCESS) {
1839 io->g.lm_hash = NULL;
1840 io->g.lm_history_len = 0;
1843 ret = setup_supplemental_field(io);
1844 if (ret != LDB_SUCCESS) {
1848 ret = setup_last_set_field(io);
1849 if (ret != LDB_SUCCESS) {
1856 static int check_password_restrictions(struct setup_password_fields_io *io)
1858 struct ldb_context *ldb;
1860 enum samr_ValidationStatus stat;
1862 ldb = ldb_module_get_ctx(io->ac->module);
1864 /* First check the old password is correct, for password changes */
1865 if (!io->ac->pwd_reset) {
1866 bool nt_hash_checked = false;
1868 /* we need the old nt or lm hash given by the client */
1869 if (!io->og.nt_hash && !io->og.lm_hash) {
1870 ldb_asprintf_errstring(ldb,
1871 "check_password_restrictions: "
1872 "You need to provide the old password in order "
1874 return LDB_ERR_UNWILLING_TO_PERFORM;
1877 /* The password modify through the NT hash is encouraged and
1878 has no problems at all */
1879 if (io->og.nt_hash) {
1880 if (!io->o.nt_hash) {
1881 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1882 ldb_asprintf_errstring(ldb,
1883 "%08X: %s - check_password_restrictions: "
1884 "There's no old nt_hash, which is needed "
1885 "in order to change your password!",
1886 W_ERROR_V(WERR_INVALID_PASSWORD),
1891 if (memcmp(io->og.nt_hash->hash, io->o.nt_hash->hash, 16) != 0) {
1892 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1893 ldb_asprintf_errstring(ldb,
1894 "%08X: %s - check_password_restrictions: "
1895 "The old password specified doesn't match!",
1896 W_ERROR_V(WERR_INVALID_PASSWORD),
1901 nt_hash_checked = true;
1904 /* But it is also possible to change a password by the LM hash
1905 * alone for compatibility reasons. This check is optional if
1906 * the NT hash was already checked - otherwise it's mandatory.
1907 * (as the SAMR operations request it). */
1908 if (io->og.lm_hash) {
1909 if (!io->o.lm_hash && !nt_hash_checked) {
1910 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1911 ldb_asprintf_errstring(ldb,
1912 "%08X: %s - check_password_restrictions: "
1913 "There's no old lm_hash, which is needed "
1914 "in order to change your password!",
1915 W_ERROR_V(WERR_INVALID_PASSWORD),
1920 if (io->o.lm_hash &&
1921 memcmp(io->og.lm_hash->hash, io->o.lm_hash->hash, 16) != 0) {
1922 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1923 ldb_asprintf_errstring(ldb,
1924 "%08X: %s - check_password_restrictions: "
1925 "The old password specified doesn't match!",
1926 W_ERROR_V(WERR_INVALID_PASSWORD),
1933 if (io->u.restrictions == 0) {
1934 /* FIXME: Is this right? */
1939 * Fundamental password checks done by the call
1940 * "samdb_check_password".
1941 * It is also in use by "dcesrv_samr_ValidatePassword".
1943 if (io->n.cleartext_utf8 != NULL) {
1944 stat = samdb_check_password(io->n.cleartext_utf8,
1945 io->ac->status->domain_data.pwdProperties,
1946 io->ac->status->domain_data.minPwdLength);
1948 case SAMR_VALIDATION_STATUS_SUCCESS:
1949 /* perfect -> proceed! */
1952 case SAMR_VALIDATION_STATUS_PWD_TOO_SHORT:
1953 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1954 ldb_asprintf_errstring(ldb,
1955 "%08X: %s - check_password_restrictions: "
1956 "the password is too short. It should be equal or longer than %u characters!",
1957 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
1959 io->ac->status->domain_data.minPwdLength);
1960 io->ac->status->reject_reason = SAM_PWD_CHANGE_PASSWORD_TOO_SHORT;
1963 case SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH:
1964 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1965 ldb_asprintf_errstring(ldb,
1966 "%08X: %s - check_password_restrictions: "
1967 "the password does not meet the complexity criteria!",
1968 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
1970 io->ac->status->reject_reason = SAM_PWD_CHANGE_NOT_COMPLEX;
1974 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1975 ldb_asprintf_errstring(ldb,
1976 "%08X: %s - check_password_restrictions: "
1977 "the password doesn't fit by a certain reason!",
1978 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
1984 if (io->ac->pwd_reset) {
1988 if (io->n.nt_hash) {
1991 /* checks the NT hash password history */
1992 for (i = 0; i < io->o.nt_history_len; i++) {
1993 ret = memcmp(io->n.nt_hash, io->o.nt_history[i].hash, 16);
1995 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1996 ldb_asprintf_errstring(ldb,
1997 "%08X: %s - check_password_restrictions: "
1998 "the password was already used (in history)!",
1999 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2001 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
2007 if (io->n.lm_hash) {
2010 /* checks the LM hash password history */
2011 for (i = 0; i < io->o.lm_history_len; i++) {
2012 ret = memcmp(io->n.nt_hash, io->o.lm_history[i].hash, 16);
2014 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2015 ldb_asprintf_errstring(ldb,
2016 "%08X: %s - check_password_restrictions: "
2017 "the password was already used (in history)!",
2018 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2020 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
2026 /* are all password changes disallowed? */
2027 if (io->ac->status->domain_data.pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
2028 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2029 ldb_asprintf_errstring(ldb,
2030 "%08X: %s - check_password_restrictions: "
2031 "password changes disabled!",
2032 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2037 /* can this user change the password? */
2038 if (io->u.userAccountControl & UF_PASSWD_CANT_CHANGE) {
2039 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2040 ldb_asprintf_errstring(ldb,
2041 "%08X: %s - check_password_restrictions: "
2042 "password can't be changed on this account!",
2043 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2048 /* Password minimum age: yes, this is a minus. The ages are in negative 100nsec units! */
2049 if (io->u.pwdLastSet - io->ac->status->domain_data.minPwdAge > io->g.last_set) {
2050 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2051 ldb_asprintf_errstring(ldb,
2052 "%08X: %s - check_password_restrictions: "
2053 "password is too young to change!",
2054 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2063 * This is intended for use by the "password_hash" module since there
2064 * password changes can be specified through one message element with the
2065 * new password (to set) and another one with the old password (to unset).
2067 * The first which sets a password (new value) can have flags
2068 * (LDB_FLAG_MOD_ADD, LDB_FLAG_MOD_REPLACE) but also none (on "add" operations
2069 * for entries). The latter (old value) has always specified
2070 * LDB_FLAG_MOD_DELETE.
2072 * Returns LDB_ERR_CONSTRAINT_VIOLATION and LDB_ERR_UNWILLING_TO_PERFORM if
2073 * matching message elements are malformed in respect to the set/change rules.
2074 * Otherwise it returns LDB_SUCCESS.
2076 static int msg_find_old_and_new_pwd_val(const struct ldb_message *msg,
2078 enum ldb_request_type operation,
2079 const struct ldb_val **new_val,
2080 const struct ldb_val **old_val)
2091 for (i = 0; i < msg->num_elements; i++) {
2092 if (ldb_attr_cmp(msg->elements[i].name, name) != 0) {
2096 if ((operation == LDB_MODIFY) &&
2097 (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_DELETE)) {
2098 /* 0 values are allowed */
2099 if (msg->elements[i].num_values == 1) {
2100 *old_val = &msg->elements[i].values[0];
2101 } else if (msg->elements[i].num_values > 1) {
2102 return LDB_ERR_CONSTRAINT_VIOLATION;
2104 } else if ((operation == LDB_MODIFY) &&
2105 (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_REPLACE)) {
2106 if (msg->elements[i].num_values > 0) {
2107 *new_val = &msg->elements[i].values[msg->elements[i].num_values - 1];
2109 return LDB_ERR_UNWILLING_TO_PERFORM;
2112 /* Add operations and LDB_FLAG_MOD_ADD */
2113 if (msg->elements[i].num_values > 0) {
2114 *new_val = &msg->elements[i].values[msg->elements[i].num_values - 1];
2116 return LDB_ERR_CONSTRAINT_VIOLATION;
2124 static int setup_io(struct ph_context *ac,
2125 const struct ldb_message *orig_msg,
2126 const struct ldb_message *searched_msg,
2127 struct setup_password_fields_io *io)
2129 const struct ldb_val *quoted_utf16, *old_quoted_utf16, *lm_hash, *old_lm_hash;
2130 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2131 struct loadparm_context *lp_ctx =
2132 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2133 struct loadparm_context);
2138 /* Some operations below require kerberos contexts */
2140 if (smb_krb5_init_context(ac,
2141 ldb_get_event_context(ldb),
2142 (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"),
2143 &io->smb_krb5_context) != 0) {
2144 return ldb_operr(ldb);
2149 io->u.userAccountControl = ldb_msg_find_attr_as_uint(searched_msg,
2150 "userAccountControl", 0);
2151 io->u.pwdLastSet = samdb_result_nttime(searched_msg, "pwdLastSet", 0);
2152 io->u.sAMAccountName = ldb_msg_find_attr_as_string(searched_msg,
2153 "sAMAccountName", NULL);
2154 io->u.user_principal_name = ldb_msg_find_attr_as_string(searched_msg,
2155 "userPrincipalName", NULL);
2156 io->u.is_computer = ldb_msg_check_string_attribute(searched_msg, "objectClass", "computer");
2158 if (io->u.sAMAccountName == NULL) {
2159 ldb_asprintf_errstring(ldb,
2160 "setup_io: sAMAccountName attribute is missing on %s for attempted password set/change",
2161 ldb_dn_get_linearized(searched_msg->dn));
2163 return LDB_ERR_CONSTRAINT_VIOLATION;
2166 /* Only non-trust accounts have restrictions (possibly this test is the
2167 * wrong way around, but we like to be restrictive if possible */
2168 io->u.restrictions = !(io->u.userAccountControl
2169 & (UF_INTERDOMAIN_TRUST_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT
2170 | UF_SERVER_TRUST_ACCOUNT));
2172 if ((io->u.userAccountControl & UF_PASSWD_NOTREQD) != 0) {
2173 /* see [MS-ADTS] 2.2.15 */
2174 io->u.restrictions = 0;
2177 if (ac->userPassword) {
2178 ret = msg_find_old_and_new_pwd_val(orig_msg, "userPassword",
2180 &io->n.cleartext_utf8,
2181 &io->og.cleartext_utf8);
2182 if (ret != LDB_SUCCESS) {
2183 ldb_asprintf_errstring(ldb,
2185 "it's only allowed to set the old password once!");
2190 ret = msg_find_old_and_new_pwd_val(orig_msg, "clearTextPassword",
2192 &io->n.cleartext_utf16,
2193 &io->og.cleartext_utf16);
2194 if (ret != LDB_SUCCESS) {
2195 ldb_asprintf_errstring(ldb,
2197 "it's only allowed to set the old password once!");
2201 /* this rather strange looking piece of code is there to
2202 handle a ldap client setting a password remotely using the
2203 unicodePwd ldap field. The syntax is that the password is
2204 in UTF-16LE, with a " at either end. Unfortunately the
2205 unicodePwd field is also used to store the nt hashes
2206 internally in Samba, and is used in the nt hash format on
2207 the wire in DRS replication, so we have a single name for
2208 two distinct values. The code below leaves us with a small
2209 chance (less than 1 in 2^32) of a mixup, if someone manages
2210 to create a MD4 hash which starts and ends in 0x22 0x00, as
2211 that would then be treated as a UTF16 password rather than
2214 ret = msg_find_old_and_new_pwd_val(orig_msg, "unicodePwd",
2218 if (ret != LDB_SUCCESS) {
2219 ldb_asprintf_errstring(ldb,
2221 "it's only allowed to set the old password once!");
2225 /* Checks and converts the actual "unicodePwd" attribute */
2226 if (!ac->hash_values &&
2228 quoted_utf16->length >= 4 &&
2229 quoted_utf16->data[0] == '"' &&
2230 quoted_utf16->data[1] == 0 &&
2231 quoted_utf16->data[quoted_utf16->length-2] == '"' &&
2232 quoted_utf16->data[quoted_utf16->length-1] == 0) {
2233 struct ldb_val *quoted_utf16_2;
2235 if (io->n.cleartext_utf16) {
2236 /* refuse the change if someone wants to change with
2237 with both UTF16 possibilities at the same time... */
2238 ldb_asprintf_errstring(ldb,
2240 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
2241 return LDB_ERR_UNWILLING_TO_PERFORM;
2245 * adapt the quoted UTF16 string to be a real
2248 quoted_utf16_2 = talloc(io->ac, struct ldb_val);
2249 if (quoted_utf16_2 == NULL) {
2250 return ldb_oom(ldb);
2253 quoted_utf16_2->data = quoted_utf16->data + 2;
2254 quoted_utf16_2->length = quoted_utf16->length-4;
2255 io->n.cleartext_utf16 = quoted_utf16_2;
2256 io->n.nt_hash = NULL;
2258 } else if (quoted_utf16) {
2259 /* We have only the hash available -> so no plaintext here */
2260 if (!ac->hash_values) {
2261 /* refuse the change if someone wants to change
2262 the hash without control specified... */
2263 ldb_asprintf_errstring(ldb,
2265 "it's not allowed to set the NT hash password directly'");
2266 /* this looks odd but this is what Windows does:
2267 returns "UNWILLING_TO_PERFORM" on wrong
2268 password sets and "CONSTRAINT_VIOLATION" on
2269 wrong password changes. */
2270 if (old_quoted_utf16 == NULL) {
2271 return LDB_ERR_UNWILLING_TO_PERFORM;
2274 return LDB_ERR_CONSTRAINT_VIOLATION;
2277 io->n.nt_hash = talloc(io->ac, struct samr_Password);
2278 memcpy(io->n.nt_hash->hash, quoted_utf16->data,
2279 MIN(quoted_utf16->length, sizeof(io->n.nt_hash->hash)));
2282 /* Checks and converts the previous "unicodePwd" attribute */
2283 if (!ac->hash_values &&
2285 old_quoted_utf16->length >= 4 &&
2286 old_quoted_utf16->data[0] == '"' &&
2287 old_quoted_utf16->data[1] == 0 &&
2288 old_quoted_utf16->data[old_quoted_utf16->length-2] == '"' &&
2289 old_quoted_utf16->data[old_quoted_utf16->length-1] == 0) {
2290 struct ldb_val *old_quoted_utf16_2;
2292 if (io->og.cleartext_utf16) {
2293 /* refuse the change if someone wants to change with
2294 both UTF16 possibilities at the same time... */
2295 ldb_asprintf_errstring(ldb,
2297 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
2298 return LDB_ERR_UNWILLING_TO_PERFORM;
2302 * adapt the quoted UTF16 string to be a real
2305 old_quoted_utf16_2 = talloc(io->ac, struct ldb_val);
2306 if (old_quoted_utf16_2 == NULL) {
2307 return ldb_oom(ldb);
2310 old_quoted_utf16_2->data = old_quoted_utf16->data + 2;
2311 old_quoted_utf16_2->length = old_quoted_utf16->length-4;
2313 io->og.cleartext_utf16 = old_quoted_utf16_2;
2314 io->og.nt_hash = NULL;
2315 } else if (old_quoted_utf16) {
2316 /* We have only the hash available -> so no plaintext here */
2317 if (!ac->hash_values) {
2318 /* refuse the change if someone wants to change
2319 the hash without control specified... */
2320 ldb_asprintf_errstring(ldb,
2322 "it's not allowed to set the NT hash password directly'");
2323 return LDB_ERR_UNWILLING_TO_PERFORM;
2326 io->og.nt_hash = talloc(io->ac, struct samr_Password);
2327 memcpy(io->og.nt_hash->hash, old_quoted_utf16->data,
2328 MIN(old_quoted_utf16->length, sizeof(io->og.nt_hash->hash)));
2331 /* Handles the "dBCSPwd" attribute (LM hash) */
2332 io->n.lm_hash = NULL; io->og.lm_hash = NULL;
2333 ret = msg_find_old_and_new_pwd_val(orig_msg, "dBCSPwd",
2335 &lm_hash, &old_lm_hash);
2336 if (ret != LDB_SUCCESS) {
2337 ldb_asprintf_errstring(ldb,
2339 "it's only allowed to set the old password once!");
2343 if (((lm_hash != NULL) || (old_lm_hash != NULL)) && (!ac->hash_values)) {
2344 /* refuse the change if someone wants to change the hash
2345 without control specified... */
2346 ldb_asprintf_errstring(ldb,
2348 "it's not allowed to set the LM hash password directly'");
2349 return LDB_ERR_UNWILLING_TO_PERFORM;
2352 if (lpcfg_lanman_auth(lp_ctx) && (lm_hash != NULL)) {
2353 io->n.lm_hash = talloc(io->ac, struct samr_Password);
2354 memcpy(io->n.lm_hash->hash, lm_hash->data, MIN(lm_hash->length,
2355 sizeof(io->n.lm_hash->hash)));
2357 if (lpcfg_lanman_auth(lp_ctx) && (old_lm_hash != NULL)) {
2358 io->og.lm_hash = talloc(io->ac, struct samr_Password);
2359 memcpy(io->og.lm_hash->hash, old_lm_hash->data, MIN(old_lm_hash->length,
2360 sizeof(io->og.lm_hash->hash)));
2364 * Handles the password change control if it's specified. It has the
2365 * precedance and overrides already specified old password values of
2366 * change requests (but that shouldn't happen since the control is
2367 * fully internal and only used in conjunction with replace requests!).
2369 if (ac->change != NULL) {
2370 io->og.nt_hash = NULL;
2371 if (ac->change->old_nt_pwd_hash != NULL) {
2372 io->og.nt_hash = talloc_memdup(io->ac,
2373 ac->change->old_nt_pwd_hash,
2374 sizeof(struct samr_Password));
2376 io->og.lm_hash = NULL;
2377 if (lpcfg_lanman_auth(lp_ctx) && (ac->change->old_lm_pwd_hash != NULL)) {
2378 io->og.lm_hash = talloc_memdup(io->ac,
2379 ac->change->old_lm_pwd_hash,
2380 sizeof(struct samr_Password));
2384 /* refuse the change if someone wants to change the clear-
2385 text and supply his own hashes at the same time... */
2386 if ((io->n.cleartext_utf8 || io->n.cleartext_utf16)
2387 && (io->n.nt_hash || io->n.lm_hash)) {
2388 ldb_asprintf_errstring(ldb,
2390 "it's only allowed to set the password in form of cleartext attributes or as hashes");
2391 return LDB_ERR_UNWILLING_TO_PERFORM;
2394 /* refuse the change if someone wants to change the password
2395 using both plaintext methods (UTF8 and UTF16) at the same time... */
2396 if (io->n.cleartext_utf8 && io->n.cleartext_utf16) {
2397 ldb_asprintf_errstring(ldb,
2399 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
2400 return LDB_ERR_UNWILLING_TO_PERFORM;
2403 /* refuse the change if someone tries to set/change the password by
2404 * the lanman hash alone and we've deactivated that mechanism. This
2405 * would end in an account without any password! */
2406 if ((!io->n.cleartext_utf8) && (!io->n.cleartext_utf16)
2407 && (!io->n.nt_hash) && (!io->n.lm_hash)) {
2408 ldb_asprintf_errstring(ldb,
2410 "It' not possible to delete the password (changes using the LAN Manager hash alone could be deactivated)!");
2411 /* on "userPassword" and "clearTextPassword" we've to return
2412 * something different, since these are virtual attributes */
2413 if ((ldb_msg_find_element(orig_msg, "userPassword") != NULL) ||
2414 (ldb_msg_find_element(orig_msg, "clearTextPassword") != NULL)) {
2415 return LDB_ERR_CONSTRAINT_VIOLATION;
2417 return LDB_ERR_UNWILLING_TO_PERFORM;
2420 /* refuse the change if someone wants to compare against a plaintext
2421 or hash at the same time for a "password modify" operation... */
2422 if ((io->og.cleartext_utf8 || io->og.cleartext_utf16)
2423 && (io->og.nt_hash || io->og.lm_hash)) {
2424 ldb_asprintf_errstring(ldb,
2426 "it's only allowed to provide the old password in form of cleartext attributes or as hashes");
2427 return LDB_ERR_UNWILLING_TO_PERFORM;
2430 /* refuse the change if someone wants to compare against both
2431 * plaintexts at the same time for a "password modify" operation... */
2432 if (io->og.cleartext_utf8 && io->og.cleartext_utf16) {
2433 ldb_asprintf_errstring(ldb,
2435 "it's only allowed to provide the old cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
2436 return LDB_ERR_UNWILLING_TO_PERFORM;
2439 /* Decides if we have a password modify or password reset operation */
2440 if (ac->req->operation == LDB_ADD) {
2441 /* On "add" we have only "password reset" */
2442 ac->pwd_reset = true;
2443 } else if (ac->req->operation == LDB_MODIFY) {
2444 if (io->og.cleartext_utf8 || io->og.cleartext_utf16
2445 || io->og.nt_hash || io->og.lm_hash) {
2446 /* If we have an old password specified then for sure it
2447 * is a user "password change" */
2448 ac->pwd_reset = false;
2450 /* Otherwise we have also here a "password reset" */
2451 ac->pwd_reset = true;
2454 /* this shouldn't happen */
2455 return ldb_operr(ldb);
2461 static struct ph_context *ph_init_context(struct ldb_module *module,
2462 struct ldb_request *req,
2465 struct ldb_context *ldb;
2466 struct ph_context *ac;
2468 ldb = ldb_module_get_ctx(module);
2470 ac = talloc_zero(req, struct ph_context);
2472 ldb_set_errstring(ldb, "Out of Memory");
2476 ac->module = module;
2478 ac->userPassword = userPassword;
2483 static void ph_apply_controls(struct ph_context *ac)
2485 struct ldb_control *ctrl;
2487 ac->change_status = false;
2488 ctrl = ldb_request_get_control(ac->req,
2489 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID);
2491 ac->change_status = true;
2493 /* Mark the "change status" control as uncritical (done) */
2494 ctrl->critical = false;
2497 ac->hash_values = false;
2498 ctrl = ldb_request_get_control(ac->req,
2499 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID);
2501 ac->hash_values = true;
2503 /* Mark the "hash values" control as uncritical (done) */
2504 ctrl->critical = false;
2507 ctrl = ldb_request_get_control(ac->req,
2508 DSDB_CONTROL_PASSWORD_CHANGE_OID);
2510 ac->change = (struct dsdb_control_password_change *) ctrl->data;
2512 /* Mark the "change" control as uncritical (done) */
2513 ctrl->critical = false;
2516 ac->pwd_last_set_bypass = false;
2517 ctrl = ldb_request_get_control(ac->req,
2518 DSDB_CONTROL_PASSWORD_BYPASS_LAST_SET_OID);
2520 ac->pwd_last_set_bypass = true;
2522 /* Mark the "bypass pwdLastSet" control as uncritical (done) */
2523 ctrl->critical = false;
2527 static int ph_op_callback(struct ldb_request *req, struct ldb_reply *ares)
2529 struct ph_context *ac;
2531 ac = talloc_get_type(req->context, struct ph_context);
2534 return ldb_module_done(ac->req, NULL, NULL,
2535 LDB_ERR_OPERATIONS_ERROR);
2538 if (ares->type == LDB_REPLY_REFERRAL) {
2539 return ldb_module_send_referral(ac->req, ares->referral);
2542 if ((ares->error != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
2543 /* On success and trivial errors a status control is being
2544 * added (used for example by the "samdb_set_password" call) */
2545 ldb_reply_add_control(ares,
2546 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2551 if (ares->error != LDB_SUCCESS) {
2552 return ldb_module_done(ac->req, ares->controls,
2553 ares->response, ares->error);
2556 if (ares->type != LDB_REPLY_DONE) {
2558 return ldb_module_done(ac->req, NULL, NULL,
2559 LDB_ERR_OPERATIONS_ERROR);
2562 return ldb_module_done(ac->req, ares->controls,
2563 ares->response, ares->error);
2566 static int password_hash_add_do_add(struct ph_context *ac);
2567 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares);
2568 static int password_hash_mod_search_self(struct ph_context *ac);
2569 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares);
2570 static int password_hash_mod_do_mod(struct ph_context *ac);
2572 static int get_domain_data_callback(struct ldb_request *req,
2573 struct ldb_reply *ares)
2575 struct ldb_context *ldb;
2576 struct ph_context *ac;
2577 struct loadparm_context *lp_ctx;
2580 ac = talloc_get_type(req->context, struct ph_context);
2581 ldb = ldb_module_get_ctx(ac->module);
2584 ret = LDB_ERR_OPERATIONS_ERROR;
2587 if (ares->error != LDB_SUCCESS) {
2588 return ldb_module_done(ac->req, ares->controls,
2589 ares->response, ares->error);
2592 switch (ares->type) {
2593 case LDB_REPLY_ENTRY:
2594 if (ac->status != NULL) {
2597 ldb_set_errstring(ldb, "Too many results");
2598 ret = LDB_ERR_OPERATIONS_ERROR;
2602 /* Setup the "status" structure (used as control later) */
2603 ac->status = talloc_zero(ac->req,
2604 struct dsdb_control_password_change_status);
2605 if (ac->status == NULL) {
2609 ret = LDB_ERR_OPERATIONS_ERROR;
2613 /* Setup the "domain data" structure */
2614 ac->status->domain_data.pwdProperties =
2615 ldb_msg_find_attr_as_uint(ares->message, "pwdProperties", -1);
2616 ac->status->domain_data.pwdHistoryLength =
2617 ldb_msg_find_attr_as_uint(ares->message, "pwdHistoryLength", -1);
2618 ac->status->domain_data.maxPwdAge =
2619 ldb_msg_find_attr_as_int64(ares->message, "maxPwdAge", -1);
2620 ac->status->domain_data.minPwdAge =
2621 ldb_msg_find_attr_as_int64(ares->message, "minPwdAge", -1);
2622 ac->status->domain_data.minPwdLength =
2623 ldb_msg_find_attr_as_uint(ares->message, "minPwdLength", -1);
2624 ac->status->domain_data.store_cleartext =
2625 ac->status->domain_data.pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
2629 /* For a domain DN, this puts things in dotted notation */
2630 /* For builtin domains, this will give details for the host,
2631 * but that doesn't really matter, as it's just used for salt
2632 * and kerberos principals, which don't exist here */
2634 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2635 struct loadparm_context);
2637 ac->status->domain_data.dns_domain = lpcfg_dnsdomain(lp_ctx);
2638 ac->status->domain_data.realm = lpcfg_realm(lp_ctx);
2639 ac->status->domain_data.netbios_domain = lpcfg_sam_name(lp_ctx);
2641 ac->status->reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2646 case LDB_REPLY_REFERRAL:
2652 case LDB_REPLY_DONE:
2654 /* call the next step */
2655 switch (ac->req->operation) {
2657 ret = password_hash_add_do_add(ac);
2661 ret = password_hash_mod_do_mod(ac);
2665 ret = LDB_ERR_OPERATIONS_ERROR;
2672 if (ret != LDB_SUCCESS) {
2673 struct ldb_reply *new_ares;
2675 new_ares = talloc_zero(ac->req, struct ldb_reply);
2676 if (new_ares == NULL) {
2678 return ldb_module_done(ac->req, NULL, NULL,
2679 LDB_ERR_OPERATIONS_ERROR);
2682 new_ares->error = ret;
2683 if ((ret != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
2684 /* On success and trivial errors a status control is being
2685 * added (used for example by the "samdb_set_password" call) */
2686 ldb_reply_add_control(new_ares,
2687 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2692 return ldb_module_done(ac->req, new_ares->controls,
2693 new_ares->response, new_ares->error);
2699 static int build_domain_data_request(struct ph_context *ac)
2701 /* attrs[] is returned from this function in
2702 ac->dom_req->op.search.attrs, so it must be static, as
2703 otherwise the compiler can put it on the stack */
2704 struct ldb_context *ldb;
2705 static const char * const attrs[] = { "pwdProperties",
2713 ldb = ldb_module_get_ctx(ac->module);
2715 ret = ldb_build_search_req(&ac->dom_req, ldb, ac,
2716 ldb_get_default_basedn(ldb),
2720 ac, get_domain_data_callback,
2722 LDB_REQ_SET_LOCATION(ac->dom_req);
2726 static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
2728 struct ldb_context *ldb;
2729 struct ph_context *ac;
2730 struct ldb_message_element *userPasswordAttr, *clearTextPasswordAttr,
2733 struct ldb_control *bypass = NULL;
2734 bool userPassword = dsdb_user_password_support(module, req, req);
2736 ldb = ldb_module_get_ctx(module);
2738 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add\n");
2740 if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
2741 return ldb_next_request(module, req);
2744 /* If the caller is manipulating the local passwords directly, let them pass */
2745 if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
2746 req->op.add.message->dn) == 0) {
2747 return ldb_next_request(module, req);
2750 bypass = ldb_request_get_control(req,
2751 DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID);
2752 if (bypass != NULL) {
2753 /* Mark the "bypass" control as uncritical (done) */
2754 bypass->critical = false;
2755 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add (bypassing)\n");
2756 return password_hash_bypass(module, req);
2759 /* nobody must touch password histories and 'supplementalCredentials' */
2760 if (ldb_msg_find_element(req->op.add.message, "ntPwdHistory")) {
2761 return LDB_ERR_UNWILLING_TO_PERFORM;
2763 if (ldb_msg_find_element(req->op.add.message, "lmPwdHistory")) {
2764 return LDB_ERR_UNWILLING_TO_PERFORM;
2766 if (ldb_msg_find_element(req->op.add.message, "supplementalCredentials")) {
2767 return LDB_ERR_UNWILLING_TO_PERFORM;
2770 /* If no part of this touches the 'userPassword' OR 'clearTextPassword'
2771 * OR 'unicodePwd' OR 'dBCSPwd' we don't need to make any changes. */
2773 userPasswordAttr = NULL;
2775 userPasswordAttr = ldb_msg_find_element(req->op.add.message,
2777 /* MS-ADTS 3.1.1.3.1.5.2 */
2778 if ((userPasswordAttr != NULL) &&
2779 (dsdb_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
2780 return LDB_ERR_CONSTRAINT_VIOLATION;
2783 clearTextPasswordAttr = ldb_msg_find_element(req->op.add.message, "clearTextPassword");
2784 ntAttr = ldb_msg_find_element(req->op.add.message, "unicodePwd");
2785 lmAttr = ldb_msg_find_element(req->op.add.message, "dBCSPwd");
2787 if ((!userPasswordAttr) && (!clearTextPasswordAttr) && (!ntAttr) && (!lmAttr)) {
2788 return ldb_next_request(module, req);
2791 /* Make sure we are performing the password set action on a (for us)
2792 * valid object. Those are instances of either "user" and/or
2793 * "inetOrgPerson". Otherwise continue with the submodules. */
2794 if ((!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "user"))
2795 && (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "inetOrgPerson"))) {
2797 if (ldb_msg_find_element(req->op.add.message, "clearTextPassword") != NULL) {
2798 ldb_set_errstring(ldb,
2799 "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
2800 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2803 return ldb_next_request(module, req);
2806 ac = ph_init_context(module, req, userPassword);
2808 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
2809 return ldb_operr(ldb);
2811 ph_apply_controls(ac);
2813 /* get user domain data */
2814 ret = build_domain_data_request(ac);
2815 if (ret != LDB_SUCCESS) {
2819 return ldb_next_request(module, ac->dom_req);
2822 static int password_hash_add_do_add(struct ph_context *ac)
2824 struct ldb_context *ldb;
2825 struct ldb_request *down_req;
2826 struct ldb_message *msg;
2827 struct setup_password_fields_io io;
2830 /* Prepare the internal data structure containing the passwords */
2831 ret = setup_io(ac, ac->req->op.add.message, ac->req->op.add.message, &io);
2832 if (ret != LDB_SUCCESS) {
2836 ldb = ldb_module_get_ctx(ac->module);
2838 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
2840 return ldb_operr(ldb);
2843 /* remove attributes that we just read into 'io' */
2844 if (ac->userPassword) {
2845 ldb_msg_remove_attr(msg, "userPassword");
2847 ldb_msg_remove_attr(msg, "clearTextPassword");
2848 ldb_msg_remove_attr(msg, "unicodePwd");
2849 ldb_msg_remove_attr(msg, "dBCSPwd");
2850 ldb_msg_remove_attr(msg, "pwdLastSet");
2852 ret = setup_password_fields(&io);
2853 if (ret != LDB_SUCCESS) {
2857 ret = check_password_restrictions(&io);
2858 if (ret != LDB_SUCCESS) {
2863 ret = samdb_msg_add_hash(ldb, ac, msg,
2864 "unicodePwd", io.g.nt_hash);
2865 if (ret != LDB_SUCCESS) {
2870 ret = samdb_msg_add_hash(ldb, ac, msg,
2871 "dBCSPwd", io.g.lm_hash);
2872 if (ret != LDB_SUCCESS) {
2876 if (io.g.nt_history_len > 0) {
2877 ret = samdb_msg_add_hashes(ldb, ac, msg,
2880 io.g.nt_history_len);
2881 if (ret != LDB_SUCCESS) {
2885 if (io.g.lm_history_len > 0) {
2886 ret = samdb_msg_add_hashes(ldb, ac, msg,
2889 io.g.lm_history_len);
2890 if (ret != LDB_SUCCESS) {
2894 if (io.g.supplemental.length > 0) {
2895 ret = ldb_msg_add_value(msg, "supplementalCredentials",
2896 &io.g.supplemental, NULL);
2897 if (ret != LDB_SUCCESS) {
2901 ret = samdb_msg_add_uint64(ldb, ac, msg,
2904 if (ret != LDB_SUCCESS) {
2908 ret = ldb_build_add_req(&down_req, ldb, ac,
2913 LDB_REQ_SET_LOCATION(down_req);
2914 if (ret != LDB_SUCCESS) {
2918 return ldb_next_request(ac->module, down_req);
2921 static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
2923 struct ldb_context *ldb;
2924 struct ph_context *ac;
2925 const char *passwordAttrs[] = { "userPassword", "clearTextPassword",
2926 "unicodePwd", "dBCSPwd", NULL }, **l;
2927 unsigned int attr_cnt, del_attr_cnt, add_attr_cnt, rep_attr_cnt;
2928 struct ldb_message_element *passwordAttr;
2929 struct ldb_message *msg;
2930 struct ldb_request *down_req;
2932 struct ldb_control *bypass = NULL;
2933 bool userPassword = dsdb_user_password_support(module, req, req);
2935 ldb = ldb_module_get_ctx(module);
2937 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
2939 if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
2940 return ldb_next_request(module, req);
2943 /* If the caller is manipulating the local passwords directly, let them pass */
2944 if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
2945 req->op.mod.message->dn) == 0) {
2946 return ldb_next_request(module, req);
2949 bypass = ldb_request_get_control(req,
2950 DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID);
2951 if (bypass != NULL) {
2952 /* Mark the "bypass" control as uncritical (done) */
2953 bypass->critical = false;
2954 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify (bypassing)\n");
2955 return password_hash_bypass(module, req);
2958 /* nobody must touch password histories and 'supplementalCredentials' */
2959 if (ldb_msg_find_element(req->op.mod.message, "ntPwdHistory")) {
2960 return LDB_ERR_UNWILLING_TO_PERFORM;
2962 if (ldb_msg_find_element(req->op.mod.message, "lmPwdHistory")) {
2963 return LDB_ERR_UNWILLING_TO_PERFORM;
2965 if (ldb_msg_find_element(req->op.mod.message, "supplementalCredentials")) {
2966 return LDB_ERR_UNWILLING_TO_PERFORM;
2969 /* If no part of this touches the 'userPassword' OR 'clearTextPassword'
2970 * OR 'unicodePwd' OR 'dBCSPwd' we don't need to make any changes.
2971 * For password changes/set there should be a 'delete' or a 'modify'
2972 * on these attributes. */
2974 for (l = passwordAttrs; *l != NULL; l++) {
2975 if ((!userPassword) && (ldb_attr_cmp(*l, "userPassword") == 0)) {
2979 if (ldb_msg_find_element(req->op.mod.message, *l) != NULL) {
2980 /* MS-ADTS 3.1.1.3.1.5.2 */
2981 if ((ldb_attr_cmp(*l, "userPassword") == 0) &&
2982 (dsdb_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
2983 return LDB_ERR_CONSTRAINT_VIOLATION;
2989 if (attr_cnt == 0) {
2990 return ldb_next_request(module, req);
2993 ac = ph_init_context(module, req, userPassword);
2995 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
2996 return ldb_operr(ldb);
2998 ph_apply_controls(ac);
3000 /* use a new message structure so that we can modify it */
3001 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3003 return ldb_oom(ldb);
3006 /* - check for single-valued password attributes
3007 * (if not return "CONSTRAINT_VIOLATION")
3008 * - check that for a password change operation one add and one delete
3010 * (if not return "CONSTRAINT_VIOLATION" or "UNWILLING_TO_PERFORM")
3011 * - check that a password change and a password set operation cannot
3013 * (if not return "UNWILLING_TO_PERFORM")
3014 * - remove all password attributes modifications from the first change
3015 * operation (anything without the passwords) - we will make the real
3016 * modification later */
3020 for (l = passwordAttrs; *l != NULL; l++) {
3021 if ((!ac->userPassword) &&
3022 (ldb_attr_cmp(*l, "userPassword") == 0)) {
3026 while ((passwordAttr = ldb_msg_find_element(msg, *l)) != NULL) {
3027 if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_DELETE) {
3030 if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_ADD) {
3033 if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_REPLACE) {
3036 if ((passwordAttr->num_values != 1) &&
3037 (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_ADD)) {
3039 ldb_asprintf_errstring(ldb,
3040 "'%s' attribute must have exactly one value on add operations!",
3042 return LDB_ERR_CONSTRAINT_VIOLATION;
3044 if ((passwordAttr->num_values > 1) &&
3045 (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_DELETE)) {
3047 ldb_asprintf_errstring(ldb,
3048 "'%s' attribute must have zero or one value(s) on delete operations!",
3050 return LDB_ERR_CONSTRAINT_VIOLATION;
3052 ldb_msg_remove_element(msg, passwordAttr);
3055 if ((del_attr_cnt == 0) && (add_attr_cnt > 0)) {
3057 ldb_set_errstring(ldb,
3058 "Only the add action for a password change specified!");
3059 return LDB_ERR_UNWILLING_TO_PERFORM;
3061 if ((del_attr_cnt > 1) || (add_attr_cnt > 1)) {
3063 ldb_set_errstring(ldb,
3064 "Only one delete and one add action for a password change allowed!");
3065 return LDB_ERR_UNWILLING_TO_PERFORM;
3067 if ((rep_attr_cnt > 0) && ((del_attr_cnt > 0) || (add_attr_cnt > 0))) {
3069 ldb_set_errstring(ldb,
3070 "Either a password change or a password set operation is allowed!");
3071 return LDB_ERR_UNWILLING_TO_PERFORM;
3074 /* if there was nothing else to be modified skip to next step */
3075 if (msg->num_elements == 0) {
3076 return password_hash_mod_search_self(ac);
3079 ret = ldb_build_mod_req(&down_req, ldb, ac,
3082 ac, ph_modify_callback,
3084 LDB_REQ_SET_LOCATION(down_req);
3085 if (ret != LDB_SUCCESS) {
3089 return ldb_next_request(module, down_req);
3092 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
3094 struct ph_context *ac;
3096 ac = talloc_get_type(req->context, struct ph_context);
3099 return ldb_module_done(ac->req, NULL, NULL,
3100 LDB_ERR_OPERATIONS_ERROR);
3103 if (ares->type == LDB_REPLY_REFERRAL) {
3104 return ldb_module_send_referral(ac->req, ares->referral);
3107 if (ares->error != LDB_SUCCESS) {
3108 return ldb_module_done(ac->req, ares->controls,
3109 ares->response, ares->error);
3112 if (ares->type != LDB_REPLY_DONE) {
3114 return ldb_module_done(ac->req, NULL, NULL,
3115 LDB_ERR_OPERATIONS_ERROR);
3120 return password_hash_mod_search_self(ac);
3123 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
3125 struct ldb_context *ldb;
3126 struct ph_context *ac;
3129 ac = talloc_get_type(req->context, struct ph_context);
3130 ldb = ldb_module_get_ctx(ac->module);
3133 ret = LDB_ERR_OPERATIONS_ERROR;
3136 if (ares->error != LDB_SUCCESS) {
3137 return ldb_module_done(ac->req, ares->controls,
3138 ares->response, ares->error);
3141 /* we are interested only in the single reply (base search) */
3142 switch (ares->type) {
3143 case LDB_REPLY_ENTRY:
3144 /* Make sure we are performing the password change action on a
3145 * (for us) valid object. Those are instances of either "user"
3146 * and/or "inetOrgPerson". Otherwise continue with the
3148 if ((!ldb_msg_check_string_attribute(ares->message, "objectClass", "user"))
3149 && (!ldb_msg_check_string_attribute(ares->message, "objectClass", "inetOrgPerson"))) {
3152 if (ldb_msg_find_element(ac->req->op.mod.message, "clearTextPassword") != NULL) {
3153 ldb_set_errstring(ldb,
3154 "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
3155 ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
3159 ret = ldb_next_request(ac->module, ac->req);
3163 if (ac->search_res != NULL) {
3166 ldb_set_errstring(ldb, "Too many results");
3167 ret = LDB_ERR_OPERATIONS_ERROR;
3171 ac->search_res = talloc_steal(ac, ares);
3175 case LDB_REPLY_REFERRAL:
3176 /* ignore anything else for now */
3181 case LDB_REPLY_DONE:
3184 /* get user domain data */
3185 ret = build_domain_data_request(ac);
3186 if (ret != LDB_SUCCESS) {
3187 return ldb_module_done(ac->req, NULL, NULL, ret);
3190 ret = ldb_next_request(ac->module, ac->dom_req);
3195 if (ret != LDB_SUCCESS) {
3196 return ldb_module_done(ac->req, NULL, NULL, ret);
3202 static int password_hash_mod_search_self(struct ph_context *ac)
3204 struct ldb_context *ldb;
3205 static const char * const attrs[] = { "objectClass",
3206 "userAccountControl",
3210 "userPrincipalName",
3211 "supplementalCredentials",
3217 struct ldb_request *search_req;
3220 ldb = ldb_module_get_ctx(ac->module);
3222 ret = ldb_build_search_req(&search_req, ldb, ac,
3223 ac->req->op.mod.message->dn,
3228 ac, ph_mod_search_callback,
3230 LDB_REQ_SET_LOCATION(search_req);
3231 if (ret != LDB_SUCCESS) {
3235 return ldb_next_request(ac->module, search_req);
3238 static int password_hash_mod_do_mod(struct ph_context *ac)
3240 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3241 struct loadparm_context *lp_ctx =
3242 talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3243 struct loadparm_context);
3244 struct ldb_request *mod_req;
3245 struct ldb_message *msg;
3246 const struct ldb_message *orig_msg, *searched_msg;
3247 struct setup_password_fields_io io;
3251 /* use a new message structure so that we can modify it */
3252 msg = ldb_msg_new(ac);
3254 return ldb_operr(ldb);
3258 msg->dn = ac->req->op.mod.message->dn;
3260 orig_msg = ac->req->op.mod.message;
3261 searched_msg = ac->search_res->message;
3263 /* Prepare the internal data structure containing the passwords */
3264 ret = setup_io(ac, orig_msg, searched_msg, &io);
3265 if (ret != LDB_SUCCESS) {
3269 /* Get the old password from the database */
3270 status = samdb_result_passwords(io.ac,
3272 discard_const_p(struct ldb_message, searched_msg),
3273 &io.o.lm_hash, &io.o.nt_hash);
3274 if (!NT_STATUS_IS_OK(status)) {
3275 return ldb_operr(ldb);
3278 io.o.nt_history_len = samdb_result_hashes(io.ac, searched_msg, "ntPwdHistory", &io.o.nt_history);
3279 io.o.lm_history_len = samdb_result_hashes(io.ac, searched_msg, "lmPwdHistory", &io.o.lm_history);
3280 io.o.supplemental = ldb_msg_find_ldb_val(searched_msg, "supplementalCredentials");
3282 ret = setup_password_fields(&io);
3283 if (ret != LDB_SUCCESS) {
3287 ret = check_password_restrictions(&io);
3288 if (ret != LDB_SUCCESS) {
3292 /* make sure we replace all the old attributes */
3293 ret = ldb_msg_add_empty(msg, "unicodePwd", LDB_FLAG_MOD_REPLACE, NULL);
3294 ret = ldb_msg_add_empty(msg, "dBCSPwd", LDB_FLAG_MOD_REPLACE, NULL);
3295 ret = ldb_msg_add_empty(msg, "ntPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
3296 ret = ldb_msg_add_empty(msg, "lmPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
3297 ret = ldb_msg_add_empty(msg, "supplementalCredentials", LDB_FLAG_MOD_REPLACE, NULL);
3298 ret = ldb_msg_add_empty(msg, "pwdLastSet", LDB_FLAG_MOD_REPLACE, NULL);
3301 ret = samdb_msg_add_hash(ldb, ac, msg,
3302 "unicodePwd", io.g.nt_hash);
3303 if (ret != LDB_SUCCESS) {
3308 ret = samdb_msg_add_hash(ldb, ac, msg,
3309 "dBCSPwd", io.g.lm_hash);
3310 if (ret != LDB_SUCCESS) {
3314 if (io.g.nt_history_len > 0) {
3315 ret = samdb_msg_add_hashes(ldb, ac, msg,
3318 io.g.nt_history_len);
3319 if (ret != LDB_SUCCESS) {
3323 if (io.g.lm_history_len > 0) {
3324 ret = samdb_msg_add_hashes(ldb, ac, msg,
3327 io.g.lm_history_len);
3328 if (ret != LDB_SUCCESS) {
3332 if (io.g.supplemental.length > 0) {
3333 ret = ldb_msg_add_value(msg, "supplementalCredentials",
3334 &io.g.supplemental, NULL);
3335 if (ret != LDB_SUCCESS) {
3339 ret = samdb_msg_add_uint64(ldb, ac, msg,
3342 if (ret != LDB_SUCCESS) {
3346 ret = ldb_build_mod_req(&mod_req, ldb, ac,
3351 LDB_REQ_SET_LOCATION(mod_req);
3352 if (ret != LDB_SUCCESS) {
3356 return ldb_next_request(ac->module, mod_req);
3359 static const struct ldb_module_ops ldb_password_hash_module_ops = {
3360 .name = "password_hash",
3361 .add = password_hash_add,
3362 .modify = password_hash_modify
3365 int ldb_password_hash_module_init(const char *version)
3367 LDB_MODULE_CHECK_VERSION(version);
3368 return ldb_register_module(&ldb_password_hash_module_ops);