summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/dsdb/kcc/kcc_periodic.c150
1 files changed, 147 insertions, 3 deletions
diff --git a/source4/dsdb/kcc/kcc_periodic.c b/source4/dsdb/kcc/kcc_periodic.c
index 2654f9f2d9..d9a716f61f 100644
--- a/source4/dsdb/kcc/kcc_periodic.c
+++ b/source4/dsdb/kcc/kcc_periodic.c
@@ -35,6 +35,7 @@
#include "librpc/gen_ndr/ndr_drsblobs.h"
#include "librpc/gen_ndr/ndr_irpc_c.h"
#include "param/param.h"
+#include "dsdb/common/util.h"
/*
* see if two repsFromToBlob blobs are for the same source DSA
@@ -309,6 +310,145 @@ NTSTATUS kccsrv_add_repsFrom(struct kccsrv_service *s, TALLOC_CTX *mem_ctx,
}
+
+/*
+ form a unique list of DNs from a search result and a given set of attributes
+ */
+static int kccsrv_dn_list(struct ldb_context *ldb, struct ldb_result *res,
+ TALLOC_CTX *mem_ctx,
+ const char **attrs,
+ struct ldb_dn ***dn_list, int *dn_count)
+{
+ int i;
+ struct ldb_dn **nc_list = NULL;
+ int nc_count = 0;
+
+ nc_list = talloc_array(mem_ctx, struct ldb_dn *, 0);
+ if (nc_list == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* gather up a list of all NCs in this forest */
+ for (i=0; i<res->count; i++) {
+ struct ldb_message *msg = res->msgs[i];
+ int j;
+ for (j=0; attrs[j]; j++) {
+ struct ldb_message_element *el;
+ int k;
+
+ el = ldb_msg_find_element(msg, attrs[j]);
+ if (el == NULL) continue;
+ for (k=0; k<el->num_values; k++) {
+ struct ldb_dn *dn;
+ dn = ldb_dn_from_ldb_val(nc_list, ldb, &el->values[k]);
+ if (dn != NULL) {
+ int l;
+ for (l=0; l<nc_count; l++) {
+ if (ldb_dn_compare(nc_list[l], dn) == 0) break;
+ }
+ if (l < nc_count) continue;
+ nc_list = talloc_realloc(mem_ctx, nc_list, struct ldb_dn *, nc_count+1);
+ if (nc_list == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ nc_list[nc_count] = dn;
+ nc_count++;
+ }
+ }
+ }
+ }
+
+ (*dn_list) = nc_list;
+ (*dn_count) = nc_count;
+ return LDB_SUCCESS;
+}
+
+
+/*
+ look for any additional global catalog partitions that we should be
+ replicating (by looking for msDS-HasDomainNCs), and add them to our
+ hasPartialReplicaNCs NTDS attribute
+ */
+static int kccsrv_gc_update(struct kccsrv_service *s, struct ldb_result *res)
+{
+ int i;
+ struct ldb_dn **nc_list = NULL;
+ int nc_count = 0;
+ struct ldb_dn **our_nc_list = NULL;
+ int our_nc_count = 0;
+ const char *attrs1[] = { "msDS-hasMasterNCs", "hasMasterNCs", "msDS-HasDomainNCs", NULL };
+ const char *attrs2[] = { "msDS-hasMasterNCs", "hasMasterNCs", "msDS-HasDomainNCs", "hasPartialReplicaNCs", NULL };
+ int ret;
+ TALLOC_CTX *tmp_ctx = talloc_new(res);
+ struct ldb_result *res2;
+ struct ldb_message *msg;
+
+ /* get a complete list of NCs for the forest */
+ ret = kccsrv_dn_list(s->samdb, res, tmp_ctx, attrs1, &nc_list, &nc_count);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(1,("Failed to get NC list for GC update - %s\n", ldb_errstring(s->samdb)));
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ /* get a list of what NCs we are already replicating */
+ ret = dsdb_search_dn(s->samdb, tmp_ctx, &res2, samdb_ntds_settings_dn(s->samdb), attrs2, 0);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(1,("Failed to get our NC list attributes for GC update - %s\n", ldb_errstring(s->samdb)));
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ ret = kccsrv_dn_list(s->samdb, res2, tmp_ctx, attrs2, &our_nc_list, &our_nc_count);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(1,("Failed to get our NC list for GC update - %s\n", ldb_errstring(s->samdb)));
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ msg = ldb_msg_new(tmp_ctx);
+ if (msg == NULL) {
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ msg->dn = res2->msgs[0]->dn;
+
+ /* see if we are missing any */
+ for (i=0; i<nc_count; i++) {
+ int j;
+ for (j=0; j<our_nc_count; j++) {
+ if (ldb_dn_compare(nc_list[i], our_nc_list[j]) == 0) break;
+ }
+ if (j == our_nc_count) {
+ /* its a new one */
+ ret = ldb_msg_add_string(msg, "hasPartialReplicaNCs",
+ ldb_dn_get_extended_linearized(msg, nc_list[i], 1));
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ }
+ }
+
+ if (msg->num_elements == 0) {
+ /* none to add */
+ talloc_free(tmp_ctx);
+ return LDB_SUCCESS;
+ }
+ msg->elements[0].flags = LDB_FLAG_MOD_ADD;
+
+ ret = dsdb_modify(s->samdb, msg, 0);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0,("Failed to add hasPartialReplicaNCs - %s\n",
+ ldb_errstring(s->samdb)));
+ }
+
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+
/*
this is the core of our initial simple KCC
We just add a repsFrom entry for all DCs we find that have nTDSDSA
@@ -319,18 +459,22 @@ NTSTATUS kccsrv_simple_update(struct kccsrv_service *s, TALLOC_CTX *mem_ctx)
struct ldb_result *res;
unsigned int i;
int ret;
- const char *attrs[] = { "objectGUID", "invocationID", "msDS-hasMasterNCs", "hasMasterNCs", NULL };
+ const char *attrs[] = { "objectGUID", "invocationID", "msDS-hasMasterNCs", "hasMasterNCs", "msDS-HasDomainNCs", NULL };
struct repsFromToBlob *reps = NULL;
uint32_t count = 0;
struct kcc_connection_list *ntds_conn, *dsa_conn;
- ret = ldb_search(s->samdb, mem_ctx, &res, s->config_dn, LDB_SCOPE_SUBTREE,
- attrs, "objectClass=nTDSDSA");
+ ret = dsdb_search(s->samdb, mem_ctx, &res, s->config_dn, LDB_SCOPE_SUBTREE,
+ attrs, DSDB_SEARCH_SHOW_EXTENDED_DN, "objectClass=nTDSDSA");
if (ret != LDB_SUCCESS) {
DEBUG(0,(__location__ ": Failed nTDSDSA search - %s\n", ldb_errstring(s->samdb)));
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
+ if (samdb_is_gc(s->samdb)) {
+ kccsrv_gc_update(s, res);
+ }
+
/* get the current list of connections */
ntds_conn = kccsrv_find_connections(s, mem_ctx);