bool is_get_anc;
bool broken_samba_4_5_get_anc_emulation;
bool is_get_tgt;
+ bool send_nc_root_first;
uint64_t min_usn;
uint64_t max_usn;
struct drsuapi_DsReplicaHighWaterMark last_hwm;
struct drsuapi_changed_objects *m2,
struct drsuapi_getncchanges_state *getnc_state)
{
- int ret;
-
- ret = ldb_dn_compare(getnc_state->ncRoot_dn, m1->dn);
- if (ret == 0) {
- return -1;
- }
-
- ret = ldb_dn_compare(getnc_state->ncRoot_dn, m2->dn);
- if (ret == 0) {
- return 1;
- }
-
if (m1->usn == m2->usn) {
return ldb_dn_compare(m2->dn, m1->dn);
}
* @param new_objs if parents are added, this gets updated to point to a chain
* of parent objects (with the parents first and the child last)
*/
-static WERROR getncchanges_add_ancestors(struct drsuapi_DsReplicaObjectListItemEx *child_obj,
+static WERROR getncchanges_add_ancestors(const struct GUID *parent_object_guid,
struct ldb_dn *child_dn,
TALLOC_CTX *mem_ctx,
struct ldb_context *sam_ctx,
DSDB_SECRET_ATTRIBUTES,
NULL };
- next_anc_guid = child_obj->parent_object_guid;
+ next_anc_guid = parent_object_guid;
while (next_anc_guid != NULL) {
struct drsuapi_DsReplicaObjectListItemEx *anc_obj = NULL;
struct ldb_dn *anc_dn = NULL;
/*
- * Don't send an object twice. (If we've sent the object, then
- * we've also sent all its parents as well)
+ * For the GET_ANC case (but not the 'send NC root
+ * first' case), don't send an object twice.
+ *
+ * (If we've sent the object, then we've also sent all
+ * its parents as well)
*/
- werr = dcesrv_drsuapi_obj_cache_exists(getnc_state->obj_cache,
- next_anc_guid);
- if (W_ERROR_EQUAL(werr, WERR_OBJECT_NAME_EXISTS)) {
- return WERR_OK;
- }
- if (W_ERROR_IS_OK(werr)) {
- return WERR_INTERNAL_ERROR;
- }
- if (!W_ERROR_EQUAL(werr, WERR_OBJECT_NOT_FOUND)) {
- return werr;
+ if (getnc_state->obj_cache) {
+ werr = dcesrv_drsuapi_obj_cache_exists(getnc_state->obj_cache,
+ next_anc_guid);
+ if (W_ERROR_EQUAL(werr, WERR_OBJECT_NAME_EXISTS)) {
+ return WERR_OK;
+ }
+ if (W_ERROR_IS_OK(werr)) {
+ return WERR_INTERNAL_ERROR;
+ }
+ if (!W_ERROR_EQUAL(werr, WERR_OBJECT_NOT_FOUND)) {
+ return werr;
+ }
}
anc_obj = talloc_zero(mem_ctx,
/*
* Regardless of whether we actually use it or not,
* we add it to the cache so we don't look at it again
+ *
+ * The only time we are here without
+ * getnc_state->obj_cache is for the forced addition
+ * of the NC root to the start of the reply, this we
+ * want to add each and every call..
*/
- werr = dcesrv_drsuapi_obj_cache_add(getnc_state->obj_cache,
- next_anc_guid);
- if (!W_ERROR_IS_OK(werr)) {
- return werr;
+ if (getnc_state->obj_cache) {
+ werr = dcesrv_drsuapi_obj_cache_add(getnc_state->obj_cache,
+ next_anc_guid);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
}
/*
*/
if (getnc_state->is_get_anc
&& !getnc_state->broken_samba_4_5_get_anc_emulation) {
- werr = getncchanges_add_ancestors(obj, msg->dn, mem_ctx,
+ werr = getncchanges_add_ancestors(obj->parent_object_guid,
+ msg->dn, mem_ctx,
sam_ctx, getnc_state,
schema, session_key,
req10, local_pas,
if (changes[i].usn > getnc_state->max_usn) {
getnc_state->max_usn = changes[i].usn;
}
+
+ if (req10->extended_op == DRSUAPI_EXOP_NONE &&
+ GUID_equal(&changes[i].guid, &getnc_state->ncRoot_guid))
+ {
+ getnc_state->send_nc_root_first = true;
+ }
}
if (req10->extended_op == DRSUAPI_EXOP_NONE) {
uint32_t_ptr_cmp);
}
+ /*
+ * If we have the NC root in this replication, send it
+ * first regardless. However, don't bump the USN now,
+ * treat it as if it was sent early due to GET_ANC
+ *
+ * This is triggered for each call, so every page of responses
+ * gets the NC root as the first object, up to the point where
+ * it naturally occurs in the replication.
+ */
+
+ if (getnc_state->send_nc_root_first) {
+ struct drsuapi_DsReplicaObjectListItemEx *new_objs = NULL;
+
+ werr = getncchanges_add_ancestors(&getnc_state->ncRoot_guid,
+ NULL, mem_ctx,
+ sam_ctx, getnc_state,
+ schema, &session_key,
+ req10, local_pas,
+ machine_dn, &new_objs);
+
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ getncchanges_chunk_add_objects(repl_chunk, new_objs);
+
+ DEBUG(8,(__location__ ": replicating NC root %s\n",
+ ldb_dn_get_linearized(getnc_state->ncRoot_dn)));
+ }
+
/*
* Check in case we're still processing the links from an object in the
* previous chunk. We want to send the links (and any targets needed)
TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
uint32_t old_la_index;
+ /*
+ * Once we get to the 'natural' place to send the NC
+ * root, stop sending it at the front of each reply
+ * and make sure to suppress sending it now
+ *
+ * We don't just 'continue' here as we must send links
+ * and unlike Windows we want to update the
+ * tmp_highest_usn
+ */
+
+ if (getnc_state->send_nc_root_first &&
+ GUID_equal(&getnc_state->guids[i], &getnc_state->ncRoot_guid))
+ {
+ getnc_state->send_nc_root_first = false;
+ obj_already_sent = true;
+ }
+
msg_dn = ldb_dn_new_fmt(tmp_ctx, sam_ctx, "<GUID=%s>",
GUID_string(tmp_ctx, &getnc_state->guids[i]));
W_ERROR_HAVE_NO_MEMORY(msg_dn);