diff options
author | Meghana Madhusudhan <mmadhusu@redhat.com> | 2014-11-10 15:20:51 +0530 |
---|---|---|
committer | Niels de Vos <ndevos@redhat.com> | 2014-11-13 11:58:00 -0800 |
commit | 878b30420891c8b00043391cdce90930eaf18795 (patch) | |
tree | 5a6e783a4dda30d3020b0a00b482ca7e6f70169a | |
parent | b4597a92ccfebf362c63977bc4bada7b65e28753 (diff) |
gNFS: Allow reading ACLs even without read permissions on the file.
When root-squash is enabled or when no permissions are given to
a file, NFS threw permission errors. According to the kernel-nfs
behaviour, no permissions are required to read ACLs.
When no ACLs are set, the system call sys_lgetxattr fails and
returns a ENODATA error. This translates to ESERVERFAULT error
in NFS. Fuse makes an exception to this error and returns a success
case. Similar changes are made here to achieve the expected behaviour.
Change-Id: I46b8f5911114eb087a3f8ca4e921b6b41e83f3b3
BUG: 1161092
Signed-off-by: Meghana Madhusudhan <mmadhusu@redhat.com>
Signed-off-by: Niels de Vos <ndevos@redhat.com>
Reviewed-on: http://review.gluster.org/9085
Tested-by: Gluster Build System <jenkins@build.gluster.com>
-rw-r--r-- | tests/bugs/bug-1161092-nfs-acls.t | 36 | ||||
-rw-r--r-- | xlators/nfs/server/src/acl3.c | 86 | ||||
-rw-r--r-- | xlators/system/posix-acl/src/posix-acl.c | 2 |
3 files changed, 115 insertions, 9 deletions
diff --git a/tests/bugs/bug-1161092-nfs-acls.t b/tests/bugs/bug-1161092-nfs-acls.t new file mode 100644 index 00000000000..f64ae5b3c18 --- /dev/null +++ b/tests/bugs/bug-1161092-nfs-acls.t @@ -0,0 +1,36 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../nfs.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume info + +TEST $CLI volume create $V0 $H0:$B0/brick1; +EXPECT 'Created' volinfo_field $V0 'Status'; + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +EXPECT_WITHIN $NFS_EXPORT_TIMEOUT 1 is_nfs_export_available +TEST mount_nfs $H0:/$V0 $N0 + +TEST touch $N0/file1 +TEST chmod 700 $N0/file1 +TEST getfacl $N0/file1 + +TEST $CLI volume set $V0 root-squash on +TEST getfacl $N0/file1 + +TEST umount_nfs $H0:/$V0 $N0 +TEST mount_nfs $H0:/$V0 $N0 +TEST getfacl $N0/file1 + +## Before killing daemon to avoid deadlocks +umount_nfs $N0 + +cleanup; + diff --git a/xlators/nfs/server/src/acl3.c b/xlators/nfs/server/src/acl3.c index 5cd8b8e7061..b00e8170ebd 100644 --- a/xlators/nfs/server/src/acl3.c +++ b/xlators/nfs/server/src/acl3.c @@ -29,6 +29,7 @@ #include "nfs-generics.h" #include "acl3.h" #include "byte-order.h" +#include "compat-errno.h" static int acl3_nfs_acl_to_xattr (aclentry *ace, void *xattrbuf, @@ -244,7 +245,10 @@ acl3_setacl_reply (rpcsvc_request_t *req, setaclreply *reply) return 0; } - +/* acl3_getacl_cbk: fetch and decode the ACL in the POSIX_ACL_ACCESS_XATTR + * + * The POSIX_ACL_ACCESS_XATTR can be set on files and directories. + */ int acl3_getacl_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, dict_t *dict, @@ -260,17 +264,16 @@ acl3_getacl_cbk (call_frame_t *frame, void *cookie, xlator_t *this, if (!frame->local) { gf_log (GF_ACL, GF_LOG_ERROR, "Invalid argument," " frame->local NULL"); - return EINVAL; + return -EINVAL; } cs = frame->local; getaclreply = &cs->args.getaclreply; - if (op_ret < 0) { + if ((op_ret < 0) && (op_errno != ENODATA && op_errno != ENOATTR)) { stat = nfs3_cbk_errno_status (op_ret, op_errno); goto err; } getaclreply->aclentry.aclentry_val = cs->aclentry; - getaclreply->daclentry.daclentry_val = cs->daclentry; /* getfacl: NFS USER ACL */ data = dict_get (dict, POSIX_ACL_ACCESS_XATTR); @@ -285,11 +288,59 @@ acl3_getacl_cbk (call_frame_t *frame, void *cookie, xlator_t *this, stat = nfs3_errno_to_nfsstat3 (-aclcount); goto err; } - getaclreply->aclcount = aclcount; getaclreply->aclentry.aclentry_len = aclcount; } + acl3_getacl_reply (cs->req, getaclreply); + nfs3_call_state_wipe (cs); + return 0; + +err: + if (getaclreply) + getaclreply->status = stat; + acl3_getacl_reply (cs->req, getaclreply); + nfs3_call_state_wipe (cs); + return 0; +} + +/* acl3_default_getacl_cbk: fetch and decode the ACL set in the + * POSIX_ACL_DEFAULT_XATTR xattr. + * + * The POSIX_ACL_DEFAULT_XATTR xattr is only set on directories, not on files. + * + * When done with POSIX_ACL_DEFAULT_XATTR, we also need to get and decode the + * ACL that can be set in POSIX_ACL_DEFAULT_XATTR. + */ +int +acl3_default_getacl_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict, + dict_t *xdata) +{ + nfsstat3 stat = NFS3ERR_SERVERFAULT; + nfs3_call_state_t *cs = NULL; + data_t *data = NULL; + getaclreply *getaclreply = NULL; + int aclcount = 0; + int defacl = 1; /* DEFAULT ACL */ + nfs_user_t nfu = {0, }; + int ret = -1; + + if (!frame->local) { + gf_log (GF_ACL, GF_LOG_ERROR, "Invalid argument," + " frame->local NULL"); + return -EINVAL; + } + cs = frame->local; + getaclreply = &cs->args.getaclreply; + if ((op_ret < 0) && (op_errno != ENODATA && op_errno != ENOATTR)) { + stat = nfs3_cbk_errno_status (op_ret, op_errno); + goto err; + } + + + getaclreply->daclentry.daclentry_val = cs->daclentry; + /* getfacl: NFS DEFAULT ACL */ data = dict_get (dict, POSIX_ACL_DEFAULT_XATTR); if (data && data->data) { @@ -308,8 +359,15 @@ acl3_getacl_cbk (call_frame_t *frame, void *cookie, xlator_t *this, getaclreply->daclentry.daclentry_len = aclcount; } - acl3_getacl_reply (cs->req, getaclreply); - nfs3_call_state_wipe (cs); + getaclreply->attr_follows = TRUE; + nfs_request_user_init (&nfu, cs->req); + ret = nfs_getxattr (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, + POSIX_ACL_ACCESS_XATTR, NULL, acl3_getacl_cbk, cs); + if (ret < 0) { + stat = nfs3_errno_to_nfsstat3 (-ret); + goto err; + } + return 0; err: @@ -320,6 +378,7 @@ err: return 0; } + int acl3_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, struct iatt *buf, @@ -353,12 +412,21 @@ acl3_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, getaclreply->attr = nfs3_stat_to_fattr3 (buf); nfs_request_user_init (&nfu, cs->req); - ret = nfs_getxattr (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, - NULL, NULL, acl3_getacl_cbk, cs); + if (buf->ia_type == IA_IFDIR) { + ret = nfs_getxattr (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, + POSIX_ACL_DEFAULT_XATTR, NULL, + acl3_default_getacl_cbk, cs); + } else { + ret = nfs_getxattr (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, + POSIX_ACL_ACCESS_XATTR, NULL, + acl3_getacl_cbk, cs); + } + if (ret < 0) { stat = nfs3_errno_to_nfsstat3 (-ret); goto err; } + return 0; err: getaclreply->status = stat; diff --git a/xlators/system/posix-acl/src/posix-acl.c b/xlators/system/posix-acl/src/posix-acl.c index 500bd6c3c79..05608696ea6 100644 --- a/xlators/system/posix-acl/src/posix-acl.c +++ b/xlators/system/posix-acl/src/posix-acl.c @@ -1973,11 +1973,13 @@ posix_acl_getxattr (call_frame_t *frame, xlator_t *this, loc_t *loc, goto green; else goto red; + green: STACK_WIND (frame, posix_acl_getxattr_cbk, FIRST_CHILD(this), FIRST_CHILD(this)->fops->getxattr, loc, name, xdata); return 0; + red: STACK_UNWIND_STRICT (getxattr, frame, -1, EACCES, NULL, xdata); |