📄 pvfs_acl.c
字号:
static bool pvfs_read_only(struct pvfs_state *pvfs, uint32_t access_mask){ if ((pvfs->flags & PVFS_FLAG_READONLY) && (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA | SEC_FILE_WRITE_EA | SEC_FILE_WRITE_ATTRIBUTE | SEC_STD_DELETE | SEC_STD_WRITE_DAC | SEC_STD_WRITE_OWNER | SEC_DIR_DELETE_CHILD))) { return true; } return false;}/* default access check function based on unix permissions doing this saves on building a full security descriptor for the common case of access check on files with no specific NT ACL*/NTSTATUS pvfs_access_check_unix(struct pvfs_state *pvfs, struct ntvfs_request *req, struct pvfs_filename *name, uint32_t *access_mask){ uid_t uid = geteuid(); uint32_t max_bits = SEC_RIGHTS_FILE_READ | SEC_FILE_ALL; if (pvfs_read_only(pvfs, *access_mask)) { return NT_STATUS_ACCESS_DENIED; } /* owner and root get extra permissions */ if (uid == 0) { max_bits |= SEC_STD_ALL | SEC_FLAG_SYSTEM_SECURITY; } else if (uid == name->st.st_uid) { max_bits |= SEC_STD_ALL; } if (*access_mask == SEC_FLAG_MAXIMUM_ALLOWED) { *access_mask = max_bits; return NT_STATUS_OK; } if (uid != 0 && (*access_mask & SEC_FLAG_SYSTEM_SECURITY)) { return NT_STATUS_ACCESS_DENIED; } if (*access_mask & ~max_bits) { return NT_STATUS_ACCESS_DENIED; } if (pvfs->ntvfs->ctx->protocol != PROTOCOL_SMB2) { /* on SMB, this bit is always granted, even if not asked for */ *access_mask |= SEC_FILE_READ_ATTRIBUTE; } return NT_STATUS_OK;}/* check the security descriptor on a file, if any *access_mask is modified with the access actually granted*/NTSTATUS pvfs_access_check(struct pvfs_state *pvfs, struct ntvfs_request *req, struct pvfs_filename *name, uint32_t *access_mask){ struct security_token *token = req->session_info->security_token; struct xattr_NTACL *acl; NTSTATUS status; struct security_descriptor *sd; if (pvfs_read_only(pvfs, *access_mask)) { return NT_STATUS_ACCESS_DENIED; } acl = talloc(req, struct xattr_NTACL); if (acl == NULL) { return NT_STATUS_NO_MEMORY; } /* expand the generic access bits to file specific bits */ *access_mask = pvfs_translate_mask(*access_mask); if (pvfs->ntvfs->ctx->protocol != PROTOCOL_SMB2) { *access_mask &= ~SEC_FILE_READ_ATTRIBUTE; } status = pvfs_acl_load(pvfs, name, -1, acl); if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { talloc_free(acl); return pvfs_access_check_unix(pvfs, req, name, access_mask); } if (!NT_STATUS_IS_OK(status)) { return status; } switch (acl->version) { case 1: sd = acl->info.sd; break; default: return NT_STATUS_INVALID_ACL; } /* check the acl against the required access mask */ status = sec_access_check(sd, token, *access_mask, access_mask); if (pvfs->ntvfs->ctx->protocol != PROTOCOL_SMB2) { /* on SMB, this bit is always granted, even if not asked for */ *access_mask |= SEC_FILE_READ_ATTRIBUTE; } talloc_free(acl); return status;}/* a simplified interface to access check, designed for calls that do not take or return an access check mask*/NTSTATUS pvfs_access_check_simple(struct pvfs_state *pvfs, struct ntvfs_request *req, struct pvfs_filename *name, uint32_t access_needed){ if (access_needed == 0) { return NT_STATUS_OK; } return pvfs_access_check(pvfs, req, name, &access_needed);}/* access check for creating a new file/directory*/NTSTATUS pvfs_access_check_create(struct pvfs_state *pvfs, struct ntvfs_request *req, struct pvfs_filename *name, uint32_t *access_mask){ struct pvfs_filename *parent; NTSTATUS status; status = pvfs_resolve_parent(pvfs, req, name, &parent); if (!NT_STATUS_IS_OK(status)) { return status; } status = pvfs_access_check(pvfs, req, parent, access_mask); if (!NT_STATUS_IS_OK(status)) { return status; } if (! ((*access_mask) & SEC_DIR_ADD_FILE)) { return pvfs_access_check_simple(pvfs, req, parent, SEC_DIR_ADD_FILE); } return status;}/* access check for creating a new file/directory - no access mask supplied*/NTSTATUS pvfs_access_check_parent(struct pvfs_state *pvfs, struct ntvfs_request *req, struct pvfs_filename *name, uint32_t access_mask){ struct pvfs_filename *parent; NTSTATUS status; status = pvfs_resolve_parent(pvfs, req, name, &parent); if (!NT_STATUS_IS_OK(status)) { return status; } return pvfs_access_check_simple(pvfs, req, parent, access_mask);}/* determine if an ACE is inheritable*/static bool pvfs_inheritable_ace(struct pvfs_state *pvfs, const struct security_ace *ace, bool container){ if (!container) { return (ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) != 0; } if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) { return true; } if ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) && !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) { return true; } return false;}/* this is the core of ACL inheritance. It copies any inheritable aces from the parent SD to the child SD. Note that the algorithm depends on whether the child is a container or not*/static NTSTATUS pvfs_acl_inherit_aces(struct pvfs_state *pvfs, struct security_descriptor *parent_sd, struct security_descriptor *sd, bool container){ int i; for (i=0;i<parent_sd->dacl->num_aces;i++) { struct security_ace ace = parent_sd->dacl->aces[i]; NTSTATUS status; const struct dom_sid *creator = NULL, *new_id = NULL; uint32_t orig_flags; if (!pvfs_inheritable_ace(pvfs, &ace, container)) { continue; } orig_flags = ace.flags; /* see the RAW-ACLS inheritance test for details on these rules */ if (!container) { ace.flags = 0; } else { ace.flags &= ~SEC_ACE_FLAG_INHERIT_ONLY; if (!(ace.flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) { ace.flags |= SEC_ACE_FLAG_INHERIT_ONLY; } if (ace.flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) { ace.flags = 0; } } /* the CREATOR sids are special when inherited */ if (dom_sid_equal(&ace.trustee, pvfs->sid_cache.creator_owner)) { creator = pvfs->sid_cache.creator_owner; new_id = sd->owner_sid; } else if (dom_sid_equal(&ace.trustee, pvfs->sid_cache.creator_group)) { creator = pvfs->sid_cache.creator_group; new_id = sd->group_sid; } else { new_id = &ace.trustee; } if (creator && container && (ace.flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) { uint32_t flags = ace.flags; ace.trustee = *new_id; ace.flags = 0; status = security_descriptor_dacl_add(sd, &ace); if (!NT_STATUS_IS_OK(status)) { return status; } ace.trustee = *creator; ace.flags = flags | SEC_ACE_FLAG_INHERIT_ONLY; status = security_descriptor_dacl_add(sd, &ace); } else if (container && !(orig_flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) { status = security_descriptor_dacl_add(sd, &ace); } else { ace.trustee = *new_id; status = security_descriptor_dacl_add(sd, &ace); } if (!NT_STATUS_IS_OK(status)) { return status; } } return NT_STATUS_OK;}/* setup an ACL on a new file/directory based on the inherited ACL from the parent. If there is no inherited ACL then we don't set anything, as the default ACL applies anyway*/NTSTATUS pvfs_acl_inherit(struct pvfs_state *pvfs, struct ntvfs_request *req, struct pvfs_filename *name, int fd){ struct xattr_NTACL *acl; NTSTATUS status; struct pvfs_filename *parent; struct security_descriptor *parent_sd, *sd; bool container; struct id_mapping *ids; struct composite_context *ctx; /* form the parents path */ status = pvfs_resolve_parent(pvfs, req, name, &parent); if (!NT_STATUS_IS_OK(status)) { return status; } acl = talloc(req, struct xattr_NTACL); if (acl == NULL) { return NT_STATUS_NO_MEMORY; } status = pvfs_acl_load(pvfs, parent, -1, acl); if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { return NT_STATUS_OK; } if (!NT_STATUS_IS_OK(status)) { return status; } switch (acl->version) { case 1: parent_sd = acl->info.sd; break; default: return NT_STATUS_INVALID_ACL; } if (parent_sd == NULL || parent_sd->dacl == NULL || parent_sd->dacl->num_aces == 0) { /* go with the default ACL */ return NT_STATUS_OK; } /* create the new sd */ sd = security_descriptor_initialise(req); if (sd == NULL) { return NT_STATUS_NO_MEMORY; } ids = talloc_array(sd, struct id_mapping, 2); NT_STATUS_HAVE_NO_MEMORY(ids); ids[0].unixid = talloc(ids, struct unixid); NT_STATUS_HAVE_NO_MEMORY(ids[0].unixid); ids[0].unixid->id = name->st.st_uid; ids[0].unixid->type = ID_TYPE_UID; ids[0].sid = NULL; ids[0].status = NT_STATUS_NONE_MAPPED; ids[1].unixid = talloc(ids, struct unixid); NT_STATUS_HAVE_NO_MEMORY(ids[1].unixid); ids[1].unixid->id = name->st.st_gid; ids[1].unixid->type = ID_TYPE_GID; ids[1].sid = NULL; ids[1].status = NT_STATUS_NONE_MAPPED; ctx = wbc_xids_to_sids_send(pvfs->wbc_ctx, ids, 2, ids); NT_STATUS_HAVE_NO_MEMORY(ctx); status = wbc_xids_to_sids_recv(ctx, &ids); NT_STATUS_NOT_OK_RETURN(status); sd->owner_sid = talloc_steal(sd, ids[0].sid); sd->group_sid = talloc_steal(sd, ids[1].sid); sd->type |= SEC_DESC_DACL_PRESENT; container = (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) ? true:false; /* fill in the aces from the parent */ status = pvfs_acl_inherit_aces(pvfs, parent_sd, sd, container); if (!NT_STATUS_IS_OK(status)) { return status; } /* if there is nothing to inherit then we fallback to the default acl */ if (sd->dacl == NULL || sd->dacl->num_aces == 0) { return NT_STATUS_OK; } acl->info.sd = sd; status = pvfs_acl_save(pvfs, name, fd, acl); return status;}/* return the maximum allowed access mask*/NTSTATUS pvfs_access_maximal_allowed(struct pvfs_state *pvfs, struct ntvfs_request *req, struct pvfs_filename *name, uint32_t *maximal_access){ *maximal_access = SEC_FLAG_MAXIMUM_ALLOWED; return pvfs_access_check(pvfs, req, name, maximal_access);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -