linux/fs/reiserfs/xattr_acl.c
<<
>>
Prefs
   1#include <linux/capability.h>
   2#include <linux/fs.h>
   3#include <linux/posix_acl.h>
   4#include <linux/reiserfs_fs.h>
   5#include <linux/errno.h>
   6#include <linux/pagemap.h>
   7#include <linux/xattr.h>
   8#include <linux/posix_acl_xattr.h>
   9#include <linux/reiserfs_xattr.h>
  10#include <linux/reiserfs_acl.h>
  11#include <asm/uaccess.h>
  12
  13static int reiserfs_set_acl(struct inode *inode, int type,
  14                            struct posix_acl *acl);
  15
  16static int
  17xattr_set_acl(struct inode *inode, int type, const void *value, size_t size)
  18{
  19        struct posix_acl *acl;
  20        int error;
  21
  22        if (!reiserfs_posixacl(inode->i_sb))
  23                return -EOPNOTSUPP;
  24        if (!is_owner_or_cap(inode))
  25                return -EPERM;
  26
  27        if (value) {
  28                acl = posix_acl_from_xattr(value, size);
  29                if (IS_ERR(acl)) {
  30                        return PTR_ERR(acl);
  31                } else if (acl) {
  32                        error = posix_acl_valid(acl);
  33                        if (error)
  34                                goto release_and_out;
  35                }
  36        } else
  37                acl = NULL;
  38
  39        error = reiserfs_set_acl(inode, type, acl);
  40
  41      release_and_out:
  42        posix_acl_release(acl);
  43        return error;
  44}
  45
  46static int
  47xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size)
  48{
  49        struct posix_acl *acl;
  50        int error;
  51
  52        if (!reiserfs_posixacl(inode->i_sb))
  53                return -EOPNOTSUPP;
  54
  55        acl = reiserfs_get_acl(inode, type);
  56        if (IS_ERR(acl))
  57                return PTR_ERR(acl);
  58        if (acl == NULL)
  59                return -ENODATA;
  60        error = posix_acl_to_xattr(acl, buffer, size);
  61        posix_acl_release(acl);
  62
  63        return error;
  64}
  65
  66/*
  67 * Convert from filesystem to in-memory representation.
  68 */
  69static struct posix_acl *posix_acl_from_disk(const void *value, size_t size)
  70{
  71        const char *end = (char *)value + size;
  72        int n, count;
  73        struct posix_acl *acl;
  74
  75        if (!value)
  76                return NULL;
  77        if (size < sizeof(reiserfs_acl_header))
  78                return ERR_PTR(-EINVAL);
  79        if (((reiserfs_acl_header *) value)->a_version !=
  80            cpu_to_le32(REISERFS_ACL_VERSION))
  81                return ERR_PTR(-EINVAL);
  82        value = (char *)value + sizeof(reiserfs_acl_header);
  83        count = reiserfs_acl_count(size);
  84        if (count < 0)
  85                return ERR_PTR(-EINVAL);
  86        if (count == 0)
  87                return NULL;
  88        acl = posix_acl_alloc(count, GFP_NOFS);
  89        if (!acl)
  90                return ERR_PTR(-ENOMEM);
  91        for (n = 0; n < count; n++) {
  92                reiserfs_acl_entry *entry = (reiserfs_acl_entry *) value;
  93                if ((char *)value + sizeof(reiserfs_acl_entry_short) > end)
  94                        goto fail;
  95                acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag);
  96                acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm);
  97                switch (acl->a_entries[n].e_tag) {
  98                case ACL_USER_OBJ:
  99                case ACL_GROUP_OBJ:
 100                case ACL_MASK:
 101                case ACL_OTHER:
 102                        value = (char *)value +
 103                            sizeof(reiserfs_acl_entry_short);
 104                        acl->a_entries[n].e_id = ACL_UNDEFINED_ID;
 105                        break;
 106
 107                case ACL_USER:
 108                case ACL_GROUP:
 109                        value = (char *)value + sizeof(reiserfs_acl_entry);
 110                        if ((char *)value > end)
 111                                goto fail;
 112                        acl->a_entries[n].e_id = le32_to_cpu(entry->e_id);
 113                        break;
 114
 115                default:
 116                        goto fail;
 117                }
 118        }
 119        if (value != end)
 120                goto fail;
 121        return acl;
 122
 123      fail:
 124        posix_acl_release(acl);
 125        return ERR_PTR(-EINVAL);
 126}
 127
 128/*
 129 * Convert from in-memory to filesystem representation.
 130 */
 131static void *posix_acl_to_disk(const struct posix_acl *acl, size_t * size)
 132{
 133        reiserfs_acl_header *ext_acl;
 134        char *e;
 135        int n;
 136
 137        *size = reiserfs_acl_size(acl->a_count);
 138        ext_acl = kmalloc(sizeof(reiserfs_acl_header) +
 139                                                  acl->a_count *
 140                                                  sizeof(reiserfs_acl_entry),
 141                                                  GFP_NOFS);
 142        if (!ext_acl)
 143                return ERR_PTR(-ENOMEM);
 144        ext_acl->a_version = cpu_to_le32(REISERFS_ACL_VERSION);
 145        e = (char *)ext_acl + sizeof(reiserfs_acl_header);
 146        for (n = 0; n < acl->a_count; n++) {
 147                reiserfs_acl_entry *entry = (reiserfs_acl_entry *) e;
 148                entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag);
 149                entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm);
 150                switch (acl->a_entries[n].e_tag) {
 151                case ACL_USER:
 152                case ACL_GROUP:
 153                        entry->e_id = cpu_to_le32(acl->a_entries[n].e_id);
 154                        e += sizeof(reiserfs_acl_entry);
 155                        break;
 156
 157                case ACL_USER_OBJ:
 158                case ACL_GROUP_OBJ:
 159                case ACL_MASK:
 160                case ACL_OTHER:
 161                        e += sizeof(reiserfs_acl_entry_short);
 162                        break;
 163
 164                default:
 165                        goto fail;
 166                }
 167        }
 168        return (char *)ext_acl;
 169
 170      fail:
 171        kfree(ext_acl);
 172        return ERR_PTR(-EINVAL);
 173}
 174
 175/*
 176 * Inode operation get_posix_acl().
 177 *
 178 * inode->i_mutex: down
 179 * BKL held [before 2.5.x]
 180 */
 181struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
 182{
 183        char *name, *value;
 184        struct posix_acl *acl, **p_acl;
 185        int size;
 186        int retval;
 187        struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
 188
 189        switch (type) {
 190        case ACL_TYPE_ACCESS:
 191                name = POSIX_ACL_XATTR_ACCESS;
 192                p_acl = &reiserfs_i->i_acl_access;
 193                break;
 194        case ACL_TYPE_DEFAULT:
 195                name = POSIX_ACL_XATTR_DEFAULT;
 196                p_acl = &reiserfs_i->i_acl_default;
 197                break;
 198        default:
 199                return ERR_PTR(-EINVAL);
 200        }
 201
 202        if (IS_ERR(*p_acl)) {
 203                if (PTR_ERR(*p_acl) == -ENODATA)
 204                        return NULL;
 205        } else if (*p_acl != NULL)
 206                return posix_acl_dup(*p_acl);
 207
 208        size = reiserfs_xattr_get(inode, name, NULL, 0);
 209        if (size < 0) {
 210                if (size == -ENODATA || size == -ENOSYS) {
 211                        *p_acl = ERR_PTR(-ENODATA);
 212                        return NULL;
 213                }
 214                return ERR_PTR(size);
 215        }
 216
 217        value = kmalloc(size, GFP_NOFS);
 218        if (!value)
 219                return ERR_PTR(-ENOMEM);
 220
 221        retval = reiserfs_xattr_get(inode, name, value, size);
 222        if (retval == -ENODATA || retval == -ENOSYS) {
 223                /* This shouldn't actually happen as it should have
 224                   been caught above.. but just in case */
 225                acl = NULL;
 226                *p_acl = ERR_PTR(-ENODATA);
 227        } else if (retval < 0) {
 228                acl = ERR_PTR(retval);
 229        } else {
 230                acl = posix_acl_from_disk(value, retval);
 231                if (!IS_ERR(acl))
 232                        *p_acl = posix_acl_dup(acl);
 233        }
 234
 235        kfree(value);
 236        return acl;
 237}
 238
 239/*
 240 * Inode operation set_posix_acl().
 241 *
 242 * inode->i_mutex: down
 243 * BKL held [before 2.5.x]
 244 */
 245static int
 246reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
 247{
 248        char *name;
 249        void *value = NULL;
 250        struct posix_acl **p_acl;
 251        size_t size;
 252        int error;
 253        struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
 254
 255        if (S_ISLNK(inode->i_mode))
 256                return -EOPNOTSUPP;
 257
 258        switch (type) {
 259        case ACL_TYPE_ACCESS:
 260                name = POSIX_ACL_XATTR_ACCESS;
 261                p_acl = &reiserfs_i->i_acl_access;
 262                if (acl) {
 263                        mode_t mode = inode->i_mode;
 264                        error = posix_acl_equiv_mode(acl, &mode);
 265                        if (error < 0)
 266                                return error;
 267                        else {
 268                                inode->i_mode = mode;
 269                                if (error == 0)
 270                                        acl = NULL;
 271                        }
 272                }
 273                break;
 274        case ACL_TYPE_DEFAULT:
 275                name = POSIX_ACL_XATTR_DEFAULT;
 276                p_acl = &reiserfs_i->i_acl_default;
 277                if (!S_ISDIR(inode->i_mode))
 278                        return acl ? -EACCES : 0;
 279                break;
 280        default:
 281                return -EINVAL;
 282        }
 283
 284        if (acl) {
 285                value = posix_acl_to_disk(acl, &size);
 286                if (IS_ERR(value))
 287                        return (int)PTR_ERR(value);
 288                error = reiserfs_xattr_set(inode, name, value, size, 0);
 289        } else {
 290                error = reiserfs_xattr_del(inode, name);
 291                if (error == -ENODATA) {
 292                        /* This may seem odd here, but it means that the ACL was set
 293                         * with a value representable with mode bits. If there was
 294                         * an ACL before, reiserfs_xattr_del already dirtied the inode.
 295                         */
 296                        mark_inode_dirty(inode);
 297                        error = 0;
 298                }
 299        }
 300
 301        kfree(value);
 302
 303        if (!error) {
 304                /* Release the old one */
 305                if (!IS_ERR(*p_acl) && *p_acl)
 306                        posix_acl_release(*p_acl);
 307
 308                if (acl == NULL)
 309                        *p_acl = ERR_PTR(-ENODATA);
 310                else
 311                        *p_acl = posix_acl_dup(acl);
 312        }
 313
 314        return error;
 315}
 316
 317/* dir->i_mutex: locked,
 318 * inode is new and not released into the wild yet */
 319int
 320reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry,
 321                             struct inode *inode)
 322{
 323        struct posix_acl *acl;
 324        int err = 0;
 325
 326        /* ACLs only get applied to files and directories */
 327        if (S_ISLNK(inode->i_mode))
 328                return 0;
 329
 330        /* ACLs can only be used on "new" objects, so if it's an old object
 331         * there is nothing to inherit from */
 332        if (get_inode_sd_version(dir) == STAT_DATA_V1)
 333                goto apply_umask;
 334
 335        /* Don't apply ACLs to objects in the .reiserfs_priv tree.. This
 336         * would be useless since permissions are ignored, and a pain because
 337         * it introduces locking cycles */
 338        if (is_reiserfs_priv_object(dir)) {
 339                reiserfs_mark_inode_private(inode);
 340                goto apply_umask;
 341        }
 342
 343        acl = reiserfs_get_acl(dir, ACL_TYPE_DEFAULT);
 344        if (IS_ERR(acl)) {
 345                if (PTR_ERR(acl) == -ENODATA)
 346                        goto apply_umask;
 347                return PTR_ERR(acl);
 348        }
 349
 350        if (acl) {
 351                struct posix_acl *acl_copy;
 352                mode_t mode = inode->i_mode;
 353                int need_acl;
 354
 355                /* Copy the default ACL to the default ACL of a new directory */
 356                if (S_ISDIR(inode->i_mode)) {
 357                        err = reiserfs_set_acl(inode, ACL_TYPE_DEFAULT, acl);
 358                        if (err)
 359                                goto cleanup;
 360                }
 361
 362                /* Now we reconcile the new ACL and the mode,
 363                   potentially modifying both */
 364                acl_copy = posix_acl_clone(acl, GFP_NOFS);
 365                if (!acl_copy) {
 366                        err = -ENOMEM;
 367                        goto cleanup;
 368                }
 369
 370                need_acl = posix_acl_create_masq(acl_copy, &mode);
 371                if (need_acl >= 0) {
 372                        if (mode != inode->i_mode) {
 373                                inode->i_mode = mode;
 374                        }
 375
 376                        /* If we need an ACL.. */
 377                        if (need_acl > 0) {
 378                                err =
 379                                    reiserfs_set_acl(inode, ACL_TYPE_ACCESS,
 380                                                     acl_copy);
 381                                if (err)
 382                                        goto cleanup_copy;
 383                        }
 384                }
 385              cleanup_copy:
 386                posix_acl_release(acl_copy);
 387              cleanup:
 388                posix_acl_release(acl);
 389        } else {
 390              apply_umask:
 391                /* no ACL, apply umask */
 392                inode->i_mode &= ~current->fs->umask;
 393        }
 394
 395        return err;
 396}
 397
 398/* Looks up and caches the result of the default ACL.
 399 * We do this so that we don't need to carry the xattr_sem into
 400 * reiserfs_new_inode if we don't need to */
 401int reiserfs_cache_default_acl(struct inode *inode)
 402{
 403        int ret = 0;
 404        if (reiserfs_posixacl(inode->i_sb) && !is_reiserfs_priv_object(inode)) {
 405                struct posix_acl *acl;
 406                reiserfs_read_lock_xattr_i(inode);
 407                reiserfs_read_lock_xattrs(inode->i_sb);
 408                acl = reiserfs_get_acl(inode, ACL_TYPE_DEFAULT);
 409                reiserfs_read_unlock_xattrs(inode->i_sb);
 410                reiserfs_read_unlock_xattr_i(inode);
 411                ret = (acl && !IS_ERR(acl));
 412                if (ret)
 413                        posix_acl_release(acl);
 414        }
 415
 416        return ret;
 417}
 418
 419int reiserfs_acl_chmod(struct inode *inode)
 420{
 421        struct posix_acl *acl, *clone;
 422        int error;
 423
 424        if (S_ISLNK(inode->i_mode))
 425                return -EOPNOTSUPP;
 426
 427        if (get_inode_sd_version(inode) == STAT_DATA_V1 ||
 428            !reiserfs_posixacl(inode->i_sb)) {
 429                return 0;
 430        }
 431
 432        reiserfs_read_lock_xattrs(inode->i_sb);
 433        acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS);
 434        reiserfs_read_unlock_xattrs(inode->i_sb);
 435        if (!acl)
 436                return 0;
 437        if (IS_ERR(acl))
 438                return PTR_ERR(acl);
 439        clone = posix_acl_clone(acl, GFP_NOFS);
 440        posix_acl_release(acl);
 441        if (!clone)
 442                return -ENOMEM;
 443        error = posix_acl_chmod_masq(clone, inode->i_mode);
 444        if (!error) {
 445                int lock = !has_xattr_dir(inode);
 446                reiserfs_write_lock_xattr_i(inode);
 447                if (lock)
 448                        reiserfs_write_lock_xattrs(inode->i_sb);
 449                else
 450                        reiserfs_read_lock_xattrs(inode->i_sb);
 451                error = reiserfs_set_acl(inode, ACL_TYPE_ACCESS, clone);
 452                if (lock)
 453                        reiserfs_write_unlock_xattrs(inode->i_sb);
 454                else
 455                        reiserfs_read_unlock_xattrs(inode->i_sb);
 456                reiserfs_write_unlock_xattr_i(inode);
 457        }
 458        posix_acl_release(clone);
 459        return error;
 460}
 461
 462static int
 463posix_acl_access_get(struct inode *inode, const char *name,
 464                     void *buffer, size_t size)
 465{
 466        if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS) - 1)
 467                return -EINVAL;
 468        return xattr_get_acl(inode, ACL_TYPE_ACCESS, buffer, size);
 469}
 470
 471static int
 472posix_acl_access_set(struct inode *inode, const char *name,
 473                     const void *value, size_t size, int flags)
 474{
 475        if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS) - 1)
 476                return -EINVAL;
 477        return xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size);
 478}
 479
 480static int posix_acl_access_del(struct inode *inode, const char *name)
 481{
 482        struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
 483        struct posix_acl **acl = &reiserfs_i->i_acl_access;
 484        if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS) - 1)
 485                return -EINVAL;
 486        if (!IS_ERR(*acl) && *acl) {
 487                posix_acl_release(*acl);
 488                *acl = ERR_PTR(-ENODATA);
 489        }
 490
 491        return 0;
 492}
 493
 494static int
 495posix_acl_access_list(struct inode *inode, const char *name, int namelen,
 496                      char *out)
 497{
 498        int len = namelen;
 499        if (!reiserfs_posixacl(inode->i_sb))
 500                return 0;
 501        if (out)
 502                memcpy(out, name, len);
 503
 504        return len;
 505}
 506
 507struct reiserfs_xattr_handler posix_acl_access_handler = {
 508        .prefix = POSIX_ACL_XATTR_ACCESS,
 509        .get = posix_acl_access_get,
 510        .set = posix_acl_access_set,
 511        .del = posix_acl_access_del,
 512        .list = posix_acl_access_list,
 513};
 514
 515static int
 516posix_acl_default_get(struct inode *inode, const char *name,
 517                      void *buffer, size_t size)
 518{
 519        if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT) - 1)
 520                return -EINVAL;
 521        return xattr_get_acl(inode, ACL_TYPE_DEFAULT, buffer, size);
 522}
 523
 524static int
 525posix_acl_default_set(struct inode *inode, const char *name,
 526                      const void *value, size_t size, int flags)
 527{
 528        if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT) - 1)
 529                return -EINVAL;
 530        return xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size);
 531}
 532
 533static int posix_acl_default_del(struct inode *inode, const char *name)
 534{
 535        struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
 536        struct posix_acl **acl = &reiserfs_i->i_acl_default;
 537        if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT) - 1)
 538                return -EINVAL;
 539        if (!IS_ERR(*acl) && *acl) {
 540                posix_acl_release(*acl);
 541                *acl = ERR_PTR(-ENODATA);
 542        }
 543
 544        return 0;
 545}
 546
 547static int
 548posix_acl_default_list(struct inode *inode, const char *name, int namelen,
 549                       char *out)
 550{
 551        int len = namelen;
 552        if (!reiserfs_posixacl(inode->i_sb))
 553                return 0;
 554        if (out)
 555                memcpy(out, name, len);
 556
 557        return len;
 558}
 559
 560struct reiserfs_xattr_handler posix_acl_default_handler = {
 561        .prefix = POSIX_ACL_XATTR_DEFAULT,
 562        .get = posix_acl_default_get,
 563        .set = posix_acl_default_set,
 564        .del = posix_acl_default_del,
 565        .list = posix_acl_default_list,
 566};
 567