4 Copyright (C) Simo Sorce 2004-2008
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2006
6 Copyright (C) Andrew Tridgell 2004
7 Copyright (C) Stefan Metzmacher 2007-2010
8 Copyright (C) Matthias Dieter Wallnöfer 2009-2010
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 * Component: ldb password_hash module
29 * Description: correctly handle AD password changes fields
31 * Author: Andrew Bartlett
32 * Author: Stefan Metzmacher
36 #include "ldb_module.h"
37 #include "libcli/auth/libcli_auth.h"
38 #include "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"
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
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
;
113 bool update_password
;
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 */
129 uint32_t userAccountControl
;
131 const char *sAMAccountName
;
132 const char *user_principal_name
;
134 uint32_t restrictions
;
135 struct dom_sid
*account_sid
;
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
;
146 /* old credentials */
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
;
158 /* generated credentials */
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
;
171 struct ldb_val supplemental
;
176 static int msg_find_old_and_new_pwd_val(const struct ldb_message
*msg
,
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
) {
194 msg
= request
->op
.add
.message
;
197 msg
= request
->op
.mod
.message
;
200 return ldb_next_request(module
, request
);
203 /* nobody must touch password histories and 'supplementalCredentials' */
204 nte
= dsdb_get_single_valued_attr(msg
, "unicodePwd",
206 lme
= dsdb_get_single_valued_attr(msg
, "dBCSPwd",
208 nthe
= dsdb_get_single_valued_attr(msg
, "ntPwdHistory",
210 lmhe
= dsdb_get_single_valued_attr(msg
, "lmPwdHistory",
212 sce
= dsdb_get_single_valued_attr(msg
, "supplementalCredentials",
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, \
231 if (_count > max) { \
232 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
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
;
257 if (sce
->num_values
!= 1) {
258 return ldb_error(ldb
, LDB_ERR_CONSTRAINT_VIOLATION
,
262 scb
= talloc_zero(request
, struct supplementalCredentialsBlob
);
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
,
279 for (i
=0; i
< scb
->sub
.num_packages
; i
++) {
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) {
289 return ldb_error(ldb
,
290 LDB_ERR_CONSTRAINT_VIOLATION
,
293 scpp
= &scb
->sub
.packages
[i
];
297 if (strcmp(scb
->sub
.packages
[i
].name
, "Primary:Kerberos") == 0) {
299 return ldb_error(ldb
,
300 LDB_ERR_CONSTRAINT_VIOLATION
,
301 "Primary:Kerberos twice");
303 scpk
= &scb
->sub
.packages
[i
];
307 if (strcmp(scb
->sub
.packages
[i
].name
, "Primary:Kerberos-Newer-Keys") == 0) {
309 return ldb_error(ldb
,
310 LDB_ERR_CONSTRAINT_VIOLATION
,
311 "Primary:Kerberos-Newer-Keys twice");
313 scpkn
= &scb
->sub
.packages
[i
];
317 if (strcmp(scb
->sub
.packages
[i
].name
, "Primary:CLEARTEXT") == 0) {
319 return ldb_error(ldb
,
320 LDB_ERR_CONSTRAINT_VIOLATION
,
321 "Primary:CLEARTEXT twice");
323 scpct
= &scb
->sub
.packages
[i
];
328 data_blob_free(&subblob
);
332 return ldb_error(ldb
,
333 LDB_ERR_CONSTRAINT_VIOLATION
,
334 "Primary:Packages missing");
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");
348 struct package_PackagesBlob
*p
;
351 p
= talloc_zero(scb
, struct package_PackagesBlob
);
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
++) {
372 if (scb
->sub
.num_packages
!= (n
+ 1)) {
373 return ldb_error(ldb
, LDB_ERR_CONSTRAINT_VIOLATION
,
374 "Packages num_packages != num_names + 1");
381 struct package_PrimaryKerberosBlob
*k
;
383 k
= talloc_zero(scb
, struct package_PrimaryKerberosBlob
);
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
) {
446 return ldb_error(ldb
, LDB_ERR_CONSTRAINT_VIOLATION
,
447 "PrimaryKerberos old_keys type/value_len doesn't match");
454 struct package_PrimaryKerberosBlob
*k
;
456 k
= talloc_zero(scb
, struct package_PrimaryKerberosBlob
);
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");
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
545 struct package_PrimaryCLEARTEXTBlob
*ct
;
547 ct
= talloc_zero(scb
, struct package_PrimaryCLEARTEXTBlob
);
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");
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");
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
;
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) {
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
) {
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;
621 io
->g
.nt_history
[0] = *io
->g
.nt_hash
;
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
);
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
;
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) {
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
) {
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;
663 io
->g
.lm_history
[0] = *io
->g
.lm_hash
;
665 E_deshash("", io
->g
.lm_history
[0].hash
);
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
;
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
,
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
,
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
);
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
,
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
,
729 ENCTYPE_AES256_CTS_HMAC_SHA1_96
,
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
,
737 return LDB_ERR_OPERATIONS_ERROR
;
739 io
->g
.aes_256
= data_blob_talloc(io
->ac
,
741 KRB5_KEY_LENGTH(&key
));
742 krb5_free_keyblock_contents(io
->smb_krb5_context
->krb5_context
, &key
);
743 if (!io
->g
.aes_256
.data
) {
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
,
755 ENCTYPE_AES128_CTS_HMAC_SHA1_96
,
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
,
763 return LDB_ERR_OPERATIONS_ERROR
;
765 io
->g
.aes_128
= data_blob_talloc(io
->ac
,
767 KRB5_KEY_LENGTH(&key
));
768 krb5_free_keyblock_contents(io
->smb_krb5_context
->krb5_context
, &key
);
769 if (!io
->g
.aes_128
.data
) {
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
,
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
,
789 return LDB_ERR_OPERATIONS_ERROR
;
791 io
->g
.des_md5
= data_blob_talloc(io
->ac
,
793 KRB5_KEY_LENGTH(&key
));
794 krb5_free_keyblock_contents(io
->smb_krb5_context
->krb5_context
, &key
);
795 if (!io
->g
.des_md5
.data
) {
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
,
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
,
815 return LDB_ERR_OPERATIONS_ERROR
;
817 io
->g
.des_crc
= data_blob_talloc(io
->ac
,
819 KRB5_KEY_LENGTH(&key
));
820 krb5_free_keyblock_contents(io
->smb_krb5_context
->krb5_context
, &key
);
821 if (!io
->g
.des_crc
.data
) {
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
;
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
849 pkb3
->salt
.string
= io
->g
.salt
;
851 pkb3
->keys
= talloc_array(io
->ac
,
852 struct package_PrimaryKerberosKey3
,
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 */
872 for (i
=0; i
< old_scb
->sub
.num_packages
; i
++) {
873 if (strcmp("Primary:Kerberos", old_scb
->sub
.packages
[i
].name
) != 0) {
877 if (!old_scb
->sub
.packages
[i
].data
|| !old_scb
->sub
.packages
[i
].data
[0]) {
881 old_scp
= &old_scb
->sub
.packages
[i
];
884 /* Primary:Kerberos element of supplementalCredentials */
888 blob
= strhex_to_data_blob(io
->ac
, old_scp
->data
);
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",
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]",
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 */
921 /* fill in the old keys */
922 pkb3
->num_old_keys
= old_pkb3
->num_keys
;
923 pkb3
->old_keys
= old_pkb3
->keys
;
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
;
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
951 pkb4
->salt
.string
= io
->g
.salt
;
952 pkb4
->default_iteration_count
= 4096;
955 pkb4
->keys
= talloc_array(io
->ac
,
956 struct package_PrimaryKerberosKey4
,
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 */
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) {
991 if (!old_scb
->sub
.packages
[i
].data
|| !old_scb
->sub
.packages
[i
].data
[0]) {
995 old_scp
= &old_scb
->sub
.packages
[i
];
998 /* Primary:Kerberos-Newer-Keys element of supplementalCredentials */
1002 blob
= strhex_to_data_blob(io
->ac
, old_scp
->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
,
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",
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]",
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 */
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
;
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
;
1065 DATA_BLOB backslash
;
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
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
,
1263 .user
= &sAMAccountName_l
,
1267 .user
= &sAMAccountName_u
,
1270 /* userPrincipalName with "Digest" realm */
1272 .user
= &userPrincipalName
,
1276 .user
= &userPrincipalName_l
,
1280 .user
= &userPrincipalName_u
,
1283 /* nt4dom\\sAMAccountName with "Digest" realm */
1285 .user
= &sAMAccountName
,
1286 .nt4dom
= &netbios_domain
,
1290 .user
= &sAMAccountName_l
,
1291 .nt4dom
= &netbios_domain_l
,
1295 .user
= &sAMAccountName_u
,
1296 .nt4dom
= &netbios_domain_u
,
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
,
1356 return ldb_oom(ldb
);
1359 for (i
=0; i
< ARRAY_SIZE(wdigest
); i
++) {
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
);
1379 #define SHA_SALT_PERMITTED_CHARS "abcdefghijklmnopqrstuvwxyz" \
1380 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
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
))
1405 *algorithm
= SHA_512_ALGORITHM_ID
;
1410 rp
= strcasestr(scheme
, ROUNDS_PARAMETER
);
1412 /* No options specified, use crypt default number of rounds */
1416 rp
+= strlen(ROUNDS_PARAMETER
);
1417 for (i
= 0; isdigit(rp
[i
]) && i
< (sizeof(digits
) - 1); i
++) {
1421 *rounds
= atoi(digits
);
1426 * Calculate the password hash specified by scheme, and return it in
1429 static int setup_primary_userPassword_hash(
1431 struct setup_password_fields_io
*io
,
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();
1444 struct crypt_data crypt_data
; /* working storage used by crypt */
1447 /* Genrate a random password salt */
1448 salt
= generate_random_str_list(frame
,
1450 SHA_SALT_PERMITTED_CHARS
);
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(
1460 "setup_primary_userPassword: Invalid scheme of [%s] "
1461 "specified for 'password hash userPassword schemes' in "
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 */
1472 cmd
= talloc_asprintf(frame
,
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
1486 hash
= crypt_r((char *)io
->n
.cleartext_utf8
->data
, cmd
, &crypt_data
);
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
);
1496 int err
= strerror_r(errno
, buf
, sizeof(buf
));
1498 strlcpy(buf
, "Unknown error", sizeof(buf
)-1);
1500 ldb_asprintf_errstring(
1502 "setup_primary_userPassword: generation of a %s "
1503 "password hash failed: (%s)",
1507 return LDB_ERR_OPERATIONS_ERROR
;
1510 hash_blob
= talloc_zero(ctx
, DATA_BLOB
);
1512 if (hash_blob
== NULL
) {
1514 return ldb_oom(ldb
);
1517 *hash_blob
= data_blob_talloc(hash_blob
,
1518 (const uint8_t *)hash
,
1520 if (hash_blob
->data
== NULL
) {
1522 return ldb_oom(ldb
);
1524 hash_value
->value
= hash_blob
;
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();
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
) {
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
) {
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
);
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];
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
,
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
));
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
);
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
);
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__
,
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
);
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
) {
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
,
1668 "'password hash gpg key ids': "
1669 "Public Key ID [%s] "
1670 "not found in keyring\n",
1674 ldb_debug(ldb
, LDB_DEBUG_ERROR
,
1675 "%s:%s: ki[%zu] key_id[%s] "
1677 __location__
, __func__
,
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
);
1687 return ldb_module_operr(io
->ac
->module
);
1692 gret
= gpgme_op_encrypt(ctx
, keys
,
1693 GPGME_ENCRYPT_ALWAYS_TRUST
,
1694 plain_data
, crypt_data
);
1695 gpgme_data_release(plain_data
);
1697 for (kr
= 0; keys
[kr
] != NULL
; kr
++) {
1698 gpgme_key_release(keys
[kr
]);
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
);
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
,
1721 gpgme_free(crypt_mem
);
1724 if (pgb
->gpg_blob
.data
== NULL
) {
1725 return ldb_module_oom(io
->ac
->module
);
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
;
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
;
1755 enum ndr_err_code ndr_err
;
1756 bool do_newer_keys
= false;
1757 bool do_cleartext
= false;
1758 bool do_samba_gpg
= false;
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
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
;
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)
1796 * Primary:CLEARTEXT (optional)
1797 * Primary:userPassword
1798 * Primary:SambaGPG (optional)
1800 * And the 'Packages' package is insert before the last
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
;
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
) {
1824 ndr_err
= ndr_push_struct_blob(
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(
1832 "setup_supplemental_field: "
1834 "package_PrimaryKerberosNeverBlob: %s",
1836 return LDB_ERR_OPERATIONS_ERROR
;
1838 pknb_hexstr
= data_blob_hex_string_upper(io
->ac
, &pknb_blob
);
1840 return ldb_oom(ldb
);
1842 pp
->name
= "Primary:Kerberos-Newer-Keys";
1844 pp
->data
= pknb_hexstr
;
1851 * setup 'Primary:Kerberos' element
1853 /* Primary:Kerberos */
1854 struct package_PrimaryKerberosBlob pkb
;
1858 names
[num_names
++] = "Kerberos";
1860 ret
= setup_primary_kerberos(io
, old_scb
, &pkb
);
1861 if (ret
!= LDB_SUCCESS
) {
1865 ndr_err
= ndr_push_struct_blob(
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(
1873 "setup_supplemental_field: "
1874 "failed to push package_PrimaryKerberosBlob: %s",
1876 return LDB_ERR_OPERATIONS_ERROR
;
1878 pkb_hexstr
= data_blob_hex_string_upper(io
->ac
, &pkb_blob
);
1880 return ldb_oom(ldb
);
1882 pp
->name
= "Primary:Kerberos";
1884 pp
->data
= pkb_hexstr
;
1891 * setup 'Primary:WDigest' element
1893 struct package_PrimaryWDigestBlob pdb
;
1897 names
[num_names
++] = "WDigest";
1899 ret
= setup_primary_wdigest(io
, old_scb
, &pdb
);
1900 if (ret
!= LDB_SUCCESS
) {
1904 ndr_err
= ndr_push_struct_blob(
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(
1912 "setup_supplemental_field: "
1913 "failed to push package_PrimaryWDigestBlob: %s",
1915 return LDB_ERR_OPERATIONS_ERROR
;
1917 pdb_hexstr
= data_blob_hex_string_upper(io
->ac
, &pdb_blob
);
1919 return ldb_oom(ldb
);
1921 pp
->name
= "Primary:WDigest";
1923 pp
->data
= pdb_hexstr
;
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;
1936 struct package_PrimaryCLEARTEXTBlob pcb
;
1940 names
[num_names
++] = "CLEARTEXT";
1942 pcb
.cleartext
= *io
->n
.cleartext_utf16
;
1944 ndr_err
= ndr_push_struct_blob(
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(
1952 "setup_supplemental_field: "
1953 "failed to push package_PrimaryCLEARTEXTBlob: %s",
1955 return LDB_ERR_OPERATIONS_ERROR
;
1957 pcb_hexstr
= data_blob_hex_string_upper(io
->ac
, &pcb_blob
);
1959 return ldb_oom(ldb
);
1961 pp
->name
= "Primary:CLEARTEXT";
1963 pp
->data
= pcb_hexstr
;
1968 if (io
->ac
->userPassword_schemes
) {
1970 * setup 'Primary:userPassword' element
1972 struct package_PrimaryUserPasswordBlob
1974 DATA_BLOB p_userPassword_b_blob
;
1975 char *p_userPassword_b_hexstr
;
1977 names
[num_names
++] = "userPassword";
1979 ret
= setup_primary_userPassword(io
,
1982 if (ret
!= LDB_SUCCESS
) {
1986 ndr_err
= ndr_push_struct_blob(
1987 &p_userPassword_b_blob
,
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(
1996 "setup_supplemental_field: failed to push "
1997 "package_PrimaryUserPasswordBlob: %s",
1999 return LDB_ERR_OPERATIONS_ERROR
;
2001 p_userPassword_b_hexstr
2002 = data_blob_hex_string_upper(
2004 &p_userPassword_b_blob
);
2005 if (!p_userPassword_b_hexstr
) {
2006 return ldb_oom(ldb
);
2008 pp
->name
= "Primary:userPassword";
2010 pp
->data
= p_userPassword_b_hexstr
;
2016 * setup 'Primary:SambaGPG' element
2018 if (io
->ac
->gpg_key_ids
!= NULL
) {
2019 do_samba_gpg
= true;
2022 struct package_PrimarySambaGPGBlob pgb
;
2026 names
[num_names
++] = "SambaGPG";
2028 ret
= setup_primary_samba_gpg(io
, &pgb
);
2029 if (ret
!= LDB_SUCCESS
) {
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",
2041 return LDB_ERR_OPERATIONS_ERROR
;
2043 pgb_hexstr
= data_blob_hex_string_upper(io
->ac
, &pgb_blob
);
2045 return ldb_oom(ldb
);
2047 pp
->name
= "Primary:SambaGPG";
2049 pp
->data
= pgb_hexstr
;
2055 * setup 'Packages' element
2058 struct package_PackagesBlob pb
;
2063 ndr_err
= ndr_push_struct_blob(
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(
2071 "setup_supplemental_field: "
2072 "failed to push package_PackagesBlob: %s",
2074 return LDB_ERR_OPERATIONS_ERROR
;
2076 pb_hexstr
= data_blob_hex_string_upper(io
->ac
, &pb_blob
);
2078 return ldb_oom(ldb
);
2080 pp
->name
= "Packages";
2082 pp
->data
= pb_hexstr
;
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
;
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
,
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(
2118 "setup_supplemental_field: "
2119 "failed to push supplementalCredentialsBlob: %s",
2121 return LDB_ERR_OPERATIONS_ERROR
;
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
;
2137 switch (io
->ac
->req
->operation
) {
2139 msg
= io
->ac
->req
->op
.add
.message
;
2142 msg
= io
->ac
->req
->op
.mod
.message
;
2145 return LDB_ERR_OPERATIONS_ERROR
;
2149 if (io
->ac
->pwd_last_set_bypass
) {
2150 struct ldb_message_element
*el1
= NULL
;
2151 struct ldb_message_element
*el2
= NULL
;
2154 return LDB_ERR_CONSTRAINT_VIOLATION
;
2157 el1
= dsdb_get_single_valued_attr(msg
, "pwdLastSet",
2158 io
->ac
->req
->operation
);
2160 return LDB_ERR_CONSTRAINT_VIOLATION
;
2162 el2
= ldb_msg_find_element(msg
, "pwdLastSet");
2164 return LDB_ERR_CONSTRAINT_VIOLATION
;
2167 return LDB_ERR_CONSTRAINT_VIOLATION
;
2170 io
->g
.last_set
= samdb_result_nttime(msg
, "pwdLastSet", 0);
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
) {
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",
2201 if (ret
!= LDB_SUCCESS
) {
2205 old_last_set
= samdb_result_nttime(tmp_msg
,
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",
2219 if (ret
!= LDB_SUCCESS
) {
2223 io
->g
.last_set
= samdb_result_nttime(tmp_msg
,
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
) {
2241 if (!io
->ac
->pwd_last_set_default
) {
2244 if (!io
->ac
->update_password
) {
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;
2261 /* -1 means set it as now */
2263 io
->g
.last_set
= timeval_to_nttime(&tv
);
2266 return dsdb_module_werror(io
->ac
->module
,
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
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;
2291 static int setup_given_passwords(struct setup_password_fields_io
*io
,
2292 struct setup_password_fields_given
*g
)
2294 struct ldb_context
*ldb
;
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
,
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
;
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
;
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
);
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
);
2377 return ldb_oom(ldb
);
2380 /* compute the new lm hash */
2381 ok
= E_deshash((char *)g
->cleartext_utf8
->data
, lm_hash
->hash
);
2383 g
->lm_hash
= lm_hash
;
2385 talloc_free(lm_hash
);
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
);
2400 ret
= setup_last_set_field(io
);
2401 if (ret
!= LDB_SUCCESS
) {
2405 if (!io
->ac
->update_password
) {
2409 /* transform the old password (for password changes) */
2410 ret
= setup_given_passwords(io
, &io
->og
);
2411 if (ret
!= LDB_SUCCESS
) {
2415 /* transform the new password */
2416 ret
= setup_given_passwords(io
, &io
->n
);
2417 if (ret
!= LDB_SUCCESS
) {
2421 if (io
->n
.cleartext_utf8
) {
2422 ret
= setup_kerberos_keys(io
);
2423 if (ret
!= LDB_SUCCESS
) {
2428 ret
= setup_nt_fields(io
);
2429 if (ret
!= LDB_SUCCESS
) {
2433 if (lpcfg_lanman_auth(lp_ctx
)) {
2434 ret
= setup_lm_fields(io
);
2435 if (ret
!= LDB_SUCCESS
) {
2439 io
->g
.lm_hash
= NULL
;
2440 io
->g
.lm_history_len
= 0;
2443 ret
= setup_supplemental_field(io
);
2444 if (ret
!= 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
) {
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
));
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
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
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().
2508 scb
.sub
.num_packages
= 0;
2511 * setup 'supplementalCredentials' value without packages
2513 ndr_err
= ndr_push_struct_blob(&io
->g
.supplemental
, io
->ac
,
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",
2522 return LDB_ERR_OPERATIONS_ERROR
;
2525 io
->ac
->update_password
= true;
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
;
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
,
2547 if (!NT_STATUS_IS_OK(status
)) {
2551 if (mod_msg
== NULL
) {
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
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
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
2597 ret
= dsdb_module_modify(io
->ac
->module
, mod_msg
,
2598 DSDB_FLAG_NEXT_MODULE
,
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...
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!",
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
);
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
) {
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 "
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? */
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
) &&
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!",
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
);
2723 case SAMR_VALIDATION_STATUS_SUCCESS
:
2724 /* perfect -> proceed! */
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!",
2735 io
->ac
->status
->domain_data
.minPwdLength
);
2736 io
->ac
->status
->reject_reason
= SAM_PWD_CHANGE_PASSWORD_TOO_SHORT
;
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!",
2747 io
->ac
->status
->reject_reason
= SAM_PWD_CHANGE_NOT_COMPLEX
;
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!",
2762 if (io
->ac
->pwd_reset
) {
2767 if (io
->n
.nt_hash
) {
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);
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)!",
2781 io
->ac
->status
->reject_reason
= SAM_PWD_CHANGE_PWD_IN_HISTORY
;
2787 if (io
->n
.lm_hash
) {
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);
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)!",
2801 io
->ac
->status
->reject_reason
= SAM_PWD_CHANGE_PWD_IN_HISTORY
;
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!",
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!",
2834 static int check_password_restrictions_and_log(struct setup_password_fields_io
*io
)
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
2847 /* Do not record a failure in the auth log below in the success case */
2848 if (ret
== LDB_SUCCESS
) {
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,
2870 .account_name
= io
->u
.sAMAccountName
,
2871 .domain_name
= domain_name
,
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
,
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 "
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
));
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
,
2908 io
->u
.sAMAccountName
,
2916 static int update_final_msg(struct setup_password_fields_io
*io
)
2918 struct ldb_context
*ldb
= ldb_module_get_ctx(io
->ac
->module
);
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:
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:
2942 * - supplementalCredentials
2945 switch (io
->ac
->req
->operation
) {
2947 update_password
= true;
2948 el_flags
|= DSDB_FLAG_INTERNAL_FORCE_META_DATA
;
2951 el_flags
|= LDB_FLAG_MOD_REPLACE
;
2952 el_flags
|= DSDB_FLAG_INTERNAL_FORCE_META_DATA
;
2955 return ldb_module_operr(io
->ac
->module
);
2958 if (update_password
) {
2959 ret
= ldb_msg_add_empty(io
->ac
->update_msg
,
2962 if (ret
!= LDB_SUCCESS
) {
2965 ret
= ldb_msg_add_empty(io
->ac
->update_msg
,
2968 if (ret
!= LDB_SUCCESS
) {
2971 ret
= ldb_msg_add_empty(io
->ac
->update_msg
,
2974 if (ret
!= LDB_SUCCESS
) {
2977 ret
= ldb_msg_add_empty(io
->ac
->update_msg
,
2980 if (ret
!= LDB_SUCCESS
) {
2985 ret
= ldb_msg_add_empty(io
->ac
->update_msg
,
2986 "supplementalCredentials",
2988 if (ret
!= LDB_SUCCESS
) {
2992 if (io
->ac
->update_lastset
) {
2993 ret
= ldb_msg_add_empty(io
->ac
->update_msg
,
2996 if (ret
!= LDB_SUCCESS
) {
3001 if (io
->g
.nt_hash
!= NULL
) {
3002 ret
= samdb_msg_add_hash(ldb
, io
->ac
,
3006 if (ret
!= LDB_SUCCESS
) {
3010 if (io
->g
.lm_hash
!= NULL
) {
3011 ret
= samdb_msg_add_hash(ldb
, io
->ac
,
3015 if (ret
!= LDB_SUCCESS
) {
3019 if (io
->g
.nt_history_len
> 0) {
3020 ret
= samdb_msg_add_hashes(ldb
, io
->ac
,
3024 io
->g
.nt_history_len
);
3025 if (ret
!= LDB_SUCCESS
) {
3029 if (io
->g
.lm_history_len
> 0) {
3030 ret
= samdb_msg_add_hashes(ldb
, io
->ac
,
3034 io
->g
.lm_history_len
);
3035 if (ret
!= LDB_SUCCESS
) {
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
) {
3047 if (io
->ac
->update_lastset
) {
3048 ret
= samdb_msg_add_uint64(ldb
, io
->ac
,
3052 if (ret
!= 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
,
3076 enum ldb_request_type operation
,
3077 const struct ldb_val
**new_val
,
3078 const struct ldb_val
**old_val
)
3089 for (i
= 0; i
< msg
->num_elements
; i
++) {
3090 if (ldb_attr_cmp(msg
->elements
[i
].name
, name
) != 0) {
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];
3107 return LDB_ERR_UNWILLING_TO_PERFORM
;
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];
3114 return LDB_ERR_CONSTRAINT_VIOLATION
;
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
);
3132 const struct ldb_message
*info_msg
= NULL
;
3133 struct dom_sid
*account_sid
= NULL
;
3134 int rodc_krbtgt
= 0;
3138 /* Some operations below require kerberos contexts */
3140 if (existing_msg
!= NULL
) {
3142 * This is a modify operation
3144 info_msg
= existing_msg
;
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
);
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
));
3169 ldb_asprintf_errstring(ldb
, "Failed to setup krb5_context: %s",
3170 error_message(ret
));
3172 return LDB_ERR_OPERATIONS_ERROR
;
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",
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
) {
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
),
3234 ldb_dn_get_linearized(info_msg
->dn
));
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",
3252 &io
->n
.cleartext_utf8
,
3253 &io
->og
.cleartext_utf8
);
3254 if (ret
!= LDB_SUCCESS
) {
3255 ldb_asprintf_errstring(ldb
,
3257 "it's only allowed to set the old password once!");
3262 if (io
->n
.cleartext_utf8
!= NULL
) {
3263 struct ldb_val
*cleartext_utf8_blob
;
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",
3287 &io
->n
.cleartext_utf16
,
3288 &io
->og
.cleartext_utf16
);
3289 if (ret
!= LDB_SUCCESS
) {
3290 ldb_asprintf_errstring(ldb
,
3292 "it's only allowed to set the old password once!");
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
3309 ret
= msg_find_old_and_new_pwd_val(client_msg
, "unicodePwd",
3313 if (ret
!= LDB_SUCCESS
) {
3314 ldb_asprintf_errstring(ldb
,
3316 "it's only allowed to set the old password once!");
3320 /* Checks and converts the actual "unicodePwd" attribute */
3321 if (!ac
->hash_values
&&
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
,
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
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
,
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
&&
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
,
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
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
,
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",
3430 &lm_hash
, &old_lm_hash
);
3431 if (ret
!= LDB_SUCCESS
) {
3432 ldb_asprintf_errstring(ldb
,
3434 "it's only allowed to set the old password once!");
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
,
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
,
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
,
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
,
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
,
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
,
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
) {
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
);
3559 return ldb_module_operr(ac
->module
);
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;
3574 /* Otherwise we have also here a "password reset" */
3575 ac
->pwd_reset
= true;
3578 /* this shouldn't happen */
3579 return ldb_operr(ldb
);
3582 if (io
->u
.is_krbtgt
) {
3585 size_t diff
= max
- min
;
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.
3612 generate_random_buffer((uint8_t *)&tmp
, sizeof(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
,
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
) {
3638 if (ac
->pwd_reset
) {
3639 /* Get the old password from the database */
3640 status
= samdb_result_passwords_no_lockout(ac
,
3646 /* Get the old password from the database */
3647 status
= samdb_result_passwords(ac
,
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
,
3673 io
->o
.lm_history_len
= samdb_result_hashes(ac
, existing_msg
,
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
,
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",
3691 return LDB_ERR_OPERATIONS_ERROR
;
3699 static struct ph_context
*ph_init_context(struct ldb_module
*module
,
3700 struct ldb_request
*req
,
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
);
3712 ldb_set_errstring(ldb
, "Out of Memory");
3716 ac
->module
= module
;
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
,
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
) {
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
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
);
3868 ret
= LDB_ERR_OPERATIONS_ERROR
;
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
) {
3882 ldb_set_errstring(ldb
, "Uninitialized status");
3883 ret
= LDB_ERR_OPERATIONS_ERROR
;
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
);
3915 (settings
->pwdProperties
& DOMAIN_PASSWORD_COMPLEX
);
3917 ldb_msg_find_attr_as_bool(ares
->message
,
3918 "msDS-PasswordComplexityEnabled",
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
);
3939 case LDB_REPLY_REFERRAL
:
3945 case LDB_REPLY_DONE
:
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
);
3955 ret
= LDB_ERR_OPERATIONS_ERROR
;
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
) {
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
,
3981 return ldb_module_done(ac
->req
, new_ares
->controls
,
3982 new_ares
->response
, new_ares
->error
);
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",
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
;
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
) {
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
,
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
);
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
);
4049 ret
= LDB_ERR_OPERATIONS_ERROR
;
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
) {
4062 ldb_set_errstring(ldb
, "Too many results");
4063 ret
= LDB_ERR_OPERATIONS_ERROR
;
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
) {
4074 ret
= LDB_ERR_OPERATIONS_ERROR
;
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
) {
4109 ldb_set_errstring(ldb
, "Too many results");
4110 ret
= LDB_ERR_OPERATIONS_ERROR
;
4114 ac
->dom_res
= talloc_steal(ac
, ares
);
4118 case LDB_REPLY_REFERRAL
:
4124 case LDB_REPLY_DONE
:
4126 /* call the next step */
4127 switch (ac
->req
->operation
) {
4129 ret
= password_hash_add_do_add(ac
);
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
);
4144 /* no PSO, so we can perform the modify now */
4145 ret
= password_hash_mod_do_mod(ac
);
4150 ret
= LDB_ERR_OPERATIONS_ERROR
;
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
) {
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
,
4177 return ldb_module_done(ac
->req
, new_ares
->controls
,
4178 new_ares
->response
, new_ares
->error
);
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",
4196 "lockOutObservationWindow",
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
),
4207 ac
, get_domain_data_callback
,
4209 LDB_REQ_SET_LOCATION(ac
->dom_req
);
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
,
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;
4235 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "password_hash_needed\n");
4237 switch (req
->operation
) {
4240 msg
= req
->op
.add
.message
;
4243 operation
= "modify";
4244 msg
= req
->op
.mod
.message
;
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",
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)) {
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
;
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
);
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");
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
;
4367 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "password_hash_add\n");
4369 ret
= password_hash_needed(module
, req
, &ac
);
4370 if (ret
!= LDB_SUCCESS
) {
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"))) {
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
) {
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
;
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
) {
4416 ret
= setup_password_fields(&io
);
4417 if (ret
!= LDB_SUCCESS
) {
4421 ret
= check_password_restrictions_and_log(&io
);
4422 if (ret
!= LDB_SUCCESS
) {
4426 ret
= setup_smartcard_reset(&io
);
4427 if (ret
!= LDB_SUCCESS
) {
4431 ret
= update_final_msg(&io
);
4432 if (ret
!= LDB_SUCCESS
) {
4436 ret
= ldb_build_add_req(&down_req
, ldb
, ac
,
4441 LDB_REQ_SET_LOCATION(down_req
);
4442 if (ret
!= LDB_SUCCESS
) {
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
;
4462 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "password_hash_modify\n");
4464 ret
= password_hash_needed(module
, req
, &ac
);
4465 if (ret
!= LDB_SUCCESS
) {
4472 /* use a new message structure so that we can modify it */
4473 msg
= ldb_msg_copy_shallow(ac
, req
->op
.mod
.message
);
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
4482 * (if not return "CONSTRAINT_VIOLATION" or "UNWILLING_TO_PERFORM")
4483 * - check that a password change and a password set operation cannot
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 */
4492 for (l
= passwordAttrs
; *l
!= NULL
; l
++) {
4493 if ((!ac
->userPassword
) &&
4494 (ldb_attr_cmp(*l
, "userPassword") == 0)) {
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
) {
4505 if (mtype
== LDB_FLAG_MOD_ADD
) {
4508 if (mtype
== LDB_FLAG_MOD_REPLACE
) {
4511 if ((nvalues
!= 1) && (mtype
== LDB_FLAG_MOD_ADD
)) {
4513 ldb_asprintf_errstring(ldb
,
4514 "'%s' attribute must have exactly one value on add operations!",
4516 return LDB_ERR_CONSTRAINT_VIOLATION
;
4518 if ((nvalues
> 1) && (mtype
== LDB_FLAG_MOD_DELETE
)) {
4520 ldb_asprintf_errstring(ldb
,
4521 "'%s' attribute must have zero or one value(s) on delete operations!",
4523 return LDB_ERR_CONSTRAINT_VIOLATION
;
4525 ldb_msg_remove_element(msg
, passwordAttr
);
4528 if ((del_attr_cnt
== 0) && (add_attr_cnt
> 0)) {
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)) {
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))) {
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
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
,
4579 ac
, ph_modify_callback
,
4581 LDB_REQ_SET_LOCATION(down_req
);
4582 if (ret
!= LDB_SUCCESS
) {
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
);
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
) {
4611 return ldb_module_done(ac
->req
, NULL
, NULL
,
4612 LDB_ERR_OPERATIONS_ERROR
);
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
);
4630 ret
= LDB_ERR_OPERATIONS_ERROR
;
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
4645 if ((!ldb_msg_check_string_attribute(ares
->message
, "objectClass", "user"))
4646 && (!ldb_msg_check_string_attribute(ares
->message
, "objectClass", "inetOrgPerson"))) {
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
;
4656 ret
= ldb_next_request(ac
->module
, ac
->req
);
4660 if (ac
->search_res
!= NULL
) {
4663 ldb_set_errstring(ldb
, "Too many results");
4664 ret
= LDB_ERR_OPERATIONS_ERROR
;
4668 ac
->search_res
= talloc_steal(ac
, ares
);
4672 case LDB_REPLY_REFERRAL
:
4673 /* ignore anything else for now */
4678 case LDB_REPLY_DONE
:
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
);
4692 if (ret
!= LDB_SUCCESS
) {
4693 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
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",
4709 "userPrincipalName",
4710 "supplementalCredentials",
4718 "msDS-SecondaryKrbTgtNumber",
4720 struct ldb_request
*search_req
;
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
,
4731 ac
, ph_mod_search_callback
,
4733 LDB_REQ_SET_LOCATION(search_req
);
4734 if (ret
!= LDB_SUCCESS
) {
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
;
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
) {
4755 ret
= setup_password_fields(&io
);
4756 if (ret
!= LDB_SUCCESS
) {
4760 ret
= check_password_restrictions_and_log(&io
);
4761 if (ret
!= LDB_SUCCESS
) {
4765 ret
= setup_smartcard_reset(&io
);
4766 if (ret
!= LDB_SUCCESS
) {
4770 ret
= update_final_msg(&io
);
4771 if (ret
!= LDB_SUCCESS
) {
4775 ret
= ldb_build_mod_req(&mod_req
, ldb
, ac
,
4780 LDB_REQ_SET_LOCATION(mod_req
);
4781 if (ret
!= LDB_SUCCESS
) {
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
)
4797 const char *gversion
= NULL
;
4798 #endif /* ENABLE_GPGME */
4800 LDB_MODULE_CHECK_VERSION(version
);
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
);