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