at v2.6.33-rc2 217 lines 4.6 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/fs.h> 11#include <linux/generic_acl.h> 12#include <linux/posix_acl.h> 13#include <linux/posix_acl_xattr.h> 14 15 16static size_t 17generic_acl_list(struct dentry *dentry, char *list, size_t list_size, 18 const char *name, size_t name_len, int type) 19{ 20 struct posix_acl *acl; 21 const char *xname; 22 size_t size; 23 24 acl = get_cached_acl(dentry->d_inode, type); 25 if (!acl) 26 return 0; 27 posix_acl_release(acl); 28 29 switch (type) { 30 case ACL_TYPE_ACCESS: 31 xname = POSIX_ACL_XATTR_ACCESS; 32 break; 33 case ACL_TYPE_DEFAULT: 34 xname = POSIX_ACL_XATTR_DEFAULT; 35 break; 36 default: 37 return 0; 38 } 39 size = strlen(xname) + 1; 40 if (list && size <= list_size) 41 memcpy(list, xname, size); 42 return size; 43} 44 45static int 46generic_acl_get(struct dentry *dentry, const char *name, void *buffer, 47 size_t size, int type) 48{ 49 struct posix_acl *acl; 50 int error; 51 52 if (strcmp(name, "") != 0) 53 return -EINVAL; 54 55 acl = get_cached_acl(dentry->d_inode, type); 56 if (!acl) 57 return -ENODATA; 58 error = posix_acl_to_xattr(acl, buffer, size); 59 posix_acl_release(acl); 60 61 return error; 62} 63 64static int 65generic_acl_set(struct dentry *dentry, const char *name, const void *value, 66 size_t size, int flags, int type) 67{ 68 struct inode *inode = dentry->d_inode; 69 struct posix_acl *acl = NULL; 70 int error; 71 72 if (strcmp(name, "") != 0) 73 return -EINVAL; 74 if (S_ISLNK(inode->i_mode)) 75 return -EOPNOTSUPP; 76 if (!is_owner_or_cap(inode)) 77 return -EPERM; 78 if (value) { 79 acl = posix_acl_from_xattr(value, size); 80 if (IS_ERR(acl)) 81 return PTR_ERR(acl); 82 } 83 if (acl) { 84 mode_t mode; 85 86 error = posix_acl_valid(acl); 87 if (error) 88 goto failed; 89 switch (type) { 90 case ACL_TYPE_ACCESS: 91 mode = inode->i_mode; 92 error = posix_acl_equiv_mode(acl, &mode); 93 if (error < 0) 94 goto failed; 95 inode->i_mode = mode; 96 if (error == 0) { 97 posix_acl_release(acl); 98 acl = NULL; 99 } 100 break; 101 case ACL_TYPE_DEFAULT: 102 if (!S_ISDIR(inode->i_mode)) { 103 error = -EINVAL; 104 goto failed; 105 } 106 break; 107 } 108 } 109 set_cached_acl(inode, type, acl); 110 error = 0; 111failed: 112 posix_acl_release(acl); 113 return error; 114} 115 116/** 117 * generic_acl_init - Take care of acl inheritance at @inode create time 118 * 119 * Files created inside a directory with a default ACL inherit the 120 * directory's default ACL. 121 */ 122int 123generic_acl_init(struct inode *inode, struct inode *dir) 124{ 125 struct posix_acl *acl = NULL; 126 mode_t mode = inode->i_mode; 127 int error; 128 129 inode->i_mode = mode & ~current_umask(); 130 if (!S_ISLNK(inode->i_mode)) 131 acl = get_cached_acl(dir, ACL_TYPE_DEFAULT); 132 if (acl) { 133 struct posix_acl *clone; 134 135 if (S_ISDIR(inode->i_mode)) { 136 clone = posix_acl_clone(acl, GFP_KERNEL); 137 error = -ENOMEM; 138 if (!clone) 139 goto cleanup; 140 set_cached_acl(inode, ACL_TYPE_DEFAULT, clone); 141 posix_acl_release(clone); 142 } 143 clone = posix_acl_clone(acl, GFP_KERNEL); 144 error = -ENOMEM; 145 if (!clone) 146 goto cleanup; 147 error = posix_acl_create_masq(clone, &mode); 148 if (error >= 0) { 149 inode->i_mode = mode; 150 if (error > 0) 151 set_cached_acl(inode, ACL_TYPE_ACCESS, clone); 152 } 153 posix_acl_release(clone); 154 } 155 error = 0; 156 157cleanup: 158 posix_acl_release(acl); 159 return error; 160} 161 162/** 163 * generic_acl_chmod - change the access acl of @inode upon chmod() 164 * 165 * A chmod also changes the permissions of the owner, group/mask, and 166 * other ACL entries. 167 */ 168int 169generic_acl_chmod(struct inode *inode) 170{ 171 struct posix_acl *acl, *clone; 172 int error = 0; 173 174 if (S_ISLNK(inode->i_mode)) 175 return -EOPNOTSUPP; 176 acl = get_cached_acl(inode, ACL_TYPE_ACCESS); 177 if (acl) { 178 clone = posix_acl_clone(acl, GFP_KERNEL); 179 posix_acl_release(acl); 180 if (!clone) 181 return -ENOMEM; 182 error = posix_acl_chmod_masq(clone, inode->i_mode); 183 if (!error) 184 set_cached_acl(inode, ACL_TYPE_ACCESS, clone); 185 posix_acl_release(clone); 186 } 187 return error; 188} 189 190int 191generic_check_acl(struct inode *inode, int mask) 192{ 193 struct posix_acl *acl = get_cached_acl(inode, ACL_TYPE_ACCESS); 194 195 if (acl) { 196 int error = posix_acl_permission(inode, acl, mask); 197 posix_acl_release(acl); 198 return error; 199 } 200 return -EAGAIN; 201} 202 203struct xattr_handler generic_acl_access_handler = { 204 .prefix = POSIX_ACL_XATTR_ACCESS, 205 .flags = ACL_TYPE_ACCESS, 206 .list = generic_acl_list, 207 .get = generic_acl_get, 208 .set = generic_acl_set, 209}; 210 211struct xattr_handler generic_acl_default_handler = { 212 .prefix = POSIX_ACL_XATTR_DEFAULT, 213 .flags = ACL_TYPE_DEFAULT, 214 .list = generic_acl_list, 215 .get = generic_acl_get, 216 .set = generic_acl_set, 217};