[SAMBA 4] Some cosmetic changes for the LDB modules
[Samba/eduardoll.git] / source4 / dsdb / samdb / ldb_modules / password_hash.c
blobc7fa636aa801e25f1cc667a96e5dbd8ae1dca3f3
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 dom_sid *domain_sid;
83 struct domain_data *domain;
86 struct domain_data {
87 bool store_cleartext;
88 uint_t pwdProperties;
89 uint_t pwdHistoryLength;
90 char *netbios_domain;
91 char *dns_domain;
92 char *realm;
95 struct setup_password_fields_io {
96 struct ph_context *ac;
97 struct domain_data *domain;
98 struct smb_krb5_context *smb_krb5_context;
100 /* infos about the user account */
101 struct {
102 uint32_t user_account_control;
103 const char *sAMAccountName;
104 const char *user_principal_name;
105 bool is_computer;
106 } u;
108 /* new credentials */
109 struct {
110 const struct ldb_val *cleartext_utf8;
111 const struct ldb_val *cleartext_utf16;
112 struct ldb_val quoted_utf16;
113 struct samr_Password *nt_hash;
114 struct samr_Password *lm_hash;
115 } n;
117 /* old credentials */
118 struct {
119 uint32_t nt_history_len;
120 struct samr_Password *nt_history;
121 uint32_t lm_history_len;
122 struct samr_Password *lm_history;
123 const struct ldb_val *supplemental;
124 struct supplementalCredentialsBlob scb;
125 uint32_t kvno;
126 } o;
128 /* generated credentials */
129 struct {
130 struct samr_Password *nt_hash;
131 struct samr_Password *lm_hash;
132 uint32_t nt_history_len;
133 struct samr_Password *nt_history;
134 uint32_t lm_history_len;
135 struct samr_Password *lm_history;
136 const char *salt;
137 DATA_BLOB aes_256;
138 DATA_BLOB aes_128;
139 DATA_BLOB des_md5;
140 DATA_BLOB des_crc;
141 struct ldb_val supplemental;
142 NTTIME last_set;
143 uint32_t kvno;
144 } g;
147 /* Get the NT hash, and fill it in as an entry in the password history,
148 and specify it into io->g.nt_hash */
150 static int setup_nt_fields(struct setup_password_fields_io *io)
152 struct ldb_context *ldb;
153 uint32_t i;
155 io->g.nt_hash = io->n.nt_hash;
156 ldb = ldb_module_get_ctx(io->ac->module);
158 if (io->domain->pwdHistoryLength == 0) {
159 return LDB_SUCCESS;
162 /* We might not have an old NT password */
163 io->g.nt_history = talloc_array(io->ac,
164 struct samr_Password,
165 io->domain->pwdHistoryLength);
166 if (!io->g.nt_history) {
167 ldb_oom(ldb);
168 return LDB_ERR_OPERATIONS_ERROR;
171 for (i = 0; i < MIN(io->domain->pwdHistoryLength-1, io->o.nt_history_len); i++) {
172 io->g.nt_history[i+1] = io->o.nt_history[i];
174 io->g.nt_history_len = i + 1;
176 if (io->g.nt_hash) {
177 io->g.nt_history[0] = *io->g.nt_hash;
178 } else {
180 * TODO: is this correct?
181 * the simular behavior is correct for the lm history case
183 E_md4hash("", io->g.nt_history[0].hash);
186 return LDB_SUCCESS;
189 /* Get the LANMAN hash, and fill it in as an entry in the password history,
190 and specify it into io->g.lm_hash */
192 static int setup_lm_fields(struct setup_password_fields_io *io)
194 struct ldb_context *ldb;
195 uint32_t i;
197 io->g.lm_hash = io->n.lm_hash;
198 ldb = ldb_module_get_ctx(io->ac->module);
200 if (io->domain->pwdHistoryLength == 0) {
201 return LDB_SUCCESS;
204 /* We might not have an old NT password */
205 io->g.lm_history = talloc_array(io->ac,
206 struct samr_Password,
207 io->domain->pwdHistoryLength);
208 if (!io->g.lm_history) {
209 ldb_oom(ldb);
210 return LDB_ERR_OPERATIONS_ERROR;
213 for (i = 0; i < MIN(io->domain->pwdHistoryLength-1, io->o.lm_history_len); i++) {
214 io->g.lm_history[i+1] = io->o.lm_history[i];
216 io->g.lm_history_len = i + 1;
218 if (io->g.lm_hash) {
219 io->g.lm_history[0] = *io->g.lm_hash;
220 } else {
221 E_deshash("", io->g.lm_history[0].hash);
224 return LDB_SUCCESS;
227 static int setup_kerberos_keys(struct setup_password_fields_io *io)
229 struct ldb_context *ldb;
230 krb5_error_code krb5_ret;
231 Principal *salt_principal;
232 krb5_salt salt;
233 krb5_keyblock key;
234 krb5_data cleartext_data;
236 ldb = ldb_module_get_ctx(io->ac->module);
237 cleartext_data.data = io->n.cleartext_utf8->data;
238 cleartext_data.length = io->n.cleartext_utf8->length;
240 /* Many, many thanks to lukeh@padl.com for this
241 * algorithm, described in his Nov 10 2004 mail to
242 * samba-technical@samba.org */
245 * Determine a salting principal
247 if (io->u.is_computer) {
248 char *name;
249 char *saltbody;
251 name = talloc_strdup(io->ac, io->u.sAMAccountName);
252 if (!name) {
253 ldb_oom(ldb);
254 return LDB_ERR_OPERATIONS_ERROR;
257 if (name[strlen(name)-1] == '$') {
258 name[strlen(name)-1] = '\0';
261 saltbody = talloc_asprintf(io->ac, "%s.%s", name, io->domain->dns_domain);
262 if (!saltbody) {
263 ldb_oom(ldb);
264 return LDB_ERR_OPERATIONS_ERROR;
267 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
268 &salt_principal,
269 io->domain->realm, "host",
270 saltbody, NULL);
271 } else if (io->u.user_principal_name) {
272 char *user_principal_name;
273 char *p;
275 user_principal_name = talloc_strdup(io->ac, io->u.user_principal_name);
276 if (!user_principal_name) {
277 ldb_oom(ldb);
278 return LDB_ERR_OPERATIONS_ERROR;
281 p = strchr(user_principal_name, '@');
282 if (p) {
283 p[0] = '\0';
286 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
287 &salt_principal,
288 io->domain->realm, user_principal_name,
289 NULL);
290 } else {
291 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
292 &salt_principal,
293 io->domain->realm, io->u.sAMAccountName,
294 NULL);
296 if (krb5_ret) {
297 ldb_asprintf_errstring(ldb,
298 "setup_kerberos_keys: "
299 "generation of a salting principal failed: %s",
300 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
301 return LDB_ERR_OPERATIONS_ERROR;
305 * create salt from salt_principal
307 krb5_ret = krb5_get_pw_salt(io->smb_krb5_context->krb5_context,
308 salt_principal, &salt);
309 krb5_free_principal(io->smb_krb5_context->krb5_context, salt_principal);
310 if (krb5_ret) {
311 ldb_asprintf_errstring(ldb,
312 "setup_kerberos_keys: "
313 "generation of krb5_salt failed: %s",
314 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
315 return LDB_ERR_OPERATIONS_ERROR;
317 /* create a talloc copy */
318 io->g.salt = talloc_strndup(io->ac,
319 salt.saltvalue.data,
320 salt.saltvalue.length);
321 krb5_free_salt(io->smb_krb5_context->krb5_context, salt);
322 if (!io->g.salt) {
323 ldb_oom(ldb);
324 return LDB_ERR_OPERATIONS_ERROR;
326 salt.saltvalue.data = discard_const(io->g.salt);
327 salt.saltvalue.length = strlen(io->g.salt);
330 * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of
331 * the salt and the cleartext password
333 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
334 ENCTYPE_AES256_CTS_HMAC_SHA1_96,
335 cleartext_data,
336 salt,
337 &key);
338 if (krb5_ret) {
339 ldb_asprintf_errstring(ldb,
340 "setup_kerberos_keys: "
341 "generation of a aes256-cts-hmac-sha1-96 key failed: %s",
342 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
343 return LDB_ERR_OPERATIONS_ERROR;
345 io->g.aes_256 = data_blob_talloc(io->ac,
346 key.keyvalue.data,
347 key.keyvalue.length);
348 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
349 if (!io->g.aes_256.data) {
350 ldb_oom(ldb);
351 return LDB_ERR_OPERATIONS_ERROR;
355 * create ENCTYPE_AES128_CTS_HMAC_SHA1_96 key out of
356 * the salt and the cleartext password
358 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
359 ENCTYPE_AES128_CTS_HMAC_SHA1_96,
360 cleartext_data,
361 salt,
362 &key);
363 if (krb5_ret) {
364 ldb_asprintf_errstring(ldb,
365 "setup_kerberos_keys: "
366 "generation of a aes128-cts-hmac-sha1-96 key failed: %s",
367 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
368 return LDB_ERR_OPERATIONS_ERROR;
370 io->g.aes_128 = data_blob_talloc(io->ac,
371 key.keyvalue.data,
372 key.keyvalue.length);
373 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
374 if (!io->g.aes_128.data) {
375 ldb_oom(ldb);
376 return LDB_ERR_OPERATIONS_ERROR;
380 * create ENCTYPE_DES_CBC_MD5 key out of
381 * the salt and the cleartext password
383 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
384 ENCTYPE_DES_CBC_MD5,
385 cleartext_data,
386 salt,
387 &key);
388 if (krb5_ret) {
389 ldb_asprintf_errstring(ldb,
390 "setup_kerberos_keys: "
391 "generation of a des-cbc-md5 key failed: %s",
392 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
393 return LDB_ERR_OPERATIONS_ERROR;
395 io->g.des_md5 = data_blob_talloc(io->ac,
396 key.keyvalue.data,
397 key.keyvalue.length);
398 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
399 if (!io->g.des_md5.data) {
400 ldb_oom(ldb);
401 return LDB_ERR_OPERATIONS_ERROR;
405 * create ENCTYPE_DES_CBC_CRC key out of
406 * the salt and the cleartext password
408 krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
409 ENCTYPE_DES_CBC_CRC,
410 cleartext_data,
411 salt,
412 &key);
413 if (krb5_ret) {
414 ldb_asprintf_errstring(ldb,
415 "setup_kerberos_keys: "
416 "generation of a des-cbc-crc key failed: %s",
417 smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
418 return LDB_ERR_OPERATIONS_ERROR;
420 io->g.des_crc = data_blob_talloc(io->ac,
421 key.keyvalue.data,
422 key.keyvalue.length);
423 krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
424 if (!io->g.des_crc.data) {
425 ldb_oom(ldb);
426 return LDB_ERR_OPERATIONS_ERROR;
429 return LDB_SUCCESS;
432 static int setup_primary_kerberos(struct setup_password_fields_io *io,
433 const struct supplementalCredentialsBlob *old_scb,
434 struct package_PrimaryKerberosBlob *pkb)
436 struct ldb_context *ldb;
437 struct package_PrimaryKerberosCtr3 *pkb3 = &pkb->ctr.ctr3;
438 struct supplementalCredentialsPackage *old_scp = NULL;
439 struct package_PrimaryKerberosBlob _old_pkb;
440 struct package_PrimaryKerberosCtr3 *old_pkb3 = NULL;
441 uint32_t i;
442 enum ndr_err_code ndr_err;
444 ldb = ldb_module_get_ctx(io->ac->module);
447 * prepare generation of keys
449 * ENCTYPE_DES_CBC_MD5
450 * ENCTYPE_DES_CBC_CRC
452 pkb->version = 3;
453 pkb3->salt.string = io->g.salt;
454 pkb3->num_keys = 2;
455 pkb3->keys = talloc_array(io->ac,
456 struct package_PrimaryKerberosKey3,
457 pkb3->num_keys);
458 if (!pkb3->keys) {
459 ldb_oom(ldb);
460 return LDB_ERR_OPERATIONS_ERROR;
463 pkb3->keys[0].keytype = ENCTYPE_DES_CBC_MD5;
464 pkb3->keys[0].value = &io->g.des_md5;
465 pkb3->keys[1].keytype = ENCTYPE_DES_CBC_CRC;
466 pkb3->keys[1].value = &io->g.des_crc;
468 /* initialize the old keys to zero */
469 pkb3->num_old_keys = 0;
470 pkb3->old_keys = NULL;
472 /* if there're no old keys, then we're done */
473 if (!old_scb) {
474 return LDB_SUCCESS;
477 for (i=0; i < old_scb->sub.num_packages; i++) {
478 if (strcmp("Primary:Kerberos", old_scb->sub.packages[i].name) != 0) {
479 continue;
482 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
483 continue;
486 old_scp = &old_scb->sub.packages[i];
487 break;
489 /* Primary:Kerberos element of supplementalCredentials */
490 if (old_scp) {
491 DATA_BLOB blob;
493 blob = strhex_to_data_blob(io->ac, old_scp->data);
494 if (!blob.data) {
495 ldb_oom(ldb);
496 return LDB_ERR_OPERATIONS_ERROR;
499 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
500 ndr_err = ndr_pull_struct_blob(&blob, io->ac, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &_old_pkb,
501 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
502 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
503 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
504 ldb_asprintf_errstring(ldb,
505 "setup_primary_kerberos: "
506 "failed to pull old package_PrimaryKerberosBlob: %s",
507 nt_errstr(status));
508 return LDB_ERR_OPERATIONS_ERROR;
511 if (_old_pkb.version != 3) {
512 ldb_asprintf_errstring(ldb,
513 "setup_primary_kerberos: "
514 "package_PrimaryKerberosBlob version[%u] expected[3]",
515 _old_pkb.version);
516 return LDB_ERR_OPERATIONS_ERROR;
519 old_pkb3 = &_old_pkb.ctr.ctr3;
522 /* if we didn't found the old keys we're done */
523 if (!old_pkb3) {
524 return LDB_SUCCESS;
527 /* fill in the old keys */
528 pkb3->num_old_keys = old_pkb3->num_keys;
529 pkb3->old_keys = old_pkb3->keys;
531 return LDB_SUCCESS;
534 static int setup_primary_kerberos_newer(struct setup_password_fields_io *io,
535 const struct supplementalCredentialsBlob *old_scb,
536 struct package_PrimaryKerberosBlob *pkb)
538 struct ldb_context *ldb;
539 struct package_PrimaryKerberosCtr4 *pkb4 = &pkb->ctr.ctr4;
540 struct supplementalCredentialsPackage *old_scp = NULL;
541 struct package_PrimaryKerberosBlob _old_pkb;
542 struct package_PrimaryKerberosCtr4 *old_pkb4 = NULL;
543 uint32_t i;
544 enum ndr_err_code ndr_err;
546 ldb = ldb_module_get_ctx(io->ac->module);
549 * prepare generation of keys
551 * ENCTYPE_AES256_CTS_HMAC_SHA1_96
552 * ENCTYPE_AES128_CTS_HMAC_SHA1_96
553 * ENCTYPE_DES_CBC_MD5
554 * ENCTYPE_DES_CBC_CRC
556 pkb->version = 4;
557 pkb4->salt.string = io->g.salt;
558 pkb4->default_iteration_count = 4096;
559 pkb4->num_keys = 4;
561 pkb4->keys = talloc_array(io->ac,
562 struct package_PrimaryKerberosKey4,
563 pkb4->num_keys);
564 if (!pkb4->keys) {
565 ldb_oom(ldb);
566 return LDB_ERR_OPERATIONS_ERROR;
569 pkb4->keys[0].iteration_count = 4096;
570 pkb4->keys[0].keytype = ENCTYPE_AES256_CTS_HMAC_SHA1_96;
571 pkb4->keys[0].value = &io->g.aes_256;
572 pkb4->keys[1].iteration_count = 4096;
573 pkb4->keys[1].keytype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
574 pkb4->keys[1].value = &io->g.aes_128;
575 pkb4->keys[2].iteration_count = 4096;
576 pkb4->keys[2].keytype = ENCTYPE_DES_CBC_MD5;
577 pkb4->keys[2].value = &io->g.des_md5;
578 pkb4->keys[3].iteration_count = 4096;
579 pkb4->keys[3].keytype = ENCTYPE_DES_CBC_CRC;
580 pkb4->keys[3].value = &io->g.des_crc;
582 /* initialize the old keys to zero */
583 pkb4->num_old_keys = 0;
584 pkb4->old_keys = NULL;
585 pkb4->num_older_keys = 0;
586 pkb4->older_keys = NULL;
588 /* if there're no old keys, then we're done */
589 if (!old_scb) {
590 return LDB_SUCCESS;
593 for (i=0; i < old_scb->sub.num_packages; i++) {
594 if (strcmp("Primary:Kerberos-Newer-Keys", old_scb->sub.packages[i].name) != 0) {
595 continue;
598 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
599 continue;
602 old_scp = &old_scb->sub.packages[i];
603 break;
605 /* Primary:Kerberos-Newer-Keys element of supplementalCredentials */
606 if (old_scp) {
607 DATA_BLOB blob;
609 blob = strhex_to_data_blob(io->ac, old_scp->data);
610 if (!blob.data) {
611 ldb_oom(ldb);
612 return LDB_ERR_OPERATIONS_ERROR;
615 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
616 ndr_err = ndr_pull_struct_blob(&blob, io->ac,
617 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
618 &_old_pkb,
619 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
620 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
621 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
622 ldb_asprintf_errstring(ldb,
623 "setup_primary_kerberos_newer: "
624 "failed to pull old package_PrimaryKerberosBlob: %s",
625 nt_errstr(status));
626 return LDB_ERR_OPERATIONS_ERROR;
629 if (_old_pkb.version != 4) {
630 ldb_asprintf_errstring(ldb,
631 "setup_primary_kerberos_newer: "
632 "package_PrimaryKerberosBlob version[%u] expected[4]",
633 _old_pkb.version);
634 return LDB_ERR_OPERATIONS_ERROR;
637 old_pkb4 = &_old_pkb.ctr.ctr4;
640 /* if we didn't found the old keys we're done */
641 if (!old_pkb4) {
642 return LDB_SUCCESS;
645 /* fill in the old keys */
646 pkb4->num_old_keys = old_pkb4->num_keys;
647 pkb4->old_keys = old_pkb4->keys;
648 pkb4->num_older_keys = old_pkb4->num_old_keys;
649 pkb4->older_keys = old_pkb4->old_keys;
651 return LDB_SUCCESS;
654 static int setup_primary_wdigest(struct setup_password_fields_io *io,
655 const struct supplementalCredentialsBlob *old_scb,
656 struct package_PrimaryWDigestBlob *pdb)
658 struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
659 DATA_BLOB sAMAccountName;
660 DATA_BLOB sAMAccountName_l;
661 DATA_BLOB sAMAccountName_u;
662 const char *user_principal_name = io->u.user_principal_name;
663 DATA_BLOB userPrincipalName;
664 DATA_BLOB userPrincipalName_l;
665 DATA_BLOB userPrincipalName_u;
666 DATA_BLOB netbios_domain;
667 DATA_BLOB netbios_domain_l;
668 DATA_BLOB netbios_domain_u;
669 DATA_BLOB dns_domain;
670 DATA_BLOB dns_domain_l;
671 DATA_BLOB dns_domain_u;
672 DATA_BLOB digest;
673 DATA_BLOB delim;
674 DATA_BLOB backslash;
675 uint8_t i;
676 struct {
677 DATA_BLOB *user;
678 DATA_BLOB *realm;
679 DATA_BLOB *nt4dom;
680 } wdigest[] = {
682 * See
683 * http://technet2.microsoft.com/WindowsServer/en/library/717b450c-f4a0-4cc9-86f4-cc0633aae5f91033.mspx?mfr=true
684 * for what precalculated hashes are supposed to be stored...
686 * I can't reproduce all values which should contain "Digest" as realm,
687 * am I doing something wrong or is w2k3 just broken...?
689 * W2K3 fills in following for a user:
691 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
692 * sAMAccountName: NewUser2Sam
693 * userPrincipalName: NewUser2Princ@sub1.w2k3.vmnet1.vm.base
695 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
696 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
697 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
698 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
699 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
700 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
701 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
702 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
703 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
704 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
705 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
706 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
707 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
708 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
709 * 221c55284451ae9b3aacaa2a3c86f10f => NewUser2Princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
710 * 74e1be668853d4324d38c07e2acfb8ea => (w2k3 has a bug here!) newuser2princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
711 * e1e244ab7f098e3ae1761be7f9229bbb => NEWUSER2PRINC@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
712 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
713 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
714 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
715 * 31dc704d3640335b2123d4ee28aa1f11 => ??? changes with NewUser2Sam => NewUser1Sam
716 * 36349f5cecd07320fb3bb0e119230c43 => ??? changes with NewUser2Sam => NewUser1Sam
717 * 12adf019d037fb535c01fd0608e78d9d => ??? changes with NewUser2Sam => NewUser1Sam
718 * 6feecf8e724906f3ee1105819c5105a1 => ??? changes with NewUser2Princ => NewUser1Princ
719 * 6c6911f3de6333422640221b9c51ff1f => ??? changes with NewUser2Princ => NewUser1Princ
720 * 4b279877e742895f9348ac67a8de2f69 => ??? changes with NewUser2Princ => NewUser1Princ
721 * db0c6bff069513e3ebb9870d29b57490 => ??? changes with NewUser2Sam => NewUser1Sam
722 * 45072621e56b1c113a4e04a8ff68cd0e => ??? changes with NewUser2Sam => NewUser1Sam
723 * 11d1220abc44a9c10cf91ef4a9c1de02 => ??? changes with NewUser2Sam => NewUser1Sam
725 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
726 * sAMAccountName: NewUser2Sam
728 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
729 * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
730 * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
731 * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
732 * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
733 * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
734 * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
735 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
736 * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
737 * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
738 * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
739 * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
740 * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
741 * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
742 * 8a140d30b6f0a5912735dc1e3bc993b4 => NewUser2Sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
743 * 86d95b2faae6cae4ec261e7fbaccf093 => (here w2k3 is correct) newuser2sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
744 * dfeff1493110220efcdfc6362e5f5450 => NEWUSER2SAM@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
745 * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
746 * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
747 * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
748 * 31dc704d3640335b2123d4ee28aa1f11 => ???M1 changes with NewUser2Sam => NewUser1Sam
749 * 36349f5cecd07320fb3bb0e119230c43 => ???M1.L changes with newuser2sam => newuser1sam
750 * 12adf019d037fb535c01fd0608e78d9d => ???M1.U changes with NEWUSER2SAM => NEWUSER1SAM
751 * 569b4533f2d9e580211dd040e5e360a8 => ???M2 changes with NewUser2Princ => NewUser1Princ
752 * 52528bddf310a587c5d7e6a9ae2cbb20 => ???M2.L changes with newuser2princ => newuser1princ
753 * 4f629a4f0361289ca4255ab0f658fcd5 => ???M3 changes with NewUser2Princ => NewUser1Princ (doesn't depend on case of userPrincipal )
754 * db0c6bff069513e3ebb9870d29b57490 => ???M4 changes with NewUser2Sam => NewUser1Sam
755 * 45072621e56b1c113a4e04a8ff68cd0e => ???M5 changes with NewUser2Sam => NewUser1Sam (doesn't depend on case of sAMAccountName)
756 * 11d1220abc44a9c10cf91ef4a9c1de02 => ???M4.U changes with NEWUSER2SAM => NEWUSER1SAM
760 * sAMAccountName, netbios_domain
763 .user = &sAMAccountName,
764 .realm = &netbios_domain,
767 .user = &sAMAccountName_l,
768 .realm = &netbios_domain_l,
771 .user = &sAMAccountName_u,
772 .realm = &netbios_domain_u,
775 .user = &sAMAccountName,
776 .realm = &netbios_domain_u,
779 .user = &sAMAccountName,
780 .realm = &netbios_domain_l,
783 .user = &sAMAccountName_u,
784 .realm = &netbios_domain_l,
787 .user = &sAMAccountName_l,
788 .realm = &netbios_domain_u,
791 * sAMAccountName, dns_domain
794 .user = &sAMAccountName,
795 .realm = &dns_domain,
798 .user = &sAMAccountName_l,
799 .realm = &dns_domain_l,
802 .user = &sAMAccountName_u,
803 .realm = &dns_domain_u,
806 .user = &sAMAccountName,
807 .realm = &dns_domain_u,
810 .user = &sAMAccountName,
811 .realm = &dns_domain_l,
814 .user = &sAMAccountName_u,
815 .realm = &dns_domain_l,
818 .user = &sAMAccountName_l,
819 .realm = &dns_domain_u,
822 * userPrincipalName, no realm
825 .user = &userPrincipalName,
829 * NOTE: w2k3 messes this up, if the user has a real userPrincipalName,
830 * the fallback to the sAMAccountName based userPrincipalName is correct
832 .user = &userPrincipalName_l,
835 .user = &userPrincipalName_u,
838 * nt4dom\sAMAccountName, no realm
841 .user = &sAMAccountName,
842 .nt4dom = &netbios_domain
845 .user = &sAMAccountName_l,
846 .nt4dom = &netbios_domain_l
849 .user = &sAMAccountName_u,
850 .nt4dom = &netbios_domain_u
854 * the following ones are guessed depending on the technet2 article
855 * but not reproducable on a w2k3 server
857 /* sAMAccountName with "Digest" realm */
859 .user = &sAMAccountName,
860 .realm = &digest
863 .user = &sAMAccountName_l,
864 .realm = &digest
867 .user = &sAMAccountName_u,
868 .realm = &digest
870 /* userPrincipalName with "Digest" realm */
872 .user = &userPrincipalName,
873 .realm = &digest
876 .user = &userPrincipalName_l,
877 .realm = &digest
880 .user = &userPrincipalName_u,
881 .realm = &digest
883 /* nt4dom\\sAMAccountName with "Digest" realm */
885 .user = &sAMAccountName,
886 .nt4dom = &netbios_domain,
887 .realm = &digest
890 .user = &sAMAccountName_l,
891 .nt4dom = &netbios_domain_l,
892 .realm = &digest
895 .user = &sAMAccountName_u,
896 .nt4dom = &netbios_domain_u,
897 .realm = &digest
901 /* prepare DATA_BLOB's used in the combinations array */
902 sAMAccountName = data_blob_string_const(io->u.sAMAccountName);
903 sAMAccountName_l = data_blob_string_const(strlower_talloc(io->ac, io->u.sAMAccountName));
904 if (!sAMAccountName_l.data) {
905 ldb_oom(ldb);
906 return LDB_ERR_OPERATIONS_ERROR;
908 sAMAccountName_u = data_blob_string_const(strupper_talloc(io->ac, io->u.sAMAccountName));
909 if (!sAMAccountName_u.data) {
910 ldb_oom(ldb);
911 return LDB_ERR_OPERATIONS_ERROR;
914 /* if the user doesn't have a userPrincipalName, create one (with lower case realm) */
915 if (!user_principal_name) {
916 user_principal_name = talloc_asprintf(io->ac, "%s@%s",
917 io->u.sAMAccountName,
918 io->domain->dns_domain);
919 if (!user_principal_name) {
920 ldb_oom(ldb);
921 return LDB_ERR_OPERATIONS_ERROR;
924 userPrincipalName = data_blob_string_const(user_principal_name);
925 userPrincipalName_l = data_blob_string_const(strlower_talloc(io->ac, user_principal_name));
926 if (!userPrincipalName_l.data) {
927 ldb_oom(ldb);
928 return LDB_ERR_OPERATIONS_ERROR;
930 userPrincipalName_u = data_blob_string_const(strupper_talloc(io->ac, user_principal_name));
931 if (!userPrincipalName_u.data) {
932 ldb_oom(ldb);
933 return LDB_ERR_OPERATIONS_ERROR;
936 netbios_domain = data_blob_string_const(io->domain->netbios_domain);
937 netbios_domain_l = data_blob_string_const(strlower_talloc(io->ac, io->domain->netbios_domain));
938 if (!netbios_domain_l.data) {
939 ldb_oom(ldb);
940 return LDB_ERR_OPERATIONS_ERROR;
942 netbios_domain_u = data_blob_string_const(strupper_talloc(io->ac, io->domain->netbios_domain));
943 if (!netbios_domain_u.data) {
944 ldb_oom(ldb);
945 return LDB_ERR_OPERATIONS_ERROR;
948 dns_domain = data_blob_string_const(io->domain->dns_domain);
949 dns_domain_l = data_blob_string_const(io->domain->dns_domain);
950 dns_domain_u = data_blob_string_const(io->domain->realm);
952 digest = data_blob_string_const("Digest");
954 delim = data_blob_string_const(":");
955 backslash = data_blob_string_const("\\");
957 pdb->num_hashes = ARRAY_SIZE(wdigest);
958 pdb->hashes = talloc_array(io->ac, struct package_PrimaryWDigestHash, pdb->num_hashes);
959 if (!pdb->hashes) {
960 ldb_oom(ldb);
961 return LDB_ERR_OPERATIONS_ERROR;
964 for (i=0; i < ARRAY_SIZE(wdigest); i++) {
965 struct MD5Context md5;
966 MD5Init(&md5);
967 if (wdigest[i].nt4dom) {
968 MD5Update(&md5, wdigest[i].nt4dom->data, wdigest[i].nt4dom->length);
969 MD5Update(&md5, backslash.data, backslash.length);
971 MD5Update(&md5, wdigest[i].user->data, wdigest[i].user->length);
972 MD5Update(&md5, delim.data, delim.length);
973 if (wdigest[i].realm) {
974 MD5Update(&md5, wdigest[i].realm->data, wdigest[i].realm->length);
976 MD5Update(&md5, delim.data, delim.length);
977 MD5Update(&md5, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length);
978 MD5Final(pdb->hashes[i].hash, &md5);
981 return LDB_SUCCESS;
984 static int setup_supplemental_field(struct setup_password_fields_io *io)
986 struct ldb_context *ldb;
987 struct supplementalCredentialsBlob scb;
988 struct supplementalCredentialsBlob _old_scb;
989 struct supplementalCredentialsBlob *old_scb = NULL;
990 /* Packages + (Kerberos-Newer-Keys, Kerberos, WDigest and CLEARTEXT) */
991 uint32_t num_names = 0;
992 const char *names[1+4];
993 uint32_t num_packages = 0;
994 struct supplementalCredentialsPackage packages[1+4];
995 /* Packages */
996 struct supplementalCredentialsPackage *pp = NULL;
997 struct package_PackagesBlob pb;
998 DATA_BLOB pb_blob;
999 char *pb_hexstr;
1000 /* Primary:Kerberos-Newer-Keys */
1001 const char **nkn = NULL;
1002 struct supplementalCredentialsPackage *pkn = NULL;
1003 struct package_PrimaryKerberosBlob pknb;
1004 DATA_BLOB pknb_blob;
1005 char *pknb_hexstr;
1006 /* Primary:Kerberos */
1007 const char **nk = NULL;
1008 struct supplementalCredentialsPackage *pk = NULL;
1009 struct package_PrimaryKerberosBlob pkb;
1010 DATA_BLOB pkb_blob;
1011 char *pkb_hexstr;
1012 /* Primary:WDigest */
1013 const char **nd = NULL;
1014 struct supplementalCredentialsPackage *pd = NULL;
1015 struct package_PrimaryWDigestBlob pdb;
1016 DATA_BLOB pdb_blob;
1017 char *pdb_hexstr;
1018 /* Primary:CLEARTEXT */
1019 const char **nc = NULL;
1020 struct supplementalCredentialsPackage *pc = NULL;
1021 struct package_PrimaryCLEARTEXTBlob pcb;
1022 DATA_BLOB pcb_blob;
1023 char *pcb_hexstr;
1024 int ret;
1025 enum ndr_err_code ndr_err;
1026 uint8_t zero16[16];
1027 bool do_newer_keys = false;
1028 bool do_cleartext = false;
1029 int *domainFunctionality;
1031 ZERO_STRUCT(zero16);
1032 ZERO_STRUCT(names);
1034 ldb = ldb_module_get_ctx(io->ac->module);
1036 if (!io->n.cleartext_utf8) {
1038 * when we don't have a cleartext password
1039 * we can't setup a supplementalCredential value
1041 return LDB_SUCCESS;
1044 /* if there's an old supplementaCredentials blob then parse it */
1045 if (io->o.supplemental) {
1046 ndr_err = ndr_pull_struct_blob_all(io->o.supplemental, io->ac,
1047 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1048 &_old_scb,
1049 (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
1050 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1051 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1052 ldb_asprintf_errstring(ldb,
1053 "setup_supplemental_field: "
1054 "failed to pull old supplementalCredentialsBlob: %s",
1055 nt_errstr(status));
1056 return LDB_ERR_OPERATIONS_ERROR;
1059 if (_old_scb.sub.signature == SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
1060 old_scb = &_old_scb;
1061 } else {
1062 ldb_debug(ldb, LDB_DEBUG_ERROR,
1063 "setup_supplemental_field: "
1064 "supplementalCredentialsBlob signature[0x%04X] expected[0x%04X]",
1065 _old_scb.sub.signature, SUPPLEMENTAL_CREDENTIALS_SIGNATURE);
1068 /* Per MS-SAMR 3.1.1.8.11.6 we create AES keys if our domain functionality level is 2008 or higher */
1069 domainFunctionality = talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
1071 do_newer_keys = *domainFunctionality && (*domainFunctionality >= DS_BEHAVIOR_WIN2008);
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(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(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(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(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(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 int ret;
1555 char *tmp;
1556 char *p;
1558 ac = talloc_get_type(req->context, struct ph_context);
1559 ldb = ldb_module_get_ctx(ac->module);
1561 if (!ares) {
1562 return ldb_module_done(ac->req, NULL, NULL,
1563 LDB_ERR_OPERATIONS_ERROR);
1565 if (ares->error != LDB_SUCCESS) {
1566 return ldb_module_done(ac->req, ares->controls,
1567 ares->response, ares->error);
1570 switch (ares->type) {
1571 case LDB_REPLY_ENTRY:
1572 if (ac->domain != NULL) {
1573 ldb_set_errstring(ldb, "Too many results");
1574 return ldb_module_done(ac->req, NULL, NULL,
1575 LDB_ERR_OPERATIONS_ERROR);
1578 data = talloc_zero(ac, struct domain_data);
1579 if (data == NULL) {
1580 return ldb_module_done(ac->req, NULL, NULL,
1581 LDB_ERR_OPERATIONS_ERROR);
1584 data->pwdProperties = samdb_result_uint(ares->message, "pwdProperties", 0);
1585 data->store_cleartext = data->pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
1586 data->pwdHistoryLength = samdb_result_uint(ares->message, "pwdHistoryLength", 0);
1588 /* For a domain DN, this puts things in dotted notation */
1589 /* For builtin domains, this will give details for the host,
1590 * but that doesn't really matter, as it's just used for salt
1591 * and kerberos principals, which don't exist here */
1593 tmp = ldb_dn_canonical_string(data, ares->message->dn);
1594 if (!tmp) {
1595 return ldb_module_done(ac->req, NULL, NULL,
1596 LDB_ERR_OPERATIONS_ERROR);
1599 /* But it puts a trailing (or just before 'builtin') / on things, so kill that */
1600 p = strchr(tmp, '/');
1601 if (p) {
1602 p[0] = '\0';
1605 data->dns_domain = strlower_talloc(data, tmp);
1606 if (data->dns_domain == NULL) {
1607 ldb_oom(ldb);
1608 return ldb_module_done(ac->req, NULL, NULL,
1609 LDB_ERR_OPERATIONS_ERROR);
1611 data->realm = strupper_talloc(data, tmp);
1612 if (data->realm == NULL) {
1613 ldb_oom(ldb);
1614 return ldb_module_done(ac->req, NULL, NULL,
1615 LDB_ERR_OPERATIONS_ERROR);
1617 /* FIXME: NetbIOS name is *always* the first domain component ?? -SSS */
1618 p = strchr(tmp, '.');
1619 if (p) {
1620 p[0] = '\0';
1622 data->netbios_domain = strupper_talloc(data, tmp);
1623 if (data->netbios_domain == NULL) {
1624 ldb_oom(ldb);
1625 return ldb_module_done(ac->req, NULL, NULL,
1626 LDB_ERR_OPERATIONS_ERROR);
1629 talloc_free(tmp);
1630 ac->domain = data;
1631 break;
1633 case LDB_REPLY_DONE:
1635 /* call the next step */
1636 switch (ac->req->operation) {
1637 case LDB_ADD:
1638 ret = password_hash_add_do_add(ac);
1639 break;
1641 case LDB_MODIFY:
1642 ret = password_hash_mod_do_mod(ac);
1643 break;
1645 default:
1646 ret = LDB_ERR_OPERATIONS_ERROR;
1647 break;
1649 if (ret != LDB_SUCCESS) {
1650 return ldb_module_done(ac->req, NULL, NULL, ret);
1652 break;
1654 case LDB_REPLY_REFERRAL:
1655 /* ignore */
1656 break;
1659 talloc_free(ares);
1660 return LDB_SUCCESS;
1663 static int build_domain_data_request(struct ph_context *ac)
1665 /* attrs[] is returned from this function in
1666 ac->dom_req->op.search.attrs, so it must be static, as
1667 otherwise the compiler can put it on the stack */
1668 struct ldb_context *ldb;
1669 static const char * const attrs[] = { "pwdProperties", "pwdHistoryLength", NULL };
1670 char *filter;
1672 ldb = ldb_module_get_ctx(ac->module);
1674 filter = talloc_asprintf(ac,
1675 "(&(objectSid=%s)(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain)))",
1676 ldap_encode_ndr_dom_sid(ac, ac->domain_sid));
1677 if (filter == NULL) {
1678 ldb_oom(ldb);
1679 return LDB_ERR_OPERATIONS_ERROR;
1682 return ldb_build_search_req(&ac->dom_req, ldb, ac,
1683 ldb_get_default_basedn(ldb),
1684 LDB_SCOPE_SUBTREE,
1685 filter, attrs,
1686 NULL,
1687 ac, get_domain_data_callback,
1688 ac->req);
1691 static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
1693 struct ldb_context *ldb;
1694 struct ph_context *ac;
1695 struct ldb_message_element *sambaAttr;
1696 struct ldb_message_element *clearTextPasswordAttr;
1697 struct ldb_message_element *ntAttr;
1698 struct ldb_message_element *lmAttr;
1699 int ret;
1701 ldb = ldb_module_get_ctx(module);
1703 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add\n");
1705 if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
1706 return ldb_next_request(module, req);
1709 /* If the caller is manipulating the local passwords directly, let them pass */
1710 if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
1711 req->op.add.message->dn) == 0) {
1712 return ldb_next_request(module, req);
1715 /* nobody must touch these fields */
1716 if (ldb_msg_find_element(req->op.add.message, "ntPwdHistory")) {
1717 return LDB_ERR_UNWILLING_TO_PERFORM;
1719 if (ldb_msg_find_element(req->op.add.message, "lmPwdHistory")) {
1720 return LDB_ERR_UNWILLING_TO_PERFORM;
1722 if (ldb_msg_find_element(req->op.add.message, "supplementalCredentials")) {
1723 return LDB_ERR_UNWILLING_TO_PERFORM;
1726 /* If no part of this ADD touches the userPassword, or the NT
1727 * or LM hashes, then we don't need to make any changes. */
1729 sambaAttr = ldb_msg_find_element(req->op.mod.message, "userPassword");
1730 clearTextPasswordAttr = ldb_msg_find_element(req->op.mod.message, "clearTextPassword");
1731 ntAttr = ldb_msg_find_element(req->op.mod.message, "unicodePwd");
1732 lmAttr = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
1734 if ((!sambaAttr) && (!clearTextPasswordAttr) && (!ntAttr) && (!lmAttr)) {
1735 return ldb_next_request(module, req);
1738 /* if it is not an entry of type person its an error */
1739 /* TODO: remove this when userPassword will be in schema */
1740 if (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "person")) {
1741 ldb_set_errstring(ldb, "Cannot set a password on entry that does not have objectClass 'person'");
1742 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1745 /* check userPassword is single valued here */
1746 /* TODO: remove this when userPassword will be single valued in schema */
1747 if (sambaAttr && sambaAttr->num_values > 1) {
1748 ldb_set_errstring(ldb, "mupltiple values for userPassword not allowed!\n");
1749 return LDB_ERR_CONSTRAINT_VIOLATION;
1751 if (clearTextPasswordAttr && clearTextPasswordAttr->num_values > 1) {
1752 ldb_set_errstring(ldb, "mupltiple values for clearTextPassword not allowed!\n");
1753 return LDB_ERR_CONSTRAINT_VIOLATION;
1756 if (ntAttr && (ntAttr->num_values > 1)) {
1757 ldb_set_errstring(ldb, "mupltiple values for unicodePwd not allowed!\n");
1758 return LDB_ERR_CONSTRAINT_VIOLATION;
1760 if (lmAttr && (lmAttr->num_values > 1)) {
1761 ldb_set_errstring(ldb, "mupltiple values for dBCSPwd not allowed!\n");
1762 return LDB_ERR_CONSTRAINT_VIOLATION;
1765 if (sambaAttr && sambaAttr->num_values == 0) {
1766 ldb_set_errstring(ldb, "userPassword must have a value!\n");
1767 return LDB_ERR_CONSTRAINT_VIOLATION;
1770 if (clearTextPasswordAttr && clearTextPasswordAttr->num_values == 0) {
1771 ldb_set_errstring(ldb, "clearTextPassword must have a value!\n");
1772 return LDB_ERR_CONSTRAINT_VIOLATION;
1775 if (ntAttr && (ntAttr->num_values == 0)) {
1776 ldb_set_errstring(ldb, "unicodePwd must have a value!\n");
1777 return LDB_ERR_CONSTRAINT_VIOLATION;
1779 if (lmAttr && (lmAttr->num_values == 0)) {
1780 ldb_set_errstring(ldb, "dBCSPwd must have a value!\n");
1781 return LDB_ERR_CONSTRAINT_VIOLATION;
1784 ac = ph_init_context(module, req);
1785 if (ac == NULL) {
1786 return LDB_ERR_OPERATIONS_ERROR;
1789 /* get user domain data */
1790 ac->domain_sid = samdb_result_sid_prefix(ac, req->op.add.message, "objectSid");
1791 if (ac->domain_sid == NULL) {
1792 ldb_debug(ldb, LDB_DEBUG_ERROR,
1793 "can't handle entry with missing objectSid!\n");
1794 return LDB_ERR_OPERATIONS_ERROR;
1797 ret = build_domain_data_request(ac);
1798 if (ret != LDB_SUCCESS) {
1799 return ret;
1802 return ldb_next_request(module, ac->dom_req);
1805 static int password_hash_add_do_add(struct ph_context *ac)
1807 struct ldb_context *ldb;
1808 struct ldb_request *down_req;
1809 struct ldb_message *msg;
1810 struct setup_password_fields_io io;
1811 int ret;
1813 /* Prepare the internal data structure containing the passwords */
1814 ret = setup_io(ac, ac->req->op.add.message, ac->req->op.add.message, &io);
1815 if (ret != LDB_SUCCESS) {
1816 return ret;
1819 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
1820 if (msg == NULL) {
1821 return LDB_ERR_OPERATIONS_ERROR;
1824 /* remove attributes that we just read into 'io' */
1825 ldb_msg_remove_attr(msg, "userPassword");
1826 ldb_msg_remove_attr(msg, "clearTextPassword");
1827 ldb_msg_remove_attr(msg, "unicodePwd");
1828 ldb_msg_remove_attr(msg, "dBCSPwd");
1829 ldb_msg_remove_attr(msg, "pwdLastSet");
1830 io.o.kvno = samdb_result_uint(msg, "msDs-KeyVersionNumber", 1) - 1;
1831 ldb_msg_remove_attr(msg, "msDs-KeyVersionNumber");
1833 ldb = ldb_module_get_ctx(ac->module);
1835 ret = setup_password_fields(&io);
1836 if (ret != LDB_SUCCESS) {
1837 return ret;
1840 if (io.g.nt_hash) {
1841 ret = samdb_msg_add_hash(ldb, ac, msg,
1842 "unicodePwd", io.g.nt_hash);
1843 if (ret != LDB_SUCCESS) {
1844 return ret;
1847 if (io.g.lm_hash) {
1848 ret = samdb_msg_add_hash(ldb, ac, msg,
1849 "dBCSPwd", io.g.lm_hash);
1850 if (ret != LDB_SUCCESS) {
1851 return ret;
1854 if (io.g.nt_history_len > 0) {
1855 ret = samdb_msg_add_hashes(ac, msg,
1856 "ntPwdHistory",
1857 io.g.nt_history,
1858 io.g.nt_history_len);
1859 if (ret != LDB_SUCCESS) {
1860 return ret;
1863 if (io.g.lm_history_len > 0) {
1864 ret = samdb_msg_add_hashes(ac, msg,
1865 "lmPwdHistory",
1866 io.g.lm_history,
1867 io.g.lm_history_len);
1868 if (ret != LDB_SUCCESS) {
1869 return ret;
1872 if (io.g.supplemental.length > 0) {
1873 ret = ldb_msg_add_value(msg, "supplementalCredentials",
1874 &io.g.supplemental, NULL);
1875 if (ret != LDB_SUCCESS) {
1876 return ret;
1879 ret = samdb_msg_add_uint64(ldb, ac, msg,
1880 "pwdLastSet",
1881 io.g.last_set);
1882 if (ret != LDB_SUCCESS) {
1883 return ret;
1885 ret = samdb_msg_add_uint(ldb, ac, msg,
1886 "msDs-KeyVersionNumber",
1887 io.g.kvno);
1888 if (ret != LDB_SUCCESS) {
1889 return ret;
1892 ret = ldb_build_add_req(&down_req, ldb, ac,
1893 msg,
1894 ac->req->controls,
1895 ac, ph_op_callback,
1896 ac->req);
1897 if (ret != LDB_SUCCESS) {
1898 return ret;
1901 return ldb_next_request(ac->module, down_req);
1904 static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
1906 struct ldb_context *ldb;
1907 struct ph_context *ac;
1908 struct ldb_message_element *sambaAttr;
1909 struct ldb_message_element *clearTextAttr;
1910 struct ldb_message_element *ntAttr;
1911 struct ldb_message_element *lmAttr;
1912 struct ldb_message *msg;
1913 struct ldb_request *down_req;
1914 int ret;
1916 ldb = ldb_module_get_ctx(module);
1918 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
1920 if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
1921 return ldb_next_request(module, req);
1924 /* If the caller is manipulating the local passwords directly, let them pass */
1925 if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
1926 req->op.mod.message->dn) == 0) {
1927 return ldb_next_request(module, req);
1930 /* nobody must touch password Histories */
1931 if (ldb_msg_find_element(req->op.add.message, "ntPwdHistory")) {
1932 return LDB_ERR_UNWILLING_TO_PERFORM;
1934 if (ldb_msg_find_element(req->op.add.message, "lmPwdHistory")) {
1935 return LDB_ERR_UNWILLING_TO_PERFORM;
1937 if (ldb_msg_find_element(req->op.add.message, "supplementalCredentials")) {
1938 return LDB_ERR_UNWILLING_TO_PERFORM;
1941 sambaAttr = ldb_msg_find_element(req->op.mod.message, "userPassword");
1942 clearTextAttr = ldb_msg_find_element(req->op.mod.message, "clearTextPassword");
1943 ntAttr = ldb_msg_find_element(req->op.mod.message, "unicodePwd");
1944 lmAttr = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
1946 /* If no part of this touches the userPassword OR
1947 * clearTextPassword OR unicodePwd and/or dBCSPwd, then we
1948 * don't need to make any changes. For password changes/set
1949 * there should be a 'delete' or a 'modify' on this
1950 * attribute. */
1951 if ((!sambaAttr) && (!clearTextAttr) && (!ntAttr) && (!lmAttr)) {
1952 return ldb_next_request(module, req);
1955 /* check passwords are single valued here */
1956 /* TODO: remove this when passwords will be single valued in schema */
1957 if (sambaAttr && (sambaAttr->num_values > 1)) {
1958 return LDB_ERR_CONSTRAINT_VIOLATION;
1960 if (clearTextAttr && (clearTextAttr->num_values > 1)) {
1961 return LDB_ERR_CONSTRAINT_VIOLATION;
1963 if (ntAttr && (ntAttr->num_values > 1)) {
1964 return LDB_ERR_CONSTRAINT_VIOLATION;
1966 if (lmAttr && (lmAttr->num_values > 1)) {
1967 return LDB_ERR_CONSTRAINT_VIOLATION;
1970 ac = ph_init_context(module, req);
1971 if (!ac) {
1972 return LDB_ERR_OPERATIONS_ERROR;
1975 /* use a new message structure so that we can modify it */
1976 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
1977 if (msg == NULL) {
1978 ldb_oom(ldb);
1979 return LDB_ERR_OPERATIONS_ERROR;
1982 /* - remove any modification to the password from the first commit
1983 * we will make the real modification later */
1984 if (sambaAttr) ldb_msg_remove_attr(msg, "userPassword");
1985 if (clearTextAttr) ldb_msg_remove_attr(msg, "clearTextPassword");
1986 if (ntAttr) ldb_msg_remove_attr(msg, "unicodePwd");
1987 if (lmAttr) ldb_msg_remove_attr(msg, "dBCSPwd");
1989 /* if there was nothing else to be modified skip to next step */
1990 if (msg->num_elements == 0) {
1991 return password_hash_mod_search_self(ac);
1994 ret = ldb_build_mod_req(&down_req, ldb, ac,
1995 msg,
1996 req->controls,
1997 ac, ph_modify_callback,
1998 req);
1999 if (ret != LDB_SUCCESS) {
2000 return ret;
2003 return ldb_next_request(module, down_req);
2006 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
2008 struct ph_context *ac;
2009 int ret;
2011 ac = talloc_get_type(req->context, struct ph_context);
2013 if (!ares) {
2014 return ldb_module_done(ac->req, NULL, NULL,
2015 LDB_ERR_OPERATIONS_ERROR);
2017 if (ares->error != LDB_SUCCESS) {
2018 return ldb_module_done(ac->req, ares->controls,
2019 ares->response, ares->error);
2022 if (ares->type != LDB_REPLY_DONE) {
2023 talloc_free(ares);
2024 return ldb_module_done(ac->req, NULL, NULL,
2025 LDB_ERR_OPERATIONS_ERROR);
2028 ret = password_hash_mod_search_self(ac);
2029 if (ret != LDB_SUCCESS) {
2030 return ldb_module_done(ac->req, NULL, NULL, ret);
2033 talloc_free(ares);
2034 return LDB_SUCCESS;
2037 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
2039 struct ldb_context *ldb;
2040 struct ph_context *ac;
2041 int ret;
2043 ac = talloc_get_type(req->context, struct ph_context);
2044 ldb = ldb_module_get_ctx(ac->module);
2046 if (!ares) {
2047 return ldb_module_done(ac->req, NULL, NULL,
2048 LDB_ERR_OPERATIONS_ERROR);
2050 if (ares->error != LDB_SUCCESS) {
2051 return ldb_module_done(ac->req, ares->controls,
2052 ares->response, ares->error);
2055 /* we are interested only in the single reply (base search) */
2056 switch (ares->type) {
2057 case LDB_REPLY_ENTRY:
2059 if (ac->search_res != NULL) {
2060 ldb_set_errstring(ldb, "Too many results");
2061 talloc_free(ares);
2062 return ldb_module_done(ac->req, NULL, NULL,
2063 LDB_ERR_OPERATIONS_ERROR);
2066 /* if it is not an entry of type person this is an error */
2067 /* TODO: remove this when sambaPassword will be in schema */
2068 if (!ldb_msg_check_string_attribute(ares->message, "objectClass", "person")) {
2069 ldb_set_errstring(ldb, "Object class violation");
2070 talloc_free(ares);
2071 return ldb_module_done(ac->req, NULL, NULL,
2072 LDB_ERR_OBJECT_CLASS_VIOLATION);
2075 ac->search_res = talloc_steal(ac, ares);
2076 return LDB_SUCCESS;
2078 case LDB_REPLY_DONE:
2080 /* get object domain sid */
2081 ac->domain_sid = samdb_result_sid_prefix(ac,
2082 ac->search_res->message,
2083 "objectSid");
2084 if (ac->domain_sid == NULL) {
2085 ldb_debug(ldb, LDB_DEBUG_ERROR,
2086 "can't handle entry without objectSid!\n");
2087 return ldb_module_done(ac->req, NULL, NULL,
2088 LDB_ERR_OPERATIONS_ERROR);
2091 /* get user domain data */
2092 ret = build_domain_data_request(ac);
2093 if (ret != LDB_SUCCESS) {
2094 return ldb_module_done(ac->req, NULL, NULL,ret);
2097 return ldb_next_request(ac->module, ac->dom_req);
2099 case LDB_REPLY_REFERRAL:
2100 /*ignore anything else for now */
2101 break;
2104 talloc_free(ares);
2105 return LDB_SUCCESS;
2108 static int password_hash_mod_search_self(struct ph_context *ac)
2110 struct ldb_context *ldb;
2111 static const char * const attrs[] = { "userAccountControl", "lmPwdHistory",
2112 "ntPwdHistory",
2113 "objectSid", "msDS-KeyVersionNumber",
2114 "objectClass", "userPrincipalName",
2115 "sAMAccountName",
2116 "dBCSPwd", "unicodePwd",
2117 "supplementalCredentials",
2118 NULL };
2119 struct ldb_request *search_req;
2120 int ret;
2122 ldb = ldb_module_get_ctx(ac->module);
2124 ret = ldb_build_search_req(&search_req, ldb, ac,
2125 ac->req->op.mod.message->dn,
2126 LDB_SCOPE_BASE,
2127 "(objectclass=*)",
2128 attrs,
2129 NULL,
2130 ac, ph_mod_search_callback,
2131 ac->req);
2133 if (ret != LDB_SUCCESS) {
2134 return ret;
2137 return ldb_next_request(ac->module, search_req);
2140 static int password_hash_mod_do_mod(struct ph_context *ac)
2142 struct ldb_context *ldb;
2143 struct ldb_request *mod_req;
2144 struct ldb_message *msg;
2145 const struct ldb_message *searched_msg;
2146 struct setup_password_fields_io io;
2147 int ret;
2149 ldb = ldb_module_get_ctx(ac->module);
2151 /* use a new message structure so that we can modify it */
2152 msg = ldb_msg_new(ac);
2153 if (msg == NULL) {
2154 return LDB_ERR_OPERATIONS_ERROR;
2157 /* modify dn */
2158 msg->dn = ac->req->op.mod.message->dn;
2160 /* Prepare the internal data structure containing the passwords */
2161 ret = setup_io(ac,
2162 ac->req->op.mod.message,
2163 ac->search_res->message,
2164 &io);
2165 if (ret != LDB_SUCCESS) {
2166 return ret;
2169 searched_msg = ac->search_res->message;
2171 /* Fill in some final details (only relevent once the password has been set) */
2172 io.o.kvno = samdb_result_uint(searched_msg, "msDs-KeyVersionNumber", 0);
2173 io.o.nt_history_len = samdb_result_hashes(io.ac, searched_msg, "ntPwdHistory", &io.o.nt_history);
2174 io.o.lm_history_len = samdb_result_hashes(io.ac, searched_msg, "lmPwdHistory", &io.o.lm_history);
2175 io.o.supplemental = ldb_msg_find_ldb_val(searched_msg, "supplementalCredentials");
2177 ret = setup_password_fields(&io);
2178 if (ret != LDB_SUCCESS) {
2179 return ret;
2182 /* make sure we replace all the old attributes */
2183 ret = ldb_msg_add_empty(msg, "unicodePwd", LDB_FLAG_MOD_REPLACE, NULL);
2184 ret = ldb_msg_add_empty(msg, "dBCSPwd", LDB_FLAG_MOD_REPLACE, NULL);
2185 ret = ldb_msg_add_empty(msg, "ntPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
2186 ret = ldb_msg_add_empty(msg, "lmPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
2187 ret = ldb_msg_add_empty(msg, "supplementalCredentials", LDB_FLAG_MOD_REPLACE, NULL);
2188 ret = ldb_msg_add_empty(msg, "pwdLastSet", LDB_FLAG_MOD_REPLACE, NULL);
2189 ret = ldb_msg_add_empty(msg, "msDs-KeyVersionNumber", LDB_FLAG_MOD_REPLACE, NULL);
2191 if (io.g.nt_hash) {
2192 ret = samdb_msg_add_hash(ldb, ac, msg,
2193 "unicodePwd", io.g.nt_hash);
2194 if (ret != LDB_SUCCESS) {
2195 return ret;
2198 if (io.g.lm_hash) {
2199 ret = samdb_msg_add_hash(ldb, ac, msg,
2200 "dBCSPwd", io.g.lm_hash);
2201 if (ret != LDB_SUCCESS) {
2202 return ret;
2205 if (io.g.nt_history_len > 0) {
2206 ret = samdb_msg_add_hashes(ac, msg,
2207 "ntPwdHistory",
2208 io.g.nt_history,
2209 io.g.nt_history_len);
2210 if (ret != LDB_SUCCESS) {
2211 return ret;
2214 if (io.g.lm_history_len > 0) {
2215 ret = samdb_msg_add_hashes(ac, msg,
2216 "lmPwdHistory",
2217 io.g.lm_history,
2218 io.g.lm_history_len);
2219 if (ret != LDB_SUCCESS) {
2220 return ret;
2223 if (io.g.supplemental.length > 0) {
2224 ret = ldb_msg_add_value(msg, "supplementalCredentials",
2225 &io.g.supplemental, NULL);
2226 if (ret != LDB_SUCCESS) {
2227 return ret;
2230 ret = samdb_msg_add_uint64(ldb, ac, msg,
2231 "pwdLastSet",
2232 io.g.last_set);
2233 if (ret != LDB_SUCCESS) {
2234 return ret;
2236 ret = samdb_msg_add_uint(ldb, ac, msg,
2237 "msDs-KeyVersionNumber",
2238 io.g.kvno);
2239 if (ret != LDB_SUCCESS) {
2240 return ret;
2243 ret = ldb_build_mod_req(&mod_req, ldb, ac,
2244 msg,
2245 ac->req->controls,
2246 ac, ph_op_callback,
2247 ac->req);
2248 if (ret != LDB_SUCCESS) {
2249 return ret;
2252 return ldb_next_request(ac->module, mod_req);
2255 _PUBLIC_ const struct ldb_module_ops ldb_password_hash_module_ops = {
2256 .name = "password_hash",
2257 .add = password_hash_add,
2258 .modify = password_hash_modify,