4 Copyright (C) Simo Sorce 2004-2006
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2006
6 Copyright (C) Andrew Tridgell 2004
7 Copyright (C) Stefan Metzmacher 2007
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 * Component: ldb password_hash module
28 * Description: correctly update hash values based on changes to userPassword and friends
30 * Author: Andrew Bartlett
31 * Author: Stefan Metzmacher
35 #include "libcli/ldap/ldap_ndr.h"
36 #include "ldb/include/ldb_errors.h"
37 #include "ldb/include/ldb.h"
38 #include "ldb/include/ldb_private.h"
39 #include "librpc/gen_ndr/misc.h"
40 #include "librpc/gen_ndr/samr.h"
41 #include "libcli/auth/libcli_auth.h"
42 #include "libcli/security/security.h"
43 #include "system/kerberos.h"
44 #include "auth/kerberos/kerberos.h"
45 #include "system/time.h"
46 #include "dsdb/samdb/samdb.h"
47 #include "dsdb/common/flags.h"
48 #include "dsdb/samdb/ldb_modules/password_modules.h"
49 #include "librpc/ndr/libndr.h"
50 #include "librpc/gen_ndr/ndr_drsblobs.h"
51 #include "lib/crypto/crypto.h"
52 #include "param/param.h"
54 /* If we have decided there is reason to work on this request, then
55 * setup all the password hash types correctly.
57 * If the administrator doesn't want the userPassword stored (set in the
58 * domain and per-account policies) then we must strip that out before
59 * we do the first operation.
61 * Once this is done (which could update anything at all), we
62 * calculate the password hashes.
64 * This function must not only update the unicodePwd, dBCSPwd and
65 * supplementalCredentials fields, it must also atomicly increment the
66 * msDS-KeyVersionNumber. We should be in a transaction, so all this
67 * should be quite safe...
69 * Finally, if the administrator has requested that a password history
70 * be maintained, then this should also be written out.
76 enum ph_type
{PH_ADD
, PH_MOD
} type
;
77 enum ph_step
{PH_ADD_SEARCH_DOM
, PH_ADD_DO_ADD
, PH_MOD_DO_REQ
, PH_MOD_SEARCH_SELF
, PH_MOD_SEARCH_DOM
, PH_MOD_DO_MOD
} step
;
79 struct ldb_module
*module
;
80 struct ldb_request
*orig_req
;
82 struct ldb_request
*dom_req
;
83 struct ldb_reply
*dom_res
;
85 struct ldb_request
*down_req
;
87 struct ldb_request
*search_req
;
88 struct ldb_reply
*search_res
;
90 struct ldb_request
*mod_req
;
92 struct dom_sid
*domain_sid
;
98 uint_t pwdHistoryLength
;
104 struct setup_password_fields_io
{
105 struct ph_context
*ac
;
106 struct domain_data
*domain
;
107 struct smb_krb5_context
*smb_krb5_context
;
109 /* infos about the user account */
111 uint32_t user_account_control
;
112 const char *sAMAccountName
;
113 const char *user_principal_name
;
117 /* new credentials */
119 const char *cleartext
;
120 struct samr_Password
*nt_hash
;
121 struct samr_Password
*lm_hash
;
124 /* old credentials */
126 uint32_t nt_history_len
;
127 struct samr_Password
*nt_history
;
128 uint32_t lm_history_len
;
129 struct samr_Password
*lm_history
;
130 const struct ldb_val
*supplemental
;
131 struct supplementalCredentialsBlob scb
;
135 /* generated credentials */
137 struct samr_Password
*nt_hash
;
138 struct samr_Password
*lm_hash
;
139 uint32_t nt_history_len
;
140 struct samr_Password
*nt_history
;
141 uint32_t lm_history_len
;
142 struct samr_Password
*lm_history
;
148 struct ldb_val supplemental
;
154 static int setup_nt_fields(struct setup_password_fields_io
*io
)
158 io
->g
.nt_hash
= io
->n
.nt_hash
;
160 if (io
->domain
->pwdHistoryLength
== 0) {
164 /* We might not have an old NT password */
165 io
->g
.nt_history
= talloc_array(io
->ac
,
166 struct samr_Password
,
167 io
->domain
->pwdHistoryLength
);
168 if (!io
->g
.nt_history
) {
169 ldb_oom(io
->ac
->module
->ldb
);
170 return LDB_ERR_OPERATIONS_ERROR
;
173 for (i
= 0; i
< MIN(io
->domain
->pwdHistoryLength
-1, io
->o
.nt_history_len
); i
++) {
174 io
->g
.nt_history
[i
+1] = io
->o
.nt_history
[i
];
176 io
->g
.nt_history_len
= i
+ 1;
179 io
->g
.nt_history
[0] = *io
->g
.nt_hash
;
182 * TODO: is this correct?
183 * the simular behavior is correct for the lm history case
185 E_md4hash("", io
->g
.nt_history
[0].hash
);
191 static int setup_lm_fields(struct setup_password_fields_io
*io
)
195 io
->g
.lm_hash
= io
->n
.lm_hash
;
197 if (io
->domain
->pwdHistoryLength
== 0) {
201 /* We might not have an old NT password */
202 io
->g
.lm_history
= talloc_array(io
->ac
,
203 struct samr_Password
,
204 io
->domain
->pwdHistoryLength
);
205 if (!io
->g
.lm_history
) {
206 ldb_oom(io
->ac
->module
->ldb
);
207 return LDB_ERR_OPERATIONS_ERROR
;
210 for (i
= 0; i
< MIN(io
->domain
->pwdHistoryLength
-1, io
->o
.lm_history_len
); i
++) {
211 io
->g
.lm_history
[i
+1] = io
->o
.lm_history
[i
];
213 io
->g
.lm_history_len
= i
+ 1;
216 io
->g
.lm_history
[0] = *io
->g
.lm_hash
;
218 E_deshash("", io
->g
.lm_history
[0].hash
);
224 static int setup_kerberos_keys(struct setup_password_fields_io
*io
)
226 krb5_error_code krb5_ret
;
227 Principal
*salt_principal
;
231 /* Many, many thanks to lukeh@padl.com for this
232 * algorithm, described in his Nov 10 2004 mail to
233 * samba-technical@samba.org */
236 * Determine a salting principal
238 if (io
->u
.is_computer
) {
242 name
= talloc_strdup(io
->ac
, io
->u
.sAMAccountName
);
244 ldb_oom(io
->ac
->module
->ldb
);
245 return LDB_ERR_OPERATIONS_ERROR
;
248 if (name
[strlen(name
)-1] == '$') {
249 name
[strlen(name
)-1] = '\0';
252 saltbody
= talloc_asprintf(io
->ac
, "%s.%s", name
, io
->domain
->dns_domain
);
254 ldb_oom(io
->ac
->module
->ldb
);
255 return LDB_ERR_OPERATIONS_ERROR
;
258 krb5_ret
= krb5_make_principal(io
->smb_krb5_context
->krb5_context
,
260 io
->domain
->realm
, "host",
262 } else if (io
->u
.user_principal_name
) {
263 char *user_principal_name
;
266 user_principal_name
= talloc_strdup(io
->ac
, io
->u
.user_principal_name
);
267 if (!user_principal_name
) {
268 ldb_oom(io
->ac
->module
->ldb
);
269 return LDB_ERR_OPERATIONS_ERROR
;
272 p
= strchr(user_principal_name
, '@');
277 krb5_ret
= krb5_make_principal(io
->smb_krb5_context
->krb5_context
,
279 io
->domain
->realm
, user_principal_name
,
282 krb5_ret
= krb5_make_principal(io
->smb_krb5_context
->krb5_context
,
284 io
->domain
->realm
, io
->u
.sAMAccountName
,
288 ldb_asprintf_errstring(io
->ac
->module
->ldb
,
289 "setup_kerberos_keys: "
290 "generation of a salting principal failed: %s",
291 smb_get_krb5_error_message(io
->smb_krb5_context
->krb5_context
, krb5_ret
, io
->ac
));
292 return LDB_ERR_OPERATIONS_ERROR
;
296 * create salt from salt_principal
298 krb5_ret
= krb5_get_pw_salt(io
->smb_krb5_context
->krb5_context
,
299 salt_principal
, &salt
);
300 krb5_free_principal(io
->smb_krb5_context
->krb5_context
, salt_principal
);
302 ldb_asprintf_errstring(io
->ac
->module
->ldb
,
303 "setup_kerberos_keys: "
304 "generation of krb5_salt failed: %s",
305 smb_get_krb5_error_message(io
->smb_krb5_context
->krb5_context
, krb5_ret
, io
->ac
));
306 return LDB_ERR_OPERATIONS_ERROR
;
308 /* create a talloc copy */
309 io
->g
.salt
= talloc_strndup(io
->ac
,
311 salt
.saltvalue
.length
);
312 krb5_free_salt(io
->smb_krb5_context
->krb5_context
, salt
);
314 ldb_oom(io
->ac
->module
->ldb
);
315 return LDB_ERR_OPERATIONS_ERROR
;
317 salt
.saltvalue
.data
= discard_const(io
->g
.salt
);
318 salt
.saltvalue
.length
= strlen(io
->g
.salt
);
321 * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of
322 * the salt and the cleartext password
324 krb5_ret
= krb5_string_to_key_salt(io
->smb_krb5_context
->krb5_context
,
325 ENCTYPE_AES256_CTS_HMAC_SHA1_96
,
330 ldb_asprintf_errstring(io
->ac
->module
->ldb
,
331 "setup_kerberos_keys: "
332 "generation of a aes256-cts-hmac-sha1-96 key failed: %s",
333 smb_get_krb5_error_message(io
->smb_krb5_context
->krb5_context
, krb5_ret
, io
->ac
));
334 return LDB_ERR_OPERATIONS_ERROR
;
336 io
->g
.aes_256
= data_blob_talloc(io
->ac
,
338 key
.keyvalue
.length
);
339 krb5_free_keyblock_contents(io
->smb_krb5_context
->krb5_context
, &key
);
340 if (!io
->g
.aes_256
.data
) {
341 ldb_oom(io
->ac
->module
->ldb
);
342 return LDB_ERR_OPERATIONS_ERROR
;
346 * create ENCTYPE_AES128_CTS_HMAC_SHA1_96 key out of
347 * the salt and the cleartext password
349 krb5_ret
= krb5_string_to_key_salt(io
->smb_krb5_context
->krb5_context
,
350 ENCTYPE_AES128_CTS_HMAC_SHA1_96
,
355 ldb_asprintf_errstring(io
->ac
->module
->ldb
,
356 "setup_kerberos_keys: "
357 "generation of a aes128-cts-hmac-sha1-96 key failed: %s",
358 smb_get_krb5_error_message(io
->smb_krb5_context
->krb5_context
, krb5_ret
, io
->ac
));
359 return LDB_ERR_OPERATIONS_ERROR
;
361 io
->g
.aes_128
= data_blob_talloc(io
->ac
,
363 key
.keyvalue
.length
);
364 krb5_free_keyblock_contents(io
->smb_krb5_context
->krb5_context
, &key
);
365 if (!io
->g
.aes_128
.data
) {
366 ldb_oom(io
->ac
->module
->ldb
);
367 return LDB_ERR_OPERATIONS_ERROR
;
371 * create ENCTYPE_DES_CBC_MD5 key out of
372 * the salt and the cleartext password
374 krb5_ret
= krb5_string_to_key_salt(io
->smb_krb5_context
->krb5_context
,
380 ldb_asprintf_errstring(io
->ac
->module
->ldb
,
381 "setup_kerberos_keys: "
382 "generation of a des-cbc-md5 key failed: %s",
383 smb_get_krb5_error_message(io
->smb_krb5_context
->krb5_context
, krb5_ret
, io
->ac
));
384 return LDB_ERR_OPERATIONS_ERROR
;
386 io
->g
.des_md5
= data_blob_talloc(io
->ac
,
388 key
.keyvalue
.length
);
389 krb5_free_keyblock_contents(io
->smb_krb5_context
->krb5_context
, &key
);
390 if (!io
->g
.des_md5
.data
) {
391 ldb_oom(io
->ac
->module
->ldb
);
392 return LDB_ERR_OPERATIONS_ERROR
;
396 * create ENCTYPE_DES_CBC_CRC key out of
397 * the salt and the cleartext password
399 krb5_ret
= krb5_string_to_key_salt(io
->smb_krb5_context
->krb5_context
,
405 ldb_asprintf_errstring(io
->ac
->module
->ldb
,
406 "setup_kerberos_keys: "
407 "generation of a des-cbc-crc key failed: %s",
408 smb_get_krb5_error_message(io
->smb_krb5_context
->krb5_context
, krb5_ret
, io
->ac
));
409 return LDB_ERR_OPERATIONS_ERROR
;
411 io
->g
.des_crc
= data_blob_talloc(io
->ac
,
413 key
.keyvalue
.length
);
414 krb5_free_keyblock_contents(io
->smb_krb5_context
->krb5_context
, &key
);
415 if (!io
->g
.des_crc
.data
) {
416 ldb_oom(io
->ac
->module
->ldb
);
417 return LDB_ERR_OPERATIONS_ERROR
;
423 static int setup_primary_kerberos(struct setup_password_fields_io
*io
,
424 const struct supplementalCredentialsBlob
*old_scb
,
425 struct package_PrimaryKerberosBlob
*pkb
)
427 struct package_PrimaryKerberosCtr3
*pkb3
= &pkb
->ctr
.ctr3
;
428 struct supplementalCredentialsPackage
*old_scp
= NULL
;
429 struct package_PrimaryKerberosBlob _old_pkb
;
430 struct package_PrimaryKerberosCtr3
*old_pkb3
= NULL
;
432 enum ndr_err_code ndr_err
;
435 * prepare generation of keys
437 * ENCTYPE_DES_CBC_MD5
438 * ENCTYPE_DES_CBC_CRC
441 pkb3
->salt
.string
= io
->g
.salt
;
443 pkb3
->keys
= talloc_array(io
->ac
,
444 struct package_PrimaryKerberosKey3
,
447 ldb_oom(io
->ac
->module
->ldb
);
448 return LDB_ERR_OPERATIONS_ERROR
;
451 pkb3
->keys
[0].keytype
= ENCTYPE_DES_CBC_MD5
;
452 pkb3
->keys
[0].value
= &io
->g
.des_md5
;
453 pkb3
->keys
[1].keytype
= ENCTYPE_DES_CBC_CRC
;
454 pkb3
->keys
[1].value
= &io
->g
.des_crc
;
456 /* initialize the old keys to zero */
457 pkb3
->num_old_keys
= 0;
458 pkb3
->old_keys
= NULL
;
460 /* if there're no old keys, then we're done */
465 for (i
=0; i
< old_scb
->sub
.num_packages
; i
++) {
466 if (strcmp("Primary:Kerberos", old_scb
->sub
.packages
[i
].name
) != 0) {
470 if (!old_scb
->sub
.packages
[i
].data
|| !old_scb
->sub
.packages
[i
].data
[0]) {
474 old_scp
= &old_scb
->sub
.packages
[i
];
477 /* Primary:Kerberos element of supplementalCredentials */
481 blob
= strhex_to_data_blob(old_scp
->data
);
483 ldb_oom(io
->ac
->module
->ldb
);
484 return LDB_ERR_OPERATIONS_ERROR
;
486 talloc_steal(io
->ac
, blob
.data
);
488 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
489 ndr_err
= ndr_pull_struct_blob(&blob
, io
->ac
, lp_iconv_convenience(ldb_get_opaque(io
->ac
->module
->ldb
, "loadparm")), &_old_pkb
,
490 (ndr_pull_flags_fn_t
)ndr_pull_package_PrimaryKerberosBlob
);
491 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
492 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
493 ldb_asprintf_errstring(io
->ac
->module
->ldb
,
494 "setup_primary_kerberos: "
495 "failed to pull old package_PrimaryKerberosBlob: %s",
497 return LDB_ERR_OPERATIONS_ERROR
;
500 if (_old_pkb
.version
!= 3) {
501 ldb_asprintf_errstring(io
->ac
->module
->ldb
,
502 "setup_primary_kerberos: "
503 "package_PrimaryKerberosBlob version[%u] expected[3]",
505 return LDB_ERR_OPERATIONS_ERROR
;
508 old_pkb3
= &_old_pkb
.ctr
.ctr3
;
511 /* if we didn't found the old keys we're done */
516 /* fill in the old keys */
517 pkb3
->num_old_keys
= old_pkb3
->num_keys
;
518 pkb3
->old_keys
= old_pkb3
->keys
;
523 static int setup_primary_kerberos_newer(struct setup_password_fields_io
*io
,
524 const struct supplementalCredentialsBlob
*old_scb
,
525 struct package_PrimaryKerberosBlob
*pkb
)
527 struct package_PrimaryKerberosCtr4
*pkb4
= &pkb
->ctr
.ctr4
;
528 struct supplementalCredentialsPackage
*old_scp
= NULL
;
529 struct package_PrimaryKerberosBlob _old_pkb
;
530 struct package_PrimaryKerberosCtr4
*old_pkb4
= NULL
;
532 enum ndr_err_code ndr_err
;
535 * prepare generation of keys
537 * ENCTYPE_AES256_CTS_HMAC_SHA1_96
538 * ENCTYPE_AES128_CTS_HMAC_SHA1_96
539 * ENCTYPE_DES_CBC_MD5
540 * ENCTYPE_DES_CBC_CRC
543 pkb4
->salt
.string
= io
->g
.salt
;
544 pkb4
->default_iteration_count
= 4096;
547 pkb4
->keys
= talloc_array(io
->ac
,
548 struct package_PrimaryKerberosKey4
,
551 ldb_oom(io
->ac
->module
->ldb
);
552 return LDB_ERR_OPERATIONS_ERROR
;
555 pkb4
->keys
[0].iteration_count
= 4096;
556 pkb4
->keys
[0].keytype
= ENCTYPE_AES256_CTS_HMAC_SHA1_96
;
557 pkb4
->keys
[0].value
= &io
->g
.aes_256
;
558 pkb4
->keys
[1].iteration_count
= 4096;
559 pkb4
->keys
[1].keytype
= ENCTYPE_AES128_CTS_HMAC_SHA1_96
;
560 pkb4
->keys
[1].value
= &io
->g
.aes_128
;
561 pkb4
->keys
[2].iteration_count
= 4096;
562 pkb4
->keys
[2].keytype
= ENCTYPE_DES_CBC_MD5
;
563 pkb4
->keys
[2].value
= &io
->g
.des_md5
;
564 pkb4
->keys
[3].iteration_count
= 4096;
565 pkb4
->keys
[3].keytype
= ENCTYPE_DES_CBC_CRC
;
566 pkb4
->keys
[3].value
= &io
->g
.des_crc
;
568 /* initialize the old keys to zero */
569 pkb4
->num_old_keys
= 0;
570 pkb4
->old_keys
= NULL
;
571 pkb4
->num_older_keys
= 0;
572 pkb4
->older_keys
= NULL
;
574 /* if there're no old keys, then we're done */
579 for (i
=0; i
< old_scb
->sub
.num_packages
; i
++) {
580 if (strcmp("Primary:Kerberos-Newer-Keys", old_scb
->sub
.packages
[i
].name
) != 0) {
584 if (!old_scb
->sub
.packages
[i
].data
|| !old_scb
->sub
.packages
[i
].data
[0]) {
588 old_scp
= &old_scb
->sub
.packages
[i
];
591 /* Primary:Kerberos-Newer-Keys element of supplementalCredentials */
595 blob
= strhex_to_data_blob(old_scp
->data
);
597 ldb_oom(io
->ac
->module
->ldb
);
598 return LDB_ERR_OPERATIONS_ERROR
;
600 talloc_steal(io
->ac
, blob
.data
);
602 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
603 ndr_err
= ndr_pull_struct_blob(&blob
, io
->ac
,
604 lp_iconv_convenience(ldb_get_opaque(io
->ac
->module
->ldb
, "loadparm")),
606 (ndr_pull_flags_fn_t
)ndr_pull_package_PrimaryKerberosBlob
);
607 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
608 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
609 ldb_asprintf_errstring(io
->ac
->module
->ldb
,
610 "setup_primary_kerberos_newer: "
611 "failed to pull old package_PrimaryKerberosBlob: %s",
613 return LDB_ERR_OPERATIONS_ERROR
;
616 if (_old_pkb
.version
!= 4) {
617 ldb_asprintf_errstring(io
->ac
->module
->ldb
,
618 "setup_primary_kerberos_newer: "
619 "package_PrimaryKerberosBlob version[%u] expected[4]",
621 return LDB_ERR_OPERATIONS_ERROR
;
624 old_pkb4
= &_old_pkb
.ctr
.ctr4
;
627 /* if we didn't found the old keys we're done */
632 /* fill in the old keys */
633 pkb4
->num_old_keys
= old_pkb4
->num_keys
;
634 pkb4
->old_keys
= old_pkb4
->keys
;
635 pkb4
->num_older_keys
= old_pkb4
->num_old_keys
;
636 pkb4
->older_keys
= old_pkb4
->old_keys
;
641 static int setup_primary_wdigest(struct setup_password_fields_io
*io
,
642 const struct supplementalCredentialsBlob
*old_scb
,
643 struct package_PrimaryWDigestBlob
*pdb
)
645 DATA_BLOB sAMAccountName
;
646 DATA_BLOB sAMAccountName_l
;
647 DATA_BLOB sAMAccountName_u
;
648 const char *user_principal_name
= io
->u
.user_principal_name
;
649 DATA_BLOB userPrincipalName
;
650 DATA_BLOB userPrincipalName_l
;
651 DATA_BLOB userPrincipalName_u
;
652 DATA_BLOB netbios_domain
;
653 DATA_BLOB netbios_domain_l
;
654 DATA_BLOB netbios_domain_u
;
655 DATA_BLOB dns_domain
;
656 DATA_BLOB dns_domain_l
;
657 DATA_BLOB dns_domain_u
;
670 * http://technet2.microsoft.com/WindowsServer/en/library/717b450c-f4a0-4cc9-86f4-cc0633aae5f91033.mspx?mfr=true
671 * for what precalculated hashes are supposed to be stored...
673 * I can't reproduce all values which should contain "Digest" as realm,
674 * am I doing something wrong or is w2k3 just broken...?
676 * W2K3 fills in following for a user:
678 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
679 * sAMAccountName: NewUser2Sam
680 * userPrincipalName: NewUser2Princ@sub1.w2k3.vmnet1.vm.base
682 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
683 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
684 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
685 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
686 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
687 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
688 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
689 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
690 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
691 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
692 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
693 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
694 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
695 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
696 * 221c55284451ae9b3aacaa2a3c86f10f => NewUser2Princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
697 * 74e1be668853d4324d38c07e2acfb8ea => (w2k3 has a bug here!) newuser2princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
698 * e1e244ab7f098e3ae1761be7f9229bbb => NEWUSER2PRINC@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
699 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
700 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
701 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
702 * 31dc704d3640335b2123d4ee28aa1f11 => ??? changes with NewUser2Sam => NewUser1Sam
703 * 36349f5cecd07320fb3bb0e119230c43 => ??? changes with NewUser2Sam => NewUser1Sam
704 * 12adf019d037fb535c01fd0608e78d9d => ??? changes with NewUser2Sam => NewUser1Sam
705 * 6feecf8e724906f3ee1105819c5105a1 => ??? changes with NewUser2Princ => NewUser1Princ
706 * 6c6911f3de6333422640221b9c51ff1f => ??? changes with NewUser2Princ => NewUser1Princ
707 * 4b279877e742895f9348ac67a8de2f69 => ??? changes with NewUser2Princ => NewUser1Princ
708 * db0c6bff069513e3ebb9870d29b57490 => ??? changes with NewUser2Sam => NewUser1Sam
709 * 45072621e56b1c113a4e04a8ff68cd0e => ??? changes with NewUser2Sam => NewUser1Sam
710 * 11d1220abc44a9c10cf91ef4a9c1de02 => ??? changes with NewUser2Sam => NewUser1Sam
712 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
713 * sAMAccountName: NewUser2Sam
715 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
716 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
717 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
718 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
719 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
720 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
721 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
722 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
723 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
724 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
725 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
726 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
727 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
728 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
729 * 8a140d30b6f0a5912735dc1e3bc993b4 => NewUser2Sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
730 * 86d95b2faae6cae4ec261e7fbaccf093 => (here w2k3 is correct) newuser2sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
731 * dfeff1493110220efcdfc6362e5f5450 => NEWUSER2SAM@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
732 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
733 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
734 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
735 * 31dc704d3640335b2123d4ee28aa1f11 => ???M1 changes with NewUser2Sam => NewUser1Sam
736 * 36349f5cecd07320fb3bb0e119230c43 => ???M1.L changes with newuser2sam => newuser1sam
737 * 12adf019d037fb535c01fd0608e78d9d => ???M1.U changes with NEWUSER2SAM => NEWUSER1SAM
738 * 569b4533f2d9e580211dd040e5e360a8 => ???M2 changes with NewUser2Princ => NewUser1Princ
739 * 52528bddf310a587c5d7e6a9ae2cbb20 => ???M2.L changes with newuser2princ => newuser1princ
740 * 4f629a4f0361289ca4255ab0f658fcd5 => ???M3 changes with NewUser2Princ => NewUser1Princ (doesn't depend on case of userPrincipal )
741 * db0c6bff069513e3ebb9870d29b57490 => ???M4 changes with NewUser2Sam => NewUser1Sam
742 * 45072621e56b1c113a4e04a8ff68cd0e => ???M5 changes with NewUser2Sam => NewUser1Sam (doesn't depend on case of sAMAccountName)
743 * 11d1220abc44a9c10cf91ef4a9c1de02 => ???M4.U changes with NEWUSER2SAM => NEWUSER1SAM
747 * sAMAccountName, netbios_domain
750 .user
= &sAMAccountName
,
751 .realm
= &netbios_domain
,
754 .user
= &sAMAccountName_l
,
755 .realm
= &netbios_domain_l
,
758 .user
= &sAMAccountName_u
,
759 .realm
= &netbios_domain_u
,
762 .user
= &sAMAccountName
,
763 .realm
= &netbios_domain_u
,
766 .user
= &sAMAccountName
,
767 .realm
= &netbios_domain_l
,
770 .user
= &sAMAccountName_u
,
771 .realm
= &netbios_domain_l
,
774 .user
= &sAMAccountName_l
,
775 .realm
= &netbios_domain_u
,
778 * sAMAccountName, dns_domain
781 .user
= &sAMAccountName
,
782 .realm
= &dns_domain
,
785 .user
= &sAMAccountName_l
,
786 .realm
= &dns_domain_l
,
789 .user
= &sAMAccountName_u
,
790 .realm
= &dns_domain_u
,
793 .user
= &sAMAccountName
,
794 .realm
= &dns_domain_u
,
797 .user
= &sAMAccountName
,
798 .realm
= &dns_domain_l
,
801 .user
= &sAMAccountName_u
,
802 .realm
= &dns_domain_l
,
805 .user
= &sAMAccountName_l
,
806 .realm
= &dns_domain_u
,
809 * userPrincipalName, no realm
812 .user
= &userPrincipalName
,
816 * NOTE: w2k3 messes this up, if the user has a real userPrincipalName,
817 * the fallback to the sAMAccountName based userPrincipalName is correct
819 .user
= &userPrincipalName_l
,
822 .user
= &userPrincipalName_u
,
825 * nt4dom\sAMAccountName, no realm
828 .user
= &sAMAccountName
,
829 .nt4dom
= &netbios_domain
832 .user
= &sAMAccountName_l
,
833 .nt4dom
= &netbios_domain_l
836 .user
= &sAMAccountName_u
,
837 .nt4dom
= &netbios_domain_u
841 * the following ones are guessed depending on the technet2 article
842 * but not reproducable on a w2k3 server
844 /* sAMAccountName with "Digest" realm */
846 .user
= &sAMAccountName
,
850 .user
= &sAMAccountName_l
,
854 .user
= &sAMAccountName_u
,
857 /* userPrincipalName with "Digest" realm */
859 .user
= &userPrincipalName
,
863 .user
= &userPrincipalName_l
,
867 .user
= &userPrincipalName_u
,
870 /* nt4dom\\sAMAccountName with "Digest" realm */
872 .user
= &sAMAccountName
,
873 .nt4dom
= &netbios_domain
,
877 .user
= &sAMAccountName_l
,
878 .nt4dom
= &netbios_domain_l
,
882 .user
= &sAMAccountName_u
,
883 .nt4dom
= &netbios_domain_u
,
888 /* prepare DATA_BLOB's used in the combinations array */
889 sAMAccountName
= data_blob_string_const(io
->u
.sAMAccountName
);
890 sAMAccountName_l
= data_blob_string_const(strlower_talloc(io
->ac
, io
->u
.sAMAccountName
));
891 if (!sAMAccountName_l
.data
) {
892 ldb_oom(io
->ac
->module
->ldb
);
893 return LDB_ERR_OPERATIONS_ERROR
;
895 sAMAccountName_u
= data_blob_string_const(strupper_talloc(io
->ac
, io
->u
.sAMAccountName
));
896 if (!sAMAccountName_u
.data
) {
897 ldb_oom(io
->ac
->module
->ldb
);
898 return LDB_ERR_OPERATIONS_ERROR
;
901 /* if the user doesn't have a userPrincipalName, create one (with lower case realm) */
902 if (!user_principal_name
) {
903 user_principal_name
= talloc_asprintf(io
->ac
, "%s@%s",
904 io
->u
.sAMAccountName
,
905 io
->domain
->dns_domain
);
906 if (!user_principal_name
) {
907 ldb_oom(io
->ac
->module
->ldb
);
908 return LDB_ERR_OPERATIONS_ERROR
;
911 userPrincipalName
= data_blob_string_const(user_principal_name
);
912 userPrincipalName_l
= data_blob_string_const(strlower_talloc(io
->ac
, user_principal_name
));
913 if (!userPrincipalName_l
.data
) {
914 ldb_oom(io
->ac
->module
->ldb
);
915 return LDB_ERR_OPERATIONS_ERROR
;
917 userPrincipalName_u
= data_blob_string_const(strupper_talloc(io
->ac
, user_principal_name
));
918 if (!userPrincipalName_u
.data
) {
919 ldb_oom(io
->ac
->module
->ldb
);
920 return LDB_ERR_OPERATIONS_ERROR
;
923 netbios_domain
= data_blob_string_const(io
->domain
->netbios_domain
);
924 netbios_domain_l
= data_blob_string_const(strlower_talloc(io
->ac
, io
->domain
->netbios_domain
));
925 if (!netbios_domain_l
.data
) {
926 ldb_oom(io
->ac
->module
->ldb
);
927 return LDB_ERR_OPERATIONS_ERROR
;
929 netbios_domain_u
= data_blob_string_const(strupper_talloc(io
->ac
, io
->domain
->netbios_domain
));
930 if (!netbios_domain_u
.data
) {
931 ldb_oom(io
->ac
->module
->ldb
);
932 return LDB_ERR_OPERATIONS_ERROR
;
935 dns_domain
= data_blob_string_const(io
->domain
->dns_domain
);
936 dns_domain_l
= data_blob_string_const(io
->domain
->dns_domain
);
937 dns_domain_u
= data_blob_string_const(io
->domain
->realm
);
939 cleartext
= data_blob_string_const(io
->n
.cleartext
);
941 digest
= data_blob_string_const("Digest");
943 delim
= data_blob_string_const(":");
944 backslash
= data_blob_string_const("\\");
946 pdb
->num_hashes
= ARRAY_SIZE(wdigest
);
947 pdb
->hashes
= talloc_array(io
->ac
, struct package_PrimaryWDigestHash
, pdb
->num_hashes
);
949 ldb_oom(io
->ac
->module
->ldb
);
950 return LDB_ERR_OPERATIONS_ERROR
;
953 for (i
=0; i
< ARRAY_SIZE(wdigest
); i
++) {
954 struct MD5Context md5
;
956 if (wdigest
[i
].nt4dom
) {
957 MD5Update(&md5
, wdigest
[i
].nt4dom
->data
, wdigest
[i
].nt4dom
->length
);
958 MD5Update(&md5
, backslash
.data
, backslash
.length
);
960 MD5Update(&md5
, wdigest
[i
].user
->data
, wdigest
[i
].user
->length
);
961 MD5Update(&md5
, delim
.data
, delim
.length
);
962 if (wdigest
[i
].realm
) {
963 MD5Update(&md5
, wdigest
[i
].realm
->data
, wdigest
[i
].realm
->length
);
965 MD5Update(&md5
, delim
.data
, delim
.length
);
966 MD5Update(&md5
, cleartext
.data
, cleartext
.length
);
967 MD5Final(pdb
->hashes
[i
].hash
, &md5
);
973 static int setup_supplemental_field(struct setup_password_fields_io
*io
)
975 struct supplementalCredentialsBlob scb
;
976 struct supplementalCredentialsBlob _old_scb
;
977 struct supplementalCredentialsBlob
*old_scb
= NULL
;
978 /* Packages + (Kerberos-Newer-Keys, Kerberos, WDigest and CLEARTEXT) */
979 uint32_t num_names
= 0;
980 const char *names
[1+4];
981 uint32_t num_packages
= 0;
982 struct supplementalCredentialsPackage packages
[1+4];
984 struct supplementalCredentialsPackage
*pp
= NULL
;
985 struct package_PackagesBlob pb
;
988 /* Primary:Kerberos-Newer-Keys */
989 const char **nkn
= NULL
;
990 struct supplementalCredentialsPackage
*pkn
= NULL
;
991 struct package_PrimaryKerberosBlob pknb
;
994 /* Primary:Kerberos */
995 const char **nk
= NULL
;
996 struct supplementalCredentialsPackage
*pk
= NULL
;
997 struct package_PrimaryKerberosBlob pkb
;
1000 /* Primary:WDigest */
1001 const char **nd
= NULL
;
1002 struct supplementalCredentialsPackage
*pd
= NULL
;
1003 struct package_PrimaryWDigestBlob pdb
;
1006 /* Primary:CLEARTEXT */
1007 const char **nc
= NULL
;
1008 struct supplementalCredentialsPackage
*pc
= NULL
;
1009 struct package_PrimaryCLEARTEXTBlob pcb
;
1013 enum ndr_err_code ndr_err
;
1015 bool do_newer_keys
= false;
1016 bool do_cleartext
= false;
1018 ZERO_STRUCT(zero16
);
1021 if (!io
->n
.cleartext
) {
1023 * when we don't have a cleartext password
1024 * we can't setup a supplementalCredential value
1029 /* if there's an old supplementaCredentials blob then parse it */
1030 if (io
->o
.supplemental
) {
1031 ndr_err
= ndr_pull_struct_blob_all(io
->o
.supplemental
, io
->ac
,
1032 lp_iconv_convenience(ldb_get_opaque(io
->ac
->module
->ldb
, "loadparm")),
1034 (ndr_pull_flags_fn_t
)ndr_pull_supplementalCredentialsBlob
);
1035 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1036 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1037 ldb_asprintf_errstring(io
->ac
->module
->ldb
,
1038 "setup_supplemental_field: "
1039 "failed to pull old supplementalCredentialsBlob: %s",
1041 return LDB_ERR_OPERATIONS_ERROR
;
1044 if (_old_scb
.sub
.signature
== SUPPLEMENTAL_CREDENTIALS_SIGNATURE
) {
1045 old_scb
= &_old_scb
;
1047 ldb_debug(io
->ac
->module
->ldb
, LDB_DEBUG_ERROR
,
1048 "setup_supplemental_field: "
1049 "supplementalCredentialsBlob signature[0x%04X] expected[0x%04X]",
1050 _old_scb
.sub
.signature
, SUPPLEMENTAL_CREDENTIALS_SIGNATURE
);
1054 /* TODO: do the correct check for this, it maybe depends on the functional level? */
1055 do_newer_keys
= lp_parm_bool(ldb_get_opaque(io
->ac
->module
->ldb
, "loadparm"),
1056 NULL
, "password_hash", "create_aes_key", false);
1058 if (io
->domain
->store_cleartext
&&
1059 (io
->u
.user_account_control
& UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED
)) {
1060 do_cleartext
= true;
1064 * The ordering is this
1066 * Primary:Kerberos-Newer-Keys (optional)
1069 * Primary:CLEARTEXT (optional)
1071 * And the 'Packages' package is insert before the last
1074 if (do_newer_keys
) {
1075 /* Primary:Kerberos-Newer-Keys */
1076 nkn
= &names
[num_names
++];
1077 pkn
= &packages
[num_packages
++];
1080 /* Primary:Kerberos */
1081 nk
= &names
[num_names
++];
1082 pk
= &packages
[num_packages
++];
1084 if (!do_cleartext
) {
1086 pp
= &packages
[num_packages
++];
1089 /* Primary:WDigest */
1090 nd
= &names
[num_names
++];
1091 pd
= &packages
[num_packages
++];
1095 pp
= &packages
[num_packages
++];
1097 /* Primary:CLEARTEXT */
1098 nc
= &names
[num_names
++];
1099 pc
= &packages
[num_packages
++];
1104 * setup 'Primary:Kerberos-Newer-Keys' element
1106 *nkn
= "Kerberos-Newer-Keys";
1108 ret
= setup_primary_kerberos_newer(io
, old_scb
, &pknb
);
1109 if (ret
!= LDB_SUCCESS
) {
1113 ndr_err
= ndr_push_struct_blob(&pknb_blob
, io
->ac
,
1114 lp_iconv_convenience(ldb_get_opaque(io
->ac
->module
->ldb
, "loadparm")),
1116 (ndr_push_flags_fn_t
)ndr_push_package_PrimaryKerberosBlob
);
1117 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1118 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1119 ldb_asprintf_errstring(io
->ac
->module
->ldb
,
1120 "setup_supplemental_field: "
1121 "failed to push package_PrimaryKerberosNeverBlob: %s",
1123 return LDB_ERR_OPERATIONS_ERROR
;
1125 pknb_hexstr
= data_blob_hex_string(io
->ac
, &pknb_blob
);
1127 ldb_oom(io
->ac
->module
->ldb
);
1128 return LDB_ERR_OPERATIONS_ERROR
;
1130 pkn
->name
= "Primary:Kerberos-Newer-Keys";
1132 pkn
->data
= pknb_hexstr
;
1136 * setup 'Primary:Kerberos' element
1140 ret
= setup_primary_kerberos(io
, old_scb
, &pkb
);
1141 if (ret
!= LDB_SUCCESS
) {
1145 ndr_err
= ndr_push_struct_blob(&pkb_blob
, io
->ac
,
1146 lp_iconv_convenience(ldb_get_opaque(io
->ac
->module
->ldb
, "loadparm")),
1148 (ndr_push_flags_fn_t
)ndr_push_package_PrimaryKerberosBlob
);
1149 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1150 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1151 ldb_asprintf_errstring(io
->ac
->module
->ldb
,
1152 "setup_supplemental_field: "
1153 "failed to push package_PrimaryKerberosBlob: %s",
1155 return LDB_ERR_OPERATIONS_ERROR
;
1157 pkb_hexstr
= data_blob_hex_string(io
->ac
, &pkb_blob
);
1159 ldb_oom(io
->ac
->module
->ldb
);
1160 return LDB_ERR_OPERATIONS_ERROR
;
1162 pk
->name
= "Primary:Kerberos";
1164 pk
->data
= pkb_hexstr
;
1167 * setup 'Primary:WDigest' element
1171 ret
= setup_primary_wdigest(io
, old_scb
, &pdb
);
1172 if (ret
!= LDB_SUCCESS
) {
1176 ndr_err
= ndr_push_struct_blob(&pdb_blob
, io
->ac
,
1177 lp_iconv_convenience(ldb_get_opaque(io
->ac
->module
->ldb
, "loadparm")),
1179 (ndr_push_flags_fn_t
)ndr_push_package_PrimaryWDigestBlob
);
1180 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1181 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1182 ldb_asprintf_errstring(io
->ac
->module
->ldb
,
1183 "setup_supplemental_field: "
1184 "failed to push package_PrimaryWDigestBlob: %s",
1186 return LDB_ERR_OPERATIONS_ERROR
;
1188 pdb_hexstr
= data_blob_hex_string(io
->ac
, &pdb_blob
);
1190 ldb_oom(io
->ac
->module
->ldb
);
1191 return LDB_ERR_OPERATIONS_ERROR
;
1193 pd
->name
= "Primary:WDigest";
1195 pd
->data
= pdb_hexstr
;
1198 * setup 'Primary:CLEARTEXT' element
1203 pcb
.cleartext
= io
->n
.cleartext
;
1205 ndr_err
= ndr_push_struct_blob(&pcb_blob
, io
->ac
,
1206 lp_iconv_convenience(ldb_get_opaque(io
->ac
->module
->ldb
, "loadparm")),
1208 (ndr_push_flags_fn_t
)ndr_push_package_PrimaryCLEARTEXTBlob
);
1209 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1210 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1211 ldb_asprintf_errstring(io
->ac
->module
->ldb
,
1212 "setup_supplemental_field: "
1213 "failed to push package_PrimaryCLEARTEXTBlob: %s",
1215 return LDB_ERR_OPERATIONS_ERROR
;
1217 pcb_hexstr
= data_blob_hex_string(io
->ac
, &pcb_blob
);
1219 ldb_oom(io
->ac
->module
->ldb
);
1220 return LDB_ERR_OPERATIONS_ERROR
;
1222 pc
->name
= "Primary:CLEARTEXT";
1224 pc
->data
= pcb_hexstr
;
1228 * setup 'Packages' element
1231 ndr_err
= ndr_push_struct_blob(&pb_blob
, io
->ac
,
1232 lp_iconv_convenience(ldb_get_opaque(io
->ac
->module
->ldb
, "loadparm")),
1234 (ndr_push_flags_fn_t
)ndr_push_package_PackagesBlob
);
1235 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1236 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1237 ldb_asprintf_errstring(io
->ac
->module
->ldb
,
1238 "setup_supplemental_field: "
1239 "failed to push package_PackagesBlob: %s",
1241 return LDB_ERR_OPERATIONS_ERROR
;
1243 pb_hexstr
= data_blob_hex_string(io
->ac
, &pb_blob
);
1245 ldb_oom(io
->ac
->module
->ldb
);
1246 return LDB_ERR_OPERATIONS_ERROR
;
1248 pp
->name
= "Packages";
1250 pp
->data
= pb_hexstr
;
1253 * setup 'supplementalCredentials' value
1256 scb
.sub
.num_packages
= num_packages
;
1257 scb
.sub
.packages
= packages
;
1259 ndr_err
= ndr_push_struct_blob(&io
->g
.supplemental
, io
->ac
,
1260 lp_iconv_convenience(ldb_get_opaque(io
->ac
->module
->ldb
, "loadparm")),
1262 (ndr_push_flags_fn_t
)ndr_push_supplementalCredentialsBlob
);
1263 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1264 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1265 ldb_asprintf_errstring(io
->ac
->module
->ldb
,
1266 "setup_supplemental_field: "
1267 "failed to push supplementalCredentialsBlob: %s",
1269 return LDB_ERR_OPERATIONS_ERROR
;
1275 static int setup_last_set_field(struct setup_password_fields_io
*io
)
1278 unix_to_nt_time(&io
->g
.last_set
, time(NULL
));
1283 static int setup_kvno_field(struct setup_password_fields_io
*io
)
1285 /* increment by one */
1286 io
->g
.kvno
= io
->o
.kvno
+ 1;
1291 static int setup_password_fields(struct setup_password_fields_io
*io
)
1297 * refuse the change if someone want to change the cleartext
1298 * and supply his own hashes at the same time...
1300 if (io
->n
.cleartext
&& (io
->n
.nt_hash
|| io
->n
.lm_hash
)) {
1301 ldb_asprintf_errstring(io
->ac
->module
->ldb
,
1302 "setup_password_fields: "
1303 "it's only allowed to set the cleartext password or the password hashes");
1304 return LDB_ERR_UNWILLING_TO_PERFORM
;
1307 if (io
->n
.cleartext
) {
1308 struct samr_Password
*hash
;
1310 hash
= talloc(io
->ac
, struct samr_Password
);
1312 ldb_oom(io
->ac
->module
->ldb
);
1313 return LDB_ERR_OPERATIONS_ERROR
;
1316 /* compute the new nt hash */
1317 ok
= E_md4hash(io
->n
.cleartext
, hash
->hash
);
1319 io
->n
.nt_hash
= hash
;
1321 ldb_asprintf_errstring(io
->ac
->module
->ldb
,
1322 "setup_password_fields: "
1323 "failed to generate nthash from cleartext password");
1324 return LDB_ERR_OPERATIONS_ERROR
;
1328 if (io
->n
.cleartext
) {
1329 struct samr_Password
*hash
;
1331 hash
= talloc(io
->ac
, struct samr_Password
);
1333 ldb_oom(io
->ac
->module
->ldb
);
1334 return LDB_ERR_OPERATIONS_ERROR
;
1337 /* compute the new lm hash */
1338 ok
= E_deshash(io
->n
.cleartext
, hash
->hash
);
1340 io
->n
.lm_hash
= hash
;
1342 talloc_free(hash
->hash
);
1346 if (io
->n
.cleartext
) {
1347 ret
= setup_kerberos_keys(io
);
1353 ret
= setup_nt_fields(io
);
1358 ret
= setup_lm_fields(io
);
1363 ret
= setup_supplemental_field(io
);
1368 ret
= setup_last_set_field(io
);
1373 ret
= setup_kvno_field(io
);
1381 static struct ldb_handle
*ph_init_handle(struct ldb_request
*req
, struct ldb_module
*module
, enum ph_type type
)
1383 struct ph_context
*ac
;
1384 struct ldb_handle
*h
;
1386 h
= talloc_zero(req
, struct ldb_handle
);
1388 ldb_set_errstring(module
->ldb
, "Out of Memory");
1394 ac
= talloc_zero(h
, struct ph_context
);
1396 ldb_set_errstring(module
->ldb
, "Out of Memory");
1401 h
->private_data
= (void *)ac
;
1403 h
->state
= LDB_ASYNC_INIT
;
1404 h
->status
= LDB_SUCCESS
;
1407 ac
->module
= module
;
1413 static int get_domain_data_callback(struct ldb_context
*ldb
, void *context
, struct ldb_reply
*ares
)
1415 struct ph_context
*ac
;
1417 ac
= talloc_get_type(context
, struct ph_context
);
1419 /* we are interested only in the single reply (base search) we receive here */
1420 if (ares
->type
== LDB_REPLY_ENTRY
) {
1421 if (ac
->dom_res
!= NULL
) {
1422 ldb_set_errstring(ldb
, "Too many results");
1424 return LDB_ERR_OPERATIONS_ERROR
;
1426 ac
->dom_res
= talloc_steal(ac
, ares
);
1434 static int build_domain_data_request(struct ph_context
*ac
)
1436 /* attrs[] is returned from this function in
1437 ac->dom_req->op.search.attrs, so it must be static, as
1438 otherwise the compiler can put it on the stack */
1439 static const char * const attrs
[] = { "pwdProperties", "pwdHistoryLength", NULL
};
1442 ac
->dom_req
= talloc_zero(ac
, struct ldb_request
);
1443 if (ac
->dom_req
== NULL
) {
1444 ldb_debug(ac
->module
->ldb
, LDB_DEBUG_ERROR
, "Out of Memory!\n");
1445 return LDB_ERR_OPERATIONS_ERROR
;
1447 ac
->dom_req
->operation
= LDB_SEARCH
;
1448 ac
->dom_req
->op
.search
.base
= ldb_get_default_basedn(ac
->module
->ldb
);
1449 ac
->dom_req
->op
.search
.scope
= LDB_SCOPE_SUBTREE
;
1451 filter
= talloc_asprintf(ac
->dom_req
,
1452 "(&(objectSid=%s)(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain)))",
1453 ldap_encode_ndr_dom_sid(ac
->dom_req
, ac
->domain_sid
));
1454 if (filter
== NULL
) {
1455 ldb_debug(ac
->module
->ldb
, LDB_DEBUG_ERROR
, "Out of Memory!\n");
1456 talloc_free(ac
->dom_req
);
1457 return LDB_ERR_OPERATIONS_ERROR
;
1460 ac
->dom_req
->op
.search
.tree
= ldb_parse_tree(ac
->dom_req
, filter
);
1461 if (ac
->dom_req
->op
.search
.tree
== NULL
) {
1462 ldb_set_errstring(ac
->module
->ldb
, "Invalid search filter");
1463 talloc_free(ac
->dom_req
);
1464 return LDB_ERR_OPERATIONS_ERROR
;
1466 ac
->dom_req
->op
.search
.attrs
= attrs
;
1467 ac
->dom_req
->controls
= NULL
;
1468 ac
->dom_req
->context
= ac
;
1469 ac
->dom_req
->callback
= get_domain_data_callback
;
1470 ldb_set_timeout_from_prev_req(ac
->module
->ldb
, ac
->orig_req
, ac
->dom_req
);
1475 static struct domain_data
*get_domain_data(struct ldb_module
*module
, void *ctx
, struct ldb_reply
*res
)
1477 struct domain_data
*data
;
1479 struct ph_context
*ac
;
1482 ac
= talloc_get_type(ctx
, struct ph_context
);
1484 data
= talloc_zero(ac
, struct domain_data
);
1490 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "Could not find this user's domain: %s!\n", dom_sid_string(data
, ac
->domain_sid
));
1495 data
->pwdProperties
= samdb_result_uint(res
->message
, "pwdProperties", 0);
1496 data
->store_cleartext
= data
->pwdProperties
& DOMAIN_PASSWORD_STORE_CLEARTEXT
;
1497 data
->pwdHistoryLength
= samdb_result_uint(res
->message
, "pwdHistoryLength", 0);
1499 /* For a domain DN, this puts things in dotted notation */
1500 /* For builtin domains, this will give details for the host,
1501 * but that doesn't really matter, as it's just used for salt
1502 * and kerberos principals, which don't exist here */
1504 tmp
= ldb_dn_canonical_string(ctx
, res
->message
->dn
);
1509 /* But it puts a trailing (or just before 'builtin') / on things, so kill that */
1510 p
= strchr(tmp
, '/');
1516 data
->dns_domain
= strlower_talloc(data
, tmp
);
1517 if (data
->dns_domain
== NULL
) {
1518 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "Out of memory!\n");
1521 data
->realm
= strupper_talloc(data
, tmp
);
1522 if (data
->realm
== NULL
) {
1523 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "Out of memory!\n");
1526 p
= strchr(tmp
, '.');
1530 data
->netbios_domain
= strupper_talloc(data
, tmp
);
1531 if (data
->netbios_domain
== NULL
) {
1532 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "Out of memory!\n");
1540 static int password_hash_add(struct ldb_module
*module
, struct ldb_request
*req
)
1542 struct ldb_handle
*h
;
1543 struct ph_context
*ac
;
1544 struct ldb_message_element
*sambaAttr
;
1545 struct ldb_message_element
*ntAttr
;
1546 struct ldb_message_element
*lmAttr
;
1549 ldb_debug(module
->ldb
, LDB_DEBUG_TRACE
, "password_hash_add\n");
1551 if (ldb_dn_is_special(req
->op
.add
.message
->dn
)) { /* do not manipulate our control entries */
1552 return ldb_next_request(module
, req
);
1555 /* If the caller is manipulating the local passwords directly, let them pass */
1556 if (ldb_dn_compare_base(ldb_dn_new(req
, module
->ldb
, LOCAL_BASE
),
1557 req
->op
.add
.message
->dn
) == 0) {
1558 return ldb_next_request(module
, req
);
1561 /* nobody must touch this fields */
1562 if (ldb_msg_find_element(req
->op
.add
.message
, "ntPwdHistory")) {
1563 return LDB_ERR_UNWILLING_TO_PERFORM
;
1565 if (ldb_msg_find_element(req
->op
.add
.message
, "lmPwdHistory")) {
1566 return LDB_ERR_UNWILLING_TO_PERFORM
;
1568 if (ldb_msg_find_element(req
->op
.add
.message
, "supplementalCredentials")) {
1569 return LDB_ERR_UNWILLING_TO_PERFORM
;
1572 /* If no part of this ADD touches the userPassword, or the NT
1573 * or LM hashes, then we don't need to make any changes. */
1575 sambaAttr
= ldb_msg_find_element(req
->op
.mod
.message
, "userPassword");
1576 ntAttr
= ldb_msg_find_element(req
->op
.mod
.message
, "unicodePwd");
1577 lmAttr
= ldb_msg_find_element(req
->op
.mod
.message
, "dBCSPwd");
1579 if ((!sambaAttr
) && (!ntAttr
) && (!lmAttr
)) {
1580 return ldb_next_request(module
, req
);
1583 /* if it is not an entry of type person its an error */
1584 /* TODO: remove this when userPassword will be in schema */
1585 if (!ldb_msg_check_string_attribute(req
->op
.add
.message
, "objectClass", "person")) {
1586 ldb_set_errstring(module
->ldb
, "Cannot set a password on entry that does not have objectClass 'person'");
1587 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
1590 /* check userPassword is single valued here */
1591 /* TODO: remove this when userPassword will be single valued in schema */
1592 if (sambaAttr
&& sambaAttr
->num_values
> 1) {
1593 ldb_set_errstring(module
->ldb
, "mupltiple values for userPassword not allowed!\n");
1594 return LDB_ERR_CONSTRAINT_VIOLATION
;
1597 if (ntAttr
&& (ntAttr
->num_values
> 1)) {
1598 ldb_set_errstring(module
->ldb
, "mupltiple values for unicodePwd not allowed!\n");
1599 return LDB_ERR_CONSTRAINT_VIOLATION
;
1601 if (lmAttr
&& (lmAttr
->num_values
> 1)) {
1602 ldb_set_errstring(module
->ldb
, "mupltiple values for dBCSPwd not allowed!\n");
1603 return LDB_ERR_CONSTRAINT_VIOLATION
;
1606 if (sambaAttr
&& sambaAttr
->num_values
== 0) {
1607 ldb_set_errstring(module
->ldb
, "userPassword must have a value!\n");
1608 return LDB_ERR_CONSTRAINT_VIOLATION
;
1611 if (ntAttr
&& (ntAttr
->num_values
== 0)) {
1612 ldb_set_errstring(module
->ldb
, "unicodePwd must have a value!\n");
1613 return LDB_ERR_CONSTRAINT_VIOLATION
;
1615 if (lmAttr
&& (lmAttr
->num_values
== 0)) {
1616 ldb_set_errstring(module
->ldb
, "dBCSPwd must have a value!\n");
1617 return LDB_ERR_CONSTRAINT_VIOLATION
;
1620 h
= ph_init_handle(req
, module
, PH_ADD
);
1622 return LDB_ERR_OPERATIONS_ERROR
;
1624 ac
= talloc_get_type(h
->private_data
, struct ph_context
);
1626 /* get user domain data */
1627 ac
->domain_sid
= samdb_result_sid_prefix(ac
, req
->op
.add
.message
, "objectSid");
1628 if (ac
->domain_sid
== NULL
) {
1629 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "can't handle entry with missing objectSid!\n");
1630 return LDB_ERR_OPERATIONS_ERROR
;
1633 ret
= build_domain_data_request(ac
);
1634 if (ret
!= LDB_SUCCESS
) {
1638 ac
->step
= PH_ADD_SEARCH_DOM
;
1642 return ldb_next_request(module
, ac
->dom_req
);
1645 static int password_hash_add_do_add(struct ldb_handle
*h
) {
1647 struct ph_context
*ac
;
1648 struct domain_data
*domain
;
1649 struct smb_krb5_context
*smb_krb5_context
;
1650 struct ldb_message
*msg
;
1651 struct setup_password_fields_io io
;
1654 ac
= talloc_get_type(h
->private_data
, struct ph_context
);
1656 domain
= get_domain_data(ac
->module
, ac
, ac
->dom_res
);
1657 if (domain
== NULL
) {
1658 return LDB_ERR_OPERATIONS_ERROR
;
1661 ac
->down_req
= talloc(ac
, struct ldb_request
);
1662 if (ac
->down_req
== NULL
) {
1663 return LDB_ERR_OPERATIONS_ERROR
;
1666 *(ac
->down_req
) = *(ac
->orig_req
);
1667 ac
->down_req
->op
.add
.message
= msg
= ldb_msg_copy_shallow(ac
->down_req
, ac
->orig_req
->op
.add
.message
);
1668 if (ac
->down_req
->op
.add
.message
== NULL
) {
1669 return LDB_ERR_OPERATIONS_ERROR
;
1672 /* Some operations below require kerberos contexts */
1673 if (smb_krb5_init_context(ac
->down_req
,
1674 ldb_get_opaque(h
->module
->ldb
, "EventContext"),
1675 (struct loadparm_context
*)ldb_get_opaque(h
->module
->ldb
, "loadparm"),
1676 &smb_krb5_context
) != 0) {
1677 return LDB_ERR_OPERATIONS_ERROR
;
1683 io
.smb_krb5_context
= smb_krb5_context
;
1685 io
.u
.user_account_control
= samdb_result_uint(msg
, "userAccountControl", 0);
1686 io
.u
.sAMAccountName
= samdb_result_string(msg
, "samAccountName", NULL
);
1687 io
.u
.user_principal_name
= samdb_result_string(msg
, "userPrincipalName", NULL
);
1688 io
.u
.is_computer
= ldb_msg_check_string_attribute(msg
, "objectClass", "computer");
1690 io
.n
.cleartext
= samdb_result_string(msg
, "userPassword", NULL
);
1691 io
.n
.nt_hash
= samdb_result_hash(io
.ac
, msg
, "unicodePwd");
1692 io
.n
.lm_hash
= samdb_result_hash(io
.ac
, msg
, "dBCSPwd");
1694 /* remove attributes */
1695 if (io
.n
.cleartext
) ldb_msg_remove_attr(msg
, "userPassword");
1696 if (io
.n
.nt_hash
) ldb_msg_remove_attr(msg
, "unicodePwd");
1697 if (io
.n
.lm_hash
) ldb_msg_remove_attr(msg
, "dBCSPwd");
1698 ldb_msg_remove_attr(msg
, "pwdLastSet");
1699 io
.o
.kvno
= samdb_result_uint(msg
, "msDs-KeyVersionNumber", 1) - 1;
1700 ldb_msg_remove_attr(msg
, "msDs-KeyVersionNumber");
1702 ret
= setup_password_fields(&io
);
1703 if (ret
!= LDB_SUCCESS
) {
1708 ret
= samdb_msg_add_hash(ac
->module
->ldb
, ac
, msg
,
1709 "unicodePwd", io
.g
.nt_hash
);
1710 if (ret
!= LDB_SUCCESS
) {
1715 ret
= samdb_msg_add_hash(ac
->module
->ldb
, ac
, msg
,
1716 "dBCSPwd", io
.g
.lm_hash
);
1717 if (ret
!= LDB_SUCCESS
) {
1721 if (io
.g
.nt_history_len
> 0) {
1722 ret
= samdb_msg_add_hashes(ac
, msg
,
1725 io
.g
.nt_history_len
);
1726 if (ret
!= LDB_SUCCESS
) {
1730 if (io
.g
.lm_history_len
> 0) {
1731 ret
= samdb_msg_add_hashes(ac
, msg
,
1734 io
.g
.lm_history_len
);
1735 if (ret
!= LDB_SUCCESS
) {
1739 if (io
.g
.supplemental
.length
> 0) {
1740 ret
= ldb_msg_add_value(msg
, "supplementalCredentials",
1741 &io
.g
.supplemental
, NULL
);
1742 if (ret
!= LDB_SUCCESS
) {
1746 ret
= samdb_msg_add_uint64(ac
->module
->ldb
, ac
, msg
,
1749 if (ret
!= LDB_SUCCESS
) {
1752 ret
= samdb_msg_add_uint(ac
->module
->ldb
, ac
, msg
,
1753 "msDs-KeyVersionNumber",
1755 if (ret
!= LDB_SUCCESS
) {
1759 h
->state
= LDB_ASYNC_INIT
;
1760 h
->status
= LDB_SUCCESS
;
1762 ac
->step
= PH_ADD_DO_ADD
;
1764 ldb_set_timeout_from_prev_req(ac
->module
->ldb
, ac
->orig_req
, ac
->down_req
);
1766 /* perform the operation */
1767 return ldb_next_request(ac
->module
, ac
->down_req
);
1770 static int password_hash_mod_search_self(struct ldb_handle
*h
);
1772 static int password_hash_modify(struct ldb_module
*module
, struct ldb_request
*req
)
1774 struct ldb_handle
*h
;
1775 struct ph_context
*ac
;
1776 struct ldb_message_element
*sambaAttr
;
1777 struct ldb_message_element
*ntAttr
;
1778 struct ldb_message_element
*lmAttr
;
1779 struct ldb_message
*msg
;
1781 ldb_debug(module
->ldb
, LDB_DEBUG_TRACE
, "password_hash_modify\n");
1783 if (ldb_dn_is_special(req
->op
.mod
.message
->dn
)) { /* do not manipulate our control entries */
1784 return ldb_next_request(module
, req
);
1787 /* If the caller is manipulating the local passwords directly, let them pass */
1788 if (ldb_dn_compare_base(ldb_dn_new(req
, module
->ldb
, LOCAL_BASE
),
1789 req
->op
.mod
.message
->dn
) == 0) {
1790 return ldb_next_request(module
, req
);
1793 /* nobody must touch password Histories */
1794 if (ldb_msg_find_element(req
->op
.add
.message
, "ntPwdHistory")) {
1795 return LDB_ERR_UNWILLING_TO_PERFORM
;
1797 if (ldb_msg_find_element(req
->op
.add
.message
, "lmPwdHistory")) {
1798 return LDB_ERR_UNWILLING_TO_PERFORM
;
1800 if (ldb_msg_find_element(req
->op
.add
.message
, "supplementalCredentials")) {
1801 return LDB_ERR_UNWILLING_TO_PERFORM
;
1804 sambaAttr
= ldb_msg_find_element(req
->op
.mod
.message
, "userPassword");
1805 ntAttr
= ldb_msg_find_element(req
->op
.mod
.message
, "unicodePwd");
1806 lmAttr
= ldb_msg_find_element(req
->op
.mod
.message
, "dBCSPwd");
1808 /* If no part of this touches the userPassword OR unicodePwd and/or dBCSPwd, then we don't
1809 * need to make any changes. For password changes/set there should
1810 * be a 'delete' or a 'modify' on this attribute. */
1811 if ((!sambaAttr
) && (!ntAttr
) && (!lmAttr
)) {
1812 return ldb_next_request(module
, req
);
1815 /* check passwords are single valued here */
1816 /* TODO: remove this when passwords will be single valued in schema */
1817 if (sambaAttr
&& (sambaAttr
->num_values
> 1)) {
1818 return LDB_ERR_CONSTRAINT_VIOLATION
;
1820 if (ntAttr
&& (ntAttr
->num_values
> 1)) {
1821 return LDB_ERR_CONSTRAINT_VIOLATION
;
1823 if (lmAttr
&& (lmAttr
->num_values
> 1)) {
1824 return LDB_ERR_CONSTRAINT_VIOLATION
;
1827 h
= ph_init_handle(req
, module
, PH_MOD
);
1829 return LDB_ERR_OPERATIONS_ERROR
;
1831 ac
= talloc_get_type(h
->private_data
, struct ph_context
);
1833 /* return or own handle to deal with this call */
1836 /* prepare the first operation */
1837 ac
->down_req
= talloc_zero(ac
, struct ldb_request
);
1838 if (ac
->down_req
== NULL
) {
1839 ldb_set_errstring(module
->ldb
, "Out of memory!");
1840 return LDB_ERR_OPERATIONS_ERROR
;
1843 *(ac
->down_req
) = *req
; /* copy the request */
1845 /* use a new message structure so that we can modify it */
1846 ac
->down_req
->op
.mod
.message
= msg
= ldb_msg_copy_shallow(ac
->down_req
, req
->op
.mod
.message
);
1848 /* - remove any imodification to the password from the first commit
1849 * we will make the real modification later */
1850 if (sambaAttr
) ldb_msg_remove_attr(msg
, "userPassword");
1851 if (ntAttr
) ldb_msg_remove_attr(msg
, "unicodePwd");
1852 if (lmAttr
) ldb_msg_remove_attr(msg
, "dBCSPwd");
1854 /* if there was nothing else to be modify skip to next step */
1855 if (msg
->num_elements
== 0) {
1856 talloc_free(ac
->down_req
);
1857 ac
->down_req
= NULL
;
1858 return password_hash_mod_search_self(h
);
1861 ac
->down_req
->context
= NULL
;
1862 ac
->down_req
->callback
= NULL
;
1864 ac
->step
= PH_MOD_DO_REQ
;
1866 ldb_set_timeout_from_prev_req(module
->ldb
, req
, ac
->down_req
);
1868 return ldb_next_request(module
, ac
->down_req
);
1871 static int get_self_callback(struct ldb_context
*ldb
, void *context
, struct ldb_reply
*ares
)
1873 struct ph_context
*ac
;
1875 ac
= talloc_get_type(context
, struct ph_context
);
1877 /* we are interested only in the single reply (base search) we receive here */
1878 if (ares
->type
== LDB_REPLY_ENTRY
) {
1879 if (ac
->search_res
!= NULL
) {
1880 ldb_set_errstring(ldb
, "Too many results");
1882 return LDB_ERR_OPERATIONS_ERROR
;
1885 /* if it is not an entry of type person this is an error */
1886 /* TODO: remove this when userPassword will be in schema */
1887 if (!ldb_msg_check_string_attribute(ares
->message
, "objectClass", "person")) {
1888 ldb_set_errstring(ldb
, "Object class violation");
1890 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
1893 ac
->search_res
= talloc_steal(ac
, ares
);
1901 static int password_hash_mod_search_self(struct ldb_handle
*h
) {
1903 struct ph_context
*ac
;
1904 static const char * const attrs
[] = { "userAccountControl", "lmPwdHistory",
1906 "objectSid", "msDS-KeyVersionNumber",
1907 "objectClass", "userPrincipalName",
1909 "dBCSPwd", "unicodePwd",
1910 "supplementalCredentials",
1913 ac
= talloc_get_type(h
->private_data
, struct ph_context
);
1915 /* prepare the search operation */
1916 ac
->search_req
= talloc_zero(ac
, struct ldb_request
);
1917 if (ac
->search_req
== NULL
) {
1918 ldb_debug(ac
->module
->ldb
, LDB_DEBUG_ERROR
, "Out of Memory!\n");
1919 return LDB_ERR_OPERATIONS_ERROR
;
1922 ac
->search_req
->operation
= LDB_SEARCH
;
1923 ac
->search_req
->op
.search
.base
= ac
->orig_req
->op
.mod
.message
->dn
;
1924 ac
->search_req
->op
.search
.scope
= LDB_SCOPE_BASE
;
1925 ac
->search_req
->op
.search
.tree
= ldb_parse_tree(ac
->search_req
, NULL
);
1926 if (ac
->search_req
->op
.search
.tree
== NULL
) {
1927 ldb_set_errstring(ac
->module
->ldb
, "Invalid search filter");
1928 return LDB_ERR_OPERATIONS_ERROR
;
1930 ac
->search_req
->op
.search
.attrs
= attrs
;
1931 ac
->search_req
->controls
= NULL
;
1932 ac
->search_req
->context
= ac
;
1933 ac
->search_req
->callback
= get_self_callback
;
1934 ldb_set_timeout_from_prev_req(ac
->module
->ldb
, ac
->orig_req
, ac
->search_req
);
1936 ac
->step
= PH_MOD_SEARCH_SELF
;
1938 return ldb_next_request(ac
->module
, ac
->search_req
);
1941 static int password_hash_mod_search_dom(struct ldb_handle
*h
) {
1943 struct ph_context
*ac
;
1946 ac
= talloc_get_type(h
->private_data
, struct ph_context
);
1948 /* get object domain sid */
1949 ac
->domain_sid
= samdb_result_sid_prefix(ac
, ac
->search_res
->message
, "objectSid");
1950 if (ac
->domain_sid
== NULL
) {
1951 ldb_debug(ac
->module
->ldb
, LDB_DEBUG_ERROR
, "can't handle entry with missing objectSid!\n");
1952 return LDB_ERR_OPERATIONS_ERROR
;
1955 /* get user domain data */
1956 ret
= build_domain_data_request(ac
);
1957 if (ret
!= LDB_SUCCESS
) {
1961 ac
->step
= PH_MOD_SEARCH_DOM
;
1963 return ldb_next_request(ac
->module
, ac
->dom_req
);
1966 static int password_hash_mod_do_mod(struct ldb_handle
*h
) {
1968 struct ph_context
*ac
;
1969 struct domain_data
*domain
;
1970 struct smb_krb5_context
*smb_krb5_context
;
1971 struct ldb_message
*msg
;
1972 struct ldb_message
*orig_msg
;
1973 struct ldb_message
*searched_msg
;
1974 struct setup_password_fields_io io
;
1977 ac
= talloc_get_type(h
->private_data
, struct ph_context
);
1979 domain
= get_domain_data(ac
->module
, ac
, ac
->dom_res
);
1980 if (domain
== NULL
) {
1981 return LDB_ERR_OPERATIONS_ERROR
;
1984 ac
->mod_req
= talloc(ac
, struct ldb_request
);
1985 if (ac
->mod_req
== NULL
) {
1986 return LDB_ERR_OPERATIONS_ERROR
;
1989 *(ac
->mod_req
) = *(ac
->orig_req
);
1991 /* use a new message structure so that we can modify it */
1992 ac
->mod_req
->op
.mod
.message
= msg
= ldb_msg_new(ac
->mod_req
);
1994 return LDB_ERR_OPERATIONS_ERROR
;
1998 msg
->dn
= ac
->orig_req
->op
.mod
.message
->dn
;
2000 /* Some operations below require kerberos contexts */
2001 if (smb_krb5_init_context(ac
->mod_req
,
2002 ldb_get_opaque(h
->module
->ldb
, "EventContext"),
2003 (struct loadparm_context
*)ldb_get_opaque(h
->module
->ldb
, "loadparm"),
2004 &smb_krb5_context
) != 0) {
2005 return LDB_ERR_OPERATIONS_ERROR
;
2008 orig_msg
= discard_const(ac
->orig_req
->op
.mod
.message
);
2009 searched_msg
= ac
->search_res
->message
;
2014 io
.smb_krb5_context
= smb_krb5_context
;
2016 io
.u
.user_account_control
= samdb_result_uint(searched_msg
, "userAccountControl", 0);
2017 io
.u
.sAMAccountName
= samdb_result_string(searched_msg
, "samAccountName", NULL
);
2018 io
.u
.user_principal_name
= samdb_result_string(searched_msg
, "userPrincipalName", NULL
);
2019 io
.u
.is_computer
= ldb_msg_check_string_attribute(searched_msg
, "objectClass", "computer");
2021 io
.n
.cleartext
= samdb_result_string(orig_msg
, "userPassword", NULL
);
2022 io
.n
.nt_hash
= samdb_result_hash(io
.ac
, orig_msg
, "unicodePwd");
2023 io
.n
.lm_hash
= samdb_result_hash(io
.ac
, orig_msg
, "dBCSPwd");
2025 io
.o
.kvno
= samdb_result_uint(searched_msg
, "msDs-KeyVersionNumber", 0);
2026 io
.o
.nt_history_len
= samdb_result_hashes(io
.ac
, searched_msg
, "ntPwdHistory", &io
.o
.nt_history
);
2027 io
.o
.lm_history_len
= samdb_result_hashes(io
.ac
, searched_msg
, "lmPwdHistory", &io
.o
.lm_history
);
2028 io
.o
.supplemental
= ldb_msg_find_ldb_val(searched_msg
, "supplementalCredentials");
2030 ret
= setup_password_fields(&io
);
2031 if (ret
!= LDB_SUCCESS
) {
2035 /* make sure we replace all the old attributes */
2036 ret
= ldb_msg_add_empty(msg
, "unicodePwd", LDB_FLAG_MOD_REPLACE
, NULL
);
2037 ret
= ldb_msg_add_empty(msg
, "dBCSPwd", LDB_FLAG_MOD_REPLACE
, NULL
);
2038 ret
= ldb_msg_add_empty(msg
, "ntPwdHistory", LDB_FLAG_MOD_REPLACE
, NULL
);
2039 ret
= ldb_msg_add_empty(msg
, "lmPwdHistory", LDB_FLAG_MOD_REPLACE
, NULL
);
2040 ret
= ldb_msg_add_empty(msg
, "supplementalCredentials", LDB_FLAG_MOD_REPLACE
, NULL
);
2041 ret
= ldb_msg_add_empty(msg
, "pwdLastSet", LDB_FLAG_MOD_REPLACE
, NULL
);
2042 ret
= ldb_msg_add_empty(msg
, "msDs-KeyVersionNumber", LDB_FLAG_MOD_REPLACE
, NULL
);
2045 ret
= samdb_msg_add_hash(ac
->module
->ldb
, ac
, msg
,
2046 "unicodePwd", io
.g
.nt_hash
);
2047 if (ret
!= LDB_SUCCESS
) {
2052 ret
= samdb_msg_add_hash(ac
->module
->ldb
, ac
, msg
,
2053 "dBCSPwd", io
.g
.lm_hash
);
2054 if (ret
!= LDB_SUCCESS
) {
2058 if (io
.g
.nt_history_len
> 0) {
2059 ret
= samdb_msg_add_hashes(ac
, msg
,
2062 io
.g
.nt_history_len
);
2063 if (ret
!= LDB_SUCCESS
) {
2067 if (io
.g
.lm_history_len
> 0) {
2068 ret
= samdb_msg_add_hashes(ac
, msg
,
2071 io
.g
.lm_history_len
);
2072 if (ret
!= LDB_SUCCESS
) {
2076 if (io
.g
.supplemental
.length
> 0) {
2077 ret
= ldb_msg_add_value(msg
, "supplementalCredentials",
2078 &io
.g
.supplemental
, NULL
);
2079 if (ret
!= LDB_SUCCESS
) {
2083 ret
= samdb_msg_add_uint64(ac
->module
->ldb
, ac
, msg
,
2086 if (ret
!= LDB_SUCCESS
) {
2089 ret
= samdb_msg_add_uint(ac
->module
->ldb
, ac
, msg
,
2090 "msDs-KeyVersionNumber",
2092 if (ret
!= LDB_SUCCESS
) {
2096 h
->state
= LDB_ASYNC_INIT
;
2097 h
->status
= LDB_SUCCESS
;
2099 ac
->step
= PH_MOD_DO_MOD
;
2101 ldb_set_timeout_from_prev_req(ac
->module
->ldb
, ac
->orig_req
, ac
->mod_req
);
2103 /* perform the search */
2104 return ldb_next_request(ac
->module
, ac
->mod_req
);
2107 static int ph_wait(struct ldb_handle
*handle
) {
2108 struct ph_context
*ac
;
2111 if (!handle
|| !handle
->private_data
) {
2112 return LDB_ERR_OPERATIONS_ERROR
;
2115 if (handle
->state
== LDB_ASYNC_DONE
) {
2116 return handle
->status
;
2119 handle
->state
= LDB_ASYNC_PENDING
;
2120 handle
->status
= LDB_SUCCESS
;
2122 ac
= talloc_get_type(handle
->private_data
, struct ph_context
);
2125 case PH_ADD_SEARCH_DOM
:
2126 ret
= ldb_wait(ac
->dom_req
->handle
, LDB_WAIT_NONE
);
2128 if (ret
!= LDB_SUCCESS
) {
2129 handle
->status
= ret
;
2132 if (ac
->dom_req
->handle
->status
!= LDB_SUCCESS
) {
2133 handle
->status
= ac
->dom_req
->handle
->status
;
2137 if (ac
->dom_req
->handle
->state
!= LDB_ASYNC_DONE
) {
2141 /* domain search done, go on */
2142 return password_hash_add_do_add(handle
);
2145 ret
= ldb_wait(ac
->down_req
->handle
, LDB_WAIT_NONE
);
2147 if (ret
!= LDB_SUCCESS
) {
2148 handle
->status
= ret
;
2151 if (ac
->down_req
->handle
->status
!= LDB_SUCCESS
) {
2152 handle
->status
= ac
->down_req
->handle
->status
;
2156 if (ac
->down_req
->handle
->state
!= LDB_ASYNC_DONE
) {
2163 ret
= ldb_wait(ac
->down_req
->handle
, LDB_WAIT_NONE
);
2165 if (ret
!= LDB_SUCCESS
) {
2166 handle
->status
= ret
;
2169 if (ac
->down_req
->handle
->status
!= LDB_SUCCESS
) {
2170 handle
->status
= ac
->down_req
->handle
->status
;
2174 if (ac
->down_req
->handle
->state
!= LDB_ASYNC_DONE
) {
2178 /* non-password mods done, go on */
2179 return password_hash_mod_search_self(handle
);
2181 case PH_MOD_SEARCH_SELF
:
2182 ret
= ldb_wait(ac
->search_req
->handle
, LDB_WAIT_NONE
);
2184 if (ret
!= LDB_SUCCESS
) {
2185 handle
->status
= ret
;
2188 if (ac
->search_req
->handle
->status
!= LDB_SUCCESS
) {
2189 handle
->status
= ac
->search_req
->handle
->status
;
2193 if (ac
->search_req
->handle
->state
!= LDB_ASYNC_DONE
) {
2197 if (ac
->search_res
== NULL
) {
2198 return LDB_ERR_NO_SUCH_OBJECT
;
2201 /* self search done, go on */
2202 return password_hash_mod_search_dom(handle
);
2204 case PH_MOD_SEARCH_DOM
:
2205 ret
= ldb_wait(ac
->dom_req
->handle
, LDB_WAIT_NONE
);
2207 if (ret
!= LDB_SUCCESS
) {
2208 handle
->status
= ret
;
2211 if (ac
->dom_req
->handle
->status
!= LDB_SUCCESS
) {
2212 handle
->status
= ac
->dom_req
->handle
->status
;
2216 if (ac
->dom_req
->handle
->state
!= LDB_ASYNC_DONE
) {
2220 /* domain search done, go on */
2221 return password_hash_mod_do_mod(handle
);
2224 ret
= ldb_wait(ac
->mod_req
->handle
, LDB_WAIT_NONE
);
2226 if (ret
!= LDB_SUCCESS
) {
2227 handle
->status
= ret
;
2230 if (ac
->mod_req
->handle
->status
!= LDB_SUCCESS
) {
2231 handle
->status
= ac
->mod_req
->handle
->status
;
2235 if (ac
->mod_req
->handle
->state
!= LDB_ASYNC_DONE
) {
2242 ret
= LDB_ERR_OPERATIONS_ERROR
;
2249 handle
->state
= LDB_ASYNC_DONE
;
2253 static int ph_wait_all(struct ldb_handle
*handle
) {
2257 while (handle
->state
!= LDB_ASYNC_DONE
) {
2258 ret
= ph_wait(handle
);
2259 if (ret
!= LDB_SUCCESS
) {
2264 return handle
->status
;
2267 static int password_hash_wait(struct ldb_handle
*handle
, enum ldb_wait_type type
)
2269 if (type
== LDB_WAIT_ALL
) {
2270 return ph_wait_all(handle
);
2272 return ph_wait(handle
);
2276 _PUBLIC_
const struct ldb_module_ops ldb_password_hash_module_ops
= {
2277 .name
= "password_hash",
2278 .add
= password_hash_add
,
2279 .modify
= password_hash_modify
,
2280 .wait
= password_hash_wait