• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 Christoph Hellwig.
3  * Portions Copyright (C) 2000-2008 Silicon Graphics, Inc.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write the Free Software Foundation,
16  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18 
19 #include "xfs.h"
20 #include "xfs_da_btree.h"
21 #include "xfs_bmap_btree.h"
22 #include "xfs_inode.h"
23 #include "xfs_attr.h"
24 #include "xfs_attr_leaf.h"
25 #include "xfs_acl.h"
26 #include "xfs_vnodeops.h"
27 
28 #include <linux/posix_acl_xattr.h>
29 #include <linux/xattr.h>
30 
31 
32 /*
33  * ACL handling.  Should eventually be moved into xfs_acl.c
34  */
35 
36 static int
xfs_decode_acl(const char * name)37 xfs_decode_acl(const char *name)
38 {
39 	if (strcmp(name, "posix_acl_access") == 0)
40 		return _ACL_TYPE_ACCESS;
41 	else if (strcmp(name, "posix_acl_default") == 0)
42 		return _ACL_TYPE_DEFAULT;
43 	return -EINVAL;
44 }
45 
46 /*
47  * Get system extended attributes which at the moment only
48  * includes Posix ACLs.
49  */
50 static int
xfs_xattr_system_get(struct inode * inode,const char * name,void * buffer,size_t size)51 xfs_xattr_system_get(struct inode *inode, const char *name,
52 		void *buffer, size_t size)
53 {
54 	int acl;
55 
56 	acl = xfs_decode_acl(name);
57 	if (acl < 0)
58 		return acl;
59 
60 	return xfs_acl_vget(inode, buffer, size, acl);
61 }
62 
63 static int
xfs_xattr_system_set(struct inode * inode,const char * name,const void * value,size_t size,int flags)64 xfs_xattr_system_set(struct inode *inode, const char *name,
65 		const void *value, size_t size, int flags)
66 {
67 	int acl;
68 
69 	acl = xfs_decode_acl(name);
70 	if (acl < 0)
71 		return acl;
72 	if (flags & XATTR_CREATE)
73 		return -EINVAL;
74 
75 	if (!value)
76 		return xfs_acl_vremove(inode, acl);
77 
78 	return xfs_acl_vset(inode, (void *)value, size, acl);
79 }
80 
81 static struct xattr_handler xfs_xattr_system_handler = {
82 	.prefix	= XATTR_SYSTEM_PREFIX,
83 	.get	= xfs_xattr_system_get,
84 	.set	= xfs_xattr_system_set,
85 };
86 
87 
88 /*
89  * Real xattr handling.  The only difference between the namespaces is
90  * a flag passed to the low-level attr code.
91  */
92 
93 static int
__xfs_xattr_get(struct inode * inode,const char * name,void * value,size_t size,int xflags)94 __xfs_xattr_get(struct inode *inode, const char *name,
95 		void *value, size_t size, int xflags)
96 {
97 	struct xfs_inode *ip = XFS_I(inode);
98 	int error, asize = size;
99 
100 	if (strcmp(name, "") == 0)
101 		return -EINVAL;
102 
103 	/* Convert Linux syscall to XFS internal ATTR flags */
104 	if (!size) {
105 		xflags |= ATTR_KERNOVAL;
106 		value = NULL;
107 	}
108 
109 	error = -xfs_attr_get(ip, name, value, &asize, xflags);
110 	if (error)
111 		return error;
112 	return asize;
113 }
114 
115 static int
__xfs_xattr_set(struct inode * inode,const char * name,const void * value,size_t size,int flags,int xflags)116 __xfs_xattr_set(struct inode *inode, const char *name, const void *value,
117 		size_t size, int flags, int xflags)
118 {
119 	struct xfs_inode *ip = XFS_I(inode);
120 
121 	if (strcmp(name, "") == 0)
122 		return -EINVAL;
123 
124 	/* Convert Linux syscall to XFS internal ATTR flags */
125 	if (flags & XATTR_CREATE)
126 		xflags |= ATTR_CREATE;
127 	if (flags & XATTR_REPLACE)
128 		xflags |= ATTR_REPLACE;
129 
130 	if (!value)
131 		return -xfs_attr_remove(ip, name, xflags);
132 	return -xfs_attr_set(ip, name, (void *)value, size, xflags);
133 }
134 
135 static int
xfs_xattr_user_get(struct inode * inode,const char * name,void * value,size_t size)136 xfs_xattr_user_get(struct inode *inode, const char *name,
137 		void *value, size_t size)
138 {
139 	return __xfs_xattr_get(inode, name, value, size, 0);
140 }
141 
142 static int
xfs_xattr_user_set(struct inode * inode,const char * name,const void * value,size_t size,int flags)143 xfs_xattr_user_set(struct inode *inode, const char *name,
144 		const void *value, size_t size, int flags)
145 {
146 	return __xfs_xattr_set(inode, name, value, size, flags, 0);
147 }
148 
149 static struct xattr_handler xfs_xattr_user_handler = {
150 	.prefix	= XATTR_USER_PREFIX,
151 	.get	= xfs_xattr_user_get,
152 	.set	= xfs_xattr_user_set,
153 };
154 
155 
156 static int
xfs_xattr_trusted_get(struct inode * inode,const char * name,void * value,size_t size)157 xfs_xattr_trusted_get(struct inode *inode, const char *name,
158 		void *value, size_t size)
159 {
160 	return __xfs_xattr_get(inode, name, value, size, ATTR_ROOT);
161 }
162 
163 static int
xfs_xattr_trusted_set(struct inode * inode,const char * name,const void * value,size_t size,int flags)164 xfs_xattr_trusted_set(struct inode *inode, const char *name,
165 		const void *value, size_t size, int flags)
166 {
167 	return __xfs_xattr_set(inode, name, value, size, flags, ATTR_ROOT);
168 }
169 
170 static struct xattr_handler xfs_xattr_trusted_handler = {
171 	.prefix	= XATTR_TRUSTED_PREFIX,
172 	.get	= xfs_xattr_trusted_get,
173 	.set	= xfs_xattr_trusted_set,
174 };
175 
176 
177 static int
xfs_xattr_secure_get(struct inode * inode,const char * name,void * value,size_t size)178 xfs_xattr_secure_get(struct inode *inode, const char *name,
179 		void *value, size_t size)
180 {
181 	return __xfs_xattr_get(inode, name, value, size, ATTR_SECURE);
182 }
183 
184 static int
xfs_xattr_secure_set(struct inode * inode,const char * name,const void * value,size_t size,int flags)185 xfs_xattr_secure_set(struct inode *inode, const char *name,
186 		const void *value, size_t size, int flags)
187 {
188 	return __xfs_xattr_set(inode, name, value, size, flags, ATTR_SECURE);
189 }
190 
191 static struct xattr_handler xfs_xattr_security_handler = {
192 	.prefix	= XATTR_SECURITY_PREFIX,
193 	.get	= xfs_xattr_secure_get,
194 	.set	= xfs_xattr_secure_set,
195 };
196 
197 
198 struct xattr_handler *xfs_xattr_handlers[] = {
199 	&xfs_xattr_user_handler,
200 	&xfs_xattr_trusted_handler,
201 	&xfs_xattr_security_handler,
202 	&xfs_xattr_system_handler,
203 	NULL
204 };
205 
xfs_xattr_prefix_len(int flags)206 static unsigned int xfs_xattr_prefix_len(int flags)
207 {
208 	if (flags & XFS_ATTR_SECURE)
209 		return sizeof("security");
210 	else if (flags & XFS_ATTR_ROOT)
211 		return sizeof("trusted");
212 	else
213 		return sizeof("user");
214 }
215 
xfs_xattr_prefix(int flags)216 static const char *xfs_xattr_prefix(int flags)
217 {
218 	if (flags & XFS_ATTR_SECURE)
219 		return xfs_xattr_security_handler.prefix;
220 	else if (flags & XFS_ATTR_ROOT)
221 		return xfs_xattr_trusted_handler.prefix;
222 	else
223 		return xfs_xattr_user_handler.prefix;
224 }
225 
226 static int
xfs_xattr_put_listent(struct xfs_attr_list_context * context,int flags,char * name,int namelen,int valuelen,char * value)227 xfs_xattr_put_listent(struct xfs_attr_list_context *context, int flags,
228 		char *name, int namelen, int valuelen, char *value)
229 {
230 	unsigned int prefix_len = xfs_xattr_prefix_len(flags);
231 	char *offset;
232 	int arraytop;
233 
234 	ASSERT(context->count >= 0);
235 
236 	/*
237 	 * Only show root namespace entries if we are actually allowed to
238 	 * see them.
239 	 */
240 	if ((flags & XFS_ATTR_ROOT) && !capable(CAP_SYS_ADMIN))
241 		return 0;
242 
243 	arraytop = context->count + prefix_len + namelen + 1;
244 	if (arraytop > context->firstu) {
245 		context->count = -1;	/* insufficient space */
246 		return 1;
247 	}
248 	offset = (char *)context->alist + context->count;
249 	strncpy(offset, xfs_xattr_prefix(flags), prefix_len);
250 	offset += prefix_len;
251 	strncpy(offset, name, namelen);			/* real name */
252 	offset += namelen;
253 	*offset = '\0';
254 	context->count += prefix_len + namelen + 1;
255 	return 0;
256 }
257 
258 static int
xfs_xattr_put_listent_sizes(struct xfs_attr_list_context * context,int flags,char * name,int namelen,int valuelen,char * value)259 xfs_xattr_put_listent_sizes(struct xfs_attr_list_context *context, int flags,
260 		char *name, int namelen, int valuelen, char *value)
261 {
262 	context->count += xfs_xattr_prefix_len(flags) + namelen + 1;
263 	return 0;
264 }
265 
266 static int
list_one_attr(const char * name,const size_t len,void * data,size_t size,ssize_t * result)267 list_one_attr(const char *name, const size_t len, void *data,
268 		size_t size, ssize_t *result)
269 {
270 	char *p = data + *result;
271 
272 	*result += len;
273 	if (!size)
274 		return 0;
275 	if (*result > size)
276 		return -ERANGE;
277 
278 	strcpy(p, name);
279 	return 0;
280 }
281 
282 ssize_t
xfs_vn_listxattr(struct dentry * dentry,char * data,size_t size)283 xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size)
284 {
285 	struct xfs_attr_list_context context;
286 	struct attrlist_cursor_kern cursor = { 0 };
287 	struct inode		*inode = dentry->d_inode;
288 	int			error;
289 
290 	/*
291 	 * First read the regular on-disk attributes.
292 	 */
293 	memset(&context, 0, sizeof(context));
294 	context.dp = XFS_I(inode);
295 	context.cursor = &cursor;
296 	context.resynch = 1;
297 	context.alist = data;
298 	context.bufsize = size;
299 	context.firstu = context.bufsize;
300 
301 	if (size)
302 		context.put_listent = xfs_xattr_put_listent;
303 	else
304 		context.put_listent = xfs_xattr_put_listent_sizes;
305 
306 	xfs_attr_list_int(&context);
307 	if (context.count < 0)
308 		return -ERANGE;
309 
310 	/*
311 	 * Then add the two synthetic ACL attributes.
312 	 */
313 	if (xfs_acl_vhasacl_access(inode)) {
314 		error = list_one_attr(POSIX_ACL_XATTR_ACCESS,
315 				strlen(POSIX_ACL_XATTR_ACCESS) + 1,
316 				data, size, &context.count);
317 		if (error)
318 			return error;
319 	}
320 
321 	if (xfs_acl_vhasacl_default(inode)) {
322 		error = list_one_attr(POSIX_ACL_XATTR_DEFAULT,
323 				strlen(POSIX_ACL_XATTR_DEFAULT) + 1,
324 				data, size, &context.count);
325 		if (error)
326 			return error;
327 	}
328 
329 	return context.count;
330 }
331