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;
101 struct setup_password_fields_io {
102 struct ph_context *ac;
104 struct smb_krb5_context *smb_krb5_context;
106 /* infos about the user account */
108 uint32_t userAccountControl;
110 const char *sAMAccountName;
111 const char *user_principal_name;
113 uint32_t restrictions;
116 /* new credentials and old given credentials */
117 struct setup_password_fields_given {
118 const struct ldb_val *cleartext_utf8;
119 const struct ldb_val *cleartext_utf16;
120 struct samr_Password *nt_hash;
121 struct samr_Password *lm_hash;
124 /* old credentials */
126 struct samr_Password *nt_hash;
127 struct samr_Password *lm_hash;
128 uint32_t nt_history_len;
129 struct samr_Password *nt_history;
130 uint32_t lm_history_len;
131 struct samr_Password *lm_history;
132 const struct ldb_val *supplemental;
133 struct supplementalCredentialsBlob scb;
136 /* generated credentials */
138 struct samr_Password *nt_hash;
139 struct samr_Password *lm_hash;
140 uint32_t nt_history_len;
141 struct samr_Password *nt_history;
142 uint32_t lm_history_len;
143 struct samr_Password *lm_history;
149 struct ldb_val supplemental;
154 static int password_hash_bypass(struct ldb_module *module, struct ldb_request *request)
156 struct ldb_context *ldb = ldb_module_get_ctx(module);
157 const struct ldb_message *msg;
158 struct ldb_message_element *nte;
159 struct ldb_message_element *lme;
160 struct ldb_message_element *nthe;
161 struct ldb_message_element *lmhe;
162 struct ldb_message_element *sce;
164 switch (request->operation) {
166 msg = request->op.add.message;
169 msg = request->op.mod.message;
172 return ldb_next_request(module, request);
175 /* nobody must touch password histories and 'supplementalCredentials' */
176 nte = dsdb_get_single_valued_attr(msg, "unicodePwd",
178 lme = dsdb_get_single_valued_attr(msg, "dBCSPwd",
180 nthe = dsdb_get_single_valued_attr(msg, "ntPwdHistory",
182 lmhe = dsdb_get_single_valued_attr(msg, "lmPwdHistory",
184 sce = dsdb_get_single_valued_attr(msg, "supplementalCredentials",
187 #define CHECK_HASH_ELEMENT(e, min, max) do {\
188 if (e && e->num_values) { \
189 unsigned int _count; \
190 if (e->num_values != 1) { \
191 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
192 "num_values != 1"); \
194 if ((e->values[0].length % 16) != 0) { \
195 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
196 "length % 16 != 0"); \
198 _count = e->values[0].length / 16; \
199 if (_count < min) { \
200 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
203 if (_count > max) { \
204 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
210 CHECK_HASH_ELEMENT(nte, 1, 1);
211 CHECK_HASH_ELEMENT(lme, 1, 1);
212 CHECK_HASH_ELEMENT(nthe, 1, INT32_MAX);
213 CHECK_HASH_ELEMENT(lmhe, 1, INT32_MAX);
215 if (sce && sce->num_values) {
216 enum ndr_err_code ndr_err;
217 struct supplementalCredentialsBlob *scb;
218 struct supplementalCredentialsPackage *scpp = NULL;
219 struct supplementalCredentialsPackage *scpk = NULL;
220 struct supplementalCredentialsPackage *scpkn = NULL;
221 struct supplementalCredentialsPackage *scpct = NULL;
222 DATA_BLOB scpbp = data_blob_null;
223 DATA_BLOB scpbk = data_blob_null;
224 DATA_BLOB scpbkn = data_blob_null;
225 DATA_BLOB scpbct = data_blob_null;
229 if (sce->num_values != 1) {
230 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
234 scb = talloc_zero(request, struct supplementalCredentialsBlob);
236 return ldb_module_oom(module);
239 ndr_err = ndr_pull_struct_blob_all(&sce->values[0], scb, scb,
240 (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
241 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
242 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
243 "ndr_pull_struct_blob_all");
246 if (scb->sub.num_packages < 2) {
247 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
251 for (i=0; i < scb->sub.num_packages; i++) {
254 subblob = strhex_to_data_blob(scb, scb->sub.packages[i].data);
255 if (subblob.data == NULL) {
256 return ldb_module_oom(module);
259 if (strcmp(scb->sub.packages[i].name, "Packages") == 0) {
261 return ldb_error(ldb,
262 LDB_ERR_CONSTRAINT_VIOLATION,
265 scpp = &scb->sub.packages[i];
269 if (strcmp(scb->sub.packages[i].name, "Primary:Kerberos") == 0) {
271 return ldb_error(ldb,
272 LDB_ERR_CONSTRAINT_VIOLATION,
273 "Primary:Kerberos twice");
275 scpk = &scb->sub.packages[i];
279 if (strcmp(scb->sub.packages[i].name, "Primary:Kerberos-Newer-Keys") == 0) {
281 return ldb_error(ldb,
282 LDB_ERR_CONSTRAINT_VIOLATION,
283 "Primary:Kerberos-Newer-Keys twice");
285 scpkn = &scb->sub.packages[i];
289 if (strcmp(scb->sub.packages[i].name, "Primary:CLEARTEXT") == 0) {
291 return ldb_error(ldb,
292 LDB_ERR_CONSTRAINT_VIOLATION,
293 "Primary:CLEARTEXT twice");
295 scpct = &scb->sub.packages[i];
300 data_blob_free(&subblob);
304 struct package_PackagesBlob *p;
307 p = talloc_zero(scb, struct package_PackagesBlob);
309 return ldb_module_oom(module);
312 ndr_err = ndr_pull_struct_blob(&scpbp, p, p,
313 (ndr_pull_flags_fn_t)ndr_pull_package_PackagesBlob);
314 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
315 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
316 "ndr_pull_struct_blob Packages");
319 if (p->names == NULL) {
320 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
321 "Packages names == NULL");
324 for (n = 0; p->names[n]; n++) {
328 if (scb->sub.num_packages != (n + 1)) {
329 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
330 "Packages num_packages != num_names + 1");
337 struct package_PrimaryKerberosBlob *k;
339 k = talloc_zero(scb, struct package_PrimaryKerberosBlob);
341 return ldb_module_oom(module);
344 ndr_err = ndr_pull_struct_blob(&scpbk, k, k,
345 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
346 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
347 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
348 "ndr_pull_struct_blob PrimaryKerberos");
351 if (k->version != 3) {
352 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
353 "PrimaryKerberos version != 3");
356 if (k->ctr.ctr3.salt.string == NULL) {
357 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
358 "PrimaryKerberos salt == NULL");
361 if (strlen(k->ctr.ctr3.salt.string) == 0) {
362 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
363 "PrimaryKerberos strlen(salt) == 0");
366 if (k->ctr.ctr3.num_keys != 2) {
367 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
368 "PrimaryKerberos num_keys != 2");
371 if (k->ctr.ctr3.num_old_keys > k->ctr.ctr3.num_keys) {
372 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
373 "PrimaryKerberos num_old_keys > num_keys");
376 if (k->ctr.ctr3.keys[0].keytype != ENCTYPE_DES_CBC_MD5) {
377 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
378 "PrimaryKerberos key[0] != DES_CBC_MD5");
380 if (k->ctr.ctr3.keys[1].keytype != ENCTYPE_DES_CBC_CRC) {
381 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
382 "PrimaryKerberos key[1] != DES_CBC_CRC");
385 if (k->ctr.ctr3.keys[0].value_len != 8) {
386 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
387 "PrimaryKerberos key[0] value_len != 8");
389 if (k->ctr.ctr3.keys[1].value_len != 8) {
390 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
391 "PrimaryKerberos key[1] value_len != 8");
394 for (i = 0; i < k->ctr.ctr3.num_old_keys; i++) {
395 if (k->ctr.ctr3.old_keys[i].keytype ==
396 k->ctr.ctr3.keys[i].keytype &&
397 k->ctr.ctr3.old_keys[i].value_len ==
398 k->ctr.ctr3.keys[i].value_len) {
402 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
403 "PrimaryKerberos old_keys type/value_len doesn't match");
410 struct package_PrimaryKerberosBlob *k;
412 k = talloc_zero(scb, struct package_PrimaryKerberosBlob);
414 return ldb_module_oom(module);
417 ndr_err = ndr_pull_struct_blob(&scpbkn, k, k,
418 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
419 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
420 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
421 "ndr_pull_struct_blob PrimaryKerberosNeverKeys");
424 if (k->version != 4) {
425 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
426 "KerberosNerverKeys version != 4");
429 if (k->ctr.ctr4.salt.string == NULL) {
430 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
431 "KerberosNewerKeys salt == NULL");
434 if (strlen(k->ctr.ctr4.salt.string) == 0) {
435 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
436 "KerberosNewerKeys strlen(salt) == 0");
439 if (k->ctr.ctr4.num_keys != 4) {
440 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
441 "KerberosNewerKeys num_keys != 2");
444 if (k->ctr.ctr4.num_old_keys > k->ctr.ctr4.num_keys) {
445 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
446 "KerberosNewerKeys num_old_keys > num_keys");
449 if (k->ctr.ctr4.num_older_keys > k->ctr.ctr4.num_old_keys) {
450 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
451 "KerberosNewerKeys num_older_keys > num_old_keys");
454 if (k->ctr.ctr4.keys[0].keytype != ENCTYPE_AES256_CTS_HMAC_SHA1_96) {
455 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
456 "KerberosNewerKeys key[0] != AES256");
458 if (k->ctr.ctr4.keys[1].keytype != ENCTYPE_AES128_CTS_HMAC_SHA1_96) {
459 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
460 "KerberosNewerKeys key[1] != AES128");
462 if (k->ctr.ctr4.keys[2].keytype != ENCTYPE_DES_CBC_MD5) {
463 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
464 "KerberosNewerKeys key[2] != DES_CBC_MD5");
466 if (k->ctr.ctr4.keys[3].keytype != ENCTYPE_DES_CBC_CRC) {
467 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
468 "KerberosNewerKeys key[3] != DES_CBC_CRC");
471 if (k->ctr.ctr4.keys[0].value_len != 32) {
472 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
473 "KerberosNewerKeys key[0] value_len != 32");
475 if (k->ctr.ctr4.keys[1].value_len != 16) {
476 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
477 "KerberosNewerKeys key[1] value_len != 16");
479 if (k->ctr.ctr4.keys[2].value_len != 8) {
480 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
481 "KerberosNewerKeys key[2] value_len != 8");
483 if (k->ctr.ctr4.keys[3].value_len != 8) {
484 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
485 "KerberosNewerKeys key[3] value_len != 8");
490 * Maybe we can check old and older keys here.
491 * But we need to do some tests, if the old keys
492 * can be taken from the PrimaryKerberos blob
493 * (with only des keys), when the domain was upgraded
501 struct package_PrimaryCLEARTEXTBlob *ct;
503 ct = talloc_zero(scb, struct package_PrimaryCLEARTEXTBlob);
505 return ldb_module_oom(module);
508 ndr_err = ndr_pull_struct_blob(&scpbct, ct, ct,
509 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryCLEARTEXTBlob);
510 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
511 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
512 "ndr_pull_struct_blob PrimaryCLEARTEXT");
515 if ((ct->cleartext.length % 2) != 0) {
516 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
517 "PrimaryCLEARTEXT length % 2 != 0");
523 ndr_err = ndr_push_struct_blob(&blob, scb, scb,
524 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
525 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
526 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
527 "ndr_pull_struct_blob_all");
530 if (sce->values[0].length != blob.length) {
531 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
532 "supplementalCredentialsBlob length differ");
535 if (memcmp(sce->values[0].data, blob.data, blob.length) != 0) {
536 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
537 "supplementalCredentialsBlob memcmp differ");
543 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_bypass - validated\n");
544 return ldb_next_request(module, request);
547 /* Get the NT hash, and fill it in as an entry in the password history,
548 and specify it into io->g.nt_hash */
550 static int setup_nt_fields(struct setup_password_fields_io *io)
552 struct ldb_context *ldb;
555 io->g.nt_hash = io->n.nt_hash;
556 ldb = ldb_module_get_ctx(io->ac->module);
558 if (io->ac->status->domain_data.pwdHistoryLength == 0) {
562 /* We might not have an old NT password */
563 io->g.nt_history = talloc_array(io->ac,
564 struct samr_Password,
565 io->ac->status->domain_data.pwdHistoryLength);
566 if (!io->g.nt_history) {
570 for (i = 0; i < MIN(io->ac->status->domain_data.pwdHistoryLength-1,
571 io->o.nt_history_len); i++) {
572 io->g.nt_history[i+1] = io->o.nt_history[i];
574 io->g.nt_history_len = i + 1;
577 io->g.nt_history[0] = *io->g.nt_hash;
580 * TODO: is this correct?
581 * the simular behavior is correct for the lm history case
583 E_md4hash("", io->g.nt_history[0].hash);
589 /* Get the LANMAN hash, and fill it in as an entry in the password history,
590 and specify it into io->g.lm_hash */
592 static int setup_lm_fields(struct setup_password_fields_io *io)
594 struct ldb_context *ldb;
597 io->g.lm_hash = io->n.lm_hash;
598 ldb = ldb_module_get_ctx(io->ac->module);
600 if (io->ac->status->domain_data.pwdHistoryLength == 0) {
604 /* We might not have an old LM password */
605 io->g.lm_history = talloc_array(io->ac,
606 struct samr_Password,
607 io->ac->status->domain_data.pwdHistoryLength);
608 if (!io->g.lm_history) {
612 for (i = 0; i < MIN(io->ac->status->domain_data.pwdHistoryLength-1,
613 io->o.lm_history_len); i++) {
614 io->g.lm_history[i+1] = io->o.lm_history[i];
616 io->g.lm_history_len = i + 1;
619 io->g.lm_history[0] = *io->g.lm_hash;
621 E_deshash("", io->g.lm_history[0].hash);
627 static int setup_kerberos_keys(struct setup_password_fields_io *io)
629 struct ldb_context *ldb;
630 krb5_error_code krb5_ret;
631 Principal *salt_principal;
634 krb5_data cleartext_data;
636 ldb = ldb_module_get_ctx(io->ac->module);
637 cleartext_data.data = io->n.cleartext_utf8->data;
638 cleartext_data.length = io->n.cleartext_utf8->length;
640 /* Many, many thanks to lukeh@padl.com for this
641 * algorithm, described in his Nov 10 2004 mail to
642 * samba-technical@samba.org */
645 * Determine a salting principal
647 if (io->u.is_computer) {
651 name = strlower_talloc(io->ac, io->u.sAMAccountName);
656 if (name[strlen(name)-1] == '$') {
657 name[strlen(name)-1] = '\0';
660 saltbody = talloc_asprintf(io->ac, "%s.%s", name,
661 io->ac->status->domain_data.dns_domain);
666 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
668 io->ac->status->domain_data.realm,
669 "host", saltbody, NULL);
670 } else if (io->u.user_principal_name) {
671 char *user_principal_name;
674 user_principal_name = talloc_strdup(io->ac, io->u.user_principal_name);
675 if (!user_principal_name) {
679 p = strchr(user_principal_name, '@');
684 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
686 io->ac->status->domain_data.realm,
687 user_principal_name, NULL);
689 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
691 io->ac->status->domain_data.realm,
692 io->u.sAMAccountName, NULL);
695 ldb_asprintf_errstring(ldb,
696 "setup_kerberos_keys: "
697 "generation of a salting principal failed: %s",
698 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
700 return LDB_ERR_OPERATIONS_ERROR;
704 * create salt from salt_principal
706 krb5_ret = krb5_get_pw_salt(io->smb_krb5_context->krb5_context,
707 salt_principal, &salt);
708 krb5_free_principal(io->smb_krb5_context->krb5_context, salt_principal);
710 ldb_asprintf_errstring(ldb,
711 "setup_kerberos_keys: "
712 "generation of krb5_salt failed: %s",
713 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
715 return LDB_ERR_OPERATIONS_ERROR;
717 /* create a talloc copy */
718 io->g.salt = talloc_strndup(io->ac,
719 (char *)salt.saltvalue.data,
720 salt.saltvalue.length);
721 krb5_free_salt(io->smb_krb5_context->krb5_context, salt);
725 salt.saltvalue.data = discard_const(io->g.salt);
726 salt.saltvalue.length = strlen(io->g.salt);
729 * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of
730 * the salt and the cleartext password
732 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
733 ENCTYPE_AES256_CTS_HMAC_SHA1_96,
738 ldb_asprintf_errstring(ldb,
739 "setup_kerberos_keys: "
740 "generation of a aes256-cts-hmac-sha1-96 key failed: %s",
741 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
743 return LDB_ERR_OPERATIONS_ERROR;
745 io->g.aes_256 = data_blob_talloc(io->ac,
747 key.keyvalue.length);
748 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
749 if (!io->g.aes_256.data) {
754 * create ENCTYPE_AES128_CTS_HMAC_SHA1_96 key out of
755 * the salt and the cleartext password
757 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
758 ENCTYPE_AES128_CTS_HMAC_SHA1_96,
763 ldb_asprintf_errstring(ldb,
764 "setup_kerberos_keys: "
765 "generation of a aes128-cts-hmac-sha1-96 key failed: %s",
766 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
768 return LDB_ERR_OPERATIONS_ERROR;
770 io->g.aes_128 = data_blob_talloc(io->ac,
772 key.keyvalue.length);
773 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
774 if (!io->g.aes_128.data) {
779 * create ENCTYPE_DES_CBC_MD5 key out of
780 * the salt and the cleartext password
782 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
788 ldb_asprintf_errstring(ldb,
789 "setup_kerberos_keys: "
790 "generation of a des-cbc-md5 key failed: %s",
791 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
793 return LDB_ERR_OPERATIONS_ERROR;
795 io->g.des_md5 = data_blob_talloc(io->ac,
797 key.keyvalue.length);
798 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
799 if (!io->g.des_md5.data) {
804 * create ENCTYPE_DES_CBC_CRC key out of
805 * the salt and the cleartext password
807 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
813 ldb_asprintf_errstring(ldb,
814 "setup_kerberos_keys: "
815 "generation of a des-cbc-crc key failed: %s",
816 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
818 return LDB_ERR_OPERATIONS_ERROR;
820 io->g.des_crc = data_blob_talloc(io->ac,
822 key.keyvalue.length);
823 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
824 if (!io->g.des_crc.data) {
831 static int setup_primary_kerberos(struct setup_password_fields_io *io,
832 const struct supplementalCredentialsBlob *old_scb,
833 struct package_PrimaryKerberosBlob *pkb)
835 struct ldb_context *ldb;
836 struct package_PrimaryKerberosCtr3 *pkb3 = &pkb->ctr.ctr3;
837 struct supplementalCredentialsPackage *old_scp = NULL;
838 struct package_PrimaryKerberosBlob _old_pkb;
839 struct package_PrimaryKerberosCtr3 *old_pkb3 = NULL;
841 enum ndr_err_code ndr_err;
843 ldb = ldb_module_get_ctx(io->ac->module);
846 * prepare generation of keys
848 * ENCTYPE_DES_CBC_MD5
849 * ENCTYPE_DES_CBC_CRC
852 pkb3->salt.string = io->g.salt;
854 pkb3->keys = talloc_array(io->ac,
855 struct package_PrimaryKerberosKey3,
861 pkb3->keys[0].keytype = ENCTYPE_DES_CBC_MD5;
862 pkb3->keys[0].value = &io->g.des_md5;
863 pkb3->keys[1].keytype = ENCTYPE_DES_CBC_CRC;
864 pkb3->keys[1].value = &io->g.des_crc;
866 /* initialize the old keys to zero */
867 pkb3->num_old_keys = 0;
868 pkb3->old_keys = NULL;
870 /* if there're no old keys, then we're done */
875 for (i=0; i < old_scb->sub.num_packages; i++) {
876 if (strcmp("Primary:Kerberos", old_scb->sub.packages[i].name) != 0) {
880 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
884 old_scp = &old_scb->sub.packages[i];
887 /* Primary:Kerberos element of supplementalCredentials */
891 blob = strhex_to_data_blob(io->ac, old_scp->data);
896 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
897 ndr_err = ndr_pull_struct_blob(&blob, io->ac, &_old_pkb,
898 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
899 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
900 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
901 ldb_asprintf_errstring(ldb,
902 "setup_primary_kerberos: "
903 "failed to pull old package_PrimaryKerberosBlob: %s",
905 return LDB_ERR_OPERATIONS_ERROR;
908 if (_old_pkb.version != 3) {
909 ldb_asprintf_errstring(ldb,
910 "setup_primary_kerberos: "
911 "package_PrimaryKerberosBlob version[%u] expected[3]",
913 return LDB_ERR_OPERATIONS_ERROR;
916 old_pkb3 = &_old_pkb.ctr.ctr3;
919 /* if we didn't found the old keys we're done */
924 /* fill in the old keys */
925 pkb3->num_old_keys = old_pkb3->num_keys;
926 pkb3->old_keys = old_pkb3->keys;
931 static int setup_primary_kerberos_newer(struct setup_password_fields_io *io,
932 const struct supplementalCredentialsBlob *old_scb,
933 struct package_PrimaryKerberosBlob *pkb)
935 struct ldb_context *ldb;
936 struct package_PrimaryKerberosCtr4 *pkb4 = &pkb->ctr.ctr4;
937 struct supplementalCredentialsPackage *old_scp = NULL;
938 struct package_PrimaryKerberosBlob _old_pkb;
939 struct package_PrimaryKerberosCtr4 *old_pkb4 = NULL;
941 enum ndr_err_code ndr_err;
943 ldb = ldb_module_get_ctx(io->ac->module);
946 * prepare generation of keys
948 * ENCTYPE_AES256_CTS_HMAC_SHA1_96
949 * ENCTYPE_AES128_CTS_HMAC_SHA1_96
950 * ENCTYPE_DES_CBC_MD5
951 * ENCTYPE_DES_CBC_CRC
954 pkb4->salt.string = io->g.salt;
955 pkb4->default_iteration_count = 4096;
958 pkb4->keys = talloc_array(io->ac,
959 struct package_PrimaryKerberosKey4,
965 pkb4->keys[0].iteration_count = 4096;
966 pkb4->keys[0].keytype = ENCTYPE_AES256_CTS_HMAC_SHA1_96;
967 pkb4->keys[0].value = &io->g.aes_256;
968 pkb4->keys[1].iteration_count = 4096;
969 pkb4->keys[1].keytype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
970 pkb4->keys[1].value = &io->g.aes_128;
971 pkb4->keys[2].iteration_count = 4096;
972 pkb4->keys[2].keytype = ENCTYPE_DES_CBC_MD5;
973 pkb4->keys[2].value = &io->g.des_md5;
974 pkb4->keys[3].iteration_count = 4096;
975 pkb4->keys[3].keytype = ENCTYPE_DES_CBC_CRC;
976 pkb4->keys[3].value = &io->g.des_crc;
978 /* initialize the old keys to zero */
979 pkb4->num_old_keys = 0;
980 pkb4->old_keys = NULL;
981 pkb4->num_older_keys = 0;
982 pkb4->older_keys = NULL;
984 /* if there're no old keys, then we're done */
989 for (i=0; i < old_scb->sub.num_packages; i++) {
990 if (strcmp("Primary:Kerberos-Newer-Keys", old_scb->sub.packages[i].name) != 0) {
994 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
998 old_scp = &old_scb->sub.packages[i];
1001 /* Primary:Kerberos-Newer-Keys element of supplementalCredentials */
1005 blob = strhex_to_data_blob(io->ac, old_scp->data);
1007 return ldb_oom(ldb);
1010 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
1011 ndr_err = ndr_pull_struct_blob(&blob, io->ac,
1013 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
1014 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1015 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1016 ldb_asprintf_errstring(ldb,
1017 "setup_primary_kerberos_newer: "
1018 "failed to pull old package_PrimaryKerberosBlob: %s",
1020 return LDB_ERR_OPERATIONS_ERROR;
1023 if (_old_pkb.version != 4) {
1024 ldb_asprintf_errstring(ldb,
1025 "setup_primary_kerberos_newer: "
1026 "package_PrimaryKerberosBlob version[%u] expected[4]",
1028 return LDB_ERR_OPERATIONS_ERROR;
1031 old_pkb4 = &_old_pkb.ctr.ctr4;
1034 /* if we didn't found the old keys we're done */
1039 /* fill in the old keys */
1040 pkb4->num_old_keys = old_pkb4->num_keys;
1041 pkb4->old_keys = old_pkb4->keys;
1042 pkb4->num_older_keys = old_pkb4->num_old_keys;
1043 pkb4->older_keys = old_pkb4->old_keys;
1048 static int setup_primary_wdigest(struct setup_password_fields_io *io,
1049 const struct supplementalCredentialsBlob *old_scb,
1050 struct package_PrimaryWDigestBlob *pdb)
1052 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1053 DATA_BLOB sAMAccountName;
1054 DATA_BLOB sAMAccountName_l;
1055 DATA_BLOB sAMAccountName_u;
1056 const char *user_principal_name = io->u.user_principal_name;
1057 DATA_BLOB userPrincipalName;
1058 DATA_BLOB userPrincipalName_l;
1059 DATA_BLOB userPrincipalName_u;
1060 DATA_BLOB netbios_domain;
1061 DATA_BLOB netbios_domain_l;
1062 DATA_BLOB netbios_domain_u;
1063 DATA_BLOB dns_domain;
1064 DATA_BLOB dns_domain_l;
1065 DATA_BLOB dns_domain_u;
1068 DATA_BLOB backslash;
1077 * http://technet2.microsoft.com/WindowsServer/en/library/717b450c-f4a0-4cc9-86f4-cc0633aae5f91033.mspx?mfr=true
1078 * for what precalculated hashes are supposed to be stored...
1080 * I can't reproduce all values which should contain "Digest" as realm,
1081 * am I doing something wrong or is w2k3 just broken...?
1083 * W2K3 fills in following for a user:
1085 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
1086 * sAMAccountName: NewUser2Sam
1087 * userPrincipalName: NewUser2Princ@sub1.w2k3.vmnet1.vm.base
1089 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1090 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
1091 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
1092 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1093 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
1094 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
1095 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
1096 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1097 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1098 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1099 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1100 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1101 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1102 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1103 * 221c55284451ae9b3aacaa2a3c86f10f => NewUser2Princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1104 * 74e1be668853d4324d38c07e2acfb8ea => (w2k3 has a bug here!) newuser2princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1105 * e1e244ab7f098e3ae1761be7f9229bbb => NEWUSER2PRINC@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
1106 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
1107 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
1108 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
1109 * 31dc704d3640335b2123d4ee28aa1f11 => ??? changes with NewUser2Sam => NewUser1Sam
1110 * 36349f5cecd07320fb3bb0e119230c43 => ??? changes with NewUser2Sam => NewUser1Sam
1111 * 12adf019d037fb535c01fd0608e78d9d => ??? changes with NewUser2Sam => NewUser1Sam
1112 * 6feecf8e724906f3ee1105819c5105a1 => ??? changes with NewUser2Princ => NewUser1Princ
1113 * 6c6911f3de6333422640221b9c51ff1f => ??? changes with NewUser2Princ => NewUser1Princ
1114 * 4b279877e742895f9348ac67a8de2f69 => ??? changes with NewUser2Princ => NewUser1Princ
1115 * db0c6bff069513e3ebb9870d29b57490 => ??? changes with NewUser2Sam => NewUser1Sam
1116 * 45072621e56b1c113a4e04a8ff68cd0e => ??? changes with NewUser2Sam => NewUser1Sam
1117 * 11d1220abc44a9c10cf91ef4a9c1de02 => ??? changes with NewUser2Sam => NewUser1Sam
1119 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
1120 * sAMAccountName: NewUser2Sam
1122 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1123 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
1124 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
1125 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1126 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
1127 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
1128 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
1129 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1130 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1131 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1132 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1133 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1134 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1135 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1136 * 8a140d30b6f0a5912735dc1e3bc993b4 => NewUser2Sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1137 * 86d95b2faae6cae4ec261e7fbaccf093 => (here w2k3 is correct) newuser2sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1138 * dfeff1493110220efcdfc6362e5f5450 => NEWUSER2SAM@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
1139 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
1140 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
1141 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
1142 * 31dc704d3640335b2123d4ee28aa1f11 => ???M1 changes with NewUser2Sam => NewUser1Sam
1143 * 36349f5cecd07320fb3bb0e119230c43 => ???M1.L changes with newuser2sam => newuser1sam
1144 * 12adf019d037fb535c01fd0608e78d9d => ???M1.U changes with NEWUSER2SAM => NEWUSER1SAM
1145 * 569b4533f2d9e580211dd040e5e360a8 => ???M2 changes with NewUser2Princ => NewUser1Princ
1146 * 52528bddf310a587c5d7e6a9ae2cbb20 => ???M2.L changes with newuser2princ => newuser1princ
1147 * 4f629a4f0361289ca4255ab0f658fcd5 => ???M3 changes with NewUser2Princ => NewUser1Princ (doesn't depend on case of userPrincipal )
1148 * db0c6bff069513e3ebb9870d29b57490 => ???M4 changes with NewUser2Sam => NewUser1Sam
1149 * 45072621e56b1c113a4e04a8ff68cd0e => ???M5 changes with NewUser2Sam => NewUser1Sam (doesn't depend on case of sAMAccountName)
1150 * 11d1220abc44a9c10cf91ef4a9c1de02 => ???M4.U changes with NEWUSER2SAM => NEWUSER1SAM
1154 * sAMAccountName, netbios_domain
1157 .user = &sAMAccountName,
1158 .realm = &netbios_domain,
1161 .user = &sAMAccountName_l,
1162 .realm = &netbios_domain_l,
1165 .user = &sAMAccountName_u,
1166 .realm = &netbios_domain_u,
1169 .user = &sAMAccountName,
1170 .realm = &netbios_domain_u,
1173 .user = &sAMAccountName,
1174 .realm = &netbios_domain_l,
1177 .user = &sAMAccountName_u,
1178 .realm = &netbios_domain_l,
1181 .user = &sAMAccountName_l,
1182 .realm = &netbios_domain_u,
1185 * sAMAccountName, dns_domain
1188 .user = &sAMAccountName,
1189 .realm = &dns_domain,
1192 .user = &sAMAccountName_l,
1193 .realm = &dns_domain_l,
1196 .user = &sAMAccountName_u,
1197 .realm = &dns_domain_u,
1200 .user = &sAMAccountName,
1201 .realm = &dns_domain_u,
1204 .user = &sAMAccountName,
1205 .realm = &dns_domain_l,
1208 .user = &sAMAccountName_u,
1209 .realm = &dns_domain_l,
1212 .user = &sAMAccountName_l,
1213 .realm = &dns_domain_u,
1216 * userPrincipalName, no realm
1219 .user = &userPrincipalName,
1223 * NOTE: w2k3 messes this up, if the user has a real userPrincipalName,
1224 * the fallback to the sAMAccountName based userPrincipalName is correct
1226 .user = &userPrincipalName_l,
1229 .user = &userPrincipalName_u,
1232 * nt4dom\sAMAccountName, no realm
1235 .user = &sAMAccountName,
1236 .nt4dom = &netbios_domain
1239 .user = &sAMAccountName_l,
1240 .nt4dom = &netbios_domain_l
1243 .user = &sAMAccountName_u,
1244 .nt4dom = &netbios_domain_u
1248 * the following ones are guessed depending on the technet2 article
1249 * but not reproducable on a w2k3 server
1251 /* sAMAccountName with "Digest" realm */
1253 .user = &sAMAccountName,
1257 .user = &sAMAccountName_l,
1261 .user = &sAMAccountName_u,
1264 /* userPrincipalName with "Digest" realm */
1266 .user = &userPrincipalName,
1270 .user = &userPrincipalName_l,
1274 .user = &userPrincipalName_u,
1277 /* nt4dom\\sAMAccountName with "Digest" realm */
1279 .user = &sAMAccountName,
1280 .nt4dom = &netbios_domain,
1284 .user = &sAMAccountName_l,
1285 .nt4dom = &netbios_domain_l,
1289 .user = &sAMAccountName_u,
1290 .nt4dom = &netbios_domain_u,
1295 /* prepare DATA_BLOB's used in the combinations array */
1296 sAMAccountName = data_blob_string_const(io->u.sAMAccountName);
1297 sAMAccountName_l = data_blob_string_const(strlower_talloc(io->ac, io->u.sAMAccountName));
1298 if (!sAMAccountName_l.data) {
1299 return ldb_oom(ldb);
1301 sAMAccountName_u = data_blob_string_const(strupper_talloc(io->ac, io->u.sAMAccountName));
1302 if (!sAMAccountName_u.data) {
1303 return ldb_oom(ldb);
1306 /* if the user doesn't have a userPrincipalName, create one (with lower case realm) */
1307 if (!user_principal_name) {
1308 user_principal_name = talloc_asprintf(io->ac, "%s@%s",
1309 io->u.sAMAccountName,
1310 io->ac->status->domain_data.dns_domain);
1311 if (!user_principal_name) {
1312 return ldb_oom(ldb);
1315 userPrincipalName = data_blob_string_const(user_principal_name);
1316 userPrincipalName_l = data_blob_string_const(strlower_talloc(io->ac, user_principal_name));
1317 if (!userPrincipalName_l.data) {
1318 return ldb_oom(ldb);
1320 userPrincipalName_u = data_blob_string_const(strupper_talloc(io->ac, user_principal_name));
1321 if (!userPrincipalName_u.data) {
1322 return ldb_oom(ldb);
1325 netbios_domain = data_blob_string_const(io->ac->status->domain_data.netbios_domain);
1326 netbios_domain_l = data_blob_string_const(strlower_talloc(io->ac,
1327 io->ac->status->domain_data.netbios_domain));
1328 if (!netbios_domain_l.data) {
1329 return ldb_oom(ldb);
1331 netbios_domain_u = data_blob_string_const(strupper_talloc(io->ac,
1332 io->ac->status->domain_data.netbios_domain));
1333 if (!netbios_domain_u.data) {
1334 return ldb_oom(ldb);
1337 dns_domain = data_blob_string_const(io->ac->status->domain_data.dns_domain);
1338 dns_domain_l = data_blob_string_const(io->ac->status->domain_data.dns_domain);
1339 dns_domain_u = data_blob_string_const(io->ac->status->domain_data.realm);
1341 digest = data_blob_string_const("Digest");
1343 delim = data_blob_string_const(":");
1344 backslash = data_blob_string_const("\\");
1346 pdb->num_hashes = ARRAY_SIZE(wdigest);
1347 pdb->hashes = talloc_array(io->ac, struct package_PrimaryWDigestHash,
1350 return ldb_oom(ldb);
1353 for (i=0; i < ARRAY_SIZE(wdigest); i++) {
1354 struct MD5Context md5;
1356 if (wdigest[i].nt4dom) {
1357 MD5Update(&md5, wdigest[i].nt4dom->data, wdigest[i].nt4dom->length);
1358 MD5Update(&md5, backslash.data, backslash.length);
1360 MD5Update(&md5, wdigest[i].user->data, wdigest[i].user->length);
1361 MD5Update(&md5, delim.data, delim.length);
1362 if (wdigest[i].realm) {
1363 MD5Update(&md5, wdigest[i].realm->data, wdigest[i].realm->length);
1365 MD5Update(&md5, delim.data, delim.length);
1366 MD5Update(&md5, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length);
1367 MD5Final(pdb->hashes[i].hash, &md5);
1373 static int setup_supplemental_field(struct setup_password_fields_io *io)
1375 struct ldb_context *ldb;
1376 struct supplementalCredentialsBlob scb;
1377 struct supplementalCredentialsBlob _old_scb;
1378 struct supplementalCredentialsBlob *old_scb = NULL;
1379 /* Packages + (Kerberos-Newer-Keys, Kerberos, WDigest and CLEARTEXT) */
1380 uint32_t num_names = 0;
1381 const char *names[1+4];
1382 uint32_t num_packages = 0;
1383 struct supplementalCredentialsPackage packages[1+4];
1385 struct supplementalCredentialsPackage *pp = NULL;
1386 struct package_PackagesBlob pb;
1389 /* Primary:Kerberos-Newer-Keys */
1390 const char **nkn = NULL;
1391 struct supplementalCredentialsPackage *pkn = NULL;
1392 struct package_PrimaryKerberosBlob pknb;
1393 DATA_BLOB pknb_blob;
1395 /* Primary:Kerberos */
1396 const char **nk = NULL;
1397 struct supplementalCredentialsPackage *pk = NULL;
1398 struct package_PrimaryKerberosBlob pkb;
1401 /* Primary:WDigest */
1402 const char **nd = NULL;
1403 struct supplementalCredentialsPackage *pd = NULL;
1404 struct package_PrimaryWDigestBlob pdb;
1407 /* Primary:CLEARTEXT */
1408 const char **nc = NULL;
1409 struct supplementalCredentialsPackage *pc = NULL;
1410 struct package_PrimaryCLEARTEXTBlob pcb;
1414 enum ndr_err_code ndr_err;
1416 bool do_newer_keys = false;
1417 bool do_cleartext = false;
1419 ZERO_STRUCT(zero16);
1422 ldb = ldb_module_get_ctx(io->ac->module);
1424 if (!io->n.cleartext_utf8) {
1426 * when we don't have a cleartext password
1427 * we can't setup a supplementalCredential value
1432 /* if there's an old supplementaCredentials blob then parse it */
1433 if (io->o.supplemental) {
1434 ndr_err = ndr_pull_struct_blob_all(io->o.supplemental, io->ac,
1436 (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
1437 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1438 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1439 ldb_asprintf_errstring(ldb,
1440 "setup_supplemental_field: "
1441 "failed to pull old supplementalCredentialsBlob: %s",
1443 return LDB_ERR_OPERATIONS_ERROR;
1446 if (_old_scb.sub.signature == SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
1447 old_scb = &_old_scb;
1449 ldb_debug(ldb, LDB_DEBUG_ERROR,
1450 "setup_supplemental_field: "
1451 "supplementalCredentialsBlob signature[0x%04X] expected[0x%04X]",
1452 _old_scb.sub.signature, SUPPLEMENTAL_CREDENTIALS_SIGNATURE);
1455 /* Per MS-SAMR 3.1.1.8.11.6 we create AES keys if our domain functionality level is 2008 or higher */
1456 do_newer_keys = (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008);
1458 if (io->ac->status->domain_data.store_cleartext &&
1459 (io->u.userAccountControl & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) {
1460 do_cleartext = true;
1464 * The ordering is this
1466 * Primary:Kerberos-Newer-Keys (optional)
1469 * Primary:CLEARTEXT (optional)
1471 * And the 'Packages' package is insert before the last
1474 if (do_newer_keys) {
1475 /* Primary:Kerberos-Newer-Keys */
1476 nkn = &names[num_names++];
1477 pkn = &packages[num_packages++];
1480 /* Primary:Kerberos */
1481 nk = &names[num_names++];
1482 pk = &packages[num_packages++];
1484 if (!do_cleartext) {
1486 pp = &packages[num_packages++];
1489 /* Primary:WDigest */
1490 nd = &names[num_names++];
1491 pd = &packages[num_packages++];
1495 pp = &packages[num_packages++];
1497 /* Primary:CLEARTEXT */
1498 nc = &names[num_names++];
1499 pc = &packages[num_packages++];
1504 * setup 'Primary:Kerberos-Newer-Keys' element
1506 *nkn = "Kerberos-Newer-Keys";
1508 ret = setup_primary_kerberos_newer(io, old_scb, &pknb);
1509 if (ret != LDB_SUCCESS) {
1513 ndr_err = ndr_push_struct_blob(&pknb_blob, io->ac,
1515 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1516 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1517 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1518 ldb_asprintf_errstring(ldb,
1519 "setup_supplemental_field: "
1520 "failed to push package_PrimaryKerberosNeverBlob: %s",
1522 return LDB_ERR_OPERATIONS_ERROR;
1524 pknb_hexstr = data_blob_hex_string_upper(io->ac, &pknb_blob);
1526 return ldb_oom(ldb);
1528 pkn->name = "Primary:Kerberos-Newer-Keys";
1530 pkn->data = pknb_hexstr;
1534 * setup 'Primary:Kerberos' element
1538 ret = setup_primary_kerberos(io, old_scb, &pkb);
1539 if (ret != LDB_SUCCESS) {
1543 ndr_err = ndr_push_struct_blob(&pkb_blob, io->ac,
1545 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1546 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1547 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1548 ldb_asprintf_errstring(ldb,
1549 "setup_supplemental_field: "
1550 "failed to push package_PrimaryKerberosBlob: %s",
1552 return LDB_ERR_OPERATIONS_ERROR;
1554 pkb_hexstr = data_blob_hex_string_upper(io->ac, &pkb_blob);
1556 return ldb_oom(ldb);
1558 pk->name = "Primary:Kerberos";
1560 pk->data = pkb_hexstr;
1563 * setup 'Primary:WDigest' element
1567 ret = setup_primary_wdigest(io, old_scb, &pdb);
1568 if (ret != LDB_SUCCESS) {
1572 ndr_err = ndr_push_struct_blob(&pdb_blob, io->ac,
1574 (ndr_push_flags_fn_t)ndr_push_package_PrimaryWDigestBlob);
1575 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1576 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1577 ldb_asprintf_errstring(ldb,
1578 "setup_supplemental_field: "
1579 "failed to push package_PrimaryWDigestBlob: %s",
1581 return LDB_ERR_OPERATIONS_ERROR;
1583 pdb_hexstr = data_blob_hex_string_upper(io->ac, &pdb_blob);
1585 return ldb_oom(ldb);
1587 pd->name = "Primary:WDigest";
1589 pd->data = pdb_hexstr;
1592 * setup 'Primary:CLEARTEXT' element
1597 pcb.cleartext = *io->n.cleartext_utf16;
1599 ndr_err = ndr_push_struct_blob(&pcb_blob, io->ac,
1601 (ndr_push_flags_fn_t)ndr_push_package_PrimaryCLEARTEXTBlob);
1602 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1603 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1604 ldb_asprintf_errstring(ldb,
1605 "setup_supplemental_field: "
1606 "failed to push package_PrimaryCLEARTEXTBlob: %s",
1608 return LDB_ERR_OPERATIONS_ERROR;
1610 pcb_hexstr = data_blob_hex_string_upper(io->ac, &pcb_blob);
1612 return ldb_oom(ldb);
1614 pc->name = "Primary:CLEARTEXT";
1616 pc->data = pcb_hexstr;
1620 * setup 'Packages' element
1623 ndr_err = ndr_push_struct_blob(&pb_blob, io->ac,
1625 (ndr_push_flags_fn_t)ndr_push_package_PackagesBlob);
1626 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1627 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1628 ldb_asprintf_errstring(ldb,
1629 "setup_supplemental_field: "
1630 "failed to push package_PackagesBlob: %s",
1632 return LDB_ERR_OPERATIONS_ERROR;
1634 pb_hexstr = data_blob_hex_string_upper(io->ac, &pb_blob);
1636 return ldb_oom(ldb);
1638 pp->name = "Packages";
1640 pp->data = pb_hexstr;
1643 * setup 'supplementalCredentials' value
1646 scb.sub.num_packages = num_packages;
1647 scb.sub.packages = packages;
1649 ndr_err = ndr_push_struct_blob(&io->g.supplemental, io->ac,
1651 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
1652 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1653 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1654 ldb_asprintf_errstring(ldb,
1655 "setup_supplemental_field: "
1656 "failed to push supplementalCredentialsBlob: %s",
1658 return LDB_ERR_OPERATIONS_ERROR;
1664 static int setup_last_set_field(struct setup_password_fields_io *io)
1667 unix_to_nt_time(&io->g.last_set, time(NULL));
1672 static int setup_given_passwords(struct setup_password_fields_io *io,
1673 struct setup_password_fields_given *g)
1675 struct ldb_context *ldb;
1678 ldb = ldb_module_get_ctx(io->ac->module);
1680 if (g->cleartext_utf8) {
1681 struct ldb_val *cleartext_utf16_blob;
1683 cleartext_utf16_blob = talloc(io->ac, struct ldb_val);
1684 if (!cleartext_utf16_blob) {
1685 return ldb_oom(ldb);
1687 if (!convert_string_talloc(io->ac,
1689 g->cleartext_utf8->data,
1690 g->cleartext_utf8->length,
1691 (void *)&cleartext_utf16_blob->data,
1692 &cleartext_utf16_blob->length,
1694 if (g->cleartext_utf8->length != 0) {
1695 talloc_free(cleartext_utf16_blob);
1696 ldb_asprintf_errstring(ldb,
1697 "setup_password_fields: "
1698 "failed to generate UTF16 password from cleartext UTF8 one for user '%s'!",
1699 io->u.sAMAccountName);
1700 return LDB_ERR_CONSTRAINT_VIOLATION;
1702 /* passwords with length "0" are valid! */
1703 cleartext_utf16_blob->data = NULL;
1704 cleartext_utf16_blob->length = 0;
1707 g->cleartext_utf16 = cleartext_utf16_blob;
1708 } else if (g->cleartext_utf16) {
1709 struct ldb_val *cleartext_utf8_blob;
1711 cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
1712 if (!cleartext_utf8_blob) {
1713 return ldb_oom(ldb);
1715 if (!convert_string_talloc(io->ac,
1716 CH_UTF16MUNGED, CH_UTF8,
1717 g->cleartext_utf16->data,
1718 g->cleartext_utf16->length,
1719 (void *)&cleartext_utf8_blob->data,
1720 &cleartext_utf8_blob->length,
1722 if (g->cleartext_utf16->length != 0) {
1723 /* We must bail out here, the input wasn't even
1724 * a multiple of 2 bytes */
1725 talloc_free(cleartext_utf8_blob);
1726 ldb_asprintf_errstring(ldb,
1727 "setup_password_fields: "
1728 "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)!",
1729 io->u.sAMAccountName);
1730 return LDB_ERR_CONSTRAINT_VIOLATION;
1732 /* passwords with length "0" are valid! */
1733 cleartext_utf8_blob->data = NULL;
1734 cleartext_utf8_blob->length = 0;
1737 g->cleartext_utf8 = cleartext_utf8_blob;
1740 if (g->cleartext_utf16) {
1741 struct samr_Password *nt_hash;
1743 nt_hash = talloc(io->ac, struct samr_Password);
1745 return ldb_oom(ldb);
1747 g->nt_hash = nt_hash;
1749 /* compute the new nt hash */
1750 mdfour(nt_hash->hash,
1751 g->cleartext_utf16->data,
1752 g->cleartext_utf16->length);
1755 if (g->cleartext_utf8) {
1756 struct samr_Password *lm_hash;
1758 lm_hash = talloc(io->ac, struct samr_Password);
1760 return ldb_oom(ldb);
1763 /* compute the new lm hash */
1764 ok = E_deshash((char *)g->cleartext_utf8->data, lm_hash->hash);
1766 g->lm_hash = lm_hash;
1768 talloc_free(lm_hash);
1775 static int setup_password_fields(struct setup_password_fields_io *io)
1777 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1778 struct loadparm_context *lp_ctx =
1779 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
1780 struct loadparm_context);
1783 /* transform the old password (for password changes) */
1784 ret = setup_given_passwords(io, &io->og);
1785 if (ret != LDB_SUCCESS) {
1789 /* transform the new password */
1790 ret = setup_given_passwords(io, &io->n);
1791 if (ret != LDB_SUCCESS) {
1795 if (io->n.cleartext_utf8) {
1796 ret = setup_kerberos_keys(io);
1797 if (ret != LDB_SUCCESS) {
1802 ret = setup_nt_fields(io);
1803 if (ret != LDB_SUCCESS) {
1807 if (lpcfg_lanman_auth(lp_ctx)) {
1808 ret = setup_lm_fields(io);
1809 if (ret != LDB_SUCCESS) {
1813 io->g.lm_hash = NULL;
1814 io->g.lm_history_len = 0;
1817 ret = setup_supplemental_field(io);
1818 if (ret != LDB_SUCCESS) {
1822 ret = setup_last_set_field(io);
1823 if (ret != LDB_SUCCESS) {
1830 static int check_password_restrictions(struct setup_password_fields_io *io)
1832 struct ldb_context *ldb;
1834 enum samr_ValidationStatus stat;
1836 ldb = ldb_module_get_ctx(io->ac->module);
1838 /* First check the old password is correct, for password changes */
1839 if (!io->ac->pwd_reset) {
1840 bool nt_hash_checked = false;
1842 /* we need the old nt or lm hash given by the client */
1843 if (!io->og.nt_hash && !io->og.lm_hash) {
1844 ldb_asprintf_errstring(ldb,
1845 "check_password_restrictions: "
1846 "You need to provide the old password in order "
1848 return LDB_ERR_UNWILLING_TO_PERFORM;
1851 /* The password modify through the NT hash is encouraged and
1852 has no problems at all */
1853 if (io->og.nt_hash) {
1854 if (!io->o.nt_hash) {
1855 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1856 ldb_asprintf_errstring(ldb,
1857 "%08X: %s - check_password_restrictions: "
1858 "There's no old nt_hash, which is needed "
1859 "in order to change your password!",
1860 W_ERROR_V(WERR_INVALID_PASSWORD),
1865 if (memcmp(io->og.nt_hash->hash, io->o.nt_hash->hash, 16) != 0) {
1866 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1867 ldb_asprintf_errstring(ldb,
1868 "%08X: %s - check_password_restrictions: "
1869 "The old password specified doesn't match!",
1870 W_ERROR_V(WERR_INVALID_PASSWORD),
1875 nt_hash_checked = true;
1878 /* But it is also possible to change a password by the LM hash
1879 * alone for compatibility reasons. This check is optional if
1880 * the NT hash was already checked - otherwise it's mandatory.
1881 * (as the SAMR operations request it). */
1882 if (io->og.lm_hash) {
1883 if (!io->o.lm_hash && !nt_hash_checked) {
1884 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1885 ldb_asprintf_errstring(ldb,
1886 "%08X: %s - check_password_restrictions: "
1887 "There's no old lm_hash, which is needed "
1888 "in order to change your password!",
1889 W_ERROR_V(WERR_INVALID_PASSWORD),
1894 if (io->o.lm_hash &&
1895 memcmp(io->og.lm_hash->hash, io->o.lm_hash->hash, 16) != 0) {
1896 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1897 ldb_asprintf_errstring(ldb,
1898 "%08X: %s - check_password_restrictions: "
1899 "The old password specified doesn't match!",
1900 W_ERROR_V(WERR_INVALID_PASSWORD),
1907 if (io->u.restrictions == 0) {
1908 /* FIXME: Is this right? */
1913 * Fundamental password checks done by the call
1914 * "samdb_check_password".
1915 * It is also in use by "dcesrv_samr_ValidatePassword".
1917 if (io->n.cleartext_utf8 != NULL) {
1918 stat = samdb_check_password(io->n.cleartext_utf8,
1919 io->ac->status->domain_data.pwdProperties,
1920 io->ac->status->domain_data.minPwdLength);
1922 case SAMR_VALIDATION_STATUS_SUCCESS:
1923 /* perfect -> proceed! */
1926 case SAMR_VALIDATION_STATUS_PWD_TOO_SHORT:
1927 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1928 ldb_asprintf_errstring(ldb,
1929 "%08X: %s - check_password_restrictions: "
1930 "the password is too short. It should be equal or longer than %u characters!",
1931 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
1933 io->ac->status->domain_data.minPwdLength);
1934 io->ac->status->reject_reason = SAM_PWD_CHANGE_PASSWORD_TOO_SHORT;
1937 case SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH:
1938 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1939 ldb_asprintf_errstring(ldb,
1940 "%08X: %s - check_password_restrictions: "
1941 "the password does not meet the complexity criterias!",
1942 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
1944 io->ac->status->reject_reason = SAM_PWD_CHANGE_NOT_COMPLEX;
1948 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1949 ldb_asprintf_errstring(ldb,
1950 "%08X: %s - check_password_restrictions: "
1951 "the password doesn't fit by a certain reason!",
1952 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
1958 if (io->ac->pwd_reset) {
1962 if (io->n.nt_hash) {
1965 /* checks the NT hash password history */
1966 for (i = 0; i < io->o.nt_history_len; i++) {
1967 ret = memcmp(io->n.nt_hash, io->o.nt_history[i].hash, 16);
1969 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1970 ldb_asprintf_errstring(ldb,
1971 "%08X: %s - check_password_restrictions: "
1972 "the password was already used (in history)!",
1973 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
1975 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
1981 if (io->n.lm_hash) {
1984 /* checks the LM hash password history */
1985 for (i = 0; i < io->o.lm_history_len; i++) {
1986 ret = memcmp(io->n.nt_hash, io->o.lm_history[i].hash, 16);
1988 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1989 ldb_asprintf_errstring(ldb,
1990 "%08X: %s - check_password_restrictions: "
1991 "the password was already used (in history)!",
1992 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
1994 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
2000 /* are all password changes disallowed? */
2001 if (io->ac->status->domain_data.pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
2002 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2003 ldb_asprintf_errstring(ldb,
2004 "%08X: %s - check_password_restrictions: "
2005 "password changes disabled!",
2006 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2011 /* can this user change the password? */
2012 if (io->u.userAccountControl & UF_PASSWD_CANT_CHANGE) {
2013 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2014 ldb_asprintf_errstring(ldb,
2015 "%08X: %s - check_password_restrictions: "
2016 "password can't be changed on this account!",
2017 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2022 /* Password minimum age: yes, this is a minus. The ages are in negative 100nsec units! */
2023 if (io->u.pwdLastSet - io->ac->status->domain_data.minPwdAge > io->g.last_set) {
2024 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2025 ldb_asprintf_errstring(ldb,
2026 "%08X: %s - check_password_restrictions: "
2027 "password is too young to change!",
2028 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2037 * This is intended for use by the "password_hash" module since there
2038 * password changes can be specified through one message element with the
2039 * new password (to set) and another one with the old password (to unset).
2041 * The first which sets a password (new value) can have flags
2042 * (LDB_FLAG_MOD_ADD, LDB_FLAG_MOD_REPLACE) but also none (on "add" operations
2043 * for entries). The latter (old value) has always specified
2044 * LDB_FLAG_MOD_DELETE.
2046 * Returns LDB_ERR_CONSTRAINT_VIOLATION and LDB_ERR_UNWILLING_TO_PERFORM if
2047 * matching message elements are malformed in respect to the set/change rules.
2048 * Otherwise it returns LDB_SUCCESS.
2050 static int msg_find_old_and_new_pwd_val(const struct ldb_message *msg,
2052 enum ldb_request_type operation,
2053 const struct ldb_val **new_val,
2054 const struct ldb_val **old_val)
2065 for (i = 0; i < msg->num_elements; i++) {
2066 if (ldb_attr_cmp(msg->elements[i].name, name) != 0) {
2070 if ((operation == LDB_MODIFY) &&
2071 (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_DELETE)) {
2072 /* 0 values are allowed */
2073 if (msg->elements[i].num_values == 1) {
2074 *old_val = &msg->elements[i].values[0];
2075 } else if (msg->elements[i].num_values > 1) {
2076 return LDB_ERR_CONSTRAINT_VIOLATION;
2078 } else if ((operation == LDB_MODIFY) &&
2079 (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_REPLACE)) {
2080 if (msg->elements[i].num_values > 0) {
2081 *new_val = &msg->elements[i].values[msg->elements[i].num_values - 1];
2083 return LDB_ERR_UNWILLING_TO_PERFORM;
2086 /* Add operations and LDB_FLAG_MOD_ADD */
2087 if (msg->elements[i].num_values > 0) {
2088 *new_val = &msg->elements[i].values[msg->elements[i].num_values - 1];
2090 return LDB_ERR_CONSTRAINT_VIOLATION;
2098 static int setup_io(struct ph_context *ac,
2099 const struct ldb_message *orig_msg,
2100 const struct ldb_message *searched_msg,
2101 struct setup_password_fields_io *io)
2103 const struct ldb_val *quoted_utf16, *old_quoted_utf16, *lm_hash, *old_lm_hash;
2104 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2105 struct loadparm_context *lp_ctx =
2106 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2107 struct loadparm_context);
2112 /* Some operations below require kerberos contexts */
2114 if (smb_krb5_init_context(ac,
2115 ldb_get_event_context(ldb),
2116 (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"),
2117 &io->smb_krb5_context) != 0) {
2118 return ldb_operr(ldb);
2123 io->u.userAccountControl = ldb_msg_find_attr_as_uint(searched_msg,
2124 "userAccountControl", 0);
2125 io->u.pwdLastSet = samdb_result_nttime(searched_msg, "pwdLastSet", 0);
2126 io->u.sAMAccountName = ldb_msg_find_attr_as_string(searched_msg,
2127 "sAMAccountName", NULL);
2128 io->u.user_principal_name = ldb_msg_find_attr_as_string(searched_msg,
2129 "userPrincipalName", NULL);
2130 io->u.is_computer = ldb_msg_check_string_attribute(searched_msg, "objectClass", "computer");
2132 if (io->u.sAMAccountName == NULL) {
2133 ldb_asprintf_errstring(ldb,
2134 "setup_io: sAMAccountName attribute is missing on %s for attempted password set/change",
2135 ldb_dn_get_linearized(searched_msg->dn));
2137 return LDB_ERR_CONSTRAINT_VIOLATION;
2140 /* Only non-trust accounts have restrictions (possibly this test is the
2141 * wrong way around, but we like to be restrictive if possible */
2142 io->u.restrictions = !(io->u.userAccountControl
2143 & (UF_INTERDOMAIN_TRUST_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT
2144 | UF_SERVER_TRUST_ACCOUNT));
2146 if ((io->u.userAccountControl & UF_PASSWD_NOTREQD) != 0) {
2147 /* see [MS-ADTS] 2.2.15 */
2148 io->u.restrictions = 0;
2151 if (ac->userPassword) {
2152 ret = msg_find_old_and_new_pwd_val(orig_msg, "userPassword",
2154 &io->n.cleartext_utf8,
2155 &io->og.cleartext_utf8);
2156 if (ret != LDB_SUCCESS) {
2157 ldb_asprintf_errstring(ldb,
2159 "it's only allowed to set the old password once!");
2164 ret = msg_find_old_and_new_pwd_val(orig_msg, "clearTextPassword",
2166 &io->n.cleartext_utf16,
2167 &io->og.cleartext_utf16);
2168 if (ret != LDB_SUCCESS) {
2169 ldb_asprintf_errstring(ldb,
2171 "it's only allowed to set the old password once!");
2175 /* this rather strange looking piece of code is there to
2176 handle a ldap client setting a password remotely using the
2177 unicodePwd ldap field. The syntax is that the password is
2178 in UTF-16LE, with a " at either end. Unfortunately the
2179 unicodePwd field is also used to store the nt hashes
2180 internally in Samba, and is used in the nt hash format on
2181 the wire in DRS replication, so we have a single name for
2182 two distinct values. The code below leaves us with a small
2183 chance (less than 1 in 2^32) of a mixup, if someone manages
2184 to create a MD4 hash which starts and ends in 0x22 0x00, as
2185 that would then be treated as a UTF16 password rather than
2188 ret = msg_find_old_and_new_pwd_val(orig_msg, "unicodePwd",
2192 if (ret != LDB_SUCCESS) {
2193 ldb_asprintf_errstring(ldb,
2195 "it's only allowed to set the old password once!");
2199 /* Checks and converts the actual "unicodePwd" attribute */
2201 quoted_utf16->length >= 4 &&
2202 quoted_utf16->data[0] == '"' &&
2203 quoted_utf16->data[1] == 0 &&
2204 quoted_utf16->data[quoted_utf16->length-2] == '"' &&
2205 quoted_utf16->data[quoted_utf16->length-1] == 0) {
2206 struct ldb_val *quoted_utf16_2;
2208 if (io->n.cleartext_utf16) {
2209 /* refuse the change if someone wants to change with
2210 with both UTF16 possibilities at the same time... */
2211 ldb_asprintf_errstring(ldb,
2213 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
2214 return LDB_ERR_UNWILLING_TO_PERFORM;
2218 * adapt the quoted UTF16 string to be a real
2221 quoted_utf16_2 = talloc(io->ac, struct ldb_val);
2222 if (quoted_utf16_2 == NULL) {
2223 return ldb_oom(ldb);
2226 quoted_utf16_2->data = quoted_utf16->data + 2;
2227 quoted_utf16_2->length = quoted_utf16->length-4;
2228 io->n.cleartext_utf16 = quoted_utf16_2;
2229 io->n.nt_hash = NULL;
2231 } else if (quoted_utf16) {
2232 /* We have only the hash available -> so no plaintext here */
2233 if (!ac->hash_values) {
2234 /* refuse the change if someone wants to change
2235 the hash without control specified... */
2236 ldb_asprintf_errstring(ldb,
2238 "it's not allowed to set the NT hash password directly'");
2239 /* this looks odd but this is what Windows does:
2240 returns "UNWILLING_TO_PERFORM" on wrong
2241 password sets and "CONSTRAINT_VIOLATION" on
2242 wrong password changes. */
2243 if (old_quoted_utf16 == NULL) {
2244 return LDB_ERR_UNWILLING_TO_PERFORM;
2247 return LDB_ERR_CONSTRAINT_VIOLATION;
2250 io->n.nt_hash = talloc(io->ac, struct samr_Password);
2251 memcpy(io->n.nt_hash->hash, quoted_utf16->data,
2252 MIN(quoted_utf16->length, sizeof(io->n.nt_hash->hash)));
2255 /* Checks and converts the previous "unicodePwd" attribute */
2256 if (old_quoted_utf16 &&
2257 old_quoted_utf16->length >= 4 &&
2258 old_quoted_utf16->data[0] == '"' &&
2259 old_quoted_utf16->data[1] == 0 &&
2260 old_quoted_utf16->data[old_quoted_utf16->length-2] == '"' &&
2261 old_quoted_utf16->data[old_quoted_utf16->length-1] == 0) {
2262 struct ldb_val *old_quoted_utf16_2;
2264 if (io->og.cleartext_utf16) {
2265 /* refuse the change if someone wants to change with
2266 both UTF16 possibilities at the same time... */
2267 ldb_asprintf_errstring(ldb,
2269 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
2270 return LDB_ERR_UNWILLING_TO_PERFORM;
2274 * adapt the quoted UTF16 string to be a real
2277 old_quoted_utf16_2 = talloc(io->ac, struct ldb_val);
2278 if (old_quoted_utf16_2 == NULL) {
2279 return ldb_oom(ldb);
2282 old_quoted_utf16_2->data = old_quoted_utf16->data + 2;
2283 old_quoted_utf16_2->length = old_quoted_utf16->length-4;
2285 io->og.cleartext_utf16 = old_quoted_utf16_2;
2286 io->og.nt_hash = NULL;
2287 } else if (old_quoted_utf16) {
2288 /* We have only the hash available -> so no plaintext here */
2289 if (!ac->hash_values) {
2290 /* refuse the change if someone wants to change
2291 the hash without control specified... */
2292 ldb_asprintf_errstring(ldb,
2294 "it's not allowed to set the NT hash password directly'");
2295 return LDB_ERR_UNWILLING_TO_PERFORM;
2298 io->og.nt_hash = talloc(io->ac, struct samr_Password);
2299 memcpy(io->og.nt_hash->hash, old_quoted_utf16->data,
2300 MIN(old_quoted_utf16->length, sizeof(io->og.nt_hash->hash)));
2303 /* Handles the "dBCSPwd" attribute (LM hash) */
2304 io->n.lm_hash = NULL; io->og.lm_hash = NULL;
2305 ret = msg_find_old_and_new_pwd_val(orig_msg, "dBCSPwd",
2307 &lm_hash, &old_lm_hash);
2308 if (ret != LDB_SUCCESS) {
2309 ldb_asprintf_errstring(ldb,
2311 "it's only allowed to set the old password once!");
2315 if (((lm_hash != NULL) || (old_lm_hash != NULL)) && (!ac->hash_values)) {
2316 /* refuse the change if someone wants to change the hash
2317 without control specified... */
2318 ldb_asprintf_errstring(ldb,
2320 "it's not allowed to set the LM hash password directly'");
2321 return LDB_ERR_UNWILLING_TO_PERFORM;
2324 if (lpcfg_lanman_auth(lp_ctx) && (lm_hash != NULL)) {
2325 io->n.lm_hash = talloc(io->ac, struct samr_Password);
2326 memcpy(io->n.lm_hash->hash, lm_hash->data, MIN(lm_hash->length,
2327 sizeof(io->n.lm_hash->hash)));
2329 if (lpcfg_lanman_auth(lp_ctx) && (old_lm_hash != NULL)) {
2330 io->og.lm_hash = talloc(io->ac, struct samr_Password);
2331 memcpy(io->og.lm_hash->hash, old_lm_hash->data, MIN(old_lm_hash->length,
2332 sizeof(io->og.lm_hash->hash)));
2336 * Handles the password change control if it's specified. It has the
2337 * precedance and overrides already specified old password values of
2338 * change requests (but that shouldn't happen since the control is
2339 * fully internal and only used in conjunction with replace requests!).
2341 if (ac->change != NULL) {
2342 io->og.nt_hash = NULL;
2343 if (ac->change->old_nt_pwd_hash != NULL) {
2344 io->og.nt_hash = talloc_memdup(io->ac,
2345 ac->change->old_nt_pwd_hash,
2346 sizeof(struct samr_Password));
2348 io->og.lm_hash = NULL;
2349 if (lpcfg_lanman_auth(lp_ctx) && (ac->change->old_lm_pwd_hash != NULL)) {
2350 io->og.lm_hash = talloc_memdup(io->ac,
2351 ac->change->old_lm_pwd_hash,
2352 sizeof(struct samr_Password));
2356 /* refuse the change if someone wants to change the clear-
2357 text and supply his own hashes at the same time... */
2358 if ((io->n.cleartext_utf8 || io->n.cleartext_utf16)
2359 && (io->n.nt_hash || io->n.lm_hash)) {
2360 ldb_asprintf_errstring(ldb,
2362 "it's only allowed to set the password in form of cleartext attributes or as hashes");
2363 return LDB_ERR_UNWILLING_TO_PERFORM;
2366 /* refuse the change if someone wants to change the password
2367 using both plaintext methods (UTF8 and UTF16) at the same time... */
2368 if (io->n.cleartext_utf8 && io->n.cleartext_utf16) {
2369 ldb_asprintf_errstring(ldb,
2371 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
2372 return LDB_ERR_UNWILLING_TO_PERFORM;
2375 /* refuse the change if someone tries to set/change the password by
2376 * the lanman hash alone and we've deactivated that mechanism. This
2377 * would end in an account without any password! */
2378 if ((!io->n.cleartext_utf8) && (!io->n.cleartext_utf16)
2379 && (!io->n.nt_hash) && (!io->n.lm_hash)) {
2380 ldb_asprintf_errstring(ldb,
2382 "It' not possible to delete the password (changes using the LAN Manager hash alone could be deactivated)!");
2383 /* on "userPassword" and "clearTextPassword" we've to return
2384 * something different, since these are virtual attributes */
2385 if ((ldb_msg_find_element(orig_msg, "userPassword") != NULL) ||
2386 (ldb_msg_find_element(orig_msg, "clearTextPassword") != NULL)) {
2387 return LDB_ERR_CONSTRAINT_VIOLATION;
2389 return LDB_ERR_UNWILLING_TO_PERFORM;
2392 /* refuse the change if someone wants to compare against a plaintext
2393 or hash at the same time for a "password modify" operation... */
2394 if ((io->og.cleartext_utf8 || io->og.cleartext_utf16)
2395 && (io->og.nt_hash || io->og.lm_hash)) {
2396 ldb_asprintf_errstring(ldb,
2398 "it's only allowed to provide the old password in form of cleartext attributes or as hashes");
2399 return LDB_ERR_UNWILLING_TO_PERFORM;
2402 /* refuse the change if someone wants to compare against both
2403 * plaintexts at the same time for a "password modify" operation... */
2404 if (io->og.cleartext_utf8 && io->og.cleartext_utf16) {
2405 ldb_asprintf_errstring(ldb,
2407 "it's only allowed to provide the old cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
2408 return LDB_ERR_UNWILLING_TO_PERFORM;
2411 /* Decides if we have a password modify or password reset operation */
2412 if (ac->req->operation == LDB_ADD) {
2413 /* On "add" we have only "password reset" */
2414 ac->pwd_reset = true;
2415 } else if (ac->req->operation == LDB_MODIFY) {
2416 if (io->og.cleartext_utf8 || io->og.cleartext_utf16
2417 || io->og.nt_hash || io->og.lm_hash) {
2418 /* If we have an old password specified then for sure it
2419 * is a user "password change" */
2420 ac->pwd_reset = false;
2422 /* Otherwise we have also here a "password reset" */
2423 ac->pwd_reset = true;
2426 /* this shouldn't happen */
2427 return ldb_operr(ldb);
2433 static struct ph_context *ph_init_context(struct ldb_module *module,
2434 struct ldb_request *req,
2437 struct ldb_context *ldb;
2438 struct ph_context *ac;
2440 ldb = ldb_module_get_ctx(module);
2442 ac = talloc_zero(req, struct ph_context);
2444 ldb_set_errstring(ldb, "Out of Memory");
2448 ac->module = module;
2450 ac->userPassword = userPassword;
2455 static void ph_apply_controls(struct ph_context *ac)
2457 struct ldb_control *ctrl;
2459 ac->change_status = false;
2460 ctrl = ldb_request_get_control(ac->req,
2461 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID);
2463 ac->change_status = true;
2465 /* Mark the "change status" control as uncritical (done) */
2466 ctrl->critical = false;
2469 ac->hash_values = false;
2470 ctrl = ldb_request_get_control(ac->req,
2471 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID);
2473 ac->hash_values = true;
2475 /* Mark the "hash values" control as uncritical (done) */
2476 ctrl->critical = false;
2479 ctrl = ldb_request_get_control(ac->req,
2480 DSDB_CONTROL_PASSWORD_CHANGE_OID);
2482 ac->change = (struct dsdb_control_password_change *) ctrl->data;
2484 /* Mark the "change" control as uncritical (done) */
2485 ctrl->critical = false;
2489 static int ph_op_callback(struct ldb_request *req, struct ldb_reply *ares)
2491 struct ph_context *ac;
2493 ac = talloc_get_type(req->context, struct ph_context);
2496 return ldb_module_done(ac->req, NULL, NULL,
2497 LDB_ERR_OPERATIONS_ERROR);
2500 if (ares->type == LDB_REPLY_REFERRAL) {
2501 return ldb_module_send_referral(ac->req, ares->referral);
2504 if ((ares->error != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
2505 /* On success and trivial errors a status control is being
2506 * added (used for example by the "samdb_set_password" call) */
2507 ldb_reply_add_control(ares,
2508 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2513 if (ares->error != LDB_SUCCESS) {
2514 return ldb_module_done(ac->req, ares->controls,
2515 ares->response, ares->error);
2518 if (ares->type != LDB_REPLY_DONE) {
2520 return ldb_module_done(ac->req, NULL, NULL,
2521 LDB_ERR_OPERATIONS_ERROR);
2524 return ldb_module_done(ac->req, ares->controls,
2525 ares->response, ares->error);
2528 static int password_hash_add_do_add(struct ph_context *ac);
2529 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares);
2530 static int password_hash_mod_search_self(struct ph_context *ac);
2531 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares);
2532 static int password_hash_mod_do_mod(struct ph_context *ac);
2534 static int get_domain_data_callback(struct ldb_request *req,
2535 struct ldb_reply *ares)
2537 struct ldb_context *ldb;
2538 struct ph_context *ac;
2539 struct loadparm_context *lp_ctx;
2542 ac = talloc_get_type(req->context, struct ph_context);
2543 ldb = ldb_module_get_ctx(ac->module);
2546 ret = LDB_ERR_OPERATIONS_ERROR;
2549 if (ares->error != LDB_SUCCESS) {
2550 return ldb_module_done(ac->req, ares->controls,
2551 ares->response, ares->error);
2554 switch (ares->type) {
2555 case LDB_REPLY_ENTRY:
2556 if (ac->status != NULL) {
2559 ldb_set_errstring(ldb, "Too many results");
2560 ret = LDB_ERR_OPERATIONS_ERROR;
2564 /* Setup the "status" structure (used as control later) */
2565 ac->status = talloc_zero(ac->req,
2566 struct dsdb_control_password_change_status);
2567 if (ac->status == NULL) {
2571 ret = LDB_ERR_OPERATIONS_ERROR;
2575 /* Setup the "domain data" structure */
2576 ac->status->domain_data.pwdProperties =
2577 ldb_msg_find_attr_as_uint(ares->message, "pwdProperties", -1);
2578 ac->status->domain_data.pwdHistoryLength =
2579 ldb_msg_find_attr_as_uint(ares->message, "pwdHistoryLength", -1);
2580 ac->status->domain_data.maxPwdAge =
2581 ldb_msg_find_attr_as_int64(ares->message, "maxPwdAge", -1);
2582 ac->status->domain_data.minPwdAge =
2583 ldb_msg_find_attr_as_int64(ares->message, "minPwdAge", -1);
2584 ac->status->domain_data.minPwdLength =
2585 ldb_msg_find_attr_as_uint(ares->message, "minPwdLength", -1);
2586 ac->status->domain_data.store_cleartext =
2587 ac->status->domain_data.pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
2591 /* For a domain DN, this puts things in dotted notation */
2592 /* For builtin domains, this will give details for the host,
2593 * but that doesn't really matter, as it's just used for salt
2594 * and kerberos principals, which don't exist here */
2596 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2597 struct loadparm_context);
2599 ac->status->domain_data.dns_domain = lpcfg_dnsdomain(lp_ctx);
2600 ac->status->domain_data.realm = lpcfg_realm(lp_ctx);
2601 ac->status->domain_data.netbios_domain = lpcfg_sam_name(lp_ctx);
2603 ac->status->reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2608 case LDB_REPLY_REFERRAL:
2614 case LDB_REPLY_DONE:
2616 /* call the next step */
2617 switch (ac->req->operation) {
2619 ret = password_hash_add_do_add(ac);
2623 ret = password_hash_mod_do_mod(ac);
2627 ret = LDB_ERR_OPERATIONS_ERROR;
2634 if (ret != LDB_SUCCESS) {
2635 struct ldb_reply *new_ares;
2637 new_ares = talloc_zero(ac->req, struct ldb_reply);
2638 if (new_ares == NULL) {
2640 return ldb_module_done(ac->req, NULL, NULL,
2641 LDB_ERR_OPERATIONS_ERROR);
2644 new_ares->error = ret;
2645 if ((ret != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
2646 /* On success and trivial errors a status control is being
2647 * added (used for example by the "samdb_set_password" call) */
2648 ldb_reply_add_control(new_ares,
2649 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2654 return ldb_module_done(ac->req, new_ares->controls,
2655 new_ares->response, new_ares->error);
2661 static int build_domain_data_request(struct ph_context *ac)
2663 /* attrs[] is returned from this function in
2664 ac->dom_req->op.search.attrs, so it must be static, as
2665 otherwise the compiler can put it on the stack */
2666 struct ldb_context *ldb;
2667 static const char * const attrs[] = { "pwdProperties",
2675 ldb = ldb_module_get_ctx(ac->module);
2677 ret = ldb_build_search_req(&ac->dom_req, ldb, ac,
2678 ldb_get_default_basedn(ldb),
2682 ac, get_domain_data_callback,
2684 LDB_REQ_SET_LOCATION(ac->dom_req);
2688 static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
2690 struct ldb_context *ldb;
2691 struct ph_context *ac;
2692 struct ldb_message_element *userPasswordAttr, *clearTextPasswordAttr,
2695 struct ldb_control *bypass = NULL;
2696 bool userPassword = dsdb_user_password_support(module, req);
2698 ldb = ldb_module_get_ctx(module);
2700 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add\n");
2702 if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
2703 return ldb_next_request(module, req);
2706 /* If the caller is manipulating the local passwords directly, let them pass */
2707 if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
2708 req->op.add.message->dn) == 0) {
2709 return ldb_next_request(module, req);
2712 bypass = ldb_request_get_control(req,
2713 DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID);
2714 if (bypass != NULL) {
2715 /* Mark the "bypass" control as uncritical (done) */
2716 bypass->critical = false;
2717 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add (bypassing)\n");
2718 return password_hash_bypass(module, req);
2721 /* nobody must touch password histories and 'supplementalCredentials' */
2722 if (ldb_msg_find_element(req->op.add.message, "ntPwdHistory")) {
2723 return LDB_ERR_UNWILLING_TO_PERFORM;
2725 if (ldb_msg_find_element(req->op.add.message, "lmPwdHistory")) {
2726 return LDB_ERR_UNWILLING_TO_PERFORM;
2728 if (ldb_msg_find_element(req->op.add.message, "supplementalCredentials")) {
2729 return LDB_ERR_UNWILLING_TO_PERFORM;
2732 /* If no part of this touches the 'userPassword' OR 'clearTextPassword'
2733 * OR 'unicodePwd' OR 'dBCSPwd' we don't need to make any changes. */
2735 userPasswordAttr = NULL;
2737 userPasswordAttr = ldb_msg_find_element(req->op.add.message,
2739 /* MS-ADTS 3.1.1.3.1.5.2 */
2740 if ((userPasswordAttr != NULL) &&
2741 (dsdb_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
2742 return LDB_ERR_CONSTRAINT_VIOLATION;
2745 clearTextPasswordAttr = ldb_msg_find_element(req->op.add.message, "clearTextPassword");
2746 ntAttr = ldb_msg_find_element(req->op.add.message, "unicodePwd");
2747 lmAttr = ldb_msg_find_element(req->op.add.message, "dBCSPwd");
2749 if ((!userPasswordAttr) && (!clearTextPasswordAttr) && (!ntAttr) && (!lmAttr)) {
2750 return ldb_next_request(module, req);
2753 /* Make sure we are performing the password set action on a (for us)
2754 * valid object. Those are instances of either "user" and/or
2755 * "inetOrgPerson". Otherwise continue with the submodules. */
2756 if ((!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "user"))
2757 && (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "inetOrgPerson"))) {
2759 if (ldb_msg_find_element(req->op.add.message, "clearTextPassword") != NULL) {
2760 ldb_set_errstring(ldb,
2761 "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
2762 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2765 return ldb_next_request(module, req);
2768 ac = ph_init_context(module, req, userPassword);
2770 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
2771 return ldb_operr(ldb);
2773 ph_apply_controls(ac);
2775 /* get user domain data */
2776 ret = build_domain_data_request(ac);
2777 if (ret != LDB_SUCCESS) {
2781 return ldb_next_request(module, ac->dom_req);
2784 static int password_hash_add_do_add(struct ph_context *ac)
2786 struct ldb_context *ldb;
2787 struct ldb_request *down_req;
2788 struct ldb_message *msg;
2789 struct setup_password_fields_io io;
2792 /* Prepare the internal data structure containing the passwords */
2793 ret = setup_io(ac, ac->req->op.add.message, ac->req->op.add.message, &io);
2794 if (ret != LDB_SUCCESS) {
2798 ldb = ldb_module_get_ctx(ac->module);
2800 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
2802 return ldb_operr(ldb);
2805 /* remove attributes that we just read into 'io' */
2806 if (ac->userPassword) {
2807 ldb_msg_remove_attr(msg, "userPassword");
2809 ldb_msg_remove_attr(msg, "clearTextPassword");
2810 ldb_msg_remove_attr(msg, "unicodePwd");
2811 ldb_msg_remove_attr(msg, "dBCSPwd");
2812 ldb_msg_remove_attr(msg, "pwdLastSet");
2814 ret = setup_password_fields(&io);
2815 if (ret != LDB_SUCCESS) {
2819 ret = check_password_restrictions(&io);
2820 if (ret != LDB_SUCCESS) {
2825 ret = samdb_msg_add_hash(ldb, ac, msg,
2826 "unicodePwd", io.g.nt_hash);
2827 if (ret != LDB_SUCCESS) {
2832 ret = samdb_msg_add_hash(ldb, ac, msg,
2833 "dBCSPwd", io.g.lm_hash);
2834 if (ret != LDB_SUCCESS) {
2838 if (io.g.nt_history_len > 0) {
2839 ret = samdb_msg_add_hashes(ldb, ac, msg,
2842 io.g.nt_history_len);
2843 if (ret != LDB_SUCCESS) {
2847 if (io.g.lm_history_len > 0) {
2848 ret = samdb_msg_add_hashes(ldb, ac, msg,
2851 io.g.lm_history_len);
2852 if (ret != LDB_SUCCESS) {
2856 if (io.g.supplemental.length > 0) {
2857 ret = ldb_msg_add_value(msg, "supplementalCredentials",
2858 &io.g.supplemental, NULL);
2859 if (ret != LDB_SUCCESS) {
2863 ret = samdb_msg_add_uint64(ldb, ac, msg,
2866 if (ret != LDB_SUCCESS) {
2870 ret = ldb_build_add_req(&down_req, ldb, ac,
2875 LDB_REQ_SET_LOCATION(down_req);
2876 if (ret != LDB_SUCCESS) {
2880 return ldb_next_request(ac->module, down_req);
2883 static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
2885 struct ldb_context *ldb;
2886 struct ph_context *ac;
2887 const char *passwordAttrs[] = { "userPassword", "clearTextPassword",
2888 "unicodePwd", "dBCSPwd", NULL }, **l;
2889 unsigned int attr_cnt, del_attr_cnt, add_attr_cnt, rep_attr_cnt;
2890 struct ldb_message_element *passwordAttr;
2891 struct ldb_message *msg;
2892 struct ldb_request *down_req;
2894 struct ldb_control *bypass = NULL;
2895 bool userPassword = dsdb_user_password_support(module, req);
2897 ldb = ldb_module_get_ctx(module);
2899 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
2901 if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
2902 return ldb_next_request(module, req);
2905 /* If the caller is manipulating the local passwords directly, let them pass */
2906 if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
2907 req->op.mod.message->dn) == 0) {
2908 return ldb_next_request(module, req);
2911 bypass = ldb_request_get_control(req,
2912 DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID);
2913 if (bypass != NULL) {
2914 /* Mark the "bypass" control as uncritical (done) */
2915 bypass->critical = false;
2916 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify (bypassing)\n");
2917 return password_hash_bypass(module, req);
2920 /* nobody must touch password histories and 'supplementalCredentials' */
2921 if (ldb_msg_find_element(req->op.mod.message, "ntPwdHistory")) {
2922 return LDB_ERR_UNWILLING_TO_PERFORM;
2924 if (ldb_msg_find_element(req->op.mod.message, "lmPwdHistory")) {
2925 return LDB_ERR_UNWILLING_TO_PERFORM;
2927 if (ldb_msg_find_element(req->op.mod.message, "supplementalCredentials")) {
2928 return LDB_ERR_UNWILLING_TO_PERFORM;
2931 /* If no part of this touches the 'userPassword' OR 'clearTextPassword'
2932 * OR 'unicodePwd' OR 'dBCSPwd' we don't need to make any changes.
2933 * For password changes/set there should be a 'delete' or a 'modify'
2934 * on these attributes. */
2936 for (l = passwordAttrs; *l != NULL; l++) {
2937 if ((!userPassword) && (ldb_attr_cmp(*l, "userPassword") == 0)) {
2941 if (ldb_msg_find_element(req->op.mod.message, *l) != NULL) {
2942 /* MS-ADTS 3.1.1.3.1.5.2 */
2943 if ((ldb_attr_cmp(*l, "userPassword") == 0) &&
2944 (dsdb_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
2945 return LDB_ERR_CONSTRAINT_VIOLATION;
2951 if (attr_cnt == 0) {
2952 return ldb_next_request(module, req);
2955 ac = ph_init_context(module, req, userPassword);
2957 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
2958 return ldb_operr(ldb);
2960 ph_apply_controls(ac);
2962 /* use a new message structure so that we can modify it */
2963 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2965 return ldb_oom(ldb);
2968 /* - check for single-valued password attributes
2969 * (if not return "CONSTRAINT_VIOLATION")
2970 * - check that for a password change operation one add and one delete
2972 * (if not return "CONSTRAINT_VIOLATION" or "UNWILLING_TO_PERFORM")
2973 * - check that a password change and a password set operation cannot
2975 * (if not return "UNWILLING_TO_PERFORM")
2976 * - remove all password attributes modifications from the first change
2977 * operation (anything without the passwords) - we will make the real
2978 * modification later */
2982 for (l = passwordAttrs; *l != NULL; l++) {
2983 if ((!ac->userPassword) &&
2984 (ldb_attr_cmp(*l, "userPassword") == 0)) {
2988 while ((passwordAttr = ldb_msg_find_element(msg, *l)) != NULL) {
2989 if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_DELETE) {
2992 if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_ADD) {
2995 if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_REPLACE) {
2998 if ((passwordAttr->num_values != 1) &&
2999 (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_ADD)) {
3001 ldb_asprintf_errstring(ldb,
3002 "'%s' attribute must have exactly one value on add operations!",
3004 return LDB_ERR_CONSTRAINT_VIOLATION;
3006 if ((passwordAttr->num_values > 1) &&
3007 (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_DELETE)) {
3009 ldb_asprintf_errstring(ldb,
3010 "'%s' attribute must have zero or one value(s) on delete operations!",
3012 return LDB_ERR_CONSTRAINT_VIOLATION;
3014 ldb_msg_remove_element(msg, passwordAttr);
3017 if ((del_attr_cnt == 0) && (add_attr_cnt > 0)) {
3019 ldb_set_errstring(ldb,
3020 "Only the add action for a password change specified!");
3021 return LDB_ERR_UNWILLING_TO_PERFORM;
3023 if ((del_attr_cnt > 1) || (add_attr_cnt > 1)) {
3025 ldb_set_errstring(ldb,
3026 "Only one delete and one add action for a password change allowed!");
3027 return LDB_ERR_UNWILLING_TO_PERFORM;
3029 if ((rep_attr_cnt > 0) && ((del_attr_cnt > 0) || (add_attr_cnt > 0))) {
3031 ldb_set_errstring(ldb,
3032 "Either a password change or a password set operation is allowed!");
3033 return LDB_ERR_UNWILLING_TO_PERFORM;
3036 /* if there was nothing else to be modified skip to next step */
3037 if (msg->num_elements == 0) {
3038 return password_hash_mod_search_self(ac);
3041 ret = ldb_build_mod_req(&down_req, ldb, ac,
3044 ac, ph_modify_callback,
3046 LDB_REQ_SET_LOCATION(down_req);
3047 if (ret != LDB_SUCCESS) {
3051 return ldb_next_request(module, down_req);
3054 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
3056 struct ph_context *ac;
3058 ac = talloc_get_type(req->context, struct ph_context);
3061 return ldb_module_done(ac->req, NULL, NULL,
3062 LDB_ERR_OPERATIONS_ERROR);
3065 if (ares->type == LDB_REPLY_REFERRAL) {
3066 return ldb_module_send_referral(ac->req, ares->referral);
3069 if (ares->error != LDB_SUCCESS) {
3070 return ldb_module_done(ac->req, ares->controls,
3071 ares->response, ares->error);
3074 if (ares->type != LDB_REPLY_DONE) {
3076 return ldb_module_done(ac->req, NULL, NULL,
3077 LDB_ERR_OPERATIONS_ERROR);
3082 return password_hash_mod_search_self(ac);
3085 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
3087 struct ldb_context *ldb;
3088 struct ph_context *ac;
3091 ac = talloc_get_type(req->context, struct ph_context);
3092 ldb = ldb_module_get_ctx(ac->module);
3095 ret = LDB_ERR_OPERATIONS_ERROR;
3098 if (ares->error != LDB_SUCCESS) {
3099 return ldb_module_done(ac->req, ares->controls,
3100 ares->response, ares->error);
3103 /* we are interested only in the single reply (base search) */
3104 switch (ares->type) {
3105 case LDB_REPLY_ENTRY:
3106 /* Make sure we are performing the password change action on a
3107 * (for us) valid object. Those are instances of either "user"
3108 * and/or "inetOrgPerson". Otherwise continue with the
3110 if ((!ldb_msg_check_string_attribute(ares->message, "objectClass", "user"))
3111 && (!ldb_msg_check_string_attribute(ares->message, "objectClass", "inetOrgPerson"))) {
3114 if (ldb_msg_find_element(ac->req->op.mod.message, "clearTextPassword") != NULL) {
3115 ldb_set_errstring(ldb,
3116 "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
3117 ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
3121 ret = ldb_next_request(ac->module, ac->req);
3125 if (ac->search_res != NULL) {
3128 ldb_set_errstring(ldb, "Too many results");
3129 ret = LDB_ERR_OPERATIONS_ERROR;
3133 ac->search_res = talloc_steal(ac, ares);
3137 case LDB_REPLY_REFERRAL:
3138 /* ignore anything else for now */
3143 case LDB_REPLY_DONE:
3146 /* get user domain data */
3147 ret = build_domain_data_request(ac);
3148 if (ret != LDB_SUCCESS) {
3149 return ldb_module_done(ac->req, NULL, NULL, ret);
3152 ret = ldb_next_request(ac->module, ac->dom_req);
3157 if (ret != LDB_SUCCESS) {
3158 return ldb_module_done(ac->req, NULL, NULL, ret);
3164 static int password_hash_mod_search_self(struct ph_context *ac)
3166 struct ldb_context *ldb;
3167 static const char * const attrs[] = { "objectClass",
3168 "userAccountControl",
3172 "userPrincipalName",
3173 "supplementalCredentials",
3179 struct ldb_request *search_req;
3182 ldb = ldb_module_get_ctx(ac->module);
3184 ret = ldb_build_search_req(&search_req, ldb, ac,
3185 ac->req->op.mod.message->dn,
3190 ac, ph_mod_search_callback,
3192 LDB_REQ_SET_LOCATION(search_req);
3193 if (ret != LDB_SUCCESS) {
3197 return ldb_next_request(ac->module, search_req);
3200 static int password_hash_mod_do_mod(struct ph_context *ac)
3202 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3203 struct loadparm_context *lp_ctx =
3204 talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3205 struct loadparm_context);
3206 struct ldb_request *mod_req;
3207 struct ldb_message *msg;
3208 const struct ldb_message *orig_msg, *searched_msg;
3209 struct setup_password_fields_io io;
3213 /* use a new message structure so that we can modify it */
3214 msg = ldb_msg_new(ac);
3216 return ldb_operr(ldb);
3220 msg->dn = ac->req->op.mod.message->dn;
3222 orig_msg = ac->req->op.mod.message;
3223 searched_msg = ac->search_res->message;
3225 /* Prepare the internal data structure containing the passwords */
3226 ret = setup_io(ac, orig_msg, searched_msg, &io);
3227 if (ret != LDB_SUCCESS) {
3231 /* Get the old password from the database */
3232 status = samdb_result_passwords(io.ac,
3234 discard_const_p(struct ldb_message, searched_msg),
3235 &io.o.lm_hash, &io.o.nt_hash);
3236 if (!NT_STATUS_IS_OK(status)) {
3237 return ldb_operr(ldb);
3240 io.o.nt_history_len = samdb_result_hashes(io.ac, searched_msg, "ntPwdHistory", &io.o.nt_history);
3241 io.o.lm_history_len = samdb_result_hashes(io.ac, searched_msg, "lmPwdHistory", &io.o.lm_history);
3242 io.o.supplemental = ldb_msg_find_ldb_val(searched_msg, "supplementalCredentials");
3244 ret = setup_password_fields(&io);
3245 if (ret != LDB_SUCCESS) {
3249 ret = check_password_restrictions(&io);
3250 if (ret != LDB_SUCCESS) {
3254 /* make sure we replace all the old attributes */
3255 ret = ldb_msg_add_empty(msg, "unicodePwd", LDB_FLAG_MOD_REPLACE, NULL);
3256 ret = ldb_msg_add_empty(msg, "dBCSPwd", LDB_FLAG_MOD_REPLACE, NULL);
3257 ret = ldb_msg_add_empty(msg, "ntPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
3258 ret = ldb_msg_add_empty(msg, "lmPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
3259 ret = ldb_msg_add_empty(msg, "supplementalCredentials", LDB_FLAG_MOD_REPLACE, NULL);
3260 ret = ldb_msg_add_empty(msg, "pwdLastSet", LDB_FLAG_MOD_REPLACE, NULL);
3263 ret = samdb_msg_add_hash(ldb, ac, msg,
3264 "unicodePwd", io.g.nt_hash);
3265 if (ret != LDB_SUCCESS) {
3270 ret = samdb_msg_add_hash(ldb, ac, msg,
3271 "dBCSPwd", io.g.lm_hash);
3272 if (ret != LDB_SUCCESS) {
3276 if (io.g.nt_history_len > 0) {
3277 ret = samdb_msg_add_hashes(ldb, ac, msg,
3280 io.g.nt_history_len);
3281 if (ret != LDB_SUCCESS) {
3285 if (io.g.lm_history_len > 0) {
3286 ret = samdb_msg_add_hashes(ldb, ac, msg,
3289 io.g.lm_history_len);
3290 if (ret != LDB_SUCCESS) {
3294 if (io.g.supplemental.length > 0) {
3295 ret = ldb_msg_add_value(msg, "supplementalCredentials",
3296 &io.g.supplemental, NULL);
3297 if (ret != LDB_SUCCESS) {
3301 ret = samdb_msg_add_uint64(ldb, ac, msg,
3304 if (ret != LDB_SUCCESS) {
3308 ret = ldb_build_mod_req(&mod_req, ldb, ac,
3313 LDB_REQ_SET_LOCATION(mod_req);
3314 if (ret != LDB_SUCCESS) {
3318 return ldb_next_request(ac->module, mod_req);
3321 static const struct ldb_module_ops ldb_password_hash_module_ops = {
3322 .name = "password_hash",
3323 .add = password_hash_add,
3324 .modify = password_hash_modify
3327 int ldb_password_hash_module_init(const char *version)
3329 LDB_MODULE_CHECK_VERSION(version);
3330 return ldb_register_module(&ldb_password_hash_module_ops);