diff options
-rw-r--r-- | source4/dsdb/common/util.c | 111 | ||||
-rw-r--r-- | source4/dsdb/kcc/kcc_periodic.c | 116 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 68 | ||||
-rw-r--r-- | source4/rpc_server/drsuapi/getncchanges.c | 229 | ||||
-rw-r--r-- | source4/rpc_server/drsuapi/updaterefs.c | 112 |
5 files changed, 395 insertions, 241 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; i<count; 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")), + &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 %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,11 +35,71 @@ #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; i<count; i++) { + if (strcmp(r->ctr.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; i<count; i++) { + if (!reps_in_list(&reps[i], old_reps, old_count)) { + old_reps = talloc_realloc(mem_ctx, old_reps, struct repsFromToBlob, old_count+1); + NT_STATUS_HAVE_NO_MEMORY(old_reps); + old_reps[old_count] = reps[i]; + old_count++; + modified = true; + } + } + + if (modified) { + werr = dsdb_savereps(s->samdb, 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 objects, except for ourselves @@ -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; i<res->count; 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); } 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; i<msg->num_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); } diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c index 3b908fffbc..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; i<md.ctr.ctr1.count; i++) { - obj->meta_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; i<md.ctr.ctr1.count; i++) { + if (md.ctr.ctr1.array[i].originating_usn < highest_usn) continue; + obj->meta_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]); @@ -150,6 +163,101 @@ 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); +} + +/* + 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) +{ + 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; + } + + 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; + } + + 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; +} + /* drsuapi_DsGetNCChanges */ @@ -164,12 +272,11 @@ 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; + 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 @@ -197,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)) { @@ -244,44 +348,51 @@ 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.first_object = talloc(mem_ctx, struct drsuapi_DsReplicaObjectListItemEx); - currentObject = r->out.ctr->ctr6.first_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->reserved1 = 0; + r->out.ctr->ctr6.uptodateness_vector->reserved2 = 0; + + r->out.ctr->ctr6.first_object = NULL; + currentObject = &r->out.ctr->ctr6.first_object; for(i=0; i<site_res->count; 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; } - if (i == (site_res->count-1)) { - break; + + if (obj->meta_data_ctr == NULL) { + /* no attributes to send */ + talloc_free(obj); + continue; } - 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; } - r->out.ctr->ctr6.uptodateness_vector = talloc(mem_ctx, struct drsuapi_DsReplicaCursor2CtrEx); + werr = get_nc_changes_udv(sam_ctx, ncRoot_dn, r->out.ctr->ctr6.uptodateness_vector); + if (!W_ERROR_IS_OK(werr)) { + return werr; + } - 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; + 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; } 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 @@ -36,110 +36,6 @@ struct repsTo { }; /* - 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; i<reps->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")), - &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; i<reps->count; 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 */ static WERROR uref_add_dest(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, @@ -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; } |