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 int name_index; 102 char *value = NULL; 103 struct posix_acl *acl; 104 int retval; 105 106 switch (type) { 107 case ACL_TYPE_ACCESS: 108 name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS; 109 break; 110 case ACL_TYPE_DEFAULT: 111 name_index = OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT; 112 break; 113 default: 114 return ERR_PTR(-EINVAL); 115 } 116 117 retval = ocfs2_xattr_get_nolock(inode, di_bh, name_index, "", NULL, 0); 118 if (retval > 0) { 119 value = kmalloc(retval, GFP_NOFS); 120 if (!value) 121 return ERR_PTR(-ENOMEM); 122 retval = ocfs2_xattr_get_nolock(inode, di_bh, name_index, 123 "", value, retval); 124 } 125 126 if (retval > 0) 127 acl = ocfs2_acl_from_xattr(value, retval); 128 else if (retval == -ENODATA || retval == 0) 129 acl = NULL; 130 else 131 acl = ERR_PTR(retval); 132 133 kfree(value); 134 135 return acl; 136 } 137 138 139 /* 140 * Get posix acl. 141 */ 142 static struct posix_acl *ocfs2_get_acl(struct inode *inode, int type) 143 { 144 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 145 struct buffer_head *di_bh = NULL; 146 struct posix_acl *acl; 147 int ret; 148 149 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 150 return NULL; 151 152 ret = ocfs2_inode_lock(inode, &di_bh, 0); 153 if (ret < 0) { 154 mlog_errno(ret); 155 acl = ERR_PTR(ret); 156 return acl; 157 } 158 159 acl = ocfs2_get_acl_nolock(inode, type, di_bh); 160 161 ocfs2_inode_unlock(inode, 0); 162 163 brelse(di_bh); 164 165 return acl; 166 } 167 168 /* 169 * Set the access or default ACL of an inode. 170 */ 171 static int ocfs2_set_acl(handle_t *handle, 172 struct inode *inode, 173 struct buffer_head *di_bh, 174 int type, 175 struct posix_acl *acl, 176 struct ocfs2_alloc_context *meta_ac, 177 struct ocfs2_alloc_context *data_ac) 178 { 179 int name_index; 180 void *value = NULL; 181 size_t size = 0; 182 int ret; 183 184 if (S_ISLNK(inode->i_mode)) 185 return -EOPNOTSUPP; 186 187 switch (type) { 188 case ACL_TYPE_ACCESS: 189 name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS; 190 if (acl) { 191 mode_t mode = inode->i_mode; 192 ret = posix_acl_equiv_mode(acl, &mode); 193 if (ret < 0) 194 return ret; 195 else { 196 inode->i_mode = mode; 197 if (ret == 0) 198 acl = NULL; 199 } 200 } 201 break; 202 case ACL_TYPE_DEFAULT: 203 name_index = OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT; 204 if (!S_ISDIR(inode->i_mode)) 205 return acl ? -EACCES : 0; 206 break; 207 default: 208 return -EINVAL; 209 } 210 211 if (acl) { 212 value = ocfs2_acl_to_xattr(acl, &size); 213 if (IS_ERR(value)) 214 return (int)PTR_ERR(value); 215 } 216 217 if (handle) 218 ret = ocfs2_xattr_set_handle(handle, inode, di_bh, name_index, 219 "", value, size, 0, 220 meta_ac, data_ac); 221 else 222 ret = ocfs2_xattr_set(inode, name_index, "", value, size, 0); 223 224 kfree(value); 225 226 return ret; 227 } 228 229 int ocfs2_check_acl(struct inode *inode, int mask) 230 { 231 struct posix_acl *acl = ocfs2_get_acl(inode, ACL_TYPE_ACCESS); 232 233 if (IS_ERR(acl)) 234 return PTR_ERR(acl); 235 if (acl) { 236 int ret = posix_acl_permission(inode, acl, mask); 237 posix_acl_release(acl); 238 return ret; 239 } 240 241 return -EAGAIN; 242 } 243 244 int ocfs2_acl_chmod(struct inode *inode) 245 { 246 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 247 struct posix_acl *acl, *clone; 248 int ret; 249 250 if (S_ISLNK(inode->i_mode)) 251 return -EOPNOTSUPP; 252 253 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 254 return 0; 255 256 acl = ocfs2_get_acl(inode, ACL_TYPE_ACCESS); 257 if (IS_ERR(acl) || !acl) 258 return PTR_ERR(acl); 259 clone = posix_acl_clone(acl, GFP_KERNEL); 260 posix_acl_release(acl); 261 if (!clone) 262 return -ENOMEM; 263 ret = posix_acl_chmod_masq(clone, inode->i_mode); 264 if (!ret) 265 ret = ocfs2_set_acl(NULL, inode, NULL, ACL_TYPE_ACCESS, 266 clone, NULL, NULL); 267 posix_acl_release(clone); 268 return ret; 269 } 270 271 /* 272 * Initialize the ACLs of a new inode. If parent directory has default ACL, 273 * then clone to new inode. Called from ocfs2_mknod. 274 */ 275 int ocfs2_init_acl(handle_t *handle, 276 struct inode *inode, 277 struct inode *dir, 278 struct buffer_head *di_bh, 279 struct buffer_head *dir_bh, 280 struct ocfs2_alloc_context *meta_ac, 281 struct ocfs2_alloc_context *data_ac) 282 { 283 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 284 struct posix_acl *acl = NULL; 285 int ret = 0; 286 287 if (!S_ISLNK(inode->i_mode)) { 288 if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) { 289 acl = ocfs2_get_acl_nolock(dir, ACL_TYPE_DEFAULT, 290 dir_bh); 291 if (IS_ERR(acl)) 292 return PTR_ERR(acl); 293 } 294 if (!acl) 295 inode->i_mode &= ~current_umask(); 296 } 297 if ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) && acl) { 298 struct posix_acl *clone; 299 mode_t mode; 300 301 if (S_ISDIR(inode->i_mode)) { 302 ret = ocfs2_set_acl(handle, inode, di_bh, 303 ACL_TYPE_DEFAULT, acl, 304 meta_ac, data_ac); 305 if (ret) 306 goto cleanup; 307 } 308 clone = posix_acl_clone(acl, GFP_NOFS); 309 ret = -ENOMEM; 310 if (!clone) 311 goto cleanup; 312 313 mode = inode->i_mode; 314 ret = posix_acl_create_masq(clone, &mode); 315 if (ret >= 0) { 316 inode->i_mode = mode; 317 if (ret > 0) { 318 ret = ocfs2_set_acl(handle, inode, 319 di_bh, ACL_TYPE_ACCESS, 320 clone, meta_ac, data_ac); 321 } 322 } 323 posix_acl_release(clone); 324 } 325 cleanup: 326 posix_acl_release(acl); 327 return ret; 328 } 329 330 static size_t ocfs2_xattr_list_acl_access(struct dentry *dentry, 331 char *list, 332 size_t list_len, 333 const char *name, 334 size_t name_len, 335 int type) 336 { 337 struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb); 338 const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS); 339 340 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 341 return 0; 342 343 if (list && size <= list_len) 344 memcpy(list, POSIX_ACL_XATTR_ACCESS, size); 345 return size; 346 } 347 348 static size_t ocfs2_xattr_list_acl_default(struct dentry *dentry, 349 char *list, 350 size_t list_len, 351 const char *name, 352 size_t name_len, 353 int type) 354 { 355 struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb); 356 const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT); 357 358 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 359 return 0; 360 361 if (list && size <= list_len) 362 memcpy(list, POSIX_ACL_XATTR_DEFAULT, size); 363 return size; 364 } 365 366 static int ocfs2_xattr_get_acl(struct dentry *dentry, const char *name, 367 void *buffer, size_t size, int type) 368 { 369 struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb); 370 struct posix_acl *acl; 371 int ret; 372 373 if (strcmp(name, "") != 0) 374 return -EINVAL; 375 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 376 return -EOPNOTSUPP; 377 378 acl = ocfs2_get_acl(dentry->d_inode, type); 379 if (IS_ERR(acl)) 380 return PTR_ERR(acl); 381 if (acl == NULL) 382 return -ENODATA; 383 ret = posix_acl_to_xattr(acl, buffer, size); 384 posix_acl_release(acl); 385 386 return ret; 387 } 388 389 static int ocfs2_xattr_set_acl(struct dentry *dentry, const char *name, 390 const void *value, size_t size, int flags, int type) 391 { 392 struct inode *inode = dentry->d_inode; 393 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 394 struct posix_acl *acl; 395 int ret = 0; 396 397 if (strcmp(name, "") != 0) 398 return -EINVAL; 399 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 400 return -EOPNOTSUPP; 401 402 if (!is_owner_or_cap(inode)) 403 return -EPERM; 404 405 if (value) { 406 acl = posix_acl_from_xattr(value, size); 407 if (IS_ERR(acl)) 408 return PTR_ERR(acl); 409 else if (acl) { 410 ret = posix_acl_valid(acl); 411 if (ret) 412 goto cleanup; 413 } 414 } else 415 acl = NULL; 416 417 ret = ocfs2_set_acl(NULL, inode, NULL, type, acl, NULL, NULL); 418 419 cleanup: 420 posix_acl_release(acl); 421 return ret; 422 } 423 424 struct xattr_handler ocfs2_xattr_acl_access_handler = { 425 .prefix = POSIX_ACL_XATTR_ACCESS, 426 .flags = ACL_TYPE_ACCESS, 427 .list = ocfs2_xattr_list_acl_access, 428 .get = ocfs2_xattr_get_acl, 429 .set = ocfs2_xattr_set_acl, 430 }; 431 432 struct xattr_handler ocfs2_xattr_acl_default_handler = { 433 .prefix = POSIX_ACL_XATTR_DEFAULT, 434 .flags = ACL_TYPE_DEFAULT, 435 .list = ocfs2_xattr_list_acl_default, 436 .get = ocfs2_xattr_get_acl, 437 .set = ocfs2_xattr_set_acl, 438 }; 439