• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/fs/xfs/linux-2.6/
1/*
2 * Copyright (c) 2008, Christoph Hellwig
3 * All Rights Reserved.
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#include "xfs.h"
19#include "xfs_acl.h"
20#include "xfs_attr.h"
21#include "xfs_bmap_btree.h"
22#include "xfs_inode.h"
23#include "xfs_vnodeops.h"
24#include "xfs_trace.h"
25#include <linux/slab.h>
26#include <linux/xattr.h>
27#include <linux/posix_acl_xattr.h>
28
29
30/*
31 * Locking scheme:
32 *  - all ACL updates are protected by inode->i_mutex, which is taken before
33 *    calling into this file.
34 */
35
36STATIC struct posix_acl *
37xfs_acl_from_disk(struct xfs_acl *aclp)
38{
39	struct posix_acl_entry *acl_e;
40	struct posix_acl *acl;
41	struct xfs_acl_entry *ace;
42	int count, i;
43
44	count = be32_to_cpu(aclp->acl_cnt);
45
46	acl = posix_acl_alloc(count, GFP_KERNEL);
47	if (!acl)
48		return ERR_PTR(-ENOMEM);
49
50	for (i = 0; i < count; i++) {
51		acl_e = &acl->a_entries[i];
52		ace = &aclp->acl_entry[i];
53
54		/*
55		 * The tag is 32 bits on disk and 16 bits in core.
56		 *
57		 * Because every access to it goes through the core
58		 * format first this is not a problem.
59		 */
60		acl_e->e_tag = be32_to_cpu(ace->ae_tag);
61		acl_e->e_perm = be16_to_cpu(ace->ae_perm);
62
63		switch (acl_e->e_tag) {
64		case ACL_USER:
65		case ACL_GROUP:
66			acl_e->e_id = be32_to_cpu(ace->ae_id);
67			break;
68		case ACL_USER_OBJ:
69		case ACL_GROUP_OBJ:
70		case ACL_MASK:
71		case ACL_OTHER:
72			acl_e->e_id = ACL_UNDEFINED_ID;
73			break;
74		default:
75			goto fail;
76		}
77	}
78	return acl;
79
80fail:
81	posix_acl_release(acl);
82	return ERR_PTR(-EINVAL);
83}
84
85STATIC void
86xfs_acl_to_disk(struct xfs_acl *aclp, const struct posix_acl *acl)
87{
88	const struct posix_acl_entry *acl_e;
89	struct xfs_acl_entry *ace;
90	int i;
91
92	aclp->acl_cnt = cpu_to_be32(acl->a_count);
93	for (i = 0; i < acl->a_count; i++) {
94		ace = &aclp->acl_entry[i];
95		acl_e = &acl->a_entries[i];
96
97		ace->ae_tag = cpu_to_be32(acl_e->e_tag);
98		ace->ae_id = cpu_to_be32(acl_e->e_id);
99		ace->ae_perm = cpu_to_be16(acl_e->e_perm);
100	}
101}
102
103struct posix_acl *
104xfs_get_acl(struct inode *inode, int type)
105{
106	struct xfs_inode *ip = XFS_I(inode);
107	struct posix_acl *acl;
108	struct xfs_acl *xfs_acl;
109	int len = sizeof(struct xfs_acl);
110	unsigned char *ea_name;
111	int error;
112
113	acl = get_cached_acl(inode, type);
114	if (acl != ACL_NOT_CACHED)
115		return acl;
116
117	switch (type) {
118	case ACL_TYPE_ACCESS:
119		ea_name = SGI_ACL_FILE;
120		break;
121	case ACL_TYPE_DEFAULT:
122		ea_name = SGI_ACL_DEFAULT;
123		break;
124	default:
125		BUG();
126	}
127
128	/*
129	 * If we have a cached ACLs value just return it, not need to
130	 * go out to the disk.
131	 */
132
133	xfs_acl = kzalloc(sizeof(struct xfs_acl), GFP_KERNEL);
134	if (!xfs_acl)
135		return ERR_PTR(-ENOMEM);
136
137	error = -xfs_attr_get(ip, ea_name, (unsigned char *)xfs_acl,
138							&len, ATTR_ROOT);
139	if (error) {
140		/*
141		 * If the attribute doesn't exist make sure we have a negative
142		 * cache entry, for any other error assume it is transient and
143		 * leave the cache entry as ACL_NOT_CACHED.
144		 */
145		if (error == -ENOATTR) {
146			acl = NULL;
147			goto out_update_cache;
148		}
149		goto out;
150	}
151
152	acl = xfs_acl_from_disk(xfs_acl);
153	if (IS_ERR(acl))
154		goto out;
155
156 out_update_cache:
157	set_cached_acl(inode, type, acl);
158 out:
159	kfree(xfs_acl);
160	return acl;
161}
162
163STATIC int
164xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
165{
166	struct xfs_inode *ip = XFS_I(inode);
167	unsigned char *ea_name;
168	int error;
169
170	if (S_ISLNK(inode->i_mode))
171		return -EOPNOTSUPP;
172
173	switch (type) {
174	case ACL_TYPE_ACCESS:
175		ea_name = SGI_ACL_FILE;
176		break;
177	case ACL_TYPE_DEFAULT:
178		if (!S_ISDIR(inode->i_mode))
179			return acl ? -EACCES : 0;
180		ea_name = SGI_ACL_DEFAULT;
181		break;
182	default:
183		return -EINVAL;
184	}
185
186	if (acl) {
187		struct xfs_acl *xfs_acl;
188		int len;
189
190		xfs_acl = kzalloc(sizeof(struct xfs_acl), GFP_KERNEL);
191		if (!xfs_acl)
192			return -ENOMEM;
193
194		xfs_acl_to_disk(xfs_acl, acl);
195		len = sizeof(struct xfs_acl) -
196			(sizeof(struct xfs_acl_entry) *
197			 (XFS_ACL_MAX_ENTRIES - acl->a_count));
198
199		error = -xfs_attr_set(ip, ea_name, (unsigned char *)xfs_acl,
200				len, ATTR_ROOT);
201
202		kfree(xfs_acl);
203	} else {
204		/*
205		 * A NULL ACL argument means we want to remove the ACL.
206		 */
207		error = -xfs_attr_remove(ip, ea_name, ATTR_ROOT);
208
209		/*
210		 * If the attribute didn't exist to start with that's fine.
211		 */
212		if (error == -ENOATTR)
213			error = 0;
214	}
215
216	if (!error)
217		set_cached_acl(inode, type, acl);
218	return error;
219}
220
221int
222xfs_check_acl(struct inode *inode, int mask)
223{
224	struct xfs_inode *ip = XFS_I(inode);
225	struct posix_acl *acl;
226	int error = -EAGAIN;
227
228	trace_xfs_check_acl(ip);
229
230	/*
231	 * If there is no attribute fork no ACL exists on this inode and
232	 * we can skip the whole exercise.
233	 */
234	if (!XFS_IFORK_Q(ip))
235		return -EAGAIN;
236
237	acl = xfs_get_acl(inode, ACL_TYPE_ACCESS);
238	if (IS_ERR(acl))
239		return PTR_ERR(acl);
240	if (acl) {
241		error = posix_acl_permission(inode, acl, mask);
242		posix_acl_release(acl);
243	}
244
245	return error;
246}
247
248static int
249xfs_set_mode(struct inode *inode, mode_t mode)
250{
251	int error = 0;
252
253	if (mode != inode->i_mode) {
254		struct iattr iattr;
255
256		iattr.ia_valid = ATTR_MODE | ATTR_CTIME;
257		iattr.ia_mode = mode;
258		iattr.ia_ctime = current_fs_time(inode->i_sb);
259
260		error = -xfs_setattr(XFS_I(inode), &iattr, XFS_ATTR_NOACL);
261	}
262
263	return error;
264}
265
266static int
267xfs_acl_exists(struct inode *inode, unsigned char *name)
268{
269	int len = sizeof(struct xfs_acl);
270
271	return (xfs_attr_get(XFS_I(inode), name, NULL, &len,
272			    ATTR_ROOT|ATTR_KERNOVAL) == 0);
273}
274
275int
276posix_acl_access_exists(struct inode *inode)
277{
278	return xfs_acl_exists(inode, SGI_ACL_FILE);
279}
280
281int
282posix_acl_default_exists(struct inode *inode)
283{
284	if (!S_ISDIR(inode->i_mode))
285		return 0;
286	return xfs_acl_exists(inode, SGI_ACL_DEFAULT);
287}
288
289/*
290 * No need for i_mutex because the inode is not yet exposed to the VFS.
291 */
292int
293xfs_inherit_acl(struct inode *inode, struct posix_acl *default_acl)
294{
295	struct posix_acl *clone;
296	mode_t mode;
297	int error = 0, inherit = 0;
298
299	if (S_ISDIR(inode->i_mode)) {
300		error = xfs_set_acl(inode, ACL_TYPE_DEFAULT, default_acl);
301		if (error)
302			return error;
303	}
304
305	clone = posix_acl_clone(default_acl, GFP_KERNEL);
306	if (!clone)
307		return -ENOMEM;
308
309	mode = inode->i_mode;
310	error = posix_acl_create_masq(clone, &mode);
311	if (error < 0)
312		goto out_release_clone;
313
314	/*
315	 * If posix_acl_create_masq returns a positive value we need to
316	 * inherit a permission that can't be represented using the Unix
317	 * mode bits and we actually need to set an ACL.
318	 */
319	if (error > 0)
320		inherit = 1;
321
322	error = xfs_set_mode(inode, mode);
323	if (error)
324		goto out_release_clone;
325
326	if (inherit)
327		error = xfs_set_acl(inode, ACL_TYPE_ACCESS, clone);
328
329 out_release_clone:
330	posix_acl_release(clone);
331	return error;
332}
333
334int
335xfs_acl_chmod(struct inode *inode)
336{
337	struct posix_acl *acl, *clone;
338	int error;
339
340	if (S_ISLNK(inode->i_mode))
341		return -EOPNOTSUPP;
342
343	acl = xfs_get_acl(inode, ACL_TYPE_ACCESS);
344	if (IS_ERR(acl) || !acl)
345		return PTR_ERR(acl);
346
347	clone = posix_acl_clone(acl, GFP_KERNEL);
348	posix_acl_release(acl);
349	if (!clone)
350		return -ENOMEM;
351
352	error = posix_acl_chmod_masq(clone, inode->i_mode);
353	if (!error)
354		error = xfs_set_acl(inode, ACL_TYPE_ACCESS, clone);
355
356	posix_acl_release(clone);
357	return error;
358}
359
360static int
361xfs_xattr_acl_get(struct dentry *dentry, const char *name,
362		void *value, size_t size, int type)
363{
364	struct posix_acl *acl;
365	int error;
366
367	acl = xfs_get_acl(dentry->d_inode, type);
368	if (IS_ERR(acl))
369		return PTR_ERR(acl);
370	if (acl == NULL)
371		return -ENODATA;
372
373	error = posix_acl_to_xattr(acl, value, size);
374	posix_acl_release(acl);
375
376	return error;
377}
378
379static int
380xfs_xattr_acl_set(struct dentry *dentry, const char *name,
381		const void *value, size_t size, int flags, int type)
382{
383	struct inode *inode = dentry->d_inode;
384	struct posix_acl *acl = NULL;
385	int error = 0;
386
387	if (flags & XATTR_CREATE)
388		return -EINVAL;
389	if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
390		return value ? -EACCES : 0;
391	if ((current_fsuid() != inode->i_uid) && !capable(CAP_FOWNER))
392		return -EPERM;
393
394	if (!value)
395		goto set_acl;
396
397	acl = posix_acl_from_xattr(value, size);
398	if (!acl) {
399		/*
400		 * acl_set_file(3) may request that we set default ACLs with
401		 * zero length -- defend (gracefully) against that here.
402		 */
403		goto out;
404	}
405	if (IS_ERR(acl)) {
406		error = PTR_ERR(acl);
407		goto out;
408	}
409
410	error = posix_acl_valid(acl);
411	if (error)
412		goto out_release;
413
414	error = -EINVAL;
415	if (acl->a_count > XFS_ACL_MAX_ENTRIES)
416		goto out_release;
417
418	if (type == ACL_TYPE_ACCESS) {
419		mode_t mode = inode->i_mode;
420		error = posix_acl_equiv_mode(acl, &mode);
421
422		if (error <= 0) {
423			posix_acl_release(acl);
424			acl = NULL;
425
426			if (error < 0)
427				return error;
428		}
429
430		error = xfs_set_mode(inode, mode);
431		if (error)
432			goto out_release;
433	}
434
435 set_acl:
436	error = xfs_set_acl(inode, type, acl);
437 out_release:
438	posix_acl_release(acl);
439 out:
440	return error;
441}
442
443const struct xattr_handler xfs_xattr_acl_access_handler = {
444	.prefix	= POSIX_ACL_XATTR_ACCESS,
445	.flags	= ACL_TYPE_ACCESS,
446	.get	= xfs_xattr_acl_get,
447	.set	= xfs_xattr_acl_set,
448};
449
450const struct xattr_handler xfs_xattr_acl_default_handler = {
451	.prefix	= POSIX_ACL_XATTR_DEFAULT,
452	.flags	= ACL_TYPE_DEFAULT,
453	.get	= xfs_xattr_acl_get,
454	.set	= xfs_xattr_acl_set,
455};
456