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