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 "reiserfs.h"
   5#include <linux/errno.h>
   6#include <linux/pagemap.h>
   7#include <linux/xattr.h>
   8#include <linux/slab.h>
   9#include <linux/posix_acl_xattr.h>
  10#include "xattr.h"
  11#include "acl.h"
  12#include <asm/uaccess.h>
  13
  14static int reiserfs_set_acl(struct reiserfs_transaction_handle *th,
  15                            struct inode *inode, int type,
  16                            struct posix_acl *acl);
  17
  18static int
  19posix_acl_set(struct dentry *dentry, const char *name, const void *value,
  20                size_t size, int flags, int type)
  21{
  22        struct inode *inode = dentry->d_inode;
  23        struct posix_acl *acl;
  24        int error, error2;
  25        struct reiserfs_transaction_handle th;
  26        size_t jcreate_blocks;
  27        if (!reiserfs_posixacl(inode->i_sb))
  28                return -EOPNOTSUPP;
  29        if (!inode_owner_or_capable(inode))
  30                return -EPERM;
  31
  32        if (value) {
  33                acl = posix_acl_from_xattr(&init_user_ns, value, size);
  34                if (IS_ERR(acl)) {
  35                        return PTR_ERR(acl);
  36                } else if (acl) {
  37                        error = posix_acl_valid(acl);
  38                        if (error)
  39                                goto release_and_out;
  40                }
  41        } else
  42                acl = NULL;
  43
  44        /* Pessimism: We can't assume that anything from the xattr root up
  45         * has been created. */
  46
  47        jcreate_blocks = reiserfs_xattr_jcreate_nblocks(inode) +
  48                         reiserfs_xattr_nblocks(inode, size) * 2;
  49
  50        reiserfs_write_lock(inode->i_sb);
  51        error = journal_begin(&th, inode->i_sb, jcreate_blocks);
  52        reiserfs_write_unlock(inode->i_sb);
  53        if (error == 0) {
  54                error = reiserfs_set_acl(&th, inode, type, acl);
  55                reiserfs_write_lock(inode->i_sb);
  56                error2 = journal_end(&th, inode->i_sb, jcreate_blocks);
  57                reiserfs_write_unlock(inode->i_sb);
  58                if (error2)
  59                        error = error2;
  60        }
  61
  62      release_and_out:
  63        posix_acl_release(acl);
  64        return error;
  65}
  66
  67static int
  68posix_acl_get(struct dentry *dentry, const char *name, void *buffer,
  69                size_t size, int type)
  70{
  71        struct posix_acl *acl;
  72        int error;
  73
  74        if (!reiserfs_posixacl(dentry->d_sb))
  75                return -EOPNOTSUPP;
  76
  77        acl = reiserfs_get_acl(dentry->d_inode, type);
  78        if (IS_ERR(acl))
  79                return PTR_ERR(acl);
  80        if (acl == NULL)
  81                return -ENODATA;
  82        error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
  83        posix_acl_release(acl);
  84
  85        return error;
  86}
  87
  88/*
  89 * Convert from filesystem to in-memory representation.
  90 */
  91static struct posix_acl *posix_acl_from_disk(const void *value, size_t size)
  92{
  93        const char *end = (char *)value + size;
  94        int n, count;
  95        struct posix_acl *acl;
  96
  97        if (!value)
  98                return NULL;
  99        if (size < sizeof(reiserfs_acl_header))
 100                return ERR_PTR(-EINVAL);
 101        if (((reiserfs_acl_header *) value)->a_version !=
 102            cpu_to_le32(REISERFS_ACL_VERSION))
 103                return ERR_PTR(-EINVAL);
 104        value = (char *)value + sizeof(reiserfs_acl_header);
 105        count = reiserfs_acl_count(size);
 106        if (count < 0)
 107                return ERR_PTR(-EINVAL);
 108        if (count == 0)
 109                return NULL;
 110        acl = posix_acl_alloc(count, GFP_NOFS);
 111        if (!acl)
 112                return ERR_PTR(-ENOMEM);
 113        for (n = 0; n < count; n++) {
 114                reiserfs_acl_entry *entry = (reiserfs_acl_entry *) value;
 115                if ((char *)value + sizeof(reiserfs_acl_entry_short) > end)
 116                        goto fail;
 117                acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag);
 118                acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm);
 119                switch (acl->a_entries[n].e_tag) {
 120                case ACL_USER_OBJ:
 121                case ACL_GROUP_OBJ:
 122                case ACL_MASK:
 123                case ACL_OTHER:
 124                        value = (char *)value +
 125                            sizeof(reiserfs_acl_entry_short);
 126                        break;
 127
 128                case ACL_USER:
 129                        value = (char *)value + sizeof(reiserfs_acl_entry);
 130                        if ((char *)value > end)
 131                                goto fail;
 132                        acl->a_entries[n].e_uid = 
 133                                make_kuid(&init_user_ns,
 134                                          le32_to_cpu(entry->e_id));
 135                        break;
 136                case ACL_GROUP:
 137                        value = (char *)value + sizeof(reiserfs_acl_entry);
 138                        if ((char *)value > end)
 139                                goto fail;
 140                        acl->a_entries[n].e_gid =
 141                                make_kgid(&init_user_ns,
 142                                          le32_to_cpu(entry->e_id));
 143                        break;
 144
 145                default:
 146                        goto fail;
 147                }
 148        }
 149        if (value != end)
 150                goto fail;
 151        return acl;
 152
 153      fail:
 154        posix_acl_release(acl);
 155        return ERR_PTR(-EINVAL);
 156}
 157
 158/*
 159 * Convert from in-memory to filesystem representation.
 160 */
 161static void *posix_acl_to_disk(const struct posix_acl *acl, size_t * size)
 162{
 163        reiserfs_acl_header *ext_acl;
 164        char *e;
 165        int n;
 166
 167        *size = reiserfs_acl_size(acl->a_count);
 168        ext_acl = kmalloc(sizeof(reiserfs_acl_header) +
 169                                                  acl->a_count *
 170                                                  sizeof(reiserfs_acl_entry),
 171                                                  GFP_NOFS);
 172        if (!ext_acl)
 173                return ERR_PTR(-ENOMEM);
 174        ext_acl->a_version = cpu_to_le32(REISERFS_ACL_VERSION);
 175        e = (char *)ext_acl + sizeof(reiserfs_acl_header);
 176        for (n = 0; n < acl->a_count; n++) {
 177                const struct posix_acl_entry *acl_e = &acl->a_entries[n];
 178                reiserfs_acl_entry *entry = (reiserfs_acl_entry *) e;
 179                entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag);
 180                entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm);
 181                switch (acl->a_entries[n].e_tag) {
 182                case ACL_USER:
 183                        entry->e_id = cpu_to_le32(
 184                                from_kuid(&init_user_ns, acl_e->e_uid));
 185                        e += sizeof(reiserfs_acl_entry);
 186                        break;
 187                case ACL_GROUP:
 188                        entry->e_id = cpu_to_le32(
 189                                from_kgid(&init_user_ns, acl_e->e_gid));
 190                        e += sizeof(reiserfs_acl_entry);
 191                        break;
 192
 193                case ACL_USER_OBJ:
 194                case ACL_GROUP_OBJ:
 195                case ACL_MASK:
 196                case ACL_OTHER:
 197                        e += sizeof(reiserfs_acl_entry_short);
 198                        break;
 199
 200                default:
 201                        goto fail;
 202                }
 203        }
 204        return (char *)ext_acl;
 205
 206      fail:
 207        kfree(ext_acl);
 208        return ERR_PTR(-EINVAL);
 209}
 210
 211/*
 212 * Inode operation get_posix_acl().
 213 *
 214 * inode->i_mutex: down
 215 * BKL held [before 2.5.x]
 216 */
 217struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
 218{
 219        char *name, *value;
 220        struct posix_acl *acl;
 221        int size;
 222        int retval;
 223
 224        acl = get_cached_acl(inode, type);
 225        if (acl != ACL_NOT_CACHED)
 226                return acl;
 227
 228        switch (type) {
 229        case ACL_TYPE_ACCESS:
 230                name = POSIX_ACL_XATTR_ACCESS;
 231                break;
 232        case ACL_TYPE_DEFAULT:
 233                name = POSIX_ACL_XATTR_DEFAULT;
 234                break;
 235        default:
 236                BUG();
 237        }
 238
 239        size = reiserfs_xattr_get(inode, name, NULL, 0);
 240        if (size < 0) {
 241                if (size == -ENODATA || size == -ENOSYS) {
 242                        set_cached_acl(inode, type, NULL);
 243                        return NULL;
 244                }
 245                return ERR_PTR(size);
 246        }
 247
 248        value = kmalloc(size, GFP_NOFS);
 249        if (!value)
 250                return ERR_PTR(-ENOMEM);
 251
 252        retval = reiserfs_xattr_get(inode, name, value, size);
 253        if (retval == -ENODATA || retval == -ENOSYS) {
 254                /* This shouldn't actually happen as it should have
 255                   been caught above.. but just in case */
 256                acl = NULL;
 257        } else if (retval < 0) {
 258                acl = ERR_PTR(retval);
 259        } else {
 260                acl = posix_acl_from_disk(value, retval);
 261        }
 262        if (!IS_ERR(acl))
 263                set_cached_acl(inode, type, acl);
 264
 265        kfree(value);
 266        return acl;
 267}
 268
 269/*
 270 * Inode operation set_posix_acl().
 271 *
 272 * inode->i_mutex: down
 273 * BKL held [before 2.5.x]
 274 */
 275static int
 276reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
 277                 int type, struct posix_acl *acl)
 278{
 279        char *name;
 280        void *value = NULL;
 281        size_t size = 0;
 282        int error;
 283
 284        if (S_ISLNK(inode->i_mode))
 285                return -EOPNOTSUPP;
 286
 287        switch (type) {
 288        case ACL_TYPE_ACCESS:
 289                name = POSIX_ACL_XATTR_ACCESS;
 290                if (acl) {
 291                        error = posix_acl_equiv_mode(acl, &inode->i_mode);
 292                        if (error < 0)
 293                                return error;
 294                        else {
 295                                if (error == 0)
 296                                        acl = NULL;
 297                        }
 298                }
 299                break;
 300        case ACL_TYPE_DEFAULT:
 301                name = POSIX_ACL_XATTR_DEFAULT;
 302                if (!S_ISDIR(inode->i_mode))
 303                        return acl ? -EACCES : 0;
 304                break;
 305        default:
 306                return -EINVAL;
 307        }
 308
 309        if (acl) {
 310                value = posix_acl_to_disk(acl, &size);
 311                if (IS_ERR(value))
 312                        return (int)PTR_ERR(value);
 313        }
 314
 315        error = reiserfs_xattr_set_handle(th, inode, name, value, size, 0);
 316
 317        /*
 318         * Ensure that the inode gets dirtied if we're only using
 319         * the mode bits and an old ACL didn't exist. We don't need
 320         * to check if the inode is hashed here since we won't get
 321         * called by reiserfs_inherit_default_acl().
 322         */
 323        if (error == -ENODATA) {
 324                error = 0;
 325                if (type == ACL_TYPE_ACCESS) {
 326                        inode->i_ctime = CURRENT_TIME_SEC;
 327                        mark_inode_dirty(inode);
 328                }
 329        }
 330
 331        kfree(value);
 332
 333        if (!error)
 334                set_cached_acl(inode, type, acl);
 335
 336        return error;
 337}
 338
 339/* dir->i_mutex: locked,
 340 * inode is new and not released into the wild yet */
 341int
 342reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
 343                             struct inode *dir, struct dentry *dentry,
 344                             struct inode *inode)
 345{
 346        struct posix_acl *acl;
 347        int err = 0;
 348
 349        /* ACLs only get applied to files and directories */
 350        if (S_ISLNK(inode->i_mode))
 351                return 0;
 352
 353        /* ACLs can only be used on "new" objects, so if it's an old object
 354         * there is nothing to inherit from */
 355        if (get_inode_sd_version(dir) == STAT_DATA_V1)
 356                goto apply_umask;
 357
 358        /* Don't apply ACLs to objects in the .reiserfs_priv tree.. This
 359         * would be useless since permissions are ignored, and a pain because
 360         * it introduces locking cycles */
 361        if (IS_PRIVATE(dir)) {
 362                inode->i_flags |= S_PRIVATE;
 363                goto apply_umask;
 364        }
 365
 366        acl = reiserfs_get_acl(dir, ACL_TYPE_DEFAULT);
 367        if (IS_ERR(acl))
 368                return PTR_ERR(acl);
 369
 370        if (acl) {
 371                /* Copy the default ACL to the default ACL of a new directory */
 372                if (S_ISDIR(inode->i_mode)) {
 373                        err = reiserfs_set_acl(th, inode, ACL_TYPE_DEFAULT,
 374                                               acl);
 375                        if (err)
 376                                goto cleanup;
 377                }
 378
 379                /* Now we reconcile the new ACL and the mode,
 380                   potentially modifying both */
 381                err = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
 382                if (err < 0)
 383                        return err;
 384
 385                /* If we need an ACL.. */
 386                if (err > 0)
 387                        err = reiserfs_set_acl(th, inode, ACL_TYPE_ACCESS, acl);
 388              cleanup:
 389                posix_acl_release(acl);
 390        } else {
 391              apply_umask:
 392                /* no ACL, apply umask */
 393                inode->i_mode &= ~current_umask();
 394        }
 395
 396        return err;
 397}
 398
 399/* This is used to cache the default acl before a new object is created.
 400 * The biggest reason for this is to get an idea of how many blocks will
 401 * actually be required for the create operation if we must inherit an ACL.
 402 * An ACL write can add up to 3 object creations and an additional file write
 403 * so we'd prefer not to reserve that many blocks in the journal if we can.
 404 * It also has the advantage of not loading the ACL with a transaction open,
 405 * this may seem silly, but if the owner of the directory is doing the
 406 * creation, the ACL may not be loaded since the permissions wouldn't require
 407 * it.
 408 * We return the number of blocks required for the transaction.
 409 */
 410int reiserfs_cache_default_acl(struct inode *inode)
 411{
 412        struct posix_acl *acl;
 413        int nblocks = 0;
 414
 415        if (IS_PRIVATE(inode))
 416                return 0;
 417
 418        acl = reiserfs_get_acl(inode, ACL_TYPE_DEFAULT);
 419
 420        if (acl && !IS_ERR(acl)) {
 421                int size = reiserfs_acl_size(acl->a_count);
 422
 423                /* Other xattrs can be created during inode creation. We don't
 424                 * want to claim too many blocks, so we check to see if we
 425                 * we need to create the tree to the xattrs, and then we
 426                 * just want two files. */
 427                nblocks = reiserfs_xattr_jcreate_nblocks(inode);
 428                nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb);
 429
 430                REISERFS_I(inode)->i_flags |= i_has_xattr_dir;
 431
 432                /* We need to account for writes + bitmaps for two files */
 433                nblocks += reiserfs_xattr_nblocks(inode, size) * 4;
 434                posix_acl_release(acl);
 435        }
 436
 437        return nblocks;
 438}
 439
 440/*
 441 * Called under i_mutex
 442 */
 443int reiserfs_acl_chmod(struct inode *inode)
 444{
 445        struct reiserfs_transaction_handle th;
 446        struct posix_acl *acl;
 447        size_t size;
 448        int error;
 449
 450        if (IS_PRIVATE(inode))
 451                return 0;
 452
 453        if (S_ISLNK(inode->i_mode))
 454                return -EOPNOTSUPP;
 455
 456        if (get_inode_sd_version(inode) == STAT_DATA_V1 ||
 457            !reiserfs_posixacl(inode->i_sb)) {
 458                return 0;
 459        }
 460
 461        acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS);
 462        if (!acl)
 463                return 0;
 464        if (IS_ERR(acl))
 465                return PTR_ERR(acl);
 466        error = posix_acl_chmod(&acl, GFP_NOFS, inode->i_mode);
 467        if (error)
 468                return error;
 469
 470        size = reiserfs_xattr_nblocks(inode, reiserfs_acl_size(acl->a_count));
 471        reiserfs_write_lock(inode->i_sb);
 472        error = journal_begin(&th, inode->i_sb, size * 2);
 473        reiserfs_write_unlock(inode->i_sb);
 474        if (!error) {
 475                int error2;
 476                error = reiserfs_set_acl(&th, inode, ACL_TYPE_ACCESS, acl);
 477                reiserfs_write_lock(inode->i_sb);
 478                error2 = journal_end(&th, inode->i_sb, size * 2);
 479                reiserfs_write_unlock(inode->i_sb);
 480                if (error2)
 481                        error = error2;
 482        }
 483        posix_acl_release(acl);
 484        return error;
 485}
 486
 487static size_t posix_acl_access_list(struct dentry *dentry, char *list,
 488                                    size_t list_size, const char *name,
 489                                    size_t name_len, int type)
 490{
 491        const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS);
 492        if (!reiserfs_posixacl(dentry->d_sb))
 493                return 0;
 494        if (list && size <= list_size)
 495                memcpy(list, POSIX_ACL_XATTR_ACCESS, size);
 496        return size;
 497}
 498
 499const struct xattr_handler reiserfs_posix_acl_access_handler = {
 500        .prefix = POSIX_ACL_XATTR_ACCESS,
 501        .flags = ACL_TYPE_ACCESS,
 502        .get = posix_acl_get,
 503        .set = posix_acl_set,
 504        .list = posix_acl_access_list,
 505};
 506
 507static size_t posix_acl_default_list(struct dentry *dentry, char *list,
 508                                     size_t list_size, const char *name,
 509                                     size_t name_len, int type)
 510{
 511        const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT);
 512        if (!reiserfs_posixacl(dentry->d_sb))
 513                return 0;
 514        if (list && size <= list_size)
 515                memcpy(list, POSIX_ACL_XATTR_DEFAULT, size);
 516        return size;
 517}
 518
 519const struct xattr_handler reiserfs_posix_acl_default_handler = {
 520        .prefix = POSIX_ACL_XATTR_DEFAULT,
 521        .flags = ACL_TYPE_DEFAULT,
 522        .get = posix_acl_get,
 523        .set = posix_acl_set,
 524        .list = posix_acl_default_list,
 525};
 526