at v3.7 184 lines 4.0 kB view raw
1/* 2 * (C) 2005 Andreas Gruenbacher <agruen@suse.de> 3 * 4 * This file is released under the GPL. 5 * 6 * Generic ACL support for in-memory filesystems. 7 */ 8 9#include <linux/sched.h> 10#include <linux/gfp.h> 11#include <linux/fs.h> 12#include <linux/generic_acl.h> 13#include <linux/posix_acl.h> 14#include <linux/posix_acl_xattr.h> 15 16 17static size_t 18generic_acl_list(struct dentry *dentry, char *list, size_t list_size, 19 const char *name, size_t name_len, int type) 20{ 21 struct posix_acl *acl; 22 const char *xname; 23 size_t size; 24 25 acl = get_cached_acl(dentry->d_inode, type); 26 if (!acl) 27 return 0; 28 posix_acl_release(acl); 29 30 switch (type) { 31 case ACL_TYPE_ACCESS: 32 xname = POSIX_ACL_XATTR_ACCESS; 33 break; 34 case ACL_TYPE_DEFAULT: 35 xname = POSIX_ACL_XATTR_DEFAULT; 36 break; 37 default: 38 return 0; 39 } 40 size = strlen(xname) + 1; 41 if (list && size <= list_size) 42 memcpy(list, xname, size); 43 return size; 44} 45 46static int 47generic_acl_get(struct dentry *dentry, const char *name, void *buffer, 48 size_t size, int type) 49{ 50 struct posix_acl *acl; 51 int error; 52 53 if (strcmp(name, "") != 0) 54 return -EINVAL; 55 56 acl = get_cached_acl(dentry->d_inode, type); 57 if (!acl) 58 return -ENODATA; 59 error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); 60 posix_acl_release(acl); 61 62 return error; 63} 64 65static int 66generic_acl_set(struct dentry *dentry, const char *name, const void *value, 67 size_t size, int flags, int type) 68{ 69 struct inode *inode = dentry->d_inode; 70 struct posix_acl *acl = NULL; 71 int error; 72 73 if (strcmp(name, "") != 0) 74 return -EINVAL; 75 if (S_ISLNK(inode->i_mode)) 76 return -EOPNOTSUPP; 77 if (!inode_owner_or_capable(inode)) 78 return -EPERM; 79 if (value) { 80 acl = posix_acl_from_xattr(&init_user_ns, value, size); 81 if (IS_ERR(acl)) 82 return PTR_ERR(acl); 83 } 84 if (acl) { 85 error = posix_acl_valid(acl); 86 if (error) 87 goto failed; 88 switch (type) { 89 case ACL_TYPE_ACCESS: 90 error = posix_acl_equiv_mode(acl, &inode->i_mode); 91 if (error < 0) 92 goto failed; 93 inode->i_ctime = CURRENT_TIME; 94 if (error == 0) { 95 posix_acl_release(acl); 96 acl = NULL; 97 } 98 break; 99 case ACL_TYPE_DEFAULT: 100 if (!S_ISDIR(inode->i_mode)) { 101 error = -EINVAL; 102 goto failed; 103 } 104 break; 105 } 106 } 107 set_cached_acl(inode, type, acl); 108 error = 0; 109failed: 110 posix_acl_release(acl); 111 return error; 112} 113 114/** 115 * generic_acl_init - Take care of acl inheritance at @inode create time 116 * 117 * Files created inside a directory with a default ACL inherit the 118 * directory's default ACL. 119 */ 120int 121generic_acl_init(struct inode *inode, struct inode *dir) 122{ 123 struct posix_acl *acl = NULL; 124 int error; 125 126 if (!S_ISLNK(inode->i_mode)) 127 acl = get_cached_acl(dir, ACL_TYPE_DEFAULT); 128 if (acl) { 129 if (S_ISDIR(inode->i_mode)) 130 set_cached_acl(inode, ACL_TYPE_DEFAULT, acl); 131 error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); 132 if (error < 0) 133 return error; 134 if (error > 0) 135 set_cached_acl(inode, ACL_TYPE_ACCESS, acl); 136 } else { 137 inode->i_mode &= ~current_umask(); 138 } 139 error = 0; 140 141 posix_acl_release(acl); 142 return error; 143} 144 145/** 146 * generic_acl_chmod - change the access acl of @inode upon chmod() 147 * 148 * A chmod also changes the permissions of the owner, group/mask, and 149 * other ACL entries. 150 */ 151int 152generic_acl_chmod(struct inode *inode) 153{ 154 struct posix_acl *acl; 155 int error = 0; 156 157 if (S_ISLNK(inode->i_mode)) 158 return -EOPNOTSUPP; 159 acl = get_cached_acl(inode, ACL_TYPE_ACCESS); 160 if (acl) { 161 error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); 162 if (error) 163 return error; 164 set_cached_acl(inode, ACL_TYPE_ACCESS, acl); 165 posix_acl_release(acl); 166 } 167 return error; 168} 169 170const struct xattr_handler generic_acl_access_handler = { 171 .prefix = POSIX_ACL_XATTR_ACCESS, 172 .flags = ACL_TYPE_ACCESS, 173 .list = generic_acl_list, 174 .get = generic_acl_get, 175 .set = generic_acl_set, 176}; 177 178const struct xattr_handler generic_acl_default_handler = { 179 .prefix = POSIX_ACL_XATTR_DEFAULT, 180 .flags = ACL_TYPE_DEFAULT, 181 .list = generic_acl_list, 182 .get = generic_acl_get, 183 .set = generic_acl_set, 184};