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/include/ldb_errors.h"
37 #include "ldb/include/ldb.h"
38 #include "ldb/include/ldb_private.h"
39 #include "librpc/gen_ndr/misc.h"
40 #include "librpc/gen_ndr/samr.h"
41 #include "libcli/auth/libcli_auth.h"
42 #include "libcli/security/security.h"
43 #include "system/kerberos.h"
44 #include "auth/kerberos/kerberos.h"
45 #include "system/time.h"
46 #include "dsdb/samdb/samdb.h"
47 #include "dsdb/common/flags.h"
48 #include "dsdb/samdb/ldb_modules/password_modules.h"
49 #include "librpc/ndr/libndr.h"
50 #include "librpc/gen_ndr/ndr_drsblobs.h"
51 #include "../lib/crypto/crypto.h"
52 #include "param/param.h"
54 /* If we have decided there is reason to work on this request, then
55 * setup all the password hash types correctly.
57 * If the administrator doesn't want the userPassword stored (set in the
58 * domain and per-account policies) then we must strip that out before
59 * we do the first operation.
61 * Once this is done (which could update anything at all), we
62 * calculate the password hashes.
64 * This function must not only update the unicodePwd, dBCSPwd and
65 * supplementalCredentials fields, it must also atomicly increment the
66 * msDS-KeyVersionNumber. We should be in a transaction, so all this
67 * should be quite safe...
69 * Finally, if the administrator has requested that a password history
70 * be maintained, then this should also be written out.
76 struct ldb_module *module;
77 struct ldb_request *req;
79 struct ldb_request *dom_req;
80 struct ldb_reply *dom_res;
82 struct ldb_reply *search_res;
84 struct dom_sid *domain_sid;
85 struct domain_data *domain;
91 uint_t pwdHistoryLength;
97 struct setup_password_fields_io {
98 struct ph_context *ac;
99 struct domain_data *domain;
100 struct smb_krb5_context *smb_krb5_context;
102 /* infos about the user account */
104 uint32_t user_account_control;
105 const char *sAMAccountName;
106 const char *user_principal_name;
110 /* new credentials */
112 const char *cleartext;
113 struct samr_Password *nt_hash;
114 struct samr_Password *lm_hash;
117 /* old credentials */
119 uint32_t nt_history_len;
120 struct samr_Password *nt_history;
121 uint32_t lm_history_len;
122 struct samr_Password *lm_history;
123 const struct ldb_val *supplemental;
124 struct supplementalCredentialsBlob scb;
128 /* generated credentials */
130 struct samr_Password *nt_hash;
131 struct samr_Password *lm_hash;
132 uint32_t nt_history_len;
133 struct samr_Password *nt_history;
134 uint32_t lm_history_len;
135 struct samr_Password *lm_history;
141 struct ldb_val supplemental;
147 static int setup_nt_fields(struct setup_password_fields_io *io)
151 io->g.nt_hash = io->n.nt_hash;
153 if (io->domain->pwdHistoryLength == 0) {
157 /* We might not have an old NT password */
158 io->g.nt_history = talloc_array(io->ac,
159 struct samr_Password,
160 io->domain->pwdHistoryLength);
161 if (!io->g.nt_history) {
162 ldb_oom(io->ac->module->ldb);
163 return LDB_ERR_OPERATIONS_ERROR;
166 for (i = 0; i < MIN(io->domain->pwdHistoryLength-1, io->o.nt_history_len); i++) {
167 io->g.nt_history[i+1] = io->o.nt_history[i];
169 io->g.nt_history_len = i + 1;
172 io->g.nt_history[0] = *io->g.nt_hash;
175 * TODO: is this correct?
176 * the simular behavior is correct for the lm history case
178 E_md4hash("", io->g.nt_history[0].hash);
184 static int setup_lm_fields(struct setup_password_fields_io *io)
188 io->g.lm_hash = io->n.lm_hash;
190 if (io->domain->pwdHistoryLength == 0) {
194 /* We might not have an old NT password */
195 io->g.lm_history = talloc_array(io->ac,
196 struct samr_Password,
197 io->domain->pwdHistoryLength);
198 if (!io->g.lm_history) {
199 ldb_oom(io->ac->module->ldb);
200 return LDB_ERR_OPERATIONS_ERROR;
203 for (i = 0; i < MIN(io->domain->pwdHistoryLength-1, io->o.lm_history_len); i++) {
204 io->g.lm_history[i+1] = io->o.lm_history[i];
206 io->g.lm_history_len = i + 1;
209 io->g.lm_history[0] = *io->g.lm_hash;
211 E_deshash("", io->g.lm_history[0].hash);
217 static int setup_kerberos_keys(struct setup_password_fields_io *io)
219 krb5_error_code krb5_ret;
220 Principal *salt_principal;
224 /* Many, many thanks to lukeh@padl.com for this
225 * algorithm, described in his Nov 10 2004 mail to
226 * samba-technical@samba.org */
229 * Determine a salting principal
231 if (io->u.is_computer) {
235 name = talloc_strdup(io->ac, io->u.sAMAccountName);
237 ldb_oom(io->ac->module->ldb);
238 return LDB_ERR_OPERATIONS_ERROR;
241 if (name[strlen(name)-1] == '$') {
242 name[strlen(name)-1] = '\0';
245 saltbody = talloc_asprintf(io->ac, "%s.%s", name, io->domain->dns_domain);
247 ldb_oom(io->ac->module->ldb);
248 return LDB_ERR_OPERATIONS_ERROR;
251 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
253 io->domain->realm, "host",
255 } else if (io->u.user_principal_name) {
256 char *user_principal_name;
259 user_principal_name = talloc_strdup(io->ac, io->u.user_principal_name);
260 if (!user_principal_name) {
261 ldb_oom(io->ac->module->ldb);
262 return LDB_ERR_OPERATIONS_ERROR;
265 p = strchr(user_principal_name, '@');
270 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
272 io->domain->realm, user_principal_name,
275 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
277 io->domain->realm, io->u.sAMAccountName,
281 ldb_asprintf_errstring(io->ac->module->ldb,
282 "setup_kerberos_keys: "
283 "generation of a salting principal failed: %s",
284 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
285 return LDB_ERR_OPERATIONS_ERROR;
289 * create salt from salt_principal
291 krb5_ret = krb5_get_pw_salt(io->smb_krb5_context->krb5_context,
292 salt_principal, &salt);
293 krb5_free_principal(io->smb_krb5_context->krb5_context, salt_principal);
295 ldb_asprintf_errstring(io->ac->module->ldb,
296 "setup_kerberos_keys: "
297 "generation of krb5_salt failed: %s",
298 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
299 return LDB_ERR_OPERATIONS_ERROR;
301 /* create a talloc copy */
302 io->g.salt = talloc_strndup(io->ac,
304 salt.saltvalue.length);
305 krb5_free_salt(io->smb_krb5_context->krb5_context, salt);
307 ldb_oom(io->ac->module->ldb);
308 return LDB_ERR_OPERATIONS_ERROR;
310 salt.saltvalue.data = discard_const(io->g.salt);
311 salt.saltvalue.length = strlen(io->g.salt);
314 * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of
315 * the salt and the cleartext password
317 krb5_ret = krb5_string_to_key_salt(io->smb_krb5_context->krb5_context,
318 ENCTYPE_AES256_CTS_HMAC_SHA1_96,
323 ldb_asprintf_errstring(io->ac->module->ldb,
324 "setup_kerberos_keys: "
325 "generation of a aes256-cts-hmac-sha1-96 key failed: %s",
326 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
327 return LDB_ERR_OPERATIONS_ERROR;
329 io->g.aes_256 = data_blob_talloc(io->ac,
331 key.keyvalue.length);
332 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
333 if (!io->g.aes_256.data) {
334 ldb_oom(io->ac->module->ldb);
335 return LDB_ERR_OPERATIONS_ERROR;
339 * create ENCTYPE_AES128_CTS_HMAC_SHA1_96 key out of
340 * the salt and the cleartext password
342 krb5_ret = krb5_string_to_key_salt(io->smb_krb5_context->krb5_context,
343 ENCTYPE_AES128_CTS_HMAC_SHA1_96,
348 ldb_asprintf_errstring(io->ac->module->ldb,
349 "setup_kerberos_keys: "
350 "generation of a aes128-cts-hmac-sha1-96 key failed: %s",
351 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
352 return LDB_ERR_OPERATIONS_ERROR;
354 io->g.aes_128 = data_blob_talloc(io->ac,
356 key.keyvalue.length);
357 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
358 if (!io->g.aes_128.data) {
359 ldb_oom(io->ac->module->ldb);
360 return LDB_ERR_OPERATIONS_ERROR;
364 * create ENCTYPE_DES_CBC_MD5 key out of
365 * the salt and the cleartext password
367 krb5_ret = krb5_string_to_key_salt(io->smb_krb5_context->krb5_context,
373 ldb_asprintf_errstring(io->ac->module->ldb,
374 "setup_kerberos_keys: "
375 "generation of a des-cbc-md5 key failed: %s",
376 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
377 return LDB_ERR_OPERATIONS_ERROR;
379 io->g.des_md5 = data_blob_talloc(io->ac,
381 key.keyvalue.length);
382 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
383 if (!io->g.des_md5.data) {
384 ldb_oom(io->ac->module->ldb);
385 return LDB_ERR_OPERATIONS_ERROR;
389 * create ENCTYPE_DES_CBC_CRC key out of
390 * the salt and the cleartext password
392 krb5_ret = krb5_string_to_key_salt(io->smb_krb5_context->krb5_context,
398 ldb_asprintf_errstring(io->ac->module->ldb,
399 "setup_kerberos_keys: "
400 "generation of a des-cbc-crc key failed: %s",
401 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
402 return LDB_ERR_OPERATIONS_ERROR;
404 io->g.des_crc = data_blob_talloc(io->ac,
406 key.keyvalue.length);
407 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
408 if (!io->g.des_crc.data) {
409 ldb_oom(io->ac->module->ldb);
410 return LDB_ERR_OPERATIONS_ERROR;
416 static int setup_primary_kerberos(struct setup_password_fields_io *io,
417 const struct supplementalCredentialsBlob *old_scb,
418 struct package_PrimaryKerberosBlob *pkb)
420 struct package_PrimaryKerberosCtr3 *pkb3 = &pkb->ctr.ctr3;
421 struct supplementalCredentialsPackage *old_scp = NULL;
422 struct package_PrimaryKerberosBlob _old_pkb;
423 struct package_PrimaryKerberosCtr3 *old_pkb3 = NULL;
425 enum ndr_err_code ndr_err;
428 * prepare generation of keys
430 * ENCTYPE_DES_CBC_MD5
431 * ENCTYPE_DES_CBC_CRC
434 pkb3->salt.string = io->g.salt;
436 pkb3->keys = talloc_array(io->ac,
437 struct package_PrimaryKerberosKey3,
440 ldb_oom(io->ac->module->ldb);
441 return LDB_ERR_OPERATIONS_ERROR;
444 pkb3->keys[0].keytype = ENCTYPE_DES_CBC_MD5;
445 pkb3->keys[0].value = &io->g.des_md5;
446 pkb3->keys[1].keytype = ENCTYPE_DES_CBC_CRC;
447 pkb3->keys[1].value = &io->g.des_crc;
449 /* initialize the old keys to zero */
450 pkb3->num_old_keys = 0;
451 pkb3->old_keys = NULL;
453 /* if there're no old keys, then we're done */
458 for (i=0; i < old_scb->sub.num_packages; i++) {
459 if (strcmp("Primary:Kerberos", old_scb->sub.packages[i].name) != 0) {
463 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
467 old_scp = &old_scb->sub.packages[i];
470 /* Primary:Kerberos element of supplementalCredentials */
474 blob = strhex_to_data_blob(old_scp->data);
476 ldb_oom(io->ac->module->ldb);
477 return LDB_ERR_OPERATIONS_ERROR;
479 talloc_steal(io->ac, blob.data);
481 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
482 ndr_err = ndr_pull_struct_blob(&blob, io->ac, lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")), &_old_pkb,
483 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
484 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
485 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
486 ldb_asprintf_errstring(io->ac->module->ldb,
487 "setup_primary_kerberos: "
488 "failed to pull old package_PrimaryKerberosBlob: %s",
490 return LDB_ERR_OPERATIONS_ERROR;
493 if (_old_pkb.version != 3) {
494 ldb_asprintf_errstring(io->ac->module->ldb,
495 "setup_primary_kerberos: "
496 "package_PrimaryKerberosBlob version[%u] expected[3]",
498 return LDB_ERR_OPERATIONS_ERROR;
501 old_pkb3 = &_old_pkb.ctr.ctr3;
504 /* if we didn't found the old keys we're done */
509 /* fill in the old keys */
510 pkb3->num_old_keys = old_pkb3->num_keys;
511 pkb3->old_keys = old_pkb3->keys;
516 static int setup_primary_kerberos_newer(struct setup_password_fields_io *io,
517 const struct supplementalCredentialsBlob *old_scb,
518 struct package_PrimaryKerberosBlob *pkb)
520 struct package_PrimaryKerberosCtr4 *pkb4 = &pkb->ctr.ctr4;
521 struct supplementalCredentialsPackage *old_scp = NULL;
522 struct package_PrimaryKerberosBlob _old_pkb;
523 struct package_PrimaryKerberosCtr4 *old_pkb4 = NULL;
525 enum ndr_err_code ndr_err;
528 * prepare generation of keys
530 * ENCTYPE_AES256_CTS_HMAC_SHA1_96
531 * ENCTYPE_AES128_CTS_HMAC_SHA1_96
532 * ENCTYPE_DES_CBC_MD5
533 * ENCTYPE_DES_CBC_CRC
536 pkb4->salt.string = io->g.salt;
537 pkb4->default_iteration_count = 4096;
540 pkb4->keys = talloc_array(io->ac,
541 struct package_PrimaryKerberosKey4,
544 ldb_oom(io->ac->module->ldb);
545 return LDB_ERR_OPERATIONS_ERROR;
548 pkb4->keys[0].iteration_count = 4096;
549 pkb4->keys[0].keytype = ENCTYPE_AES256_CTS_HMAC_SHA1_96;
550 pkb4->keys[0].value = &io->g.aes_256;
551 pkb4->keys[1].iteration_count = 4096;
552 pkb4->keys[1].keytype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
553 pkb4->keys[1].value = &io->g.aes_128;
554 pkb4->keys[2].iteration_count = 4096;
555 pkb4->keys[2].keytype = ENCTYPE_DES_CBC_MD5;
556 pkb4->keys[2].value = &io->g.des_md5;
557 pkb4->keys[3].iteration_count = 4096;
558 pkb4->keys[3].keytype = ENCTYPE_DES_CBC_CRC;
559 pkb4->keys[3].value = &io->g.des_crc;
561 /* initialize the old keys to zero */
562 pkb4->num_old_keys = 0;
563 pkb4->old_keys = NULL;
564 pkb4->num_older_keys = 0;
565 pkb4->older_keys = NULL;
567 /* if there're no old keys, then we're done */
572 for (i=0; i < old_scb->sub.num_packages; i++) {
573 if (strcmp("Primary:Kerberos-Newer-Keys", old_scb->sub.packages[i].name) != 0) {
577 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
581 old_scp = &old_scb->sub.packages[i];
584 /* Primary:Kerberos-Newer-Keys element of supplementalCredentials */
588 blob = strhex_to_data_blob(old_scp->data);
590 ldb_oom(io->ac->module->ldb);
591 return LDB_ERR_OPERATIONS_ERROR;
593 talloc_steal(io->ac, blob.data);
595 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
596 ndr_err = ndr_pull_struct_blob(&blob, io->ac,
597 lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
599 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
600 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
601 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
602 ldb_asprintf_errstring(io->ac->module->ldb,
603 "setup_primary_kerberos_newer: "
604 "failed to pull old package_PrimaryKerberosBlob: %s",
606 return LDB_ERR_OPERATIONS_ERROR;
609 if (_old_pkb.version != 4) {
610 ldb_asprintf_errstring(io->ac->module->ldb,
611 "setup_primary_kerberos_newer: "
612 "package_PrimaryKerberosBlob version[%u] expected[4]",
614 return LDB_ERR_OPERATIONS_ERROR;
617 old_pkb4 = &_old_pkb.ctr.ctr4;
620 /* if we didn't found the old keys we're done */
625 /* fill in the old keys */
626 pkb4->num_old_keys = old_pkb4->num_keys;
627 pkb4->old_keys = old_pkb4->keys;
628 pkb4->num_older_keys = old_pkb4->num_old_keys;
629 pkb4->older_keys = old_pkb4->old_keys;
634 static int setup_primary_wdigest(struct setup_password_fields_io *io,
635 const struct supplementalCredentialsBlob *old_scb,
636 struct package_PrimaryWDigestBlob *pdb)
638 DATA_BLOB sAMAccountName;
639 DATA_BLOB sAMAccountName_l;
640 DATA_BLOB sAMAccountName_u;
641 const char *user_principal_name = io->u.user_principal_name;
642 DATA_BLOB userPrincipalName;
643 DATA_BLOB userPrincipalName_l;
644 DATA_BLOB userPrincipalName_u;
645 DATA_BLOB netbios_domain;
646 DATA_BLOB netbios_domain_l;
647 DATA_BLOB netbios_domain_u;
648 DATA_BLOB dns_domain;
649 DATA_BLOB dns_domain_l;
650 DATA_BLOB dns_domain_u;
663 * http://technet2.microsoft.com/WindowsServer/en/library/717b450c-f4a0-4cc9-86f4-cc0633aae5f91033.mspx?mfr=true
664 * for what precalculated hashes are supposed to be stored...
666 * I can't reproduce all values which should contain "Digest" as realm,
667 * am I doing something wrong or is w2k3 just broken...?
669 * W2K3 fills in following for a user:
671 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
672 * sAMAccountName: NewUser2Sam
673 * userPrincipalName: NewUser2Princ@sub1.w2k3.vmnet1.vm.base
675 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
676 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
677 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
678 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
679 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
680 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
681 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
682 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
683 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
684 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
685 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
686 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
687 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
688 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
689 * 221c55284451ae9b3aacaa2a3c86f10f => NewUser2Princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
690 * 74e1be668853d4324d38c07e2acfb8ea => (w2k3 has a bug here!) newuser2princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
691 * e1e244ab7f098e3ae1761be7f9229bbb => NEWUSER2PRINC@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
692 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
693 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
694 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
695 * 31dc704d3640335b2123d4ee28aa1f11 => ??? changes with NewUser2Sam => NewUser1Sam
696 * 36349f5cecd07320fb3bb0e119230c43 => ??? changes with NewUser2Sam => NewUser1Sam
697 * 12adf019d037fb535c01fd0608e78d9d => ??? changes with NewUser2Sam => NewUser1Sam
698 * 6feecf8e724906f3ee1105819c5105a1 => ??? changes with NewUser2Princ => NewUser1Princ
699 * 6c6911f3de6333422640221b9c51ff1f => ??? changes with NewUser2Princ => NewUser1Princ
700 * 4b279877e742895f9348ac67a8de2f69 => ??? changes with NewUser2Princ => NewUser1Princ
701 * db0c6bff069513e3ebb9870d29b57490 => ??? changes with NewUser2Sam => NewUser1Sam
702 * 45072621e56b1c113a4e04a8ff68cd0e => ??? changes with NewUser2Sam => NewUser1Sam
703 * 11d1220abc44a9c10cf91ef4a9c1de02 => ??? changes with NewUser2Sam => NewUser1Sam
705 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
706 * sAMAccountName: NewUser2Sam
708 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
709 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
710 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
711 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
712 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
713 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
714 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
715 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
716 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
717 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
718 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
719 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
720 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
721 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
722 * 8a140d30b6f0a5912735dc1e3bc993b4 => NewUser2Sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
723 * 86d95b2faae6cae4ec261e7fbaccf093 => (here w2k3 is correct) newuser2sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
724 * dfeff1493110220efcdfc6362e5f5450 => NEWUSER2SAM@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
725 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
726 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
727 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
728 * 31dc704d3640335b2123d4ee28aa1f11 => ???M1 changes with NewUser2Sam => NewUser1Sam
729 * 36349f5cecd07320fb3bb0e119230c43 => ???M1.L changes with newuser2sam => newuser1sam
730 * 12adf019d037fb535c01fd0608e78d9d => ???M1.U changes with NEWUSER2SAM => NEWUSER1SAM
731 * 569b4533f2d9e580211dd040e5e360a8 => ???M2 changes with NewUser2Princ => NewUser1Princ
732 * 52528bddf310a587c5d7e6a9ae2cbb20 => ???M2.L changes with newuser2princ => newuser1princ
733 * 4f629a4f0361289ca4255ab0f658fcd5 => ???M3 changes with NewUser2Princ => NewUser1Princ (doesn't depend on case of userPrincipal )
734 * db0c6bff069513e3ebb9870d29b57490 => ???M4 changes with NewUser2Sam => NewUser1Sam
735 * 45072621e56b1c113a4e04a8ff68cd0e => ???M5 changes with NewUser2Sam => NewUser1Sam (doesn't depend on case of sAMAccountName)
736 * 11d1220abc44a9c10cf91ef4a9c1de02 => ???M4.U changes with NEWUSER2SAM => NEWUSER1SAM
740 * sAMAccountName, netbios_domain
743 .user = &sAMAccountName,
744 .realm = &netbios_domain,
747 .user = &sAMAccountName_l,
748 .realm = &netbios_domain_l,
751 .user = &sAMAccountName_u,
752 .realm = &netbios_domain_u,
755 .user = &sAMAccountName,
756 .realm = &netbios_domain_u,
759 .user = &sAMAccountName,
760 .realm = &netbios_domain_l,
763 .user = &sAMAccountName_u,
764 .realm = &netbios_domain_l,
767 .user = &sAMAccountName_l,
768 .realm = &netbios_domain_u,
771 * sAMAccountName, dns_domain
774 .user = &sAMAccountName,
775 .realm = &dns_domain,
778 .user = &sAMAccountName_l,
779 .realm = &dns_domain_l,
782 .user = &sAMAccountName_u,
783 .realm = &dns_domain_u,
786 .user = &sAMAccountName,
787 .realm = &dns_domain_u,
790 .user = &sAMAccountName,
791 .realm = &dns_domain_l,
794 .user = &sAMAccountName_u,
795 .realm = &dns_domain_l,
798 .user = &sAMAccountName_l,
799 .realm = &dns_domain_u,
802 * userPrincipalName, no realm
805 .user = &userPrincipalName,
809 * NOTE: w2k3 messes this up, if the user has a real userPrincipalName,
810 * the fallback to the sAMAccountName based userPrincipalName is correct
812 .user = &userPrincipalName_l,
815 .user = &userPrincipalName_u,
818 * nt4dom\sAMAccountName, no realm
821 .user = &sAMAccountName,
822 .nt4dom = &netbios_domain
825 .user = &sAMAccountName_l,
826 .nt4dom = &netbios_domain_l
829 .user = &sAMAccountName_u,
830 .nt4dom = &netbios_domain_u
834 * the following ones are guessed depending on the technet2 article
835 * but not reproducable on a w2k3 server
837 /* sAMAccountName with "Digest" realm */
839 .user = &sAMAccountName,
843 .user = &sAMAccountName_l,
847 .user = &sAMAccountName_u,
850 /* userPrincipalName with "Digest" realm */
852 .user = &userPrincipalName,
856 .user = &userPrincipalName_l,
860 .user = &userPrincipalName_u,
863 /* nt4dom\\sAMAccountName with "Digest" realm */
865 .user = &sAMAccountName,
866 .nt4dom = &netbios_domain,
870 .user = &sAMAccountName_l,
871 .nt4dom = &netbios_domain_l,
875 .user = &sAMAccountName_u,
876 .nt4dom = &netbios_domain_u,
881 /* prepare DATA_BLOB's used in the combinations array */
882 sAMAccountName = data_blob_string_const(io->u.sAMAccountName);
883 sAMAccountName_l = data_blob_string_const(strlower_talloc(io->ac, io->u.sAMAccountName));
884 if (!sAMAccountName_l.data) {
885 ldb_oom(io->ac->module->ldb);
886 return LDB_ERR_OPERATIONS_ERROR;
888 sAMAccountName_u = data_blob_string_const(strupper_talloc(io->ac, io->u.sAMAccountName));
889 if (!sAMAccountName_u.data) {
890 ldb_oom(io->ac->module->ldb);
891 return LDB_ERR_OPERATIONS_ERROR;
894 /* if the user doesn't have a userPrincipalName, create one (with lower case realm) */
895 if (!user_principal_name) {
896 user_principal_name = talloc_asprintf(io->ac, "%s@%s",
897 io->u.sAMAccountName,
898 io->domain->dns_domain);
899 if (!user_principal_name) {
900 ldb_oom(io->ac->module->ldb);
901 return LDB_ERR_OPERATIONS_ERROR;
904 userPrincipalName = data_blob_string_const(user_principal_name);
905 userPrincipalName_l = data_blob_string_const(strlower_talloc(io->ac, user_principal_name));
906 if (!userPrincipalName_l.data) {
907 ldb_oom(io->ac->module->ldb);
908 return LDB_ERR_OPERATIONS_ERROR;
910 userPrincipalName_u = data_blob_string_const(strupper_talloc(io->ac, user_principal_name));
911 if (!userPrincipalName_u.data) {
912 ldb_oom(io->ac->module->ldb);
913 return LDB_ERR_OPERATIONS_ERROR;
916 netbios_domain = data_blob_string_const(io->domain->netbios_domain);
917 netbios_domain_l = data_blob_string_const(strlower_talloc(io->ac, io->domain->netbios_domain));
918 if (!netbios_domain_l.data) {
919 ldb_oom(io->ac->module->ldb);
920 return LDB_ERR_OPERATIONS_ERROR;
922 netbios_domain_u = data_blob_string_const(strupper_talloc(io->ac, io->domain->netbios_domain));
923 if (!netbios_domain_u.data) {
924 ldb_oom(io->ac->module->ldb);
925 return LDB_ERR_OPERATIONS_ERROR;
928 dns_domain = data_blob_string_const(io->domain->dns_domain);
929 dns_domain_l = data_blob_string_const(io->domain->dns_domain);
930 dns_domain_u = data_blob_string_const(io->domain->realm);
932 cleartext = data_blob_string_const(io->n.cleartext);
934 digest = data_blob_string_const("Digest");
936 delim = data_blob_string_const(":");
937 backslash = data_blob_string_const("\\");
939 pdb->num_hashes = ARRAY_SIZE(wdigest);
940 pdb->hashes = talloc_array(io->ac, struct package_PrimaryWDigestHash, pdb->num_hashes);
942 ldb_oom(io->ac->module->ldb);
943 return LDB_ERR_OPERATIONS_ERROR;
946 for (i=0; i < ARRAY_SIZE(wdigest); i++) {
947 struct MD5Context md5;
949 if (wdigest[i].nt4dom) {
950 MD5Update(&md5, wdigest[i].nt4dom->data, wdigest[i].nt4dom->length);
951 MD5Update(&md5, backslash.data, backslash.length);
953 MD5Update(&md5, wdigest[i].user->data, wdigest[i].user->length);
954 MD5Update(&md5, delim.data, delim.length);
955 if (wdigest[i].realm) {
956 MD5Update(&md5, wdigest[i].realm->data, wdigest[i].realm->length);
958 MD5Update(&md5, delim.data, delim.length);
959 MD5Update(&md5, cleartext.data, cleartext.length);
960 MD5Final(pdb->hashes[i].hash, &md5);
966 static int setup_supplemental_field(struct setup_password_fields_io *io)
968 struct supplementalCredentialsBlob scb;
969 struct supplementalCredentialsBlob _old_scb;
970 struct supplementalCredentialsBlob *old_scb = NULL;
971 /* Packages + (Kerberos-Newer-Keys, Kerberos, WDigest and CLEARTEXT) */
972 uint32_t num_names = 0;
973 const char *names[1+4];
974 uint32_t num_packages = 0;
975 struct supplementalCredentialsPackage packages[1+4];
977 struct supplementalCredentialsPackage *pp = NULL;
978 struct package_PackagesBlob pb;
981 /* Primary:Kerberos-Newer-Keys */
982 const char **nkn = NULL;
983 struct supplementalCredentialsPackage *pkn = NULL;
984 struct package_PrimaryKerberosBlob pknb;
987 /* Primary:Kerberos */
988 const char **nk = NULL;
989 struct supplementalCredentialsPackage *pk = NULL;
990 struct package_PrimaryKerberosBlob pkb;
993 /* Primary:WDigest */
994 const char **nd = NULL;
995 struct supplementalCredentialsPackage *pd = NULL;
996 struct package_PrimaryWDigestBlob pdb;
999 /* Primary:CLEARTEXT */
1000 const char **nc = NULL;
1001 struct supplementalCredentialsPackage *pc = NULL;
1002 struct package_PrimaryCLEARTEXTBlob pcb;
1006 enum ndr_err_code ndr_err;
1008 bool do_newer_keys = false;
1009 bool do_cleartext = false;
1011 ZERO_STRUCT(zero16);
1014 if (!io->n.cleartext) {
1016 * when we don't have a cleartext password
1017 * we can't setup a supplementalCredential value
1022 /* if there's an old supplementaCredentials blob then parse it */
1023 if (io->o.supplemental) {
1024 ndr_err = ndr_pull_struct_blob_all(io->o.supplemental, io->ac,
1025 lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
1027 (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
1028 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1029 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1030 ldb_asprintf_errstring(io->ac->module->ldb,
1031 "setup_supplemental_field: "
1032 "failed to pull old supplementalCredentialsBlob: %s",
1034 return LDB_ERR_OPERATIONS_ERROR;
1037 if (_old_scb.sub.signature == SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
1038 old_scb = &_old_scb;
1040 ldb_debug(io->ac->module->ldb, LDB_DEBUG_ERROR,
1041 "setup_supplemental_field: "
1042 "supplementalCredentialsBlob signature[0x%04X] expected[0x%04X]",
1043 _old_scb.sub.signature, SUPPLEMENTAL_CREDENTIALS_SIGNATURE);
1047 /* TODO: do the correct check for this, it maybe depends on the functional level? */
1048 do_newer_keys = lp_parm_bool(ldb_get_opaque(io->ac->module->ldb, "loadparm"),
1049 NULL, "password_hash", "create_aes_key", false);
1051 if (io->domain->store_cleartext &&
1052 (io->u.user_account_control & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) {
1053 do_cleartext = true;
1057 * The ordering is this
1059 * Primary:Kerberos-Newer-Keys (optional)
1062 * Primary:CLEARTEXT (optional)
1064 * And the 'Packages' package is insert before the last
1067 if (do_newer_keys) {
1068 /* Primary:Kerberos-Newer-Keys */
1069 nkn = &names[num_names++];
1070 pkn = &packages[num_packages++];
1073 /* Primary:Kerberos */
1074 nk = &names[num_names++];
1075 pk = &packages[num_packages++];
1077 if (!do_cleartext) {
1079 pp = &packages[num_packages++];
1082 /* Primary:WDigest */
1083 nd = &names[num_names++];
1084 pd = &packages[num_packages++];
1088 pp = &packages[num_packages++];
1090 /* Primary:CLEARTEXT */
1091 nc = &names[num_names++];
1092 pc = &packages[num_packages++];
1097 * setup 'Primary:Kerberos-Newer-Keys' element
1099 *nkn = "Kerberos-Newer-Keys";
1101 ret = setup_primary_kerberos_newer(io, old_scb, &pknb);
1102 if (ret != LDB_SUCCESS) {
1106 ndr_err = ndr_push_struct_blob(&pknb_blob, io->ac,
1107 lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
1109 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1110 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1111 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1112 ldb_asprintf_errstring(io->ac->module->ldb,
1113 "setup_supplemental_field: "
1114 "failed to push package_PrimaryKerberosNeverBlob: %s",
1116 return LDB_ERR_OPERATIONS_ERROR;
1118 pknb_hexstr = data_blob_hex_string(io->ac, &pknb_blob);
1120 ldb_oom(io->ac->module->ldb);
1121 return LDB_ERR_OPERATIONS_ERROR;
1123 pkn->name = "Primary:Kerberos-Newer-Keys";
1125 pkn->data = pknb_hexstr;
1129 * setup 'Primary:Kerberos' element
1133 ret = setup_primary_kerberos(io, old_scb, &pkb);
1134 if (ret != LDB_SUCCESS) {
1138 ndr_err = ndr_push_struct_blob(&pkb_blob, io->ac,
1139 lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
1141 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1142 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1143 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1144 ldb_asprintf_errstring(io->ac->module->ldb,
1145 "setup_supplemental_field: "
1146 "failed to push package_PrimaryKerberosBlob: %s",
1148 return LDB_ERR_OPERATIONS_ERROR;
1150 pkb_hexstr = data_blob_hex_string(io->ac, &pkb_blob);
1152 ldb_oom(io->ac->module->ldb);
1153 return LDB_ERR_OPERATIONS_ERROR;
1155 pk->name = "Primary:Kerberos";
1157 pk->data = pkb_hexstr;
1160 * setup 'Primary:WDigest' element
1164 ret = setup_primary_wdigest(io, old_scb, &pdb);
1165 if (ret != LDB_SUCCESS) {
1169 ndr_err = ndr_push_struct_blob(&pdb_blob, io->ac,
1170 lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
1172 (ndr_push_flags_fn_t)ndr_push_package_PrimaryWDigestBlob);
1173 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1174 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1175 ldb_asprintf_errstring(io->ac->module->ldb,
1176 "setup_supplemental_field: "
1177 "failed to push package_PrimaryWDigestBlob: %s",
1179 return LDB_ERR_OPERATIONS_ERROR;
1181 pdb_hexstr = data_blob_hex_string(io->ac, &pdb_blob);
1183 ldb_oom(io->ac->module->ldb);
1184 return LDB_ERR_OPERATIONS_ERROR;
1186 pd->name = "Primary:WDigest";
1188 pd->data = pdb_hexstr;
1191 * setup 'Primary:CLEARTEXT' element
1196 pcb.cleartext = io->n.cleartext;
1198 ndr_err = ndr_push_struct_blob(&pcb_blob, io->ac,
1199 lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
1201 (ndr_push_flags_fn_t)ndr_push_package_PrimaryCLEARTEXTBlob);
1202 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1203 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1204 ldb_asprintf_errstring(io->ac->module->ldb,
1205 "setup_supplemental_field: "
1206 "failed to push package_PrimaryCLEARTEXTBlob: %s",
1208 return LDB_ERR_OPERATIONS_ERROR;
1210 pcb_hexstr = data_blob_hex_string(io->ac, &pcb_blob);
1212 ldb_oom(io->ac->module->ldb);
1213 return LDB_ERR_OPERATIONS_ERROR;
1215 pc->name = "Primary:CLEARTEXT";
1217 pc->data = pcb_hexstr;
1221 * setup 'Packages' element
1224 ndr_err = ndr_push_struct_blob(&pb_blob, io->ac,
1225 lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
1227 (ndr_push_flags_fn_t)ndr_push_package_PackagesBlob);
1228 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1229 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1230 ldb_asprintf_errstring(io->ac->module->ldb,
1231 "setup_supplemental_field: "
1232 "failed to push package_PackagesBlob: %s",
1234 return LDB_ERR_OPERATIONS_ERROR;
1236 pb_hexstr = data_blob_hex_string(io->ac, &pb_blob);
1238 ldb_oom(io->ac->module->ldb);
1239 return LDB_ERR_OPERATIONS_ERROR;
1241 pp->name = "Packages";
1243 pp->data = pb_hexstr;
1246 * setup 'supplementalCredentials' value
1249 scb.sub.num_packages = num_packages;
1250 scb.sub.packages = packages;
1252 ndr_err = ndr_push_struct_blob(&io->g.supplemental, io->ac,
1253 lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
1255 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
1256 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1257 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1258 ldb_asprintf_errstring(io->ac->module->ldb,
1259 "setup_supplemental_field: "
1260 "failed to push supplementalCredentialsBlob: %s",
1262 return LDB_ERR_OPERATIONS_ERROR;
1268 static int setup_last_set_field(struct setup_password_fields_io *io)
1271 unix_to_nt_time(&io->g.last_set, time(NULL));
1276 static int setup_kvno_field(struct setup_password_fields_io *io)
1278 /* increment by one */
1279 io->g.kvno = io->o.kvno + 1;
1284 static int setup_password_fields(struct setup_password_fields_io *io)
1290 * refuse the change if someone want to change the cleartext
1291 * and supply his own hashes at the same time...
1293 if (io->n.cleartext && (io->n.nt_hash || io->n.lm_hash)) {
1294 ldb_asprintf_errstring(io->ac->module->ldb,
1295 "setup_password_fields: "
1296 "it's only allowed to set the cleartext password or the password hashes");
1297 return LDB_ERR_UNWILLING_TO_PERFORM;
1300 if (io->n.cleartext) {
1301 struct samr_Password *hash;
1303 hash = talloc(io->ac, struct samr_Password);
1305 ldb_oom(io->ac->module->ldb);
1306 return LDB_ERR_OPERATIONS_ERROR;
1309 /* compute the new nt hash */
1310 ok = E_md4hash(io->n.cleartext, hash->hash);
1312 io->n.nt_hash = hash;
1314 ldb_asprintf_errstring(io->ac->module->ldb,
1315 "setup_password_fields: "
1316 "failed to generate nthash from cleartext password");
1317 return LDB_ERR_OPERATIONS_ERROR;
1321 if (io->n.cleartext) {
1322 struct samr_Password *hash;
1324 hash = talloc(io->ac, struct samr_Password);
1326 ldb_oom(io->ac->module->ldb);
1327 return LDB_ERR_OPERATIONS_ERROR;
1330 /* compute the new lm hash */
1331 ok = E_deshash(io->n.cleartext, hash->hash);
1333 io->n.lm_hash = hash;
1335 talloc_free(hash->hash);
1339 if (io->n.cleartext) {
1340 ret = setup_kerberos_keys(io);
1346 ret = setup_nt_fields(io);
1351 ret = setup_lm_fields(io);
1356 ret = setup_supplemental_field(io);
1361 ret = setup_last_set_field(io);
1366 ret = setup_kvno_field(io);
1374 static struct ph_context *ph_init_context(struct ldb_module *module,
1375 struct ldb_request *req)
1377 struct ph_context *ac;
1379 ac = talloc_zero(req, struct ph_context);
1381 ldb_set_errstring(module->ldb, "Out of Memory");
1385 ac->module = module;
1391 static int ph_op_callback(struct ldb_request *req, struct ldb_reply *ares)
1393 struct ph_context *ac;
1395 ac = talloc_get_type(req->context, struct ph_context);
1398 return ldb_module_done(ac->req, NULL, NULL,
1399 LDB_ERR_OPERATIONS_ERROR);
1401 if (ares->error != LDB_SUCCESS) {
1402 return ldb_module_done(ac->req, ares->controls,
1403 ares->response, ares->error);
1406 if (ares->type != LDB_REPLY_DONE) {
1408 return ldb_module_done(ac->req, NULL, NULL,
1409 LDB_ERR_OPERATIONS_ERROR);
1412 return ldb_module_done(ac->req, ares->controls,
1413 ares->response, ares->error);
1416 static int password_hash_add_do_add(struct ph_context *ac);
1417 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares);
1418 static int password_hash_mod_search_self(struct ph_context *ac);
1419 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares);
1420 static int password_hash_mod_do_mod(struct ph_context *ac);
1422 static int get_domain_data_callback(struct ldb_request *req,
1423 struct ldb_reply *ares)
1425 struct domain_data *data;
1426 struct ph_context *ac;
1431 ac = talloc_get_type(req->context, struct ph_context);
1434 return ldb_module_done(ac->req, NULL, NULL,
1435 LDB_ERR_OPERATIONS_ERROR);
1437 if (ares->error != LDB_SUCCESS) {
1438 return ldb_module_done(ac->req, ares->controls,
1439 ares->response, ares->error);
1442 switch (ares->type) {
1443 case LDB_REPLY_ENTRY:
1444 if (ac->domain != NULL) {
1445 ldb_set_errstring(ac->module->ldb, "Too many results");
1446 return ldb_module_done(ac->req, NULL, NULL,
1447 LDB_ERR_OPERATIONS_ERROR);
1450 data = talloc_zero(ac, struct domain_data);
1452 return ldb_module_done(ac->req, NULL, NULL,
1453 LDB_ERR_OPERATIONS_ERROR);
1456 data->pwdProperties = samdb_result_uint(ares->message, "pwdProperties", 0);
1457 data->store_cleartext = data->pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
1458 data->pwdHistoryLength = samdb_result_uint(ares->message, "pwdHistoryLength", 0);
1460 /* For a domain DN, this puts things in dotted notation */
1461 /* For builtin domains, this will give details for the host,
1462 * but that doesn't really matter, as it's just used for salt
1463 * and kerberos principals, which don't exist here */
1465 tmp = ldb_dn_canonical_string(data, ares->message->dn);
1467 return ldb_module_done(ac->req, NULL, NULL,
1468 LDB_ERR_OPERATIONS_ERROR);
1471 /* But it puts a trailing (or just before 'builtin') / on things, so kill that */
1472 p = strchr(tmp, '/');
1477 data->dns_domain = strlower_talloc(data, tmp);
1478 if (data->dns_domain == NULL) {
1479 ldb_oom(ac->module->ldb);
1480 return ldb_module_done(ac->req, NULL, NULL,
1481 LDB_ERR_OPERATIONS_ERROR);
1483 data->realm = strupper_talloc(data, tmp);
1484 if (data->realm == NULL) {
1485 ldb_oom(ac->module->ldb);
1486 return ldb_module_done(ac->req, NULL, NULL,
1487 LDB_ERR_OPERATIONS_ERROR);
1489 /* FIXME: NetbIOS name is *always* the first domain component ?? -SSS */
1490 p = strchr(tmp, '.');
1494 data->netbios_domain = strupper_talloc(data, tmp);
1495 if (data->netbios_domain == NULL) {
1496 ldb_oom(ac->module->ldb);
1497 return ldb_module_done(ac->req, NULL, NULL,
1498 LDB_ERR_OPERATIONS_ERROR);
1505 case LDB_REPLY_DONE:
1507 /* call the next step */
1508 switch (ac->req->operation) {
1510 ret = password_hash_add_do_add(ac);
1514 ret = password_hash_mod_do_mod(ac);
1518 ret = LDB_ERR_OPERATIONS_ERROR;
1521 if (ret != LDB_SUCCESS) {
1522 return ldb_module_done(ac->req, NULL, NULL, ret);
1525 case LDB_REPLY_REFERRAL:
1534 static int build_domain_data_request(struct ph_context *ac)
1536 /* attrs[] is returned from this function in
1537 ac->dom_req->op.search.attrs, so it must be static, as
1538 otherwise the compiler can put it on the stack */
1539 static const char * const attrs[] = { "pwdProperties", "pwdHistoryLength", NULL };
1542 filter = talloc_asprintf(ac,
1543 "(&(objectSid=%s)(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain)))",
1544 ldap_encode_ndr_dom_sid(ac, ac->domain_sid));
1545 if (filter == NULL) {
1546 ldb_oom(ac->module->ldb);
1547 return LDB_ERR_OPERATIONS_ERROR;
1550 return ldb_build_search_req(&ac->dom_req, ac->module->ldb, ac,
1551 ldb_get_default_basedn(ac->module->ldb),
1555 ac, get_domain_data_callback,
1559 static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
1561 struct ph_context *ac;
1562 struct ldb_message_element *sambaAttr;
1563 struct ldb_message_element *ntAttr;
1564 struct ldb_message_element *lmAttr;
1567 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "password_hash_add\n");
1569 if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
1570 return ldb_next_request(module, req);
1573 /* If the caller is manipulating the local passwords directly, let them pass */
1574 if (ldb_dn_compare_base(ldb_dn_new(req, module->ldb, LOCAL_BASE),
1575 req->op.add.message->dn) == 0) {
1576 return ldb_next_request(module, req);
1579 /* nobody must touch these fields */
1580 if (ldb_msg_find_element(req->op.add.message, "ntPwdHistory")) {
1581 return LDB_ERR_UNWILLING_TO_PERFORM;
1583 if (ldb_msg_find_element(req->op.add.message, "lmPwdHistory")) {
1584 return LDB_ERR_UNWILLING_TO_PERFORM;
1586 if (ldb_msg_find_element(req->op.add.message, "supplementalCredentials")) {
1587 return LDB_ERR_UNWILLING_TO_PERFORM;
1590 /* If no part of this ADD touches the userPassword, or the NT
1591 * or LM hashes, then we don't need to make any changes. */
1593 sambaAttr = ldb_msg_find_element(req->op.mod.message, "userPassword");
1594 ntAttr = ldb_msg_find_element(req->op.mod.message, "unicodePwd");
1595 lmAttr = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
1597 if ((!sambaAttr) && (!ntAttr) && (!lmAttr)) {
1598 return ldb_next_request(module, req);
1601 /* if it is not an entry of type person its an error */
1602 /* TODO: remove this when userPassword will be in schema */
1603 if (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "person")) {
1604 ldb_set_errstring(module->ldb, "Cannot set a password on entry that does not have objectClass 'person'");
1605 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1608 /* check userPassword is single valued here */
1609 /* TODO: remove this when userPassword will be single valued in schema */
1610 if (sambaAttr && sambaAttr->num_values > 1) {
1611 ldb_set_errstring(module->ldb, "mupltiple values for userPassword not allowed!\n");
1612 return LDB_ERR_CONSTRAINT_VIOLATION;
1615 if (ntAttr && (ntAttr->num_values > 1)) {
1616 ldb_set_errstring(module->ldb, "mupltiple values for unicodePwd not allowed!\n");
1617 return LDB_ERR_CONSTRAINT_VIOLATION;
1619 if (lmAttr && (lmAttr->num_values > 1)) {
1620 ldb_set_errstring(module->ldb, "mupltiple values for dBCSPwd not allowed!\n");
1621 return LDB_ERR_CONSTRAINT_VIOLATION;
1624 if (sambaAttr && sambaAttr->num_values == 0) {
1625 ldb_set_errstring(module->ldb, "userPassword must have a value!\n");
1626 return LDB_ERR_CONSTRAINT_VIOLATION;
1629 if (ntAttr && (ntAttr->num_values == 0)) {
1630 ldb_set_errstring(module->ldb, "unicodePwd must have a value!\n");
1631 return LDB_ERR_CONSTRAINT_VIOLATION;
1633 if (lmAttr && (lmAttr->num_values == 0)) {
1634 ldb_set_errstring(module->ldb, "dBCSPwd must have a value!\n");
1635 return LDB_ERR_CONSTRAINT_VIOLATION;
1638 ac = ph_init_context(module, req);
1640 return LDB_ERR_OPERATIONS_ERROR;
1643 /* get user domain data */
1644 ac->domain_sid = samdb_result_sid_prefix(ac, req->op.add.message, "objectSid");
1645 if (ac->domain_sid == NULL) {
1646 ldb_debug(module->ldb, LDB_DEBUG_ERROR,
1647 "can't handle entry with missing objectSid!\n");
1648 return LDB_ERR_OPERATIONS_ERROR;
1651 ret = build_domain_data_request(ac);
1652 if (ret != LDB_SUCCESS) {
1656 return ldb_next_request(module, ac->dom_req);
1659 static int password_hash_add_do_add(struct ph_context *ac) {
1661 struct ldb_request *down_req;
1662 struct smb_krb5_context *smb_krb5_context;
1663 struct ldb_message *msg;
1664 struct setup_password_fields_io io;
1667 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
1669 return LDB_ERR_OPERATIONS_ERROR;
1672 /* Some operations below require kerberos contexts */
1673 if (smb_krb5_init_context(ac,
1674 ldb_get_event_context(ac->module->ldb),
1675 (struct loadparm_context *)ldb_get_opaque(ac->module->ldb, "loadparm"),
1676 &smb_krb5_context) != 0) {
1677 return LDB_ERR_OPERATIONS_ERROR;
1682 io.domain = ac->domain;
1683 io.smb_krb5_context = smb_krb5_context;
1685 io.u.user_account_control = samdb_result_uint(msg, "userAccountControl", 0);
1686 io.u.sAMAccountName = samdb_result_string(msg, "samAccountName", NULL);
1687 io.u.user_principal_name = samdb_result_string(msg, "userPrincipalName", NULL);
1688 io.u.is_computer = ldb_msg_check_string_attribute(msg, "objectClass", "computer");
1690 io.n.cleartext = samdb_result_string(msg, "userPassword", NULL);
1691 io.n.nt_hash = samdb_result_hash(io.ac, msg, "unicodePwd");
1692 io.n.lm_hash = samdb_result_hash(io.ac, msg, "dBCSPwd");
1694 /* remove attributes */
1695 if (io.n.cleartext) ldb_msg_remove_attr(msg, "userPassword");
1696 if (io.n.nt_hash) ldb_msg_remove_attr(msg, "unicodePwd");
1697 if (io.n.lm_hash) ldb_msg_remove_attr(msg, "dBCSPwd");
1698 ldb_msg_remove_attr(msg, "pwdLastSet");
1699 io.o.kvno = samdb_result_uint(msg, "msDs-KeyVersionNumber", 1) - 1;
1700 ldb_msg_remove_attr(msg, "msDs-KeyVersionNumber");
1702 ret = setup_password_fields(&io);
1703 if (ret != LDB_SUCCESS) {
1708 ret = samdb_msg_add_hash(ac->module->ldb, ac, msg,
1709 "unicodePwd", io.g.nt_hash);
1710 if (ret != LDB_SUCCESS) {
1715 ret = samdb_msg_add_hash(ac->module->ldb, ac, msg,
1716 "dBCSPwd", io.g.lm_hash);
1717 if (ret != LDB_SUCCESS) {
1721 if (io.g.nt_history_len > 0) {
1722 ret = samdb_msg_add_hashes(ac, msg,
1725 io.g.nt_history_len);
1726 if (ret != LDB_SUCCESS) {
1730 if (io.g.lm_history_len > 0) {
1731 ret = samdb_msg_add_hashes(ac, msg,
1734 io.g.lm_history_len);
1735 if (ret != LDB_SUCCESS) {
1739 if (io.g.supplemental.length > 0) {
1740 ret = ldb_msg_add_value(msg, "supplementalCredentials",
1741 &io.g.supplemental, NULL);
1742 if (ret != LDB_SUCCESS) {
1746 ret = samdb_msg_add_uint64(ac->module->ldb, ac, msg,
1749 if (ret != LDB_SUCCESS) {
1752 ret = samdb_msg_add_uint(ac->module->ldb, ac, msg,
1753 "msDs-KeyVersionNumber",
1755 if (ret != LDB_SUCCESS) {
1759 ret = ldb_build_add_req(&down_req, ac->module->ldb, ac,
1764 if (ret != LDB_SUCCESS) {
1768 return ldb_next_request(ac->module, down_req);
1771 static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
1773 struct ph_context *ac;
1774 struct ldb_message_element *sambaAttr;
1775 struct ldb_message_element *ntAttr;
1776 struct ldb_message_element *lmAttr;
1777 struct ldb_message *msg;
1778 struct ldb_request *down_req;
1781 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
1783 if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
1784 return ldb_next_request(module, req);
1787 /* If the caller is manipulating the local passwords directly, let them pass */
1788 if (ldb_dn_compare_base(ldb_dn_new(req, module->ldb, LOCAL_BASE),
1789 req->op.mod.message->dn) == 0) {
1790 return ldb_next_request(module, req);
1793 /* nobody must touch password Histories */
1794 if (ldb_msg_find_element(req->op.add.message, "ntPwdHistory")) {
1795 return LDB_ERR_UNWILLING_TO_PERFORM;
1797 if (ldb_msg_find_element(req->op.add.message, "lmPwdHistory")) {
1798 return LDB_ERR_UNWILLING_TO_PERFORM;
1800 if (ldb_msg_find_element(req->op.add.message, "supplementalCredentials")) {
1801 return LDB_ERR_UNWILLING_TO_PERFORM;
1804 sambaAttr = ldb_msg_find_element(req->op.mod.message, "userPassword");
1805 ntAttr = ldb_msg_find_element(req->op.mod.message, "unicodePwd");
1806 lmAttr = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
1808 /* If no part of this touches the userPassword OR unicodePwd and/or dBCSPwd, then we don't
1809 * need to make any changes. For password changes/set there should
1810 * be a 'delete' or a 'modify' on this attribute. */
1811 if ((!sambaAttr) && (!ntAttr) && (!lmAttr)) {
1812 return ldb_next_request(module, req);
1815 /* check passwords are single valued here */
1816 /* TODO: remove this when passwords will be single valued in schema */
1817 if (sambaAttr && (sambaAttr->num_values > 1)) {
1818 return LDB_ERR_CONSTRAINT_VIOLATION;
1820 if (ntAttr && (ntAttr->num_values > 1)) {
1821 return LDB_ERR_CONSTRAINT_VIOLATION;
1823 if (lmAttr && (lmAttr->num_values > 1)) {
1824 return LDB_ERR_CONSTRAINT_VIOLATION;
1827 ac = ph_init_context(module, req);
1829 return LDB_ERR_OPERATIONS_ERROR;
1832 /* use a new message structure so that we can modify it */
1833 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
1835 ldb_oom(module->ldb);
1836 return LDB_ERR_OPERATIONS_ERROR;
1839 /* - remove any modification to the password from the first commit
1840 * we will make the real modification later */
1841 if (sambaAttr) ldb_msg_remove_attr(msg, "userPassword");
1842 if (ntAttr) ldb_msg_remove_attr(msg, "unicodePwd");
1843 if (lmAttr) ldb_msg_remove_attr(msg, "dBCSPwd");
1845 /* if there was nothing else to be modified skip to next step */
1846 if (msg->num_elements == 0) {
1847 return password_hash_mod_search_self(ac);
1850 ret = ldb_build_mod_req(&down_req, module->ldb, ac,
1853 ac, ph_modify_callback,
1855 if (ret != LDB_SUCCESS) {
1859 return ldb_next_request(module, down_req);
1862 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
1864 struct ph_context *ac;
1867 ac = talloc_get_type(req->context, struct ph_context);
1870 return ldb_module_done(ac->req, NULL, NULL,
1871 LDB_ERR_OPERATIONS_ERROR);
1873 if (ares->error != LDB_SUCCESS) {
1874 return ldb_module_done(ac->req, ares->controls,
1875 ares->response, ares->error);
1878 if (ares->type != LDB_REPLY_DONE) {
1880 return ldb_module_done(ac->req, NULL, NULL,
1881 LDB_ERR_OPERATIONS_ERROR);
1884 ret = password_hash_mod_search_self(ac);
1885 if (ret != LDB_SUCCESS) {
1886 return ldb_module_done(ac->req, NULL, NULL, ret);
1893 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
1895 struct ph_context *ac;
1898 ac = talloc_get_type(req->context, struct ph_context);
1901 return ldb_module_done(ac->req, NULL, NULL,
1902 LDB_ERR_OPERATIONS_ERROR);
1904 if (ares->error != LDB_SUCCESS) {
1905 return ldb_module_done(ac->req, ares->controls,
1906 ares->response, ares->error);
1909 /* we are interested only in the single reply (base search) */
1910 switch (ares->type) {
1911 case LDB_REPLY_ENTRY:
1913 if (ac->search_res != NULL) {
1914 ldb_set_errstring(ac->module->ldb, "Too many results");
1916 return ldb_module_done(ac->req, NULL, NULL,
1917 LDB_ERR_OPERATIONS_ERROR);
1920 /* if it is not an entry of type person this is an error */
1921 /* TODO: remove this when sambaPassword will be in schema */
1922 if (!ldb_msg_check_string_attribute(ares->message, "objectClass", "person")) {
1923 ldb_set_errstring(ac->module->ldb, "Object class violation");
1925 return ldb_module_done(ac->req, NULL, NULL,
1926 LDB_ERR_OBJECT_CLASS_VIOLATION);
1929 ac->search_res = talloc_steal(ac, ares);
1932 case LDB_REPLY_DONE:
1934 /* get object domain sid */
1935 ac->domain_sid = samdb_result_sid_prefix(ac,
1936 ac->search_res->message,
1938 if (ac->domain_sid == NULL) {
1939 ldb_debug(ac->module->ldb, LDB_DEBUG_ERROR,
1940 "can't handle entry without objectSid!\n");
1941 return ldb_module_done(ac->req, NULL, NULL,
1942 LDB_ERR_OPERATIONS_ERROR);
1945 /* get user domain data */
1946 ret = build_domain_data_request(ac);
1947 if (ret != LDB_SUCCESS) {
1948 return ldb_module_done(ac->req, NULL, NULL,ret);
1951 return ldb_next_request(ac->module, ac->dom_req);
1953 case LDB_REPLY_REFERRAL:
1954 /*ignore anything else for now */
1962 static int password_hash_mod_search_self(struct ph_context *ac) {
1964 static const char * const attrs[] = { "userAccountControl", "lmPwdHistory",
1966 "objectSid", "msDS-KeyVersionNumber",
1967 "objectClass", "userPrincipalName",
1969 "dBCSPwd", "unicodePwd",
1970 "supplementalCredentials",
1972 struct ldb_request *search_req;
1975 ret = ldb_build_search_req(&search_req, ac->module->ldb, ac,
1976 ac->req->op.mod.message->dn,
1981 ac, ph_mod_search_callback,
1984 if (ret != LDB_SUCCESS) {
1988 return ldb_next_request(ac->module, search_req);
1991 static int password_hash_mod_do_mod(struct ph_context *ac) {
1993 struct ldb_request *mod_req;
1994 struct smb_krb5_context *smb_krb5_context;
1995 struct ldb_message *msg;
1996 struct ldb_message *orig_msg;
1997 struct ldb_message *searched_msg;
1998 struct setup_password_fields_io io;
2001 /* use a new message structure so that we can modify it */
2002 msg = ldb_msg_new(ac);
2004 return LDB_ERR_OPERATIONS_ERROR;
2008 msg->dn = ac->req->op.mod.message->dn;
2010 /* Some operations below require kerberos contexts */
2011 if (smb_krb5_init_context(ac,
2012 ldb_get_event_context(ac->module->ldb),
2013 (struct loadparm_context *)ldb_get_opaque(ac->module->ldb, "loadparm"),
2014 &smb_krb5_context) != 0) {
2015 return LDB_ERR_OPERATIONS_ERROR;
2018 orig_msg = discard_const(ac->req->op.mod.message);
2019 searched_msg = ac->search_res->message;
2023 io.domain = ac->domain;
2024 io.smb_krb5_context = smb_krb5_context;
2026 io.u.user_account_control = samdb_result_uint(searched_msg, "userAccountControl", 0);
2027 io.u.sAMAccountName = samdb_result_string(searched_msg, "samAccountName", NULL);
2028 io.u.user_principal_name = samdb_result_string(searched_msg, "userPrincipalName", NULL);
2029 io.u.is_computer = ldb_msg_check_string_attribute(searched_msg, "objectClass", "computer");
2031 io.n.cleartext = samdb_result_string(orig_msg, "userPassword", NULL);
2032 io.n.nt_hash = samdb_result_hash(io.ac, orig_msg, "unicodePwd");
2033 io.n.lm_hash = samdb_result_hash(io.ac, orig_msg, "dBCSPwd");
2035 io.o.kvno = samdb_result_uint(searched_msg, "msDs-KeyVersionNumber", 0);
2036 io.o.nt_history_len = samdb_result_hashes(io.ac, searched_msg, "ntPwdHistory", &io.o.nt_history);
2037 io.o.lm_history_len = samdb_result_hashes(io.ac, searched_msg, "lmPwdHistory", &io.o.lm_history);
2038 io.o.supplemental = ldb_msg_find_ldb_val(searched_msg, "supplementalCredentials");
2040 ret = setup_password_fields(&io);
2041 if (ret != LDB_SUCCESS) {
2045 /* make sure we replace all the old attributes */
2046 ret = ldb_msg_add_empty(msg, "unicodePwd", LDB_FLAG_MOD_REPLACE, NULL);
2047 ret = ldb_msg_add_empty(msg, "dBCSPwd", LDB_FLAG_MOD_REPLACE, NULL);
2048 ret = ldb_msg_add_empty(msg, "ntPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
2049 ret = ldb_msg_add_empty(msg, "lmPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
2050 ret = ldb_msg_add_empty(msg, "supplementalCredentials", LDB_FLAG_MOD_REPLACE, NULL);
2051 ret = ldb_msg_add_empty(msg, "pwdLastSet", LDB_FLAG_MOD_REPLACE, NULL);
2052 ret = ldb_msg_add_empty(msg, "msDs-KeyVersionNumber", LDB_FLAG_MOD_REPLACE, NULL);
2055 ret = samdb_msg_add_hash(ac->module->ldb, ac, msg,
2056 "unicodePwd", io.g.nt_hash);
2057 if (ret != LDB_SUCCESS) {
2062 ret = samdb_msg_add_hash(ac->module->ldb, ac, msg,
2063 "dBCSPwd", io.g.lm_hash);
2064 if (ret != LDB_SUCCESS) {
2068 if (io.g.nt_history_len > 0) {
2069 ret = samdb_msg_add_hashes(ac, msg,
2072 io.g.nt_history_len);
2073 if (ret != LDB_SUCCESS) {
2077 if (io.g.lm_history_len > 0) {
2078 ret = samdb_msg_add_hashes(ac, msg,
2081 io.g.lm_history_len);
2082 if (ret != LDB_SUCCESS) {
2086 if (io.g.supplemental.length > 0) {
2087 ret = ldb_msg_add_value(msg, "supplementalCredentials",
2088 &io.g.supplemental, NULL);
2089 if (ret != LDB_SUCCESS) {
2093 ret = samdb_msg_add_uint64(ac->module->ldb, ac, msg,
2096 if (ret != LDB_SUCCESS) {
2099 ret = samdb_msg_add_uint(ac->module->ldb, ac, msg,
2100 "msDs-KeyVersionNumber",
2102 if (ret != LDB_SUCCESS) {
2106 ret = ldb_build_mod_req(&mod_req, ac->module->ldb, ac,
2111 if (ret != LDB_SUCCESS) {
2115 return ldb_next_request(ac->module, mod_req);
2118 _PUBLIC_ const struct ldb_module_ops ldb_password_hash_module_ops = {
2119 .name = "password_hash",
2120 .add = password_hash_add,
2121 .modify = password_hash_modify,