s4:dsdb/common: add dsdb_trust_merge_forest_info() helper function
[Samba.git] / source4 / dsdb / common / util_trusts.c
blob0e41803f7c553de7a929305bb4b5affa13af4225
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"
37 NTSTATUS dsdb_trust_forest_info_from_lsa(TALLOC_CTX *mem_ctx,
38 const struct lsa_ForestTrustInformation *lfti,
39 struct ForestTrustInfo **_fti)
41 struct ForestTrustInfo *fti;
42 uint32_t i;
44 *_fti = NULL;
46 fti = talloc_zero(mem_ctx, struct ForestTrustInfo);
47 if (fti == NULL) {
48 return NT_STATUS_NO_MEMORY;
51 fti->version = 1;
52 fti->count = lfti->count;
53 fti->records = talloc_zero_array(mem_ctx,
54 struct ForestTrustInfoRecordArmor,
55 fti->count);
56 if (fti->records == NULL) {
57 TALLOC_FREE(fti);
58 return NT_STATUS_NO_MEMORY;
61 for (i = 0; i < fti->count; i++) {
62 const struct lsa_ForestTrustRecord *lftr = lfti->entries[i];
63 struct ForestTrustInfoRecord *ftr = &fti->records[i].record;
64 struct ForestTrustString *str = NULL;
65 const struct lsa_StringLarge *lstr = NULL;
66 const struct lsa_ForestTrustDomainInfo *linfo = NULL;
67 struct ForestTrustDataDomainInfo *info = NULL;
69 if (lftr == NULL) {
70 TALLOC_FREE(fti);
71 return NT_STATUS_INVALID_PARAMETER;
74 ftr->flags = lftr->flags;
75 ftr->timestamp = lftr->time;
76 ftr->type = lftr->type;
78 switch (lftr->type) {
79 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
80 lstr = &lftr->forest_trust_data.top_level_name;
81 str = &ftr->data.name;
83 str->string = talloc_strdup(mem_ctx, lstr->string);
84 if (str->string == NULL) {
85 TALLOC_FREE(fti);
86 return NT_STATUS_NO_MEMORY;
89 break;
91 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
92 lstr = &lftr->forest_trust_data.top_level_name_ex;
93 str = &ftr->data.name;
95 str->string = talloc_strdup(mem_ctx, lstr->string);
96 if (str->string == NULL) {
97 TALLOC_FREE(fti);
98 return NT_STATUS_NO_MEMORY;
101 break;
103 case LSA_FOREST_TRUST_DOMAIN_INFO:
104 linfo = &lftr->forest_trust_data.domain_info;
105 info = &ftr->data.info;
107 if (linfo->domain_sid == NULL) {
108 TALLOC_FREE(fti);
109 return NT_STATUS_INVALID_PARAMETER;
111 info->sid = *linfo->domain_sid;
113 lstr = &linfo->dns_domain_name;
114 str = &info->dns_name;
115 str->string = talloc_strdup(mem_ctx, lstr->string);
116 if (str->string == NULL) {
117 TALLOC_FREE(fti);
118 return NT_STATUS_NO_MEMORY;
121 lstr = &linfo->netbios_domain_name;
122 str = &info->netbios_name;
123 str->string = talloc_strdup(mem_ctx, lstr->string);
124 if (str->string == NULL) {
125 TALLOC_FREE(fti);
126 return NT_STATUS_NO_MEMORY;
129 break;
131 default:
132 return NT_STATUS_NOT_SUPPORTED;
136 *_fti = fti;
137 return NT_STATUS_OK;
140 static NTSTATUS dsdb_trust_forest_record_to_lsa(TALLOC_CTX *mem_ctx,
141 const struct ForestTrustInfoRecord *ftr,
142 struct lsa_ForestTrustRecord **_lftr)
144 struct lsa_ForestTrustRecord *lftr = NULL;
145 const struct ForestTrustString *str = NULL;
146 struct lsa_StringLarge *lstr = NULL;
147 const struct ForestTrustDataDomainInfo *info = NULL;
148 struct lsa_ForestTrustDomainInfo *linfo = NULL;
150 *_lftr = NULL;
152 lftr = talloc_zero(mem_ctx, struct lsa_ForestTrustRecord);
153 if (lftr == NULL) {
154 return NT_STATUS_NO_MEMORY;
157 lftr->flags = ftr->flags;
158 lftr->time = ftr->timestamp;
159 lftr->type = ftr->type;
161 switch (lftr->type) {
162 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
163 lstr = &lftr->forest_trust_data.top_level_name;
164 str = &ftr->data.name;
166 lstr->string = talloc_strdup(mem_ctx, str->string);
167 if (lstr->string == NULL) {
168 TALLOC_FREE(lftr);
169 return NT_STATUS_NO_MEMORY;
172 break;
174 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
175 lstr = &lftr->forest_trust_data.top_level_name_ex;
176 str = &ftr->data.name;
178 lstr->string = talloc_strdup(mem_ctx, str->string);
179 if (lstr->string == NULL) {
180 TALLOC_FREE(lftr);
181 return NT_STATUS_NO_MEMORY;
184 break;
186 case LSA_FOREST_TRUST_DOMAIN_INFO:
187 linfo = &lftr->forest_trust_data.domain_info;
188 info = &ftr->data.info;
190 linfo->domain_sid = dom_sid_dup(lftr, &info->sid);
191 if (linfo->domain_sid == NULL) {
192 TALLOC_FREE(lftr);
193 return NT_STATUS_NO_MEMORY;
196 lstr = &linfo->dns_domain_name;
197 str = &info->dns_name;
198 lstr->string = talloc_strdup(mem_ctx, str->string);
199 if (lstr->string == NULL) {
200 TALLOC_FREE(lftr);
201 return NT_STATUS_NO_MEMORY;
204 lstr = &linfo->netbios_domain_name;
205 str = &info->netbios_name;
206 lstr->string = talloc_strdup(mem_ctx, str->string);
207 if (lstr->string == NULL) {
208 TALLOC_FREE(lftr);
209 return NT_STATUS_NO_MEMORY;
212 break;
214 default:
215 return NT_STATUS_NOT_SUPPORTED;
218 *_lftr = lftr;
219 return NT_STATUS_OK;
222 NTSTATUS dsdb_trust_forest_info_to_lsa(TALLOC_CTX *mem_ctx,
223 const struct ForestTrustInfo *fti,
224 struct lsa_ForestTrustInformation **_lfti)
226 struct lsa_ForestTrustInformation *lfti;
227 uint32_t i;
229 *_lfti = NULL;
231 if (fti->version != 1) {
232 return NT_STATUS_INVALID_PARAMETER;
235 lfti = talloc_zero(mem_ctx, struct lsa_ForestTrustInformation);
236 if (fti == NULL) {
237 return NT_STATUS_NO_MEMORY;
240 lfti->count = fti->count;
241 lfti->entries = talloc_zero_array(mem_ctx,
242 struct lsa_ForestTrustRecord *,
243 lfti->count);
244 if (lfti->entries == NULL) {
245 TALLOC_FREE(lfti);
246 return NT_STATUS_NO_MEMORY;
249 for (i = 0; i < fti->count; i++) {
250 struct ForestTrustInfoRecord *ftr = &fti->records[i].record;
251 struct lsa_ForestTrustRecord *lftr = NULL;
252 NTSTATUS status;
254 status = dsdb_trust_forest_record_to_lsa(lfti->entries, ftr,
255 &lftr);
256 if (!NT_STATUS_IS_OK(status)) {
257 TALLOC_FREE(lfti);
258 return NT_STATUS_NO_MEMORY;
260 lfti->entries[i] = lftr;
263 *_lfti = lfti;
264 return NT_STATUS_OK;
267 static NTSTATUS dsdb_trust_forest_info_add_record(struct lsa_ForestTrustInformation *fti,
268 const struct lsa_ForestTrustRecord *ftr)
270 struct lsa_ForestTrustRecord **es = NULL;
271 struct lsa_ForestTrustRecord *e = NULL;
272 const struct lsa_StringLarge *dns1 = NULL;
273 struct lsa_StringLarge *dns2 = NULL;
274 const struct lsa_ForestTrustDomainInfo *d1 = NULL;
275 struct lsa_ForestTrustDomainInfo *d2 = NULL;
276 size_t len = 0;
278 es = talloc_realloc(fti, fti->entries,
279 struct lsa_ForestTrustRecord *,
280 fti->count + 1);
281 if (!es) {
282 return NT_STATUS_NO_MEMORY;
284 fti->entries = es;
286 e = talloc_zero(es, struct lsa_ForestTrustRecord);
287 if (e == NULL) {
288 return NT_STATUS_NO_MEMORY;
291 e->type = ftr->type;
292 e->flags = ftr->flags;
293 e->time = ftr->time;
295 switch (ftr->type) {
296 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
297 dns1 = &ftr->forest_trust_data.top_level_name;
298 dns2 = &e->forest_trust_data.top_level_name;
299 break;
301 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
302 dns1 = &ftr->forest_trust_data.top_level_name_ex;
303 dns2 = &e->forest_trust_data.top_level_name_ex;
304 break;
306 case LSA_FOREST_TRUST_DOMAIN_INFO:
307 dns1 = &ftr->forest_trust_data.domain_info.dns_domain_name;
308 dns2 = &e->forest_trust_data.domain_info.dns_domain_name;
309 d1 = &ftr->forest_trust_data.domain_info;
310 d2 = &e->forest_trust_data.domain_info;
311 break;
312 default:
313 return NT_STATUS_INVALID_PARAMETER;
316 if (dns1->string == NULL) {
317 TALLOC_FREE(e);
318 return NT_STATUS_INVALID_PARAMETER;
321 len = strlen(dns1->string);
322 if (len == 0) {
323 TALLOC_FREE(e);
324 return NT_STATUS_INVALID_PARAMETER;
327 dns2->string = talloc_strdup(e, dns1->string);
328 if (dns2->string == NULL) {
329 TALLOC_FREE(e);
330 return NT_STATUS_NO_MEMORY;
333 if (d1 != NULL) {
334 const struct lsa_StringLarge *nb1 = &d1->netbios_domain_name;
335 struct lsa_StringLarge *nb2 = &d2->netbios_domain_name;
337 if (nb1->string == NULL) {
338 TALLOC_FREE(e);
339 return NT_STATUS_INVALID_PARAMETER;
342 len = strlen(nb1->string);
343 if (len == 0) {
344 TALLOC_FREE(e);
345 return NT_STATUS_INVALID_PARAMETER;
347 if (len > 15) {
348 TALLOC_FREE(e);
349 return NT_STATUS_INVALID_PARAMETER;
352 nb2->string = talloc_strdup(e, nb1->string);
353 if (nb2->string == NULL) {
354 TALLOC_FREE(e);
355 return NT_STATUS_NO_MEMORY;
358 if (d1->domain_sid == NULL) {
359 TALLOC_FREE(e);
360 return NT_STATUS_INVALID_PARAMETER;
363 d2->domain_sid = dom_sid_dup(e, d1->domain_sid);
364 if (d2->domain_sid == NULL) {
365 TALLOC_FREE(e);
366 return NT_STATUS_NO_MEMORY;
370 fti->entries[fti->count++] = e;
371 return NT_STATUS_OK;
374 static NTSTATUS dsdb_trust_parse_crossref_info(TALLOC_CTX *mem_ctx,
375 struct ldb_context *sam_ctx,
376 const struct ldb_message *msg,
377 struct lsa_TrustDomainInfoInfoEx **_tdo)
379 TALLOC_CTX *frame = talloc_stackframe();
380 struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
381 const char *dns = NULL;
382 const char *netbios = NULL;
383 struct ldb_dn *nc_dn = NULL;
384 struct dom_sid sid = {};
385 NTSTATUS status;
387 *_tdo = NULL;
388 tdo = talloc_zero(mem_ctx, struct lsa_TrustDomainInfoInfoEx);
389 if (tdo == NULL) {
390 TALLOC_FREE(frame);
391 return NT_STATUS_NO_MEMORY;
393 talloc_steal(frame, tdo);
395 dns = ldb_msg_find_attr_as_string(msg, "dnsRoot", NULL);
396 if (dns == NULL) {
397 TALLOC_FREE(frame);
398 return NT_STATUS_INTERNAL_DB_CORRUPTION;
400 tdo->domain_name.string = talloc_strdup(tdo, dns);
401 if (tdo->domain_name.string == NULL) {
402 TALLOC_FREE(frame);
403 return NT_STATUS_NO_MEMORY;
406 netbios = ldb_msg_find_attr_as_string(msg, "nETBIOSName", NULL);
407 if (netbios == NULL) {
408 TALLOC_FREE(frame);
409 return NT_STATUS_INTERNAL_DB_CORRUPTION;
411 tdo->netbios_name.string = talloc_strdup(tdo, netbios);
412 if (tdo->netbios_name.string == NULL) {
413 TALLOC_FREE(frame);
414 return NT_STATUS_NO_MEMORY;
417 nc_dn = samdb_result_dn(sam_ctx, frame, msg, "ncName", NULL);
418 if (nc_dn == NULL) {
419 TALLOC_FREE(frame);
420 return NT_STATUS_INTERNAL_DB_CORRUPTION;
423 status = dsdb_get_extended_dn_sid(nc_dn, &sid, "SID");
424 if (!NT_STATUS_IS_OK(status)) {
425 TALLOC_FREE(frame);
426 return status;
428 tdo->sid = dom_sid_dup(tdo, &sid);
429 if (tdo->sid == NULL) {
430 TALLOC_FREE(frame);
431 return NT_STATUS_NO_MEMORY;
434 tdo->trust_type = LSA_TRUST_TYPE_UPLEVEL;
435 tdo->trust_direction = LSA_TRUST_DIRECTION_INBOUND |
436 LSA_TRUST_DIRECTION_OUTBOUND;
437 tdo->trust_attributes = LSA_TRUST_ATTRIBUTE_WITHIN_FOREST;
439 *_tdo = talloc_move(mem_ctx, &tdo);
440 TALLOC_FREE(frame);
441 return NT_STATUS_OK;
444 static NTSTATUS dsdb_trust_crossref_tdo_info(TALLOC_CTX *mem_ctx,
445 struct ldb_context *sam_ctx,
446 struct ldb_dn *domain_dn,
447 const char *extra_filter,
448 struct lsa_TrustDomainInfoInfoEx **_tdo,
449 struct lsa_TrustDomainInfoInfoEx **_root_trust_tdo,
450 struct lsa_TrustDomainInfoInfoEx **_trust_parent_tdo)
452 TALLOC_CTX *frame = talloc_stackframe();
453 struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
454 struct lsa_TrustDomainInfoInfoEx *root_trust_tdo = NULL;
455 struct lsa_TrustDomainInfoInfoEx *trust_parent_tdo = NULL;
456 struct ldb_dn *partitions_dn = NULL;
457 const char * const cross_attrs[] = {
458 "dnsRoot",
459 "nETBIOSName",
460 "nCName",
461 "rootTrust",
462 "trustParent",
463 NULL,
465 struct ldb_result *cross_res = NULL;
466 struct ldb_message *msg = NULL;
467 struct ldb_dn *root_trust_dn = NULL;
468 struct ldb_dn *trust_parent_dn = NULL;
469 NTSTATUS status;
470 int ret;
472 if (extra_filter == NULL) {
473 extra_filter = "";
476 *_tdo = NULL;
477 if (_root_trust_tdo != NULL) {
478 *_root_trust_tdo = NULL;
480 if (_trust_parent_tdo != NULL) {
481 *_trust_parent_tdo = NULL;
484 domain_dn = ldb_get_default_basedn(sam_ctx);
485 if (domain_dn == NULL) {
486 TALLOC_FREE(frame);
487 return NT_STATUS_INTERNAL_ERROR;
490 partitions_dn = samdb_partitions_dn(sam_ctx, frame);
491 if (partitions_dn == NULL) {
492 TALLOC_FREE(frame);
493 return NT_STATUS_NO_MEMORY;
496 ret = dsdb_search(sam_ctx, partitions_dn, &cross_res,
497 partitions_dn, LDB_SCOPE_ONELEVEL,
498 cross_attrs,
499 DSDB_SEARCH_ONE_ONLY |
500 DSDB_SEARCH_SHOW_EXTENDED_DN,
501 "(&"
502 "(ncName=%s)"
503 "(objectClass=crossRef)"
504 "(systemFlags:%s:=%u)"
505 "%s"
506 ")",
507 ldb_dn_get_linearized(domain_dn),
508 LDB_OID_COMPARATOR_AND,
509 SYSTEM_FLAG_CR_NTDS_DOMAIN,
510 extra_filter);
511 if (ret != LDB_SUCCESS) {
512 TALLOC_FREE(frame);
513 return dsdb_ldb_err_to_ntstatus(ret);
515 msg = cross_res->msgs[0];
517 status = dsdb_trust_parse_crossref_info(mem_ctx, sam_ctx, msg, &tdo);
518 if (!NT_STATUS_IS_OK(status)) {
519 TALLOC_FREE(frame);
520 return status;
522 talloc_steal(frame, tdo);
524 if (_root_trust_tdo != NULL) {
525 root_trust_dn = samdb_result_dn(sam_ctx, frame, msg,
526 "rootTrust", NULL);
528 if (_trust_parent_tdo != NULL) {
529 trust_parent_dn = samdb_result_dn(sam_ctx, frame, msg,
530 "trustParent", NULL);
533 if (root_trust_dn != NULL) {
534 struct ldb_message *root_trust_msg = NULL;
536 ret = dsdb_search_one(sam_ctx, frame,
537 &root_trust_msg,
538 root_trust_dn,
539 LDB_SCOPE_BASE,
540 cross_attrs,
541 DSDB_SEARCH_NO_GLOBAL_CATALOG,
542 "(objectClass=crossRef)");
543 if (ret != LDB_SUCCESS) {
544 status = dsdb_ldb_err_to_ntstatus(ret);
545 DEBUG(3, ("Failed to search for %s: %s - %s\n",
546 ldb_dn_get_linearized(root_trust_dn),
547 nt_errstr(status), ldb_errstring(sam_ctx)));
548 TALLOC_FREE(frame);
549 return status;
552 status = dsdb_trust_parse_crossref_info(mem_ctx, sam_ctx,
553 root_trust_msg,
554 &root_trust_tdo);
555 if (!NT_STATUS_IS_OK(status)) {
556 TALLOC_FREE(frame);
557 return status;
559 talloc_steal(frame, root_trust_tdo);
562 if (trust_parent_dn != NULL) {
563 struct ldb_message *trust_parent_msg = NULL;
565 ret = dsdb_search_one(sam_ctx, frame,
566 &trust_parent_msg,
567 trust_parent_dn,
568 LDB_SCOPE_BASE,
569 cross_attrs,
570 DSDB_SEARCH_NO_GLOBAL_CATALOG,
571 "(objectClass=crossRef)");
572 if (ret != LDB_SUCCESS) {
573 status = dsdb_ldb_err_to_ntstatus(ret);
574 DEBUG(3, ("Failed to search for %s: %s - %s\n",
575 ldb_dn_get_linearized(trust_parent_dn),
576 nt_errstr(status), ldb_errstring(sam_ctx)));
577 TALLOC_FREE(frame);
578 return status;
581 status = dsdb_trust_parse_crossref_info(mem_ctx, sam_ctx,
582 trust_parent_msg,
583 &trust_parent_tdo);
584 if (!NT_STATUS_IS_OK(status)) {
585 TALLOC_FREE(frame);
586 return status;
588 talloc_steal(frame, trust_parent_tdo);
591 *_tdo = talloc_move(mem_ctx, &tdo);
592 if (_root_trust_tdo != NULL) {
593 *_root_trust_tdo = talloc_move(mem_ctx, &root_trust_tdo);
595 if (_trust_parent_tdo != NULL) {
596 *_trust_parent_tdo = talloc_move(mem_ctx, &trust_parent_tdo);
598 TALLOC_FREE(frame);
599 return NT_STATUS_OK;
602 #define DNS_CMP_FIRST_IS_CHILD -2
603 #define DNS_CMP_FIRST_IS_LESS -1
604 #define DNS_CMP_MATCH 0
605 #define DNS_CMP_SECOND_IS_LESS 1
606 #define DNS_CMP_SECOND_IS_CHILD 2
608 #define DNS_CMP_IS_NO_MATCH(__cmp) \
609 ((__cmp == DNS_CMP_FIRST_IS_LESS) || (__cmp == DNS_CMP_SECOND_IS_LESS))
612 * this function assumes names are well formed DNS names.
613 * it doesn't validate them
615 * It allows strings up to a length of UINT16_MAX - 1
616 * with up to UINT8_MAX components. On overflow this
617 * just returns the result of strcasecmp_m().
619 * Trailing dots (only one) are ignored.
621 * The DNS names are compared per component, starting from
622 * the last one.
624 static int dns_cmp(const char *s1, const char *s2)
626 size_t l1 = 0;
627 const char *p1 = NULL;
628 size_t num_comp1 = 0;
629 uint16_t comp1[UINT8_MAX] = {};
630 size_t l2 = 0;
631 const char *p2 = NULL;
632 size_t num_comp2 = 0;
633 uint16_t comp2[UINT8_MAX] = {};
634 size_t i;
636 if (s1 != NULL) {
637 l1 = strlen(s1);
640 if (s2 != NULL) {
641 l2 = strlen(s2);
645 * trailing '.' are ignored.
647 if (l1 > 1 && s1[l1 - 1] == '.') {
648 l1--;
650 if (l2 > 1 && s2[l2 - 1] == '.') {
651 l2--;
654 for (i = 0; i < ARRAY_SIZE(comp1); i++) {
655 char *p;
657 if (i == 0) {
658 p1 = s1;
660 if (l1 == 0 && l1 >= UINT16_MAX) {
661 /* just use one single component on overflow */
662 break;
666 comp1[num_comp1++] = PTR_DIFF(p1, s1);
668 p = strchr_m(p1, '.');
669 if (p == NULL) {
670 p1 = NULL;
671 break;
674 p1 = p + 1;
677 if (p1 != NULL) {
678 /* just use one single component on overflow */
679 num_comp1 = 0;
680 comp1[num_comp1++] = 0;
681 p1 = NULL;
684 for (i = 0; i < ARRAY_SIZE(comp2); i++) {
685 char *p;
687 if (i == 0) {
688 p2 = s2;
690 if (l2 == 0 && l2 >= UINT16_MAX) {
691 /* just use one single component on overflow */
692 break;
696 comp2[num_comp2++] = PTR_DIFF(p2, s2);
698 p = strchr_m(p2, '.');
699 if (p == NULL) {
700 p2 = NULL;
701 break;
704 p2 = p + 1;
707 if (p2 != NULL) {
708 /* just use one single component on overflow */
709 num_comp2 = 0;
710 comp2[num_comp2++] = 0;
711 p2 = NULL;
714 for (i = 0; i < UINT8_MAX; i++) {
715 int cmp;
717 if (i < num_comp1) {
718 size_t idx = num_comp1 - (i + 1);
719 p1 = s1 + comp1[idx];
720 } else {
721 p1 = NULL;
724 if (i < num_comp2) {
725 size_t idx = num_comp2 - (i + 1);
726 p2 = s2 + comp2[idx];
727 } else {
728 p2 = NULL;
731 if (p1 == NULL && p2 == NULL) {
732 return DNS_CMP_MATCH;
734 if (p1 != NULL && p2 == NULL) {
735 return DNS_CMP_FIRST_IS_CHILD;
737 if (p1 == NULL && p2 != NULL) {
738 return DNS_CMP_SECOND_IS_CHILD;
741 cmp = strcasecmp_m(p1, p2);
742 if (cmp < 0) {
743 return DNS_CMP_FIRST_IS_LESS;
745 if (cmp > 0) {
746 return DNS_CMP_SECOND_IS_LESS;
750 smb_panic(__location__);
751 return -1;
754 static int dsdb_trust_find_tln_match_internal(const struct lsa_ForestTrustInformation *info,
755 enum lsa_ForestTrustRecordType type,
756 uint32_t disable_mask,
757 const char *tln)
759 uint32_t i;
761 for (i = 0; i < info->count; i++) {
762 struct lsa_ForestTrustRecord *e = info->entries[i];
763 struct lsa_StringLarge *t = NULL;
764 int cmp;
766 if (e == NULL) {
767 continue;
770 if (e->type != type) {
771 continue;
774 if (e->flags & disable_mask) {
775 continue;
778 switch (type) {
779 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
780 t = &e->forest_trust_data.top_level_name;
781 break;
782 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
783 t = &e->forest_trust_data.top_level_name_ex;
784 break;
785 default:
786 break;
789 if (t == NULL) {
790 continue;
793 cmp = dns_cmp(tln, t->string);
794 switch (cmp) {
795 case DNS_CMP_MATCH:
796 case DNS_CMP_FIRST_IS_CHILD:
797 return i;
801 return -1;
804 static bool dsdb_trust_find_tln_match(const struct lsa_ForestTrustInformation *info,
805 const char *tln)
807 int m;
809 m = dsdb_trust_find_tln_match_internal(info,
810 LSA_FOREST_TRUST_TOP_LEVEL_NAME,
811 LSA_TLN_DISABLED_MASK,
812 tln);
813 if (m != -1) {
814 return true;
817 return false;
820 static bool dsdb_trust_find_tln_ex_match(const struct lsa_ForestTrustInformation *info,
821 const char *tln)
823 int m;
825 m = dsdb_trust_find_tln_match_internal(info,
826 LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX,
828 tln);
829 if (m != -1) {
830 return true;
833 return false;
836 NTSTATUS dsdb_trust_xref_tdo_info(TALLOC_CTX *mem_ctx,
837 struct ldb_context *sam_ctx,
838 struct lsa_TrustDomainInfoInfoEx **_tdo)
841 * The extra filter makes sure we only find the forest root domain
843 const char *extra_filter = "(!(|(rootTrust=*)(trustParent=*)))";
844 struct ldb_dn *domain_dn = NULL;
846 domain_dn = ldb_get_default_basedn(sam_ctx);
847 if (domain_dn == NULL) {
848 return NT_STATUS_INTERNAL_ERROR;
851 return dsdb_trust_crossref_tdo_info(mem_ctx, sam_ctx,
852 domain_dn, extra_filter,
853 _tdo, NULL, NULL);
856 static int dsdb_trust_xref_sort_msgs(struct ldb_message **_m1,
857 struct ldb_message **_m2)
859 struct ldb_message *m1 = *_m1;
860 struct ldb_message *m2 = *_m2;
861 const char *dns1 = NULL;
862 const char *dns2 = NULL;
863 int cmp;
864 struct ldb_message_element *rootTrust1 = NULL;
865 struct ldb_message_element *trustParent1 = NULL;
866 struct ldb_message_element *rootTrust2 = NULL;
867 struct ldb_message_element *trustParent2 = NULL;
869 dns1 = ldb_msg_find_attr_as_string(m1, "dnsRoot", NULL);
870 dns2 = ldb_msg_find_attr_as_string(m2, "dnsRoot", NULL);
872 cmp = dns_cmp(dns1, dns2);
873 switch (cmp) {
874 case DNS_CMP_FIRST_IS_CHILD:
875 return -1;
876 case DNS_CMP_SECOND_IS_CHILD:
877 return 1;
880 rootTrust1 = ldb_msg_find_element(m1, "rootTrust");
881 trustParent1 = ldb_msg_find_element(m1, "trustParent");
882 rootTrust2 = ldb_msg_find_element(m2, "rootTrust");
883 trustParent2 = ldb_msg_find_element(m2, "trustParent");
885 if (rootTrust1 == NULL && trustParent1 == NULL) {
886 /* m1 is the forest root */
887 return -1;
889 if (rootTrust2 == NULL && trustParent2 == NULL) {
890 /* m2 is the forest root */
891 return 1;
894 return cmp;
897 static int dsdb_trust_xref_sort_vals(struct ldb_val *v1,
898 struct ldb_val *v2)
900 const char *dns1 = (const char *)v1->data;
901 const char *dns2 = (const char *)v2->data;
903 return dns_cmp(dns1, dns2);
906 NTSTATUS dsdb_trust_xref_forest_info(TALLOC_CTX *mem_ctx,
907 struct ldb_context *sam_ctx,
908 struct lsa_ForestTrustInformation **_info)
910 TALLOC_CTX *frame = talloc_stackframe();
911 struct lsa_ForestTrustInformation *info = NULL;
912 struct ldb_dn *partitions_dn = NULL;
913 const char * const cross_attrs1[] = {
914 "uPNSuffixes",
915 "msDS-SPNSuffixes",
916 NULL,
918 struct ldb_result *cross_res1 = NULL;
919 struct ldb_message_element *upn_el = NULL;
920 struct ldb_message_element *spn_el = NULL;
921 struct ldb_message *tln_msg = NULL;
922 struct ldb_message_element *tln_el = NULL;
923 const char * const cross_attrs2[] = {
924 "dnsRoot",
925 "nETBIOSName",
926 "nCName",
927 "rootTrust",
928 "trustParent",
929 NULL,
931 struct ldb_result *cross_res2 = NULL;
932 int ret;
933 unsigned int i;
934 bool restart = false;
936 *_info = NULL;
937 info = talloc_zero(mem_ctx, struct lsa_ForestTrustInformation);
938 if (info == NULL) {
939 TALLOC_FREE(frame);
940 return NT_STATUS_NO_MEMORY;
942 talloc_steal(frame, info);
944 partitions_dn = samdb_partitions_dn(sam_ctx, frame);
945 if (partitions_dn == NULL) {
946 TALLOC_FREE(frame);
947 return NT_STATUS_NO_MEMORY;
950 ret = dsdb_search_dn(sam_ctx, partitions_dn, &cross_res1,
951 partitions_dn, cross_attrs1, 0);
952 if (ret != LDB_SUCCESS) {
953 TALLOC_FREE(frame);
954 return dsdb_ldb_err_to_ntstatus(ret);
957 ret = dsdb_search(sam_ctx, partitions_dn, &cross_res2,
958 partitions_dn, LDB_SCOPE_ONELEVEL,
959 cross_attrs2,
960 DSDB_SEARCH_SHOW_EXTENDED_DN,
961 "(&(objectClass=crossRef)"
962 "(systemFlags:%s:=%u))",
963 LDB_OID_COMPARATOR_AND,
964 SYSTEM_FLAG_CR_NTDS_DOMAIN);
965 if (ret != LDB_SUCCESS) {
966 TALLOC_FREE(frame);
967 return dsdb_ldb_err_to_ntstatus(ret);
971 * Sort the domains as trees, starting with the forest root
973 TYPESAFE_QSORT(cross_res2->msgs, cross_res2->count,
974 dsdb_trust_xref_sort_msgs);
976 upn_el = ldb_msg_find_element(cross_res1->msgs[0], "uPNSuffixes");
977 if (upn_el != NULL) {
978 upn_el->name = "__tln__";
980 spn_el = ldb_msg_find_element(cross_res1->msgs[0], "msDS-SPNSuffixes");
981 if (spn_el != NULL) {
982 spn_el->name = "__tln__";
984 ret = ldb_msg_normalize(sam_ctx, frame, cross_res1->msgs[0], &tln_msg);
985 if (ret != LDB_SUCCESS) {
986 TALLOC_FREE(frame);
987 return dsdb_ldb_err_to_ntstatus(ret);
989 tln_el = ldb_msg_find_element(tln_msg, "__tln__");
990 if (tln_el != NULL) {
992 * Sort the domains as trees
994 TYPESAFE_QSORT(tln_el->values, tln_el->num_values,
995 dsdb_trust_xref_sort_vals);
998 for (i=0; i < cross_res2->count; i++) {
999 struct ldb_message *m = cross_res2->msgs[i];
1000 const char *dns = NULL;
1001 const char *netbios = NULL;
1002 struct ldb_dn *nc_dn = NULL;
1003 struct dom_sid sid = {};
1004 struct lsa_ForestTrustRecord e = {};
1005 struct lsa_ForestTrustDomainInfo *d = NULL;
1006 struct lsa_StringLarge *t = NULL;
1007 bool match = false;
1008 NTSTATUS status;
1010 dns = ldb_msg_find_attr_as_string(m, "dnsRoot", NULL);
1011 if (dns == NULL) {
1012 TALLOC_FREE(frame);
1013 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1016 netbios = ldb_msg_find_attr_as_string(m, "nETBIOSName", NULL);
1017 if (netbios == NULL) {
1018 TALLOC_FREE(frame);
1019 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1022 nc_dn = samdb_result_dn(sam_ctx, m, m, "ncName", NULL);
1023 if (nc_dn == NULL) {
1024 TALLOC_FREE(frame);
1025 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1028 status = dsdb_get_extended_dn_sid(nc_dn, &sid, "SID");
1029 if (!NT_STATUS_IS_OK(status)) {
1030 TALLOC_FREE(frame);
1031 return status;
1034 match = dsdb_trust_find_tln_match(info, dns);
1035 if (!match) {
1037 * First the TOP_LEVEL_NAME, if required
1039 e = (struct lsa_ForestTrustRecord) {
1040 .flags = 0,
1041 .type = LSA_FOREST_TRUST_TOP_LEVEL_NAME,
1042 .time = 0, /* so far always 0 in traces. */
1045 t = &e.forest_trust_data.top_level_name;
1046 t->string = dns;
1048 status = dsdb_trust_forest_info_add_record(info, &e);
1049 if (!NT_STATUS_IS_OK(status)) {
1050 TALLOC_FREE(frame);
1051 return status;
1056 * Then the DOMAIN_INFO
1058 e = (struct lsa_ForestTrustRecord) {
1059 .flags = 0,
1060 .type = LSA_FOREST_TRUST_DOMAIN_INFO,
1061 .time = 0, /* so far always 0 in traces. */
1063 d = &e.forest_trust_data.domain_info;
1064 d->domain_sid = &sid;
1065 d->dns_domain_name.string = dns;
1066 d->netbios_domain_name.string = netbios;
1068 status = dsdb_trust_forest_info_add_record(info, &e);
1069 if (!NT_STATUS_IS_OK(status)) {
1070 TALLOC_FREE(frame);
1071 return status;
1075 for (i=0; (tln_el != NULL) && i < tln_el->num_values; i++) {
1076 const struct ldb_val *v = &tln_el->values[i];
1077 const char *dns = (const char *)v->data;
1078 struct lsa_ForestTrustRecord e = {};
1079 struct lsa_StringLarge *t = NULL;
1080 bool match = false;
1081 NTSTATUS status;
1083 if (dns == NULL) {
1084 TALLOC_FREE(frame);
1085 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1088 match = dsdb_trust_find_tln_match(info, dns);
1089 if (match) {
1090 continue;
1094 * an additional the TOP_LEVEL_NAME
1096 e = (struct lsa_ForestTrustRecord) {
1097 .flags = 0,
1098 .type = LSA_FOREST_TRUST_TOP_LEVEL_NAME,
1099 .time = 0, /* so far always 0 in traces. */
1101 t = &e.forest_trust_data.top_level_name;
1102 t->string = dns;
1104 status = dsdb_trust_forest_info_add_record(info, &e);
1105 if (!NT_STATUS_IS_OK(status)) {
1106 TALLOC_FREE(frame);
1107 return status;
1111 for (i=0; i < info->count; restart ? i=0 : i++) {
1112 struct lsa_ForestTrustRecord *tr = info->entries[i];
1113 const struct lsa_StringLarge *ts = NULL;
1114 uint32_t c;
1116 restart = false;
1118 if (tr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
1119 continue;
1122 ts = &tr->forest_trust_data.top_level_name;
1124 for (c = i + 1; c < info->count; c++) {
1125 struct lsa_ForestTrustRecord *cr = info->entries[c];
1126 const struct lsa_StringLarge *cs = NULL;
1127 uint32_t j;
1128 int cmp;
1130 if (cr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
1131 continue;
1134 cs = &cr->forest_trust_data.top_level_name;
1136 cmp = dns_cmp(ts->string, cs->string);
1137 if (DNS_CMP_IS_NO_MATCH(cmp)) {
1138 continue;
1140 if (cmp != DNS_CMP_FIRST_IS_CHILD) {
1141 /* can't happen ... */
1142 continue;
1145 ts = NULL;
1146 tr = NULL;
1147 TALLOC_FREE(info->entries[i]);
1148 info->entries[i] = info->entries[c];
1150 for (j = c + 1; j < info->count; j++) {
1151 info->entries[j-1] = info->entries[j];
1153 info->count -= 1;
1154 restart = true;
1155 break;
1159 *_info = talloc_move(mem_ctx, &info);
1160 TALLOC_FREE(frame);
1161 return NT_STATUS_OK;
1164 NTSTATUS dsdb_trust_parse_tdo_info(TALLOC_CTX *mem_ctx,
1165 struct ldb_message *m,
1166 struct lsa_TrustDomainInfoInfoEx **_tdo)
1168 struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
1169 const char *dns = NULL;
1170 const char *netbios = NULL;
1172 *_tdo = NULL;
1174 tdo = talloc_zero(mem_ctx, struct lsa_TrustDomainInfoInfoEx);
1175 if (tdo == NULL) {
1176 return NT_STATUS_NO_MEMORY;
1179 dns = ldb_msg_find_attr_as_string(m, "trustPartner", NULL);
1180 if (dns == NULL) {
1181 TALLOC_FREE(tdo);
1182 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1184 tdo->domain_name.string = talloc_strdup(tdo, dns);
1185 if (tdo->domain_name.string == NULL) {
1186 TALLOC_FREE(tdo);
1187 return NT_STATUS_NO_MEMORY;
1190 netbios = ldb_msg_find_attr_as_string(m, "flatName", NULL);
1191 if (netbios == NULL) {
1192 TALLOC_FREE(tdo);
1193 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1195 tdo->netbios_name.string = talloc_strdup(tdo, netbios);
1196 if (tdo->netbios_name.string == NULL) {
1197 TALLOC_FREE(tdo);
1198 return NT_STATUS_NO_MEMORY;
1201 tdo->sid = samdb_result_dom_sid(tdo, m, "securityIdentifier");
1202 if (tdo->sid == NULL) {
1203 TALLOC_FREE(tdo);
1204 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1207 tdo->trust_type = ldb_msg_find_attr_as_uint(m, "trustType", 0);
1208 tdo->trust_direction = ldb_msg_find_attr_as_uint(m, "trustDirection", 0);
1209 tdo->trust_attributes = ldb_msg_find_attr_as_uint(m, "trustAttributes", 0);
1211 *_tdo = tdo;
1212 return NT_STATUS_OK;
1215 NTSTATUS dsdb_trust_parse_forest_info(TALLOC_CTX *mem_ctx,
1216 struct ldb_message *m,
1217 struct ForestTrustInfo **_fti)
1219 const struct ldb_val *ft_blob = NULL;
1220 struct ForestTrustInfo *fti = NULL;
1221 enum ndr_err_code ndr_err;
1223 *_fti = NULL;
1225 ft_blob = ldb_msg_find_ldb_val(m, "msDS-TrustForestTrustInfo");
1226 if (ft_blob == NULL) {
1227 return NT_STATUS_NOT_FOUND;
1230 fti = talloc_zero(mem_ctx, struct ForestTrustInfo);
1231 if (fti == NULL) {
1232 return NT_STATUS_NO_MEMORY;
1235 /* ldb_val is equivalent to DATA_BLOB */
1236 ndr_err = ndr_pull_struct_blob_all(ft_blob, fti, fti,
1237 (ndr_pull_flags_fn_t)ndr_pull_ForestTrustInfo);
1238 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1239 TALLOC_FREE(fti);
1240 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1243 *_fti = fti;
1244 return NT_STATUS_OK;
1247 NTSTATUS dsdb_trust_normalize_forest_info_step1(TALLOC_CTX *mem_ctx,
1248 const struct lsa_ForestTrustInformation *gfti,
1249 struct lsa_ForestTrustInformation **_nfti)
1251 TALLOC_CTX *frame = talloc_stackframe();
1252 struct lsa_ForestTrustInformation *nfti;
1253 uint32_t n;
1255 *_nfti = NULL;
1257 nfti = talloc_zero(mem_ctx, struct lsa_ForestTrustInformation);
1258 if (nfti == NULL) {
1259 TALLOC_FREE(frame);
1260 return NT_STATUS_NO_MEMORY;
1262 talloc_steal(frame, nfti);
1265 * First we copy every record and remove possible trailing dots
1266 * from dns names.
1268 * We also NULL out dublicates. The first one wins and
1269 * we keep 'count' as is. This is required in order to
1270 * provide the correct index for collision records.
1272 for (n = 0; n < gfti->count; n++) {
1273 const struct lsa_ForestTrustRecord *gftr = gfti->entries[n];
1274 struct lsa_ForestTrustRecord *nftr = NULL;
1275 struct lsa_ForestTrustDomainInfo *ninfo = NULL;
1276 struct lsa_StringLarge *ntln = NULL;
1277 struct lsa_StringLarge *nnb = NULL;
1278 struct dom_sid *nsid = NULL;
1279 NTSTATUS status;
1280 size_t len = 0;
1281 char *p = NULL;
1282 uint32_t c;
1284 if (gftr == NULL) {
1285 TALLOC_FREE(frame);
1286 return NT_STATUS_INVALID_PARAMETER;
1289 status = dsdb_trust_forest_info_add_record(nfti, gftr);
1290 if (!NT_STATUS_IS_OK(status)) {
1291 TALLOC_FREE(frame);
1292 return status;
1295 nftr = nfti->entries[n];
1297 switch (nftr->type) {
1298 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
1299 ntln = &nftr->forest_trust_data.top_level_name;
1300 break;
1302 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
1303 ntln = &nftr->forest_trust_data.top_level_name_ex;
1304 break;
1306 case LSA_FOREST_TRUST_DOMAIN_INFO:
1307 ninfo = &nftr->forest_trust_data.domain_info;
1308 ntln = &ninfo->dns_domain_name;
1309 nnb = &ninfo->netbios_domain_name;
1310 nsid = ninfo->domain_sid;
1311 break;
1313 default:
1314 TALLOC_FREE(frame);
1315 return NT_STATUS_INVALID_PARAMETER;
1319 * We remove one trailing '.' before checking
1320 * for invalid dots.
1322 * domain.com. becomes domain.com
1323 * domain.com.. becomes domain.com.
1325 * Then the following is invalid:
1327 * domain..com
1328 * .domain.com
1329 * domain.com.
1331 len = strlen(ntln->string);
1332 if (len > 1 && ntln->string[len - 1] == '.') {
1333 const char *cp = &ntln->string[len - 1];
1334 p = discard_const_p(char, cp);
1335 *p= '\0';
1337 if (ntln->string[0] == '.') {
1338 TALLOC_FREE(frame);
1339 return NT_STATUS_INVALID_PARAMETER;
1341 p = strstr_m(ntln->string, "..");
1342 if (p != NULL) {
1343 TALLOC_FREE(frame);
1344 return NT_STATUS_INVALID_PARAMETER;
1347 for (c = 0; c < n; c++) {
1348 const struct lsa_ForestTrustRecord *cftr = nfti->entries[c];
1349 const struct lsa_ForestTrustDomainInfo *cinfo = NULL;
1350 const struct lsa_StringLarge *ctln = NULL;
1351 const struct lsa_StringLarge *cnb = NULL;
1352 const struct dom_sid *csid = NULL;
1353 int cmp;
1355 if (cftr == NULL) {
1356 continue;
1359 if (cftr->type != nftr->type) {
1360 continue;
1363 switch (cftr->type) {
1364 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
1365 ctln = &cftr->forest_trust_data.top_level_name;
1366 break;
1368 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
1369 ctln = &cftr->forest_trust_data.top_level_name_ex;
1370 break;
1372 case LSA_FOREST_TRUST_DOMAIN_INFO:
1373 cinfo = &cftr->forest_trust_data.domain_info;
1374 ctln = &cinfo->dns_domain_name;
1375 cnb = &cinfo->netbios_domain_name;
1376 csid = cinfo->domain_sid;
1377 break;
1379 default:
1380 TALLOC_FREE(frame);
1381 return NT_STATUS_INVALID_PARAMETER;
1384 cmp = dns_cmp(ntln->string, ctln->string);
1385 if (cmp == DNS_CMP_MATCH) {
1386 nftr = NULL;
1387 TALLOC_FREE(nfti->entries[n]);
1388 break;
1391 if (cinfo == NULL) {
1392 continue;
1395 cmp = strcasecmp_m(nnb->string, cnb->string);
1396 if (cmp == 0) {
1397 nftr = NULL;
1398 TALLOC_FREE(nfti->entries[n]);
1399 break;
1402 cmp = dom_sid_compare(nsid, csid);
1403 if (cmp == 0) {
1404 nftr = NULL;
1405 TALLOC_FREE(nfti->entries[n]);
1406 break;
1412 * Now we check that only true top level names are provided
1414 for (n = 0; n < nfti->count; n++) {
1415 const struct lsa_ForestTrustRecord *nftr = nfti->entries[n];
1416 const struct lsa_StringLarge *ntln = NULL;
1417 uint32_t c;
1419 if (nftr == NULL) {
1420 continue;
1423 if (nftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
1424 continue;
1427 ntln = &nftr->forest_trust_data.top_level_name;
1429 for (c = 0; c < nfti->count; c++) {
1430 const struct lsa_ForestTrustRecord *cftr = nfti->entries[c];
1431 const struct lsa_StringLarge *ctln = NULL;
1432 int cmp;
1434 if (cftr == NULL) {
1435 continue;
1438 if (cftr == nftr) {
1439 continue;
1442 if (cftr->type != nftr->type) {
1443 continue;
1446 ctln = &cftr->forest_trust_data.top_level_name;
1448 cmp = dns_cmp(ntln->string, ctln->string);
1449 if (DNS_CMP_IS_NO_MATCH(cmp)) {
1450 continue;
1453 TALLOC_FREE(frame);
1454 return NT_STATUS_INVALID_PARAMETER;
1459 * Now we check that only true sub level excludes are provided
1461 for (n = 0; n < nfti->count; n++) {
1462 const struct lsa_ForestTrustRecord *nftr = nfti->entries[n];
1463 const struct lsa_StringLarge *ntln = NULL;
1464 uint32_t c;
1465 bool found_tln = false;
1467 if (nftr == NULL) {
1468 continue;
1471 if (nftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX) {
1472 continue;
1475 ntln = &nftr->forest_trust_data.top_level_name;
1477 for (c = 0; c < nfti->count; c++) {
1478 const struct lsa_ForestTrustRecord *cftr = nfti->entries[c];
1479 const struct lsa_StringLarge *ctln = NULL;
1480 int cmp;
1482 if (cftr == NULL) {
1483 continue;
1486 if (cftr == nftr) {
1487 continue;
1490 if (cftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
1491 continue;
1494 ctln = &cftr->forest_trust_data.top_level_name;
1496 cmp = dns_cmp(ntln->string, ctln->string);
1497 if (cmp == DNS_CMP_FIRST_IS_CHILD) {
1498 found_tln = true;
1499 break;
1503 if (found_tln) {
1504 continue;
1507 TALLOC_FREE(frame);
1508 return NT_STATUS_INVALID_PARAMETER;
1512 * Now we check that there's a top level name for each domain
1514 for (n = 0; n < nfti->count; n++) {
1515 const struct lsa_ForestTrustRecord *nftr = nfti->entries[n];
1516 const struct lsa_ForestTrustDomainInfo *ninfo = NULL;
1517 const struct lsa_StringLarge *ntln = NULL;
1518 uint32_t c;
1519 bool found_tln = false;
1521 if (nftr == NULL) {
1522 continue;
1525 if (nftr->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
1526 continue;
1529 ninfo = &nftr->forest_trust_data.domain_info;
1530 ntln = &ninfo->dns_domain_name;
1532 for (c = 0; c < nfti->count; c++) {
1533 const struct lsa_ForestTrustRecord *cftr = nfti->entries[c];
1534 const struct lsa_StringLarge *ctln = NULL;
1535 int cmp;
1537 if (cftr == NULL) {
1538 continue;
1541 if (cftr == nftr) {
1542 continue;
1545 if (cftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
1546 continue;
1549 ctln = &cftr->forest_trust_data.top_level_name;
1551 cmp = dns_cmp(ntln->string, ctln->string);
1552 if (cmp == DNS_CMP_MATCH) {
1553 found_tln = true;
1554 break;
1556 if (cmp == DNS_CMP_FIRST_IS_CHILD) {
1557 found_tln = true;
1558 break;
1562 if (found_tln) {
1563 continue;
1566 TALLOC_FREE(frame);
1567 return NT_STATUS_INVALID_PARAMETER;
1570 *_nfti = talloc_move(mem_ctx, &nfti);
1571 TALLOC_FREE(frame);
1572 return NT_STATUS_OK;
1575 NTSTATUS dsdb_trust_normalize_forest_info_step2(TALLOC_CTX *mem_ctx,
1576 const struct lsa_ForestTrustInformation *gfti,
1577 struct lsa_ForestTrustInformation **_nfti)
1579 TALLOC_CTX *frame = talloc_stackframe();
1580 struct timeval tv = timeval_current();
1581 NTTIME now = timeval_to_nttime(&tv);
1582 struct lsa_ForestTrustInformation *nfti;
1583 uint32_t g;
1585 *_nfti = NULL;
1587 nfti = talloc_zero(mem_ctx, struct lsa_ForestTrustInformation);
1588 if (nfti == NULL) {
1589 TALLOC_FREE(frame);
1590 return NT_STATUS_NO_MEMORY;
1592 talloc_steal(frame, nfti);
1595 * Now we add TOP_LEVEL_NAME[_EX] in reverse order
1596 * followed by LSA_FOREST_TRUST_DOMAIN_INFO in reverse order.
1598 * This also removes the possible NULL entries generated in step1.
1601 for (g = 0; g < gfti->count; g++) {
1602 const struct lsa_ForestTrustRecord *gftr = gfti->entries[gfti->count - (g+1)];
1603 struct lsa_ForestTrustRecord tftr;
1604 bool skip = false;
1605 NTSTATUS status;
1607 if (gftr == NULL) {
1608 continue;
1611 switch (gftr->type) {
1612 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
1613 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
1614 break;
1616 case LSA_FOREST_TRUST_DOMAIN_INFO:
1617 skip = true;
1618 break;
1620 default:
1621 TALLOC_FREE(frame);
1622 return NT_STATUS_INVALID_PARAMETER;
1625 if (skip) {
1626 continue;
1629 /* make a copy in order to update the time. */
1630 tftr = *gftr;
1631 if (tftr.time == 0) {
1632 tftr.time = now;
1635 status = dsdb_trust_forest_info_add_record(nfti, &tftr);
1636 if (!NT_STATUS_IS_OK(status)) {
1637 TALLOC_FREE(frame);
1638 return status;
1642 for (g = 0; g < gfti->count; g++) {
1643 const struct lsa_ForestTrustRecord *gftr = gfti->entries[gfti->count - (g+1)];
1644 struct lsa_ForestTrustRecord tftr;
1645 bool skip = false;
1646 NTSTATUS status;
1648 if (gftr == NULL) {
1649 continue;
1652 switch (gftr->type) {
1653 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
1654 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
1655 skip = true;
1656 break;
1658 case LSA_FOREST_TRUST_DOMAIN_INFO:
1659 break;
1661 default:
1662 TALLOC_FREE(frame);
1663 return NT_STATUS_INVALID_PARAMETER;
1666 if (skip) {
1667 continue;
1670 /* make a copy in order to update the time. */
1671 tftr = *gftr;
1672 if (tftr.time == 0) {
1673 tftr.time = now;
1676 status = dsdb_trust_forest_info_add_record(nfti, &tftr);
1677 if (!NT_STATUS_IS_OK(status)) {
1678 TALLOC_FREE(frame);
1679 return status;
1683 *_nfti = talloc_move(mem_ctx, &nfti);
1684 TALLOC_FREE(frame);
1685 return NT_STATUS_OK;
1688 static NTSTATUS dsdb_trust_add_collision(
1689 struct lsa_ForestTrustCollisionInfo *c_info,
1690 enum lsa_ForestTrustCollisionRecordType type,
1691 uint32_t idx, uint32_t flags,
1692 const char *tdo_name)
1694 struct lsa_ForestTrustCollisionRecord **es;
1695 uint32_t i = c_info->count;
1697 es = talloc_realloc(c_info, c_info->entries,
1698 struct lsa_ForestTrustCollisionRecord *, i + 1);
1699 if (es == NULL) {
1700 return NT_STATUS_NO_MEMORY;
1702 c_info->entries = es;
1703 c_info->count = i + 1;
1705 es[i] = talloc_zero(es, struct lsa_ForestTrustCollisionRecord);
1706 if (es[i] == NULL) {
1707 return NT_STATUS_NO_MEMORY;
1710 es[i]->index = idx;
1711 es[i]->type = type;
1712 es[i]->flags = flags;
1713 es[i]->name.string = talloc_strdup(es[i], tdo_name);
1714 if (es[i]->name.string == NULL) {
1715 return NT_STATUS_NO_MEMORY;
1718 return NT_STATUS_OK;
1721 NTSTATUS dsdb_trust_verify_forest_info(const struct lsa_TrustDomainInfoInfoEx *ref_tdo,
1722 const struct lsa_ForestTrustInformation *ref_fti,
1723 enum lsa_ForestTrustCollisionRecordType collision_type,
1724 struct lsa_ForestTrustCollisionInfo *c_info,
1725 struct lsa_ForestTrustInformation *new_fti)
1727 uint32_t n;
1729 for (n = 0; n < new_fti->count; n++) {
1730 struct lsa_ForestTrustRecord *nftr = new_fti->entries[n];
1731 struct lsa_StringLarge *ntln = NULL;
1732 bool ntln_excluded = false;
1733 uint32_t flags = 0;
1734 uint32_t r;
1735 NTSTATUS status;
1737 if (nftr == NULL) {
1738 continue;
1741 if (nftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
1742 continue;
1745 ntln = &nftr->forest_trust_data.top_level_name;
1746 if (ntln->string == NULL) {
1747 return NT_STATUS_INVALID_PARAMETER;
1750 ntln_excluded = dsdb_trust_find_tln_ex_match(ref_fti,
1751 ntln->string);
1753 /* check if this is already taken and not excluded */
1754 for (r = 0; r < ref_fti->count; r++) {
1755 const struct lsa_ForestTrustRecord *rftr =
1756 ref_fti->entries[r];
1757 const struct lsa_StringLarge *rtln = NULL;
1758 int cmp;
1760 if (rftr == NULL) {
1761 continue;
1764 if (rftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
1765 continue;
1768 rtln = &rftr->forest_trust_data.top_level_name;
1769 if (rtln->string == NULL) {
1770 continue;
1773 cmp = dns_cmp(ntln->string, rtln->string);
1774 if (DNS_CMP_IS_NO_MATCH(cmp)) {
1775 continue;
1777 if (cmp == DNS_CMP_MATCH) {
1778 /* We need to normalize the string */
1779 ntln->string = talloc_strdup(nftr,
1780 rtln->string);
1781 if (ntln->string == NULL) {
1782 return NT_STATUS_NO_MEMORY;
1786 if (ntln_excluded) {
1787 continue;
1790 if (rftr->flags & LSA_TLN_DISABLED_MASK) {
1791 continue;
1794 if (nftr->flags & LSA_TLN_DISABLED_MASK) {
1795 continue;
1798 if (cmp == DNS_CMP_SECOND_IS_CHILD) {
1799 bool m;
1802 * If the conflicting tln is a child, check if
1803 * we have an exclusion record for it.
1805 m = dsdb_trust_find_tln_ex_match(new_fti,
1806 rtln->string);
1807 if (m) {
1808 continue;
1812 flags |= LSA_TLN_DISABLED_CONFLICT;
1815 if (flags == 0) {
1816 continue;
1819 nftr->flags |= flags;
1821 status = dsdb_trust_add_collision(c_info,
1822 collision_type,
1823 n, nftr->flags,
1824 ref_tdo->domain_name.string);
1825 if (!NT_STATUS_IS_OK(status)) {
1826 return status;
1830 for (n = 0; n < new_fti->count; n++) {
1831 struct lsa_ForestTrustRecord *nftr = new_fti->entries[n];
1832 struct lsa_ForestTrustDomainInfo *ninfo = NULL;
1833 struct lsa_StringLarge *ntln = NULL;
1834 struct lsa_StringLarge *nnb = NULL;
1835 struct dom_sid *nsid = NULL;
1836 bool ntln_found = false;
1837 uint32_t flags = 0;
1838 uint32_t r;
1839 NTSTATUS status;
1841 if (nftr == NULL) {
1842 continue;
1845 if (nftr->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
1846 continue;
1849 ninfo = &nftr->forest_trust_data.domain_info;
1850 ntln = &ninfo->dns_domain_name;
1851 if (ntln->string == NULL) {
1852 return NT_STATUS_INVALID_PARAMETER;
1854 nnb = &ninfo->netbios_domain_name;
1855 if (nnb->string == NULL) {
1856 return NT_STATUS_INVALID_PARAMETER;
1858 nsid = ninfo->domain_sid;
1859 if (nsid == NULL) {
1860 return NT_STATUS_INVALID_PARAMETER;
1863 ntln_found = dsdb_trust_find_tln_match(ref_fti, ntln->string);
1865 /* check if this is already taken and not excluded */
1866 for (r = 0; r < ref_fti->count; r++) {
1867 const struct lsa_ForestTrustRecord *rftr =
1868 ref_fti->entries[r];
1869 const struct lsa_ForestTrustDomainInfo *rinfo = NULL;
1870 const struct lsa_StringLarge *rtln = NULL;
1871 const struct lsa_StringLarge *rnb = NULL;
1872 const struct dom_sid *rsid = NULL;
1873 bool nb_possible = true;
1874 bool sid_possible = true;
1875 int cmp;
1877 if (rftr == NULL) {
1878 continue;
1881 if (!ntln_found) {
1883 * If the dns name doesn't match any existing
1884 * tln any conflict is ignored, but name
1885 * normalization still happens.
1887 * I guess that's a bug in Windows
1888 * (tested with Windows 2012r2).
1890 nb_possible = false;
1891 sid_possible = false;
1894 if (nftr->flags & LSA_SID_DISABLED_MASK) {
1895 sid_possible = false;
1898 if (nftr->flags & LSA_NB_DISABLED_MASK) {
1899 nb_possible = false;
1902 switch (rftr->type) {
1903 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
1904 rtln = &rftr->forest_trust_data.top_level_name;
1905 nb_possible = false;
1906 sid_possible = false;
1907 break;
1909 case LSA_FOREST_TRUST_DOMAIN_INFO:
1910 rinfo = &rftr->forest_trust_data.domain_info;
1911 rtln = &rinfo->dns_domain_name;
1912 rnb = &rinfo->netbios_domain_name;
1913 rsid = rinfo->domain_sid;
1915 if (rftr->flags & LSA_SID_DISABLED_MASK) {
1916 sid_possible = false;
1919 if (rftr->flags & LSA_NB_DISABLED_MASK) {
1920 nb_possible = false;
1922 break;
1924 default:
1925 break;
1928 if (rtln == NULL) {
1929 continue;
1932 if (rtln->string == NULL) {
1933 continue;
1936 cmp = dns_cmp(ntln->string, rtln->string);
1937 if (DNS_CMP_IS_NO_MATCH(cmp)) {
1938 nb_possible = false;
1939 sid_possible = false;
1941 if (cmp == DNS_CMP_MATCH) {
1942 /* We need to normalize the string */
1943 ntln->string = talloc_strdup(nftr,
1944 rtln->string);
1945 if (ntln->string == NULL) {
1946 return NT_STATUS_NO_MEMORY;
1950 if (rinfo == NULL) {
1951 continue;
1954 if (rsid != NULL) {
1955 cmp = dom_sid_compare(nsid, rsid);
1956 } else {
1957 cmp = -1;
1959 if (cmp == 0) {
1960 if (sid_possible) {
1961 flags |= LSA_SID_DISABLED_CONFLICT;
1965 if (rnb->string != NULL) {
1966 cmp = strcasecmp_m(nnb->string, rnb->string);
1967 } else {
1968 cmp = -1;
1970 if (cmp == 0) {
1971 nnb->string = talloc_strdup(nftr, rnb->string);
1972 if (nnb->string == NULL) {
1973 return NT_STATUS_NO_MEMORY;
1975 if (nb_possible) {
1976 flags |= LSA_NB_DISABLED_CONFLICT;
1981 if (flags == 0) {
1982 continue;
1985 nftr->flags |= flags;
1987 status = dsdb_trust_add_collision(c_info,
1988 collision_type,
1989 n, nftr->flags,
1990 ref_tdo->domain_name.string);
1991 if (!NT_STATUS_IS_OK(status)) {
1992 return status;
1996 return NT_STATUS_OK;
1999 NTSTATUS dsdb_trust_merge_forest_info(TALLOC_CTX *mem_ctx,
2000 const struct lsa_TrustDomainInfoInfoEx *tdo,
2001 const struct lsa_ForestTrustInformation *ofti,
2002 const struct lsa_ForestTrustInformation *nfti,
2003 struct lsa_ForestTrustInformation **_mfti)
2005 TALLOC_CTX *frame = talloc_stackframe();
2006 struct lsa_ForestTrustInformation *mfti = NULL;
2007 uint32_t ni;
2008 uint32_t oi;
2009 NTSTATUS status;
2010 int cmp;
2012 *_mfti = NULL;
2013 mfti = talloc_zero(mem_ctx, struct lsa_ForestTrustInformation);
2014 if (mfti == NULL) {
2015 TALLOC_FREE(frame);
2016 return NT_STATUS_NO_MEMORY;
2018 talloc_steal(frame, mfti);
2021 * First we add all top unique level names.
2023 * The one matching the tdo dns name, will be
2024 * added without further checking. All others
2025 * may keep the flags and time values.
2027 for (ni = 0; ni < nfti->count; ni++) {
2028 const struct lsa_ForestTrustRecord *nftr = nfti->entries[ni];
2029 struct lsa_ForestTrustRecord tftr = {};
2030 const char *ndns = NULL;
2031 bool ignore_new = false;
2032 bool found_old = false;
2033 uint32_t mi;
2035 if (nftr == NULL) {
2036 TALLOC_FREE(frame);
2037 return NT_STATUS_INVALID_PARAMETER;
2040 if (nftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
2041 continue;
2044 ndns = nftr->forest_trust_data.top_level_name.string;
2045 if (ndns == NULL) {
2046 TALLOC_FREE(frame);
2047 return NT_STATUS_INVALID_PARAMETER;
2050 cmp = dns_cmp(tdo->domain_name.string, ndns);
2051 if (cmp == DNS_CMP_MATCH) {
2052 status = dsdb_trust_forest_info_add_record(mfti, nftr);
2053 if (!NT_STATUS_IS_OK(status)) {
2054 TALLOC_FREE(frame);
2055 return status;
2059 for (mi = 0; mi < mfti->count; mi++) {
2060 const struct lsa_ForestTrustRecord *mftr =
2061 mfti->entries[mi];
2062 const char *mdns = NULL;
2065 * we just added this above, so we're sure to have a
2066 * valid LSA_FOREST_TRUST_TOP_LEVEL_NAME record
2068 mdns = mftr->forest_trust_data.top_level_name.string;
2070 cmp = dns_cmp(mdns, ndns);
2071 switch (cmp) {
2072 case DNS_CMP_MATCH:
2073 case DNS_CMP_SECOND_IS_CHILD:
2074 ignore_new = true;
2075 break;
2078 if (ignore_new) {
2079 break;
2083 if (ignore_new) {
2084 continue;
2088 * make a temporary copy where we can change time and flags
2090 tftr = *nftr;
2092 for (oi = 0; oi < ofti->count; oi++) {
2093 const struct lsa_ForestTrustRecord *oftr =
2094 ofti->entries[oi];
2095 const char *odns = NULL;
2097 if (oftr == NULL) {
2099 * broken record => ignore...
2101 continue;
2104 if (oftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
2105 continue;
2108 odns = oftr->forest_trust_data.top_level_name.string;
2109 if (odns == NULL) {
2111 * broken record => ignore...
2113 continue;
2116 cmp = dns_cmp(odns, ndns);
2117 if (cmp != DNS_CMP_MATCH) {
2118 continue;
2121 found_old = true;
2122 tftr.flags = oftr->flags;
2123 tftr.time = oftr->time;
2126 if (!found_old) {
2127 tftr.flags = LSA_TLN_DISABLED_NEW;
2128 tftr.time = 0;
2131 status = dsdb_trust_forest_info_add_record(mfti, &tftr);
2132 if (!NT_STATUS_IS_OK(status)) {
2133 TALLOC_FREE(frame);
2134 return status;
2139 * Now we add all unique (based on their SID) domains
2140 * and may keep the flags and time values.
2142 for (ni = 0; ni < nfti->count; ni++) {
2143 const struct lsa_ForestTrustRecord *nftr = nfti->entries[ni];
2144 struct lsa_ForestTrustRecord tftr = {};
2145 const struct lsa_ForestTrustDomainInfo *nd = NULL;
2146 const char *ndns = NULL;
2147 const char *nnbt = NULL;
2148 bool ignore_new = false;
2149 bool found_old = false;
2150 uint32_t mi;
2152 if (nftr == NULL) {
2153 TALLOC_FREE(frame);
2154 return NT_STATUS_INVALID_PARAMETER;
2157 if (nftr->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
2158 continue;
2161 nd = &nftr->forest_trust_data.domain_info;
2162 if (nd->domain_sid == NULL) {
2163 TALLOC_FREE(frame);
2164 return NT_STATUS_INVALID_PARAMETER;
2166 ndns = nd->dns_domain_name.string;
2167 if (ndns == NULL) {
2168 TALLOC_FREE(frame);
2169 return NT_STATUS_INVALID_PARAMETER;
2171 nnbt = nd->netbios_domain_name.string;
2172 if (nnbt == NULL) {
2173 TALLOC_FREE(frame);
2174 return NT_STATUS_INVALID_PARAMETER;
2177 for (mi = 0; mi < mfti->count; mi++) {
2178 const struct lsa_ForestTrustRecord *mftr =
2179 mfti->entries[mi];
2180 const struct lsa_ForestTrustDomainInfo *md = NULL;
2182 if (mftr->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
2183 continue;
2187 * we just added this above, so we're sure to have a
2188 * valid LSA_FOREST_TRUST_DOMAIN_INFO record
2190 md = &mftr->forest_trust_data.domain_info;
2192 cmp = dom_sid_compare(nd->domain_sid, md->domain_sid);
2193 if (cmp == 0) {
2194 ignore_new = true;
2195 break;
2199 if (ignore_new) {
2200 continue;
2204 * make a temporary copy where we can change time and flags
2206 tftr = *nftr;
2208 for (oi = 0; oi < ofti->count; oi++) {
2209 const struct lsa_ForestTrustRecord *oftr =
2210 ofti->entries[oi];
2211 const struct lsa_ForestTrustDomainInfo *od = NULL;
2212 const char *onbt = NULL;
2214 if (oftr == NULL) {
2216 * broken record => ignore...
2218 continue;
2221 if (oftr->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
2222 continue;
2225 od = &oftr->forest_trust_data.domain_info;
2226 onbt = od->netbios_domain_name.string;
2227 if (onbt == NULL) {
2229 * broken record => ignore...
2231 continue;
2234 cmp = strcasecmp(onbt, nnbt);
2235 if (cmp != 0) {
2236 continue;
2239 found_old = true;
2240 tftr.flags = oftr->flags;
2241 tftr.time = oftr->time;
2244 if (!found_old) {
2245 tftr.flags = 0;
2246 tftr.time = 0;
2249 status = dsdb_trust_forest_info_add_record(mfti, &tftr);
2250 if (!NT_STATUS_IS_OK(status)) {
2251 TALLOC_FREE(frame);
2252 return status;
2257 * We keep old domain records disabled by the admin
2258 * if not already in the list.
2260 for (oi = 0; oi < ofti->count; oi++) {
2261 const struct lsa_ForestTrustRecord *oftr =
2262 ofti->entries[oi];
2263 const struct lsa_ForestTrustDomainInfo *od = NULL;
2264 const char *odns = NULL;
2265 const char *onbt = NULL;
2266 bool ignore_old = true;
2267 uint32_t mi;
2269 if (oftr == NULL) {
2271 * broken record => ignore...
2273 continue;
2276 if (oftr->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
2277 continue;
2280 od = &oftr->forest_trust_data.domain_info;
2281 odns = od->dns_domain_name.string;
2282 if (odns == NULL) {
2284 * broken record => ignore...
2286 continue;
2288 onbt = od->netbios_domain_name.string;
2289 if (onbt == NULL) {
2291 * broken record => ignore...
2293 continue;
2295 if (od->domain_sid == NULL) {
2297 * broken record => ignore...
2299 continue;
2302 if (oftr->flags & LSA_NB_DISABLED_ADMIN) {
2303 ignore_old = false;
2304 } else if (oftr->flags & LSA_SID_DISABLED_ADMIN) {
2305 ignore_old = false;
2308 for (mi = 0; mi < mfti->count; mi++) {
2309 const struct lsa_ForestTrustRecord *mftr =
2310 mfti->entries[mi];
2311 const struct lsa_ForestTrustDomainInfo *md = NULL;
2313 if (mftr->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
2314 continue;
2318 * we just added this above, so we're sure to have a
2319 * valid LSA_FOREST_TRUST_DOMAIN_INFO record
2321 md = &mftr->forest_trust_data.domain_info;
2323 cmp = dom_sid_compare(od->domain_sid, md->domain_sid);
2324 if (cmp == 0) {
2325 ignore_old = true;
2326 break;
2330 if (ignore_old) {
2331 continue;
2334 status = dsdb_trust_forest_info_add_record(mfti, oftr);
2335 if (!NT_STATUS_IS_OK(status)) {
2336 TALLOC_FREE(frame);
2337 return status;
2342 * Finally we readd top level exclusions,
2343 * if they still match a top level name.
2345 for (oi = 0; oi < ofti->count; oi++) {
2346 const struct lsa_ForestTrustRecord *oftr =
2347 ofti->entries[oi];
2348 const char *odns = NULL;
2349 bool ignore_old = false;
2350 uint32_t mi;
2352 if (oftr == NULL) {
2354 * broken record => ignore...
2356 continue;
2359 if (oftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX) {
2360 continue;
2363 odns = oftr->forest_trust_data.top_level_name_ex.string;
2364 if (odns == NULL) {
2366 * broken record => ignore...
2368 continue;
2371 for (mi = 0; mi < mfti->count; mi++) {
2372 const struct lsa_ForestTrustRecord *mftr =
2373 mfti->entries[mi];
2374 const char *mdns = NULL;
2376 if (mftr->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
2377 continue;
2381 * we just added this above, so we're sure to have a
2382 * valid LSA_FOREST_TRUST_TOP_LEVEL_NAME.
2384 mdns = mftr->forest_trust_data.top_level_name.string;
2386 cmp = dns_cmp(mdns, odns);
2387 switch (cmp) {
2388 case DNS_CMP_MATCH:
2389 case DNS_CMP_SECOND_IS_CHILD:
2390 break;
2391 default:
2392 ignore_old = true;
2393 break;
2396 if (ignore_old) {
2397 break;
2401 if (ignore_old) {
2402 continue;
2405 status = dsdb_trust_forest_info_add_record(mfti, oftr);
2406 if (!NT_STATUS_IS_OK(status)) {
2407 TALLOC_FREE(frame);
2408 return status;
2412 *_mfti = talloc_move(mem_ctx, &mfti);
2413 TALLOC_FREE(frame);
2414 return NT_STATUS_OK;
2417 NTSTATUS dsdb_trust_search_tdo(struct ldb_context *sam_ctx,
2418 const char *netbios, const char *dns,
2419 const char * const *attrs,
2420 TALLOC_CTX *mem_ctx,
2421 struct ldb_message **msg)
2423 TALLOC_CTX *frame = talloc_stackframe();
2424 int ret;
2425 struct ldb_dn *system_dn = NULL;
2426 char *netbios_encoded = NULL;
2427 char *dns_encoded = NULL;
2428 char *filter = NULL;
2430 *msg = NULL;
2432 if (netbios == NULL && dns == NULL) {
2433 TALLOC_FREE(frame);
2434 return NT_STATUS_INVALID_PARAMETER_MIX;
2437 system_dn = ldb_dn_copy(frame, ldb_get_default_basedn(sam_ctx));
2438 if (system_dn == NULL) {
2439 TALLOC_FREE(frame);
2440 return NT_STATUS_NO_MEMORY;
2443 if (!ldb_dn_add_child_fmt(system_dn, "CN=System")) {
2444 TALLOC_FREE(frame);
2445 return NT_STATUS_NO_MEMORY;
2448 if (netbios != NULL) {
2449 netbios_encoded = ldb_binary_encode_string(frame, netbios);
2450 if (netbios_encoded == NULL) {
2451 TALLOC_FREE(frame);
2452 return NT_STATUS_NO_MEMORY;
2456 if (dns != NULL) {
2457 dns_encoded = ldb_binary_encode_string(frame, dns);
2458 if (dns_encoded == NULL) {
2459 TALLOC_FREE(frame);
2460 return NT_STATUS_NO_MEMORY;
2464 if (netbios != NULL && dns != NULL) {
2465 filter = talloc_asprintf(frame,
2466 "(&(objectClass=trustedDomain)"
2467 "(|(trustPartner=%s)(flatName=%s))"
2468 ")",
2469 dns_encoded, netbios_encoded);
2470 if (filter == NULL) {
2471 TALLOC_FREE(frame);
2472 return NT_STATUS_NO_MEMORY;
2474 } else if (netbios != NULL) {
2475 filter = talloc_asprintf(frame,
2476 "(&(objectClass=trustedDomain)(flatName=%s))",
2477 netbios_encoded);
2478 if (filter == NULL) {
2479 TALLOC_FREE(frame);
2480 return NT_STATUS_NO_MEMORY;
2482 } else if (dns != NULL) {
2483 filter = talloc_asprintf(frame,
2484 "(&(objectClass=trustedDomain)(trustPartner=%s))",
2485 dns_encoded);
2486 if (filter == NULL) {
2487 TALLOC_FREE(frame);
2488 return NT_STATUS_NO_MEMORY;
2492 ret = dsdb_search_one(sam_ctx, mem_ctx, msg,
2493 system_dn,
2494 LDB_SCOPE_ONELEVEL, attrs,
2495 DSDB_SEARCH_NO_GLOBAL_CATALOG,
2496 "%s", filter);
2497 if (ret != LDB_SUCCESS) {
2498 NTSTATUS status = dsdb_ldb_err_to_ntstatus(ret);
2499 DEBUG(3, ("Failed to search for %s: %s - %s\n",
2500 filter, nt_errstr(status), ldb_errstring(sam_ctx)));
2501 TALLOC_FREE(frame);
2502 return status;
2505 TALLOC_FREE(frame);
2506 return NT_STATUS_OK;
2509 NTSTATUS dsdb_trust_search_tdo_by_type(struct ldb_context *sam_ctx,
2510 enum netr_SchannelType type,
2511 const char *name,
2512 const char * const *attrs,
2513 TALLOC_CTX *mem_ctx,
2514 struct ldb_message **msg)
2516 TALLOC_CTX *frame = talloc_stackframe();
2517 NTSTATUS status;
2518 size_t len;
2519 char trailer = '$';
2520 bool require_trailer = true;
2521 char *encoded_name = NULL;
2522 const char *netbios = NULL;
2523 const char *dns = NULL;
2525 if (type != SEC_CHAN_DOMAIN && type != SEC_CHAN_DNS_DOMAIN) {
2526 TALLOC_FREE(frame);
2527 return NT_STATUS_INVALID_PARAMETER;
2530 if (type == SEC_CHAN_DNS_DOMAIN) {
2531 trailer = '.';
2532 require_trailer = false;
2535 encoded_name = ldb_binary_encode_string(frame, name);
2536 if (encoded_name == NULL) {
2537 TALLOC_FREE(frame);
2538 return NT_STATUS_NO_MEMORY;
2541 len = strlen(encoded_name);
2542 if (len < 2) {
2543 TALLOC_FREE(frame);
2544 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2547 if (require_trailer && encoded_name[len - 1] != trailer) {
2548 TALLOC_FREE(frame);
2549 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2551 encoded_name[len - 1] = '\0';
2553 if (type == SEC_CHAN_DNS_DOMAIN) {
2554 dns = encoded_name;
2555 } else {
2556 netbios = encoded_name;
2559 status = dsdb_trust_search_tdo(sam_ctx, netbios, dns,
2560 attrs, mem_ctx, msg);
2561 if (!NT_STATUS_IS_OK(status)) {
2562 TALLOC_FREE(frame);
2563 return status;
2566 TALLOC_FREE(frame);
2567 return NT_STATUS_OK;
2570 NTSTATUS dsdb_trust_get_incoming_passwords(struct ldb_message *msg,
2571 TALLOC_CTX *mem_ctx,
2572 struct samr_Password **_current,
2573 struct samr_Password **_previous)
2575 TALLOC_CTX *frame = talloc_stackframe();
2576 struct samr_Password __current = {};
2577 struct samr_Password __previous = {};
2578 struct samr_Password *current = NULL;
2579 struct samr_Password *previous = NULL;
2580 const struct ldb_val *blob = NULL;
2581 enum ndr_err_code ndr_err;
2582 struct trustAuthInOutBlob incoming = {};
2583 uint32_t i;
2585 if (_current != NULL) {
2586 *_current = NULL;
2588 if (_previous != NULL) {
2589 *_previous = NULL;
2592 blob = ldb_msg_find_ldb_val(msg, "trustAuthIncoming");
2593 if (blob == NULL) {
2594 TALLOC_FREE(frame);
2595 return NT_STATUS_ACCOUNT_DISABLED;
2598 /* ldb_val is equivalent to DATA_BLOB */
2599 ndr_err = ndr_pull_struct_blob_all(blob, frame, &incoming,
2600 (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
2601 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2602 TALLOC_FREE(frame);
2603 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2606 for (i = 0; i < incoming.current.count; i++) {
2607 struct AuthenticationInformation *a =
2608 &incoming.current.array[i];
2610 if (current != NULL) {
2611 break;
2614 switch (a->AuthType) {
2615 case TRUST_AUTH_TYPE_NONE:
2616 case TRUST_AUTH_TYPE_VERSION:
2617 break;
2618 case TRUST_AUTH_TYPE_NT4OWF:
2619 current = &a->AuthInfo.nt4owf.password;
2620 break;
2621 case TRUST_AUTH_TYPE_CLEAR:
2622 mdfour(__current.hash,
2623 a->AuthInfo.clear.password,
2624 a->AuthInfo.clear.size);
2625 current = &__current;
2626 break;
2630 if (current == NULL) {
2631 TALLOC_FREE(frame);
2632 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2635 for (i = 0; i < incoming.previous.count; i++) {
2636 struct AuthenticationInformation *a =
2637 &incoming.previous.array[i];
2639 if (previous != NULL) {
2640 break;
2643 switch (a->AuthType) {
2644 case TRUST_AUTH_TYPE_NONE:
2645 case TRUST_AUTH_TYPE_VERSION:
2646 break;
2647 case TRUST_AUTH_TYPE_NT4OWF:
2648 previous = &a->AuthInfo.nt4owf.password;
2649 break;
2650 case TRUST_AUTH_TYPE_CLEAR:
2651 mdfour(__previous.hash,
2652 a->AuthInfo.clear.password,
2653 a->AuthInfo.clear.size);
2654 previous = &__previous;
2655 break;
2659 if (previous == NULL) {
2660 previous = current;
2663 if (_current != NULL) {
2664 *_current = talloc(mem_ctx, struct samr_Password);
2665 if (*_current == NULL) {
2666 TALLOC_FREE(frame);
2667 return NT_STATUS_NO_MEMORY;
2669 **_current = *current;
2671 if (_previous != NULL) {
2672 *_previous = talloc(mem_ctx, struct samr_Password);
2673 if (*_previous == NULL) {
2674 TALLOC_FREE(*_current);
2675 TALLOC_FREE(frame);
2676 return NT_STATUS_NO_MEMORY;
2678 **_previous = *previous;
2680 ZERO_STRUCTP(current);
2681 ZERO_STRUCTP(previous);
2682 TALLOC_FREE(frame);
2683 return NT_STATUS_OK;
2686 NTSTATUS dsdb_trust_search_tdos(struct ldb_context *sam_ctx,
2687 const char *exclude,
2688 const char * const *attrs,
2689 TALLOC_CTX *mem_ctx,
2690 struct ldb_result **res)
2692 TALLOC_CTX *frame = talloc_stackframe();
2693 int ret;
2694 struct ldb_dn *system_dn = NULL;
2695 const char *filter = NULL;
2696 char *exclude_encoded = NULL;
2698 *res = NULL;
2700 system_dn = ldb_dn_copy(frame, ldb_get_default_basedn(sam_ctx));
2701 if (system_dn == NULL) {
2702 TALLOC_FREE(frame);
2703 return NT_STATUS_NO_MEMORY;
2706 if (!ldb_dn_add_child_fmt(system_dn, "CN=System")) {
2707 TALLOC_FREE(frame);
2708 return NT_STATUS_NO_MEMORY;
2711 if (exclude != NULL) {
2712 exclude_encoded = ldb_binary_encode_string(frame, exclude);
2713 if (exclude_encoded == NULL) {
2714 TALLOC_FREE(frame);
2715 return NT_STATUS_NO_MEMORY;
2718 filter = talloc_asprintf(frame,
2719 "(&(objectClass=trustedDomain)"
2720 "(!(|(trustPartner=%s)(flatName=%s)))"
2721 ")",
2722 exclude_encoded, exclude_encoded);
2723 if (filter == NULL) {
2724 TALLOC_FREE(frame);
2725 return NT_STATUS_NO_MEMORY;
2727 } else {
2728 filter = "(objectClass=trustedDomain)";
2731 ret = dsdb_search(sam_ctx, mem_ctx, res,
2732 system_dn,
2733 LDB_SCOPE_ONELEVEL, attrs,
2734 DSDB_SEARCH_NO_GLOBAL_CATALOG,
2735 "%s", filter);
2736 if (ret != LDB_SUCCESS) {
2737 NTSTATUS status = dsdb_ldb_err_to_ntstatus(ret);
2738 DEBUG(3, ("Failed to search for %s: %s - %s\n",
2739 filter, nt_errstr(status), ldb_errstring(sam_ctx)));
2740 TALLOC_FREE(frame);
2741 return status;
2744 TALLOC_FREE(frame);
2745 return NT_STATUS_OK;
2748 struct dsdb_trust_routing_domain;
2750 struct dsdb_trust_routing_table {
2751 struct dsdb_trust_routing_domain *domains;
2754 struct dsdb_trust_routing_domain {
2755 struct dsdb_trust_routing_domain *prev, *next;
2757 struct lsa_TrustDomainInfoInfoEx *tdo;
2758 struct lsa_ForestTrustInformation *fti;
2761 NTSTATUS dsdb_trust_routing_table_load(struct ldb_context *sam_ctx,
2762 TALLOC_CTX *mem_ctx,
2763 struct dsdb_trust_routing_table **_table)
2765 TALLOC_CTX *frame = talloc_stackframe();
2766 struct dsdb_trust_routing_table *table;
2767 struct dsdb_trust_routing_domain *d = NULL;
2768 struct ldb_dn *domain_dn = NULL;
2769 struct lsa_TrustDomainInfoInfoEx *root_trust_tdo = NULL;
2770 struct lsa_TrustDomainInfoInfoEx *trust_parent_tdo = NULL;
2771 struct lsa_TrustDomainInfoInfoEx *root_direction_tdo = NULL;
2772 const char * const trusts_attrs[] = {
2773 "securityIdentifier",
2774 "flatName",
2775 "trustPartner",
2776 "trustAttributes",
2777 "trustDirection",
2778 "trustType",
2779 "msDS-TrustForestTrustInfo",
2780 NULL
2782 struct ldb_result *trusts_res = NULL;
2783 unsigned int i;
2784 NTSTATUS status;
2786 *_table = NULL;
2788 domain_dn = ldb_get_default_basedn(sam_ctx);
2789 if (domain_dn == NULL) {
2790 TALLOC_FREE(frame);
2791 return NT_STATUS_INTERNAL_ERROR;
2794 table = talloc_zero(mem_ctx, struct dsdb_trust_routing_table);
2795 if (table == NULL) {
2796 TALLOC_FREE(frame);
2797 return NT_STATUS_NO_MEMORY;
2799 talloc_steal(frame, table);
2801 d = talloc_zero(table, struct dsdb_trust_routing_domain);
2802 if (d == NULL) {
2803 TALLOC_FREE(frame);
2804 return NT_STATUS_NO_MEMORY;
2807 status = dsdb_trust_crossref_tdo_info(d, sam_ctx,
2808 domain_dn, NULL,
2809 &d->tdo,
2810 &root_trust_tdo,
2811 &trust_parent_tdo);
2812 if (!NT_STATUS_IS_OK(status)) {
2813 TALLOC_FREE(frame);
2814 return status;
2817 if (root_trust_tdo != NULL) {
2818 root_direction_tdo = root_trust_tdo;
2819 } else if (trust_parent_tdo != NULL) {
2820 root_direction_tdo = trust_parent_tdo;
2823 if (root_direction_tdo == NULL) {
2824 /* we're the forest root */
2825 status = dsdb_trust_xref_forest_info(d, sam_ctx, &d->fti);
2826 if (!NT_STATUS_IS_OK(status)) {
2827 TALLOC_FREE(frame);
2828 return status;
2832 DLIST_ADD(table->domains, d);
2834 status = dsdb_trust_search_tdos(sam_ctx, NULL, trusts_attrs,
2835 frame, &trusts_res);
2836 if (!NT_STATUS_IS_OK(status)) {
2837 TALLOC_FREE(frame);
2838 return status;
2841 for (i = 0; i < trusts_res->count; i++) {
2842 bool ok;
2843 int cmp;
2845 d = talloc_zero(table, struct dsdb_trust_routing_domain);
2846 if (d == NULL) {
2847 TALLOC_FREE(frame);
2848 return NT_STATUS_NO_MEMORY;
2851 status = dsdb_trust_parse_tdo_info(d,
2852 trusts_res->msgs[i],
2853 &d->tdo);
2854 if (!NT_STATUS_IS_OK(status)) {
2855 TALLOC_FREE(frame);
2856 return status;
2859 DLIST_ADD_END(table->domains, d, NULL);
2861 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
2862 struct ForestTrustInfo *fti = NULL;
2864 status = dsdb_trust_parse_forest_info(frame,
2865 trusts_res->msgs[i],
2866 &fti);
2867 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2868 fti = NULL;
2869 status = NT_STATUS_OK;
2871 if (!NT_STATUS_IS_OK(status)) {
2872 TALLOC_FREE(frame);
2873 return status;
2876 if (fti == NULL) {
2877 continue;
2880 status = dsdb_trust_forest_info_to_lsa(d, fti, &d->fti);
2881 if (!NT_STATUS_IS_OK(status)) {
2882 TALLOC_FREE(frame);
2883 return status;
2886 continue;
2889 if (!(d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST)) {
2890 continue;
2893 if (root_direction_tdo == NULL) {
2894 continue;
2897 ok = dom_sid_equal(root_direction_tdo->sid, d->tdo->sid);
2898 if (!ok) {
2899 continue;
2902 cmp = strcasecmp_m(root_direction_tdo->netbios_name.string,
2903 d->tdo->netbios_name.string);
2904 if (cmp != 0) {
2905 continue;
2908 cmp = strcasecmp_m(root_direction_tdo->domain_name.string,
2909 d->tdo->domain_name.string);
2910 if (cmp != 0) {
2911 continue;
2914 /* this our route to the forest root */
2915 status = dsdb_trust_xref_forest_info(d, sam_ctx, &d->fti);
2916 if (!NT_STATUS_IS_OK(status)) {
2917 TALLOC_FREE(frame);
2918 return status;
2922 *_table = talloc_move(mem_ctx, &table);
2923 TALLOC_FREE(frame);
2924 return NT_STATUS_OK;
2927 static void dsdb_trust_update_best_tln(
2928 const struct dsdb_trust_routing_domain **best_d,
2929 const char **best_tln,
2930 const struct dsdb_trust_routing_domain *d,
2931 const char *tln)
2933 int cmp;
2935 if (*best_tln == NULL) {
2936 *best_tln = tln;
2937 *best_d = d;
2938 return;
2941 cmp = dns_cmp(*best_tln, tln);
2942 if (cmp != DNS_CMP_FIRST_IS_CHILD) {
2943 return;
2946 *best_tln = tln;
2947 *best_d = d;
2950 const struct lsa_TrustDomainInfoInfoEx *dsdb_trust_routing_by_name(
2951 const struct dsdb_trust_routing_table *table,
2952 const char *name)
2954 const struct dsdb_trust_routing_domain *best_d = NULL;
2955 const char *best_tln = NULL;
2956 const struct dsdb_trust_routing_domain *d = NULL;
2958 if (name == NULL) {
2959 return NULL;
2962 for (d = table->domains; d != NULL; d = d->next) {
2963 bool transitive = false;
2964 bool allow_netbios = false;
2965 bool exclude = false;
2966 uint32_t i;
2968 if (d->tdo->trust_type != LSA_TRUST_TYPE_UPLEVEL) {
2970 * Only uplevel trusts have top level names
2972 continue;
2975 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
2976 transitive = true;
2979 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
2980 transitive = true;
2983 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE) {
2984 transitive = false;
2987 if (d->tdo->trust_type != LSA_TRUST_TYPE_UPLEVEL) {
2988 transitive = false;
2991 switch (d->tdo->trust_type) {
2992 case LSA_TRUST_TYPE_UPLEVEL:
2993 if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_UPLEVEL_ONLY) {
2994 break;
2996 allow_netbios = true;
2997 break;
2998 case LSA_TRUST_TYPE_DOWNLEVEL:
2999 allow_netbios = true;
3000 break;
3001 default:
3002 allow_netbios = false;
3003 break;
3006 if (!transitive || d->fti == NULL) {
3007 int cmp;
3009 if (allow_netbios) {
3010 cmp = dns_cmp(name, d->tdo->netbios_name.string);
3011 if (cmp == DNS_CMP_MATCH) {
3013 * exact match
3015 return d->tdo;
3019 cmp = dns_cmp(name, d->tdo->domain_name.string);
3020 if (cmp == DNS_CMP_MATCH) {
3022 * exact match
3024 return d->tdo;
3026 if (cmp != DNS_CMP_FIRST_IS_CHILD) {
3027 continue;
3030 if (!transitive) {
3031 continue;
3034 dsdb_trust_update_best_tln(&best_d, &best_tln, d,
3035 d->tdo->domain_name.string);
3036 continue;
3039 exclude = dsdb_trust_find_tln_ex_match(d->fti, name);
3040 if (exclude) {
3041 continue;
3044 for (i = 0; i < d->fti->count; i++ ) {
3045 const struct lsa_ForestTrustRecord *f = d->fti->entries[i];
3046 const struct lsa_ForestTrustDomainInfo *di = NULL;
3047 const char *fti_nbt = NULL;
3048 int cmp;
3050 if (!allow_netbios) {
3051 break;
3054 if (f == NULL) {
3055 /* broken record */
3056 continue;
3059 if (f->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
3060 continue;
3063 if (f->flags & LSA_NB_DISABLED_MASK) {
3065 * any flag disables the entry.
3067 continue;
3070 di = &f->forest_trust_data.domain_info;
3071 fti_nbt = di->netbios_domain_name.string;
3072 if (fti_nbt == NULL) {
3073 /* broken record */
3074 continue;
3077 cmp = dns_cmp(name, fti_nbt);
3078 if (cmp == DNS_CMP_MATCH) {
3080 * exact match
3082 return d->tdo;
3086 for (i = 0; i < d->fti->count; i++ ) {
3087 const struct lsa_ForestTrustRecord *f = d->fti->entries[i];
3088 const union lsa_ForestTrustData *u = NULL;
3089 const char *fti_tln = NULL;
3090 int cmp;
3092 if (f == NULL) {
3093 /* broken record */
3094 continue;
3097 if (f->type != LSA_FOREST_TRUST_TOP_LEVEL_NAME) {
3098 continue;
3101 if (f->flags & LSA_TLN_DISABLED_MASK) {
3103 * any flag disables the entry.
3105 continue;
3108 u = &f->forest_trust_data;
3109 fti_tln = u->top_level_name.string;
3110 if (fti_tln == NULL) {
3111 continue;
3114 cmp = dns_cmp(name, fti_tln);
3115 switch (cmp) {
3116 case DNS_CMP_MATCH:
3117 case DNS_CMP_FIRST_IS_CHILD:
3118 dsdb_trust_update_best_tln(&best_d, &best_tln,
3119 d, fti_tln);
3120 break;
3121 default:
3122 break;
3127 if (best_d != NULL) {
3128 return best_d->tdo;
3131 return NULL;