2 Unix SMB/CIFS implementation.
6 Copyright (C) CrÃstian Deives 2010
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "dsdb/samdb/samdb.h"
25 #include "lib/messaging/irpc.h"
26 #include "librpc/gen_ndr/ndr_misc.h"
28 #define FLAG_CR_NTDS_DOMAIN 0x00000002
30 #define NTDSSETTINGS_OPT_W2K3_BRIDGES_REQUIRED 0x00001000
32 #define NTDSTRANSPORT_OPT_BRIDGES_REQUIRED 0x00000002
34 /** replication parameters of a graph edge */
35 struct kcctpl_repl_info
{
42 /** color of a vertex */
43 enum kcctpl_color
{ RED
, BLACK
, WHITE
};
45 /** a GUID array list */
51 /** a vertex in the site graph */
52 struct kcctpl_vertex
{
54 struct GUID_list edge_ids
;
55 enum kcctpl_color color
;
56 struct GUID_list accept_red_red
;
57 struct GUID_list accept_black
;
58 struct kcctpl_repl_info repl_info
;
66 struct GUID component_id
;
67 uint32_t component_index
;
70 /** fully connected subgraph of vertices */
71 struct kcctpl_multi_edge
{
73 struct GUID_list vertex_ids
;
75 struct kcctpl_repl_info repl_info
;
79 /** set of transitively connected kcc_multi_edge's. all edges within the set
80 * have the same type. */
81 struct kcctpl_multi_edge_set
{
83 struct GUID_list edge_ids
;
86 /** a vertices array list */
87 struct kcctpl_vertex_list
{
88 struct kcctpl_vertex
*data
;
92 /** an edges array list */
93 struct kcctpl_multi_edge_list
{
94 struct kcctpl_multi_edge
*data
;
98 /** an edge sets array list */
99 struct kcctpl_multi_edge_set_list
{
100 struct kcctpl_multi_edge_set
*data
;
105 struct kcctpl_graph
{
106 struct kcctpl_vertex_list vertices
;
107 struct kcctpl_multi_edge_list edges
;
108 struct kcctpl_multi_edge_set_list edge_sets
;
111 /** path found in the graph between two non-white vertices */
112 struct kcctpl_internal_edge
{
116 struct kcctpl_repl_info repl_info
;
120 /** an internal edges array list */
121 struct kcctpl_internal_edge_list
{
122 struct kcctpl_internal_edge
*data
;
126 /** an LDB messages array list */
127 struct message_list
{
128 struct ldb_message
*data
;
133 * find a graph vertex based on its GUID.
135 static struct kcctpl_vertex
*kcctpl_find_vertex_by_guid(struct kcctpl_graph
*graph
,
140 for (i
= 0; i
< graph
->vertices
.count
; i
++) {
141 if (GUID_equal(&graph
->vertices
.data
[i
].id
, &guid
)) {
142 return &graph
->vertices
.data
[i
];
150 * find a graph edge based on its GUID.
152 static struct kcctpl_multi_edge
*kcctpl_find_edge_by_guid(struct kcctpl_graph
*graph
,
157 for (i
= 0; i
< graph
->edges
.count
; i
++) {
158 if (GUID_equal(&graph
->edges
.data
[i
].id
, &guid
)) {
159 return &graph
->edges
.data
[i
];
167 * find a graph edge that contains a vertex with the specified GUID. the first
168 * occurrence will be returned.
170 static struct kcctpl_multi_edge
*kcctpl_find_edge_by_vertex_guid(struct kcctpl_graph
*graph
,
175 for (i
= 0; i
< graph
->edges
.count
; i
++) {
176 struct kcctpl_multi_edge
*edge
;
179 edge
= &graph
->edges
.data
[i
];
181 for (j
= 0; j
< edge
->vertex_ids
.count
; j
++) {
182 struct GUID vertex_guid
= edge
->vertex_ids
.data
[j
];
184 struct GUID
*p
= &guid
;
186 if (GUID_equal(&vertex_guid
, p
)) {
196 * get the Transports DN
197 * (CN=Inter-Site Transports,CN=Sites,CN=Configuration,DC=<domain>).
199 static struct ldb_dn
*kcctpl_transports_dn(struct ldb_context
*ldb
,
202 struct ldb_dn
*sites_dn
;
205 sites_dn
= samdb_sites_dn(ldb
, mem_ctx
);
210 ok
= ldb_dn_add_child_fmt(sites_dn
, "CN=Inter-Site Transports");
212 talloc_free(sites_dn
);
219 * get the domain local site object.
221 static struct ldb_message
*kcctpl_local_site(struct ldb_context
*ldb
,
226 struct ldb_dn
*sites_dn
;
227 struct ldb_result
*res
;
228 const char * const attrs
[] = { "objectGUID", "options", NULL
};
230 tmp_ctx
= talloc_new(ldb
);
232 sites_dn
= samdb_sites_dn(ldb
, tmp_ctx
);
234 talloc_free(tmp_ctx
);
238 ret
= ldb_search(ldb
, tmp_ctx
, &res
, sites_dn
, LDB_SCOPE_SUBTREE
, attrs
,
241 if (ret
!= LDB_SUCCESS
|| res
->count
== 0) {
242 talloc_free(tmp_ctx
);
246 talloc_steal(mem_ctx
, res
);
247 talloc_free(tmp_ctx
);
252 * create a kcctpl_graph instance.
254 static NTSTATUS
kcctpl_create_graph(TALLOC_CTX
*mem_ctx
,
255 struct GUID_list guids
,
256 struct kcctpl_graph
**_graph
)
258 struct kcctpl_graph
*graph
;
261 graph
= talloc_zero(mem_ctx
, struct kcctpl_graph
);
262 NT_STATUS_HAVE_NO_MEMORY(graph
);
264 graph
->vertices
.count
= guids
.count
;
265 graph
->vertices
.data
= talloc_zero_array(graph
, struct kcctpl_vertex
,
267 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(graph
->vertices
.data
, graph
);
269 TYPESAFE_QSORT(guids
.data
, guids
.count
, GUID_compare
);
271 for (i
= 0; i
< guids
.count
; i
++) {
272 graph
->vertices
.data
[i
].id
= guids
.data
[i
];
280 * create a kcctpl_multi_edge instance.
282 static NTSTATUS
kcctpl_create_edge(struct ldb_context
*ldb
, TALLOC_CTX
*mem_ctx
,
284 struct ldb_message
*site_link
,
285 struct kcctpl_multi_edge
**_edge
)
287 struct kcctpl_multi_edge
*edge
;
289 struct ldb_dn
*sites_dn
;
290 struct ldb_result
*res
;
291 const char * const attrs
[] = { "siteList", NULL
};
293 struct ldb_message_element
*el
;
297 tmp_ctx
= talloc_new(mem_ctx
);
298 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
300 edge
= talloc_zero(tmp_ctx
, struct kcctpl_multi_edge
);
301 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(edge
, tmp_ctx
);
303 edge
->id
= samdb_result_guid(site_link
, "objectGUID");
305 sites_dn
= samdb_sites_dn(ldb
, tmp_ctx
);
307 DEBUG(1, (__location__
": failed to find our own Sites DN\n"));
309 talloc_free(tmp_ctx
);
310 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
313 ret
= ldb_search(ldb
, tmp_ctx
, &res
, sites_dn
, LDB_SCOPE_SUBTREE
, attrs
,
314 "objectGUID=%s", GUID_string(tmp_ctx
, &edge
->id
));
315 if (ret
!= LDB_SUCCESS
) {
316 DEBUG(1, (__location__
": failed to find siteLink object %s: "
317 "%s\n", GUID_string(tmp_ctx
, &edge
->id
),
320 talloc_free(tmp_ctx
);
321 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
323 if (res
->count
== 0) {
324 DEBUG(1, (__location__
": failed to find siteLink object %s\n",
325 GUID_string(tmp_ctx
, &edge
->id
)));
327 talloc_free(tmp_ctx
);
328 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
331 el
= ldb_msg_find_element(res
->msgs
[0], "siteList");
333 DEBUG(1, (__location__
": failed to find siteList attribute of "
335 ldb_dn_get_linearized(res
->msgs
[0]->dn
)));
337 talloc_free(tmp_ctx
);
338 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
341 edge
->vertex_ids
.data
= talloc_array(edge
, struct GUID
, el
->num_values
);
342 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(edge
->vertex_ids
.data
, tmp_ctx
);
343 edge
->vertex_ids
.count
= el
->num_values
;
345 for (i
= 0; i
< el
->num_values
; i
++) {
350 dn
= ldb_dn_from_ldb_val(tmp_ctx
, ldb
, &val
);
352 DEBUG(1, (__location__
": failed to read a DN from "
353 "siteList attribute of %s\n",
354 ldb_dn_get_linearized(res
->msgs
[0]->dn
)));
356 talloc_free(tmp_ctx
);
357 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
359 ret
= dsdb_find_guid_by_dn(ldb
, dn
, &guid
);
360 if (ret
!= LDB_SUCCESS
) {
361 DEBUG(1, (__location__
": failed to find objectGUID "
362 "for object %s: %s\n",
363 ldb_dn_get_linearized(dn
),
366 talloc_free(tmp_ctx
);
367 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
370 edge
->vertex_ids
.data
[i
] = guid
;
373 edge
->repl_info
.cost
= samdb_result_int64(site_link
, "cost", 0);
374 edge
->repl_info
.options
= samdb_result_int64(site_link
, "options", 0);
375 edge
->repl_info
.interval
= samdb_result_int64(site_link
,
377 /* TODO: edge->repl_info.schedule = site_link!schedule */
379 edge
->directed
= false;
381 *_edge
= talloc_steal(mem_ctx
, edge
);
382 talloc_free(tmp_ctx
);
387 * create a kcctpl_multi_edge_set instance containing edges for all siteLink
390 static NTSTATUS
kcctpl_create_auto_edge_set(struct kcctpl_graph
*graph
,
392 struct ldb_result
*res_site_link
,
393 struct kcctpl_multi_edge_set
**_set
)
395 struct kcctpl_multi_edge_set
*set
;
399 tmp_ctx
= talloc_new(graph
);
400 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
402 set
= talloc_zero(tmp_ctx
, struct kcctpl_multi_edge_set
);
403 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set
, tmp_ctx
);
405 for (i
= 0; i
< res_site_link
->count
; i
++) {
406 struct GUID site_link_guid
;
407 struct kcctpl_multi_edge
*edge
;
409 site_link_guid
= samdb_result_guid(res_site_link
->msgs
[i
],
411 edge
= kcctpl_find_edge_by_guid(graph
, site_link_guid
);
413 DEBUG(1, (__location__
": failed to find a graph edge "
415 GUID_string(tmp_ctx
, &site_link_guid
)));
417 talloc_free(tmp_ctx
);
418 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
421 if (GUID_equal(&edge
->type
, &type
)) {
422 struct GUID
*new_data
;
424 new_data
= talloc_realloc(set
, set
->edge_ids
.data
,
426 set
->edge_ids
.count
+ 1);
427 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(new_data
, tmp_ctx
);
428 new_data
[set
->edge_ids
.count
] = site_link_guid
;
429 set
->edge_ids
.data
= new_data
;
430 set
->edge_ids
.count
++;
434 *_set
= talloc_steal(graph
, set
);
439 * create a kcctpl_multi_edge_set instance.
441 static NTSTATUS
kcctpl_create_edge_set(struct ldb_context
*ldb
,
442 struct kcctpl_graph
*graph
,
444 struct ldb_message
*bridge
,
445 struct kcctpl_multi_edge_set
**_set
)
447 struct kcctpl_multi_edge_set
*set
;
449 struct ldb_message_element
*el
;
452 tmp_ctx
= talloc_new(ldb
);
453 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
455 set
= talloc_zero(tmp_ctx
, struct kcctpl_multi_edge_set
);
456 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set
, tmp_ctx
);
458 set
->id
= samdb_result_guid(bridge
, "objectGUID");
460 el
= ldb_msg_find_element(bridge
, "siteLinkList");
462 DEBUG(1, (__location__
": failed to find siteLinkList "
463 "attribute of object %s\n",
464 ldb_dn_get_linearized(bridge
->dn
)));
466 talloc_free(tmp_ctx
);
467 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
469 for (i
= 0; i
< el
->num_values
; i
++) {
472 struct GUID site_link_guid
;
474 struct kcctpl_multi_edge
*edge
;
477 dn
= ldb_dn_from_ldb_val(tmp_ctx
, ldb
, &val
);
479 DEBUG(1, (__location__
": failed to read a DN from "
480 "siteList attribute of %s\n",
481 ldb_dn_get_linearized(bridge
->dn
)));
483 talloc_free(tmp_ctx
);
484 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
487 ret
= dsdb_find_guid_by_dn(ldb
, dn
, &site_link_guid
);
488 if (ret
!= LDB_SUCCESS
) {
489 DEBUG(1, (__location__
": failed to find objectGUID "
490 "for object %s: %s\n",
491 ldb_dn_get_linearized(dn
),
494 talloc_free(tmp_ctx
);
495 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
498 edge
= kcctpl_find_edge_by_guid(graph
, site_link_guid
);
500 DEBUG(1, (__location__
": failed to find a graph edge "
502 GUID_string(tmp_ctx
, &site_link_guid
)));
504 talloc_free(tmp_ctx
);
505 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
508 if (GUID_equal(&edge
->type
, &type
)) {
509 struct GUID
*new_data
;
511 new_data
= talloc_realloc(set
, set
->edge_ids
.data
,
513 set
->edge_ids
.count
+ 1);
514 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(new_data
, tmp_ctx
);
515 new_data
[set
->edge_ids
.count
] = site_link_guid
;
516 set
->edge_ids
.data
= new_data
;
517 set
->edge_ids
.count
++;
521 *_set
= talloc_steal(graph
, set
);
522 talloc_free(tmp_ctx
);
527 * set up a kcctpl_graph, populated with a kcctpl_vertex for each site object, a
528 * kcctpl_multi_edge for each siteLink object, and a kcctpl_multi_edge_set for
529 * each siteLinkBridge object (or implied siteLinkBridge).
531 static NTSTATUS
kcctpl_setup_graph(struct ldb_context
*ldb
, TALLOC_CTX
*mem_ctx
,
532 struct kcctpl_graph
**_graph
)
534 struct kcctpl_graph
*graph
;
535 struct ldb_dn
*sites_dn
, *transports_dn
;
537 struct ldb_result
*res
;
538 const char * const transport_attrs
[] = { "objectGUID", NULL
};
539 const char * const site_attrs
[] = { "objectGUID", "options", NULL
};
540 const char * const attrs
[] = { "objectGUID", "cost", "options",
541 "replInterval", "schedule", NULL
};
542 const char * const site_link_bridge_attrs
[] = { "objectGUID",
546 struct GUID_list vertex_ids
;
549 struct ldb_message
*site
;
552 tmp_ctx
= talloc_new(mem_ctx
);
553 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
555 sites_dn
= samdb_sites_dn(ldb
, tmp_ctx
);
557 DEBUG(1, (__location__
": failed to find our own Sites DN\n"));
559 talloc_free(tmp_ctx
);
560 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
563 ret
= ldb_search(ldb
, tmp_ctx
, &res
, sites_dn
, LDB_SCOPE_SUBTREE
,
564 site_attrs
, "objectClass=site");
565 if (ret
!= LDB_SUCCESS
) {
566 DEBUG(1, (__location__
": failed to find site objects under "
567 "%s: %s\n", ldb_dn_get_linearized(sites_dn
),
570 talloc_free(tmp_ctx
);
571 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
574 ZERO_STRUCT(vertex_ids
);
575 for (i
= 0; i
< res
->count
; i
++) {
576 struct GUID guid
, *new_data
;
578 guid
= samdb_result_guid(res
->msgs
[i
], "objectGUID");
580 new_data
= talloc_realloc(tmp_ctx
, vertex_ids
.data
, struct GUID
,
581 vertex_ids
.count
+ 1);
582 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(new_data
, tmp_ctx
);
583 new_data
[vertex_ids
.count
] = guid
;
584 vertex_ids
.data
= new_data
;
588 status
= kcctpl_create_graph(tmp_ctx
, vertex_ids
, &graph
);
589 if (NT_STATUS_IS_ERR(status
)) {
590 DEBUG(1, (__location__
": failed to create graph: %s\n",
593 talloc_free(tmp_ctx
);
597 site
= kcctpl_local_site(ldb
, tmp_ctx
);
599 DEBUG(1, (__location__
": failed to find our own local DC's "
602 talloc_free(tmp_ctx
);
603 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
605 site_opts
= samdb_result_int64(site
, "options", 0);
607 transports_dn
= kcctpl_transports_dn(ldb
, tmp_ctx
);
608 if (!transports_dn
) {
609 DEBUG(1, (__location__
": failed to find our own Inter-Site "
612 talloc_free(tmp_ctx
);
613 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
616 ret
= ldb_search(ldb
, tmp_ctx
, &res
, transports_dn
, LDB_SCOPE_ONELEVEL
,
617 transport_attrs
, "objectClass=interSiteTransport");
618 if (ret
!= LDB_SUCCESS
) {
619 DEBUG(1, (__location__
": failed to find interSiteTransport "
620 "objects under %s: %s\n",
621 ldb_dn_get_linearized(transports_dn
),
624 talloc_free(tmp_ctx
);
625 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
628 for (i
= 0; i
< res
->count
; i
++) {
629 struct ldb_message
*transport
;
630 struct ldb_result
*res_site_link
;
631 struct GUID transport_guid
;
633 uint64_t transport_opts
;
635 transport
= res
->msgs
[i
];
637 ret
= ldb_search(ldb
, tmp_ctx
, &res_site_link
, transport
->dn
,
638 LDB_SCOPE_SUBTREE
, attrs
,
639 "objectClass=siteLink");
640 if (ret
!= LDB_SUCCESS
) {
641 DEBUG(1, (__location__
": failed to find siteLink "
642 "objects under %s: %s\n",
643 ldb_dn_get_linearized(transport
->dn
),
646 talloc_free(tmp_ctx
);
647 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
650 transport_guid
= samdb_result_guid(transport
, "objectGUID");
651 for (j
= 0; j
< res_site_link
->count
; j
++) {
652 struct kcctpl_multi_edge
*edge
, *new_data
;
654 status
= kcctpl_create_edge(ldb
, graph
, transport_guid
,
655 res_site_link
->msgs
[j
],
657 if (NT_STATUS_IS_ERR(status
)) {
658 DEBUG(1, (__location__
": failed to create "
659 "edge: %s\n", nt_errstr(status
)));
660 talloc_free(tmp_ctx
);
664 new_data
= talloc_realloc(graph
, graph
->edges
.data
,
665 struct kcctpl_multi_edge
,
666 graph
->edges
.count
+ 1);
667 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(new_data
, tmp_ctx
);
668 new_data
[graph
->edges
.count
] = *edge
;
669 graph
->edges
.data
= new_data
;
670 graph
->edges
.count
++;
673 transport_opts
= samdb_result_int64(transport
, "options", 0);
674 if (!(transport_opts
& NTDSTRANSPORT_OPT_BRIDGES_REQUIRED
) &&
675 !(site_opts
& NTDSSETTINGS_OPT_W2K3_BRIDGES_REQUIRED
)) {
676 struct kcctpl_multi_edge_set
*edge_set
, *new_data
;
678 status
= kcctpl_create_auto_edge_set(graph
,
682 if (NT_STATUS_IS_ERR(status
)) {
683 DEBUG(1, (__location__
": failed to create "
684 "edge set: %s\n", nt_errstr(status
)));
685 talloc_free(tmp_ctx
);
689 new_data
= talloc_realloc(graph
, graph
->edge_sets
.data
,
690 struct kcctpl_multi_edge_set
,
691 graph
->edge_sets
.count
+ 1);
692 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(new_data
, tmp_ctx
);
693 new_data
[graph
->edge_sets
.count
] = *edge_set
;
694 graph
->edge_sets
.data
= new_data
;
695 graph
->edge_sets
.count
++;
697 ret
= ldb_search(ldb
, tmp_ctx
, &res_site_link
,
698 transport
->dn
, LDB_SCOPE_SUBTREE
,
699 site_link_bridge_attrs
,
700 "objectClass=siteLinkBridge");
701 if (ret
!= LDB_SUCCESS
) {
702 DEBUG(1, (__location__
": failed to find "
703 "siteLinkBridge objects under %s: "
705 ldb_dn_get_linearized(transport
->dn
),
708 talloc_free(tmp_ctx
);
709 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
712 for (j
= 0; j
< res_site_link
->count
; j
++) {
713 struct ldb_message
*bridge
;
714 struct kcctpl_multi_edge_set
*edge_set
,
717 bridge
= res_site_link
->msgs
[j
];
718 status
= kcctpl_create_edge_set(ldb
, graph
,
722 if (NT_STATUS_IS_ERR(status
)) {
723 DEBUG(1, (__location__
": failed to "
724 "create edge set: %s\n",
727 talloc_free(tmp_ctx
);
731 new_data
= talloc_realloc(graph
,
732 graph
->edge_sets
.data
,
733 struct kcctpl_multi_edge_set
,
734 graph
->edge_sets
.count
+ 1);
735 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(new_data
,
737 new_data
[graph
->edge_sets
.count
] = *edge_set
;
738 graph
->edge_sets
.data
= new_data
;
739 graph
->edge_sets
.count
++;
744 *_graph
= talloc_steal(mem_ctx
, graph
);
745 talloc_free(tmp_ctx
);
750 * get a bridgehead DC.
752 static NTSTATUS
kcctpl_get_bridgehead_dc(struct ldb_context
*ldb
,
754 struct GUID site_guid
,
755 struct ldb_message
*cross_ref
,
756 struct ldb_message
*transport
,
757 bool partial_replica_okay
,
758 bool detect_failed_dcs
,
759 struct ldb_message
**_dsa
)
765 * color each vertex to indicate which kinds of NC replicas it contains.
767 static NTSTATUS
kcctpl_color_vertices(struct ldb_context
*ldb
,
768 struct kcctpl_graph
*graph
,
769 struct ldb_message
*cross_ref
,
770 bool detect_failed_dcs
,
771 bool *_found_failed_dcs
)
774 struct ldb_dn
*sites_dn
;
775 bool found_failed_dcs
, partial_replica_okay
;
777 struct ldb_message
*site
;
778 struct ldb_result
*res
;
780 struct GUID site_guid
;
781 struct kcctpl_vertex
*site_vertex
;
783 found_failed_dcs
= false;
785 tmp_ctx
= talloc_new(ldb
);
786 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
788 sites_dn
= samdb_sites_dn(ldb
, tmp_ctx
);
790 DEBUG(1, (__location__
": failed to find our own Sites DN\n"));
792 talloc_free(tmp_ctx
);
793 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
796 for (i
= 0; i
< graph
->vertices
.count
; i
++) {
797 struct kcctpl_vertex
*vertex
;
798 struct ldb_dn
*nc_name
;
799 /* TODO: set 'attrs' with its corresponding values */
800 const char * const attrs
[] = { NULL
};
802 vertex
= &graph
->vertices
.data
[i
];
804 ret
= ldb_search(ldb
, tmp_ctx
, &res
, sites_dn
,
805 LDB_SCOPE_SUBTREE
, attrs
, "objectGUID=%s",
806 GUID_string(tmp_ctx
, &vertex
->id
));
807 if (ret
!= LDB_SUCCESS
) {
808 DEBUG(1, (__location__
": failed to find site object "
809 "%s: %s\n", GUID_string(tmp_ctx
, &vertex
->id
),
812 talloc_free(tmp_ctx
);
813 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
815 if (res
->count
== 0) {
816 DEBUG(1, (__location__
": failed to find site object "
817 "%s\n", GUID_string(tmp_ctx
, &vertex
->id
)));
819 talloc_free(tmp_ctx
);
820 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
824 nc_name
= samdb_result_dn(ldb
, tmp_ctx
, cross_ref
,
827 DEBUG(1, (__location__
": failed to find nCName "
828 "attribute of object %s\n",
829 ldb_dn_get_linearized(cross_ref
->dn
)));
831 talloc_free(tmp_ctx
);
832 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
835 if (true) { /* TODO: site contains 1+ DCs with full replicas of
838 } else if (true) { /* TODO: site contains 1+ partial replicas of
840 vertex
->color
= BLACK
;
842 vertex
->color
= WHITE
;
846 site
= kcctpl_local_site(ldb
, tmp_ctx
);
848 DEBUG(1, (__location__
": failed to find our own local DC's "
851 talloc_free(tmp_ctx
);
852 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
854 site_guid
= samdb_result_guid(site
, "objectGUID");
856 site_vertex
= kcctpl_find_vertex_by_guid(graph
, site_guid
);
858 DEBUG(1, (__location__
": failed to find a vertex edge with "
859 "GUID=%s\n", GUID_string(tmp_ctx
, &site_guid
)));
861 talloc_free(tmp_ctx
);
862 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
865 partial_replica_okay
= (site_vertex
->color
== BLACK
);
867 cr_flags
= samdb_result_int64(cross_ref
, "systemFlags", 0);
869 for (i
= 0; i
< graph
->vertices
.count
; i
++) {
870 struct kcctpl_vertex
*vertex
;
871 struct ldb_dn
*transports_dn
;
872 const char * const attrs
[] = { "objectGUID", "name",
873 "transportAddressAttribute",
877 vertex
= &graph
->vertices
.data
[i
];
879 transports_dn
= kcctpl_transports_dn(ldb
, tmp_ctx
);
880 if (!transports_dn
) {
881 DEBUG(1, (__location__
": failed to find our own "
882 "Inter-Site Transports DN\n"));
884 talloc_free(tmp_ctx
);
885 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
888 ret
= ldb_search(ldb
, tmp_ctx
, &res
, transports_dn
,
889 LDB_SCOPE_ONELEVEL
, attrs
,
890 "objectClass=interSiteTransport");
891 if (ret
!= LDB_SUCCESS
) {
892 DEBUG(1, (__location__
": failed to find "
893 "interSiteTransport objects under %s: %s\n",
894 ldb_dn_get_linearized(transports_dn
),
897 talloc_free(tmp_ctx
);
898 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
901 for (j
= 0; j
< res
->count
; j
++) {
902 struct ldb_message
*transport
, *bridgehead
;
903 const char *transport_name
;
904 struct GUID transport_guid
, *new_data
;
907 transport
= res
->msgs
[j
];
909 transport_name
= samdb_result_string(transport
,
911 if (!transport_name
) {
912 DEBUG(1, (__location__
": failed to find name "
913 "attribute of object %s\n",
914 ldb_dn_get_linearized(transport
->dn
)));
916 talloc_free(tmp_ctx
);
917 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
920 transport_guid
= samdb_result_guid(transport
,
923 if (site_vertex
->color
== RED
&&
924 strncmp(transport_name
, "IP", 2) != 0 &&
925 (cr_flags
& FLAG_CR_NTDS_DOMAIN
)) {
929 if (!kcctpl_find_edge_by_vertex_guid(graph
,
934 status
= kcctpl_get_bridgehead_dc(ldb
, tmp_ctx
,
936 cross_ref
, transport
,
937 partial_replica_okay
,
940 if (NT_STATUS_IS_ERR(status
)) {
941 DEBUG(1, (__location__
": failed to get a "
942 "bridgehead DC: %s\n",
945 talloc_free(tmp_ctx
);
949 found_failed_dcs
= true;
953 new_data
= talloc_realloc(vertex
,
954 vertex
->accept_red_red
.data
,
956 vertex
->accept_red_red
.count
+ 1);
957 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(new_data
, tmp_ctx
);
958 new_data
[vertex
->accept_red_red
.count
+ 1] = transport_guid
;
959 vertex
->accept_red_red
.data
= new_data
;
960 vertex
->accept_red_red
.count
++;
962 new_data
= talloc_realloc(vertex
,
963 vertex
->accept_black
.data
,
965 vertex
->accept_black
.count
+ 1);
966 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(new_data
, tmp_ctx
);
967 new_data
[vertex
->accept_black
.count
+ 1] = transport_guid
;
968 vertex
->accept_black
.data
= new_data
;
969 vertex
->accept_black
.count
++;
973 *_found_failed_dcs
= found_failed_dcs
;
974 talloc_free(tmp_ctx
);