⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nfs4acl.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  fs/nfs4acl/acl.c * *  Common NFSv4 ACL handling code. * *  Copyright (c) 2002, 2003 The Regents of the University of Michigan. *  All rights reserved. * *  Marius Aamodt Eriksen <marius@umich.edu> *  Jeff Sedlak <jsedlak@umich.edu> *  J. Bruce Fields <bfields@umich.edu> * *  Redistribution and use in source and binary forms, with or without *  modification, are permitted provided that the following conditions *  are met: * *  1. Redistributions of source code must retain the above copyright *     notice, this list of conditions and the following disclaimer. *  2. Redistributions in binary form must reproduce the above copyright *     notice, this list of conditions and the following disclaimer in the *     documentation and/or other materials provided with the distribution. *  3. Neither the name of the University nor the names of its *     contributors may be used to endorse or promote products derived *     from this software without specific prior written permission. * *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include <linux/string.h>#include <linux/slab.h>#include <linux/list.h>#include <linux/types.h>#include <linux/fs.h>#include <linux/module.h>#include <linux/nfs_fs.h>#include <linux/posix_acl.h>#include <linux/nfs4.h>#include <linux/nfs4_acl.h>/* mode bit translations: */#define NFS4_READ_MODE (NFS4_ACE_READ_DATA)#define NFS4_WRITE_MODE (NFS4_ACE_WRITE_DATA | NFS4_ACE_APPEND_DATA)#define NFS4_EXECUTE_MODE NFS4_ACE_EXECUTE#define NFS4_ANYONE_MODE (NFS4_ACE_READ_ATTRIBUTES | NFS4_ACE_READ_ACL | NFS4_ACE_SYNCHRONIZE)#define NFS4_OWNER_MODE (NFS4_ACE_WRITE_ATTRIBUTES | NFS4_ACE_WRITE_ACL)/* We don't support these bits; insist they be neither allowed nor denied */#define NFS4_MASK_UNSUPP (NFS4_ACE_DELETE | NFS4_ACE_WRITE_OWNER \		| NFS4_ACE_READ_NAMED_ATTRS | NFS4_ACE_WRITE_NAMED_ATTRS)/* flags used to simulate posix default ACLs */#define NFS4_INHERITANCE_FLAGS (NFS4_ACE_FILE_INHERIT_ACE \		| NFS4_ACE_DIRECTORY_INHERIT_ACE)#define NFS4_SUPPORTED_FLAGS (NFS4_INHERITANCE_FLAGS \		| NFS4_ACE_INHERIT_ONLY_ACE \		| NFS4_ACE_IDENTIFIER_GROUP)#define MASK_EQUAL(mask1, mask2) \	( ((mask1) & NFS4_ACE_MASK_ALL) == ((mask2) & NFS4_ACE_MASK_ALL) )static u32mask_from_posix(unsigned short perm, unsigned int flags){	int mask = NFS4_ANYONE_MODE;	if (flags & NFS4_ACL_OWNER)		mask |= NFS4_OWNER_MODE;	if (perm & ACL_READ)		mask |= NFS4_READ_MODE;	if (perm & ACL_WRITE)		mask |= NFS4_WRITE_MODE;	if ((perm & ACL_WRITE) && (flags & NFS4_ACL_DIR))		mask |= NFS4_ACE_DELETE_CHILD;	if (perm & ACL_EXECUTE)		mask |= NFS4_EXECUTE_MODE;	return mask;}static u32deny_mask_from_posix(unsigned short perm, u32 flags){	u32 mask = 0;	if (perm & ACL_READ)		mask |= NFS4_READ_MODE;	if (perm & ACL_WRITE)		mask |= NFS4_WRITE_MODE;	if ((perm & ACL_WRITE) && (flags & NFS4_ACL_DIR))		mask |= NFS4_ACE_DELETE_CHILD;	if (perm & ACL_EXECUTE)		mask |= NFS4_EXECUTE_MODE;	return mask;}/* XXX: modify functions to return NFS errors; they're only ever * used by nfs code, after all.... *//* We only map from NFSv4 to POSIX ACLs when setting ACLs, when we err on the * side of being more restrictive, so the mode bit mapping below is * pessimistic.  An optimistic version would be needed to handle DENY's, * but we espect to coalesce all ALLOWs and DENYs before mapping to mode * bits. */static voidlow_mode_from_nfs4(u32 perm, unsigned short *mode, unsigned int flags){	u32 write_mode = NFS4_WRITE_MODE;	if (flags & NFS4_ACL_DIR)		write_mode |= NFS4_ACE_DELETE_CHILD;	*mode = 0;	if ((perm & NFS4_READ_MODE) == NFS4_READ_MODE)		*mode |= ACL_READ;	if ((perm & write_mode) == write_mode)		*mode |= ACL_WRITE;	if ((perm & NFS4_EXECUTE_MODE) == NFS4_EXECUTE_MODE)		*mode |= ACL_EXECUTE;}struct ace_container {	struct nfs4_ace  *ace;	struct list_head  ace_l;};static short ace2type(struct nfs4_ace *);static void _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *,				unsigned int);struct nfs4_acl *nfs4_acl_posix_to_nfsv4(struct posix_acl *pacl, struct posix_acl *dpacl,			unsigned int flags){	struct nfs4_acl *acl;	int size = 0;	if (pacl) {		if (posix_acl_valid(pacl) < 0)			return ERR_PTR(-EINVAL);		size += 2*pacl->a_count;	}	if (dpacl) {		if (posix_acl_valid(dpacl) < 0)			return ERR_PTR(-EINVAL);		size += 2*dpacl->a_count;	}	/* Allocate for worst case: one (deny, allow) pair each: */	acl = nfs4_acl_new(size);	if (acl == NULL)		return ERR_PTR(-ENOMEM);	if (pacl)		_posix_to_nfsv4_one(pacl, acl, flags & ~NFS4_ACL_TYPE_DEFAULT);	if (dpacl)		_posix_to_nfsv4_one(dpacl, acl, flags | NFS4_ACL_TYPE_DEFAULT);	return acl;}struct posix_acl_summary {	unsigned short owner;	unsigned short users;	unsigned short group;	unsigned short groups;	unsigned short other;	unsigned short mask;};static voidsummarize_posix_acl(struct posix_acl *acl, struct posix_acl_summary *pas){	struct posix_acl_entry *pa, *pe;	/*	 * Only pas.users and pas.groups need initialization; previous	 * posix_acl_valid() calls ensure that the other fields will be	 * initialized in the following loop.  But, just to placate gcc:	 */	memset(pas, 0, sizeof(*pas));	pas->mask = 07;	pe = acl->a_entries + acl->a_count;	FOREACH_ACL_ENTRY(pa, acl, pe) {		switch (pa->e_tag) {			case ACL_USER_OBJ:				pas->owner = pa->e_perm;				break;			case ACL_GROUP_OBJ:				pas->group = pa->e_perm;				break;			case ACL_USER:				pas->users |= pa->e_perm;				break;			case ACL_GROUP:				pas->groups |= pa->e_perm;				break;			case ACL_OTHER:				pas->other = pa->e_perm;				break;			case ACL_MASK:				pas->mask = pa->e_perm;				break;		}	}	/* We'll only care about effective permissions: */	pas->users &= pas->mask;	pas->group &= pas->mask;	pas->groups &= pas->mask;}/* We assume the acl has been verified with posix_acl_valid. */static void_posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl,						unsigned int flags){	struct posix_acl_entry *pa, *group_owner_entry;	struct nfs4_ace *ace;	struct posix_acl_summary pas;	unsigned short deny;	int eflag = ((flags & NFS4_ACL_TYPE_DEFAULT) ?		NFS4_INHERITANCE_FLAGS | NFS4_ACE_INHERIT_ONLY_ACE : 0);	BUG_ON(pacl->a_count < 3);	summarize_posix_acl(pacl, &pas);	pa = pacl->a_entries;	ace = acl->aces + acl->naces;	/* We could deny everything not granted by the owner: */	deny = ~pas.owner;	/*	 * but it is equivalent (and simpler) to deny only what is not	 * granted by later entries:	 */	deny &= pas.users | pas.group | pas.groups | pas.other;	if (deny) {		ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE;		ace->flag = eflag;		ace->access_mask = deny_mask_from_posix(deny, flags);		ace->whotype = NFS4_ACL_WHO_OWNER;		ace++;		acl->naces++;	}	ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;	ace->flag = eflag;	ace->access_mask = mask_from_posix(pa->e_perm, flags | NFS4_ACL_OWNER);	ace->whotype = NFS4_ACL_WHO_OWNER;	ace++;	acl->naces++;	pa++;	while (pa->e_tag == ACL_USER) {		deny = ~(pa->e_perm & pas.mask);		deny &= pas.groups | pas.group | pas.other;		if (deny) {			ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE;			ace->flag = eflag;			ace->access_mask = deny_mask_from_posix(deny, flags);			ace->whotype = NFS4_ACL_WHO_NAMED;			ace->who = pa->e_id;			ace++;			acl->naces++;		}		ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;		ace->flag = eflag;		ace->access_mask = mask_from_posix(pa->e_perm & pas.mask,						   flags);		ace->whotype = NFS4_ACL_WHO_NAMED;		ace->who = pa->e_id;		ace++;		acl->naces++;		pa++;	}	/* In the case of groups, we apply allow ACEs first, then deny ACEs,	 * since a user can be in more than one group.  */	/* allow ACEs */	group_owner_entry = pa;	ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;	ace->flag = eflag;	ace->access_mask = mask_from_posix(pas.group, flags);	ace->whotype = NFS4_ACL_WHO_GROUP;	ace++;	acl->naces++;	pa++;	while (pa->e_tag == ACL_GROUP) {		ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;		ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP;		ace->access_mask = mask_from_posix(pa->e_perm & pas.mask,						   flags);		ace->whotype = NFS4_ACL_WHO_NAMED;		ace->who = pa->e_id;		ace++;		acl->naces++;		pa++;	}	/* deny ACEs */	pa = group_owner_entry;	deny = ~pas.group & pas.other;	if (deny) {		ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE;		ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP;		ace->access_mask = deny_mask_from_posix(deny, flags);		ace->whotype = NFS4_ACL_WHO_GROUP;		ace++;		acl->naces++;	}	pa++;	while (pa->e_tag == ACL_GROUP) {		deny = ~(pa->e_perm & pas.mask);		deny &= pas.other;		if (deny) {			ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE;			ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP;			ace->access_mask = mask_from_posix(deny, flags);			ace->whotype = NFS4_ACL_WHO_NAMED;			ace->who = pa->e_id;			ace++;			acl->naces++;		}		pa++;	}	if (pa->e_tag == ACL_MASK)		pa++;	ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;	ace->flag = eflag;	ace->access_mask = mask_from_posix(pa->e_perm, flags);	ace->whotype = NFS4_ACL_WHO_EVERYONE;	acl->naces++;}static voidsort_pacl_range(struct posix_acl *pacl, int start, int end) {	int sorted = 0, i;	struct posix_acl_entry tmp;	/* We just do a bubble sort; easy to do in place, and we're not	 * expecting acl's to be long enough to justify anything more. */	while (!sorted) {		sorted = 1;		for (i = start; i < end; i++) {			if (pacl->a_entries[i].e_id					> pacl->a_entries[i+1].e_id) {				sorted = 0;				tmp = pacl->a_entries[i];				pacl->a_entries[i] = pacl->a_entries[i+1];				pacl->a_entries[i+1] = tmp;			}		}	}}static voidsort_pacl(struct posix_acl *pacl){	/* posix_acl_valid requires that users and groups be in order	 * by uid/gid. */	int i, j;	if (pacl->a_count <= 4)		return; /* no users or groups */	i = 1;	while (pacl->a_entries[i].e_tag == ACL_USER)		i++;	sort_pacl_range(pacl, 1, i-1);	BUG_ON(pacl->a_entries[i].e_tag != ACL_GROUP_OBJ);	j = i++;	while (pacl->a_entries[j].e_tag == ACL_GROUP)		j++;	sort_pacl_range(pacl, i, j-1);	return;}/* * While processing the NFSv4 ACE, this maintains bitmasks representing * which permission bits have been allowed and which denied to a given * entity: */struct posix_ace_state {	u32 allow;	u32 deny;};struct posix_user_ace_state {	uid_t uid;	struct posix_ace_state perms;};struct posix_ace_state_array {	int n;	struct posix_user_ace_state aces[];};/* * While processing the NFSv4 ACE, this maintains the partial permissions * calculated so far: */struct posix_acl_state {	int empty;	struct posix_ace_state owner;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -