summaryrefslogtreecommitdiffstats
path: root/xlators/nfs/server/src/acl3.c
diff options
context:
space:
mode:
authorSantosh Kumar Pradhan <spradhan@redhat.com>2013-11-27 15:50:21 +0530
committerAnand Avati <avati@redhat.com>2013-12-03 15:22:03 -0800
commite4b9a74f46bca3894d686ce87042168c4304f07b (patch)
tree903e4b2ba55fe66aa83d652a7a3e9172c849adf0 /xlators/nfs/server/src/acl3.c
parent916785766777ea74c30df17b6e2c572bc1c9a534 (diff)
gNFS: Inconsistent behaviour of setfacl/getfacl
The permissions returned by NFS ACL are wrong, which are rejected by NFS client as "Invalid argument". Refactor the NFS ACL code to return the proper permissions which would match with the requested permissions. Change-Id: I409a6600538a90f2c5c2e8d84657c3b508468fe6 BUG: 1035218 Signed-off-by: Santosh Kumar Pradhan <spradhan@redhat.com> Reviewed-on: http://review.gluster.org/6368 Tested-by: Gluster Build System <jenkins@build.gluster.com> Reviewed-by: Anand Avati <avati@redhat.com>
Diffstat (limited to 'xlators/nfs/server/src/acl3.c')
-rw-r--r--xlators/nfs/server/src/acl3.c294
1 files changed, 201 insertions, 93 deletions
diff --git a/xlators/nfs/server/src/acl3.c b/xlators/nfs/server/src/acl3.c
index a9843c7108b..59c7637e3b4 100644
--- a/xlators/nfs/server/src/acl3.c
+++ b/xlators/nfs/server/src/acl3.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Red Hat, Inc. <http://www.redhat.com>
+ * Copyright (c) 2012-2013 Red Hat, Inc. <http://www.redhat.com>
* This file is part of GlusterFS.
*
* This file is licensed to you under your choice of the GNU Lesser
@@ -28,7 +28,15 @@
#include "nfs3-fh.h"
#include "nfs-generics.h"
#include "acl3.h"
+#include "byte-order.h"
+static int
+acl3_nfs_acl_to_xattr (aclentry *ace, void *xattrbuf,
+ int aclcount, int defacl);
+
+static int
+acl3_nfs_acl_from_xattr (aclentry *ace, void *xattrbuf,
+ int bufsize, int defacl);
typedef ssize_t (*acl3_serializer) (struct iovec outmsg, void *args);
@@ -233,12 +241,12 @@ acl3_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;
- int *p = NULL;
- int i = 0;
- getaclreply *getaclreply = NULL;
+ 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 */
if (!frame->local) {
gf_log (GF_ACL, GF_LOG_ERROR, "Invalid argument,"
@@ -255,32 +263,40 @@ acl3_getacl_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
getaclreply->aclentry.aclentry_val = cs->aclentry;
getaclreply->daclentry.daclentry_val = cs->daclentry;
- /* FIXME: use posix_acl_from_xattr() */
+ /* getfacl: NFS USER ACL */
data = dict_get (dict, POSIX_ACL_ACCESS_XATTR);
- if (data && (p = data_to_bin (data))) {
- /* POSIX_ACL_VERSION */
- p++;
- while ((char *)p < (data->data + data->len)) {
- getaclreply->aclentry.aclentry_val[i].type = *(*(short **)&p)++;
- getaclreply->aclentry.aclentry_val[i].perm = *(*(short **)&p)++;
- getaclreply->aclentry.aclentry_val[i].uid = *(*(int **)&p)++;
- i++;
+ if (data && data->data) {
+ aclcount = acl3_nfs_acl_from_xattr (cs->aclentry,
+ data->data,
+ data->len,
+ !defacl);
+ if (aclcount < 0) {
+ gf_log (GF_ACL, GF_LOG_ERROR,
+ "Failed to get USER ACL");
+ stat = nfs3_errno_to_nfsstat3 (-aclcount);
+ goto err;
}
- getaclreply->aclcount = getaclreply->aclentry.aclentry_len = i;
+
+ getaclreply->aclcount = aclcount;
+ getaclreply->aclentry.aclentry_len = aclcount;
}
- i = 0;
+ /* getfacl: NFS DEFAULT ACL */
data = dict_get (dict, POSIX_ACL_DEFAULT_XATTR);
- if (data && (p = data_to_bin (data))) {
- /* POSIX_ACL_VERSION */
- p++;
- while ((char *)p < (data->data + data->len)) {
- getaclreply->daclentry.daclentry_val[i].type = *(*(short **)&p)++;
- getaclreply->daclentry.daclentry_val[i].perm = *(*(short **)&p)++;
- getaclreply->daclentry.daclentry_val[i].uid = *(*(int **)&p)++;
- i++;
+ if (data && data->data) {
+ aclcount = acl3_nfs_acl_from_xattr (cs->daclentry,
+ data->data,
+ data->len,
+ defacl);
+ if (aclcount < 0) {
+ gf_log (GF_ACL, GF_LOG_ERROR,
+ "Failed to get DEFAULT ACL");
+ stat = nfs3_errno_to_nfsstat3 (-aclcount);
+ goto err;
}
- getaclreply->daclcount = getaclreply->daclentry.daclentry_len = i;
+
+ getaclreply->daclcount = aclcount;
+ getaclreply->daclentry.daclentry_len = aclcount;
}
acl3_getacl_reply (cs, getaclreply);
@@ -481,20 +497,19 @@ acl3err:
int
acl3svc_setacl (rpcsvc_request_t *req)
{
- xlator_t *vol = NULL;
+ xlator_t *vol = NULL;
struct nfs_state *nfs = NULL;
nfs3_state_t *nfs3 = NULL;
- nfs3_call_state_t *cs = NULL;
- int ret = RPCSVC_ACTOR_ERROR;
- nfsstat3 stat = NFS3ERR_SERVERFAULT;
- struct nfs3_fh fh;
+ nfs3_call_state_t *cs = NULL;
+ int ret = RPCSVC_ACTOR_ERROR;
+ nfsstat3 stat = NFS3ERR_SERVERFAULT;
+ struct nfs3_fh fh;
struct nfs3_fh *fhp = NULL;
- setaclargs setaclargs;
- aclentry *aclentry = NULL;
- struct aclentry *daclentry = NULL;
- int i = 0;
- struct posix_acl_xattr_header *bufheader = NULL;
- struct posix_acl_xattr_entry *bufentry = NULL;
+ setaclargs setaclargs;
+ aclentry *aclentry = NULL;
+ struct aclentry *daclentry = NULL;
+ int aclerrno = 0;
+ int defacl = 1;
if (!req)
return ret;
@@ -534,64 +549,27 @@ acl3svc_setacl (rpcsvc_request_t *req)
cs->aclcount = setaclargs.aclcount;
cs->daclcount = setaclargs.daclcount;
- if ((cs->aclcount > NFS_ACL_MAX_ENTRIES) ||
- (cs->daclcount > NFS_ACL_MAX_ENTRIES))
+ /* setfacl: NFS USER ACL */
+ aclerrno = acl3_nfs_acl_to_xattr (aclentry,
+ cs->aclxattr,
+ cs->aclcount,
+ !defacl);
+ if (aclerrno < 0) {
+ gf_log (GF_ACL, GF_LOG_ERROR, "Failed to set USER ACL");
+ stat = nfs3_errno_to_nfsstat3 (-aclerrno);
goto acl3err;
- /* FIXME: use posix_acl_to_xattr() */
- /* Populate xattr buffer for user ACL */
- bufheader = (struct posix_acl_xattr_header *)(cs->aclxattr);
- bufheader->version = htole32(POSIX_ACL_VERSION);
- bufentry = bufheader->entries;
- for (i = 0; i < cs->aclcount; i++) {
- int uaceuid;
- const struct aclentry *uace = &aclentry[i];
- switch (uace->type) {
- case POSIX_ACL_USER:
- case POSIX_ACL_GROUP:
- uaceuid = uace->uid;
- break;
- default:
- uaceuid = POSIX_ACL_UNDEFINED_ID;
- break;
- }
- bufentry->tag = htole16(uace->type);
- bufentry->perm = htole16(uace->perm);
- bufentry->id = htole32(uaceuid);
-
- bufentry++;
- }
-
- /* Populate xattr buffer for Default ACL */
- bufheader = (struct posix_acl_xattr_header *)(cs->daclxattr);
- bufheader->version = htole32(POSIX_ACL_VERSION);
- bufentry = bufheader->entries;
- for (i = 0; i < cs->daclcount; i++) {
- int daceuid;
- int dacetype;
- const struct aclentry *dace = &daclentry[i];
- /*
- * For "default ACL", NFSv3 handles the 'type' differently
- * i.e. by logical OR'ing 'type' with NFS_ACL_DEFAULT.
- * Which the backend File system does not understand and
- * that needs to be masked OFF.
- */
- dacetype = (dace->type & ~(NFS_ACL_DEFAULT));
- switch (dacetype) {
- case POSIX_ACL_USER:
- case POSIX_ACL_GROUP:
- daceuid = dace->uid;
- break;
- default:
- daceuid = POSIX_ACL_UNDEFINED_ID;
- break;
- }
- bufentry->tag = htole16(dacetype);
- bufentry->perm = htole16(dace->perm);
- bufentry->id = htole32(daceuid);
-
- bufentry++;
}
+ /* setfacl: NFS DEFAULT ACL */
+ aclerrno = acl3_nfs_acl_to_xattr (daclentry,
+ cs->daclxattr,
+ cs->daclcount,
+ defacl);
+ if (aclerrno < 0) {
+ gf_log (GF_ACL, GF_LOG_ERROR, "Failed to set DEFAULT ACL");
+ stat = nfs3_errno_to_nfsstat3 (-aclerrno);
+ goto acl3err;
+ }
ret = nfs3_fh_resolve_and_resume (cs, fhp,
NULL, acl3_setacl_resume);
@@ -706,3 +684,133 @@ acl3svc_init(xlator_t *nfsx)
err:
return NULL;
}
+
+static int
+acl3_nfs_acl_to_xattr (aclentry *ace, /* ACL entries to be read */
+ void *xattrbuf, /* XATTR buf to be populated */
+ int aclcount, /* No of ACLs to be read */
+ int defacl) /* 1 if DEFAULT ACL */
+{
+ int idx = 0;
+ posix_acl_xattr_header *xheader = NULL;
+ posix_acl_xattr_entry *xentry = NULL;
+
+ if ((!ace) || (!xattrbuf))
+ return (-EINVAL);
+
+ /* ACL count is ZERO, nothing to do */
+ if (!aclcount)
+ return (0);
+
+ if ((aclcount < 0) || (aclcount > NFS_ACL_MAX_ENTRIES))
+ return (-EINVAL);
+
+ xheader = (posix_acl_xattr_header *) (xattrbuf);
+ xentry = (posix_acl_xattr_entry *) (xheader + 1);
+
+ /*
+ * For "default ACL", NFSv3 handles the 'type' differently
+ * i.e. by logical OR'ing 'type' with NFS_ACL_DEFAULT.
+ * Which the backend File system does not understand and
+ * that needs to be masked OFF.
+ */
+ xheader->version = POSIX_ACL_XATTR_VERSION;
+
+ for (idx = 0; idx < aclcount; idx++) {
+ xentry->tag = ace->type;
+ if (defacl)
+ xentry->tag &= ~NFS_ACL_DEFAULT;
+ xentry->perm = ace->perm;
+
+ switch (xentry->tag) {
+ case POSIX_ACL_USER:
+ case POSIX_ACL_GROUP:
+ if (xentry->perm & ~S_IRWXO)
+ return (-EINVAL);
+ xentry->id = ace->uid;
+ break;
+ case POSIX_ACL_USER_OBJ:
+ case POSIX_ACL_GROUP_OBJ:
+ case POSIX_ACL_OTHER:
+ if (xentry->perm & ~S_IRWXO)
+ return (-EINVAL);
+ xentry->id = POSIX_ACL_UNDEFINED_ID;
+ break;
+ case POSIX_ACL_MASK:
+ /* Solaris sometimes sets additional bits in
+ * the mask.
+ */
+ xentry->perm &= S_IRWXO;
+ xentry->id = POSIX_ACL_UNDEFINED_ID;
+ break;
+ default:
+ return (-EINVAL);
+ }
+
+ xentry++;
+ ace++;
+ }
+
+ /* SUCCESS */
+ return (0);
+}
+
+static int
+acl3_nfs_acl_from_xattr (aclentry *ace, /* ACL entries to be filled */
+ void *xattrbuf, /* XATTR buf to be read */
+ int bufsize, /* Size of XATTR buffer */
+ int defacl) /* 1 if DEFAULT ACL */
+{
+ int idx = 0;
+ ssize_t aclcount = 0;
+ posix_acl_xattr_header *xheader = NULL;
+ posix_acl_xattr_entry *xentry = NULL;
+
+ if ((!xattrbuf) || (!ace))
+ return (-EINVAL);
+
+ aclcount = posix_acl_xattr_count (bufsize);
+ if ((aclcount < 0) || (aclcount > NFS_ACL_MAX_ENTRIES))
+ return (-EINVAL);
+
+ xheader = (posix_acl_xattr_header *) (xattrbuf);
+ xentry = (posix_acl_xattr_entry *) (xheader + 1);
+
+ /* Check for supported POSIX ACL xattr version */
+ if (xheader->version != POSIX_ACL_XATTR_VERSION)
+ return (-ENOSYS);
+
+ for (idx = 0; idx < (int)aclcount; idx++) {
+ ace->type = xentry->tag;
+ if (defacl) {
+ /*
+ * SET the NFS_ACL_DEFAULT flag for default
+ * ACL which was masked OFF during setfacl().
+ */
+ ace->type |= NFS_ACL_DEFAULT;
+ }
+ ace->perm = (xentry->perm & S_IRWXO);
+
+ switch (xentry->tag) {
+ case POSIX_ACL_USER:
+ case POSIX_ACL_GROUP:
+ ace->uid = xentry->id;
+ break;
+ case POSIX_ACL_USER_OBJ:
+ case POSIX_ACL_GROUP_OBJ:
+ case POSIX_ACL_MASK:
+ case POSIX_ACL_OTHER:
+ ace->uid = POSIX_ACL_UNDEFINED_ID;
+ break;
+ default:
+ return (-EINVAL);
+ }
+
+
+ xentry++;
+ ace++;
+ }
+
+ /* SUCCESS: ACL count */
+ return aclcount;
+}