1 /* 2 * linux/fs/ext2/acl.c 3 * 4 * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de> 5 */ 6 7 #include <linux/capability.h> 8 #include <linux/init.h> 9 #include <linux/sched.h> 10 #include <linux/slab.h> 11 #include <linux/fs.h> 12 #include "ext2.h" 13 #include "xattr.h" 14 #include "acl.h" 15 16 /* 17 * Convert from filesystem to in-memory representation. 18 */ 19 static struct posix_acl * 20 ext2_acl_from_disk(const void *value, size_t size) 21 { 22 const char *end = (char *)value + size; 23 int n, count; 24 struct posix_acl *acl; 25 26 if (!value) 27 return NULL; 28 if (size < sizeof(ext2_acl_header)) 29 return ERR_PTR(-EINVAL); 30 if (((ext2_acl_header *)value)->a_version != 31 cpu_to_le32(EXT2_ACL_VERSION)) 32 return ERR_PTR(-EINVAL); 33 value = (char *)value + sizeof(ext2_acl_header); 34 count = ext2_acl_count(size); 35 if (count < 0) 36 return ERR_PTR(-EINVAL); 37 if (count == 0) 38 return NULL; 39 acl = posix_acl_alloc(count, GFP_KERNEL); 40 if (!acl) 41 return ERR_PTR(-ENOMEM); 42 for (n=0; n < count; n++) { 43 ext2_acl_entry *entry = 44 (ext2_acl_entry *)value; 45 if ((char *)value + sizeof(ext2_acl_entry_short) > end) 46 goto fail; 47 acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag); 48 acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm); 49 switch(acl->a_entries[n].e_tag) { 50 case ACL_USER_OBJ: 51 case ACL_GROUP_OBJ: 52 case ACL_MASK: 53 case ACL_OTHER: 54 value = (char *)value + 55 sizeof(ext2_acl_entry_short); 56 acl->a_entries[n].e_id = ACL_UNDEFINED_ID; 57 break; 58 59 case ACL_USER: 60 case ACL_GROUP: 61 value = (char *)value + sizeof(ext2_acl_entry); 62 if ((char *)value > end) 63 goto fail; 64 acl->a_entries[n].e_id = 65 le32_to_cpu(entry->e_id); 66 break; 67 68 default: 69 goto fail; 70 } 71 } 72 if (value != end) 73 goto fail; 74 return acl; 75 76 fail: 77 posix_acl_release(acl); 78 return ERR_PTR(-EINVAL); 79 } 80 81 /* 82 * Convert from in-memory to filesystem representation. 83 */ 84 static void * 85 ext2_acl_to_disk(const struct posix_acl *acl, size_t *size) 86 { 87 ext2_acl_header *ext_acl; 88 char *e; 89 size_t n; 90 91 *size = ext2_acl_size(acl->a_count); 92 ext_acl = (ext2_acl_header *)kmalloc(sizeof(ext2_acl_header) + 93 acl->a_count * sizeof(ext2_acl_entry), GFP_KERNEL); 94 if (!ext_acl) 95 return ERR_PTR(-ENOMEM); 96 ext_acl->a_version = cpu_to_le32(EXT2_ACL_VERSION); 97 e = (char *)ext_acl + sizeof(ext2_acl_header); 98 for (n=0; n < acl->a_count; n++) { 99 ext2_acl_entry *entry = (ext2_acl_entry *)e; 100 entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag); 101 entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm); 102 switch(acl->a_entries[n].e_tag) { 103 case ACL_USER: 104 case ACL_GROUP: 105 entry->e_id = 106 cpu_to_le32(acl->a_entries[n].e_id); 107 e += sizeof(ext2_acl_entry); 108 break; 109 110 case ACL_USER_OBJ: 111 case ACL_GROUP_OBJ: 112 case ACL_MASK: 113 case ACL_OTHER: 114 e += sizeof(ext2_acl_entry_short); 115 break; 116 117 default: 118 goto fail; 119 } 120 } 121 return (char *)ext_acl; 122 123 fail: 124 kfree(ext_acl); 125 return ERR_PTR(-EINVAL); 126 } 127 128 static inline struct posix_acl * 129 ext2_iget_acl(struct inode *inode, struct posix_acl **i_acl) 130 { 131 struct posix_acl *acl = EXT2_ACL_NOT_CACHED; 132 133 spin_lock(&inode->i_lock); 134 if (*i_acl != EXT2_ACL_NOT_CACHED) 135 acl = posix_acl_dup(*i_acl); 136 spin_unlock(&inode->i_lock); 137 138 return acl; 139 } 140 141 static inline void 142 ext2_iset_acl(struct inode *inode, struct posix_acl **i_acl, 143 struct posix_acl *acl) 144 { 145 spin_lock(&inode->i_lock); 146 if (*i_acl != EXT2_ACL_NOT_CACHED) 147 posix_acl_release(*i_acl); 148 *i_acl = posix_acl_dup(acl); 149 spin_unlock(&inode->i_lock); 150 } 151 152 /* 153 * inode->i_mutex: don't care 154 */ 155 static struct posix_acl * 156 ext2_get_acl(struct inode *inode, int type) 157 { 158 struct ext2_inode_info *ei = EXT2_I(inode); 159 int name_index; 160 char *value = NULL; 161 struct posix_acl *acl; 162 int retval; 163 164 if (!test_opt(inode->i_sb, POSIX_ACL)) 165 return NULL; 166 167 switch(type) { 168 case ACL_TYPE_ACCESS: 169 acl = ext2_iget_acl(inode, &ei->i_acl); 170 if (acl != EXT2_ACL_NOT_CACHED) 171 return acl; 172 name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS; 173 break; 174 175 case ACL_TYPE_DEFAULT: 176 acl = ext2_iget_acl(inode, &ei->i_default_acl); 177 if (acl != EXT2_ACL_NOT_CACHED) 178 return acl; 179 name_index = EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT; 180 break; 181 182 default: 183 return ERR_PTR(-EINVAL); 184 } 185 retval = ext2_xattr_get(inode, name_index, "", NULL, 0); 186 if (retval > 0) { 187 value = kmalloc(retval, GFP_KERNEL); 188 if (!value) 189 return ERR_PTR(-ENOMEM); 190 retval = ext2_xattr_get(inode, name_index, "", value, retval); 191 } 192 if (retval > 0) 193 acl = ext2_acl_from_disk(value, retval); 194 else if (retval == -ENODATA || retval == -ENOSYS) 195 acl = NULL; 196 else 197 acl = ERR_PTR(retval); 198 kfree(value); 199 200 if (!IS_ERR(acl)) { 201 switch(type) { 202 case ACL_TYPE_ACCESS: 203 ext2_iset_acl(inode, &ei->i_acl, acl); 204 break; 205 206 case ACL_TYPE_DEFAULT: 207 ext2_iset_acl(inode, &ei->i_default_acl, acl); 208 break; 209 } 210 } 211 return acl; 212 } 213 214 /* 215 * inode->i_mutex: down 216 */ 217 static int 218 ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) 219 { 220 struct ext2_inode_info *ei = EXT2_I(inode); 221 int name_index; 222 void *value = NULL; 223 size_t size = 0; 224 int error; 225 226 if (S_ISLNK(inode->i_mode)) 227 return -EOPNOTSUPP; 228 if (!test_opt(inode->i_sb, POSIX_ACL)) 229 return 0; 230 231 switch(type) { 232 case ACL_TYPE_ACCESS: 233 name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS; 234 if (acl) { 235 mode_t mode = inode->i_mode; 236 error = posix_acl_equiv_mode(acl, &mode); 237 if (error < 0) 238 return error; 239 else { 240 inode->i_mode = mode; 241 mark_inode_dirty(inode); 242 if (error == 0) 243 acl = NULL; 244 } 245 } 246 break; 247 248 case ACL_TYPE_DEFAULT: 249 name_index = EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT; 250 if (!S_ISDIR(inode->i_mode)) 251 return acl ? -EACCES : 0; 252 break; 253 254 default: 255 return -EINVAL; 256 } 257 if (acl) { 258 value = ext2_acl_to_disk(acl, &size); 259 if (IS_ERR(value)) 260 return (int)PTR_ERR(value); 261 } 262 263 error = ext2_xattr_set(inode, name_index, "", value, size, 0); 264 265 kfree(value); 266 if (!error) { 267 switch(type) { 268 case ACL_TYPE_ACCESS: 269 ext2_iset_acl(inode, &ei->i_acl, acl); 270 break; 271 272 case ACL_TYPE_DEFAULT: 273 ext2_iset_acl(inode, &ei->i_default_acl, acl); 274 break; 275 } 276 } 277 return error; 278 } 279 280 static int 281 ext2_check_acl(struct inode *inode, int mask) 282 { 283 struct posix_acl *acl = ext2_get_acl(inode, ACL_TYPE_ACCESS); 284 285 if (IS_ERR(acl)) 286 return PTR_ERR(acl); 287 if (acl) { 288 int error = posix_acl_permission(inode, acl, mask); 289 posix_acl_release(acl); 290 return error; 291 } 292 293 return -EAGAIN; 294 } 295 296 int 297 ext2_permission(struct inode *inode, int mask, struct nameidata *nd) 298 { 299 return generic_permission(inode, mask, ext2_check_acl); 300 } 301 302 /* 303 * Initialize the ACLs of a new inode. Called from ext2_new_inode. 304 * 305 * dir->i_mutex: down 306 * inode->i_mutex: up (access to inode is still exclusive) 307 */ 308 int 309 ext2_init_acl(struct inode *inode, struct inode *dir) 310 { 311 struct posix_acl *acl = NULL; 312 int error = 0; 313 314 if (!S_ISLNK(inode->i_mode)) { 315 if (test_opt(dir->i_sb, POSIX_ACL)) { 316 acl = ext2_get_acl(dir, ACL_TYPE_DEFAULT); 317 if (IS_ERR(acl)) 318 return PTR_ERR(acl); 319 } 320 if (!acl) 321 inode->i_mode &= ~current->fs->umask; 322 } 323 if (test_opt(inode->i_sb, POSIX_ACL) && acl) { 324 struct posix_acl *clone; 325 mode_t mode; 326 327 if (S_ISDIR(inode->i_mode)) { 328 error = ext2_set_acl(inode, ACL_TYPE_DEFAULT, acl); 329 if (error) 330 goto cleanup; 331 } 332 clone = posix_acl_clone(acl, GFP_KERNEL); 333 error = -ENOMEM; 334 if (!clone) 335 goto cleanup; 336 mode = inode->i_mode; 337 error = posix_acl_create_masq(clone, &mode); 338 if (error >= 0) { 339 inode->i_mode = mode; 340 if (error > 0) { 341 /* This is an extended ACL */ 342 error = ext2_set_acl(inode, 343 ACL_TYPE_ACCESS, clone); 344 } 345 } 346 posix_acl_release(clone); 347 } 348 cleanup: 349 posix_acl_release(acl); 350 return error; 351 } 352 353 /* 354 * Does chmod for an inode that may have an Access Control List. The 355 * inode->i_mode field must be updated to the desired value by the caller 356 * before calling this function. 357 * Returns 0 on success, or a negative error number. 358 * 359 * We change the ACL rather than storing some ACL entries in the file 360 * mode permission bits (which would be more efficient), because that 361 * would break once additional permissions (like ACL_APPEND, ACL_DELETE 362 * for directories) are added. There are no more bits available in the 363 * file mode. 364 * 365 * inode->i_mutex: down 366 */ 367 int 368 ext2_acl_chmod(struct inode *inode) 369 { 370 struct posix_acl *acl, *clone; 371 int error; 372 373 if (!test_opt(inode->i_sb, POSIX_ACL)) 374 return 0; 375 if (S_ISLNK(inode->i_mode)) 376 return -EOPNOTSUPP; 377 acl = ext2_get_acl(inode, ACL_TYPE_ACCESS); 378 if (IS_ERR(acl) || !acl) 379 return PTR_ERR(acl); 380 clone = posix_acl_clone(acl, GFP_KERNEL); 381 posix_acl_release(acl); 382 if (!clone) 383 return -ENOMEM; 384 error = posix_acl_chmod_masq(clone, inode->i_mode); 385 if (!error) 386 error = ext2_set_acl(inode, ACL_TYPE_ACCESS, clone); 387 posix_acl_release(clone); 388 return error; 389 } 390 391 /* 392 * Extended attribut handlers 393 */ 394 static size_t 395 ext2_xattr_list_acl_access(struct inode *inode, char *list, size_t list_size, 396 const char *name, size_t name_len) 397 { 398 const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS); 399 400 if (!test_opt(inode->i_sb, POSIX_ACL)) 401 return 0; 402 if (list && size <= list_size) 403 memcpy(list, POSIX_ACL_XATTR_ACCESS, size); 404 return size; 405 } 406 407 static size_t 408 ext2_xattr_list_acl_default(struct inode *inode, char *list, size_t list_size, 409 const char *name, size_t name_len) 410 { 411 const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT); 412 413 if (!test_opt(inode->i_sb, POSIX_ACL)) 414 return 0; 415 if (list && size <= list_size) 416 memcpy(list, POSIX_ACL_XATTR_DEFAULT, size); 417 return size; 418 } 419 420 static int 421 ext2_xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size) 422 { 423 struct posix_acl *acl; 424 int error; 425 426 if (!test_opt(inode->i_sb, POSIX_ACL)) 427 return -EOPNOTSUPP; 428 429 acl = ext2_get_acl(inode, type); 430 if (IS_ERR(acl)) 431 return PTR_ERR(acl); 432 if (acl == NULL) 433 return -ENODATA; 434 error = posix_acl_to_xattr(acl, buffer, size); 435 posix_acl_release(acl); 436 437 return error; 438 } 439 440 static int 441 ext2_xattr_get_acl_access(struct inode *inode, const char *name, 442 void *buffer, size_t size) 443 { 444 if (strcmp(name, "") != 0) 445 return -EINVAL; 446 return ext2_xattr_get_acl(inode, ACL_TYPE_ACCESS, buffer, size); 447 } 448 449 static int 450 ext2_xattr_get_acl_default(struct inode *inode, const char *name, 451 void *buffer, size_t size) 452 { 453 if (strcmp(name, "") != 0) 454 return -EINVAL; 455 return ext2_xattr_get_acl(inode, ACL_TYPE_DEFAULT, buffer, size); 456 } 457 458 static int 459 ext2_xattr_set_acl(struct inode *inode, int type, const void *value, 460 size_t size) 461 { 462 struct posix_acl *acl; 463 int error; 464 465 if (!test_opt(inode->i_sb, POSIX_ACL)) 466 return -EOPNOTSUPP; 467 if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 468 return -EPERM; 469 470 if (value) { 471 acl = posix_acl_from_xattr(value, size); 472 if (IS_ERR(acl)) 473 return PTR_ERR(acl); 474 else if (acl) { 475 error = posix_acl_valid(acl); 476 if (error) 477 goto release_and_out; 478 } 479 } else 480 acl = NULL; 481 482 error = ext2_set_acl(inode, type, acl); 483 484 release_and_out: 485 posix_acl_release(acl); 486 return error; 487 } 488 489 static int 490 ext2_xattr_set_acl_access(struct inode *inode, const char *name, 491 const void *value, size_t size, int flags) 492 { 493 if (strcmp(name, "") != 0) 494 return -EINVAL; 495 return ext2_xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size); 496 } 497 498 static int 499 ext2_xattr_set_acl_default(struct inode *inode, const char *name, 500 const void *value, size_t size, int flags) 501 { 502 if (strcmp(name, "") != 0) 503 return -EINVAL; 504 return ext2_xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size); 505 } 506 507 struct xattr_handler ext2_xattr_acl_access_handler = { 508 .prefix = POSIX_ACL_XATTR_ACCESS, 509 .list = ext2_xattr_list_acl_access, 510 .get = ext2_xattr_get_acl_access, 511 .set = ext2_xattr_set_acl_access, 512 }; 513 514 struct xattr_handler ext2_xattr_acl_default_handler = { 515 .prefix = POSIX_ACL_XATTR_DEFAULT, 516 .list = ext2_xattr_list_acl_default, 517 .get = ext2_xattr_get_acl_default, 518 .set = ext2_xattr_set_acl_default, 519 }; 520