#include "libcli/security/security.h"
#include "lib/util/binsearch.h"
#include "lib/util/tsort.h"
+#include "auth/session.h"
/*
build a DsReplicaObjectIdentifier from a ldb msg
return WERR_OK;
}
- ndr_err = ndr_pull_struct_blob(md_value, obj,
- lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")), &md,
+ if (instanceType & INSTANCE_TYPE_UNINSTANT) {
+ /* don't send uninstantiated objects */
+ return WERR_OK;
+ }
+
+ ndr_err = ndr_pull_struct_blob(md_value, obj, &md,
(ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
return WERR_DS_DRA_INTERNAL_ERROR;
continue;
}
+ /*
+ * If the recipient is a RODC, then we should not add any
+ * RODC filtered attribute
+ *
+ * TODO: This is not strictly correct, as it doesn't allow for administrators
+ * to setup some users to transfer passwords to specific RODCs. To support that
+ * we would instead remove this check and rely on extended ACL checking in the dsdb
+ * acl module.
+ */
+ if (dsdb_attr_in_rodc_fas(replica_flags, sa)) {
+ 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;
struct ldb_dn *last_dn;
struct drsuapi_DsReplicaLinkedAttribute *la_list;
uint32_t la_count;
+ bool la_sorted;
+ uint32_t la_idx;
struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;
};
struct drsuapi_DsGetNCChangesRequest8 *req8;
uint32_t options;
uint32_t max_objects;
+ uint32_t max_links;
+ uint32_t link_count = 0;
+ uint32_t link_total = 0;
+ uint32_t link_given = 0;
struct ldb_dn *search_dn = NULL;
+ bool am_rodc;
+ enum security_user_level security_level;
DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
b_state = h->data;
r->out.ctr->ctr6.uptodateness_vector = NULL;
/* a RODC doesn't allow for any replication */
- if (samdb_rodc(b_state->sam_ctx)) {
+ ret = samdb_rodc(b_state->sam_ctx, &am_rodc);
+ if (ret == LDB_SUCCESS && am_rodc) {
DEBUG(0,(__location__ ": DsGetNCChanges attempt on RODC\n"));
return WERR_DS_DRA_SOURCE_DISABLED;
}
return WERR_DS_DRA_SOURCE_DISABLED;
}
+ werr = drs_security_level_check(dce_call, "DsGetNCChanges", SECURITY_RO_DOMAIN_CONTROLLER,
+ samdb_domain_sid(b_state->sam_ctx));
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ /* for non-administrator replications, check that they have
+ given the correct source_dsa_invocation_id */
+ security_level = security_session_user_level(dce_call->conn->auth_state.session_info,
+ samdb_domain_sid(b_state->sam_ctx));
+ if (security_level == SECURITY_RO_DOMAIN_CONTROLLER &&
+ (req8->replica_flags & DRSUAPI_DRS_WRIT_REP)) {
+ DEBUG(0,(__location__ ": Attempt to do writeable replication by RODC %s\n",
+ dom_sid_string(mem_ctx,
+ dce_call->conn->auth_state.session_info->security_token->user_sid)));
+ return WERR_DS_DRA_INVALID_PARAMETER;
+ }
+
if (req8->replica_flags & DRSUAPI_DRS_FULL_SYNC_PACKET) {
/* Ignore the _in_ uptpdateness vector*/
req8->uptodateness_vector = NULL;
}
- werr = drs_security_level_check(dce_call, "DsGetNCChanges");
- if (!W_ERROR_IS_OK(werr)) {
- return werr;
- }
-
/* we don't yet support extended operations */
switch (req8->extended_op) {
case DRSUAPI_EXOP_NONE:
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");
+ extra_filter = lpcfg_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "drs", "object filter");
getnc_state->min_usn = req8->highwatermark.highest_usn;
/* 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);
+ max_objects = lpcfg_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;
}
+ /*
+ * TODO: work out how the maximum should be calculated
+ */
+ max_links = lpcfg_parm_int(dce_call->conn->dce_ctx->lp_ctx, NULL, "drs", "max link sync", 1500);
for(i=getnc_state->num_sent;
i<getnc_state->site_res->count &&
/* the client can us to call UpdateRefs on its behalf to
re-establish monitoring of the NC */
- if ((req8->replica_flags & DRSUAPI_DRS_ADD_REF) &&
+ if ((req8->replica_flags & (DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_REF_GCSPN)) &&
!GUID_all_zero(&req8->destination_dsa_guid)) {
struct drsuapi_DsReplicaUpdateRefsRequest1 ureq;
+ DEBUG(3,("UpdateRefs on getncchanges for %s\n",
+ GUID_string(mem_ctx, &req8->destination_dsa_guid)));
ureq.naming_context = ncRoot;
ureq.dest_dsa_dns_name = talloc_asprintf(mem_ctx, "%s._msdcs.%s",
GUID_string(mem_ctx, &req8->destination_dsa_guid),
- lp_realm(dce_call->conn->dce_ctx->lp_ctx));
+ lpcfg_realm(dce_call->conn->dce_ctx->lp_ctx));
if (!ureq.dest_dsa_dns_name) {
return WERR_NOMEM;
}
}
}
+ /*
+ * TODO:
+ * This is just a guess, how to calculate the
+ * number of linked attributes to send, we need to
+ * find out how to do this right.
+ */
+ if (r->out.ctr->ctr6.object_count >= max_links) {
+ max_links = 0;
+ } else {
+ max_links -= r->out.ctr->ctr6.object_count;
+ }
+
+ link_total = getnc_state->la_count;
+
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);
+ /* sort the whole array the first time */
+ if (!getnc_state->la_sorted) {
+ LDB_TYPESAFE_QSORT(getnc_state->la_list, getnc_state->la_count,
+ b_state->sam_ctx, linked_attribute_compare);
+ getnc_state->la_sorted = true;
+ }
+
+ link_count = getnc_state->la_count - getnc_state->la_idx;
+ link_count = MIN(max_links, link_count);
+
+ r->out.ctr->ctr6.linked_attributes_count = link_count;
+ r->out.ctr->ctr6.linked_attributes = getnc_state->la_list + getnc_state->la_idx;
+
+ getnc_state->la_idx += link_count;
+ link_given = getnc_state->la_idx;
- LDB_TYPESAFE_QSORT(r->out.ctr->ctr6.linked_attributes, r->out.ctr->ctr6.linked_attributes_count,
- b_state->sam_ctx, linked_attribute_compare);
+ if (getnc_state->la_idx < getnc_state->la_count) {
+ r->out.ctr->ctr6.more_data = true;
+ }
+ }
+
+ if (!r->out.ctr->ctr6.more_data) {
+ talloc_steal(mem_ctx, getnc_state->la_list);
r->out.ctr->ctr6.uptodateness_vector = talloc(mem_ctx, struct drsuapi_DsReplicaCursor2CtrEx);
r->out.ctr->ctr6.new_highwatermark.highest_usn = r->out.ctr->ctr6.new_highwatermark.tmp_highest_usn;
}
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",
+ ("DsGetNCChanges with uSNChanged >= %llu flags 0x%08x on %s gave %u objects (done %u/%u) %u links (done %u/%u)\n",
(unsigned long long)(req8->highwatermark.highest_usn+1),
- req8->replica_flags,
- ncRoot->dn, r->out.ctr->ctr6.object_count,
+ 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));
+ r->out.ctr->ctr6.linked_attributes_count,
+ link_given, link_total));
#if 0
if (!r->out.ctr->ctr6.more_data) {