From 0ba9a1bd3f2f0b278a86f6e244162b0efa7dd510 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 12 Sep 2009 11:09:10 +1000 Subject: s4-kcc: we should only add to the repsFrom if it doesn't already exist If we already have a repsFrom for a particular DC and naming context then we should not overwrite it, as it contains info on what replication we've already done --- source4/dsdb/common/util.c | 111 ++++++++++++++++++++++++++++++++++++++ source4/dsdb/kcc/kcc_periodic.c | 116 ++++++++++++++++++++++++---------------- 2 files changed, 182 insertions(+), 45 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index 6da02b0b6a..b5005444cc 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -36,6 +36,7 @@ #include "libcli/ldap/ldap_ndr.h" #include "param/param.h" #include "libcli/auth/libcli_auth.h" +#include "librpc/gen_ndr/ndr_drsblobs.h" /* search the sam for the specified attributes in a specific domain, filter on @@ -2146,3 +2147,113 @@ int dsdb_find_guid_by_dn(struct ldb_context *ldb, talloc_free(tmp_ctx); return LDB_SUCCESS; } + + + +/* + load a repsFromTo blob list for a given partition GUID + attr must be "repsFrom" or "repsTo" + */ +WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn, + const char *attr, struct repsFromToBlob **r, uint32_t *count) +{ + const char *attrs[] = { attr, NULL }; + struct ldb_result *res = NULL; + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + int i; + struct ldb_message_element *el; + + *r = NULL; + *count = 0; + + if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS || + res->count < 1) { + DEBUG(0,("dsdb_loadreps: failed to read partition object\n")); + talloc_free(tmp_ctx); + return WERR_DS_DRA_INTERNAL_ERROR; + } + + el = ldb_msg_find_element(res->msgs[0], attr); + if (el == NULL) { + /* it's OK to be empty */ + talloc_free(tmp_ctx); + return WERR_OK; + } + + *count = el->num_values; + *r = talloc_array(mem_ctx, struct repsFromToBlob, *count); + if (*r == NULL) { + talloc_free(tmp_ctx); + return WERR_DS_DRA_INTERNAL_ERROR; + } + + for (i=0; i<(*count); i++) { + enum ndr_err_code ndr_err; + ndr_err = ndr_pull_struct_blob(&el->values[i], + mem_ctx, lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")), + &(*r)[i], + (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + talloc_free(tmp_ctx); + return WERR_DS_DRA_INTERNAL_ERROR; + } + } + + talloc_free(tmp_ctx); + + return WERR_OK; +} + +/* + save the repsFromTo blob list for a given partition GUID + attr must be "repsFrom" or "repsTo" + */ +WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn, + const char *attr, struct repsFromToBlob *r, uint32_t count) +{ + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + struct ldb_message *msg; + struct ldb_message_element *el; + int i; + + msg = ldb_msg_new(tmp_ctx); + msg->dn = dn; + if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) { + goto failed; + } + + el->values = talloc_array(msg, struct ldb_val, count); + if (!el->values) { + goto failed; + } + + for (i=0; inum_values++; + el->values[i] = v; + } + + if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) { + DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx))); + goto failed; + } + + talloc_free(tmp_ctx); + + return WERR_OK; + +failed: + talloc_free(tmp_ctx); + return WERR_DS_DRA_INTERNAL_ERROR; +} + + diff --git a/source4/dsdb/kcc/kcc_periodic.c b/source4/dsdb/kcc/kcc_periodic.c index 649efd51ca..3af79d8b89 100644 --- a/source4/dsdb/kcc/kcc_periodic.c +++ b/source4/dsdb/kcc/kcc_periodic.c @@ -35,10 +35,70 @@ #include "param/param.h" /* - * add a repsFrom to all our partitions + * see if a repsFromToBlob is in a list */ +static bool reps_in_list(struct repsFromToBlob *r, struct repsFromToBlob *reps, uint32_t count) +{ + int i; + for (i=0; ictr.ctr1.other_info->dns_name, + reps[i].ctr.ctr1.other_info->dns_name) == 0 && + GUID_compare(&r->ctr.ctr1.source_dsa_obj_guid, + &reps[i].ctr.ctr1.source_dsa_obj_guid) == 0) { + return true; + } + } + return false; +} +/* + * add any missing repsFrom structures to our partitions + */ +static NTSTATUS kccsrv_add_repsFrom(struct kccsrv_service *s, TALLOC_CTX *mem_ctx, + struct repsFromToBlob *reps, uint32_t count) +{ + struct kccsrv_partition *p; + + /* update the repsFrom on all partitions */ + for (p=s->partitions; p; p=p->next) { + struct repsFromToBlob *old_reps; + uint32_t old_count; + WERROR werr; + int i; + bool modified = false; + + werr = dsdb_loadreps(s->samdb, mem_ctx, p->dn, "repsFrom", &old_reps, &old_count); + if (!W_ERROR_IS_OK(werr)) { + DEBUG(0,(__location__ ": Failed to load repsFrom from %s - %s\n", + ldb_dn_get_linearized(p->dn), ldb_errstring(s->samdb))); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + for (i=0; isamdb, mem_ctx, p->dn, "repsFrom", old_reps, old_count); + if (!W_ERROR_IS_OK(werr)) { + DEBUG(0,(__location__ ": Failed to save repsFrom to %s - %s\n", + ldb_dn_get_linearized(p->dn), ldb_errstring(s->samdb))); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + } + } + + return NT_STATUS_OK; + +} + /* this is the core of our initial simple KCC We just add a repsFrom entry for all DCs we find that have nTDSDSA @@ -49,9 +109,8 @@ static NTSTATUS kccsrv_simple_update(struct kccsrv_service *s, TALLOC_CTX *mem_c struct ldb_result *res; int ret, i; const char *attrs[] = { "objectGUID", "invocationID", NULL }; - struct ldb_message *msg; - struct ldb_message_element *el; - struct kccsrv_partition *p; + struct repsFromToBlob *reps = NULL; + uint32_t count = 0; ret = ldb_search(s->samdb, mem_ctx, &res, s->config_dn, LDB_SCOPE_SUBTREE, attrs, "objectClass=nTDSDSA"); @@ -60,21 +119,10 @@ static NTSTATUS kccsrv_simple_update(struct kccsrv_service *s, TALLOC_CTX *mem_c return NT_STATUS_INTERNAL_DB_CORRUPTION; } - msg = ldb_msg_new(mem_ctx); - NT_STATUS_HAVE_NO_MEMORY(msg); - - ret = ldb_msg_add_empty(msg, "repsFrom", LDB_FLAG_MOD_REPLACE, &el); - if (ret != LDB_SUCCESS) { - return NT_STATUS_NO_MEMORY; - } - for (i=0; icount; i++) { - struct repsFromToBlob r; struct repsFromTo1 *r1; struct repsFromTo1OtherInfo oi; struct GUID ntds_guid, invocation_id; - struct ldb_val v; - enum ndr_err_code ndr_err; ntds_guid = samdb_result_guid(res->msgs[i], "objectGUID"); if (GUID_compare(&ntds_guid, &s->ntds_guid) == 0) { @@ -84,10 +132,13 @@ static NTSTATUS kccsrv_simple_update(struct kccsrv_service *s, TALLOC_CTX *mem_c invocation_id = samdb_result_guid(res->msgs[i], "invocationID"); - ZERO_STRUCT(r); + reps = talloc_realloc(mem_ctx, reps, struct repsFromToBlob, count+1); + NT_STATUS_HAVE_NO_MEMORY(reps); + + ZERO_STRUCT(reps[count]); ZERO_STRUCT(oi); - r.version = 1; - r1 = &r.ctr.ctr1; + reps[count].version = 1; + r1 = &reps[count].ctr.ctr1; oi.dns_name = talloc_asprintf(mem_ctx, "%s._msdcs.%s", GUID_string(mem_ctx, &ntds_guid), @@ -100,35 +151,10 @@ static NTSTATUS kccsrv_simple_update(struct kccsrv_service *s, TALLOC_CTX *mem_c DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS; memset(r1->schedule, 0x11, sizeof(r1->schedule)); - - - ndr_err = ndr_push_struct_blob(&v, mem_ctx, - lp_iconv_convenience(s->task->lp_ctx), - &r, - (ndr_push_flags_fn_t)ndr_push_repsFromToBlob); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - DEBUG(0,(__location__ ": Failed tp push repsFrom blob\n")); - return NT_STATUS_INTERNAL_ERROR; - } - - el->values = talloc_realloc(msg, el->values, struct ldb_val, el->num_values+1); - NT_STATUS_HAVE_NO_MEMORY(el->values); - el->values[el->num_values] = v; - el->num_values++; - } - - /* replace the repsFrom on all partitions */ - for (p=s->partitions; p; p=p->next) { - msg->dn = p->dn; - ret = ldb_modify(s->samdb, msg); - if (ret != LDB_SUCCESS) { - DEBUG(0,(__location__ ": Failed to store repsFrom for %s - %s\n", - ldb_dn_get_linearized(msg->dn), ldb_errstring(s->samdb))); - return NT_STATUS_INTERNAL_ERROR; - } + count++; } - return NT_STATUS_OK; + return kccsrv_add_repsFrom(s, mem_ctx, reps, count); } -- cgit