Blame view
fs/xfs/xfs_acl.c
8.71 KB
ef14f0c15 xfs: use generic ... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/* * Copyright (c) 2008, Christoph Hellwig * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "xfs.h" #include "xfs_acl.h" #include "xfs_attr.h" #include "xfs_bmap_btree.h" #include "xfs_inode.h" #include "xfs_vnodeops.h" |
0b1b213fc xfs: event tracin... |
24 |
#include "xfs_trace.h" |
5a0e3ad6a include cleanup: ... |
25 |
#include <linux/slab.h> |
ef14f0c15 xfs: use generic ... |
26 27 |
#include <linux/xattr.h> #include <linux/posix_acl_xattr.h> |
ef14f0c15 xfs: use generic ... |
28 29 30 31 |
/* * Locking scheme: * - all ACL updates are protected by inode->i_mutex, which is taken before * calling into this file. |
ef14f0c15 xfs: use generic ... |
32 33 34 35 36 37 38 39 |
*/ STATIC struct posix_acl * xfs_acl_from_disk(struct xfs_acl *aclp) { struct posix_acl_entry *acl_e; struct posix_acl *acl; struct xfs_acl_entry *ace; |
093019cf1 xfs: fix acl coun... |
40 |
unsigned int count, i; |
ef14f0c15 xfs: use generic ... |
41 42 |
count = be32_to_cpu(aclp->acl_cnt); |
fa8b18edd xfs: validate acl... |
43 44 |
if (count > XFS_ACL_MAX_ENTRIES) return ERR_PTR(-EFSCORRUPTED); |
ef14f0c15 xfs: use generic ... |
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
acl = posix_acl_alloc(count, GFP_KERNEL); if (!acl) return ERR_PTR(-ENOMEM); for (i = 0; i < count; i++) { acl_e = &acl->a_entries[i]; ace = &aclp->acl_entry[i]; /* * The tag is 32 bits on disk and 16 bits in core. * * Because every access to it goes through the core * format first this is not a problem. */ acl_e->e_tag = be32_to_cpu(ace->ae_tag); acl_e->e_perm = be16_to_cpu(ace->ae_perm); switch (acl_e->e_tag) { case ACL_USER: case ACL_GROUP: acl_e->e_id = be32_to_cpu(ace->ae_id); break; case ACL_USER_OBJ: case ACL_GROUP_OBJ: case ACL_MASK: case ACL_OTHER: acl_e->e_id = ACL_UNDEFINED_ID; break; default: goto fail; } } return acl; fail: posix_acl_release(acl); return ERR_PTR(-EINVAL); } STATIC void xfs_acl_to_disk(struct xfs_acl *aclp, const struct posix_acl *acl) { const struct posix_acl_entry *acl_e; struct xfs_acl_entry *ace; int i; aclp->acl_cnt = cpu_to_be32(acl->a_count); for (i = 0; i < acl->a_count; i++) { ace = &aclp->acl_entry[i]; acl_e = &acl->a_entries[i]; ace->ae_tag = cpu_to_be32(acl_e->e_tag); ace->ae_id = cpu_to_be32(acl_e->e_id); ace->ae_perm = cpu_to_be16(acl_e->e_perm); } } |
ef14f0c15 xfs: use generic ... |
102 103 104 105 |
struct posix_acl * xfs_get_acl(struct inode *inode, int type) { struct xfs_inode *ip = XFS_I(inode); |
1cbd20d82 switch xfs to gen... |
106 |
struct posix_acl *acl; |
ef14f0c15 xfs: use generic ... |
107 108 |
struct xfs_acl *xfs_acl; int len = sizeof(struct xfs_acl); |
a9273ca5c xfs: convert attr... |
109 |
unsigned char *ea_name; |
ef14f0c15 xfs: use generic ... |
110 |
int error; |
1cbd20d82 switch xfs to gen... |
111 112 113 |
acl = get_cached_acl(inode, type); if (acl != ACL_NOT_CACHED) return acl; |
4e34e719e fs: take the ACL ... |
114 |
trace_xfs_get_acl(ip); |
ef14f0c15 xfs: use generic ... |
115 116 117 |
switch (type) { case ACL_TYPE_ACCESS: ea_name = SGI_ACL_FILE; |
ef14f0c15 xfs: use generic ... |
118 119 120 |
break; case ACL_TYPE_DEFAULT: ea_name = SGI_ACL_DEFAULT; |
ef14f0c15 xfs: use generic ... |
121 122 |
break; default: |
1cbd20d82 switch xfs to gen... |
123 |
BUG(); |
ef14f0c15 xfs: use generic ... |
124 |
} |
ef14f0c15 xfs: use generic ... |
125 126 127 128 |
/* * If we have a cached ACLs value just return it, not need to * go out to the disk. */ |
ef14f0c15 xfs: use generic ... |
129 130 131 132 |
xfs_acl = kzalloc(sizeof(struct xfs_acl), GFP_KERNEL); if (!xfs_acl) return ERR_PTR(-ENOMEM); |
a9273ca5c xfs: convert attr... |
133 134 |
error = -xfs_attr_get(ip, ea_name, (unsigned char *)xfs_acl, &len, ATTR_ROOT); |
ef14f0c15 xfs: use generic ... |
135 136 137 138 |
if (error) { /* * If the attribute doesn't exist make sure we have a negative * cache entry, for any other error assume it is transient and |
1cbd20d82 switch xfs to gen... |
139 |
* leave the cache entry as ACL_NOT_CACHED. |
ef14f0c15 xfs: use generic ... |
140 141 142 143 144 145 146 147 148 149 150 151 152 |
*/ if (error == -ENOATTR) { acl = NULL; goto out_update_cache; } goto out; } acl = xfs_acl_from_disk(xfs_acl); if (IS_ERR(acl)) goto out; out_update_cache: |
1cbd20d82 switch xfs to gen... |
153 |
set_cached_acl(inode, type, acl); |
ef14f0c15 xfs: use generic ... |
154 155 156 157 158 159 160 161 162 |
out: kfree(xfs_acl); return acl; } STATIC int xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) { struct xfs_inode *ip = XFS_I(inode); |
a9273ca5c xfs: convert attr... |
163 |
unsigned char *ea_name; |
ef14f0c15 xfs: use generic ... |
164 165 166 167 168 169 170 171 |
int error; if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; switch (type) { case ACL_TYPE_ACCESS: ea_name = SGI_ACL_FILE; |
ef14f0c15 xfs: use generic ... |
172 173 174 175 176 |
break; case ACL_TYPE_DEFAULT: if (!S_ISDIR(inode->i_mode)) return acl ? -EACCES : 0; ea_name = SGI_ACL_DEFAULT; |
ef14f0c15 xfs: use generic ... |
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
break; default: return -EINVAL; } if (acl) { struct xfs_acl *xfs_acl; int len; xfs_acl = kzalloc(sizeof(struct xfs_acl), GFP_KERNEL); if (!xfs_acl) return -ENOMEM; xfs_acl_to_disk(xfs_acl, acl); len = sizeof(struct xfs_acl) - (sizeof(struct xfs_acl_entry) * (XFS_ACL_MAX_ENTRIES - acl->a_count)); |
a9273ca5c xfs: convert attr... |
194 |
error = -xfs_attr_set(ip, ea_name, (unsigned char *)xfs_acl, |
ef14f0c15 xfs: use generic ... |
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
len, ATTR_ROOT); kfree(xfs_acl); } else { /* * A NULL ACL argument means we want to remove the ACL. */ error = -xfs_attr_remove(ip, ea_name, ATTR_ROOT); /* * If the attribute didn't exist to start with that's fine. */ if (error == -ENOATTR) error = 0; } if (!error) |
1cbd20d82 switch xfs to gen... |
212 |
set_cached_acl(inode, type, acl); |
ef14f0c15 xfs: use generic ... |
213 214 |
return error; } |
ef14f0c15 xfs: use generic ... |
215 |
static int |
d3fb61207 switch posix_acl_... |
216 |
xfs_set_mode(struct inode *inode, umode_t mode) |
ef14f0c15 xfs: use generic ... |
217 218 219 220 221 |
{ int error = 0; if (mode != inode->i_mode) { struct iattr iattr; |
d6d59bada xfs: fix timestam... |
222 |
iattr.ia_valid = ATTR_MODE | ATTR_CTIME; |
ef14f0c15 xfs: use generic ... |
223 |
iattr.ia_mode = mode; |
d6d59bada xfs: fix timestam... |
224 |
iattr.ia_ctime = current_fs_time(inode->i_sb); |
ef14f0c15 xfs: use generic ... |
225 |
|
c4ed4243c xfs: split xfs_se... |
226 |
error = -xfs_setattr_nonsize(XFS_I(inode), &iattr, XFS_ATTR_NOACL); |
ef14f0c15 xfs: use generic ... |
227 228 229 230 231 232 |
} return error; } static int |
a9273ca5c xfs: convert attr... |
233 |
xfs_acl_exists(struct inode *inode, unsigned char *name) |
ef14f0c15 xfs: use generic ... |
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
{ int len = sizeof(struct xfs_acl); return (xfs_attr_get(XFS_I(inode), name, NULL, &len, ATTR_ROOT|ATTR_KERNOVAL) == 0); } int posix_acl_access_exists(struct inode *inode) { return xfs_acl_exists(inode, SGI_ACL_FILE); } int posix_acl_default_exists(struct inode *inode) { if (!S_ISDIR(inode->i_mode)) return 0; return xfs_acl_exists(inode, SGI_ACL_DEFAULT); } /* * No need for i_mutex because the inode is not yet exposed to the VFS. */ int |
826cae2f2 kill boilerplates... |
259 |
xfs_inherit_acl(struct inode *inode, struct posix_acl *acl) |
ef14f0c15 xfs: use generic ... |
260 |
{ |
d3fb61207 switch posix_acl_... |
261 |
umode_t mode = inode->i_mode; |
ef14f0c15 xfs: use generic ... |
262 263 264 |
int error = 0, inherit = 0; if (S_ISDIR(inode->i_mode)) { |
826cae2f2 kill boilerplates... |
265 |
error = xfs_set_acl(inode, ACL_TYPE_DEFAULT, acl); |
ef14f0c15 xfs: use generic ... |
266 |
if (error) |
826cae2f2 kill boilerplates... |
267 |
goto out; |
ef14f0c15 xfs: use generic ... |
268 |
} |
826cae2f2 kill boilerplates... |
269 |
error = posix_acl_create(&acl, GFP_KERNEL, &mode); |
ef14f0c15 xfs: use generic ... |
270 |
if (error < 0) |
826cae2f2 kill boilerplates... |
271 |
return error; |
ef14f0c15 xfs: use generic ... |
272 273 |
/* |
826cae2f2 kill boilerplates... |
274 |
* If posix_acl_create returns a positive value we need to |
ef14f0c15 xfs: use generic ... |
275 276 277 278 279 280 281 282 |
* inherit a permission that can't be represented using the Unix * mode bits and we actually need to set an ACL. */ if (error > 0) inherit = 1; error = xfs_set_mode(inode, mode); if (error) |
826cae2f2 kill boilerplates... |
283 |
goto out; |
ef14f0c15 xfs: use generic ... |
284 285 |
if (inherit) |
826cae2f2 kill boilerplates... |
286 |
error = xfs_set_acl(inode, ACL_TYPE_ACCESS, acl); |
ef14f0c15 xfs: use generic ... |
287 |
|
826cae2f2 kill boilerplates... |
288 289 |
out: posix_acl_release(acl); |
ef14f0c15 xfs: use generic ... |
290 291 292 293 294 295 |
return error; } int xfs_acl_chmod(struct inode *inode) { |
bc26ab5f6 kill boilerplate ... |
296 |
struct posix_acl *acl; |
ef14f0c15 xfs: use generic ... |
297 298 299 300 301 302 303 304 |
int error; if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; acl = xfs_get_acl(inode, ACL_TYPE_ACCESS); if (IS_ERR(acl) || !acl) return PTR_ERR(acl); |
bc26ab5f6 kill boilerplate ... |
305 306 307 |
error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); if (error) return error; |
ef14f0c15 xfs: use generic ... |
308 |
|
bc26ab5f6 kill boilerplate ... |
309 310 |
error = xfs_set_acl(inode, ACL_TYPE_ACCESS, acl); posix_acl_release(acl); |
ef14f0c15 xfs: use generic ... |
311 312 |
return error; } |
ef14f0c15 xfs: use generic ... |
313 |
static int |
431547b3c sanitize xattr ha... |
314 315 |
xfs_xattr_acl_get(struct dentry *dentry, const char *name, void *value, size_t size, int type) |
ef14f0c15 xfs: use generic ... |
316 317 |
{ struct posix_acl *acl; |
431547b3c sanitize xattr ha... |
318 |
int error; |
ef14f0c15 xfs: use generic ... |
319 |
|
431547b3c sanitize xattr ha... |
320 |
acl = xfs_get_acl(dentry->d_inode, type); |
ef14f0c15 xfs: use generic ... |
321 322 323 324 325 326 327 328 329 330 331 332 |
if (IS_ERR(acl)) return PTR_ERR(acl); if (acl == NULL) return -ENODATA; error = posix_acl_to_xattr(acl, value, size); posix_acl_release(acl); return error; } static int |
431547b3c sanitize xattr ha... |
333 334 |
xfs_xattr_acl_set(struct dentry *dentry, const char *name, const void *value, size_t size, int flags, int type) |
ef14f0c15 xfs: use generic ... |
335 |
{ |
431547b3c sanitize xattr ha... |
336 |
struct inode *inode = dentry->d_inode; |
ef14f0c15 xfs: use generic ... |
337 |
struct posix_acl *acl = NULL; |
431547b3c sanitize xattr ha... |
338 |
int error = 0; |
ef14f0c15 xfs: use generic ... |
339 |
|
ef14f0c15 xfs: use generic ... |
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 |
if (flags & XATTR_CREATE) return -EINVAL; if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode)) return value ? -EACCES : 0; if ((current_fsuid() != inode->i_uid) && !capable(CAP_FOWNER)) return -EPERM; if (!value) goto set_acl; acl = posix_acl_from_xattr(value, size); if (!acl) { /* * acl_set_file(3) may request that we set default ACLs with * zero length -- defend (gracefully) against that here. */ goto out; } if (IS_ERR(acl)) { error = PTR_ERR(acl); goto out; } error = posix_acl_valid(acl); if (error) goto out_release; error = -EINVAL; if (acl->a_count > XFS_ACL_MAX_ENTRIES) goto out_release; if (type == ACL_TYPE_ACCESS) { |
d6952123b switch posix_acl_... |
372 |
umode_t mode = inode->i_mode; |
ef14f0c15 xfs: use generic ... |
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 |
error = posix_acl_equiv_mode(acl, &mode); if (error <= 0) { posix_acl_release(acl); acl = NULL; if (error < 0) return error; } error = xfs_set_mode(inode, mode); if (error) goto out_release; } set_acl: error = xfs_set_acl(inode, type, acl); out_release: posix_acl_release(acl); out: return error; } |
46e58764f xfs: constify xat... |
395 |
const struct xattr_handler xfs_xattr_acl_access_handler = { |
431547b3c sanitize xattr ha... |
396 397 398 399 400 |
.prefix = POSIX_ACL_XATTR_ACCESS, .flags = ACL_TYPE_ACCESS, .get = xfs_xattr_acl_get, .set = xfs_xattr_acl_set, }; |
46e58764f xfs: constify xat... |
401 |
const struct xattr_handler xfs_xattr_acl_default_handler = { |
431547b3c sanitize xattr ha... |
402 403 404 405 |
.prefix = POSIX_ACL_XATTR_DEFAULT, .flags = ACL_TYPE_DEFAULT, .get = xfs_xattr_acl_get, .set = xfs_xattr_acl_set, |
ef14f0c15 xfs: use generic ... |
406 |
}; |