2009-05-28 02:07:26 +04:00
/*
Unix SMB / CIFS implementation .
Core SMB2 server
Copyright ( C ) Stefan Metzmacher 2009
2010-04-29 01:56:12 +04:00
Copyright ( C ) Jeremy Allison 2010
2009-05-28 02:07:26 +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"
2010-05-04 12:28:48 +04:00
# include "printing.h"
2011-03-22 18:57:01 +03:00
# include "smbd/smbd.h"
2009-05-28 02:07:26 +04:00
# include "smbd/globals.h"
2009-08-12 19:52:55 +04:00
# include "../libcli/smb/smb_common.h"
2010-05-28 04:19:32 +04:00
# include "../librpc/gen_ndr/ndr_security.h"
2011-04-28 19:38:09 +04:00
# include "../lib/util/tevent_ntstatus.h"
2011-12-15 14:51:20 +04:00
# include "messages.h"
2009-05-28 02:07:26 +04:00
2010-04-24 11:29:41 +04:00
int map_smb2_oplock_levels_to_samba ( uint8_t in_oplock_level )
{
switch ( in_oplock_level ) {
case SMB2_OPLOCK_LEVEL_NONE :
return NO_OPLOCK ;
case SMB2_OPLOCK_LEVEL_II :
return LEVEL_II_OPLOCK ;
case SMB2_OPLOCK_LEVEL_EXCLUSIVE :
return EXCLUSIVE_OPLOCK ;
case SMB2_OPLOCK_LEVEL_BATCH :
return BATCH_OPLOCK ;
case SMB2_OPLOCK_LEVEL_LEASE :
DEBUG ( 2 , ( " map_smb2_oplock_levels_to_samba: "
" LEASE_OPLOCK_REQUESTED \n " ) ) ;
return NO_OPLOCK ;
default :
DEBUG ( 2 , ( " map_smb2_oplock_levels_to_samba: "
" unknown level %u \n " ,
( unsigned int ) in_oplock_level ) ) ;
return NO_OPLOCK ;
}
}
2010-05-11 01:23:44 +04:00
static uint8_t map_samba_oplock_levels_to_smb2 ( int oplock_type )
2010-04-24 11:29:41 +04:00
{
if ( BATCH_OPLOCK_TYPE ( oplock_type ) ) {
return SMB2_OPLOCK_LEVEL_BATCH ;
} else if ( EXCLUSIVE_OPLOCK_TYPE ( oplock_type ) ) {
return SMB2_OPLOCK_LEVEL_EXCLUSIVE ;
2010-05-12 01:00:38 +04:00
} else if ( oplock_type = = LEVEL_II_OPLOCK ) {
/*
* Don ' t use LEVEL_II_OPLOCK_TYPE here as
* this also includes FAKE_LEVEL_II_OPLOCKs
* which are internal only .
*/
2010-04-24 11:29:41 +04:00
return SMB2_OPLOCK_LEVEL_II ;
} else {
return SMB2_OPLOCK_LEVEL_NONE ;
}
}
2009-06-05 23:06:27 +04:00
static struct tevent_req * smbd_smb2_create_send ( TALLOC_CTX * mem_ctx ,
2009-08-12 22:39:58 +04:00
struct tevent_context * ev ,
struct smbd_smb2_request * smb2req ,
uint8_t in_oplock_level ,
uint32_t in_impersonation_level ,
uint32_t in_desired_access ,
uint32_t in_file_attributes ,
uint32_t in_share_access ,
uint32_t in_create_disposition ,
uint32_t in_create_options ,
const char * in_name ,
struct smb2_create_blobs in_context_blobs ) ;
2010-04-23 21:53:44 +04:00
static NTSTATUS smbd_smb2_create_recv ( struct tevent_req * req ,
2009-08-12 22:39:58 +04:00
TALLOC_CTX * mem_ctx ,
uint8_t * out_oplock_level ,
uint32_t * out_create_action ,
NTTIME * out_creation_time ,
NTTIME * out_last_access_time ,
NTTIME * out_last_write_time ,
NTTIME * out_change_time ,
uint64_t * out_allocation_size ,
uint64_t * out_end_of_file ,
uint32_t * out_file_attributes ,
2010-05-20 06:28:26 +04:00
uint64_t * out_file_id_persistent ,
2009-08-12 22:39:58 +04:00
uint64_t * out_file_id_volatile ,
struct smb2_create_blobs * out_context_blobs ) ;
2009-06-05 23:06:27 +04:00
2010-04-23 21:29:48 +04:00
static void smbd_smb2_request_create_done ( struct tevent_req * tsubreq ) ;
NTSTATUS smbd_smb2_request_process_create ( struct smbd_smb2_request * smb2req )
2009-05-28 02:07:26 +04:00
{
const uint8_t * inbody ;
2012-04-24 14:58:23 +04:00
const struct iovec * indyniov ;
2009-05-28 02:07:26 +04:00
uint8_t in_oplock_level ;
uint32_t in_impersonation_level ;
uint32_t in_desired_access ;
uint32_t in_file_attributes ;
uint32_t in_share_access ;
uint32_t in_create_disposition ;
uint32_t in_create_options ;
uint16_t in_name_offset ;
uint16_t in_name_length ;
DATA_BLOB in_name_buffer ;
char * in_name_string ;
size_t in_name_string_size ;
2009-08-12 22:39:58 +04:00
uint32_t name_offset = 0 ;
uint32_t name_available_length = 0 ;
uint32_t in_context_offset ;
uint32_t in_context_length ;
DATA_BLOB in_context_buffer ;
struct smb2_create_blobs in_context_blobs ;
uint32_t context_offset = 0 ;
uint32_t context_available_length = 0 ;
uint32_t dyn_offset ;
NTSTATUS status ;
2009-05-28 02:07:26 +04:00
bool ok ;
2010-04-23 21:29:48 +04:00
struct tevent_req * tsubreq ;
2009-05-28 02:07:26 +04:00
2011-09-06 16:01:43 +04:00
status = smbd_smb2_request_verify_sizes ( smb2req , 0x39 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return smbd_smb2_request_error ( smb2req , status ) ;
2009-05-28 02:07:26 +04:00
}
2012-08-05 17:00:23 +04:00
inbody = SMBD_SMB2_IN_BODY_PTR ( smb2req ) ;
2009-05-28 02:07:26 +04:00
in_oplock_level = CVAL ( inbody , 0x03 ) ;
in_impersonation_level = IVAL ( inbody , 0x04 ) ;
in_desired_access = IVAL ( inbody , 0x18 ) ;
in_file_attributes = IVAL ( inbody , 0x1C ) ;
in_share_access = IVAL ( inbody , 0x20 ) ;
in_create_disposition = IVAL ( inbody , 0x24 ) ;
in_create_options = IVAL ( inbody , 0x28 ) ;
in_name_offset = SVAL ( inbody , 0x2C ) ;
in_name_length = SVAL ( inbody , 0x2E ) ;
2009-08-12 22:39:58 +04:00
in_context_offset = IVAL ( inbody , 0x30 ) ;
in_context_length = IVAL ( inbody , 0x34 ) ;
/*
* First check if the dynamic name and context buffers
* are correctly specified .
*
* Note : That we don ' t check if the name and context buffers
* overlap
*/
2012-08-05 17:00:23 +04:00
dyn_offset = SMB2_HDR_BODY + SMBD_SMB2_IN_BODY_LEN ( smb2req ) ;
2009-05-28 02:07:26 +04:00
2009-06-30 15:25:21 +04:00
if ( in_name_offset = = 0 & & in_name_length = = 0 ) {
/* This is ok */
2009-08-12 22:39:58 +04:00
name_offset = 0 ;
} else if ( in_name_offset < dyn_offset ) {
2010-04-23 21:29:48 +04:00
return smbd_smb2_request_error ( smb2req , NT_STATUS_INVALID_PARAMETER ) ;
2009-08-12 22:39:58 +04:00
} else {
name_offset = in_name_offset - dyn_offset ;
}
2012-08-05 17:00:23 +04:00
indyniov = SMBD_SMB2_IN_DYN_IOV ( smb2req ) ;
2012-04-24 14:58:23 +04:00
if ( name_offset > indyniov - > iov_len ) {
2010-04-23 21:29:48 +04:00
return smbd_smb2_request_error ( smb2req , NT_STATUS_INVALID_PARAMETER ) ;
2009-05-28 02:07:26 +04:00
}
2012-04-24 14:58:23 +04:00
name_available_length = indyniov - > iov_len - name_offset ;
2009-08-12 22:39:58 +04:00
if ( in_name_length > name_available_length ) {
2010-04-23 21:29:48 +04:00
return smbd_smb2_request_error ( smb2req , NT_STATUS_INVALID_PARAMETER ) ;
2009-05-28 02:07:26 +04:00
}
2012-04-24 14:58:23 +04:00
in_name_buffer . data = ( uint8_t * ) indyniov - > iov_base + name_offset ;
2009-05-28 02:07:26 +04:00
in_name_buffer . length = in_name_length ;
2009-08-12 22:39:58 +04:00
if ( in_context_offset = = 0 & & in_context_length = = 0 ) {
/* This is ok */
context_offset = 0 ;
} else if ( in_context_offset < dyn_offset ) {
2010-04-23 21:29:48 +04:00
return smbd_smb2_request_error ( smb2req , NT_STATUS_INVALID_PARAMETER ) ;
2009-08-12 22:39:58 +04:00
} else {
context_offset = in_context_offset - dyn_offset ;
}
2012-04-24 14:58:23 +04:00
if ( context_offset > indyniov - > iov_len ) {
2010-04-23 21:29:48 +04:00
return smbd_smb2_request_error ( smb2req , NT_STATUS_INVALID_PARAMETER ) ;
2009-08-12 22:39:58 +04:00
}
2012-04-24 14:58:23 +04:00
context_available_length = indyniov - > iov_len - context_offset ;
2009-08-12 22:39:58 +04:00
if ( in_context_length > context_available_length ) {
2010-04-23 21:29:48 +04:00
return smbd_smb2_request_error ( smb2req , NT_STATUS_INVALID_PARAMETER ) ;
2009-08-12 22:39:58 +04:00
}
2012-04-24 14:58:23 +04:00
in_context_buffer . data = ( uint8_t * ) indyniov - > iov_base +
context_offset ;
2009-08-12 22:39:58 +04:00
in_context_buffer . length = in_context_length ;
/*
* Now interpret the name and context buffers
*/
2010-04-23 21:29:48 +04:00
ok = convert_string_talloc ( smb2req , CH_UTF16 , CH_UNIX ,
2009-05-28 02:07:26 +04:00
in_name_buffer . data ,
in_name_buffer . length ,
& in_name_string ,
2011-03-24 02:59:41 +03:00
& in_name_string_size ) ;
2009-05-28 02:07:26 +04:00
if ( ! ok ) {
2010-04-23 21:29:48 +04:00
return smbd_smb2_request_error ( smb2req , NT_STATUS_ILLEGAL_CHARACTER ) ;
2009-05-28 02:07:26 +04:00
}
2011-09-06 16:14:52 +04:00
if ( in_name_buffer . length = = 0 ) {
in_name_string_size = 0 ;
}
if ( strlen ( in_name_string ) ! = in_name_string_size ) {
return smbd_smb2_request_error ( smb2req , NT_STATUS_OBJECT_NAME_INVALID ) ;
}
2009-08-12 22:39:58 +04:00
ZERO_STRUCT ( in_context_blobs ) ;
2010-04-23 21:29:48 +04:00
status = smb2_create_blob_parse ( smb2req , in_context_buffer , & in_context_blobs ) ;
2009-08-12 22:39:58 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-04-23 21:29:48 +04:00
return smbd_smb2_request_error ( smb2req , status ) ;
2009-08-12 22:39:58 +04:00
}
2010-04-23 21:29:48 +04:00
tsubreq = smbd_smb2_create_send ( smb2req ,
2011-12-12 17:15:03 +04:00
smb2req - > sconn - > ev_ctx ,
2010-04-23 21:29:48 +04:00
smb2req ,
2009-06-05 23:06:27 +04:00
in_oplock_level ,
in_impersonation_level ,
in_desired_access ,
in_file_attributes ,
in_share_access ,
in_create_disposition ,
in_create_options ,
2009-08-12 22:39:58 +04:00
in_name_string ,
in_context_blobs ) ;
2010-04-23 21:29:48 +04:00
if ( tsubreq = = NULL ) {
smb2req - > subreq = NULL ;
return smbd_smb2_request_error ( smb2req , NT_STATUS_NO_MEMORY ) ;
2009-06-05 23:06:27 +04:00
}
2010-04-23 21:29:48 +04:00
tevent_req_set_callback ( tsubreq , smbd_smb2_request_create_done , smb2req ) ;
2009-06-10 00:34:14 +04:00
2011-11-14 18:50:47 +04:00
/*
* For now we keep the logic that we do not send STATUS_PENDING
* for sharing violations , so we just wait 2 seconds .
*
* TODO : we need more tests for this .
*/
return smbd_smb2_request_pending_queue ( smb2req , tsubreq , 2000000 ) ;
2009-06-05 23:06:27 +04:00
}
2010-04-24 00:10:15 +04:00
static uint64_t get_mid_from_smb2req ( struct smbd_smb2_request * smb2req )
{
2012-08-05 17:00:23 +04:00
uint8_t * reqhdr = SMBD_SMB2_OUT_HDR_PTR ( smb2req ) ;
2010-04-24 00:10:15 +04:00
return BVAL ( reqhdr , SMB2_HDR_MESSAGE_ID ) ;
}
2010-04-23 21:29:48 +04:00
static void smbd_smb2_request_create_done ( struct tevent_req * tsubreq )
2009-06-05 23:06:27 +04:00
{
2010-04-23 21:29:48 +04:00
struct smbd_smb2_request * smb2req = tevent_req_callback_data ( tsubreq ,
2009-06-05 23:06:27 +04:00
struct smbd_smb2_request ) ;
DATA_BLOB outbody ;
DATA_BLOB outdyn ;
2009-07-24 18:21:07 +04:00
uint8_t out_oplock_level = 0 ;
uint32_t out_create_action = 0 ;
NTTIME out_creation_time = 0 ;
NTTIME out_last_access_time = 0 ;
NTTIME out_last_write_time = 0 ;
NTTIME out_change_time = 0 ;
uint64_t out_allocation_size = 0 ;
uint64_t out_end_of_file = 0 ;
uint32_t out_file_attributes = 0 ;
2010-05-20 06:28:26 +04:00
uint64_t out_file_id_persistent = 0 ;
2009-07-24 18:21:07 +04:00
uint64_t out_file_id_volatile = 0 ;
2009-08-12 22:39:58 +04:00
struct smb2_create_blobs out_context_blobs ;
DATA_BLOB out_context_buffer ;
uint16_t out_context_buffer_offset = 0 ;
2009-06-05 23:06:27 +04:00
NTSTATUS status ;
NTSTATUS error ; /* transport error */
2010-04-24 00:10:15 +04:00
if ( smb2req - > cancelled ) {
uint64_t mid = get_mid_from_smb2req ( smb2req ) ;
DEBUG ( 10 , ( " smbd_smb2_request_create_done: cancelled mid %llu \n " ,
( unsigned long long ) mid ) ) ;
error = smbd_smb2_request_error ( smb2req , NT_STATUS_CANCELLED ) ;
if ( ! NT_STATUS_IS_OK ( error ) ) {
smbd_server_connection_terminate ( smb2req - > sconn ,
nt_errstr ( error ) ) ;
return ;
}
return ;
}
2010-04-23 21:29:48 +04:00
status = smbd_smb2_create_recv ( tsubreq ,
smb2req ,
2009-06-05 23:06:27 +04:00
& out_oplock_level ,
& out_create_action ,
& out_creation_time ,
& out_last_access_time ,
& out_last_write_time ,
& out_change_time ,
& out_allocation_size ,
& out_end_of_file ,
& out_file_attributes ,
2010-05-20 06:28:26 +04:00
& out_file_id_persistent ,
2009-08-12 22:39:58 +04:00
& out_file_id_volatile ,
& out_context_blobs ) ;
2009-05-28 02:07:26 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-04-23 21:29:48 +04:00
error = smbd_smb2_request_error ( smb2req , status ) ;
2009-06-05 23:06:27 +04:00
if ( ! NT_STATUS_IS_OK ( error ) ) {
2010-04-23 21:29:48 +04:00
smbd_server_connection_terminate ( smb2req - > sconn ,
2009-06-05 23:06:27 +04:00
nt_errstr ( error ) ) ;
return ;
}
return ;
2009-05-28 02:07:26 +04:00
}
2010-04-23 21:29:48 +04:00
status = smb2_create_blob_push ( smb2req , & out_context_buffer , out_context_blobs ) ;
2009-08-12 22:39:58 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-04-23 21:29:48 +04:00
error = smbd_smb2_request_error ( smb2req , status ) ;
2009-08-12 22:39:58 +04:00
if ( ! NT_STATUS_IS_OK ( error ) ) {
2010-04-23 21:29:48 +04:00
smbd_server_connection_terminate ( smb2req - > sconn ,
2009-08-12 22:39:58 +04:00
nt_errstr ( error ) ) ;
return ;
}
return ;
}
if ( out_context_buffer . length > 0 ) {
out_context_buffer_offset = SMB2_HDR_BODY + 0x58 ;
}
2010-04-23 21:29:48 +04:00
outbody = data_blob_talloc ( smb2req - > out . vector , NULL , 0x58 ) ;
2009-05-28 02:07:26 +04:00
if ( outbody . data = = NULL ) {
2010-04-23 21:29:48 +04:00
error = smbd_smb2_request_error ( smb2req , NT_STATUS_NO_MEMORY ) ;
2009-06-05 23:06:27 +04:00
if ( ! NT_STATUS_IS_OK ( error ) ) {
2010-04-23 21:29:48 +04:00
smbd_server_connection_terminate ( smb2req - > sconn ,
2009-06-05 23:06:27 +04:00
nt_errstr ( error ) ) ;
return ;
}
return ;
2009-05-28 02:07:26 +04:00
}
SSVAL ( outbody . data , 0x00 , 0x58 + 1 ) ; /* struct size */
SCVAL ( outbody . data , 0x02 ,
out_oplock_level ) ; /* oplock level */
SCVAL ( outbody . data , 0x03 , 0 ) ; /* reserved */
SIVAL ( outbody . data , 0x04 ,
out_create_action ) ; /* create action */
SBVAL ( outbody . data , 0x08 ,
out_creation_time ) ; /* creation time */
SBVAL ( outbody . data , 0x10 ,
out_last_access_time ) ; /* last access time */
SBVAL ( outbody . data , 0x18 ,
out_last_write_time ) ; /* last write time */
SBVAL ( outbody . data , 0x20 ,
out_change_time ) ; /* change time */
SBVAL ( outbody . data , 0x28 ,
out_allocation_size ) ; /* allocation size */
SBVAL ( outbody . data , 0x30 ,
out_end_of_file ) ; /* end of file */
SIVAL ( outbody . data , 0x38 ,
out_file_attributes ) ; /* file attributes */
SIVAL ( outbody . data , 0x3C , 0 ) ; /* reserved */
2010-05-20 06:28:26 +04:00
SBVAL ( outbody . data , 0x40 ,
out_file_id_persistent ) ; /* file id (persistent) */
2009-05-28 02:07:26 +04:00
SBVAL ( outbody . data , 0x48 ,
out_file_id_volatile ) ; /* file id (volatile) */
2009-08-12 22:39:58 +04:00
SIVAL ( outbody . data , 0x50 ,
out_context_buffer_offset ) ; /* create contexts offset */
SIVAL ( outbody . data , 0x54 ,
out_context_buffer . length ) ; /* create contexts length */
2009-05-28 02:07:26 +04:00
2009-08-12 22:39:58 +04:00
outdyn = out_context_buffer ;
2009-05-28 02:07:26 +04:00
2010-04-23 21:29:48 +04:00
error = smbd_smb2_request_done ( smb2req , outbody , & outdyn ) ;
2009-06-05 23:06:27 +04:00
if ( ! NT_STATUS_IS_OK ( error ) ) {
2010-04-23 21:29:48 +04:00
smbd_server_connection_terminate ( smb2req - > sconn ,
2009-06-05 23:06:27 +04:00
nt_errstr ( error ) ) ;
return ;
}
2009-05-28 02:07:26 +04:00
}
2009-06-05 23:06:27 +04:00
struct smbd_smb2_create_state {
struct smbd_smb2_request * smb2req ;
2010-04-23 10:52:19 +04:00
struct smb_request * smb1req ;
struct timed_event * te ;
2010-05-11 00:58:41 +04:00
struct tevent_immediate * im ;
2010-04-23 10:52:19 +04:00
struct timeval request_time ;
2010-04-24 00:10:15 +04:00
struct file_id id ;
2010-04-23 10:52:19 +04:00
DATA_BLOB private_data ;
2009-06-05 23:06:27 +04:00
uint8_t out_oplock_level ;
uint32_t out_create_action ;
NTTIME out_creation_time ;
NTTIME out_last_access_time ;
NTTIME out_last_write_time ;
NTTIME out_change_time ;
uint64_t out_allocation_size ;
uint64_t out_end_of_file ;
uint32_t out_file_attributes ;
2010-05-20 06:28:26 +04:00
uint64_t out_file_id_persistent ;
2009-06-05 23:06:27 +04:00
uint64_t out_file_id_volatile ;
2009-08-12 22:39:58 +04:00
struct smb2_create_blobs out_context_blobs ;
2009-06-05 23:06:27 +04:00
} ;
static struct tevent_req * smbd_smb2_create_send ( TALLOC_CTX * mem_ctx ,
2009-08-12 22:39:58 +04:00
struct tevent_context * ev ,
struct smbd_smb2_request * smb2req ,
uint8_t in_oplock_level ,
uint32_t in_impersonation_level ,
uint32_t in_desired_access ,
uint32_t in_file_attributes ,
uint32_t in_share_access ,
uint32_t in_create_disposition ,
uint32_t in_create_options ,
const char * in_name ,
struct smb2_create_blobs in_context_blobs )
2009-05-28 02:07:26 +04:00
{
2010-04-23 21:53:44 +04:00
struct tevent_req * req = NULL ;
2010-04-23 10:52:19 +04:00
struct smbd_smb2_create_state * state = NULL ;
2009-05-28 02:07:26 +04:00
NTSTATUS status ;
2010-04-23 10:52:19 +04:00
struct smb_request * smb1req = NULL ;
files_struct * result = NULL ;
2009-05-28 02:07:26 +04:00
int info ;
2009-11-18 01:55:02 +03:00
struct timespec write_time_ts ;
2009-08-12 22:39:58 +04:00
struct smb2_create_blobs out_context_blobs ;
2010-05-20 19:13:37 +04:00
int requested_oplock_level ;
2012-08-28 11:33:51 +04:00
struct smb2_create_blob * dhnc = NULL ;
2009-08-12 22:39:58 +04:00
ZERO_STRUCT ( out_context_blobs ) ;
2009-05-28 02:07:26 +04:00
2012-03-27 13:09:05 +04:00
if ( lp_fake_oplocks ( SNUM ( smb2req - > tcon - > compat ) ) ) {
2010-05-22 10:59:54 +04:00
requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE ;
2010-05-20 19:13:37 +04:00
} else {
requested_oplock_level = in_oplock_level ;
}
2011-11-09 14:47:33 +04:00
if ( smb2req - > subreq = = NULL ) {
2010-04-23 10:52:19 +04:00
/* New create call. */
2010-04-23 21:53:44 +04:00
req = tevent_req_create ( mem_ctx , & state ,
2009-06-05 23:06:27 +04:00
struct smbd_smb2_create_state ) ;
2010-04-23 21:53:44 +04:00
if ( req = = NULL ) {
2010-04-23 10:52:19 +04:00
return NULL ;
}
state - > smb2req = smb2req ;
2009-05-28 02:07:26 +04:00
2010-04-23 10:52:19 +04:00
smb1req = smbd_smb2_fake_smb_request ( smb2req ) ;
2010-04-23 21:53:44 +04:00
if ( tevent_req_nomem ( smb1req , req ) ) {
return tevent_req_post ( req , ev ) ;
2010-04-23 10:52:19 +04:00
}
state - > smb1req = smb1req ;
2012-02-10 15:48:30 +04:00
smb2req - > subreq = req ;
2010-04-23 10:52:19 +04:00
DEBUG ( 10 , ( " smbd_smb2_create: name[%s] \n " ,
in_name ) ) ;
} else {
/* Re-entrant create call. */
2010-04-23 21:53:44 +04:00
req = smb2req - > subreq ;
state = tevent_req_data ( req ,
2010-04-23 10:52:19 +04:00
struct smbd_smb2_create_state ) ;
smb1req = state - > smb1req ;
DEBUG ( 10 , ( " smbd_smb2_create_send: reentrant for file %s \n " ,
in_name ) ) ;
2009-05-28 02:07:26 +04:00
}
2012-08-28 11:33:51 +04:00
dhnc = smb2_create_blob_find ( & in_context_blobs ,
SMB2_CREATE_TAG_DHNC ) ;
if ( dhnc ) {
if ( dhnc - > data . length ! = 16 ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
}
/* we don't support durable handles yet */
tevent_req_nterror ( req , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
return tevent_req_post ( req , ev ) ;
}
2010-04-23 10:52:19 +04:00
if ( IS_IPC ( smb1req - > conn ) ) {
2009-06-05 12:46:30 +04:00
const char * pipe_name = in_name ;
if ( ! lp_nt_pipe_support ( ) ) {
2010-04-23 21:53:44 +04:00
tevent_req_nterror ( req , NT_STATUS_ACCESS_DENIED ) ;
return tevent_req_post ( req , ev ) ;
2009-06-05 12:46:30 +04:00
}
2010-04-23 10:52:19 +04:00
status = open_np_file ( smb1req , pipe_name , & result ) ;
2009-06-05 12:46:30 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-04-23 21:53:44 +04:00
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
2009-06-05 12:46:30 +04:00
}
2009-06-05 23:06:27 +04:00
info = FILE_WAS_OPENED ;
2010-04-23 10:52:19 +04:00
} else if ( CAN_PRINT ( smb1req - > conn ) ) {
status = file_new ( smb1req , smb1req - > conn , & result ) ;
2009-06-02 18:07:53 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-04-23 21:53:44 +04:00
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
2009-06-02 18:07:53 +04:00
}
2009-05-28 02:07:26 +04:00
2010-05-04 12:28:48 +04:00
status = print_spool_open ( result , in_name ,
smb1req - > vuid ) ;
2009-06-02 18:07:53 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-04-23 10:52:19 +04:00
file_free ( smb1req , result ) ;
2010-04-23 21:53:44 +04:00
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
2009-06-02 18:07:53 +04:00
}
info = FILE_WAS_CREATED ;
} else {
2009-08-11 20:31:27 +04:00
char * fname ;
2009-07-11 01:50:37 +04:00
struct smb_filename * smb_fname = NULL ;
2009-08-15 13:52:37 +04:00
struct smb2_create_blob * exta = NULL ;
struct ea_list * ea_list = NULL ;
struct smb2_create_blob * mxac = NULL ;
NTTIME max_access_time = 0 ;
struct smb2_create_blob * secd = NULL ;
struct security_descriptor * sec_desc = NULL ;
struct smb2_create_blob * dhnq = NULL ;
struct smb2_create_blob * alsi = NULL ;
uint64_t allocation_size = 0 ;
struct smb2_create_blob * twrp = NULL ;
struct smb2_create_blob * qfid = NULL ;
exta = smb2_create_blob_find ( & in_context_blobs ,
SMB2_CREATE_TAG_EXTA ) ;
mxac = smb2_create_blob_find ( & in_context_blobs ,
SMB2_CREATE_TAG_MXAC ) ;
secd = smb2_create_blob_find ( & in_context_blobs ,
SMB2_CREATE_TAG_SECD ) ;
dhnq = smb2_create_blob_find ( & in_context_blobs ,
SMB2_CREATE_TAG_DHNQ ) ;
alsi = smb2_create_blob_find ( & in_context_blobs ,
SMB2_CREATE_TAG_ALSI ) ;
twrp = smb2_create_blob_find ( & in_context_blobs ,
SMB2_CREATE_TAG_TWRP ) ;
qfid = smb2_create_blob_find ( & in_context_blobs ,
SMB2_CREATE_TAG_QFID ) ;
2009-06-04 14:17:37 +04:00
2009-08-11 20:31:27 +04:00
fname = talloc_strdup ( state , in_name ) ;
2010-04-23 21:53:44 +04:00
if ( tevent_req_nomem ( fname , req ) ) {
return tevent_req_post ( req , ev ) ;
2009-08-11 20:31:27 +04:00
}
2009-08-15 13:52:37 +04:00
if ( exta ) {
2009-09-17 20:29:07 +04:00
ea_list = read_nttrans_ea_list ( mem_ctx ,
( const char * ) exta - > data . data , exta - > data . length ) ;
if ( ! ea_list ) {
DEBUG ( 10 , ( " smbd_smb2_create_send: read_ea_name_list failed. \n " ) ) ;
2010-04-23 21:53:44 +04:00
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
2009-09-17 20:29:07 +04:00
}
2009-08-15 13:52:37 +04:00
}
if ( mxac ) {
if ( mxac - > data . length = = 0 ) {
max_access_time = 0 ;
} else if ( mxac - > data . length = = 8 ) {
max_access_time = BVAL ( mxac - > data . data , 0 ) ;
} else {
2010-04-23 21:53:44 +04:00
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
2009-08-15 13:52:37 +04:00
}
}
if ( secd ) {
enum ndr_err_code ndr_err ;
sec_desc = talloc_zero ( state , struct security_descriptor ) ;
2010-04-23 21:53:44 +04:00
if ( tevent_req_nomem ( sec_desc , req ) ) {
return tevent_req_post ( req , ev ) ;
2009-08-15 13:52:37 +04:00
}
ndr_err = ndr_pull_struct_blob ( & secd - > data ,
2010-05-10 02:42:06 +04:00
sec_desc , sec_desc ,
2009-08-15 13:52:37 +04:00
( ndr_pull_flags_fn_t ) ndr_pull_security_descriptor ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
DEBUG ( 2 , ( " ndr_pull_security_descriptor failed: %s \n " ,
ndr_errstr ( ndr_err ) ) ) ;
2010-04-23 21:53:44 +04:00
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
2009-08-15 13:52:37 +04:00
}
}
if ( dhnq ) {
if ( dhnq - > data . length ! = 16 ) {
2010-04-23 21:53:44 +04:00
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
2009-08-15 13:52:37 +04:00
}
/*
* we don ' t support durable handles yet
* and have to ignore this
*/
}
if ( alsi ) {
if ( alsi - > data . length ! = 8 ) {
2010-04-23 21:53:44 +04:00
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
2009-08-15 13:52:37 +04:00
}
allocation_size = BVAL ( alsi - > data . data , 0 ) ;
}
if ( twrp ) {
NTTIME nttime ;
time_t t ;
struct tm * tm ;
if ( twrp - > data . length ! = 8 ) {
2010-04-23 21:53:44 +04:00
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
2009-08-15 13:52:37 +04:00
}
nttime = BVAL ( twrp - > data . data , 0 ) ;
t = nt_time_to_unix ( nttime ) ;
tm = gmtime ( & t ) ;
TALLOC_FREE ( fname ) ;
fname = talloc_asprintf ( state ,
" @GMT-%04u.%02u.%02u-%02u.%02u.%02u \\ %s " ,
tm - > tm_year + 1900 ,
tm - > tm_mon + 1 ,
tm - > tm_mday ,
tm - > tm_hour ,
tm - > tm_min ,
tm - > tm_sec ,
in_name ) ;
2010-04-23 21:53:44 +04:00
if ( tevent_req_nomem ( fname , req ) ) {
return tevent_req_post ( req , ev ) ;
2009-08-15 13:52:37 +04:00
}
}
if ( qfid ) {
if ( qfid - > data . length ! = 0 ) {
2010-04-23 21:53:44 +04:00
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
2009-08-15 13:52:37 +04:00
}
}
/* these are ignored for SMB2 */
in_create_options & = ~ ( 0x10 ) ; /* NTCREATEX_OPTIONS_SYNC_ALERT */
in_create_options & = ~ ( 0x20 ) ; /* NTCREATEX_OPTIONS_ASYNC_ALERT */
2010-05-22 03:56:10 +04:00
/*
* For a DFS path the function parse_dfs_path ( )
* will do the path processing .
*/
2010-05-22 04:12:40 +04:00
if ( ! ( smb1req - > flags2 & FLAGS2_DFS_PATHNAMES ) ) {
2010-05-22 03:56:10 +04:00
/* convert '\\' into '/' */
status = check_path_syntax ( fname ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
}
2009-08-08 12:47:11 +04:00
}
2010-04-23 21:53:44 +04:00
status = filename_convert ( req ,
2010-04-23 10:52:19 +04:00
smb1req - > conn ,
smb1req - > flags2 & FLAGS2_DFS_PATHNAMES ,
2009-08-11 20:31:27 +04:00
fname ,
2012-06-07 16:49:28 +04:00
0 , /* unix_convert flags */
NULL , /* ppath_contains_wcards */
2009-08-11 20:29:06 +04:00
& smb_fname ) ;
2009-06-17 04:23:54 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-04-23 21:53:44 +04:00
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
2009-06-17 04:23:54 +04:00
}
2010-04-24 11:29:41 +04:00
in_file_attributes & = ~ FILE_FLAG_POSIX_SEMANTICS ;
2010-04-23 10:52:19 +04:00
status = SMB_VFS_CREATE_FILE ( smb1req - > conn ,
smb1req ,
2009-06-02 18:07:53 +04:00
0 , /* root_dir_fid */
2009-06-12 23:54:11 +04:00
smb_fname ,
2009-06-02 18:07:53 +04:00
in_desired_access ,
in_share_access ,
in_create_disposition ,
in_create_options ,
in_file_attributes ,
2010-05-20 19:13:37 +04:00
map_smb2_oplock_levels_to_samba ( requested_oplock_level ) ,
2009-08-15 13:52:37 +04:00
allocation_size ,
2010-03-06 02:10:30 +03:00
0 , /* private_flags */
2009-08-15 13:52:37 +04:00
sec_desc ,
ea_list ,
2009-06-02 18:07:53 +04:00
& result ,
2009-06-12 23:54:11 +04:00
& info ) ;
2009-06-02 18:07:53 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-08-02 19:05:33 +04:00
if ( open_was_deferred ( smb1req - > sconn , smb1req - > mid ) ) {
2010-04-23 21:53:44 +04:00
return req ;
2010-04-23 10:52:19 +04:00
}
2010-04-23 21:53:44 +04:00
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
2009-06-02 18:07:53 +04:00
}
2009-08-15 13:52:37 +04:00
if ( mxac ) {
NTTIME last_write_time ;
unix_timespec_to_nt_time ( & last_write_time ,
result - > fsp_name - > st . st_ex_mtime ) ;
if ( last_write_time ! = max_access_time ) {
uint8_t p [ 8 ] ;
uint32_t max_access_granted ;
DATA_BLOB blob = data_blob_const ( p , sizeof ( p ) ) ;
2011-07-10 15:09:06 +04:00
status = smbd_calculate_access_mask ( smb1req - > conn ,
2009-08-15 13:52:37 +04:00
result - > fsp_name ,
SEC_FLAG_MAXIMUM_ALLOWED ,
& max_access_granted ) ;
SIVAL ( p , 0 , NT_STATUS_V ( status ) ) ;
SIVAL ( p , 4 , max_access_granted ) ;
status = smb2_create_blob_add ( state ,
& out_context_blobs ,
SMB2_CREATE_TAG_MXAC ,
blob ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-04-23 21:53:44 +04:00
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
2009-08-15 13:52:37 +04:00
}
}
}
if ( qfid ) {
uint8_t p [ 32 ] ;
2010-05-20 22:36:47 +04:00
uint64_t file_index = get_FileIndex ( result - > conn ,
& result - > fsp_name - > st ) ;
2009-08-15 13:52:37 +04:00
DATA_BLOB blob = data_blob_const ( p , sizeof ( p ) ) ;
ZERO_STRUCT ( p ) ;
2010-05-20 22:36:47 +04:00
/* From conversations with Microsoft engineers at
the MS plugfest . The first 8 bytes are the " volume index "
= = inode , the second 8 bytes are the " volume id " ,
= = dev . This will be updated in the SMB2 doc . */
SBVAL ( p , 0 , file_index ) ;
SIVAL ( p , 8 , result - > fsp_name - > st . st_ex_dev ) ; /* FileIndexHigh */
2009-08-15 13:52:37 +04:00
status = smb2_create_blob_add ( state , & out_context_blobs ,
SMB2_CREATE_TAG_QFID ,
blob ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-04-23 21:53:44 +04:00
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
2009-08-15 13:52:37 +04:00
}
}
2009-07-08 23:24:03 +04:00
}
2010-04-23 10:52:19 +04:00
smb2req - > compat_chain_fsp = smb1req - > chain_fsp ;
2009-06-05 22:02:21 +04:00
2012-03-27 13:09:05 +04:00
if ( lp_fake_oplocks ( SNUM ( smb2req - > tcon - > compat ) ) ) {
2010-05-20 19:13:37 +04:00
state - > out_oplock_level = in_oplock_level ;
} else {
state - > out_oplock_level = map_samba_oplock_levels_to_smb2 ( result - > oplock_type ) ;
}
2010-04-24 11:29:41 +04:00
2009-05-28 02:07:26 +04:00
if ( ( in_create_disposition = = FILE_SUPERSEDE )
& & ( info = = FILE_WAS_OVERWRITTEN ) ) {
2009-06-05 23:06:27 +04:00
state - > out_create_action = FILE_WAS_SUPERSEDED ;
2009-05-28 02:07:26 +04:00
} else {
2009-06-05 23:06:27 +04:00
state - > out_create_action = info ;
2009-05-28 02:07:26 +04:00
}
2009-11-18 01:55:02 +03:00
state - > out_file_attributes = dos_mode ( result - > conn ,
result - > fsp_name ) ;
/* Deal with other possible opens having a modified
write time . JRA . */
ZERO_STRUCT ( write_time_ts ) ;
2011-01-26 00:57:38 +03:00
get_file_infos ( result - > file_id , 0 , NULL , & write_time_ts ) ;
2009-11-18 01:55:02 +03:00
if ( ! null_timespec ( write_time_ts ) ) {
update_stat_ex_mtime ( & result - > fsp_name - > st , write_time_ts ) ;
}
unix_timespec_to_nt_time ( & state - > out_creation_time ,
2010-04-23 10:52:19 +04:00
get_create_timespec ( smb1req - > conn , result ,
2009-11-18 01:55:02 +03:00
result - > fsp_name ) ) ;
unix_timespec_to_nt_time ( & state - > out_last_access_time ,
result - > fsp_name - > st . st_ex_atime ) ;
unix_timespec_to_nt_time ( & state - > out_last_write_time ,
result - > fsp_name - > st . st_ex_mtime ) ;
unix_timespec_to_nt_time ( & state - > out_change_time ,
2010-04-23 10:52:19 +04:00
get_change_timespec ( smb1req - > conn , result ,
2009-11-18 01:55:02 +03:00
result - > fsp_name ) ) ;
state - > out_allocation_size =
2011-10-10 19:48:18 +04:00
SMB_VFS_GET_ALLOC_SIZE ( smb1req - > conn , result ,
& ( result - > fsp_name - > st ) ) ;
2009-11-18 01:55:02 +03:00
state - > out_end_of_file = result - > fsp_name - > st . st_ex_size ;
2009-06-05 23:06:27 +04:00
if ( state - > out_file_attributes = = 0 ) {
state - > out_file_attributes = FILE_ATTRIBUTE_NORMAL ;
2009-05-28 02:07:26 +04:00
}
2012-06-08 19:51:47 +04:00
state - > out_file_id_persistent = result - > op - > global - > open_persistent_id ;
state - > out_file_id_volatile = result - > op - > global - > open_volatile_id ;
2009-08-12 22:39:58 +04:00
state - > out_context_blobs = out_context_blobs ;
2009-06-05 23:06:27 +04:00
2012-06-28 12:02:01 +04:00
DEBUG ( 10 , ( " smbd_smb2_create_send: %s - %s \n " ,
fsp_str_dbg ( result ) , fsp_fnum_dbg ( result ) ) ) ;
2010-04-23 21:53:44 +04:00
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
2009-06-05 23:06:27 +04:00
}
2010-04-23 21:53:44 +04:00
static NTSTATUS smbd_smb2_create_recv ( struct tevent_req * req ,
2009-08-12 22:39:58 +04:00
TALLOC_CTX * mem_ctx ,
uint8_t * out_oplock_level ,
uint32_t * out_create_action ,
NTTIME * out_creation_time ,
NTTIME * out_last_access_time ,
NTTIME * out_last_write_time ,
NTTIME * out_change_time ,
uint64_t * out_allocation_size ,
uint64_t * out_end_of_file ,
uint32_t * out_file_attributes ,
2010-05-20 06:28:26 +04:00
uint64_t * out_file_id_persistent ,
2009-08-12 22:39:58 +04:00
uint64_t * out_file_id_volatile ,
struct smb2_create_blobs * out_context_blobs )
2009-06-05 23:06:27 +04:00
{
NTSTATUS status ;
2010-04-23 21:53:44 +04:00
struct smbd_smb2_create_state * state = tevent_req_data ( req ,
2009-06-05 23:06:27 +04:00
struct smbd_smb2_create_state ) ;
2010-04-23 21:53:44 +04:00
if ( tevent_req_is_nterror ( req , & status ) ) {
tevent_req_received ( req ) ;
2009-06-05 23:06:27 +04:00
return status ;
}
* out_oplock_level = state - > out_oplock_level ;
* out_create_action = state - > out_create_action ;
* out_creation_time = state - > out_creation_time ;
* out_last_access_time = state - > out_last_access_time ;
* out_last_write_time = state - > out_last_write_time ;
* out_change_time = state - > out_change_time ;
* out_allocation_size = state - > out_allocation_size ;
* out_end_of_file = state - > out_end_of_file ;
* out_file_attributes = state - > out_file_attributes ;
2010-05-20 06:28:26 +04:00
* out_file_id_persistent = state - > out_file_id_persistent ;
2009-06-05 23:06:27 +04:00
* out_file_id_volatile = state - > out_file_id_volatile ;
2009-08-12 22:39:58 +04:00
* out_context_blobs = state - > out_context_blobs ;
talloc_steal ( mem_ctx , state - > out_context_blobs . blobs ) ;
2009-06-05 23:06:27 +04:00
2010-04-23 21:53:44 +04:00
tevent_req_received ( req ) ;
2009-05-28 02:07:26 +04:00
return NT_STATUS_OK ;
}
2010-04-23 10:52:19 +04:00
/*********************************************************
Code for dealing with deferred opens .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool get_deferred_open_message_state_smb2 ( struct smbd_smb2_request * smb2req ,
struct timeval * p_request_time ,
void * * pp_state )
{
struct smbd_smb2_create_state * state = NULL ;
2010-04-23 21:53:44 +04:00
struct tevent_req * req = NULL ;
2010-04-23 10:52:19 +04:00
if ( ! smb2req ) {
return false ;
}
2012-02-10 15:49:28 +04:00
if ( smb2req - > async_te = = NULL ) {
2010-04-23 10:52:19 +04:00
return false ;
}
2010-04-23 21:53:44 +04:00
req = smb2req - > subreq ;
if ( ! req ) {
2010-04-23 10:52:19 +04:00
return false ;
}
2010-04-23 21:53:44 +04:00
state = tevent_req_data ( req , struct smbd_smb2_create_state ) ;
2010-04-23 10:52:19 +04:00
if ( ! state ) {
return false ;
}
if ( p_request_time ) {
* p_request_time = state - > request_time ;
}
if ( pp_state ) {
* pp_state = ( void * ) state - > private_data . data ;
}
return true ;
}
/*********************************************************
Re - process this call early - requested by message or
close .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-06-12 16:43:12 +04:00
static struct smbd_smb2_request * find_open_smb2req (
struct smbd_server_connection * sconn , uint64_t mid )
2010-04-23 10:52:19 +04:00
{
struct smbd_smb2_request * smb2req ;
for ( smb2req = sconn - > smb2 . requests ; smb2req ; smb2req = smb2req - > next ) {
2010-04-26 23:29:03 +04:00
uint64_t message_id ;
if ( smb2req - > subreq = = NULL ) {
/* This message has been processed. */
continue ;
}
if ( ! tevent_req_is_in_progress ( smb2req - > subreq ) ) {
/* This message has been processed. */
continue ;
}
message_id = get_mid_from_smb2req ( smb2req ) ;
2010-04-23 10:52:19 +04:00
if ( message_id = = mid ) {
return smb2req ;
}
}
return NULL ;
}
2010-06-12 16:44:53 +04:00
bool open_was_deferred_smb2 ( struct smbd_server_connection * sconn , uint64_t mid )
2010-04-23 10:52:19 +04:00
{
struct smbd_smb2_create_state * state = NULL ;
2010-06-12 16:43:12 +04:00
struct smbd_smb2_request * smb2req ;
2010-06-12 16:44:53 +04:00
smb2req = find_open_smb2req ( sconn , mid ) ;
2010-04-23 10:52:19 +04:00
if ( ! smb2req ) {
DEBUG ( 10 , ( " open_was_deferred_smb2: mid %llu smb2req == NULL \n " ,
( unsigned long long ) mid ) ) ;
return false ;
}
if ( ! smb2req - > subreq ) {
return false ;
}
if ( ! tevent_req_is_in_progress ( smb2req - > subreq ) ) {
return false ;
}
state = tevent_req_data ( smb2req - > subreq ,
struct smbd_smb2_create_state ) ;
if ( ! state ) {
return false ;
}
/* It's not in progress if there's no timeout event. */
if ( ! state - > te ) {
return false ;
}
DEBUG ( 10 , ( " open_was_deferred_smb2: mid = %llu \n " ,
( unsigned long long ) mid ) ) ;
2010-04-23 21:29:48 +04:00
2010-04-23 10:52:19 +04:00
return true ;
}
2010-04-24 00:10:15 +04:00
static void remove_deferred_open_message_smb2_internal ( struct smbd_smb2_request * smb2req ,
uint64_t mid )
2010-04-23 10:52:19 +04:00
{
struct smbd_smb2_create_state * state = NULL ;
if ( ! smb2req - > subreq ) {
return ;
}
if ( ! tevent_req_is_in_progress ( smb2req - > subreq ) ) {
return ;
}
state = tevent_req_data ( smb2req - > subreq ,
struct smbd_smb2_create_state ) ;
if ( ! state ) {
return ;
}
2010-04-24 00:10:15 +04:00
DEBUG ( 10 , ( " remove_deferred_open_message_smb2_internal: "
2010-04-23 10:52:19 +04:00
" mid %llu \n " ,
( unsigned long long ) mid ) ) ;
/* Ensure we don't have any outstanding timer event. */
TALLOC_FREE ( state - > te ) ;
2010-05-11 00:58:41 +04:00
/* Ensure we don't have any outstanding immediate event. */
TALLOC_FREE ( state - > im ) ;
2010-04-23 10:52:19 +04:00
}
2010-06-12 16:48:42 +04:00
void remove_deferred_open_message_smb2 (
struct smbd_server_connection * sconn , uint64_t mid )
2010-04-24 00:10:15 +04:00
{
2010-06-12 16:43:12 +04:00
struct smbd_smb2_request * smb2req ;
2010-06-12 16:48:42 +04:00
smb2req = find_open_smb2req ( sconn , mid ) ;
2010-04-24 00:10:15 +04:00
if ( ! smb2req ) {
DEBUG ( 10 , ( " remove_deferred_open_message_smb2: "
" can't find mid %llu \n " ,
( unsigned long long ) mid ) ) ;
return ;
}
remove_deferred_open_message_smb2_internal ( smb2req , mid ) ;
}
2010-05-11 00:58:41 +04:00
static void smbd_smb2_create_request_dispatch_immediate ( struct tevent_context * ctx ,
struct tevent_immediate * im ,
void * private_data )
{
struct smbd_smb2_request * smb2req = talloc_get_type_abort ( private_data ,
struct smbd_smb2_request ) ;
struct smbd_server_connection * sconn = smb2req - > sconn ;
uint64_t mid = get_mid_from_smb2req ( smb2req ) ;
NTSTATUS status ;
DEBUG ( 10 , ( " smbd_smb2_create_request_dispatch_immediate: "
" re-dispatching mid %llu \n " ,
( unsigned long long ) mid ) ) ;
status = smbd_smb2_request_dispatch ( smb2req ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
smbd_server_connection_terminate ( sconn , nt_errstr ( status ) ) ;
return ;
}
}
2012-06-30 00:53:31 +04:00
bool schedule_deferred_open_message_smb2 (
2010-06-12 16:48:42 +04:00
struct smbd_server_connection * sconn , uint64_t mid )
2010-04-23 10:52:19 +04:00
{
struct smbd_smb2_create_state * state = NULL ;
2010-06-12 16:43:12 +04:00
struct smbd_smb2_request * smb2req ;
2010-06-12 16:48:42 +04:00
smb2req = find_open_smb2req ( sconn , mid ) ;
2010-04-23 10:52:19 +04:00
if ( ! smb2req ) {
DEBUG ( 10 , ( " schedule_deferred_open_message_smb2: "
" can't find mid %llu \n " ,
( unsigned long long ) mid ) ) ;
2012-06-30 00:53:31 +04:00
return false ;
2010-04-23 10:52:19 +04:00
}
if ( ! smb2req - > subreq ) {
2012-06-30 00:53:31 +04:00
return false ;
2010-04-23 10:52:19 +04:00
}
if ( ! tevent_req_is_in_progress ( smb2req - > subreq ) ) {
2012-06-30 00:53:31 +04:00
return false ;
2010-04-23 10:52:19 +04:00
}
state = tevent_req_data ( smb2req - > subreq ,
struct smbd_smb2_create_state ) ;
if ( ! state ) {
2012-06-30 00:53:31 +04:00
return false ;
2010-04-23 10:52:19 +04:00
}
2010-05-11 00:58:41 +04:00
2010-04-23 10:52:19 +04:00
/* Ensure we don't have any outstanding timer event. */
TALLOC_FREE ( state - > te ) ;
2010-05-11 00:58:41 +04:00
/* Ensure we don't have any outstanding immediate event. */
TALLOC_FREE ( state - > im ) ;
2010-04-23 10:52:19 +04:00
2010-04-26 21:54:33 +04:00
/*
* This is subtle . We must null out the callback
2012-06-25 13:07:22 +04:00
* before rescheduling , else the first call to
2010-04-26 21:54:33 +04:00
* tevent_req_nterror ( ) causes the _receive ( )
* function to be called , this causing tevent_req_post ( )
* to crash .
*/
tevent_req_set_callback ( smb2req - > subreq , NULL , NULL ) ;
2010-05-11 00:58:41 +04:00
state - > im = tevent_create_immediate ( smb2req ) ;
if ( ! state - > im ) {
2010-04-23 10:52:19 +04:00
smbd_server_connection_terminate ( smb2req - > sconn ,
nt_errstr ( NT_STATUS_NO_MEMORY ) ) ;
2012-06-30 00:53:31 +04:00
return false ;
2010-04-23 10:52:19 +04:00
}
DEBUG ( 10 , ( " schedule_deferred_open_message_smb2: "
" re-processing mid %llu \n " ,
( unsigned long long ) mid ) ) ;
2010-05-11 00:58:41 +04:00
tevent_schedule_immediate ( state - > im ,
2011-12-12 17:15:03 +04:00
smb2req - > sconn - > ev_ctx ,
2010-05-11 00:58:41 +04:00
smbd_smb2_create_request_dispatch_immediate ,
2010-04-23 10:52:19 +04:00
smb2req ) ;
2012-06-30 00:53:31 +04:00
return true ;
2010-04-23 10:52:19 +04:00
}
/*********************************************************
Re - process this call .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void smb2_deferred_open_timer ( struct event_context * ev ,
struct timed_event * te ,
struct timeval _tval ,
void * private_data )
{
NTSTATUS status ;
struct smbd_smb2_create_state * state = NULL ;
struct smbd_smb2_request * smb2req = talloc_get_type ( private_data ,
struct smbd_smb2_request ) ;
DEBUG ( 10 , ( " smb2_deferred_open_timer: [idx=%d], %s \n " ,
smb2req - > current_idx ,
tevent_req_default_print ( smb2req - > subreq , talloc_tos ( ) ) ) ) ;
state = tevent_req_data ( smb2req - > subreq ,
struct smbd_smb2_create_state ) ;
if ( ! state ) {
return ;
}
/*
* Null this out , don ' t talloc_free . It will
* be talloc_free ' d by the tevent library when
* this returns .
*/
state - > te = NULL ;
2010-05-11 00:58:41 +04:00
/* Ensure we don't have any outstanding immediate event. */
TALLOC_FREE ( state - > im ) ;
2010-04-23 10:52:19 +04:00
/*
* This is subtle . We must null out the callback
2012-06-25 13:07:22 +04:00
* before rescheduling , else the first call to
2010-04-23 10:52:19 +04:00
* tevent_req_nterror ( ) causes the _receive ( )
* function to be called , this causing tevent_req_post ( )
* to crash .
*/
tevent_req_set_callback ( smb2req - > subreq , NULL , NULL ) ;
status = smbd_smb2_request_dispatch ( smb2req ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
smbd_server_connection_terminate ( smb2req - > sconn ,
nt_errstr ( status ) ) ;
}
}
2010-04-24 00:10:15 +04:00
static bool smbd_smb2_create_cancel ( struct tevent_req * req )
{
struct smbd_smb2_request * smb2req = NULL ;
struct smbd_smb2_create_state * state = tevent_req_data ( req ,
struct smbd_smb2_create_state ) ;
uint64_t mid ;
if ( ! state ) {
return false ;
}
if ( ! state - > smb2req ) {
return false ;
}
smb2req = state - > smb2req ;
mid = get_mid_from_smb2req ( smb2req ) ;
2012-06-30 01:25:53 +04:00
if ( is_deferred_open_async ( state - > private_data . data ) ) {
/* Can't cancel an async create. */
return false ;
}
2010-07-04 22:14:27 +04:00
remove_deferred_open_entry ( state - > id , mid ,
2011-12-15 14:51:20 +04:00
messaging_server_id ( smb2req - > sconn - > msg_ctx ) ) ;
2010-04-24 00:10:15 +04:00
remove_deferred_open_message_smb2_internal ( smb2req , mid ) ;
smb2req - > cancelled = true ;
tevent_req_done ( req ) ;
return true ;
}
2010-04-23 10:52:19 +04:00
bool push_deferred_open_message_smb2 ( struct smbd_smb2_request * smb2req ,
struct timeval request_time ,
struct timeval timeout ,
2010-04-24 00:10:15 +04:00
struct file_id id ,
2010-04-23 10:52:19 +04:00
char * private_data ,
size_t priv_len )
{
2010-04-23 21:53:44 +04:00
struct tevent_req * req = NULL ;
2010-04-23 10:52:19 +04:00
struct smbd_smb2_create_state * state = NULL ;
struct timeval end_time ;
if ( ! smb2req ) {
return false ;
}
2010-04-23 21:53:44 +04:00
req = smb2req - > subreq ;
if ( ! req ) {
2010-04-23 10:52:19 +04:00
return false ;
}
2010-04-23 21:53:44 +04:00
state = tevent_req_data ( req , struct smbd_smb2_create_state ) ;
2010-04-23 10:52:19 +04:00
if ( ! state ) {
return false ;
}
2010-04-24 00:10:15 +04:00
state - > id = id ;
2010-04-23 10:52:19 +04:00
state - > request_time = request_time ;
state - > private_data = data_blob_talloc ( state , private_data ,
priv_len ) ;
if ( ! state - > private_data . data ) {
return false ;
}
2010-05-20 07:09:51 +04:00
2010-04-23 10:52:19 +04:00
/* Re-schedule us to retry on timer expiry. */
end_time = timeval_sum ( & request_time , & timeout ) ;
DEBUG ( 10 , ( " push_deferred_open_message_smb2: "
" timeout at %s \n " ,
timeval_string ( talloc_tos ( ) ,
& end_time ,
true ) ) ) ;
2011-12-12 17:15:03 +04:00
state - > te = tevent_add_timer ( smb2req - > sconn - > ev_ctx ,
2010-04-23 10:52:19 +04:00
state ,
end_time ,
smb2_deferred_open_timer ,
smb2req ) ;
if ( ! state - > te ) {
return false ;
}
2010-04-24 00:10:15 +04:00
/* allow this request to be canceled */
tevent_req_set_cancel_fn ( req , smbd_smb2_create_cancel ) ;
2010-04-23 10:52:19 +04:00
return true ;
}