xattr_acl.c 14.2 KB
Newer Older
1
#include <linux/capability.h>
L
Linus Torvalds 已提交
2 3 4 5 6 7
#include <linux/fs.h>
#include <linux/posix_acl.h>
#include <linux/reiserfs_fs.h>
#include <linux/errno.h>
#include <linux/pagemap.h>
#include <linux/xattr.h>
8
#include <linux/posix_acl_xattr.h>
L
Linus Torvalds 已提交
9 10 11 12
#include <linux/reiserfs_xattr.h>
#include <linux/reiserfs_acl.h>
#include <asm/uaccess.h>

J
Jeff Mahoney 已提交
13 14
static int reiserfs_set_acl(struct reiserfs_transaction_handle *th,
			    struct inode *inode, int type,
15
			    struct posix_acl *acl);
L
Linus Torvalds 已提交
16 17 18 19 20

static int
xattr_set_acl(struct inode *inode, int type, const void *value, size_t size)
{
	struct posix_acl *acl;
J
Jeff Mahoney 已提交
21 22 23
	int error, error2;
	struct reiserfs_transaction_handle th;
	size_t jcreate_blocks;
L
Linus Torvalds 已提交
24 25
	if (!reiserfs_posixacl(inode->i_sb))
		return -EOPNOTSUPP;
26
	if (!is_owner_or_cap(inode))
L
Linus Torvalds 已提交
27 28 29 30 31 32 33 34 35 36 37 38 39 40
		return -EPERM;

	if (value) {
		acl = posix_acl_from_xattr(value, size);
		if (IS_ERR(acl)) {
			return PTR_ERR(acl);
		} else if (acl) {
			error = posix_acl_valid(acl);
			if (error)
				goto release_and_out;
		}
	} else
		acl = NULL;

J
Jeff Mahoney 已提交
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
	/* Pessimism: We can't assume that anything from the xattr root up
	 * has been created. */

	jcreate_blocks = reiserfs_xattr_jcreate_nblocks(inode) +
			 reiserfs_xattr_nblocks(inode, size) * 2;

	reiserfs_write_lock(inode->i_sb);
	error = journal_begin(&th, inode->i_sb, jcreate_blocks);
	if (error == 0) {
		error = reiserfs_set_acl(&th, inode, type, acl);
		error2 = journal_end(&th, inode->i_sb, jcreate_blocks);
		if (error2)
			error = error2;
	}
	reiserfs_write_unlock(inode->i_sb);
L
Linus Torvalds 已提交
56

57
      release_and_out:
L
Linus Torvalds 已提交
58 59 60 61 62 63 64 65 66 67 68 69 70
	posix_acl_release(acl);
	return error;
}

static int
xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size)
{
	struct posix_acl *acl;
	int error;

	if (!reiserfs_posixacl(inode->i_sb))
		return -EOPNOTSUPP;

71
	acl = reiserfs_get_acl(inode, type);
L
Linus Torvalds 已提交
72 73 74 75 76 77 78 79 80 81 82 83 84
	if (IS_ERR(acl))
		return PTR_ERR(acl);
	if (acl == NULL)
		return -ENODATA;
	error = posix_acl_to_xattr(acl, buffer, size);
	posix_acl_release(acl);

	return error;
}

/*
 * Convert from filesystem to in-memory representation.
 */
85
static struct posix_acl *posix_acl_from_disk(const void *value, size_t size)
L
Linus Torvalds 已提交
86 87 88 89 90 91 92 93
{
	const char *end = (char *)value + size;
	int n, count;
	struct posix_acl *acl;

	if (!value)
		return NULL;
	if (size < sizeof(reiserfs_acl_header))
94 95
		return ERR_PTR(-EINVAL);
	if (((reiserfs_acl_header *) value)->a_version !=
L
Linus Torvalds 已提交
96 97 98 99 100 101 102 103 104 105 106
	    cpu_to_le32(REISERFS_ACL_VERSION))
		return ERR_PTR(-EINVAL);
	value = (char *)value + sizeof(reiserfs_acl_header);
	count = reiserfs_acl_count(size);
	if (count < 0)
		return ERR_PTR(-EINVAL);
	if (count == 0)
		return NULL;
	acl = posix_acl_alloc(count, GFP_NOFS);
	if (!acl)
		return ERR_PTR(-ENOMEM);
107 108
	for (n = 0; n < count; n++) {
		reiserfs_acl_entry *entry = (reiserfs_acl_entry *) value;
L
Linus Torvalds 已提交
109 110
		if ((char *)value + sizeof(reiserfs_acl_entry_short) > end)
			goto fail;
111
		acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag);
L
Linus Torvalds 已提交
112
		acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm);
113 114 115 116 117 118 119 120 121 122 123 124 125 126
		switch (acl->a_entries[n].e_tag) {
		case ACL_USER_OBJ:
		case ACL_GROUP_OBJ:
		case ACL_MASK:
		case ACL_OTHER:
			value = (char *)value +
			    sizeof(reiserfs_acl_entry_short);
			acl->a_entries[n].e_id = ACL_UNDEFINED_ID;
			break;

		case ACL_USER:
		case ACL_GROUP:
			value = (char *)value + sizeof(reiserfs_acl_entry);
			if ((char *)value > end)
L
Linus Torvalds 已提交
127
				goto fail;
128 129 130 131 132
			acl->a_entries[n].e_id = le32_to_cpu(entry->e_id);
			break;

		default:
			goto fail;
L
Linus Torvalds 已提交
133 134 135 136 137 138
		}
	}
	if (value != end)
		goto fail;
	return acl;

139
      fail:
L
Linus Torvalds 已提交
140 141 142 143 144 145 146
	posix_acl_release(acl);
	return ERR_PTR(-EINVAL);
}

/*
 * Convert from in-memory to filesystem representation.
 */
147
static void *posix_acl_to_disk(const struct posix_acl *acl, size_t * size)
L
Linus Torvalds 已提交
148 149 150 151 152 153
{
	reiserfs_acl_header *ext_acl;
	char *e;
	int n;

	*size = reiserfs_acl_size(acl->a_count);
154
	ext_acl = kmalloc(sizeof(reiserfs_acl_header) +
155 156 157
						  acl->a_count *
						  sizeof(reiserfs_acl_entry),
						  GFP_NOFS);
L
Linus Torvalds 已提交
158 159 160 161
	if (!ext_acl)
		return ERR_PTR(-ENOMEM);
	ext_acl->a_version = cpu_to_le32(REISERFS_ACL_VERSION);
	e = (char *)ext_acl + sizeof(reiserfs_acl_header);
162 163 164
	for (n = 0; n < acl->a_count; n++) {
		reiserfs_acl_entry *entry = (reiserfs_acl_entry *) e;
		entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag);
L
Linus Torvalds 已提交
165
		entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm);
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
		switch (acl->a_entries[n].e_tag) {
		case ACL_USER:
		case ACL_GROUP:
			entry->e_id = cpu_to_le32(acl->a_entries[n].e_id);
			e += sizeof(reiserfs_acl_entry);
			break;

		case ACL_USER_OBJ:
		case ACL_GROUP_OBJ:
		case ACL_MASK:
		case ACL_OTHER:
			e += sizeof(reiserfs_acl_entry_short);
			break;

		default:
			goto fail;
L
Linus Torvalds 已提交
182 183 184 185
		}
	}
	return (char *)ext_acl;

186
      fail:
L
Linus Torvalds 已提交
187 188 189 190
	kfree(ext_acl);
	return ERR_PTR(-EINVAL);
}

191 192 193 194
static inline void iset_acl(struct inode *inode, struct posix_acl **i_acl,
			    struct posix_acl *acl)
{
	spin_lock(&inode->i_lock);
195
	if (*i_acl != ACL_NOT_CACHED)
196
		posix_acl_release(*i_acl);
197
	*i_acl = posix_acl_dup(acl);
198 199 200 201 202 203
	spin_unlock(&inode->i_lock);
}

static inline struct posix_acl *iget_acl(struct inode *inode,
					 struct posix_acl **i_acl)
{
204
	struct posix_acl *acl = ACL_NOT_CACHED;
205 206

	spin_lock(&inode->i_lock);
207
	if (*i_acl != ACL_NOT_CACHED)
208 209 210 211 212 213
		acl = posix_acl_dup(*i_acl);
	spin_unlock(&inode->i_lock);

	return acl;
}

L
Linus Torvalds 已提交
214 215 216
/*
 * Inode operation get_posix_acl().
 *
217
 * inode->i_mutex: down
L
Linus Torvalds 已提交
218 219
 * BKL held [before 2.5.x]
 */
220
struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
L
Linus Torvalds 已提交
221 222 223
{
	char *name, *value;
	struct posix_acl *acl, **p_acl;
224
	int size;
L
Linus Torvalds 已提交
225
	int retval;
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
	struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);

	switch (type) {
	case ACL_TYPE_ACCESS:
		name = POSIX_ACL_XATTR_ACCESS;
		p_acl = &reiserfs_i->i_acl_access;
		break;
	case ACL_TYPE_DEFAULT:
		name = POSIX_ACL_XATTR_DEFAULT;
		p_acl = &reiserfs_i->i_acl_default;
		break;
	default:
		return ERR_PTR(-EINVAL);
	}

241
	acl = iget_acl(inode, p_acl);
242
	if (acl != ACL_NOT_CACHED)
243
		return acl;
244 245

	size = reiserfs_xattr_get(inode, name, NULL, 0);
246
	if (size < 0) {
247
		if (size == -ENODATA || size == -ENOSYS) {
248
			*p_acl = NULL;
249 250 251 252
			return NULL;
		}
		return ERR_PTR(size);
	}
L
Linus Torvalds 已提交
253

254 255 256
	value = kmalloc(size, GFP_NOFS);
	if (!value)
		return ERR_PTR(-ENOMEM);
L
Linus Torvalds 已提交
257 258 259 260 261 262

	retval = reiserfs_xattr_get(inode, name, value, size);
	if (retval == -ENODATA || retval == -ENOSYS) {
		/* This shouldn't actually happen as it should have
		   been caught above.. but just in case */
		acl = NULL;
263
		*p_acl = acl;
264
	} else if (retval < 0) {
L
Linus Torvalds 已提交
265 266 267
		acl = ERR_PTR(retval);
	} else {
		acl = posix_acl_from_disk(value, retval);
268
		if (!IS_ERR(acl))
269
			iset_acl(inode, p_acl, acl);
270
	}
L
Linus Torvalds 已提交
271 272 273 274 275 276 277 278

	kfree(value);
	return acl;
}

/*
 * Inode operation set_posix_acl().
 *
279
 * inode->i_mutex: down
L
Linus Torvalds 已提交
280 281 282
 * BKL held [before 2.5.x]
 */
static int
J
Jeff Mahoney 已提交
283 284
reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
		 int type, struct posix_acl *acl)
L
Linus Torvalds 已提交
285
{
286
	char *name;
L
Linus Torvalds 已提交
287 288
	void *value = NULL;
	struct posix_acl **p_acl;
289
	size_t size = 0;
L
Linus Torvalds 已提交
290
	int error;
291
	struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
L
Linus Torvalds 已提交
292 293 294 295

	if (S_ISLNK(inode->i_mode))
		return -EOPNOTSUPP;

296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
	switch (type) {
	case ACL_TYPE_ACCESS:
		name = POSIX_ACL_XATTR_ACCESS;
		p_acl = &reiserfs_i->i_acl_access;
		if (acl) {
			mode_t mode = inode->i_mode;
			error = posix_acl_equiv_mode(acl, &mode);
			if (error < 0)
				return error;
			else {
				inode->i_mode = mode;
				if (error == 0)
					acl = NULL;
			}
		}
		break;
	case ACL_TYPE_DEFAULT:
		name = POSIX_ACL_XATTR_DEFAULT;
		p_acl = &reiserfs_i->i_acl_default;
		if (!S_ISDIR(inode->i_mode))
			return acl ? -EACCES : 0;
		break;
	default:
		return -EINVAL;
	}

	if (acl) {
		value = posix_acl_to_disk(acl, &size);
		if (IS_ERR(value))
			return (int)PTR_ERR(value);
326 327
	}

J
Jeff Mahoney 已提交
328
	error = reiserfs_xattr_set_handle(th, inode, name, value, size, 0);
329 330 331 332 333 334 335 336 337 338 339

	/*
	 * Ensure that the inode gets dirtied if we're only using
	 * the mode bits and an old ACL didn't exist. We don't need
	 * to check if the inode is hashed here since we won't get
	 * called by reiserfs_inherit_default_acl().
	 */
	if (error == -ENODATA) {
		error = 0;
		if (type == ACL_TYPE_ACCESS) {
			inode->i_ctime = CURRENT_TIME_SEC;
340 341 342
			mark_inode_dirty(inode);
		}
	}
L
Linus Torvalds 已提交
343

344
	kfree(value);
L
Linus Torvalds 已提交
345

346 347
	if (!error)
		iset_acl(inode, p_acl, acl);
L
Linus Torvalds 已提交
348 349 350 351

	return error;
}

352
/* dir->i_mutex: locked,
L
Linus Torvalds 已提交
353 354
 * inode is new and not released into the wild yet */
int
J
Jeff Mahoney 已提交
355 356
reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
			     struct inode *dir, struct dentry *dentry,
357
			     struct inode *inode)
L
Linus Torvalds 已提交
358
{
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
	struct posix_acl *acl;
	int err = 0;

	/* ACLs only get applied to files and directories */
	if (S_ISLNK(inode->i_mode))
		return 0;

	/* ACLs can only be used on "new" objects, so if it's an old object
	 * there is nothing to inherit from */
	if (get_inode_sd_version(dir) == STAT_DATA_V1)
		goto apply_umask;

	/* Don't apply ACLs to objects in the .reiserfs_priv tree.. This
	 * would be useless since permissions are ignored, and a pain because
	 * it introduces locking cycles */
374 375
	if (IS_PRIVATE(dir)) {
		inode->i_flags |= S_PRIVATE;
376 377 378 379
		goto apply_umask;
	}

	acl = reiserfs_get_acl(dir, ACL_TYPE_DEFAULT);
380
	if (IS_ERR(acl))
381 382 383 384 385 386 387 388 389
		return PTR_ERR(acl);

	if (acl) {
		struct posix_acl *acl_copy;
		mode_t mode = inode->i_mode;
		int need_acl;

		/* Copy the default ACL to the default ACL of a new directory */
		if (S_ISDIR(inode->i_mode)) {
J
Jeff Mahoney 已提交
390 391
			err = reiserfs_set_acl(th, inode, ACL_TYPE_DEFAULT,
					       acl);
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
			if (err)
				goto cleanup;
		}

		/* Now we reconcile the new ACL and the mode,
		   potentially modifying both */
		acl_copy = posix_acl_clone(acl, GFP_NOFS);
		if (!acl_copy) {
			err = -ENOMEM;
			goto cleanup;
		}

		need_acl = posix_acl_create_masq(acl_copy, &mode);
		if (need_acl >= 0) {
			if (mode != inode->i_mode) {
				inode->i_mode = mode;
			}

			/* If we need an ACL.. */
			if (need_acl > 0) {
J
Jeff Mahoney 已提交
412 413 414
				err = reiserfs_set_acl(th, inode,
						       ACL_TYPE_ACCESS,
						       acl_copy);
415 416 417 418 419 420 421 422 423 424 425
				if (err)
					goto cleanup_copy;
			}
		}
	      cleanup_copy:
		posix_acl_release(acl_copy);
	      cleanup:
		posix_acl_release(acl);
	} else {
	      apply_umask:
		/* no ACL, apply umask */
A
Al Viro 已提交
426
		inode->i_mode &= ~current_umask();
427 428 429
	}

	return err;
L
Linus Torvalds 已提交
430 431
}

J
Jeff Mahoney 已提交
432 433 434 435 436 437 438 439 440 441 442
/* This is used to cache the default acl before a new object is created.
 * The biggest reason for this is to get an idea of how many blocks will
 * actually be required for the create operation if we must inherit an ACL.
 * An ACL write can add up to 3 object creations and an additional file write
 * so we'd prefer not to reserve that many blocks in the journal if we can.
 * It also has the advantage of not loading the ACL with a transaction open,
 * this may seem silly, but if the owner of the directory is doing the
 * creation, the ACL may not be loaded since the permissions wouldn't require
 * it.
 * We return the number of blocks required for the transaction.
 */
443
int reiserfs_cache_default_acl(struct inode *inode)
L
Linus Torvalds 已提交
444
{
J
Jeff Mahoney 已提交
445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
	struct posix_acl *acl;
	int nblocks = 0;

	if (IS_PRIVATE(inode))
		return 0;

	acl = reiserfs_get_acl(inode, ACL_TYPE_DEFAULT);

	if (acl && !IS_ERR(acl)) {
		int size = reiserfs_acl_size(acl->a_count);

		/* Other xattrs can be created during inode creation. We don't
		 * want to claim too many blocks, so we check to see if we
		 * we need to create the tree to the xattrs, and then we
		 * just want two files. */
		nblocks = reiserfs_xattr_jcreate_nblocks(inode);
		nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb);

		REISERFS_I(inode)->i_flags |= i_has_xattr_dir;

		/* We need to account for writes + bitmaps for two files */
		nblocks += reiserfs_xattr_nblocks(inode, size) * 4;
		posix_acl_release(acl);
468 469
	}

J
Jeff Mahoney 已提交
470
	return nblocks;
L
Linus Torvalds 已提交
471 472
}

473
int reiserfs_acl_chmod(struct inode *inode)
L
Linus Torvalds 已提交
474
{
475 476
	struct posix_acl *acl, *clone;
	int error;
L
Linus Torvalds 已提交
477

478 479
	if (S_ISLNK(inode->i_mode))
		return -EOPNOTSUPP;
L
Linus Torvalds 已提交
480

481 482 483
	if (get_inode_sd_version(inode) == STAT_DATA_V1 ||
	    !reiserfs_posixacl(inode->i_sb)) {
		return 0;
L
Linus Torvalds 已提交
484 485
	}

486 487 488 489 490 491 492 493 494 495
	acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS);
	if (!acl)
		return 0;
	if (IS_ERR(acl))
		return PTR_ERR(acl);
	clone = posix_acl_clone(acl, GFP_NOFS);
	posix_acl_release(acl);
	if (!clone)
		return -ENOMEM;
	error = posix_acl_chmod_masq(clone, inode->i_mode);
J
Jeff Mahoney 已提交
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
	if (!error) {
		struct reiserfs_transaction_handle th;
		size_t size = reiserfs_xattr_nblocks(inode,
					     reiserfs_acl_size(clone->a_count));
		reiserfs_write_lock(inode->i_sb);
		error = journal_begin(&th, inode->i_sb, size * 2);
		if (!error) {
			int error2;
			error = reiserfs_set_acl(&th, inode, ACL_TYPE_ACCESS,
						 clone);
			error2 = journal_end(&th, inode->i_sb, size * 2);
			if (error2)
				error = error2;
		}
		reiserfs_write_unlock(inode->i_sb);
	}
512 513
	posix_acl_release(clone);
	return error;
L
Linus Torvalds 已提交
514 515 516 517
}

static int
posix_acl_access_get(struct inode *inode, const char *name,
518
		     void *buffer, size_t size)
L
Linus Torvalds 已提交
519
{
520
	if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS) - 1)
L
Linus Torvalds 已提交
521 522 523 524 525 526
		return -EINVAL;
	return xattr_get_acl(inode, ACL_TYPE_ACCESS, buffer, size);
}

static int
posix_acl_access_set(struct inode *inode, const char *name,
527
		     const void *value, size_t size, int flags)
L
Linus Torvalds 已提交
528
{
529
	if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS) - 1)
L
Linus Torvalds 已提交
530 531 532 533
		return -EINVAL;
	return xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size);
}

534 535 536
static size_t posix_acl_access_list(struct inode *inode, char *list,
				    size_t list_size, const char *name,
				    size_t name_len)
L
Linus Torvalds 已提交
537
{
538
	const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS);
539 540
	if (!reiserfs_posixacl(inode->i_sb))
		return 0;
541 542 543
	if (list && size <= list_size)
		memcpy(list, POSIX_ACL_XATTR_ACCESS, size);
	return size;
L
Linus Torvalds 已提交
544 545
}

546
struct xattr_handler reiserfs_posix_acl_access_handler = {
547
	.prefix = POSIX_ACL_XATTR_ACCESS,
L
Linus Torvalds 已提交
548 549 550 551 552 553
	.get = posix_acl_access_get,
	.set = posix_acl_access_set,
	.list = posix_acl_access_list,
};

static int
554 555
posix_acl_default_get(struct inode *inode, const char *name,
		      void *buffer, size_t size)
L
Linus Torvalds 已提交
556
{
557
	if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT) - 1)
L
Linus Torvalds 已提交
558 559 560 561 562 563
		return -EINVAL;
	return xattr_get_acl(inode, ACL_TYPE_DEFAULT, buffer, size);
}

static int
posix_acl_default_set(struct inode *inode, const char *name,
564
		      const void *value, size_t size, int flags)
L
Linus Torvalds 已提交
565
{
566
	if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT) - 1)
L
Linus Torvalds 已提交
567 568 569 570
		return -EINVAL;
	return xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size);
}

571 572 573
static size_t posix_acl_default_list(struct inode *inode, char *list,
				     size_t list_size, const char *name,
				     size_t name_len)
L
Linus Torvalds 已提交
574
{
575
	const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT);
576 577
	if (!reiserfs_posixacl(inode->i_sb))
		return 0;
578 579 580
	if (list && size <= list_size)
		memcpy(list, POSIX_ACL_XATTR_DEFAULT, size);
	return size;
L
Linus Torvalds 已提交
581 582
}

583
struct xattr_handler reiserfs_posix_acl_default_handler = {
584
	.prefix = POSIX_ACL_XATTR_DEFAULT,
L
Linus Torvalds 已提交
585 586 587 588
	.get = posix_acl_default_get,
	.set = posix_acl_default_set,
	.list = posix_acl_default_list,
};