1 /* 2 * Copyright (c) 2008, Christoph Hellwig 3 * All Rights Reserved. 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it would be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write the Free Software Foundation, 16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 #include "xfs.h" 19 #include "xfs_format.h" 20 #include "xfs_log_format.h" 21 #include "xfs_trans_resv.h" 22 #include "xfs_ag.h" 23 #include "xfs_sb.h" 24 #include "xfs_mount.h" 25 #include "xfs_inode.h" 26 #include "xfs_acl.h" 27 #include "xfs_attr.h" 28 #include "xfs_trace.h" 29 #include <linux/slab.h> 30 #include <linux/xattr.h> 31 #include <linux/posix_acl_xattr.h> 32 33 34 /* 35 * Locking scheme: 36 * - all ACL updates are protected by inode->i_mutex, which is taken before 37 * calling into this file. 38 */ 39 40 STATIC struct posix_acl * 41 xfs_acl_from_disk( 42 struct xfs_acl *aclp, 43 int max_entries) 44 { 45 struct posix_acl_entry *acl_e; 46 struct posix_acl *acl; 47 struct xfs_acl_entry *ace; 48 unsigned int count, i; 49 50 count = be32_to_cpu(aclp->acl_cnt); 51 if (count > max_entries) 52 return ERR_PTR(-EFSCORRUPTED); 53 54 acl = posix_acl_alloc(count, GFP_KERNEL); 55 if (!acl) 56 return ERR_PTR(-ENOMEM); 57 58 for (i = 0; i < count; i++) { 59 acl_e = &acl->a_entries[i]; 60 ace = &aclp->acl_entry[i]; 61 62 /* 63 * The tag is 32 bits on disk and 16 bits in core. 64 * 65 * Because every access to it goes through the core 66 * format first this is not a problem. 67 */ 68 acl_e->e_tag = be32_to_cpu(ace->ae_tag); 69 acl_e->e_perm = be16_to_cpu(ace->ae_perm); 70 71 switch (acl_e->e_tag) { 72 case ACL_USER: 73 acl_e->e_uid = xfs_uid_to_kuid(be32_to_cpu(ace->ae_id)); 74 break; 75 case ACL_GROUP: 76 acl_e->e_gid = xfs_gid_to_kgid(be32_to_cpu(ace->ae_id)); 77 break; 78 case ACL_USER_OBJ: 79 case ACL_GROUP_OBJ: 80 case ACL_MASK: 81 case ACL_OTHER: 82 break; 83 default: 84 goto fail; 85 } 86 } 87 return acl; 88 89 fail: 90 posix_acl_release(acl); 91 return ERR_PTR(-EINVAL); 92 } 93 94 STATIC void 95 xfs_acl_to_disk(struct xfs_acl *aclp, const struct posix_acl *acl) 96 { 97 const struct posix_acl_entry *acl_e; 98 struct xfs_acl_entry *ace; 99 int i; 100 101 aclp->acl_cnt = cpu_to_be32(acl->a_count); 102 for (i = 0; i < acl->a_count; i++) { 103 ace = &aclp->acl_entry[i]; 104 acl_e = &acl->a_entries[i]; 105 106 ace->ae_tag = cpu_to_be32(acl_e->e_tag); 107 switch (acl_e->e_tag) { 108 case ACL_USER: 109 ace->ae_id = cpu_to_be32(xfs_kuid_to_uid(acl_e->e_uid)); 110 break; 111 case ACL_GROUP: 112 ace->ae_id = cpu_to_be32(xfs_kgid_to_gid(acl_e->e_gid)); 113 break; 114 default: 115 ace->ae_id = cpu_to_be32(ACL_UNDEFINED_ID); 116 break; 117 } 118 119 ace->ae_perm = cpu_to_be16(acl_e->e_perm); 120 } 121 } 122 123 struct posix_acl * 124 xfs_get_acl(struct inode *inode, int type) 125 { 126 struct xfs_inode *ip = XFS_I(inode); 127 struct posix_acl *acl = NULL; 128 struct xfs_acl *xfs_acl; 129 unsigned char *ea_name; 130 int error; 131 int len; 132 133 trace_xfs_get_acl(ip); 134 135 switch (type) { 136 case ACL_TYPE_ACCESS: 137 ea_name = SGI_ACL_FILE; 138 break; 139 case ACL_TYPE_DEFAULT: 140 ea_name = SGI_ACL_DEFAULT; 141 break; 142 default: 143 BUG(); 144 } 145 146 /* 147 * If we have a cached ACLs value just return it, not need to 148 * go out to the disk. 149 */ 150 len = XFS_ACL_MAX_SIZE(ip->i_mount); 151 xfs_acl = kmem_zalloc_large(len, KM_SLEEP); 152 if (!xfs_acl) 153 return ERR_PTR(-ENOMEM); 154 155 error = xfs_attr_get(ip, ea_name, (unsigned char *)xfs_acl, 156 &len, ATTR_ROOT); 157 if (error) { 158 /* 159 * If the attribute doesn't exist make sure we have a negative 160 * cache entry, for any other error assume it is transient and 161 * leave the cache entry as ACL_NOT_CACHED. 162 */ 163 if (error == -ENOATTR) 164 goto out_update_cache; 165 goto out; 166 } 167 168 acl = xfs_acl_from_disk(xfs_acl, XFS_ACL_MAX_ENTRIES(ip->i_mount)); 169 if (IS_ERR(acl)) 170 goto out; 171 172 out_update_cache: 173 set_cached_acl(inode, type, acl); 174 out: 175 kmem_free(xfs_acl); 176 return acl; 177 } 178 179 STATIC int 180 __xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) 181 { 182 struct xfs_inode *ip = XFS_I(inode); 183 unsigned char *ea_name; 184 int error; 185 186 switch (type) { 187 case ACL_TYPE_ACCESS: 188 ea_name = SGI_ACL_FILE; 189 break; 190 case ACL_TYPE_DEFAULT: 191 if (!S_ISDIR(inode->i_mode)) 192 return acl ? -EACCES : 0; 193 ea_name = SGI_ACL_DEFAULT; 194 break; 195 default: 196 return -EINVAL; 197 } 198 199 if (acl) { 200 struct xfs_acl *xfs_acl; 201 int len = XFS_ACL_MAX_SIZE(ip->i_mount); 202 203 xfs_acl = kmem_zalloc_large(len, KM_SLEEP); 204 if (!xfs_acl) 205 return -ENOMEM; 206 207 xfs_acl_to_disk(xfs_acl, acl); 208 209 /* subtract away the unused acl entries */ 210 len -= sizeof(struct xfs_acl_entry) * 211 (XFS_ACL_MAX_ENTRIES(ip->i_mount) - acl->a_count); 212 213 error = xfs_attr_set(ip, ea_name, (unsigned char *)xfs_acl, 214 len, ATTR_ROOT); 215 216 kmem_free(xfs_acl); 217 } else { 218 /* 219 * A NULL ACL argument means we want to remove the ACL. 220 */ 221 error = xfs_attr_remove(ip, ea_name, ATTR_ROOT); 222 223 /* 224 * If the attribute didn't exist to start with that's fine. 225 */ 226 if (error == -ENOATTR) 227 error = 0; 228 } 229 230 if (!error) 231 set_cached_acl(inode, type, acl); 232 return error; 233 } 234 235 static int 236 xfs_set_mode(struct inode *inode, umode_t mode) 237 { 238 int error = 0; 239 240 if (mode != inode->i_mode) { 241 struct iattr iattr; 242 243 iattr.ia_valid = ATTR_MODE | ATTR_CTIME; 244 iattr.ia_mode = mode; 245 iattr.ia_ctime = current_fs_time(inode->i_sb); 246 247 error = xfs_setattr_nonsize(XFS_I(inode), &iattr, XFS_ATTR_NOACL); 248 } 249 250 return error; 251 } 252 253 static int 254 xfs_acl_exists(struct inode *inode, unsigned char *name) 255 { 256 int len = XFS_ACL_MAX_SIZE(XFS_M(inode->i_sb)); 257 258 return (xfs_attr_get(XFS_I(inode), name, NULL, &len, 259 ATTR_ROOT|ATTR_KERNOVAL) == 0); 260 } 261 262 int 263 posix_acl_access_exists(struct inode *inode) 264 { 265 return xfs_acl_exists(inode, SGI_ACL_FILE); 266 } 267 268 int 269 posix_acl_default_exists(struct inode *inode) 270 { 271 if (!S_ISDIR(inode->i_mode)) 272 return 0; 273 return xfs_acl_exists(inode, SGI_ACL_DEFAULT); 274 } 275 276 int 277 xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) 278 { 279 int error = 0; 280 281 if (!acl) 282 goto set_acl; 283 284 error = -E2BIG; 285 if (acl->a_count > XFS_ACL_MAX_ENTRIES(XFS_M(inode->i_sb))) 286 return error; 287 288 if (type == ACL_TYPE_ACCESS) { 289 umode_t mode = inode->i_mode; 290 error = posix_acl_equiv_mode(acl, &mode); 291 292 if (error <= 0) { 293 acl = NULL; 294 295 if (error < 0) 296 return error; 297 } 298 299 error = xfs_set_mode(inode, mode); 300 if (error) 301 return error; 302 } 303 304 set_acl: 305 return __xfs_set_acl(inode, type, acl); 306 } 307