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

📄 xfs_acl.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 2001-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */#include "xfs.h"#include "xfs_fs.h"#include "xfs_types.h"#include "xfs_bit.h"#include "xfs_inum.h"#include "xfs_ag.h"#include "xfs_dir2.h"#include "xfs_bmap_btree.h"#include "xfs_alloc_btree.h"#include "xfs_ialloc_btree.h"#include "xfs_dir2_sf.h"#include "xfs_attr_sf.h"#include "xfs_dinode.h"#include "xfs_inode.h"#include "xfs_btree.h"#include "xfs_acl.h"#include "xfs_attr.h"#include "xfs_vnodeops.h"#include <linux/capability.h>#include <linux/posix_acl_xattr.h>STATIC int	xfs_acl_setmode(bhv_vnode_t *, xfs_acl_t *, int *);STATIC void     xfs_acl_filter_mode(mode_t, xfs_acl_t *);STATIC void	xfs_acl_get_endian(xfs_acl_t *);STATIC int	xfs_acl_access(uid_t, gid_t, xfs_acl_t *, mode_t, cred_t *);STATIC int	xfs_acl_invalid(xfs_acl_t *);STATIC void	xfs_acl_sync_mode(mode_t, xfs_acl_t *);STATIC void	xfs_acl_get_attr(bhv_vnode_t *, xfs_acl_t *, int, int, int *);STATIC void	xfs_acl_set_attr(bhv_vnode_t *, xfs_acl_t *, int, int *);STATIC int	xfs_acl_allow_set(bhv_vnode_t *, int);kmem_zone_t *xfs_acl_zone;/* * Test for existence of access ACL attribute as efficiently as possible. */intxfs_acl_vhasacl_access(	bhv_vnode_t	*vp){	int		error;	xfs_acl_get_attr(vp, NULL, _ACL_TYPE_ACCESS, ATTR_KERNOVAL, &error);	return (error == 0);}/* * Test for existence of default ACL attribute as efficiently as possible. */intxfs_acl_vhasacl_default(	bhv_vnode_t	*vp){	int		error;	if (!VN_ISDIR(vp))		return 0;	xfs_acl_get_attr(vp, NULL, _ACL_TYPE_DEFAULT, ATTR_KERNOVAL, &error);	return (error == 0);}/* * Convert from extended attribute representation to in-memory for XFS. */STATIC intposix_acl_xattr_to_xfs(	posix_acl_xattr_header	*src,	size_t			size,	xfs_acl_t		*dest){	posix_acl_xattr_entry	*src_entry;	xfs_acl_entry_t		*dest_entry;	int			n;	if (!src || !dest)		return EINVAL;	if (size < sizeof(posix_acl_xattr_header))		return EINVAL;	if (src->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))		return EOPNOTSUPP;	memset(dest, 0, sizeof(xfs_acl_t));	dest->acl_cnt = posix_acl_xattr_count(size);	if (dest->acl_cnt < 0 || dest->acl_cnt > XFS_ACL_MAX_ENTRIES)		return EINVAL;	/*	 * acl_set_file(3) may request that we set default ACLs with	 * zero length -- defend (gracefully) against that here.	 */	if (!dest->acl_cnt)		return 0;	src_entry = (posix_acl_xattr_entry *)((char *)src + sizeof(*src));	dest_entry = &dest->acl_entry[0];	for (n = 0; n < dest->acl_cnt; n++, src_entry++, dest_entry++) {		dest_entry->ae_perm = le16_to_cpu(src_entry->e_perm);		if (_ACL_PERM_INVALID(dest_entry->ae_perm))			return EINVAL;		dest_entry->ae_tag  = le16_to_cpu(src_entry->e_tag);		switch(dest_entry->ae_tag) {		case ACL_USER:		case ACL_GROUP:			dest_entry->ae_id = le32_to_cpu(src_entry->e_id);			break;		case ACL_USER_OBJ:		case ACL_GROUP_OBJ:		case ACL_MASK:		case ACL_OTHER:			dest_entry->ae_id = ACL_UNDEFINED_ID;			break;		default:			return EINVAL;		}	}	if (xfs_acl_invalid(dest))		return EINVAL;	return 0;}/* * Comparison function called from xfs_sort(). * Primary key is ae_tag, secondary key is ae_id. */STATIC intxfs_acl_entry_compare(	const void	*va,	const void	*vb){	xfs_acl_entry_t	*a = (xfs_acl_entry_t *)va,			*b = (xfs_acl_entry_t *)vb;	if (a->ae_tag == b->ae_tag)		return (a->ae_id - b->ae_id);	return (a->ae_tag - b->ae_tag);}/* * Convert from in-memory XFS to extended attribute representation. */STATIC intposix_acl_xfs_to_xattr(	xfs_acl_t		*src,	posix_acl_xattr_header	*dest,	size_t			size){	int			n;	size_t			new_size = posix_acl_xattr_size(src->acl_cnt);	posix_acl_xattr_entry	*dest_entry;	xfs_acl_entry_t		*src_entry;	if (size < new_size)		return -ERANGE;	/* Need to sort src XFS ACL by <ae_tag,ae_id> */	xfs_sort(src->acl_entry, src->acl_cnt, sizeof(src->acl_entry[0]),		 xfs_acl_entry_compare);	dest->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);	dest_entry = &dest->a_entries[0];	src_entry = &src->acl_entry[0];	for (n = 0; n < src->acl_cnt; n++, dest_entry++, src_entry++) {		dest_entry->e_perm = cpu_to_le16(src_entry->ae_perm);		if (_ACL_PERM_INVALID(src_entry->ae_perm))			return -EINVAL;		dest_entry->e_tag  = cpu_to_le16(src_entry->ae_tag);		switch (src_entry->ae_tag) {		case ACL_USER:		case ACL_GROUP:			dest_entry->e_id = cpu_to_le32(src_entry->ae_id);				break;		case ACL_USER_OBJ:		case ACL_GROUP_OBJ:		case ACL_MASK:		case ACL_OTHER:			dest_entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID);			break;		default:			return -EINVAL;		}	}	return new_size;}intxfs_acl_vget(	bhv_vnode_t	*vp,	void		*acl,	size_t		size,	int		kind){	int			error;	xfs_acl_t		*xfs_acl = NULL;	posix_acl_xattr_header	*ext_acl = acl;	int			flags = 0;	VN_HOLD(vp);	if(size) {		if (!(_ACL_ALLOC(xfs_acl))) {			error = ENOMEM;			goto out;		}		memset(xfs_acl, 0, sizeof(xfs_acl_t));	} else		flags = ATTR_KERNOVAL;	xfs_acl_get_attr(vp, xfs_acl, kind, flags, &error);	if (error)		goto out;	if (!size) {		error = -posix_acl_xattr_size(XFS_ACL_MAX_ENTRIES);	} else {		if (xfs_acl_invalid(xfs_acl)) {			error = EINVAL;			goto out;		}		if (kind == _ACL_TYPE_ACCESS) {			bhv_vattr_t	va;			va.va_mask = XFS_AT_MODE;			error = xfs_getattr(xfs_vtoi(vp), &va, 0);			if (error)				goto out;			xfs_acl_sync_mode(va.va_mode, xfs_acl);		}		error = -posix_acl_xfs_to_xattr(xfs_acl, ext_acl, size);	}out:	VN_RELE(vp);	if(xfs_acl)		_ACL_FREE(xfs_acl);	return -error;}intxfs_acl_vremove(	bhv_vnode_t	*vp,	int		kind){	int		error;	VN_HOLD(vp);	error = xfs_acl_allow_set(vp, kind);	if (!error) {		error = xfs_attr_remove(xfs_vtoi(vp),						kind == _ACL_TYPE_DEFAULT?						SGI_ACL_DEFAULT: SGI_ACL_FILE,						ATTR_ROOT);		if (error == ENOATTR)			error = 0;	/* 'scool */	}	VN_RELE(vp);	return -error;}intxfs_acl_vset(	bhv_vnode_t		*vp,	void			*acl,	size_t			size,	int			kind){	posix_acl_xattr_header	*ext_acl = acl;	xfs_acl_t		*xfs_acl;	int			error;	int			basicperms = 0; /* more than std unix perms? */	if (!acl)		return -EINVAL;	if (!(_ACL_ALLOC(xfs_acl)))		return -ENOMEM;	error = posix_acl_xattr_to_xfs(ext_acl, size, xfs_acl);	if (error) {		_ACL_FREE(xfs_acl);		return -error;	}	if (!xfs_acl->acl_cnt) {		_ACL_FREE(xfs_acl);		return 0;	}	VN_HOLD(vp);	error = xfs_acl_allow_set(vp, kind);	if (error)		goto out;	/* Incoming ACL exists, set file mode based on its value */	if (kind == _ACL_TYPE_ACCESS)		xfs_acl_setmode(vp, xfs_acl, &basicperms);	/*	 * If we have more than std unix permissions, set up the actual attr.	 * Otherwise, delete any existing attr.  This prevents us from	 * having actual attrs for permissions that can be stored in the	 * standard permission bits.	 */	if (!basicperms) {		xfs_acl_set_attr(vp, xfs_acl, kind, &error);	} else {		xfs_acl_vremove(vp, _ACL_TYPE_ACCESS);	}out:	VN_RELE(vp);	_ACL_FREE(xfs_acl);	return -error;}intxfs_acl_iaccess(	xfs_inode_t	*ip,	mode_t		mode,	cred_t		*cr){	xfs_acl_t	*acl;	int		rval;	if (!(_ACL_ALLOC(acl)))		return -1;	/* If the file has no ACL return -1. */	rval = sizeof(xfs_acl_t);	if (xfs_attr_fetch(ip, SGI_ACL_FILE, SGI_ACL_FILE_SIZE,			(char *)acl, &rval, ATTR_ROOT | ATTR_KERNACCESS, cr)) {		_ACL_FREE(acl);		return -1;	}	xfs_acl_get_endian(acl);	/* If the file has an empty ACL return -1. */	if (acl->acl_cnt == XFS_ACL_NOT_PRESENT) {		_ACL_FREE(acl);		return -1;	}	/* Synchronize ACL with mode bits */	xfs_acl_sync_mode(ip->i_d.di_mode, acl);	rval = xfs_acl_access(ip->i_d.di_uid, ip->i_d.di_gid, acl, mode, cr);	_ACL_FREE(acl);	return rval;}STATIC intxfs_acl_allow_set(	bhv_vnode_t	*vp,	int		kind){	xfs_inode_t	*ip = xfs_vtoi(vp);	bhv_vattr_t	va;	int		error;	if (vp->i_flags & (S_IMMUTABLE|S_APPEND))		return EPERM;	if (kind == _ACL_TYPE_DEFAULT && !VN_ISDIR(vp))		return ENOTDIR;	if (vp->i_sb->s_flags & MS_RDONLY)		return EROFS;	va.va_mask = XFS_AT_UID;	error = xfs_getattr(ip, &va, 0);	if (error)		return error;	if (va.va_uid != current->fsuid && !capable(CAP_FOWNER))		return EPERM;	return error;}/* * The access control process to determine the access permission: *	if uid == file owner id, use the file owner bits. *	if gid == file owner group id, use the file group bits. *	scan ACL for a matching user or group, and use matched entry *	permission. Use total permissions of all matching group entries, *	until all acl entries are exhausted. The final permission produced *	by matching acl entry or entries needs to be & with group permission. *	if not owner, owning group, or matching entry in ACL, use file *	other bits.   */STATIC intxfs_acl_capability_check(	mode_t		mode,	cred_t		*cr){	if ((mode & ACL_READ) && !capable_cred(cr, CAP_DAC_READ_SEARCH))		return EACCES;	if ((mode & ACL_WRITE) && !capable_cred(cr, CAP_DAC_OVERRIDE))		return EACCES;	if ((mode & ACL_EXECUTE) && !capable_cred(cr, CAP_DAC_OVERRIDE))		return EACCES;	return 0;}/* * Note: cr is only used here for the capability check if the ACL test fails. *       It is not used to find out the credentials uid or groups etc, as was *       done in IRIX. It is assumed that the uid and groups for the current *       thread are taken from "current" instead of the cr parameter. */STATIC intxfs_acl_access(	uid_t		fuid,	gid_t		fgid,	xfs_acl_t	*fap,	mode_t		md,	cred_t		*cr){	xfs_acl_entry_t	matched;	int		i, allows;	int		maskallows = -1;	/* true, but not 1, either */	int		seen_userobj = 0;	matched.ae_tag = 0;	/* Invalid type */	matched.ae_perm = 0;	md >>= 6;	/* Normalize the bits for comparison */	for (i = 0; i < fap->acl_cnt; i++) {		/*		 * Break out if we've got a user_obj entry or		 * a user entry and the mask (and have processed USER_OBJ)		 */		if (matched.ae_tag == ACL_USER_OBJ)			break;		if (matched.ae_tag == ACL_USER) {			if (maskallows != -1 && seen_userobj)				break;			if (fap->acl_entry[i].ae_tag != ACL_MASK &&			    fap->acl_entry[i].ae_tag != ACL_USER_OBJ)				continue;		}		/* True if this entry allows the requested access */		allows = ((fap->acl_entry[i].ae_perm & md) == md);		switch (fap->acl_entry[i].ae_tag) {		case ACL_USER_OBJ:			seen_userobj = 1;			if (fuid != current->fsuid)				continue;			matched.ae_tag = ACL_USER_OBJ;

⌨️ 快捷键说明

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