/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- setup_nt_fields
- setup_lm_fields
- setup_kerberos_keys
- setup_primary_kerberos
- setup_primary_kerberos_newer
- setup_primary_wdigest
- setup_supplemental_field
- setup_last_set_field
- setup_kvno_field
- setup_password_fields
- ph_init_context
- ph_op_callback
- get_domain_data_callback
- build_domain_data_request
- password_hash_add
- password_hash_add_do_add
- password_hash_modify
- ph_modify_callback
- ph_mod_search_callback
- password_hash_mod_search_self
- password_hash_mod_do_mod
1 /*
2 ldb database module
3
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
8
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.
13
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.
18
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/>.
21 */
22
23 /*
24 * Name: ldb
25 *
26 * Component: ldb password_hash module
27 *
28 * Description: correctly update hash values based on changes to userPassword and friends
29 *
30 * Author: Andrew Bartlett
31 * Author: Stefan Metzmacher
32 */
33
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 "dsdb/common/flags.h"
46 #include "dsdb/samdb/ldb_modules/password_modules.h"
47 #include "librpc/ndr/libndr.h"
48 #include "librpc/gen_ndr/ndr_drsblobs.h"
49 #include "../lib/crypto/crypto.h"
50 #include "param/param.h"
51
52 /* If we have decided there is reason to work on this request, then
53 * setup all the password hash types correctly.
54 *
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.
58 *
59 * Once this is done (which could update anything at all), we
60 * calculate the password hashes.
61 *
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...
66 *
67 * Finally, if the administrator has requested that a password history
68 * be maintained, then this should also be written out.
69 *
70 */
71
72 struct ph_context {
73
74 struct ldb_module *module;
75 struct ldb_request *req;
76
77 struct ldb_request *dom_req;
78 struct ldb_reply *dom_res;
79
80 struct ldb_reply *search_res;
81
82 struct dom_sid *domain_sid;
83 struct domain_data *domain;
84 };
85
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;
93 };
94
95 struct setup_password_fields_io {
96 struct ph_context *ac;
97 struct domain_data *domain;
98 struct smb_krb5_context *smb_krb5_context;
99
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;
107
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;
116
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;
127
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;
145 };
146
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 */
149
150 static int setup_nt_fields(struct setup_password_fields_io *io)
/* [<][>][^][v][top][bottom][index][help] */
151 {
152 struct ldb_context *ldb;
153 uint32_t i;
154
155 io->g.nt_hash = io->n.nt_hash;
156 ldb = ldb_module_get_ctx(io->ac->module);
157
158 if (io->domain->pwdHistoryLength == 0) {
159 return LDB_SUCCESS;
160 }
161
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;
169 }
170
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];
173 }
174 io->g.nt_history_len = i + 1;
175
176 if (io->g.nt_hash) {
177 io->g.nt_history[0] = *io->g.nt_hash;
178 } else {
179 /*
180 * TODO: is this correct?
181 * the simular behavior is correct for the lm history case
182 */
183 E_md4hash("", io->g.nt_history[0].hash);
184 }
185
186 return LDB_SUCCESS;
187 }
188
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 */
191
192 static int setup_lm_fields(struct setup_password_fields_io *io)
/* [<][>][^][v][top][bottom][index][help] */
193 {
194 struct ldb_context *ldb;
195 uint32_t i;
196
197 io->g.lm_hash = io->n.lm_hash;
198 ldb = ldb_module_get_ctx(io->ac->module);
199
200 if (io->domain->pwdHistoryLength == 0) {
201 return LDB_SUCCESS;
202 }
203
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;
211 }
212
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];
215 }
216 io->g.lm_history_len = i + 1;
217
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);
222 }
223
224 return LDB_SUCCESS;
225 }
226
227 static int setup_kerberos_keys(struct setup_password_fields_io *io)
/* [<][>][^][v][top][bottom][index][help] */
228 {
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;
235
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;
239
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 */
243
244 /*
245 * Determine a salting principal
246 */
247 if (io->u.is_computer) {
248 char *name;
249 char *saltbody;
250
251 name = talloc_strdup(io->ac, io->u.sAMAccountName);
252 if (!name) {
253 ldb_oom(ldb);
254 return LDB_ERR_OPERATIONS_ERROR;
255 }
256
257 if (name[strlen(name)-1] == '$') {
258 name[strlen(name)-1] = '\0';
259 }
260
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;
265 }
266
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;
274
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;
279 }
280
281 p = strchr(user_principal_name, '@');
282 if (p) {
283 p[0] = '\0';
284 }
285
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);
295 }
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;
302 }
303
304 /*
305 * create salt from salt_principal
306 */
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;
316 }
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;
325 }
326 salt.saltvalue.data = discard_const(io->g.salt);
327 salt.saltvalue.length = strlen(io->g.salt);
328
329 /*
330 * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of
331 * the salt and the cleartext password
332 */
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;
344 }
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;
352 }
353
354 /*
355 * create ENCTYPE_AES128_CTS_HMAC_SHA1_96 key out of
356 * the salt and the cleartext password
357 */
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;
369 }
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;
377 }
378
379 /*
380 * create ENCTYPE_DES_CBC_MD5 key out of
381 * the salt and the cleartext password
382 */
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;
394 }
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;
402 }
403
404 /*
405 * create ENCTYPE_DES_CBC_CRC key out of
406 * the salt and the cleartext password
407 */
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;
419 }
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;
427 }
428
429 return LDB_SUCCESS;
430 }
431
432 static int setup_primary_kerberos(struct setup_password_fields_io *io,
/* [<][>][^][v][top][bottom][index][help] */
433 const struct supplementalCredentialsBlob *old_scb,
434 struct package_PrimaryKerberosBlob *pkb)
435 {
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;
443
444 ldb = ldb_module_get_ctx(io->ac->module);
445
446 /*
447 * prepare generation of keys
448 *
449 * ENCTYPE_DES_CBC_MD5
450 * ENCTYPE_DES_CBC_CRC
451 */
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;
461 }
462
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;
467
468 /* initialize the old keys to zero */
469 pkb3->num_old_keys = 0;
470 pkb3->old_keys = NULL;
471
472 /* if there're no old keys, then we're done */
473 if (!old_scb) {
474 return LDB_SUCCESS;
475 }
476
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;
480 }
481
482 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
483 continue;
484 }
485
486 old_scp = &old_scb->sub.packages[i];
487 break;
488 }
489 /* Primary:Kerberos element of supplementalCredentials */
490 if (old_scp) {
491 DATA_BLOB blob;
492
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;
497 }
498
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;
509 }
510
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;
517 }
518
519 old_pkb3 = &_old_pkb.ctr.ctr3;
520 }
521
522 /* if we didn't found the old keys we're done */
523 if (!old_pkb3) {
524 return LDB_SUCCESS;
525 }
526
527 /* fill in the old keys */
528 pkb3->num_old_keys = old_pkb3->num_keys;
529 pkb3->old_keys = old_pkb3->keys;
530
531 return LDB_SUCCESS;
532 }
533
534 static int setup_primary_kerberos_newer(struct setup_password_fields_io *io,
/* [<][>][^][v][top][bottom][index][help] */
535 const struct supplementalCredentialsBlob *old_scb,
536 struct package_PrimaryKerberosBlob *pkb)
537 {
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;
545
546 ldb = ldb_module_get_ctx(io->ac->module);
547
548 /*
549 * prepare generation of keys
550 *
551 * ENCTYPE_AES256_CTS_HMAC_SHA1_96
552 * ENCTYPE_AES128_CTS_HMAC_SHA1_96
553 * ENCTYPE_DES_CBC_MD5
554 * ENCTYPE_DES_CBC_CRC
555 */
556 pkb->version = 4;
557 pkb4->salt.string = io->g.salt;
558 pkb4->default_iteration_count = 4096;
559 pkb4->num_keys = 4;
560
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;
567 }
568
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;
581
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;
587
588 /* if there're no old keys, then we're done */
589 if (!old_scb) {
590 return LDB_SUCCESS;
591 }
592
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;
596 }
597
598 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
599 continue;
600 }
601
602 old_scp = &old_scb->sub.packages[i];
603 break;
604 }
605 /* Primary:Kerberos-Newer-Keys element of supplementalCredentials */
606 if (old_scp) {
607 DATA_BLOB blob;
608
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;
613 }
614
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;
627 }
628
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;
635 }
636
637 old_pkb4 = &_old_pkb.ctr.ctr4;
638 }
639
640 /* if we didn't found the old keys we're done */
641 if (!old_pkb4) {
642 return LDB_SUCCESS;
643 }
644
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;
650
651 return LDB_SUCCESS;
652 }
653
654 static int setup_primary_wdigest(struct setup_password_fields_io *io,
/* [<][>][^][v][top][bottom][index][help] */
655 const struct supplementalCredentialsBlob *old_scb,
656 struct package_PrimaryWDigestBlob *pdb)
657 {
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[] = {
681 /*
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...
685 *
686 * I can't reproduce all values which should contain "Digest" as realm,
687 * am I doing something wrong or is w2k3 just broken...?
688 *
689 * W2K3 fills in following for a user:
690 *
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
694 *
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
724 *
725 * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
726 * sAMAccountName: NewUser2Sam
727 *
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
757 */
758
759 /*
760 * sAMAccountName, netbios_domain
761 */
762 {
763 .user = &sAMAccountName,
764 .realm = &netbios_domain,
765 },
766 {
767 .user = &sAMAccountName_l,
768 .realm = &netbios_domain_l,
769 },
770 {
771 .user = &sAMAccountName_u,
772 .realm = &netbios_domain_u,
773 },
774 {
775 .user = &sAMAccountName,
776 .realm = &netbios_domain_u,
777 },
778 {
779 .user = &sAMAccountName,
780 .realm = &netbios_domain_l,
781 },
782 {
783 .user = &sAMAccountName_u,
784 .realm = &netbios_domain_l,
785 },
786 {
787 .user = &sAMAccountName_l,
788 .realm = &netbios_domain_u,
789 },
790 /*
791 * sAMAccountName, dns_domain
792 */
793 {
794 .user = &sAMAccountName,
795 .realm = &dns_domain,
796 },
797 {
798 .user = &sAMAccountName_l,
799 .realm = &dns_domain_l,
800 },
801 {
802 .user = &sAMAccountName_u,
803 .realm = &dns_domain_u,
804 },
805 {
806 .user = &sAMAccountName,
807 .realm = &dns_domain_u,
808 },
809 {
810 .user = &sAMAccountName,
811 .realm = &dns_domain_l,
812 },
813 {
814 .user = &sAMAccountName_u,
815 .realm = &dns_domain_l,
816 },
817 {
818 .user = &sAMAccountName_l,
819 .realm = &dns_domain_u,
820 },
821 /*
822 * userPrincipalName, no realm
823 */
824 {
825 .user = &userPrincipalName,
826 },
827 {
828 /*
829 * NOTE: w2k3 messes this up, if the user has a real userPrincipalName,
830 * the fallback to the sAMAccountName based userPrincipalName is correct
831 */
832 .user = &userPrincipalName_l,
833 },
834 {
835 .user = &userPrincipalName_u,
836 },
837 /*
838 * nt4dom\sAMAccountName, no realm
839 */
840 {
841 .user = &sAMAccountName,
842 .nt4dom = &netbios_domain
843 },
844 {
845 .user = &sAMAccountName_l,
846 .nt4dom = &netbios_domain_l
847 },
848 {
849 .user = &sAMAccountName_u,
850 .nt4dom = &netbios_domain_u
851 },
852
853 /*
854 * the following ones are guessed depending on the technet2 article
855 * but not reproducable on a w2k3 server
856 */
857 /* sAMAccountName with "Digest" realm */
858 {
859 .user = &sAMAccountName,
860 .realm = &digest
861 },
862 {
863 .user = &sAMAccountName_l,
864 .realm = &digest
865 },
866 {
867 .user = &sAMAccountName_u,
868 .realm = &digest
869 },
870 /* userPrincipalName with "Digest" realm */
871 {
872 .user = &userPrincipalName,
873 .realm = &digest
874 },
875 {
876 .user = &userPrincipalName_l,
877 .realm = &digest
878 },
879 {
880 .user = &userPrincipalName_u,
881 .realm = &digest
882 },
883 /* nt4dom\\sAMAccountName with "Digest" realm */
884 {
885 .user = &sAMAccountName,
886 .nt4dom = &netbios_domain,
887 .realm = &digest
888 },
889 {
890 .user = &sAMAccountName_l,
891 .nt4dom = &netbios_domain_l,
892 .realm = &digest
893 },
894 {
895 .user = &sAMAccountName_u,
896 .nt4dom = &netbios_domain_u,
897 .realm = &digest
898 },
899 };
900
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;
907 }
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;
912 }
913
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;
922 }
923 }
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;
929 }
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;
934 }
935
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;
941 }
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;
946 }
947
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);
951
952 digest = data_blob_string_const("Digest");
953
954 delim = data_blob_string_const(":");
955 backslash = data_blob_string_const("\\");
956
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;
962 }
963
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);
970 }
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);
975 }
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);
979 }
980
981 return LDB_SUCCESS;
982 }
983
984 static int setup_supplemental_field(struct setup_password_fields_io *io)
/* [<][>][^][v][top][bottom][index][help] */
985 {
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
1030 ZERO_STRUCT(zero16);
1031 ZERO_STRUCT(names);
1032
1033 ldb = ldb_module_get_ctx(io->ac->module);
1034
1035 if (!io->n.cleartext_utf8) {
1036 /*
1037 * when we don't have a cleartext password
1038 * we can't setup a supplementalCredential value
1039 */
1040 return LDB_SUCCESS;
1041 }
1042
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;
1056 }
1057
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);
1065 }
1066 }
1067
1068 /* TODO: do the correct check for this, it maybe depends on the functional level? */
1069 do_newer_keys = lp_parm_bool(ldb_get_opaque(ldb, "loadparm"),
1070 NULL, "password_hash", "create_aes_key", false);
1071
1072 if (io->domain->store_cleartext &&
1073 (io->u.user_account_control & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) {
1074 do_cleartext = true;
1075 }
1076
1077 /*
1078 * The ordering is this
1079 *
1080 * Primary:Kerberos-Newer-Keys (optional)
1081 * Primary:Kerberos
1082 * Primary:WDigest
1083 * Primary:CLEARTEXT (optional)
1084 *
1085 * And the 'Packages' package is insert before the last
1086 * other package.
1087 */
1088 if (do_newer_keys) {
1089 /* Primary:Kerberos-Newer-Keys */
1090 nkn = &names[num_names++];
1091 pkn = &packages[num_packages++];
1092 }
1093
1094 /* Primary:Kerberos */
1095 nk = &names[num_names++];
1096 pk = &packages[num_packages++];
1097
1098 if (!do_cleartext) {
1099 /* Packages */
1100 pp = &packages[num_packages++];
1101 }
1102
1103 /* Primary:WDigest */
1104 nd = &names[num_names++];
1105 pd = &packages[num_packages++];
1106
1107 if (do_cleartext) {
1108 /* Packages */
1109 pp = &packages[num_packages++];
1110
1111 /* Primary:CLEARTEXT */
1112 nc = &names[num_names++];
1113 pc = &packages[num_packages++];
1114 }
1115
1116 if (pkn) {
1117 /*
1118 * setup 'Primary:Kerberos-Newer-Keys' element
1119 */
1120 *nkn = "Kerberos-Newer-Keys";
1121
1122 ret = setup_primary_kerberos_newer(io, old_scb, &pknb);
1123 if (ret != LDB_SUCCESS) {
1124 return ret;
1125 }
1126
1127 ndr_err = ndr_push_struct_blob(&pknb_blob, io->ac,
1128 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1129 &pknb,
1130 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1131 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1132 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1133 ldb_asprintf_errstring(ldb,
1134 "setup_supplemental_field: "
1135 "failed to push package_PrimaryKerberosNeverBlob: %s",
1136 nt_errstr(status));
1137 return LDB_ERR_OPERATIONS_ERROR;
1138 }
1139 pknb_hexstr = data_blob_hex_string(io->ac, &pknb_blob);
1140 if (!pknb_hexstr) {
1141 ldb_oom(ldb);
1142 return LDB_ERR_OPERATIONS_ERROR;
1143 }
1144 pkn->name = "Primary:Kerberos-Newer-Keys";
1145 pkn->reserved = 1;
1146 pkn->data = pknb_hexstr;
1147 }
1148
1149 /*
1150 * setup 'Primary:Kerberos' element
1151 */
1152 *nk = "Kerberos";
1153
1154 ret = setup_primary_kerberos(io, old_scb, &pkb);
1155 if (ret != LDB_SUCCESS) {
1156 return ret;
1157 }
1158
1159 ndr_err = ndr_push_struct_blob(&pkb_blob, io->ac,
1160 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1161 &pkb,
1162 (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1163 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1164 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1165 ldb_asprintf_errstring(ldb,
1166 "setup_supplemental_field: "
1167 "failed to push package_PrimaryKerberosBlob: %s",
1168 nt_errstr(status));
1169 return LDB_ERR_OPERATIONS_ERROR;
1170 }
1171 pkb_hexstr = data_blob_hex_string(io->ac, &pkb_blob);
1172 if (!pkb_hexstr) {
1173 ldb_oom(ldb);
1174 return LDB_ERR_OPERATIONS_ERROR;
1175 }
1176 pk->name = "Primary:Kerberos";
1177 pk->reserved = 1;
1178 pk->data = pkb_hexstr;
1179
1180 /*
1181 * setup 'Primary:WDigest' element
1182 */
1183 *nd = "WDigest";
1184
1185 ret = setup_primary_wdigest(io, old_scb, &pdb);
1186 if (ret != LDB_SUCCESS) {
1187 return ret;
1188 }
1189
1190 ndr_err = ndr_push_struct_blob(&pdb_blob, io->ac,
1191 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1192 &pdb,
1193 (ndr_push_flags_fn_t)ndr_push_package_PrimaryWDigestBlob);
1194 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1195 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1196 ldb_asprintf_errstring(ldb,
1197 "setup_supplemental_field: "
1198 "failed to push package_PrimaryWDigestBlob: %s",
1199 nt_errstr(status));
1200 return LDB_ERR_OPERATIONS_ERROR;
1201 }
1202 pdb_hexstr = data_blob_hex_string(io->ac, &pdb_blob);
1203 if (!pdb_hexstr) {
1204 ldb_oom(ldb);
1205 return LDB_ERR_OPERATIONS_ERROR;
1206 }
1207 pd->name = "Primary:WDigest";
1208 pd->reserved = 1;
1209 pd->data = pdb_hexstr;
1210
1211 /*
1212 * setup 'Primary:CLEARTEXT' element
1213 */
1214 if (pc) {
1215 *nc = "CLEARTEXT";
1216
1217 pcb.cleartext = *io->n.cleartext_utf16;
1218
1219 ndr_err = ndr_push_struct_blob(&pcb_blob, io->ac,
1220 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1221 &pcb,
1222 (ndr_push_flags_fn_t)ndr_push_package_PrimaryCLEARTEXTBlob);
1223 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1224 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1225 ldb_asprintf_errstring(ldb,
1226 "setup_supplemental_field: "
1227 "failed to push package_PrimaryCLEARTEXTBlob: %s",
1228 nt_errstr(status));
1229 return LDB_ERR_OPERATIONS_ERROR;
1230 }
1231 pcb_hexstr = data_blob_hex_string(io->ac, &pcb_blob);
1232 if (!pcb_hexstr) {
1233 ldb_oom(ldb);
1234 return LDB_ERR_OPERATIONS_ERROR;
1235 }
1236 pc->name = "Primary:CLEARTEXT";
1237 pc->reserved = 1;
1238 pc->data = pcb_hexstr;
1239 }
1240
1241 /*
1242 * setup 'Packages' element
1243 */
1244 pb.names = names;
1245 ndr_err = ndr_push_struct_blob(&pb_blob, io->ac,
1246 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1247 &pb,
1248 (ndr_push_flags_fn_t)ndr_push_package_PackagesBlob);
1249 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1250 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1251 ldb_asprintf_errstring(ldb,
1252 "setup_supplemental_field: "
1253 "failed to push package_PackagesBlob: %s",
1254 nt_errstr(status));
1255 return LDB_ERR_OPERATIONS_ERROR;
1256 }
1257 pb_hexstr = data_blob_hex_string(io->ac, &pb_blob);
1258 if (!pb_hexstr) {
1259 ldb_oom(ldb);
1260 return LDB_ERR_OPERATIONS_ERROR;
1261 }
1262 pp->name = "Packages";
1263 pp->reserved = 2;
1264 pp->data = pb_hexstr;
1265
1266 /*
1267 * setup 'supplementalCredentials' value
1268 */
1269 ZERO_STRUCT(scb);
1270 scb.sub.num_packages = num_packages;
1271 scb.sub.packages = packages;
1272
1273 ndr_err = ndr_push_struct_blob(&io->g.supplemental, io->ac,
1274 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1275 &scb,
1276 (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
1277 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1278 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1279 ldb_asprintf_errstring(ldb,
1280 "setup_supplemental_field: "
1281 "failed to push supplementalCredentialsBlob: %s",
1282 nt_errstr(status));
1283 return LDB_ERR_OPERATIONS_ERROR;
1284 }
1285
1286 return LDB_SUCCESS;
1287 }
1288
1289 static int setup_last_set_field(struct setup_password_fields_io *io)
/* [<][>][^][v][top][bottom][index][help] */
1290 {
1291 /* set it as now */
1292 unix_to_nt_time(&io->g.last_set, time(NULL));
1293
1294 return LDB_SUCCESS;
1295 }
1296
1297 static int setup_kvno_field(struct setup_password_fields_io *io)
/* [<][>][^][v][top][bottom][index][help] */
1298 {
1299 /* increment by one */
1300 io->g.kvno = io->o.kvno + 1;
1301
1302 return LDB_SUCCESS;
1303 }
1304
1305 static int setup_password_fields(struct setup_password_fields_io *io)
/* [<][>][^][v][top][bottom][index][help] */
1306 {
1307 struct ldb_context *ldb;
1308 bool ok;
1309 int ret;
1310 size_t converted_pw_len;
1311
1312 ldb = ldb_module_get_ctx(io->ac->module);
1313
1314 /*
1315 * refuse the change if someone want to change the cleartext
1316 * and supply his own hashes at the same time...
1317 */
1318 if ((io->n.cleartext_utf8 || io->n.cleartext_utf16) && (io->n.nt_hash || io->n.lm_hash)) {
1319 ldb_asprintf_errstring(ldb,
1320 "setup_password_fields: "
1321 "it's only allowed to set the cleartext password or the password hashes");
1322 return LDB_ERR_UNWILLING_TO_PERFORM;
1323 }
1324
1325 if (io->n.cleartext_utf8 && io->n.cleartext_utf16) {
1326 ldb_asprintf_errstring(ldb,
1327 "setup_password_fields: "
1328 "it's only allowed to set the cleartext password as userPassword or clearTextPasssword, not both at once");
1329 return LDB_ERR_UNWILLING_TO_PERFORM;
1330 }
1331
1332 if (io->n.cleartext_utf8) {
1333 char **cleartext_utf16_str;
1334 struct ldb_val *cleartext_utf16_blob;
1335 io->n.cleartext_utf16 = cleartext_utf16_blob = talloc(io->ac, struct ldb_val);
1336 if (!io->n.cleartext_utf16) {
1337 ldb_oom(ldb);
1338 return LDB_ERR_OPERATIONS_ERROR;
1339 }
1340 if (!convert_string_talloc_convenience(io->ac, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1341 CH_UTF8, CH_UTF16, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length,
1342 (void **)&cleartext_utf16_str, &converted_pw_len, false)) {
1343 ldb_asprintf_errstring(ldb,
1344 "setup_password_fields: "
1345 "failed to generate UTF16 password from cleartext UTF8 password");
1346 return LDB_ERR_OPERATIONS_ERROR;
1347 }
1348 *cleartext_utf16_blob = data_blob_const(cleartext_utf16_str, converted_pw_len);
1349 } else if (io->n.cleartext_utf16) {
1350 char *cleartext_utf8_str;
1351 struct ldb_val *cleartext_utf8_blob;
1352 io->n.cleartext_utf8 = cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
1353 if (!io->n.cleartext_utf8) {
1354 ldb_oom(ldb);
1355 return LDB_ERR_OPERATIONS_ERROR;
1356 }
1357 if (!convert_string_talloc_convenience(io->ac, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1358 CH_UTF16MUNGED, CH_UTF8, io->n.cleartext_utf16->data, io->n.cleartext_utf16->length,
1359 (void **)&cleartext_utf8_str, &converted_pw_len, false)) {
1360 /* We can't bail out entirely, as these unconvertable passwords are frustratingly valid */
1361 io->n.cleartext_utf8 = NULL;
1362 talloc_free(cleartext_utf8_blob);
1363 }
1364 *cleartext_utf8_blob = data_blob_const(cleartext_utf8_str, converted_pw_len);
1365 }
1366 if (io->n.cleartext_utf16) {
1367 struct samr_Password *nt_hash;
1368 nt_hash = talloc(io->ac, struct samr_Password);
1369 if (!nt_hash) {
1370 ldb_oom(ldb);
1371 return LDB_ERR_OPERATIONS_ERROR;
1372 }
1373 io->n.nt_hash = nt_hash;
1374
1375 /* compute the new nt hash */
1376 mdfour(nt_hash->hash, io->n.cleartext_utf16->data, io->n.cleartext_utf16->length);
1377 }
1378
1379 if (io->n.cleartext_utf8) {
1380 struct samr_Password *lm_hash;
1381 char *cleartext_unix;
1382 if (convert_string_talloc_convenience(io->ac, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1383 CH_UTF8, CH_UNIX, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length,
1384 (void **)&cleartext_unix, &converted_pw_len, false)) {
1385 lm_hash = talloc(io->ac, struct samr_Password);
1386 if (!lm_hash) {
1387 ldb_oom(ldb);
1388 return LDB_ERR_OPERATIONS_ERROR;
1389 }
1390
1391 /* compute the new lm hash. */
1392 ok = E_deshash((char *)cleartext_unix, lm_hash->hash);
1393 if (ok) {
1394 io->n.lm_hash = lm_hash;
1395 } else {
1396 talloc_free(lm_hash->hash);
1397 }
1398 }
1399
1400 ret = setup_kerberos_keys(io);
1401 if (ret != 0) {
1402 return ret;
1403 }
1404 }
1405
1406 ret = setup_nt_fields(io);
1407 if (ret != 0) {
1408 return ret;
1409 }
1410
1411 ret = setup_lm_fields(io);
1412 if (ret != 0) {
1413 return ret;
1414 }
1415
1416 ret = setup_supplemental_field(io);
1417 if (ret != 0) {
1418 return ret;
1419 }
1420
1421 ret = setup_last_set_field(io);
1422 if (ret != 0) {
1423 return ret;
1424 }
1425
1426 ret = setup_kvno_field(io);
1427 if (ret != 0) {
1428 return ret;
1429 }
1430
1431 return LDB_SUCCESS;
1432 }
1433
1434 static struct ph_context *ph_init_context(struct ldb_module *module,
/* [<][>][^][v][top][bottom][index][help] */
1435 struct ldb_request *req)
1436 {
1437 struct ldb_context *ldb;
1438 struct ph_context *ac;
1439
1440 ldb = ldb_module_get_ctx(module);
1441
1442 ac = talloc_zero(req, struct ph_context);
1443 if (ac == NULL) {
1444 ldb_set_errstring(ldb, "Out of Memory");
1445 return NULL;
1446 }
1447
1448 ac->module = module;
1449 ac->req = req;
1450
1451 return ac;
1452 }
1453
1454 static int ph_op_callback(struct ldb_request *req, struct ldb_reply *ares)
/* [<][>][^][v][top][bottom][index][help] */
1455 {
1456 struct ph_context *ac;
1457
1458 ac = talloc_get_type(req->context, struct ph_context);
1459
1460 if (!ares) {
1461 return ldb_module_done(ac->req, NULL, NULL,
1462 LDB_ERR_OPERATIONS_ERROR);
1463 }
1464 if (ares->error != LDB_SUCCESS) {
1465 return ldb_module_done(ac->req, ares->controls,
1466 ares->response, ares->error);
1467 }
1468
1469 if (ares->type != LDB_REPLY_DONE) {
1470 talloc_free(ares);
1471 return ldb_module_done(ac->req, NULL, NULL,
1472 LDB_ERR_OPERATIONS_ERROR);
1473 }
1474
1475 return ldb_module_done(ac->req, ares->controls,
1476 ares->response, ares->error);
1477 }
1478
1479 static int password_hash_add_do_add(struct ph_context *ac);
1480 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares);
1481 static int password_hash_mod_search_self(struct ph_context *ac);
1482 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares);
1483 static int password_hash_mod_do_mod(struct ph_context *ac);
1484
1485 static int get_domain_data_callback(struct ldb_request *req,
/* [<][>][^][v][top][bottom][index][help] */
1486 struct ldb_reply *ares)
1487 {
1488 struct ldb_context *ldb;
1489 struct domain_data *data;
1490 struct ph_context *ac;
1491 int ret;
1492 char *tmp;
1493 char *p;
1494
1495 ac = talloc_get_type(req->context, struct ph_context);
1496 ldb = ldb_module_get_ctx(ac->module);
1497
1498 if (!ares) {
1499 return ldb_module_done(ac->req, NULL, NULL,
1500 LDB_ERR_OPERATIONS_ERROR);
1501 }
1502 if (ares->error != LDB_SUCCESS) {
1503 return ldb_module_done(ac->req, ares->controls,
1504 ares->response, ares->error);
1505 }
1506
1507 switch (ares->type) {
1508 case LDB_REPLY_ENTRY:
1509 if (ac->domain != NULL) {
1510 ldb_set_errstring(ldb, "Too many results");
1511 return ldb_module_done(ac->req, NULL, NULL,
1512 LDB_ERR_OPERATIONS_ERROR);
1513 }
1514
1515 data = talloc_zero(ac, struct domain_data);
1516 if (data == NULL) {
1517 return ldb_module_done(ac->req, NULL, NULL,
1518 LDB_ERR_OPERATIONS_ERROR);
1519 }
1520
1521 data->pwdProperties = samdb_result_uint(ares->message, "pwdProperties", 0);
1522 data->store_cleartext = data->pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
1523 data->pwdHistoryLength = samdb_result_uint(ares->message, "pwdHistoryLength", 0);
1524
1525 /* For a domain DN, this puts things in dotted notation */
1526 /* For builtin domains, this will give details for the host,
1527 * but that doesn't really matter, as it's just used for salt
1528 * and kerberos principals, which don't exist here */
1529
1530 tmp = ldb_dn_canonical_string(data, ares->message->dn);
1531 if (!tmp) {
1532 return ldb_module_done(ac->req, NULL, NULL,
1533 LDB_ERR_OPERATIONS_ERROR);
1534 }
1535
1536 /* But it puts a trailing (or just before 'builtin') / on things, so kill that */
1537 p = strchr(tmp, '/');
1538 if (p) {
1539 p[0] = '\0';
1540 }
1541
1542 data->dns_domain = strlower_talloc(data, tmp);
1543 if (data->dns_domain == NULL) {
1544 ldb_oom(ldb);
1545 return ldb_module_done(ac->req, NULL, NULL,
1546 LDB_ERR_OPERATIONS_ERROR);
1547 }
1548 data->realm = strupper_talloc(data, tmp);
1549 if (data->realm == NULL) {
1550 ldb_oom(ldb);
1551 return ldb_module_done(ac->req, NULL, NULL,
1552 LDB_ERR_OPERATIONS_ERROR);
1553 }
1554 /* FIXME: NetbIOS name is *always* the first domain component ?? -SSS */
1555 p = strchr(tmp, '.');
1556 if (p) {
1557 p[0] = '\0';
1558 }
1559 data->netbios_domain = strupper_talloc(data, tmp);
1560 if (data->netbios_domain == NULL) {
1561 ldb_oom(ldb);
1562 return ldb_module_done(ac->req, NULL, NULL,
1563 LDB_ERR_OPERATIONS_ERROR);
1564 }
1565
1566 talloc_free(tmp);
1567 ac->domain = data;
1568 break;
1569
1570 case LDB_REPLY_DONE:
1571
1572 /* call the next step */
1573 switch (ac->req->operation) {
1574 case LDB_ADD:
1575 ret = password_hash_add_do_add(ac);
1576 break;
1577
1578 case LDB_MODIFY:
1579 ret = password_hash_mod_do_mod(ac);
1580 break;
1581
1582 default:
1583 ret = LDB_ERR_OPERATIONS_ERROR;
1584 break;
1585 }
1586 if (ret != LDB_SUCCESS) {
1587 return ldb_module_done(ac->req, NULL, NULL, ret);
1588 }
1589
1590 case LDB_REPLY_REFERRAL:
1591 /* ignore */
1592 break;
1593 }
1594
1595 talloc_free(ares);
1596 return LDB_SUCCESS;
1597 }
1598
1599 static int build_domain_data_request(struct ph_context *ac)
/* [<][>][^][v][top][bottom][index][help] */
1600 {
1601 /* attrs[] is returned from this function in
1602 ac->dom_req->op.search.attrs, so it must be static, as
1603 otherwise the compiler can put it on the stack */
1604 struct ldb_context *ldb;
1605 static const char * const attrs[] = { "pwdProperties", "pwdHistoryLength", NULL };
1606 char *filter;
1607
1608 ldb = ldb_module_get_ctx(ac->module);
1609
1610 filter = talloc_asprintf(ac,
1611 "(&(objectSid=%s)(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain)))",
1612 ldap_encode_ndr_dom_sid(ac, ac->domain_sid));
1613 if (filter == NULL) {
1614 ldb_oom(ldb);
1615 return LDB_ERR_OPERATIONS_ERROR;
1616 }
1617
1618 return ldb_build_search_req(&ac->dom_req, ldb, ac,
1619 ldb_get_default_basedn(ldb),
1620 LDB_SCOPE_SUBTREE,
1621 filter, attrs,
1622 NULL,
1623 ac, get_domain_data_callback,
1624 ac->req);
1625 }
1626
1627 static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
/* [<][>][^][v][top][bottom][index][help] */
1628 {
1629 struct ldb_context *ldb;
1630 struct ph_context *ac;
1631 struct ldb_message_element *sambaAttr;
1632 struct ldb_message_element *clearTextPasswordAttr;
1633 struct ldb_message_element *ntAttr;
1634 struct ldb_message_element *lmAttr;
1635 int ret;
1636
1637 ldb = ldb_module_get_ctx(module);
1638
1639 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add\n");
1640
1641 if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
1642 return ldb_next_request(module, req);
1643 }
1644
1645 /* If the caller is manipulating the local passwords directly, let them pass */
1646 if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
1647 req->op.add.message->dn) == 0) {
1648 return ldb_next_request(module, req);
1649 }
1650
1651 /* nobody must touch these fields */
1652 if (ldb_msg_find_element(req->op.add.message, "ntPwdHistory")) {
1653 return LDB_ERR_UNWILLING_TO_PERFORM;
1654 }
1655 if (ldb_msg_find_element(req->op.add.message, "lmPwdHistory")) {
1656 return LDB_ERR_UNWILLING_TO_PERFORM;
1657 }
1658 if (ldb_msg_find_element(req->op.add.message, "supplementalCredentials")) {
1659 return LDB_ERR_UNWILLING_TO_PERFORM;
1660 }
1661
1662 /* If no part of this ADD touches the userPassword, or the NT
1663 * or LM hashes, then we don't need to make any changes. */
1664
1665 sambaAttr = ldb_msg_find_element(req->op.mod.message, "userPassword");
1666 clearTextPasswordAttr = ldb_msg_find_element(req->op.mod.message, "clearTextPassword");
1667 ntAttr = ldb_msg_find_element(req->op.mod.message, "unicodePwd");
1668 lmAttr = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
1669
1670 if ((!sambaAttr) && (!clearTextPasswordAttr) && (!ntAttr) && (!lmAttr)) {
1671 return ldb_next_request(module, req);
1672 }
1673
1674 /* if it is not an entry of type person its an error */
1675 /* TODO: remove this when userPassword will be in schema */
1676 if (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "person")) {
1677 ldb_set_errstring(ldb, "Cannot set a password on entry that does not have objectClass 'person'");
1678 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1679 }
1680
1681 /* check userPassword is single valued here */
1682 /* TODO: remove this when userPassword will be single valued in schema */
1683 if (sambaAttr && sambaAttr->num_values > 1) {
1684 ldb_set_errstring(ldb, "mupltiple values for userPassword not allowed!\n");
1685 return LDB_ERR_CONSTRAINT_VIOLATION;
1686 }
1687 if (clearTextPasswordAttr && clearTextPasswordAttr->num_values > 1) {
1688 ldb_set_errstring(ldb, "mupltiple values for clearTextPassword not allowed!\n");
1689 return LDB_ERR_CONSTRAINT_VIOLATION;
1690 }
1691
1692 if (ntAttr && (ntAttr->num_values > 1)) {
1693 ldb_set_errstring(ldb, "mupltiple values for unicodePwd not allowed!\n");
1694 return LDB_ERR_CONSTRAINT_VIOLATION;
1695 }
1696 if (lmAttr && (lmAttr->num_values > 1)) {
1697 ldb_set_errstring(ldb, "mupltiple values for dBCSPwd not allowed!\n");
1698 return LDB_ERR_CONSTRAINT_VIOLATION;
1699 }
1700
1701 if (sambaAttr && sambaAttr->num_values == 0) {
1702 ldb_set_errstring(ldb, "userPassword must have a value!\n");
1703 return LDB_ERR_CONSTRAINT_VIOLATION;
1704 }
1705
1706 if (clearTextPasswordAttr && clearTextPasswordAttr->num_values == 0) {
1707 ldb_set_errstring(ldb, "clearTextPassword must have a value!\n");
1708 return LDB_ERR_CONSTRAINT_VIOLATION;
1709 }
1710
1711 if (ntAttr && (ntAttr->num_values == 0)) {
1712 ldb_set_errstring(ldb, "unicodePwd must have a value!\n");
1713 return LDB_ERR_CONSTRAINT_VIOLATION;
1714 }
1715 if (lmAttr && (lmAttr->num_values == 0)) {
1716 ldb_set_errstring(ldb, "dBCSPwd must have a value!\n");
1717 return LDB_ERR_CONSTRAINT_VIOLATION;
1718 }
1719
1720 ac = ph_init_context(module, req);
1721 if (ac == NULL) {
1722 return LDB_ERR_OPERATIONS_ERROR;
1723 }
1724
1725 /* get user domain data */
1726 ac->domain_sid = samdb_result_sid_prefix(ac, req->op.add.message, "objectSid");
1727 if (ac->domain_sid == NULL) {
1728 ldb_debug(ldb, LDB_DEBUG_ERROR,
1729 "can't handle entry with missing objectSid!\n");
1730 return LDB_ERR_OPERATIONS_ERROR;
1731 }
1732
1733 ret = build_domain_data_request(ac);
1734 if (ret != LDB_SUCCESS) {
1735 return ret;
1736 }
1737
1738 return ldb_next_request(module, ac->dom_req);
1739 }
1740
1741 static int password_hash_add_do_add(struct ph_context *ac)
/* [<][>][^][v][top][bottom][index][help] */
1742 {
1743 struct ldb_context *ldb;
1744 struct ldb_request *down_req;
1745 struct smb_krb5_context *smb_krb5_context;
1746 struct ldb_message *msg;
1747 struct setup_password_fields_io io;
1748 int ret;
1749
1750 ldb = ldb_module_get_ctx(ac->module);
1751
1752 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
1753 if (msg == NULL) {
1754 return LDB_ERR_OPERATIONS_ERROR;
1755 }
1756
1757 /* Some operations below require kerberos contexts */
1758 if (smb_krb5_init_context(ac,
1759 ldb_get_event_context(ldb),
1760 (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"),
1761 &smb_krb5_context) != 0) {
1762 return LDB_ERR_OPERATIONS_ERROR;
1763 }
1764
1765 ZERO_STRUCT(io);
1766 io.ac = ac;
1767 io.domain = ac->domain;
1768 io.smb_krb5_context = smb_krb5_context;
1769
1770 io.u.user_account_control = samdb_result_uint(msg, "userAccountControl", 0);
1771 io.u.sAMAccountName = samdb_result_string(msg, "samAccountName", NULL);
1772 io.u.user_principal_name = samdb_result_string(msg, "userPrincipalName", NULL);
1773 io.u.is_computer = ldb_msg_check_string_attribute(msg, "objectClass", "computer");
1774
1775 io.n.cleartext_utf8 = ldb_msg_find_ldb_val(msg, "userPassword");
1776 io.n.cleartext_utf16 = ldb_msg_find_ldb_val(msg, "clearTextPassword");
1777 io.n.nt_hash = samdb_result_hash(io.ac, msg, "unicodePwd");
1778 io.n.lm_hash = samdb_result_hash(io.ac, msg, "dBCSPwd");
1779
1780 /* remove attributes */
1781 if (io.n.cleartext_utf8) ldb_msg_remove_attr(msg, "userPassword");
1782 if (io.n.cleartext_utf16) ldb_msg_remove_attr(msg, "clearTextPassword");
1783 if (io.n.nt_hash) ldb_msg_remove_attr(msg, "unicodePwd");
1784 if (io.n.lm_hash) ldb_msg_remove_attr(msg, "dBCSPwd");
1785 ldb_msg_remove_attr(msg, "pwdLastSet");
1786 io.o.kvno = samdb_result_uint(msg, "msDs-KeyVersionNumber", 1) - 1;
1787 ldb_msg_remove_attr(msg, "msDs-KeyVersionNumber");
1788
1789 ret = setup_password_fields(&io);
1790 if (ret != LDB_SUCCESS) {
1791 return ret;
1792 }
1793
1794 if (io.g.nt_hash) {
1795 ret = samdb_msg_add_hash(ldb, ac, msg,
1796 "unicodePwd", io.g.nt_hash);
1797 if (ret != LDB_SUCCESS) {
1798 return ret;
1799 }
1800 }
1801 if (io.g.lm_hash) {
1802 ret = samdb_msg_add_hash(ldb, ac, msg,
1803 "dBCSPwd", io.g.lm_hash);
1804 if (ret != LDB_SUCCESS) {
1805 return ret;
1806 }
1807 }
1808 if (io.g.nt_history_len > 0) {
1809 ret = samdb_msg_add_hashes(ac, msg,
1810 "ntPwdHistory",
1811 io.g.nt_history,
1812 io.g.nt_history_len);
1813 if (ret != LDB_SUCCESS) {
1814 return ret;
1815 }
1816 }
1817 if (io.g.lm_history_len > 0) {
1818 ret = samdb_msg_add_hashes(ac, msg,
1819 "lmPwdHistory",
1820 io.g.lm_history,
1821 io.g.lm_history_len);
1822 if (ret != LDB_SUCCESS) {
1823 return ret;
1824 }
1825 }
1826 if (io.g.supplemental.length > 0) {
1827 ret = ldb_msg_add_value(msg, "supplementalCredentials",
1828 &io.g.supplemental, NULL);
1829 if (ret != LDB_SUCCESS) {
1830 return ret;
1831 }
1832 }
1833 ret = samdb_msg_add_uint64(ldb, ac, msg,
1834 "pwdLastSet",
1835 io.g.last_set);
1836 if (ret != LDB_SUCCESS) {
1837 return ret;
1838 }
1839 ret = samdb_msg_add_uint(ldb, ac, msg,
1840 "msDs-KeyVersionNumber",
1841 io.g.kvno);
1842 if (ret != LDB_SUCCESS) {
1843 return ret;
1844 }
1845
1846 ret = ldb_build_add_req(&down_req, ldb, ac,
1847 msg,
1848 ac->req->controls,
1849 ac, ph_op_callback,
1850 ac->req);
1851 if (ret != LDB_SUCCESS) {
1852 return ret;
1853 }
1854
1855 return ldb_next_request(ac->module, down_req);
1856 }
1857
1858 static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
/* [<][>][^][v][top][bottom][index][help] */
1859 {
1860 struct ldb_context *ldb;
1861 struct ph_context *ac;
1862 struct ldb_message_element *sambaAttr;
1863 struct ldb_message_element *clearTextAttr;
1864 struct ldb_message_element *ntAttr;
1865 struct ldb_message_element *lmAttr;
1866 struct ldb_message *msg;
1867 struct ldb_request *down_req;
1868 int ret;
1869
1870 ldb = ldb_module_get_ctx(module);
1871
1872 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
1873
1874 if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
1875 return ldb_next_request(module, req);
1876 }
1877
1878 /* If the caller is manipulating the local passwords directly, let them pass */
1879 if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
1880 req->op.mod.message->dn) == 0) {
1881 return ldb_next_request(module, req);
1882 }
1883
1884 /* nobody must touch password Histories */
1885 if (ldb_msg_find_element(req->op.add.message, "ntPwdHistory")) {
1886 return LDB_ERR_UNWILLING_TO_PERFORM;
1887 }
1888 if (ldb_msg_find_element(req->op.add.message, "lmPwdHistory")) {
1889 return LDB_ERR_UNWILLING_TO_PERFORM;
1890 }
1891 if (ldb_msg_find_element(req->op.add.message, "supplementalCredentials")) {
1892 return LDB_ERR_UNWILLING_TO_PERFORM;
1893 }
1894
1895 sambaAttr = ldb_msg_find_element(req->op.mod.message, "userPassword");
1896 clearTextAttr = ldb_msg_find_element(req->op.mod.message, "clearTextPassword");
1897 ntAttr = ldb_msg_find_element(req->op.mod.message, "unicodePwd");
1898 lmAttr = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
1899
1900 /* If no part of this touches the userPassword OR
1901 * clearTextPassword OR unicodePwd and/or dBCSPwd, then we
1902 * don't need to make any changes. For password changes/set
1903 * there should be a 'delete' or a 'modify' on this
1904 * attribute. */
1905 if ((!sambaAttr) && (!clearTextAttr) && (!ntAttr) && (!lmAttr)) {
1906 return ldb_next_request(module, req);
1907 }
1908
1909 /* check passwords are single valued here */
1910 /* TODO: remove this when passwords will be single valued in schema */
1911 if (sambaAttr && (sambaAttr->num_values > 1)) {
1912 return LDB_ERR_CONSTRAINT_VIOLATION;
1913 }
1914 if (clearTextAttr && (clearTextAttr->num_values > 1)) {
1915 return LDB_ERR_CONSTRAINT_VIOLATION;
1916 }
1917 if (ntAttr && (ntAttr->num_values > 1)) {
1918 return LDB_ERR_CONSTRAINT_VIOLATION;
1919 }
1920 if (lmAttr && (lmAttr->num_values > 1)) {
1921 return LDB_ERR_CONSTRAINT_VIOLATION;
1922 }
1923
1924 ac = ph_init_context(module, req);
1925 if (!ac) {
1926 return LDB_ERR_OPERATIONS_ERROR;
1927 }
1928
1929 /* use a new message structure so that we can modify it */
1930 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
1931 if (msg == NULL) {
1932 ldb_oom(ldb);
1933 return LDB_ERR_OPERATIONS_ERROR;
1934 }
1935
1936 /* - remove any modification to the password from the first commit
1937 * we will make the real modification later */
1938 if (sambaAttr) ldb_msg_remove_attr(msg, "userPassword");
1939 if (clearTextAttr) ldb_msg_remove_attr(msg, "clearTextPassword");
1940 if (ntAttr) ldb_msg_remove_attr(msg, "unicodePwd");
1941 if (lmAttr) ldb_msg_remove_attr(msg, "dBCSPwd");
1942
1943 /* if there was nothing else to be modified skip to next step */
1944 if (msg->num_elements == 0) {
1945 return password_hash_mod_search_self(ac);
1946 }
1947
1948 ret = ldb_build_mod_req(&down_req, ldb, ac,
1949 msg,
1950 req->controls,
1951 ac, ph_modify_callback,
1952 req);
1953 if (ret != LDB_SUCCESS) {
1954 return ret;
1955 }
1956
1957 return ldb_next_request(module, down_req);
1958 }
1959
1960 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
/* [<][>][^][v][top][bottom][index][help] */
1961 {
1962 struct ph_context *ac;
1963 int ret;
1964
1965 ac = talloc_get_type(req->context, struct ph_context);
1966
1967 if (!ares) {
1968 return ldb_module_done(ac->req, NULL, NULL,
1969 LDB_ERR_OPERATIONS_ERROR);
1970 }
1971 if (ares->error != LDB_SUCCESS) {
1972 return ldb_module_done(ac->req, ares->controls,
1973 ares->response, ares->error);
1974 }
1975
1976 if (ares->type != LDB_REPLY_DONE) {
1977 talloc_free(ares);
1978 return ldb_module_done(ac->req, NULL, NULL,
1979 LDB_ERR_OPERATIONS_ERROR);
1980 }
1981
1982 ret = password_hash_mod_search_self(ac);
1983 if (ret != LDB_SUCCESS) {
1984 return ldb_module_done(ac->req, NULL, NULL, ret);
1985 }
1986
1987 talloc_free(ares);
1988 return LDB_SUCCESS;
1989 }
1990
1991 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
/* [<][>][^][v][top][bottom][index][help] */
1992 {
1993 struct ldb_context *ldb;
1994 struct ph_context *ac;
1995 int ret;
1996
1997 ac = talloc_get_type(req->context, struct ph_context);
1998 ldb = ldb_module_get_ctx(ac->module);
1999
2000 if (!ares) {
2001 return ldb_module_done(ac->req, NULL, NULL,
2002 LDB_ERR_OPERATIONS_ERROR);
2003 }
2004 if (ares->error != LDB_SUCCESS) {
2005 return ldb_module_done(ac->req, ares->controls,
2006 ares->response, ares->error);
2007 }
2008
2009 /* we are interested only in the single reply (base search) */
2010 switch (ares->type) {
2011 case LDB_REPLY_ENTRY:
2012
2013 if (ac->search_res != NULL) {
2014 ldb_set_errstring(ldb, "Too many results");
2015 talloc_free(ares);
2016 return ldb_module_done(ac->req, NULL, NULL,
2017 LDB_ERR_OPERATIONS_ERROR);
2018 }
2019
2020 /* if it is not an entry of type person this is an error */
2021 /* TODO: remove this when sambaPassword will be in schema */
2022 if (!ldb_msg_check_string_attribute(ares->message, "objectClass", "person")) {
2023 ldb_set_errstring(ldb, "Object class violation");
2024 talloc_free(ares);
2025 return ldb_module_done(ac->req, NULL, NULL,
2026 LDB_ERR_OBJECT_CLASS_VIOLATION);
2027 }
2028
2029 ac->search_res = talloc_steal(ac, ares);
2030 return LDB_SUCCESS;
2031
2032 case LDB_REPLY_DONE:
2033
2034 /* get object domain sid */
2035 ac->domain_sid = samdb_result_sid_prefix(ac,
2036 ac->search_res->message,
2037 "objectSid");
2038 if (ac->domain_sid == NULL) {
2039 ldb_debug(ldb, LDB_DEBUG_ERROR,
2040 "can't handle entry without objectSid!\n");
2041 return ldb_module_done(ac->req, NULL, NULL,
2042 LDB_ERR_OPERATIONS_ERROR);
2043 }
2044
2045 /* get user domain data */
2046 ret = build_domain_data_request(ac);
2047 if (ret != LDB_SUCCESS) {
2048 return ldb_module_done(ac->req, NULL, NULL,ret);
2049 }
2050
2051 return ldb_next_request(ac->module, ac->dom_req);
2052
2053 case LDB_REPLY_REFERRAL:
2054 /*ignore anything else for now */
2055 break;
2056 }
2057
2058 talloc_free(ares);
2059 return LDB_SUCCESS;
2060 }
2061
2062 static int password_hash_mod_search_self(struct ph_context *ac)
/* [<][>][^][v][top][bottom][index][help] */
2063 {
2064 struct ldb_context *ldb;
2065 static const char * const attrs[] = { "userAccountControl", "lmPwdHistory",
2066 "ntPwdHistory",
2067 "objectSid", "msDS-KeyVersionNumber",
2068 "objectClass", "userPrincipalName",
2069 "sAMAccountName",
2070 "dBCSPwd", "unicodePwd",
2071 "supplementalCredentials",
2072 NULL };
2073 struct ldb_request *search_req;
2074 int ret;
2075
2076 ldb = ldb_module_get_ctx(ac->module);
2077
2078 ret = ldb_build_search_req(&search_req, ldb, ac,
2079 ac->req->op.mod.message->dn,
2080 LDB_SCOPE_BASE,
2081 "(objectclass=*)",
2082 attrs,
2083 NULL,
2084 ac, ph_mod_search_callback,
2085 ac->req);
2086
2087 if (ret != LDB_SUCCESS) {
2088 return ret;
2089 }
2090
2091 return ldb_next_request(ac->module, search_req);
2092 }
2093
2094 static int password_hash_mod_do_mod(struct ph_context *ac)
/* [<][>][^][v][top][bottom][index][help] */
2095 {
2096 struct ldb_context *ldb;
2097 struct ldb_request *mod_req;
2098 struct smb_krb5_context *smb_krb5_context;
2099 struct ldb_message *msg;
2100 struct ldb_message *orig_msg;
2101 struct ldb_message *searched_msg;
2102 struct setup_password_fields_io io;
2103 const struct ldb_val *quoted_utf16;
2104 int ret;
2105
2106 ldb = ldb_module_get_ctx(ac->module);
2107
2108 /* use a new message structure so that we can modify it */
2109 msg = ldb_msg_new(ac);
2110 if (msg == NULL) {
2111 return LDB_ERR_OPERATIONS_ERROR;
2112 }
2113
2114 /* modify dn */
2115 msg->dn = ac->req->op.mod.message->dn;
2116
2117 /* Some operations below require kerberos contexts */
2118 if (smb_krb5_init_context(ac,
2119 ldb_get_event_context(ldb),
2120 (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"),
2121 &smb_krb5_context) != 0) {
2122 return LDB_ERR_OPERATIONS_ERROR;
2123 }
2124
2125 orig_msg = discard_const(ac->req->op.mod.message);
2126 searched_msg = ac->search_res->message;
2127
2128 ZERO_STRUCT(io);
2129 io.ac = ac;
2130 io.domain = ac->domain;
2131 io.smb_krb5_context = smb_krb5_context;
2132
2133 io.u.user_account_control = samdb_result_uint(searched_msg, "userAccountControl", 0);
2134 io.u.sAMAccountName = samdb_result_string(searched_msg, "samAccountName", NULL);
2135 io.u.user_principal_name = samdb_result_string(searched_msg, "userPrincipalName", NULL);
2136 io.u.is_computer = ldb_msg_check_string_attribute(searched_msg, "objectClass", "computer");
2137
2138 io.n.cleartext_utf8 = ldb_msg_find_ldb_val(orig_msg, "userPassword");
2139 io.n.cleartext_utf16 = ldb_msg_find_ldb_val(orig_msg, "clearTextPassword");
2140
2141 /* this rather strange looking piece of code is there to
2142 handle a ldap client setting a password remotely using the
2143 unicodePwd ldap field. The syntax is that the password is
2144 in UTF-16LE, with a " at either end. Unfortunately the
2145 unicodePwd field is also used to store the nt hashes
2146 internally in Samba, and is used in the nt hash format on
2147 the wire in DRS replication, so we have a single name for
2148 two distinct values. The code below leaves us with a small
2149 chance (less than 1 in 2^32) of a mixup, if someone manages
2150 to create a MD4 hash which starts and ends in 0x22 0x00, as
2151 that would then be treated as a UTF16 password rather than
2152 a nthash */
2153 quoted_utf16 = ldb_msg_find_ldb_val(orig_msg, "unicodePwd");
2154 if (quoted_utf16 &&
2155 quoted_utf16->length >= 4 &&
2156 quoted_utf16->data[0] == '"' &&
2157 quoted_utf16->data[1] == 0 &&
2158 quoted_utf16->data[quoted_utf16->length-2] == '"' &&
2159 quoted_utf16->data[quoted_utf16->length-1] == 0) {
2160 io.n.quoted_utf16.data = talloc_memdup(orig_msg, quoted_utf16->data+2, quoted_utf16->length-4);
2161 io.n.quoted_utf16.length = quoted_utf16->length-4;
2162 io.n.cleartext_utf16 = &io.n.quoted_utf16;
2163 io.n.nt_hash = NULL;
2164 } else {
2165 io.n.nt_hash = samdb_result_hash(io.ac, orig_msg, "unicodePwd");
2166 }
2167
2168 io.n.lm_hash = samdb_result_hash(io.ac, orig_msg, "dBCSPwd");
2169
2170 io.o.kvno = samdb_result_uint(searched_msg, "msDs-KeyVersionNumber", 0);
2171 io.o.nt_history_len = samdb_result_hashes(io.ac, searched_msg, "ntPwdHistory", &io.o.nt_history);
2172 io.o.lm_history_len = samdb_result_hashes(io.ac, searched_msg, "lmPwdHistory", &io.o.lm_history);
2173 io.o.supplemental = ldb_msg_find_ldb_val(searched_msg, "supplementalCredentials");
2174
2175 ret = setup_password_fields(&io);
2176 if (ret != LDB_SUCCESS) {
2177 return ret;
2178 }
2179
2180 /* make sure we replace all the old attributes */
2181 ret = ldb_msg_add_empty(msg, "unicodePwd", LDB_FLAG_MOD_REPLACE, NULL);
2182 ret = ldb_msg_add_empty(msg, "dBCSPwd", LDB_FLAG_MOD_REPLACE, NULL);
2183 ret = ldb_msg_add_empty(msg, "ntPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
2184 ret = ldb_msg_add_empty(msg, "lmPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
2185 ret = ldb_msg_add_empty(msg, "supplementalCredentials", LDB_FLAG_MOD_REPLACE, NULL);
2186 ret = ldb_msg_add_empty(msg, "pwdLastSet", LDB_FLAG_MOD_REPLACE, NULL);
2187 ret = ldb_msg_add_empty(msg, "msDs-KeyVersionNumber", LDB_FLAG_MOD_REPLACE, NULL);
2188
2189 if (io.g.nt_hash) {
2190 ret = samdb_msg_add_hash(ldb, ac, msg,
2191 "unicodePwd", io.g.nt_hash);
2192 if (ret != LDB_SUCCESS) {
2193 return ret;
2194 }
2195 }
2196 if (io.g.lm_hash) {
2197 ret = samdb_msg_add_hash(ldb, ac, msg,
2198 "dBCSPwd", io.g.lm_hash);
2199 if (ret != LDB_SUCCESS) {
2200 return ret;
2201 }
2202 }
2203 if (io.g.nt_history_len > 0) {
2204 ret = samdb_msg_add_hashes(ac, msg,
2205 "ntPwdHistory",
2206 io.g.nt_history,
2207 io.g.nt_history_len);
2208 if (ret != LDB_SUCCESS) {
2209 return ret;
2210 }
2211 }
2212 if (io.g.lm_history_len > 0) {
2213 ret = samdb_msg_add_hashes(ac, msg,
2214 "lmPwdHistory",
2215 io.g.lm_history,
2216 io.g.lm_history_len);
2217 if (ret != LDB_SUCCESS) {
2218 return ret;
2219 }
2220 }
2221 if (io.g.supplemental.length > 0) {
2222 ret = ldb_msg_add_value(msg, "supplementalCredentials",
2223 &io.g.supplemental, NULL);
2224 if (ret != LDB_SUCCESS) {
2225 return ret;
2226 }
2227 }
2228 ret = samdb_msg_add_uint64(ldb, ac, msg,
2229 "pwdLastSet",
2230 io.g.last_set);
2231 if (ret != LDB_SUCCESS) {
2232 return ret;
2233 }
2234 ret = samdb_msg_add_uint(ldb, ac, msg,
2235 "msDs-KeyVersionNumber",
2236 io.g.kvno);
2237 if (ret != LDB_SUCCESS) {
2238 return ret;
2239 }
2240
2241 ret = ldb_build_mod_req(&mod_req, ldb, ac,
2242 msg,
2243 ac->req->controls,
2244 ac, ph_op_callback,
2245 ac->req);
2246 if (ret != LDB_SUCCESS) {
2247 return ret;
2248 }
2249
2250 return ldb_next_request(ac->module, mod_req);
2251 }
2252
2253 _PUBLIC_ const struct ldb_module_ops ldb_password_hash_module_ops = {
2254 .name = "password_hash",
2255 .add = password_hash_add,
2256 .modify = password_hash_modify,
2257 };