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/md4.h"
36 #include "libcli/ldap/ldap_ndr.h"
40 NTSTATUS dsdb_trust_forest_info_from_lsa(TALLOC_CTX *mem_ctx,
41 const struct lsa_ForestTrustInformation *lfti,
42 struct ForestTrustInfo **_fti)
44 struct ForestTrustInfo *fti;
49 fti = talloc_zero(mem_ctx, struct ForestTrustInfo);
51 return NT_STATUS_NO_MEMORY;
55 fti->count = lfti->count;
56 fti->records = talloc_zero_array(mem_ctx,
57 struct ForestTrustInfoRecordArmor,
59 if (fti->records == NULL) {
61 return NT_STATUS_NO_MEMORY;
64 for (i = 0; i < fti->count; i++) {
65 const struct lsa_ForestTrustRecord *lftr = lfti->entries[i];
66 struct ForestTrustInfoRecord *ftr = &fti->records[i].record;
67 struct ForestTrustString *str = NULL;
68 const struct lsa_StringLarge *lstr = NULL;
69 const struct lsa_ForestTrustDomainInfo *linfo = NULL;
70 struct ForestTrustDataDomainInfo *info = NULL;
74 return NT_STATUS_INVALID_PARAMETER;
77 ftr->flags = lftr->flags;
78 ftr->timestamp = lftr->time;
79 ftr->type = (enum ForestTrustInfoRecordType)lftr->type;
82 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
83 lstr = &lftr->forest_trust_data.top_level_name;
84 str = &ftr->data.name;
86 str->string = talloc_strdup(mem_ctx, lstr->string);
87 if (str->string == NULL) {
89 return NT_STATUS_NO_MEMORY;
94 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
95 lstr = &lftr->forest_trust_data.top_level_name_ex;
96 str = &ftr->data.name;
98 str->string = talloc_strdup(mem_ctx, lstr->string);
99 if (str->string == NULL) {
101 return NT_STATUS_NO_MEMORY;
106 case LSA_FOREST_TRUST_DOMAIN_INFO:
107 linfo = &lftr->forest_trust_data.domain_info;
108 info = &ftr->data.info;
110 if (linfo->domain_sid == NULL) {
112 return NT_STATUS_INVALID_PARAMETER;
114 info->sid = *linfo->domain_sid;
116 lstr = &linfo->dns_domain_name;
117 str = &info->dns_name;
118 str->string = talloc_strdup(mem_ctx, lstr->string);
119 if (str->string == NULL) {
121 return NT_STATUS_NO_MEMORY;
124 lstr = &linfo->netbios_domain_name;
125 str = &info->netbios_name;
126 str->string = talloc_strdup(mem_ctx, lstr->string);
127 if (str->string == NULL) {
129 return NT_STATUS_NO_MEMORY;
135 return NT_STATUS_NOT_SUPPORTED;
143 static NTSTATUS dsdb_trust_forest_record_to_lsa(TALLOC_CTX *mem_ctx,
144 const struct ForestTrustInfoRecord *ftr,
145 struct lsa_ForestTrustRecord **_lftr)
147 struct lsa_ForestTrustRecord *lftr = NULL;
148 const struct ForestTrustString *str = NULL;
149 struct lsa_StringLarge *lstr = NULL;
150 const struct ForestTrustDataDomainInfo *info = NULL;
151 struct lsa_ForestTrustDomainInfo *linfo = NULL;
155 lftr = talloc_zero(mem_ctx, struct lsa_ForestTrustRecord);
157 return NT_STATUS_NO_MEMORY;
160 lftr->flags = ftr->flags;
161 lftr->time = ftr->timestamp;
162 lftr->type = (enum lsa_ForestTrustRecordType)ftr->type;
164 switch (lftr->type) {
165 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
166 lstr = &lftr->forest_trust_data.top_level_name;
167 str = &ftr->data.name;
169 lstr->string = talloc_strdup(mem_ctx, str->string);
170 if (lstr->string == NULL) {
172 return NT_STATUS_NO_MEMORY;
177 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
178 lstr = &lftr->forest_trust_data.top_level_name_ex;
179 str = &ftr->data.name;
181 lstr->string = talloc_strdup(mem_ctx, str->string);
182 if (lstr->string == NULL) {
184 return NT_STATUS_NO_MEMORY;
189 case LSA_FOREST_TRUST_DOMAIN_INFO:
190 linfo = &lftr->forest_trust_data.domain_info;
191 info = &ftr->data.info;
193 linfo->domain_sid = dom_sid_dup(lftr, &info->sid);
194 if (linfo->domain_sid == NULL) {
196 return NT_STATUS_NO_MEMORY;
199 lstr = &linfo->dns_domain_name;
200 str = &info->dns_name;
201 lstr->string = talloc_strdup(mem_ctx, str->string);
202 if (lstr->string == NULL) {
204 return NT_STATUS_NO_MEMORY;
207 lstr = &linfo->netbios_domain_name;
208 str = &info->netbios_name;
209 lstr->string = talloc_strdup(mem_ctx, str->string);
210 if (lstr->string == NULL) {
212 return NT_STATUS_NO_MEMORY;
218 return NT_STATUS_NOT_SUPPORTED;
225 NTSTATUS dsdb_trust_forest_info_to_lsa(TALLOC_CTX *mem_ctx,
226 const struct ForestTrustInfo *fti,
227 struct lsa_ForestTrustInformation **_lfti)
229 struct lsa_ForestTrustInformation *lfti;
234 if (fti->version != 1) {
235 return NT_STATUS_INVALID_PARAMETER;
238 lfti = talloc_zero(mem_ctx, struct lsa_ForestTrustInformation);
240 return NT_STATUS_NO_MEMORY;
243 lfti->count = fti->count;
244 lfti->entries = talloc_zero_array(mem_ctx,
245 struct lsa_ForestTrustRecord *,
247 if (lfti->entries == NULL) {
249 return NT_STATUS_NO_MEMORY;
252 for (i = 0; i < fti->count; i++) {
253 struct ForestTrustInfoRecord *ftr = &fti->records[i].record;
254 struct lsa_ForestTrustRecord *lftr = NULL;
257 status = dsdb_trust_forest_record_to_lsa(lfti->entries, ftr,
259 if (!NT_STATUS_IS_OK(status)) {
261 return NT_STATUS_NO_MEMORY;
263 lfti->entries[i] = lftr;
270 static NTSTATUS dsdb_trust_forest_info_add_record(struct lsa_ForestTrustInformation *fti,
271 const struct lsa_ForestTrustRecord *ftr)
273 struct lsa_ForestTrustRecord **es = NULL;
274 struct lsa_ForestTrustRecord *e = NULL;
275 const struct lsa_StringLarge *dns1 = NULL;
276 struct lsa_StringLarge *dns2 = NULL;
277 const struct lsa_ForestTrustDomainInfo *d1 = NULL;
278 struct lsa_ForestTrustDomainInfo *d2 = NULL;
281 es = talloc_realloc(fti, fti->entries,
282 struct lsa_ForestTrustRecord *,
285 return NT_STATUS_NO_MEMORY;
289 e = talloc_zero(es, struct lsa_ForestTrustRecord);
291 return NT_STATUS_NO_MEMORY;
295 e->flags = ftr->flags;
299 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
300 dns1 = &ftr->forest_trust_data.top_level_name;
301 dns2 = &e->forest_trust_data.top_level_name;
304 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
305 dns1 = &ftr->forest_trust_data.top_level_name_ex;
306 dns2 = &e->forest_trust_data.top_level_name_ex;
309 case LSA_FOREST_TRUST_DOMAIN_INFO:
310 dns1 = &ftr->forest_trust_data.domain_info.dns_domain_name;
311 dns2 = &e->forest_trust_data.domain_info.dns_domain_name;
312 d1 = &ftr->forest_trust_data.domain_info;
313 d2 = &e->forest_trust_data.domain_info;
316 return NT_STATUS_INVALID_PARAMETER;
319 if (dns1->string == NULL) {
321 return NT_STATUS_INVALID_PARAMETER;
324 len = strlen(dns1->string);
327 return NT_STATUS_INVALID_PARAMETER;
330 dns2->string = talloc_strdup(e, dns1->string);
331 if (dns2->string == NULL) {
333 return NT_STATUS_NO_MEMORY;
337 const struct lsa_StringLarge *nb1 = &d1->netbios_domain_name;
338 struct lsa_StringLarge *nb2 = &d2->netbios_domain_name;
340 if (nb1->string == NULL) {
342 return NT_STATUS_INVALID_PARAMETER;
345 len = strlen(nb1->string);
348 return NT_STATUS_INVALID_PARAMETER;
352 return NT_STATUS_INVALID_PARAMETER;
355 nb2->string = talloc_strdup(e, nb1->string);
356 if (nb2->string == NULL) {
358 return NT_STATUS_NO_MEMORY;
361 if (d1->domain_sid == NULL) {
363 return NT_STATUS_INVALID_PARAMETER;
366 d2->domain_sid = dom_sid_dup(e, d1->domain_sid);
367 if (d2->domain_sid == NULL) {
369 return NT_STATUS_NO_MEMORY;
373 fti->entries[fti->count++] = e;
377 static NTSTATUS dsdb_trust_parse_crossref_info(TALLOC_CTX *mem_ctx,
378 struct ldb_context *sam_ctx,
379 const struct ldb_message *msg,
380 struct lsa_TrustDomainInfoInfoEx **_tdo)
382 TALLOC_CTX *frame = talloc_stackframe();
383 struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
384 const char *dns = NULL;
385 const char *netbios = NULL;
386 struct ldb_dn *nc_dn = NULL;
387 struct dom_sid sid = {
393 tdo = talloc_zero(mem_ctx, struct lsa_TrustDomainInfoInfoEx);
396 return NT_STATUS_NO_MEMORY;
398 talloc_steal(frame, tdo);
400 dns = ldb_msg_find_attr_as_string(msg, "dnsRoot", NULL);
403 return NT_STATUS_INTERNAL_DB_CORRUPTION;
405 tdo->domain_name.string = talloc_strdup(tdo, dns);
406 if (tdo->domain_name.string == NULL) {
408 return NT_STATUS_NO_MEMORY;
411 netbios = ldb_msg_find_attr_as_string(msg, "nETBIOSName", NULL);
412 if (netbios == NULL) {
414 return NT_STATUS_INTERNAL_DB_CORRUPTION;
416 tdo->netbios_name.string = talloc_strdup(tdo, netbios);
417 if (tdo->netbios_name.string == NULL) {
419 return NT_STATUS_NO_MEMORY;
422 nc_dn = samdb_result_dn(sam_ctx, frame, msg, "ncName", NULL);
425 return NT_STATUS_INTERNAL_DB_CORRUPTION;
428 status = dsdb_get_extended_dn_sid(nc_dn, &sid, "SID");
429 if (!NT_STATUS_IS_OK(status)) {
433 tdo->sid = dom_sid_dup(tdo, &sid);
434 if (tdo->sid == NULL) {
436 return NT_STATUS_NO_MEMORY;
439 tdo->trust_type = LSA_TRUST_TYPE_UPLEVEL;
440 tdo->trust_direction = LSA_TRUST_DIRECTION_INBOUND |
441 LSA_TRUST_DIRECTION_OUTBOUND;
442 tdo->trust_attributes = LSA_TRUST_ATTRIBUTE_WITHIN_FOREST;
444 *_tdo = talloc_move(mem_ctx, &tdo);
449 static NTSTATUS dsdb_trust_crossref_tdo_info(TALLOC_CTX *mem_ctx,
450 struct ldb_context *sam_ctx,
451 struct ldb_dn *domain_dn,
452 const char *extra_filter,
453 struct lsa_TrustDomainInfoInfoEx **_tdo,
454 struct lsa_TrustDomainInfoInfoEx **_root_trust_tdo,
455 struct lsa_TrustDomainInfoInfoEx **_trust_parent_tdo)
457 TALLOC_CTX *frame = talloc_stackframe();
458 struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
459 struct lsa_TrustDomainInfoInfoEx *root_trust_tdo = NULL;
460 struct lsa_TrustDomainInfoInfoEx *trust_parent_tdo = NULL;
461 struct ldb_dn *partitions_dn = NULL;
462 const char * const cross_attrs[] = {
470 struct ldb_result *cross_res = NULL;
471 struct ldb_message *msg = NULL;
472 struct ldb_dn *root_trust_dn = NULL;
473 struct ldb_dn *trust_parent_dn = NULL;
477 if (extra_filter == NULL) {
482 if (_root_trust_tdo != NULL) {
483 *_root_trust_tdo = NULL;
485 if (_trust_parent_tdo != NULL) {
486 *_trust_parent_tdo = NULL;
489 partitions_dn = samdb_partitions_dn(sam_ctx, frame);
490 if (partitions_dn == NULL) {
492 return NT_STATUS_NO_MEMORY;
495 ret = dsdb_search(sam_ctx, partitions_dn, &cross_res,
496 partitions_dn, LDB_SCOPE_ONELEVEL,
498 DSDB_SEARCH_ONE_ONLY |
499 DSDB_SEARCH_SHOW_EXTENDED_DN,
502 "(objectClass=crossRef)"
503 "(systemFlags:%s:=%u)"
506 ldb_dn_get_linearized(domain_dn),
507 LDB_OID_COMPARATOR_AND,
508 SYSTEM_FLAG_CR_NTDS_DOMAIN,
510 if (ret != LDB_SUCCESS) {
512 return dsdb_ldb_err_to_ntstatus(ret);
514 msg = cross_res->msgs[0];
516 status = dsdb_trust_parse_crossref_info(mem_ctx, sam_ctx, msg, &tdo);
517 if (!NT_STATUS_IS_OK(status)) {
521 talloc_steal(frame, tdo);
523 if (_root_trust_tdo != NULL) {
524 root_trust_dn = samdb_result_dn(sam_ctx, frame, msg,
527 if (_trust_parent_tdo != NULL) {
528 trust_parent_dn = samdb_result_dn(sam_ctx, frame, msg,
529 "trustParent", NULL);
532 if (root_trust_dn != NULL) {
533 struct ldb_message *root_trust_msg = NULL;
535 ret = dsdb_search_one(sam_ctx, frame,
540 DSDB_SEARCH_NO_GLOBAL_CATALOG,
541 "(objectClass=crossRef)");
542 if (ret != LDB_SUCCESS) {
543 status = dsdb_ldb_err_to_ntstatus(ret);
544 DEBUG(3, ("Failed to search for %s: %s - %s\n",
545 ldb_dn_get_linearized(root_trust_dn),
546 nt_errstr(status), ldb_errstring(sam_ctx)));
551 status = dsdb_trust_parse_crossref_info(mem_ctx, sam_ctx,
554 if (!NT_STATUS_IS_OK(status)) {
558 talloc_steal(frame, root_trust_tdo);
561 if (trust_parent_dn != NULL) {
562 struct ldb_message *trust_parent_msg = NULL;
564 ret = dsdb_search_one(sam_ctx, frame,
569 DSDB_SEARCH_NO_GLOBAL_CATALOG,
570 "(objectClass=crossRef)");
571 if (ret != LDB_SUCCESS) {
572 status = dsdb_ldb_err_to_ntstatus(ret);
573 DEBUG(3, ("Failed to search for %s: %s - %s\n",
574 ldb_dn_get_linearized(trust_parent_dn),
575 nt_errstr(status), ldb_errstring(sam_ctx)));
580 status = dsdb_trust_parse_crossref_info(mem_ctx, sam_ctx,
583 if (!NT_STATUS_IS_OK(status)) {
587 talloc_steal(frame, trust_parent_tdo);
590 *_tdo = talloc_move(mem_ctx, &tdo);
591 if (_root_trust_tdo != NULL) {
592 *_root_trust_tdo = talloc_move(mem_ctx, &root_trust_tdo);
594 if (_trust_parent_tdo != NULL) {
595 *_trust_parent_tdo = talloc_move(mem_ctx, &trust_parent_tdo);
601 #define DNS_CMP_FIRST_IS_CHILD -2
602 #define DNS_CMP_FIRST_IS_LESS -1
603 #define DNS_CMP_MATCH 0
604 #define DNS_CMP_SECOND_IS_LESS 1
605 #define DNS_CMP_SECOND_IS_CHILD 2
607 #define DNS_CMP_IS_NO_MATCH(__cmp) \
608 ((__cmp == DNS_CMP_FIRST_IS_LESS) || (__cmp == DNS_CMP_SECOND_IS_LESS))
611 * this function assumes names are well formed DNS names.
612 * it doesn't validate them
614 * It allows strings up to a length of UINT16_MAX - 1
615 * with up to UINT8_MAX components. On overflow this
616 * just returns the result of strcasecmp_m().
618 * Trailing dots (only one) are ignored.
620 * The DNS names are compared per component, starting from
623 static int dns_cmp(const char *s1, const char *s2)
626 const char *p1 = NULL;
627 size_t num_comp1 = 0;
628 uint16_t comp1[UINT8_MAX] = {0};
630 const char *p2 = NULL;
631 size_t num_comp2 = 0;
632 uint16_t comp2[UINT8_MAX] = {0};
644 * trailing '.' are ignored.
646 if (l1 > 1 && s1[l1 - 1] == '.') {
649 if (l2 > 1 && s2[l2 - 1] == '.') {
653 for (i = 0; i < ARRAY_SIZE(comp1); i++) {
659 if (l1 == 0 || l1 >= UINT16_MAX) {
660 /* just use one single component on overflow */
665 comp1[num_comp1++] = PTR_DIFF(p1, s1);
667 p = strchr_m(p1, '.');
677 /* just use one single component on overflow */
679 comp1[num_comp1++] = 0;
683 for (i = 0; i < ARRAY_SIZE(comp2); i++) {
689 if (l2 == 0 || l2 >= UINT16_MAX) {
690 /* just use one single component on overflow */
695 comp2[num_comp2++] = PTR_DIFF(p2, s2);
697 p = strchr_m(p2, '.');
707 /* just use one single component on overflow */
709 comp2[num_comp2++] = 0;
713 for (i = 0; i < UINT8_MAX; i++) {
717 size_t idx = num_comp1 - (i + 1);
718 p1 = s1 + comp1[idx];
724 size_t idx = num_comp2 - (i + 1);
725 p2 = s2 + comp2[idx];
730 if (p1 == NULL && p2 == NULL) {
731 return DNS_CMP_MATCH;
733 if (p1 != NULL && p2 == NULL) {
734 return DNS_CMP_FIRST_IS_CHILD;
736 if (p1 == NULL && p2 != NULL) {
737 return DNS_CMP_SECOND_IS_CHILD;
740 cmp = strcasecmp_m(p1, p2);
742 return DNS_CMP_FIRST_IS_LESS;
745 return DNS_CMP_SECOND_IS_LESS;
749 smb_panic(__location__);
753 static int dsdb_trust_find_tln_match_internal(const struct lsa_ForestTrustInformation *info,
754 enum lsa_ForestTrustRecordType type,
755 uint32_t disable_mask,
760 for (i = 0; i < info->count; i++) {
761 struct lsa_ForestTrustRecord *e = info->entries[i];
762 struct lsa_StringLarge *t = NULL;
769 if (e->type != type) {
773 if (e->flags & disable_mask) {
778 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
779 t = &e->forest_trust_data.top_level_name;
781 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
782 t = &e->forest_trust_data.top_level_name_ex;
792 cmp = dns_cmp(tln, t->string);
795 case DNS_CMP_FIRST_IS_CHILD:
803 static bool dsdb_trust_find_tln_match(const struct lsa_ForestTrustInformation *info,
808 m = dsdb_trust_find_tln_match_internal(info,
809 LSA_FOREST_TRUST_TOP_LEVEL_NAME,
810 LSA_TLN_DISABLED_MASK,
819 static bool dsdb_trust_find_tln_ex_match(const struct lsa_ForestTrustInformation *info,
824 m = dsdb_trust_find_tln_match_internal(info,
825 LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX,
835 NTSTATUS dsdb_trust_local_tdo_info(TALLOC_CTX *mem_ctx,
836 struct ldb_context *sam_ctx,
837 struct lsa_TrustDomainInfoInfoEx **_tdo)
839 struct ldb_dn *domain_dn = NULL;
841 domain_dn = ldb_get_default_basedn(sam_ctx);
842 if (domain_dn == NULL) {
843 return NT_STATUS_INTERNAL_ERROR;
846 return dsdb_trust_crossref_tdo_info(mem_ctx, sam_ctx,
851 NTSTATUS dsdb_trust_xref_tdo_info(TALLOC_CTX *mem_ctx,
852 struct ldb_context *sam_ctx,
853 struct lsa_TrustDomainInfoInfoEx **_tdo)
856 * The extra filter makes sure we only find the forest root domain
858 const char *extra_filter = "(!(|(rootTrust=*)(trustParent=*)))";
859 struct ldb_dn *domain_dn = NULL;
861 domain_dn = ldb_get_default_basedn(sam_ctx);
862 if (domain_dn == NULL) {
863 return NT_STATUS_INTERNAL_ERROR;
866 return dsdb_trust_crossref_tdo_info(mem_ctx, sam_ctx,
867 domain_dn, extra_filter,
871 static int dsdb_trust_xref_sort_msgs(struct ldb_message **_m1,
872 struct ldb_message **_m2)
874 struct ldb_message *m1 = *_m1;
875 struct ldb_message *m2 = *_m2;
876 const char *dns1 = NULL;
877 const char *dns2 = NULL;
879 struct ldb_message_element *rootTrust1 = NULL;
880 struct ldb_message_element *trustParent1 = NULL;
881 struct ldb_message_element *rootTrust2 = NULL;
882 struct ldb_message_element *trustParent2 = NULL;
884 dns1 = ldb_msg_find_attr_as_string(m1, "dnsRoot", NULL);
885 dns2 = ldb_msg_find_attr_as_string(m2, "dnsRoot", NULL);
887 cmp = dns_cmp(dns1, dns2);
889 case DNS_CMP_FIRST_IS_CHILD:
891 case DNS_CMP_SECOND_IS_CHILD:
895 rootTrust1 = ldb_msg_find_element(m1, "rootTrust");
896 trustParent1 = ldb_msg_find_element(m1, "trustParent");
897 rootTrust2 = ldb_msg_find_element(m2, "rootTrust");
898 trustParent2 = ldb_msg_find_element(m2, "trustParent");
900 if (rootTrust1 == NULL && trustParent1 == NULL) {
901 /* m1 is the forest root */
904 if (rootTrust2 == NULL && trustParent2 == NULL) {
905 /* m2 is the forest root */
912 static int dsdb_trust_xref_sort_vals(struct ldb_val *v1,
915 const char *dns1 = (const char *)v1->data;
916 const char *dns2 = (const char *)v2->data;
918 return dns_cmp(dns1, dns2);
921 NTSTATUS dsdb_trust_xref_forest_info(TALLOC_CTX *mem_ctx,
922 struct ldb_context *sam_ctx,
923 struct lsa_ForestTrustInformation **_info)
925 TALLOC_CTX *frame = talloc_stackframe();
926 struct lsa_ForestTrustInformation *info = NULL;
927 struct ldb_dn *partitions_dn = NULL;
928 const char * const cross_attrs1[] = {
933 struct ldb_result *cross_res1 = NULL;
934 struct ldb_message_element *upn_el = NULL;
935 struct ldb_message_element *spn_el = NULL;
936 struct ldb_message *tln_msg = NULL;
937 struct ldb_message_element *tln_el = NULL;
938 const char * const cross_attrs2[] = {
946 struct ldb_result *cross_res2 = NULL;
949 bool restart = false;
952 info = talloc_zero(mem_ctx, struct lsa_ForestTrustInformation);
955 return NT_STATUS_NO_MEMORY;
957 talloc_steal(frame, info);
959 partitions_dn = samdb_partitions_dn(sam_ctx, frame);
960 if (partitions_dn == NULL) {
962 return NT_STATUS_NO_MEMORY;
965 ret = dsdb_search_dn(sam_ctx, partitions_dn, &cross_res1,
966 partitions_dn, cross_attrs1, 0);
967 if (ret != LDB_SUCCESS) {
969 return dsdb_ldb_err_to_ntstatus(ret);
972 ret = dsdb_search(sam_ctx, partitions_dn, &cross_res2,
973 partitions_dn, LDB_SCOPE_ONELEVEL,
975 DSDB_SEARCH_SHOW_EXTENDED_DN,
976 "(&(objectClass=crossRef)"
977 "(systemFlags:%s:=%u))",
978 LDB_OID_COMPARATOR_AND,
979 SYSTEM_FLAG_CR_NTDS_DOMAIN);
980 if (ret != LDB_SUCCESS) {
982 return dsdb_ldb_err_to_ntstatus(ret);
986 * Sort the domains as trees, starting with the forest root
988 TYPESAFE_QSORT(cross_res2->msgs, cross_res2->count,
989 dsdb_trust_xref_sort_msgs);
991 upn_el = ldb_msg_find_element(cross_res1->msgs[0], "uPNSuffixes");
992 if (upn_el != NULL) {
993 upn_el->name = "__tln__";
995 spn_el = ldb_msg_find_element(cross_res1->msgs[0], "msDS-SPNSuffixes");
996 if (spn_el != NULL) {
997 spn_el->name = "__tln__";
999 ret = ldb_msg_normalize(sam_ctx, frame, cross_res1->msgs[0], &tln_msg);
1000 if (ret != LDB_SUCCESS) {
1002 return dsdb_ldb_err_to_ntstatus(ret);
1004 tln_el = ldb_msg_find_element(tln_msg, "__tln__");
1005 if (tln_el != NULL) {
1007 * Sort the domains as trees
1009 TYPESAFE_QSORT(tln_el->values, tln_el->num_values,
1010 dsdb_trust_xref_sort_vals);
1013 for (i=0; i < cross_res2->count; i++) {
1014 struct ldb_message *m = cross_res2->msgs[i];
1015 const char *dns = NULL;
1016 const char *netbios = NULL;
1017 struct ldb_dn *nc_dn = NULL;
1018 struct dom_sid sid = {
1021 struct lsa_ForestTrustRecord e = {
1024 struct lsa_ForestTrustDomainInfo *d = NULL;
1025 struct lsa_StringLarge *t = NULL;
1029 dns = ldb_msg_find_attr_as_string(m, "dnsRoot", NULL);
1032 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1035 netbios = ldb_msg_find_attr_as_string(m, "nETBIOSName", NULL);
1036 if (netbios == NULL) {
1038 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1041 nc_dn = samdb_result_dn(sam_ctx, m, m, "ncName", NULL);
1042 if (nc_dn == NULL) {
1044 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1047 status = dsdb_get_extended_dn_sid(nc_dn, &sid, "SID");
1048 if (!NT_STATUS_IS_OK(status)) {
1053 match = dsdb_trust_find_tln_match(info, dns);
1056 * First the TOP_LEVEL_NAME, if required
1058 e = (struct lsa_ForestTrustRecord) {
1060 .type = LSA_FOREST_TRUST_TOP_LEVEL_NAME,
1061 .time = 0, /* so far always 0 in traces. */
1064 t = &e.forest_trust_data.top_level_name;
1067 status = dsdb_trust_forest_info_add_record(info, &e);
1068 if (!NT_STATUS_IS_OK(status)) {
1075 * Then the DOMAIN_INFO
1077 e = (struct lsa_ForestTrustRecord) {
1079 .type = LSA_FOREST_TRUST_DOMAIN_INFO,
1080 .time = 0, /* so far always 0 in traces. */
1082 d = &e.forest_trust_data.domain_info;
1083 d->domain_sid = &sid;
1084 d->dns_domain_name.string = dns;
1085 d->netbios_domain_name.string = netbios;
1087 status = dsdb_trust_forest_info_add_record(info, &e);
1088 if (!NT_STATUS_IS_OK(status)) {
1094 for (i=0; (tln_el != NULL) && i < tln_el->num_values; i++) {
1095 const struct ldb_val *v = &tln_el->values[i];
1096 const char *dns = (const char *)v->data;
1097 struct lsa_ForestTrustRecord e = {
1100 struct lsa_StringLarge *t = NULL;
1106 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1109 match = dsdb_trust_find_tln_match(info, dns);
1115 * an additional the TOP_LEVEL_NAME
1117 e = (struct lsa_ForestTrustRecord) {
1119 .type = LSA_FOREST_TRUST_TOP_LEVEL_NAME,
1120 .time = 0, /* so far always 0 in traces. */
1122 t = &e.forest_trust_data.top_level_name;
1125 status = dsdb_trust_forest_info_add_record(info, &e);
1126 if (!NT_STATUS_IS_OK(status)) {
1132 for (i=0; i < info->count; restart ? i=0 : i++) {
1133 struct lsa_ForestTrustRecord *tr = info->entries[i];
1134 const struct lsa_StringLarge *ts = NULL;
1139 if (tr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
1143 ts = &tr->forest_trust_data.top_level_name;
1145 for (c = i + 1; c < info->count; c++) {
1146 struct lsa_ForestTrustRecord *cr = info->entries[c];
1147 const struct lsa_StringLarge *cs = NULL;
1151 if (cr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
1155 cs = &cr->forest_trust_data.top_level_name;
1157 cmp = dns_cmp(ts->string, cs->string);
1158 if (DNS_CMP_IS_NO_MATCH(cmp)) {
1161 if (cmp != DNS_CMP_FIRST_IS_CHILD) {
1162 /* can't happen ... */
1168 TALLOC_FREE(info->entries[i]);
1169 info->entries[i] = info->entries[c];
1171 for (j = c + 1; j < info->count; j++) {
1172 info->entries[j-1] = info->entries[j];
1180 *_info = talloc_move(mem_ctx, &info);
1182 return NT_STATUS_OK;
1185 NTSTATUS dsdb_trust_parse_tdo_info(TALLOC_CTX *mem_ctx,
1186 struct ldb_message *m,
1187 struct lsa_TrustDomainInfoInfoEx **_tdo)
1189 struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
1190 const char *dns = NULL;
1191 const char *netbios = NULL;
1195 tdo = talloc_zero(mem_ctx, struct lsa_TrustDomainInfoInfoEx);
1197 return NT_STATUS_NO_MEMORY;
1200 dns = ldb_msg_find_attr_as_string(m, "trustPartner", NULL);
1203 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1205 tdo->domain_name.string = talloc_strdup(tdo, dns);
1206 if (tdo->domain_name.string == NULL) {
1208 return NT_STATUS_NO_MEMORY;
1211 netbios = ldb_msg_find_attr_as_string(m, "flatName", NULL);
1212 if (netbios == NULL) {
1214 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1216 tdo->netbios_name.string = talloc_strdup(tdo, netbios);
1217 if (tdo->netbios_name.string == NULL) {
1219 return NT_STATUS_NO_MEMORY;
1222 tdo->sid = samdb_result_dom_sid(tdo, m, "securityIdentifier");
1223 if (tdo->sid == NULL) {
1225 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1228 tdo->trust_type = ldb_msg_find_attr_as_uint(m, "trustType", 0);
1229 tdo->trust_direction = ldb_msg_find_attr_as_uint(m, "trustDirection", 0);
1230 tdo->trust_attributes = ldb_msg_find_attr_as_uint(m, "trustAttributes", 0);
1233 return NT_STATUS_OK;
1236 NTSTATUS dsdb_trust_parse_forest_info(TALLOC_CTX *mem_ctx,
1237 struct ldb_message *m,
1238 struct ForestTrustInfo **_fti)
1240 const struct ldb_val *ft_blob = NULL;
1241 struct ForestTrustInfo *fti = NULL;
1242 enum ndr_err_code ndr_err;
1246 ft_blob = ldb_msg_find_ldb_val(m, "msDS-TrustForestTrustInfo");
1247 if (ft_blob == NULL) {
1248 return NT_STATUS_NOT_FOUND;
1251 fti = talloc_zero(mem_ctx, struct ForestTrustInfo);
1253 return NT_STATUS_NO_MEMORY;
1256 /* ldb_val is equivalent to DATA_BLOB */
1257 ndr_err = ndr_pull_struct_blob_all(ft_blob, fti, fti,
1258 (ndr_pull_flags_fn_t)ndr_pull_ForestTrustInfo);
1259 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1261 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1265 return NT_STATUS_OK;
1268 NTSTATUS dsdb_trust_normalize_forest_info_step1(TALLOC_CTX *mem_ctx,
1269 const struct lsa_ForestTrustInformation *gfti,
1270 struct lsa_ForestTrustInformation **_nfti)
1272 TALLOC_CTX *frame = talloc_stackframe();
1273 struct lsa_ForestTrustInformation *nfti;
1278 nfti = talloc_zero(mem_ctx, struct lsa_ForestTrustInformation);
1281 return NT_STATUS_NO_MEMORY;
1283 talloc_steal(frame, nfti);
1286 * First we copy every record and remove possible trailing dots
1289 * We also NULL out dublicates. The first one wins and
1290 * we keep 'count' as is. This is required in order to
1291 * provide the correct index for collision records.
1293 for (n = 0; n < gfti->count; n++) {
1294 const struct lsa_ForestTrustRecord *gftr = gfti->entries[n];
1295 struct lsa_ForestTrustRecord *nftr = NULL;
1296 struct lsa_ForestTrustDomainInfo *ninfo = NULL;
1297 struct lsa_StringLarge *ntln = NULL;
1298 struct lsa_StringLarge *nnb = NULL;
1299 struct dom_sid *nsid = NULL;
1307 return NT_STATUS_INVALID_PARAMETER;
1310 status = dsdb_trust_forest_info_add_record(nfti, gftr);
1311 if (!NT_STATUS_IS_OK(status)) {
1316 nftr = nfti->entries[n];
1318 switch (nftr->type) {
1319 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
1320 ntln = &nftr->forest_trust_data.top_level_name;
1323 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
1324 ntln = &nftr->forest_trust_data.top_level_name_ex;
1327 case LSA_FOREST_TRUST_DOMAIN_INFO:
1328 ninfo = &nftr->forest_trust_data.domain_info;
1329 ntln = &ninfo->dns_domain_name;
1330 nnb = &ninfo->netbios_domain_name;
1331 nsid = ninfo->domain_sid;
1336 return NT_STATUS_INVALID_PARAMETER;
1340 * We remove one trailing '.' before checking
1343 * domain.com. becomes domain.com
1344 * domain.com.. becomes domain.com.
1346 * Then the following is invalid:
1352 len = strlen(ntln->string);
1353 if (len > 1 && ntln->string[len - 1] == '.') {
1354 const char *cp = &ntln->string[len - 1];
1355 p = discard_const_p(char, cp);
1358 if (ntln->string[0] == '.') {
1360 return NT_STATUS_INVALID_PARAMETER;
1362 p = strstr_m(ntln->string, "..");
1365 return NT_STATUS_INVALID_PARAMETER;
1368 for (c = 0; c < n; c++) {
1369 const struct lsa_ForestTrustRecord *cftr = nfti->entries[c];
1370 const struct lsa_ForestTrustDomainInfo *cinfo = NULL;
1371 const struct lsa_StringLarge *ctln = NULL;
1372 const struct lsa_StringLarge *cnb = NULL;
1373 const struct dom_sid *csid = NULL;
1380 if (cftr->type != nftr->type) {
1384 switch (cftr->type) {
1385 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
1386 ctln = &cftr->forest_trust_data.top_level_name;
1389 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
1390 ctln = &cftr->forest_trust_data.top_level_name_ex;
1393 case LSA_FOREST_TRUST_DOMAIN_INFO:
1394 cinfo = &cftr->forest_trust_data.domain_info;
1395 ctln = &cinfo->dns_domain_name;
1396 cnb = &cinfo->netbios_domain_name;
1397 csid = cinfo->domain_sid;
1402 return NT_STATUS_INVALID_PARAMETER;
1405 cmp = dns_cmp(ntln->string, ctln->string);
1406 if (cmp == DNS_CMP_MATCH) {
1408 TALLOC_FREE(nfti->entries[n]);
1412 if (cinfo == NULL) {
1416 cmp = strcasecmp_m(nnb->string, cnb->string);
1419 TALLOC_FREE(nfti->entries[n]);
1423 cmp = dom_sid_compare(nsid, csid);
1426 TALLOC_FREE(nfti->entries[n]);
1433 * Now we check that only true top level names are provided
1435 for (n = 0; n < nfti->count; n++) {
1436 const struct lsa_ForestTrustRecord *nftr = nfti->entries[n];
1437 const struct lsa_StringLarge *ntln = NULL;
1444 if (nftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
1448 ntln = &nftr->forest_trust_data.top_level_name;
1450 for (c = 0; c < nfti->count; c++) {
1451 const struct lsa_ForestTrustRecord *cftr = nfti->entries[c];
1452 const struct lsa_StringLarge *ctln = NULL;
1463 if (cftr->type != nftr->type) {
1467 ctln = &cftr->forest_trust_data.top_level_name;
1469 cmp = dns_cmp(ntln->string, ctln->string);
1470 if (DNS_CMP_IS_NO_MATCH(cmp)) {
1475 return NT_STATUS_INVALID_PARAMETER;
1480 * Now we check that only true sub level excludes are provided
1482 for (n = 0; n < nfti->count; n++) {
1483 const struct lsa_ForestTrustRecord *nftr = nfti->entries[n];
1484 const struct lsa_StringLarge *ntln = NULL;
1486 bool found_tln = false;
1492 if (nftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX) {
1496 ntln = &nftr->forest_trust_data.top_level_name;
1498 for (c = 0; c < nfti->count; c++) {
1499 const struct lsa_ForestTrustRecord *cftr = nfti->entries[c];
1500 const struct lsa_StringLarge *ctln = NULL;
1511 if (cftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
1515 ctln = &cftr->forest_trust_data.top_level_name;
1517 cmp = dns_cmp(ntln->string, ctln->string);
1518 if (cmp == DNS_CMP_FIRST_IS_CHILD) {
1529 return NT_STATUS_INVALID_PARAMETER;
1533 * Now we check that there's a top level name for each domain
1535 for (n = 0; n < nfti->count; n++) {
1536 const struct lsa_ForestTrustRecord *nftr = nfti->entries[n];
1537 const struct lsa_ForestTrustDomainInfo *ninfo = NULL;
1538 const struct lsa_StringLarge *ntln = NULL;
1540 bool found_tln = false;
1546 if (nftr->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
1550 ninfo = &nftr->forest_trust_data.domain_info;
1551 ntln = &ninfo->dns_domain_name;
1553 for (c = 0; c < nfti->count; c++) {
1554 const struct lsa_ForestTrustRecord *cftr = nfti->entries[c];
1555 const struct lsa_StringLarge *ctln = NULL;
1566 if (cftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
1570 ctln = &cftr->forest_trust_data.top_level_name;
1572 cmp = dns_cmp(ntln->string, ctln->string);
1573 if (cmp == DNS_CMP_MATCH) {
1577 if (cmp == DNS_CMP_FIRST_IS_CHILD) {
1588 return NT_STATUS_INVALID_PARAMETER;
1591 *_nfti = talloc_move(mem_ctx, &nfti);
1593 return NT_STATUS_OK;
1596 NTSTATUS dsdb_trust_normalize_forest_info_step2(TALLOC_CTX *mem_ctx,
1597 const struct lsa_ForestTrustInformation *gfti,
1598 struct lsa_ForestTrustInformation **_nfti)
1600 TALLOC_CTX *frame = talloc_stackframe();
1601 struct timeval tv = timeval_current();
1602 NTTIME now = timeval_to_nttime(&tv);
1603 struct lsa_ForestTrustInformation *nfti;
1608 nfti = talloc_zero(mem_ctx, struct lsa_ForestTrustInformation);
1611 return NT_STATUS_NO_MEMORY;
1613 talloc_steal(frame, nfti);
1616 * Now we add TOP_LEVEL_NAME[_EX] in reverse order
1617 * followed by LSA_FOREST_TRUST_DOMAIN_INFO in reverse order.
1619 * This also removes the possible NULL entries generated in step1.
1622 for (g = 0; g < gfti->count; g++) {
1623 const struct lsa_ForestTrustRecord *gftr = gfti->entries[gfti->count - (g+1)];
1624 struct lsa_ForestTrustRecord tftr;
1632 switch (gftr->type) {
1633 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
1634 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
1637 case LSA_FOREST_TRUST_DOMAIN_INFO:
1643 return NT_STATUS_INVALID_PARAMETER;
1650 /* make a copy in order to update the time. */
1652 if (tftr.time == 0) {
1656 status = dsdb_trust_forest_info_add_record(nfti, &tftr);
1657 if (!NT_STATUS_IS_OK(status)) {
1663 for (g = 0; g < gfti->count; g++) {
1664 const struct lsa_ForestTrustRecord *gftr = gfti->entries[gfti->count - (g+1)];
1665 struct lsa_ForestTrustRecord tftr;
1673 switch (gftr->type) {
1674 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
1675 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
1679 case LSA_FOREST_TRUST_DOMAIN_INFO:
1684 return NT_STATUS_INVALID_PARAMETER;
1691 /* make a copy in order to update the time. */
1693 if (tftr.time == 0) {
1697 status = dsdb_trust_forest_info_add_record(nfti, &tftr);
1698 if (!NT_STATUS_IS_OK(status)) {
1704 *_nfti = talloc_move(mem_ctx, &nfti);
1706 return NT_STATUS_OK;
1709 static NTSTATUS dsdb_trust_add_collision(
1710 struct lsa_ForestTrustCollisionInfo *c_info,
1711 enum lsa_ForestTrustCollisionRecordType type,
1712 uint32_t idx, uint32_t flags,
1713 const char *tdo_name)
1715 struct lsa_ForestTrustCollisionRecord **es;
1716 uint32_t i = c_info->count;
1718 es = talloc_realloc(c_info, c_info->entries,
1719 struct lsa_ForestTrustCollisionRecord *, i + 1);
1721 return NT_STATUS_NO_MEMORY;
1723 c_info->entries = es;
1724 c_info->count = i + 1;
1726 es[i] = talloc_zero(es, struct lsa_ForestTrustCollisionRecord);
1727 if (es[i] == NULL) {
1728 return NT_STATUS_NO_MEMORY;
1733 es[i]->flags = flags;
1734 es[i]->name.string = talloc_strdup(es[i], tdo_name);
1735 if (es[i]->name.string == NULL) {
1736 return NT_STATUS_NO_MEMORY;
1739 return NT_STATUS_OK;
1742 NTSTATUS dsdb_trust_verify_forest_info(const struct lsa_TrustDomainInfoInfoEx *ref_tdo,
1743 const struct lsa_ForestTrustInformation *ref_fti,
1744 enum lsa_ForestTrustCollisionRecordType collision_type,
1745 struct lsa_ForestTrustCollisionInfo *c_info,
1746 struct lsa_ForestTrustInformation *new_fti)
1750 for (n = 0; n < new_fti->count; n++) {
1751 struct lsa_ForestTrustRecord *nftr = new_fti->entries[n];
1752 struct lsa_StringLarge *ntln = NULL;
1753 bool ntln_excluded = false;
1762 if (nftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
1766 ntln = &nftr->forest_trust_data.top_level_name;
1767 if (ntln->string == NULL) {
1768 return NT_STATUS_INVALID_PARAMETER;
1771 ntln_excluded = dsdb_trust_find_tln_ex_match(ref_fti,
1774 /* check if this is already taken and not excluded */
1775 for (r = 0; r < ref_fti->count; r++) {
1776 const struct lsa_ForestTrustRecord *rftr =
1777 ref_fti->entries[r];
1778 const struct lsa_StringLarge *rtln = NULL;
1785 if (rftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
1789 rtln = &rftr->forest_trust_data.top_level_name;
1790 if (rtln->string == NULL) {
1794 cmp = dns_cmp(ntln->string, rtln->string);
1795 if (DNS_CMP_IS_NO_MATCH(cmp)) {
1798 if (cmp == DNS_CMP_MATCH) {
1799 /* We need to normalize the string */
1800 ntln->string = talloc_strdup(nftr,
1802 if (ntln->string == NULL) {
1803 return NT_STATUS_NO_MEMORY;
1807 if (ntln_excluded) {
1811 if (rftr->flags & LSA_TLN_DISABLED_MASK) {
1815 if (nftr->flags & LSA_TLN_DISABLED_MASK) {
1819 if (cmp == DNS_CMP_SECOND_IS_CHILD) {
1823 * If the conflicting tln is a child, check if
1824 * we have an exclusion record for it.
1826 m = dsdb_trust_find_tln_ex_match(new_fti,
1833 flags |= LSA_TLN_DISABLED_CONFLICT;
1840 nftr->flags |= flags;
1842 status = dsdb_trust_add_collision(c_info,
1845 ref_tdo->domain_name.string);
1846 if (!NT_STATUS_IS_OK(status)) {
1851 for (n = 0; n < new_fti->count; n++) {
1852 struct lsa_ForestTrustRecord *nftr = new_fti->entries[n];
1853 struct lsa_ForestTrustDomainInfo *ninfo = NULL;
1854 struct lsa_StringLarge *ntln = NULL;
1855 struct lsa_StringLarge *nnb = NULL;
1856 struct dom_sid *nsid = NULL;
1857 bool ntln_found = false;
1866 if (nftr->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
1870 ninfo = &nftr->forest_trust_data.domain_info;
1871 ntln = &ninfo->dns_domain_name;
1872 if (ntln->string == NULL) {
1873 return NT_STATUS_INVALID_PARAMETER;
1875 nnb = &ninfo->netbios_domain_name;
1876 if (nnb->string == NULL) {
1877 return NT_STATUS_INVALID_PARAMETER;
1879 nsid = ninfo->domain_sid;
1881 return NT_STATUS_INVALID_PARAMETER;
1884 ntln_found = dsdb_trust_find_tln_match(ref_fti, ntln->string);
1886 /* check if this is already taken and not excluded */
1887 for (r = 0; r < ref_fti->count; r++) {
1888 const struct lsa_ForestTrustRecord *rftr =
1889 ref_fti->entries[r];
1890 const struct lsa_ForestTrustDomainInfo *rinfo = NULL;
1891 const struct lsa_StringLarge *rtln = NULL;
1892 const struct lsa_StringLarge *rnb = NULL;
1893 const struct dom_sid *rsid = NULL;
1894 bool nb_possible = true;
1895 bool sid_possible = true;
1904 * If the dns name doesn't match any existing
1905 * tln any conflict is ignored, but name
1906 * normalization still happens.
1908 * I guess that's a bug in Windows
1909 * (tested with Windows 2012r2).
1911 nb_possible = false;
1912 sid_possible = false;
1915 if (nftr->flags & LSA_SID_DISABLED_MASK) {
1916 sid_possible = false;
1919 if (nftr->flags & LSA_NB_DISABLED_MASK) {
1920 nb_possible = false;
1923 switch (rftr->type) {
1924 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
1925 rtln = &rftr->forest_trust_data.top_level_name;
1926 nb_possible = false;
1927 sid_possible = false;
1930 case LSA_FOREST_TRUST_DOMAIN_INFO:
1931 rinfo = &rftr->forest_trust_data.domain_info;
1932 rtln = &rinfo->dns_domain_name;
1933 rnb = &rinfo->netbios_domain_name;
1934 rsid = rinfo->domain_sid;
1936 if (rftr->flags & LSA_SID_DISABLED_MASK) {
1937 sid_possible = false;
1940 if (rftr->flags & LSA_NB_DISABLED_MASK) {
1941 nb_possible = false;
1953 if (rtln->string == NULL) {
1957 cmp = dns_cmp(ntln->string, rtln->string);
1958 if (DNS_CMP_IS_NO_MATCH(cmp)) {
1959 nb_possible = false;
1960 sid_possible = false;
1962 if (cmp == DNS_CMP_MATCH) {
1963 /* We need to normalize the string */
1964 ntln->string = talloc_strdup(nftr,
1966 if (ntln->string == NULL) {
1967 return NT_STATUS_NO_MEMORY;
1971 if (rinfo == NULL) {
1976 cmp = dom_sid_compare(nsid, rsid);
1982 flags |= LSA_SID_DISABLED_CONFLICT;
1986 if (rnb->string != NULL) {
1987 cmp = strcasecmp_m(nnb->string, rnb->string);
1992 nnb->string = talloc_strdup(nftr, rnb->string);
1993 if (nnb->string == NULL) {
1994 return NT_STATUS_NO_MEMORY;
1997 flags |= LSA_NB_DISABLED_CONFLICT;
2006 nftr->flags |= flags;
2008 status = dsdb_trust_add_collision(c_info,
2011 ref_tdo->domain_name.string);
2012 if (!NT_STATUS_IS_OK(status)) {
2017 return NT_STATUS_OK;
2020 NTSTATUS dsdb_trust_merge_forest_info(TALLOC_CTX *mem_ctx,
2021 const struct lsa_TrustDomainInfoInfoEx *tdo,
2022 const struct lsa_ForestTrustInformation *ofti,
2023 const struct lsa_ForestTrustInformation *nfti,
2024 struct lsa_ForestTrustInformation **_mfti)
2026 TALLOC_CTX *frame = talloc_stackframe();
2027 struct lsa_ForestTrustInformation *mfti = NULL;
2034 mfti = talloc_zero(mem_ctx, struct lsa_ForestTrustInformation);
2037 return NT_STATUS_NO_MEMORY;
2039 talloc_steal(frame, mfti);
2042 * First we add all top unique level names.
2044 * The one matching the tdo dns name, will be
2045 * added without further checking. All others
2046 * may keep the flags and time values.
2048 for (ni = 0; ni < nfti->count; ni++) {
2049 const struct lsa_ForestTrustRecord *nftr = nfti->entries[ni];
2050 struct lsa_ForestTrustRecord tftr = {
2053 const char *ndns = NULL;
2054 bool ignore_new = false;
2055 bool found_old = false;
2060 return NT_STATUS_INVALID_PARAMETER;
2063 if (nftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
2067 ndns = nftr->forest_trust_data.top_level_name.string;
2070 return NT_STATUS_INVALID_PARAMETER;
2073 cmp = dns_cmp(tdo->domain_name.string, ndns);
2074 if (cmp == DNS_CMP_MATCH) {
2075 status = dsdb_trust_forest_info_add_record(mfti, nftr);
2076 if (!NT_STATUS_IS_OK(status)) {
2082 for (mi = 0; mi < mfti->count; mi++) {
2083 const struct lsa_ForestTrustRecord *mftr =
2085 const char *mdns = NULL;
2088 * we just added this above, so we're sure to have a
2089 * valid LSA_FOREST_TRUST_TOP_LEVEL_NAME record
2091 mdns = mftr->forest_trust_data.top_level_name.string;
2093 cmp = dns_cmp(mdns, ndns);
2096 case DNS_CMP_SECOND_IS_CHILD:
2111 * make a temporary copy where we can change time and flags
2115 for (oi = 0; oi < ofti->count; oi++) {
2116 const struct lsa_ForestTrustRecord *oftr =
2118 const char *odns = NULL;
2122 * broken record => ignore...
2127 if (oftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
2131 odns = oftr->forest_trust_data.top_level_name.string;
2134 * broken record => ignore...
2139 cmp = dns_cmp(odns, ndns);
2140 if (cmp != DNS_CMP_MATCH) {
2145 tftr.flags = oftr->flags;
2146 tftr.time = oftr->time;
2150 tftr.flags = LSA_TLN_DISABLED_NEW;
2154 status = dsdb_trust_forest_info_add_record(mfti, &tftr);
2155 if (!NT_STATUS_IS_OK(status)) {
2162 * Now we add all unique (based on their SID) domains
2163 * and may keep the flags and time values.
2165 for (ni = 0; ni < nfti->count; ni++) {
2166 const struct lsa_ForestTrustRecord *nftr = nfti->entries[ni];
2167 struct lsa_ForestTrustRecord tftr = {
2170 const struct lsa_ForestTrustDomainInfo *nd = NULL;
2171 const char *ndns = NULL;
2172 const char *nnbt = NULL;
2173 bool ignore_new = false;
2174 bool found_old = false;
2179 return NT_STATUS_INVALID_PARAMETER;
2182 if (nftr->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
2186 nd = &nftr->forest_trust_data.domain_info;
2187 if (nd->domain_sid == NULL) {
2189 return NT_STATUS_INVALID_PARAMETER;
2191 ndns = nd->dns_domain_name.string;
2194 return NT_STATUS_INVALID_PARAMETER;
2196 nnbt = nd->netbios_domain_name.string;
2199 return NT_STATUS_INVALID_PARAMETER;
2202 for (mi = 0; mi < mfti->count; mi++) {
2203 const struct lsa_ForestTrustRecord *mftr =
2205 const struct lsa_ForestTrustDomainInfo *md = NULL;
2207 if (mftr->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
2212 * we just added this above, so we're sure to have a
2213 * valid LSA_FOREST_TRUST_DOMAIN_INFO record
2215 md = &mftr->forest_trust_data.domain_info;
2217 cmp = dom_sid_compare(nd->domain_sid, md->domain_sid);
2229 * make a temporary copy where we can change time and flags
2233 for (oi = 0; oi < ofti->count; oi++) {
2234 const struct lsa_ForestTrustRecord *oftr =
2236 const struct lsa_ForestTrustDomainInfo *od = NULL;
2237 const char *onbt = NULL;
2241 * broken record => ignore...
2246 if (oftr->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
2250 od = &oftr->forest_trust_data.domain_info;
2251 onbt = od->netbios_domain_name.string;
2254 * broken record => ignore...
2259 cmp = strcasecmp(onbt, nnbt);
2265 tftr.flags = oftr->flags;
2266 tftr.time = oftr->time;
2274 status = dsdb_trust_forest_info_add_record(mfti, &tftr);
2275 if (!NT_STATUS_IS_OK(status)) {
2282 * We keep old domain records disabled by the admin
2283 * if not already in the list.
2285 for (oi = 0; oi < ofti->count; oi++) {
2286 const struct lsa_ForestTrustRecord *oftr =
2288 const struct lsa_ForestTrustDomainInfo *od = NULL;
2289 const char *odns = NULL;
2290 const char *onbt = NULL;
2291 bool ignore_old = true;
2296 * broken record => ignore...
2301 if (oftr->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
2305 od = &oftr->forest_trust_data.domain_info;
2306 odns = od->dns_domain_name.string;
2309 * broken record => ignore...
2313 onbt = od->netbios_domain_name.string;
2316 * broken record => ignore...
2320 if (od->domain_sid == NULL) {
2322 * broken record => ignore...
2327 if (oftr->flags & LSA_NB_DISABLED_ADMIN) {
2329 } else if (oftr->flags & LSA_SID_DISABLED_ADMIN) {
2333 for (mi = 0; mi < mfti->count; mi++) {
2334 const struct lsa_ForestTrustRecord *mftr =
2336 const struct lsa_ForestTrustDomainInfo *md = NULL;
2338 if (mftr->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
2343 * we just added this above, so we're sure to have a
2344 * valid LSA_FOREST_TRUST_DOMAIN_INFO record
2346 md = &mftr->forest_trust_data.domain_info;
2348 cmp = dom_sid_compare(od->domain_sid, md->domain_sid);
2359 status = dsdb_trust_forest_info_add_record(mfti, oftr);
2360 if (!NT_STATUS_IS_OK(status)) {
2367 * Finally we readd top level exclusions,
2368 * if they still match a top level name.
2370 for (oi = 0; oi < ofti->count; oi++) {
2371 const struct lsa_ForestTrustRecord *oftr =
2373 const char *odns = NULL;
2374 bool ignore_old = false;
2379 * broken record => ignore...
2384 if (oftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX) {
2388 odns = oftr->forest_trust_data.top_level_name_ex.string;
2391 * broken record => ignore...
2396 for (mi = 0; mi < mfti->count; mi++) {
2397 const struct lsa_ForestTrustRecord *mftr =
2399 const char *mdns = NULL;
2401 if (mftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
2406 * we just added this above, so we're sure to have a
2407 * valid LSA_FOREST_TRUST_TOP_LEVEL_NAME.
2409 mdns = mftr->forest_trust_data.top_level_name.string;
2411 cmp = dns_cmp(mdns, odns);
2414 case DNS_CMP_SECOND_IS_CHILD:
2430 status = dsdb_trust_forest_info_add_record(mfti, oftr);
2431 if (!NT_STATUS_IS_OK(status)) {
2437 *_mfti = talloc_move(mem_ctx, &mfti);
2439 return NT_STATUS_OK;
2442 NTSTATUS dsdb_trust_search_tdo(struct ldb_context *sam_ctx,
2443 const char *netbios, const char *dns,
2444 const char * const *attrs,
2445 TALLOC_CTX *mem_ctx,
2446 struct ldb_message **msg)
2448 TALLOC_CTX *frame = talloc_stackframe();
2450 struct ldb_dn *system_dn = NULL;
2451 char *netbios_encoded = NULL;
2452 char *dns_encoded = NULL;
2453 char *filter = NULL;
2457 if (netbios == NULL && dns == NULL) {
2459 return NT_STATUS_INVALID_PARAMETER_MIX;
2462 system_dn = ldb_dn_copy(frame, ldb_get_default_basedn(sam_ctx));
2463 if (system_dn == NULL) {
2465 return NT_STATUS_NO_MEMORY;
2468 if (!ldb_dn_add_child_fmt(system_dn, "CN=System")) {
2470 return NT_STATUS_NO_MEMORY;
2473 if (netbios != NULL) {
2474 netbios_encoded = ldb_binary_encode_string(frame, netbios);
2475 if (netbios_encoded == NULL) {
2477 return NT_STATUS_NO_MEMORY;
2482 dns_encoded = ldb_binary_encode_string(frame, dns);
2483 if (dns_encoded == NULL) {
2485 return NT_STATUS_NO_MEMORY;
2489 if (netbios != NULL && dns != NULL) {
2490 filter = talloc_asprintf(frame,
2491 "(&(objectClass=trustedDomain)"
2492 "(|(trustPartner=%s)(flatName=%s))"
2494 dns_encoded, netbios_encoded);
2495 if (filter == NULL) {
2497 return NT_STATUS_NO_MEMORY;
2499 } else if (netbios != NULL) {
2500 filter = talloc_asprintf(frame,
2501 "(&(objectClass=trustedDomain)(flatName=%s))",
2503 if (filter == NULL) {
2505 return NT_STATUS_NO_MEMORY;
2507 } else if (dns != NULL) {
2508 filter = talloc_asprintf(frame,
2509 "(&(objectClass=trustedDomain)(trustPartner=%s))",
2511 if (filter == NULL) {
2513 return NT_STATUS_NO_MEMORY;
2517 ret = dsdb_search_one(sam_ctx, mem_ctx, msg,
2519 LDB_SCOPE_ONELEVEL, attrs,
2520 DSDB_SEARCH_NO_GLOBAL_CATALOG,
2522 if (ret != LDB_SUCCESS) {
2523 NTSTATUS status = dsdb_ldb_err_to_ntstatus(ret);
2524 DEBUG(3, ("Failed to search for %s: %s - %s\n",
2525 filter, nt_errstr(status), ldb_errstring(sam_ctx)));
2531 return NT_STATUS_OK;
2534 NTSTATUS dsdb_trust_search_tdo_by_type(struct ldb_context *sam_ctx,
2535 enum netr_SchannelType type,
2537 const char * const *attrs,
2538 TALLOC_CTX *mem_ctx,
2539 struct ldb_message **msg)
2541 TALLOC_CTX *frame = talloc_stackframe();
2545 bool require_trailer = true;
2546 char *encoded_name = NULL;
2547 const char *netbios = NULL;
2548 const char *dns = NULL;
2550 if (type != SEC_CHAN_DOMAIN && type != SEC_CHAN_DNS_DOMAIN) {
2552 return NT_STATUS_INVALID_PARAMETER;
2555 if (type == SEC_CHAN_DNS_DOMAIN) {
2557 require_trailer = false;
2560 encoded_name = ldb_binary_encode_string(frame, name);
2561 if (encoded_name == NULL) {
2563 return NT_STATUS_NO_MEMORY;
2566 len = strlen(encoded_name);
2569 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2572 if (require_trailer && encoded_name[len - 1] != trailer) {
2574 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2576 encoded_name[len - 1] = '\0';
2578 if (type == SEC_CHAN_DNS_DOMAIN) {
2581 netbios = encoded_name;
2584 status = dsdb_trust_search_tdo(sam_ctx, netbios, dns,
2585 attrs, mem_ctx, msg);
2586 if (!NT_STATUS_IS_OK(status)) {
2592 return NT_STATUS_OK;
2595 NTSTATUS dsdb_trust_search_tdo_by_sid(struct ldb_context *sam_ctx,
2596 const struct dom_sid *sid,
2597 const char * const *attrs,
2598 TALLOC_CTX *mem_ctx,
2599 struct ldb_message **msg)
2601 TALLOC_CTX *frame = talloc_stackframe();
2603 struct ldb_dn *system_dn = NULL;
2604 char *encoded_sid = NULL;
2605 char *filter = NULL;
2611 return NT_STATUS_INVALID_PARAMETER_MIX;
2614 encoded_sid = ldap_encode_ndr_dom_sid(frame, sid);
2615 if (encoded_sid == NULL) {
2617 return NT_STATUS_NO_MEMORY;
2620 system_dn = ldb_dn_copy(frame, ldb_get_default_basedn(sam_ctx));
2621 if (system_dn == NULL) {
2623 return NT_STATUS_NO_MEMORY;
2626 if (!ldb_dn_add_child_fmt(system_dn, "CN=System")) {
2628 return NT_STATUS_NO_MEMORY;
2631 filter = talloc_asprintf(frame,
2633 "(objectClass=trustedDomain)"
2634 "(securityIdentifier=%s)"
2637 if (filter == NULL) {
2639 return NT_STATUS_NO_MEMORY;
2642 ret = dsdb_search_one(sam_ctx, mem_ctx, msg,
2644 LDB_SCOPE_ONELEVEL, attrs,
2645 DSDB_SEARCH_NO_GLOBAL_CATALOG,
2647 if (ret != LDB_SUCCESS) {
2648 NTSTATUS status = dsdb_ldb_err_to_ntstatus(ret);
2649 DEBUG(3, ("Failed to search for %s: %s - %s\n",
2650 filter, nt_errstr(status), ldb_errstring(sam_ctx)));
2656 return NT_STATUS_OK;
2659 NTSTATUS dsdb_trust_get_incoming_passwords(struct ldb_message *msg,
2660 TALLOC_CTX *mem_ctx,
2661 struct samr_Password **_current,
2662 struct samr_Password **_previous)
2664 TALLOC_CTX *frame = talloc_stackframe();
2665 struct samr_Password __current = {
2668 struct samr_Password __previous = {
2671 struct samr_Password *current = NULL;
2672 struct samr_Password *previous = NULL;
2673 const struct ldb_val *blob = NULL;
2674 enum ndr_err_code ndr_err;
2675 struct trustAuthInOutBlob incoming = {
2680 if (_current != NULL) {
2683 if (_previous != NULL) {
2687 blob = ldb_msg_find_ldb_val(msg, "trustAuthIncoming");
2690 return NT_STATUS_ACCOUNT_DISABLED;
2693 /* ldb_val is equivalent to DATA_BLOB */
2694 ndr_err = ndr_pull_struct_blob_all(blob, frame, &incoming,
2695 (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
2696 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2698 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2701 for (i = 0; i < incoming.current.count; i++) {
2702 struct AuthenticationInformation *a =
2703 &incoming.current.array[i];
2705 if (current != NULL) {
2709 switch (a->AuthType) {
2710 case TRUST_AUTH_TYPE_NONE:
2711 case TRUST_AUTH_TYPE_VERSION:
2713 case TRUST_AUTH_TYPE_NT4OWF:
2714 current = &a->AuthInfo.nt4owf.password;
2716 case TRUST_AUTH_TYPE_CLEAR:
2717 mdfour(__current.hash,
2718 a->AuthInfo.clear.password,
2719 a->AuthInfo.clear.size);
2720 current = &__current;
2725 if (current == NULL) {
2727 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2730 for (i = 0; i < incoming.previous.count; i++) {
2731 struct AuthenticationInformation *a =
2732 &incoming.previous.array[i];
2734 if (previous != NULL) {
2738 switch (a->AuthType) {
2739 case TRUST_AUTH_TYPE_NONE:
2740 case TRUST_AUTH_TYPE_VERSION:
2742 case TRUST_AUTH_TYPE_NT4OWF:
2743 previous = &a->AuthInfo.nt4owf.password;
2745 case TRUST_AUTH_TYPE_CLEAR:
2746 mdfour(__previous.hash,
2747 a->AuthInfo.clear.password,
2748 a->AuthInfo.clear.size);
2749 previous = &__previous;
2754 if (previous == NULL) {
2758 if (_current != NULL) {
2759 *_current = talloc(mem_ctx, struct samr_Password);
2760 if (*_current == NULL) {
2762 return NT_STATUS_NO_MEMORY;
2764 **_current = *current;
2766 if (_previous != NULL) {
2767 *_previous = talloc(mem_ctx, struct samr_Password);
2768 if (*_previous == NULL) {
2769 if (_current != NULL) {
2770 TALLOC_FREE(*_current);
2773 return NT_STATUS_NO_MEMORY;
2775 **_previous = *previous;
2777 ZERO_STRUCTP(current);
2778 ZERO_STRUCTP(previous);
2780 return NT_STATUS_OK;
2783 NTSTATUS dsdb_trust_search_tdos(struct ldb_context *sam_ctx,
2784 const char *exclude,
2785 const char * const *attrs,
2786 TALLOC_CTX *mem_ctx,
2787 struct ldb_result **res)
2789 TALLOC_CTX *frame = talloc_stackframe();
2791 struct ldb_dn *system_dn = NULL;
2792 const char *filter = NULL;
2793 char *exclude_encoded = NULL;
2797 system_dn = ldb_dn_copy(frame, ldb_get_default_basedn(sam_ctx));
2798 if (system_dn == NULL) {
2800 return NT_STATUS_NO_MEMORY;
2803 if (!ldb_dn_add_child_fmt(system_dn, "CN=System")) {
2805 return NT_STATUS_NO_MEMORY;
2808 if (exclude != NULL) {
2809 exclude_encoded = ldb_binary_encode_string(frame, exclude);
2810 if (exclude_encoded == NULL) {
2812 return NT_STATUS_NO_MEMORY;
2815 filter = talloc_asprintf(frame,
2816 "(&(objectClass=trustedDomain)"
2817 "(!(|(trustPartner=%s)(flatName=%s)))"
2819 exclude_encoded, exclude_encoded);
2820 if (filter == NULL) {
2822 return NT_STATUS_NO_MEMORY;
2825 filter = "(objectClass=trustedDomain)";
2828 ret = dsdb_search(sam_ctx, mem_ctx, res,
2830 LDB_SCOPE_ONELEVEL, attrs,
2831 DSDB_SEARCH_NO_GLOBAL_CATALOG,
2833 if (ret != LDB_SUCCESS) {
2834 NTSTATUS status = dsdb_ldb_err_to_ntstatus(ret);
2835 DEBUG(3, ("Failed to search for %s: %s - %s\n",
2836 filter, nt_errstr(status), ldb_errstring(sam_ctx)));
2842 return NT_STATUS_OK;
2845 struct dsdb_trust_routing_domain;
2847 struct dsdb_trust_routing_table {
2848 struct dsdb_trust_routing_domain *domains;
2851 struct dsdb_trust_routing_domain {
2852 struct dsdb_trust_routing_domain *prev, *next;
2854 struct lsa_TrustDomainInfoInfoEx *tdo;
2856 struct lsa_ForestTrustDomainInfo di;
2858 struct lsa_ForestTrustInformation *fti;
2861 NTSTATUS dsdb_trust_routing_table_load(struct ldb_context *sam_ctx,
2862 TALLOC_CTX *mem_ctx,
2863 struct dsdb_trust_routing_table **_table)
2865 TALLOC_CTX *frame = talloc_stackframe();
2866 struct dsdb_trust_routing_table *table;
2867 struct dsdb_trust_routing_domain *d = NULL;
2868 struct ldb_dn *domain_dn = NULL;
2869 struct lsa_TrustDomainInfoInfoEx *root_trust_tdo = NULL;
2870 struct lsa_TrustDomainInfoInfoEx *trust_parent_tdo = NULL;
2871 struct lsa_TrustDomainInfoInfoEx *root_direction_tdo = NULL;
2872 const char * const trusts_attrs[] = {
2873 "securityIdentifier",
2879 "msDS-TrustForestTrustInfo",
2882 struct ldb_result *trusts_res = NULL;
2888 domain_dn = ldb_get_default_basedn(sam_ctx);
2889 if (domain_dn == NULL) {
2891 return NT_STATUS_INTERNAL_ERROR;
2894 table = talloc_zero(mem_ctx, struct dsdb_trust_routing_table);
2895 if (table == NULL) {
2897 return NT_STATUS_NO_MEMORY;
2899 talloc_steal(frame, table);
2901 d = talloc_zero(table, struct dsdb_trust_routing_domain);
2904 return NT_STATUS_NO_MEMORY;
2907 status = dsdb_trust_crossref_tdo_info(d, sam_ctx,
2912 if (!NT_STATUS_IS_OK(status)) {
2918 * d->tdo should not be NULL of status above is 'NT_STATUS_OK'
2919 * check is needed to satisfy clang static checker
2921 if (d->tdo == NULL) {
2923 return NT_STATUS_NO_MEMORY;
2925 d->di.domain_sid = d->tdo->sid;
2926 d->di.netbios_domain_name.string = d->tdo->netbios_name.string;
2927 d->di.dns_domain_name.string = d->tdo->domain_name.string;
2929 if (root_trust_tdo != NULL) {
2930 root_direction_tdo = root_trust_tdo;
2931 } else if (trust_parent_tdo != NULL) {
2932 root_direction_tdo = trust_parent_tdo;
2935 if (root_direction_tdo == NULL) {
2936 /* we're the forest root */
2937 status = dsdb_trust_xref_forest_info(d, sam_ctx, &d->fti);
2938 if (!NT_STATUS_IS_OK(status)) {
2944 DLIST_ADD(table->domains, d);
2946 status = dsdb_trust_search_tdos(sam_ctx, NULL, trusts_attrs,
2947 frame, &trusts_res);
2948 if (!NT_STATUS_IS_OK(status)) {
2953 for (i = 0; i < trusts_res->count; i++) {
2957 d = talloc_zero(table, struct dsdb_trust_routing_domain);
2960 return NT_STATUS_NO_MEMORY;
2963 status = dsdb_trust_parse_tdo_info(d,
2964 trusts_res->msgs[i],
2966 if (!NT_STATUS_IS_OK(status)) {
2971 d->di.domain_sid = d->tdo->sid;
2972 d->di.netbios_domain_name.string = d->tdo->netbios_name.string;
2973 d->di.dns_domain_name.string = d->tdo->domain_name.string;
2975 DLIST_ADD_END(table->domains, d);
2977 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
2978 struct ForestTrustInfo *fti = NULL;
2980 status = dsdb_trust_parse_forest_info(frame,
2981 trusts_res->msgs[i],
2983 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2985 status = NT_STATUS_OK;
2987 if (!NT_STATUS_IS_OK(status)) {
2996 status = dsdb_trust_forest_info_to_lsa(d, fti, &d->fti);
2997 if (!NT_STATUS_IS_OK(status)) {
3005 if (!(d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST)) {
3009 if (root_direction_tdo == NULL) {
3013 ok = dom_sid_equal(root_direction_tdo->sid, d->tdo->sid);
3018 cmp = strcasecmp_m(root_direction_tdo->netbios_name.string,
3019 d->tdo->netbios_name.string);
3024 cmp = strcasecmp_m(root_direction_tdo->domain_name.string,
3025 d->tdo->domain_name.string);
3030 /* this our route to the forest root */
3031 status = dsdb_trust_xref_forest_info(d, sam_ctx, &d->fti);
3032 if (!NT_STATUS_IS_OK(status)) {
3038 *_table = talloc_move(mem_ctx, &table);
3040 return NT_STATUS_OK;
3043 static void dsdb_trust_update_best_tln(
3044 const struct dsdb_trust_routing_domain **best_d,
3045 const char **best_tln,
3046 const struct dsdb_trust_routing_domain *d,
3051 if (*best_tln == NULL) {
3057 cmp = dns_cmp(*best_tln, tln);
3058 if (cmp != DNS_CMP_FIRST_IS_CHILD) {
3066 const struct lsa_TrustDomainInfoInfoEx *dsdb_trust_routing_by_name(
3067 const struct dsdb_trust_routing_table *table,
3070 const struct dsdb_trust_routing_domain *best_d = NULL;
3071 const char *best_tln = NULL;
3072 const struct dsdb_trust_routing_domain *d = NULL;
3078 for (d = table->domains; d != NULL; d = d->next) {
3079 bool transitive = false;
3080 bool allow_netbios = false;
3081 bool exclude = false;
3084 if (d->tdo->trust_type != LSA_TRUST_TYPE_UPLEVEL) {
3086 * Only uplevel trusts have top level names
3091 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
3095 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
3099 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE) {
3103 if (d->tdo->trust_type != LSA_TRUST_TYPE_UPLEVEL) {
3107 switch (d->tdo->trust_type) {
3108 case LSA_TRUST_TYPE_UPLEVEL:
3109 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_UPLEVEL_ONLY) {
3112 allow_netbios = true;
3114 case LSA_TRUST_TYPE_DOWNLEVEL:
3115 allow_netbios = true;
3118 allow_netbios = false;
3122 if (!transitive || d->fti == NULL) {
3125 if (allow_netbios) {
3126 cmp = dns_cmp(name, d->tdo->netbios_name.string);
3127 if (cmp == DNS_CMP_MATCH) {
3135 cmp = dns_cmp(name, d->tdo->domain_name.string);
3136 if (cmp == DNS_CMP_MATCH) {
3142 if (cmp != DNS_CMP_FIRST_IS_CHILD) {
3150 dsdb_trust_update_best_tln(&best_d, &best_tln, d,
3151 d->tdo->domain_name.string);
3155 exclude = dsdb_trust_find_tln_ex_match(d->fti, name);
3160 for (i = 0; i < d->fti->count; i++ ) {
3161 const struct lsa_ForestTrustRecord *f = d->fti->entries[i];
3162 const struct lsa_ForestTrustDomainInfo *di = NULL;
3163 const char *fti_nbt = NULL;
3166 if (!allow_netbios) {
3175 if (f->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
3179 if (f->flags & LSA_NB_DISABLED_MASK) {
3181 * any flag disables the entry.
3186 di = &f->forest_trust_data.domain_info;
3187 fti_nbt = di->netbios_domain_name.string;
3188 if (fti_nbt == NULL) {
3193 cmp = dns_cmp(name, fti_nbt);
3194 if (cmp == DNS_CMP_MATCH) {
3202 for (i = 0; i < d->fti->count; i++ ) {
3203 const struct lsa_ForestTrustRecord *f = d->fti->entries[i];
3204 const union lsa_ForestTrustData *u = NULL;
3205 const char *fti_tln = NULL;
3213 if (f->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
3217 if (f->flags & LSA_TLN_DISABLED_MASK) {
3219 * any flag disables the entry.
3224 u = &f->forest_trust_data;
3225 fti_tln = u->top_level_name.string;
3226 if (fti_tln == NULL) {
3230 cmp = dns_cmp(name, fti_tln);
3233 case DNS_CMP_FIRST_IS_CHILD:
3234 dsdb_trust_update_best_tln(&best_d, &best_tln,
3243 if (best_d != NULL) {
3250 const struct lsa_TrustDomainInfoInfoEx *dsdb_trust_domain_by_sid(
3251 const struct dsdb_trust_routing_table *table,
3252 const struct dom_sid *sid,
3253 const struct lsa_ForestTrustDomainInfo **pdi)
3255 const struct dsdb_trust_routing_domain *d = NULL;
3265 for (d = table->domains; d != NULL; d = d->next) {
3266 bool transitive = false;
3269 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
3273 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
3277 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE) {
3281 if (d->tdo->trust_type != LSA_TRUST_TYPE_UPLEVEL) {
3285 if (!transitive || d->fti == NULL) {
3288 match = dom_sid_equal(d->di.domain_sid, sid);
3291 * exact match, it's the domain itself.
3301 for (i = 0; i < d->fti->count; i++ ) {
3302 const struct lsa_ForestTrustRecord *f = d->fti->entries[i];
3303 const struct lsa_ForestTrustDomainInfo *di = NULL;
3304 const struct dom_sid *fti_sid = NULL;
3312 if (f->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
3316 if (f->flags & LSA_SID_DISABLED_MASK) {
3318 * any flag disables the entry.
3323 di = &f->forest_trust_data.domain_info;
3324 fti_sid = di->domain_sid;
3325 if (fti_sid == NULL) {
3330 match = dom_sid_equal(fti_sid, sid);
3333 * exact match, it's a domain in the forest.
3346 const struct lsa_TrustDomainInfoInfoEx *dsdb_trust_domain_by_name(
3347 const struct dsdb_trust_routing_table *table,
3349 const struct lsa_ForestTrustDomainInfo **pdi)
3351 const struct dsdb_trust_routing_domain *d = NULL;
3361 for (d = table->domains; d != NULL; d = d->next) {
3362 bool transitive = false;
3365 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
3369 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
3373 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE) {
3377 if (d->tdo->trust_type != LSA_TRUST_TYPE_UPLEVEL) {
3381 if (!transitive || d->fti == NULL) {
3384 match = strequal_m(d->di.netbios_domain_name.string,
3388 * exact match for netbios name,
3389 * it's the domain itself.
3396 match = strequal_m(d->di.dns_domain_name.string,
3400 * exact match for dns name,
3401 * it's the domain itself.
3411 for (i = 0; i < d->fti->count; i++ ) {
3412 const struct lsa_ForestTrustRecord *f = d->fti->entries[i];
3413 const struct lsa_ForestTrustDomainInfo *di = NULL;
3421 if (f->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
3424 di = &f->forest_trust_data.domain_info;
3426 if (!(f->flags & LSA_NB_DISABLED_MASK)) {
3427 match = strequal_m(di->netbios_domain_name.string,
3431 * exact match for netbios name,
3432 * it's a domain in the forest.
3441 if (!(f->flags & LSA_TLN_DISABLED_MASK)) {
3442 match = strequal_m(di->dns_domain_name.string,
3446 * exact match for dns name,
3447 * it's a domain in the forest.