1153323Srodrigc/* 2159451Srodrigc * Copyright (c) 2001-2002,2005 Silicon Graphics, Inc. 3159451Srodrigc * All Rights Reserved. 4153323Srodrigc * 5159451Srodrigc * This program is free software; you can redistribute it and/or 6159451Srodrigc * modify it under the terms of the GNU General Public License as 7153323Srodrigc * published by the Free Software Foundation. 8153323Srodrigc * 9159451Srodrigc * This program is distributed in the hope that it would be useful, 10159451Srodrigc * but WITHOUT ANY WARRANTY; without even the implied warranty of 11159451Srodrigc * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12159451Srodrigc * GNU General Public License for more details. 13153323Srodrigc * 14159451Srodrigc * You should have received a copy of the GNU General Public License 15159451Srodrigc * along with this program; if not, write the Free Software Foundation, 16159451Srodrigc * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17153323Srodrigc */ 18153323Srodrigc#include "xfs.h" 19159451Srodrigc#include "xfs_fs.h" 20159451Srodrigc#include "xfs_types.h" 21159451Srodrigc#include "xfs_bit.h" 22153323Srodrigc#include "xfs_inum.h" 23159451Srodrigc#include "xfs_ag.h" 24153323Srodrigc#include "xfs_dir.h" 25153323Srodrigc#include "xfs_dir2.h" 26159451Srodrigc#include "xfs_bmap_btree.h" 27153323Srodrigc#include "xfs_alloc_btree.h" 28153323Srodrigc#include "xfs_ialloc_btree.h" 29153323Srodrigc#include "xfs_dir_sf.h" 30153323Srodrigc#include "xfs_dir2_sf.h" 31159451Srodrigc#include "xfs_attr_sf.h" 32153323Srodrigc#include "xfs_dinode.h" 33153323Srodrigc#include "xfs_inode.h" 34159451Srodrigc#include "xfs_btree.h" 35153323Srodrigc#include "xfs_acl.h" 36153323Srodrigc#include "xfs_mac.h" 37153323Srodrigc#include "xfs_attr.h" 38153323Srodrigc 39159451Srodrigc#include <linux/capability.h> 40153323Srodrigc#include <linux/posix_acl_xattr.h> 41153323Srodrigc 42153323SrodrigcSTATIC int xfs_acl_setmode(xfs_vnode_t *, xfs_acl_t *, int *); 43153323SrodrigcSTATIC void xfs_acl_filter_mode(mode_t, xfs_acl_t *); 44153323SrodrigcSTATIC void xfs_acl_get_endian(xfs_acl_t *); 45153323SrodrigcSTATIC int xfs_acl_access(uid_t, gid_t, xfs_acl_t *, mode_t, cred_t *); 46153323SrodrigcSTATIC int xfs_acl_invalid(xfs_acl_t *); 47153323SrodrigcSTATIC void xfs_acl_sync_mode(mode_t, xfs_acl_t *); 48153323SrodrigcSTATIC void xfs_acl_get_attr(xfs_vnode_t *, xfs_acl_t *, int, int, int *); 49153323SrodrigcSTATIC void xfs_acl_set_attr(xfs_vnode_t *, xfs_acl_t *, int, int *); 50153323SrodrigcSTATIC int xfs_acl_allow_set(xfs_vnode_t *, int); 51153323Srodrigc 52153323Srodrigckmem_zone_t *xfs_acl_zone; 53153323Srodrigc 54153323Srodrigc 55153323Srodrigc/* 56153323Srodrigc * Test for existence of access ACL attribute as efficiently as possible. 57153323Srodrigc */ 58153323Srodrigcint 59153323Srodrigcxfs_acl_vhasacl_access( 60153323Srodrigc xfs_vnode_t *vp) 61153323Srodrigc{ 62153323Srodrigc int error; 63153323Srodrigc 64153323Srodrigc xfs_acl_get_attr(vp, NULL, _ACL_TYPE_ACCESS, ATTR_KERNOVAL, &error); 65153323Srodrigc return (error == 0); 66153323Srodrigc} 67153323Srodrigc 68153323Srodrigc/* 69153323Srodrigc * Test for existence of default ACL attribute as efficiently as possible. 70153323Srodrigc */ 71153323Srodrigcint 72153323Srodrigcxfs_acl_vhasacl_default( 73153323Srodrigc xfs_vnode_t *vp) 74153323Srodrigc{ 75153323Srodrigc int error; 76153323Srodrigc 77159451Srodrigc if (!VN_ISDIR(vp)) 78153323Srodrigc return 0; 79153323Srodrigc xfs_acl_get_attr(vp, NULL, _ACL_TYPE_DEFAULT, ATTR_KERNOVAL, &error); 80153323Srodrigc return (error == 0); 81153323Srodrigc} 82153323Srodrigc 83153323Srodrigc/* 84153323Srodrigc * Convert from extended attribute representation to in-memory for XFS. 85153323Srodrigc */ 86153323SrodrigcSTATIC int 87153323Srodrigcposix_acl_xattr_to_xfs( 88153323Srodrigc posix_acl_xattr_header *src, 89153323Srodrigc size_t size, 90153323Srodrigc xfs_acl_t *dest) 91153323Srodrigc{ 92153323Srodrigc posix_acl_xattr_entry *src_entry; 93153323Srodrigc xfs_acl_entry_t *dest_entry; 94153323Srodrigc int n; 95153323Srodrigc 96153323Srodrigc if (!src || !dest) 97153323Srodrigc return EINVAL; 98153323Srodrigc 99153323Srodrigc if (size < sizeof(posix_acl_xattr_header)) 100153323Srodrigc return EINVAL; 101153323Srodrigc 102153323Srodrigc if (src->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION)) 103159451Srodrigc return EOPNOTSUPP; 104153323Srodrigc 105153323Srodrigc memset(dest, 0, sizeof(xfs_acl_t)); 106153323Srodrigc dest->acl_cnt = posix_acl_xattr_count(size); 107153323Srodrigc if (dest->acl_cnt < 0 || dest->acl_cnt > XFS_ACL_MAX_ENTRIES) 108153323Srodrigc return EINVAL; 109153323Srodrigc 110153323Srodrigc /* 111153323Srodrigc * acl_set_file(3) may request that we set default ACLs with 112153323Srodrigc * zero length -- defend (gracefully) against that here. 113153323Srodrigc */ 114153323Srodrigc if (!dest->acl_cnt) 115153323Srodrigc return 0; 116153323Srodrigc 117153323Srodrigc src_entry = (posix_acl_xattr_entry *)((char *)src + sizeof(*src)); 118153323Srodrigc dest_entry = &dest->acl_entry[0]; 119153323Srodrigc 120153323Srodrigc for (n = 0; n < dest->acl_cnt; n++, src_entry++, dest_entry++) { 121153323Srodrigc dest_entry->ae_perm = le16_to_cpu(src_entry->e_perm); 122153323Srodrigc if (_ACL_PERM_INVALID(dest_entry->ae_perm)) 123153323Srodrigc return EINVAL; 124153323Srodrigc dest_entry->ae_tag = le16_to_cpu(src_entry->e_tag); 125153323Srodrigc switch(dest_entry->ae_tag) { 126153323Srodrigc case ACL_USER: 127153323Srodrigc case ACL_GROUP: 128153323Srodrigc dest_entry->ae_id = le32_to_cpu(src_entry->e_id); 129153323Srodrigc break; 130153323Srodrigc case ACL_USER_OBJ: 131153323Srodrigc case ACL_GROUP_OBJ: 132153323Srodrigc case ACL_MASK: 133153323Srodrigc case ACL_OTHER: 134153323Srodrigc dest_entry->ae_id = ACL_UNDEFINED_ID; 135153323Srodrigc break; 136153323Srodrigc default: 137153323Srodrigc return EINVAL; 138153323Srodrigc } 139153323Srodrigc } 140153323Srodrigc if (xfs_acl_invalid(dest)) 141153323Srodrigc return EINVAL; 142153323Srodrigc 143153323Srodrigc return 0; 144153323Srodrigc} 145153323Srodrigc 146153323Srodrigc/* 147159451Srodrigc * Comparison function called from xfs_sort(). 148153323Srodrigc * Primary key is ae_tag, secondary key is ae_id. 149153323Srodrigc */ 150153323SrodrigcSTATIC int 151153323Srodrigcxfs_acl_entry_compare( 152153323Srodrigc const void *va, 153153323Srodrigc const void *vb) 154153323Srodrigc{ 155153323Srodrigc xfs_acl_entry_t *a = (xfs_acl_entry_t *)va, 156153323Srodrigc *b = (xfs_acl_entry_t *)vb; 157153323Srodrigc 158153323Srodrigc if (a->ae_tag == b->ae_tag) 159153323Srodrigc return (a->ae_id - b->ae_id); 160153323Srodrigc return (a->ae_tag - b->ae_tag); 161153323Srodrigc} 162153323Srodrigc 163153323Srodrigc/* 164153323Srodrigc * Convert from in-memory XFS to extended attribute representation. 165153323Srodrigc */ 166153323SrodrigcSTATIC int 167153323Srodrigcposix_acl_xfs_to_xattr( 168153323Srodrigc xfs_acl_t *src, 169153323Srodrigc posix_acl_xattr_header *dest, 170153323Srodrigc size_t size) 171153323Srodrigc{ 172153323Srodrigc int n; 173153323Srodrigc size_t new_size = posix_acl_xattr_size(src->acl_cnt); 174153323Srodrigc posix_acl_xattr_entry *dest_entry; 175153323Srodrigc xfs_acl_entry_t *src_entry; 176153323Srodrigc 177153323Srodrigc if (size < new_size) 178153323Srodrigc return -ERANGE; 179153323Srodrigc 180153323Srodrigc /* Need to sort src XFS ACL by <ae_tag,ae_id> */ 181159451Srodrigc xfs_sort(src->acl_entry, src->acl_cnt, sizeof(src->acl_entry[0]), 182159451Srodrigc xfs_acl_entry_compare); 183153323Srodrigc 184153323Srodrigc dest->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION); 185153323Srodrigc dest_entry = &dest->a_entries[0]; 186153323Srodrigc src_entry = &src->acl_entry[0]; 187153323Srodrigc for (n = 0; n < src->acl_cnt; n++, dest_entry++, src_entry++) { 188153323Srodrigc dest_entry->e_perm = cpu_to_le16(src_entry->ae_perm); 189153323Srodrigc if (_ACL_PERM_INVALID(src_entry->ae_perm)) 190153323Srodrigc return -EINVAL; 191153323Srodrigc dest_entry->e_tag = cpu_to_le16(src_entry->ae_tag); 192153323Srodrigc switch (src_entry->ae_tag) { 193153323Srodrigc case ACL_USER: 194153323Srodrigc case ACL_GROUP: 195153323Srodrigc dest_entry->e_id = cpu_to_le32(src_entry->ae_id); 196153323Srodrigc break; 197153323Srodrigc case ACL_USER_OBJ: 198153323Srodrigc case ACL_GROUP_OBJ: 199153323Srodrigc case ACL_MASK: 200153323Srodrigc case ACL_OTHER: 201153323Srodrigc dest_entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID); 202153323Srodrigc break; 203153323Srodrigc default: 204153323Srodrigc return -EINVAL; 205153323Srodrigc } 206153323Srodrigc } 207153323Srodrigc return new_size; 208153323Srodrigc} 209153323Srodrigc 210153323Srodrigcint 211153323Srodrigcxfs_acl_vget( 212153323Srodrigc xfs_vnode_t *vp, 213153323Srodrigc void *acl, 214153323Srodrigc size_t size, 215153323Srodrigc int kind) 216153323Srodrigc{ 217153323Srodrigc int error; 218153323Srodrigc xfs_acl_t *xfs_acl = NULL; 219153323Srodrigc posix_acl_xattr_header *ext_acl = acl; 220153323Srodrigc int flags = 0; 221153323Srodrigc 222153323Srodrigc VN_HOLD(vp); 223153323Srodrigc if(size) { 224153323Srodrigc if (!(_ACL_ALLOC(xfs_acl))) { 225153323Srodrigc error = ENOMEM; 226153323Srodrigc goto out; 227153323Srodrigc } 228153323Srodrigc memset(xfs_acl, 0, sizeof(xfs_acl_t)); 229153323Srodrigc } else 230153323Srodrigc flags = ATTR_KERNOVAL; 231153323Srodrigc 232153323Srodrigc xfs_acl_get_attr(vp, xfs_acl, kind, flags, &error); 233153323Srodrigc if (error) 234153323Srodrigc goto out; 235153323Srodrigc 236153323Srodrigc if (!size) { 237153323Srodrigc error = -posix_acl_xattr_size(XFS_ACL_MAX_ENTRIES); 238153323Srodrigc } else { 239153323Srodrigc if (xfs_acl_invalid(xfs_acl)) { 240153323Srodrigc error = EINVAL; 241153323Srodrigc goto out; 242153323Srodrigc } 243153323Srodrigc if (kind == _ACL_TYPE_ACCESS) { 244153323Srodrigc xfs_vattr_t va; 245153323Srodrigc 246153323Srodrigc va.va_mask = XFS_AT_MODE; 247153323Srodrigc XVOP_GETATTR(vp, &va, 0, sys_cred, error); 248153323Srodrigc if (error) 249153323Srodrigc goto out; 250153323Srodrigc xfs_acl_sync_mode(va.va_mode, xfs_acl); 251153323Srodrigc } 252153323Srodrigc error = -posix_acl_xfs_to_xattr(xfs_acl, ext_acl, size); 253153323Srodrigc } 254153323Srodrigcout: 255153323Srodrigc VN_RELE(vp); 256153323Srodrigc if(xfs_acl) 257153323Srodrigc _ACL_FREE(xfs_acl); 258153323Srodrigc return -error; 259153323Srodrigc} 260153323Srodrigc 261153323Srodrigcint 262153323Srodrigcxfs_acl_vremove( 263153323Srodrigc xfs_vnode_t *vp, 264153323Srodrigc int kind) 265153323Srodrigc{ 266153323Srodrigc int error; 267153323Srodrigc 268153323Srodrigc VN_HOLD(vp); 269153323Srodrigc error = xfs_acl_allow_set(vp, kind); 270153323Srodrigc if (!error) { 271153323Srodrigc XVOP_ATTR_REMOVE(vp, kind == _ACL_TYPE_DEFAULT? 272153323Srodrigc SGI_ACL_DEFAULT: SGI_ACL_FILE, 273153323Srodrigc ATTR_ROOT, sys_cred, error); 274153323Srodrigc if (error == ENOATTR) 275153323Srodrigc error = 0; /* 'scool */ 276153323Srodrigc } 277153323Srodrigc VN_RELE(vp); 278153323Srodrigc return -error; 279153323Srodrigc} 280153323Srodrigc 281153323Srodrigcint 282153323Srodrigcxfs_acl_vset( 283153323Srodrigc xfs_vnode_t *vp, 284153323Srodrigc void *acl, 285153323Srodrigc size_t size, 286153323Srodrigc int kind) 287153323Srodrigc{ 288153323Srodrigc posix_acl_xattr_header *ext_acl = acl; 289153323Srodrigc xfs_acl_t *xfs_acl; 290153323Srodrigc int error; 291153323Srodrigc int basicperms = 0; /* more than std unix perms? */ 292153323Srodrigc 293153323Srodrigc if (!acl) 294153323Srodrigc return -EINVAL; 295153323Srodrigc 296153323Srodrigc if (!(_ACL_ALLOC(xfs_acl))) 297153323Srodrigc return -ENOMEM; 298153323Srodrigc 299153323Srodrigc error = posix_acl_xattr_to_xfs(ext_acl, size, xfs_acl); 300153323Srodrigc if (error) { 301153323Srodrigc _ACL_FREE(xfs_acl); 302153323Srodrigc return -error; 303153323Srodrigc } 304153323Srodrigc if (!xfs_acl->acl_cnt) { 305153323Srodrigc _ACL_FREE(xfs_acl); 306153323Srodrigc return 0; 307153323Srodrigc } 308153323Srodrigc 309153323Srodrigc VN_HOLD(vp); 310153323Srodrigc error = xfs_acl_allow_set(vp, kind); 311153323Srodrigc if (error) 312153323Srodrigc goto out; 313153323Srodrigc 314153323Srodrigc /* Incoming ACL exists, set file mode based on its value */ 315153323Srodrigc if (kind == _ACL_TYPE_ACCESS) 316153323Srodrigc xfs_acl_setmode(vp, xfs_acl, &basicperms); 317153323Srodrigc 318153323Srodrigc /* 319153323Srodrigc * If we have more than std unix permissions, set up the actual attr. 320153323Srodrigc * Otherwise, delete any existing attr. This prevents us from 321153323Srodrigc * having actual attrs for permissions that can be stored in the 322153323Srodrigc * standard permission bits. 323153323Srodrigc */ 324153323Srodrigc if (!basicperms) { 325153323Srodrigc xfs_acl_set_attr(vp, xfs_acl, kind, &error); 326153323Srodrigc } else { 327153323Srodrigc xfs_acl_vremove(vp, _ACL_TYPE_ACCESS); 328153323Srodrigc } 329153323Srodrigc 330153323Srodrigcout: 331153323Srodrigc VN_RELE(vp); 332153323Srodrigc _ACL_FREE(xfs_acl); 333153323Srodrigc return -error; 334153323Srodrigc} 335153323Srodrigc 336153323Srodrigcint 337153323Srodrigcxfs_acl_iaccess( 338153323Srodrigc xfs_inode_t *ip, 339153323Srodrigc mode_t mode, 340153323Srodrigc cred_t *cr) 341153323Srodrigc{ 342153323Srodrigc xfs_acl_t *acl; 343159451Srodrigc int rval; 344153323Srodrigc 345153323Srodrigc if (!(_ACL_ALLOC(acl))) 346153323Srodrigc return -1; 347153323Srodrigc 348153323Srodrigc /* If the file has no ACL return -1. */ 349159451Srodrigc rval = sizeof(xfs_acl_t); 350159451Srodrigc if (xfs_attr_fetch(ip, SGI_ACL_FILE, SGI_ACL_FILE_SIZE, 351159451Srodrigc (char *)acl, &rval, ATTR_ROOT | ATTR_KERNACCESS, cr)) { 352153323Srodrigc _ACL_FREE(acl); 353153323Srodrigc return -1; 354153323Srodrigc } 355153323Srodrigc xfs_acl_get_endian(acl); 356153323Srodrigc 357153323Srodrigc /* If the file has an empty ACL return -1. */ 358153323Srodrigc if (acl->acl_cnt == XFS_ACL_NOT_PRESENT) { 359153323Srodrigc _ACL_FREE(acl); 360153323Srodrigc return -1; 361153323Srodrigc } 362153323Srodrigc 363153323Srodrigc /* Synchronize ACL with mode bits */ 364153323Srodrigc xfs_acl_sync_mode(ip->i_d.di_mode, acl); 365153323Srodrigc 366159451Srodrigc rval = xfs_acl_access(ip->i_d.di_uid, ip->i_d.di_gid, acl, mode, cr); 367153323Srodrigc _ACL_FREE(acl); 368159451Srodrigc return rval; 369153323Srodrigc} 370153323Srodrigc 371153323SrodrigcSTATIC int 372153323Srodrigcxfs_acl_allow_set( 373153323Srodrigc xfs_vnode_t *vp, 374153323Srodrigc int kind) 375153323Srodrigc{ 376153323Srodrigc xfs_vattr_t va; 377153323Srodrigc int error; 378153323Srodrigc 379153323Srodrigc if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND)) 380153323Srodrigc return EPERM; 381159451Srodrigc if (kind == _ACL_TYPE_DEFAULT && !VN_ISDIR(vp)) 382153323Srodrigc return ENOTDIR; 383153323Srodrigc if (vp->v_vfsp->vfs_flag & VFS_RDONLY) 384153323Srodrigc return EROFS; 385153323Srodrigc va.va_mask = XFS_AT_UID; 386153323Srodrigc XVOP_GETATTR(vp, &va, 0, NULL, error); 387153323Srodrigc if (error) 388153323Srodrigc return error; 389153323Srodrigc if (va.va_uid != current->fsuid && !capable(CAP_FOWNER)) 390153323Srodrigc return EPERM; 391153323Srodrigc return error; 392153323Srodrigc} 393153323Srodrigc 394153323Srodrigc/* 395153323Srodrigc * The access control process to determine the access permission: 396153323Srodrigc * if uid == file owner id, use the file owner bits. 397153323Srodrigc * if gid == file owner group id, use the file group bits. 398159451Srodrigc * scan ACL for a matching user or group, and use matched entry 399153323Srodrigc * permission. Use total permissions of all matching group entries, 400153323Srodrigc * until all acl entries are exhausted. The final permission produced 401153323Srodrigc * by matching acl entry or entries needs to be & with group permission. 402153323Srodrigc * if not owner, owning group, or matching entry in ACL, use file 403159451Srodrigc * other bits. 404153323Srodrigc */ 405153323SrodrigcSTATIC int 406153323Srodrigcxfs_acl_capability_check( 407153323Srodrigc mode_t mode, 408159451Srodrigc cred_t *cr) 409153323Srodrigc{ 410153323Srodrigc if ((mode & ACL_READ) && !capable_cred(cr, CAP_DAC_READ_SEARCH)) 411153323Srodrigc return EACCES; 412153323Srodrigc if ((mode & ACL_WRITE) && !capable_cred(cr, CAP_DAC_OVERRIDE)) 413153323Srodrigc return EACCES; 414159451Srodrigc if ((mode & ACL_EXECUTE) && !capable_cred(cr, CAP_DAC_OVERRIDE)) 415153323Srodrigc return EACCES; 416153323Srodrigc 417153323Srodrigc return 0; 418153323Srodrigc} 419153323Srodrigc 420153323Srodrigc/* 421153323Srodrigc * Note: cr is only used here for the capability check if the ACL test fails. 422153323Srodrigc * It is not used to find out the credentials uid or groups etc, as was 423153323Srodrigc * done in IRIX. It is assumed that the uid and groups for the current 424153323Srodrigc * thread are taken from "current" instead of the cr parameter. 425153323Srodrigc */ 426153323SrodrigcSTATIC int 427153323Srodrigcxfs_acl_access( 428153323Srodrigc uid_t fuid, 429153323Srodrigc gid_t fgid, 430153323Srodrigc xfs_acl_t *fap, 431153323Srodrigc mode_t md, 432153323Srodrigc cred_t *cr) 433153323Srodrigc{ 434153323Srodrigc xfs_acl_entry_t matched; 435153323Srodrigc int i, allows; 436153323Srodrigc int maskallows = -1; /* true, but not 1, either */ 437153323Srodrigc int seen_userobj = 0; 438153323Srodrigc 439153323Srodrigc matched.ae_tag = 0; /* Invalid type */ 440159451Srodrigc matched.ae_perm = 0; 441153323Srodrigc md >>= 6; /* Normalize the bits for comparison */ 442153323Srodrigc 443153323Srodrigc for (i = 0; i < fap->acl_cnt; i++) { 444153323Srodrigc /* 445153323Srodrigc * Break out if we've got a user_obj entry or 446153323Srodrigc * a user entry and the mask (and have processed USER_OBJ) 447153323Srodrigc */ 448153323Srodrigc if (matched.ae_tag == ACL_USER_OBJ) 449153323Srodrigc break; 450153323Srodrigc if (matched.ae_tag == ACL_USER) { 451153323Srodrigc if (maskallows != -1 && seen_userobj) 452153323Srodrigc break; 453153323Srodrigc if (fap->acl_entry[i].ae_tag != ACL_MASK && 454153323Srodrigc fap->acl_entry[i].ae_tag != ACL_USER_OBJ) 455153323Srodrigc continue; 456153323Srodrigc } 457153323Srodrigc /* True if this entry allows the requested access */ 458153323Srodrigc allows = ((fap->acl_entry[i].ae_perm & md) == md); 459153323Srodrigc 460153323Srodrigc switch (fap->acl_entry[i].ae_tag) { 461153323Srodrigc case ACL_USER_OBJ: 462153323Srodrigc seen_userobj = 1; 463153323Srodrigc if (fuid != current->fsuid) 464153323Srodrigc continue; 465153323Srodrigc matched.ae_tag = ACL_USER_OBJ; 466153323Srodrigc matched.ae_perm = allows; 467153323Srodrigc break; 468153323Srodrigc case ACL_USER: 469153323Srodrigc if (fap->acl_entry[i].ae_id != current->fsuid) 470153323Srodrigc continue; 471153323Srodrigc matched.ae_tag = ACL_USER; 472153323Srodrigc matched.ae_perm = allows; 473153323Srodrigc break; 474153323Srodrigc case ACL_GROUP_OBJ: 475153323Srodrigc if ((matched.ae_tag == ACL_GROUP_OBJ || 476153323Srodrigc matched.ae_tag == ACL_GROUP) && !allows) 477153323Srodrigc continue; 478153323Srodrigc if (!in_group_p(fgid)) 479153323Srodrigc continue; 480153323Srodrigc matched.ae_tag = ACL_GROUP_OBJ; 481153323Srodrigc matched.ae_perm = allows; 482153323Srodrigc break; 483153323Srodrigc case ACL_GROUP: 484153323Srodrigc if ((matched.ae_tag == ACL_GROUP_OBJ || 485153323Srodrigc matched.ae_tag == ACL_GROUP) && !allows) 486153323Srodrigc continue; 487153323Srodrigc if (!in_group_p(fap->acl_entry[i].ae_id)) 488153323Srodrigc continue; 489153323Srodrigc matched.ae_tag = ACL_GROUP; 490153323Srodrigc matched.ae_perm = allows; 491153323Srodrigc break; 492153323Srodrigc case ACL_MASK: 493153323Srodrigc maskallows = allows; 494153323Srodrigc break; 495153323Srodrigc case ACL_OTHER: 496153323Srodrigc if (matched.ae_tag != 0) 497153323Srodrigc continue; 498153323Srodrigc matched.ae_tag = ACL_OTHER; 499153323Srodrigc matched.ae_perm = allows; 500153323Srodrigc break; 501153323Srodrigc } 502153323Srodrigc } 503153323Srodrigc /* 504153323Srodrigc * First possibility is that no matched entry allows access. 505153323Srodrigc * The capability to override DAC may exist, so check for it. 506153323Srodrigc */ 507153323Srodrigc switch (matched.ae_tag) { 508153323Srodrigc case ACL_OTHER: 509153323Srodrigc case ACL_USER_OBJ: 510153323Srodrigc if (matched.ae_perm) 511153323Srodrigc return 0; 512153323Srodrigc break; 513153323Srodrigc case ACL_USER: 514153323Srodrigc case ACL_GROUP_OBJ: 515153323Srodrigc case ACL_GROUP: 516153323Srodrigc if (maskallows && matched.ae_perm) 517153323Srodrigc return 0; 518153323Srodrigc break; 519153323Srodrigc case 0: 520153323Srodrigc break; 521153323Srodrigc } 522153323Srodrigc 523159451Srodrigc return xfs_acl_capability_check(md, cr); 524153323Srodrigc} 525153323Srodrigc 526153323Srodrigc/* 527153323Srodrigc * ACL validity checker. 528153323Srodrigc * This acl validation routine checks each ACL entry read in makes sense. 529153323Srodrigc */ 530153323SrodrigcSTATIC int 531153323Srodrigcxfs_acl_invalid( 532153323Srodrigc xfs_acl_t *aclp) 533153323Srodrigc{ 534153323Srodrigc xfs_acl_entry_t *entry, *e; 535153323Srodrigc int user = 0, group = 0, other = 0, mask = 0; 536153323Srodrigc int mask_required = 0; 537153323Srodrigc int i, j; 538153323Srodrigc 539153323Srodrigc if (!aclp) 540153323Srodrigc goto acl_invalid; 541153323Srodrigc 542153323Srodrigc if (aclp->acl_cnt > XFS_ACL_MAX_ENTRIES) 543153323Srodrigc goto acl_invalid; 544153323Srodrigc 545153323Srodrigc for (i = 0; i < aclp->acl_cnt; i++) { 546153323Srodrigc entry = &aclp->acl_entry[i]; 547153323Srodrigc switch (entry->ae_tag) { 548153323Srodrigc case ACL_USER_OBJ: 549153323Srodrigc if (user++) 550153323Srodrigc goto acl_invalid; 551153323Srodrigc break; 552153323Srodrigc case ACL_GROUP_OBJ: 553153323Srodrigc if (group++) 554153323Srodrigc goto acl_invalid; 555153323Srodrigc break; 556153323Srodrigc case ACL_OTHER: 557153323Srodrigc if (other++) 558153323Srodrigc goto acl_invalid; 559153323Srodrigc break; 560153323Srodrigc case ACL_USER: 561153323Srodrigc case ACL_GROUP: 562153323Srodrigc for (j = i + 1; j < aclp->acl_cnt; j++) { 563153323Srodrigc e = &aclp->acl_entry[j]; 564153323Srodrigc if (e->ae_id == entry->ae_id && 565153323Srodrigc e->ae_tag == entry->ae_tag) 566153323Srodrigc goto acl_invalid; 567153323Srodrigc } 568153323Srodrigc mask_required++; 569153323Srodrigc break; 570153323Srodrigc case ACL_MASK: 571153323Srodrigc if (mask++) 572153323Srodrigc goto acl_invalid; 573153323Srodrigc break; 574153323Srodrigc default: 575153323Srodrigc goto acl_invalid; 576153323Srodrigc } 577153323Srodrigc } 578153323Srodrigc if (!user || !group || !other || (mask_required && !mask)) 579153323Srodrigc goto acl_invalid; 580153323Srodrigc else 581153323Srodrigc return 0; 582153323Srodrigcacl_invalid: 583153323Srodrigc return EINVAL; 584153323Srodrigc} 585153323Srodrigc 586153323Srodrigc/* 587153323Srodrigc * Do ACL endian conversion. 588153323Srodrigc */ 589153323SrodrigcSTATIC void 590153323Srodrigcxfs_acl_get_endian( 591153323Srodrigc xfs_acl_t *aclp) 592153323Srodrigc{ 593153323Srodrigc xfs_acl_entry_t *ace, *end; 594153323Srodrigc 595153323Srodrigc INT_SET(aclp->acl_cnt, ARCH_CONVERT, aclp->acl_cnt); 596153323Srodrigc end = &aclp->acl_entry[0]+aclp->acl_cnt; 597153323Srodrigc for (ace = &aclp->acl_entry[0]; ace < end; ace++) { 598153323Srodrigc INT_SET(ace->ae_tag, ARCH_CONVERT, ace->ae_tag); 599153323Srodrigc INT_SET(ace->ae_id, ARCH_CONVERT, ace->ae_id); 600153323Srodrigc INT_SET(ace->ae_perm, ARCH_CONVERT, ace->ae_perm); 601153323Srodrigc } 602153323Srodrigc} 603153323Srodrigc 604153323Srodrigc/* 605153323Srodrigc * Get the ACL from the EA and do endian conversion. 606153323Srodrigc */ 607153323SrodrigcSTATIC void 608153323Srodrigcxfs_acl_get_attr( 609153323Srodrigc xfs_vnode_t *vp, 610153323Srodrigc xfs_acl_t *aclp, 611153323Srodrigc int kind, 612153323Srodrigc int flags, 613153323Srodrigc int *error) 614153323Srodrigc{ 615153323Srodrigc int len = sizeof(xfs_acl_t); 616153323Srodrigc 617153323Srodrigc ASSERT((flags & ATTR_KERNOVAL) ? (aclp == NULL) : 1); 618153323Srodrigc flags |= ATTR_ROOT; 619153323Srodrigc XVOP_ATTR_GET(vp, 620153323Srodrigc kind == _ACL_TYPE_ACCESS ? SGI_ACL_FILE : SGI_ACL_DEFAULT, 621153323Srodrigc (char *)aclp, &len, flags, sys_cred, *error); 622153323Srodrigc if (*error || (flags & ATTR_KERNOVAL)) 623153323Srodrigc return; 624153323Srodrigc xfs_acl_get_endian(aclp); 625153323Srodrigc} 626153323Srodrigc 627153323Srodrigc/* 628153323Srodrigc * Set the EA with the ACL and do endian conversion. 629153323Srodrigc */ 630153323SrodrigcSTATIC void 631153323Srodrigcxfs_acl_set_attr( 632153323Srodrigc xfs_vnode_t *vp, 633153323Srodrigc xfs_acl_t *aclp, 634153323Srodrigc int kind, 635153323Srodrigc int *error) 636153323Srodrigc{ 637153323Srodrigc xfs_acl_entry_t *ace, *newace, *end; 638153323Srodrigc xfs_acl_t *newacl; 639153323Srodrigc int len; 640153323Srodrigc 641153323Srodrigc if (!(_ACL_ALLOC(newacl))) { 642153323Srodrigc *error = ENOMEM; 643153323Srodrigc return; 644153323Srodrigc } 645153323Srodrigc 646153323Srodrigc len = sizeof(xfs_acl_t) - 647153323Srodrigc (sizeof(xfs_acl_entry_t) * (XFS_ACL_MAX_ENTRIES - aclp->acl_cnt)); 648153323Srodrigc end = &aclp->acl_entry[0]+aclp->acl_cnt; 649153323Srodrigc for (ace = &aclp->acl_entry[0], newace = &newacl->acl_entry[0]; 650153323Srodrigc ace < end; 651153323Srodrigc ace++, newace++) { 652153323Srodrigc INT_SET(newace->ae_tag, ARCH_CONVERT, ace->ae_tag); 653153323Srodrigc INT_SET(newace->ae_id, ARCH_CONVERT, ace->ae_id); 654153323Srodrigc INT_SET(newace->ae_perm, ARCH_CONVERT, ace->ae_perm); 655153323Srodrigc } 656153323Srodrigc INT_SET(newacl->acl_cnt, ARCH_CONVERT, aclp->acl_cnt); 657153323Srodrigc XVOP_ATTR_SET(vp, 658153323Srodrigc kind == _ACL_TYPE_ACCESS ? SGI_ACL_FILE: SGI_ACL_DEFAULT, 659153323Srodrigc (char *)newacl, len, ATTR_ROOT, sys_cred, *error); 660153323Srodrigc _ACL_FREE(newacl); 661153323Srodrigc} 662153323Srodrigc 663153323Srodrigcint 664153323Srodrigcxfs_acl_vtoacl( 665153323Srodrigc xfs_vnode_t *vp, 666153323Srodrigc xfs_acl_t *access_acl, 667153323Srodrigc xfs_acl_t *default_acl) 668153323Srodrigc{ 669153323Srodrigc xfs_vattr_t va; 670153323Srodrigc int error = 0; 671153323Srodrigc 672153323Srodrigc if (access_acl) { 673153323Srodrigc /* 674153323Srodrigc * Get the Access ACL and the mode. If either cannot 675153323Srodrigc * be obtained for some reason, invalidate the access ACL. 676153323Srodrigc */ 677153323Srodrigc xfs_acl_get_attr(vp, access_acl, _ACL_TYPE_ACCESS, 0, &error); 678153323Srodrigc if (!error) { 679153323Srodrigc /* Got the ACL, need the mode... */ 680153323Srodrigc va.va_mask = XFS_AT_MODE; 681153323Srodrigc XVOP_GETATTR(vp, &va, 0, sys_cred, error); 682153323Srodrigc } 683153323Srodrigc 684153323Srodrigc if (error) 685153323Srodrigc access_acl->acl_cnt = XFS_ACL_NOT_PRESENT; 686153323Srodrigc else /* We have a good ACL and the file mode, synchronize. */ 687153323Srodrigc xfs_acl_sync_mode(va.va_mode, access_acl); 688153323Srodrigc } 689153323Srodrigc 690153323Srodrigc if (default_acl) { 691153323Srodrigc xfs_acl_get_attr(vp, default_acl, _ACL_TYPE_DEFAULT, 0, &error); 692153323Srodrigc if (error) 693153323Srodrigc default_acl->acl_cnt = XFS_ACL_NOT_PRESENT; 694153323Srodrigc } 695153323Srodrigc return error; 696153323Srodrigc} 697153323Srodrigc 698153323Srodrigc/* 699153323Srodrigc * This function retrieves the parent directory's acl, processes it 700153323Srodrigc * and lets the child inherit the acl(s) that it should. 701153323Srodrigc */ 702153323Srodrigcint 703153323Srodrigcxfs_acl_inherit( 704153323Srodrigc xfs_vnode_t *vp, 705153323Srodrigc xfs_vattr_t *vap, 706153323Srodrigc xfs_acl_t *pdaclp) 707153323Srodrigc{ 708153323Srodrigc xfs_acl_t *cacl; 709153323Srodrigc int error = 0; 710153323Srodrigc int basicperms = 0; 711153323Srodrigc 712153323Srodrigc /* 713153323Srodrigc * If the parent does not have a default ACL, or it's an 714153323Srodrigc * invalid ACL, we're done. 715153323Srodrigc */ 716153323Srodrigc if (!vp) 717153323Srodrigc return 0; 718153323Srodrigc if (!pdaclp || xfs_acl_invalid(pdaclp)) 719153323Srodrigc return 0; 720153323Srodrigc 721153323Srodrigc /* 722153323Srodrigc * Copy the default ACL of the containing directory to 723153323Srodrigc * the access ACL of the new file and use the mode that 724153323Srodrigc * was passed in to set up the correct initial values for 725153323Srodrigc * the u::,g::[m::], and o:: entries. This is what makes 726153323Srodrigc * umask() "work" with ACL's. 727153323Srodrigc */ 728153323Srodrigc 729153323Srodrigc if (!(_ACL_ALLOC(cacl))) 730153323Srodrigc return ENOMEM; 731153323Srodrigc 732153323Srodrigc memcpy(cacl, pdaclp, sizeof(xfs_acl_t)); 733153323Srodrigc xfs_acl_filter_mode(vap->va_mode, cacl); 734153323Srodrigc xfs_acl_setmode(vp, cacl, &basicperms); 735153323Srodrigc 736153323Srodrigc /* 737153323Srodrigc * Set the Default and Access ACL on the file. The mode is already 738153323Srodrigc * set on the file, so we don't need to worry about that. 739153323Srodrigc * 740153323Srodrigc * If the new file is a directory, its default ACL is a copy of 741153323Srodrigc * the containing directory's default ACL. 742153323Srodrigc */ 743159451Srodrigc if (VN_ISDIR(vp)) 744153323Srodrigc xfs_acl_set_attr(vp, pdaclp, _ACL_TYPE_DEFAULT, &error); 745153323Srodrigc if (!error && !basicperms) 746153323Srodrigc xfs_acl_set_attr(vp, cacl, _ACL_TYPE_ACCESS, &error); 747153323Srodrigc _ACL_FREE(cacl); 748153323Srodrigc return error; 749153323Srodrigc} 750153323Srodrigc 751153323Srodrigc/* 752153323Srodrigc * Set up the correct mode on the file based on the supplied ACL. This 753153323Srodrigc * makes sure that the mode on the file reflects the state of the 754153323Srodrigc * u::,g::[m::], and o:: entries in the ACL. Since the mode is where 755153323Srodrigc * the ACL is going to get the permissions for these entries, we must 756153323Srodrigc * synchronize the mode whenever we set the ACL on a file. 757153323Srodrigc */ 758153323SrodrigcSTATIC int 759153323Srodrigcxfs_acl_setmode( 760153323Srodrigc xfs_vnode_t *vp, 761153323Srodrigc xfs_acl_t *acl, 762153323Srodrigc int *basicperms) 763153323Srodrigc{ 764153323Srodrigc xfs_vattr_t va; 765153323Srodrigc xfs_acl_entry_t *ap; 766153323Srodrigc xfs_acl_entry_t *gap = NULL; 767153323Srodrigc int i, error, nomask = 1; 768153323Srodrigc 769153323Srodrigc *basicperms = 1; 770153323Srodrigc 771153323Srodrigc if (acl->acl_cnt == XFS_ACL_NOT_PRESENT) 772153323Srodrigc return 0; 773153323Srodrigc 774153323Srodrigc /* 775153323Srodrigc * Copy the u::, g::, o::, and m:: bits from the ACL into the 776153323Srodrigc * mode. The m:: bits take precedence over the g:: bits. 777153323Srodrigc */ 778153323Srodrigc va.va_mask = XFS_AT_MODE; 779153323Srodrigc XVOP_GETATTR(vp, &va, 0, sys_cred, error); 780153323Srodrigc if (error) 781153323Srodrigc return error; 782153323Srodrigc 783153323Srodrigc va.va_mask = XFS_AT_MODE; 784153323Srodrigc va.va_mode &= ~(S_IRWXU|S_IRWXG|S_IRWXO); 785153323Srodrigc ap = acl->acl_entry; 786153323Srodrigc for (i = 0; i < acl->acl_cnt; ++i) { 787153323Srodrigc switch (ap->ae_tag) { 788153323Srodrigc case ACL_USER_OBJ: 789153323Srodrigc va.va_mode |= ap->ae_perm << 6; 790153323Srodrigc break; 791153323Srodrigc case ACL_GROUP_OBJ: 792153323Srodrigc gap = ap; 793153323Srodrigc break; 794153323Srodrigc case ACL_MASK: /* more than just standard modes */ 795153323Srodrigc nomask = 0; 796153323Srodrigc va.va_mode |= ap->ae_perm << 3; 797153323Srodrigc *basicperms = 0; 798153323Srodrigc break; 799153323Srodrigc case ACL_OTHER: 800153323Srodrigc va.va_mode |= ap->ae_perm; 801153323Srodrigc break; 802153323Srodrigc default: /* more than just standard modes */ 803153323Srodrigc *basicperms = 0; 804153323Srodrigc break; 805153323Srodrigc } 806153323Srodrigc ap++; 807153323Srodrigc } 808153323Srodrigc 809153323Srodrigc /* Set the group bits from ACL_GROUP_OBJ if there's no ACL_MASK */ 810153323Srodrigc if (gap && nomask) 811153323Srodrigc va.va_mode |= gap->ae_perm << 3; 812153323Srodrigc 813153323Srodrigc XVOP_SETATTR(vp, &va, 0, sys_cred, error); 814153323Srodrigc return error; 815153323Srodrigc} 816153323Srodrigc 817153323Srodrigc/* 818153323Srodrigc * The permissions for the special ACL entries (u::, g::[m::], o::) are 819153323Srodrigc * actually stored in the file mode (if there is both a group and a mask, 820153323Srodrigc * the group is stored in the ACL entry and the mask is stored on the file). 821153323Srodrigc * This allows the mode to remain automatically in sync with the ACL without 822153323Srodrigc * the need for a call-back to the ACL system at every point where the mode 823153323Srodrigc * could change. This function takes the permissions from the specified mode 824153323Srodrigc * and places it in the supplied ACL. 825153323Srodrigc * 826153323Srodrigc * This implementation draws its validity from the fact that, when the ACL 827153323Srodrigc * was assigned, the mode was copied from the ACL. 828153323Srodrigc * If the mode did not change, therefore, the mode remains exactly what was 829153323Srodrigc * taken from the special ACL entries at assignment. 830153323Srodrigc * If a subsequent chmod() was done, the POSIX spec says that the change in 831153323Srodrigc * mode must cause an update to the ACL seen at user level and used for 832153323Srodrigc * access checks. Before and after a mode change, therefore, the file mode 833153323Srodrigc * most accurately reflects what the special ACL entries should permit/deny. 834153323Srodrigc * 835153323Srodrigc * CAVEAT: If someone sets the SGI_ACL_FILE attribute directly, 836153323Srodrigc * the existing mode bits will override whatever is in the 837153323Srodrigc * ACL. Similarly, if there is a pre-existing ACL that was 838153323Srodrigc * never in sync with its mode (owing to a bug in 6.5 and 839153323Srodrigc * before), it will now magically (or mystically) be 840153323Srodrigc * synchronized. This could cause slight astonishment, but 841153323Srodrigc * it is better than inconsistent permissions. 842153323Srodrigc * 843153323Srodrigc * The supplied ACL is a template that may contain any combination 844153323Srodrigc * of special entries. These are treated as place holders when we fill 845153323Srodrigc * out the ACL. This routine does not add or remove special entries, it 846153323Srodrigc * simply unites each special entry with its associated set of permissions. 847153323Srodrigc */ 848153323SrodrigcSTATIC void 849153323Srodrigcxfs_acl_sync_mode( 850153323Srodrigc mode_t mode, 851153323Srodrigc xfs_acl_t *acl) 852153323Srodrigc{ 853153323Srodrigc int i, nomask = 1; 854153323Srodrigc xfs_acl_entry_t *ap; 855153323Srodrigc xfs_acl_entry_t *gap = NULL; 856153323Srodrigc 857153323Srodrigc /* 858153323Srodrigc * Set ACL entries. POSIX1003.1eD16 requires that the MASK 859153323Srodrigc * be set instead of the GROUP entry, if there is a MASK. 860153323Srodrigc */ 861153323Srodrigc for (ap = acl->acl_entry, i = 0; i < acl->acl_cnt; ap++, i++) { 862153323Srodrigc switch (ap->ae_tag) { 863153323Srodrigc case ACL_USER_OBJ: 864153323Srodrigc ap->ae_perm = (mode >> 6) & 0x7; 865153323Srodrigc break; 866153323Srodrigc case ACL_GROUP_OBJ: 867153323Srodrigc gap = ap; 868153323Srodrigc break; 869153323Srodrigc case ACL_MASK: 870153323Srodrigc nomask = 0; 871153323Srodrigc ap->ae_perm = (mode >> 3) & 0x7; 872153323Srodrigc break; 873153323Srodrigc case ACL_OTHER: 874153323Srodrigc ap->ae_perm = mode & 0x7; 875153323Srodrigc break; 876153323Srodrigc default: 877153323Srodrigc break; 878153323Srodrigc } 879153323Srodrigc } 880153323Srodrigc /* Set the ACL_GROUP_OBJ if there's no ACL_MASK */ 881153323Srodrigc if (gap && nomask) 882153323Srodrigc gap->ae_perm = (mode >> 3) & 0x7; 883153323Srodrigc} 884153323Srodrigc 885153323Srodrigc/* 886153323Srodrigc * When inheriting an Access ACL from a directory Default ACL, 887153323Srodrigc * the ACL bits are set to the intersection of the ACL default 888153323Srodrigc * permission bits and the file permission bits in mode. If there 889153323Srodrigc * are no permission bits on the file then we must not give them 890153323Srodrigc * the ACL. This is what what makes umask() work with ACLs. 891153323Srodrigc */ 892153323SrodrigcSTATIC void 893153323Srodrigcxfs_acl_filter_mode( 894153323Srodrigc mode_t mode, 895153323Srodrigc xfs_acl_t *acl) 896153323Srodrigc{ 897153323Srodrigc int i, nomask = 1; 898153323Srodrigc xfs_acl_entry_t *ap; 899153323Srodrigc xfs_acl_entry_t *gap = NULL; 900153323Srodrigc 901153323Srodrigc /* 902153323Srodrigc * Set ACL entries. POSIX1003.1eD16 requires that the MASK 903153323Srodrigc * be merged with GROUP entry, if there is a MASK. 904153323Srodrigc */ 905153323Srodrigc for (ap = acl->acl_entry, i = 0; i < acl->acl_cnt; ap++, i++) { 906153323Srodrigc switch (ap->ae_tag) { 907153323Srodrigc case ACL_USER_OBJ: 908153323Srodrigc ap->ae_perm &= (mode >> 6) & 0x7; 909153323Srodrigc break; 910153323Srodrigc case ACL_GROUP_OBJ: 911153323Srodrigc gap = ap; 912153323Srodrigc break; 913153323Srodrigc case ACL_MASK: 914153323Srodrigc nomask = 0; 915153323Srodrigc ap->ae_perm &= (mode >> 3) & 0x7; 916153323Srodrigc break; 917153323Srodrigc case ACL_OTHER: 918153323Srodrigc ap->ae_perm &= mode & 0x7; 919153323Srodrigc break; 920153323Srodrigc default: 921153323Srodrigc break; 922153323Srodrigc } 923153323Srodrigc } 924153323Srodrigc /* Set the ACL_GROUP_OBJ if there's no ACL_MASK */ 925153323Srodrigc if (gap && nomask) 926153323Srodrigc gap->ae_perm &= (mode >> 3) & 0x7; 927153323Srodrigc} 928153323Srodrigc 929