#include "libcli/security/session.h"
#include "rpc_server/drsuapi/dcesrv_drsuapi.h"
#include "rpc_server/dcerpc_server_proto.h"
+#include "rpc_server/common/sid_helper.h"
#include "../libcli/drsuapi/drsuapi.h"
#include "lib/util/binsearch.h"
#include "lib/util/tsort.h"
#include "lib/dbwrap/dbwrap_rbt.h"
#include "librpc/gen_ndr/ndr_misc.h"
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_DRS_REPL
+
/* state of a partially completed getncchanges call */
struct drsuapi_getncchanges_state {
struct db_context *anc_cache;
return true;
}
return false;
-
}
static int uint32_t_cmp(uint32_t a1, uint32_t a2)
}
}
+/*
+ * Similar to function in repl_meta_data without the extra
+ * dependencies.
+ */
+static WERROR get_parsed_dns_trusted(TALLOC_CTX *mem_ctx, struct ldb_message_element *el,
+ struct parsed_dn **pdn)
+{
+ /* Here we get a list of 'struct parsed_dns' without the parsing */
+ int i;
+ *pdn = talloc_zero_array(mem_ctx, struct parsed_dn,
+ el->num_values);
+ if (!*pdn) {
+ return WERR_DS_DRA_INTERNAL_ERROR;
+ }
+
+ for (i = 0; i < el->num_values; i++) {
+ (*pdn)[i].v = &el->values[i];
+ }
+
+ return WERR_OK;
+}
+
static WERROR getncchanges_update_revealed_list(struct ldb_context *sam_ctx,
TALLOC_CTX *mem_ctx,
struct ldb_message **msg,
struct ldb_dn *object_dn,
+ const struct GUID *object_guid,
const struct dsdb_attribute *sa,
struct replPropertyMetaData1 *meta_data,
struct ldb_message *revealed_users)
{
enum ndr_err_code ndr_err;
int ldb_err;
- unsigned i;
char *attr_str = NULL;
char *attr_hex = NULL;
DATA_BLOB attr_blob;
existing = ldb_msg_find_element(revealed_users, "msDS-RevealedUsers");
if (existing != NULL) {
/* Replace the old value (if one exists) with the current one */
- for (i = 0; i < existing->num_values; i++) {
- struct dsdb_dn *existing_dn = dsdb_dn_parse_trusted(mem_ctx, sam_ctx, &existing->values[i], DSDB_SYNTAX_BINARY_DN);
- if (ldb_dn_compare(object_dn, existing_dn->dn) == 0) {
- struct replPropertyMetaData1 existing_meta_data;
- ndr_err = ndr_pull_struct_blob_all_noalloc(&existing_dn->extra_part,
- &existing_meta_data,
- (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaData1);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ struct parsed_dn *link_dns;
+ struct parsed_dn *exact = NULL, *unused = NULL;
+ WERROR werr;
+ uint8_t attid[4];
+ DATA_BLOB partial_meta;
+
+ werr = get_parsed_dns_trusted(mem_ctx, existing, &link_dns);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ /* Construct a partial metadata blob to match on in the DB */
+ SIVAL(attid, 0, sa->attributeID_id);
+ partial_meta.length = 4;
+ partial_meta.data = attid;
+
+ /* Binary search using GUID and attribute id for uniqueness */
+ ldb_err = parsed_dn_find(sam_ctx, link_dns, existing->num_values,
+ object_guid, object_dn,
+ partial_meta, 4,
+ &exact, &unused,
+ DSDB_SYNTAX_BINARY_DN, true);
+
+ if (ldb_err != LDB_SUCCESS) {
+ DEBUG(0,(__location__ ": Failed parsed DN find - %s\n",
+ ldb_errstring(sam_ctx)));
+ return WERR_DS_DRA_INTERNAL_ERROR;
+ }
+
+ if (exact != NULL) {
+ /* Perform some verification of the blob */
+ struct replPropertyMetaData1 existing_meta_data;
+ ndr_err = ndr_pull_struct_blob_all_noalloc(&exact->dsdb_dn->extra_part,
+ &existing_meta_data,
+ (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaData1);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return WERR_DS_DRA_INTERNAL_ERROR;
+ }
+
+ if (existing_meta_data.attid == sa->attributeID_id) {
+ ldb_err = ldb_msg_add_empty(*msg, "msDS-RevealedUsers", LDB_FLAG_MOD_DELETE, &el_del);
+ if (ldb_err != LDB_SUCCESS) {
return WERR_DS_DRA_INTERNAL_ERROR;
}
- if (existing_meta_data.attid == sa->attributeID_id) {
- ldb_err = ldb_msg_add_empty(*msg, "msDS-RevealedUsers", LDB_FLAG_MOD_DELETE, &el_del);
- if (ldb_err != LDB_SUCCESS) {
- return WERR_DS_DRA_INTERNAL_ERROR;
- }
-
- el_del->values = talloc_array((*msg)->elements, struct ldb_val, 1);
- if (el_del->values == NULL) {
- return WERR_NOT_ENOUGH_MEMORY;
- }
- el_del->values[0] = existing->values[i];
- el_del->num_values = 1;
+ el_del->values = talloc_array((*msg)->elements, struct ldb_val, 1);
+ if (el_del->values == NULL) {
+ return WERR_NOT_ENOUGH_MEMORY;
}
+ el_del->values[0] = *exact->v;
+ el_del->num_values = 1;
+ } else {
+ return WERR_DS_DRA_INTERNAL_ERROR;
}
}
}
return WERR_OK;
}
+/*
+ * This function filter attributes for build_object based on the
+ * uptodatenessvector and partial attribute set.
+ *
+ * Any secret attributes are forced here for REPL_SECRET, and audited at this
+ * point with msDS-RevealedUsers.
+ */
static WERROR get_nc_changes_filter_attrs(struct drsuapi_DsReplicaObjectListItemEx *obj,
struct replPropertyMetaDataBlob md,
struct ldb_context *sam_ctx,
const struct ldb_message *msg,
+ const struct GUID *guid,
uint32_t *count,
uint64_t highest_usn,
const struct dsdb_attribute *rdn_sa,
struct dsdb_schema *schema,
+ struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector,
+ struct drsuapi_DsPartialAttributeSet *partial_attribute_set,
+ uint32_t *local_pas,
+ uint32_t *attids,
bool exop_secret,
struct ldb_message **revealed_list_msg,
- struct ldb_message *existing_revealed_list_msg,
- struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector,
- struct drsuapi_DsPartialAttributeSet *partial_attribute_set, uint32_t *local_pas,
- uint32_t *attids)
+ struct ldb_message *existing_revealed_list_msg)
{
uint32_t i, n;
WERROR werr;
sa->lDAPDisplayName, ldb_dn_get_linearized(msg->dn)));
werr = getncchanges_update_revealed_list(sam_ctx, obj,
revealed_list_msg,
- msg->dn, sa,
+ msg->dn, guid, sa,
&md.ctr.ctr1.array[i],
existing_revealed_list_msg);
if (!W_ERROR_IS_OK(werr)) {
enum drsuapi_DsExtendedOperation extended_op,
bool force_object_return,
uint32_t *local_pas,
- struct ldb_dn *machine_dn)
+ struct ldb_dn *machine_dn,
+ const struct GUID *guid)
{
const struct ldb_val *md_value;
uint32_t i, n;
unsigned int instanceType;
struct dsdb_syntax_ctx syntax_ctx;
struct ldb_result *res = NULL;
- struct ldb_message *revealed_list_msg = NULL, *existing_revealed_list_msg = NULL;
WERROR werr;
int ret;
if (extended_op == DRSUAPI_EXOP_REPL_SECRET) {
/* Get the existing revealed users for the destination */
- static const char *machine_attrs[] = { "msDS-RevealedUsers", NULL };
+ struct ldb_message *revealed_list_msg = NULL;
+ struct ldb_message *existing_revealed_list_msg = NULL;
+ const char *machine_attrs[] = {
+ "msDS-RevealedUsers",
+ NULL
+ };
revealed_list_msg = ldb_msg_new(sam_ctx);
if (revealed_list_msg == NULL) {
return WERR_DS_DRA_INTERNAL_ERROR;
}
- ldb_err = dsdb_search_dn(sam_ctx, obj, &res, machine_dn, machine_attrs, 0);
+ ldb_err = dsdb_search_dn(sam_ctx, obj, &res, machine_dn, machine_attrs, DSDB_SEARCH_SHOW_EXTENDED_DN);
if (ldb_err != LDB_SUCCESS || res->count != 1) {
ldb_transaction_cancel(sam_ctx);
return WERR_DS_DRA_INTERNAL_ERROR;
existing_revealed_list_msg = res->msgs[0];
- werr = get_nc_changes_filter_attrs(obj, md, sam_ctx, msg, &n,
- highest_usn, rdn_sa, schema,
- true,
- &revealed_list_msg,
- existing_revealed_list_msg,
+ werr = get_nc_changes_filter_attrs(obj, md, sam_ctx, msg,
+ guid, &n, highest_usn,
+ rdn_sa, schema,
uptodateness_vector,
partial_attribute_set, local_pas,
- attids);
+ attids,
+ true,
+ &revealed_list_msg,
+ existing_revealed_list_msg);
if (!W_ERROR_IS_OK(werr)) {
ldb_transaction_cancel(sam_ctx);
return werr;
return WERR_DS_DRA_INTERNAL_ERROR;
}
} else {
- werr = get_nc_changes_filter_attrs(obj, md, sam_ctx, msg, &n,
- highest_usn, rdn_sa, schema,
- false,
- &revealed_list_msg,
- existing_revealed_list_msg,
- uptodateness_vector,
+ werr = get_nc_changes_filter_attrs(obj, md, sam_ctx, msg, guid,
+ &n, highest_usn, rdn_sa,
+ schema, uptodateness_vector,
partial_attribute_set, local_pas,
- attids);
+ attids,
+ false,
+ NULL,
+ NULL);
if (!W_ERROR_IS_OK(werr)) {
return werr;
}
return WERR_OK;
}
-/*
- return an array of SIDs from a ldb_message given an attribute name
- assumes the SIDs are in extended DN format
- */
-static WERROR samdb_result_sid_array_dn(struct ldb_context *sam_ctx,
- struct ldb_message *msg,
- TALLOC_CTX *mem_ctx,
- const char *attr,
- const struct dom_sid ***sids)
-{
- struct ldb_message_element *el;
- unsigned int i;
-
- el = ldb_msg_find_element(msg, attr);
- if (!el) {
- *sids = NULL;
- return WERR_OK;
- }
-
- (*sids) = talloc_array(mem_ctx, const struct dom_sid *, el->num_values + 1);
- W_ERROR_HAVE_NO_MEMORY(*sids);
-
- for (i=0; i<el->num_values; i++) {
- struct ldb_dn *dn = ldb_dn_from_ldb_val(mem_ctx, sam_ctx, &el->values[i]);
- NTSTATUS status;
- struct dom_sid *sid;
-
- sid = talloc(*sids, struct dom_sid);
- W_ERROR_HAVE_NO_MEMORY(sid);
- status = dsdb_get_extended_dn_sid(dn, sid, "SID");
- if (!NT_STATUS_IS_OK(status)) {
- return WERR_INTERNAL_DB_CORRUPTION;
- }
- (*sids)[i] = sid;
- }
- (*sids)[i] = NULL;
-
- return WERR_OK;
-}
-
-
-/*
- return an array of SIDs from a ldb_message given an attribute name
- assumes the SIDs are in NDR form
- */
-static WERROR samdb_result_sid_array_ndr(struct ldb_context *sam_ctx,
- struct ldb_message *msg,
- TALLOC_CTX *mem_ctx,
- const char *attr,
- const struct dom_sid ***sids)
-{
- struct ldb_message_element *el;
- unsigned int i;
-
- el = ldb_msg_find_element(msg, attr);
- if (!el) {
- *sids = NULL;
- return WERR_OK;
- }
-
- (*sids) = talloc_array(mem_ctx, const struct dom_sid *, el->num_values + 1);
- W_ERROR_HAVE_NO_MEMORY(*sids);
-
- for (i=0; i<el->num_values; i++) {
- enum ndr_err_code ndr_err;
- struct dom_sid *sid;
-
- sid = talloc(*sids, struct dom_sid);
- W_ERROR_HAVE_NO_MEMORY(sid);
-
- ndr_err = ndr_pull_struct_blob(&el->values[i], sid, sid,
- (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- return WERR_INTERNAL_DB_CORRUPTION;
- }
- (*sids)[i] = sid;
- }
- (*sids)[i] = NULL;
-
- return WERR_OK;
-}
-
-/*
- see if any SIDs in list1 are in list2
- */
-static bool sid_list_match(const struct dom_sid **list1, const struct dom_sid **list2)
-{
- unsigned int i, j;
- /* do we ever have enough SIDs here to worry about O(n^2) ? */
- for (i=0; list1[i]; i++) {
- for (j=0; list2[j]; j++) {
- if (dom_sid_equal(list1[i], list2[j])) {
- return true;
- }
- }
- }
- return false;
-}
-
/*
handle a DRSUAPI_EXOP_REPL_SECRET call
*/
int ret;
const char *rodc_attrs[] = { "msDS-KrbTgtLink", "msDS-NeverRevealGroup", "msDS-RevealOnDemandGroup", "objectGUID", NULL };
const char *obj_attrs[] = { "tokenGroups", "objectSid", "UserAccountControl", "msDS-KrbTgtLinkBL", NULL };
- struct ldb_result *rodc_res, *obj_res;
+ struct ldb_result *rodc_res = NULL, *obj_res = NULL;
const struct dom_sid **never_reveal_sids, **reveal_sids, **token_sids;
+ const struct dom_sid *object_sid = NULL;
WERROR werr;
+ const struct dom_sid *additional_sids[] = { NULL, NULL };
DEBUG(3,(__location__ ": DRSUAPI_EXOP_REPL_SECRET extended op on %s\n",
drs_ObjectIdentifier_to_string(mem_ctx, ncRoot)));
if (b_state->sam_ctx_system == NULL) {
/* this operation needs system level access */
ctr6->extended_ret = DRSUAPI_EXOP_ERR_ACCESS_DENIED;
- return WERR_DS_DRA_SOURCE_DISABLED;
+ return WERR_DS_DRA_ACCESS_DENIED;
}
/*
* Which basically means that if you have GET_ALL_CHANGES rights (~== RWDC)
* then you can do EXOP_REPL_SECRETS
*/
+ obj_dn = drs_ObjectIdentifier_to_dn(mem_ctx, b_state->sam_ctx_system, ncRoot);
+ if (!ldb_dn_validate(obj_dn)) goto failed;
+
if (has_get_all_changes) {
goto allowed;
}
- obj_dn = drs_ObjectIdentifier_to_dn(mem_ctx, b_state->sam_ctx_system, ncRoot);
- if (!ldb_dn_validate(obj_dn)) goto failed;
-
rodc_dn = ldb_dn_new_fmt(mem_ctx, b_state->sam_ctx_system, "<SID=%s>",
dom_sid_string(mem_ctx, user_sid));
if (!ldb_dn_validate(rodc_dn)) goto failed;
if (ret != LDB_SUCCESS || obj_res->count != 1) goto failed;
/* if the object SID is equal to the user_sid, allow */
- if (dom_sid_equal(user_sid,
- samdb_result_dom_sid(mem_ctx, obj_res->msgs[0], "objectSid"))) {
+ object_sid = samdb_result_dom_sid(mem_ctx, obj_res->msgs[0], "objectSid");
+ if (dom_sid_equal(user_sid, object_sid)) {
goto allowed;
}
+ additional_sids[0] = object_sid;
+
/*
* Must be an RODC account at this point, verify machine DN matches the
* SID account
goto denied;
}
+ /*
+ * The SID list needs to include itself as well as the tokenGroups.
+ *
+ * TODO determine if sIDHistory is required for this check
+ */
werr = samdb_result_sid_array_ndr(b_state->sam_ctx_system, obj_res->msgs[0],
- mem_ctx, "tokenGroups", &token_sids);
+ mem_ctx, "tokenGroups", &token_sids,
+ additional_sids, 1);
if (!W_ERROR_IS_OK(werr) || token_sids==NULL) {
goto denied;
}
allowed:
DEBUG(2,(__location__ ": Allowed single object with secret replication for %s by %s %s\n",
ldb_dn_get_linearized(obj_dn), has_get_all_changes?"RWDC":"RODC",
- ldb_dn_get_linearized(rodc_res->msgs[0]->dn)));
+ ldb_dn_get_linearized(*machine_dn)));
ctr6->extended_ret = DRSUAPI_EXOP_ERR_SUCCESS;
req10->highwatermark.highest_usn = 0;
return WERR_OK;
uint32_t link_total = 0;
uint32_t link_given = 0;
struct ldb_dn *search_dn = NULL;
- bool am_rodc, null_scope=false;
+ bool am_rodc;
enum security_user_level security_level;
struct ldb_context *sam_ctx;
struct dom_sid *user_sid;
DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
b_state = h->data;
+ /* sam_ctx_system is not present for non-administrator users */
sam_ctx = b_state->sam_ctx_system?b_state->sam_ctx_system:b_state->sam_ctx;
invocation_id = *(samdb_ntds_invocation_id(sam_ctx));
user_sid = &dce_call->conn->auth_state.session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
/* all clients must have GUID_DRS_GET_CHANGES */
- werr = drs_security_access_check_nc_root(b_state->sam_ctx,
+ werr = drs_security_access_check_nc_root(sam_ctx,
mem_ctx,
dce_call->conn->auth_state.session_info->security_token,
req10->naming_context,
return werr;
}
if (is_gc_pas_request) {
- werr = drs_security_access_check_nc_root(b_state->sam_ctx,
+ werr = drs_security_access_check_nc_root(sam_ctx,
mem_ctx,
dce_call->conn->auth_state.session_info->security_token,
req10->naming_context,
return werr;
}
if (is_secret_request) {
- werr = drs_security_access_check_nc_root(b_state->sam_ctx,
+ werr = drs_security_access_check_nc_root(sam_ctx,
mem_ctx,
dce_call->conn->auth_state.session_info->security_token,
req10->naming_context,
ldb_dn_get_linearized(new_dn),
ldb_dn_get_linearized(getnc_state->ncRoot_dn),
ldb_dn_get_linearized(getnc_state->last_dn)));
- talloc_free(getnc_state);
- getnc_state = NULL;
+ TALLOC_FREE(getnc_state);
+ b_state->getncchanges_state = NULL;
}
}
ldb_dn_get_linearized(getnc_state->ncRoot_dn),
(ret > 0) ? "older" : "newer",
ldb_dn_get_linearized(getnc_state->last_dn)));
- talloc_free(getnc_state);
- getnc_state = NULL;
+ TALLOC_FREE(getnc_state);
+ b_state->getncchanges_state = NULL;
}
}
if (getnc_state == NULL) {
- getnc_state = talloc_zero(b_state, struct drsuapi_getncchanges_state);
- if (getnc_state == NULL) {
- return WERR_NOT_ENOUGH_MEMORY;
- }
- b_state->getncchanges_state = getnc_state;
- getnc_state->ncRoot_dn = drs_ObjectIdentifier_to_dn(getnc_state, sam_ctx, ncRoot);
- if (getnc_state->ncRoot_dn == NULL) {
+ struct ldb_result *res = NULL;
+ const char *attrs[] = {
+ "instanceType",
+ "objectGuID",
+ NULL
+ };
+ uint32_t nc_instanceType;
+ struct ldb_dn *ncRoot_dn;
+
+ ncRoot_dn = drs_ObjectIdentifier_to_dn(mem_ctx, sam_ctx, ncRoot);
+ if (ncRoot_dn == NULL) {
return WERR_NOT_ENOUGH_MEMORY;
}
- ret = dsdb_find_guid_by_dn(b_state->sam_ctx_system,
- getnc_state->ncRoot_dn,
- &getnc_state->ncRoot_guid);
+ ret = dsdb_search_dn(sam_ctx, mem_ctx, &res,
+ ncRoot_dn, attrs,
+ DSDB_SEARCH_SHOW_DELETED |
+ DSDB_SEARCH_SHOW_RECYCLED);
if (ret != LDB_SUCCESS) {
- DEBUG(0,(__location__ ": Failed to find GUID of ncRoot_dn %s\n",
- ldb_dn_get_linearized(getnc_state->ncRoot_dn)));
- return WERR_DS_DRA_INTERNAL_ERROR;
+ DBG_WARNING("Failed to find ncRoot_dn %s\n",
+ ldb_dn_get_linearized(ncRoot_dn));
+ return WERR_DS_DRA_BAD_DN;
}
- ncRoot->guid = getnc_state->ncRoot_guid;
-
- /* find out if we are to replicate Schema NC */
- ret = ldb_dn_compare_base(ldb_get_schema_basedn(b_state->sam_ctx),
- getnc_state->ncRoot_dn);
-
- getnc_state->is_schema_nc = (0 == ret);
+ nc_instanceType = ldb_msg_find_attr_as_int(res->msgs[0],
+ "instanceType",
+ 0);
if (req10->extended_op != DRSUAPI_EXOP_NONE) {
r->out.ctr->ctr6.extended_ret = DRSUAPI_EXOP_ERR_SUCCESS;
*/
switch (req10->extended_op) {
case DRSUAPI_EXOP_NONE:
+ if ((nc_instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0) {
+ const char *dn_str
+ = ldb_dn_get_linearized(ncRoot_dn);
+
+ DBG_NOTICE("Rejecting full replication on "
+ "not NC %s", dn_str);
+
+ return WERR_DS_CANT_FIND_EXPECTED_NC;
+ }
+
break;
case DRSUAPI_EXOP_FSMO_RID_ALLOC:
werr = getncchanges_rid_alloc(b_state, mem_ctx, req10, &r->out.ctr->ctr6, &search_dn);
(unsigned)req10->extended_op));
return WERR_DS_DRA_NOT_SUPPORTED;
}
+
+ /* Initialize the state we'll store over the replication cycle */
+ getnc_state = talloc_zero(b_state, struct drsuapi_getncchanges_state);
+ if (getnc_state == NULL) {
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+ b_state->getncchanges_state = getnc_state;
+
+ getnc_state->ncRoot_dn = ncRoot_dn;
+ talloc_steal(getnc_state, ncRoot_dn);
+
+ getnc_state->ncRoot_guid = samdb_result_guid(res->msgs[0],
+ "objectGUID");
+ ncRoot->guid = getnc_state->ncRoot_guid;
+
+ /* find out if we are to replicate Schema NC */
+ ret = ldb_dn_compare_base(ldb_get_schema_basedn(sam_ctx),
+ ncRoot_dn);
+ getnc_state->is_schema_nc = (0 == ret);
+
+ TALLOC_FREE(res);
}
if (!ldb_dn_validate(getnc_state->ncRoot_dn) ||
extra_filter = lpcfg_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "drs", "object filter");
- if (req10->uptodateness_vector != NULL) {
- udv = req10->uptodateness_vector;
- } else {
- udv = &empty_udv;
- }
+ if (req10->extended_op == DRSUAPI_EXOP_NONE) {
+ if (req10->uptodateness_vector != NULL) {
+ udv = req10->uptodateness_vector;
+ } else {
+ udv = &empty_udv;
+ }
- getnc_state->min_usn = req10->highwatermark.highest_usn;
- for (i = 0; i < udv->count; i++) {
- bool match;
- const struct drsuapi_DsReplicaCursor *cur =
- &udv->cursors[i];
+ getnc_state->min_usn = req10->highwatermark.highest_usn;
+ for (i = 0; i < udv->count; i++) {
+ bool match;
+ const struct drsuapi_DsReplicaCursor *cur =
+ &udv->cursors[i];
- match = GUID_equal(&invocation_id,
- &cur->source_dsa_invocation_id);
- if (!match) {
- continue;
- }
- if (cur->highest_usn > getnc_state->min_usn) {
- getnc_state->min_usn = cur->highest_usn;
+ match = GUID_equal(&invocation_id,
+ &cur->source_dsa_invocation_id);
+ if (!match) {
+ continue;
+ }
+ if (cur->highest_usn > getnc_state->min_usn) {
+ getnc_state->min_usn = cur->highest_usn;
+ }
+ break;
}
- break;
+ } else {
+ /* We do not want REPL_SECRETS or REPL_SINGLE to return empty-handed */
+ udv = &empty_udv;
+ getnc_state->min_usn = 0;
}
+
getnc_state->max_usn = getnc_state->min_usn;
getnc_state->final_udv = talloc_zero(getnc_state,
struct dsdb_syntax_ctx syntax_ctx;
uint32_t j = 0;
- dsdb_syntax_ctx_init(&syntax_ctx, b_state->sam_ctx, schema);
+ dsdb_syntax_ctx_init(&syntax_ctx, sam_ctx, schema);
syntax_ctx.pfm_remote = pfm_remote;
local_pas = talloc_array(b_state, uint32_t, req10->partial_attribute_set->num_attids);
for (i=getnc_state->num_processed;
i<getnc_state->num_records &&
- !null_scope &&
(r->out.ctr->ctr6.object_count < max_objects)
&& !max_wait_reached;
i++) {
W_ERROR_HAVE_NO_MEMORY(msg_dn);
- /* by re-searching here we avoid having a lot of full
- * records in memory between calls to getncchanges
+ /*
+ * by re-searching here we avoid having a lot of full
+ * records in memory between calls to getncchanges.
+ *
+ * We expect that we may get some objects that vanish
+ * (tombstone expunge) between the first and second
+ * check.
*/
ret = drsuapi_search_with_extended_dn(sam_ctx, obj, &msg_res,
msg_dn,
continue;
}
+ if (msg_res->count == 0) {
+ DEBUG(1,("getncchanges: got LDB_SUCCESS but failed"
+ "to get any results in fetch of DN "
+ "%s (race with tombstone expunge?)\n",
+ ldb_dn_get_extended_linearized(obj,
+ msg_dn, 1)));
+ talloc_free(obj);
+ continue;
+ }
+
msg = msg_res->msgs[0];
/*
req10->uptodateness_vector,
req10->extended_op,
max_wait_reached,
- local_pas, machine_dn);
+ local_pas, machine_dn,
+ &getnc_state->guids[i]);
if (!W_ERROR_IS_OK(werr)) {
return werr;
}
req10->extended_op,
false, /* force_object_return */
local_pas,
- machine_dn);
+ machine_dn,
+ next_anc_guid);
if (!W_ERROR_IS_OK(werr)) {
return werr;
}
DEBUG(3,("UpdateRefs on getncchanges for %s\n",
GUID_string(mem_ctx, &req10->destination_dsa_guid)));
ureq.naming_context = ncRoot;
- ureq.dest_dsa_dns_name = samdb_ntds_msdcs_dns_name(b_state->sam_ctx, mem_ctx,
+ ureq.dest_dsa_dns_name = samdb_ntds_msdcs_dns_name(sam_ctx, mem_ctx,
&req10->destination_dsa_guid);
if (!ureq.dest_dsa_dns_name) {
return WERR_NOT_ENOUGH_MEMORY;
to send notifies using the GC SPN */
ureq.options |= (req10->replica_flags & DRSUAPI_DRS_REF_GCSPN);
- werr = drsuapi_UpdateRefs(b_state, mem_ctx, &ureq);
+ werr = drsuapi_UpdateRefs(dce_call->msg_ctx,
+ dce_call->event_ctx, b_state,
+ mem_ctx, &ureq);
if (!W_ERROR_IS_OK(werr)) {
DEBUG(0,(__location__ ": Failed UpdateRefs on %s for %s in DsGetNCChanges - %s\n",
drs_ObjectIdentifier_to_string(mem_ctx, ncRoot), ureq.dest_dsa_dns_name,