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 struct ldb_val *cleartext_utf8;
113 const struct ldb_val *cleartext_utf16;
114 struct samr_Password *nt_hash;
115 struct samr_Password *lm_hash;
118 /* old credentials */
120 uint32_t nt_history_len;
121 struct samr_Password *nt_history;
122 uint32_t lm_history_len;
123 struct samr_Password *lm_history;
124 const struct ldb_val *supplemental;
125 struct supplementalCredentialsBlob scb;
129 /* generated credentials */
131 struct samr_Password *nt_hash;
132 struct samr_Password *lm_hash;
133 uint32_t nt_history_len;
134 struct samr_Password *nt_history;
135 uint32_t lm_history_len;
136 struct samr_Password *lm_history;
142 struct ldb_val supplemental;
148 /* Get the NT hash, and fill it in as an entry in the password history,
149 and specify it into io->g.nt_hash */
151 static int setup_nt_fields(struct setup_password_fields_io *io)
155 io->g.nt_hash = io->n.nt_hash;
157 if (io->domain->pwdHistoryLength == 0) {
161 /* We might not have an old NT password */
162 io->g.nt_history = talloc_array(io->ac,
163 struct samr_Password,
164 io->domain->pwdHistoryLength);
165 if (!io->g.nt_history) {
166 ldb_oom(io->ac->module->ldb);
167 return LDB_ERR_OPERATIONS_ERROR;
170 for (i = 0; i < MIN(io->domain->pwdHistoryLength-1, io->o.nt_history_len); i++) {
171 io->g.nt_history[i+1] = io->o.nt_history[i];
173 io->g.nt_history_len = i + 1;
176 io->g.nt_history[0] = *io->g.nt_hash;
179 * TODO: is this correct?
180 * the simular behavior is correct for the lm history case
182 E_md4hash("", io->g.nt_history[0].hash);
188 /* Get the LANMAN hash, and fill it in as an entry in the password history,
189 and specify it into io->g.lm_hash */
191 static int setup_lm_fields(struct setup_password_fields_io *io)
195 io->g.lm_hash = io->n.lm_hash;
197 if (io->domain->pwdHistoryLength == 0) {
201 /* We might not have an old NT password */
202 io->g.lm_history = talloc_array(io->ac,
203 struct samr_Password,
204 io->domain->pwdHistoryLength);
205 if (!io->g.lm_history) {
206 ldb_oom(io->ac->module->ldb);
207 return LDB_ERR_OPERATIONS_ERROR;
210 for (i = 0; i < MIN(io->domain->pwdHistoryLength-1, io->o.lm_history_len); i++) {
211 io->g.lm_history[i+1] = io->o.lm_history[i];
213 io->g.lm_history_len = i + 1;
216 io->g.lm_history[0] = *io->g.lm_hash;
218 E_deshash("", io->g.lm_history[0].hash);
224 static int setup_kerberos_keys(struct setup_password_fields_io *io)
226 krb5_error_code krb5_ret;
227 Principal *salt_principal;
230 krb5_data cleartext_data;
232 cleartext_data.data = io->n.cleartext_utf8->data;
233 cleartext_data.length = io->n.cleartext_utf8->length;
235 /* Many, many thanks to lukeh@padl.com for this
236 * algorithm, described in his Nov 10 2004 mail to
237 * samba-technical@samba.org */
240 * Determine a salting principal
242 if (io->u.is_computer) {
246 name = talloc_strdup(io->ac, io->u.sAMAccountName);
248 ldb_oom(io->ac->module->ldb);
249 return LDB_ERR_OPERATIONS_ERROR;
252 if (name[strlen(name)-1] == '$') {
253 name[strlen(name)-1] = '\0';
256 saltbody = talloc_asprintf(io->ac, "%s.%s", name, io->domain->dns_domain);
258 ldb_oom(io->ac->module->ldb);
259 return LDB_ERR_OPERATIONS_ERROR;
262 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
264 io->domain->realm, "host",
266 } else if (io->u.user_principal_name) {
267 char *user_principal_name;
270 user_principal_name = talloc_strdup(io->ac, io->u.user_principal_name);
271 if (!user_principal_name) {
272 ldb_oom(io->ac->module->ldb);
273 return LDB_ERR_OPERATIONS_ERROR;
276 p = strchr(user_principal_name, '@');
281 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
283 io->domain->realm, user_principal_name,
286 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
288 io->domain->realm, io->u.sAMAccountName,
292 ldb_asprintf_errstring(io->ac->module->ldb,
293 "setup_kerberos_keys: "
294 "generation of a salting principal failed: %s",
295 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
296 return LDB_ERR_OPERATIONS_ERROR;
300 * create salt from salt_principal
302 krb5_ret = krb5_get_pw_salt(io->smb_krb5_context->krb5_context,
303 salt_principal, &salt);
304 krb5_free_principal(io->smb_krb5_context->krb5_context, salt_principal);
306 ldb_asprintf_errstring(io->ac->module->ldb,
307 "setup_kerberos_keys: "
308 "generation of krb5_salt failed: %s",
309 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
310 return LDB_ERR_OPERATIONS_ERROR;
312 /* create a talloc copy */
313 io->g.salt = talloc_strndup(io->ac,
315 salt.saltvalue.length);
316 krb5_free_salt(io->smb_krb5_context->krb5_context, salt);
318 ldb_oom(io->ac->module->ldb);
319 return LDB_ERR_OPERATIONS_ERROR;
321 salt.saltvalue.data = discard_const(io->g.salt);
322 salt.saltvalue.length = strlen(io->g.salt);
325 * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of
326 * the salt and the cleartext password
328 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
329 ENCTYPE_AES256_CTS_HMAC_SHA1_96,
334 ldb_asprintf_errstring(io->ac->module->ldb,
335 "setup_kerberos_keys: "
336 "generation of a aes256-cts-hmac-sha1-96 key failed: %s",
337 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
338 return LDB_ERR_OPERATIONS_ERROR;
340 io->g.aes_256 = data_blob_talloc(io->ac,
342 key.keyvalue.length);
343 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
344 if (!io->g.aes_256.data) {
345 ldb_oom(io->ac->module->ldb);
346 return LDB_ERR_OPERATIONS_ERROR;
350 * create ENCTYPE_AES128_CTS_HMAC_SHA1_96 key out of
351 * the salt and the cleartext password
353 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
354 ENCTYPE_AES128_CTS_HMAC_SHA1_96,
359 ldb_asprintf_errstring(io->ac->module->ldb,
360 "setup_kerberos_keys: "
361 "generation of a aes128-cts-hmac-sha1-96 key failed: %s",
362 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
363 return LDB_ERR_OPERATIONS_ERROR;
365 io->g.aes_128 = data_blob_talloc(io->ac,
367 key.keyvalue.length);
368 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
369 if (!io->g.aes_128.data) {
370 ldb_oom(io->ac->module->ldb);
371 return LDB_ERR_OPERATIONS_ERROR;
375 * create ENCTYPE_DES_CBC_MD5 key out of
376 * the salt and the cleartext password
378 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
384 ldb_asprintf_errstring(io->ac->module->ldb,
385 "setup_kerberos_keys: "
386 "generation of a des-cbc-md5 key failed: %s",
387 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
388 return LDB_ERR_OPERATIONS_ERROR;
390 io->g.des_md5 = data_blob_talloc(io->ac,
392 key.keyvalue.length);
393 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
394 if (!io->g.des_md5.data) {
395 ldb_oom(io->ac->module->ldb);
396 return LDB_ERR_OPERATIONS_ERROR;
400 * create ENCTYPE_DES_CBC_CRC key out of
401 * the salt and the cleartext password
403 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
409 ldb_asprintf_errstring(io->ac->module->ldb,
410 "setup_kerberos_keys: "
411 "generation of a des-cbc-crc key failed: %s",
412 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
413 return LDB_ERR_OPERATIONS_ERROR;
415 io->g.des_crc = data_blob_talloc(io->ac,
417 key.keyvalue.length);
418 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
419 if (!io->g.des_crc.data) {
420 ldb_oom(io->ac->module->ldb);
421 return LDB_ERR_OPERATIONS_ERROR;
427 static int setup_primary_kerberos(struct setup_password_fields_io *io,
428 const struct supplementalCredentialsBlob *old_scb,
429 struct package_PrimaryKerberosBlob *pkb)
431 struct package_PrimaryKerberosCtr3 *pkb3 = &pkb->ctr.ctr3;
432 struct supplementalCredentialsPackage *old_scp = NULL;
433 struct package_PrimaryKerberosBlob _old_pkb;
434 struct package_PrimaryKerberosCtr3 *old_pkb3 = NULL;
436 enum ndr_err_code ndr_err;
439 * prepare generation of keys
441 * ENCTYPE_DES_CBC_MD5
442 * ENCTYPE_DES_CBC_CRC
445 pkb3->salt.string = io->g.salt;
447 pkb3->keys = talloc_array(io->ac,
448 struct package_PrimaryKerberosKey3,
451 ldb_oom(io->ac->module->ldb);
452 return LDB_ERR_OPERATIONS_ERROR;
455 pkb3->keys[0].keytype = ENCTYPE_DES_CBC_MD5;
456 pkb3->keys[0].value = &io->g.des_md5;
457 pkb3->keys[1].keytype = ENCTYPE_DES_CBC_CRC;
458 pkb3->keys[1].value = &io->g.des_crc;
460 /* initialize the old keys to zero */
461 pkb3->num_old_keys = 0;
462 pkb3->old_keys = NULL;
464 /* if there're no old keys, then we're done */
469 for (i=0; i < old_scb->sub.num_packages; i++) {
470 if (strcmp("Primary:Kerberos", old_scb->sub.packages[i].name) != 0) {
474 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
478 old_scp = &old_scb->sub.packages[i];
481 /* Primary:Kerberos element of supplementalCredentials */
485 blob = strhex_to_data_blob(io->ac, old_scp->data);
487 ldb_oom(io->ac->module->ldb);
488 return LDB_ERR_OPERATIONS_ERROR;
491 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
492 ndr_err = ndr_pull_struct_blob(&blob, io->ac, lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")), &_old_pkb,
493 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
494 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
495 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
496 ldb_asprintf_errstring(io->ac->module->ldb,
497 "setup_primary_kerberos: "
498 "failed to pull old package_PrimaryKerberosBlob: %s",
500 return LDB_ERR_OPERATIONS_ERROR;
503 if (_old_pkb.version != 3) {
504 ldb_asprintf_errstring(io->ac->module->ldb,
505 "setup_primary_kerberos: "
506 "package_PrimaryKerberosBlob version[%u] expected[3]",
508 return LDB_ERR_OPERATIONS_ERROR;
511 old_pkb3 = &_old_pkb.ctr.ctr3;
514 /* if we didn't found the old keys we're done */
519 /* fill in the old keys */
520 pkb3->num_old_keys = old_pkb3->num_keys;
521 pkb3->old_keys = old_pkb3->keys;
526 static int setup_primary_kerberos_newer(struct setup_password_fields_io *io,
527 const struct supplementalCredentialsBlob *old_scb,
528 struct package_PrimaryKerberosBlob *pkb)
530 struct package_PrimaryKerberosCtr4 *pkb4 = &pkb->ctr.ctr4;
531 struct supplementalCredentialsPackage *old_scp = NULL;
532 struct package_PrimaryKerberosBlob _old_pkb;
533 struct package_PrimaryKerberosCtr4 *old_pkb4 = NULL;
535 enum ndr_err_code ndr_err;
538 * prepare generation of keys
540 * ENCTYPE_AES256_CTS_HMAC_SHA1_96
541 * ENCTYPE_AES128_CTS_HMAC_SHA1_96
542 * ENCTYPE_DES_CBC_MD5
543 * ENCTYPE_DES_CBC_CRC
546 pkb4->salt.string = io->g.salt;
547 pkb4->default_iteration_count = 4096;
550 pkb4->keys = talloc_array(io->ac,
551 struct package_PrimaryKerberosKey4,
554 ldb_oom(io->ac->module->ldb);
555 return LDB_ERR_OPERATIONS_ERROR;
558 pkb4->keys[0].iteration_count = 4096;
559 pkb4->keys[0].keytype = ENCTYPE_AES256_CTS_HMAC_SHA1_96;
560 pkb4->keys[0].value = &io->g.aes_256;
561 pkb4->keys[1].iteration_count = 4096;
562 pkb4->keys[1].keytype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
563 pkb4->keys[1].value = &io->g.aes_128;
564 pkb4->keys[2].iteration_count = 4096;
565 pkb4->keys[2].keytype = ENCTYPE_DES_CBC_MD5;
566 pkb4->keys[2].value = &io->g.des_md5;
567 pkb4->keys[3].iteration_count = 4096;
568 pkb4->keys[3].keytype = ENCTYPE_DES_CBC_CRC;
569 pkb4->keys[3].value = &io->g.des_crc;
571 /* initialize the old keys to zero */
572 pkb4->num_old_keys = 0;
573 pkb4->old_keys = NULL;
574 pkb4->num_older_keys = 0;
575 pkb4->older_keys = NULL;
577 /* if there're no old keys, then we're done */
582 for (i=0; i < old_scb->sub.num_packages; i++) {
583 if (strcmp("Primary:Kerberos-Newer-Keys", old_scb->sub.packages[i].name) != 0) {
587 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
591 old_scp = &old_scb->sub.packages[i];
594 /* Primary:Kerberos-Newer-Keys element of supplementalCredentials */
598 blob = strhex_to_data_blob(io->ac, old_scp->data);
600 ldb_oom(io->ac->module->ldb);
601 return LDB_ERR_OPERATIONS_ERROR;
604 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
605 ndr_err = ndr_pull_struct_blob(&blob, io->ac,
606 lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
608 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
609 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
610 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
611 ldb_asprintf_errstring(io->ac->module->ldb,
612 "setup_primary_kerberos_newer: "
613 "failed to pull old package_PrimaryKerberosBlob: %s",
615 return LDB_ERR_OPERATIONS_ERROR;
618 if (_old_pkb.version != 4) {
619 ldb_asprintf_errstring(io->ac->module->ldb,
620 "setup_primary_kerberos_newer: "
621 "package_PrimaryKerberosBlob version[%u] expected[4]",
623 return LDB_ERR_OPERATIONS_ERROR;
626 old_pkb4 = &_old_pkb.ctr.ctr4;
629 /* if we didn't found the old keys we're done */
634 /* fill in the old keys */
635 pkb4->num_old_keys = old_pkb4->num_keys;
636 pkb4->old_keys = old_pkb4->keys;
637 pkb4->num_older_keys = old_pkb4->num_old_keys;
638 pkb4->older_keys = old_pkb4->old_keys;
643 static int setup_primary_wdigest(struct setup_password_fields_io *io,
644 const struct supplementalCredentialsBlob *old_scb,
645 struct package_PrimaryWDigestBlob *pdb)
647 DATA_BLOB sAMAccountName;
648 DATA_BLOB sAMAccountName_l;
649 DATA_BLOB sAMAccountName_u;
650 const char *user_principal_name = io->u.user_principal_name;
651 DATA_BLOB userPrincipalName;
652 DATA_BLOB userPrincipalName_l;
653 DATA_BLOB userPrincipalName_u;
654 DATA_BLOB netbios_domain;
655 DATA_BLOB netbios_domain_l;
656 DATA_BLOB netbios_domain_u;
657 DATA_BLOB dns_domain;
658 DATA_BLOB dns_domain_l;
659 DATA_BLOB dns_domain_u;
671 * http://technet2.microsoft.com/WindowsServer/en/library/717b450c-f4a0-4cc9-86f4-cc0633aae5f91033.mspx?mfr=true
672 * for what precalculated hashes are supposed to be stored...
674 * I can't reproduce all values which should contain "Digest" as realm,
675 * am I doing something wrong or is w2k3 just broken...?
677 * W2K3 fills in following for a user:
679 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
680 * sAMAccountName: NewUser2Sam
681 * userPrincipalName: NewUser2Princ@sub1.w2k3.vmnet1.vm.base
683 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
684 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
685 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
686 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
687 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
688 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
689 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
690 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
691 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
692 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
693 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
694 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
695 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
696 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
697 * 221c55284451ae9b3aacaa2a3c86f10f => NewUser2Princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
698 * 74e1be668853d4324d38c07e2acfb8ea => (w2k3 has a bug here!) newuser2princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
699 * e1e244ab7f098e3ae1761be7f9229bbb => NEWUSER2PRINC@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
700 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
701 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
702 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
703 * 31dc704d3640335b2123d4ee28aa1f11 => ??? changes with NewUser2Sam => NewUser1Sam
704 * 36349f5cecd07320fb3bb0e119230c43 => ??? changes with NewUser2Sam => NewUser1Sam
705 * 12adf019d037fb535c01fd0608e78d9d => ??? changes with NewUser2Sam => NewUser1Sam
706 * 6feecf8e724906f3ee1105819c5105a1 => ??? changes with NewUser2Princ => NewUser1Princ
707 * 6c6911f3de6333422640221b9c51ff1f => ??? changes with NewUser2Princ => NewUser1Princ
708 * 4b279877e742895f9348ac67a8de2f69 => ??? changes with NewUser2Princ => NewUser1Princ
709 * db0c6bff069513e3ebb9870d29b57490 => ??? changes with NewUser2Sam => NewUser1Sam
710 * 45072621e56b1c113a4e04a8ff68cd0e => ??? changes with NewUser2Sam => NewUser1Sam
711 * 11d1220abc44a9c10cf91ef4a9c1de02 => ??? changes with NewUser2Sam => NewUser1Sam
713 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
714 * sAMAccountName: NewUser2Sam
716 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
717 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
718 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
719 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
720 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
721 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
722 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
723 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
724 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
725 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
726 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
727 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
728 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
729 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
730 * 8a140d30b6f0a5912735dc1e3bc993b4 => NewUser2Sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
731 * 86d95b2faae6cae4ec261e7fbaccf093 => (here w2k3 is correct) newuser2sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
732 * dfeff1493110220efcdfc6362e5f5450 => NEWUSER2SAM@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
733 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
734 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
735 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
736 * 31dc704d3640335b2123d4ee28aa1f11 => ???M1 changes with NewUser2Sam => NewUser1Sam
737 * 36349f5cecd07320fb3bb0e119230c43 => ???M1.L changes with newuser2sam => newuser1sam
738 * 12adf019d037fb535c01fd0608e78d9d => ???M1.U changes with NEWUSER2SAM => NEWUSER1SAM
739 * 569b4533f2d9e580211dd040e5e360a8 => ???M2 changes with NewUser2Princ => NewUser1Princ
740 * 52528bddf310a587c5d7e6a9ae2cbb20 => ???M2.L changes with newuser2princ => newuser1princ
741 * 4f629a4f0361289ca4255ab0f658fcd5 => ???M3 changes with NewUser2Princ => NewUser1Princ (doesn't depend on case of userPrincipal )
742 * db0c6bff069513e3ebb9870d29b57490 => ???M4 changes with NewUser2Sam => NewUser1Sam
743 * 45072621e56b1c113a4e04a8ff68cd0e => ???M5 changes with NewUser2Sam => NewUser1Sam (doesn't depend on case of sAMAccountName)
744 * 11d1220abc44a9c10cf91ef4a9c1de02 => ???M4.U changes with NEWUSER2SAM => NEWUSER1SAM
748 * sAMAccountName, netbios_domain
751 .user = &sAMAccountName,
752 .realm = &netbios_domain,
755 .user = &sAMAccountName_l,
756 .realm = &netbios_domain_l,
759 .user = &sAMAccountName_u,
760 .realm = &netbios_domain_u,
763 .user = &sAMAccountName,
764 .realm = &netbios_domain_u,
767 .user = &sAMAccountName,
768 .realm = &netbios_domain_l,
771 .user = &sAMAccountName_u,
772 .realm = &netbios_domain_l,
775 .user = &sAMAccountName_l,
776 .realm = &netbios_domain_u,
779 * sAMAccountName, dns_domain
782 .user = &sAMAccountName,
783 .realm = &dns_domain,
786 .user = &sAMAccountName_l,
787 .realm = &dns_domain_l,
790 .user = &sAMAccountName_u,
791 .realm = &dns_domain_u,
794 .user = &sAMAccountName,
795 .realm = &dns_domain_u,
798 .user = &sAMAccountName,
799 .realm = &dns_domain_l,
802 .user = &sAMAccountName_u,
803 .realm = &dns_domain_l,
806 .user = &sAMAccountName_l,
807 .realm = &dns_domain_u,
810 * userPrincipalName, no realm
813 .user = &userPrincipalName,
817 * NOTE: w2k3 messes this up, if the user has a real userPrincipalName,
818 * the fallback to the sAMAccountName based userPrincipalName is correct
820 .user = &userPrincipalName_l,
823 .user = &userPrincipalName_u,
826 * nt4dom\sAMAccountName, no realm
829 .user = &sAMAccountName,
830 .nt4dom = &netbios_domain
833 .user = &sAMAccountName_l,
834 .nt4dom = &netbios_domain_l
837 .user = &sAMAccountName_u,
838 .nt4dom = &netbios_domain_u
842 * the following ones are guessed depending on the technet2 article
843 * but not reproducable on a w2k3 server
845 /* sAMAccountName with "Digest" realm */
847 .user = &sAMAccountName,
851 .user = &sAMAccountName_l,
855 .user = &sAMAccountName_u,
858 /* userPrincipalName with "Digest" realm */
860 .user = &userPrincipalName,
864 .user = &userPrincipalName_l,
868 .user = &userPrincipalName_u,
871 /* nt4dom\\sAMAccountName with "Digest" realm */
873 .user = &sAMAccountName,
874 .nt4dom = &netbios_domain,
878 .user = &sAMAccountName_l,
879 .nt4dom = &netbios_domain_l,
883 .user = &sAMAccountName_u,
884 .nt4dom = &netbios_domain_u,
889 /* prepare DATA_BLOB's used in the combinations array */
890 sAMAccountName = data_blob_string_const(io->u.sAMAccountName);
891 sAMAccountName_l = data_blob_string_const(strlower_talloc(io->ac, io->u.sAMAccountName));
892 if (!sAMAccountName_l.data) {
893 ldb_oom(io->ac->module->ldb);
894 return LDB_ERR_OPERATIONS_ERROR;
896 sAMAccountName_u = data_blob_string_const(strupper_talloc(io->ac, io->u.sAMAccountName));
897 if (!sAMAccountName_u.data) {
898 ldb_oom(io->ac->module->ldb);
899 return LDB_ERR_OPERATIONS_ERROR;
902 /* if the user doesn't have a userPrincipalName, create one (with lower case realm) */
903 if (!user_principal_name) {
904 user_principal_name = talloc_asprintf(io->ac, "%s@%s",
905 io->u.sAMAccountName,
906 io->domain->dns_domain);
907 if (!user_principal_name) {
908 ldb_oom(io->ac->module->ldb);
909 return LDB_ERR_OPERATIONS_ERROR;
912 userPrincipalName = data_blob_string_const(user_principal_name);
913 userPrincipalName_l = data_blob_string_const(strlower_talloc(io->ac, user_principal_name));
914 if (!userPrincipalName_l.data) {
915 ldb_oom(io->ac->module->ldb);
916 return LDB_ERR_OPERATIONS_ERROR;
918 userPrincipalName_u = data_blob_string_const(strupper_talloc(io->ac, user_principal_name));
919 if (!userPrincipalName_u.data) {
920 ldb_oom(io->ac->module->ldb);
921 return LDB_ERR_OPERATIONS_ERROR;
924 netbios_domain = data_blob_string_const(io->domain->netbios_domain);
925 netbios_domain_l = data_blob_string_const(strlower_talloc(io->ac, io->domain->netbios_domain));
926 if (!netbios_domain_l.data) {
927 ldb_oom(io->ac->module->ldb);
928 return LDB_ERR_OPERATIONS_ERROR;
930 netbios_domain_u = data_blob_string_const(strupper_talloc(io->ac, io->domain->netbios_domain));
931 if (!netbios_domain_u.data) {
932 ldb_oom(io->ac->module->ldb);
933 return LDB_ERR_OPERATIONS_ERROR;
936 dns_domain = data_blob_string_const(io->domain->dns_domain);
937 dns_domain_l = data_blob_string_const(io->domain->dns_domain);
938 dns_domain_u = data_blob_string_const(io->domain->realm);
940 digest = data_blob_string_const("Digest");
942 delim = data_blob_string_const(":");
943 backslash = data_blob_string_const("\\");
945 pdb->num_hashes = ARRAY_SIZE(wdigest);
946 pdb->hashes = talloc_array(io->ac, struct package_PrimaryWDigestHash, pdb->num_hashes);
948 ldb_oom(io->ac->module->ldb);
949 return LDB_ERR_OPERATIONS_ERROR;
952 for (i=0; i < ARRAY_SIZE(wdigest); i++) {
953 struct MD5Context md5;
955 if (wdigest[i].nt4dom) {
956 MD5Update(&md5, wdigest[i].nt4dom->data, wdigest[i].nt4dom->length);
957 MD5Update(&md5, backslash.data, backslash.length);
959 MD5Update(&md5, wdigest[i].user->data, wdigest[i].user->length);
960 MD5Update(&md5, delim.data, delim.length);
961 if (wdigest[i].realm) {
962 MD5Update(&md5, wdigest[i].realm->data, wdigest[i].realm->length);
964 MD5Update(&md5, delim.data, delim.length);
965 MD5Update(&md5, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length);
966 MD5Final(pdb->hashes[i].hash, &md5);
972 static int setup_supplemental_field(struct setup_password_fields_io *io)
974 struct supplementalCredentialsBlob scb;
975 struct supplementalCredentialsBlob _old_scb;
976 struct supplementalCredentialsBlob *old_scb = NULL;
977 /* Packages + (Kerberos-Newer-Keys, Kerberos, WDigest and CLEARTEXT) */
978 uint32_t num_names = 0;
979 const char *names[1+4];
980 uint32_t num_packages = 0;
981 struct supplementalCredentialsPackage packages[1+4];
983 struct supplementalCredentialsPackage *pp = NULL;
984 struct package_PackagesBlob pb;
987 /* Primary:Kerberos-Newer-Keys */
988 const char **nkn = NULL;
989 struct supplementalCredentialsPackage *pkn = NULL;
990 struct package_PrimaryKerberosBlob pknb;
993 /* Primary:Kerberos */
994 const char **nk = NULL;
995 struct supplementalCredentialsPackage *pk = NULL;
996 struct package_PrimaryKerberosBlob pkb;
999 /* Primary:WDigest */
1000 const char **nd = NULL;
1001 struct supplementalCredentialsPackage *pd = NULL;
1002 struct package_PrimaryWDigestBlob pdb;
1005 /* Primary:CLEARTEXT */
1006 const char **nc = NULL;
1007 struct supplementalCredentialsPackage *pc = NULL;
1008 struct package_PrimaryCLEARTEXTBlob pcb;
1012 enum ndr_err_code ndr_err;
1014 bool do_newer_keys = false;
1015 bool do_cleartext = false;
1017 ZERO_STRUCT(zero16);
1020 if (!io->n.cleartext_utf8) {
1022 * when we don't have a cleartext password
1023 * we can't setup a supplementalCredential value
1028 /* if there's an old supplementaCredentials blob then parse it */
1029 if (io->o.supplemental) {
1030 ndr_err = ndr_pull_struct_blob_all(io->o.supplemental, io->ac,
1031 lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
1033 (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
1034 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1035 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1036 ldb_asprintf_errstring(io->ac->module->ldb,
1037 "setup_supplemental_field: "
1038 "failed to pull old supplementalCredentialsBlob: %s",
1040 return LDB_ERR_OPERATIONS_ERROR;
1043 if (_old_scb.sub.signature == SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
1044 old_scb = &_old_scb;
1046 ldb_debug(io->ac->module->ldb, LDB_DEBUG_ERROR,
1047 "setup_supplemental_field: "
1048 "supplementalCredentialsBlob signature[0x%04X] expected[0x%04X]",
1049 _old_scb.sub.signature, SUPPLEMENTAL_CREDENTIALS_SIGNATURE);
1053 /* TODO: do the correct check for this, it maybe depends on the functional level? */
1054 do_newer_keys = lp_parm_bool(ldb_get_opaque(io->ac->module->ldb, "loadparm"),
1055 NULL, "password_hash", "create_aes_key", false);
1057 if (io->domain->store_cleartext &&
1058 (io->u.user_account_control & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) {
1059 do_cleartext = true;
1063 * The ordering is this
1065 * Primary:Kerberos-Newer-Keys (optional)
1068 * Primary:CLEARTEXT (optional)
1070 * And the 'Packages' package is insert before the last
1073 if (do_newer_keys) {
1074 /* Primary:Kerberos-Newer-Keys */
1075 nkn = &names[num_names++];
1076 pkn = &packages[num_packages++];
1079 /* Primary:Kerberos */
1080 nk = &names[num_names++];
1081 pk = &packages[num_packages++];
1083 if (!do_cleartext) {
1085 pp = &packages[num_packages++];
1088 /* Primary:WDigest */
1089 nd = &names[num_names++];
1090 pd = &packages[num_packages++];
1094 pp = &packages[num_packages++];
1096 /* Primary:CLEARTEXT */
1097 nc = &names[num_names++];
1098 pc = &packages[num_packages++];
1103 * setup 'Primary:Kerberos-Newer-Keys' element
1105 *nkn = "Kerberos-Newer-Keys";
1107 ret = setup_primary_kerberos_newer(io, old_scb, &pknb);
1108 if (ret != LDB_SUCCESS) {
1112 ndr_err = ndr_push_struct_blob(&pknb_blob, io->ac,
1113 lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
1115 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1116 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1117 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1118 ldb_asprintf_errstring(io->ac->module->ldb,
1119 "setup_supplemental_field: "
1120 "failed to push package_PrimaryKerberosNeverBlob: %s",
1122 return LDB_ERR_OPERATIONS_ERROR;
1124 pknb_hexstr = data_blob_hex_string(io->ac, &pknb_blob);
1126 ldb_oom(io->ac->module->ldb);
1127 return LDB_ERR_OPERATIONS_ERROR;
1129 pkn->name = "Primary:Kerberos-Newer-Keys";
1131 pkn->data = pknb_hexstr;
1135 * setup 'Primary:Kerberos' element
1139 ret = setup_primary_kerberos(io, old_scb, &pkb);
1140 if (ret != LDB_SUCCESS) {
1144 ndr_err = ndr_push_struct_blob(&pkb_blob, io->ac,
1145 lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
1147 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1148 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1149 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1150 ldb_asprintf_errstring(io->ac->module->ldb,
1151 "setup_supplemental_field: "
1152 "failed to push package_PrimaryKerberosBlob: %s",
1154 return LDB_ERR_OPERATIONS_ERROR;
1156 pkb_hexstr = data_blob_hex_string(io->ac, &pkb_blob);
1158 ldb_oom(io->ac->module->ldb);
1159 return LDB_ERR_OPERATIONS_ERROR;
1161 pk->name = "Primary:Kerberos";
1163 pk->data = pkb_hexstr;
1166 * setup 'Primary:WDigest' element
1170 ret = setup_primary_wdigest(io, old_scb, &pdb);
1171 if (ret != LDB_SUCCESS) {
1175 ndr_err = ndr_push_struct_blob(&pdb_blob, io->ac,
1176 lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
1178 (ndr_push_flags_fn_t)ndr_push_package_PrimaryWDigestBlob);
1179 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1180 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1181 ldb_asprintf_errstring(io->ac->module->ldb,
1182 "setup_supplemental_field: "
1183 "failed to push package_PrimaryWDigestBlob: %s",
1185 return LDB_ERR_OPERATIONS_ERROR;
1187 pdb_hexstr = data_blob_hex_string(io->ac, &pdb_blob);
1189 ldb_oom(io->ac->module->ldb);
1190 return LDB_ERR_OPERATIONS_ERROR;
1192 pd->name = "Primary:WDigest";
1194 pd->data = pdb_hexstr;
1197 * setup 'Primary:CLEARTEXT' element
1202 pcb.cleartext = *io->n.cleartext_utf16;
1204 ndr_err = ndr_push_struct_blob(&pcb_blob, io->ac,
1205 lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
1207 (ndr_push_flags_fn_t)ndr_push_package_PrimaryCLEARTEXTBlob);
1208 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1209 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1210 ldb_asprintf_errstring(io->ac->module->ldb,
1211 "setup_supplemental_field: "
1212 "failed to push package_PrimaryCLEARTEXTBlob: %s",
1214 return LDB_ERR_OPERATIONS_ERROR;
1216 pcb_hexstr = data_blob_hex_string(io->ac, &pcb_blob);
1218 ldb_oom(io->ac->module->ldb);
1219 return LDB_ERR_OPERATIONS_ERROR;
1221 pc->name = "Primary:CLEARTEXT";
1223 pc->data = pcb_hexstr;
1227 * setup 'Packages' element
1230 ndr_err = ndr_push_struct_blob(&pb_blob, io->ac,
1231 lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
1233 (ndr_push_flags_fn_t)ndr_push_package_PackagesBlob);
1234 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1235 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1236 ldb_asprintf_errstring(io->ac->module->ldb,
1237 "setup_supplemental_field: "
1238 "failed to push package_PackagesBlob: %s",
1240 return LDB_ERR_OPERATIONS_ERROR;
1242 pb_hexstr = data_blob_hex_string(io->ac, &pb_blob);
1244 ldb_oom(io->ac->module->ldb);
1245 return LDB_ERR_OPERATIONS_ERROR;
1247 pp->name = "Packages";
1249 pp->data = pb_hexstr;
1252 * setup 'supplementalCredentials' value
1255 scb.sub.num_packages = num_packages;
1256 scb.sub.packages = packages;
1258 ndr_err = ndr_push_struct_blob(&io->g.supplemental, io->ac,
1259 lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
1261 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
1262 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1263 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1264 ldb_asprintf_errstring(io->ac->module->ldb,
1265 "setup_supplemental_field: "
1266 "failed to push supplementalCredentialsBlob: %s",
1268 return LDB_ERR_OPERATIONS_ERROR;
1274 static int setup_last_set_field(struct setup_password_fields_io *io)
1277 unix_to_nt_time(&io->g.last_set, time(NULL));
1282 static int setup_kvno_field(struct setup_password_fields_io *io)
1284 /* increment by one */
1285 io->g.kvno = io->o.kvno + 1;
1290 static int setup_password_fields(struct setup_password_fields_io *io)
1294 ssize_t converted_pw_len;
1297 * refuse the change if someone want to change the cleartext
1298 * and supply his own hashes at the same time...
1300 if ((io->n.cleartext_utf8 || io->n.cleartext_utf16) && (io->n.nt_hash || io->n.lm_hash)) {
1301 ldb_asprintf_errstring(io->ac->module->ldb,
1302 "setup_password_fields: "
1303 "it's only allowed to set the cleartext password or the password hashes");
1304 return LDB_ERR_UNWILLING_TO_PERFORM;
1307 if (io->n.cleartext_utf8 && io->n.cleartext_utf16) {
1308 ldb_asprintf_errstring(io->ac->module->ldb,
1309 "setup_password_fields: "
1310 "it's only allowed to set the cleartext password as userPassword or clearTextPasssword, not both at once");
1311 return LDB_ERR_UNWILLING_TO_PERFORM;
1314 if (io->n.cleartext_utf8) {
1315 char **cleartext_utf16_str;
1316 struct ldb_val *cleartext_utf16_blob;
1317 io->n.cleartext_utf16 = cleartext_utf16_blob = talloc(io->ac, struct ldb_val);
1318 if (!io->n.cleartext_utf16) {
1319 ldb_oom(io->ac->module->ldb);
1320 return LDB_ERR_OPERATIONS_ERROR;
1322 converted_pw_len = convert_string_talloc_convenience(io->ac, lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
1323 CH_UTF8, CH_UTF16, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length,
1324 (void **)&cleartext_utf16_str);
1325 if (converted_pw_len == -1) {
1326 ldb_asprintf_errstring(io->ac->module->ldb,
1327 "setup_password_fields: "
1328 "failed to generate UTF16 password from cleartext UTF8 password");
1329 return LDB_ERR_OPERATIONS_ERROR;
1331 *cleartext_utf16_blob = data_blob_const(cleartext_utf16_str, converted_pw_len);
1332 } else if (io->n.cleartext_utf16) {
1333 char *cleartext_utf8_str;
1334 struct ldb_val *cleartext_utf8_blob;
1335 io->n.cleartext_utf8 = cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
1336 if (!io->n.cleartext_utf8) {
1337 ldb_oom(io->ac->module->ldb);
1338 return LDB_ERR_OPERATIONS_ERROR;
1340 converted_pw_len = convert_string_talloc_convenience(io->ac, lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
1341 CH_UTF16MUNGED, CH_UTF8, io->n.cleartext_utf16->data, io->n.cleartext_utf16->length,
1342 (void **)&cleartext_utf8_str);
1343 if (converted_pw_len == -1) {
1344 /* We can't bail out entirely, as these unconvertable passwords are frustratingly valid */
1345 io->n.cleartext_utf8 = NULL;
1346 talloc_free(cleartext_utf8_blob);
1348 *cleartext_utf8_blob = data_blob_const(cleartext_utf8_str, converted_pw_len);
1350 if (io->n.cleartext_utf16) {
1351 struct samr_Password *nt_hash;
1352 nt_hash = talloc(io->ac, struct samr_Password);
1354 ldb_oom(io->ac->module->ldb);
1355 return LDB_ERR_OPERATIONS_ERROR;
1357 io->n.nt_hash = nt_hash;
1359 /* compute the new nt hash */
1360 mdfour(nt_hash->hash, io->n.cleartext_utf16->data, io->n.cleartext_utf16->length);
1363 if (io->n.cleartext_utf8) {
1364 struct samr_Password *lm_hash;
1365 char *cleartext_unix;
1366 converted_pw_len = convert_string_talloc_convenience(io->ac, lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
1367 CH_UTF8, CH_UNIX, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length,
1368 (void **)&cleartext_unix);
1369 if (converted_pw_len != -1) {
1370 lm_hash = talloc(io->ac, struct samr_Password);
1372 ldb_oom(io->ac->module->ldb);
1373 return LDB_ERR_OPERATIONS_ERROR;
1376 /* compute the new lm hash. */
1377 ok = E_deshash((char *)cleartext_unix, lm_hash->hash);
1379 io->n.lm_hash = lm_hash;
1381 talloc_free(lm_hash->hash);
1385 ret = setup_kerberos_keys(io);
1391 ret = setup_nt_fields(io);
1396 ret = setup_lm_fields(io);
1401 ret = setup_supplemental_field(io);
1406 ret = setup_last_set_field(io);
1411 ret = setup_kvno_field(io);
1419 static struct ph_context *ph_init_context(struct ldb_module *module,
1420 struct ldb_request *req)
1422 struct ph_context *ac;
1424 ac = talloc_zero(req, struct ph_context);
1426 ldb_set_errstring(module->ldb, "Out of Memory");
1430 ac->module = module;
1436 static int ph_op_callback(struct ldb_request *req, struct ldb_reply *ares)
1438 struct ph_context *ac;
1440 ac = talloc_get_type(req->context, struct ph_context);
1443 return ldb_module_done(ac->req, NULL, NULL,
1444 LDB_ERR_OPERATIONS_ERROR);
1446 if (ares->error != LDB_SUCCESS) {
1447 return ldb_module_done(ac->req, ares->controls,
1448 ares->response, ares->error);
1451 if (ares->type != LDB_REPLY_DONE) {
1453 return ldb_module_done(ac->req, NULL, NULL,
1454 LDB_ERR_OPERATIONS_ERROR);
1457 return ldb_module_done(ac->req, ares->controls,
1458 ares->response, ares->error);
1461 static int password_hash_add_do_add(struct ph_context *ac);
1462 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares);
1463 static int password_hash_mod_search_self(struct ph_context *ac);
1464 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares);
1465 static int password_hash_mod_do_mod(struct ph_context *ac);
1467 static int get_domain_data_callback(struct ldb_request *req,
1468 struct ldb_reply *ares)
1470 struct domain_data *data;
1471 struct ph_context *ac;
1476 ac = talloc_get_type(req->context, struct ph_context);
1479 return ldb_module_done(ac->req, NULL, NULL,
1480 LDB_ERR_OPERATIONS_ERROR);
1482 if (ares->error != LDB_SUCCESS) {
1483 return ldb_module_done(ac->req, ares->controls,
1484 ares->response, ares->error);
1487 switch (ares->type) {
1488 case LDB_REPLY_ENTRY:
1489 if (ac->domain != NULL) {
1490 ldb_set_errstring(ac->module->ldb, "Too many results");
1491 return ldb_module_done(ac->req, NULL, NULL,
1492 LDB_ERR_OPERATIONS_ERROR);
1495 data = talloc_zero(ac, struct domain_data);
1497 return ldb_module_done(ac->req, NULL, NULL,
1498 LDB_ERR_OPERATIONS_ERROR);
1501 data->pwdProperties = samdb_result_uint(ares->message, "pwdProperties", 0);
1502 data->store_cleartext = data->pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
1503 data->pwdHistoryLength = samdb_result_uint(ares->message, "pwdHistoryLength", 0);
1505 /* For a domain DN, this puts things in dotted notation */
1506 /* For builtin domains, this will give details for the host,
1507 * but that doesn't really matter, as it's just used for salt
1508 * and kerberos principals, which don't exist here */
1510 tmp = ldb_dn_canonical_string(data, ares->message->dn);
1512 return ldb_module_done(ac->req, NULL, NULL,
1513 LDB_ERR_OPERATIONS_ERROR);
1516 /* But it puts a trailing (or just before 'builtin') / on things, so kill that */
1517 p = strchr(tmp, '/');
1522 data->dns_domain = strlower_talloc(data, tmp);
1523 if (data->dns_domain == NULL) {
1524 ldb_oom(ac->module->ldb);
1525 return ldb_module_done(ac->req, NULL, NULL,
1526 LDB_ERR_OPERATIONS_ERROR);
1528 data->realm = strupper_talloc(data, tmp);
1529 if (data->realm == NULL) {
1530 ldb_oom(ac->module->ldb);
1531 return ldb_module_done(ac->req, NULL, NULL,
1532 LDB_ERR_OPERATIONS_ERROR);
1534 /* FIXME: NetbIOS name is *always* the first domain component ?? -SSS */
1535 p = strchr(tmp, '.');
1539 data->netbios_domain = strupper_talloc(data, tmp);
1540 if (data->netbios_domain == NULL) {
1541 ldb_oom(ac->module->ldb);
1542 return ldb_module_done(ac->req, NULL, NULL,
1543 LDB_ERR_OPERATIONS_ERROR);
1550 case LDB_REPLY_DONE:
1552 /* call the next step */
1553 switch (ac->req->operation) {
1555 ret = password_hash_add_do_add(ac);
1559 ret = password_hash_mod_do_mod(ac);
1563 ret = LDB_ERR_OPERATIONS_ERROR;
1566 if (ret != LDB_SUCCESS) {
1567 return ldb_module_done(ac->req, NULL, NULL, ret);
1570 case LDB_REPLY_REFERRAL:
1579 static int build_domain_data_request(struct ph_context *ac)
1581 /* attrs[] is returned from this function in
1582 ac->dom_req->op.search.attrs, so it must be static, as
1583 otherwise the compiler can put it on the stack */
1584 static const char * const attrs[] = { "pwdProperties", "pwdHistoryLength", NULL };
1587 filter = talloc_asprintf(ac,
1588 "(&(objectSid=%s)(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain)))",
1589 ldap_encode_ndr_dom_sid(ac, ac->domain_sid));
1590 if (filter == NULL) {
1591 ldb_oom(ac->module->ldb);
1592 return LDB_ERR_OPERATIONS_ERROR;
1595 return ldb_build_search_req(&ac->dom_req, ac->module->ldb, ac,
1596 ldb_get_default_basedn(ac->module->ldb),
1600 ac, get_domain_data_callback,
1604 static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
1606 struct ph_context *ac;
1607 struct ldb_message_element *sambaAttr;
1608 struct ldb_message_element *clearTextPasswordAttr;
1609 struct ldb_message_element *ntAttr;
1610 struct ldb_message_element *lmAttr;
1613 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "password_hash_add\n");
1615 if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
1616 return ldb_next_request(module, req);
1619 /* If the caller is manipulating the local passwords directly, let them pass */
1620 if (ldb_dn_compare_base(ldb_dn_new(req, module->ldb, LOCAL_BASE),
1621 req->op.add.message->dn) == 0) {
1622 return ldb_next_request(module, req);
1625 /* nobody must touch these fields */
1626 if (ldb_msg_find_element(req->op.add.message, "ntPwdHistory")) {
1627 return LDB_ERR_UNWILLING_TO_PERFORM;
1629 if (ldb_msg_find_element(req->op.add.message, "lmPwdHistory")) {
1630 return LDB_ERR_UNWILLING_TO_PERFORM;
1632 if (ldb_msg_find_element(req->op.add.message, "supplementalCredentials")) {
1633 return LDB_ERR_UNWILLING_TO_PERFORM;
1636 /* If no part of this ADD touches the userPassword, or the NT
1637 * or LM hashes, then we don't need to make any changes. */
1639 sambaAttr = ldb_msg_find_element(req->op.mod.message, "userPassword");
1640 clearTextPasswordAttr = ldb_msg_find_element(req->op.mod.message, "clearTextPassword");
1641 ntAttr = ldb_msg_find_element(req->op.mod.message, "unicodePwd");
1642 lmAttr = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
1644 if ((!sambaAttr) && (!clearTextPasswordAttr) && (!ntAttr) && (!lmAttr)) {
1645 return ldb_next_request(module, req);
1648 /* if it is not an entry of type person its an error */
1649 /* TODO: remove this when userPassword will be in schema */
1650 if (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "person")) {
1651 ldb_set_errstring(module->ldb, "Cannot set a password on entry that does not have objectClass 'person'");
1652 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1655 /* check userPassword is single valued here */
1656 /* TODO: remove this when userPassword will be single valued in schema */
1657 if (sambaAttr && sambaAttr->num_values > 1) {
1658 ldb_set_errstring(module->ldb, "mupltiple values for userPassword not allowed!\n");
1659 return LDB_ERR_CONSTRAINT_VIOLATION;
1661 if (clearTextPasswordAttr && clearTextPasswordAttr->num_values > 1) {
1662 ldb_set_errstring(module->ldb, "mupltiple values for clearTextPassword not allowed!\n");
1663 return LDB_ERR_CONSTRAINT_VIOLATION;
1666 if (ntAttr && (ntAttr->num_values > 1)) {
1667 ldb_set_errstring(module->ldb, "mupltiple values for unicodePwd not allowed!\n");
1668 return LDB_ERR_CONSTRAINT_VIOLATION;
1670 if (lmAttr && (lmAttr->num_values > 1)) {
1671 ldb_set_errstring(module->ldb, "mupltiple values for dBCSPwd not allowed!\n");
1672 return LDB_ERR_CONSTRAINT_VIOLATION;
1675 if (sambaAttr && sambaAttr->num_values == 0) {
1676 ldb_set_errstring(module->ldb, "userPassword must have a value!\n");
1677 return LDB_ERR_CONSTRAINT_VIOLATION;
1680 if (clearTextPasswordAttr && clearTextPasswordAttr->num_values == 0) {
1681 ldb_set_errstring(module->ldb, "clearTextPassword must have a value!\n");
1682 return LDB_ERR_CONSTRAINT_VIOLATION;
1685 if (ntAttr && (ntAttr->num_values == 0)) {
1686 ldb_set_errstring(module->ldb, "unicodePwd must have a value!\n");
1687 return LDB_ERR_CONSTRAINT_VIOLATION;
1689 if (lmAttr && (lmAttr->num_values == 0)) {
1690 ldb_set_errstring(module->ldb, "dBCSPwd must have a value!\n");
1691 return LDB_ERR_CONSTRAINT_VIOLATION;
1694 ac = ph_init_context(module, req);
1696 return LDB_ERR_OPERATIONS_ERROR;
1699 /* get user domain data */
1700 ac->domain_sid = samdb_result_sid_prefix(ac, req->op.add.message, "objectSid");
1701 if (ac->domain_sid == NULL) {
1702 ldb_debug(module->ldb, LDB_DEBUG_ERROR,
1703 "can't handle entry with missing objectSid!\n");
1704 return LDB_ERR_OPERATIONS_ERROR;
1707 ret = build_domain_data_request(ac);
1708 if (ret != LDB_SUCCESS) {
1712 return ldb_next_request(module, ac->dom_req);
1715 static int password_hash_add_do_add(struct ph_context *ac) {
1717 struct ldb_request *down_req;
1718 struct smb_krb5_context *smb_krb5_context;
1719 struct ldb_message *msg;
1720 struct setup_password_fields_io io;
1723 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
1725 return LDB_ERR_OPERATIONS_ERROR;
1728 /* Some operations below require kerberos contexts */
1729 if (smb_krb5_init_context(ac,
1730 ldb_get_event_context(ac->module->ldb),
1731 (struct loadparm_context *)ldb_get_opaque(ac->module->ldb, "loadparm"),
1732 &smb_krb5_context) != 0) {
1733 return LDB_ERR_OPERATIONS_ERROR;
1738 io.domain = ac->domain;
1739 io.smb_krb5_context = smb_krb5_context;
1741 io.u.user_account_control = samdb_result_uint(msg, "userAccountControl", 0);
1742 io.u.sAMAccountName = samdb_result_string(msg, "samAccountName", NULL);
1743 io.u.user_principal_name = samdb_result_string(msg, "userPrincipalName", NULL);
1744 io.u.is_computer = ldb_msg_check_string_attribute(msg, "objectClass", "computer");
1746 io.n.cleartext_utf8 = ldb_msg_find_ldb_val(msg, "userPassword");
1747 io.n.cleartext_utf16 = ldb_msg_find_ldb_val(msg, "clearTextPassword");
1748 io.n.nt_hash = samdb_result_hash(io.ac, msg, "unicodePwd");
1749 io.n.lm_hash = samdb_result_hash(io.ac, msg, "dBCSPwd");
1751 /* remove attributes */
1752 if (io.n.cleartext_utf8) ldb_msg_remove_attr(msg, "userPassword");
1753 if (io.n.cleartext_utf16) ldb_msg_remove_attr(msg, "clearTextPassword");
1754 if (io.n.nt_hash) ldb_msg_remove_attr(msg, "unicodePwd");
1755 if (io.n.lm_hash) ldb_msg_remove_attr(msg, "dBCSPwd");
1756 ldb_msg_remove_attr(msg, "pwdLastSet");
1757 io.o.kvno = samdb_result_uint(msg, "msDs-KeyVersionNumber", 1) - 1;
1758 ldb_msg_remove_attr(msg, "msDs-KeyVersionNumber");
1760 ret = setup_password_fields(&io);
1761 if (ret != LDB_SUCCESS) {
1766 ret = samdb_msg_add_hash(ac->module->ldb, ac, msg,
1767 "unicodePwd", io.g.nt_hash);
1768 if (ret != LDB_SUCCESS) {
1773 ret = samdb_msg_add_hash(ac->module->ldb, ac, msg,
1774 "dBCSPwd", io.g.lm_hash);
1775 if (ret != LDB_SUCCESS) {
1779 if (io.g.nt_history_len > 0) {
1780 ret = samdb_msg_add_hashes(ac, msg,
1783 io.g.nt_history_len);
1784 if (ret != LDB_SUCCESS) {
1788 if (io.g.lm_history_len > 0) {
1789 ret = samdb_msg_add_hashes(ac, msg,
1792 io.g.lm_history_len);
1793 if (ret != LDB_SUCCESS) {
1797 if (io.g.supplemental.length > 0) {
1798 ret = ldb_msg_add_value(msg, "supplementalCredentials",
1799 &io.g.supplemental, NULL);
1800 if (ret != LDB_SUCCESS) {
1804 ret = samdb_msg_add_uint64(ac->module->ldb, ac, msg,
1807 if (ret != LDB_SUCCESS) {
1810 ret = samdb_msg_add_uint(ac->module->ldb, ac, msg,
1811 "msDs-KeyVersionNumber",
1813 if (ret != LDB_SUCCESS) {
1817 ret = ldb_build_add_req(&down_req, ac->module->ldb, ac,
1822 if (ret != LDB_SUCCESS) {
1826 return ldb_next_request(ac->module, down_req);
1829 static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
1831 struct ph_context *ac;
1832 struct ldb_message_element *sambaAttr;
1833 struct ldb_message_element *clearTextAttr;
1834 struct ldb_message_element *ntAttr;
1835 struct ldb_message_element *lmAttr;
1836 struct ldb_message *msg;
1837 struct ldb_request *down_req;
1840 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
1842 if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
1843 return ldb_next_request(module, req);
1846 /* If the caller is manipulating the local passwords directly, let them pass */
1847 if (ldb_dn_compare_base(ldb_dn_new(req, module->ldb, LOCAL_BASE),
1848 req->op.mod.message->dn) == 0) {
1849 return ldb_next_request(module, req);
1852 /* nobody must touch password Histories */
1853 if (ldb_msg_find_element(req->op.add.message, "ntPwdHistory")) {
1854 return LDB_ERR_UNWILLING_TO_PERFORM;
1856 if (ldb_msg_find_element(req->op.add.message, "lmPwdHistory")) {
1857 return LDB_ERR_UNWILLING_TO_PERFORM;
1859 if (ldb_msg_find_element(req->op.add.message, "supplementalCredentials")) {
1860 return LDB_ERR_UNWILLING_TO_PERFORM;
1863 sambaAttr = ldb_msg_find_element(req->op.mod.message, "userPassword");
1864 clearTextAttr = ldb_msg_find_element(req->op.mod.message, "clearTextPassword");
1865 ntAttr = ldb_msg_find_element(req->op.mod.message, "unicodePwd");
1866 lmAttr = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
1868 /* If no part of this touches the userPassword OR
1869 * clearTextPassword OR unicodePwd and/or dBCSPwd, then we
1870 * don't need to make any changes. For password changes/set
1871 * there should be a 'delete' or a 'modify' on this
1873 if ((!sambaAttr) && (!clearTextAttr) && (!ntAttr) && (!lmAttr)) {
1874 return ldb_next_request(module, req);
1877 /* check passwords are single valued here */
1878 /* TODO: remove this when passwords will be single valued in schema */
1879 if (sambaAttr && (sambaAttr->num_values > 1)) {
1880 return LDB_ERR_CONSTRAINT_VIOLATION;
1882 if (clearTextAttr && (clearTextAttr->num_values > 1)) {
1883 return LDB_ERR_CONSTRAINT_VIOLATION;
1885 if (ntAttr && (ntAttr->num_values > 1)) {
1886 return LDB_ERR_CONSTRAINT_VIOLATION;
1888 if (lmAttr && (lmAttr->num_values > 1)) {
1889 return LDB_ERR_CONSTRAINT_VIOLATION;
1892 ac = ph_init_context(module, req);
1894 return LDB_ERR_OPERATIONS_ERROR;
1897 /* use a new message structure so that we can modify it */
1898 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
1900 ldb_oom(module->ldb);
1901 return LDB_ERR_OPERATIONS_ERROR;
1904 /* - remove any modification to the password from the first commit
1905 * we will make the real modification later */
1906 if (sambaAttr) ldb_msg_remove_attr(msg, "userPassword");
1907 if (clearTextAttr) ldb_msg_remove_attr(msg, "clearTextPassword");
1908 if (ntAttr) ldb_msg_remove_attr(msg, "unicodePwd");
1909 if (lmAttr) ldb_msg_remove_attr(msg, "dBCSPwd");
1911 /* if there was nothing else to be modified skip to next step */
1912 if (msg->num_elements == 0) {
1913 return password_hash_mod_search_self(ac);
1916 ret = ldb_build_mod_req(&down_req, module->ldb, ac,
1919 ac, ph_modify_callback,
1921 if (ret != LDB_SUCCESS) {
1925 return ldb_next_request(module, down_req);
1928 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
1930 struct ph_context *ac;
1933 ac = talloc_get_type(req->context, struct ph_context);
1936 return ldb_module_done(ac->req, NULL, NULL,
1937 LDB_ERR_OPERATIONS_ERROR);
1939 if (ares->error != LDB_SUCCESS) {
1940 return ldb_module_done(ac->req, ares->controls,
1941 ares->response, ares->error);
1944 if (ares->type != LDB_REPLY_DONE) {
1946 return ldb_module_done(ac->req, NULL, NULL,
1947 LDB_ERR_OPERATIONS_ERROR);
1950 ret = password_hash_mod_search_self(ac);
1951 if (ret != LDB_SUCCESS) {
1952 return ldb_module_done(ac->req, NULL, NULL, ret);
1959 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
1961 struct ph_context *ac;
1964 ac = talloc_get_type(req->context, struct ph_context);
1967 return ldb_module_done(ac->req, NULL, NULL,
1968 LDB_ERR_OPERATIONS_ERROR);
1970 if (ares->error != LDB_SUCCESS) {
1971 return ldb_module_done(ac->req, ares->controls,
1972 ares->response, ares->error);
1975 /* we are interested only in the single reply (base search) */
1976 switch (ares->type) {
1977 case LDB_REPLY_ENTRY:
1979 if (ac->search_res != NULL) {
1980 ldb_set_errstring(ac->module->ldb, "Too many results");
1982 return ldb_module_done(ac->req, NULL, NULL,
1983 LDB_ERR_OPERATIONS_ERROR);
1986 /* if it is not an entry of type person this is an error */
1987 /* TODO: remove this when sambaPassword will be in schema */
1988 if (!ldb_msg_check_string_attribute(ares->message, "objectClass", "person")) {
1989 ldb_set_errstring(ac->module->ldb, "Object class violation");
1991 return ldb_module_done(ac->req, NULL, NULL,
1992 LDB_ERR_OBJECT_CLASS_VIOLATION);
1995 ac->search_res = talloc_steal(ac, ares);
1998 case LDB_REPLY_DONE:
2000 /* get object domain sid */
2001 ac->domain_sid = samdb_result_sid_prefix(ac,
2002 ac->search_res->message,
2004 if (ac->domain_sid == NULL) {
2005 ldb_debug(ac->module->ldb, LDB_DEBUG_ERROR,
2006 "can't handle entry without objectSid!\n");
2007 return ldb_module_done(ac->req, NULL, NULL,
2008 LDB_ERR_OPERATIONS_ERROR);
2011 /* get user domain data */
2012 ret = build_domain_data_request(ac);
2013 if (ret != LDB_SUCCESS) {
2014 return ldb_module_done(ac->req, NULL, NULL,ret);
2017 return ldb_next_request(ac->module, ac->dom_req);
2019 case LDB_REPLY_REFERRAL:
2020 /*ignore anything else for now */
2028 static int password_hash_mod_search_self(struct ph_context *ac) {
2030 static const char * const attrs[] = { "userAccountControl", "lmPwdHistory",
2032 "objectSid", "msDS-KeyVersionNumber",
2033 "objectClass", "userPrincipalName",
2035 "dBCSPwd", "unicodePwd",
2036 "supplementalCredentials",
2038 struct ldb_request *search_req;
2041 ret = ldb_build_search_req(&search_req, ac->module->ldb, ac,
2042 ac->req->op.mod.message->dn,
2047 ac, ph_mod_search_callback,
2050 if (ret != LDB_SUCCESS) {
2054 return ldb_next_request(ac->module, search_req);
2057 static int password_hash_mod_do_mod(struct ph_context *ac) {
2059 struct ldb_request *mod_req;
2060 struct smb_krb5_context *smb_krb5_context;
2061 struct ldb_message *msg;
2062 struct ldb_message *orig_msg;
2063 struct ldb_message *searched_msg;
2064 struct setup_password_fields_io io;
2067 /* use a new message structure so that we can modify it */
2068 msg = ldb_msg_new(ac);
2070 return LDB_ERR_OPERATIONS_ERROR;
2074 msg->dn = ac->req->op.mod.message->dn;
2076 /* Some operations below require kerberos contexts */
2077 if (smb_krb5_init_context(ac,
2078 ldb_get_event_context(ac->module->ldb),
2079 (struct loadparm_context *)ldb_get_opaque(ac->module->ldb, "loadparm"),
2080 &smb_krb5_context) != 0) {
2081 return LDB_ERR_OPERATIONS_ERROR;
2084 orig_msg = discard_const(ac->req->op.mod.message);
2085 searched_msg = ac->search_res->message;
2089 io.domain = ac->domain;
2090 io.smb_krb5_context = smb_krb5_context;
2092 io.u.user_account_control = samdb_result_uint(searched_msg, "userAccountControl", 0);
2093 io.u.sAMAccountName = samdb_result_string(searched_msg, "samAccountName", NULL);
2094 io.u.user_principal_name = samdb_result_string(searched_msg, "userPrincipalName", NULL);
2095 io.u.is_computer = ldb_msg_check_string_attribute(searched_msg, "objectClass", "computer");
2097 io.n.cleartext_utf8 = ldb_msg_find_ldb_val(orig_msg, "userPassword");
2098 io.n.cleartext_utf16 = ldb_msg_find_ldb_val(orig_msg, "clearTextPassword");
2099 io.n.nt_hash = samdb_result_hash(io.ac, orig_msg, "unicodePwd");
2100 io.n.lm_hash = samdb_result_hash(io.ac, orig_msg, "dBCSPwd");
2102 io.o.kvno = samdb_result_uint(searched_msg, "msDs-KeyVersionNumber", 0);
2103 io.o.nt_history_len = samdb_result_hashes(io.ac, searched_msg, "ntPwdHistory", &io.o.nt_history);
2104 io.o.lm_history_len = samdb_result_hashes(io.ac, searched_msg, "lmPwdHistory", &io.o.lm_history);
2105 io.o.supplemental = ldb_msg_find_ldb_val(searched_msg, "supplementalCredentials");
2107 ret = setup_password_fields(&io);
2108 if (ret != LDB_SUCCESS) {
2112 /* make sure we replace all the old attributes */
2113 ret = ldb_msg_add_empty(msg, "unicodePwd", LDB_FLAG_MOD_REPLACE, NULL);
2114 ret = ldb_msg_add_empty(msg, "dBCSPwd", LDB_FLAG_MOD_REPLACE, NULL);
2115 ret = ldb_msg_add_empty(msg, "ntPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
2116 ret = ldb_msg_add_empty(msg, "lmPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
2117 ret = ldb_msg_add_empty(msg, "supplementalCredentials", LDB_FLAG_MOD_REPLACE, NULL);
2118 ret = ldb_msg_add_empty(msg, "pwdLastSet", LDB_FLAG_MOD_REPLACE, NULL);
2119 ret = ldb_msg_add_empty(msg, "msDs-KeyVersionNumber", LDB_FLAG_MOD_REPLACE, NULL);
2122 ret = samdb_msg_add_hash(ac->module->ldb, ac, msg,
2123 "unicodePwd", io.g.nt_hash);
2124 if (ret != LDB_SUCCESS) {
2129 ret = samdb_msg_add_hash(ac->module->ldb, ac, msg,
2130 "dBCSPwd", io.g.lm_hash);
2131 if (ret != LDB_SUCCESS) {
2135 if (io.g.nt_history_len > 0) {
2136 ret = samdb_msg_add_hashes(ac, msg,
2139 io.g.nt_history_len);
2140 if (ret != LDB_SUCCESS) {
2144 if (io.g.lm_history_len > 0) {
2145 ret = samdb_msg_add_hashes(ac, msg,
2148 io.g.lm_history_len);
2149 if (ret != LDB_SUCCESS) {
2153 if (io.g.supplemental.length > 0) {
2154 ret = ldb_msg_add_value(msg, "supplementalCredentials",
2155 &io.g.supplemental, NULL);
2156 if (ret != LDB_SUCCESS) {
2160 ret = samdb_msg_add_uint64(ac->module->ldb, ac, msg,
2163 if (ret != LDB_SUCCESS) {
2166 ret = samdb_msg_add_uint(ac->module->ldb, ac, msg,
2167 "msDs-KeyVersionNumber",
2169 if (ret != LDB_SUCCESS) {
2173 ret = ldb_build_mod_req(&mod_req, ac->module->ldb, ac,
2178 if (ret != LDB_SUCCESS) {
2182 return ldb_next_request(ac->module, mod_req);
2185 _PUBLIC_ const struct ldb_module_ops ldb_password_hash_module_ops = {
2186 .name = "password_hash",
2187 .add = password_hash_add,
2188 .modify = password_hash_modify,