linux-old/fs/xfs/xfs_acl.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2001-2002 Silicon Graphics, Inc.  All Rights Reserved.
   3 *
   4 * This program is free software; you can redistribute it and/or modify it
   5 * under the terms of version 2 of the GNU General Public License as
   6 * published by the Free Software Foundation.
   7 *
   8 * This program is distributed in the hope that it would be useful, but
   9 * WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11 *
  12 * Further, this software is distributed without any warranty that it is
  13 * free of the rightful claim of any third person regarding infringement
  14 * or the like.  Any license provided herein, whether implied or
  15 * otherwise, applies only to this software file.  Patent licenses, if
  16 * any, provided herein do not apply to combinations of this program with
  17 * other software, or any other product whatsoever.
  18 *
  19 * You should have received a copy of the GNU General Public License along
  20 * with this program; if not, write the Free Software Foundation, Inc., 59
  21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
  22 *
  23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
  24 * Mountain View, CA  94043, or:
  25 *
  26 * http://www.sgi.com
  27 *
  28 * For further information regarding this notice, see:
  29 *
  30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
  31 */
  32
  33#include "xfs.h"
  34
  35#include "xfs_inum.h"
  36#include "xfs_dir.h"
  37#include "xfs_dir2.h"
  38#include "xfs_alloc_btree.h"
  39#include "xfs_bmap_btree.h"
  40#include "xfs_ialloc_btree.h"
  41#include "xfs_btree.h"
  42#include "xfs_attr_sf.h"
  43#include "xfs_dir_sf.h"
  44#include "xfs_dir2_sf.h"
  45#include "xfs_dinode.h"
  46#include "xfs_inode.h"
  47#include "xfs_acl.h"
  48#include "xfs_mac.h"
  49#include "xfs_attr.h"
  50
  51#include <linux/posix_acl_xattr.h>
  52
  53STATIC int      xfs_acl_setmode(vnode_t *, xfs_acl_t *, int *);
  54STATIC void     xfs_acl_filter_mode(mode_t, xfs_acl_t *);
  55STATIC void     xfs_acl_get_endian(xfs_acl_t *);
  56STATIC int      xfs_acl_access(uid_t, gid_t, xfs_acl_t *, mode_t, cred_t *);
  57STATIC int      xfs_acl_invalid(xfs_acl_t *);
  58STATIC void     xfs_acl_sync_mode(mode_t, xfs_acl_t *);
  59STATIC void     xfs_acl_get_attr(vnode_t *, xfs_acl_t *, int, int, int *);
  60STATIC void     xfs_acl_set_attr(vnode_t *, xfs_acl_t *, int, int *);
  61STATIC int      xfs_acl_allow_set(vnode_t *, int);
  62
  63kmem_zone_t *xfs_acl_zone;
  64
  65
  66/*
  67 * Test for existence of access ACL attribute as efficiently as possible.
  68 */
  69int
  70xfs_acl_vhasacl_access(
  71        vnode_t         *vp)
  72{
  73        int             error;
  74
  75        xfs_acl_get_attr(vp, NULL, _ACL_TYPE_ACCESS, ATTR_KERNOVAL, &error);
  76        return (error == 0);
  77}
  78
  79/*
  80 * Test for existence of default ACL attribute as efficiently as possible.
  81 */
  82int
  83xfs_acl_vhasacl_default(
  84        vnode_t         *vp)
  85{
  86        int             error;
  87
  88        if (vp->v_type != VDIR)
  89                return 0;
  90        xfs_acl_get_attr(vp, NULL, _ACL_TYPE_DEFAULT, ATTR_KERNOVAL, &error);
  91        return (error == 0);
  92}
  93
  94/*
  95 * Convert from extended attribute representation to in-memory for XFS.
  96 */
  97STATIC int
  98posix_acl_xattr_to_xfs(
  99        posix_acl_xattr_header  *src,
 100        size_t                  size,
 101        xfs_acl_t               *dest)
 102{
 103        posix_acl_xattr_entry   *src_entry;
 104        xfs_acl_entry_t         *dest_entry;
 105        int                     n;
 106
 107        if (!src || !dest)
 108                return EINVAL;
 109
 110        if (size < sizeof(posix_acl_xattr_header))
 111                return EINVAL;
 112
 113        if (src->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
 114                return EOPNOTSUPP;
 115
 116        memset(dest, 0, sizeof(xfs_acl_t));
 117        dest->acl_cnt = posix_acl_xattr_count(size);
 118        if (dest->acl_cnt < 0 || dest->acl_cnt > XFS_ACL_MAX_ENTRIES)
 119                return EINVAL;
 120
 121        /*
 122         * acl_set_file(3) may request that we set default ACLs with
 123         * zero length -- defend (gracefully) against that here.
 124         */
 125        if (!dest->acl_cnt)
 126                return 0;
 127
 128        src_entry = (posix_acl_xattr_entry *)((char *)src + sizeof(*src));
 129        dest_entry = &dest->acl_entry[0];
 130
 131        for (n = 0; n < dest->acl_cnt; n++, src_entry++, dest_entry++) {
 132                dest_entry->ae_perm = le16_to_cpu(src_entry->e_perm);
 133                if (_ACL_PERM_INVALID(dest_entry->ae_perm))
 134                        return EINVAL;
 135                dest_entry->ae_tag  = le16_to_cpu(src_entry->e_tag);
 136                switch(dest_entry->ae_tag) {
 137                case ACL_USER:
 138                case ACL_GROUP:
 139                        dest_entry->ae_id = le32_to_cpu(src_entry->e_id);
 140                        break;
 141                case ACL_USER_OBJ:
 142                case ACL_GROUP_OBJ:
 143                case ACL_MASK:
 144                case ACL_OTHER:
 145                        dest_entry->ae_id = ACL_UNDEFINED_ID;
 146                        break;
 147                default:
 148                        return EINVAL;
 149                }
 150        }
 151        if (xfs_acl_invalid(dest))
 152                return EINVAL;
 153
 154        return 0;
 155}
 156
 157/*
 158 * Comparison function called from qsort().
 159 * Primary key is ae_tag, secondary key is ae_id.
 160 */
 161STATIC int
 162xfs_acl_entry_compare(
 163        const void      *va,
 164        const void      *vb)
 165{
 166        xfs_acl_entry_t *a = (xfs_acl_entry_t *)va,
 167                        *b = (xfs_acl_entry_t *)vb;
 168
 169        if (a->ae_tag == b->ae_tag)
 170                return (a->ae_id - b->ae_id);
 171        return (a->ae_tag - b->ae_tag);
 172}
 173
 174/*
 175 * Convert from in-memory XFS to extended attribute representation.
 176 */
 177STATIC int
 178posix_acl_xfs_to_xattr(
 179        xfs_acl_t               *src,
 180        posix_acl_xattr_header  *dest,
 181        size_t                  size)
 182{
 183        int                     n;
 184        size_t                  new_size = posix_acl_xattr_size(src->acl_cnt);
 185        posix_acl_xattr_entry   *dest_entry;
 186        xfs_acl_entry_t         *src_entry;
 187
 188        if (size < new_size)
 189                return -ERANGE;
 190
 191        /* Need to sort src XFS ACL by <ae_tag,ae_id> */
 192        qsort(src->acl_entry, src->acl_cnt, sizeof(src->acl_entry[0]),
 193                xfs_acl_entry_compare);
 194
 195        dest->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
 196        dest_entry = &dest->a_entries[0];
 197        src_entry = &src->acl_entry[0];
 198        for (n = 0; n < src->acl_cnt; n++, dest_entry++, src_entry++) {
 199                dest_entry->e_perm = cpu_to_le16(src_entry->ae_perm);
 200                if (_ACL_PERM_INVALID(src_entry->ae_perm))
 201                        return -EINVAL;
 202                dest_entry->e_tag  = cpu_to_le16(src_entry->ae_tag);
 203                switch (src_entry->ae_tag) {
 204                case ACL_USER:
 205                case ACL_GROUP:
 206                        dest_entry->e_id = cpu_to_le32(src_entry->ae_id);
 207                                break;
 208                case ACL_USER_OBJ:
 209                case ACL_GROUP_OBJ:
 210                case ACL_MASK:
 211                case ACL_OTHER:
 212                        dest_entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID);
 213                        break;
 214                default:
 215                        return -EINVAL;
 216                }
 217        }
 218        return new_size;
 219}
 220
 221int
 222xfs_acl_vget(
 223        vnode_t         *vp,
 224        void            *acl,
 225        size_t          size,
 226        int             kind)
 227{
 228        int                     error;
 229        xfs_acl_t               *xfs_acl = NULL;
 230        posix_acl_xattr_header  *ext_acl = acl;
 231        int                     flags = 0;
 232
 233        VN_HOLD(vp);
 234        if(size) {
 235                if (!(_ACL_ALLOC(xfs_acl))) {
 236                        error = ENOMEM;
 237                        goto out;
 238                }
 239                memset(xfs_acl, 0, sizeof(xfs_acl_t));
 240        } else
 241                flags = ATTR_KERNOVAL;
 242
 243        xfs_acl_get_attr(vp, xfs_acl, kind, flags, &error);
 244        if (error)
 245                goto out;
 246
 247        if (!size) {
 248                error = -posix_acl_xattr_size(XFS_ACL_MAX_ENTRIES);
 249        } else {
 250                if (xfs_acl_invalid(xfs_acl)) {
 251                        error = EINVAL;
 252                        goto out;
 253                }
 254                if (kind == _ACL_TYPE_ACCESS) {
 255                        vattr_t va;
 256
 257                        va.va_mask = XFS_AT_MODE;
 258                        VOP_GETATTR(vp, &va, 0, sys_cred, error);
 259                        if (error)
 260                                goto out;
 261                        xfs_acl_sync_mode(va.va_mode, xfs_acl);
 262                }
 263                error = -posix_acl_xfs_to_xattr(xfs_acl, ext_acl, size);
 264        }
 265out:
 266        VN_RELE(vp);
 267        if(xfs_acl)
 268                _ACL_FREE(xfs_acl);
 269        return -error;
 270}
 271
 272int
 273xfs_acl_vremove(
 274        vnode_t         *vp,
 275        int             kind)
 276{
 277        int             error;
 278
 279        VN_HOLD(vp);
 280        error = xfs_acl_allow_set(vp, kind);
 281        if (!error) {
 282                VOP_ATTR_REMOVE(vp, kind == _ACL_TYPE_DEFAULT?
 283                                SGI_ACL_DEFAULT: SGI_ACL_FILE,
 284                                ATTR_ROOT, sys_cred, error);
 285                if (error == ENOATTR)
 286                        error = 0;      /* 'scool */
 287        }
 288        VN_RELE(vp);
 289        return -error;
 290}
 291
 292int
 293xfs_acl_vset(
 294        vnode_t                 *vp,
 295        void                    *acl,
 296        size_t                  size,
 297        int                     kind)
 298{
 299        posix_acl_xattr_header  *ext_acl = acl;
 300        xfs_acl_t               *xfs_acl;
 301        int                     error;
 302        int                     basicperms = 0; /* more than std unix perms? */
 303
 304        if (!acl)
 305                return -EINVAL;
 306
 307        if (!(_ACL_ALLOC(xfs_acl)))
 308                return -ENOMEM;
 309
 310        error = posix_acl_xattr_to_xfs(ext_acl, size, xfs_acl);
 311        if (error) {
 312                _ACL_FREE(xfs_acl);
 313                return -error;
 314        }
 315        if (!xfs_acl->acl_cnt) {
 316                _ACL_FREE(xfs_acl);
 317                return 0;
 318        }
 319
 320        VN_HOLD(vp);
 321        error = xfs_acl_allow_set(vp, kind);
 322        if (error)
 323                goto out;
 324
 325        /* Incoming ACL exists, set file mode based on its value */
 326        if (kind == _ACL_TYPE_ACCESS)
 327                xfs_acl_setmode(vp, xfs_acl, &basicperms);
 328
 329        /*
 330         * If we have more than std unix permissions, set up the actual attr.
 331         * Otherwise, delete any existing attr.  This prevents us from
 332         * having actual attrs for permissions that can be stored in the
 333         * standard permission bits.
 334         */
 335        if (!basicperms) {
 336                xfs_acl_set_attr(vp, xfs_acl, kind, &error);
 337        } else {
 338                xfs_acl_vremove(vp, _ACL_TYPE_ACCESS);
 339        }
 340
 341out:
 342        VN_RELE(vp);
 343        _ACL_FREE(xfs_acl);
 344        return -error;
 345}
 346
 347int
 348xfs_acl_iaccess(
 349        xfs_inode_t     *ip,
 350        mode_t          mode,
 351        cred_t          *cr)
 352{
 353        xfs_acl_t       *acl;
 354        int             rval;
 355
 356        if (!(_ACL_ALLOC(acl)))
 357                return -1;
 358
 359        /* If the file has no ACL return -1. */
 360        rval = sizeof(xfs_acl_t);
 361        if (xfs_attr_fetch(ip, SGI_ACL_FILE, SGI_ACL_FILE_SIZE,
 362                        (char *)acl, &rval, ATTR_ROOT | ATTR_KERNACCESS, cr)) {
 363                _ACL_FREE(acl);
 364                return -1;
 365        }
 366        xfs_acl_get_endian(acl);
 367
 368        /* If the file has an empty ACL return -1. */
 369        if (acl->acl_cnt == XFS_ACL_NOT_PRESENT) {
 370                _ACL_FREE(acl);
 371                return -1;
 372        }
 373
 374        /* Synchronize ACL with mode bits */
 375        xfs_acl_sync_mode(ip->i_d.di_mode, acl);
 376
 377        rval = xfs_acl_access(ip->i_d.di_uid, ip->i_d.di_gid, acl, mode, cr);
 378        _ACL_FREE(acl);
 379        return rval;
 380}
 381
 382STATIC int
 383xfs_acl_allow_set(
 384        vnode_t         *vp,
 385        int             kind)
 386{
 387        vattr_t         va;
 388        int             error;
 389
 390        if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND))
 391                return EPERM;
 392        if (kind == _ACL_TYPE_DEFAULT && vp->v_type != VDIR)
 393                return ENOTDIR;
 394        if (vp->v_vfsp->vfs_flag & VFS_RDONLY)
 395                return EROFS;
 396        va.va_mask = XFS_AT_UID;
 397        VOP_GETATTR(vp, &va, 0, NULL, error);
 398        if (error)
 399                return error;
 400        if (va.va_uid != current->fsuid && !capable(CAP_FOWNER))
 401                return EPERM;
 402        return error;
 403}
 404
 405/*
 406 * Look for any effective exec access, to allow CAP_DAC_OVERRIDE for exec.
 407 * Ignore checking for exec in USER_OBJ when there is no mask, because
 408 * in this "minimal acl" case we don't have any actual acls, and we
 409 * won't even be here.
 410 */
 411STATIC int
 412xfs_acl_find_any_exec(
 413        xfs_acl_t       *fap)
 414{
 415        int             i;
 416        int             masked_aces = 0;
 417        int             mask = 0;
 418
 419        for (i = 0; i < fap->acl_cnt; i++) {
 420                if (fap->acl_entry[i].ae_perm & ACL_EXECUTE) {
 421                        if (fap->acl_entry[i].ae_tag & (ACL_USER_OBJ|ACL_OTHER))
 422                                return 1;
 423
 424                        if (fap->acl_entry[i].ae_tag == ACL_MASK)
 425                                mask = fap->acl_entry[i].ae_perm;
 426                        else
 427                                masked_aces |= fap->acl_entry[i].ae_perm;
 428
 429                        if ((mask & masked_aces) & ACL_EXECUTE)
 430                                return 1;
 431                }
 432        }
 433
 434        return 0;
 435}
 436
 437/*
 438 * The access control process to determine the access permission:
 439 *      if uid == file owner id, use the file owner bits.
 440 *      if gid == file owner group id, use the file group bits.
 441 *      scan ACL for a maching user or group, and use matched entry
 442 *      permission. Use total permissions of all matching group entries,
 443 *      until all acl entries are exhausted. The final permission produced
 444 *      by matching acl entry or entries needs to be & with group permission.
 445 *      if not owner, owning group, or matching entry in ACL, use file
 446 *      other bits.  Don't allow CAP_DAC_OVERRIDE on exec access unless
 447 *      there is some effective exec access somewhere.
 448 */
 449STATIC int
 450xfs_acl_capability_check(
 451        mode_t          mode,
 452        cred_t          *cr,
 453        xfs_acl_t       *fap)
 454{
 455        if ((mode & ACL_READ) && !capable_cred(cr, CAP_DAC_READ_SEARCH))
 456                return EACCES;
 457        if ((mode & ACL_WRITE) && !capable_cred(cr, CAP_DAC_OVERRIDE))
 458                return EACCES;
 459        if ((mode & ACL_EXECUTE) &&
 460            (!capable_cred(cr, CAP_DAC_OVERRIDE) ||
 461             !xfs_acl_find_any_exec(fap))) {
 462                return EACCES;
 463        }
 464
 465        return 0;
 466}
 467
 468/*
 469 * Note: cr is only used here for the capability check if the ACL test fails.
 470 *       It is not used to find out the credentials uid or groups etc, as was
 471 *       done in IRIX. It is assumed that the uid and groups for the current
 472 *       thread are taken from "current" instead of the cr parameter.
 473 */
 474STATIC int
 475xfs_acl_access(
 476        uid_t           fuid,
 477        gid_t           fgid,
 478        xfs_acl_t       *fap,
 479        mode_t          md,
 480        cred_t          *cr)
 481{
 482        xfs_acl_entry_t matched;
 483        int             i, allows;
 484        int             maskallows = -1;        /* true, but not 1, either */
 485        int             seen_userobj = 0;
 486
 487        matched.ae_tag = 0;     /* Invalid type */
 488        md >>= 6;       /* Normalize the bits for comparison */
 489
 490        for (i = 0; i < fap->acl_cnt; i++) {
 491                /*
 492                 * Break out if we've got a user_obj entry or
 493                 * a user entry and the mask (and have processed USER_OBJ)
 494                 */
 495                if (matched.ae_tag == ACL_USER_OBJ)
 496                        break;
 497                if (matched.ae_tag == ACL_USER) {
 498                        if (maskallows != -1 && seen_userobj)
 499                                break;
 500                        if (fap->acl_entry[i].ae_tag != ACL_MASK &&
 501                            fap->acl_entry[i].ae_tag != ACL_USER_OBJ)
 502                                continue;
 503                }
 504                /* True if this entry allows the requested access */
 505                allows = ((fap->acl_entry[i].ae_perm & md) == md);
 506
 507                switch (fap->acl_entry[i].ae_tag) {
 508                case ACL_USER_OBJ:
 509                        seen_userobj = 1;
 510                        if (fuid != current->fsuid)
 511                                continue;
 512                        matched.ae_tag = ACL_USER_OBJ;
 513                        matched.ae_perm = allows;
 514                        break;
 515                case ACL_USER:
 516                        if (fap->acl_entry[i].ae_id != current->fsuid)
 517                                continue;
 518                        matched.ae_tag = ACL_USER;
 519                        matched.ae_perm = allows;
 520                        break;
 521                case ACL_GROUP_OBJ:
 522                        if ((matched.ae_tag == ACL_GROUP_OBJ ||
 523                            matched.ae_tag == ACL_GROUP) && !allows)
 524                                continue;
 525                        if (!in_group_p(fgid))
 526                                continue;
 527                        matched.ae_tag = ACL_GROUP_OBJ;
 528                        matched.ae_perm = allows;
 529                        break;
 530                case ACL_GROUP:
 531                        if ((matched.ae_tag == ACL_GROUP_OBJ ||
 532                            matched.ae_tag == ACL_GROUP) && !allows)
 533                                continue;
 534                        if (!in_group_p(fap->acl_entry[i].ae_id))
 535                                continue;
 536                        matched.ae_tag = ACL_GROUP;
 537                        matched.ae_perm = allows;
 538                        break;
 539                case ACL_MASK:
 540                        maskallows = allows;
 541                        break;
 542                case ACL_OTHER:
 543                        if (matched.ae_tag != 0)
 544                                continue;
 545                        matched.ae_tag = ACL_OTHER;
 546                        matched.ae_perm = allows;
 547                        break;
 548                }
 549        }
 550        /*
 551         * First possibility is that no matched entry allows access.
 552         * The capability to override DAC may exist, so check for it.
 553         */
 554        switch (matched.ae_tag) {
 555        case ACL_OTHER:
 556        case ACL_USER_OBJ:
 557                if (matched.ae_perm)
 558                        return 0;
 559                break;
 560        case ACL_USER:
 561        case ACL_GROUP_OBJ:
 562        case ACL_GROUP:
 563                if (maskallows && matched.ae_perm)
 564                        return 0;
 565                break;
 566        case 0:
 567                break;
 568        }
 569
 570        return xfs_acl_capability_check(md, cr, fap);
 571}
 572
 573/*
 574 * ACL validity checker.
 575 *   This acl validation routine checks each ACL entry read in makes sense.
 576 */
 577STATIC int
 578xfs_acl_invalid(
 579        xfs_acl_t       *aclp)
 580{
 581        xfs_acl_entry_t *entry, *e;
 582        int             user = 0, group = 0, other = 0, mask = 0;
 583        int             mask_required = 0;
 584        int             i, j;
 585
 586        if (!aclp)
 587                goto acl_invalid;
 588
 589        if (aclp->acl_cnt > XFS_ACL_MAX_ENTRIES)
 590                goto acl_invalid;
 591
 592        for (i = 0; i < aclp->acl_cnt; i++) {
 593                entry = &aclp->acl_entry[i];
 594                switch (entry->ae_tag) {
 595                case ACL_USER_OBJ:
 596                        if (user++)
 597                                goto acl_invalid;
 598                        break;
 599                case ACL_GROUP_OBJ:
 600                        if (group++)
 601                                goto acl_invalid;
 602                        break;
 603                case ACL_OTHER:
 604                        if (other++)
 605                                goto acl_invalid;
 606                        break;
 607                case ACL_USER:
 608                case ACL_GROUP:
 609                        for (j = i + 1; j < aclp->acl_cnt; j++) {
 610                                e = &aclp->acl_entry[j];
 611                                if (e->ae_id == entry->ae_id &&
 612                                    e->ae_tag == entry->ae_tag)
 613                                        goto acl_invalid;
 614                        }
 615                        mask_required++;
 616                        break;
 617                case ACL_MASK:
 618                        if (mask++)
 619                                goto acl_invalid;
 620                        break;
 621                default:
 622                        goto acl_invalid;
 623                }
 624        }
 625        if (!user || !group || !other || (mask_required && !mask))
 626                goto acl_invalid;
 627        else
 628                return 0;
 629acl_invalid:
 630        return EINVAL;
 631}
 632
 633/*
 634 * Do ACL endian conversion.
 635 */
 636STATIC void
 637xfs_acl_get_endian(
 638        xfs_acl_t       *aclp)
 639{
 640        xfs_acl_entry_t *ace, *end;
 641
 642        INT_SET(aclp->acl_cnt, ARCH_CONVERT, aclp->acl_cnt);
 643        end = &aclp->acl_entry[0]+aclp->acl_cnt;
 644        for (ace = &aclp->acl_entry[0]; ace < end; ace++) {
 645                INT_SET(ace->ae_tag, ARCH_CONVERT, ace->ae_tag);
 646                INT_SET(ace->ae_id, ARCH_CONVERT, ace->ae_id);
 647                INT_SET(ace->ae_perm, ARCH_CONVERT, ace->ae_perm);
 648        }
 649}
 650
 651/*
 652 * Get the ACL from the EA and do endian conversion.
 653 */
 654STATIC void
 655xfs_acl_get_attr(
 656        vnode_t         *vp,
 657        xfs_acl_t       *aclp,
 658        int             kind,
 659        int             flags,
 660        int             *error)
 661{
 662        int             len = sizeof(xfs_acl_t);
 663
 664        ASSERT((flags & ATTR_KERNOVAL) ? (aclp == NULL) : 1);
 665        flags |= ATTR_ROOT;
 666        VOP_ATTR_GET(vp,
 667                kind == _ACL_TYPE_ACCESS ? SGI_ACL_FILE : SGI_ACL_DEFAULT,
 668                (char *)aclp, &len, flags, sys_cred, *error);
 669        if (*error || (flags & ATTR_KERNOVAL))
 670                return;
 671        xfs_acl_get_endian(aclp);
 672}
 673
 674/*
 675 * Set the EA with the ACL and do endian conversion.
 676 */
 677STATIC void
 678xfs_acl_set_attr(
 679        vnode_t         *vp,
 680        xfs_acl_t       *aclp,
 681        int             kind,
 682        int             *error)
 683{
 684        xfs_acl_entry_t *ace, *newace, *end;
 685        xfs_acl_t       *newacl;
 686        int             len;
 687
 688        if (!(_ACL_ALLOC(newacl))) {
 689                *error = ENOMEM;
 690                return;
 691        }
 692
 693        len = sizeof(xfs_acl_t) -
 694              (sizeof(xfs_acl_entry_t) * (XFS_ACL_MAX_ENTRIES - aclp->acl_cnt));
 695        end = &aclp->acl_entry[0]+aclp->acl_cnt;
 696        for (ace = &aclp->acl_entry[0], newace = &newacl->acl_entry[0];
 697             ace < end;
 698             ace++, newace++) {
 699                INT_SET(newace->ae_tag, ARCH_CONVERT, ace->ae_tag);
 700                INT_SET(newace->ae_id, ARCH_CONVERT, ace->ae_id);
 701                INT_SET(newace->ae_perm, ARCH_CONVERT, ace->ae_perm);
 702        }
 703        INT_SET(newacl->acl_cnt, ARCH_CONVERT, aclp->acl_cnt);
 704        VOP_ATTR_SET(vp,
 705                kind == _ACL_TYPE_ACCESS ? SGI_ACL_FILE: SGI_ACL_DEFAULT,
 706                (char *)newacl, len, ATTR_ROOT, sys_cred, *error);
 707        _ACL_FREE(newacl);
 708}
 709
 710int
 711xfs_acl_vtoacl(
 712        vnode_t         *vp,
 713        xfs_acl_t       *access_acl,
 714        xfs_acl_t       *default_acl)
 715{
 716        vattr_t         va;
 717        int             error = 0;
 718
 719        if (access_acl) {
 720                /*
 721                 * Get the Access ACL and the mode.  If either cannot
 722                 * be obtained for some reason, invalidate the access ACL.
 723                 */
 724                xfs_acl_get_attr(vp, access_acl, _ACL_TYPE_ACCESS, 0, &error);
 725                if (!error) {
 726                        /* Got the ACL, need the mode... */
 727                        va.va_mask = XFS_AT_MODE;
 728                        VOP_GETATTR(vp, &va, 0, sys_cred, error);
 729                }
 730
 731                if (error)
 732                        access_acl->acl_cnt = XFS_ACL_NOT_PRESENT;
 733                else /* We have a good ACL and the file mode, synchronize. */
 734                        xfs_acl_sync_mode(va.va_mode, access_acl);
 735        }
 736
 737        if (default_acl) {
 738                xfs_acl_get_attr(vp, default_acl, _ACL_TYPE_DEFAULT, 0, &error);
 739                if (error)
 740                        default_acl->acl_cnt = XFS_ACL_NOT_PRESENT;
 741        }
 742        return error;
 743}
 744
 745/*
 746 * This function retrieves the parent directory's acl, processes it
 747 * and lets the child inherit the acl(s) that it should.
 748 */
 749int
 750xfs_acl_inherit(
 751        vnode_t         *vp,
 752        vattr_t         *vap,
 753        xfs_acl_t       *pdaclp)
 754{
 755        xfs_acl_t       *cacl;
 756        int             error = 0;
 757        int             basicperms = 0;
 758
 759        /*
 760         * If the parent does not have a default ACL, or it's an
 761         * invalid ACL, we're done.
 762         */
 763        if (!vp)
 764                return 0;
 765        if (!pdaclp || xfs_acl_invalid(pdaclp))
 766                return 0;
 767
 768        /*
 769         * Copy the default ACL of the containing directory to
 770         * the access ACL of the new file and use the mode that
 771         * was passed in to set up the correct initial values for
 772         * the u::,g::[m::], and o:: entries.  This is what makes
 773         * umask() "work" with ACL's.
 774         */
 775
 776        if (!(_ACL_ALLOC(cacl)))
 777                return ENOMEM;
 778
 779        memcpy(cacl, pdaclp, sizeof(xfs_acl_t));
 780        xfs_acl_filter_mode(vap->va_mode, cacl);
 781        xfs_acl_setmode(vp, cacl, &basicperms);
 782
 783        /*
 784         * Set the Default and Access ACL on the file.  The mode is already
 785         * set on the file, so we don't need to worry about that.
 786         *
 787         * If the new file is a directory, its default ACL is a copy of
 788         * the containing directory's default ACL.
 789         */
 790        if (vp->v_type == VDIR)
 791                xfs_acl_set_attr(vp, pdaclp, _ACL_TYPE_DEFAULT, &error);
 792        if (!error && !basicperms)
 793                xfs_acl_set_attr(vp, cacl, _ACL_TYPE_ACCESS, &error);
 794        _ACL_FREE(cacl);
 795        return error;
 796}
 797
 798/*
 799 * Set up the correct mode on the file based on the supplied ACL.  This
 800 * makes sure that the mode on the file reflects the state of the
 801 * u::,g::[m::], and o:: entries in the ACL.  Since the mode is where
 802 * the ACL is going to get the permissions for these entries, we must
 803 * synchronize the mode whenever we set the ACL on a file.
 804 */
 805STATIC int
 806xfs_acl_setmode(
 807        vnode_t         *vp,
 808        xfs_acl_t       *acl,
 809        int             *basicperms)
 810{
 811        vattr_t         va;
 812        xfs_acl_entry_t *ap;
 813        xfs_acl_entry_t *gap = NULL;
 814        int             i, error, nomask = 1;
 815
 816        *basicperms = 1;
 817
 818        if (acl->acl_cnt == XFS_ACL_NOT_PRESENT)
 819                return 0;
 820
 821        /*
 822         * Copy the u::, g::, o::, and m:: bits from the ACL into the
 823         * mode.  The m:: bits take precedence over the g:: bits.
 824         */
 825        va.va_mask = XFS_AT_MODE;
 826        VOP_GETATTR(vp, &va, 0, sys_cred, error);
 827        if (error)
 828                return error;
 829
 830        va.va_mask = XFS_AT_MODE;
 831        va.va_mode &= ~(S_IRWXU|S_IRWXG|S_IRWXO);
 832        ap = acl->acl_entry;
 833        for (i = 0; i < acl->acl_cnt; ++i) {
 834                switch (ap->ae_tag) {
 835                case ACL_USER_OBJ:
 836                        va.va_mode |= ap->ae_perm << 6;
 837                        break;
 838                case ACL_GROUP_OBJ:
 839                        gap = ap;
 840                        break;
 841                case ACL_MASK:  /* more than just standard modes */
 842                        nomask = 0;
 843                        va.va_mode |= ap->ae_perm << 3;
 844                        *basicperms = 0;
 845                        break;
 846                case ACL_OTHER:
 847                        va.va_mode |= ap->ae_perm;
 848                        break;
 849                default:        /* more than just standard modes */
 850                        *basicperms = 0;
 851                        break;
 852                }
 853                ap++;
 854        }
 855
 856        /* Set the group bits from ACL_GROUP_OBJ if there's no ACL_MASK */
 857        if (gap && nomask)
 858                va.va_mode |= gap->ae_perm << 3;
 859
 860        VOP_SETATTR(vp, &va, 0, sys_cred, error);
 861        return error;
 862}
 863
 864/*
 865 * The permissions for the special ACL entries (u::, g::[m::], o::) are
 866 * actually stored in the file mode (if there is both a group and a mask,
 867 * the group is stored in the ACL entry and the mask is stored on the file).
 868 * This allows the mode to remain automatically in sync with the ACL without
 869 * the need for a call-back to the ACL system at every point where the mode
 870 * could change.  This function takes the permissions from the specified mode
 871 * and places it in the supplied ACL.
 872 *
 873 * This implementation draws its validity from the fact that, when the ACL
 874 * was assigned, the mode was copied from the ACL.
 875 * If the mode did not change, therefore, the mode remains exactly what was
 876 * taken from the special ACL entries at assignment.
 877 * If a subsequent chmod() was done, the POSIX spec says that the change in
 878 * mode must cause an update to the ACL seen at user level and used for
 879 * access checks.  Before and after a mode change, therefore, the file mode
 880 * most accurately reflects what the special ACL entries should permit/deny.
 881 *
 882 * CAVEAT: If someone sets the SGI_ACL_FILE attribute directly,
 883 *         the existing mode bits will override whatever is in the
 884 *         ACL. Similarly, if there is a pre-existing ACL that was
 885 *         never in sync with its mode (owing to a bug in 6.5 and
 886 *         before), it will now magically (or mystically) be
 887 *         synchronized.  This could cause slight astonishment, but
 888 *         it is better than inconsistent permissions.
 889 *
 890 * The supplied ACL is a template that may contain any combination
 891 * of special entries.  These are treated as place holders when we fill
 892 * out the ACL.  This routine does not add or remove special entries, it
 893 * simply unites each special entry with its associated set of permissions.
 894 */
 895STATIC void
 896xfs_acl_sync_mode(
 897        mode_t          mode,
 898        xfs_acl_t       *acl)
 899{
 900        int             i, nomask = 1;
 901        xfs_acl_entry_t *ap;
 902        xfs_acl_entry_t *gap = NULL;
 903
 904        /*
 905         * Set ACL entries. POSIX1003.1eD16 requires that the MASK
 906         * be set instead of the GROUP entry, if there is a MASK.
 907         */
 908        for (ap = acl->acl_entry, i = 0; i < acl->acl_cnt; ap++, i++) {
 909                switch (ap->ae_tag) {
 910                case ACL_USER_OBJ:
 911                        ap->ae_perm = (mode >> 6) & 0x7;
 912                        break;
 913                case ACL_GROUP_OBJ:
 914                        gap = ap;
 915                        break;
 916                case ACL_MASK:
 917                        nomask = 0;
 918                        ap->ae_perm = (mode >> 3) & 0x7;
 919                        break;
 920                case ACL_OTHER:
 921                        ap->ae_perm = mode & 0x7;
 922                        break;
 923                default:
 924                        break;
 925                }
 926        }
 927        /* Set the ACL_GROUP_OBJ if there's no ACL_MASK */
 928        if (gap && nomask)
 929                gap->ae_perm = (mode >> 3) & 0x7;
 930}
 931
 932/*
 933 * When inheriting an Access ACL from a directory Default ACL,
 934 * the ACL bits are set to the intersection of the ACL default
 935 * permission bits and the file permission bits in mode. If there
 936 * are no permission bits on the file then we must not give them
 937 * the ACL. This is what what makes umask() work with ACLs.
 938 */
 939STATIC void
 940xfs_acl_filter_mode(
 941        mode_t          mode,
 942        xfs_acl_t       *acl)
 943{
 944        int             i, nomask = 1;
 945        xfs_acl_entry_t *ap;
 946        xfs_acl_entry_t *gap = NULL;
 947
 948        /*
 949         * Set ACL entries. POSIX1003.1eD16 requires that the MASK
 950         * be merged with GROUP entry, if there is a MASK.
 951         */
 952        for (ap = acl->acl_entry, i = 0; i < acl->acl_cnt; ap++, i++) {
 953                switch (ap->ae_tag) {
 954                case ACL_USER_OBJ:
 955                        ap->ae_perm &= (mode >> 6) & 0x7;
 956                        break;
 957                case ACL_GROUP_OBJ:
 958                        gap = ap;
 959                        break;
 960                case ACL_MASK:
 961                        nomask = 0;
 962                        ap->ae_perm &= (mode >> 3) & 0x7;
 963                        break;
 964                case ACL_OTHER:
 965                        ap->ae_perm &= mode & 0x7;
 966                        break;
 967                default:
 968                        break;
 969                }
 970        }
 971        /* Set the ACL_GROUP_OBJ if there's no ACL_MASK */
 972        if (gap && nomask)
 973                gap->ae_perm &= (mode >> 3) & 0x7;
 974}
 975
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.