linux/fs/xfs/xfs_xattr.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2008 Christoph Hellwig.
   4 * Portions Copyright (C) 2000-2008 Silicon Graphics, Inc.
   5 */
   6
   7#include "xfs.h"
   8#include "xfs_shared.h"
   9#include "xfs_format.h"
  10#include "xfs_log_format.h"
  11#include "xfs_da_format.h"
  12#include "xfs_inode.h"
  13#include "xfs_attr.h"
  14#include "xfs_acl.h"
  15#include "xfs_da_btree.h"
  16
  17#include <linux/posix_acl_xattr.h>
  18
  19
  20static int
  21xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
  22                struct inode *inode, const char *name, void *value, size_t size)
  23{
  24        struct xfs_da_args      args = {
  25                .dp             = XFS_I(inode),
  26                .attr_filter    = handler->flags,
  27                .name           = name,
  28                .namelen        = strlen(name),
  29                .value          = value,
  30                .valuelen       = size,
  31        };
  32        int                     error;
  33
  34        error = xfs_attr_get(&args);
  35        if (error)
  36                return error;
  37        return args.valuelen;
  38}
  39
  40static int
  41xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
  42                struct inode *inode, const char *name, const void *value,
  43                size_t size, int flags)
  44{
  45        struct xfs_da_args      args = {
  46                .dp             = XFS_I(inode),
  47                .attr_filter    = handler->flags,
  48                .attr_flags     = flags,
  49                .name           = name,
  50                .namelen        = strlen(name),
  51                .value          = (void *)value,
  52                .valuelen       = size,
  53        };
  54        int                     error;
  55
  56        error = xfs_attr_set(&args);
  57        if (!error && (handler->flags & XFS_ATTR_ROOT))
  58                xfs_forget_acl(inode, name);
  59        return error;
  60}
  61
  62static const struct xattr_handler xfs_xattr_user_handler = {
  63        .prefix = XATTR_USER_PREFIX,
  64        .flags  = 0, /* no flags implies user namespace */
  65        .get    = xfs_xattr_get,
  66        .set    = xfs_xattr_set,
  67};
  68
  69static const struct xattr_handler xfs_xattr_trusted_handler = {
  70        .prefix = XATTR_TRUSTED_PREFIX,
  71        .flags  = XFS_ATTR_ROOT,
  72        .get    = xfs_xattr_get,
  73        .set    = xfs_xattr_set,
  74};
  75
  76static const struct xattr_handler xfs_xattr_security_handler = {
  77        .prefix = XATTR_SECURITY_PREFIX,
  78        .flags  = XFS_ATTR_SECURE,
  79        .get    = xfs_xattr_get,
  80        .set    = xfs_xattr_set,
  81};
  82
  83const struct xattr_handler *xfs_xattr_handlers[] = {
  84        &xfs_xattr_user_handler,
  85        &xfs_xattr_trusted_handler,
  86        &xfs_xattr_security_handler,
  87#ifdef CONFIG_XFS_POSIX_ACL
  88        &posix_acl_access_xattr_handler,
  89        &posix_acl_default_xattr_handler,
  90#endif
  91        NULL
  92};
  93
  94static void
  95__xfs_xattr_put_listent(
  96        struct xfs_attr_list_context *context,
  97        char *prefix,
  98        int prefix_len,
  99        unsigned char *name,
 100        int namelen)
 101{
 102        char *offset;
 103        int arraytop;
 104
 105        if (context->count < 0 || context->seen_enough)
 106                return;
 107
 108        if (!context->buffer)
 109                goto compute_size;
 110
 111        arraytop = context->count + prefix_len + namelen + 1;
 112        if (arraytop > context->firstu) {
 113                context->count = -1;    /* insufficient space */
 114                context->seen_enough = 1;
 115                return;
 116        }
 117        offset = context->buffer + context->count;
 118        strncpy(offset, prefix, prefix_len);
 119        offset += prefix_len;
 120        strncpy(offset, (char *)name, namelen);                 /* real name */
 121        offset += namelen;
 122        *offset = '\0';
 123
 124compute_size:
 125        context->count += prefix_len + namelen + 1;
 126        return;
 127}
 128
 129static void
 130xfs_xattr_put_listent(
 131        struct xfs_attr_list_context *context,
 132        int             flags,
 133        unsigned char   *name,
 134        int             namelen,
 135        int             valuelen)
 136{
 137        char *prefix;
 138        int prefix_len;
 139
 140        ASSERT(context->count >= 0);
 141
 142        if (flags & XFS_ATTR_ROOT) {
 143#ifdef CONFIG_XFS_POSIX_ACL
 144                if (namelen == SGI_ACL_FILE_SIZE &&
 145                    strncmp(name, SGI_ACL_FILE,
 146                            SGI_ACL_FILE_SIZE) == 0) {
 147                        __xfs_xattr_put_listent(
 148                                        context, XATTR_SYSTEM_PREFIX,
 149                                        XATTR_SYSTEM_PREFIX_LEN,
 150                                        XATTR_POSIX_ACL_ACCESS,
 151                                        strlen(XATTR_POSIX_ACL_ACCESS));
 152                } else if (namelen == SGI_ACL_DEFAULT_SIZE &&
 153                         strncmp(name, SGI_ACL_DEFAULT,
 154                                 SGI_ACL_DEFAULT_SIZE) == 0) {
 155                        __xfs_xattr_put_listent(
 156                                        context, XATTR_SYSTEM_PREFIX,
 157                                        XATTR_SYSTEM_PREFIX_LEN,
 158                                        XATTR_POSIX_ACL_DEFAULT,
 159                                        strlen(XATTR_POSIX_ACL_DEFAULT));
 160                }
 161#endif
 162
 163                /*
 164                 * Only show root namespace entries if we are actually allowed to
 165                 * see them.
 166                 */
 167                if (!capable(CAP_SYS_ADMIN))
 168                        return;
 169
 170                prefix = XATTR_TRUSTED_PREFIX;
 171                prefix_len = XATTR_TRUSTED_PREFIX_LEN;
 172        } else if (flags & XFS_ATTR_SECURE) {
 173                prefix = XATTR_SECURITY_PREFIX;
 174                prefix_len = XATTR_SECURITY_PREFIX_LEN;
 175        } else {
 176                prefix = XATTR_USER_PREFIX;
 177                prefix_len = XATTR_USER_PREFIX_LEN;
 178        }
 179
 180        __xfs_xattr_put_listent(context, prefix, prefix_len, name,
 181                                namelen);
 182        return;
 183}
 184
 185ssize_t
 186xfs_vn_listxattr(
 187        struct dentry   *dentry,
 188        char            *data,
 189        size_t          size)
 190{
 191        struct xfs_attr_list_context context;
 192        struct inode    *inode = d_inode(dentry);
 193        int             error;
 194
 195        /*
 196         * First read the regular on-disk attributes.
 197         */
 198        memset(&context, 0, sizeof(context));
 199        context.dp = XFS_I(inode);
 200        context.resynch = 1;
 201        context.buffer = size ? data : NULL;
 202        context.bufsize = size;
 203        context.firstu = context.bufsize;
 204        context.put_listent = xfs_xattr_put_listent;
 205
 206        error = xfs_attr_list(&context);
 207        if (error)
 208                return error;
 209        if (context.count < 0)
 210                return -ERANGE;
 211
 212        return context.count;
 213}
 214