new function kcctpl_color_vertices
[Samba/cd1.git] / source4 / dsdb / kcc / kcc_topology.c
blob50a1fee49b0d6c980f218964b52f0df0b6bf1350
1 /*
2 Unix SMB/CIFS implementation.
4 KCC service
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/>.
23 #include "includes.h"
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 {
36 uint32_t cost;
37 uint32_t interval;
38 uint32_t options;
39 uint8_t schedule[84];
42 /** color of a vertex */
43 enum kcctpl_color { RED, BLACK, WHITE };
45 /** a GUID array list */
46 struct GUID_list {
47 struct GUID *data;
48 uint32_t count;
51 /** a vertex in the site graph */
52 struct kcctpl_vertex {
53 struct GUID id;
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;
59 uint32_t dist_to_red;
61 /* Dijkstra data */
62 struct GUID root_id;
63 bool demoted;
65 /* Kruskal data */
66 struct GUID component_id;
67 uint32_t component_index;
70 /** fully connected subgraph of vertices */
71 struct kcctpl_multi_edge {
72 struct GUID id;
73 struct GUID_list vertex_ids;
74 struct GUID type;
75 struct kcctpl_repl_info repl_info;
76 bool directed;
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 {
82 struct GUID id;
83 struct GUID_list edge_ids;
86 /** a vertices array list */
87 struct kcctpl_vertex_list {
88 struct kcctpl_vertex *data;
89 uint32_t count;
92 /** an edges array list */
93 struct kcctpl_multi_edge_list {
94 struct kcctpl_multi_edge *data;
95 uint32_t count;
98 /** an edge sets array list */
99 struct kcctpl_multi_edge_set_list {
100 struct kcctpl_multi_edge_set *data;
101 uint32_t count;
104 /** a site graph */
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 {
113 struct GUID v1id;
114 struct GUID v2id;
115 bool red_red;
116 struct kcctpl_repl_info repl_info;
117 struct GUID type;
120 /** an internal edges array list */
121 struct kcctpl_internal_edge_list {
122 struct kcctpl_internal_edge *data;
123 uint32_t count;
126 /** an LDB messages array list */
127 struct message_list {
128 struct ldb_message *data;
129 uint32_t count;
133 * find a graph vertex based on its GUID.
135 static struct kcctpl_vertex *kcctpl_find_vertex_by_guid(struct kcctpl_graph *graph,
136 struct GUID guid)
138 uint32_t i;
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];
146 return NULL;
150 * find a graph edge based on its GUID.
152 static struct kcctpl_multi_edge *kcctpl_find_edge_by_guid(struct kcctpl_graph *graph,
153 struct GUID guid)
155 uint32_t i;
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];
163 return NULL;
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,
171 struct GUID guid)
173 uint32_t i;
175 for (i = 0; i < graph->edges.count; i++) {
176 struct kcctpl_multi_edge *edge;
177 uint32_t j;
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)) {
187 return edge;
192 return NULL;
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,
200 TALLOC_CTX *mem_ctx)
202 struct ldb_dn *sites_dn;
203 bool ok;
205 sites_dn = samdb_sites_dn(ldb, mem_ctx);
206 if (!sites_dn) {
207 return NULL;
210 ok = ldb_dn_add_child_fmt(sites_dn, "CN=Inter-Site Transports");
211 if (!ok) {
212 talloc_free(sites_dn);
213 return NULL;
216 return sites_dn;
219 * get the domain local site object.
221 static struct ldb_message *kcctpl_local_site(struct ldb_context *ldb,
222 TALLOC_CTX *mem_ctx)
224 int ret;
225 TALLOC_CTX *tmp_ctx;
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);
233 if (!sites_dn) {
234 talloc_free(tmp_ctx);
235 return NULL;
238 ret = ldb_search(ldb, tmp_ctx, &res, sites_dn, LDB_SCOPE_SUBTREE, attrs,
239 "objectClass=site");
241 if (ret != LDB_SUCCESS || res->count == 0) {
242 talloc_free(tmp_ctx);
243 return NULL;
246 talloc_steal(mem_ctx, res);
247 talloc_free(tmp_ctx);
248 return res->msgs[0];
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;
259 uint32_t i;
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,
266 guids.count);
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];
275 *_graph = graph;
276 return NT_STATUS_OK;
280 * create a kcctpl_multi_edge instance.
282 static NTSTATUS kcctpl_create_edge(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
283 struct GUID type,
284 struct ldb_message *site_link,
285 struct kcctpl_multi_edge **_edge)
287 struct kcctpl_multi_edge *edge;
288 TALLOC_CTX *tmp_ctx;
289 struct ldb_dn *sites_dn;
290 struct ldb_result *res;
291 const char * const attrs[] = { "siteList", NULL };
292 int ret;
293 struct ldb_message_element *el;
294 uint32_t i;
295 struct ldb_val val;
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);
306 if (!sites_dn) {
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),
318 ldb_strerror(ret)));
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");
332 if (!el) {
333 DEBUG(1, (__location__ ": failed to find siteList attribute of "
334 "object %s\n",
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++) {
346 struct ldb_dn *dn;
347 struct GUID guid;
349 val = el->values[i];
350 dn = ldb_dn_from_ldb_val(tmp_ctx, ldb, &val);
351 if (!dn) {
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),
364 ldb_strerror(ret)));
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,
376 "replInterval", 0);
377 /* TODO: edge->repl_info.schedule = site_link!schedule */
378 edge->type = type;
379 edge->directed = false;
381 *_edge = talloc_steal(mem_ctx, edge);
382 talloc_free(tmp_ctx);
383 return NT_STATUS_OK;
387 * create a kcctpl_multi_edge_set instance containing edges for all siteLink
388 * objects.
390 static NTSTATUS kcctpl_create_auto_edge_set(struct kcctpl_graph *graph,
391 struct GUID type,
392 struct ldb_result *res_site_link,
393 struct kcctpl_multi_edge_set **_set)
395 struct kcctpl_multi_edge_set *set;
396 TALLOC_CTX *tmp_ctx;
397 uint32_t i;
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],
410 "objectGUID");
411 edge = kcctpl_find_edge_by_guid(graph, site_link_guid);
412 if (!edge) {
413 DEBUG(1, (__location__ ": failed to find a graph edge "
414 "with ID=%s\n",
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,
425 struct GUID,
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);
435 return NT_STATUS_OK;
439 * create a kcctpl_multi_edge_set instance.
441 static NTSTATUS kcctpl_create_edge_set(struct ldb_context *ldb,
442 struct kcctpl_graph *graph,
443 struct GUID type,
444 struct ldb_message *bridge,
445 struct kcctpl_multi_edge_set **_set)
447 struct kcctpl_multi_edge_set *set;
448 TALLOC_CTX *tmp_ctx;
449 struct ldb_message_element *el;
450 uint32_t i;
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");
461 if (!el) {
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++) {
470 struct ldb_val val;
471 struct ldb_dn *dn;
472 struct GUID site_link_guid;
473 int ret;
474 struct kcctpl_multi_edge *edge;
476 val = el->values[i];
477 dn = ldb_dn_from_ldb_val(tmp_ctx, ldb, &val);
478 if (!dn) {
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),
492 ldb_strerror(ret)));
494 talloc_free(tmp_ctx);
495 return NT_STATUS_INTERNAL_DB_CORRUPTION;
498 edge = kcctpl_find_edge_by_guid(graph, site_link_guid);
499 if (!edge) {
500 DEBUG(1, (__location__ ": failed to find a graph edge "
501 "with ID=%s\n",
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,
512 struct GUID,
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);
523 return NT_STATUS_OK;
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;
536 TALLOC_CTX *tmp_ctx;
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",
543 "siteLinkList",
544 NULL };
545 int ret;
546 struct GUID_list vertex_ids;
547 uint32_t i;
548 NTSTATUS status;
549 struct ldb_message *site;
550 uint64_t site_opts;
552 tmp_ctx = talloc_new(mem_ctx);
553 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
555 sites_dn = samdb_sites_dn(ldb, tmp_ctx);
556 if (!sites_dn) {
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),
568 ldb_strerror(ret)));
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;
585 vertex_ids.count++;
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",
591 nt_errstr(status)));
593 talloc_free(tmp_ctx);
594 return status;
597 site = kcctpl_local_site(ldb, tmp_ctx);
598 if (!site) {
599 DEBUG(1, (__location__ ": failed to find our own local DC's "
600 "site\n"));
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 "
610 "Transports DN\n"));
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),
622 ldb_strerror(ret)));
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;
632 unsigned int j;
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),
644 ldb_strerror(ret)));
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],
656 &edge);
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);
661 return status;
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,
679 transport_guid,
680 res_site_link,
681 &edge_set);
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);
686 return status;
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++;
696 } else {
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: "
704 "%s\n",
705 ldb_dn_get_linearized(transport->dn),
706 ldb_strerror(ret)));
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,
715 *new_data;
717 bridge = res_site_link->msgs[j];
718 status = kcctpl_create_edge_set(ldb, graph,
719 transport_guid,
720 bridge,
721 &edge_set);
722 if (NT_STATUS_IS_ERR(status)) {
723 DEBUG(1, (__location__ ": failed to "
724 "create edge set: %s\n",
725 nt_errstr(status)));
727 talloc_free(tmp_ctx);
728 return status;
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,
736 tmp_ctx);
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);
746 return NT_STATUS_OK;
750 * get a bridgehead DC.
752 static NTSTATUS kcctpl_get_bridgehead_dc(struct ldb_context *ldb,
753 TALLOC_CTX *mem_ctx,
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)
761 return NT_STATUS_OK;
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)
773 TALLOC_CTX *tmp_ctx;
774 struct ldb_dn *sites_dn;
775 bool found_failed_dcs, partial_replica_okay;
776 uint32_t i;
777 struct ldb_message *site;
778 struct ldb_result *res;
779 int ret, cr_flags;
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);
789 if (!sites_dn) {
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),
810 ldb_strerror(ret)));
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;
822 site = res->msgs[0];
824 nc_name = samdb_result_dn(ldb, tmp_ctx, cross_ref,
825 "nCName", NULL);
826 if (!nc_name) {
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
836 'nc_name' */
837 vertex->color = RED;
838 } else if (true) { /* TODO: site contains 1+ partial replicas of
839 'nc_name' */
840 vertex->color = BLACK;
841 } else {
842 vertex->color = WHITE;
846 site = kcctpl_local_site(ldb, tmp_ctx);
847 if (!site) {
848 DEBUG(1, (__location__ ": failed to find our own local DC's "
849 "site\n"));
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);
857 if (!site_vertex) {
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",
874 NULL };
875 uint32_t j;
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),
895 ldb_strerror(ret)));
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;
905 NTSTATUS status;
907 transport = res->msgs[j];
909 transport_name = samdb_result_string(transport,
910 "name", NULL);
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,
921 "objectGUID");
923 if (site_vertex->color == RED &&
924 strncmp(transport_name, "IP", 2) != 0 &&
925 (cr_flags & FLAG_CR_NTDS_DOMAIN)) {
926 continue;
929 if (!kcctpl_find_edge_by_vertex_guid(graph,
930 vertex->id)) {
931 continue;
934 status = kcctpl_get_bridgehead_dc(ldb, tmp_ctx,
935 site_vertex->id,
936 cross_ref, transport,
937 partial_replica_okay,
938 detect_failed_dcs,
939 &bridgehead);
940 if (NT_STATUS_IS_ERR(status)) {
941 DEBUG(1, (__location__ ": failed to get a "
942 "bridgehead DC: %s\n",
943 nt_errstr(status)));
945 talloc_free(tmp_ctx);
946 return status;
948 if (!bridgehead) {
949 found_failed_dcs = true;
950 continue;
953 new_data = talloc_realloc(vertex,
954 vertex->accept_red_red.data,
955 struct GUID,
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,
964 struct GUID,
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);
975 return NT_STATUS_OK;