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"
2014-10-29 01:31:46 +03:00
# include "../librpc/gen_ndr/ndr_smb2_lease_struct.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
2018-03-21 22:01:05 +03:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_SMB2
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 :
2014-10-29 01:31:46 +03:00
return LEASE_OPLOCK ;
2010-04-24 11:29:41 +04:00
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 ) {
2010-04-24 11:29:41 +04:00
return SMB2_OPLOCK_LEVEL_II ;
2014-10-29 01:31:46 +03:00
} else if ( oplock_type = = LEASE_OPLOCK ) {
return SMB2_OPLOCK_LEVEL_LEASE ;
2010-04-24 11:29:41 +04:00
} 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 ,
2014-05-21 22:57:16 +04:00
struct timespec * out_creation_ts ,
struct timespec * out_last_access_ts ,
struct timespec * out_last_write_ts ,
struct timespec * out_change_ts ,
2009-08-12 22:39:58 +04:00
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 ,
2018-03-22 12:54:41 +03:00
smb2req - > 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
2014-11-13 14:10:46 +03:00
return smbd_smb2_request_pending_queue ( smb2req , tsubreq , 500 ) ;
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 ;
2014-05-21 22:57:16 +04:00
connection_struct * conn = smb2req - > tcon - > compat ;
struct timespec out_creation_ts = { 0 , } ;
struct timespec out_last_access_ts = { 0 , } ;
struct timespec out_last_write_ts = { 0 , } ;
struct timespec out_change_ts = { 0 , } ;
2009-07-24 18:21:07 +04:00
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-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 ,
2014-05-21 22:57:16 +04:00
& out_creation_ts ,
& out_last_access_ts ,
& out_last_write_ts ,
& out_change_ts ,
2009-06-05 23:06:27 +04:00
& 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 ) ) {
2014-06-11 14:15:48 +04:00
smbd_server_connection_terminate ( smb2req - > xconn ,
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 ) ) {
2014-06-11 14:15:48 +04:00
smbd_server_connection_terminate ( smb2req - > xconn ,
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 ;
}
2013-12-04 17:59:07 +04:00
outbody = smbd_smb2_generate_outbody ( smb2req , 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 ) ) {
2014-06-11 14:15:48 +04:00
smbd_server_connection_terminate ( smb2req - > xconn ,
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 */
2014-05-21 22:57:16 +04:00
put_long_date_timespec ( conn - > ts_res ,
( char * ) outbody . data + 0x08 ,
out_creation_ts ) ; /* creation time */
put_long_date_timespec ( conn - > ts_res ,
( char * ) outbody . data + 0x10 ,
out_last_access_ts ) ; /* last access time */
put_long_date_timespec ( conn - > ts_res ,
( char * ) outbody . data + 0x18 ,
out_last_write_ts ) ; /* last write time */
put_long_date_timespec ( conn - > ts_res ,
( char * ) outbody . data + 0x20 ,
out_change_ts ) ; /* change time */
2009-05-28 02:07:26 +04:00
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 ) ) {
2014-06-11 14:15:48 +04:00
smbd_server_connection_terminate ( smb2req - > xconn ,
2009-06-05 23:06:27 +04:00
nt_errstr ( error ) ) ;
return ;
}
2009-05-28 02:07:26 +04:00
}
2014-10-29 01:31:46 +03:00
static bool smb2_lease_key_valid ( const struct smb2_lease_key * key )
{
return ( ( key - > data [ 0 ] ! = 0 ) | | ( key - > data [ 1 ] ! = 0 ) ) ;
}
2016-10-13 13:42:59 +03:00
static NTSTATUS smbd_smb2_create_durable_lease_check ( struct smb_request * smb1req ,
2014-10-29 01:31:46 +03:00
const char * requested_filename , const struct files_struct * fsp ,
const struct smb2_lease * lease_ptr )
{
2018-07-17 16:40:04 +03:00
char * filename = NULL ;
2014-10-29 01:31:46 +03:00
struct smb_filename * smb_fname = NULL ;
2016-10-13 13:42:59 +03:00
uint32_t ucf_flags ;
2014-10-29 01:31:46 +03:00
NTSTATUS status ;
if ( lease_ptr = = NULL ) {
if ( fsp - > oplock_type ! = LEASE_OPLOCK ) {
return NT_STATUS_OK ;
}
DEBUG ( 10 , ( " Reopened file has lease, but no lease "
" requested \n " ) ) ;
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
if ( fsp - > oplock_type ! = LEASE_OPLOCK ) {
DEBUG ( 10 , ( " Lease requested, but reopened file has no "
" lease \n " ) ) ;
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
if ( ! smb2_lease_key_equal ( & lease_ptr - > lease_key ,
& fsp - > lease - > lease . lease_key ) ) {
DEBUG ( 10 , ( " Different lease key requested than found "
" in reopened file \n " ) ) ;
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
2018-07-17 16:40:04 +03:00
filename = talloc_strdup ( talloc_tos ( ) , requested_filename ) ;
if ( filename = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
/* This also converts '\' to '/' */
status = check_path_syntax ( filename ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( filename ) ;
return status ;
}
2016-10-13 13:42:59 +03:00
ucf_flags = filename_create_ucf_flags ( smb1req , FILE_OPEN ) ;
2017-05-18 22:29:50 +03:00
status = filename_convert ( talloc_tos ( ) , fsp - > conn ,
2018-07-17 16:40:04 +03:00
filename , ucf_flags ,
2014-10-29 01:31:46 +03:00
NULL , & smb_fname ) ;
2018-07-17 16:40:04 +03:00
TALLOC_FREE ( filename ) ;
2014-10-29 01:31:46 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " filename_convert returned %s \n " ,
nt_errstr ( status ) ) ) ;
return status ;
}
if ( ! strequal ( fsp - > fsp_name - > base_name , smb_fname - > base_name ) ) {
DEBUG ( 10 , ( " Lease requested for file %s, reopened file "
" is named %s \n " , smb_fname - > base_name ,
fsp - > fsp_name - > base_name ) ) ;
TALLOC_FREE ( smb_fname ) ;
return NT_STATUS_INVALID_PARAMETER ;
}
TALLOC_FREE ( smb_fname ) ;
return NT_STATUS_OK ;
}
2009-06-05 23:06:27 +04:00
struct smbd_smb2_create_state {
2017-07-21 17:23:53 +03:00
struct tevent_context * ev ;
2009-06-05 23:06:27 +04:00
struct smbd_smb2_request * smb2req ;
2010-04-23 10:52:19 +04:00
struct smb_request * smb1req ;
2012-09-26 05:04:20 +04:00
bool open_was_deferred ;
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 ;
2014-06-20 18:12:14 +04:00
struct deferred_open_record * open_rec ;
2017-07-22 16:31:05 +03:00
files_struct * result ;
2017-07-22 19:32:50 +03:00
bool replay_operation ;
2017-07-22 19:43:33 +03:00
uint8_t in_oplock_level ;
2017-07-22 19:47:17 +03:00
uint32_t in_create_disposition ;
2017-07-22 19:40:16 +03:00
int requested_oplock_level ;
2017-07-22 19:49:50 +03:00
int info ;
2017-07-21 19:02:05 +03:00
char * fname ;
struct ea_list * ea_list ;
NTTIME max_access_time ;
struct security_descriptor * sec_desc ;
uint64_t allocation_size ;
struct GUID _create_guid ;
struct GUID * create_guid ;
bool update_open ;
bool durable_requested ;
uint32_t durable_timeout_msec ;
bool do_durable_reconnect ;
uint64_t persistent_id ;
struct smb2_lease lease ;
struct smb2_lease * lease_ptr ;
ssize_t lease_len ;
bool need_replay_cache ;
struct smbXsrv_open * op ;
2017-07-20 13:15:19 +03:00
struct smb2_create_blob * dhnc ;
struct smb2_create_blob * dh2c ;
struct smb2_create_blob * dhnq ;
struct smb2_create_blob * dh2q ;
struct smb2_create_blob * rqls ;
struct smb2_create_blob * exta ;
struct smb2_create_blob * mxac ;
struct smb2_create_blob * secd ;
struct smb2_create_blob * alsi ;
struct smb2_create_blob * twrp ;
struct smb2_create_blob * qfid ;
struct smb2_create_blob * svhdx ;
2009-06-05 23:06:27 +04:00
uint8_t out_oplock_level ;
uint32_t out_create_action ;
2014-05-21 22:57:16 +04:00
struct timespec out_creation_ts ;
struct timespec out_last_access_ts ;
struct timespec out_last_write_ts ;
struct timespec out_change_ts ;
2009-06-05 23:06:27 +04:00
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 ;
2014-11-28 13:44:09 +03:00
struct smb2_create_blobs * out_context_blobs ;
2009-06-05 23:06:27 +04:00
} ;
2017-07-20 13:51:37 +03:00
static NTSTATUS smbd_smb2_create_fetch_create_ctx (
struct tevent_req * req ,
struct smb2_create_blobs * in_context_blobs )
{
struct smbd_smb2_create_state * state = tevent_req_data (
req , struct smbd_smb2_create_state ) ;
state - > dhnq = smb2_create_blob_find ( in_context_blobs ,
SMB2_CREATE_TAG_DHNQ ) ;
state - > dhnc = smb2_create_blob_find ( in_context_blobs ,
SMB2_CREATE_TAG_DHNC ) ;
state - > dh2q = smb2_create_blob_find ( in_context_blobs ,
SMB2_CREATE_TAG_DH2Q ) ;
state - > dh2c = smb2_create_blob_find ( in_context_blobs ,
SMB2_CREATE_TAG_DH2C ) ;
if ( state - > smb2req - > xconn - > smb2 . server . capabilities & SMB2_CAP_LEASING ) {
state - > rqls = smb2_create_blob_find ( in_context_blobs ,
SMB2_CREATE_TAG_RQLS ) ;
}
if ( ( ( state - > dhnc ! = NULL ) & & ( state - > dh2c ! = NULL ) ) | |
( ( state - > dhnc ! = NULL ) & & ( state - > dh2q ! = NULL ) ) | |
( ( state - > dh2c ! = NULL ) & & ( state - > dhnq ! = NULL ) ) | |
( ( state - > dh2q ! = NULL ) & & ( state - > dh2c ! = NULL ) ) )
{
/* not both are allowed at the same time */
return NT_STATUS_INVALID_PARAMETER ;
}
if ( state - > dhnc ! = NULL ) {
uint32_t num_blobs_allowed ;
if ( state - > dhnc - > data . length ! = 16 ) {
return NT_STATUS_INVALID_PARAMETER ;
}
/*
* According to MS - SMB2 : 3.3 .5 .9 .7 , " Handling the
* SMB2_CREATE_DURABLE_HANDLE_RECONNECT Create Context " ,
* we should ignore an additional dhnq blob , but fail
* the request ( with status OBJECT_NAME_NOT_FOUND ) if
* any other extra create blob has been provided .
*
* ( Note that the cases of an additional dh2q or dh2c blob
* which require a different error code , have been treated
* above . )
*/
if ( state - > dhnq ! = NULL ) {
num_blobs_allowed = 2 ;
} else {
num_blobs_allowed = 1 ;
}
if ( state - > rqls ! = NULL ) {
num_blobs_allowed + = 1 ;
}
if ( in_context_blobs - > num_blobs ! = num_blobs_allowed ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
}
if ( state - > dh2c ! = NULL ) {
uint32_t num_blobs_allowed ;
if ( state - > dh2c - > data . length ! = 36 ) {
return NT_STATUS_INVALID_PARAMETER ;
}
/*
* According to MS - SMB2 : 3.3 .5 .9 .12 , " Handling the
* SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 Create Context " ,
* we should fail the request with status
* OBJECT_NAME_NOT_FOUND if any other create blob has been
* provided .
*
* ( Note that the cases of an additional dhnq , dhnc or dh2q
* blob which require a different error code , have been
* treated above . )
*/
num_blobs_allowed = 1 ;
if ( state - > rqls ! = NULL ) {
num_blobs_allowed + = 1 ;
}
if ( in_context_blobs - > num_blobs ! = num_blobs_allowed ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
}
state - > exta = smb2_create_blob_find ( in_context_blobs ,
SMB2_CREATE_TAG_EXTA ) ;
state - > mxac = smb2_create_blob_find ( in_context_blobs ,
SMB2_CREATE_TAG_MXAC ) ;
state - > secd = smb2_create_blob_find ( in_context_blobs ,
SMB2_CREATE_TAG_SECD ) ;
state - > alsi = smb2_create_blob_find ( in_context_blobs ,
SMB2_CREATE_TAG_ALSI ) ;
state - > twrp = smb2_create_blob_find ( in_context_blobs ,
SMB2_CREATE_TAG_TWRP ) ;
state - > qfid = smb2_create_blob_find ( in_context_blobs ,
SMB2_CREATE_TAG_QFID ) ;
if ( state - > smb2req - > xconn - > protocol > = PROTOCOL_SMB3_02 ) {
/*
* This was introduced with SMB3_02
*/
state - > svhdx = smb2_create_blob_find (
in_context_blobs , SVHDX_OPEN_DEVICE_CONTEXT ) ;
}
return NT_STATUS_OK ;
}
2017-07-20 17:14:31 +03:00
static void smbd_smb2_create_before_exec ( struct tevent_req * req ) ;
2017-07-20 17:14:31 +03:00
static void smbd_smb2_create_after_exec ( struct tevent_req * req ) ;
2017-07-20 12:29:46 +03:00
static void smbd_smb2_create_finish ( struct tevent_req * req ) ;
2017-07-19 20:04:46 +03:00
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 ;
2017-07-21 19:59:55 +03:00
struct smb_filename * smb_fname = NULL ;
uint32_t ucf_flags ;
2009-08-12 22:39:58 +04:00
2017-06-09 13:30:33 +03:00
req = tevent_req_create ( mem_ctx , & state ,
2009-06-05 23:06:27 +04:00
struct smbd_smb2_create_state ) ;
2017-06-09 13:30:33 +03:00
if ( req = = NULL ) {
return NULL ;
}
2017-07-20 07:49:46 +03:00
* state = ( struct smbd_smb2_create_state ) {
2017-07-21 17:23:53 +03:00
. ev = ev ,
2017-07-20 07:49:46 +03:00
. smb2req = smb2req ,
2017-07-22 19:43:33 +03:00
. in_oplock_level = in_oplock_level ,
2017-07-22 19:47:17 +03:00
. in_create_disposition = in_create_disposition ,
2017-07-20 07:49:46 +03:00
} ;
2009-05-28 02:07:26 +04:00
2017-06-09 13:30:33 +03:00
smb1req = smbd_smb2_fake_smb_request ( smb2req ) ;
if ( tevent_req_nomem ( smb1req , req ) ) {
2017-07-21 17:23:53 +03:00
return tevent_req_post ( req , state - > ev ) ;
2017-06-09 13:30:33 +03:00
}
state - > smb1req = smb1req ;
if ( smb2req - > subreq = = NULL ) {
2017-07-22 20:34:25 +03:00
DBG_DEBUG ( " name [%s] \n " , in_name ) ;
2010-04-23 10:52:19 +04:00
} else {
2017-06-09 13:30:33 +03:00
struct smbd_smb2_create_state * old_state = tevent_req_data (
smb2req - > subreq , struct smbd_smb2_create_state ) ;
2017-07-22 20:34:25 +03:00
DBG_DEBUG ( " reentrant for file %s \n " , in_name ) ;
2017-06-09 13:30:33 +03:00
state - > id = old_state - > id ;
state - > request_time = old_state - > request_time ;
state - > open_rec = talloc_move ( state , & old_state - > open_rec ) ;
state - > open_was_deferred = old_state - > open_was_deferred ;
2009-05-28 02:07:26 +04:00
}
2017-06-09 13:30:33 +03:00
TALLOC_FREE ( smb2req - > subreq ) ;
smb2req - > subreq = req ;
2017-07-22 19:40:16 +03:00
if ( lp_fake_oplocks ( SNUM ( smb2req - > tcon - > compat ) ) ) {
state - > requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE ;
} else {
2017-07-22 19:43:33 +03:00
state - > requested_oplock_level = state - > in_oplock_level ;
2017-07-22 19:40:16 +03:00
}
2017-07-20 07:03:34 +03:00
/* these are ignored for SMB2 */
in_create_options & = ~ ( 0x10 ) ; /* NTCREATEX_OPTIONS_SYNC_ALERT */
in_create_options & = ~ ( 0x20 ) ; /* NTCREATEX_OPTIONS_ASYNC_ALERT */
in_file_attributes & = ~ FILE_FLAG_POSIX_SEMANTICS ;
2017-07-21 19:02:05 +03:00
state - > fname = talloc_strdup ( state , in_name ) ;
if ( tevent_req_nomem ( state - > fname , req ) ) {
2017-07-20 07:03:34 +03:00
return tevent_req_post ( req , state - > ev ) ;
}
2014-11-28 13:44:09 +03:00
state - > out_context_blobs = talloc_zero ( state , struct smb2_create_blobs ) ;
if ( tevent_req_nomem ( state - > out_context_blobs , req ) ) {
2017-07-21 17:23:53 +03:00
return tevent_req_post ( req , state - > ev ) ;
2014-11-28 13:44:09 +03:00
}
2017-07-20 13:51:37 +03:00
status = smbd_smb2_create_fetch_create_ctx ( req , & in_context_blobs ) ;
if ( tevent_req_nterror ( req , status ) ) {
2017-07-21 17:23:53 +03:00
return tevent_req_post ( req , state - > ev ) ;
2013-09-25 22:39:17 +04:00
}
2012-08-28 11:33:51 +04:00
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 ;
2017-07-20 13:15:19 +03:00
if ( state - > dhnc ! = NULL | | state - > dh2c ! = NULL ) {
2012-06-08 19:54:19 +04:00
/* durable handles are not supported on IPC$ */
tevent_req_nterror ( req , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
2017-07-21 17:23:53 +03:00
return tevent_req_post ( req , state - > ev ) ;
2012-06-08 19:54:19 +04:00
}
2009-06-05 12:46:30 +04:00
if ( ! lp_nt_pipe_support ( ) ) {
2010-04-23 21:53:44 +04:00
tevent_req_nterror ( req , NT_STATUS_ACCESS_DENIED ) ;
2017-07-21 17:23:53 +03:00
return tevent_req_post ( req , state - > ev ) ;
2009-06-05 12:46:30 +04:00
}
2017-07-22 16:31:05 +03:00
status = open_np_file ( smb1req , pipe_name , & state - > 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 ) ;
2017-07-21 17:23:53 +03:00
return tevent_req_post ( req , state - > ev ) ;
2009-06-05 12:46:30 +04:00
}
2017-07-22 19:49:50 +03:00
state - > info = FILE_WAS_OPENED ;
2017-07-19 20:04:46 +03:00
2017-07-20 12:29:46 +03:00
smbd_smb2_create_finish ( req ) ;
2017-07-19 20:04:46 +03:00
return req ;
2010-04-23 10:52:19 +04:00
} else if ( CAN_PRINT ( smb1req - > conn ) ) {
2017-07-20 13:15:19 +03:00
if ( state - > dhnc ! = NULL | | state - > dh2c ! = NULL ) {
2012-06-08 19:54:19 +04:00
/* durable handles are not supported on printers */
tevent_req_nterror ( req , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
2017-07-21 17:23:53 +03:00
return tevent_req_post ( req , state - > ev ) ;
2012-06-08 19:54:19 +04:00
}
2017-07-22 16:31:05 +03:00
status = file_new ( smb1req , smb1req - > conn , & state - > 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 ) ;
2017-07-21 17:23:53 +03:00
return tevent_req_post ( req , state - > ev ) ;
2009-06-02 18:07:53 +04:00
}
2009-05-28 02:07:26 +04:00
2017-07-22 16:31:05 +03:00
status = print_spool_open ( state - > result , in_name ,
2010-05-04 12:28:48 +04:00
smb1req - > vuid ) ;
2009-06-02 18:07:53 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2017-07-22 16:31:05 +03:00
file_free ( smb1req , state - > result ) ;
2010-04-23 21:53:44 +04:00
tevent_req_nterror ( req , status ) ;
2017-07-21 17:23:53 +03:00
return tevent_req_post ( req , state - > ev ) ;
2009-06-02 18:07:53 +04:00
}
2017-07-22 19:49:50 +03:00
state - > info = FILE_WAS_CREATED ;
2017-07-19 20:04:46 +03:00
2017-07-20 12:29:46 +03:00
smbd_smb2_create_finish ( req ) ;
2017-07-19 20:04:46 +03:00
return req ;
2017-07-19 20:07:55 +03:00
}
2017-07-19 20:04:46 +03:00
2017-07-20 17:14:31 +03:00
smbd_smb2_create_before_exec ( req ) ;
if ( ! tevent_req_is_in_progress ( req ) ) {
return tevent_req_post ( req , state - > ev ) ;
}
2009-06-04 14:17:37 +04:00
2017-07-22 20:34:25 +03:00
DBG_DEBUG ( " open execution phase \n " ) ;
2015-11-04 20:34:57 +03:00
2017-07-20 17:14:31 +03:00
/*
* For the backend file open procedure , there are
* three possible modes : replay operation ( in which case
* there is nothing else to do ) , durable_reconnect or
* new open .
*/
if ( state - > replay_operation ) {
state - > result = state - > op - > compat ;
state - > result - > op = state - > op ;
state - > update_open = false ;
state - > info = state - > op - > create_action ;
2017-07-21 19:59:55 +03:00
smbd_smb2_create_after_exec ( req ) ;
if ( ! tevent_req_is_in_progress ( req ) ) {
return req ;
}
smbd_smb2_create_finish ( req ) ;
return req ;
2017-07-20 17:14:31 +03:00
} else if ( state - > do_durable_reconnect ) {
DATA_BLOB new_cookie = data_blob_null ;
NTTIME now = timeval_to_nttime ( & smb2req - > request_time ) ;
2013-07-10 03:02:50 +04:00
2017-07-20 17:14:31 +03:00
status = smb2srv_open_recreate ( smb2req - > xconn ,
smb1req - > conn - > session_info ,
state - > persistent_id ,
state - > create_guid ,
now ,
& state - > op ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2017-07-22 20:34:25 +03:00
DBG_NOTICE ( " smb2srv_open_recreate failed: %s \n " ,
nt_errstr ( status ) ) ;
2017-07-20 17:14:31 +03:00
tevent_req_nterror ( req , status ) ;
2017-07-19 20:07:55 +03:00
return tevent_req_post ( req , state - > ev ) ;
2009-08-15 13:52:37 +04:00
}
2017-07-22 20:34:25 +03:00
DBG_DEBUG ( " %s to recreate durable handle \n " ,
state - > op - > global - > durable ? " succeeded " : " failed " ) ;
2017-07-19 20:07:55 +03:00
2017-07-20 17:14:31 +03:00
if ( ! state - > op - > global - > durable ) {
talloc_free ( state - > op ) ;
tevent_req_nterror ( req ,
NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
2017-07-19 20:07:55 +03:00
return tevent_req_post ( req , state - > ev ) ;
2009-08-15 13:52:37 +04:00
}
2017-07-20 17:14:31 +03:00
status = SMB_VFS_DURABLE_RECONNECT ( smb1req - > conn ,
smb1req ,
state - > op , /* smbXsrv_open input */
state - > op - > global - > backend_cookie ,
state - > op , /* TALLOC_CTX */
& state - > result ,
& new_cookie ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
NTSTATUS return_status ;
2009-08-15 13:52:37 +04:00
2017-07-20 17:14:31 +03:00
return_status = NT_STATUS_OBJECT_NAME_NOT_FOUND ;
2017-07-22 20:34:25 +03:00
DBG_NOTICE ( " durable_reconnect failed: %s => %s \n " ,
nt_errstr ( status ) ,
nt_errstr ( return_status ) ) ;
2017-07-20 17:14:31 +03:00
tevent_req_nterror ( req , return_status ) ;
2017-07-19 20:07:55 +03:00
return tevent_req_post ( req , state - > ev ) ;
}
2009-08-15 13:52:37 +04:00
2017-07-22 20:34:25 +03:00
DBG_DEBUG ( " oplock_type=%u, lease_ptr==%p \n " ,
( unsigned ) state - > result - > oplock_type , state - > lease_ptr ) ;
2017-07-20 17:14:31 +03:00
status = smbd_smb2_create_durable_lease_check (
smb1req , state - > fname , state - > result , state - > lease_ptr ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
close_file ( smb1req , state - > result , SHUTDOWN_CLOSE ) ;
tevent_req_nterror ( req , status ) ;
2017-07-19 20:07:55 +03:00
return tevent_req_post ( req , state - > ev ) ;
2009-08-15 13:52:37 +04:00
}
2017-07-20 17:14:31 +03:00
data_blob_free ( & state - > op - > global - > backend_cookie ) ;
state - > op - > global - > backend_cookie = new_cookie ;
2012-06-15 15:37:26 +04:00
2017-07-20 17:14:31 +03:00
state - > op - > status = NT_STATUS_OK ;
state - > op - > global - > disconnect_time = 0 ;
2012-06-15 15:37:26 +04:00
2017-07-20 17:14:31 +03:00
/* save the timout for later update */
state - > durable_timeout_msec = state - > op - > global - > durable_timeout_msec ;
2012-06-08 19:54:19 +04:00
2017-07-20 17:14:31 +03:00
state - > update_open = true ;
2012-06-15 15:37:26 +04:00
2017-07-20 17:14:31 +03:00
state - > info = FILE_WAS_OPENED ;
2012-06-15 15:37:26 +04:00
2017-07-21 19:59:55 +03:00
smbd_smb2_create_after_exec ( req ) ;
if ( ! tevent_req_is_in_progress ( req ) ) {
return req ;
2017-07-19 20:07:55 +03:00
}
2017-07-21 19:02:05 +03:00
2017-07-21 19:59:55 +03:00
smbd_smb2_create_finish ( req ) ;
return req ;
}
2012-06-15 15:37:26 +04:00
2017-07-21 19:59:55 +03:00
if ( state - > requested_oplock_level = = SMB2_OPLOCK_LEVEL_LEASE ) {
if ( state - > lease_ptr = = NULL ) {
state - > requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE ;
2017-07-20 17:14:31 +03:00
}
2017-07-21 19:59:55 +03:00
} else {
state - > lease_ptr = NULL ;
}
/*
* For a DFS path the function parse_dfs_path ( )
* will do the path processing .
*/
2016-02-26 15:53:25 +03:00
2017-07-21 19:59:55 +03:00
if ( ! ( smb1req - > flags2 & FLAGS2_DFS_PATHNAMES ) ) {
/* convert '\\' into '/' */
status = check_path_syntax ( state - > fname ) ;
2017-07-20 17:14:31 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , state - > ev ) ;
2017-07-19 20:07:55 +03:00
}
2017-07-21 19:59:55 +03:00
}
2016-02-28 04:32:36 +03:00
2017-07-21 19:59:55 +03:00
ucf_flags = filename_create_ucf_flags (
smb1req , state - > in_create_disposition ) ;
status = filename_convert ( req ,
smb1req - > conn ,
state - > fname ,
ucf_flags ,
NULL , /* ppath_contains_wcards */
& smb_fname ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , state - > ev ) ;
}
2017-07-19 20:07:55 +03:00
2017-07-21 19:59:55 +03:00
/*
* MS - SMB2 : 2.2 .13 SMB2 CREATE Request
* ImpersonationLevel . . . MUST contain one of the
* following values . The server MUST validate this
* field , but otherwise ignore it .
*
* NB . The source4 / torture / smb2 / durable_open . c test
* shows this check is only done on real opens , not
* on durable handle - reopens .
*/
2017-07-20 17:14:31 +03:00
2017-07-21 19:59:55 +03:00
if ( in_impersonation_level >
SMB2_IMPERSONATION_DELEGATE ) {
tevent_req_nterror ( req ,
NT_STATUS_BAD_IMPERSONATION_LEVEL ) ;
return tevent_req_post ( req , state - > ev ) ;
}
2012-06-15 15:37:26 +04:00
2017-07-21 19:59:55 +03:00
/*
* We know we ' re going to do a local open , so now
* we must be protocol strict . JRA .
*
* MS - SMB2 : 3.3 .5 .9 - Receiving an SMB2 CREATE Request
* If the file name length is greater than zero and the
* first character is a path separator character , the
* server MUST fail the request with
* STATUS_INVALID_PARAMETER .
*/
if ( in_name [ 0 ] = = ' \\ ' | | in_name [ 0 ] = = ' / ' ) {
tevent_req_nterror ( req ,
NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , state - > ev ) ;
}
status = SMB_VFS_CREATE_FILE ( smb1req - > conn ,
smb1req ,
0 , /* root_dir_fid */
smb_fname ,
in_desired_access ,
in_share_access ,
state - > in_create_disposition ,
in_create_options ,
in_file_attributes ,
map_smb2_oplock_levels_to_samba (
state - > requested_oplock_level ) ,
state - > lease_ptr ,
state - > allocation_size ,
0 , /* private_flags */
state - > sec_desc ,
state - > ea_list ,
& state - > result ,
& state - > info ,
& in_context_blobs ,
state - > out_context_blobs ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
if ( open_was_deferred ( smb1req - > xconn , smb1req - > mid ) ) {
SMBPROFILE_IOBYTES_ASYNC_SET_IDLE ( smb2req - > profile ) ;
return req ;
2017-07-20 17:14:31 +03:00
}
2017-07-21 19:59:55 +03:00
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , state - > ev ) ;
2017-07-19 20:07:55 +03:00
}
2017-07-21 19:59:55 +03:00
state - > op = state - > result - > op ;
2012-06-15 15:37:26 +04:00
2017-07-20 17:14:31 +03:00
smbd_smb2_create_after_exec ( req ) ;
if ( ! tevent_req_is_in_progress ( req ) ) {
return req ;
2017-07-20 17:14:31 +03:00
}
2016-02-28 04:32:36 +03:00
2017-07-20 17:14:31 +03:00
smbd_smb2_create_finish ( req ) ;
return req ;
}
static void smbd_smb2_create_before_exec ( struct tevent_req * req )
{
struct smbd_smb2_create_state * state = tevent_req_data (
req , struct smbd_smb2_create_state ) ;
struct smb_request * smb1req = state - > smb1req ;
struct smbd_smb2_request * smb2req = state - > smb2req ;
NTSTATUS status ;
if ( state - > exta ! = NULL ) {
if ( ! lp_ea_support ( SNUM ( smb2req - > tcon - > compat ) ) ) {
tevent_req_nterror ( req , NT_STATUS_EAS_NOT_SUPPORTED ) ;
return ;
2014-10-29 01:31:46 +03:00
}
2017-07-20 17:14:31 +03:00
state - > ea_list = read_nttrans_ea_list (
state ,
( const char * ) state - > exta - > data . data ,
state - > exta - > data . length ) ;
if ( state - > ea_list = = NULL ) {
DEBUG ( 10 , ( " smbd_smb2_create_send: read_ea_name_list failed. \n " ) ) ;
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return ;
2017-07-19 20:07:55 +03:00
}
2012-06-08 19:54:19 +04:00
/*
2017-07-20 17:14:31 +03:00
* NB . When SMB2 + unix extensions are added ,
* we need to relax this check in invalid
* names - we used to not do this if
* lp_posix_pathnames ( ) was false .
2010-05-22 03:56:10 +04:00
*/
2017-07-20 17:14:31 +03:00
if ( ea_list_has_invalid_name ( state - > ea_list ) ) {
tevent_req_nterror ( req , STATUS_INVALID_EA_NAME ) ;
return ;
2017-07-19 20:07:55 +03:00
}
}
2012-06-08 19:54:19 +04:00
2017-07-20 17:14:31 +03:00
if ( state - > mxac ! = NULL ) {
if ( state - > mxac - > data . length = = 0 ) {
state - > max_access_time = 0 ;
} else if ( state - > mxac - > data . length = = 8 ) {
state - > max_access_time = BVAL ( state - > mxac - > data . data , 0 ) ;
} else {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return ;
2017-07-19 20:07:55 +03:00
}
2017-07-20 17:14:31 +03:00
}
2012-06-08 19:54:19 +04:00
2017-07-20 17:14:31 +03:00
if ( state - > secd ! = NULL ) {
enum ndr_err_code ndr_err ;
2012-06-08 19:54:19 +04:00
2017-07-20 17:14:31 +03:00
state - > sec_desc = talloc_zero ( state , struct security_descriptor ) ;
if ( tevent_req_nomem ( state - > sec_desc , req ) ) {
return ;
2017-07-19 20:07:55 +03:00
}
2012-06-08 19:54:19 +04:00
2017-07-20 17:14:31 +03:00
ndr_err = ndr_pull_struct_blob ( & state - > secd - > data ,
state - > sec_desc , state - > sec_desc ,
( 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 ) ) ) ;
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return ;
2017-07-19 20:07:55 +03:00
}
2017-07-20 17:14:31 +03:00
}
2012-06-08 19:54:19 +04:00
2017-07-20 17:14:31 +03:00
if ( state - > dhnq ! = NULL ) {
if ( state - > dhnq - > data . length ! = 16 ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return ;
2017-07-19 20:07:55 +03:00
}
2009-08-08 12:47:11 +04:00
2017-07-20 17:14:31 +03:00
if ( state - > dh2q ! = NULL ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return ;
2017-07-19 20:07:55 +03:00
}
2014-06-17 01:13:02 +04:00
2017-07-19 20:07:55 +03:00
/*
2017-07-20 17:14:31 +03:00
* durable handle request is processed below .
2017-07-19 20:07:55 +03:00
*/
2017-07-20 17:14:31 +03:00
state - > durable_requested = true ;
2012-06-08 19:54:19 +04:00
/*
2017-07-20 17:14:31 +03:00
* Set the timeout to 16 mins .
2017-07-19 20:07:55 +03:00
*
2017-07-20 17:14:31 +03:00
* TODO : test this against Windows 2012
* as the default for durable v2 is 1 min .
2012-06-08 19:54:19 +04:00
*/
2017-07-20 17:14:31 +03:00
state - > durable_timeout_msec = ( 16 * 60 * 1000 ) ;
}
2012-06-08 19:54:19 +04:00
2017-07-20 17:14:31 +03:00
if ( state - > dh2q ! = NULL ) {
const uint8_t * p = state - > dh2q - > data . data ;
uint32_t durable_v2_timeout = 0 ;
DATA_BLOB create_guid_blob ;
const uint8_t * hdr ;
uint32_t flags ;
2009-08-15 13:52:37 +04:00
2017-07-20 17:14:31 +03:00
if ( state - > dh2q - > data . length ! = 32 ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return ;
2012-06-08 19:54:19 +04:00
}
2017-07-20 17:14:31 +03:00
if ( state - > dhnq ! = NULL ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return ;
2012-06-08 19:54:19 +04:00
}
2017-07-20 17:14:31 +03:00
durable_v2_timeout = IVAL ( p , 0 ) ;
create_guid_blob = data_blob_const ( p + 16 , 16 ) ;
2012-06-08 19:54:19 +04:00
2017-07-20 17:14:31 +03:00
status = GUID_from_ndr_blob ( & create_guid_blob ,
& state - > _create_guid ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
state - > create_guid = & state - > _create_guid ;
2012-06-08 19:54:19 +04:00
2017-07-20 17:14:31 +03:00
/*
* we need to store the create_guid later
*/
state - > update_open = true ;
2017-07-19 20:07:55 +03:00
2017-07-20 17:14:31 +03:00
/*
* And we need to create a cache for replaying the
* create .
*/
state - > need_replay_cache = true ;
2012-06-08 19:54:19 +04:00
2017-07-20 17:14:31 +03:00
/*
* durable handle v2 request processed below
*/
state - > durable_requested = true ;
state - > durable_timeout_msec = durable_v2_timeout ;
if ( state - > durable_timeout_msec = = 0 ) {
/*
* Set the timeout to 1 min as default .
*
* This matches Windows 2012.
*/
state - > durable_timeout_msec = ( 60 * 1000 ) ;
}
2017-07-19 20:07:55 +03:00
2017-07-20 17:14:31 +03:00
/*
* Check for replay operation .
* Only consider it when we have dh2q .
* If we do not have a replay operation , verify that
* the create_guid is not cached for replay .
*/
hdr = SMBD_SMB2_IN_HDR_PTR ( smb2req ) ;
flags = IVAL ( hdr , SMB2_HDR_FLAGS ) ;
state - > replay_operation =
flags & SMB2_HDR_FLAG_REPLAY_OPERATION ;
2017-07-19 20:07:55 +03:00
2017-07-20 17:14:31 +03:00
status = smb2srv_open_lookup_replay_cache ( smb2req - > xconn ,
state - > create_guid ,
0 /* now */ ,
& state - > op ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NOT_FOUND ) ) {
state - > replay_operation = false ;
} else if ( tevent_req_nterror ( req , status ) ) {
DBG_WARNING ( " smb2srv_open_lookup_replay_cache "
" failed: %s \n " , nt_errstr ( status ) ) ;
return ;
} else if ( ! state - > replay_operation ) {
/*
* If a create without replay operation flag
* is sent but with a create_guid that is
* currently in the replay cache - - fail .
*/
status = NT_STATUS_DUPLICATE_OBJECTID ;
( void ) tevent_req_nterror ( req , status ) ;
return ;
2012-06-08 19:54:19 +04:00
}
2017-07-19 20:07:55 +03:00
}
2012-06-08 19:54:19 +04:00
2017-07-20 17:14:31 +03:00
if ( state - > dhnc ! = NULL ) {
state - > persistent_id = BVAL ( state - > dhnc - > data . data , 0 ) ;
state - > do_durable_reconnect = true ;
2017-07-19 20:07:55 +03:00
}
2012-06-15 15:37:26 +04:00
2017-07-20 17:14:31 +03:00
if ( state - > dh2c ! = NULL ) {
const uint8_t * p = state - > dh2c - > data . data ;
DATA_BLOB create_guid_blob ;
2012-06-15 15:37:26 +04:00
2017-07-20 17:14:31 +03:00
state - > persistent_id = BVAL ( p , 0 ) ;
create_guid_blob = data_blob_const ( p + 16 , 16 ) ;
2012-06-15 15:37:26 +04:00
2017-07-20 17:14:31 +03:00
status = GUID_from_ndr_blob ( & create_guid_blob ,
& state - > _create_guid ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
2017-07-19 20:07:55 +03:00
}
2009-08-15 13:52:37 +04:00
2017-07-20 17:14:31 +03:00
state - > create_guid = & state - > _create_guid ;
state - > do_durable_reconnect = true ;
}
2009-08-15 13:52:37 +04:00
2017-07-20 17:14:31 +03:00
if ( state - > alsi ! = NULL ) {
if ( state - > alsi - > data . length ! = 8 ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return ;
2017-07-19 20:07:55 +03:00
}
2017-07-20 17:14:31 +03:00
state - > allocation_size = BVAL ( state - > alsi - > data . data , 0 ) ;
2017-07-19 20:07:55 +03:00
}
2009-08-15 13:52:37 +04:00
2017-07-20 17:14:31 +03:00
if ( state - > twrp ! = NULL ) {
NTTIME nttime ;
time_t t ;
struct tm * tm ;
char * tmpname = state - > fname ;
2017-07-19 20:07:55 +03:00
2017-07-20 17:14:31 +03:00
if ( state - > twrp - > data . length ! = 8 ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return ;
}
2017-07-19 20:07:55 +03:00
2017-07-20 17:14:31 +03:00
nttime = BVAL ( state - > twrp - > data . data , 0 ) ;
t = nt_time_to_unix ( nttime ) ;
tm = gmtime ( & t ) ;
state - > fname = talloc_asprintf (
state ,
" %s \\ @GMT-%04u.%02u.%02u-%02u.%02u.%02u " ,
state - > fname ,
tm - > tm_year + 1900 ,
tm - > tm_mon + 1 ,
tm - > tm_mday ,
tm - > tm_hour ,
tm - > tm_min ,
tm - > tm_sec ) ;
if ( tevent_req_nomem ( state - > fname , req ) ) {
return ;
2009-08-15 13:52:37 +04:00
}
2017-07-20 17:14:31 +03:00
TALLOC_FREE ( tmpname ) ;
/*
* Tell filename_create_ucf_flags ( ) this
* is an @ GMT path .
*/
smb1req - > flags2 | = FLAGS2_REPARSE_PATH ;
2017-07-19 20:07:55 +03:00
}
2014-10-29 01:31:46 +03:00
2017-07-20 13:15:19 +03:00
if ( state - > qfid ! = NULL ) {
2017-07-20 17:14:31 +03:00
if ( state - > qfid - > data . length ! = 0 ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return ;
2017-07-19 20:07:55 +03:00
}
}
2014-10-29 01:31:46 +03:00
2017-07-20 17:14:31 +03:00
if ( state - > rqls ! = NULL ) {
ssize_t lease_len = - 1 ;
2014-10-29 01:31:46 +03:00
2017-07-20 17:14:31 +03:00
lease_len = smb2_lease_pull ( state - > rqls - > data . data ,
state - > rqls - > data . length ,
& state - > lease ) ;
if ( lease_len = = - 1 ) {
tevent_req_nterror (
req , NT_STATUS_INVALID_PARAMETER ) ;
return ;
}
state - > lease_ptr = & state - > lease ;
2014-10-29 01:31:46 +03:00
2017-07-20 17:14:31 +03:00
if ( DEBUGLEVEL > = 10 ) {
DEBUG ( 10 , ( " Got lease request size %d \n " ,
( int ) lease_len ) ) ;
NDR_PRINT_DEBUG ( smb2_lease , state - > lease_ptr ) ;
2017-07-19 20:07:55 +03:00
}
2014-10-29 01:31:46 +03:00
2017-07-20 17:14:31 +03:00
if ( ! smb2_lease_key_valid ( & state - > lease . lease_key ) ) {
state - > lease_ptr = NULL ;
state - > requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE ;
2017-07-19 20:07:55 +03:00
}
2017-07-20 17:14:31 +03:00
if ( ( smb2req - > xconn - > protocol < PROTOCOL_SMB3_00 ) & &
( state - > lease . lease_version ! = 1 ) )
{
DEBUG ( 10 , ( " v2 lease key only for SMB3 \n " ) ) ;
state - > lease_ptr = NULL ;
}
/*
* Replay with a lease is only allowed if the
* established open carries a lease with the
* same lease key .
*/
if ( state - > replay_operation ) {
struct smb2_lease * op_ls =
& state - > op - > compat - > lease - > lease ;
int op_oplock = state - > op - > compat - > oplock_type ;
if ( map_samba_oplock_levels_to_smb2 ( op_oplock )
! = SMB2_OPLOCK_LEVEL_LEASE )
{
status = NT_STATUS_ACCESS_DENIED ;
( void ) tevent_req_nterror ( req , status ) ;
return ;
}
if ( ! smb2_lease_key_equal ( & state - > lease . lease_key ,
& op_ls - > lease_key ) )
{
status = NT_STATUS_ACCESS_DENIED ;
( void ) tevent_req_nterror ( req , status ) ;
return ;
}
2014-10-29 01:31:46 +03:00
}
2009-07-08 23:24:03 +04:00
}
2017-07-20 17:14:31 +03:00
return ;
2017-07-19 20:04:46 +03:00
}
2017-07-20 17:14:31 +03:00
static void smbd_smb2_create_after_exec ( struct tevent_req * req )
{
struct smbd_smb2_create_state * state = tevent_req_data (
req , struct smbd_smb2_create_state ) ;
struct smb_request * smb1req = state - > smb1req ;
NTSTATUS status ;
/*
* here we have op = = result - > op
*/
DEBUG ( 10 , ( " smbd_smb2_create_send: "
" response construction phase \n " ) ) ;
if ( state - > mxac ! = NULL ) {
NTTIME last_write_time ;
last_write_time = unix_timespec_to_nt_time (
state - > result - > fsp_name - > st . st_ex_mtime ) ;
if ( last_write_time ! = state - > max_access_time ) {
uint8_t p [ 8 ] ;
uint32_t max_access_granted ;
DATA_BLOB blob = data_blob_const ( p , sizeof ( p ) ) ;
status = smbd_calculate_access_mask ( smb1req - > conn ,
state - > result - > fsp_name ,
false ,
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 ,
state - > out_context_blobs ,
SMB2_CREATE_TAG_MXAC ,
blob ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( req , status ) ;
tevent_req_post ( req , state - > ev ) ;
return ;
}
}
}
if ( ! state - > replay_operation & & state - > durable_requested & &
( fsp_lease_type ( state - > result ) & SMB2_LEASE_HANDLE ) )
{
status = SMB_VFS_DURABLE_COOKIE (
state - > result ,
state - > op ,
& state - > op - > global - > backend_cookie ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
state - > op - > global - > backend_cookie = data_blob_null ;
}
}
if ( ! state - > replay_operation & & state - > op - > global - > backend_cookie . length > 0 )
{
state - > update_open = true ;
state - > op - > global - > durable = true ;
state - > op - > global - > durable_timeout_msec = state - > durable_timeout_msec ;
}
if ( state - > update_open ) {
state - > op - > global - > create_guid = state - > _create_guid ;
if ( state - > need_replay_cache ) {
state - > op - > flags | = SMBXSRV_OPEN_NEED_REPLAY_CACHE ;
}
status = smbXsrv_open_update ( state - > op ) ;
DEBUG ( 10 , ( " smb2_create_send: smbXsrv_open_update "
" returned %s \n " ,
nt_errstr ( status ) ) ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( req , status ) ;
tevent_req_post ( req , state - > ev ) ;
return ;
}
}
if ( state - > dhnq ! = NULL & & state - > op - > global - > durable ) {
uint8_t p [ 8 ] = { 0 , } ;
DATA_BLOB blob = data_blob_const ( p , sizeof ( p ) ) ;
status = smb2_create_blob_add ( state - > out_context_blobs ,
state - > out_context_blobs ,
SMB2_CREATE_TAG_DHNQ ,
blob ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( req , status ) ;
tevent_req_post ( req , state - > ev ) ;
return ;
}
}
if ( state - > dh2q ! = NULL & & state - > op - > global - > durable & &
/*
* For replay operations , we return the dh2q blob
* in the case of oplocks not based on the state of
* the open , but on whether it could have been granted
* for the request data . In the case of leases instead ,
* the state of the open is used . . .
*/
( ! state - > replay_operation | |
state - > in_oplock_level = = SMB2_OPLOCK_LEVEL_BATCH | |
state - > in_oplock_level = = SMB2_OPLOCK_LEVEL_LEASE ) )
{
uint8_t p [ 8 ] = { 0 , } ;
DATA_BLOB blob = data_blob_const ( p , sizeof ( p ) ) ;
uint32_t durable_v2_response_flags = 0 ;
SIVAL ( p , 0 , state - > op - > global - > durable_timeout_msec ) ;
SIVAL ( p , 4 , durable_v2_response_flags ) ;
status = smb2_create_blob_add ( state - > out_context_blobs ,
state - > out_context_blobs ,
SMB2_CREATE_TAG_DH2Q ,
blob ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( req , status ) ;
tevent_req_post ( req , state - > ev ) ;
return ;
}
}
if ( state - > qfid ! = NULL ) {
uint8_t p [ 32 ] ;
uint64_t file_index = get_FileIndex ( state - > result - > conn ,
& state - > result - > fsp_name - > st ) ;
DATA_BLOB blob = data_blob_const ( p , sizeof ( p ) ) ;
ZERO_STRUCT ( p ) ;
/* 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 , state - > result - > fsp_name - > st . st_ex_dev ) ; /* FileIndexHigh */
status = smb2_create_blob_add ( state - > out_context_blobs ,
state - > out_context_blobs ,
SMB2_CREATE_TAG_QFID ,
blob ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( req , status ) ;
tevent_req_post ( req , state - > ev ) ;
return ;
}
}
if ( ( state - > rqls ! = NULL ) & & ( state - > result - > oplock_type = = LEASE_OPLOCK ) ) {
uint8_t buf [ 52 ] ;
struct smb2_lease lease ;
size_t lease_len ;
lease = state - > result - > lease - > lease ;
lease_len = sizeof ( buf ) ;
if ( lease . lease_version = = 1 ) {
lease_len = 32 ;
}
if ( ! smb2_lease_push ( & lease , buf , lease_len ) ) {
tevent_req_nterror (
req , NT_STATUS_INTERNAL_ERROR ) ;
tevent_req_post ( req , state - > ev ) ;
return ;
}
status = smb2_create_blob_add (
state , state - > out_context_blobs ,
SMB2_CREATE_TAG_RQLS ,
data_blob_const ( buf , lease_len ) ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( req , status ) ;
tevent_req_post ( req , state - > ev ) ;
return ;
}
}
return ;
}
2017-07-20 12:29:46 +03:00
static void smbd_smb2_create_finish ( struct tevent_req * req )
2017-07-19 20:04:46 +03:00
{
struct smbd_smb2_create_state * state = tevent_req_data (
req , struct smbd_smb2_create_state ) ;
2017-07-20 12:29:46 +03:00
struct smbd_smb2_request * smb2req = state - > smb2req ;
struct smb_request * smb1req = state - > smb1req ;
files_struct * result = state - > result ;
2017-07-19 20:04:46 +03:00
2010-04-23 10:52:19 +04:00
smb2req - > compat_chain_fsp = smb1req - > chain_fsp ;
2009-06-05 22:02:21 +04:00
2017-07-20 12:29:46 +03:00
if ( state - > replay_operation ) {
state - > out_oplock_level = state - > in_oplock_level ;
2016-02-28 04:32:36 +03:00
} else if ( lp_fake_oplocks ( SNUM ( smb2req - > tcon - > compat ) ) ) {
2017-07-20 12:29:46 +03:00
state - > out_oplock_level = state - > in_oplock_level ;
2010-05-20 19:13:37 +04:00
} else {
state - > out_oplock_level = map_samba_oplock_levels_to_smb2 ( result - > oplock_type ) ;
}
2010-04-24 11:29:41 +04:00
2017-07-20 12:29:46 +03:00
if ( ( state - > in_create_disposition = = FILE_SUPERSEDE )
& & ( state - > 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 {
2017-07-20 12:29:46 +03:00
state - > out_create_action = state - > info ;
2009-05-28 02:07:26 +04:00
}
2016-02-28 04:32:36 +03:00
result - > op - > create_action = state - > out_create_action ;
2009-11-18 01:55:02 +03:00
state - > out_file_attributes = dos_mode ( result - > conn ,
result - > fsp_name ) ;
2014-05-21 22:57:16 +04:00
state - > out_creation_ts = get_create_timespec ( smb1req - > conn ,
result , result - > fsp_name ) ;
state - > out_last_access_ts = result - > fsp_name - > st . st_ex_atime ;
state - > out_last_write_ts = result - > fsp_name - > st . st_ex_mtime ;
state - > out_change_ts = get_change_timespec ( smb1req - > conn ,
result , result - > fsp_name ) ;
2016-01-29 03:35:13 +03:00
if ( lp_dos_filetime_resolution ( SNUM ( smb2req - > tcon - > compat ) ) ) {
dos_filetime_timespec ( & state - > out_creation_ts ) ;
dos_filetime_timespec ( & state - > out_last_access_ts ) ;
dos_filetime_timespec ( & state - > out_last_write_ts ) ;
dos_filetime_timespec ( & state - > out_change_ts ) ;
}
2009-11-18 01:55:02 +03:00
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-06-05 23:06:27 +04:00
2017-07-21 16:34:02 +03:00
DBG_DEBUG ( " %s - %s \n " , fsp_str_dbg ( result ) , fsp_fnum_dbg ( result ) ) ;
2012-06-28 12:02:01 +04:00
2010-04-23 21:53:44 +04:00
tevent_req_done ( req ) ;
2017-07-19 20:04:46 +03:00
tevent_req_post ( req , state - > ev ) ;
return ;
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 ,
2014-05-21 22:57:16 +04:00
struct timespec * out_creation_ts ,
struct timespec * out_last_access_ts ,
struct timespec * out_last_write_ts ,
struct timespec * out_change_ts ,
2009-08-12 22:39:58 +04:00
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 ;
2014-05-21 22:57:16 +04:00
* out_creation_ts = state - > out_creation_ts ;
* out_last_access_ts = state - > out_last_access_ts ;
* out_last_write_ts = state - > out_last_write_ts ;
* out_change_ts = state - > out_change_ts ;
2009-06-05 23:06:27 +04:00
* 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 ;
2014-11-28 13:44:09 +03:00
* out_context_blobs = * ( state - > out_context_blobs ) ;
2009-08-12 22:39:58 +04:00
2014-11-28 13:44:09 +03:00
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 ,
2014-06-20 18:12:14 +04:00
struct deferred_open_record * * open_rec )
2010-04-23 10:52:19 +04:00
{
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 ;
}
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 ;
}
2012-12-14 20:39:26 +04:00
if ( ! state - > open_was_deferred ) {
return false ;
}
2010-04-23 10:52:19 +04:00
if ( p_request_time ) {
* p_request_time = state - > request_time ;
}
2014-06-20 18:12:14 +04:00
if ( open_rec ! = NULL ) {
* open_rec = state - > open_rec ;
2010-04-23 10:52:19 +04:00
}
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 (
2014-09-16 09:49:44 +04:00
struct smbXsrv_connection * xconn , uint64_t mid )
2010-04-23 10:52:19 +04:00
{
struct smbd_smb2_request * smb2req ;
2014-06-10 15:24:50 +04:00
for ( smb2req = xconn - > 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 ;
}
2014-09-16 09:49:44 +04:00
bool open_was_deferred_smb2 ( struct smbXsrv_connection * xconn , 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 ;
2014-09-16 09:49:44 +04:00
smb2req = find_open_smb2req ( xconn , 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. */
2012-09-26 05:04:20 +04:00
if ( ! state - > open_was_deferred ) {
2010-04-23 10:52:19 +04:00
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 ) ) ;
2012-09-26 05:04:20 +04:00
state - > open_was_deferred = false ;
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 (
2014-09-16 09:49:44 +04:00
struct smbXsrv_connection * xconn , uint64_t mid )
2010-04-24 00:10:15 +04:00
{
2010-06-12 16:43:12 +04:00
struct smbd_smb2_request * smb2req ;
2014-09-16 09:49:44 +04:00
smb2req = find_open_smb2req ( xconn , 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 ) ;
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 ) ) {
2014-06-11 14:15:48 +04:00
smbd_server_connection_terminate ( smb2req - > xconn ,
nt_errstr ( status ) ) ;
2010-05-11 00:58:41 +04:00
return ;
}
}
2012-06-30 00:53:31 +04:00
bool schedule_deferred_open_message_smb2 (
2014-09-16 09:49:44 +04:00
struct smbXsrv_connection * xconn , 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 ;
2014-09-16 09:49:44 +04:00
smb2req = find_open_smb2req ( xconn , 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
/* 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 ) {
2014-06-11 14:15:48 +04:00
smbd_server_connection_terminate ( smb2req - > xconn ,
2010-04-23 10:52:19 +04:00
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 ,
2018-03-22 12:54:41 +03:00
smb2req - > 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
}
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 ) ;
2014-06-20 18:12:14 +04:00
if ( is_deferred_open_async ( state - > open_rec ) ) {
2012-06-30 01:25:53 +04:00
/* Can't cancel an async create. */
return false ;
}
2010-04-24 00:10:15 +04:00
remove_deferred_open_message_smb2_internal ( smb2req , mid ) ;
2018-03-22 12:54:41 +03:00
tevent_req_defer_callback ( req , smb2req - > ev_ctx ) ;
2012-09-20 18:16:03 +04:00
tevent_req_nterror ( req , NT_STATUS_CANCELLED ) ;
2010-04-24 00:10:15 +04:00
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 ,
2014-06-20 18:12:14 +04:00
struct deferred_open_record * open_rec )
2010-04-23 10:52:19 +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 ;
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 ;
2014-06-20 18:12:14 +04:00
state - > open_rec = talloc_move ( state , & open_rec ) ;
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 ) ) ) ;
2012-09-26 05:04:20 +04:00
state - > open_was_deferred = true ;
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 ;
}