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;
1029 ZERO_STRUCT(zero16
);
1032 ldb
= ldb_module_get_ctx(io
->ac
->module
);
1034 if (!io
->n
.cleartext_utf8
) {
1036 * when we don't have a cleartext password
1037 * we can't setup a supplementalCredential value
1042 /* if there's an old supplementaCredentials blob then parse it */
1043 if (io
->o
.supplemental
) {
1044 ndr_err
= ndr_pull_struct_blob_all(io
->o
.supplemental
, io
->ac
,
1045 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1047 (ndr_pull_flags_fn_t
)ndr_pull_supplementalCredentialsBlob
);
1048 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1049 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1050 ldb_asprintf_errstring(ldb
,
1051 "setup_supplemental_field: "
1052 "failed to pull old supplementalCredentialsBlob: %s",
1054 return LDB_ERR_OPERATIONS_ERROR
;
1057 if (_old_scb
.sub
.signature
== SUPPLEMENTAL_CREDENTIALS_SIGNATURE
) {
1058 old_scb
= &_old_scb
;
1060 ldb_debug(ldb
, LDB_DEBUG_ERROR
,
1061 "setup_supplemental_field: "
1062 "supplementalCredentialsBlob signature[0x%04X] expected[0x%04X]",
1063 _old_scb
.sub
.signature
, SUPPLEMENTAL_CREDENTIALS_SIGNATURE
);
1066 /* Per MS-SAMR 3.1.1.8.11.6 we create AES keys if our domain functionality level is 2008 or higher */
1067 do_newer_keys
= (dsdb_functional_level(ldb
) >= DS_DOMAIN_FUNCTION_2008
);
1069 if (io
->domain
->store_cleartext
&&
1070 (io
->u
.user_account_control
& UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED
)) {
1071 do_cleartext
= true;
1075 * The ordering is this
1077 * Primary:Kerberos-Newer-Keys (optional)
1080 * Primary:CLEARTEXT (optional)
1082 * And the 'Packages' package is insert before the last
1085 if (do_newer_keys
) {
1086 /* Primary:Kerberos-Newer-Keys */
1087 nkn
= &names
[num_names
++];
1088 pkn
= &packages
[num_packages
++];
1091 /* Primary:Kerberos */
1092 nk
= &names
[num_names
++];
1093 pk
= &packages
[num_packages
++];
1095 if (!do_cleartext
) {
1097 pp
= &packages
[num_packages
++];
1100 /* Primary:WDigest */
1101 nd
= &names
[num_names
++];
1102 pd
= &packages
[num_packages
++];
1106 pp
= &packages
[num_packages
++];
1108 /* Primary:CLEARTEXT */
1109 nc
= &names
[num_names
++];
1110 pc
= &packages
[num_packages
++];
1115 * setup 'Primary:Kerberos-Newer-Keys' element
1117 *nkn
= "Kerberos-Newer-Keys";
1119 ret
= setup_primary_kerberos_newer(io
, old_scb
, &pknb
);
1120 if (ret
!= LDB_SUCCESS
) {
1124 ndr_err
= ndr_push_struct_blob(&pknb_blob
, io
->ac
,
1125 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1127 (ndr_push_flags_fn_t
)ndr_push_package_PrimaryKerberosBlob
);
1128 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1129 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1130 ldb_asprintf_errstring(ldb
,
1131 "setup_supplemental_field: "
1132 "failed to push package_PrimaryKerberosNeverBlob: %s",
1134 return LDB_ERR_OPERATIONS_ERROR
;
1136 pknb_hexstr
= data_blob_hex_string_upper(io
->ac
, &pknb_blob
);
1139 return LDB_ERR_OPERATIONS_ERROR
;
1141 pkn
->name
= "Primary:Kerberos-Newer-Keys";
1143 pkn
->data
= pknb_hexstr
;
1147 * setup 'Primary:Kerberos' element
1151 ret
= setup_primary_kerberos(io
, old_scb
, &pkb
);
1152 if (ret
!= LDB_SUCCESS
) {
1156 ndr_err
= ndr_push_struct_blob(&pkb_blob
, io
->ac
,
1157 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1159 (ndr_push_flags_fn_t
)ndr_push_package_PrimaryKerberosBlob
);
1160 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1161 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1162 ldb_asprintf_errstring(ldb
,
1163 "setup_supplemental_field: "
1164 "failed to push package_PrimaryKerberosBlob: %s",
1166 return LDB_ERR_OPERATIONS_ERROR
;
1168 pkb_hexstr
= data_blob_hex_string_upper(io
->ac
, &pkb_blob
);
1171 return LDB_ERR_OPERATIONS_ERROR
;
1173 pk
->name
= "Primary:Kerberos";
1175 pk
->data
= pkb_hexstr
;
1178 * setup 'Primary:WDigest' element
1182 ret
= setup_primary_wdigest(io
, old_scb
, &pdb
);
1183 if (ret
!= LDB_SUCCESS
) {
1187 ndr_err
= ndr_push_struct_blob(&pdb_blob
, io
->ac
,
1188 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1190 (ndr_push_flags_fn_t
)ndr_push_package_PrimaryWDigestBlob
);
1191 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1192 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1193 ldb_asprintf_errstring(ldb
,
1194 "setup_supplemental_field: "
1195 "failed to push package_PrimaryWDigestBlob: %s",
1197 return LDB_ERR_OPERATIONS_ERROR
;
1199 pdb_hexstr
= data_blob_hex_string_upper(io
->ac
, &pdb_blob
);
1202 return LDB_ERR_OPERATIONS_ERROR
;
1204 pd
->name
= "Primary:WDigest";
1206 pd
->data
= pdb_hexstr
;
1209 * setup 'Primary:CLEARTEXT' element
1214 pcb
.cleartext
= *io
->n
.cleartext_utf16
;
1216 ndr_err
= ndr_push_struct_blob(&pcb_blob
, io
->ac
,
1217 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1219 (ndr_push_flags_fn_t
)ndr_push_package_PrimaryCLEARTEXTBlob
);
1220 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1221 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1222 ldb_asprintf_errstring(ldb
,
1223 "setup_supplemental_field: "
1224 "failed to push package_PrimaryCLEARTEXTBlob: %s",
1226 return LDB_ERR_OPERATIONS_ERROR
;
1228 pcb_hexstr
= data_blob_hex_string_upper(io
->ac
, &pcb_blob
);
1231 return LDB_ERR_OPERATIONS_ERROR
;
1233 pc
->name
= "Primary:CLEARTEXT";
1235 pc
->data
= pcb_hexstr
;
1239 * setup 'Packages' element
1242 ndr_err
= ndr_push_struct_blob(&pb_blob
, io
->ac
,
1243 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1245 (ndr_push_flags_fn_t
)ndr_push_package_PackagesBlob
);
1246 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1247 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1248 ldb_asprintf_errstring(ldb
,
1249 "setup_supplemental_field: "
1250 "failed to push package_PackagesBlob: %s",
1252 return LDB_ERR_OPERATIONS_ERROR
;
1254 pb_hexstr
= data_blob_hex_string_upper(io
->ac
, &pb_blob
);
1257 return LDB_ERR_OPERATIONS_ERROR
;
1259 pp
->name
= "Packages";
1261 pp
->data
= pb_hexstr
;
1264 * setup 'supplementalCredentials' value
1267 scb
.sub
.num_packages
= num_packages
;
1268 scb
.sub
.packages
= packages
;
1270 ndr_err
= ndr_push_struct_blob(&io
->g
.supplemental
, io
->ac
,
1271 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1273 (ndr_push_flags_fn_t
)ndr_push_supplementalCredentialsBlob
);
1274 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1275 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1276 ldb_asprintf_errstring(ldb
,
1277 "setup_supplemental_field: "
1278 "failed to push supplementalCredentialsBlob: %s",
1280 return LDB_ERR_OPERATIONS_ERROR
;
1286 static int setup_last_set_field(struct setup_password_fields_io
*io
)
1289 unix_to_nt_time(&io
->g
.last_set
, time(NULL
));
1294 static int setup_kvno_field(struct setup_password_fields_io
*io
)
1296 /* increment by one */
1297 io
->g
.kvno
= io
->o
.kvno
+ 1;
1302 static int setup_password_fields(struct setup_password_fields_io
*io
)
1304 struct ldb_context
*ldb
;
1307 size_t converted_pw_len
;
1309 ldb
= ldb_module_get_ctx(io
->ac
->module
);
1312 * refuse the change if someone want to change the cleartext
1313 * and supply his own hashes at the same time...
1315 if ((io
->n
.cleartext_utf8
|| io
->n
.cleartext_utf16
) && (io
->n
.nt_hash
|| io
->n
.lm_hash
)) {
1316 ldb_asprintf_errstring(ldb
,
1317 "setup_password_fields: "
1318 "it's only allowed to set the cleartext password or the password hashes");
1319 return LDB_ERR_UNWILLING_TO_PERFORM
;
1322 if (io
->n
.cleartext_utf8
&& io
->n
.cleartext_utf16
) {
1323 ldb_asprintf_errstring(ldb
,
1324 "setup_password_fields: "
1325 "it's only allowed to set the cleartext password as userPassword or clearTextPasssword, not both at once");
1326 return LDB_ERR_UNWILLING_TO_PERFORM
;
1329 if (io
->n
.cleartext_utf8
) {
1330 char **cleartext_utf16_str
;
1331 struct ldb_val
*cleartext_utf16_blob
;
1332 io
->n
.cleartext_utf16
= cleartext_utf16_blob
= talloc(io
->ac
, struct ldb_val
);
1333 if (!io
->n
.cleartext_utf16
) {
1335 return LDB_ERR_OPERATIONS_ERROR
;
1337 if (!convert_string_talloc_convenience(io
->ac
, lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1338 CH_UTF8
, CH_UTF16
, io
->n
.cleartext_utf8
->data
, io
->n
.cleartext_utf8
->length
,
1339 (void **)&cleartext_utf16_str
, &converted_pw_len
, false)) {
1340 ldb_asprintf_errstring(ldb
,
1341 "setup_password_fields: "
1342 "failed to generate UTF16 password from cleartext UTF8 password");
1343 return LDB_ERR_OPERATIONS_ERROR
;
1345 *cleartext_utf16_blob
= data_blob_const(cleartext_utf16_str
, converted_pw_len
);
1346 } else if (io
->n
.cleartext_utf16
) {
1347 char *cleartext_utf8_str
;
1348 struct ldb_val
*cleartext_utf8_blob
;
1349 io
->n
.cleartext_utf8
= cleartext_utf8_blob
= talloc(io
->ac
, struct ldb_val
);
1350 if (!io
->n
.cleartext_utf8
) {
1352 return LDB_ERR_OPERATIONS_ERROR
;
1354 if (!convert_string_talloc_convenience(io
->ac
, lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1355 CH_UTF16MUNGED
, CH_UTF8
, io
->n
.cleartext_utf16
->data
, io
->n
.cleartext_utf16
->length
,
1356 (void **)&cleartext_utf8_str
, &converted_pw_len
, false)) {
1357 /* We can't bail out entirely, as these unconvertable passwords are frustratingly valid */
1358 io
->n
.cleartext_utf8
= NULL
;
1359 talloc_free(cleartext_utf8_blob
);
1361 *cleartext_utf8_blob
= data_blob_const(cleartext_utf8_str
, converted_pw_len
);
1363 if (io
->n
.cleartext_utf16
) {
1364 struct samr_Password
*nt_hash
;
1365 nt_hash
= talloc(io
->ac
, struct samr_Password
);
1368 return LDB_ERR_OPERATIONS_ERROR
;
1370 io
->n
.nt_hash
= nt_hash
;
1372 /* compute the new nt hash */
1373 mdfour(nt_hash
->hash
, io
->n
.cleartext_utf16
->data
, io
->n
.cleartext_utf16
->length
);
1376 if (io
->n
.cleartext_utf8
) {
1377 struct samr_Password
*lm_hash
;
1378 char *cleartext_unix
;
1379 if (lp_lanman_auth(ldb_get_opaque(ldb
, "loadparm")) &&
1380 convert_string_talloc_convenience(io
->ac
, lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1381 CH_UTF8
, CH_UNIX
, io
->n
.cleartext_utf8
->data
, io
->n
.cleartext_utf8
->length
,
1382 (void **)&cleartext_unix
, &converted_pw_len
, false)) {
1383 lm_hash
= talloc(io
->ac
, struct samr_Password
);
1386 return LDB_ERR_OPERATIONS_ERROR
;
1389 /* compute the new lm hash. */
1390 ok
= E_deshash((char *)cleartext_unix
, lm_hash
->hash
);
1392 io
->n
.lm_hash
= lm_hash
;
1394 talloc_free(lm_hash
->hash
);
1398 ret
= setup_kerberos_keys(io
);
1399 if (ret
!= LDB_SUCCESS
) {
1404 ret
= setup_nt_fields(io
);
1405 if (ret
!= LDB_SUCCESS
) {
1409 ret
= setup_lm_fields(io
);
1410 if (ret
!= LDB_SUCCESS
) {
1414 ret
= setup_supplemental_field(io
);
1415 if (ret
!= LDB_SUCCESS
) {
1419 ret
= setup_last_set_field(io
);
1420 if (ret
!= LDB_SUCCESS
) {
1424 ret
= setup_kvno_field(io
);
1425 if (ret
!= LDB_SUCCESS
) {
1432 static int setup_io(struct ph_context
*ac
,
1433 const struct ldb_message
*new_msg
,
1434 const struct ldb_message
*searched_msg
,
1435 struct setup_password_fields_io
*io
)
1437 const struct ldb_val
*quoted_utf16
;
1438 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
1442 /* Some operations below require kerberos contexts */
1443 if (smb_krb5_init_context(ac
,
1444 ldb_get_event_context(ldb
),
1445 (struct loadparm_context
*)ldb_get_opaque(ldb
, "loadparm"),
1446 &io
->smb_krb5_context
) != 0) {
1447 return LDB_ERR_OPERATIONS_ERROR
;
1451 io
->domain
= ac
->domain
;
1453 io
->u
.user_account_control
= samdb_result_uint(searched_msg
, "userAccountControl", 0);
1454 io
->u
.sAMAccountName
= samdb_result_string(searched_msg
, "samAccountName", NULL
);
1455 io
->u
.user_principal_name
= samdb_result_string(searched_msg
, "userPrincipalName", NULL
);
1456 io
->u
.is_computer
= ldb_msg_check_string_attribute(searched_msg
, "objectClass", "computer");
1458 io
->n
.cleartext_utf8
= ldb_msg_find_ldb_val(new_msg
, "userPassword");
1459 io
->n
.cleartext_utf16
= ldb_msg_find_ldb_val(new_msg
, "clearTextPassword");
1461 /* this rather strange looking piece of code is there to
1462 handle a ldap client setting a password remotely using the
1463 unicodePwd ldap field. The syntax is that the password is
1464 in UTF-16LE, with a " at either end. Unfortunately the
1465 unicodePwd field is also used to store the nt hashes
1466 internally in Samba, and is used in the nt hash format on
1467 the wire in DRS replication, so we have a single name for
1468 two distinct values. The code below leaves us with a small
1469 chance (less than 1 in 2^32) of a mixup, if someone manages
1470 to create a MD4 hash which starts and ends in 0x22 0x00, as
1471 that would then be treated as a UTF16 password rather than
1473 quoted_utf16
= ldb_msg_find_ldb_val(new_msg
, "unicodePwd");
1475 quoted_utf16
->length
>= 4 &&
1476 quoted_utf16
->data
[0] == '"' &&
1477 quoted_utf16
->data
[1] == 0 &&
1478 quoted_utf16
->data
[quoted_utf16
->length
-2] == '"' &&
1479 quoted_utf16
->data
[quoted_utf16
->length
-1] == 0) {
1480 io
->n
.quoted_utf16
.data
= talloc_memdup(io
->ac
, quoted_utf16
->data
+2, quoted_utf16
->length
-4);
1481 io
->n
.quoted_utf16
.length
= quoted_utf16
->length
-4;
1482 io
->n
.cleartext_utf16
= &io
->n
.quoted_utf16
;
1483 io
->n
.nt_hash
= NULL
;
1485 io
->n
.nt_hash
= samdb_result_hash(io
->ac
, new_msg
, "unicodePwd");
1488 io
->n
.lm_hash
= samdb_result_hash(io
->ac
, new_msg
, "dBCSPwd");
1490 if(io
->u
.sAMAccountName
== NULL
)
1492 ldb_asprintf_errstring(ldb
, "samAccountName is missing on %s for attempted password set/change",
1493 ldb_dn_get_linearized(new_msg
->dn
));
1494 return(LDB_ERR_CONSTRAINT_VIOLATION
);
1500 static struct ph_context
*ph_init_context(struct ldb_module
*module
,
1501 struct ldb_request
*req
)
1503 struct ldb_context
*ldb
;
1504 struct ph_context
*ac
;
1506 ldb
= ldb_module_get_ctx(module
);
1508 ac
= talloc_zero(req
, struct ph_context
);
1510 ldb_set_errstring(ldb
, "Out of Memory");
1514 ac
->module
= module
;
1520 static int ph_op_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
1522 struct ph_context
*ac
;
1524 ac
= talloc_get_type(req
->context
, struct ph_context
);
1527 return ldb_module_done(ac
->req
, NULL
, NULL
,
1528 LDB_ERR_OPERATIONS_ERROR
);
1530 if (ares
->error
!= LDB_SUCCESS
) {
1531 return ldb_module_done(ac
->req
, ares
->controls
,
1532 ares
->response
, ares
->error
);
1535 if (ares
->type
!= LDB_REPLY_DONE
) {
1537 return ldb_module_done(ac
->req
, NULL
, NULL
,
1538 LDB_ERR_OPERATIONS_ERROR
);
1541 return ldb_module_done(ac
->req
, ares
->controls
,
1542 ares
->response
, ares
->error
);
1545 static int password_hash_add_do_add(struct ph_context
*ac
);
1546 static int ph_modify_callback(struct ldb_request
*req
, struct ldb_reply
*ares
);
1547 static int password_hash_mod_search_self(struct ph_context
*ac
);
1548 static int ph_mod_search_callback(struct ldb_request
*req
, struct ldb_reply
*ares
);
1549 static int password_hash_mod_do_mod(struct ph_context
*ac
);
1551 static int get_domain_data_callback(struct ldb_request
*req
,
1552 struct ldb_reply
*ares
)
1554 struct ldb_context
*ldb
;
1555 struct domain_data
*data
;
1556 struct ph_context
*ac
;
1557 struct loadparm_context
*lp_ctx
;
1560 ac
= talloc_get_type(req
->context
, struct ph_context
);
1561 ldb
= ldb_module_get_ctx(ac
->module
);
1564 return ldb_module_done(ac
->req
, NULL
, NULL
,
1565 LDB_ERR_OPERATIONS_ERROR
);
1567 if (ares
->error
!= LDB_SUCCESS
) {
1568 return ldb_module_done(ac
->req
, ares
->controls
,
1569 ares
->response
, ares
->error
);
1572 switch (ares
->type
) {
1573 case LDB_REPLY_ENTRY
:
1574 if (ac
->domain
!= NULL
) {
1575 ldb_set_errstring(ldb
, "Too many results");
1576 return ldb_module_done(ac
->req
, NULL
, NULL
,
1577 LDB_ERR_OPERATIONS_ERROR
);
1580 data
= talloc_zero(ac
, struct domain_data
);
1582 return ldb_module_done(ac
->req
, NULL
, NULL
,
1583 LDB_ERR_OPERATIONS_ERROR
);
1586 data
->pwdProperties
= samdb_result_uint(ares
->message
, "pwdProperties", 0);
1587 data
->store_cleartext
= data
->pwdProperties
& DOMAIN_PASSWORD_STORE_CLEARTEXT
;
1588 data
->pwdHistoryLength
= samdb_result_uint(ares
->message
, "pwdHistoryLength", 0);
1590 /* For a domain DN, this puts things in dotted notation */
1591 /* For builtin domains, this will give details for the host,
1592 * but that doesn't really matter, as it's just used for salt
1593 * and kerberos principals, which don't exist here */
1595 lp_ctx
= talloc_get_type(ldb_get_opaque(ldb
, "loadparm"),
1596 struct loadparm_context
);
1598 data
->dns_domain
= lp_dnsdomain(lp_ctx
);
1599 data
->realm
= lp_realm(lp_ctx
);
1600 data
->netbios_domain
= lp_sam_name(lp_ctx
);
1605 case LDB_REPLY_DONE
:
1607 /* call the next step */
1608 switch (ac
->req
->operation
) {
1610 ret
= password_hash_add_do_add(ac
);
1614 ret
= password_hash_mod_do_mod(ac
);
1618 ret
= LDB_ERR_OPERATIONS_ERROR
;
1621 if (ret
!= LDB_SUCCESS
) {
1622 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
1626 case LDB_REPLY_REFERRAL
:
1635 static int build_domain_data_request(struct ph_context
*ac
)
1637 /* attrs[] is returned from this function in
1638 ac->dom_req->op.search.attrs, so it must be static, as
1639 otherwise the compiler can put it on the stack */
1640 struct ldb_context
*ldb
;
1641 static const char * const attrs
[] = { "pwdProperties", "pwdHistoryLength", NULL
};
1643 ldb
= ldb_module_get_ctx(ac
->module
);
1645 return ldb_build_search_req(&ac
->dom_req
, ldb
, ac
,
1646 ldb_get_default_basedn(ldb
),
1650 ac
, get_domain_data_callback
,
1654 static int password_hash_add(struct ldb_module
*module
, struct ldb_request
*req
)
1656 struct ldb_context
*ldb
;
1657 struct ph_context
*ac
;
1658 struct ldb_message_element
*sambaAttr
;
1659 struct ldb_message_element
*clearTextPasswordAttr
;
1660 struct ldb_message_element
*ntAttr
;
1661 struct ldb_message_element
*lmAttr
;
1664 ldb
= ldb_module_get_ctx(module
);
1666 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "password_hash_add\n");
1668 if (ldb_dn_is_special(req
->op
.add
.message
->dn
)) { /* do not manipulate our control entries */
1669 return ldb_next_request(module
, req
);
1672 /* If the caller is manipulating the local passwords directly, let them pass */
1673 if (ldb_dn_compare_base(ldb_dn_new(req
, ldb
, LOCAL_BASE
),
1674 req
->op
.add
.message
->dn
) == 0) {
1675 return ldb_next_request(module
, req
);
1678 /* nobody must touch these fields */
1679 if (ldb_msg_find_element(req
->op
.add
.message
, "ntPwdHistory")) {
1680 return LDB_ERR_UNWILLING_TO_PERFORM
;
1682 if (ldb_msg_find_element(req
->op
.add
.message
, "lmPwdHistory")) {
1683 return LDB_ERR_UNWILLING_TO_PERFORM
;
1685 if (ldb_msg_find_element(req
->op
.add
.message
, "supplementalCredentials")) {
1686 return LDB_ERR_UNWILLING_TO_PERFORM
;
1689 /* If no part of this ADD touches the userPassword, or the NT
1690 * or LM hashes, then we don't need to make any changes. */
1692 sambaAttr
= ldb_msg_find_element(req
->op
.mod
.message
, "userPassword");
1693 clearTextPasswordAttr
= ldb_msg_find_element(req
->op
.mod
.message
, "clearTextPassword");
1694 ntAttr
= ldb_msg_find_element(req
->op
.mod
.message
, "unicodePwd");
1695 lmAttr
= ldb_msg_find_element(req
->op
.mod
.message
, "dBCSPwd");
1697 if ((!sambaAttr
) && (!clearTextPasswordAttr
) && (!ntAttr
) && (!lmAttr
)) {
1698 return ldb_next_request(module
, req
);
1701 /* if it is not an entry of type person its an error */
1702 /* TODO: remove this when userPassword will be in schema */
1703 if (!ldb_msg_check_string_attribute(req
->op
.add
.message
, "objectClass", "person")) {
1704 ldb_set_errstring(ldb
, "Cannot set a password on entry that does not have objectClass 'person'");
1705 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
1708 /* check userPassword is single valued here */
1709 /* TODO: remove this when userPassword will be single valued in schema */
1710 if (sambaAttr
&& sambaAttr
->num_values
> 1) {
1711 ldb_set_errstring(ldb
, "mupltiple values for userPassword not allowed!\n");
1712 return LDB_ERR_CONSTRAINT_VIOLATION
;
1714 if (clearTextPasswordAttr
&& clearTextPasswordAttr
->num_values
> 1) {
1715 ldb_set_errstring(ldb
, "mupltiple values for clearTextPassword not allowed!\n");
1716 return LDB_ERR_CONSTRAINT_VIOLATION
;
1719 if (ntAttr
&& (ntAttr
->num_values
> 1)) {
1720 ldb_set_errstring(ldb
, "mupltiple values for unicodePwd not allowed!\n");
1721 return LDB_ERR_CONSTRAINT_VIOLATION
;
1723 if (lmAttr
&& (lmAttr
->num_values
> 1)) {
1724 ldb_set_errstring(ldb
, "mupltiple values for dBCSPwd not allowed!\n");
1725 return LDB_ERR_CONSTRAINT_VIOLATION
;
1728 if (sambaAttr
&& sambaAttr
->num_values
== 0) {
1729 ldb_set_errstring(ldb
, "userPassword must have a value!\n");
1730 return LDB_ERR_CONSTRAINT_VIOLATION
;
1733 if (clearTextPasswordAttr
&& clearTextPasswordAttr
->num_values
== 0) {
1734 ldb_set_errstring(ldb
, "clearTextPassword must have a value!\n");
1735 return LDB_ERR_CONSTRAINT_VIOLATION
;
1738 if (ntAttr
&& (ntAttr
->num_values
== 0)) {
1739 ldb_set_errstring(ldb
, "unicodePwd must have a value!\n");
1740 return LDB_ERR_CONSTRAINT_VIOLATION
;
1742 if (lmAttr
&& (lmAttr
->num_values
== 0)) {
1743 ldb_set_errstring(ldb
, "dBCSPwd must have a value!\n");
1744 return LDB_ERR_CONSTRAINT_VIOLATION
;
1747 ac
= ph_init_context(module
, req
);
1749 return LDB_ERR_OPERATIONS_ERROR
;
1752 /* get user domain data */
1753 ret
= build_domain_data_request(ac
);
1754 if (ret
!= LDB_SUCCESS
) {
1758 return ldb_next_request(module
, ac
->dom_req
);
1761 static int password_hash_add_do_add(struct ph_context
*ac
)
1763 struct ldb_context
*ldb
;
1764 struct ldb_request
*down_req
;
1765 struct ldb_message
*msg
;
1766 struct setup_password_fields_io io
;
1769 /* Prepare the internal data structure containing the passwords */
1770 ret
= setup_io(ac
, ac
->req
->op
.add
.message
, ac
->req
->op
.add
.message
, &io
);
1771 if (ret
!= LDB_SUCCESS
) {
1775 msg
= ldb_msg_copy_shallow(ac
, ac
->req
->op
.add
.message
);
1777 return LDB_ERR_OPERATIONS_ERROR
;
1780 /* remove attributes that we just read into 'io' */
1781 ldb_msg_remove_attr(msg
, "userPassword");
1782 ldb_msg_remove_attr(msg
, "clearTextPassword");
1783 ldb_msg_remove_attr(msg
, "unicodePwd");
1784 ldb_msg_remove_attr(msg
, "dBCSPwd");
1785 ldb_msg_remove_attr(msg
, "pwdLastSet");
1786 io
.o
.kvno
= samdb_result_uint(msg
, "msDs-KeyVersionNumber", 1) - 1;
1787 ldb_msg_remove_attr(msg
, "msDs-KeyVersionNumber");
1789 ldb
= ldb_module_get_ctx(ac
->module
);
1791 ret
= setup_password_fields(&io
);
1792 if (ret
!= LDB_SUCCESS
) {
1797 ret
= samdb_msg_add_hash(ldb
, ac
, msg
,
1798 "unicodePwd", io
.g
.nt_hash
);
1799 if (ret
!= LDB_SUCCESS
) {
1804 ret
= samdb_msg_add_hash(ldb
, ac
, msg
,
1805 "dBCSPwd", io
.g
.lm_hash
);
1806 if (ret
!= LDB_SUCCESS
) {
1810 if (io
.g
.nt_history_len
> 0) {
1811 ret
= samdb_msg_add_hashes(ac
, msg
,
1814 io
.g
.nt_history_len
);
1815 if (ret
!= LDB_SUCCESS
) {
1819 if (io
.g
.lm_history_len
> 0) {
1820 ret
= samdb_msg_add_hashes(ac
, msg
,
1823 io
.g
.lm_history_len
);
1824 if (ret
!= LDB_SUCCESS
) {
1828 if (io
.g
.supplemental
.length
> 0) {
1829 ret
= ldb_msg_add_value(msg
, "supplementalCredentials",
1830 &io
.g
.supplemental
, NULL
);
1831 if (ret
!= LDB_SUCCESS
) {
1835 ret
= samdb_msg_add_uint64(ldb
, ac
, msg
,
1838 if (ret
!= LDB_SUCCESS
) {
1841 ret
= samdb_msg_add_uint(ldb
, ac
, msg
,
1842 "msDs-KeyVersionNumber",
1844 if (ret
!= LDB_SUCCESS
) {
1848 ret
= ldb_build_add_req(&down_req
, ldb
, ac
,
1853 if (ret
!= LDB_SUCCESS
) {
1857 return ldb_next_request(ac
->module
, down_req
);
1860 static int password_hash_modify(struct ldb_module
*module
, struct ldb_request
*req
)
1862 struct ldb_context
*ldb
;
1863 struct ph_context
*ac
;
1864 struct ldb_message_element
*sambaAttr
;
1865 struct ldb_message_element
*clearTextAttr
;
1866 struct ldb_message_element
*ntAttr
;
1867 struct ldb_message_element
*lmAttr
;
1868 struct ldb_message
*msg
;
1869 struct ldb_request
*down_req
;
1872 ldb
= ldb_module_get_ctx(module
);
1874 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "password_hash_modify\n");
1876 if (ldb_dn_is_special(req
->op
.mod
.message
->dn
)) { /* do not manipulate our control entries */
1877 return ldb_next_request(module
, req
);
1880 /* If the caller is manipulating the local passwords directly, let them pass */
1881 if (ldb_dn_compare_base(ldb_dn_new(req
, ldb
, LOCAL_BASE
),
1882 req
->op
.mod
.message
->dn
) == 0) {
1883 return ldb_next_request(module
, req
);
1886 /* nobody must touch password Histories */
1887 if (ldb_msg_find_element(req
->op
.add
.message
, "ntPwdHistory")) {
1888 return LDB_ERR_UNWILLING_TO_PERFORM
;
1890 if (ldb_msg_find_element(req
->op
.add
.message
, "lmPwdHistory")) {
1891 return LDB_ERR_UNWILLING_TO_PERFORM
;
1893 if (ldb_msg_find_element(req
->op
.add
.message
, "supplementalCredentials")) {
1894 return LDB_ERR_UNWILLING_TO_PERFORM
;
1897 sambaAttr
= ldb_msg_find_element(req
->op
.mod
.message
, "userPassword");
1898 clearTextAttr
= ldb_msg_find_element(req
->op
.mod
.message
, "clearTextPassword");
1899 ntAttr
= ldb_msg_find_element(req
->op
.mod
.message
, "unicodePwd");
1900 lmAttr
= ldb_msg_find_element(req
->op
.mod
.message
, "dBCSPwd");
1902 /* If no part of this touches the userPassword OR
1903 * clearTextPassword OR unicodePwd and/or dBCSPwd, then we
1904 * don't need to make any changes. For password changes/set
1905 * there should be a 'delete' or a 'modify' on this
1907 if ((!sambaAttr
) && (!clearTextAttr
) && (!ntAttr
) && (!lmAttr
)) {
1908 return ldb_next_request(module
, req
);
1911 /* check passwords are single valued here */
1912 /* TODO: remove this when passwords will be single valued in schema */
1913 if (sambaAttr
&& (sambaAttr
->num_values
> 1)) {
1914 DEBUG(0,(__location__
": %s\n", ldb_errstring(ldb
)));
1915 return LDB_ERR_CONSTRAINT_VIOLATION
;
1917 if (clearTextAttr
&& (clearTextAttr
->num_values
> 1)) {
1918 DEBUG(0,(__location__
": %s\n", ldb_errstring(ldb
)));
1919 return LDB_ERR_CONSTRAINT_VIOLATION
;
1921 if (ntAttr
&& (ntAttr
->num_values
> 1)) {
1922 DEBUG(0,(__location__
": %s\n", ldb_errstring(ldb
)));
1923 return LDB_ERR_CONSTRAINT_VIOLATION
;
1925 if (lmAttr
&& (lmAttr
->num_values
> 1)) {
1926 DEBUG(0,(__location__
": %s\n", ldb_errstring(ldb
)));
1927 return LDB_ERR_CONSTRAINT_VIOLATION
;
1930 ac
= ph_init_context(module
, req
);
1932 DEBUG(0,(__location__
": %s\n", ldb_errstring(ldb
)));
1933 return LDB_ERR_OPERATIONS_ERROR
;
1936 /* use a new message structure so that we can modify it */
1937 msg
= ldb_msg_copy_shallow(ac
, req
->op
.mod
.message
);
1940 return LDB_ERR_OPERATIONS_ERROR
;
1943 /* - remove any modification to the password from the first commit
1944 * we will make the real modification later */
1945 if (sambaAttr
) ldb_msg_remove_attr(msg
, "userPassword");
1946 if (clearTextAttr
) ldb_msg_remove_attr(msg
, "clearTextPassword");
1947 if (ntAttr
) ldb_msg_remove_attr(msg
, "unicodePwd");
1948 if (lmAttr
) ldb_msg_remove_attr(msg
, "dBCSPwd");
1950 /* if there was nothing else to be modified skip to next step */
1951 if (msg
->num_elements
== 0) {
1952 return password_hash_mod_search_self(ac
);
1955 ret
= ldb_build_mod_req(&down_req
, ldb
, ac
,
1958 ac
, ph_modify_callback
,
1960 if (ret
!= LDB_SUCCESS
) {
1964 return ldb_next_request(module
, down_req
);
1967 static int ph_modify_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
1969 struct ph_context
*ac
;
1972 ac
= talloc_get_type(req
->context
, struct ph_context
);
1975 return ldb_module_done(ac
->req
, NULL
, NULL
,
1976 LDB_ERR_OPERATIONS_ERROR
);
1978 if (ares
->error
!= LDB_SUCCESS
) {
1979 return ldb_module_done(ac
->req
, ares
->controls
,
1980 ares
->response
, ares
->error
);
1983 if (ares
->type
!= LDB_REPLY_DONE
) {
1985 return ldb_module_done(ac
->req
, NULL
, NULL
,
1986 LDB_ERR_OPERATIONS_ERROR
);
1989 ret
= password_hash_mod_search_self(ac
);
1990 if (ret
!= LDB_SUCCESS
) {
1991 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
1998 static int ph_mod_search_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
2000 struct ldb_context
*ldb
;
2001 struct ph_context
*ac
;
2004 ac
= talloc_get_type(req
->context
, struct ph_context
);
2005 ldb
= ldb_module_get_ctx(ac
->module
);
2008 return ldb_module_done(ac
->req
, NULL
, NULL
,
2009 LDB_ERR_OPERATIONS_ERROR
);
2011 if (ares
->error
!= LDB_SUCCESS
) {
2012 return ldb_module_done(ac
->req
, ares
->controls
,
2013 ares
->response
, ares
->error
);
2016 /* we are interested only in the single reply (base search) */
2017 switch (ares
->type
) {
2018 case LDB_REPLY_ENTRY
:
2020 if (ac
->search_res
!= NULL
) {
2021 ldb_set_errstring(ldb
, "Too many results");
2023 return ldb_module_done(ac
->req
, NULL
, NULL
,
2024 LDB_ERR_OPERATIONS_ERROR
);
2027 /* if it is not an entry of type person this is an error */
2028 /* TODO: remove this when sambaPassword will be in schema */
2029 if (!ldb_msg_check_string_attribute(ares
->message
, "objectClass", "person")) {
2030 ldb_set_errstring(ldb
, "Object class violation");
2032 return ldb_module_done(ac
->req
, NULL
, NULL
,
2033 LDB_ERR_OBJECT_CLASS_VIOLATION
);
2036 ac
->search_res
= talloc_steal(ac
, ares
);
2039 case LDB_REPLY_DONE
:
2041 /* get user domain data */
2042 ret
= build_domain_data_request(ac
);
2043 if (ret
!= LDB_SUCCESS
) {
2044 return ldb_module_done(ac
->req
, NULL
, NULL
,ret
);
2047 return ldb_next_request(ac
->module
, ac
->dom_req
);
2049 case LDB_REPLY_REFERRAL
:
2050 /*ignore anything else for now */
2058 static int password_hash_mod_search_self(struct ph_context
*ac
)
2060 struct ldb_context
*ldb
;
2061 static const char * const attrs
[] = { "userAccountControl", "lmPwdHistory",
2063 "objectSid", "msDS-KeyVersionNumber",
2064 "objectClass", "userPrincipalName",
2066 "dBCSPwd", "unicodePwd",
2067 "supplementalCredentials",
2069 struct ldb_request
*search_req
;
2072 ldb
= ldb_module_get_ctx(ac
->module
);
2074 ret
= ldb_build_search_req(&search_req
, ldb
, ac
,
2075 ac
->req
->op
.mod
.message
->dn
,
2080 ac
, ph_mod_search_callback
,
2083 if (ret
!= LDB_SUCCESS
) {
2087 return ldb_next_request(ac
->module
, search_req
);
2090 static int password_hash_mod_do_mod(struct ph_context
*ac
)
2092 struct ldb_context
*ldb
;
2093 struct ldb_request
*mod_req
;
2094 struct ldb_message
*msg
;
2095 const struct ldb_message
*searched_msg
;
2096 struct setup_password_fields_io io
;
2099 ldb
= ldb_module_get_ctx(ac
->module
);
2101 /* use a new message structure so that we can modify it */
2102 msg
= ldb_msg_new(ac
);
2104 return LDB_ERR_OPERATIONS_ERROR
;
2108 msg
->dn
= ac
->req
->op
.mod
.message
->dn
;
2110 /* Prepare the internal data structure containing the passwords */
2112 ac
->req
->op
.mod
.message
,
2113 ac
->search_res
->message
,
2115 if (ret
!= LDB_SUCCESS
) {
2119 searched_msg
= ac
->search_res
->message
;
2121 /* Fill in some final details (only relevent once the password has been set) */
2122 io
.o
.kvno
= samdb_result_uint(searched_msg
, "msDs-KeyVersionNumber", 0);
2123 io
.o
.nt_history_len
= samdb_result_hashes(io
.ac
, searched_msg
, "ntPwdHistory", &io
.o
.nt_history
);
2124 io
.o
.lm_history_len
= samdb_result_hashes(io
.ac
, searched_msg
, "lmPwdHistory", &io
.o
.lm_history
);
2125 io
.o
.supplemental
= ldb_msg_find_ldb_val(searched_msg
, "supplementalCredentials");
2127 ret
= setup_password_fields(&io
);
2128 if (ret
!= LDB_SUCCESS
) {
2132 /* make sure we replace all the old attributes */
2133 ret
= ldb_msg_add_empty(msg
, "unicodePwd", LDB_FLAG_MOD_REPLACE
, NULL
);
2134 ret
= ldb_msg_add_empty(msg
, "dBCSPwd", LDB_FLAG_MOD_REPLACE
, NULL
);
2135 ret
= ldb_msg_add_empty(msg
, "ntPwdHistory", LDB_FLAG_MOD_REPLACE
, NULL
);
2136 ret
= ldb_msg_add_empty(msg
, "lmPwdHistory", LDB_FLAG_MOD_REPLACE
, NULL
);
2137 ret
= ldb_msg_add_empty(msg
, "supplementalCredentials", LDB_FLAG_MOD_REPLACE
, NULL
);
2138 ret
= ldb_msg_add_empty(msg
, "pwdLastSet", LDB_FLAG_MOD_REPLACE
, NULL
);
2139 ret
= ldb_msg_add_empty(msg
, "msDs-KeyVersionNumber", LDB_FLAG_MOD_REPLACE
, NULL
);
2142 ret
= samdb_msg_add_hash(ldb
, ac
, msg
,
2143 "unicodePwd", io
.g
.nt_hash
);
2144 if (ret
!= LDB_SUCCESS
) {
2149 ret
= samdb_msg_add_hash(ldb
, ac
, msg
,
2150 "dBCSPwd", io
.g
.lm_hash
);
2151 if (ret
!= LDB_SUCCESS
) {
2155 if (io
.g
.nt_history_len
> 0) {
2156 ret
= samdb_msg_add_hashes(ac
, msg
,
2159 io
.g
.nt_history_len
);
2160 if (ret
!= LDB_SUCCESS
) {
2164 if (io
.g
.lm_history_len
> 0) {
2165 ret
= samdb_msg_add_hashes(ac
, msg
,
2168 io
.g
.lm_history_len
);
2169 if (ret
!= LDB_SUCCESS
) {
2173 if (io
.g
.supplemental
.length
> 0) {
2174 ret
= ldb_msg_add_value(msg
, "supplementalCredentials",
2175 &io
.g
.supplemental
, NULL
);
2176 if (ret
!= LDB_SUCCESS
) {
2180 ret
= samdb_msg_add_uint64(ldb
, ac
, msg
,
2183 if (ret
!= LDB_SUCCESS
) {
2186 ret
= samdb_msg_add_uint(ldb
, ac
, msg
,
2187 "msDs-KeyVersionNumber",
2189 if (ret
!= LDB_SUCCESS
) {
2193 ret
= ldb_build_mod_req(&mod_req
, ldb
, ac
,
2198 if (ret
!= LDB_SUCCESS
) {
2202 return ldb_next_request(ac
->module
, mod_req
);
2205 _PUBLIC_
const struct ldb_module_ops ldb_password_hash_module_ops
= {
2206 .name
= "password_hash",
2207 .add
= password_hash_add
,
2208 .modify
= password_hash_modify
,