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/>.
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"
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
;
39 ret
= libnet_keytab_init(mem_ctx
, ctx
->output_filename
, &keytab_ctx
);
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
,
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",
68 if (DEBUGLEVEL
>= 10) {
69 NDR_PRINT_DEBUG(replUpToDateVectorBlob
, old_utdv
);
74 *pold_utdv
= old_utdv
;
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
;
89 enum ndr_err_code ndr_err
;
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",
106 status
= libnet_keytab_add_to_keytab_entries(mem_ctx
, keytab_ctx
, 0,
110 if (!NT_STATUS_IS_OK(status
)) {
115 ret
= libnet_keytab_add(keytab_ctx
);
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
));
124 ctx
->result_message
= talloc_asprintf(ctx
,
125 "Vampired %d accounts to keytab %s",
127 keytab_ctx
->keytab_name
);
130 TALLOC_FREE(keytab_ctx
);
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
)
143 enum ndr_err_code ndr_err
;
144 struct supplementalCredentialsBlob scb
;
145 struct supplementalCredentialsPackage
*scpk
= NULL
;
147 struct package_PrimaryKerberosBlob
*pkb
;
148 bool newer_keys
= false;
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
);
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
;
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]) {
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]) {
193 status
= NT_STATUS_OK
;
197 scpk_blob
= strhex_to_data_blob(mem_ctx
, scpk
->data
);
198 if (!scpk_blob
.data
) {
199 status
= NT_STATUS_NO_MEMORY
;
203 pkb
= talloc_zero(mem_ctx
, struct package_PrimaryKerberosBlob
);
205 status
= NT_STATUS_NO_MEMORY
;
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
);
215 if (!newer_keys
&& pkb
->version
!= 3) {
216 status
= NT_STATUS_INVALID_PARAMETER
;
220 if (newer_keys
&& pkb
->version
!= 4) {
221 status
= NT_STATUS_INVALID_PARAMETER
;
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
;
237 static NTSTATUS
store_or_fetch_attribute(TALLOC_CTX
*mem_ctx
,
238 struct libnet_keytab_context
*ctx
,
239 const char *object_dn
,
243 DATA_BLOB blob
= { .length
= 0, };
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 keytab...\n",
252 attr
, object_dn
, ctx
->dns_domain_name
);
254 principal
= talloc_asprintf(mem_ctx
,
258 ctx
->dns_domain_name
);
259 if (principal
== NULL
) {
260 return NT_STATUS_NO_MEMORY
;
262 entry
= libnet_keytab_search(ctx
,
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
);
278 D_DEBUG("entry not found\n");
280 TALLOC_FREE(principal
);
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
,
297 if (!NT_STATUS_IS_OK(status
)) {
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
;
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
;
321 uint32_t num_spns
= 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
);
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
) {
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
;
352 pull_string_talloc(spn
, NULL
, 0,
354 blob
->data
, blob
->length
,
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) {
375 if (!attr
->value_ctr
.values
[0].blob
) {
379 blob
= attr
->value_ctr
.values
[0].blob
;
381 switch (attr
->attid
) {
382 case DRSUAPI_ATTID_unicodePwd
:
384 if (blob
->length
!= 16) {
388 memcpy(&nt_passwd
, blob
->data
, 16);
391 case DRSUAPI_ATTID_ntPwdHistory
:
392 pwd_history_len
= blob
->length
/ 16;
393 pwd_history
= blob
->data
;
395 case DRSUAPI_ATTID_userPrincipalName
:
396 pull_string_talloc(mem_ctx
, NULL
, 0, &upn
,
397 blob
->data
, blob
->length
,
400 case DRSUAPI_ATTID_sAMAccountName
:
401 pull_string_talloc(mem_ctx
, NULL
, 0, &name
,
402 blob
->data
, blob
->length
,
405 case DRSUAPI_ATTID_sAMAccountType
:
406 sam_type
= IVAL(blob
->data
, 0);
408 case DRSUAPI_ATTID_userAccountControl
:
409 uacc
= IVAL(blob
->data
, 0);
411 case DRSUAPI_ATTID_supplementalCredentials
:
412 status
= parse_supplemental_credentials(mem_ctx
,
416 if (!NT_STATUS_IS_OK(status
)) {
417 DEBUG(2, ("parsing of supplemental "
418 "credentials failed: %s\n",
427 status
= store_or_fetch_attribute(mem_ctx
,
432 if (!NT_STATUS_IS_OK(status
)) {
433 DBG_ERR("store_or_fetch_attribute(%s, %s, %s): %s\n",
434 object_dn
, "SAMACCOUNTNAME", name
,
440 DEBUG(10, ("no name (sAMAccountName) found - skipping.\n"));
444 DEBUG(1,("#%02d: %s:%d, ", ctx
->count
, name
, kvno
));
445 DEBUGADD(1,("sAMAccountType: 0x%08x, userAccountControl: 0x%08x",
448 DEBUGADD(1,(", upn: %s", upn
));
451 DEBUGADD(1, (", spns: ["));
452 for (i
= 0; i
< num_spns
; i
++) {
453 DEBUGADD(1, ("%s%s", spn
[i
],
454 (i
+1 == num_spns
)?"]":", "));
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
)) {
469 /* add kerberos keys (if any) */
472 for (i
=0; i
< pkb4
->num_keys
; i
++) {
473 if (!pkb4
->keys
[i
].value
) {
476 status
= libnet_keytab_add_to_keytab_entries(mem_ctx
, ctx
, kvno
,
479 pkb4
->keys
[i
].keytype
,
480 *pkb4
->keys
[i
].value
);
481 if (!NT_STATUS_IS_OK(status
)) {
485 for (i
=0; i
< pkb4
->num_old_keys
; i
++) {
486 if (!pkb4
->old_keys
[i
].value
) {
489 status
= libnet_keytab_add_to_keytab_entries(mem_ctx
, ctx
, kvno
- 1,
492 pkb4
->old_keys
[i
].keytype
,
493 *pkb4
->old_keys
[i
].value
);
494 if (!NT_STATUS_IS_OK(status
)) {
498 for (i
=0; i
< pkb4
->num_older_keys
; i
++) {
499 if (!pkb4
->older_keys
[i
].value
) {
502 status
= libnet_keytab_add_to_keytab_entries(mem_ctx
, ctx
, kvno
- 2,
505 pkb4
->older_keys
[i
].keytype
,
506 *pkb4
->older_keys
[i
].value
);
507 if (!NT_STATUS_IS_OK(status
)) {
514 for (i
=0; i
< pkb3
->num_keys
; i
++) {
515 if (!pkb3
->keys
[i
].value
) {
518 status
= libnet_keytab_add_to_keytab_entries(mem_ctx
, ctx
, kvno
, name
,
520 pkb3
->keys
[i
].keytype
,
521 *pkb3
->keys
[i
].value
);
522 if (!NT_STATUS_IS_OK(status
)) {
526 for (i
=0; i
< pkb3
->num_old_keys
; i
++) {
527 if (!pkb3
->old_keys
[i
].value
) {
530 status
= libnet_keytab_add_to_keytab_entries(mem_ctx
, ctx
, kvno
- 1,
533 pkb3
->old_keys
[i
].keytype
,
534 *pkb3
->old_keys
[i
].value
);
535 if (!NT_STATUS_IS_OK(status
)) {
541 if (kvno
< pwd_history_len
) {
545 /* add password history */
547 /* skip first entry */
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
)) {
567 static NTSTATUS
parse_AuthenticationInformation(TALLOC_CTX
*mem_ctx
,
568 struct libnet_keytab_context
*ctx
,
570 const char *trust_name
,
571 const char *attr_name
,
572 const char *salt_principal
,
575 const struct AuthenticationInformationArray
*ia
)
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
;
590 case TRUST_AUTH_TYPE_NT4OWF
:
591 nthash
= &a
->AuthInfo
.nt4owf
.password
;
593 case TRUST_AUTH_TYPE_CLEAR
:
594 clear
= &a
->AuthInfo
.clear
;
601 if (clear
!= NULL
&& clear
->size
!= 0) {
602 DATA_BLOB password_utf16
= data_blob_null
;
605 password_utf16
= data_blob_const(clear
->password
,
608 if (nthash
== NULL
) {
611 password_utf16
.length
);
615 ok
= convert_string_talloc(mem_ctx
,
616 CH_UTF16MUNGED
, CH_UTF8
,
618 password_utf16
.length
,
619 (void *)&password_utf8
.data
,
620 &password_utf8
.length
);
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
,
635 krb5_error_code kret
;
638 kret
= smb_krb5_parse_name(ctx
->context
,
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
,
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
,
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
,
684 if (!NT_STATUS_IS_OK(status
)) {
685 smb_krb5_free_data_contents(ctx
->context
, &salt
);
686 krb5_free_principal(ctx
->context
, salt_princ
);
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
;
699 blob
= data_blob_talloc(mem_ctx
, nthash
->hash
, sizeof(nthash
->hash
));
701 status
= libnet_keytab_add_to_keytab_entries(mem_ctx
, ctx
,
705 ENCTYPE_ARCFOUR_HMAC
,
707 if (!NT_STATUS_IS_OK(status
)) {
715 static NTSTATUS
parse_trustAuthInOutBlob(TALLOC_CTX
*mem_ctx
,
716 struct libnet_keytab_context
*ctx
,
718 const char *trust_name
,
719 const char *attr_name
,
720 const char *salt_principal
,
721 const DATA_BLOB
*blob
)
724 enum ndr_err_code ndr_err
;
725 struct trustAuthInOutBlob taiob
;
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
);
735 D_WARNING("# %s %s/%s\n", dn
, attr_name
, trust_name
);
737 status
= parse_AuthenticationInformation(mem_ctx
,
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
));
752 status
= parse_AuthenticationInformation(mem_ctx
,
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
;
771 static NTSTATUS
parse_tdo(TALLOC_CTX
*mem_ctx
,
772 struct libnet_keytab_context
*ctx
,
773 struct drsuapi_DsReplicaObjectListItemEx
*cur
)
776 const char *dn
= cur
->object
.identifier
->dn
;
777 char *trustPartner
= NULL
;
778 char *flatName
= 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
;
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) {
798 if (attr
->value_ctr
.values
[0].blob
== NULL
) {
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
,
810 case DRSUAPI_ATTID_flatName
:
811 pull_string_talloc(mem_ctx
, NULL
, 0, &flatName
,
812 blob
->data
, blob
->length
,
815 case DRSUAPI_ATTID_cn
:
816 pull_string_talloc(mem_ctx
, NULL
, 0, &cn
,
817 blob
->data
, blob
->length
,
825 if (trustPartner
!= NULL
) {
826 trust_name
= trustPartner
;
827 } else if (flatName
!= NULL
) {
828 trust_name
= flatName
;
833 status
= store_or_fetch_attribute(mem_ctx
,
838 if (!NT_STATUS_IS_OK(status
)) {
839 DBG_ERR("store_or_fetch_attribute(%s, %s, %s): %s\n",
840 dn
, "REMOTETRUSTNAME", trust_name
,
845 if (trust_name
== NULL
) {
846 D_DEBUG("no trust_name (trustPartner, flatName, cn) found - "
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
,
864 if (incoming_salt
== NULL
) {
865 return NT_STATUS_NO_MEMORY
;
867 outgoing_salt
= talloc_asprintf(mem_ctx
,
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) {
886 if (attr
->value_ctr
.values
[0].blob
== NULL
) {
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
;
897 case DRSUAPI_ATTID_trustAuthOutgoing
:
898 attr_name
= "trustAuthOutgoing";
899 salt_principal
= outgoing_salt
;
905 if (attr_name
== NULL
) {
909 status
= parse_trustAuthInOutBlob(mem_ctx
,
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
));
925 static NTSTATUS
parse_object(TALLOC_CTX
*mem_ctx
,
926 struct libnet_keytab_context
*ctx
,
927 struct drsuapi_DsReplicaObjectListItemEx
*cur
)
931 if (cur
->object
.identifier
->dn
== NULL
) {
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
;
941 switch (attr
->attid
) {
942 case DRSUAPI_ATTID_isDeleted
:
943 case DRSUAPI_ATTID_isRecycled
:
949 if (attr
->value_ctr
.num_values
!= 1) {
953 if (attr
->value_ctr
.values
[0].blob
== NULL
) {
957 blob
= attr
->value_ctr
.values
[0].blob
;
959 if (blob
->length
!= 4) {
963 val
= PULL_LE_U32(blob
->data
, 0);
965 /* ignore deleted object */
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
);
990 static bool dn_is_in_object_list(struct dssync_context
*ctx
,
995 if (ctx
->object_count
== 0) {
999 for (count
= 0; count
< ctx
->object_count
; count
++) {
1000 if (strequal(ctx
->object_dns
[count
], dn
)) {
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
))
1031 status
= parse_object(mem_ctx
, keytab_ctx
, cur
);
1032 if (!NT_STATUS_IS_OK(status
)) {
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
,