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"
37 NTSTATUS
dsdb_trust_forest_info_from_lsa(TALLOC_CTX
*mem_ctx
,
38 const struct lsa_ForestTrustInformation
*lfti
,
39 struct ForestTrustInfo
**_fti
)
41 struct ForestTrustInfo
*fti
;
46 fti
= talloc_zero(mem_ctx
, struct ForestTrustInfo
);
48 return NT_STATUS_NO_MEMORY
;
52 fti
->count
= lfti
->count
;
53 fti
->records
= talloc_zero_array(mem_ctx
,
54 struct ForestTrustInfoRecordArmor
,
56 if (fti
->records
== NULL
) {
58 return NT_STATUS_NO_MEMORY
;
61 for (i
= 0; i
< fti
->count
; i
++) {
62 const struct lsa_ForestTrustRecord
*lftr
= lfti
->entries
[i
];
63 struct ForestTrustInfoRecord
*ftr
= &fti
->records
[i
].record
;
64 struct ForestTrustString
*str
= NULL
;
65 const struct lsa_StringLarge
*lstr
= NULL
;
66 const struct lsa_ForestTrustDomainInfo
*linfo
= NULL
;
67 struct ForestTrustDataDomainInfo
*info
= NULL
;
71 return NT_STATUS_INVALID_PARAMETER
;
74 ftr
->flags
= lftr
->flags
;
75 ftr
->timestamp
= lftr
->time
;
76 ftr
->type
= lftr
->type
;
79 case LSA_FOREST_TRUST_TOP_LEVEL_NAME
:
80 lstr
= &lftr
->forest_trust_data
.top_level_name
;
81 str
= &ftr
->data
.name
;
83 str
->string
= talloc_strdup(mem_ctx
, lstr
->string
);
84 if (str
->string
== NULL
) {
86 return NT_STATUS_NO_MEMORY
;
91 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX
:
92 lstr
= &lftr
->forest_trust_data
.top_level_name_ex
;
93 str
= &ftr
->data
.name
;
95 str
->string
= talloc_strdup(mem_ctx
, lstr
->string
);
96 if (str
->string
== NULL
) {
98 return NT_STATUS_NO_MEMORY
;
103 case LSA_FOREST_TRUST_DOMAIN_INFO
:
104 linfo
= &lftr
->forest_trust_data
.domain_info
;
105 info
= &ftr
->data
.info
;
107 if (linfo
->domain_sid
== NULL
) {
109 return NT_STATUS_INVALID_PARAMETER
;
111 info
->sid
= *linfo
->domain_sid
;
113 lstr
= &linfo
->dns_domain_name
;
114 str
= &info
->dns_name
;
115 str
->string
= talloc_strdup(mem_ctx
, lstr
->string
);
116 if (str
->string
== NULL
) {
118 return NT_STATUS_NO_MEMORY
;
121 lstr
= &linfo
->netbios_domain_name
;
122 str
= &info
->netbios_name
;
123 str
->string
= talloc_strdup(mem_ctx
, lstr
->string
);
124 if (str
->string
== NULL
) {
126 return NT_STATUS_NO_MEMORY
;
132 return NT_STATUS_NOT_SUPPORTED
;
140 static NTSTATUS
dsdb_trust_forest_record_to_lsa(TALLOC_CTX
*mem_ctx
,
141 const struct ForestTrustInfoRecord
*ftr
,
142 struct lsa_ForestTrustRecord
**_lftr
)
144 struct lsa_ForestTrustRecord
*lftr
= NULL
;
145 const struct ForestTrustString
*str
= NULL
;
146 struct lsa_StringLarge
*lstr
= NULL
;
147 const struct ForestTrustDataDomainInfo
*info
= NULL
;
148 struct lsa_ForestTrustDomainInfo
*linfo
= NULL
;
152 lftr
= talloc_zero(mem_ctx
, struct lsa_ForestTrustRecord
);
154 return NT_STATUS_NO_MEMORY
;
157 lftr
->flags
= ftr
->flags
;
158 lftr
->time
= ftr
->timestamp
;
159 lftr
->type
= ftr
->type
;
161 switch (lftr
->type
) {
162 case LSA_FOREST_TRUST_TOP_LEVEL_NAME
:
163 lstr
= &lftr
->forest_trust_data
.top_level_name
;
164 str
= &ftr
->data
.name
;
166 lstr
->string
= talloc_strdup(mem_ctx
, str
->string
);
167 if (lstr
->string
== NULL
) {
169 return NT_STATUS_NO_MEMORY
;
174 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX
:
175 lstr
= &lftr
->forest_trust_data
.top_level_name_ex
;
176 str
= &ftr
->data
.name
;
178 lstr
->string
= talloc_strdup(mem_ctx
, str
->string
);
179 if (lstr
->string
== NULL
) {
181 return NT_STATUS_NO_MEMORY
;
186 case LSA_FOREST_TRUST_DOMAIN_INFO
:
187 linfo
= &lftr
->forest_trust_data
.domain_info
;
188 info
= &ftr
->data
.info
;
190 linfo
->domain_sid
= dom_sid_dup(lftr
, &info
->sid
);
191 if (linfo
->domain_sid
== NULL
) {
193 return NT_STATUS_NO_MEMORY
;
196 lstr
= &linfo
->dns_domain_name
;
197 str
= &info
->dns_name
;
198 lstr
->string
= talloc_strdup(mem_ctx
, str
->string
);
199 if (lstr
->string
== NULL
) {
201 return NT_STATUS_NO_MEMORY
;
204 lstr
= &linfo
->netbios_domain_name
;
205 str
= &info
->netbios_name
;
206 lstr
->string
= talloc_strdup(mem_ctx
, str
->string
);
207 if (lstr
->string
== NULL
) {
209 return NT_STATUS_NO_MEMORY
;
215 return NT_STATUS_NOT_SUPPORTED
;
222 NTSTATUS
dsdb_trust_forest_info_to_lsa(TALLOC_CTX
*mem_ctx
,
223 const struct ForestTrustInfo
*fti
,
224 struct lsa_ForestTrustInformation
**_lfti
)
226 struct lsa_ForestTrustInformation
*lfti
;
231 if (fti
->version
!= 1) {
232 return NT_STATUS_INVALID_PARAMETER
;
235 lfti
= talloc_zero(mem_ctx
, struct lsa_ForestTrustInformation
);
237 return NT_STATUS_NO_MEMORY
;
240 lfti
->count
= fti
->count
;
241 lfti
->entries
= talloc_zero_array(mem_ctx
,
242 struct lsa_ForestTrustRecord
*,
244 if (lfti
->entries
== NULL
) {
246 return NT_STATUS_NO_MEMORY
;
249 for (i
= 0; i
< fti
->count
; i
++) {
250 struct ForestTrustInfoRecord
*ftr
= &fti
->records
[i
].record
;
251 struct lsa_ForestTrustRecord
*lftr
= NULL
;
254 status
= dsdb_trust_forest_record_to_lsa(lfti
->entries
, ftr
,
256 if (!NT_STATUS_IS_OK(status
)) {
258 return NT_STATUS_NO_MEMORY
;
260 lfti
->entries
[i
] = lftr
;
267 static NTSTATUS
dsdb_trust_forest_info_add_record(struct lsa_ForestTrustInformation
*fti
,
268 const struct lsa_ForestTrustRecord
*ftr
)
270 struct lsa_ForestTrustRecord
**es
= NULL
;
271 struct lsa_ForestTrustRecord
*e
= NULL
;
272 const struct lsa_StringLarge
*dns1
= NULL
;
273 struct lsa_StringLarge
*dns2
= NULL
;
274 const struct lsa_ForestTrustDomainInfo
*d1
= NULL
;
275 struct lsa_ForestTrustDomainInfo
*d2
= NULL
;
278 es
= talloc_realloc(fti
, fti
->entries
,
279 struct lsa_ForestTrustRecord
*,
282 return NT_STATUS_NO_MEMORY
;
286 e
= talloc_zero(es
, struct lsa_ForestTrustRecord
);
288 return NT_STATUS_NO_MEMORY
;
292 e
->flags
= ftr
->flags
;
296 case LSA_FOREST_TRUST_TOP_LEVEL_NAME
:
297 dns1
= &ftr
->forest_trust_data
.top_level_name
;
298 dns2
= &e
->forest_trust_data
.top_level_name
;
301 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX
:
302 dns1
= &ftr
->forest_trust_data
.top_level_name_ex
;
303 dns2
= &e
->forest_trust_data
.top_level_name_ex
;
306 case LSA_FOREST_TRUST_DOMAIN_INFO
:
307 dns1
= &ftr
->forest_trust_data
.domain_info
.dns_domain_name
;
308 dns2
= &e
->forest_trust_data
.domain_info
.dns_domain_name
;
309 d1
= &ftr
->forest_trust_data
.domain_info
;
310 d2
= &e
->forest_trust_data
.domain_info
;
313 return NT_STATUS_INVALID_PARAMETER
;
316 if (dns1
->string
== NULL
) {
318 return NT_STATUS_INVALID_PARAMETER
;
321 len
= strlen(dns1
->string
);
324 return NT_STATUS_INVALID_PARAMETER
;
327 dns2
->string
= talloc_strdup(e
, dns1
->string
);
328 if (dns2
->string
== NULL
) {
330 return NT_STATUS_NO_MEMORY
;
334 const struct lsa_StringLarge
*nb1
= &d1
->netbios_domain_name
;
335 struct lsa_StringLarge
*nb2
= &d2
->netbios_domain_name
;
337 if (nb1
->string
== NULL
) {
339 return NT_STATUS_INVALID_PARAMETER
;
342 len
= strlen(nb1
->string
);
345 return NT_STATUS_INVALID_PARAMETER
;
349 return NT_STATUS_INVALID_PARAMETER
;
352 nb2
->string
= talloc_strdup(e
, nb1
->string
);
353 if (nb2
->string
== NULL
) {
355 return NT_STATUS_NO_MEMORY
;
358 if (d1
->domain_sid
== NULL
) {
360 return NT_STATUS_INVALID_PARAMETER
;
363 d2
->domain_sid
= dom_sid_dup(e
, d1
->domain_sid
);
364 if (d2
->domain_sid
== NULL
) {
366 return NT_STATUS_NO_MEMORY
;
370 fti
->entries
[fti
->count
++] = e
;
374 static NTSTATUS
dsdb_trust_parse_crossref_info(TALLOC_CTX
*mem_ctx
,
375 struct ldb_context
*sam_ctx
,
376 const struct ldb_message
*msg
,
377 struct lsa_TrustDomainInfoInfoEx
**_tdo
)
379 TALLOC_CTX
*frame
= talloc_stackframe();
380 struct lsa_TrustDomainInfoInfoEx
*tdo
= NULL
;
381 const char *dns
= NULL
;
382 const char *netbios
= NULL
;
383 struct ldb_dn
*nc_dn
= NULL
;
384 struct dom_sid sid
= {};
388 tdo
= talloc_zero(mem_ctx
, struct lsa_TrustDomainInfoInfoEx
);
391 return NT_STATUS_NO_MEMORY
;
393 talloc_steal(frame
, tdo
);
395 dns
= ldb_msg_find_attr_as_string(msg
, "dnsRoot", NULL
);
398 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
400 tdo
->domain_name
.string
= talloc_strdup(tdo
, dns
);
401 if (tdo
->domain_name
.string
== NULL
) {
403 return NT_STATUS_NO_MEMORY
;
406 netbios
= ldb_msg_find_attr_as_string(msg
, "nETBIOSName", NULL
);
407 if (netbios
== NULL
) {
409 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
411 tdo
->netbios_name
.string
= talloc_strdup(tdo
, netbios
);
412 if (tdo
->netbios_name
.string
== NULL
) {
414 return NT_STATUS_NO_MEMORY
;
417 nc_dn
= samdb_result_dn(sam_ctx
, frame
, msg
, "ncName", NULL
);
420 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
423 status
= dsdb_get_extended_dn_sid(nc_dn
, &sid
, "SID");
424 if (!NT_STATUS_IS_OK(status
)) {
428 tdo
->sid
= dom_sid_dup(tdo
, &sid
);
429 if (tdo
->sid
== NULL
) {
431 return NT_STATUS_NO_MEMORY
;
434 tdo
->trust_type
= LSA_TRUST_TYPE_UPLEVEL
;
435 tdo
->trust_direction
= LSA_TRUST_DIRECTION_INBOUND
|
436 LSA_TRUST_DIRECTION_OUTBOUND
;
437 tdo
->trust_attributes
= LSA_TRUST_ATTRIBUTE_WITHIN_FOREST
;
439 *_tdo
= talloc_move(mem_ctx
, &tdo
);
444 static NTSTATUS
dsdb_trust_crossref_tdo_info(TALLOC_CTX
*mem_ctx
,
445 struct ldb_context
*sam_ctx
,
446 struct ldb_dn
*domain_dn
,
447 const char *extra_filter
,
448 struct lsa_TrustDomainInfoInfoEx
**_tdo
,
449 struct lsa_TrustDomainInfoInfoEx
**_root_trust_tdo
,
450 struct lsa_TrustDomainInfoInfoEx
**_trust_parent_tdo
)
452 TALLOC_CTX
*frame
= talloc_stackframe();
453 struct lsa_TrustDomainInfoInfoEx
*tdo
= NULL
;
454 struct lsa_TrustDomainInfoInfoEx
*root_trust_tdo
= NULL
;
455 struct lsa_TrustDomainInfoInfoEx
*trust_parent_tdo
= NULL
;
456 struct ldb_dn
*partitions_dn
= NULL
;
457 const char * const cross_attrs
[] = {
465 struct ldb_result
*cross_res
= NULL
;
466 struct ldb_message
*msg
= NULL
;
467 struct ldb_dn
*root_trust_dn
= NULL
;
468 struct ldb_dn
*trust_parent_dn
= NULL
;
472 if (extra_filter
== NULL
) {
477 if (_root_trust_tdo
!= NULL
) {
478 *_root_trust_tdo
= NULL
;
480 if (_trust_parent_tdo
!= NULL
) {
481 *_trust_parent_tdo
= NULL
;
484 domain_dn
= ldb_get_default_basedn(sam_ctx
);
485 if (domain_dn
== NULL
) {
487 return NT_STATUS_INTERNAL_ERROR
;
490 partitions_dn
= samdb_partitions_dn(sam_ctx
, frame
);
491 if (partitions_dn
== NULL
) {
493 return NT_STATUS_NO_MEMORY
;
496 ret
= dsdb_search(sam_ctx
, partitions_dn
, &cross_res
,
497 partitions_dn
, LDB_SCOPE_ONELEVEL
,
499 DSDB_SEARCH_ONE_ONLY
|
500 DSDB_SEARCH_SHOW_EXTENDED_DN
,
503 "(objectClass=crossRef)"
504 "(systemFlags:%s:=%u)"
507 ldb_dn_get_linearized(domain_dn
),
508 LDB_OID_COMPARATOR_AND
,
509 SYSTEM_FLAG_CR_NTDS_DOMAIN
,
511 if (ret
!= LDB_SUCCESS
) {
513 return dsdb_ldb_err_to_ntstatus(ret
);
515 msg
= cross_res
->msgs
[0];
517 status
= dsdb_trust_parse_crossref_info(mem_ctx
, sam_ctx
, msg
, &tdo
);
518 if (!NT_STATUS_IS_OK(status
)) {
522 talloc_steal(frame
, tdo
);
524 if (_root_trust_tdo
!= NULL
) {
525 root_trust_dn
= samdb_result_dn(sam_ctx
, frame
, msg
,
528 if (_trust_parent_tdo
!= NULL
) {
529 trust_parent_dn
= samdb_result_dn(sam_ctx
, frame
, msg
,
530 "trustParent", NULL
);
533 if (root_trust_dn
!= NULL
) {
534 struct ldb_message
*root_trust_msg
= NULL
;
536 ret
= dsdb_search_one(sam_ctx
, frame
,
541 DSDB_SEARCH_NO_GLOBAL_CATALOG
,
542 "(objectClass=crossRef)");
543 if (ret
!= LDB_SUCCESS
) {
544 status
= dsdb_ldb_err_to_ntstatus(ret
);
545 DEBUG(3, ("Failed to search for %s: %s - %s\n",
546 ldb_dn_get_linearized(root_trust_dn
),
547 nt_errstr(status
), ldb_errstring(sam_ctx
)));
552 status
= dsdb_trust_parse_crossref_info(mem_ctx
, sam_ctx
,
555 if (!NT_STATUS_IS_OK(status
)) {
559 talloc_steal(frame
, root_trust_tdo
);
562 if (trust_parent_dn
!= NULL
) {
563 struct ldb_message
*trust_parent_msg
= NULL
;
565 ret
= dsdb_search_one(sam_ctx
, frame
,
570 DSDB_SEARCH_NO_GLOBAL_CATALOG
,
571 "(objectClass=crossRef)");
572 if (ret
!= LDB_SUCCESS
) {
573 status
= dsdb_ldb_err_to_ntstatus(ret
);
574 DEBUG(3, ("Failed to search for %s: %s - %s\n",
575 ldb_dn_get_linearized(trust_parent_dn
),
576 nt_errstr(status
), ldb_errstring(sam_ctx
)));
581 status
= dsdb_trust_parse_crossref_info(mem_ctx
, sam_ctx
,
584 if (!NT_STATUS_IS_OK(status
)) {
588 talloc_steal(frame
, trust_parent_tdo
);
591 *_tdo
= talloc_move(mem_ctx
, &tdo
);
592 if (_root_trust_tdo
!= NULL
) {
593 *_root_trust_tdo
= talloc_move(mem_ctx
, &root_trust_tdo
);
595 if (_trust_parent_tdo
!= NULL
) {
596 *_trust_parent_tdo
= talloc_move(mem_ctx
, &trust_parent_tdo
);
602 #define DNS_CMP_FIRST_IS_CHILD -2
603 #define DNS_CMP_FIRST_IS_LESS -1
604 #define DNS_CMP_MATCH 0
605 #define DNS_CMP_SECOND_IS_LESS 1
606 #define DNS_CMP_SECOND_IS_CHILD 2
608 #define DNS_CMP_IS_NO_MATCH(__cmp) \
609 ((__cmp == DNS_CMP_FIRST_IS_LESS) || (__cmp == DNS_CMP_SECOND_IS_LESS))
612 * this function assumes names are well formed DNS names.
613 * it doesn't validate them
615 * It allows strings up to a length of UINT16_MAX - 1
616 * with up to UINT8_MAX components. On overflow this
617 * just returns the result of strcasecmp_m().
619 * Trailing dots (only one) are ignored.
621 * The DNS names are compared per component, starting from
624 static int dns_cmp(const char *s1
, const char *s2
)
627 const char *p1
= NULL
;
628 size_t num_comp1
= 0;
629 uint16_t comp1
[UINT8_MAX
] = {};
631 const char *p2
= NULL
;
632 size_t num_comp2
= 0;
633 uint16_t comp2
[UINT8_MAX
] = {};
645 * trailing '.' are ignored.
647 if (l1
> 1 && s1
[l1
- 1] == '.') {
650 if (l2
> 1 && s2
[l2
- 1] == '.') {
654 for (i
= 0; i
< ARRAY_SIZE(comp1
); i
++) {
660 if (l1
== 0 && l1
>= UINT16_MAX
) {
661 /* just use one single component on overflow */
666 comp1
[num_comp1
++] = PTR_DIFF(p1
, s1
);
668 p
= strchr_m(p1
, '.');
678 /* just use one single component on overflow */
680 comp1
[num_comp1
++] = 0;
684 for (i
= 0; i
< ARRAY_SIZE(comp2
); i
++) {
690 if (l2
== 0 && l2
>= UINT16_MAX
) {
691 /* just use one single component on overflow */
696 comp2
[num_comp2
++] = PTR_DIFF(p2
, s2
);
698 p
= strchr_m(p2
, '.');
708 /* just use one single component on overflow */
710 comp2
[num_comp2
++] = 0;
714 for (i
= 0; i
< UINT8_MAX
; i
++) {
718 size_t idx
= num_comp1
- (i
+ 1);
719 p1
= s1
+ comp1
[idx
];
725 size_t idx
= num_comp2
- (i
+ 1);
726 p2
= s2
+ comp2
[idx
];
731 if (p1
== NULL
&& p2
== NULL
) {
732 return DNS_CMP_MATCH
;
734 if (p1
!= NULL
&& p2
== NULL
) {
735 return DNS_CMP_FIRST_IS_CHILD
;
737 if (p1
== NULL
&& p2
!= NULL
) {
738 return DNS_CMP_SECOND_IS_CHILD
;
741 cmp
= strcasecmp_m(p1
, p2
);
743 return DNS_CMP_FIRST_IS_LESS
;
746 return DNS_CMP_SECOND_IS_LESS
;
750 smb_panic(__location__
);
754 static int dsdb_trust_find_tln_match_internal(const struct lsa_ForestTrustInformation
*info
,
755 enum lsa_ForestTrustRecordType type
,
756 uint32_t disable_mask
,
761 for (i
= 0; i
< info
->count
; i
++) {
762 struct lsa_ForestTrustRecord
*e
= info
->entries
[i
];
763 struct lsa_StringLarge
*t
= NULL
;
770 if (e
->type
!= type
) {
774 if (e
->flags
& disable_mask
) {
779 case LSA_FOREST_TRUST_TOP_LEVEL_NAME
:
780 t
= &e
->forest_trust_data
.top_level_name
;
782 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX
:
783 t
= &e
->forest_trust_data
.top_level_name_ex
;
793 cmp
= dns_cmp(tln
, t
->string
);
796 case DNS_CMP_FIRST_IS_CHILD
:
804 static bool dsdb_trust_find_tln_match(const struct lsa_ForestTrustInformation
*info
,
809 m
= dsdb_trust_find_tln_match_internal(info
,
810 LSA_FOREST_TRUST_TOP_LEVEL_NAME
,
811 LSA_TLN_DISABLED_MASK
,
820 static bool dsdb_trust_find_tln_ex_match(const struct lsa_ForestTrustInformation
*info
,
825 m
= dsdb_trust_find_tln_match_internal(info
,
826 LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX
,
836 NTSTATUS
dsdb_trust_xref_tdo_info(TALLOC_CTX
*mem_ctx
,
837 struct ldb_context
*sam_ctx
,
838 struct lsa_TrustDomainInfoInfoEx
**_tdo
)
841 * The extra filter makes sure we only find the forest root domain
843 const char *extra_filter
= "(!(|(rootTrust=*)(trustParent=*)))";
844 struct ldb_dn
*domain_dn
= NULL
;
846 domain_dn
= ldb_get_default_basedn(sam_ctx
);
847 if (domain_dn
== NULL
) {
848 return NT_STATUS_INTERNAL_ERROR
;
851 return dsdb_trust_crossref_tdo_info(mem_ctx
, sam_ctx
,
852 domain_dn
, extra_filter
,
856 static int dsdb_trust_xref_sort_msgs(struct ldb_message
**_m1
,
857 struct ldb_message
**_m2
)
859 struct ldb_message
*m1
= *_m1
;
860 struct ldb_message
*m2
= *_m2
;
861 const char *dns1
= NULL
;
862 const char *dns2
= NULL
;
864 struct ldb_message_element
*rootTrust1
= NULL
;
865 struct ldb_message_element
*trustParent1
= NULL
;
866 struct ldb_message_element
*rootTrust2
= NULL
;
867 struct ldb_message_element
*trustParent2
= NULL
;
869 dns1
= ldb_msg_find_attr_as_string(m1
, "dnsRoot", NULL
);
870 dns2
= ldb_msg_find_attr_as_string(m2
, "dnsRoot", NULL
);
872 cmp
= dns_cmp(dns1
, dns2
);
874 case DNS_CMP_FIRST_IS_CHILD
:
876 case DNS_CMP_SECOND_IS_CHILD
:
880 rootTrust1
= ldb_msg_find_element(m1
, "rootTrust");
881 trustParent1
= ldb_msg_find_element(m1
, "trustParent");
882 rootTrust2
= ldb_msg_find_element(m2
, "rootTrust");
883 trustParent2
= ldb_msg_find_element(m2
, "trustParent");
885 if (rootTrust1
== NULL
&& trustParent1
== NULL
) {
886 /* m1 is the forest root */
889 if (rootTrust2
== NULL
&& trustParent2
== NULL
) {
890 /* m2 is the forest root */
897 static int dsdb_trust_xref_sort_vals(struct ldb_val
*v1
,
900 const char *dns1
= (const char *)v1
->data
;
901 const char *dns2
= (const char *)v2
->data
;
903 return dns_cmp(dns1
, dns2
);
906 NTSTATUS
dsdb_trust_xref_forest_info(TALLOC_CTX
*mem_ctx
,
907 struct ldb_context
*sam_ctx
,
908 struct lsa_ForestTrustInformation
**_info
)
910 TALLOC_CTX
*frame
= talloc_stackframe();
911 struct lsa_ForestTrustInformation
*info
= NULL
;
912 struct ldb_dn
*partitions_dn
= NULL
;
913 const char * const cross_attrs1
[] = {
918 struct ldb_result
*cross_res1
= NULL
;
919 struct ldb_message_element
*upn_el
= NULL
;
920 struct ldb_message_element
*spn_el
= NULL
;
921 struct ldb_message
*tln_msg
= NULL
;
922 struct ldb_message_element
*tln_el
= NULL
;
923 const char * const cross_attrs2
[] = {
931 struct ldb_result
*cross_res2
= NULL
;
934 bool restart
= false;
937 info
= talloc_zero(mem_ctx
, struct lsa_ForestTrustInformation
);
940 return NT_STATUS_NO_MEMORY
;
942 talloc_steal(frame
, info
);
944 partitions_dn
= samdb_partitions_dn(sam_ctx
, frame
);
945 if (partitions_dn
== NULL
) {
947 return NT_STATUS_NO_MEMORY
;
950 ret
= dsdb_search_dn(sam_ctx
, partitions_dn
, &cross_res1
,
951 partitions_dn
, cross_attrs1
, 0);
952 if (ret
!= LDB_SUCCESS
) {
954 return dsdb_ldb_err_to_ntstatus(ret
);
957 ret
= dsdb_search(sam_ctx
, partitions_dn
, &cross_res2
,
958 partitions_dn
, LDB_SCOPE_ONELEVEL
,
960 DSDB_SEARCH_SHOW_EXTENDED_DN
,
961 "(&(objectClass=crossRef)"
962 "(systemFlags:%s:=%u))",
963 LDB_OID_COMPARATOR_AND
,
964 SYSTEM_FLAG_CR_NTDS_DOMAIN
);
965 if (ret
!= LDB_SUCCESS
) {
967 return dsdb_ldb_err_to_ntstatus(ret
);
971 * Sort the domains as trees, starting with the forest root
973 TYPESAFE_QSORT(cross_res2
->msgs
, cross_res2
->count
,
974 dsdb_trust_xref_sort_msgs
);
976 upn_el
= ldb_msg_find_element(cross_res1
->msgs
[0], "uPNSuffixes");
977 if (upn_el
!= NULL
) {
978 upn_el
->name
= "__tln__";
980 spn_el
= ldb_msg_find_element(cross_res1
->msgs
[0], "msDS-SPNSuffixes");
981 if (spn_el
!= NULL
) {
982 spn_el
->name
= "__tln__";
984 ret
= ldb_msg_normalize(sam_ctx
, frame
, cross_res1
->msgs
[0], &tln_msg
);
985 if (ret
!= LDB_SUCCESS
) {
987 return dsdb_ldb_err_to_ntstatus(ret
);
989 tln_el
= ldb_msg_find_element(tln_msg
, "__tln__");
990 if (tln_el
!= NULL
) {
992 * Sort the domains as trees
994 TYPESAFE_QSORT(tln_el
->values
, tln_el
->num_values
,
995 dsdb_trust_xref_sort_vals
);
998 for (i
=0; i
< cross_res2
->count
; i
++) {
999 struct ldb_message
*m
= cross_res2
->msgs
[i
];
1000 const char *dns
= NULL
;
1001 const char *netbios
= NULL
;
1002 struct ldb_dn
*nc_dn
= NULL
;
1003 struct dom_sid sid
= {};
1004 struct lsa_ForestTrustRecord e
= {};
1005 struct lsa_ForestTrustDomainInfo
*d
= NULL
;
1006 struct lsa_StringLarge
*t
= NULL
;
1010 dns
= ldb_msg_find_attr_as_string(m
, "dnsRoot", NULL
);
1013 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1016 netbios
= ldb_msg_find_attr_as_string(m
, "nETBIOSName", NULL
);
1017 if (netbios
== NULL
) {
1019 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1022 nc_dn
= samdb_result_dn(sam_ctx
, m
, m
, "ncName", NULL
);
1023 if (nc_dn
== NULL
) {
1025 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1028 status
= dsdb_get_extended_dn_sid(nc_dn
, &sid
, "SID");
1029 if (!NT_STATUS_IS_OK(status
)) {
1034 match
= dsdb_trust_find_tln_match(info
, dns
);
1037 * First the TOP_LEVEL_NAME, if required
1039 e
= (struct lsa_ForestTrustRecord
) {
1041 .type
= LSA_FOREST_TRUST_TOP_LEVEL_NAME
,
1042 .time
= 0, /* so far always 0 in traces. */
1045 t
= &e
.forest_trust_data
.top_level_name
;
1048 status
= dsdb_trust_forest_info_add_record(info
, &e
);
1049 if (!NT_STATUS_IS_OK(status
)) {
1056 * Then the DOMAIN_INFO
1058 e
= (struct lsa_ForestTrustRecord
) {
1060 .type
= LSA_FOREST_TRUST_DOMAIN_INFO
,
1061 .time
= 0, /* so far always 0 in traces. */
1063 d
= &e
.forest_trust_data
.domain_info
;
1064 d
->domain_sid
= &sid
;
1065 d
->dns_domain_name
.string
= dns
;
1066 d
->netbios_domain_name
.string
= netbios
;
1068 status
= dsdb_trust_forest_info_add_record(info
, &e
);
1069 if (!NT_STATUS_IS_OK(status
)) {
1075 for (i
=0; (tln_el
!= NULL
) && i
< tln_el
->num_values
; i
++) {
1076 const struct ldb_val
*v
= &tln_el
->values
[i
];
1077 const char *dns
= (const char *)v
->data
;
1078 struct lsa_ForestTrustRecord e
= {};
1079 struct lsa_StringLarge
*t
= NULL
;
1085 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1088 match
= dsdb_trust_find_tln_match(info
, dns
);
1094 * an additional the TOP_LEVEL_NAME
1096 e
= (struct lsa_ForestTrustRecord
) {
1098 .type
= LSA_FOREST_TRUST_TOP_LEVEL_NAME
,
1099 .time
= 0, /* so far always 0 in traces. */
1101 t
= &e
.forest_trust_data
.top_level_name
;
1104 status
= dsdb_trust_forest_info_add_record(info
, &e
);
1105 if (!NT_STATUS_IS_OK(status
)) {
1111 for (i
=0; i
< info
->count
; restart
? i
=0 : i
++) {
1112 struct lsa_ForestTrustRecord
*tr
= info
->entries
[i
];
1113 const struct lsa_StringLarge
*ts
= NULL
;
1118 if (tr
->type
!= LSA_FOREST_TRUST_TOP_LEVEL_NAME
) {
1122 ts
= &tr
->forest_trust_data
.top_level_name
;
1124 for (c
= i
+ 1; c
< info
->count
; c
++) {
1125 struct lsa_ForestTrustRecord
*cr
= info
->entries
[c
];
1126 const struct lsa_StringLarge
*cs
= NULL
;
1130 if (cr
->type
!= LSA_FOREST_TRUST_TOP_LEVEL_NAME
) {
1134 cs
= &cr
->forest_trust_data
.top_level_name
;
1136 cmp
= dns_cmp(ts
->string
, cs
->string
);
1137 if (DNS_CMP_IS_NO_MATCH(cmp
)) {
1140 if (cmp
!= DNS_CMP_FIRST_IS_CHILD
) {
1141 /* can't happen ... */
1147 TALLOC_FREE(info
->entries
[i
]);
1148 info
->entries
[i
] = info
->entries
[c
];
1150 for (j
= c
+ 1; j
< info
->count
; j
++) {
1151 info
->entries
[j
-1] = info
->entries
[j
];
1159 *_info
= talloc_move(mem_ctx
, &info
);
1161 return NT_STATUS_OK
;
1164 NTSTATUS
dsdb_trust_parse_tdo_info(TALLOC_CTX
*mem_ctx
,
1165 struct ldb_message
*m
,
1166 struct lsa_TrustDomainInfoInfoEx
**_tdo
)
1168 struct lsa_TrustDomainInfoInfoEx
*tdo
= NULL
;
1169 const char *dns
= NULL
;
1170 const char *netbios
= NULL
;
1174 tdo
= talloc_zero(mem_ctx
, struct lsa_TrustDomainInfoInfoEx
);
1176 return NT_STATUS_NO_MEMORY
;
1179 dns
= ldb_msg_find_attr_as_string(m
, "trustPartner", NULL
);
1182 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1184 tdo
->domain_name
.string
= talloc_strdup(tdo
, dns
);
1185 if (tdo
->domain_name
.string
== NULL
) {
1187 return NT_STATUS_NO_MEMORY
;
1190 netbios
= ldb_msg_find_attr_as_string(m
, "flatName", NULL
);
1191 if (netbios
== NULL
) {
1193 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1195 tdo
->netbios_name
.string
= talloc_strdup(tdo
, netbios
);
1196 if (tdo
->netbios_name
.string
== NULL
) {
1198 return NT_STATUS_NO_MEMORY
;
1201 tdo
->sid
= samdb_result_dom_sid(tdo
, m
, "securityIdentifier");
1202 if (tdo
->sid
== NULL
) {
1204 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1207 tdo
->trust_type
= ldb_msg_find_attr_as_uint(m
, "trustType", 0);
1208 tdo
->trust_direction
= ldb_msg_find_attr_as_uint(m
, "trustDirection", 0);
1209 tdo
->trust_attributes
= ldb_msg_find_attr_as_uint(m
, "trustAttributes", 0);
1212 return NT_STATUS_OK
;
1215 NTSTATUS
dsdb_trust_parse_forest_info(TALLOC_CTX
*mem_ctx
,
1216 struct ldb_message
*m
,
1217 struct ForestTrustInfo
**_fti
)
1219 const struct ldb_val
*ft_blob
= NULL
;
1220 struct ForestTrustInfo
*fti
= NULL
;
1221 enum ndr_err_code ndr_err
;
1225 ft_blob
= ldb_msg_find_ldb_val(m
, "msDS-TrustForestTrustInfo");
1226 if (ft_blob
== NULL
) {
1227 return NT_STATUS_NOT_FOUND
;
1230 fti
= talloc_zero(mem_ctx
, struct ForestTrustInfo
);
1232 return NT_STATUS_NO_MEMORY
;
1235 /* ldb_val is equivalent to DATA_BLOB */
1236 ndr_err
= ndr_pull_struct_blob_all(ft_blob
, fti
, fti
,
1237 (ndr_pull_flags_fn_t
)ndr_pull_ForestTrustInfo
);
1238 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1240 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1244 return NT_STATUS_OK
;
1247 NTSTATUS
dsdb_trust_normalize_forest_info_step1(TALLOC_CTX
*mem_ctx
,
1248 const struct lsa_ForestTrustInformation
*gfti
,
1249 struct lsa_ForestTrustInformation
**_nfti
)
1251 TALLOC_CTX
*frame
= talloc_stackframe();
1252 struct lsa_ForestTrustInformation
*nfti
;
1257 nfti
= talloc_zero(mem_ctx
, struct lsa_ForestTrustInformation
);
1260 return NT_STATUS_NO_MEMORY
;
1262 talloc_steal(frame
, nfti
);
1265 * First we copy every record and remove possible trailing dots
1268 * We also NULL out dublicates. The first one wins and
1269 * we keep 'count' as is. This is required in order to
1270 * provide the correct index for collision records.
1272 for (n
= 0; n
< gfti
->count
; n
++) {
1273 const struct lsa_ForestTrustRecord
*gftr
= gfti
->entries
[n
];
1274 struct lsa_ForestTrustRecord
*nftr
= NULL
;
1275 struct lsa_ForestTrustDomainInfo
*ninfo
= NULL
;
1276 struct lsa_StringLarge
*ntln
= NULL
;
1277 struct lsa_StringLarge
*nnb
= NULL
;
1278 struct dom_sid
*nsid
= NULL
;
1286 return NT_STATUS_INVALID_PARAMETER
;
1289 status
= dsdb_trust_forest_info_add_record(nfti
, gftr
);
1290 if (!NT_STATUS_IS_OK(status
)) {
1295 nftr
= nfti
->entries
[n
];
1297 switch (nftr
->type
) {
1298 case LSA_FOREST_TRUST_TOP_LEVEL_NAME
:
1299 ntln
= &nftr
->forest_trust_data
.top_level_name
;
1302 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX
:
1303 ntln
= &nftr
->forest_trust_data
.top_level_name_ex
;
1306 case LSA_FOREST_TRUST_DOMAIN_INFO
:
1307 ninfo
= &nftr
->forest_trust_data
.domain_info
;
1308 ntln
= &ninfo
->dns_domain_name
;
1309 nnb
= &ninfo
->netbios_domain_name
;
1310 nsid
= ninfo
->domain_sid
;
1315 return NT_STATUS_INVALID_PARAMETER
;
1319 * We remove one trailing '.' before checking
1322 * domain.com. becomes domain.com
1323 * domain.com.. becomes domain.com.
1325 * Then the following is invalid:
1331 len
= strlen(ntln
->string
);
1332 if (len
> 1 && ntln
->string
[len
- 1] == '.') {
1333 const char *cp
= &ntln
->string
[len
- 1];
1334 p
= discard_const_p(char, cp
);
1337 if (ntln
->string
[0] == '.') {
1339 return NT_STATUS_INVALID_PARAMETER
;
1341 p
= strstr_m(ntln
->string
, "..");
1344 return NT_STATUS_INVALID_PARAMETER
;
1347 for (c
= 0; c
< n
; c
++) {
1348 const struct lsa_ForestTrustRecord
*cftr
= nfti
->entries
[c
];
1349 const struct lsa_ForestTrustDomainInfo
*cinfo
= NULL
;
1350 const struct lsa_StringLarge
*ctln
= NULL
;
1351 const struct lsa_StringLarge
*cnb
= NULL
;
1352 const struct dom_sid
*csid
= NULL
;
1359 if (cftr
->type
!= nftr
->type
) {
1363 switch (cftr
->type
) {
1364 case LSA_FOREST_TRUST_TOP_LEVEL_NAME
:
1365 ctln
= &cftr
->forest_trust_data
.top_level_name
;
1368 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX
:
1369 ctln
= &cftr
->forest_trust_data
.top_level_name_ex
;
1372 case LSA_FOREST_TRUST_DOMAIN_INFO
:
1373 cinfo
= &cftr
->forest_trust_data
.domain_info
;
1374 ctln
= &cinfo
->dns_domain_name
;
1375 cnb
= &cinfo
->netbios_domain_name
;
1376 csid
= cinfo
->domain_sid
;
1381 return NT_STATUS_INVALID_PARAMETER
;
1384 cmp
= dns_cmp(ntln
->string
, ctln
->string
);
1385 if (cmp
== DNS_CMP_MATCH
) {
1387 TALLOC_FREE(nfti
->entries
[n
]);
1391 if (cinfo
== NULL
) {
1395 cmp
= strcasecmp_m(nnb
->string
, cnb
->string
);
1398 TALLOC_FREE(nfti
->entries
[n
]);
1402 cmp
= dom_sid_compare(nsid
, csid
);
1405 TALLOC_FREE(nfti
->entries
[n
]);
1412 * Now we check that only true top level names are provided
1414 for (n
= 0; n
< nfti
->count
; n
++) {
1415 const struct lsa_ForestTrustRecord
*nftr
= nfti
->entries
[n
];
1416 const struct lsa_StringLarge
*ntln
= NULL
;
1423 if (nftr
->type
!= LSA_FOREST_TRUST_TOP_LEVEL_NAME
) {
1427 ntln
= &nftr
->forest_trust_data
.top_level_name
;
1429 for (c
= 0; c
< nfti
->count
; c
++) {
1430 const struct lsa_ForestTrustRecord
*cftr
= nfti
->entries
[c
];
1431 const struct lsa_StringLarge
*ctln
= NULL
;
1442 if (cftr
->type
!= nftr
->type
) {
1446 ctln
= &cftr
->forest_trust_data
.top_level_name
;
1448 cmp
= dns_cmp(ntln
->string
, ctln
->string
);
1449 if (DNS_CMP_IS_NO_MATCH(cmp
)) {
1454 return NT_STATUS_INVALID_PARAMETER
;
1459 * Now we check that only true sub level excludes are provided
1461 for (n
= 0; n
< nfti
->count
; n
++) {
1462 const struct lsa_ForestTrustRecord
*nftr
= nfti
->entries
[n
];
1463 const struct lsa_StringLarge
*ntln
= NULL
;
1465 bool found_tln
= false;
1471 if (nftr
->type
!= LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX
) {
1475 ntln
= &nftr
->forest_trust_data
.top_level_name
;
1477 for (c
= 0; c
< nfti
->count
; c
++) {
1478 const struct lsa_ForestTrustRecord
*cftr
= nfti
->entries
[c
];
1479 const struct lsa_StringLarge
*ctln
= NULL
;
1490 if (cftr
->type
!= LSA_FOREST_TRUST_TOP_LEVEL_NAME
) {
1494 ctln
= &cftr
->forest_trust_data
.top_level_name
;
1496 cmp
= dns_cmp(ntln
->string
, ctln
->string
);
1497 if (cmp
== DNS_CMP_FIRST_IS_CHILD
) {
1508 return NT_STATUS_INVALID_PARAMETER
;
1512 * Now we check that there's a top level name for each domain
1514 for (n
= 0; n
< nfti
->count
; n
++) {
1515 const struct lsa_ForestTrustRecord
*nftr
= nfti
->entries
[n
];
1516 const struct lsa_ForestTrustDomainInfo
*ninfo
= NULL
;
1517 const struct lsa_StringLarge
*ntln
= NULL
;
1519 bool found_tln
= false;
1525 if (nftr
->type
!= LSA_FOREST_TRUST_DOMAIN_INFO
) {
1529 ninfo
= &nftr
->forest_trust_data
.domain_info
;
1530 ntln
= &ninfo
->dns_domain_name
;
1532 for (c
= 0; c
< nfti
->count
; c
++) {
1533 const struct lsa_ForestTrustRecord
*cftr
= nfti
->entries
[c
];
1534 const struct lsa_StringLarge
*ctln
= NULL
;
1545 if (cftr
->type
!= LSA_FOREST_TRUST_TOP_LEVEL_NAME
) {
1549 ctln
= &cftr
->forest_trust_data
.top_level_name
;
1551 cmp
= dns_cmp(ntln
->string
, ctln
->string
);
1552 if (cmp
== DNS_CMP_MATCH
) {
1556 if (cmp
== DNS_CMP_FIRST_IS_CHILD
) {
1567 return NT_STATUS_INVALID_PARAMETER
;
1570 *_nfti
= talloc_move(mem_ctx
, &nfti
);
1572 return NT_STATUS_OK
;
1575 NTSTATUS
dsdb_trust_normalize_forest_info_step2(TALLOC_CTX
*mem_ctx
,
1576 const struct lsa_ForestTrustInformation
*gfti
,
1577 struct lsa_ForestTrustInformation
**_nfti
)
1579 TALLOC_CTX
*frame
= talloc_stackframe();
1580 struct timeval tv
= timeval_current();
1581 NTTIME now
= timeval_to_nttime(&tv
);
1582 struct lsa_ForestTrustInformation
*nfti
;
1587 nfti
= talloc_zero(mem_ctx
, struct lsa_ForestTrustInformation
);
1590 return NT_STATUS_NO_MEMORY
;
1592 talloc_steal(frame
, nfti
);
1595 * Now we add TOP_LEVEL_NAME[_EX] in reverse order
1596 * followed by LSA_FOREST_TRUST_DOMAIN_INFO in reverse order.
1598 * This also removes the possible NULL entries generated in step1.
1601 for (g
= 0; g
< gfti
->count
; g
++) {
1602 const struct lsa_ForestTrustRecord
*gftr
= gfti
->entries
[gfti
->count
- (g
+1)];
1603 struct lsa_ForestTrustRecord tftr
;
1611 switch (gftr
->type
) {
1612 case LSA_FOREST_TRUST_TOP_LEVEL_NAME
:
1613 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX
:
1616 case LSA_FOREST_TRUST_DOMAIN_INFO
:
1622 return NT_STATUS_INVALID_PARAMETER
;
1629 /* make a copy in order to update the time. */
1631 if (tftr
.time
== 0) {
1635 status
= dsdb_trust_forest_info_add_record(nfti
, &tftr
);
1636 if (!NT_STATUS_IS_OK(status
)) {
1642 for (g
= 0; g
< gfti
->count
; g
++) {
1643 const struct lsa_ForestTrustRecord
*gftr
= gfti
->entries
[gfti
->count
- (g
+1)];
1644 struct lsa_ForestTrustRecord tftr
;
1652 switch (gftr
->type
) {
1653 case LSA_FOREST_TRUST_TOP_LEVEL_NAME
:
1654 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX
:
1658 case LSA_FOREST_TRUST_DOMAIN_INFO
:
1663 return NT_STATUS_INVALID_PARAMETER
;
1670 /* make a copy in order to update the time. */
1672 if (tftr
.time
== 0) {
1676 status
= dsdb_trust_forest_info_add_record(nfti
, &tftr
);
1677 if (!NT_STATUS_IS_OK(status
)) {
1683 *_nfti
= talloc_move(mem_ctx
, &nfti
);
1685 return NT_STATUS_OK
;
1688 static NTSTATUS
dsdb_trust_add_collision(
1689 struct lsa_ForestTrustCollisionInfo
*c_info
,
1690 enum lsa_ForestTrustCollisionRecordType type
,
1691 uint32_t idx
, uint32_t flags
,
1692 const char *tdo_name
)
1694 struct lsa_ForestTrustCollisionRecord
**es
;
1695 uint32_t i
= c_info
->count
;
1697 es
= talloc_realloc(c_info
, c_info
->entries
,
1698 struct lsa_ForestTrustCollisionRecord
*, i
+ 1);
1700 return NT_STATUS_NO_MEMORY
;
1702 c_info
->entries
= es
;
1703 c_info
->count
= i
+ 1;
1705 es
[i
] = talloc_zero(es
, struct lsa_ForestTrustCollisionRecord
);
1706 if (es
[i
] == NULL
) {
1707 return NT_STATUS_NO_MEMORY
;
1712 es
[i
]->flags
= flags
;
1713 es
[i
]->name
.string
= talloc_strdup(es
[i
], tdo_name
);
1714 if (es
[i
]->name
.string
== NULL
) {
1715 return NT_STATUS_NO_MEMORY
;
1718 return NT_STATUS_OK
;
1721 NTSTATUS
dsdb_trust_verify_forest_info(const struct lsa_TrustDomainInfoInfoEx
*ref_tdo
,
1722 const struct lsa_ForestTrustInformation
*ref_fti
,
1723 enum lsa_ForestTrustCollisionRecordType collision_type
,
1724 struct lsa_ForestTrustCollisionInfo
*c_info
,
1725 struct lsa_ForestTrustInformation
*new_fti
)
1729 for (n
= 0; n
< new_fti
->count
; n
++) {
1730 struct lsa_ForestTrustRecord
*nftr
= new_fti
->entries
[n
];
1731 struct lsa_StringLarge
*ntln
= NULL
;
1732 bool ntln_excluded
= false;
1741 if (nftr
->type
!= LSA_FOREST_TRUST_TOP_LEVEL_NAME
) {
1745 ntln
= &nftr
->forest_trust_data
.top_level_name
;
1746 if (ntln
->string
== NULL
) {
1747 return NT_STATUS_INVALID_PARAMETER
;
1750 ntln_excluded
= dsdb_trust_find_tln_ex_match(ref_fti
,
1753 /* check if this is already taken and not excluded */
1754 for (r
= 0; r
< ref_fti
->count
; r
++) {
1755 const struct lsa_ForestTrustRecord
*rftr
=
1756 ref_fti
->entries
[r
];
1757 const struct lsa_StringLarge
*rtln
= NULL
;
1764 if (rftr
->type
!= LSA_FOREST_TRUST_TOP_LEVEL_NAME
) {
1768 rtln
= &rftr
->forest_trust_data
.top_level_name
;
1769 if (rtln
->string
== NULL
) {
1773 cmp
= dns_cmp(ntln
->string
, rtln
->string
);
1774 if (DNS_CMP_IS_NO_MATCH(cmp
)) {
1777 if (cmp
== DNS_CMP_MATCH
) {
1778 /* We need to normalize the string */
1779 ntln
->string
= talloc_strdup(nftr
,
1781 if (ntln
->string
== NULL
) {
1782 return NT_STATUS_NO_MEMORY
;
1786 if (ntln_excluded
) {
1790 if (rftr
->flags
& LSA_TLN_DISABLED_MASK
) {
1794 if (nftr
->flags
& LSA_TLN_DISABLED_MASK
) {
1798 if (cmp
== DNS_CMP_SECOND_IS_CHILD
) {
1802 * If the conflicting tln is a child, check if
1803 * we have an exclusion record for it.
1805 m
= dsdb_trust_find_tln_ex_match(new_fti
,
1812 flags
|= LSA_TLN_DISABLED_CONFLICT
;
1819 nftr
->flags
|= flags
;
1821 status
= dsdb_trust_add_collision(c_info
,
1824 ref_tdo
->domain_name
.string
);
1825 if (!NT_STATUS_IS_OK(status
)) {
1830 for (n
= 0; n
< new_fti
->count
; n
++) {
1831 struct lsa_ForestTrustRecord
*nftr
= new_fti
->entries
[n
];
1832 struct lsa_ForestTrustDomainInfo
*ninfo
= NULL
;
1833 struct lsa_StringLarge
*ntln
= NULL
;
1834 struct lsa_StringLarge
*nnb
= NULL
;
1835 struct dom_sid
*nsid
= NULL
;
1836 bool ntln_found
= false;
1845 if (nftr
->type
!= LSA_FOREST_TRUST_DOMAIN_INFO
) {
1849 ninfo
= &nftr
->forest_trust_data
.domain_info
;
1850 ntln
= &ninfo
->dns_domain_name
;
1851 if (ntln
->string
== NULL
) {
1852 return NT_STATUS_INVALID_PARAMETER
;
1854 nnb
= &ninfo
->netbios_domain_name
;
1855 if (nnb
->string
== NULL
) {
1856 return NT_STATUS_INVALID_PARAMETER
;
1858 nsid
= ninfo
->domain_sid
;
1860 return NT_STATUS_INVALID_PARAMETER
;
1863 ntln_found
= dsdb_trust_find_tln_match(ref_fti
, ntln
->string
);
1865 /* check if this is already taken and not excluded */
1866 for (r
= 0; r
< ref_fti
->count
; r
++) {
1867 const struct lsa_ForestTrustRecord
*rftr
=
1868 ref_fti
->entries
[r
];
1869 const struct lsa_ForestTrustDomainInfo
*rinfo
= NULL
;
1870 const struct lsa_StringLarge
*rtln
= NULL
;
1871 const struct lsa_StringLarge
*rnb
= NULL
;
1872 const struct dom_sid
*rsid
= NULL
;
1873 bool nb_possible
= true;
1874 bool sid_possible
= true;
1883 * If the dns name doesn't match any existing
1884 * tln any conflict is ignored, but name
1885 * normalization still happens.
1887 * I guess that's a bug in Windows
1888 * (tested with Windows 2012r2).
1890 nb_possible
= false;
1891 sid_possible
= false;
1894 if (nftr
->flags
& LSA_SID_DISABLED_MASK
) {
1895 sid_possible
= false;
1898 if (nftr
->flags
& LSA_NB_DISABLED_MASK
) {
1899 nb_possible
= false;
1902 switch (rftr
->type
) {
1903 case LSA_FOREST_TRUST_TOP_LEVEL_NAME
:
1904 rtln
= &rftr
->forest_trust_data
.top_level_name
;
1905 nb_possible
= false;
1906 sid_possible
= false;
1909 case LSA_FOREST_TRUST_DOMAIN_INFO
:
1910 rinfo
= &rftr
->forest_trust_data
.domain_info
;
1911 rtln
= &rinfo
->dns_domain_name
;
1912 rnb
= &rinfo
->netbios_domain_name
;
1913 rsid
= rinfo
->domain_sid
;
1915 if (rftr
->flags
& LSA_SID_DISABLED_MASK
) {
1916 sid_possible
= false;
1919 if (rftr
->flags
& LSA_NB_DISABLED_MASK
) {
1920 nb_possible
= false;
1932 if (rtln
->string
== NULL
) {
1936 cmp
= dns_cmp(ntln
->string
, rtln
->string
);
1937 if (DNS_CMP_IS_NO_MATCH(cmp
)) {
1938 nb_possible
= false;
1939 sid_possible
= false;
1941 if (cmp
== DNS_CMP_MATCH
) {
1942 /* We need to normalize the string */
1943 ntln
->string
= talloc_strdup(nftr
,
1945 if (ntln
->string
== NULL
) {
1946 return NT_STATUS_NO_MEMORY
;
1950 if (rinfo
== NULL
) {
1955 cmp
= dom_sid_compare(nsid
, rsid
);
1961 flags
|= LSA_SID_DISABLED_CONFLICT
;
1965 if (rnb
->string
!= NULL
) {
1966 cmp
= strcasecmp_m(nnb
->string
, rnb
->string
);
1971 nnb
->string
= talloc_strdup(nftr
, rnb
->string
);
1972 if (nnb
->string
== NULL
) {
1973 return NT_STATUS_NO_MEMORY
;
1976 flags
|= LSA_NB_DISABLED_CONFLICT
;
1985 nftr
->flags
|= flags
;
1987 status
= dsdb_trust_add_collision(c_info
,
1990 ref_tdo
->domain_name
.string
);
1991 if (!NT_STATUS_IS_OK(status
)) {
1996 return NT_STATUS_OK
;
1999 NTSTATUS
dsdb_trust_merge_forest_info(TALLOC_CTX
*mem_ctx
,
2000 const struct lsa_TrustDomainInfoInfoEx
*tdo
,
2001 const struct lsa_ForestTrustInformation
*ofti
,
2002 const struct lsa_ForestTrustInformation
*nfti
,
2003 struct lsa_ForestTrustInformation
**_mfti
)
2005 TALLOC_CTX
*frame
= talloc_stackframe();
2006 struct lsa_ForestTrustInformation
*mfti
= NULL
;
2013 mfti
= talloc_zero(mem_ctx
, struct lsa_ForestTrustInformation
);
2016 return NT_STATUS_NO_MEMORY
;
2018 talloc_steal(frame
, mfti
);
2021 * First we add all top unique level names.
2023 * The one matching the tdo dns name, will be
2024 * added without further checking. All others
2025 * may keep the flags and time values.
2027 for (ni
= 0; ni
< nfti
->count
; ni
++) {
2028 const struct lsa_ForestTrustRecord
*nftr
= nfti
->entries
[ni
];
2029 struct lsa_ForestTrustRecord tftr
= {};
2030 const char *ndns
= NULL
;
2031 bool ignore_new
= false;
2032 bool found_old
= false;
2037 return NT_STATUS_INVALID_PARAMETER
;
2040 if (nftr
->type
!= LSA_FOREST_TRUST_TOP_LEVEL_NAME
) {
2044 ndns
= nftr
->forest_trust_data
.top_level_name
.string
;
2047 return NT_STATUS_INVALID_PARAMETER
;
2050 cmp
= dns_cmp(tdo
->domain_name
.string
, ndns
);
2051 if (cmp
== DNS_CMP_MATCH
) {
2052 status
= dsdb_trust_forest_info_add_record(mfti
, nftr
);
2053 if (!NT_STATUS_IS_OK(status
)) {
2059 for (mi
= 0; mi
< mfti
->count
; mi
++) {
2060 const struct lsa_ForestTrustRecord
*mftr
=
2062 const char *mdns
= NULL
;
2065 * we just added this above, so we're sure to have a
2066 * valid LSA_FOREST_TRUST_TOP_LEVEL_NAME record
2068 mdns
= mftr
->forest_trust_data
.top_level_name
.string
;
2070 cmp
= dns_cmp(mdns
, ndns
);
2073 case DNS_CMP_SECOND_IS_CHILD
:
2088 * make a temporary copy where we can change time and flags
2092 for (oi
= 0; oi
< ofti
->count
; oi
++) {
2093 const struct lsa_ForestTrustRecord
*oftr
=
2095 const char *odns
= NULL
;
2099 * broken record => ignore...
2104 if (oftr
->type
!= LSA_FOREST_TRUST_TOP_LEVEL_NAME
) {
2108 odns
= oftr
->forest_trust_data
.top_level_name
.string
;
2111 * broken record => ignore...
2116 cmp
= dns_cmp(odns
, ndns
);
2117 if (cmp
!= DNS_CMP_MATCH
) {
2122 tftr
.flags
= oftr
->flags
;
2123 tftr
.time
= oftr
->time
;
2127 tftr
.flags
= LSA_TLN_DISABLED_NEW
;
2131 status
= dsdb_trust_forest_info_add_record(mfti
, &tftr
);
2132 if (!NT_STATUS_IS_OK(status
)) {
2139 * Now we add all unique (based on their SID) domains
2140 * and may keep the flags and time values.
2142 for (ni
= 0; ni
< nfti
->count
; ni
++) {
2143 const struct lsa_ForestTrustRecord
*nftr
= nfti
->entries
[ni
];
2144 struct lsa_ForestTrustRecord tftr
= {};
2145 const struct lsa_ForestTrustDomainInfo
*nd
= NULL
;
2146 const char *ndns
= NULL
;
2147 const char *nnbt
= NULL
;
2148 bool ignore_new
= false;
2149 bool found_old
= false;
2154 return NT_STATUS_INVALID_PARAMETER
;
2157 if (nftr
->type
!= LSA_FOREST_TRUST_DOMAIN_INFO
) {
2161 nd
= &nftr
->forest_trust_data
.domain_info
;
2162 if (nd
->domain_sid
== NULL
) {
2164 return NT_STATUS_INVALID_PARAMETER
;
2166 ndns
= nd
->dns_domain_name
.string
;
2169 return NT_STATUS_INVALID_PARAMETER
;
2171 nnbt
= nd
->netbios_domain_name
.string
;
2174 return NT_STATUS_INVALID_PARAMETER
;
2177 for (mi
= 0; mi
< mfti
->count
; mi
++) {
2178 const struct lsa_ForestTrustRecord
*mftr
=
2180 const struct lsa_ForestTrustDomainInfo
*md
= NULL
;
2182 if (mftr
->type
!= LSA_FOREST_TRUST_DOMAIN_INFO
) {
2187 * we just added this above, so we're sure to have a
2188 * valid LSA_FOREST_TRUST_DOMAIN_INFO record
2190 md
= &mftr
->forest_trust_data
.domain_info
;
2192 cmp
= dom_sid_compare(nd
->domain_sid
, md
->domain_sid
);
2204 * make a temporary copy where we can change time and flags
2208 for (oi
= 0; oi
< ofti
->count
; oi
++) {
2209 const struct lsa_ForestTrustRecord
*oftr
=
2211 const struct lsa_ForestTrustDomainInfo
*od
= NULL
;
2212 const char *onbt
= NULL
;
2216 * broken record => ignore...
2221 if (oftr
->type
!= LSA_FOREST_TRUST_DOMAIN_INFO
) {
2225 od
= &oftr
->forest_trust_data
.domain_info
;
2226 onbt
= od
->netbios_domain_name
.string
;
2229 * broken record => ignore...
2234 cmp
= strcasecmp(onbt
, nnbt
);
2240 tftr
.flags
= oftr
->flags
;
2241 tftr
.time
= oftr
->time
;
2249 status
= dsdb_trust_forest_info_add_record(mfti
, &tftr
);
2250 if (!NT_STATUS_IS_OK(status
)) {
2257 * We keep old domain records disabled by the admin
2258 * if not already in the list.
2260 for (oi
= 0; oi
< ofti
->count
; oi
++) {
2261 const struct lsa_ForestTrustRecord
*oftr
=
2263 const struct lsa_ForestTrustDomainInfo
*od
= NULL
;
2264 const char *odns
= NULL
;
2265 const char *onbt
= NULL
;
2266 bool ignore_old
= true;
2271 * broken record => ignore...
2276 if (oftr
->type
!= LSA_FOREST_TRUST_DOMAIN_INFO
) {
2280 od
= &oftr
->forest_trust_data
.domain_info
;
2281 odns
= od
->dns_domain_name
.string
;
2284 * broken record => ignore...
2288 onbt
= od
->netbios_domain_name
.string
;
2291 * broken record => ignore...
2295 if (od
->domain_sid
== NULL
) {
2297 * broken record => ignore...
2302 if (oftr
->flags
& LSA_NB_DISABLED_ADMIN
) {
2304 } else if (oftr
->flags
& LSA_SID_DISABLED_ADMIN
) {
2308 for (mi
= 0; mi
< mfti
->count
; mi
++) {
2309 const struct lsa_ForestTrustRecord
*mftr
=
2311 const struct lsa_ForestTrustDomainInfo
*md
= NULL
;
2313 if (mftr
->type
!= LSA_FOREST_TRUST_DOMAIN_INFO
) {
2318 * we just added this above, so we're sure to have a
2319 * valid LSA_FOREST_TRUST_DOMAIN_INFO record
2321 md
= &mftr
->forest_trust_data
.domain_info
;
2323 cmp
= dom_sid_compare(od
->domain_sid
, md
->domain_sid
);
2334 status
= dsdb_trust_forest_info_add_record(mfti
, oftr
);
2335 if (!NT_STATUS_IS_OK(status
)) {
2342 * Finally we readd top level exclusions,
2343 * if they still match a top level name.
2345 for (oi
= 0; oi
< ofti
->count
; oi
++) {
2346 const struct lsa_ForestTrustRecord
*oftr
=
2348 const char *odns
= NULL
;
2349 bool ignore_old
= false;
2354 * broken record => ignore...
2359 if (oftr
->type
!= LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX
) {
2363 odns
= oftr
->forest_trust_data
.top_level_name_ex
.string
;
2366 * broken record => ignore...
2371 for (mi
= 0; mi
< mfti
->count
; mi
++) {
2372 const struct lsa_ForestTrustRecord
*mftr
=
2374 const char *mdns
= NULL
;
2376 if (mftr
->type
!= LSA_FOREST_TRUST_TOP_LEVEL_NAME
) {
2381 * we just added this above, so we're sure to have a
2382 * valid LSA_FOREST_TRUST_TOP_LEVEL_NAME.
2384 mdns
= mftr
->forest_trust_data
.top_level_name
.string
;
2386 cmp
= dns_cmp(mdns
, odns
);
2389 case DNS_CMP_SECOND_IS_CHILD
:
2405 status
= dsdb_trust_forest_info_add_record(mfti
, oftr
);
2406 if (!NT_STATUS_IS_OK(status
)) {
2412 *_mfti
= talloc_move(mem_ctx
, &mfti
);
2414 return NT_STATUS_OK
;
2417 NTSTATUS
dsdb_trust_search_tdo(struct ldb_context
*sam_ctx
,
2418 const char *netbios
, const char *dns
,
2419 const char * const *attrs
,
2420 TALLOC_CTX
*mem_ctx
,
2421 struct ldb_message
**msg
)
2423 TALLOC_CTX
*frame
= talloc_stackframe();
2425 struct ldb_dn
*system_dn
= NULL
;
2426 char *netbios_encoded
= NULL
;
2427 char *dns_encoded
= NULL
;
2428 char *filter
= NULL
;
2432 if (netbios
== NULL
&& dns
== NULL
) {
2434 return NT_STATUS_INVALID_PARAMETER_MIX
;
2437 system_dn
= ldb_dn_copy(frame
, ldb_get_default_basedn(sam_ctx
));
2438 if (system_dn
== NULL
) {
2440 return NT_STATUS_NO_MEMORY
;
2443 if (!ldb_dn_add_child_fmt(system_dn
, "CN=System")) {
2445 return NT_STATUS_NO_MEMORY
;
2448 if (netbios
!= NULL
) {
2449 netbios_encoded
= ldb_binary_encode_string(frame
, netbios
);
2450 if (netbios_encoded
== NULL
) {
2452 return NT_STATUS_NO_MEMORY
;
2457 dns_encoded
= ldb_binary_encode_string(frame
, dns
);
2458 if (dns_encoded
== NULL
) {
2460 return NT_STATUS_NO_MEMORY
;
2464 if (netbios
!= NULL
&& dns
!= NULL
) {
2465 filter
= talloc_asprintf(frame
,
2466 "(&(objectClass=trustedDomain)"
2467 "(|(trustPartner=%s)(flatName=%s))"
2469 dns_encoded
, netbios_encoded
);
2470 if (filter
== NULL
) {
2472 return NT_STATUS_NO_MEMORY
;
2474 } else if (netbios
!= NULL
) {
2475 filter
= talloc_asprintf(frame
,
2476 "(&(objectClass=trustedDomain)(flatName=%s))",
2478 if (filter
== NULL
) {
2480 return NT_STATUS_NO_MEMORY
;
2482 } else if (dns
!= NULL
) {
2483 filter
= talloc_asprintf(frame
,
2484 "(&(objectClass=trustedDomain)(trustPartner=%s))",
2486 if (filter
== NULL
) {
2488 return NT_STATUS_NO_MEMORY
;
2492 ret
= dsdb_search_one(sam_ctx
, mem_ctx
, msg
,
2494 LDB_SCOPE_ONELEVEL
, attrs
,
2495 DSDB_SEARCH_NO_GLOBAL_CATALOG
,
2497 if (ret
!= LDB_SUCCESS
) {
2498 NTSTATUS status
= dsdb_ldb_err_to_ntstatus(ret
);
2499 DEBUG(3, ("Failed to search for %s: %s - %s\n",
2500 filter
, nt_errstr(status
), ldb_errstring(sam_ctx
)));
2506 return NT_STATUS_OK
;
2509 NTSTATUS
dsdb_trust_search_tdo_by_type(struct ldb_context
*sam_ctx
,
2510 enum netr_SchannelType type
,
2512 const char * const *attrs
,
2513 TALLOC_CTX
*mem_ctx
,
2514 struct ldb_message
**msg
)
2516 TALLOC_CTX
*frame
= talloc_stackframe();
2520 bool require_trailer
= true;
2521 char *encoded_name
= NULL
;
2522 const char *netbios
= NULL
;
2523 const char *dns
= NULL
;
2525 if (type
!= SEC_CHAN_DOMAIN
&& type
!= SEC_CHAN_DNS_DOMAIN
) {
2527 return NT_STATUS_INVALID_PARAMETER
;
2530 if (type
== SEC_CHAN_DNS_DOMAIN
) {
2532 require_trailer
= false;
2535 encoded_name
= ldb_binary_encode_string(frame
, name
);
2536 if (encoded_name
== NULL
) {
2538 return NT_STATUS_NO_MEMORY
;
2541 len
= strlen(encoded_name
);
2544 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
2547 if (require_trailer
&& encoded_name
[len
- 1] != trailer
) {
2549 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
2551 encoded_name
[len
- 1] = '\0';
2553 if (type
== SEC_CHAN_DNS_DOMAIN
) {
2556 netbios
= encoded_name
;
2559 status
= dsdb_trust_search_tdo(sam_ctx
, netbios
, dns
,
2560 attrs
, mem_ctx
, msg
);
2561 if (!NT_STATUS_IS_OK(status
)) {
2567 return NT_STATUS_OK
;
2570 NTSTATUS
dsdb_trust_get_incoming_passwords(struct ldb_message
*msg
,
2571 TALLOC_CTX
*mem_ctx
,
2572 struct samr_Password
**_current
,
2573 struct samr_Password
**_previous
)
2575 TALLOC_CTX
*frame
= talloc_stackframe();
2576 struct samr_Password __current
= {};
2577 struct samr_Password __previous
= {};
2578 struct samr_Password
*current
= NULL
;
2579 struct samr_Password
*previous
= NULL
;
2580 const struct ldb_val
*blob
= NULL
;
2581 enum ndr_err_code ndr_err
;
2582 struct trustAuthInOutBlob incoming
= {};
2585 if (_current
!= NULL
) {
2588 if (_previous
!= NULL
) {
2592 blob
= ldb_msg_find_ldb_val(msg
, "trustAuthIncoming");
2595 return NT_STATUS_ACCOUNT_DISABLED
;
2598 /* ldb_val is equivalent to DATA_BLOB */
2599 ndr_err
= ndr_pull_struct_blob_all(blob
, frame
, &incoming
,
2600 (ndr_pull_flags_fn_t
)ndr_pull_trustAuthInOutBlob
);
2601 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
2603 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2606 for (i
= 0; i
< incoming
.current
.count
; i
++) {
2607 struct AuthenticationInformation
*a
=
2608 &incoming
.current
.array
[i
];
2610 if (current
!= NULL
) {
2614 switch (a
->AuthType
) {
2615 case TRUST_AUTH_TYPE_NONE
:
2616 case TRUST_AUTH_TYPE_VERSION
:
2618 case TRUST_AUTH_TYPE_NT4OWF
:
2619 current
= &a
->AuthInfo
.nt4owf
.password
;
2621 case TRUST_AUTH_TYPE_CLEAR
:
2622 mdfour(__current
.hash
,
2623 a
->AuthInfo
.clear
.password
,
2624 a
->AuthInfo
.clear
.size
);
2625 current
= &__current
;
2630 if (current
== NULL
) {
2632 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2635 for (i
= 0; i
< incoming
.previous
.count
; i
++) {
2636 struct AuthenticationInformation
*a
=
2637 &incoming
.previous
.array
[i
];
2639 if (previous
!= NULL
) {
2643 switch (a
->AuthType
) {
2644 case TRUST_AUTH_TYPE_NONE
:
2645 case TRUST_AUTH_TYPE_VERSION
:
2647 case TRUST_AUTH_TYPE_NT4OWF
:
2648 previous
= &a
->AuthInfo
.nt4owf
.password
;
2650 case TRUST_AUTH_TYPE_CLEAR
:
2651 mdfour(__previous
.hash
,
2652 a
->AuthInfo
.clear
.password
,
2653 a
->AuthInfo
.clear
.size
);
2654 previous
= &__previous
;
2659 if (previous
== NULL
) {
2663 if (_current
!= NULL
) {
2664 *_current
= talloc(mem_ctx
, struct samr_Password
);
2665 if (*_current
== NULL
) {
2667 return NT_STATUS_NO_MEMORY
;
2669 **_current
= *current
;
2671 if (_previous
!= NULL
) {
2672 *_previous
= talloc(mem_ctx
, struct samr_Password
);
2673 if (*_previous
== NULL
) {
2674 TALLOC_FREE(*_current
);
2676 return NT_STATUS_NO_MEMORY
;
2678 **_previous
= *previous
;
2680 ZERO_STRUCTP(current
);
2681 ZERO_STRUCTP(previous
);
2683 return NT_STATUS_OK
;
2686 NTSTATUS
dsdb_trust_search_tdos(struct ldb_context
*sam_ctx
,
2687 const char *exclude
,
2688 const char * const *attrs
,
2689 TALLOC_CTX
*mem_ctx
,
2690 struct ldb_result
**res
)
2692 TALLOC_CTX
*frame
= talloc_stackframe();
2694 struct ldb_dn
*system_dn
= NULL
;
2695 const char *filter
= NULL
;
2696 char *exclude_encoded
= NULL
;
2700 system_dn
= ldb_dn_copy(frame
, ldb_get_default_basedn(sam_ctx
));
2701 if (system_dn
== NULL
) {
2703 return NT_STATUS_NO_MEMORY
;
2706 if (!ldb_dn_add_child_fmt(system_dn
, "CN=System")) {
2708 return NT_STATUS_NO_MEMORY
;
2711 if (exclude
!= NULL
) {
2712 exclude_encoded
= ldb_binary_encode_string(frame
, exclude
);
2713 if (exclude_encoded
== NULL
) {
2715 return NT_STATUS_NO_MEMORY
;
2718 filter
= talloc_asprintf(frame
,
2719 "(&(objectClass=trustedDomain)"
2720 "(!(|(trustPartner=%s)(flatName=%s)))"
2722 exclude_encoded
, exclude_encoded
);
2723 if (filter
== NULL
) {
2725 return NT_STATUS_NO_MEMORY
;
2728 filter
= "(objectClass=trustedDomain)";
2731 ret
= dsdb_search(sam_ctx
, mem_ctx
, res
,
2733 LDB_SCOPE_ONELEVEL
, attrs
,
2734 DSDB_SEARCH_NO_GLOBAL_CATALOG
,
2736 if (ret
!= LDB_SUCCESS
) {
2737 NTSTATUS status
= dsdb_ldb_err_to_ntstatus(ret
);
2738 DEBUG(3, ("Failed to search for %s: %s - %s\n",
2739 filter
, nt_errstr(status
), ldb_errstring(sam_ctx
)));
2745 return NT_STATUS_OK
;
2748 struct dsdb_trust_routing_domain
;
2750 struct dsdb_trust_routing_table
{
2751 struct dsdb_trust_routing_domain
*domains
;
2754 struct dsdb_trust_routing_domain
{
2755 struct dsdb_trust_routing_domain
*prev
, *next
;
2757 struct lsa_TrustDomainInfoInfoEx
*tdo
;
2758 struct lsa_ForestTrustInformation
*fti
;
2761 NTSTATUS
dsdb_trust_routing_table_load(struct ldb_context
*sam_ctx
,
2762 TALLOC_CTX
*mem_ctx
,
2763 struct dsdb_trust_routing_table
**_table
)
2765 TALLOC_CTX
*frame
= talloc_stackframe();
2766 struct dsdb_trust_routing_table
*table
;
2767 struct dsdb_trust_routing_domain
*d
= NULL
;
2768 struct ldb_dn
*domain_dn
= NULL
;
2769 struct lsa_TrustDomainInfoInfoEx
*root_trust_tdo
= NULL
;
2770 struct lsa_TrustDomainInfoInfoEx
*trust_parent_tdo
= NULL
;
2771 struct lsa_TrustDomainInfoInfoEx
*root_direction_tdo
= NULL
;
2772 const char * const trusts_attrs
[] = {
2773 "securityIdentifier",
2779 "msDS-TrustForestTrustInfo",
2782 struct ldb_result
*trusts_res
= NULL
;
2788 domain_dn
= ldb_get_default_basedn(sam_ctx
);
2789 if (domain_dn
== NULL
) {
2791 return NT_STATUS_INTERNAL_ERROR
;
2794 table
= talloc_zero(mem_ctx
, struct dsdb_trust_routing_table
);
2795 if (table
== NULL
) {
2797 return NT_STATUS_NO_MEMORY
;
2799 talloc_steal(frame
, table
);
2801 d
= talloc_zero(table
, struct dsdb_trust_routing_domain
);
2804 return NT_STATUS_NO_MEMORY
;
2807 status
= dsdb_trust_crossref_tdo_info(d
, sam_ctx
,
2812 if (!NT_STATUS_IS_OK(status
)) {
2817 if (root_trust_tdo
!= NULL
) {
2818 root_direction_tdo
= root_trust_tdo
;
2819 } else if (trust_parent_tdo
!= NULL
) {
2820 root_direction_tdo
= trust_parent_tdo
;
2823 if (root_direction_tdo
== NULL
) {
2824 /* we're the forest root */
2825 status
= dsdb_trust_xref_forest_info(d
, sam_ctx
, &d
->fti
);
2826 if (!NT_STATUS_IS_OK(status
)) {
2832 DLIST_ADD(table
->domains
, d
);
2834 status
= dsdb_trust_search_tdos(sam_ctx
, NULL
, trusts_attrs
,
2835 frame
, &trusts_res
);
2836 if (!NT_STATUS_IS_OK(status
)) {
2841 for (i
= 0; i
< trusts_res
->count
; i
++) {
2845 d
= talloc_zero(table
, struct dsdb_trust_routing_domain
);
2848 return NT_STATUS_NO_MEMORY
;
2851 status
= dsdb_trust_parse_tdo_info(d
,
2852 trusts_res
->msgs
[i
],
2854 if (!NT_STATUS_IS_OK(status
)) {
2859 DLIST_ADD_END(table
->domains
, d
, NULL
);
2861 if (d
->tdo
->trust_attributes
& LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
) {
2862 struct ForestTrustInfo
*fti
= NULL
;
2864 status
= dsdb_trust_parse_forest_info(frame
,
2865 trusts_res
->msgs
[i
],
2867 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2869 status
= NT_STATUS_OK
;
2871 if (!NT_STATUS_IS_OK(status
)) {
2880 status
= dsdb_trust_forest_info_to_lsa(d
, fti
, &d
->fti
);
2881 if (!NT_STATUS_IS_OK(status
)) {
2889 if (!(d
->tdo
->trust_attributes
& LSA_TRUST_ATTRIBUTE_WITHIN_FOREST
)) {
2893 if (root_direction_tdo
== NULL
) {
2897 ok
= dom_sid_equal(root_direction_tdo
->sid
, d
->tdo
->sid
);
2902 cmp
= strcasecmp_m(root_direction_tdo
->netbios_name
.string
,
2903 d
->tdo
->netbios_name
.string
);
2908 cmp
= strcasecmp_m(root_direction_tdo
->domain_name
.string
,
2909 d
->tdo
->domain_name
.string
);
2914 /* this our route to the forest root */
2915 status
= dsdb_trust_xref_forest_info(d
, sam_ctx
, &d
->fti
);
2916 if (!NT_STATUS_IS_OK(status
)) {
2922 *_table
= talloc_move(mem_ctx
, &table
);
2924 return NT_STATUS_OK
;
2927 static void dsdb_trust_update_best_tln(
2928 const struct dsdb_trust_routing_domain
**best_d
,
2929 const char **best_tln
,
2930 const struct dsdb_trust_routing_domain
*d
,
2935 if (*best_tln
== NULL
) {
2941 cmp
= dns_cmp(*best_tln
, tln
);
2942 if (cmp
!= DNS_CMP_FIRST_IS_CHILD
) {
2950 const struct lsa_TrustDomainInfoInfoEx
*dsdb_trust_routing_by_name(
2951 const struct dsdb_trust_routing_table
*table
,
2954 const struct dsdb_trust_routing_domain
*best_d
= NULL
;
2955 const char *best_tln
= NULL
;
2956 const struct dsdb_trust_routing_domain
*d
= NULL
;
2962 for (d
= table
->domains
; d
!= NULL
; d
= d
->next
) {
2963 bool transitive
= false;
2964 bool allow_netbios
= false;
2965 bool exclude
= false;
2968 if (d
->tdo
->trust_type
!= LSA_TRUST_TYPE_UPLEVEL
) {
2970 * Only uplevel trusts have top level names
2975 if (d
->tdo
->trust_attributes
& LSA_TRUST_ATTRIBUTE_WITHIN_FOREST
) {
2979 if (d
->tdo
->trust_attributes
& LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
) {
2983 if (d
->tdo
->trust_attributes
& LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE
) {
2987 if (d
->tdo
->trust_type
!= LSA_TRUST_TYPE_UPLEVEL
) {
2991 switch (d
->tdo
->trust_type
) {
2992 case LSA_TRUST_TYPE_UPLEVEL
:
2993 if (d
->tdo
->trust_attributes
& LSA_TRUST_ATTRIBUTE_UPLEVEL_ONLY
) {
2996 allow_netbios
= true;
2998 case LSA_TRUST_TYPE_DOWNLEVEL
:
2999 allow_netbios
= true;
3002 allow_netbios
= false;
3006 if (!transitive
|| d
->fti
== NULL
) {
3009 if (allow_netbios
) {
3010 cmp
= dns_cmp(name
, d
->tdo
->netbios_name
.string
);
3011 if (cmp
== DNS_CMP_MATCH
) {
3019 cmp
= dns_cmp(name
, d
->tdo
->domain_name
.string
);
3020 if (cmp
== DNS_CMP_MATCH
) {
3026 if (cmp
!= DNS_CMP_FIRST_IS_CHILD
) {
3034 dsdb_trust_update_best_tln(&best_d
, &best_tln
, d
,
3035 d
->tdo
->domain_name
.string
);
3039 exclude
= dsdb_trust_find_tln_ex_match(d
->fti
, name
);
3044 for (i
= 0; i
< d
->fti
->count
; i
++ ) {
3045 const struct lsa_ForestTrustRecord
*f
= d
->fti
->entries
[i
];
3046 const struct lsa_ForestTrustDomainInfo
*di
= NULL
;
3047 const char *fti_nbt
= NULL
;
3050 if (!allow_netbios
) {
3059 if (f
->type
!= LSA_FOREST_TRUST_DOMAIN_INFO
) {
3063 if (f
->flags
& LSA_NB_DISABLED_MASK
) {
3065 * any flag disables the entry.
3070 di
= &f
->forest_trust_data
.domain_info
;
3071 fti_nbt
= di
->netbios_domain_name
.string
;
3072 if (fti_nbt
== NULL
) {
3077 cmp
= dns_cmp(name
, fti_nbt
);
3078 if (cmp
== DNS_CMP_MATCH
) {
3086 for (i
= 0; i
< d
->fti
->count
; i
++ ) {
3087 const struct lsa_ForestTrustRecord
*f
= d
->fti
->entries
[i
];
3088 const union lsa_ForestTrustData
*u
= NULL
;
3089 const char *fti_tln
= NULL
;
3097 if (f
->type
!= LSA_FOREST_TRUST_TOP_LEVEL_NAME
) {
3101 if (f
->flags
& LSA_TLN_DISABLED_MASK
) {
3103 * any flag disables the entry.
3108 u
= &f
->forest_trust_data
;
3109 fti_tln
= u
->top_level_name
.string
;
3110 if (fti_tln
== NULL
) {
3114 cmp
= dns_cmp(name
, fti_tln
);
3117 case DNS_CMP_FIRST_IS_CHILD
:
3118 dsdb_trust_update_best_tln(&best_d
, &best_tln
,
3127 if (best_d
!= NULL
) {