summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2010-08-18 14:31:05 +1000
committerAndrew Tridgell <tridge@samba.org>2010-08-20 20:34:11 +1000
commitc12293991988bda16ff85135e83c21d23d08abca (patch)
tree674ac9323cc77f0cdb9a0ca638ce51d34a9660ba
parentdc7cf47371e15a1bfe8c97341773076f00c67aa1 (diff)
downloadsamba-c12293991988bda16ff85135e83c21d23d08abca.tar.gz
samba-c12293991988bda16ff85135e83c21d23d08abca.tar.bz2
samba-c12293991988bda16ff85135e83c21d23d08abca.zip
s4-drs: implement RODC attribute filtering override
When a RODC uses extended getncchanges operation DRSUAPI_EXOP_REPL_SECRET it gets an override on the ability to replicate the secret attributes. Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
-rw-r--r--source4/dsdb/common/util.c44
-rw-r--r--source4/rpc_server/drsuapi/getncchanges.c74
2 files changed, 79 insertions, 39 deletions
diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c
index cf13b64e07..7c2414a23f 100644
--- a/source4/dsdb/common/util.c
+++ b/source4/dsdb/common/util.c
@@ -3940,29 +3940,43 @@ int dsdb_validate_dsa_guid(struct ldb_context *ldb,
return LDB_SUCCESS;
}
-const char *rodc_fas_list[] = {"ms-PKI-DPAPIMasterKeys",
- "ms-PKI-AccountCredentials",
- "ms-PKI-RoamingTimeStamp",
- "ms-FVE-KeyPackage",
- "ms-FVE-RecoveryGuid",
- "ms-FVE-RecoveryInformation",
- "ms-FVE-RecoveryPassword",
- "ms-FVE-VolumeGuid",
- "ms-TPM-OwnerInformation",
- NULL};
+static const char *secret_attributes[] = {
+ "currentValue",
+ "dBCSPwd",
+ "initialAuthIncoming",
+ "initialAuthOutgoing",
+ "lmPwdHistory",
+ "ntPwdHistory",
+ "priorValue",
+ "supplementalCredentials",
+ "trustAuthIncoming",
+ "trustAuthOutgoing",
+ "unicodePwd",
+ NULL
+};
+
/*
check if the attribute belongs to the RODC filtered attribute set
+ Note that attributes that are in the filtered attribute set are the
+ ones that _are_ always sent to a RODC
*/
-bool dsdb_attr_in_rodc_fas(uint32_t replica_flags, const struct dsdb_attribute *sa)
+bool dsdb_attr_in_rodc_fas(const struct dsdb_attribute *sa)
{
- int rodc_filtered_flags = SEARCH_FLAG_RODC_ATTRIBUTE | SEARCH_FLAG_CONFIDENTIAL;
- bool drs_write_replica = ((replica_flags & DRSUAPI_DRS_WRIT_REP) == 0);
+ /* they never get secret attributes */
+ if (is_attr_in_list(secret_attributes, sa->lDAPDisplayName)) {
+ return false;
+ }
- if (drs_write_replica && (sa->searchFlags & rodc_filtered_flags)) {
+ /* they do get non-secret critical attributes */
+ if (sa->schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) {
return true;
}
- if (drs_write_replica && is_attr_in_list(rodc_fas_list, sa->cn)) {
+
+ /* they do get non-secret attributes marked as being in the FAS */
+ if (sa->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
return true;
}
+
+ /* other attributes are denied */
return false;
}
diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c
index 23edf6d4b4..779b7c78f9 100644
--- a/source4/rpc_server/drsuapi/getncchanges.c
+++ b/source4/rpc_server/drsuapi/getncchanges.c
@@ -95,7 +95,8 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem
DATA_BLOB *session_key,
uint64_t highest_usn,
uint32_t replica_flags,
- struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector)
+ struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector,
+ enum drsuapi_DsExtendedOperation extended_op)
{
const struct ldb_val *md_value;
unsigned int i, n;
@@ -177,9 +178,12 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem
obj->meta_data_ctr->meta_data = talloc_array(obj, struct drsuapi_DsReplicaMetaData, md.ctr.ctr1.count);
for (n=i=0; i<md.ctr.ctr1.count; i++) {
const struct dsdb_attribute *sa;
+ bool force_attribute = false;
+
/* if the attribute has not changed, and it is not the
instanceType then don't include it */
if (md.ctr.ctr1.array[i].local_usn < highest_usn &&
+ extended_op != DRSUAPI_EXOP_REPL_SECRET &&
md.ctr.ctr1.array[i].attid != DRSUAPI_ATTRIBUTE_instanceType) continue;
/* don't include the rDN */
@@ -202,8 +206,16 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem
}
}
+ if (extended_op == DRSUAPI_EXOP_REPL_SECRET &&
+ !dsdb_attr_in_rodc_fas(sa)) {
+ force_attribute = true;
+ DEBUG(4,("Forcing attribute %s in %s\n",
+ sa->lDAPDisplayName, ldb_dn_get_linearized(msg->dn)));
+ }
+
/* filter by uptodateness_vector */
if (md.ctr.ctr1.array[i].attid != DRSUAPI_ATTRIBUTE_instanceType &&
+ !force_attribute &&
udv_filter(uptodateness_vector,
&md.ctr.ctr1.array[i].originating_invocation_id,
md.ctr.ctr1.array[i].originating_usn)) {
@@ -211,15 +223,20 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem
}
/*
- * If the recipient is a RODC, then we should not add any
- * RODC filtered attribute
+ * If the recipient is a RODC, then we should only give
+ * attributes from the RODC filtered attribute set
*
* 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)) {
+ if (!(replica_flags & DRSUAPI_DRS_WRIT_REP) &&
+ !force_attribute &&
+ !dsdb_attr_in_rodc_fas(sa)) {
+ DEBUG(4,("Skipping non-FAS attr %s in %s\n",
+ sa->lDAPDisplayName,
+ ldb_dn_get_linearized(msg->dn)));
continue;
}
@@ -718,10 +735,13 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
struct ldb_dn *search_dn = NULL;
bool am_rodc;
enum security_user_level security_level;
+ struct ldb_context *sam_ctx;
DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
b_state = h->data;
+ sam_ctx = b_state->sam_ctx_system?b_state->sam_ctx_system:b_state->sam_ctx;
+
*r->out.level_out = 6;
/* TODO: linked attributes*/
r->out.ctr->ctr6.linked_attributes_count = 0;
@@ -733,7 +753,7 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
r->out.ctr->ctr6.uptodateness_vector = NULL;
/* a RODC doesn't allow for any replication */
- ret = samdb_rodc(b_state->sam_ctx, &am_rodc);
+ ret = samdb_rodc(sam_ctx, &am_rodc);
if (ret == LDB_SUCCESS && am_rodc) {
DEBUG(0,(__location__ ": DsGetNCChanges attempt on RODC\n"));
return WERR_DS_DRA_SOURCE_DISABLED;
@@ -759,7 +779,7 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
return WERR_DS_DRA_INVALID_PARAMETER;
}
- if (samdb_ntds_options(b_state->sam_ctx, &options) != LDB_SUCCESS) {
+ if (samdb_ntds_options(sam_ctx, &options) != LDB_SUCCESS) {
return WERR_DS_DRA_INTERNAL_ERROR;
}
@@ -769,7 +789,7 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
}
werr = drs_security_level_check(dce_call, "DsGetNCChanges", SECURITY_RO_DOMAIN_CONTROLLER,
- samdb_domain_sid(b_state->sam_ctx));
+ samdb_domain_sid(sam_ctx));
if (!W_ERROR_IS_OK(werr)) {
return werr;
}
@@ -777,9 +797,10 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
/* 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));
+ samdb_domain_sid(sam_ctx));
if (security_level == SECURITY_RO_DOMAIN_CONTROLLER &&
- (req8->replica_flags & DRSUAPI_DRS_WRIT_REP)) {
+ (req8->replica_flags & DRSUAPI_DRS_WRIT_REP) &&
+ req8->extended_op != DRSUAPI_EXOP_REPL_SECRET) {
DEBUG(3,(__location__ ": Removing WRIT_REP flag for replication by RODC %s\n",
dom_sid_string(mem_ctx,
dce_call->conn->auth_state.session_info->security_token->sids[PRIMARY_USER_SID_INDEX])));
@@ -800,15 +821,19 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
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 = ldb_get_default_basedn(b_state->sam_ctx);
+ search_dn = ldb_get_default_basedn(sam_ctx);
break;
+ case DRSUAPI_EXOP_REPL_SECRET:
+ DEBUG(0,(__location__ ": DRSUAPI_EXOP_REPL_SECRET extended op\n"));
+ r->out.ctr->ctr6.extended_ret = DRSUAPI_EXOP_ERR_SUCCESS;
+ req8->highwatermark.highest_usn = 0;
+ break;
case DRSUAPI_EXOP_FSMO_REQ_ROLE:
case DRSUAPI_EXOP_FSMO_RID_REQ_ROLE:
case DRSUAPI_EXOP_FSMO_REQ_PDC:
case DRSUAPI_EXOP_FSMO_ABANDON_ROLE:
case DRSUAPI_EXOP_REPL_OBJ:
- case DRSUAPI_EXOP_REPL_SECRET:
DEBUG(0,(__location__ ": Request for DsGetNCChanges unsupported extended op 0x%x\n",
(unsigned)req8->extended_op));
return WERR_DS_DRA_NOT_SUPPORTED;
@@ -818,7 +843,7 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
/* see if a previous replication has been abandoned */
if (getnc_state) {
- struct ldb_dn *new_dn = ldb_dn_new(getnc_state, b_state->sam_ctx, ncRoot->dn);
+ struct ldb_dn *new_dn = ldb_dn_new(getnc_state, sam_ctx, ncRoot->dn);
if (ldb_dn_compare(new_dn, getnc_state->ncRoot_dn) != 0) {
DEBUG(0,(__location__ ": DsGetNCChanges 2nd replication on different DN %s %s (last_dn %s)\n",
ldb_dn_get_linearized(new_dn),
@@ -835,7 +860,7 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
return WERR_NOMEM;
}
b_state->getncchanges_state = getnc_state;
- getnc_state->ncRoot_dn = ldb_dn_new(getnc_state, b_state->sam_ctx, ncRoot->dn);
+ getnc_state->ncRoot_dn = ldb_dn_new(getnc_state, sam_ctx, ncRoot->dn);
/* find out if we are to replicate Schema NC */
ret = ldb_dn_compare(getnc_state->ncRoot_dn,
@@ -894,7 +919,7 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
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,
+ ret = drsuapi_search_with_extended_dn(sam_ctx, getnc_state, &getnc_state->site_res,
search_dn, scope, attrs,
search_filter);
if (ret != LDB_SUCCESS) {
@@ -921,7 +946,7 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
}
/* Prefix mapping */
- schema = dsdb_get_schema(b_state->sam_ctx, mem_ctx);
+ schema = dsdb_get_schema(sam_ctx, mem_ctx);
if (!schema) {
DEBUG(0,("No schema in sam_ctx\n"));
return WERR_DS_DRA_INTERNAL_ERROR;
@@ -930,7 +955,7 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
r->out.ctr->ctr6.naming_context = talloc(mem_ctx, struct drsuapi_DsReplicaObjectIdentifier);
*r->out.ctr->ctr6.naming_context = *ncRoot;
- if (dsdb_find_guid_by_dn(b_state->sam_ctx, getnc_state->ncRoot_dn,
+ if (dsdb_find_guid_by_dn(sam_ctx, getnc_state->ncRoot_dn,
&r->out.ctr->ctr6.naming_context->guid) != LDB_SUCCESS) {
DEBUG(0,(__location__ ": Failed to find GUID of ncRoot_dn %s\n",
ldb_dn_get_linearized(getnc_state->ncRoot_dn)));
@@ -938,13 +963,13 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
}
/* find the SID if there is one */
- dsdb_find_sid_by_dn(b_state->sam_ctx, getnc_state->ncRoot_dn, &r->out.ctr->ctr6.naming_context->sid);
+ dsdb_find_sid_by_dn(sam_ctx, getnc_state->ncRoot_dn, &r->out.ctr->ctr6.naming_context->sid);
dsdb_get_oid_mappings_drsuapi(schema, true, mem_ctx, &ctr);
r->out.ctr->ctr6.mapping_ctr = *ctr;
- r->out.ctr->ctr6.source_dsa_guid = *(samdb_ntds_objectGUID(b_state->sam_ctx));
- r->out.ctr->ctr6.source_dsa_invocation_id = *(samdb_ntds_invocation_id(b_state->sam_ctx));
+ r->out.ctr->ctr6.source_dsa_guid = *(samdb_ntds_objectGUID(sam_ctx));
+ r->out.ctr->ctr6.source_dsa_invocation_id = *(samdb_ntds_invocation_id(sam_ctx));
r->out.ctr->ctr6.old_highwatermark = req8->highwatermark;
r->out.ctr->ctr6.new_highwatermark = req8->highwatermark;
@@ -975,15 +1000,16 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
obj = talloc_zero(mem_ctx, struct drsuapi_DsReplicaObjectListItemEx);
werr = get_nc_changes_build_object(obj, msg,
- b_state->sam_ctx, getnc_state->ncRoot_dn,
+ sam_ctx, getnc_state->ncRoot_dn,
getnc_state->is_schema_nc,
schema, &session_key, getnc_state->min_usn,
- req8->replica_flags, getnc_state->uptodateness_vector);
+ req8->replica_flags, getnc_state->uptodateness_vector,
+ req8->extended_op);
if (!W_ERROR_IS_OK(werr)) {
return werr;
}
- werr = get_nc_changes_add_links(b_state->sam_ctx, getnc_state,
+ werr = get_nc_changes_add_links(sam_ctx, getnc_state,
getnc_state->ncRoot_dn,
schema, getnc_state->min_usn,
req8->replica_flags,
@@ -1071,7 +1097,7 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
/* 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);
+ sam_ctx, linked_attribute_compare);
getnc_state->la_sorted = true;
}
@@ -1095,7 +1121,7 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
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;
- werr = get_nc_changes_udv(b_state->sam_ctx, getnc_state->ncRoot_dn,
+ werr = get_nc_changes_udv(sam_ctx, getnc_state->ncRoot_dn,
r->out.ctr->ctr6.uptodateness_vector);
if (!W_ERROR_IS_OK(werr)) {
return werr;