2012-06-08 19:54:19 +04:00
/*
Unix SMB / CIFS implementation .
Durable Handle default VFS implementation
Copyright ( C ) Stefan Metzmacher 2012
Copyright ( C ) Michael Adam 2012
Copyright ( C ) Volker Lendecke 2012
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 "system/filesys.h"
2017-01-01 23:00:55 +03:00
# include "lib/util/server_id.h"
2012-06-08 19:54:19 +04:00
# include "smbd/smbd.h"
# include "smbd/globals.h"
# include "libcli/security/security.h"
# include "messages.h"
# include "librpc/gen_ndr/ndr_open_files.h"
# include "serverid.h"
# include "fake_file.h"
2018-09-19 14:37:23 +03:00
# include "locking/leases_db.h"
2012-06-08 19:54:19 +04:00
NTSTATUS vfs_default_durable_cookie ( struct files_struct * fsp ,
TALLOC_CTX * mem_ctx ,
DATA_BLOB * cookie_blob )
{
struct connection_struct * conn = fsp - > conn ;
enum ndr_err_code ndr_err ;
struct vfs_default_durable_cookie cookie ;
if ( ! lp_durable_handles ( SNUM ( conn ) ) ) {
return NT_STATUS_NOT_SUPPORTED ;
}
if ( lp_kernel_share_modes ( SNUM ( conn ) ) ) {
/*
* We do not support durable handles
* if kernel share modes ( flocks ) are used
*/
return NT_STATUS_NOT_SUPPORTED ;
}
if ( lp_kernel_oplocks ( SNUM ( conn ) ) ) {
/*
* We do not support durable handles
* if kernel oplocks are used
*/
return NT_STATUS_NOT_SUPPORTED ;
}
if ( ( fsp - > current_lock_count > 0 ) & &
lp_posix_locking ( fsp - > conn - > params ) )
{
/*
* We do not support durable handles
* if the handle has posix locks .
*/
return NT_STATUS_NOT_SUPPORTED ;
}
if ( fsp - > is_directory ) {
return NT_STATUS_NOT_SUPPORTED ;
}
if ( fsp - > fh - > fd = = - 1 ) {
return NT_STATUS_NOT_SUPPORTED ;
}
if ( is_ntfs_stream_smb_fname ( fsp - > fsp_name ) ) {
/*
* We do not support durable handles
* on streams for now .
*/
return NT_STATUS_NOT_SUPPORTED ;
}
if ( is_fake_file ( fsp - > fsp_name ) ) {
/*
* We do not support durable handles
* on fake files .
*/
return NT_STATUS_NOT_SUPPORTED ;
}
ZERO_STRUCT ( cookie ) ;
cookie . allow_reconnect = false ;
cookie . id = fsp - > file_id ;
cookie . servicepath = conn - > connectpath ;
cookie . base_name = fsp - > fsp_name - > base_name ;
cookie . initial_allocation_size = fsp - > initial_allocation_size ;
cookie . position_information = fsp - > fh - > position_information ;
2012-10-19 13:12:05 +04:00
cookie . update_write_time_triggered = fsp - > update_write_time_triggered ;
cookie . update_write_time_on_close = fsp - > update_write_time_on_close ;
cookie . write_time_forced = fsp - > write_time_forced ;
2019-12-02 18:30:50 +03:00
cookie . close_write_time = full_timespec_to_nt_time (
& fsp - > close_write_time ) ;
2012-06-08 19:54:19 +04:00
2012-10-19 18:00:05 +04:00
cookie . stat_info . st_ex_dev = fsp - > fsp_name - > st . st_ex_dev ;
cookie . stat_info . st_ex_ino = fsp - > fsp_name - > st . st_ex_ino ;
cookie . stat_info . st_ex_mode = fsp - > fsp_name - > st . st_ex_mode ;
cookie . stat_info . st_ex_nlink = fsp - > fsp_name - > st . st_ex_nlink ;
cookie . stat_info . st_ex_uid = fsp - > fsp_name - > st . st_ex_uid ;
cookie . stat_info . st_ex_gid = fsp - > fsp_name - > st . st_ex_gid ;
cookie . stat_info . st_ex_rdev = fsp - > fsp_name - > st . st_ex_rdev ;
cookie . stat_info . st_ex_size = fsp - > fsp_name - > st . st_ex_size ;
cookie . stat_info . st_ex_atime = fsp - > fsp_name - > st . st_ex_atime ;
cookie . stat_info . st_ex_mtime = fsp - > fsp_name - > st . st_ex_mtime ;
cookie . stat_info . st_ex_ctime = fsp - > fsp_name - > st . st_ex_ctime ;
cookie . stat_info . st_ex_btime = fsp - > fsp_name - > st . st_ex_btime ;
2019-06-27 18:06:46 +03:00
cookie . stat_info . st_ex_iflags = fsp - > fsp_name - > st . st_ex_iflags ;
2012-10-19 18:00:05 +04:00
cookie . stat_info . st_ex_blksize = fsp - > fsp_name - > st . st_ex_blksize ;
cookie . stat_info . st_ex_blocks = fsp - > fsp_name - > st . st_ex_blocks ;
cookie . stat_info . st_ex_flags = fsp - > fsp_name - > st . st_ex_flags ;
2012-06-08 19:54:19 +04:00
ndr_err = ndr_push_struct_blob ( cookie_blob , mem_ctx , & cookie ,
( ndr_push_flags_fn_t ) ndr_push_vfs_default_durable_cookie ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
NTSTATUS status = ndr_map_error2ntstatus ( ndr_err ) ;
return status ;
}
return NT_STATUS_OK ;
}
NTSTATUS vfs_default_durable_disconnect ( struct files_struct * fsp ,
const DATA_BLOB old_cookie ,
TALLOC_CTX * mem_ctx ,
DATA_BLOB * new_cookie )
{
struct connection_struct * conn = fsp - > conn ;
NTSTATUS status ;
enum ndr_err_code ndr_err ;
struct vfs_default_durable_cookie cookie ;
DATA_BLOB new_cookie_blob = data_blob_null ;
struct share_mode_lock * lck ;
bool ok ;
* new_cookie = data_blob_null ;
ZERO_STRUCT ( cookie ) ;
ndr_err = ndr_pull_struct_blob ( & old_cookie , talloc_tos ( ) , & cookie ,
( ndr_pull_flags_fn_t ) ndr_pull_vfs_default_durable_cookie ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
status = ndr_map_error2ntstatus ( ndr_err ) ;
return status ;
}
if ( strcmp ( cookie . magic , VFS_DEFAULT_DURABLE_COOKIE_MAGIC ) ! = 0 ) {
return NT_STATUS_INVALID_PARAMETER ;
}
if ( cookie . version ! = VFS_DEFAULT_DURABLE_COOKIE_VERSION ) {
return NT_STATUS_INVALID_PARAMETER ;
}
if ( ! file_id_equal ( & fsp - > file_id , & cookie . id ) ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2014-10-29 01:31:46 +03:00
if ( ( fsp_lease_type ( fsp ) & SMB2_LEASE_HANDLE ) = = 0 ) {
2012-06-08 19:54:19 +04:00
return NT_STATUS_NOT_SUPPORTED ;
}
/*
* For now let it be simple and do not keep
* delete on close files durable open
*/
if ( fsp - > initial_delete_on_close ) {
return NT_STATUS_NOT_SUPPORTED ;
}
if ( fsp - > delete_on_close ) {
return NT_STATUS_NOT_SUPPORTED ;
}
if ( ! VALID_STAT ( fsp - > fsp_name - > st ) ) {
return NT_STATUS_NOT_SUPPORTED ;
}
if ( ! S_ISREG ( fsp - > fsp_name - > st . st_ex_mode ) ) {
return NT_STATUS_NOT_SUPPORTED ;
}
2012-10-19 12:54:27 +04:00
/* Ensure any pending write time updates are done. */
if ( fsp - > update_write_time_event ) {
2018-05-23 10:41:29 +03:00
fsp_flush_write_time_update ( fsp ) ;
2012-10-19 12:54:27 +04:00
}
2012-06-08 19:54:19 +04:00
/*
* The above checks are done in mark_share_mode_disconnected ( ) too
* but we want to avoid getting the lock if possible
*/
lck = get_existing_share_mode_lock ( talloc_tos ( ) , fsp - > file_id ) ;
if ( lck ! = NULL ) {
2012-10-19 12:58:47 +04:00
struct smb_file_time ft ;
2019-12-02 18:30:50 +03:00
init_smb_file_time ( & ft ) ;
2012-10-19 12:58:47 +04:00
if ( fsp - > write_time_forced ) {
2019-12-02 18:30:50 +03:00
ft . mtime = nt_time_to_full_timespec (
lck - > data - > changed_write_time ) ;
2012-10-19 12:58:47 +04:00
} else if ( fsp - > update_write_time_on_close ) {
2019-12-02 18:30:50 +03:00
if ( is_omit_timespec ( & fsp - > close_write_time ) ) {
2012-10-19 12:58:47 +04:00
ft . mtime = timespec_current ( ) ;
} else {
ft . mtime = fsp - > close_write_time ;
}
}
2019-12-02 18:30:50 +03:00
if ( ! is_omit_timespec ( & ft . mtime ) ) {
2012-10-19 12:58:47 +04:00
round_timespec ( conn - > ts_res , & ft . mtime ) ;
file_ntimes ( conn , fsp - > fsp_name , & ft ) ;
}
2012-06-08 19:54:19 +04:00
ok = mark_share_mode_disconnected ( lck , fsp ) ;
if ( ! ok ) {
TALLOC_FREE ( lck ) ;
}
}
if ( lck ! = NULL ) {
ok = brl_mark_disconnected ( fsp ) ;
if ( ! ok ) {
TALLOC_FREE ( lck ) ;
}
}
if ( lck = = NULL ) {
return NT_STATUS_NOT_SUPPORTED ;
}
TALLOC_FREE ( lck ) ;
2012-10-19 18:00:05 +04:00
status = vfs_stat_fsp ( fsp ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2012-06-08 19:54:19 +04:00
ZERO_STRUCT ( cookie ) ;
cookie . allow_reconnect = true ;
cookie . id = fsp - > file_id ;
cookie . servicepath = conn - > connectpath ;
cookie . base_name = fsp - > fsp_name - > base_name ;
cookie . initial_allocation_size = fsp - > initial_allocation_size ;
cookie . position_information = fsp - > fh - > position_information ;
2012-10-19 13:12:05 +04:00
cookie . update_write_time_triggered = fsp - > update_write_time_triggered ;
cookie . update_write_time_on_close = fsp - > update_write_time_on_close ;
cookie . write_time_forced = fsp - > write_time_forced ;
2019-12-02 18:30:50 +03:00
cookie . close_write_time = full_timespec_to_nt_time (
& fsp - > close_write_time ) ;
2012-06-08 19:54:19 +04:00
2012-10-19 18:00:05 +04:00
cookie . stat_info . st_ex_dev = fsp - > fsp_name - > st . st_ex_dev ;
cookie . stat_info . st_ex_ino = fsp - > fsp_name - > st . st_ex_ino ;
cookie . stat_info . st_ex_mode = fsp - > fsp_name - > st . st_ex_mode ;
cookie . stat_info . st_ex_nlink = fsp - > fsp_name - > st . st_ex_nlink ;
cookie . stat_info . st_ex_uid = fsp - > fsp_name - > st . st_ex_uid ;
cookie . stat_info . st_ex_gid = fsp - > fsp_name - > st . st_ex_gid ;
cookie . stat_info . st_ex_rdev = fsp - > fsp_name - > st . st_ex_rdev ;
cookie . stat_info . st_ex_size = fsp - > fsp_name - > st . st_ex_size ;
cookie . stat_info . st_ex_atime = fsp - > fsp_name - > st . st_ex_atime ;
cookie . stat_info . st_ex_mtime = fsp - > fsp_name - > st . st_ex_mtime ;
cookie . stat_info . st_ex_ctime = fsp - > fsp_name - > st . st_ex_ctime ;
cookie . stat_info . st_ex_btime = fsp - > fsp_name - > st . st_ex_btime ;
2019-06-27 18:06:46 +03:00
cookie . stat_info . st_ex_iflags = fsp - > fsp_name - > st . st_ex_iflags ;
2012-10-19 18:00:05 +04:00
cookie . stat_info . st_ex_blksize = fsp - > fsp_name - > st . st_ex_blksize ;
cookie . stat_info . st_ex_blocks = fsp - > fsp_name - > st . st_ex_blocks ;
cookie . stat_info . st_ex_flags = fsp - > fsp_name - > st . st_ex_flags ;
2012-06-08 19:54:19 +04:00
ndr_err = ndr_push_struct_blob ( & new_cookie_blob , mem_ctx , & cookie ,
( ndr_push_flags_fn_t ) ndr_push_vfs_default_durable_cookie ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
status = ndr_map_error2ntstatus ( ndr_err ) ;
return status ;
}
status = fd_close ( fsp ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
data_blob_free ( & new_cookie_blob ) ;
return status ;
}
* new_cookie = new_cookie_blob ;
return NT_STATUS_OK ;
}
2012-10-23 15:00:02 +04:00
/**
* Check whether a cookie - stored struct info is the same
* as a given SMB_STRUCT_STAT , as coming with the fsp .
*/
static bool vfs_default_durable_reconnect_check_stat (
struct vfs_default_durable_stat * cookie_st ,
SMB_STRUCT_STAT * fsp_st ,
const char * name )
{
int ret ;
if ( cookie_st - > st_ex_mode ! = fsp_st - > st_ex_mode ) {
DEBUG ( 1 , ( " vfs_default_durable_reconnect (%s): "
" stat_ex.%s differs: "
" cookie:%llu != stat:%llu, "
" denying durable reconnect \n " ,
name ,
" st_ex_mode " ,
( unsigned long long ) cookie_st - > st_ex_mode ,
( unsigned long long ) fsp_st - > st_ex_mode ) ) ;
return false ;
}
if ( cookie_st - > st_ex_nlink ! = fsp_st - > st_ex_nlink ) {
DEBUG ( 1 , ( " vfs_default_durable_reconnect (%s): "
" stat_ex.%s differs: "
" cookie:%llu != stat:%llu, "
" denying durable reconnect \n " ,
name ,
" st_ex_nlink " ,
( unsigned long long ) cookie_st - > st_ex_nlink ,
( unsigned long long ) fsp_st - > st_ex_nlink ) ) ;
return false ;
}
if ( cookie_st - > st_ex_uid ! = fsp_st - > st_ex_uid ) {
DEBUG ( 1 , ( " vfs_default_durable_reconnect (%s): "
" stat_ex.%s differs: "
" cookie:%llu != stat:%llu, "
" denying durable reconnect \n " ,
name ,
" st_ex_uid " ,
( unsigned long long ) cookie_st - > st_ex_uid ,
( unsigned long long ) fsp_st - > st_ex_uid ) ) ;
return false ;
}
if ( cookie_st - > st_ex_gid ! = fsp_st - > st_ex_gid ) {
DEBUG ( 1 , ( " vfs_default_durable_reconnect (%s): "
" stat_ex.%s differs: "
" cookie:%llu != stat:%llu, "
" denying durable reconnect \n " ,
name ,
" st_ex_gid " ,
( unsigned long long ) cookie_st - > st_ex_gid ,
( unsigned long long ) fsp_st - > st_ex_gid ) ) ;
return false ;
}
if ( cookie_st - > st_ex_rdev ! = fsp_st - > st_ex_rdev ) {
DEBUG ( 1 , ( " vfs_default_durable_reconnect (%s): "
" stat_ex.%s differs: "
" cookie:%llu != stat:%llu, "
" denying durable reconnect \n " ,
name ,
" st_ex_rdev " ,
( unsigned long long ) cookie_st - > st_ex_rdev ,
( unsigned long long ) fsp_st - > st_ex_rdev ) ) ;
return false ;
}
if ( cookie_st - > st_ex_size ! = fsp_st - > st_ex_size ) {
DEBUG ( 1 , ( " vfs_default_durable_reconnect (%s): "
" stat_ex.%s differs: "
" cookie:%llu != stat:%llu, "
" denying durable reconnect \n " ,
name ,
" st_ex_size " ,
( unsigned long long ) cookie_st - > st_ex_size ,
( unsigned long long ) fsp_st - > st_ex_size ) ) ;
return false ;
}
ret = timespec_compare ( & cookie_st - > st_ex_atime ,
& fsp_st - > st_ex_atime ) ;
if ( ret ! = 0 ) {
struct timeval tc , ts ;
tc = convert_timespec_to_timeval ( cookie_st - > st_ex_atime ) ;
ts = convert_timespec_to_timeval ( fsp_st - > st_ex_atime ) ;
DEBUG ( 1 , ( " vfs_default_durable_reconnect (%s): "
" stat_ex.%s differs: "
" cookie:'%s' != stat:'%s', "
" denying durable reconnect \n " ,
name ,
" st_ex_atime " ,
timeval_string ( talloc_tos ( ) , & tc , true ) ,
timeval_string ( talloc_tos ( ) , & ts , true ) ) ) ;
return false ;
}
ret = timespec_compare ( & cookie_st - > st_ex_mtime ,
& fsp_st - > st_ex_mtime ) ;
if ( ret ! = 0 ) {
struct timeval tc , ts ;
tc = convert_timespec_to_timeval ( cookie_st - > st_ex_mtime ) ;
ts = convert_timespec_to_timeval ( fsp_st - > st_ex_mtime ) ;
DEBUG ( 1 , ( " vfs_default_durable_reconnect (%s): "
" stat_ex.%s differs: "
" cookie:'%s' != stat:'%s', "
" denying durable reconnect \n " ,
name ,
" st_ex_mtime " ,
timeval_string ( talloc_tos ( ) , & tc , true ) ,
timeval_string ( talloc_tos ( ) , & ts , true ) ) ) ;
return false ;
}
ret = timespec_compare ( & cookie_st - > st_ex_ctime ,
& fsp_st - > st_ex_ctime ) ;
if ( ret ! = 0 ) {
struct timeval tc , ts ;
tc = convert_timespec_to_timeval ( cookie_st - > st_ex_ctime ) ;
ts = convert_timespec_to_timeval ( fsp_st - > st_ex_ctime ) ;
DEBUG ( 1 , ( " vfs_default_durable_reconnect (%s): "
" stat_ex.%s differs: "
" cookie:'%s' != stat:'%s', "
" denying durable reconnect \n " ,
name ,
" st_ex_ctime " ,
timeval_string ( talloc_tos ( ) , & tc , true ) ,
timeval_string ( talloc_tos ( ) , & ts , true ) ) ) ;
return false ;
}
ret = timespec_compare ( & cookie_st - > st_ex_btime ,
& fsp_st - > st_ex_btime ) ;
if ( ret ! = 0 ) {
struct timeval tc , ts ;
tc = convert_timespec_to_timeval ( cookie_st - > st_ex_btime ) ;
ts = convert_timespec_to_timeval ( fsp_st - > st_ex_btime ) ;
DEBUG ( 1 , ( " vfs_default_durable_reconnect (%s): "
" stat_ex.%s differs: "
" cookie:'%s' != stat:'%s', "
" denying durable reconnect \n " ,
name ,
" st_ex_btime " ,
timeval_string ( talloc_tos ( ) , & tc , true ) ,
timeval_string ( talloc_tos ( ) , & ts , true ) ) ) ;
return false ;
}
2019-06-27 18:06:46 +03:00
if ( cookie_st - > st_ex_iflags ! = fsp_st - > st_ex_iflags ) {
2012-10-23 15:00:02 +04:00
DEBUG ( 1 , ( " vfs_default_durable_reconnect (%s): "
" stat_ex.%s differs: "
" cookie:%llu != stat:%llu, "
" denying durable reconnect \n " ,
name ,
" st_ex_calculated_birthtime " ,
2019-06-27 18:06:46 +03:00
( unsigned long long ) cookie_st - > st_ex_iflags ,
( unsigned long long ) fsp_st - > st_ex_iflags ) ) ;
2012-10-23 15:00:02 +04:00
return false ;
}
if ( cookie_st - > st_ex_blksize ! = fsp_st - > st_ex_blksize ) {
DEBUG ( 1 , ( " vfs_default_durable_reconnect (%s): "
" stat_ex.%s differs: "
" cookie:%llu != stat:%llu, "
" denying durable reconnect \n " ,
name ,
" st_ex_blksize " ,
( unsigned long long ) cookie_st - > st_ex_blksize ,
( unsigned long long ) fsp_st - > st_ex_blksize ) ) ;
return false ;
}
if ( cookie_st - > st_ex_blocks ! = fsp_st - > st_ex_blocks ) {
DEBUG ( 1 , ( " vfs_default_durable_reconnect (%s): "
" stat_ex.%s differs: "
" cookie:%llu != stat:%llu, "
" denying durable reconnect \n " ,
name ,
" st_ex_blocks " ,
( unsigned long long ) cookie_st - > st_ex_blocks ,
( unsigned long long ) fsp_st - > st_ex_blocks ) ) ;
return false ;
}
if ( cookie_st - > st_ex_flags ! = fsp_st - > st_ex_flags ) {
DEBUG ( 1 , ( " vfs_default_durable_reconnect (%s): "
" stat_ex.%s differs: "
" cookie:%llu != stat:%llu, "
" denying durable reconnect \n " ,
name ,
" st_ex_flags " ,
( unsigned long long ) cookie_st - > st_ex_flags ,
( unsigned long long ) fsp_st - > st_ex_flags ) ) ;
return false ;
}
return true ;
}
2019-08-23 15:30:07 +03:00
static bool durable_reconnect_fn (
struct share_mode_entry * e ,
bool * modified ,
void * private_data )
{
struct share_mode_entry * dst_e = private_data ;
if ( dst_e - > pid . pid ! = 0 ) {
DBG_INFO ( " Found more than one entry, invalidating previous \n " ) ;
dst_e - > pid . pid = 0 ;
return true ; /* end the loop through share mode entries */
}
* dst_e = * e ;
return false ; /* Look at potential other entries */
}
2012-06-08 19:54:19 +04:00
NTSTATUS vfs_default_durable_reconnect ( struct connection_struct * conn ,
struct smb_request * smb1req ,
struct smbXsrv_open * op ,
const DATA_BLOB old_cookie ,
TALLOC_CTX * mem_ctx ,
files_struct * * result ,
DATA_BLOB * new_cookie )
{
2019-11-07 13:01:05 +03:00
const struct loadparm_substitution * lp_sub =
loadparm_s3_global_substitution ( ) ;
2012-06-08 19:54:19 +04:00
struct share_mode_lock * lck ;
2019-08-23 15:30:07 +03:00
struct share_mode_entry e ;
2012-06-08 19:54:19 +04:00
struct files_struct * fsp = NULL ;
NTSTATUS status ;
bool ok ;
int ret ;
2012-09-22 00:56:20 +04:00
int flags = 0 ;
2012-06-08 19:54:19 +04:00
struct file_id file_id ;
struct smb_filename * smb_fname = NULL ;
enum ndr_err_code ndr_err ;
struct vfs_default_durable_cookie cookie ;
DATA_BLOB new_cookie_blob = data_blob_null ;
* result = NULL ;
* new_cookie = data_blob_null ;
if ( ! lp_durable_handles ( SNUM ( conn ) ) ) {
return NT_STATUS_NOT_SUPPORTED ;
}
/*
* the checks for kernel oplocks
* and similar things are done
* in the vfs_default_durable_cookie ( )
* call below .
*/
2018-09-10 15:53:37 +03:00
ndr_err = ndr_pull_struct_blob_all (
& old_cookie ,
talloc_tos ( ) ,
& cookie ,
( ndr_pull_flags_fn_t ) ndr_pull_vfs_default_durable_cookie ) ;
2012-06-08 19:54:19 +04:00
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
status = ndr_map_error2ntstatus ( ndr_err ) ;
return status ;
}
if ( strcmp ( cookie . magic , VFS_DEFAULT_DURABLE_COOKIE_MAGIC ) ! = 0 ) {
return NT_STATUS_INVALID_PARAMETER ;
}
if ( cookie . version ! = VFS_DEFAULT_DURABLE_COOKIE_VERSION ) {
return NT_STATUS_INVALID_PARAMETER ;
}
if ( ! cookie . allow_reconnect ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
if ( strcmp ( cookie . servicepath , conn - > connectpath ) ! = 0 ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
/* Create an smb_filename with stream_name == NULL. */
2016-03-19 07:19:38 +03:00
smb_fname = synthetic_smb_fname ( talloc_tos ( ) ,
cookie . base_name ,
NULL ,
NULL ,
0 ) ;
2013-04-12 13:41:20 +04:00
if ( smb_fname = = NULL ) {
return NT_STATUS_NO_MEMORY ;
2012-06-08 19:54:19 +04:00
}
ret = SMB_VFS_LSTAT ( conn , smb_fname ) ;
if ( ret = = - 1 ) {
status = map_nt_error_from_unix_common ( errno ) ;
DEBUG ( 1 , ( " Unable to lstat stream: %s => %s \n " ,
smb_fname_str_dbg ( smb_fname ) ,
nt_errstr ( status ) ) ) ;
return status ;
}
if ( ! S_ISREG ( smb_fname - > st . st_ex_mode ) ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
file_id = vfs_file_id_from_sbuf ( conn , & smb_fname - > st ) ;
if ( ! file_id_equal ( & cookie . id , & file_id ) ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
/*
* 1. check entry in locking . tdb
*/
lck = get_existing_share_mode_lock ( mem_ctx , file_id ) ;
if ( lck = = NULL ) {
DEBUG ( 5 , ( " vfs_default_durable_reconnect: share-mode lock "
" not obtained from db \n " ) ) ;
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
2019-08-23 15:30:07 +03:00
e = ( struct share_mode_entry ) { . pid . pid = 0 } ;
ok = share_mode_forall_entries ( lck , durable_reconnect_fn , & e ) ;
if ( ! ok ) {
DBG_WARNING ( " share_mode_forall_entries failed \n " ) ;
2012-06-08 19:54:19 +04:00
TALLOC_FREE ( lck ) ;
return NT_STATUS_INTERNAL_DB_ERROR ;
}
2019-08-23 15:30:07 +03:00
if ( e . pid . pid = = 0 ) {
DBG_WARNING ( " Did not find a unique valid share mode entry \n " ) ;
2012-06-08 19:54:19 +04:00
TALLOC_FREE ( lck ) ;
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
2019-08-23 15:30:07 +03:00
if ( ! server_id_is_disconnected ( & e . pid ) ) {
2012-06-08 19:54:19 +04:00
DEBUG ( 5 , ( " vfs_default_durable_reconnect: denying durable "
" reconnect for handle that was not marked "
" disconnected (e.g. smbd or cluster node died) \n " ) ) ;
TALLOC_FREE ( lck ) ;
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
2019-08-23 15:30:07 +03:00
if ( e . share_file_id ! = op - > global - > open_persistent_id ) {
2019-09-05 10:52:10 +03:00
DBG_INFO ( " denying durable "
" share_file_id changed % " PRIu64 " != % " PRIu64 " "
" (e.g. another client had opened the file) \n " ,
2019-08-23 15:30:07 +03:00
e . share_file_id ,
2019-09-05 10:52:10 +03:00
op - > global - > open_persistent_id ) ;
2012-06-08 19:54:19 +04:00
TALLOC_FREE ( lck ) ;
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
2019-08-23 15:30:07 +03:00
if ( ( e . access_mask & ( FILE_WRITE_DATA | FILE_APPEND_DATA ) ) & &
2012-06-08 19:54:19 +04:00
! CAN_WRITE ( conn ) )
{
DEBUG ( 5 , ( " vfs_default_durable_reconnect: denying durable "
" share[%s] is not writeable anymore \n " ,
2019-11-07 13:01:05 +03:00
lp_servicename ( talloc_tos ( ) , lp_sub , SNUM ( conn ) ) ) ) ;
2012-06-08 19:54:19 +04:00
TALLOC_FREE ( lck ) ;
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
/*
* 2. proceed with opening file
*/
status = fsp_new ( conn , conn , & fsp ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " vfs_default_durable_reconnect: failed to create "
" new fsp: %s \n " , nt_errstr ( status ) ) ) ;
TALLOC_FREE ( lck ) ;
return status ;
}
2019-08-23 15:30:07 +03:00
fsp - > fh - > private_options = e . private_options ;
2012-06-08 19:54:19 +04:00
fsp - > file_id = file_id ;
fsp - > file_pid = smb1req - > smbpid ;
fsp - > vuid = smb1req - > vuid ;
2019-08-23 15:30:07 +03:00
fsp - > open_time = e . time ;
fsp - > access_mask = e . access_mask ;
2012-06-08 19:54:19 +04:00
fsp - > can_read = ( ( fsp - > access_mask & ( FILE_READ_DATA ) ) ! = 0 ) ;
fsp - > can_write = ( ( fsp - > access_mask & ( FILE_WRITE_DATA | FILE_APPEND_DATA ) ) ! = 0 ) ;
2014-01-24 03:09:50 +04:00
fsp - > fnum = op - > local_id ;
2019-09-16 13:54:32 +03:00
fsp_set_gen_id ( fsp ) ;
2012-06-08 19:54:19 +04:00
/*
* TODO :
* Do we need to store the modified flag in the DB ?
*/
fsp - > modified = false ;
/*
* no durables for directories
*/
fsp - > is_directory = false ;
/*
* For normal files , can_lock = = ! is_directory
*/
fsp - > can_lock = true ;
/*
* We do not support aio write behind for smb2
*/
fsp - > aio_write_behind = false ;
2019-08-23 15:30:07 +03:00
fsp - > oplock_type = e . op_type ;
2012-06-08 19:54:19 +04:00
2014-10-29 01:31:46 +03:00
if ( fsp - > oplock_type = = LEASE_OPLOCK ) {
2018-09-19 14:37:23 +03:00
uint32_t current_state ;
uint16_t lease_version , epoch ;
2014-10-29 01:31:46 +03:00
/*
* Ensure the existing client guid matches the
2019-04-10 22:34:24 +03:00
* stored one in the share_mode_entry .
2014-10-29 01:31:46 +03:00
*/
if ( ! GUID_equal ( fsp_client_guid ( fsp ) ,
2019-08-23 15:30:07 +03:00
& e . client_guid ) ) {
2014-10-29 01:31:46 +03:00
TALLOC_FREE ( lck ) ;
fsp_free ( fsp ) ;
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
2018-09-19 14:37:23 +03:00
status = leases_db_get (
2019-08-23 15:30:07 +03:00
& e . client_guid ,
& e . lease_key ,
2018-09-19 14:37:23 +03:00
& file_id ,
& current_state , /* current_state */
NULL , /* breaking */
NULL , /* breaking_to_requested */
NULL , /* breaking_to_required */
& lease_version , /* lease_version */
& epoch ) ; /* epoch */
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( lck ) ;
fsp_free ( fsp ) ;
return status ;
}
fsp - > lease = find_fsp_lease (
fsp ,
2019-08-23 15:30:07 +03:00
& e . lease_key ,
2018-09-19 14:37:23 +03:00
current_state ,
lease_version ,
epoch ) ;
if ( fsp - > lease = = NULL ) {
TALLOC_FREE ( lck ) ;
fsp_free ( fsp ) ;
return NT_STATUS_NO_MEMORY ;
}
2014-10-29 01:31:46 +03:00
}
2012-06-08 19:54:19 +04:00
fsp - > initial_allocation_size = cookie . initial_allocation_size ;
fsp - > fh - > position_information = cookie . position_information ;
2012-10-19 13:12:05 +04:00
fsp - > update_write_time_triggered = cookie . update_write_time_triggered ;
fsp - > update_write_time_on_close = cookie . update_write_time_on_close ;
fsp - > write_time_forced = cookie . write_time_forced ;
2019-12-02 18:30:50 +03:00
fsp - > close_write_time = nt_time_to_full_timespec (
cookie . close_write_time ) ;
2012-06-08 19:54:19 +04:00
status = fsp_set_smb_fname ( fsp , smb_fname ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( lck ) ;
fsp_free ( fsp ) ;
DEBUG ( 0 , ( " vfs_default_durable_reconnect: "
" fsp_set_smb_fname failed: %s \n " ,
nt_errstr ( status ) ) ) ;
return status ;
}
op - > compat = fsp ;
fsp - > op = op ;
2019-08-23 15:30:07 +03:00
ok = reset_share_mode_entry (
lck ,
e . pid ,
e . share_file_id ,
messaging_server_id ( conn - > sconn - > msg_ctx ) ,
smb1req - > mid ,
fsp - > fh - > gen_id ) ;
if ( ! ok ) {
DBG_DEBUG ( " Could not set new share_mode_entry values \n " ) ;
TALLOC_FREE ( lck ) ;
op - > compat = NULL ;
fsp_free ( fsp ) ;
return NT_STATUS_INTERNAL_ERROR ;
}
2012-06-08 19:54:19 +04:00
ok = brl_reconnect_disconnected ( fsp ) ;
if ( ! ok ) {
status = NT_STATUS_INTERNAL_ERROR ;
DEBUG ( 1 , ( " vfs_default_durable_reconnect: "
" failed to reopen brlocks: %s \n " ,
nt_errstr ( status ) ) ) ;
TALLOC_FREE ( lck ) ;
op - > compat = NULL ;
fsp_free ( fsp ) ;
return status ;
}
/*
* TODO : properly calculate open flags
*/
if ( fsp - > can_write & & fsp - > can_read ) {
flags = O_RDWR ;
} else if ( fsp - > can_write ) {
flags = O_WRONLY ;
} else if ( fsp - > can_read ) {
flags = O_RDONLY ;
}
status = fd_open ( conn , fsp , flags , 0 /* mode */ ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( lck ) ;
DEBUG ( 1 , ( " vfs_default_durable_reconnect: failed to open "
" file: %s \n " , nt_errstr ( status ) ) ) ;
op - > compat = NULL ;
fsp_free ( fsp ) ;
return status ;
}
2012-10-19 18:00:05 +04:00
/*
* We now check the stat info stored in the cookie against
* the current stat data from the file we just opened .
* If any detail differs , we deny the durable reconnect ,
* because in that case it is very likely that someone
* opened the file while the handle was disconnected ,
* which has to be interpreted as an oplock break .
*/
2012-06-08 19:54:19 +04:00
ret = SMB_VFS_FSTAT ( fsp , & fsp - > fsp_name - > st ) ;
if ( ret = = - 1 ) {
status = map_nt_error_from_unix_common ( errno ) ;
DEBUG ( 1 , ( " Unable to fstat stream: %s => %s \n " ,
smb_fname_str_dbg ( smb_fname ) ,
nt_errstr ( status ) ) ) ;
ret = SMB_VFS_CLOSE ( fsp ) ;
if ( ret = = - 1 ) {
DEBUG ( 0 , ( " vfs_default_durable_reconnect: "
" SMB_VFS_CLOSE failed (%s) - leaking file "
" descriptor \n " , strerror ( errno ) ) ) ;
}
TALLOC_FREE ( lck ) ;
op - > compat = NULL ;
fsp_free ( fsp ) ;
return status ;
}
if ( ! S_ISREG ( fsp - > fsp_name - > st . st_ex_mode ) ) {
ret = SMB_VFS_CLOSE ( fsp ) ;
if ( ret = = - 1 ) {
DEBUG ( 0 , ( " vfs_default_durable_reconnect: "
" SMB_VFS_CLOSE failed (%s) - leaking file "
" descriptor \n " , strerror ( errno ) ) ) ;
}
TALLOC_FREE ( lck ) ;
op - > compat = NULL ;
fsp_free ( fsp ) ;
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
file_id = vfs_file_id_from_sbuf ( conn , & fsp - > fsp_name - > st ) ;
if ( ! file_id_equal ( & cookie . id , & file_id ) ) {
ret = SMB_VFS_CLOSE ( fsp ) ;
if ( ret = = - 1 ) {
DEBUG ( 0 , ( " vfs_default_durable_reconnect: "
" SMB_VFS_CLOSE failed (%s) - leaking file "
" descriptor \n " , strerror ( errno ) ) ) ;
}
TALLOC_FREE ( lck ) ;
op - > compat = NULL ;
fsp_free ( fsp ) ;
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
2019-09-09 09:08:06 +03:00
( void ) dos_mode ( fsp - > conn , fsp - > fsp_name ) ;
2012-10-23 15:00:02 +04:00
ok = vfs_default_durable_reconnect_check_stat ( & cookie . stat_info ,
& fsp - > fsp_name - > st ,
fsp_str_dbg ( fsp ) ) ;
if ( ! ok ) {
2012-10-19 18:00:05 +04:00
ret = SMB_VFS_CLOSE ( fsp ) ;
if ( ret = = - 1 ) {
DEBUG ( 0 , ( " vfs_default_durable_reconnect: "
" SMB_VFS_CLOSE failed (%s) - leaking file "
" descriptor \n " , strerror ( errno ) ) ) ;
}
TALLOC_FREE ( lck ) ;
op - > compat = NULL ;
fsp_free ( fsp ) ;
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
2013-09-03 17:57:11 +04:00
status = set_file_oplock ( fsp ) ;
2012-06-08 19:54:19 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " vfs_default_durable_reconnect failed to set oplock "
" after opening file: %s \n " , nt_errstr ( status ) ) ) ;
ret = SMB_VFS_CLOSE ( fsp ) ;
if ( ret = = - 1 ) {
DEBUG ( 0 , ( " vfs_default_durable_reconnect: "
" SMB_VFS_CLOSE failed (%s) - leaking file "
" descriptor \n " , strerror ( errno ) ) ) ;
}
TALLOC_FREE ( lck ) ;
op - > compat = NULL ;
fsp_free ( fsp ) ;
return status ;
}
status = vfs_default_durable_cookie ( fsp , mem_ctx , & new_cookie_blob ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( lck ) ;
DEBUG ( 1 , ( " vfs_default_durable_reconnect: "
" vfs_default_durable_cookie - %s \n " ,
nt_errstr ( status ) ) ) ;
op - > compat = NULL ;
fsp_free ( fsp ) ;
return status ;
}
smb1req - > chain_fsp = fsp ;
smb1req - > smb2req - > compat_chain_fsp = fsp ;
DEBUG ( 10 , ( " vfs_default_durable_reconnect: opened file '%s' \n " ,
fsp_str_dbg ( fsp ) ) ) ;
/*
* release the sharemode lock : this writes the changes
*/
lck - > data - > modified = true ;
TALLOC_FREE ( lck ) ;
* result = fsp ;
* new_cookie = new_cookie_blob ;
return NT_STATUS_OK ;
}