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 inode->i_ctime = CURRENT_TIME; 213 di->i_mode = cpu_to_le16(inode->i_mode); 214 di->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec); 215 di->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec); 216 217 ocfs2_journal_dirty(handle, di_bh); 218 219 out_commit: 220 if (commit_handle) 221 ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); 222 out_brelse: 223 brelse(di_bh); 224 out: 225 return ret; 226 } 227 228 /* 229 * Set the access or default ACL of an inode. 230 */ 231 static int ocfs2_set_acl(handle_t *handle, 232 struct inode *inode, 233 struct buffer_head *di_bh, 234 int type, 235 struct posix_acl *acl, 236 struct ocfs2_alloc_context *meta_ac, 237 struct ocfs2_alloc_context *data_ac) 238 { 239 int name_index; 240 void *value = NULL; 241 size_t size = 0; 242 int ret; 243 244 if (S_ISLNK(inode->i_mode)) 245 return -EOPNOTSUPP; 246 247 switch (type) { 248 case ACL_TYPE_ACCESS: 249 name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS; 250 if (acl) { 251 mode_t mode = inode->i_mode; 252 ret = posix_acl_equiv_mode(acl, &mode); 253 if (ret < 0) 254 return ret; 255 else { 256 if (ret == 0) 257 acl = NULL; 258 259 ret = ocfs2_acl_set_mode(inode, di_bh, 260 handle, mode); 261 if (ret) 262 return ret; 263 264 } 265 } 266 break; 267 case ACL_TYPE_DEFAULT: 268 name_index = OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT; 269 if (!S_ISDIR(inode->i_mode)) 270 return acl ? -EACCES : 0; 271 break; 272 default: 273 return -EINVAL; 274 } 275 276 if (acl) { 277 value = ocfs2_acl_to_xattr(acl, &size); 278 if (IS_ERR(value)) 279 return (int)PTR_ERR(value); 280 } 281 282 if (handle) 283 ret = ocfs2_xattr_set_handle(handle, inode, di_bh, name_index, 284 "", value, size, 0, 285 meta_ac, data_ac); 286 else 287 ret = ocfs2_xattr_set(inode, name_index, "", value, size, 0); 288 289 kfree(value); 290 291 return ret; 292 } 293 294 int ocfs2_check_acl(struct inode *inode, int mask, unsigned int flags) 295 { 296 struct ocfs2_super *osb; 297 struct buffer_head *di_bh = NULL; 298 struct posix_acl *acl; 299 int ret = -EAGAIN; 300 301 if (flags & IPERM_FLAG_RCU) 302 return -ECHILD; 303 304 osb = OCFS2_SB(inode->i_sb); 305 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 306 return ret; 307 308 ret = ocfs2_read_inode_block(inode, &di_bh); 309 if (ret < 0) { 310 mlog_errno(ret); 311 return ret; 312 } 313 314 acl = ocfs2_get_acl_nolock(inode, ACL_TYPE_ACCESS, di_bh); 315 316 brelse(di_bh); 317 318 if (IS_ERR(acl)) { 319 mlog_errno(PTR_ERR(acl)); 320 return PTR_ERR(acl); 321 } 322 if (acl) { 323 ret = posix_acl_permission(inode, acl, mask); 324 posix_acl_release(acl); 325 return ret; 326 } 327 328 return -EAGAIN; 329 } 330 331 int ocfs2_acl_chmod(struct inode *inode) 332 { 333 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 334 struct posix_acl *acl, *clone; 335 int ret; 336 337 if (S_ISLNK(inode->i_mode)) 338 return -EOPNOTSUPP; 339 340 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 341 return 0; 342 343 acl = ocfs2_get_acl(inode, ACL_TYPE_ACCESS); 344 if (IS_ERR(acl) || !acl) 345 return PTR_ERR(acl); 346 clone = posix_acl_clone(acl, GFP_KERNEL); 347 posix_acl_release(acl); 348 if (!clone) 349 return -ENOMEM; 350 ret = posix_acl_chmod_masq(clone, inode->i_mode); 351 if (!ret) 352 ret = ocfs2_set_acl(NULL, inode, NULL, ACL_TYPE_ACCESS, 353 clone, NULL, NULL); 354 posix_acl_release(clone); 355 return ret; 356 } 357 358 /* 359 * Initialize the ACLs of a new inode. If parent directory has default ACL, 360 * then clone to new inode. Called from ocfs2_mknod. 361 */ 362 int ocfs2_init_acl(handle_t *handle, 363 struct inode *inode, 364 struct inode *dir, 365 struct buffer_head *di_bh, 366 struct buffer_head *dir_bh, 367 struct ocfs2_alloc_context *meta_ac, 368 struct ocfs2_alloc_context *data_ac) 369 { 370 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 371 struct posix_acl *acl = NULL; 372 int ret = 0, ret2; 373 mode_t mode; 374 375 if (!S_ISLNK(inode->i_mode)) { 376 if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) { 377 acl = ocfs2_get_acl_nolock(dir, ACL_TYPE_DEFAULT, 378 dir_bh); 379 if (IS_ERR(acl)) 380 return PTR_ERR(acl); 381 } 382 if (!acl) { 383 mode = inode->i_mode & ~current_umask(); 384 ret = ocfs2_acl_set_mode(inode, di_bh, handle, mode); 385 if (ret) { 386 mlog_errno(ret); 387 goto cleanup; 388 } 389 } 390 } 391 if ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) && acl) { 392 struct posix_acl *clone; 393 394 if (S_ISDIR(inode->i_mode)) { 395 ret = ocfs2_set_acl(handle, inode, di_bh, 396 ACL_TYPE_DEFAULT, acl, 397 meta_ac, data_ac); 398 if (ret) 399 goto cleanup; 400 } 401 clone = posix_acl_clone(acl, GFP_NOFS); 402 ret = -ENOMEM; 403 if (!clone) 404 goto cleanup; 405 406 mode = inode->i_mode; 407 ret = posix_acl_create_masq(clone, &mode); 408 if (ret >= 0) { 409 ret2 = ocfs2_acl_set_mode(inode, di_bh, handle, mode); 410 if (ret2) { 411 mlog_errno(ret2); 412 ret = ret2; 413 goto cleanup; 414 } 415 if (ret > 0) { 416 ret = ocfs2_set_acl(handle, inode, 417 di_bh, ACL_TYPE_ACCESS, 418 clone, meta_ac, data_ac); 419 } 420 } 421 posix_acl_release(clone); 422 } 423 cleanup: 424 posix_acl_release(acl); 425 return ret; 426 } 427 428 static size_t ocfs2_xattr_list_acl_access(struct dentry *dentry, 429 char *list, 430 size_t list_len, 431 const char *name, 432 size_t name_len, 433 int type) 434 { 435 struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb); 436 const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS); 437 438 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 439 return 0; 440 441 if (list && size <= list_len) 442 memcpy(list, POSIX_ACL_XATTR_ACCESS, size); 443 return size; 444 } 445 446 static size_t ocfs2_xattr_list_acl_default(struct dentry *dentry, 447 char *list, 448 size_t list_len, 449 const char *name, 450 size_t name_len, 451 int type) 452 { 453 struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb); 454 const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT); 455 456 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 457 return 0; 458 459 if (list && size <= list_len) 460 memcpy(list, POSIX_ACL_XATTR_DEFAULT, size); 461 return size; 462 } 463 464 static int ocfs2_xattr_get_acl(struct dentry *dentry, const char *name, 465 void *buffer, size_t size, int type) 466 { 467 struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb); 468 struct posix_acl *acl; 469 int ret; 470 471 if (strcmp(name, "") != 0) 472 return -EINVAL; 473 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 474 return -EOPNOTSUPP; 475 476 acl = ocfs2_get_acl(dentry->d_inode, type); 477 if (IS_ERR(acl)) 478 return PTR_ERR(acl); 479 if (acl == NULL) 480 return -ENODATA; 481 ret = posix_acl_to_xattr(acl, buffer, size); 482 posix_acl_release(acl); 483 484 return ret; 485 } 486 487 static int ocfs2_xattr_set_acl(struct dentry *dentry, const char *name, 488 const void *value, size_t size, int flags, int type) 489 { 490 struct inode *inode = dentry->d_inode; 491 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 492 struct posix_acl *acl; 493 int ret = 0; 494 495 if (strcmp(name, "") != 0) 496 return -EINVAL; 497 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 498 return -EOPNOTSUPP; 499 500 if (!is_owner_or_cap(inode)) 501 return -EPERM; 502 503 if (value) { 504 acl = posix_acl_from_xattr(value, size); 505 if (IS_ERR(acl)) 506 return PTR_ERR(acl); 507 else if (acl) { 508 ret = posix_acl_valid(acl); 509 if (ret) 510 goto cleanup; 511 } 512 } else 513 acl = NULL; 514 515 ret = ocfs2_set_acl(NULL, inode, NULL, type, acl, NULL, NULL); 516 517 cleanup: 518 posix_acl_release(acl); 519 return ret; 520 } 521 522 const struct xattr_handler ocfs2_xattr_acl_access_handler = { 523 .prefix = POSIX_ACL_XATTR_ACCESS, 524 .flags = ACL_TYPE_ACCESS, 525 .list = ocfs2_xattr_list_acl_access, 526 .get = ocfs2_xattr_get_acl, 527 .set = ocfs2_xattr_set_acl, 528 }; 529 530 const struct xattr_handler ocfs2_xattr_acl_default_handler = { 531 .prefix = POSIX_ACL_XATTR_DEFAULT, 532 .flags = ACL_TYPE_DEFAULT, 533 .list = ocfs2_xattr_list_acl_default, 534 .get = ocfs2_xattr_get_acl, 535 .set = ocfs2_xattr_set_acl, 536 }; 537