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 "cifsfs.h"
  26#include "cifspdu.h"
  27#include "cifsglob.h"
  28#include "cifsproto.h"
  29#include "cifs_debug.h"
  30
  31#define MAX_EA_VALUE_SIZE 65535
  32#define CIFS_XATTR_DOS_ATTRIB "user.DosAttrib"
  33#define CIFS_XATTR_CIFS_ACL "system.cifs_acl"
  34#define CIFS_XATTR_USER_PREFIX "user."
  35#define CIFS_XATTR_SYSTEM_PREFIX "system."
  36#define CIFS_XATTR_OS2_PREFIX "os2."
  37#define CIFS_XATTR_SECURITY_PREFIX "security."
  38#define CIFS_XATTR_TRUSTED_PREFIX "trusted."
  39#define XATTR_TRUSTED_PREFIX_LEN  8
  40#define XATTR_SECURITY_PREFIX_LEN 9
  41/* BB need to add server (Samba e.g) support for security and trusted prefix */
  42
  43
  44
  45int cifs_removexattr(struct dentry *direntry, const char *ea_name)
  46{
  47        int rc = -EOPNOTSUPP;
  48#ifdef CONFIG_CIFS_XATTR
  49        int xid;
  50        struct cifs_sb_info *cifs_sb;
  51        struct tcon_link *tlink;
  52        struct cifsTconInfo *pTcon;
  53        struct super_block *sb;
  54        char *full_path = NULL;
  55
  56        if (direntry == NULL)
  57                return -EIO;
  58        if (direntry->d_inode == NULL)
  59                return -EIO;
  60        sb = direntry->d_inode->i_sb;
  61        if (sb == NULL)
  62                return -EIO;
  63
  64        cifs_sb = CIFS_SB(sb);
  65        tlink = cifs_sb_tlink(cifs_sb);
  66        if (IS_ERR(tlink))
  67                return PTR_ERR(tlink);
  68        pTcon = tlink_tcon(tlink);
  69
  70        xid = GetXid();
  71
  72        full_path = build_path_from_dentry(direntry);
  73        if (full_path == NULL) {
  74                rc = -ENOMEM;
  75                goto remove_ea_exit;
  76        }
  77        if (ea_name == NULL) {
  78                cFYI(1, "Null xattr names not supported");
  79        } else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5)
  80                && (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4))) {
  81                cFYI(1,
  82                     "illegal xattr request %s (only user namespace supported)",
  83                     ea_name);
  84                /* BB what if no namespace prefix? */
  85                /* Should we just pass them to server, except for
  86                system and perhaps security prefixes? */
  87        } else {
  88                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
  89                        goto remove_ea_exit;
  90
  91                ea_name += 5; /* skip past user. prefix */
  92                rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, NULL,
  93                        (__u16)0, cifs_sb->local_nls,
  94                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
  95        }
  96remove_ea_exit:
  97        kfree(full_path);
  98        FreeXid(xid);
  99        cifs_put_tlink(tlink);
 100#endif
 101        return rc;
 102}
 103
 104int cifs_setxattr(struct dentry *direntry, const char *ea_name,
 105                  const void *ea_value, size_t value_size, int flags)
 106{
 107        int rc = -EOPNOTSUPP;
 108#ifdef CONFIG_CIFS_XATTR
 109        int xid;
 110        struct cifs_sb_info *cifs_sb;
 111        struct tcon_link *tlink;
 112        struct cifsTconInfo *pTcon;
 113        struct super_block *sb;
 114        char *full_path;
 115
 116        if (direntry == NULL)
 117                return -EIO;
 118        if (direntry->d_inode == NULL)
 119                return -EIO;
 120        sb = direntry->d_inode->i_sb;
 121        if (sb == NULL)
 122                return -EIO;
 123
 124        cifs_sb = CIFS_SB(sb);
 125        tlink = cifs_sb_tlink(cifs_sb);
 126        if (IS_ERR(tlink))
 127                return PTR_ERR(tlink);
 128        pTcon = tlink_tcon(tlink);
 129
 130        xid = GetXid();
 131
 132        full_path = build_path_from_dentry(direntry);
 133        if (full_path == NULL) {
 134                rc = -ENOMEM;
 135                goto set_ea_exit;
 136        }
 137        /* return dos attributes as pseudo xattr */
 138        /* return alt name if available as pseudo attr */
 139
 140        /* if proc/fs/cifs/streamstoxattr is set then
 141                search server for EAs or streams to
 142                returns as xattrs */
 143        if (value_size > MAX_EA_VALUE_SIZE) {
 144                cFYI(1, "size of EA value too large");
 145                rc = -EOPNOTSUPP;
 146                goto set_ea_exit;
 147        }
 148
 149        if (ea_name == NULL) {
 150                cFYI(1, "Null xattr names not supported");
 151        } else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5) == 0) {
 152                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
 153                        goto set_ea_exit;
 154                if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0)
 155                        cFYI(1, "attempt to set cifs inode metadata");
 156
 157                ea_name += 5; /* skip past user. prefix */
 158                rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value,
 159                        (__u16)value_size, cifs_sb->local_nls,
 160                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 161        } else if (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4) == 0) {
 162                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
 163                        goto set_ea_exit;
 164
 165                ea_name += 4; /* skip past os2. prefix */
 166                rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value,
 167                        (__u16)value_size, cifs_sb->local_nls,
 168                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 169        } else {
 170                int temp;
 171                temp = strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
 172                        strlen(POSIX_ACL_XATTR_ACCESS));
 173                if (temp == 0) {
 174#ifdef CONFIG_CIFS_POSIX
 175                        if (sb->s_flags & MS_POSIXACL)
 176                                rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
 177                                        ea_value, (const int)value_size,
 178                                        ACL_TYPE_ACCESS, cifs_sb->local_nls,
 179                                        cifs_sb->mnt_cifs_flags &
 180                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
 181                        cFYI(1, "set POSIX ACL rc %d", rc);
 182#else
 183                        cFYI(1, "set POSIX ACL not supported");
 184#endif
 185                } else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT,
 186                                   strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
 187#ifdef CONFIG_CIFS_POSIX
 188                        if (sb->s_flags & MS_POSIXACL)
 189                                rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
 190                                        ea_value, (const int)value_size,
 191                                        ACL_TYPE_DEFAULT, cifs_sb->local_nls,
 192                                        cifs_sb->mnt_cifs_flags &
 193                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
 194                        cFYI(1, "set POSIX default ACL rc %d", rc);
 195#else
 196                        cFYI(1, "set default POSIX ACL not supported");
 197#endif
 198                } else {
 199                        cFYI(1, "illegal xattr request %s (only user namespace"
 200                                " supported)", ea_name);
 201                  /* BB what if no namespace prefix? */
 202                  /* Should we just pass them to server, except for
 203                  system and perhaps security prefixes? */
 204                }
 205        }
 206
 207set_ea_exit:
 208        kfree(full_path);
 209        FreeXid(xid);
 210        cifs_put_tlink(tlink);
 211#endif
 212        return rc;
 213}
 214
 215ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
 216        void *ea_value, size_t buf_size)
 217{
 218        ssize_t rc = -EOPNOTSUPP;
 219#ifdef CONFIG_CIFS_XATTR
 220        int xid;
 221        struct cifs_sb_info *cifs_sb;
 222        struct tcon_link *tlink;
 223        struct cifsTconInfo *pTcon;
 224        struct super_block *sb;
 225        char *full_path;
 226
 227        if (direntry == NULL)
 228                return -EIO;
 229        if (direntry->d_inode == NULL)
 230                return -EIO;
 231        sb = direntry->d_inode->i_sb;
 232        if (sb == NULL)
 233                return -EIO;
 234
 235        cifs_sb = CIFS_SB(sb);
 236        tlink = cifs_sb_tlink(cifs_sb);
 237        if (IS_ERR(tlink))
 238                return PTR_ERR(tlink);
 239        pTcon = tlink_tcon(tlink);
 240
 241        xid = GetXid();
 242
 243        full_path = build_path_from_dentry(direntry);
 244        if (full_path == NULL) {
 245                rc = -ENOMEM;
 246                goto get_ea_exit;
 247        }
 248        /* return dos attributes as pseudo xattr */
 249        /* return alt name if available as pseudo attr */
 250        if (ea_name == NULL) {
 251                cFYI(1, "Null xattr names not supported");
 252        } else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5) == 0) {
 253                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
 254                        goto get_ea_exit;
 255
 256                if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0) {
 257                        cFYI(1, "attempt to query cifs inode metadata");
 258                        /* revalidate/getattr then populate from inode */
 259                } /* BB add else when above is implemented */
 260                ea_name += 5; /* skip past user. prefix */
 261                rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value,
 262                        buf_size, cifs_sb->local_nls,
 263                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 264        } else if (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4) == 0) {
 265                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
 266                        goto get_ea_exit;
 267
 268                ea_name += 4; /* skip past os2. prefix */
 269                rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value,
 270                        buf_size, cifs_sb->local_nls,
 271                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 272        } else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
 273                          strlen(POSIX_ACL_XATTR_ACCESS)) == 0) {
 274#ifdef CONFIG_CIFS_POSIX
 275                if (sb->s_flags & MS_POSIXACL)
 276                        rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
 277                                ea_value, buf_size, ACL_TYPE_ACCESS,
 278                                cifs_sb->local_nls,
 279                                cifs_sb->mnt_cifs_flags &
 280                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
 281#else
 282                cFYI(1, "Query POSIX ACL not supported yet");
 283#endif /* CONFIG_CIFS_POSIX */
 284        } else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT,
 285                          strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
 286#ifdef CONFIG_CIFS_POSIX
 287                if (sb->s_flags & MS_POSIXACL)
 288                        rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
 289                                ea_value, buf_size, ACL_TYPE_DEFAULT,
 290                                cifs_sb->local_nls,
 291                                cifs_sb->mnt_cifs_flags &
 292                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
 293#else
 294                cFYI(1, "Query POSIX default ACL not supported yet");
 295#endif /* CONFIG_CIFS_POSIX */
 296        } else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL,
 297                                strlen(CIFS_XATTR_CIFS_ACL)) == 0) {
 298#ifdef CONFIG_CIFS_ACL
 299                        u32 acllen;
 300                        struct cifs_ntsd *pacl;
 301
 302                        pacl = get_cifs_acl(cifs_sb, direntry->d_inode,
 303                                                full_path, &acllen);
 304                        if (IS_ERR(pacl)) {
 305                                rc = PTR_ERR(pacl);
 306                                cERROR(1, "%s: error %zd getting sec desc",
 307                                                __func__, rc);
 308                        } else {
 309                                if (ea_value) {
 310                                        if (acllen > buf_size)
 311                                                acllen = -ERANGE;
 312                                        else
 313                                                memcpy(ea_value, pacl, acllen);
 314                                }
 315                                rc = acllen;
 316                                kfree(pacl);
 317                        }
 318#else
 319                cFYI(1, "Query CIFS ACL not supported yet");
 320#endif /* CONFIG_CIFS_ACL */
 321        } else if (strncmp(ea_name,
 322                  CIFS_XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) == 0) {
 323                cFYI(1, "Trusted xattr namespace not supported yet");
 324        } else if (strncmp(ea_name,
 325                  CIFS_XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) == 0) {
 326                cFYI(1, "Security xattr namespace not supported yet");
 327        } else
 328                cFYI(1,
 329                    "illegal xattr request %s (only user namespace supported)",
 330                     ea_name);
 331
 332        /* We could add an additional check for streams ie
 333            if proc/fs/cifs/streamstoxattr is set then
 334                search server for EAs or streams to
 335                returns as xattrs */
 336
 337        if (rc == -EINVAL)
 338                rc = -EOPNOTSUPP;
 339
 340get_ea_exit:
 341        kfree(full_path);
 342        FreeXid(xid);
 343        cifs_put_tlink(tlink);
 344#endif
 345        return rc;
 346}
 347
 348ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
 349{
 350        ssize_t rc = -EOPNOTSUPP;
 351#ifdef CONFIG_CIFS_XATTR
 352        int xid;
 353        struct cifs_sb_info *cifs_sb;
 354        struct tcon_link *tlink;
 355        struct cifsTconInfo *pTcon;
 356        struct super_block *sb;
 357        char *full_path;
 358
 359        if (direntry == NULL)
 360                return -EIO;
 361        if (direntry->d_inode == NULL)
 362                return -EIO;
 363        sb = direntry->d_inode->i_sb;
 364        if (sb == NULL)
 365                return -EIO;
 366
 367        cifs_sb = CIFS_SB(sb);
 368        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
 369                return -EOPNOTSUPP;
 370
 371        tlink = cifs_sb_tlink(cifs_sb);
 372        if (IS_ERR(tlink))
 373                return PTR_ERR(tlink);
 374        pTcon = tlink_tcon(tlink);
 375
 376        xid = GetXid();
 377
 378        full_path = build_path_from_dentry(direntry);
 379        if (full_path == NULL) {
 380                rc = -ENOMEM;
 381                goto list_ea_exit;
 382        }
 383        /* return dos attributes as pseudo xattr */
 384        /* return alt name if available as pseudo attr */
 385
 386        /* if proc/fs/cifs/streamstoxattr is set then
 387                search server for EAs or streams to
 388                returns as xattrs */
 389        rc = CIFSSMBQAllEAs(xid, pTcon, full_path, NULL, data,
 390                                buf_size, cifs_sb->local_nls,
 391                                cifs_sb->mnt_cifs_flags &
 392                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
 393
 394list_ea_exit:
 395        kfree(full_path);
 396        FreeXid(xid);
 397        cifs_put_tlink(tlink);
 398#endif
 399        return rc;
 400}
 401