4
Copyright (C) Simo Sorce 2004-2008
5
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2006
6
Copyright (C) Andrew Tridgell 2004
7
Copyright (C) Stefan Metzmacher 2007
9
This program is free software; you can redistribute it and/or modify
10
it under the terms of the GNU General Public License as published by
11
the Free Software Foundation; either version 3 of the License, or
12
(at your option) any later version.
14
This program is distributed in the hope that it will be useful,
15
but WITHOUT ANY WARRANTY; without even the implied warranty of
16
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
GNU General Public License for more details.
19
You should have received a copy of the GNU General Public License
20
along with this program. If not, see <http://www.gnu.org/licenses/>.
26
* Component: ldb password_hash module
28
* Description: correctly update hash values based on changes to userPassword and friends
30
* Author: Andrew Bartlett
31
* Author: Stefan Metzmacher
35
#include "libcli/ldap/ldap_ndr.h"
36
#include "ldb_module.h"
37
#include "librpc/gen_ndr/misc.h"
38
#include "librpc/gen_ndr/samr.h"
39
#include "libcli/auth/libcli_auth.h"
40
#include "libcli/security/security.h"
41
#include "system/kerberos.h"
42
#include "auth/kerberos/kerberos.h"
43
#include "system/time.h"
44
#include "dsdb/samdb/samdb.h"
45
#include "dsdb/common/flags.h"
46
#include "dsdb/samdb/ldb_modules/password_modules.h"
47
#include "librpc/ndr/libndr.h"
48
#include "librpc/gen_ndr/ndr_drsblobs.h"
49
#include "../lib/crypto/crypto.h"
50
#include "param/param.h"
52
/* If we have decided there is reason to work on this request, then
53
* setup all the password hash types correctly.
55
* If the administrator doesn't want the userPassword stored (set in the
56
* domain and per-account policies) then we must strip that out before
57
* we do the first operation.
59
* Once this is done (which could update anything at all), we
60
* calculate the password hashes.
62
* This function must not only update the unicodePwd, dBCSPwd and
63
* supplementalCredentials fields, it must also atomicly increment the
64
* msDS-KeyVersionNumber. We should be in a transaction, so all this
65
* should be quite safe...
67
* Finally, if the administrator has requested that a password history
68
* be maintained, then this should also be written out.
74
struct ldb_module *module;
75
struct ldb_request *req;
77
struct ldb_request *dom_req;
78
struct ldb_reply *dom_res;
80
struct ldb_reply *search_res;
82
struct dom_sid *domain_sid;
83
struct domain_data *domain;
89
uint_t pwdHistoryLength;
95
struct setup_password_fields_io {
96
struct ph_context *ac;
97
struct domain_data *domain;
98
struct smb_krb5_context *smb_krb5_context;
100
/* infos about the user account */
102
uint32_t user_account_control;
103
const char *sAMAccountName;
104
const char *user_principal_name;
108
/* new credentials */
110
const struct ldb_val *cleartext_utf8;
111
const struct ldb_val *cleartext_utf16;
112
struct ldb_val quoted_utf16;
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
/* Get the NT hash, and fill it in as an entry in the password history,
148
and specify it into io->g.nt_hash */
150
static int setup_nt_fields(struct setup_password_fields_io *io)
152
struct ldb_context *ldb;
155
io->g.nt_hash = io->n.nt_hash;
156
ldb = ldb_module_get_ctx(io->ac->module);
158
if (io->domain->pwdHistoryLength == 0) {
162
/* We might not have an old NT password */
163
io->g.nt_history = talloc_array(io->ac,
164
struct samr_Password,
165
io->domain->pwdHistoryLength);
166
if (!io->g.nt_history) {
168
return LDB_ERR_OPERATIONS_ERROR;
171
for (i = 0; i < MIN(io->domain->pwdHistoryLength-1, io->o.nt_history_len); i++) {
172
io->g.nt_history[i+1] = io->o.nt_history[i];
174
io->g.nt_history_len = i + 1;
177
io->g.nt_history[0] = *io->g.nt_hash;
180
* TODO: is this correct?
181
* the simular behavior is correct for the lm history case
183
E_md4hash("", io->g.nt_history[0].hash);
189
/* Get the LANMAN hash, and fill it in as an entry in the password history,
190
and specify it into io->g.lm_hash */
192
static int setup_lm_fields(struct setup_password_fields_io *io)
194
struct ldb_context *ldb;
197
io->g.lm_hash = io->n.lm_hash;
198
ldb = ldb_module_get_ctx(io->ac->module);
200
if (io->domain->pwdHistoryLength == 0) {
204
/* We might not have an old NT password */
205
io->g.lm_history = talloc_array(io->ac,
206
struct samr_Password,
207
io->domain->pwdHistoryLength);
208
if (!io->g.lm_history) {
210
return LDB_ERR_OPERATIONS_ERROR;
213
for (i = 0; i < MIN(io->domain->pwdHistoryLength-1, io->o.lm_history_len); i++) {
214
io->g.lm_history[i+1] = io->o.lm_history[i];
216
io->g.lm_history_len = i + 1;
219
io->g.lm_history[0] = *io->g.lm_hash;
221
E_deshash("", io->g.lm_history[0].hash);
227
static int setup_kerberos_keys(struct setup_password_fields_io *io)
229
struct ldb_context *ldb;
230
krb5_error_code krb5_ret;
231
Principal *salt_principal;
234
krb5_data cleartext_data;
236
ldb = ldb_module_get_ctx(io->ac->module);
237
cleartext_data.data = io->n.cleartext_utf8->data;
238
cleartext_data.length = io->n.cleartext_utf8->length;
240
/* Many, many thanks to lukeh@padl.com for this
241
* algorithm, described in his Nov 10 2004 mail to
242
* samba-technical@samba.org */
245
* Determine a salting principal
247
if (io->u.is_computer) {
251
name = talloc_strdup(io->ac, io->u.sAMAccountName);
254
return LDB_ERR_OPERATIONS_ERROR;
257
if (name[strlen(name)-1] == '$') {
258
name[strlen(name)-1] = '\0';
261
saltbody = talloc_asprintf(io->ac, "%s.%s", name, io->domain->dns_domain);
264
return LDB_ERR_OPERATIONS_ERROR;
267
krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
269
io->domain->realm, "host",
271
} else if (io->u.user_principal_name) {
272
char *user_principal_name;
275
user_principal_name = talloc_strdup(io->ac, io->u.user_principal_name);
276
if (!user_principal_name) {
278
return LDB_ERR_OPERATIONS_ERROR;
281
p = strchr(user_principal_name, '@');
286
krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
288
io->domain->realm, user_principal_name,
291
krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
293
io->domain->realm, io->u.sAMAccountName,
297
ldb_asprintf_errstring(ldb,
298
"setup_kerberos_keys: "
299
"generation of a salting principal failed: %s",
300
smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
301
return LDB_ERR_OPERATIONS_ERROR;
305
* create salt from salt_principal
307
krb5_ret = krb5_get_pw_salt(io->smb_krb5_context->krb5_context,
308
salt_principal, &salt);
309
krb5_free_principal(io->smb_krb5_context->krb5_context, salt_principal);
311
ldb_asprintf_errstring(ldb,
312
"setup_kerberos_keys: "
313
"generation of krb5_salt failed: %s",
314
smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
315
return LDB_ERR_OPERATIONS_ERROR;
317
/* create a talloc copy */
318
io->g.salt = talloc_strndup(io->ac,
320
salt.saltvalue.length);
321
krb5_free_salt(io->smb_krb5_context->krb5_context, salt);
324
return LDB_ERR_OPERATIONS_ERROR;
326
salt.saltvalue.data = discard_const(io->g.salt);
327
salt.saltvalue.length = strlen(io->g.salt);
330
* create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of
331
* the salt and the cleartext password
333
krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
334
ENCTYPE_AES256_CTS_HMAC_SHA1_96,
339
ldb_asprintf_errstring(ldb,
340
"setup_kerberos_keys: "
341
"generation of a aes256-cts-hmac-sha1-96 key failed: %s",
342
smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
343
return LDB_ERR_OPERATIONS_ERROR;
345
io->g.aes_256 = data_blob_talloc(io->ac,
347
key.keyvalue.length);
348
krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
349
if (!io->g.aes_256.data) {
351
return LDB_ERR_OPERATIONS_ERROR;
355
* create ENCTYPE_AES128_CTS_HMAC_SHA1_96 key out of
356
* the salt and the cleartext password
358
krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
359
ENCTYPE_AES128_CTS_HMAC_SHA1_96,
364
ldb_asprintf_errstring(ldb,
365
"setup_kerberos_keys: "
366
"generation of a aes128-cts-hmac-sha1-96 key failed: %s",
367
smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
368
return LDB_ERR_OPERATIONS_ERROR;
370
io->g.aes_128 = data_blob_talloc(io->ac,
372
key.keyvalue.length);
373
krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
374
if (!io->g.aes_128.data) {
376
return LDB_ERR_OPERATIONS_ERROR;
380
* create ENCTYPE_DES_CBC_MD5 key out of
381
* the salt and the cleartext password
383
krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
389
ldb_asprintf_errstring(ldb,
390
"setup_kerberos_keys: "
391
"generation of a des-cbc-md5 key failed: %s",
392
smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
393
return LDB_ERR_OPERATIONS_ERROR;
395
io->g.des_md5 = data_blob_talloc(io->ac,
397
key.keyvalue.length);
398
krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
399
if (!io->g.des_md5.data) {
401
return LDB_ERR_OPERATIONS_ERROR;
405
* create ENCTYPE_DES_CBC_CRC key out of
406
* the salt and the cleartext password
408
krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
414
ldb_asprintf_errstring(ldb,
415
"setup_kerberos_keys: "
416
"generation of a des-cbc-crc key failed: %s",
417
smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
418
return LDB_ERR_OPERATIONS_ERROR;
420
io->g.des_crc = data_blob_talloc(io->ac,
422
key.keyvalue.length);
423
krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
424
if (!io->g.des_crc.data) {
426
return LDB_ERR_OPERATIONS_ERROR;
432
static int setup_primary_kerberos(struct setup_password_fields_io *io,
433
const struct supplementalCredentialsBlob *old_scb,
434
struct package_PrimaryKerberosBlob *pkb)
436
struct ldb_context *ldb;
437
struct package_PrimaryKerberosCtr3 *pkb3 = &pkb->ctr.ctr3;
438
struct supplementalCredentialsPackage *old_scp = NULL;
439
struct package_PrimaryKerberosBlob _old_pkb;
440
struct package_PrimaryKerberosCtr3 *old_pkb3 = NULL;
442
enum ndr_err_code ndr_err;
444
ldb = ldb_module_get_ctx(io->ac->module);
447
* prepare generation of keys
449
* ENCTYPE_DES_CBC_MD5
450
* ENCTYPE_DES_CBC_CRC
453
pkb3->salt.string = io->g.salt;
455
pkb3->keys = talloc_array(io->ac,
456
struct package_PrimaryKerberosKey3,
460
return LDB_ERR_OPERATIONS_ERROR;
463
pkb3->keys[0].keytype = ENCTYPE_DES_CBC_MD5;
464
pkb3->keys[0].value = &io->g.des_md5;
465
pkb3->keys[1].keytype = ENCTYPE_DES_CBC_CRC;
466
pkb3->keys[1].value = &io->g.des_crc;
468
/* initialize the old keys to zero */
469
pkb3->num_old_keys = 0;
470
pkb3->old_keys = NULL;
472
/* if there're no old keys, then we're done */
477
for (i=0; i < old_scb->sub.num_packages; i++) {
478
if (strcmp("Primary:Kerberos", old_scb->sub.packages[i].name) != 0) {
482
if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
486
old_scp = &old_scb->sub.packages[i];
489
/* Primary:Kerberos element of supplementalCredentials */
493
blob = strhex_to_data_blob(io->ac, old_scp->data);
496
return LDB_ERR_OPERATIONS_ERROR;
499
/* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
500
ndr_err = ndr_pull_struct_blob(&blob, io->ac, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &_old_pkb,
501
(ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
502
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
503
NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
504
ldb_asprintf_errstring(ldb,
505
"setup_primary_kerberos: "
506
"failed to pull old package_PrimaryKerberosBlob: %s",
508
return LDB_ERR_OPERATIONS_ERROR;
511
if (_old_pkb.version != 3) {
512
ldb_asprintf_errstring(ldb,
513
"setup_primary_kerberos: "
514
"package_PrimaryKerberosBlob version[%u] expected[3]",
516
return LDB_ERR_OPERATIONS_ERROR;
519
old_pkb3 = &_old_pkb.ctr.ctr3;
522
/* if we didn't found the old keys we're done */
527
/* fill in the old keys */
528
pkb3->num_old_keys = old_pkb3->num_keys;
529
pkb3->old_keys = old_pkb3->keys;
534
static int setup_primary_kerberos_newer(struct setup_password_fields_io *io,
535
const struct supplementalCredentialsBlob *old_scb,
536
struct package_PrimaryKerberosBlob *pkb)
538
struct ldb_context *ldb;
539
struct package_PrimaryKerberosCtr4 *pkb4 = &pkb->ctr.ctr4;
540
struct supplementalCredentialsPackage *old_scp = NULL;
541
struct package_PrimaryKerberosBlob _old_pkb;
542
struct package_PrimaryKerberosCtr4 *old_pkb4 = NULL;
544
enum ndr_err_code ndr_err;
546
ldb = ldb_module_get_ctx(io->ac->module);
549
* prepare generation of keys
551
* ENCTYPE_AES256_CTS_HMAC_SHA1_96
552
* ENCTYPE_AES128_CTS_HMAC_SHA1_96
553
* ENCTYPE_DES_CBC_MD5
554
* ENCTYPE_DES_CBC_CRC
557
pkb4->salt.string = io->g.salt;
558
pkb4->default_iteration_count = 4096;
561
pkb4->keys = talloc_array(io->ac,
562
struct package_PrimaryKerberosKey4,
566
return LDB_ERR_OPERATIONS_ERROR;
569
pkb4->keys[0].iteration_count = 4096;
570
pkb4->keys[0].keytype = ENCTYPE_AES256_CTS_HMAC_SHA1_96;
571
pkb4->keys[0].value = &io->g.aes_256;
572
pkb4->keys[1].iteration_count = 4096;
573
pkb4->keys[1].keytype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
574
pkb4->keys[1].value = &io->g.aes_128;
575
pkb4->keys[2].iteration_count = 4096;
576
pkb4->keys[2].keytype = ENCTYPE_DES_CBC_MD5;
577
pkb4->keys[2].value = &io->g.des_md5;
578
pkb4->keys[3].iteration_count = 4096;
579
pkb4->keys[3].keytype = ENCTYPE_DES_CBC_CRC;
580
pkb4->keys[3].value = &io->g.des_crc;
582
/* initialize the old keys to zero */
583
pkb4->num_old_keys = 0;
584
pkb4->old_keys = NULL;
585
pkb4->num_older_keys = 0;
586
pkb4->older_keys = NULL;
588
/* if there're no old keys, then we're done */
593
for (i=0; i < old_scb->sub.num_packages; i++) {
594
if (strcmp("Primary:Kerberos-Newer-Keys", old_scb->sub.packages[i].name) != 0) {
598
if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
602
old_scp = &old_scb->sub.packages[i];
605
/* Primary:Kerberos-Newer-Keys element of supplementalCredentials */
609
blob = strhex_to_data_blob(io->ac, old_scp->data);
612
return LDB_ERR_OPERATIONS_ERROR;
615
/* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
616
ndr_err = ndr_pull_struct_blob(&blob, io->ac,
617
lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
619
(ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
620
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
621
NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
622
ldb_asprintf_errstring(ldb,
623
"setup_primary_kerberos_newer: "
624
"failed to pull old package_PrimaryKerberosBlob: %s",
626
return LDB_ERR_OPERATIONS_ERROR;
629
if (_old_pkb.version != 4) {
630
ldb_asprintf_errstring(ldb,
631
"setup_primary_kerberos_newer: "
632
"package_PrimaryKerberosBlob version[%u] expected[4]",
634
return LDB_ERR_OPERATIONS_ERROR;
637
old_pkb4 = &_old_pkb.ctr.ctr4;
640
/* if we didn't found the old keys we're done */
645
/* fill in the old keys */
646
pkb4->num_old_keys = old_pkb4->num_keys;
647
pkb4->old_keys = old_pkb4->keys;
648
pkb4->num_older_keys = old_pkb4->num_old_keys;
649
pkb4->older_keys = old_pkb4->old_keys;
654
static int setup_primary_wdigest(struct setup_password_fields_io *io,
655
const struct supplementalCredentialsBlob *old_scb,
656
struct package_PrimaryWDigestBlob *pdb)
658
struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
659
DATA_BLOB sAMAccountName;
660
DATA_BLOB sAMAccountName_l;
661
DATA_BLOB sAMAccountName_u;
662
const char *user_principal_name = io->u.user_principal_name;
663
DATA_BLOB userPrincipalName;
664
DATA_BLOB userPrincipalName_l;
665
DATA_BLOB userPrincipalName_u;
666
DATA_BLOB netbios_domain;
667
DATA_BLOB netbios_domain_l;
668
DATA_BLOB netbios_domain_u;
669
DATA_BLOB dns_domain;
670
DATA_BLOB dns_domain_l;
671
DATA_BLOB dns_domain_u;
683
* http://technet2.microsoft.com/WindowsServer/en/library/717b450c-f4a0-4cc9-86f4-cc0633aae5f91033.mspx?mfr=true
684
* for what precalculated hashes are supposed to be stored...
686
* I can't reproduce all values which should contain "Digest" as realm,
687
* am I doing something wrong or is w2k3 just broken...?
689
* W2K3 fills in following for a user:
691
* dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
692
* sAMAccountName: NewUser2Sam
693
* userPrincipalName: NewUser2Princ@sub1.w2k3.vmnet1.vm.base
695
* 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
696
* b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
697
* 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
698
* 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
699
* 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
700
* 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
701
* e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
702
* 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
703
* f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
704
* d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
705
* fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
706
* 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
707
* 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
708
* c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
709
* 221c55284451ae9b3aacaa2a3c86f10f => NewUser2Princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
710
* 74e1be668853d4324d38c07e2acfb8ea => (w2k3 has a bug here!) newuser2princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
711
* e1e244ab7f098e3ae1761be7f9229bbb => NEWUSER2PRINC@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
712
* 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
713
* f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
714
* 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
715
* 31dc704d3640335b2123d4ee28aa1f11 => ??? changes with NewUser2Sam => NewUser1Sam
716
* 36349f5cecd07320fb3bb0e119230c43 => ??? changes with NewUser2Sam => NewUser1Sam
717
* 12adf019d037fb535c01fd0608e78d9d => ??? changes with NewUser2Sam => NewUser1Sam
718
* 6feecf8e724906f3ee1105819c5105a1 => ??? changes with NewUser2Princ => NewUser1Princ
719
* 6c6911f3de6333422640221b9c51ff1f => ??? changes with NewUser2Princ => NewUser1Princ
720
* 4b279877e742895f9348ac67a8de2f69 => ??? changes with NewUser2Princ => NewUser1Princ
721
* db0c6bff069513e3ebb9870d29b57490 => ??? changes with NewUser2Sam => NewUser1Sam
722
* 45072621e56b1c113a4e04a8ff68cd0e => ??? changes with NewUser2Sam => NewUser1Sam
723
* 11d1220abc44a9c10cf91ef4a9c1de02 => ??? changes with NewUser2Sam => NewUser1Sam
725
* dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
726
* sAMAccountName: NewUser2Sam
728
* 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
729
* b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
730
* 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
731
* 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
732
* 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
733
* 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
734
* e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
735
* 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
736
* f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
737
* d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
738
* fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
739
* 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
740
* 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
741
* c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
742
* 8a140d30b6f0a5912735dc1e3bc993b4 => NewUser2Sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
743
* 86d95b2faae6cae4ec261e7fbaccf093 => (here w2k3 is correct) newuser2sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
744
* dfeff1493110220efcdfc6362e5f5450 => NEWUSER2SAM@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
745
* 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
746
* f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
747
* 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
748
* 31dc704d3640335b2123d4ee28aa1f11 => ???M1 changes with NewUser2Sam => NewUser1Sam
749
* 36349f5cecd07320fb3bb0e119230c43 => ???M1.L changes with newuser2sam => newuser1sam
750
* 12adf019d037fb535c01fd0608e78d9d => ???M1.U changes with NEWUSER2SAM => NEWUSER1SAM
751
* 569b4533f2d9e580211dd040e5e360a8 => ???M2 changes with NewUser2Princ => NewUser1Princ
752
* 52528bddf310a587c5d7e6a9ae2cbb20 => ???M2.L changes with newuser2princ => newuser1princ
753
* 4f629a4f0361289ca4255ab0f658fcd5 => ???M3 changes with NewUser2Princ => NewUser1Princ (doesn't depend on case of userPrincipal )
754
* db0c6bff069513e3ebb9870d29b57490 => ???M4 changes with NewUser2Sam => NewUser1Sam
755
* 45072621e56b1c113a4e04a8ff68cd0e => ???M5 changes with NewUser2Sam => NewUser1Sam (doesn't depend on case of sAMAccountName)
756
* 11d1220abc44a9c10cf91ef4a9c1de02 => ???M4.U changes with NEWUSER2SAM => NEWUSER1SAM
760
* sAMAccountName, netbios_domain
763
.user = &sAMAccountName,
764
.realm = &netbios_domain,
767
.user = &sAMAccountName_l,
768
.realm = &netbios_domain_l,
771
.user = &sAMAccountName_u,
772
.realm = &netbios_domain_u,
775
.user = &sAMAccountName,
776
.realm = &netbios_domain_u,
779
.user = &sAMAccountName,
780
.realm = &netbios_domain_l,
783
.user = &sAMAccountName_u,
784
.realm = &netbios_domain_l,
787
.user = &sAMAccountName_l,
788
.realm = &netbios_domain_u,
791
* sAMAccountName, dns_domain
794
.user = &sAMAccountName,
795
.realm = &dns_domain,
798
.user = &sAMAccountName_l,
799
.realm = &dns_domain_l,
802
.user = &sAMAccountName_u,
803
.realm = &dns_domain_u,
806
.user = &sAMAccountName,
807
.realm = &dns_domain_u,
810
.user = &sAMAccountName,
811
.realm = &dns_domain_l,
814
.user = &sAMAccountName_u,
815
.realm = &dns_domain_l,
818
.user = &sAMAccountName_l,
819
.realm = &dns_domain_u,
822
* userPrincipalName, no realm
825
.user = &userPrincipalName,
829
* NOTE: w2k3 messes this up, if the user has a real userPrincipalName,
830
* the fallback to the sAMAccountName based userPrincipalName is correct
832
.user = &userPrincipalName_l,
835
.user = &userPrincipalName_u,
838
* nt4dom\sAMAccountName, no realm
841
.user = &sAMAccountName,
842
.nt4dom = &netbios_domain
845
.user = &sAMAccountName_l,
846
.nt4dom = &netbios_domain_l
849
.user = &sAMAccountName_u,
850
.nt4dom = &netbios_domain_u
854
* the following ones are guessed depending on the technet2 article
855
* but not reproducable on a w2k3 server
857
/* sAMAccountName with "Digest" realm */
859
.user = &sAMAccountName,
863
.user = &sAMAccountName_l,
867
.user = &sAMAccountName_u,
870
/* userPrincipalName with "Digest" realm */
872
.user = &userPrincipalName,
876
.user = &userPrincipalName_l,
880
.user = &userPrincipalName_u,
883
/* nt4dom\\sAMAccountName with "Digest" realm */
885
.user = &sAMAccountName,
886
.nt4dom = &netbios_domain,
890
.user = &sAMAccountName_l,
891
.nt4dom = &netbios_domain_l,
895
.user = &sAMAccountName_u,
896
.nt4dom = &netbios_domain_u,
901
/* prepare DATA_BLOB's used in the combinations array */
902
sAMAccountName = data_blob_string_const(io->u.sAMAccountName);
903
sAMAccountName_l = data_blob_string_const(strlower_talloc(io->ac, io->u.sAMAccountName));
904
if (!sAMAccountName_l.data) {
906
return LDB_ERR_OPERATIONS_ERROR;
908
sAMAccountName_u = data_blob_string_const(strupper_talloc(io->ac, io->u.sAMAccountName));
909
if (!sAMAccountName_u.data) {
911
return LDB_ERR_OPERATIONS_ERROR;
914
/* if the user doesn't have a userPrincipalName, create one (with lower case realm) */
915
if (!user_principal_name) {
916
user_principal_name = talloc_asprintf(io->ac, "%s@%s",
917
io->u.sAMAccountName,
918
io->domain->dns_domain);
919
if (!user_principal_name) {
921
return LDB_ERR_OPERATIONS_ERROR;
924
userPrincipalName = data_blob_string_const(user_principal_name);
925
userPrincipalName_l = data_blob_string_const(strlower_talloc(io->ac, user_principal_name));
926
if (!userPrincipalName_l.data) {
928
return LDB_ERR_OPERATIONS_ERROR;
930
userPrincipalName_u = data_blob_string_const(strupper_talloc(io->ac, user_principal_name));
931
if (!userPrincipalName_u.data) {
933
return LDB_ERR_OPERATIONS_ERROR;
936
netbios_domain = data_blob_string_const(io->domain->netbios_domain);
937
netbios_domain_l = data_blob_string_const(strlower_talloc(io->ac, io->domain->netbios_domain));
938
if (!netbios_domain_l.data) {
940
return LDB_ERR_OPERATIONS_ERROR;
942
netbios_domain_u = data_blob_string_const(strupper_talloc(io->ac, io->domain->netbios_domain));
943
if (!netbios_domain_u.data) {
945
return LDB_ERR_OPERATIONS_ERROR;
948
dns_domain = data_blob_string_const(io->domain->dns_domain);
949
dns_domain_l = data_blob_string_const(io->domain->dns_domain);
950
dns_domain_u = data_blob_string_const(io->domain->realm);
952
digest = data_blob_string_const("Digest");
954
delim = data_blob_string_const(":");
955
backslash = data_blob_string_const("\\");
957
pdb->num_hashes = ARRAY_SIZE(wdigest);
958
pdb->hashes = talloc_array(io->ac, struct package_PrimaryWDigestHash, pdb->num_hashes);
961
return LDB_ERR_OPERATIONS_ERROR;
964
for (i=0; i < ARRAY_SIZE(wdigest); i++) {
965
struct MD5Context md5;
967
if (wdigest[i].nt4dom) {
968
MD5Update(&md5, wdigest[i].nt4dom->data, wdigest[i].nt4dom->length);
969
MD5Update(&md5, backslash.data, backslash.length);
971
MD5Update(&md5, wdigest[i].user->data, wdigest[i].user->length);
972
MD5Update(&md5, delim.data, delim.length);
973
if (wdigest[i].realm) {
974
MD5Update(&md5, wdigest[i].realm->data, wdigest[i].realm->length);
976
MD5Update(&md5, delim.data, delim.length);
977
MD5Update(&md5, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length);
978
MD5Final(pdb->hashes[i].hash, &md5);
984
static int setup_supplemental_field(struct setup_password_fields_io *io)
986
struct ldb_context *ldb;
987
struct supplementalCredentialsBlob scb;
988
struct supplementalCredentialsBlob _old_scb;
989
struct supplementalCredentialsBlob *old_scb = NULL;
990
/* Packages + (Kerberos-Newer-Keys, Kerberos, WDigest and CLEARTEXT) */
991
uint32_t num_names = 0;
992
const char *names[1+4];
993
uint32_t num_packages = 0;
994
struct supplementalCredentialsPackage packages[1+4];
996
struct supplementalCredentialsPackage *pp = NULL;
997
struct package_PackagesBlob pb;
1000
/* Primary:Kerberos-Newer-Keys */
1001
const char **nkn = NULL;
1002
struct supplementalCredentialsPackage *pkn = NULL;
1003
struct package_PrimaryKerberosBlob pknb;
1004
DATA_BLOB pknb_blob;
1006
/* Primary:Kerberos */
1007
const char **nk = NULL;
1008
struct supplementalCredentialsPackage *pk = NULL;
1009
struct package_PrimaryKerberosBlob pkb;
1012
/* Primary:WDigest */
1013
const char **nd = NULL;
1014
struct supplementalCredentialsPackage *pd = NULL;
1015
struct package_PrimaryWDigestBlob pdb;
1018
/* Primary:CLEARTEXT */
1019
const char **nc = NULL;
1020
struct supplementalCredentialsPackage *pc = NULL;
1021
struct package_PrimaryCLEARTEXTBlob pcb;
1025
enum ndr_err_code ndr_err;
1027
bool do_newer_keys = false;
1028
bool do_cleartext = false;
1030
ZERO_STRUCT(zero16);
1033
ldb = ldb_module_get_ctx(io->ac->module);
1035
if (!io->n.cleartext_utf8) {
1037
* when we don't have a cleartext password
1038
* we can't setup a supplementalCredential value
1043
/* if there's an old supplementaCredentials blob then parse it */
1044
if (io->o.supplemental) {
1045
ndr_err = ndr_pull_struct_blob_all(io->o.supplemental, io->ac,
1046
lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1048
(ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
1049
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1050
NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1051
ldb_asprintf_errstring(ldb,
1052
"setup_supplemental_field: "
1053
"failed to pull old supplementalCredentialsBlob: %s",
1055
return LDB_ERR_OPERATIONS_ERROR;
1058
if (_old_scb.sub.signature == SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
1059
old_scb = &_old_scb;
1061
ldb_debug(ldb, LDB_DEBUG_ERROR,
1062
"setup_supplemental_field: "
1063
"supplementalCredentialsBlob signature[0x%04X] expected[0x%04X]",
1064
_old_scb.sub.signature, SUPPLEMENTAL_CREDENTIALS_SIGNATURE);
1068
/* TODO: do the correct check for this, it maybe depends on the functional level? */
1069
do_newer_keys = lp_parm_bool(ldb_get_opaque(ldb, "loadparm"),
1070
NULL, "password_hash", "create_aes_key", false);
1072
if (io->domain->store_cleartext &&
1073
(io->u.user_account_control & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) {
1074
do_cleartext = true;
1078
* The ordering is this
1080
* Primary:Kerberos-Newer-Keys (optional)
1083
* Primary:CLEARTEXT (optional)
1085
* And the 'Packages' package is insert before the last
1088
if (do_newer_keys) {
1089
/* Primary:Kerberos-Newer-Keys */
1090
nkn = &names[num_names++];
1091
pkn = &packages[num_packages++];
1094
/* Primary:Kerberos */
1095
nk = &names[num_names++];
1096
pk = &packages[num_packages++];
1098
if (!do_cleartext) {
1100
pp = &packages[num_packages++];
1103
/* Primary:WDigest */
1104
nd = &names[num_names++];
1105
pd = &packages[num_packages++];
1109
pp = &packages[num_packages++];
1111
/* Primary:CLEARTEXT */
1112
nc = &names[num_names++];
1113
pc = &packages[num_packages++];
1118
* setup 'Primary:Kerberos-Newer-Keys' element
1120
*nkn = "Kerberos-Newer-Keys";
1122
ret = setup_primary_kerberos_newer(io, old_scb, &pknb);
1123
if (ret != LDB_SUCCESS) {
1127
ndr_err = ndr_push_struct_blob(&pknb_blob, io->ac,
1128
lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1130
(ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1131
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1132
NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1133
ldb_asprintf_errstring(ldb,
1134
"setup_supplemental_field: "
1135
"failed to push package_PrimaryKerberosNeverBlob: %s",
1137
return LDB_ERR_OPERATIONS_ERROR;
1139
pknb_hexstr = data_blob_hex_string(io->ac, &pknb_blob);
1142
return LDB_ERR_OPERATIONS_ERROR;
1144
pkn->name = "Primary:Kerberos-Newer-Keys";
1146
pkn->data = pknb_hexstr;
1150
* setup 'Primary:Kerberos' element
1154
ret = setup_primary_kerberos(io, old_scb, &pkb);
1155
if (ret != LDB_SUCCESS) {
1159
ndr_err = ndr_push_struct_blob(&pkb_blob, io->ac,
1160
lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1162
(ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1163
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1164
NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1165
ldb_asprintf_errstring(ldb,
1166
"setup_supplemental_field: "
1167
"failed to push package_PrimaryKerberosBlob: %s",
1169
return LDB_ERR_OPERATIONS_ERROR;
1171
pkb_hexstr = data_blob_hex_string(io->ac, &pkb_blob);
1174
return LDB_ERR_OPERATIONS_ERROR;
1176
pk->name = "Primary:Kerberos";
1178
pk->data = pkb_hexstr;
1181
* setup 'Primary:WDigest' element
1185
ret = setup_primary_wdigest(io, old_scb, &pdb);
1186
if (ret != LDB_SUCCESS) {
1190
ndr_err = ndr_push_struct_blob(&pdb_blob, io->ac,
1191
lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1193
(ndr_push_flags_fn_t)ndr_push_package_PrimaryWDigestBlob);
1194
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1195
NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1196
ldb_asprintf_errstring(ldb,
1197
"setup_supplemental_field: "
1198
"failed to push package_PrimaryWDigestBlob: %s",
1200
return LDB_ERR_OPERATIONS_ERROR;
1202
pdb_hexstr = data_blob_hex_string(io->ac, &pdb_blob);
1205
return LDB_ERR_OPERATIONS_ERROR;
1207
pd->name = "Primary:WDigest";
1209
pd->data = pdb_hexstr;
1212
* setup 'Primary:CLEARTEXT' element
1217
pcb.cleartext = *io->n.cleartext_utf16;
1219
ndr_err = ndr_push_struct_blob(&pcb_blob, io->ac,
1220
lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1222
(ndr_push_flags_fn_t)ndr_push_package_PrimaryCLEARTEXTBlob);
1223
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1224
NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1225
ldb_asprintf_errstring(ldb,
1226
"setup_supplemental_field: "
1227
"failed to push package_PrimaryCLEARTEXTBlob: %s",
1229
return LDB_ERR_OPERATIONS_ERROR;
1231
pcb_hexstr = data_blob_hex_string(io->ac, &pcb_blob);
1234
return LDB_ERR_OPERATIONS_ERROR;
1236
pc->name = "Primary:CLEARTEXT";
1238
pc->data = pcb_hexstr;
1242
* setup 'Packages' element
1245
ndr_err = ndr_push_struct_blob(&pb_blob, io->ac,
1246
lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1248
(ndr_push_flags_fn_t)ndr_push_package_PackagesBlob);
1249
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1250
NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1251
ldb_asprintf_errstring(ldb,
1252
"setup_supplemental_field: "
1253
"failed to push package_PackagesBlob: %s",
1255
return LDB_ERR_OPERATIONS_ERROR;
1257
pb_hexstr = data_blob_hex_string(io->ac, &pb_blob);
1260
return LDB_ERR_OPERATIONS_ERROR;
1262
pp->name = "Packages";
1264
pp->data = pb_hexstr;
1267
* setup 'supplementalCredentials' value
1270
scb.sub.num_packages = num_packages;
1271
scb.sub.packages = packages;
1273
ndr_err = ndr_push_struct_blob(&io->g.supplemental, io->ac,
1274
lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1276
(ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
1277
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1278
NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1279
ldb_asprintf_errstring(ldb,
1280
"setup_supplemental_field: "
1281
"failed to push supplementalCredentialsBlob: %s",
1283
return LDB_ERR_OPERATIONS_ERROR;
1289
static int setup_last_set_field(struct setup_password_fields_io *io)
1292
unix_to_nt_time(&io->g.last_set, time(NULL));
1297
static int setup_kvno_field(struct setup_password_fields_io *io)
1299
/* increment by one */
1300
io->g.kvno = io->o.kvno + 1;
1305
static int setup_password_fields(struct setup_password_fields_io *io)
1307
struct ldb_context *ldb;
1310
size_t converted_pw_len;
1312
ldb = ldb_module_get_ctx(io->ac->module);
1315
* refuse the change if someone want to change the cleartext
1316
* and supply his own hashes at the same time...
1318
if ((io->n.cleartext_utf8 || io->n.cleartext_utf16) && (io->n.nt_hash || io->n.lm_hash)) {
1319
ldb_asprintf_errstring(ldb,
1320
"setup_password_fields: "
1321
"it's only allowed to set the cleartext password or the password hashes");
1322
return LDB_ERR_UNWILLING_TO_PERFORM;
1325
if (io->n.cleartext_utf8 && io->n.cleartext_utf16) {
1326
ldb_asprintf_errstring(ldb,
1327
"setup_password_fields: "
1328
"it's only allowed to set the cleartext password as userPassword or clearTextPasssword, not both at once");
1329
return LDB_ERR_UNWILLING_TO_PERFORM;
1332
if (io->n.cleartext_utf8) {
1333
char **cleartext_utf16_str;
1334
struct ldb_val *cleartext_utf16_blob;
1335
io->n.cleartext_utf16 = cleartext_utf16_blob = talloc(io->ac, struct ldb_val);
1336
if (!io->n.cleartext_utf16) {
1338
return LDB_ERR_OPERATIONS_ERROR;
1340
if (!convert_string_talloc_convenience(io->ac, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1341
CH_UTF8, CH_UTF16, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length,
1342
(void **)&cleartext_utf16_str, &converted_pw_len, false)) {
1343
ldb_asprintf_errstring(ldb,
1344
"setup_password_fields: "
1345
"failed to generate UTF16 password from cleartext UTF8 password");
1346
return LDB_ERR_OPERATIONS_ERROR;
1348
*cleartext_utf16_blob = data_blob_const(cleartext_utf16_str, converted_pw_len);
1349
} else if (io->n.cleartext_utf16) {
1350
char *cleartext_utf8_str;
1351
struct ldb_val *cleartext_utf8_blob;
1352
io->n.cleartext_utf8 = cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
1353
if (!io->n.cleartext_utf8) {
1355
return LDB_ERR_OPERATIONS_ERROR;
1357
if (!convert_string_talloc_convenience(io->ac, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1358
CH_UTF16MUNGED, CH_UTF8, io->n.cleartext_utf16->data, io->n.cleartext_utf16->length,
1359
(void **)&cleartext_utf8_str, &converted_pw_len, false)) {
1360
/* We can't bail out entirely, as these unconvertable passwords are frustratingly valid */
1361
io->n.cleartext_utf8 = NULL;
1362
talloc_free(cleartext_utf8_blob);
1364
*cleartext_utf8_blob = data_blob_const(cleartext_utf8_str, converted_pw_len);
1366
if (io->n.cleartext_utf16) {
1367
struct samr_Password *nt_hash;
1368
nt_hash = talloc(io->ac, struct samr_Password);
1371
return LDB_ERR_OPERATIONS_ERROR;
1373
io->n.nt_hash = nt_hash;
1375
/* compute the new nt hash */
1376
mdfour(nt_hash->hash, io->n.cleartext_utf16->data, io->n.cleartext_utf16->length);
1379
if (io->n.cleartext_utf8) {
1380
struct samr_Password *lm_hash;
1381
char *cleartext_unix;
1382
if (convert_string_talloc_convenience(io->ac, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1383
CH_UTF8, CH_UNIX, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length,
1384
(void **)&cleartext_unix, &converted_pw_len, false)) {
1385
lm_hash = talloc(io->ac, struct samr_Password);
1388
return LDB_ERR_OPERATIONS_ERROR;
1391
/* compute the new lm hash. */
1392
ok = E_deshash((char *)cleartext_unix, lm_hash->hash);
1394
io->n.lm_hash = lm_hash;
1396
talloc_free(lm_hash->hash);
1400
ret = setup_kerberos_keys(io);
1406
ret = setup_nt_fields(io);
1411
ret = setup_lm_fields(io);
1416
ret = setup_supplemental_field(io);
1421
ret = setup_last_set_field(io);
1426
ret = setup_kvno_field(io);
1434
static struct ph_context *ph_init_context(struct ldb_module *module,
1435
struct ldb_request *req)
1437
struct ldb_context *ldb;
1438
struct ph_context *ac;
1440
ldb = ldb_module_get_ctx(module);
1442
ac = talloc_zero(req, struct ph_context);
1444
ldb_set_errstring(ldb, "Out of Memory");
1448
ac->module = module;
1454
static int ph_op_callback(struct ldb_request *req, struct ldb_reply *ares)
1456
struct ph_context *ac;
1458
ac = talloc_get_type(req->context, struct ph_context);
1461
return ldb_module_done(ac->req, NULL, NULL,
1462
LDB_ERR_OPERATIONS_ERROR);
1464
if (ares->error != LDB_SUCCESS) {
1465
return ldb_module_done(ac->req, ares->controls,
1466
ares->response, ares->error);
1469
if (ares->type != LDB_REPLY_DONE) {
1471
return ldb_module_done(ac->req, NULL, NULL,
1472
LDB_ERR_OPERATIONS_ERROR);
1475
return ldb_module_done(ac->req, ares->controls,
1476
ares->response, ares->error);
1479
static int password_hash_add_do_add(struct ph_context *ac);
1480
static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares);
1481
static int password_hash_mod_search_self(struct ph_context *ac);
1482
static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares);
1483
static int password_hash_mod_do_mod(struct ph_context *ac);
1485
static int get_domain_data_callback(struct ldb_request *req,
1486
struct ldb_reply *ares)
1488
struct ldb_context *ldb;
1489
struct domain_data *data;
1490
struct ph_context *ac;
1495
ac = talloc_get_type(req->context, struct ph_context);
1496
ldb = ldb_module_get_ctx(ac->module);
1499
return ldb_module_done(ac->req, NULL, NULL,
1500
LDB_ERR_OPERATIONS_ERROR);
1502
if (ares->error != LDB_SUCCESS) {
1503
return ldb_module_done(ac->req, ares->controls,
1504
ares->response, ares->error);
1507
switch (ares->type) {
1508
case LDB_REPLY_ENTRY:
1509
if (ac->domain != NULL) {
1510
ldb_set_errstring(ldb, "Too many results");
1511
return ldb_module_done(ac->req, NULL, NULL,
1512
LDB_ERR_OPERATIONS_ERROR);
1515
data = talloc_zero(ac, struct domain_data);
1517
return ldb_module_done(ac->req, NULL, NULL,
1518
LDB_ERR_OPERATIONS_ERROR);
1521
data->pwdProperties = samdb_result_uint(ares->message, "pwdProperties", 0);
1522
data->store_cleartext = data->pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
1523
data->pwdHistoryLength = samdb_result_uint(ares->message, "pwdHistoryLength", 0);
1525
/* For a domain DN, this puts things in dotted notation */
1526
/* For builtin domains, this will give details for the host,
1527
* but that doesn't really matter, as it's just used for salt
1528
* and kerberos principals, which don't exist here */
1530
tmp = ldb_dn_canonical_string(data, ares->message->dn);
1532
return ldb_module_done(ac->req, NULL, NULL,
1533
LDB_ERR_OPERATIONS_ERROR);
1536
/* But it puts a trailing (or just before 'builtin') / on things, so kill that */
1537
p = strchr(tmp, '/');
1542
data->dns_domain = strlower_talloc(data, tmp);
1543
if (data->dns_domain == NULL) {
1545
return ldb_module_done(ac->req, NULL, NULL,
1546
LDB_ERR_OPERATIONS_ERROR);
1548
data->realm = strupper_talloc(data, tmp);
1549
if (data->realm == NULL) {
1551
return ldb_module_done(ac->req, NULL, NULL,
1552
LDB_ERR_OPERATIONS_ERROR);
1554
/* FIXME: NetbIOS name is *always* the first domain component ?? -SSS */
1555
p = strchr(tmp, '.');
1559
data->netbios_domain = strupper_talloc(data, tmp);
1560
if (data->netbios_domain == NULL) {
1562
return ldb_module_done(ac->req, NULL, NULL,
1563
LDB_ERR_OPERATIONS_ERROR);
1570
case LDB_REPLY_DONE:
1572
/* call the next step */
1573
switch (ac->req->operation) {
1575
ret = password_hash_add_do_add(ac);
1579
ret = password_hash_mod_do_mod(ac);
1583
ret = LDB_ERR_OPERATIONS_ERROR;
1586
if (ret != LDB_SUCCESS) {
1587
return ldb_module_done(ac->req, NULL, NULL, ret);
1590
case LDB_REPLY_REFERRAL:
1599
static int build_domain_data_request(struct ph_context *ac)
1601
/* attrs[] is returned from this function in
1602
ac->dom_req->op.search.attrs, so it must be static, as
1603
otherwise the compiler can put it on the stack */
1604
struct ldb_context *ldb;
1605
static const char * const attrs[] = { "pwdProperties", "pwdHistoryLength", NULL };
1608
ldb = ldb_module_get_ctx(ac->module);
1610
filter = talloc_asprintf(ac,
1611
"(&(objectSid=%s)(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain)))",
1612
ldap_encode_ndr_dom_sid(ac, ac->domain_sid));
1613
if (filter == NULL) {
1615
return LDB_ERR_OPERATIONS_ERROR;
1618
return ldb_build_search_req(&ac->dom_req, ldb, ac,
1619
ldb_get_default_basedn(ldb),
1623
ac, get_domain_data_callback,
1627
static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
1629
struct ldb_context *ldb;
1630
struct ph_context *ac;
1631
struct ldb_message_element *sambaAttr;
1632
struct ldb_message_element *clearTextPasswordAttr;
1633
struct ldb_message_element *ntAttr;
1634
struct ldb_message_element *lmAttr;
1637
ldb = ldb_module_get_ctx(module);
1639
ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add\n");
1641
if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
1642
return ldb_next_request(module, req);
1645
/* If the caller is manipulating the local passwords directly, let them pass */
1646
if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
1647
req->op.add.message->dn) == 0) {
1648
return ldb_next_request(module, req);
1651
/* nobody must touch these fields */
1652
if (ldb_msg_find_element(req->op.add.message, "ntPwdHistory")) {
1653
return LDB_ERR_UNWILLING_TO_PERFORM;
1655
if (ldb_msg_find_element(req->op.add.message, "lmPwdHistory")) {
1656
return LDB_ERR_UNWILLING_TO_PERFORM;
1658
if (ldb_msg_find_element(req->op.add.message, "supplementalCredentials")) {
1659
return LDB_ERR_UNWILLING_TO_PERFORM;
1662
/* If no part of this ADD touches the userPassword, or the NT
1663
* or LM hashes, then we don't need to make any changes. */
1665
sambaAttr = ldb_msg_find_element(req->op.mod.message, "userPassword");
1666
clearTextPasswordAttr = ldb_msg_find_element(req->op.mod.message, "clearTextPassword");
1667
ntAttr = ldb_msg_find_element(req->op.mod.message, "unicodePwd");
1668
lmAttr = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
1670
if ((!sambaAttr) && (!clearTextPasswordAttr) && (!ntAttr) && (!lmAttr)) {
1671
return ldb_next_request(module, req);
1674
/* if it is not an entry of type person its an error */
1675
/* TODO: remove this when userPassword will be in schema */
1676
if (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "person")) {
1677
ldb_set_errstring(ldb, "Cannot set a password on entry that does not have objectClass 'person'");
1678
return LDB_ERR_OBJECT_CLASS_VIOLATION;
1681
/* check userPassword is single valued here */
1682
/* TODO: remove this when userPassword will be single valued in schema */
1683
if (sambaAttr && sambaAttr->num_values > 1) {
1684
ldb_set_errstring(ldb, "mupltiple values for userPassword not allowed!\n");
1685
return LDB_ERR_CONSTRAINT_VIOLATION;
1687
if (clearTextPasswordAttr && clearTextPasswordAttr->num_values > 1) {
1688
ldb_set_errstring(ldb, "mupltiple values for clearTextPassword not allowed!\n");
1689
return LDB_ERR_CONSTRAINT_VIOLATION;
1692
if (ntAttr && (ntAttr->num_values > 1)) {
1693
ldb_set_errstring(ldb, "mupltiple values for unicodePwd not allowed!\n");
1694
return LDB_ERR_CONSTRAINT_VIOLATION;
1696
if (lmAttr && (lmAttr->num_values > 1)) {
1697
ldb_set_errstring(ldb, "mupltiple values for dBCSPwd not allowed!\n");
1698
return LDB_ERR_CONSTRAINT_VIOLATION;
1701
if (sambaAttr && sambaAttr->num_values == 0) {
1702
ldb_set_errstring(ldb, "userPassword must have a value!\n");
1703
return LDB_ERR_CONSTRAINT_VIOLATION;
1706
if (clearTextPasswordAttr && clearTextPasswordAttr->num_values == 0) {
1707
ldb_set_errstring(ldb, "clearTextPassword must have a value!\n");
1708
return LDB_ERR_CONSTRAINT_VIOLATION;
1711
if (ntAttr && (ntAttr->num_values == 0)) {
1712
ldb_set_errstring(ldb, "unicodePwd must have a value!\n");
1713
return LDB_ERR_CONSTRAINT_VIOLATION;
1715
if (lmAttr && (lmAttr->num_values == 0)) {
1716
ldb_set_errstring(ldb, "dBCSPwd must have a value!\n");
1717
return LDB_ERR_CONSTRAINT_VIOLATION;
1720
ac = ph_init_context(module, req);
1722
return LDB_ERR_OPERATIONS_ERROR;
1725
/* get user domain data */
1726
ac->domain_sid = samdb_result_sid_prefix(ac, req->op.add.message, "objectSid");
1727
if (ac->domain_sid == NULL) {
1728
ldb_debug(ldb, LDB_DEBUG_ERROR,
1729
"can't handle entry with missing objectSid!\n");
1730
return LDB_ERR_OPERATIONS_ERROR;
1733
ret = build_domain_data_request(ac);
1734
if (ret != LDB_SUCCESS) {
1738
return ldb_next_request(module, ac->dom_req);
1741
static int password_hash_add_do_add(struct ph_context *ac)
1743
struct ldb_context *ldb;
1744
struct ldb_request *down_req;
1745
struct smb_krb5_context *smb_krb5_context;
1746
struct ldb_message *msg;
1747
struct setup_password_fields_io io;
1750
ldb = ldb_module_get_ctx(ac->module);
1752
msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
1754
return LDB_ERR_OPERATIONS_ERROR;
1757
/* Some operations below require kerberos contexts */
1758
if (smb_krb5_init_context(ac,
1759
ldb_get_event_context(ldb),
1760
(struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"),
1761
&smb_krb5_context) != 0) {
1762
return LDB_ERR_OPERATIONS_ERROR;
1767
io.domain = ac->domain;
1768
io.smb_krb5_context = smb_krb5_context;
1770
io.u.user_account_control = samdb_result_uint(msg, "userAccountControl", 0);
1771
io.u.sAMAccountName = samdb_result_string(msg, "samAccountName", NULL);
1772
io.u.user_principal_name = samdb_result_string(msg, "userPrincipalName", NULL);
1773
io.u.is_computer = ldb_msg_check_string_attribute(msg, "objectClass", "computer");
1775
io.n.cleartext_utf8 = ldb_msg_find_ldb_val(msg, "userPassword");
1776
io.n.cleartext_utf16 = ldb_msg_find_ldb_val(msg, "clearTextPassword");
1777
io.n.nt_hash = samdb_result_hash(io.ac, msg, "unicodePwd");
1778
io.n.lm_hash = samdb_result_hash(io.ac, msg, "dBCSPwd");
1780
/* remove attributes */
1781
if (io.n.cleartext_utf8) ldb_msg_remove_attr(msg, "userPassword");
1782
if (io.n.cleartext_utf16) ldb_msg_remove_attr(msg, "clearTextPassword");
1783
if (io.n.nt_hash) ldb_msg_remove_attr(msg, "unicodePwd");
1784
if (io.n.lm_hash) ldb_msg_remove_attr(msg, "dBCSPwd");
1785
ldb_msg_remove_attr(msg, "pwdLastSet");
1786
io.o.kvno = samdb_result_uint(msg, "msDs-KeyVersionNumber", 1) - 1;
1787
ldb_msg_remove_attr(msg, "msDs-KeyVersionNumber");
1789
ret = setup_password_fields(&io);
1790
if (ret != LDB_SUCCESS) {
1795
ret = samdb_msg_add_hash(ldb, ac, msg,
1796
"unicodePwd", io.g.nt_hash);
1797
if (ret != LDB_SUCCESS) {
1802
ret = samdb_msg_add_hash(ldb, ac, msg,
1803
"dBCSPwd", io.g.lm_hash);
1804
if (ret != LDB_SUCCESS) {
1808
if (io.g.nt_history_len > 0) {
1809
ret = samdb_msg_add_hashes(ac, msg,
1812
io.g.nt_history_len);
1813
if (ret != LDB_SUCCESS) {
1817
if (io.g.lm_history_len > 0) {
1818
ret = samdb_msg_add_hashes(ac, msg,
1821
io.g.lm_history_len);
1822
if (ret != LDB_SUCCESS) {
1826
if (io.g.supplemental.length > 0) {
1827
ret = ldb_msg_add_value(msg, "supplementalCredentials",
1828
&io.g.supplemental, NULL);
1829
if (ret != LDB_SUCCESS) {
1833
ret = samdb_msg_add_uint64(ldb, ac, msg,
1836
if (ret != LDB_SUCCESS) {
1839
ret = samdb_msg_add_uint(ldb, ac, msg,
1840
"msDs-KeyVersionNumber",
1842
if (ret != LDB_SUCCESS) {
1846
ret = ldb_build_add_req(&down_req, ldb, ac,
1851
if (ret != LDB_SUCCESS) {
1855
return ldb_next_request(ac->module, down_req);
1858
static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
1860
struct ldb_context *ldb;
1861
struct ph_context *ac;
1862
struct ldb_message_element *sambaAttr;
1863
struct ldb_message_element *clearTextAttr;
1864
struct ldb_message_element *ntAttr;
1865
struct ldb_message_element *lmAttr;
1866
struct ldb_message *msg;
1867
struct ldb_request *down_req;
1870
ldb = ldb_module_get_ctx(module);
1872
ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
1874
if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
1875
return ldb_next_request(module, req);
1878
/* If the caller is manipulating the local passwords directly, let them pass */
1879
if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
1880
req->op.mod.message->dn) == 0) {
1881
return ldb_next_request(module, req);
1884
/* nobody must touch password Histories */
1885
if (ldb_msg_find_element(req->op.add.message, "ntPwdHistory")) {
1886
return LDB_ERR_UNWILLING_TO_PERFORM;
1888
if (ldb_msg_find_element(req->op.add.message, "lmPwdHistory")) {
1889
return LDB_ERR_UNWILLING_TO_PERFORM;
1891
if (ldb_msg_find_element(req->op.add.message, "supplementalCredentials")) {
1892
return LDB_ERR_UNWILLING_TO_PERFORM;
1895
sambaAttr = ldb_msg_find_element(req->op.mod.message, "userPassword");
1896
clearTextAttr = ldb_msg_find_element(req->op.mod.message, "clearTextPassword");
1897
ntAttr = ldb_msg_find_element(req->op.mod.message, "unicodePwd");
1898
lmAttr = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
1900
/* If no part of this touches the userPassword OR
1901
* clearTextPassword OR unicodePwd and/or dBCSPwd, then we
1902
* don't need to make any changes. For password changes/set
1903
* there should be a 'delete' or a 'modify' on this
1905
if ((!sambaAttr) && (!clearTextAttr) && (!ntAttr) && (!lmAttr)) {
1906
return ldb_next_request(module, req);
1909
/* check passwords are single valued here */
1910
/* TODO: remove this when passwords will be single valued in schema */
1911
if (sambaAttr && (sambaAttr->num_values > 1)) {
1912
return LDB_ERR_CONSTRAINT_VIOLATION;
1914
if (clearTextAttr && (clearTextAttr->num_values > 1)) {
1915
return LDB_ERR_CONSTRAINT_VIOLATION;
1917
if (ntAttr && (ntAttr->num_values > 1)) {
1918
return LDB_ERR_CONSTRAINT_VIOLATION;
1920
if (lmAttr && (lmAttr->num_values > 1)) {
1921
return LDB_ERR_CONSTRAINT_VIOLATION;
1924
ac = ph_init_context(module, req);
1926
return LDB_ERR_OPERATIONS_ERROR;
1929
/* use a new message structure so that we can modify it */
1930
msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
1933
return LDB_ERR_OPERATIONS_ERROR;
1936
/* - remove any modification to the password from the first commit
1937
* we will make the real modification later */
1938
if (sambaAttr) ldb_msg_remove_attr(msg, "userPassword");
1939
if (clearTextAttr) ldb_msg_remove_attr(msg, "clearTextPassword");
1940
if (ntAttr) ldb_msg_remove_attr(msg, "unicodePwd");
1941
if (lmAttr) ldb_msg_remove_attr(msg, "dBCSPwd");
1943
/* if there was nothing else to be modified skip to next step */
1944
if (msg->num_elements == 0) {
1945
return password_hash_mod_search_self(ac);
1948
ret = ldb_build_mod_req(&down_req, ldb, ac,
1951
ac, ph_modify_callback,
1953
if (ret != LDB_SUCCESS) {
1957
return ldb_next_request(module, down_req);
1960
static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
1962
struct ph_context *ac;
1965
ac = talloc_get_type(req->context, struct ph_context);
1968
return ldb_module_done(ac->req, NULL, NULL,
1969
LDB_ERR_OPERATIONS_ERROR);
1971
if (ares->error != LDB_SUCCESS) {
1972
return ldb_module_done(ac->req, ares->controls,
1973
ares->response, ares->error);
1976
if (ares->type != LDB_REPLY_DONE) {
1978
return ldb_module_done(ac->req, NULL, NULL,
1979
LDB_ERR_OPERATIONS_ERROR);
1982
ret = password_hash_mod_search_self(ac);
1983
if (ret != LDB_SUCCESS) {
1984
return ldb_module_done(ac->req, NULL, NULL, ret);
1991
static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
1993
struct ldb_context *ldb;
1994
struct ph_context *ac;
1997
ac = talloc_get_type(req->context, struct ph_context);
1998
ldb = ldb_module_get_ctx(ac->module);
2001
return ldb_module_done(ac->req, NULL, NULL,
2002
LDB_ERR_OPERATIONS_ERROR);
2004
if (ares->error != LDB_SUCCESS) {
2005
return ldb_module_done(ac->req, ares->controls,
2006
ares->response, ares->error);
2009
/* we are interested only in the single reply (base search) */
2010
switch (ares->type) {
2011
case LDB_REPLY_ENTRY:
2013
if (ac->search_res != NULL) {
2014
ldb_set_errstring(ldb, "Too many results");
2016
return ldb_module_done(ac->req, NULL, NULL,
2017
LDB_ERR_OPERATIONS_ERROR);
2020
/* if it is not an entry of type person this is an error */
2021
/* TODO: remove this when sambaPassword will be in schema */
2022
if (!ldb_msg_check_string_attribute(ares->message, "objectClass", "person")) {
2023
ldb_set_errstring(ldb, "Object class violation");
2025
return ldb_module_done(ac->req, NULL, NULL,
2026
LDB_ERR_OBJECT_CLASS_VIOLATION);
2029
ac->search_res = talloc_steal(ac, ares);
2032
case LDB_REPLY_DONE:
2034
/* get object domain sid */
2035
ac->domain_sid = samdb_result_sid_prefix(ac,
2036
ac->search_res->message,
2038
if (ac->domain_sid == NULL) {
2039
ldb_debug(ldb, LDB_DEBUG_ERROR,
2040
"can't handle entry without objectSid!\n");
2041
return ldb_module_done(ac->req, NULL, NULL,
2042
LDB_ERR_OPERATIONS_ERROR);
2045
/* get user domain data */
2046
ret = build_domain_data_request(ac);
2047
if (ret != LDB_SUCCESS) {
2048
return ldb_module_done(ac->req, NULL, NULL,ret);
2051
return ldb_next_request(ac->module, ac->dom_req);
2053
case LDB_REPLY_REFERRAL:
2054
/*ignore anything else for now */
2062
static int password_hash_mod_search_self(struct ph_context *ac)
2064
struct ldb_context *ldb;
2065
static const char * const attrs[] = { "userAccountControl", "lmPwdHistory",
2067
"objectSid", "msDS-KeyVersionNumber",
2068
"objectClass", "userPrincipalName",
2070
"dBCSPwd", "unicodePwd",
2071
"supplementalCredentials",
2073
struct ldb_request *search_req;
2076
ldb = ldb_module_get_ctx(ac->module);
2078
ret = ldb_build_search_req(&search_req, ldb, ac,
2079
ac->req->op.mod.message->dn,
2084
ac, ph_mod_search_callback,
2087
if (ret != LDB_SUCCESS) {
2091
return ldb_next_request(ac->module, search_req);
2094
static int password_hash_mod_do_mod(struct ph_context *ac)
2096
struct ldb_context *ldb;
2097
struct ldb_request *mod_req;
2098
struct smb_krb5_context *smb_krb5_context;
2099
struct ldb_message *msg;
2100
struct ldb_message *orig_msg;
2101
struct ldb_message *searched_msg;
2102
struct setup_password_fields_io io;
2103
const struct ldb_val *quoted_utf16;
2106
ldb = ldb_module_get_ctx(ac->module);
2108
/* use a new message structure so that we can modify it */
2109
msg = ldb_msg_new(ac);
2111
return LDB_ERR_OPERATIONS_ERROR;
2115
msg->dn = ac->req->op.mod.message->dn;
2117
/* Some operations below require kerberos contexts */
2118
if (smb_krb5_init_context(ac,
2119
ldb_get_event_context(ldb),
2120
(struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"),
2121
&smb_krb5_context) != 0) {
2122
return LDB_ERR_OPERATIONS_ERROR;
2125
orig_msg = discard_const(ac->req->op.mod.message);
2126
searched_msg = ac->search_res->message;
2130
io.domain = ac->domain;
2131
io.smb_krb5_context = smb_krb5_context;
2133
io.u.user_account_control = samdb_result_uint(searched_msg, "userAccountControl", 0);
2134
io.u.sAMAccountName = samdb_result_string(searched_msg, "samAccountName", NULL);
2135
io.u.user_principal_name = samdb_result_string(searched_msg, "userPrincipalName", NULL);
2136
io.u.is_computer = ldb_msg_check_string_attribute(searched_msg, "objectClass", "computer");
2138
io.n.cleartext_utf8 = ldb_msg_find_ldb_val(orig_msg, "userPassword");
2139
io.n.cleartext_utf16 = ldb_msg_find_ldb_val(orig_msg, "clearTextPassword");
2141
/* this rather strange looking piece of code is there to
2142
handle a ldap client setting a password remotely using the
2143
unicodePwd ldap field. The syntax is that the password is
2144
in UTF-16LE, with a " at either end. Unfortunately the
2145
unicodePwd field is also used to store the nt hashes
2146
internally in Samba, and is used in the nt hash format on
2147
the wire in DRS replication, so we have a single name for
2148
two distinct values. The code below leaves us with a small
2149
chance (less than 1 in 2^32) of a mixup, if someone manages
2150
to create a MD4 hash which starts and ends in 0x22 0x00, as
2151
that would then be treated as a UTF16 password rather than
2153
quoted_utf16 = ldb_msg_find_ldb_val(orig_msg, "unicodePwd");
2155
quoted_utf16->length >= 4 &&
2156
quoted_utf16->data[0] == '"' &&
2157
quoted_utf16->data[1] == 0 &&
2158
quoted_utf16->data[quoted_utf16->length-2] == '"' &&
2159
quoted_utf16->data[quoted_utf16->length-1] == 0) {
2160
io.n.quoted_utf16.data = talloc_memdup(orig_msg, quoted_utf16->data+2, quoted_utf16->length-4);
2161
io.n.quoted_utf16.length = quoted_utf16->length-4;
2162
io.n.cleartext_utf16 = &io.n.quoted_utf16;
2163
io.n.nt_hash = NULL;
2165
io.n.nt_hash = samdb_result_hash(io.ac, orig_msg, "unicodePwd");
2168
io.n.lm_hash = samdb_result_hash(io.ac, orig_msg, "dBCSPwd");
2170
io.o.kvno = samdb_result_uint(searched_msg, "msDs-KeyVersionNumber", 0);
2171
io.o.nt_history_len = samdb_result_hashes(io.ac, searched_msg, "ntPwdHistory", &io.o.nt_history);
2172
io.o.lm_history_len = samdb_result_hashes(io.ac, searched_msg, "lmPwdHistory", &io.o.lm_history);
2173
io.o.supplemental = ldb_msg_find_ldb_val(searched_msg, "supplementalCredentials");
2175
ret = setup_password_fields(&io);
2176
if (ret != LDB_SUCCESS) {
2180
/* make sure we replace all the old attributes */
2181
ret = ldb_msg_add_empty(msg, "unicodePwd", LDB_FLAG_MOD_REPLACE, NULL);
2182
ret = ldb_msg_add_empty(msg, "dBCSPwd", LDB_FLAG_MOD_REPLACE, NULL);
2183
ret = ldb_msg_add_empty(msg, "ntPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
2184
ret = ldb_msg_add_empty(msg, "lmPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
2185
ret = ldb_msg_add_empty(msg, "supplementalCredentials", LDB_FLAG_MOD_REPLACE, NULL);
2186
ret = ldb_msg_add_empty(msg, "pwdLastSet", LDB_FLAG_MOD_REPLACE, NULL);
2187
ret = ldb_msg_add_empty(msg, "msDs-KeyVersionNumber", LDB_FLAG_MOD_REPLACE, NULL);
2190
ret = samdb_msg_add_hash(ldb, ac, msg,
2191
"unicodePwd", io.g.nt_hash);
2192
if (ret != LDB_SUCCESS) {
2197
ret = samdb_msg_add_hash(ldb, ac, msg,
2198
"dBCSPwd", io.g.lm_hash);
2199
if (ret != LDB_SUCCESS) {
2203
if (io.g.nt_history_len > 0) {
2204
ret = samdb_msg_add_hashes(ac, msg,
2207
io.g.nt_history_len);
2208
if (ret != LDB_SUCCESS) {
2212
if (io.g.lm_history_len > 0) {
2213
ret = samdb_msg_add_hashes(ac, msg,
2216
io.g.lm_history_len);
2217
if (ret != LDB_SUCCESS) {
2221
if (io.g.supplemental.length > 0) {
2222
ret = ldb_msg_add_value(msg, "supplementalCredentials",
2223
&io.g.supplemental, NULL);
2224
if (ret != LDB_SUCCESS) {
2228
ret = samdb_msg_add_uint64(ldb, ac, msg,
2231
if (ret != LDB_SUCCESS) {
2234
ret = samdb_msg_add_uint(ldb, ac, msg,
2235
"msDs-KeyVersionNumber",
2237
if (ret != LDB_SUCCESS) {
2241
ret = ldb_build_mod_req(&mod_req, ldb, ac,
2246
if (ret != LDB_SUCCESS) {
2250
return ldb_next_request(ac->module, mod_req);
2253
_PUBLIC_ const struct ldb_module_ops ldb_password_hash_module_ops = {
2254
.name = "password_hash",
2255
.add = password_hash_add,
2256
.modify = password_hash_modify,