s4:resolve_oids LDB module - not really a change but a nicer method to call "talloc_r...
[Samba/nascimento.git] / source4 / dsdb / samdb / ldb_modules / password_hash.c
blob3cefa184e5dae2c401cd62e42ef8aadaba9fdceb
1 /*
2 ldb database module
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/>.
24 * Name: ldb
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
34 #include "includes.h"
35 #include "libcli/ldap/ldap_ndr.h"
36 #include "ldb_module.h"
37 #include "librpc/gen_ndr/misc.h"
38 #include "librpc/gen_ndr/samr.h"
39 #include "libcli/auth/libcli_auth.h"
40 #include "libcli/security/security.h"
41 #include "system/kerberos.h"
42 #include "auth/kerberos/kerberos.h"
43 #include "system/time.h"
44 #include "dsdb/samdb/samdb.h"
45 #include "../libds/common/flags.h"
46 #include "dsdb/samdb/ldb_modules/password_modules.h"
47 #include "librpc/ndr/libndr.h"
48 #include "librpc/gen_ndr/ndr_drsblobs.h"
49 #include "../lib/crypto/crypto.h"
50 #include "param/param.h"
52 /* If we have decided there is reason to work on this request, then
53 * setup all the password hash types correctly.
55 * If the administrator doesn't want the userPassword stored (set in the
56 * domain and per-account policies) then we must strip that out before
57 * we do the first operation.
59 * Once this is done (which could update anything at all), we
60 * calculate the password hashes.
62 * This function must not only update the unicodePwd, dBCSPwd and
63 * supplementalCredentials fields, it must also atomicly increment the
64 * msDS-KeyVersionNumber. We should be in a transaction, so all this
65 * should be quite safe...
67 * Finally, if the administrator has requested that a password history
68 * be maintained, then this should also be written out.
72 struct ph_context {
74 struct ldb_module *module;
75 struct ldb_request *req;
77 struct ldb_request *dom_req;
78 struct ldb_reply *dom_res;
80 struct ldb_reply *search_res;
82 struct domain_data *domain;
85 struct domain_data {
86 bool store_cleartext;
87 unsigned int pwdProperties;
88 unsigned int pwdHistoryLength;
89 const char *netbios_domain;
90 const char *dns_domain;
91 const char *realm;
94 struct setup_password_fields_io {
95 struct ph_context *ac;
96 struct domain_data *domain;
97 struct smb_krb5_context *smb_krb5_context;
99 /* infos about the user account */
100 struct {
101 uint32_t user_account_control;
102 const char *sAMAccountName;
103 const char *user_principal_name;
104 bool is_computer;
105 } u;
107 /* new credentials */
108 struct {
109 const struct ldb_val *cleartext_utf8;
110 const struct ldb_val *cleartext_utf16;
111 struct ldb_val quoted_utf16;
112 struct samr_Password *nt_hash;
113 struct samr_Password *lm_hash;
114 } n;
116 /* old credentials */
117 struct {
118 uint32_t nt_history_len;
119 struct samr_Password *nt_history;
120 uint32_t lm_history_len;
121 struct samr_Password *lm_history;
122 const struct ldb_val *supplemental;
123 struct supplementalCredentialsBlob scb;
124 uint32_t kvno;
125 } o;
127 /* generated credentials */
128 struct {
129 struct samr_Password *nt_hash;
130 struct samr_Password *lm_hash;
131 uint32_t nt_history_len;
132 struct samr_Password *nt_history;
133 uint32_t lm_history_len;
134 struct samr_Password *lm_history;
135 const char *salt;
136 DATA_BLOB aes_256;
137 DATA_BLOB aes_128;
138 DATA_BLOB des_md5;
139 DATA_BLOB des_crc;
140 struct ldb_val supplemental;
141 NTTIME last_set;
142 uint32_t kvno;
143 } g;
146 /* Get the NT hash, and fill it in as an entry in the password history,
147 and specify it into io->g.nt_hash */
149 static int setup_nt_fields(struct setup_password_fields_io *io)
151 struct ldb_context *ldb;
152 uint32_t i;
154 io->g.nt_hash = io->n.nt_hash;
155 ldb = ldb_module_get_ctx(io->ac->module);
157 if (io->domain->pwdHistoryLength == 0) {
158 return LDB_SUCCESS;
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(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;
175 if (io->g.nt_hash) {
176 io->g.nt_history[0] = *io->g.nt_hash;
177 } else {
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);
185 return LDB_SUCCESS;
188 /* Get the LANMAN hash, and fill it in as an entry in the password history,
189 and specify it into io->g.lm_hash */
191 static int setup_lm_fields(struct setup_password_fields_io *io)
193 struct ldb_context *ldb;
194 uint32_t i;
196 io->g.lm_hash = io->n.lm_hash;
197 ldb = ldb_module_get_ctx(io->ac->module);
199 if (io->domain->pwdHistoryLength == 0) {
200 return LDB_SUCCESS;
203 /* We might not have an old NT password */
204 io->g.lm_history = talloc_array(io->ac,
205 struct samr_Password,
206 io->domain->pwdHistoryLength);
207 if (!io->g.lm_history) {
208 ldb_oom(ldb);
209 return LDB_ERR_OPERATIONS_ERROR;
212 for (i = 0; i < MIN(io->domain->pwdHistoryLength-1, io->o.lm_history_len); i++) {
213 io->g.lm_history[i+1] = io->o.lm_history[i];
215 io->g.lm_history_len = i + 1;
217 if (io->g.lm_hash) {
218 io->g.lm_history[0] = *io->g.lm_hash;
219 } else {
220 E_deshash("", io->g.lm_history[0].hash);
223 return LDB_SUCCESS;
226 static int setup_kerberos_keys(struct setup_password_fields_io *io)
228 struct ldb_context *ldb;
229 krb5_error_code krb5_ret;
230 Principal *salt_principal;
231 krb5_salt salt;
232 krb5_keyblock key;
233 krb5_data cleartext_data;
235 ldb = ldb_module_get_ctx(io->ac->module);
236 cleartext_data.data = io->n.cleartext_utf8->data;
237 cleartext_data.length = io->n.cleartext_utf8->length;
239 /* Many, many thanks to lukeh@padl.com for this
240 * algorithm, described in his Nov 10 2004 mail to
241 * samba-technical@samba.org */
244 * Determine a salting principal
246 if (io->u.is_computer) {
247 char *name;
248 char *saltbody;
250 name = strlower_talloc(io->ac, io->u.sAMAccountName);
251 if (!name) {
252 ldb_oom(ldb);
253 return LDB_ERR_OPERATIONS_ERROR;
256 if (name[strlen(name)-1] == '$') {
257 name[strlen(name)-1] = '\0';
260 saltbody = talloc_asprintf(io->ac, "%s.%s", name, io->domain->dns_domain);
261 if (!saltbody) {
262 ldb_oom(ldb);
263 return LDB_ERR_OPERATIONS_ERROR;
266 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
267 &salt_principal,
268 io->domain->realm, "host",
269 saltbody, NULL);
270 } else if (io->u.user_principal_name) {
271 char *user_principal_name;
272 char *p;
274 user_principal_name = talloc_strdup(io->ac, io->u.user_principal_name);
275 if (!user_principal_name) {
276 ldb_oom(ldb);
277 return LDB_ERR_OPERATIONS_ERROR;
280 p = strchr(user_principal_name, '@');
281 if (p) {
282 p[0] = '\0';
285 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
286 &salt_principal,
287 io->domain->realm, user_principal_name,
288 NULL);
289 } else {
290 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
291 &salt_principal,
292 io->domain->realm, io->u.sAMAccountName,
293 NULL);
295 if (krb5_ret) {
296 ldb_asprintf_errstring(ldb,
297 "setup_kerberos_keys: "
298 "generation of a salting principal failed: %s",
299 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
300 return LDB_ERR_OPERATIONS_ERROR;
304 * create salt from salt_principal
306 krb5_ret = krb5_get_pw_salt(io->smb_krb5_context->krb5_context,
307 salt_principal, &salt);
308 krb5_free_principal(io->smb_krb5_context->krb5_context, salt_principal);
309 if (krb5_ret) {
310 ldb_asprintf_errstring(ldb,
311 "setup_kerberos_keys: "
312 "generation of krb5_salt failed: %s",
313 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
314 return LDB_ERR_OPERATIONS_ERROR;
316 /* create a talloc copy */
317 io->g.salt = talloc_strndup(io->ac,
318 salt.saltvalue.data,
319 salt.saltvalue.length);
320 krb5_free_salt(io->smb_krb5_context->krb5_context, salt);
321 if (!io->g.salt) {
322 ldb_oom(ldb);
323 return LDB_ERR_OPERATIONS_ERROR;
325 salt.saltvalue.data = discard_const(io->g.salt);
326 salt.saltvalue.length = strlen(io->g.salt);
329 * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of
330 * the salt and the cleartext password
332 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
333 ENCTYPE_AES256_CTS_HMAC_SHA1_96,
334 cleartext_data,
335 salt,
336 &key);
337 if (krb5_ret) {
338 ldb_asprintf_errstring(ldb,
339 "setup_kerberos_keys: "
340 "generation of a aes256-cts-hmac-sha1-96 key failed: %s",
341 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
342 return LDB_ERR_OPERATIONS_ERROR;
344 io->g.aes_256 = data_blob_talloc(io->ac,
345 key.keyvalue.data,
346 key.keyvalue.length);
347 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
348 if (!io->g.aes_256.data) {
349 ldb_oom(ldb);
350 return LDB_ERR_OPERATIONS_ERROR;
354 * create ENCTYPE_AES128_CTS_HMAC_SHA1_96 key out of
355 * the salt and the cleartext password
357 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
358 ENCTYPE_AES128_CTS_HMAC_SHA1_96,
359 cleartext_data,
360 salt,
361 &key);
362 if (krb5_ret) {
363 ldb_asprintf_errstring(ldb,
364 "setup_kerberos_keys: "
365 "generation of a aes128-cts-hmac-sha1-96 key failed: %s",
366 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
367 return LDB_ERR_OPERATIONS_ERROR;
369 io->g.aes_128 = data_blob_talloc(io->ac,
370 key.keyvalue.data,
371 key.keyvalue.length);
372 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
373 if (!io->g.aes_128.data) {
374 ldb_oom(ldb);
375 return LDB_ERR_OPERATIONS_ERROR;
379 * create ENCTYPE_DES_CBC_MD5 key out of
380 * the salt and the cleartext password
382 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
383 ENCTYPE_DES_CBC_MD5,
384 cleartext_data,
385 salt,
386 &key);
387 if (krb5_ret) {
388 ldb_asprintf_errstring(ldb,
389 "setup_kerberos_keys: "
390 "generation of a des-cbc-md5 key failed: %s",
391 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
392 return LDB_ERR_OPERATIONS_ERROR;
394 io->g.des_md5 = data_blob_talloc(io->ac,
395 key.keyvalue.data,
396 key.keyvalue.length);
397 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
398 if (!io->g.des_md5.data) {
399 ldb_oom(ldb);
400 return LDB_ERR_OPERATIONS_ERROR;
404 * create ENCTYPE_DES_CBC_CRC key out of
405 * the salt and the cleartext password
407 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
408 ENCTYPE_DES_CBC_CRC,
409 cleartext_data,
410 salt,
411 &key);
412 if (krb5_ret) {
413 ldb_asprintf_errstring(ldb,
414 "setup_kerberos_keys: "
415 "generation of a des-cbc-crc key failed: %s",
416 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
417 return LDB_ERR_OPERATIONS_ERROR;
419 io->g.des_crc = data_blob_talloc(io->ac,
420 key.keyvalue.data,
421 key.keyvalue.length);
422 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
423 if (!io->g.des_crc.data) {
424 ldb_oom(ldb);
425 return LDB_ERR_OPERATIONS_ERROR;
428 return LDB_SUCCESS;
431 static int setup_primary_kerberos(struct setup_password_fields_io *io,
432 const struct supplementalCredentialsBlob *old_scb,
433 struct package_PrimaryKerberosBlob *pkb)
435 struct ldb_context *ldb;
436 struct package_PrimaryKerberosCtr3 *pkb3 = &pkb->ctr.ctr3;
437 struct supplementalCredentialsPackage *old_scp = NULL;
438 struct package_PrimaryKerberosBlob _old_pkb;
439 struct package_PrimaryKerberosCtr3 *old_pkb3 = NULL;
440 uint32_t i;
441 enum ndr_err_code ndr_err;
443 ldb = ldb_module_get_ctx(io->ac->module);
446 * prepare generation of keys
448 * ENCTYPE_DES_CBC_MD5
449 * ENCTYPE_DES_CBC_CRC
451 pkb->version = 3;
452 pkb3->salt.string = io->g.salt;
453 pkb3->num_keys = 2;
454 pkb3->keys = talloc_array(io->ac,
455 struct package_PrimaryKerberosKey3,
456 pkb3->num_keys);
457 if (!pkb3->keys) {
458 ldb_oom(ldb);
459 return LDB_ERR_OPERATIONS_ERROR;
462 pkb3->keys[0].keytype = ENCTYPE_DES_CBC_MD5;
463 pkb3->keys[0].value = &io->g.des_md5;
464 pkb3->keys[1].keytype = ENCTYPE_DES_CBC_CRC;
465 pkb3->keys[1].value = &io->g.des_crc;
467 /* initialize the old keys to zero */
468 pkb3->num_old_keys = 0;
469 pkb3->old_keys = NULL;
471 /* if there're no old keys, then we're done */
472 if (!old_scb) {
473 return LDB_SUCCESS;
476 for (i=0; i < old_scb->sub.num_packages; i++) {
477 if (strcmp("Primary:Kerberos", old_scb->sub.packages[i].name) != 0) {
478 continue;
481 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
482 continue;
485 old_scp = &old_scb->sub.packages[i];
486 break;
488 /* Primary:Kerberos element of supplementalCredentials */
489 if (old_scp) {
490 DATA_BLOB blob;
492 blob = strhex_to_data_blob(io->ac, old_scp->data);
493 if (!blob.data) {
494 ldb_oom(ldb);
495 return LDB_ERR_OPERATIONS_ERROR;
498 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
499 ndr_err = ndr_pull_struct_blob(&blob, io->ac, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &_old_pkb,
500 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
501 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
502 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
503 ldb_asprintf_errstring(ldb,
504 "setup_primary_kerberos: "
505 "failed to pull old package_PrimaryKerberosBlob: %s",
506 nt_errstr(status));
507 return LDB_ERR_OPERATIONS_ERROR;
510 if (_old_pkb.version != 3) {
511 ldb_asprintf_errstring(ldb,
512 "setup_primary_kerberos: "
513 "package_PrimaryKerberosBlob version[%u] expected[3]",
514 _old_pkb.version);
515 return LDB_ERR_OPERATIONS_ERROR;
518 old_pkb3 = &_old_pkb.ctr.ctr3;
521 /* if we didn't found the old keys we're done */
522 if (!old_pkb3) {
523 return LDB_SUCCESS;
526 /* fill in the old keys */
527 pkb3->num_old_keys = old_pkb3->num_keys;
528 pkb3->old_keys = old_pkb3->keys;
530 return LDB_SUCCESS;
533 static int setup_primary_kerberos_newer(struct setup_password_fields_io *io,
534 const struct supplementalCredentialsBlob *old_scb,
535 struct package_PrimaryKerberosBlob *pkb)
537 struct ldb_context *ldb;
538 struct package_PrimaryKerberosCtr4 *pkb4 = &pkb->ctr.ctr4;
539 struct supplementalCredentialsPackage *old_scp = NULL;
540 struct package_PrimaryKerberosBlob _old_pkb;
541 struct package_PrimaryKerberosCtr4 *old_pkb4 = NULL;
542 uint32_t i;
543 enum ndr_err_code ndr_err;
545 ldb = ldb_module_get_ctx(io->ac->module);
548 * prepare generation of keys
550 * ENCTYPE_AES256_CTS_HMAC_SHA1_96
551 * ENCTYPE_AES128_CTS_HMAC_SHA1_96
552 * ENCTYPE_DES_CBC_MD5
553 * ENCTYPE_DES_CBC_CRC
555 pkb->version = 4;
556 pkb4->salt.string = io->g.salt;
557 pkb4->default_iteration_count = 4096;
558 pkb4->num_keys = 4;
560 pkb4->keys = talloc_array(io->ac,
561 struct package_PrimaryKerberosKey4,
562 pkb4->num_keys);
563 if (!pkb4->keys) {
564 ldb_oom(ldb);
565 return LDB_ERR_OPERATIONS_ERROR;
568 pkb4->keys[0].iteration_count = 4096;
569 pkb4->keys[0].keytype = ENCTYPE_AES256_CTS_HMAC_SHA1_96;
570 pkb4->keys[0].value = &io->g.aes_256;
571 pkb4->keys[1].iteration_count = 4096;
572 pkb4->keys[1].keytype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
573 pkb4->keys[1].value = &io->g.aes_128;
574 pkb4->keys[2].iteration_count = 4096;
575 pkb4->keys[2].keytype = ENCTYPE_DES_CBC_MD5;
576 pkb4->keys[2].value = &io->g.des_md5;
577 pkb4->keys[3].iteration_count = 4096;
578 pkb4->keys[3].keytype = ENCTYPE_DES_CBC_CRC;
579 pkb4->keys[3].value = &io->g.des_crc;
581 /* initialize the old keys to zero */
582 pkb4->num_old_keys = 0;
583 pkb4->old_keys = NULL;
584 pkb4->num_older_keys = 0;
585 pkb4->older_keys = NULL;
587 /* if there're no old keys, then we're done */
588 if (!old_scb) {
589 return LDB_SUCCESS;
592 for (i=0; i < old_scb->sub.num_packages; i++) {
593 if (strcmp("Primary:Kerberos-Newer-Keys", old_scb->sub.packages[i].name) != 0) {
594 continue;
597 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
598 continue;
601 old_scp = &old_scb->sub.packages[i];
602 break;
604 /* Primary:Kerberos-Newer-Keys element of supplementalCredentials */
605 if (old_scp) {
606 DATA_BLOB blob;
608 blob = strhex_to_data_blob(io->ac, old_scp->data);
609 if (!blob.data) {
610 ldb_oom(ldb);
611 return LDB_ERR_OPERATIONS_ERROR;
614 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
615 ndr_err = ndr_pull_struct_blob(&blob, io->ac,
616 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
617 &_old_pkb,
618 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
619 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
620 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
621 ldb_asprintf_errstring(ldb,
622 "setup_primary_kerberos_newer: "
623 "failed to pull old package_PrimaryKerberosBlob: %s",
624 nt_errstr(status));
625 return LDB_ERR_OPERATIONS_ERROR;
628 if (_old_pkb.version != 4) {
629 ldb_asprintf_errstring(ldb,
630 "setup_primary_kerberos_newer: "
631 "package_PrimaryKerberosBlob version[%u] expected[4]",
632 _old_pkb.version);
633 return LDB_ERR_OPERATIONS_ERROR;
636 old_pkb4 = &_old_pkb.ctr.ctr4;
639 /* if we didn't found the old keys we're done */
640 if (!old_pkb4) {
641 return LDB_SUCCESS;
644 /* fill in the old keys */
645 pkb4->num_old_keys = old_pkb4->num_keys;
646 pkb4->old_keys = old_pkb4->keys;
647 pkb4->num_older_keys = old_pkb4->num_old_keys;
648 pkb4->older_keys = old_pkb4->old_keys;
650 return LDB_SUCCESS;
653 static int setup_primary_wdigest(struct setup_password_fields_io *io,
654 const struct supplementalCredentialsBlob *old_scb,
655 struct package_PrimaryWDigestBlob *pdb)
657 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
658 DATA_BLOB sAMAccountName;
659 DATA_BLOB sAMAccountName_l;
660 DATA_BLOB sAMAccountName_u;
661 const char *user_principal_name = io->u.user_principal_name;
662 DATA_BLOB userPrincipalName;
663 DATA_BLOB userPrincipalName_l;
664 DATA_BLOB userPrincipalName_u;
665 DATA_BLOB netbios_domain;
666 DATA_BLOB netbios_domain_l;
667 DATA_BLOB netbios_domain_u;
668 DATA_BLOB dns_domain;
669 DATA_BLOB dns_domain_l;
670 DATA_BLOB dns_domain_u;
671 DATA_BLOB digest;
672 DATA_BLOB delim;
673 DATA_BLOB backslash;
674 uint8_t i;
675 struct {
676 DATA_BLOB *user;
677 DATA_BLOB *realm;
678 DATA_BLOB *nt4dom;
679 } wdigest[] = {
681 * See
682 * http://technet2.microsoft.com/WindowsServer/en/library/717b450c-f4a0-4cc9-86f4-cc0633aae5f91033.mspx?mfr=true
683 * for what precalculated hashes are supposed to be stored...
685 * I can't reproduce all values which should contain "Digest" as realm,
686 * am I doing something wrong or is w2k3 just broken...?
688 * W2K3 fills in following for a user:
690 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
691 * sAMAccountName: NewUser2Sam
692 * userPrincipalName: NewUser2Princ@sub1.w2k3.vmnet1.vm.base
694 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
695 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
696 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
697 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
698 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
699 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
700 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
701 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
702 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
703 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
704 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
705 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
706 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
707 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
708 * 221c55284451ae9b3aacaa2a3c86f10f => NewUser2Princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
709 * 74e1be668853d4324d38c07e2acfb8ea => (w2k3 has a bug here!) newuser2princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
710 * e1e244ab7f098e3ae1761be7f9229bbb => NEWUSER2PRINC@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
711 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
712 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
713 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
714 * 31dc704d3640335b2123d4ee28aa1f11 => ??? changes with NewUser2Sam => NewUser1Sam
715 * 36349f5cecd07320fb3bb0e119230c43 => ??? changes with NewUser2Sam => NewUser1Sam
716 * 12adf019d037fb535c01fd0608e78d9d => ??? changes with NewUser2Sam => NewUser1Sam
717 * 6feecf8e724906f3ee1105819c5105a1 => ??? changes with NewUser2Princ => NewUser1Princ
718 * 6c6911f3de6333422640221b9c51ff1f => ??? changes with NewUser2Princ => NewUser1Princ
719 * 4b279877e742895f9348ac67a8de2f69 => ??? changes with NewUser2Princ => NewUser1Princ
720 * db0c6bff069513e3ebb9870d29b57490 => ??? changes with NewUser2Sam => NewUser1Sam
721 * 45072621e56b1c113a4e04a8ff68cd0e => ??? changes with NewUser2Sam => NewUser1Sam
722 * 11d1220abc44a9c10cf91ef4a9c1de02 => ??? changes with NewUser2Sam => NewUser1Sam
724 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
725 * sAMAccountName: NewUser2Sam
727 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
728 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
729 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
730 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
731 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
732 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
733 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
734 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
735 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
736 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
737 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
738 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
739 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
740 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
741 * 8a140d30b6f0a5912735dc1e3bc993b4 => NewUser2Sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
742 * 86d95b2faae6cae4ec261e7fbaccf093 => (here w2k3 is correct) newuser2sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
743 * dfeff1493110220efcdfc6362e5f5450 => NEWUSER2SAM@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
744 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
745 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
746 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
747 * 31dc704d3640335b2123d4ee28aa1f11 => ???M1 changes with NewUser2Sam => NewUser1Sam
748 * 36349f5cecd07320fb3bb0e119230c43 => ???M1.L changes with newuser2sam => newuser1sam
749 * 12adf019d037fb535c01fd0608e78d9d => ???M1.U changes with NEWUSER2SAM => NEWUSER1SAM
750 * 569b4533f2d9e580211dd040e5e360a8 => ???M2 changes with NewUser2Princ => NewUser1Princ
751 * 52528bddf310a587c5d7e6a9ae2cbb20 => ???M2.L changes with newuser2princ => newuser1princ
752 * 4f629a4f0361289ca4255ab0f658fcd5 => ???M3 changes with NewUser2Princ => NewUser1Princ (doesn't depend on case of userPrincipal )
753 * db0c6bff069513e3ebb9870d29b57490 => ???M4 changes with NewUser2Sam => NewUser1Sam
754 * 45072621e56b1c113a4e04a8ff68cd0e => ???M5 changes with NewUser2Sam => NewUser1Sam (doesn't depend on case of sAMAccountName)
755 * 11d1220abc44a9c10cf91ef4a9c1de02 => ???M4.U changes with NEWUSER2SAM => NEWUSER1SAM
759 * sAMAccountName, netbios_domain
762 .user = &sAMAccountName,
763 .realm = &netbios_domain,
766 .user = &sAMAccountName_l,
767 .realm = &netbios_domain_l,
770 .user = &sAMAccountName_u,
771 .realm = &netbios_domain_u,
774 .user = &sAMAccountName,
775 .realm = &netbios_domain_u,
778 .user = &sAMAccountName,
779 .realm = &netbios_domain_l,
782 .user = &sAMAccountName_u,
783 .realm = &netbios_domain_l,
786 .user = &sAMAccountName_l,
787 .realm = &netbios_domain_u,
790 * sAMAccountName, dns_domain
793 .user = &sAMAccountName,
794 .realm = &dns_domain,
797 .user = &sAMAccountName_l,
798 .realm = &dns_domain_l,
801 .user = &sAMAccountName_u,
802 .realm = &dns_domain_u,
805 .user = &sAMAccountName,
806 .realm = &dns_domain_u,
809 .user = &sAMAccountName,
810 .realm = &dns_domain_l,
813 .user = &sAMAccountName_u,
814 .realm = &dns_domain_l,
817 .user = &sAMAccountName_l,
818 .realm = &dns_domain_u,
821 * userPrincipalName, no realm
824 .user = &userPrincipalName,
828 * NOTE: w2k3 messes this up, if the user has a real userPrincipalName,
829 * the fallback to the sAMAccountName based userPrincipalName is correct
831 .user = &userPrincipalName_l,
834 .user = &userPrincipalName_u,
837 * nt4dom\sAMAccountName, no realm
840 .user = &sAMAccountName,
841 .nt4dom = &netbios_domain
844 .user = &sAMAccountName_l,
845 .nt4dom = &netbios_domain_l
848 .user = &sAMAccountName_u,
849 .nt4dom = &netbios_domain_u
853 * the following ones are guessed depending on the technet2 article
854 * but not reproducable on a w2k3 server
856 /* sAMAccountName with "Digest" realm */
858 .user = &sAMAccountName,
859 .realm = &digest
862 .user = &sAMAccountName_l,
863 .realm = &digest
866 .user = &sAMAccountName_u,
867 .realm = &digest
869 /* userPrincipalName with "Digest" realm */
871 .user = &userPrincipalName,
872 .realm = &digest
875 .user = &userPrincipalName_l,
876 .realm = &digest
879 .user = &userPrincipalName_u,
880 .realm = &digest
882 /* nt4dom\\sAMAccountName with "Digest" realm */
884 .user = &sAMAccountName,
885 .nt4dom = &netbios_domain,
886 .realm = &digest
889 .user = &sAMAccountName_l,
890 .nt4dom = &netbios_domain_l,
891 .realm = &digest
894 .user = &sAMAccountName_u,
895 .nt4dom = &netbios_domain_u,
896 .realm = &digest
900 /* prepare DATA_BLOB's used in the combinations array */
901 sAMAccountName = data_blob_string_const(io->u.sAMAccountName);
902 sAMAccountName_l = data_blob_string_const(strlower_talloc(io->ac, io->u.sAMAccountName));
903 if (!sAMAccountName_l.data) {
904 ldb_oom(ldb);
905 return LDB_ERR_OPERATIONS_ERROR;
907 sAMAccountName_u = data_blob_string_const(strupper_talloc(io->ac, io->u.sAMAccountName));
908 if (!sAMAccountName_u.data) {
909 ldb_oom(ldb);
910 return LDB_ERR_OPERATIONS_ERROR;
913 /* if the user doesn't have a userPrincipalName, create one (with lower case realm) */
914 if (!user_principal_name) {
915 user_principal_name = talloc_asprintf(io->ac, "%s@%s",
916 io->u.sAMAccountName,
917 io->domain->dns_domain);
918 if (!user_principal_name) {
919 ldb_oom(ldb);
920 return LDB_ERR_OPERATIONS_ERROR;
923 userPrincipalName = data_blob_string_const(user_principal_name);
924 userPrincipalName_l = data_blob_string_const(strlower_talloc(io->ac, user_principal_name));
925 if (!userPrincipalName_l.data) {
926 ldb_oom(ldb);
927 return LDB_ERR_OPERATIONS_ERROR;
929 userPrincipalName_u = data_blob_string_const(strupper_talloc(io->ac, user_principal_name));
930 if (!userPrincipalName_u.data) {
931 ldb_oom(ldb);
932 return LDB_ERR_OPERATIONS_ERROR;
935 netbios_domain = data_blob_string_const(io->domain->netbios_domain);
936 netbios_domain_l = data_blob_string_const(strlower_talloc(io->ac, io->domain->netbios_domain));
937 if (!netbios_domain_l.data) {
938 ldb_oom(ldb);
939 return LDB_ERR_OPERATIONS_ERROR;
941 netbios_domain_u = data_blob_string_const(strupper_talloc(io->ac, io->domain->netbios_domain));
942 if (!netbios_domain_u.data) {
943 ldb_oom(ldb);
944 return LDB_ERR_OPERATIONS_ERROR;
947 dns_domain = data_blob_string_const(io->domain->dns_domain);
948 dns_domain_l = data_blob_string_const(io->domain->dns_domain);
949 dns_domain_u = data_blob_string_const(io->domain->realm);
951 digest = data_blob_string_const("Digest");
953 delim = data_blob_string_const(":");
954 backslash = data_blob_string_const("\\");
956 pdb->num_hashes = ARRAY_SIZE(wdigest);
957 pdb->hashes = talloc_array(io->ac, struct package_PrimaryWDigestHash, pdb->num_hashes);
958 if (!pdb->hashes) {
959 ldb_oom(ldb);
960 return LDB_ERR_OPERATIONS_ERROR;
963 for (i=0; i < ARRAY_SIZE(wdigest); i++) {
964 struct MD5Context md5;
965 MD5Init(&md5);
966 if (wdigest[i].nt4dom) {
967 MD5Update(&md5, wdigest[i].nt4dom->data, wdigest[i].nt4dom->length);
968 MD5Update(&md5, backslash.data, backslash.length);
970 MD5Update(&md5, wdigest[i].user->data, wdigest[i].user->length);
971 MD5Update(&md5, delim.data, delim.length);
972 if (wdigest[i].realm) {
973 MD5Update(&md5, wdigest[i].realm->data, wdigest[i].realm->length);
975 MD5Update(&md5, delim.data, delim.length);
976 MD5Update(&md5, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length);
977 MD5Final(pdb->hashes[i].hash, &md5);
980 return LDB_SUCCESS;
983 static int setup_supplemental_field(struct setup_password_fields_io *io)
985 struct ldb_context *ldb;
986 struct supplementalCredentialsBlob scb;
987 struct supplementalCredentialsBlob _old_scb;
988 struct supplementalCredentialsBlob *old_scb = NULL;
989 /* Packages + (Kerberos-Newer-Keys, Kerberos, WDigest and CLEARTEXT) */
990 uint32_t num_names = 0;
991 const char *names[1+4];
992 uint32_t num_packages = 0;
993 struct supplementalCredentialsPackage packages[1+4];
994 /* Packages */
995 struct supplementalCredentialsPackage *pp = NULL;
996 struct package_PackagesBlob pb;
997 DATA_BLOB pb_blob;
998 char *pb_hexstr;
999 /* Primary:Kerberos-Newer-Keys */
1000 const char **nkn = NULL;
1001 struct supplementalCredentialsPackage *pkn = NULL;
1002 struct package_PrimaryKerberosBlob pknb;
1003 DATA_BLOB pknb_blob;
1004 char *pknb_hexstr;
1005 /* Primary:Kerberos */
1006 const char **nk = NULL;
1007 struct supplementalCredentialsPackage *pk = NULL;
1008 struct package_PrimaryKerberosBlob pkb;
1009 DATA_BLOB pkb_blob;
1010 char *pkb_hexstr;
1011 /* Primary:WDigest */
1012 const char **nd = NULL;
1013 struct supplementalCredentialsPackage *pd = NULL;
1014 struct package_PrimaryWDigestBlob pdb;
1015 DATA_BLOB pdb_blob;
1016 char *pdb_hexstr;
1017 /* Primary:CLEARTEXT */
1018 const char **nc = NULL;
1019 struct supplementalCredentialsPackage *pc = NULL;
1020 struct package_PrimaryCLEARTEXTBlob pcb;
1021 DATA_BLOB pcb_blob;
1022 char *pcb_hexstr;
1023 int ret;
1024 enum ndr_err_code ndr_err;
1025 uint8_t zero16[16];
1026 bool do_newer_keys = false;
1027 bool do_cleartext = false;
1029 ZERO_STRUCT(zero16);
1030 ZERO_STRUCT(names);
1032 ldb = ldb_module_get_ctx(io->ac->module);
1034 if (!io->n.cleartext_utf8) {
1036 * when we don't have a cleartext password
1037 * we can't setup a supplementalCredential value
1039 return LDB_SUCCESS;
1042 /* if there's an old supplementaCredentials blob then parse it */
1043 if (io->o.supplemental) {
1044 ndr_err = ndr_pull_struct_blob_all(io->o.supplemental, io->ac,
1045 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1046 &_old_scb,
1047 (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
1048 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1049 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1050 ldb_asprintf_errstring(ldb,
1051 "setup_supplemental_field: "
1052 "failed to pull old supplementalCredentialsBlob: %s",
1053 nt_errstr(status));
1054 return LDB_ERR_OPERATIONS_ERROR;
1057 if (_old_scb.sub.signature == SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
1058 old_scb = &_old_scb;
1059 } else {
1060 ldb_debug(ldb, LDB_DEBUG_ERROR,
1061 "setup_supplemental_field: "
1062 "supplementalCredentialsBlob signature[0x%04X] expected[0x%04X]",
1063 _old_scb.sub.signature, SUPPLEMENTAL_CREDENTIALS_SIGNATURE);
1066 /* Per MS-SAMR 3.1.1.8.11.6 we create AES keys if our domain functionality level is 2008 or higher */
1067 do_newer_keys = (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008);
1069 if (io->domain->store_cleartext &&
1070 (io->u.user_account_control & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) {
1071 do_cleartext = true;
1075 * The ordering is this
1077 * Primary:Kerberos-Newer-Keys (optional)
1078 * Primary:Kerberos
1079 * Primary:WDigest
1080 * Primary:CLEARTEXT (optional)
1082 * And the 'Packages' package is insert before the last
1083 * other package.
1085 if (do_newer_keys) {
1086 /* Primary:Kerberos-Newer-Keys */
1087 nkn = &names[num_names++];
1088 pkn = &packages[num_packages++];
1091 /* Primary:Kerberos */
1092 nk = &names[num_names++];
1093 pk = &packages[num_packages++];
1095 if (!do_cleartext) {
1096 /* Packages */
1097 pp = &packages[num_packages++];
1100 /* Primary:WDigest */
1101 nd = &names[num_names++];
1102 pd = &packages[num_packages++];
1104 if (do_cleartext) {
1105 /* Packages */
1106 pp = &packages[num_packages++];
1108 /* Primary:CLEARTEXT */
1109 nc = &names[num_names++];
1110 pc = &packages[num_packages++];
1113 if (pkn) {
1115 * setup 'Primary:Kerberos-Newer-Keys' element
1117 *nkn = "Kerberos-Newer-Keys";
1119 ret = setup_primary_kerberos_newer(io, old_scb, &pknb);
1120 if (ret != LDB_SUCCESS) {
1121 return ret;
1124 ndr_err = ndr_push_struct_blob(&pknb_blob, io->ac,
1125 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1126 &pknb,
1127 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1128 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1129 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1130 ldb_asprintf_errstring(ldb,
1131 "setup_supplemental_field: "
1132 "failed to push package_PrimaryKerberosNeverBlob: %s",
1133 nt_errstr(status));
1134 return LDB_ERR_OPERATIONS_ERROR;
1136 pknb_hexstr = data_blob_hex_string_upper(io->ac, &pknb_blob);
1137 if (!pknb_hexstr) {
1138 ldb_oom(ldb);
1139 return LDB_ERR_OPERATIONS_ERROR;
1141 pkn->name = "Primary:Kerberos-Newer-Keys";
1142 pkn->reserved = 1;
1143 pkn->data = pknb_hexstr;
1147 * setup 'Primary:Kerberos' element
1149 *nk = "Kerberos";
1151 ret = setup_primary_kerberos(io, old_scb, &pkb);
1152 if (ret != LDB_SUCCESS) {
1153 return ret;
1156 ndr_err = ndr_push_struct_blob(&pkb_blob, io->ac,
1157 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1158 &pkb,
1159 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1160 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1161 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1162 ldb_asprintf_errstring(ldb,
1163 "setup_supplemental_field: "
1164 "failed to push package_PrimaryKerberosBlob: %s",
1165 nt_errstr(status));
1166 return LDB_ERR_OPERATIONS_ERROR;
1168 pkb_hexstr = data_blob_hex_string_upper(io->ac, &pkb_blob);
1169 if (!pkb_hexstr) {
1170 ldb_oom(ldb);
1171 return LDB_ERR_OPERATIONS_ERROR;
1173 pk->name = "Primary:Kerberos";
1174 pk->reserved = 1;
1175 pk->data = pkb_hexstr;
1178 * setup 'Primary:WDigest' element
1180 *nd = "WDigest";
1182 ret = setup_primary_wdigest(io, old_scb, &pdb);
1183 if (ret != LDB_SUCCESS) {
1184 return ret;
1187 ndr_err = ndr_push_struct_blob(&pdb_blob, io->ac,
1188 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1189 &pdb,
1190 (ndr_push_flags_fn_t)ndr_push_package_PrimaryWDigestBlob);
1191 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1192 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1193 ldb_asprintf_errstring(ldb,
1194 "setup_supplemental_field: "
1195 "failed to push package_PrimaryWDigestBlob: %s",
1196 nt_errstr(status));
1197 return LDB_ERR_OPERATIONS_ERROR;
1199 pdb_hexstr = data_blob_hex_string_upper(io->ac, &pdb_blob);
1200 if (!pdb_hexstr) {
1201 ldb_oom(ldb);
1202 return LDB_ERR_OPERATIONS_ERROR;
1204 pd->name = "Primary:WDigest";
1205 pd->reserved = 1;
1206 pd->data = pdb_hexstr;
1209 * setup 'Primary:CLEARTEXT' element
1211 if (pc) {
1212 *nc = "CLEARTEXT";
1214 pcb.cleartext = *io->n.cleartext_utf16;
1216 ndr_err = ndr_push_struct_blob(&pcb_blob, io->ac,
1217 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1218 &pcb,
1219 (ndr_push_flags_fn_t)ndr_push_package_PrimaryCLEARTEXTBlob);
1220 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1221 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1222 ldb_asprintf_errstring(ldb,
1223 "setup_supplemental_field: "
1224 "failed to push package_PrimaryCLEARTEXTBlob: %s",
1225 nt_errstr(status));
1226 return LDB_ERR_OPERATIONS_ERROR;
1228 pcb_hexstr = data_blob_hex_string_upper(io->ac, &pcb_blob);
1229 if (!pcb_hexstr) {
1230 ldb_oom(ldb);
1231 return LDB_ERR_OPERATIONS_ERROR;
1233 pc->name = "Primary:CLEARTEXT";
1234 pc->reserved = 1;
1235 pc->data = pcb_hexstr;
1239 * setup 'Packages' element
1241 pb.names = names;
1242 ndr_err = ndr_push_struct_blob(&pb_blob, io->ac,
1243 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1244 &pb,
1245 (ndr_push_flags_fn_t)ndr_push_package_PackagesBlob);
1246 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1247 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1248 ldb_asprintf_errstring(ldb,
1249 "setup_supplemental_field: "
1250 "failed to push package_PackagesBlob: %s",
1251 nt_errstr(status));
1252 return LDB_ERR_OPERATIONS_ERROR;
1254 pb_hexstr = data_blob_hex_string_upper(io->ac, &pb_blob);
1255 if (!pb_hexstr) {
1256 ldb_oom(ldb);
1257 return LDB_ERR_OPERATIONS_ERROR;
1259 pp->name = "Packages";
1260 pp->reserved = 2;
1261 pp->data = pb_hexstr;
1264 * setup 'supplementalCredentials' value
1266 ZERO_STRUCT(scb);
1267 scb.sub.num_packages = num_packages;
1268 scb.sub.packages = packages;
1270 ndr_err = ndr_push_struct_blob(&io->g.supplemental, io->ac,
1271 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1272 &scb,
1273 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
1274 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1275 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1276 ldb_asprintf_errstring(ldb,
1277 "setup_supplemental_field: "
1278 "failed to push supplementalCredentialsBlob: %s",
1279 nt_errstr(status));
1280 return LDB_ERR_OPERATIONS_ERROR;
1283 return LDB_SUCCESS;
1286 static int setup_last_set_field(struct setup_password_fields_io *io)
1288 /* set it as now */
1289 unix_to_nt_time(&io->g.last_set, time(NULL));
1291 return LDB_SUCCESS;
1294 static int setup_kvno_field(struct setup_password_fields_io *io)
1296 /* increment by one */
1297 io->g.kvno = io->o.kvno + 1;
1299 return LDB_SUCCESS;
1302 static int setup_password_fields(struct setup_password_fields_io *io)
1304 struct ldb_context *ldb;
1305 bool ok;
1306 int ret;
1307 size_t converted_pw_len;
1309 ldb = ldb_module_get_ctx(io->ac->module);
1312 * refuse the change if someone want to change the cleartext
1313 * and supply his own hashes at the same time...
1315 if ((io->n.cleartext_utf8 || io->n.cleartext_utf16) && (io->n.nt_hash || io->n.lm_hash)) {
1316 ldb_asprintf_errstring(ldb,
1317 "setup_password_fields: "
1318 "it's only allowed to set the cleartext password or the password hashes");
1319 return LDB_ERR_UNWILLING_TO_PERFORM;
1322 if (io->n.cleartext_utf8 && io->n.cleartext_utf16) {
1323 ldb_asprintf_errstring(ldb,
1324 "setup_password_fields: "
1325 "it's only allowed to set the cleartext password as userPassword or clearTextPasssword, not both at once");
1326 return LDB_ERR_UNWILLING_TO_PERFORM;
1329 if (io->n.cleartext_utf8) {
1330 char **cleartext_utf16_str;
1331 struct ldb_val *cleartext_utf16_blob;
1332 io->n.cleartext_utf16 = cleartext_utf16_blob = talloc(io->ac, struct ldb_val);
1333 if (!io->n.cleartext_utf16) {
1334 ldb_oom(ldb);
1335 return LDB_ERR_OPERATIONS_ERROR;
1337 if (!convert_string_talloc_convenience(io->ac, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1338 CH_UTF8, CH_UTF16, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length,
1339 (void **)&cleartext_utf16_str, &converted_pw_len, false)) {
1340 ldb_asprintf_errstring(ldb,
1341 "setup_password_fields: "
1342 "failed to generate UTF16 password from cleartext UTF8 password");
1343 return LDB_ERR_OPERATIONS_ERROR;
1345 *cleartext_utf16_blob = data_blob_const(cleartext_utf16_str, converted_pw_len);
1346 } else if (io->n.cleartext_utf16) {
1347 char *cleartext_utf8_str;
1348 struct ldb_val *cleartext_utf8_blob;
1349 io->n.cleartext_utf8 = cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
1350 if (!io->n.cleartext_utf8) {
1351 ldb_oom(ldb);
1352 return LDB_ERR_OPERATIONS_ERROR;
1354 if (!convert_string_talloc_convenience(io->ac, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1355 CH_UTF16MUNGED, CH_UTF8, io->n.cleartext_utf16->data, io->n.cleartext_utf16->length,
1356 (void **)&cleartext_utf8_str, &converted_pw_len, false)) {
1357 /* We can't bail out entirely, as these unconvertable passwords are frustratingly valid */
1358 io->n.cleartext_utf8 = NULL;
1359 talloc_free(cleartext_utf8_blob);
1361 *cleartext_utf8_blob = data_blob_const(cleartext_utf8_str, converted_pw_len);
1363 if (io->n.cleartext_utf16) {
1364 struct samr_Password *nt_hash;
1365 nt_hash = talloc(io->ac, struct samr_Password);
1366 if (!nt_hash) {
1367 ldb_oom(ldb);
1368 return LDB_ERR_OPERATIONS_ERROR;
1370 io->n.nt_hash = nt_hash;
1372 /* compute the new nt hash */
1373 mdfour(nt_hash->hash, io->n.cleartext_utf16->data, io->n.cleartext_utf16->length);
1376 if (io->n.cleartext_utf8) {
1377 struct samr_Password *lm_hash;
1378 char *cleartext_unix;
1379 if (lp_lanman_auth(ldb_get_opaque(ldb, "loadparm")) &&
1380 convert_string_talloc_convenience(io->ac, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1381 CH_UTF8, CH_UNIX, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length,
1382 (void **)&cleartext_unix, &converted_pw_len, false)) {
1383 lm_hash = talloc(io->ac, struct samr_Password);
1384 if (!lm_hash) {
1385 ldb_oom(ldb);
1386 return LDB_ERR_OPERATIONS_ERROR;
1389 /* compute the new lm hash. */
1390 ok = E_deshash((char *)cleartext_unix, lm_hash->hash);
1391 if (ok) {
1392 io->n.lm_hash = lm_hash;
1393 } else {
1394 talloc_free(lm_hash->hash);
1398 ret = setup_kerberos_keys(io);
1399 if (ret != LDB_SUCCESS) {
1400 return ret;
1404 ret = setup_nt_fields(io);
1405 if (ret != LDB_SUCCESS) {
1406 return ret;
1409 ret = setup_lm_fields(io);
1410 if (ret != LDB_SUCCESS) {
1411 return ret;
1414 ret = setup_supplemental_field(io);
1415 if (ret != LDB_SUCCESS) {
1416 return ret;
1419 ret = setup_last_set_field(io);
1420 if (ret != LDB_SUCCESS) {
1421 return ret;
1424 ret = setup_kvno_field(io);
1425 if (ret != LDB_SUCCESS) {
1426 return ret;
1429 return LDB_SUCCESS;
1432 static int setup_io(struct ph_context *ac,
1433 const struct ldb_message *new_msg,
1434 const struct ldb_message *searched_msg,
1435 struct setup_password_fields_io *io)
1437 const struct ldb_val *quoted_utf16;
1438 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1440 ZERO_STRUCTP(io);
1442 /* Some operations below require kerberos contexts */
1443 if (smb_krb5_init_context(ac,
1444 ldb_get_event_context(ldb),
1445 (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"),
1446 &io->smb_krb5_context) != 0) {
1447 return LDB_ERR_OPERATIONS_ERROR;
1450 io->ac = ac;
1451 io->domain = ac->domain;
1453 io->u.user_account_control = samdb_result_uint(searched_msg, "userAccountControl", 0);
1454 io->u.sAMAccountName = samdb_result_string(searched_msg, "samAccountName", NULL);
1455 io->u.user_principal_name = samdb_result_string(searched_msg, "userPrincipalName", NULL);
1456 io->u.is_computer = ldb_msg_check_string_attribute(searched_msg, "objectClass", "computer");
1458 io->n.cleartext_utf8 = ldb_msg_find_ldb_val(new_msg, "userPassword");
1459 io->n.cleartext_utf16 = ldb_msg_find_ldb_val(new_msg, "clearTextPassword");
1461 /* this rather strange looking piece of code is there to
1462 handle a ldap client setting a password remotely using the
1463 unicodePwd ldap field. The syntax is that the password is
1464 in UTF-16LE, with a " at either end. Unfortunately the
1465 unicodePwd field is also used to store the nt hashes
1466 internally in Samba, and is used in the nt hash format on
1467 the wire in DRS replication, so we have a single name for
1468 two distinct values. The code below leaves us with a small
1469 chance (less than 1 in 2^32) of a mixup, if someone manages
1470 to create a MD4 hash which starts and ends in 0x22 0x00, as
1471 that would then be treated as a UTF16 password rather than
1472 a nthash */
1473 quoted_utf16 = ldb_msg_find_ldb_val(new_msg, "unicodePwd");
1474 if (quoted_utf16 &&
1475 quoted_utf16->length >= 4 &&
1476 quoted_utf16->data[0] == '"' &&
1477 quoted_utf16->data[1] == 0 &&
1478 quoted_utf16->data[quoted_utf16->length-2] == '"' &&
1479 quoted_utf16->data[quoted_utf16->length-1] == 0) {
1480 io->n.quoted_utf16.data = talloc_memdup(io->ac, quoted_utf16->data+2, quoted_utf16->length-4);
1481 io->n.quoted_utf16.length = quoted_utf16->length-4;
1482 io->n.cleartext_utf16 = &io->n.quoted_utf16;
1483 io->n.nt_hash = NULL;
1484 } else {
1485 io->n.nt_hash = samdb_result_hash(io->ac, new_msg, "unicodePwd");
1488 io->n.lm_hash = samdb_result_hash(io->ac, new_msg, "dBCSPwd");
1490 if(io->u.sAMAccountName == NULL)
1492 ldb_asprintf_errstring(ldb, "samAccountName is missing on %s for attempted password set/change",
1493 ldb_dn_get_linearized(new_msg->dn));
1494 return(LDB_ERR_CONSTRAINT_VIOLATION);
1497 return LDB_SUCCESS;
1500 static struct ph_context *ph_init_context(struct ldb_module *module,
1501 struct ldb_request *req)
1503 struct ldb_context *ldb;
1504 struct ph_context *ac;
1506 ldb = ldb_module_get_ctx(module);
1508 ac = talloc_zero(req, struct ph_context);
1509 if (ac == NULL) {
1510 ldb_set_errstring(ldb, "Out of Memory");
1511 return NULL;
1514 ac->module = module;
1515 ac->req = req;
1517 return ac;
1520 static int ph_op_callback(struct ldb_request *req, struct ldb_reply *ares)
1522 struct ph_context *ac;
1524 ac = talloc_get_type(req->context, struct ph_context);
1526 if (!ares) {
1527 return ldb_module_done(ac->req, NULL, NULL,
1528 LDB_ERR_OPERATIONS_ERROR);
1530 if (ares->error != LDB_SUCCESS) {
1531 return ldb_module_done(ac->req, ares->controls,
1532 ares->response, ares->error);
1535 if (ares->type != LDB_REPLY_DONE) {
1536 talloc_free(ares);
1537 return ldb_module_done(ac->req, NULL, NULL,
1538 LDB_ERR_OPERATIONS_ERROR);
1541 return ldb_module_done(ac->req, ares->controls,
1542 ares->response, ares->error);
1545 static int password_hash_add_do_add(struct ph_context *ac);
1546 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares);
1547 static int password_hash_mod_search_self(struct ph_context *ac);
1548 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares);
1549 static int password_hash_mod_do_mod(struct ph_context *ac);
1551 static int get_domain_data_callback(struct ldb_request *req,
1552 struct ldb_reply *ares)
1554 struct ldb_context *ldb;
1555 struct domain_data *data;
1556 struct ph_context *ac;
1557 struct loadparm_context *lp_ctx;
1558 int ret;
1560 ac = talloc_get_type(req->context, struct ph_context);
1561 ldb = ldb_module_get_ctx(ac->module);
1563 if (!ares) {
1564 return ldb_module_done(ac->req, NULL, NULL,
1565 LDB_ERR_OPERATIONS_ERROR);
1567 if (ares->error != LDB_SUCCESS) {
1568 return ldb_module_done(ac->req, ares->controls,
1569 ares->response, ares->error);
1572 switch (ares->type) {
1573 case LDB_REPLY_ENTRY:
1574 if (ac->domain != NULL) {
1575 ldb_set_errstring(ldb, "Too many results");
1576 return ldb_module_done(ac->req, NULL, NULL,
1577 LDB_ERR_OPERATIONS_ERROR);
1580 data = talloc_zero(ac, struct domain_data);
1581 if (data == NULL) {
1582 return ldb_module_done(ac->req, NULL, NULL,
1583 LDB_ERR_OPERATIONS_ERROR);
1586 data->pwdProperties = samdb_result_uint(ares->message, "pwdProperties", 0);
1587 data->store_cleartext = data->pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
1588 data->pwdHistoryLength = samdb_result_uint(ares->message, "pwdHistoryLength", 0);
1590 /* For a domain DN, this puts things in dotted notation */
1591 /* For builtin domains, this will give details for the host,
1592 * but that doesn't really matter, as it's just used for salt
1593 * and kerberos principals, which don't exist here */
1595 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
1596 struct loadparm_context);
1598 data->dns_domain = lp_dnsdomain(lp_ctx);
1599 data->realm = lp_realm(lp_ctx);
1600 data->netbios_domain = lp_sam_name(lp_ctx);
1602 ac->domain = data;
1603 break;
1605 case LDB_REPLY_DONE:
1607 /* call the next step */
1608 switch (ac->req->operation) {
1609 case LDB_ADD:
1610 ret = password_hash_add_do_add(ac);
1611 break;
1613 case LDB_MODIFY:
1614 ret = password_hash_mod_do_mod(ac);
1615 break;
1617 default:
1618 ret = LDB_ERR_OPERATIONS_ERROR;
1619 break;
1621 if (ret != LDB_SUCCESS) {
1622 return ldb_module_done(ac->req, NULL, NULL, ret);
1624 break;
1626 case LDB_REPLY_REFERRAL:
1627 /* ignore */
1628 break;
1631 talloc_free(ares);
1632 return LDB_SUCCESS;
1635 static int build_domain_data_request(struct ph_context *ac)
1637 /* attrs[] is returned from this function in
1638 ac->dom_req->op.search.attrs, so it must be static, as
1639 otherwise the compiler can put it on the stack */
1640 struct ldb_context *ldb;
1641 static const char * const attrs[] = { "pwdProperties", "pwdHistoryLength", NULL };
1643 ldb = ldb_module_get_ctx(ac->module);
1645 return ldb_build_search_req(&ac->dom_req, ldb, ac,
1646 ldb_get_default_basedn(ldb),
1647 LDB_SCOPE_BASE,
1648 NULL, attrs,
1649 NULL,
1650 ac, get_domain_data_callback,
1651 ac->req);
1654 static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
1656 struct ldb_context *ldb;
1657 struct ph_context *ac;
1658 struct ldb_message_element *sambaAttr;
1659 struct ldb_message_element *clearTextPasswordAttr;
1660 struct ldb_message_element *ntAttr;
1661 struct ldb_message_element *lmAttr;
1662 int ret;
1664 ldb = ldb_module_get_ctx(module);
1666 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add\n");
1668 if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
1669 return ldb_next_request(module, req);
1672 /* If the caller is manipulating the local passwords directly, let them pass */
1673 if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
1674 req->op.add.message->dn) == 0) {
1675 return ldb_next_request(module, req);
1678 /* nobody must touch these fields */
1679 if (ldb_msg_find_element(req->op.add.message, "ntPwdHistory")) {
1680 return LDB_ERR_UNWILLING_TO_PERFORM;
1682 if (ldb_msg_find_element(req->op.add.message, "lmPwdHistory")) {
1683 return LDB_ERR_UNWILLING_TO_PERFORM;
1685 if (ldb_msg_find_element(req->op.add.message, "supplementalCredentials")) {
1686 return LDB_ERR_UNWILLING_TO_PERFORM;
1689 /* If no part of this ADD touches the userPassword, or the NT
1690 * or LM hashes, then we don't need to make any changes. */
1692 sambaAttr = ldb_msg_find_element(req->op.add.message, "userPassword");
1693 clearTextPasswordAttr = ldb_msg_find_element(req->op.add.message, "clearTextPassword");
1694 ntAttr = ldb_msg_find_element(req->op.add.message, "unicodePwd");
1695 lmAttr = ldb_msg_find_element(req->op.add.message, "dBCSPwd");
1697 if ((!sambaAttr) && (!clearTextPasswordAttr) && (!ntAttr) && (!lmAttr)) {
1698 return ldb_next_request(module, req);
1701 /* if it is not an entry of type person its an error */
1702 /* TODO: remove this when userPassword will be in schema */
1703 if (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "person")) {
1704 ldb_set_errstring(ldb, "Cannot set a password on entry that does not have objectClass 'person'");
1705 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1708 /* check userPassword is single valued here */
1709 /* TODO: remove this when userPassword will be single valued in schema */
1710 if (sambaAttr && sambaAttr->num_values > 1) {
1711 ldb_set_errstring(ldb, "mupltiple values for userPassword not allowed!\n");
1712 return LDB_ERR_CONSTRAINT_VIOLATION;
1714 if (clearTextPasswordAttr && clearTextPasswordAttr->num_values > 1) {
1715 ldb_set_errstring(ldb, "mupltiple values for clearTextPassword not allowed!\n");
1716 return LDB_ERR_CONSTRAINT_VIOLATION;
1719 if (ntAttr && (ntAttr->num_values > 1)) {
1720 ldb_set_errstring(ldb, "mupltiple values for unicodePwd not allowed!\n");
1721 return LDB_ERR_CONSTRAINT_VIOLATION;
1723 if (lmAttr && (lmAttr->num_values > 1)) {
1724 ldb_set_errstring(ldb, "mupltiple values for dBCSPwd not allowed!\n");
1725 return LDB_ERR_CONSTRAINT_VIOLATION;
1728 if (sambaAttr && sambaAttr->num_values == 0) {
1729 ldb_set_errstring(ldb, "userPassword must have a value!\n");
1730 return LDB_ERR_CONSTRAINT_VIOLATION;
1733 if (clearTextPasswordAttr && clearTextPasswordAttr->num_values == 0) {
1734 ldb_set_errstring(ldb, "clearTextPassword must have a value!\n");
1735 return LDB_ERR_CONSTRAINT_VIOLATION;
1738 if (ntAttr && (ntAttr->num_values == 0)) {
1739 ldb_set_errstring(ldb, "unicodePwd must have a value!\n");
1740 return LDB_ERR_CONSTRAINT_VIOLATION;
1742 if (lmAttr && (lmAttr->num_values == 0)) {
1743 ldb_set_errstring(ldb, "dBCSPwd must have a value!\n");
1744 return LDB_ERR_CONSTRAINT_VIOLATION;
1747 ac = ph_init_context(module, req);
1748 if (ac == NULL) {
1749 return LDB_ERR_OPERATIONS_ERROR;
1752 /* get user domain data */
1753 ret = build_domain_data_request(ac);
1754 if (ret != LDB_SUCCESS) {
1755 return ret;
1758 return ldb_next_request(module, ac->dom_req);
1761 static int password_hash_add_do_add(struct ph_context *ac)
1763 struct ldb_context *ldb;
1764 struct ldb_request *down_req;
1765 struct ldb_message *msg;
1766 struct setup_password_fields_io io;
1767 int ret;
1769 /* Prepare the internal data structure containing the passwords */
1770 ret = setup_io(ac, ac->req->op.add.message, ac->req->op.add.message, &io);
1771 if (ret != LDB_SUCCESS) {
1772 return ret;
1775 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
1776 if (msg == NULL) {
1777 return LDB_ERR_OPERATIONS_ERROR;
1780 /* remove attributes that we just read into 'io' */
1781 ldb_msg_remove_attr(msg, "userPassword");
1782 ldb_msg_remove_attr(msg, "clearTextPassword");
1783 ldb_msg_remove_attr(msg, "unicodePwd");
1784 ldb_msg_remove_attr(msg, "dBCSPwd");
1785 ldb_msg_remove_attr(msg, "pwdLastSet");
1786 io.o.kvno = samdb_result_uint(msg, "msDs-KeyVersionNumber", 1) - 1;
1787 ldb_msg_remove_attr(msg, "msDs-KeyVersionNumber");
1789 ldb = ldb_module_get_ctx(ac->module);
1791 ret = setup_password_fields(&io);
1792 if (ret != LDB_SUCCESS) {
1793 return ret;
1796 if (io.g.nt_hash) {
1797 ret = samdb_msg_add_hash(ldb, ac, msg,
1798 "unicodePwd", io.g.nt_hash);
1799 if (ret != LDB_SUCCESS) {
1800 return ret;
1803 if (io.g.lm_hash) {
1804 ret = samdb_msg_add_hash(ldb, ac, msg,
1805 "dBCSPwd", io.g.lm_hash);
1806 if (ret != LDB_SUCCESS) {
1807 return ret;
1810 if (io.g.nt_history_len > 0) {
1811 ret = samdb_msg_add_hashes(ac, msg,
1812 "ntPwdHistory",
1813 io.g.nt_history,
1814 io.g.nt_history_len);
1815 if (ret != LDB_SUCCESS) {
1816 return ret;
1819 if (io.g.lm_history_len > 0) {
1820 ret = samdb_msg_add_hashes(ac, msg,
1821 "lmPwdHistory",
1822 io.g.lm_history,
1823 io.g.lm_history_len);
1824 if (ret != LDB_SUCCESS) {
1825 return ret;
1828 if (io.g.supplemental.length > 0) {
1829 ret = ldb_msg_add_value(msg, "supplementalCredentials",
1830 &io.g.supplemental, NULL);
1831 if (ret != LDB_SUCCESS) {
1832 return ret;
1835 ret = samdb_msg_add_uint64(ldb, ac, msg,
1836 "pwdLastSet",
1837 io.g.last_set);
1838 if (ret != LDB_SUCCESS) {
1839 return ret;
1841 ret = samdb_msg_add_uint(ldb, ac, msg,
1842 "msDs-KeyVersionNumber",
1843 io.g.kvno);
1844 if (ret != LDB_SUCCESS) {
1845 return ret;
1848 ret = ldb_build_add_req(&down_req, ldb, ac,
1849 msg,
1850 ac->req->controls,
1851 ac, ph_op_callback,
1852 ac->req);
1853 if (ret != LDB_SUCCESS) {
1854 return ret;
1857 return ldb_next_request(ac->module, down_req);
1860 static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
1862 struct ldb_context *ldb;
1863 struct ph_context *ac;
1864 struct ldb_message_element *sambaAttr;
1865 struct ldb_message_element *clearTextAttr;
1866 struct ldb_message_element *ntAttr;
1867 struct ldb_message_element *lmAttr;
1868 struct ldb_message *msg;
1869 struct ldb_request *down_req;
1870 int ret;
1872 ldb = ldb_module_get_ctx(module);
1874 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
1876 if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
1877 return ldb_next_request(module, req);
1880 /* If the caller is manipulating the local passwords directly, let them pass */
1881 if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
1882 req->op.mod.message->dn) == 0) {
1883 return ldb_next_request(module, req);
1886 /* nobody must touch password Histories */
1887 if (ldb_msg_find_element(req->op.mod.message, "ntPwdHistory")) {
1888 return LDB_ERR_UNWILLING_TO_PERFORM;
1890 if (ldb_msg_find_element(req->op.mod.message, "lmPwdHistory")) {
1891 return LDB_ERR_UNWILLING_TO_PERFORM;
1893 if (ldb_msg_find_element(req->op.mod.message, "supplementalCredentials")) {
1894 return LDB_ERR_UNWILLING_TO_PERFORM;
1897 sambaAttr = ldb_msg_find_element(req->op.mod.message, "userPassword");
1898 clearTextAttr = ldb_msg_find_element(req->op.mod.message, "clearTextPassword");
1899 ntAttr = ldb_msg_find_element(req->op.mod.message, "unicodePwd");
1900 lmAttr = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
1902 /* If no part of this touches the userPassword OR
1903 * clearTextPassword OR unicodePwd and/or dBCSPwd, then we
1904 * don't need to make any changes. For password changes/set
1905 * there should be a 'delete' or a 'modify' on this
1906 * attribute. */
1907 if ((!sambaAttr) && (!clearTextAttr) && (!ntAttr) && (!lmAttr)) {
1908 return ldb_next_request(module, req);
1911 /* check passwords are single valued here */
1912 /* TODO: remove this when passwords will be single valued in schema */
1913 if (sambaAttr && (sambaAttr->num_values > 1)) {
1914 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
1915 return LDB_ERR_CONSTRAINT_VIOLATION;
1917 if (clearTextAttr && (clearTextAttr->num_values > 1)) {
1918 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
1919 return LDB_ERR_CONSTRAINT_VIOLATION;
1921 if (ntAttr && (ntAttr->num_values > 1)) {
1922 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
1923 return LDB_ERR_CONSTRAINT_VIOLATION;
1925 if (lmAttr && (lmAttr->num_values > 1)) {
1926 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
1927 return LDB_ERR_CONSTRAINT_VIOLATION;
1930 ac = ph_init_context(module, req);
1931 if (!ac) {
1932 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
1933 return LDB_ERR_OPERATIONS_ERROR;
1936 /* use a new message structure so that we can modify it */
1937 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
1938 if (msg == NULL) {
1939 ldb_oom(ldb);
1940 return LDB_ERR_OPERATIONS_ERROR;
1943 /* - remove any modification to the password from the first commit
1944 * we will make the real modification later */
1945 if (sambaAttr) ldb_msg_remove_attr(msg, "userPassword");
1946 if (clearTextAttr) ldb_msg_remove_attr(msg, "clearTextPassword");
1947 if (ntAttr) ldb_msg_remove_attr(msg, "unicodePwd");
1948 if (lmAttr) ldb_msg_remove_attr(msg, "dBCSPwd");
1950 /* if there was nothing else to be modified skip to next step */
1951 if (msg->num_elements == 0) {
1952 return password_hash_mod_search_self(ac);
1955 ret = ldb_build_mod_req(&down_req, ldb, ac,
1956 msg,
1957 req->controls,
1958 ac, ph_modify_callback,
1959 req);
1960 if (ret != LDB_SUCCESS) {
1961 return ret;
1964 return ldb_next_request(module, down_req);
1967 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
1969 struct ph_context *ac;
1970 int ret;
1972 ac = talloc_get_type(req->context, struct ph_context);
1974 if (!ares) {
1975 return ldb_module_done(ac->req, NULL, NULL,
1976 LDB_ERR_OPERATIONS_ERROR);
1978 if (ares->error != LDB_SUCCESS) {
1979 return ldb_module_done(ac->req, ares->controls,
1980 ares->response, ares->error);
1983 if (ares->type != LDB_REPLY_DONE) {
1984 talloc_free(ares);
1985 return ldb_module_done(ac->req, NULL, NULL,
1986 LDB_ERR_OPERATIONS_ERROR);
1989 ret = password_hash_mod_search_self(ac);
1990 if (ret != LDB_SUCCESS) {
1991 return ldb_module_done(ac->req, NULL, NULL, ret);
1994 talloc_free(ares);
1995 return LDB_SUCCESS;
1998 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
2000 struct ldb_context *ldb;
2001 struct ph_context *ac;
2002 int ret;
2004 ac = talloc_get_type(req->context, struct ph_context);
2005 ldb = ldb_module_get_ctx(ac->module);
2007 if (!ares) {
2008 return ldb_module_done(ac->req, NULL, NULL,
2009 LDB_ERR_OPERATIONS_ERROR);
2011 if (ares->error != LDB_SUCCESS) {
2012 return ldb_module_done(ac->req, ares->controls,
2013 ares->response, ares->error);
2016 /* we are interested only in the single reply (base search) */
2017 switch (ares->type) {
2018 case LDB_REPLY_ENTRY:
2020 if (ac->search_res != NULL) {
2021 ldb_set_errstring(ldb, "Too many results");
2022 talloc_free(ares);
2023 return ldb_module_done(ac->req, NULL, NULL,
2024 LDB_ERR_OPERATIONS_ERROR);
2027 /* if it is not an entry of type person this is an error */
2028 /* TODO: remove this when sambaPassword will be in schema */
2029 if (!ldb_msg_check_string_attribute(ares->message, "objectClass", "person")) {
2030 ldb_set_errstring(ldb, "Object class violation");
2031 talloc_free(ares);
2032 return ldb_module_done(ac->req, NULL, NULL,
2033 LDB_ERR_OBJECT_CLASS_VIOLATION);
2036 ac->search_res = talloc_steal(ac, ares);
2037 return LDB_SUCCESS;
2039 case LDB_REPLY_DONE:
2041 /* get user domain data */
2042 ret = build_domain_data_request(ac);
2043 if (ret != LDB_SUCCESS) {
2044 return ldb_module_done(ac->req, NULL, NULL,ret);
2047 return ldb_next_request(ac->module, ac->dom_req);
2049 case LDB_REPLY_REFERRAL:
2050 /*ignore anything else for now */
2051 break;
2054 talloc_free(ares);
2055 return LDB_SUCCESS;
2058 static int password_hash_mod_search_self(struct ph_context *ac)
2060 struct ldb_context *ldb;
2061 static const char * const attrs[] = { "userAccountControl", "lmPwdHistory",
2062 "ntPwdHistory",
2063 "objectSid", "msDS-KeyVersionNumber",
2064 "objectClass", "userPrincipalName",
2065 "sAMAccountName",
2066 "dBCSPwd", "unicodePwd",
2067 "supplementalCredentials",
2068 NULL };
2069 struct ldb_request *search_req;
2070 int ret;
2072 ldb = ldb_module_get_ctx(ac->module);
2074 ret = ldb_build_search_req(&search_req, ldb, ac,
2075 ac->req->op.mod.message->dn,
2076 LDB_SCOPE_BASE,
2077 "(objectclass=*)",
2078 attrs,
2079 NULL,
2080 ac, ph_mod_search_callback,
2081 ac->req);
2083 if (ret != LDB_SUCCESS) {
2084 return ret;
2087 return ldb_next_request(ac->module, search_req);
2090 static int password_hash_mod_do_mod(struct ph_context *ac)
2092 struct ldb_context *ldb;
2093 struct ldb_request *mod_req;
2094 struct ldb_message *msg;
2095 const struct ldb_message *searched_msg;
2096 struct setup_password_fields_io io;
2097 int ret;
2099 ldb = ldb_module_get_ctx(ac->module);
2101 /* use a new message structure so that we can modify it */
2102 msg = ldb_msg_new(ac);
2103 if (msg == NULL) {
2104 return LDB_ERR_OPERATIONS_ERROR;
2107 /* modify dn */
2108 msg->dn = ac->req->op.mod.message->dn;
2110 /* Prepare the internal data structure containing the passwords */
2111 ret = setup_io(ac,
2112 ac->req->op.mod.message,
2113 ac->search_res->message,
2114 &io);
2115 if (ret != LDB_SUCCESS) {
2116 return ret;
2119 searched_msg = ac->search_res->message;
2121 /* Fill in some final details (only relevent once the password has been set) */
2122 io.o.kvno = samdb_result_uint(searched_msg, "msDs-KeyVersionNumber", 0);
2123 io.o.nt_history_len = samdb_result_hashes(io.ac, searched_msg, "ntPwdHistory", &io.o.nt_history);
2124 io.o.lm_history_len = samdb_result_hashes(io.ac, searched_msg, "lmPwdHistory", &io.o.lm_history);
2125 io.o.supplemental = ldb_msg_find_ldb_val(searched_msg, "supplementalCredentials");
2127 ret = setup_password_fields(&io);
2128 if (ret != LDB_SUCCESS) {
2129 return ret;
2132 /* make sure we replace all the old attributes */
2133 ret = ldb_msg_add_empty(msg, "unicodePwd", LDB_FLAG_MOD_REPLACE, NULL);
2134 ret = ldb_msg_add_empty(msg, "dBCSPwd", LDB_FLAG_MOD_REPLACE, NULL);
2135 ret = ldb_msg_add_empty(msg, "ntPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
2136 ret = ldb_msg_add_empty(msg, "lmPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
2137 ret = ldb_msg_add_empty(msg, "supplementalCredentials", LDB_FLAG_MOD_REPLACE, NULL);
2138 ret = ldb_msg_add_empty(msg, "pwdLastSet", LDB_FLAG_MOD_REPLACE, NULL);
2139 ret = ldb_msg_add_empty(msg, "msDs-KeyVersionNumber", LDB_FLAG_MOD_REPLACE, NULL);
2141 if (io.g.nt_hash) {
2142 ret = samdb_msg_add_hash(ldb, ac, msg,
2143 "unicodePwd", io.g.nt_hash);
2144 if (ret != LDB_SUCCESS) {
2145 return ret;
2148 if (io.g.lm_hash) {
2149 ret = samdb_msg_add_hash(ldb, ac, msg,
2150 "dBCSPwd", io.g.lm_hash);
2151 if (ret != LDB_SUCCESS) {
2152 return ret;
2155 if (io.g.nt_history_len > 0) {
2156 ret = samdb_msg_add_hashes(ac, msg,
2157 "ntPwdHistory",
2158 io.g.nt_history,
2159 io.g.nt_history_len);
2160 if (ret != LDB_SUCCESS) {
2161 return ret;
2164 if (io.g.lm_history_len > 0) {
2165 ret = samdb_msg_add_hashes(ac, msg,
2166 "lmPwdHistory",
2167 io.g.lm_history,
2168 io.g.lm_history_len);
2169 if (ret != LDB_SUCCESS) {
2170 return ret;
2173 if (io.g.supplemental.length > 0) {
2174 ret = ldb_msg_add_value(msg, "supplementalCredentials",
2175 &io.g.supplemental, NULL);
2176 if (ret != LDB_SUCCESS) {
2177 return ret;
2180 ret = samdb_msg_add_uint64(ldb, ac, msg,
2181 "pwdLastSet",
2182 io.g.last_set);
2183 if (ret != LDB_SUCCESS) {
2184 return ret;
2186 ret = samdb_msg_add_uint(ldb, ac, msg,
2187 "msDs-KeyVersionNumber",
2188 io.g.kvno);
2189 if (ret != LDB_SUCCESS) {
2190 return ret;
2193 ret = ldb_build_mod_req(&mod_req, ldb, ac,
2194 msg,
2195 ac->req->controls,
2196 ac, ph_op_callback,
2197 ac->req);
2198 if (ret != LDB_SUCCESS) {
2199 return ret;
2202 return ldb_next_request(ac->module, mod_req);
2205 _PUBLIC_ const struct ldb_module_ops ldb_password_hash_module_ops = {
2206 .name = "password_hash",
2207 .add = password_hash_add,
2208 .modify = password_hash_modify,