diff options
-rw-r--r-- | Documentation/filesystems/9p.txt | 4 | ||||
-rw-r--r-- | fs/9p/acl.c | 78 | ||||
-rw-r--r-- | fs/9p/fid.c | 1 | ||||
-rw-r--r-- | fs/9p/v9fs.c | 22 | ||||
-rw-r--r-- | fs/9p/v9fs.h | 8 | ||||
-rw-r--r-- | fs/9p/vfs_super.c | 4 |
6 files changed, 110 insertions, 7 deletions
diff --git a/Documentation/filesystems/9p.txt b/Documentation/filesystems/9p.txt index f9765e8cf08..b22abba78fe 100644 --- a/Documentation/filesystems/9p.txt +++ b/Documentation/filesystems/9p.txt @@ -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 diff --git a/fs/9p/acl.c b/fs/9p/acl.c index 8b3c54a4958..12d602351db 100644 --- a/fs/9p/acl.c +++ b/fs/9p/acl.c @@ -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)) diff --git a/fs/9p/fid.c b/fs/9p/fid.c index 6406f896bf9..b00223c99d7 100644 --- a/fs/9p/fid.c +++ b/fs/9p/fid.c @@ -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; diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 38dc0e06759..2f77cd33ba8 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -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)) { diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h index 4c963c9fc41..8bb7792afe2 100644 --- a/fs/9p/v9fs.h +++ b/fs/9p/v9fs.h @@ -33,13 +33,17 @@ * * 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 */ diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index 14da5778d44..174643f4f90 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c @@ -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"); |