xref: /openbmc/linux/fs/9p/acl.c (revision 7a4566b0b8fa67c7cd7be9f2969a085920356abb)
1 /*
2  * Copyright IBM Corporation, 2010
3  * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2.1 of the GNU Lesser General Public License
7  * as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12  *
13  */
14 
15 #include <linux/module.h>
16 #include <linux/fs.h>
17 #include <net/9p/9p.h>
18 #include <net/9p/client.h>
19 #include <linux/slab.h>
20 #include <linux/posix_acl_xattr.h>
21 #include "xattr.h"
22 #include "acl.h"
23 
24 static struct posix_acl *__v9fs_get_acl(struct p9_fid *fid, char *name)
25 {
26 	ssize_t size;
27 	void *value = NULL;
28 	struct posix_acl *acl = NULL;;
29 
30 	size = v9fs_fid_xattr_get(fid, name, NULL, 0);
31 	if (size > 0) {
32 		value = kzalloc(size, GFP_NOFS);
33 		if (!value)
34 			return ERR_PTR(-ENOMEM);
35 		size = v9fs_fid_xattr_get(fid, name, value, size);
36 		if (size > 0) {
37 			acl = posix_acl_from_xattr(value, size);
38 			if (IS_ERR(acl))
39 				goto err_out;
40 		}
41 	} else if (size == -ENODATA || size == 0 ||
42 		   size == -ENOSYS || size == -EOPNOTSUPP) {
43 		acl = NULL;
44 	} else
45 		acl = ERR_PTR(-EIO);
46 
47 err_out:
48 	kfree(value);
49 	return acl;
50 }
51 
52 int v9fs_get_acl(struct inode *inode, struct p9_fid *fid)
53 {
54 	int retval = 0;
55 	struct posix_acl *pacl, *dacl;
56 
57 	/* get the default/access acl values and cache them */
58 	dacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_DEFAULT);
59 	pacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_ACCESS);
60 
61 	if (!IS_ERR(dacl) && !IS_ERR(pacl)) {
62 		set_cached_acl(inode, ACL_TYPE_DEFAULT, dacl);
63 		set_cached_acl(inode, ACL_TYPE_ACCESS, pacl);
64 		posix_acl_release(dacl);
65 		posix_acl_release(pacl);
66 	} else
67 		retval = -EIO;
68 
69 	return retval;
70 }
71 
72 static struct posix_acl *v9fs_get_cached_acl(struct inode *inode, int type)
73 {
74 	struct posix_acl *acl;
75 	/*
76 	 * 9p Always cache the acl value when
77 	 * instantiating the inode (v9fs_inode_from_fid)
78 	 */
79 	acl = get_cached_acl(inode, type);
80 	BUG_ON(acl == ACL_NOT_CACHED);
81 	return acl;
82 }
83 
84 int v9fs_check_acl(struct inode *inode, int mask)
85 {
86 	struct posix_acl *acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS);
87 
88 	if (IS_ERR(acl))
89 		return PTR_ERR(acl);
90 	if (acl) {
91 		int error = posix_acl_permission(inode, acl, mask);
92 		posix_acl_release(acl);
93 		return error;
94 	}
95 	return -EAGAIN;
96 }
97 
98 static int v9fs_xattr_get_acl(struct dentry *dentry, const char *name,
99 			      void *buffer, size_t size, int type)
100 {
101 	struct posix_acl *acl;
102 	int error;
103 
104 	if (strcmp(name, "") != 0)
105 		return -EINVAL;
106 
107 	acl = v9fs_get_cached_acl(dentry->d_inode, type);
108 	if (IS_ERR(acl))
109 		return PTR_ERR(acl);
110 	if (acl == NULL)
111 		return -ENODATA;
112 	error = posix_acl_to_xattr(acl, buffer, size);
113 	posix_acl_release(acl);
114 
115 	return error;
116 }
117 
118 static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name,
119 			      const void *value, size_t size,
120 			      int flags, int type)
121 {
122 	return 0;
123 }
124 
125 const struct xattr_handler v9fs_xattr_acl_access_handler = {
126 	.prefix	= POSIX_ACL_XATTR_ACCESS,
127 	.flags	= ACL_TYPE_ACCESS,
128 	.get	= v9fs_xattr_get_acl,
129 	.set	= v9fs_xattr_set_acl,
130 };
131 
132 const struct xattr_handler v9fs_xattr_acl_default_handler = {
133 	.prefix	= POSIX_ACL_XATTR_DEFAULT,
134 	.flags	= ACL_TYPE_DEFAULT,
135 	.get	= v9fs_xattr_get_acl,
136 	.set	= v9fs_xattr_set_acl,
137 };
138