dsdb: Allow special chars like "@" in samAccountName when generating the salt
[Samba.git] / source4 / dsdb / samdb / ldb_modules / password_hash.c
blob7ecf8c4304051dd974a379bcae07c64a1154c417
1 /*
2 ldb database module
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/>.
25 * Name: ldb
27 * Component: ldb password_hash module
29 * Description: correctly handle AD password changes fields
31 * Author: Andrew Bartlett
32 * Author: Stefan Metzmacher
35 #include "includes.h"
36 #include "ldb_module.h"
37 #include "libcli/auth/libcli_auth.h"
38 #include "libcli/security/dom_sid.h"
39 #include "system/kerberos.h"
40 #include "auth/kerberos/kerberos.h"
41 #include "dsdb/samdb/samdb.h"
42 #include "dsdb/samdb/ldb_modules/util.h"
43 #include "dsdb/samdb/ldb_modules/password_modules.h"
44 #include "librpc/gen_ndr/ndr_drsblobs.h"
45 #include "lib/crypto/md4.h"
46 #include "param/param.h"
47 #include "lib/krb5_wrap/krb5_samba.h"
48 #include "auth/common_auth.h"
49 #include "lib/messaging/messaging.h"
50 #include "lib/param/loadparm.h"
52 #include "lib/crypto/gnutls_helpers.h"
53 #include <gnutls/crypto.h>
55 #ifdef ENABLE_GPGME
56 #undef class
57 #include <gpgme.h>
60 * 1.2.0 is what dpkg-shlibdeps generates, based on used symbols and
61 * libgpgme11.symbols
62 * https://salsa.debian.org/debian/gpgme/blob/debian/master/debian/libgpgme11.symbols
65 #define MINIMUM_GPGME_VERSION "1.2.0"
66 #endif
68 #undef strncasecmp
69 #undef strcasecmp
71 /* If we have decided there is a reason to work on this request, then
72 * setup all the password hash types correctly.
74 * If we haven't the hashes yet but the password given as plain-text (attributes
75 * 'unicodePwd', 'userPassword' and 'clearTextPassword') we have to check for
76 * the constraints. Once this is done, we calculate the password hashes.
78 * Notice: unlike the real AD which only supports the UTF16 special based
79 * 'unicodePwd' and the UTF8 based 'userPassword' plaintext attribute we
80 * understand also a UTF16 based 'clearTextPassword' one.
81 * The latter is also accessible through LDAP so it can also be set by external
82 * tools and scripts. But be aware that this isn't portable on non SAMBA 4 ADs!
84 * Also when the module receives only the password hashes (possible through
85 * specifying an internal LDB control - for security reasons) some checks are
86 * performed depending on the operation mode (see below) (e.g. if the password
87 * has been in use before if the password memory policy was activated).
89 * Attention: There is a difference between "modify" and "reset" operations
90 * (see MS-ADTS 3.1.1.3.1.5). If the client sends a "add" and "remove"
91 * operation for a password attribute we thread this as a "modify"; if it sends
92 * only a "replace" one we have an (administrative) reset.
94 * Finally, if the administrator has requested that a password history
95 * be maintained, then this should also be written out.
99 /* TODO: [consider always MS-ADTS 3.1.1.3.1.5]
100 * - Check for right connection encryption
103 /* Notice: Definition of "dsdb_control_password_change_status" moved into
104 * "samdb.h" */
106 struct ph_context {
107 struct ldb_module *module;
108 struct ldb_request *req;
110 struct ldb_request *dom_req;
111 struct ldb_reply *dom_res;
113 struct ldb_reply *pso_res;
115 struct ldb_reply *search_res;
117 struct ldb_message *update_msg;
119 struct dsdb_control_password_change_status *status;
120 struct dsdb_control_password_change *change;
122 const char **gpg_key_ids;
124 bool pwd_reset;
125 bool change_status;
126 bool hash_values;
127 bool userPassword;
128 bool update_password;
129 bool update_lastset;
130 bool pwd_last_set_bypass;
131 bool pwd_last_set_default;
132 bool smartcard_reset;
133 const char **userPassword_schemes;
137 struct setup_password_fields_io {
138 struct ph_context *ac;
140 struct smb_krb5_context *smb_krb5_context;
142 /* info about the user account */
143 struct {
144 uint32_t userAccountControl;
145 NTTIME pwdLastSet;
146 const char *sAMAccountName;
147 const char *user_principal_name;
148 const char *displayName; /* full name */
149 bool is_krbtgt;
150 uint32_t restrictions;
151 struct dom_sid *account_sid;
152 } u;
154 /* new credentials and old given credentials */
155 struct setup_password_fields_given {
156 const struct ldb_val *cleartext_utf8;
157 const struct ldb_val *cleartext_utf16;
158 struct samr_Password *nt_hash;
159 struct samr_Password *lm_hash;
160 } n, og;
162 /* old credentials */
163 struct {
164 struct samr_Password *nt_hash;
165 struct samr_Password *lm_hash;
166 uint32_t nt_history_len;
167 struct samr_Password *nt_history;
168 uint32_t lm_history_len;
169 struct samr_Password *lm_history;
170 const struct ldb_val *supplemental;
171 struct supplementalCredentialsBlob scb;
172 } o;
174 /* generated credentials */
175 struct {
176 struct samr_Password *nt_hash;
177 struct samr_Password *lm_hash;
178 uint32_t nt_history_len;
179 struct samr_Password *nt_history;
180 uint32_t lm_history_len;
181 struct samr_Password *lm_history;
182 const char *salt;
183 DATA_BLOB aes_256;
184 DATA_BLOB aes_128;
185 DATA_BLOB des_md5;
186 DATA_BLOB des_crc;
187 struct ldb_val supplemental;
188 NTTIME last_set;
189 } g;
192 static int msg_find_old_and_new_pwd_val(const struct ldb_message *msg,
193 const char *name,
194 enum ldb_request_type operation,
195 const struct ldb_val **new_val,
196 const struct ldb_val **old_val);
198 static int password_hash_bypass(struct ldb_module *module, struct ldb_request *request)
200 struct ldb_context *ldb = ldb_module_get_ctx(module);
201 const struct ldb_message *msg;
202 struct ldb_message_element *nte;
203 struct ldb_message_element *lme;
204 struct ldb_message_element *nthe;
205 struct ldb_message_element *lmhe;
206 struct ldb_message_element *sce;
208 switch (request->operation) {
209 case LDB_ADD:
210 msg = request->op.add.message;
211 break;
212 case LDB_MODIFY:
213 msg = request->op.mod.message;
214 break;
215 default:
216 return ldb_next_request(module, request);
219 /* nobody must touch password histories and 'supplementalCredentials' */
220 nte = dsdb_get_single_valued_attr(msg, "unicodePwd",
221 request->operation);
222 lme = dsdb_get_single_valued_attr(msg, "dBCSPwd",
223 request->operation);
224 nthe = dsdb_get_single_valued_attr(msg, "ntPwdHistory",
225 request->operation);
226 lmhe = dsdb_get_single_valued_attr(msg, "lmPwdHistory",
227 request->operation);
228 sce = dsdb_get_single_valued_attr(msg, "supplementalCredentials",
229 request->operation);
231 #define CHECK_HASH_ELEMENT(e, min, max) do {\
232 if (e && e->num_values) { \
233 unsigned int _count; \
234 if (e->num_values != 1) { \
235 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
236 "num_values != 1"); \
238 if ((e->values[0].length % 16) != 0) { \
239 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
240 "length % 16 != 0"); \
242 _count = e->values[0].length / 16; \
243 if (_count < min) { \
244 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
245 "count < min"); \
247 if (_count > max) { \
248 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
249 "count > max"); \
252 } while (0)
254 CHECK_HASH_ELEMENT(nte, 1, 1);
255 CHECK_HASH_ELEMENT(lme, 1, 1);
256 CHECK_HASH_ELEMENT(nthe, 1, INT32_MAX);
257 CHECK_HASH_ELEMENT(lmhe, 1, INT32_MAX);
259 if (sce && sce->num_values) {
260 enum ndr_err_code ndr_err;
261 struct supplementalCredentialsBlob *scb;
262 struct supplementalCredentialsPackage *scpp = NULL;
263 struct supplementalCredentialsPackage *scpk = NULL;
264 struct supplementalCredentialsPackage *scpkn = NULL;
265 struct supplementalCredentialsPackage *scpct = NULL;
266 DATA_BLOB scpbp = data_blob_null;
267 DATA_BLOB scpbk = data_blob_null;
268 DATA_BLOB scpbkn = data_blob_null;
269 DATA_BLOB scpbct = data_blob_null;
270 DATA_BLOB blob;
271 uint32_t i;
273 if (sce->num_values != 1) {
274 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
275 "num_values != 1");
278 scb = talloc_zero(request, struct supplementalCredentialsBlob);
279 if (!scb) {
280 return ldb_module_oom(module);
283 ndr_err = ndr_pull_struct_blob_all(&sce->values[0], scb, scb,
284 (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
285 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
286 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
287 "ndr_pull_struct_blob_all");
290 if (scb->sub.num_packages < 2) {
291 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
292 "num_packages < 2");
295 for (i=0; i < scb->sub.num_packages; i++) {
296 DATA_BLOB subblob;
298 subblob = strhex_to_data_blob(scb, scb->sub.packages[i].data);
299 if (subblob.data == NULL) {
300 return ldb_module_oom(module);
303 if (strcmp(scb->sub.packages[i].name, "Packages") == 0) {
304 if (scpp) {
305 return ldb_error(ldb,
306 LDB_ERR_CONSTRAINT_VIOLATION,
307 "Packages twice");
309 scpp = &scb->sub.packages[i];
310 scpbp = subblob;
311 continue;
313 if (strcmp(scb->sub.packages[i].name, "Primary:Kerberos") == 0) {
314 if (scpk) {
315 return ldb_error(ldb,
316 LDB_ERR_CONSTRAINT_VIOLATION,
317 "Primary:Kerberos twice");
319 scpk = &scb->sub.packages[i];
320 scpbk = subblob;
321 continue;
323 if (strcmp(scb->sub.packages[i].name, "Primary:Kerberos-Newer-Keys") == 0) {
324 if (scpkn) {
325 return ldb_error(ldb,
326 LDB_ERR_CONSTRAINT_VIOLATION,
327 "Primary:Kerberos-Newer-Keys twice");
329 scpkn = &scb->sub.packages[i];
330 scpbkn = subblob;
331 continue;
333 if (strcmp(scb->sub.packages[i].name, "Primary:CLEARTEXT") == 0) {
334 if (scpct) {
335 return ldb_error(ldb,
336 LDB_ERR_CONSTRAINT_VIOLATION,
337 "Primary:CLEARTEXT twice");
339 scpct = &scb->sub.packages[i];
340 scpbct = subblob;
341 continue;
344 data_blob_free(&subblob);
347 if (scpp == NULL) {
348 return ldb_error(ldb,
349 LDB_ERR_CONSTRAINT_VIOLATION,
350 "Primary:Packages missing");
353 if (scpk == NULL) {
355 * If Primary:Kerberos is missing w2k8r2 reboots
356 * when a password is changed.
358 return ldb_error(ldb,
359 LDB_ERR_CONSTRAINT_VIOLATION,
360 "Primary:Kerberos missing");
363 if (scpp) {
364 struct package_PackagesBlob *p;
365 uint32_t n;
367 p = talloc_zero(scb, struct package_PackagesBlob);
368 if (p == NULL) {
369 return ldb_module_oom(module);
372 ndr_err = ndr_pull_struct_blob(&scpbp, p, p,
373 (ndr_pull_flags_fn_t)ndr_pull_package_PackagesBlob);
374 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
375 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
376 "ndr_pull_struct_blob Packages");
379 if (p->names == NULL) {
380 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
381 "Packages names == NULL");
384 for (n = 0; p->names[n]; n++) {
385 /* noop */
388 if (scb->sub.num_packages != (n + 1)) {
389 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
390 "Packages num_packages != num_names + 1");
393 talloc_free(p);
396 if (scpk) {
397 struct package_PrimaryKerberosBlob *k;
399 k = talloc_zero(scb, struct package_PrimaryKerberosBlob);
400 if (k == NULL) {
401 return ldb_module_oom(module);
404 ndr_err = ndr_pull_struct_blob(&scpbk, k, k,
405 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
406 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
407 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
408 "ndr_pull_struct_blob PrimaryKerberos");
411 if (k->version != 3) {
412 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
413 "PrimaryKerberos version != 3");
416 if (k->ctr.ctr3.salt.string == NULL) {
417 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
418 "PrimaryKerberos salt == NULL");
421 if (strlen(k->ctr.ctr3.salt.string) == 0) {
422 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
423 "PrimaryKerberos strlen(salt) == 0");
426 if (k->ctr.ctr3.num_keys != 2) {
427 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
428 "PrimaryKerberos num_keys != 2");
431 if (k->ctr.ctr3.num_old_keys > k->ctr.ctr3.num_keys) {
432 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
433 "PrimaryKerberos num_old_keys > num_keys");
436 if (k->ctr.ctr3.keys[0].keytype != ENCTYPE_DES_CBC_MD5) {
437 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
438 "PrimaryKerberos key[0] != DES_CBC_MD5");
440 if (k->ctr.ctr3.keys[1].keytype != ENCTYPE_DES_CBC_CRC) {
441 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
442 "PrimaryKerberos key[1] != DES_CBC_CRC");
445 if (k->ctr.ctr3.keys[0].value_len != 8) {
446 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
447 "PrimaryKerberos key[0] value_len != 8");
449 if (k->ctr.ctr3.keys[1].value_len != 8) {
450 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
451 "PrimaryKerberos key[1] value_len != 8");
454 for (i = 0; i < k->ctr.ctr3.num_old_keys; i++) {
455 if (k->ctr.ctr3.old_keys[i].keytype ==
456 k->ctr.ctr3.keys[i].keytype &&
457 k->ctr.ctr3.old_keys[i].value_len ==
458 k->ctr.ctr3.keys[i].value_len) {
459 continue;
462 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
463 "PrimaryKerberos old_keys type/value_len doesn't match");
466 talloc_free(k);
469 if (scpkn) {
470 struct package_PrimaryKerberosBlob *k;
472 k = talloc_zero(scb, struct package_PrimaryKerberosBlob);
473 if (k == NULL) {
474 return ldb_module_oom(module);
477 ndr_err = ndr_pull_struct_blob(&scpbkn, k, k,
478 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
479 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
480 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
481 "ndr_pull_struct_blob PrimaryKerberosNeverKeys");
484 if (k->version != 4) {
485 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
486 "KerberosNerverKeys version != 4");
489 if (k->ctr.ctr4.salt.string == NULL) {
490 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
491 "KerberosNewerKeys salt == NULL");
494 if (strlen(k->ctr.ctr4.salt.string) == 0) {
495 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
496 "KerberosNewerKeys strlen(salt) == 0");
499 if (k->ctr.ctr4.num_keys != 4) {
500 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
501 "KerberosNewerKeys num_keys != 2");
504 if (k->ctr.ctr4.num_old_keys > k->ctr.ctr4.num_keys) {
505 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
506 "KerberosNewerKeys num_old_keys > num_keys");
509 if (k->ctr.ctr4.num_older_keys > k->ctr.ctr4.num_old_keys) {
510 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
511 "KerberosNewerKeys num_older_keys > num_old_keys");
514 if (k->ctr.ctr4.keys[0].keytype != ENCTYPE_AES256_CTS_HMAC_SHA1_96) {
515 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
516 "KerberosNewerKeys key[0] != AES256");
518 if (k->ctr.ctr4.keys[1].keytype != ENCTYPE_AES128_CTS_HMAC_SHA1_96) {
519 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
520 "KerberosNewerKeys key[1] != AES128");
522 if (k->ctr.ctr4.keys[2].keytype != ENCTYPE_DES_CBC_MD5) {
523 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
524 "KerberosNewerKeys key[2] != DES_CBC_MD5");
526 if (k->ctr.ctr4.keys[3].keytype != ENCTYPE_DES_CBC_CRC) {
527 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
528 "KerberosNewerKeys key[3] != DES_CBC_CRC");
531 if (k->ctr.ctr4.keys[0].value_len != 32) {
532 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
533 "KerberosNewerKeys key[0] value_len != 32");
535 if (k->ctr.ctr4.keys[1].value_len != 16) {
536 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
537 "KerberosNewerKeys key[1] value_len != 16");
539 if (k->ctr.ctr4.keys[2].value_len != 8) {
540 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
541 "KerberosNewerKeys key[2] value_len != 8");
543 if (k->ctr.ctr4.keys[3].value_len != 8) {
544 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
545 "KerberosNewerKeys key[3] value_len != 8");
549 * TODO:
550 * Maybe we can check old and older keys here.
551 * But we need to do some tests, if the old keys
552 * can be taken from the PrimaryKerberos blob
553 * (with only des keys), when the domain was upgraded
554 * from w2k3 to w2k8.
557 talloc_free(k);
560 if (scpct) {
561 struct package_PrimaryCLEARTEXTBlob *ct;
563 ct = talloc_zero(scb, struct package_PrimaryCLEARTEXTBlob);
564 if (ct == NULL) {
565 return ldb_module_oom(module);
568 ndr_err = ndr_pull_struct_blob(&scpbct, ct, ct,
569 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryCLEARTEXTBlob);
570 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
571 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
572 "ndr_pull_struct_blob PrimaryCLEARTEXT");
575 if ((ct->cleartext.length % 2) != 0) {
576 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
577 "PrimaryCLEARTEXT length % 2 != 0");
580 talloc_free(ct);
583 ndr_err = ndr_push_struct_blob(&blob, scb, scb,
584 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
585 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
586 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
587 "ndr_pull_struct_blob_all");
590 if (sce->values[0].length != blob.length) {
591 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
592 "supplementalCredentialsBlob length differ");
595 if (memcmp(sce->values[0].data, blob.data, blob.length) != 0) {
596 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
597 "supplementalCredentialsBlob memcmp differ");
600 talloc_free(scb);
603 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_bypass - validated\n");
604 return ldb_next_request(module, request);
607 /* Get the NT hash, and fill it in as an entry in the password history,
608 and specify it into io->g.nt_hash */
610 static int setup_nt_fields(struct setup_password_fields_io *io)
612 struct ldb_context *ldb;
613 uint32_t i;
615 io->g.nt_hash = io->n.nt_hash;
616 ldb = ldb_module_get_ctx(io->ac->module);
618 if (io->ac->status->domain_data.pwdHistoryLength == 0) {
619 return LDB_SUCCESS;
622 /* We might not have an old NT password */
623 io->g.nt_history = talloc_array(io->ac,
624 struct samr_Password,
625 io->ac->status->domain_data.pwdHistoryLength);
626 if (!io->g.nt_history) {
627 return ldb_oom(ldb);
630 for (i = 0; i < MIN(io->ac->status->domain_data.pwdHistoryLength-1,
631 io->o.nt_history_len); i++) {
632 io->g.nt_history[i+1] = io->o.nt_history[i];
634 io->g.nt_history_len = i + 1;
636 if (io->g.nt_hash) {
637 io->g.nt_history[0] = *io->g.nt_hash;
638 } else {
640 * TODO: is this correct?
641 * the simular behavior is correct for the lm history case
643 E_md4hash("", io->g.nt_history[0].hash);
646 return LDB_SUCCESS;
649 /* Get the LANMAN hash, and fill it in as an entry in the password history,
650 and specify it into io->g.lm_hash */
652 static int setup_lm_fields(struct setup_password_fields_io *io)
654 struct ldb_context *ldb;
655 uint32_t i;
657 io->g.lm_hash = io->n.lm_hash;
658 ldb = ldb_module_get_ctx(io->ac->module);
660 if (io->ac->status->domain_data.pwdHistoryLength == 0) {
661 return LDB_SUCCESS;
664 /* We might not have an old LM password */
665 io->g.lm_history = talloc_array(io->ac,
666 struct samr_Password,
667 io->ac->status->domain_data.pwdHistoryLength);
668 if (!io->g.lm_history) {
669 return ldb_oom(ldb);
672 for (i = 0; i < MIN(io->ac->status->domain_data.pwdHistoryLength-1,
673 io->o.lm_history_len); i++) {
674 io->g.lm_history[i+1] = io->o.lm_history[i];
676 io->g.lm_history_len = i + 1;
678 if (io->g.lm_hash) {
679 io->g.lm_history[0] = *io->g.lm_hash;
680 } else {
681 E_deshash("", io->g.lm_history[0].hash);
684 return LDB_SUCCESS;
687 static int setup_kerberos_keys(struct setup_password_fields_io *io)
689 struct ldb_context *ldb;
690 krb5_error_code krb5_ret;
691 krb5_principal salt_principal = NULL;
692 krb5_data salt_data;
693 krb5_data salt;
694 krb5_keyblock key;
695 krb5_data cleartext_data;
696 uint32_t uac_flags = 0;
698 ldb = ldb_module_get_ctx(io->ac->module);
699 cleartext_data.data = (char *)io->n.cleartext_utf8->data;
700 cleartext_data.length = io->n.cleartext_utf8->length;
702 uac_flags = io->u.userAccountControl & UF_ACCOUNT_TYPE_MASK;
703 krb5_ret = smb_krb5_salt_principal(io->smb_krb5_context->krb5_context,
704 io->ac->status->domain_data.realm,
705 io->u.sAMAccountName,
706 io->u.user_principal_name,
707 uac_flags,
708 &salt_principal);
709 if (krb5_ret) {
710 ldb_asprintf_errstring(ldb,
711 "setup_kerberos_keys: "
712 "generation of a salting principal failed: %s",
713 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
714 krb5_ret, io->ac));
715 return LDB_ERR_OPERATIONS_ERROR;
719 * create salt from salt_principal
721 krb5_ret = smb_krb5_get_pw_salt(io->smb_krb5_context->krb5_context,
722 salt_principal, &salt_data);
724 krb5_free_principal(io->smb_krb5_context->krb5_context, salt_principal);
725 if (krb5_ret) {
726 ldb_asprintf_errstring(ldb,
727 "setup_kerberos_keys: "
728 "generation of krb5_salt failed: %s",
729 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
730 krb5_ret, io->ac));
731 return LDB_ERR_OPERATIONS_ERROR;
734 /* now use the talloced copy of the salt */
735 salt.data = talloc_strndup(io->ac,
736 (char *)salt_data.data,
737 salt_data.length);
738 io->g.salt = salt.data;
739 salt.length = strlen(io->g.salt);
741 smb_krb5_free_data_contents(io->smb_krb5_context->krb5_context,
742 &salt_data);
745 * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of
746 * the salt and the cleartext password
748 krb5_ret = smb_krb5_create_key_from_string(io->smb_krb5_context->krb5_context,
749 NULL,
750 &salt,
751 &cleartext_data,
752 ENCTYPE_AES256_CTS_HMAC_SHA1_96,
753 &key);
754 if (krb5_ret) {
755 ldb_asprintf_errstring(ldb,
756 "setup_kerberos_keys: "
757 "generation of a aes256-cts-hmac-sha1-96 key failed: %s",
758 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
759 krb5_ret, io->ac));
760 return LDB_ERR_OPERATIONS_ERROR;
762 io->g.aes_256 = data_blob_talloc(io->ac,
763 KRB5_KEY_DATA(&key),
764 KRB5_KEY_LENGTH(&key));
765 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
766 if (!io->g.aes_256.data) {
767 return ldb_oom(ldb);
771 * create ENCTYPE_AES128_CTS_HMAC_SHA1_96 key out of
772 * the salt and the cleartext password
774 krb5_ret = smb_krb5_create_key_from_string(io->smb_krb5_context->krb5_context,
775 NULL,
776 &salt,
777 &cleartext_data,
778 ENCTYPE_AES128_CTS_HMAC_SHA1_96,
779 &key);
780 if (krb5_ret) {
781 ldb_asprintf_errstring(ldb,
782 "setup_kerberos_keys: "
783 "generation of a aes128-cts-hmac-sha1-96 key failed: %s",
784 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
785 krb5_ret, io->ac));
786 return LDB_ERR_OPERATIONS_ERROR;
788 io->g.aes_128 = data_blob_talloc(io->ac,
789 KRB5_KEY_DATA(&key),
790 KRB5_KEY_LENGTH(&key));
791 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
792 if (!io->g.aes_128.data) {
793 return ldb_oom(ldb);
797 * As per RFC-6649 single DES encryption types are no longer considered
798 * secure to be used in Kerberos, we store random keys instead of the
799 * ENCTYPE_DES_CBC_MD5 and ENCTYPE_DES_CBC_CRC keys.
801 io->g.des_md5 = data_blob_talloc(io->ac, NULL, 8);
802 if (!io->g.des_md5.data) {
803 return ldb_oom(ldb);
805 generate_secret_buffer(io->g.des_md5.data, 8);
807 io->g.des_crc = data_blob_talloc(io->ac, NULL, 8);
808 if (!io->g.des_crc.data) {
809 return ldb_oom(ldb);
811 generate_secret_buffer(io->g.des_crc.data, 8);
813 return LDB_SUCCESS;
816 static int setup_primary_kerberos(struct setup_password_fields_io *io,
817 const struct supplementalCredentialsBlob *old_scb,
818 struct package_PrimaryKerberosBlob *pkb)
820 struct ldb_context *ldb;
821 struct package_PrimaryKerberosCtr3 *pkb3 = &pkb->ctr.ctr3;
822 struct supplementalCredentialsPackage *old_scp = NULL;
823 struct package_PrimaryKerberosBlob _old_pkb;
824 struct package_PrimaryKerberosCtr3 *old_pkb3 = NULL;
825 uint32_t i;
826 enum ndr_err_code ndr_err;
828 ldb = ldb_module_get_ctx(io->ac->module);
831 * prepare generation of keys
833 * ENCTYPE_DES_CBC_MD5
834 * ENCTYPE_DES_CBC_CRC
836 pkb->version = 3;
837 pkb3->salt.string = io->g.salt;
838 pkb3->num_keys = 2;
839 pkb3->keys = talloc_array(io->ac,
840 struct package_PrimaryKerberosKey3,
841 pkb3->num_keys);
842 if (!pkb3->keys) {
843 return ldb_oom(ldb);
846 pkb3->keys[0].keytype = ENCTYPE_DES_CBC_MD5;
847 pkb3->keys[0].value = &io->g.des_md5;
848 pkb3->keys[1].keytype = ENCTYPE_DES_CBC_CRC;
849 pkb3->keys[1].value = &io->g.des_crc;
851 /* initialize the old keys to zero */
852 pkb3->num_old_keys = 0;
853 pkb3->old_keys = NULL;
855 /* if there're no old keys, then we're done */
856 if (!old_scb) {
857 return LDB_SUCCESS;
860 for (i=0; i < old_scb->sub.num_packages; i++) {
861 if (strcmp("Primary:Kerberos", old_scb->sub.packages[i].name) != 0) {
862 continue;
865 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
866 continue;
869 old_scp = &old_scb->sub.packages[i];
870 break;
872 /* Primary:Kerberos element of supplementalCredentials */
873 if (old_scp) {
874 DATA_BLOB blob;
876 blob = strhex_to_data_blob(io->ac, old_scp->data);
877 if (!blob.data) {
878 return ldb_oom(ldb);
881 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
882 ndr_err = ndr_pull_struct_blob(&blob, io->ac, &_old_pkb,
883 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
884 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
885 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
886 ldb_asprintf_errstring(ldb,
887 "setup_primary_kerberos: "
888 "failed to pull old package_PrimaryKerberosBlob: %s",
889 nt_errstr(status));
890 return LDB_ERR_OPERATIONS_ERROR;
893 if (_old_pkb.version != 3) {
894 ldb_asprintf_errstring(ldb,
895 "setup_primary_kerberos: "
896 "package_PrimaryKerberosBlob version[%u] expected[3]",
897 _old_pkb.version);
898 return LDB_ERR_OPERATIONS_ERROR;
901 old_pkb3 = &_old_pkb.ctr.ctr3;
904 /* if we didn't found the old keys we're done */
905 if (!old_pkb3) {
906 return LDB_SUCCESS;
909 /* fill in the old keys */
910 pkb3->num_old_keys = old_pkb3->num_keys;
911 pkb3->old_keys = old_pkb3->keys;
913 return LDB_SUCCESS;
916 static int setup_primary_kerberos_newer(struct setup_password_fields_io *io,
917 const struct supplementalCredentialsBlob *old_scb,
918 struct package_PrimaryKerberosBlob *pkb)
920 struct ldb_context *ldb;
921 struct package_PrimaryKerberosCtr4 *pkb4 = &pkb->ctr.ctr4;
922 struct supplementalCredentialsPackage *old_scp = NULL;
923 struct package_PrimaryKerberosBlob _old_pkb;
924 struct package_PrimaryKerberosCtr4 *old_pkb4 = NULL;
925 uint32_t i;
926 enum ndr_err_code ndr_err;
928 ldb = ldb_module_get_ctx(io->ac->module);
931 * prepare generation of keys
933 * ENCTYPE_AES256_CTS_HMAC_SHA1_96
934 * ENCTYPE_AES128_CTS_HMAC_SHA1_96
935 * ENCTYPE_DES_CBC_MD5
936 * ENCTYPE_DES_CBC_CRC
938 pkb->version = 4;
939 pkb4->salt.string = io->g.salt;
940 pkb4->default_iteration_count = 4096;
941 pkb4->num_keys = 4;
943 pkb4->keys = talloc_array(io->ac,
944 struct package_PrimaryKerberosKey4,
945 pkb4->num_keys);
946 if (!pkb4->keys) {
947 return ldb_oom(ldb);
950 pkb4->keys[0].iteration_count = 4096;
951 pkb4->keys[0].keytype = ENCTYPE_AES256_CTS_HMAC_SHA1_96;
952 pkb4->keys[0].value = &io->g.aes_256;
953 pkb4->keys[1].iteration_count = 4096;
954 pkb4->keys[1].keytype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
955 pkb4->keys[1].value = &io->g.aes_128;
956 pkb4->keys[2].iteration_count = 4096;
957 pkb4->keys[2].keytype = ENCTYPE_DES_CBC_MD5;
958 pkb4->keys[2].value = &io->g.des_md5;
959 pkb4->keys[3].iteration_count = 4096;
960 pkb4->keys[3].keytype = ENCTYPE_DES_CBC_CRC;
961 pkb4->keys[3].value = &io->g.des_crc;
963 /* initialize the old keys to zero */
964 pkb4->num_old_keys = 0;
965 pkb4->old_keys = NULL;
966 pkb4->num_older_keys = 0;
967 pkb4->older_keys = NULL;
969 /* if there're no old keys, then we're done */
970 if (!old_scb) {
971 return LDB_SUCCESS;
974 for (i=0; i < old_scb->sub.num_packages; i++) {
975 if (strcmp("Primary:Kerberos-Newer-Keys", old_scb->sub.packages[i].name) != 0) {
976 continue;
979 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
980 continue;
983 old_scp = &old_scb->sub.packages[i];
984 break;
986 /* Primary:Kerberos-Newer-Keys element of supplementalCredentials */
987 if (old_scp) {
988 DATA_BLOB blob;
990 blob = strhex_to_data_blob(io->ac, old_scp->data);
991 if (!blob.data) {
992 return ldb_oom(ldb);
995 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
996 ndr_err = ndr_pull_struct_blob(&blob, io->ac,
997 &_old_pkb,
998 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
999 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1000 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1001 ldb_asprintf_errstring(ldb,
1002 "setup_primary_kerberos_newer: "
1003 "failed to pull old package_PrimaryKerberosBlob: %s",
1004 nt_errstr(status));
1005 return LDB_ERR_OPERATIONS_ERROR;
1008 if (_old_pkb.version != 4) {
1009 ldb_asprintf_errstring(ldb,
1010 "setup_primary_kerberos_newer: "
1011 "package_PrimaryKerberosBlob version[%u] expected[4]",
1012 _old_pkb.version);
1013 return LDB_ERR_OPERATIONS_ERROR;
1016 old_pkb4 = &_old_pkb.ctr.ctr4;
1019 /* if we didn't found the old keys we're done */
1020 if (!old_pkb4) {
1021 return LDB_SUCCESS;
1024 /* fill in the old keys */
1025 pkb4->num_old_keys = old_pkb4->num_keys;
1026 pkb4->old_keys = old_pkb4->keys;
1027 pkb4->num_older_keys = old_pkb4->num_old_keys;
1028 pkb4->older_keys = old_pkb4->old_keys;
1030 return LDB_SUCCESS;
1033 static int setup_primary_wdigest(struct setup_password_fields_io *io,
1034 const struct supplementalCredentialsBlob *old_scb,
1035 struct package_PrimaryWDigestBlob *pdb)
1037 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1038 DATA_BLOB sAMAccountName;
1039 DATA_BLOB sAMAccountName_l;
1040 DATA_BLOB sAMAccountName_u;
1041 const char *user_principal_name = io->u.user_principal_name;
1042 DATA_BLOB userPrincipalName;
1043 DATA_BLOB userPrincipalName_l;
1044 DATA_BLOB userPrincipalName_u;
1045 DATA_BLOB netbios_domain;
1046 DATA_BLOB netbios_domain_l;
1047 DATA_BLOB netbios_domain_u;
1048 DATA_BLOB dns_domain;
1049 DATA_BLOB dns_domain_l;
1050 DATA_BLOB dns_domain_u;
1051 DATA_BLOB digest;
1052 DATA_BLOB delim;
1053 DATA_BLOB backslash;
1054 uint8_t i;
1055 struct {
1056 DATA_BLOB *user;
1057 DATA_BLOB *realm;
1058 DATA_BLOB *nt4dom;
1059 } wdigest[] = {
1061 * See 3.1.1.8.11.3.1 WDIGEST_CREDENTIALS Construction
1062 * https://msdn.microsoft.com/en-us/library/cc245680.aspx
1063 * for what precalculated hashes are supposed to be stored...
1065 * I can't reproduce all values which should contain "Digest" as realm,
1066 * am I doing something wrong or is w2k3 just broken...?
1068 * W2K3 fills in following for a user:
1070 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
1071 * sAMAccountName: NewUser2Sam
1072 * userPrincipalName: NewUser2Princ@sub1.w2k3.vmnet1.vm.base
1074 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1075 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
1076 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
1077 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1078 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
1079 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
1080 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
1081 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1082 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1083 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1084 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1085 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1086 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1087 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1088 * 221c55284451ae9b3aacaa2a3c86f10f => NewUser2Princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1089 * 74e1be668853d4324d38c07e2acfb8ea => (w2k3 has a bug here!) newuser2princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1090 * e1e244ab7f098e3ae1761be7f9229bbb => NEWUSER2PRINC@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
1091 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
1092 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
1093 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
1094 * 31dc704d3640335b2123d4ee28aa1f11 => ??? changes with NewUser2Sam => NewUser1Sam
1095 * 36349f5cecd07320fb3bb0e119230c43 => ??? changes with NewUser2Sam => NewUser1Sam
1096 * 12adf019d037fb535c01fd0608e78d9d => ??? changes with NewUser2Sam => NewUser1Sam
1097 * 6feecf8e724906f3ee1105819c5105a1 => ??? changes with NewUser2Princ => NewUser1Princ
1098 * 6c6911f3de6333422640221b9c51ff1f => ??? changes with NewUser2Princ => NewUser1Princ
1099 * 4b279877e742895f9348ac67a8de2f69 => ??? changes with NewUser2Princ => NewUser1Princ
1100 * db0c6bff069513e3ebb9870d29b57490 => ??? changes with NewUser2Sam => NewUser1Sam
1101 * 45072621e56b1c113a4e04a8ff68cd0e => ??? changes with NewUser2Sam => NewUser1Sam
1102 * 11d1220abc44a9c10cf91ef4a9c1de02 => ??? changes with NewUser2Sam => NewUser1Sam
1104 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
1105 * sAMAccountName: NewUser2Sam
1107 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1108 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
1109 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
1110 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1111 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
1112 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
1113 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
1114 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1115 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1116 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1117 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1118 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1119 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1120 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1121 * 8a140d30b6f0a5912735dc1e3bc993b4 => NewUser2Sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1122 * 86d95b2faae6cae4ec261e7fbaccf093 => (here w2k3 is correct) newuser2sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1123 * dfeff1493110220efcdfc6362e5f5450 => NEWUSER2SAM@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
1124 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
1125 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
1126 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
1127 * 31dc704d3640335b2123d4ee28aa1f11 => ???M1 changes with NewUser2Sam => NewUser1Sam
1128 * 36349f5cecd07320fb3bb0e119230c43 => ???M1.L changes with newuser2sam => newuser1sam
1129 * 12adf019d037fb535c01fd0608e78d9d => ???M1.U changes with NEWUSER2SAM => NEWUSER1SAM
1130 * 569b4533f2d9e580211dd040e5e360a8 => ???M2 changes with NewUser2Princ => NewUser1Princ
1131 * 52528bddf310a587c5d7e6a9ae2cbb20 => ???M2.L changes with newuser2princ => newuser1princ
1132 * 4f629a4f0361289ca4255ab0f658fcd5 => ???M3 changes with NewUser2Princ => NewUser1Princ (doesn't depend on case of userPrincipal )
1133 * db0c6bff069513e3ebb9870d29b57490 => ???M4 changes with NewUser2Sam => NewUser1Sam
1134 * 45072621e56b1c113a4e04a8ff68cd0e => ???M5 changes with NewUser2Sam => NewUser1Sam (doesn't depend on case of sAMAccountName)
1135 * 11d1220abc44a9c10cf91ef4a9c1de02 => ???M4.U changes with NEWUSER2SAM => NEWUSER1SAM
1139 * sAMAccountName, netbios_domain
1142 .user = &sAMAccountName,
1143 .realm = &netbios_domain,
1146 .user = &sAMAccountName_l,
1147 .realm = &netbios_domain_l,
1150 .user = &sAMAccountName_u,
1151 .realm = &netbios_domain_u,
1154 .user = &sAMAccountName,
1155 .realm = &netbios_domain_u,
1158 .user = &sAMAccountName,
1159 .realm = &netbios_domain_l,
1162 .user = &sAMAccountName_u,
1163 .realm = &netbios_domain_l,
1166 .user = &sAMAccountName_l,
1167 .realm = &netbios_domain_u,
1170 * sAMAccountName, dns_domain
1172 * TODO:
1173 * Windows preserves the case of the DNS domain,
1174 * Samba lower cases the domain at provision time
1175 * This means that for mixed case Domains, the WDigest08 hash
1176 * calculated by Samba differs from that calculated by Windows.
1177 * Until we get a real world use case this will remain a known
1178 * bug, as changing the case could have unforeseen impacts.
1182 .user = &sAMAccountName,
1183 .realm = &dns_domain,
1186 .user = &sAMAccountName_l,
1187 .realm = &dns_domain_l,
1190 .user = &sAMAccountName_u,
1191 .realm = &dns_domain_u,
1194 .user = &sAMAccountName,
1195 .realm = &dns_domain_u,
1198 .user = &sAMAccountName,
1199 .realm = &dns_domain_l,
1202 .user = &sAMAccountName_u,
1203 .realm = &dns_domain_l,
1206 .user = &sAMAccountName_l,
1207 .realm = &dns_domain_u,
1210 * userPrincipalName, no realm
1213 .user = &userPrincipalName,
1217 * NOTE: w2k3 messes this up, if the user has a real userPrincipalName,
1218 * the fallback to the sAMAccountName based userPrincipalName is correct
1220 .user = &userPrincipalName_l,
1223 .user = &userPrincipalName_u,
1226 * nt4dom\sAMAccountName, no realm
1229 .user = &sAMAccountName,
1230 .nt4dom = &netbios_domain
1233 .user = &sAMAccountName_l,
1234 .nt4dom = &netbios_domain_l
1237 .user = &sAMAccountName_u,
1238 .nt4dom = &netbios_domain_u
1242 * the following ones are guessed depending on the technet2 article
1243 * but not reproducable on a w2k3 server
1245 /* sAMAccountName with "Digest" realm */
1247 .user = &sAMAccountName,
1248 .realm = &digest
1251 .user = &sAMAccountName_l,
1252 .realm = &digest
1255 .user = &sAMAccountName_u,
1256 .realm = &digest
1258 /* userPrincipalName with "Digest" realm */
1260 .user = &userPrincipalName,
1261 .realm = &digest
1264 .user = &userPrincipalName_l,
1265 .realm = &digest
1268 .user = &userPrincipalName_u,
1269 .realm = &digest
1271 /* nt4dom\\sAMAccountName with "Digest" realm */
1273 .user = &sAMAccountName,
1274 .nt4dom = &netbios_domain,
1275 .realm = &digest
1278 .user = &sAMAccountName_l,
1279 .nt4dom = &netbios_domain_l,
1280 .realm = &digest
1283 .user = &sAMAccountName_u,
1284 .nt4dom = &netbios_domain_u,
1285 .realm = &digest
1288 int rc = LDB_ERR_OTHER;
1290 /* prepare DATA_BLOB's used in the combinations array */
1291 sAMAccountName = data_blob_string_const(io->u.sAMAccountName);
1292 sAMAccountName_l = data_blob_string_const(strlower_talloc(io->ac, io->u.sAMAccountName));
1293 if (!sAMAccountName_l.data) {
1294 return ldb_oom(ldb);
1296 sAMAccountName_u = data_blob_string_const(strupper_talloc(io->ac, io->u.sAMAccountName));
1297 if (!sAMAccountName_u.data) {
1298 return ldb_oom(ldb);
1301 /* if the user doesn't have a userPrincipalName, create one (with lower case realm) */
1302 if (!user_principal_name) {
1303 user_principal_name = talloc_asprintf(io->ac, "%s@%s",
1304 io->u.sAMAccountName,
1305 io->ac->status->domain_data.dns_domain);
1306 if (!user_principal_name) {
1307 return ldb_oom(ldb);
1310 userPrincipalName = data_blob_string_const(user_principal_name);
1311 userPrincipalName_l = data_blob_string_const(strlower_talloc(io->ac, user_principal_name));
1312 if (!userPrincipalName_l.data) {
1313 return ldb_oom(ldb);
1315 userPrincipalName_u = data_blob_string_const(strupper_talloc(io->ac, user_principal_name));
1316 if (!userPrincipalName_u.data) {
1317 return ldb_oom(ldb);
1320 netbios_domain = data_blob_string_const(io->ac->status->domain_data.netbios_domain);
1321 netbios_domain_l = data_blob_string_const(strlower_talloc(io->ac,
1322 io->ac->status->domain_data.netbios_domain));
1323 if (!netbios_domain_l.data) {
1324 return ldb_oom(ldb);
1326 netbios_domain_u = data_blob_string_const(strupper_talloc(io->ac,
1327 io->ac->status->domain_data.netbios_domain));
1328 if (!netbios_domain_u.data) {
1329 return ldb_oom(ldb);
1332 dns_domain = data_blob_string_const(io->ac->status->domain_data.dns_domain);
1333 dns_domain_l = data_blob_string_const(io->ac->status->domain_data.dns_domain);
1334 dns_domain_u = data_blob_string_const(io->ac->status->domain_data.realm);
1336 digest = data_blob_string_const("Digest");
1338 delim = data_blob_string_const(":");
1339 backslash = data_blob_string_const("\\");
1341 pdb->num_hashes = ARRAY_SIZE(wdigest);
1342 pdb->hashes = talloc_array(io->ac, struct package_PrimaryWDigestHash,
1343 pdb->num_hashes);
1344 if (!pdb->hashes) {
1345 return ldb_oom(ldb);
1348 for (i=0; i < ARRAY_SIZE(wdigest); i++) {
1349 gnutls_hash_hd_t hash_hnd = NULL;
1351 rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5);
1352 if (rc < 0) {
1353 rc = ldb_oom(ldb);
1354 goto out;
1357 if (wdigest[i].nt4dom) {
1358 rc = gnutls_hash(hash_hnd,
1359 wdigest[i].nt4dom->data,
1360 wdigest[i].nt4dom->length);
1361 if (rc < 0) {
1362 gnutls_hash_deinit(hash_hnd, NULL);
1363 rc = LDB_ERR_UNWILLING_TO_PERFORM;
1364 goto out;
1366 rc = gnutls_hash(hash_hnd,
1367 backslash.data,
1368 backslash.length);
1369 if (rc < 0) {
1370 gnutls_hash_deinit(hash_hnd, NULL);
1371 rc = LDB_ERR_UNWILLING_TO_PERFORM;
1372 goto out;
1375 rc = gnutls_hash(hash_hnd,
1376 wdigest[i].user->data,
1377 wdigest[i].user->length);
1378 if (rc < 0) {
1379 gnutls_hash_deinit(hash_hnd, NULL);
1380 rc = LDB_ERR_UNWILLING_TO_PERFORM;
1381 goto out;
1383 rc = gnutls_hash(hash_hnd, delim.data, delim.length);
1384 if (rc < 0) {
1385 gnutls_hash_deinit(hash_hnd, NULL);
1386 rc = LDB_ERR_UNWILLING_TO_PERFORM;
1387 goto out;
1389 if (wdigest[i].realm) {
1390 rc = gnutls_hash(hash_hnd,
1391 wdigest[i].realm->data,
1392 wdigest[i].realm->length);
1393 if (rc < 0) {
1394 gnutls_hash_deinit(hash_hnd, NULL);
1395 rc = LDB_ERR_UNWILLING_TO_PERFORM;
1396 goto out;
1399 rc = gnutls_hash(hash_hnd, delim.data, delim.length);
1400 if (rc < 0) {
1401 gnutls_hash_deinit(hash_hnd, NULL);
1402 rc = LDB_ERR_UNWILLING_TO_PERFORM;
1403 goto out;
1405 rc = gnutls_hash(hash_hnd,
1406 io->n.cleartext_utf8->data,
1407 io->n.cleartext_utf8->length);
1408 if (rc < 0) {
1409 gnutls_hash_deinit(hash_hnd, NULL);
1410 rc = LDB_ERR_UNWILLING_TO_PERFORM;
1411 goto out;
1414 gnutls_hash_deinit(hash_hnd, pdb->hashes[i].hash);
1417 rc = LDB_SUCCESS;
1418 out:
1419 return rc;
1422 #define SHA_SALT_PERMITTED_CHARS "abcdefghijklmnopqrstuvwxyz" \
1423 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
1424 "0123456789./"
1425 #define SHA_SALT_SIZE 16
1426 #define SHA_256_SCHEME "CryptSHA256"
1427 #define SHA_512_SCHEME "CryptSHA512"
1428 #define CRYPT "{CRYPT}"
1429 #define SHA_ID_LEN 3
1430 #define SHA_256_ALGORITHM_ID 5
1431 #define SHA_512_ALGORITHM_ID 6
1432 #define ROUNDS_PARAMETER "rounds="
1435 * Extract the crypt (3) algorithm number and number of hash rounds from the
1436 * supplied scheme string
1438 static bool parse_scheme(const char *scheme, int *algorithm, int *rounds) {
1440 const char *rp = NULL; /* Pointer to the 'rounds=' option */
1441 char digits[21]; /* digits extracted from the rounds option */
1442 int i = 0; /* loop index variable */
1444 if (strncasecmp(SHA_256_SCHEME, scheme, strlen(SHA_256_SCHEME)) == 0) {
1445 *algorithm = SHA_256_ALGORITHM_ID;
1446 } else if (strncasecmp(SHA_512_SCHEME, scheme, strlen(SHA_256_SCHEME))
1447 == 0) {
1448 *algorithm = SHA_512_ALGORITHM_ID;
1449 } else {
1450 return false;
1453 rp = strcasestr(scheme, ROUNDS_PARAMETER);
1454 if (rp == NULL) {
1455 /* No options specified, use crypt default number of rounds */
1456 *rounds = 0;
1457 return true;
1459 rp += strlen(ROUNDS_PARAMETER);
1460 for (i = 0; isdigit(rp[i]) && i < (sizeof(digits) - 1); i++) {
1461 digits[i] = rp[i];
1463 digits[i] = '\0';
1464 *rounds = atoi(digits);
1465 return true;
1469 * Calculate the password hash specified by scheme, and return it in
1470 * hash_value
1472 static int setup_primary_userPassword_hash(
1473 TALLOC_CTX *ctx,
1474 struct setup_password_fields_io *io,
1475 const char* scheme,
1476 struct package_PrimaryUserPasswordValue *hash_value)
1478 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1479 const char *salt = NULL; /* Randomly generated salt */
1480 const char *cmd = NULL; /* command passed to crypt */
1481 const char *hash = NULL; /* password hash generated by crypt */
1482 int algorithm = 0; /* crypt hash algorithm number */
1483 int rounds = 0; /* The number of hash rounds */
1484 DATA_BLOB *hash_blob = NULL;
1485 TALLOC_CTX *frame = talloc_stackframe();
1486 #if defined(HAVE_CRYPT_R) || defined(HAVE_CRYPT_RN)
1487 struct crypt_data crypt_data = {
1488 .initialized = 0 /* working storage used by crypt */
1490 #endif
1492 /* Genrate a random password salt */
1493 salt = generate_random_str_list(frame,
1494 SHA_SALT_SIZE,
1495 SHA_SALT_PERMITTED_CHARS);
1496 if (salt == NULL) {
1497 TALLOC_FREE(frame);
1498 return ldb_oom(ldb);
1501 /* determine the hashing algoritm and number of rounds*/
1502 if (!parse_scheme(scheme, &algorithm, &rounds)) {
1503 ldb_asprintf_errstring(
1504 ldb,
1505 "setup_primary_userPassword: Invalid scheme of [%s] "
1506 "specified for 'password hash userPassword schemes' in "
1507 "samba.conf",
1508 scheme);
1509 TALLOC_FREE(frame);
1510 return LDB_ERR_OPERATIONS_ERROR;
1512 hash_value->scheme = talloc_strdup(ctx, CRYPT);
1513 hash_value->scheme_len = strlen(CRYPT) + 1;
1515 /* generate the id/salt parameter used by crypt */
1516 if (rounds) {
1517 cmd = talloc_asprintf(frame,
1518 "$%d$rounds=%d$%s",
1519 algorithm,
1520 rounds,
1521 salt);
1522 } else {
1523 cmd = talloc_asprintf(frame, "$%d$%s", algorithm, salt);
1527 * Relies on the assertion that cleartext_utf8->data is a zero
1528 * terminated UTF-8 string
1532 * crypt_r() and crypt() may return a null pointer upon error
1533 * depending on how libcrypt was configured, so we prefer
1534 * crypt_rn() from libcrypt / libxcrypt which always returns
1535 * NULL on error.
1537 * POSIX specifies returning a null pointer and setting
1538 * errno.
1540 * RHEL 7 (which does not use libcrypt / libxcrypt) returns a
1541 * non-NULL pointer from crypt_r() on success but (always?)
1542 * sets errno during internal processing in the NSS crypto
1543 * subsystem.
1545 * By preferring crypt_rn we avoid the 'return non-NULL but
1546 * set-errno' that we otherwise cannot tell apart from the
1547 * RHEL 7 behaviour.
1549 errno = 0;
1551 #ifdef HAVE_CRYPT_RN
1552 hash = crypt_rn((char *)io->n.cleartext_utf8->data,
1553 cmd,
1554 &crypt_data,
1555 sizeof(crypt_data));
1556 #elif HAVE_CRYPT_R
1557 hash = crypt_r((char *)io->n.cleartext_utf8->data, cmd, &crypt_data);
1558 #else
1560 * No crypt_r falling back to crypt, which is NOT thread safe
1561 * Thread safety MT-Unsafe race:crypt
1563 hash = crypt((char *)io->n.cleartext_utf8->data, cmd);
1564 #endif
1566 * On error, crypt() and crypt_r() may return a null pointer,
1567 * or a pointer to an invalid hash beginning with a '*'.
1569 if (hash == NULL || hash[0] == '*') {
1570 char buf[1024];
1571 const char *reason = NULL;
1572 if (errno == ERANGE) {
1573 reason = "Password exceeds maximum length allowed for crypt() hashing";
1574 } else {
1575 int err = strerror_r(errno, buf, sizeof(buf));
1576 if (err == 0) {
1577 reason = buf;
1578 } else {
1579 reason = "Unknown error";
1582 ldb_asprintf_errstring(
1583 ldb,
1584 "setup_primary_userPassword: generation of a %s "
1585 "password hash failed: (%s)",
1586 scheme,
1587 reason);
1588 TALLOC_FREE(frame);
1589 return LDB_ERR_OPERATIONS_ERROR;
1592 hash_blob = talloc_zero(ctx, DATA_BLOB);
1594 if (hash_blob == NULL) {
1595 TALLOC_FREE(frame);
1596 return ldb_oom(ldb);
1599 *hash_blob = data_blob_talloc(hash_blob,
1600 (const uint8_t *)hash,
1601 strlen(hash));
1602 if (hash_blob->data == NULL) {
1603 TALLOC_FREE(frame);
1604 return ldb_oom(ldb);
1606 hash_value->value = hash_blob;
1607 TALLOC_FREE(frame);
1608 return LDB_SUCCESS;
1612 * Calculate the desired extra password hashes
1614 static int setup_primary_userPassword(
1615 struct setup_password_fields_io *io,
1616 const struct supplementalCredentialsBlob *old_scb,
1617 struct package_PrimaryUserPasswordBlob *p_userPassword_b)
1619 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1620 TALLOC_CTX *frame = talloc_stackframe();
1621 int i;
1622 int ret;
1625 * Save the current nt_hash, use this to determine if the password
1626 * has been changed by windows. Which will invalidate the userPassword
1627 * hash. Note once NTLM-Strong-NOWTF becomes available it should be
1628 * used in preference to the NT password hash
1630 if (io->g.nt_hash == NULL) {
1631 ldb_asprintf_errstring(ldb,
1632 "No NT Hash, unable to calculate userPassword hashes");
1633 return LDB_ERR_UNWILLING_TO_PERFORM;
1635 p_userPassword_b->current_nt_hash = *io->g.nt_hash;
1638 * Determine the number of hashes
1639 * Note: that currently there is no limit on the number of hashes
1640 * no checking is done on the number of schemes specified
1641 * or for uniqueness.
1643 p_userPassword_b->num_hashes = 0;
1644 for (i = 0; io->ac->userPassword_schemes[i]; i++) {
1645 p_userPassword_b->num_hashes++;
1648 p_userPassword_b->hashes
1649 = talloc_array(io->ac,
1650 struct package_PrimaryUserPasswordValue,
1651 p_userPassword_b->num_hashes);
1652 if (p_userPassword_b->hashes == NULL) {
1653 TALLOC_FREE(frame);
1654 return ldb_oom(ldb);
1657 for (i = 0; io->ac->userPassword_schemes[i]; i++) {
1658 ret = setup_primary_userPassword_hash(
1659 p_userPassword_b->hashes,
1661 io->ac->userPassword_schemes[i],
1662 &p_userPassword_b->hashes[i]);
1663 if (ret != LDB_SUCCESS) {
1664 TALLOC_FREE(frame);
1665 return ret;
1668 return LDB_SUCCESS;
1672 static int setup_primary_samba_gpg(struct setup_password_fields_io *io,
1673 struct package_PrimarySambaGPGBlob *pgb)
1675 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1676 #ifdef ENABLE_GPGME
1677 gpgme_error_t gret;
1678 gpgme_ctx_t ctx = NULL;
1679 size_t num_keys = str_list_length(io->ac->gpg_key_ids);
1680 gpgme_key_t keys[num_keys+1];
1681 size_t ki = 0;
1682 size_t kr = 0;
1683 gpgme_data_t plain_data = NULL;
1684 gpgme_data_t crypt_data = NULL;
1685 size_t crypt_length = 0;
1686 char *crypt_mem = NULL;
1688 gret = gpgme_new(&ctx);
1689 if (gret != GPG_ERR_NO_ERROR) {
1690 ldb_debug(ldb, LDB_DEBUG_ERROR,
1691 "%s:%s: gret[%u] %s\n",
1692 __location__, __func__,
1693 gret, gpgme_strerror(gret));
1694 return ldb_module_operr(io->ac->module);
1697 gpgme_set_armor(ctx, 1);
1699 gret = gpgme_data_new_from_mem(&plain_data,
1700 (const char *)io->n.cleartext_utf16->data,
1701 io->n.cleartext_utf16->length,
1702 0 /* no copy */);
1703 if (gret != GPG_ERR_NO_ERROR) {
1704 ldb_debug(ldb, LDB_DEBUG_ERROR,
1705 "%s:%s: gret[%u] %s\n",
1706 __location__, __func__,
1707 gret, gpgme_strerror(gret));
1708 gpgme_release(ctx);
1709 return ldb_module_operr(io->ac->module);
1711 gret = gpgme_data_new(&crypt_data);
1712 if (gret != GPG_ERR_NO_ERROR) {
1713 ldb_debug(ldb, LDB_DEBUG_ERROR,
1714 "%s:%s: gret[%u] %s\n",
1715 __location__, __func__,
1716 gret, gpgme_strerror(gret));
1717 gpgme_data_release(plain_data);
1718 gpgme_release(ctx);
1719 return ldb_module_operr(io->ac->module);
1722 for (ki = 0; ki < num_keys; ki++) {
1723 const char *key_id = io->ac->gpg_key_ids[ki];
1724 size_t len = strlen(key_id);
1726 keys[ki] = NULL;
1728 if (len < 16) {
1729 ldb_debug(ldb, LDB_DEBUG_FATAL,
1730 "%s:%s: ki[%zu] key_id[%s] strlen < 16, "
1731 "please specify at least the 64bit key id\n",
1732 __location__, __func__,
1733 ki, key_id);
1734 for (kr = 0; keys[kr] != NULL; kr++) {
1735 gpgme_key_release(keys[kr]);
1737 gpgme_data_release(crypt_data);
1738 gpgme_data_release(plain_data);
1739 gpgme_release(ctx);
1740 return ldb_module_operr(io->ac->module);
1743 gret = gpgme_get_key(ctx, key_id, &keys[ki], 0 /* public key */);
1744 if (gret != GPG_ERR_NO_ERROR) {
1745 keys[ki] = NULL;
1746 if (gpg_err_source(gret) == GPG_ERR_SOURCE_GPGME
1747 && gpg_err_code(gret) == GPG_ERR_EOF) {
1748 ldb_debug(ldb, LDB_DEBUG_ERROR,
1749 "Invalid "
1750 "'password hash gpg key ids': "
1751 "Public Key ID [%s] "
1752 "not found in keyring\n",
1753 key_id);
1755 } else {
1756 ldb_debug(ldb, LDB_DEBUG_ERROR,
1757 "%s:%s: ki[%zu] key_id[%s] "
1758 "gret[%u] %s\n",
1759 __location__, __func__,
1760 ki, key_id,
1761 gret, gpgme_strerror(gret));
1763 for (kr = 0; keys[kr] != NULL; kr++) {
1764 gpgme_key_release(keys[kr]);
1766 gpgme_data_release(crypt_data);
1767 gpgme_data_release(plain_data);
1768 gpgme_release(ctx);
1769 return ldb_module_operr(io->ac->module);
1772 keys[ki] = NULL;
1774 gret = gpgme_op_encrypt(ctx, keys,
1775 GPGME_ENCRYPT_ALWAYS_TRUST,
1776 plain_data, crypt_data);
1777 gpgme_data_release(plain_data);
1778 plain_data = NULL;
1779 for (kr = 0; keys[kr] != NULL; kr++) {
1780 gpgme_key_release(keys[kr]);
1781 keys[kr] = NULL;
1783 gpgme_release(ctx);
1784 ctx = NULL;
1785 if (gret != GPG_ERR_NO_ERROR) {
1786 ldb_debug(ldb, LDB_DEBUG_ERROR,
1787 "%s:%s: gret[%u] %s\n",
1788 __location__, __func__,
1789 gret, gpgme_strerror(gret));
1790 gpgme_data_release(crypt_data);
1791 return ldb_module_operr(io->ac->module);
1794 crypt_mem = gpgme_data_release_and_get_mem(crypt_data, &crypt_length);
1795 crypt_data = NULL;
1796 if (crypt_mem == NULL) {
1797 return ldb_module_oom(io->ac->module);
1800 pgb->gpg_blob = data_blob_talloc(io->ac,
1801 (const uint8_t *)crypt_mem,
1802 crypt_length);
1803 gpgme_free(crypt_mem);
1804 crypt_mem = NULL;
1805 crypt_length = 0;
1806 if (pgb->gpg_blob.data == NULL) {
1807 return ldb_module_oom(io->ac->module);
1810 return LDB_SUCCESS;
1811 #else /* ENABLE_GPGME */
1812 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
1813 "You configured 'password hash gpg key ids', "
1814 "but GPGME support is missing. (%s:%d)",
1815 __FILE__, __LINE__);
1816 return LDB_ERR_UNWILLING_TO_PERFORM;
1817 #endif /* else ENABLE_GPGME */
1820 #define NUM_PACKAGES 6
1821 static int setup_supplemental_field(struct setup_password_fields_io *io)
1823 struct ldb_context *ldb;
1824 struct supplementalCredentialsBlob scb;
1825 struct supplementalCredentialsBlob *old_scb = NULL;
1827 * Packages +
1828 * ( Kerberos-Newer-Keys, Kerberos,
1829 * WDigest, CLEARTEXT, userPassword, SambaGPG)
1831 uint32_t num_names = 0;
1832 const char *names[1+NUM_PACKAGES];
1833 uint32_t num_packages = 0;
1834 struct supplementalCredentialsPackage packages[1+NUM_PACKAGES];
1835 struct supplementalCredentialsPackage *pp = packages;
1836 int ret;
1837 enum ndr_err_code ndr_err;
1838 bool do_newer_keys = false;
1839 bool do_cleartext = false;
1840 bool do_samba_gpg = false;
1841 struct loadparm_context *lp_ctx = NULL;
1843 ZERO_STRUCT(names);
1844 ZERO_STRUCT(packages);
1846 ldb = ldb_module_get_ctx(io->ac->module);
1847 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
1848 struct loadparm_context);
1850 if (!io->n.cleartext_utf8) {
1852 * when we don't have a cleartext password
1853 * we can't setup a supplementalCredential value
1855 return LDB_SUCCESS;
1858 /* if there's an old supplementaCredentials blob then use it */
1859 if (io->o.supplemental) {
1860 if (io->o.scb.sub.signature == SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
1861 old_scb = &io->o.scb;
1862 } else {
1863 ldb_debug(ldb, LDB_DEBUG_ERROR,
1864 "setup_supplemental_field: "
1865 "supplementalCredentialsBlob "
1866 "signature[0x%04X] expected[0x%04X]",
1867 io->o.scb.sub.signature,
1868 SUPPLEMENTAL_CREDENTIALS_SIGNATURE);
1871 /* Per MS-SAMR 3.1.1.8.11.6 we create AES keys if our domain functionality level is 2008 or higher */
1876 * The ordering is this
1878 * Primary:Kerberos-Newer-Keys (optional)
1879 * Primary:Kerberos
1880 * Primary:WDigest
1881 * Primary:CLEARTEXT (optional)
1882 * Primary:userPassword
1883 * Primary:SambaGPG (optional)
1885 * And the 'Packages' package is insert before the last
1886 * other package.
1888 * Note: it's important that Primary:SambaGPG is added as
1889 * the last element. This is the indication that it matches
1890 * the current password. When a password change happens on
1891 * a Windows DC, it will keep the old Primary:SambaGPG value,
1892 * but as the first element.
1894 do_newer_keys = (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008);
1895 if (do_newer_keys) {
1896 struct package_PrimaryKerberosBlob pknb;
1897 DATA_BLOB pknb_blob;
1898 char *pknb_hexstr;
1900 * setup 'Primary:Kerberos-Newer-Keys' element
1902 names[num_names++] = "Kerberos-Newer-Keys";
1904 ret = setup_primary_kerberos_newer(io, old_scb, &pknb);
1905 if (ret != LDB_SUCCESS) {
1906 return ret;
1909 ndr_err = ndr_push_struct_blob(
1910 &pknb_blob, io->ac,
1911 &pknb,
1912 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1913 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1914 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1915 ldb_asprintf_errstring(
1916 ldb,
1917 "setup_supplemental_field: "
1918 "failed to push "
1919 "package_PrimaryKerberosNeverBlob: %s",
1920 nt_errstr(status));
1921 return LDB_ERR_OPERATIONS_ERROR;
1923 pknb_hexstr = data_blob_hex_string_upper(io->ac, &pknb_blob);
1924 if (!pknb_hexstr) {
1925 return ldb_oom(ldb);
1927 pp->name = "Primary:Kerberos-Newer-Keys";
1928 pp->reserved = 1;
1929 pp->data = pknb_hexstr;
1930 pp++;
1931 num_packages++;
1936 * setup 'Primary:Kerberos' element
1938 /* Primary:Kerberos */
1939 struct package_PrimaryKerberosBlob pkb;
1940 DATA_BLOB pkb_blob;
1941 char *pkb_hexstr;
1943 names[num_names++] = "Kerberos";
1945 ret = setup_primary_kerberos(io, old_scb, &pkb);
1946 if (ret != LDB_SUCCESS) {
1947 return ret;
1950 ndr_err = ndr_push_struct_blob(
1951 &pkb_blob, io->ac,
1952 &pkb,
1953 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1954 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1955 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1956 ldb_asprintf_errstring(
1957 ldb,
1958 "setup_supplemental_field: "
1959 "failed to push package_PrimaryKerberosBlob: %s",
1960 nt_errstr(status));
1961 return LDB_ERR_OPERATIONS_ERROR;
1963 pkb_hexstr = data_blob_hex_string_upper(io->ac, &pkb_blob);
1964 if (!pkb_hexstr) {
1965 return ldb_oom(ldb);
1967 pp->name = "Primary:Kerberos";
1968 pp->reserved = 1;
1969 pp->data = pkb_hexstr;
1970 pp++;
1971 num_packages++;
1974 if (lpcfg_weak_crypto(lp_ctx) == SAMBA_WEAK_CRYPTO_ALLOWED) {
1976 * setup 'Primary:WDigest' element
1978 struct package_PrimaryWDigestBlob pdb;
1979 DATA_BLOB pdb_blob;
1980 char *pdb_hexstr;
1982 names[num_names++] = "WDigest";
1984 ret = setup_primary_wdigest(io, old_scb, &pdb);
1985 if (ret != LDB_SUCCESS) {
1986 return ret;
1989 ndr_err = ndr_push_struct_blob(
1990 &pdb_blob, io->ac,
1991 &pdb,
1992 (ndr_push_flags_fn_t)ndr_push_package_PrimaryWDigestBlob);
1993 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1994 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1995 ldb_asprintf_errstring(
1996 ldb,
1997 "setup_supplemental_field: "
1998 "failed to push package_PrimaryWDigestBlob: %s",
1999 nt_errstr(status));
2000 return LDB_ERR_OPERATIONS_ERROR;
2002 pdb_hexstr = data_blob_hex_string_upper(io->ac, &pdb_blob);
2003 if (!pdb_hexstr) {
2004 return ldb_oom(ldb);
2006 pp->name = "Primary:WDigest";
2007 pp->reserved = 1;
2008 pp->data = pdb_hexstr;
2009 pp++;
2010 num_packages++;
2014 * setup 'Primary:CLEARTEXT' element
2016 if (io->ac->status->domain_data.store_cleartext &&
2017 (io->u.userAccountControl & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) {
2018 do_cleartext = true;
2020 if (do_cleartext) {
2021 struct package_PrimaryCLEARTEXTBlob pcb;
2022 DATA_BLOB pcb_blob;
2023 char *pcb_hexstr;
2025 names[num_names++] = "CLEARTEXT";
2027 pcb.cleartext = *io->n.cleartext_utf16;
2029 ndr_err = ndr_push_struct_blob(
2030 &pcb_blob, io->ac,
2031 &pcb,
2032 (ndr_push_flags_fn_t)ndr_push_package_PrimaryCLEARTEXTBlob);
2033 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2034 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2035 ldb_asprintf_errstring(
2036 ldb,
2037 "setup_supplemental_field: "
2038 "failed to push package_PrimaryCLEARTEXTBlob: %s",
2039 nt_errstr(status));
2040 return LDB_ERR_OPERATIONS_ERROR;
2042 pcb_hexstr = data_blob_hex_string_upper(io->ac, &pcb_blob);
2043 if (!pcb_hexstr) {
2044 return ldb_oom(ldb);
2046 pp->name = "Primary:CLEARTEXT";
2047 pp->reserved = 1;
2048 pp->data = pcb_hexstr;
2049 pp++;
2050 num_packages++;
2054 * Don't generate crypt() or similar password for the krbtgt account.
2055 * It's unnecessary, and the length of the cleartext in UTF-8 form
2056 * exceeds the maximum (CRYPT_MAX_PASSPHRASE_SIZE) allowed by crypt().
2058 if (io->ac->userPassword_schemes && !io->u.is_krbtgt) {
2060 * setup 'Primary:userPassword' element
2062 struct package_PrimaryUserPasswordBlob
2063 p_userPassword_b;
2064 DATA_BLOB p_userPassword_b_blob;
2065 char *p_userPassword_b_hexstr;
2067 names[num_names++] = "userPassword";
2069 ret = setup_primary_userPassword(io,
2070 old_scb,
2071 &p_userPassword_b);
2072 if (ret != LDB_SUCCESS) {
2073 return ret;
2076 ndr_err = ndr_push_struct_blob(
2077 &p_userPassword_b_blob,
2078 io->ac,
2079 &p_userPassword_b,
2080 (ndr_push_flags_fn_t)
2081 ndr_push_package_PrimaryUserPasswordBlob);
2082 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2083 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2084 ldb_asprintf_errstring(
2085 ldb,
2086 "setup_supplemental_field: failed to push "
2087 "package_PrimaryUserPasswordBlob: %s",
2088 nt_errstr(status));
2089 return LDB_ERR_OPERATIONS_ERROR;
2091 p_userPassword_b_hexstr
2092 = data_blob_hex_string_upper(
2093 io->ac,
2094 &p_userPassword_b_blob);
2095 if (!p_userPassword_b_hexstr) {
2096 return ldb_oom(ldb);
2098 pp->name = "Primary:userPassword";
2099 pp->reserved = 1;
2100 pp->data = p_userPassword_b_hexstr;
2101 pp++;
2102 num_packages++;
2106 * setup 'Primary:SambaGPG' element
2108 if (io->ac->gpg_key_ids != NULL) {
2109 do_samba_gpg = true;
2111 if (do_samba_gpg) {
2112 struct package_PrimarySambaGPGBlob pgb;
2113 DATA_BLOB pgb_blob;
2114 char *pgb_hexstr;
2116 names[num_names++] = "SambaGPG";
2118 ret = setup_primary_samba_gpg(io, &pgb);
2119 if (ret != LDB_SUCCESS) {
2120 return ret;
2123 ndr_err = ndr_push_struct_blob(&pgb_blob, io->ac, &pgb,
2124 (ndr_push_flags_fn_t)ndr_push_package_PrimarySambaGPGBlob);
2125 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2126 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2127 ldb_asprintf_errstring(ldb,
2128 "setup_supplemental_field: failed to "
2129 "push package_PrimarySambaGPGBlob: %s",
2130 nt_errstr(status));
2131 return LDB_ERR_OPERATIONS_ERROR;
2133 pgb_hexstr = data_blob_hex_string_upper(io->ac, &pgb_blob);
2134 if (!pgb_hexstr) {
2135 return ldb_oom(ldb);
2137 pp->name = "Primary:SambaGPG";
2138 pp->reserved = 1;
2139 pp->data = pgb_hexstr;
2140 pp++;
2141 num_packages++;
2145 * setup 'Packages' element
2148 struct package_PackagesBlob pb;
2149 DATA_BLOB pb_blob;
2150 char *pb_hexstr;
2152 pb.names = names;
2153 ndr_err = ndr_push_struct_blob(
2154 &pb_blob, io->ac,
2155 &pb,
2156 (ndr_push_flags_fn_t)ndr_push_package_PackagesBlob);
2157 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2158 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2159 ldb_asprintf_errstring(
2160 ldb,
2161 "setup_supplemental_field: "
2162 "failed to push package_PackagesBlob: %s",
2163 nt_errstr(status));
2164 return LDB_ERR_OPERATIONS_ERROR;
2166 pb_hexstr = data_blob_hex_string_upper(io->ac, &pb_blob);
2167 if (!pb_hexstr) {
2168 return ldb_oom(ldb);
2170 pp->name = "Packages";
2171 pp->reserved = 2;
2172 pp->data = pb_hexstr;
2173 num_packages++;
2175 * We don't increment pp so it's pointing to the last package
2180 * setup 'supplementalCredentials' value
2184 * The 'Packages' element needs to be the second last element
2185 * in supplementalCredentials
2187 struct supplementalCredentialsPackage temp;
2188 struct supplementalCredentialsPackage *prev;
2190 prev = pp-1;
2191 temp = *prev;
2192 *prev = *pp;
2193 *pp = temp;
2195 ZERO_STRUCT(scb);
2196 scb.sub.signature = SUPPLEMENTAL_CREDENTIALS_SIGNATURE;
2197 scb.sub.num_packages = num_packages;
2198 scb.sub.packages = packages;
2200 ndr_err = ndr_push_struct_blob(
2201 &io->g.supplemental, io->ac,
2202 &scb,
2203 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
2204 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2205 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2206 ldb_asprintf_errstring(
2207 ldb,
2208 "setup_supplemental_field: "
2209 "failed to push supplementalCredentialsBlob: %s",
2210 nt_errstr(status));
2211 return LDB_ERR_OPERATIONS_ERROR;
2215 return LDB_SUCCESS;
2218 static int setup_last_set_field(struct setup_password_fields_io *io)
2220 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2221 const struct ldb_message *msg = NULL;
2222 struct timeval tv = { .tv_sec = 0 };
2223 const struct ldb_val *old_val = NULL;
2224 const struct ldb_val *new_val = NULL;
2225 int ret;
2227 switch (io->ac->req->operation) {
2228 case LDB_ADD:
2229 msg = io->ac->req->op.add.message;
2230 break;
2231 case LDB_MODIFY:
2232 msg = io->ac->req->op.mod.message;
2233 break;
2234 default:
2235 return LDB_ERR_OPERATIONS_ERROR;
2236 break;
2239 if (io->ac->pwd_last_set_bypass) {
2240 struct ldb_message_element *el1 = NULL;
2241 struct ldb_message_element *el2 = NULL;
2243 if (msg == NULL) {
2244 return LDB_ERR_CONSTRAINT_VIOLATION;
2247 el1 = dsdb_get_single_valued_attr(msg, "pwdLastSet",
2248 io->ac->req->operation);
2249 if (el1 == NULL) {
2250 return LDB_ERR_CONSTRAINT_VIOLATION;
2252 el2 = ldb_msg_find_element(msg, "pwdLastSet");
2253 if (el2 == NULL) {
2254 return LDB_ERR_CONSTRAINT_VIOLATION;
2256 if (el1 != el2) {
2257 return LDB_ERR_CONSTRAINT_VIOLATION;
2260 io->g.last_set = samdb_result_nttime(msg, "pwdLastSet", 0);
2261 return LDB_SUCCESS;
2264 ret = msg_find_old_and_new_pwd_val(msg, "pwdLastSet",
2265 io->ac->req->operation,
2266 &new_val, &old_val);
2267 if (ret != LDB_SUCCESS) {
2268 return ret;
2271 if (old_val != NULL && new_val == NULL) {
2272 ldb_set_errstring(ldb,
2273 "'pwdLastSet' deletion is not allowed!");
2274 return LDB_ERR_UNWILLING_TO_PERFORM;
2277 io->g.last_set = UINT64_MAX;
2278 if (new_val != NULL) {
2279 struct ldb_message *tmp_msg = NULL;
2281 tmp_msg = ldb_msg_new(io->ac);
2282 if (tmp_msg == NULL) {
2283 return ldb_module_oom(io->ac->module);
2286 if (old_val != NULL) {
2287 NTTIME old_last_set = 0;
2289 ret = ldb_msg_add_value(tmp_msg, "oldval",
2290 old_val, NULL);
2291 if (ret != LDB_SUCCESS) {
2292 return ret;
2295 old_last_set = samdb_result_nttime(tmp_msg,
2296 "oldval",
2298 if (io->u.pwdLastSet != old_last_set) {
2299 return dsdb_module_werror(io->ac->module,
2300 LDB_ERR_NO_SUCH_ATTRIBUTE,
2301 WERR_DS_CANT_REM_MISSING_ATT_VAL,
2302 "setup_last_set_field: old pwdLastSet "
2303 "value not found!");
2307 ret = ldb_msg_add_value(tmp_msg, "newval",
2308 new_val, NULL);
2309 if (ret != LDB_SUCCESS) {
2310 return ret;
2313 io->g.last_set = samdb_result_nttime(tmp_msg,
2314 "newval",
2316 } else if (ldb_msg_find_element(msg, "pwdLastSet")) {
2317 ldb_set_errstring(ldb,
2318 "'pwdLastSet' deletion is not allowed!");
2319 return LDB_ERR_UNWILLING_TO_PERFORM;
2320 } else if (io->ac->smartcard_reset) {
2322 * adding UF_SMARTCARD_REQUIRED doesn't update
2323 * pwdLastSet implicitly.
2325 io->ac->update_lastset = false;
2328 /* only 0 or -1 (0xFFFFFFFFFFFFFFFF) are allowed */
2329 switch (io->g.last_set) {
2330 case 0:
2331 if (!io->ac->pwd_last_set_default) {
2332 break;
2334 if (!io->ac->update_password) {
2335 break;
2337 FALL_THROUGH;
2338 case UINT64_MAX:
2339 if (!io->ac->update_password &&
2340 io->u.pwdLastSet != 0 &&
2341 io->u.pwdLastSet != UINT64_MAX)
2344 * Just setting pwdLastSet to -1, while not changing
2345 * any password field has no effect if pwdLastSet
2346 * is already non-zero.
2348 io->ac->update_lastset = false;
2349 break;
2351 /* -1 means set it as now */
2352 GetTimeOfDay(&tv);
2353 io->g.last_set = timeval_to_nttime(&tv);
2354 break;
2355 default:
2356 return dsdb_module_werror(io->ac->module,
2357 LDB_ERR_OTHER,
2358 WERR_INVALID_PARAMETER,
2359 "setup_last_set_field: "
2360 "pwdLastSet must be 0 or -1 only!");
2363 if (io->ac->req->operation == LDB_ADD) {
2365 * We always need to store the value on add
2366 * operations.
2368 return LDB_SUCCESS;
2371 if (io->g.last_set == io->u.pwdLastSet) {
2373 * Just setting pwdLastSet to 0, is no-op if it's already 0.
2375 io->ac->update_lastset = false;
2378 return LDB_SUCCESS;
2381 static int setup_given_passwords(struct setup_password_fields_io *io,
2382 struct setup_password_fields_given *g)
2384 struct ldb_context *ldb;
2385 bool ok;
2387 ldb = ldb_module_get_ctx(io->ac->module);
2389 if (g->cleartext_utf8) {
2390 struct ldb_val *cleartext_utf16_blob;
2392 cleartext_utf16_blob = talloc(io->ac, struct ldb_val);
2393 if (!cleartext_utf16_blob) {
2394 return ldb_oom(ldb);
2396 if (!convert_string_talloc(io->ac,
2397 CH_UTF8, CH_UTF16,
2398 g->cleartext_utf8->data,
2399 g->cleartext_utf8->length,
2400 (void *)&cleartext_utf16_blob->data,
2401 &cleartext_utf16_blob->length)) {
2402 if (g->cleartext_utf8->length != 0) {
2403 talloc_free(cleartext_utf16_blob);
2404 ldb_asprintf_errstring(ldb,
2405 "setup_password_fields: "
2406 "failed to generate UTF16 password from cleartext UTF8 one for user '%s'!",
2407 io->u.sAMAccountName);
2408 return LDB_ERR_CONSTRAINT_VIOLATION;
2409 } else {
2410 /* passwords with length "0" are valid! */
2411 cleartext_utf16_blob->data = NULL;
2412 cleartext_utf16_blob->length = 0;
2415 g->cleartext_utf16 = cleartext_utf16_blob;
2416 } else if (g->cleartext_utf16) {
2417 struct ldb_val *cleartext_utf8_blob;
2419 cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
2420 if (!cleartext_utf8_blob) {
2421 return ldb_oom(ldb);
2423 if (!convert_string_talloc(io->ac,
2424 CH_UTF16MUNGED, CH_UTF8,
2425 g->cleartext_utf16->data,
2426 g->cleartext_utf16->length,
2427 (void *)&cleartext_utf8_blob->data,
2428 &cleartext_utf8_blob->length)) {
2429 if (g->cleartext_utf16->length != 0) {
2430 /* We must bail out here, the input wasn't even
2431 * a multiple of 2 bytes */
2432 talloc_free(cleartext_utf8_blob);
2433 ldb_asprintf_errstring(ldb,
2434 "setup_password_fields: "
2435 "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)!",
2436 io->u.sAMAccountName);
2437 return LDB_ERR_CONSTRAINT_VIOLATION;
2438 } else {
2439 /* passwords with length "0" are valid! */
2440 cleartext_utf8_blob->data = NULL;
2441 cleartext_utf8_blob->length = 0;
2444 g->cleartext_utf8 = cleartext_utf8_blob;
2447 if (g->cleartext_utf16) {
2448 struct samr_Password *nt_hash;
2450 nt_hash = talloc(io->ac, struct samr_Password);
2451 if (!nt_hash) {
2452 return ldb_oom(ldb);
2454 g->nt_hash = nt_hash;
2456 /* compute the new nt hash */
2457 mdfour(nt_hash->hash,
2458 g->cleartext_utf16->data,
2459 g->cleartext_utf16->length);
2462 if (g->cleartext_utf8) {
2463 struct samr_Password *lm_hash;
2465 lm_hash = talloc(io->ac, struct samr_Password);
2466 if (!lm_hash) {
2467 return ldb_oom(ldb);
2470 /* compute the new lm hash */
2471 ok = E_deshash((char *)g->cleartext_utf8->data, lm_hash->hash);
2472 if (ok) {
2473 g->lm_hash = lm_hash;
2474 } else {
2475 talloc_free(lm_hash);
2479 return LDB_SUCCESS;
2482 static int setup_password_fields(struct setup_password_fields_io *io)
2484 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2485 struct loadparm_context *lp_ctx =
2486 talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2487 struct loadparm_context);
2488 int ret;
2490 ret = setup_last_set_field(io);
2491 if (ret != LDB_SUCCESS) {
2492 return ret;
2495 if (!io->ac->update_password) {
2496 return LDB_SUCCESS;
2499 /* transform the old password (for password changes) */
2500 ret = setup_given_passwords(io, &io->og);
2501 if (ret != LDB_SUCCESS) {
2502 return ret;
2505 /* transform the new password */
2506 ret = setup_given_passwords(io, &io->n);
2507 if (ret != LDB_SUCCESS) {
2508 return ret;
2511 if (io->n.cleartext_utf8) {
2512 ret = setup_kerberos_keys(io);
2513 if (ret != LDB_SUCCESS) {
2514 return ret;
2518 ret = setup_nt_fields(io);
2519 if (ret != LDB_SUCCESS) {
2520 return ret;
2523 if (lpcfg_lanman_auth(lp_ctx)) {
2524 ret = setup_lm_fields(io);
2525 if (ret != LDB_SUCCESS) {
2526 return ret;
2528 } else {
2529 io->g.lm_hash = NULL;
2530 io->g.lm_history_len = 0;
2533 ret = setup_supplemental_field(io);
2534 if (ret != LDB_SUCCESS) {
2535 return ret;
2538 return LDB_SUCCESS;
2541 static int setup_smartcard_reset(struct setup_password_fields_io *io)
2543 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2544 struct loadparm_context *lp_ctx = talloc_get_type(
2545 ldb_get_opaque(ldb, "loadparm"), struct loadparm_context);
2546 struct supplementalCredentialsBlob scb = { .__ndr_size = 0 };
2547 enum ndr_err_code ndr_err;
2549 if (!io->ac->smartcard_reset) {
2550 return LDB_SUCCESS;
2553 io->g.nt_hash = talloc(io->ac, struct samr_Password);
2554 if (io->g.nt_hash == NULL) {
2555 return ldb_module_oom(io->ac->module);
2557 generate_secret_buffer(io->g.nt_hash->hash,
2558 sizeof(io->g.nt_hash->hash));
2559 io->g.nt_history_len = 0;
2561 if (lpcfg_lanman_auth(lp_ctx)) {
2562 io->g.lm_hash = talloc(io->ac, struct samr_Password);
2563 if (io->g.lm_hash == NULL) {
2564 return ldb_module_oom(io->ac->module);
2566 generate_secret_buffer(io->g.lm_hash->hash,
2567 sizeof(io->g.lm_hash->hash));
2568 } else {
2569 io->g.lm_hash = NULL;
2571 io->g.lm_history_len = 0;
2574 * We take the "old" value and store it
2575 * with num_packages = 0.
2577 * On "add" we have scb.sub.signature == 0, which
2578 * results in:
2580 * [0000] 00 00 00 00 00 00 00 00 00 00 00 00 00
2582 * On modify it's likely to be scb.sub.signature ==
2583 * SUPPLEMENTAL_CREDENTIALS_SIGNATURE (0x0050), which results in
2584 * something like:
2586 * [0000] 00 00 00 00 62 00 00 00 00 00 00 00 20 00 20 00
2587 * [0010] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2588 * [0020] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2589 * [0030] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2590 * [0040] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2591 * [0050] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2592 * [0060] 20 00 20 00 20 00 20 00 20 00 20 00 50 00 00
2594 * See https://bugzilla.samba.org/show_bug.cgi?id=11441
2595 * and ndr_{push,pull}_supplementalCredentialsSubBlob().
2597 scb = io->o.scb;
2598 scb.sub.num_packages = 0;
2601 * setup 'supplementalCredentials' value without packages
2603 ndr_err = ndr_push_struct_blob(&io->g.supplemental, io->ac,
2604 &scb,
2605 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
2606 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2607 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2608 ldb_asprintf_errstring(ldb,
2609 "setup_smartcard_reset: "
2610 "failed to push supplementalCredentialsBlob: %s",
2611 nt_errstr(status));
2612 return LDB_ERR_OPERATIONS_ERROR;
2615 io->ac->update_password = true;
2616 return LDB_SUCCESS;
2619 static int make_error_and_update_badPwdCount(struct setup_password_fields_io *io, WERROR *werror)
2621 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2622 struct ldb_message *mod_msg = NULL;
2623 struct ldb_message *pso_msg = NULL;
2624 NTSTATUS status;
2625 int ret;
2627 /* PSO search result is optional (NULL if no PSO applies) */
2628 if (io->ac->pso_res != NULL) {
2629 pso_msg = io->ac->pso_res->message;
2632 status = dsdb_update_bad_pwd_count(io->ac, ldb,
2633 io->ac->search_res->message,
2634 io->ac->dom_res->message,
2635 pso_msg,
2636 &mod_msg);
2637 if (!NT_STATUS_IS_OK(status)) {
2638 goto done;
2641 if (mod_msg == NULL) {
2642 goto done;
2646 * OK, horrible semantics ahead.
2648 * - We need to abort any existing transaction
2649 * - create a transaction arround the badPwdCount update
2650 * - re-open the transaction so the upper layer
2651 * doesn't know what happened.
2653 * This is needed because returning an error to the upper
2654 * layer will cancel the transaction and undo the badPwdCount
2655 * update.
2659 * Checking errors here is a bit pointless.
2660 * What can we do if we can't end the transaction?
2662 ret = ldb_next_del_trans(io->ac->module);
2663 if (ret != LDB_SUCCESS) {
2664 ldb_debug(ldb, LDB_DEBUG_FATAL,
2665 "Failed to abort transaction prior to update of badPwdCount of %s: %s",
2666 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2667 ldb_errstring(ldb));
2669 * just return the original error
2671 goto done;
2674 /* Likewise, what should we do if we can't open a new transaction? */
2675 ret = ldb_next_start_trans(io->ac->module);
2676 if (ret != LDB_SUCCESS) {
2677 ldb_debug(ldb, LDB_DEBUG_ERROR,
2678 "Failed to open transaction to update badPwdCount of %s: %s",
2679 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2680 ldb_errstring(ldb));
2682 * just return the original error
2684 goto done;
2687 ret = dsdb_module_modify(io->ac->module, mod_msg,
2688 DSDB_FLAG_NEXT_MODULE,
2689 io->ac->req);
2690 if (ret != LDB_SUCCESS) {
2691 ldb_debug(ldb, LDB_DEBUG_ERROR,
2692 "Failed to update badPwdCount of %s: %s",
2693 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2694 ldb_errstring(ldb));
2696 * We can only ignore this...
2700 ret = ldb_next_end_trans(io->ac->module);
2701 if (ret != LDB_SUCCESS) {
2702 ldb_debug(ldb, LDB_DEBUG_ERROR,
2703 "Failed to close transaction to update badPwdCount of %s: %s",
2704 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2705 ldb_errstring(ldb));
2707 * We can only ignore this...
2711 ret = ldb_next_start_trans(io->ac->module);
2712 if (ret != LDB_SUCCESS) {
2713 ldb_debug(ldb, LDB_DEBUG_ERROR,
2714 "Failed to open transaction after update of badPwdCount of %s: %s",
2715 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2716 ldb_errstring(ldb));
2718 * We can only ignore this...
2722 done:
2723 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2724 *werror = WERR_INVALID_PASSWORD;
2725 ldb_asprintf_errstring(ldb,
2726 "%08X: %s - check_password_restrictions: "
2727 "The old password specified doesn't match!",
2728 W_ERROR_V(*werror),
2729 ldb_strerror(ret));
2730 return ret;
2733 static int check_password_restrictions(struct setup_password_fields_io *io, WERROR *werror)
2735 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2736 int ret;
2737 struct loadparm_context *lp_ctx =
2738 talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2739 struct loadparm_context);
2741 *werror = WERR_INVALID_PARAMETER;
2743 if (!io->ac->update_password) {
2744 return LDB_SUCCESS;
2747 /* First check the old password is correct, for password changes */
2748 if (!io->ac->pwd_reset) {
2749 bool nt_hash_checked = false;
2751 /* we need the old nt or lm hash given by the client */
2752 if (!io->og.nt_hash && !io->og.lm_hash) {
2753 ldb_asprintf_errstring(ldb,
2754 "check_password_restrictions: "
2755 "You need to provide the old password in order "
2756 "to change it!");
2757 return LDB_ERR_UNWILLING_TO_PERFORM;
2760 /* The password modify through the NT hash is encouraged and
2761 has no problems at all */
2762 if (io->og.nt_hash) {
2763 if (!io->o.nt_hash || memcmp(io->og.nt_hash->hash, io->o.nt_hash->hash, 16) != 0) {
2764 return make_error_and_update_badPwdCount(io, werror);
2767 nt_hash_checked = true;
2770 /* But it is also possible to change a password by the LM hash
2771 * alone for compatibility reasons. This check is optional if
2772 * the NT hash was already checked - otherwise it's mandatory.
2773 * (as the SAMR operations request it). */
2774 if (io->og.lm_hash) {
2775 if ((!io->o.lm_hash && !nt_hash_checked)
2776 || (io->o.lm_hash && memcmp(io->og.lm_hash->hash, io->o.lm_hash->hash, 16) != 0)) {
2777 return make_error_and_update_badPwdCount(io, werror);
2782 if (io->u.restrictions == 0) {
2783 /* FIXME: Is this right? */
2784 return LDB_SUCCESS;
2787 /* Password minimum age: yes, this is a minus. The ages are in negative 100nsec units! */
2788 if ((io->u.pwdLastSet - io->ac->status->domain_data.minPwdAge > io->g.last_set) &&
2789 !io->ac->pwd_reset)
2791 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2792 *werror = WERR_PASSWORD_RESTRICTION;
2793 ldb_asprintf_errstring(ldb,
2794 "%08X: %s - check_password_restrictions: "
2795 "password is too young to change!",
2796 W_ERROR_V(*werror),
2797 ldb_strerror(ret));
2798 return ret;
2802 * Fundamental password checks done by the call
2803 * "samdb_check_password".
2804 * It is also in use by "dcesrv_samr_ValidatePassword".
2806 if (io->n.cleartext_utf8 != NULL) {
2807 enum samr_ValidationStatus vstat;
2808 vstat = samdb_check_password(io->ac, lp_ctx,
2809 io->u.sAMAccountName,
2810 io->u.user_principal_name,
2811 io->u.displayName,
2812 io->n.cleartext_utf8,
2813 io->ac->status->domain_data.pwdProperties,
2814 io->ac->status->domain_data.minPwdLength);
2815 switch (vstat) {
2816 case SAMR_VALIDATION_STATUS_SUCCESS:
2817 /* perfect -> proceed! */
2818 break;
2820 case SAMR_VALIDATION_STATUS_PWD_TOO_SHORT:
2821 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2822 *werror = WERR_PASSWORD_RESTRICTION;
2823 ldb_asprintf_errstring(ldb,
2824 "%08X: %s - check_password_restrictions: "
2825 "the password is too short. It should be equal or longer than %u characters!",
2826 W_ERROR_V(*werror),
2827 ldb_strerror(ret),
2828 io->ac->status->domain_data.minPwdLength);
2829 io->ac->status->reject_reason = SAM_PWD_CHANGE_PASSWORD_TOO_SHORT;
2830 return ret;
2832 case SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH:
2833 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2834 *werror = WERR_PASSWORD_RESTRICTION;
2835 ldb_asprintf_errstring(ldb,
2836 "%08X: %s - check_password_restrictions: "
2837 "the password does not meet the complexity criteria!",
2838 W_ERROR_V(*werror),
2839 ldb_strerror(ret));
2840 io->ac->status->reject_reason = SAM_PWD_CHANGE_NOT_COMPLEX;
2841 return ret;
2843 default:
2844 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2845 *werror = WERR_PASSWORD_RESTRICTION;
2846 ldb_asprintf_errstring(ldb,
2847 "%08X: %s - check_password_restrictions: "
2848 "the password doesn't fit due to a miscellaneous restriction!",
2849 W_ERROR_V(*werror),
2850 ldb_strerror(ret));
2851 return ret;
2855 if (io->ac->pwd_reset) {
2856 *werror = WERR_OK;
2857 return LDB_SUCCESS;
2860 if (io->n.nt_hash) {
2861 uint32_t i;
2863 /* checks the NT hash password history */
2864 for (i = 0; i < io->o.nt_history_len; i++) {
2865 ret = memcmp(io->n.nt_hash, io->o.nt_history[i].hash, 16);
2866 if (ret == 0) {
2867 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2868 *werror = WERR_PASSWORD_RESTRICTION;
2869 ldb_asprintf_errstring(ldb,
2870 "%08X: %s - check_password_restrictions: "
2871 "the password was already used (in history)!",
2872 W_ERROR_V(*werror),
2873 ldb_strerror(ret));
2874 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
2875 return ret;
2880 if (io->n.lm_hash) {
2881 uint32_t i;
2883 /* checks the LM hash password history */
2884 for (i = 0; i < io->o.lm_history_len; i++) {
2885 ret = memcmp(io->n.lm_hash, io->o.lm_history[i].hash, 16);
2886 if (ret == 0) {
2887 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2888 *werror = WERR_PASSWORD_RESTRICTION;
2889 ldb_asprintf_errstring(ldb,
2890 "%08X: %s - check_password_restrictions: "
2891 "the password was already used (in history)!",
2892 W_ERROR_V(*werror),
2893 ldb_strerror(ret));
2894 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
2895 return ret;
2900 /* are all password changes disallowed? */
2901 if (io->ac->status->domain_data.pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
2902 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2903 *werror = WERR_PASSWORD_RESTRICTION;
2904 ldb_asprintf_errstring(ldb,
2905 "%08X: %s - check_password_restrictions: "
2906 "password changes disabled!",
2907 W_ERROR_V(*werror),
2908 ldb_strerror(ret));
2909 return ret;
2912 /* can this user change the password? */
2913 if (io->u.userAccountControl & UF_PASSWD_CANT_CHANGE) {
2914 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2915 *werror = WERR_PASSWORD_RESTRICTION;
2916 ldb_asprintf_errstring(ldb,
2917 "%08X: %s - check_password_restrictions: "
2918 "password can't be changed on this account!",
2919 W_ERROR_V(*werror),
2920 ldb_strerror(ret));
2921 return ret;
2924 return LDB_SUCCESS;
2927 static int check_password_restrictions_and_log(struct setup_password_fields_io *io)
2929 WERROR werror;
2930 int ret = check_password_restrictions(io, &werror);
2931 struct ph_context *ac = io->ac;
2933 * Password resets are not authentication events, and if the
2934 * upper layer checked the password and supplied the hash
2935 * values as proof, then this is also not an authentication
2936 * even at this layer (already logged). This is to log LDAP
2937 * password changes.
2940 /* Do not record a failure in the auth log below in the success case */
2941 if (ret == LDB_SUCCESS) {
2942 werror = WERR_OK;
2945 if (ac->pwd_reset == false && ac->change == NULL) {
2946 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2947 struct imessaging_context *msg_ctx;
2948 struct loadparm_context *lp_ctx
2949 = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"),
2950 struct loadparm_context);
2951 NTSTATUS status = werror_to_ntstatus(werror);
2952 const char *domain_name = lpcfg_sam_name(lp_ctx);
2953 void *opaque_remote_address = NULL;
2955 * Forcing this via the NTLM auth structure is not ideal, but
2956 * it is the most practical option right now, and ensures the
2957 * logs are consistent, even if some elements are always NULL.
2959 struct auth_usersupplied_info ui = {
2960 .mapped_state = true,
2961 .was_mapped = true,
2962 .client = {
2963 .account_name = io->u.sAMAccountName,
2964 .domain_name = domain_name,
2966 .mapped = {
2967 .account_name = io->u.sAMAccountName,
2968 .domain_name = domain_name,
2970 .service_description = "LDAP Password Change",
2971 .auth_description = "LDAP Modify",
2972 .password_type = "plaintext"
2975 opaque_remote_address = ldb_get_opaque(ldb,
2976 "remoteAddress");
2977 if (opaque_remote_address == NULL) {
2978 ldb_asprintf_errstring(ldb,
2979 "Failed to obtain remote address for "
2980 "the LDAP client while changing the "
2981 "password");
2982 return LDB_ERR_OPERATIONS_ERROR;
2984 ui.remote_host = talloc_get_type(opaque_remote_address,
2985 struct tsocket_address);
2987 msg_ctx = imessaging_client_init(ac, lp_ctx,
2988 ldb_get_event_context(ldb));
2989 if (!msg_ctx) {
2990 ldb_asprintf_errstring(ldb,
2991 "Failed to generate client messaging context in %s",
2992 lpcfg_imessaging_path(ac, lp_ctx));
2993 return LDB_ERR_OPERATIONS_ERROR;
2995 log_authentication_event(msg_ctx,
2996 lp_ctx,
2997 NULL,
2998 &ui,
2999 status,
3000 domain_name,
3001 io->u.sAMAccountName,
3002 io->u.account_sid);
3005 return ret;
3008 static int update_final_msg(struct setup_password_fields_io *io)
3010 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
3011 int ret;
3012 int el_flags = 0;
3013 bool update_password = io->ac->update_password;
3014 bool update_scb = io->ac->update_password;
3017 * If we add a user without initial password,
3018 * we need to add replication meta data for
3019 * following attributes:
3020 * - unicodePwd
3021 * - dBCSPwd
3022 * - ntPwdHistory
3023 * - lmPwdHistory
3025 * If we add a user with initial password or a
3026 * password is changed of an existing user,
3027 * we need to replace the following attributes
3028 * with a forced meta data update, e.g. also
3029 * when updating an empty attribute with an empty value:
3030 * - unicodePwd
3031 * - dBCSPwd
3032 * - ntPwdHistory
3033 * - lmPwdHistory
3034 * - supplementalCredentials
3037 switch (io->ac->req->operation) {
3038 case LDB_ADD:
3039 update_password = true;
3040 el_flags |= DSDB_FLAG_INTERNAL_FORCE_META_DATA;
3041 break;
3042 case LDB_MODIFY:
3043 el_flags |= LDB_FLAG_MOD_REPLACE;
3044 el_flags |= DSDB_FLAG_INTERNAL_FORCE_META_DATA;
3045 break;
3046 default:
3047 return ldb_module_operr(io->ac->module);
3050 if (update_password) {
3051 ret = ldb_msg_add_empty(io->ac->update_msg,
3052 "unicodePwd",
3053 el_flags, NULL);
3054 if (ret != LDB_SUCCESS) {
3055 return ret;
3057 ret = ldb_msg_add_empty(io->ac->update_msg,
3058 "dBCSPwd",
3059 el_flags, NULL);
3060 if (ret != LDB_SUCCESS) {
3061 return ret;
3063 ret = ldb_msg_add_empty(io->ac->update_msg,
3064 "ntPwdHistory",
3065 el_flags, NULL);
3066 if (ret != LDB_SUCCESS) {
3067 return ret;
3069 ret = ldb_msg_add_empty(io->ac->update_msg,
3070 "lmPwdHistory",
3071 el_flags, NULL);
3072 if (ret != LDB_SUCCESS) {
3073 return ret;
3076 if (update_scb) {
3077 ret = ldb_msg_add_empty(io->ac->update_msg,
3078 "supplementalCredentials",
3079 el_flags, NULL);
3080 if (ret != LDB_SUCCESS) {
3081 return ret;
3084 if (io->ac->update_lastset) {
3085 ret = ldb_msg_add_empty(io->ac->update_msg,
3086 "pwdLastSet",
3087 el_flags, NULL);
3088 if (ret != LDB_SUCCESS) {
3089 return ret;
3093 if (io->g.nt_hash != NULL) {
3094 ret = samdb_msg_add_hash(ldb, io->ac,
3095 io->ac->update_msg,
3096 "unicodePwd",
3097 io->g.nt_hash);
3098 if (ret != LDB_SUCCESS) {
3099 return ret;
3102 if (io->g.lm_hash != NULL) {
3103 ret = samdb_msg_add_hash(ldb, io->ac,
3104 io->ac->update_msg,
3105 "dBCSPwd",
3106 io->g.lm_hash);
3107 if (ret != LDB_SUCCESS) {
3108 return ret;
3111 if (io->g.nt_history_len > 0) {
3112 ret = samdb_msg_add_hashes(ldb, io->ac,
3113 io->ac->update_msg,
3114 "ntPwdHistory",
3115 io->g.nt_history,
3116 io->g.nt_history_len);
3117 if (ret != LDB_SUCCESS) {
3118 return ret;
3121 if (io->g.lm_history_len > 0) {
3122 ret = samdb_msg_add_hashes(ldb, io->ac,
3123 io->ac->update_msg,
3124 "lmPwdHistory",
3125 io->g.lm_history,
3126 io->g.lm_history_len);
3127 if (ret != LDB_SUCCESS) {
3128 return ret;
3131 if (io->g.supplemental.length > 0) {
3132 ret = ldb_msg_add_value(io->ac->update_msg,
3133 "supplementalCredentials",
3134 &io->g.supplemental, NULL);
3135 if (ret != LDB_SUCCESS) {
3136 return ret;
3139 if (io->ac->update_lastset) {
3140 ret = samdb_msg_add_uint64(ldb, io->ac,
3141 io->ac->update_msg,
3142 "pwdLastSet",
3143 io->g.last_set);
3144 if (ret != LDB_SUCCESS) {
3145 return ret;
3149 return LDB_SUCCESS;
3153 * This is intended for use by the "password_hash" module since there
3154 * password changes can be specified through one message element with the
3155 * new password (to set) and another one with the old password (to unset).
3157 * The first which sets a password (new value) can have flags
3158 * (LDB_FLAG_MOD_ADD, LDB_FLAG_MOD_REPLACE) but also none (on "add" operations
3159 * for entries). The latter (old value) has always specified
3160 * LDB_FLAG_MOD_DELETE.
3162 * Returns LDB_ERR_CONSTRAINT_VIOLATION and LDB_ERR_UNWILLING_TO_PERFORM if
3163 * matching message elements are malformed in respect to the set/change rules.
3164 * Otherwise it returns LDB_SUCCESS.
3166 static int msg_find_old_and_new_pwd_val(const struct ldb_message *msg,
3167 const char *name,
3168 enum ldb_request_type operation,
3169 const struct ldb_val **new_val,
3170 const struct ldb_val **old_val)
3172 unsigned int i;
3174 *new_val = NULL;
3175 *old_val = NULL;
3177 if (msg == NULL) {
3178 return LDB_SUCCESS;
3181 for (i = 0; i < msg->num_elements; i++) {
3182 if (ldb_attr_cmp(msg->elements[i].name, name) != 0) {
3183 continue;
3186 if ((operation == LDB_MODIFY) &&
3187 (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_DELETE)) {
3188 /* 0 values are allowed */
3189 if (msg->elements[i].num_values == 1) {
3190 *old_val = &msg->elements[i].values[0];
3191 } else if (msg->elements[i].num_values > 1) {
3192 return LDB_ERR_CONSTRAINT_VIOLATION;
3194 } else if ((operation == LDB_MODIFY) &&
3195 (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_REPLACE)) {
3196 if (msg->elements[i].num_values > 0) {
3197 *new_val = &msg->elements[i].values[msg->elements[i].num_values - 1];
3198 } else {
3199 return LDB_ERR_UNWILLING_TO_PERFORM;
3201 } else {
3202 /* Add operations and LDB_FLAG_MOD_ADD */
3203 if (msg->elements[i].num_values > 0) {
3204 *new_val = &msg->elements[i].values[msg->elements[i].num_values - 1];
3205 } else {
3206 return LDB_ERR_CONSTRAINT_VIOLATION;
3211 return LDB_SUCCESS;
3214 static int setup_io(struct ph_context *ac,
3215 const struct ldb_message *client_msg,
3216 const struct ldb_message *existing_msg,
3217 struct setup_password_fields_io *io)
3219 const struct ldb_val *quoted_utf16, *old_quoted_utf16, *lm_hash, *old_lm_hash;
3220 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3221 struct loadparm_context *lp_ctx = talloc_get_type(
3222 ldb_get_opaque(ldb, "loadparm"), struct loadparm_context);
3223 int ret;
3224 const struct ldb_message *info_msg = NULL;
3225 struct dom_sid *account_sid = NULL;
3226 int rodc_krbtgt = 0;
3228 ZERO_STRUCTP(io);
3230 /* Some operations below require kerberos contexts */
3232 if (existing_msg != NULL) {
3234 * This is a modify operation
3236 info_msg = existing_msg;
3237 } else {
3239 * This is an add operation
3241 info_msg = client_msg;
3244 ret = smb_krb5_init_context(ac,
3245 (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"),
3246 &io->smb_krb5_context);
3248 if (ret != 0) {
3250 * In the special case of mit krb5.conf vs heimdal, the includedir
3251 * statement causes ret == 22 (KRB5_CONFIG_BADFORMAT) to be returned.
3252 * We look for this case so that we can give a more instructional
3253 * message to the administrator.
3255 if (ret == KRB5_CONFIG_BADFORMAT || ret == EINVAL) {
3256 ldb_asprintf_errstring(ldb, "Failed to setup krb5_context: %s - "
3257 "This could be due to an invalid krb5 configuration. "
3258 "Please check your system's krb5 configuration is correct.",
3259 error_message(ret));
3260 } else {
3261 ldb_asprintf_errstring(ldb, "Failed to setup krb5_context: %s",
3262 error_message(ret));
3264 return LDB_ERR_OPERATIONS_ERROR;
3267 io->ac = ac;
3269 io->u.userAccountControl = ldb_msg_find_attr_as_uint(info_msg,
3270 "userAccountControl", 0);
3271 if (info_msg == existing_msg) {
3273 * We only take pwdLastSet from the existing object
3274 * otherwise we leave it as 0.
3276 * If no attribute is available, e.g. on deleted objects
3277 * we remember that as UINT64_MAX.
3279 io->u.pwdLastSet = samdb_result_nttime(info_msg, "pwdLastSet",
3280 UINT64_MAX);
3282 io->u.sAMAccountName = ldb_msg_find_attr_as_string(info_msg,
3283 "sAMAccountName", NULL);
3284 io->u.user_principal_name = ldb_msg_find_attr_as_string(info_msg,
3285 "userPrincipalName", NULL);
3286 io->u.displayName = ldb_msg_find_attr_as_string(info_msg,
3287 "displayName", NULL);
3289 /* Ensure it has an objectSID too */
3290 io->u.account_sid = samdb_result_dom_sid(ac, info_msg, "objectSid");
3291 if (io->u.account_sid != NULL) {
3292 NTSTATUS status;
3293 uint32_t rid = 0;
3295 status = dom_sid_split_rid(account_sid, io->u.account_sid, NULL, &rid);
3296 if (NT_STATUS_IS_OK(status)) {
3297 if (rid == DOMAIN_RID_KRBTGT) {
3298 io->u.is_krbtgt = true;
3303 rodc_krbtgt = ldb_msg_find_attr_as_int(info_msg,
3304 "msDS-SecondaryKrbTgtNumber", 0);
3305 if (rodc_krbtgt != 0) {
3306 io->u.is_krbtgt = true;
3309 if (io->u.sAMAccountName == NULL) {
3310 ldb_asprintf_errstring(ldb,
3311 "setup_io: sAMAccountName attribute is missing on %s for attempted password set/change",
3312 ldb_dn_get_linearized(info_msg->dn));
3314 return LDB_ERR_CONSTRAINT_VIOLATION;
3317 if (io->u.userAccountControl & UF_INTERDOMAIN_TRUST_ACCOUNT) {
3318 struct ldb_control *permit_trust = ldb_request_get_control(ac->req,
3319 DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID);
3321 if (permit_trust == NULL) {
3322 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
3323 ldb_asprintf_errstring(ldb,
3324 "%08X: %s - setup_io: changing the interdomain trust password "
3325 "on %s not allowed via LDAP. Use LSA or NETLOGON",
3326 W_ERROR_V(WERR_ACCESS_DENIED),
3327 ldb_strerror(ret),
3328 ldb_dn_get_linearized(info_msg->dn));
3329 return ret;
3333 /* Only non-trust accounts have restrictions (possibly this test is the
3334 * wrong way around, but we like to be restrictive if possible */
3335 io->u.restrictions = !(io->u.userAccountControl & UF_TRUST_ACCOUNT_MASK);
3337 if (io->u.is_krbtgt) {
3338 io->u.restrictions = 0;
3339 io->ac->status->domain_data.pwdHistoryLength =
3340 MAX(io->ac->status->domain_data.pwdHistoryLength, 3);
3343 if (ac->userPassword) {
3344 ret = msg_find_old_and_new_pwd_val(client_msg, "userPassword",
3345 ac->req->operation,
3346 &io->n.cleartext_utf8,
3347 &io->og.cleartext_utf8);
3348 if (ret != LDB_SUCCESS) {
3349 ldb_asprintf_errstring(ldb,
3350 "setup_io: "
3351 "it's only allowed to set the old password once!");
3352 return ret;
3356 if (io->n.cleartext_utf8 != NULL) {
3357 struct ldb_val *cleartext_utf8_blob;
3358 char *p;
3360 cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
3361 if (!cleartext_utf8_blob) {
3362 return ldb_oom(ldb);
3365 *cleartext_utf8_blob = *io->n.cleartext_utf8;
3367 /* make sure we have a null terminated string */
3368 p = talloc_strndup(cleartext_utf8_blob,
3369 (const char *)io->n.cleartext_utf8->data,
3370 io->n.cleartext_utf8->length);
3371 if ((p == NULL) && (io->n.cleartext_utf8->length > 0)) {
3372 return ldb_oom(ldb);
3374 cleartext_utf8_blob->data = (uint8_t *)p;
3376 io->n.cleartext_utf8 = cleartext_utf8_blob;
3379 ret = msg_find_old_and_new_pwd_val(client_msg, "clearTextPassword",
3380 ac->req->operation,
3381 &io->n.cleartext_utf16,
3382 &io->og.cleartext_utf16);
3383 if (ret != LDB_SUCCESS) {
3384 ldb_asprintf_errstring(ldb,
3385 "setup_io: "
3386 "it's only allowed to set the old password once!");
3387 return ret;
3390 /* this rather strange looking piece of code is there to
3391 handle a ldap client setting a password remotely using the
3392 unicodePwd ldap field. The syntax is that the password is
3393 in UTF-16LE, with a " at either end. Unfortunately the
3394 unicodePwd field is also used to store the nt hashes
3395 internally in Samba, and is used in the nt hash format on
3396 the wire in DRS replication, so we have a single name for
3397 two distinct values. The code below leaves us with a small
3398 chance (less than 1 in 2^32) of a mixup, if someone manages
3399 to create a MD4 hash which starts and ends in 0x22 0x00, as
3400 that would then be treated as a UTF16 password rather than
3401 a nthash */
3403 ret = msg_find_old_and_new_pwd_val(client_msg, "unicodePwd",
3404 ac->req->operation,
3405 &quoted_utf16,
3406 &old_quoted_utf16);
3407 if (ret != LDB_SUCCESS) {
3408 ldb_asprintf_errstring(ldb,
3409 "setup_io: "
3410 "it's only allowed to set the old password once!");
3411 return ret;
3414 /* Checks and converts the actual "unicodePwd" attribute */
3415 if (!ac->hash_values &&
3416 quoted_utf16 &&
3417 quoted_utf16->length >= 4 &&
3418 quoted_utf16->data[0] == '"' &&
3419 quoted_utf16->data[1] == 0 &&
3420 quoted_utf16->data[quoted_utf16->length-2] == '"' &&
3421 quoted_utf16->data[quoted_utf16->length-1] == 0) {
3422 struct ldb_val *quoted_utf16_2;
3424 if (io->n.cleartext_utf16) {
3425 /* refuse the change if someone wants to change with
3426 with both UTF16 possibilities at the same time... */
3427 ldb_asprintf_errstring(ldb,
3428 "setup_io: "
3429 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
3430 return LDB_ERR_UNWILLING_TO_PERFORM;
3434 * adapt the quoted UTF16 string to be a real
3435 * cleartext one
3437 quoted_utf16_2 = talloc(io->ac, struct ldb_val);
3438 if (quoted_utf16_2 == NULL) {
3439 return ldb_oom(ldb);
3442 quoted_utf16_2->data = quoted_utf16->data + 2;
3443 quoted_utf16_2->length = quoted_utf16->length-4;
3444 io->n.cleartext_utf16 = quoted_utf16_2;
3445 io->n.nt_hash = NULL;
3447 } else if (quoted_utf16) {
3448 /* We have only the hash available -> so no plaintext here */
3449 if (!ac->hash_values) {
3450 /* refuse the change if someone wants to change
3451 the hash without control specified... */
3452 ldb_asprintf_errstring(ldb,
3453 "setup_io: "
3454 "it's not allowed to set the NT hash password directly'");
3455 /* this looks odd but this is what Windows does:
3456 returns "UNWILLING_TO_PERFORM" on wrong
3457 password sets and "CONSTRAINT_VIOLATION" on
3458 wrong password changes. */
3459 if (old_quoted_utf16 == NULL) {
3460 return LDB_ERR_UNWILLING_TO_PERFORM;
3463 return LDB_ERR_CONSTRAINT_VIOLATION;
3466 io->n.nt_hash = talloc(io->ac, struct samr_Password);
3467 memcpy(io->n.nt_hash->hash, quoted_utf16->data,
3468 MIN(quoted_utf16->length, sizeof(io->n.nt_hash->hash)));
3471 /* Checks and converts the previous "unicodePwd" attribute */
3472 if (!ac->hash_values &&
3473 old_quoted_utf16 &&
3474 old_quoted_utf16->length >= 4 &&
3475 old_quoted_utf16->data[0] == '"' &&
3476 old_quoted_utf16->data[1] == 0 &&
3477 old_quoted_utf16->data[old_quoted_utf16->length-2] == '"' &&
3478 old_quoted_utf16->data[old_quoted_utf16->length-1] == 0) {
3479 struct ldb_val *old_quoted_utf16_2;
3481 if (io->og.cleartext_utf16) {
3482 /* refuse the change if someone wants to change with
3483 both UTF16 possibilities at the same time... */
3484 ldb_asprintf_errstring(ldb,
3485 "setup_io: "
3486 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
3487 return LDB_ERR_UNWILLING_TO_PERFORM;
3491 * adapt the quoted UTF16 string to be a real
3492 * cleartext one
3494 old_quoted_utf16_2 = talloc(io->ac, struct ldb_val);
3495 if (old_quoted_utf16_2 == NULL) {
3496 return ldb_oom(ldb);
3499 old_quoted_utf16_2->data = old_quoted_utf16->data + 2;
3500 old_quoted_utf16_2->length = old_quoted_utf16->length-4;
3502 io->og.cleartext_utf16 = old_quoted_utf16_2;
3503 io->og.nt_hash = NULL;
3504 } else if (old_quoted_utf16) {
3505 /* We have only the hash available -> so no plaintext here */
3506 if (!ac->hash_values) {
3507 /* refuse the change if someone wants to change
3508 the hash without control specified... */
3509 ldb_asprintf_errstring(ldb,
3510 "setup_io: "
3511 "it's not allowed to set the NT hash password directly'");
3512 return LDB_ERR_UNWILLING_TO_PERFORM;
3515 io->og.nt_hash = talloc(io->ac, struct samr_Password);
3516 memcpy(io->og.nt_hash->hash, old_quoted_utf16->data,
3517 MIN(old_quoted_utf16->length, sizeof(io->og.nt_hash->hash)));
3520 /* Handles the "dBCSPwd" attribute (LM hash) */
3521 io->n.lm_hash = NULL; io->og.lm_hash = NULL;
3522 ret = msg_find_old_and_new_pwd_val(client_msg, "dBCSPwd",
3523 ac->req->operation,
3524 &lm_hash, &old_lm_hash);
3525 if (ret != LDB_SUCCESS) {
3526 ldb_asprintf_errstring(ldb,
3527 "setup_io: "
3528 "it's only allowed to set the old password once!");
3529 return ret;
3532 if (((lm_hash != NULL) || (old_lm_hash != NULL)) && (!ac->hash_values)) {
3533 /* refuse the change if someone wants to change the hash
3534 without control specified... */
3535 ldb_asprintf_errstring(ldb,
3536 "setup_io: "
3537 "it's not allowed to set the LM hash password directly'");
3538 return LDB_ERR_UNWILLING_TO_PERFORM;
3541 if (lpcfg_lanman_auth(lp_ctx) && (lm_hash != NULL)) {
3542 io->n.lm_hash = talloc(io->ac, struct samr_Password);
3543 memcpy(io->n.lm_hash->hash, lm_hash->data, MIN(lm_hash->length,
3544 sizeof(io->n.lm_hash->hash)));
3546 if (lpcfg_lanman_auth(lp_ctx) && (old_lm_hash != NULL)) {
3547 io->og.lm_hash = talloc(io->ac, struct samr_Password);
3548 memcpy(io->og.lm_hash->hash, old_lm_hash->data, MIN(old_lm_hash->length,
3549 sizeof(io->og.lm_hash->hash)));
3553 * Handles the password change control if it's specified. It has the
3554 * precedance and overrides already specified old password values of
3555 * change requests (but that shouldn't happen since the control is
3556 * fully internal and only used in conjunction with replace requests!).
3558 if (ac->change != NULL) {
3559 io->og.nt_hash = NULL;
3560 if (ac->change->old_nt_pwd_hash != NULL) {
3561 io->og.nt_hash = talloc_memdup(io->ac,
3562 ac->change->old_nt_pwd_hash,
3563 sizeof(struct samr_Password));
3565 io->og.lm_hash = NULL;
3566 if (lpcfg_lanman_auth(lp_ctx) && (ac->change->old_lm_pwd_hash != NULL)) {
3567 io->og.lm_hash = talloc_memdup(io->ac,
3568 ac->change->old_lm_pwd_hash,
3569 sizeof(struct samr_Password));
3573 /* refuse the change if someone wants to change the clear-
3574 text and supply his own hashes at the same time... */
3575 if ((io->n.cleartext_utf8 || io->n.cleartext_utf16)
3576 && (io->n.nt_hash || io->n.lm_hash)) {
3577 ldb_asprintf_errstring(ldb,
3578 "setup_io: "
3579 "it's only allowed to set the password in form of cleartext attributes or as hashes");
3580 return LDB_ERR_UNWILLING_TO_PERFORM;
3583 /* refuse the change if someone wants to change the password
3584 using both plaintext methods (UTF8 and UTF16) at the same time... */
3585 if (io->n.cleartext_utf8 && io->n.cleartext_utf16) {
3586 ldb_asprintf_errstring(ldb,
3587 "setup_io: "
3588 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
3589 return LDB_ERR_UNWILLING_TO_PERFORM;
3592 /* refuse the change if someone tries to set/change the password by
3593 * the lanman hash alone and we've deactivated that mechanism. This
3594 * would end in an account without any password! */
3595 if (io->ac->update_password
3596 && (!io->n.cleartext_utf8) && (!io->n.cleartext_utf16)
3597 && (!io->n.nt_hash) && (!io->n.lm_hash)) {
3598 ldb_asprintf_errstring(ldb,
3599 "setup_io: "
3600 "It's not possible to delete the password (changes using the LAN Manager hash alone could be deactivated)!");
3601 /* on "userPassword" and "clearTextPassword" we've to return
3602 * something different, since these are virtual attributes */
3603 if ((ldb_msg_find_element(client_msg, "userPassword") != NULL) ||
3604 (ldb_msg_find_element(client_msg, "clearTextPassword") != NULL)) {
3605 return LDB_ERR_CONSTRAINT_VIOLATION;
3607 return LDB_ERR_UNWILLING_TO_PERFORM;
3610 /* refuse the change if someone wants to compare against a plaintext
3611 or hash at the same time for a "password modify" operation... */
3612 if ((io->og.cleartext_utf8 || io->og.cleartext_utf16)
3613 && (io->og.nt_hash || io->og.lm_hash)) {
3614 ldb_asprintf_errstring(ldb,
3615 "setup_io: "
3616 "it's only allowed to provide the old password in form of cleartext attributes or as hashes");
3617 return LDB_ERR_UNWILLING_TO_PERFORM;
3620 /* refuse the change if someone wants to compare against both
3621 * plaintexts at the same time for a "password modify" operation... */
3622 if (io->og.cleartext_utf8 && io->og.cleartext_utf16) {
3623 ldb_asprintf_errstring(ldb,
3624 "setup_io: "
3625 "it's only allowed to provide the old cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
3626 return LDB_ERR_UNWILLING_TO_PERFORM;
3629 /* Decides if we have a password modify or password reset operation */
3630 if (ac->req->operation == LDB_ADD) {
3631 /* On "add" we have only "password reset" */
3632 ac->pwd_reset = true;
3633 } else if (ac->req->operation == LDB_MODIFY) {
3634 struct ldb_control *pav_ctrl = NULL;
3635 struct dsdb_control_password_acl_validation *pav = NULL;
3637 pav_ctrl = ldb_request_get_control(ac->req,
3638 DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
3639 if (pav_ctrl != NULL) {
3640 pav = talloc_get_type_abort(pav_ctrl->data,
3641 struct dsdb_control_password_acl_validation);
3644 if (pav == NULL && ac->update_password) {
3645 bool ok;
3648 * If the DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID
3649 * control is missing, we require system access!
3651 ok = dsdb_module_am_system(ac->module);
3652 if (!ok) {
3653 return ldb_module_operr(ac->module);
3657 if (pav != NULL) {
3659 * We assume what the acl module has validated.
3661 ac->pwd_reset = pav->pwd_reset;
3662 } else if (io->og.cleartext_utf8 || io->og.cleartext_utf16
3663 || io->og.nt_hash || io->og.lm_hash) {
3664 /* If we have an old password specified then for sure it
3665 * is a user "password change" */
3666 ac->pwd_reset = false;
3667 } else {
3668 /* Otherwise we have also here a "password reset" */
3669 ac->pwd_reset = true;
3671 } else {
3672 /* this shouldn't happen */
3673 return ldb_operr(ldb);
3676 if (io->u.is_krbtgt) {
3677 size_t min = 196;
3678 size_t max = 255;
3679 size_t diff = max - min;
3680 size_t len = max;
3681 struct ldb_val *krbtgt_utf16 = NULL;
3683 if (!ac->pwd_reset) {
3684 return dsdb_module_werror(ac->module,
3685 LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS,
3686 WERR_DS_ATT_ALREADY_EXISTS,
3687 "Password change on krbtgt not permitted!");
3690 if (io->n.cleartext_utf16 == NULL) {
3691 return dsdb_module_werror(ac->module,
3692 LDB_ERR_UNWILLING_TO_PERFORM,
3693 WERR_DS_INVALID_ATTRIBUTE_SYNTAX,
3694 "Password reset on krbtgt requires UTF16!");
3698 * Instead of taking the callers value,
3699 * we just generate a new random value here.
3701 * Include null termination in the array.
3703 if (diff > 0) {
3704 size_t tmp;
3706 generate_random_buffer((uint8_t *)&tmp, sizeof(tmp));
3708 tmp %= diff;
3710 len = min + tmp;
3713 krbtgt_utf16 = talloc_zero(io->ac, struct ldb_val);
3714 if (krbtgt_utf16 == NULL) {
3715 return ldb_oom(ldb);
3718 *krbtgt_utf16 = data_blob_talloc_zero(krbtgt_utf16,
3719 (len+1)*2);
3720 if (krbtgt_utf16->data == NULL) {
3721 return ldb_oom(ldb);
3723 krbtgt_utf16->length = len * 2;
3724 generate_secret_buffer(krbtgt_utf16->data,
3725 krbtgt_utf16->length);
3726 io->n.cleartext_utf16 = krbtgt_utf16;
3729 if (existing_msg != NULL) {
3730 NTSTATUS status;
3732 if (ac->pwd_reset) {
3733 /* Get the old password from the database */
3734 status = samdb_result_passwords_no_lockout(ac,
3735 lp_ctx,
3736 existing_msg,
3737 &io->o.lm_hash,
3738 &io->o.nt_hash);
3739 } else {
3740 /* Get the old password from the database */
3741 status = samdb_result_passwords(ac,
3742 lp_ctx,
3743 existing_msg,
3744 &io->o.lm_hash,
3745 &io->o.nt_hash);
3748 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCOUNT_LOCKED_OUT)) {
3749 return dsdb_module_werror(ac->module,
3750 LDB_ERR_CONSTRAINT_VIOLATION,
3751 WERR_ACCOUNT_LOCKED_OUT,
3752 "Password change not permitted,"
3753 " account locked out!");
3756 if (!NT_STATUS_IS_OK(status)) {
3758 * This only happens if the database has gone weird,
3759 * not if we are just missing the passwords
3761 return ldb_operr(ldb);
3764 io->o.nt_history_len = samdb_result_hashes(ac, existing_msg,
3765 "ntPwdHistory",
3766 &io->o.nt_history);
3767 io->o.lm_history_len = samdb_result_hashes(ac, existing_msg,
3768 "lmPwdHistory",
3769 &io->o.lm_history);
3770 io->o.supplemental = ldb_msg_find_ldb_val(existing_msg,
3771 "supplementalCredentials");
3773 if (io->o.supplemental != NULL) {
3774 enum ndr_err_code ndr_err;
3776 ndr_err = ndr_pull_struct_blob_all(io->o.supplemental, io->ac,
3777 &io->o.scb,
3778 (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
3779 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3780 status = ndr_map_error2ntstatus(ndr_err);
3781 ldb_asprintf_errstring(ldb,
3782 "setup_io: failed to pull "
3783 "old supplementalCredentialsBlob: %s",
3784 nt_errstr(status));
3785 return LDB_ERR_OPERATIONS_ERROR;
3790 return LDB_SUCCESS;
3793 static struct ph_context *ph_init_context(struct ldb_module *module,
3794 struct ldb_request *req,
3795 bool userPassword,
3796 bool update_password)
3798 struct ldb_context *ldb;
3799 struct ph_context *ac;
3800 struct loadparm_context *lp_ctx = NULL;
3802 ldb = ldb_module_get_ctx(module);
3804 ac = talloc_zero(req, struct ph_context);
3805 if (ac == NULL) {
3806 ldb_set_errstring(ldb, "Out of Memory");
3807 return NULL;
3810 ac->module = module;
3811 ac->req = req;
3812 ac->userPassword = userPassword;
3813 ac->update_password = update_password;
3814 ac->update_lastset = true;
3816 lp_ctx = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"),
3817 struct loadparm_context);
3818 ac->gpg_key_ids = lpcfg_password_hash_gpg_key_ids(lp_ctx);
3819 ac->userPassword_schemes
3820 = lpcfg_password_hash_userpassword_schemes(lp_ctx);
3821 return ac;
3824 static void ph_apply_controls(struct ph_context *ac)
3826 struct ldb_control *ctrl;
3828 ac->change_status = false;
3829 ctrl = ldb_request_get_control(ac->req,
3830 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID);
3831 if (ctrl != NULL) {
3832 ac->change_status = true;
3834 /* Mark the "change status" control as uncritical (done) */
3835 ctrl->critical = false;
3838 ac->hash_values = false;
3839 ctrl = ldb_request_get_control(ac->req,
3840 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID);
3841 if (ctrl != NULL) {
3842 ac->hash_values = true;
3844 /* Mark the "hash values" control as uncritical (done) */
3845 ctrl->critical = false;
3848 ctrl = ldb_request_get_control(ac->req,
3849 DSDB_CONTROL_PASSWORD_CHANGE_OID);
3850 if (ctrl != NULL) {
3851 ac->change = (struct dsdb_control_password_change *) ctrl->data;
3853 /* Mark the "change" control as uncritical (done) */
3854 ctrl->critical = false;
3857 ac->pwd_last_set_bypass = false;
3858 ctrl = ldb_request_get_control(ac->req,
3859 DSDB_CONTROL_PASSWORD_BYPASS_LAST_SET_OID);
3860 if (ctrl != NULL) {
3861 ac->pwd_last_set_bypass = true;
3863 /* Mark the "bypass pwdLastSet" control as uncritical (done) */
3864 ctrl->critical = false;
3867 ac->pwd_last_set_default = false;
3868 ctrl = ldb_request_get_control(ac->req,
3869 DSDB_CONTROL_PASSWORD_DEFAULT_LAST_SET_OID);
3870 if (ctrl != NULL) {
3871 ac->pwd_last_set_default = true;
3873 /* Mark the "bypass pwdLastSet" control as uncritical (done) */
3874 ctrl->critical = false;
3877 ac->smartcard_reset = false;
3878 ctrl = ldb_request_get_control(ac->req,
3879 DSDB_CONTROL_PASSWORD_USER_ACCOUNT_CONTROL_OID);
3880 if (ctrl != NULL) {
3881 struct dsdb_control_password_user_account_control *uac = NULL;
3882 uint32_t added_flags = 0;
3884 uac = talloc_get_type_abort(ctrl->data,
3885 struct dsdb_control_password_user_account_control);
3887 added_flags = uac->new_flags & ~uac->old_flags;
3889 if (added_flags & UF_SMARTCARD_REQUIRED) {
3890 ac->smartcard_reset = true;
3893 /* Mark the "smartcard required" control as uncritical (done) */
3894 ctrl->critical = false;
3898 static int ph_op_callback(struct ldb_request *req, struct ldb_reply *ares)
3900 struct ph_context *ac;
3902 ac = talloc_get_type(req->context, struct ph_context);
3904 if (!ares) {
3905 return ldb_module_done(ac->req, NULL, NULL,
3906 LDB_ERR_OPERATIONS_ERROR);
3909 if (ares->type == LDB_REPLY_REFERRAL) {
3910 return ldb_module_send_referral(ac->req, ares->referral);
3913 if ((ares->error != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
3914 /* On success and trivial errors a status control is being
3915 * added (used for example by the "samdb_set_password" call) */
3916 ldb_reply_add_control(ares,
3917 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
3918 false,
3919 ac->status);
3922 if (ares->error != LDB_SUCCESS) {
3923 return ldb_module_done(ac->req, ares->controls,
3924 ares->response, ares->error);
3927 if (ares->type != LDB_REPLY_DONE) {
3928 talloc_free(ares);
3929 return ldb_module_done(ac->req, NULL, NULL,
3930 LDB_ERR_OPERATIONS_ERROR);
3933 return ldb_module_done(ac->req, ares->controls,
3934 ares->response, ares->error);
3937 static int password_hash_add_do_add(struct ph_context *ac);
3938 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares);
3939 static int password_hash_mod_search_self(struct ph_context *ac);
3940 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares);
3941 static int password_hash_mod_do_mod(struct ph_context *ac);
3944 * LDB callback handler for searching for a user's PSO. Once we have all the
3945 * Password Settings that apply to the user, we can continue with the modify
3946 * operation
3948 static int get_pso_data_callback(struct ldb_request *req,
3949 struct ldb_reply *ares)
3951 struct ldb_context *ldb = NULL;
3952 struct ph_context *ac = NULL;
3953 bool domain_complexity = true;
3954 bool pso_complexity = true;
3955 struct dsdb_user_pwd_settings *settings = NULL;
3956 int ret = LDB_SUCCESS;
3958 ac = talloc_get_type(req->context, struct ph_context);
3959 ldb = ldb_module_get_ctx(ac->module);
3961 if (!ares) {
3962 ret = LDB_ERR_OPERATIONS_ERROR;
3963 goto done;
3965 if (ares->error != LDB_SUCCESS) {
3966 return ldb_module_done(ac->req, ares->controls,
3967 ares->response, ares->error);
3970 switch (ares->type) {
3971 case LDB_REPLY_ENTRY:
3973 /* check status was initialized by the domain query */
3974 if (ac->status == NULL) {
3975 talloc_free(ares);
3976 ldb_set_errstring(ldb, "Uninitialized status");
3977 ret = LDB_ERR_OPERATIONS_ERROR;
3978 goto done;
3982 * use the PSO's values instead of the domain defaults (the PSO
3983 * attributes should always exist, but use the domain default
3984 * values as a fallback).
3986 settings = &ac->status->domain_data;
3987 settings->store_cleartext =
3988 ldb_msg_find_attr_as_bool(ares->message,
3989 "msDS-PasswordReversibleEncryptionEnabled",
3990 settings->store_cleartext);
3992 settings->pwdHistoryLength =
3993 ldb_msg_find_attr_as_uint(ares->message,
3994 "msDS-PasswordHistoryLength",
3995 settings->pwdHistoryLength);
3996 settings->maxPwdAge =
3997 ldb_msg_find_attr_as_int64(ares->message,
3998 "msDS-MaximumPasswordAge",
3999 settings->maxPwdAge);
4000 settings->minPwdAge =
4001 ldb_msg_find_attr_as_int64(ares->message,
4002 "msDS-MinimumPasswordAge",
4003 settings->minPwdAge);
4004 settings->minPwdLength =
4005 ldb_msg_find_attr_as_uint(ares->message,
4006 "msDS-MinimumPasswordLength",
4007 settings->minPwdLength);
4008 domain_complexity =
4009 (settings->pwdProperties & DOMAIN_PASSWORD_COMPLEX);
4010 pso_complexity =
4011 ldb_msg_find_attr_as_bool(ares->message,
4012 "msDS-PasswordComplexityEnabled",
4013 domain_complexity);
4015 /* set or clear the complexity bit if required */
4016 if (pso_complexity && !domain_complexity) {
4017 settings->pwdProperties |= DOMAIN_PASSWORD_COMPLEX;
4018 } else if (domain_complexity && !pso_complexity) {
4019 settings->pwdProperties &= ~DOMAIN_PASSWORD_COMPLEX;
4022 if (ac->pso_res != NULL) {
4023 DBG_ERR("Too many PSO results for %s",
4024 ldb_dn_get_linearized(ac->search_res->message->dn));
4025 talloc_free(ac->pso_res);
4028 /* store the PSO result (we may need its lockout settings) */
4029 ac->pso_res = talloc_steal(ac, ares);
4030 ret = LDB_SUCCESS;
4031 break;
4033 case LDB_REPLY_REFERRAL:
4034 /* ignore */
4035 talloc_free(ares);
4036 ret = LDB_SUCCESS;
4037 break;
4039 case LDB_REPLY_DONE:
4040 talloc_free(ares);
4043 * perform the next step of the modify operation (this code
4044 * shouldn't get called in the 'user add' case)
4046 if (ac->req->operation == LDB_MODIFY) {
4047 ret = password_hash_mod_do_mod(ac);
4048 } else {
4049 ret = LDB_ERR_OPERATIONS_ERROR;
4051 break;
4054 done:
4055 if (ret != LDB_SUCCESS) {
4056 struct ldb_reply *new_ares;
4058 new_ares = talloc_zero(ac->req, struct ldb_reply);
4059 if (new_ares == NULL) {
4060 ldb_oom(ldb);
4061 return ldb_module_done(ac->req, NULL, NULL,
4062 LDB_ERR_OPERATIONS_ERROR);
4065 new_ares->error = ret;
4066 if ((ret != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
4067 /* On success and trivial errors a status control is being
4068 * added (used for example by the "samdb_set_password" call) */
4069 ldb_reply_add_control(new_ares,
4070 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
4071 false,
4072 ac->status);
4075 return ldb_module_done(ac->req, new_ares->controls,
4076 new_ares->response, new_ares->error);
4079 return LDB_SUCCESS;
4083 * Builds and returns a search request to lookup up the PSO that applies to
4084 * the user in question. Returns NULL if no PSO applies, or could not be found
4086 static struct ldb_request * build_pso_data_request(struct ph_context *ac)
4088 /* attrs[] is returned from this function in
4089 pso_req->op.search.attrs, so it must be static, as
4090 otherwise the compiler can put it on the stack */
4091 static const char * const attrs[] = { "msDS-PasswordComplexityEnabled",
4092 "msDS-PasswordReversibleEncryptionEnabled",
4093 "msDS-PasswordHistoryLength",
4094 "msDS-MaximumPasswordAge",
4095 "msDS-MinimumPasswordAge",
4096 "msDS-MinimumPasswordLength",
4097 "msDS-LockoutThreshold",
4098 "msDS-LockoutObservationWindow",
4099 NULL };
4100 struct ldb_context *ldb = NULL;
4101 struct ldb_request *pso_req = NULL;
4102 struct ldb_dn *pso_dn = NULL;
4103 TALLOC_CTX *mem_ctx = ac;
4104 int ret;
4106 ldb = ldb_module_get_ctx(ac->module);
4108 /* if a PSO applies to the user, we need to lookup the PSO as well */
4109 pso_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, ac->search_res->message,
4110 "msDS-ResultantPSO");
4111 if (pso_dn == NULL) {
4112 return NULL;
4115 ret = ldb_build_search_req(&pso_req, ldb, mem_ctx, pso_dn,
4116 LDB_SCOPE_BASE, NULL, attrs, NULL,
4117 ac, get_pso_data_callback,
4118 ac->dom_req);
4120 /* log errors, but continue with the default domain settings */
4121 if (ret != LDB_SUCCESS) {
4122 DBG_ERR("Error %d constructing PSO query for user %s", ret,
4123 ldb_dn_get_linearized(ac->search_res->message->dn));
4125 LDB_REQ_SET_LOCATION(pso_req);
4126 return pso_req;
4130 static int get_domain_data_callback(struct ldb_request *req,
4131 struct ldb_reply *ares)
4133 struct ldb_context *ldb;
4134 struct ph_context *ac;
4135 struct loadparm_context *lp_ctx;
4136 struct ldb_request *pso_req = NULL;
4137 int ret = LDB_SUCCESS;
4139 ac = talloc_get_type(req->context, struct ph_context);
4140 ldb = ldb_module_get_ctx(ac->module);
4142 if (!ares) {
4143 ret = LDB_ERR_OPERATIONS_ERROR;
4144 goto done;
4146 if (ares->error != LDB_SUCCESS) {
4147 return ldb_module_done(ac->req, ares->controls,
4148 ares->response, ares->error);
4151 switch (ares->type) {
4152 case LDB_REPLY_ENTRY:
4153 if (ac->status != NULL) {
4154 talloc_free(ares);
4156 ldb_set_errstring(ldb, "Too many results");
4157 ret = LDB_ERR_OPERATIONS_ERROR;
4158 goto done;
4161 /* Setup the "status" structure (used as control later) */
4162 ac->status = talloc_zero(ac->req,
4163 struct dsdb_control_password_change_status);
4164 if (ac->status == NULL) {
4165 talloc_free(ares);
4167 ldb_oom(ldb);
4168 ret = LDB_ERR_OPERATIONS_ERROR;
4169 goto done;
4172 /* Setup the "domain data" structure */
4173 ac->status->domain_data.pwdProperties =
4174 ldb_msg_find_attr_as_uint(ares->message, "pwdProperties", -1);
4175 ac->status->domain_data.pwdHistoryLength =
4176 ldb_msg_find_attr_as_uint(ares->message, "pwdHistoryLength", -1);
4177 ac->status->domain_data.maxPwdAge =
4178 ldb_msg_find_attr_as_int64(ares->message, "maxPwdAge", -1);
4179 ac->status->domain_data.minPwdAge =
4180 ldb_msg_find_attr_as_int64(ares->message, "minPwdAge", -1);
4181 ac->status->domain_data.minPwdLength =
4182 ldb_msg_find_attr_as_uint(ares->message, "minPwdLength", -1);
4183 ac->status->domain_data.store_cleartext =
4184 ac->status->domain_data.pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
4186 /* For a domain DN, this puts things in dotted notation */
4187 /* For builtin domains, this will give details for the host,
4188 * but that doesn't really matter, as it's just used for salt
4189 * and kerberos principals, which don't exist here */
4191 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
4192 struct loadparm_context);
4194 ac->status->domain_data.dns_domain = lpcfg_dnsdomain(lp_ctx);
4195 ac->status->domain_data.realm = lpcfg_realm(lp_ctx);
4196 ac->status->domain_data.netbios_domain = lpcfg_sam_name(lp_ctx);
4198 ac->status->reject_reason = SAM_PWD_CHANGE_NO_ERROR;
4200 if (ac->dom_res != NULL) {
4201 talloc_free(ares);
4203 ldb_set_errstring(ldb, "Too many results");
4204 ret = LDB_ERR_OPERATIONS_ERROR;
4205 goto done;
4208 ac->dom_res = talloc_steal(ac, ares);
4209 ret = LDB_SUCCESS;
4210 break;
4212 case LDB_REPLY_REFERRAL:
4213 /* ignore */
4214 talloc_free(ares);
4215 ret = LDB_SUCCESS;
4216 break;
4218 case LDB_REPLY_DONE:
4219 talloc_free(ares);
4220 /* call the next step */
4221 switch (ac->req->operation) {
4222 case LDB_ADD:
4223 ret = password_hash_add_do_add(ac);
4224 break;
4226 case LDB_MODIFY:
4229 * The user may have an optional PSO applied. If so,
4230 * query the PSO to get the Fine-Grained Password Policy
4231 * for the user, before we perform the modify
4233 pso_req = build_pso_data_request(ac);
4234 if (pso_req != NULL) {
4235 ret = ldb_next_request(ac->module, pso_req);
4236 } else {
4238 /* no PSO, so we can perform the modify now */
4239 ret = password_hash_mod_do_mod(ac);
4241 break;
4243 default:
4244 ret = LDB_ERR_OPERATIONS_ERROR;
4245 break;
4247 break;
4250 done:
4251 if (ret != LDB_SUCCESS) {
4252 struct ldb_reply *new_ares;
4254 new_ares = talloc_zero(ac->req, struct ldb_reply);
4255 if (new_ares == NULL) {
4256 ldb_oom(ldb);
4257 return ldb_module_done(ac->req, NULL, NULL,
4258 LDB_ERR_OPERATIONS_ERROR);
4261 new_ares->error = ret;
4262 if ((ret != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
4263 /* On success and trivial errors a status control is being
4264 * added (used for example by the "samdb_set_password" call) */
4265 ldb_reply_add_control(new_ares,
4266 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
4267 false,
4268 ac->status);
4271 return ldb_module_done(ac->req, new_ares->controls,
4272 new_ares->response, new_ares->error);
4275 return LDB_SUCCESS;
4278 static int build_domain_data_request(struct ph_context *ac)
4280 /* attrs[] is returned from this function in
4281 ac->dom_req->op.search.attrs, so it must be static, as
4282 otherwise the compiler can put it on the stack */
4283 struct ldb_context *ldb;
4284 static const char * const attrs[] = { "pwdProperties",
4285 "pwdHistoryLength",
4286 "maxPwdAge",
4287 "minPwdAge",
4288 "minPwdLength",
4289 "lockoutThreshold",
4290 "lockOutObservationWindow",
4291 NULL };
4292 int ret;
4294 ldb = ldb_module_get_ctx(ac->module);
4296 ret = ldb_build_search_req(&ac->dom_req, ldb, ac,
4297 ldb_get_default_basedn(ldb),
4298 LDB_SCOPE_BASE,
4299 NULL, attrs,
4300 NULL,
4301 ac, get_domain_data_callback,
4302 ac->req);
4303 LDB_REQ_SET_LOCATION(ac->dom_req);
4304 return ret;
4307 static int password_hash_needed(struct ldb_module *module,
4308 struct ldb_request *req,
4309 struct ph_context **_ac)
4311 struct ldb_context *ldb = ldb_module_get_ctx(module);
4312 const char *operation = NULL;
4313 const struct ldb_message *msg = NULL;
4314 struct ph_context *ac = NULL;
4315 const char *passwordAttrs[] = {
4316 DSDB_PASSWORD_ATTRIBUTES,
4317 NULL
4319 const char **a = NULL;
4320 unsigned int attr_cnt = 0;
4321 struct ldb_control *bypass = NULL;
4322 struct ldb_control *uac_ctrl = NULL;
4323 bool userPassword = dsdb_user_password_support(module, req, req);
4324 bool update_password = false;
4325 bool processing_needed = false;
4327 *_ac = NULL;
4329 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_needed\n");
4331 switch (req->operation) {
4332 case LDB_ADD:
4333 operation = "add";
4334 msg = req->op.add.message;
4335 break;
4336 case LDB_MODIFY:
4337 operation = "modify";
4338 msg = req->op.mod.message;
4339 break;
4340 default:
4341 return ldb_next_request(module, req);
4344 if (ldb_dn_is_special(msg->dn)) { /* do not manipulate our control entries */
4345 return ldb_next_request(module, req);
4348 bypass = ldb_request_get_control(req,
4349 DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID);
4350 if (bypass != NULL) {
4351 /* Mark the "bypass" control as uncritical (done) */
4352 bypass->critical = false;
4353 ldb_debug(ldb, LDB_DEBUG_TRACE,
4354 "password_hash_needed(%s) (bypassing)\n",
4355 operation);
4356 return password_hash_bypass(module, req);
4359 /* nobody must touch password histories and 'supplementalCredentials' */
4360 if (ldb_msg_find_element(msg, "ntPwdHistory")) {
4361 return LDB_ERR_UNWILLING_TO_PERFORM;
4363 if (ldb_msg_find_element(msg, "lmPwdHistory")) {
4364 return LDB_ERR_UNWILLING_TO_PERFORM;
4366 if (ldb_msg_find_element(msg, "supplementalCredentials")) {
4367 return LDB_ERR_UNWILLING_TO_PERFORM;
4371 * If no part of this touches the 'userPassword' OR 'clearTextPassword'
4372 * OR 'unicodePwd' OR 'dBCSPwd' we don't need to make any changes.
4373 * For password changes/set there should be a 'delete' or a 'modify'
4374 * on these attributes.
4376 for (a = passwordAttrs; *a != NULL; a++) {
4377 if ((!userPassword) && (ldb_attr_cmp(*a, "userPassword") == 0)) {
4378 continue;
4381 if (ldb_msg_find_element(msg, *a) != NULL) {
4382 /* MS-ADTS 3.1.1.3.1.5.2 */
4383 if ((ldb_attr_cmp(*a, "userPassword") == 0) &&
4384 (dsdb_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
4385 return LDB_ERR_CONSTRAINT_VIOLATION;
4388 ++attr_cnt;
4392 if (attr_cnt > 0) {
4393 update_password = true;
4394 processing_needed = true;
4397 if (ldb_msg_find_element(msg, "pwdLastSet")) {
4398 processing_needed = true;
4401 uac_ctrl = ldb_request_get_control(req,
4402 DSDB_CONTROL_PASSWORD_USER_ACCOUNT_CONTROL_OID);
4403 if (uac_ctrl != NULL) {
4404 struct dsdb_control_password_user_account_control *uac = NULL;
4405 uint32_t added_flags = 0;
4407 uac = talloc_get_type_abort(uac_ctrl->data,
4408 struct dsdb_control_password_user_account_control);
4410 added_flags = uac->new_flags & ~uac->old_flags;
4412 if (added_flags & UF_SMARTCARD_REQUIRED) {
4413 processing_needed = true;
4417 if (!processing_needed) {
4418 return ldb_next_request(module, req);
4421 ac = ph_init_context(module, req, userPassword, update_password);
4422 if (!ac) {
4423 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
4424 return ldb_operr(ldb);
4426 ph_apply_controls(ac);
4429 * Make a copy in order to apply our modifications
4430 * to the final update
4432 ac->update_msg = ldb_msg_copy_shallow(ac, msg);
4433 if (ac->update_msg == NULL) {
4434 return ldb_oom(ldb);
4438 * Remove all password related attributes.
4440 if (ac->userPassword) {
4441 ldb_msg_remove_attr(ac->update_msg, "userPassword");
4443 ldb_msg_remove_attr(ac->update_msg, "clearTextPassword");
4444 ldb_msg_remove_attr(ac->update_msg, "unicodePwd");
4445 ldb_msg_remove_attr(ac->update_msg, "ntPwdHistory");
4446 ldb_msg_remove_attr(ac->update_msg, "dBCSPwd");
4447 ldb_msg_remove_attr(ac->update_msg, "lmPwdHistory");
4448 ldb_msg_remove_attr(ac->update_msg, "supplementalCredentials");
4449 ldb_msg_remove_attr(ac->update_msg, "pwdLastSet");
4451 *_ac = ac;
4452 return LDB_SUCCESS;
4455 static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
4457 struct ldb_context *ldb = ldb_module_get_ctx(module);
4458 struct ph_context *ac = NULL;
4459 int ret;
4461 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add\n");
4463 ret = password_hash_needed(module, req, &ac);
4464 if (ret != LDB_SUCCESS) {
4465 return ret;
4467 if (ac == NULL) {
4468 return ret;
4471 /* Make sure we are performing the password set action on a (for us)
4472 * valid object. Those are instances of either "user" and/or
4473 * "inetOrgPerson". Otherwise continue with the submodules. */
4474 if ((!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "user"))
4475 && (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "inetOrgPerson"))) {
4477 TALLOC_FREE(ac);
4479 if (ldb_msg_find_element(req->op.add.message, "clearTextPassword") != NULL) {
4480 ldb_set_errstring(ldb,
4481 "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
4482 return LDB_ERR_NO_SUCH_ATTRIBUTE;
4485 return ldb_next_request(module, req);
4488 /* get user domain data */
4489 ret = build_domain_data_request(ac);
4490 if (ret != LDB_SUCCESS) {
4491 return ret;
4494 return ldb_next_request(module, ac->dom_req);
4497 static int password_hash_add_do_add(struct ph_context *ac)
4499 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
4500 struct ldb_request *down_req;
4501 struct setup_password_fields_io io;
4502 int ret;
4504 /* Prepare the internal data structure containing the passwords */
4505 ret = setup_io(ac, ac->req->op.add.message, NULL, &io);
4506 if (ret != LDB_SUCCESS) {
4507 return ret;
4510 ret = setup_password_fields(&io);
4511 if (ret != LDB_SUCCESS) {
4512 return ret;
4515 ret = check_password_restrictions_and_log(&io);
4516 if (ret != LDB_SUCCESS) {
4517 return ret;
4520 ret = setup_smartcard_reset(&io);
4521 if (ret != LDB_SUCCESS) {
4522 return ret;
4525 ret = update_final_msg(&io);
4526 if (ret != LDB_SUCCESS) {
4527 return ret;
4530 ret = ldb_build_add_req(&down_req, ldb, ac,
4531 ac->update_msg,
4532 ac->req->controls,
4533 ac, ph_op_callback,
4534 ac->req);
4535 LDB_REQ_SET_LOCATION(down_req);
4536 if (ret != LDB_SUCCESS) {
4537 return ret;
4540 return ldb_next_request(ac->module, down_req);
4543 static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
4545 struct ldb_context *ldb = ldb_module_get_ctx(module);
4546 struct ph_context *ac = NULL;
4547 const char *passwordAttrs[] = {DSDB_PASSWORD_ATTRIBUTES, NULL}, **l;
4548 unsigned int del_attr_cnt, add_attr_cnt, rep_attr_cnt;
4549 struct ldb_message_element *passwordAttr;
4550 struct ldb_message *msg;
4551 struct ldb_request *down_req;
4552 struct ldb_control *restore = NULL;
4553 int ret;
4554 unsigned int i = 0;
4556 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
4558 ret = password_hash_needed(module, req, &ac);
4559 if (ret != LDB_SUCCESS) {
4560 return ret;
4562 if (ac == NULL) {
4563 return ret;
4566 /* use a new message structure so that we can modify it */
4567 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
4568 if (msg == NULL) {
4569 return ldb_oom(ldb);
4572 /* - check for single-valued password attributes
4573 * (if not return "CONSTRAINT_VIOLATION")
4574 * - check that for a password change operation one add and one delete
4575 * operation exists
4576 * (if not return "CONSTRAINT_VIOLATION" or "UNWILLING_TO_PERFORM")
4577 * - check that a password change and a password set operation cannot
4578 * be mixed
4579 * (if not return "UNWILLING_TO_PERFORM")
4580 * - remove all password attributes modifications from the first change
4581 * operation (anything without the passwords) - we will make the real
4582 * modification later */
4583 del_attr_cnt = 0;
4584 add_attr_cnt = 0;
4585 rep_attr_cnt = 0;
4586 for (l = passwordAttrs; *l != NULL; l++) {
4587 if ((!ac->userPassword) &&
4588 (ldb_attr_cmp(*l, "userPassword") == 0)) {
4589 continue;
4592 while ((passwordAttr = ldb_msg_find_element(msg, *l)) != NULL) {
4593 unsigned int mtype = LDB_FLAG_MOD_TYPE(passwordAttr->flags);
4594 unsigned int nvalues = passwordAttr->num_values;
4596 if (mtype == LDB_FLAG_MOD_DELETE) {
4597 ++del_attr_cnt;
4599 if (mtype == LDB_FLAG_MOD_ADD) {
4600 ++add_attr_cnt;
4602 if (mtype == LDB_FLAG_MOD_REPLACE) {
4603 ++rep_attr_cnt;
4605 if ((nvalues != 1) && (mtype == LDB_FLAG_MOD_ADD)) {
4606 talloc_free(ac);
4607 ldb_asprintf_errstring(ldb,
4608 "'%s' attribute must have exactly one value on add operations!",
4609 *l);
4610 return LDB_ERR_CONSTRAINT_VIOLATION;
4612 if ((nvalues > 1) && (mtype == LDB_FLAG_MOD_DELETE)) {
4613 talloc_free(ac);
4614 ldb_asprintf_errstring(ldb,
4615 "'%s' attribute must have zero or one value(s) on delete operations!",
4616 *l);
4617 return LDB_ERR_CONSTRAINT_VIOLATION;
4619 ldb_msg_remove_element(msg, passwordAttr);
4622 if ((del_attr_cnt == 0) && (add_attr_cnt > 0)) {
4623 talloc_free(ac);
4624 ldb_set_errstring(ldb,
4625 "Only the add action for a password change specified!");
4626 return LDB_ERR_UNWILLING_TO_PERFORM;
4628 if ((del_attr_cnt > 1) || (add_attr_cnt > 1)) {
4629 talloc_free(ac);
4630 ldb_set_errstring(ldb,
4631 "Only one delete and one add action for a password change allowed!");
4632 return LDB_ERR_UNWILLING_TO_PERFORM;
4634 if ((rep_attr_cnt > 0) && ((del_attr_cnt > 0) || (add_attr_cnt > 0))) {
4635 talloc_free(ac);
4636 ldb_set_errstring(ldb,
4637 "Either a password change or a password set operation is allowed!");
4638 return LDB_ERR_UNWILLING_TO_PERFORM;
4641 restore = ldb_request_get_control(req,
4642 DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
4643 if (restore == NULL) {
4645 * A tomstone reanimation generates a double update
4646 * of pwdLastSet.
4648 * So we only remove it without the
4649 * DSDB_CONTROL_RESTORE_TOMBSTONE_OID control.
4651 ldb_msg_remove_attr(msg, "pwdLastSet");
4655 /* if there was nothing else to be modified skip to next step */
4656 if (msg->num_elements == 0) {
4657 return password_hash_mod_search_self(ac);
4661 * Now we apply all changes remaining in msg
4662 * and remove them from our final update_msg
4665 for (i = 0; i < msg->num_elements; i++) {
4666 ldb_msg_remove_attr(ac->update_msg,
4667 msg->elements[i].name);
4670 ret = ldb_build_mod_req(&down_req, ldb, ac,
4671 msg,
4672 req->controls,
4673 ac, ph_modify_callback,
4674 req);
4675 LDB_REQ_SET_LOCATION(down_req);
4676 if (ret != LDB_SUCCESS) {
4677 return ret;
4680 return ldb_next_request(module, down_req);
4683 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
4685 struct ph_context *ac;
4687 ac = talloc_get_type(req->context, struct ph_context);
4689 if (!ares) {
4690 return ldb_module_done(ac->req, NULL, NULL,
4691 LDB_ERR_OPERATIONS_ERROR);
4694 if (ares->type == LDB_REPLY_REFERRAL) {
4695 return ldb_module_send_referral(ac->req, ares->referral);
4698 if (ares->error != LDB_SUCCESS) {
4699 return ldb_module_done(ac->req, ares->controls,
4700 ares->response, ares->error);
4703 if (ares->type != LDB_REPLY_DONE) {
4704 talloc_free(ares);
4705 return ldb_module_done(ac->req, NULL, NULL,
4706 LDB_ERR_OPERATIONS_ERROR);
4709 talloc_free(ares);
4711 return password_hash_mod_search_self(ac);
4714 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
4716 struct ldb_context *ldb;
4717 struct ph_context *ac;
4718 int ret = LDB_SUCCESS;
4720 ac = talloc_get_type(req->context, struct ph_context);
4721 ldb = ldb_module_get_ctx(ac->module);
4723 if (!ares) {
4724 ret = LDB_ERR_OPERATIONS_ERROR;
4725 goto done;
4727 if (ares->error != LDB_SUCCESS) {
4728 return ldb_module_done(ac->req, ares->controls,
4729 ares->response, ares->error);
4732 /* we are interested only in the single reply (base search) */
4733 switch (ares->type) {
4734 case LDB_REPLY_ENTRY:
4735 /* Make sure we are performing the password change action on a
4736 * (for us) valid object. Those are instances of either "user"
4737 * and/or "inetOrgPerson". Otherwise continue with the
4738 * submodules. */
4739 if ((!ldb_msg_check_string_attribute(ares->message, "objectClass", "user"))
4740 && (!ldb_msg_check_string_attribute(ares->message, "objectClass", "inetOrgPerson"))) {
4741 talloc_free(ares);
4743 if (ldb_msg_find_element(ac->req->op.mod.message, "clearTextPassword") != NULL) {
4744 ldb_set_errstring(ldb,
4745 "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
4746 ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
4747 goto done;
4750 ret = ldb_next_request(ac->module, ac->req);
4751 goto done;
4754 if (ac->search_res != NULL) {
4755 talloc_free(ares);
4757 ldb_set_errstring(ldb, "Too many results");
4758 ret = LDB_ERR_OPERATIONS_ERROR;
4759 goto done;
4762 ac->search_res = talloc_steal(ac, ares);
4763 ret = LDB_SUCCESS;
4764 break;
4766 case LDB_REPLY_REFERRAL:
4767 /* ignore anything else for now */
4768 talloc_free(ares);
4769 ret = LDB_SUCCESS;
4770 break;
4772 case LDB_REPLY_DONE:
4773 talloc_free(ares);
4775 /* get user domain data */
4776 ret = build_domain_data_request(ac);
4777 if (ret != LDB_SUCCESS) {
4778 return ldb_module_done(ac->req, NULL, NULL, ret);
4781 ret = ldb_next_request(ac->module, ac->dom_req);
4782 break;
4785 done:
4786 if (ret != LDB_SUCCESS) {
4787 return ldb_module_done(ac->req, NULL, NULL, ret);
4790 return LDB_SUCCESS;
4793 static int password_hash_mod_search_self(struct ph_context *ac)
4795 struct ldb_context *ldb;
4796 static const char * const attrs[] = { "objectClass",
4797 "userAccountControl",
4798 "msDS-ResultantPSO",
4799 "msDS-User-Account-Control-Computed",
4800 "pwdLastSet",
4801 "sAMAccountName",
4802 "objectSid",
4803 "userPrincipalName",
4804 "displayName",
4805 "supplementalCredentials",
4806 "lmPwdHistory",
4807 "ntPwdHistory",
4808 "dBCSPwd",
4809 "unicodePwd",
4810 "badPasswordTime",
4811 "badPwdCount",
4812 "lockoutTime",
4813 "msDS-SecondaryKrbTgtNumber",
4814 NULL };
4815 struct ldb_request *search_req;
4816 int ret;
4818 ldb = ldb_module_get_ctx(ac->module);
4820 ret = ldb_build_search_req(&search_req, ldb, ac,
4821 ac->req->op.mod.message->dn,
4822 LDB_SCOPE_BASE,
4823 "(objectclass=*)",
4824 attrs,
4825 NULL,
4826 ac, ph_mod_search_callback,
4827 ac->req);
4828 LDB_REQ_SET_LOCATION(search_req);
4829 if (ret != LDB_SUCCESS) {
4830 return ret;
4833 return ldb_next_request(ac->module, search_req);
4836 static int password_hash_mod_do_mod(struct ph_context *ac)
4838 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
4839 struct ldb_request *mod_req;
4840 struct setup_password_fields_io io;
4841 int ret;
4843 /* Prepare the internal data structure containing the passwords */
4844 ret = setup_io(ac, ac->req->op.mod.message,
4845 ac->search_res->message, &io);
4846 if (ret != LDB_SUCCESS) {
4847 return ret;
4850 ret = setup_password_fields(&io);
4851 if (ret != LDB_SUCCESS) {
4852 return ret;
4855 ret = check_password_restrictions_and_log(&io);
4856 if (ret != LDB_SUCCESS) {
4857 return ret;
4860 ret = setup_smartcard_reset(&io);
4861 if (ret != LDB_SUCCESS) {
4862 return ret;
4865 ret = update_final_msg(&io);
4866 if (ret != LDB_SUCCESS) {
4867 return ret;
4870 ret = ldb_build_mod_req(&mod_req, ldb, ac,
4871 ac->update_msg,
4872 ac->req->controls,
4873 ac, ph_op_callback,
4874 ac->req);
4875 LDB_REQ_SET_LOCATION(mod_req);
4876 if (ret != LDB_SUCCESS) {
4877 return ret;
4880 return ldb_next_request(ac->module, mod_req);
4883 static const struct ldb_module_ops ldb_password_hash_module_ops = {
4884 .name = "password_hash",
4885 .add = password_hash_add,
4886 .modify = password_hash_modify
4889 int ldb_password_hash_module_init(const char *version)
4891 #ifdef ENABLE_GPGME
4892 const char *gversion = NULL;
4893 #endif /* ENABLE_GPGME */
4895 LDB_MODULE_CHECK_VERSION(version);
4897 #ifdef ENABLE_GPGME
4899 * Note: this sets a SIGPIPE handler
4900 * if none is active already. See:
4901 * https://www.gnupg.org/documentation/manuals/gpgme/Signal-Handling.html#Signal-Handling
4903 gversion = gpgme_check_version(MINIMUM_GPGME_VERSION);
4904 if (gversion == NULL) {
4905 fprintf(stderr, "%s() in %s version[%s]: "
4906 "gpgme_check_version(%s) not available, "
4907 "gpgme_check_version(NULL) => '%s'\n",
4908 __func__, __FILE__, version,
4909 MINIMUM_GPGME_VERSION, gpgme_check_version(NULL));
4910 return LDB_ERR_UNAVAILABLE;
4912 #endif /* ENABLE_GPGME */
4914 return ldb_register_module(&ldb_password_hash_module_ops);