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                cifs_dbg(FYI, "Null xattr names not supported\n");
  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                cifs_dbg(FYI,
  75                         "illegal xattr request %s (only user namespace supported)\n",
  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                cifs_dbg(FYI, "size of EA value too large\n");
 138                rc = -EOPNOTSUPP;
 139                goto set_ea_exit;
 140        }
 141
 142        if (ea_name == NULL) {
 143                cifs_dbg(FYI, "Null xattr names not supported\n");
 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                        cifs_dbg(FYI, "attempt to set cifs inode metadata\n");
 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                        rc = -ENOMEM;
 171                } else {
 172                        memcpy(pacl, ea_value, value_size);
 173                        rc = set_cifs_acl(pacl, value_size,
 174                                direntry->d_inode, full_path, CIFS_ACL_DACL);
 175                        if (rc == 0) /* force revalidate of the inode */
 176                                CIFS_I(direntry->d_inode)->time = 0;
 177                        kfree(pacl);
 178                }
 179#else
 180                cifs_dbg(FYI, "Set CIFS ACL not supported yet\n");
 181#endif /* CONFIG_CIFS_ACL */
 182        } else {
 183                int temp;
 184                temp = strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
 185                        strlen(POSIX_ACL_XATTR_ACCESS));
 186                if (temp == 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_ACCESS, cifs_sb->local_nls,
 192                                        cifs_sb->mnt_cifs_flags &
 193                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
 194                        cifs_dbg(FYI, "set POSIX ACL rc %d\n", rc);
 195#else
 196                        cifs_dbg(FYI, "set POSIX ACL not supported\n");
 197#endif
 198                } else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT,
 199                                   strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
 200#ifdef CONFIG_CIFS_POSIX
 201                        if (sb->s_flags & MS_POSIXACL)
 202                                rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
 203                                        ea_value, (const int)value_size,
 204                                        ACL_TYPE_DEFAULT, cifs_sb->local_nls,
 205                                        cifs_sb->mnt_cifs_flags &
 206                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
 207                        cifs_dbg(FYI, "set POSIX default ACL rc %d\n", rc);
 208#else
 209                        cifs_dbg(FYI, "set default POSIX ACL not supported\n");
 210#endif
 211                } else {
 212                        cifs_dbg(FYI, "illegal xattr request %s (only user namespace supported)\n",
 213                                 ea_name);
 214                  /* BB what if no namespace prefix? */
 215                  /* Should we just pass them to server, except for
 216                  system and perhaps security prefixes? */
 217                }
 218        }
 219
 220set_ea_exit:
 221        kfree(full_path);
 222        free_xid(xid);
 223        cifs_put_tlink(tlink);
 224#endif
 225        return rc;
 226}
 227
 228ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
 229        void *ea_value, size_t buf_size)
 230{
 231        ssize_t rc = -EOPNOTSUPP;
 232#ifdef CONFIG_CIFS_XATTR
 233        unsigned int xid;
 234        struct cifs_sb_info *cifs_sb;
 235        struct tcon_link *tlink;
 236        struct cifs_tcon *pTcon;
 237        struct super_block *sb;
 238        char *full_path;
 239
 240        if (direntry == NULL)
 241                return -EIO;
 242        if (direntry->d_inode == NULL)
 243                return -EIO;
 244        sb = direntry->d_inode->i_sb;
 245        if (sb == NULL)
 246                return -EIO;
 247
 248        cifs_sb = CIFS_SB(sb);
 249        tlink = cifs_sb_tlink(cifs_sb);
 250        if (IS_ERR(tlink))
 251                return PTR_ERR(tlink);
 252        pTcon = tlink_tcon(tlink);
 253
 254        xid = get_xid();
 255
 256        full_path = build_path_from_dentry(direntry);
 257        if (full_path == NULL) {
 258                rc = -ENOMEM;
 259                goto get_ea_exit;
 260        }
 261        /* return dos attributes as pseudo xattr */
 262        /* return alt name if available as pseudo attr */
 263        if (ea_name == NULL) {
 264                cifs_dbg(FYI, "Null xattr names not supported\n");
 265        } else if (strncmp(ea_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)
 266                   == 0) {
 267                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
 268                        goto get_ea_exit;
 269
 270                if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0) {
 271                        cifs_dbg(FYI, "attempt to query cifs inode metadata\n");
 272                        /* revalidate/getattr then populate from inode */
 273                } /* BB add else when above is implemented */
 274                ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */
 275                rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value,
 276                        buf_size, cifs_sb->local_nls,
 277                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 278        } else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) {
 279                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
 280                        goto get_ea_exit;
 281
 282                ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */
 283                rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value,
 284                        buf_size, cifs_sb->local_nls,
 285                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 286        } else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
 287                          strlen(POSIX_ACL_XATTR_ACCESS)) == 0) {
 288#ifdef CONFIG_CIFS_POSIX
 289                if (sb->s_flags & MS_POSIXACL)
 290                        rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
 291                                ea_value, buf_size, ACL_TYPE_ACCESS,
 292                                cifs_sb->local_nls,
 293                                cifs_sb->mnt_cifs_flags &
 294                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
 295#else
 296                cifs_dbg(FYI, "Query POSIX ACL not supported yet\n");
 297#endif /* CONFIG_CIFS_POSIX */
 298        } else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT,
 299                          strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
 300#ifdef CONFIG_CIFS_POSIX
 301                if (sb->s_flags & MS_POSIXACL)
 302                        rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
 303                                ea_value, buf_size, ACL_TYPE_DEFAULT,
 304                                cifs_sb->local_nls,
 305                                cifs_sb->mnt_cifs_flags &
 306                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
 307#else
 308                cifs_dbg(FYI, "Query POSIX default ACL not supported yet\n");
 309#endif /* CONFIG_CIFS_POSIX */
 310        } else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL,
 311                                strlen(CIFS_XATTR_CIFS_ACL)) == 0) {
 312#ifdef CONFIG_CIFS_ACL
 313                        u32 acllen;
 314                        struct cifs_ntsd *pacl;
 315
 316                        pacl = get_cifs_acl(cifs_sb, direntry->d_inode,
 317                                                full_path, &acllen);
 318                        if (IS_ERR(pacl)) {
 319                                rc = PTR_ERR(pacl);
 320                                cifs_dbg(VFS, "%s: error %zd getting sec desc\n",
 321                                         __func__, rc);
 322                        } else {
 323                                if (ea_value) {
 324                                        if (acllen > buf_size)
 325                                                acllen = -ERANGE;
 326                                        else
 327                                                memcpy(ea_value, pacl, acllen);
 328                                }
 329                                rc = acllen;
 330                                kfree(pacl);
 331                        }
 332#else
 333                        cifs_dbg(FYI, "Query CIFS ACL not supported yet\n");
 334#endif /* CONFIG_CIFS_ACL */
 335        } else if (strncmp(ea_name,
 336                  XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) == 0) {
 337                cifs_dbg(FYI, "Trusted xattr namespace not supported yet\n");
 338        } else if (strncmp(ea_name,
 339                  XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) == 0) {
 340                cifs_dbg(FYI, "Security xattr namespace not supported yet\n");
 341        } else
 342                cifs_dbg(FYI,
 343                         "illegal xattr request %s (only user namespace supported)\n",
 344                         ea_name);
 345
 346        /* We could add an additional check for streams ie
 347            if proc/fs/cifs/streamstoxattr is set then
 348                search server for EAs or streams to
 349                returns as xattrs */
 350
 351        if (rc == -EINVAL)
 352                rc = -EOPNOTSUPP;
 353
 354get_ea_exit:
 355        kfree(full_path);
 356        free_xid(xid);
 357        cifs_put_tlink(tlink);
 358#endif
 359        return rc;
 360}
 361
 362ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
 363{
 364        ssize_t rc = -EOPNOTSUPP;
 365#ifdef CONFIG_CIFS_XATTR
 366        unsigned int xid;
 367        struct cifs_sb_info *cifs_sb;
 368        struct tcon_link *tlink;
 369        struct cifs_tcon *pTcon;
 370        struct super_block *sb;
 371        char *full_path;
 372
 373        if (direntry == NULL)
 374                return -EIO;
 375        if (direntry->d_inode == NULL)
 376                return -EIO;
 377        sb = direntry->d_inode->i_sb;
 378        if (sb == NULL)
 379                return -EIO;
 380
 381        cifs_sb = CIFS_SB(sb);
 382        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
 383                return -EOPNOTSUPP;
 384
 385        tlink = cifs_sb_tlink(cifs_sb);
 386        if (IS_ERR(tlink))
 387                return PTR_ERR(tlink);
 388        pTcon = tlink_tcon(tlink);
 389
 390        xid = get_xid();
 391
 392        full_path = build_path_from_dentry(direntry);
 393        if (full_path == NULL) {
 394                rc = -ENOMEM;
 395                goto list_ea_exit;
 396        }
 397        /* return dos attributes as pseudo xattr */
 398        /* return alt name if available as pseudo attr */
 399
 400        /* if proc/fs/cifs/streamstoxattr is set then
 401                search server for EAs or streams to
 402                returns as xattrs */
 403        rc = CIFSSMBQAllEAs(xid, pTcon, full_path, NULL, data,
 404                                buf_size, cifs_sb->local_nls,
 405                                cifs_sb->mnt_cifs_flags &
 406                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
 407
 408list_ea_exit:
 409        kfree(full_path);
 410        free_xid(xid);
 411        cifs_put_tlink(tlink);
 412#endif
 413        return rc;
 414}
 415