lib/util Split data_blob_hex_string() into upper and lower
[Samba/ekacnet.git] / source4 / dsdb / samdb / ldb_modules / password_hash.c
blob8791db2bc4fcd4d31cf223e25f2ae5af0b9fc1c9
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 uint_t pwdProperties;
88 uint_t 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;
1028 int *domainFunctionality;
1030 ZERO_STRUCT(zero16);
1031 ZERO_STRUCT(names);
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
1040 return LDB_SUCCESS;
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")),
1047 &_old_scb,
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",
1054 nt_errstr(status));
1055 return LDB_ERR_OPERATIONS_ERROR;
1058 if (_old_scb.sub.signature == SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
1059 old_scb = &_old_scb;
1060 } else {
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);
1067 /* Per MS-SAMR 3.1.1.8.11.6 we create AES keys if our domain functionality level is 2008 or higher */
1068 domainFunctionality = talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
1070 do_newer_keys = *domainFunctionality &&
1071 (*domainFunctionality >= DS_DOMAIN_FUNCTION_2008);
1073 if (io->domain->store_cleartext &&
1074 (io->u.user_account_control & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) {
1075 do_cleartext = true;
1079 * The ordering is this
1081 * Primary:Kerberos-Newer-Keys (optional)
1082 * Primary:Kerberos
1083 * Primary:WDigest
1084 * Primary:CLEARTEXT (optional)
1086 * And the 'Packages' package is insert before the last
1087 * other package.
1089 if (do_newer_keys) {
1090 /* Primary:Kerberos-Newer-Keys */
1091 nkn = &names[num_names++];
1092 pkn = &packages[num_packages++];
1095 /* Primary:Kerberos */
1096 nk = &names[num_names++];
1097 pk = &packages[num_packages++];
1099 if (!do_cleartext) {
1100 /* Packages */
1101 pp = &packages[num_packages++];
1104 /* Primary:WDigest */
1105 nd = &names[num_names++];
1106 pd = &packages[num_packages++];
1108 if (do_cleartext) {
1109 /* Packages */
1110 pp = &packages[num_packages++];
1112 /* Primary:CLEARTEXT */
1113 nc = &names[num_names++];
1114 pc = &packages[num_packages++];
1117 if (pkn) {
1119 * setup 'Primary:Kerberos-Newer-Keys' element
1121 *nkn = "Kerberos-Newer-Keys";
1123 ret = setup_primary_kerberos_newer(io, old_scb, &pknb);
1124 if (ret != LDB_SUCCESS) {
1125 return ret;
1128 ndr_err = ndr_push_struct_blob(&pknb_blob, io->ac,
1129 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1130 &pknb,
1131 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1132 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1133 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1134 ldb_asprintf_errstring(ldb,
1135 "setup_supplemental_field: "
1136 "failed to push package_PrimaryKerberosNeverBlob: %s",
1137 nt_errstr(status));
1138 return LDB_ERR_OPERATIONS_ERROR;
1140 pknb_hexstr = data_blob_hex_string_upper(io->ac, &pknb_blob);
1141 if (!pknb_hexstr) {
1142 ldb_oom(ldb);
1143 return LDB_ERR_OPERATIONS_ERROR;
1145 pkn->name = "Primary:Kerberos-Newer-Keys";
1146 pkn->reserved = 1;
1147 pkn->data = pknb_hexstr;
1151 * setup 'Primary:Kerberos' element
1153 *nk = "Kerberos";
1155 ret = setup_primary_kerberos(io, old_scb, &pkb);
1156 if (ret != LDB_SUCCESS) {
1157 return ret;
1160 ndr_err = ndr_push_struct_blob(&pkb_blob, io->ac,
1161 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1162 &pkb,
1163 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1164 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1165 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1166 ldb_asprintf_errstring(ldb,
1167 "setup_supplemental_field: "
1168 "failed to push package_PrimaryKerberosBlob: %s",
1169 nt_errstr(status));
1170 return LDB_ERR_OPERATIONS_ERROR;
1172 pkb_hexstr = data_blob_hex_string_upper(io->ac, &pkb_blob);
1173 if (!pkb_hexstr) {
1174 ldb_oom(ldb);
1175 return LDB_ERR_OPERATIONS_ERROR;
1177 pk->name = "Primary:Kerberos";
1178 pk->reserved = 1;
1179 pk->data = pkb_hexstr;
1182 * setup 'Primary:WDigest' element
1184 *nd = "WDigest";
1186 ret = setup_primary_wdigest(io, old_scb, &pdb);
1187 if (ret != LDB_SUCCESS) {
1188 return ret;
1191 ndr_err = ndr_push_struct_blob(&pdb_blob, io->ac,
1192 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1193 &pdb,
1194 (ndr_push_flags_fn_t)ndr_push_package_PrimaryWDigestBlob);
1195 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1196 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1197 ldb_asprintf_errstring(ldb,
1198 "setup_supplemental_field: "
1199 "failed to push package_PrimaryWDigestBlob: %s",
1200 nt_errstr(status));
1201 return LDB_ERR_OPERATIONS_ERROR;
1203 pdb_hexstr = data_blob_hex_string_upper(io->ac, &pdb_blob);
1204 if (!pdb_hexstr) {
1205 ldb_oom(ldb);
1206 return LDB_ERR_OPERATIONS_ERROR;
1208 pd->name = "Primary:WDigest";
1209 pd->reserved = 1;
1210 pd->data = pdb_hexstr;
1213 * setup 'Primary:CLEARTEXT' element
1215 if (pc) {
1216 *nc = "CLEARTEXT";
1218 pcb.cleartext = *io->n.cleartext_utf16;
1220 ndr_err = ndr_push_struct_blob(&pcb_blob, io->ac,
1221 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1222 &pcb,
1223 (ndr_push_flags_fn_t)ndr_push_package_PrimaryCLEARTEXTBlob);
1224 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1225 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1226 ldb_asprintf_errstring(ldb,
1227 "setup_supplemental_field: "
1228 "failed to push package_PrimaryCLEARTEXTBlob: %s",
1229 nt_errstr(status));
1230 return LDB_ERR_OPERATIONS_ERROR;
1232 pcb_hexstr = data_blob_hex_string_upper(io->ac, &pcb_blob);
1233 if (!pcb_hexstr) {
1234 ldb_oom(ldb);
1235 return LDB_ERR_OPERATIONS_ERROR;
1237 pc->name = "Primary:CLEARTEXT";
1238 pc->reserved = 1;
1239 pc->data = pcb_hexstr;
1243 * setup 'Packages' element
1245 pb.names = names;
1246 ndr_err = ndr_push_struct_blob(&pb_blob, io->ac,
1247 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1248 &pb,
1249 (ndr_push_flags_fn_t)ndr_push_package_PackagesBlob);
1250 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1251 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1252 ldb_asprintf_errstring(ldb,
1253 "setup_supplemental_field: "
1254 "failed to push package_PackagesBlob: %s",
1255 nt_errstr(status));
1256 return LDB_ERR_OPERATIONS_ERROR;
1258 pb_hexstr = data_blob_hex_string_upper(io->ac, &pb_blob);
1259 if (!pb_hexstr) {
1260 ldb_oom(ldb);
1261 return LDB_ERR_OPERATIONS_ERROR;
1263 pp->name = "Packages";
1264 pp->reserved = 2;
1265 pp->data = pb_hexstr;
1268 * setup 'supplementalCredentials' value
1270 ZERO_STRUCT(scb);
1271 scb.sub.num_packages = num_packages;
1272 scb.sub.packages = packages;
1274 ndr_err = ndr_push_struct_blob(&io->g.supplemental, io->ac,
1275 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1276 &scb,
1277 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
1278 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1279 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1280 ldb_asprintf_errstring(ldb,
1281 "setup_supplemental_field: "
1282 "failed to push supplementalCredentialsBlob: %s",
1283 nt_errstr(status));
1284 return LDB_ERR_OPERATIONS_ERROR;
1287 return LDB_SUCCESS;
1290 static int setup_last_set_field(struct setup_password_fields_io *io)
1292 /* set it as now */
1293 unix_to_nt_time(&io->g.last_set, time(NULL));
1295 return LDB_SUCCESS;
1298 static int setup_kvno_field(struct setup_password_fields_io *io)
1300 /* increment by one */
1301 io->g.kvno = io->o.kvno + 1;
1303 return LDB_SUCCESS;
1306 static int setup_password_fields(struct setup_password_fields_io *io)
1308 struct ldb_context *ldb;
1309 bool ok;
1310 int ret;
1311 size_t converted_pw_len;
1313 ldb = ldb_module_get_ctx(io->ac->module);
1316 * refuse the change if someone want to change the cleartext
1317 * and supply his own hashes at the same time...
1319 if ((io->n.cleartext_utf8 || io->n.cleartext_utf16) && (io->n.nt_hash || io->n.lm_hash)) {
1320 ldb_asprintf_errstring(ldb,
1321 "setup_password_fields: "
1322 "it's only allowed to set the cleartext password or the password hashes");
1323 return LDB_ERR_UNWILLING_TO_PERFORM;
1326 if (io->n.cleartext_utf8 && io->n.cleartext_utf16) {
1327 ldb_asprintf_errstring(ldb,
1328 "setup_password_fields: "
1329 "it's only allowed to set the cleartext password as userPassword or clearTextPasssword, not both at once");
1330 return LDB_ERR_UNWILLING_TO_PERFORM;
1333 if (io->n.cleartext_utf8) {
1334 char **cleartext_utf16_str;
1335 struct ldb_val *cleartext_utf16_blob;
1336 io->n.cleartext_utf16 = cleartext_utf16_blob = talloc(io->ac, struct ldb_val);
1337 if (!io->n.cleartext_utf16) {
1338 ldb_oom(ldb);
1339 return LDB_ERR_OPERATIONS_ERROR;
1341 if (!convert_string_talloc_convenience(io->ac, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1342 CH_UTF8, CH_UTF16, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length,
1343 (void **)&cleartext_utf16_str, &converted_pw_len, false)) {
1344 ldb_asprintf_errstring(ldb,
1345 "setup_password_fields: "
1346 "failed to generate UTF16 password from cleartext UTF8 password");
1347 return LDB_ERR_OPERATIONS_ERROR;
1349 *cleartext_utf16_blob = data_blob_const(cleartext_utf16_str, converted_pw_len);
1350 } else if (io->n.cleartext_utf16) {
1351 char *cleartext_utf8_str;
1352 struct ldb_val *cleartext_utf8_blob;
1353 io->n.cleartext_utf8 = cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
1354 if (!io->n.cleartext_utf8) {
1355 ldb_oom(ldb);
1356 return LDB_ERR_OPERATIONS_ERROR;
1358 if (!convert_string_talloc_convenience(io->ac, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1359 CH_UTF16MUNGED, CH_UTF8, io->n.cleartext_utf16->data, io->n.cleartext_utf16->length,
1360 (void **)&cleartext_utf8_str, &converted_pw_len, false)) {
1361 /* We can't bail out entirely, as these unconvertable passwords are frustratingly valid */
1362 io->n.cleartext_utf8 = NULL;
1363 talloc_free(cleartext_utf8_blob);
1365 *cleartext_utf8_blob = data_blob_const(cleartext_utf8_str, converted_pw_len);
1367 if (io->n.cleartext_utf16) {
1368 struct samr_Password *nt_hash;
1369 nt_hash = talloc(io->ac, struct samr_Password);
1370 if (!nt_hash) {
1371 ldb_oom(ldb);
1372 return LDB_ERR_OPERATIONS_ERROR;
1374 io->n.nt_hash = nt_hash;
1376 /* compute the new nt hash */
1377 mdfour(nt_hash->hash, io->n.cleartext_utf16->data, io->n.cleartext_utf16->length);
1380 if (io->n.cleartext_utf8) {
1381 struct samr_Password *lm_hash;
1382 char *cleartext_unix;
1383 if (lp_lanman_auth(ldb_get_opaque(ldb, "loadparm")) &&
1384 convert_string_talloc_convenience(io->ac, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1385 CH_UTF8, CH_UNIX, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length,
1386 (void **)&cleartext_unix, &converted_pw_len, false)) {
1387 lm_hash = talloc(io->ac, struct samr_Password);
1388 if (!lm_hash) {
1389 ldb_oom(ldb);
1390 return LDB_ERR_OPERATIONS_ERROR;
1393 /* compute the new lm hash. */
1394 ok = E_deshash((char *)cleartext_unix, lm_hash->hash);
1395 if (ok) {
1396 io->n.lm_hash = lm_hash;
1397 } else {
1398 talloc_free(lm_hash->hash);
1402 ret = setup_kerberos_keys(io);
1403 if (ret != LDB_SUCCESS) {
1404 return ret;
1408 ret = setup_nt_fields(io);
1409 if (ret != LDB_SUCCESS) {
1410 return ret;
1413 ret = setup_lm_fields(io);
1414 if (ret != LDB_SUCCESS) {
1415 return ret;
1418 ret = setup_supplemental_field(io);
1419 if (ret != LDB_SUCCESS) {
1420 return ret;
1423 ret = setup_last_set_field(io);
1424 if (ret != LDB_SUCCESS) {
1425 return ret;
1428 ret = setup_kvno_field(io);
1429 if (ret != LDB_SUCCESS) {
1430 return ret;
1433 return LDB_SUCCESS;
1436 static int setup_io(struct ph_context *ac,
1437 const struct ldb_message *new_msg,
1438 const struct ldb_message *searched_msg,
1439 struct setup_password_fields_io *io)
1441 const struct ldb_val *quoted_utf16;
1442 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1444 ZERO_STRUCTP(io);
1446 /* Some operations below require kerberos contexts */
1447 if (smb_krb5_init_context(ac,
1448 ldb_get_event_context(ldb),
1449 (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"),
1450 &io->smb_krb5_context) != 0) {
1451 return LDB_ERR_OPERATIONS_ERROR;
1454 io->ac = ac;
1455 io->domain = ac->domain;
1457 io->u.user_account_control = samdb_result_uint(searched_msg, "userAccountControl", 0);
1458 io->u.sAMAccountName = samdb_result_string(searched_msg, "samAccountName", NULL);
1459 io->u.user_principal_name = samdb_result_string(searched_msg, "userPrincipalName", NULL);
1460 io->u.is_computer = ldb_msg_check_string_attribute(searched_msg, "objectClass", "computer");
1462 io->n.cleartext_utf8 = ldb_msg_find_ldb_val(new_msg, "userPassword");
1463 io->n.cleartext_utf16 = ldb_msg_find_ldb_val(new_msg, "clearTextPassword");
1465 /* this rather strange looking piece of code is there to
1466 handle a ldap client setting a password remotely using the
1467 unicodePwd ldap field. The syntax is that the password is
1468 in UTF-16LE, with a " at either end. Unfortunately the
1469 unicodePwd field is also used to store the nt hashes
1470 internally in Samba, and is used in the nt hash format on
1471 the wire in DRS replication, so we have a single name for
1472 two distinct values. The code below leaves us with a small
1473 chance (less than 1 in 2^32) of a mixup, if someone manages
1474 to create a MD4 hash which starts and ends in 0x22 0x00, as
1475 that would then be treated as a UTF16 password rather than
1476 a nthash */
1477 quoted_utf16 = ldb_msg_find_ldb_val(new_msg, "unicodePwd");
1478 if (quoted_utf16 &&
1479 quoted_utf16->length >= 4 &&
1480 quoted_utf16->data[0] == '"' &&
1481 quoted_utf16->data[1] == 0 &&
1482 quoted_utf16->data[quoted_utf16->length-2] == '"' &&
1483 quoted_utf16->data[quoted_utf16->length-1] == 0) {
1484 io->n.quoted_utf16.data = talloc_memdup(io->ac, quoted_utf16->data+2, quoted_utf16->length-4);
1485 io->n.quoted_utf16.length = quoted_utf16->length-4;
1486 io->n.cleartext_utf16 = &io->n.quoted_utf16;
1487 io->n.nt_hash = NULL;
1488 } else {
1489 io->n.nt_hash = samdb_result_hash(io->ac, new_msg, "unicodePwd");
1492 io->n.lm_hash = samdb_result_hash(io->ac, new_msg, "dBCSPwd");
1494 return LDB_SUCCESS;
1497 static struct ph_context *ph_init_context(struct ldb_module *module,
1498 struct ldb_request *req)
1500 struct ldb_context *ldb;
1501 struct ph_context *ac;
1503 ldb = ldb_module_get_ctx(module);
1505 ac = talloc_zero(req, struct ph_context);
1506 if (ac == NULL) {
1507 ldb_set_errstring(ldb, "Out of Memory");
1508 return NULL;
1511 ac->module = module;
1512 ac->req = req;
1514 return ac;
1517 static int ph_op_callback(struct ldb_request *req, struct ldb_reply *ares)
1519 struct ph_context *ac;
1521 ac = talloc_get_type(req->context, struct ph_context);
1523 if (!ares) {
1524 return ldb_module_done(ac->req, NULL, NULL,
1525 LDB_ERR_OPERATIONS_ERROR);
1527 if (ares->error != LDB_SUCCESS) {
1528 return ldb_module_done(ac->req, ares->controls,
1529 ares->response, ares->error);
1532 if (ares->type != LDB_REPLY_DONE) {
1533 talloc_free(ares);
1534 return ldb_module_done(ac->req, NULL, NULL,
1535 LDB_ERR_OPERATIONS_ERROR);
1538 return ldb_module_done(ac->req, ares->controls,
1539 ares->response, ares->error);
1542 static int password_hash_add_do_add(struct ph_context *ac);
1543 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares);
1544 static int password_hash_mod_search_self(struct ph_context *ac);
1545 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares);
1546 static int password_hash_mod_do_mod(struct ph_context *ac);
1548 static int get_domain_data_callback(struct ldb_request *req,
1549 struct ldb_reply *ares)
1551 struct ldb_context *ldb;
1552 struct domain_data *data;
1553 struct ph_context *ac;
1554 struct loadparm_context *lp_ctx;
1555 int ret;
1557 ac = talloc_get_type(req->context, struct ph_context);
1558 ldb = ldb_module_get_ctx(ac->module);
1560 if (!ares) {
1561 return ldb_module_done(ac->req, NULL, NULL,
1562 LDB_ERR_OPERATIONS_ERROR);
1564 if (ares->error != LDB_SUCCESS) {
1565 return ldb_module_done(ac->req, ares->controls,
1566 ares->response, ares->error);
1569 switch (ares->type) {
1570 case LDB_REPLY_ENTRY:
1571 if (ac->domain != NULL) {
1572 ldb_set_errstring(ldb, "Too many results");
1573 return ldb_module_done(ac->req, NULL, NULL,
1574 LDB_ERR_OPERATIONS_ERROR);
1577 data = talloc_zero(ac, struct domain_data);
1578 if (data == NULL) {
1579 return ldb_module_done(ac->req, NULL, NULL,
1580 LDB_ERR_OPERATIONS_ERROR);
1583 data->pwdProperties = samdb_result_uint(ares->message, "pwdProperties", 0);
1584 data->store_cleartext = data->pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
1585 data->pwdHistoryLength = samdb_result_uint(ares->message, "pwdHistoryLength", 0);
1587 /* For a domain DN, this puts things in dotted notation */
1588 /* For builtin domains, this will give details for the host,
1589 * but that doesn't really matter, as it's just used for salt
1590 * and kerberos principals, which don't exist here */
1592 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
1593 struct loadparm_context);
1595 data->dns_domain = lp_dnsdomain(lp_ctx);
1596 data->realm = lp_realm(lp_ctx);
1597 data->netbios_domain = lp_sam_name(lp_ctx);
1599 ac->domain = data;
1600 break;
1602 case LDB_REPLY_DONE:
1604 /* call the next step */
1605 switch (ac->req->operation) {
1606 case LDB_ADD:
1607 ret = password_hash_add_do_add(ac);
1608 break;
1610 case LDB_MODIFY:
1611 ret = password_hash_mod_do_mod(ac);
1612 break;
1614 default:
1615 ret = LDB_ERR_OPERATIONS_ERROR;
1616 break;
1618 if (ret != LDB_SUCCESS) {
1619 return ldb_module_done(ac->req, NULL, NULL, ret);
1621 break;
1623 case LDB_REPLY_REFERRAL:
1624 /* ignore */
1625 break;
1628 talloc_free(ares);
1629 return LDB_SUCCESS;
1632 static int build_domain_data_request(struct ph_context *ac)
1634 /* attrs[] is returned from this function in
1635 ac->dom_req->op.search.attrs, so it must be static, as
1636 otherwise the compiler can put it on the stack */
1637 struct ldb_context *ldb;
1638 static const char * const attrs[] = { "pwdProperties", "pwdHistoryLength", NULL };
1640 ldb = ldb_module_get_ctx(ac->module);
1642 return ldb_build_search_req(&ac->dom_req, ldb, ac,
1643 ldb_get_default_basedn(ldb),
1644 LDB_SCOPE_BASE,
1645 NULL, attrs,
1646 NULL,
1647 ac, get_domain_data_callback,
1648 ac->req);
1651 static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
1653 struct ldb_context *ldb;
1654 struct ph_context *ac;
1655 struct ldb_message_element *sambaAttr;
1656 struct ldb_message_element *clearTextPasswordAttr;
1657 struct ldb_message_element *ntAttr;
1658 struct ldb_message_element *lmAttr;
1659 int ret;
1661 ldb = ldb_module_get_ctx(module);
1663 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add\n");
1665 if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
1666 return ldb_next_request(module, req);
1669 /* If the caller is manipulating the local passwords directly, let them pass */
1670 if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
1671 req->op.add.message->dn) == 0) {
1672 return ldb_next_request(module, req);
1675 /* nobody must touch these fields */
1676 if (ldb_msg_find_element(req->op.add.message, "ntPwdHistory")) {
1677 return LDB_ERR_UNWILLING_TO_PERFORM;
1679 if (ldb_msg_find_element(req->op.add.message, "lmPwdHistory")) {
1680 return LDB_ERR_UNWILLING_TO_PERFORM;
1682 if (ldb_msg_find_element(req->op.add.message, "supplementalCredentials")) {
1683 return LDB_ERR_UNWILLING_TO_PERFORM;
1686 /* If no part of this ADD touches the userPassword, or the NT
1687 * or LM hashes, then we don't need to make any changes. */
1689 sambaAttr = ldb_msg_find_element(req->op.mod.message, "userPassword");
1690 clearTextPasswordAttr = ldb_msg_find_element(req->op.mod.message, "clearTextPassword");
1691 ntAttr = ldb_msg_find_element(req->op.mod.message, "unicodePwd");
1692 lmAttr = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
1694 if ((!sambaAttr) && (!clearTextPasswordAttr) && (!ntAttr) && (!lmAttr)) {
1695 return ldb_next_request(module, req);
1698 /* if it is not an entry of type person its an error */
1699 /* TODO: remove this when userPassword will be in schema */
1700 if (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "person")) {
1701 ldb_set_errstring(ldb, "Cannot set a password on entry that does not have objectClass 'person'");
1702 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1705 /* check userPassword is single valued here */
1706 /* TODO: remove this when userPassword will be single valued in schema */
1707 if (sambaAttr && sambaAttr->num_values > 1) {
1708 ldb_set_errstring(ldb, "mupltiple values for userPassword not allowed!\n");
1709 return LDB_ERR_CONSTRAINT_VIOLATION;
1711 if (clearTextPasswordAttr && clearTextPasswordAttr->num_values > 1) {
1712 ldb_set_errstring(ldb, "mupltiple values for clearTextPassword not allowed!\n");
1713 return LDB_ERR_CONSTRAINT_VIOLATION;
1716 if (ntAttr && (ntAttr->num_values > 1)) {
1717 ldb_set_errstring(ldb, "mupltiple values for unicodePwd not allowed!\n");
1718 return LDB_ERR_CONSTRAINT_VIOLATION;
1720 if (lmAttr && (lmAttr->num_values > 1)) {
1721 ldb_set_errstring(ldb, "mupltiple values for dBCSPwd not allowed!\n");
1722 return LDB_ERR_CONSTRAINT_VIOLATION;
1725 if (sambaAttr && sambaAttr->num_values == 0) {
1726 ldb_set_errstring(ldb, "userPassword must have a value!\n");
1727 return LDB_ERR_CONSTRAINT_VIOLATION;
1730 if (clearTextPasswordAttr && clearTextPasswordAttr->num_values == 0) {
1731 ldb_set_errstring(ldb, "clearTextPassword must have a value!\n");
1732 return LDB_ERR_CONSTRAINT_VIOLATION;
1735 if (ntAttr && (ntAttr->num_values == 0)) {
1736 ldb_set_errstring(ldb, "unicodePwd must have a value!\n");
1737 return LDB_ERR_CONSTRAINT_VIOLATION;
1739 if (lmAttr && (lmAttr->num_values == 0)) {
1740 ldb_set_errstring(ldb, "dBCSPwd must have a value!\n");
1741 return LDB_ERR_CONSTRAINT_VIOLATION;
1744 ac = ph_init_context(module, req);
1745 if (ac == NULL) {
1746 return LDB_ERR_OPERATIONS_ERROR;
1749 /* get user domain data */
1750 ret = build_domain_data_request(ac);
1751 if (ret != LDB_SUCCESS) {
1752 return ret;
1755 return ldb_next_request(module, ac->dom_req);
1758 static int password_hash_add_do_add(struct ph_context *ac)
1760 struct ldb_context *ldb;
1761 struct ldb_request *down_req;
1762 struct ldb_message *msg;
1763 struct setup_password_fields_io io;
1764 int ret;
1766 /* Prepare the internal data structure containing the passwords */
1767 ret = setup_io(ac, ac->req->op.add.message, ac->req->op.add.message, &io);
1768 if (ret != LDB_SUCCESS) {
1769 return ret;
1772 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
1773 if (msg == NULL) {
1774 return LDB_ERR_OPERATIONS_ERROR;
1777 /* remove attributes that we just read into 'io' */
1778 ldb_msg_remove_attr(msg, "userPassword");
1779 ldb_msg_remove_attr(msg, "clearTextPassword");
1780 ldb_msg_remove_attr(msg, "unicodePwd");
1781 ldb_msg_remove_attr(msg, "dBCSPwd");
1782 ldb_msg_remove_attr(msg, "pwdLastSet");
1783 io.o.kvno = samdb_result_uint(msg, "msDs-KeyVersionNumber", 1) - 1;
1784 ldb_msg_remove_attr(msg, "msDs-KeyVersionNumber");
1786 ldb = ldb_module_get_ctx(ac->module);
1788 ret = setup_password_fields(&io);
1789 if (ret != LDB_SUCCESS) {
1790 return ret;
1793 if (io.g.nt_hash) {
1794 ret = samdb_msg_add_hash(ldb, ac, msg,
1795 "unicodePwd", io.g.nt_hash);
1796 if (ret != LDB_SUCCESS) {
1797 return ret;
1800 if (io.g.lm_hash) {
1801 ret = samdb_msg_add_hash(ldb, ac, msg,
1802 "dBCSPwd", io.g.lm_hash);
1803 if (ret != LDB_SUCCESS) {
1804 return ret;
1807 if (io.g.nt_history_len > 0) {
1808 ret = samdb_msg_add_hashes(ac, msg,
1809 "ntPwdHistory",
1810 io.g.nt_history,
1811 io.g.nt_history_len);
1812 if (ret != LDB_SUCCESS) {
1813 return ret;
1816 if (io.g.lm_history_len > 0) {
1817 ret = samdb_msg_add_hashes(ac, msg,
1818 "lmPwdHistory",
1819 io.g.lm_history,
1820 io.g.lm_history_len);
1821 if (ret != LDB_SUCCESS) {
1822 return ret;
1825 if (io.g.supplemental.length > 0) {
1826 ret = ldb_msg_add_value(msg, "supplementalCredentials",
1827 &io.g.supplemental, NULL);
1828 if (ret != LDB_SUCCESS) {
1829 return ret;
1832 ret = samdb_msg_add_uint64(ldb, ac, msg,
1833 "pwdLastSet",
1834 io.g.last_set);
1835 if (ret != LDB_SUCCESS) {
1836 return ret;
1838 ret = samdb_msg_add_uint(ldb, ac, msg,
1839 "msDs-KeyVersionNumber",
1840 io.g.kvno);
1841 if (ret != LDB_SUCCESS) {
1842 return ret;
1845 ret = ldb_build_add_req(&down_req, ldb, ac,
1846 msg,
1847 ac->req->controls,
1848 ac, ph_op_callback,
1849 ac->req);
1850 if (ret != LDB_SUCCESS) {
1851 return ret;
1854 return ldb_next_request(ac->module, down_req);
1857 static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
1859 struct ldb_context *ldb;
1860 struct ph_context *ac;
1861 struct ldb_message_element *sambaAttr;
1862 struct ldb_message_element *clearTextAttr;
1863 struct ldb_message_element *ntAttr;
1864 struct ldb_message_element *lmAttr;
1865 struct ldb_message *msg;
1866 struct ldb_request *down_req;
1867 int ret;
1869 ldb = ldb_module_get_ctx(module);
1871 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
1873 if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
1874 return ldb_next_request(module, req);
1877 /* If the caller is manipulating the local passwords directly, let them pass */
1878 if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
1879 req->op.mod.message->dn) == 0) {
1880 return ldb_next_request(module, req);
1883 /* nobody must touch password Histories */
1884 if (ldb_msg_find_element(req->op.add.message, "ntPwdHistory")) {
1885 return LDB_ERR_UNWILLING_TO_PERFORM;
1887 if (ldb_msg_find_element(req->op.add.message, "lmPwdHistory")) {
1888 return LDB_ERR_UNWILLING_TO_PERFORM;
1890 if (ldb_msg_find_element(req->op.add.message, "supplementalCredentials")) {
1891 return LDB_ERR_UNWILLING_TO_PERFORM;
1894 sambaAttr = ldb_msg_find_element(req->op.mod.message, "userPassword");
1895 clearTextAttr = ldb_msg_find_element(req->op.mod.message, "clearTextPassword");
1896 ntAttr = ldb_msg_find_element(req->op.mod.message, "unicodePwd");
1897 lmAttr = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
1899 /* If no part of this touches the userPassword OR
1900 * clearTextPassword OR unicodePwd and/or dBCSPwd, then we
1901 * don't need to make any changes. For password changes/set
1902 * there should be a 'delete' or a 'modify' on this
1903 * attribute. */
1904 if ((!sambaAttr) && (!clearTextAttr) && (!ntAttr) && (!lmAttr)) {
1905 return ldb_next_request(module, req);
1908 /* check passwords are single valued here */
1909 /* TODO: remove this when passwords will be single valued in schema */
1910 if (sambaAttr && (sambaAttr->num_values > 1)) {
1911 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
1912 return LDB_ERR_CONSTRAINT_VIOLATION;
1914 if (clearTextAttr && (clearTextAttr->num_values > 1)) {
1915 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
1916 return LDB_ERR_CONSTRAINT_VIOLATION;
1918 if (ntAttr && (ntAttr->num_values > 1)) {
1919 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
1920 return LDB_ERR_CONSTRAINT_VIOLATION;
1922 if (lmAttr && (lmAttr->num_values > 1)) {
1923 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
1924 return LDB_ERR_CONSTRAINT_VIOLATION;
1927 ac = ph_init_context(module, req);
1928 if (!ac) {
1929 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
1930 return LDB_ERR_OPERATIONS_ERROR;
1933 /* use a new message structure so that we can modify it */
1934 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
1935 if (msg == NULL) {
1936 ldb_oom(ldb);
1937 return LDB_ERR_OPERATIONS_ERROR;
1940 /* - remove any modification to the password from the first commit
1941 * we will make the real modification later */
1942 if (sambaAttr) ldb_msg_remove_attr(msg, "userPassword");
1943 if (clearTextAttr) ldb_msg_remove_attr(msg, "clearTextPassword");
1944 if (ntAttr) ldb_msg_remove_attr(msg, "unicodePwd");
1945 if (lmAttr) ldb_msg_remove_attr(msg, "dBCSPwd");
1947 /* if there was nothing else to be modified skip to next step */
1948 if (msg->num_elements == 0) {
1949 return password_hash_mod_search_self(ac);
1952 ret = ldb_build_mod_req(&down_req, ldb, ac,
1953 msg,
1954 req->controls,
1955 ac, ph_modify_callback,
1956 req);
1957 if (ret != LDB_SUCCESS) {
1958 return ret;
1961 return ldb_next_request(module, down_req);
1964 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
1966 struct ph_context *ac;
1967 int ret;
1969 ac = talloc_get_type(req->context, struct ph_context);
1971 if (!ares) {
1972 return ldb_module_done(ac->req, NULL, NULL,
1973 LDB_ERR_OPERATIONS_ERROR);
1975 if (ares->error != LDB_SUCCESS) {
1976 return ldb_module_done(ac->req, ares->controls,
1977 ares->response, ares->error);
1980 if (ares->type != LDB_REPLY_DONE) {
1981 talloc_free(ares);
1982 return ldb_module_done(ac->req, NULL, NULL,
1983 LDB_ERR_OPERATIONS_ERROR);
1986 ret = password_hash_mod_search_self(ac);
1987 if (ret != LDB_SUCCESS) {
1988 return ldb_module_done(ac->req, NULL, NULL, ret);
1991 talloc_free(ares);
1992 return LDB_SUCCESS;
1995 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
1997 struct ldb_context *ldb;
1998 struct ph_context *ac;
1999 int ret;
2001 ac = talloc_get_type(req->context, struct ph_context);
2002 ldb = ldb_module_get_ctx(ac->module);
2004 if (!ares) {
2005 return ldb_module_done(ac->req, NULL, NULL,
2006 LDB_ERR_OPERATIONS_ERROR);
2008 if (ares->error != LDB_SUCCESS) {
2009 return ldb_module_done(ac->req, ares->controls,
2010 ares->response, ares->error);
2013 /* we are interested only in the single reply (base search) */
2014 switch (ares->type) {
2015 case LDB_REPLY_ENTRY:
2017 if (ac->search_res != NULL) {
2018 ldb_set_errstring(ldb, "Too many results");
2019 talloc_free(ares);
2020 return ldb_module_done(ac->req, NULL, NULL,
2021 LDB_ERR_OPERATIONS_ERROR);
2024 /* if it is not an entry of type person this is an error */
2025 /* TODO: remove this when sambaPassword will be in schema */
2026 if (!ldb_msg_check_string_attribute(ares->message, "objectClass", "person")) {
2027 ldb_set_errstring(ldb, "Object class violation");
2028 talloc_free(ares);
2029 return ldb_module_done(ac->req, NULL, NULL,
2030 LDB_ERR_OBJECT_CLASS_VIOLATION);
2033 ac->search_res = talloc_steal(ac, ares);
2034 return LDB_SUCCESS;
2036 case LDB_REPLY_DONE:
2038 /* get user domain data */
2039 ret = build_domain_data_request(ac);
2040 if (ret != LDB_SUCCESS) {
2041 return ldb_module_done(ac->req, NULL, NULL,ret);
2044 return ldb_next_request(ac->module, ac->dom_req);
2046 case LDB_REPLY_REFERRAL:
2047 /*ignore anything else for now */
2048 break;
2051 talloc_free(ares);
2052 return LDB_SUCCESS;
2055 static int password_hash_mod_search_self(struct ph_context *ac)
2057 struct ldb_context *ldb;
2058 static const char * const attrs[] = { "userAccountControl", "lmPwdHistory",
2059 "ntPwdHistory",
2060 "objectSid", "msDS-KeyVersionNumber",
2061 "objectClass", "userPrincipalName",
2062 "sAMAccountName",
2063 "dBCSPwd", "unicodePwd",
2064 "supplementalCredentials",
2065 NULL };
2066 struct ldb_request *search_req;
2067 int ret;
2069 ldb = ldb_module_get_ctx(ac->module);
2071 ret = ldb_build_search_req(&search_req, ldb, ac,
2072 ac->req->op.mod.message->dn,
2073 LDB_SCOPE_BASE,
2074 "(objectclass=*)",
2075 attrs,
2076 NULL,
2077 ac, ph_mod_search_callback,
2078 ac->req);
2080 if (ret != LDB_SUCCESS) {
2081 return ret;
2084 return ldb_next_request(ac->module, search_req);
2087 static int password_hash_mod_do_mod(struct ph_context *ac)
2089 struct ldb_context *ldb;
2090 struct ldb_request *mod_req;
2091 struct ldb_message *msg;
2092 const struct ldb_message *searched_msg;
2093 struct setup_password_fields_io io;
2094 int ret;
2096 ldb = ldb_module_get_ctx(ac->module);
2098 /* use a new message structure so that we can modify it */
2099 msg = ldb_msg_new(ac);
2100 if (msg == NULL) {
2101 return LDB_ERR_OPERATIONS_ERROR;
2104 /* modify dn */
2105 msg->dn = ac->req->op.mod.message->dn;
2107 /* Prepare the internal data structure containing the passwords */
2108 ret = setup_io(ac,
2109 ac->req->op.mod.message,
2110 ac->search_res->message,
2111 &io);
2112 if (ret != LDB_SUCCESS) {
2113 return ret;
2116 searched_msg = ac->search_res->message;
2118 /* Fill in some final details (only relevent once the password has been set) */
2119 io.o.kvno = samdb_result_uint(searched_msg, "msDs-KeyVersionNumber", 0);
2120 io.o.nt_history_len = samdb_result_hashes(io.ac, searched_msg, "ntPwdHistory", &io.o.nt_history);
2121 io.o.lm_history_len = samdb_result_hashes(io.ac, searched_msg, "lmPwdHistory", &io.o.lm_history);
2122 io.o.supplemental = ldb_msg_find_ldb_val(searched_msg, "supplementalCredentials");
2124 ret = setup_password_fields(&io);
2125 if (ret != LDB_SUCCESS) {
2126 return ret;
2129 /* make sure we replace all the old attributes */
2130 ret = ldb_msg_add_empty(msg, "unicodePwd", LDB_FLAG_MOD_REPLACE, NULL);
2131 ret = ldb_msg_add_empty(msg, "dBCSPwd", LDB_FLAG_MOD_REPLACE, NULL);
2132 ret = ldb_msg_add_empty(msg, "ntPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
2133 ret = ldb_msg_add_empty(msg, "lmPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
2134 ret = ldb_msg_add_empty(msg, "supplementalCredentials", LDB_FLAG_MOD_REPLACE, NULL);
2135 ret = ldb_msg_add_empty(msg, "pwdLastSet", LDB_FLAG_MOD_REPLACE, NULL);
2136 ret = ldb_msg_add_empty(msg, "msDs-KeyVersionNumber", LDB_FLAG_MOD_REPLACE, NULL);
2138 if (io.g.nt_hash) {
2139 ret = samdb_msg_add_hash(ldb, ac, msg,
2140 "unicodePwd", io.g.nt_hash);
2141 if (ret != LDB_SUCCESS) {
2142 return ret;
2145 if (io.g.lm_hash) {
2146 ret = samdb_msg_add_hash(ldb, ac, msg,
2147 "dBCSPwd", io.g.lm_hash);
2148 if (ret != LDB_SUCCESS) {
2149 return ret;
2152 if (io.g.nt_history_len > 0) {
2153 ret = samdb_msg_add_hashes(ac, msg,
2154 "ntPwdHistory",
2155 io.g.nt_history,
2156 io.g.nt_history_len);
2157 if (ret != LDB_SUCCESS) {
2158 return ret;
2161 if (io.g.lm_history_len > 0) {
2162 ret = samdb_msg_add_hashes(ac, msg,
2163 "lmPwdHistory",
2164 io.g.lm_history,
2165 io.g.lm_history_len);
2166 if (ret != LDB_SUCCESS) {
2167 return ret;
2170 if (io.g.supplemental.length > 0) {
2171 ret = ldb_msg_add_value(msg, "supplementalCredentials",
2172 &io.g.supplemental, NULL);
2173 if (ret != LDB_SUCCESS) {
2174 return ret;
2177 ret = samdb_msg_add_uint64(ldb, ac, msg,
2178 "pwdLastSet",
2179 io.g.last_set);
2180 if (ret != LDB_SUCCESS) {
2181 return ret;
2183 ret = samdb_msg_add_uint(ldb, ac, msg,
2184 "msDs-KeyVersionNumber",
2185 io.g.kvno);
2186 if (ret != LDB_SUCCESS) {
2187 return ret;
2190 ret = ldb_build_mod_req(&mod_req, ldb, ac,
2191 msg,
2192 ac->req->controls,
2193 ac, ph_op_callback,
2194 ac->req);
2195 if (ret != LDB_SUCCESS) {
2196 return ret;
2199 return ldb_next_request(ac->module, mod_req);
2202 _PUBLIC_ const struct ldb_module_ops ldb_password_hash_module_ops = {
2203 .name = "password_hash",
2204 .add = password_hash_add,
2205 .modify = password_hash_modify,