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
8 Copyright (C) Matthias Dieter Wallnöfer 2009-2010
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 * Component: ldb password_hash module
29 * Description: correctly handle AD password changes fields
31 * Author: Andrew Bartlett
32 * Author: Stefan Metzmacher
36 #include "libcli/ldap/ldap_ndr.h"
37 #include "ldb_module.h"
38 #include "librpc/gen_ndr/misc.h"
39 #include "librpc/gen_ndr/samr.h"
40 #include "libcli/auth/libcli_auth.h"
41 #include "libcli/security/security.h"
42 #include "system/kerberos.h"
43 #include "auth/kerberos/kerberos.h"
44 #include "system/time.h"
45 #include "dsdb/samdb/samdb.h"
46 #include "../libds/common/flags.h"
47 #include "dsdb/samdb/ldb_modules/password_modules.h"
48 #include "librpc/ndr/libndr.h"
49 #include "librpc/gen_ndr/ndr_drsblobs.h"
50 #include "../lib/crypto/crypto.h"
51 #include "param/param.h"
53 /* If we have decided there is a reason to work on this request, then
54 * setup all the password hash types correctly.
56 * If we haven't the hashes yet but the password given as plain-text (attributes
57 * 'unicodePwd', 'userPassword' and 'clearTextPassword') we have to check for
58 * the constraints. Once this is done, we calculate the password hashes.
60 * Notice: unlike the real AD which only supports the UTF16 special based
61 * 'unicodePwd' and the UTF8 based 'userPassword' plaintext attribute we
62 * understand also a UTF16 based 'clearTextPassword' one.
63 * The latter is also accessible through LDAP so it can also be set by external
64 * tools and scripts. But be aware that this isn't portable on non SAMBA 4 ADs!
66 * Also when the module receives only the password hashes (possible through
67 * specifying an internal LDB control - for security reasons) some checks are
68 * performed depending on the operation mode (see below) (e.g. if the password
69 * has been in use before if the password memory policy was activated).
71 * Attention: There is a difference between "modify" and "reset" operations
72 * (see MS-ADTS 3.1.1.3.1.5). If the client sends a "add" and "remove"
73 * operation for a password attribute we thread this as a "modify"; if it sends
74 * only a "replace" one we have an (administrative) reset.
76 * Finally, if the administrator has requested that a password history
77 * be maintained, then this should also be written out.
81 /* TODO: [consider always MS-ADTS 3.1.1.3.1.5]
82 * - Check for right connection encryption
86 struct ldb_module
*module
;
87 struct ldb_request
*req
;
89 struct ldb_request
*dom_req
;
90 struct ldb_reply
*dom_res
;
92 struct ldb_reply
*search_res
;
94 struct domain_data
*domain
;
99 uint32_t pwdProperties
;
100 uint32_t pwdHistoryLength
;
103 uint32_t minPwdLength
;
104 const char *netbios_domain
;
105 const char *dns_domain
;
109 struct setup_password_fields_io
{
110 struct ph_context
*ac
;
111 struct domain_data
*domain
;
112 struct smb_krb5_context
*smb_krb5_context
;
114 /* infos about the user account */
116 uint32_t userAccountControl
;
118 const char *sAMAccountName
;
119 const char *user_principal_name
;
123 /* new credentials */
125 const struct ldb_val
*cleartext_utf8
;
126 const struct ldb_val
*cleartext_utf16
;
127 struct ldb_val quoted_utf16
;
128 struct samr_Password
*nt_hash
;
129 struct samr_Password
*lm_hash
;
132 /* old credentials */
134 uint32_t nt_history_len
;
135 struct samr_Password
*nt_history
;
136 uint32_t lm_history_len
;
137 struct samr_Password
*lm_history
;
138 const struct ldb_val
*supplemental
;
139 struct supplementalCredentialsBlob scb
;
142 /* generated credentials */
144 struct samr_Password
*nt_hash
;
145 struct samr_Password
*lm_hash
;
146 uint32_t nt_history_len
;
147 struct samr_Password
*nt_history
;
148 uint32_t lm_history_len
;
149 struct samr_Password
*lm_history
;
155 struct ldb_val supplemental
;
160 /* Get the NT hash, and fill it in as an entry in the password history,
161 and specify it into io->g.nt_hash */
163 static int setup_nt_fields(struct setup_password_fields_io
*io
)
165 struct ldb_context
*ldb
;
168 io
->g
.nt_hash
= io
->n
.nt_hash
;
169 ldb
= ldb_module_get_ctx(io
->ac
->module
);
171 if (io
->domain
->pwdHistoryLength
== 0) {
175 /* We might not have an old NT password */
176 io
->g
.nt_history
= talloc_array(io
->ac
,
177 struct samr_Password
,
178 io
->domain
->pwdHistoryLength
);
179 if (!io
->g
.nt_history
) {
181 return LDB_ERR_OPERATIONS_ERROR
;
184 for (i
= 0; i
< MIN(io
->domain
->pwdHistoryLength
-1, io
->o
.nt_history_len
); i
++) {
185 io
->g
.nt_history
[i
+1] = io
->o
.nt_history
[i
];
187 io
->g
.nt_history_len
= i
+ 1;
190 io
->g
.nt_history
[0] = *io
->g
.nt_hash
;
193 * TODO: is this correct?
194 * the simular behavior is correct for the lm history case
196 E_md4hash("", io
->g
.nt_history
[0].hash
);
202 /* Get the LANMAN hash, and fill it in as an entry in the password history,
203 and specify it into io->g.lm_hash */
205 static int setup_lm_fields(struct setup_password_fields_io
*io
)
207 struct ldb_context
*ldb
;
210 io
->g
.lm_hash
= io
->n
.lm_hash
;
211 ldb
= ldb_module_get_ctx(io
->ac
->module
);
213 if (io
->domain
->pwdHistoryLength
== 0) {
217 /* We might not have an old NT password */
218 io
->g
.lm_history
= talloc_array(io
->ac
,
219 struct samr_Password
,
220 io
->domain
->pwdHistoryLength
);
221 if (!io
->g
.lm_history
) {
223 return LDB_ERR_OPERATIONS_ERROR
;
226 for (i
= 0; i
< MIN(io
->domain
->pwdHistoryLength
-1, io
->o
.lm_history_len
); i
++) {
227 io
->g
.lm_history
[i
+1] = io
->o
.lm_history
[i
];
229 io
->g
.lm_history_len
= i
+ 1;
232 io
->g
.lm_history
[0] = *io
->g
.lm_hash
;
234 E_deshash("", io
->g
.lm_history
[0].hash
);
240 static int setup_kerberos_keys(struct setup_password_fields_io
*io
)
242 struct ldb_context
*ldb
;
243 krb5_error_code krb5_ret
;
244 Principal
*salt_principal
;
247 krb5_data cleartext_data
;
249 ldb
= ldb_module_get_ctx(io
->ac
->module
);
250 cleartext_data
.data
= io
->n
.cleartext_utf8
->data
;
251 cleartext_data
.length
= io
->n
.cleartext_utf8
->length
;
253 /* Many, many thanks to lukeh@padl.com for this
254 * algorithm, described in his Nov 10 2004 mail to
255 * samba-technical@samba.org */
258 * Determine a salting principal
260 if (io
->u
.is_computer
) {
264 name
= strlower_talloc(io
->ac
, io
->u
.sAMAccountName
);
267 return LDB_ERR_OPERATIONS_ERROR
;
270 if (name
[strlen(name
)-1] == '$') {
271 name
[strlen(name
)-1] = '\0';
274 saltbody
= talloc_asprintf(io
->ac
, "%s.%s", name
, io
->domain
->dns_domain
);
277 return LDB_ERR_OPERATIONS_ERROR
;
280 krb5_ret
= krb5_make_principal(io
->smb_krb5_context
->krb5_context
,
282 io
->domain
->realm
, "host",
284 } else if (io
->u
.user_principal_name
) {
285 char *user_principal_name
;
288 user_principal_name
= talloc_strdup(io
->ac
, io
->u
.user_principal_name
);
289 if (!user_principal_name
) {
291 return LDB_ERR_OPERATIONS_ERROR
;
294 p
= strchr(user_principal_name
, '@');
299 krb5_ret
= krb5_make_principal(io
->smb_krb5_context
->krb5_context
,
301 io
->domain
->realm
, user_principal_name
,
304 krb5_ret
= krb5_make_principal(io
->smb_krb5_context
->krb5_context
,
306 io
->domain
->realm
, io
->u
.sAMAccountName
,
310 ldb_asprintf_errstring(ldb
,
311 "setup_kerberos_keys: "
312 "generation of a salting principal failed: %s",
313 smb_get_krb5_error_message(io
->smb_krb5_context
->krb5_context
,
315 return LDB_ERR_OPERATIONS_ERROR
;
319 * create salt from salt_principal
321 krb5_ret
= krb5_get_pw_salt(io
->smb_krb5_context
->krb5_context
,
322 salt_principal
, &salt
);
323 krb5_free_principal(io
->smb_krb5_context
->krb5_context
, salt_principal
);
325 ldb_asprintf_errstring(ldb
,
326 "setup_kerberos_keys: "
327 "generation of krb5_salt failed: %s",
328 smb_get_krb5_error_message(io
->smb_krb5_context
->krb5_context
,
330 return LDB_ERR_OPERATIONS_ERROR
;
332 /* create a talloc copy */
333 io
->g
.salt
= talloc_strndup(io
->ac
,
335 salt
.saltvalue
.length
);
336 krb5_free_salt(io
->smb_krb5_context
->krb5_context
, salt
);
339 return LDB_ERR_OPERATIONS_ERROR
;
341 salt
.saltvalue
.data
= discard_const(io
->g
.salt
);
342 salt
.saltvalue
.length
= strlen(io
->g
.salt
);
345 * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of
346 * the salt and the cleartext password
348 krb5_ret
= krb5_string_to_key_data_salt(io
->smb_krb5_context
->krb5_context
,
349 ENCTYPE_AES256_CTS_HMAC_SHA1_96
,
354 ldb_asprintf_errstring(ldb
,
355 "setup_kerberos_keys: "
356 "generation of a aes256-cts-hmac-sha1-96 key failed: %s",
357 smb_get_krb5_error_message(io
->smb_krb5_context
->krb5_context
,
359 return LDB_ERR_OPERATIONS_ERROR
;
361 io
->g
.aes_256
= data_blob_talloc(io
->ac
,
363 key
.keyvalue
.length
);
364 krb5_free_keyblock_contents(io
->smb_krb5_context
->krb5_context
, &key
);
365 if (!io
->g
.aes_256
.data
) {
367 return LDB_ERR_OPERATIONS_ERROR
;
371 * create ENCTYPE_AES128_CTS_HMAC_SHA1_96 key out of
372 * the salt and the cleartext password
374 krb5_ret
= krb5_string_to_key_data_salt(io
->smb_krb5_context
->krb5_context
,
375 ENCTYPE_AES128_CTS_HMAC_SHA1_96
,
380 ldb_asprintf_errstring(ldb
,
381 "setup_kerberos_keys: "
382 "generation of a aes128-cts-hmac-sha1-96 key failed: %s",
383 smb_get_krb5_error_message(io
->smb_krb5_context
->krb5_context
,
385 return LDB_ERR_OPERATIONS_ERROR
;
387 io
->g
.aes_128
= data_blob_talloc(io
->ac
,
389 key
.keyvalue
.length
);
390 krb5_free_keyblock_contents(io
->smb_krb5_context
->krb5_context
, &key
);
391 if (!io
->g
.aes_128
.data
) {
393 return LDB_ERR_OPERATIONS_ERROR
;
397 * create ENCTYPE_DES_CBC_MD5 key out of
398 * the salt and the cleartext password
400 krb5_ret
= krb5_string_to_key_data_salt(io
->smb_krb5_context
->krb5_context
,
406 ldb_asprintf_errstring(ldb
,
407 "setup_kerberos_keys: "
408 "generation of a des-cbc-md5 key failed: %s",
409 smb_get_krb5_error_message(io
->smb_krb5_context
->krb5_context
,
411 return LDB_ERR_OPERATIONS_ERROR
;
413 io
->g
.des_md5
= data_blob_talloc(io
->ac
,
415 key
.keyvalue
.length
);
416 krb5_free_keyblock_contents(io
->smb_krb5_context
->krb5_context
, &key
);
417 if (!io
->g
.des_md5
.data
) {
419 return LDB_ERR_OPERATIONS_ERROR
;
423 * create ENCTYPE_DES_CBC_CRC key out of
424 * the salt and the cleartext password
426 krb5_ret
= krb5_string_to_key_data_salt(io
->smb_krb5_context
->krb5_context
,
432 ldb_asprintf_errstring(ldb
,
433 "setup_kerberos_keys: "
434 "generation of a des-cbc-crc key failed: %s",
435 smb_get_krb5_error_message(io
->smb_krb5_context
->krb5_context
,
437 return LDB_ERR_OPERATIONS_ERROR
;
439 io
->g
.des_crc
= data_blob_talloc(io
->ac
,
441 key
.keyvalue
.length
);
442 krb5_free_keyblock_contents(io
->smb_krb5_context
->krb5_context
, &key
);
443 if (!io
->g
.des_crc
.data
) {
445 return LDB_ERR_OPERATIONS_ERROR
;
451 static int setup_primary_kerberos(struct setup_password_fields_io
*io
,
452 const struct supplementalCredentialsBlob
*old_scb
,
453 struct package_PrimaryKerberosBlob
*pkb
)
455 struct ldb_context
*ldb
;
456 struct package_PrimaryKerberosCtr3
*pkb3
= &pkb
->ctr
.ctr3
;
457 struct supplementalCredentialsPackage
*old_scp
= NULL
;
458 struct package_PrimaryKerberosBlob _old_pkb
;
459 struct package_PrimaryKerberosCtr3
*old_pkb3
= NULL
;
461 enum ndr_err_code ndr_err
;
463 ldb
= ldb_module_get_ctx(io
->ac
->module
);
466 * prepare generation of keys
468 * ENCTYPE_DES_CBC_MD5
469 * ENCTYPE_DES_CBC_CRC
472 pkb3
->salt
.string
= io
->g
.salt
;
474 pkb3
->keys
= talloc_array(io
->ac
,
475 struct package_PrimaryKerberosKey3
,
479 return LDB_ERR_OPERATIONS_ERROR
;
482 pkb3
->keys
[0].keytype
= ENCTYPE_DES_CBC_MD5
;
483 pkb3
->keys
[0].value
= &io
->g
.des_md5
;
484 pkb3
->keys
[1].keytype
= ENCTYPE_DES_CBC_CRC
;
485 pkb3
->keys
[1].value
= &io
->g
.des_crc
;
487 /* initialize the old keys to zero */
488 pkb3
->num_old_keys
= 0;
489 pkb3
->old_keys
= NULL
;
491 /* if there're no old keys, then we're done */
496 for (i
=0; i
< old_scb
->sub
.num_packages
; i
++) {
497 if (strcmp("Primary:Kerberos", old_scb
->sub
.packages
[i
].name
) != 0) {
501 if (!old_scb
->sub
.packages
[i
].data
|| !old_scb
->sub
.packages
[i
].data
[0]) {
505 old_scp
= &old_scb
->sub
.packages
[i
];
508 /* Primary:Kerberos element of supplementalCredentials */
512 blob
= strhex_to_data_blob(io
->ac
, old_scp
->data
);
515 return LDB_ERR_OPERATIONS_ERROR
;
518 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
519 ndr_err
= ndr_pull_struct_blob(&blob
, io
->ac
, lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")), &_old_pkb
,
520 (ndr_pull_flags_fn_t
)ndr_pull_package_PrimaryKerberosBlob
);
521 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
522 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
523 ldb_asprintf_errstring(ldb
,
524 "setup_primary_kerberos: "
525 "failed to pull old package_PrimaryKerberosBlob: %s",
527 return LDB_ERR_OPERATIONS_ERROR
;
530 if (_old_pkb
.version
!= 3) {
531 ldb_asprintf_errstring(ldb
,
532 "setup_primary_kerberos: "
533 "package_PrimaryKerberosBlob version[%u] expected[3]",
535 return LDB_ERR_OPERATIONS_ERROR
;
538 old_pkb3
= &_old_pkb
.ctr
.ctr3
;
541 /* if we didn't found the old keys we're done */
546 /* fill in the old keys */
547 pkb3
->num_old_keys
= old_pkb3
->num_keys
;
548 pkb3
->old_keys
= old_pkb3
->keys
;
553 static int setup_primary_kerberos_newer(struct setup_password_fields_io
*io
,
554 const struct supplementalCredentialsBlob
*old_scb
,
555 struct package_PrimaryKerberosBlob
*pkb
)
557 struct ldb_context
*ldb
;
558 struct package_PrimaryKerberosCtr4
*pkb4
= &pkb
->ctr
.ctr4
;
559 struct supplementalCredentialsPackage
*old_scp
= NULL
;
560 struct package_PrimaryKerberosBlob _old_pkb
;
561 struct package_PrimaryKerberosCtr4
*old_pkb4
= NULL
;
563 enum ndr_err_code ndr_err
;
565 ldb
= ldb_module_get_ctx(io
->ac
->module
);
568 * prepare generation of keys
570 * ENCTYPE_AES256_CTS_HMAC_SHA1_96
571 * ENCTYPE_AES128_CTS_HMAC_SHA1_96
572 * ENCTYPE_DES_CBC_MD5
573 * ENCTYPE_DES_CBC_CRC
576 pkb4
->salt
.string
= io
->g
.salt
;
577 pkb4
->default_iteration_count
= 4096;
580 pkb4
->keys
= talloc_array(io
->ac
,
581 struct package_PrimaryKerberosKey4
,
585 return LDB_ERR_OPERATIONS_ERROR
;
588 pkb4
->keys
[0].iteration_count
= 4096;
589 pkb4
->keys
[0].keytype
= ENCTYPE_AES256_CTS_HMAC_SHA1_96
;
590 pkb4
->keys
[0].value
= &io
->g
.aes_256
;
591 pkb4
->keys
[1].iteration_count
= 4096;
592 pkb4
->keys
[1].keytype
= ENCTYPE_AES128_CTS_HMAC_SHA1_96
;
593 pkb4
->keys
[1].value
= &io
->g
.aes_128
;
594 pkb4
->keys
[2].iteration_count
= 4096;
595 pkb4
->keys
[2].keytype
= ENCTYPE_DES_CBC_MD5
;
596 pkb4
->keys
[2].value
= &io
->g
.des_md5
;
597 pkb4
->keys
[3].iteration_count
= 4096;
598 pkb4
->keys
[3].keytype
= ENCTYPE_DES_CBC_CRC
;
599 pkb4
->keys
[3].value
= &io
->g
.des_crc
;
601 /* initialize the old keys to zero */
602 pkb4
->num_old_keys
= 0;
603 pkb4
->old_keys
= NULL
;
604 pkb4
->num_older_keys
= 0;
605 pkb4
->older_keys
= NULL
;
607 /* if there're no old keys, then we're done */
612 for (i
=0; i
< old_scb
->sub
.num_packages
; i
++) {
613 if (strcmp("Primary:Kerberos-Newer-Keys", old_scb
->sub
.packages
[i
].name
) != 0) {
617 if (!old_scb
->sub
.packages
[i
].data
|| !old_scb
->sub
.packages
[i
].data
[0]) {
621 old_scp
= &old_scb
->sub
.packages
[i
];
624 /* Primary:Kerberos-Newer-Keys element of supplementalCredentials */
628 blob
= strhex_to_data_blob(io
->ac
, old_scp
->data
);
631 return LDB_ERR_OPERATIONS_ERROR
;
634 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
635 ndr_err
= ndr_pull_struct_blob(&blob
, io
->ac
,
636 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
638 (ndr_pull_flags_fn_t
)ndr_pull_package_PrimaryKerberosBlob
);
639 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
640 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
641 ldb_asprintf_errstring(ldb
,
642 "setup_primary_kerberos_newer: "
643 "failed to pull old package_PrimaryKerberosBlob: %s",
645 return LDB_ERR_OPERATIONS_ERROR
;
648 if (_old_pkb
.version
!= 4) {
649 ldb_asprintf_errstring(ldb
,
650 "setup_primary_kerberos_newer: "
651 "package_PrimaryKerberosBlob version[%u] expected[4]",
653 return LDB_ERR_OPERATIONS_ERROR
;
656 old_pkb4
= &_old_pkb
.ctr
.ctr4
;
659 /* if we didn't found the old keys we're done */
664 /* fill in the old keys */
665 pkb4
->num_old_keys
= old_pkb4
->num_keys
;
666 pkb4
->old_keys
= old_pkb4
->keys
;
667 pkb4
->num_older_keys
= old_pkb4
->num_old_keys
;
668 pkb4
->older_keys
= old_pkb4
->old_keys
;
673 static int setup_primary_wdigest(struct setup_password_fields_io
*io
,
674 const struct supplementalCredentialsBlob
*old_scb
,
675 struct package_PrimaryWDigestBlob
*pdb
)
677 struct ldb_context
*ldb
= ldb_module_get_ctx(io
->ac
->module
);
678 DATA_BLOB sAMAccountName
;
679 DATA_BLOB sAMAccountName_l
;
680 DATA_BLOB sAMAccountName_u
;
681 const char *user_principal_name
= io
->u
.user_principal_name
;
682 DATA_BLOB userPrincipalName
;
683 DATA_BLOB userPrincipalName_l
;
684 DATA_BLOB userPrincipalName_u
;
685 DATA_BLOB netbios_domain
;
686 DATA_BLOB netbios_domain_l
;
687 DATA_BLOB netbios_domain_u
;
688 DATA_BLOB dns_domain
;
689 DATA_BLOB dns_domain_l
;
690 DATA_BLOB dns_domain_u
;
702 * http://technet2.microsoft.com/WindowsServer/en/library/717b450c-f4a0-4cc9-86f4-cc0633aae5f91033.mspx?mfr=true
703 * for what precalculated hashes are supposed to be stored...
705 * I can't reproduce all values which should contain "Digest" as realm,
706 * am I doing something wrong or is w2k3 just broken...?
708 * W2K3 fills in following for a user:
710 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
711 * sAMAccountName: NewUser2Sam
712 * userPrincipalName: NewUser2Princ@sub1.w2k3.vmnet1.vm.base
714 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
715 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
716 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
717 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
718 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
719 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
720 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
721 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
722 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
723 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
724 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
725 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
726 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
727 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
728 * 221c55284451ae9b3aacaa2a3c86f10f => NewUser2Princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
729 * 74e1be668853d4324d38c07e2acfb8ea => (w2k3 has a bug here!) newuser2princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
730 * e1e244ab7f098e3ae1761be7f9229bbb => NEWUSER2PRINC@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
731 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
732 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
733 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
734 * 31dc704d3640335b2123d4ee28aa1f11 => ??? changes with NewUser2Sam => NewUser1Sam
735 * 36349f5cecd07320fb3bb0e119230c43 => ??? changes with NewUser2Sam => NewUser1Sam
736 * 12adf019d037fb535c01fd0608e78d9d => ??? changes with NewUser2Sam => NewUser1Sam
737 * 6feecf8e724906f3ee1105819c5105a1 => ??? changes with NewUser2Princ => NewUser1Princ
738 * 6c6911f3de6333422640221b9c51ff1f => ??? changes with NewUser2Princ => NewUser1Princ
739 * 4b279877e742895f9348ac67a8de2f69 => ??? changes with NewUser2Princ => NewUser1Princ
740 * db0c6bff069513e3ebb9870d29b57490 => ??? changes with NewUser2Sam => NewUser1Sam
741 * 45072621e56b1c113a4e04a8ff68cd0e => ??? changes with NewUser2Sam => NewUser1Sam
742 * 11d1220abc44a9c10cf91ef4a9c1de02 => ??? changes with NewUser2Sam => NewUser1Sam
744 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
745 * sAMAccountName: NewUser2Sam
747 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
748 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
749 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
750 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
751 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
752 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
753 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
754 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
755 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
756 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
757 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
758 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
759 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
760 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
761 * 8a140d30b6f0a5912735dc1e3bc993b4 => NewUser2Sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
762 * 86d95b2faae6cae4ec261e7fbaccf093 => (here w2k3 is correct) newuser2sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
763 * dfeff1493110220efcdfc6362e5f5450 => NEWUSER2SAM@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
764 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
765 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
766 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
767 * 31dc704d3640335b2123d4ee28aa1f11 => ???M1 changes with NewUser2Sam => NewUser1Sam
768 * 36349f5cecd07320fb3bb0e119230c43 => ???M1.L changes with newuser2sam => newuser1sam
769 * 12adf019d037fb535c01fd0608e78d9d => ???M1.U changes with NEWUSER2SAM => NEWUSER1SAM
770 * 569b4533f2d9e580211dd040e5e360a8 => ???M2 changes with NewUser2Princ => NewUser1Princ
771 * 52528bddf310a587c5d7e6a9ae2cbb20 => ???M2.L changes with newuser2princ => newuser1princ
772 * 4f629a4f0361289ca4255ab0f658fcd5 => ???M3 changes with NewUser2Princ => NewUser1Princ (doesn't depend on case of userPrincipal )
773 * db0c6bff069513e3ebb9870d29b57490 => ???M4 changes with NewUser2Sam => NewUser1Sam
774 * 45072621e56b1c113a4e04a8ff68cd0e => ???M5 changes with NewUser2Sam => NewUser1Sam (doesn't depend on case of sAMAccountName)
775 * 11d1220abc44a9c10cf91ef4a9c1de02 => ???M4.U changes with NEWUSER2SAM => NEWUSER1SAM
779 * sAMAccountName, netbios_domain
782 .user
= &sAMAccountName
,
783 .realm
= &netbios_domain
,
786 .user
= &sAMAccountName_l
,
787 .realm
= &netbios_domain_l
,
790 .user
= &sAMAccountName_u
,
791 .realm
= &netbios_domain_u
,
794 .user
= &sAMAccountName
,
795 .realm
= &netbios_domain_u
,
798 .user
= &sAMAccountName
,
799 .realm
= &netbios_domain_l
,
802 .user
= &sAMAccountName_u
,
803 .realm
= &netbios_domain_l
,
806 .user
= &sAMAccountName_l
,
807 .realm
= &netbios_domain_u
,
810 * sAMAccountName, dns_domain
813 .user
= &sAMAccountName
,
814 .realm
= &dns_domain
,
817 .user
= &sAMAccountName_l
,
818 .realm
= &dns_domain_l
,
821 .user
= &sAMAccountName_u
,
822 .realm
= &dns_domain_u
,
825 .user
= &sAMAccountName
,
826 .realm
= &dns_domain_u
,
829 .user
= &sAMAccountName
,
830 .realm
= &dns_domain_l
,
833 .user
= &sAMAccountName_u
,
834 .realm
= &dns_domain_l
,
837 .user
= &sAMAccountName_l
,
838 .realm
= &dns_domain_u
,
841 * userPrincipalName, no realm
844 .user
= &userPrincipalName
,
848 * NOTE: w2k3 messes this up, if the user has a real userPrincipalName,
849 * the fallback to the sAMAccountName based userPrincipalName is correct
851 .user
= &userPrincipalName_l
,
854 .user
= &userPrincipalName_u
,
857 * nt4dom\sAMAccountName, no realm
860 .user
= &sAMAccountName
,
861 .nt4dom
= &netbios_domain
864 .user
= &sAMAccountName_l
,
865 .nt4dom
= &netbios_domain_l
868 .user
= &sAMAccountName_u
,
869 .nt4dom
= &netbios_domain_u
873 * the following ones are guessed depending on the technet2 article
874 * but not reproducable on a w2k3 server
876 /* sAMAccountName with "Digest" realm */
878 .user
= &sAMAccountName
,
882 .user
= &sAMAccountName_l
,
886 .user
= &sAMAccountName_u
,
889 /* userPrincipalName with "Digest" realm */
891 .user
= &userPrincipalName
,
895 .user
= &userPrincipalName_l
,
899 .user
= &userPrincipalName_u
,
902 /* nt4dom\\sAMAccountName with "Digest" realm */
904 .user
= &sAMAccountName
,
905 .nt4dom
= &netbios_domain
,
909 .user
= &sAMAccountName_l
,
910 .nt4dom
= &netbios_domain_l
,
914 .user
= &sAMAccountName_u
,
915 .nt4dom
= &netbios_domain_u
,
920 /* prepare DATA_BLOB's used in the combinations array */
921 sAMAccountName
= data_blob_string_const(io
->u
.sAMAccountName
);
922 sAMAccountName_l
= data_blob_string_const(strlower_talloc(io
->ac
, io
->u
.sAMAccountName
));
923 if (!sAMAccountName_l
.data
) {
925 return LDB_ERR_OPERATIONS_ERROR
;
927 sAMAccountName_u
= data_blob_string_const(strupper_talloc(io
->ac
, io
->u
.sAMAccountName
));
928 if (!sAMAccountName_u
.data
) {
930 return LDB_ERR_OPERATIONS_ERROR
;
933 /* if the user doesn't have a userPrincipalName, create one (with lower case realm) */
934 if (!user_principal_name
) {
935 user_principal_name
= talloc_asprintf(io
->ac
, "%s@%s",
936 io
->u
.sAMAccountName
,
937 io
->domain
->dns_domain
);
938 if (!user_principal_name
) {
940 return LDB_ERR_OPERATIONS_ERROR
;
943 userPrincipalName
= data_blob_string_const(user_principal_name
);
944 userPrincipalName_l
= data_blob_string_const(strlower_talloc(io
->ac
, user_principal_name
));
945 if (!userPrincipalName_l
.data
) {
947 return LDB_ERR_OPERATIONS_ERROR
;
949 userPrincipalName_u
= data_blob_string_const(strupper_talloc(io
->ac
, user_principal_name
));
950 if (!userPrincipalName_u
.data
) {
952 return LDB_ERR_OPERATIONS_ERROR
;
955 netbios_domain
= data_blob_string_const(io
->domain
->netbios_domain
);
956 netbios_domain_l
= data_blob_string_const(strlower_talloc(io
->ac
, io
->domain
->netbios_domain
));
957 if (!netbios_domain_l
.data
) {
959 return LDB_ERR_OPERATIONS_ERROR
;
961 netbios_domain_u
= data_blob_string_const(strupper_talloc(io
->ac
, io
->domain
->netbios_domain
));
962 if (!netbios_domain_u
.data
) {
964 return LDB_ERR_OPERATIONS_ERROR
;
967 dns_domain
= data_blob_string_const(io
->domain
->dns_domain
);
968 dns_domain_l
= data_blob_string_const(io
->domain
->dns_domain
);
969 dns_domain_u
= data_blob_string_const(io
->domain
->realm
);
971 digest
= data_blob_string_const("Digest");
973 delim
= data_blob_string_const(":");
974 backslash
= data_blob_string_const("\\");
976 pdb
->num_hashes
= ARRAY_SIZE(wdigest
);
977 pdb
->hashes
= talloc_array(io
->ac
, struct package_PrimaryWDigestHash
,
981 return LDB_ERR_OPERATIONS_ERROR
;
984 for (i
=0; i
< ARRAY_SIZE(wdigest
); i
++) {
985 struct MD5Context md5
;
987 if (wdigest
[i
].nt4dom
) {
988 MD5Update(&md5
, wdigest
[i
].nt4dom
->data
, wdigest
[i
].nt4dom
->length
);
989 MD5Update(&md5
, backslash
.data
, backslash
.length
);
991 MD5Update(&md5
, wdigest
[i
].user
->data
, wdigest
[i
].user
->length
);
992 MD5Update(&md5
, delim
.data
, delim
.length
);
993 if (wdigest
[i
].realm
) {
994 MD5Update(&md5
, wdigest
[i
].realm
->data
, wdigest
[i
].realm
->length
);
996 MD5Update(&md5
, delim
.data
, delim
.length
);
997 MD5Update(&md5
, io
->n
.cleartext_utf8
->data
, io
->n
.cleartext_utf8
->length
);
998 MD5Final(pdb
->hashes
[i
].hash
, &md5
);
1004 static int setup_supplemental_field(struct setup_password_fields_io
*io
)
1006 struct ldb_context
*ldb
;
1007 struct supplementalCredentialsBlob scb
;
1008 struct supplementalCredentialsBlob _old_scb
;
1009 struct supplementalCredentialsBlob
*old_scb
= NULL
;
1010 /* Packages + (Kerberos-Newer-Keys, Kerberos, WDigest and CLEARTEXT) */
1011 uint32_t num_names
= 0;
1012 const char *names
[1+4];
1013 uint32_t num_packages
= 0;
1014 struct supplementalCredentialsPackage packages
[1+4];
1016 struct supplementalCredentialsPackage
*pp
= NULL
;
1017 struct package_PackagesBlob pb
;
1020 /* Primary:Kerberos-Newer-Keys */
1021 const char **nkn
= NULL
;
1022 struct supplementalCredentialsPackage
*pkn
= NULL
;
1023 struct package_PrimaryKerberosBlob pknb
;
1024 DATA_BLOB pknb_blob
;
1026 /* Primary:Kerberos */
1027 const char **nk
= NULL
;
1028 struct supplementalCredentialsPackage
*pk
= NULL
;
1029 struct package_PrimaryKerberosBlob pkb
;
1032 /* Primary:WDigest */
1033 const char **nd
= NULL
;
1034 struct supplementalCredentialsPackage
*pd
= NULL
;
1035 struct package_PrimaryWDigestBlob pdb
;
1038 /* Primary:CLEARTEXT */
1039 const char **nc
= NULL
;
1040 struct supplementalCredentialsPackage
*pc
= NULL
;
1041 struct package_PrimaryCLEARTEXTBlob pcb
;
1045 enum ndr_err_code ndr_err
;
1047 bool do_newer_keys
= false;
1048 bool do_cleartext
= false;
1050 ZERO_STRUCT(zero16
);
1053 ldb
= ldb_module_get_ctx(io
->ac
->module
);
1055 if (!io
->n
.cleartext_utf8
) {
1057 * when we don't have a cleartext password
1058 * we can't setup a supplementalCredential value
1063 /* if there's an old supplementaCredentials blob then parse it */
1064 if (io
->o
.supplemental
) {
1065 ndr_err
= ndr_pull_struct_blob_all(io
->o
.supplemental
, io
->ac
,
1066 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1068 (ndr_pull_flags_fn_t
)ndr_pull_supplementalCredentialsBlob
);
1069 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1070 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1071 ldb_asprintf_errstring(ldb
,
1072 "setup_supplemental_field: "
1073 "failed to pull old supplementalCredentialsBlob: %s",
1075 return LDB_ERR_OPERATIONS_ERROR
;
1078 if (_old_scb
.sub
.signature
== SUPPLEMENTAL_CREDENTIALS_SIGNATURE
) {
1079 old_scb
= &_old_scb
;
1081 ldb_debug(ldb
, LDB_DEBUG_ERROR
,
1082 "setup_supplemental_field: "
1083 "supplementalCredentialsBlob signature[0x%04X] expected[0x%04X]",
1084 _old_scb
.sub
.signature
, SUPPLEMENTAL_CREDENTIALS_SIGNATURE
);
1087 /* Per MS-SAMR 3.1.1.8.11.6 we create AES keys if our domain functionality level is 2008 or higher */
1088 do_newer_keys
= (dsdb_functional_level(ldb
) >= DS_DOMAIN_FUNCTION_2008
);
1090 if (io
->domain
->store_cleartext
&&
1091 (io
->u
.userAccountControl
& UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED
)) {
1092 do_cleartext
= true;
1096 * The ordering is this
1098 * Primary:Kerberos-Newer-Keys (optional)
1101 * Primary:CLEARTEXT (optional)
1103 * And the 'Packages' package is insert before the last
1106 if (do_newer_keys
) {
1107 /* Primary:Kerberos-Newer-Keys */
1108 nkn
= &names
[num_names
++];
1109 pkn
= &packages
[num_packages
++];
1112 /* Primary:Kerberos */
1113 nk
= &names
[num_names
++];
1114 pk
= &packages
[num_packages
++];
1116 if (!do_cleartext
) {
1118 pp
= &packages
[num_packages
++];
1121 /* Primary:WDigest */
1122 nd
= &names
[num_names
++];
1123 pd
= &packages
[num_packages
++];
1127 pp
= &packages
[num_packages
++];
1129 /* Primary:CLEARTEXT */
1130 nc
= &names
[num_names
++];
1131 pc
= &packages
[num_packages
++];
1136 * setup 'Primary:Kerberos-Newer-Keys' element
1138 *nkn
= "Kerberos-Newer-Keys";
1140 ret
= setup_primary_kerberos_newer(io
, old_scb
, &pknb
);
1141 if (ret
!= LDB_SUCCESS
) {
1145 ndr_err
= ndr_push_struct_blob(&pknb_blob
, io
->ac
,
1146 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1148 (ndr_push_flags_fn_t
)ndr_push_package_PrimaryKerberosBlob
);
1149 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1150 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1151 ldb_asprintf_errstring(ldb
,
1152 "setup_supplemental_field: "
1153 "failed to push package_PrimaryKerberosNeverBlob: %s",
1155 return LDB_ERR_OPERATIONS_ERROR
;
1157 pknb_hexstr
= data_blob_hex_string_upper(io
->ac
, &pknb_blob
);
1160 return LDB_ERR_OPERATIONS_ERROR
;
1162 pkn
->name
= "Primary:Kerberos-Newer-Keys";
1164 pkn
->data
= pknb_hexstr
;
1168 * setup 'Primary:Kerberos' element
1172 ret
= setup_primary_kerberos(io
, old_scb
, &pkb
);
1173 if (ret
!= LDB_SUCCESS
) {
1177 ndr_err
= ndr_push_struct_blob(&pkb_blob
, io
->ac
,
1178 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1180 (ndr_push_flags_fn_t
)ndr_push_package_PrimaryKerberosBlob
);
1181 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1182 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1183 ldb_asprintf_errstring(ldb
,
1184 "setup_supplemental_field: "
1185 "failed to push package_PrimaryKerberosBlob: %s",
1187 return LDB_ERR_OPERATIONS_ERROR
;
1189 pkb_hexstr
= data_blob_hex_string_upper(io
->ac
, &pkb_blob
);
1192 return LDB_ERR_OPERATIONS_ERROR
;
1194 pk
->name
= "Primary:Kerberos";
1196 pk
->data
= pkb_hexstr
;
1199 * setup 'Primary:WDigest' element
1203 ret
= setup_primary_wdigest(io
, old_scb
, &pdb
);
1204 if (ret
!= LDB_SUCCESS
) {
1208 ndr_err
= ndr_push_struct_blob(&pdb_blob
, io
->ac
,
1209 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1211 (ndr_push_flags_fn_t
)ndr_push_package_PrimaryWDigestBlob
);
1212 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1213 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1214 ldb_asprintf_errstring(ldb
,
1215 "setup_supplemental_field: "
1216 "failed to push package_PrimaryWDigestBlob: %s",
1218 return LDB_ERR_OPERATIONS_ERROR
;
1220 pdb_hexstr
= data_blob_hex_string_upper(io
->ac
, &pdb_blob
);
1223 return LDB_ERR_OPERATIONS_ERROR
;
1225 pd
->name
= "Primary:WDigest";
1227 pd
->data
= pdb_hexstr
;
1230 * setup 'Primary:CLEARTEXT' element
1235 pcb
.cleartext
= *io
->n
.cleartext_utf16
;
1237 ndr_err
= ndr_push_struct_blob(&pcb_blob
, io
->ac
,
1238 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1240 (ndr_push_flags_fn_t
)ndr_push_package_PrimaryCLEARTEXTBlob
);
1241 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1242 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1243 ldb_asprintf_errstring(ldb
,
1244 "setup_supplemental_field: "
1245 "failed to push package_PrimaryCLEARTEXTBlob: %s",
1247 return LDB_ERR_OPERATIONS_ERROR
;
1249 pcb_hexstr
= data_blob_hex_string_upper(io
->ac
, &pcb_blob
);
1252 return LDB_ERR_OPERATIONS_ERROR
;
1254 pc
->name
= "Primary:CLEARTEXT";
1256 pc
->data
= pcb_hexstr
;
1260 * setup 'Packages' element
1263 ndr_err
= ndr_push_struct_blob(&pb_blob
, io
->ac
,
1264 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1266 (ndr_push_flags_fn_t
)ndr_push_package_PackagesBlob
);
1267 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1268 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1269 ldb_asprintf_errstring(ldb
,
1270 "setup_supplemental_field: "
1271 "failed to push package_PackagesBlob: %s",
1273 return LDB_ERR_OPERATIONS_ERROR
;
1275 pb_hexstr
= data_blob_hex_string_upper(io
->ac
, &pb_blob
);
1278 return LDB_ERR_OPERATIONS_ERROR
;
1280 pp
->name
= "Packages";
1282 pp
->data
= pb_hexstr
;
1285 * setup 'supplementalCredentials' value
1288 scb
.sub
.num_packages
= num_packages
;
1289 scb
.sub
.packages
= packages
;
1291 ndr_err
= ndr_push_struct_blob(&io
->g
.supplemental
, io
->ac
,
1292 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1294 (ndr_push_flags_fn_t
)ndr_push_supplementalCredentialsBlob
);
1295 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1296 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1297 ldb_asprintf_errstring(ldb
,
1298 "setup_supplemental_field: "
1299 "failed to push supplementalCredentialsBlob: %s",
1301 return LDB_ERR_OPERATIONS_ERROR
;
1307 static int setup_last_set_field(struct setup_password_fields_io
*io
)
1310 unix_to_nt_time(&io
->g
.last_set
, time(NULL
));
1315 static int setup_password_fields(struct setup_password_fields_io
*io
)
1317 struct ldb_context
*ldb
;
1320 size_t converted_pw_len
;
1322 ldb
= ldb_module_get_ctx(io
->ac
->module
);
1325 * refuse the change if someone want to change the cleartext
1326 * and supply his own hashes at the same time...
1328 if ((io
->n
.cleartext_utf8
|| io
->n
.cleartext_utf16
) && (io
->n
.nt_hash
|| io
->n
.lm_hash
)) {
1329 ldb_asprintf_errstring(ldb
,
1330 "setup_password_fields: "
1331 "it's only allowed to set the cleartext password or the password hashes");
1332 return LDB_ERR_UNWILLING_TO_PERFORM
;
1335 if (io
->n
.cleartext_utf8
&& io
->n
.cleartext_utf16
) {
1336 ldb_asprintf_errstring(ldb
,
1337 "setup_password_fields: "
1338 "it's only allowed to set the cleartext password as userPassword or clearTextPasssword, not both at once");
1339 return LDB_ERR_UNWILLING_TO_PERFORM
;
1342 if (io
->n
.cleartext_utf8
) {
1343 char **cleartext_utf16_str
;
1344 struct ldb_val
*cleartext_utf16_blob
;
1345 io
->n
.cleartext_utf16
= cleartext_utf16_blob
= talloc(io
->ac
, struct ldb_val
);
1346 if (!io
->n
.cleartext_utf16
) {
1348 return LDB_ERR_OPERATIONS_ERROR
;
1350 if (!convert_string_talloc_convenience(io
->ac
,
1351 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1353 io
->n
.cleartext_utf8
->data
,
1354 io
->n
.cleartext_utf8
->length
,
1355 (void **)&cleartext_utf16_str
,
1356 &converted_pw_len
, false)) {
1357 ldb_asprintf_errstring(ldb
,
1358 "setup_password_fields: "
1359 "failed to generate UTF16 password from cleartext UTF8 password");
1360 return LDB_ERR_OPERATIONS_ERROR
;
1362 *cleartext_utf16_blob
= data_blob_const(cleartext_utf16_str
,
1364 } else if (io
->n
.cleartext_utf16
) {
1365 char *cleartext_utf8_str
;
1366 struct ldb_val
*cleartext_utf8_blob
;
1367 io
->n
.cleartext_utf8
= cleartext_utf8_blob
= talloc(io
->ac
, struct ldb_val
);
1368 if (!io
->n
.cleartext_utf8
) {
1370 return LDB_ERR_OPERATIONS_ERROR
;
1372 if (!convert_string_talloc_convenience(io
->ac
,
1373 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1374 CH_UTF16MUNGED
, CH_UTF8
,
1375 io
->n
.cleartext_utf16
->data
,
1376 io
->n
.cleartext_utf16
->length
,
1377 (void **)&cleartext_utf8_str
,
1378 &converted_pw_len
, false)) {
1379 /* We can't bail out entirely, as these unconvertable passwords are frustratingly valid */
1380 io
->n
.cleartext_utf8
= NULL
;
1381 talloc_free(cleartext_utf8_blob
);
1383 *cleartext_utf8_blob
= data_blob_const(cleartext_utf8_str
,
1386 if (io
->n
.cleartext_utf16
) {
1387 struct samr_Password
*nt_hash
;
1388 nt_hash
= talloc(io
->ac
, struct samr_Password
);
1391 return LDB_ERR_OPERATIONS_ERROR
;
1393 io
->n
.nt_hash
= nt_hash
;
1395 /* compute the new nt hash */
1396 mdfour(nt_hash
->hash
, io
->n
.cleartext_utf16
->data
,
1397 io
->n
.cleartext_utf16
->length
);
1400 if (io
->n
.cleartext_utf8
) {
1401 struct samr_Password
*lm_hash
;
1402 char *cleartext_unix
;
1403 if (lp_lanman_auth(ldb_get_opaque(ldb
, "loadparm")) &&
1404 convert_string_talloc_convenience(io
->ac
,
1405 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1407 io
->n
.cleartext_utf8
->data
,
1408 io
->n
.cleartext_utf8
->length
,
1409 (void **)&cleartext_unix
,
1410 &converted_pw_len
, false)) {
1411 lm_hash
= talloc(io
->ac
, struct samr_Password
);
1414 return LDB_ERR_OPERATIONS_ERROR
;
1417 /* compute the new lm hash */
1418 ok
= E_deshash((char *)cleartext_unix
, lm_hash
->hash
);
1420 io
->n
.lm_hash
= lm_hash
;
1422 talloc_free(lm_hash
->hash
);
1426 ret
= setup_kerberos_keys(io
);
1427 if (ret
!= LDB_SUCCESS
) {
1432 ret
= setup_nt_fields(io
);
1433 if (ret
!= LDB_SUCCESS
) {
1437 ret
= setup_lm_fields(io
);
1438 if (ret
!= LDB_SUCCESS
) {
1442 ret
= setup_supplemental_field(io
);
1443 if (ret
!= LDB_SUCCESS
) {
1447 ret
= setup_last_set_field(io
);
1448 if (ret
!= LDB_SUCCESS
) {
1455 static int setup_io(struct ph_context
*ac
,
1456 const struct ldb_message
*orig_msg
,
1457 const struct ldb_message
*searched_msg
,
1458 struct setup_password_fields_io
*io
)
1460 const struct ldb_val
*quoted_utf16
;
1461 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
1465 /* Some operations below require kerberos contexts */
1466 if (smb_krb5_init_context(ac
,
1467 ldb_get_event_context(ldb
),
1468 (struct loadparm_context
*)ldb_get_opaque(ldb
, "loadparm"),
1469 &io
->smb_krb5_context
) != 0) {
1470 return LDB_ERR_OPERATIONS_ERROR
;
1474 io
->domain
= ac
->domain
;
1476 io
->u
.userAccountControl
= samdb_result_uint(searched_msg
, "userAccountControl", 0);
1477 io
->u
.pwdLastSet
= samdb_result_nttime(searched_msg
, "pwdLastSet", 0);
1478 io
->u
.sAMAccountName
= samdb_result_string(searched_msg
, "sAMAccountName", NULL
);
1479 io
->u
.user_principal_name
= samdb_result_string(searched_msg
, "userPrincipalName", NULL
);
1480 io
->u
.is_computer
= ldb_msg_check_string_attribute(searched_msg
, "objectClass", "computer");
1482 if (io
->u
.sAMAccountName
== NULL
) {
1483 ldb_asprintf_errstring(ldb
,
1484 "setup_io: sAMAccountName attribute is missing on %s for attempted password set/change",
1485 ldb_dn_get_linearized(searched_msg
->dn
));
1487 return LDB_ERR_CONSTRAINT_VIOLATION
;
1490 io
->n
.cleartext_utf8
= ldb_msg_find_ldb_val(orig_msg
, "userPassword");
1491 io
->n
.cleartext_utf16
= ldb_msg_find_ldb_val(orig_msg
, "clearTextPassword");
1493 /* this rather strange looking piece of code is there to
1494 handle a ldap client setting a password remotely using the
1495 unicodePwd ldap field. The syntax is that the password is
1496 in UTF-16LE, with a " at either end. Unfortunately the
1497 unicodePwd field is also used to store the nt hashes
1498 internally in Samba, and is used in the nt hash format on
1499 the wire in DRS replication, so we have a single name for
1500 two distinct values. The code below leaves us with a small
1501 chance (less than 1 in 2^32) of a mixup, if someone manages
1502 to create a MD4 hash which starts and ends in 0x22 0x00, as
1503 that would then be treated as a UTF16 password rather than
1505 quoted_utf16
= ldb_msg_find_ldb_val(orig_msg
, "unicodePwd");
1507 quoted_utf16
->length
>= 4 &&
1508 quoted_utf16
->data
[0] == '"' &&
1509 quoted_utf16
->data
[1] == 0 &&
1510 quoted_utf16
->data
[quoted_utf16
->length
-2] == '"' &&
1511 quoted_utf16
->data
[quoted_utf16
->length
-1] == 0) {
1512 io
->n
.quoted_utf16
.data
= talloc_memdup(io
->ac
, quoted_utf16
->data
+2, quoted_utf16
->length
-4);
1513 io
->n
.quoted_utf16
.length
= quoted_utf16
->length
-4;
1514 io
->n
.cleartext_utf16
= &io
->n
.quoted_utf16
;
1515 io
->n
.nt_hash
= NULL
;
1517 io
->n
.nt_hash
= samdb_result_hash(io
->ac
, orig_msg
, "unicodePwd");
1520 io
->n
.lm_hash
= samdb_result_hash(io
->ac
, orig_msg
, "dBCSPwd");
1525 static struct ph_context
*ph_init_context(struct ldb_module
*module
,
1526 struct ldb_request
*req
)
1528 struct ldb_context
*ldb
;
1529 struct ph_context
*ac
;
1531 ldb
= ldb_module_get_ctx(module
);
1533 ac
= talloc_zero(req
, struct ph_context
);
1535 ldb_set_errstring(ldb
, "Out of Memory");
1539 ac
->module
= module
;
1545 static int ph_op_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
1547 struct ph_context
*ac
;
1549 ac
= talloc_get_type(req
->context
, struct ph_context
);
1552 return ldb_module_done(ac
->req
, NULL
, NULL
,
1553 LDB_ERR_OPERATIONS_ERROR
);
1556 if (ares
->type
== LDB_REPLY_REFERRAL
) {
1557 return ldb_module_send_referral(ac
->req
, ares
->referral
);
1560 if (ares
->error
!= LDB_SUCCESS
) {
1561 return ldb_module_done(ac
->req
, ares
->controls
,
1562 ares
->response
, ares
->error
);
1565 if (ares
->type
!= LDB_REPLY_DONE
) {
1567 return ldb_module_done(ac
->req
, NULL
, NULL
,
1568 LDB_ERR_OPERATIONS_ERROR
);
1571 return ldb_module_done(ac
->req
, ares
->controls
,
1572 ares
->response
, ares
->error
);
1575 static int password_hash_add_do_add(struct ph_context
*ac
);
1576 static int ph_modify_callback(struct ldb_request
*req
, struct ldb_reply
*ares
);
1577 static int password_hash_mod_search_self(struct ph_context
*ac
);
1578 static int ph_mod_search_callback(struct ldb_request
*req
, struct ldb_reply
*ares
);
1579 static int password_hash_mod_do_mod(struct ph_context
*ac
);
1581 static int get_domain_data_callback(struct ldb_request
*req
,
1582 struct ldb_reply
*ares
)
1584 struct ldb_context
*ldb
;
1585 struct domain_data
*data
;
1586 struct ph_context
*ac
;
1587 struct loadparm_context
*lp_ctx
;
1590 ac
= talloc_get_type(req
->context
, struct ph_context
);
1591 ldb
= ldb_module_get_ctx(ac
->module
);
1594 ret
= LDB_ERR_OPERATIONS_ERROR
;
1597 if (ares
->error
!= LDB_SUCCESS
) {
1598 return ldb_module_done(ac
->req
, ares
->controls
,
1599 ares
->response
, ares
->error
);
1602 switch (ares
->type
) {
1603 case LDB_REPLY_ENTRY
:
1604 if (ac
->domain
!= NULL
) {
1607 ldb_set_errstring(ldb
, "Too many results");
1608 ret
= LDB_ERR_OPERATIONS_ERROR
;
1612 data
= talloc_zero(ac
, struct domain_data
);
1617 ret
= LDB_ERR_OPERATIONS_ERROR
;
1621 data
->pwdProperties
= samdb_result_uint(ares
->message
, "pwdProperties", -1);
1622 data
->pwdHistoryLength
= samdb_result_uint(ares
->message
, "pwdHistoryLength", -1);
1623 data
->maxPwdAge
= samdb_result_int64(ares
->message
, "maxPwdAge", -1);
1624 data
->minPwdAge
= samdb_result_int64(ares
->message
, "minPwdAge", -1);
1625 data
->minPwdLength
= samdb_result_uint(ares
->message
, "minPwdLength", -1);
1626 data
->store_cleartext
=
1627 data
->pwdProperties
& DOMAIN_PASSWORD_STORE_CLEARTEXT
;
1631 /* For a domain DN, this puts things in dotted notation */
1632 /* For builtin domains, this will give details for the host,
1633 * but that doesn't really matter, as it's just used for salt
1634 * and kerberos principals, which don't exist here */
1636 lp_ctx
= talloc_get_type(ldb_get_opaque(ldb
, "loadparm"),
1637 struct loadparm_context
);
1639 data
->dns_domain
= lp_dnsdomain(lp_ctx
);
1640 data
->realm
= lp_realm(lp_ctx
);
1641 data
->netbios_domain
= lp_sam_name(lp_ctx
);
1648 case LDB_REPLY_REFERRAL
:
1654 case LDB_REPLY_DONE
:
1656 /* call the next step */
1657 switch (ac
->req
->operation
) {
1659 ret
= password_hash_add_do_add(ac
);
1663 ret
= password_hash_mod_do_mod(ac
);
1667 ret
= LDB_ERR_OPERATIONS_ERROR
;
1675 if (ret
!= LDB_SUCCESS
) {
1676 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
1682 static int build_domain_data_request(struct ph_context
*ac
)
1684 /* attrs[] is returned from this function in
1685 ac->dom_req->op.search.attrs, so it must be static, as
1686 otherwise the compiler can put it on the stack */
1687 struct ldb_context
*ldb
;
1688 static const char * const attrs
[] = { "pwdProperties",
1695 ldb
= ldb_module_get_ctx(ac
->module
);
1697 return ldb_build_search_req(&ac
->dom_req
, ldb
, ac
,
1698 ldb_get_default_basedn(ldb
),
1702 ac
, get_domain_data_callback
,
1706 static int password_hash_add(struct ldb_module
*module
, struct ldb_request
*req
)
1708 struct ldb_context
*ldb
;
1709 struct ph_context
*ac
;
1710 struct ldb_message_element
*userPasswordAttr
, *clearTextPasswordAttr
,
1714 ldb
= ldb_module_get_ctx(module
);
1716 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "password_hash_add\n");
1718 if (ldb_dn_is_special(req
->op
.add
.message
->dn
)) { /* do not manipulate our control entries */
1719 return ldb_next_request(module
, req
);
1722 /* If the caller is manipulating the local passwords directly, let them pass */
1723 if (ldb_dn_compare_base(ldb_dn_new(req
, ldb
, LOCAL_BASE
),
1724 req
->op
.add
.message
->dn
) == 0) {
1725 return ldb_next_request(module
, req
);
1728 /* nobody must touch password histories and 'supplementalCredentials' */
1729 if (ldb_msg_find_element(req
->op
.add
.message
, "ntPwdHistory")) {
1730 return LDB_ERR_UNWILLING_TO_PERFORM
;
1732 if (ldb_msg_find_element(req
->op
.add
.message
, "lmPwdHistory")) {
1733 return LDB_ERR_UNWILLING_TO_PERFORM
;
1735 if (ldb_msg_find_element(req
->op
.add
.message
, "supplementalCredentials")) {
1736 return LDB_ERR_UNWILLING_TO_PERFORM
;
1739 /* If no part of this touches the 'userPassword' OR 'clearTextPassword'
1740 * OR 'unicodePwd' OR 'dBCSPwd' we don't need to make any changes. */
1742 userPasswordAttr
= ldb_msg_find_element(req
->op
.add
.message
, "userPassword");
1743 clearTextPasswordAttr
= ldb_msg_find_element(req
->op
.add
.message
, "clearTextPassword");
1744 ntAttr
= ldb_msg_find_element(req
->op
.add
.message
, "unicodePwd");
1745 lmAttr
= ldb_msg_find_element(req
->op
.add
.message
, "dBCSPwd");
1747 if ((!userPasswordAttr
) && (!clearTextPasswordAttr
) && (!ntAttr
) && (!lmAttr
)) {
1748 return ldb_next_request(module
, req
);
1751 /* Make sure we are performing the password set action on a (for us)
1752 * valid object. Those are instances of either "user" and/or
1753 * "inetOrgPerson". Otherwise continue with the submodules. */
1754 if ((!ldb_msg_check_string_attribute(req
->op
.add
.message
, "objectClass", "user"))
1755 && (!ldb_msg_check_string_attribute(req
->op
.add
.message
, "objectClass", "inetOrgPerson"))) {
1757 if (ldb_msg_find_element(req
->op
.add
.message
, "clearTextPassword") != NULL
) {
1758 ldb_set_errstring(ldb
,
1759 "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
1760 return LDB_ERR_NO_SUCH_ATTRIBUTE
;
1763 return ldb_next_request(module
, req
);
1766 ac
= ph_init_context(module
, req
);
1768 DEBUG(0,(__location__
": %s\n", ldb_errstring(ldb
)));
1769 return LDB_ERR_OPERATIONS_ERROR
;
1772 /* get user domain data */
1773 ret
= build_domain_data_request(ac
);
1774 if (ret
!= LDB_SUCCESS
) {
1778 return ldb_next_request(module
, ac
->dom_req
);
1781 static int password_hash_add_do_add(struct ph_context
*ac
)
1783 struct ldb_context
*ldb
;
1784 struct ldb_request
*down_req
;
1785 struct ldb_message
*msg
;
1786 struct setup_password_fields_io io
;
1789 /* Prepare the internal data structure containing the passwords */
1790 ret
= setup_io(ac
, ac
->req
->op
.add
.message
, ac
->req
->op
.add
.message
, &io
);
1791 if (ret
!= LDB_SUCCESS
) {
1795 msg
= ldb_msg_copy_shallow(ac
, ac
->req
->op
.add
.message
);
1797 return LDB_ERR_OPERATIONS_ERROR
;
1800 /* remove attributes that we just read into 'io' */
1801 ldb_msg_remove_attr(msg
, "userPassword");
1802 ldb_msg_remove_attr(msg
, "clearTextPassword");
1803 ldb_msg_remove_attr(msg
, "unicodePwd");
1804 ldb_msg_remove_attr(msg
, "dBCSPwd");
1805 ldb_msg_remove_attr(msg
, "pwdLastSet");
1807 ldb
= ldb_module_get_ctx(ac
->module
);
1809 ret
= setup_password_fields(&io
);
1810 if (ret
!= LDB_SUCCESS
) {
1815 ret
= samdb_msg_add_hash(ldb
, ac
, msg
,
1816 "unicodePwd", io
.g
.nt_hash
);
1817 if (ret
!= LDB_SUCCESS
) {
1822 ret
= samdb_msg_add_hash(ldb
, ac
, msg
,
1823 "dBCSPwd", io
.g
.lm_hash
);
1824 if (ret
!= LDB_SUCCESS
) {
1828 if (io
.g
.nt_history_len
> 0) {
1829 ret
= samdb_msg_add_hashes(ac
, msg
,
1832 io
.g
.nt_history_len
);
1833 if (ret
!= LDB_SUCCESS
) {
1837 if (io
.g
.lm_history_len
> 0) {
1838 ret
= samdb_msg_add_hashes(ac
, msg
,
1841 io
.g
.lm_history_len
);
1842 if (ret
!= LDB_SUCCESS
) {
1846 if (io
.g
.supplemental
.length
> 0) {
1847 ret
= ldb_msg_add_value(msg
, "supplementalCredentials",
1848 &io
.g
.supplemental
, NULL
);
1849 if (ret
!= LDB_SUCCESS
) {
1853 ret
= samdb_msg_add_uint64(ldb
, ac
, msg
,
1856 if (ret
!= LDB_SUCCESS
) {
1860 ret
= ldb_build_add_req(&down_req
, ldb
, ac
,
1865 if (ret
!= LDB_SUCCESS
) {
1869 return ldb_next_request(ac
->module
, down_req
);
1872 static int password_hash_modify(struct ldb_module
*module
, struct ldb_request
*req
)
1874 struct ldb_context
*ldb
;
1875 struct ph_context
*ac
;
1876 const char *passwordAttrs
[] = { "userPassword", "clearTextPassword",
1877 "unicodePwd", "dBCSPwd", NULL
}, **l
;
1878 unsigned int attr_cnt
, del_attr_cnt
, add_attr_cnt
, rep_attr_cnt
;
1879 struct ldb_message_element
*passwordAttr
;
1880 struct ldb_message
*msg
;
1881 struct ldb_request
*down_req
;
1884 ldb
= ldb_module_get_ctx(module
);
1886 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "password_hash_modify\n");
1888 if (ldb_dn_is_special(req
->op
.mod
.message
->dn
)) { /* do not manipulate our control entries */
1889 return ldb_next_request(module
, req
);
1892 /* If the caller is manipulating the local passwords directly, let them pass */
1893 if (ldb_dn_compare_base(ldb_dn_new(req
, ldb
, LOCAL_BASE
),
1894 req
->op
.mod
.message
->dn
) == 0) {
1895 return ldb_next_request(module
, req
);
1898 /* nobody must touch password histories and 'supplementalCredentials' */
1899 if (ldb_msg_find_element(req
->op
.mod
.message
, "ntPwdHistory")) {
1900 return LDB_ERR_UNWILLING_TO_PERFORM
;
1902 if (ldb_msg_find_element(req
->op
.mod
.message
, "lmPwdHistory")) {
1903 return LDB_ERR_UNWILLING_TO_PERFORM
;
1905 if (ldb_msg_find_element(req
->op
.mod
.message
, "supplementalCredentials")) {
1906 return LDB_ERR_UNWILLING_TO_PERFORM
;
1909 /* If no part of this touches the 'userPassword' OR 'clearTextPassword'
1910 * OR 'unicodePwd' OR 'dBCSPwd' we don't need to make any changes.
1911 * For password changes/set there should be a 'delete' or a 'modify'
1912 * on these attributes. */
1914 for (l
= passwordAttrs
; *l
!= NULL
; l
++) {
1915 if (ldb_msg_find_element(req
->op
.mod
.message
, *l
) != NULL
) {
1919 if (attr_cnt
== 0) {
1920 return ldb_next_request(module
, req
);
1923 ac
= ph_init_context(module
, req
);
1925 DEBUG(0,(__location__
": %s\n", ldb_errstring(ldb
)));
1926 return LDB_ERR_OPERATIONS_ERROR
;
1929 /* use a new message structure so that we can modify it */
1930 msg
= ldb_msg_copy_shallow(ac
, req
->op
.mod
.message
);
1933 return LDB_ERR_OPERATIONS_ERROR
;
1936 /* - check for single-valued password attributes
1937 * (if not return "CONSTRAINT_VIOLATION")
1938 * - check that for a password change operation one add and one delete
1940 * (if not return "CONSTRAINT_VIOLATION" or "UNWILLING_TO_PERFORM")
1941 * - check that a password change and a password set operation cannot
1943 * (if not return "UNWILLING_TO_PERFORM")
1944 * - remove all password attributes modifications from the first change
1945 * operation (anything without the passwords) - we will make the real
1946 * modification later */
1950 for (l
= passwordAttrs
; *l
!= NULL
; l
++) {
1951 while ((passwordAttr
= ldb_msg_find_element(msg
, *l
)) != NULL
) {
1952 if (passwordAttr
->flags
== LDB_FLAG_MOD_DELETE
) {
1955 if (passwordAttr
->flags
== LDB_FLAG_MOD_ADD
) {
1958 if (passwordAttr
->flags
== LDB_FLAG_MOD_REPLACE
) {
1961 if ((passwordAttr
->num_values
!= 1) &&
1962 (passwordAttr
->flags
!= LDB_FLAG_MOD_REPLACE
)) {
1964 ldb_asprintf_errstring(ldb
,
1965 "'%s' attributes must have exactly one value!",
1967 return LDB_ERR_CONSTRAINT_VIOLATION
;
1969 ldb_msg_remove_attr(msg
, *l
);
1972 if ((del_attr_cnt
> 0) && (add_attr_cnt
== 0)) {
1974 ldb_set_errstring(ldb
,
1975 "Only the delete action for a password change specified!");
1976 return LDB_ERR_CONSTRAINT_VIOLATION
;
1978 if ((del_attr_cnt
== 0) && (add_attr_cnt
> 0)) {
1980 ldb_set_errstring(ldb
,
1981 "Only the add action for a password change specified!");
1982 return LDB_ERR_UNWILLING_TO_PERFORM
;
1984 if ((del_attr_cnt
> 1) || (add_attr_cnt
> 1)) {
1986 ldb_set_errstring(ldb
,
1987 "Only one delete and one add action for a password change allowed!");
1988 return LDB_ERR_UNWILLING_TO_PERFORM
;
1990 if ((rep_attr_cnt
> 0) && ((del_attr_cnt
> 0) || (add_attr_cnt
> 0))) {
1992 ldb_set_errstring(ldb
,
1993 "Either a password change or a password set operation is allowed!");
1994 return LDB_ERR_UNWILLING_TO_PERFORM
;
1997 /* if there was nothing else to be modified skip to next step */
1998 if (msg
->num_elements
== 0) {
1999 return password_hash_mod_search_self(ac
);
2002 ret
= ldb_build_mod_req(&down_req
, ldb
, ac
,
2005 ac
, ph_modify_callback
,
2007 if (ret
!= LDB_SUCCESS
) {
2011 return ldb_next_request(module
, down_req
);
2014 static int ph_modify_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
2016 struct ph_context
*ac
;
2018 ac
= talloc_get_type(req
->context
, struct ph_context
);
2021 return ldb_module_done(ac
->req
, NULL
, NULL
,
2022 LDB_ERR_OPERATIONS_ERROR
);
2025 if (ares
->type
== LDB_REPLY_REFERRAL
) {
2026 return ldb_module_send_referral(ac
->req
, ares
->referral
);
2029 if (ares
->error
!= LDB_SUCCESS
) {
2030 return ldb_module_done(ac
->req
, ares
->controls
,
2031 ares
->response
, ares
->error
);
2034 if (ares
->type
!= LDB_REPLY_DONE
) {
2036 return ldb_module_done(ac
->req
, NULL
, NULL
,
2037 LDB_ERR_OPERATIONS_ERROR
);
2042 return password_hash_mod_search_self(ac
);
2045 static int ph_mod_search_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
2047 struct ldb_context
*ldb
;
2048 struct ph_context
*ac
;
2051 ac
= talloc_get_type(req
->context
, struct ph_context
);
2052 ldb
= ldb_module_get_ctx(ac
->module
);
2055 ret
= LDB_ERR_OPERATIONS_ERROR
;
2058 if (ares
->error
!= LDB_SUCCESS
) {
2059 return ldb_module_done(ac
->req
, ares
->controls
,
2060 ares
->response
, ares
->error
);
2063 /* we are interested only in the single reply (base search) */
2064 switch (ares
->type
) {
2065 case LDB_REPLY_ENTRY
:
2066 /* Make sure we are performing the password change action on a
2067 * (for us) valid object. Those are instances of either "user"
2068 * and/or "inetOrgPerson". Otherwise continue with the
2070 if ((!ldb_msg_check_string_attribute(ares
->message
, "objectClass", "user"))
2071 && (!ldb_msg_check_string_attribute(ares
->message
, "objectClass", "inetOrgPerson"))) {
2074 if (ldb_msg_find_element(ac
->req
->op
.mod
.message
, "clearTextPassword") != NULL
) {
2075 ldb_set_errstring(ldb
,
2076 "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
2077 ret
= LDB_ERR_NO_SUCH_ATTRIBUTE
;
2081 ret
= ldb_next_request(ac
->module
, ac
->req
);
2085 if (ac
->search_res
!= NULL
) {
2088 ldb_set_errstring(ldb
, "Too many results");
2089 ret
= LDB_ERR_OPERATIONS_ERROR
;
2093 ac
->search_res
= talloc_steal(ac
, ares
);
2097 case LDB_REPLY_REFERRAL
:
2098 /* ignore anything else for now */
2103 case LDB_REPLY_DONE
:
2106 /* get user domain data */
2107 ret
= build_domain_data_request(ac
);
2108 if (ret
!= LDB_SUCCESS
) {
2109 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
2112 ret
= ldb_next_request(ac
->module
, ac
->dom_req
);
2117 if (ret
!= LDB_SUCCESS
) {
2118 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
2124 static int password_hash_mod_search_self(struct ph_context
*ac
)
2126 struct ldb_context
*ldb
;
2127 static const char * const attrs
[] = { "objectClass",
2128 "userAccountControl",
2132 "userPrincipalName",
2133 "supplementalCredentials",
2139 struct ldb_request
*search_req
;
2142 ldb
= ldb_module_get_ctx(ac
->module
);
2144 ret
= ldb_build_search_req(&search_req
, ldb
, ac
,
2145 ac
->req
->op
.mod
.message
->dn
,
2150 ac
, ph_mod_search_callback
,
2153 if (ret
!= LDB_SUCCESS
) {
2157 return ldb_next_request(ac
->module
, search_req
);
2160 static int password_hash_mod_do_mod(struct ph_context
*ac
)
2162 struct ldb_context
*ldb
;
2163 struct ldb_request
*mod_req
;
2164 struct ldb_message
*msg
;
2165 const struct ldb_message
*orig_msg
, *searched_msg
;
2166 struct setup_password_fields_io io
;
2169 ldb
= ldb_module_get_ctx(ac
->module
);
2171 /* use a new message structure so that we can modify it */
2172 msg
= ldb_msg_new(ac
);
2174 return LDB_ERR_OPERATIONS_ERROR
;
2178 msg
->dn
= ac
->req
->op
.mod
.message
->dn
;
2180 orig_msg
= ac
->req
->op
.mod
.message
;
2181 searched_msg
= ac
->search_res
->message
;
2183 /* Prepare the internal data structure containing the passwords */
2184 ret
= setup_io(ac
, orig_msg
, searched_msg
, &io
);
2185 if (ret
!= LDB_SUCCESS
) {
2189 /* Fill in some final details (only relevent once the password has been set) */
2190 io
.o
.nt_history_len
= samdb_result_hashes(io
.ac
, searched_msg
, "ntPwdHistory", &io
.o
.nt_history
);
2191 io
.o
.lm_history_len
= samdb_result_hashes(io
.ac
, searched_msg
, "lmPwdHistory", &io
.o
.lm_history
);
2192 io
.o
.supplemental
= ldb_msg_find_ldb_val(searched_msg
, "supplementalCredentials");
2194 ret
= setup_password_fields(&io
);
2195 if (ret
!= LDB_SUCCESS
) {
2199 /* make sure we replace all the old attributes */
2200 ret
= ldb_msg_add_empty(msg
, "unicodePwd", LDB_FLAG_MOD_REPLACE
, NULL
);
2201 ret
= ldb_msg_add_empty(msg
, "dBCSPwd", LDB_FLAG_MOD_REPLACE
, NULL
);
2202 ret
= ldb_msg_add_empty(msg
, "ntPwdHistory", LDB_FLAG_MOD_REPLACE
, NULL
);
2203 ret
= ldb_msg_add_empty(msg
, "lmPwdHistory", LDB_FLAG_MOD_REPLACE
, NULL
);
2204 ret
= ldb_msg_add_empty(msg
, "supplementalCredentials", LDB_FLAG_MOD_REPLACE
, NULL
);
2205 ret
= ldb_msg_add_empty(msg
, "pwdLastSet", LDB_FLAG_MOD_REPLACE
, NULL
);
2208 ret
= samdb_msg_add_hash(ldb
, ac
, msg
,
2209 "unicodePwd", io
.g
.nt_hash
);
2210 if (ret
!= LDB_SUCCESS
) {
2215 ret
= samdb_msg_add_hash(ldb
, ac
, msg
,
2216 "dBCSPwd", io
.g
.lm_hash
);
2217 if (ret
!= LDB_SUCCESS
) {
2221 if (io
.g
.nt_history_len
> 0) {
2222 ret
= samdb_msg_add_hashes(ac
, msg
,
2225 io
.g
.nt_history_len
);
2226 if (ret
!= LDB_SUCCESS
) {
2230 if (io
.g
.lm_history_len
> 0) {
2231 ret
= samdb_msg_add_hashes(ac
, msg
,
2234 io
.g
.lm_history_len
);
2235 if (ret
!= LDB_SUCCESS
) {
2239 if (io
.g
.supplemental
.length
> 0) {
2240 ret
= ldb_msg_add_value(msg
, "supplementalCredentials",
2241 &io
.g
.supplemental
, NULL
);
2242 if (ret
!= LDB_SUCCESS
) {
2246 ret
= samdb_msg_add_uint64(ldb
, ac
, msg
,
2249 if (ret
!= LDB_SUCCESS
) {
2253 ret
= ldb_build_mod_req(&mod_req
, ldb
, ac
,
2258 if (ret
!= LDB_SUCCESS
) {
2262 return ldb_next_request(ac
->module
, mod_req
);
2265 _PUBLIC_
const struct ldb_module_ops ldb_password_hash_module_ops
= {
2266 .name
= "password_hash",
2267 .add
= password_hash_add
,
2268 .modify
= password_hash_modify