linux/fs/cifs/xattr.c
<<
>>
Prefs
   1/*
   2 *   fs/cifs/xattr.c
   3 *
   4 *   Copyright (c) International Business Machines  Corp., 2003, 2007
   5 *   Author(s): Steve French (sfrench@us.ibm.com)
   6 *
   7 *   This library is free software; you can redistribute it and/or modify
   8 *   it under the terms of the GNU Lesser General Public License as published
   9 *   by the Free Software Foundation; either version 2.1 of the License, or
  10 *   (at your option) any later version.
  11 *
  12 *   This library is distributed in the hope that it will be useful,
  13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
  15 *   the GNU Lesser General Public License for more details.
  16 *
  17 *   You should have received a copy of the GNU Lesser General Public License
  18 *   along with this library; if not, write to the Free Software
  19 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20 */
  21
  22#include <linux/fs.h>
  23#include <linux/posix_acl_xattr.h>
  24#include <linux/slab.h>
  25#include <linux/xattr.h>
  26#include "cifsfs.h"
  27#include "cifspdu.h"
  28#include "cifsglob.h"
  29#include "cifsproto.h"
  30#include "cifs_debug.h"
  31#include "cifs_fs_sb.h"
  32#include "cifs_unicode.h"
  33
  34#define MAX_EA_VALUE_SIZE 65535
  35#define CIFS_XATTR_CIFS_ACL "system.cifs_acl"
  36#define CIFS_XATTR_ATTRIB "cifs.dosattrib"  /* full name: user.cifs.dosattrib */
  37#define CIFS_XATTR_CREATETIME "cifs.creationtime"  /* user.cifs.creationtime */
  38/* BB need to add server (Samba e.g) support for security and trusted prefix */
  39
  40enum { XATTR_USER, XATTR_CIFS_ACL, XATTR_ACL_ACCESS, XATTR_ACL_DEFAULT };
  41
  42static int cifs_xattr_set(const struct xattr_handler *handler,
  43                          struct dentry *dentry, struct inode *inode,
  44                          const char *name, const void *value,
  45                          size_t size, int flags)
  46{
  47        int rc = -EOPNOTSUPP;
  48        unsigned int xid;
  49        struct super_block *sb = dentry->d_sb;
  50        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
  51        struct tcon_link *tlink;
  52        struct cifs_tcon *pTcon;
  53        char *full_path;
  54
  55        tlink = cifs_sb_tlink(cifs_sb);
  56        if (IS_ERR(tlink))
  57                return PTR_ERR(tlink);
  58        pTcon = tlink_tcon(tlink);
  59
  60        xid = get_xid();
  61
  62        full_path = build_path_from_dentry(dentry);
  63        if (full_path == NULL) {
  64                rc = -ENOMEM;
  65                goto out;
  66        }
  67        /* return dos attributes as pseudo xattr */
  68        /* return alt name if available as pseudo attr */
  69
  70        /* if proc/fs/cifs/streamstoxattr is set then
  71                search server for EAs or streams to
  72                returns as xattrs */
  73        if (size > MAX_EA_VALUE_SIZE) {
  74                cifs_dbg(FYI, "size of EA value too large\n");
  75                rc = -EOPNOTSUPP;
  76                goto out;
  77        }
  78
  79        switch (handler->flags) {
  80        case XATTR_USER:
  81                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
  82                        goto out;
  83
  84                if (pTcon->ses->server->ops->set_EA)
  85                        rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
  86                                full_path, name, value, (__u16)size,
  87                                cifs_sb->local_nls, cifs_remap(cifs_sb));
  88                break;
  89
  90        case XATTR_CIFS_ACL: {
  91#ifdef CONFIG_CIFS_ACL
  92                struct cifs_ntsd *pacl;
  93
  94                if (!value)
  95                        goto out;
  96                pacl = kmalloc(size, GFP_KERNEL);
  97                if (!pacl) {
  98                        rc = -ENOMEM;
  99                } else {
 100                        memcpy(pacl, value, size);
 101                        if (value &&
 102                            pTcon->ses->server->ops->set_acl)
 103                                rc = pTcon->ses->server->ops->set_acl(pacl,
 104                                                size, inode,
 105                                                full_path, CIFS_ACL_DACL);
 106                        else
 107                                rc = -EOPNOTSUPP;
 108                        if (rc == 0) /* force revalidate of the inode */
 109                                CIFS_I(inode)->time = 0;
 110                        kfree(pacl);
 111                }
 112#endif /* CONFIG_CIFS_ACL */
 113                break;
 114        }
 115
 116        case XATTR_ACL_ACCESS:
 117#ifdef CONFIG_CIFS_POSIX
 118                if (!value)
 119                        goto out;
 120                if (sb->s_flags & MS_POSIXACL)
 121                        rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
 122                                value, (const int)size,
 123                                ACL_TYPE_ACCESS, cifs_sb->local_nls,
 124                                cifs_remap(cifs_sb));
 125#endif  /* CONFIG_CIFS_POSIX */
 126                break;
 127
 128        case XATTR_ACL_DEFAULT:
 129#ifdef CONFIG_CIFS_POSIX
 130                if (!value)
 131                        goto out;
 132                if (sb->s_flags & MS_POSIXACL)
 133                        rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
 134                                value, (const int)size,
 135                                ACL_TYPE_DEFAULT, cifs_sb->local_nls,
 136                                cifs_remap(cifs_sb));
 137#endif  /* CONFIG_CIFS_POSIX */
 138                break;
 139        }
 140
 141out:
 142        kfree(full_path);
 143        free_xid(xid);
 144        cifs_put_tlink(tlink);
 145        return rc;
 146}
 147
 148static int cifs_attrib_get(struct dentry *dentry,
 149                           struct inode *inode, void *value,
 150                           size_t size)
 151{
 152        ssize_t rc;
 153        __u32 *pattribute;
 154
 155        rc = cifs_revalidate_dentry_attr(dentry);
 156
 157        if (rc)
 158                return rc;
 159
 160        if ((value == NULL) || (size == 0))
 161                return sizeof(__u32);
 162        else if (size < sizeof(__u32))
 163                return -ERANGE;
 164
 165        /* return dos attributes as pseudo xattr */
 166        pattribute = (__u32 *)value;
 167        *pattribute = CIFS_I(inode)->cifsAttrs;
 168
 169        return sizeof(__u32);
 170}
 171
 172static int cifs_creation_time_get(struct dentry *dentry, struct inode *inode,
 173                                  void *value, size_t size)
 174{
 175        ssize_t rc;
 176        __u64 * pcreatetime;
 177
 178        rc = cifs_revalidate_dentry_attr(dentry);
 179        if (rc)
 180                return rc;
 181
 182        if ((value == NULL) || (size == 0))
 183                return sizeof(__u64);
 184        else if (size < sizeof(__u64))
 185                return -ERANGE;
 186
 187        /* return dos attributes as pseudo xattr */
 188        pcreatetime = (__u64 *)value;
 189        *pcreatetime = CIFS_I(inode)->createtime;
 190        return sizeof(__u64);
 191
 192        return rc;
 193}
 194
 195
 196static int cifs_xattr_get(const struct xattr_handler *handler,
 197                          struct dentry *dentry, struct inode *inode,
 198                          const char *name, void *value, size_t size)
 199{
 200        ssize_t rc = -EOPNOTSUPP;
 201        unsigned int xid;
 202        struct super_block *sb = dentry->d_sb;
 203        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 204        struct tcon_link *tlink;
 205        struct cifs_tcon *pTcon;
 206        char *full_path;
 207
 208        tlink = cifs_sb_tlink(cifs_sb);
 209        if (IS_ERR(tlink))
 210                return PTR_ERR(tlink);
 211        pTcon = tlink_tcon(tlink);
 212
 213        xid = get_xid();
 214
 215        full_path = build_path_from_dentry(dentry);
 216        if (full_path == NULL) {
 217                rc = -ENOMEM;
 218                goto out;
 219        }
 220
 221        /* return alt name if available as pseudo attr */
 222        switch (handler->flags) {
 223        case XATTR_USER:
 224                cifs_dbg(FYI, "%s:querying user xattr %s\n", __func__, name);
 225                if (strcmp(name, CIFS_XATTR_ATTRIB) == 0) {
 226                        rc = cifs_attrib_get(dentry, inode, value, size);
 227                        break;
 228                } else if (strcmp(name, CIFS_XATTR_CREATETIME) == 0) {
 229                        rc = cifs_creation_time_get(dentry, inode, value, size);
 230                        break;
 231                }
 232
 233                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
 234                        goto out;
 235
 236                if (pTcon->ses->server->ops->query_all_EAs)
 237                        rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
 238                                full_path, name, value, size,
 239                                cifs_sb->local_nls, cifs_remap(cifs_sb));
 240                break;
 241
 242        case XATTR_CIFS_ACL: {
 243#ifdef CONFIG_CIFS_ACL
 244                u32 acllen;
 245                struct cifs_ntsd *pacl;
 246
 247                if (pTcon->ses->server->ops->get_acl == NULL)
 248                        goto out; /* rc already EOPNOTSUPP */
 249
 250                pacl = pTcon->ses->server->ops->get_acl(cifs_sb,
 251                                inode, full_path, &acllen);
 252                if (IS_ERR(pacl)) {
 253                        rc = PTR_ERR(pacl);
 254                        cifs_dbg(VFS, "%s: error %zd getting sec desc\n",
 255                                 __func__, rc);
 256                } else {
 257                        if (value) {
 258                                if (acllen > size)
 259                                        acllen = -ERANGE;
 260                                else
 261                                        memcpy(value, pacl, acllen);
 262                        }
 263                        rc = acllen;
 264                        kfree(pacl);
 265                }
 266#endif  /* CONFIG_CIFS_ACL */
 267                break;
 268        }
 269
 270        case XATTR_ACL_ACCESS:
 271#ifdef CONFIG_CIFS_POSIX
 272                if (sb->s_flags & MS_POSIXACL)
 273                        rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
 274                                value, size, ACL_TYPE_ACCESS,
 275                                cifs_sb->local_nls,
 276                                cifs_remap(cifs_sb));
 277#endif  /* CONFIG_CIFS_POSIX */
 278                break;
 279
 280        case XATTR_ACL_DEFAULT:
 281#ifdef CONFIG_CIFS_POSIX
 282                if (sb->s_flags & MS_POSIXACL)
 283                        rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
 284                                value, size, ACL_TYPE_DEFAULT,
 285                                cifs_sb->local_nls,
 286                                cifs_remap(cifs_sb));
 287#endif  /* CONFIG_CIFS_POSIX */
 288                break;
 289        }
 290
 291        /* We could add an additional check for streams ie
 292            if proc/fs/cifs/streamstoxattr is set then
 293                search server for EAs or streams to
 294                returns as xattrs */
 295
 296        if (rc == -EINVAL)
 297                rc = -EOPNOTSUPP;
 298
 299out:
 300        kfree(full_path);
 301        free_xid(xid);
 302        cifs_put_tlink(tlink);
 303        return rc;
 304}
 305
 306ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
 307{
 308        ssize_t rc = -EOPNOTSUPP;
 309        unsigned int xid;
 310        struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
 311        struct tcon_link *tlink;
 312        struct cifs_tcon *pTcon;
 313        char *full_path;
 314
 315        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
 316                return -EOPNOTSUPP;
 317
 318        tlink = cifs_sb_tlink(cifs_sb);
 319        if (IS_ERR(tlink))
 320                return PTR_ERR(tlink);
 321        pTcon = tlink_tcon(tlink);
 322
 323        xid = get_xid();
 324
 325        full_path = build_path_from_dentry(direntry);
 326        if (full_path == NULL) {
 327                rc = -ENOMEM;
 328                goto list_ea_exit;
 329        }
 330        /* return dos attributes as pseudo xattr */
 331        /* return alt name if available as pseudo attr */
 332
 333        /* if proc/fs/cifs/streamstoxattr is set then
 334                search server for EAs or streams to
 335                returns as xattrs */
 336
 337        if (pTcon->ses->server->ops->query_all_EAs)
 338                rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
 339                                full_path, NULL, data, buf_size,
 340                                cifs_sb->local_nls, cifs_remap(cifs_sb));
 341list_ea_exit:
 342        kfree(full_path);
 343        free_xid(xid);
 344        cifs_put_tlink(tlink);
 345        return rc;
 346}
 347
 348static const struct xattr_handler cifs_user_xattr_handler = {
 349        .prefix = XATTR_USER_PREFIX,
 350        .flags = XATTR_USER,
 351        .get = cifs_xattr_get,
 352        .set = cifs_xattr_set,
 353};
 354
 355/* os2.* attributes are treated like user.* attributes */
 356static const struct xattr_handler cifs_os2_xattr_handler = {
 357        .prefix = XATTR_OS2_PREFIX,
 358        .flags = XATTR_USER,
 359        .get = cifs_xattr_get,
 360        .set = cifs_xattr_set,
 361};
 362
 363static const struct xattr_handler cifs_cifs_acl_xattr_handler = {
 364        .name = CIFS_XATTR_CIFS_ACL,
 365        .flags = XATTR_CIFS_ACL,
 366        .get = cifs_xattr_get,
 367        .set = cifs_xattr_set,
 368};
 369
 370static const struct xattr_handler cifs_posix_acl_access_xattr_handler = {
 371        .name = XATTR_NAME_POSIX_ACL_ACCESS,
 372        .flags = XATTR_ACL_ACCESS,
 373        .get = cifs_xattr_get,
 374        .set = cifs_xattr_set,
 375};
 376
 377static const struct xattr_handler cifs_posix_acl_default_xattr_handler = {
 378        .name = XATTR_NAME_POSIX_ACL_DEFAULT,
 379        .flags = XATTR_ACL_DEFAULT,
 380        .get = cifs_xattr_get,
 381        .set = cifs_xattr_set,
 382};
 383
 384const struct xattr_handler *cifs_xattr_handlers[] = {
 385        &cifs_user_xattr_handler,
 386        &cifs_os2_xattr_handler,
 387        &cifs_cifs_acl_xattr_handler,
 388        &cifs_posix_acl_access_xattr_handler,
 389        &cifs_posix_acl_default_xattr_handler,
 390        NULL
 391};
 392