#include "rpc_server/dcerpc_server_proto.h"
#include "../libcli/drsuapi/drsuapi.h"
#include "libcli/security/security.h"
+#include "lib/util/binsearch.h"
/*
build a DsReplicaObjectIdentifier from a ldb msg
return identifier;
}
+static int udv_compare(const struct GUID *guid1, struct GUID guid2)
+{
+ return GUID_compare(guid1, &guid2);
+}
+
+/*
+ see if we can filter an attribute using the uptodateness_vector
+ */
+static bool udv_filter(const struct drsuapi_DsReplicaCursorCtrEx *udv,
+ const struct GUID *originating_invocation_id,
+ uint64_t originating_usn)
+{
+ const struct drsuapi_DsReplicaCursor *c;
+ if (udv == NULL) return false;
+ BINARY_ARRAY_SEARCH(udv->cursors, udv->count, source_dsa_invocation_id,
+ originating_invocation_id, udv_compare, c);
+ if (c && originating_usn <= c->highest_usn) {
+ return true;
+ }
+ return false;
+
+}
+
/*
drsuapi_DsGetNCChanges for one object
*/
struct dsdb_schema *schema,
DATA_BLOB *session_key,
uint64_t highest_usn,
- uint32_t replica_flags)
+ uint32_t replica_flags,
+ struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector)
{
const struct ldb_val *md_value;
int i, n;
}
}
+ /* filter by uptodateness_vector */
+ if (md.ctr.ctr1.array[i].attid != DRSUAPI_ATTRIBUTE_instanceType &&
+ udv_filter(uptodateness_vector,
+ &md.ctr.ctr1.array[i].originating_invocation_id,
+ md.ctr.ctr1.array[i].originating_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;
n++;
}
- /*
- note that if n==0 we still need to send the change, as it
- could be a rename, which changes the uSNChanged, but not any
- of the replicated attributes
- */
+ /* ignore it if its an empty change. Note that renames always
+ * change the 'name' attribute, so they won't be ignored by
+ * this */
+ if (n == 0 ||
+ (n == 1 && attids[0] == DRSUAPI_ATTRIBUTE_instanceType)) {
+ talloc_free(obj->meta_data_ctr);
+ obj->meta_data_ctr = NULL;
+ return WERR_OK;
+ }
obj->meta_data_ctr->count = n;
uint32_t replica_flags,
struct ldb_message *msg,
struct drsuapi_DsReplicaLinkedAttribute **la_list,
- uint32_t *la_count)
+ uint32_t *la_count,
+ struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector)
{
int i;
TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
struct replUpToDateVectorBlob ouv;
int i;
+ udv->version = 2;
+ udv->reserved1 = 0;
+ udv->reserved2 = 0;
+
werr = load_udv(sam_ctx, udv, ncRoot_dn, &ouv);
if (!W_ERROR_IS_OK(werr)) {
return werr;
/* work out who is the RID Manager */
ret = samdb_rid_manager_dn(ldb, mem_ctx, &rid_manager_dn);
if (ret != LDB_SUCCESS) {
- DEBUG(0, (__location__ ": Failed to find RID Manager object - %s", ldb_errstring(ldb)));
+ DEBUG(0, (__location__ ": Failed to find RID Manager object - %s\n", ldb_errstring(ldb)));
return WERR_DS_DRA_INTERNAL_ERROR;
}
- req_dn = ldb_dn_new(ldb, mem_ctx, req8->naming_context->dn);
+ req_dn = ldb_dn_new(mem_ctx, ldb, req8->naming_context->dn);
if (!req_dn ||
!ldb_dn_validate(req_dn) ||
- ldb_dn_compare(samdb_ntds_settings_dn(ldb), rid_manager_dn) != 0) {
+ ldb_dn_compare(req_dn, rid_manager_dn) != 0) {
/* that isn't the RID Manager DN */
- DEBUG(0,(__location__ ": RID Alloc request for wrong DN %s",
+ DEBUG(0,(__location__ ": RID Alloc request for wrong DN %s\n",
req8->naming_context->dn));
ctr6->extended_ret = DRSUAPI_EXOP_ERR_MISMATCH;
return WERR_OK;
/* find the DN of the RID Manager */
ret = samdb_reference_dn(ldb, mem_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn);
if (ret != LDB_SUCCESS) {
- DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s",
+ DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s\n",
ldb_errstring(ldb)));
+ ctr6->extended_ret = DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER;
return WERR_DS_DRA_INTERNAL_ERROR;
}
if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), fsmo_role_dn) != 0) {
/* we're not the RID Manager - go away */
- DEBUG(0,(__location__ ": RID Alloc request when not RID Manager"));
+ DEBUG(0,(__location__ ": RID Alloc request when not RID Manager\n"));
ctr6->extended_ret = DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER;
return WERR_OK;
}
exop->fsmo_info = req8->fsmo_info;
exop->destination_dsa_guid = req8->destination_dsa_guid;
+ ret = ldb_transaction_start(ldb);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0,(__location__ ": Failed transaction start - %s\n",
+ ldb_errstring(ldb)));
+ return WERR_DS_DRA_INTERNAL_ERROR;
+ }
+
ret = ldb_extended(ldb, DSDB_EXTENDED_ALLOCATE_RID_POOL, exop, &ext_res);
if (ret != LDB_SUCCESS) {
DEBUG(0,(__location__ ": Failed extended allocation RID pool operation - %s\n",
ldb_errstring(ldb)));
+ ldb_transaction_cancel(ldb);
+ return WERR_DS_DRA_INTERNAL_ERROR;
+ }
+
+ ret = ldb_transaction_commit(ldb);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0,(__location__ ": Failed transaction commit - %s\n",
+ ldb_errstring(ldb)));
return WERR_DS_DRA_INTERNAL_ERROR;
}
+
talloc_free(ext_res);
base_dn = samdb_base_dn(ldb);
DEBUG(2,("Allocated RID pool for server %s\n",
GUID_string(mem_ctx, &req8->destination_dsa_guid)));
- /* to complete the rest of the operation we need to point
- getncchanges at the base DN for the domain */
- req8->naming_context->dn = ldb_dn_get_linearized(base_dn);
- ret = dsdb_find_guid_by_dn(ldb, base_dn, &req8->naming_context->guid);
- if (ret != LDB_SUCCESS) {
- DEBUG(0,(__location__ ": Failed to find base DN GUID - %s\n",
- ldb_errstring(ldb)));
- return WERR_DS_DRA_INTERNAL_ERROR;
- }
+ ctr6->extended_ret = DRSUAPI_EXOP_ERR_SUCCESS;
return WERR_OK;
}
struct ldb_dn *last_dn;
struct drsuapi_DsReplicaLinkedAttribute *la_list;
uint32_t la_count;
+ struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;
};
/*
struct drsuapi_DsGetNCChangesRequest8 *req8;
uint32_t options;
uint32_t max_objects;
+ struct ldb_dn *search_dn = NULL;
DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
b_state = h->data;
case DRSUAPI_EXOP_FSMO_RID_ALLOC:
werr = getncchanges_rid_alloc(b_state, mem_ctx, req8, &r->out.ctr->ctr6);
W_ERROR_NOT_OK_RETURN(werr);
+ search_dn = samdb_base_dn(b_state->sam_ctx);
break;
case DRSUAPI_EXOP_FSMO_REQ_ROLE:
scope = LDB_SCOPE_BASE;
}
+ if (!search_dn) {
+ search_dn = getnc_state->ncRoot_dn;
+ }
+
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,
+ search_dn, scope, attrs,
search_filter);
if (ret != LDB_SUCCESS) {
return WERR_DS_DRA_INTERNAL_ERROR;
(comparison_fn_t)site_res_cmp_usn_order);
}
+ getnc_state->uptodateness_vector = talloc_steal(getnc_state, req8->uptodateness_vector);
+ if (getnc_state->uptodateness_vector) {
+ /* make sure its sorted */
+ qsort(getnc_state->uptodateness_vector->cursors,
+ getnc_state->uptodateness_vector->count,
+ sizeof(getnc_state->uptodateness_vector->cursors[0]),
+ (comparison_fn_t)drsuapi_DsReplicaCursor_compare);
+ }
}
/* Prefix mapping */
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);
+ req8->replica_flags, getnc_state->uptodateness_vector);
if (!W_ERROR_IS_OK(werr)) {
return werr;
}
req8->replica_flags,
msg,
&getnc_state->la_list,
- &getnc_state->la_count);
+ &getnc_state->la_count,
+ getnc_state->uptodateness_vector);
if (!W_ERROR_IS_OK(werr)) {
return werr;
}
}
if (obj->meta_data_ctr == NULL) {
- DEBUG(0,(__location__ ": getncchanges skipping send of object %s\n",
+ DEBUG(8,(__location__ ": getncchanges skipping send of object %s\n",
ldb_dn_get_linearized(msg->dn)));
/* no attributes to send */
talloc_free(obj);
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;
- r->out.ctr->ctr6.uptodateness_vector->reserved2 = 0;
-
r->out.ctr->ctr6.new_highwatermark.highest_usn = r->out.ctr->ctr6.new_highwatermark.tmp_highest_usn;
werr = get_nc_changes_udv(b_state->sam_ctx, getnc_state->ncRoot_dn,
b_state->getncchanges_state = NULL;
}
+ if (req8->extended_op != DRSUAPI_EXOP_NONE) {
+ r->out.ctr->ctr6.uptodateness_vector = NULL;
+ r->out.ctr->ctr6.nc_object_count = 0;
+ ZERO_STRUCT(r->out.ctr->ctr6.new_highwatermark);
+ }
+
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),