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

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
struct posix_acl *gfs2_get_acl(struct inode *inode, int type)
D
David Teigland 已提交
71
{
72
	return gfs2_acl_get(GFS2_I(inode), type);
D
David Teigland 已提交
73 74
}

A
Al Viro 已提交
75
static int gfs2_set_mode(struct inode *inode, umode_t mode)
D
David Teigland 已提交
76
{
77
	int error = 0;
D
David Teigland 已提交
78

79 80
	if (mode != inode->i_mode) {
		struct iattr iattr;
D
David Teigland 已提交
81

82 83
		iattr.ia_valid = ATTR_MODE;
		iattr.ia_mode = mode;
D
David Teigland 已提交
84

85 86
		error = gfs2_setattr_simple(GFS2_I(inode), &iattr);
	}
D
David Teigland 已提交
87

88
	return error;
D
David Teigland 已提交
89 90
}

S
Steven Whitehouse 已提交
91
static int gfs2_acl_set(struct inode *inode, int type, struct posix_acl *acl)
D
David Teigland 已提交
92 93
{
	int error;
S
Steven Whitehouse 已提交
94 95 96 97 98 99 100 101 102 103 104 105 106 107
	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;
108
	error = __gfs2_xattr_set(inode, name, data, len, 0, GFS2_EATYPE_SYS);
S
Steven Whitehouse 已提交
109 110
	if (!error)
		set_cached_acl(inode, type, acl);
S
Steven Whitehouse 已提交
111 112 113 114 115 116 117 118
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);
119
	struct posix_acl *acl;
A
Al Viro 已提交
120
	umode_t mode = inode->i_mode;
S
Steven Whitehouse 已提交
121
	int error = 0;
D
David Teigland 已提交
122 123 124

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

S
Steven Whitehouse 已提交
128 129 130
	acl = gfs2_acl_get(dip, ACL_TYPE_DEFAULT);
	if (IS_ERR(acl))
		return PTR_ERR(acl);
D
David Teigland 已提交
131
	if (!acl) {
A
Al Viro 已提交
132
		mode &= ~current_umask();
S
Steven Whitehouse 已提交
133 134
		if (mode != inode->i_mode)
			error = gfs2_set_mode(inode, mode);
D
David Teigland 已提交
135 136 137
		return error;
	}

S
Steven Whitehouse 已提交
138 139 140 141 142 143
	if (S_ISDIR(inode->i_mode)) {
		error = gfs2_acl_set(inode, ACL_TYPE_DEFAULT, acl);
		if (error)
			goto out;
	}

144
	error = posix_acl_create(&acl, GFP_NOFS, &mode);
D
David Teigland 已提交
145
	if (error < 0)
146 147
		return error;

148 149
	if (error == 0)
		goto munge;
D
David Teigland 已提交
150

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

int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
{
163
	struct posix_acl *acl;
D
David Teigland 已提交
164 165 166 167
	char *data;
	unsigned int len;
	int error;

S
Steven Whitehouse 已提交
168 169 170
	acl = gfs2_acl_get(ip, ACL_TYPE_ACCESS);
	if (IS_ERR(acl))
		return PTR_ERR(acl);
D
David Teigland 已提交
171 172 173
	if (!acl)
		return gfs2_setattr_simple(ip, attr);

174 175 176 177 178 179
	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 已提交
180
	error = -ENOMEM;
181
	if (data == NULL)
D
David Teigland 已提交
182
		goto out;
183 184 185 186
	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 已提交
187

188
out:
D
David Teigland 已提交
189 190 191 192
	posix_acl_release(acl);
	return error;
}

S
Steven Whitehouse 已提交
193 194 195 196 197 198 199 200 201
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;
}

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

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

S
Steven Whitehouse 已提交
214 215 216 217
	type = gfs2_acl_type(name);
	if (type < 0)
		return type;

S
Steven Whitehouse 已提交
218 219 220 221 222
	acl = gfs2_acl_get(GFS2_I(inode), type);
	if (IS_ERR(acl))
		return PTR_ERR(acl);
	if (acl == NULL)
		return -ENODATA;
S
Steven Whitehouse 已提交
223

S
Steven Whitehouse 已提交
224 225 226 227 228
	error = posix_acl_to_xattr(acl, buffer, size);
	posix_acl_release(acl);

	return error;
}
S
Steven Whitehouse 已提交
229

230 231 232
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 已提交
233
{
234
	struct inode *inode = dentry->d_inode;
S
Steven Whitehouse 已提交
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 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
	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:
296
	error = __gfs2_xattr_set(inode, name, value, size, 0, GFS2_EATYPE_SYS);
S
Steven Whitehouse 已提交
297 298 299 300 301 302
	if (!error) {
		if (acl)
			set_cached_acl(inode, type, acl);
		else
			forget_cached_acl(inode, type);
	}
S
Steven Whitehouse 已提交
303 304 305 306 307 308
out_release:
	posix_acl_release(acl);
out:
	return error;
}

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