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) 295 { 296 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 297 struct buffer_head *di_bh = NULL; 298 struct posix_acl *acl; 299 int ret = -EAGAIN; 300 301 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 302 return ret; 303 304 ret = ocfs2_read_inode_block(inode, &di_bh); 305 if (ret < 0) { 306 mlog_errno(ret); 307 return ret; 308 } 309 310 acl = ocfs2_get_acl_nolock(inode, ACL_TYPE_ACCESS, di_bh); 311 312 brelse(di_bh); 313 314 if (IS_ERR(acl)) { 315 mlog_errno(PTR_ERR(acl)); 316 return PTR_ERR(acl); 317 } 318 if (acl) { 319 ret = posix_acl_permission(inode, acl, mask); 320 posix_acl_release(acl); 321 return ret; 322 } 323 324 return -EAGAIN; 325 } 326 327 int ocfs2_acl_chmod(struct inode *inode) 328 { 329 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 330 struct posix_acl *acl, *clone; 331 int ret; 332 333 if (S_ISLNK(inode->i_mode)) 334 return -EOPNOTSUPP; 335 336 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 337 return 0; 338 339 acl = ocfs2_get_acl(inode, ACL_TYPE_ACCESS); 340 if (IS_ERR(acl) || !acl) 341 return PTR_ERR(acl); 342 clone = posix_acl_clone(acl, GFP_KERNEL); 343 posix_acl_release(acl); 344 if (!clone) 345 return -ENOMEM; 346 ret = posix_acl_chmod_masq(clone, inode->i_mode); 347 if (!ret) 348 ret = ocfs2_set_acl(NULL, inode, NULL, ACL_TYPE_ACCESS, 349 clone, NULL, NULL); 350 posix_acl_release(clone); 351 return ret; 352 } 353 354 /* 355 * Initialize the ACLs of a new inode. If parent directory has default ACL, 356 * then clone to new inode. Called from ocfs2_mknod. 357 */ 358 int ocfs2_init_acl(handle_t *handle, 359 struct inode *inode, 360 struct inode *dir, 361 struct buffer_head *di_bh, 362 struct buffer_head *dir_bh, 363 struct ocfs2_alloc_context *meta_ac, 364 struct ocfs2_alloc_context *data_ac) 365 { 366 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 367 struct posix_acl *acl = NULL; 368 int ret = 0, ret2; 369 mode_t mode; 370 371 if (!S_ISLNK(inode->i_mode)) { 372 if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) { 373 acl = ocfs2_get_acl_nolock(dir, ACL_TYPE_DEFAULT, 374 dir_bh); 375 if (IS_ERR(acl)) 376 return PTR_ERR(acl); 377 } 378 if (!acl) { 379 mode = inode->i_mode & ~current_umask(); 380 ret = ocfs2_acl_set_mode(inode, di_bh, handle, mode); 381 if (ret) { 382 mlog_errno(ret); 383 goto cleanup; 384 } 385 } 386 } 387 if ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) && acl) { 388 struct posix_acl *clone; 389 390 if (S_ISDIR(inode->i_mode)) { 391 ret = ocfs2_set_acl(handle, inode, di_bh, 392 ACL_TYPE_DEFAULT, acl, 393 meta_ac, data_ac); 394 if (ret) 395 goto cleanup; 396 } 397 clone = posix_acl_clone(acl, GFP_NOFS); 398 ret = -ENOMEM; 399 if (!clone) 400 goto cleanup; 401 402 mode = inode->i_mode; 403 ret = posix_acl_create_masq(clone, &mode); 404 if (ret >= 0) { 405 ret2 = ocfs2_acl_set_mode(inode, di_bh, handle, mode); 406 if (ret2) { 407 mlog_errno(ret2); 408 ret = ret2; 409 goto cleanup; 410 } 411 if (ret > 0) { 412 ret = ocfs2_set_acl(handle, inode, 413 di_bh, ACL_TYPE_ACCESS, 414 clone, meta_ac, data_ac); 415 } 416 } 417 posix_acl_release(clone); 418 } 419 cleanup: 420 posix_acl_release(acl); 421 return ret; 422 } 423 424 static size_t ocfs2_xattr_list_acl_access(struct dentry *dentry, 425 char *list, 426 size_t list_len, 427 const char *name, 428 size_t name_len, 429 int type) 430 { 431 struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb); 432 const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS); 433 434 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 435 return 0; 436 437 if (list && size <= list_len) 438 memcpy(list, POSIX_ACL_XATTR_ACCESS, size); 439 return size; 440 } 441 442 static size_t ocfs2_xattr_list_acl_default(struct dentry *dentry, 443 char *list, 444 size_t list_len, 445 const char *name, 446 size_t name_len, 447 int type) 448 { 449 struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb); 450 const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT); 451 452 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 453 return 0; 454 455 if (list && size <= list_len) 456 memcpy(list, POSIX_ACL_XATTR_DEFAULT, size); 457 return size; 458 } 459 460 static int ocfs2_xattr_get_acl(struct dentry *dentry, const char *name, 461 void *buffer, size_t size, int type) 462 { 463 struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb); 464 struct posix_acl *acl; 465 int ret; 466 467 if (strcmp(name, "") != 0) 468 return -EINVAL; 469 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 470 return -EOPNOTSUPP; 471 472 acl = ocfs2_get_acl(dentry->d_inode, type); 473 if (IS_ERR(acl)) 474 return PTR_ERR(acl); 475 if (acl == NULL) 476 return -ENODATA; 477 ret = posix_acl_to_xattr(acl, buffer, size); 478 posix_acl_release(acl); 479 480 return ret; 481 } 482 483 static int ocfs2_xattr_set_acl(struct dentry *dentry, const char *name, 484 const void *value, size_t size, int flags, int type) 485 { 486 struct inode *inode = dentry->d_inode; 487 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 488 struct posix_acl *acl; 489 int ret = 0; 490 491 if (strcmp(name, "") != 0) 492 return -EINVAL; 493 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 494 return -EOPNOTSUPP; 495 496 if (!is_owner_or_cap(inode)) 497 return -EPERM; 498 499 if (value) { 500 acl = posix_acl_from_xattr(value, size); 501 if (IS_ERR(acl)) 502 return PTR_ERR(acl); 503 else if (acl) { 504 ret = posix_acl_valid(acl); 505 if (ret) 506 goto cleanup; 507 } 508 } else 509 acl = NULL; 510 511 ret = ocfs2_set_acl(NULL, inode, NULL, type, acl, NULL, NULL); 512 513 cleanup: 514 posix_acl_release(acl); 515 return ret; 516 } 517 518 const struct xattr_handler ocfs2_xattr_acl_access_handler = { 519 .prefix = POSIX_ACL_XATTR_ACCESS, 520 .flags = ACL_TYPE_ACCESS, 521 .list = ocfs2_xattr_list_acl_access, 522 .get = ocfs2_xattr_get_acl, 523 .set = ocfs2_xattr_set_acl, 524 }; 525 526 const struct xattr_handler ocfs2_xattr_acl_default_handler = { 527 .prefix = POSIX_ACL_XATTR_DEFAULT, 528 .flags = ACL_TYPE_DEFAULT, 529 .list = ocfs2_xattr_list_acl_default, 530 .get = ocfs2_xattr_get_acl, 531 .set = ocfs2_xattr_set_acl, 532 }; 533