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
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_module.h"
37 #include "librpc/gen_ndr/misc.h"
38 #include "librpc/gen_ndr/samr.h"
39 #include "libcli/auth/libcli_auth.h"
40 #include "libcli/security/security.h"
41 #include "system/kerberos.h"
42 #include "auth/kerberos/kerberos.h"
43 #include "system/time.h"
44 #include "dsdb/samdb/samdb.h"
45 #include "../libds/common/flags.h"
46 #include "dsdb/samdb/ldb_modules/password_modules.h"
47 #include "librpc/ndr/libndr.h"
48 #include "librpc/gen_ndr/ndr_drsblobs.h"
49 #include "../lib/crypto/crypto.h"
50 #include "param/param.h"
52 /* If we have decided there is reason to work on this request, then
53 * setup all the password hash types correctly.
55 * If the administrator doesn't want the userPassword stored (set in the
56 * domain and per-account policies) then we must strip that out before
57 * we do the first operation.
59 * Once this is done (which could update anything at all), we
60 * calculate the password hashes.
62 * This function must not only update the unicodePwd, dBCSPwd and
63 * supplementalCredentials fields, it must also atomicly increment the
64 * msDS-KeyVersionNumber. We should be in a transaction, so all this
65 * should be quite safe...
67 * Finally, if the administrator has requested that a password history
68 * be maintained, then this should also be written out.
74 struct ldb_module
*module
;
75 struct ldb_request
*req
;
77 struct ldb_request
*dom_req
;
78 struct ldb_reply
*dom_res
;
80 struct ldb_reply
*search_res
;
82 struct domain_data
*domain
;
88 uint_t pwdHistoryLength
;
89 const char *netbios_domain
;
90 const char *dns_domain
;
94 struct setup_password_fields_io
{
95 struct ph_context
*ac
;
96 struct domain_data
*domain
;
97 struct smb_krb5_context
*smb_krb5_context
;
99 /* infos about the user account */
101 uint32_t user_account_control
;
102 const char *sAMAccountName
;
103 const char *user_principal_name
;
107 /* new credentials */
109 const struct ldb_val
*cleartext_utf8
;
110 const struct ldb_val
*cleartext_utf16
;
111 struct ldb_val quoted_utf16
;
112 struct samr_Password
*nt_hash
;
113 struct samr_Password
*lm_hash
;
116 /* old credentials */
118 uint32_t nt_history_len
;
119 struct samr_Password
*nt_history
;
120 uint32_t lm_history_len
;
121 struct samr_Password
*lm_history
;
122 const struct ldb_val
*supplemental
;
123 struct supplementalCredentialsBlob scb
;
127 /* generated credentials */
129 struct samr_Password
*nt_hash
;
130 struct samr_Password
*lm_hash
;
131 uint32_t nt_history_len
;
132 struct samr_Password
*nt_history
;
133 uint32_t lm_history_len
;
134 struct samr_Password
*lm_history
;
140 struct ldb_val supplemental
;
146 /* Get the NT hash, and fill it in as an entry in the password history,
147 and specify it into io->g.nt_hash */
149 static int setup_nt_fields(struct setup_password_fields_io
*io
)
151 struct ldb_context
*ldb
;
154 io
->g
.nt_hash
= io
->n
.nt_hash
;
155 ldb
= ldb_module_get_ctx(io
->ac
->module
);
157 if (io
->domain
->pwdHistoryLength
== 0) {
161 /* We might not have an old NT password */
162 io
->g
.nt_history
= talloc_array(io
->ac
,
163 struct samr_Password
,
164 io
->domain
->pwdHistoryLength
);
165 if (!io
->g
.nt_history
) {
167 return LDB_ERR_OPERATIONS_ERROR
;
170 for (i
= 0; i
< MIN(io
->domain
->pwdHistoryLength
-1, io
->o
.nt_history_len
); i
++) {
171 io
->g
.nt_history
[i
+1] = io
->o
.nt_history
[i
];
173 io
->g
.nt_history_len
= i
+ 1;
176 io
->g
.nt_history
[0] = *io
->g
.nt_hash
;
179 * TODO: is this correct?
180 * the simular behavior is correct for the lm history case
182 E_md4hash("", io
->g
.nt_history
[0].hash
);
188 /* Get the LANMAN hash, and fill it in as an entry in the password history,
189 and specify it into io->g.lm_hash */
191 static int setup_lm_fields(struct setup_password_fields_io
*io
)
193 struct ldb_context
*ldb
;
196 io
->g
.lm_hash
= io
->n
.lm_hash
;
197 ldb
= ldb_module_get_ctx(io
->ac
->module
);
199 if (io
->domain
->pwdHistoryLength
== 0) {
203 /* We might not have an old NT password */
204 io
->g
.lm_history
= talloc_array(io
->ac
,
205 struct samr_Password
,
206 io
->domain
->pwdHistoryLength
);
207 if (!io
->g
.lm_history
) {
209 return LDB_ERR_OPERATIONS_ERROR
;
212 for (i
= 0; i
< MIN(io
->domain
->pwdHistoryLength
-1, io
->o
.lm_history_len
); i
++) {
213 io
->g
.lm_history
[i
+1] = io
->o
.lm_history
[i
];
215 io
->g
.lm_history_len
= i
+ 1;
218 io
->g
.lm_history
[0] = *io
->g
.lm_hash
;
220 E_deshash("", io
->g
.lm_history
[0].hash
);
226 static int setup_kerberos_keys(struct setup_password_fields_io
*io
)
228 struct ldb_context
*ldb
;
229 krb5_error_code krb5_ret
;
230 Principal
*salt_principal
;
233 krb5_data cleartext_data
;
235 ldb
= ldb_module_get_ctx(io
->ac
->module
);
236 cleartext_data
.data
= io
->n
.cleartext_utf8
->data
;
237 cleartext_data
.length
= io
->n
.cleartext_utf8
->length
;
239 /* Many, many thanks to lukeh@padl.com for this
240 * algorithm, described in his Nov 10 2004 mail to
241 * samba-technical@samba.org */
244 * Determine a salting principal
246 if (io
->u
.is_computer
) {
250 name
= strlower_talloc(io
->ac
, io
->u
.sAMAccountName
);
253 return LDB_ERR_OPERATIONS_ERROR
;
256 if (name
[strlen(name
)-1] == '$') {
257 name
[strlen(name
)-1] = '\0';
260 saltbody
= talloc_asprintf(io
->ac
, "%s.%s", name
, io
->domain
->dns_domain
);
263 return LDB_ERR_OPERATIONS_ERROR
;
266 krb5_ret
= krb5_make_principal(io
->smb_krb5_context
->krb5_context
,
268 io
->domain
->realm
, "host",
270 } else if (io
->u
.user_principal_name
) {
271 char *user_principal_name
;
274 user_principal_name
= talloc_strdup(io
->ac
, io
->u
.user_principal_name
);
275 if (!user_principal_name
) {
277 return LDB_ERR_OPERATIONS_ERROR
;
280 p
= strchr(user_principal_name
, '@');
285 krb5_ret
= krb5_make_principal(io
->smb_krb5_context
->krb5_context
,
287 io
->domain
->realm
, user_principal_name
,
290 krb5_ret
= krb5_make_principal(io
->smb_krb5_context
->krb5_context
,
292 io
->domain
->realm
, io
->u
.sAMAccountName
,
296 ldb_asprintf_errstring(ldb
,
297 "setup_kerberos_keys: "
298 "generation of a salting principal failed: %s",
299 smb_get_krb5_error_message(io
->smb_krb5_context
->krb5_context
, krb5_ret
, io
->ac
));
300 return LDB_ERR_OPERATIONS_ERROR
;
304 * create salt from salt_principal
306 krb5_ret
= krb5_get_pw_salt(io
->smb_krb5_context
->krb5_context
,
307 salt_principal
, &salt
);
308 krb5_free_principal(io
->smb_krb5_context
->krb5_context
, salt_principal
);
310 ldb_asprintf_errstring(ldb
,
311 "setup_kerberos_keys: "
312 "generation of krb5_salt failed: %s",
313 smb_get_krb5_error_message(io
->smb_krb5_context
->krb5_context
, krb5_ret
, io
->ac
));
314 return LDB_ERR_OPERATIONS_ERROR
;
316 /* create a talloc copy */
317 io
->g
.salt
= talloc_strndup(io
->ac
,
319 salt
.saltvalue
.length
);
320 krb5_free_salt(io
->smb_krb5_context
->krb5_context
, salt
);
323 return LDB_ERR_OPERATIONS_ERROR
;
325 salt
.saltvalue
.data
= discard_const(io
->g
.salt
);
326 salt
.saltvalue
.length
= strlen(io
->g
.salt
);
329 * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of
330 * the salt and the cleartext password
332 krb5_ret
= krb5_string_to_key_data_salt(io
->smb_krb5_context
->krb5_context
,
333 ENCTYPE_AES256_CTS_HMAC_SHA1_96
,
338 ldb_asprintf_errstring(ldb
,
339 "setup_kerberos_keys: "
340 "generation of a aes256-cts-hmac-sha1-96 key failed: %s",
341 smb_get_krb5_error_message(io
->smb_krb5_context
->krb5_context
, krb5_ret
, io
->ac
));
342 return LDB_ERR_OPERATIONS_ERROR
;
344 io
->g
.aes_256
= data_blob_talloc(io
->ac
,
346 key
.keyvalue
.length
);
347 krb5_free_keyblock_contents(io
->smb_krb5_context
->krb5_context
, &key
);
348 if (!io
->g
.aes_256
.data
) {
350 return LDB_ERR_OPERATIONS_ERROR
;
354 * create ENCTYPE_AES128_CTS_HMAC_SHA1_96 key out of
355 * the salt and the cleartext password
357 krb5_ret
= krb5_string_to_key_data_salt(io
->smb_krb5_context
->krb5_context
,
358 ENCTYPE_AES128_CTS_HMAC_SHA1_96
,
363 ldb_asprintf_errstring(ldb
,
364 "setup_kerberos_keys: "
365 "generation of a aes128-cts-hmac-sha1-96 key failed: %s",
366 smb_get_krb5_error_message(io
->smb_krb5_context
->krb5_context
, krb5_ret
, io
->ac
));
367 return LDB_ERR_OPERATIONS_ERROR
;
369 io
->g
.aes_128
= data_blob_talloc(io
->ac
,
371 key
.keyvalue
.length
);
372 krb5_free_keyblock_contents(io
->smb_krb5_context
->krb5_context
, &key
);
373 if (!io
->g
.aes_128
.data
) {
375 return LDB_ERR_OPERATIONS_ERROR
;
379 * create ENCTYPE_DES_CBC_MD5 key out of
380 * the salt and the cleartext password
382 krb5_ret
= krb5_string_to_key_data_salt(io
->smb_krb5_context
->krb5_context
,
388 ldb_asprintf_errstring(ldb
,
389 "setup_kerberos_keys: "
390 "generation of a des-cbc-md5 key failed: %s",
391 smb_get_krb5_error_message(io
->smb_krb5_context
->krb5_context
, krb5_ret
, io
->ac
));
392 return LDB_ERR_OPERATIONS_ERROR
;
394 io
->g
.des_md5
= data_blob_talloc(io
->ac
,
396 key
.keyvalue
.length
);
397 krb5_free_keyblock_contents(io
->smb_krb5_context
->krb5_context
, &key
);
398 if (!io
->g
.des_md5
.data
) {
400 return LDB_ERR_OPERATIONS_ERROR
;
404 * create ENCTYPE_DES_CBC_CRC key out of
405 * the salt and the cleartext password
407 krb5_ret
= krb5_string_to_key_data_salt(io
->smb_krb5_context
->krb5_context
,
413 ldb_asprintf_errstring(ldb
,
414 "setup_kerberos_keys: "
415 "generation of a des-cbc-crc key failed: %s",
416 smb_get_krb5_error_message(io
->smb_krb5_context
->krb5_context
, krb5_ret
, io
->ac
));
417 return LDB_ERR_OPERATIONS_ERROR
;
419 io
->g
.des_crc
= data_blob_talloc(io
->ac
,
421 key
.keyvalue
.length
);
422 krb5_free_keyblock_contents(io
->smb_krb5_context
->krb5_context
, &key
);
423 if (!io
->g
.des_crc
.data
) {
425 return LDB_ERR_OPERATIONS_ERROR
;
431 static int setup_primary_kerberos(struct setup_password_fields_io
*io
,
432 const struct supplementalCredentialsBlob
*old_scb
,
433 struct package_PrimaryKerberosBlob
*pkb
)
435 struct ldb_context
*ldb
;
436 struct package_PrimaryKerberosCtr3
*pkb3
= &pkb
->ctr
.ctr3
;
437 struct supplementalCredentialsPackage
*old_scp
= NULL
;
438 struct package_PrimaryKerberosBlob _old_pkb
;
439 struct package_PrimaryKerberosCtr3
*old_pkb3
= NULL
;
441 enum ndr_err_code ndr_err
;
443 ldb
= ldb_module_get_ctx(io
->ac
->module
);
446 * prepare generation of keys
448 * ENCTYPE_DES_CBC_MD5
449 * ENCTYPE_DES_CBC_CRC
452 pkb3
->salt
.string
= io
->g
.salt
;
454 pkb3
->keys
= talloc_array(io
->ac
,
455 struct package_PrimaryKerberosKey3
,
459 return LDB_ERR_OPERATIONS_ERROR
;
462 pkb3
->keys
[0].keytype
= ENCTYPE_DES_CBC_MD5
;
463 pkb3
->keys
[0].value
= &io
->g
.des_md5
;
464 pkb3
->keys
[1].keytype
= ENCTYPE_DES_CBC_CRC
;
465 pkb3
->keys
[1].value
= &io
->g
.des_crc
;
467 /* initialize the old keys to zero */
468 pkb3
->num_old_keys
= 0;
469 pkb3
->old_keys
= NULL
;
471 /* if there're no old keys, then we're done */
476 for (i
=0; i
< old_scb
->sub
.num_packages
; i
++) {
477 if (strcmp("Primary:Kerberos", old_scb
->sub
.packages
[i
].name
) != 0) {
481 if (!old_scb
->sub
.packages
[i
].data
|| !old_scb
->sub
.packages
[i
].data
[0]) {
485 old_scp
= &old_scb
->sub
.packages
[i
];
488 /* Primary:Kerberos element of supplementalCredentials */
492 blob
= strhex_to_data_blob(io
->ac
, old_scp
->data
);
495 return LDB_ERR_OPERATIONS_ERROR
;
498 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
499 ndr_err
= ndr_pull_struct_blob(&blob
, io
->ac
, lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")), &_old_pkb
,
500 (ndr_pull_flags_fn_t
)ndr_pull_package_PrimaryKerberosBlob
);
501 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
502 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
503 ldb_asprintf_errstring(ldb
,
504 "setup_primary_kerberos: "
505 "failed to pull old package_PrimaryKerberosBlob: %s",
507 return LDB_ERR_OPERATIONS_ERROR
;
510 if (_old_pkb
.version
!= 3) {
511 ldb_asprintf_errstring(ldb
,
512 "setup_primary_kerberos: "
513 "package_PrimaryKerberosBlob version[%u] expected[3]",
515 return LDB_ERR_OPERATIONS_ERROR
;
518 old_pkb3
= &_old_pkb
.ctr
.ctr3
;
521 /* if we didn't found the old keys we're done */
526 /* fill in the old keys */
527 pkb3
->num_old_keys
= old_pkb3
->num_keys
;
528 pkb3
->old_keys
= old_pkb3
->keys
;
533 static int setup_primary_kerberos_newer(struct setup_password_fields_io
*io
,
534 const struct supplementalCredentialsBlob
*old_scb
,
535 struct package_PrimaryKerberosBlob
*pkb
)
537 struct ldb_context
*ldb
;
538 struct package_PrimaryKerberosCtr4
*pkb4
= &pkb
->ctr
.ctr4
;
539 struct supplementalCredentialsPackage
*old_scp
= NULL
;
540 struct package_PrimaryKerberosBlob _old_pkb
;
541 struct package_PrimaryKerberosCtr4
*old_pkb4
= NULL
;
543 enum ndr_err_code ndr_err
;
545 ldb
= ldb_module_get_ctx(io
->ac
->module
);
548 * prepare generation of keys
550 * ENCTYPE_AES256_CTS_HMAC_SHA1_96
551 * ENCTYPE_AES128_CTS_HMAC_SHA1_96
552 * ENCTYPE_DES_CBC_MD5
553 * ENCTYPE_DES_CBC_CRC
556 pkb4
->salt
.string
= io
->g
.salt
;
557 pkb4
->default_iteration_count
= 4096;
560 pkb4
->keys
= talloc_array(io
->ac
,
561 struct package_PrimaryKerberosKey4
,
565 return LDB_ERR_OPERATIONS_ERROR
;
568 pkb4
->keys
[0].iteration_count
= 4096;
569 pkb4
->keys
[0].keytype
= ENCTYPE_AES256_CTS_HMAC_SHA1_96
;
570 pkb4
->keys
[0].value
= &io
->g
.aes_256
;
571 pkb4
->keys
[1].iteration_count
= 4096;
572 pkb4
->keys
[1].keytype
= ENCTYPE_AES128_CTS_HMAC_SHA1_96
;
573 pkb4
->keys
[1].value
= &io
->g
.aes_128
;
574 pkb4
->keys
[2].iteration_count
= 4096;
575 pkb4
->keys
[2].keytype
= ENCTYPE_DES_CBC_MD5
;
576 pkb4
->keys
[2].value
= &io
->g
.des_md5
;
577 pkb4
->keys
[3].iteration_count
= 4096;
578 pkb4
->keys
[3].keytype
= ENCTYPE_DES_CBC_CRC
;
579 pkb4
->keys
[3].value
= &io
->g
.des_crc
;
581 /* initialize the old keys to zero */
582 pkb4
->num_old_keys
= 0;
583 pkb4
->old_keys
= NULL
;
584 pkb4
->num_older_keys
= 0;
585 pkb4
->older_keys
= NULL
;
587 /* if there're no old keys, then we're done */
592 for (i
=0; i
< old_scb
->sub
.num_packages
; i
++) {
593 if (strcmp("Primary:Kerberos-Newer-Keys", old_scb
->sub
.packages
[i
].name
) != 0) {
597 if (!old_scb
->sub
.packages
[i
].data
|| !old_scb
->sub
.packages
[i
].data
[0]) {
601 old_scp
= &old_scb
->sub
.packages
[i
];
604 /* Primary:Kerberos-Newer-Keys element of supplementalCredentials */
608 blob
= strhex_to_data_blob(io
->ac
, old_scp
->data
);
611 return LDB_ERR_OPERATIONS_ERROR
;
614 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
615 ndr_err
= ndr_pull_struct_blob(&blob
, io
->ac
,
616 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
618 (ndr_pull_flags_fn_t
)ndr_pull_package_PrimaryKerberosBlob
);
619 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
620 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
621 ldb_asprintf_errstring(ldb
,
622 "setup_primary_kerberos_newer: "
623 "failed to pull old package_PrimaryKerberosBlob: %s",
625 return LDB_ERR_OPERATIONS_ERROR
;
628 if (_old_pkb
.version
!= 4) {
629 ldb_asprintf_errstring(ldb
,
630 "setup_primary_kerberos_newer: "
631 "package_PrimaryKerberosBlob version[%u] expected[4]",
633 return LDB_ERR_OPERATIONS_ERROR
;
636 old_pkb4
= &_old_pkb
.ctr
.ctr4
;
639 /* if we didn't found the old keys we're done */
644 /* fill in the old keys */
645 pkb4
->num_old_keys
= old_pkb4
->num_keys
;
646 pkb4
->old_keys
= old_pkb4
->keys
;
647 pkb4
->num_older_keys
= old_pkb4
->num_old_keys
;
648 pkb4
->older_keys
= old_pkb4
->old_keys
;
653 static int setup_primary_wdigest(struct setup_password_fields_io
*io
,
654 const struct supplementalCredentialsBlob
*old_scb
,
655 struct package_PrimaryWDigestBlob
*pdb
)
657 struct ldb_context
*ldb
= ldb_module_get_ctx(io
->ac
->module
);
658 DATA_BLOB sAMAccountName
;
659 DATA_BLOB sAMAccountName_l
;
660 DATA_BLOB sAMAccountName_u
;
661 const char *user_principal_name
= io
->u
.user_principal_name
;
662 DATA_BLOB userPrincipalName
;
663 DATA_BLOB userPrincipalName_l
;
664 DATA_BLOB userPrincipalName_u
;
665 DATA_BLOB netbios_domain
;
666 DATA_BLOB netbios_domain_l
;
667 DATA_BLOB netbios_domain_u
;
668 DATA_BLOB dns_domain
;
669 DATA_BLOB dns_domain_l
;
670 DATA_BLOB dns_domain_u
;
682 * http://technet2.microsoft.com/WindowsServer/en/library/717b450c-f4a0-4cc9-86f4-cc0633aae5f91033.mspx?mfr=true
683 * for what precalculated hashes are supposed to be stored...
685 * I can't reproduce all values which should contain "Digest" as realm,
686 * am I doing something wrong or is w2k3 just broken...?
688 * W2K3 fills in following for a user:
690 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
691 * sAMAccountName: NewUser2Sam
692 * userPrincipalName: NewUser2Princ@sub1.w2k3.vmnet1.vm.base
694 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
695 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
696 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
697 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
698 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
699 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
700 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
701 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
702 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
703 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
704 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
705 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
706 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
707 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
708 * 221c55284451ae9b3aacaa2a3c86f10f => NewUser2Princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
709 * 74e1be668853d4324d38c07e2acfb8ea => (w2k3 has a bug here!) newuser2princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
710 * e1e244ab7f098e3ae1761be7f9229bbb => NEWUSER2PRINC@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
711 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
712 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
713 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
714 * 31dc704d3640335b2123d4ee28aa1f11 => ??? changes with NewUser2Sam => NewUser1Sam
715 * 36349f5cecd07320fb3bb0e119230c43 => ??? changes with NewUser2Sam => NewUser1Sam
716 * 12adf019d037fb535c01fd0608e78d9d => ??? changes with NewUser2Sam => NewUser1Sam
717 * 6feecf8e724906f3ee1105819c5105a1 => ??? changes with NewUser2Princ => NewUser1Princ
718 * 6c6911f3de6333422640221b9c51ff1f => ??? changes with NewUser2Princ => NewUser1Princ
719 * 4b279877e742895f9348ac67a8de2f69 => ??? changes with NewUser2Princ => NewUser1Princ
720 * db0c6bff069513e3ebb9870d29b57490 => ??? changes with NewUser2Sam => NewUser1Sam
721 * 45072621e56b1c113a4e04a8ff68cd0e => ??? changes with NewUser2Sam => NewUser1Sam
722 * 11d1220abc44a9c10cf91ef4a9c1de02 => ??? changes with NewUser2Sam => NewUser1Sam
724 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
725 * sAMAccountName: NewUser2Sam
727 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
728 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
729 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
730 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
731 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
732 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
733 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
734 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
735 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
736 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
737 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
738 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
739 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
740 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
741 * 8a140d30b6f0a5912735dc1e3bc993b4 => NewUser2Sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
742 * 86d95b2faae6cae4ec261e7fbaccf093 => (here w2k3 is correct) newuser2sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
743 * dfeff1493110220efcdfc6362e5f5450 => NEWUSER2SAM@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
744 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
745 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
746 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
747 * 31dc704d3640335b2123d4ee28aa1f11 => ???M1 changes with NewUser2Sam => NewUser1Sam
748 * 36349f5cecd07320fb3bb0e119230c43 => ???M1.L changes with newuser2sam => newuser1sam
749 * 12adf019d037fb535c01fd0608e78d9d => ???M1.U changes with NEWUSER2SAM => NEWUSER1SAM
750 * 569b4533f2d9e580211dd040e5e360a8 => ???M2 changes with NewUser2Princ => NewUser1Princ
751 * 52528bddf310a587c5d7e6a9ae2cbb20 => ???M2.L changes with newuser2princ => newuser1princ
752 * 4f629a4f0361289ca4255ab0f658fcd5 => ???M3 changes with NewUser2Princ => NewUser1Princ (doesn't depend on case of userPrincipal )
753 * db0c6bff069513e3ebb9870d29b57490 => ???M4 changes with NewUser2Sam => NewUser1Sam
754 * 45072621e56b1c113a4e04a8ff68cd0e => ???M5 changes with NewUser2Sam => NewUser1Sam (doesn't depend on case of sAMAccountName)
755 * 11d1220abc44a9c10cf91ef4a9c1de02 => ???M4.U changes with NEWUSER2SAM => NEWUSER1SAM
759 * sAMAccountName, netbios_domain
762 .user
= &sAMAccountName
,
763 .realm
= &netbios_domain
,
766 .user
= &sAMAccountName_l
,
767 .realm
= &netbios_domain_l
,
770 .user
= &sAMAccountName_u
,
771 .realm
= &netbios_domain_u
,
774 .user
= &sAMAccountName
,
775 .realm
= &netbios_domain_u
,
778 .user
= &sAMAccountName
,
779 .realm
= &netbios_domain_l
,
782 .user
= &sAMAccountName_u
,
783 .realm
= &netbios_domain_l
,
786 .user
= &sAMAccountName_l
,
787 .realm
= &netbios_domain_u
,
790 * sAMAccountName, dns_domain
793 .user
= &sAMAccountName
,
794 .realm
= &dns_domain
,
797 .user
= &sAMAccountName_l
,
798 .realm
= &dns_domain_l
,
801 .user
= &sAMAccountName_u
,
802 .realm
= &dns_domain_u
,
805 .user
= &sAMAccountName
,
806 .realm
= &dns_domain_u
,
809 .user
= &sAMAccountName
,
810 .realm
= &dns_domain_l
,
813 .user
= &sAMAccountName_u
,
814 .realm
= &dns_domain_l
,
817 .user
= &sAMAccountName_l
,
818 .realm
= &dns_domain_u
,
821 * userPrincipalName, no realm
824 .user
= &userPrincipalName
,
828 * NOTE: w2k3 messes this up, if the user has a real userPrincipalName,
829 * the fallback to the sAMAccountName based userPrincipalName is correct
831 .user
= &userPrincipalName_l
,
834 .user
= &userPrincipalName_u
,
837 * nt4dom\sAMAccountName, no realm
840 .user
= &sAMAccountName
,
841 .nt4dom
= &netbios_domain
844 .user
= &sAMAccountName_l
,
845 .nt4dom
= &netbios_domain_l
848 .user
= &sAMAccountName_u
,
849 .nt4dom
= &netbios_domain_u
853 * the following ones are guessed depending on the technet2 article
854 * but not reproducable on a w2k3 server
856 /* sAMAccountName with "Digest" realm */
858 .user
= &sAMAccountName
,
862 .user
= &sAMAccountName_l
,
866 .user
= &sAMAccountName_u
,
869 /* userPrincipalName with "Digest" realm */
871 .user
= &userPrincipalName
,
875 .user
= &userPrincipalName_l
,
879 .user
= &userPrincipalName_u
,
882 /* nt4dom\\sAMAccountName with "Digest" realm */
884 .user
= &sAMAccountName
,
885 .nt4dom
= &netbios_domain
,
889 .user
= &sAMAccountName_l
,
890 .nt4dom
= &netbios_domain_l
,
894 .user
= &sAMAccountName_u
,
895 .nt4dom
= &netbios_domain_u
,
900 /* prepare DATA_BLOB's used in the combinations array */
901 sAMAccountName
= data_blob_string_const(io
->u
.sAMAccountName
);
902 sAMAccountName_l
= data_blob_string_const(strlower_talloc(io
->ac
, io
->u
.sAMAccountName
));
903 if (!sAMAccountName_l
.data
) {
905 return LDB_ERR_OPERATIONS_ERROR
;
907 sAMAccountName_u
= data_blob_string_const(strupper_talloc(io
->ac
, io
->u
.sAMAccountName
));
908 if (!sAMAccountName_u
.data
) {
910 return LDB_ERR_OPERATIONS_ERROR
;
913 /* if the user doesn't have a userPrincipalName, create one (with lower case realm) */
914 if (!user_principal_name
) {
915 user_principal_name
= talloc_asprintf(io
->ac
, "%s@%s",
916 io
->u
.sAMAccountName
,
917 io
->domain
->dns_domain
);
918 if (!user_principal_name
) {
920 return LDB_ERR_OPERATIONS_ERROR
;
923 userPrincipalName
= data_blob_string_const(user_principal_name
);
924 userPrincipalName_l
= data_blob_string_const(strlower_talloc(io
->ac
, user_principal_name
));
925 if (!userPrincipalName_l
.data
) {
927 return LDB_ERR_OPERATIONS_ERROR
;
929 userPrincipalName_u
= data_blob_string_const(strupper_talloc(io
->ac
, user_principal_name
));
930 if (!userPrincipalName_u
.data
) {
932 return LDB_ERR_OPERATIONS_ERROR
;
935 netbios_domain
= data_blob_string_const(io
->domain
->netbios_domain
);
936 netbios_domain_l
= data_blob_string_const(strlower_talloc(io
->ac
, io
->domain
->netbios_domain
));
937 if (!netbios_domain_l
.data
) {
939 return LDB_ERR_OPERATIONS_ERROR
;
941 netbios_domain_u
= data_blob_string_const(strupper_talloc(io
->ac
, io
->domain
->netbios_domain
));
942 if (!netbios_domain_u
.data
) {
944 return LDB_ERR_OPERATIONS_ERROR
;
947 dns_domain
= data_blob_string_const(io
->domain
->dns_domain
);
948 dns_domain_l
= data_blob_string_const(io
->domain
->dns_domain
);
949 dns_domain_u
= data_blob_string_const(io
->domain
->realm
);
951 digest
= data_blob_string_const("Digest");
953 delim
= data_blob_string_const(":");
954 backslash
= data_blob_string_const("\\");
956 pdb
->num_hashes
= ARRAY_SIZE(wdigest
);
957 pdb
->hashes
= talloc_array(io
->ac
, struct package_PrimaryWDigestHash
, pdb
->num_hashes
);
960 return LDB_ERR_OPERATIONS_ERROR
;
963 for (i
=0; i
< ARRAY_SIZE(wdigest
); i
++) {
964 struct MD5Context md5
;
966 if (wdigest
[i
].nt4dom
) {
967 MD5Update(&md5
, wdigest
[i
].nt4dom
->data
, wdigest
[i
].nt4dom
->length
);
968 MD5Update(&md5
, backslash
.data
, backslash
.length
);
970 MD5Update(&md5
, wdigest
[i
].user
->data
, wdigest
[i
].user
->length
);
971 MD5Update(&md5
, delim
.data
, delim
.length
);
972 if (wdigest
[i
].realm
) {
973 MD5Update(&md5
, wdigest
[i
].realm
->data
, wdigest
[i
].realm
->length
);
975 MD5Update(&md5
, delim
.data
, delim
.length
);
976 MD5Update(&md5
, io
->n
.cleartext_utf8
->data
, io
->n
.cleartext_utf8
->length
);
977 MD5Final(pdb
->hashes
[i
].hash
, &md5
);
983 static int setup_supplemental_field(struct setup_password_fields_io
*io
)
985 struct ldb_context
*ldb
;
986 struct supplementalCredentialsBlob scb
;
987 struct supplementalCredentialsBlob _old_scb
;
988 struct supplementalCredentialsBlob
*old_scb
= NULL
;
989 /* Packages + (Kerberos-Newer-Keys, Kerberos, WDigest and CLEARTEXT) */
990 uint32_t num_names
= 0;
991 const char *names
[1+4];
992 uint32_t num_packages
= 0;
993 struct supplementalCredentialsPackage packages
[1+4];
995 struct supplementalCredentialsPackage
*pp
= NULL
;
996 struct package_PackagesBlob pb
;
999 /* Primary:Kerberos-Newer-Keys */
1000 const char **nkn
= NULL
;
1001 struct supplementalCredentialsPackage
*pkn
= NULL
;
1002 struct package_PrimaryKerberosBlob pknb
;
1003 DATA_BLOB pknb_blob
;
1005 /* Primary:Kerberos */
1006 const char **nk
= NULL
;
1007 struct supplementalCredentialsPackage
*pk
= NULL
;
1008 struct package_PrimaryKerberosBlob pkb
;
1011 /* Primary:WDigest */
1012 const char **nd
= NULL
;
1013 struct supplementalCredentialsPackage
*pd
= NULL
;
1014 struct package_PrimaryWDigestBlob pdb
;
1017 /* Primary:CLEARTEXT */
1018 const char **nc
= NULL
;
1019 struct supplementalCredentialsPackage
*pc
= NULL
;
1020 struct package_PrimaryCLEARTEXTBlob pcb
;
1024 enum ndr_err_code ndr_err
;
1026 bool do_newer_keys
= false;
1027 bool do_cleartext
= false;
1028 int *domainFunctionality
;
1030 ZERO_STRUCT(zero16
);
1033 ldb
= ldb_module_get_ctx(io
->ac
->module
);
1035 if (!io
->n
.cleartext_utf8
) {
1037 * when we don't have a cleartext password
1038 * we can't setup a supplementalCredential value
1043 /* if there's an old supplementaCredentials blob then parse it */
1044 if (io
->o
.supplemental
) {
1045 ndr_err
= ndr_pull_struct_blob_all(io
->o
.supplemental
, io
->ac
,
1046 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1048 (ndr_pull_flags_fn_t
)ndr_pull_supplementalCredentialsBlob
);
1049 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1050 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1051 ldb_asprintf_errstring(ldb
,
1052 "setup_supplemental_field: "
1053 "failed to pull old supplementalCredentialsBlob: %s",
1055 return LDB_ERR_OPERATIONS_ERROR
;
1058 if (_old_scb
.sub
.signature
== SUPPLEMENTAL_CREDENTIALS_SIGNATURE
) {
1059 old_scb
= &_old_scb
;
1061 ldb_debug(ldb
, LDB_DEBUG_ERROR
,
1062 "setup_supplemental_field: "
1063 "supplementalCredentialsBlob signature[0x%04X] expected[0x%04X]",
1064 _old_scb
.sub
.signature
, SUPPLEMENTAL_CREDENTIALS_SIGNATURE
);
1067 /* Per MS-SAMR 3.1.1.8.11.6 we create AES keys if our domain functionality level is 2008 or higher */
1068 domainFunctionality
= talloc_get_type(ldb_get_opaque(ldb
, "domainFunctionality"), int);
1070 do_newer_keys
= *domainFunctionality
&&
1071 (*domainFunctionality
>= DS_DOMAIN_FUNCTION_2008
);
1073 if (io
->domain
->store_cleartext
&&
1074 (io
->u
.user_account_control
& UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED
)) {
1075 do_cleartext
= true;
1079 * The ordering is this
1081 * Primary:Kerberos-Newer-Keys (optional)
1084 * Primary:CLEARTEXT (optional)
1086 * And the 'Packages' package is insert before the last
1089 if (do_newer_keys
) {
1090 /* Primary:Kerberos-Newer-Keys */
1091 nkn
= &names
[num_names
++];
1092 pkn
= &packages
[num_packages
++];
1095 /* Primary:Kerberos */
1096 nk
= &names
[num_names
++];
1097 pk
= &packages
[num_packages
++];
1099 if (!do_cleartext
) {
1101 pp
= &packages
[num_packages
++];
1104 /* Primary:WDigest */
1105 nd
= &names
[num_names
++];
1106 pd
= &packages
[num_packages
++];
1110 pp
= &packages
[num_packages
++];
1112 /* Primary:CLEARTEXT */
1113 nc
= &names
[num_names
++];
1114 pc
= &packages
[num_packages
++];
1119 * setup 'Primary:Kerberos-Newer-Keys' element
1121 *nkn
= "Kerberos-Newer-Keys";
1123 ret
= setup_primary_kerberos_newer(io
, old_scb
, &pknb
);
1124 if (ret
!= LDB_SUCCESS
) {
1128 ndr_err
= ndr_push_struct_blob(&pknb_blob
, io
->ac
,
1129 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1131 (ndr_push_flags_fn_t
)ndr_push_package_PrimaryKerberosBlob
);
1132 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1133 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1134 ldb_asprintf_errstring(ldb
,
1135 "setup_supplemental_field: "
1136 "failed to push package_PrimaryKerberosNeverBlob: %s",
1138 return LDB_ERR_OPERATIONS_ERROR
;
1140 pknb_hexstr
= data_blob_hex_string_upper(io
->ac
, &pknb_blob
);
1143 return LDB_ERR_OPERATIONS_ERROR
;
1145 pkn
->name
= "Primary:Kerberos-Newer-Keys";
1147 pkn
->data
= pknb_hexstr
;
1151 * setup 'Primary:Kerberos' element
1155 ret
= setup_primary_kerberos(io
, old_scb
, &pkb
);
1156 if (ret
!= LDB_SUCCESS
) {
1160 ndr_err
= ndr_push_struct_blob(&pkb_blob
, io
->ac
,
1161 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1163 (ndr_push_flags_fn_t
)ndr_push_package_PrimaryKerberosBlob
);
1164 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1165 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1166 ldb_asprintf_errstring(ldb
,
1167 "setup_supplemental_field: "
1168 "failed to push package_PrimaryKerberosBlob: %s",
1170 return LDB_ERR_OPERATIONS_ERROR
;
1172 pkb_hexstr
= data_blob_hex_string_upper(io
->ac
, &pkb_blob
);
1175 return LDB_ERR_OPERATIONS_ERROR
;
1177 pk
->name
= "Primary:Kerberos";
1179 pk
->data
= pkb_hexstr
;
1182 * setup 'Primary:WDigest' element
1186 ret
= setup_primary_wdigest(io
, old_scb
, &pdb
);
1187 if (ret
!= LDB_SUCCESS
) {
1191 ndr_err
= ndr_push_struct_blob(&pdb_blob
, io
->ac
,
1192 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1194 (ndr_push_flags_fn_t
)ndr_push_package_PrimaryWDigestBlob
);
1195 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1196 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1197 ldb_asprintf_errstring(ldb
,
1198 "setup_supplemental_field: "
1199 "failed to push package_PrimaryWDigestBlob: %s",
1201 return LDB_ERR_OPERATIONS_ERROR
;
1203 pdb_hexstr
= data_blob_hex_string_upper(io
->ac
, &pdb_blob
);
1206 return LDB_ERR_OPERATIONS_ERROR
;
1208 pd
->name
= "Primary:WDigest";
1210 pd
->data
= pdb_hexstr
;
1213 * setup 'Primary:CLEARTEXT' element
1218 pcb
.cleartext
= *io
->n
.cleartext_utf16
;
1220 ndr_err
= ndr_push_struct_blob(&pcb_blob
, io
->ac
,
1221 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1223 (ndr_push_flags_fn_t
)ndr_push_package_PrimaryCLEARTEXTBlob
);
1224 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1225 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1226 ldb_asprintf_errstring(ldb
,
1227 "setup_supplemental_field: "
1228 "failed to push package_PrimaryCLEARTEXTBlob: %s",
1230 return LDB_ERR_OPERATIONS_ERROR
;
1232 pcb_hexstr
= data_blob_hex_string_upper(io
->ac
, &pcb_blob
);
1235 return LDB_ERR_OPERATIONS_ERROR
;
1237 pc
->name
= "Primary:CLEARTEXT";
1239 pc
->data
= pcb_hexstr
;
1243 * setup 'Packages' element
1246 ndr_err
= ndr_push_struct_blob(&pb_blob
, io
->ac
,
1247 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1249 (ndr_push_flags_fn_t
)ndr_push_package_PackagesBlob
);
1250 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1251 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1252 ldb_asprintf_errstring(ldb
,
1253 "setup_supplemental_field: "
1254 "failed to push package_PackagesBlob: %s",
1256 return LDB_ERR_OPERATIONS_ERROR
;
1258 pb_hexstr
= data_blob_hex_string_upper(io
->ac
, &pb_blob
);
1261 return LDB_ERR_OPERATIONS_ERROR
;
1263 pp
->name
= "Packages";
1265 pp
->data
= pb_hexstr
;
1268 * setup 'supplementalCredentials' value
1271 scb
.sub
.num_packages
= num_packages
;
1272 scb
.sub
.packages
= packages
;
1274 ndr_err
= ndr_push_struct_blob(&io
->g
.supplemental
, io
->ac
,
1275 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1277 (ndr_push_flags_fn_t
)ndr_push_supplementalCredentialsBlob
);
1278 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1279 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1280 ldb_asprintf_errstring(ldb
,
1281 "setup_supplemental_field: "
1282 "failed to push supplementalCredentialsBlob: %s",
1284 return LDB_ERR_OPERATIONS_ERROR
;
1290 static int setup_last_set_field(struct setup_password_fields_io
*io
)
1293 unix_to_nt_time(&io
->g
.last_set
, time(NULL
));
1298 static int setup_kvno_field(struct setup_password_fields_io
*io
)
1300 /* increment by one */
1301 io
->g
.kvno
= io
->o
.kvno
+ 1;
1306 static int setup_password_fields(struct setup_password_fields_io
*io
)
1308 struct ldb_context
*ldb
;
1311 size_t converted_pw_len
;
1313 ldb
= ldb_module_get_ctx(io
->ac
->module
);
1316 * refuse the change if someone want to change the cleartext
1317 * and supply his own hashes at the same time...
1319 if ((io
->n
.cleartext_utf8
|| io
->n
.cleartext_utf16
) && (io
->n
.nt_hash
|| io
->n
.lm_hash
)) {
1320 ldb_asprintf_errstring(ldb
,
1321 "setup_password_fields: "
1322 "it's only allowed to set the cleartext password or the password hashes");
1323 return LDB_ERR_UNWILLING_TO_PERFORM
;
1326 if (io
->n
.cleartext_utf8
&& io
->n
.cleartext_utf16
) {
1327 ldb_asprintf_errstring(ldb
,
1328 "setup_password_fields: "
1329 "it's only allowed to set the cleartext password as userPassword or clearTextPasssword, not both at once");
1330 return LDB_ERR_UNWILLING_TO_PERFORM
;
1333 if (io
->n
.cleartext_utf8
) {
1334 char **cleartext_utf16_str
;
1335 struct ldb_val
*cleartext_utf16_blob
;
1336 io
->n
.cleartext_utf16
= cleartext_utf16_blob
= talloc(io
->ac
, struct ldb_val
);
1337 if (!io
->n
.cleartext_utf16
) {
1339 return LDB_ERR_OPERATIONS_ERROR
;
1341 if (!convert_string_talloc_convenience(io
->ac
, lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1342 CH_UTF8
, CH_UTF16
, io
->n
.cleartext_utf8
->data
, io
->n
.cleartext_utf8
->length
,
1343 (void **)&cleartext_utf16_str
, &converted_pw_len
, false)) {
1344 ldb_asprintf_errstring(ldb
,
1345 "setup_password_fields: "
1346 "failed to generate UTF16 password from cleartext UTF8 password");
1347 return LDB_ERR_OPERATIONS_ERROR
;
1349 *cleartext_utf16_blob
= data_blob_const(cleartext_utf16_str
, converted_pw_len
);
1350 } else if (io
->n
.cleartext_utf16
) {
1351 char *cleartext_utf8_str
;
1352 struct ldb_val
*cleartext_utf8_blob
;
1353 io
->n
.cleartext_utf8
= cleartext_utf8_blob
= talloc(io
->ac
, struct ldb_val
);
1354 if (!io
->n
.cleartext_utf8
) {
1356 return LDB_ERR_OPERATIONS_ERROR
;
1358 if (!convert_string_talloc_convenience(io
->ac
, lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1359 CH_UTF16MUNGED
, CH_UTF8
, io
->n
.cleartext_utf16
->data
, io
->n
.cleartext_utf16
->length
,
1360 (void **)&cleartext_utf8_str
, &converted_pw_len
, false)) {
1361 /* We can't bail out entirely, as these unconvertable passwords are frustratingly valid */
1362 io
->n
.cleartext_utf8
= NULL
;
1363 talloc_free(cleartext_utf8_blob
);
1365 *cleartext_utf8_blob
= data_blob_const(cleartext_utf8_str
, converted_pw_len
);
1367 if (io
->n
.cleartext_utf16
) {
1368 struct samr_Password
*nt_hash
;
1369 nt_hash
= talloc(io
->ac
, struct samr_Password
);
1372 return LDB_ERR_OPERATIONS_ERROR
;
1374 io
->n
.nt_hash
= nt_hash
;
1376 /* compute the new nt hash */
1377 mdfour(nt_hash
->hash
, io
->n
.cleartext_utf16
->data
, io
->n
.cleartext_utf16
->length
);
1380 if (io
->n
.cleartext_utf8
) {
1381 struct samr_Password
*lm_hash
;
1382 char *cleartext_unix
;
1383 if (lp_lanman_auth(ldb_get_opaque(ldb
, "loadparm")) &&
1384 convert_string_talloc_convenience(io
->ac
, lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1385 CH_UTF8
, CH_UNIX
, io
->n
.cleartext_utf8
->data
, io
->n
.cleartext_utf8
->length
,
1386 (void **)&cleartext_unix
, &converted_pw_len
, false)) {
1387 lm_hash
= talloc(io
->ac
, struct samr_Password
);
1390 return LDB_ERR_OPERATIONS_ERROR
;
1393 /* compute the new lm hash. */
1394 ok
= E_deshash((char *)cleartext_unix
, lm_hash
->hash
);
1396 io
->n
.lm_hash
= lm_hash
;
1398 talloc_free(lm_hash
->hash
);
1402 ret
= setup_kerberos_keys(io
);
1403 if (ret
!= LDB_SUCCESS
) {
1408 ret
= setup_nt_fields(io
);
1409 if (ret
!= LDB_SUCCESS
) {
1413 ret
= setup_lm_fields(io
);
1414 if (ret
!= LDB_SUCCESS
) {
1418 ret
= setup_supplemental_field(io
);
1419 if (ret
!= LDB_SUCCESS
) {
1423 ret
= setup_last_set_field(io
);
1424 if (ret
!= LDB_SUCCESS
) {
1428 ret
= setup_kvno_field(io
);
1429 if (ret
!= LDB_SUCCESS
) {
1436 static int setup_io(struct ph_context
*ac
,
1437 const struct ldb_message
*new_msg
,
1438 const struct ldb_message
*searched_msg
,
1439 struct setup_password_fields_io
*io
)
1441 const struct ldb_val
*quoted_utf16
;
1442 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
1446 /* Some operations below require kerberos contexts */
1447 if (smb_krb5_init_context(ac
,
1448 ldb_get_event_context(ldb
),
1449 (struct loadparm_context
*)ldb_get_opaque(ldb
, "loadparm"),
1450 &io
->smb_krb5_context
) != 0) {
1451 return LDB_ERR_OPERATIONS_ERROR
;
1455 io
->domain
= ac
->domain
;
1457 io
->u
.user_account_control
= samdb_result_uint(searched_msg
, "userAccountControl", 0);
1458 io
->u
.sAMAccountName
= samdb_result_string(searched_msg
, "samAccountName", NULL
);
1459 io
->u
.user_principal_name
= samdb_result_string(searched_msg
, "userPrincipalName", NULL
);
1460 io
->u
.is_computer
= ldb_msg_check_string_attribute(searched_msg
, "objectClass", "computer");
1462 io
->n
.cleartext_utf8
= ldb_msg_find_ldb_val(new_msg
, "userPassword");
1463 io
->n
.cleartext_utf16
= ldb_msg_find_ldb_val(new_msg
, "clearTextPassword");
1465 /* this rather strange looking piece of code is there to
1466 handle a ldap client setting a password remotely using the
1467 unicodePwd ldap field. The syntax is that the password is
1468 in UTF-16LE, with a " at either end. Unfortunately the
1469 unicodePwd field is also used to store the nt hashes
1470 internally in Samba, and is used in the nt hash format on
1471 the wire in DRS replication, so we have a single name for
1472 two distinct values. The code below leaves us with a small
1473 chance (less than 1 in 2^32) of a mixup, if someone manages
1474 to create a MD4 hash which starts and ends in 0x22 0x00, as
1475 that would then be treated as a UTF16 password rather than
1477 quoted_utf16
= ldb_msg_find_ldb_val(new_msg
, "unicodePwd");
1479 quoted_utf16
->length
>= 4 &&
1480 quoted_utf16
->data
[0] == '"' &&
1481 quoted_utf16
->data
[1] == 0 &&
1482 quoted_utf16
->data
[quoted_utf16
->length
-2] == '"' &&
1483 quoted_utf16
->data
[quoted_utf16
->length
-1] == 0) {
1484 io
->n
.quoted_utf16
.data
= talloc_memdup(io
->ac
, quoted_utf16
->data
+2, quoted_utf16
->length
-4);
1485 io
->n
.quoted_utf16
.length
= quoted_utf16
->length
-4;
1486 io
->n
.cleartext_utf16
= &io
->n
.quoted_utf16
;
1487 io
->n
.nt_hash
= NULL
;
1489 io
->n
.nt_hash
= samdb_result_hash(io
->ac
, new_msg
, "unicodePwd");
1492 io
->n
.lm_hash
= samdb_result_hash(io
->ac
, new_msg
, "dBCSPwd");
1497 static struct ph_context
*ph_init_context(struct ldb_module
*module
,
1498 struct ldb_request
*req
)
1500 struct ldb_context
*ldb
;
1501 struct ph_context
*ac
;
1503 ldb
= ldb_module_get_ctx(module
);
1505 ac
= talloc_zero(req
, struct ph_context
);
1507 ldb_set_errstring(ldb
, "Out of Memory");
1511 ac
->module
= module
;
1517 static int ph_op_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
1519 struct ph_context
*ac
;
1521 ac
= talloc_get_type(req
->context
, struct ph_context
);
1524 return ldb_module_done(ac
->req
, NULL
, NULL
,
1525 LDB_ERR_OPERATIONS_ERROR
);
1527 if (ares
->error
!= LDB_SUCCESS
) {
1528 return ldb_module_done(ac
->req
, ares
->controls
,
1529 ares
->response
, ares
->error
);
1532 if (ares
->type
!= LDB_REPLY_DONE
) {
1534 return ldb_module_done(ac
->req
, NULL
, NULL
,
1535 LDB_ERR_OPERATIONS_ERROR
);
1538 return ldb_module_done(ac
->req
, ares
->controls
,
1539 ares
->response
, ares
->error
);
1542 static int password_hash_add_do_add(struct ph_context
*ac
);
1543 static int ph_modify_callback(struct ldb_request
*req
, struct ldb_reply
*ares
);
1544 static int password_hash_mod_search_self(struct ph_context
*ac
);
1545 static int ph_mod_search_callback(struct ldb_request
*req
, struct ldb_reply
*ares
);
1546 static int password_hash_mod_do_mod(struct ph_context
*ac
);
1548 static int get_domain_data_callback(struct ldb_request
*req
,
1549 struct ldb_reply
*ares
)
1551 struct ldb_context
*ldb
;
1552 struct domain_data
*data
;
1553 struct ph_context
*ac
;
1554 struct loadparm_context
*lp_ctx
;
1557 ac
= talloc_get_type(req
->context
, struct ph_context
);
1558 ldb
= ldb_module_get_ctx(ac
->module
);
1561 return ldb_module_done(ac
->req
, NULL
, NULL
,
1562 LDB_ERR_OPERATIONS_ERROR
);
1564 if (ares
->error
!= LDB_SUCCESS
) {
1565 return ldb_module_done(ac
->req
, ares
->controls
,
1566 ares
->response
, ares
->error
);
1569 switch (ares
->type
) {
1570 case LDB_REPLY_ENTRY
:
1571 if (ac
->domain
!= NULL
) {
1572 ldb_set_errstring(ldb
, "Too many results");
1573 return ldb_module_done(ac
->req
, NULL
, NULL
,
1574 LDB_ERR_OPERATIONS_ERROR
);
1577 data
= talloc_zero(ac
, struct domain_data
);
1579 return ldb_module_done(ac
->req
, NULL
, NULL
,
1580 LDB_ERR_OPERATIONS_ERROR
);
1583 data
->pwdProperties
= samdb_result_uint(ares
->message
, "pwdProperties", 0);
1584 data
->store_cleartext
= data
->pwdProperties
& DOMAIN_PASSWORD_STORE_CLEARTEXT
;
1585 data
->pwdHistoryLength
= samdb_result_uint(ares
->message
, "pwdHistoryLength", 0);
1587 /* For a domain DN, this puts things in dotted notation */
1588 /* For builtin domains, this will give details for the host,
1589 * but that doesn't really matter, as it's just used for salt
1590 * and kerberos principals, which don't exist here */
1592 lp_ctx
= talloc_get_type(ldb_get_opaque(ldb
, "loadparm"),
1593 struct loadparm_context
);
1595 data
->dns_domain
= lp_dnsdomain(lp_ctx
);
1596 data
->realm
= lp_realm(lp_ctx
);
1597 data
->netbios_domain
= lp_sam_name(lp_ctx
);
1602 case LDB_REPLY_DONE
:
1604 /* call the next step */
1605 switch (ac
->req
->operation
) {
1607 ret
= password_hash_add_do_add(ac
);
1611 ret
= password_hash_mod_do_mod(ac
);
1615 ret
= LDB_ERR_OPERATIONS_ERROR
;
1618 if (ret
!= LDB_SUCCESS
) {
1619 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
1623 case LDB_REPLY_REFERRAL
:
1632 static int build_domain_data_request(struct ph_context
*ac
)
1634 /* attrs[] is returned from this function in
1635 ac->dom_req->op.search.attrs, so it must be static, as
1636 otherwise the compiler can put it on the stack */
1637 struct ldb_context
*ldb
;
1638 static const char * const attrs
[] = { "pwdProperties", "pwdHistoryLength", NULL
};
1640 ldb
= ldb_module_get_ctx(ac
->module
);
1642 return ldb_build_search_req(&ac
->dom_req
, ldb
, ac
,
1643 ldb_get_default_basedn(ldb
),
1647 ac
, get_domain_data_callback
,
1651 static int password_hash_add(struct ldb_module
*module
, struct ldb_request
*req
)
1653 struct ldb_context
*ldb
;
1654 struct ph_context
*ac
;
1655 struct ldb_message_element
*sambaAttr
;
1656 struct ldb_message_element
*clearTextPasswordAttr
;
1657 struct ldb_message_element
*ntAttr
;
1658 struct ldb_message_element
*lmAttr
;
1661 ldb
= ldb_module_get_ctx(module
);
1663 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "password_hash_add\n");
1665 if (ldb_dn_is_special(req
->op
.add
.message
->dn
)) { /* do not manipulate our control entries */
1666 return ldb_next_request(module
, req
);
1669 /* If the caller is manipulating the local passwords directly, let them pass */
1670 if (ldb_dn_compare_base(ldb_dn_new(req
, ldb
, LOCAL_BASE
),
1671 req
->op
.add
.message
->dn
) == 0) {
1672 return ldb_next_request(module
, req
);
1675 /* nobody must touch these fields */
1676 if (ldb_msg_find_element(req
->op
.add
.message
, "ntPwdHistory")) {
1677 return LDB_ERR_UNWILLING_TO_PERFORM
;
1679 if (ldb_msg_find_element(req
->op
.add
.message
, "lmPwdHistory")) {
1680 return LDB_ERR_UNWILLING_TO_PERFORM
;
1682 if (ldb_msg_find_element(req
->op
.add
.message
, "supplementalCredentials")) {
1683 return LDB_ERR_UNWILLING_TO_PERFORM
;
1686 /* If no part of this ADD touches the userPassword, or the NT
1687 * or LM hashes, then we don't need to make any changes. */
1689 sambaAttr
= ldb_msg_find_element(req
->op
.mod
.message
, "userPassword");
1690 clearTextPasswordAttr
= ldb_msg_find_element(req
->op
.mod
.message
, "clearTextPassword");
1691 ntAttr
= ldb_msg_find_element(req
->op
.mod
.message
, "unicodePwd");
1692 lmAttr
= ldb_msg_find_element(req
->op
.mod
.message
, "dBCSPwd");
1694 if ((!sambaAttr
) && (!clearTextPasswordAttr
) && (!ntAttr
) && (!lmAttr
)) {
1695 return ldb_next_request(module
, req
);
1698 /* if it is not an entry of type person its an error */
1699 /* TODO: remove this when userPassword will be in schema */
1700 if (!ldb_msg_check_string_attribute(req
->op
.add
.message
, "objectClass", "person")) {
1701 ldb_set_errstring(ldb
, "Cannot set a password on entry that does not have objectClass 'person'");
1702 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
1705 /* check userPassword is single valued here */
1706 /* TODO: remove this when userPassword will be single valued in schema */
1707 if (sambaAttr
&& sambaAttr
->num_values
> 1) {
1708 ldb_set_errstring(ldb
, "mupltiple values for userPassword not allowed!\n");
1709 return LDB_ERR_CONSTRAINT_VIOLATION
;
1711 if (clearTextPasswordAttr
&& clearTextPasswordAttr
->num_values
> 1) {
1712 ldb_set_errstring(ldb
, "mupltiple values for clearTextPassword not allowed!\n");
1713 return LDB_ERR_CONSTRAINT_VIOLATION
;
1716 if (ntAttr
&& (ntAttr
->num_values
> 1)) {
1717 ldb_set_errstring(ldb
, "mupltiple values for unicodePwd not allowed!\n");
1718 return LDB_ERR_CONSTRAINT_VIOLATION
;
1720 if (lmAttr
&& (lmAttr
->num_values
> 1)) {
1721 ldb_set_errstring(ldb
, "mupltiple values for dBCSPwd not allowed!\n");
1722 return LDB_ERR_CONSTRAINT_VIOLATION
;
1725 if (sambaAttr
&& sambaAttr
->num_values
== 0) {
1726 ldb_set_errstring(ldb
, "userPassword must have a value!\n");
1727 return LDB_ERR_CONSTRAINT_VIOLATION
;
1730 if (clearTextPasswordAttr
&& clearTextPasswordAttr
->num_values
== 0) {
1731 ldb_set_errstring(ldb
, "clearTextPassword must have a value!\n");
1732 return LDB_ERR_CONSTRAINT_VIOLATION
;
1735 if (ntAttr
&& (ntAttr
->num_values
== 0)) {
1736 ldb_set_errstring(ldb
, "unicodePwd must have a value!\n");
1737 return LDB_ERR_CONSTRAINT_VIOLATION
;
1739 if (lmAttr
&& (lmAttr
->num_values
== 0)) {
1740 ldb_set_errstring(ldb
, "dBCSPwd must have a value!\n");
1741 return LDB_ERR_CONSTRAINT_VIOLATION
;
1744 ac
= ph_init_context(module
, req
);
1746 return LDB_ERR_OPERATIONS_ERROR
;
1749 /* get user domain data */
1750 ret
= build_domain_data_request(ac
);
1751 if (ret
!= LDB_SUCCESS
) {
1755 return ldb_next_request(module
, ac
->dom_req
);
1758 static int password_hash_add_do_add(struct ph_context
*ac
)
1760 struct ldb_context
*ldb
;
1761 struct ldb_request
*down_req
;
1762 struct ldb_message
*msg
;
1763 struct setup_password_fields_io io
;
1766 /* Prepare the internal data structure containing the passwords */
1767 ret
= setup_io(ac
, ac
->req
->op
.add
.message
, ac
->req
->op
.add
.message
, &io
);
1768 if (ret
!= LDB_SUCCESS
) {
1772 msg
= ldb_msg_copy_shallow(ac
, ac
->req
->op
.add
.message
);
1774 return LDB_ERR_OPERATIONS_ERROR
;
1777 /* remove attributes that we just read into 'io' */
1778 ldb_msg_remove_attr(msg
, "userPassword");
1779 ldb_msg_remove_attr(msg
, "clearTextPassword");
1780 ldb_msg_remove_attr(msg
, "unicodePwd");
1781 ldb_msg_remove_attr(msg
, "dBCSPwd");
1782 ldb_msg_remove_attr(msg
, "pwdLastSet");
1783 io
.o
.kvno
= samdb_result_uint(msg
, "msDs-KeyVersionNumber", 1) - 1;
1784 ldb_msg_remove_attr(msg
, "msDs-KeyVersionNumber");
1786 ldb
= ldb_module_get_ctx(ac
->module
);
1788 ret
= setup_password_fields(&io
);
1789 if (ret
!= LDB_SUCCESS
) {
1794 ret
= samdb_msg_add_hash(ldb
, ac
, msg
,
1795 "unicodePwd", io
.g
.nt_hash
);
1796 if (ret
!= LDB_SUCCESS
) {
1801 ret
= samdb_msg_add_hash(ldb
, ac
, msg
,
1802 "dBCSPwd", io
.g
.lm_hash
);
1803 if (ret
!= LDB_SUCCESS
) {
1807 if (io
.g
.nt_history_len
> 0) {
1808 ret
= samdb_msg_add_hashes(ac
, msg
,
1811 io
.g
.nt_history_len
);
1812 if (ret
!= LDB_SUCCESS
) {
1816 if (io
.g
.lm_history_len
> 0) {
1817 ret
= samdb_msg_add_hashes(ac
, msg
,
1820 io
.g
.lm_history_len
);
1821 if (ret
!= LDB_SUCCESS
) {
1825 if (io
.g
.supplemental
.length
> 0) {
1826 ret
= ldb_msg_add_value(msg
, "supplementalCredentials",
1827 &io
.g
.supplemental
, NULL
);
1828 if (ret
!= LDB_SUCCESS
) {
1832 ret
= samdb_msg_add_uint64(ldb
, ac
, msg
,
1835 if (ret
!= LDB_SUCCESS
) {
1838 ret
= samdb_msg_add_uint(ldb
, ac
, msg
,
1839 "msDs-KeyVersionNumber",
1841 if (ret
!= LDB_SUCCESS
) {
1845 ret
= ldb_build_add_req(&down_req
, ldb
, ac
,
1850 if (ret
!= LDB_SUCCESS
) {
1854 return ldb_next_request(ac
->module
, down_req
);
1857 static int password_hash_modify(struct ldb_module
*module
, struct ldb_request
*req
)
1859 struct ldb_context
*ldb
;
1860 struct ph_context
*ac
;
1861 struct ldb_message_element
*sambaAttr
;
1862 struct ldb_message_element
*clearTextAttr
;
1863 struct ldb_message_element
*ntAttr
;
1864 struct ldb_message_element
*lmAttr
;
1865 struct ldb_message
*msg
;
1866 struct ldb_request
*down_req
;
1869 ldb
= ldb_module_get_ctx(module
);
1871 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "password_hash_modify\n");
1873 if (ldb_dn_is_special(req
->op
.mod
.message
->dn
)) { /* do not manipulate our control entries */
1874 return ldb_next_request(module
, req
);
1877 /* If the caller is manipulating the local passwords directly, let them pass */
1878 if (ldb_dn_compare_base(ldb_dn_new(req
, ldb
, LOCAL_BASE
),
1879 req
->op
.mod
.message
->dn
) == 0) {
1880 return ldb_next_request(module
, req
);
1883 /* nobody must touch password Histories */
1884 if (ldb_msg_find_element(req
->op
.add
.message
, "ntPwdHistory")) {
1885 return LDB_ERR_UNWILLING_TO_PERFORM
;
1887 if (ldb_msg_find_element(req
->op
.add
.message
, "lmPwdHistory")) {
1888 return LDB_ERR_UNWILLING_TO_PERFORM
;
1890 if (ldb_msg_find_element(req
->op
.add
.message
, "supplementalCredentials")) {
1891 return LDB_ERR_UNWILLING_TO_PERFORM
;
1894 sambaAttr
= ldb_msg_find_element(req
->op
.mod
.message
, "userPassword");
1895 clearTextAttr
= ldb_msg_find_element(req
->op
.mod
.message
, "clearTextPassword");
1896 ntAttr
= ldb_msg_find_element(req
->op
.mod
.message
, "unicodePwd");
1897 lmAttr
= ldb_msg_find_element(req
->op
.mod
.message
, "dBCSPwd");
1899 /* If no part of this touches the userPassword OR
1900 * clearTextPassword OR unicodePwd and/or dBCSPwd, then we
1901 * don't need to make any changes. For password changes/set
1902 * there should be a 'delete' or a 'modify' on this
1904 if ((!sambaAttr
) && (!clearTextAttr
) && (!ntAttr
) && (!lmAttr
)) {
1905 return ldb_next_request(module
, req
);
1908 /* check passwords are single valued here */
1909 /* TODO: remove this when passwords will be single valued in schema */
1910 if (sambaAttr
&& (sambaAttr
->num_values
> 1)) {
1911 DEBUG(0,(__location__
": %s\n", ldb_errstring(ldb
)));
1912 return LDB_ERR_CONSTRAINT_VIOLATION
;
1914 if (clearTextAttr
&& (clearTextAttr
->num_values
> 1)) {
1915 DEBUG(0,(__location__
": %s\n", ldb_errstring(ldb
)));
1916 return LDB_ERR_CONSTRAINT_VIOLATION
;
1918 if (ntAttr
&& (ntAttr
->num_values
> 1)) {
1919 DEBUG(0,(__location__
": %s\n", ldb_errstring(ldb
)));
1920 return LDB_ERR_CONSTRAINT_VIOLATION
;
1922 if (lmAttr
&& (lmAttr
->num_values
> 1)) {
1923 DEBUG(0,(__location__
": %s\n", ldb_errstring(ldb
)));
1924 return LDB_ERR_CONSTRAINT_VIOLATION
;
1927 ac
= ph_init_context(module
, req
);
1929 DEBUG(0,(__location__
": %s\n", ldb_errstring(ldb
)));
1930 return LDB_ERR_OPERATIONS_ERROR
;
1933 /* use a new message structure so that we can modify it */
1934 msg
= ldb_msg_copy_shallow(ac
, req
->op
.mod
.message
);
1937 return LDB_ERR_OPERATIONS_ERROR
;
1940 /* - remove any modification to the password from the first commit
1941 * we will make the real modification later */
1942 if (sambaAttr
) ldb_msg_remove_attr(msg
, "userPassword");
1943 if (clearTextAttr
) ldb_msg_remove_attr(msg
, "clearTextPassword");
1944 if (ntAttr
) ldb_msg_remove_attr(msg
, "unicodePwd");
1945 if (lmAttr
) ldb_msg_remove_attr(msg
, "dBCSPwd");
1947 /* if there was nothing else to be modified skip to next step */
1948 if (msg
->num_elements
== 0) {
1949 return password_hash_mod_search_self(ac
);
1952 ret
= ldb_build_mod_req(&down_req
, ldb
, ac
,
1955 ac
, ph_modify_callback
,
1957 if (ret
!= LDB_SUCCESS
) {
1961 return ldb_next_request(module
, down_req
);
1964 static int ph_modify_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
1966 struct ph_context
*ac
;
1969 ac
= talloc_get_type(req
->context
, struct ph_context
);
1972 return ldb_module_done(ac
->req
, NULL
, NULL
,
1973 LDB_ERR_OPERATIONS_ERROR
);
1975 if (ares
->error
!= LDB_SUCCESS
) {
1976 return ldb_module_done(ac
->req
, ares
->controls
,
1977 ares
->response
, ares
->error
);
1980 if (ares
->type
!= LDB_REPLY_DONE
) {
1982 return ldb_module_done(ac
->req
, NULL
, NULL
,
1983 LDB_ERR_OPERATIONS_ERROR
);
1986 ret
= password_hash_mod_search_self(ac
);
1987 if (ret
!= LDB_SUCCESS
) {
1988 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
1995 static int ph_mod_search_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
1997 struct ldb_context
*ldb
;
1998 struct ph_context
*ac
;
2001 ac
= talloc_get_type(req
->context
, struct ph_context
);
2002 ldb
= ldb_module_get_ctx(ac
->module
);
2005 return ldb_module_done(ac
->req
, NULL
, NULL
,
2006 LDB_ERR_OPERATIONS_ERROR
);
2008 if (ares
->error
!= LDB_SUCCESS
) {
2009 return ldb_module_done(ac
->req
, ares
->controls
,
2010 ares
->response
, ares
->error
);
2013 /* we are interested only in the single reply (base search) */
2014 switch (ares
->type
) {
2015 case LDB_REPLY_ENTRY
:
2017 if (ac
->search_res
!= NULL
) {
2018 ldb_set_errstring(ldb
, "Too many results");
2020 return ldb_module_done(ac
->req
, NULL
, NULL
,
2021 LDB_ERR_OPERATIONS_ERROR
);
2024 /* if it is not an entry of type person this is an error */
2025 /* TODO: remove this when sambaPassword will be in schema */
2026 if (!ldb_msg_check_string_attribute(ares
->message
, "objectClass", "person")) {
2027 ldb_set_errstring(ldb
, "Object class violation");
2029 return ldb_module_done(ac
->req
, NULL
, NULL
,
2030 LDB_ERR_OBJECT_CLASS_VIOLATION
);
2033 ac
->search_res
= talloc_steal(ac
, ares
);
2036 case LDB_REPLY_DONE
:
2038 /* get user domain data */
2039 ret
= build_domain_data_request(ac
);
2040 if (ret
!= LDB_SUCCESS
) {
2041 return ldb_module_done(ac
->req
, NULL
, NULL
,ret
);
2044 return ldb_next_request(ac
->module
, ac
->dom_req
);
2046 case LDB_REPLY_REFERRAL
:
2047 /*ignore anything else for now */
2055 static int password_hash_mod_search_self(struct ph_context
*ac
)
2057 struct ldb_context
*ldb
;
2058 static const char * const attrs
[] = { "userAccountControl", "lmPwdHistory",
2060 "objectSid", "msDS-KeyVersionNumber",
2061 "objectClass", "userPrincipalName",
2063 "dBCSPwd", "unicodePwd",
2064 "supplementalCredentials",
2066 struct ldb_request
*search_req
;
2069 ldb
= ldb_module_get_ctx(ac
->module
);
2071 ret
= ldb_build_search_req(&search_req
, ldb
, ac
,
2072 ac
->req
->op
.mod
.message
->dn
,
2077 ac
, ph_mod_search_callback
,
2080 if (ret
!= LDB_SUCCESS
) {
2084 return ldb_next_request(ac
->module
, search_req
);
2087 static int password_hash_mod_do_mod(struct ph_context
*ac
)
2089 struct ldb_context
*ldb
;
2090 struct ldb_request
*mod_req
;
2091 struct ldb_message
*msg
;
2092 const struct ldb_message
*searched_msg
;
2093 struct setup_password_fields_io io
;
2096 ldb
= ldb_module_get_ctx(ac
->module
);
2098 /* use a new message structure so that we can modify it */
2099 msg
= ldb_msg_new(ac
);
2101 return LDB_ERR_OPERATIONS_ERROR
;
2105 msg
->dn
= ac
->req
->op
.mod
.message
->dn
;
2107 /* Prepare the internal data structure containing the passwords */
2109 ac
->req
->op
.mod
.message
,
2110 ac
->search_res
->message
,
2112 if (ret
!= LDB_SUCCESS
) {
2116 searched_msg
= ac
->search_res
->message
;
2118 /* Fill in some final details (only relevent once the password has been set) */
2119 io
.o
.kvno
= samdb_result_uint(searched_msg
, "msDs-KeyVersionNumber", 0);
2120 io
.o
.nt_history_len
= samdb_result_hashes(io
.ac
, searched_msg
, "ntPwdHistory", &io
.o
.nt_history
);
2121 io
.o
.lm_history_len
= samdb_result_hashes(io
.ac
, searched_msg
, "lmPwdHistory", &io
.o
.lm_history
);
2122 io
.o
.supplemental
= ldb_msg_find_ldb_val(searched_msg
, "supplementalCredentials");
2124 ret
= setup_password_fields(&io
);
2125 if (ret
!= LDB_SUCCESS
) {
2129 /* make sure we replace all the old attributes */
2130 ret
= ldb_msg_add_empty(msg
, "unicodePwd", LDB_FLAG_MOD_REPLACE
, NULL
);
2131 ret
= ldb_msg_add_empty(msg
, "dBCSPwd", LDB_FLAG_MOD_REPLACE
, NULL
);
2132 ret
= ldb_msg_add_empty(msg
, "ntPwdHistory", LDB_FLAG_MOD_REPLACE
, NULL
);
2133 ret
= ldb_msg_add_empty(msg
, "lmPwdHistory", LDB_FLAG_MOD_REPLACE
, NULL
);
2134 ret
= ldb_msg_add_empty(msg
, "supplementalCredentials", LDB_FLAG_MOD_REPLACE
, NULL
);
2135 ret
= ldb_msg_add_empty(msg
, "pwdLastSet", LDB_FLAG_MOD_REPLACE
, NULL
);
2136 ret
= ldb_msg_add_empty(msg
, "msDs-KeyVersionNumber", LDB_FLAG_MOD_REPLACE
, NULL
);
2139 ret
= samdb_msg_add_hash(ldb
, ac
, msg
,
2140 "unicodePwd", io
.g
.nt_hash
);
2141 if (ret
!= LDB_SUCCESS
) {
2146 ret
= samdb_msg_add_hash(ldb
, ac
, msg
,
2147 "dBCSPwd", io
.g
.lm_hash
);
2148 if (ret
!= LDB_SUCCESS
) {
2152 if (io
.g
.nt_history_len
> 0) {
2153 ret
= samdb_msg_add_hashes(ac
, msg
,
2156 io
.g
.nt_history_len
);
2157 if (ret
!= LDB_SUCCESS
) {
2161 if (io
.g
.lm_history_len
> 0) {
2162 ret
= samdb_msg_add_hashes(ac
, msg
,
2165 io
.g
.lm_history_len
);
2166 if (ret
!= LDB_SUCCESS
) {
2170 if (io
.g
.supplemental
.length
> 0) {
2171 ret
= ldb_msg_add_value(msg
, "supplementalCredentials",
2172 &io
.g
.supplemental
, NULL
);
2173 if (ret
!= LDB_SUCCESS
) {
2177 ret
= samdb_msg_add_uint64(ldb
, ac
, msg
,
2180 if (ret
!= LDB_SUCCESS
) {
2183 ret
= samdb_msg_add_uint(ldb
, ac
, msg
,
2184 "msDs-KeyVersionNumber",
2186 if (ret
!= LDB_SUCCESS
) {
2190 ret
= ldb_build_mod_req(&mod_req
, ldb
, ac
,
2195 if (ret
!= LDB_SUCCESS
) {
2199 return ldb_next_request(ac
->module
, mod_req
);
2202 _PUBLIC_
const struct ldb_module_ops ldb_password_hash_module_ops
= {
2203 .name
= "password_hash",
2204 .add
= password_hash_add
,
2205 .modify
= password_hash_modify
,