2021-11-02 22:12:01 +09:00
// SPDX-License-Identifier: LGPL-2.1
2010-09-28 00:27:39 +05:30
/*
* Copyright IBM Corporation , 2010
* Author Aneesh Kumar K . V < aneesh . kumar @ linux . vnet . ibm . com >
*/
# include <linux/module.h>
# include <linux/fs.h>
# include <net/9p/9p.h>
# include <net/9p/client.h>
# include <linux/slab.h>
2010-09-28 00:27:40 +05:30
# include <linux/sched.h>
2010-09-28 00:27:39 +05:30
# include <linux/posix_acl_xattr.h>
# include "xattr.h"
# include "acl.h"
2010-09-28 00:27:41 +05:30
# include "v9fs.h"
2011-02-28 17:04:01 +05:30
# include "v9fs_vfs.h"
2013-01-31 12:54:47 -05:00
# include "fid.h"
2010-09-28 00:27:39 +05:30
2022-09-22 17:17:04 +02:00
static struct posix_acl * v9fs_fid_get_acl ( struct p9_fid * fid , const char * name )
2010-09-28 00:27:39 +05:30
{
ssize_t size ;
void * value = NULL ;
2010-11-15 03:04:51 +00:00
struct posix_acl * acl = NULL ;
2010-09-28 00:27:39 +05:30
size = v9fs_fid_xattr_get ( fid , name , NULL , 0 ) ;
2022-09-22 17:17:04 +02:00
if ( size < 0 )
return ERR_PTR ( size ) ;
if ( size = = 0 )
return ERR_PTR ( - ENODATA ) ;
value = kzalloc ( size , GFP_NOFS ) ;
if ( ! value )
return ERR_PTR ( - ENOMEM ) ;
size = v9fs_fid_xattr_get ( fid , name , value , size ) ;
if ( size < 0 )
acl = ERR_PTR ( size ) ;
else if ( size = = 0 )
acl = ERR_PTR ( - ENODATA ) ;
else
acl = posix_acl_from_xattr ( & init_user_ns , value , size ) ;
2010-09-28 00:27:39 +05:30
kfree ( value ) ;
return acl ;
}
2022-09-22 17:17:04 +02:00
static struct posix_acl * v9fs_acl_get ( struct dentry * dentry , const char * name )
{
struct p9_fid * fid ;
struct posix_acl * acl = NULL ;
fid = v9fs_fid_lookup ( dentry ) ;
if ( IS_ERR ( fid ) )
return ERR_CAST ( fid ) ;
acl = v9fs_fid_get_acl ( fid , name ) ;
p9_fid_put ( fid ) ;
return acl ;
}
static struct posix_acl * __v9fs_get_acl ( struct p9_fid * fid , const char * name )
{
int retval ;
struct posix_acl * acl = NULL ;
acl = v9fs_fid_get_acl ( fid , name ) ;
if ( ! IS_ERR ( acl ) )
return acl ;
retval = PTR_ERR ( acl ) ;
if ( retval = = - ENODATA | | retval = = - ENOSYS | | retval = = - EOPNOTSUPP )
return NULL ;
/* map everything else to -EIO */
return ERR_PTR ( - EIO ) ;
}
2010-09-28 00:27:39 +05:30
int v9fs_get_acl ( struct inode * inode , struct p9_fid * fid )
{
int retval = 0 ;
struct posix_acl * pacl , * dacl ;
2010-09-28 00:27:41 +05:30
struct v9fs_session_info * v9ses ;
2010-09-28 00:27:39 +05:30
2010-09-28 00:27:41 +05:30
v9ses = v9fs_inode2v9ses ( inode ) ;
2011-01-25 15:40:54 -08:00
if ( ( ( v9ses - > flags & V9FS_ACCESS_MASK ) ! = V9FS_ACCESS_CLIENT ) | |
( ( v9ses - > flags & V9FS_ACL_MASK ) ! = V9FS_POSIX_ACL ) ) {
2010-09-28 00:27:41 +05:30
set_cached_acl ( inode , ACL_TYPE_DEFAULT , NULL ) ;
set_cached_acl ( inode , ACL_TYPE_ACCESS , NULL ) ;
return 0 ;
}
2010-09-28 00:27:39 +05:30
/* get the default/access acl values and cache them */
2015-12-02 14:44:35 +01:00
dacl = __v9fs_get_acl ( fid , XATTR_NAME_POSIX_ACL_DEFAULT ) ;
pacl = __v9fs_get_acl ( fid , XATTR_NAME_POSIX_ACL_ACCESS ) ;
2010-09-28 00:27:39 +05:30
if ( ! IS_ERR ( dacl ) & & ! IS_ERR ( pacl ) ) {
set_cached_acl ( inode , ACL_TYPE_DEFAULT , dacl ) ;
set_cached_acl ( inode , ACL_TYPE_ACCESS , pacl ) ;
} else
retval = - EIO ;
2011-01-13 15:28:39 -08:00
if ( ! IS_ERR ( dacl ) )
posix_acl_release ( dacl ) ;
if ( ! IS_ERR ( pacl ) )
posix_acl_release ( pacl ) ;
2010-09-28 00:27:39 +05:30
return retval ;
}
static struct posix_acl * v9fs_get_cached_acl ( struct inode * inode , int type )
{
struct posix_acl * acl ;
/*
* 9 p Always cache the acl value when
* instantiating the inode ( v9fs_inode_from_fid )
*/
acl = get_cached_acl ( inode , type ) ;
2016-03-24 14:38:37 +01:00
BUG_ON ( is_uncached_acl ( acl ) ) ;
2010-09-28 00:27:39 +05:30
return acl ;
}
2022-09-22 17:17:04 +02:00
struct posix_acl * v9fs_iop_get_inode_acl ( struct inode * inode , int type , bool rcu )
2010-09-28 00:27:39 +05:30
{
2010-09-28 00:27:41 +05:30
struct v9fs_session_info * v9ses ;
2021-08-18 22:08:24 +02:00
if ( rcu )
return ERR_PTR ( - ECHILD ) ;
2010-09-28 00:27:41 +05:30
v9ses = v9fs_inode2v9ses ( inode ) ;
2011-01-25 15:40:54 -08:00
if ( ( ( v9ses - > flags & V9FS_ACCESS_MASK ) ! = V9FS_ACCESS_CLIENT ) | |
( ( v9ses - > flags & V9FS_ACL_MASK ) ! = V9FS_POSIX_ACL ) ) {
2010-09-28 00:27:41 +05:30
/*
2011-01-25 15:40:54 -08:00
* On access = client and acl = on mode get the acl
2010-09-28 00:27:41 +05:30
* values from the server
*/
2011-07-23 17:37:31 +02:00
return NULL ;
2010-09-28 00:27:41 +05:30
}
2011-07-23 17:37:31 +02:00
return v9fs_get_cached_acl ( inode , type ) ;
2010-09-28 00:27:39 +05:30
}
2010-09-28 00:27:39 +05:30
2022-09-22 17:17:04 +02:00
struct posix_acl * v9fs_iop_get_acl ( struct user_namespace * mnt_userns ,
struct dentry * dentry , int type )
{
struct v9fs_session_info * v9ses ;
v9ses = v9fs_dentry2v9ses ( dentry ) ;
/* We allow set/get/list of acl when access=client is not specified. */
if ( ( v9ses - > flags & V9FS_ACCESS_MASK ) ! = V9FS_ACCESS_CLIENT )
return v9fs_acl_get ( dentry , posix_acl_xattr_name ( type ) ) ;
return v9fs_get_cached_acl ( d_inode ( dentry ) , type ) ;
}
2022-09-22 17:17:05 +02:00
int v9fs_iop_set_acl ( struct user_namespace * mnt_userns , struct dentry * dentry ,
struct posix_acl * acl , int type )
{
int retval ;
size_t size = 0 ;
void * value = NULL ;
const char * acl_name ;
struct v9fs_session_info * v9ses ;
struct inode * inode = d_inode ( dentry ) ;
if ( acl ) {
retval = posix_acl_valid ( inode - > i_sb - > s_user_ns , acl ) ;
if ( retval )
goto err_out ;
size = posix_acl_xattr_size ( acl - > a_count ) ;
value = kzalloc ( size , GFP_NOFS ) ;
if ( ! value ) {
retval = - ENOMEM ;
goto err_out ;
}
retval = posix_acl_to_xattr ( & init_user_ns , acl , value , size ) ;
if ( retval < 0 )
goto err_out ;
}
/*
* set the attribute on the remote . Without even looking at the
* xattr value . We leave it to the server to validate
*/
acl_name = posix_acl_xattr_name ( type ) ;
v9ses = v9fs_dentry2v9ses ( dentry ) ;
if ( ( v9ses - > flags & V9FS_ACCESS_MASK ) ! = V9FS_ACCESS_CLIENT ) {
retval = v9fs_xattr_set ( dentry , acl_name , value , size , 0 ) ;
goto err_out ;
}
if ( S_ISLNK ( inode - > i_mode ) ) {
retval = - EOPNOTSUPP ;
goto err_out ;
}
if ( ! inode_owner_or_capable ( & init_user_ns , inode ) ) {
retval = - EPERM ;
goto err_out ;
}
switch ( type ) {
case ACL_TYPE_ACCESS :
if ( acl ) {
struct iattr iattr = { } ;
struct posix_acl * acl_mode = acl ;
retval = posix_acl_update_mode ( & init_user_ns , inode ,
& iattr . ia_mode ,
& acl_mode ) ;
if ( retval )
goto err_out ;
if ( ! acl_mode ) {
/*
* ACL can be represented by the mode bits .
* So don ' t update ACL below .
*/
kfree ( value ) ;
value = NULL ;
size = 0 ;
}
iattr . ia_valid = ATTR_MODE ;
/*
* FIXME should we update ctime ?
* What is the following setxattr update the mode ?
*/
2023-01-13 12:49:11 +01:00
v9fs_vfs_setattr_dotl ( & nop_mnt_idmap , dentry , & iattr ) ;
2022-09-22 17:17:05 +02:00
}
break ;
case ACL_TYPE_DEFAULT :
if ( ! S_ISDIR ( inode - > i_mode ) ) {
retval = acl ? - EINVAL : 0 ;
goto err_out ;
}
break ;
}
retval = v9fs_xattr_set ( dentry , acl_name , value , size , 0 ) ;
if ( ! retval )
set_cached_acl ( inode , type , acl ) ;
err_out :
kfree ( value ) ;
return retval ;
}
2013-01-31 12:54:47 -05:00
static int v9fs_set_acl ( struct p9_fid * fid , int type , struct posix_acl * acl )
2010-09-28 00:27:40 +05:30
{
int retval ;
char * name ;
size_t size ;
void * buffer ;
2021-11-02 22:16:43 +09:00
2011-01-13 16:33:00 -08:00
if ( ! acl )
return 0 ;
2010-09-28 00:27:40 +05:30
/* Set a setxattr request to server */
size = posix_acl_xattr_size ( acl - > a_count ) ;
buffer = kmalloc ( size , GFP_KERNEL ) ;
if ( ! buffer )
return - ENOMEM ;
2012-09-10 20:17:44 -07:00
retval = posix_acl_to_xattr ( & init_user_ns , acl , buffer , size ) ;
2010-09-28 00:27:40 +05:30
if ( retval < 0 )
goto err_free_out ;
switch ( type ) {
case ACL_TYPE_ACCESS :
2015-12-02 14:44:35 +01:00
name = XATTR_NAME_POSIX_ACL_ACCESS ;
2010-09-28 00:27:40 +05:30
break ;
case ACL_TYPE_DEFAULT :
2015-12-02 14:44:35 +01:00
name = XATTR_NAME_POSIX_ACL_DEFAULT ;
2010-09-28 00:27:40 +05:30
break ;
default :
BUG ( ) ;
}
2013-01-31 12:54:47 -05:00
retval = v9fs_fid_xattr_set ( fid , name , buffer , size , 0 ) ;
2010-09-28 00:27:40 +05:30
err_free_out :
kfree ( buffer ) ;
return retval ;
}
2013-01-31 12:58:16 -05:00
int v9fs_acl_chmod ( struct inode * inode , struct p9_fid * fid )
2010-09-28 00:27:40 +05:30
{
int retval = 0 ;
2011-07-23 00:18:02 -04:00
struct posix_acl * acl ;
2010-09-28 00:27:40 +05:30
if ( S_ISLNK ( inode - > i_mode ) )
return - EOPNOTSUPP ;
acl = v9fs_get_cached_acl ( inode , ACL_TYPE_ACCESS ) ;
if ( acl ) {
2013-12-20 05:16:41 -08:00
retval = __posix_acl_chmod ( & acl , GFP_KERNEL , inode - > i_mode ) ;
2011-07-23 00:18:02 -04:00
if ( retval )
return retval ;
2013-01-31 12:46:55 -05:00
set_cached_acl ( inode , ACL_TYPE_ACCESS , acl ) ;
2013-01-31 12:54:47 -05:00
retval = v9fs_set_acl ( fid , ACL_TYPE_ACCESS , acl ) ;
2010-09-28 00:27:40 +05:30
posix_acl_release ( acl ) ;
}
return retval ;
}
2013-01-31 13:45:39 -05:00
int v9fs_set_create_acl ( struct inode * inode , struct p9_fid * fid ,
2013-01-31 13:31:23 -05:00
struct posix_acl * dacl , struct posix_acl * acl )
2010-09-28 00:27:40 +05:30
{
2013-01-31 13:45:39 -05:00
set_cached_acl ( inode , ACL_TYPE_DEFAULT , dacl ) ;
set_cached_acl ( inode , ACL_TYPE_ACCESS , acl ) ;
v9fs_set_acl ( fid , ACL_TYPE_DEFAULT , dacl ) ;
v9fs_set_acl ( fid , ACL_TYPE_ACCESS , acl ) ;
2010-09-28 00:27:40 +05:30
return 0 ;
}
2013-01-31 13:31:23 -05:00
void v9fs_put_acl ( struct posix_acl * dacl ,
struct posix_acl * acl )
{
posix_acl_release ( dacl ) ;
posix_acl_release ( acl ) ;
}
2011-07-23 18:37:50 -04:00
int v9fs_acl_mode ( struct inode * dir , umode_t * modep ,
2010-09-28 00:27:40 +05:30
struct posix_acl * * dpacl , struct posix_acl * * pacl )
{
int retval = 0 ;
2011-07-23 18:37:50 -04:00
umode_t mode = * modep ;
2010-09-28 00:27:40 +05:30
struct posix_acl * acl = NULL ;
if ( ! S_ISLNK ( mode ) ) {
acl = v9fs_get_cached_acl ( dir , ACL_TYPE_DEFAULT ) ;
if ( IS_ERR ( acl ) )
return PTR_ERR ( acl ) ;
if ( ! acl )
mode & = ~ current_umask ( ) ;
}
if ( acl ) {
if ( S_ISDIR ( mode ) )
2011-07-23 02:28:13 -04:00
* dpacl = posix_acl_dup ( acl ) ;
2013-12-20 05:16:42 -08:00
retval = __posix_acl_create ( & acl , GFP_NOFS , & mode ) ;
2011-07-23 03:10:32 -04:00
if ( retval < 0 )
return retval ;
2010-09-28 00:27:40 +05:30
if ( retval > 0 )
2011-07-23 03:10:32 -04:00
* pacl = acl ;
2011-07-23 02:28:13 -04:00
else
2011-07-23 03:10:32 -04:00
posix_acl_release ( acl ) ;
2010-09-28 00:27:40 +05:30
}
* modep = mode ;
return 0 ;
}