2 Unix SMB/CIFS implementation.
4 Copyright (C) Stefan Metzmacher 2015
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "../lib/util/util_ldb.h"
23 #include "dsdb/samdb/samdb.h"
24 #include "libcli/security/security.h"
25 #include "librpc/gen_ndr/ndr_security.h"
26 #include "librpc/gen_ndr/ndr_misc.h"
27 #include "../libds/common/flags.h"
28 #include "dsdb/common/proto.h"
29 #include "param/param.h"
30 #include "librpc/gen_ndr/ndr_drsblobs.h"
31 #include "lib/util/tsort.h"
32 #include "dsdb/common/util.h"
33 #include "libds/common/flag_mapping.h"
34 #include "../lib/util/dlinklist.h"
35 #include "../lib/crypto/crypto.h"
36 #include "libcli/ldap/ldap_ndr.h"
38 NTSTATUS
dsdb_trust_forest_info_from_lsa(TALLOC_CTX
*mem_ctx
,
39 const struct lsa_ForestTrustInformation
*lfti
,
40 struct ForestTrustInfo
**_fti
)
42 struct ForestTrustInfo
*fti
;
47 fti
= talloc_zero(mem_ctx
, struct ForestTrustInfo
);
49 return NT_STATUS_NO_MEMORY
;
53 fti
->count
= lfti
->count
;
54 fti
->records
= talloc_zero_array(mem_ctx
,
55 struct ForestTrustInfoRecordArmor
,
57 if (fti
->records
== NULL
) {
59 return NT_STATUS_NO_MEMORY
;
62 for (i
= 0; i
< fti
->count
; i
++) {
63 const struct lsa_ForestTrustRecord
*lftr
= lfti
->entries
[i
];
64 struct ForestTrustInfoRecord
*ftr
= &fti
->records
[i
].record
;
65 struct ForestTrustString
*str
= NULL
;
66 const struct lsa_StringLarge
*lstr
= NULL
;
67 const struct lsa_ForestTrustDomainInfo
*linfo
= NULL
;
68 struct ForestTrustDataDomainInfo
*info
= NULL
;
72 return NT_STATUS_INVALID_PARAMETER
;
75 ftr
->flags
= lftr
->flags
;
76 ftr
->timestamp
= lftr
->time
;
77 ftr
->type
= (enum ForestTrustInfoRecordType
)lftr
->type
;
80 case LSA_FOREST_TRUST_TOP_LEVEL_NAME
:
81 lstr
= &lftr
->forest_trust_data
.top_level_name
;
82 str
= &ftr
->data
.name
;
84 str
->string
= talloc_strdup(mem_ctx
, lstr
->string
);
85 if (str
->string
== NULL
) {
87 return NT_STATUS_NO_MEMORY
;
92 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX
:
93 lstr
= &lftr
->forest_trust_data
.top_level_name_ex
;
94 str
= &ftr
->data
.name
;
96 str
->string
= talloc_strdup(mem_ctx
, lstr
->string
);
97 if (str
->string
== NULL
) {
99 return NT_STATUS_NO_MEMORY
;
104 case LSA_FOREST_TRUST_DOMAIN_INFO
:
105 linfo
= &lftr
->forest_trust_data
.domain_info
;
106 info
= &ftr
->data
.info
;
108 if (linfo
->domain_sid
== NULL
) {
110 return NT_STATUS_INVALID_PARAMETER
;
112 info
->sid
= *linfo
->domain_sid
;
114 lstr
= &linfo
->dns_domain_name
;
115 str
= &info
->dns_name
;
116 str
->string
= talloc_strdup(mem_ctx
, lstr
->string
);
117 if (str
->string
== NULL
) {
119 return NT_STATUS_NO_MEMORY
;
122 lstr
= &linfo
->netbios_domain_name
;
123 str
= &info
->netbios_name
;
124 str
->string
= talloc_strdup(mem_ctx
, lstr
->string
);
125 if (str
->string
== NULL
) {
127 return NT_STATUS_NO_MEMORY
;
133 return NT_STATUS_NOT_SUPPORTED
;
141 static NTSTATUS
dsdb_trust_forest_record_to_lsa(TALLOC_CTX
*mem_ctx
,
142 const struct ForestTrustInfoRecord
*ftr
,
143 struct lsa_ForestTrustRecord
**_lftr
)
145 struct lsa_ForestTrustRecord
*lftr
= NULL
;
146 const struct ForestTrustString
*str
= NULL
;
147 struct lsa_StringLarge
*lstr
= NULL
;
148 const struct ForestTrustDataDomainInfo
*info
= NULL
;
149 struct lsa_ForestTrustDomainInfo
*linfo
= NULL
;
153 lftr
= talloc_zero(mem_ctx
, struct lsa_ForestTrustRecord
);
155 return NT_STATUS_NO_MEMORY
;
158 lftr
->flags
= ftr
->flags
;
159 lftr
->time
= ftr
->timestamp
;
160 lftr
->type
= (enum lsa_ForestTrustRecordType
)ftr
->type
;
162 switch (lftr
->type
) {
163 case LSA_FOREST_TRUST_TOP_LEVEL_NAME
:
164 lstr
= &lftr
->forest_trust_data
.top_level_name
;
165 str
= &ftr
->data
.name
;
167 lstr
->string
= talloc_strdup(mem_ctx
, str
->string
);
168 if (lstr
->string
== NULL
) {
170 return NT_STATUS_NO_MEMORY
;
175 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX
:
176 lstr
= &lftr
->forest_trust_data
.top_level_name_ex
;
177 str
= &ftr
->data
.name
;
179 lstr
->string
= talloc_strdup(mem_ctx
, str
->string
);
180 if (lstr
->string
== NULL
) {
182 return NT_STATUS_NO_MEMORY
;
187 case LSA_FOREST_TRUST_DOMAIN_INFO
:
188 linfo
= &lftr
->forest_trust_data
.domain_info
;
189 info
= &ftr
->data
.info
;
191 linfo
->domain_sid
= dom_sid_dup(lftr
, &info
->sid
);
192 if (linfo
->domain_sid
== NULL
) {
194 return NT_STATUS_NO_MEMORY
;
197 lstr
= &linfo
->dns_domain_name
;
198 str
= &info
->dns_name
;
199 lstr
->string
= talloc_strdup(mem_ctx
, str
->string
);
200 if (lstr
->string
== NULL
) {
202 return NT_STATUS_NO_MEMORY
;
205 lstr
= &linfo
->netbios_domain_name
;
206 str
= &info
->netbios_name
;
207 lstr
->string
= talloc_strdup(mem_ctx
, str
->string
);
208 if (lstr
->string
== NULL
) {
210 return NT_STATUS_NO_MEMORY
;
216 return NT_STATUS_NOT_SUPPORTED
;
223 NTSTATUS
dsdb_trust_forest_info_to_lsa(TALLOC_CTX
*mem_ctx
,
224 const struct ForestTrustInfo
*fti
,
225 struct lsa_ForestTrustInformation
**_lfti
)
227 struct lsa_ForestTrustInformation
*lfti
;
232 if (fti
->version
!= 1) {
233 return NT_STATUS_INVALID_PARAMETER
;
236 lfti
= talloc_zero(mem_ctx
, struct lsa_ForestTrustInformation
);
238 return NT_STATUS_NO_MEMORY
;
241 lfti
->count
= fti
->count
;
242 lfti
->entries
= talloc_zero_array(mem_ctx
,
243 struct lsa_ForestTrustRecord
*,
245 if (lfti
->entries
== NULL
) {
247 return NT_STATUS_NO_MEMORY
;
250 for (i
= 0; i
< fti
->count
; i
++) {
251 struct ForestTrustInfoRecord
*ftr
= &fti
->records
[i
].record
;
252 struct lsa_ForestTrustRecord
*lftr
= NULL
;
255 status
= dsdb_trust_forest_record_to_lsa(lfti
->entries
, ftr
,
257 if (!NT_STATUS_IS_OK(status
)) {
259 return NT_STATUS_NO_MEMORY
;
261 lfti
->entries
[i
] = lftr
;
268 static NTSTATUS
dsdb_trust_forest_info_add_record(struct lsa_ForestTrustInformation
*fti
,
269 const struct lsa_ForestTrustRecord
*ftr
)
271 struct lsa_ForestTrustRecord
**es
= NULL
;
272 struct lsa_ForestTrustRecord
*e
= NULL
;
273 const struct lsa_StringLarge
*dns1
= NULL
;
274 struct lsa_StringLarge
*dns2
= NULL
;
275 const struct lsa_ForestTrustDomainInfo
*d1
= NULL
;
276 struct lsa_ForestTrustDomainInfo
*d2
= NULL
;
279 es
= talloc_realloc(fti
, fti
->entries
,
280 struct lsa_ForestTrustRecord
*,
283 return NT_STATUS_NO_MEMORY
;
287 e
= talloc_zero(es
, struct lsa_ForestTrustRecord
);
289 return NT_STATUS_NO_MEMORY
;
293 e
->flags
= ftr
->flags
;
297 case LSA_FOREST_TRUST_TOP_LEVEL_NAME
:
298 dns1
= &ftr
->forest_trust_data
.top_level_name
;
299 dns2
= &e
->forest_trust_data
.top_level_name
;
302 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX
:
303 dns1
= &ftr
->forest_trust_data
.top_level_name_ex
;
304 dns2
= &e
->forest_trust_data
.top_level_name_ex
;
307 case LSA_FOREST_TRUST_DOMAIN_INFO
:
308 dns1
= &ftr
->forest_trust_data
.domain_info
.dns_domain_name
;
309 dns2
= &e
->forest_trust_data
.domain_info
.dns_domain_name
;
310 d1
= &ftr
->forest_trust_data
.domain_info
;
311 d2
= &e
->forest_trust_data
.domain_info
;
314 return NT_STATUS_INVALID_PARAMETER
;
317 if (dns1
->string
== NULL
) {
319 return NT_STATUS_INVALID_PARAMETER
;
322 len
= strlen(dns1
->string
);
325 return NT_STATUS_INVALID_PARAMETER
;
328 dns2
->string
= talloc_strdup(e
, dns1
->string
);
329 if (dns2
->string
== NULL
) {
331 return NT_STATUS_NO_MEMORY
;
335 const struct lsa_StringLarge
*nb1
= &d1
->netbios_domain_name
;
336 struct lsa_StringLarge
*nb2
= &d2
->netbios_domain_name
;
338 if (nb1
->string
== NULL
) {
340 return NT_STATUS_INVALID_PARAMETER
;
343 len
= strlen(nb1
->string
);
346 return NT_STATUS_INVALID_PARAMETER
;
350 return NT_STATUS_INVALID_PARAMETER
;
353 nb2
->string
= talloc_strdup(e
, nb1
->string
);
354 if (nb2
->string
== NULL
) {
356 return NT_STATUS_NO_MEMORY
;
359 if (d1
->domain_sid
== NULL
) {
361 return NT_STATUS_INVALID_PARAMETER
;
364 d2
->domain_sid
= dom_sid_dup(e
, d1
->domain_sid
);
365 if (d2
->domain_sid
== NULL
) {
367 return NT_STATUS_NO_MEMORY
;
371 fti
->entries
[fti
->count
++] = e
;
375 static NTSTATUS
dsdb_trust_parse_crossref_info(TALLOC_CTX
*mem_ctx
,
376 struct ldb_context
*sam_ctx
,
377 const struct ldb_message
*msg
,
378 struct lsa_TrustDomainInfoInfoEx
**_tdo
)
380 TALLOC_CTX
*frame
= talloc_stackframe();
381 struct lsa_TrustDomainInfoInfoEx
*tdo
= NULL
;
382 const char *dns
= NULL
;
383 const char *netbios
= NULL
;
384 struct ldb_dn
*nc_dn
= NULL
;
385 struct dom_sid sid
= {};
389 tdo
= talloc_zero(mem_ctx
, struct lsa_TrustDomainInfoInfoEx
);
392 return NT_STATUS_NO_MEMORY
;
394 talloc_steal(frame
, tdo
);
396 dns
= ldb_msg_find_attr_as_string(msg
, "dnsRoot", NULL
);
399 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
401 tdo
->domain_name
.string
= talloc_strdup(tdo
, dns
);
402 if (tdo
->domain_name
.string
== NULL
) {
404 return NT_STATUS_NO_MEMORY
;
407 netbios
= ldb_msg_find_attr_as_string(msg
, "nETBIOSName", NULL
);
408 if (netbios
== NULL
) {
410 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
412 tdo
->netbios_name
.string
= talloc_strdup(tdo
, netbios
);
413 if (tdo
->netbios_name
.string
== NULL
) {
415 return NT_STATUS_NO_MEMORY
;
418 nc_dn
= samdb_result_dn(sam_ctx
, frame
, msg
, "ncName", NULL
);
421 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
424 status
= dsdb_get_extended_dn_sid(nc_dn
, &sid
, "SID");
425 if (!NT_STATUS_IS_OK(status
)) {
429 tdo
->sid
= dom_sid_dup(tdo
, &sid
);
430 if (tdo
->sid
== NULL
) {
432 return NT_STATUS_NO_MEMORY
;
435 tdo
->trust_type
= LSA_TRUST_TYPE_UPLEVEL
;
436 tdo
->trust_direction
= LSA_TRUST_DIRECTION_INBOUND
|
437 LSA_TRUST_DIRECTION_OUTBOUND
;
438 tdo
->trust_attributes
= LSA_TRUST_ATTRIBUTE_WITHIN_FOREST
;
440 *_tdo
= talloc_move(mem_ctx
, &tdo
);
445 static NTSTATUS
dsdb_trust_crossref_tdo_info(TALLOC_CTX
*mem_ctx
,
446 struct ldb_context
*sam_ctx
,
447 struct ldb_dn
*domain_dn
,
448 const char *extra_filter
,
449 struct lsa_TrustDomainInfoInfoEx
**_tdo
,
450 struct lsa_TrustDomainInfoInfoEx
**_root_trust_tdo
,
451 struct lsa_TrustDomainInfoInfoEx
**_trust_parent_tdo
)
453 TALLOC_CTX
*frame
= talloc_stackframe();
454 struct lsa_TrustDomainInfoInfoEx
*tdo
= NULL
;
455 struct lsa_TrustDomainInfoInfoEx
*root_trust_tdo
= NULL
;
456 struct lsa_TrustDomainInfoInfoEx
*trust_parent_tdo
= NULL
;
457 struct ldb_dn
*partitions_dn
= NULL
;
458 const char * const cross_attrs
[] = {
466 struct ldb_result
*cross_res
= NULL
;
467 struct ldb_message
*msg
= NULL
;
468 struct ldb_dn
*root_trust_dn
= NULL
;
469 struct ldb_dn
*trust_parent_dn
= NULL
;
473 if (extra_filter
== NULL
) {
478 if (_root_trust_tdo
!= NULL
) {
479 *_root_trust_tdo
= NULL
;
481 if (_trust_parent_tdo
!= NULL
) {
482 *_trust_parent_tdo
= NULL
;
485 partitions_dn
= samdb_partitions_dn(sam_ctx
, frame
);
486 if (partitions_dn
== NULL
) {
488 return NT_STATUS_NO_MEMORY
;
491 ret
= dsdb_search(sam_ctx
, partitions_dn
, &cross_res
,
492 partitions_dn
, LDB_SCOPE_ONELEVEL
,
494 DSDB_SEARCH_ONE_ONLY
|
495 DSDB_SEARCH_SHOW_EXTENDED_DN
,
498 "(objectClass=crossRef)"
499 "(systemFlags:%s:=%u)"
502 ldb_dn_get_linearized(domain_dn
),
503 LDB_OID_COMPARATOR_AND
,
504 SYSTEM_FLAG_CR_NTDS_DOMAIN
,
506 if (ret
!= LDB_SUCCESS
) {
508 return dsdb_ldb_err_to_ntstatus(ret
);
510 msg
= cross_res
->msgs
[0];
512 status
= dsdb_trust_parse_crossref_info(mem_ctx
, sam_ctx
, msg
, &tdo
);
513 if (!NT_STATUS_IS_OK(status
)) {
517 talloc_steal(frame
, tdo
);
519 if (_root_trust_tdo
!= NULL
) {
520 root_trust_dn
= samdb_result_dn(sam_ctx
, frame
, msg
,
523 if (_trust_parent_tdo
!= NULL
) {
524 trust_parent_dn
= samdb_result_dn(sam_ctx
, frame
, msg
,
525 "trustParent", NULL
);
528 if (root_trust_dn
!= NULL
) {
529 struct ldb_message
*root_trust_msg
= NULL
;
531 ret
= dsdb_search_one(sam_ctx
, frame
,
536 DSDB_SEARCH_NO_GLOBAL_CATALOG
,
537 "(objectClass=crossRef)");
538 if (ret
!= LDB_SUCCESS
) {
539 status
= dsdb_ldb_err_to_ntstatus(ret
);
540 DEBUG(3, ("Failed to search for %s: %s - %s\n",
541 ldb_dn_get_linearized(root_trust_dn
),
542 nt_errstr(status
), ldb_errstring(sam_ctx
)));
547 status
= dsdb_trust_parse_crossref_info(mem_ctx
, sam_ctx
,
550 if (!NT_STATUS_IS_OK(status
)) {
554 talloc_steal(frame
, root_trust_tdo
);
557 if (trust_parent_dn
!= NULL
) {
558 struct ldb_message
*trust_parent_msg
= NULL
;
560 ret
= dsdb_search_one(sam_ctx
, frame
,
565 DSDB_SEARCH_NO_GLOBAL_CATALOG
,
566 "(objectClass=crossRef)");
567 if (ret
!= LDB_SUCCESS
) {
568 status
= dsdb_ldb_err_to_ntstatus(ret
);
569 DEBUG(3, ("Failed to search for %s: %s - %s\n",
570 ldb_dn_get_linearized(trust_parent_dn
),
571 nt_errstr(status
), ldb_errstring(sam_ctx
)));
576 status
= dsdb_trust_parse_crossref_info(mem_ctx
, sam_ctx
,
579 if (!NT_STATUS_IS_OK(status
)) {
583 talloc_steal(frame
, trust_parent_tdo
);
586 *_tdo
= talloc_move(mem_ctx
, &tdo
);
587 if (_root_trust_tdo
!= NULL
) {
588 *_root_trust_tdo
= talloc_move(mem_ctx
, &root_trust_tdo
);
590 if (_trust_parent_tdo
!= NULL
) {
591 *_trust_parent_tdo
= talloc_move(mem_ctx
, &trust_parent_tdo
);
597 #define DNS_CMP_FIRST_IS_CHILD -2
598 #define DNS_CMP_FIRST_IS_LESS -1
599 #define DNS_CMP_MATCH 0
600 #define DNS_CMP_SECOND_IS_LESS 1
601 #define DNS_CMP_SECOND_IS_CHILD 2
603 #define DNS_CMP_IS_NO_MATCH(__cmp) \
604 ((__cmp == DNS_CMP_FIRST_IS_LESS) || (__cmp == DNS_CMP_SECOND_IS_LESS))
607 * this function assumes names are well formed DNS names.
608 * it doesn't validate them
610 * It allows strings up to a length of UINT16_MAX - 1
611 * with up to UINT8_MAX components. On overflow this
612 * just returns the result of strcasecmp_m().
614 * Trailing dots (only one) are ignored.
616 * The DNS names are compared per component, starting from
619 static int dns_cmp(const char *s1
, const char *s2
)
622 const char *p1
= NULL
;
623 size_t num_comp1
= 0;
624 uint16_t comp1
[UINT8_MAX
] = {};
626 const char *p2
= NULL
;
627 size_t num_comp2
= 0;
628 uint16_t comp2
[UINT8_MAX
] = {};
640 * trailing '.' are ignored.
642 if (l1
> 1 && s1
[l1
- 1] == '.') {
645 if (l2
> 1 && s2
[l2
- 1] == '.') {
649 for (i
= 0; i
< ARRAY_SIZE(comp1
); i
++) {
655 if (l1
== 0 || l1
>= UINT16_MAX
) {
656 /* just use one single component on overflow */
661 comp1
[num_comp1
++] = PTR_DIFF(p1
, s1
);
663 p
= strchr_m(p1
, '.');
673 /* just use one single component on overflow */
675 comp1
[num_comp1
++] = 0;
679 for (i
= 0; i
< ARRAY_SIZE(comp2
); i
++) {
685 if (l2
== 0 || l2
>= UINT16_MAX
) {
686 /* just use one single component on overflow */
691 comp2
[num_comp2
++] = PTR_DIFF(p2
, s2
);
693 p
= strchr_m(p2
, '.');
703 /* just use one single component on overflow */
705 comp2
[num_comp2
++] = 0;
709 for (i
= 0; i
< UINT8_MAX
; i
++) {
713 size_t idx
= num_comp1
- (i
+ 1);
714 p1
= s1
+ comp1
[idx
];
720 size_t idx
= num_comp2
- (i
+ 1);
721 p2
= s2
+ comp2
[idx
];
726 if (p1
== NULL
&& p2
== NULL
) {
727 return DNS_CMP_MATCH
;
729 if (p1
!= NULL
&& p2
== NULL
) {
730 return DNS_CMP_FIRST_IS_CHILD
;
732 if (p1
== NULL
&& p2
!= NULL
) {
733 return DNS_CMP_SECOND_IS_CHILD
;
736 cmp
= strcasecmp_m(p1
, p2
);
738 return DNS_CMP_FIRST_IS_LESS
;
741 return DNS_CMP_SECOND_IS_LESS
;
745 smb_panic(__location__
);
749 static int dsdb_trust_find_tln_match_internal(const struct lsa_ForestTrustInformation
*info
,
750 enum lsa_ForestTrustRecordType type
,
751 uint32_t disable_mask
,
756 for (i
= 0; i
< info
->count
; i
++) {
757 struct lsa_ForestTrustRecord
*e
= info
->entries
[i
];
758 struct lsa_StringLarge
*t
= NULL
;
765 if (e
->type
!= type
) {
769 if (e
->flags
& disable_mask
) {
774 case LSA_FOREST_TRUST_TOP_LEVEL_NAME
:
775 t
= &e
->forest_trust_data
.top_level_name
;
777 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX
:
778 t
= &e
->forest_trust_data
.top_level_name_ex
;
788 cmp
= dns_cmp(tln
, t
->string
);
791 case DNS_CMP_FIRST_IS_CHILD
:
799 static bool dsdb_trust_find_tln_match(const struct lsa_ForestTrustInformation
*info
,
804 m
= dsdb_trust_find_tln_match_internal(info
,
805 LSA_FOREST_TRUST_TOP_LEVEL_NAME
,
806 LSA_TLN_DISABLED_MASK
,
815 static bool dsdb_trust_find_tln_ex_match(const struct lsa_ForestTrustInformation
*info
,
820 m
= dsdb_trust_find_tln_match_internal(info
,
821 LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX
,
831 NTSTATUS
dsdb_trust_local_tdo_info(TALLOC_CTX
*mem_ctx
,
832 struct ldb_context
*sam_ctx
,
833 struct lsa_TrustDomainInfoInfoEx
**_tdo
)
835 struct ldb_dn
*domain_dn
= NULL
;
837 domain_dn
= ldb_get_default_basedn(sam_ctx
);
838 if (domain_dn
== NULL
) {
839 return NT_STATUS_INTERNAL_ERROR
;
842 return dsdb_trust_crossref_tdo_info(mem_ctx
, sam_ctx
,
847 NTSTATUS
dsdb_trust_xref_tdo_info(TALLOC_CTX
*mem_ctx
,
848 struct ldb_context
*sam_ctx
,
849 struct lsa_TrustDomainInfoInfoEx
**_tdo
)
852 * The extra filter makes sure we only find the forest root domain
854 const char *extra_filter
= "(!(|(rootTrust=*)(trustParent=*)))";
855 struct ldb_dn
*domain_dn
= NULL
;
857 domain_dn
= ldb_get_default_basedn(sam_ctx
);
858 if (domain_dn
== NULL
) {
859 return NT_STATUS_INTERNAL_ERROR
;
862 return dsdb_trust_crossref_tdo_info(mem_ctx
, sam_ctx
,
863 domain_dn
, extra_filter
,
867 static int dsdb_trust_xref_sort_msgs(struct ldb_message
**_m1
,
868 struct ldb_message
**_m2
)
870 struct ldb_message
*m1
= *_m1
;
871 struct ldb_message
*m2
= *_m2
;
872 const char *dns1
= NULL
;
873 const char *dns2
= NULL
;
875 struct ldb_message_element
*rootTrust1
= NULL
;
876 struct ldb_message_element
*trustParent1
= NULL
;
877 struct ldb_message_element
*rootTrust2
= NULL
;
878 struct ldb_message_element
*trustParent2
= NULL
;
880 dns1
= ldb_msg_find_attr_as_string(m1
, "dnsRoot", NULL
);
881 dns2
= ldb_msg_find_attr_as_string(m2
, "dnsRoot", NULL
);
883 cmp
= dns_cmp(dns1
, dns2
);
885 case DNS_CMP_FIRST_IS_CHILD
:
887 case DNS_CMP_SECOND_IS_CHILD
:
891 rootTrust1
= ldb_msg_find_element(m1
, "rootTrust");
892 trustParent1
= ldb_msg_find_element(m1
, "trustParent");
893 rootTrust2
= ldb_msg_find_element(m2
, "rootTrust");
894 trustParent2
= ldb_msg_find_element(m2
, "trustParent");
896 if (rootTrust1
== NULL
&& trustParent1
== NULL
) {
897 /* m1 is the forest root */
900 if (rootTrust2
== NULL
&& trustParent2
== NULL
) {
901 /* m2 is the forest root */
908 static int dsdb_trust_xref_sort_vals(struct ldb_val
*v1
,
911 const char *dns1
= (const char *)v1
->data
;
912 const char *dns2
= (const char *)v2
->data
;
914 return dns_cmp(dns1
, dns2
);
917 NTSTATUS
dsdb_trust_xref_forest_info(TALLOC_CTX
*mem_ctx
,
918 struct ldb_context
*sam_ctx
,
919 struct lsa_ForestTrustInformation
**_info
)
921 TALLOC_CTX
*frame
= talloc_stackframe();
922 struct lsa_ForestTrustInformation
*info
= NULL
;
923 struct ldb_dn
*partitions_dn
= NULL
;
924 const char * const cross_attrs1
[] = {
929 struct ldb_result
*cross_res1
= NULL
;
930 struct ldb_message_element
*upn_el
= NULL
;
931 struct ldb_message_element
*spn_el
= NULL
;
932 struct ldb_message
*tln_msg
= NULL
;
933 struct ldb_message_element
*tln_el
= NULL
;
934 const char * const cross_attrs2
[] = {
942 struct ldb_result
*cross_res2
= NULL
;
945 bool restart
= false;
948 info
= talloc_zero(mem_ctx
, struct lsa_ForestTrustInformation
);
951 return NT_STATUS_NO_MEMORY
;
953 talloc_steal(frame
, info
);
955 partitions_dn
= samdb_partitions_dn(sam_ctx
, frame
);
956 if (partitions_dn
== NULL
) {
958 return NT_STATUS_NO_MEMORY
;
961 ret
= dsdb_search_dn(sam_ctx
, partitions_dn
, &cross_res1
,
962 partitions_dn
, cross_attrs1
, 0);
963 if (ret
!= LDB_SUCCESS
) {
965 return dsdb_ldb_err_to_ntstatus(ret
);
968 ret
= dsdb_search(sam_ctx
, partitions_dn
, &cross_res2
,
969 partitions_dn
, LDB_SCOPE_ONELEVEL
,
971 DSDB_SEARCH_SHOW_EXTENDED_DN
,
972 "(&(objectClass=crossRef)"
973 "(systemFlags:%s:=%u))",
974 LDB_OID_COMPARATOR_AND
,
975 SYSTEM_FLAG_CR_NTDS_DOMAIN
);
976 if (ret
!= LDB_SUCCESS
) {
978 return dsdb_ldb_err_to_ntstatus(ret
);
982 * Sort the domains as trees, starting with the forest root
984 TYPESAFE_QSORT(cross_res2
->msgs
, cross_res2
->count
,
985 dsdb_trust_xref_sort_msgs
);
987 upn_el
= ldb_msg_find_element(cross_res1
->msgs
[0], "uPNSuffixes");
988 if (upn_el
!= NULL
) {
989 upn_el
->name
= "__tln__";
991 spn_el
= ldb_msg_find_element(cross_res1
->msgs
[0], "msDS-SPNSuffixes");
992 if (spn_el
!= NULL
) {
993 spn_el
->name
= "__tln__";
995 ret
= ldb_msg_normalize(sam_ctx
, frame
, cross_res1
->msgs
[0], &tln_msg
);
996 if (ret
!= LDB_SUCCESS
) {
998 return dsdb_ldb_err_to_ntstatus(ret
);
1000 tln_el
= ldb_msg_find_element(tln_msg
, "__tln__");
1001 if (tln_el
!= NULL
) {
1003 * Sort the domains as trees
1005 TYPESAFE_QSORT(tln_el
->values
, tln_el
->num_values
,
1006 dsdb_trust_xref_sort_vals
);
1009 for (i
=0; i
< cross_res2
->count
; i
++) {
1010 struct ldb_message
*m
= cross_res2
->msgs
[i
];
1011 const char *dns
= NULL
;
1012 const char *netbios
= NULL
;
1013 struct ldb_dn
*nc_dn
= NULL
;
1014 struct dom_sid sid
= {};
1015 struct lsa_ForestTrustRecord e
= {};
1016 struct lsa_ForestTrustDomainInfo
*d
= NULL
;
1017 struct lsa_StringLarge
*t
= NULL
;
1021 dns
= ldb_msg_find_attr_as_string(m
, "dnsRoot", NULL
);
1024 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1027 netbios
= ldb_msg_find_attr_as_string(m
, "nETBIOSName", NULL
);
1028 if (netbios
== NULL
) {
1030 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1033 nc_dn
= samdb_result_dn(sam_ctx
, m
, m
, "ncName", NULL
);
1034 if (nc_dn
== NULL
) {
1036 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1039 status
= dsdb_get_extended_dn_sid(nc_dn
, &sid
, "SID");
1040 if (!NT_STATUS_IS_OK(status
)) {
1045 match
= dsdb_trust_find_tln_match(info
, dns
);
1048 * First the TOP_LEVEL_NAME, if required
1050 e
= (struct lsa_ForestTrustRecord
) {
1052 .type
= LSA_FOREST_TRUST_TOP_LEVEL_NAME
,
1053 .time
= 0, /* so far always 0 in traces. */
1056 t
= &e
.forest_trust_data
.top_level_name
;
1059 status
= dsdb_trust_forest_info_add_record(info
, &e
);
1060 if (!NT_STATUS_IS_OK(status
)) {
1067 * Then the DOMAIN_INFO
1069 e
= (struct lsa_ForestTrustRecord
) {
1071 .type
= LSA_FOREST_TRUST_DOMAIN_INFO
,
1072 .time
= 0, /* so far always 0 in traces. */
1074 d
= &e
.forest_trust_data
.domain_info
;
1075 d
->domain_sid
= &sid
;
1076 d
->dns_domain_name
.string
= dns
;
1077 d
->netbios_domain_name
.string
= netbios
;
1079 status
= dsdb_trust_forest_info_add_record(info
, &e
);
1080 if (!NT_STATUS_IS_OK(status
)) {
1086 for (i
=0; (tln_el
!= NULL
) && i
< tln_el
->num_values
; i
++) {
1087 const struct ldb_val
*v
= &tln_el
->values
[i
];
1088 const char *dns
= (const char *)v
->data
;
1089 struct lsa_ForestTrustRecord e
= {};
1090 struct lsa_StringLarge
*t
= NULL
;
1096 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1099 match
= dsdb_trust_find_tln_match(info
, dns
);
1105 * an additional the TOP_LEVEL_NAME
1107 e
= (struct lsa_ForestTrustRecord
) {
1109 .type
= LSA_FOREST_TRUST_TOP_LEVEL_NAME
,
1110 .time
= 0, /* so far always 0 in traces. */
1112 t
= &e
.forest_trust_data
.top_level_name
;
1115 status
= dsdb_trust_forest_info_add_record(info
, &e
);
1116 if (!NT_STATUS_IS_OK(status
)) {
1122 for (i
=0; i
< info
->count
; restart
? i
=0 : i
++) {
1123 struct lsa_ForestTrustRecord
*tr
= info
->entries
[i
];
1124 const struct lsa_StringLarge
*ts
= NULL
;
1129 if (tr
->type
!= LSA_FOREST_TRUST_TOP_LEVEL_NAME
) {
1133 ts
= &tr
->forest_trust_data
.top_level_name
;
1135 for (c
= i
+ 1; c
< info
->count
; c
++) {
1136 struct lsa_ForestTrustRecord
*cr
= info
->entries
[c
];
1137 const struct lsa_StringLarge
*cs
= NULL
;
1141 if (cr
->type
!= LSA_FOREST_TRUST_TOP_LEVEL_NAME
) {
1145 cs
= &cr
->forest_trust_data
.top_level_name
;
1147 cmp
= dns_cmp(ts
->string
, cs
->string
);
1148 if (DNS_CMP_IS_NO_MATCH(cmp
)) {
1151 if (cmp
!= DNS_CMP_FIRST_IS_CHILD
) {
1152 /* can't happen ... */
1158 TALLOC_FREE(info
->entries
[i
]);
1159 info
->entries
[i
] = info
->entries
[c
];
1161 for (j
= c
+ 1; j
< info
->count
; j
++) {
1162 info
->entries
[j
-1] = info
->entries
[j
];
1170 *_info
= talloc_move(mem_ctx
, &info
);
1172 return NT_STATUS_OK
;
1175 NTSTATUS
dsdb_trust_parse_tdo_info(TALLOC_CTX
*mem_ctx
,
1176 struct ldb_message
*m
,
1177 struct lsa_TrustDomainInfoInfoEx
**_tdo
)
1179 struct lsa_TrustDomainInfoInfoEx
*tdo
= NULL
;
1180 const char *dns
= NULL
;
1181 const char *netbios
= NULL
;
1185 tdo
= talloc_zero(mem_ctx
, struct lsa_TrustDomainInfoInfoEx
);
1187 return NT_STATUS_NO_MEMORY
;
1190 dns
= ldb_msg_find_attr_as_string(m
, "trustPartner", NULL
);
1193 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1195 tdo
->domain_name
.string
= talloc_strdup(tdo
, dns
);
1196 if (tdo
->domain_name
.string
== NULL
) {
1198 return NT_STATUS_NO_MEMORY
;
1201 netbios
= ldb_msg_find_attr_as_string(m
, "flatName", NULL
);
1202 if (netbios
== NULL
) {
1204 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1206 tdo
->netbios_name
.string
= talloc_strdup(tdo
, netbios
);
1207 if (tdo
->netbios_name
.string
== NULL
) {
1209 return NT_STATUS_NO_MEMORY
;
1212 tdo
->sid
= samdb_result_dom_sid(tdo
, m
, "securityIdentifier");
1213 if (tdo
->sid
== NULL
) {
1215 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1218 tdo
->trust_type
= ldb_msg_find_attr_as_uint(m
, "trustType", 0);
1219 tdo
->trust_direction
= ldb_msg_find_attr_as_uint(m
, "trustDirection", 0);
1220 tdo
->trust_attributes
= ldb_msg_find_attr_as_uint(m
, "trustAttributes", 0);
1223 return NT_STATUS_OK
;
1226 NTSTATUS
dsdb_trust_parse_forest_info(TALLOC_CTX
*mem_ctx
,
1227 struct ldb_message
*m
,
1228 struct ForestTrustInfo
**_fti
)
1230 const struct ldb_val
*ft_blob
= NULL
;
1231 struct ForestTrustInfo
*fti
= NULL
;
1232 enum ndr_err_code ndr_err
;
1236 ft_blob
= ldb_msg_find_ldb_val(m
, "msDS-TrustForestTrustInfo");
1237 if (ft_blob
== NULL
) {
1238 return NT_STATUS_NOT_FOUND
;
1241 fti
= talloc_zero(mem_ctx
, struct ForestTrustInfo
);
1243 return NT_STATUS_NO_MEMORY
;
1246 /* ldb_val is equivalent to DATA_BLOB */
1247 ndr_err
= ndr_pull_struct_blob_all(ft_blob
, fti
, fti
,
1248 (ndr_pull_flags_fn_t
)ndr_pull_ForestTrustInfo
);
1249 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1251 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1255 return NT_STATUS_OK
;
1258 NTSTATUS
dsdb_trust_normalize_forest_info_step1(TALLOC_CTX
*mem_ctx
,
1259 const struct lsa_ForestTrustInformation
*gfti
,
1260 struct lsa_ForestTrustInformation
**_nfti
)
1262 TALLOC_CTX
*frame
= talloc_stackframe();
1263 struct lsa_ForestTrustInformation
*nfti
;
1268 nfti
= talloc_zero(mem_ctx
, struct lsa_ForestTrustInformation
);
1271 return NT_STATUS_NO_MEMORY
;
1273 talloc_steal(frame
, nfti
);
1276 * First we copy every record and remove possible trailing dots
1279 * We also NULL out dublicates. The first one wins and
1280 * we keep 'count' as is. This is required in order to
1281 * provide the correct index for collision records.
1283 for (n
= 0; n
< gfti
->count
; n
++) {
1284 const struct lsa_ForestTrustRecord
*gftr
= gfti
->entries
[n
];
1285 struct lsa_ForestTrustRecord
*nftr
= NULL
;
1286 struct lsa_ForestTrustDomainInfo
*ninfo
= NULL
;
1287 struct lsa_StringLarge
*ntln
= NULL
;
1288 struct lsa_StringLarge
*nnb
= NULL
;
1289 struct dom_sid
*nsid
= NULL
;
1297 return NT_STATUS_INVALID_PARAMETER
;
1300 status
= dsdb_trust_forest_info_add_record(nfti
, gftr
);
1301 if (!NT_STATUS_IS_OK(status
)) {
1306 nftr
= nfti
->entries
[n
];
1308 switch (nftr
->type
) {
1309 case LSA_FOREST_TRUST_TOP_LEVEL_NAME
:
1310 ntln
= &nftr
->forest_trust_data
.top_level_name
;
1313 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX
:
1314 ntln
= &nftr
->forest_trust_data
.top_level_name_ex
;
1317 case LSA_FOREST_TRUST_DOMAIN_INFO
:
1318 ninfo
= &nftr
->forest_trust_data
.domain_info
;
1319 ntln
= &ninfo
->dns_domain_name
;
1320 nnb
= &ninfo
->netbios_domain_name
;
1321 nsid
= ninfo
->domain_sid
;
1326 return NT_STATUS_INVALID_PARAMETER
;
1330 * We remove one trailing '.' before checking
1333 * domain.com. becomes domain.com
1334 * domain.com.. becomes domain.com.
1336 * Then the following is invalid:
1342 len
= strlen(ntln
->string
);
1343 if (len
> 1 && ntln
->string
[len
- 1] == '.') {
1344 const char *cp
= &ntln
->string
[len
- 1];
1345 p
= discard_const_p(char, cp
);
1348 if (ntln
->string
[0] == '.') {
1350 return NT_STATUS_INVALID_PARAMETER
;
1352 p
= strstr_m(ntln
->string
, "..");
1355 return NT_STATUS_INVALID_PARAMETER
;
1358 for (c
= 0; c
< n
; c
++) {
1359 const struct lsa_ForestTrustRecord
*cftr
= nfti
->entries
[c
];
1360 const struct lsa_ForestTrustDomainInfo
*cinfo
= NULL
;
1361 const struct lsa_StringLarge
*ctln
= NULL
;
1362 const struct lsa_StringLarge
*cnb
= NULL
;
1363 const struct dom_sid
*csid
= NULL
;
1370 if (cftr
->type
!= nftr
->type
) {
1374 switch (cftr
->type
) {
1375 case LSA_FOREST_TRUST_TOP_LEVEL_NAME
:
1376 ctln
= &cftr
->forest_trust_data
.top_level_name
;
1379 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX
:
1380 ctln
= &cftr
->forest_trust_data
.top_level_name_ex
;
1383 case LSA_FOREST_TRUST_DOMAIN_INFO
:
1384 cinfo
= &cftr
->forest_trust_data
.domain_info
;
1385 ctln
= &cinfo
->dns_domain_name
;
1386 cnb
= &cinfo
->netbios_domain_name
;
1387 csid
= cinfo
->domain_sid
;
1392 return NT_STATUS_INVALID_PARAMETER
;
1395 cmp
= dns_cmp(ntln
->string
, ctln
->string
);
1396 if (cmp
== DNS_CMP_MATCH
) {
1398 TALLOC_FREE(nfti
->entries
[n
]);
1402 if (cinfo
== NULL
) {
1406 cmp
= strcasecmp_m(nnb
->string
, cnb
->string
);
1409 TALLOC_FREE(nfti
->entries
[n
]);
1413 cmp
= dom_sid_compare(nsid
, csid
);
1416 TALLOC_FREE(nfti
->entries
[n
]);
1423 * Now we check that only true top level names are provided
1425 for (n
= 0; n
< nfti
->count
; n
++) {
1426 const struct lsa_ForestTrustRecord
*nftr
= nfti
->entries
[n
];
1427 const struct lsa_StringLarge
*ntln
= NULL
;
1434 if (nftr
->type
!= LSA_FOREST_TRUST_TOP_LEVEL_NAME
) {
1438 ntln
= &nftr
->forest_trust_data
.top_level_name
;
1440 for (c
= 0; c
< nfti
->count
; c
++) {
1441 const struct lsa_ForestTrustRecord
*cftr
= nfti
->entries
[c
];
1442 const struct lsa_StringLarge
*ctln
= NULL
;
1453 if (cftr
->type
!= nftr
->type
) {
1457 ctln
= &cftr
->forest_trust_data
.top_level_name
;
1459 cmp
= dns_cmp(ntln
->string
, ctln
->string
);
1460 if (DNS_CMP_IS_NO_MATCH(cmp
)) {
1465 return NT_STATUS_INVALID_PARAMETER
;
1470 * Now we check that only true sub level excludes are provided
1472 for (n
= 0; n
< nfti
->count
; n
++) {
1473 const struct lsa_ForestTrustRecord
*nftr
= nfti
->entries
[n
];
1474 const struct lsa_StringLarge
*ntln
= NULL
;
1476 bool found_tln
= false;
1482 if (nftr
->type
!= LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX
) {
1486 ntln
= &nftr
->forest_trust_data
.top_level_name
;
1488 for (c
= 0; c
< nfti
->count
; c
++) {
1489 const struct lsa_ForestTrustRecord
*cftr
= nfti
->entries
[c
];
1490 const struct lsa_StringLarge
*ctln
= NULL
;
1501 if (cftr
->type
!= LSA_FOREST_TRUST_TOP_LEVEL_NAME
) {
1505 ctln
= &cftr
->forest_trust_data
.top_level_name
;
1507 cmp
= dns_cmp(ntln
->string
, ctln
->string
);
1508 if (cmp
== DNS_CMP_FIRST_IS_CHILD
) {
1519 return NT_STATUS_INVALID_PARAMETER
;
1523 * Now we check that there's a top level name for each domain
1525 for (n
= 0; n
< nfti
->count
; n
++) {
1526 const struct lsa_ForestTrustRecord
*nftr
= nfti
->entries
[n
];
1527 const struct lsa_ForestTrustDomainInfo
*ninfo
= NULL
;
1528 const struct lsa_StringLarge
*ntln
= NULL
;
1530 bool found_tln
= false;
1536 if (nftr
->type
!= LSA_FOREST_TRUST_DOMAIN_INFO
) {
1540 ninfo
= &nftr
->forest_trust_data
.domain_info
;
1541 ntln
= &ninfo
->dns_domain_name
;
1543 for (c
= 0; c
< nfti
->count
; c
++) {
1544 const struct lsa_ForestTrustRecord
*cftr
= nfti
->entries
[c
];
1545 const struct lsa_StringLarge
*ctln
= NULL
;
1556 if (cftr
->type
!= LSA_FOREST_TRUST_TOP_LEVEL_NAME
) {
1560 ctln
= &cftr
->forest_trust_data
.top_level_name
;
1562 cmp
= dns_cmp(ntln
->string
, ctln
->string
);
1563 if (cmp
== DNS_CMP_MATCH
) {
1567 if (cmp
== DNS_CMP_FIRST_IS_CHILD
) {
1578 return NT_STATUS_INVALID_PARAMETER
;
1581 *_nfti
= talloc_move(mem_ctx
, &nfti
);
1583 return NT_STATUS_OK
;
1586 NTSTATUS
dsdb_trust_normalize_forest_info_step2(TALLOC_CTX
*mem_ctx
,
1587 const struct lsa_ForestTrustInformation
*gfti
,
1588 struct lsa_ForestTrustInformation
**_nfti
)
1590 TALLOC_CTX
*frame
= talloc_stackframe();
1591 struct timeval tv
= timeval_current();
1592 NTTIME now
= timeval_to_nttime(&tv
);
1593 struct lsa_ForestTrustInformation
*nfti
;
1598 nfti
= talloc_zero(mem_ctx
, struct lsa_ForestTrustInformation
);
1601 return NT_STATUS_NO_MEMORY
;
1603 talloc_steal(frame
, nfti
);
1606 * Now we add TOP_LEVEL_NAME[_EX] in reverse order
1607 * followed by LSA_FOREST_TRUST_DOMAIN_INFO in reverse order.
1609 * This also removes the possible NULL entries generated in step1.
1612 for (g
= 0; g
< gfti
->count
; g
++) {
1613 const struct lsa_ForestTrustRecord
*gftr
= gfti
->entries
[gfti
->count
- (g
+1)];
1614 struct lsa_ForestTrustRecord tftr
;
1622 switch (gftr
->type
) {
1623 case LSA_FOREST_TRUST_TOP_LEVEL_NAME
:
1624 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX
:
1627 case LSA_FOREST_TRUST_DOMAIN_INFO
:
1633 return NT_STATUS_INVALID_PARAMETER
;
1640 /* make a copy in order to update the time. */
1642 if (tftr
.time
== 0) {
1646 status
= dsdb_trust_forest_info_add_record(nfti
, &tftr
);
1647 if (!NT_STATUS_IS_OK(status
)) {
1653 for (g
= 0; g
< gfti
->count
; g
++) {
1654 const struct lsa_ForestTrustRecord
*gftr
= gfti
->entries
[gfti
->count
- (g
+1)];
1655 struct lsa_ForestTrustRecord tftr
;
1663 switch (gftr
->type
) {
1664 case LSA_FOREST_TRUST_TOP_LEVEL_NAME
:
1665 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX
:
1669 case LSA_FOREST_TRUST_DOMAIN_INFO
:
1674 return NT_STATUS_INVALID_PARAMETER
;
1681 /* make a copy in order to update the time. */
1683 if (tftr
.time
== 0) {
1687 status
= dsdb_trust_forest_info_add_record(nfti
, &tftr
);
1688 if (!NT_STATUS_IS_OK(status
)) {
1694 *_nfti
= talloc_move(mem_ctx
, &nfti
);
1696 return NT_STATUS_OK
;
1699 static NTSTATUS
dsdb_trust_add_collision(
1700 struct lsa_ForestTrustCollisionInfo
*c_info
,
1701 enum lsa_ForestTrustCollisionRecordType type
,
1702 uint32_t idx
, uint32_t flags
,
1703 const char *tdo_name
)
1705 struct lsa_ForestTrustCollisionRecord
**es
;
1706 uint32_t i
= c_info
->count
;
1708 es
= talloc_realloc(c_info
, c_info
->entries
,
1709 struct lsa_ForestTrustCollisionRecord
*, i
+ 1);
1711 return NT_STATUS_NO_MEMORY
;
1713 c_info
->entries
= es
;
1714 c_info
->count
= i
+ 1;
1716 es
[i
] = talloc_zero(es
, struct lsa_ForestTrustCollisionRecord
);
1717 if (es
[i
] == NULL
) {
1718 return NT_STATUS_NO_MEMORY
;
1723 es
[i
]->flags
= flags
;
1724 es
[i
]->name
.string
= talloc_strdup(es
[i
], tdo_name
);
1725 if (es
[i
]->name
.string
== NULL
) {
1726 return NT_STATUS_NO_MEMORY
;
1729 return NT_STATUS_OK
;
1732 NTSTATUS
dsdb_trust_verify_forest_info(const struct lsa_TrustDomainInfoInfoEx
*ref_tdo
,
1733 const struct lsa_ForestTrustInformation
*ref_fti
,
1734 enum lsa_ForestTrustCollisionRecordType collision_type
,
1735 struct lsa_ForestTrustCollisionInfo
*c_info
,
1736 struct lsa_ForestTrustInformation
*new_fti
)
1740 for (n
= 0; n
< new_fti
->count
; n
++) {
1741 struct lsa_ForestTrustRecord
*nftr
= new_fti
->entries
[n
];
1742 struct lsa_StringLarge
*ntln
= NULL
;
1743 bool ntln_excluded
= false;
1752 if (nftr
->type
!= LSA_FOREST_TRUST_TOP_LEVEL_NAME
) {
1756 ntln
= &nftr
->forest_trust_data
.top_level_name
;
1757 if (ntln
->string
== NULL
) {
1758 return NT_STATUS_INVALID_PARAMETER
;
1761 ntln_excluded
= dsdb_trust_find_tln_ex_match(ref_fti
,
1764 /* check if this is already taken and not excluded */
1765 for (r
= 0; r
< ref_fti
->count
; r
++) {
1766 const struct lsa_ForestTrustRecord
*rftr
=
1767 ref_fti
->entries
[r
];
1768 const struct lsa_StringLarge
*rtln
= NULL
;
1775 if (rftr
->type
!= LSA_FOREST_TRUST_TOP_LEVEL_NAME
) {
1779 rtln
= &rftr
->forest_trust_data
.top_level_name
;
1780 if (rtln
->string
== NULL
) {
1784 cmp
= dns_cmp(ntln
->string
, rtln
->string
);
1785 if (DNS_CMP_IS_NO_MATCH(cmp
)) {
1788 if (cmp
== DNS_CMP_MATCH
) {
1789 /* We need to normalize the string */
1790 ntln
->string
= talloc_strdup(nftr
,
1792 if (ntln
->string
== NULL
) {
1793 return NT_STATUS_NO_MEMORY
;
1797 if (ntln_excluded
) {
1801 if (rftr
->flags
& LSA_TLN_DISABLED_MASK
) {
1805 if (nftr
->flags
& LSA_TLN_DISABLED_MASK
) {
1809 if (cmp
== DNS_CMP_SECOND_IS_CHILD
) {
1813 * If the conflicting tln is a child, check if
1814 * we have an exclusion record for it.
1816 m
= dsdb_trust_find_tln_ex_match(new_fti
,
1823 flags
|= LSA_TLN_DISABLED_CONFLICT
;
1830 nftr
->flags
|= flags
;
1832 status
= dsdb_trust_add_collision(c_info
,
1835 ref_tdo
->domain_name
.string
);
1836 if (!NT_STATUS_IS_OK(status
)) {
1841 for (n
= 0; n
< new_fti
->count
; n
++) {
1842 struct lsa_ForestTrustRecord
*nftr
= new_fti
->entries
[n
];
1843 struct lsa_ForestTrustDomainInfo
*ninfo
= NULL
;
1844 struct lsa_StringLarge
*ntln
= NULL
;
1845 struct lsa_StringLarge
*nnb
= NULL
;
1846 struct dom_sid
*nsid
= NULL
;
1847 bool ntln_found
= false;
1856 if (nftr
->type
!= LSA_FOREST_TRUST_DOMAIN_INFO
) {
1860 ninfo
= &nftr
->forest_trust_data
.domain_info
;
1861 ntln
= &ninfo
->dns_domain_name
;
1862 if (ntln
->string
== NULL
) {
1863 return NT_STATUS_INVALID_PARAMETER
;
1865 nnb
= &ninfo
->netbios_domain_name
;
1866 if (nnb
->string
== NULL
) {
1867 return NT_STATUS_INVALID_PARAMETER
;
1869 nsid
= ninfo
->domain_sid
;
1871 return NT_STATUS_INVALID_PARAMETER
;
1874 ntln_found
= dsdb_trust_find_tln_match(ref_fti
, ntln
->string
);
1876 /* check if this is already taken and not excluded */
1877 for (r
= 0; r
< ref_fti
->count
; r
++) {
1878 const struct lsa_ForestTrustRecord
*rftr
=
1879 ref_fti
->entries
[r
];
1880 const struct lsa_ForestTrustDomainInfo
*rinfo
= NULL
;
1881 const struct lsa_StringLarge
*rtln
= NULL
;
1882 const struct lsa_StringLarge
*rnb
= NULL
;
1883 const struct dom_sid
*rsid
= NULL
;
1884 bool nb_possible
= true;
1885 bool sid_possible
= true;
1894 * If the dns name doesn't match any existing
1895 * tln any conflict is ignored, but name
1896 * normalization still happens.
1898 * I guess that's a bug in Windows
1899 * (tested with Windows 2012r2).
1901 nb_possible
= false;
1902 sid_possible
= false;
1905 if (nftr
->flags
& LSA_SID_DISABLED_MASK
) {
1906 sid_possible
= false;
1909 if (nftr
->flags
& LSA_NB_DISABLED_MASK
) {
1910 nb_possible
= false;
1913 switch (rftr
->type
) {
1914 case LSA_FOREST_TRUST_TOP_LEVEL_NAME
:
1915 rtln
= &rftr
->forest_trust_data
.top_level_name
;
1916 nb_possible
= false;
1917 sid_possible
= false;
1920 case LSA_FOREST_TRUST_DOMAIN_INFO
:
1921 rinfo
= &rftr
->forest_trust_data
.domain_info
;
1922 rtln
= &rinfo
->dns_domain_name
;
1923 rnb
= &rinfo
->netbios_domain_name
;
1924 rsid
= rinfo
->domain_sid
;
1926 if (rftr
->flags
& LSA_SID_DISABLED_MASK
) {
1927 sid_possible
= false;
1930 if (rftr
->flags
& LSA_NB_DISABLED_MASK
) {
1931 nb_possible
= false;
1943 if (rtln
->string
== NULL
) {
1947 cmp
= dns_cmp(ntln
->string
, rtln
->string
);
1948 if (DNS_CMP_IS_NO_MATCH(cmp
)) {
1949 nb_possible
= false;
1950 sid_possible
= false;
1952 if (cmp
== DNS_CMP_MATCH
) {
1953 /* We need to normalize the string */
1954 ntln
->string
= talloc_strdup(nftr
,
1956 if (ntln
->string
== NULL
) {
1957 return NT_STATUS_NO_MEMORY
;
1961 if (rinfo
== NULL
) {
1966 cmp
= dom_sid_compare(nsid
, rsid
);
1972 flags
|= LSA_SID_DISABLED_CONFLICT
;
1976 if (rnb
->string
!= NULL
) {
1977 cmp
= strcasecmp_m(nnb
->string
, rnb
->string
);
1982 nnb
->string
= talloc_strdup(nftr
, rnb
->string
);
1983 if (nnb
->string
== NULL
) {
1984 return NT_STATUS_NO_MEMORY
;
1987 flags
|= LSA_NB_DISABLED_CONFLICT
;
1996 nftr
->flags
|= flags
;
1998 status
= dsdb_trust_add_collision(c_info
,
2001 ref_tdo
->domain_name
.string
);
2002 if (!NT_STATUS_IS_OK(status
)) {
2007 return NT_STATUS_OK
;
2010 NTSTATUS
dsdb_trust_merge_forest_info(TALLOC_CTX
*mem_ctx
,
2011 const struct lsa_TrustDomainInfoInfoEx
*tdo
,
2012 const struct lsa_ForestTrustInformation
*ofti
,
2013 const struct lsa_ForestTrustInformation
*nfti
,
2014 struct lsa_ForestTrustInformation
**_mfti
)
2016 TALLOC_CTX
*frame
= talloc_stackframe();
2017 struct lsa_ForestTrustInformation
*mfti
= NULL
;
2024 mfti
= talloc_zero(mem_ctx
, struct lsa_ForestTrustInformation
);
2027 return NT_STATUS_NO_MEMORY
;
2029 talloc_steal(frame
, mfti
);
2032 * First we add all top unique level names.
2034 * The one matching the tdo dns name, will be
2035 * added without further checking. All others
2036 * may keep the flags and time values.
2038 for (ni
= 0; ni
< nfti
->count
; ni
++) {
2039 const struct lsa_ForestTrustRecord
*nftr
= nfti
->entries
[ni
];
2040 struct lsa_ForestTrustRecord tftr
= {};
2041 const char *ndns
= NULL
;
2042 bool ignore_new
= false;
2043 bool found_old
= false;
2048 return NT_STATUS_INVALID_PARAMETER
;
2051 if (nftr
->type
!= LSA_FOREST_TRUST_TOP_LEVEL_NAME
) {
2055 ndns
= nftr
->forest_trust_data
.top_level_name
.string
;
2058 return NT_STATUS_INVALID_PARAMETER
;
2061 cmp
= dns_cmp(tdo
->domain_name
.string
, ndns
);
2062 if (cmp
== DNS_CMP_MATCH
) {
2063 status
= dsdb_trust_forest_info_add_record(mfti
, nftr
);
2064 if (!NT_STATUS_IS_OK(status
)) {
2070 for (mi
= 0; mi
< mfti
->count
; mi
++) {
2071 const struct lsa_ForestTrustRecord
*mftr
=
2073 const char *mdns
= NULL
;
2076 * we just added this above, so we're sure to have a
2077 * valid LSA_FOREST_TRUST_TOP_LEVEL_NAME record
2079 mdns
= mftr
->forest_trust_data
.top_level_name
.string
;
2081 cmp
= dns_cmp(mdns
, ndns
);
2084 case DNS_CMP_SECOND_IS_CHILD
:
2099 * make a temporary copy where we can change time and flags
2103 for (oi
= 0; oi
< ofti
->count
; oi
++) {
2104 const struct lsa_ForestTrustRecord
*oftr
=
2106 const char *odns
= NULL
;
2110 * broken record => ignore...
2115 if (oftr
->type
!= LSA_FOREST_TRUST_TOP_LEVEL_NAME
) {
2119 odns
= oftr
->forest_trust_data
.top_level_name
.string
;
2122 * broken record => ignore...
2127 cmp
= dns_cmp(odns
, ndns
);
2128 if (cmp
!= DNS_CMP_MATCH
) {
2133 tftr
.flags
= oftr
->flags
;
2134 tftr
.time
= oftr
->time
;
2138 tftr
.flags
= LSA_TLN_DISABLED_NEW
;
2142 status
= dsdb_trust_forest_info_add_record(mfti
, &tftr
);
2143 if (!NT_STATUS_IS_OK(status
)) {
2150 * Now we add all unique (based on their SID) domains
2151 * and may keep the flags and time values.
2153 for (ni
= 0; ni
< nfti
->count
; ni
++) {
2154 const struct lsa_ForestTrustRecord
*nftr
= nfti
->entries
[ni
];
2155 struct lsa_ForestTrustRecord tftr
= {};
2156 const struct lsa_ForestTrustDomainInfo
*nd
= NULL
;
2157 const char *ndns
= NULL
;
2158 const char *nnbt
= NULL
;
2159 bool ignore_new
= false;
2160 bool found_old
= false;
2165 return NT_STATUS_INVALID_PARAMETER
;
2168 if (nftr
->type
!= LSA_FOREST_TRUST_DOMAIN_INFO
) {
2172 nd
= &nftr
->forest_trust_data
.domain_info
;
2173 if (nd
->domain_sid
== NULL
) {
2175 return NT_STATUS_INVALID_PARAMETER
;
2177 ndns
= nd
->dns_domain_name
.string
;
2180 return NT_STATUS_INVALID_PARAMETER
;
2182 nnbt
= nd
->netbios_domain_name
.string
;
2185 return NT_STATUS_INVALID_PARAMETER
;
2188 for (mi
= 0; mi
< mfti
->count
; mi
++) {
2189 const struct lsa_ForestTrustRecord
*mftr
=
2191 const struct lsa_ForestTrustDomainInfo
*md
= NULL
;
2193 if (mftr
->type
!= LSA_FOREST_TRUST_DOMAIN_INFO
) {
2198 * we just added this above, so we're sure to have a
2199 * valid LSA_FOREST_TRUST_DOMAIN_INFO record
2201 md
= &mftr
->forest_trust_data
.domain_info
;
2203 cmp
= dom_sid_compare(nd
->domain_sid
, md
->domain_sid
);
2215 * make a temporary copy where we can change time and flags
2219 for (oi
= 0; oi
< ofti
->count
; oi
++) {
2220 const struct lsa_ForestTrustRecord
*oftr
=
2222 const struct lsa_ForestTrustDomainInfo
*od
= NULL
;
2223 const char *onbt
= NULL
;
2227 * broken record => ignore...
2232 if (oftr
->type
!= LSA_FOREST_TRUST_DOMAIN_INFO
) {
2236 od
= &oftr
->forest_trust_data
.domain_info
;
2237 onbt
= od
->netbios_domain_name
.string
;
2240 * broken record => ignore...
2245 cmp
= strcasecmp(onbt
, nnbt
);
2251 tftr
.flags
= oftr
->flags
;
2252 tftr
.time
= oftr
->time
;
2260 status
= dsdb_trust_forest_info_add_record(mfti
, &tftr
);
2261 if (!NT_STATUS_IS_OK(status
)) {
2268 * We keep old domain records disabled by the admin
2269 * if not already in the list.
2271 for (oi
= 0; oi
< ofti
->count
; oi
++) {
2272 const struct lsa_ForestTrustRecord
*oftr
=
2274 const struct lsa_ForestTrustDomainInfo
*od
= NULL
;
2275 const char *odns
= NULL
;
2276 const char *onbt
= NULL
;
2277 bool ignore_old
= true;
2282 * broken record => ignore...
2287 if (oftr
->type
!= LSA_FOREST_TRUST_DOMAIN_INFO
) {
2291 od
= &oftr
->forest_trust_data
.domain_info
;
2292 odns
= od
->dns_domain_name
.string
;
2295 * broken record => ignore...
2299 onbt
= od
->netbios_domain_name
.string
;
2302 * broken record => ignore...
2306 if (od
->domain_sid
== NULL
) {
2308 * broken record => ignore...
2313 if (oftr
->flags
& LSA_NB_DISABLED_ADMIN
) {
2315 } else if (oftr
->flags
& LSA_SID_DISABLED_ADMIN
) {
2319 for (mi
= 0; mi
< mfti
->count
; mi
++) {
2320 const struct lsa_ForestTrustRecord
*mftr
=
2322 const struct lsa_ForestTrustDomainInfo
*md
= NULL
;
2324 if (mftr
->type
!= LSA_FOREST_TRUST_DOMAIN_INFO
) {
2329 * we just added this above, so we're sure to have a
2330 * valid LSA_FOREST_TRUST_DOMAIN_INFO record
2332 md
= &mftr
->forest_trust_data
.domain_info
;
2334 cmp
= dom_sid_compare(od
->domain_sid
, md
->domain_sid
);
2345 status
= dsdb_trust_forest_info_add_record(mfti
, oftr
);
2346 if (!NT_STATUS_IS_OK(status
)) {
2353 * Finally we readd top level exclusions,
2354 * if they still match a top level name.
2356 for (oi
= 0; oi
< ofti
->count
; oi
++) {
2357 const struct lsa_ForestTrustRecord
*oftr
=
2359 const char *odns
= NULL
;
2360 bool ignore_old
= false;
2365 * broken record => ignore...
2370 if (oftr
->type
!= LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX
) {
2374 odns
= oftr
->forest_trust_data
.top_level_name_ex
.string
;
2377 * broken record => ignore...
2382 for (mi
= 0; mi
< mfti
->count
; mi
++) {
2383 const struct lsa_ForestTrustRecord
*mftr
=
2385 const char *mdns
= NULL
;
2387 if (mftr
->type
!= LSA_FOREST_TRUST_TOP_LEVEL_NAME
) {
2392 * we just added this above, so we're sure to have a
2393 * valid LSA_FOREST_TRUST_TOP_LEVEL_NAME.
2395 mdns
= mftr
->forest_trust_data
.top_level_name
.string
;
2397 cmp
= dns_cmp(mdns
, odns
);
2400 case DNS_CMP_SECOND_IS_CHILD
:
2416 status
= dsdb_trust_forest_info_add_record(mfti
, oftr
);
2417 if (!NT_STATUS_IS_OK(status
)) {
2423 *_mfti
= talloc_move(mem_ctx
, &mfti
);
2425 return NT_STATUS_OK
;
2428 NTSTATUS
dsdb_trust_search_tdo(struct ldb_context
*sam_ctx
,
2429 const char *netbios
, const char *dns
,
2430 const char * const *attrs
,
2431 TALLOC_CTX
*mem_ctx
,
2432 struct ldb_message
**msg
)
2434 TALLOC_CTX
*frame
= talloc_stackframe();
2436 struct ldb_dn
*system_dn
= NULL
;
2437 char *netbios_encoded
= NULL
;
2438 char *dns_encoded
= NULL
;
2439 char *filter
= NULL
;
2443 if (netbios
== NULL
&& dns
== NULL
) {
2445 return NT_STATUS_INVALID_PARAMETER_MIX
;
2448 system_dn
= ldb_dn_copy(frame
, ldb_get_default_basedn(sam_ctx
));
2449 if (system_dn
== NULL
) {
2451 return NT_STATUS_NO_MEMORY
;
2454 if (!ldb_dn_add_child_fmt(system_dn
, "CN=System")) {
2456 return NT_STATUS_NO_MEMORY
;
2459 if (netbios
!= NULL
) {
2460 netbios_encoded
= ldb_binary_encode_string(frame
, netbios
);
2461 if (netbios_encoded
== NULL
) {
2463 return NT_STATUS_NO_MEMORY
;
2468 dns_encoded
= ldb_binary_encode_string(frame
, dns
);
2469 if (dns_encoded
== NULL
) {
2471 return NT_STATUS_NO_MEMORY
;
2475 if (netbios
!= NULL
&& dns
!= NULL
) {
2476 filter
= talloc_asprintf(frame
,
2477 "(&(objectClass=trustedDomain)"
2478 "(|(trustPartner=%s)(flatName=%s))"
2480 dns_encoded
, netbios_encoded
);
2481 if (filter
== NULL
) {
2483 return NT_STATUS_NO_MEMORY
;
2485 } else if (netbios
!= NULL
) {
2486 filter
= talloc_asprintf(frame
,
2487 "(&(objectClass=trustedDomain)(flatName=%s))",
2489 if (filter
== NULL
) {
2491 return NT_STATUS_NO_MEMORY
;
2493 } else if (dns
!= NULL
) {
2494 filter
= talloc_asprintf(frame
,
2495 "(&(objectClass=trustedDomain)(trustPartner=%s))",
2497 if (filter
== NULL
) {
2499 return NT_STATUS_NO_MEMORY
;
2503 ret
= dsdb_search_one(sam_ctx
, mem_ctx
, msg
,
2505 LDB_SCOPE_ONELEVEL
, attrs
,
2506 DSDB_SEARCH_NO_GLOBAL_CATALOG
,
2508 if (ret
!= LDB_SUCCESS
) {
2509 NTSTATUS status
= dsdb_ldb_err_to_ntstatus(ret
);
2510 DEBUG(3, ("Failed to search for %s: %s - %s\n",
2511 filter
, nt_errstr(status
), ldb_errstring(sam_ctx
)));
2517 return NT_STATUS_OK
;
2520 NTSTATUS
dsdb_trust_search_tdo_by_type(struct ldb_context
*sam_ctx
,
2521 enum netr_SchannelType type
,
2523 const char * const *attrs
,
2524 TALLOC_CTX
*mem_ctx
,
2525 struct ldb_message
**msg
)
2527 TALLOC_CTX
*frame
= talloc_stackframe();
2531 bool require_trailer
= true;
2532 char *encoded_name
= NULL
;
2533 const char *netbios
= NULL
;
2534 const char *dns
= NULL
;
2536 if (type
!= SEC_CHAN_DOMAIN
&& type
!= SEC_CHAN_DNS_DOMAIN
) {
2538 return NT_STATUS_INVALID_PARAMETER
;
2541 if (type
== SEC_CHAN_DNS_DOMAIN
) {
2543 require_trailer
= false;
2546 encoded_name
= ldb_binary_encode_string(frame
, name
);
2547 if (encoded_name
== NULL
) {
2549 return NT_STATUS_NO_MEMORY
;
2552 len
= strlen(encoded_name
);
2555 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
2558 if (require_trailer
&& encoded_name
[len
- 1] != trailer
) {
2560 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
2562 encoded_name
[len
- 1] = '\0';
2564 if (type
== SEC_CHAN_DNS_DOMAIN
) {
2567 netbios
= encoded_name
;
2570 status
= dsdb_trust_search_tdo(sam_ctx
, netbios
, dns
,
2571 attrs
, mem_ctx
, msg
);
2572 if (!NT_STATUS_IS_OK(status
)) {
2578 return NT_STATUS_OK
;
2581 NTSTATUS
dsdb_trust_search_tdo_by_sid(struct ldb_context
*sam_ctx
,
2582 const struct dom_sid
*sid
,
2583 const char * const *attrs
,
2584 TALLOC_CTX
*mem_ctx
,
2585 struct ldb_message
**msg
)
2587 TALLOC_CTX
*frame
= talloc_stackframe();
2589 struct ldb_dn
*system_dn
= NULL
;
2590 char *encoded_sid
= NULL
;
2591 char *filter
= NULL
;
2597 return NT_STATUS_INVALID_PARAMETER_MIX
;
2600 encoded_sid
= ldap_encode_ndr_dom_sid(frame
, sid
);
2601 if (encoded_sid
== NULL
) {
2603 return NT_STATUS_NO_MEMORY
;
2606 system_dn
= ldb_dn_copy(frame
, ldb_get_default_basedn(sam_ctx
));
2607 if (system_dn
== NULL
) {
2609 return NT_STATUS_NO_MEMORY
;
2612 if (!ldb_dn_add_child_fmt(system_dn
, "CN=System")) {
2614 return NT_STATUS_NO_MEMORY
;
2617 filter
= talloc_asprintf(frame
,
2619 "(objectClass=trustedDomain)"
2620 "(securityIdentifier=%s)"
2623 if (filter
== NULL
) {
2625 return NT_STATUS_NO_MEMORY
;
2628 ret
= dsdb_search_one(sam_ctx
, mem_ctx
, msg
,
2630 LDB_SCOPE_ONELEVEL
, attrs
,
2631 DSDB_SEARCH_NO_GLOBAL_CATALOG
,
2633 if (ret
!= LDB_SUCCESS
) {
2634 NTSTATUS status
= dsdb_ldb_err_to_ntstatus(ret
);
2635 DEBUG(3, ("Failed to search for %s: %s - %s\n",
2636 filter
, nt_errstr(status
), ldb_errstring(sam_ctx
)));
2642 return NT_STATUS_OK
;
2645 NTSTATUS
dsdb_trust_get_incoming_passwords(struct ldb_message
*msg
,
2646 TALLOC_CTX
*mem_ctx
,
2647 struct samr_Password
**_current
,
2648 struct samr_Password
**_previous
)
2650 TALLOC_CTX
*frame
= talloc_stackframe();
2651 struct samr_Password __current
= {};
2652 struct samr_Password __previous
= {};
2653 struct samr_Password
*current
= NULL
;
2654 struct samr_Password
*previous
= NULL
;
2655 const struct ldb_val
*blob
= NULL
;
2656 enum ndr_err_code ndr_err
;
2657 struct trustAuthInOutBlob incoming
= {};
2660 if (_current
!= NULL
) {
2663 if (_previous
!= NULL
) {
2667 blob
= ldb_msg_find_ldb_val(msg
, "trustAuthIncoming");
2670 return NT_STATUS_ACCOUNT_DISABLED
;
2673 /* ldb_val is equivalent to DATA_BLOB */
2674 ndr_err
= ndr_pull_struct_blob_all(blob
, frame
, &incoming
,
2675 (ndr_pull_flags_fn_t
)ndr_pull_trustAuthInOutBlob
);
2676 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
2678 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2681 for (i
= 0; i
< incoming
.current
.count
; i
++) {
2682 struct AuthenticationInformation
*a
=
2683 &incoming
.current
.array
[i
];
2685 if (current
!= NULL
) {
2689 switch (a
->AuthType
) {
2690 case TRUST_AUTH_TYPE_NONE
:
2691 case TRUST_AUTH_TYPE_VERSION
:
2693 case TRUST_AUTH_TYPE_NT4OWF
:
2694 current
= &a
->AuthInfo
.nt4owf
.password
;
2696 case TRUST_AUTH_TYPE_CLEAR
:
2697 mdfour(__current
.hash
,
2698 a
->AuthInfo
.clear
.password
,
2699 a
->AuthInfo
.clear
.size
);
2700 current
= &__current
;
2705 if (current
== NULL
) {
2707 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2710 for (i
= 0; i
< incoming
.previous
.count
; i
++) {
2711 struct AuthenticationInformation
*a
=
2712 &incoming
.previous
.array
[i
];
2714 if (previous
!= NULL
) {
2718 switch (a
->AuthType
) {
2719 case TRUST_AUTH_TYPE_NONE
:
2720 case TRUST_AUTH_TYPE_VERSION
:
2722 case TRUST_AUTH_TYPE_NT4OWF
:
2723 previous
= &a
->AuthInfo
.nt4owf
.password
;
2725 case TRUST_AUTH_TYPE_CLEAR
:
2726 mdfour(__previous
.hash
,
2727 a
->AuthInfo
.clear
.password
,
2728 a
->AuthInfo
.clear
.size
);
2729 previous
= &__previous
;
2734 if (previous
== NULL
) {
2738 if (_current
!= NULL
) {
2739 *_current
= talloc(mem_ctx
, struct samr_Password
);
2740 if (*_current
== NULL
) {
2742 return NT_STATUS_NO_MEMORY
;
2744 **_current
= *current
;
2746 if (_previous
!= NULL
) {
2747 *_previous
= talloc(mem_ctx
, struct samr_Password
);
2748 if (*_previous
== NULL
) {
2749 if (_current
!= NULL
) {
2750 TALLOC_FREE(*_current
);
2753 return NT_STATUS_NO_MEMORY
;
2755 **_previous
= *previous
;
2757 ZERO_STRUCTP(current
);
2758 ZERO_STRUCTP(previous
);
2760 return NT_STATUS_OK
;
2763 NTSTATUS
dsdb_trust_search_tdos(struct ldb_context
*sam_ctx
,
2764 const char *exclude
,
2765 const char * const *attrs
,
2766 TALLOC_CTX
*mem_ctx
,
2767 struct ldb_result
**res
)
2769 TALLOC_CTX
*frame
= talloc_stackframe();
2771 struct ldb_dn
*system_dn
= NULL
;
2772 const char *filter
= NULL
;
2773 char *exclude_encoded
= NULL
;
2777 system_dn
= ldb_dn_copy(frame
, ldb_get_default_basedn(sam_ctx
));
2778 if (system_dn
== NULL
) {
2780 return NT_STATUS_NO_MEMORY
;
2783 if (!ldb_dn_add_child_fmt(system_dn
, "CN=System")) {
2785 return NT_STATUS_NO_MEMORY
;
2788 if (exclude
!= NULL
) {
2789 exclude_encoded
= ldb_binary_encode_string(frame
, exclude
);
2790 if (exclude_encoded
== NULL
) {
2792 return NT_STATUS_NO_MEMORY
;
2795 filter
= talloc_asprintf(frame
,
2796 "(&(objectClass=trustedDomain)"
2797 "(!(|(trustPartner=%s)(flatName=%s)))"
2799 exclude_encoded
, exclude_encoded
);
2800 if (filter
== NULL
) {
2802 return NT_STATUS_NO_MEMORY
;
2805 filter
= "(objectClass=trustedDomain)";
2808 ret
= dsdb_search(sam_ctx
, mem_ctx
, res
,
2810 LDB_SCOPE_ONELEVEL
, attrs
,
2811 DSDB_SEARCH_NO_GLOBAL_CATALOG
,
2813 if (ret
!= LDB_SUCCESS
) {
2814 NTSTATUS status
= dsdb_ldb_err_to_ntstatus(ret
);
2815 DEBUG(3, ("Failed to search for %s: %s - %s\n",
2816 filter
, nt_errstr(status
), ldb_errstring(sam_ctx
)));
2822 return NT_STATUS_OK
;
2825 struct dsdb_trust_routing_domain
;
2827 struct dsdb_trust_routing_table
{
2828 struct dsdb_trust_routing_domain
*domains
;
2831 struct dsdb_trust_routing_domain
{
2832 struct dsdb_trust_routing_domain
*prev
, *next
;
2834 struct lsa_TrustDomainInfoInfoEx
*tdo
;
2836 struct lsa_ForestTrustDomainInfo di
;
2838 struct lsa_ForestTrustInformation
*fti
;
2841 NTSTATUS
dsdb_trust_routing_table_load(struct ldb_context
*sam_ctx
,
2842 TALLOC_CTX
*mem_ctx
,
2843 struct dsdb_trust_routing_table
**_table
)
2845 TALLOC_CTX
*frame
= talloc_stackframe();
2846 struct dsdb_trust_routing_table
*table
;
2847 struct dsdb_trust_routing_domain
*d
= NULL
;
2848 struct ldb_dn
*domain_dn
= NULL
;
2849 struct lsa_TrustDomainInfoInfoEx
*root_trust_tdo
= NULL
;
2850 struct lsa_TrustDomainInfoInfoEx
*trust_parent_tdo
= NULL
;
2851 struct lsa_TrustDomainInfoInfoEx
*root_direction_tdo
= NULL
;
2852 const char * const trusts_attrs
[] = {
2853 "securityIdentifier",
2859 "msDS-TrustForestTrustInfo",
2862 struct ldb_result
*trusts_res
= NULL
;
2868 domain_dn
= ldb_get_default_basedn(sam_ctx
);
2869 if (domain_dn
== NULL
) {
2871 return NT_STATUS_INTERNAL_ERROR
;
2874 table
= talloc_zero(mem_ctx
, struct dsdb_trust_routing_table
);
2875 if (table
== NULL
) {
2877 return NT_STATUS_NO_MEMORY
;
2879 talloc_steal(frame
, table
);
2881 d
= talloc_zero(table
, struct dsdb_trust_routing_domain
);
2884 return NT_STATUS_NO_MEMORY
;
2887 status
= dsdb_trust_crossref_tdo_info(d
, sam_ctx
,
2892 if (!NT_STATUS_IS_OK(status
)) {
2897 d
->di
.domain_sid
= d
->tdo
->sid
;
2898 d
->di
.netbios_domain_name
.string
= d
->tdo
->netbios_name
.string
;
2899 d
->di
.dns_domain_name
.string
= d
->tdo
->domain_name
.string
;
2901 if (root_trust_tdo
!= NULL
) {
2902 root_direction_tdo
= root_trust_tdo
;
2903 } else if (trust_parent_tdo
!= NULL
) {
2904 root_direction_tdo
= trust_parent_tdo
;
2907 if (root_direction_tdo
== NULL
) {
2908 /* we're the forest root */
2909 status
= dsdb_trust_xref_forest_info(d
, sam_ctx
, &d
->fti
);
2910 if (!NT_STATUS_IS_OK(status
)) {
2916 DLIST_ADD(table
->domains
, d
);
2918 status
= dsdb_trust_search_tdos(sam_ctx
, NULL
, trusts_attrs
,
2919 frame
, &trusts_res
);
2920 if (!NT_STATUS_IS_OK(status
)) {
2925 for (i
= 0; i
< trusts_res
->count
; i
++) {
2929 d
= talloc_zero(table
, struct dsdb_trust_routing_domain
);
2932 return NT_STATUS_NO_MEMORY
;
2935 status
= dsdb_trust_parse_tdo_info(d
,
2936 trusts_res
->msgs
[i
],
2938 if (!NT_STATUS_IS_OK(status
)) {
2943 d
->di
.domain_sid
= d
->tdo
->sid
;
2944 d
->di
.netbios_domain_name
.string
= d
->tdo
->netbios_name
.string
;
2945 d
->di
.dns_domain_name
.string
= d
->tdo
->domain_name
.string
;
2947 DLIST_ADD_END(table
->domains
, d
);
2949 if (d
->tdo
->trust_attributes
& LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
) {
2950 struct ForestTrustInfo
*fti
= NULL
;
2952 status
= dsdb_trust_parse_forest_info(frame
,
2953 trusts_res
->msgs
[i
],
2955 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2957 status
= NT_STATUS_OK
;
2959 if (!NT_STATUS_IS_OK(status
)) {
2968 status
= dsdb_trust_forest_info_to_lsa(d
, fti
, &d
->fti
);
2969 if (!NT_STATUS_IS_OK(status
)) {
2977 if (!(d
->tdo
->trust_attributes
& LSA_TRUST_ATTRIBUTE_WITHIN_FOREST
)) {
2981 if (root_direction_tdo
== NULL
) {
2985 ok
= dom_sid_equal(root_direction_tdo
->sid
, d
->tdo
->sid
);
2990 cmp
= strcasecmp_m(root_direction_tdo
->netbios_name
.string
,
2991 d
->tdo
->netbios_name
.string
);
2996 cmp
= strcasecmp_m(root_direction_tdo
->domain_name
.string
,
2997 d
->tdo
->domain_name
.string
);
3002 /* this our route to the forest root */
3003 status
= dsdb_trust_xref_forest_info(d
, sam_ctx
, &d
->fti
);
3004 if (!NT_STATUS_IS_OK(status
)) {
3010 *_table
= talloc_move(mem_ctx
, &table
);
3012 return NT_STATUS_OK
;
3015 static void dsdb_trust_update_best_tln(
3016 const struct dsdb_trust_routing_domain
**best_d
,
3017 const char **best_tln
,
3018 const struct dsdb_trust_routing_domain
*d
,
3023 if (*best_tln
== NULL
) {
3029 cmp
= dns_cmp(*best_tln
, tln
);
3030 if (cmp
!= DNS_CMP_FIRST_IS_CHILD
) {
3038 const struct lsa_TrustDomainInfoInfoEx
*dsdb_trust_routing_by_name(
3039 const struct dsdb_trust_routing_table
*table
,
3042 const struct dsdb_trust_routing_domain
*best_d
= NULL
;
3043 const char *best_tln
= NULL
;
3044 const struct dsdb_trust_routing_domain
*d
= NULL
;
3050 for (d
= table
->domains
; d
!= NULL
; d
= d
->next
) {
3051 bool transitive
= false;
3052 bool allow_netbios
= false;
3053 bool exclude
= false;
3056 if (d
->tdo
->trust_type
!= LSA_TRUST_TYPE_UPLEVEL
) {
3058 * Only uplevel trusts have top level names
3063 if (d
->tdo
->trust_attributes
& LSA_TRUST_ATTRIBUTE_WITHIN_FOREST
) {
3067 if (d
->tdo
->trust_attributes
& LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
) {
3071 if (d
->tdo
->trust_attributes
& LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE
) {
3075 if (d
->tdo
->trust_type
!= LSA_TRUST_TYPE_UPLEVEL
) {
3079 switch (d
->tdo
->trust_type
) {
3080 case LSA_TRUST_TYPE_UPLEVEL
:
3081 if (d
->tdo
->trust_attributes
& LSA_TRUST_ATTRIBUTE_UPLEVEL_ONLY
) {
3084 allow_netbios
= true;
3086 case LSA_TRUST_TYPE_DOWNLEVEL
:
3087 allow_netbios
= true;
3090 allow_netbios
= false;
3094 if (!transitive
|| d
->fti
== NULL
) {
3097 if (allow_netbios
) {
3098 cmp
= dns_cmp(name
, d
->tdo
->netbios_name
.string
);
3099 if (cmp
== DNS_CMP_MATCH
) {
3107 cmp
= dns_cmp(name
, d
->tdo
->domain_name
.string
);
3108 if (cmp
== DNS_CMP_MATCH
) {
3114 if (cmp
!= DNS_CMP_FIRST_IS_CHILD
) {
3122 dsdb_trust_update_best_tln(&best_d
, &best_tln
, d
,
3123 d
->tdo
->domain_name
.string
);
3127 exclude
= dsdb_trust_find_tln_ex_match(d
->fti
, name
);
3132 for (i
= 0; i
< d
->fti
->count
; i
++ ) {
3133 const struct lsa_ForestTrustRecord
*f
= d
->fti
->entries
[i
];
3134 const struct lsa_ForestTrustDomainInfo
*di
= NULL
;
3135 const char *fti_nbt
= NULL
;
3138 if (!allow_netbios
) {
3147 if (f
->type
!= LSA_FOREST_TRUST_DOMAIN_INFO
) {
3151 if (f
->flags
& LSA_NB_DISABLED_MASK
) {
3153 * any flag disables the entry.
3158 di
= &f
->forest_trust_data
.domain_info
;
3159 fti_nbt
= di
->netbios_domain_name
.string
;
3160 if (fti_nbt
== NULL
) {
3165 cmp
= dns_cmp(name
, fti_nbt
);
3166 if (cmp
== DNS_CMP_MATCH
) {
3174 for (i
= 0; i
< d
->fti
->count
; i
++ ) {
3175 const struct lsa_ForestTrustRecord
*f
= d
->fti
->entries
[i
];
3176 const union lsa_ForestTrustData
*u
= NULL
;
3177 const char *fti_tln
= NULL
;
3185 if (f
->type
!= LSA_FOREST_TRUST_TOP_LEVEL_NAME
) {
3189 if (f
->flags
& LSA_TLN_DISABLED_MASK
) {
3191 * any flag disables the entry.
3196 u
= &f
->forest_trust_data
;
3197 fti_tln
= u
->top_level_name
.string
;
3198 if (fti_tln
== NULL
) {
3202 cmp
= dns_cmp(name
, fti_tln
);
3205 case DNS_CMP_FIRST_IS_CHILD
:
3206 dsdb_trust_update_best_tln(&best_d
, &best_tln
,
3215 if (best_d
!= NULL
) {
3222 const struct lsa_TrustDomainInfoInfoEx
*dsdb_trust_domain_by_sid(
3223 const struct dsdb_trust_routing_table
*table
,
3224 const struct dom_sid
*sid
,
3225 const struct lsa_ForestTrustDomainInfo
**pdi
)
3227 const struct dsdb_trust_routing_domain
*d
= NULL
;
3237 for (d
= table
->domains
; d
!= NULL
; d
= d
->next
) {
3238 bool transitive
= false;
3241 if (d
->tdo
->trust_attributes
& LSA_TRUST_ATTRIBUTE_WITHIN_FOREST
) {
3245 if (d
->tdo
->trust_attributes
& LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
) {
3249 if (d
->tdo
->trust_attributes
& LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE
) {
3253 if (d
->tdo
->trust_type
!= LSA_TRUST_TYPE_UPLEVEL
) {
3257 if (!transitive
|| d
->fti
== NULL
) {
3260 match
= dom_sid_equal(d
->di
.domain_sid
, sid
);
3263 * exact match, it's the domain itself.
3273 for (i
= 0; i
< d
->fti
->count
; i
++ ) {
3274 const struct lsa_ForestTrustRecord
*f
= d
->fti
->entries
[i
];
3275 const struct lsa_ForestTrustDomainInfo
*di
= NULL
;
3276 const struct dom_sid
*fti_sid
= NULL
;
3284 if (f
->type
!= LSA_FOREST_TRUST_DOMAIN_INFO
) {
3288 if (f
->flags
& LSA_SID_DISABLED_MASK
) {
3290 * any flag disables the entry.
3295 di
= &f
->forest_trust_data
.domain_info
;
3296 fti_sid
= di
->domain_sid
;
3297 if (fti_sid
== NULL
) {
3302 match
= dom_sid_equal(fti_sid
, sid
);
3305 * exact match, it's a domain in the forest.
3318 const struct lsa_TrustDomainInfoInfoEx
*dsdb_trust_domain_by_name(
3319 const struct dsdb_trust_routing_table
*table
,
3321 const struct lsa_ForestTrustDomainInfo
**pdi
)
3323 const struct dsdb_trust_routing_domain
*d
= NULL
;
3333 for (d
= table
->domains
; d
!= NULL
; d
= d
->next
) {
3334 bool transitive
= false;
3337 if (d
->tdo
->trust_attributes
& LSA_TRUST_ATTRIBUTE_WITHIN_FOREST
) {
3341 if (d
->tdo
->trust_attributes
& LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
) {
3345 if (d
->tdo
->trust_attributes
& LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE
) {
3349 if (d
->tdo
->trust_type
!= LSA_TRUST_TYPE_UPLEVEL
) {
3353 if (!transitive
|| d
->fti
== NULL
) {
3356 match
= strequal_m(d
->di
.netbios_domain_name
.string
,
3360 * exact match for netbios name,
3361 * it's the domain itself.
3368 match
= strequal_m(d
->di
.dns_domain_name
.string
,
3372 * exact match for dns name,
3373 * it's the domain itself.
3383 for (i
= 0; i
< d
->fti
->count
; i
++ ) {
3384 const struct lsa_ForestTrustRecord
*f
= d
->fti
->entries
[i
];
3385 const struct lsa_ForestTrustDomainInfo
*di
= NULL
;
3393 if (f
->type
!= LSA_FOREST_TRUST_DOMAIN_INFO
) {
3396 di
= &f
->forest_trust_data
.domain_info
;
3398 if (!(f
->flags
& LSA_NB_DISABLED_MASK
)) {
3399 match
= strequal_m(di
->netbios_domain_name
.string
,
3403 * exact match for netbios name,
3404 * it's a domain in the forest.
3413 if (!(f
->flags
& LSA_TLN_DISABLED_MASK
)) {
3414 match
= strequal_m(di
->dns_domain_name
.string
,
3418 * exact match for dns name,
3419 * it's a domain in the forest.