s3: tests: Add new test_stream_dir_rename.sh test.
[Samba.git] / source4 / dsdb / common / util_trusts.c
blob0f4d5584192edc4357370b3402607892ad7ef7d4
1 /*
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/>.
20 #include "includes.h"
21 #include "ldb.h"
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"
38 #undef strcasecmp
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;
45 uint32_t i;
47 *_fti = NULL;
49 fti = talloc_zero(mem_ctx, struct ForestTrustInfo);
50 if (fti == NULL) {
51 return NT_STATUS_NO_MEMORY;
54 fti->version = 1;
55 fti->count = lfti->count;
56 fti->records = talloc_zero_array(mem_ctx,
57 struct ForestTrustInfoRecordArmor,
58 fti->count);
59 if (fti->records == NULL) {
60 TALLOC_FREE(fti);
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;
72 if (lftr == NULL) {
73 TALLOC_FREE(fti);
74 return NT_STATUS_INVALID_PARAMETER;
77 ftr->flags = lftr->flags;
78 ftr->timestamp = lftr->time;
79 ftr->type = (enum ForestTrustInfoRecordType)lftr->type;
81 switch (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) {
88 TALLOC_FREE(fti);
89 return NT_STATUS_NO_MEMORY;
92 break;
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) {
100 TALLOC_FREE(fti);
101 return NT_STATUS_NO_MEMORY;
104 break;
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) {
111 TALLOC_FREE(fti);
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) {
120 TALLOC_FREE(fti);
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) {
128 TALLOC_FREE(fti);
129 return NT_STATUS_NO_MEMORY;
132 break;
134 default:
135 return NT_STATUS_NOT_SUPPORTED;
139 *_fti = fti;
140 return NT_STATUS_OK;
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;
153 *_lftr = NULL;
155 lftr = talloc_zero(mem_ctx, struct lsa_ForestTrustRecord);
156 if (lftr == NULL) {
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) {
171 TALLOC_FREE(lftr);
172 return NT_STATUS_NO_MEMORY;
175 break;
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) {
183 TALLOC_FREE(lftr);
184 return NT_STATUS_NO_MEMORY;
187 break;
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) {
195 TALLOC_FREE(lftr);
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) {
203 TALLOC_FREE(lftr);
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) {
211 TALLOC_FREE(lftr);
212 return NT_STATUS_NO_MEMORY;
215 break;
217 default:
218 return NT_STATUS_NOT_SUPPORTED;
221 *_lftr = lftr;
222 return NT_STATUS_OK;
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;
230 uint32_t i;
232 *_lfti = NULL;
234 if (fti->version != 1) {
235 return NT_STATUS_INVALID_PARAMETER;
238 lfti = talloc_zero(mem_ctx, struct lsa_ForestTrustInformation);
239 if (lfti == NULL) {
240 return NT_STATUS_NO_MEMORY;
243 lfti->count = fti->count;
244 lfti->entries = talloc_zero_array(mem_ctx,
245 struct lsa_ForestTrustRecord *,
246 lfti->count);
247 if (lfti->entries == NULL) {
248 TALLOC_FREE(lfti);
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;
255 NTSTATUS status;
257 status = dsdb_trust_forest_record_to_lsa(lfti->entries, ftr,
258 &lftr);
259 if (!NT_STATUS_IS_OK(status)) {
260 TALLOC_FREE(lfti);
261 return NT_STATUS_NO_MEMORY;
263 lfti->entries[i] = lftr;
266 *_lfti = lfti;
267 return NT_STATUS_OK;
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;
279 size_t len = 0;
281 es = talloc_realloc(fti, fti->entries,
282 struct lsa_ForestTrustRecord *,
283 fti->count + 1);
284 if (!es) {
285 return NT_STATUS_NO_MEMORY;
287 fti->entries = es;
289 e = talloc_zero(es, struct lsa_ForestTrustRecord);
290 if (e == NULL) {
291 return NT_STATUS_NO_MEMORY;
294 e->type = ftr->type;
295 e->flags = ftr->flags;
296 e->time = ftr->time;
298 switch (ftr->type) {
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;
302 break;
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;
307 break;
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;
314 break;
315 default:
316 return NT_STATUS_INVALID_PARAMETER;
319 if (dns1->string == NULL) {
320 TALLOC_FREE(e);
321 return NT_STATUS_INVALID_PARAMETER;
324 len = strlen(dns1->string);
325 if (len == 0) {
326 TALLOC_FREE(e);
327 return NT_STATUS_INVALID_PARAMETER;
330 dns2->string = talloc_strdup(e, dns1->string);
331 if (dns2->string == NULL) {
332 TALLOC_FREE(e);
333 return NT_STATUS_NO_MEMORY;
336 if (d1 != NULL) {
337 const struct lsa_StringLarge *nb1 = &d1->netbios_domain_name;
338 struct lsa_StringLarge *nb2 = &d2->netbios_domain_name;
340 if (nb1->string == NULL) {
341 TALLOC_FREE(e);
342 return NT_STATUS_INVALID_PARAMETER;
345 len = strlen(nb1->string);
346 if (len == 0) {
347 TALLOC_FREE(e);
348 return NT_STATUS_INVALID_PARAMETER;
350 if (len > 15) {
351 TALLOC_FREE(e);
352 return NT_STATUS_INVALID_PARAMETER;
355 nb2->string = talloc_strdup(e, nb1->string);
356 if (nb2->string == NULL) {
357 TALLOC_FREE(e);
358 return NT_STATUS_NO_MEMORY;
361 if (d1->domain_sid == NULL) {
362 TALLOC_FREE(e);
363 return NT_STATUS_INVALID_PARAMETER;
366 d2->domain_sid = dom_sid_dup(e, d1->domain_sid);
367 if (d2->domain_sid == NULL) {
368 TALLOC_FREE(e);
369 return NT_STATUS_NO_MEMORY;
373 fti->entries[fti->count++] = e;
374 return NT_STATUS_OK;
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 = {
388 .num_auths = 0,
390 NTSTATUS status;
392 *_tdo = NULL;
393 tdo = talloc_zero(mem_ctx, struct lsa_TrustDomainInfoInfoEx);
394 if (tdo == NULL) {
395 TALLOC_FREE(frame);
396 return NT_STATUS_NO_MEMORY;
398 talloc_steal(frame, tdo);
400 dns = ldb_msg_find_attr_as_string(msg, "dnsRoot", NULL);
401 if (dns == NULL) {
402 TALLOC_FREE(frame);
403 return NT_STATUS_INTERNAL_DB_CORRUPTION;
405 tdo->domain_name.string = talloc_strdup(tdo, dns);
406 if (tdo->domain_name.string == NULL) {
407 TALLOC_FREE(frame);
408 return NT_STATUS_NO_MEMORY;
411 netbios = ldb_msg_find_attr_as_string(msg, "nETBIOSName", NULL);
412 if (netbios == NULL) {
413 TALLOC_FREE(frame);
414 return NT_STATUS_INTERNAL_DB_CORRUPTION;
416 tdo->netbios_name.string = talloc_strdup(tdo, netbios);
417 if (tdo->netbios_name.string == NULL) {
418 TALLOC_FREE(frame);
419 return NT_STATUS_NO_MEMORY;
422 nc_dn = samdb_result_dn(sam_ctx, frame, msg, "ncName", NULL);
423 if (nc_dn == NULL) {
424 TALLOC_FREE(frame);
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)) {
430 TALLOC_FREE(frame);
431 return status;
433 tdo->sid = dom_sid_dup(tdo, &sid);
434 if (tdo->sid == NULL) {
435 TALLOC_FREE(frame);
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);
445 TALLOC_FREE(frame);
446 return NT_STATUS_OK;
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[] = {
463 "dnsRoot",
464 "nETBIOSName",
465 "nCName",
466 "rootTrust",
467 "trustParent",
468 NULL,
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;
474 NTSTATUS status;
475 int ret;
477 if (extra_filter == NULL) {
478 extra_filter = "";
481 *_tdo = 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) {
491 TALLOC_FREE(frame);
492 return NT_STATUS_NO_MEMORY;
495 ret = dsdb_search(sam_ctx, partitions_dn, &cross_res,
496 partitions_dn, LDB_SCOPE_ONELEVEL,
497 cross_attrs,
498 DSDB_SEARCH_ONE_ONLY |
499 DSDB_SEARCH_SHOW_EXTENDED_DN,
500 "(&"
501 "(ncName=%s)"
502 "(objectClass=crossRef)"
503 "(systemFlags:%s:=%u)"
504 "%s"
505 ")",
506 ldb_dn_get_linearized(domain_dn),
507 LDB_OID_COMPARATOR_AND,
508 SYSTEM_FLAG_CR_NTDS_DOMAIN,
509 extra_filter);
510 if (ret != LDB_SUCCESS) {
511 TALLOC_FREE(frame);
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)) {
518 TALLOC_FREE(frame);
519 return status;
521 talloc_steal(frame, tdo);
523 if (_root_trust_tdo != NULL) {
524 root_trust_dn = samdb_result_dn(sam_ctx, frame, msg,
525 "rootTrust", NULL);
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,
536 &root_trust_msg,
537 root_trust_dn,
538 LDB_SCOPE_BASE,
539 cross_attrs,
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)));
547 TALLOC_FREE(frame);
548 return status;
551 status = dsdb_trust_parse_crossref_info(mem_ctx, sam_ctx,
552 root_trust_msg,
553 &root_trust_tdo);
554 if (!NT_STATUS_IS_OK(status)) {
555 TALLOC_FREE(frame);
556 return 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,
565 &trust_parent_msg,
566 trust_parent_dn,
567 LDB_SCOPE_BASE,
568 cross_attrs,
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)));
576 TALLOC_FREE(frame);
577 return status;
580 status = dsdb_trust_parse_crossref_info(mem_ctx, sam_ctx,
581 trust_parent_msg,
582 &trust_parent_tdo);
583 if (!NT_STATUS_IS_OK(status)) {
584 TALLOC_FREE(frame);
585 return 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);
597 TALLOC_FREE(frame);
598 return NT_STATUS_OK;
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
621 * the last one.
623 static int dns_cmp(const char *s1, const char *s2)
625 size_t l1 = 0;
626 const char *p1 = NULL;
627 size_t num_comp1 = 0;
628 uint16_t comp1[UINT8_MAX] = {0};
629 size_t l2 = 0;
630 const char *p2 = NULL;
631 size_t num_comp2 = 0;
632 uint16_t comp2[UINT8_MAX] = {0};
633 size_t i;
635 if (s1 != NULL) {
636 l1 = strlen(s1);
639 if (s2 != NULL) {
640 l2 = strlen(s2);
644 * trailing '.' are ignored.
646 if (l1 > 1 && s1[l1 - 1] == '.') {
647 l1--;
649 if (l2 > 1 && s2[l2 - 1] == '.') {
650 l2--;
653 for (i = 0; i < ARRAY_SIZE(comp1); i++) {
654 char *p;
656 if (i == 0) {
657 p1 = s1;
659 if (l1 == 0 || l1 >= UINT16_MAX) {
660 /* just use one single component on overflow */
661 break;
665 comp1[num_comp1++] = PTR_DIFF(p1, s1);
667 p = strchr_m(p1, '.');
668 if (p == NULL) {
669 p1 = NULL;
670 break;
673 p1 = p + 1;
676 if (p1 != NULL) {
677 /* just use one single component on overflow */
678 num_comp1 = 0;
679 comp1[num_comp1++] = 0;
680 p1 = NULL;
683 for (i = 0; i < ARRAY_SIZE(comp2); i++) {
684 char *p;
686 if (i == 0) {
687 p2 = s2;
689 if (l2 == 0 || l2 >= UINT16_MAX) {
690 /* just use one single component on overflow */
691 break;
695 comp2[num_comp2++] = PTR_DIFF(p2, s2);
697 p = strchr_m(p2, '.');
698 if (p == NULL) {
699 p2 = NULL;
700 break;
703 p2 = p + 1;
706 if (p2 != NULL) {
707 /* just use one single component on overflow */
708 num_comp2 = 0;
709 comp2[num_comp2++] = 0;
710 p2 = NULL;
713 for (i = 0; i < UINT8_MAX; i++) {
714 int cmp;
716 if (i < num_comp1) {
717 size_t idx = num_comp1 - (i + 1);
718 p1 = s1 + comp1[idx];
719 } else {
720 p1 = NULL;
723 if (i < num_comp2) {
724 size_t idx = num_comp2 - (i + 1);
725 p2 = s2 + comp2[idx];
726 } else {
727 p2 = NULL;
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);
741 if (cmp < 0) {
742 return DNS_CMP_FIRST_IS_LESS;
744 if (cmp > 0) {
745 return DNS_CMP_SECOND_IS_LESS;
749 smb_panic(__location__);
750 return -1;
753 static int dsdb_trust_find_tln_match_internal(const struct lsa_ForestTrustInformation *info,
754 enum lsa_ForestTrustRecordType type,
755 uint32_t disable_mask,
756 const char *tln)
758 uint32_t i;
760 for (i = 0; i < info->count; i++) {
761 struct lsa_ForestTrustRecord *e = info->entries[i];
762 struct lsa_StringLarge *t = NULL;
763 int cmp;
765 if (e == NULL) {
766 continue;
769 if (e->type != type) {
770 continue;
773 if (e->flags & disable_mask) {
774 continue;
777 switch (type) {
778 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
779 t = &e->forest_trust_data.top_level_name;
780 break;
781 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
782 t = &e->forest_trust_data.top_level_name_ex;
783 break;
784 default:
785 break;
788 if (t == NULL) {
789 continue;
792 cmp = dns_cmp(tln, t->string);
793 switch (cmp) {
794 case DNS_CMP_MATCH:
795 case DNS_CMP_FIRST_IS_CHILD:
796 return i;
800 return -1;
803 static bool dsdb_trust_find_tln_match(const struct lsa_ForestTrustInformation *info,
804 const char *tln)
806 int m;
808 m = dsdb_trust_find_tln_match_internal(info,
809 LSA_FOREST_TRUST_TOP_LEVEL_NAME,
810 LSA_TLN_DISABLED_MASK,
811 tln);
812 if (m != -1) {
813 return true;
816 return false;
819 static bool dsdb_trust_find_tln_ex_match(const struct lsa_ForestTrustInformation *info,
820 const char *tln)
822 int m;
824 m = dsdb_trust_find_tln_match_internal(info,
825 LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX,
827 tln);
828 if (m != -1) {
829 return true;
832 return false;
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,
847 domain_dn, NULL,
848 _tdo, NULL, NULL);
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,
868 _tdo, NULL, NULL);
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;
878 int cmp;
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);
888 switch (cmp) {
889 case DNS_CMP_FIRST_IS_CHILD:
890 return -1;
891 case DNS_CMP_SECOND_IS_CHILD:
892 return 1;
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 */
902 return -1;
904 if (rootTrust2 == NULL && trustParent2 == NULL) {
905 /* m2 is the forest root */
906 return 1;
909 return cmp;
912 static int dsdb_trust_xref_sort_vals(struct ldb_val *v1,
913 struct ldb_val *v2)
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[] = {
929 "uPNSuffixes",
930 "msDS-SPNSuffixes",
931 NULL,
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[] = {
939 "dnsRoot",
940 "nETBIOSName",
941 "nCName",
942 "rootTrust",
943 "trustParent",
944 NULL,
946 struct ldb_result *cross_res2 = NULL;
947 int ret;
948 unsigned int i;
949 bool restart = false;
951 *_info = NULL;
952 info = talloc_zero(mem_ctx, struct lsa_ForestTrustInformation);
953 if (info == NULL) {
954 TALLOC_FREE(frame);
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) {
961 TALLOC_FREE(frame);
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) {
968 TALLOC_FREE(frame);
969 return dsdb_ldb_err_to_ntstatus(ret);
972 ret = dsdb_search(sam_ctx, partitions_dn, &cross_res2,
973 partitions_dn, LDB_SCOPE_ONELEVEL,
974 cross_attrs2,
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) {
981 TALLOC_FREE(frame);
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) {
1001 TALLOC_FREE(frame);
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 = {
1019 .num_auths = 0,
1021 struct lsa_ForestTrustRecord e = {
1022 .flags = 0,
1024 struct lsa_ForestTrustDomainInfo *d = NULL;
1025 struct lsa_StringLarge *t = NULL;
1026 bool match = false;
1027 NTSTATUS status;
1029 dns = ldb_msg_find_attr_as_string(m, "dnsRoot", NULL);
1030 if (dns == NULL) {
1031 TALLOC_FREE(frame);
1032 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1035 netbios = ldb_msg_find_attr_as_string(m, "nETBIOSName", NULL);
1036 if (netbios == NULL) {
1037 TALLOC_FREE(frame);
1038 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1041 nc_dn = samdb_result_dn(sam_ctx, m, m, "ncName", NULL);
1042 if (nc_dn == NULL) {
1043 TALLOC_FREE(frame);
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)) {
1049 TALLOC_FREE(frame);
1050 return status;
1053 match = dsdb_trust_find_tln_match(info, dns);
1054 if (!match) {
1056 * First the TOP_LEVEL_NAME, if required
1058 e = (struct lsa_ForestTrustRecord) {
1059 .flags = 0,
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;
1065 t->string = dns;
1067 status = dsdb_trust_forest_info_add_record(info, &e);
1068 if (!NT_STATUS_IS_OK(status)) {
1069 TALLOC_FREE(frame);
1070 return status;
1075 * Then the DOMAIN_INFO
1077 e = (struct lsa_ForestTrustRecord) {
1078 .flags = 0,
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)) {
1089 TALLOC_FREE(frame);
1090 return 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 = {
1098 .flags = 0,
1100 struct lsa_StringLarge *t = NULL;
1101 bool match = false;
1102 NTSTATUS status;
1104 if (dns == NULL) {
1105 TALLOC_FREE(frame);
1106 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1109 match = dsdb_trust_find_tln_match(info, dns);
1110 if (match) {
1111 continue;
1115 * an additional the TOP_LEVEL_NAME
1117 e = (struct lsa_ForestTrustRecord) {
1118 .flags = 0,
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;
1123 t->string = dns;
1125 status = dsdb_trust_forest_info_add_record(info, &e);
1126 if (!NT_STATUS_IS_OK(status)) {
1127 TALLOC_FREE(frame);
1128 return 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;
1135 uint32_t c;
1137 restart = false;
1139 if (tr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
1140 continue;
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;
1148 uint32_t j;
1149 int cmp;
1151 if (cr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
1152 continue;
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)) {
1159 continue;
1161 if (cmp != DNS_CMP_FIRST_IS_CHILD) {
1162 /* can't happen ... */
1163 continue;
1166 ts = NULL;
1167 tr = NULL;
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];
1174 info->count -= 1;
1175 restart = true;
1176 break;
1180 *_info = talloc_move(mem_ctx, &info);
1181 TALLOC_FREE(frame);
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;
1193 *_tdo = NULL;
1195 tdo = talloc_zero(mem_ctx, struct lsa_TrustDomainInfoInfoEx);
1196 if (tdo == NULL) {
1197 return NT_STATUS_NO_MEMORY;
1200 dns = ldb_msg_find_attr_as_string(m, "trustPartner", NULL);
1201 if (dns == NULL) {
1202 TALLOC_FREE(tdo);
1203 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1205 tdo->domain_name.string = talloc_strdup(tdo, dns);
1206 if (tdo->domain_name.string == NULL) {
1207 TALLOC_FREE(tdo);
1208 return NT_STATUS_NO_MEMORY;
1211 netbios = ldb_msg_find_attr_as_string(m, "flatName", NULL);
1212 if (netbios == NULL) {
1213 TALLOC_FREE(tdo);
1214 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1216 tdo->netbios_name.string = talloc_strdup(tdo, netbios);
1217 if (tdo->netbios_name.string == NULL) {
1218 TALLOC_FREE(tdo);
1219 return NT_STATUS_NO_MEMORY;
1222 tdo->sid = samdb_result_dom_sid(tdo, m, "securityIdentifier");
1223 if (tdo->sid == NULL) {
1224 TALLOC_FREE(tdo);
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);
1232 *_tdo = tdo;
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;
1244 *_fti = NULL;
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);
1252 if (fti == NULL) {
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)) {
1260 TALLOC_FREE(fti);
1261 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1264 *_fti = fti;
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;
1274 uint32_t n;
1276 *_nfti = NULL;
1278 nfti = talloc_zero(mem_ctx, struct lsa_ForestTrustInformation);
1279 if (nfti == NULL) {
1280 TALLOC_FREE(frame);
1281 return NT_STATUS_NO_MEMORY;
1283 talloc_steal(frame, nfti);
1286 * First we copy every record and remove possible trailing dots
1287 * from dns names.
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;
1300 NTSTATUS status;
1301 size_t len = 0;
1302 char *p = NULL;
1303 uint32_t c;
1305 if (gftr == NULL) {
1306 TALLOC_FREE(frame);
1307 return NT_STATUS_INVALID_PARAMETER;
1310 status = dsdb_trust_forest_info_add_record(nfti, gftr);
1311 if (!NT_STATUS_IS_OK(status)) {
1312 TALLOC_FREE(frame);
1313 return 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;
1321 break;
1323 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
1324 ntln = &nftr->forest_trust_data.top_level_name_ex;
1325 break;
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;
1332 break;
1334 default:
1335 TALLOC_FREE(frame);
1336 return NT_STATUS_INVALID_PARAMETER;
1340 * We remove one trailing '.' before checking
1341 * for invalid dots.
1343 * domain.com. becomes domain.com
1344 * domain.com.. becomes domain.com.
1346 * Then the following is invalid:
1348 * domain..com
1349 * .domain.com
1350 * domain.com.
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);
1356 *p= '\0';
1358 if (ntln->string[0] == '.') {
1359 TALLOC_FREE(frame);
1360 return NT_STATUS_INVALID_PARAMETER;
1362 p = strstr_m(ntln->string, "..");
1363 if (p != NULL) {
1364 TALLOC_FREE(frame);
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;
1374 int cmp;
1376 if (cftr == NULL) {
1377 continue;
1380 if (cftr->type != nftr->type) {
1381 continue;
1384 switch (cftr->type) {
1385 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
1386 ctln = &cftr->forest_trust_data.top_level_name;
1387 break;
1389 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
1390 ctln = &cftr->forest_trust_data.top_level_name_ex;
1391 break;
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;
1398 break;
1400 default:
1401 TALLOC_FREE(frame);
1402 return NT_STATUS_INVALID_PARAMETER;
1405 cmp = dns_cmp(ntln->string, ctln->string);
1406 if (cmp == DNS_CMP_MATCH) {
1407 nftr = NULL;
1408 TALLOC_FREE(nfti->entries[n]);
1409 break;
1412 if (cinfo == NULL) {
1413 continue;
1416 cmp = strcasecmp_m(nnb->string, cnb->string);
1417 if (cmp == 0) {
1418 nftr = NULL;
1419 TALLOC_FREE(nfti->entries[n]);
1420 break;
1423 cmp = dom_sid_compare(nsid, csid);
1424 if (cmp == 0) {
1425 nftr = NULL;
1426 TALLOC_FREE(nfti->entries[n]);
1427 break;
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;
1438 uint32_t c;
1440 if (nftr == NULL) {
1441 continue;
1444 if (nftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
1445 continue;
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;
1453 int cmp;
1455 if (cftr == NULL) {
1456 continue;
1459 if (cftr == nftr) {
1460 continue;
1463 if (cftr->type != nftr->type) {
1464 continue;
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)) {
1471 continue;
1474 TALLOC_FREE(frame);
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;
1485 uint32_t c;
1486 bool found_tln = false;
1488 if (nftr == NULL) {
1489 continue;
1492 if (nftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX) {
1493 continue;
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;
1501 int cmp;
1503 if (cftr == NULL) {
1504 continue;
1507 if (cftr == nftr) {
1508 continue;
1511 if (cftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
1512 continue;
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) {
1519 found_tln = true;
1520 break;
1524 if (found_tln) {
1525 continue;
1528 TALLOC_FREE(frame);
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;
1539 uint32_t c;
1540 bool found_tln = false;
1542 if (nftr == NULL) {
1543 continue;
1546 if (nftr->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
1547 continue;
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;
1556 int cmp;
1558 if (cftr == NULL) {
1559 continue;
1562 if (cftr == nftr) {
1563 continue;
1566 if (cftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
1567 continue;
1570 ctln = &cftr->forest_trust_data.top_level_name;
1572 cmp = dns_cmp(ntln->string, ctln->string);
1573 if (cmp == DNS_CMP_MATCH) {
1574 found_tln = true;
1575 break;
1577 if (cmp == DNS_CMP_FIRST_IS_CHILD) {
1578 found_tln = true;
1579 break;
1583 if (found_tln) {
1584 continue;
1587 TALLOC_FREE(frame);
1588 return NT_STATUS_INVALID_PARAMETER;
1591 *_nfti = talloc_move(mem_ctx, &nfti);
1592 TALLOC_FREE(frame);
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;
1604 uint32_t g;
1606 *_nfti = NULL;
1608 nfti = talloc_zero(mem_ctx, struct lsa_ForestTrustInformation);
1609 if (nfti == NULL) {
1610 TALLOC_FREE(frame);
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;
1625 bool skip = false;
1626 NTSTATUS status;
1628 if (gftr == NULL) {
1629 continue;
1632 switch (gftr->type) {
1633 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
1634 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
1635 break;
1637 case LSA_FOREST_TRUST_DOMAIN_INFO:
1638 skip = true;
1639 break;
1641 default:
1642 TALLOC_FREE(frame);
1643 return NT_STATUS_INVALID_PARAMETER;
1646 if (skip) {
1647 continue;
1650 /* make a copy in order to update the time. */
1651 tftr = *gftr;
1652 if (tftr.time == 0) {
1653 tftr.time = now;
1656 status = dsdb_trust_forest_info_add_record(nfti, &tftr);
1657 if (!NT_STATUS_IS_OK(status)) {
1658 TALLOC_FREE(frame);
1659 return 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;
1666 bool skip = false;
1667 NTSTATUS status;
1669 if (gftr == NULL) {
1670 continue;
1673 switch (gftr->type) {
1674 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
1675 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
1676 skip = true;
1677 break;
1679 case LSA_FOREST_TRUST_DOMAIN_INFO:
1680 break;
1682 default:
1683 TALLOC_FREE(frame);
1684 return NT_STATUS_INVALID_PARAMETER;
1687 if (skip) {
1688 continue;
1691 /* make a copy in order to update the time. */
1692 tftr = *gftr;
1693 if (tftr.time == 0) {
1694 tftr.time = now;
1697 status = dsdb_trust_forest_info_add_record(nfti, &tftr);
1698 if (!NT_STATUS_IS_OK(status)) {
1699 TALLOC_FREE(frame);
1700 return status;
1704 *_nfti = talloc_move(mem_ctx, &nfti);
1705 TALLOC_FREE(frame);
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);
1720 if (es == NULL) {
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;
1731 es[i]->index = idx;
1732 es[i]->type = type;
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)
1748 uint32_t n;
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;
1754 uint32_t flags = 0;
1755 uint32_t r;
1756 NTSTATUS status;
1758 if (nftr == NULL) {
1759 continue;
1762 if (nftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
1763 continue;
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,
1772 ntln->string);
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;
1779 int cmp;
1781 if (rftr == NULL) {
1782 continue;
1785 if (rftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
1786 continue;
1789 rtln = &rftr->forest_trust_data.top_level_name;
1790 if (rtln->string == NULL) {
1791 continue;
1794 cmp = dns_cmp(ntln->string, rtln->string);
1795 if (DNS_CMP_IS_NO_MATCH(cmp)) {
1796 continue;
1798 if (cmp == DNS_CMP_MATCH) {
1799 /* We need to normalize the string */
1800 ntln->string = talloc_strdup(nftr,
1801 rtln->string);
1802 if (ntln->string == NULL) {
1803 return NT_STATUS_NO_MEMORY;
1807 if (ntln_excluded) {
1808 continue;
1811 if (rftr->flags & LSA_TLN_DISABLED_MASK) {
1812 continue;
1815 if (nftr->flags & LSA_TLN_DISABLED_MASK) {
1816 continue;
1819 if (cmp == DNS_CMP_SECOND_IS_CHILD) {
1820 bool m;
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,
1827 rtln->string);
1828 if (m) {
1829 continue;
1833 flags |= LSA_TLN_DISABLED_CONFLICT;
1836 if (flags == 0) {
1837 continue;
1840 nftr->flags |= flags;
1842 status = dsdb_trust_add_collision(c_info,
1843 collision_type,
1844 n, nftr->flags,
1845 ref_tdo->domain_name.string);
1846 if (!NT_STATUS_IS_OK(status)) {
1847 return 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;
1858 uint32_t flags = 0;
1859 uint32_t r;
1860 NTSTATUS status;
1862 if (nftr == NULL) {
1863 continue;
1866 if (nftr->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
1867 continue;
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;
1880 if (nsid == NULL) {
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;
1896 int cmp;
1898 if (rftr == NULL) {
1899 continue;
1902 if (!ntln_found) {
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;
1928 break;
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;
1943 break;
1945 default:
1946 break;
1949 if (rtln == NULL) {
1950 continue;
1953 if (rtln->string == NULL) {
1954 continue;
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,
1965 rtln->string);
1966 if (ntln->string == NULL) {
1967 return NT_STATUS_NO_MEMORY;
1971 if (rinfo == NULL) {
1972 continue;
1975 if (rsid != NULL) {
1976 cmp = dom_sid_compare(nsid, rsid);
1977 } else {
1978 cmp = -1;
1980 if (cmp == 0) {
1981 if (sid_possible) {
1982 flags |= LSA_SID_DISABLED_CONFLICT;
1986 if (rnb->string != NULL) {
1987 cmp = strcasecmp_m(nnb->string, rnb->string);
1988 } else {
1989 cmp = -1;
1991 if (cmp == 0) {
1992 nnb->string = talloc_strdup(nftr, rnb->string);
1993 if (nnb->string == NULL) {
1994 return NT_STATUS_NO_MEMORY;
1996 if (nb_possible) {
1997 flags |= LSA_NB_DISABLED_CONFLICT;
2002 if (flags == 0) {
2003 continue;
2006 nftr->flags |= flags;
2008 status = dsdb_trust_add_collision(c_info,
2009 collision_type,
2010 n, nftr->flags,
2011 ref_tdo->domain_name.string);
2012 if (!NT_STATUS_IS_OK(status)) {
2013 return 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;
2028 uint32_t ni;
2029 uint32_t oi;
2030 NTSTATUS status;
2031 int cmp;
2033 *_mfti = NULL;
2034 mfti = talloc_zero(mem_ctx, struct lsa_ForestTrustInformation);
2035 if (mfti == NULL) {
2036 TALLOC_FREE(frame);
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 = {
2051 .flags = 0,
2053 const char *ndns = NULL;
2054 bool ignore_new = false;
2055 bool found_old = false;
2056 uint32_t mi;
2058 if (nftr == NULL) {
2059 TALLOC_FREE(frame);
2060 return NT_STATUS_INVALID_PARAMETER;
2063 if (nftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
2064 continue;
2067 ndns = nftr->forest_trust_data.top_level_name.string;
2068 if (ndns == NULL) {
2069 TALLOC_FREE(frame);
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)) {
2077 TALLOC_FREE(frame);
2078 return status;
2082 for (mi = 0; mi < mfti->count; mi++) {
2083 const struct lsa_ForestTrustRecord *mftr =
2084 mfti->entries[mi];
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);
2094 switch (cmp) {
2095 case DNS_CMP_MATCH:
2096 case DNS_CMP_SECOND_IS_CHILD:
2097 ignore_new = true;
2098 break;
2101 if (ignore_new) {
2102 break;
2106 if (ignore_new) {
2107 continue;
2111 * make a temporary copy where we can change time and flags
2113 tftr = *nftr;
2115 for (oi = 0; oi < ofti->count; oi++) {
2116 const struct lsa_ForestTrustRecord *oftr =
2117 ofti->entries[oi];
2118 const char *odns = NULL;
2120 if (oftr == NULL) {
2122 * broken record => ignore...
2124 continue;
2127 if (oftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
2128 continue;
2131 odns = oftr->forest_trust_data.top_level_name.string;
2132 if (odns == NULL) {
2134 * broken record => ignore...
2136 continue;
2139 cmp = dns_cmp(odns, ndns);
2140 if (cmp != DNS_CMP_MATCH) {
2141 continue;
2144 found_old = true;
2145 tftr.flags = oftr->flags;
2146 tftr.time = oftr->time;
2149 if (!found_old) {
2150 tftr.flags = LSA_TLN_DISABLED_NEW;
2151 tftr.time = 0;
2154 status = dsdb_trust_forest_info_add_record(mfti, &tftr);
2155 if (!NT_STATUS_IS_OK(status)) {
2156 TALLOC_FREE(frame);
2157 return 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 = {
2168 .flags = 0,
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;
2175 uint32_t mi;
2177 if (nftr == NULL) {
2178 TALLOC_FREE(frame);
2179 return NT_STATUS_INVALID_PARAMETER;
2182 if (nftr->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
2183 continue;
2186 nd = &nftr->forest_trust_data.domain_info;
2187 if (nd->domain_sid == NULL) {
2188 TALLOC_FREE(frame);
2189 return NT_STATUS_INVALID_PARAMETER;
2191 ndns = nd->dns_domain_name.string;
2192 if (ndns == NULL) {
2193 TALLOC_FREE(frame);
2194 return NT_STATUS_INVALID_PARAMETER;
2196 nnbt = nd->netbios_domain_name.string;
2197 if (nnbt == NULL) {
2198 TALLOC_FREE(frame);
2199 return NT_STATUS_INVALID_PARAMETER;
2202 for (mi = 0; mi < mfti->count; mi++) {
2203 const struct lsa_ForestTrustRecord *mftr =
2204 mfti->entries[mi];
2205 const struct lsa_ForestTrustDomainInfo *md = NULL;
2207 if (mftr->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
2208 continue;
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);
2218 if (cmp == 0) {
2219 ignore_new = true;
2220 break;
2224 if (ignore_new) {
2225 continue;
2229 * make a temporary copy where we can change time and flags
2231 tftr = *nftr;
2233 for (oi = 0; oi < ofti->count; oi++) {
2234 const struct lsa_ForestTrustRecord *oftr =
2235 ofti->entries[oi];
2236 const struct lsa_ForestTrustDomainInfo *od = NULL;
2237 const char *onbt = NULL;
2239 if (oftr == NULL) {
2241 * broken record => ignore...
2243 continue;
2246 if (oftr->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
2247 continue;
2250 od = &oftr->forest_trust_data.domain_info;
2251 onbt = od->netbios_domain_name.string;
2252 if (onbt == NULL) {
2254 * broken record => ignore...
2256 continue;
2259 cmp = strcasecmp(onbt, nnbt);
2260 if (cmp != 0) {
2261 continue;
2264 found_old = true;
2265 tftr.flags = oftr->flags;
2266 tftr.time = oftr->time;
2269 if (!found_old) {
2270 tftr.flags = 0;
2271 tftr.time = 0;
2274 status = dsdb_trust_forest_info_add_record(mfti, &tftr);
2275 if (!NT_STATUS_IS_OK(status)) {
2276 TALLOC_FREE(frame);
2277 return 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 =
2287 ofti->entries[oi];
2288 const struct lsa_ForestTrustDomainInfo *od = NULL;
2289 const char *odns = NULL;
2290 const char *onbt = NULL;
2291 bool ignore_old = true;
2292 uint32_t mi;
2294 if (oftr == NULL) {
2296 * broken record => ignore...
2298 continue;
2301 if (oftr->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
2302 continue;
2305 od = &oftr->forest_trust_data.domain_info;
2306 odns = od->dns_domain_name.string;
2307 if (odns == NULL) {
2309 * broken record => ignore...
2311 continue;
2313 onbt = od->netbios_domain_name.string;
2314 if (onbt == NULL) {
2316 * broken record => ignore...
2318 continue;
2320 if (od->domain_sid == NULL) {
2322 * broken record => ignore...
2324 continue;
2327 if (oftr->flags & LSA_NB_DISABLED_ADMIN) {
2328 ignore_old = false;
2329 } else if (oftr->flags & LSA_SID_DISABLED_ADMIN) {
2330 ignore_old = false;
2333 for (mi = 0; mi < mfti->count; mi++) {
2334 const struct lsa_ForestTrustRecord *mftr =
2335 mfti->entries[mi];
2336 const struct lsa_ForestTrustDomainInfo *md = NULL;
2338 if (mftr->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
2339 continue;
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);
2349 if (cmp == 0) {
2350 ignore_old = true;
2351 break;
2355 if (ignore_old) {
2356 continue;
2359 status = dsdb_trust_forest_info_add_record(mfti, oftr);
2360 if (!NT_STATUS_IS_OK(status)) {
2361 TALLOC_FREE(frame);
2362 return 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 =
2372 ofti->entries[oi];
2373 const char *odns = NULL;
2374 bool ignore_old = false;
2375 uint32_t mi;
2377 if (oftr == NULL) {
2379 * broken record => ignore...
2381 continue;
2384 if (oftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX) {
2385 continue;
2388 odns = oftr->forest_trust_data.top_level_name_ex.string;
2389 if (odns == NULL) {
2391 * broken record => ignore...
2393 continue;
2396 for (mi = 0; mi < mfti->count; mi++) {
2397 const struct lsa_ForestTrustRecord *mftr =
2398 mfti->entries[mi];
2399 const char *mdns = NULL;
2401 if (mftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
2402 continue;
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);
2412 switch (cmp) {
2413 case DNS_CMP_MATCH:
2414 case DNS_CMP_SECOND_IS_CHILD:
2415 break;
2416 default:
2417 ignore_old = true;
2418 break;
2421 if (ignore_old) {
2422 break;
2426 if (ignore_old) {
2427 continue;
2430 status = dsdb_trust_forest_info_add_record(mfti, oftr);
2431 if (!NT_STATUS_IS_OK(status)) {
2432 TALLOC_FREE(frame);
2433 return status;
2437 *_mfti = talloc_move(mem_ctx, &mfti);
2438 TALLOC_FREE(frame);
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();
2449 int ret;
2450 struct ldb_dn *system_dn = NULL;
2451 char *netbios_encoded = NULL;
2452 char *dns_encoded = NULL;
2453 char *filter = NULL;
2455 *msg = NULL;
2457 if (netbios == NULL && dns == NULL) {
2458 TALLOC_FREE(frame);
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) {
2464 TALLOC_FREE(frame);
2465 return NT_STATUS_NO_MEMORY;
2468 if (!ldb_dn_add_child_fmt(system_dn, "CN=System")) {
2469 TALLOC_FREE(frame);
2470 return NT_STATUS_NO_MEMORY;
2473 if (netbios != NULL) {
2474 netbios_encoded = ldb_binary_encode_string(frame, netbios);
2475 if (netbios_encoded == NULL) {
2476 TALLOC_FREE(frame);
2477 return NT_STATUS_NO_MEMORY;
2481 if (dns != NULL) {
2482 dns_encoded = ldb_binary_encode_string(frame, dns);
2483 if (dns_encoded == NULL) {
2484 TALLOC_FREE(frame);
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))"
2493 ")",
2494 dns_encoded, netbios_encoded);
2495 if (filter == NULL) {
2496 TALLOC_FREE(frame);
2497 return NT_STATUS_NO_MEMORY;
2499 } else if (netbios != NULL) {
2500 filter = talloc_asprintf(frame,
2501 "(&(objectClass=trustedDomain)(flatName=%s))",
2502 netbios_encoded);
2503 if (filter == NULL) {
2504 TALLOC_FREE(frame);
2505 return NT_STATUS_NO_MEMORY;
2507 } else if (dns != NULL) {
2508 filter = talloc_asprintf(frame,
2509 "(&(objectClass=trustedDomain)(trustPartner=%s))",
2510 dns_encoded);
2511 if (filter == NULL) {
2512 TALLOC_FREE(frame);
2513 return NT_STATUS_NO_MEMORY;
2517 ret = dsdb_search_one(sam_ctx, mem_ctx, msg,
2518 system_dn,
2519 LDB_SCOPE_ONELEVEL, attrs,
2520 DSDB_SEARCH_NO_GLOBAL_CATALOG,
2521 "%s", filter);
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)));
2526 TALLOC_FREE(frame);
2527 return status;
2530 TALLOC_FREE(frame);
2531 return NT_STATUS_OK;
2534 NTSTATUS dsdb_trust_search_tdo_by_type(struct ldb_context *sam_ctx,
2535 enum netr_SchannelType type,
2536 const char *name,
2537 const char * const *attrs,
2538 TALLOC_CTX *mem_ctx,
2539 struct ldb_message **msg)
2541 TALLOC_CTX *frame = talloc_stackframe();
2542 NTSTATUS status;
2543 size_t len;
2544 char trailer = '$';
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) {
2551 TALLOC_FREE(frame);
2552 return NT_STATUS_INVALID_PARAMETER;
2555 if (type == SEC_CHAN_DNS_DOMAIN) {
2556 trailer = '.';
2557 require_trailer = false;
2560 encoded_name = ldb_binary_encode_string(frame, name);
2561 if (encoded_name == NULL) {
2562 TALLOC_FREE(frame);
2563 return NT_STATUS_NO_MEMORY;
2566 len = strlen(encoded_name);
2567 if (len < 2) {
2568 TALLOC_FREE(frame);
2569 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2572 if (require_trailer && encoded_name[len - 1] != trailer) {
2573 TALLOC_FREE(frame);
2574 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2576 encoded_name[len - 1] = '\0';
2578 if (type == SEC_CHAN_DNS_DOMAIN) {
2579 dns = encoded_name;
2580 } else {
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)) {
2587 TALLOC_FREE(frame);
2588 return status;
2591 TALLOC_FREE(frame);
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();
2602 int ret;
2603 struct ldb_dn *system_dn = NULL;
2604 char *encoded_sid = NULL;
2605 char *filter = NULL;
2607 *msg = NULL;
2609 if (sid == NULL) {
2610 TALLOC_FREE(frame);
2611 return NT_STATUS_INVALID_PARAMETER_MIX;
2614 encoded_sid = ldap_encode_ndr_dom_sid(frame, sid);
2615 if (encoded_sid == NULL) {
2616 TALLOC_FREE(frame);
2617 return NT_STATUS_NO_MEMORY;
2620 system_dn = ldb_dn_copy(frame, ldb_get_default_basedn(sam_ctx));
2621 if (system_dn == NULL) {
2622 TALLOC_FREE(frame);
2623 return NT_STATUS_NO_MEMORY;
2626 if (!ldb_dn_add_child_fmt(system_dn, "CN=System")) {
2627 TALLOC_FREE(frame);
2628 return NT_STATUS_NO_MEMORY;
2631 filter = talloc_asprintf(frame,
2632 "(&"
2633 "(objectClass=trustedDomain)"
2634 "(securityIdentifier=%s)"
2635 ")",
2636 encoded_sid);
2637 if (filter == NULL) {
2638 TALLOC_FREE(frame);
2639 return NT_STATUS_NO_MEMORY;
2642 ret = dsdb_search_one(sam_ctx, mem_ctx, msg,
2643 system_dn,
2644 LDB_SCOPE_ONELEVEL, attrs,
2645 DSDB_SEARCH_NO_GLOBAL_CATALOG,
2646 "%s", filter);
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)));
2651 TALLOC_FREE(frame);
2652 return status;
2655 TALLOC_FREE(frame);
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 = {
2666 .hash = {0},
2668 struct samr_Password __previous = {
2669 .hash = {0},
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 = {
2676 .count = 0,
2678 uint32_t i;
2680 if (_current != NULL) {
2681 *_current = NULL;
2683 if (_previous != NULL) {
2684 *_previous = NULL;
2687 blob = ldb_msg_find_ldb_val(msg, "trustAuthIncoming");
2688 if (blob == NULL) {
2689 TALLOC_FREE(frame);
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)) {
2697 TALLOC_FREE(frame);
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) {
2706 break;
2709 switch (a->AuthType) {
2710 case TRUST_AUTH_TYPE_NONE:
2711 case TRUST_AUTH_TYPE_VERSION:
2712 break;
2713 case TRUST_AUTH_TYPE_NT4OWF:
2714 current = &a->AuthInfo.nt4owf.password;
2715 break;
2716 case TRUST_AUTH_TYPE_CLEAR:
2717 mdfour(__current.hash,
2718 a->AuthInfo.clear.password,
2719 a->AuthInfo.clear.size);
2720 current = &__current;
2721 break;
2725 if (current == NULL) {
2726 TALLOC_FREE(frame);
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) {
2735 break;
2738 switch (a->AuthType) {
2739 case TRUST_AUTH_TYPE_NONE:
2740 case TRUST_AUTH_TYPE_VERSION:
2741 break;
2742 case TRUST_AUTH_TYPE_NT4OWF:
2743 previous = &a->AuthInfo.nt4owf.password;
2744 break;
2745 case TRUST_AUTH_TYPE_CLEAR:
2746 mdfour(__previous.hash,
2747 a->AuthInfo.clear.password,
2748 a->AuthInfo.clear.size);
2749 previous = &__previous;
2750 break;
2754 if (previous == NULL) {
2755 previous = current;
2758 if (_current != NULL) {
2759 *_current = talloc(mem_ctx, struct samr_Password);
2760 if (*_current == NULL) {
2761 TALLOC_FREE(frame);
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);
2772 TALLOC_FREE(frame);
2773 return NT_STATUS_NO_MEMORY;
2775 **_previous = *previous;
2777 ZERO_STRUCTP(current);
2778 ZERO_STRUCTP(previous);
2779 TALLOC_FREE(frame);
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();
2790 int ret;
2791 struct ldb_dn *system_dn = NULL;
2792 const char *filter = NULL;
2793 char *exclude_encoded = NULL;
2795 *res = NULL;
2797 system_dn = ldb_dn_copy(frame, ldb_get_default_basedn(sam_ctx));
2798 if (system_dn == NULL) {
2799 TALLOC_FREE(frame);
2800 return NT_STATUS_NO_MEMORY;
2803 if (!ldb_dn_add_child_fmt(system_dn, "CN=System")) {
2804 TALLOC_FREE(frame);
2805 return NT_STATUS_NO_MEMORY;
2808 if (exclude != NULL) {
2809 exclude_encoded = ldb_binary_encode_string(frame, exclude);
2810 if (exclude_encoded == NULL) {
2811 TALLOC_FREE(frame);
2812 return NT_STATUS_NO_MEMORY;
2815 filter = talloc_asprintf(frame,
2816 "(&(objectClass=trustedDomain)"
2817 "(!(|(trustPartner=%s)(flatName=%s)))"
2818 ")",
2819 exclude_encoded, exclude_encoded);
2820 if (filter == NULL) {
2821 TALLOC_FREE(frame);
2822 return NT_STATUS_NO_MEMORY;
2824 } else {
2825 filter = "(objectClass=trustedDomain)";
2828 ret = dsdb_search(sam_ctx, mem_ctx, res,
2829 system_dn,
2830 LDB_SCOPE_ONELEVEL, attrs,
2831 DSDB_SEARCH_NO_GLOBAL_CATALOG,
2832 "%s", filter);
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)));
2837 TALLOC_FREE(frame);
2838 return status;
2841 TALLOC_FREE(frame);
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",
2874 "flatName",
2875 "trustPartner",
2876 "trustAttributes",
2877 "trustDirection",
2878 "trustType",
2879 "msDS-TrustForestTrustInfo",
2880 NULL
2882 struct ldb_result *trusts_res = NULL;
2883 unsigned int i;
2884 NTSTATUS status;
2886 *_table = NULL;
2888 domain_dn = ldb_get_default_basedn(sam_ctx);
2889 if (domain_dn == NULL) {
2890 TALLOC_FREE(frame);
2891 return NT_STATUS_INTERNAL_ERROR;
2894 table = talloc_zero(mem_ctx, struct dsdb_trust_routing_table);
2895 if (table == NULL) {
2896 TALLOC_FREE(frame);
2897 return NT_STATUS_NO_MEMORY;
2899 talloc_steal(frame, table);
2901 d = talloc_zero(table, struct dsdb_trust_routing_domain);
2902 if (d == NULL) {
2903 TALLOC_FREE(frame);
2904 return NT_STATUS_NO_MEMORY;
2907 status = dsdb_trust_crossref_tdo_info(d, sam_ctx,
2908 domain_dn, NULL,
2909 &d->tdo,
2910 &root_trust_tdo,
2911 &trust_parent_tdo);
2912 if (!NT_STATUS_IS_OK(status)) {
2913 TALLOC_FREE(frame);
2914 return 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) {
2922 TALLOC_FREE(frame);
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)) {
2939 TALLOC_FREE(frame);
2940 return 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)) {
2949 TALLOC_FREE(frame);
2950 return status;
2953 for (i = 0; i < trusts_res->count; i++) {
2954 bool ok;
2955 int cmp;
2957 d = talloc_zero(table, struct dsdb_trust_routing_domain);
2958 if (d == NULL) {
2959 TALLOC_FREE(frame);
2960 return NT_STATUS_NO_MEMORY;
2963 status = dsdb_trust_parse_tdo_info(d,
2964 trusts_res->msgs[i],
2965 &d->tdo);
2966 if (!NT_STATUS_IS_OK(status)) {
2967 TALLOC_FREE(frame);
2968 return 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],
2982 &fti);
2983 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2984 fti = NULL;
2985 status = NT_STATUS_OK;
2987 if (!NT_STATUS_IS_OK(status)) {
2988 TALLOC_FREE(frame);
2989 return status;
2992 if (fti == NULL) {
2993 continue;
2996 status = dsdb_trust_forest_info_to_lsa(d, fti, &d->fti);
2997 if (!NT_STATUS_IS_OK(status)) {
2998 TALLOC_FREE(frame);
2999 return status;
3002 continue;
3005 if (!(d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST)) {
3006 continue;
3009 if (root_direction_tdo == NULL) {
3010 continue;
3013 ok = dom_sid_equal(root_direction_tdo->sid, d->tdo->sid);
3014 if (!ok) {
3015 continue;
3018 cmp = strcasecmp_m(root_direction_tdo->netbios_name.string,
3019 d->tdo->netbios_name.string);
3020 if (cmp != 0) {
3021 continue;
3024 cmp = strcasecmp_m(root_direction_tdo->domain_name.string,
3025 d->tdo->domain_name.string);
3026 if (cmp != 0) {
3027 continue;
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)) {
3033 TALLOC_FREE(frame);
3034 return status;
3038 *_table = talloc_move(mem_ctx, &table);
3039 TALLOC_FREE(frame);
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,
3047 const char *tln)
3049 int cmp;
3051 if (*best_tln == NULL) {
3052 *best_tln = tln;
3053 *best_d = d;
3054 return;
3057 cmp = dns_cmp(*best_tln, tln);
3058 if (cmp != DNS_CMP_FIRST_IS_CHILD) {
3059 return;
3062 *best_tln = tln;
3063 *best_d = d;
3066 const struct lsa_TrustDomainInfoInfoEx *dsdb_trust_routing_by_name(
3067 const struct dsdb_trust_routing_table *table,
3068 const char *name)
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;
3074 if (name == NULL) {
3075 return NULL;
3078 for (d = table->domains; d != NULL; d = d->next) {
3079 bool transitive = false;
3080 bool allow_netbios = false;
3081 bool exclude = false;
3082 uint32_t i;
3084 if (d->tdo->trust_type != LSA_TRUST_TYPE_UPLEVEL) {
3086 * Only uplevel trusts have top level names
3088 continue;
3091 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
3092 transitive = true;
3095 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
3096 transitive = true;
3099 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE) {
3100 transitive = false;
3103 if (d->tdo->trust_type != LSA_TRUST_TYPE_UPLEVEL) {
3104 transitive = false;
3107 switch (d->tdo->trust_type) {
3108 case LSA_TRUST_TYPE_UPLEVEL:
3109 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_UPLEVEL_ONLY) {
3110 break;
3112 allow_netbios = true;
3113 break;
3114 case LSA_TRUST_TYPE_DOWNLEVEL:
3115 allow_netbios = true;
3116 break;
3117 default:
3118 allow_netbios = false;
3119 break;
3122 if (!transitive || d->fti == NULL) {
3123 int cmp;
3125 if (allow_netbios) {
3126 cmp = dns_cmp(name, d->tdo->netbios_name.string);
3127 if (cmp == DNS_CMP_MATCH) {
3129 * exact match
3131 return d->tdo;
3135 cmp = dns_cmp(name, d->tdo->domain_name.string);
3136 if (cmp == DNS_CMP_MATCH) {
3138 * exact match
3140 return d->tdo;
3142 if (cmp != DNS_CMP_FIRST_IS_CHILD) {
3143 continue;
3146 if (!transitive) {
3147 continue;
3150 dsdb_trust_update_best_tln(&best_d, &best_tln, d,
3151 d->tdo->domain_name.string);
3152 continue;
3155 exclude = dsdb_trust_find_tln_ex_match(d->fti, name);
3156 if (exclude) {
3157 continue;
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;
3164 int cmp;
3166 if (!allow_netbios) {
3167 break;
3170 if (f == NULL) {
3171 /* broken record */
3172 continue;
3175 if (f->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
3176 continue;
3179 if (f->flags & LSA_NB_DISABLED_MASK) {
3181 * any flag disables the entry.
3183 continue;
3186 di = &f->forest_trust_data.domain_info;
3187 fti_nbt = di->netbios_domain_name.string;
3188 if (fti_nbt == NULL) {
3189 /* broken record */
3190 continue;
3193 cmp = dns_cmp(name, fti_nbt);
3194 if (cmp == DNS_CMP_MATCH) {
3196 * exact match
3198 return d->tdo;
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;
3206 int cmp;
3208 if (f == NULL) {
3209 /* broken record */
3210 continue;
3213 if (f->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
3214 continue;
3217 if (f->flags & LSA_TLN_DISABLED_MASK) {
3219 * any flag disables the entry.
3221 continue;
3224 u = &f->forest_trust_data;
3225 fti_tln = u->top_level_name.string;
3226 if (fti_tln == NULL) {
3227 continue;
3230 cmp = dns_cmp(name, fti_tln);
3231 switch (cmp) {
3232 case DNS_CMP_MATCH:
3233 case DNS_CMP_FIRST_IS_CHILD:
3234 dsdb_trust_update_best_tln(&best_d, &best_tln,
3235 d, fti_tln);
3236 break;
3237 default:
3238 break;
3243 if (best_d != NULL) {
3244 return best_d->tdo;
3247 return 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;
3257 if (pdi != NULL) {
3258 *pdi = NULL;
3261 if (sid == NULL) {
3262 return NULL;
3265 for (d = table->domains; d != NULL; d = d->next) {
3266 bool transitive = false;
3267 uint32_t i;
3269 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
3270 transitive = true;
3273 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
3274 transitive = true;
3277 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE) {
3278 transitive = false;
3281 if (d->tdo->trust_type != LSA_TRUST_TYPE_UPLEVEL) {
3282 transitive = false;
3285 if (!transitive || d->fti == NULL) {
3286 bool match = false;
3288 match = dom_sid_equal(d->di.domain_sid, sid);
3289 if (match) {
3291 * exact match, it's the domain itself.
3293 if (pdi != NULL) {
3294 *pdi = &d->di;
3296 return d->tdo;
3298 continue;
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;
3305 bool match = false;
3307 if (f == NULL) {
3308 /* broken record */
3309 continue;
3312 if (f->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
3313 continue;
3316 if (f->flags & LSA_SID_DISABLED_MASK) {
3318 * any flag disables the entry.
3320 continue;
3323 di = &f->forest_trust_data.domain_info;
3324 fti_sid = di->domain_sid;
3325 if (fti_sid == NULL) {
3326 /* broken record */
3327 continue;
3330 match = dom_sid_equal(fti_sid, sid);
3331 if (match) {
3333 * exact match, it's a domain in the forest.
3335 if (pdi != NULL) {
3336 *pdi = di;
3338 return d->tdo;
3343 return NULL;
3346 const struct lsa_TrustDomainInfoInfoEx *dsdb_trust_domain_by_name(
3347 const struct dsdb_trust_routing_table *table,
3348 const char *name,
3349 const struct lsa_ForestTrustDomainInfo **pdi)
3351 const struct dsdb_trust_routing_domain *d = NULL;
3353 if (pdi != NULL) {
3354 *pdi = NULL;
3357 if (name == NULL) {
3358 return NULL;
3361 for (d = table->domains; d != NULL; d = d->next) {
3362 bool transitive = false;
3363 uint32_t i;
3365 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
3366 transitive = true;
3369 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
3370 transitive = true;
3373 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE) {
3374 transitive = false;
3377 if (d->tdo->trust_type != LSA_TRUST_TYPE_UPLEVEL) {
3378 transitive = false;
3381 if (!transitive || d->fti == NULL) {
3382 bool match = false;
3384 match = strequal_m(d->di.netbios_domain_name.string,
3385 name);
3386 if (match) {
3388 * exact match for netbios name,
3389 * it's the domain itself.
3391 if (pdi != NULL) {
3392 *pdi = &d->di;
3394 return d->tdo;
3396 match = strequal_m(d->di.dns_domain_name.string,
3397 name);
3398 if (match) {
3400 * exact match for dns name,
3401 * it's the domain itself.
3403 if (pdi != NULL) {
3404 *pdi = &d->di;
3406 return d->tdo;
3408 continue;
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;
3414 bool match = false;
3416 if (f == NULL) {
3417 /* broken record */
3418 continue;
3421 if (f->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
3422 continue;
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,
3428 name);
3429 if (match) {
3431 * exact match for netbios name,
3432 * it's a domain in the forest.
3434 if (pdi != NULL) {
3435 *pdi = di;
3437 return d->tdo;
3441 if (!(f->flags & LSA_TLN_DISABLED_MASK)) {
3442 match = strequal_m(di->dns_domain_name.string,
3443 name);
3444 if (match) {
3446 * exact match for dns name,
3447 * it's a domain in the forest.
3449 if (pdi != NULL) {
3450 *pdi = di;
3452 return d->tdo;
3458 return NULL;