acl.c 6.8 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

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

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

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

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

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

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

/**
S
Steven Whitehouse 已提交
71
 * gfs2_check_acl - Check an ACL to see if we're allowed to do something
D
David Teigland 已提交
72 73 74 75 76 77
 * @inode: the file we want to do something to
 * @mask: what we want to do
 *
 * Returns: errno
 */

78
int gfs2_check_acl(struct inode *inode, int mask)
D
David Teigland 已提交
79
{
S
Steven Whitehouse 已提交
80
	struct posix_acl *acl;
D
David Teigland 已提交
81 82
	int error;

S
Steven Whitehouse 已提交
83 84 85
	acl = gfs2_acl_get(GFS2_I(inode), ACL_TYPE_ACCESS);
	if (IS_ERR(acl))
		return PTR_ERR(acl);
D
David Teigland 已提交
86 87 88 89 90 91 92 93 94 95

	if (acl) {
		error = posix_acl_permission(inode, acl, mask);
		posix_acl_release(acl);
		return error;
	}

	return -EAGAIN;
}

96
static int gfs2_set_mode(struct inode *inode, mode_t mode)
D
David Teigland 已提交
97
{
98
	int error = 0;
D
David Teigland 已提交
99

100 101
	if (mode != inode->i_mode) {
		struct iattr iattr;
D
David Teigland 已提交
102

103 104
		iattr.ia_valid = ATTR_MODE;
		iattr.ia_mode = mode;
D
David Teigland 已提交
105

106 107
		error = gfs2_setattr_simple(GFS2_I(inode), &iattr);
	}
D
David Teigland 已提交
108

109
	return error;
D
David Teigland 已提交
110 111
}

S
Steven Whitehouse 已提交
112
static int gfs2_acl_set(struct inode *inode, int type, struct posix_acl *acl)
D
David Teigland 已提交
113 114
{
	int error;
S
Steven Whitehouse 已提交
115 116 117 118 119 120 121 122 123 124 125 126 127 128
	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;
129
	error = __gfs2_xattr_set(inode, name, data, len, 0, GFS2_EATYPE_SYS);
S
Steven Whitehouse 已提交
130 131
	if (!error)
		set_cached_acl(inode, type, acl);
S
Steven Whitehouse 已提交
132 133 134 135 136 137 138 139
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);
140
	struct posix_acl *acl;
S
Steven Whitehouse 已提交
141 142
	mode_t mode = inode->i_mode;
	int error = 0;
D
David Teigland 已提交
143 144 145

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

S
Steven Whitehouse 已提交
149 150 151
	acl = gfs2_acl_get(dip, ACL_TYPE_DEFAULT);
	if (IS_ERR(acl))
		return PTR_ERR(acl);
D
David Teigland 已提交
152
	if (!acl) {
A
Al Viro 已提交
153
		mode &= ~current_umask();
S
Steven Whitehouse 已提交
154 155
		if (mode != inode->i_mode)
			error = gfs2_set_mode(inode, mode);
D
David Teigland 已提交
156 157 158
		return error;
	}

S
Steven Whitehouse 已提交
159 160 161 162 163 164
	if (S_ISDIR(inode->i_mode)) {
		error = gfs2_acl_set(inode, ACL_TYPE_DEFAULT, acl);
		if (error)
			goto out;
	}

165
	error = posix_acl_create(&acl, GFP_NOFS, &mode);
D
David Teigland 已提交
166
	if (error < 0)
167 168
		return error;

169 170
	if (error == 0)
		goto munge;
D
David Teigland 已提交
171

S
Steven Whitehouse 已提交
172
	error = gfs2_acl_set(inode, ACL_TYPE_ACCESS, acl);
173 174 175
	if (error)
		goto out;
munge:
S
Steven Whitehouse 已提交
176
	error = gfs2_set_mode(inode, mode);
177
out:
D
David Teigland 已提交
178 179 180 181 182 183
	posix_acl_release(acl);
	return error;
}

int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
{
184
	struct posix_acl *acl;
D
David Teigland 已提交
185 186 187 188
	char *data;
	unsigned int len;
	int error;

S
Steven Whitehouse 已提交
189 190 191
	acl = gfs2_acl_get(ip, ACL_TYPE_ACCESS);
	if (IS_ERR(acl))
		return PTR_ERR(acl);
D
David Teigland 已提交
192 193 194
	if (!acl)
		return gfs2_setattr_simple(ip, attr);

195 196 197 198 199 200
	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 已提交
201
	error = -ENOMEM;
202
	if (data == NULL)
D
David Teigland 已提交
203
		goto out;
204 205 206 207
	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 已提交
208

209
out:
D
David Teigland 已提交
210 211 212 213
	posix_acl_release(acl);
	return error;
}

S
Steven Whitehouse 已提交
214 215 216 217 218 219 220 221 222
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;
}

223 224
static int gfs2_xattr_system_get(struct dentry *dentry, const char *name,
				 void *buffer, size_t size, int xtype)
S
Steven Whitehouse 已提交
225
{
226
	struct inode *inode = dentry->d_inode;
227
	struct gfs2_sbd *sdp = GFS2_SB(inode);
S
Steven Whitehouse 已提交
228
	struct posix_acl *acl;
S
Steven Whitehouse 已提交
229
	int type;
S
Steven Whitehouse 已提交
230
	int error;
S
Steven Whitehouse 已提交
231

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

S
Steven Whitehouse 已提交
235 236 237 238
	type = gfs2_acl_type(name);
	if (type < 0)
		return type;

S
Steven Whitehouse 已提交
239 240 241 242 243
	acl = gfs2_acl_get(GFS2_I(inode), type);
	if (IS_ERR(acl))
		return PTR_ERR(acl);
	if (acl == NULL)
		return -ENODATA;
S
Steven Whitehouse 已提交
244

S
Steven Whitehouse 已提交
245 246 247 248 249
	error = posix_acl_to_xattr(acl, buffer, size);
	posix_acl_release(acl);

	return error;
}
S
Steven Whitehouse 已提交
250

251 252 253
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 已提交
254
{
255
	struct inode *inode = dentry->d_inode;
S
Steven Whitehouse 已提交
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
	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) {
		mode_t mode = inode->i_mode;
		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:
317
	error = __gfs2_xattr_set(inode, name, value, size, 0, GFS2_EATYPE_SYS);
S
Steven Whitehouse 已提交
318 319 320 321 322 323
	if (!error) {
		if (acl)
			set_cached_acl(inode, type, acl);
		else
			forget_cached_acl(inode, type);
	}
S
Steven Whitehouse 已提交
324 325 326 327 328 329
out_release:
	posix_acl_release(acl);
out:
	return error;
}

S
Stephen Hemminger 已提交
330
const struct xattr_handler gfs2_xattr_system_handler = {
S
Steven Whitehouse 已提交
331
	.prefix = XATTR_SYSTEM_PREFIX,
332
	.flags  = GFS2_EATYPE_SYS,
S
Steven Whitehouse 已提交
333 334 335 336
	.get    = gfs2_xattr_system_get,
	.set    = gfs2_xattr_system_set,
};