162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Common NFSv4 ACL handling code. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (c) 2002, 2003 The Regents of the University of Michigan. 562306a36Sopenharmony_ci * All rights reserved. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Marius Aamodt Eriksen <marius@umich.edu> 862306a36Sopenharmony_ci * Jeff Sedlak <jsedlak@umich.edu> 962306a36Sopenharmony_ci * J. Bruce Fields <bfields@umich.edu> 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 1262306a36Sopenharmony_ci * modification, are permitted provided that the following conditions 1362306a36Sopenharmony_ci * are met: 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 1662306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 1762306a36Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 1862306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 1962306a36Sopenharmony_ci * documentation and/or other materials provided with the distribution. 2062306a36Sopenharmony_ci * 3. Neither the name of the University nor the names of its 2162306a36Sopenharmony_ci * contributors may be used to endorse or promote products derived 2262306a36Sopenharmony_ci * from this software without specific prior written permission. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 2562306a36Sopenharmony_ci * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 2662306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 2762306a36Sopenharmony_ci * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2862306a36Sopenharmony_ci * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2962306a36Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 3062306a36Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 3162306a36Sopenharmony_ci * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 3262306a36Sopenharmony_ci * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 3362306a36Sopenharmony_ci * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 3462306a36Sopenharmony_ci * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include <linux/fs.h> 3862306a36Sopenharmony_ci#include <linux/slab.h> 3962306a36Sopenharmony_ci#include <linux/posix_acl.h> 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#include "nfsfh.h" 4262306a36Sopenharmony_ci#include "nfsd.h" 4362306a36Sopenharmony_ci#include "acl.h" 4462306a36Sopenharmony_ci#include "vfs.h" 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define NFS4_ACL_TYPE_DEFAULT 0x01 4762306a36Sopenharmony_ci#define NFS4_ACL_DIR 0x02 4862306a36Sopenharmony_ci#define NFS4_ACL_OWNER 0x04 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/* mode bit translations: */ 5162306a36Sopenharmony_ci#define NFS4_READ_MODE (NFS4_ACE_READ_DATA) 5262306a36Sopenharmony_ci#define NFS4_WRITE_MODE (NFS4_ACE_WRITE_DATA | NFS4_ACE_APPEND_DATA) 5362306a36Sopenharmony_ci#define NFS4_EXECUTE_MODE NFS4_ACE_EXECUTE 5462306a36Sopenharmony_ci#define NFS4_ANYONE_MODE (NFS4_ACE_READ_ATTRIBUTES | NFS4_ACE_READ_ACL | NFS4_ACE_SYNCHRONIZE) 5562306a36Sopenharmony_ci#define NFS4_OWNER_MODE (NFS4_ACE_WRITE_ATTRIBUTES | NFS4_ACE_WRITE_ACL) 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* flags used to simulate posix default ACLs */ 5862306a36Sopenharmony_ci#define NFS4_INHERITANCE_FLAGS (NFS4_ACE_FILE_INHERIT_ACE \ 5962306a36Sopenharmony_ci | NFS4_ACE_DIRECTORY_INHERIT_ACE) 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#define NFS4_SUPPORTED_FLAGS (NFS4_INHERITANCE_FLAGS \ 6262306a36Sopenharmony_ci | NFS4_ACE_INHERIT_ONLY_ACE \ 6362306a36Sopenharmony_ci | NFS4_ACE_IDENTIFIER_GROUP) 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic u32 6662306a36Sopenharmony_cimask_from_posix(unsigned short perm, unsigned int flags) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci int mask = NFS4_ANYONE_MODE; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci if (flags & NFS4_ACL_OWNER) 7162306a36Sopenharmony_ci mask |= NFS4_OWNER_MODE; 7262306a36Sopenharmony_ci if (perm & ACL_READ) 7362306a36Sopenharmony_ci mask |= NFS4_READ_MODE; 7462306a36Sopenharmony_ci if (perm & ACL_WRITE) 7562306a36Sopenharmony_ci mask |= NFS4_WRITE_MODE; 7662306a36Sopenharmony_ci if ((perm & ACL_WRITE) && (flags & NFS4_ACL_DIR)) 7762306a36Sopenharmony_ci mask |= NFS4_ACE_DELETE_CHILD; 7862306a36Sopenharmony_ci if (perm & ACL_EXECUTE) 7962306a36Sopenharmony_ci mask |= NFS4_EXECUTE_MODE; 8062306a36Sopenharmony_ci return mask; 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic u32 8462306a36Sopenharmony_cideny_mask_from_posix(unsigned short perm, u32 flags) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci u32 mask = 0; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci if (perm & ACL_READ) 8962306a36Sopenharmony_ci mask |= NFS4_READ_MODE; 9062306a36Sopenharmony_ci if (perm & ACL_WRITE) 9162306a36Sopenharmony_ci mask |= NFS4_WRITE_MODE; 9262306a36Sopenharmony_ci if ((perm & ACL_WRITE) && (flags & NFS4_ACL_DIR)) 9362306a36Sopenharmony_ci mask |= NFS4_ACE_DELETE_CHILD; 9462306a36Sopenharmony_ci if (perm & ACL_EXECUTE) 9562306a36Sopenharmony_ci mask |= NFS4_EXECUTE_MODE; 9662306a36Sopenharmony_ci return mask; 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/* XXX: modify functions to return NFS errors; they're only ever 10062306a36Sopenharmony_ci * used by nfs code, after all.... */ 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci/* We only map from NFSv4 to POSIX ACLs when setting ACLs, when we err on the 10362306a36Sopenharmony_ci * side of being more restrictive, so the mode bit mapping below is 10462306a36Sopenharmony_ci * pessimistic. An optimistic version would be needed to handle DENY's, 10562306a36Sopenharmony_ci * but we expect to coalesce all ALLOWs and DENYs before mapping to mode 10662306a36Sopenharmony_ci * bits. */ 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic void 10962306a36Sopenharmony_cilow_mode_from_nfs4(u32 perm, unsigned short *mode, unsigned int flags) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci u32 write_mode = NFS4_WRITE_MODE; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci if (flags & NFS4_ACL_DIR) 11462306a36Sopenharmony_ci write_mode |= NFS4_ACE_DELETE_CHILD; 11562306a36Sopenharmony_ci *mode = 0; 11662306a36Sopenharmony_ci if ((perm & NFS4_READ_MODE) == NFS4_READ_MODE) 11762306a36Sopenharmony_ci *mode |= ACL_READ; 11862306a36Sopenharmony_ci if ((perm & write_mode) == write_mode) 11962306a36Sopenharmony_ci *mode |= ACL_WRITE; 12062306a36Sopenharmony_ci if ((perm & NFS4_EXECUTE_MODE) == NFS4_EXECUTE_MODE) 12162306a36Sopenharmony_ci *mode |= ACL_EXECUTE; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic short ace2type(struct nfs4_ace *); 12562306a36Sopenharmony_cistatic void _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *, 12662306a36Sopenharmony_ci unsigned int); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ciint 12962306a36Sopenharmony_cinfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, 13062306a36Sopenharmony_ci struct nfs4_acl **acl) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci struct inode *inode = d_inode(dentry); 13362306a36Sopenharmony_ci int error = 0; 13462306a36Sopenharmony_ci struct posix_acl *pacl = NULL, *dpacl = NULL; 13562306a36Sopenharmony_ci unsigned int flags = 0; 13662306a36Sopenharmony_ci int size = 0; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci pacl = get_inode_acl(inode, ACL_TYPE_ACCESS); 13962306a36Sopenharmony_ci if (!pacl) 14062306a36Sopenharmony_ci pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci if (IS_ERR(pacl)) 14362306a36Sopenharmony_ci return PTR_ERR(pacl); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci /* allocate for worst case: one (deny, allow) pair each: */ 14662306a36Sopenharmony_ci size += 2 * pacl->a_count; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (S_ISDIR(inode->i_mode)) { 14962306a36Sopenharmony_ci flags = NFS4_ACL_DIR; 15062306a36Sopenharmony_ci dpacl = get_inode_acl(inode, ACL_TYPE_DEFAULT); 15162306a36Sopenharmony_ci if (IS_ERR(dpacl)) { 15262306a36Sopenharmony_ci error = PTR_ERR(dpacl); 15362306a36Sopenharmony_ci goto rel_pacl; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci if (dpacl) 15762306a36Sopenharmony_ci size += 2 * dpacl->a_count; 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci *acl = kmalloc(nfs4_acl_bytes(size), GFP_KERNEL); 16162306a36Sopenharmony_ci if (*acl == NULL) { 16262306a36Sopenharmony_ci error = -ENOMEM; 16362306a36Sopenharmony_ci goto out; 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci (*acl)->naces = 0; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci _posix_to_nfsv4_one(pacl, *acl, flags & ~NFS4_ACL_TYPE_DEFAULT); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci if (dpacl) 17062306a36Sopenharmony_ci _posix_to_nfsv4_one(dpacl, *acl, flags | NFS4_ACL_TYPE_DEFAULT); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ciout: 17362306a36Sopenharmony_ci posix_acl_release(dpacl); 17462306a36Sopenharmony_cirel_pacl: 17562306a36Sopenharmony_ci posix_acl_release(pacl); 17662306a36Sopenharmony_ci return error; 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistruct posix_acl_summary { 18062306a36Sopenharmony_ci unsigned short owner; 18162306a36Sopenharmony_ci unsigned short users; 18262306a36Sopenharmony_ci unsigned short group; 18362306a36Sopenharmony_ci unsigned short groups; 18462306a36Sopenharmony_ci unsigned short other; 18562306a36Sopenharmony_ci unsigned short mask; 18662306a36Sopenharmony_ci}; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic void 18962306a36Sopenharmony_cisummarize_posix_acl(struct posix_acl *acl, struct posix_acl_summary *pas) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci struct posix_acl_entry *pa, *pe; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci /* 19462306a36Sopenharmony_ci * Only pas.users and pas.groups need initialization; previous 19562306a36Sopenharmony_ci * posix_acl_valid() calls ensure that the other fields will be 19662306a36Sopenharmony_ci * initialized in the following loop. But, just to placate gcc: 19762306a36Sopenharmony_ci */ 19862306a36Sopenharmony_ci memset(pas, 0, sizeof(*pas)); 19962306a36Sopenharmony_ci pas->mask = 07; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci pe = acl->a_entries + acl->a_count; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci FOREACH_ACL_ENTRY(pa, acl, pe) { 20462306a36Sopenharmony_ci switch (pa->e_tag) { 20562306a36Sopenharmony_ci case ACL_USER_OBJ: 20662306a36Sopenharmony_ci pas->owner = pa->e_perm; 20762306a36Sopenharmony_ci break; 20862306a36Sopenharmony_ci case ACL_GROUP_OBJ: 20962306a36Sopenharmony_ci pas->group = pa->e_perm; 21062306a36Sopenharmony_ci break; 21162306a36Sopenharmony_ci case ACL_USER: 21262306a36Sopenharmony_ci pas->users |= pa->e_perm; 21362306a36Sopenharmony_ci break; 21462306a36Sopenharmony_ci case ACL_GROUP: 21562306a36Sopenharmony_ci pas->groups |= pa->e_perm; 21662306a36Sopenharmony_ci break; 21762306a36Sopenharmony_ci case ACL_OTHER: 21862306a36Sopenharmony_ci pas->other = pa->e_perm; 21962306a36Sopenharmony_ci break; 22062306a36Sopenharmony_ci case ACL_MASK: 22162306a36Sopenharmony_ci pas->mask = pa->e_perm; 22262306a36Sopenharmony_ci break; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci /* We'll only care about effective permissions: */ 22662306a36Sopenharmony_ci pas->users &= pas->mask; 22762306a36Sopenharmony_ci pas->group &= pas->mask; 22862306a36Sopenharmony_ci pas->groups &= pas->mask; 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci/* We assume the acl has been verified with posix_acl_valid. */ 23262306a36Sopenharmony_cistatic void 23362306a36Sopenharmony_ci_posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, 23462306a36Sopenharmony_ci unsigned int flags) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci struct posix_acl_entry *pa, *group_owner_entry; 23762306a36Sopenharmony_ci struct nfs4_ace *ace; 23862306a36Sopenharmony_ci struct posix_acl_summary pas; 23962306a36Sopenharmony_ci unsigned short deny; 24062306a36Sopenharmony_ci int eflag = ((flags & NFS4_ACL_TYPE_DEFAULT) ? 24162306a36Sopenharmony_ci NFS4_INHERITANCE_FLAGS | NFS4_ACE_INHERIT_ONLY_ACE : 0); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci BUG_ON(pacl->a_count < 3); 24462306a36Sopenharmony_ci summarize_posix_acl(pacl, &pas); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci pa = pacl->a_entries; 24762306a36Sopenharmony_ci ace = acl->aces + acl->naces; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci /* We could deny everything not granted by the owner: */ 25062306a36Sopenharmony_ci deny = ~pas.owner; 25162306a36Sopenharmony_ci /* 25262306a36Sopenharmony_ci * but it is equivalent (and simpler) to deny only what is not 25362306a36Sopenharmony_ci * granted by later entries: 25462306a36Sopenharmony_ci */ 25562306a36Sopenharmony_ci deny &= pas.users | pas.group | pas.groups | pas.other; 25662306a36Sopenharmony_ci if (deny) { 25762306a36Sopenharmony_ci ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; 25862306a36Sopenharmony_ci ace->flag = eflag; 25962306a36Sopenharmony_ci ace->access_mask = deny_mask_from_posix(deny, flags); 26062306a36Sopenharmony_ci ace->whotype = NFS4_ACL_WHO_OWNER; 26162306a36Sopenharmony_ci ace++; 26262306a36Sopenharmony_ci acl->naces++; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; 26662306a36Sopenharmony_ci ace->flag = eflag; 26762306a36Sopenharmony_ci ace->access_mask = mask_from_posix(pa->e_perm, flags | NFS4_ACL_OWNER); 26862306a36Sopenharmony_ci ace->whotype = NFS4_ACL_WHO_OWNER; 26962306a36Sopenharmony_ci ace++; 27062306a36Sopenharmony_ci acl->naces++; 27162306a36Sopenharmony_ci pa++; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci while (pa->e_tag == ACL_USER) { 27462306a36Sopenharmony_ci deny = ~(pa->e_perm & pas.mask); 27562306a36Sopenharmony_ci deny &= pas.groups | pas.group | pas.other; 27662306a36Sopenharmony_ci if (deny) { 27762306a36Sopenharmony_ci ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; 27862306a36Sopenharmony_ci ace->flag = eflag; 27962306a36Sopenharmony_ci ace->access_mask = deny_mask_from_posix(deny, flags); 28062306a36Sopenharmony_ci ace->whotype = NFS4_ACL_WHO_NAMED; 28162306a36Sopenharmony_ci ace->who_uid = pa->e_uid; 28262306a36Sopenharmony_ci ace++; 28362306a36Sopenharmony_ci acl->naces++; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; 28662306a36Sopenharmony_ci ace->flag = eflag; 28762306a36Sopenharmony_ci ace->access_mask = mask_from_posix(pa->e_perm & pas.mask, 28862306a36Sopenharmony_ci flags); 28962306a36Sopenharmony_ci ace->whotype = NFS4_ACL_WHO_NAMED; 29062306a36Sopenharmony_ci ace->who_uid = pa->e_uid; 29162306a36Sopenharmony_ci ace++; 29262306a36Sopenharmony_ci acl->naces++; 29362306a36Sopenharmony_ci pa++; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci /* In the case of groups, we apply allow ACEs first, then deny ACEs, 29762306a36Sopenharmony_ci * since a user can be in more than one group. */ 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci /* allow ACEs */ 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci group_owner_entry = pa; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; 30462306a36Sopenharmony_ci ace->flag = eflag; 30562306a36Sopenharmony_ci ace->access_mask = mask_from_posix(pas.group, flags); 30662306a36Sopenharmony_ci ace->whotype = NFS4_ACL_WHO_GROUP; 30762306a36Sopenharmony_ci ace++; 30862306a36Sopenharmony_ci acl->naces++; 30962306a36Sopenharmony_ci pa++; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci while (pa->e_tag == ACL_GROUP) { 31262306a36Sopenharmony_ci ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; 31362306a36Sopenharmony_ci ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP; 31462306a36Sopenharmony_ci ace->access_mask = mask_from_posix(pa->e_perm & pas.mask, 31562306a36Sopenharmony_ci flags); 31662306a36Sopenharmony_ci ace->whotype = NFS4_ACL_WHO_NAMED; 31762306a36Sopenharmony_ci ace->who_gid = pa->e_gid; 31862306a36Sopenharmony_ci ace++; 31962306a36Sopenharmony_ci acl->naces++; 32062306a36Sopenharmony_ci pa++; 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci /* deny ACEs */ 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci pa = group_owner_entry; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci deny = ~pas.group & pas.other; 32862306a36Sopenharmony_ci if (deny) { 32962306a36Sopenharmony_ci ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; 33062306a36Sopenharmony_ci ace->flag = eflag; 33162306a36Sopenharmony_ci ace->access_mask = deny_mask_from_posix(deny, flags); 33262306a36Sopenharmony_ci ace->whotype = NFS4_ACL_WHO_GROUP; 33362306a36Sopenharmony_ci ace++; 33462306a36Sopenharmony_ci acl->naces++; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci pa++; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci while (pa->e_tag == ACL_GROUP) { 33962306a36Sopenharmony_ci deny = ~(pa->e_perm & pas.mask); 34062306a36Sopenharmony_ci deny &= pas.other; 34162306a36Sopenharmony_ci if (deny) { 34262306a36Sopenharmony_ci ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; 34362306a36Sopenharmony_ci ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP; 34462306a36Sopenharmony_ci ace->access_mask = deny_mask_from_posix(deny, flags); 34562306a36Sopenharmony_ci ace->whotype = NFS4_ACL_WHO_NAMED; 34662306a36Sopenharmony_ci ace->who_gid = pa->e_gid; 34762306a36Sopenharmony_ci ace++; 34862306a36Sopenharmony_ci acl->naces++; 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci pa++; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci if (pa->e_tag == ACL_MASK) 35462306a36Sopenharmony_ci pa++; 35562306a36Sopenharmony_ci ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; 35662306a36Sopenharmony_ci ace->flag = eflag; 35762306a36Sopenharmony_ci ace->access_mask = mask_from_posix(pa->e_perm, flags); 35862306a36Sopenharmony_ci ace->whotype = NFS4_ACL_WHO_EVERYONE; 35962306a36Sopenharmony_ci acl->naces++; 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic bool 36362306a36Sopenharmony_cipace_gt(struct posix_acl_entry *pace1, struct posix_acl_entry *pace2) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci if (pace1->e_tag != pace2->e_tag) 36662306a36Sopenharmony_ci return pace1->e_tag > pace2->e_tag; 36762306a36Sopenharmony_ci if (pace1->e_tag == ACL_USER) 36862306a36Sopenharmony_ci return uid_gt(pace1->e_uid, pace2->e_uid); 36962306a36Sopenharmony_ci if (pace1->e_tag == ACL_GROUP) 37062306a36Sopenharmony_ci return gid_gt(pace1->e_gid, pace2->e_gid); 37162306a36Sopenharmony_ci return false; 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistatic void 37562306a36Sopenharmony_cisort_pacl_range(struct posix_acl *pacl, int start, int end) { 37662306a36Sopenharmony_ci int sorted = 0, i; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci /* We just do a bubble sort; easy to do in place, and we're not 37962306a36Sopenharmony_ci * expecting acl's to be long enough to justify anything more. */ 38062306a36Sopenharmony_ci while (!sorted) { 38162306a36Sopenharmony_ci sorted = 1; 38262306a36Sopenharmony_ci for (i = start; i < end; i++) { 38362306a36Sopenharmony_ci if (pace_gt(&pacl->a_entries[i], 38462306a36Sopenharmony_ci &pacl->a_entries[i+1])) { 38562306a36Sopenharmony_ci sorted = 0; 38662306a36Sopenharmony_ci swap(pacl->a_entries[i], 38762306a36Sopenharmony_ci pacl->a_entries[i + 1]); 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic void 39462306a36Sopenharmony_cisort_pacl(struct posix_acl *pacl) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci /* posix_acl_valid requires that users and groups be in order 39762306a36Sopenharmony_ci * by uid/gid. */ 39862306a36Sopenharmony_ci int i, j; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci /* no users or groups */ 40162306a36Sopenharmony_ci if (!pacl || pacl->a_count <= 4) 40262306a36Sopenharmony_ci return; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci i = 1; 40562306a36Sopenharmony_ci while (pacl->a_entries[i].e_tag == ACL_USER) 40662306a36Sopenharmony_ci i++; 40762306a36Sopenharmony_ci sort_pacl_range(pacl, 1, i-1); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci BUG_ON(pacl->a_entries[i].e_tag != ACL_GROUP_OBJ); 41062306a36Sopenharmony_ci j = ++i; 41162306a36Sopenharmony_ci while (pacl->a_entries[j].e_tag == ACL_GROUP) 41262306a36Sopenharmony_ci j++; 41362306a36Sopenharmony_ci sort_pacl_range(pacl, i, j-1); 41462306a36Sopenharmony_ci return; 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci/* 41862306a36Sopenharmony_ci * While processing the NFSv4 ACE, this maintains bitmasks representing 41962306a36Sopenharmony_ci * which permission bits have been allowed and which denied to a given 42062306a36Sopenharmony_ci * entity: */ 42162306a36Sopenharmony_cistruct posix_ace_state { 42262306a36Sopenharmony_ci u32 allow; 42362306a36Sopenharmony_ci u32 deny; 42462306a36Sopenharmony_ci}; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_cistruct posix_user_ace_state { 42762306a36Sopenharmony_ci union { 42862306a36Sopenharmony_ci kuid_t uid; 42962306a36Sopenharmony_ci kgid_t gid; 43062306a36Sopenharmony_ci }; 43162306a36Sopenharmony_ci struct posix_ace_state perms; 43262306a36Sopenharmony_ci}; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cistruct posix_ace_state_array { 43562306a36Sopenharmony_ci int n; 43662306a36Sopenharmony_ci struct posix_user_ace_state aces[]; 43762306a36Sopenharmony_ci}; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci/* 44062306a36Sopenharmony_ci * While processing the NFSv4 ACE, this maintains the partial permissions 44162306a36Sopenharmony_ci * calculated so far: */ 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_cistruct posix_acl_state { 44462306a36Sopenharmony_ci unsigned char valid; 44562306a36Sopenharmony_ci struct posix_ace_state owner; 44662306a36Sopenharmony_ci struct posix_ace_state group; 44762306a36Sopenharmony_ci struct posix_ace_state other; 44862306a36Sopenharmony_ci struct posix_ace_state everyone; 44962306a36Sopenharmony_ci struct posix_ace_state mask; /* Deny unused in this case */ 45062306a36Sopenharmony_ci struct posix_ace_state_array *users; 45162306a36Sopenharmony_ci struct posix_ace_state_array *groups; 45262306a36Sopenharmony_ci}; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_cistatic int 45562306a36Sopenharmony_ciinit_state(struct posix_acl_state *state, int cnt) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci int alloc; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci memset(state, 0, sizeof(struct posix_acl_state)); 46062306a36Sopenharmony_ci /* 46162306a36Sopenharmony_ci * In the worst case, each individual acl could be for a distinct 46262306a36Sopenharmony_ci * named user or group, but we don't know which, so we allocate 46362306a36Sopenharmony_ci * enough space for either: 46462306a36Sopenharmony_ci */ 46562306a36Sopenharmony_ci alloc = sizeof(struct posix_ace_state_array) 46662306a36Sopenharmony_ci + cnt*sizeof(struct posix_user_ace_state); 46762306a36Sopenharmony_ci state->users = kzalloc(alloc, GFP_KERNEL); 46862306a36Sopenharmony_ci if (!state->users) 46962306a36Sopenharmony_ci return -ENOMEM; 47062306a36Sopenharmony_ci state->groups = kzalloc(alloc, GFP_KERNEL); 47162306a36Sopenharmony_ci if (!state->groups) { 47262306a36Sopenharmony_ci kfree(state->users); 47362306a36Sopenharmony_ci return -ENOMEM; 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci return 0; 47662306a36Sopenharmony_ci} 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_cistatic void 47962306a36Sopenharmony_cifree_state(struct posix_acl_state *state) { 48062306a36Sopenharmony_ci kfree(state->users); 48162306a36Sopenharmony_ci kfree(state->groups); 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic inline void add_to_mask(struct posix_acl_state *state, struct posix_ace_state *astate) 48562306a36Sopenharmony_ci{ 48662306a36Sopenharmony_ci state->mask.allow |= astate->allow; 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cistatic struct posix_acl * 49062306a36Sopenharmony_ciposix_state_to_acl(struct posix_acl_state *state, unsigned int flags) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci struct posix_acl_entry *pace; 49362306a36Sopenharmony_ci struct posix_acl *pacl; 49462306a36Sopenharmony_ci int nace; 49562306a36Sopenharmony_ci int i; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci /* 49862306a36Sopenharmony_ci * ACLs with no ACEs are treated differently in the inheritable 49962306a36Sopenharmony_ci * and effective cases: when there are no inheritable ACEs, 50062306a36Sopenharmony_ci * calls ->set_acl with a NULL ACL structure. 50162306a36Sopenharmony_ci */ 50262306a36Sopenharmony_ci if (!state->valid && (flags & NFS4_ACL_TYPE_DEFAULT)) 50362306a36Sopenharmony_ci return NULL; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci /* 50662306a36Sopenharmony_ci * When there are no effective ACEs, the following will end 50762306a36Sopenharmony_ci * up setting a 3-element effective posix ACL with all 50862306a36Sopenharmony_ci * permissions zero. 50962306a36Sopenharmony_ci */ 51062306a36Sopenharmony_ci if (!state->users->n && !state->groups->n) 51162306a36Sopenharmony_ci nace = 3; 51262306a36Sopenharmony_ci else /* Note we also include a MASK ACE in this case: */ 51362306a36Sopenharmony_ci nace = 4 + state->users->n + state->groups->n; 51462306a36Sopenharmony_ci pacl = posix_acl_alloc(nace, GFP_KERNEL); 51562306a36Sopenharmony_ci if (!pacl) 51662306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci pace = pacl->a_entries; 51962306a36Sopenharmony_ci pace->e_tag = ACL_USER_OBJ; 52062306a36Sopenharmony_ci low_mode_from_nfs4(state->owner.allow, &pace->e_perm, flags); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci for (i=0; i < state->users->n; i++) { 52362306a36Sopenharmony_ci pace++; 52462306a36Sopenharmony_ci pace->e_tag = ACL_USER; 52562306a36Sopenharmony_ci low_mode_from_nfs4(state->users->aces[i].perms.allow, 52662306a36Sopenharmony_ci &pace->e_perm, flags); 52762306a36Sopenharmony_ci pace->e_uid = state->users->aces[i].uid; 52862306a36Sopenharmony_ci add_to_mask(state, &state->users->aces[i].perms); 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci pace++; 53262306a36Sopenharmony_ci pace->e_tag = ACL_GROUP_OBJ; 53362306a36Sopenharmony_ci low_mode_from_nfs4(state->group.allow, &pace->e_perm, flags); 53462306a36Sopenharmony_ci add_to_mask(state, &state->group); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci for (i=0; i < state->groups->n; i++) { 53762306a36Sopenharmony_ci pace++; 53862306a36Sopenharmony_ci pace->e_tag = ACL_GROUP; 53962306a36Sopenharmony_ci low_mode_from_nfs4(state->groups->aces[i].perms.allow, 54062306a36Sopenharmony_ci &pace->e_perm, flags); 54162306a36Sopenharmony_ci pace->e_gid = state->groups->aces[i].gid; 54262306a36Sopenharmony_ci add_to_mask(state, &state->groups->aces[i].perms); 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci if (state->users->n || state->groups->n) { 54662306a36Sopenharmony_ci pace++; 54762306a36Sopenharmony_ci pace->e_tag = ACL_MASK; 54862306a36Sopenharmony_ci low_mode_from_nfs4(state->mask.allow, &pace->e_perm, flags); 54962306a36Sopenharmony_ci } 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci pace++; 55262306a36Sopenharmony_ci pace->e_tag = ACL_OTHER; 55362306a36Sopenharmony_ci low_mode_from_nfs4(state->other.allow, &pace->e_perm, flags); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci return pacl; 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_cistatic inline void allow_bits(struct posix_ace_state *astate, u32 mask) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci /* Allow all bits in the mask not already denied: */ 56162306a36Sopenharmony_ci astate->allow |= mask & ~astate->deny; 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_cistatic inline void deny_bits(struct posix_ace_state *astate, u32 mask) 56562306a36Sopenharmony_ci{ 56662306a36Sopenharmony_ci /* Deny all bits in the mask not already allowed: */ 56762306a36Sopenharmony_ci astate->deny |= mask & ~astate->allow; 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_cistatic int find_uid(struct posix_acl_state *state, kuid_t uid) 57162306a36Sopenharmony_ci{ 57262306a36Sopenharmony_ci struct posix_ace_state_array *a = state->users; 57362306a36Sopenharmony_ci int i; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci for (i = 0; i < a->n; i++) 57662306a36Sopenharmony_ci if (uid_eq(a->aces[i].uid, uid)) 57762306a36Sopenharmony_ci return i; 57862306a36Sopenharmony_ci /* Not found: */ 57962306a36Sopenharmony_ci a->n++; 58062306a36Sopenharmony_ci a->aces[i].uid = uid; 58162306a36Sopenharmony_ci a->aces[i].perms.allow = state->everyone.allow; 58262306a36Sopenharmony_ci a->aces[i].perms.deny = state->everyone.deny; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci return i; 58562306a36Sopenharmony_ci} 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_cistatic int find_gid(struct posix_acl_state *state, kgid_t gid) 58862306a36Sopenharmony_ci{ 58962306a36Sopenharmony_ci struct posix_ace_state_array *a = state->groups; 59062306a36Sopenharmony_ci int i; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci for (i = 0; i < a->n; i++) 59362306a36Sopenharmony_ci if (gid_eq(a->aces[i].gid, gid)) 59462306a36Sopenharmony_ci return i; 59562306a36Sopenharmony_ci /* Not found: */ 59662306a36Sopenharmony_ci a->n++; 59762306a36Sopenharmony_ci a->aces[i].gid = gid; 59862306a36Sopenharmony_ci a->aces[i].perms.allow = state->everyone.allow; 59962306a36Sopenharmony_ci a->aces[i].perms.deny = state->everyone.deny; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci return i; 60262306a36Sopenharmony_ci} 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_cistatic void deny_bits_array(struct posix_ace_state_array *a, u32 mask) 60562306a36Sopenharmony_ci{ 60662306a36Sopenharmony_ci int i; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci for (i=0; i < a->n; i++) 60962306a36Sopenharmony_ci deny_bits(&a->aces[i].perms, mask); 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_cistatic void allow_bits_array(struct posix_ace_state_array *a, u32 mask) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci int i; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci for (i=0; i < a->n; i++) 61762306a36Sopenharmony_ci allow_bits(&a->aces[i].perms, mask); 61862306a36Sopenharmony_ci} 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_cistatic void process_one_v4_ace(struct posix_acl_state *state, 62162306a36Sopenharmony_ci struct nfs4_ace *ace) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci u32 mask = ace->access_mask; 62462306a36Sopenharmony_ci short type = ace2type(ace); 62562306a36Sopenharmony_ci int i; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci state->valid |= type; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci switch (type) { 63062306a36Sopenharmony_ci case ACL_USER_OBJ: 63162306a36Sopenharmony_ci if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { 63262306a36Sopenharmony_ci allow_bits(&state->owner, mask); 63362306a36Sopenharmony_ci } else { 63462306a36Sopenharmony_ci deny_bits(&state->owner, mask); 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci break; 63762306a36Sopenharmony_ci case ACL_USER: 63862306a36Sopenharmony_ci i = find_uid(state, ace->who_uid); 63962306a36Sopenharmony_ci if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { 64062306a36Sopenharmony_ci allow_bits(&state->users->aces[i].perms, mask); 64162306a36Sopenharmony_ci } else { 64262306a36Sopenharmony_ci deny_bits(&state->users->aces[i].perms, mask); 64362306a36Sopenharmony_ci mask = state->users->aces[i].perms.deny; 64462306a36Sopenharmony_ci deny_bits(&state->owner, mask); 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci break; 64762306a36Sopenharmony_ci case ACL_GROUP_OBJ: 64862306a36Sopenharmony_ci if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { 64962306a36Sopenharmony_ci allow_bits(&state->group, mask); 65062306a36Sopenharmony_ci } else { 65162306a36Sopenharmony_ci deny_bits(&state->group, mask); 65262306a36Sopenharmony_ci mask = state->group.deny; 65362306a36Sopenharmony_ci deny_bits(&state->owner, mask); 65462306a36Sopenharmony_ci deny_bits(&state->everyone, mask); 65562306a36Sopenharmony_ci deny_bits_array(state->users, mask); 65662306a36Sopenharmony_ci deny_bits_array(state->groups, mask); 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci break; 65962306a36Sopenharmony_ci case ACL_GROUP: 66062306a36Sopenharmony_ci i = find_gid(state, ace->who_gid); 66162306a36Sopenharmony_ci if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { 66262306a36Sopenharmony_ci allow_bits(&state->groups->aces[i].perms, mask); 66362306a36Sopenharmony_ci } else { 66462306a36Sopenharmony_ci deny_bits(&state->groups->aces[i].perms, mask); 66562306a36Sopenharmony_ci mask = state->groups->aces[i].perms.deny; 66662306a36Sopenharmony_ci deny_bits(&state->owner, mask); 66762306a36Sopenharmony_ci deny_bits(&state->group, mask); 66862306a36Sopenharmony_ci deny_bits(&state->everyone, mask); 66962306a36Sopenharmony_ci deny_bits_array(state->users, mask); 67062306a36Sopenharmony_ci deny_bits_array(state->groups, mask); 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci break; 67362306a36Sopenharmony_ci case ACL_OTHER: 67462306a36Sopenharmony_ci if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { 67562306a36Sopenharmony_ci allow_bits(&state->owner, mask); 67662306a36Sopenharmony_ci allow_bits(&state->group, mask); 67762306a36Sopenharmony_ci allow_bits(&state->other, mask); 67862306a36Sopenharmony_ci allow_bits(&state->everyone, mask); 67962306a36Sopenharmony_ci allow_bits_array(state->users, mask); 68062306a36Sopenharmony_ci allow_bits_array(state->groups, mask); 68162306a36Sopenharmony_ci } else { 68262306a36Sopenharmony_ci deny_bits(&state->owner, mask); 68362306a36Sopenharmony_ci deny_bits(&state->group, mask); 68462306a36Sopenharmony_ci deny_bits(&state->other, mask); 68562306a36Sopenharmony_ci deny_bits(&state->everyone, mask); 68662306a36Sopenharmony_ci deny_bits_array(state->users, mask); 68762306a36Sopenharmony_ci deny_bits_array(state->groups, mask); 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci} 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_cistatic int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, 69362306a36Sopenharmony_ci struct posix_acl **pacl, struct posix_acl **dpacl, 69462306a36Sopenharmony_ci unsigned int flags) 69562306a36Sopenharmony_ci{ 69662306a36Sopenharmony_ci struct posix_acl_state effective_acl_state, default_acl_state; 69762306a36Sopenharmony_ci struct nfs4_ace *ace; 69862306a36Sopenharmony_ci int ret; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci ret = init_state(&effective_acl_state, acl->naces); 70162306a36Sopenharmony_ci if (ret) 70262306a36Sopenharmony_ci return ret; 70362306a36Sopenharmony_ci ret = init_state(&default_acl_state, acl->naces); 70462306a36Sopenharmony_ci if (ret) 70562306a36Sopenharmony_ci goto out_estate; 70662306a36Sopenharmony_ci ret = -EINVAL; 70762306a36Sopenharmony_ci for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) { 70862306a36Sopenharmony_ci if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE && 70962306a36Sopenharmony_ci ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE) 71062306a36Sopenharmony_ci goto out_dstate; 71162306a36Sopenharmony_ci if (ace->flag & ~NFS4_SUPPORTED_FLAGS) 71262306a36Sopenharmony_ci goto out_dstate; 71362306a36Sopenharmony_ci if ((ace->flag & NFS4_INHERITANCE_FLAGS) == 0) { 71462306a36Sopenharmony_ci process_one_v4_ace(&effective_acl_state, ace); 71562306a36Sopenharmony_ci continue; 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci if (!(flags & NFS4_ACL_DIR)) 71862306a36Sopenharmony_ci goto out_dstate; 71962306a36Sopenharmony_ci /* 72062306a36Sopenharmony_ci * Note that when only one of FILE_INHERIT or DIRECTORY_INHERIT 72162306a36Sopenharmony_ci * is set, we're effectively turning on the other. That's OK, 72262306a36Sopenharmony_ci * according to rfc 3530. 72362306a36Sopenharmony_ci */ 72462306a36Sopenharmony_ci process_one_v4_ace(&default_acl_state, ace); 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci if (!(ace->flag & NFS4_ACE_INHERIT_ONLY_ACE)) 72762306a36Sopenharmony_ci process_one_v4_ace(&effective_acl_state, ace); 72862306a36Sopenharmony_ci } 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci /* 73162306a36Sopenharmony_ci * At this point, the default ACL may have zeroed-out entries for owner, 73262306a36Sopenharmony_ci * group and other. That usually results in a non-sensical resulting ACL 73362306a36Sopenharmony_ci * that denies all access except to any ACE that was explicitly added. 73462306a36Sopenharmony_ci * 73562306a36Sopenharmony_ci * The setfacl command solves a similar problem with this logic: 73662306a36Sopenharmony_ci * 73762306a36Sopenharmony_ci * "If a Default ACL entry is created, and the Default ACL contains 73862306a36Sopenharmony_ci * no owner, owning group, or others entry, a copy of the ACL 73962306a36Sopenharmony_ci * owner, owning group, or others entry is added to the Default ACL." 74062306a36Sopenharmony_ci * 74162306a36Sopenharmony_ci * Copy any missing ACEs from the effective set, if any ACEs were 74262306a36Sopenharmony_ci * explicitly set. 74362306a36Sopenharmony_ci */ 74462306a36Sopenharmony_ci if (default_acl_state.valid) { 74562306a36Sopenharmony_ci if (!(default_acl_state.valid & ACL_USER_OBJ)) 74662306a36Sopenharmony_ci default_acl_state.owner = effective_acl_state.owner; 74762306a36Sopenharmony_ci if (!(default_acl_state.valid & ACL_GROUP_OBJ)) 74862306a36Sopenharmony_ci default_acl_state.group = effective_acl_state.group; 74962306a36Sopenharmony_ci if (!(default_acl_state.valid & ACL_OTHER)) 75062306a36Sopenharmony_ci default_acl_state.other = effective_acl_state.other; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci *pacl = posix_state_to_acl(&effective_acl_state, flags); 75462306a36Sopenharmony_ci if (IS_ERR(*pacl)) { 75562306a36Sopenharmony_ci ret = PTR_ERR(*pacl); 75662306a36Sopenharmony_ci *pacl = NULL; 75762306a36Sopenharmony_ci goto out_dstate; 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci *dpacl = posix_state_to_acl(&default_acl_state, 76062306a36Sopenharmony_ci flags | NFS4_ACL_TYPE_DEFAULT); 76162306a36Sopenharmony_ci if (IS_ERR(*dpacl)) { 76262306a36Sopenharmony_ci ret = PTR_ERR(*dpacl); 76362306a36Sopenharmony_ci *dpacl = NULL; 76462306a36Sopenharmony_ci posix_acl_release(*pacl); 76562306a36Sopenharmony_ci *pacl = NULL; 76662306a36Sopenharmony_ci goto out_dstate; 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci sort_pacl(*pacl); 76962306a36Sopenharmony_ci sort_pacl(*dpacl); 77062306a36Sopenharmony_ci ret = 0; 77162306a36Sopenharmony_ciout_dstate: 77262306a36Sopenharmony_ci free_state(&default_acl_state); 77362306a36Sopenharmony_ciout_estate: 77462306a36Sopenharmony_ci free_state(&effective_acl_state); 77562306a36Sopenharmony_ci return ret; 77662306a36Sopenharmony_ci} 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci__be32 nfsd4_acl_to_attr(enum nfs_ftype4 type, struct nfs4_acl *acl, 77962306a36Sopenharmony_ci struct nfsd_attrs *attr) 78062306a36Sopenharmony_ci{ 78162306a36Sopenharmony_ci int host_error; 78262306a36Sopenharmony_ci unsigned int flags = 0; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci if (!acl) 78562306a36Sopenharmony_ci return nfs_ok; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci if (type == NF4DIR) 78862306a36Sopenharmony_ci flags = NFS4_ACL_DIR; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci host_error = nfs4_acl_nfsv4_to_posix(acl, &attr->na_pacl, 79162306a36Sopenharmony_ci &attr->na_dpacl, flags); 79262306a36Sopenharmony_ci if (host_error == -EINVAL) 79362306a36Sopenharmony_ci return nfserr_attrnotsupp; 79462306a36Sopenharmony_ci else 79562306a36Sopenharmony_ci return nfserrno(host_error); 79662306a36Sopenharmony_ci} 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_cistatic short 79962306a36Sopenharmony_ciace2type(struct nfs4_ace *ace) 80062306a36Sopenharmony_ci{ 80162306a36Sopenharmony_ci switch (ace->whotype) { 80262306a36Sopenharmony_ci case NFS4_ACL_WHO_NAMED: 80362306a36Sopenharmony_ci return (ace->flag & NFS4_ACE_IDENTIFIER_GROUP ? 80462306a36Sopenharmony_ci ACL_GROUP : ACL_USER); 80562306a36Sopenharmony_ci case NFS4_ACL_WHO_OWNER: 80662306a36Sopenharmony_ci return ACL_USER_OBJ; 80762306a36Sopenharmony_ci case NFS4_ACL_WHO_GROUP: 80862306a36Sopenharmony_ci return ACL_GROUP_OBJ; 80962306a36Sopenharmony_ci case NFS4_ACL_WHO_EVERYONE: 81062306a36Sopenharmony_ci return ACL_OTHER; 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci BUG(); 81362306a36Sopenharmony_ci return -1; 81462306a36Sopenharmony_ci} 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci/* 81762306a36Sopenharmony_ci * return the size of the struct nfs4_acl required to represent an acl 81862306a36Sopenharmony_ci * with @entries entries. 81962306a36Sopenharmony_ci */ 82062306a36Sopenharmony_ciint nfs4_acl_bytes(int entries) 82162306a36Sopenharmony_ci{ 82262306a36Sopenharmony_ci return sizeof(struct nfs4_acl) + entries * sizeof(struct nfs4_ace); 82362306a36Sopenharmony_ci} 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_cistatic struct { 82662306a36Sopenharmony_ci char *string; 82762306a36Sopenharmony_ci int stringlen; 82862306a36Sopenharmony_ci int type; 82962306a36Sopenharmony_ci} s2t_map[] = { 83062306a36Sopenharmony_ci { 83162306a36Sopenharmony_ci .string = "OWNER@", 83262306a36Sopenharmony_ci .stringlen = sizeof("OWNER@") - 1, 83362306a36Sopenharmony_ci .type = NFS4_ACL_WHO_OWNER, 83462306a36Sopenharmony_ci }, 83562306a36Sopenharmony_ci { 83662306a36Sopenharmony_ci .string = "GROUP@", 83762306a36Sopenharmony_ci .stringlen = sizeof("GROUP@") - 1, 83862306a36Sopenharmony_ci .type = NFS4_ACL_WHO_GROUP, 83962306a36Sopenharmony_ci }, 84062306a36Sopenharmony_ci { 84162306a36Sopenharmony_ci .string = "EVERYONE@", 84262306a36Sopenharmony_ci .stringlen = sizeof("EVERYONE@") - 1, 84362306a36Sopenharmony_ci .type = NFS4_ACL_WHO_EVERYONE, 84462306a36Sopenharmony_ci }, 84562306a36Sopenharmony_ci}; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ciint 84862306a36Sopenharmony_cinfs4_acl_get_whotype(char *p, u32 len) 84962306a36Sopenharmony_ci{ 85062306a36Sopenharmony_ci int i; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(s2t_map); i++) { 85362306a36Sopenharmony_ci if (s2t_map[i].stringlen == len && 85462306a36Sopenharmony_ci 0 == memcmp(s2t_map[i].string, p, len)) 85562306a36Sopenharmony_ci return s2t_map[i].type; 85662306a36Sopenharmony_ci } 85762306a36Sopenharmony_ci return NFS4_ACL_WHO_NAMED; 85862306a36Sopenharmony_ci} 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci__be32 nfs4_acl_write_who(struct xdr_stream *xdr, int who) 86162306a36Sopenharmony_ci{ 86262306a36Sopenharmony_ci __be32 *p; 86362306a36Sopenharmony_ci int i; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(s2t_map); i++) { 86662306a36Sopenharmony_ci if (s2t_map[i].type != who) 86762306a36Sopenharmony_ci continue; 86862306a36Sopenharmony_ci p = xdr_reserve_space(xdr, s2t_map[i].stringlen + 4); 86962306a36Sopenharmony_ci if (!p) 87062306a36Sopenharmony_ci return nfserr_resource; 87162306a36Sopenharmony_ci p = xdr_encode_opaque(p, s2t_map[i].string, 87262306a36Sopenharmony_ci s2t_map[i].stringlen); 87362306a36Sopenharmony_ci return 0; 87462306a36Sopenharmony_ci } 87562306a36Sopenharmony_ci WARN_ON_ONCE(1); 87662306a36Sopenharmony_ci return nfserr_serverfault; 87762306a36Sopenharmony_ci} 878