From 96be1f4ef31fdfa463e916177706bbe4437e4166 Mon Sep 17 00:00:00 2001 From: Anatoliy Atanasov Date: Thu, 10 Sep 2009 12:41:48 +0300 Subject: Fix up-to-dateness vector creation. --- source4/rpc_server/drsuapi/getncchanges.c | 91 ++++++++++++++++++++++++++----- 1 file changed, 76 insertions(+), 15 deletions(-) diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c index 3b908fffbc..3388886105 100644 --- a/source4/rpc_server/drsuapi/getncchanges.c +++ b/source4/rpc_server/drsuapi/getncchanges.c @@ -150,6 +150,71 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem return WERR_OK; } +static int replmd_drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1, + const struct drsuapi_DsReplicaCursor2 *c2) +{ + return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id); +} + +static WERROR get_nc_changes_udv(struct drsuapi_DsReplicaCursor2CtrEx *udv, + struct ldb_message *msg, + struct ldb_context *sam_ctx) +{ + uint32_t it_value; + + it_value = ldb_msg_find_attr_as_uint(msg, "instanceType", 0); + if ((it_value & INSTANCE_TYPE_IS_NC_HEAD) == INSTANCE_TYPE_IS_NC_HEAD) { + const struct ldb_val *ouv_value; + struct drsuapi_DsReplicaCursor2 *tmp_cursor; + uint64_t highest_commited_usn; + NTTIME now; + time_t t = time(NULL); + + int ret = ldb_sequence_number(sam_ctx, LDB_SEQ_HIGHEST_SEQ, &highest_commited_usn); + if (ret != LDB_SUCCESS) { + return WERR_DS_DRA_INTERNAL_ERROR; + } + tmp_cursor = talloc(udv, struct drsuapi_DsReplicaCursor2); + tmp_cursor->source_dsa_invocation_id = *(samdb_ntds_invocation_id(sam_ctx)); + tmp_cursor->highest_usn = highest_commited_usn; + unix_to_nt_time(&now, t); + tmp_cursor->last_sync_success = now; + + ouv_value = ldb_msg_find_ldb_val(msg, "replUpToDateVector"); + if (ouv_value) { + struct replUpToDateVectorBlob ouv; + enum ndr_err_code ndr_err; + + ndr_err = ndr_pull_struct_blob(ouv_value, udv, + lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")), &ouv, + (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return WERR_DS_DRA_INTERNAL_ERROR; + } + if (ouv.version != 2) { + return WERR_DS_DRA_INTERNAL_ERROR; + } + + udv->count = ouv.ctr.ctr2.count + 1; + udv->cursors = talloc_steal(udv, ouv.ctr.ctr2.cursors); + udv->cursors = talloc_realloc(udv, udv->cursors, struct drsuapi_DsReplicaCursor2, udv->count); + if (!udv->cursors) { + return WERR_DS_DRA_INTERNAL_ERROR; + } + udv->cursors[udv->count - 1] = *tmp_cursor; + + qsort(udv->cursors, udv->count, + sizeof(struct drsuapi_DsReplicaCursor2), + (comparison_fn_t)replmd_drsuapi_DsReplicaCursor2_compare); + } else { + udv->count = 1; + udv->cursors = talloc_steal(udv, tmp_cursor); + } + } + + return WERR_OK; +} + /* drsuapi_DsGetNCChanges */ @@ -164,8 +229,6 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ int i; struct dsdb_schema *schema; struct drsuapi_DsReplicaOIDMapping_Ctr *ctr; - time_t t = time(NULL); - NTTIME now; struct drsuapi_DsReplicaObjectListItemEx *currentObject; NTSTATUS status; DATA_BLOB session_key; @@ -244,6 +307,11 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ r->out.ctr->ctr6.old_highwatermark = r->in.req->req8.highwatermark; r->out.ctr->ctr6.new_highwatermark = r->in.req->req8.highwatermark; + r->out.ctr->ctr6.uptodateness_vector = talloc(mem_ctx, struct drsuapi_DsReplicaCursor2CtrEx); + r->out.ctr->ctr6.uptodateness_vector->version = 2; + r->out.ctr->ctr6.uptodateness_vector->reserved1 = 0; + r->out.ctr->ctr6.uptodateness_vector->reserved2 = 0; + r->out.ctr->ctr6.first_object = talloc(mem_ctx, struct drsuapi_DsReplicaObjectListItemEx); currentObject = r->out.ctr->ctr6.first_object; @@ -263,6 +331,12 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ r->out.ctr->ctr6.first_object = NULL; return werr; } + + werr = get_nc_changes_udv(r->out.ctr->ctr6.uptodateness_vector, site_res->msgs[i], sam_ctx); + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + if (i == (site_res->count-1)) { break; } @@ -270,18 +344,5 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ currentObject = currentObject->next_object; } - r->out.ctr->ctr6.uptodateness_vector = talloc(mem_ctx, struct drsuapi_DsReplicaCursor2CtrEx); - - r->out.ctr->ctr6.uptodateness_vector->version = 2; - r->out.ctr->ctr6.uptodateness_vector->count = 1; - r->out.ctr->ctr6.uptodateness_vector->reserved1 = 0; - r->out.ctr->ctr6.uptodateness_vector->reserved2 = 0; - r->out.ctr->ctr6.uptodateness_vector->cursors = talloc(mem_ctx, struct drsuapi_DsReplicaCursor2); - - r->out.ctr->ctr6.uptodateness_vector->cursors[0].source_dsa_invocation_id = *(samdb_ntds_invocation_id(sam_ctx)); - r->out.ctr->ctr6.uptodateness_vector->cursors[0].highest_usn = r->out.ctr->ctr6.new_highwatermark.highest_usn; - unix_to_nt_time(&now, t); - r->out.ctr->ctr6.uptodateness_vector->cursors[0].last_sync_success = now; - return WERR_OK; } -- cgit From 4687db00a8b3658ad87a824525bf1dc24f9fd1c7 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(-) 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 From f4b37f193b9c9e594734476d21ac57de43dd4631 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 12 Sep 2009 11:10:19 +1000 Subject: s4-repl: we should only update uSNChanged when replication data changes When changing non-replicated attributes we should not update the uSNChanged attribute on the record, otherwise the DRS server will think this record needs replicating. --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 68 ++++++++++++++----------- 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index fbcde764cc..e7ca074779 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -280,7 +280,7 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req) schema = dsdb_get_schema(ldb); if (!schema) { ldb_debug_set(ldb, LDB_DEBUG_FATAL, - "replmd_modify: no dsdb_schema loaded"); + "replmd_add: no dsdb_schema loaded"); return LDB_ERR_CONSTRAINT_VIOLATION; } @@ -475,10 +475,9 @@ static int replmd_update_rpmd_element(struct ldb_context *ldb, struct ldb_message_element *el, struct replPropertyMetaDataBlob *omd, struct dsdb_schema *schema, - uint64_t seq_num, + uint64_t *seq_num, const struct GUID *our_invocation_id, - NTTIME now, - bool *modified) + NTTIME now) { int i; const struct dsdb_attribute *a; @@ -512,15 +511,25 @@ static int replmd_update_rpmd_element(struct ldb_context *ldb, omd->ctr.ctr1.count++; } + /* Get a new sequence number from the backend. We only do this + * if we have a change that requires a new + * replPropertyMetaData element + */ + if (*seq_num == 0) { + int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num); + if (ret != LDB_SUCCESS) { + return LDB_ERR_OPERATIONS_ERROR; + } + } + md1 = &omd->ctr.ctr1.array[i]; md1->version = 1; md1->attid = a->attributeID_id; md1->originating_change_time = now; md1->originating_invocation_id = *our_invocation_id; - md1->originating_usn = seq_num; - md1->local_usn = seq_num; + md1->originating_usn = *seq_num; + md1->local_usn = *seq_num; - *modified = true; return LDB_SUCCESS; } @@ -530,13 +539,12 @@ static int replmd_update_rpmd_element(struct ldb_context *ldb, * client is based on this object */ static int replmd_update_rpmd(struct ldb_context *ldb, struct ldb_message *msg, - uint64_t seq_num) + uint64_t *seq_num) { const struct ldb_val *omd_value; enum ndr_err_code ndr_err; struct replPropertyMetaDataBlob omd; int i; - bool modified = false; struct dsdb_schema *schema; time_t t = time(NULL); NTTIME now; @@ -590,13 +598,17 @@ static int replmd_update_rpmd(struct ldb_context *ldb, struct ldb_message *msg, for (i=0; inum_elements; i++) { ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], &omd, schema, seq_num, - our_invocation_id, now, &modified); + our_invocation_id, now); if (ret != LDB_SUCCESS) { return ret; } } - if (modified) { + /* + * replmd_update_rpmd_element has done an update if the + * seq_num is set + */ + if (*seq_num != 0) { struct ldb_val *md_value; struct ldb_message_element *el; @@ -640,7 +652,7 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req) struct ldb_message *msg; int ret; time_t t = time(NULL); - uint64_t seq_num; + uint64_t seq_num = 0; /* do not manipulate our control entries */ if (ldb_dn_is_special(req->op.mod.message->dn)) { @@ -683,27 +695,11 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req) * attribute was changed */ - /* Get a sequence number from the backend */ - ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num); - if (ret != LDB_SUCCESS) { - return LDB_ERR_OPERATIONS_ERROR; - } - - ret = replmd_update_rpmd(ldb, msg, seq_num); + ret = replmd_update_rpmd(ldb, msg, &seq_num); if (ret != LDB_SUCCESS) { return ret; } - if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) { - talloc_free(ac); - return LDB_ERR_OPERATIONS_ERROR; - } - - if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) { - talloc_free(ac); - return LDB_ERR_OPERATIONS_ERROR; - } - /* TODO: * - sort the attributes by attid with replmd_ldb_message_sort() * - replace the old object with the newly constructed one @@ -719,6 +715,20 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req) } talloc_steal(down_req, msg); + /* we only change whenChanged and uSNChanged if the seq_num + has changed */ + if (seq_num != 0) { + if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) { + talloc_free(ac); + return LDB_ERR_OPERATIONS_ERROR; + } + + if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) { + talloc_free(ac); + return LDB_ERR_OPERATIONS_ERROR; + } + } + /* go on with the call chain */ return ldb_next_request(module, down_req); } -- cgit From 47a147ee284ba822f2a35e1ff173955407d71fc4 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 12 Sep 2009 11:12:05 +1000 Subject: s4-repl: use common functions to simplify updaterefs.c We now have dsdb_loadreps() and dsdb_savereps() --- source4/rpc_server/drsuapi/updaterefs.c | 112 ++------------------------------ 1 file changed, 4 insertions(+), 108 deletions(-) diff --git a/source4/rpc_server/drsuapi/updaterefs.c b/source4/rpc_server/drsuapi/updaterefs.c index 92027ba455..45244c7801 100644 --- a/source4/rpc_server/drsuapi/updaterefs.c +++ b/source4/rpc_server/drsuapi/updaterefs.c @@ -35,110 +35,6 @@ struct repsTo { struct repsFromToBlob *r; }; -/* - load the repsTo structure for a given partition GUID - */ -static WERROR uref_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn, - struct repsTo *reps) -{ - const char *attrs[] = { "repsTo", NULL }; - struct ldb_result *res; - TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); - int i; - struct ldb_message_element *el; - - /* TODO: possibly check in the rootDSE to see that this DN is - * one of our partition roots */ - - if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS) { - DEBUG(0,("drsuapi_addref: failed to read partition object\n")); - talloc_free(tmp_ctx); - return WERR_DS_DRA_INTERNAL_ERROR; - } - - ZERO_STRUCTP(reps); - - el = ldb_msg_find_element(res->msgs[0], "repsTo"); - if (el == NULL) { - talloc_free(tmp_ctx); - return WERR_OK; - } - - reps->count = el->num_values; - reps->r = talloc_array(mem_ctx, struct repsFromToBlob, reps->count); - if (reps->r == NULL) { - talloc_free(tmp_ctx); - return WERR_DS_DRA_INTERNAL_ERROR; - } - - for (i=0; icount; 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")), - &reps->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 repsTo structure for a given partition GUID - */ -static WERROR uref_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn, - struct repsTo *reps) -{ - 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, "repsTo", LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) { - goto failed; - } - - el->values = talloc_array(msg, struct ldb_val, reps->count); - if (!el->values) { - goto failed; - } - - for (i=0; icount; i++) { - struct ldb_val v; - enum ndr_err_code ndr_err; - - ndr_err = ndr_push_struct_blob(&v, tmp_ctx, lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")), - &reps->r[i], - (ndr_push_flags_fn_t)ndr_push_repsFromToBlob); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - goto failed; - } - - el->num_values++; - el->values[i] = v; - } - - if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) { - DEBUG(0,("Failed to store repsTo - %s\n", ldb_errstring(sam_ctx))); - goto failed; - } - - talloc_free(tmp_ctx); - - return WERR_OK; - -failed: - talloc_free(tmp_ctx); - return WERR_DS_DRA_INTERNAL_ERROR; -} - /* add a replication destination for a given partition GUID */ @@ -148,7 +44,7 @@ static WERROR uref_add_dest(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct repsTo reps; WERROR werr; - werr = uref_loadreps(sam_ctx, mem_ctx, dn, &reps); + werr = dsdb_loadreps(sam_ctx, mem_ctx, dn, "repsTo", &reps.r, &reps.count); if (!W_ERROR_IS_OK(werr)) { return werr; } @@ -162,7 +58,7 @@ static WERROR uref_add_dest(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, reps.r[reps.count].ctr.ctr1 = *dest; reps.count++; - werr = uref_savereps(sam_ctx, mem_ctx, dn, &reps); + werr = dsdb_savereps(sam_ctx, mem_ctx, dn, "repsTo", reps.r, reps.count); if (!W_ERROR_IS_OK(werr)) { return werr; } @@ -180,7 +76,7 @@ static WERROR uref_del_dest(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, WERROR werr; int i; - werr = uref_loadreps(sam_ctx, mem_ctx, dn, &reps); + werr = dsdb_loadreps(sam_ctx, mem_ctx, dn, "repsTo", &reps.r, &reps.count); if (!W_ERROR_IS_OK(werr)) { return werr; } @@ -194,7 +90,7 @@ static WERROR uref_del_dest(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, } } - werr = uref_savereps(sam_ctx, mem_ctx, dn, &reps); + werr = dsdb_savereps(sam_ctx, mem_ctx, dn, "repsTo", reps.r, reps.count); if (!W_ERROR_IS_OK(werr)) { return werr; } -- cgit From 21a6ba41150a133d3207928a8b4c7b1d6c1e411f Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 12 Sep 2009 11:14:29 +1000 Subject: s4-drs: fixed the cursor generation to always be filled in We were relying on the uSNChanged>=n search always finding the DN of the root of the partition, but this now doesn't happen very often as we are now restricting when we change uSNChanged. This means we need to always load the replUpToDateVector attribute from the NC root and use it to populate the cursors in the return. --- source4/rpc_server/drsuapi/getncchanges.c | 254 ++++++++++++++++++------------ 1 file changed, 152 insertions(+), 102 deletions(-) diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c index 3388886105..725a380f89 100644 --- a/source4/rpc_server/drsuapi/getncchanges.c +++ b/source4/rpc_server/drsuapi/getncchanges.c @@ -42,14 +42,17 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem struct ldb_context *sam_ctx, struct ldb_dn *ncRoot_dn, struct dsdb_schema *schema, - DATA_BLOB *session_key) + DATA_BLOB *session_key, + uint64_t highest_usn) { const struct ldb_val *md_value; - int i; + int i, n; struct ldb_dn *obj_dn; struct replPropertyMetaDataBlob md; struct dom_sid *sid; uint32_t rid = 0; + enum ndr_err_code ndr_err; + uint32_t *attids; if (ldb_dn_compare(ncRoot_dn, msg->dn) == 0) { obj->is_nc_prefix = true; @@ -61,34 +64,44 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem } obj->next_object = NULL; - obj->meta_data_ctr = talloc(obj, struct drsuapi_DsReplicaMetaDataCtr); md_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData"); - if (md_value) { - enum ndr_err_code ndr_err; - ndr_err = ndr_pull_struct_blob(md_value, obj, - lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")), &md, - (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return WERR_DS_DRA_INTERNAL_ERROR; - } - - if (md.version != 1) { - return WERR_DS_DRA_INTERNAL_ERROR; - } - - obj->meta_data_ctr->count = md.ctr.ctr1.count; - obj->meta_data_ctr->meta_data = talloc_array(obj, struct drsuapi_DsReplicaMetaData, md.ctr.ctr1.count); - for (i=0; imeta_data_ctr->meta_data[i].originating_change_time = md.ctr.ctr1.array[i].originating_change_time; - obj->meta_data_ctr->meta_data[i].version = md.ctr.ctr1.array[i].version; - obj->meta_data_ctr->meta_data[i].originating_invocation_id = md.ctr.ctr1.array[i].originating_invocation_id; - obj->meta_data_ctr->meta_data[i].originating_usn = md.ctr.ctr1.array[i].originating_usn; - } - } else { - obj->meta_data_ctr->meta_data = talloc(obj, struct drsuapi_DsReplicaMetaData); - obj->meta_data_ctr->count = 0; - ZERO_STRUCT(md); + if (!md_value) { + /* nothing to send */ + return WERR_OK; + } + + ndr_err = ndr_pull_struct_blob(md_value, obj, + lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")), &md, + (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return WERR_DS_DRA_INTERNAL_ERROR; + } + + if (md.version != 1) { + return WERR_DS_DRA_INTERNAL_ERROR; } + + obj->meta_data_ctr = talloc(obj, struct drsuapi_DsReplicaMetaDataCtr); + attids = talloc_array(obj, uint32_t, md.ctr.ctr1.count); + + obj->meta_data_ctr->meta_data = talloc_array(obj, struct drsuapi_DsReplicaMetaData, md.ctr.ctr1.count); + for (n=i=0; imeta_data_ctr->meta_data[n].originating_change_time = md.ctr.ctr1.array[i].originating_change_time; + obj->meta_data_ctr->meta_data[n].version = md.ctr.ctr1.array[i].version; + obj->meta_data_ctr->meta_data[n].originating_invocation_id = md.ctr.ctr1.array[i].originating_invocation_id; + obj->meta_data_ctr->meta_data[n].originating_usn = md.ctr.ctr1.array[i].originating_usn; + attids[n] = md.ctr.ctr1.array[i].attid; + n++; + } + if (n == 0) { + /* nothing to send */ + talloc_free(obj->meta_data_ctr); + obj->meta_data_ctr = NULL; + return WERR_OK; + } + obj->meta_data_ctr->count = n; + obj->object.identifier = talloc(obj, struct drsuapi_DsReplicaObjectIdentifier); obj_dn = ldb_msg_find_attr_as_dn(sam_ctx, obj, msg, "distinguishedName"); obj->object.identifier->dn = ldb_dn_get_linearized(obj_dn); @@ -114,18 +127,18 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem struct ldb_message_element *el; WERROR werr; - sa = dsdb_attribute_by_attributeID_id(schema, md.ctr.ctr1.array[i].attid); + sa = dsdb_attribute_by_attributeID_id(schema, attids[i]); if (!sa) { - DEBUG(0,("Unable to find attributeID %u in schema\n", md.ctr.ctr1.array[i].attid)); + DEBUG(0,("Unable to find attributeID %u in schema\n", attids[i])); return WERR_DS_DRA_INTERNAL_ERROR; } el = ldb_msg_find_element(msg, sa->lDAPDisplayName); if (el == NULL) { DEBUG(0,("No element '%s' for attributeID %u in message\n", - sa->lDAPDisplayName, md.ctr.ctr1.array[i].attid)); + sa->lDAPDisplayName, attids[i])); ZERO_STRUCT(obj->object.attribute_ctr.attributes[i]); - obj->object.attribute_ctr.attributes[i].attid = md.ctr.ctr1.array[i].attid; + obj->object.attribute_ctr.attributes[i].attid = attids[i]; } else { werr = dsdb_attribute_ldb_to_drsuapi(sam_ctx, schema, el, obj, &obj->object.attribute_ctr.attributes[i]); @@ -156,62 +169,92 @@ static int replmd_drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplic return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id); } -static WERROR get_nc_changes_udv(struct drsuapi_DsReplicaCursor2CtrEx *udv, - struct ldb_message *msg, - struct ldb_context *sam_ctx) +/* + load replUpToDateVector from a DN + */ +static WERROR load_udv(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, + struct ldb_dn *dn, struct replUpToDateVectorBlob *ouv) { - uint32_t it_value; - - it_value = ldb_msg_find_attr_as_uint(msg, "instanceType", 0); - if ((it_value & INSTANCE_TYPE_IS_NC_HEAD) == INSTANCE_TYPE_IS_NC_HEAD) { - const struct ldb_val *ouv_value; - struct drsuapi_DsReplicaCursor2 *tmp_cursor; - uint64_t highest_commited_usn; - NTTIME now; - time_t t = time(NULL); - - int ret = ldb_sequence_number(sam_ctx, LDB_SEQ_HIGHEST_SEQ, &highest_commited_usn); - if (ret != LDB_SUCCESS) { - return WERR_DS_DRA_INTERNAL_ERROR; - } - tmp_cursor = talloc(udv, struct drsuapi_DsReplicaCursor2); - tmp_cursor->source_dsa_invocation_id = *(samdb_ntds_invocation_id(sam_ctx)); - tmp_cursor->highest_usn = highest_commited_usn; - unix_to_nt_time(&now, t); - tmp_cursor->last_sync_success = now; - - ouv_value = ldb_msg_find_ldb_val(msg, "replUpToDateVector"); - if (ouv_value) { - struct replUpToDateVectorBlob ouv; - enum ndr_err_code ndr_err; - - ndr_err = ndr_pull_struct_blob(ouv_value, udv, - lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")), &ouv, - (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return WERR_DS_DRA_INTERNAL_ERROR; - } - if (ouv.version != 2) { - return WERR_DS_DRA_INTERNAL_ERROR; - } + const char *attrs[] = { "replUpToDateVector", NULL }; + struct ldb_result *res = NULL; + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + struct ldb_message_element *el; + enum ndr_err_code ndr_err; + + ZERO_STRUCTP(ouv); + + if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS || + res->count < 1) { + DEBUG(0,("load_udv: failed to read partition object\n")); + talloc_free(tmp_ctx); + return WERR_DS_DRA_INTERNAL_ERROR; + } - udv->count = ouv.ctr.ctr2.count + 1; - udv->cursors = talloc_steal(udv, ouv.ctr.ctr2.cursors); - udv->cursors = talloc_realloc(udv, udv->cursors, struct drsuapi_DsReplicaCursor2, udv->count); - if (!udv->cursors) { - return WERR_DS_DRA_INTERNAL_ERROR; - } - udv->cursors[udv->count - 1] = *tmp_cursor; + el = ldb_msg_find_element(res->msgs[0], "replUpToDateVector"); + if (el == NULL || el->num_values < 1) { + talloc_free(tmp_ctx); + ouv->version = 2; + return WERR_OK; + } - qsort(udv->cursors, udv->count, - sizeof(struct drsuapi_DsReplicaCursor2), - (comparison_fn_t)replmd_drsuapi_DsReplicaCursor2_compare); - } else { - udv->count = 1; - udv->cursors = talloc_steal(udv, tmp_cursor); - } + ndr_err = ndr_pull_struct_blob(&el->values[0], + mem_ctx, lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")), + ouv, + (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob); + talloc_free(tmp_ctx); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(0,(__location__ ": Failed to parse replUpToDateVector for %s\n", + ldb_dn_get_linearized(dn))); + return WERR_DS_DRA_INTERNAL_ERROR; + } + + return WERR_OK; + +} + +/* + fill in the cursors return based on the replUpToDateVector for the ncRoot_dn + */ +static WERROR get_nc_changes_udv(struct ldb_context *sam_ctx, + struct ldb_dn *ncRoot_dn, + struct drsuapi_DsReplicaCursor2CtrEx *udv) +{ + WERROR werr; + struct drsuapi_DsReplicaCursor2 *tmp_cursor; + uint64_t highest_commited_usn; + NTTIME now; + time_t t = time(NULL); + int ret; + struct replUpToDateVectorBlob ouv; + + werr = load_udv(sam_ctx, udv, ncRoot_dn, &ouv); + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + ret = ldb_sequence_number(sam_ctx, LDB_SEQ_HIGHEST_SEQ, &highest_commited_usn); + if (ret != LDB_SUCCESS) { + return WERR_DS_DRA_INTERNAL_ERROR; } + tmp_cursor = talloc(udv, struct drsuapi_DsReplicaCursor2); + tmp_cursor->source_dsa_invocation_id = *(samdb_ntds_invocation_id(sam_ctx)); + tmp_cursor->highest_usn = highest_commited_usn; + unix_to_nt_time(&now, t); + tmp_cursor->last_sync_success = now; + + udv->count = ouv.ctr.ctr2.count + 1; + udv->cursors = talloc_steal(udv, ouv.ctr.ctr2.cursors); + udv->cursors = talloc_realloc(udv, udv->cursors, struct drsuapi_DsReplicaCursor2, udv->count); + if (!udv->cursors) { + return WERR_DS_DRA_INTERNAL_ERROR; + } + udv->cursors[udv->count - 1] = *tmp_cursor; + + qsort(udv->cursors, udv->count, + sizeof(struct drsuapi_DsReplicaCursor2), + (comparison_fn_t)replmd_drsuapi_DsReplicaCursor2_compare); + return WERR_OK; } @@ -229,10 +272,11 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ int i; struct dsdb_schema *schema; struct drsuapi_DsReplicaOIDMapping_Ctr *ctr; - struct drsuapi_DsReplicaObjectListItemEx *currentObject; + struct drsuapi_DsReplicaObjectListItemEx **currentObject; NTSTATUS status; DATA_BLOB session_key; const char *attrs[] = { "*", "parentGUID", NULL }; + WERROR werr; /* * connect to the samdb. TODO: We need to check that the caller @@ -260,9 +304,6 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ return WERR_DS_DRA_BAD_NC; } - DEBUG(4,("DsGetNSChanges with uSNChanged >= %llu\n", - (unsigned long long)r->in.req->req8.highwatermark.highest_usn)); - /* we need the session key for encrypting password attributes */ status = dcesrv_inherited_session_key(dce_call->conn, &session_key); if (!NT_STATUS_IS_OK(status)) { @@ -312,37 +353,46 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ r->out.ctr->ctr6.uptodateness_vector->reserved1 = 0; r->out.ctr->ctr6.uptodateness_vector->reserved2 = 0; - r->out.ctr->ctr6.first_object = talloc(mem_ctx, struct drsuapi_DsReplicaObjectListItemEx); - currentObject = r->out.ctr->ctr6.first_object; + r->out.ctr->ctr6.first_object = NULL; + currentObject = &r->out.ctr->ctr6.first_object; for(i=0; icount; i++) { int uSN; - WERROR werr; + struct drsuapi_DsReplicaObjectListItemEx *obj; + obj = talloc_zero(mem_ctx, struct drsuapi_DsReplicaObjectListItemEx); uSN = ldb_msg_find_attr_as_int(site_res->msgs[i], "uSNChanged", -1); - r->out.ctr->ctr6.object_count++; if (uSN > r->out.ctr->ctr6.new_highwatermark.highest_usn) { r->out.ctr->ctr6.new_highwatermark.highest_usn = uSN; } - werr = get_nc_changes_build_object(currentObject, site_res->msgs[i], sam_ctx, ncRoot_dn, - schema, &session_key); + werr = get_nc_changes_build_object(obj, site_res->msgs[i], sam_ctx, ncRoot_dn, + schema, &session_key, r->in.req->req8.highwatermark.highest_usn); if (!W_ERROR_IS_OK(werr)) { - r->out.ctr->ctr6.first_object = NULL; return werr; } - werr = get_nc_changes_udv(r->out.ctr->ctr6.uptodateness_vector, site_res->msgs[i], sam_ctx); - if (!W_ERROR_IS_OK(werr)) { - return werr; + if (obj->meta_data_ctr == NULL) { + /* no attributes to send */ + talloc_free(obj); + continue; } - if (i == (site_res->count-1)) { - break; - } - currentObject->next_object = talloc_zero(mem_ctx, struct drsuapi_DsReplicaObjectListItemEx); - currentObject = currentObject->next_object; + r->out.ctr->ctr6.object_count++; + + *currentObject = obj; + currentObject = &obj->next_object; } + werr = get_nc_changes_udv(sam_ctx, ncRoot_dn, r->out.ctr->ctr6.uptodateness_vector); + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + + DEBUG(4,("DsGetNSChanges with uSNChanged >= %llu on %s gave %u objects\n", + (unsigned long long)r->in.req->req8.highwatermark.highest_usn, + ncRoot->dn, r->out.ctr->ctr6.object_count)); + return WERR_OK; } -- cgit