zfs_acl.c revision 84c5a1550ecbf7356ab4133238160367c507f4fb
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/sysmacros.h>
#include <sys/resource.h>
#include <sys/zfs_znode.h>
#include <sys/zfs_vfsops.h>
#include <acl/acl_common.h>
#define ALLOW ACE_ACCESS_ALLOWED_ACE_TYPE
#define DENY ACE_ACCESS_DENIED_ACE_TYPE
static zfs_acl_t *
zfs_acl_alloc(int slots)
{
if (slots != 0) {
aclp->z_acl_count = 0;
} else {
}
return (aclp);
}
void
{
}
}
static uint32_t
{
return (new_mask);
}
/*
* Convert unix access mask to v4 access mask
*/
static uint32_t
{
if (access_mask & 01)
new_mask |= (ACE_EXECUTE);
if (access_mask & 02) {
new_mask |= (ACE_WRITE_DATA);
} if (access_mask & 04) {
}
return (new_mask);
}
static void
{
}
static uint64_t
{
int i;
int entry_type;
if (entry_type == ACE_OWNER) {
}
}
}
}
}
}
} else if (entry_type == OWNING_GROUP) {
}
}
}
}
}
}
} else if (entry_type == ACE_EVERYONE) {
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
return (mode);
}
static zfs_acl_t *
{
aclp = zfs_acl_alloc(0);
return (aclp);
}
/*
* Read an external acl object.
*/
{
return (zfs_acl_node_read_internal(zp));
return (aclp);
}
static boolean_t
{
int i;
*inherit = 0;
return (B_FALSE);
}
/*
* first check type of entry
*/
case ACE_OWNER:
break;
case (ACE_IDENTIFIER_GROUP | ACE_GROUP):
case ACE_IDENTIFIER_GROUP:
}
break;
case ACE_EVERYONE:
break;
}
/*
* next check inheritance level flags
*/
return (B_FALSE);
/*
* Only directories should have inheritance flags.
*/
return (B_FALSE);
}
*inherit = 1;
ACE_DIRECTORY_INHERIT_ACE)) == 0) {
return (B_FALSE);
}
}
}
return (B_TRUE);
}
/*
* common code for setting acl's.
*
* This function is called from zfs_mode_update, zfs_perm_init, and zfs_setacl.
* zfs_setacl passes a non-NULL inherit pointer (ihp) to indicate that it's
* already checked the acl and knows whether to inherit.
*/
int
{
int inherit = 0;
int error;
if (ihp)
return (EINVAL);
}
/*
* Will ACL fit internally?
*/
if (aoid == 0) {
} else {
acl_phys_size, 0, tx);
}
} else {
/*
* Migrating back embedded?
*/
if (error)
return (error);
}
}
if (inherit) {
}
return (0);
}
/*
* Create space for slots_needed ACEs to be append
* to aclp.
*/
static void
{
int slot_cnt;
}
}
/*
* Remove "slot" ACE from aclp
*/
static void
{
} else
aclp->z_acl_count--;
}
/*
* Update access mask for prepended ACE
*
* This applies the "groupmask" value for aclmode property.
*/
static void
{
int user_ace;
} else {
}
else
}
else
}
else
}
else
}
}
/*
* Apply mode to canonical six ACEs.
*/
static void
{
int cnt;
/*
* Fixup final ACEs to match the mode
*/
}
static int
{
}
/*
* Can prepended ACE be reused?
*/
static int
{
int okay_masks;
if (i < 1)
return (B_FALSE);
return (B_FALSE);
return (B_FALSE);
return (B_FALSE);
return (B_TRUE);
}
/*
* Create space to prepend an ACE
*/
static void
{
int oldslots;
int need_free = 0;
need_free++;
} else {
}
if (oldaclp) {
if (need_free)
}
}
/*
* Prepend deny ACE
*/
static void
{
zfs_acl_prepend(aclp, i);
aclp->z_acl_count++;
}
/*
* Split an inherited ACE into inherit_only ACE
* and original ACE with inheritance flags stripped off.
*/
static void
{
zfs_acl_prepend(aclp, i);
aclp->z_acl_count++;
}
/*
* Are ACES started at index i, the canonical six ACES?
*/
static int
{
if ((zfs_acl_ace_match(&acep[i],
EVERYONE_ALLOW_MASK))) {
return (1);
} else {
return (0);
}
}
/*
* Apply step 1g, to group entries
*
* Need to deal with corner case where group may have
* greater permissions than owner. If so then limit
* group permissions, based on what extra permissions
* group has.
*/
static void
{
if (extramode) {
if (extramode & 04) {
}
if (extramode & 02) {
acep[0].a_access_mask &=
}
if (extramode & 01) {
}
}
}
}
/*
* Apply the chmod algorithm as described
* in PSARC/2002/240
*/
static int
{
int i;
int error;
int entry_type;
int reuse_deny;
int need_canonical_six = 1;
int inherit = 0;
int iflags;
i = 0;
while (i < aclp->z_acl_count) {
(iflags & ACE_INHERIT_ONLY_ACE)) {
i++;
if (iflags)
inherit = 1;
continue;
}
zfs_ace_remove(aclp, i);
continue;
}
/*
* Need to split ace into two?
*/
if ((iflags & (ACE_FILE_INHERIT_ACE|
(!(iflags & ACE_INHERIT_ONLY_ACE))) {
zfs_acl_split_ace(aclp, i);
i++;
inherit = 1;
continue;
}
(entry_type == OWNING_GROUP)) {
i++;
continue;
} else {
/*
* Check preceding ACE if any, to see
* if we need to prepend a DENY ACE.
* This is only applicable when the acl_mode
* property == groupmask.
*/
if (reuse_deny == B_FALSE) {
i, mode);
i++;
} else {
&acep[i - 1],
}
mode);
}
}
i++;
}
}
/*
* Check out last six aces, if we have six.
*/
if (zfs_have_canonical_six(aclp, i)) {
need_canonical_six = 0;
}
}
if (need_canonical_six) {
i = aclp->z_acl_count;
}
return (error);
}
int
{
int error;
return (error);
}
/*
* strip off write_owner and write_acl
*/
static void
{
}
/*
* inherit inheritable ACEs from parent
*/
static zfs_acl_t *
{
int ace_cnt = 0;
int pace_cnt;
int i, j;
i = j = 0;
for (i = 0; i != pace_cnt; i++) {
continue;
ace_cnt++;
ace_cnt++;
}
}
}
for (i = 0; i != pace_cnt; i++) {
continue;
/*
* Now create entry for inherited ace
*/
j++;
continue;
}
j++;
continue;
}
j++;
continue;
}
/*
* If we are inheriting an ACE targeted for
* only files, then make sure inherit_only
* is on for future propagation.
*/
} else {
}
j++;
}
}
}
aclp->z_acl_count = j;
return (aclp);
}
/*
* Create file system object initial permissions
* including inheritable ACEs.
*/
void
{
int error;
int pull_down;
/*
* Determine uid and gid.
*/
} else {
else
}
/*
* If we're creating a directory, and the parent directory has the
* set-GID bit set, set in on the new directory.
* Otherwise, if the user is neither privileged nor a member of the
* file's new group, clear the file's set-GID bit.
*/
else {
}
if (pull_down) {
} else {
}
}
/*
* Should ACE be inherited?
*/
static int
{
return (1);
else if (iflags & ACE_FILE_INHERIT_ACE)
return (0);
}
/*
* Retrieve a files ACL
*/
int
{
int error;
/*
* If owner of file then allow reading of the
* ACL.
*/
return (error);
}
if (mask == 0)
return (ENOSYS);
if (mask & VSA_ACECNT) {
}
}
return (0);
}
/*
* Set a files ACL
*/
int
{
int error;
int inherit;
if (mask == 0)
return (EINVAL);
return (EINVAL);
top:
return (error);
}
} else if (error) {
}
0, ZFS_ACL_SIZE(aclcnt));
} else if (aclcnt > ACE_SLOT_CNT) {
}
if (error) {
goto top;
}
return (error);
}
done:
return (error);
}
static int
{
return (0);
}
return (0);
return (EACCES);
}
}
/*
* haven't been specifcally denied at this point
* so return UNDETERMINED.
*/
return (ACCESS_UNDETERMINED);
}
static int
{
int mode_wanted = v4_mode;
int cnt;
int i;
int access_deny = ACCESS_UNDETERMINED;
*working_mode = 0;
return (0);
if ((v4_mode & WRITE_MASK) &&
return (EROFS);
}
for (i = 0; i != cnt; i++) {
continue;
switch (entry_type) {
case ACE_OWNER:
}
break;
case (ACE_IDENTIFIER_GROUP | ACE_GROUP):
case ACE_IDENTIFIER_GROUP:
/*
* Owning group gid is in znode not ACL
*/
else
}
break;
case ACE_EVERYONE:
break;
/* USER Entry */
default:
if (entry_type == 0) {
}
break;
}
return (EIO);
}
if (access_deny != ACCESS_UNDETERMINED)
break;
}
return (access_deny);
}
/*
* priv subsytem when a deny is determined.
*/
int
{
int working_mode = 0;
int error;
int is_attr;
/*
* If attribute then validate against base file
*/
if (is_attr) {
return (error);
}
/*
* fixup mode to map to xattr perms
*/
}
}
}
if (is_attr)
return (error);
}
}
if (is_attr)
return (error);
}
/*
* Special zaccess function to check for special nfsv4 perm.
* doesn't call secpolicy_vnode_access() for failure, since that
* would probably be the wrong policy function to call.
* instead its up to the caller to handle that situation.
*/
int
{
int working_mode = 0;
}
/*
* native ACL format and call zfs_zaccess()
*/
int
{
}
/*
* consulting least priv subsystem.
*
*
* The following chart is the recommended NFSv4 enforcement for
* ability to delete an object.
*
* -------------------------------------------------------
* | Parent Dir | Target Object Permissions |
* | permissions | |
* -------------------------------------------------------
* | | ACL Allows | ACL Denies| Delete |
* | | Delete | Delete | unspecified|
* -------------------------------------------------------
* | ACL Allows | Permit | Permit | Permit |
* | DELETE_CHILD | |
* -------------------------------------------------------
* | ACL Denies | Permit | Deny | Deny |
* | DELETE_CHILD | | | |
* -------------------------------------------------------
* | ACL specifies | | | |
* | only allow | Permit | Permit | Permit |
* | write and | | | |
* | execute | | | |
* -------------------------------------------------------
* | ACL denies | | | |
* | write and | Permit | Deny | Deny |
* | execute | | | |
* -------------------------------------------------------
* ^
* |
* No search privilege, can't even look up file?
*
*/
int
{
int dzp_working_mode = 0;
int zp_working_mode = 0;
int error;
/*
* Arghh, this check is going to require a couple of questions
* to be asked. We want specific DELETE permissions to
* want an ACL such as this to mess us up.
* user:sloar:write_data:deny,user:sloar:delete:allow
*
* However, deny permissions may ultimately be overridden
* by secpolicy_vnode_access().
*/
&dzp_working_mode, cr);
return (dzp_error);
/*
* First handle the first row
*/
if (dzp_working_mode & ACE_DELETE_CHILD)
return (0);
/*
* Second row
*/
if (zp_working_mode & ACE_DELETE)
return (0);
/*
* Third Row
*/
&dzp_working_mode, cr);
return (dzp_error);
goto sticky;
/*
* Fourth Row
*/
goto sticky;
if (error)
return (error);
return (error);
}
int
{
int add_perm;
int error;
/*
* Rename permissions are combination of delete permission +
*/
/*
* first make sure we do the delete portion.
*
* If that succeeds then check for add_file/add_subdir permissions
*/
return (error);
/*
* If we have a tzp, see if we can delete it?
*/
if (tzp) {
return (error);
}
/*
* Now check for add permissions
*/
return (error);
}