2014-09-01 12:40:10 +04:00
/*
Unix SMB / CIFS implementation .
Wrap VxFS calls in vfs functions .
2016-06-02 09:38:31 +03:00
This module is for ACL and XATTR handling .
2014-09-01 12:40:10 +04:00
Copyright ( C ) Symantec Corporation < www . symantec . com > 2014
2016-06-02 09:38:31 +03:00
Copyright ( C ) Veritas Technologies LLC < www . veritas . com > 2016
2014-09-01 12:40:10 +04:00
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 ; either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will 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 , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
# include "smbd/smbd.h"
# include "librpc/gen_ndr/ndr_xattr.h"
# include "../libcli/security/security.h"
# include "../librpc/gen_ndr/ndr_security.h"
# include "system/filesys.h"
2016-06-02 09:38:31 +03:00
# include "vfs_vxfs.h"
2014-09-01 12:40:10 +04:00
2020-08-07 23:27:39 +03:00
# undef strcasecmp
2014-09-01 12:40:10 +04:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_VFS
# define MODULE_NAME "vxfs"
/*
* WARNING ! ! WARNING ! !
*
* DO NOT CHANGE THIS FROM " system. " space to
* " user. " space unless you are shipping a product
* that RESTRICTS access to extended attributes
* to smbd - only . " system. " space is restricted
* to root access only , " user. " space is available
* to ANY USER .
*
* If this is changed to " user. " and access
* to extended attributes is available via
* local processes or other remote file system
* ( e . g . NFS ) then the security of the system
* WILL BE COMPROMISED . i . e . non - root users
* WILL be able to overwrite Samba ACLs on
* the file system .
*
* If you need to modify this define , do
* so using CFLAGS on your build command
* line .
* e . g . CFLAGS = - DXATTR_USER_NTACL = " user.NTACL "
*
* Added by : < jra @ samba . org > 17 Sept . 2014.
*
*/
# ifndef XATTR_USER_NTACL
# define XATTR_USER_NTACL "system.NTACL"
# endif
/* type values */
# define VXFS_ACL_UNDEFINED_TYPE 0
# define VXFS_ACL_USER_OBJ 1
# define VXFS_ACL_GROUP_OBJ 2
# define VXFS_ACL_USER 3
# define VXFS_ACL_GROUP 4
# define VXFS_ACL_OTHER 5
# define VXFS_ACL_MASK 6
/*
* Compare aces
* This will compare two ace entries for sorting
* each entry contains : type , perms and id
* Sort by type first , if type is same sort by id .
*/
static int vxfs_ace_cmp ( const void * ace1 , const void * ace2 )
{
int ret = 0 ;
uint16_t type_a1 , type_a2 ;
uint32_t id_a1 , id_a2 ;
/* Type must be compared first */
type_a1 = SVAL ( ace1 , 0 ) ;
type_a2 = SVAL ( ace2 , 0 ) ;
ret = ( type_a1 - type_a2 ) ;
if ( ! ret ) {
/* Compare ID under type */
/* skip perm thus take offset as 4*/
id_a1 = IVAL ( ace1 , 4 ) ;
id_a2 = IVAL ( ace2 , 4 ) ;
ret = id_a1 - id_a2 ;
}
return ret ;
}
static void vxfs_print_ace_buf ( char * buf , int count ) {
int i , offset = 0 ;
uint16_t type , perm ;
uint32_t id ;
DEBUG ( 10 , ( " vfs_vxfs: Printing aces: \n " ) ) ;
for ( i = 0 ; i < count ; i + + ) {
type = SVAL ( buf , offset ) ;
offset + = 2 ;
perm = SVAL ( buf , offset ) ;
offset + = 2 ;
id = IVAL ( buf , offset ) ;
offset + = 4 ;
DEBUG ( 10 , ( " vfs_vxfs: type = %u, perm = %u, id = %u \n " ,
( unsigned int ) type , ( unsigned int ) perm ,
( unsigned int ) id ) ) ;
}
}
/*
* Sort aces so that comparing 2 ACLs will be straight forward .
* This function will fill buffer as follows :
* For each ace :
* 1. ace - > a_type will be filled as first 2 bytes in buf .
* 2. ace - > a_perm will be filled as next 2 bytes .
* 3. ace - > xid will be filled as next 4 bytes .
* Thus each ace entry in buf is equal to 8 bytes .
* Also a_type is mapped to VXFS_ACL_ * so that ordering aces
* becomes easy .
*/
static char * vxfs_sort_acl ( SMB_ACL_T theacl , TALLOC_CTX * mem_ctx ,
uint32_t o_uid ,
uint32_t o_gid ) {
struct smb_acl_entry * smb_ace ;
int i , count ;
uint16_t type , perm ;
uint32_t id ;
int offset = 0 ;
char * buf = NULL ;
count = theacl - > count ;
buf = talloc_zero_size ( mem_ctx , count * 8 ) ;
if ( ! buf ) {
return NULL ;
}
smb_ace = theacl - > acl ;
for ( i = 0 ; i < count ; i + + ) {
/* Calculate type */
/* Map type to SMB_ACL_* to VXFS_ACL_* */
switch ( smb_ace - > a_type ) {
case SMB_ACL_USER :
type = VXFS_ACL_USER ;
break ;
case SMB_ACL_USER_OBJ :
type = VXFS_ACL_USER_OBJ ;
break ;
case SMB_ACL_GROUP :
type = VXFS_ACL_GROUP ;
break ;
case SMB_ACL_GROUP_OBJ :
type = VXFS_ACL_GROUP_OBJ ;
break ;
case SMB_ACL_OTHER :
type = VXFS_ACL_OTHER ;
break ;
case SMB_ACL_MASK :
type = VXFS_ACL_MASK ;
break ;
default :
type = - 1 ;
talloc_free ( buf ) ;
return NULL ;
}
type = type & 0xff ;
/* Calculate id:
* We get owner uid and owner group gid in o_uid and o_gid
* Put these ids instead of - 1
*/
switch ( smb_ace - > a_type ) {
case SMB_ACL_USER :
id = smb_ace - > info . user . uid ;
break ;
case SMB_ACL_GROUP :
id = smb_ace - > info . group . gid ;
break ;
case SMB_ACL_USER_OBJ :
id = o_uid ;
break ;
case SMB_ACL_GROUP_OBJ :
id = o_gid ;
break ;
case SMB_ACL_MASK :
case SMB_ACL_OTHER :
id = - 1 ;
break ;
default :
/* Can't happen.. */
id = - 1 ;
break ;
}
/* Calculate perm */
perm = smb_ace - > a_perm & 0xff ;
/* TYPE is the first 2 bytes of an entry */
SSVAL ( buf , offset , type ) ;
offset + = 2 ;
/* PERM is the next 2 bytes of an entry */
SSVAL ( buf , offset , perm ) ;
offset + = 2 ;
/* ID is the last 4 bytes of an entry */
SIVAL ( buf , offset , id ) ;
offset + = 4 ;
smb_ace + + ;
}
qsort ( buf , count , 8 , vxfs_ace_cmp ) ;
DEBUG ( 10 , ( " vfs_vxfs: Print sorted aces: \n " ) ) ;
vxfs_print_ace_buf ( buf , count ) ;
return buf ;
}
/* This function gets e_buf as an arg which is sorted and created out of
* existing ACL . This function will compact this e_buf to c_buf where USER
* and GROUP aces matching with USER_OBJ and GROUP_OBJ will be merged
* respectively .
* This is similar to what posix_acls . c does . This will make sure existing
* acls are converted much similar to what posix_acls calculates .
*/
static char * vxfs_compact_buf ( char * e_buf , int * new_count , int count ,
TALLOC_CTX * mem_ctx )
{
int i , e_offset = 0 , c_offset = 0 ;
uint16_t type , perm , o_perm ;
uint32_t id , owner_id , group_id ;
char * c_buf = NULL ;
if ( count < 2 ) {
return NULL ;
}
c_buf = talloc_zero_size ( mem_ctx , count * 8 ) ;
if ( ! c_buf ) {
return NULL ;
}
/*Copy first two enries from e_buf to c_buf
* These are USER_OBJ and GROUP_OBJ
*/
memcpy ( c_buf , e_buf , 16 ) ;
( * new_count ) = 2 ;
owner_id = IVAL ( e_buf , 4 ) ;
group_id = IVAL ( e_buf , 12 ) ;
c_offset = e_offset = 16 ;
/* Start comparing other entries */
for ( i = 2 ; i < count ; i + + ) {
type = SVAL ( e_buf , e_offset ) ;
e_offset + = 2 ;
perm = SVAL ( e_buf , e_offset ) ;
e_offset + = 2 ;
id = IVAL ( e_buf , e_offset ) ;
e_offset + = 4 ;
switch ( type ) {
case VXFS_ACL_USER :
if ( id = = owner_id ) {
o_perm = SVAL ( c_buf , 2 ) ;
o_perm | = perm ;
SSVAL ( c_buf , 2 , o_perm ) ;
DEBUG ( 10 , ( " vfs_vxfs: merging with owner "
" e_type = %u, "
" e_perm = %u, "
" e_id = %u \n " , ( unsigned int ) type ,
( unsigned int ) perm ,
( unsigned int ) id ) ) ;
continue ;
}
break ;
case VXFS_ACL_GROUP :
if ( id = = group_id ) {
o_perm = SVAL ( c_buf , 10 ) ;
o_perm | = perm ;
SSVAL ( c_buf , 10 , o_perm ) ;
DEBUG ( 10 , ( " vfs_vxfs: merging with owner group "
" e_type = %u, "
" e_perm = %u, "
" e_id = %u \n " , ( unsigned int ) type ,
( unsigned int ) perm ,
( unsigned int ) id ) ) ;
continue ;
}
break ;
}
SSVAL ( c_buf , c_offset , type ) ;
c_offset + = 2 ;
SSVAL ( c_buf , c_offset , perm ) ;
c_offset + = 2 ;
SIVAL ( c_buf , c_offset , id ) ;
c_offset + = 4 ;
( * new_count ) + + ;
}
DEBUG ( 10 , ( " vfs_vxfs: new_count is %d \n " , * new_count ) ) ;
return c_buf ;
}
/* Actually compare New ACL and existing ACL buf */
static bool vxfs_compare_acls ( char * e_buf , char * n_buf , int n_count ,
int e_count ) {
uint16_t e_type , n_type , e_perm , n_perm ;
uint32_t e_id , n_id ;
int i , offset = 0 ;
if ( ! e_buf & & ! n_buf ) {
DEBUG ( 10 , ( " vfs_vxfs: Empty buffers! \n " ) ) ;
return false ;
}
if ( ( e_count < 2 ) | | ( n_count < 2 ) ) {
return false ;
}
/*Get type from last entry from both buffers.
* It may or may not be ACL_MASK
*/
n_type = SVAL ( n_buf , offset + ( 8 * ( n_count - 1 ) ) ) ;
e_type = SVAL ( e_buf , offset + ( 8 * ( e_count - 1 ) ) ) ;
/* Check for ACL_MASK entry properly. Handle all 4 cases*/
/* If ACL_MASK entry is present in any of the buffers,
* it will be always the last one . Calculate count to compare
* based on if ACL_MASK is present on new and existing ACL
*/
if ( ( n_type ! = VXFS_ACL_MASK ) & & ( e_type = = VXFS_ACL_MASK ) ) {
DEBUG ( 10 , ( " vfs_vxfs: New ACL does not have mask entry, "
" reduce count by 1 and compare \n " ) ) ;
e_count = e_count - 1 ;
}
if ( ( n_type = = VXFS_ACL_MASK ) & & ( e_type ! = VXFS_ACL_MASK ) ) {
DEBUG ( 10 , ( " vfs_vxfs: new ACL to be set contains mask "
" existing ACL does not have mask entry \n "
" Need to set New ACL \n " ) ) ;
return false ;
}
if ( memcmp ( e_buf , n_buf , ( e_count * 8 ) ) ! = 0 ) {
DEBUG ( 10 , ( " vfs_vxfs: Compare with memcmp, "
" buffers not same! \n " ) ) ;
return false ;
}
return true ;
}
/* In VxFS, POSIX ACLs are pointed by separate inode for each file/dir.
* However , files / dir share same POSIX ACL inode if ACLs are inherited
* from parent .
* To retain this behaviour , below function avoids ACL set call if
* underlying ACLs are already same and thus saves creating extra inode .
*
* This function will execute following steps :
* 1. Get existing ACL
* 2. Sort New ACL and existing ACL into buffers
* 3. Compact existing ACL buf
* 4. Finally compare New ACL buf and Compact buf
* 5. If same , return true
* 6. Else need to set New ACL
*/
2020-04-30 12:48:41 +03:00
static bool vxfs_compare ( connection_struct * conn ,
2020-04-30 12:51:15 +03:00
const struct smb_filename * smb_fname ,
2020-04-30 12:48:41 +03:00
SMB_ACL_T the_acl ,
2014-09-01 12:40:10 +04:00
SMB_ACL_TYPE_T the_acl_type )
{
2020-04-30 12:51:15 +03:00
char * name = smb_fname - > base_name ;
2014-09-01 12:40:10 +04:00
SMB_ACL_T existing_acl = NULL ;
bool ret = false ;
int i , count = 0 ;
TALLOC_CTX * mem_ctx = talloc_tos ( ) ;
char * existing_buf = NULL , * new_buf = NULL , * compact_buf = NULL ;
struct smb_filename * smb_fname = NULL ;
int status ;
DEBUG ( 10 , ( " vfs_vxfs: Getting existing ACL for %s \n " , name ) ) ;
2017-05-24 03:11:18 +03:00
existing_acl = SMB_VFS_SYS_ACL_GET_FILE ( conn , smb_fname , the_acl_type ,
2014-09-01 12:40:10 +04:00
mem_ctx ) ;
if ( existing_acl = = NULL ) {
DEBUG ( 10 , ( " vfs_vxfs: Failed to get ACL \n " ) ) ;
goto out ;
}
DEBUG ( 10 , ( " vfs_vxfs: Existing ACL count=%d \n " , existing_acl - > count ) ) ;
DEBUG ( 10 , ( " vfs_vxfs: New ACL count=%d \n " , the_acl - > count ) ) ;
if ( existing_acl - > count = = 0 ) {
DEBUG ( 10 , ( " vfs_vxfs: ACL count is 0, Need to set \n " ) ) ;
goto out ;
}
status = SMB_VFS_STAT ( conn , smb_fname ) ;
if ( status = = - 1 ) {
DEBUG ( 10 , ( " vfs_vxfs: stat failed! \n " ) ) ;
goto out ;
}
DEBUG ( 10 , ( " vfs_vxfs: Sorting existing ACL \n " ) ) ;
existing_buf = vxfs_sort_acl ( existing_acl , mem_ctx ,
smb_fname - > st . st_ex_uid ,
smb_fname - > st . st_ex_gid ) ;
if ( ! existing_buf )
goto out ;
DEBUG ( 10 , ( " vfs_vxfs: Sorting new ACL \n " ) ) ;
new_buf = vxfs_sort_acl ( the_acl , mem_ctx , smb_fname - > st . st_ex_uid ,
smb_fname - > st . st_ex_gid ) ;
if ( ! new_buf ) {
goto out ;
}
DEBUG ( 10 , ( " vfs_vxfs: Compact existing buf \n " ) ) ;
compact_buf = vxfs_compact_buf ( existing_buf , & count ,
existing_acl - > count ,
mem_ctx ) ;
if ( ! compact_buf ) {
goto out ;
}
vxfs_print_ace_buf ( compact_buf , count ) ;
/* COmpare ACLs only if count is same or mismatch by 1 */
if ( ( count = = the_acl - > count ) | |
( count = = the_acl - > count + 1 ) | |
( count + 1 = = the_acl - > count ) ) {
if ( vxfs_compare_acls ( compact_buf , new_buf , the_acl - > count ,
count ) ) {
DEBUG ( 10 , ( " vfs_vxfs: ACLs matched. Not setting. \n " ) ) ;
ret = true ;
goto out ;
} else
DEBUG ( 10 , ( " vfs_vxfs: ACLs NOT matched. Setting \n " ) ) ;
} else {
DEBUG ( 10 , ( " vfs_vxfs: ACLs count does not match. Setting \n " ) ) ;
}
out :
TALLOC_FREE ( existing_acl ) ;
TALLOC_FREE ( existing_buf ) ;
TALLOC_FREE ( compact_buf ) ;
TALLOC_FREE ( new_buf ) ;
return ret ;
}
2020-12-14 18:28:26 +03:00
static int vxfs_sys_acl_set_fd ( vfs_handle_struct * handle ,
struct files_struct * fsp ,
SMB_ACL_TYPE_T type ,
2014-09-01 12:40:10 +04:00
SMB_ACL_T theacl )
{
2020-04-30 12:51:15 +03:00
if ( vxfs_compare ( fsp - > conn , fsp - > fsp_name , theacl ,
2020-12-14 10:10:44 +03:00
type ) ) {
2014-09-01 12:40:10 +04:00
return 0 ;
}
2020-12-14 18:28:26 +03:00
return SMB_VFS_NEXT_SYS_ACL_SET_FD ( handle , fsp , type , theacl ) ;
2014-09-01 12:40:10 +04:00
}
2017-05-25 22:41:31 +03:00
static int vxfs_set_xattr ( struct vfs_handle_struct * handle ,
const struct smb_filename * smb_fname_in ,
const char * name ,
const void * value ,
size_t size ,
int flags )
{
struct smb_filename * smb_fname = NULL ;
2016-06-02 09:38:31 +03:00
bool is_dir = false ;
int ret = 0 ;
2017-05-25 22:41:31 +03:00
int saved_errno = 0 ;
2014-09-01 12:40:10 +04:00
DEBUG ( 10 , ( " In vxfs_set_xattr \n " ) ) ;
2017-05-25 22:41:31 +03:00
smb_fname = cp_smb_filename_nostream ( talloc_tos ( ) , smb_fname_in ) ;
2016-06-02 09:38:31 +03:00
if ( smb_fname = = NULL ) {
errno = ENOMEM ;
return - 1 ;
}
if ( SMB_VFS_NEXT_STAT ( handle , smb_fname ) ! = 0 ) {
TALLOC_FREE ( smb_fname ) ;
return - 1 ;
}
is_dir = S_ISDIR ( smb_fname - > st . st_ex_mode ) ;
2017-05-25 22:41:31 +03:00
ret = vxfs_setxattr_path ( smb_fname_in - > base_name , name , value , size ,
flags , is_dir ) ;
2016-06-02 09:38:31 +03:00
if ( ( ret = = 0 ) | |
( ( ret = = - 1 ) & & ( errno ! = ENOTSUP ) & & ( errno ! = ENOSYS ) ) ) {
/*
* Now remve old style xattr if it exists
*/
2017-05-24 21:35:50 +03:00
SMB_VFS_NEXT_REMOVEXATTR ( handle , smb_fname , name ) ;
2016-06-02 09:38:31 +03:00
/*
* Do not bother about return value
*/
2017-05-25 22:41:31 +03:00
if ( ret ! = 0 ) {
saved_errno = errno ;
}
goto fail ;
2016-06-02 09:38:31 +03:00
}
DEBUG ( 10 , ( " Fallback to xattr \n " ) ) ;
2014-09-01 12:40:10 +04:00
if ( strcmp ( name , XATTR_NTACL_NAME ) = = 0 ) {
2017-05-25 22:41:31 +03:00
ret = SMB_VFS_NEXT_SETXATTR ( handle , smb_fname ,
XATTR_USER_NTACL ,
value , size , flags ) ;
if ( ret ! = 0 ) {
saved_errno = errno ;
goto fail ;
}
return 0 ;
2014-09-01 12:40:10 +04:00
}
/* Clients can't set XATTR_USER_NTACL directly. */
if ( strcasecmp ( name , XATTR_USER_NTACL ) = = 0 ) {
2017-05-25 22:41:31 +03:00
saved_errno = EACCES ;
ret = - 1 ;
goto fail ;
}
ret = SMB_VFS_NEXT_SETXATTR ( handle , smb_fname ,
name , value , size , flags ) ;
if ( ret ! = 0 ) {
saved_errno = errno ;
goto fail ;
2014-09-01 12:40:10 +04:00
}
2017-05-25 22:41:31 +03:00
fail :
TALLOC_FREE ( smb_fname ) ;
if ( saved_errno ! = 0 ) {
saved_errno = errno ;
}
return ret ;
2014-09-01 12:40:10 +04:00
}
static int vxfs_fset_xattr ( struct vfs_handle_struct * handle ,
struct files_struct * fsp , const char * name ,
const void * value , size_t size , int flags ) {
2016-06-02 09:38:31 +03:00
int ret = 0 ;
2014-09-01 12:40:10 +04:00
DEBUG ( 10 , ( " In vxfs_fset_xattr \n " ) ) ;
2020-09-26 22:52:52 +03:00
ret = vxfs_setxattr_fd ( fsp_get_io_fd ( fsp ) , name , value , size , flags ) ;
2016-06-02 09:38:31 +03:00
if ( ( ret = = 0 ) | |
( ( ret = = - 1 ) & & ( errno ! = ENOTSUP ) & & ( errno ! = ENOSYS ) ) ) {
SMB_VFS_NEXT_FREMOVEXATTR ( handle , fsp , name ) ;
return ret ;
}
DEBUG ( 10 , ( " Fallback to xattr " ) ) ;
2014-09-01 12:40:10 +04:00
if ( strcmp ( name , XATTR_NTACL_NAME ) = = 0 ) {
return SMB_VFS_NEXT_FSETXATTR ( handle , fsp , XATTR_USER_NTACL ,
value , size , flags ) ;
}
/* Clients can't set XATTR_USER_NTACL directly. */
if ( strcasecmp ( name , XATTR_USER_NTACL ) = = 0 ) {
errno = EACCES ;
return - 1 ;
}
return SMB_VFS_NEXT_FSETXATTR ( handle , fsp , name , value , size , flags ) ;
}
static ssize_t vxfs_get_xattr ( struct vfs_handle_struct * handle ,
2017-05-26 02:42:04 +03:00
const struct smb_filename * smb_fname ,
const char * name ,
void * value ,
size_t size ) {
2016-06-02 09:38:31 +03:00
int ret ;
2014-09-01 12:40:10 +04:00
DEBUG ( 10 , ( " In vxfs_get_xattr \n " ) ) ;
2017-05-26 02:42:04 +03:00
ret = vxfs_getxattr_path ( smb_fname - > base_name , name , value , size ) ;
2016-06-02 09:38:31 +03:00
if ( ( ret ! = - 1 ) | | ( ( errno ! = ENOTSUP ) & &
( errno ! = ENOSYS ) & & ( errno ! = ENODATA ) ) ) {
return ret ;
}
2014-09-01 12:40:10 +04:00
2016-06-02 09:38:31 +03:00
DEBUG ( 10 , ( " Fallback to xattr \n " ) ) ;
2014-09-01 12:40:10 +04:00
if ( strcmp ( name , XATTR_NTACL_NAME ) = = 0 ) {
2017-05-26 02:42:04 +03:00
return SMB_VFS_NEXT_GETXATTR ( handle , smb_fname ,
XATTR_USER_NTACL , value , size ) ;
2014-09-01 12:40:10 +04:00
}
/* Clients can't see XATTR_USER_NTACL directly. */
if ( strcasecmp ( name , XATTR_USER_NTACL ) = = 0 ) {
errno = ENOATTR ;
return - 1 ;
}
2017-05-26 02:42:04 +03:00
return SMB_VFS_NEXT_GETXATTR ( handle , smb_fname , name , value , size ) ;
2014-09-01 12:40:10 +04:00
}
static ssize_t vxfs_fget_xattr ( struct vfs_handle_struct * handle ,
struct files_struct * fsp , const char * name ,
void * value , size_t size ) {
2016-06-02 09:38:31 +03:00
int ret ;
2014-09-01 12:40:10 +04:00
DEBUG ( 10 , ( " In vxfs_fget_xattr \n " ) ) ;
2020-09-26 22:52:52 +03:00
ret = vxfs_getxattr_fd ( fsp_get_io_fd ( fsp ) , name , value , size ) ;
2016-06-02 09:38:31 +03:00
if ( ( ret ! = - 1 ) | | ( ( errno ! = ENOTSUP ) & &
( errno ! = ENOSYS ) & & ( errno ! = ENODATA ) ) ) {
return ret ;
}
DEBUG ( 10 , ( " Fallback to xattr \n " ) ) ;
2014-09-01 12:40:10 +04:00
if ( strcmp ( name , XATTR_NTACL_NAME ) = = 0 ) {
return SMB_VFS_NEXT_FGETXATTR ( handle , fsp , XATTR_USER_NTACL ,
value , size ) ;
}
/* Clients can't see XATTR_USER_NTACL directly. */
if ( strcasecmp ( name , XATTR_USER_NTACL ) = = 0 ) {
errno = ENOATTR ;
return - 1 ;
}
return SMB_VFS_NEXT_FGETXATTR ( handle , fsp , name , value , size ) ;
}
static int vxfs_remove_xattr ( struct vfs_handle_struct * handle ,
2017-05-24 21:35:50 +03:00
const struct smb_filename * smb_fname_in ,
const char * name )
{
2016-06-02 09:38:31 +03:00
bool is_dir = false ;
int ret = 0 , ret_new = 0 , old_errno ;
2017-05-24 21:35:50 +03:00
struct smb_filename * smb_fname = NULL ;
2014-09-01 12:40:10 +04:00
DEBUG ( 10 , ( " In vxfs_remove_xattr \n " ) ) ;
2017-05-24 21:35:50 +03:00
smb_fname = cp_smb_filename_nostream ( talloc_tos ( ) , smb_fname_in ) ;
if ( smb_fname = = NULL ) {
errno = ENOMEM ;
return - 1 ;
}
2016-06-02 09:38:31 +03:00
/* Remove with old way */
2014-09-01 12:40:10 +04:00
if ( strcmp ( name , XATTR_NTACL_NAME ) = = 0 ) {
2017-05-24 21:35:50 +03:00
ret = SMB_VFS_NEXT_REMOVEXATTR ( handle , smb_fname ,
2016-06-02 09:38:31 +03:00
XATTR_USER_NTACL ) ;
} else {
if ( strcasecmp ( name , XATTR_USER_NTACL ) ! = 0 ) {
2017-05-24 21:35:50 +03:00
ret = SMB_VFS_NEXT_REMOVEXATTR ( handle , smb_fname ,
2016-06-02 09:38:31 +03:00
name ) ;
}
2014-09-01 12:40:10 +04:00
}
2016-06-02 09:38:31 +03:00
/* Remove with new way */
2017-05-24 21:35:50 +03:00
old_errno = errno ;
2016-06-02 09:38:31 +03:00
if ( SMB_VFS_NEXT_STAT ( handle , smb_fname ) ! = 0 ) {
TALLOC_FREE ( smb_fname ) ;
2014-09-01 12:40:10 +04:00
return - 1 ;
}
2016-06-02 09:38:31 +03:00
is_dir = S_ISDIR ( smb_fname - > st . st_ex_mode ) ;
TALLOC_FREE ( smb_fname ) ;
/*
* If both fail , return failuer else return whichever succeeded
*/
2017-05-24 21:35:50 +03:00
ret_new = vxfs_removexattr_path ( smb_fname_in - > base_name , name , is_dir ) ;
2016-06-02 09:38:31 +03:00
if ( errno = = ENOTSUP | | errno = = ENOSYS ) {
errno = old_errno ;
}
if ( ( ret_new ! = - 1 ) & & ( ret = = - 1 ) ) {
ret = ret_new ;
}
return ret ;
2014-09-01 12:40:10 +04:00
}
static int vxfs_fremove_xattr ( struct vfs_handle_struct * handle ,
struct files_struct * fsp , const char * name ) {
2016-06-02 09:38:31 +03:00
int ret = 0 , ret_new = 0 , old_errno ;
2014-09-01 12:40:10 +04:00
DEBUG ( 10 , ( " In vxfs_fremove_xattr \n " ) ) ;
2016-06-02 09:38:31 +03:00
/* Remove with old way */
2014-09-01 12:40:10 +04:00
if ( strcmp ( name , XATTR_NTACL_NAME ) = = 0 ) {
2016-06-02 09:38:31 +03:00
ret = SMB_VFS_NEXT_FREMOVEXATTR ( handle , fsp ,
XATTR_USER_NTACL ) ;
} else {
/* Clients can't remove XATTR_USER_NTACL directly. */
if ( strcasecmp ( name , XATTR_USER_NTACL ) ! = 0 ) {
ret = SMB_VFS_NEXT_FREMOVEXATTR ( handle , fsp ,
name ) ;
}
2014-09-01 12:40:10 +04:00
}
2016-06-02 09:38:31 +03:00
old_errno = errno ;
2014-09-01 12:40:10 +04:00
2016-06-02 09:38:31 +03:00
/* Remove with new way */
2020-09-26 22:52:52 +03:00
ret_new = vxfs_removexattr_fd ( fsp_get_io_fd ( fsp ) , name ) ;
2016-06-02 09:38:31 +03:00
/*
* If both fail , return failuer else return whichever succeeded
*/
if ( errno = = ENOTSUP | | errno = = ENOSYS ) {
errno = old_errno ;
}
if ( ( ret_new ! = - 1 ) & & ( ret = = - 1 ) ) {
ret = ret_new ;
2014-09-01 12:40:10 +04:00
}
2016-06-02 09:38:31 +03:00
return ret ;
2014-09-01 12:40:10 +04:00
}
static size_t vxfs_filter_list ( char * list , size_t size )
{
char * str = list ;
while ( str - list < size ) {
size_t element_len = strlen ( str ) + 1 ;
if ( strcasecmp ( str , XATTR_USER_NTACL ) = = 0 ) {
memmove ( str ,
str + element_len ,
size - ( str - list ) - element_len ) ;
size - = element_len ;
continue ;
}
str + = element_len ;
}
return size ;
}
2017-05-23 23:12:29 +03:00
static ssize_t vxfs_listxattr ( vfs_handle_struct * handle ,
const struct smb_filename * smb_fname ,
char * list ,
size_t size )
2014-09-01 12:40:10 +04:00
{
ssize_t result ;
2017-05-23 23:12:29 +03:00
result = vxfs_listxattr_path ( smb_fname - > base_name , list , size ) ;
2016-06-02 09:38:31 +03:00
if ( result > = 0 | | ( ( errno ! = ENOTSUP ) & & ( errno ! = ENOSYS ) ) ) {
return result ;
}
2017-05-23 23:12:29 +03:00
result = SMB_VFS_NEXT_LISTXATTR ( handle , smb_fname , list , size ) ;
2014-09-01 12:40:10 +04:00
if ( result < = 0 ) {
return result ;
}
/* Remove any XATTR_USER_NTACL elements from the returned list. */
result = vxfs_filter_list ( list , result ) ;
return result ;
}
static ssize_t vxfs_flistxattr ( struct vfs_handle_struct * handle ,
struct files_struct * fsp , char * list ,
size_t size )
{
ssize_t result ;
2020-09-26 22:52:52 +03:00
result = vxfs_listxattr_fd ( fsp_get_io_fd ( fsp ) , list , size ) ;
2016-06-02 09:38:31 +03:00
if ( result > = 0 | | ( ( errno ! = ENOTSUP ) & & ( errno ! = ENOSYS ) ) ) {
return result ;
}
2014-09-01 12:40:10 +04:00
result = SMB_VFS_NEXT_FLISTXATTR ( handle , fsp , list , size ) ;
if ( result < = 0 ) {
return result ;
}
/* Remove any XATTR_USER_NTACL elements from the returned list. */
result = vxfs_filter_list ( list , result ) ;
return result ;
}
2017-08-27 14:54:32 +03:00
static NTSTATUS vxfs_set_ea_dos_attributes ( struct vfs_handle_struct * handle ,
const struct smb_filename * smb_fname ,
uint32_t dosmode )
{
NTSTATUS err ;
2018-07-10 08:47:42 +03:00
int ret = 0 ;
2017-08-27 14:54:32 +03:00
bool attrset = false ;
2018-07-10 08:47:42 +03:00
bool is_dir = false ;
2017-08-27 14:54:32 +03:00
DBG_DEBUG ( " Entered function \n " ) ;
2018-07-10 08:47:42 +03:00
is_dir = S_ISDIR ( smb_fname - > st . st_ex_mode ) ;
2017-08-27 14:54:32 +03:00
if ( ! ( dosmode & FILE_ATTRIBUTE_READONLY ) ) {
ret = vxfs_checkwxattr_path ( smb_fname - > base_name ) ;
if ( ret = = - 1 ) {
DBG_DEBUG ( " ret:%d \n " , ret ) ;
if ( ( errno ! = EOPNOTSUPP ) & & ( errno ! = ENOENT ) ) {
return map_nt_error_from_unix ( errno ) ;
}
}
}
if ( dosmode & FILE_ATTRIBUTE_READONLY ) {
2018-07-10 08:47:42 +03:00
ret = vxfs_setwxattr_path ( smb_fname - > base_name , is_dir ) ;
2017-08-27 14:54:32 +03:00
DBG_DEBUG ( " ret:%d \n " , ret ) ;
if ( ret = = - 1 ) {
if ( ( errno ! = EOPNOTSUPP ) & & ( errno ! = EINVAL ) ) {
return map_nt_error_from_unix ( errno ) ;
}
} else {
attrset = true ;
}
}
err = SMB_VFS_NEXT_SET_DOS_ATTRIBUTES ( handle , smb_fname , dosmode ) ;
if ( ! NT_STATUS_IS_OK ( err ) ) {
if ( attrset ) {
2018-07-10 08:47:42 +03:00
ret = vxfs_clearwxattr_path ( smb_fname - > base_name , is_dir ) ;
2017-08-27 14:54:32 +03:00
DBG_DEBUG ( " ret:%d \n " , ret ) ;
if ( ( ret = = - 1 ) & & ( errno ! = ENOENT ) ) {
return map_nt_error_from_unix ( errno ) ;
}
}
}
return err ;
}
static NTSTATUS vxfs_fset_ea_dos_attributes ( struct vfs_handle_struct * handle ,
struct files_struct * fsp ,
uint32_t dosmode )
{
NTSTATUS err ;
int ret = 0 ;
bool attrset = false ;
DBG_DEBUG ( " Entered function \n " ) ;
if ( ! ( dosmode & FILE_ATTRIBUTE_READONLY ) ) {
2020-09-26 22:52:52 +03:00
ret = vxfs_checkwxattr_fd ( fsp_get_io_fd ( fsp ) ) ;
2017-08-27 14:54:32 +03:00
if ( ret = = - 1 ) {
DBG_DEBUG ( " ret:%d \n " , ret ) ;
if ( ( errno ! = EOPNOTSUPP ) & & ( errno ! = ENOENT ) ) {
return map_nt_error_from_unix ( errno ) ;
}
}
}
if ( dosmode & FILE_ATTRIBUTE_READONLY ) {
2020-09-26 22:52:52 +03:00
ret = vxfs_setwxattr_fd ( fsp_get_io_fd ( fsp ) ) ;
2017-08-27 14:54:32 +03:00
DBG_DEBUG ( " ret:%d \n " , ret ) ;
if ( ret = = - 1 ) {
if ( ( errno ! = EOPNOTSUPP ) & & ( errno ! = EINVAL ) ) {
return map_nt_error_from_unix ( errno ) ;
}
} else {
attrset = true ;
}
}
err = SMB_VFS_NEXT_FSET_DOS_ATTRIBUTES ( handle , fsp , dosmode ) ;
if ( ! NT_STATUS_IS_OK ( err ) ) {
if ( attrset ) {
2020-09-26 22:52:52 +03:00
ret = vxfs_clearwxattr_fd ( fsp_get_io_fd ( fsp ) ) ;
2017-08-27 14:54:32 +03:00
DBG_DEBUG ( " ret:%d \n " , ret ) ;
if ( ( ret = = - 1 ) & & ( errno ! = ENOENT ) ) {
return map_nt_error_from_unix ( errno ) ;
}
}
}
return err ;
}
2014-09-01 12:40:10 +04:00
static int vfs_vxfs_connect ( struct vfs_handle_struct * handle ,
const char * service , const char * user )
{
2016-06-02 09:38:31 +03:00
int ret ;
2014-09-01 12:40:10 +04:00
2016-06-02 09:38:31 +03:00
ret = SMB_VFS_NEXT_CONNECT ( handle , service , user ) ;
2014-09-01 12:40:10 +04:00
if ( ret < 0 ) {
return ret ;
}
2016-06-02 09:38:31 +03:00
vxfs_init ( ) ;
2014-09-01 12:40:10 +04:00
return 0 ;
}
static struct vfs_fn_pointers vfs_vxfs_fns = {
. connect_fn = vfs_vxfs_connect ,
2016-06-02 09:38:31 +03:00
# ifdef VXFS_ACL_SHARE
2014-09-01 12:40:10 +04:00
. sys_acl_set_fd_fn = vxfs_sys_acl_set_fd ,
2016-06-02 09:38:31 +03:00
# endif
2014-09-01 12:40:10 +04:00
2017-08-27 14:54:32 +03:00
. set_dos_attributes_fn = vxfs_set_ea_dos_attributes ,
. fset_dos_attributes_fn = vxfs_fset_ea_dos_attributes ,
2014-09-01 12:40:10 +04:00
. getxattr_fn = vxfs_get_xattr ,
2018-03-13 10:14:53 +03:00
. getxattrat_send_fn = vfs_not_implemented_getxattrat_send ,
. getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv ,
2014-09-01 12:40:10 +04:00
. fgetxattr_fn = vxfs_fget_xattr ,
. listxattr_fn = vxfs_listxattr ,
. flistxattr_fn = vxfs_flistxattr ,
. removexattr_fn = vxfs_remove_xattr ,
. fremovexattr_fn = vxfs_fremove_xattr ,
. setxattr_fn = vxfs_set_xattr ,
. fsetxattr_fn = vxfs_fset_xattr ,
} ;
2017-12-16 01:32:12 +03:00
static_decl_vfs ;
2017-04-20 22:24:43 +03:00
NTSTATUS vfs_vxfs_init ( TALLOC_CTX * ctx )
2014-09-01 12:40:10 +04:00
{
return smb_register_vfs ( SMB_VFS_INTERFACE_VERSION , " vxfs " ,
& vfs_vxfs_fns ) ;
}