1 /* -*- mode: c; c-basic-offset: 8; -*- 2 * vim: noexpandtab sw=8 ts=8 sts=0: 3 * 4 * acl.c 5 * 6 * Copyright (C) 2004, 2008 Oracle. All rights reserved. 7 * 8 * CREDITS: 9 * Lots of code in this file is copy from linux/fs/ext3/acl.c. 10 * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de> 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public 14 * License version 2 as published by the Free Software Foundation. 15 * 16 * This program is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 * General Public License for more details. 20 */ 21 22 #include <linux/init.h> 23 #include <linux/module.h> 24 #include <linux/slab.h> 25 #include <linux/string.h> 26 27 #define MLOG_MASK_PREFIX ML_INODE 28 #include <cluster/masklog.h> 29 30 #include "ocfs2.h" 31 #include "alloc.h" 32 #include "dlmglue.h" 33 #include "file.h" 34 #include "inode.h" 35 #include "journal.h" 36 #include "ocfs2_fs.h" 37 38 #include "xattr.h" 39 #include "acl.h" 40 41 /* 42 * Convert from xattr value to acl struct. 43 */ 44 static struct posix_acl *ocfs2_acl_from_xattr(const void *value, size_t size) 45 { 46 int n, count; 47 struct posix_acl *acl; 48 49 if (!value) 50 return NULL; 51 if (size < sizeof(struct posix_acl_entry)) 52 return ERR_PTR(-EINVAL); 53 54 count = size / sizeof(struct posix_acl_entry); 55 if (count < 0) 56 return ERR_PTR(-EINVAL); 57 if (count == 0) 58 return NULL; 59 60 acl = posix_acl_alloc(count, GFP_NOFS); 61 if (!acl) 62 return ERR_PTR(-ENOMEM); 63 for (n = 0; n < count; n++) { 64 struct ocfs2_acl_entry *entry = 65 (struct ocfs2_acl_entry *)value; 66 67 acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag); 68 acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm); 69 acl->a_entries[n].e_id = le32_to_cpu(entry->e_id); 70 value += sizeof(struct posix_acl_entry); 71 72 } 73 return acl; 74 } 75 76 /* 77 * Convert acl struct to xattr value. 78 */ 79 static void *ocfs2_acl_to_xattr(const struct posix_acl *acl, size_t *size) 80 { 81 struct ocfs2_acl_entry *entry = NULL; 82 char *ocfs2_acl; 83 size_t n; 84 85 *size = acl->a_count * sizeof(struct posix_acl_entry); 86 87 ocfs2_acl = kmalloc(*size, GFP_NOFS); 88 if (!ocfs2_acl) 89 return ERR_PTR(-ENOMEM); 90 91 entry = (struct ocfs2_acl_entry *)ocfs2_acl; 92 for (n = 0; n < acl->a_count; n++, entry++) { 93 entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag); 94 entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm); 95 entry->e_id = cpu_to_le32(acl->a_entries[n].e_id); 96 } 97 return ocfs2_acl; 98 } 99 100 static struct posix_acl *ocfs2_get_acl_nolock(struct inode *inode, 101 int type, 102 struct buffer_head *di_bh) 103 { 104 int name_index; 105 char *value = NULL; 106 struct posix_acl *acl; 107 int retval; 108 109 switch (type) { 110 case ACL_TYPE_ACCESS: 111 name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS; 112 break; 113 case ACL_TYPE_DEFAULT: 114 name_index = OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT; 115 break; 116 default: 117 return ERR_PTR(-EINVAL); 118 } 119 120 retval = ocfs2_xattr_get_nolock(inode, di_bh, name_index, "", NULL, 0); 121 if (retval > 0) { 122 value = kmalloc(retval, GFP_NOFS); 123 if (!value) 124 return ERR_PTR(-ENOMEM); 125 retval = ocfs2_xattr_get_nolock(inode, di_bh, name_index, 126 "", value, retval); 127 } 128 129 if (retval > 0) 130 acl = ocfs2_acl_from_xattr(value, retval); 131 else if (retval == -ENODATA || retval == 0) 132 acl = NULL; 133 else 134 acl = ERR_PTR(retval); 135 136 kfree(value); 137 138 return acl; 139 } 140 141 142 /* 143 * Get posix acl. 144 */ 145 static struct posix_acl *ocfs2_get_acl(struct inode *inode, int type) 146 { 147 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 148 struct buffer_head *di_bh = NULL; 149 struct posix_acl *acl; 150 int ret; 151 152 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 153 return NULL; 154 155 ret = ocfs2_inode_lock(inode, &di_bh, 0); 156 if (ret < 0) { 157 mlog_errno(ret); 158 acl = ERR_PTR(ret); 159 return acl; 160 } 161 162 acl = ocfs2_get_acl_nolock(inode, type, di_bh); 163 164 ocfs2_inode_unlock(inode, 0); 165 166 brelse(di_bh); 167 168 return acl; 169 } 170 171 /* 172 * Helper function to set i_mode in memory and disk. Some call paths 173 * will not have di_bh or a journal handle to pass, in which case it 174 * will create it's own. 175 */ 176 static int ocfs2_acl_set_mode(struct inode *inode, struct buffer_head *di_bh, 177 handle_t *handle, umode_t new_mode) 178 { 179 int ret, commit_handle = 0; 180 struct ocfs2_dinode *di; 181 182 if (di_bh == NULL) { 183 ret = ocfs2_read_inode_block(inode, &di_bh); 184 if (ret) { 185 mlog_errno(ret); 186 goto out; 187 } 188 } else 189 get_bh(di_bh); 190 191 if (handle == NULL) { 192 handle = ocfs2_start_trans(OCFS2_SB(inode->i_sb), 193 OCFS2_INODE_UPDATE_CREDITS); 194 if (IS_ERR(handle)) { 195 ret = PTR_ERR(handle); 196 mlog_errno(ret); 197 goto out_brelse; 198 } 199 200 commit_handle = 1; 201 } 202 203 di = (struct ocfs2_dinode *)di_bh->b_data; 204 ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh, 205 OCFS2_JOURNAL_ACCESS_WRITE); 206 if (ret) { 207 mlog_errno(ret); 208 goto out_commit; 209 } 210 211 inode->i_mode = new_mode; 212 di->i_mode = cpu_to_le16(inode->i_mode); 213 214 ocfs2_journal_dirty(handle, di_bh); 215 216 out_commit: 217 if (commit_handle) 218 ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); 219 out_brelse: 220 brelse(di_bh); 221 out: 222 return ret; 223 } 224 225 /* 226 * Set the access or default ACL of an inode. 227 */ 228 static int ocfs2_set_acl(handle_t *handle, 229 struct inode *inode, 230 struct buffer_head *di_bh, 231 int type, 232 struct posix_acl *acl, 233 struct ocfs2_alloc_context *meta_ac, 234 struct ocfs2_alloc_context *data_ac) 235 { 236 int name_index; 237 void *value = NULL; 238 size_t size = 0; 239 int ret; 240 241 if (S_ISLNK(inode->i_mode)) 242 return -EOPNOTSUPP; 243 244 switch (type) { 245 case ACL_TYPE_ACCESS: 246 name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS; 247 if (acl) { 248 mode_t mode = inode->i_mode; 249 ret = posix_acl_equiv_mode(acl, &mode); 250 if (ret < 0) 251 return ret; 252 else { 253 if (ret == 0) 254 acl = NULL; 255 256 ret = ocfs2_acl_set_mode(inode, di_bh, 257 handle, mode); 258 if (ret) 259 return ret; 260 261 } 262 } 263 break; 264 case ACL_TYPE_DEFAULT: 265 name_index = OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT; 266 if (!S_ISDIR(inode->i_mode)) 267 return acl ? -EACCES : 0; 268 break; 269 default: 270 return -EINVAL; 271 } 272 273 if (acl) { 274 value = ocfs2_acl_to_xattr(acl, &size); 275 if (IS_ERR(value)) 276 return (int)PTR_ERR(value); 277 } 278 279 if (handle) 280 ret = ocfs2_xattr_set_handle(handle, inode, di_bh, name_index, 281 "", value, size, 0, 282 meta_ac, data_ac); 283 else 284 ret = ocfs2_xattr_set(inode, name_index, "", value, size, 0); 285 286 kfree(value); 287 288 return ret; 289 } 290 291 int ocfs2_check_acl(struct inode *inode, int mask) 292 { 293 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 294 struct buffer_head *di_bh = NULL; 295 struct posix_acl *acl; 296 int ret = -EAGAIN; 297 298 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 299 return ret; 300 301 ret = ocfs2_read_inode_block(inode, &di_bh); 302 if (ret < 0) { 303 mlog_errno(ret); 304 return ret; 305 } 306 307 acl = ocfs2_get_acl_nolock(inode, ACL_TYPE_ACCESS, di_bh); 308 309 brelse(di_bh); 310 311 if (IS_ERR(acl)) { 312 mlog_errno(PTR_ERR(acl)); 313 return PTR_ERR(acl); 314 } 315 if (acl) { 316 ret = posix_acl_permission(inode, acl, mask); 317 posix_acl_release(acl); 318 return ret; 319 } 320 321 return -EAGAIN; 322 } 323 324 int ocfs2_acl_chmod(struct inode *inode) 325 { 326 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 327 struct posix_acl *acl, *clone; 328 int ret; 329 330 if (S_ISLNK(inode->i_mode)) 331 return -EOPNOTSUPP; 332 333 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 334 return 0; 335 336 acl = ocfs2_get_acl(inode, ACL_TYPE_ACCESS); 337 if (IS_ERR(acl) || !acl) 338 return PTR_ERR(acl); 339 clone = posix_acl_clone(acl, GFP_KERNEL); 340 posix_acl_release(acl); 341 if (!clone) 342 return -ENOMEM; 343 ret = posix_acl_chmod_masq(clone, inode->i_mode); 344 if (!ret) 345 ret = ocfs2_set_acl(NULL, inode, NULL, ACL_TYPE_ACCESS, 346 clone, NULL, NULL); 347 posix_acl_release(clone); 348 return ret; 349 } 350 351 /* 352 * Initialize the ACLs of a new inode. If parent directory has default ACL, 353 * then clone to new inode. Called from ocfs2_mknod. 354 */ 355 int ocfs2_init_acl(handle_t *handle, 356 struct inode *inode, 357 struct inode *dir, 358 struct buffer_head *di_bh, 359 struct buffer_head *dir_bh, 360 struct ocfs2_alloc_context *meta_ac, 361 struct ocfs2_alloc_context *data_ac) 362 { 363 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 364 struct posix_acl *acl = NULL; 365 int ret = 0, ret2; 366 mode_t mode; 367 368 if (!S_ISLNK(inode->i_mode)) { 369 if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) { 370 acl = ocfs2_get_acl_nolock(dir, ACL_TYPE_DEFAULT, 371 dir_bh); 372 if (IS_ERR(acl)) 373 return PTR_ERR(acl); 374 } 375 if (!acl) { 376 mode = inode->i_mode & ~current_umask(); 377 ret = ocfs2_acl_set_mode(inode, di_bh, handle, mode); 378 if (ret) { 379 mlog_errno(ret); 380 goto cleanup; 381 } 382 } 383 } 384 if ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) && acl) { 385 struct posix_acl *clone; 386 387 if (S_ISDIR(inode->i_mode)) { 388 ret = ocfs2_set_acl(handle, inode, di_bh, 389 ACL_TYPE_DEFAULT, acl, 390 meta_ac, data_ac); 391 if (ret) 392 goto cleanup; 393 } 394 clone = posix_acl_clone(acl, GFP_NOFS); 395 ret = -ENOMEM; 396 if (!clone) 397 goto cleanup; 398 399 mode = inode->i_mode; 400 ret = posix_acl_create_masq(clone, &mode); 401 if (ret >= 0) { 402 ret2 = ocfs2_acl_set_mode(inode, di_bh, handle, mode); 403 if (ret2) { 404 mlog_errno(ret2); 405 ret = ret2; 406 goto cleanup; 407 } 408 if (ret > 0) { 409 ret = ocfs2_set_acl(handle, inode, 410 di_bh, ACL_TYPE_ACCESS, 411 clone, meta_ac, data_ac); 412 } 413 } 414 posix_acl_release(clone); 415 } 416 cleanup: 417 posix_acl_release(acl); 418 return ret; 419 } 420 421 static size_t ocfs2_xattr_list_acl_access(struct dentry *dentry, 422 char *list, 423 size_t list_len, 424 const char *name, 425 size_t name_len, 426 int type) 427 { 428 struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb); 429 const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS); 430 431 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 432 return 0; 433 434 if (list && size <= list_len) 435 memcpy(list, POSIX_ACL_XATTR_ACCESS, size); 436 return size; 437 } 438 439 static size_t ocfs2_xattr_list_acl_default(struct dentry *dentry, 440 char *list, 441 size_t list_len, 442 const char *name, 443 size_t name_len, 444 int type) 445 { 446 struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb); 447 const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT); 448 449 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 450 return 0; 451 452 if (list && size <= list_len) 453 memcpy(list, POSIX_ACL_XATTR_DEFAULT, size); 454 return size; 455 } 456 457 static int ocfs2_xattr_get_acl(struct dentry *dentry, const char *name, 458 void *buffer, size_t size, int type) 459 { 460 struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb); 461 struct posix_acl *acl; 462 int ret; 463 464 if (strcmp(name, "") != 0) 465 return -EINVAL; 466 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 467 return -EOPNOTSUPP; 468 469 acl = ocfs2_get_acl(dentry->d_inode, type); 470 if (IS_ERR(acl)) 471 return PTR_ERR(acl); 472 if (acl == NULL) 473 return -ENODATA; 474 ret = posix_acl_to_xattr(acl, buffer, size); 475 posix_acl_release(acl); 476 477 return ret; 478 } 479 480 static int ocfs2_xattr_set_acl(struct dentry *dentry, const char *name, 481 const void *value, size_t size, int flags, int type) 482 { 483 struct inode *inode = dentry->d_inode; 484 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 485 struct posix_acl *acl; 486 int ret = 0; 487 488 if (strcmp(name, "") != 0) 489 return -EINVAL; 490 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 491 return -EOPNOTSUPP; 492 493 if (!is_owner_or_cap(inode)) 494 return -EPERM; 495 496 if (value) { 497 acl = posix_acl_from_xattr(value, size); 498 if (IS_ERR(acl)) 499 return PTR_ERR(acl); 500 else if (acl) { 501 ret = posix_acl_valid(acl); 502 if (ret) 503 goto cleanup; 504 } 505 } else 506 acl = NULL; 507 508 ret = ocfs2_set_acl(NULL, inode, NULL, type, acl, NULL, NULL); 509 510 cleanup: 511 posix_acl_release(acl); 512 return ret; 513 } 514 515 const struct xattr_handler ocfs2_xattr_acl_access_handler = { 516 .prefix = POSIX_ACL_XATTR_ACCESS, 517 .flags = ACL_TYPE_ACCESS, 518 .list = ocfs2_xattr_list_acl_access, 519 .get = ocfs2_xattr_get_acl, 520 .set = ocfs2_xattr_set_acl, 521 }; 522 523 const struct xattr_handler ocfs2_xattr_acl_default_handler = { 524 .prefix = POSIX_ACL_XATTR_DEFAULT, 525 .flags = ACL_TYPE_DEFAULT, 526 .list = ocfs2_xattr_list_acl_default, 527 .get = ocfs2_xattr_get_acl, 528 .set = ocfs2_xattr_set_acl, 529 }; 530