static int descriptor_extended_sec_desc_propagation(struct ldb_module *module,
						    struct ldb_request *req)
{
	struct descriptor_data *descriptor_private =
		talloc_get_type_abort(ldb_module_get_private(module),
		struct descriptor_data);
	struct descriptor_transaction *t = &descriptor_private->transaction;
	struct ldb_context *ldb = ldb_module_get_ctx(module);
	struct dsdb_extended_sec_desc_propagation_op *op;
	struct descriptor_changes *c = NULL;
	TDB_DATA key;
	NTSTATUS status;

	op = talloc_get_type(req->op.extended.data,
			     struct dsdb_extended_sec_desc_propagation_op);
	if (op == NULL) {
		ldb_debug(ldb, LDB_DEBUG_FATAL,
			  "descriptor_extended_sec_desc_propagation: "
			  "invalid extended data\n");
		return LDB_ERR_PROTOCOL_ERROR;
	}

	if (t->mem == NULL) {
		return ldb_module_operr(module);
	}

	if (GUID_equal(&op->parent_guid, &op->guid)) {
		/*
		 * This is an unexpected situation,
		 * it should never happen!
		 */
		DBG_ERR("ERROR: Object %s is its own parent (nc_root=%s)\n",
			GUID_string(t->mem, &op->guid),
			ldb_dn_get_extended_linearized(t->mem, op->nc_root, 1));
		return ldb_module_operr(module);
	}

	/*
	 * First we check if we already have an registration
	 * for the given object.
	 */

	key = make_tdb_data((const void*)&op->guid, sizeof(op->guid));
	status = dbwrap_parse_record(t->changes.map, key,
				     descriptor_changes_parser, &c);
	if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
		c = NULL;
		status = NT_STATUS_OK;
	}
	if (!NT_STATUS_IS_OK(status)) {
		ldb_debug(ldb, LDB_DEBUG_FATAL,
			  "dbwrap_parse_record() - %s\n",
			  nt_errstr(status));
		return ldb_module_operr(module);
	}

	if (c == NULL) {
		/*
		 * Create a new structure if we
		 * don't know about the object yet.
		 */

		c = talloc_zero(t->mem, struct descriptor_changes);
		if (c == NULL) {
			return ldb_module_oom(module);
		}
		c->nc_root = ldb_dn_copy(c, op->nc_root);
		if (c->nc_root == NULL) {
			return ldb_module_oom(module);
		}
		c->guid = op->guid;
	}

	if (ldb_dn_compare(c->nc_root, op->nc_root) != 0) {
		/*
		 * This is an unexpected situation,
		 * we don't expect the nc root to change
		 * during a replication cycle.
		 */
		DBG_ERR("ERROR: Object %s nc_root changed %s => %s\n",
			GUID_string(c, &c->guid),
			ldb_dn_get_extended_linearized(c, c->nc_root, 1),
			ldb_dn_get_extended_linearized(c, op->nc_root, 1));
		return ldb_module_operr(module);
	}

	c->ref_count += 1;

	/*
	 * always use the last known parent_guid.
	 */
	c->parent_guid = op->parent_guid;

	/*
	 * Note that we only set, but don't clear values here,
	 * it means c->force_self and c->force_children can
	 * both be true in the end.
	 */
	if (op->include_self) {
		c->force_self = true;
	} else {
		c->force_children = true;
	}

	if (c->ref_count == 1) {
		struct TDB_DATA val = make_tdb_data((const void*)&c, sizeof(c));

		/*
		 * Remember the change by objectGUID in order
		 * to avoid processing it more than once.
		 */

		status = dbwrap_store(t->changes.map, key, val, TDB_INSERT);
		if (!NT_STATUS_IS_OK(status)) {
			ldb_debug(ldb, LDB_DEBUG_FATAL,
				  "dbwrap_parse_record() - %s\n",
				  nt_errstr(status));
			return ldb_module_operr(module);
		}

		DLIST_ADD_END(t->changes.list, c);
		t->changes.num_registered += 1;
	}
	t->changes.num_registrations += 1;

	return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
}