diff --git a/usr/src/common/acl/acl_common.c b/usr/src/common/acl/acl_common.c index eafc47d10f2d..494c5f73f4b7 100644 --- a/usr/src/common/acl/acl_common.c +++ b/usr/src/common/acl/acl_common.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. */ #include @@ -372,7 +373,7 @@ access_mask_set(int haswriteperm, int hasreadperm, int isowner, int isallow) * by nfsace, assuming aclent_t -> nfsace semantics. */ static uint32_t -mode_to_ace_access(mode_t mode, int isdir, int isowner, int isallow) +mode_to_ace_access(mode_t mode, boolean_t isdir, int isowner, int isallow) { uint32_t access = 0; int haswriteperm = 0; @@ -415,7 +416,7 @@ mode_to_ace_access(mode_t mode, int isdir, int isowner, int isallow) access |= ACE_DELETE_CHILD; } /* exec */ - if (mode & 01) { + if (mode & S_IXOTH) { access |= ACE_EXECUTE; } @@ -666,7 +667,7 @@ ln_aent_to_ace(aclent_t *aclent, int n, ace_t **acepp, int *rescount, int isdir) } static int -convert_aent_to_ace(aclent_t *aclentp, int aclcnt, int isdir, +convert_aent_to_ace(aclent_t *aclentp, int aclcnt, boolean_t isdir, ace_t **retacep, int *retacecnt) { ace_t *acep; @@ -692,7 +693,7 @@ convert_aent_to_ace(aclent_t *aclentp, int aclcnt, int isdir, dfaclcnt = aclcnt - i; } - if (dfaclcnt && isdir == 0) { + if (dfaclcnt && !isdir) { return (EINVAL); } @@ -730,7 +731,7 @@ convert_aent_to_ace(aclent_t *aclentp, int aclcnt, int isdir, } static int -ace_mask_to_mode(uint32_t mask, o_mode_t *modep, int isdir) +ace_mask_to_mode(uint32_t mask, o_mode_t *modep, boolean_t isdir) { int error = 0; o_mode_t mode = 0; @@ -1027,7 +1028,7 @@ ace_to_aent_legal(ace_t *acep) } static int -ace_allow_to_mode(uint32_t mask, o_mode_t *modep, int isdir) +ace_allow_to_mode(uint32_t mask, o_mode_t *modep, boolean_t isdir) { /* ACE_READ_ACL and ACE_READ_ATTRIBUTES must both be set */ if ((mask & (ACE_READ_ACL | ACE_READ_ATTRIBUTES)) != @@ -1040,7 +1041,7 @@ ace_allow_to_mode(uint32_t mask, o_mode_t *modep, int isdir) static int acevals_to_aent(acevals_t *vals, aclent_t *dest, ace_list_t *list, - uid_t owner, gid_t group, int isdir) + uid_t owner, gid_t group, boolean_t isdir) { int error; uint32_t flips = ACE_POSIX_SUPPORTED_BITS; @@ -1080,7 +1081,7 @@ acevals_to_aent(acevals_t *vals, aclent_t *dest, ace_list_t *list, static int ace_list_to_aent(ace_list_t *list, aclent_t **aclentp, int *aclcnt, - uid_t owner, gid_t group, int isdir) + uid_t owner, gid_t group, boolean_t isdir) { int error = 0; aclent_t *aent, *result = NULL; @@ -1260,7 +1261,7 @@ acevals_compare(const void *va, const void *vb) static int ln_ace_to_aent(ace_t *ace, int n, uid_t owner, gid_t group, aclent_t **aclentp, int *aclcnt, aclent_t **dfaclentp, int *dfaclcnt, - int isdir) + boolean_t isdir) { int error = 0; ace_t *acep; @@ -1455,7 +1456,7 @@ ln_ace_to_aent(ace_t *ace, int n, uid_t owner, gid_t group, } static int -convert_ace_to_aent(ace_t *acebufp, int acecnt, int isdir, +convert_ace_to_aent(ace_t *acebufp, int acecnt, boolean_t isdir, uid_t owner, gid_t group, aclent_t **retaclentp, int *retaclcnt) { int error = 0; @@ -1497,7 +1498,7 @@ convert_ace_to_aent(ace_t *acebufp, int acecnt, int isdir, int -acl_translate(acl_t *aclp, int target_flavor, int isdir, uid_t owner, +acl_translate(acl_t *aclp, int target_flavor, boolean_t isdir, uid_t owner, gid_t group) { int aclcnt; @@ -1568,101 +1569,105 @@ acl_translate(acl_t *aclp, int target_flavor, int isdir, uid_t owner, } void -acl_trivial_access_masks(mode_t mode, uint32_t *allow0, uint32_t *deny1, - uint32_t *deny2, uint32_t *owner, uint32_t *group, uint32_t *everyone) +acl_trivial_access_masks(mode_t mode, boolean_t isdir, trivial_acl_t *masks) { - *deny1 = *deny2 = *allow0 = *group = 0; + uint32_t read_mask = ACE_READ_DATA; + uint32_t write_mask = ACE_WRITE_DATA|ACE_APPEND_DATA; + uint32_t execute_mask = ACE_EXECUTE; + (void) isdir; /* will need this later */ + + masks->deny1 = 0; if (!(mode & S_IRUSR) && (mode & (S_IRGRP|S_IROTH))) - *deny1 |= ACE_READ_DATA; + masks->deny1 |= read_mask; if (!(mode & S_IWUSR) && (mode & (S_IWGRP|S_IWOTH))) - *deny1 |= ACE_WRITE_DATA; + masks->deny1 |= write_mask; if (!(mode & S_IXUSR) && (mode & (S_IXGRP|S_IXOTH))) - *deny1 |= ACE_EXECUTE; + masks->deny1 |= execute_mask; + masks->deny2 = 0; if (!(mode & S_IRGRP) && (mode & S_IROTH)) - *deny2 = ACE_READ_DATA; + masks->deny2 |= read_mask; if (!(mode & S_IWGRP) && (mode & S_IWOTH)) - *deny2 |= ACE_WRITE_DATA; + masks->deny2 |= write_mask; if (!(mode & S_IXGRP) && (mode & S_IXOTH)) - *deny2 |= ACE_EXECUTE; + masks->deny2 |= execute_mask; + masks->allow0 = 0; if ((mode & S_IRUSR) && (!(mode & S_IRGRP) && (mode & S_IROTH))) - *allow0 |= ACE_READ_DATA; + masks->allow0 |= read_mask; if ((mode & S_IWUSR) && (!(mode & S_IWGRP) && (mode & S_IWOTH))) - *allow0 |= ACE_WRITE_DATA; + masks->allow0 |= write_mask; if ((mode & S_IXUSR) && (!(mode & S_IXGRP) && (mode & S_IXOTH))) - *allow0 |= ACE_EXECUTE; + masks->allow0 |= execute_mask; - *owner = ACE_WRITE_ATTRIBUTES|ACE_WRITE_OWNER|ACE_WRITE_ACL| + masks->owner = ACE_WRITE_ATTRIBUTES|ACE_WRITE_OWNER|ACE_WRITE_ACL| ACE_WRITE_NAMED_ATTRS|ACE_READ_ACL|ACE_READ_ATTRIBUTES| ACE_READ_NAMED_ATTRS|ACE_SYNCHRONIZE; if (mode & S_IRUSR) - *owner |= ACE_READ_DATA; + masks->owner |= read_mask; if (mode & S_IWUSR) - *owner |= ACE_WRITE_DATA|ACE_APPEND_DATA; + masks->owner |= write_mask; if (mode & S_IXUSR) - *owner |= ACE_EXECUTE; + masks->owner |= execute_mask; - *group = ACE_READ_ACL|ACE_READ_ATTRIBUTES| ACE_READ_NAMED_ATTRS| + masks->group = ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_READ_NAMED_ATTRS| ACE_SYNCHRONIZE; if (mode & S_IRGRP) - *group |= ACE_READ_DATA; + masks->group |= read_mask; if (mode & S_IWGRP) - *group |= ACE_WRITE_DATA|ACE_APPEND_DATA; + masks->group |= write_mask; if (mode & S_IXGRP) - *group |= ACE_EXECUTE; + masks->group |= execute_mask; - *everyone = ACE_READ_ACL|ACE_READ_ATTRIBUTES| ACE_READ_NAMED_ATTRS| + masks->everyone = ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_READ_NAMED_ATTRS| ACE_SYNCHRONIZE; if (mode & S_IROTH) - *everyone |= ACE_READ_DATA; + masks->everyone |= read_mask; if (mode & S_IWOTH) - *everyone |= ACE_WRITE_DATA|ACE_APPEND_DATA; + masks->everyone |= write_mask; if (mode & S_IXOTH) - *everyone |= ACE_EXECUTE; + masks->everyone |= execute_mask; } int -acl_trivial_create(mode_t mode, ace_t **acl, int *count) +acl_trivial_create(mode_t mode, boolean_t isdir, ace_t **acl, int *count) { - uint32_t deny1, deny2; - uint32_t allow0; - uint32_t owner, group, everyone; int index = 0; int error; + trivial_acl_t masks; *count = 3; - acl_trivial_access_masks(mode, &allow0, &deny1, &deny2, &owner, &group, - &everyone); + acl_trivial_access_masks(mode, isdir, &masks); - if (allow0) + if (masks.allow0) (*count)++; - if (deny1) + if (masks.deny1) (*count)++; - if (deny2) + if (masks.deny2) (*count)++; if ((error = cacl_malloc((void **)acl, *count * sizeof (ace_t))) != 0) return (error); - if (allow0) { - SET_ACE(acl, index, -1, allow0, ACE_ACCESS_ALLOWED_ACE_TYPE, - ACE_OWNER); + if (masks.allow0) { + SET_ACE(acl, index, -1, masks.allow0, + ACE_ACCESS_ALLOWED_ACE_TYPE, ACE_OWNER); } - if (deny1) { - SET_ACE(acl, index, -1, deny1, ACE_ACCESS_DENIED_ACE_TYPE, - ACE_OWNER); + if (masks.deny1) { + SET_ACE(acl, index, -1, masks.deny1, + ACE_ACCESS_DENIED_ACE_TYPE, ACE_OWNER); } - if (deny2) { - SET_ACE(acl, index, -1, deny2, ACE_ACCESS_DENIED_ACE_TYPE, - ACE_GROUP|ACE_IDENTIFIER_GROUP); + if (masks.deny2) { + SET_ACE(acl, index, -1, masks.deny2, + ACE_ACCESS_DENIED_ACE_TYPE, ACE_GROUP|ACE_IDENTIFIER_GROUP); } - SET_ACE(acl, index, -1, owner, ACE_ACCESS_ALLOWED_ACE_TYPE, ACE_OWNER); - SET_ACE(acl, index, -1, group, ACE_ACCESS_ALLOWED_ACE_TYPE, + SET_ACE(acl, index, -1, masks.owner, ACE_ACCESS_ALLOWED_ACE_TYPE, + ACE_OWNER); + SET_ACE(acl, index, -1, masks.group, ACE_ACCESS_ALLOWED_ACE_TYPE, ACE_IDENTIFIER_GROUP|ACE_GROUP); - SET_ACE(acl, index, -1, everyone, ACE_ACCESS_ALLOWED_ACE_TYPE, + SET_ACE(acl, index, -1, masks.everyone, ACE_ACCESS_ALLOWED_ACE_TYPE, ACE_EVERYONE); return (0); diff --git a/usr/src/common/acl/acl_common.h b/usr/src/common/acl/acl_common.h index f76cbd3b450f..be4fd0c9e1d3 100644 --- a/usr/src/common/acl/acl_common.h +++ b/usr/src/common/acl/acl_common.h @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. */ #ifndef _ACL_COMMON_H @@ -33,7 +34,14 @@ extern "C" { #endif -extern ace_t trivial_acl[6]; +typedef struct trivial_acl { + uint32_t allow0; /* allow mask for bits only in owner */ + uint32_t deny1; /* deny mask for bits not in owner */ + uint32_t deny2; /* deny mask for bits not in group */ + uint32_t owner; /* allow mask matching mode */ + uint32_t group; /* allow mask matching mode */ + uint32_t everyone; /* allow mask matching mode */ +} trivial_acl_t; extern int acltrivial(const char *); extern void adjust_ace_pair(ace_t *pair, mode_t mode); @@ -44,13 +52,13 @@ extern int ace_trivial_common(void *, int, uint32_t *mask)); extern acl_t *acl_alloc(acl_type_t); extern void acl_free(acl_t *aclp); -extern int acl_translate(acl_t *aclp, int target_flavor, - int isdir, uid_t owner, gid_t group); +extern int acl_translate(acl_t *aclp, int target_flavor, boolean_t isdir, + uid_t owner, gid_t group); void ksort(caddr_t v, int n, int s, int (*f)()); int cmp2acls(void *a, void *b); -int acl_trivial_create(mode_t mode, ace_t **acl, int *count); -void acl_trivial_access_masks(mode_t mode, uint32_t *allow0, uint32_t *deny1, - uint32_t *deny2, uint32_t *owner, uint32_t *group, uint32_t *everyone); +int acl_trivial_create(mode_t mode, boolean_t isdir, ace_t **acl, int *count); +void acl_trivial_access_masks(mode_t mode, boolean_t isdir, + trivial_acl_t *masks); #ifdef __cplusplus } diff --git a/usr/src/common/zfs/zfs_prop.c b/usr/src/common/zfs/zfs_prop.c index f29bcf62718f..37a9491f3765 100644 --- a/usr/src/common/zfs/zfs_prop.c +++ b/usr/src/common/zfs/zfs_prop.c @@ -104,6 +104,13 @@ zfs_prop_init(void) { NULL } }; + static zprop_index_t acl_mode_table[] = { + { "discard", ZFS_ACL_DISCARD }, + { "groupmask", ZFS_ACL_GROUPMASK }, + { "passthrough", ZFS_ACL_PASSTHROUGH }, + { NULL } + }; + static zprop_index_t acl_inherit_table[] = { { "discard", ZFS_ACL_DISCARD }, { "noallow", ZFS_ACL_NOALLOW }, @@ -207,6 +214,9 @@ zfs_prop_init(void) zprop_register_index(ZFS_PROP_SNAPDIR, "snapdir", ZFS_SNAPDIR_HIDDEN, PROP_INHERIT, ZFS_TYPE_FILESYSTEM, "hidden | visible", "SNAPDIR", snapdir_table); + zprop_register_index(ZFS_PROP_ACLMODE, "aclmode", ZFS_ACL_DISCARD, + PROP_INHERIT, ZFS_TYPE_FILESYSTEM, + "discard | groupmask | passthrough", "ACLMODE", acl_mode_table); zprop_register_index(ZFS_PROP_ACLINHERIT, "aclinherit", ZFS_ACL_RESTRICTED, PROP_INHERIT, ZFS_TYPE_FILESYSTEM, "discard | noallow | restricted | passthrough | passthrough-x", @@ -370,13 +380,6 @@ zfs_prop_init(void) zprop_register_hidden(ZFS_PROP_OBJSETID, "objsetid", PROP_TYPE_NUMBER, PROP_READONLY, ZFS_TYPE_DATASET, "OBJSETID"); - /* - * Property to be removed once libbe is integrated - */ - zprop_register_hidden(ZFS_PROP_PRIVATE, "priv_prop", - PROP_TYPE_NUMBER, PROP_READONLY, ZFS_TYPE_FILESYSTEM, - "PRIV_PROP"); - /* oddball properties */ zprop_register_impl(ZFS_PROP_CREATION, "creation", PROP_TYPE_NUMBER, 0, NULL, PROP_READONLY, ZFS_TYPE_DATASET, diff --git a/usr/src/lib/libsec/common/aclutils.c b/usr/src/lib/libsec/common/aclutils.c index ba7117c7f7b4..f104687b4461 100644 --- a/usr/src/lib/libsec/common/aclutils.c +++ b/usr/src/lib/libsec/common/aclutils.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. */ @@ -393,9 +394,15 @@ acl_strip(const char *file, uid_t owner, gid_t group, mode_t mode) ace_t *min_ace_acl; int acl_flavor; int aclcnt; + struct stat64 statbuf; acl_flavor = pathconf(file, _PC_ACL_ENABLED); + if (stat64(file, &statbuf) != 0) { + error = 1; + return (error); + } + /* * force it through aclent flavor when file system doesn't * understand question @@ -419,8 +426,8 @@ acl_strip(const char *file, uid_t owner, gid_t group, mode_t mode) aclcnt = 4; error = acl(file, SETACL, aclcnt, min_acl); } else if (acl_flavor & _ACL_ACE_ENABLED) { - if ((error = acl_trivial_create(mode, &min_ace_acl, - &aclcnt)) != 0) + if ((error = acl_trivial_create(mode, S_ISDIR(statbuf.st_mode), + &min_ace_acl, &aclcnt)) != 0) return (error); error = acl(file, ACE_SETACL, aclcnt, min_ace_acl); free(min_ace_acl); diff --git a/usr/src/lib/libzfs_jni/common/libzfs_jni_property.c b/usr/src/lib/libzfs_jni/common/libzfs_jni_property.c index cce767243bbf..1b78bb50b419 100644 --- a/usr/src/lib/libzfs_jni/common/libzfs_jni_property.c +++ b/usr/src/lib/libzfs_jni/common/libzfs_jni_property.c @@ -68,6 +68,7 @@ static jobject create_default_ObjectProperty( JNIEnv *, zfs_prop_t, str_to_obj_f, uint64_to_obj_f, char *, char *); static jobject str_to_enum_element(JNIEnv *, char *, char *); static jobject str_to_aclinherit(JNIEnv *, char *); +static jobject str_to_aclmode(JNIEnv *, char *); static jobject str_to_checksum(JNIEnv *, char *); static jobject str_to_compression(JNIEnv *, char *); static jobject str_to_snapdir(JNIEnv *, char *); @@ -114,6 +115,10 @@ custom_prop_desct_t props_custom[] = { ZFSJNI_PACKAGE_DATA "AclInheritProperty", ZFSJNI_PACKAGE_DATA "AclInheritProperty$AclInherit" }, + { ZFS_PROP_ACLMODE, str_to_aclmode, NULL, + ZFSJNI_PACKAGE_DATA "AclModeProperty", + ZFSJNI_PACKAGE_DATA "AclModeProperty$AclMode" }, + { ZFS_PROP_CHECKSUM, str_to_checksum, NULL, ZFSJNI_PACKAGE_DATA "ChecksumProperty", ZFSJNI_PACKAGE_DATA "ChecksumProperty$Checksum" }, @@ -450,6 +455,13 @@ str_to_aclinherit(JNIEnv *env, char *str) ZFSJNI_PACKAGE_DATA "AclInheritProperty$AclInherit")); } +static jobject +str_to_aclmode(JNIEnv *env, char *str) +{ + return (str_to_enum_element(env, str, + ZFSJNI_PACKAGE_DATA "AclModeProperty$AclMode")); +} + static jobject str_to_checksum(JNIEnv *env, char *str) { diff --git a/usr/src/man/man1m/zfs.1m b/usr/src/man/man1m/zfs.1m index 68244c710793..154029430be3 100644 --- a/usr/src/man/man1m/zfs.1m +++ b/usr/src/man/man1m/zfs.1m @@ -6,6 +6,7 @@ .\" The contents of this file are subject to the terms of the Common Development and Distribution License (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 or http://www.opensolaris.org/os/licensing. .\" 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] +.\" Copyright 2011 Nexenta Systems, Inc. All rights reserved. .TH zfs 1M "24 Sep 2009" "SunOS 5.11" "System Administration Commands" .SH NAME zfs \- configures ZFS file systems @@ -776,16 +777,14 @@ mode from the application. .sp .6 .RS 4n Controls how an \fBACL\fR is modified during \fBchmod\fR(2). A file system with -an \fBaclmode\fR property of \fBdiscard\fR deletes all \fBACL\fR entries that -do not represent the mode of the file. An \fBaclmode\fR property of -\fBgroupmask\fR (the default) reduces user or group permissions. The -permissions are reduced, such that they are no greater than the group -permission bits, unless it is a user entry that has the same \fBUID\fR as the -owner of the file or directory. In this case, the \fBACL\fR permissions are -reduced so that they are no greater than owner permission bits. A file system -with an \fBaclmode\fR property of \fBpassthrough\fR indicates that no changes -are made to the \fBACL\fR other than generating the necessary \fBACL\fR entries -to represent the new mode of the file or directory. +an \fBaclmode\fR property of \fBdiscard\fR (the default) deletes all \fBACL\fR +entries that do not represent the mode of the file. An \fBaclmode\fR property +of \fBgroupmask\fR reduces permissions granted in all \fBALLOW\fR entries found +in the \fBACL\fR such that they are no greater than the group permissions +specified by \fBchmod\fR. A file system with an \fBaclmode\fR property of +\fBpassthrough\fR indicates that no changes are made to the \fBACL\fR other +than creating or updating the necessary \fBACL\fR entries to +represent the new mode of the file or directory. .RE .sp @@ -3323,7 +3322,7 @@ pool/home/bob setuid on default pool/home/bob readonly off default pool/home/bob zoned off default pool/home/bob snapdir hidden default -pool/home/bob aclmode groupmask default +pool/home/bob aclmode discard default pool/home/bob aclinherit restricted default pool/home/bob canmount on default pool/home/bob shareiscsi off default diff --git a/usr/src/uts/common/fs/fs_subr.c b/usr/src/uts/common/fs/fs_subr.c index 1858d0ef3059..744d269716c3 100644 --- a/usr/src/uts/common/fs/fs_subr.c +++ b/usr/src/uts/common/fs/fs_subr.c @@ -24,6 +24,7 @@ /* * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. */ /* @@ -622,7 +623,8 @@ fs_fab_acl( aclentp->a_id = (gid_t)-1; /* Really undefined */ } else if (vsecattr->vsa_mask & (VSA_ACECNT | VSA_ACE)) { VERIFY(0 == acl_trivial_create(vattr.va_mode, - (ace_t **)&vsecattr->vsa_aclentp, &vsecattr->vsa_aclcnt)); + (vp->v_type == VDIR), (ace_t **)&vsecattr->vsa_aclentp, + &vsecattr->vsa_aclcnt)); vsecattr->vsa_aclentsz = vsecattr->vsa_aclcnt * sizeof (ace_t); } diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_acl.h b/usr/src/uts/common/fs/zfs/sys/zfs_acl.h index c1a0aeebdce4..d1a64180d5d0 100644 --- a/usr/src/uts/common/fs/zfs/sys/zfs_acl.h +++ b/usr/src/uts/common/fs/zfs/sys/zfs_acl.h @@ -218,7 +218,7 @@ int zfs_fastaccesschk_execute(struct znode *, cred_t *); extern int zfs_zaccess_rwx(struct znode *, mode_t, int, cred_t *); extern int zfs_zaccess_unix(struct znode *, mode_t, cred_t *); extern int zfs_acl_access(struct znode *, int, cred_t *); -void zfs_acl_chmod_setattr(struct znode *, zfs_acl_t **, uint64_t); +int zfs_acl_chmod_setattr(struct znode *, zfs_acl_t **, uint64_t); int zfs_zaccess_delete(struct znode *, struct znode *, cred_t *); int zfs_zaccess_rename(struct znode *, struct znode *, struct znode *, struct znode *, cred_t *cr); diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h b/usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h index 38c87df4300f..9af5cef05863 100644 --- a/usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h +++ b/usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h @@ -57,6 +57,7 @@ struct zfsvfs { boolean_t z_fuid_dirty; /* need to sync fuid table ? */ struct zfs_fuid_info *z_fuid_replay; /* fuid info for replay */ zilog_t *z_log; /* intent log pointer */ + uint_t z_acl_mode; /* acl chmod/mode behavior */ uint_t z_acl_inherit; /* acl inheritance behavior */ zfs_case_t z_case; /* case-sense */ boolean_t z_utf8; /* utf8-only */ diff --git a/usr/src/uts/common/fs/zfs/zfs_acl.c b/usr/src/uts/common/fs/zfs/zfs_acl.c index 843b5ff06ef4..2b93fc8329f9 100644 --- a/usr/src/uts/common/fs/zfs/zfs_acl.c +++ b/usr/src/uts/common/fs/zfs/zfs_acl.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. */ #include @@ -1330,75 +1331,8 @@ zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, cred_t *cr, dmu_tx_t *tx) return (sa_bulk_update(zp->z_sa_hdl, bulk, count, tx)); } -/* - * Update access mask for prepended ACE - * - * This applies the "groupmask" value for aclmode property. - */ -static void -zfs_acl_prepend_fixup(zfs_acl_t *aclp, void *acep, void *origacep, - mode_t mode, uint64_t owner) -{ - int rmask, wmask, xmask; - int user_ace; - uint16_t aceflags; - uint32_t origmask, acepmask; - uint64_t fuid; - - aceflags = aclp->z_ops.ace_flags_get(acep); - fuid = aclp->z_ops.ace_who_get(acep); - origmask = aclp->z_ops.ace_mask_get(origacep); - acepmask = aclp->z_ops.ace_mask_get(acep); - - user_ace = (!(aceflags & - (ACE_OWNER|ACE_GROUP|ACE_IDENTIFIER_GROUP))); - - if (user_ace && (fuid == owner)) { - rmask = S_IRUSR; - wmask = S_IWUSR; - xmask = S_IXUSR; - } else { - rmask = S_IRGRP; - wmask = S_IWGRP; - xmask = S_IXGRP; - } - - if (origmask & ACE_READ_DATA) { - if (mode & rmask) { - acepmask &= ~ACE_READ_DATA; - } else { - acepmask |= ACE_READ_DATA; - } - } - - if (origmask & ACE_WRITE_DATA) { - if (mode & wmask) { - acepmask &= ~ACE_WRITE_DATA; - } else { - acepmask |= ACE_WRITE_DATA; - } - } - - if (origmask & ACE_APPEND_DATA) { - if (mode & wmask) { - acepmask &= ~ACE_APPEND_DATA; - } else { - acepmask |= ACE_APPEND_DATA; - } - } - - if (origmask & ACE_EXECUTE) { - if (mode & xmask) { - acepmask &= ~ACE_EXECUTE; - } else { - acepmask |= ACE_EXECUTE; - } - } - aclp->z_ops.ace_mask_set(acep, acepmask); -} - static void -zfs_acl_chmod(zfsvfs_t *zfsvfs, uint64_t mode, zfs_acl_t *aclp) +zfs_acl_chmod(vtype_t vtype, uint64_t mode, boolean_t trim, zfs_acl_t *aclp) { void *acep = NULL; uint64_t who; @@ -1410,30 +1344,31 @@ zfs_acl_chmod(zfsvfs_t *zfsvfs, uint64_t mode, zfs_acl_t *aclp) zfs_acl_node_t *newnode; size_t abstract_size = aclp->z_ops.ace_abstract_size(); void *zacep; - uint32_t owner, group, everyone; - uint32_t deny1, deny2, allow0; + boolean_t isdir; + trivial_acl_t masks; new_count = new_bytes = 0; - acl_trivial_access_masks((mode_t)mode, &allow0, &deny1, &deny2, - &owner, &group, &everyone); + isdir = (vtype == VDIR); + + acl_trivial_access_masks((mode_t)mode, isdir, &masks); newnode = zfs_acl_node_alloc((abstract_size * 6) + aclp->z_acl_bytes); zacep = newnode->z_acldata; - if (allow0) { - zfs_set_ace(aclp, zacep, allow0, ALLOW, -1, ACE_OWNER); + if (masks.allow0) { + zfs_set_ace(aclp, zacep, masks.allow0, ALLOW, -1, ACE_OWNER); zacep = (void *)((uintptr_t)zacep + abstract_size); new_count++; new_bytes += abstract_size; - } if (deny1) { - zfs_set_ace(aclp, zacep, deny1, DENY, -1, ACE_OWNER); + } if (masks.deny1) { + zfs_set_ace(aclp, zacep, masks.deny1, DENY, -1, ACE_OWNER); zacep = (void *)((uintptr_t)zacep + abstract_size); new_count++; new_bytes += abstract_size; } - if (deny2) { - zfs_set_ace(aclp, zacep, deny2, DENY, -1, OWNING_GROUP); + if (masks.deny2) { + zfs_set_ace(aclp, zacep, masks.deny2, DENY, -1, OWNING_GROUP); zacep = (void *)((uintptr_t)zacep + abstract_size); new_count++; new_bytes += abstract_size; @@ -1452,10 +1387,17 @@ zfs_acl_chmod(zfsvfs_t *zfsvfs, uint64_t mode, zfs_acl_t *aclp) continue; } + /* + * If this ACL has any inheritable ACEs, mark that in + * the hints (which are later masked into the pflags) + * so create knows to do inheritance. + */ + if (isdir && (inherit_flags & + (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE))) + aclp->z_hints |= ZFS_INHERIT_ACE; + if ((type != ALLOW && type != DENY) || (inherit_flags & ACE_INHERIT_ONLY_ACE)) { - if (inherit_flags) - aclp->z_hints |= ZFS_INHERIT_ACE; switch (type) { case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: @@ -1468,20 +1410,13 @@ zfs_acl_chmod(zfsvfs_t *zfsvfs, uint64_t mode, zfs_acl_t *aclp) /* * Limit permissions to be no greater than - * group permissions + * group permissions. + * The "aclinherit" and "aclmode" properties + * affect policy for create and chmod(2), + * respectively. */ - if (zfsvfs->z_acl_inherit == ZFS_ACL_RESTRICTED) { - if (!(mode & S_IRGRP)) - access_mask &= ~ACE_READ_DATA; - if (!(mode & S_IWGRP)) - access_mask &= - ~(ACE_WRITE_DATA|ACE_APPEND_DATA); - if (!(mode & S_IXGRP)) - access_mask &= ~ACE_EXECUTE; - access_mask &= - ~(ACE_WRITE_OWNER|ACE_WRITE_ACL| - ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS); - } + if ((type == ALLOW) && trim) + access_mask &= masks.group; } zfs_set_ace(aclp, zacep, access_mask, type, who, iflags); ace_size = aclp->z_ops.ace_size(acep); @@ -1489,11 +1424,11 @@ zfs_acl_chmod(zfsvfs_t *zfsvfs, uint64_t mode, zfs_acl_t *aclp) new_count++; new_bytes += ace_size; } - zfs_set_ace(aclp, zacep, owner, 0, -1, ACE_OWNER); + zfs_set_ace(aclp, zacep, masks.owner, 0, -1, ACE_OWNER); zacep = (void *)((uintptr_t)zacep + abstract_size); - zfs_set_ace(aclp, zacep, group, 0, -1, OWNING_GROUP); + zfs_set_ace(aclp, zacep, masks.group, 0, -1, OWNING_GROUP); zacep = (void *)((uintptr_t)zacep + abstract_size); - zfs_set_ace(aclp, zacep, everyone, 0, -1, ACE_EVERYONE); + zfs_set_ace(aclp, zacep, masks.everyone, 0, -1, ACE_EVERYONE); new_count += 3; new_bytes += abstract_size * 3; @@ -1505,17 +1440,27 @@ zfs_acl_chmod(zfsvfs_t *zfsvfs, uint64_t mode, zfs_acl_t *aclp) list_insert_tail(&aclp->z_acl, newnode); } -void +int zfs_acl_chmod_setattr(znode_t *zp, zfs_acl_t **aclp, uint64_t mode) { + int error = 0; + mutex_enter(&zp->z_acl_lock); mutex_enter(&zp->z_lock); - *aclp = zfs_acl_alloc(zfs_acl_version_zp(zp)); - (*aclp)->z_hints = zp->z_pflags & V4_ACL_WIDE_FLAGS; - zfs_acl_chmod(zp->z_zfsvfs, mode, *aclp); + if (zp->z_zfsvfs->z_acl_mode == ZFS_ACL_DISCARD) + *aclp = zfs_acl_alloc(zfs_acl_version_zp(zp)); + else + error = zfs_acl_node_read(zp, B_TRUE, aclp, B_TRUE); + + if (error == 0) { + (*aclp)->z_hints = zp->z_pflags & V4_ACL_WIDE_FLAGS; + zfs_acl_chmod(ZTOV(zp)->v_type, mode, + (zp->z_zfsvfs->z_acl_mode == ZFS_ACL_GROUPMASK), *aclp); + } mutex_exit(&zp->z_lock); mutex_exit(&zp->z_acl_lock); - ASSERT(*aclp); + + return (error); } /* @@ -1763,8 +1708,8 @@ zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr, if (acl_ids->z_aclp == NULL) { mutex_enter(&dzp->z_acl_lock); mutex_enter(&dzp->z_lock); - if (!(flag & IS_ROOT_NODE) && (ZTOV(dzp)->v_type == VDIR && - (dzp->z_pflags & ZFS_INHERIT_ACE)) && + if (!(flag & IS_ROOT_NODE) && + (dzp->z_pflags & ZFS_INHERIT_ACE) && !(dzp->z_pflags & ZFS_XATTR)) { VERIFY(0 == zfs_acl_node_read(dzp, B_TRUE, &paclp, B_FALSE)); @@ -1781,7 +1726,9 @@ zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr, if (need_chmod) { acl_ids->z_aclp->z_hints |= (vap->va_type == VDIR) ? ZFS_ACL_AUTO_INHERIT : 0; - zfs_acl_chmod(zfsvfs, acl_ids->z_mode, acl_ids->z_aclp); + zfs_acl_chmod(vap->va_type, acl_ids->z_mode, + (zfsvfs->z_acl_inherit == ZFS_ACL_RESTRICTED), + acl_ids->z_aclp); } } diff --git a/usr/src/uts/common/fs/zfs/zfs_vfsops.c b/usr/src/uts/common/fs/zfs/zfs_vfsops.c index 4970552d0cb7..14b888b29e03 100644 --- a/usr/src/uts/common/fs/zfs/zfs_vfsops.c +++ b/usr/src/uts/common/fs/zfs/zfs_vfsops.c @@ -383,6 +383,14 @@ vscan_changed_cb(void *arg, uint64_t newval) zfsvfs->z_vscan = newval; } +static void +acl_mode_changed_cb(void *arg, uint64_t newval) +{ + zfsvfs_t *zfsvfs = arg; + + zfsvfs->z_acl_mode = newval; +} + static void acl_inherit_changed_cb(void *arg, uint64_t newval) { @@ -513,6 +521,8 @@ zfs_register_callbacks(vfs_t *vfsp) "exec", exec_changed_cb, zfsvfs); error = error ? error : dsl_prop_register(ds, "snapdir", snapdir_changed_cb, zfsvfs); + error = error ? error : dsl_prop_register(ds, + "aclmode", acl_mode_changed_cb, zfsvfs); error = error ? error : dsl_prop_register(ds, "aclinherit", acl_inherit_changed_cb, zfsvfs); error = error ? error : dsl_prop_register(ds, @@ -554,6 +564,7 @@ zfs_register_callbacks(vfs_t *vfsp) (void) dsl_prop_unregister(ds, "setuid", setuid_changed_cb, zfsvfs); (void) dsl_prop_unregister(ds, "exec", exec_changed_cb, zfsvfs); (void) dsl_prop_unregister(ds, "snapdir", snapdir_changed_cb, zfsvfs); + (void) dsl_prop_unregister(ds, "aclmode", acl_mode_changed_cb, zfsvfs); (void) dsl_prop_unregister(ds, "aclinherit", acl_inherit_changed_cb, zfsvfs); (void) dsl_prop_unregister(ds, "vscan", vscan_changed_cb, zfsvfs); @@ -1236,6 +1247,9 @@ zfs_unregister_callbacks(zfsvfs_t *zfsvfs) VERIFY(dsl_prop_unregister(ds, "snapdir", snapdir_changed_cb, zfsvfs) == 0); + VERIFY(dsl_prop_unregister(ds, "aclmode", acl_mode_changed_cb, + zfsvfs) == 0); + VERIFY(dsl_prop_unregister(ds, "aclinherit", acl_inherit_changed_cb, zfsvfs) == 0); diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c index 6081470b0bce..f26a65661f7a 100644 --- a/usr/src/uts/common/fs/zfs/zfs_vnops.c +++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c @@ -2975,7 +2975,8 @@ zfs_setattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, uint64_t acl_obj; new_mode = (pmode & S_IFMT) | (vap->va_mode & ~S_IFMT); - zfs_acl_chmod_setattr(zp, &aclp, new_mode); + if (err = zfs_acl_chmod_setattr(zp, &aclp, new_mode)) + goto out; mutex_enter(&zp->z_lock); if (!zp->z_is_sa && ((acl_obj = zfs_external_acl(zp)) != 0)) { diff --git a/usr/src/uts/common/sys/fs/zfs.h b/usr/src/uts/common/sys/fs/zfs.h index da0b12bab4a9..6864bb81df56 100644 --- a/usr/src/uts/common/sys/fs/zfs.h +++ b/usr/src/uts/common/sys/fs/zfs.h @@ -87,7 +87,7 @@ typedef enum { ZFS_PROP_READONLY, ZFS_PROP_ZONED, ZFS_PROP_SNAPDIR, - ZFS_PROP_PRIVATE, /* not exposed to user, temporary */ + ZFS_PROP_ACLMODE, ZFS_PROP_ACLINHERIT, ZFS_PROP_CREATETXG, /* not exposed to the user */ ZFS_PROP_NAME, /* not exposed to the user */