diff options
Diffstat (limited to 'source4/rpc_server/drsuapi')
-rw-r--r-- | source4/rpc_server/drsuapi/addentry.c | 3 | ||||
-rw-r--r-- | source4/rpc_server/drsuapi/dcesrv_drsuapi.c | 5 | ||||
-rw-r--r-- | source4/rpc_server/drsuapi/dcesrv_drsuapi.h | 1 | ||||
-rw-r--r-- | source4/rpc_server/drsuapi/drsutil.c | 22 | ||||
-rw-r--r-- | source4/rpc_server/drsuapi/getncchanges.c | 421 | ||||
-rw-r--r-- | source4/rpc_server/drsuapi/updaterefs.c | 4 |
6 files changed, 393 insertions, 63 deletions
diff --git a/source4/rpc_server/drsuapi/addentry.c b/source4/rpc_server/drsuapi/addentry.c index 89b664d691..ac94daa6a6 100644 --- a/source4/rpc_server/drsuapi/addentry.c +++ b/source4/rpc_server/drsuapi/addentry.c @@ -199,7 +199,8 @@ WERROR dcesrv_drsuapi_DsAddEntry(struct dcesrv_call_state *dce_call, TALLOC_CTX ret = ldb_transaction_commit(b_state->sam_ctx); if (ret != LDB_SUCCESS) { - DEBUG(0,(__location__ ": DsAddEntry commit failed\n")); + DEBUG(0,(__location__ ": DsAddEntry commit failed: %s\n", + ldb_errstring(b_state->sam_ctx))); return WERR_DS_DRA_INTERNAL_ERROR; } diff --git a/source4/rpc_server/drsuapi/dcesrv_drsuapi.c b/source4/rpc_server/drsuapi/dcesrv_drsuapi.c index 3d92880162..6a6bc8be7e 100644 --- a/source4/rpc_server/drsuapi/dcesrv_drsuapi.c +++ b/source4/rpc_server/drsuapi/dcesrv_drsuapi.c @@ -159,10 +159,7 @@ static WERROR dcesrv_drsuapi_DsBind(struct dcesrv_call_state *dce_call, TALLOC_C b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2; - if (0 /*domain.behavior_version == 2*/) { - /* TODO: find out how this is really triggered! */ - b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION; - } + b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND; diff --git a/source4/rpc_server/drsuapi/dcesrv_drsuapi.h b/source4/rpc_server/drsuapi/dcesrv_drsuapi.h index e42d9569e7..3a64ef5c9c 100644 --- a/source4/rpc_server/drsuapi/dcesrv_drsuapi.h +++ b/source4/rpc_server/drsuapi/dcesrv_drsuapi.h @@ -57,7 +57,6 @@ int drsuapi_search_with_extended_dn(struct ldb_context *ldb, struct ldb_dn *basedn, enum ldb_scope scope, const char * const *attrs, - const char *sort_attrib, const char *filter); WERROR drs_security_level_check(struct dcesrv_call_state *dce_call, diff --git a/source4/rpc_server/drsuapi/drsutil.c b/source4/rpc_server/drsuapi/drsutil.c index a62f911537..0a8a576d60 100644 --- a/source4/rpc_server/drsuapi/drsutil.c +++ b/source4/rpc_server/drsuapi/drsutil.c @@ -47,7 +47,6 @@ int drsuapi_search_with_extended_dn(struct ldb_context *ldb, struct ldb_dn *basedn, enum ldb_scope scope, const char * const *attrs, - const char *sort_attrib, const char *filter) { int ret; @@ -86,26 +85,11 @@ int drsuapi_search_with_extended_dn(struct ldb_context *ldb, return ret; } - if (sort_attrib) { - struct ldb_server_sort_control **sort_control; - sort_control = talloc_array(req, struct ldb_server_sort_control *, 2); - if (sort_control == NULL) { - talloc_free(tmp_ctx); - return LDB_ERR_OPERATIONS_ERROR; - } - sort_control[0] = talloc(req, struct ldb_server_sort_control); - sort_control[0]->attributeName = sort_attrib; - sort_control[0]->orderingRule = NULL; - sort_control[0]->reverse = 0; - sort_control[1] = NULL; - - ret = ldb_request_add_control(req, LDB_CONTROL_SERVER_SORT_OID, true, sort_control); - if (ret != LDB_SUCCESS) { - return ret; - } + ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL); + if (ret != LDB_SUCCESS) { + return ret; } - ret = ldb_request(ldb, req); if (ret == LDB_SUCCESS) { ret = ldb_wait(req->handle, LDB_WAIT_ALL); diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c index 488ecd129e..437dc87ae8 100644 --- a/source4/rpc_server/drsuapi/getncchanges.c +++ b/source4/rpc_server/drsuapi/getncchanges.c @@ -25,11 +25,38 @@ #include "dsdb/samdb/samdb.h" #include "param/param.h" #include "librpc/gen_ndr/ndr_drsblobs.h" +#include "librpc/gen_ndr/ndr_drsuapi.h" #include "rpc_server/drsuapi/dcesrv_drsuapi.h" #include "rpc_server/dcerpc_server_proto.h" #include "../libcli/drsuapi/drsuapi.h" #include "libcli/security/security.h" +/* + build a DsReplicaObjectIdentifier from a ldb msg + */ +static struct drsuapi_DsReplicaObjectIdentifier *get_object_identifier(TALLOC_CTX *mem_ctx, + struct ldb_message *msg) +{ + struct drsuapi_DsReplicaObjectIdentifier *identifier; + struct dom_sid *sid; + + identifier = talloc(mem_ctx, struct drsuapi_DsReplicaObjectIdentifier); + if (identifier == NULL) { + return NULL; + } + + identifier->dn = ldb_dn_alloc_linearized(identifier, msg->dn); + identifier->guid = samdb_result_guid(msg, "objectGUID"); + + sid = samdb_result_dom_sid(identifier, msg, "objectSid"); + if (sid) { + identifier->sid = *sid; + } else { + ZERO_STRUCT(identifier->sid); + } + return identifier; +} + /* drsuapi_DsGetNCChanges for one object */ @@ -44,9 +71,7 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem { const struct ldb_val *md_value; 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; @@ -104,20 +129,15 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem obj->meta_data_ctr = talloc(obj, struct drsuapi_DsReplicaMetaDataCtr); attids = talloc_array(obj, uint32_t, md.ctr.ctr1.count); - 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); - obj->object.identifier->guid = samdb_result_guid(msg, "objectGUID"); - sid = samdb_result_dom_sid(obj, msg, "objectSid"); - if (sid) { - dom_sid_split_rid(NULL, sid, NULL, &rid); - obj->object.identifier->sid = *sid; - } else { - ZERO_STRUCT(obj->object.identifier->sid); + obj->object.identifier = get_object_identifier(obj, msg); + if (obj->object.identifier == NULL) { + return WERR_NOMEM; } + dom_sid_split_rid(NULL, &obj->object.identifier->sid, NULL, &rid); 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++) { + const struct dsdb_attribute *sa; /* if the attribute has not changed, and it is not the instanceType then don't include it */ if (md.ctr.ctr1.array[i].local_usn < highest_usn && @@ -126,6 +146,16 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem /* don't include the rDN */ if (md.ctr.ctr1.array[i].attid == rdn_sa->attributeID_id) continue; + sa = dsdb_attribute_by_attributeID_id(schema, md.ctr.ctr1.array[i].attid); + if (sa->linkID) { + struct ldb_message_element *el; + el = ldb_msg_find_element(msg, sa->lDAPDisplayName); + if (el && el->num_values && dsdb_dn_is_upgraded_link_val(&el->values[0])) { + /* don't send upgraded links inline */ + 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; @@ -199,6 +229,149 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem return WERR_OK; } + +/* + add one linked attribute from an object to the list of linked + attributes in a getncchanges request + */ +static WERROR get_nc_changes_add_la(TALLOC_CTX *mem_ctx, + struct ldb_context *sam_ctx, + const struct dsdb_schema *schema, + const struct dsdb_attribute *sa, + struct ldb_message *msg, + struct dsdb_dn *dsdb_dn, + struct drsuapi_DsReplicaLinkedAttribute **la_list, + uint32_t *la_count) +{ + struct drsuapi_DsReplicaLinkedAttribute *la; + bool active; + NTSTATUS status; + WERROR werr; + + (*la_list) = talloc_realloc(mem_ctx, *la_list, struct drsuapi_DsReplicaLinkedAttribute, (*la_count)+1); + W_ERROR_HAVE_NO_MEMORY(*la_list); + + la = &(*la_list)[*la_count]; + + la->identifier = get_object_identifier(*la_list, msg); + W_ERROR_HAVE_NO_MEMORY(la->identifier); + + active = (dsdb_dn_rmd_flags(dsdb_dn->dn) & DSDB_RMD_FLAG_DELETED) == 0; + + la->attid = sa->attributeID_id; + la->flags = active?DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE:0; + + status = dsdb_get_extended_dn_nttime(dsdb_dn->dn, &la->originating_add_time, "RMD_ADDTIME"); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + status = dsdb_get_extended_dn_uint32(dsdb_dn->dn, &la->meta_data.version, "RMD_VERSION"); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + status = dsdb_get_extended_dn_nttime(dsdb_dn->dn, &la->meta_data.originating_change_time, "RMD_CHANGETIME"); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &la->meta_data.originating_invocation_id, "RMD_INVOCID"); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + status = dsdb_get_extended_dn_uint64(dsdb_dn->dn, &la->meta_data.originating_usn, "RMD_ORIGINATING_USN"); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + werr = dsdb_dn_la_to_blob(sam_ctx, sa, schema, *la_list, dsdb_dn, &la->value.blob); + W_ERROR_NOT_OK_RETURN(werr); + + (*la_count)++; + return WERR_OK; +} + + +/* + add linked attributes from an object to the list of linked + attributes in a getncchanges request + */ +static WERROR get_nc_changes_add_links(struct ldb_context *sam_ctx, + TALLOC_CTX *mem_ctx, + struct ldb_dn *ncRoot_dn, + struct dsdb_schema *schema, + uint64_t highest_usn, + uint32_t replica_flags, + struct ldb_message *msg, + struct drsuapi_DsReplicaLinkedAttribute **la_list, + uint32_t *la_count) +{ + int i; + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + uint64_t uSNChanged = ldb_msg_find_attr_as_int(msg, "uSNChanged", -1); + + for (i=0; i<msg->num_elements; i++) { + struct ldb_message_element *el = &msg->elements[i]; + const struct dsdb_attribute *sa; + int j; + + sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name); + + if (!sa || sa->linkID == 0 || (sa->linkID & 1)) { + /* we only want forward links */ + continue; + } + + if (el->num_values && !dsdb_dn_is_upgraded_link_val(&el->values[0])) { + /* its an old style link, it will have been + * sent in the main replication data */ + continue; + } + + for (j=0; j<el->num_values; j++) { + struct dsdb_dn *dsdb_dn; + uint64_t local_usn; + NTSTATUS status; + WERROR werr; + + dsdb_dn = dsdb_dn_parse(tmp_ctx, sam_ctx, &el->values[j], sa->syntax->ldap_oid); + if (dsdb_dn == NULL) { + DEBUG(1,(__location__ ": Failed to parse DN for %s in %s\n", + el->name, ldb_dn_get_linearized(msg->dn))); + talloc_free(tmp_ctx); + return WERR_DS_DRA_INTERNAL_ERROR; + } + + status = dsdb_get_extended_dn_uint64(dsdb_dn->dn, &local_usn, "RMD_LOCAL_USN"); + if (!NT_STATUS_IS_OK(status)) { + /* this can happen for attributes + given to us with old style meta + data */ + continue; + } + + if (local_usn > uSNChanged) { + DEBUG(1,(__location__ ": uSNChanged less than RMD_LOCAL_USN for %s on %s\n", + el->name, ldb_dn_get_linearized(msg->dn))); + talloc_free(tmp_ctx); + return WERR_DS_DRA_INTERNAL_ERROR; + } + + if (local_usn < highest_usn) { + continue; + } + + werr = get_nc_changes_add_la(mem_ctx, sam_ctx, schema, sa, msg, + dsdb_dn, la_list, la_count); + if (!W_ERROR_IS_OK(werr)) { + talloc_free(tmp_ctx); + return werr; + } + } + } + + talloc_free(tmp_ctx); + return WERR_OK; +} + /* load replUpToDateVector from a DN */ @@ -255,6 +428,7 @@ static WERROR get_nc_changes_udv(struct ldb_context *sam_ctx, NTTIME now; time_t t = time(NULL); struct replUpToDateVectorBlob ouv; + int i; werr = load_udv(sam_ctx, udv, ncRoot_dn, &ouv); if (!W_ERROR_IS_OK(werr)) { @@ -267,13 +441,24 @@ static WERROR get_nc_changes_udv(struct ldb_context *sam_ctx, unix_to_nt_time(&now, t); tmp_cursor->last_sync_success = now; - udv->count = ouv.ctr.ctr2.count + 1; + udv->count = ouv.ctr.ctr2.count; 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; + + for (i=0; i<udv->count; i++) { + if (GUID_equal(&tmp_cursor->source_dsa_invocation_id, + &udv->cursors[i].source_dsa_invocation_id)) { + udv->cursors[i] = *tmp_cursor; + break; + } + } + if (i == udv->count) { + udv->cursors = talloc_realloc(udv, udv->cursors, struct drsuapi_DsReplicaCursor2, udv->count+1); + if (!udv->cursors) { + return WERR_DS_DRA_INTERNAL_ERROR; + } + udv->cursors[udv->count] = *tmp_cursor; + udv->count++; } - udv->cursors[udv->count - 1] = *tmp_cursor; qsort(udv->cursors, udv->count, sizeof(struct drsuapi_DsReplicaCursor2), @@ -282,6 +467,103 @@ static WERROR get_nc_changes_udv(struct ldb_context *sam_ctx, return WERR_OK; } + +/* comparison function for linked attributes - see CompareLinks() in + * MS-DRSR section 4.1.10.5.17 */ +static int linked_attribute_compare(const struct drsuapi_DsReplicaLinkedAttribute *la1, + const struct drsuapi_DsReplicaLinkedAttribute *la2, + struct ldb_context *sam_ctx) +{ + int c; + WERROR werr; + TALLOC_CTX *tmp_ctx; + const struct dsdb_schema *schema; + const struct dsdb_attribute *schema_attrib; + struct dsdb_dn *dn1, *dn2; + struct GUID guid1, guid2; + NTSTATUS status; + + c = GUID_compare(&la1->identifier->guid, + &la2->identifier->guid); + if (c != 0) return c; + + if (la1->attid != la2->attid) { + return la1->attid < la2->attid? -1:1; + } + + if ((la1->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) != + (la2->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)) { + return (la1->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)? 1:-1; + } + + /* we need to get the target GUIDs to compare */ + tmp_ctx = talloc_new(sam_ctx); + + schema = dsdb_get_schema(sam_ctx); + schema_attrib = dsdb_attribute_by_attributeID_id(schema, la1->attid); + + werr = dsdb_dn_la_from_blob(sam_ctx, schema_attrib, schema, tmp_ctx, la1->value.blob, &dn1); + if (!W_ERROR_IS_OK(werr)) { + DEBUG(0,(__location__ ": Bad la1 blob in sort\n")); + talloc_free(tmp_ctx); + return 0; + } + + werr = dsdb_dn_la_from_blob(sam_ctx, schema_attrib, schema, tmp_ctx, la2->value.blob, &dn2); + if (!W_ERROR_IS_OK(werr)) { + DEBUG(0,(__location__ ": Bad la2 blob in sort\n")); + talloc_free(tmp_ctx); + return 0; + } + + status = dsdb_get_extended_dn_guid(dn1->dn, &guid1, "GUID"); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,(__location__ ": Bad la1 guid in sort\n")); + talloc_free(tmp_ctx); + return 0; + } + status = dsdb_get_extended_dn_guid(dn2->dn, &guid2, "GUID"); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,(__location__ ": Bad la2 guid in sort\n")); + talloc_free(tmp_ctx); + return 0; + } + + talloc_free(tmp_ctx); + + return GUID_compare(&guid1, &guid2); +} + + +/* + sort the objects we send by tree order + */ +static int site_res_cmp_parent_order(const struct ldb_message **m1, const struct ldb_message **m2) +{ + return ldb_dn_compare((*m2)->dn, (*m1)->dn); +} + +/* + sort the objects we send first by uSNChanged + */ +static int site_res_cmp_usn_order(const struct ldb_message **m1, const struct ldb_message **m2) +{ + unsigned usnchanged1, usnchanged2; + unsigned cn1, cn2; + cn1 = ldb_dn_get_comp_num((*m1)->dn); + cn2 = ldb_dn_get_comp_num((*m2)->dn); + if (cn1 != cn2) { + return cn1 > cn2 ? 1 : -1; + } + usnchanged1 = ldb_msg_find_attr_as_uint(*m1, "uSNChanged", 0); + usnchanged2 = ldb_msg_find_attr_as_uint(*m2, "uSNChanged", 0); + if (usnchanged1 == usnchanged2) { + return 0; + } + return usnchanged1 > usnchanged2 ? 1 : -1; +} + + /* state of a partially completed getncchanges call */ struct drsuapi_getncchanges_state { struct ldb_result *site_res; @@ -289,6 +571,9 @@ struct drsuapi_getncchanges_state { struct ldb_dn *ncRoot_dn; uint64_t min_usn; uint64_t highest_usn; + struct ldb_dn *last_dn; + struct drsuapi_DsReplicaLinkedAttribute *la_list; + uint32_t la_count; }; /* @@ -323,6 +608,7 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ struct drsuapi_getncchanges_state *getnc_state; struct drsuapi_DsGetNCChangesRequest8 *req8; uint32_t options; + uint32_t max_objects; DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE); b_state = h->data; @@ -389,9 +675,10 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ if (getnc_state) { struct ldb_dn *new_dn = ldb_dn_new(getnc_state, b_state->sam_ctx, ncRoot->dn); if (ldb_dn_compare(new_dn, getnc_state->ncRoot_dn) != 0) { - DEBUG(0,(__location__ ": DsGetNCChanges 2nd replication on different DN %s %s\n", + DEBUG(0,(__location__ ": DsGetNCChanges 2nd replication on different DN %s %s (last_dn %s)\n", ldb_dn_get_linearized(new_dn), - ldb_dn_get_linearized(getnc_state->ncRoot_dn))); + ldb_dn_get_linearized(getnc_state->ncRoot_dn), + ldb_dn_get_linearized(getnc_state->last_dn))); talloc_free(getnc_state); getnc_state = NULL; } @@ -433,6 +720,9 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ if (getnc_state->site_res == NULL) { char* search_filter; enum ldb_scope scope = LDB_SCOPE_SUBTREE; + const char *extra_filter; + + extra_filter = lp_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "drs", "object filter"); getnc_state->min_usn = req8->highwatermark.highest_usn; @@ -441,6 +731,10 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ "(uSNChanged>=%llu)", (unsigned long long)(getnc_state->min_usn+1)); + if (extra_filter) { + search_filter = talloc_asprintf(mem_ctx, "(&%s(%s))", search_filter, extra_filter); + } + if (req8->replica_flags & DRSUAPI_DS_REPLICA_NEIGHBOUR_CRITICAL_ONLY) { search_filter = talloc_asprintf(mem_ctx, "(&%s(isCriticalSystemObject=TRUE))", @@ -451,15 +745,27 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ scope = LDB_SCOPE_BASE; } - DEBUG(6,(__location__ ": getncchanges on %s using filter %s\n", + DEBUG(1,(__location__ ": getncchanges on %s using filter %s\n", ldb_dn_get_linearized(getnc_state->ncRoot_dn), search_filter)); ret = drsuapi_search_with_extended_dn(b_state->sam_ctx, getnc_state, &getnc_state->site_res, getnc_state->ncRoot_dn, scope, attrs, - "uSNChanged", search_filter); if (ret != LDB_SUCCESS) { return WERR_DS_DRA_INTERNAL_ERROR; } + + if (req8->replica_flags & DRSUAPI_DS_REPLICA_NEIGHBOUR_RETURN_OBJECT_PARENTS) { + qsort(getnc_state->site_res->msgs, + getnc_state->site_res->count, + sizeof(getnc_state->site_res->msgs[0]), + (comparison_fn_t)site_res_cmp_parent_order); + } else { + qsort(getnc_state->site_res->msgs, + getnc_state->site_res->count, + sizeof(getnc_state->site_res->msgs[0]), + (comparison_fn_t)site_res_cmp_usn_order); + } + } /* Prefix mapping */ @@ -494,23 +800,25 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ r->out.ctr->ctr6.first_object = NULL; currentObject = &r->out.ctr->ctr6.first_object; + /* use this to force single objects at a time, which is useful + * for working out what object is giving problems + */ + max_objects = lp_parm_int(dce_call->conn->dce_ctx->lp_ctx, NULL, "drs", "max object sync", 1000); + if (req8->max_object_count < max_objects) { + max_objects = req8->max_object_count; + } + for(i=getnc_state->num_sent; i<getnc_state->site_res->count && - (r->out.ctr->ctr6.object_count < req8->max_object_count); + (r->out.ctr->ctr6.object_count < max_objects); i++) { int uSN; struct drsuapi_DsReplicaObjectListItemEx *obj; - obj = talloc_zero(mem_ctx, struct drsuapi_DsReplicaObjectListItemEx); + struct ldb_message *msg = getnc_state->site_res->msgs[i]; - uSN = ldb_msg_find_attr_as_int(getnc_state->site_res->msgs[i], "uSNChanged", -1); - if (uSN > r->out.ctr->ctr6.new_highwatermark.tmp_highest_usn) { - r->out.ctr->ctr6.new_highwatermark.tmp_highest_usn = uSN; - } - if (uSN > getnc_state->highest_usn) { - getnc_state->highest_usn = uSN; - } + obj = talloc_zero(mem_ctx, struct drsuapi_DsReplicaObjectListItemEx); - werr = get_nc_changes_build_object(obj, getnc_state->site_res->msgs[i], + werr = get_nc_changes_build_object(obj, msg, b_state->sam_ctx, getnc_state->ncRoot_dn, schema, &session_key, getnc_state->min_usn, req8->replica_flags); @@ -518,9 +826,28 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ return werr; } + werr = get_nc_changes_add_links(b_state->sam_ctx, getnc_state, + getnc_state->ncRoot_dn, + schema, getnc_state->min_usn, + req8->replica_flags, + msg, + &getnc_state->la_list, + &getnc_state->la_count); + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + uSN = ldb_msg_find_attr_as_int(msg, "uSNChanged", -1); + if (uSN > r->out.ctr->ctr6.new_highwatermark.tmp_highest_usn) { + r->out.ctr->ctr6.new_highwatermark.tmp_highest_usn = uSN; + } + if (uSN > getnc_state->highest_usn) { + getnc_state->highest_usn = uSN; + } + if (obj->meta_data_ctr == NULL) { DEBUG(0,(__location__ ": getncchanges skipping send of object %s\n", - ldb_dn_get_linearized(getnc_state->site_res->msgs[i]->dn))); + ldb_dn_get_linearized(msg->dn))); /* no attributes to send */ talloc_free(obj); continue; @@ -530,6 +857,11 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ *currentObject = obj; currentObject = &obj->next_object; + + talloc_free(getnc_state->last_dn); + getnc_state->last_dn = ldb_dn_copy(getnc_state, msg->dn); + + DEBUG(8,(__location__ ": replicating object %s\n", ldb_dn_get_linearized(msg->dn))); } getnc_state->num_sent += r->out.ctr->ctr6.object_count; @@ -562,6 +894,13 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ if (i < getnc_state->site_res->count) { r->out.ctr->ctr6.more_data = true; } else { + r->out.ctr->ctr6.linked_attributes_count = getnc_state->la_count; + r->out.ctr->ctr6.linked_attributes = talloc_steal(mem_ctx, getnc_state->la_list); + + ldb_qsort(r->out.ctr->ctr6.linked_attributes, r->out.ctr->ctr6.linked_attributes_count, + sizeof(r->out.ctr->ctr6.linked_attributes[0]), + b_state->sam_ctx, (ldb_qsort_cmp_fn_t)linked_attribute_compare); + 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; @@ -580,11 +919,19 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ b_state->getncchanges_state = NULL; } - DEBUG(2,("DsGetNCChanges with uSNChanged >= %llu flags 0x%08x on %s gave %u objects (done %d/%d)\n", - (unsigned long long)(req8->highwatermark.highest_usn+1), - req8->replica_flags, - ncRoot->dn, r->out.ctr->ctr6.object_count, - i, r->out.ctr->ctr6.more_data?getnc_state->site_res->count:i)); + DEBUG(r->out.ctr->ctr6.more_data?2:1, + ("DsGetNCChanges with uSNChanged >= %llu flags 0x%08x on %s gave %u objects (done %d/%d la=%d)\n", + (unsigned long long)(req8->highwatermark.highest_usn+1), + req8->replica_flags, + ncRoot->dn, r->out.ctr->ctr6.object_count, + i, r->out.ctr->ctr6.more_data?getnc_state->site_res->count:i, + r->out.ctr->ctr6.linked_attributes_count)); + +#if 0 + if (!r->out.ctr->ctr6.more_data) { + NDR_PRINT_FUNCTION_DEBUG(drsuapi_DsGetNCChanges, NDR_BOTH, r); + } +#endif return WERR_OK; } diff --git a/source4/rpc_server/drsuapi/updaterefs.c b/source4/rpc_server/drsuapi/updaterefs.c index 6e2efed4f9..b1e3d6c352 100644 --- a/source4/rpc_server/drsuapi/updaterefs.c +++ b/source4/rpc_server/drsuapi/updaterefs.c @@ -105,7 +105,9 @@ static WERROR uref_del_dest(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, return werr; } - if (!found && !(options & DRSUAPI_DS_REPLICA_UPDATE_GETCHG_CHECK)) { + if (!found && + !(options & DRSUAPI_DS_REPLICA_UPDATE_GETCHG_CHECK) && + !(options & DRSUAPI_DS_REPLICA_UPDATE_ADD_REFERENCE)) { return WERR_DS_DRA_REF_NOT_FOUND; } |