wafsamba: remove unused Build.BuildContext.pre_build overload
[Samba.git] / source4 / dsdb / common / util_trusts.c
blob40777ec14ff75b9100517fd90c29ec9f601397a3
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/crypto.h"
36 #include "libcli/ldap/ldap_ndr.h"
38 NTSTATUS dsdb_trust_forest_info_from_lsa(TALLOC_CTX *mem_ctx,
39 const struct lsa_ForestTrustInformation *lfti,
40 struct ForestTrustInfo **_fti)
42 struct ForestTrustInfo *fti;
43 uint32_t i;
45 *_fti = NULL;
47 fti = talloc_zero(mem_ctx, struct ForestTrustInfo);
48 if (fti == NULL) {
49 return NT_STATUS_NO_MEMORY;
52 fti->version = 1;
53 fti->count = lfti->count;
54 fti->records = talloc_zero_array(mem_ctx,
55 struct ForestTrustInfoRecordArmor,
56 fti->count);
57 if (fti->records == NULL) {
58 TALLOC_FREE(fti);
59 return NT_STATUS_NO_MEMORY;
62 for (i = 0; i < fti->count; i++) {
63 const struct lsa_ForestTrustRecord *lftr = lfti->entries[i];
64 struct ForestTrustInfoRecord *ftr = &fti->records[i].record;
65 struct ForestTrustString *str = NULL;
66 const struct lsa_StringLarge *lstr = NULL;
67 const struct lsa_ForestTrustDomainInfo *linfo = NULL;
68 struct ForestTrustDataDomainInfo *info = NULL;
70 if (lftr == NULL) {
71 TALLOC_FREE(fti);
72 return NT_STATUS_INVALID_PARAMETER;
75 ftr->flags = lftr->flags;
76 ftr->timestamp = lftr->time;
77 ftr->type = (enum ForestTrustInfoRecordType)lftr->type;
79 switch (lftr->type) {
80 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
81 lstr = &lftr->forest_trust_data.top_level_name;
82 str = &ftr->data.name;
84 str->string = talloc_strdup(mem_ctx, lstr->string);
85 if (str->string == NULL) {
86 TALLOC_FREE(fti);
87 return NT_STATUS_NO_MEMORY;
90 break;
92 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
93 lstr = &lftr->forest_trust_data.top_level_name_ex;
94 str = &ftr->data.name;
96 str->string = talloc_strdup(mem_ctx, lstr->string);
97 if (str->string == NULL) {
98 TALLOC_FREE(fti);
99 return NT_STATUS_NO_MEMORY;
102 break;
104 case LSA_FOREST_TRUST_DOMAIN_INFO:
105 linfo = &lftr->forest_trust_data.domain_info;
106 info = &ftr->data.info;
108 if (linfo->domain_sid == NULL) {
109 TALLOC_FREE(fti);
110 return NT_STATUS_INVALID_PARAMETER;
112 info->sid = *linfo->domain_sid;
114 lstr = &linfo->dns_domain_name;
115 str = &info->dns_name;
116 str->string = talloc_strdup(mem_ctx, lstr->string);
117 if (str->string == NULL) {
118 TALLOC_FREE(fti);
119 return NT_STATUS_NO_MEMORY;
122 lstr = &linfo->netbios_domain_name;
123 str = &info->netbios_name;
124 str->string = talloc_strdup(mem_ctx, lstr->string);
125 if (str->string == NULL) {
126 TALLOC_FREE(fti);
127 return NT_STATUS_NO_MEMORY;
130 break;
132 default:
133 return NT_STATUS_NOT_SUPPORTED;
137 *_fti = fti;
138 return NT_STATUS_OK;
141 static NTSTATUS dsdb_trust_forest_record_to_lsa(TALLOC_CTX *mem_ctx,
142 const struct ForestTrustInfoRecord *ftr,
143 struct lsa_ForestTrustRecord **_lftr)
145 struct lsa_ForestTrustRecord *lftr = NULL;
146 const struct ForestTrustString *str = NULL;
147 struct lsa_StringLarge *lstr = NULL;
148 const struct ForestTrustDataDomainInfo *info = NULL;
149 struct lsa_ForestTrustDomainInfo *linfo = NULL;
151 *_lftr = NULL;
153 lftr = talloc_zero(mem_ctx, struct lsa_ForestTrustRecord);
154 if (lftr == NULL) {
155 return NT_STATUS_NO_MEMORY;
158 lftr->flags = ftr->flags;
159 lftr->time = ftr->timestamp;
160 lftr->type = (enum lsa_ForestTrustRecordType)ftr->type;
162 switch (lftr->type) {
163 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
164 lstr = &lftr->forest_trust_data.top_level_name;
165 str = &ftr->data.name;
167 lstr->string = talloc_strdup(mem_ctx, str->string);
168 if (lstr->string == NULL) {
169 TALLOC_FREE(lftr);
170 return NT_STATUS_NO_MEMORY;
173 break;
175 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
176 lstr = &lftr->forest_trust_data.top_level_name_ex;
177 str = &ftr->data.name;
179 lstr->string = talloc_strdup(mem_ctx, str->string);
180 if (lstr->string == NULL) {
181 TALLOC_FREE(lftr);
182 return NT_STATUS_NO_MEMORY;
185 break;
187 case LSA_FOREST_TRUST_DOMAIN_INFO:
188 linfo = &lftr->forest_trust_data.domain_info;
189 info = &ftr->data.info;
191 linfo->domain_sid = dom_sid_dup(lftr, &info->sid);
192 if (linfo->domain_sid == NULL) {
193 TALLOC_FREE(lftr);
194 return NT_STATUS_NO_MEMORY;
197 lstr = &linfo->dns_domain_name;
198 str = &info->dns_name;
199 lstr->string = talloc_strdup(mem_ctx, str->string);
200 if (lstr->string == NULL) {
201 TALLOC_FREE(lftr);
202 return NT_STATUS_NO_MEMORY;
205 lstr = &linfo->netbios_domain_name;
206 str = &info->netbios_name;
207 lstr->string = talloc_strdup(mem_ctx, str->string);
208 if (lstr->string == NULL) {
209 TALLOC_FREE(lftr);
210 return NT_STATUS_NO_MEMORY;
213 break;
215 default:
216 return NT_STATUS_NOT_SUPPORTED;
219 *_lftr = lftr;
220 return NT_STATUS_OK;
223 NTSTATUS dsdb_trust_forest_info_to_lsa(TALLOC_CTX *mem_ctx,
224 const struct ForestTrustInfo *fti,
225 struct lsa_ForestTrustInformation **_lfti)
227 struct lsa_ForestTrustInformation *lfti;
228 uint32_t i;
230 *_lfti = NULL;
232 if (fti->version != 1) {
233 return NT_STATUS_INVALID_PARAMETER;
236 lfti = talloc_zero(mem_ctx, struct lsa_ForestTrustInformation);
237 if (lfti == NULL) {
238 return NT_STATUS_NO_MEMORY;
241 lfti->count = fti->count;
242 lfti->entries = talloc_zero_array(mem_ctx,
243 struct lsa_ForestTrustRecord *,
244 lfti->count);
245 if (lfti->entries == NULL) {
246 TALLOC_FREE(lfti);
247 return NT_STATUS_NO_MEMORY;
250 for (i = 0; i < fti->count; i++) {
251 struct ForestTrustInfoRecord *ftr = &fti->records[i].record;
252 struct lsa_ForestTrustRecord *lftr = NULL;
253 NTSTATUS status;
255 status = dsdb_trust_forest_record_to_lsa(lfti->entries, ftr,
256 &lftr);
257 if (!NT_STATUS_IS_OK(status)) {
258 TALLOC_FREE(lfti);
259 return NT_STATUS_NO_MEMORY;
261 lfti->entries[i] = lftr;
264 *_lfti = lfti;
265 return NT_STATUS_OK;
268 static NTSTATUS dsdb_trust_forest_info_add_record(struct lsa_ForestTrustInformation *fti,
269 const struct lsa_ForestTrustRecord *ftr)
271 struct lsa_ForestTrustRecord **es = NULL;
272 struct lsa_ForestTrustRecord *e = NULL;
273 const struct lsa_StringLarge *dns1 = NULL;
274 struct lsa_StringLarge *dns2 = NULL;
275 const struct lsa_ForestTrustDomainInfo *d1 = NULL;
276 struct lsa_ForestTrustDomainInfo *d2 = NULL;
277 size_t len = 0;
279 es = talloc_realloc(fti, fti->entries,
280 struct lsa_ForestTrustRecord *,
281 fti->count + 1);
282 if (!es) {
283 return NT_STATUS_NO_MEMORY;
285 fti->entries = es;
287 e = talloc_zero(es, struct lsa_ForestTrustRecord);
288 if (e == NULL) {
289 return NT_STATUS_NO_MEMORY;
292 e->type = ftr->type;
293 e->flags = ftr->flags;
294 e->time = ftr->time;
296 switch (ftr->type) {
297 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
298 dns1 = &ftr->forest_trust_data.top_level_name;
299 dns2 = &e->forest_trust_data.top_level_name;
300 break;
302 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
303 dns1 = &ftr->forest_trust_data.top_level_name_ex;
304 dns2 = &e->forest_trust_data.top_level_name_ex;
305 break;
307 case LSA_FOREST_TRUST_DOMAIN_INFO:
308 dns1 = &ftr->forest_trust_data.domain_info.dns_domain_name;
309 dns2 = &e->forest_trust_data.domain_info.dns_domain_name;
310 d1 = &ftr->forest_trust_data.domain_info;
311 d2 = &e->forest_trust_data.domain_info;
312 break;
313 default:
314 return NT_STATUS_INVALID_PARAMETER;
317 if (dns1->string == NULL) {
318 TALLOC_FREE(e);
319 return NT_STATUS_INVALID_PARAMETER;
322 len = strlen(dns1->string);
323 if (len == 0) {
324 TALLOC_FREE(e);
325 return NT_STATUS_INVALID_PARAMETER;
328 dns2->string = talloc_strdup(e, dns1->string);
329 if (dns2->string == NULL) {
330 TALLOC_FREE(e);
331 return NT_STATUS_NO_MEMORY;
334 if (d1 != NULL) {
335 const struct lsa_StringLarge *nb1 = &d1->netbios_domain_name;
336 struct lsa_StringLarge *nb2 = &d2->netbios_domain_name;
338 if (nb1->string == NULL) {
339 TALLOC_FREE(e);
340 return NT_STATUS_INVALID_PARAMETER;
343 len = strlen(nb1->string);
344 if (len == 0) {
345 TALLOC_FREE(e);
346 return NT_STATUS_INVALID_PARAMETER;
348 if (len > 15) {
349 TALLOC_FREE(e);
350 return NT_STATUS_INVALID_PARAMETER;
353 nb2->string = talloc_strdup(e, nb1->string);
354 if (nb2->string == NULL) {
355 TALLOC_FREE(e);
356 return NT_STATUS_NO_MEMORY;
359 if (d1->domain_sid == NULL) {
360 TALLOC_FREE(e);
361 return NT_STATUS_INVALID_PARAMETER;
364 d2->domain_sid = dom_sid_dup(e, d1->domain_sid);
365 if (d2->domain_sid == NULL) {
366 TALLOC_FREE(e);
367 return NT_STATUS_NO_MEMORY;
371 fti->entries[fti->count++] = e;
372 return NT_STATUS_OK;
375 static NTSTATUS dsdb_trust_parse_crossref_info(TALLOC_CTX *mem_ctx,
376 struct ldb_context *sam_ctx,
377 const struct ldb_message *msg,
378 struct lsa_TrustDomainInfoInfoEx **_tdo)
380 TALLOC_CTX *frame = talloc_stackframe();
381 struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
382 const char *dns = NULL;
383 const char *netbios = NULL;
384 struct ldb_dn *nc_dn = NULL;
385 struct dom_sid sid = {};
386 NTSTATUS status;
388 *_tdo = NULL;
389 tdo = talloc_zero(mem_ctx, struct lsa_TrustDomainInfoInfoEx);
390 if (tdo == NULL) {
391 TALLOC_FREE(frame);
392 return NT_STATUS_NO_MEMORY;
394 talloc_steal(frame, tdo);
396 dns = ldb_msg_find_attr_as_string(msg, "dnsRoot", NULL);
397 if (dns == NULL) {
398 TALLOC_FREE(frame);
399 return NT_STATUS_INTERNAL_DB_CORRUPTION;
401 tdo->domain_name.string = talloc_strdup(tdo, dns);
402 if (tdo->domain_name.string == NULL) {
403 TALLOC_FREE(frame);
404 return NT_STATUS_NO_MEMORY;
407 netbios = ldb_msg_find_attr_as_string(msg, "nETBIOSName", NULL);
408 if (netbios == NULL) {
409 TALLOC_FREE(frame);
410 return NT_STATUS_INTERNAL_DB_CORRUPTION;
412 tdo->netbios_name.string = talloc_strdup(tdo, netbios);
413 if (tdo->netbios_name.string == NULL) {
414 TALLOC_FREE(frame);
415 return NT_STATUS_NO_MEMORY;
418 nc_dn = samdb_result_dn(sam_ctx, frame, msg, "ncName", NULL);
419 if (nc_dn == NULL) {
420 TALLOC_FREE(frame);
421 return NT_STATUS_INTERNAL_DB_CORRUPTION;
424 status = dsdb_get_extended_dn_sid(nc_dn, &sid, "SID");
425 if (!NT_STATUS_IS_OK(status)) {
426 TALLOC_FREE(frame);
427 return status;
429 tdo->sid = dom_sid_dup(tdo, &sid);
430 if (tdo->sid == NULL) {
431 TALLOC_FREE(frame);
432 return NT_STATUS_NO_MEMORY;
435 tdo->trust_type = LSA_TRUST_TYPE_UPLEVEL;
436 tdo->trust_direction = LSA_TRUST_DIRECTION_INBOUND |
437 LSA_TRUST_DIRECTION_OUTBOUND;
438 tdo->trust_attributes = LSA_TRUST_ATTRIBUTE_WITHIN_FOREST;
440 *_tdo = talloc_move(mem_ctx, &tdo);
441 TALLOC_FREE(frame);
442 return NT_STATUS_OK;
445 static NTSTATUS dsdb_trust_crossref_tdo_info(TALLOC_CTX *mem_ctx,
446 struct ldb_context *sam_ctx,
447 struct ldb_dn *domain_dn,
448 const char *extra_filter,
449 struct lsa_TrustDomainInfoInfoEx **_tdo,
450 struct lsa_TrustDomainInfoInfoEx **_root_trust_tdo,
451 struct lsa_TrustDomainInfoInfoEx **_trust_parent_tdo)
453 TALLOC_CTX *frame = talloc_stackframe();
454 struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
455 struct lsa_TrustDomainInfoInfoEx *root_trust_tdo = NULL;
456 struct lsa_TrustDomainInfoInfoEx *trust_parent_tdo = NULL;
457 struct ldb_dn *partitions_dn = NULL;
458 const char * const cross_attrs[] = {
459 "dnsRoot",
460 "nETBIOSName",
461 "nCName",
462 "rootTrust",
463 "trustParent",
464 NULL,
466 struct ldb_result *cross_res = NULL;
467 struct ldb_message *msg = NULL;
468 struct ldb_dn *root_trust_dn = NULL;
469 struct ldb_dn *trust_parent_dn = NULL;
470 NTSTATUS status;
471 int ret;
473 if (extra_filter == NULL) {
474 extra_filter = "";
477 *_tdo = NULL;
478 if (_root_trust_tdo != NULL) {
479 *_root_trust_tdo = NULL;
481 if (_trust_parent_tdo != NULL) {
482 *_trust_parent_tdo = NULL;
485 partitions_dn = samdb_partitions_dn(sam_ctx, frame);
486 if (partitions_dn == NULL) {
487 TALLOC_FREE(frame);
488 return NT_STATUS_NO_MEMORY;
491 ret = dsdb_search(sam_ctx, partitions_dn, &cross_res,
492 partitions_dn, LDB_SCOPE_ONELEVEL,
493 cross_attrs,
494 DSDB_SEARCH_ONE_ONLY |
495 DSDB_SEARCH_SHOW_EXTENDED_DN,
496 "(&"
497 "(ncName=%s)"
498 "(objectClass=crossRef)"
499 "(systemFlags:%s:=%u)"
500 "%s"
501 ")",
502 ldb_dn_get_linearized(domain_dn),
503 LDB_OID_COMPARATOR_AND,
504 SYSTEM_FLAG_CR_NTDS_DOMAIN,
505 extra_filter);
506 if (ret != LDB_SUCCESS) {
507 TALLOC_FREE(frame);
508 return dsdb_ldb_err_to_ntstatus(ret);
510 msg = cross_res->msgs[0];
512 status = dsdb_trust_parse_crossref_info(mem_ctx, sam_ctx, msg, &tdo);
513 if (!NT_STATUS_IS_OK(status)) {
514 TALLOC_FREE(frame);
515 return status;
517 talloc_steal(frame, tdo);
519 if (_root_trust_tdo != NULL) {
520 root_trust_dn = samdb_result_dn(sam_ctx, frame, msg,
521 "rootTrust", NULL);
523 if (_trust_parent_tdo != NULL) {
524 trust_parent_dn = samdb_result_dn(sam_ctx, frame, msg,
525 "trustParent", NULL);
528 if (root_trust_dn != NULL) {
529 struct ldb_message *root_trust_msg = NULL;
531 ret = dsdb_search_one(sam_ctx, frame,
532 &root_trust_msg,
533 root_trust_dn,
534 LDB_SCOPE_BASE,
535 cross_attrs,
536 DSDB_SEARCH_NO_GLOBAL_CATALOG,
537 "(objectClass=crossRef)");
538 if (ret != LDB_SUCCESS) {
539 status = dsdb_ldb_err_to_ntstatus(ret);
540 DEBUG(3, ("Failed to search for %s: %s - %s\n",
541 ldb_dn_get_linearized(root_trust_dn),
542 nt_errstr(status), ldb_errstring(sam_ctx)));
543 TALLOC_FREE(frame);
544 return status;
547 status = dsdb_trust_parse_crossref_info(mem_ctx, sam_ctx,
548 root_trust_msg,
549 &root_trust_tdo);
550 if (!NT_STATUS_IS_OK(status)) {
551 TALLOC_FREE(frame);
552 return status;
554 talloc_steal(frame, root_trust_tdo);
557 if (trust_parent_dn != NULL) {
558 struct ldb_message *trust_parent_msg = NULL;
560 ret = dsdb_search_one(sam_ctx, frame,
561 &trust_parent_msg,
562 trust_parent_dn,
563 LDB_SCOPE_BASE,
564 cross_attrs,
565 DSDB_SEARCH_NO_GLOBAL_CATALOG,
566 "(objectClass=crossRef)");
567 if (ret != LDB_SUCCESS) {
568 status = dsdb_ldb_err_to_ntstatus(ret);
569 DEBUG(3, ("Failed to search for %s: %s - %s\n",
570 ldb_dn_get_linearized(trust_parent_dn),
571 nt_errstr(status), ldb_errstring(sam_ctx)));
572 TALLOC_FREE(frame);
573 return status;
576 status = dsdb_trust_parse_crossref_info(mem_ctx, sam_ctx,
577 trust_parent_msg,
578 &trust_parent_tdo);
579 if (!NT_STATUS_IS_OK(status)) {
580 TALLOC_FREE(frame);
581 return status;
583 talloc_steal(frame, trust_parent_tdo);
586 *_tdo = talloc_move(mem_ctx, &tdo);
587 if (_root_trust_tdo != NULL) {
588 *_root_trust_tdo = talloc_move(mem_ctx, &root_trust_tdo);
590 if (_trust_parent_tdo != NULL) {
591 *_trust_parent_tdo = talloc_move(mem_ctx, &trust_parent_tdo);
593 TALLOC_FREE(frame);
594 return NT_STATUS_OK;
597 #define DNS_CMP_FIRST_IS_CHILD -2
598 #define DNS_CMP_FIRST_IS_LESS -1
599 #define DNS_CMP_MATCH 0
600 #define DNS_CMP_SECOND_IS_LESS 1
601 #define DNS_CMP_SECOND_IS_CHILD 2
603 #define DNS_CMP_IS_NO_MATCH(__cmp) \
604 ((__cmp == DNS_CMP_FIRST_IS_LESS) || (__cmp == DNS_CMP_SECOND_IS_LESS))
607 * this function assumes names are well formed DNS names.
608 * it doesn't validate them
610 * It allows strings up to a length of UINT16_MAX - 1
611 * with up to UINT8_MAX components. On overflow this
612 * just returns the result of strcasecmp_m().
614 * Trailing dots (only one) are ignored.
616 * The DNS names are compared per component, starting from
617 * the last one.
619 static int dns_cmp(const char *s1, const char *s2)
621 size_t l1 = 0;
622 const char *p1 = NULL;
623 size_t num_comp1 = 0;
624 uint16_t comp1[UINT8_MAX] = {};
625 size_t l2 = 0;
626 const char *p2 = NULL;
627 size_t num_comp2 = 0;
628 uint16_t comp2[UINT8_MAX] = {};
629 size_t i;
631 if (s1 != NULL) {
632 l1 = strlen(s1);
635 if (s2 != NULL) {
636 l2 = strlen(s2);
640 * trailing '.' are ignored.
642 if (l1 > 1 && s1[l1 - 1] == '.') {
643 l1--;
645 if (l2 > 1 && s2[l2 - 1] == '.') {
646 l2--;
649 for (i = 0; i < ARRAY_SIZE(comp1); i++) {
650 char *p;
652 if (i == 0) {
653 p1 = s1;
655 if (l1 == 0 || l1 >= UINT16_MAX) {
656 /* just use one single component on overflow */
657 break;
661 comp1[num_comp1++] = PTR_DIFF(p1, s1);
663 p = strchr_m(p1, '.');
664 if (p == NULL) {
665 p1 = NULL;
666 break;
669 p1 = p + 1;
672 if (p1 != NULL) {
673 /* just use one single component on overflow */
674 num_comp1 = 0;
675 comp1[num_comp1++] = 0;
676 p1 = NULL;
679 for (i = 0; i < ARRAY_SIZE(comp2); i++) {
680 char *p;
682 if (i == 0) {
683 p2 = s2;
685 if (l2 == 0 || l2 >= UINT16_MAX) {
686 /* just use one single component on overflow */
687 break;
691 comp2[num_comp2++] = PTR_DIFF(p2, s2);
693 p = strchr_m(p2, '.');
694 if (p == NULL) {
695 p2 = NULL;
696 break;
699 p2 = p + 1;
702 if (p2 != NULL) {
703 /* just use one single component on overflow */
704 num_comp2 = 0;
705 comp2[num_comp2++] = 0;
706 p2 = NULL;
709 for (i = 0; i < UINT8_MAX; i++) {
710 int cmp;
712 if (i < num_comp1) {
713 size_t idx = num_comp1 - (i + 1);
714 p1 = s1 + comp1[idx];
715 } else {
716 p1 = NULL;
719 if (i < num_comp2) {
720 size_t idx = num_comp2 - (i + 1);
721 p2 = s2 + comp2[idx];
722 } else {
723 p2 = NULL;
726 if (p1 == NULL && p2 == NULL) {
727 return DNS_CMP_MATCH;
729 if (p1 != NULL && p2 == NULL) {
730 return DNS_CMP_FIRST_IS_CHILD;
732 if (p1 == NULL && p2 != NULL) {
733 return DNS_CMP_SECOND_IS_CHILD;
736 cmp = strcasecmp_m(p1, p2);
737 if (cmp < 0) {
738 return DNS_CMP_FIRST_IS_LESS;
740 if (cmp > 0) {
741 return DNS_CMP_SECOND_IS_LESS;
745 smb_panic(__location__);
746 return -1;
749 static int dsdb_trust_find_tln_match_internal(const struct lsa_ForestTrustInformation *info,
750 enum lsa_ForestTrustRecordType type,
751 uint32_t disable_mask,
752 const char *tln)
754 uint32_t i;
756 for (i = 0; i < info->count; i++) {
757 struct lsa_ForestTrustRecord *e = info->entries[i];
758 struct lsa_StringLarge *t = NULL;
759 int cmp;
761 if (e == NULL) {
762 continue;
765 if (e->type != type) {
766 continue;
769 if (e->flags & disable_mask) {
770 continue;
773 switch (type) {
774 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
775 t = &e->forest_trust_data.top_level_name;
776 break;
777 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
778 t = &e->forest_trust_data.top_level_name_ex;
779 break;
780 default:
781 break;
784 if (t == NULL) {
785 continue;
788 cmp = dns_cmp(tln, t->string);
789 switch (cmp) {
790 case DNS_CMP_MATCH:
791 case DNS_CMP_FIRST_IS_CHILD:
792 return i;
796 return -1;
799 static bool dsdb_trust_find_tln_match(const struct lsa_ForestTrustInformation *info,
800 const char *tln)
802 int m;
804 m = dsdb_trust_find_tln_match_internal(info,
805 LSA_FOREST_TRUST_TOP_LEVEL_NAME,
806 LSA_TLN_DISABLED_MASK,
807 tln);
808 if (m != -1) {
809 return true;
812 return false;
815 static bool dsdb_trust_find_tln_ex_match(const struct lsa_ForestTrustInformation *info,
816 const char *tln)
818 int m;
820 m = dsdb_trust_find_tln_match_internal(info,
821 LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX,
823 tln);
824 if (m != -1) {
825 return true;
828 return false;
831 NTSTATUS dsdb_trust_local_tdo_info(TALLOC_CTX *mem_ctx,
832 struct ldb_context *sam_ctx,
833 struct lsa_TrustDomainInfoInfoEx **_tdo)
835 struct ldb_dn *domain_dn = NULL;
837 domain_dn = ldb_get_default_basedn(sam_ctx);
838 if (domain_dn == NULL) {
839 return NT_STATUS_INTERNAL_ERROR;
842 return dsdb_trust_crossref_tdo_info(mem_ctx, sam_ctx,
843 domain_dn, NULL,
844 _tdo, NULL, NULL);
847 NTSTATUS dsdb_trust_xref_tdo_info(TALLOC_CTX *mem_ctx,
848 struct ldb_context *sam_ctx,
849 struct lsa_TrustDomainInfoInfoEx **_tdo)
852 * The extra filter makes sure we only find the forest root domain
854 const char *extra_filter = "(!(|(rootTrust=*)(trustParent=*)))";
855 struct ldb_dn *domain_dn = NULL;
857 domain_dn = ldb_get_default_basedn(sam_ctx);
858 if (domain_dn == NULL) {
859 return NT_STATUS_INTERNAL_ERROR;
862 return dsdb_trust_crossref_tdo_info(mem_ctx, sam_ctx,
863 domain_dn, extra_filter,
864 _tdo, NULL, NULL);
867 static int dsdb_trust_xref_sort_msgs(struct ldb_message **_m1,
868 struct ldb_message **_m2)
870 struct ldb_message *m1 = *_m1;
871 struct ldb_message *m2 = *_m2;
872 const char *dns1 = NULL;
873 const char *dns2 = NULL;
874 int cmp;
875 struct ldb_message_element *rootTrust1 = NULL;
876 struct ldb_message_element *trustParent1 = NULL;
877 struct ldb_message_element *rootTrust2 = NULL;
878 struct ldb_message_element *trustParent2 = NULL;
880 dns1 = ldb_msg_find_attr_as_string(m1, "dnsRoot", NULL);
881 dns2 = ldb_msg_find_attr_as_string(m2, "dnsRoot", NULL);
883 cmp = dns_cmp(dns1, dns2);
884 switch (cmp) {
885 case DNS_CMP_FIRST_IS_CHILD:
886 return -1;
887 case DNS_CMP_SECOND_IS_CHILD:
888 return 1;
891 rootTrust1 = ldb_msg_find_element(m1, "rootTrust");
892 trustParent1 = ldb_msg_find_element(m1, "trustParent");
893 rootTrust2 = ldb_msg_find_element(m2, "rootTrust");
894 trustParent2 = ldb_msg_find_element(m2, "trustParent");
896 if (rootTrust1 == NULL && trustParent1 == NULL) {
897 /* m1 is the forest root */
898 return -1;
900 if (rootTrust2 == NULL && trustParent2 == NULL) {
901 /* m2 is the forest root */
902 return 1;
905 return cmp;
908 static int dsdb_trust_xref_sort_vals(struct ldb_val *v1,
909 struct ldb_val *v2)
911 const char *dns1 = (const char *)v1->data;
912 const char *dns2 = (const char *)v2->data;
914 return dns_cmp(dns1, dns2);
917 NTSTATUS dsdb_trust_xref_forest_info(TALLOC_CTX *mem_ctx,
918 struct ldb_context *sam_ctx,
919 struct lsa_ForestTrustInformation **_info)
921 TALLOC_CTX *frame = talloc_stackframe();
922 struct lsa_ForestTrustInformation *info = NULL;
923 struct ldb_dn *partitions_dn = NULL;
924 const char * const cross_attrs1[] = {
925 "uPNSuffixes",
926 "msDS-SPNSuffixes",
927 NULL,
929 struct ldb_result *cross_res1 = NULL;
930 struct ldb_message_element *upn_el = NULL;
931 struct ldb_message_element *spn_el = NULL;
932 struct ldb_message *tln_msg = NULL;
933 struct ldb_message_element *tln_el = NULL;
934 const char * const cross_attrs2[] = {
935 "dnsRoot",
936 "nETBIOSName",
937 "nCName",
938 "rootTrust",
939 "trustParent",
940 NULL,
942 struct ldb_result *cross_res2 = NULL;
943 int ret;
944 unsigned int i;
945 bool restart = false;
947 *_info = NULL;
948 info = talloc_zero(mem_ctx, struct lsa_ForestTrustInformation);
949 if (info == NULL) {
950 TALLOC_FREE(frame);
951 return NT_STATUS_NO_MEMORY;
953 talloc_steal(frame, info);
955 partitions_dn = samdb_partitions_dn(sam_ctx, frame);
956 if (partitions_dn == NULL) {
957 TALLOC_FREE(frame);
958 return NT_STATUS_NO_MEMORY;
961 ret = dsdb_search_dn(sam_ctx, partitions_dn, &cross_res1,
962 partitions_dn, cross_attrs1, 0);
963 if (ret != LDB_SUCCESS) {
964 TALLOC_FREE(frame);
965 return dsdb_ldb_err_to_ntstatus(ret);
968 ret = dsdb_search(sam_ctx, partitions_dn, &cross_res2,
969 partitions_dn, LDB_SCOPE_ONELEVEL,
970 cross_attrs2,
971 DSDB_SEARCH_SHOW_EXTENDED_DN,
972 "(&(objectClass=crossRef)"
973 "(systemFlags:%s:=%u))",
974 LDB_OID_COMPARATOR_AND,
975 SYSTEM_FLAG_CR_NTDS_DOMAIN);
976 if (ret != LDB_SUCCESS) {
977 TALLOC_FREE(frame);
978 return dsdb_ldb_err_to_ntstatus(ret);
982 * Sort the domains as trees, starting with the forest root
984 TYPESAFE_QSORT(cross_res2->msgs, cross_res2->count,
985 dsdb_trust_xref_sort_msgs);
987 upn_el = ldb_msg_find_element(cross_res1->msgs[0], "uPNSuffixes");
988 if (upn_el != NULL) {
989 upn_el->name = "__tln__";
991 spn_el = ldb_msg_find_element(cross_res1->msgs[0], "msDS-SPNSuffixes");
992 if (spn_el != NULL) {
993 spn_el->name = "__tln__";
995 ret = ldb_msg_normalize(sam_ctx, frame, cross_res1->msgs[0], &tln_msg);
996 if (ret != LDB_SUCCESS) {
997 TALLOC_FREE(frame);
998 return dsdb_ldb_err_to_ntstatus(ret);
1000 tln_el = ldb_msg_find_element(tln_msg, "__tln__");
1001 if (tln_el != NULL) {
1003 * Sort the domains as trees
1005 TYPESAFE_QSORT(tln_el->values, tln_el->num_values,
1006 dsdb_trust_xref_sort_vals);
1009 for (i=0; i < cross_res2->count; i++) {
1010 struct ldb_message *m = cross_res2->msgs[i];
1011 const char *dns = NULL;
1012 const char *netbios = NULL;
1013 struct ldb_dn *nc_dn = NULL;
1014 struct dom_sid sid = {};
1015 struct lsa_ForestTrustRecord e = {};
1016 struct lsa_ForestTrustDomainInfo *d = NULL;
1017 struct lsa_StringLarge *t = NULL;
1018 bool match = false;
1019 NTSTATUS status;
1021 dns = ldb_msg_find_attr_as_string(m, "dnsRoot", NULL);
1022 if (dns == NULL) {
1023 TALLOC_FREE(frame);
1024 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1027 netbios = ldb_msg_find_attr_as_string(m, "nETBIOSName", NULL);
1028 if (netbios == NULL) {
1029 TALLOC_FREE(frame);
1030 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1033 nc_dn = samdb_result_dn(sam_ctx, m, m, "ncName", NULL);
1034 if (nc_dn == NULL) {
1035 TALLOC_FREE(frame);
1036 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1039 status = dsdb_get_extended_dn_sid(nc_dn, &sid, "SID");
1040 if (!NT_STATUS_IS_OK(status)) {
1041 TALLOC_FREE(frame);
1042 return status;
1045 match = dsdb_trust_find_tln_match(info, dns);
1046 if (!match) {
1048 * First the TOP_LEVEL_NAME, if required
1050 e = (struct lsa_ForestTrustRecord) {
1051 .flags = 0,
1052 .type = LSA_FOREST_TRUST_TOP_LEVEL_NAME,
1053 .time = 0, /* so far always 0 in traces. */
1056 t = &e.forest_trust_data.top_level_name;
1057 t->string = dns;
1059 status = dsdb_trust_forest_info_add_record(info, &e);
1060 if (!NT_STATUS_IS_OK(status)) {
1061 TALLOC_FREE(frame);
1062 return status;
1067 * Then the DOMAIN_INFO
1069 e = (struct lsa_ForestTrustRecord) {
1070 .flags = 0,
1071 .type = LSA_FOREST_TRUST_DOMAIN_INFO,
1072 .time = 0, /* so far always 0 in traces. */
1074 d = &e.forest_trust_data.domain_info;
1075 d->domain_sid = &sid;
1076 d->dns_domain_name.string = dns;
1077 d->netbios_domain_name.string = netbios;
1079 status = dsdb_trust_forest_info_add_record(info, &e);
1080 if (!NT_STATUS_IS_OK(status)) {
1081 TALLOC_FREE(frame);
1082 return status;
1086 for (i=0; (tln_el != NULL) && i < tln_el->num_values; i++) {
1087 const struct ldb_val *v = &tln_el->values[i];
1088 const char *dns = (const char *)v->data;
1089 struct lsa_ForestTrustRecord e = {};
1090 struct lsa_StringLarge *t = NULL;
1091 bool match = false;
1092 NTSTATUS status;
1094 if (dns == NULL) {
1095 TALLOC_FREE(frame);
1096 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1099 match = dsdb_trust_find_tln_match(info, dns);
1100 if (match) {
1101 continue;
1105 * an additional the TOP_LEVEL_NAME
1107 e = (struct lsa_ForestTrustRecord) {
1108 .flags = 0,
1109 .type = LSA_FOREST_TRUST_TOP_LEVEL_NAME,
1110 .time = 0, /* so far always 0 in traces. */
1112 t = &e.forest_trust_data.top_level_name;
1113 t->string = dns;
1115 status = dsdb_trust_forest_info_add_record(info, &e);
1116 if (!NT_STATUS_IS_OK(status)) {
1117 TALLOC_FREE(frame);
1118 return status;
1122 for (i=0; i < info->count; restart ? i=0 : i++) {
1123 struct lsa_ForestTrustRecord *tr = info->entries[i];
1124 const struct lsa_StringLarge *ts = NULL;
1125 uint32_t c;
1127 restart = false;
1129 if (tr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
1130 continue;
1133 ts = &tr->forest_trust_data.top_level_name;
1135 for (c = i + 1; c < info->count; c++) {
1136 struct lsa_ForestTrustRecord *cr = info->entries[c];
1137 const struct lsa_StringLarge *cs = NULL;
1138 uint32_t j;
1139 int cmp;
1141 if (cr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
1142 continue;
1145 cs = &cr->forest_trust_data.top_level_name;
1147 cmp = dns_cmp(ts->string, cs->string);
1148 if (DNS_CMP_IS_NO_MATCH(cmp)) {
1149 continue;
1151 if (cmp != DNS_CMP_FIRST_IS_CHILD) {
1152 /* can't happen ... */
1153 continue;
1156 ts = NULL;
1157 tr = NULL;
1158 TALLOC_FREE(info->entries[i]);
1159 info->entries[i] = info->entries[c];
1161 for (j = c + 1; j < info->count; j++) {
1162 info->entries[j-1] = info->entries[j];
1164 info->count -= 1;
1165 restart = true;
1166 break;
1170 *_info = talloc_move(mem_ctx, &info);
1171 TALLOC_FREE(frame);
1172 return NT_STATUS_OK;
1175 NTSTATUS dsdb_trust_parse_tdo_info(TALLOC_CTX *mem_ctx,
1176 struct ldb_message *m,
1177 struct lsa_TrustDomainInfoInfoEx **_tdo)
1179 struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
1180 const char *dns = NULL;
1181 const char *netbios = NULL;
1183 *_tdo = NULL;
1185 tdo = talloc_zero(mem_ctx, struct lsa_TrustDomainInfoInfoEx);
1186 if (tdo == NULL) {
1187 return NT_STATUS_NO_MEMORY;
1190 dns = ldb_msg_find_attr_as_string(m, "trustPartner", NULL);
1191 if (dns == NULL) {
1192 TALLOC_FREE(tdo);
1193 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1195 tdo->domain_name.string = talloc_strdup(tdo, dns);
1196 if (tdo->domain_name.string == NULL) {
1197 TALLOC_FREE(tdo);
1198 return NT_STATUS_NO_MEMORY;
1201 netbios = ldb_msg_find_attr_as_string(m, "flatName", NULL);
1202 if (netbios == NULL) {
1203 TALLOC_FREE(tdo);
1204 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1206 tdo->netbios_name.string = talloc_strdup(tdo, netbios);
1207 if (tdo->netbios_name.string == NULL) {
1208 TALLOC_FREE(tdo);
1209 return NT_STATUS_NO_MEMORY;
1212 tdo->sid = samdb_result_dom_sid(tdo, m, "securityIdentifier");
1213 if (tdo->sid == NULL) {
1214 TALLOC_FREE(tdo);
1215 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1218 tdo->trust_type = ldb_msg_find_attr_as_uint(m, "trustType", 0);
1219 tdo->trust_direction = ldb_msg_find_attr_as_uint(m, "trustDirection", 0);
1220 tdo->trust_attributes = ldb_msg_find_attr_as_uint(m, "trustAttributes", 0);
1222 *_tdo = tdo;
1223 return NT_STATUS_OK;
1226 NTSTATUS dsdb_trust_parse_forest_info(TALLOC_CTX *mem_ctx,
1227 struct ldb_message *m,
1228 struct ForestTrustInfo **_fti)
1230 const struct ldb_val *ft_blob = NULL;
1231 struct ForestTrustInfo *fti = NULL;
1232 enum ndr_err_code ndr_err;
1234 *_fti = NULL;
1236 ft_blob = ldb_msg_find_ldb_val(m, "msDS-TrustForestTrustInfo");
1237 if (ft_blob == NULL) {
1238 return NT_STATUS_NOT_FOUND;
1241 fti = talloc_zero(mem_ctx, struct ForestTrustInfo);
1242 if (fti == NULL) {
1243 return NT_STATUS_NO_MEMORY;
1246 /* ldb_val is equivalent to DATA_BLOB */
1247 ndr_err = ndr_pull_struct_blob_all(ft_blob, fti, fti,
1248 (ndr_pull_flags_fn_t)ndr_pull_ForestTrustInfo);
1249 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1250 TALLOC_FREE(fti);
1251 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1254 *_fti = fti;
1255 return NT_STATUS_OK;
1258 NTSTATUS dsdb_trust_normalize_forest_info_step1(TALLOC_CTX *mem_ctx,
1259 const struct lsa_ForestTrustInformation *gfti,
1260 struct lsa_ForestTrustInformation **_nfti)
1262 TALLOC_CTX *frame = talloc_stackframe();
1263 struct lsa_ForestTrustInformation *nfti;
1264 uint32_t n;
1266 *_nfti = NULL;
1268 nfti = talloc_zero(mem_ctx, struct lsa_ForestTrustInformation);
1269 if (nfti == NULL) {
1270 TALLOC_FREE(frame);
1271 return NT_STATUS_NO_MEMORY;
1273 talloc_steal(frame, nfti);
1276 * First we copy every record and remove possible trailing dots
1277 * from dns names.
1279 * We also NULL out dublicates. The first one wins and
1280 * we keep 'count' as is. This is required in order to
1281 * provide the correct index for collision records.
1283 for (n = 0; n < gfti->count; n++) {
1284 const struct lsa_ForestTrustRecord *gftr = gfti->entries[n];
1285 struct lsa_ForestTrustRecord *nftr = NULL;
1286 struct lsa_ForestTrustDomainInfo *ninfo = NULL;
1287 struct lsa_StringLarge *ntln = NULL;
1288 struct lsa_StringLarge *nnb = NULL;
1289 struct dom_sid *nsid = NULL;
1290 NTSTATUS status;
1291 size_t len = 0;
1292 char *p = NULL;
1293 uint32_t c;
1295 if (gftr == NULL) {
1296 TALLOC_FREE(frame);
1297 return NT_STATUS_INVALID_PARAMETER;
1300 status = dsdb_trust_forest_info_add_record(nfti, gftr);
1301 if (!NT_STATUS_IS_OK(status)) {
1302 TALLOC_FREE(frame);
1303 return status;
1306 nftr = nfti->entries[n];
1308 switch (nftr->type) {
1309 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
1310 ntln = &nftr->forest_trust_data.top_level_name;
1311 break;
1313 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
1314 ntln = &nftr->forest_trust_data.top_level_name_ex;
1315 break;
1317 case LSA_FOREST_TRUST_DOMAIN_INFO:
1318 ninfo = &nftr->forest_trust_data.domain_info;
1319 ntln = &ninfo->dns_domain_name;
1320 nnb = &ninfo->netbios_domain_name;
1321 nsid = ninfo->domain_sid;
1322 break;
1324 default:
1325 TALLOC_FREE(frame);
1326 return NT_STATUS_INVALID_PARAMETER;
1330 * We remove one trailing '.' before checking
1331 * for invalid dots.
1333 * domain.com. becomes domain.com
1334 * domain.com.. becomes domain.com.
1336 * Then the following is invalid:
1338 * domain..com
1339 * .domain.com
1340 * domain.com.
1342 len = strlen(ntln->string);
1343 if (len > 1 && ntln->string[len - 1] == '.') {
1344 const char *cp = &ntln->string[len - 1];
1345 p = discard_const_p(char, cp);
1346 *p= '\0';
1348 if (ntln->string[0] == '.') {
1349 TALLOC_FREE(frame);
1350 return NT_STATUS_INVALID_PARAMETER;
1352 p = strstr_m(ntln->string, "..");
1353 if (p != NULL) {
1354 TALLOC_FREE(frame);
1355 return NT_STATUS_INVALID_PARAMETER;
1358 for (c = 0; c < n; c++) {
1359 const struct lsa_ForestTrustRecord *cftr = nfti->entries[c];
1360 const struct lsa_ForestTrustDomainInfo *cinfo = NULL;
1361 const struct lsa_StringLarge *ctln = NULL;
1362 const struct lsa_StringLarge *cnb = NULL;
1363 const struct dom_sid *csid = NULL;
1364 int cmp;
1366 if (cftr == NULL) {
1367 continue;
1370 if (cftr->type != nftr->type) {
1371 continue;
1374 switch (cftr->type) {
1375 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
1376 ctln = &cftr->forest_trust_data.top_level_name;
1377 break;
1379 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
1380 ctln = &cftr->forest_trust_data.top_level_name_ex;
1381 break;
1383 case LSA_FOREST_TRUST_DOMAIN_INFO:
1384 cinfo = &cftr->forest_trust_data.domain_info;
1385 ctln = &cinfo->dns_domain_name;
1386 cnb = &cinfo->netbios_domain_name;
1387 csid = cinfo->domain_sid;
1388 break;
1390 default:
1391 TALLOC_FREE(frame);
1392 return NT_STATUS_INVALID_PARAMETER;
1395 cmp = dns_cmp(ntln->string, ctln->string);
1396 if (cmp == DNS_CMP_MATCH) {
1397 nftr = NULL;
1398 TALLOC_FREE(nfti->entries[n]);
1399 break;
1402 if (cinfo == NULL) {
1403 continue;
1406 cmp = strcasecmp_m(nnb->string, cnb->string);
1407 if (cmp == 0) {
1408 nftr = NULL;
1409 TALLOC_FREE(nfti->entries[n]);
1410 break;
1413 cmp = dom_sid_compare(nsid, csid);
1414 if (cmp == 0) {
1415 nftr = NULL;
1416 TALLOC_FREE(nfti->entries[n]);
1417 break;
1423 * Now we check that only true top level names are provided
1425 for (n = 0; n < nfti->count; n++) {
1426 const struct lsa_ForestTrustRecord *nftr = nfti->entries[n];
1427 const struct lsa_StringLarge *ntln = NULL;
1428 uint32_t c;
1430 if (nftr == NULL) {
1431 continue;
1434 if (nftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
1435 continue;
1438 ntln = &nftr->forest_trust_data.top_level_name;
1440 for (c = 0; c < nfti->count; c++) {
1441 const struct lsa_ForestTrustRecord *cftr = nfti->entries[c];
1442 const struct lsa_StringLarge *ctln = NULL;
1443 int cmp;
1445 if (cftr == NULL) {
1446 continue;
1449 if (cftr == nftr) {
1450 continue;
1453 if (cftr->type != nftr->type) {
1454 continue;
1457 ctln = &cftr->forest_trust_data.top_level_name;
1459 cmp = dns_cmp(ntln->string, ctln->string);
1460 if (DNS_CMP_IS_NO_MATCH(cmp)) {
1461 continue;
1464 TALLOC_FREE(frame);
1465 return NT_STATUS_INVALID_PARAMETER;
1470 * Now we check that only true sub level excludes are provided
1472 for (n = 0; n < nfti->count; n++) {
1473 const struct lsa_ForestTrustRecord *nftr = nfti->entries[n];
1474 const struct lsa_StringLarge *ntln = NULL;
1475 uint32_t c;
1476 bool found_tln = false;
1478 if (nftr == NULL) {
1479 continue;
1482 if (nftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX) {
1483 continue;
1486 ntln = &nftr->forest_trust_data.top_level_name;
1488 for (c = 0; c < nfti->count; c++) {
1489 const struct lsa_ForestTrustRecord *cftr = nfti->entries[c];
1490 const struct lsa_StringLarge *ctln = NULL;
1491 int cmp;
1493 if (cftr == NULL) {
1494 continue;
1497 if (cftr == nftr) {
1498 continue;
1501 if (cftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
1502 continue;
1505 ctln = &cftr->forest_trust_data.top_level_name;
1507 cmp = dns_cmp(ntln->string, ctln->string);
1508 if (cmp == DNS_CMP_FIRST_IS_CHILD) {
1509 found_tln = true;
1510 break;
1514 if (found_tln) {
1515 continue;
1518 TALLOC_FREE(frame);
1519 return NT_STATUS_INVALID_PARAMETER;
1523 * Now we check that there's a top level name for each domain
1525 for (n = 0; n < nfti->count; n++) {
1526 const struct lsa_ForestTrustRecord *nftr = nfti->entries[n];
1527 const struct lsa_ForestTrustDomainInfo *ninfo = NULL;
1528 const struct lsa_StringLarge *ntln = NULL;
1529 uint32_t c;
1530 bool found_tln = false;
1532 if (nftr == NULL) {
1533 continue;
1536 if (nftr->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
1537 continue;
1540 ninfo = &nftr->forest_trust_data.domain_info;
1541 ntln = &ninfo->dns_domain_name;
1543 for (c = 0; c < nfti->count; c++) {
1544 const struct lsa_ForestTrustRecord *cftr = nfti->entries[c];
1545 const struct lsa_StringLarge *ctln = NULL;
1546 int cmp;
1548 if (cftr == NULL) {
1549 continue;
1552 if (cftr == nftr) {
1553 continue;
1556 if (cftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
1557 continue;
1560 ctln = &cftr->forest_trust_data.top_level_name;
1562 cmp = dns_cmp(ntln->string, ctln->string);
1563 if (cmp == DNS_CMP_MATCH) {
1564 found_tln = true;
1565 break;
1567 if (cmp == DNS_CMP_FIRST_IS_CHILD) {
1568 found_tln = true;
1569 break;
1573 if (found_tln) {
1574 continue;
1577 TALLOC_FREE(frame);
1578 return NT_STATUS_INVALID_PARAMETER;
1581 *_nfti = talloc_move(mem_ctx, &nfti);
1582 TALLOC_FREE(frame);
1583 return NT_STATUS_OK;
1586 NTSTATUS dsdb_trust_normalize_forest_info_step2(TALLOC_CTX *mem_ctx,
1587 const struct lsa_ForestTrustInformation *gfti,
1588 struct lsa_ForestTrustInformation **_nfti)
1590 TALLOC_CTX *frame = talloc_stackframe();
1591 struct timeval tv = timeval_current();
1592 NTTIME now = timeval_to_nttime(&tv);
1593 struct lsa_ForestTrustInformation *nfti;
1594 uint32_t g;
1596 *_nfti = NULL;
1598 nfti = talloc_zero(mem_ctx, struct lsa_ForestTrustInformation);
1599 if (nfti == NULL) {
1600 TALLOC_FREE(frame);
1601 return NT_STATUS_NO_MEMORY;
1603 talloc_steal(frame, nfti);
1606 * Now we add TOP_LEVEL_NAME[_EX] in reverse order
1607 * followed by LSA_FOREST_TRUST_DOMAIN_INFO in reverse order.
1609 * This also removes the possible NULL entries generated in step1.
1612 for (g = 0; g < gfti->count; g++) {
1613 const struct lsa_ForestTrustRecord *gftr = gfti->entries[gfti->count - (g+1)];
1614 struct lsa_ForestTrustRecord tftr;
1615 bool skip = false;
1616 NTSTATUS status;
1618 if (gftr == NULL) {
1619 continue;
1622 switch (gftr->type) {
1623 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
1624 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
1625 break;
1627 case LSA_FOREST_TRUST_DOMAIN_INFO:
1628 skip = true;
1629 break;
1631 default:
1632 TALLOC_FREE(frame);
1633 return NT_STATUS_INVALID_PARAMETER;
1636 if (skip) {
1637 continue;
1640 /* make a copy in order to update the time. */
1641 tftr = *gftr;
1642 if (tftr.time == 0) {
1643 tftr.time = now;
1646 status = dsdb_trust_forest_info_add_record(nfti, &tftr);
1647 if (!NT_STATUS_IS_OK(status)) {
1648 TALLOC_FREE(frame);
1649 return status;
1653 for (g = 0; g < gfti->count; g++) {
1654 const struct lsa_ForestTrustRecord *gftr = gfti->entries[gfti->count - (g+1)];
1655 struct lsa_ForestTrustRecord tftr;
1656 bool skip = false;
1657 NTSTATUS status;
1659 if (gftr == NULL) {
1660 continue;
1663 switch (gftr->type) {
1664 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
1665 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
1666 skip = true;
1667 break;
1669 case LSA_FOREST_TRUST_DOMAIN_INFO:
1670 break;
1672 default:
1673 TALLOC_FREE(frame);
1674 return NT_STATUS_INVALID_PARAMETER;
1677 if (skip) {
1678 continue;
1681 /* make a copy in order to update the time. */
1682 tftr = *gftr;
1683 if (tftr.time == 0) {
1684 tftr.time = now;
1687 status = dsdb_trust_forest_info_add_record(nfti, &tftr);
1688 if (!NT_STATUS_IS_OK(status)) {
1689 TALLOC_FREE(frame);
1690 return status;
1694 *_nfti = talloc_move(mem_ctx, &nfti);
1695 TALLOC_FREE(frame);
1696 return NT_STATUS_OK;
1699 static NTSTATUS dsdb_trust_add_collision(
1700 struct lsa_ForestTrustCollisionInfo *c_info,
1701 enum lsa_ForestTrustCollisionRecordType type,
1702 uint32_t idx, uint32_t flags,
1703 const char *tdo_name)
1705 struct lsa_ForestTrustCollisionRecord **es;
1706 uint32_t i = c_info->count;
1708 es = talloc_realloc(c_info, c_info->entries,
1709 struct lsa_ForestTrustCollisionRecord *, i + 1);
1710 if (es == NULL) {
1711 return NT_STATUS_NO_MEMORY;
1713 c_info->entries = es;
1714 c_info->count = i + 1;
1716 es[i] = talloc_zero(es, struct lsa_ForestTrustCollisionRecord);
1717 if (es[i] == NULL) {
1718 return NT_STATUS_NO_MEMORY;
1721 es[i]->index = idx;
1722 es[i]->type = type;
1723 es[i]->flags = flags;
1724 es[i]->name.string = talloc_strdup(es[i], tdo_name);
1725 if (es[i]->name.string == NULL) {
1726 return NT_STATUS_NO_MEMORY;
1729 return NT_STATUS_OK;
1732 NTSTATUS dsdb_trust_verify_forest_info(const struct lsa_TrustDomainInfoInfoEx *ref_tdo,
1733 const struct lsa_ForestTrustInformation *ref_fti,
1734 enum lsa_ForestTrustCollisionRecordType collision_type,
1735 struct lsa_ForestTrustCollisionInfo *c_info,
1736 struct lsa_ForestTrustInformation *new_fti)
1738 uint32_t n;
1740 for (n = 0; n < new_fti->count; n++) {
1741 struct lsa_ForestTrustRecord *nftr = new_fti->entries[n];
1742 struct lsa_StringLarge *ntln = NULL;
1743 bool ntln_excluded = false;
1744 uint32_t flags = 0;
1745 uint32_t r;
1746 NTSTATUS status;
1748 if (nftr == NULL) {
1749 continue;
1752 if (nftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
1753 continue;
1756 ntln = &nftr->forest_trust_data.top_level_name;
1757 if (ntln->string == NULL) {
1758 return NT_STATUS_INVALID_PARAMETER;
1761 ntln_excluded = dsdb_trust_find_tln_ex_match(ref_fti,
1762 ntln->string);
1764 /* check if this is already taken and not excluded */
1765 for (r = 0; r < ref_fti->count; r++) {
1766 const struct lsa_ForestTrustRecord *rftr =
1767 ref_fti->entries[r];
1768 const struct lsa_StringLarge *rtln = NULL;
1769 int cmp;
1771 if (rftr == NULL) {
1772 continue;
1775 if (rftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
1776 continue;
1779 rtln = &rftr->forest_trust_data.top_level_name;
1780 if (rtln->string == NULL) {
1781 continue;
1784 cmp = dns_cmp(ntln->string, rtln->string);
1785 if (DNS_CMP_IS_NO_MATCH(cmp)) {
1786 continue;
1788 if (cmp == DNS_CMP_MATCH) {
1789 /* We need to normalize the string */
1790 ntln->string = talloc_strdup(nftr,
1791 rtln->string);
1792 if (ntln->string == NULL) {
1793 return NT_STATUS_NO_MEMORY;
1797 if (ntln_excluded) {
1798 continue;
1801 if (rftr->flags & LSA_TLN_DISABLED_MASK) {
1802 continue;
1805 if (nftr->flags & LSA_TLN_DISABLED_MASK) {
1806 continue;
1809 if (cmp == DNS_CMP_SECOND_IS_CHILD) {
1810 bool m;
1813 * If the conflicting tln is a child, check if
1814 * we have an exclusion record for it.
1816 m = dsdb_trust_find_tln_ex_match(new_fti,
1817 rtln->string);
1818 if (m) {
1819 continue;
1823 flags |= LSA_TLN_DISABLED_CONFLICT;
1826 if (flags == 0) {
1827 continue;
1830 nftr->flags |= flags;
1832 status = dsdb_trust_add_collision(c_info,
1833 collision_type,
1834 n, nftr->flags,
1835 ref_tdo->domain_name.string);
1836 if (!NT_STATUS_IS_OK(status)) {
1837 return status;
1841 for (n = 0; n < new_fti->count; n++) {
1842 struct lsa_ForestTrustRecord *nftr = new_fti->entries[n];
1843 struct lsa_ForestTrustDomainInfo *ninfo = NULL;
1844 struct lsa_StringLarge *ntln = NULL;
1845 struct lsa_StringLarge *nnb = NULL;
1846 struct dom_sid *nsid = NULL;
1847 bool ntln_found = false;
1848 uint32_t flags = 0;
1849 uint32_t r;
1850 NTSTATUS status;
1852 if (nftr == NULL) {
1853 continue;
1856 if (nftr->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
1857 continue;
1860 ninfo = &nftr->forest_trust_data.domain_info;
1861 ntln = &ninfo->dns_domain_name;
1862 if (ntln->string == NULL) {
1863 return NT_STATUS_INVALID_PARAMETER;
1865 nnb = &ninfo->netbios_domain_name;
1866 if (nnb->string == NULL) {
1867 return NT_STATUS_INVALID_PARAMETER;
1869 nsid = ninfo->domain_sid;
1870 if (nsid == NULL) {
1871 return NT_STATUS_INVALID_PARAMETER;
1874 ntln_found = dsdb_trust_find_tln_match(ref_fti, ntln->string);
1876 /* check if this is already taken and not excluded */
1877 for (r = 0; r < ref_fti->count; r++) {
1878 const struct lsa_ForestTrustRecord *rftr =
1879 ref_fti->entries[r];
1880 const struct lsa_ForestTrustDomainInfo *rinfo = NULL;
1881 const struct lsa_StringLarge *rtln = NULL;
1882 const struct lsa_StringLarge *rnb = NULL;
1883 const struct dom_sid *rsid = NULL;
1884 bool nb_possible = true;
1885 bool sid_possible = true;
1886 int cmp;
1888 if (rftr == NULL) {
1889 continue;
1892 if (!ntln_found) {
1894 * If the dns name doesn't match any existing
1895 * tln any conflict is ignored, but name
1896 * normalization still happens.
1898 * I guess that's a bug in Windows
1899 * (tested with Windows 2012r2).
1901 nb_possible = false;
1902 sid_possible = false;
1905 if (nftr->flags & LSA_SID_DISABLED_MASK) {
1906 sid_possible = false;
1909 if (nftr->flags & LSA_NB_DISABLED_MASK) {
1910 nb_possible = false;
1913 switch (rftr->type) {
1914 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
1915 rtln = &rftr->forest_trust_data.top_level_name;
1916 nb_possible = false;
1917 sid_possible = false;
1918 break;
1920 case LSA_FOREST_TRUST_DOMAIN_INFO:
1921 rinfo = &rftr->forest_trust_data.domain_info;
1922 rtln = &rinfo->dns_domain_name;
1923 rnb = &rinfo->netbios_domain_name;
1924 rsid = rinfo->domain_sid;
1926 if (rftr->flags & LSA_SID_DISABLED_MASK) {
1927 sid_possible = false;
1930 if (rftr->flags & LSA_NB_DISABLED_MASK) {
1931 nb_possible = false;
1933 break;
1935 default:
1936 break;
1939 if (rtln == NULL) {
1940 continue;
1943 if (rtln->string == NULL) {
1944 continue;
1947 cmp = dns_cmp(ntln->string, rtln->string);
1948 if (DNS_CMP_IS_NO_MATCH(cmp)) {
1949 nb_possible = false;
1950 sid_possible = false;
1952 if (cmp == DNS_CMP_MATCH) {
1953 /* We need to normalize the string */
1954 ntln->string = talloc_strdup(nftr,
1955 rtln->string);
1956 if (ntln->string == NULL) {
1957 return NT_STATUS_NO_MEMORY;
1961 if (rinfo == NULL) {
1962 continue;
1965 if (rsid != NULL) {
1966 cmp = dom_sid_compare(nsid, rsid);
1967 } else {
1968 cmp = -1;
1970 if (cmp == 0) {
1971 if (sid_possible) {
1972 flags |= LSA_SID_DISABLED_CONFLICT;
1976 if (rnb->string != NULL) {
1977 cmp = strcasecmp_m(nnb->string, rnb->string);
1978 } else {
1979 cmp = -1;
1981 if (cmp == 0) {
1982 nnb->string = talloc_strdup(nftr, rnb->string);
1983 if (nnb->string == NULL) {
1984 return NT_STATUS_NO_MEMORY;
1986 if (nb_possible) {
1987 flags |= LSA_NB_DISABLED_CONFLICT;
1992 if (flags == 0) {
1993 continue;
1996 nftr->flags |= flags;
1998 status = dsdb_trust_add_collision(c_info,
1999 collision_type,
2000 n, nftr->flags,
2001 ref_tdo->domain_name.string);
2002 if (!NT_STATUS_IS_OK(status)) {
2003 return status;
2007 return NT_STATUS_OK;
2010 NTSTATUS dsdb_trust_merge_forest_info(TALLOC_CTX *mem_ctx,
2011 const struct lsa_TrustDomainInfoInfoEx *tdo,
2012 const struct lsa_ForestTrustInformation *ofti,
2013 const struct lsa_ForestTrustInformation *nfti,
2014 struct lsa_ForestTrustInformation **_mfti)
2016 TALLOC_CTX *frame = talloc_stackframe();
2017 struct lsa_ForestTrustInformation *mfti = NULL;
2018 uint32_t ni;
2019 uint32_t oi;
2020 NTSTATUS status;
2021 int cmp;
2023 *_mfti = NULL;
2024 mfti = talloc_zero(mem_ctx, struct lsa_ForestTrustInformation);
2025 if (mfti == NULL) {
2026 TALLOC_FREE(frame);
2027 return NT_STATUS_NO_MEMORY;
2029 talloc_steal(frame, mfti);
2032 * First we add all top unique level names.
2034 * The one matching the tdo dns name, will be
2035 * added without further checking. All others
2036 * may keep the flags and time values.
2038 for (ni = 0; ni < nfti->count; ni++) {
2039 const struct lsa_ForestTrustRecord *nftr = nfti->entries[ni];
2040 struct lsa_ForestTrustRecord tftr = {};
2041 const char *ndns = NULL;
2042 bool ignore_new = false;
2043 bool found_old = false;
2044 uint32_t mi;
2046 if (nftr == NULL) {
2047 TALLOC_FREE(frame);
2048 return NT_STATUS_INVALID_PARAMETER;
2051 if (nftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
2052 continue;
2055 ndns = nftr->forest_trust_data.top_level_name.string;
2056 if (ndns == NULL) {
2057 TALLOC_FREE(frame);
2058 return NT_STATUS_INVALID_PARAMETER;
2061 cmp = dns_cmp(tdo->domain_name.string, ndns);
2062 if (cmp == DNS_CMP_MATCH) {
2063 status = dsdb_trust_forest_info_add_record(mfti, nftr);
2064 if (!NT_STATUS_IS_OK(status)) {
2065 TALLOC_FREE(frame);
2066 return status;
2070 for (mi = 0; mi < mfti->count; mi++) {
2071 const struct lsa_ForestTrustRecord *mftr =
2072 mfti->entries[mi];
2073 const char *mdns = NULL;
2076 * we just added this above, so we're sure to have a
2077 * valid LSA_FOREST_TRUST_TOP_LEVEL_NAME record
2079 mdns = mftr->forest_trust_data.top_level_name.string;
2081 cmp = dns_cmp(mdns, ndns);
2082 switch (cmp) {
2083 case DNS_CMP_MATCH:
2084 case DNS_CMP_SECOND_IS_CHILD:
2085 ignore_new = true;
2086 break;
2089 if (ignore_new) {
2090 break;
2094 if (ignore_new) {
2095 continue;
2099 * make a temporary copy where we can change time and flags
2101 tftr = *nftr;
2103 for (oi = 0; oi < ofti->count; oi++) {
2104 const struct lsa_ForestTrustRecord *oftr =
2105 ofti->entries[oi];
2106 const char *odns = NULL;
2108 if (oftr == NULL) {
2110 * broken record => ignore...
2112 continue;
2115 if (oftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
2116 continue;
2119 odns = oftr->forest_trust_data.top_level_name.string;
2120 if (odns == NULL) {
2122 * broken record => ignore...
2124 continue;
2127 cmp = dns_cmp(odns, ndns);
2128 if (cmp != DNS_CMP_MATCH) {
2129 continue;
2132 found_old = true;
2133 tftr.flags = oftr->flags;
2134 tftr.time = oftr->time;
2137 if (!found_old) {
2138 tftr.flags = LSA_TLN_DISABLED_NEW;
2139 tftr.time = 0;
2142 status = dsdb_trust_forest_info_add_record(mfti, &tftr);
2143 if (!NT_STATUS_IS_OK(status)) {
2144 TALLOC_FREE(frame);
2145 return status;
2150 * Now we add all unique (based on their SID) domains
2151 * and may keep the flags and time values.
2153 for (ni = 0; ni < nfti->count; ni++) {
2154 const struct lsa_ForestTrustRecord *nftr = nfti->entries[ni];
2155 struct lsa_ForestTrustRecord tftr = {};
2156 const struct lsa_ForestTrustDomainInfo *nd = NULL;
2157 const char *ndns = NULL;
2158 const char *nnbt = NULL;
2159 bool ignore_new = false;
2160 bool found_old = false;
2161 uint32_t mi;
2163 if (nftr == NULL) {
2164 TALLOC_FREE(frame);
2165 return NT_STATUS_INVALID_PARAMETER;
2168 if (nftr->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
2169 continue;
2172 nd = &nftr->forest_trust_data.domain_info;
2173 if (nd->domain_sid == NULL) {
2174 TALLOC_FREE(frame);
2175 return NT_STATUS_INVALID_PARAMETER;
2177 ndns = nd->dns_domain_name.string;
2178 if (ndns == NULL) {
2179 TALLOC_FREE(frame);
2180 return NT_STATUS_INVALID_PARAMETER;
2182 nnbt = nd->netbios_domain_name.string;
2183 if (nnbt == NULL) {
2184 TALLOC_FREE(frame);
2185 return NT_STATUS_INVALID_PARAMETER;
2188 for (mi = 0; mi < mfti->count; mi++) {
2189 const struct lsa_ForestTrustRecord *mftr =
2190 mfti->entries[mi];
2191 const struct lsa_ForestTrustDomainInfo *md = NULL;
2193 if (mftr->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
2194 continue;
2198 * we just added this above, so we're sure to have a
2199 * valid LSA_FOREST_TRUST_DOMAIN_INFO record
2201 md = &mftr->forest_trust_data.domain_info;
2203 cmp = dom_sid_compare(nd->domain_sid, md->domain_sid);
2204 if (cmp == 0) {
2205 ignore_new = true;
2206 break;
2210 if (ignore_new) {
2211 continue;
2215 * make a temporary copy where we can change time and flags
2217 tftr = *nftr;
2219 for (oi = 0; oi < ofti->count; oi++) {
2220 const struct lsa_ForestTrustRecord *oftr =
2221 ofti->entries[oi];
2222 const struct lsa_ForestTrustDomainInfo *od = NULL;
2223 const char *onbt = NULL;
2225 if (oftr == NULL) {
2227 * broken record => ignore...
2229 continue;
2232 if (oftr->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
2233 continue;
2236 od = &oftr->forest_trust_data.domain_info;
2237 onbt = od->netbios_domain_name.string;
2238 if (onbt == NULL) {
2240 * broken record => ignore...
2242 continue;
2245 cmp = strcasecmp(onbt, nnbt);
2246 if (cmp != 0) {
2247 continue;
2250 found_old = true;
2251 tftr.flags = oftr->flags;
2252 tftr.time = oftr->time;
2255 if (!found_old) {
2256 tftr.flags = 0;
2257 tftr.time = 0;
2260 status = dsdb_trust_forest_info_add_record(mfti, &tftr);
2261 if (!NT_STATUS_IS_OK(status)) {
2262 TALLOC_FREE(frame);
2263 return status;
2268 * We keep old domain records disabled by the admin
2269 * if not already in the list.
2271 for (oi = 0; oi < ofti->count; oi++) {
2272 const struct lsa_ForestTrustRecord *oftr =
2273 ofti->entries[oi];
2274 const struct lsa_ForestTrustDomainInfo *od = NULL;
2275 const char *odns = NULL;
2276 const char *onbt = NULL;
2277 bool ignore_old = true;
2278 uint32_t mi;
2280 if (oftr == NULL) {
2282 * broken record => ignore...
2284 continue;
2287 if (oftr->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
2288 continue;
2291 od = &oftr->forest_trust_data.domain_info;
2292 odns = od->dns_domain_name.string;
2293 if (odns == NULL) {
2295 * broken record => ignore...
2297 continue;
2299 onbt = od->netbios_domain_name.string;
2300 if (onbt == NULL) {
2302 * broken record => ignore...
2304 continue;
2306 if (od->domain_sid == NULL) {
2308 * broken record => ignore...
2310 continue;
2313 if (oftr->flags & LSA_NB_DISABLED_ADMIN) {
2314 ignore_old = false;
2315 } else if (oftr->flags & LSA_SID_DISABLED_ADMIN) {
2316 ignore_old = false;
2319 for (mi = 0; mi < mfti->count; mi++) {
2320 const struct lsa_ForestTrustRecord *mftr =
2321 mfti->entries[mi];
2322 const struct lsa_ForestTrustDomainInfo *md = NULL;
2324 if (mftr->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
2325 continue;
2329 * we just added this above, so we're sure to have a
2330 * valid LSA_FOREST_TRUST_DOMAIN_INFO record
2332 md = &mftr->forest_trust_data.domain_info;
2334 cmp = dom_sid_compare(od->domain_sid, md->domain_sid);
2335 if (cmp == 0) {
2336 ignore_old = true;
2337 break;
2341 if (ignore_old) {
2342 continue;
2345 status = dsdb_trust_forest_info_add_record(mfti, oftr);
2346 if (!NT_STATUS_IS_OK(status)) {
2347 TALLOC_FREE(frame);
2348 return status;
2353 * Finally we readd top level exclusions,
2354 * if they still match a top level name.
2356 for (oi = 0; oi < ofti->count; oi++) {
2357 const struct lsa_ForestTrustRecord *oftr =
2358 ofti->entries[oi];
2359 const char *odns = NULL;
2360 bool ignore_old = false;
2361 uint32_t mi;
2363 if (oftr == NULL) {
2365 * broken record => ignore...
2367 continue;
2370 if (oftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX) {
2371 continue;
2374 odns = oftr->forest_trust_data.top_level_name_ex.string;
2375 if (odns == NULL) {
2377 * broken record => ignore...
2379 continue;
2382 for (mi = 0; mi < mfti->count; mi++) {
2383 const struct lsa_ForestTrustRecord *mftr =
2384 mfti->entries[mi];
2385 const char *mdns = NULL;
2387 if (mftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
2388 continue;
2392 * we just added this above, so we're sure to have a
2393 * valid LSA_FOREST_TRUST_TOP_LEVEL_NAME.
2395 mdns = mftr->forest_trust_data.top_level_name.string;
2397 cmp = dns_cmp(mdns, odns);
2398 switch (cmp) {
2399 case DNS_CMP_MATCH:
2400 case DNS_CMP_SECOND_IS_CHILD:
2401 break;
2402 default:
2403 ignore_old = true;
2404 break;
2407 if (ignore_old) {
2408 break;
2412 if (ignore_old) {
2413 continue;
2416 status = dsdb_trust_forest_info_add_record(mfti, oftr);
2417 if (!NT_STATUS_IS_OK(status)) {
2418 TALLOC_FREE(frame);
2419 return status;
2423 *_mfti = talloc_move(mem_ctx, &mfti);
2424 TALLOC_FREE(frame);
2425 return NT_STATUS_OK;
2428 NTSTATUS dsdb_trust_search_tdo(struct ldb_context *sam_ctx,
2429 const char *netbios, const char *dns,
2430 const char * const *attrs,
2431 TALLOC_CTX *mem_ctx,
2432 struct ldb_message **msg)
2434 TALLOC_CTX *frame = talloc_stackframe();
2435 int ret;
2436 struct ldb_dn *system_dn = NULL;
2437 char *netbios_encoded = NULL;
2438 char *dns_encoded = NULL;
2439 char *filter = NULL;
2441 *msg = NULL;
2443 if (netbios == NULL && dns == NULL) {
2444 TALLOC_FREE(frame);
2445 return NT_STATUS_INVALID_PARAMETER_MIX;
2448 system_dn = ldb_dn_copy(frame, ldb_get_default_basedn(sam_ctx));
2449 if (system_dn == NULL) {
2450 TALLOC_FREE(frame);
2451 return NT_STATUS_NO_MEMORY;
2454 if (!ldb_dn_add_child_fmt(system_dn, "CN=System")) {
2455 TALLOC_FREE(frame);
2456 return NT_STATUS_NO_MEMORY;
2459 if (netbios != NULL) {
2460 netbios_encoded = ldb_binary_encode_string(frame, netbios);
2461 if (netbios_encoded == NULL) {
2462 TALLOC_FREE(frame);
2463 return NT_STATUS_NO_MEMORY;
2467 if (dns != NULL) {
2468 dns_encoded = ldb_binary_encode_string(frame, dns);
2469 if (dns_encoded == NULL) {
2470 TALLOC_FREE(frame);
2471 return NT_STATUS_NO_MEMORY;
2475 if (netbios != NULL && dns != NULL) {
2476 filter = talloc_asprintf(frame,
2477 "(&(objectClass=trustedDomain)"
2478 "(|(trustPartner=%s)(flatName=%s))"
2479 ")",
2480 dns_encoded, netbios_encoded);
2481 if (filter == NULL) {
2482 TALLOC_FREE(frame);
2483 return NT_STATUS_NO_MEMORY;
2485 } else if (netbios != NULL) {
2486 filter = talloc_asprintf(frame,
2487 "(&(objectClass=trustedDomain)(flatName=%s))",
2488 netbios_encoded);
2489 if (filter == NULL) {
2490 TALLOC_FREE(frame);
2491 return NT_STATUS_NO_MEMORY;
2493 } else if (dns != NULL) {
2494 filter = talloc_asprintf(frame,
2495 "(&(objectClass=trustedDomain)(trustPartner=%s))",
2496 dns_encoded);
2497 if (filter == NULL) {
2498 TALLOC_FREE(frame);
2499 return NT_STATUS_NO_MEMORY;
2503 ret = dsdb_search_one(sam_ctx, mem_ctx, msg,
2504 system_dn,
2505 LDB_SCOPE_ONELEVEL, attrs,
2506 DSDB_SEARCH_NO_GLOBAL_CATALOG,
2507 "%s", filter);
2508 if (ret != LDB_SUCCESS) {
2509 NTSTATUS status = dsdb_ldb_err_to_ntstatus(ret);
2510 DEBUG(3, ("Failed to search for %s: %s - %s\n",
2511 filter, nt_errstr(status), ldb_errstring(sam_ctx)));
2512 TALLOC_FREE(frame);
2513 return status;
2516 TALLOC_FREE(frame);
2517 return NT_STATUS_OK;
2520 NTSTATUS dsdb_trust_search_tdo_by_type(struct ldb_context *sam_ctx,
2521 enum netr_SchannelType type,
2522 const char *name,
2523 const char * const *attrs,
2524 TALLOC_CTX *mem_ctx,
2525 struct ldb_message **msg)
2527 TALLOC_CTX *frame = talloc_stackframe();
2528 NTSTATUS status;
2529 size_t len;
2530 char trailer = '$';
2531 bool require_trailer = true;
2532 char *encoded_name = NULL;
2533 const char *netbios = NULL;
2534 const char *dns = NULL;
2536 if (type != SEC_CHAN_DOMAIN && type != SEC_CHAN_DNS_DOMAIN) {
2537 TALLOC_FREE(frame);
2538 return NT_STATUS_INVALID_PARAMETER;
2541 if (type == SEC_CHAN_DNS_DOMAIN) {
2542 trailer = '.';
2543 require_trailer = false;
2546 encoded_name = ldb_binary_encode_string(frame, name);
2547 if (encoded_name == NULL) {
2548 TALLOC_FREE(frame);
2549 return NT_STATUS_NO_MEMORY;
2552 len = strlen(encoded_name);
2553 if (len < 2) {
2554 TALLOC_FREE(frame);
2555 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2558 if (require_trailer && encoded_name[len - 1] != trailer) {
2559 TALLOC_FREE(frame);
2560 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2562 encoded_name[len - 1] = '\0';
2564 if (type == SEC_CHAN_DNS_DOMAIN) {
2565 dns = encoded_name;
2566 } else {
2567 netbios = encoded_name;
2570 status = dsdb_trust_search_tdo(sam_ctx, netbios, dns,
2571 attrs, mem_ctx, msg);
2572 if (!NT_STATUS_IS_OK(status)) {
2573 TALLOC_FREE(frame);
2574 return status;
2577 TALLOC_FREE(frame);
2578 return NT_STATUS_OK;
2581 NTSTATUS dsdb_trust_search_tdo_by_sid(struct ldb_context *sam_ctx,
2582 const struct dom_sid *sid,
2583 const char * const *attrs,
2584 TALLOC_CTX *mem_ctx,
2585 struct ldb_message **msg)
2587 TALLOC_CTX *frame = talloc_stackframe();
2588 int ret;
2589 struct ldb_dn *system_dn = NULL;
2590 char *encoded_sid = NULL;
2591 char *filter = NULL;
2593 *msg = NULL;
2595 if (sid == NULL) {
2596 TALLOC_FREE(frame);
2597 return NT_STATUS_INVALID_PARAMETER_MIX;
2600 encoded_sid = ldap_encode_ndr_dom_sid(frame, sid);
2601 if (encoded_sid == NULL) {
2602 TALLOC_FREE(frame);
2603 return NT_STATUS_NO_MEMORY;
2606 system_dn = ldb_dn_copy(frame, ldb_get_default_basedn(sam_ctx));
2607 if (system_dn == NULL) {
2608 TALLOC_FREE(frame);
2609 return NT_STATUS_NO_MEMORY;
2612 if (!ldb_dn_add_child_fmt(system_dn, "CN=System")) {
2613 TALLOC_FREE(frame);
2614 return NT_STATUS_NO_MEMORY;
2617 filter = talloc_asprintf(frame,
2618 "(&"
2619 "(objectClass=trustedDomain)"
2620 "(securityIdentifier=%s)"
2621 ")",
2622 encoded_sid);
2623 if (filter == NULL) {
2624 TALLOC_FREE(frame);
2625 return NT_STATUS_NO_MEMORY;
2628 ret = dsdb_search_one(sam_ctx, mem_ctx, msg,
2629 system_dn,
2630 LDB_SCOPE_ONELEVEL, attrs,
2631 DSDB_SEARCH_NO_GLOBAL_CATALOG,
2632 "%s", filter);
2633 if (ret != LDB_SUCCESS) {
2634 NTSTATUS status = dsdb_ldb_err_to_ntstatus(ret);
2635 DEBUG(3, ("Failed to search for %s: %s - %s\n",
2636 filter, nt_errstr(status), ldb_errstring(sam_ctx)));
2637 TALLOC_FREE(frame);
2638 return status;
2641 TALLOC_FREE(frame);
2642 return NT_STATUS_OK;
2645 NTSTATUS dsdb_trust_get_incoming_passwords(struct ldb_message *msg,
2646 TALLOC_CTX *mem_ctx,
2647 struct samr_Password **_current,
2648 struct samr_Password **_previous)
2650 TALLOC_CTX *frame = talloc_stackframe();
2651 struct samr_Password __current = {};
2652 struct samr_Password __previous = {};
2653 struct samr_Password *current = NULL;
2654 struct samr_Password *previous = NULL;
2655 const struct ldb_val *blob = NULL;
2656 enum ndr_err_code ndr_err;
2657 struct trustAuthInOutBlob incoming = {};
2658 uint32_t i;
2660 if (_current != NULL) {
2661 *_current = NULL;
2663 if (_previous != NULL) {
2664 *_previous = NULL;
2667 blob = ldb_msg_find_ldb_val(msg, "trustAuthIncoming");
2668 if (blob == NULL) {
2669 TALLOC_FREE(frame);
2670 return NT_STATUS_ACCOUNT_DISABLED;
2673 /* ldb_val is equivalent to DATA_BLOB */
2674 ndr_err = ndr_pull_struct_blob_all(blob, frame, &incoming,
2675 (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
2676 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2677 TALLOC_FREE(frame);
2678 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2681 for (i = 0; i < incoming.current.count; i++) {
2682 struct AuthenticationInformation *a =
2683 &incoming.current.array[i];
2685 if (current != NULL) {
2686 break;
2689 switch (a->AuthType) {
2690 case TRUST_AUTH_TYPE_NONE:
2691 case TRUST_AUTH_TYPE_VERSION:
2692 break;
2693 case TRUST_AUTH_TYPE_NT4OWF:
2694 current = &a->AuthInfo.nt4owf.password;
2695 break;
2696 case TRUST_AUTH_TYPE_CLEAR:
2697 mdfour(__current.hash,
2698 a->AuthInfo.clear.password,
2699 a->AuthInfo.clear.size);
2700 current = &__current;
2701 break;
2705 if (current == NULL) {
2706 TALLOC_FREE(frame);
2707 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2710 for (i = 0; i < incoming.previous.count; i++) {
2711 struct AuthenticationInformation *a =
2712 &incoming.previous.array[i];
2714 if (previous != NULL) {
2715 break;
2718 switch (a->AuthType) {
2719 case TRUST_AUTH_TYPE_NONE:
2720 case TRUST_AUTH_TYPE_VERSION:
2721 break;
2722 case TRUST_AUTH_TYPE_NT4OWF:
2723 previous = &a->AuthInfo.nt4owf.password;
2724 break;
2725 case TRUST_AUTH_TYPE_CLEAR:
2726 mdfour(__previous.hash,
2727 a->AuthInfo.clear.password,
2728 a->AuthInfo.clear.size);
2729 previous = &__previous;
2730 break;
2734 if (previous == NULL) {
2735 previous = current;
2738 if (_current != NULL) {
2739 *_current = talloc(mem_ctx, struct samr_Password);
2740 if (*_current == NULL) {
2741 TALLOC_FREE(frame);
2742 return NT_STATUS_NO_MEMORY;
2744 **_current = *current;
2746 if (_previous != NULL) {
2747 *_previous = talloc(mem_ctx, struct samr_Password);
2748 if (*_previous == NULL) {
2749 if (_current != NULL) {
2750 TALLOC_FREE(*_current);
2752 TALLOC_FREE(frame);
2753 return NT_STATUS_NO_MEMORY;
2755 **_previous = *previous;
2757 ZERO_STRUCTP(current);
2758 ZERO_STRUCTP(previous);
2759 TALLOC_FREE(frame);
2760 return NT_STATUS_OK;
2763 NTSTATUS dsdb_trust_search_tdos(struct ldb_context *sam_ctx,
2764 const char *exclude,
2765 const char * const *attrs,
2766 TALLOC_CTX *mem_ctx,
2767 struct ldb_result **res)
2769 TALLOC_CTX *frame = talloc_stackframe();
2770 int ret;
2771 struct ldb_dn *system_dn = NULL;
2772 const char *filter = NULL;
2773 char *exclude_encoded = NULL;
2775 *res = NULL;
2777 system_dn = ldb_dn_copy(frame, ldb_get_default_basedn(sam_ctx));
2778 if (system_dn == NULL) {
2779 TALLOC_FREE(frame);
2780 return NT_STATUS_NO_MEMORY;
2783 if (!ldb_dn_add_child_fmt(system_dn, "CN=System")) {
2784 TALLOC_FREE(frame);
2785 return NT_STATUS_NO_MEMORY;
2788 if (exclude != NULL) {
2789 exclude_encoded = ldb_binary_encode_string(frame, exclude);
2790 if (exclude_encoded == NULL) {
2791 TALLOC_FREE(frame);
2792 return NT_STATUS_NO_MEMORY;
2795 filter = talloc_asprintf(frame,
2796 "(&(objectClass=trustedDomain)"
2797 "(!(|(trustPartner=%s)(flatName=%s)))"
2798 ")",
2799 exclude_encoded, exclude_encoded);
2800 if (filter == NULL) {
2801 TALLOC_FREE(frame);
2802 return NT_STATUS_NO_MEMORY;
2804 } else {
2805 filter = "(objectClass=trustedDomain)";
2808 ret = dsdb_search(sam_ctx, mem_ctx, res,
2809 system_dn,
2810 LDB_SCOPE_ONELEVEL, attrs,
2811 DSDB_SEARCH_NO_GLOBAL_CATALOG,
2812 "%s", filter);
2813 if (ret != LDB_SUCCESS) {
2814 NTSTATUS status = dsdb_ldb_err_to_ntstatus(ret);
2815 DEBUG(3, ("Failed to search for %s: %s - %s\n",
2816 filter, nt_errstr(status), ldb_errstring(sam_ctx)));
2817 TALLOC_FREE(frame);
2818 return status;
2821 TALLOC_FREE(frame);
2822 return NT_STATUS_OK;
2825 struct dsdb_trust_routing_domain;
2827 struct dsdb_trust_routing_table {
2828 struct dsdb_trust_routing_domain *domains;
2831 struct dsdb_trust_routing_domain {
2832 struct dsdb_trust_routing_domain *prev, *next;
2834 struct lsa_TrustDomainInfoInfoEx *tdo;
2836 struct lsa_ForestTrustDomainInfo di;
2838 struct lsa_ForestTrustInformation *fti;
2841 NTSTATUS dsdb_trust_routing_table_load(struct ldb_context *sam_ctx,
2842 TALLOC_CTX *mem_ctx,
2843 struct dsdb_trust_routing_table **_table)
2845 TALLOC_CTX *frame = talloc_stackframe();
2846 struct dsdb_trust_routing_table *table;
2847 struct dsdb_trust_routing_domain *d = NULL;
2848 struct ldb_dn *domain_dn = NULL;
2849 struct lsa_TrustDomainInfoInfoEx *root_trust_tdo = NULL;
2850 struct lsa_TrustDomainInfoInfoEx *trust_parent_tdo = NULL;
2851 struct lsa_TrustDomainInfoInfoEx *root_direction_tdo = NULL;
2852 const char * const trusts_attrs[] = {
2853 "securityIdentifier",
2854 "flatName",
2855 "trustPartner",
2856 "trustAttributes",
2857 "trustDirection",
2858 "trustType",
2859 "msDS-TrustForestTrustInfo",
2860 NULL
2862 struct ldb_result *trusts_res = NULL;
2863 unsigned int i;
2864 NTSTATUS status;
2866 *_table = NULL;
2868 domain_dn = ldb_get_default_basedn(sam_ctx);
2869 if (domain_dn == NULL) {
2870 TALLOC_FREE(frame);
2871 return NT_STATUS_INTERNAL_ERROR;
2874 table = talloc_zero(mem_ctx, struct dsdb_trust_routing_table);
2875 if (table == NULL) {
2876 TALLOC_FREE(frame);
2877 return NT_STATUS_NO_MEMORY;
2879 talloc_steal(frame, table);
2881 d = talloc_zero(table, struct dsdb_trust_routing_domain);
2882 if (d == NULL) {
2883 TALLOC_FREE(frame);
2884 return NT_STATUS_NO_MEMORY;
2887 status = dsdb_trust_crossref_tdo_info(d, sam_ctx,
2888 domain_dn, NULL,
2889 &d->tdo,
2890 &root_trust_tdo,
2891 &trust_parent_tdo);
2892 if (!NT_STATUS_IS_OK(status)) {
2893 TALLOC_FREE(frame);
2894 return status;
2897 d->di.domain_sid = d->tdo->sid;
2898 d->di.netbios_domain_name.string = d->tdo->netbios_name.string;
2899 d->di.dns_domain_name.string = d->tdo->domain_name.string;
2901 if (root_trust_tdo != NULL) {
2902 root_direction_tdo = root_trust_tdo;
2903 } else if (trust_parent_tdo != NULL) {
2904 root_direction_tdo = trust_parent_tdo;
2907 if (root_direction_tdo == NULL) {
2908 /* we're the forest root */
2909 status = dsdb_trust_xref_forest_info(d, sam_ctx, &d->fti);
2910 if (!NT_STATUS_IS_OK(status)) {
2911 TALLOC_FREE(frame);
2912 return status;
2916 DLIST_ADD(table->domains, d);
2918 status = dsdb_trust_search_tdos(sam_ctx, NULL, trusts_attrs,
2919 frame, &trusts_res);
2920 if (!NT_STATUS_IS_OK(status)) {
2921 TALLOC_FREE(frame);
2922 return status;
2925 for (i = 0; i < trusts_res->count; i++) {
2926 bool ok;
2927 int cmp;
2929 d = talloc_zero(table, struct dsdb_trust_routing_domain);
2930 if (d == NULL) {
2931 TALLOC_FREE(frame);
2932 return NT_STATUS_NO_MEMORY;
2935 status = dsdb_trust_parse_tdo_info(d,
2936 trusts_res->msgs[i],
2937 &d->tdo);
2938 if (!NT_STATUS_IS_OK(status)) {
2939 TALLOC_FREE(frame);
2940 return status;
2943 d->di.domain_sid = d->tdo->sid;
2944 d->di.netbios_domain_name.string = d->tdo->netbios_name.string;
2945 d->di.dns_domain_name.string = d->tdo->domain_name.string;
2947 DLIST_ADD_END(table->domains, d);
2949 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
2950 struct ForestTrustInfo *fti = NULL;
2952 status = dsdb_trust_parse_forest_info(frame,
2953 trusts_res->msgs[i],
2954 &fti);
2955 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2956 fti = NULL;
2957 status = NT_STATUS_OK;
2959 if (!NT_STATUS_IS_OK(status)) {
2960 TALLOC_FREE(frame);
2961 return status;
2964 if (fti == NULL) {
2965 continue;
2968 status = dsdb_trust_forest_info_to_lsa(d, fti, &d->fti);
2969 if (!NT_STATUS_IS_OK(status)) {
2970 TALLOC_FREE(frame);
2971 return status;
2974 continue;
2977 if (!(d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST)) {
2978 continue;
2981 if (root_direction_tdo == NULL) {
2982 continue;
2985 ok = dom_sid_equal(root_direction_tdo->sid, d->tdo->sid);
2986 if (!ok) {
2987 continue;
2990 cmp = strcasecmp_m(root_direction_tdo->netbios_name.string,
2991 d->tdo->netbios_name.string);
2992 if (cmp != 0) {
2993 continue;
2996 cmp = strcasecmp_m(root_direction_tdo->domain_name.string,
2997 d->tdo->domain_name.string);
2998 if (cmp != 0) {
2999 continue;
3002 /* this our route to the forest root */
3003 status = dsdb_trust_xref_forest_info(d, sam_ctx, &d->fti);
3004 if (!NT_STATUS_IS_OK(status)) {
3005 TALLOC_FREE(frame);
3006 return status;
3010 *_table = talloc_move(mem_ctx, &table);
3011 TALLOC_FREE(frame);
3012 return NT_STATUS_OK;
3015 static void dsdb_trust_update_best_tln(
3016 const struct dsdb_trust_routing_domain **best_d,
3017 const char **best_tln,
3018 const struct dsdb_trust_routing_domain *d,
3019 const char *tln)
3021 int cmp;
3023 if (*best_tln == NULL) {
3024 *best_tln = tln;
3025 *best_d = d;
3026 return;
3029 cmp = dns_cmp(*best_tln, tln);
3030 if (cmp != DNS_CMP_FIRST_IS_CHILD) {
3031 return;
3034 *best_tln = tln;
3035 *best_d = d;
3038 const struct lsa_TrustDomainInfoInfoEx *dsdb_trust_routing_by_name(
3039 const struct dsdb_trust_routing_table *table,
3040 const char *name)
3042 const struct dsdb_trust_routing_domain *best_d = NULL;
3043 const char *best_tln = NULL;
3044 const struct dsdb_trust_routing_domain *d = NULL;
3046 if (name == NULL) {
3047 return NULL;
3050 for (d = table->domains; d != NULL; d = d->next) {
3051 bool transitive = false;
3052 bool allow_netbios = false;
3053 bool exclude = false;
3054 uint32_t i;
3056 if (d->tdo->trust_type != LSA_TRUST_TYPE_UPLEVEL) {
3058 * Only uplevel trusts have top level names
3060 continue;
3063 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
3064 transitive = true;
3067 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
3068 transitive = true;
3071 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE) {
3072 transitive = false;
3075 if (d->tdo->trust_type != LSA_TRUST_TYPE_UPLEVEL) {
3076 transitive = false;
3079 switch (d->tdo->trust_type) {
3080 case LSA_TRUST_TYPE_UPLEVEL:
3081 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_UPLEVEL_ONLY) {
3082 break;
3084 allow_netbios = true;
3085 break;
3086 case LSA_TRUST_TYPE_DOWNLEVEL:
3087 allow_netbios = true;
3088 break;
3089 default:
3090 allow_netbios = false;
3091 break;
3094 if (!transitive || d->fti == NULL) {
3095 int cmp;
3097 if (allow_netbios) {
3098 cmp = dns_cmp(name, d->tdo->netbios_name.string);
3099 if (cmp == DNS_CMP_MATCH) {
3101 * exact match
3103 return d->tdo;
3107 cmp = dns_cmp(name, d->tdo->domain_name.string);
3108 if (cmp == DNS_CMP_MATCH) {
3110 * exact match
3112 return d->tdo;
3114 if (cmp != DNS_CMP_FIRST_IS_CHILD) {
3115 continue;
3118 if (!transitive) {
3119 continue;
3122 dsdb_trust_update_best_tln(&best_d, &best_tln, d,
3123 d->tdo->domain_name.string);
3124 continue;
3127 exclude = dsdb_trust_find_tln_ex_match(d->fti, name);
3128 if (exclude) {
3129 continue;
3132 for (i = 0; i < d->fti->count; i++ ) {
3133 const struct lsa_ForestTrustRecord *f = d->fti->entries[i];
3134 const struct lsa_ForestTrustDomainInfo *di = NULL;
3135 const char *fti_nbt = NULL;
3136 int cmp;
3138 if (!allow_netbios) {
3139 break;
3142 if (f == NULL) {
3143 /* broken record */
3144 continue;
3147 if (f->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
3148 continue;
3151 if (f->flags & LSA_NB_DISABLED_MASK) {
3153 * any flag disables the entry.
3155 continue;
3158 di = &f->forest_trust_data.domain_info;
3159 fti_nbt = di->netbios_domain_name.string;
3160 if (fti_nbt == NULL) {
3161 /* broken record */
3162 continue;
3165 cmp = dns_cmp(name, fti_nbt);
3166 if (cmp == DNS_CMP_MATCH) {
3168 * exact match
3170 return d->tdo;
3174 for (i = 0; i < d->fti->count; i++ ) {
3175 const struct lsa_ForestTrustRecord *f = d->fti->entries[i];
3176 const union lsa_ForestTrustData *u = NULL;
3177 const char *fti_tln = NULL;
3178 int cmp;
3180 if (f == NULL) {
3181 /* broken record */
3182 continue;
3185 if (f->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
3186 continue;
3189 if (f->flags & LSA_TLN_DISABLED_MASK) {
3191 * any flag disables the entry.
3193 continue;
3196 u = &f->forest_trust_data;
3197 fti_tln = u->top_level_name.string;
3198 if (fti_tln == NULL) {
3199 continue;
3202 cmp = dns_cmp(name, fti_tln);
3203 switch (cmp) {
3204 case DNS_CMP_MATCH:
3205 case DNS_CMP_FIRST_IS_CHILD:
3206 dsdb_trust_update_best_tln(&best_d, &best_tln,
3207 d, fti_tln);
3208 break;
3209 default:
3210 break;
3215 if (best_d != NULL) {
3216 return best_d->tdo;
3219 return NULL;
3222 const struct lsa_TrustDomainInfoInfoEx *dsdb_trust_domain_by_sid(
3223 const struct dsdb_trust_routing_table *table,
3224 const struct dom_sid *sid,
3225 const struct lsa_ForestTrustDomainInfo **pdi)
3227 const struct dsdb_trust_routing_domain *d = NULL;
3229 if (pdi != NULL) {
3230 *pdi = NULL;
3233 if (sid == NULL) {
3234 return NULL;
3237 for (d = table->domains; d != NULL; d = d->next) {
3238 bool transitive = false;
3239 uint32_t i;
3241 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
3242 transitive = true;
3245 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
3246 transitive = true;
3249 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE) {
3250 transitive = false;
3253 if (d->tdo->trust_type != LSA_TRUST_TYPE_UPLEVEL) {
3254 transitive = false;
3257 if (!transitive || d->fti == NULL) {
3258 bool match = false;
3260 match = dom_sid_equal(d->di.domain_sid, sid);
3261 if (match) {
3263 * exact match, it's the domain itself.
3265 if (pdi != NULL) {
3266 *pdi = &d->di;
3268 return d->tdo;
3270 continue;
3273 for (i = 0; i < d->fti->count; i++ ) {
3274 const struct lsa_ForestTrustRecord *f = d->fti->entries[i];
3275 const struct lsa_ForestTrustDomainInfo *di = NULL;
3276 const struct dom_sid *fti_sid = NULL;
3277 bool match = false;
3279 if (f == NULL) {
3280 /* broken record */
3281 continue;
3284 if (f->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
3285 continue;
3288 if (f->flags & LSA_SID_DISABLED_MASK) {
3290 * any flag disables the entry.
3292 continue;
3295 di = &f->forest_trust_data.domain_info;
3296 fti_sid = di->domain_sid;
3297 if (fti_sid == NULL) {
3298 /* broken record */
3299 continue;
3302 match = dom_sid_equal(fti_sid, sid);
3303 if (match) {
3305 * exact match, it's a domain in the forest.
3307 if (pdi != NULL) {
3308 *pdi = di;
3310 return d->tdo;
3315 return NULL;
3318 const struct lsa_TrustDomainInfoInfoEx *dsdb_trust_domain_by_name(
3319 const struct dsdb_trust_routing_table *table,
3320 const char *name,
3321 const struct lsa_ForestTrustDomainInfo **pdi)
3323 const struct dsdb_trust_routing_domain *d = NULL;
3325 if (pdi != NULL) {
3326 *pdi = NULL;
3329 if (name == NULL) {
3330 return NULL;
3333 for (d = table->domains; d != NULL; d = d->next) {
3334 bool transitive = false;
3335 uint32_t i;
3337 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
3338 transitive = true;
3341 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
3342 transitive = true;
3345 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE) {
3346 transitive = false;
3349 if (d->tdo->trust_type != LSA_TRUST_TYPE_UPLEVEL) {
3350 transitive = false;
3353 if (!transitive || d->fti == NULL) {
3354 bool match = false;
3356 match = strequal_m(d->di.netbios_domain_name.string,
3357 name);
3358 if (match) {
3360 * exact match for netbios name,
3361 * it's the domain itself.
3363 if (pdi != NULL) {
3364 *pdi = &d->di;
3366 return d->tdo;
3368 match = strequal_m(d->di.dns_domain_name.string,
3369 name);
3370 if (match) {
3372 * exact match for dns name,
3373 * it's the domain itself.
3375 if (pdi != NULL) {
3376 *pdi = &d->di;
3378 return d->tdo;
3380 continue;
3383 for (i = 0; i < d->fti->count; i++ ) {
3384 const struct lsa_ForestTrustRecord *f = d->fti->entries[i];
3385 const struct lsa_ForestTrustDomainInfo *di = NULL;
3386 bool match = false;
3388 if (f == NULL) {
3389 /* broken record */
3390 continue;
3393 if (f->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
3394 continue;
3396 di = &f->forest_trust_data.domain_info;
3398 if (!(f->flags & LSA_NB_DISABLED_MASK)) {
3399 match = strequal_m(di->netbios_domain_name.string,
3400 name);
3401 if (match) {
3403 * exact match for netbios name,
3404 * it's a domain in the forest.
3406 if (pdi != NULL) {
3407 *pdi = di;
3409 return d->tdo;
3413 if (!(f->flags & LSA_TLN_DISABLED_MASK)) {
3414 match = strequal_m(di->dns_domain_name.string,
3415 name);
3416 if (match) {
3418 * exact match for dns name,
3419 * it's a domain in the forest.
3421 if (pdi != NULL) {
3422 *pdi = di;
3424 return d->tdo;
3430 return NULL;