fs/9p: Add access = client option to opt in acl evaluation.
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Mon, 27 Sep 2010 18:57:41 +0000 (00:27 +0530)
committerEric Van Hensbergen <ericvh@gmail.com>
Thu, 28 Oct 2010 14:08:46 +0000 (09:08 -0500)
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Venkateswararao Jujjuri <jvrao@linux.vnet.ibm.com>
Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
Documentation/filesystems/9p.txt
fs/9p/acl.c
fs/9p/fid.c
fs/9p/v9fs.c
fs/9p/v9fs.h
fs/9p/vfs_super.c

index f9765e8..b22abba 100644 (file)
@@ -111,7 +111,7 @@ OPTIONS
                This can be used to share devices/named pipes/sockets between
                hosts.  This functionality will be expanded in later versions.
 
-  access       there are three access modes.
+  access       there are four access modes.
                        user  = if a user tries to access a file on v9fs
                                filesystem for the first time, v9fs sends an
                                attach command (Tattach) for that user.
@@ -120,6 +120,8 @@ OPTIONS
                                the files on the mounted filesystem
                        any   = v9fs does single attach and performs all
                                operations as one user
+                       client = ACL based access check on the 9p client
+                                side for access validation
 
   cachetag     cache tag to use the specified persistent cache.
                cache tags for existing cache sessions can be listed at
index 8b3c54a..12d6023 100644 (file)
@@ -22,6 +22,7 @@
 #include "xattr.h"
 #include "acl.h"
 #include "v9fs_vfs.h"
+#include "v9fs.h"
 
 static struct posix_acl *__v9fs_get_acl(struct p9_fid *fid, char *name)
 {
@@ -55,7 +56,14 @@ int v9fs_get_acl(struct inode *inode, struct p9_fid *fid)
 {
        int retval = 0;
        struct posix_acl *pacl, *dacl;
+       struct v9fs_session_info *v9ses;
 
+       v9ses = v9fs_inode2v9ses(inode);
+       if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) {
+               set_cached_acl(inode, ACL_TYPE_DEFAULT, NULL);
+               set_cached_acl(inode, ACL_TYPE_ACCESS, NULL);
+               return 0;
+       }
        /* get the default/access acl values and cache them */
        dacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_DEFAULT);
        pacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_ACCESS);
@@ -85,7 +93,18 @@ static struct posix_acl *v9fs_get_cached_acl(struct inode *inode, int type)
 
 int v9fs_check_acl(struct inode *inode, int mask)
 {
-       struct posix_acl *acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS);
+       struct posix_acl *acl;
+       struct v9fs_session_info *v9ses;
+
+       v9ses = v9fs_inode2v9ses(inode);
+       if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) {
+               /*
+                * On access = client mode get the acl
+                * values from the server
+                */
+               return 0;
+       }
+       acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS);
 
        if (IS_ERR(acl))
                return PTR_ERR(acl);
@@ -204,15 +223,41 @@ cleanup:
 
 }
 
+static int v9fs_remote_get_acl(struct dentry *dentry, const char *name,
+                              void *buffer, size_t size, int type)
+{
+       char *full_name;
+
+       switch (type) {
+       case ACL_TYPE_ACCESS:
+               full_name =  POSIX_ACL_XATTR_ACCESS;
+               break;
+       case ACL_TYPE_DEFAULT:
+               full_name = POSIX_ACL_XATTR_DEFAULT;
+               break;
+       default:
+               BUG();
+       }
+       return v9fs_xattr_get(dentry, full_name, buffer, size);
+}
+
 static int v9fs_xattr_get_acl(struct dentry *dentry, const char *name,
                              void *buffer, size_t size, int type)
 {
+       struct v9fs_session_info *v9ses;
        struct posix_acl *acl;
        int error;
 
        if (strcmp(name, "") != 0)
                return -EINVAL;
 
+       v9ses = v9fs_inode2v9ses(dentry->d_inode);
+       /*
+        * We allow set/get/list of acl when access=client is not specified
+        */
+       if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT)
+               return v9fs_remote_get_acl(dentry, name, buffer, size, type);
+
        acl = v9fs_get_cached_acl(dentry->d_inode, type);
        if (IS_ERR(acl))
                return PTR_ERR(acl);
@@ -224,16 +269,47 @@ static int v9fs_xattr_get_acl(struct dentry *dentry, const char *name,
        return error;
 }
 
+static int v9fs_remote_set_acl(struct dentry *dentry, const char *name,
+                             const void *value, size_t size,
+                             int flags, int type)
+{
+       char *full_name;
+
+       switch (type) {
+       case ACL_TYPE_ACCESS:
+               full_name =  POSIX_ACL_XATTR_ACCESS;
+               break;
+       case ACL_TYPE_DEFAULT:
+               full_name = POSIX_ACL_XATTR_DEFAULT;
+               break;
+       default:
+               BUG();
+       }
+       return v9fs_xattr_set(dentry, full_name, value, size, flags);
+}
+
+
 static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name,
                              const void *value, size_t size,
                              int flags, int type)
 {
        int retval;
        struct posix_acl *acl;
+       struct v9fs_session_info *v9ses;
        struct inode *inode = dentry->d_inode;
 
        if (strcmp(name, "") != 0)
                return -EINVAL;
+
+       v9ses = v9fs_inode2v9ses(dentry->d_inode);
+       /*
+        * set the attribute on the remote. Without even looking at the
+        * xattr value. We leave it to the server to validate
+        */
+       if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT)
+               return v9fs_remote_set_acl(dentry, name,
+                                          value, size, flags, type);
+
        if (S_ISLNK(inode->i_mode))
                return -EOPNOTSUPP;
        if (!is_owner_or_cap(inode))
index 6406f89..b00223c 100644 (file)
@@ -149,6 +149,7 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
        switch (access) {
        case V9FS_ACCESS_SINGLE:
        case V9FS_ACCESS_USER:
+       case V9FS_ACCESS_CLIENT:
                uid = current_fsuid();
                any = 0;
                break;
index 38dc0e0..2f77cd3 100644 (file)
@@ -193,7 +193,17 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
                                v9ses->flags |= V9FS_ACCESS_USER;
                        else if (strcmp(s, "any") == 0)
                                v9ses->flags |= V9FS_ACCESS_ANY;
-                       else {
+                       else if (strcmp(s, "client") == 0) {
+#ifdef CONFIG_9P_FS_POSIX_ACL
+                               v9ses->flags |= V9FS_ACCESS_CLIENT;
+#else
+                               P9_DPRINTK(P9_DEBUG_ERROR,
+                                       "access=client option not supported\n");
+                               kfree(s);
+                               ret = -EINVAL;
+                               goto free_and_return;
+#endif
+                       } else {
                                v9ses->flags |= V9FS_ACCESS_SINGLE;
                                v9ses->uid = simple_strtoul(s, &e, 10);
                                if (*e != '\0')
@@ -278,6 +288,16 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
 
        v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ;
 
+       if (!v9fs_proto_dotl(v9ses) &&
+           ((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_CLIENT)) {
+               /*
+                * We support ACCESS_CLIENT only for dotl.
+                * Fall back to ACCESS_USER
+                */
+               v9ses->flags &= ~V9FS_ACCESS_MASK;
+               v9ses->flags |= V9FS_ACCESS_USER;
+       }
+       /*FIXME !! */
        /* for legacy mode, fall back to V9FS_ACCESS_ANY */
        if (!(v9fs_proto_dotu(v9ses) || v9fs_proto_dotl(v9ses)) &&
                ((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) {
index 4c963c9..8bb7792 100644 (file)
  *
  * Session flags reflect options selected by users at mount time
  */
+#define        V9FS_ACCESS_ANY (V9FS_ACCESS_SINGLE | \
+                        V9FS_ACCESS_USER |   \
+                        V9FS_ACCESS_CLIENT)
+#define V9FS_ACCESS_MASK V9FS_ACCESS_ANY
+
 enum p9_session_flags {
        V9FS_PROTO_2000U        = 0x01,
        V9FS_PROTO_2000L        = 0x02,
        V9FS_ACCESS_SINGLE      = 0x04,
        V9FS_ACCESS_USER        = 0x08,
-       V9FS_ACCESS_ANY         = 0x0C,
-       V9FS_ACCESS_MASK        = 0x0C,
+       V9FS_ACCESS_CLIENT      = 0x10
 };
 
 /* possible values of ->cache */
index 14da577..174643f 100644 (file)
@@ -90,7 +90,8 @@ v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses,
            MS_NOATIME;
 
 #ifdef CONFIG_9P_FS_POSIX_ACL
-       sb->s_flags |= MS_POSIXACL;
+       if ((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_CLIENT)
+               sb->s_flags |= MS_POSIXACL;
 #endif
 
        save_mount_options(sb, data);
@@ -181,7 +182,6 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
        retval = v9fs_get_acl(inode, fid);
        if (retval)
                goto release_sb;
-
        v9fs_fid_add(root, fid);
 
        P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n");