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 = (enum ForestTrustInfoRecordType)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 = (enum lsa_ForestTrustRecordType)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);
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) {