void object_tree_modify_access(struct object_tree *root, uint32_t access) { struct object_tree *p; if (root){ root->remaining_access &= ~access; } for (p = root->children; p != NULL; p = p->next) object_tree_modify_access(p, access); }
NTSTATUS sec_access_check_ds(const struct security_descriptor *sd, const struct security_token *token, uint32_t access_desired, uint32_t *access_granted, struct object_tree *tree, struct dom_sid *replace_sid) { uint32_t i; uint32_t bits_remaining; struct object_tree *node; const struct GUID *type; struct dom_sid self_sid; dom_sid_parse(SID_NT_SELF, &self_sid); *access_granted = access_desired; bits_remaining = access_desired; /* handle the maximum allowed flag */ if (access_desired & SEC_FLAG_MAXIMUM_ALLOWED) { access_desired |= access_check_max_allowed(sd, token); access_desired &= ~SEC_FLAG_MAXIMUM_ALLOWED; *access_granted = access_desired; bits_remaining = access_desired; } if (access_desired & SEC_FLAG_SYSTEM_SECURITY) { if (security_token_has_privilege(token, SEC_PRIV_SECURITY)) { bits_remaining &= ~SEC_FLAG_SYSTEM_SECURITY; } else { return NT_STATUS_PRIVILEGE_NOT_HELD; } } /* the owner always gets SEC_STD_WRITE_DAC and SEC_STD_READ_CONTROL */ if ((bits_remaining & (SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL)) && security_token_has_sid(token, sd->owner_sid)) { bits_remaining &= ~(SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL); } /* TODO: remove this, as it is file server specific */ if ((bits_remaining & SEC_RIGHTS_PRIV_RESTORE) && security_token_has_privilege(token, SEC_PRIV_RESTORE)) { bits_remaining &= ~(SEC_RIGHTS_PRIV_RESTORE); } if ((bits_remaining & SEC_RIGHTS_PRIV_BACKUP) && security_token_has_privilege(token, SEC_PRIV_BACKUP)) { bits_remaining &= ~(SEC_RIGHTS_PRIV_BACKUP); } /* a NULL dacl allows access */ if ((sd->type & SEC_DESC_DACL_PRESENT) && sd->dacl == NULL) { *access_granted = access_desired; return NT_STATUS_OK; } if (sd->dacl == NULL) { goto done; } /* check each ace in turn. */ for (i=0; bits_remaining && i < sd->dacl->num_aces; i++) { struct dom_sid *trustee; struct security_ace *ace = &sd->dacl->aces[i]; if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) { continue; } if (dom_sid_equal(&ace->trustee, &self_sid) && replace_sid) { trustee = replace_sid; } else { trustee = &ace->trustee; } if (!security_token_has_sid(token, trustee)) { continue; } switch (ace->type) { case SEC_ACE_TYPE_ACCESS_ALLOWED: if (tree) { object_tree_modify_access(tree, ace->access_mask); } bits_remaining &= ~ace->access_mask; break; case SEC_ACE_TYPE_ACCESS_DENIED: if (bits_remaining & ace->access_mask) { return NT_STATUS_ACCESS_DENIED; } break; case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT: case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT: /* * check only in case we have provided a tree, * the ACE has an object type and that type * is in the tree */ type = get_ace_object_type(ace); if (!tree) { continue; } if (!type) { node = tree; } else { if (!(node = get_object_tree_by_GUID(tree, type))) { continue; } } if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT) { object_tree_modify_access(node, ace->access_mask); if (node->remaining_access == 0) { return NT_STATUS_OK; } } else { if (node->remaining_access & ace->access_mask){ return NT_STATUS_ACCESS_DENIED; } } break; default: /* Other ACE types not handled/supported */ break; } } done: if (bits_remaining != 0) { return NT_STATUS_ACCESS_DENIED; } return NT_STATUS_OK; }