summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2010-09-29 15:49:15 -0700
committerAndrew Tridgell <tridge@samba.org>2010-09-29 16:36:22 -0700
commit1ec5f5c09cc0e61fc41de720820ccddf6f6259e6 (patch)
tree139b2ad038c755c5020989a5a96ef9ecff1e2dfa
parenteebe5e1251cb99c1ca2ae4280d72a4c3baea8607 (diff)
downloadsamba-1ec5f5c09cc0e61fc41de720820ccddf6f6259e6.tar.gz
samba-1ec5f5c09cc0e61fc41de720820ccddf6f6259e6.tar.bz2
samba-1ec5f5c09cc0e61fc41de720820ccddf6f6259e6.zip
s4-drs: implement PAS checks and access checks for getncchanges
This implements partial attribute set checking on getncchanges. If the client sends a partial_attribute_set then we only return the specified attributes. This also implements access checking on the NC root for the access right GUIDs for requests with and without reveal secrets Pair-Programmed-With: Anatoliy Atanasov <anatoliy.atanasov@postpath.com>
-rw-r--r--source4/rpc_server/drsuapi/getncchanges.c156
1 files changed, 130 insertions, 26 deletions
diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c
index 408aee1b46..3245e01911 100644
--- a/source4/rpc_server/drsuapi/getncchanges.c
+++ b/source4/rpc_server/drsuapi/getncchanges.c
@@ -85,6 +85,25 @@ static bool udv_filter(const struct drsuapi_DsReplicaCursorCtrEx *udv,
}
+static int attid_cmp(enum drsuapi_DsAttributeId a1, enum drsuapi_DsAttributeId a2)
+{
+ if (a1 == a2) return 0;
+ return ((uint32_t)a1) > ((uint32_t)a2) ? 1 : -1;
+}
+
+/*
+ check if an attribute is in a partial_attribute_set
+ */
+static bool check_partial_attribute_set(const struct dsdb_attribute *sa,
+ struct drsuapi_DsPartialAttributeSet *pas)
+{
+ enum drsuapi_DsAttributeId *result;
+ BINARY_ARRAY_SEARCH_V(pas->attids, pas->num_attids, (enum drsuapi_DsAttributeId)sa->attributeID_id,
+ attid_cmp, result);
+ return result != NULL;
+}
+
+
/*
drsuapi_DsGetNCChanges for one object
*/
@@ -97,6 +116,7 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem
DATA_BLOB *session_key,
uint64_t highest_usn,
uint32_t replica_flags,
+ struct drsuapi_DsPartialAttributeSet *partial_attribute_set,
struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector,
enum drsuapi_DsExtendedOperation extended_op)
{
@@ -224,21 +244,8 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem
continue;
}
- /*
- * 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 (!(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)));
+ /* filter by partial_attribute_set */
+ if (partial_attribute_set && !check_partial_attribute_set(sa, partial_attribute_set)) {
continue;
}
@@ -1047,6 +1054,82 @@ struct drsuapi_getncchanges_state {
struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;
};
+/*
+ see if this getncchanges request includes a request to reveal secret information
+ */
+static WERROR dcesrv_drsuapi_is_reveal_secrets_request(struct drsuapi_bind_state *b_state,
+ struct drsuapi_DsGetNCChangesRequest8 *req8,
+ bool *is_secret_request)
+{
+ enum drsuapi_DsExtendedOperation exop;
+ int i;
+ struct dsdb_schema *schema;
+
+ *is_secret_request = true;
+
+ exop = req8->extended_op;
+
+ switch (exop) {
+ case DRSUAPI_EXOP_FSMO_REQ_ROLE:
+ case DRSUAPI_EXOP_FSMO_RID_ALLOC:
+ case DRSUAPI_EXOP_FSMO_RID_REQ_ROLE:
+ case DRSUAPI_EXOP_FSMO_REQ_PDC:
+ case DRSUAPI_EXOP_FSMO_ABANDON_ROLE:
+ /* FSMO exops can reveal secrets */
+ *is_secret_request = true;
+ return WERR_OK;
+ case DRSUAPI_EXOP_REPL_SECRET:
+ case DRSUAPI_EXOP_REPL_OBJ:
+ case DRSUAPI_EXOP_NONE:
+ break;
+ }
+
+ if (req8->replica_flags & DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING) {
+ *is_secret_request = false;
+ return WERR_OK;
+ }
+
+ if (exop == DRSUAPI_EXOP_REPL_SECRET ||
+ req8->partial_attribute_set == NULL) {
+ /* they want secrets */
+ *is_secret_request = true;
+ return WERR_OK;
+ }
+
+ schema = dsdb_get_schema(b_state->sam_ctx, NULL);
+
+ /* check the attributes they asked for */
+ for (i=0; i<req8->partial_attribute_set->num_attids; i++) {
+ const struct dsdb_attribute *sa;
+ sa = dsdb_attribute_by_attributeID_id(schema, req8->partial_attribute_set->attids[i]);
+ if (sa == NULL) {
+ return WERR_DS_DRA_SCHEMA_MISMATCH;
+ }
+ if (!dsdb_attr_in_rodc_fas(sa)) {
+ *is_secret_request = true;
+ return WERR_OK;
+ }
+ }
+
+ /* check the attributes they asked for */
+ for (i=0; i<req8->partial_attribute_set_ex->num_attids; i++) {
+ const struct dsdb_attribute *sa;
+ sa = dsdb_attribute_by_attributeID_id(schema, req8->partial_attribute_set_ex->attids[i]);
+ if (sa == NULL) {
+ return WERR_DS_DRA_SCHEMA_MISMATCH;
+ }
+ if (!dsdb_attr_in_rodc_fas(sa)) {
+ *is_secret_request = true;
+ return WERR_OK;
+ }
+ }
+
+ *is_secret_request = false;
+ return WERR_OK;
+}
+
+
+
/*
drsuapi_DsGetNCChanges
@@ -1089,6 +1172,7 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
enum security_user_level security_level;
struct ldb_context *sam_ctx;
struct dom_sid *user_sid;
+ bool is_secret_request;
DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
b_state = h->data;
@@ -1141,26 +1225,43 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
return WERR_DS_DRA_SOURCE_DISABLED;
}
- werr = drs_security_level_check(dce_call, "DsGetNCChanges", SECURITY_RO_DOMAIN_CONTROLLER,
- samdb_domain_sid(sam_ctx));
+ user_sid = &dce_call->conn->auth_state.session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
+
+ werr = drs_security_access_check_nc_root(b_state->sam_ctx,
+ mem_ctx,
+ dce_call->conn->auth_state.session_info->security_token,
+ req8->naming_context,
+ GUID_DRS_GET_CHANGES);
if (!W_ERROR_IS_OK(werr)) {
return werr;
}
- user_sid = &dce_call->conn->auth_state.session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
-
+ werr = dcesrv_drsuapi_is_reveal_secrets_request(b_state, req8, &is_secret_request);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+ if (is_secret_request && req8->extended_op != DRSUAPI_EXOP_REPL_SECRET) {
+ werr = drs_security_access_check_nc_root(b_state->sam_ctx,
+ mem_ctx,
+ dce_call->conn->auth_state.session_info->security_token,
+ req8->naming_context,
+ GUID_DRS_GET_ALL_CHANGES);
+ 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(sam_ctx));
- if (security_level == SECURITY_RO_DOMAIN_CONTROLLER &&
- req8->replica_flags & DRSUAPI_DRS_WRIT_REP) {
- /* we rely on this flag being unset for RODC requests */
- req8->replica_flags &= ~DRSUAPI_DRS_WRIT_REP;
+ if (security_level == SECURITY_RO_DOMAIN_CONTROLLER) {
+ if (req8->replica_flags & DRSUAPI_DRS_WRIT_REP) {
+ /* we rely on this flag being unset for RODC requests */
+ req8->replica_flags &= ~DRSUAPI_DRS_WRIT_REP;
+ }
}
-
if (req8->replica_flags & DRSUAPI_DRS_FULL_SYNC_PACKET) {
/* Ignore the _in_ uptpdateness vector*/
req8->uptodateness_vector = NULL;
@@ -1262,7 +1363,8 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
enum ldb_scope scope = LDB_SCOPE_SUBTREE;
const char *extra_filter;
- if (req8->extended_op == DRSUAPI_EXOP_REPL_OBJ) {
+ if (req8->extended_op == DRSUAPI_EXOP_REPL_OBJ ||
+ req8->extended_op == DRSUAPI_EXOP_REPL_SECRET) {
scope = LDB_SCOPE_BASE;
}
@@ -1380,7 +1482,9 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
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,
+ req8->partial_attribute_set,
+ getnc_state->uptodateness_vector,
req8->extended_op);
if (!W_ERROR_IS_OK(werr)) {
return werr;