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
 193
 194static int cifs_xattr_get(const struct xattr_handler *handler,
 195                          struct dentry *dentry, struct inode *inode,
 196                          const char *name, void *value, size_t size)
 197{
 198        ssize_t rc = -EOPNOTSUPP;
 199        unsigned int xid;
 200        struct super_block *sb = dentry->d_sb;
 201        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 202        struct tcon_link *tlink;
 203        struct cifs_tcon *pTcon;
 204        char *full_path;
 205
 206        tlink = cifs_sb_tlink(cifs_sb);
 207        if (IS_ERR(tlink))
 208                return PTR_ERR(tlink);
 209        pTcon = tlink_tcon(tlink);
 210
 211        xid = get_xid();
 212
 213        full_path = build_path_from_dentry(dentry);
 214        if (full_path == NULL) {
 215                rc = -ENOMEM;
 216                goto out;
 217        }
 218
 219        /* return alt name if available as pseudo attr */
 220        switch (handler->flags) {
 221        case XATTR_USER:
 222                cifs_dbg(FYI, "%s:querying user xattr %s\n", __func__, name);
 223                if (strcmp(name, CIFS_XATTR_ATTRIB) == 0) {
 224                        rc = cifs_attrib_get(dentry, inode, value, size);
 225                        break;
 226                } else if (strcmp(name, CIFS_XATTR_CREATETIME) == 0) {
 227                        rc = cifs_creation_time_get(dentry, inode, value, size);
 228                        break;
 229                }
 230
 231                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
 232                        goto out;
 233
 234                if (pTcon->ses->server->ops->query_all_EAs)
 235                        rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
 236                                full_path, name, value, size, cifs_sb);
 237                break;
 238
 239        case XATTR_CIFS_ACL: {
 240#ifdef CONFIG_CIFS_ACL
 241                u32 acllen;
 242                struct cifs_ntsd *pacl;
 243
 244                if (pTcon->ses->server->ops->get_acl == NULL)
 245                        goto out; /* rc already EOPNOTSUPP */
 246
 247                pacl = pTcon->ses->server->ops->get_acl(cifs_sb,
 248                                inode, full_path, &acllen);
 249                if (IS_ERR(pacl)) {
 250                        rc = PTR_ERR(pacl);
 251                        cifs_dbg(VFS, "%s: error %zd getting sec desc\n",
 252                                 __func__, rc);
 253                } else {
 254                        if (value) {
 255                                if (acllen > size)
 256                                        acllen = -ERANGE;
 257                                else
 258                                        memcpy(value, pacl, acllen);
 259                        }
 260                        rc = acllen;
 261                        kfree(pacl);
 262                }
 263#endif  /* CONFIG_CIFS_ACL */
 264                break;
 265        }
 266
 267        case XATTR_ACL_ACCESS:
 268#ifdef CONFIG_CIFS_POSIX
 269                if (sb->s_flags & MS_POSIXACL)
 270                        rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
 271                                value, size, ACL_TYPE_ACCESS,
 272                                cifs_sb->local_nls,
 273                                cifs_remap(cifs_sb));
 274#endif  /* CONFIG_CIFS_POSIX */
 275                break;
 276
 277        case XATTR_ACL_DEFAULT:
 278#ifdef CONFIG_CIFS_POSIX
 279                if (sb->s_flags & MS_POSIXACL)
 280                        rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
 281                                value, size, ACL_TYPE_DEFAULT,
 282                                cifs_sb->local_nls,
 283                                cifs_remap(cifs_sb));
 284#endif  /* CONFIG_CIFS_POSIX */
 285                break;
 286        }
 287
 288        /* We could add an additional check for streams ie
 289            if proc/fs/cifs/streamstoxattr is set then
 290                search server for EAs or streams to
 291                returns as xattrs */
 292
 293        if (rc == -EINVAL)
 294                rc = -EOPNOTSUPP;
 295
 296out:
 297        kfree(full_path);
 298        free_xid(xid);
 299        cifs_put_tlink(tlink);
 300        return rc;
 301}
 302
 303ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
 304{
 305        ssize_t rc = -EOPNOTSUPP;
 306        unsigned int xid;
 307        struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
 308        struct tcon_link *tlink;
 309        struct cifs_tcon *pTcon;
 310        char *full_path;
 311
 312        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
 313                return -EOPNOTSUPP;
 314
 315        tlink = cifs_sb_tlink(cifs_sb);
 316        if (IS_ERR(tlink))
 317                return PTR_ERR(tlink);
 318        pTcon = tlink_tcon(tlink);
 319
 320        xid = get_xid();
 321
 322        full_path = build_path_from_dentry(direntry);
 323        if (full_path == NULL) {
 324                rc = -ENOMEM;
 325                goto list_ea_exit;
 326        }
 327        /* return dos attributes as pseudo xattr */
 328        /* return alt name if available as pseudo attr */
 329
 330        /* if proc/fs/cifs/streamstoxattr is set then
 331                search server for EAs or streams to
 332                returns as xattrs */
 333
 334        if (pTcon->ses->server->ops->query_all_EAs)
 335                rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
 336                                full_path, NULL, data, buf_size, cifs_sb);
 337list_ea_exit:
 338        kfree(full_path);
 339        free_xid(xid);
 340        cifs_put_tlink(tlink);
 341        return rc;
 342}
 343
 344static const struct xattr_handler cifs_user_xattr_handler = {
 345        .prefix = XATTR_USER_PREFIX,
 346        .flags = XATTR_USER,
 347        .get = cifs_xattr_get,
 348        .set = cifs_xattr_set,
 349};
 350
 351/* os2.* attributes are treated like user.* attributes */
 352static const struct xattr_handler cifs_os2_xattr_handler = {
 353        .prefix = XATTR_OS2_PREFIX,
 354        .flags = XATTR_USER,
 355        .get = cifs_xattr_get,
 356        .set = cifs_xattr_set,
 357};
 358
 359static const struct xattr_handler cifs_cifs_acl_xattr_handler = {
 360        .name = CIFS_XATTR_CIFS_ACL,
 361        .flags = XATTR_CIFS_ACL,
 362        .get = cifs_xattr_get,
 363        .set = cifs_xattr_set,
 364};
 365
 366static const struct xattr_handler cifs_posix_acl_access_xattr_handler = {
 367        .name = XATTR_NAME_POSIX_ACL_ACCESS,
 368        .flags = XATTR_ACL_ACCESS,
 369        .get = cifs_xattr_get,
 370        .set = cifs_xattr_set,
 371};
 372
 373static const struct xattr_handler cifs_posix_acl_default_xattr_handler = {
 374        .name = XATTR_NAME_POSIX_ACL_DEFAULT,
 375        .flags = XATTR_ACL_DEFAULT,
 376        .get = cifs_xattr_get,
 377        .set = cifs_xattr_set,
 378};
 379
 380const struct xattr_handler *cifs_xattr_handlers[] = {
 381        &cifs_user_xattr_handler,
 382        &cifs_os2_xattr_handler,
 383        &cifs_cifs_acl_xattr_handler,
 384        &cifs_posix_acl_access_xattr_handler,
 385        &cifs_posix_acl_default_xattr_handler,
 386        NULL
 387};
 388