2013-08-08 02:54:05 +04:00
/*
Unix SMB / CIFS implementation .
smb2 lib
Copyright ( C ) Jeremy Allison 2013
Copyright ( C ) Volker Lendecke 2013
Copyright ( C ) Stefan Metzmacher 2013
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/>.
*/
/*
This code is a thin wrapper around the existing
cli_smb2_XXXX ( ) functions in libcli / smb / smb2cli_XXXXX . c ,
but allows the handles to be mapped to uint16_t fnums ,
which are easier for smbclient to use .
*/
# include "includes.h"
# include "client.h"
# include "async_smb.h"
# include "../libcli/smb/smbXcli_base.h"
# include "cli_smb2_fnum.h"
# include "trans2.h"
# include "clirap.h"
# include "../libcli/smb/smb2_create_blob.h"
# include "libsmb/proto.h"
# include "lib/util/tevent_ntstatus.h"
# include "../libcli/security/security.h"
# include "lib/util_ea.h"
2015-05-28 01:13:15 +03:00
# include "librpc/gen_ndr/ndr_ioctl.h"
2013-08-08 02:54:05 +04:00
struct smb2_hnd {
uint64_t fid_persistent ;
uint64_t fid_volatile ;
} ;
/*
* Handle mapping code .
*/
/***************************************************************
Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd .
Ensures handle is owned by cli struct .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS map_smb2_handle_to_fnum ( struct cli_state * cli ,
const struct smb2_hnd * ph , /* In */
uint16_t * pfnum ) /* Out */
{
int ret ;
struct idr_context * idp = cli - > smb2 . open_handles ;
struct smb2_hnd * owned_h = talloc_memdup ( cli ,
ph ,
sizeof ( struct smb2_hnd ) ) ;
if ( owned_h = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
if ( idp = = NULL ) {
/* Lazy init */
cli - > smb2 . open_handles = idr_init ( cli ) ;
if ( cli - > smb2 . open_handles = = NULL ) {
TALLOC_FREE ( owned_h ) ;
return NT_STATUS_NO_MEMORY ;
}
idp = cli - > smb2 . open_handles ;
}
ret = idr_get_new_above ( idp , owned_h , 1 , 0xFFFE ) ;
if ( ret = = - 1 ) {
TALLOC_FREE ( owned_h ) ;
return NT_STATUS_NO_MEMORY ;
}
* pfnum = ( uint16_t ) ret ;
return NT_STATUS_OK ;
}
/***************************************************************
Return the smb2_hnd pointer associated with the given fnum .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS map_fnum_to_smb2_handle ( struct cli_state * cli ,
uint16_t fnum , /* In */
struct smb2_hnd * * pph ) /* Out */
{
struct idr_context * idp = cli - > smb2 . open_handles ;
if ( idp = = NULL ) {
return NT_STATUS_INVALID_PARAMETER ;
}
* pph = ( struct smb2_hnd * ) idr_find ( idp , fnum ) ;
if ( * pph = = NULL ) {
return NT_STATUS_INVALID_HANDLE ;
}
return NT_STATUS_OK ;
}
/***************************************************************
Delete the fnum to smb2_hnd mapping . Zeros out handle on
successful return .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS delete_smb2_handle_mapping ( struct cli_state * cli ,
struct smb2_hnd * * pph , /* In */
uint16_t fnum ) /* In */
{
struct idr_context * idp = cli - > smb2 . open_handles ;
struct smb2_hnd * ph ;
if ( idp = = NULL ) {
return NT_STATUS_INVALID_PARAMETER ;
}
ph = ( struct smb2_hnd * ) idr_find ( idp , fnum ) ;
if ( ph ! = * pph ) {
return NT_STATUS_INVALID_PARAMETER ;
}
idr_remove ( idp , fnum ) ;
TALLOC_FREE ( * pph ) ;
return NT_STATUS_OK ;
}
/***************************************************************
Oplock mapping code .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static uint8_t flags_to_smb2_oplock ( uint32_t create_flags )
{
if ( create_flags & REQUEST_BATCH_OPLOCK ) {
return SMB2_OPLOCK_LEVEL_BATCH ;
} else if ( create_flags & REQUEST_OPLOCK ) {
return SMB2_OPLOCK_LEVEL_EXCLUSIVE ;
}
/* create_flags doesn't do a level2 request. */
return SMB2_OPLOCK_LEVEL_NONE ;
}
/***************************************************************
Small wrapper that allows SMB2 create to return a uint16_t fnum .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-06-20 12:23:47 +04:00
struct cli_smb2_create_fnum_state {
struct cli_state * cli ;
struct smb_create_returns cr ;
uint16_t fnum ;
2014-06-20 14:37:46 +04:00
struct tevent_req * subreq ;
2014-06-20 12:23:47 +04:00
} ;
static void cli_smb2_create_fnum_done ( struct tevent_req * subreq ) ;
2014-06-20 14:37:46 +04:00
static bool cli_smb2_create_fnum_cancel ( struct tevent_req * req ) ;
2014-06-20 12:23:47 +04:00
struct tevent_req * cli_smb2_create_fnum_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
const char * fname ,
uint32_t create_flags ,
uint32_t desired_access ,
uint32_t file_attributes ,
uint32_t share_access ,
uint32_t create_disposition ,
uint32_t create_options )
2013-08-08 02:54:05 +04:00
{
2014-06-20 12:23:47 +04:00
struct tevent_req * req , * subreq ;
struct cli_smb2_create_fnum_state * state ;
2013-08-08 02:54:05 +04:00
2014-06-20 12:23:47 +04:00
req = tevent_req_create ( mem_ctx , & state ,
struct cli_smb2_create_fnum_state ) ;
if ( req = = NULL ) {
return NULL ;
2013-08-08 02:54:05 +04:00
}
2014-06-20 12:23:47 +04:00
state - > cli = cli ;
2013-08-08 02:54:05 +04:00
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
2014-06-20 12:23:47 +04:00
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
2013-08-08 02:54:05 +04:00
}
if ( cli - > backup_intent ) {
create_options | = FILE_OPEN_FOR_BACKUP_INTENT ;
}
/* SMB2 is pickier about pathnames. Ensure it doesn't
start in a ' \ ' */
if ( * fname = = ' \\ ' ) {
fname + + ;
}
2014-06-20 12:23:47 +04:00
subreq = smb2cli_create_send ( state , ev ,
cli - > conn ,
cli - > timeout ,
cli - > smb2 . session ,
cli - > smb2 . tcon ,
fname ,
flags_to_smb2_oplock ( create_flags ) ,
SMB2_IMPERSONATION_IMPERSONATION ,
desired_access ,
file_attributes ,
share_access ,
create_disposition ,
create_options ,
NULL ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , cli_smb2_create_fnum_done , req ) ;
2014-06-20 14:37:46 +04:00
state - > subreq = subreq ;
tevent_req_set_cancel_fn ( req , cli_smb2_create_fnum_cancel ) ;
2014-06-20 12:23:47 +04:00
return req ;
}
2013-08-08 02:54:05 +04:00
2014-06-20 12:23:47 +04:00
static void cli_smb2_create_fnum_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_smb2_create_fnum_state * state = tevent_req_data (
req , struct cli_smb2_create_fnum_state ) ;
struct smb2_hnd h ;
NTSTATUS status ;
status = smb2cli_create_recv ( subreq , & h . fid_persistent ,
2014-06-27 13:32:34 +04:00
& h . fid_volatile , & state - > cr , NULL , NULL ) ;
2014-06-20 12:23:47 +04:00
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
2013-08-08 02:54:05 +04:00
}
2014-06-20 12:23:47 +04:00
status = map_smb2_handle_to_fnum ( state - > cli , & h , & state - > fnum ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
tevent_req_done ( req ) ;
}
2014-06-20 14:37:46 +04:00
static bool cli_smb2_create_fnum_cancel ( struct tevent_req * req )
{
struct cli_smb2_create_fnum_state * state = tevent_req_data (
req , struct cli_smb2_create_fnum_state ) ;
return tevent_req_cancel ( state - > subreq ) ;
}
2014-06-20 12:23:47 +04:00
NTSTATUS cli_smb2_create_fnum_recv ( struct tevent_req * req , uint16_t * pfnum ,
struct smb_create_returns * cr )
{
struct cli_smb2_create_fnum_state * state = tevent_req_data (
req , struct cli_smb2_create_fnum_state ) ;
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
return status ;
}
if ( pfnum ! = NULL ) {
* pfnum = state - > fnum ;
}
if ( cr ! = NULL ) {
* cr = state - > cr ;
}
return NT_STATUS_OK ;
}
NTSTATUS cli_smb2_create_fnum ( struct cli_state * cli ,
const char * fname ,
uint32_t create_flags ,
uint32_t desired_access ,
uint32_t file_attributes ,
uint32_t share_access ,
uint32_t create_disposition ,
uint32_t create_options ,
uint16_t * pfid ,
struct smb_create_returns * cr )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct tevent_context * ev ;
struct tevent_req * req ;
NTSTATUS status = NT_STATUS_NO_MEMORY ;
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
/*
* Can ' t use sync call while an async call is in flight
*/
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
ev = samba_tevent_context_init ( frame ) ;
if ( ev = = NULL ) {
goto fail ;
}
req = cli_smb2_create_fnum_send ( frame , ev , cli , fname , create_flags ,
desired_access , file_attributes ,
share_access , create_disposition ,
create_options ) ;
if ( req = = NULL ) {
goto fail ;
}
if ( ! tevent_req_poll_ntstatus ( req , ev , & status ) ) {
goto fail ;
}
status = cli_smb2_create_fnum_recv ( req , pfid , cr ) ;
fail :
TALLOC_FREE ( frame ) ;
2013-08-08 02:54:05 +04:00
return status ;
}
/***************************************************************
Small wrapper that allows SMB2 close to use a uint16_t fnum .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-06-27 13:47:36 +04:00
struct cli_smb2_close_fnum_state {
struct cli_state * cli ;
uint16_t fnum ;
struct smb2_hnd * ph ;
} ;
static void cli_smb2_close_fnum_done ( struct tevent_req * subreq ) ;
struct tevent_req * cli_smb2_close_fnum_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
uint16_t fnum )
2013-08-08 02:54:05 +04:00
{
2014-06-27 13:47:36 +04:00
struct tevent_req * req , * subreq ;
struct cli_smb2_close_fnum_state * state ;
2013-08-08 02:54:05 +04:00
NTSTATUS status ;
2014-06-27 13:47:36 +04:00
req = tevent_req_create ( mem_ctx , & state ,
struct cli_smb2_close_fnum_state ) ;
if ( req = = NULL ) {
return NULL ;
2013-08-08 02:54:05 +04:00
}
2014-06-27 13:47:36 +04:00
state - > cli = cli ;
state - > fnum = fnum ;
2013-08-08 02:54:05 +04:00
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
2014-06-27 13:47:36 +04:00
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
2013-08-08 02:54:05 +04:00
}
2014-06-27 13:47:36 +04:00
status = map_fnum_to_smb2_handle ( cli , fnum , & state - > ph ) ;
if ( tevent_req_nterror ( req , status ) ) {
return tevent_req_post ( req , ev ) ;
}
subreq = smb2cli_close_send ( state , ev , cli - > conn , cli - > timeout ,
cli - > smb2 . session , cli - > smb2 . tcon ,
0 , state - > ph - > fid_persistent ,
state - > ph - > fid_volatile ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
2013-08-08 02:54:05 +04:00
}
2014-06-27 13:47:36 +04:00
tevent_req_set_callback ( subreq , cli_smb2_close_fnum_done , req ) ;
return req ;
}
2013-08-08 02:54:05 +04:00
2014-06-27 13:47:36 +04:00
static void cli_smb2_close_fnum_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_smb2_close_fnum_state * state = tevent_req_data (
req , struct cli_smb2_close_fnum_state ) ;
NTSTATUS status ;
status = smb2cli_close_recv ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
2013-08-08 02:54:05 +04:00
/* Delete the fnum -> handle mapping. */
2014-06-27 13:47:36 +04:00
status = delete_smb2_handle_mapping ( state - > cli , & state - > ph ,
state - > fnum ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
2013-08-08 02:54:05 +04:00
}
2014-06-27 13:47:36 +04:00
tevent_req_done ( req ) ;
}
NTSTATUS cli_smb2_close_fnum_recv ( struct tevent_req * req )
{
return tevent_req_simple_recv_ntstatus ( req ) ;
}
2013-08-08 02:54:05 +04:00
2014-06-27 13:47:36 +04:00
NTSTATUS cli_smb2_close_fnum ( struct cli_state * cli , uint16_t fnum )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct tevent_context * ev ;
struct tevent_req * req ;
NTSTATUS status = NT_STATUS_NO_MEMORY ;
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
/*
* Can ' t use sync call while an async call is in flight
*/
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
ev = samba_tevent_context_init ( frame ) ;
if ( ev = = NULL ) {
goto fail ;
}
req = cli_smb2_close_fnum_send ( frame , ev , cli , fnum ) ;
if ( req = = NULL ) {
goto fail ;
}
if ( ! tevent_req_poll_ntstatus ( req , ev , & status ) ) {
goto fail ;
}
status = cli_smb2_close_fnum_recv ( req ) ;
fail :
TALLOC_FREE ( frame ) ;
2013-08-08 02:54:05 +04:00
return status ;
}
/***************************************************************
Small wrapper that allows SMB2 to create a directory
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_mkdir ( struct cli_state * cli , const char * dname )
{
NTSTATUS status ;
uint16_t fnum ;
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
/*
* Can ' t use sync call while an async call is in flight
*/
return NT_STATUS_INVALID_PARAMETER ;
}
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
return NT_STATUS_INVALID_PARAMETER ;
}
status = cli_smb2_create_fnum ( cli ,
dname ,
0 , /* create_flags */
FILE_READ_ATTRIBUTES , /* desired_access */
FILE_ATTRIBUTE_DIRECTORY , /* file attributes */
FILE_SHARE_READ | FILE_SHARE_WRITE , /* share_access */
FILE_CREATE , /* create_disposition */
FILE_DIRECTORY_FILE , /* create_options */
& fnum ,
NULL ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
return cli_smb2_close_fnum ( cli , fnum ) ;
}
/***************************************************************
Small wrapper that allows SMB2 to delete a directory
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_rmdir ( struct cli_state * cli , const char * dname )
{
NTSTATUS status ;
uint16_t fnum ;
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
/*
* Can ' t use sync call while an async call is in flight
*/
return NT_STATUS_INVALID_PARAMETER ;
}
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
return NT_STATUS_INVALID_PARAMETER ;
}
status = cli_smb2_create_fnum ( cli ,
dname ,
0 , /* create_flags */
DELETE_ACCESS , /* desired_access */
FILE_ATTRIBUTE_DIRECTORY , /* file attributes */
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE , /* share_access */
FILE_OPEN , /* create_disposition */
FILE_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE , /* create_options */
& fnum ,
NULL ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
return cli_smb2_close_fnum ( cli , fnum ) ;
}
/***************************************************************
Small wrapper that allows SMB2 to unlink a pathname .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_unlink ( struct cli_state * cli , const char * fname )
{
NTSTATUS status ;
uint16_t fnum ;
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
/*
* Can ' t use sync call while an async call is in flight
*/
return NT_STATUS_INVALID_PARAMETER ;
}
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
return NT_STATUS_INVALID_PARAMETER ;
}
status = cli_smb2_create_fnum ( cli ,
fname ,
0 , /* create_flags */
DELETE_ACCESS , /* desired_access */
FILE_ATTRIBUTE_NORMAL , /* file attributes */
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE , /* share_access */
FILE_OPEN , /* create_disposition */
FILE_DELETE_ON_CLOSE , /* create_options */
& fnum ,
NULL ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
return cli_smb2_close_fnum ( cli , fnum ) ;
}
/***************************************************************
Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS parse_finfo_id_both_directory_info ( uint8_t * dir_data ,
uint32_t dir_data_length ,
struct file_info * finfo ,
uint32_t * next_offset )
{
size_t namelen = 0 ;
size_t slen = 0 ;
size_t ret = 0 ;
if ( dir_data_length < 4 ) {
return NT_STATUS_INFO_LENGTH_MISMATCH ;
}
* next_offset = IVAL ( dir_data , 0 ) ;
if ( * next_offset > dir_data_length ) {
return NT_STATUS_INFO_LENGTH_MISMATCH ;
}
if ( * next_offset ! = 0 ) {
/* Ensure we only read what in this record. */
dir_data_length = * next_offset ;
}
if ( dir_data_length < 105 ) {
return NT_STATUS_INFO_LENGTH_MISMATCH ;
}
finfo - > atime_ts = interpret_long_date ( ( const char * ) dir_data + 16 ) ;
finfo - > mtime_ts = interpret_long_date ( ( const char * ) dir_data + 24 ) ;
finfo - > ctime_ts = interpret_long_date ( ( const char * ) dir_data + 32 ) ;
finfo - > size = IVAL2_TO_SMB_BIG_UINT ( dir_data + 40 , 0 ) ;
finfo - > mode = CVAL ( dir_data + 56 , 0 ) ;
namelen = IVAL ( dir_data + 60 , 0 ) ;
if ( namelen > ( dir_data_length - 104 ) ) {
return NT_STATUS_INFO_LENGTH_MISMATCH ;
}
2013-09-17 06:16:52 +04:00
slen = CVAL ( dir_data + 68 , 0 ) ;
2013-08-08 02:54:05 +04:00
if ( slen > 24 ) {
return NT_STATUS_INFO_LENGTH_MISMATCH ;
}
ret = pull_string_talloc ( finfo ,
dir_data ,
FLAGS2_UNICODE_STRINGS ,
& finfo - > short_name ,
dir_data + 70 ,
slen ,
STR_UNICODE ) ;
if ( ret = = ( size_t ) - 1 ) {
/* Bad conversion. */
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
ret = pull_string_talloc ( finfo ,
dir_data ,
FLAGS2_UNICODE_STRINGS ,
& finfo - > name ,
dir_data + 104 ,
namelen ,
STR_UNICODE ) ;
if ( ret = = ( size_t ) - 1 ) {
/* Bad conversion. */
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
return NT_STATUS_OK ;
}
/*******************************************************************
Given a filename - get its directory name
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static bool windows_parent_dirname ( TALLOC_CTX * mem_ctx ,
const char * dir ,
char * * parent ,
const char * * name )
{
char * p ;
ptrdiff_t len ;
p = strrchr_m ( dir , ' \\ ' ) ; /* Find final '\\', if any */
if ( p = = NULL ) {
if ( ! ( * parent = talloc_strdup ( mem_ctx , " \\ " ) ) ) {
return false ;
}
if ( name ) {
* name = dir ;
}
return true ;
}
len = p - dir ;
if ( ! ( * parent = ( char * ) talloc_memdup ( mem_ctx , dir , len + 1 ) ) ) {
return false ;
}
( * parent ) [ len ] = ' \0 ' ;
if ( name ) {
* name = p + 1 ;
}
return true ;
}
/***************************************************************
Wrapper that allows SMB2 to list a directory .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_list ( struct cli_state * cli ,
const char * pathname ,
2013-11-13 03:55:51 +04:00
uint16_t attribute ,
2013-08-08 02:54:05 +04:00
NTSTATUS ( * fn ) ( const char * ,
struct file_info * ,
const char * ,
void * ) ,
void * state )
{
NTSTATUS status ;
2013-08-20 00:36:02 +04:00
uint16_t fnum = 0xffff ;
2013-08-08 02:54:05 +04:00
char * parent_dir = NULL ;
const char * mask = NULL ;
struct smb2_hnd * ph = NULL ;
2013-11-13 03:55:51 +04:00
bool processed_file = false ;
2013-08-08 02:54:05 +04:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
TALLOC_CTX * subframe = NULL ;
2014-10-22 01:41:32 +04:00
bool mask_has_wild ;
2013-08-08 02:54:05 +04:00
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
/*
* Can ' t use sync call while an async call is in flight
*/
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
/* Get the directory name. */
if ( ! windows_parent_dirname ( frame ,
pathname ,
& parent_dir ,
& mask ) ) {
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
2014-10-22 01:41:32 +04:00
mask_has_wild = ms_has_wild ( mask ) ;
2013-08-08 02:54:05 +04:00
status = cli_smb2_create_fnum ( cli ,
parent_dir ,
0 , /* create_flags */
SEC_DIR_LIST | SEC_DIR_READ_ATTRIBUTE , /* desired_access */
FILE_ATTRIBUTE_DIRECTORY , /* file attributes */
FILE_SHARE_READ | FILE_SHARE_WRITE , /* share_access */
FILE_OPEN , /* create_disposition */
FILE_DIRECTORY_FILE , /* create_options */
& fnum ,
NULL ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
status = map_fnum_to_smb2_handle ( cli ,
fnum ,
& ph ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
do {
uint8_t * dir_data = NULL ;
uint32_t dir_data_length = 0 ;
uint32_t next_offset = 0 ;
subframe = talloc_stackframe ( ) ;
status = smb2cli_query_directory ( cli - > conn ,
cli - > timeout ,
cli - > smb2 . session ,
cli - > smb2 . tcon ,
SMB2_FIND_ID_BOTH_DIRECTORY_INFO ,
0 , /* flags */
0 , /* file_index */
ph - > fid_persistent ,
ph - > fid_volatile ,
mask ,
0xffff ,
subframe ,
& dir_data ,
& dir_data_length ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
if ( NT_STATUS_EQUAL ( status , STATUS_NO_MORE_FILES ) ) {
break ;
}
goto fail ;
}
do {
struct file_info * finfo = talloc_zero ( subframe ,
struct file_info ) ;
if ( finfo = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
status = parse_finfo_id_both_directory_info ( dir_data ,
dir_data_length ,
finfo ,
& next_offset ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
2013-11-13 03:55:51 +04:00
if ( dir_check_ftype ( ( uint32_t ) finfo - > mode ,
( uint32_t ) attribute ) ) {
/*
* Only process if attributes match .
* On SMB1 server does this , so on
* SMB2 we need to emulate in the
* client .
*
* https : //bugzilla.samba.org/show_bug.cgi?id=10260
*/
processed_file = true ;
status = fn ( cli - > dfs_mountpoint ,
2013-08-08 02:54:05 +04:00
finfo ,
pathname ,
state ) ;
2013-11-13 03:55:51 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
break ;
}
2013-08-08 02:54:05 +04:00
}
TALLOC_FREE ( finfo ) ;
/* Move to next entry. */
if ( next_offset ) {
dir_data + = next_offset ;
dir_data_length - = next_offset ;
}
} while ( next_offset ! = 0 ) ;
TALLOC_FREE ( subframe ) ;
2014-10-22 01:41:32 +04:00
if ( ! mask_has_wild ) {
/*
* MacOSX 10 doesn ' t set STATUS_NO_MORE_FILES
* when handed a non - wildcard path . Do it
* for the server ( with a non - wildcard path
* there should only ever be one file returned .
*/
status = STATUS_NO_MORE_FILES ;
break ;
}
2013-08-08 02:54:05 +04:00
} while ( NT_STATUS_IS_OK ( status ) ) ;
if ( NT_STATUS_EQUAL ( status , STATUS_NO_MORE_FILES ) ) {
status = NT_STATUS_OK ;
}
2013-11-13 03:55:51 +04:00
if ( NT_STATUS_IS_OK ( status ) & & ! processed_file ) {
/*
* In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
* if no files match . Emulate this in the client .
*/
status = NT_STATUS_NO_SUCH_FILE ;
}
2013-08-08 02:54:05 +04:00
fail :
2013-08-20 00:36:02 +04:00
if ( fnum ! = 0xffff ) {
2013-08-08 02:54:05 +04:00
cli_smb2_close_fnum ( cli , fnum ) ;
}
TALLOC_FREE ( subframe ) ;
TALLOC_FREE ( frame ) ;
return status ;
}
/***************************************************************
Wrapper that allows SMB2 to query a path info ( basic level ) .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_qpathinfo_basic ( struct cli_state * cli ,
const char * name ,
SMB_STRUCT_STAT * sbuf ,
uint32_t * attributes )
{
NTSTATUS status ;
2014-05-09 07:08:41 +04:00
struct smb_create_returns cr ;
2013-08-20 00:36:02 +04:00
uint16_t fnum = 0xffff ;
2013-08-08 02:54:05 +04:00
size_t namelen = strlen ( name ) ;
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
/*
* Can ' t use sync call while an async call is in flight
*/
return NT_STATUS_INVALID_PARAMETER ;
}
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
return NT_STATUS_INVALID_PARAMETER ;
}
/* SMB2 is pickier about pathnames. Ensure it doesn't
end in a ' \ ' */
if ( namelen > 0 & & name [ namelen - 1 ] = = ' \\ ' ) {
char * modname = talloc_strdup ( talloc_tos ( ) , name ) ;
modname [ namelen - 1 ] = ' \0 ' ;
name = modname ;
}
/* This is commonly used as a 'cd'. Try qpathinfo on
a directory handle first . */
status = cli_smb2_create_fnum ( cli ,
name ,
0 , /* create_flags */
FILE_READ_ATTRIBUTES , /* desired_access */
FILE_ATTRIBUTE_DIRECTORY , /* file attributes */
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE , /* share_access */
FILE_OPEN , /* create_disposition */
FILE_DIRECTORY_FILE , /* create_options */
& fnum ,
& cr ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NOT_A_DIRECTORY ) ) {
/* Maybe a file ? */
status = cli_smb2_create_fnum ( cli ,
name ,
0 , /* create_flags */
FILE_READ_ATTRIBUTES , /* desired_access */
0 , /* file attributes */
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE , /* share_access */
FILE_OPEN , /* create_disposition */
0 , /* create_options */
& fnum ,
& cr ) ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
cli_smb2_close_fnum ( cli , fnum ) ;
ZERO_STRUCTP ( sbuf ) ;
2014-06-18 16:21:06 +04:00
sbuf - > st_ex_atime = nt_time_to_unix_timespec ( cr . last_access_time ) ;
sbuf - > st_ex_mtime = nt_time_to_unix_timespec ( cr . last_write_time ) ;
sbuf - > st_ex_ctime = nt_time_to_unix_timespec ( cr . change_time ) ;
2013-08-08 02:54:05 +04:00
sbuf - > st_ex_size = cr . end_of_file ;
* attributes = cr . file_attributes ;
return NT_STATUS_OK ;
}
/***************************************************************
Helper function for pathname operations .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS get_fnum_from_path ( struct cli_state * cli ,
const char * name ,
uint32_t desired_access ,
uint16_t * pfnum )
{
NTSTATUS status ;
size_t namelen = strlen ( name ) ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
/* SMB2 is pickier about pathnames. Ensure it doesn't
end in a ' \ ' */
if ( namelen > 0 & & name [ namelen - 1 ] = = ' \\ ' ) {
char * modname = talloc_strdup ( frame , name ) ;
if ( modname = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
modname [ namelen - 1 ] = ' \0 ' ;
name = modname ;
}
/* Try to open a file handle first. */
status = cli_smb2_create_fnum ( cli ,
name ,
0 , /* create_flags */
desired_access ,
0 , /* file attributes */
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE , /* share_access */
FILE_OPEN , /* create_disposition */
0 , /* create_options */
pfnum ,
NULL ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_FILE_IS_A_DIRECTORY ) ) {
status = cli_smb2_create_fnum ( cli ,
name ,
0 , /* create_flags */
desired_access ,
FILE_ATTRIBUTE_DIRECTORY , /* file attributes */
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE , /* share_access */
FILE_OPEN , /* create_disposition */
FILE_DIRECTORY_FILE , /* create_options */
pfnum ,
NULL ) ;
}
fail :
TALLOC_FREE ( frame ) ;
return status ;
}
/***************************************************************
Wrapper that allows SMB2 to query a path info ( ALTNAME level ) .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_qpathinfo_alt_name ( struct cli_state * cli ,
const char * name ,
fstring alt_name )
{
NTSTATUS status ;
DATA_BLOB outbuf = data_blob_null ;
2013-08-20 00:36:02 +04:00
uint16_t fnum = 0xffff ;
2013-08-08 02:54:05 +04:00
struct smb2_hnd * ph = NULL ;
uint32_t altnamelen = 0 ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
/*
* Can ' t use sync call while an async call is in flight
*/
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
status = get_fnum_from_path ( cli ,
name ,
FILE_READ_ATTRIBUTES ,
& fnum ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
status = map_fnum_to_smb2_handle ( cli ,
fnum ,
& ph ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
/* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
level SMB_FILE_ALTERNATE_NAME_INFORMATION ( 1021 ) = = SMB2 21 */
status = smb2cli_query_info ( cli - > conn ,
cli - > timeout ,
cli - > smb2 . session ,
cli - > smb2 . tcon ,
1 , /* in_info_type */
( SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000 ) , /* in_file_info_class */
0xFFFF , /* in_max_output_length */
NULL , /* in_input_buffer */
0 , /* in_additional_info */
0 , /* in_flags */
ph - > fid_persistent ,
ph - > fid_volatile ,
frame ,
& outbuf ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
/* Parse the reply. */
if ( outbuf . length < 4 ) {
status = NT_STATUS_INVALID_NETWORK_RESPONSE ;
goto fail ;
}
altnamelen = IVAL ( outbuf . data , 0 ) ;
if ( altnamelen > outbuf . length - 4 ) {
status = NT_STATUS_INVALID_NETWORK_RESPONSE ;
goto fail ;
}
if ( altnamelen > 0 ) {
size_t ret = 0 ;
char * short_name = NULL ;
ret = pull_string_talloc ( frame ,
outbuf . data ,
FLAGS2_UNICODE_STRINGS ,
& short_name ,
outbuf . data + 4 ,
altnamelen ,
STR_UNICODE ) ;
if ( ret = = ( size_t ) - 1 ) {
/* Bad conversion. */
status = NT_STATUS_INVALID_NETWORK_RESPONSE ;
goto fail ;
}
fstrcpy ( alt_name , short_name ) ;
} else {
alt_name [ 0 ] = ' \0 ' ;
}
status = NT_STATUS_OK ;
fail :
2013-08-20 00:36:02 +04:00
if ( fnum ! = 0xffff ) {
2013-08-08 02:54:05 +04:00
cli_smb2_close_fnum ( cli , fnum ) ;
}
TALLOC_FREE ( frame ) ;
return status ;
}
/***************************************************************
Wrapper that allows SMB2 to query a fnum info ( basic level ) .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_qfileinfo_basic ( struct cli_state * cli ,
uint16_t fnum ,
uint16_t * mode ,
off_t * size ,
struct timespec * create_time ,
struct timespec * access_time ,
struct timespec * write_time ,
struct timespec * change_time ,
SMB_INO_T * ino )
{
NTSTATUS status ;
DATA_BLOB outbuf = data_blob_null ;
struct smb2_hnd * ph = NULL ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
/*
* Can ' t use sync call while an async call is in flight
*/
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
status = map_fnum_to_smb2_handle ( cli ,
fnum ,
& ph ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
/* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
level 0x12 ( SMB2_FILE_ALL_INFORMATION ) . */
status = smb2cli_query_info ( cli - > conn ,
cli - > timeout ,
cli - > smb2 . session ,
cli - > smb2 . tcon ,
1 , /* in_info_type */
( SMB_FILE_ALL_INFORMATION - 1000 ) , /* in_file_info_class */
0xFFFF , /* in_max_output_length */
NULL , /* in_input_buffer */
0 , /* in_additional_info */
0 , /* in_flags */
ph - > fid_persistent ,
ph - > fid_volatile ,
frame ,
& outbuf ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
/* Parse the reply. */
if ( outbuf . length < 0x60 ) {
status = NT_STATUS_INVALID_NETWORK_RESPONSE ;
goto fail ;
}
if ( create_time ) {
* create_time = interpret_long_date ( ( const char * ) outbuf . data + 0x0 ) ;
}
if ( access_time ) {
* access_time = interpret_long_date ( ( const char * ) outbuf . data + 0x8 ) ;
}
if ( write_time ) {
* write_time = interpret_long_date ( ( const char * ) outbuf . data + 0x10 ) ;
}
if ( change_time ) {
* change_time = interpret_long_date ( ( const char * ) outbuf . data + 0x18 ) ;
}
if ( mode ) {
uint32_t attr = IVAL ( outbuf . data , 0x20 ) ;
* mode = ( uint16_t ) attr ;
}
if ( size ) {
uint64_t file_size = BVAL ( outbuf . data , 0x30 ) ;
* size = ( off_t ) file_size ;
}
if ( ino ) {
uint64_t file_index = BVAL ( outbuf . data , 0x40 ) ;
* ino = ( SMB_INO_T ) file_index ;
}
fail :
TALLOC_FREE ( frame ) ;
return status ;
}
/***************************************************************
Wrapper that allows SMB2 to query an fnum .
Implement on top of cli_smb2_qfileinfo_basic ( ) .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_getattrE ( struct cli_state * cli ,
uint16_t fnum ,
uint16_t * attr ,
off_t * size ,
time_t * change_time ,
time_t * access_time ,
time_t * write_time )
{
struct timespec access_time_ts ;
struct timespec write_time_ts ;
struct timespec change_time_ts ;
NTSTATUS status = cli_smb2_qfileinfo_basic ( cli ,
fnum ,
attr ,
size ,
NULL ,
& access_time_ts ,
& write_time_ts ,
& change_time_ts ,
NULL ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
if ( change_time ) {
* change_time = change_time_ts . tv_sec ;
}
if ( access_time ) {
* access_time = access_time_ts . tv_sec ;
}
if ( write_time ) {
* write_time = write_time_ts . tv_sec ;
}
return NT_STATUS_OK ;
}
/***************************************************************
Wrapper that allows SMB2 to get pathname attributes .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_getatr ( struct cli_state * cli ,
const char * name ,
uint16_t * attr ,
off_t * size ,
time_t * write_time )
{
NTSTATUS status ;
2013-08-20 00:36:02 +04:00
uint16_t fnum = 0xffff ;
2013-08-08 02:54:05 +04:00
struct smb2_hnd * ph = NULL ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
/*
* Can ' t use sync call while an async call is in flight
*/
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
status = get_fnum_from_path ( cli ,
name ,
FILE_READ_ATTRIBUTES ,
& fnum ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
status = map_fnum_to_smb2_handle ( cli ,
fnum ,
& ph ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
status = cli_smb2_getattrE ( cli ,
fnum ,
attr ,
size ,
NULL ,
NULL ,
write_time ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
fail :
2013-08-20 00:36:02 +04:00
if ( fnum ! = 0xffff ) {
2013-08-08 02:54:05 +04:00
cli_smb2_close_fnum ( cli , fnum ) ;
}
TALLOC_FREE ( frame ) ;
return status ;
}
/***************************************************************
Wrapper that allows SMB2 to query a pathname info ( basic level ) .
Implement on top of cli_smb2_qfileinfo_basic ( ) .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_qpathinfo2 ( struct cli_state * cli ,
const char * name ,
struct timespec * create_time ,
struct timespec * access_time ,
struct timespec * write_time ,
struct timespec * change_time ,
off_t * size ,
uint16_t * mode ,
SMB_INO_T * ino )
{
NTSTATUS status ;
struct smb2_hnd * ph = NULL ;
2013-08-20 00:36:02 +04:00
uint16_t fnum = 0xffff ;
2013-08-08 02:54:05 +04:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
/*
* Can ' t use sync call while an async call is in flight
*/
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
status = get_fnum_from_path ( cli ,
name ,
FILE_READ_ATTRIBUTES ,
& fnum ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
status = map_fnum_to_smb2_handle ( cli ,
fnum ,
& ph ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
status = cli_smb2_qfileinfo_basic ( cli ,
fnum ,
mode ,
size ,
create_time ,
access_time ,
write_time ,
change_time ,
ino ) ;
fail :
2013-08-20 00:36:02 +04:00
if ( fnum ! = 0xffff ) {
2013-08-08 02:54:05 +04:00
cli_smb2_close_fnum ( cli , fnum ) ;
}
TALLOC_FREE ( frame ) ;
return status ;
}
/***************************************************************
Wrapper that allows SMB2 to query pathname streams .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_qpathinfo_streams ( struct cli_state * cli ,
const char * name ,
TALLOC_CTX * mem_ctx ,
unsigned int * pnum_streams ,
struct stream_struct * * pstreams )
{
NTSTATUS status ;
struct smb2_hnd * ph = NULL ;
2013-08-20 00:36:02 +04:00
uint16_t fnum = 0xffff ;
2013-08-08 02:54:05 +04:00
DATA_BLOB outbuf = data_blob_null ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
/*
* Can ' t use sync call while an async call is in flight
*/
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
status = get_fnum_from_path ( cli ,
name ,
FILE_READ_ATTRIBUTES ,
& fnum ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
status = map_fnum_to_smb2_handle ( cli ,
fnum ,
& ph ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
/* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
level 22 ( SMB2_FILE_STREAM_INFORMATION ) . */
status = smb2cli_query_info ( cli - > conn ,
cli - > timeout ,
cli - > smb2 . session ,
cli - > smb2 . tcon ,
1 , /* in_info_type */
( SMB_FILE_STREAM_INFORMATION - 1000 ) , /* in_file_info_class */
0xFFFF , /* in_max_output_length */
NULL , /* in_input_buffer */
0 , /* in_additional_info */
0 , /* in_flags */
ph - > fid_persistent ,
ph - > fid_volatile ,
frame ,
& outbuf ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
/* Parse the reply. */
if ( ! parse_streams_blob ( mem_ctx ,
outbuf . data ,
outbuf . length ,
pnum_streams ,
pstreams ) ) {
status = NT_STATUS_INVALID_NETWORK_RESPONSE ;
goto fail ;
}
fail :
2013-08-20 00:36:02 +04:00
if ( fnum ! = 0xffff ) {
2013-08-08 02:54:05 +04:00
cli_smb2_close_fnum ( cli , fnum ) ;
}
TALLOC_FREE ( frame ) ;
return status ;
}
/***************************************************************
Wrapper that allows SMB2 to set pathname attributes .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_setatr ( struct cli_state * cli ,
const char * name ,
uint16_t attr ,
time_t mtime )
{
NTSTATUS status ;
2013-08-20 00:36:02 +04:00
uint16_t fnum = 0xffff ;
2013-08-08 02:54:05 +04:00
struct smb2_hnd * ph = NULL ;
uint8_t inbuf_store [ 40 ] ;
DATA_BLOB inbuf = data_blob_null ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
/*
* Can ' t use sync call while an async call is in flight
*/
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
status = get_fnum_from_path ( cli ,
name ,
FILE_WRITE_ATTRIBUTES ,
& fnum ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
status = map_fnum_to_smb2_handle ( cli ,
fnum ,
& ph ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
/* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
level 4 ( SMB_FILE_BASIC_INFORMATION - 1000 ) . */
inbuf . data = inbuf_store ;
inbuf . length = sizeof ( inbuf_store ) ;
data_blob_clear ( & inbuf ) ;
2013-11-15 20:02:12 +04:00
SSVAL ( inbuf . data , 32 , attr ) ;
2013-08-08 02:54:05 +04:00
if ( mtime ! = 0 ) {
put_long_date ( ( char * ) inbuf . data + 16 , mtime ) ;
}
/* Set all the other times to -1. */
SBVAL ( inbuf . data , 0 , 0xFFFFFFFFFFFFFFFFLL ) ;
SBVAL ( inbuf . data , 8 , 0xFFFFFFFFFFFFFFFFLL ) ;
SBVAL ( inbuf . data , 24 , 0xFFFFFFFFFFFFFFFFLL ) ;
status = smb2cli_set_info ( cli - > conn ,
cli - > timeout ,
cli - > smb2 . session ,
cli - > smb2 . tcon ,
1 , /* in_info_type */
SMB_FILE_BASIC_INFORMATION - 1000 , /* in_file_info_class */
& inbuf , /* in_input_buffer */
0 , /* in_additional_info */
ph - > fid_persistent ,
ph - > fid_volatile ) ;
fail :
2013-08-20 00:36:02 +04:00
if ( fnum ! = 0xffff ) {
2013-08-08 02:54:05 +04:00
cli_smb2_close_fnum ( cli , fnum ) ;
}
TALLOC_FREE ( frame ) ;
return status ;
}
/***************************************************************
Wrapper that allows SMB2 to set file handle times .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_setattrE ( struct cli_state * cli ,
uint16_t fnum ,
time_t change_time ,
time_t access_time ,
time_t write_time )
{
NTSTATUS status ;
struct smb2_hnd * ph = NULL ;
uint8_t inbuf_store [ 40 ] ;
DATA_BLOB inbuf = data_blob_null ;
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
/*
* Can ' t use sync call while an async call is in flight
*/
return NT_STATUS_INVALID_PARAMETER ;
}
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
return NT_STATUS_INVALID_PARAMETER ;
}
status = map_fnum_to_smb2_handle ( cli ,
fnum ,
& ph ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
/* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
level 4 ( SMB_FILE_BASIC_INFORMATION - 1000 ) . */
inbuf . data = inbuf_store ;
inbuf . length = sizeof ( inbuf_store ) ;
data_blob_clear ( & inbuf ) ;
SBVAL ( inbuf . data , 0 , 0xFFFFFFFFFFFFFFFFLL ) ;
if ( change_time ! = 0 ) {
put_long_date ( ( char * ) inbuf . data + 24 , change_time ) ;
}
if ( access_time ! = 0 ) {
put_long_date ( ( char * ) inbuf . data + 8 , access_time ) ;
}
if ( write_time ! = 0 ) {
put_long_date ( ( char * ) inbuf . data + 16 , write_time ) ;
}
return smb2cli_set_info ( cli - > conn ,
cli - > timeout ,
cli - > smb2 . session ,
cli - > smb2 . tcon ,
1 , /* in_info_type */
SMB_FILE_BASIC_INFORMATION - 1000 , /* in_file_info_class */
& inbuf , /* in_input_buffer */
0 , /* in_additional_info */
ph - > fid_persistent ,
ph - > fid_volatile ) ;
}
/***************************************************************
Wrapper that allows SMB2 to query disk attributes ( size ) .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-06-05 01:19:30 +04:00
NTSTATUS cli_smb2_dskattr ( struct cli_state * cli , uint64_t * bsize , uint64_t * total , uint64_t * avail )
2013-08-08 02:54:05 +04:00
{
NTSTATUS status ;
2013-08-20 00:36:02 +04:00
uint16_t fnum = 0xffff ;
2013-08-08 02:54:05 +04:00
DATA_BLOB outbuf = data_blob_null ;
struct smb2_hnd * ph = NULL ;
uint32_t sectors_per_unit = 0 ;
uint32_t bytes_per_sector = 0 ;
uint64_t total_size = 0 ;
uint64_t size_free = 0 ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
/*
* Can ' t use sync call while an async call is in flight
*/
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
/* First open the top level directory. */
status = cli_smb2_create_fnum ( cli ,
" " ,
0 , /* create_flags */
FILE_READ_ATTRIBUTES , /* desired_access */
FILE_ATTRIBUTE_DIRECTORY , /* file attributes */
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE , /* share_access */
FILE_OPEN , /* create_disposition */
FILE_DIRECTORY_FILE , /* create_options */
& fnum ,
NULL ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
status = map_fnum_to_smb2_handle ( cli ,
fnum ,
& ph ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
/* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
level 3 ( SMB_FS_SIZE_INFORMATION ) . */
status = smb2cli_query_info ( cli - > conn ,
cli - > timeout ,
cli - > smb2 . session ,
cli - > smb2 . tcon ,
2 , /* in_info_type */
3 , /* in_file_info_class */
0xFFFF , /* in_max_output_length */
NULL , /* in_input_buffer */
0 , /* in_additional_info */
0 , /* in_flags */
ph - > fid_persistent ,
ph - > fid_volatile ,
frame ,
& outbuf ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
/* Parse the reply. */
if ( outbuf . length ! = 24 ) {
status = NT_STATUS_INVALID_NETWORK_RESPONSE ;
goto fail ;
}
total_size = BVAL ( outbuf . data , 0 ) ;
size_free = BVAL ( outbuf . data , 8 ) ;
sectors_per_unit = IVAL ( outbuf . data , 16 ) ;
bytes_per_sector = IVAL ( outbuf . data , 20 ) ;
if ( bsize ) {
2014-06-05 01:19:30 +04:00
* bsize = ( uint64_t ) sectors_per_unit * ( uint64_t ) bytes_per_sector ;
2013-08-08 02:54:05 +04:00
}
if ( total ) {
2014-06-05 01:19:30 +04:00
* total = total_size ;
2013-08-08 02:54:05 +04:00
}
if ( avail ) {
2014-06-05 01:19:30 +04:00
* avail = size_free ;
2013-08-08 02:54:05 +04:00
}
status = NT_STATUS_OK ;
fail :
2013-08-20 00:36:02 +04:00
if ( fnum ! = 0xffff ) {
2013-08-08 02:54:05 +04:00
cli_smb2_close_fnum ( cli , fnum ) ;
}
TALLOC_FREE ( frame ) ;
return status ;
}
/***************************************************************
Wrapper that allows SMB2 to query a security descriptor .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_query_security_descriptor ( struct cli_state * cli ,
uint16_t fnum ,
uint32_t sec_info ,
TALLOC_CTX * mem_ctx ,
struct security_descriptor * * ppsd )
{
NTSTATUS status ;
DATA_BLOB outbuf = data_blob_null ;
struct smb2_hnd * ph = NULL ;
struct security_descriptor * lsd = NULL ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
/*
* Can ' t use sync call while an async call is in flight
*/
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
status = map_fnum_to_smb2_handle ( cli ,
fnum ,
& ph ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
/* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
status = smb2cli_query_info ( cli - > conn ,
cli - > timeout ,
cli - > smb2 . session ,
cli - > smb2 . tcon ,
3 , /* in_info_type */
0 , /* in_file_info_class */
0xFFFF , /* in_max_output_length */
NULL , /* in_input_buffer */
sec_info , /* in_additional_info */
0 , /* in_flags */
ph - > fid_persistent ,
ph - > fid_volatile ,
frame ,
& outbuf ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
/* Parse the reply. */
status = unmarshall_sec_desc ( mem_ctx ,
outbuf . data ,
outbuf . length ,
& lsd ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
if ( ppsd ! = NULL ) {
* ppsd = lsd ;
} else {
TALLOC_FREE ( lsd ) ;
}
fail :
TALLOC_FREE ( frame ) ;
return status ;
}
/***************************************************************
Wrapper that allows SMB2 to set a security descriptor .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_set_security_descriptor ( struct cli_state * cli ,
uint16_t fnum ,
uint32_t sec_info ,
const struct security_descriptor * sd )
{
NTSTATUS status ;
DATA_BLOB inbuf = data_blob_null ;
struct smb2_hnd * ph = NULL ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
/*
* Can ' t use sync call while an async call is in flight
*/
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
status = map_fnum_to_smb2_handle ( cli ,
fnum ,
& ph ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
status = marshall_sec_desc ( frame ,
sd ,
& inbuf . data ,
& inbuf . length ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
/* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
status = smb2cli_set_info ( cli - > conn ,
cli - > timeout ,
cli - > smb2 . session ,
cli - > smb2 . tcon ,
3 , /* in_info_type */
0 , /* in_file_info_class */
& inbuf , /* in_input_buffer */
sec_info , /* in_additional_info */
ph - > fid_persistent ,
ph - > fid_volatile ) ;
fail :
TALLOC_FREE ( frame ) ;
return status ;
}
/***************************************************************
Wrapper that allows SMB2 to rename a file .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_rename ( struct cli_state * cli ,
const char * fname_src ,
const char * fname_dst )
{
NTSTATUS status ;
DATA_BLOB inbuf = data_blob_null ;
2013-08-20 00:36:02 +04:00
uint16_t fnum = 0xffff ;
2013-08-08 02:54:05 +04:00
struct smb2_hnd * ph = NULL ;
smb_ucs2_t * converted_str = NULL ;
size_t converted_size_bytes = 0 ;
size_t namelen = 0 ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
/*
* Can ' t use sync call while an async call is in flight
*/
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
status = get_fnum_from_path ( cli ,
fname_src ,
DELETE_ACCESS ,
& fnum ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
status = map_fnum_to_smb2_handle ( cli ,
fnum ,
& ph ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
/* SMB2 is pickier about pathnames. Ensure it doesn't
start in a ' \ ' */
if ( * fname_dst = = ' \\ ' ) {
fname_dst + + ;
}
/* SMB2 is pickier about pathnames. Ensure it doesn't
end in a ' \ ' */
namelen = strlen ( fname_dst ) ;
if ( namelen > 0 & & fname_dst [ namelen - 1 ] = = ' \\ ' ) {
char * modname = talloc_strdup ( frame , fname_dst ) ;
modname [ namelen - 1 ] = ' \0 ' ;
fname_dst = modname ;
}
if ( ! push_ucs2_talloc ( frame ,
& converted_str ,
fname_dst ,
& converted_size_bytes ) ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
/* W2K8 insists the dest name is not null
terminated . Remove the last 2 zero bytes
and reduce the name length . */
if ( converted_size_bytes < 2 ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
converted_size_bytes - = 2 ;
inbuf = data_blob_talloc_zero ( frame ,
20 + converted_size_bytes ) ;
if ( inbuf . data = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
SIVAL ( inbuf . data , 16 , converted_size_bytes ) ;
memcpy ( inbuf . data + 20 , converted_str , converted_size_bytes ) ;
/* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
level SMB2_FILE_RENAME_INFORMATION ( SMB_FILE_RENAME_INFORMATION - 1000 ) */
status = smb2cli_set_info ( cli - > conn ,
cli - > timeout ,
cli - > smb2 . session ,
cli - > smb2 . tcon ,
1 , /* in_info_type */
SMB_FILE_RENAME_INFORMATION - 1000 , /* in_file_info_class */
& inbuf , /* in_input_buffer */
0 , /* in_additional_info */
ph - > fid_persistent ,
ph - > fid_volatile ) ;
fail :
2013-08-20 00:36:02 +04:00
if ( fnum ! = 0xffff ) {
2013-08-08 02:54:05 +04:00
cli_smb2_close_fnum ( cli , fnum ) ;
}
TALLOC_FREE ( frame ) ;
return status ;
}
/***************************************************************
Wrapper that allows SMB2 to set an EA on a fnum .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_set_ea_fnum ( struct cli_state * cli ,
uint16_t fnum ,
const char * ea_name ,
const char * ea_val ,
size_t ea_len )
{
NTSTATUS status ;
DATA_BLOB inbuf = data_blob_null ;
size_t bloblen = 0 ;
char * ea_name_ascii = NULL ;
size_t namelen = 0 ;
struct smb2_hnd * ph = NULL ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
/*
* Can ' t use sync call while an async call is in flight
*/
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
status = map_fnum_to_smb2_handle ( cli ,
fnum ,
& ph ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
/* Marshall the SMB2 EA data. */
if ( ea_len > 0xFFFF ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
if ( ! push_ascii_talloc ( frame ,
& ea_name_ascii ,
ea_name ,
& namelen ) ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
if ( namelen < 2 | | namelen > 0xFF ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
bloblen = 8 + ea_len + namelen ;
/* Round up to a 4 byte boundary. */
bloblen = ( ( bloblen + 3 ) & ~ 3 ) ;
inbuf = data_blob_talloc_zero ( frame , bloblen ) ;
if ( inbuf . data = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
/* namelen doesn't include the NULL byte. */
SCVAL ( inbuf . data , 5 , namelen - 1 ) ;
SSVAL ( inbuf . data , 6 , ea_len ) ;
memcpy ( inbuf . data + 8 , ea_name_ascii , namelen ) ;
memcpy ( inbuf . data + 8 + namelen , ea_val , ea_len ) ;
/* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
level 15 ( SMB_FILE_FULL_EA_INFORMATION - 1000 ) . */
status = smb2cli_set_info ( cli - > conn ,
cli - > timeout ,
cli - > smb2 . session ,
cli - > smb2 . tcon ,
1 , /* in_info_type */
SMB_FILE_FULL_EA_INFORMATION - 1000 , /* in_file_info_class */
& inbuf , /* in_input_buffer */
0 , /* in_additional_info */
ph - > fid_persistent ,
ph - > fid_volatile ) ;
fail :
TALLOC_FREE ( frame ) ;
return status ;
}
/***************************************************************
Wrapper that allows SMB2 to set an EA on a pathname .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_set_ea_path ( struct cli_state * cli ,
const char * name ,
const char * ea_name ,
const char * ea_val ,
size_t ea_len )
{
NTSTATUS status ;
2013-08-20 00:36:02 +04:00
uint16_t fnum = 0xffff ;
2013-08-08 02:54:05 +04:00
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
/*
* Can ' t use sync call while an async call is in flight
*/
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
status = get_fnum_from_path ( cli ,
name ,
FILE_WRITE_EA ,
& fnum ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
status = cli_set_ea_fnum ( cli ,
fnum ,
ea_name ,
ea_val ,
ea_len ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
fail :
2013-08-20 00:36:02 +04:00
if ( fnum ! = 0xffff ) {
2013-08-08 02:54:05 +04:00
cli_smb2_close_fnum ( cli , fnum ) ;
}
return status ;
}
/***************************************************************
Wrapper that allows SMB2 to get an EA list on a pathname .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_get_ea_list_path ( struct cli_state * cli ,
const char * name ,
TALLOC_CTX * ctx ,
size_t * pnum_eas ,
struct ea_struct * * pea_array )
{
NTSTATUS status ;
2013-08-20 00:36:02 +04:00
uint16_t fnum = 0xffff ;
2013-08-08 02:54:05 +04:00
DATA_BLOB outbuf = data_blob_null ;
struct smb2_hnd * ph = NULL ;
struct ea_list * ea_list = NULL ;
struct ea_list * eal = NULL ;
size_t ea_count = 0 ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
* pnum_eas = 0 ;
* pea_array = NULL ;
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
/*
* Can ' t use sync call while an async call is in flight
*/
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
status = get_fnum_from_path ( cli ,
name ,
FILE_READ_EA ,
& fnum ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
status = map_fnum_to_smb2_handle ( cli ,
fnum ,
& ph ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
/* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
level 15 ( SMB_FILE_FULL_EA_INFORMATION - 1000 ) . */
status = smb2cli_query_info ( cli - > conn ,
cli - > timeout ,
cli - > smb2 . session ,
cli - > smb2 . tcon ,
1 , /* in_info_type */
SMB_FILE_FULL_EA_INFORMATION - 1000 , /* in_file_info_class */
0xFFFF , /* in_max_output_length */
NULL , /* in_input_buffer */
0 , /* in_additional_info */
0 , /* in_flags */
ph - > fid_persistent ,
ph - > fid_volatile ,
frame ,
& outbuf ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
/* Parse the reply. */
ea_list = read_nttrans_ea_list ( ctx ,
( const char * ) outbuf . data ,
outbuf . length ) ;
if ( ea_list = = NULL ) {
status = NT_STATUS_INVALID_NETWORK_RESPONSE ;
goto fail ;
}
/* Convert to an array. */
for ( eal = ea_list ; eal ; eal = eal - > next ) {
ea_count + + ;
}
if ( ea_count ) {
* pea_array = talloc_array ( ctx , struct ea_struct , ea_count ) ;
if ( * pea_array = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
ea_count = 0 ;
for ( eal = ea_list ; eal ; eal = eal - > next ) {
2015-06-26 09:54:23 +03:00
( * pea_array ) [ ea_count + + ] = eal - > ea ;
2013-08-08 02:54:05 +04:00
}
* pnum_eas = ea_count ;
}
fail :
2013-09-17 22:00:16 +04:00
if ( fnum ! = 0xffff ) {
cli_smb2_close_fnum ( cli , fnum ) ;
}
2013-08-08 02:54:05 +04:00
TALLOC_FREE ( frame ) ;
return status ;
}
struct cli_smb2_read_state {
struct tevent_context * ev ;
struct cli_state * cli ;
struct smb2_hnd * ph ;
uint64_t start_offset ;
uint32_t size ;
uint32_t received ;
uint8_t * buf ;
} ;
static void cli_smb2_read_done ( struct tevent_req * subreq ) ;
struct tevent_req * cli_smb2_read_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
uint16_t fnum ,
off_t offset ,
size_t size )
{
NTSTATUS status ;
struct tevent_req * req , * subreq ;
struct cli_smb2_read_state * state ;
req = tevent_req_create ( mem_ctx , & state , struct cli_smb2_read_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
state - > cli = cli ;
state - > start_offset = ( uint64_t ) offset ;
state - > size = ( uint32_t ) size ;
state - > received = 0 ;
state - > buf = NULL ;
status = map_fnum_to_smb2_handle ( cli ,
fnum ,
& state - > ph ) ;
if ( tevent_req_nterror ( req , status ) ) {
return tevent_req_post ( req , ev ) ;
}
subreq = smb2cli_read_send ( state ,
state - > ev ,
state - > cli - > conn ,
state - > cli - > timeout ,
state - > cli - > smb2 . session ,
state - > cli - > smb2 . tcon ,
state - > size ,
state - > start_offset ,
state - > ph - > fid_persistent ,
state - > ph - > fid_volatile ,
0 , /* minimum_count */
0 ) ; /* remaining_bytes */
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , cli_smb2_read_done , req ) ;
return req ;
}
static void cli_smb2_read_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_smb2_read_state * state = tevent_req_data (
req , struct cli_smb2_read_state ) ;
NTSTATUS status ;
status = smb2cli_read_recv ( subreq , state ,
& state - > buf , & state - > received ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
if ( state - > received > state - > size ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
tevent_req_done ( req ) ;
}
NTSTATUS cli_smb2_read_recv ( struct tevent_req * req ,
ssize_t * received ,
uint8_t * * rcvbuf )
{
NTSTATUS status ;
struct cli_smb2_read_state * state = tevent_req_data (
req , struct cli_smb2_read_state ) ;
if ( tevent_req_is_nterror ( req , & status ) ) {
return status ;
}
/*
* As in cli_read_andx_recv ( ) rcvbuf is talloced from the request , so
* better make sure that you copy it away before you talloc_free ( req ) .
* " rcvbuf " is NOT a talloc_ctx of its own , so do not talloc_move it !
*/
* received = ( ssize_t ) state - > received ;
* rcvbuf = state - > buf ;
return NT_STATUS_OK ;
}
struct cli_smb2_write_state {
struct tevent_context * ev ;
struct cli_state * cli ;
struct smb2_hnd * ph ;
uint32_t flags ;
const uint8_t * buf ;
uint64_t offset ;
uint32_t size ;
uint32_t written ;
} ;
static void cli_smb2_write_written ( struct tevent_req * req ) ;
struct tevent_req * cli_smb2_write_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
uint16_t fnum ,
uint16_t mode ,
const uint8_t * buf ,
off_t offset ,
size_t size )
{
NTSTATUS status ;
struct tevent_req * req , * subreq = NULL ;
struct cli_smb2_write_state * state = NULL ;
req = tevent_req_create ( mem_ctx , & state , struct cli_smb2_write_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
state - > cli = cli ;
/* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
state - > flags = ( uint32_t ) mode ;
state - > buf = buf ;
state - > offset = ( uint64_t ) offset ;
state - > size = ( uint32_t ) size ;
state - > written = 0 ;
status = map_fnum_to_smb2_handle ( cli ,
fnum ,
& state - > ph ) ;
if ( tevent_req_nterror ( req , status ) ) {
return tevent_req_post ( req , ev ) ;
}
subreq = smb2cli_write_send ( state ,
state - > ev ,
state - > cli - > conn ,
state - > cli - > timeout ,
state - > cli - > smb2 . session ,
state - > cli - > smb2 . tcon ,
state - > size ,
state - > offset ,
state - > ph - > fid_persistent ,
state - > ph - > fid_volatile ,
0 , /* remaining_bytes */
state - > flags , /* flags */
state - > buf ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , cli_smb2_write_written , req ) ;
return req ;
}
static void cli_smb2_write_written ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_smb2_write_state * state = tevent_req_data (
req , struct cli_smb2_write_state ) ;
NTSTATUS status ;
uint32_t written ;
status = smb2cli_write_recv ( subreq , & written ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
state - > written = written ;
tevent_req_done ( req ) ;
}
NTSTATUS cli_smb2_write_recv ( struct tevent_req * req ,
size_t * pwritten )
{
struct cli_smb2_write_state * state = tevent_req_data (
req , struct cli_smb2_write_state ) ;
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
tevent_req_received ( req ) ;
return status ;
}
if ( pwritten ! = NULL ) {
* pwritten = ( size_t ) state - > written ;
}
tevent_req_received ( req ) ;
return NT_STATUS_OK ;
}
/***************************************************************
Wrapper that allows SMB2 async write using an fnum .
This is mostly cut - and - paste from Volker ' s code inside
source3 / libsmb / clireadwrite . c , adapted for SMB2 .
Done this way so I can reuse all the logic inside cli_push ( )
for free : - ) .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct cli_smb2_writeall_state {
struct tevent_context * ev ;
struct cli_state * cli ;
struct smb2_hnd * ph ;
uint32_t flags ;
const uint8_t * buf ;
uint64_t offset ;
uint32_t size ;
uint32_t written ;
} ;
static void cli_smb2_writeall_written ( struct tevent_req * req ) ;
struct tevent_req * cli_smb2_writeall_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
uint16_t fnum ,
uint16_t mode ,
const uint8_t * buf ,
off_t offset ,
size_t size )
{
NTSTATUS status ;
struct tevent_req * req , * subreq = NULL ;
struct cli_smb2_writeall_state * state = NULL ;
uint32_t to_write ;
uint32_t max_size ;
bool ok ;
req = tevent_req_create ( mem_ctx , & state , struct cli_smb2_writeall_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
state - > cli = cli ;
/* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
state - > flags = ( uint32_t ) mode ;
state - > buf = buf ;
state - > offset = ( uint64_t ) offset ;
state - > size = ( uint32_t ) size ;
state - > written = 0 ;
status = map_fnum_to_smb2_handle ( cli ,
fnum ,
& state - > ph ) ;
if ( tevent_req_nterror ( req , status ) ) {
return tevent_req_post ( req , ev ) ;
}
to_write = state - > size ;
max_size = smb2cli_conn_max_write_size ( state - > cli - > conn ) ;
to_write = MIN ( max_size , to_write ) ;
ok = smb2cli_conn_req_possible ( state - > cli - > conn , & max_size ) ;
if ( ok ) {
to_write = MIN ( max_size , to_write ) ;
}
subreq = smb2cli_write_send ( state ,
state - > ev ,
state - > cli - > conn ,
state - > cli - > timeout ,
state - > cli - > smb2 . session ,
state - > cli - > smb2 . tcon ,
to_write ,
state - > offset ,
state - > ph - > fid_persistent ,
state - > ph - > fid_volatile ,
0 , /* remaining_bytes */
state - > flags , /* flags */
state - > buf + state - > written ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , cli_smb2_writeall_written , req ) ;
return req ;
}
static void cli_smb2_writeall_written ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_smb2_writeall_state * state = tevent_req_data (
req , struct cli_smb2_writeall_state ) ;
NTSTATUS status ;
uint32_t written , to_write ;
uint32_t max_size ;
bool ok ;
status = smb2cli_write_recv ( subreq , & written ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
state - > written + = written ;
if ( state - > written > state - > size ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
to_write = state - > size - state - > written ;
if ( to_write = = 0 ) {
tevent_req_done ( req ) ;
return ;
}
max_size = smb2cli_conn_max_write_size ( state - > cli - > conn ) ;
to_write = MIN ( max_size , to_write ) ;
ok = smb2cli_conn_req_possible ( state - > cli - > conn , & max_size ) ;
if ( ok ) {
to_write = MIN ( max_size , to_write ) ;
}
subreq = smb2cli_write_send ( state ,
state - > ev ,
state - > cli - > conn ,
state - > cli - > timeout ,
state - > cli - > smb2 . session ,
state - > cli - > smb2 . tcon ,
to_write ,
state - > offset + state - > written ,
state - > ph - > fid_persistent ,
state - > ph - > fid_volatile ,
0 , /* remaining_bytes */
state - > flags , /* flags */
state - > buf + state - > written ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , cli_smb2_writeall_written , req ) ;
}
NTSTATUS cli_smb2_writeall_recv ( struct tevent_req * req ,
size_t * pwritten )
{
struct cli_smb2_writeall_state * state = tevent_req_data (
req , struct cli_smb2_writeall_state ) ;
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
return status ;
}
if ( pwritten ! = NULL ) {
* pwritten = ( size_t ) state - > written ;
}
return NT_STATUS_OK ;
}
2015-05-28 01:13:15 +03:00
struct cli_smb2_splice_state {
struct tevent_context * ev ;
struct cli_state * cli ;
struct smb2_hnd * src_ph ;
struct smb2_hnd * dst_ph ;
int ( * splice_cb ) ( off_t n , void * priv ) ;
void * priv ;
off_t written ;
off_t size ;
off_t src_offset ;
off_t dst_offset ;
bool resized ;
struct req_resume_key_rsp resume_rsp ;
struct srv_copychunk_copy cc_copy ;
} ;
static void cli_splice_copychunk_send ( struct cli_smb2_splice_state * state ,
struct tevent_req * req ) ;
static void cli_splice_copychunk_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_smb2_splice_state * state =
tevent_req_data ( req ,
struct cli_smb2_splice_state ) ;
struct smbXcli_conn * conn = state - > cli - > conn ;
DATA_BLOB out_input_buffer = data_blob_null ;
DATA_BLOB out_output_buffer = data_blob_null ;
struct srv_copychunk_rsp cc_copy_rsp ;
enum ndr_err_code ndr_ret ;
NTSTATUS status ;
status = smb2cli_ioctl_recv ( subreq , state ,
& out_input_buffer ,
& out_output_buffer ) ;
TALLOC_FREE ( subreq ) ;
if ( ( ! NT_STATUS_EQUAL ( status , NT_STATUS_INVALID_PARAMETER ) | |
state - > resized ) & & tevent_req_nterror ( req , status ) ) {
return ;
}
ndr_ret = ndr_pull_struct_blob ( & out_output_buffer , state , & cc_copy_rsp ,
( ndr_pull_flags_fn_t ) ndr_pull_srv_copychunk_rsp ) ;
if ( ndr_ret ! = NDR_ERR_SUCCESS ) {
DEBUG ( 0 , ( " failed to unmarshall copy chunk rsp \n " ) ) ;
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
if ( NT_STATUS_EQUAL ( status , NT_STATUS_INVALID_PARAMETER ) ) {
uint32_t max_chunks = MIN ( cc_copy_rsp . chunks_written ,
cc_copy_rsp . total_bytes_written / cc_copy_rsp . chunk_bytes_written ) ;
if ( ( cc_copy_rsp . chunk_bytes_written > smb2cli_conn_cc_chunk_len ( conn ) | |
max_chunks > smb2cli_conn_cc_max_chunks ( conn ) ) & &
tevent_req_nterror ( req , status ) ) {
return ;
}
state - > resized = true ;
smb2cli_conn_set_cc_chunk_len ( conn , cc_copy_rsp . chunk_bytes_written ) ;
smb2cli_conn_set_cc_max_chunks ( conn , max_chunks ) ;
} else {
if ( ( state - > src_offset > INT64_MAX - cc_copy_rsp . total_bytes_written ) | |
( state - > dst_offset > INT64_MAX - cc_copy_rsp . total_bytes_written ) | |
( state - > written > INT64_MAX - cc_copy_rsp . total_bytes_written ) ) {
tevent_req_nterror ( req , NT_STATUS_FILE_TOO_LARGE ) ;
return ;
}
state - > src_offset + = cc_copy_rsp . total_bytes_written ;
state - > dst_offset + = cc_copy_rsp . total_bytes_written ;
state - > written + = cc_copy_rsp . total_bytes_written ;
if ( ! state - > splice_cb ( state - > written , state - > priv ) ) {
tevent_req_nterror ( req , NT_STATUS_CANCELLED ) ;
return ;
}
}
cli_splice_copychunk_send ( state , req ) ;
}
static void cli_splice_copychunk_send ( struct cli_smb2_splice_state * state ,
struct tevent_req * req )
{
struct tevent_req * subreq ;
enum ndr_err_code ndr_ret ;
struct smbXcli_conn * conn = state - > cli - > conn ;
struct srv_copychunk_copy * cc_copy = & state - > cc_copy ;
off_t src_offset = state - > src_offset ;
off_t dst_offset = state - > dst_offset ;
uint32_t req_len = MIN ( smb2cli_conn_cc_chunk_len ( conn ) * smb2cli_conn_cc_max_chunks ( conn ) ,
state - > size - state - > written ) ;
DATA_BLOB in_input_buffer = data_blob_null ;
DATA_BLOB in_output_buffer = data_blob_null ;
if ( state - > size - state - > written = = 0 ) {
tevent_req_done ( req ) ;
return ;
}
cc_copy - > chunk_count = 0 ;
while ( req_len ) {
cc_copy - > chunks [ cc_copy - > chunk_count ] . source_off = src_offset ;
cc_copy - > chunks [ cc_copy - > chunk_count ] . target_off = dst_offset ;
cc_copy - > chunks [ cc_copy - > chunk_count ] . length = MIN ( req_len ,
smb2cli_conn_cc_chunk_len ( conn ) ) ;
if ( req_len < cc_copy - > chunks [ cc_copy - > chunk_count ] . length ) {
tevent_req_nterror ( req , NT_STATUS_INTERNAL_ERROR ) ;
return ;
}
req_len - = cc_copy - > chunks [ cc_copy - > chunk_count ] . length ;
if ( ( src_offset > INT64_MAX - cc_copy - > chunks [ cc_copy - > chunk_count ] . length ) | |
( dst_offset > INT64_MAX - cc_copy - > chunks [ cc_copy - > chunk_count ] . length ) ) {
tevent_req_nterror ( req , NT_STATUS_FILE_TOO_LARGE ) ;
return ;
}
src_offset + = cc_copy - > chunks [ cc_copy - > chunk_count ] . length ;
dst_offset + = cc_copy - > chunks [ cc_copy - > chunk_count ] . length ;
cc_copy - > chunk_count + + ;
}
ndr_ret = ndr_push_struct_blob ( & in_input_buffer , state , cc_copy ,
( ndr_push_flags_fn_t ) ndr_push_srv_copychunk_copy ) ;
if ( ndr_ret ! = NDR_ERR_SUCCESS ) {
DEBUG ( 0 , ( " failed to marshall copy chunk req \n " ) ) ;
tevent_req_nterror ( req , NT_STATUS_INTERNAL_ERROR ) ;
return ;
}
subreq = smb2cli_ioctl_send ( state , state - > ev , state - > cli - > conn ,
state - > cli - > timeout ,
state - > cli - > smb2 . session ,
state - > cli - > smb2 . tcon ,
state - > dst_ph - > fid_persistent , /* in_fid_persistent */
state - > dst_ph - > fid_volatile , /* in_fid_volatile */
FSCTL_SRV_COPYCHUNK_WRITE ,
0 , /* in_max_input_length */
& in_input_buffer ,
12 , /* in_max_output_length */
& in_output_buffer ,
SMB2_IOCTL_FLAG_IS_FSCTL ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq ,
cli_splice_copychunk_done ,
req ) ;
}
static void cli_splice_key_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_smb2_splice_state * state =
tevent_req_data ( req ,
struct cli_smb2_splice_state ) ;
enum ndr_err_code ndr_ret ;
NTSTATUS status ;
DATA_BLOB out_input_buffer = data_blob_null ;
DATA_BLOB out_output_buffer = data_blob_null ;
status = smb2cli_ioctl_recv ( subreq , state ,
& out_input_buffer ,
& out_output_buffer ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
ndr_ret = ndr_pull_struct_blob ( & out_output_buffer ,
state , & state - > resume_rsp ,
( ndr_pull_flags_fn_t ) ndr_pull_req_resume_key_rsp ) ;
if ( ndr_ret ! = NDR_ERR_SUCCESS ) {
DEBUG ( 0 , ( " failed to unmarshall resume key rsp \n " ) ) ;
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
memcpy ( & state - > cc_copy . source_key ,
& state - > resume_rsp . resume_key ,
sizeof state - > resume_rsp . resume_key ) ;
cli_splice_copychunk_send ( state , req ) ;
}
struct tevent_req * cli_smb2_splice_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
uint16_t src_fnum , uint16_t dst_fnum ,
off_t size , off_t src_offset , off_t dst_offset ,
int ( * splice_cb ) ( off_t n , void * priv ) ,
void * priv )
{
struct tevent_req * req ;
struct tevent_req * subreq ;
struct cli_smb2_splice_state * state ;
NTSTATUS status ;
DATA_BLOB in_input_buffer = data_blob_null ;
DATA_BLOB in_output_buffer = data_blob_null ;
req = tevent_req_create ( mem_ctx , & state , struct cli_smb2_splice_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > cli = cli ;
state - > ev = ev ;
state - > splice_cb = splice_cb ;
state - > priv = priv ;
state - > size = size ;
state - > written = 0 ;
state - > src_offset = src_offset ;
state - > dst_offset = dst_offset ;
state - > cc_copy . chunks = talloc_array ( state ,
struct srv_copychunk ,
smb2cli_conn_cc_max_chunks ( cli - > conn ) ) ;
if ( state - > cc_copy . chunks = = NULL ) {
return NULL ;
}
status = map_fnum_to_smb2_handle ( cli , src_fnum , & state - > src_ph ) ;
if ( tevent_req_nterror ( req , status ) )
return tevent_req_post ( req , ev ) ;
status = map_fnum_to_smb2_handle ( cli , dst_fnum , & state - > dst_ph ) ;
if ( tevent_req_nterror ( req , status ) )
return tevent_req_post ( req , ev ) ;
subreq = smb2cli_ioctl_send ( state , ev , cli - > conn ,
cli - > timeout ,
cli - > smb2 . session ,
cli - > smb2 . tcon ,
state - > src_ph - > fid_persistent , /* in_fid_persistent */
state - > src_ph - > fid_volatile , /* in_fid_volatile */
FSCTL_SRV_REQUEST_RESUME_KEY ,
0 , /* in_max_input_length */
& in_input_buffer ,
32 , /* in_max_output_length */
& in_output_buffer ,
SMB2_IOCTL_FLAG_IS_FSCTL ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return NULL ;
}
tevent_req_set_callback ( subreq ,
cli_splice_key_done ,
req ) ;
return req ;
}
NTSTATUS cli_smb2_splice_recv ( struct tevent_req * req , off_t * written )
{
struct cli_smb2_splice_state * state = tevent_req_data (
req , struct cli_smb2_splice_state ) ;
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
tevent_req_received ( req ) ;
return status ;
}
if ( written ! = NULL ) {
* written = state - > written ;
}
tevent_req_received ( req ) ;
return NT_STATUS_OK ;
}