2009-05-28 00:07:26 +02:00
/*
Unix SMB / CIFS implementation .
Core SMB2 server
Copyright ( C ) Stefan Metzmacher 2009
2010-04-28 14:56:12 -07:00
Copyright ( C ) Jeremy Allison 2010
2009-05-28 00:07:26 +02: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 04:28:48 -04:00
# include "printing.h"
2011-03-22 16:57:01 +01:00
# include "smbd/smbd.h"
2009-05-28 00:07:26 +02:00
# include "smbd/globals.h"
2009-08-12 17:52:55 +02:00
# include "../libcli/smb/smb_common.h"
2010-05-28 02:19:32 +02:00
# include "../librpc/gen_ndr/ndr_security.h"
2011-04-28 17:38:09 +02:00
# include "../lib/util/tevent_ntstatus.h"
2011-12-15 11:51:20 +01:00
# include "messages.h"
2009-05-28 00:07:26 +02:00
2010-04-24 00:29:41 -07: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-10 14:23:44 -07:00
static uint8_t map_samba_oplock_levels_to_smb2 ( int oplock_type )
2010-04-24 00:29:41 -07: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-11 14:00:38 -07: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 00:29:41 -07:00
return SMB2_OPLOCK_LEVEL_II ;
} else {
return SMB2_OPLOCK_LEVEL_NONE ;
}
}
2009-06-05 21:06:27 +02:00
static struct tevent_req * smbd_smb2_create_send ( TALLOC_CTX * mem_ctx ,
2009-08-12 20:39:58 +02: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 10:53:44 -07:00
static NTSTATUS smbd_smb2_create_recv ( struct tevent_req * req ,
2009-08-12 20:39:58 +02: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-19 19:28:26 -07:00
uint64_t * out_file_id_persistent ,
2009-08-12 20:39:58 +02:00
uint64_t * out_file_id_volatile ,
struct smb2_create_blobs * out_context_blobs ) ;
2009-06-05 21:06:27 +02:00
2010-04-23 10:29:48 -07: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 00:07:26 +02:00
{
const uint8_t * inbody ;
2012-04-24 12:58:23 +02:00
const struct iovec * indyniov ;
2009-05-28 00:07:26 +02: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 20:39:58 +02: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 00:07:26 +02:00
bool ok ;
2010-04-23 10:29:48 -07:00
struct tevent_req * tsubreq ;
2009-05-28 00:07:26 +02:00
2011-09-06 14:01:43 +02: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 00:07:26 +02:00
}
2012-08-05 15:00:23 +02:00
inbody = SMBD_SMB2_IN_BODY_PTR ( smb2req ) ;
2009-05-28 00:07:26 +02: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 20:39:58 +02: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 15:00:23 +02:00
dyn_offset = SMB2_HDR_BODY + SMBD_SMB2_IN_BODY_LEN ( smb2req ) ;
2009-05-28 00:07:26 +02:00
2009-06-30 13:25:21 +02:00
if ( in_name_offset = = 0 & & in_name_length = = 0 ) {
/* This is ok */
2009-08-12 20:39:58 +02:00
name_offset = 0 ;
} else if ( in_name_offset < dyn_offset ) {
2010-04-23 10:29:48 -07:00
return smbd_smb2_request_error ( smb2req , NT_STATUS_INVALID_PARAMETER ) ;
2009-08-12 20:39:58 +02:00
} else {
name_offset = in_name_offset - dyn_offset ;
}
2012-08-05 15:00:23 +02:00
indyniov = SMBD_SMB2_IN_DYN_IOV ( smb2req ) ;
2012-04-24 12:58:23 +02:00
if ( name_offset > indyniov - > iov_len ) {
2010-04-23 10:29:48 -07:00
return smbd_smb2_request_error ( smb2req , NT_STATUS_INVALID_PARAMETER ) ;
2009-05-28 00:07:26 +02:00
}
2012-04-24 12:58:23 +02:00
name_available_length = indyniov - > iov_len - name_offset ;
2009-08-12 20:39:58 +02:00
if ( in_name_length > name_available_length ) {
2010-04-23 10:29:48 -07:00
return smbd_smb2_request_error ( smb2req , NT_STATUS_INVALID_PARAMETER ) ;
2009-05-28 00:07:26 +02:00
}
2012-04-24 12:58:23 +02:00
in_name_buffer . data = ( uint8_t * ) indyniov - > iov_base + name_offset ;
2009-05-28 00:07:26 +02:00
in_name_buffer . length = in_name_length ;
2009-08-12 20:39:58 +02: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 10:29:48 -07:00
return smbd_smb2_request_error ( smb2req , NT_STATUS_INVALID_PARAMETER ) ;
2009-08-12 20:39:58 +02:00
} else {
context_offset = in_context_offset - dyn_offset ;
}
2012-04-24 12:58:23 +02:00
if ( context_offset > indyniov - > iov_len ) {
2010-04-23 10:29:48 -07:00
return smbd_smb2_request_error ( smb2req , NT_STATUS_INVALID_PARAMETER ) ;
2009-08-12 20:39:58 +02:00
}
2012-04-24 12:58:23 +02:00
context_available_length = indyniov - > iov_len - context_offset ;
2009-08-12 20:39:58 +02:00
if ( in_context_length > context_available_length ) {
2010-04-23 10:29:48 -07:00
return smbd_smb2_request_error ( smb2req , NT_STATUS_INVALID_PARAMETER ) ;
2009-08-12 20:39:58 +02:00
}
2012-04-24 12:58:23 +02:00
in_context_buffer . data = ( uint8_t * ) indyniov - > iov_base +
context_offset ;
2009-08-12 20:39:58 +02:00
in_context_buffer . length = in_context_length ;
/*
* Now interpret the name and context buffers
*/
2010-04-23 10:29:48 -07:00
ok = convert_string_talloc ( smb2req , CH_UTF16 , CH_UNIX ,
2009-05-28 00:07:26 +02:00
in_name_buffer . data ,
in_name_buffer . length ,
& in_name_string ,
2011-03-24 10:59:41 +11:00
& in_name_string_size ) ;
2009-05-28 00:07:26 +02:00
if ( ! ok ) {
2010-04-23 10:29:48 -07:00
return smbd_smb2_request_error ( smb2req , NT_STATUS_ILLEGAL_CHARACTER ) ;
2009-05-28 00:07:26 +02:00
}
2011-09-06 14:14:52 +02: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 20:39:58 +02:00
ZERO_STRUCT ( in_context_blobs ) ;
2010-04-23 10:29:48 -07:00
status = smb2_create_blob_parse ( smb2req , in_context_buffer , & in_context_blobs ) ;
2009-08-12 20:39:58 +02:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-04-23 10:29:48 -07:00
return smbd_smb2_request_error ( smb2req , status ) ;
2009-08-12 20:39:58 +02:00
}
2010-04-23 10:29:48 -07:00
tsubreq = smbd_smb2_create_send ( smb2req ,
2011-12-12 14:15:03 +01:00
smb2req - > sconn - > ev_ctx ,
2010-04-23 10:29:48 -07:00
smb2req ,
2009-06-05 21:06:27 +02: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 20:39:58 +02:00
in_name_string ,
in_context_blobs ) ;
2010-04-23 10:29:48 -07:00
if ( tsubreq = = NULL ) {
smb2req - > subreq = NULL ;
return smbd_smb2_request_error ( smb2req , NT_STATUS_NO_MEMORY ) ;
2009-06-05 21:06:27 +02:00
}
2010-04-23 10:29:48 -07:00
tevent_req_set_callback ( tsubreq , smbd_smb2_request_create_done , smb2req ) ;
2009-06-09 22:34:14 +02:00
2011-11-14 15:50:47 +01: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 21:06:27 +02:00
}
2010-04-23 13:10:15 -07:00
static uint64_t get_mid_from_smb2req ( struct smbd_smb2_request * smb2req )
{
2012-08-05 15:00:23 +02:00
uint8_t * reqhdr = SMBD_SMB2_OUT_HDR_PTR ( smb2req ) ;
2010-04-23 13:10:15 -07:00
return BVAL ( reqhdr , SMB2_HDR_MESSAGE_ID ) ;
}
2010-04-23 10:29:48 -07:00
static void smbd_smb2_request_create_done ( struct tevent_req * tsubreq )
2009-06-05 21:06:27 +02:00
{
2010-04-23 10:29:48 -07:00
struct smbd_smb2_request * smb2req = tevent_req_callback_data ( tsubreq ,
2009-06-05 21:06:27 +02:00
struct smbd_smb2_request ) ;
DATA_BLOB outbody ;
DATA_BLOB outdyn ;
2009-07-24 10: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-19 19:28:26 -07:00
uint64_t out_file_id_persistent = 0 ;
2009-07-24 10:21:07 -04:00
uint64_t out_file_id_volatile = 0 ;
2009-08-12 20:39:58 +02:00
struct smb2_create_blobs out_context_blobs ;
DATA_BLOB out_context_buffer ;
uint16_t out_context_buffer_offset = 0 ;
2009-06-05 21:06:27 +02:00
NTSTATUS status ;
NTSTATUS error ; /* transport error */
2010-04-23 10:29:48 -07:00
status = smbd_smb2_create_recv ( tsubreq ,
smb2req ,
2009-06-05 21:06:27 +02: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-19 19:28:26 -07:00
& out_file_id_persistent ,
2009-08-12 20:39:58 +02:00
& out_file_id_volatile ,
& out_context_blobs ) ;
2009-05-28 00:07:26 +02:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-04-23 10:29:48 -07:00
error = smbd_smb2_request_error ( smb2req , status ) ;
2009-06-05 21:06:27 +02:00
if ( ! NT_STATUS_IS_OK ( error ) ) {
2010-04-23 10:29:48 -07:00
smbd_server_connection_terminate ( smb2req - > sconn ,
2009-06-05 21:06:27 +02:00
nt_errstr ( error ) ) ;
return ;
}
return ;
2009-05-28 00:07:26 +02:00
}
2010-04-23 10:29:48 -07:00
status = smb2_create_blob_push ( smb2req , & out_context_buffer , out_context_blobs ) ;
2009-08-12 20:39:58 +02:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-04-23 10:29:48 -07:00
error = smbd_smb2_request_error ( smb2req , status ) ;
2009-08-12 20:39:58 +02:00
if ( ! NT_STATUS_IS_OK ( error ) ) {
2010-04-23 10:29:48 -07:00
smbd_server_connection_terminate ( smb2req - > sconn ,
2009-08-12 20:39:58 +02:00
nt_errstr ( error ) ) ;
return ;
}
return ;
}
if ( out_context_buffer . length > 0 ) {
out_context_buffer_offset = SMB2_HDR_BODY + 0x58 ;
}
2010-04-23 10:29:48 -07:00
outbody = data_blob_talloc ( smb2req - > out . vector , NULL , 0x58 ) ;
2009-05-28 00:07:26 +02:00
if ( outbody . data = = NULL ) {
2010-04-23 10:29:48 -07:00
error = smbd_smb2_request_error ( smb2req , NT_STATUS_NO_MEMORY ) ;
2009-06-05 21:06:27 +02:00
if ( ! NT_STATUS_IS_OK ( error ) ) {
2010-04-23 10:29:48 -07:00
smbd_server_connection_terminate ( smb2req - > sconn ,
2009-06-05 21:06:27 +02:00
nt_errstr ( error ) ) ;
return ;
}
return ;
2009-05-28 00:07:26 +02: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-19 19:28:26 -07:00
SBVAL ( outbody . data , 0x40 ,
out_file_id_persistent ) ; /* file id (persistent) */
2009-05-28 00:07:26 +02:00
SBVAL ( outbody . data , 0x48 ,
out_file_id_volatile ) ; /* file id (volatile) */
2009-08-12 20:39:58 +02: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 00:07:26 +02:00
2009-08-12 20:39:58 +02:00
outdyn = out_context_buffer ;
2009-05-28 00:07:26 +02:00
2010-04-23 10:29:48 -07:00
error = smbd_smb2_request_done ( smb2req , outbody , & outdyn ) ;
2009-06-05 21:06:27 +02:00
if ( ! NT_STATUS_IS_OK ( error ) ) {
2010-04-23 10:29:48 -07:00
smbd_server_connection_terminate ( smb2req - > sconn ,
2009-06-05 21:06:27 +02:00
nt_errstr ( error ) ) ;
return ;
}
2009-05-28 00:07:26 +02:00
}
2009-06-05 21:06:27 +02:00
struct smbd_smb2_create_state {
struct smbd_smb2_request * smb2req ;
2010-04-22 23:52:19 -07:00
struct smb_request * smb1req ;
2012-09-26 03:04:20 +02:00
bool open_was_deferred ;
2013-02-18 10:18:29 +01:00
struct tevent_timer * te ;
2010-05-10 13:58:41 -07:00
struct tevent_immediate * im ;
2010-04-22 23:52:19 -07:00
struct timeval request_time ;
2010-04-23 13:10:15 -07:00
struct file_id id ;
2010-04-22 23:52:19 -07:00
DATA_BLOB private_data ;
2009-06-05 21:06:27 +02: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-19 19:28:26 -07:00
uint64_t out_file_id_persistent ;
2009-06-05 21:06:27 +02:00
uint64_t out_file_id_volatile ;
2009-08-12 20:39:58 +02:00
struct smb2_create_blobs out_context_blobs ;
2009-06-05 21:06:27 +02:00
} ;
static struct tevent_req * smbd_smb2_create_send ( TALLOC_CTX * mem_ctx ,
2009-08-12 20:39:58 +02: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 00:07:26 +02:00
{
2010-04-23 10:53:44 -07:00
struct tevent_req * req = NULL ;
2010-04-22 23:52:19 -07:00
struct smbd_smb2_create_state * state = NULL ;
2009-05-28 00:07:26 +02:00
NTSTATUS status ;
2010-04-22 23:52:19 -07:00
struct smb_request * smb1req = NULL ;
files_struct * result = NULL ;
2009-05-28 00:07:26 +02:00
int info ;
2009-11-17 14:55:02 -08:00
struct timespec write_time_ts ;
2009-08-12 20:39:58 +02:00
struct smb2_create_blobs out_context_blobs ;
2010-05-20 11:13:37 -04:00
int requested_oplock_level ;
2012-08-28 09:33:51 +02:00
struct smb2_create_blob * dhnc = NULL ;
2012-06-15 13:37:26 +02:00
struct smb2_create_blob * dh2c = NULL ;
2012-06-08 17:54:19 +02:00
struct smbXsrv_open * op = NULL ;
2009-08-12 20:39:58 +02:00
ZERO_STRUCT ( out_context_blobs ) ;
2009-05-28 00:07:26 +02:00
2012-03-27 11:09:05 +02:00
if ( lp_fake_oplocks ( SNUM ( smb2req - > tcon - > compat ) ) ) {
2010-05-21 23:59:54 -07:00
requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE ;
2010-05-20 11:13:37 -04:00
} else {
requested_oplock_level = in_oplock_level ;
}
2011-11-09 11:47:33 +01:00
if ( smb2req - > subreq = = NULL ) {
2010-04-22 23:52:19 -07:00
/* New create call. */
2010-04-23 10:53:44 -07:00
req = tevent_req_create ( mem_ctx , & state ,
2009-06-05 21:06:27 +02:00
struct smbd_smb2_create_state ) ;
2010-04-23 10:53:44 -07:00
if ( req = = NULL ) {
2010-04-22 23:52:19 -07:00
return NULL ;
}
state - > smb2req = smb2req ;
2009-05-28 00:07:26 +02:00
2010-04-22 23:52:19 -07:00
smb1req = smbd_smb2_fake_smb_request ( smb2req ) ;
2010-04-23 10:53:44 -07:00
if ( tevent_req_nomem ( smb1req , req ) ) {
return tevent_req_post ( req , ev ) ;
2010-04-22 23:52:19 -07:00
}
state - > smb1req = smb1req ;
2012-02-10 12:48:30 +01:00
smb2req - > subreq = req ;
2010-04-22 23:52:19 -07:00
DEBUG ( 10 , ( " smbd_smb2_create: name[%s] \n " ,
in_name ) ) ;
} else {
/* Re-entrant create call. */
2010-04-23 10:53:44 -07:00
req = smb2req - > subreq ;
state = tevent_req_data ( req ,
2010-04-22 23:52:19 -07: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 00:07:26 +02:00
}
2012-08-28 09:33:51 +02: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 ) ;
}
2012-06-08 17:54:19 +02:00
if ( in_context_blobs . num_blobs ! = 1 ) {
/*
* DHNC should be the only one .
*/
tevent_req_nterror ( req , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
return tevent_req_post ( req , ev ) ;
}
2012-08-28 09:33:51 +02:00
}
2012-06-15 13:37:26 +02:00
dh2c = smb2_create_blob_find ( & in_context_blobs ,
SMB2_CREATE_TAG_DH2C ) ;
if ( dh2c ) {
if ( dh2c - > data . length ! = 36 ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
}
if ( in_context_blobs . num_blobs ! = 1 ) {
/*
* DH2C should be the only one .
*/
tevent_req_nterror ( req , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
return tevent_req_post ( req , ev ) ;
}
}
2010-04-22 23:52:19 -07:00
if ( IS_IPC ( smb1req - > conn ) ) {
2009-06-05 10:46:30 +02:00
const char * pipe_name = in_name ;
2012-06-15 13:37:26 +02:00
if ( dhnc | | dh2c ) {
2012-06-08 17:54:19 +02:00
/* durable handles are not supported on IPC$ */
tevent_req_nterror ( req , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
return tevent_req_post ( req , ev ) ;
}
2009-06-05 10:46:30 +02:00
if ( ! lp_nt_pipe_support ( ) ) {
2010-04-23 10:53:44 -07:00
tevent_req_nterror ( req , NT_STATUS_ACCESS_DENIED ) ;
return tevent_req_post ( req , ev ) ;
2009-06-05 10:46:30 +02:00
}
2010-04-22 23:52:19 -07:00
status = open_np_file ( smb1req , pipe_name , & result ) ;
2009-06-05 10:46:30 +02:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-04-23 10:53:44 -07:00
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
2009-06-05 10:46:30 +02:00
}
2009-06-05 21:06:27 +02:00
info = FILE_WAS_OPENED ;
2010-04-22 23:52:19 -07:00
} else if ( CAN_PRINT ( smb1req - > conn ) ) {
2012-06-15 13:37:26 +02:00
if ( dhnc | | dh2c ) {
2012-06-08 17:54:19 +02:00
/* durable handles are not supported on printers */
tevent_req_nterror ( req , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
return tevent_req_post ( req , ev ) ;
}
2010-04-22 23:52:19 -07:00
status = file_new ( smb1req , smb1req - > conn , & result ) ;
2009-06-02 16:07:53 +02:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-04-23 10:53:44 -07:00
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
2009-06-02 16:07:53 +02:00
}
2009-05-28 00:07:26 +02:00
2010-05-04 04:28:48 -04:00
status = print_spool_open ( result , in_name ,
smb1req - > vuid ) ;
2009-06-02 16:07:53 +02:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-04-22 23:52:19 -07:00
file_free ( smb1req , result ) ;
2010-04-23 10:53:44 -07:00
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
2009-06-02 16:07:53 +02:00
}
info = FILE_WAS_CREATED ;
} else {
2009-08-11 18:31:27 +02:00
char * fname ;
2009-08-15 11:52:37 +02: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 ;
2012-06-08 17:54:19 +02:00
struct GUID create_guid = GUID_zero ( ) ;
bool update_open = false ;
bool durable_requested = false ;
uint32_t durable_timeout_msec = 0 ;
bool do_durable_reconnect = false ;
2012-06-15 13:37:26 +02:00
struct smb2_create_blob * dh2q = NULL ;
2009-08-15 11:52:37 +02:00
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 ) ;
2012-06-15 13:37:26 +02:00
dh2q = smb2_create_blob_find ( & in_context_blobs ,
SMB2_CREATE_TAG_DH2Q ) ;
2009-06-04 12:17:37 +02:00
2009-08-11 18:31:27 +02:00
fname = talloc_strdup ( state , in_name ) ;
2010-04-23 10:53:44 -07:00
if ( tevent_req_nomem ( fname , req ) ) {
return tevent_req_post ( req , ev ) ;
2009-08-11 18:31:27 +02:00
}
2009-08-15 11:52:37 +02:00
if ( exta ) {
2009-09-17 09:29:07 -07: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 10:53:44 -07:00
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
2009-09-17 09:29:07 -07:00
}
2009-08-15 11:52:37 +02: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 10:53:44 -07:00
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
2009-08-15 11:52:37 +02:00
}
}
if ( secd ) {
enum ndr_err_code ndr_err ;
sec_desc = talloc_zero ( state , struct security_descriptor ) ;
2010-04-23 10:53:44 -07:00
if ( tevent_req_nomem ( sec_desc , req ) ) {
return tevent_req_post ( req , ev ) ;
2009-08-15 11:52:37 +02:00
}
ndr_err = ndr_pull_struct_blob ( & secd - > data ,
2010-05-10 00:42:06 +02:00
sec_desc , sec_desc ,
2009-08-15 11:52:37 +02: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 10:53:44 -07:00
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
2009-08-15 11:52:37 +02:00
}
}
if ( dhnq ) {
if ( dhnq - > data . length ! = 16 ) {
2010-04-23 10:53:44 -07:00
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
2009-08-15 11:52:37 +02:00
}
2012-06-15 13:37:26 +02:00
if ( dh2q ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
}
2009-08-15 11:52:37 +02:00
/*
2012-06-08 17:54:19 +02:00
* durable handle request is processed below .
*/
durable_requested = true ;
/*
* Set the timeout to 16 mins .
*
* TODO : test this against Windows 2012
* as the default for durable v2 is 1 min .
2009-08-15 11:52:37 +02:00
*/
2012-06-08 17:54:19 +02:00
durable_timeout_msec = ( 16 * 60 * 1000 ) ;
}
2012-06-15 13:37:26 +02:00
if ( dh2q ) {
const uint8_t * p = dh2q - > data . data ;
uint32_t durable_v2_timeout = 0 ;
DATA_BLOB create_guid_blob ;
if ( dh2q - > data . length ! = 32 ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
}
if ( dhnq ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
}
durable_v2_timeout = IVAL ( p , 0 ) ;
create_guid_blob = data_blob_const ( p + 16 , 16 ) ;
status = GUID_from_ndr_blob ( & create_guid_blob ,
& create_guid ) ;
if ( tevent_req_nterror ( req , status ) ) {
return tevent_req_post ( req , ev ) ;
}
/*
* we need to store the create_guid later
*/
update_open = true ;
/*
* durable handle v2 request processed below
*/
durable_requested = true ;
durable_timeout_msec = durable_v2_timeout ;
if ( durable_timeout_msec = = 0 ) {
/*
* Set the timeout to 1 min as default .
*
* This matches Windows 2012.
*/
durable_timeout_msec = ( 60 * 1000 ) ;
}
}
2012-06-08 17:54:19 +02:00
if ( dhnc ) {
NTTIME now = timeval_to_nttime ( & smb2req - > request_time ) ;
uint64_t persistent_id ;
persistent_id = BVAL ( dhnc - > data . data , 0 ) ;
status = smb2srv_open_recreate ( smb2req - > sconn - > conn ,
smb1req - > conn - > session_info ,
persistent_id , create_guid ,
now , & op ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 3 , ( " smbd_smb2_create_send: "
" smb2srv_open_recreate v1 failed: %s \n " ,
nt_errstr ( status ) ) ) ;
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
}
DEBUG ( 10 , ( " smb2_create_send: DHNC: %s recreate the "
" smb2srv_open struct for a durable handle. \n " ,
op - > global - > durable ? " did " : " could not " ) ) ;
if ( ! op - > global - > durable ) {
talloc_free ( op ) ;
tevent_req_nterror ( req ,
NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
return tevent_req_post ( req , ev ) ;
}
do_durable_reconnect = true ;
2009-08-15 11:52:37 +02:00
}
2012-06-15 13:37:26 +02:00
if ( dh2c ) {
const uint8_t * p = dh2c - > data . data ;
NTTIME now = timeval_to_nttime ( & smb2req - > request_time ) ;
uint64_t persistent_id ;
DATA_BLOB create_guid_blob ;
persistent_id = BVAL ( p , 0 ) ;
create_guid_blob = data_blob_const ( p + 16 , 16 ) ;
status = GUID_from_ndr_blob ( & create_guid_blob ,
& create_guid ) ;
if ( tevent_req_nterror ( req , status ) ) {
return tevent_req_post ( req , ev ) ;
}
status = smb2srv_open_recreate ( smb2req - > sconn - > conn ,
smb1req - > conn - > session_info ,
persistent_id , create_guid ,
now , & op ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 3 , ( " smbd_smb2_create_send: "
" smb2srv_open_recreate v2 failed: %s \n " ,
nt_errstr ( status ) ) ) ;
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
}
DEBUG ( 10 , ( " smb2_create_send: DH2C: %s recreate the "
" smb2srv_open struct for a durable handle. \n " ,
op - > global - > durable ? " did " : " could not " ) ) ;
if ( ! op - > global - > durable ) {
talloc_free ( op ) ;
tevent_req_nterror ( req ,
NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
return tevent_req_post ( req , ev ) ;
}
do_durable_reconnect = true ;
}
2009-08-15 11:52:37 +02:00
if ( alsi ) {
if ( alsi - > data . length ! = 8 ) {
2010-04-23 10:53:44 -07:00
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
2009-08-15 11:52:37 +02: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 10:53:44 -07:00
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
2009-08-15 11:52:37 +02: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 10:53:44 -07:00
if ( tevent_req_nomem ( fname , req ) ) {
return tevent_req_post ( req , ev ) ;
2009-08-15 11:52:37 +02:00
}
}
if ( qfid ) {
if ( qfid - > data . length ! = 0 ) {
2010-04-23 10:53:44 -07:00
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
2009-08-15 11:52:37 +02:00
}
}
/* these are ignored for SMB2 */
in_create_options & = ~ ( 0x10 ) ; /* NTCREATEX_OPTIONS_SYNC_ALERT */
in_create_options & = ~ ( 0x20 ) ; /* NTCREATEX_OPTIONS_ASYNC_ALERT */
2012-06-08 17:54:19 +02:00
in_file_attributes & = ~ FILE_FLAG_POSIX_SEMANTICS ;
DEBUG ( 10 , ( " smbd_smb2_create_send: open execution phase \n " ) ) ;
/*
* For the backend file open procedure , there are
* two possible modes : durable_reconnect or not .
2010-05-21 16:56:10 -07:00
*/
2012-06-08 17:54:19 +02:00
if ( do_durable_reconnect ) {
DATA_BLOB new_cookie = data_blob_null ;
status = SMB_VFS_DURABLE_RECONNECT ( smb1req - > conn ,
smb1req ,
op ,
op - > global - > backend_cookie ,
op , & result , & new_cookie ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
NTSTATUS return_status ;
return_status = NT_STATUS_OBJECT_NAME_NOT_FOUND ;
DEBUG ( 3 , ( " smbd_smb2_create_send: "
" durable_reconnect failed: %s => %s \n " ,
nt_errstr ( status ) ,
nt_errstr ( return_status ) ) ) ;
tevent_req_nterror ( req , return_status ) ;
return tevent_req_post ( req , ev ) ;
}
data_blob_free ( & op - > global - > backend_cookie ) ;
op - > global - > backend_cookie = new_cookie ;
2010-05-21 16:56:10 -07:00
2012-06-08 17:54:19 +02:00
op - > status = NT_STATUS_OK ;
op - > global - > disconnect_time = 0 ;
2013-04-18 13:11:03 +02:00
/* save the timout for later update */
durable_timeout_msec = op - > global - > durable_timeout_msec ;
update_open = true ;
2009-08-08 10:47:11 +02:00
2012-06-08 17:54:19 +02:00
info = FILE_WAS_OPENED ;
} else {
struct smb_filename * smb_fname = NULL ;
2009-06-16 17:23:54 -07:00
2012-06-08 17:54:19 +02:00
/*
* For a DFS path the function parse_dfs_path ( )
* will do the path processing .
*/
2010-04-24 00:29:41 -07:00
2012-06-08 17:54:19 +02:00
if ( ! ( smb1req - > flags2 & FLAGS2_DFS_PATHNAMES ) ) {
/* convert '\\' into '/' */
status = check_path_syntax ( fname ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
}
2010-04-22 23:52:19 -07:00
}
2012-06-08 17:54:19 +02:00
status = filename_convert ( req ,
smb1req - > conn ,
smb1req - > flags2 & FLAGS2_DFS_PATHNAMES ,
fname ,
0 , /* unix_convert flags */
NULL , /* ppath_contains_wcards */
& smb_fname ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
}
status = SMB_VFS_CREATE_FILE ( smb1req - > conn ,
smb1req ,
0 , /* root_dir_fid */
smb_fname ,
in_desired_access ,
in_share_access ,
in_create_disposition ,
in_create_options ,
in_file_attributes ,
map_smb2_oplock_levels_to_samba ( requested_oplock_level ) ,
allocation_size ,
0 , /* private_flags */
sec_desc ,
ea_list ,
& result ,
& info ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
if ( open_was_deferred ( smb1req - > sconn , smb1req - > mid ) ) {
return req ;
}
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
}
op = result - > op ;
2009-06-02 16:07:53 +02:00
}
2009-08-15 11:52:37 +02:00
2012-06-08 17:54:19 +02:00
/*
* here we have op = = result - > op
*/
DEBUG ( 10 , ( " smbd_smb2_create_send: "
" response construction phase \n " ) ) ;
2009-08-15 11:52:37 +02: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 13:09:06 +02:00
status = smbd_calculate_access_mask ( smb1req - > conn ,
2009-08-15 11:52:37 +02:00
result - > fsp_name ,
2012-09-13 17:12:24 -07:00
false ,
2009-08-15 11:52:37 +02:00
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 10:53:44 -07:00
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
2009-08-15 11:52:37 +02:00
}
}
}
2012-06-08 17:54:19 +02:00
if ( durable_requested & &
BATCH_OPLOCK_TYPE ( result - > oplock_type ) )
{
status = SMB_VFS_DURABLE_COOKIE ( result ,
op ,
& op - > global - > backend_cookie ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
op - > global - > backend_cookie = data_blob_null ;
}
}
if ( op - > global - > backend_cookie . length > 0 ) {
update_open = true ;
op - > global - > durable = true ;
op - > global - > durable_timeout_msec = durable_timeout_msec ;
}
if ( update_open ) {
op - > global - > create_guid = create_guid ;
status = smbXsrv_open_update ( 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 ) ;
return tevent_req_post ( req , ev ) ;
}
}
if ( dhnq & & 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 ,
SMB2_CREATE_TAG_DHNQ ,
blob ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
}
}
2012-06-15 13:37:26 +02:00
if ( dh2q & & op - > global - > durable ) {
uint8_t p [ 8 ] = { 0 , } ;
DATA_BLOB blob = data_blob_const ( p , sizeof ( p ) ) ;
uint32_t durable_v2_response_flags = 0 ;
SIVAL ( p , 0 , op - > global - > durable_timeout_msec ) ;
SIVAL ( p , 4 , durable_v2_response_flags ) ;
status = smb2_create_blob_add ( state , & out_context_blobs ,
SMB2_CREATE_TAG_DH2Q ,
blob ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
}
}
2009-08-15 11:52:37 +02:00
if ( qfid ) {
uint8_t p [ 32 ] ;
2010-05-20 11:36:47 -07:00
uint64_t file_index = get_FileIndex ( result - > conn ,
& result - > fsp_name - > st ) ;
2009-08-15 11:52:37 +02:00
DATA_BLOB blob = data_blob_const ( p , sizeof ( p ) ) ;
ZERO_STRUCT ( p ) ;
2010-05-20 11:36:47 -07: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 11:52:37 +02:00
status = smb2_create_blob_add ( state , & out_context_blobs ,
SMB2_CREATE_TAG_QFID ,
blob ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-04-23 10:53:44 -07:00
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
2009-08-15 11:52:37 +02:00
}
}
2009-07-08 12:24:03 -07:00
}
2010-04-22 23:52:19 -07:00
smb2req - > compat_chain_fsp = smb1req - > chain_fsp ;
2009-06-05 20:02:21 +02:00
2012-03-27 11:09:05 +02:00
if ( lp_fake_oplocks ( SNUM ( smb2req - > tcon - > compat ) ) ) {
2010-05-20 11: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 00:29:41 -07:00
2009-05-28 00:07:26 +02:00
if ( ( in_create_disposition = = FILE_SUPERSEDE )
& & ( info = = FILE_WAS_OVERWRITTEN ) ) {
2009-06-05 21:06:27 +02:00
state - > out_create_action = FILE_WAS_SUPERSEDED ;
2009-05-28 00:07:26 +02:00
} else {
2009-06-05 21:06:27 +02:00
state - > out_create_action = info ;
2009-05-28 00:07:26 +02:00
}
2009-11-17 14:55:02 -08: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-25 13:57:38 -08:00
get_file_infos ( result - > file_id , 0 , NULL , & write_time_ts ) ;
2009-11-17 14:55:02 -08: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-22 23:52:19 -07:00
get_create_timespec ( smb1req - > conn , result ,
2009-11-17 14:55:02 -08: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-22 23:52:19 -07:00
get_change_timespec ( smb1req - > conn , result ,
2009-11-17 14:55:02 -08:00
result - > fsp_name ) ) ;
state - > out_allocation_size =
2011-10-10 17:48:18 +02:00
SMB_VFS_GET_ALLOC_SIZE ( smb1req - > conn , result ,
& ( result - > fsp_name - > st ) ) ;
2009-11-17 14:55:02 -08:00
state - > out_end_of_file = result - > fsp_name - > st . st_ex_size ;
2009-06-05 21:06:27 +02:00
if ( state - > out_file_attributes = = 0 ) {
state - > out_file_attributes = FILE_ATTRIBUTE_NORMAL ;
2009-05-28 00:07:26 +02:00
}
2012-06-08 17:51:47 +02: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 20:39:58 +02:00
state - > out_context_blobs = out_context_blobs ;
2009-06-05 21:06:27 +02:00
2012-06-28 10:02:01 +02:00
DEBUG ( 10 , ( " smbd_smb2_create_send: %s - %s \n " ,
fsp_str_dbg ( result ) , fsp_fnum_dbg ( result ) ) ) ;
2010-04-23 10:53:44 -07:00
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
2009-06-05 21:06:27 +02:00
}
2010-04-23 10:53:44 -07:00
static NTSTATUS smbd_smb2_create_recv ( struct tevent_req * req ,
2009-08-12 20:39:58 +02: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-19 19:28:26 -07:00
uint64_t * out_file_id_persistent ,
2009-08-12 20:39:58 +02:00
uint64_t * out_file_id_volatile ,
struct smb2_create_blobs * out_context_blobs )
2009-06-05 21:06:27 +02:00
{
NTSTATUS status ;
2010-04-23 10:53:44 -07:00
struct smbd_smb2_create_state * state = tevent_req_data ( req ,
2009-06-05 21:06:27 +02:00
struct smbd_smb2_create_state ) ;
2010-04-23 10:53:44 -07:00
if ( tevent_req_is_nterror ( req , & status ) ) {
tevent_req_received ( req ) ;
2009-06-05 21:06:27 +02: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-19 19:28:26 -07:00
* out_file_id_persistent = state - > out_file_id_persistent ;
2009-06-05 21:06:27 +02:00
* out_file_id_volatile = state - > out_file_id_volatile ;
2009-08-12 20:39:58 +02:00
* out_context_blobs = state - > out_context_blobs ;
talloc_steal ( mem_ctx , state - > out_context_blobs . blobs ) ;
2009-06-05 21:06:27 +02:00
2010-04-23 10:53:44 -07:00
tevent_req_received ( req ) ;
2009-05-28 00:07:26 +02:00
return NT_STATUS_OK ;
}
2010-04-22 23:52:19 -07: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 10:53:44 -07:00
struct tevent_req * req = NULL ;
2010-04-22 23:52:19 -07:00
if ( ! smb2req ) {
return false ;
}
2010-04-23 10:53:44 -07:00
req = smb2req - > subreq ;
if ( ! req ) {
2010-04-22 23:52:19 -07:00
return false ;
}
2010-04-23 10:53:44 -07:00
state = tevent_req_data ( req , struct smbd_smb2_create_state ) ;
2010-04-22 23:52:19 -07:00
if ( ! state ) {
return false ;
}
2012-12-14 08:39:26 -08:00
if ( ! state - > open_was_deferred ) {
return false ;
}
2010-04-22 23:52:19 -07:00
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 14:43:12 +02:00
static struct smbd_smb2_request * find_open_smb2req (
struct smbd_server_connection * sconn , uint64_t mid )
2010-04-22 23:52:19 -07:00
{
struct smbd_smb2_request * smb2req ;
for ( smb2req = sconn - > smb2 . requests ; smb2req ; smb2req = smb2req - > next ) {
2010-04-26 12:29:03 -07: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-22 23:52:19 -07:00
if ( message_id = = mid ) {
return smb2req ;
}
}
return NULL ;
}
2010-06-12 14:44:53 +02:00
bool open_was_deferred_smb2 ( struct smbd_server_connection * sconn , uint64_t mid )
2010-04-22 23:52:19 -07:00
{
struct smbd_smb2_create_state * state = NULL ;
2010-06-12 14:43:12 +02:00
struct smbd_smb2_request * smb2req ;
2010-06-12 14:44:53 +02:00
smb2req = find_open_smb2req ( sconn , mid ) ;
2010-04-22 23:52:19 -07: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 03:04:20 +02:00
if ( ! state - > open_was_deferred ) {
2010-04-22 23:52:19 -07:00
return false ;
}
DEBUG ( 10 , ( " open_was_deferred_smb2: mid = %llu \n " ,
( unsigned long long ) mid ) ) ;
2010-04-23 10:29:48 -07:00
2010-04-22 23:52:19 -07:00
return true ;
}
2010-04-23 13:10:15 -07:00
static void remove_deferred_open_message_smb2_internal ( struct smbd_smb2_request * smb2req ,
uint64_t mid )
2010-04-22 23:52:19 -07: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-23 13:10:15 -07:00
DEBUG ( 10 , ( " remove_deferred_open_message_smb2_internal: "
2010-04-22 23:52:19 -07:00
" mid %llu \n " ,
( unsigned long long ) mid ) ) ;
2012-09-26 03:04:20 +02:00
state - > open_was_deferred = false ;
2010-04-22 23:52:19 -07:00
/* Ensure we don't have any outstanding timer event. */
TALLOC_FREE ( state - > te ) ;
2010-05-10 13:58:41 -07:00
/* Ensure we don't have any outstanding immediate event. */
TALLOC_FREE ( state - > im ) ;
2010-04-22 23:52:19 -07:00
}
2010-06-12 14:48:42 +02:00
void remove_deferred_open_message_smb2 (
struct smbd_server_connection * sconn , uint64_t mid )
2010-04-23 13:10:15 -07:00
{
2010-06-12 14:43:12 +02:00
struct smbd_smb2_request * smb2req ;
2010-06-12 14:48:42 +02:00
smb2req = find_open_smb2req ( sconn , mid ) ;
2010-04-23 13:10:15 -07: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-10 13:58:41 -07: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-29 13:53:31 -07:00
bool schedule_deferred_open_message_smb2 (
2010-06-12 14:48:42 +02:00
struct smbd_server_connection * sconn , uint64_t mid )
2010-04-22 23:52:19 -07:00
{
struct smbd_smb2_create_state * state = NULL ;
2010-06-12 14:43:12 +02:00
struct smbd_smb2_request * smb2req ;
2010-06-12 14:48:42 +02:00
smb2req = find_open_smb2req ( sconn , mid ) ;
2010-04-22 23:52:19 -07:00
if ( ! smb2req ) {
DEBUG ( 10 , ( " schedule_deferred_open_message_smb2: "
" can't find mid %llu \n " ,
( unsigned long long ) mid ) ) ;
2012-06-29 13:53:31 -07:00
return false ;
2010-04-22 23:52:19 -07:00
}
if ( ! smb2req - > subreq ) {
2012-06-29 13:53:31 -07:00
return false ;
2010-04-22 23:52:19 -07:00
}
if ( ! tevent_req_is_in_progress ( smb2req - > subreq ) ) {
2012-06-29 13:53:31 -07:00
return false ;
2010-04-22 23:52:19 -07:00
}
state = tevent_req_data ( smb2req - > subreq ,
struct smbd_smb2_create_state ) ;
if ( ! state ) {
2012-06-29 13:53:31 -07:00
return false ;
2010-04-22 23:52:19 -07:00
}
2010-05-10 13:58:41 -07:00
2010-04-22 23:52:19 -07:00
/* Ensure we don't have any outstanding timer event. */
TALLOC_FREE ( state - > te ) ;
2010-05-10 13:58:41 -07:00
/* Ensure we don't have any outstanding immediate event. */
TALLOC_FREE ( state - > im ) ;
2010-04-22 23:52:19 -07:00
2010-04-26 10:54:33 -07:00
/*
* This is subtle . We must null out the callback
2012-06-25 11:07:22 +02:00
* before rescheduling , else the first call to
2010-04-26 10:54:33 -07: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-10 13:58:41 -07:00
state - > im = tevent_create_immediate ( smb2req ) ;
if ( ! state - > im ) {
2010-04-22 23:52:19 -07:00
smbd_server_connection_terminate ( smb2req - > sconn ,
nt_errstr ( NT_STATUS_NO_MEMORY ) ) ;
2012-06-29 13:53:31 -07:00
return false ;
2010-04-22 23:52:19 -07:00
}
DEBUG ( 10 , ( " schedule_deferred_open_message_smb2: "
" re-processing mid %llu \n " ,
( unsigned long long ) mid ) ) ;
2010-05-10 13:58:41 -07:00
tevent_schedule_immediate ( state - > im ,
2011-12-12 14:15:03 +01:00
smb2req - > sconn - > ev_ctx ,
2010-05-10 13:58:41 -07:00
smbd_smb2_create_request_dispatch_immediate ,
2010-04-22 23:52:19 -07:00
smb2req ) ;
2012-06-29 13:53:31 -07:00
return true ;
2010-04-22 23:52:19 -07:00
}
2010-04-23 13:10:15 -07: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-29 14:25:53 -07:00
if ( is_deferred_open_async ( state - > private_data . data ) ) {
/* Can't cancel an async create. */
return false ;
}
2010-07-04 20:14:27 +02:00
remove_deferred_open_entry ( state - > id , mid ,
2011-12-15 11:51:20 +01:00
messaging_server_id ( smb2req - > sconn - > msg_ctx ) ) ;
2010-04-23 13:10:15 -07:00
remove_deferred_open_message_smb2_internal ( smb2req , mid ) ;
2012-09-20 16:16:03 +02:00
tevent_req_defer_callback ( req , smb2req - > sconn - > ev_ctx ) ;
tevent_req_nterror ( req , NT_STATUS_CANCELLED ) ;
2010-04-23 13:10:15 -07:00
return true ;
}
2010-04-22 23:52:19 -07:00
bool push_deferred_open_message_smb2 ( struct smbd_smb2_request * smb2req ,
struct timeval request_time ,
struct timeval timeout ,
2010-04-23 13:10:15 -07:00
struct file_id id ,
2010-04-22 23:52:19 -07:00
char * private_data ,
size_t priv_len )
{
2010-04-23 10:53:44 -07:00
struct tevent_req * req = NULL ;
2010-04-22 23:52:19 -07:00
struct smbd_smb2_create_state * state = NULL ;
struct timeval end_time ;
if ( ! smb2req ) {
return false ;
}
2010-04-23 10:53:44 -07:00
req = smb2req - > subreq ;
if ( ! req ) {
2010-04-22 23:52:19 -07:00
return false ;
}
2010-04-23 10:53:44 -07:00
state = tevent_req_data ( req , struct smbd_smb2_create_state ) ;
2010-04-22 23:52:19 -07:00
if ( ! state ) {
return false ;
}
2010-04-23 13:10:15 -07:00
state - > id = id ;
2010-04-22 23:52:19 -07: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-19 20:09:51 -07:00
2010-04-22 23:52:19 -07: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 03:04:20 +02:00
state - > open_was_deferred = true ;
2010-04-23 13:10:15 -07:00
/* allow this request to be canceled */
tevent_req_set_cancel_fn ( req , smbd_smb2_create_cancel ) ;
2010-04-22 23:52:19 -07:00
return true ;
}