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