2017-12-09 01:29:07 +03:00
/*
* Unix SMB / CIFS implementation .
* Samba VFS module for error injection in VFS calls
* Copyright ( C ) Christof Schmitt 2017
*
* 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"
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_VFS
struct unix_error_map {
const char * err_str ;
int error ;
} unix_error_map_array [ ] = {
{ " ESTALE " , ESTALE } ,
2018-11-23 12:18:10 +03:00
{ " EBADF " , EBADF } ,
2020-02-19 16:44:11 +03:00
{ " EINTR " , EINTR } ,
2021-01-25 13:46:30 +03:00
{ " EACCES " , EACCES } ,
2017-12-09 01:29:07 +03:00
} ;
static int find_unix_error_from_string ( const char * err_str )
{
2020-10-30 17:43:03 +03:00
size_t i ;
2017-12-09 01:29:07 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( unix_error_map_array ) ; i + + ) {
struct unix_error_map * m = & unix_error_map_array [ i ] ;
if ( strequal ( err_str , m - > err_str ) ) {
return m - > error ;
}
}
return 0 ;
}
static int inject_unix_error ( const char * vfs_func , vfs_handle_struct * handle )
{
const char * err_str ;
err_str = lp_parm_const_string ( SNUM ( handle - > conn ) ,
" error_inject " , vfs_func , NULL ) ;
if ( err_str ! = NULL ) {
int error ;
error = find_unix_error_from_string ( err_str ) ;
if ( error ! = 0 ) {
DBG_WARNING ( " Returning error %s for VFS function %s \n " ,
err_str , vfs_func ) ;
return error ;
}
if ( strequal ( err_str , " panic " ) ) {
DBG_ERR ( " Panic in VFS function %s \n " , vfs_func ) ;
smb_panic ( " error_inject " ) ;
}
DBG_ERR ( " Unknown error inject %s requested "
" for vfs function %s \n " , err_str , vfs_func ) ;
}
return 0 ;
}
static int vfs_error_inject_chdir ( vfs_handle_struct * handle ,
const struct smb_filename * smb_fname )
{
int error ;
error = inject_unix_error ( " chdir " , handle ) ;
if ( error ! = 0 ) {
errno = error ;
return - 1 ;
}
return SMB_VFS_NEXT_CHDIR ( handle , smb_fname ) ;
}
2018-11-23 12:07:29 +03:00
static ssize_t vfs_error_inject_pwrite ( vfs_handle_struct * handle ,
files_struct * fsp ,
const void * data ,
size_t n ,
off_t offset )
{
int error ;
error = inject_unix_error ( " pwrite " , handle ) ;
if ( error ! = 0 ) {
errno = error ;
return - 1 ;
}
return SMB_VFS_NEXT_PWRITE ( handle , fsp , data , n , offset ) ;
}
2020-05-21 00:02:06 +03:00
static int vfs_error_inject_openat ( struct vfs_handle_struct * handle ,
const struct files_struct * dirfsp ,
const struct smb_filename * smb_fname ,
files_struct * fsp ,
2022-06-03 16:53:29 +03:00
const struct vfs_open_how * how )
2020-05-21 00:02:06 +03:00
{
int error = inject_unix_error ( " openat " , handle ) ;
2022-07-24 17:47:37 +03:00
int dirfsp_flags = ( O_NOFOLLOW | O_DIRECTORY ) ;
bool return_error ;
# ifdef O_PATH
dirfsp_flags | = O_PATH ;
# else
# ifdef O_SEARCH
dirfsp_flags | = O_SEARCH ;
# endif
# endif
return_error = ( error ! = 0 ) ;
return_error & = ! fsp - > fsp_flags . is_pathref ;
2022-06-03 16:53:29 +03:00
return_error & = ( ( how - > flags & dirfsp_flags ) ! = dirfsp_flags ) ;
2022-07-24 17:47:37 +03:00
if ( return_error ) {
2020-05-21 00:02:06 +03:00
errno = error ;
return - 1 ;
}
2022-06-03 16:53:29 +03:00
return SMB_VFS_NEXT_OPENAT ( handle , dirfsp , smb_fname , fsp , how ) ;
2020-05-21 00:02:06 +03:00
}
2021-01-25 13:46:30 +03:00
static int vfs_error_inject_unlinkat ( struct vfs_handle_struct * handle ,
struct files_struct * dirfsp ,
const struct smb_filename * smb_fname ,
int flags )
{
struct smb_filename * full_fname = NULL ;
struct smb_filename * parent_fname = NULL ;
int error = inject_unix_error ( " unlinkat " , handle ) ;
int ret ;
2021-05-26 21:03:25 +03:00
NTSTATUS status ;
2021-01-25 13:46:30 +03:00
if ( error = = 0 ) {
return SMB_VFS_NEXT_UNLINKAT ( handle , dirfsp , smb_fname , flags ) ;
}
full_fname = full_path_from_dirfsp_atname ( talloc_tos ( ) ,
dirfsp ,
smb_fname ) ;
if ( full_fname = = NULL ) {
return - 1 ;
}
2021-05-26 21:03:25 +03:00
status = SMB_VFS_PARENT_PATHNAME ( handle - > conn ,
full_fname , /* TALLOC_CTX. */
full_fname ,
& parent_fname ,
NULL ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2021-01-25 13:46:30 +03:00
TALLOC_FREE ( full_fname ) ;
2021-05-26 21:03:25 +03:00
errno = map_errno_from_nt_status ( status ) ;
2021-01-25 13:46:30 +03:00
return - 1 ;
}
ret = SMB_VFS_STAT ( handle - > conn , parent_fname ) ;
if ( ret ! = 0 ) {
TALLOC_FREE ( full_fname ) ;
return - 1 ;
}
if ( parent_fname - > st . st_ex_uid = = get_current_uid ( dirfsp - > conn ) ) {
return SMB_VFS_NEXT_UNLINKAT ( handle , dirfsp , smb_fname , flags ) ;
}
errno = error ;
return - 1 ;
}
2017-12-09 01:29:07 +03:00
static struct vfs_fn_pointers vfs_error_inject_fns = {
. chdir_fn = vfs_error_inject_chdir ,
2018-11-23 12:07:29 +03:00
. pwrite_fn = vfs_error_inject_pwrite ,
2020-05-21 00:02:06 +03:00
. openat_fn = vfs_error_inject_openat ,
2021-01-25 13:46:30 +03:00
. unlinkat_fn = vfs_error_inject_unlinkat ,
2017-12-09 01:29:07 +03:00
} ;
static_decl_vfs ;
NTSTATUS vfs_error_inject_init ( TALLOC_CTX * ctx )
{
return smb_register_vfs ( SMB_VFS_INTERFACE_VERSION , " error_inject " ,
& vfs_error_inject_fns ) ;
}