diff options
-rw-r--r-- | source4/dsdb/kcc/kcc_periodic.c | 150 |
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); |