xattr_acl.c revision 8b6dd72a441a683cef7ace93de0a57ced4367f00
1#include <linux/capability.h> 2#include <linux/fs.h> 3#include <linux/posix_acl.h> 4#include <linux/reiserfs_fs.h> 5#include <linux/errno.h> 6#include <linux/pagemap.h> 7#include <linux/xattr.h> 8#include <linux/posix_acl_xattr.h> 9#include <linux/reiserfs_xattr.h> 10#include <linux/reiserfs_acl.h> 11#include <asm/uaccess.h> 12 13static int reiserfs_set_acl(struct inode *inode, int type, 14 struct posix_acl *acl); 15 16static int 17xattr_set_acl(struct inode *inode, int type, const void *value, size_t size) 18{ 19 struct posix_acl *acl; 20 int error; 21 22 if (!reiserfs_posixacl(inode->i_sb)) 23 return -EOPNOTSUPP; 24 if (!is_owner_or_cap(inode)) 25 return -EPERM; 26 27 if (value) { 28 acl = posix_acl_from_xattr(value, size); 29 if (IS_ERR(acl)) { 30 return PTR_ERR(acl); 31 } else if (acl) { 32 error = posix_acl_valid(acl); 33 if (error) 34 goto release_and_out; 35 } 36 } else 37 acl = NULL; 38 39 error = reiserfs_set_acl(inode, type, acl); 40 41 release_and_out: 42 posix_acl_release(acl); 43 return error; 44} 45 46static int 47xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size) 48{ 49 struct posix_acl *acl; 50 int error; 51 52 if (!reiserfs_posixacl(inode->i_sb)) 53 return -EOPNOTSUPP; 54 55 acl = reiserfs_get_acl(inode, type); 56 if (IS_ERR(acl)) 57 return PTR_ERR(acl); 58 if (acl == NULL) 59 return -ENODATA; 60 error = posix_acl_to_xattr(acl, buffer, size); 61 posix_acl_release(acl); 62 63 return error; 64} 65 66/* 67 * Convert from filesystem to in-memory representation. 68 */ 69static struct posix_acl *posix_acl_from_disk(const void *value, size_t size) 70{ 71 const char *end = (char *)value + size; 72 int n, count; 73 struct posix_acl *acl; 74 75 if (!value) 76 return NULL; 77 if (size < sizeof(reiserfs_acl_header)) 78 return ERR_PTR(-EINVAL); 79 if (((reiserfs_acl_header *) value)->a_version != 80 cpu_to_le32(REISERFS_ACL_VERSION)) 81 return ERR_PTR(-EINVAL); 82 value = (char *)value + sizeof(reiserfs_acl_header); 83 count = reiserfs_acl_count(size); 84 if (count < 0) 85 return ERR_PTR(-EINVAL); 86 if (count == 0) 87 return NULL; 88 acl = posix_acl_alloc(count, GFP_NOFS); 89 if (!acl) 90 return ERR_PTR(-ENOMEM); 91 for (n = 0; n < count; n++) { 92 reiserfs_acl_entry *entry = (reiserfs_acl_entry *) value; 93 if ((char *)value + sizeof(reiserfs_acl_entry_short) > end) 94 goto fail; 95 acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag); 96 acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm); 97 switch (acl->a_entries[n].e_tag) { 98 case ACL_USER_OBJ: 99 case ACL_GROUP_OBJ: 100 case ACL_MASK: 101 case ACL_OTHER: 102 value = (char *)value + 103 sizeof(reiserfs_acl_entry_short); 104 acl->a_entries[n].e_id = ACL_UNDEFINED_ID; 105 break; 106 107 case ACL_USER: 108 case ACL_GROUP: 109 value = (char *)value + sizeof(reiserfs_acl_entry); 110 if ((char *)value > end) 111 goto fail; 112 acl->a_entries[n].e_id = le32_to_cpu(entry->e_id); 113 break; 114 115 default: 116 goto fail; 117 } 118 } 119 if (value != end) 120 goto fail; 121 return acl; 122 123 fail: 124 posix_acl_release(acl); 125 return ERR_PTR(-EINVAL); 126} 127 128/* 129 * Convert from in-memory to filesystem representation. 130 */ 131static void *posix_acl_to_disk(const struct posix_acl *acl, size_t * size) 132{ 133 reiserfs_acl_header *ext_acl; 134 char *e; 135 int n; 136 137 *size = reiserfs_acl_size(acl->a_count); 138 ext_acl = kmalloc(sizeof(reiserfs_acl_header) + 139 acl->a_count * 140 sizeof(reiserfs_acl_entry), 141 GFP_NOFS); 142 if (!ext_acl) 143 return ERR_PTR(-ENOMEM); 144 ext_acl->a_version = cpu_to_le32(REISERFS_ACL_VERSION); 145 e = (char *)ext_acl + sizeof(reiserfs_acl_header); 146 for (n = 0; n < acl->a_count; n++) { 147 reiserfs_acl_entry *entry = (reiserfs_acl_entry *) e; 148 entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag); 149 entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm); 150 switch (acl->a_entries[n].e_tag) { 151 case ACL_USER: 152 case ACL_GROUP: 153 entry->e_id = cpu_to_le32(acl->a_entries[n].e_id); 154 e += sizeof(reiserfs_acl_entry); 155 break; 156 157 case ACL_USER_OBJ: 158 case ACL_GROUP_OBJ: 159 case ACL_MASK: 160 case ACL_OTHER: 161 e += sizeof(reiserfs_acl_entry_short); 162 break; 163 164 default: 165 goto fail; 166 } 167 } 168 return (char *)ext_acl; 169 170 fail: 171 kfree(ext_acl); 172 return ERR_PTR(-EINVAL); 173} 174 175static inline void iset_acl(struct inode *inode, struct posix_acl **i_acl, 176 struct posix_acl *acl) 177{ 178 spin_lock(&inode->i_lock); 179 if (*i_acl != ERR_PTR(-ENODATA)) 180 posix_acl_release(*i_acl); 181 *i_acl = posix_acl_dup(acl); 182 spin_unlock(&inode->i_lock); 183} 184 185static inline struct posix_acl *iget_acl(struct inode *inode, 186 struct posix_acl **i_acl) 187{ 188 struct posix_acl *acl = ERR_PTR(-ENODATA); 189 190 spin_lock(&inode->i_lock); 191 if (*i_acl != ERR_PTR(-ENODATA)) 192 acl = posix_acl_dup(*i_acl); 193 spin_unlock(&inode->i_lock); 194 195 return acl; 196} 197 198/* 199 * Inode operation get_posix_acl(). 200 * 201 * inode->i_mutex: down 202 * BKL held [before 2.5.x] 203 */ 204struct posix_acl *reiserfs_get_acl(struct inode *inode, int type) 205{ 206 char *name, *value; 207 struct posix_acl *acl, **p_acl; 208 int size; 209 int retval; 210 struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode); 211 212 switch (type) { 213 case ACL_TYPE_ACCESS: 214 name = POSIX_ACL_XATTR_ACCESS; 215 p_acl = &reiserfs_i->i_acl_access; 216 break; 217 case ACL_TYPE_DEFAULT: 218 name = POSIX_ACL_XATTR_DEFAULT; 219 p_acl = &reiserfs_i->i_acl_default; 220 break; 221 default: 222 return ERR_PTR(-EINVAL); 223 } 224 225 acl = iget_acl(inode, p_acl); 226 if (acl && !IS_ERR(acl)) 227 return acl; 228 else if (PTR_ERR(acl) == -ENODATA) 229 return NULL; 230 231 size = reiserfs_xattr_get(inode, name, NULL, 0); 232 if (size < 0) { 233 if (size == -ENODATA || size == -ENOSYS) { 234 *p_acl = ERR_PTR(-ENODATA); 235 return NULL; 236 } 237 return ERR_PTR(size); 238 } 239 240 value = kmalloc(size, GFP_NOFS); 241 if (!value) 242 return ERR_PTR(-ENOMEM); 243 244 retval = reiserfs_xattr_get(inode, name, value, size); 245 if (retval == -ENODATA || retval == -ENOSYS) { 246 /* This shouldn't actually happen as it should have 247 been caught above.. but just in case */ 248 acl = NULL; 249 *p_acl = ERR_PTR(-ENODATA); 250 } else if (retval < 0) { 251 acl = ERR_PTR(retval); 252 } else { 253 acl = posix_acl_from_disk(value, retval); 254 if (!IS_ERR(acl)) 255 iset_acl(inode, p_acl, acl); 256 } 257 258 kfree(value); 259 return acl; 260} 261 262/* 263 * Inode operation set_posix_acl(). 264 * 265 * inode->i_mutex: down 266 * BKL held [before 2.5.x] 267 */ 268static int 269reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) 270{ 271 char *name; 272 void *value = NULL; 273 struct posix_acl **p_acl; 274 size_t size; 275 int error; 276 struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode); 277 278 if (S_ISLNK(inode->i_mode)) 279 return -EOPNOTSUPP; 280 281 switch (type) { 282 case ACL_TYPE_ACCESS: 283 name = POSIX_ACL_XATTR_ACCESS; 284 p_acl = &reiserfs_i->i_acl_access; 285 if (acl) { 286 mode_t mode = inode->i_mode; 287 error = posix_acl_equiv_mode(acl, &mode); 288 if (error < 0) 289 return error; 290 else { 291 inode->i_mode = mode; 292 if (error == 0) 293 acl = NULL; 294 } 295 } 296 break; 297 case ACL_TYPE_DEFAULT: 298 name = POSIX_ACL_XATTR_DEFAULT; 299 p_acl = &reiserfs_i->i_acl_default; 300 if (!S_ISDIR(inode->i_mode)) 301 return acl ? -EACCES : 0; 302 break; 303 default: 304 return -EINVAL; 305 } 306 307 if (acl) { 308 value = posix_acl_to_disk(acl, &size); 309 if (IS_ERR(value)) 310 return (int)PTR_ERR(value); 311 error = reiserfs_xattr_set(inode, name, value, size, 0); 312 } else { 313 error = reiserfs_xattr_del(inode, name); 314 if (error == -ENODATA) { 315 /* This may seem odd here, but it means that the ACL was set 316 * with a value representable with mode bits. If there was 317 * an ACL before, reiserfs_xattr_del already dirtied the inode. 318 */ 319 mark_inode_dirty(inode); 320 error = 0; 321 } 322 } 323 324 kfree(value); 325 326 if (!error) 327 iset_acl(inode, p_acl, acl); 328 329 return error; 330} 331 332/* dir->i_mutex: locked, 333 * inode is new and not released into the wild yet */ 334int 335reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry, 336 struct inode *inode) 337{ 338 struct posix_acl *acl; 339 int err = 0; 340 341 /* ACLs only get applied to files and directories */ 342 if (S_ISLNK(inode->i_mode)) 343 return 0; 344 345 /* ACLs can only be used on "new" objects, so if it's an old object 346 * there is nothing to inherit from */ 347 if (get_inode_sd_version(dir) == STAT_DATA_V1) 348 goto apply_umask; 349 350 /* Don't apply ACLs to objects in the .reiserfs_priv tree.. This 351 * would be useless since permissions are ignored, and a pain because 352 * it introduces locking cycles */ 353 if (IS_PRIVATE(dir)) { 354 inode->i_flags |= S_PRIVATE; 355 goto apply_umask; 356 } 357 358 acl = reiserfs_get_acl(dir, ACL_TYPE_DEFAULT); 359 if (IS_ERR(acl)) { 360 if (PTR_ERR(acl) == -ENODATA) 361 goto apply_umask; 362 return PTR_ERR(acl); 363 } 364 365 if (acl) { 366 struct posix_acl *acl_copy; 367 mode_t mode = inode->i_mode; 368 int need_acl; 369 370 /* Copy the default ACL to the default ACL of a new directory */ 371 if (S_ISDIR(inode->i_mode)) { 372 err = reiserfs_set_acl(inode, ACL_TYPE_DEFAULT, acl); 373 if (err) 374 goto cleanup; 375 } 376 377 /* Now we reconcile the new ACL and the mode, 378 potentially modifying both */ 379 acl_copy = posix_acl_clone(acl, GFP_NOFS); 380 if (!acl_copy) { 381 err = -ENOMEM; 382 goto cleanup; 383 } 384 385 need_acl = posix_acl_create_masq(acl_copy, &mode); 386 if (need_acl >= 0) { 387 if (mode != inode->i_mode) { 388 inode->i_mode = mode; 389 } 390 391 /* If we need an ACL.. */ 392 if (need_acl > 0) { 393 err = 394 reiserfs_set_acl(inode, ACL_TYPE_ACCESS, 395 acl_copy); 396 if (err) 397 goto cleanup_copy; 398 } 399 } 400 cleanup_copy: 401 posix_acl_release(acl_copy); 402 cleanup: 403 posix_acl_release(acl); 404 } else { 405 apply_umask: 406 /* no ACL, apply umask */ 407 inode->i_mode &= ~current->fs->umask; 408 } 409 410 return err; 411} 412 413/* Looks up and caches the result of the default ACL. 414 * We do this so that we don't need to carry the xattr_sem into 415 * reiserfs_new_inode if we don't need to */ 416int reiserfs_cache_default_acl(struct inode *inode) 417{ 418 int ret = 0; 419 if (reiserfs_posixacl(inode->i_sb) && !IS_PRIVATE(inode)) { 420 struct posix_acl *acl; 421 acl = reiserfs_get_acl(inode, ACL_TYPE_DEFAULT); 422 ret = (acl && !IS_ERR(acl)); 423 if (ret) 424 posix_acl_release(acl); 425 } 426 427 return ret; 428} 429 430int reiserfs_acl_chmod(struct inode *inode) 431{ 432 struct posix_acl *acl, *clone; 433 int error; 434 435 if (S_ISLNK(inode->i_mode)) 436 return -EOPNOTSUPP; 437 438 if (get_inode_sd_version(inode) == STAT_DATA_V1 || 439 !reiserfs_posixacl(inode->i_sb)) { 440 return 0; 441 } 442 443 acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS); 444 if (!acl) 445 return 0; 446 if (IS_ERR(acl)) 447 return PTR_ERR(acl); 448 clone = posix_acl_clone(acl, GFP_NOFS); 449 posix_acl_release(acl); 450 if (!clone) 451 return -ENOMEM; 452 error = posix_acl_chmod_masq(clone, inode->i_mode); 453 if (!error) 454 error = reiserfs_set_acl(inode, ACL_TYPE_ACCESS, clone); 455 posix_acl_release(clone); 456 return error; 457} 458 459static int 460posix_acl_access_get(struct inode *inode, const char *name, 461 void *buffer, size_t size) 462{ 463 if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS) - 1) 464 return -EINVAL; 465 return xattr_get_acl(inode, ACL_TYPE_ACCESS, buffer, size); 466} 467 468static int 469posix_acl_access_set(struct inode *inode, const char *name, 470 const void *value, size_t size, int flags) 471{ 472 if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS) - 1) 473 return -EINVAL; 474 return xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size); 475} 476 477static int posix_acl_access_del(struct inode *inode, const char *name) 478{ 479 struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode); 480 if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS) - 1) 481 return -EINVAL; 482 iset_acl(inode, &reiserfs_i->i_acl_access, ERR_PTR(-ENODATA)); 483 return 0; 484} 485 486static int 487posix_acl_access_list(struct inode *inode, const char *name, int namelen, 488 char *out) 489{ 490 int len = namelen; 491 if (!reiserfs_posixacl(inode->i_sb)) 492 return 0; 493 if (out) 494 memcpy(out, name, len); 495 496 return len; 497} 498 499struct reiserfs_xattr_handler posix_acl_access_handler = { 500 .prefix = POSIX_ACL_XATTR_ACCESS, 501 .get = posix_acl_access_get, 502 .set = posix_acl_access_set, 503 .del = posix_acl_access_del, 504 .list = posix_acl_access_list, 505}; 506 507static int 508posix_acl_default_get(struct inode *inode, const char *name, 509 void *buffer, size_t size) 510{ 511 if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT) - 1) 512 return -EINVAL; 513 return xattr_get_acl(inode, ACL_TYPE_DEFAULT, buffer, size); 514} 515 516static int 517posix_acl_default_set(struct inode *inode, const char *name, 518 const void *value, size_t size, int flags) 519{ 520 if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT) - 1) 521 return -EINVAL; 522 return xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size); 523} 524 525static int posix_acl_default_del(struct inode *inode, const char *name) 526{ 527 struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode); 528 if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT) - 1) 529 return -EINVAL; 530 iset_acl(inode, &reiserfs_i->i_acl_default, ERR_PTR(-ENODATA)); 531 return 0; 532} 533 534static int 535posix_acl_default_list(struct inode *inode, const char *name, int namelen, 536 char *out) 537{ 538 int len = namelen; 539 if (!reiserfs_posixacl(inode->i_sb)) 540 return 0; 541 if (out) 542 memcpy(out, name, len); 543 544 return len; 545} 546 547struct reiserfs_xattr_handler posix_acl_default_handler = { 548 .prefix = POSIX_ACL_XATTR_DEFAULT, 549 .get = posix_acl_default_get, 550 .set = posix_acl_default_set, 551 .del = posix_acl_default_del, 552 .list = posix_acl_default_list, 553}; 554