acl.c 6.4 KB
Newer Older
D
David Teigland 已提交
1 2
/*
 * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
3
 * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
D
David Teigland 已提交
4 5 6
 *
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
7
 * of the GNU General Public License version 2.
D
David Teigland 已提交
8 9 10 11 12 13 14
 */

#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/buffer_head.h>
S
Steven Whitehouse 已提交
15
#include <linux/xattr.h>
D
David Teigland 已提交
16 17
#include <linux/posix_acl.h>
#include <linux/posix_acl_xattr.h>
18
#include <linux/gfs2_ondisk.h>
D
David Teigland 已提交
19 20

#include "gfs2.h"
21
#include "incore.h"
D
David Teigland 已提交
22
#include "acl.h"
23
#include "xattr.h"
D
David Teigland 已提交
24 25 26 27
#include "glock.h"
#include "inode.h"
#include "meta_io.h"
#include "trans.h"
28
#include "util.h"
D
David Teigland 已提交
29

S
Steven Whitehouse 已提交
30
static const char *gfs2_acl_name(int type)
D
David Teigland 已提交
31
{
S
Steven Whitehouse 已提交
32 33 34 35 36 37 38 39
	switch (type) {
	case ACL_TYPE_ACCESS:
		return GFS2_POSIX_ACL_ACCESS;
	case ACL_TYPE_DEFAULT:
		return GFS2_POSIX_ACL_DEFAULT;
	}
	return NULL;
}
D
David Teigland 已提交
40

41
struct posix_acl *gfs2_get_acl(struct inode *inode, int type)
S
Steven Whitehouse 已提交
42
{
43
	struct gfs2_inode *ip = GFS2_I(inode);
S
Steven Whitehouse 已提交
44 45 46 47
	struct posix_acl *acl;
	const char *name;
	char *data;
	int len;
48

49
	if (!ip->i_eattr)
S
Steven Whitehouse 已提交
50
		return NULL;
D
David Teigland 已提交
51

S
Steven Whitehouse 已提交
52 53 54 55
	acl = get_cached_acl(&ip->i_inode, type);
	if (acl != ACL_NOT_CACHED)
		return acl;

S
Steven Whitehouse 已提交
56 57 58
	name = gfs2_acl_name(type);
	if (name == NULL)
		return ERR_PTR(-EINVAL);
D
David Teigland 已提交
59

S
Steven Whitehouse 已提交
60 61 62 63 64
	len = gfs2_xattr_acl_get(ip, name, &data);
	if (len < 0)
		return ERR_PTR(len);
	if (len == 0)
		return NULL;
D
David Teigland 已提交
65

S
Steven Whitehouse 已提交
66 67 68
	acl = posix_acl_from_xattr(data, len);
	kfree(data);
	return acl;
D
David Teigland 已提交
69 70
}

A
Al Viro 已提交
71
static int gfs2_set_mode(struct inode *inode, umode_t mode)
D
David Teigland 已提交
72
{
73
	int error = 0;
D
David Teigland 已提交
74

75 76
	if (mode != inode->i_mode) {
		struct iattr iattr;
D
David Teigland 已提交
77

78 79
		iattr.ia_valid = ATTR_MODE;
		iattr.ia_mode = mode;
D
David Teigland 已提交
80

S
Steven Whitehouse 已提交
81
		error = gfs2_setattr_simple(inode, &iattr);
82
	}
D
David Teigland 已提交
83

84
	return error;
D
David Teigland 已提交
85 86
}

S
Steven Whitehouse 已提交
87
static int gfs2_acl_set(struct inode *inode, int type, struct posix_acl *acl)
D
David Teigland 已提交
88 89
{
	int error;
S
Steven Whitehouse 已提交
90 91 92 93 94 95 96 97 98 99 100 101 102 103
	int len;
	char *data;
	const char *name = gfs2_acl_name(type);

	BUG_ON(name == NULL);
	len = posix_acl_to_xattr(acl, NULL, 0);
	if (len == 0)
		return 0;
	data = kmalloc(len, GFP_NOFS);
	if (data == NULL)
		return -ENOMEM;
	error = posix_acl_to_xattr(acl, data, len);
	if (error < 0)
		goto out;
104
	error = __gfs2_xattr_set(inode, name, data, len, 0, GFS2_EATYPE_SYS);
S
Steven Whitehouse 已提交
105 106
	if (!error)
		set_cached_acl(inode, type, acl);
S
Steven Whitehouse 已提交
107 108 109 110 111 112 113 114
out:
	kfree(data);
	return error;
}

int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode)
{
	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
115
	struct posix_acl *acl;
A
Al Viro 已提交
116
	umode_t mode = inode->i_mode;
S
Steven Whitehouse 已提交
117
	int error = 0;
D
David Teigland 已提交
118 119 120

	if (!sdp->sd_args.ar_posix_acl)
		return 0;
S
Steven Whitehouse 已提交
121
	if (S_ISLNK(inode->i_mode))
D
David Teigland 已提交
122 123
		return 0;

124
	acl = gfs2_get_acl(&dip->i_inode, ACL_TYPE_DEFAULT);
S
Steven Whitehouse 已提交
125 126
	if (IS_ERR(acl))
		return PTR_ERR(acl);
D
David Teigland 已提交
127
	if (!acl) {
A
Al Viro 已提交
128
		mode &= ~current_umask();
S
Steven Whitehouse 已提交
129 130
		if (mode != inode->i_mode)
			error = gfs2_set_mode(inode, mode);
D
David Teigland 已提交
131 132 133
		return error;
	}

S
Steven Whitehouse 已提交
134 135 136 137 138 139
	if (S_ISDIR(inode->i_mode)) {
		error = gfs2_acl_set(inode, ACL_TYPE_DEFAULT, acl);
		if (error)
			goto out;
	}

140
	error = posix_acl_create(&acl, GFP_NOFS, &mode);
D
David Teigland 已提交
141
	if (error < 0)
142 143
		return error;

144 145
	if (error == 0)
		goto munge;
D
David Teigland 已提交
146

S
Steven Whitehouse 已提交
147
	error = gfs2_acl_set(inode, ACL_TYPE_ACCESS, acl);
148 149 150
	if (error)
		goto out;
munge:
S
Steven Whitehouse 已提交
151
	error = gfs2_set_mode(inode, mode);
152
out:
D
David Teigland 已提交
153 154 155 156 157 158
	posix_acl_release(acl);
	return error;
}

int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
{
S
Steven Whitehouse 已提交
159
	struct inode *inode = &ip->i_inode;
160
	struct posix_acl *acl;
D
David Teigland 已提交
161 162 163 164
	char *data;
	unsigned int len;
	int error;

165
	acl = gfs2_get_acl(&ip->i_inode, ACL_TYPE_ACCESS);
S
Steven Whitehouse 已提交
166 167
	if (IS_ERR(acl))
		return PTR_ERR(acl);
D
David Teigland 已提交
168
	if (!acl)
S
Steven Whitehouse 已提交
169
		return gfs2_setattr_simple(inode, attr);
D
David Teigland 已提交
170

171 172 173 174 175 176
	error = posix_acl_chmod(&acl, GFP_NOFS, attr->ia_mode);
	if (error)
		return error;

	len = posix_acl_to_xattr(acl, NULL, 0);
	data = kmalloc(len, GFP_NOFS);
D
David Teigland 已提交
177
	error = -ENOMEM;
178
	if (data == NULL)
D
David Teigland 已提交
179
		goto out;
180 181 182 183
	posix_acl_to_xattr(acl, data, len);
	error = gfs2_xattr_acl_chmod(ip, attr, data);
	kfree(data);
	set_cached_acl(&ip->i_inode, ACL_TYPE_ACCESS, acl);
D
David Teigland 已提交
184

185
out:
D
David Teigland 已提交
186 187 188 189
	posix_acl_release(acl);
	return error;
}

S
Steven Whitehouse 已提交
190 191 192 193 194 195 196 197 198
static int gfs2_acl_type(const char *name)
{
	if (strcmp(name, GFS2_POSIX_ACL_ACCESS) == 0)
		return ACL_TYPE_ACCESS;
	if (strcmp(name, GFS2_POSIX_ACL_DEFAULT) == 0)
		return ACL_TYPE_DEFAULT;
	return -EINVAL;
}

199 200
static int gfs2_xattr_system_get(struct dentry *dentry, const char *name,
				 void *buffer, size_t size, int xtype)
S
Steven Whitehouse 已提交
201
{
202
	struct inode *inode = dentry->d_inode;
203
	struct gfs2_sbd *sdp = GFS2_SB(inode);
S
Steven Whitehouse 已提交
204
	struct posix_acl *acl;
S
Steven Whitehouse 已提交
205
	int type;
S
Steven Whitehouse 已提交
206
	int error;
S
Steven Whitehouse 已提交
207

208 209 210
	if (!sdp->sd_args.ar_posix_acl)
		return -EOPNOTSUPP;

S
Steven Whitehouse 已提交
211 212 213 214
	type = gfs2_acl_type(name);
	if (type < 0)
		return type;

215
	acl = gfs2_get_acl(inode, type);
S
Steven Whitehouse 已提交
216 217 218 219
	if (IS_ERR(acl))
		return PTR_ERR(acl);
	if (acl == NULL)
		return -ENODATA;
S
Steven Whitehouse 已提交
220

S
Steven Whitehouse 已提交
221 222 223 224 225
	error = posix_acl_to_xattr(acl, buffer, size);
	posix_acl_release(acl);

	return error;
}
S
Steven Whitehouse 已提交
226

227 228 229
static int gfs2_xattr_system_set(struct dentry *dentry, const char *name,
				 const void *value, size_t size, int flags,
				 int xtype)
S
Steven Whitehouse 已提交
230
{
231
	struct inode *inode = dentry->d_inode;
S
Steven Whitehouse 已提交
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
	struct gfs2_sbd *sdp = GFS2_SB(inode);
	struct posix_acl *acl = NULL;
	int error = 0, type;

	if (!sdp->sd_args.ar_posix_acl)
		return -EOPNOTSUPP;

	type = gfs2_acl_type(name);
	if (type < 0)
		return type;
	if (flags & XATTR_CREATE)
		return -EINVAL;
	if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
		return value ? -EACCES : 0;
	if ((current_fsuid() != inode->i_uid) && !capable(CAP_FOWNER))
		return -EPERM;
	if (S_ISLNK(inode->i_mode))
		return -EOPNOTSUPP;

	if (!value)
		goto set_acl;

	acl = posix_acl_from_xattr(value, size);
	if (!acl) {
		/*
		 * acl_set_file(3) may request that we set default ACLs with
		 * zero length -- defend (gracefully) against that here.
		 */
		goto out;
	}
	if (IS_ERR(acl)) {
		error = PTR_ERR(acl);
		goto out;
	}

	error = posix_acl_valid(acl);
	if (error)
		goto out_release;

	error = -EINVAL;
	if (acl->a_count > GFS2_ACL_MAX_ENTRIES)
		goto out_release;

	if (type == ACL_TYPE_ACCESS) {
276
		umode_t mode = inode->i_mode;
S
Steven Whitehouse 已提交
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
		error = posix_acl_equiv_mode(acl, &mode);

		if (error <= 0) {
			posix_acl_release(acl);
			acl = NULL;

			if (error < 0)
				return error;
		}

		error = gfs2_set_mode(inode, mode);
		if (error)
			goto out_release;
	}

set_acl:
293
	error = __gfs2_xattr_set(inode, name, value, size, 0, GFS2_EATYPE_SYS);
S
Steven Whitehouse 已提交
294 295 296 297 298 299
	if (!error) {
		if (acl)
			set_cached_acl(inode, type, acl);
		else
			forget_cached_acl(inode, type);
	}
S
Steven Whitehouse 已提交
300 301 302 303 304 305
out_release:
	posix_acl_release(acl);
out:
	return error;
}

S
Stephen Hemminger 已提交
306
const struct xattr_handler gfs2_xattr_system_handler = {
S
Steven Whitehouse 已提交
307
	.prefix = XATTR_SYSTEM_PREFIX,
308
	.flags  = GFS2_EATYPE_SYS,
S
Steven Whitehouse 已提交
309 310 311 312
	.get    = gfs2_xattr_system_get,
	.set    = gfs2_xattr_system_set,
};