FreeBSD/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_acl.c
/*
 * Determine whether Access should be granted/denied.
 *
 * The least priv subsytem is always consulted as a basic privilege
 * can define any form of access.
 */
Determine whether Access should be granted/denied.
The least priv subsytem is always consulted as a basic privilege
can define any form of access.
Determine whether Access should be granted / denied . The least priv subsytem is always consulted as a basic privilege can define any form of access .
int
zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr)
{
	uint32_t	working_mode;
	int		error;
	int		is_attr;
	boolean_t 	check_privs;
	znode_t		*xzp;
	znode_t 	*check_zp = zp;
	mode_t		needed_bits;
	uid_t		owner;
	is_attr = ((zp->z_pflags & ZFS_XATTR) && (ZTOV(zp)->v_type == VDIR));
#ifdef __FreeBSD_kernel__
	if (zp->z_pflags & ZFS_XATTR)
		return (0);
#else
	if (is_attr) {
		uint64_t	parent;
		if ((error = sa_lookup(zp->z_sa_hdl,
		    SA_ZPL_PARENT(zp->z_zfsvfs), &parent,
		    sizeof (parent))) != 0)
			return (error);
		if ((error = zfs_zget(zp->z_zfsvfs,
		    parent, &xzp)) != 0)	{
			return (error);
		}
		check_zp = xzp;
		if (mode & (ACE_WRITE_DATA|ACE_APPEND_DATA)) {
			mode &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA);
			mode |= ACE_WRITE_NAMED_ATTRS;
		}
		if (mode & (ACE_READ_DATA|ACE_EXECUTE)) {
			mode &= ~(ACE_READ_DATA|ACE_EXECUTE);
			mode |= ACE_READ_NAMED_ATTRS;
		}
	}
#endif
	owner = zfs_fuid_map_id(zp->z_zfsvfs, zp->z_uid, cr, ZFS_OWNER);
	needed_bits = 0;
	working_mode = mode;
	if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES)) &&
	    owner == crgetuid(cr))
		working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES);
	if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS|
	    ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_SYNCHRONIZE))
		needed_bits |= VREAD;
	if (working_mode & (ACE_WRITE_DATA|ACE_WRITE_NAMED_ATTRS|
	    ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES|ACE_SYNCHRONIZE))
		needed_bits |= VWRITE;
	if (working_mode & ACE_EXECUTE)
		needed_bits |= VEXEC;
	if ((error = zfs_zaccess_common(check_zp, mode, &working_mode,
	    &check_privs, skipaclchk, cr)) == 0) {
		if (is_attr)
			VN_RELE(ZTOV(xzp));
		return (secpolicy_vnode_access2(cr, ZTOV(zp), owner,
		    needed_bits, needed_bits));
	}
	if (error && !check_privs) {
		if (is_attr)
			VN_RELE(ZTOV(xzp));
		return (error);
	}
	if (error && (flags & V_APPEND)) {
		error = zfs_zaccess_append(zp, &working_mode, &check_privs, cr);
	}
	if (error && check_privs) {
		mode_t		checkmode = 0;
		error = 0;
		ASSERT(working_mode != 0);
		if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES) &&
		    owner == crgetuid(cr)))
			working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES);
		if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS|
		    ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_SYNCHRONIZE))
			checkmode |= VREAD;
		if (working_mode & (ACE_WRITE_DATA|ACE_WRITE_NAMED_ATTRS|
		    ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES|ACE_SYNCHRONIZE))
			checkmode |= VWRITE;
		if (working_mode & ACE_EXECUTE)
			checkmode |= VEXEC;
		error = secpolicy_vnode_access2(cr, ZTOV(check_zp), owner,
		    needed_bits & ~checkmode, needed_bits);
		if (error == 0 && (working_mode & ACE_WRITE_OWNER))
			error = secpolicy_vnode_chown(ZTOV(check_zp), cr, owner);
		if (error == 0 && (working_mode & ACE_WRITE_ACL))
			error = secpolicy_vnode_setdac(ZTOV(check_zp), cr, owner);
		if (error == 0 && (working_mode &
		    (ACE_DELETE|ACE_DELETE_CHILD)))
			error = secpolicy_vnode_remove(ZTOV(check_zp), cr);
		if (error == 0 && (working_mode & ACE_SYNCHRONIZE)) {
			error = secpolicy_vnode_chown(ZTOV(check_zp), cr, owner);
		}
		if (error == 0) {
			if (working_mode & ~(ZFS_CHECKED_MASKS)) {
				error = SET_ERROR(EACCES);
			}
		}
	} else if (error == 0) {
		error = secpolicy_vnode_access2(cr, ZTOV(zp), owner,
		    needed_bits, needed_bits);
	}
	if (is_attr)
		VN_RELE(ZTOV(xzp));
	return (error);
}
int zfs_zaccess ( znode_t * zp , int mode , int flags , boolean_t skipaclchk , cred_t * cr ) { uint32_t working_mode ; int error ; int is_attr ; boolean_t check_privs ; znode_t * xzp ; znode_t * check_zp = zp ; mode_t needed_bits ; uid_t owner ; is_attr = ( ( zp -> z_pflags & ZFS_XATTR ) && ( ZTOV ( zp ) -> v_type == VDIR ) ) ; #ifdef __FreeBSD_kernel__ if ( zp -> z_pflags & ZFS_XATTR ) return ( 0 ) ; #else if ( is_attr ) { uint64_t parent ; if ( ( error = sa_lookup ( zp -> z_sa_hdl , SA_ZPL_PARENT ( zp -> z_zfsvfs ) , & parent , sizeof ( parent ) ) ) != 0 ) return ( error ) ; if ( ( error = zfs_zget ( zp -> z_zfsvfs , parent , & xzp ) ) != 0 ) { return ( error ) ; } check_zp = xzp ; if ( mode & ( ACE_WRITE_DATA | ACE_APPEND_DATA ) ) { mode &= ~ ( ACE_WRITE_DATA | ACE_APPEND_DATA ) ; mode |= ACE_WRITE_NAMED_ATTRS ; } if ( mode & ( ACE_READ_DATA | ACE_EXECUTE ) ) { mode &= ~ ( ACE_READ_DATA | ACE_EXECUTE ) ; mode |= ACE_READ_NAMED_ATTRS ; } } #endif owner = zfs_fuid_map_id ( zp -> z_zfsvfs , zp -> z_uid , cr , ZFS_OWNER ) ; needed_bits = 0 ; working_mode = mode ; if ( ( working_mode & ( ACE_READ_ACL | ACE_READ_ATTRIBUTES ) ) && owner == crgetuid ( cr ) ) working_mode &= ~ ( ACE_READ_ACL | ACE_READ_ATTRIBUTES ) ; if ( working_mode & ( ACE_READ_DATA | ACE_READ_NAMED_ATTRS | ACE_READ_ACL | ACE_READ_ATTRIBUTES | ACE_SYNCHRONIZE ) ) needed_bits |= VREAD ; if ( working_mode & ( ACE_WRITE_DATA | ACE_WRITE_NAMED_ATTRS | ACE_APPEND_DATA | ACE_WRITE_ATTRIBUTES | ACE_SYNCHRONIZE ) ) needed_bits |= VWRITE ; if ( working_mode & ACE_EXECUTE ) needed_bits |= VEXEC ; if ( ( error = zfs_zaccess_common ( check_zp , mode , & working_mode , & check_privs , skipaclchk , cr ) ) == 0 ) { if ( is_attr ) VN_RELE ( ZTOV ( xzp ) ) ; return ( secpolicy_vnode_access2 ( cr , ZTOV ( zp ) , owner , needed_bits , needed_bits ) ) ; } if ( error && ! check_privs ) { if ( is_attr ) VN_RELE ( ZTOV ( xzp ) ) ; return ( error ) ; } if ( error && ( flags & V_APPEND ) ) { error = zfs_zaccess_append ( zp , & working_mode , & check_privs , cr ) ; } if ( error && check_privs ) { mode_t checkmode = 0 ; error = 0 ; ASSERT ( working_mode != 0 ) ; if ( ( working_mode & ( ACE_READ_ACL | ACE_READ_ATTRIBUTES ) && owner == crgetuid ( cr ) ) ) working_mode &= ~ ( ACE_READ_ACL | ACE_READ_ATTRIBUTES ) ; if ( working_mode & ( ACE_READ_DATA | ACE_READ_NAMED_ATTRS | ACE_READ_ACL | ACE_READ_ATTRIBUTES | ACE_SYNCHRONIZE ) ) checkmode |= VREAD ; if ( working_mode & ( ACE_WRITE_DATA | ACE_WRITE_NAMED_ATTRS | ACE_APPEND_DATA | ACE_WRITE_ATTRIBUTES | ACE_SYNCHRONIZE ) ) checkmode |= VWRITE ; if ( working_mode & ACE_EXECUTE ) checkmode |= VEXEC ; error = secpolicy_vnode_access2 ( cr , ZTOV ( check_zp ) , owner , needed_bits & ~ checkmode , needed_bits ) ; if ( error == 0 && ( working_mode & ACE_WRITE_OWNER ) ) error = secpolicy_vnode_chown ( ZTOV ( check_zp ) , cr , owner ) ; if ( error == 0 && ( working_mode & ACE_WRITE_ACL ) ) error = secpolicy_vnode_setdac ( ZTOV ( check_zp ) , cr , owner ) ; if ( error == 0 && ( working_mode & ( ACE_DELETE | ACE_DELETE_CHILD ) ) ) error = secpolicy_vnode_remove ( ZTOV ( check_zp ) , cr ) ; if ( error == 0 && ( working_mode & ACE_SYNCHRONIZE ) ) { error = secpolicy_vnode_chown ( ZTOV ( check_zp ) , cr , owner ) ; } if ( error == 0 ) { if ( working_mode & ~ ( ZFS_CHECKED_MASKS ) ) { error = SET_ERROR ( EACCES ) ; } } } else if ( error == 0 ) { error = secpolicy_vnode_access2 ( cr , ZTOV ( zp ) , owner , needed_bits , needed_bits ) ; } if ( is_attr ) VN_RELE ( ZTOV ( xzp ) ) ; return ( error ) ; }
Determine whether Access should be granted/denied.
Determine whether Access should be granted / denied .
/*
	 * In FreeBSD, we don't care about permissions of individual ADS.
	 * Note that not checking them is not just an optimization - without
	 * this shortcut, EA operations may bogusly fail with EACCES.
	 */ /*
	 * If attribute then validate against base file
	 */ /*
		 * fixup mode to map to xattr perms
		 */ /*
	 * Map the bits required to the standard vnode flags VREAD|VWRITE|VEXEC
	 * in needed_bits.  Map the bits mapped by working_mode (currently
	 * missing) in missing_bits.
	 * Call secpolicy_vnode_access2() with (needed_bits & ~checkmode),
	 * needed_bits.
	 */ /*
		 * First check for implicit owner permission on
		 * read_acl/read_attributes
		 */ /*
			 * See if any bits other than those already checked
			 * for are still present.  If so then return EACCES
			 */