smbd: Fix cached dos attributes
[Samba.git] / source3 / libnet / libnet_dssync_keytab.c
bloba4fc4e98b0c3141b0e33ec6a5880ab69f0e88cf0
1 /*
2 Unix SMB/CIFS implementation.
4 Copyright (C) Guenther Deschner <gd@samba.org> 2008
5 Copyright (C) Michael Adam 2008
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "smb_krb5.h"
23 #include "libnet/libnet_dssync.h"
24 #include "libnet/libnet_keytab.h"
25 #include "librpc/gen_ndr/ndr_drsblobs.h"
26 #include "lib/crypto/md4.h"
28 #if defined(HAVE_ADS)
30 static NTSTATUS keytab_startup(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
31 struct replUpToDateVectorBlob **pold_utdv)
33 krb5_error_code ret = 0;
34 struct libnet_keytab_context *keytab_ctx;
35 struct libnet_keytab_entry *entry;
36 struct replUpToDateVectorBlob *old_utdv = NULL;
37 char *principal;
39 ret = libnet_keytab_init(mem_ctx, ctx->output_filename, &keytab_ctx);
40 if (ret) {
41 return krb5_to_nt_status(ret);
44 keytab_ctx->dns_domain_name = ctx->dns_domain_name;
45 keytab_ctx->clean_old_entries = ctx->clean_old_entries;
46 ctx->private_data = keytab_ctx;
48 principal = talloc_asprintf(mem_ctx, "UTDV/%s@%s",
49 ctx->nc_dn, ctx->dns_domain_name);
50 NT_STATUS_HAVE_NO_MEMORY(principal);
52 entry = libnet_keytab_search(keytab_ctx, principal, 0, ENCTYPE_NULL,
53 mem_ctx);
54 if (entry) {
55 enum ndr_err_code ndr_err;
56 old_utdv = talloc(mem_ctx, struct replUpToDateVectorBlob);
58 ndr_err = ndr_pull_struct_blob(&entry->password, old_utdv, old_utdv,
59 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
60 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
61 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
62 ctx->error_message = talloc_asprintf(ctx,
63 "Failed to pull UpToDateVector: %s",
64 nt_errstr(status));
65 return status;
68 if (DEBUGLEVEL >= 10) {
69 NDR_PRINT_DEBUG(replUpToDateVectorBlob, old_utdv);
73 if (pold_utdv) {
74 *pold_utdv = old_utdv;
77 return NT_STATUS_OK;
80 static NTSTATUS keytab_finish(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
81 struct replUpToDateVectorBlob *new_utdv)
83 NTSTATUS status = NT_STATUS_OK;
84 krb5_error_code ret = 0;
85 struct libnet_keytab_context *keytab_ctx =
86 (struct libnet_keytab_context *)ctx->private_data;
88 if (new_utdv) {
89 enum ndr_err_code ndr_err;
90 DATA_BLOB blob;
92 if (DEBUGLEVEL >= 10) {
93 NDR_PRINT_DEBUG(replUpToDateVectorBlob, new_utdv);
96 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, new_utdv,
97 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
98 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
99 status = ndr_map_error2ntstatus(ndr_err);
100 ctx->error_message = talloc_asprintf(ctx,
101 "Failed to push UpToDateVector: %s",
102 nt_errstr(status));
103 goto done;
106 status = libnet_keytab_add_to_keytab_entries(mem_ctx, keytab_ctx, 0,
107 ctx->nc_dn, "UTDV",
108 ENCTYPE_NULL,
109 blob);
110 if (!NT_STATUS_IS_OK(status)) {
111 goto done;
115 ret = libnet_keytab_add(keytab_ctx);
116 if (ret) {
117 status = krb5_to_nt_status(ret);
118 ctx->error_message = talloc_asprintf(ctx,
119 "Failed to add entries to keytab %s: %s",
120 keytab_ctx->keytab_name, error_message(ret));
121 goto done;
124 ctx->result_message = talloc_asprintf(ctx,
125 "Vampired %d accounts to keytab %s",
126 keytab_ctx->count,
127 keytab_ctx->keytab_name);
129 done:
130 TALLOC_FREE(keytab_ctx);
131 return status;
134 /****************************************************************
135 ****************************************************************/
137 static NTSTATUS parse_supplemental_credentials(TALLOC_CTX *mem_ctx,
138 const DATA_BLOB *blob,
139 struct package_PrimaryKerberosCtr3 **pkb3,
140 struct package_PrimaryKerberosCtr4 **pkb4)
142 NTSTATUS status;
143 enum ndr_err_code ndr_err;
144 struct supplementalCredentialsBlob scb;
145 struct supplementalCredentialsPackage *scpk = NULL;
146 DATA_BLOB scpk_blob;
147 struct package_PrimaryKerberosBlob *pkb;
148 bool newer_keys = false;
149 uint32_t j;
151 ndr_err = ndr_pull_struct_blob_all(blob, mem_ctx, &scb,
152 (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
153 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
154 status = ndr_map_error2ntstatus(ndr_err);
155 goto done;
157 if ((scb.sub.signature != SUPPLEMENTAL_CREDENTIALS_SIGNATURE)
158 && (scb.sub.num_packages != 0))
160 if (DEBUGLEVEL >= 10) {
161 NDR_PRINT_DEBUG(supplementalCredentialsBlob, &scb);
163 status = NT_STATUS_INVALID_PARAMETER;
164 goto done;
166 for (j=0; j < scb.sub.num_packages; j++) {
167 if (strcmp("Primary:Kerberos-Newer-Keys",
168 scb.sub.packages[j].name) == 0)
170 scpk = &scb.sub.packages[j];
171 if (!scpk->data || !scpk->data[0]) {
172 scpk = NULL;
173 continue;
175 newer_keys = true;
176 break;
177 } else if (strcmp("Primary:Kerberos",
178 scb.sub.packages[j].name) == 0)
181 * grab this but don't break here:
182 * there might still be newer-keys ...
184 scpk = &scb.sub.packages[j];
185 if (!scpk->data || !scpk->data[0]) {
186 scpk = NULL;
191 if (!scpk) {
192 /* no data */
193 status = NT_STATUS_OK;
194 goto done;
197 scpk_blob = strhex_to_data_blob(mem_ctx, scpk->data);
198 if (!scpk_blob.data) {
199 status = NT_STATUS_NO_MEMORY;
200 goto done;
203 pkb = talloc_zero(mem_ctx, struct package_PrimaryKerberosBlob);
204 if (!pkb) {
205 status = NT_STATUS_NO_MEMORY;
206 goto done;
208 ndr_err = ndr_pull_struct_blob(&scpk_blob, mem_ctx, pkb,
209 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
210 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
211 status = ndr_map_error2ntstatus(ndr_err);
212 goto done;
215 if (!newer_keys && pkb->version != 3) {
216 status = NT_STATUS_INVALID_PARAMETER;
217 goto done;
220 if (newer_keys && pkb->version != 4) {
221 status = NT_STATUS_INVALID_PARAMETER;
222 goto done;
225 if (pkb->version == 4 && pkb4) {
226 *pkb4 = &pkb->ctr.ctr4;
227 } else if (pkb->version == 3 && pkb3) {
228 *pkb3 = &pkb->ctr.ctr3;
231 status = NT_STATUS_OK;
233 done:
234 return status;
237 static NTSTATUS store_or_fetch_attribute(TALLOC_CTX *mem_ctx,
238 struct libnet_keytab_context *ctx,
239 const char *object_dn,
240 const char *attr,
241 char **value)
243 DATA_BLOB blob = { .length = 0, };
244 NTSTATUS status;
246 if (*value == NULL) {
247 /* look into keytab ... */
248 struct libnet_keytab_entry *entry = NULL;
249 char *principal = NULL;
251 D_DEBUG("looking for %s/%s@%s in keytayb...\n",
252 attr, object_dn, ctx->dns_domain_name);
254 principal = talloc_asprintf(mem_ctx,
255 "%s/%s@%s",
256 attr,
257 object_dn,
258 ctx->dns_domain_name);
259 if (principal == NULL) {
260 return NT_STATUS_NO_MEMORY;
262 entry = libnet_keytab_search(ctx,
263 principal,
265 ENCTYPE_NULL,
266 mem_ctx);
267 if (entry != NULL) {
268 *value = talloc_strndup(mem_ctx,
269 (char *)entry->password.data,
270 entry->password.length);
271 if (*value == NULL) {
272 return NT_STATUS_NO_MEMORY;
274 D_DEBUG("found %s: %s\n", attr, *value);
275 TALLOC_FREE(entry);
276 } else {
277 *value = NULL;
278 D_DEBUG("entry not found\n");
280 TALLOC_FREE(principal);
281 return NT_STATUS_OK;
284 blob = data_blob_string_const_null(*value);
285 blob = data_blob_dup_talloc(mem_ctx, blob);
286 if (blob.data == NULL) {
287 return NT_STATUS_NO_MEMORY;
290 status = libnet_keytab_add_to_keytab_entries(mem_ctx,
291 ctx,
293 object_dn,
294 attr,
295 ENCTYPE_NULL,
296 blob);
297 if (!NT_STATUS_IS_OK(status)) {
298 return status;
301 return NT_STATUS_OK;
304 static NTSTATUS parse_user(TALLOC_CTX *mem_ctx,
305 struct libnet_keytab_context *ctx,
306 struct drsuapi_DsReplicaObjectListItemEx *cur)
308 NTSTATUS status = NT_STATUS_OK;
309 uchar nt_passwd[16];
310 DATA_BLOB *blob;
311 int i = 0;
312 struct drsuapi_DsReplicaAttribute *attr;
313 bool got_pwd = false;
315 struct package_PrimaryKerberosCtr3 *pkb3 = NULL;
316 struct package_PrimaryKerberosCtr4 *pkb4 = NULL;
318 char *object_dn = NULL;
319 char *upn = NULL;
320 char **spn = NULL;
321 uint32_t num_spns = 0;
322 char *name = NULL;
323 uint32_t kvno = 0;
324 uint32_t uacc = 0;
325 uint32_t sam_type = 0;
327 uint32_t pwd_history_len = 0;
328 uint8_t *pwd_history = NULL;
330 ZERO_STRUCT(nt_passwd);
332 object_dn = talloc_strdup(mem_ctx, cur->object.identifier->dn);
333 if (!object_dn) {
334 return NT_STATUS_NO_MEMORY;
337 DEBUG(3, ("parsing user '%s'\n", object_dn));
339 for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) {
341 attr = &cur->object.attribute_ctr.attributes[i];
343 if (attr->attid == DRSUAPI_ATTID_servicePrincipalName) {
344 uint32_t count;
345 num_spns = attr->value_ctr.num_values;
346 spn = talloc_array(mem_ctx, char *, num_spns);
347 for (count = 0; count < num_spns; count++) {
348 blob = attr->value_ctr.values[count].blob;
349 if (blob == NULL) {
350 continue;
352 pull_string_talloc(spn, NULL, 0,
353 &spn[count],
354 blob->data, blob->length,
355 STR_UNICODE);
359 if (attr->attid == DRSUAPI_ATTID_unicodePwd &&
360 cur->meta_data_ctr != NULL &&
361 cur->meta_data_ctr->count ==
362 cur->object.attribute_ctr.num_attributes)
365 * pick the kvno from the unicodePwd
366 * meta data, even without a unicodePwd blob
368 kvno = cur->meta_data_ctr->meta_data[i].version;
371 if (attr->value_ctr.num_values != 1) {
372 continue;
375 if (!attr->value_ctr.values[0].blob) {
376 continue;
379 blob = attr->value_ctr.values[0].blob;
381 switch (attr->attid) {
382 case DRSUAPI_ATTID_unicodePwd:
384 if (blob->length != 16) {
385 break;
388 memcpy(&nt_passwd, blob->data, 16);
389 got_pwd = true;
390 break;
391 case DRSUAPI_ATTID_ntPwdHistory:
392 pwd_history_len = blob->length / 16;
393 pwd_history = blob->data;
394 break;
395 case DRSUAPI_ATTID_userPrincipalName:
396 pull_string_talloc(mem_ctx, NULL, 0, &upn,
397 blob->data, blob->length,
398 STR_UNICODE);
399 break;
400 case DRSUAPI_ATTID_sAMAccountName:
401 pull_string_talloc(mem_ctx, NULL, 0, &name,
402 blob->data, blob->length,
403 STR_UNICODE);
404 break;
405 case DRSUAPI_ATTID_sAMAccountType:
406 sam_type = IVAL(blob->data, 0);
407 break;
408 case DRSUAPI_ATTID_userAccountControl:
409 uacc = IVAL(blob->data, 0);
410 break;
411 case DRSUAPI_ATTID_supplementalCredentials:
412 status = parse_supplemental_credentials(mem_ctx,
413 blob,
414 &pkb3,
415 &pkb4);
416 if (!NT_STATUS_IS_OK(status)) {
417 DEBUG(2, ("parsing of supplemental "
418 "credentials failed: %s\n",
419 nt_errstr(status)));
421 break;
422 default:
423 break;
427 status = store_or_fetch_attribute(mem_ctx,
428 ctx,
429 object_dn,
430 "SAMACCOUNTNAME",
431 &name);
432 if (!NT_STATUS_IS_OK(status)) {
433 DBG_ERR("store_or_fetch_attribute(%s, %s, %s): %s\n",
434 object_dn, "SAMACCOUNTNAME", name,
435 nt_errstr(status));
436 return status;
439 if (!name) {
440 DEBUG(10, ("no name (sAMAccountName) found - skipping.\n"));
441 return NT_STATUS_OK;
444 DEBUG(1,("#%02d: %s:%d, ", ctx->count, name, kvno));
445 DEBUGADD(1,("sAMAccountType: 0x%08x, userAccountControl: 0x%08x",
446 sam_type, uacc));
447 if (upn) {
448 DEBUGADD(1,(", upn: %s", upn));
450 if (num_spns > 0) {
451 DEBUGADD(1, (", spns: ["));
452 for (i = 0; i < num_spns; i++) {
453 DEBUGADD(1, ("%s%s", spn[i],
454 (i+1 == num_spns)?"]":", "));
457 DEBUGADD(1,("\n"));
459 if (got_pwd) {
460 status = libnet_keytab_add_to_keytab_entries(mem_ctx, ctx, kvno, name, NULL,
461 ENCTYPE_ARCFOUR_HMAC,
462 data_blob_talloc(mem_ctx, nt_passwd, 16));
464 if (!NT_STATUS_IS_OK(status)) {
465 return status;
469 /* add kerberos keys (if any) */
471 if (pkb4) {
472 for (i=0; i < pkb4->num_keys; i++) {
473 if (!pkb4->keys[i].value) {
474 continue;
476 status = libnet_keytab_add_to_keytab_entries(mem_ctx, ctx, kvno,
477 name,
478 NULL,
479 pkb4->keys[i].keytype,
480 *pkb4->keys[i].value);
481 if (!NT_STATUS_IS_OK(status)) {
482 return status;
485 for (i=0; i < pkb4->num_old_keys; i++) {
486 if (!pkb4->old_keys[i].value) {
487 continue;
489 status = libnet_keytab_add_to_keytab_entries(mem_ctx, ctx, kvno - 1,
490 name,
491 NULL,
492 pkb4->old_keys[i].keytype,
493 *pkb4->old_keys[i].value);
494 if (!NT_STATUS_IS_OK(status)) {
495 return status;
498 for (i=0; i < pkb4->num_older_keys; i++) {
499 if (!pkb4->older_keys[i].value) {
500 continue;
502 status = libnet_keytab_add_to_keytab_entries(mem_ctx, ctx, kvno - 2,
503 name,
504 NULL,
505 pkb4->older_keys[i].keytype,
506 *pkb4->older_keys[i].value);
507 if (!NT_STATUS_IS_OK(status)) {
508 return status;
513 if (pkb3) {
514 for (i=0; i < pkb3->num_keys; i++) {
515 if (!pkb3->keys[i].value) {
516 continue;
518 status = libnet_keytab_add_to_keytab_entries(mem_ctx, ctx, kvno, name,
519 NULL,
520 pkb3->keys[i].keytype,
521 *pkb3->keys[i].value);
522 if (!NT_STATUS_IS_OK(status)) {
523 return status;
526 for (i=0; i < pkb3->num_old_keys; i++) {
527 if (!pkb3->old_keys[i].value) {
528 continue;
530 status = libnet_keytab_add_to_keytab_entries(mem_ctx, ctx, kvno - 1,
531 name,
532 NULL,
533 pkb3->old_keys[i].keytype,
534 *pkb3->old_keys[i].value);
535 if (!NT_STATUS_IS_OK(status)) {
536 return status;
541 if (kvno < pwd_history_len) {
542 return status;
545 /* add password history */
547 /* skip first entry */
548 if (got_pwd) {
549 kvno--;
550 i = 1;
551 } else {
552 i = 0;
555 for (; i<pwd_history_len; i++) {
556 status = libnet_keytab_add_to_keytab_entries(mem_ctx, ctx, kvno--, name, NULL,
557 ENCTYPE_ARCFOUR_HMAC,
558 data_blob_talloc(mem_ctx, &pwd_history[i*16], 16));
559 if (!NT_STATUS_IS_OK(status)) {
560 break;
564 return status;
567 static NTSTATUS parse_AuthenticationInformation(TALLOC_CTX *mem_ctx,
568 struct libnet_keytab_context *ctx,
569 const char *dn,
570 const char *trust_name,
571 const char *attr_name,
572 const char *salt_principal,
573 const char *type,
574 uint32_t *kvno,
575 const struct AuthenticationInformationArray *ia)
577 uint32_t i;
578 struct samr_Password _nthash = {{ 0, }};
579 const struct samr_Password *nthash = NULL;
580 const struct AuthInfoClear *clear = NULL;
581 DATA_BLOB password_utf8 = data_blob_null;
583 for (i = 0; i < ia->count; i++) {
584 const struct AuthenticationInformation *a = &ia->array[i];
586 switch (a->AuthType) {
587 case TRUST_AUTH_TYPE_VERSION:
588 *kvno = a->AuthInfo.version.version;
589 break;
590 case TRUST_AUTH_TYPE_NT4OWF:
591 nthash = &a->AuthInfo.nt4owf.password;
592 break;
593 case TRUST_AUTH_TYPE_CLEAR:
594 clear = &a->AuthInfo.clear;
595 break;
596 default:
597 break;
601 if (clear != NULL && clear->size != 0) {
602 DATA_BLOB password_utf16 = data_blob_null;
603 bool ok;
605 password_utf16 = data_blob_const(clear->password,
606 clear->size);
608 if (nthash == NULL) {
609 mdfour(_nthash.hash,
610 password_utf16.data,
611 password_utf16.length);
612 nthash = &_nthash;
615 ok = convert_string_talloc(mem_ctx,
616 CH_UTF16MUNGED, CH_UTF8,
617 password_utf16.data,
618 password_utf16.length,
619 (void *)&password_utf8.data,
620 &password_utf8.length);
621 if (!ok) {
622 return NT_STATUS_NO_MEMORY;
626 if (password_utf8.length != 0) {
627 krb5_principal salt_princ = NULL;
628 krb5_data salt = { 0, };
629 krb5_data cleartext_data = { 0, };
630 krb5_enctype enctypes[] = {
631 ENCTYPE_AES256_CTS_HMAC_SHA1_96,
632 ENCTYPE_AES128_CTS_HMAC_SHA1_96,
634 size_t ei;
635 krb5_error_code kret;
636 NTSTATUS status;
638 kret = smb_krb5_parse_name(ctx->context,
639 salt_principal,
640 &salt_princ);
641 if (kret != 0) {
642 return NT_STATUS_NO_MEMORY;
645 cleartext_data.data = discard_const_p(char, password_utf8.data);
646 cleartext_data.length = password_utf8.length;
648 kret = smb_krb5_get_pw_salt(ctx->context,
649 salt_princ,
650 &salt);
651 if (kret != 0) {
652 krb5_free_principal(ctx->context, salt_princ);
653 return NT_STATUS_NO_MEMORY;
656 for (ei = 0; ei < ARRAY_SIZE(enctypes); ei++) {
657 krb5_keyblock keyb = { 0, };
658 DATA_BLOB blob = data_blob_null;
660 kret = smb_krb5_create_key_from_string(ctx->context,
661 salt_princ,
662 &salt,
663 &cleartext_data,
664 enctypes[ei],
665 &keyb);
666 if (kret != 0) {
667 smb_krb5_free_data_contents(ctx->context, &salt);
668 krb5_free_principal(ctx->context, salt_princ);
669 return NT_STATUS_NO_MEMORY;
672 blob = data_blob_talloc(mem_ctx,
673 KRB5_KEY_DATA(&keyb),
674 KRB5_KEY_LENGTH(&keyb));
675 krb5_free_keyblock_contents(ctx->context, &keyb);
677 status = libnet_keytab_add_to_keytab_entries(mem_ctx,
678 ctx,
679 *kvno,
680 trust_name,
681 attr_name,
682 enctypes[ei],
683 blob);
684 if (!NT_STATUS_IS_OK(status)) {
685 smb_krb5_free_data_contents(ctx->context, &salt);
686 krb5_free_principal(ctx->context, salt_princ);
687 return status;
691 smb_krb5_free_data_contents(ctx->context, &salt);
692 krb5_free_principal(ctx->context, salt_princ);
695 if (nthash != NULL) {
696 DATA_BLOB blob = data_blob_null;
697 NTSTATUS status;
699 blob = data_blob_talloc(mem_ctx, nthash->hash, sizeof(nthash->hash));
701 status = libnet_keytab_add_to_keytab_entries(mem_ctx, ctx,
702 *kvno,
703 trust_name,
704 attr_name,
705 ENCTYPE_ARCFOUR_HMAC,
706 blob);
707 if (!NT_STATUS_IS_OK(status)) {
708 return status;
712 return NT_STATUS_OK;
715 static NTSTATUS parse_trustAuthInOutBlob(TALLOC_CTX *mem_ctx,
716 struct libnet_keytab_context *ctx,
717 const char *dn,
718 const char *trust_name,
719 const char *attr_name,
720 const char *salt_principal,
721 const DATA_BLOB *blob)
723 NTSTATUS status;
724 enum ndr_err_code ndr_err;
725 struct trustAuthInOutBlob taiob;
726 uint32_t kvno = 0;
728 ndr_err = ndr_pull_struct_blob_all(blob, mem_ctx, &taiob,
729 (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
730 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
731 status = ndr_map_error2ntstatus(ndr_err);
732 goto done;
735 D_WARNING("# %s %s/%s\n", dn, attr_name, trust_name);
737 status = parse_AuthenticationInformation(mem_ctx,
738 ctx,
740 trust_name,
741 attr_name,
742 salt_principal,
743 "current",
744 &kvno,
745 &taiob.current);
746 if (!NT_STATUS_IS_OK(status)) {
747 DBG_ERR("parsing of %s %s/current failed: %s\n",
748 dn, attr_name, nt_errstr(status));
751 kvno -= 1;
752 status = parse_AuthenticationInformation(mem_ctx,
753 ctx,
755 trust_name,
756 attr_name,
757 salt_principal,
758 "previous",
759 &kvno,
760 &taiob.previous);
761 if (!NT_STATUS_IS_OK(status)) {
762 DBG_ERR("parsing of %s %s/previous failed: %s\n",
763 dn, attr_name, nt_errstr(status));
766 status = NT_STATUS_OK;
767 done:
768 return status;
771 static NTSTATUS parse_tdo(TALLOC_CTX *mem_ctx,
772 struct libnet_keytab_context *ctx,
773 struct drsuapi_DsReplicaObjectListItemEx *cur)
775 uint32_t i;
776 const char *dn = cur->object.identifier->dn;
777 char *trustPartner = NULL;
778 char *flatName = NULL;
779 char *cn = NULL;
780 char *trust_name = NULL;
781 char *trust_realm = NULL;
782 char *our_realm = NULL;
783 const char *incoming_salt = NULL;
784 const char *outgoing_salt = NULL;
785 NTSTATUS status;
787 D_NOTICE("parsing trust '%s'\n", dn);
789 for (i = 0; i < cur->object.attribute_ctr.num_attributes; i++) {
790 struct drsuapi_DsReplicaAttribute *attr =
791 &cur->object.attribute_ctr.attributes[i];
792 const DATA_BLOB *blob = NULL;
794 if (attr->value_ctr.num_values != 1) {
795 continue;
798 if (attr->value_ctr.values[0].blob == NULL) {
799 continue;
802 blob = attr->value_ctr.values[0].blob;
804 switch (attr->attid) {
805 case DRSUAPI_ATTID_trustPartner:
806 pull_string_talloc(mem_ctx, NULL, 0, &trustPartner,
807 blob->data, blob->length,
808 STR_UNICODE);
809 break;
810 case DRSUAPI_ATTID_flatName:
811 pull_string_talloc(mem_ctx, NULL, 0, &flatName,
812 blob->data, blob->length,
813 STR_UNICODE);
814 break;
815 case DRSUAPI_ATTID_cn:
816 pull_string_talloc(mem_ctx, NULL, 0, &cn,
817 blob->data, blob->length,
818 STR_UNICODE);
819 break;
820 default:
821 break;
825 if (trustPartner != NULL) {
826 trust_name = trustPartner;
827 } else if (flatName != NULL) {
828 trust_name = flatName;
829 } else {
830 trust_name = cn;
833 status = store_or_fetch_attribute(mem_ctx,
834 ctx,
836 "REMOTETRUSTNAME",
837 &trust_name);
838 if (!NT_STATUS_IS_OK(status)) {
839 DBG_ERR("store_or_fetch_attribute(%s, %s, %s): %s\n",
840 dn, "REMOTETRUSTNAME", trust_name,
841 nt_errstr(status));
842 return status;
845 if (trust_name == NULL) {
846 D_DEBUG("no trust_name (trustPartner, flatName, cn) found - "
847 "skipping.\n");
848 return NT_STATUS_OK;
851 trust_realm = strupper_talloc(mem_ctx, trust_name);
852 if (trust_realm == NULL) {
853 return NT_STATUS_NO_MEMORY;
855 our_realm = strupper_talloc(mem_ctx, ctx->dns_domain_name);
856 if (our_realm == NULL) {
857 return NT_STATUS_NO_MEMORY;
860 incoming_salt = talloc_asprintf(mem_ctx,
861 "krbtgt/%s@%s",
862 trust_realm,
863 our_realm);
864 if (incoming_salt == NULL) {
865 return NT_STATUS_NO_MEMORY;
867 outgoing_salt = talloc_asprintf(mem_ctx,
868 "krbtgt/%s@%s",
869 our_realm,
870 trust_realm);
871 if (outgoing_salt == NULL) {
872 return NT_STATUS_NO_MEMORY;
875 for (i = 0; i < cur->object.attribute_ctr.num_attributes; i++) {
876 struct drsuapi_DsReplicaAttribute *attr =
877 &cur->object.attribute_ctr.attributes[i];
878 const char *attr_name = NULL;
879 const DATA_BLOB *blob = NULL;
880 const char *salt_principal = NULL;
882 if (attr->value_ctr.num_values != 1) {
883 continue;
886 if (attr->value_ctr.values[0].blob == NULL) {
887 continue;
890 blob = attr->value_ctr.values[0].blob;
892 switch (attr->attid) {
893 case DRSUAPI_ATTID_trustAuthIncoming:
894 attr_name = "trustAuthIncoming";
895 salt_principal = incoming_salt;
896 break;
897 case DRSUAPI_ATTID_trustAuthOutgoing:
898 attr_name = "trustAuthOutgoing";
899 salt_principal = outgoing_salt;
900 break;
901 default:
902 break;
905 if (attr_name == NULL) {
906 continue;
909 status = parse_trustAuthInOutBlob(mem_ctx,
910 ctx,
912 trust_name,
913 attr_name,
914 salt_principal,
915 blob);
916 if (!NT_STATUS_IS_OK(status)) {
917 DBG_ERR("parsing of %s attr %s failed: %s\n",
918 dn, attr_name, nt_errstr(status));
922 return NT_STATUS_OK;
925 static NTSTATUS parse_object(TALLOC_CTX *mem_ctx,
926 struct libnet_keytab_context *ctx,
927 struct drsuapi_DsReplicaObjectListItemEx *cur)
929 uint32_t i;
931 if (cur->object.identifier->dn == NULL) {
932 return NT_STATUS_OK;
935 for (i = 0; i < cur->object.attribute_ctr.num_attributes; i++) {
936 struct drsuapi_DsReplicaAttribute *attr =
937 &cur->object.attribute_ctr.attributes[i];
938 const DATA_BLOB *blob = NULL;
939 uint32_t val;
941 switch (attr->attid) {
942 case DRSUAPI_ATTID_isDeleted:
943 case DRSUAPI_ATTID_isRecycled:
944 break;
945 default:
946 continue;
949 if (attr->value_ctr.num_values != 1) {
950 continue;
953 if (attr->value_ctr.values[0].blob == NULL) {
954 continue;
957 blob = attr->value_ctr.values[0].blob;
959 if (blob->length != 4) {
960 continue;
963 val = PULL_LE_U32(blob->data, 0);
964 if (val != 0) {
965 /* ignore deleted object */
966 return NT_STATUS_OK;
970 for (i = 0; i < cur->object.attribute_ctr.num_attributes; i++) {
971 struct drsuapi_DsReplicaAttribute *attr =
972 &cur->object.attribute_ctr.attributes[i];
974 switch (attr->attid) {
975 case DRSUAPI_ATTID_unicodePwd:
976 case DRSUAPI_ATTID_ntPwdHistory:
977 case DRSUAPI_ATTID_supplementalCredentials:
978 return parse_user(mem_ctx, ctx, cur);
979 case DRSUAPI_ATTID_trustAuthIncoming:
980 case DRSUAPI_ATTID_trustAuthOutgoing:
981 return parse_tdo(mem_ctx, ctx, cur);
982 default:
983 continue;
987 return NT_STATUS_OK;
990 static bool dn_is_in_object_list(struct dssync_context *ctx,
991 const char *dn)
993 uint32_t count;
995 if (ctx->object_count == 0) {
996 return true;
999 for (count = 0; count < ctx->object_count; count++) {
1000 if (strequal(ctx->object_dns[count], dn)) {
1001 return true;
1005 return false;
1008 /****************************************************************
1009 ****************************************************************/
1011 static NTSTATUS keytab_process_objects(struct dssync_context *ctx,
1012 TALLOC_CTX *mem_ctx,
1013 struct drsuapi_DsReplicaObjectListItemEx *cur,
1014 struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr)
1016 NTSTATUS status = NT_STATUS_OK;
1017 struct libnet_keytab_context *keytab_ctx =
1018 (struct libnet_keytab_context *)ctx->private_data;
1020 for (; cur; cur = cur->next_object) {
1022 * When not in single object replication mode,
1023 * the object_dn list is used as a positive write filter.
1025 if (!ctx->single_object_replication &&
1026 !dn_is_in_object_list(ctx, cur->object.identifier->dn))
1028 continue;
1031 status = parse_object(mem_ctx, keytab_ctx, cur);
1032 if (!NT_STATUS_IS_OK(status)) {
1033 goto out;
1037 out:
1038 return status;
1041 #else
1043 static NTSTATUS keytab_startup(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
1044 struct replUpToDateVectorBlob **pold_utdv)
1046 return NT_STATUS_NOT_SUPPORTED;
1049 static NTSTATUS keytab_finish(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
1050 struct replUpToDateVectorBlob *new_utdv)
1052 return NT_STATUS_NOT_SUPPORTED;
1055 static NTSTATUS keytab_process_objects(struct dssync_context *ctx,
1056 TALLOC_CTX *mem_ctx,
1057 struct drsuapi_DsReplicaObjectListItemEx *cur,
1058 struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr)
1060 return NT_STATUS_NOT_SUPPORTED;
1062 #endif /* defined(HAVE_ADS) */
1064 const struct dssync_ops libnet_dssync_keytab_ops = {
1065 .startup = keytab_startup,
1066 .process_objects = keytab_process_objects,
1067 .finish = keytab_finish,