1f9e09f09SLachlan McIlroy /* 2f9e09f09SLachlan McIlroy * Copyright (C) 2008 Christoph Hellwig. 3f9e09f09SLachlan McIlroy * Portions Copyright (C) 2000-2008 Silicon Graphics, Inc. 4f9e09f09SLachlan McIlroy * 5f9e09f09SLachlan McIlroy * This program is free software; you can redistribute it and/or 6f9e09f09SLachlan McIlroy * modify it under the terms of the GNU General Public License as 7f9e09f09SLachlan McIlroy * published by the Free Software Foundation. 8f9e09f09SLachlan McIlroy * 9f9e09f09SLachlan McIlroy * This program is distributed in the hope that it would be useful, 10f9e09f09SLachlan McIlroy * but WITHOUT ANY WARRANTY; without even the implied warranty of 11f9e09f09SLachlan McIlroy * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12f9e09f09SLachlan McIlroy * GNU General Public License for more details. 13f9e09f09SLachlan McIlroy * 14f9e09f09SLachlan McIlroy * You should have received a copy of the GNU General Public License 15f9e09f09SLachlan McIlroy * along with this program; if not, write the Free Software Foundation, 16f9e09f09SLachlan McIlroy * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17f9e09f09SLachlan McIlroy */ 18f9e09f09SLachlan McIlroy 19f9e09f09SLachlan McIlroy #include "xfs.h" 20a4fbe6abSDave Chinner #include "xfs_format.h" 2169432832SDave Chinner #include "xfs_log_format.h" 22239880efSDave Chinner #include "xfs_trans_resv.h" 2357062787SDave Chinner #include "xfs_mount.h" 2457062787SDave Chinner #include "xfs_da_format.h" 25f9e09f09SLachlan McIlroy #include "xfs_inode.h" 26f9e09f09SLachlan McIlroy #include "xfs_attr.h" 27f9e09f09SLachlan McIlroy #include "xfs_attr_leaf.h" 28f9e09f09SLachlan McIlroy #include "xfs_acl.h" 29f9e09f09SLachlan McIlroy 30f9e09f09SLachlan McIlroy #include <linux/posix_acl_xattr.h> 31f9e09f09SLachlan McIlroy #include <linux/xattr.h> 32f9e09f09SLachlan McIlroy 33f9e09f09SLachlan McIlroy 34f9e09f09SLachlan McIlroy static int 35d9a82a04SAndreas Gruenbacher xfs_xattr_get(const struct xattr_handler *handler, struct dentry *dentry, 36d9a82a04SAndreas Gruenbacher const char *name, void *value, size_t size) 37f9e09f09SLachlan McIlroy { 38d9a82a04SAndreas Gruenbacher int xflags = handler->flags; 392b0143b5SDavid Howells struct xfs_inode *ip = XFS_I(d_inode(dentry)); 40f9e09f09SLachlan McIlroy int error, asize = size; 41f9e09f09SLachlan McIlroy 42f9e09f09SLachlan McIlroy if (strcmp(name, "") == 0) 43f9e09f09SLachlan McIlroy return -EINVAL; 44f9e09f09SLachlan McIlroy 45f9e09f09SLachlan McIlroy /* Convert Linux syscall to XFS internal ATTR flags */ 46f9e09f09SLachlan McIlroy if (!size) { 47f9e09f09SLachlan McIlroy xflags |= ATTR_KERNOVAL; 48f9e09f09SLachlan McIlroy value = NULL; 49f9e09f09SLachlan McIlroy } 50f9e09f09SLachlan McIlroy 512451337dSDave Chinner error = xfs_attr_get(ip, (unsigned char *)name, value, &asize, xflags); 52f9e09f09SLachlan McIlroy if (error) 53f9e09f09SLachlan McIlroy return error; 54f9e09f09SLachlan McIlroy return asize; 55f9e09f09SLachlan McIlroy } 56f9e09f09SLachlan McIlroy 5747e1bf64SAndreas Gruenbacher void 5847e1bf64SAndreas Gruenbacher xfs_forget_acl( 5947e1bf64SAndreas Gruenbacher struct inode *inode, 6047e1bf64SAndreas Gruenbacher const char *name, 6147e1bf64SAndreas Gruenbacher int xflags) 6247e1bf64SAndreas Gruenbacher { 6347e1bf64SAndreas Gruenbacher /* 6447e1bf64SAndreas Gruenbacher * Invalidate any cached ACLs if the user has bypassed the ACL 6547e1bf64SAndreas Gruenbacher * interface. We don't validate the content whatsoever so it is caller 6647e1bf64SAndreas Gruenbacher * responsibility to provide data in valid format and ensure i_mode is 6747e1bf64SAndreas Gruenbacher * consistent. 6847e1bf64SAndreas Gruenbacher */ 6947e1bf64SAndreas Gruenbacher if (xflags & ATTR_ROOT) { 7047e1bf64SAndreas Gruenbacher #ifdef CONFIG_XFS_POSIX_ACL 7147e1bf64SAndreas Gruenbacher if (!strcmp(name, SGI_ACL_FILE)) 7247e1bf64SAndreas Gruenbacher forget_cached_acl(inode, ACL_TYPE_ACCESS); 7347e1bf64SAndreas Gruenbacher else if (!strcmp(name, SGI_ACL_DEFAULT)) 7447e1bf64SAndreas Gruenbacher forget_cached_acl(inode, ACL_TYPE_DEFAULT); 7547e1bf64SAndreas Gruenbacher #endif 7647e1bf64SAndreas Gruenbacher } 7747e1bf64SAndreas Gruenbacher } 7847e1bf64SAndreas Gruenbacher 79f9e09f09SLachlan McIlroy static int 80d9a82a04SAndreas Gruenbacher xfs_xattr_set(const struct xattr_handler *handler, struct dentry *dentry, 81d9a82a04SAndreas Gruenbacher const char *name, const void *value, size_t size, int flags) 82f9e09f09SLachlan McIlroy { 83d9a82a04SAndreas Gruenbacher int xflags = handler->flags; 842b0143b5SDavid Howells struct xfs_inode *ip = XFS_I(d_inode(dentry)); 8567d8e04eSBrian Foster int error; 86f9e09f09SLachlan McIlroy 87f9e09f09SLachlan McIlroy if (strcmp(name, "") == 0) 88f9e09f09SLachlan McIlroy return -EINVAL; 89f9e09f09SLachlan McIlroy 90f9e09f09SLachlan McIlroy /* Convert Linux syscall to XFS internal ATTR flags */ 91f9e09f09SLachlan McIlroy if (flags & XATTR_CREATE) 92f9e09f09SLachlan McIlroy xflags |= ATTR_CREATE; 93f9e09f09SLachlan McIlroy if (flags & XATTR_REPLACE) 94f9e09f09SLachlan McIlroy xflags |= ATTR_REPLACE; 95f9e09f09SLachlan McIlroy 96f9e09f09SLachlan McIlroy if (!value) 972451337dSDave Chinner return xfs_attr_remove(ip, (unsigned char *)name, xflags); 9867d8e04eSBrian Foster error = xfs_attr_set(ip, (unsigned char *)name, 99a9273ca5SDave Chinner (void *)value, size, xflags); 10047e1bf64SAndreas Gruenbacher if (!error) 10147e1bf64SAndreas Gruenbacher xfs_forget_acl(d_inode(dentry), name, xflags); 10267d8e04eSBrian Foster 10367d8e04eSBrian Foster return error; 104f9e09f09SLachlan McIlroy } 105f9e09f09SLachlan McIlroy 10646e58764SStephen Hemminger static const struct xattr_handler xfs_xattr_user_handler = { 107f9e09f09SLachlan McIlroy .prefix = XATTR_USER_PREFIX, 108431547b3SChristoph Hellwig .flags = 0, /* no flags implies user namespace */ 109431547b3SChristoph Hellwig .get = xfs_xattr_get, 110431547b3SChristoph Hellwig .set = xfs_xattr_set, 111f9e09f09SLachlan McIlroy }; 112f9e09f09SLachlan McIlroy 11346e58764SStephen Hemminger static const struct xattr_handler xfs_xattr_trusted_handler = { 114f9e09f09SLachlan McIlroy .prefix = XATTR_TRUSTED_PREFIX, 115431547b3SChristoph Hellwig .flags = ATTR_ROOT, 116431547b3SChristoph Hellwig .get = xfs_xattr_get, 117431547b3SChristoph Hellwig .set = xfs_xattr_set, 118f9e09f09SLachlan McIlroy }; 119f9e09f09SLachlan McIlroy 12046e58764SStephen Hemminger static const struct xattr_handler xfs_xattr_security_handler = { 121f9e09f09SLachlan McIlroy .prefix = XATTR_SECURITY_PREFIX, 122431547b3SChristoph Hellwig .flags = ATTR_SECURE, 123431547b3SChristoph Hellwig .get = xfs_xattr_get, 124431547b3SChristoph Hellwig .set = xfs_xattr_set, 125f9e09f09SLachlan McIlroy }; 126f9e09f09SLachlan McIlroy 12746e58764SStephen Hemminger const struct xattr_handler *xfs_xattr_handlers[] = { 128f9e09f09SLachlan McIlroy &xfs_xattr_user_handler, 129f9e09f09SLachlan McIlroy &xfs_xattr_trusted_handler, 130f9e09f09SLachlan McIlroy &xfs_xattr_security_handler, 131ef14f0c1SChristoph Hellwig #ifdef CONFIG_XFS_POSIX_ACL 1322401dc29SChristoph Hellwig &posix_acl_access_xattr_handler, 1332401dc29SChristoph Hellwig &posix_acl_default_xattr_handler, 134ef14f0c1SChristoph Hellwig #endif 135f9e09f09SLachlan McIlroy NULL 136f9e09f09SLachlan McIlroy }; 137f9e09f09SLachlan McIlroy 138f9e09f09SLachlan McIlroy static unsigned int xfs_xattr_prefix_len(int flags) 139f9e09f09SLachlan McIlroy { 140f9e09f09SLachlan McIlroy if (flags & XFS_ATTR_SECURE) 141f9e09f09SLachlan McIlroy return sizeof("security"); 142f9e09f09SLachlan McIlroy else if (flags & XFS_ATTR_ROOT) 143f9e09f09SLachlan McIlroy return sizeof("trusted"); 144f9e09f09SLachlan McIlroy else 145f9e09f09SLachlan McIlroy return sizeof("user"); 146f9e09f09SLachlan McIlroy } 147f9e09f09SLachlan McIlroy 148f9e09f09SLachlan McIlroy static const char *xfs_xattr_prefix(int flags) 149f9e09f09SLachlan McIlroy { 150f9e09f09SLachlan McIlroy if (flags & XFS_ATTR_SECURE) 151f9e09f09SLachlan McIlroy return xfs_xattr_security_handler.prefix; 152f9e09f09SLachlan McIlroy else if (flags & XFS_ATTR_ROOT) 153f9e09f09SLachlan McIlroy return xfs_xattr_trusted_handler.prefix; 154f9e09f09SLachlan McIlroy else 155f9e09f09SLachlan McIlroy return xfs_xattr_user_handler.prefix; 156f9e09f09SLachlan McIlroy } 157f9e09f09SLachlan McIlroy 158f9e09f09SLachlan McIlroy static int 159a9273ca5SDave Chinner xfs_xattr_put_listent( 160a9273ca5SDave Chinner struct xfs_attr_list_context *context, 161a9273ca5SDave Chinner int flags, 162a9273ca5SDave Chinner unsigned char *name, 163a9273ca5SDave Chinner int namelen, 164a9273ca5SDave Chinner int valuelen, 165a9273ca5SDave Chinner unsigned char *value) 166f9e09f09SLachlan McIlroy { 167f9e09f09SLachlan McIlroy unsigned int prefix_len = xfs_xattr_prefix_len(flags); 168f9e09f09SLachlan McIlroy char *offset; 169f9e09f09SLachlan McIlroy int arraytop; 170f9e09f09SLachlan McIlroy 171f9e09f09SLachlan McIlroy ASSERT(context->count >= 0); 172f9e09f09SLachlan McIlroy 173f9e09f09SLachlan McIlroy /* 174f9e09f09SLachlan McIlroy * Only show root namespace entries if we are actually allowed to 175f9e09f09SLachlan McIlroy * see them. 176f9e09f09SLachlan McIlroy */ 177f9e09f09SLachlan McIlroy if ((flags & XFS_ATTR_ROOT) && !capable(CAP_SYS_ADMIN)) 178f9e09f09SLachlan McIlroy return 0; 179f9e09f09SLachlan McIlroy 180f9e09f09SLachlan McIlroy arraytop = context->count + prefix_len + namelen + 1; 181f9e09f09SLachlan McIlroy if (arraytop > context->firstu) { 182f9e09f09SLachlan McIlroy context->count = -1; /* insufficient space */ 183f9e09f09SLachlan McIlroy return 1; 184f9e09f09SLachlan McIlroy } 185f9e09f09SLachlan McIlroy offset = (char *)context->alist + context->count; 186f9e09f09SLachlan McIlroy strncpy(offset, xfs_xattr_prefix(flags), prefix_len); 187f9e09f09SLachlan McIlroy offset += prefix_len; 188a9273ca5SDave Chinner strncpy(offset, (char *)name, namelen); /* real name */ 189f9e09f09SLachlan McIlroy offset += namelen; 190f9e09f09SLachlan McIlroy *offset = '\0'; 191f9e09f09SLachlan McIlroy context->count += prefix_len + namelen + 1; 192f9e09f09SLachlan McIlroy return 0; 193f9e09f09SLachlan McIlroy } 194f9e09f09SLachlan McIlroy 195f9e09f09SLachlan McIlroy static int 196a9273ca5SDave Chinner xfs_xattr_put_listent_sizes( 197a9273ca5SDave Chinner struct xfs_attr_list_context *context, 198a9273ca5SDave Chinner int flags, 199a9273ca5SDave Chinner unsigned char *name, 200a9273ca5SDave Chinner int namelen, 201a9273ca5SDave Chinner int valuelen, 202a9273ca5SDave Chinner unsigned char *value) 203f9e09f09SLachlan McIlroy { 204f9e09f09SLachlan McIlroy context->count += xfs_xattr_prefix_len(flags) + namelen + 1; 205f9e09f09SLachlan McIlroy return 0; 206f9e09f09SLachlan McIlroy } 207f9e09f09SLachlan McIlroy 208f9e09f09SLachlan McIlroy static int 209f9e09f09SLachlan McIlroy list_one_attr(const char *name, const size_t len, void *data, 210f9e09f09SLachlan McIlroy size_t size, ssize_t *result) 211f9e09f09SLachlan McIlroy { 212f9e09f09SLachlan McIlroy char *p = data + *result; 213f9e09f09SLachlan McIlroy 214f9e09f09SLachlan McIlroy *result += len; 215f9e09f09SLachlan McIlroy if (!size) 216f9e09f09SLachlan McIlroy return 0; 217f9e09f09SLachlan McIlroy if (*result > size) 218f9e09f09SLachlan McIlroy return -ERANGE; 219f9e09f09SLachlan McIlroy 220f9e09f09SLachlan McIlroy strcpy(p, name); 221f9e09f09SLachlan McIlroy return 0; 222f9e09f09SLachlan McIlroy } 223f9e09f09SLachlan McIlroy 224f9e09f09SLachlan McIlroy ssize_t 225f9e09f09SLachlan McIlroy xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size) 226f9e09f09SLachlan McIlroy { 227f9e09f09SLachlan McIlroy struct xfs_attr_list_context context; 228f9e09f09SLachlan McIlroy struct attrlist_cursor_kern cursor = { 0 }; 2292b0143b5SDavid Howells struct inode *inode = d_inode(dentry); 230f9e09f09SLachlan McIlroy int error; 231f9e09f09SLachlan McIlroy 232f9e09f09SLachlan McIlroy /* 233f9e09f09SLachlan McIlroy * First read the regular on-disk attributes. 234f9e09f09SLachlan McIlroy */ 235f9e09f09SLachlan McIlroy memset(&context, 0, sizeof(context)); 236f9e09f09SLachlan McIlroy context.dp = XFS_I(inode); 237f9e09f09SLachlan McIlroy context.cursor = &cursor; 238f9e09f09SLachlan McIlroy context.resynch = 1; 239f9e09f09SLachlan McIlroy context.alist = data; 240f9e09f09SLachlan McIlroy context.bufsize = size; 241f9e09f09SLachlan McIlroy context.firstu = context.bufsize; 242f9e09f09SLachlan McIlroy 243f9e09f09SLachlan McIlroy if (size) 244f9e09f09SLachlan McIlroy context.put_listent = xfs_xattr_put_listent; 245f9e09f09SLachlan McIlroy else 246f9e09f09SLachlan McIlroy context.put_listent = xfs_xattr_put_listent_sizes; 247f9e09f09SLachlan McIlroy 248f9e09f09SLachlan McIlroy xfs_attr_list_int(&context); 249f9e09f09SLachlan McIlroy if (context.count < 0) 250f9e09f09SLachlan McIlroy return -ERANGE; 251f9e09f09SLachlan McIlroy 252f9e09f09SLachlan McIlroy /* 253f9e09f09SLachlan McIlroy * Then add the two synthetic ACL attributes. 254f9e09f09SLachlan McIlroy */ 255ef14f0c1SChristoph Hellwig if (posix_acl_access_exists(inode)) { 256f9e09f09SLachlan McIlroy error = list_one_attr(POSIX_ACL_XATTR_ACCESS, 257f9e09f09SLachlan McIlroy strlen(POSIX_ACL_XATTR_ACCESS) + 1, 258f9e09f09SLachlan McIlroy data, size, &context.count); 259f9e09f09SLachlan McIlroy if (error) 260f9e09f09SLachlan McIlroy return error; 261f9e09f09SLachlan McIlroy } 262f9e09f09SLachlan McIlroy 263ef14f0c1SChristoph Hellwig if (posix_acl_default_exists(inode)) { 264f9e09f09SLachlan McIlroy error = list_one_attr(POSIX_ACL_XATTR_DEFAULT, 265f9e09f09SLachlan McIlroy strlen(POSIX_ACL_XATTR_DEFAULT) + 1, 266f9e09f09SLachlan McIlroy data, size, &context.count); 267f9e09f09SLachlan McIlroy if (error) 268f9e09f09SLachlan McIlroy return error; 269f9e09f09SLachlan McIlroy } 270f9e09f09SLachlan McIlroy 271f9e09f09SLachlan McIlroy return context.count; 272f9e09f09SLachlan McIlroy } 273