2009-06-02 14:06:34 +04:00
/*
Unix SMB / CIFS implementation .
Core SMB2 server
Copyright ( C ) Stefan Metzmacher 2009
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"
2011-03-22 18:57:01 +03:00
# include "smbd/smbd.h"
2009-06-02 14:06:34 +04:00
# include "smbd/globals.h"
2009-08-12 19:52:55 +04:00
# include "../libcli/smb/smb_common.h"
2011-04-28 19:38:09 +04:00
# include "../lib/util/tevent_ntstatus.h"
2018-05-10 20:26:52 +03:00
# include "libcli/security/security.h"
2009-06-02 14:06:34 +04:00
2018-03-21 22:01:05 +03:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_SMB2
2009-06-05 23:38:10 +04:00
static struct tevent_req * smbd_smb2_flush_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct smbd_smb2_request * smb2req ,
2012-06-08 12:14:45 +04:00
struct files_struct * fsp ) ;
2009-06-05 23:38:10 +04:00
static NTSTATUS smbd_smb2_flush_recv ( struct tevent_req * req ) ;
2009-06-02 14:06:34 +04:00
2009-06-05 23:38:10 +04:00
static void smbd_smb2_request_flush_done ( struct tevent_req * subreq ) ;
2009-06-02 14:06:34 +04:00
NTSTATUS smbd_smb2_request_process_flush ( struct smbd_smb2_request * req )
{
2011-09-06 16:01:43 +04:00
NTSTATUS status ;
2009-06-02 14:06:34 +04:00
const uint8_t * inbody ;
uint64_t in_file_id_persistent ;
uint64_t in_file_id_volatile ;
2012-06-08 12:14:45 +04:00
struct files_struct * in_fsp ;
2009-06-05 23:38:10 +04:00
struct tevent_req * subreq ;
2009-06-02 14:06:34 +04:00
2011-09-06 16:01:43 +04:00
status = smbd_smb2_request_verify_sizes ( req , 0x18 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return smbd_smb2_request_error ( req , status ) ;
2009-06-02 14:06:34 +04:00
}
2012-08-05 16:55:58 +04:00
inbody = SMBD_SMB2_IN_BODY_PTR ( req ) ;
2009-06-02 14:06:34 +04:00
in_file_id_persistent = BVAL ( inbody , 0x08 ) ;
in_file_id_volatile = BVAL ( inbody , 0x10 ) ;
2012-06-08 12:14:45 +04:00
in_fsp = file_fsp_smb2 ( req , in_file_id_persistent , in_file_id_volatile ) ;
if ( in_fsp = = NULL ) {
2009-06-02 14:06:34 +04:00
return smbd_smb2_request_error ( req , NT_STATUS_FILE_CLOSED ) ;
}
2018-03-22 12:54:41 +03:00
subreq = smbd_smb2_flush_send ( req , req - > ev_ctx ,
2012-06-08 12:14:45 +04:00
req , in_fsp ) ;
2009-06-05 23:38:10 +04:00
if ( subreq = = NULL ) {
return smbd_smb2_request_error ( req , NT_STATUS_NO_MEMORY ) ;
}
tevent_req_set_callback ( subreq , smbd_smb2_request_flush_done , req ) ;
2009-06-10 00:34:14 +04:00
2011-11-14 18:42:55 +04:00
return smbd_smb2_request_pending_queue ( req , subreq , 500 ) ;
2009-06-05 23:38:10 +04:00
}
static void smbd_smb2_request_flush_done ( struct tevent_req * subreq )
{
struct smbd_smb2_request * req = tevent_req_callback_data ( subreq ,
struct smbd_smb2_request ) ;
DATA_BLOB outbody ;
NTSTATUS status ;
NTSTATUS error ; /* transport error */
status = smbd_smb2_flush_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
2009-06-02 14:06:34 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-06-05 23:38:10 +04:00
error = smbd_smb2_request_error ( req , status ) ;
if ( ! NT_STATUS_IS_OK ( error ) ) {
2014-06-11 14:15:48 +04:00
smbd_server_connection_terminate ( req - > xconn ,
2009-06-05 23:38:10 +04:00
nt_errstr ( error ) ) ;
return ;
}
return ;
2009-06-02 14:06:34 +04:00
}
2013-12-04 17:59:07 +04:00
outbody = smbd_smb2_generate_outbody ( req , 0x04 ) ;
2009-06-02 14:06:34 +04:00
if ( outbody . data = = NULL ) {
2009-06-05 23:38:10 +04:00
error = smbd_smb2_request_error ( req , NT_STATUS_NO_MEMORY ) ;
if ( ! NT_STATUS_IS_OK ( error ) ) {
2014-06-11 14:15:48 +04:00
smbd_server_connection_terminate ( req - > xconn ,
2009-06-05 23:38:10 +04:00
nt_errstr ( error ) ) ;
return ;
}
return ;
2009-06-02 14:06:34 +04:00
}
SSVAL ( outbody . data , 0x00 , 0x04 ) ; /* struct size */
SSVAL ( outbody . data , 0x02 , 0 ) ; /* reserved */
2009-06-05 23:38:10 +04:00
error = smbd_smb2_request_done ( req , outbody , NULL ) ;
if ( ! NT_STATUS_IS_OK ( error ) ) {
2014-06-11 14:15:48 +04:00
smbd_server_connection_terminate ( req - > xconn ,
2009-06-05 23:38:10 +04:00
nt_errstr ( error ) ) ;
return ;
}
2009-06-02 14:06:34 +04:00
}
2009-06-05 23:38:10 +04:00
struct smbd_smb2_flush_state {
struct smbd_smb2_request * smb2req ;
} ;
2015-11-11 23:31:15 +03:00
static void smbd_smb2_flush_done ( struct tevent_req * subreq ) ;
2009-06-05 23:38:10 +04:00
static struct tevent_req * smbd_smb2_flush_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct smbd_smb2_request * smb2req ,
2012-06-08 12:14:45 +04:00
struct files_struct * fsp )
2009-06-02 14:06:34 +04:00
{
2009-06-05 23:38:10 +04:00
struct tevent_req * req ;
2015-11-11 23:31:15 +03:00
struct tevent_req * subreq ;
2009-06-05 23:38:10 +04:00
struct smbd_smb2_flush_state * state ;
2009-06-02 14:06:34 +04:00
struct smb_request * smbreq ;
2015-11-11 23:31:15 +03:00
int ret ;
2009-06-02 14:06:34 +04:00
2009-06-05 23:38:10 +04:00
req = tevent_req_create ( mem_ctx , & state ,
struct smbd_smb2_flush_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > smb2req = smb2req ;
2012-06-14 15:16:44 +04:00
DEBUG ( 10 , ( " smbd_smb2_flush: %s - %s \n " ,
fsp_str_dbg ( fsp ) , fsp_fnum_dbg ( fsp ) ) ) ;
2009-06-02 14:06:34 +04:00
2009-06-05 23:38:10 +04:00
smbreq = smbd_smb2_fake_smb_request ( smb2req ) ;
if ( tevent_req_nomem ( smbreq , req ) ) {
return tevent_req_post ( req , ev ) ;
2009-06-02 14:06:34 +04:00
}
2009-06-05 23:38:10 +04:00
if ( IS_IPC ( smbreq - > conn ) ) {
tevent_req_nterror ( req , NT_STATUS_NOT_IMPLEMENTED ) ;
return tevent_req_post ( req , ev ) ;
2009-06-02 14:06:34 +04:00
}
if ( ! CHECK_WRITE ( fsp ) ) {
2018-05-10 20:26:52 +03:00
bool allow_dir_flush = false ;
uint32_t flush_access = FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY ;
if ( ! fsp - > is_directory ) {
tevent_req_nterror ( req , NT_STATUS_ACCESS_DENIED ) ;
return tevent_req_post ( req , ev ) ;
}
/*
* Directories are not writable in the conventional
* sense , but if opened with * either *
* FILE_ADD_FILE or FILE_ADD_SUBDIRECTORY
* they can be flushed .
*/
if ( ( fsp - > access_mask & flush_access ) ! = 0 ) {
allow_dir_flush = true ;
}
if ( allow_dir_flush = = false ) {
tevent_req_nterror ( req , NT_STATUS_ACCESS_DENIED ) ;
return tevent_req_post ( req , ev ) ;
}
2009-06-02 14:06:34 +04:00
}
2015-11-11 23:31:15 +03:00
if ( fsp - > fh - > fd = = - 1 ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_HANDLE ) ;
return tevent_req_post ( req , ev ) ;
}
if ( ! lp_strict_sync ( SNUM ( smbreq - > conn ) ) ) {
/*
* No strict sync . Don ' t really do
* anything here .
*/
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
}
ret = flush_write_cache ( fsp , SAMBA_SYNC_FLUSH ) ;
if ( ret = = - 1 ) {
tevent_req_nterror ( req , map_nt_error_from_unix ( errno ) ) ;
return tevent_req_post ( req , ev ) ;
}
subreq = SMB_VFS_FSYNC_SEND ( state , ev , fsp ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , smbd_smb2_flush_done , req ) ;
/* Ensure any close request knows about this outstanding IO. */
if ( ! aio_add_req_to_fsp ( fsp , req ) ) {
tevent_req_nterror ( req , NT_STATUS_NO_MEMORY ) ;
2009-06-05 23:38:10 +04:00
return tevent_req_post ( req , ev ) ;
}
2015-11-11 23:31:15 +03:00
return req ;
}
static void smbd_smb2_flush_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
2016-02-26 12:54:01 +03:00
int ret ;
struct vfs_aio_state vfs_aio_state ;
2015-11-11 23:31:15 +03:00
2016-02-26 12:54:01 +03:00
ret = SMB_VFS_FSYNC_RECV ( subreq , & vfs_aio_state ) ;
2015-11-11 23:31:15 +03:00
TALLOC_FREE ( subreq ) ;
if ( ret = = - 1 ) {
2018-03-15 14:38:41 +03:00
tevent_req_nterror ( req , map_nt_error_from_unix ( vfs_aio_state . error ) ) ;
2015-11-11 23:31:15 +03:00
return ;
}
2009-06-05 23:38:10 +04:00
tevent_req_done ( req ) ;
}
static NTSTATUS smbd_smb2_flush_recv ( struct tevent_req * req )
{
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
tevent_req_received ( req ) ;
2009-06-02 14:06:34 +04:00
return status ;
}
2009-06-05 23:38:10 +04:00
tevent_req_received ( req ) ;
2009-06-02 14:06:34 +04:00
return NT_STATUS_OK ;
}