krb5-samba: interdomain trust uses different salt principal
[Samba.git] / source4 / dsdb / samdb / ldb_modules / password_hash.c
blob5f5710330044bb4dc37b4a76bf08866a42b1fc1f
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/crypto.h"
46 #include "param/param.h"
47 #include "lib/krb5_wrap/krb5_samba.h"
48 #include "auth/common_auth.h"
49 #include "lib/messaging/messaging.h"
51 #ifdef ENABLE_GPGME
52 #undef class
53 #include <gpgme.h>
54 #endif
56 /* If we have decided there is a reason to work on this request, then
57 * setup all the password hash types correctly.
59 * If we haven't the hashes yet but the password given as plain-text (attributes
60 * 'unicodePwd', 'userPassword' and 'clearTextPassword') we have to check for
61 * the constraints. Once this is done, we calculate the password hashes.
63 * Notice: unlike the real AD which only supports the UTF16 special based
64 * 'unicodePwd' and the UTF8 based 'userPassword' plaintext attribute we
65 * understand also a UTF16 based 'clearTextPassword' one.
66 * The latter is also accessible through LDAP so it can also be set by external
67 * tools and scripts. But be aware that this isn't portable on non SAMBA 4 ADs!
69 * Also when the module receives only the password hashes (possible through
70 * specifying an internal LDB control - for security reasons) some checks are
71 * performed depending on the operation mode (see below) (e.g. if the password
72 * has been in use before if the password memory policy was activated).
74 * Attention: There is a difference between "modify" and "reset" operations
75 * (see MS-ADTS 3.1.1.3.1.5). If the client sends a "add" and "remove"
76 * operation for a password attribute we thread this as a "modify"; if it sends
77 * only a "replace" one we have an (administrative) reset.
79 * Finally, if the administrator has requested that a password history
80 * be maintained, then this should also be written out.
84 /* TODO: [consider always MS-ADTS 3.1.1.3.1.5]
85 * - Check for right connection encryption
88 /* Notice: Definition of "dsdb_control_password_change_status" moved into
89 * "samdb.h" */
91 struct ph_context {
92 struct ldb_module *module;
93 struct ldb_request *req;
95 struct ldb_request *dom_req;
96 struct ldb_reply *dom_res;
98 struct ldb_reply *pso_res;
100 struct ldb_reply *search_res;
102 struct ldb_message *update_msg;
104 struct dsdb_control_password_change_status *status;
105 struct dsdb_control_password_change *change;
107 const char **gpg_key_ids;
109 bool pwd_reset;
110 bool change_status;
111 bool hash_values;
112 bool userPassword;
113 bool update_password;
114 bool update_lastset;
115 bool pwd_last_set_bypass;
116 bool pwd_last_set_default;
117 bool smartcard_reset;
118 const char **userPassword_schemes;
122 struct setup_password_fields_io {
123 struct ph_context *ac;
125 struct smb_krb5_context *smb_krb5_context;
127 /* info about the user account */
128 struct {
129 uint32_t userAccountControl;
130 NTTIME pwdLastSet;
131 const char *sAMAccountName;
132 const char *user_principal_name;
133 bool is_krbtgt;
134 uint32_t restrictions;
135 struct dom_sid *account_sid;
136 } u;
138 /* new credentials and old given credentials */
139 struct setup_password_fields_given {
140 const struct ldb_val *cleartext_utf8;
141 const struct ldb_val *cleartext_utf16;
142 struct samr_Password *nt_hash;
143 struct samr_Password *lm_hash;
144 } n, og;
146 /* old credentials */
147 struct {
148 struct samr_Password *nt_hash;
149 struct samr_Password *lm_hash;
150 uint32_t nt_history_len;
151 struct samr_Password *nt_history;
152 uint32_t lm_history_len;
153 struct samr_Password *lm_history;
154 const struct ldb_val *supplemental;
155 struct supplementalCredentialsBlob scb;
156 } o;
158 /* generated credentials */
159 struct {
160 struct samr_Password *nt_hash;
161 struct samr_Password *lm_hash;
162 uint32_t nt_history_len;
163 struct samr_Password *nt_history;
164 uint32_t lm_history_len;
165 struct samr_Password *lm_history;
166 const char *salt;
167 DATA_BLOB aes_256;
168 DATA_BLOB aes_128;
169 DATA_BLOB des_md5;
170 DATA_BLOB des_crc;
171 struct ldb_val supplemental;
172 NTTIME last_set;
173 } g;
176 static int msg_find_old_and_new_pwd_val(const struct ldb_message *msg,
177 const char *name,
178 enum ldb_request_type operation,
179 const struct ldb_val **new_val,
180 const struct ldb_val **old_val);
182 static int password_hash_bypass(struct ldb_module *module, struct ldb_request *request)
184 struct ldb_context *ldb = ldb_module_get_ctx(module);
185 const struct ldb_message *msg;
186 struct ldb_message_element *nte;
187 struct ldb_message_element *lme;
188 struct ldb_message_element *nthe;
189 struct ldb_message_element *lmhe;
190 struct ldb_message_element *sce;
192 switch (request->operation) {
193 case LDB_ADD:
194 msg = request->op.add.message;
195 break;
196 case LDB_MODIFY:
197 msg = request->op.mod.message;
198 break;
199 default:
200 return ldb_next_request(module, request);
203 /* nobody must touch password histories and 'supplementalCredentials' */
204 nte = dsdb_get_single_valued_attr(msg, "unicodePwd",
205 request->operation);
206 lme = dsdb_get_single_valued_attr(msg, "dBCSPwd",
207 request->operation);
208 nthe = dsdb_get_single_valued_attr(msg, "ntPwdHistory",
209 request->operation);
210 lmhe = dsdb_get_single_valued_attr(msg, "lmPwdHistory",
211 request->operation);
212 sce = dsdb_get_single_valued_attr(msg, "supplementalCredentials",
213 request->operation);
215 #define CHECK_HASH_ELEMENT(e, min, max) do {\
216 if (e && e->num_values) { \
217 unsigned int _count; \
218 if (e->num_values != 1) { \
219 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
220 "num_values != 1"); \
222 if ((e->values[0].length % 16) != 0) { \
223 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
224 "length % 16 != 0"); \
226 _count = e->values[0].length / 16; \
227 if (_count < min) { \
228 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
229 "count < min"); \
231 if (_count > max) { \
232 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
233 "count > max"); \
236 } while (0)
238 CHECK_HASH_ELEMENT(nte, 1, 1);
239 CHECK_HASH_ELEMENT(lme, 1, 1);
240 CHECK_HASH_ELEMENT(nthe, 1, INT32_MAX);
241 CHECK_HASH_ELEMENT(lmhe, 1, INT32_MAX);
243 if (sce && sce->num_values) {
244 enum ndr_err_code ndr_err;
245 struct supplementalCredentialsBlob *scb;
246 struct supplementalCredentialsPackage *scpp = NULL;
247 struct supplementalCredentialsPackage *scpk = NULL;
248 struct supplementalCredentialsPackage *scpkn = NULL;
249 struct supplementalCredentialsPackage *scpct = NULL;
250 DATA_BLOB scpbp = data_blob_null;
251 DATA_BLOB scpbk = data_blob_null;
252 DATA_BLOB scpbkn = data_blob_null;
253 DATA_BLOB scpbct = data_blob_null;
254 DATA_BLOB blob;
255 uint32_t i;
257 if (sce->num_values != 1) {
258 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
259 "num_values != 1");
262 scb = talloc_zero(request, struct supplementalCredentialsBlob);
263 if (!scb) {
264 return ldb_module_oom(module);
267 ndr_err = ndr_pull_struct_blob_all(&sce->values[0], scb, scb,
268 (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
269 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
270 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
271 "ndr_pull_struct_blob_all");
274 if (scb->sub.num_packages < 2) {
275 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
276 "num_packages < 2");
279 for (i=0; i < scb->sub.num_packages; i++) {
280 DATA_BLOB subblob;
282 subblob = strhex_to_data_blob(scb, scb->sub.packages[i].data);
283 if (subblob.data == NULL) {
284 return ldb_module_oom(module);
287 if (strcmp(scb->sub.packages[i].name, "Packages") == 0) {
288 if (scpp) {
289 return ldb_error(ldb,
290 LDB_ERR_CONSTRAINT_VIOLATION,
291 "Packages twice");
293 scpp = &scb->sub.packages[i];
294 scpbp = subblob;
295 continue;
297 if (strcmp(scb->sub.packages[i].name, "Primary:Kerberos") == 0) {
298 if (scpk) {
299 return ldb_error(ldb,
300 LDB_ERR_CONSTRAINT_VIOLATION,
301 "Primary:Kerberos twice");
303 scpk = &scb->sub.packages[i];
304 scpbk = subblob;
305 continue;
307 if (strcmp(scb->sub.packages[i].name, "Primary:Kerberos-Newer-Keys") == 0) {
308 if (scpkn) {
309 return ldb_error(ldb,
310 LDB_ERR_CONSTRAINT_VIOLATION,
311 "Primary:Kerberos-Newer-Keys twice");
313 scpkn = &scb->sub.packages[i];
314 scpbkn = subblob;
315 continue;
317 if (strcmp(scb->sub.packages[i].name, "Primary:CLEARTEXT") == 0) {
318 if (scpct) {
319 return ldb_error(ldb,
320 LDB_ERR_CONSTRAINT_VIOLATION,
321 "Primary:CLEARTEXT twice");
323 scpct = &scb->sub.packages[i];
324 scpbct = subblob;
325 continue;
328 data_blob_free(&subblob);
331 if (scpp == NULL) {
332 return ldb_error(ldb,
333 LDB_ERR_CONSTRAINT_VIOLATION,
334 "Primary:Packages missing");
337 if (scpk == NULL) {
339 * If Primary:Kerberos is missing w2k8r2 reboots
340 * when a password is changed.
342 return ldb_error(ldb,
343 LDB_ERR_CONSTRAINT_VIOLATION,
344 "Primary:Kerberos missing");
347 if (scpp) {
348 struct package_PackagesBlob *p;
349 uint32_t n;
351 p = talloc_zero(scb, struct package_PackagesBlob);
352 if (p == NULL) {
353 return ldb_module_oom(module);
356 ndr_err = ndr_pull_struct_blob(&scpbp, p, p,
357 (ndr_pull_flags_fn_t)ndr_pull_package_PackagesBlob);
358 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
359 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
360 "ndr_pull_struct_blob Packages");
363 if (p->names == NULL) {
364 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
365 "Packages names == NULL");
368 for (n = 0; p->names[n]; n++) {
369 /* noop */
372 if (scb->sub.num_packages != (n + 1)) {
373 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
374 "Packages num_packages != num_names + 1");
377 talloc_free(p);
380 if (scpk) {
381 struct package_PrimaryKerberosBlob *k;
383 k = talloc_zero(scb, struct package_PrimaryKerberosBlob);
384 if (k == NULL) {
385 return ldb_module_oom(module);
388 ndr_err = ndr_pull_struct_blob(&scpbk, k, k,
389 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
390 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
391 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
392 "ndr_pull_struct_blob PrimaryKerberos");
395 if (k->version != 3) {
396 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
397 "PrimaryKerberos version != 3");
400 if (k->ctr.ctr3.salt.string == NULL) {
401 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
402 "PrimaryKerberos salt == NULL");
405 if (strlen(k->ctr.ctr3.salt.string) == 0) {
406 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
407 "PrimaryKerberos strlen(salt) == 0");
410 if (k->ctr.ctr3.num_keys != 2) {
411 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
412 "PrimaryKerberos num_keys != 2");
415 if (k->ctr.ctr3.num_old_keys > k->ctr.ctr3.num_keys) {
416 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
417 "PrimaryKerberos num_old_keys > num_keys");
420 if (k->ctr.ctr3.keys[0].keytype != ENCTYPE_DES_CBC_MD5) {
421 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
422 "PrimaryKerberos key[0] != DES_CBC_MD5");
424 if (k->ctr.ctr3.keys[1].keytype != ENCTYPE_DES_CBC_CRC) {
425 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
426 "PrimaryKerberos key[1] != DES_CBC_CRC");
429 if (k->ctr.ctr3.keys[0].value_len != 8) {
430 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
431 "PrimaryKerberos key[0] value_len != 8");
433 if (k->ctr.ctr3.keys[1].value_len != 8) {
434 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
435 "PrimaryKerberos key[1] value_len != 8");
438 for (i = 0; i < k->ctr.ctr3.num_old_keys; i++) {
439 if (k->ctr.ctr3.old_keys[i].keytype ==
440 k->ctr.ctr3.keys[i].keytype &&
441 k->ctr.ctr3.old_keys[i].value_len ==
442 k->ctr.ctr3.keys[i].value_len) {
443 continue;
446 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
447 "PrimaryKerberos old_keys type/value_len doesn't match");
450 talloc_free(k);
453 if (scpkn) {
454 struct package_PrimaryKerberosBlob *k;
456 k = talloc_zero(scb, struct package_PrimaryKerberosBlob);
457 if (k == NULL) {
458 return ldb_module_oom(module);
461 ndr_err = ndr_pull_struct_blob(&scpbkn, k, k,
462 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
463 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
464 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
465 "ndr_pull_struct_blob PrimaryKerberosNeverKeys");
468 if (k->version != 4) {
469 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
470 "KerberosNerverKeys version != 4");
473 if (k->ctr.ctr4.salt.string == NULL) {
474 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
475 "KerberosNewerKeys salt == NULL");
478 if (strlen(k->ctr.ctr4.salt.string) == 0) {
479 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
480 "KerberosNewerKeys strlen(salt) == 0");
483 if (k->ctr.ctr4.num_keys != 4) {
484 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
485 "KerberosNewerKeys num_keys != 2");
488 if (k->ctr.ctr4.num_old_keys > k->ctr.ctr4.num_keys) {
489 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
490 "KerberosNewerKeys num_old_keys > num_keys");
493 if (k->ctr.ctr4.num_older_keys > k->ctr.ctr4.num_old_keys) {
494 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
495 "KerberosNewerKeys num_older_keys > num_old_keys");
498 if (k->ctr.ctr4.keys[0].keytype != ENCTYPE_AES256_CTS_HMAC_SHA1_96) {
499 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
500 "KerberosNewerKeys key[0] != AES256");
502 if (k->ctr.ctr4.keys[1].keytype != ENCTYPE_AES128_CTS_HMAC_SHA1_96) {
503 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
504 "KerberosNewerKeys key[1] != AES128");
506 if (k->ctr.ctr4.keys[2].keytype != ENCTYPE_DES_CBC_MD5) {
507 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
508 "KerberosNewerKeys key[2] != DES_CBC_MD5");
510 if (k->ctr.ctr4.keys[3].keytype != ENCTYPE_DES_CBC_CRC) {
511 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
512 "KerberosNewerKeys key[3] != DES_CBC_CRC");
515 if (k->ctr.ctr4.keys[0].value_len != 32) {
516 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
517 "KerberosNewerKeys key[0] value_len != 32");
519 if (k->ctr.ctr4.keys[1].value_len != 16) {
520 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
521 "KerberosNewerKeys key[1] value_len != 16");
523 if (k->ctr.ctr4.keys[2].value_len != 8) {
524 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
525 "KerberosNewerKeys key[2] value_len != 8");
527 if (k->ctr.ctr4.keys[3].value_len != 8) {
528 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
529 "KerberosNewerKeys key[3] value_len != 8");
533 * TODO:
534 * Maybe we can check old and older keys here.
535 * But we need to do some tests, if the old keys
536 * can be taken from the PrimaryKerberos blob
537 * (with only des keys), when the domain was upgraded
538 * from w2k3 to w2k8.
541 talloc_free(k);
544 if (scpct) {
545 struct package_PrimaryCLEARTEXTBlob *ct;
547 ct = talloc_zero(scb, struct package_PrimaryCLEARTEXTBlob);
548 if (ct == NULL) {
549 return ldb_module_oom(module);
552 ndr_err = ndr_pull_struct_blob(&scpbct, ct, ct,
553 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryCLEARTEXTBlob);
554 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
555 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
556 "ndr_pull_struct_blob PrimaryCLEARTEXT");
559 if ((ct->cleartext.length % 2) != 0) {
560 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
561 "PrimaryCLEARTEXT length % 2 != 0");
564 talloc_free(ct);
567 ndr_err = ndr_push_struct_blob(&blob, scb, scb,
568 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
569 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
570 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
571 "ndr_pull_struct_blob_all");
574 if (sce->values[0].length != blob.length) {
575 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
576 "supplementalCredentialsBlob length differ");
579 if (memcmp(sce->values[0].data, blob.data, blob.length) != 0) {
580 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
581 "supplementalCredentialsBlob memcmp differ");
584 talloc_free(scb);
587 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_bypass - validated\n");
588 return ldb_next_request(module, request);
591 /* Get the NT hash, and fill it in as an entry in the password history,
592 and specify it into io->g.nt_hash */
594 static int setup_nt_fields(struct setup_password_fields_io *io)
596 struct ldb_context *ldb;
597 uint32_t i;
599 io->g.nt_hash = io->n.nt_hash;
600 ldb = ldb_module_get_ctx(io->ac->module);
602 if (io->ac->status->domain_data.pwdHistoryLength == 0) {
603 return LDB_SUCCESS;
606 /* We might not have an old NT password */
607 io->g.nt_history = talloc_array(io->ac,
608 struct samr_Password,
609 io->ac->status->domain_data.pwdHistoryLength);
610 if (!io->g.nt_history) {
611 return ldb_oom(ldb);
614 for (i = 0; i < MIN(io->ac->status->domain_data.pwdHistoryLength-1,
615 io->o.nt_history_len); i++) {
616 io->g.nt_history[i+1] = io->o.nt_history[i];
618 io->g.nt_history_len = i + 1;
620 if (io->g.nt_hash) {
621 io->g.nt_history[0] = *io->g.nt_hash;
622 } else {
624 * TODO: is this correct?
625 * the simular behavior is correct for the lm history case
627 E_md4hash("", io->g.nt_history[0].hash);
630 return LDB_SUCCESS;
633 /* Get the LANMAN hash, and fill it in as an entry in the password history,
634 and specify it into io->g.lm_hash */
636 static int setup_lm_fields(struct setup_password_fields_io *io)
638 struct ldb_context *ldb;
639 uint32_t i;
641 io->g.lm_hash = io->n.lm_hash;
642 ldb = ldb_module_get_ctx(io->ac->module);
644 if (io->ac->status->domain_data.pwdHistoryLength == 0) {
645 return LDB_SUCCESS;
648 /* We might not have an old LM password */
649 io->g.lm_history = talloc_array(io->ac,
650 struct samr_Password,
651 io->ac->status->domain_data.pwdHistoryLength);
652 if (!io->g.lm_history) {
653 return ldb_oom(ldb);
656 for (i = 0; i < MIN(io->ac->status->domain_data.pwdHistoryLength-1,
657 io->o.lm_history_len); i++) {
658 io->g.lm_history[i+1] = io->o.lm_history[i];
660 io->g.lm_history_len = i + 1;
662 if (io->g.lm_hash) {
663 io->g.lm_history[0] = *io->g.lm_hash;
664 } else {
665 E_deshash("", io->g.lm_history[0].hash);
668 return LDB_SUCCESS;
671 static int setup_kerberos_keys(struct setup_password_fields_io *io)
673 struct ldb_context *ldb;
674 krb5_error_code krb5_ret;
675 char *salt_principal = NULL;
676 char *salt_data = NULL;
677 krb5_data salt;
678 krb5_keyblock key;
679 krb5_data cleartext_data;
680 uint32_t uac_flags = 0;
682 ldb = ldb_module_get_ctx(io->ac->module);
683 cleartext_data.data = (char *)io->n.cleartext_utf8->data;
684 cleartext_data.length = io->n.cleartext_utf8->length;
686 uac_flags = io->u.userAccountControl & UF_ACCOUNT_TYPE_MASK;
687 krb5_ret = smb_krb5_salt_principal(io->ac->status->domain_data.realm,
688 io->u.sAMAccountName,
689 io->u.user_principal_name,
690 uac_flags,
691 io->ac,
692 &salt_principal);
693 if (krb5_ret) {
694 ldb_asprintf_errstring(ldb,
695 "setup_kerberos_keys: "
696 "generation of a salting principal failed: %s",
697 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
698 krb5_ret, io->ac));
699 return LDB_ERR_OPERATIONS_ERROR;
703 * create salt from salt_principal
705 krb5_ret = smb_krb5_salt_principal2data(io->smb_krb5_context->krb5_context,
706 salt_principal, io->ac, &salt_data);
707 if (krb5_ret) {
708 ldb_asprintf_errstring(ldb,
709 "setup_kerberos_keys: "
710 "generation of krb5_salt failed: %s",
711 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
712 krb5_ret, io->ac));
713 return LDB_ERR_OPERATIONS_ERROR;
715 io->g.salt = salt_data;
717 /* now use the talloced copy of the salt */
718 salt.data = discard_const(io->g.salt);
719 salt.length = strlen(io->g.salt);
722 * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of
723 * the salt and the cleartext password
725 krb5_ret = smb_krb5_create_key_from_string(io->smb_krb5_context->krb5_context,
726 NULL,
727 &salt,
728 &cleartext_data,
729 ENCTYPE_AES256_CTS_HMAC_SHA1_96,
730 &key);
731 if (krb5_ret) {
732 ldb_asprintf_errstring(ldb,
733 "setup_kerberos_keys: "
734 "generation of a aes256-cts-hmac-sha1-96 key failed: %s",
735 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
736 krb5_ret, io->ac));
737 return LDB_ERR_OPERATIONS_ERROR;
739 io->g.aes_256 = data_blob_talloc(io->ac,
740 KRB5_KEY_DATA(&key),
741 KRB5_KEY_LENGTH(&key));
742 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
743 if (!io->g.aes_256.data) {
744 return ldb_oom(ldb);
748 * create ENCTYPE_AES128_CTS_HMAC_SHA1_96 key out of
749 * the salt and the cleartext password
751 krb5_ret = smb_krb5_create_key_from_string(io->smb_krb5_context->krb5_context,
752 NULL,
753 &salt,
754 &cleartext_data,
755 ENCTYPE_AES128_CTS_HMAC_SHA1_96,
756 &key);
757 if (krb5_ret) {
758 ldb_asprintf_errstring(ldb,
759 "setup_kerberos_keys: "
760 "generation of a aes128-cts-hmac-sha1-96 key failed: %s",
761 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
762 krb5_ret, io->ac));
763 return LDB_ERR_OPERATIONS_ERROR;
765 io->g.aes_128 = data_blob_talloc(io->ac,
766 KRB5_KEY_DATA(&key),
767 KRB5_KEY_LENGTH(&key));
768 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
769 if (!io->g.aes_128.data) {
770 return ldb_oom(ldb);
774 * create ENCTYPE_DES_CBC_MD5 key out of
775 * the salt and the cleartext password
777 krb5_ret = smb_krb5_create_key_from_string(io->smb_krb5_context->krb5_context,
778 NULL,
779 &salt,
780 &cleartext_data,
781 ENCTYPE_DES_CBC_MD5,
782 &key);
783 if (krb5_ret) {
784 ldb_asprintf_errstring(ldb,
785 "setup_kerberos_keys: "
786 "generation of a des-cbc-md5 key failed: %s",
787 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
788 krb5_ret, io->ac));
789 return LDB_ERR_OPERATIONS_ERROR;
791 io->g.des_md5 = data_blob_talloc(io->ac,
792 KRB5_KEY_DATA(&key),
793 KRB5_KEY_LENGTH(&key));
794 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
795 if (!io->g.des_md5.data) {
796 return ldb_oom(ldb);
800 * create ENCTYPE_DES_CBC_CRC key out of
801 * the salt and the cleartext password
803 krb5_ret = smb_krb5_create_key_from_string(io->smb_krb5_context->krb5_context,
804 NULL,
805 &salt,
806 &cleartext_data,
807 ENCTYPE_DES_CBC_CRC,
808 &key);
809 if (krb5_ret) {
810 ldb_asprintf_errstring(ldb,
811 "setup_kerberos_keys: "
812 "generation of a des-cbc-crc key failed: %s",
813 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
814 krb5_ret, io->ac));
815 return LDB_ERR_OPERATIONS_ERROR;
817 io->g.des_crc = data_blob_talloc(io->ac,
818 KRB5_KEY_DATA(&key),
819 KRB5_KEY_LENGTH(&key));
820 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
821 if (!io->g.des_crc.data) {
822 return ldb_oom(ldb);
825 return LDB_SUCCESS;
828 static int setup_primary_kerberos(struct setup_password_fields_io *io,
829 const struct supplementalCredentialsBlob *old_scb,
830 struct package_PrimaryKerberosBlob *pkb)
832 struct ldb_context *ldb;
833 struct package_PrimaryKerberosCtr3 *pkb3 = &pkb->ctr.ctr3;
834 struct supplementalCredentialsPackage *old_scp = NULL;
835 struct package_PrimaryKerberosBlob _old_pkb;
836 struct package_PrimaryKerberosCtr3 *old_pkb3 = NULL;
837 uint32_t i;
838 enum ndr_err_code ndr_err;
840 ldb = ldb_module_get_ctx(io->ac->module);
843 * prepare generation of keys
845 * ENCTYPE_DES_CBC_MD5
846 * ENCTYPE_DES_CBC_CRC
848 pkb->version = 3;
849 pkb3->salt.string = io->g.salt;
850 pkb3->num_keys = 2;
851 pkb3->keys = talloc_array(io->ac,
852 struct package_PrimaryKerberosKey3,
853 pkb3->num_keys);
854 if (!pkb3->keys) {
855 return ldb_oom(ldb);
858 pkb3->keys[0].keytype = ENCTYPE_DES_CBC_MD5;
859 pkb3->keys[0].value = &io->g.des_md5;
860 pkb3->keys[1].keytype = ENCTYPE_DES_CBC_CRC;
861 pkb3->keys[1].value = &io->g.des_crc;
863 /* initialize the old keys to zero */
864 pkb3->num_old_keys = 0;
865 pkb3->old_keys = NULL;
867 /* if there're no old keys, then we're done */
868 if (!old_scb) {
869 return LDB_SUCCESS;
872 for (i=0; i < old_scb->sub.num_packages; i++) {
873 if (strcmp("Primary:Kerberos", old_scb->sub.packages[i].name) != 0) {
874 continue;
877 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
878 continue;
881 old_scp = &old_scb->sub.packages[i];
882 break;
884 /* Primary:Kerberos element of supplementalCredentials */
885 if (old_scp) {
886 DATA_BLOB blob;
888 blob = strhex_to_data_blob(io->ac, old_scp->data);
889 if (!blob.data) {
890 return ldb_oom(ldb);
893 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
894 ndr_err = ndr_pull_struct_blob(&blob, io->ac, &_old_pkb,
895 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
896 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
897 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
898 ldb_asprintf_errstring(ldb,
899 "setup_primary_kerberos: "
900 "failed to pull old package_PrimaryKerberosBlob: %s",
901 nt_errstr(status));
902 return LDB_ERR_OPERATIONS_ERROR;
905 if (_old_pkb.version != 3) {
906 ldb_asprintf_errstring(ldb,
907 "setup_primary_kerberos: "
908 "package_PrimaryKerberosBlob version[%u] expected[3]",
909 _old_pkb.version);
910 return LDB_ERR_OPERATIONS_ERROR;
913 old_pkb3 = &_old_pkb.ctr.ctr3;
916 /* if we didn't found the old keys we're done */
917 if (!old_pkb3) {
918 return LDB_SUCCESS;
921 /* fill in the old keys */
922 pkb3->num_old_keys = old_pkb3->num_keys;
923 pkb3->old_keys = old_pkb3->keys;
925 return LDB_SUCCESS;
928 static int setup_primary_kerberos_newer(struct setup_password_fields_io *io,
929 const struct supplementalCredentialsBlob *old_scb,
930 struct package_PrimaryKerberosBlob *pkb)
932 struct ldb_context *ldb;
933 struct package_PrimaryKerberosCtr4 *pkb4 = &pkb->ctr.ctr4;
934 struct supplementalCredentialsPackage *old_scp = NULL;
935 struct package_PrimaryKerberosBlob _old_pkb;
936 struct package_PrimaryKerberosCtr4 *old_pkb4 = NULL;
937 uint32_t i;
938 enum ndr_err_code ndr_err;
940 ldb = ldb_module_get_ctx(io->ac->module);
943 * prepare generation of keys
945 * ENCTYPE_AES256_CTS_HMAC_SHA1_96
946 * ENCTYPE_AES128_CTS_HMAC_SHA1_96
947 * ENCTYPE_DES_CBC_MD5
948 * ENCTYPE_DES_CBC_CRC
950 pkb->version = 4;
951 pkb4->salt.string = io->g.salt;
952 pkb4->default_iteration_count = 4096;
953 pkb4->num_keys = 4;
955 pkb4->keys = talloc_array(io->ac,
956 struct package_PrimaryKerberosKey4,
957 pkb4->num_keys);
958 if (!pkb4->keys) {
959 return ldb_oom(ldb);
962 pkb4->keys[0].iteration_count = 4096;
963 pkb4->keys[0].keytype = ENCTYPE_AES256_CTS_HMAC_SHA1_96;
964 pkb4->keys[0].value = &io->g.aes_256;
965 pkb4->keys[1].iteration_count = 4096;
966 pkb4->keys[1].keytype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
967 pkb4->keys[1].value = &io->g.aes_128;
968 pkb4->keys[2].iteration_count = 4096;
969 pkb4->keys[2].keytype = ENCTYPE_DES_CBC_MD5;
970 pkb4->keys[2].value = &io->g.des_md5;
971 pkb4->keys[3].iteration_count = 4096;
972 pkb4->keys[3].keytype = ENCTYPE_DES_CBC_CRC;
973 pkb4->keys[3].value = &io->g.des_crc;
975 /* initialize the old keys to zero */
976 pkb4->num_old_keys = 0;
977 pkb4->old_keys = NULL;
978 pkb4->num_older_keys = 0;
979 pkb4->older_keys = NULL;
981 /* if there're no old keys, then we're done */
982 if (!old_scb) {
983 return LDB_SUCCESS;
986 for (i=0; i < old_scb->sub.num_packages; i++) {
987 if (strcmp("Primary:Kerberos-Newer-Keys", old_scb->sub.packages[i].name) != 0) {
988 continue;
991 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
992 continue;
995 old_scp = &old_scb->sub.packages[i];
996 break;
998 /* Primary:Kerberos-Newer-Keys element of supplementalCredentials */
999 if (old_scp) {
1000 DATA_BLOB blob;
1002 blob = strhex_to_data_blob(io->ac, old_scp->data);
1003 if (!blob.data) {
1004 return ldb_oom(ldb);
1007 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
1008 ndr_err = ndr_pull_struct_blob(&blob, io->ac,
1009 &_old_pkb,
1010 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
1011 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1012 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1013 ldb_asprintf_errstring(ldb,
1014 "setup_primary_kerberos_newer: "
1015 "failed to pull old package_PrimaryKerberosBlob: %s",
1016 nt_errstr(status));
1017 return LDB_ERR_OPERATIONS_ERROR;
1020 if (_old_pkb.version != 4) {
1021 ldb_asprintf_errstring(ldb,
1022 "setup_primary_kerberos_newer: "
1023 "package_PrimaryKerberosBlob version[%u] expected[4]",
1024 _old_pkb.version);
1025 return LDB_ERR_OPERATIONS_ERROR;
1028 old_pkb4 = &_old_pkb.ctr.ctr4;
1031 /* if we didn't found the old keys we're done */
1032 if (!old_pkb4) {
1033 return LDB_SUCCESS;
1036 /* fill in the old keys */
1037 pkb4->num_old_keys = old_pkb4->num_keys;
1038 pkb4->old_keys = old_pkb4->keys;
1039 pkb4->num_older_keys = old_pkb4->num_old_keys;
1040 pkb4->older_keys = old_pkb4->old_keys;
1042 return LDB_SUCCESS;
1045 static int setup_primary_wdigest(struct setup_password_fields_io *io,
1046 const struct supplementalCredentialsBlob *old_scb,
1047 struct package_PrimaryWDigestBlob *pdb)
1049 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1050 DATA_BLOB sAMAccountName;
1051 DATA_BLOB sAMAccountName_l;
1052 DATA_BLOB sAMAccountName_u;
1053 const char *user_principal_name = io->u.user_principal_name;
1054 DATA_BLOB userPrincipalName;
1055 DATA_BLOB userPrincipalName_l;
1056 DATA_BLOB userPrincipalName_u;
1057 DATA_BLOB netbios_domain;
1058 DATA_BLOB netbios_domain_l;
1059 DATA_BLOB netbios_domain_u;
1060 DATA_BLOB dns_domain;
1061 DATA_BLOB dns_domain_l;
1062 DATA_BLOB dns_domain_u;
1063 DATA_BLOB digest;
1064 DATA_BLOB delim;
1065 DATA_BLOB backslash;
1066 uint8_t i;
1067 struct {
1068 DATA_BLOB *user;
1069 DATA_BLOB *realm;
1070 DATA_BLOB *nt4dom;
1071 } wdigest[] = {
1073 * See 3.1.1.8.11.3.1 WDIGEST_CREDENTIALS Construction
1074 * https://msdn.microsoft.com/en-us/library/cc245680.aspx
1075 * for what precalculated hashes are supposed to be stored...
1077 * I can't reproduce all values which should contain "Digest" as realm,
1078 * am I doing something wrong or is w2k3 just broken...?
1080 * W2K3 fills in following for a user:
1082 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
1083 * sAMAccountName: NewUser2Sam
1084 * userPrincipalName: NewUser2Princ@sub1.w2k3.vmnet1.vm.base
1086 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1087 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
1088 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
1089 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1090 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
1091 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
1092 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
1093 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1094 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1095 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1096 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1097 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1098 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1099 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1100 * 221c55284451ae9b3aacaa2a3c86f10f => NewUser2Princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1101 * 74e1be668853d4324d38c07e2acfb8ea => (w2k3 has a bug here!) newuser2princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1102 * e1e244ab7f098e3ae1761be7f9229bbb => NEWUSER2PRINC@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
1103 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
1104 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
1105 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
1106 * 31dc704d3640335b2123d4ee28aa1f11 => ??? changes with NewUser2Sam => NewUser1Sam
1107 * 36349f5cecd07320fb3bb0e119230c43 => ??? changes with NewUser2Sam => NewUser1Sam
1108 * 12adf019d037fb535c01fd0608e78d9d => ??? changes with NewUser2Sam => NewUser1Sam
1109 * 6feecf8e724906f3ee1105819c5105a1 => ??? changes with NewUser2Princ => NewUser1Princ
1110 * 6c6911f3de6333422640221b9c51ff1f => ??? changes with NewUser2Princ => NewUser1Princ
1111 * 4b279877e742895f9348ac67a8de2f69 => ??? changes with NewUser2Princ => NewUser1Princ
1112 * db0c6bff069513e3ebb9870d29b57490 => ??? changes with NewUser2Sam => NewUser1Sam
1113 * 45072621e56b1c113a4e04a8ff68cd0e => ??? changes with NewUser2Sam => NewUser1Sam
1114 * 11d1220abc44a9c10cf91ef4a9c1de02 => ??? changes with NewUser2Sam => NewUser1Sam
1116 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
1117 * sAMAccountName: NewUser2Sam
1119 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1120 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
1121 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
1122 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1123 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
1124 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
1125 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
1126 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1127 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1128 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1129 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1130 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1131 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1132 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1133 * 8a140d30b6f0a5912735dc1e3bc993b4 => NewUser2Sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1134 * 86d95b2faae6cae4ec261e7fbaccf093 => (here w2k3 is correct) newuser2sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1135 * dfeff1493110220efcdfc6362e5f5450 => NEWUSER2SAM@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
1136 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
1137 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
1138 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
1139 * 31dc704d3640335b2123d4ee28aa1f11 => ???M1 changes with NewUser2Sam => NewUser1Sam
1140 * 36349f5cecd07320fb3bb0e119230c43 => ???M1.L changes with newuser2sam => newuser1sam
1141 * 12adf019d037fb535c01fd0608e78d9d => ???M1.U changes with NEWUSER2SAM => NEWUSER1SAM
1142 * 569b4533f2d9e580211dd040e5e360a8 => ???M2 changes with NewUser2Princ => NewUser1Princ
1143 * 52528bddf310a587c5d7e6a9ae2cbb20 => ???M2.L changes with newuser2princ => newuser1princ
1144 * 4f629a4f0361289ca4255ab0f658fcd5 => ???M3 changes with NewUser2Princ => NewUser1Princ (doesn't depend on case of userPrincipal )
1145 * db0c6bff069513e3ebb9870d29b57490 => ???M4 changes with NewUser2Sam => NewUser1Sam
1146 * 45072621e56b1c113a4e04a8ff68cd0e => ???M5 changes with NewUser2Sam => NewUser1Sam (doesn't depend on case of sAMAccountName)
1147 * 11d1220abc44a9c10cf91ef4a9c1de02 => ???M4.U changes with NEWUSER2SAM => NEWUSER1SAM
1151 * sAMAccountName, netbios_domain
1154 .user = &sAMAccountName,
1155 .realm = &netbios_domain,
1158 .user = &sAMAccountName_l,
1159 .realm = &netbios_domain_l,
1162 .user = &sAMAccountName_u,
1163 .realm = &netbios_domain_u,
1166 .user = &sAMAccountName,
1167 .realm = &netbios_domain_u,
1170 .user = &sAMAccountName,
1171 .realm = &netbios_domain_l,
1174 .user = &sAMAccountName_u,
1175 .realm = &netbios_domain_l,
1178 .user = &sAMAccountName_l,
1179 .realm = &netbios_domain_u,
1182 * sAMAccountName, dns_domain
1184 * TODO:
1185 * Windows preserves the case of the DNS domain,
1186 * Samba lower cases the domain at provision time
1187 * This means that for mixed case Domains, the WDigest08 hash
1188 * calculated by Samba differs from that calculated by Windows.
1189 * Until we get a real world use case this will remain a known
1190 * bug, as changing the case could have unforeseen impacts.
1194 .user = &sAMAccountName,
1195 .realm = &dns_domain,
1198 .user = &sAMAccountName_l,
1199 .realm = &dns_domain_l,
1202 .user = &sAMAccountName_u,
1203 .realm = &dns_domain_u,
1206 .user = &sAMAccountName,
1207 .realm = &dns_domain_u,
1210 .user = &sAMAccountName,
1211 .realm = &dns_domain_l,
1214 .user = &sAMAccountName_u,
1215 .realm = &dns_domain_l,
1218 .user = &sAMAccountName_l,
1219 .realm = &dns_domain_u,
1222 * userPrincipalName, no realm
1225 .user = &userPrincipalName,
1229 * NOTE: w2k3 messes this up, if the user has a real userPrincipalName,
1230 * the fallback to the sAMAccountName based userPrincipalName is correct
1232 .user = &userPrincipalName_l,
1235 .user = &userPrincipalName_u,
1238 * nt4dom\sAMAccountName, no realm
1241 .user = &sAMAccountName,
1242 .nt4dom = &netbios_domain
1245 .user = &sAMAccountName_l,
1246 .nt4dom = &netbios_domain_l
1249 .user = &sAMAccountName_u,
1250 .nt4dom = &netbios_domain_u
1254 * the following ones are guessed depending on the technet2 article
1255 * but not reproducable on a w2k3 server
1257 /* sAMAccountName with "Digest" realm */
1259 .user = &sAMAccountName,
1260 .realm = &digest
1263 .user = &sAMAccountName_l,
1264 .realm = &digest
1267 .user = &sAMAccountName_u,
1268 .realm = &digest
1270 /* userPrincipalName with "Digest" realm */
1272 .user = &userPrincipalName,
1273 .realm = &digest
1276 .user = &userPrincipalName_l,
1277 .realm = &digest
1280 .user = &userPrincipalName_u,
1281 .realm = &digest
1283 /* nt4dom\\sAMAccountName with "Digest" realm */
1285 .user = &sAMAccountName,
1286 .nt4dom = &netbios_domain,
1287 .realm = &digest
1290 .user = &sAMAccountName_l,
1291 .nt4dom = &netbios_domain_l,
1292 .realm = &digest
1295 .user = &sAMAccountName_u,
1296 .nt4dom = &netbios_domain_u,
1297 .realm = &digest
1301 /* prepare DATA_BLOB's used in the combinations array */
1302 sAMAccountName = data_blob_string_const(io->u.sAMAccountName);
1303 sAMAccountName_l = data_blob_string_const(strlower_talloc(io->ac, io->u.sAMAccountName));
1304 if (!sAMAccountName_l.data) {
1305 return ldb_oom(ldb);
1307 sAMAccountName_u = data_blob_string_const(strupper_talloc(io->ac, io->u.sAMAccountName));
1308 if (!sAMAccountName_u.data) {
1309 return ldb_oom(ldb);
1312 /* if the user doesn't have a userPrincipalName, create one (with lower case realm) */
1313 if (!user_principal_name) {
1314 user_principal_name = talloc_asprintf(io->ac, "%s@%s",
1315 io->u.sAMAccountName,
1316 io->ac->status->domain_data.dns_domain);
1317 if (!user_principal_name) {
1318 return ldb_oom(ldb);
1321 userPrincipalName = data_blob_string_const(user_principal_name);
1322 userPrincipalName_l = data_blob_string_const(strlower_talloc(io->ac, user_principal_name));
1323 if (!userPrincipalName_l.data) {
1324 return ldb_oom(ldb);
1326 userPrincipalName_u = data_blob_string_const(strupper_talloc(io->ac, user_principal_name));
1327 if (!userPrincipalName_u.data) {
1328 return ldb_oom(ldb);
1331 netbios_domain = data_blob_string_const(io->ac->status->domain_data.netbios_domain);
1332 netbios_domain_l = data_blob_string_const(strlower_talloc(io->ac,
1333 io->ac->status->domain_data.netbios_domain));
1334 if (!netbios_domain_l.data) {
1335 return ldb_oom(ldb);
1337 netbios_domain_u = data_blob_string_const(strupper_talloc(io->ac,
1338 io->ac->status->domain_data.netbios_domain));
1339 if (!netbios_domain_u.data) {
1340 return ldb_oom(ldb);
1343 dns_domain = data_blob_string_const(io->ac->status->domain_data.dns_domain);
1344 dns_domain_l = data_blob_string_const(io->ac->status->domain_data.dns_domain);
1345 dns_domain_u = data_blob_string_const(io->ac->status->domain_data.realm);
1347 digest = data_blob_string_const("Digest");
1349 delim = data_blob_string_const(":");
1350 backslash = data_blob_string_const("\\");
1352 pdb->num_hashes = ARRAY_SIZE(wdigest);
1353 pdb->hashes = talloc_array(io->ac, struct package_PrimaryWDigestHash,
1354 pdb->num_hashes);
1355 if (!pdb->hashes) {
1356 return ldb_oom(ldb);
1359 for (i=0; i < ARRAY_SIZE(wdigest); i++) {
1360 MD5_CTX md5;
1361 MD5Init(&md5);
1362 if (wdigest[i].nt4dom) {
1363 MD5Update(&md5, wdigest[i].nt4dom->data, wdigest[i].nt4dom->length);
1364 MD5Update(&md5, backslash.data, backslash.length);
1366 MD5Update(&md5, wdigest[i].user->data, wdigest[i].user->length);
1367 MD5Update(&md5, delim.data, delim.length);
1368 if (wdigest[i].realm) {
1369 MD5Update(&md5, wdigest[i].realm->data, wdigest[i].realm->length);
1371 MD5Update(&md5, delim.data, delim.length);
1372 MD5Update(&md5, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length);
1373 MD5Final(pdb->hashes[i].hash, &md5);
1376 return LDB_SUCCESS;
1379 #define SHA_SALT_PERMITTED_CHARS "abcdefghijklmnopqrstuvwxyz" \
1380 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
1381 "0123456789./"
1382 #define SHA_SALT_SIZE 16
1383 #define SHA_256_SCHEME "CryptSHA256"
1384 #define SHA_512_SCHEME "CryptSHA512"
1385 #define CRYPT "{CRYPT}"
1386 #define SHA_ID_LEN 3
1387 #define SHA_256_ALGORITHM_ID 5
1388 #define SHA_512_ALGORITHM_ID 6
1389 #define ROUNDS_PARAMETER "rounds="
1392 * Extract the crypt (3) algorithm number and number of hash rounds from the
1393 * supplied scheme string
1395 static bool parse_scheme(const char *scheme, int *algorithm, int *rounds) {
1397 const char *rp = NULL; /* Pointer to the 'rounds=' option */
1398 char digits[21]; /* digits extracted from the rounds option */
1399 int i = 0; /* loop index variable */
1401 if (strncasecmp(SHA_256_SCHEME, scheme, strlen(SHA_256_SCHEME)) == 0) {
1402 *algorithm = SHA_256_ALGORITHM_ID;
1403 } else if (strncasecmp(SHA_512_SCHEME, scheme, strlen(SHA_256_SCHEME))
1404 == 0) {
1405 *algorithm = SHA_512_ALGORITHM_ID;
1406 } else {
1407 return false;
1410 rp = strcasestr(scheme, ROUNDS_PARAMETER);
1411 if (rp == NULL) {
1412 /* No options specified, use crypt default number of rounds */
1413 *rounds = 0;
1414 return true;
1416 rp += strlen(ROUNDS_PARAMETER);
1417 for (i = 0; isdigit(rp[i]) && i < (sizeof(digits) - 1); i++) {
1418 digits[i] = rp[i];
1420 digits[i] = '\0';
1421 *rounds = atoi(digits);
1422 return true;
1426 * Calculate the password hash specified by scheme, and return it in
1427 * hash_value
1429 static int setup_primary_userPassword_hash(
1430 TALLOC_CTX *ctx,
1431 struct setup_password_fields_io *io,
1432 const char* scheme,
1433 struct package_PrimaryUserPasswordValue *hash_value)
1435 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1436 const char *salt = NULL; /* Randomly generated salt */
1437 const char *cmd = NULL; /* command passed to crypt */
1438 const char *hash = NULL; /* password hash generated by crypt */
1439 int algorithm = 0; /* crypt hash algorithm number */
1440 int rounds = 0; /* The number of hash rounds */
1441 DATA_BLOB *hash_blob = NULL;
1442 TALLOC_CTX *frame = talloc_stackframe();
1443 #ifdef HAVE_CRYPT_R
1444 struct crypt_data crypt_data; /* working storage used by crypt */
1445 #endif
1447 /* Genrate a random password salt */
1448 salt = generate_random_str_list(frame,
1449 SHA_SALT_SIZE,
1450 SHA_SALT_PERMITTED_CHARS);
1451 if (salt == NULL) {
1452 TALLOC_FREE(frame);
1453 return ldb_oom(ldb);
1456 /* determine the hashing algoritm and number of rounds*/
1457 if (!parse_scheme(scheme, &algorithm, &rounds)) {
1458 ldb_asprintf_errstring(
1459 ldb,
1460 "setup_primary_userPassword: Invalid scheme of [%s] "
1461 "specified for 'password hash userPassword schemes' in "
1462 "samba.conf",
1463 scheme);
1464 TALLOC_FREE(frame);
1465 return LDB_ERR_OPERATIONS_ERROR;
1467 hash_value->scheme = talloc_strdup(ctx, CRYPT);
1468 hash_value->scheme_len = strlen(CRYPT) + 1;
1470 /* generate the id/salt parameter used by crypt */
1471 if (rounds) {
1472 cmd = talloc_asprintf(frame,
1473 "$%d$rounds=%d$%s",
1474 algorithm,
1475 rounds,
1476 salt);
1477 } else {
1478 cmd = talloc_asprintf(frame, "$%d$%s", algorithm, salt);
1482 * Relies on the assertion that cleartext_utf8->data is a zero
1483 * terminated UTF-8 string
1485 #ifdef HAVE_CRYPT_R
1486 hash = crypt_r((char *)io->n.cleartext_utf8->data, cmd, &crypt_data);
1487 #else
1489 * No crypt_r falling back to crypt, which is NOT thread safe
1490 * Thread safety MT-Unsafe race:crypt
1492 hash = crypt((char *)io->n.cleartext_utf8->data, cmd);
1493 #endif
1494 if (hash == NULL) {
1495 char buf[1024];
1496 int err = strerror_r(errno, buf, sizeof(buf));
1497 if (err != 0) {
1498 strlcpy(buf, "Unknown error", sizeof(buf)-1);
1500 ldb_asprintf_errstring(
1501 ldb,
1502 "setup_primary_userPassword: generation of a %s "
1503 "password hash failed: (%s)",
1504 scheme,
1505 buf);
1506 TALLOC_FREE(frame);
1507 return LDB_ERR_OPERATIONS_ERROR;
1510 hash_blob = talloc_zero(ctx, DATA_BLOB);
1512 if (hash_blob == NULL) {
1513 TALLOC_FREE(frame);
1514 return ldb_oom(ldb);
1517 *hash_blob = data_blob_talloc(hash_blob,
1518 (const uint8_t *)hash,
1519 strlen(hash));
1520 if (hash_blob->data == NULL) {
1521 TALLOC_FREE(frame);
1522 return ldb_oom(ldb);
1524 hash_value->value = hash_blob;
1525 TALLOC_FREE(frame);
1526 return LDB_SUCCESS;
1530 * Calculate the desired extra password hashes
1532 static int setup_primary_userPassword(
1533 struct setup_password_fields_io *io,
1534 const struct supplementalCredentialsBlob *old_scb,
1535 struct package_PrimaryUserPasswordBlob *p_userPassword_b)
1537 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1538 TALLOC_CTX *frame = talloc_stackframe();
1539 int i;
1540 int ret;
1543 * Save the current nt_hash, use this to determine if the password
1544 * has been changed by windows. Which will invalidate the userPassword
1545 * hash. Note once NTLM-Strong-NOWTF becomes available it should be
1546 * used in preference to the NT password hash
1548 if (io->g.nt_hash == NULL) {
1549 ldb_asprintf_errstring(ldb,
1550 "No NT Hash, unable to calculate userPassword hashes");
1551 return LDB_ERR_UNWILLING_TO_PERFORM;
1553 p_userPassword_b->current_nt_hash = *io->g.nt_hash;
1556 * Determine the number of hashes
1557 * Note: that currently there is no limit on the number of hashes
1558 * no checking is done on the number of schemes specified
1559 * or for uniqueness.
1561 p_userPassword_b->num_hashes = 0;
1562 for (i = 0; io->ac->userPassword_schemes[i]; i++) {
1563 p_userPassword_b->num_hashes++;
1566 p_userPassword_b->hashes
1567 = talloc_array(io->ac,
1568 struct package_PrimaryUserPasswordValue,
1569 p_userPassword_b->num_hashes);
1570 if (p_userPassword_b->hashes == NULL) {
1571 TALLOC_FREE(frame);
1572 return ldb_oom(ldb);
1575 for (i = 0; io->ac->userPassword_schemes[i]; i++) {
1576 ret = setup_primary_userPassword_hash(
1577 p_userPassword_b->hashes,
1579 io->ac->userPassword_schemes[i],
1580 &p_userPassword_b->hashes[i]);
1581 if (ret != LDB_SUCCESS) {
1582 TALLOC_FREE(frame);
1583 return ret;
1586 return LDB_SUCCESS;
1590 static int setup_primary_samba_gpg(struct setup_password_fields_io *io,
1591 struct package_PrimarySambaGPGBlob *pgb)
1593 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1594 #ifdef ENABLE_GPGME
1595 gpgme_error_t gret;
1596 gpgme_ctx_t ctx = NULL;
1597 size_t num_keys = str_list_length(io->ac->gpg_key_ids);
1598 gpgme_key_t keys[num_keys+1];
1599 size_t ki = 0;
1600 size_t kr = 0;
1601 gpgme_data_t plain_data = NULL;
1602 gpgme_data_t crypt_data = NULL;
1603 size_t crypt_length = 0;
1604 char *crypt_mem = NULL;
1606 gret = gpgme_new(&ctx);
1607 if (gret != GPG_ERR_NO_ERROR) {
1608 ldb_debug(ldb, LDB_DEBUG_ERROR,
1609 "%s:%s: gret[%u] %s\n",
1610 __location__, __func__,
1611 gret, gpgme_strerror(gret));
1612 return ldb_module_operr(io->ac->module);
1615 gpgme_set_armor(ctx, 1);
1617 gret = gpgme_data_new_from_mem(&plain_data,
1618 (const char *)io->n.cleartext_utf16->data,
1619 io->n.cleartext_utf16->length,
1620 0 /* no copy */);
1621 if (gret != GPG_ERR_NO_ERROR) {
1622 ldb_debug(ldb, LDB_DEBUG_ERROR,
1623 "%s:%s: gret[%u] %s\n",
1624 __location__, __func__,
1625 gret, gpgme_strerror(gret));
1626 gpgme_release(ctx);
1627 return ldb_module_operr(io->ac->module);
1629 gret = gpgme_data_new(&crypt_data);
1630 if (gret != GPG_ERR_NO_ERROR) {
1631 ldb_debug(ldb, LDB_DEBUG_ERROR,
1632 "%s:%s: gret[%u] %s\n",
1633 __location__, __func__,
1634 gret, gpgme_strerror(gret));
1635 gpgme_data_release(plain_data);
1636 gpgme_release(ctx);
1637 return ldb_module_operr(io->ac->module);
1640 for (ki = 0; ki < num_keys; ki++) {
1641 const char *key_id = io->ac->gpg_key_ids[ki];
1642 size_t len = strlen(key_id);
1644 keys[ki] = NULL;
1646 if (len < 16) {
1647 ldb_debug(ldb, LDB_DEBUG_FATAL,
1648 "%s:%s: ki[%zu] key_id[%s] strlen < 16, "
1649 "please specify at least the 64bit key id\n",
1650 __location__, __func__,
1651 ki, key_id);
1652 for (kr = 0; keys[kr] != NULL; kr++) {
1653 gpgme_key_release(keys[kr]);
1655 gpgme_data_release(crypt_data);
1656 gpgme_data_release(plain_data);
1657 gpgme_release(ctx);
1658 return ldb_module_operr(io->ac->module);
1661 gret = gpgme_get_key(ctx, key_id, &keys[ki], 0 /* public key */);
1662 if (gret != GPG_ERR_NO_ERROR) {
1663 keys[ki] = NULL;
1664 if (gpg_err_source(gret) == GPG_ERR_SOURCE_GPGME
1665 && gpg_err_code(gret) == GPG_ERR_EOF) {
1666 ldb_debug(ldb, LDB_DEBUG_ERROR,
1667 "Invalid "
1668 "'password hash gpg key ids': "
1669 "Public Key ID [%s] "
1670 "not found in keyring\n",
1671 key_id);
1673 } else {
1674 ldb_debug(ldb, LDB_DEBUG_ERROR,
1675 "%s:%s: ki[%zu] key_id[%s] "
1676 "gret[%u] %s\n",
1677 __location__, __func__,
1678 ki, key_id,
1679 gret, gpgme_strerror(gret));
1681 for (kr = 0; keys[kr] != NULL; kr++) {
1682 gpgme_key_release(keys[kr]);
1684 gpgme_data_release(crypt_data);
1685 gpgme_data_release(plain_data);
1686 gpgme_release(ctx);
1687 return ldb_module_operr(io->ac->module);
1690 keys[ki] = NULL;
1692 gret = gpgme_op_encrypt(ctx, keys,
1693 GPGME_ENCRYPT_ALWAYS_TRUST,
1694 plain_data, crypt_data);
1695 gpgme_data_release(plain_data);
1696 plain_data = NULL;
1697 for (kr = 0; keys[kr] != NULL; kr++) {
1698 gpgme_key_release(keys[kr]);
1699 keys[kr] = NULL;
1701 gpgme_release(ctx);
1702 ctx = NULL;
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_data_release(crypt_data);
1709 return ldb_module_operr(io->ac->module);
1712 crypt_mem = gpgme_data_release_and_get_mem(crypt_data, &crypt_length);
1713 crypt_data = NULL;
1714 if (crypt_mem == NULL) {
1715 return ldb_module_oom(io->ac->module);
1718 pgb->gpg_blob = data_blob_talloc(io->ac,
1719 (const uint8_t *)crypt_mem,
1720 crypt_length);
1721 gpgme_free(crypt_mem);
1722 crypt_mem = NULL;
1723 crypt_length = 0;
1724 if (pgb->gpg_blob.data == NULL) {
1725 return ldb_module_oom(io->ac->module);
1728 return LDB_SUCCESS;
1729 #else /* ENABLE_GPGME */
1730 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
1731 "You configured 'password hash gpg key ids', "
1732 "but GPGME support is missing. (%s:%d)",
1733 __FILE__, __LINE__);
1734 return LDB_ERR_UNWILLING_TO_PERFORM;
1735 #endif /* else ENABLE_GPGME */
1738 #define NUM_PACKAGES 6
1739 static int setup_supplemental_field(struct setup_password_fields_io *io)
1741 struct ldb_context *ldb;
1742 struct supplementalCredentialsBlob scb;
1743 struct supplementalCredentialsBlob *old_scb = NULL;
1745 * Packages +
1746 * ( Kerberos-Newer-Keys, Kerberos,
1747 * WDigest, CLEARTEXT, userPassword, SambaGPG)
1749 uint32_t num_names = 0;
1750 const char *names[1+NUM_PACKAGES];
1751 uint32_t num_packages = 0;
1752 struct supplementalCredentialsPackage packages[1+NUM_PACKAGES];
1753 struct supplementalCredentialsPackage *pp = packages;
1754 int ret;
1755 enum ndr_err_code ndr_err;
1756 bool do_newer_keys = false;
1757 bool do_cleartext = false;
1758 bool do_samba_gpg = false;
1760 ZERO_STRUCT(names);
1761 ZERO_STRUCT(packages);
1763 ldb = ldb_module_get_ctx(io->ac->module);
1765 if (!io->n.cleartext_utf8) {
1767 * when we don't have a cleartext password
1768 * we can't setup a supplementalCredential value
1770 return LDB_SUCCESS;
1773 /* if there's an old supplementaCredentials blob then use it */
1774 if (io->o.supplemental) {
1775 if (io->o.scb.sub.signature == SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
1776 old_scb = &io->o.scb;
1777 } else {
1778 ldb_debug(ldb, LDB_DEBUG_ERROR,
1779 "setup_supplemental_field: "
1780 "supplementalCredentialsBlob "
1781 "signature[0x%04X] expected[0x%04X]",
1782 io->o.scb.sub.signature,
1783 SUPPLEMENTAL_CREDENTIALS_SIGNATURE);
1786 /* Per MS-SAMR 3.1.1.8.11.6 we create AES keys if our domain functionality level is 2008 or higher */
1791 * The ordering is this
1793 * Primary:Kerberos-Newer-Keys (optional)
1794 * Primary:Kerberos
1795 * Primary:WDigest
1796 * Primary:CLEARTEXT (optional)
1797 * Primary:userPassword
1798 * Primary:SambaGPG (optional)
1800 * And the 'Packages' package is insert before the last
1801 * other package.
1803 * Note: it's important that Primary:SambaGPG is added as
1804 * the last element. This is the indication that it matches
1805 * the current password. When a password change happens on
1806 * a Windows DC, it will keep the old Primary:SambaGPG value,
1807 * but as the first element.
1809 do_newer_keys = (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008);
1810 if (do_newer_keys) {
1811 struct package_PrimaryKerberosBlob pknb;
1812 DATA_BLOB pknb_blob;
1813 char *pknb_hexstr;
1815 * setup 'Primary:Kerberos-Newer-Keys' element
1817 names[num_names++] = "Kerberos-Newer-Keys";
1819 ret = setup_primary_kerberos_newer(io, old_scb, &pknb);
1820 if (ret != LDB_SUCCESS) {
1821 return ret;
1824 ndr_err = ndr_push_struct_blob(
1825 &pknb_blob, io->ac,
1826 &pknb,
1827 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1828 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1829 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1830 ldb_asprintf_errstring(
1831 ldb,
1832 "setup_supplemental_field: "
1833 "failed to push "
1834 "package_PrimaryKerberosNeverBlob: %s",
1835 nt_errstr(status));
1836 return LDB_ERR_OPERATIONS_ERROR;
1838 pknb_hexstr = data_blob_hex_string_upper(io->ac, &pknb_blob);
1839 if (!pknb_hexstr) {
1840 return ldb_oom(ldb);
1842 pp->name = "Primary:Kerberos-Newer-Keys";
1843 pp->reserved = 1;
1844 pp->data = pknb_hexstr;
1845 pp++;
1846 num_packages++;
1851 * setup 'Primary:Kerberos' element
1853 /* Primary:Kerberos */
1854 struct package_PrimaryKerberosBlob pkb;
1855 DATA_BLOB pkb_blob;
1856 char *pkb_hexstr;
1858 names[num_names++] = "Kerberos";
1860 ret = setup_primary_kerberos(io, old_scb, &pkb);
1861 if (ret != LDB_SUCCESS) {
1862 return ret;
1865 ndr_err = ndr_push_struct_blob(
1866 &pkb_blob, io->ac,
1867 &pkb,
1868 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1869 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1870 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1871 ldb_asprintf_errstring(
1872 ldb,
1873 "setup_supplemental_field: "
1874 "failed to push package_PrimaryKerberosBlob: %s",
1875 nt_errstr(status));
1876 return LDB_ERR_OPERATIONS_ERROR;
1878 pkb_hexstr = data_blob_hex_string_upper(io->ac, &pkb_blob);
1879 if (!pkb_hexstr) {
1880 return ldb_oom(ldb);
1882 pp->name = "Primary:Kerberos";
1883 pp->reserved = 1;
1884 pp->data = pkb_hexstr;
1885 pp++;
1886 num_packages++;
1891 * setup 'Primary:WDigest' element
1893 struct package_PrimaryWDigestBlob pdb;
1894 DATA_BLOB pdb_blob;
1895 char *pdb_hexstr;
1897 names[num_names++] = "WDigest";
1899 ret = setup_primary_wdigest(io, old_scb, &pdb);
1900 if (ret != LDB_SUCCESS) {
1901 return ret;
1904 ndr_err = ndr_push_struct_blob(
1905 &pdb_blob, io->ac,
1906 &pdb,
1907 (ndr_push_flags_fn_t)ndr_push_package_PrimaryWDigestBlob);
1908 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1909 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1910 ldb_asprintf_errstring(
1911 ldb,
1912 "setup_supplemental_field: "
1913 "failed to push package_PrimaryWDigestBlob: %s",
1914 nt_errstr(status));
1915 return LDB_ERR_OPERATIONS_ERROR;
1917 pdb_hexstr = data_blob_hex_string_upper(io->ac, &pdb_blob);
1918 if (!pdb_hexstr) {
1919 return ldb_oom(ldb);
1921 pp->name = "Primary:WDigest";
1922 pp->reserved = 1;
1923 pp->data = pdb_hexstr;
1924 pp++;
1925 num_packages++;
1929 * setup 'Primary:CLEARTEXT' element
1931 if (io->ac->status->domain_data.store_cleartext &&
1932 (io->u.userAccountControl & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) {
1933 do_cleartext = true;
1935 if (do_cleartext) {
1936 struct package_PrimaryCLEARTEXTBlob pcb;
1937 DATA_BLOB pcb_blob;
1938 char *pcb_hexstr;
1940 names[num_names++] = "CLEARTEXT";
1942 pcb.cleartext = *io->n.cleartext_utf16;
1944 ndr_err = ndr_push_struct_blob(
1945 &pcb_blob, io->ac,
1946 &pcb,
1947 (ndr_push_flags_fn_t)ndr_push_package_PrimaryCLEARTEXTBlob);
1948 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1949 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1950 ldb_asprintf_errstring(
1951 ldb,
1952 "setup_supplemental_field: "
1953 "failed to push package_PrimaryCLEARTEXTBlob: %s",
1954 nt_errstr(status));
1955 return LDB_ERR_OPERATIONS_ERROR;
1957 pcb_hexstr = data_blob_hex_string_upper(io->ac, &pcb_blob);
1958 if (!pcb_hexstr) {
1959 return ldb_oom(ldb);
1961 pp->name = "Primary:CLEARTEXT";
1962 pp->reserved = 1;
1963 pp->data = pcb_hexstr;
1964 pp++;
1965 num_packages++;
1968 if (io->ac->userPassword_schemes) {
1970 * setup 'Primary:userPassword' element
1972 struct package_PrimaryUserPasswordBlob
1973 p_userPassword_b;
1974 DATA_BLOB p_userPassword_b_blob;
1975 char *p_userPassword_b_hexstr;
1977 names[num_names++] = "userPassword";
1979 ret = setup_primary_userPassword(io,
1980 old_scb,
1981 &p_userPassword_b);
1982 if (ret != LDB_SUCCESS) {
1983 return ret;
1986 ndr_err = ndr_push_struct_blob(
1987 &p_userPassword_b_blob,
1988 io->ac,
1989 &p_userPassword_b,
1990 (ndr_push_flags_fn_t)
1991 ndr_push_package_PrimaryUserPasswordBlob);
1992 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1993 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1994 ldb_asprintf_errstring(
1995 ldb,
1996 "setup_supplemental_field: failed to push "
1997 "package_PrimaryUserPasswordBlob: %s",
1998 nt_errstr(status));
1999 return LDB_ERR_OPERATIONS_ERROR;
2001 p_userPassword_b_hexstr
2002 = data_blob_hex_string_upper(
2003 io->ac,
2004 &p_userPassword_b_blob);
2005 if (!p_userPassword_b_hexstr) {
2006 return ldb_oom(ldb);
2008 pp->name = "Primary:userPassword";
2009 pp->reserved = 1;
2010 pp->data = p_userPassword_b_hexstr;
2011 pp++;
2012 num_packages++;
2016 * setup 'Primary:SambaGPG' element
2018 if (io->ac->gpg_key_ids != NULL) {
2019 do_samba_gpg = true;
2021 if (do_samba_gpg) {
2022 struct package_PrimarySambaGPGBlob pgb;
2023 DATA_BLOB pgb_blob;
2024 char *pgb_hexstr;
2026 names[num_names++] = "SambaGPG";
2028 ret = setup_primary_samba_gpg(io, &pgb);
2029 if (ret != LDB_SUCCESS) {
2030 return ret;
2033 ndr_err = ndr_push_struct_blob(&pgb_blob, io->ac, &pgb,
2034 (ndr_push_flags_fn_t)ndr_push_package_PrimarySambaGPGBlob);
2035 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2036 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2037 ldb_asprintf_errstring(ldb,
2038 "setup_supplemental_field: failed to "
2039 "push package_PrimarySambaGPGBlob: %s",
2040 nt_errstr(status));
2041 return LDB_ERR_OPERATIONS_ERROR;
2043 pgb_hexstr = data_blob_hex_string_upper(io->ac, &pgb_blob);
2044 if (!pgb_hexstr) {
2045 return ldb_oom(ldb);
2047 pp->name = "Primary:SambaGPG";
2048 pp->reserved = 1;
2049 pp->data = pgb_hexstr;
2050 pp++;
2051 num_packages++;
2055 * setup 'Packages' element
2058 struct package_PackagesBlob pb;
2059 DATA_BLOB pb_blob;
2060 char *pb_hexstr;
2062 pb.names = names;
2063 ndr_err = ndr_push_struct_blob(
2064 &pb_blob, io->ac,
2065 &pb,
2066 (ndr_push_flags_fn_t)ndr_push_package_PackagesBlob);
2067 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2068 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2069 ldb_asprintf_errstring(
2070 ldb,
2071 "setup_supplemental_field: "
2072 "failed to push package_PackagesBlob: %s",
2073 nt_errstr(status));
2074 return LDB_ERR_OPERATIONS_ERROR;
2076 pb_hexstr = data_blob_hex_string_upper(io->ac, &pb_blob);
2077 if (!pb_hexstr) {
2078 return ldb_oom(ldb);
2080 pp->name = "Packages";
2081 pp->reserved = 2;
2082 pp->data = pb_hexstr;
2083 num_packages++;
2085 * We don't increment pp so it's pointing to the last package
2090 * setup 'supplementalCredentials' value
2094 * The 'Packages' element needs to be the second last element
2095 * in supplementalCredentials
2097 struct supplementalCredentialsPackage temp;
2098 struct supplementalCredentialsPackage *prev;
2100 prev = pp-1;
2101 temp = *prev;
2102 *prev = *pp;
2103 *pp = temp;
2105 ZERO_STRUCT(scb);
2106 scb.sub.signature = SUPPLEMENTAL_CREDENTIALS_SIGNATURE;
2107 scb.sub.num_packages = num_packages;
2108 scb.sub.packages = packages;
2110 ndr_err = ndr_push_struct_blob(
2111 &io->g.supplemental, io->ac,
2112 &scb,
2113 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
2114 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2115 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2116 ldb_asprintf_errstring(
2117 ldb,
2118 "setup_supplemental_field: "
2119 "failed to push supplementalCredentialsBlob: %s",
2120 nt_errstr(status));
2121 return LDB_ERR_OPERATIONS_ERROR;
2125 return LDB_SUCCESS;
2128 static int setup_last_set_field(struct setup_password_fields_io *io)
2130 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2131 const struct ldb_message *msg = NULL;
2132 struct timeval tv = { .tv_sec = 0 };
2133 const struct ldb_val *old_val = NULL;
2134 const struct ldb_val *new_val = NULL;
2135 int ret;
2137 switch (io->ac->req->operation) {
2138 case LDB_ADD:
2139 msg = io->ac->req->op.add.message;
2140 break;
2141 case LDB_MODIFY:
2142 msg = io->ac->req->op.mod.message;
2143 break;
2144 default:
2145 return LDB_ERR_OPERATIONS_ERROR;
2146 break;
2149 if (io->ac->pwd_last_set_bypass) {
2150 struct ldb_message_element *el1 = NULL;
2151 struct ldb_message_element *el2 = NULL;
2153 if (msg == NULL) {
2154 return LDB_ERR_CONSTRAINT_VIOLATION;
2157 el1 = dsdb_get_single_valued_attr(msg, "pwdLastSet",
2158 io->ac->req->operation);
2159 if (el1 == NULL) {
2160 return LDB_ERR_CONSTRAINT_VIOLATION;
2162 el2 = ldb_msg_find_element(msg, "pwdLastSet");
2163 if (el2 == NULL) {
2164 return LDB_ERR_CONSTRAINT_VIOLATION;
2166 if (el1 != el2) {
2167 return LDB_ERR_CONSTRAINT_VIOLATION;
2170 io->g.last_set = samdb_result_nttime(msg, "pwdLastSet", 0);
2171 return LDB_SUCCESS;
2174 ret = msg_find_old_and_new_pwd_val(msg, "pwdLastSet",
2175 io->ac->req->operation,
2176 &new_val, &old_val);
2177 if (ret != LDB_SUCCESS) {
2178 return ret;
2181 if (old_val != NULL && new_val == NULL) {
2182 ldb_set_errstring(ldb,
2183 "'pwdLastSet' deletion is not allowed!");
2184 return LDB_ERR_UNWILLING_TO_PERFORM;
2187 io->g.last_set = UINT64_MAX;
2188 if (new_val != NULL) {
2189 struct ldb_message *tmp_msg = NULL;
2191 tmp_msg = ldb_msg_new(io->ac);
2192 if (tmp_msg == NULL) {
2193 return ldb_module_oom(io->ac->module);
2196 if (old_val != NULL) {
2197 NTTIME old_last_set = 0;
2199 ret = ldb_msg_add_value(tmp_msg, "oldval",
2200 old_val, NULL);
2201 if (ret != LDB_SUCCESS) {
2202 return ret;
2205 old_last_set = samdb_result_nttime(tmp_msg,
2206 "oldval",
2208 if (io->u.pwdLastSet != old_last_set) {
2209 return dsdb_module_werror(io->ac->module,
2210 LDB_ERR_NO_SUCH_ATTRIBUTE,
2211 WERR_DS_CANT_REM_MISSING_ATT_VAL,
2212 "setup_last_set_field: old pwdLastSet "
2213 "value not found!");
2217 ret = ldb_msg_add_value(tmp_msg, "newval",
2218 new_val, NULL);
2219 if (ret != LDB_SUCCESS) {
2220 return ret;
2223 io->g.last_set = samdb_result_nttime(tmp_msg,
2224 "newval",
2226 } else if (ldb_msg_find_element(msg, "pwdLastSet")) {
2227 ldb_set_errstring(ldb,
2228 "'pwdLastSet' deletion is not allowed!");
2229 return LDB_ERR_UNWILLING_TO_PERFORM;
2230 } else if (io->ac->smartcard_reset) {
2232 * adding UF_SMARTCARD_REQUIRED doesn't update
2233 * pwdLastSet implicitly.
2235 io->ac->update_lastset = false;
2238 /* only 0 or -1 (0xFFFFFFFFFFFFFFFF) are allowed */
2239 switch (io->g.last_set) {
2240 case 0:
2241 if (!io->ac->pwd_last_set_default) {
2242 break;
2244 if (!io->ac->update_password) {
2245 break;
2247 FALL_THROUGH;
2248 case UINT64_MAX:
2249 if (!io->ac->update_password &&
2250 io->u.pwdLastSet != 0 &&
2251 io->u.pwdLastSet != UINT64_MAX)
2254 * Just setting pwdLastSet to -1, while not changing
2255 * any password field has no effect if pwdLastSet
2256 * is already non-zero.
2258 io->ac->update_lastset = false;
2259 break;
2261 /* -1 means set it as now */
2262 GetTimeOfDay(&tv);
2263 io->g.last_set = timeval_to_nttime(&tv);
2264 break;
2265 default:
2266 return dsdb_module_werror(io->ac->module,
2267 LDB_ERR_OTHER,
2268 WERR_INVALID_PARAMETER,
2269 "setup_last_set_field: "
2270 "pwdLastSet must be 0 or -1 only!");
2273 if (io->ac->req->operation == LDB_ADD) {
2275 * We always need to store the value on add
2276 * operations.
2278 return LDB_SUCCESS;
2281 if (io->g.last_set == io->u.pwdLastSet) {
2283 * Just setting pwdLastSet to 0, is no-op if it's already 0.
2285 io->ac->update_lastset = false;
2288 return LDB_SUCCESS;
2291 static int setup_given_passwords(struct setup_password_fields_io *io,
2292 struct setup_password_fields_given *g)
2294 struct ldb_context *ldb;
2295 bool ok;
2297 ldb = ldb_module_get_ctx(io->ac->module);
2299 if (g->cleartext_utf8) {
2300 struct ldb_val *cleartext_utf16_blob;
2302 cleartext_utf16_blob = talloc(io->ac, struct ldb_val);
2303 if (!cleartext_utf16_blob) {
2304 return ldb_oom(ldb);
2306 if (!convert_string_talloc(io->ac,
2307 CH_UTF8, CH_UTF16,
2308 g->cleartext_utf8->data,
2309 g->cleartext_utf8->length,
2310 (void *)&cleartext_utf16_blob->data,
2311 &cleartext_utf16_blob->length)) {
2312 if (g->cleartext_utf8->length != 0) {
2313 talloc_free(cleartext_utf16_blob);
2314 ldb_asprintf_errstring(ldb,
2315 "setup_password_fields: "
2316 "failed to generate UTF16 password from cleartext UTF8 one for user '%s'!",
2317 io->u.sAMAccountName);
2318 return LDB_ERR_CONSTRAINT_VIOLATION;
2319 } else {
2320 /* passwords with length "0" are valid! */
2321 cleartext_utf16_blob->data = NULL;
2322 cleartext_utf16_blob->length = 0;
2325 g->cleartext_utf16 = cleartext_utf16_blob;
2326 } else if (g->cleartext_utf16) {
2327 struct ldb_val *cleartext_utf8_blob;
2329 cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
2330 if (!cleartext_utf8_blob) {
2331 return ldb_oom(ldb);
2333 if (!convert_string_talloc(io->ac,
2334 CH_UTF16MUNGED, CH_UTF8,
2335 g->cleartext_utf16->data,
2336 g->cleartext_utf16->length,
2337 (void *)&cleartext_utf8_blob->data,
2338 &cleartext_utf8_blob->length)) {
2339 if (g->cleartext_utf16->length != 0) {
2340 /* We must bail out here, the input wasn't even
2341 * a multiple of 2 bytes */
2342 talloc_free(cleartext_utf8_blob);
2343 ldb_asprintf_errstring(ldb,
2344 "setup_password_fields: "
2345 "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)!",
2346 io->u.sAMAccountName);
2347 return LDB_ERR_CONSTRAINT_VIOLATION;
2348 } else {
2349 /* passwords with length "0" are valid! */
2350 cleartext_utf8_blob->data = NULL;
2351 cleartext_utf8_blob->length = 0;
2354 g->cleartext_utf8 = cleartext_utf8_blob;
2357 if (g->cleartext_utf16) {
2358 struct samr_Password *nt_hash;
2360 nt_hash = talloc(io->ac, struct samr_Password);
2361 if (!nt_hash) {
2362 return ldb_oom(ldb);
2364 g->nt_hash = nt_hash;
2366 /* compute the new nt hash */
2367 mdfour(nt_hash->hash,
2368 g->cleartext_utf16->data,
2369 g->cleartext_utf16->length);
2372 if (g->cleartext_utf8) {
2373 struct samr_Password *lm_hash;
2375 lm_hash = talloc(io->ac, struct samr_Password);
2376 if (!lm_hash) {
2377 return ldb_oom(ldb);
2380 /* compute the new lm hash */
2381 ok = E_deshash((char *)g->cleartext_utf8->data, lm_hash->hash);
2382 if (ok) {
2383 g->lm_hash = lm_hash;
2384 } else {
2385 talloc_free(lm_hash);
2389 return LDB_SUCCESS;
2392 static int setup_password_fields(struct setup_password_fields_io *io)
2394 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2395 struct loadparm_context *lp_ctx =
2396 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2397 struct loadparm_context);
2398 int ret;
2400 ret = setup_last_set_field(io);
2401 if (ret != LDB_SUCCESS) {
2402 return ret;
2405 if (!io->ac->update_password) {
2406 return LDB_SUCCESS;
2409 /* transform the old password (for password changes) */
2410 ret = setup_given_passwords(io, &io->og);
2411 if (ret != LDB_SUCCESS) {
2412 return ret;
2415 /* transform the new password */
2416 ret = setup_given_passwords(io, &io->n);
2417 if (ret != LDB_SUCCESS) {
2418 return ret;
2421 if (io->n.cleartext_utf8) {
2422 ret = setup_kerberos_keys(io);
2423 if (ret != LDB_SUCCESS) {
2424 return ret;
2428 ret = setup_nt_fields(io);
2429 if (ret != LDB_SUCCESS) {
2430 return ret;
2433 if (lpcfg_lanman_auth(lp_ctx)) {
2434 ret = setup_lm_fields(io);
2435 if (ret != LDB_SUCCESS) {
2436 return ret;
2438 } else {
2439 io->g.lm_hash = NULL;
2440 io->g.lm_history_len = 0;
2443 ret = setup_supplemental_field(io);
2444 if (ret != LDB_SUCCESS) {
2445 return ret;
2448 return LDB_SUCCESS;
2451 static int setup_smartcard_reset(struct setup_password_fields_io *io)
2453 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2454 struct loadparm_context *lp_ctx = talloc_get_type(
2455 ldb_get_opaque(ldb, "loadparm"), struct loadparm_context);
2456 struct supplementalCredentialsBlob scb = { .__ndr_size = 0 };
2457 enum ndr_err_code ndr_err;
2459 if (!io->ac->smartcard_reset) {
2460 return LDB_SUCCESS;
2463 io->g.nt_hash = talloc(io->ac, struct samr_Password);
2464 if (io->g.nt_hash == NULL) {
2465 return ldb_module_oom(io->ac->module);
2467 generate_secret_buffer(io->g.nt_hash->hash,
2468 sizeof(io->g.nt_hash->hash));
2469 io->g.nt_history_len = 0;
2471 if (lpcfg_lanman_auth(lp_ctx)) {
2472 io->g.lm_hash = talloc(io->ac, struct samr_Password);
2473 if (io->g.lm_hash == NULL) {
2474 return ldb_module_oom(io->ac->module);
2476 generate_secret_buffer(io->g.lm_hash->hash,
2477 sizeof(io->g.lm_hash->hash));
2478 } else {
2479 io->g.lm_hash = NULL;
2481 io->g.lm_history_len = 0;
2484 * We take the "old" value and store it
2485 * with num_packages = 0.
2487 * On "add" we have scb.sub.signature == 0, which
2488 * results in:
2490 * [0000] 00 00 00 00 00 00 00 00 00 00 00 00 00
2492 * On modify it's likely to be scb.sub.signature ==
2493 * SUPPLEMENTAL_CREDENTIALS_SIGNATURE (0x0050), which results in
2494 * something like:
2496 * [0000] 00 00 00 00 62 00 00 00 00 00 00 00 20 00 20 00
2497 * [0010] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2498 * [0020] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2499 * [0030] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2500 * [0040] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2501 * [0050] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2502 * [0060] 20 00 20 00 20 00 20 00 20 00 20 00 50 00 00
2504 * See https://bugzilla.samba.org/show_bug.cgi?id=11441
2505 * and ndr_{push,pull}_supplementalCredentialsSubBlob().
2507 scb = io->o.scb;
2508 scb.sub.num_packages = 0;
2511 * setup 'supplementalCredentials' value without packages
2513 ndr_err = ndr_push_struct_blob(&io->g.supplemental, io->ac,
2514 &scb,
2515 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
2516 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2517 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2518 ldb_asprintf_errstring(ldb,
2519 "setup_smartcard_reset: "
2520 "failed to push supplementalCredentialsBlob: %s",
2521 nt_errstr(status));
2522 return LDB_ERR_OPERATIONS_ERROR;
2525 io->ac->update_password = true;
2526 return LDB_SUCCESS;
2529 static int make_error_and_update_badPwdCount(struct setup_password_fields_io *io, WERROR *werror)
2531 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2532 struct ldb_message *mod_msg = NULL;
2533 struct ldb_message *pso_msg = NULL;
2534 NTSTATUS status;
2535 int ret;
2537 /* PSO search result is optional (NULL if no PSO applies) */
2538 if (io->ac->pso_res != NULL) {
2539 pso_msg = io->ac->pso_res->message;
2542 status = dsdb_update_bad_pwd_count(io->ac, ldb,
2543 io->ac->search_res->message,
2544 io->ac->dom_res->message,
2545 pso_msg,
2546 &mod_msg);
2547 if (!NT_STATUS_IS_OK(status)) {
2548 goto done;
2551 if (mod_msg == NULL) {
2552 goto done;
2556 * OK, horrible semantics ahead.
2558 * - We need to abort any existing transaction
2559 * - create a transaction arround the badPwdCount update
2560 * - re-open the transaction so the upper layer
2561 * doesn't know what happened.
2563 * This is needed because returning an error to the upper
2564 * layer will cancel the transaction and undo the badPwdCount
2565 * update.
2569 * Checking errors here is a bit pointless.
2570 * What can we do if we can't end the transaction?
2572 ret = ldb_next_del_trans(io->ac->module);
2573 if (ret != LDB_SUCCESS) {
2574 ldb_debug(ldb, LDB_DEBUG_FATAL,
2575 "Failed to abort transaction prior to update of badPwdCount of %s: %s",
2576 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2577 ldb_errstring(ldb));
2579 * just return the original error
2581 goto done;
2584 /* Likewise, what should we do if we can't open a new transaction? */
2585 ret = ldb_next_start_trans(io->ac->module);
2586 if (ret != LDB_SUCCESS) {
2587 ldb_debug(ldb, LDB_DEBUG_ERROR,
2588 "Failed to open transaction to update badPwdCount of %s: %s",
2589 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2590 ldb_errstring(ldb));
2592 * just return the original error
2594 goto done;
2597 ret = dsdb_module_modify(io->ac->module, mod_msg,
2598 DSDB_FLAG_NEXT_MODULE,
2599 io->ac->req);
2600 if (ret != LDB_SUCCESS) {
2601 ldb_debug(ldb, LDB_DEBUG_ERROR,
2602 "Failed to update badPwdCount of %s: %s",
2603 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2604 ldb_errstring(ldb));
2606 * We can only ignore this...
2610 ret = ldb_next_end_trans(io->ac->module);
2611 if (ret != LDB_SUCCESS) {
2612 ldb_debug(ldb, LDB_DEBUG_ERROR,
2613 "Failed to close transaction to update badPwdCount of %s: %s",
2614 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2615 ldb_errstring(ldb));
2617 * We can only ignore this...
2621 ret = ldb_next_start_trans(io->ac->module);
2622 if (ret != LDB_SUCCESS) {
2623 ldb_debug(ldb, LDB_DEBUG_ERROR,
2624 "Failed to open transaction after update of badPwdCount of %s: %s",
2625 ldb_dn_get_linearized(io->ac->search_res->message->dn),
2626 ldb_errstring(ldb));
2628 * We can only ignore this...
2632 done:
2633 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2634 *werror = WERR_INVALID_PASSWORD;
2635 ldb_asprintf_errstring(ldb,
2636 "%08X: %s - check_password_restrictions: "
2637 "The old password specified doesn't match!",
2638 W_ERROR_V(*werror),
2639 ldb_strerror(ret));
2640 return ret;
2643 static int check_password_restrictions(struct setup_password_fields_io *io, WERROR *werror)
2645 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2646 int ret;
2647 struct loadparm_context *lp_ctx =
2648 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2649 struct loadparm_context);
2651 *werror = WERR_INVALID_PARAMETER;
2653 if (!io->ac->update_password) {
2654 return LDB_SUCCESS;
2657 /* First check the old password is correct, for password changes */
2658 if (!io->ac->pwd_reset) {
2659 bool nt_hash_checked = false;
2661 /* we need the old nt or lm hash given by the client */
2662 if (!io->og.nt_hash && !io->og.lm_hash) {
2663 ldb_asprintf_errstring(ldb,
2664 "check_password_restrictions: "
2665 "You need to provide the old password in order "
2666 "to change it!");
2667 return LDB_ERR_UNWILLING_TO_PERFORM;
2670 /* The password modify through the NT hash is encouraged and
2671 has no problems at all */
2672 if (io->og.nt_hash) {
2673 if (!io->o.nt_hash || memcmp(io->og.nt_hash->hash, io->o.nt_hash->hash, 16) != 0) {
2674 return make_error_and_update_badPwdCount(io, werror);
2677 nt_hash_checked = true;
2680 /* But it is also possible to change a password by the LM hash
2681 * alone for compatibility reasons. This check is optional if
2682 * the NT hash was already checked - otherwise it's mandatory.
2683 * (as the SAMR operations request it). */
2684 if (io->og.lm_hash) {
2685 if ((!io->o.lm_hash && !nt_hash_checked)
2686 || (io->o.lm_hash && memcmp(io->og.lm_hash->hash, io->o.lm_hash->hash, 16) != 0)) {
2687 return make_error_and_update_badPwdCount(io, werror);
2692 if (io->u.restrictions == 0) {
2693 /* FIXME: Is this right? */
2694 return LDB_SUCCESS;
2697 /* Password minimum age: yes, this is a minus. The ages are in negative 100nsec units! */
2698 if ((io->u.pwdLastSet - io->ac->status->domain_data.minPwdAge > io->g.last_set) &&
2699 !io->ac->pwd_reset)
2701 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2702 *werror = WERR_PASSWORD_RESTRICTION;
2703 ldb_asprintf_errstring(ldb,
2704 "%08X: %s - check_password_restrictions: "
2705 "password is too young to change!",
2706 W_ERROR_V(*werror),
2707 ldb_strerror(ret));
2708 return ret;
2712 * Fundamental password checks done by the call
2713 * "samdb_check_password".
2714 * It is also in use by "dcesrv_samr_ValidatePassword".
2716 if (io->n.cleartext_utf8 != NULL) {
2717 enum samr_ValidationStatus vstat;
2718 vstat = samdb_check_password(io->ac, lp_ctx,
2719 io->n.cleartext_utf8,
2720 io->ac->status->domain_data.pwdProperties,
2721 io->ac->status->domain_data.minPwdLength);
2722 switch (vstat) {
2723 case SAMR_VALIDATION_STATUS_SUCCESS:
2724 /* perfect -> proceed! */
2725 break;
2727 case SAMR_VALIDATION_STATUS_PWD_TOO_SHORT:
2728 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2729 *werror = WERR_PASSWORD_RESTRICTION;
2730 ldb_asprintf_errstring(ldb,
2731 "%08X: %s - check_password_restrictions: "
2732 "the password is too short. It should be equal or longer than %u characters!",
2733 W_ERROR_V(*werror),
2734 ldb_strerror(ret),
2735 io->ac->status->domain_data.minPwdLength);
2736 io->ac->status->reject_reason = SAM_PWD_CHANGE_PASSWORD_TOO_SHORT;
2737 return ret;
2739 case SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH:
2740 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2741 *werror = WERR_PASSWORD_RESTRICTION;
2742 ldb_asprintf_errstring(ldb,
2743 "%08X: %s - check_password_restrictions: "
2744 "the password does not meet the complexity criteria!",
2745 W_ERROR_V(*werror),
2746 ldb_strerror(ret));
2747 io->ac->status->reject_reason = SAM_PWD_CHANGE_NOT_COMPLEX;
2748 return ret;
2750 default:
2751 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2752 *werror = WERR_PASSWORD_RESTRICTION;
2753 ldb_asprintf_errstring(ldb,
2754 "%08X: %s - check_password_restrictions: "
2755 "the password doesn't fit due to a miscellaneous restriction!",
2756 W_ERROR_V(*werror),
2757 ldb_strerror(ret));
2758 return ret;
2762 if (io->ac->pwd_reset) {
2763 *werror = WERR_OK;
2764 return LDB_SUCCESS;
2767 if (io->n.nt_hash) {
2768 uint32_t i;
2770 /* checks the NT hash password history */
2771 for (i = 0; i < io->o.nt_history_len; i++) {
2772 ret = memcmp(io->n.nt_hash, io->o.nt_history[i].hash, 16);
2773 if (ret == 0) {
2774 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2775 *werror = WERR_PASSWORD_RESTRICTION;
2776 ldb_asprintf_errstring(ldb,
2777 "%08X: %s - check_password_restrictions: "
2778 "the password was already used (in history)!",
2779 W_ERROR_V(*werror),
2780 ldb_strerror(ret));
2781 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
2782 return ret;
2787 if (io->n.lm_hash) {
2788 uint32_t i;
2790 /* checks the LM hash password history */
2791 for (i = 0; i < io->o.lm_history_len; i++) {
2792 ret = memcmp(io->n.lm_hash, io->o.lm_history[i].hash, 16);
2793 if (ret == 0) {
2794 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2795 *werror = WERR_PASSWORD_RESTRICTION;
2796 ldb_asprintf_errstring(ldb,
2797 "%08X: %s - check_password_restrictions: "
2798 "the password was already used (in history)!",
2799 W_ERROR_V(*werror),
2800 ldb_strerror(ret));
2801 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
2802 return ret;
2807 /* are all password changes disallowed? */
2808 if (io->ac->status->domain_data.pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
2809 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2810 *werror = WERR_PASSWORD_RESTRICTION;
2811 ldb_asprintf_errstring(ldb,
2812 "%08X: %s - check_password_restrictions: "
2813 "password changes disabled!",
2814 W_ERROR_V(*werror),
2815 ldb_strerror(ret));
2816 return ret;
2819 /* can this user change the password? */
2820 if (io->u.userAccountControl & UF_PASSWD_CANT_CHANGE) {
2821 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2822 *werror = WERR_PASSWORD_RESTRICTION;
2823 ldb_asprintf_errstring(ldb,
2824 "%08X: %s - check_password_restrictions: "
2825 "password can't be changed on this account!",
2826 W_ERROR_V(*werror),
2827 ldb_strerror(ret));
2828 return ret;
2831 return LDB_SUCCESS;
2834 static int check_password_restrictions_and_log(struct setup_password_fields_io *io)
2836 WERROR werror;
2837 int ret = check_password_restrictions(io, &werror);
2838 struct ph_context *ac = io->ac;
2840 * Password resets are not authentication events, and if the
2841 * upper layer checked the password and supplied the hash
2842 * values as proof, then this is also not an authentication
2843 * even at this layer (already logged). This is to log LDAP
2844 * password changes.
2847 /* Do not record a failure in the auth log below in the success case */
2848 if (ret == LDB_SUCCESS) {
2849 werror = WERR_OK;
2852 if (ac->pwd_reset == false && ac->change == NULL) {
2853 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2854 struct imessaging_context *msg_ctx;
2855 struct loadparm_context *lp_ctx
2856 = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"),
2857 struct loadparm_context);
2858 NTSTATUS status = werror_to_ntstatus(werror);
2859 const char *domain_name = lpcfg_sam_name(lp_ctx);
2860 void *opaque_remote_address = NULL;
2862 * Forcing this via the NTLM auth structure is not ideal, but
2863 * it is the most practical option right now, and ensures the
2864 * logs are consistent, even if some elements are always NULL.
2866 struct auth_usersupplied_info ui = {
2867 .mapped_state = true,
2868 .was_mapped = true,
2869 .client = {
2870 .account_name = io->u.sAMAccountName,
2871 .domain_name = domain_name,
2873 .mapped = {
2874 .account_name = io->u.sAMAccountName,
2875 .domain_name = domain_name,
2877 .service_description = "LDAP Password Change",
2878 .auth_description = "LDAP Modify",
2879 .password_type = "plaintext"
2882 opaque_remote_address = ldb_get_opaque(ldb,
2883 "remoteAddress");
2884 if (opaque_remote_address == NULL) {
2885 ldb_asprintf_errstring(ldb,
2886 "Failed to obtain remote address for "
2887 "the LDAP client while changing the "
2888 "password");
2889 return LDB_ERR_OPERATIONS_ERROR;
2891 ui.remote_host = talloc_get_type(opaque_remote_address,
2892 struct tsocket_address);
2894 msg_ctx = imessaging_client_init(ac, lp_ctx,
2895 ldb_get_event_context(ldb));
2896 if (!msg_ctx) {
2897 ldb_asprintf_errstring(ldb,
2898 "Failed to generate client messaging context in %s",
2899 lpcfg_imessaging_path(ac, lp_ctx));
2900 return LDB_ERR_OPERATIONS_ERROR;
2902 log_authentication_event(msg_ctx,
2903 lp_ctx,
2904 NULL,
2905 &ui,
2906 status,
2907 domain_name,
2908 io->u.sAMAccountName,
2909 NULL,
2910 io->u.account_sid);
2913 return ret;
2916 static int update_final_msg(struct setup_password_fields_io *io)
2918 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2919 int ret;
2920 int el_flags = 0;
2921 bool update_password = io->ac->update_password;
2922 bool update_scb = io->ac->update_password;
2925 * If we add a user without initial password,
2926 * we need to add replication meta data for
2927 * following attributes:
2928 * - unicodePwd
2929 * - dBCSPwd
2930 * - ntPwdHistory
2931 * - lmPwdHistory
2933 * If we add a user with initial password or a
2934 * password is changed of an existing user,
2935 * we need to replace the following attributes
2936 * with a forced meta data update, e.g. also
2937 * when updating an empty attribute with an empty value:
2938 * - unicodePwd
2939 * - dBCSPwd
2940 * - ntPwdHistory
2941 * - lmPwdHistory
2942 * - supplementalCredentials
2945 switch (io->ac->req->operation) {
2946 case LDB_ADD:
2947 update_password = true;
2948 el_flags |= DSDB_FLAG_INTERNAL_FORCE_META_DATA;
2949 break;
2950 case LDB_MODIFY:
2951 el_flags |= LDB_FLAG_MOD_REPLACE;
2952 el_flags |= DSDB_FLAG_INTERNAL_FORCE_META_DATA;
2953 break;
2954 default:
2955 return ldb_module_operr(io->ac->module);
2958 if (update_password) {
2959 ret = ldb_msg_add_empty(io->ac->update_msg,
2960 "unicodePwd",
2961 el_flags, NULL);
2962 if (ret != LDB_SUCCESS) {
2963 return ret;
2965 ret = ldb_msg_add_empty(io->ac->update_msg,
2966 "dBCSPwd",
2967 el_flags, NULL);
2968 if (ret != LDB_SUCCESS) {
2969 return ret;
2971 ret = ldb_msg_add_empty(io->ac->update_msg,
2972 "ntPwdHistory",
2973 el_flags, NULL);
2974 if (ret != LDB_SUCCESS) {
2975 return ret;
2977 ret = ldb_msg_add_empty(io->ac->update_msg,
2978 "lmPwdHistory",
2979 el_flags, NULL);
2980 if (ret != LDB_SUCCESS) {
2981 return ret;
2984 if (update_scb) {
2985 ret = ldb_msg_add_empty(io->ac->update_msg,
2986 "supplementalCredentials",
2987 el_flags, NULL);
2988 if (ret != LDB_SUCCESS) {
2989 return ret;
2992 if (io->ac->update_lastset) {
2993 ret = ldb_msg_add_empty(io->ac->update_msg,
2994 "pwdLastSet",
2995 el_flags, NULL);
2996 if (ret != LDB_SUCCESS) {
2997 return ret;
3001 if (io->g.nt_hash != NULL) {
3002 ret = samdb_msg_add_hash(ldb, io->ac,
3003 io->ac->update_msg,
3004 "unicodePwd",
3005 io->g.nt_hash);
3006 if (ret != LDB_SUCCESS) {
3007 return ret;
3010 if (io->g.lm_hash != NULL) {
3011 ret = samdb_msg_add_hash(ldb, io->ac,
3012 io->ac->update_msg,
3013 "dBCSPwd",
3014 io->g.lm_hash);
3015 if (ret != LDB_SUCCESS) {
3016 return ret;
3019 if (io->g.nt_history_len > 0) {
3020 ret = samdb_msg_add_hashes(ldb, io->ac,
3021 io->ac->update_msg,
3022 "ntPwdHistory",
3023 io->g.nt_history,
3024 io->g.nt_history_len);
3025 if (ret != LDB_SUCCESS) {
3026 return ret;
3029 if (io->g.lm_history_len > 0) {
3030 ret = samdb_msg_add_hashes(ldb, io->ac,
3031 io->ac->update_msg,
3032 "lmPwdHistory",
3033 io->g.lm_history,
3034 io->g.lm_history_len);
3035 if (ret != LDB_SUCCESS) {
3036 return ret;
3039 if (io->g.supplemental.length > 0) {
3040 ret = ldb_msg_add_value(io->ac->update_msg,
3041 "supplementalCredentials",
3042 &io->g.supplemental, NULL);
3043 if (ret != LDB_SUCCESS) {
3044 return ret;
3047 if (io->ac->update_lastset) {
3048 ret = samdb_msg_add_uint64(ldb, io->ac,
3049 io->ac->update_msg,
3050 "pwdLastSet",
3051 io->g.last_set);
3052 if (ret != LDB_SUCCESS) {
3053 return ret;
3057 return LDB_SUCCESS;
3061 * This is intended for use by the "password_hash" module since there
3062 * password changes can be specified through one message element with the
3063 * new password (to set) and another one with the old password (to unset).
3065 * The first which sets a password (new value) can have flags
3066 * (LDB_FLAG_MOD_ADD, LDB_FLAG_MOD_REPLACE) but also none (on "add" operations
3067 * for entries). The latter (old value) has always specified
3068 * LDB_FLAG_MOD_DELETE.
3070 * Returns LDB_ERR_CONSTRAINT_VIOLATION and LDB_ERR_UNWILLING_TO_PERFORM if
3071 * matching message elements are malformed in respect to the set/change rules.
3072 * Otherwise it returns LDB_SUCCESS.
3074 static int msg_find_old_and_new_pwd_val(const struct ldb_message *msg,
3075 const char *name,
3076 enum ldb_request_type operation,
3077 const struct ldb_val **new_val,
3078 const struct ldb_val **old_val)
3080 unsigned int i;
3082 *new_val = NULL;
3083 *old_val = NULL;
3085 if (msg == NULL) {
3086 return LDB_SUCCESS;
3089 for (i = 0; i < msg->num_elements; i++) {
3090 if (ldb_attr_cmp(msg->elements[i].name, name) != 0) {
3091 continue;
3094 if ((operation == LDB_MODIFY) &&
3095 (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_DELETE)) {
3096 /* 0 values are allowed */
3097 if (msg->elements[i].num_values == 1) {
3098 *old_val = &msg->elements[i].values[0];
3099 } else if (msg->elements[i].num_values > 1) {
3100 return LDB_ERR_CONSTRAINT_VIOLATION;
3102 } else if ((operation == LDB_MODIFY) &&
3103 (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_REPLACE)) {
3104 if (msg->elements[i].num_values > 0) {
3105 *new_val = &msg->elements[i].values[msg->elements[i].num_values - 1];
3106 } else {
3107 return LDB_ERR_UNWILLING_TO_PERFORM;
3109 } else {
3110 /* Add operations and LDB_FLAG_MOD_ADD */
3111 if (msg->elements[i].num_values > 0) {
3112 *new_val = &msg->elements[i].values[msg->elements[i].num_values - 1];
3113 } else {
3114 return LDB_ERR_CONSTRAINT_VIOLATION;
3119 return LDB_SUCCESS;
3122 static int setup_io(struct ph_context *ac,
3123 const struct ldb_message *client_msg,
3124 const struct ldb_message *existing_msg,
3125 struct setup_password_fields_io *io)
3127 const struct ldb_val *quoted_utf16, *old_quoted_utf16, *lm_hash, *old_lm_hash;
3128 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3129 struct loadparm_context *lp_ctx = talloc_get_type(
3130 ldb_get_opaque(ldb, "loadparm"), struct loadparm_context);
3131 int ret;
3132 const struct ldb_message *info_msg = NULL;
3133 struct dom_sid *account_sid = NULL;
3134 int rodc_krbtgt = 0;
3136 ZERO_STRUCTP(io);
3138 /* Some operations below require kerberos contexts */
3140 if (existing_msg != NULL) {
3142 * This is a modify operation
3144 info_msg = existing_msg;
3145 } else {
3147 * This is an add operation
3149 info_msg = client_msg;
3152 ret = smb_krb5_init_context(ac,
3153 (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"),
3154 &io->smb_krb5_context);
3156 if (ret != 0) {
3158 * In the special case of mit krb5.conf vs heimdal, the includedir
3159 * statement causes ret == 22 (KRB5_CONFIG_BADFORMAT) to be returned.
3160 * We look for this case so that we can give a more instructional
3161 * message to the administrator.
3163 if (ret == KRB5_CONFIG_BADFORMAT || ret == EINVAL) {
3164 ldb_asprintf_errstring(ldb, "Failed to setup krb5_context: %s - "
3165 "This could be due to an invalid krb5 configuration. "
3166 "Please check your system's krb5 configuration is correct.",
3167 error_message(ret));
3168 } else {
3169 ldb_asprintf_errstring(ldb, "Failed to setup krb5_context: %s",
3170 error_message(ret));
3172 return LDB_ERR_OPERATIONS_ERROR;
3175 io->ac = ac;
3177 io->u.userAccountControl = ldb_msg_find_attr_as_uint(info_msg,
3178 "userAccountControl", 0);
3179 if (info_msg == existing_msg) {
3181 * We only take pwdLastSet from the existing object
3182 * otherwise we leave it as 0.
3184 * If no attribute is available, e.g. on deleted objects
3185 * we remember that as UINT64_MAX.
3187 io->u.pwdLastSet = samdb_result_nttime(info_msg, "pwdLastSet",
3188 UINT64_MAX);
3190 io->u.sAMAccountName = ldb_msg_find_attr_as_string(info_msg,
3191 "sAMAccountName", NULL);
3192 io->u.user_principal_name = ldb_msg_find_attr_as_string(info_msg,
3193 "userPrincipalName", NULL);
3195 /* Ensure it has an objectSID too */
3196 io->u.account_sid = samdb_result_dom_sid(ac, info_msg, "objectSid");
3197 if (io->u.account_sid != NULL) {
3198 NTSTATUS status;
3199 uint32_t rid = 0;
3201 status = dom_sid_split_rid(account_sid, io->u.account_sid, NULL, &rid);
3202 if (NT_STATUS_IS_OK(status)) {
3203 if (rid == DOMAIN_RID_KRBTGT) {
3204 io->u.is_krbtgt = true;
3209 rodc_krbtgt = ldb_msg_find_attr_as_int(info_msg,
3210 "msDS-SecondaryKrbTgtNumber", 0);
3211 if (rodc_krbtgt != 0) {
3212 io->u.is_krbtgt = true;
3215 if (io->u.sAMAccountName == NULL) {
3216 ldb_asprintf_errstring(ldb,
3217 "setup_io: sAMAccountName attribute is missing on %s for attempted password set/change",
3218 ldb_dn_get_linearized(info_msg->dn));
3220 return LDB_ERR_CONSTRAINT_VIOLATION;
3223 if (io->u.userAccountControl & UF_INTERDOMAIN_TRUST_ACCOUNT) {
3224 struct ldb_control *permit_trust = ldb_request_get_control(ac->req,
3225 DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID);
3227 if (permit_trust == NULL) {
3228 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
3229 ldb_asprintf_errstring(ldb,
3230 "%08X: %s - setup_io: changing the interdomain trust password "
3231 "on %s not allowed via LDAP. Use LSA or NETLOGON",
3232 W_ERROR_V(WERR_ACCESS_DENIED),
3233 ldb_strerror(ret),
3234 ldb_dn_get_linearized(info_msg->dn));
3235 return ret;
3239 /* Only non-trust accounts have restrictions (possibly this test is the
3240 * wrong way around, but we like to be restrictive if possible */
3241 io->u.restrictions = !(io->u.userAccountControl & UF_TRUST_ACCOUNT_MASK);
3243 if (io->u.is_krbtgt) {
3244 io->u.restrictions = 0;
3245 io->ac->status->domain_data.pwdHistoryLength =
3246 MAX(io->ac->status->domain_data.pwdHistoryLength, 3);
3249 if (ac->userPassword) {
3250 ret = msg_find_old_and_new_pwd_val(client_msg, "userPassword",
3251 ac->req->operation,
3252 &io->n.cleartext_utf8,
3253 &io->og.cleartext_utf8);
3254 if (ret != LDB_SUCCESS) {
3255 ldb_asprintf_errstring(ldb,
3256 "setup_io: "
3257 "it's only allowed to set the old password once!");
3258 return ret;
3262 if (io->n.cleartext_utf8 != NULL) {
3263 struct ldb_val *cleartext_utf8_blob;
3264 char *p;
3266 cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
3267 if (!cleartext_utf8_blob) {
3268 return ldb_oom(ldb);
3271 *cleartext_utf8_blob = *io->n.cleartext_utf8;
3273 /* make sure we have a null terminated string */
3274 p = talloc_strndup(cleartext_utf8_blob,
3275 (const char *)io->n.cleartext_utf8->data,
3276 io->n.cleartext_utf8->length);
3277 if ((p == NULL) && (io->n.cleartext_utf8->length > 0)) {
3278 return ldb_oom(ldb);
3280 cleartext_utf8_blob->data = (uint8_t *)p;
3282 io->n.cleartext_utf8 = cleartext_utf8_blob;
3285 ret = msg_find_old_and_new_pwd_val(client_msg, "clearTextPassword",
3286 ac->req->operation,
3287 &io->n.cleartext_utf16,
3288 &io->og.cleartext_utf16);
3289 if (ret != LDB_SUCCESS) {
3290 ldb_asprintf_errstring(ldb,
3291 "setup_io: "
3292 "it's only allowed to set the old password once!");
3293 return ret;
3296 /* this rather strange looking piece of code is there to
3297 handle a ldap client setting a password remotely using the
3298 unicodePwd ldap field. The syntax is that the password is
3299 in UTF-16LE, with a " at either end. Unfortunately the
3300 unicodePwd field is also used to store the nt hashes
3301 internally in Samba, and is used in the nt hash format on
3302 the wire in DRS replication, so we have a single name for
3303 two distinct values. The code below leaves us with a small
3304 chance (less than 1 in 2^32) of a mixup, if someone manages
3305 to create a MD4 hash which starts and ends in 0x22 0x00, as
3306 that would then be treated as a UTF16 password rather than
3307 a nthash */
3309 ret = msg_find_old_and_new_pwd_val(client_msg, "unicodePwd",
3310 ac->req->operation,
3311 &quoted_utf16,
3312 &old_quoted_utf16);
3313 if (ret != LDB_SUCCESS) {
3314 ldb_asprintf_errstring(ldb,
3315 "setup_io: "
3316 "it's only allowed to set the old password once!");
3317 return ret;
3320 /* Checks and converts the actual "unicodePwd" attribute */
3321 if (!ac->hash_values &&
3322 quoted_utf16 &&
3323 quoted_utf16->length >= 4 &&
3324 quoted_utf16->data[0] == '"' &&
3325 quoted_utf16->data[1] == 0 &&
3326 quoted_utf16->data[quoted_utf16->length-2] == '"' &&
3327 quoted_utf16->data[quoted_utf16->length-1] == 0) {
3328 struct ldb_val *quoted_utf16_2;
3330 if (io->n.cleartext_utf16) {
3331 /* refuse the change if someone wants to change with
3332 with both UTF16 possibilities at the same time... */
3333 ldb_asprintf_errstring(ldb,
3334 "setup_io: "
3335 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
3336 return LDB_ERR_UNWILLING_TO_PERFORM;
3340 * adapt the quoted UTF16 string to be a real
3341 * cleartext one
3343 quoted_utf16_2 = talloc(io->ac, struct ldb_val);
3344 if (quoted_utf16_2 == NULL) {
3345 return ldb_oom(ldb);
3348 quoted_utf16_2->data = quoted_utf16->data + 2;
3349 quoted_utf16_2->length = quoted_utf16->length-4;
3350 io->n.cleartext_utf16 = quoted_utf16_2;
3351 io->n.nt_hash = NULL;
3353 } else if (quoted_utf16) {
3354 /* We have only the hash available -> so no plaintext here */
3355 if (!ac->hash_values) {
3356 /* refuse the change if someone wants to change
3357 the hash without control specified... */
3358 ldb_asprintf_errstring(ldb,
3359 "setup_io: "
3360 "it's not allowed to set the NT hash password directly'");
3361 /* this looks odd but this is what Windows does:
3362 returns "UNWILLING_TO_PERFORM" on wrong
3363 password sets and "CONSTRAINT_VIOLATION" on
3364 wrong password changes. */
3365 if (old_quoted_utf16 == NULL) {
3366 return LDB_ERR_UNWILLING_TO_PERFORM;
3369 return LDB_ERR_CONSTRAINT_VIOLATION;
3372 io->n.nt_hash = talloc(io->ac, struct samr_Password);
3373 memcpy(io->n.nt_hash->hash, quoted_utf16->data,
3374 MIN(quoted_utf16->length, sizeof(io->n.nt_hash->hash)));
3377 /* Checks and converts the previous "unicodePwd" attribute */
3378 if (!ac->hash_values &&
3379 old_quoted_utf16 &&
3380 old_quoted_utf16->length >= 4 &&
3381 old_quoted_utf16->data[0] == '"' &&
3382 old_quoted_utf16->data[1] == 0 &&
3383 old_quoted_utf16->data[old_quoted_utf16->length-2] == '"' &&
3384 old_quoted_utf16->data[old_quoted_utf16->length-1] == 0) {
3385 struct ldb_val *old_quoted_utf16_2;
3387 if (io->og.cleartext_utf16) {
3388 /* refuse the change if someone wants to change with
3389 both UTF16 possibilities at the same time... */
3390 ldb_asprintf_errstring(ldb,
3391 "setup_io: "
3392 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
3393 return LDB_ERR_UNWILLING_TO_PERFORM;
3397 * adapt the quoted UTF16 string to be a real
3398 * cleartext one
3400 old_quoted_utf16_2 = talloc(io->ac, struct ldb_val);
3401 if (old_quoted_utf16_2 == NULL) {
3402 return ldb_oom(ldb);
3405 old_quoted_utf16_2->data = old_quoted_utf16->data + 2;
3406 old_quoted_utf16_2->length = old_quoted_utf16->length-4;
3408 io->og.cleartext_utf16 = old_quoted_utf16_2;
3409 io->og.nt_hash = NULL;
3410 } else if (old_quoted_utf16) {
3411 /* We have only the hash available -> so no plaintext here */
3412 if (!ac->hash_values) {
3413 /* refuse the change if someone wants to change
3414 the hash without control specified... */
3415 ldb_asprintf_errstring(ldb,
3416 "setup_io: "
3417 "it's not allowed to set the NT hash password directly'");
3418 return LDB_ERR_UNWILLING_TO_PERFORM;
3421 io->og.nt_hash = talloc(io->ac, struct samr_Password);
3422 memcpy(io->og.nt_hash->hash, old_quoted_utf16->data,
3423 MIN(old_quoted_utf16->length, sizeof(io->og.nt_hash->hash)));
3426 /* Handles the "dBCSPwd" attribute (LM hash) */
3427 io->n.lm_hash = NULL; io->og.lm_hash = NULL;
3428 ret = msg_find_old_and_new_pwd_val(client_msg, "dBCSPwd",
3429 ac->req->operation,
3430 &lm_hash, &old_lm_hash);
3431 if (ret != LDB_SUCCESS) {
3432 ldb_asprintf_errstring(ldb,
3433 "setup_io: "
3434 "it's only allowed to set the old password once!");
3435 return ret;
3438 if (((lm_hash != NULL) || (old_lm_hash != NULL)) && (!ac->hash_values)) {
3439 /* refuse the change if someone wants to change the hash
3440 without control specified... */
3441 ldb_asprintf_errstring(ldb,
3442 "setup_io: "
3443 "it's not allowed to set the LM hash password directly'");
3444 return LDB_ERR_UNWILLING_TO_PERFORM;
3447 if (lpcfg_lanman_auth(lp_ctx) && (lm_hash != NULL)) {
3448 io->n.lm_hash = talloc(io->ac, struct samr_Password);
3449 memcpy(io->n.lm_hash->hash, lm_hash->data, MIN(lm_hash->length,
3450 sizeof(io->n.lm_hash->hash)));
3452 if (lpcfg_lanman_auth(lp_ctx) && (old_lm_hash != NULL)) {
3453 io->og.lm_hash = talloc(io->ac, struct samr_Password);
3454 memcpy(io->og.lm_hash->hash, old_lm_hash->data, MIN(old_lm_hash->length,
3455 sizeof(io->og.lm_hash->hash)));
3459 * Handles the password change control if it's specified. It has the
3460 * precedance and overrides already specified old password values of
3461 * change requests (but that shouldn't happen since the control is
3462 * fully internal and only used in conjunction with replace requests!).
3464 if (ac->change != NULL) {
3465 io->og.nt_hash = NULL;
3466 if (ac->change->old_nt_pwd_hash != NULL) {
3467 io->og.nt_hash = talloc_memdup(io->ac,
3468 ac->change->old_nt_pwd_hash,
3469 sizeof(struct samr_Password));
3471 io->og.lm_hash = NULL;
3472 if (lpcfg_lanman_auth(lp_ctx) && (ac->change->old_lm_pwd_hash != NULL)) {
3473 io->og.lm_hash = talloc_memdup(io->ac,
3474 ac->change->old_lm_pwd_hash,
3475 sizeof(struct samr_Password));
3479 /* refuse the change if someone wants to change the clear-
3480 text and supply his own hashes at the same time... */
3481 if ((io->n.cleartext_utf8 || io->n.cleartext_utf16)
3482 && (io->n.nt_hash || io->n.lm_hash)) {
3483 ldb_asprintf_errstring(ldb,
3484 "setup_io: "
3485 "it's only allowed to set the password in form of cleartext attributes or as hashes");
3486 return LDB_ERR_UNWILLING_TO_PERFORM;
3489 /* refuse the change if someone wants to change the password
3490 using both plaintext methods (UTF8 and UTF16) at the same time... */
3491 if (io->n.cleartext_utf8 && io->n.cleartext_utf16) {
3492 ldb_asprintf_errstring(ldb,
3493 "setup_io: "
3494 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
3495 return LDB_ERR_UNWILLING_TO_PERFORM;
3498 /* refuse the change if someone tries to set/change the password by
3499 * the lanman hash alone and we've deactivated that mechanism. This
3500 * would end in an account without any password! */
3501 if (io->ac->update_password
3502 && (!io->n.cleartext_utf8) && (!io->n.cleartext_utf16)
3503 && (!io->n.nt_hash) && (!io->n.lm_hash)) {
3504 ldb_asprintf_errstring(ldb,
3505 "setup_io: "
3506 "It's not possible to delete the password (changes using the LAN Manager hash alone could be deactivated)!");
3507 /* on "userPassword" and "clearTextPassword" we've to return
3508 * something different, since these are virtual attributes */
3509 if ((ldb_msg_find_element(client_msg, "userPassword") != NULL) ||
3510 (ldb_msg_find_element(client_msg, "clearTextPassword") != NULL)) {
3511 return LDB_ERR_CONSTRAINT_VIOLATION;
3513 return LDB_ERR_UNWILLING_TO_PERFORM;
3516 /* refuse the change if someone wants to compare against a plaintext
3517 or hash at the same time for a "password modify" operation... */
3518 if ((io->og.cleartext_utf8 || io->og.cleartext_utf16)
3519 && (io->og.nt_hash || io->og.lm_hash)) {
3520 ldb_asprintf_errstring(ldb,
3521 "setup_io: "
3522 "it's only allowed to provide the old password in form of cleartext attributes or as hashes");
3523 return LDB_ERR_UNWILLING_TO_PERFORM;
3526 /* refuse the change if someone wants to compare against both
3527 * plaintexts at the same time for a "password modify" operation... */
3528 if (io->og.cleartext_utf8 && io->og.cleartext_utf16) {
3529 ldb_asprintf_errstring(ldb,
3530 "setup_io: "
3531 "it's only allowed to provide the old cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
3532 return LDB_ERR_UNWILLING_TO_PERFORM;
3535 /* Decides if we have a password modify or password reset operation */
3536 if (ac->req->operation == LDB_ADD) {
3537 /* On "add" we have only "password reset" */
3538 ac->pwd_reset = true;
3539 } else if (ac->req->operation == LDB_MODIFY) {
3540 struct ldb_control *pav_ctrl = NULL;
3541 struct dsdb_control_password_acl_validation *pav = NULL;
3543 pav_ctrl = ldb_request_get_control(ac->req,
3544 DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
3545 if (pav_ctrl != NULL) {
3546 pav = talloc_get_type_abort(pav_ctrl->data,
3547 struct dsdb_control_password_acl_validation);
3550 if (pav == NULL && ac->update_password) {
3551 bool ok;
3554 * If the DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID
3555 * control is missing, we require system access!
3557 ok = dsdb_module_am_system(ac->module);
3558 if (!ok) {
3559 return ldb_module_operr(ac->module);
3563 if (pav != NULL) {
3565 * We assume what the acl module has validated.
3567 ac->pwd_reset = pav->pwd_reset;
3568 } else if (io->og.cleartext_utf8 || io->og.cleartext_utf16
3569 || io->og.nt_hash || io->og.lm_hash) {
3570 /* If we have an old password specified then for sure it
3571 * is a user "password change" */
3572 ac->pwd_reset = false;
3573 } else {
3574 /* Otherwise we have also here a "password reset" */
3575 ac->pwd_reset = true;
3577 } else {
3578 /* this shouldn't happen */
3579 return ldb_operr(ldb);
3582 if (io->u.is_krbtgt) {
3583 size_t min = 196;
3584 size_t max = 255;
3585 size_t diff = max - min;
3586 size_t len = max;
3587 struct ldb_val *krbtgt_utf16 = NULL;
3589 if (!ac->pwd_reset) {
3590 return dsdb_module_werror(ac->module,
3591 LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS,
3592 WERR_DS_ATT_ALREADY_EXISTS,
3593 "Password change on krbtgt not permitted!");
3596 if (io->n.cleartext_utf16 == NULL) {
3597 return dsdb_module_werror(ac->module,
3598 LDB_ERR_UNWILLING_TO_PERFORM,
3599 WERR_DS_INVALID_ATTRIBUTE_SYNTAX,
3600 "Password reset on krbtgt requires UTF16!");
3604 * Instead of taking the callers value,
3605 * we just generate a new random value here.
3607 * Include null termination in the array.
3609 if (diff > 0) {
3610 size_t tmp;
3612 generate_random_buffer((uint8_t *)&tmp, sizeof(tmp));
3614 tmp %= diff;
3616 len = min + tmp;
3619 krbtgt_utf16 = talloc_zero(io->ac, struct ldb_val);
3620 if (krbtgt_utf16 == NULL) {
3621 return ldb_oom(ldb);
3624 *krbtgt_utf16 = data_blob_talloc_zero(krbtgt_utf16,
3625 (len+1)*2);
3626 if (krbtgt_utf16->data == NULL) {
3627 return ldb_oom(ldb);
3629 krbtgt_utf16->length = len * 2;
3630 generate_secret_buffer(krbtgt_utf16->data,
3631 krbtgt_utf16->length);
3632 io->n.cleartext_utf16 = krbtgt_utf16;
3635 if (existing_msg != NULL) {
3636 NTSTATUS status;
3638 if (ac->pwd_reset) {
3639 /* Get the old password from the database */
3640 status = samdb_result_passwords_no_lockout(ac,
3641 lp_ctx,
3642 existing_msg,
3643 &io->o.lm_hash,
3644 &io->o.nt_hash);
3645 } else {
3646 /* Get the old password from the database */
3647 status = samdb_result_passwords(ac,
3648 lp_ctx,
3649 existing_msg,
3650 &io->o.lm_hash,
3651 &io->o.nt_hash);
3654 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCOUNT_LOCKED_OUT)) {
3655 return dsdb_module_werror(ac->module,
3656 LDB_ERR_CONSTRAINT_VIOLATION,
3657 WERR_ACCOUNT_LOCKED_OUT,
3658 "Password change not permitted,"
3659 " account locked out!");
3662 if (!NT_STATUS_IS_OK(status)) {
3664 * This only happens if the database has gone weird,
3665 * not if we are just missing the passwords
3667 return ldb_operr(ldb);
3670 io->o.nt_history_len = samdb_result_hashes(ac, existing_msg,
3671 "ntPwdHistory",
3672 &io->o.nt_history);
3673 io->o.lm_history_len = samdb_result_hashes(ac, existing_msg,
3674 "lmPwdHistory",
3675 &io->o.lm_history);
3676 io->o.supplemental = ldb_msg_find_ldb_val(existing_msg,
3677 "supplementalCredentials");
3679 if (io->o.supplemental != NULL) {
3680 enum ndr_err_code ndr_err;
3682 ndr_err = ndr_pull_struct_blob_all(io->o.supplemental, io->ac,
3683 &io->o.scb,
3684 (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
3685 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3686 status = ndr_map_error2ntstatus(ndr_err);
3687 ldb_asprintf_errstring(ldb,
3688 "setup_io: failed to pull "
3689 "old supplementalCredentialsBlob: %s",
3690 nt_errstr(status));
3691 return LDB_ERR_OPERATIONS_ERROR;
3696 return LDB_SUCCESS;
3699 static struct ph_context *ph_init_context(struct ldb_module *module,
3700 struct ldb_request *req,
3701 bool userPassword,
3702 bool update_password)
3704 struct ldb_context *ldb;
3705 struct ph_context *ac;
3706 struct loadparm_context *lp_ctx = NULL;
3708 ldb = ldb_module_get_ctx(module);
3710 ac = talloc_zero(req, struct ph_context);
3711 if (ac == NULL) {
3712 ldb_set_errstring(ldb, "Out of Memory");
3713 return NULL;
3716 ac->module = module;
3717 ac->req = req;
3718 ac->userPassword = userPassword;
3719 ac->update_password = update_password;
3720 ac->update_lastset = true;
3722 lp_ctx = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"),
3723 struct loadparm_context);
3724 ac->gpg_key_ids = lpcfg_password_hash_gpg_key_ids(lp_ctx);
3725 ac->userPassword_schemes
3726 = lpcfg_password_hash_userpassword_schemes(lp_ctx);
3727 return ac;
3730 static void ph_apply_controls(struct ph_context *ac)
3732 struct ldb_control *ctrl;
3734 ac->change_status = false;
3735 ctrl = ldb_request_get_control(ac->req,
3736 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID);
3737 if (ctrl != NULL) {
3738 ac->change_status = true;
3740 /* Mark the "change status" control as uncritical (done) */
3741 ctrl->critical = false;
3744 ac->hash_values = false;
3745 ctrl = ldb_request_get_control(ac->req,
3746 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID);
3747 if (ctrl != NULL) {
3748 ac->hash_values = true;
3750 /* Mark the "hash values" control as uncritical (done) */
3751 ctrl->critical = false;
3754 ctrl = ldb_request_get_control(ac->req,
3755 DSDB_CONTROL_PASSWORD_CHANGE_OID);
3756 if (ctrl != NULL) {
3757 ac->change = (struct dsdb_control_password_change *) ctrl->data;
3759 /* Mark the "change" control as uncritical (done) */
3760 ctrl->critical = false;
3763 ac->pwd_last_set_bypass = false;
3764 ctrl = ldb_request_get_control(ac->req,
3765 DSDB_CONTROL_PASSWORD_BYPASS_LAST_SET_OID);
3766 if (ctrl != NULL) {
3767 ac->pwd_last_set_bypass = true;
3769 /* Mark the "bypass pwdLastSet" control as uncritical (done) */
3770 ctrl->critical = false;
3773 ac->pwd_last_set_default = false;
3774 ctrl = ldb_request_get_control(ac->req,
3775 DSDB_CONTROL_PASSWORD_DEFAULT_LAST_SET_OID);
3776 if (ctrl != NULL) {
3777 ac->pwd_last_set_default = true;
3779 /* Mark the "bypass pwdLastSet" control as uncritical (done) */
3780 ctrl->critical = false;
3783 ac->smartcard_reset = false;
3784 ctrl = ldb_request_get_control(ac->req,
3785 DSDB_CONTROL_PASSWORD_USER_ACCOUNT_CONTROL_OID);
3786 if (ctrl != NULL) {
3787 struct dsdb_control_password_user_account_control *uac = NULL;
3788 uint32_t added_flags = 0;
3790 uac = talloc_get_type_abort(ctrl->data,
3791 struct dsdb_control_password_user_account_control);
3793 added_flags = uac->new_flags & ~uac->old_flags;
3795 if (added_flags & UF_SMARTCARD_REQUIRED) {
3796 ac->smartcard_reset = true;
3799 /* Mark the "smartcard required" control as uncritical (done) */
3800 ctrl->critical = false;
3804 static int ph_op_callback(struct ldb_request *req, struct ldb_reply *ares)
3806 struct ph_context *ac;
3808 ac = talloc_get_type(req->context, struct ph_context);
3810 if (!ares) {
3811 return ldb_module_done(ac->req, NULL, NULL,
3812 LDB_ERR_OPERATIONS_ERROR);
3815 if (ares->type == LDB_REPLY_REFERRAL) {
3816 return ldb_module_send_referral(ac->req, ares->referral);
3819 if ((ares->error != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
3820 /* On success and trivial errors a status control is being
3821 * added (used for example by the "samdb_set_password" call) */
3822 ldb_reply_add_control(ares,
3823 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
3824 false,
3825 ac->status);
3828 if (ares->error != LDB_SUCCESS) {
3829 return ldb_module_done(ac->req, ares->controls,
3830 ares->response, ares->error);
3833 if (ares->type != LDB_REPLY_DONE) {
3834 talloc_free(ares);
3835 return ldb_module_done(ac->req, NULL, NULL,
3836 LDB_ERR_OPERATIONS_ERROR);
3839 return ldb_module_done(ac->req, ares->controls,
3840 ares->response, ares->error);
3843 static int password_hash_add_do_add(struct ph_context *ac);
3844 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares);
3845 static int password_hash_mod_search_self(struct ph_context *ac);
3846 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares);
3847 static int password_hash_mod_do_mod(struct ph_context *ac);
3850 * LDB callback handler for searching for a user's PSO. Once we have all the
3851 * Password Settings that apply to the user, we can continue with the modify
3852 * operation
3854 static int get_pso_data_callback(struct ldb_request *req,
3855 struct ldb_reply *ares)
3857 struct ldb_context *ldb = NULL;
3858 struct ph_context *ac = NULL;
3859 bool domain_complexity = true;
3860 bool pso_complexity = true;
3861 struct dsdb_user_pwd_settings *settings = NULL;
3862 int ret = LDB_SUCCESS;
3864 ac = talloc_get_type(req->context, struct ph_context);
3865 ldb = ldb_module_get_ctx(ac->module);
3867 if (!ares) {
3868 ret = LDB_ERR_OPERATIONS_ERROR;
3869 goto done;
3871 if (ares->error != LDB_SUCCESS) {
3872 return ldb_module_done(ac->req, ares->controls,
3873 ares->response, ares->error);
3876 switch (ares->type) {
3877 case LDB_REPLY_ENTRY:
3879 /* check status was initialized by the domain query */
3880 if (ac->status == NULL) {
3881 talloc_free(ares);
3882 ldb_set_errstring(ldb, "Uninitialized status");
3883 ret = LDB_ERR_OPERATIONS_ERROR;
3884 goto done;
3888 * use the PSO's values instead of the domain defaults (the PSO
3889 * attributes should always exist, but use the domain default
3890 * values as a fallback).
3892 settings = &ac->status->domain_data;
3893 settings->store_cleartext =
3894 ldb_msg_find_attr_as_bool(ares->message,
3895 "msDS-PasswordReversibleEncryptionEnabled",
3896 settings->store_cleartext);
3898 settings->pwdHistoryLength =
3899 ldb_msg_find_attr_as_uint(ares->message,
3900 "msDS-PasswordHistoryLength",
3901 settings->pwdHistoryLength);
3902 settings->maxPwdAge =
3903 ldb_msg_find_attr_as_int64(ares->message,
3904 "msDS-MaximumPasswordAge",
3905 settings->maxPwdAge);
3906 settings->minPwdAge =
3907 ldb_msg_find_attr_as_int64(ares->message,
3908 "msDS-MinimumPasswordAge",
3909 settings->minPwdAge);
3910 settings->minPwdLength =
3911 ldb_msg_find_attr_as_uint(ares->message,
3912 "msDS-MinimumPasswordLength",
3913 settings->minPwdLength);
3914 domain_complexity =
3915 (settings->pwdProperties & DOMAIN_PASSWORD_COMPLEX);
3916 pso_complexity =
3917 ldb_msg_find_attr_as_bool(ares->message,
3918 "msDS-PasswordComplexityEnabled",
3919 domain_complexity);
3921 /* set or clear the complexity bit if required */
3922 if (pso_complexity && !domain_complexity) {
3923 settings->pwdProperties |= DOMAIN_PASSWORD_COMPLEX;
3924 } else if (domain_complexity && !pso_complexity) {
3925 settings->pwdProperties &= ~DOMAIN_PASSWORD_COMPLEX;
3928 if (ac->pso_res != NULL) {
3929 DBG_ERR("Too many PSO results for %s",
3930 ldb_dn_get_linearized(ac->search_res->message->dn));
3931 talloc_free(ac->pso_res);
3934 /* store the PSO result (we may need its lockout settings) */
3935 ac->pso_res = talloc_steal(ac, ares);
3936 ret = LDB_SUCCESS;
3937 break;
3939 case LDB_REPLY_REFERRAL:
3940 /* ignore */
3941 talloc_free(ares);
3942 ret = LDB_SUCCESS;
3943 break;
3945 case LDB_REPLY_DONE:
3946 talloc_free(ares);
3949 * perform the next step of the modify operation (this code
3950 * shouldn't get called in the 'user add' case)
3952 if (ac->req->operation == LDB_MODIFY) {
3953 ret = password_hash_mod_do_mod(ac);
3954 } else {
3955 ret = LDB_ERR_OPERATIONS_ERROR;
3957 break;
3960 done:
3961 if (ret != LDB_SUCCESS) {
3962 struct ldb_reply *new_ares;
3964 new_ares = talloc_zero(ac->req, struct ldb_reply);
3965 if (new_ares == NULL) {
3966 ldb_oom(ldb);
3967 return ldb_module_done(ac->req, NULL, NULL,
3968 LDB_ERR_OPERATIONS_ERROR);
3971 new_ares->error = ret;
3972 if ((ret != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
3973 /* On success and trivial errors a status control is being
3974 * added (used for example by the "samdb_set_password" call) */
3975 ldb_reply_add_control(new_ares,
3976 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
3977 false,
3978 ac->status);
3981 return ldb_module_done(ac->req, new_ares->controls,
3982 new_ares->response, new_ares->error);
3985 return LDB_SUCCESS;
3989 * Builds and returns a search request to lookup up the PSO that applies to
3990 * the user in question. Returns NULL if no PSO applies, or could not be found
3992 static struct ldb_request * build_pso_data_request(struct ph_context *ac)
3994 /* attrs[] is returned from this function in
3995 pso_req->op.search.attrs, so it must be static, as
3996 otherwise the compiler can put it on the stack */
3997 static const char * const attrs[] = { "msDS-PasswordComplexityEnabled",
3998 "msDS-PasswordReversibleEncryptionEnabled",
3999 "msDS-PasswordHistoryLength",
4000 "msDS-MaximumPasswordAge",
4001 "msDS-MinimumPasswordAge",
4002 "msDS-MinimumPasswordLength",
4003 "msDS-LockoutThreshold",
4004 "msDS-LockoutObservationWindow",
4005 NULL };
4006 struct ldb_context *ldb = NULL;
4007 struct ldb_request *pso_req = NULL;
4008 struct ldb_dn *pso_dn = NULL;
4009 TALLOC_CTX *mem_ctx = ac;
4010 int ret;
4012 ldb = ldb_module_get_ctx(ac->module);
4014 /* if a PSO applies to the user, we need to lookup the PSO as well */
4015 pso_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, ac->search_res->message,
4016 "msDS-ResultantPSO");
4017 if (pso_dn == NULL) {
4018 return NULL;
4021 ret = ldb_build_search_req(&pso_req, ldb, mem_ctx, pso_dn,
4022 LDB_SCOPE_BASE, NULL, attrs, NULL,
4023 ac, get_pso_data_callback,
4024 ac->dom_req);
4026 /* log errors, but continue with the default domain settings */
4027 if (ret != LDB_SUCCESS) {
4028 DBG_ERR("Error %d constructing PSO query for user %s", ret,
4029 ldb_dn_get_linearized(ac->search_res->message->dn));
4031 LDB_REQ_SET_LOCATION(pso_req);
4032 return pso_req;
4036 static int get_domain_data_callback(struct ldb_request *req,
4037 struct ldb_reply *ares)
4039 struct ldb_context *ldb;
4040 struct ph_context *ac;
4041 struct loadparm_context *lp_ctx;
4042 struct ldb_request *pso_req = NULL;
4043 int ret = LDB_SUCCESS;
4045 ac = talloc_get_type(req->context, struct ph_context);
4046 ldb = ldb_module_get_ctx(ac->module);
4048 if (!ares) {
4049 ret = LDB_ERR_OPERATIONS_ERROR;
4050 goto done;
4052 if (ares->error != LDB_SUCCESS) {
4053 return ldb_module_done(ac->req, ares->controls,
4054 ares->response, ares->error);
4057 switch (ares->type) {
4058 case LDB_REPLY_ENTRY:
4059 if (ac->status != NULL) {
4060 talloc_free(ares);
4062 ldb_set_errstring(ldb, "Too many results");
4063 ret = LDB_ERR_OPERATIONS_ERROR;
4064 goto done;
4067 /* Setup the "status" structure (used as control later) */
4068 ac->status = talloc_zero(ac->req,
4069 struct dsdb_control_password_change_status);
4070 if (ac->status == NULL) {
4071 talloc_free(ares);
4073 ldb_oom(ldb);
4074 ret = LDB_ERR_OPERATIONS_ERROR;
4075 goto done;
4078 /* Setup the "domain data" structure */
4079 ac->status->domain_data.pwdProperties =
4080 ldb_msg_find_attr_as_uint(ares->message, "pwdProperties", -1);
4081 ac->status->domain_data.pwdHistoryLength =
4082 ldb_msg_find_attr_as_uint(ares->message, "pwdHistoryLength", -1);
4083 ac->status->domain_data.maxPwdAge =
4084 ldb_msg_find_attr_as_int64(ares->message, "maxPwdAge", -1);
4085 ac->status->domain_data.minPwdAge =
4086 ldb_msg_find_attr_as_int64(ares->message, "minPwdAge", -1);
4087 ac->status->domain_data.minPwdLength =
4088 ldb_msg_find_attr_as_uint(ares->message, "minPwdLength", -1);
4089 ac->status->domain_data.store_cleartext =
4090 ac->status->domain_data.pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
4092 /* For a domain DN, this puts things in dotted notation */
4093 /* For builtin domains, this will give details for the host,
4094 * but that doesn't really matter, as it's just used for salt
4095 * and kerberos principals, which don't exist here */
4097 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
4098 struct loadparm_context);
4100 ac->status->domain_data.dns_domain = lpcfg_dnsdomain(lp_ctx);
4101 ac->status->domain_data.realm = lpcfg_realm(lp_ctx);
4102 ac->status->domain_data.netbios_domain = lpcfg_sam_name(lp_ctx);
4104 ac->status->reject_reason = SAM_PWD_CHANGE_NO_ERROR;
4106 if (ac->dom_res != NULL) {
4107 talloc_free(ares);
4109 ldb_set_errstring(ldb, "Too many results");
4110 ret = LDB_ERR_OPERATIONS_ERROR;
4111 goto done;
4114 ac->dom_res = talloc_steal(ac, ares);
4115 ret = LDB_SUCCESS;
4116 break;
4118 case LDB_REPLY_REFERRAL:
4119 /* ignore */
4120 talloc_free(ares);
4121 ret = LDB_SUCCESS;
4122 break;
4124 case LDB_REPLY_DONE:
4125 talloc_free(ares);
4126 /* call the next step */
4127 switch (ac->req->operation) {
4128 case LDB_ADD:
4129 ret = password_hash_add_do_add(ac);
4130 break;
4132 case LDB_MODIFY:
4135 * The user may have an optional PSO applied. If so,
4136 * query the PSO to get the Fine-Grained Password Policy
4137 * for the user, before we perform the modify
4139 pso_req = build_pso_data_request(ac);
4140 if (pso_req != NULL) {
4141 ret = ldb_next_request(ac->module, pso_req);
4142 } else {
4144 /* no PSO, so we can perform the modify now */
4145 ret = password_hash_mod_do_mod(ac);
4147 break;
4149 default:
4150 ret = LDB_ERR_OPERATIONS_ERROR;
4151 break;
4153 break;
4156 done:
4157 if (ret != LDB_SUCCESS) {
4158 struct ldb_reply *new_ares;
4160 new_ares = talloc_zero(ac->req, struct ldb_reply);
4161 if (new_ares == NULL) {
4162 ldb_oom(ldb);
4163 return ldb_module_done(ac->req, NULL, NULL,
4164 LDB_ERR_OPERATIONS_ERROR);
4167 new_ares->error = ret;
4168 if ((ret != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
4169 /* On success and trivial errors a status control is being
4170 * added (used for example by the "samdb_set_password" call) */
4171 ldb_reply_add_control(new_ares,
4172 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
4173 false,
4174 ac->status);
4177 return ldb_module_done(ac->req, new_ares->controls,
4178 new_ares->response, new_ares->error);
4181 return LDB_SUCCESS;
4184 static int build_domain_data_request(struct ph_context *ac)
4186 /* attrs[] is returned from this function in
4187 ac->dom_req->op.search.attrs, so it must be static, as
4188 otherwise the compiler can put it on the stack */
4189 struct ldb_context *ldb;
4190 static const char * const attrs[] = { "pwdProperties",
4191 "pwdHistoryLength",
4192 "maxPwdAge",
4193 "minPwdAge",
4194 "minPwdLength",
4195 "lockoutThreshold",
4196 "lockOutObservationWindow",
4197 NULL };
4198 int ret;
4200 ldb = ldb_module_get_ctx(ac->module);
4202 ret = ldb_build_search_req(&ac->dom_req, ldb, ac,
4203 ldb_get_default_basedn(ldb),
4204 LDB_SCOPE_BASE,
4205 NULL, attrs,
4206 NULL,
4207 ac, get_domain_data_callback,
4208 ac->req);
4209 LDB_REQ_SET_LOCATION(ac->dom_req);
4210 return ret;
4213 static int password_hash_needed(struct ldb_module *module,
4214 struct ldb_request *req,
4215 struct ph_context **_ac)
4217 struct ldb_context *ldb = ldb_module_get_ctx(module);
4218 const char *operation = NULL;
4219 const struct ldb_message *msg = NULL;
4220 struct ph_context *ac = NULL;
4221 const char *passwordAttrs[] = {
4222 DSDB_PASSWORD_ATTRIBUTES,
4223 NULL
4225 const char **a = NULL;
4226 unsigned int attr_cnt = 0;
4227 struct ldb_control *bypass = NULL;
4228 struct ldb_control *uac_ctrl = NULL;
4229 bool userPassword = dsdb_user_password_support(module, req, req);
4230 bool update_password = false;
4231 bool processing_needed = false;
4233 *_ac = NULL;
4235 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_needed\n");
4237 switch (req->operation) {
4238 case LDB_ADD:
4239 operation = "add";
4240 msg = req->op.add.message;
4241 break;
4242 case LDB_MODIFY:
4243 operation = "modify";
4244 msg = req->op.mod.message;
4245 break;
4246 default:
4247 return ldb_next_request(module, req);
4250 if (ldb_dn_is_special(msg->dn)) { /* do not manipulate our control entries */
4251 return ldb_next_request(module, req);
4254 bypass = ldb_request_get_control(req,
4255 DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID);
4256 if (bypass != NULL) {
4257 /* Mark the "bypass" control as uncritical (done) */
4258 bypass->critical = false;
4259 ldb_debug(ldb, LDB_DEBUG_TRACE,
4260 "password_hash_needed(%s) (bypassing)\n",
4261 operation);
4262 return password_hash_bypass(module, req);
4265 /* nobody must touch password histories and 'supplementalCredentials' */
4266 if (ldb_msg_find_element(msg, "ntPwdHistory")) {
4267 return LDB_ERR_UNWILLING_TO_PERFORM;
4269 if (ldb_msg_find_element(msg, "lmPwdHistory")) {
4270 return LDB_ERR_UNWILLING_TO_PERFORM;
4272 if (ldb_msg_find_element(msg, "supplementalCredentials")) {
4273 return LDB_ERR_UNWILLING_TO_PERFORM;
4277 * If no part of this touches the 'userPassword' OR 'clearTextPassword'
4278 * OR 'unicodePwd' OR 'dBCSPwd' we don't need to make any changes.
4279 * For password changes/set there should be a 'delete' or a 'modify'
4280 * on these attributes.
4282 for (a = passwordAttrs; *a != NULL; a++) {
4283 if ((!userPassword) && (ldb_attr_cmp(*a, "userPassword") == 0)) {
4284 continue;
4287 if (ldb_msg_find_element(msg, *a) != NULL) {
4288 /* MS-ADTS 3.1.1.3.1.5.2 */
4289 if ((ldb_attr_cmp(*a, "userPassword") == 0) &&
4290 (dsdb_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
4291 return LDB_ERR_CONSTRAINT_VIOLATION;
4294 ++attr_cnt;
4298 if (attr_cnt > 0) {
4299 update_password = true;
4300 processing_needed = true;
4303 if (ldb_msg_find_element(msg, "pwdLastSet")) {
4304 processing_needed = true;
4307 uac_ctrl = ldb_request_get_control(req,
4308 DSDB_CONTROL_PASSWORD_USER_ACCOUNT_CONTROL_OID);
4309 if (uac_ctrl != NULL) {
4310 struct dsdb_control_password_user_account_control *uac = NULL;
4311 uint32_t added_flags = 0;
4313 uac = talloc_get_type_abort(uac_ctrl->data,
4314 struct dsdb_control_password_user_account_control);
4316 added_flags = uac->new_flags & ~uac->old_flags;
4318 if (added_flags & UF_SMARTCARD_REQUIRED) {
4319 processing_needed = true;
4323 if (!processing_needed) {
4324 return ldb_next_request(module, req);
4327 ac = ph_init_context(module, req, userPassword, update_password);
4328 if (!ac) {
4329 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
4330 return ldb_operr(ldb);
4332 ph_apply_controls(ac);
4335 * Make a copy in order to apply our modifications
4336 * to the final update
4338 ac->update_msg = ldb_msg_copy_shallow(ac, msg);
4339 if (ac->update_msg == NULL) {
4340 return ldb_oom(ldb);
4344 * Remove all password related attributes.
4346 if (ac->userPassword) {
4347 ldb_msg_remove_attr(ac->update_msg, "userPassword");
4349 ldb_msg_remove_attr(ac->update_msg, "clearTextPassword");
4350 ldb_msg_remove_attr(ac->update_msg, "unicodePwd");
4351 ldb_msg_remove_attr(ac->update_msg, "ntPwdHistory");
4352 ldb_msg_remove_attr(ac->update_msg, "dBCSPwd");
4353 ldb_msg_remove_attr(ac->update_msg, "lmPwdHistory");
4354 ldb_msg_remove_attr(ac->update_msg, "supplementalCredentials");
4355 ldb_msg_remove_attr(ac->update_msg, "pwdLastSet");
4357 *_ac = ac;
4358 return LDB_SUCCESS;
4361 static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
4363 struct ldb_context *ldb = ldb_module_get_ctx(module);
4364 struct ph_context *ac = NULL;
4365 int ret;
4367 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add\n");
4369 ret = password_hash_needed(module, req, &ac);
4370 if (ret != LDB_SUCCESS) {
4371 return ret;
4373 if (ac == NULL) {
4374 return ret;
4377 /* Make sure we are performing the password set action on a (for us)
4378 * valid object. Those are instances of either "user" and/or
4379 * "inetOrgPerson". Otherwise continue with the submodules. */
4380 if ((!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "user"))
4381 && (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "inetOrgPerson"))) {
4383 TALLOC_FREE(ac);
4385 if (ldb_msg_find_element(req->op.add.message, "clearTextPassword") != NULL) {
4386 ldb_set_errstring(ldb,
4387 "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
4388 return LDB_ERR_NO_SUCH_ATTRIBUTE;
4391 return ldb_next_request(module, req);
4394 /* get user domain data */
4395 ret = build_domain_data_request(ac);
4396 if (ret != LDB_SUCCESS) {
4397 return ret;
4400 return ldb_next_request(module, ac->dom_req);
4403 static int password_hash_add_do_add(struct ph_context *ac)
4405 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
4406 struct ldb_request *down_req;
4407 struct setup_password_fields_io io;
4408 int ret;
4410 /* Prepare the internal data structure containing the passwords */
4411 ret = setup_io(ac, ac->req->op.add.message, NULL, &io);
4412 if (ret != LDB_SUCCESS) {
4413 return ret;
4416 ret = setup_password_fields(&io);
4417 if (ret != LDB_SUCCESS) {
4418 return ret;
4421 ret = check_password_restrictions_and_log(&io);
4422 if (ret != LDB_SUCCESS) {
4423 return ret;
4426 ret = setup_smartcard_reset(&io);
4427 if (ret != LDB_SUCCESS) {
4428 return ret;
4431 ret = update_final_msg(&io);
4432 if (ret != LDB_SUCCESS) {
4433 return ret;
4436 ret = ldb_build_add_req(&down_req, ldb, ac,
4437 ac->update_msg,
4438 ac->req->controls,
4439 ac, ph_op_callback,
4440 ac->req);
4441 LDB_REQ_SET_LOCATION(down_req);
4442 if (ret != LDB_SUCCESS) {
4443 return ret;
4446 return ldb_next_request(ac->module, down_req);
4449 static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
4451 struct ldb_context *ldb = ldb_module_get_ctx(module);
4452 struct ph_context *ac = NULL;
4453 const char *passwordAttrs[] = {DSDB_PASSWORD_ATTRIBUTES, NULL}, **l;
4454 unsigned int del_attr_cnt, add_attr_cnt, rep_attr_cnt;
4455 struct ldb_message_element *passwordAttr;
4456 struct ldb_message *msg;
4457 struct ldb_request *down_req;
4458 struct ldb_control *restore = NULL;
4459 int ret;
4460 unsigned int i = 0;
4462 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
4464 ret = password_hash_needed(module, req, &ac);
4465 if (ret != LDB_SUCCESS) {
4466 return ret;
4468 if (ac == NULL) {
4469 return ret;
4472 /* use a new message structure so that we can modify it */
4473 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
4474 if (msg == NULL) {
4475 return ldb_oom(ldb);
4478 /* - check for single-valued password attributes
4479 * (if not return "CONSTRAINT_VIOLATION")
4480 * - check that for a password change operation one add and one delete
4481 * operation exists
4482 * (if not return "CONSTRAINT_VIOLATION" or "UNWILLING_TO_PERFORM")
4483 * - check that a password change and a password set operation cannot
4484 * be mixed
4485 * (if not return "UNWILLING_TO_PERFORM")
4486 * - remove all password attributes modifications from the first change
4487 * operation (anything without the passwords) - we will make the real
4488 * modification later */
4489 del_attr_cnt = 0;
4490 add_attr_cnt = 0;
4491 rep_attr_cnt = 0;
4492 for (l = passwordAttrs; *l != NULL; l++) {
4493 if ((!ac->userPassword) &&
4494 (ldb_attr_cmp(*l, "userPassword") == 0)) {
4495 continue;
4498 while ((passwordAttr = ldb_msg_find_element(msg, *l)) != NULL) {
4499 unsigned int mtype = LDB_FLAG_MOD_TYPE(passwordAttr->flags);
4500 unsigned int nvalues = passwordAttr->num_values;
4502 if (mtype == LDB_FLAG_MOD_DELETE) {
4503 ++del_attr_cnt;
4505 if (mtype == LDB_FLAG_MOD_ADD) {
4506 ++add_attr_cnt;
4508 if (mtype == LDB_FLAG_MOD_REPLACE) {
4509 ++rep_attr_cnt;
4511 if ((nvalues != 1) && (mtype == LDB_FLAG_MOD_ADD)) {
4512 talloc_free(ac);
4513 ldb_asprintf_errstring(ldb,
4514 "'%s' attribute must have exactly one value on add operations!",
4515 *l);
4516 return LDB_ERR_CONSTRAINT_VIOLATION;
4518 if ((nvalues > 1) && (mtype == LDB_FLAG_MOD_DELETE)) {
4519 talloc_free(ac);
4520 ldb_asprintf_errstring(ldb,
4521 "'%s' attribute must have zero or one value(s) on delete operations!",
4522 *l);
4523 return LDB_ERR_CONSTRAINT_VIOLATION;
4525 ldb_msg_remove_element(msg, passwordAttr);
4528 if ((del_attr_cnt == 0) && (add_attr_cnt > 0)) {
4529 talloc_free(ac);
4530 ldb_set_errstring(ldb,
4531 "Only the add action for a password change specified!");
4532 return LDB_ERR_UNWILLING_TO_PERFORM;
4534 if ((del_attr_cnt > 1) || (add_attr_cnt > 1)) {
4535 talloc_free(ac);
4536 ldb_set_errstring(ldb,
4537 "Only one delete and one add action for a password change allowed!");
4538 return LDB_ERR_UNWILLING_TO_PERFORM;
4540 if ((rep_attr_cnt > 0) && ((del_attr_cnt > 0) || (add_attr_cnt > 0))) {
4541 talloc_free(ac);
4542 ldb_set_errstring(ldb,
4543 "Either a password change or a password set operation is allowed!");
4544 return LDB_ERR_UNWILLING_TO_PERFORM;
4547 restore = ldb_request_get_control(req,
4548 DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
4549 if (restore == NULL) {
4551 * A tomstone reanimation generates a double update
4552 * of pwdLastSet.
4554 * So we only remove it without the
4555 * DSDB_CONTROL_RESTORE_TOMBSTONE_OID control.
4557 ldb_msg_remove_attr(msg, "pwdLastSet");
4561 /* if there was nothing else to be modified skip to next step */
4562 if (msg->num_elements == 0) {
4563 return password_hash_mod_search_self(ac);
4567 * Now we apply all changes remaining in msg
4568 * and remove them from our final update_msg
4571 for (i = 0; i < msg->num_elements; i++) {
4572 ldb_msg_remove_attr(ac->update_msg,
4573 msg->elements[i].name);
4576 ret = ldb_build_mod_req(&down_req, ldb, ac,
4577 msg,
4578 req->controls,
4579 ac, ph_modify_callback,
4580 req);
4581 LDB_REQ_SET_LOCATION(down_req);
4582 if (ret != LDB_SUCCESS) {
4583 return ret;
4586 return ldb_next_request(module, down_req);
4589 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
4591 struct ph_context *ac;
4593 ac = talloc_get_type(req->context, struct ph_context);
4595 if (!ares) {
4596 return ldb_module_done(ac->req, NULL, NULL,
4597 LDB_ERR_OPERATIONS_ERROR);
4600 if (ares->type == LDB_REPLY_REFERRAL) {
4601 return ldb_module_send_referral(ac->req, ares->referral);
4604 if (ares->error != LDB_SUCCESS) {
4605 return ldb_module_done(ac->req, ares->controls,
4606 ares->response, ares->error);
4609 if (ares->type != LDB_REPLY_DONE) {
4610 talloc_free(ares);
4611 return ldb_module_done(ac->req, NULL, NULL,
4612 LDB_ERR_OPERATIONS_ERROR);
4615 talloc_free(ares);
4617 return password_hash_mod_search_self(ac);
4620 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
4622 struct ldb_context *ldb;
4623 struct ph_context *ac;
4624 int ret = LDB_SUCCESS;
4626 ac = talloc_get_type(req->context, struct ph_context);
4627 ldb = ldb_module_get_ctx(ac->module);
4629 if (!ares) {
4630 ret = LDB_ERR_OPERATIONS_ERROR;
4631 goto done;
4633 if (ares->error != LDB_SUCCESS) {
4634 return ldb_module_done(ac->req, ares->controls,
4635 ares->response, ares->error);
4638 /* we are interested only in the single reply (base search) */
4639 switch (ares->type) {
4640 case LDB_REPLY_ENTRY:
4641 /* Make sure we are performing the password change action on a
4642 * (for us) valid object. Those are instances of either "user"
4643 * and/or "inetOrgPerson". Otherwise continue with the
4644 * submodules. */
4645 if ((!ldb_msg_check_string_attribute(ares->message, "objectClass", "user"))
4646 && (!ldb_msg_check_string_attribute(ares->message, "objectClass", "inetOrgPerson"))) {
4647 talloc_free(ares);
4649 if (ldb_msg_find_element(ac->req->op.mod.message, "clearTextPassword") != NULL) {
4650 ldb_set_errstring(ldb,
4651 "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
4652 ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
4653 goto done;
4656 ret = ldb_next_request(ac->module, ac->req);
4657 goto done;
4660 if (ac->search_res != NULL) {
4661 talloc_free(ares);
4663 ldb_set_errstring(ldb, "Too many results");
4664 ret = LDB_ERR_OPERATIONS_ERROR;
4665 goto done;
4668 ac->search_res = talloc_steal(ac, ares);
4669 ret = LDB_SUCCESS;
4670 break;
4672 case LDB_REPLY_REFERRAL:
4673 /* ignore anything else for now */
4674 talloc_free(ares);
4675 ret = LDB_SUCCESS;
4676 break;
4678 case LDB_REPLY_DONE:
4679 talloc_free(ares);
4681 /* get user domain data */
4682 ret = build_domain_data_request(ac);
4683 if (ret != LDB_SUCCESS) {
4684 return ldb_module_done(ac->req, NULL, NULL, ret);
4687 ret = ldb_next_request(ac->module, ac->dom_req);
4688 break;
4691 done:
4692 if (ret != LDB_SUCCESS) {
4693 return ldb_module_done(ac->req, NULL, NULL, ret);
4696 return LDB_SUCCESS;
4699 static int password_hash_mod_search_self(struct ph_context *ac)
4701 struct ldb_context *ldb;
4702 static const char * const attrs[] = { "objectClass",
4703 "userAccountControl",
4704 "msDS-ResultantPSO",
4705 "msDS-User-Account-Control-Computed",
4706 "pwdLastSet",
4707 "sAMAccountName",
4708 "objectSid",
4709 "userPrincipalName",
4710 "supplementalCredentials",
4711 "lmPwdHistory",
4712 "ntPwdHistory",
4713 "dBCSPwd",
4714 "unicodePwd",
4715 "badPasswordTime",
4716 "badPwdCount",
4717 "lockoutTime",
4718 "msDS-SecondaryKrbTgtNumber",
4719 NULL };
4720 struct ldb_request *search_req;
4721 int ret;
4723 ldb = ldb_module_get_ctx(ac->module);
4725 ret = ldb_build_search_req(&search_req, ldb, ac,
4726 ac->req->op.mod.message->dn,
4727 LDB_SCOPE_BASE,
4728 "(objectclass=*)",
4729 attrs,
4730 NULL,
4731 ac, ph_mod_search_callback,
4732 ac->req);
4733 LDB_REQ_SET_LOCATION(search_req);
4734 if (ret != LDB_SUCCESS) {
4735 return ret;
4738 return ldb_next_request(ac->module, search_req);
4741 static int password_hash_mod_do_mod(struct ph_context *ac)
4743 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
4744 struct ldb_request *mod_req;
4745 struct setup_password_fields_io io;
4746 int ret;
4748 /* Prepare the internal data structure containing the passwords */
4749 ret = setup_io(ac, ac->req->op.mod.message,
4750 ac->search_res->message, &io);
4751 if (ret != LDB_SUCCESS) {
4752 return ret;
4755 ret = setup_password_fields(&io);
4756 if (ret != LDB_SUCCESS) {
4757 return ret;
4760 ret = check_password_restrictions_and_log(&io);
4761 if (ret != LDB_SUCCESS) {
4762 return ret;
4765 ret = setup_smartcard_reset(&io);
4766 if (ret != LDB_SUCCESS) {
4767 return ret;
4770 ret = update_final_msg(&io);
4771 if (ret != LDB_SUCCESS) {
4772 return ret;
4775 ret = ldb_build_mod_req(&mod_req, ldb, ac,
4776 ac->update_msg,
4777 ac->req->controls,
4778 ac, ph_op_callback,
4779 ac->req);
4780 LDB_REQ_SET_LOCATION(mod_req);
4781 if (ret != LDB_SUCCESS) {
4782 return ret;
4785 return ldb_next_request(ac->module, mod_req);
4788 static const struct ldb_module_ops ldb_password_hash_module_ops = {
4789 .name = "password_hash",
4790 .add = password_hash_add,
4791 .modify = password_hash_modify
4794 int ldb_password_hash_module_init(const char *version)
4796 #ifdef ENABLE_GPGME
4797 const char *gversion = NULL;
4798 #endif /* ENABLE_GPGME */
4800 LDB_MODULE_CHECK_VERSION(version);
4802 #ifdef ENABLE_GPGME
4804 * Note: this sets a SIGPIPE handler
4805 * if none is active already. See:
4806 * https://www.gnupg.org/documentation/manuals/gpgme/Signal-Handling.html#Signal-Handling
4808 gversion = gpgme_check_version(GPGME_VERSION);
4809 if (gversion == NULL) {
4810 fprintf(stderr, "%s() in %s version[%s]: "
4811 "gpgme_check_version(%s) not available, "
4812 "gpgme_check_version(NULL) => '%s'\n",
4813 __func__, __FILE__, version,
4814 GPGME_VERSION, gpgme_check_version(NULL));
4815 return LDB_ERR_UNAVAILABLE;
4817 #endif /* ENABLE_GPGME */
4819 return ldb_register_module(&ldb_password_hash_module_ops);