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/*
  39 * Although these three are just aliases for the above, need to move away from
  40 * confusing users and using the 20+ year old term 'cifs' when it is no longer
  41 * secure, replaced by SMB2 (then even more highly secure SMB3) many years ago
  42 */
  43#define SMB3_XATTR_CIFS_ACL "system.smb3_acl"
  44#define SMB3_XATTR_ATTRIB "smb3.dosattrib"  /* full name: user.smb3.dosattrib */
  45#define SMB3_XATTR_CREATETIME "smb3.creationtime"  /* user.smb3.creationtime */
  46/* BB need to add server (Samba e.g) support for security and trusted prefix */
  47
  48enum { XATTR_USER, XATTR_CIFS_ACL, XATTR_ACL_ACCESS, XATTR_ACL_DEFAULT };
  49
  50static int cifs_xattr_set(const struct xattr_handler *handler,
  51                          struct dentry *dentry, struct inode *inode,
  52                          const char *name, const void *value,
  53                          size_t size, int flags)
  54{
  55        int rc = -EOPNOTSUPP;
  56        unsigned int xid;
  57        struct super_block *sb = dentry->d_sb;
  58        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
  59        struct tcon_link *tlink;
  60        struct cifs_tcon *pTcon;
  61        char *full_path;
  62
  63        tlink = cifs_sb_tlink(cifs_sb);
  64        if (IS_ERR(tlink))
  65                return PTR_ERR(tlink);
  66        pTcon = tlink_tcon(tlink);
  67
  68        xid = get_xid();
  69
  70        full_path = build_path_from_dentry(dentry);
  71        if (full_path == NULL) {
  72                rc = -ENOMEM;
  73                goto out;
  74        }
  75        /* return dos attributes as pseudo xattr */
  76        /* return alt name if available as pseudo attr */
  77
  78        /* if proc/fs/cifs/streamstoxattr is set then
  79                search server for EAs or streams to
  80                returns as xattrs */
  81        if (size > MAX_EA_VALUE_SIZE) {
  82                cifs_dbg(FYI, "size of EA value too large\n");
  83                rc = -EOPNOTSUPP;
  84                goto out;
  85        }
  86
  87        switch (handler->flags) {
  88        case XATTR_USER:
  89                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
  90                        goto out;
  91
  92                if (pTcon->ses->server->ops->set_EA)
  93                        rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
  94                                full_path, name, value, (__u16)size,
  95                                cifs_sb->local_nls, cifs_sb);
  96                break;
  97
  98        case XATTR_CIFS_ACL: {
  99                struct cifs_ntsd *pacl;
 100
 101                if (!value)
 102                        goto out;
 103                pacl = kmalloc(size, GFP_KERNEL);
 104                if (!pacl) {
 105                        rc = -ENOMEM;
 106                } else {
 107                        memcpy(pacl, value, size);
 108                        if (value &&
 109                            pTcon->ses->server->ops->set_acl)
 110                                rc = pTcon->ses->server->ops->set_acl(pacl,
 111                                                size, inode,
 112                                                full_path, CIFS_ACL_DACL);
 113                        else
 114                                rc = -EOPNOTSUPP;
 115                        if (rc == 0) /* force revalidate of the inode */
 116                                CIFS_I(inode)->time = 0;
 117                        kfree(pacl);
 118                }
 119                break;
 120        }
 121
 122        case XATTR_ACL_ACCESS:
 123#ifdef CONFIG_CIFS_POSIX
 124                if (!value)
 125                        goto out;
 126                if (sb->s_flags & SB_POSIXACL)
 127                        rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
 128                                value, (const int)size,
 129                                ACL_TYPE_ACCESS, cifs_sb->local_nls,
 130                                cifs_remap(cifs_sb));
 131#endif  /* CONFIG_CIFS_POSIX */
 132                break;
 133
 134        case XATTR_ACL_DEFAULT:
 135#ifdef CONFIG_CIFS_POSIX
 136                if (!value)
 137                        goto out;
 138                if (sb->s_flags & SB_POSIXACL)
 139                        rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
 140                                value, (const int)size,
 141                                ACL_TYPE_DEFAULT, cifs_sb->local_nls,
 142                                cifs_remap(cifs_sb));
 143#endif  /* CONFIG_CIFS_POSIX */
 144                break;
 145        }
 146
 147out:
 148        kfree(full_path);
 149        free_xid(xid);
 150        cifs_put_tlink(tlink);
 151        return rc;
 152}
 153
 154static int cifs_attrib_get(struct dentry *dentry,
 155                           struct inode *inode, void *value,
 156                           size_t size)
 157{
 158        ssize_t rc;
 159        __u32 *pattribute;
 160
 161        rc = cifs_revalidate_dentry_attr(dentry);
 162
 163        if (rc)
 164                return rc;
 165
 166        if ((value == NULL) || (size == 0))
 167                return sizeof(__u32);
 168        else if (size < sizeof(__u32))
 169                return -ERANGE;
 170
 171        /* return dos attributes as pseudo xattr */
 172        pattribute = (__u32 *)value;
 173        *pattribute = CIFS_I(inode)->cifsAttrs;
 174
 175        return sizeof(__u32);
 176}
 177
 178static int cifs_creation_time_get(struct dentry *dentry, struct inode *inode,
 179                                  void *value, size_t size)
 180{
 181        ssize_t rc;
 182        __u64 * pcreatetime;
 183
 184        rc = cifs_revalidate_dentry_attr(dentry);
 185        if (rc)
 186                return rc;
 187
 188        if ((value == NULL) || (size == 0))
 189                return sizeof(__u64);
 190        else if (size < sizeof(__u64))
 191                return -ERANGE;
 192
 193        /* return dos attributes as pseudo xattr */
 194        pcreatetime = (__u64 *)value;
 195        *pcreatetime = CIFS_I(inode)->createtime;
 196        return sizeof(__u64);
 197}
 198
 199
 200static int cifs_xattr_get(const struct xattr_handler *handler,
 201                          struct dentry *dentry, struct inode *inode,
 202                          const char *name, void *value, size_t size)
 203{
 204        ssize_t rc = -EOPNOTSUPP;
 205        unsigned int xid;
 206        struct super_block *sb = dentry->d_sb;
 207        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 208        struct tcon_link *tlink;
 209        struct cifs_tcon *pTcon;
 210        char *full_path;
 211
 212        tlink = cifs_sb_tlink(cifs_sb);
 213        if (IS_ERR(tlink))
 214                return PTR_ERR(tlink);
 215        pTcon = tlink_tcon(tlink);
 216
 217        xid = get_xid();
 218
 219        full_path = build_path_from_dentry(dentry);
 220        if (full_path == NULL) {
 221                rc = -ENOMEM;
 222                goto out;
 223        }
 224
 225        /* return alt name if available as pseudo attr */
 226        switch (handler->flags) {
 227        case XATTR_USER:
 228                cifs_dbg(FYI, "%s:querying user xattr %s\n", __func__, name);
 229                if ((strcmp(name, CIFS_XATTR_ATTRIB) == 0) ||
 230                    (strcmp(name, SMB3_XATTR_ATTRIB) == 0)) {
 231                        rc = cifs_attrib_get(dentry, inode, value, size);
 232                        break;
 233                } else if ((strcmp(name, CIFS_XATTR_CREATETIME) == 0) ||
 234                    (strcmp(name, SMB3_XATTR_CREATETIME) == 0)) {
 235                        rc = cifs_creation_time_get(dentry, inode, value, size);
 236                        break;
 237                }
 238
 239                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
 240                        goto out;
 241
 242                if (pTcon->ses->server->ops->query_all_EAs)
 243                        rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
 244                                full_path, name, value, size, cifs_sb);
 245                break;
 246
 247        case XATTR_CIFS_ACL: {
 248                u32 acllen;
 249                struct cifs_ntsd *pacl;
 250
 251                if (pTcon->ses->server->ops->get_acl == NULL)
 252                        goto out; /* rc already EOPNOTSUPP */
 253
 254                pacl = pTcon->ses->server->ops->get_acl(cifs_sb,
 255                                inode, full_path, &acllen);
 256                if (IS_ERR(pacl)) {
 257                        rc = PTR_ERR(pacl);
 258                        cifs_dbg(VFS, "%s: error %zd getting sec desc\n",
 259                                 __func__, rc);
 260                } else {
 261                        if (value) {
 262                                if (acllen > size)
 263                                        acllen = -ERANGE;
 264                                else
 265                                        memcpy(value, pacl, acllen);
 266                        }
 267                        rc = acllen;
 268                        kfree(pacl);
 269                }
 270                break;
 271        }
 272
 273        case XATTR_ACL_ACCESS:
 274#ifdef CONFIG_CIFS_POSIX
 275                if (sb->s_flags & SB_POSIXACL)
 276                        rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
 277                                value, size, ACL_TYPE_ACCESS,
 278                                cifs_sb->local_nls,
 279                                cifs_remap(cifs_sb));
 280#endif  /* CONFIG_CIFS_POSIX */
 281                break;
 282
 283        case XATTR_ACL_DEFAULT:
 284#ifdef CONFIG_CIFS_POSIX
 285                if (sb->s_flags & SB_POSIXACL)
 286                        rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
 287                                value, size, ACL_TYPE_DEFAULT,
 288                                cifs_sb->local_nls,
 289                                cifs_remap(cifs_sb));
 290#endif  /* CONFIG_CIFS_POSIX */
 291                break;
 292        }
 293
 294        /* We could add an additional check for streams ie
 295            if proc/fs/cifs/streamstoxattr is set then
 296                search server for EAs or streams to
 297                returns as xattrs */
 298
 299        if (rc == -EINVAL)
 300                rc = -EOPNOTSUPP;
 301
 302out:
 303        kfree(full_path);
 304        free_xid(xid);
 305        cifs_put_tlink(tlink);
 306        return rc;
 307}
 308
 309ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
 310{
 311        ssize_t rc = -EOPNOTSUPP;
 312        unsigned int xid;
 313        struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
 314        struct tcon_link *tlink;
 315        struct cifs_tcon *pTcon;
 316        char *full_path;
 317
 318        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
 319                return -EOPNOTSUPP;
 320
 321        tlink = cifs_sb_tlink(cifs_sb);
 322        if (IS_ERR(tlink))
 323                return PTR_ERR(tlink);
 324        pTcon = tlink_tcon(tlink);
 325
 326        xid = get_xid();
 327
 328        full_path = build_path_from_dentry(direntry);
 329        if (full_path == NULL) {
 330                rc = -ENOMEM;
 331                goto list_ea_exit;
 332        }
 333        /* return dos attributes as pseudo xattr */
 334        /* return alt name if available as pseudo attr */
 335
 336        /* if proc/fs/cifs/streamstoxattr is set then
 337                search server for EAs or streams to
 338                returns as xattrs */
 339
 340        if (pTcon->ses->server->ops->query_all_EAs)
 341                rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
 342                                full_path, NULL, data, buf_size, cifs_sb);
 343list_ea_exit:
 344        kfree(full_path);
 345        free_xid(xid);
 346        cifs_put_tlink(tlink);
 347        return rc;
 348}
 349
 350static const struct xattr_handler cifs_user_xattr_handler = {
 351        .prefix = XATTR_USER_PREFIX,
 352        .flags = XATTR_USER,
 353        .get = cifs_xattr_get,
 354        .set = cifs_xattr_set,
 355};
 356
 357/* os2.* attributes are treated like user.* attributes */
 358static const struct xattr_handler cifs_os2_xattr_handler = {
 359        .prefix = XATTR_OS2_PREFIX,
 360        .flags = XATTR_USER,
 361        .get = cifs_xattr_get,
 362        .set = cifs_xattr_set,
 363};
 364
 365static const struct xattr_handler cifs_cifs_acl_xattr_handler = {
 366        .name = CIFS_XATTR_CIFS_ACL,
 367        .flags = XATTR_CIFS_ACL,
 368        .get = cifs_xattr_get,
 369        .set = cifs_xattr_set,
 370};
 371
 372/*
 373 * Although this is just an alias for the above, need to move away from
 374 * confusing users and using the 20 year old term 'cifs' when it is no
 375 * longer secure and was replaced by SMB2/SMB3 a long time ago, and
 376 * SMB3 and later are highly secure.
 377 */
 378static const struct xattr_handler smb3_acl_xattr_handler = {
 379        .name = SMB3_XATTR_CIFS_ACL,
 380        .flags = XATTR_CIFS_ACL,
 381        .get = cifs_xattr_get,
 382        .set = cifs_xattr_set,
 383};
 384
 385static const struct xattr_handler cifs_posix_acl_access_xattr_handler = {
 386        .name = XATTR_NAME_POSIX_ACL_ACCESS,
 387        .flags = XATTR_ACL_ACCESS,
 388        .get = cifs_xattr_get,
 389        .set = cifs_xattr_set,
 390};
 391
 392static const struct xattr_handler cifs_posix_acl_default_xattr_handler = {
 393        .name = XATTR_NAME_POSIX_ACL_DEFAULT,
 394        .flags = XATTR_ACL_DEFAULT,
 395        .get = cifs_xattr_get,
 396        .set = cifs_xattr_set,
 397};
 398
 399const struct xattr_handler *cifs_xattr_handlers[] = {
 400        &cifs_user_xattr_handler,
 401        &cifs_os2_xattr_handler,
 402        &cifs_cifs_acl_xattr_handler,
 403        &smb3_acl_xattr_handler, /* alias for above since avoiding "cifs" */
 404        &cifs_posix_acl_access_xattr_handler,
 405        &cifs_posix_acl_default_xattr_handler,
 406        NULL
 407};
 408