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