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"
2016-09-12 22:38:15 +03:00
# include "../librpc/gen_ndr/ndr_security.h"
2013-08-08 02:54:05 +04:00
# include "lib/util_ea.h"
2015-05-28 01:13:15 +03:00
# include "librpc/gen_ndr/ndr_ioctl.h"
2016-08-17 01:26:53 +03:00
# include "ntioctl.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 ;
2016-06-22 01:49:27 +03:00
size_t fname_len = 0 ;
2016-08-20 03:00:25 +03:00
const char * startp = NULL ;
const char * endp = NULL ;
time_t tstamp = ( time_t ) 0 ;
struct smb2_create_blobs * cblobs = NULL ;
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 ;
}
2016-08-20 03:00:25 +03:00
/* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
fname_len = strlen ( fname ) ;
if ( clistr_is_previous_version_path ( fname , & startp , & endp , & tstamp ) ) {
size_t len_before_gmt = startp - fname ;
size_t len_after_gmt = fname + fname_len - endp ;
DATA_BLOB twrp_blob ;
NTTIME ntt ;
NTSTATUS status ;
char * new_fname = talloc_array ( state , char ,
len_before_gmt + len_after_gmt + 1 ) ;
if ( tevent_req_nomem ( new_fname , req ) ) {
return tevent_req_post ( req , ev ) ;
}
memcpy ( new_fname , fname , len_before_gmt ) ;
memcpy ( new_fname + len_before_gmt , endp , len_after_gmt + 1 ) ;
fname = new_fname ;
fname_len = len_before_gmt + len_after_gmt ;
unix_to_nt_time ( & ntt , tstamp ) ;
twrp_blob = data_blob_const ( ( const void * ) & ntt , 8 ) ;
cblobs = talloc_zero ( state , struct smb2_create_blobs ) ;
if ( tevent_req_nomem ( cblobs , req ) ) {
return tevent_req_post ( req , ev ) ;
}
status = smb2_create_blob_add ( state , cblobs ,
SMB2_CREATE_TAG_TWRP , twrp_blob ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
}
}
2013-08-08 02:54:05 +04:00
/* SMB2 is pickier about pathnames. Ensure it doesn't
start in a ' \ ' */
if ( * fname = = ' \\ ' ) {
fname + + ;
2016-08-20 03:00:25 +03:00
fname_len - - ;
2013-08-08 02:54:05 +04:00
}
2016-06-22 01:49:27 +03:00
/* Or end in a '\' */
if ( fname_len > 0 & & fname [ fname_len - 1 ] = = ' \\ ' ) {
char * new_fname = talloc_strdup ( state , fname ) ;
if ( tevent_req_nomem ( new_fname , req ) ) {
return tevent_req_post ( req , ev ) ;
}
new_fname [ fname_len - 1 ] = ' \0 ' ;
fname = new_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 ,
2016-08-20 03:00:25 +03:00
cblobs ) ;
2014-06-20 12:23:47 +04:00
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 ) ) {
2016-05-02 23:48:14 +03:00
state - > cli - > raw_status = status ;
2014-06-20 12:23:47 +04:00
return status ;
}
if ( pfnum ! = NULL ) {
* pfnum = state - > fnum ;
}
if ( cr ! = NULL ) {
* cr = state - > cr ;
}
2016-05-02 23:48:14 +03:00
state - > cli - > raw_status = NT_STATUS_OK ;
2014-06-20 12:23:47 +04:00
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 )
{
2016-05-02 23:48:14 +03:00
struct cli_smb2_close_fnum_state * state = tevent_req_data (
req , struct cli_smb2_close_fnum_state ) ;
2017-11-29 20:21:30 +03:00
NTSTATUS status = NT_STATUS_OK ;
if ( tevent_req_is_nterror ( req , & status ) ) {
state - > cli - > raw_status = status ;
}
tevent_req_received ( req ) ;
2016-05-02 23:48:14 +03:00
return status ;
2014-06-27 13:47:36 +04:00
}
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 ) ;
2017-06-20 09:35:13 +03:00
fail :
TALLOC_FREE ( frame ) ;
return status ;
}
struct cli_smb2_delete_on_close_state {
struct cli_state * cli ;
uint16_t fnum ;
struct smb2_hnd * ph ;
uint8_t data [ 1 ] ;
DATA_BLOB inbuf ;
} ;
static void cli_smb2_delete_on_close_done ( struct tevent_req * subreq ) ;
struct tevent_req * cli_smb2_delete_on_close_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
uint16_t fnum ,
bool flag )
{
struct tevent_req * req = NULL ;
struct cli_smb2_delete_on_close_state * state = NULL ;
struct tevent_req * subreq = NULL ;
uint8_t in_info_type ;
uint8_t in_file_info_class ;
NTSTATUS status ;
req = tevent_req_create ( mem_ctx , & state ,
struct cli_smb2_delete_on_close_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > cli = cli ;
state - > fnum = fnum ;
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
}
status = map_fnum_to_smb2_handle ( cli , fnum , & state - > ph ) ;
if ( tevent_req_nterror ( req , status ) ) {
return tevent_req_post ( req , ev ) ;
}
/*
* setinfo on the handle with info_type SMB2_SETINFO_FILE ( 1 ) ,
* level 13 ( SMB_FILE_DISPOSITION_INFORMATION - 1000 ) .
*/
in_info_type = 1 ;
in_file_info_class = SMB_FILE_DISPOSITION_INFORMATION - 1000 ;
/* Setup data array. */
SCVAL ( & state - > data [ 0 ] , 0 , flag ? 1 : 0 ) ;
state - > inbuf . data = & state - > data [ 0 ] ;
state - > inbuf . length = 1 ;
subreq = smb2cli_set_info_send ( state , ev ,
cli - > conn ,
cli - > timeout ,
cli - > smb2 . session ,
cli - > smb2 . tcon ,
in_info_type ,
in_file_info_class ,
& state - > inbuf , /* in_input_buffer */
0 , /* in_additional_info */
state - > ph - > fid_persistent ,
state - > ph - > fid_volatile ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq ,
cli_smb2_delete_on_close_done ,
req ) ;
return req ;
}
static void cli_smb2_delete_on_close_done ( struct tevent_req * subreq )
{
NTSTATUS status = smb2cli_set_info_recv ( subreq ) ;
tevent_req_simple_finish_ntstatus ( subreq , status ) ;
}
NTSTATUS cli_smb2_delete_on_close_recv ( struct tevent_req * req )
{
struct cli_smb2_delete_on_close_state * state =
tevent_req_data ( req ,
struct cli_smb2_delete_on_close_state ) ;
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
state - > cli - > raw_status = status ;
tevent_req_received ( req ) ;
return status ;
}
state - > cli - > raw_status = NT_STATUS_OK ;
tevent_req_received ( req ) ;
return NT_STATUS_OK ;
}
NTSTATUS cli_smb2_delete_on_close ( struct cli_state * cli , uint16_t fnum , bool flag )
{
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_delete_on_close_send ( frame , ev , cli , fnum , flag ) ;
if ( req = = NULL ) {
goto fail ;
}
if ( ! tevent_req_poll_ntstatus ( req , ev , & status ) ) {
goto fail ;
}
status = cli_smb2_delete_on_close_recv ( req ) ;
2014-06-27 13:47:36 +04:00
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 ) ;
}
2016-12-13 02:52:11 +03:00
cli - > raw_status = status ;
2013-08-08 02:54:05 +04:00
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 ;
}
2016-12-13 02:52:11 +03:00
status = cli_smb2_close_fnum ( cli , fnum ) ;
2013-08-08 02:54:05 +04:00
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 ;
2016-12-13 02:52:11 +03:00
return status ;
2013-08-08 02:54:05 +04:00
}
2017-08-17 01:48:01 +03:00
/***************************************************************
Wrapper that allows SMB2 to check if a path is a directory .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_chkpath ( struct cli_state * cli ,
const char * name )
{
NTSTATUS status ;
uint16_t fnum = 0xffff ;
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 ;
}
/* Ensure this is a directory. */
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 ,
NULL ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
return cli_smb2_close_fnum ( cli , fnum ) ;
}
2013-08-08 02:54:05 +04:00
/***************************************************************
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 ) ;
}
2016-12-13 02:52:11 +03:00
cli - > raw_status = status ;
2013-08-08 02:54:05 +04:00
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 :
2016-12-13 02:52:11 +03:00
cli - > raw_status = status ;
2013-08-08 02:54:05 +04:00
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 ) ;
2016-12-13 02:52:11 +03:00
cli - > raw_status = status ;
2013-08-08 02:54:05 +04:00
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 ) ;
}
2016-12-13 02:52:11 +03:00
cli - > raw_status = status ;
2013-08-08 02:54:05 +04:00
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 ) ;
}
2016-12-13 02:52:11 +03:00
cli - > raw_status = status ;
2013-08-08 02:54:05 +04:00
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 ) ;
}
2016-12-13 02:52:11 +03:00
cli - > raw_status = status ;
2013-08-08 02:54:05 +04:00
TALLOC_FREE ( frame ) ;
return status ;
}
2017-07-21 22:41:11 +03:00
/***************************************************************
Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
a pathname .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_setpathinfo ( struct cli_state * cli ,
const char * name ,
uint8_t in_info_type ,
uint8_t in_file_info_class ,
const DATA_BLOB * p_in_data )
{
NTSTATUS status ;
uint16_t fnum = 0xffff ;
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_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 ;
}
status = smb2cli_set_info ( cli - > conn ,
cli - > timeout ,
cli - > smb2 . session ,
cli - > smb2 . tcon ,
in_info_type ,
in_file_info_class ,
p_in_data , /* in_input_buffer */
0 , /* in_additional_info */
ph - > fid_persistent ,
ph - > fid_volatile ) ;
fail :
if ( fnum ! = 0xffff ) {
cli_smb2_close_fnum ( cli , fnum ) ;
}
cli - > raw_status = status ;
TALLOC_FREE ( frame ) ;
return status ;
}
2013-08-08 02:54:05 +04:00
/***************************************************************
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 )
{
uint8_t inbuf_store [ 40 ] ;
DATA_BLOB inbuf = data_blob_null ;
/* 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 ) ;
2017-07-17 20:37:15 +03:00
/*
* SMB1 uses attr = = 0 to clear all attributes
* on a file ( end up with FILE_ATTRIBUTE_NORMAL ) ,
* and attr = = FILE_ATTRIBUTE_NORMAL to mean ignore
* request attribute change .
*
* SMB2 uses exactly the reverse . Unfortunately as the
* cli_setatr ( ) ABI is exposed inside libsmbclient ,
* we must make the SMB2 cli_smb2_setatr ( ) call
* export the same ABI as the SMB1 cli_setatr ( )
* which calls it . This means reversing the sense
* of the requested attr argument if it ' s zero
* or FILE_ATTRIBUTE_NORMAL .
*
* See BUG : https : //bugzilla.samba.org/show_bug.cgi?id=12899
*/
if ( attr = = 0 ) {
attr = FILE_ATTRIBUTE_NORMAL ;
} else if ( attr = = FILE_ATTRIBUTE_NORMAL ) {
attr = 0 ;
}
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 ) ;
2017-07-21 22:46:23 +03:00
return cli_smb2_setpathinfo ( cli ,
name ,
2013-08-08 02:54:05 +04:00
1 , /* in_info_type */
2017-07-21 22:46:23 +03:00
/* in_file_info_class */
SMB_FILE_BASIC_INFORMATION - 1000 ,
& inbuf ) ;
2013-08-08 02:54:05 +04:00
}
2017-07-21 22:41:11 +03:00
2013-08-08 02:54:05 +04:00
/***************************************************************
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 ) ;
}
2016-12-13 02:52:11 +03:00
cli - > raw_status = smb2cli_set_info ( cli - > conn ,
2013-08-08 02:54:05 +04:00
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 ) ;
2016-12-13 02:52:11 +03:00
return cli - > raw_status ;
2013-08-08 02:54:05 +04:00
}
/***************************************************************
Wrapper that allows SMB2 to query disk attributes ( size ) .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2016-01-06 01:08:25 +03:00
NTSTATUS cli_smb2_dskattr ( struct cli_state * cli , const char * path ,
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 ,
2016-01-06 01:08:25 +03:00
path ,
2013-08-08 02:54:05 +04:00
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 ) ;
}
2016-12-13 02:52:11 +03:00
cli - > raw_status = status ;
2013-08-08 02:54:05 +04:00
TALLOC_FREE ( frame ) ;
return status ;
}
2017-11-15 00:52:03 +03:00
/***************************************************************
Wrapper that allows SMB2 to query file system sizes .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_get_fs_full_size_info ( struct cli_state * cli ,
uint64_t * total_allocation_units ,
uint64_t * caller_allocation_units ,
uint64_t * actual_allocation_units ,
uint64_t * sectors_per_allocation_unit ,
uint64_t * bytes_per_sector )
{
NTSTATUS status ;
uint16_t fnum = 0xffff ;
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 ;
}
/* 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 7 ( SMB_FS_FULL_SIZE_INFORMATION ) . */
status = smb2cli_query_info ( cli - > conn ,
cli - > timeout ,
cli - > smb2 . session ,
cli - > smb2 . tcon ,
SMB2_GETINFO_FS , /* in_info_type */
/* in_file_info_class */
SMB_FS_FULL_SIZE_INFORMATION - 1000 ,
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 ;
}
if ( outbuf . length < 32 ) {
status = NT_STATUS_INVALID_NETWORK_RESPONSE ;
goto fail ;
}
* total_allocation_units = BIG_UINT ( outbuf . data , 0 ) ;
* caller_allocation_units = BIG_UINT ( outbuf . data , 8 ) ;
* actual_allocation_units = BIG_UINT ( outbuf . data , 16 ) ;
* sectors_per_allocation_unit = ( uint64_t ) IVAL ( outbuf . data , 24 ) ;
* bytes_per_sector = ( uint64_t ) IVAL ( outbuf . data , 28 ) ;
fail :
if ( fnum ! = 0xffff ) {
cli_smb2_close_fnum ( cli , fnum ) ;
}
cli - > raw_status = status ;
TALLOC_FREE ( frame ) ;
return status ;
}
2016-09-20 14:32:06 +03:00
/***************************************************************
Wrapper that allows SMB2 to query file system attributes .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_get_fs_attr_info ( struct cli_state * cli , uint32_t * fs_attr )
{
NTSTATUS status ;
uint16_t fnum = 0xffff ;
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 ;
}
/* 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 ;
}
status = smb2cli_query_info ( cli - > conn , cli - > timeout , cli - > smb2 . session ,
cli - > smb2 . tcon , 2 , /* in_info_type */
5 , /* 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 ;
}
if ( outbuf . length < 12 ) {
status = NT_STATUS_INVALID_NETWORK_RESPONSE ;
goto fail ;
}
* fs_attr = IVAL ( outbuf . data , 0 ) ;
fail :
if ( fnum ! = 0xffff ) {
cli_smb2_close_fnum ( cli , fnum ) ;
}
2016-12-13 02:52:11 +03:00
cli - > raw_status = status ;
2016-12-12 18:20:29 +03:00
2016-09-20 14:32:06 +03:00
TALLOC_FREE ( frame ) ;
return status ;
}
2017-11-15 02:42:14 +03:00
/***************************************************************
Wrapper that allows SMB2 to query file system volume info .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_get_fs_volume_info ( struct cli_state * cli ,
TALLOC_CTX * mem_ctx ,
char * * _volume_name ,
uint32_t * pserial_number ,
time_t * pdate )
{
NTSTATUS status ;
uint16_t fnum = 0xffff ;
DATA_BLOB outbuf = data_blob_null ;
struct smb2_hnd * ph = NULL ;
uint32_t nlen ;
char * volume_name = 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 ;
}
/* 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 1 ( SMB_FS_VOLUME_INFORMATION ) . */
status = smb2cli_query_info ( cli - > conn ,
cli - > timeout ,
cli - > smb2 . session ,
cli - > smb2 . tcon ,
SMB2_GETINFO_FS , /* in_info_type */
/* in_file_info_class */
SMB_FS_VOLUME_INFORMATION - 1000 ,
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 ;
}
if ( outbuf . length < 24 ) {
status = NT_STATUS_INVALID_NETWORK_RESPONSE ;
goto fail ;
}
if ( pdate ) {
struct timespec ts ;
ts = interpret_long_date ( ( char * ) outbuf . data ) ;
* pdate = ts . tv_sec ;
}
if ( pserial_number ) {
* pserial_number = IVAL ( outbuf . data , 8 ) ;
}
nlen = IVAL ( outbuf . data , 12 ) ;
if ( nlen + 18 < 18 ) {
/* Integer wrap. */
status = NT_STATUS_INVALID_NETWORK_RESPONSE ;
goto fail ;
}
/*
* The next check is safe as we know outbuf . length > = 24
* from above .
*/
if ( nlen > ( outbuf . length - 18 ) ) {
status = NT_STATUS_INVALID_NETWORK_RESPONSE ;
goto fail ;
}
clistr_pull_talloc ( mem_ctx ,
( const char * ) outbuf . data ,
0 ,
& volume_name ,
outbuf . data + 18 ,
nlen ,
STR_UNICODE ) ;
if ( volume_name = = NULL ) {
status = map_nt_error_from_unix ( errno ) ;
goto fail ;
}
* _volume_name = volume_name ;
fail :
if ( fnum ! = 0xffff ) {
cli_smb2_close_fnum ( cli , fnum ) ;
}
cli - > raw_status = status ;
TALLOC_FREE ( frame ) ;
return status ;
}
2013-08-08 02:54:05 +04:00
/***************************************************************
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 :
2016-12-13 02:52:11 +03:00
cli - > raw_status = status ;
2013-08-08 02:54:05 +04:00
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 :
2016-12-13 02:52:11 +03:00
cli - > raw_status = status ;
2013-08-08 02:54:05 +04:00
TALLOC_FREE ( frame ) ;
return status ;
}
/***************************************************************
Wrapper that allows SMB2 to rename a file .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_rename ( struct cli_state * cli ,
2017-03-22 00:02:48 +03:00
const char * fname_src ,
const char * fname_dst ,
bool replace )
2013-08-08 02:54:05 +04:00
{
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 ;
}
2017-03-22 00:02:48 +03:00
if ( replace ) {
SCVAL ( inbuf . data , 0 , 1 ) ;
}
2013-08-08 02:54:05 +04:00
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 ) ;
}
2016-12-13 02:52:11 +03:00
cli - > raw_status = status ;
2013-08-08 02:54:05 +04:00
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 :
2016-12-13 02:52:11 +03:00
cli - > raw_status = status ;
2013-08-08 02:54:05 +04:00
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 ) ;
}
2016-12-13 02:52:11 +03:00
cli - > raw_status = status ;
2013-08-08 02:54:05 +04:00
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 ) ;
}
2016-12-13 02:52:11 +03:00
cli - > raw_status = status ;
2013-08-08 02:54:05 +04:00
TALLOC_FREE ( frame ) ;
return status ;
}
2016-09-12 22:38:15 +03:00
/***************************************************************
Wrapper that allows SMB2 to get user quota .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_get_user_quota ( struct cli_state * cli ,
int quota_fnum ,
SMB_NTQUOTA_STRUCT * pqt )
{
NTSTATUS status ;
DATA_BLOB inbuf = data_blob_null ;
DATA_BLOB outbuf = data_blob_null ;
struct smb2_hnd * ph = NULL ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
unsigned sid_len ;
unsigned int offset ;
uint8_t * buf ;
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 , quota_fnum , & ph ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
sid_len = ndr_size_dom_sid ( & pqt - > sid , 0 ) ;
inbuf = data_blob_talloc_zero ( frame , 24 + sid_len ) ;
if ( inbuf . data = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
buf = inbuf . data ;
SCVAL ( buf , 0 , 1 ) ; /* ReturnSingle */
SCVAL ( buf , 1 , 0 ) ; /* RestartScan */
SSVAL ( buf , 2 , 0 ) ; /* Reserved */
if ( 8 + sid_len < 8 ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
SIVAL ( buf , 4 , 8 + sid_len ) ; /* SidListLength */
SIVAL ( buf , 8 , 0 ) ; /* StartSidLength */
SIVAL ( buf , 12 , 0 ) ; /* StartSidOffset */
SIVAL ( buf , 16 , 0 ) ; /* NextEntryOffset */
SIVAL ( buf , 20 , sid_len ) ; /* SidLength */
sid_linearize ( buf + 24 , sid_len , & pqt - > sid ) ;
status = smb2cli_query_info ( cli - > conn , cli - > timeout , cli - > smb2 . session ,
cli - > smb2 . tcon , 4 , /* in_info_type */
0 , /* in_file_info_class */
0xFFFF , /* in_max_output_length */
& inbuf , /* 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 ;
}
if ( ! parse_user_quota_record ( outbuf . data , outbuf . length , & offset ,
pqt ) ) {
status = NT_STATUS_INVALID_NETWORK_RESPONSE ;
DEBUG ( 0 , ( " Got invalid FILE_QUOTA_INFORMATION in reply. \n " ) ) ;
}
fail :
2016-12-13 02:52:11 +03:00
cli - > raw_status = status ;
2016-09-12 22:38:15 +03:00
TALLOC_FREE ( frame ) ;
return status ;
}
2016-09-19 22:17:10 +03:00
/***************************************************************
Wrapper that allows SMB2 to list user quota .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_list_user_quota_step ( struct cli_state * cli ,
TALLOC_CTX * mem_ctx ,
int quota_fnum ,
SMB_NTQUOTA_LIST * * pqt_list ,
bool first )
{
NTSTATUS status ;
DATA_BLOB inbuf = data_blob_null ;
DATA_BLOB outbuf = data_blob_null ;
struct smb2_hnd * ph = NULL ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
uint8_t * buf ;
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 cleanup ;
}
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto cleanup ;
}
status = map_fnum_to_smb2_handle ( cli , quota_fnum , & ph ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto cleanup ;
}
inbuf = data_blob_talloc_zero ( frame , 16 ) ;
if ( inbuf . data = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto cleanup ;
}
buf = inbuf . data ;
SCVAL ( buf , 0 , 0 ) ; /* ReturnSingle */
SCVAL ( buf , 1 , first ? 1 : 0 ) ; /* RestartScan */
SSVAL ( buf , 2 , 0 ) ; /* Reserved */
SIVAL ( buf , 4 , 0 ) ; /* SidListLength */
SIVAL ( buf , 8 , 0 ) ; /* StartSidLength */
SIVAL ( buf , 12 , 0 ) ; /* StartSidOffset */
status = smb2cli_query_info ( cli - > conn , cli - > timeout , cli - > smb2 . session ,
cli - > smb2 . tcon , 4 , /* in_info_type */
0 , /* in_file_info_class */
0xFFFF , /* in_max_output_length */
& inbuf , /* 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 cleanup ;
}
status = parse_user_quota_list ( outbuf . data , outbuf . length , mem_ctx ,
pqt_list ) ;
cleanup :
2016-12-13 02:52:11 +03:00
cli - > raw_status = status ;
2016-09-19 22:17:10 +03:00
TALLOC_FREE ( frame ) ;
return status ;
}
2016-09-20 06:46:28 +03:00
/***************************************************************
Wrapper that allows SMB2 to get file system quota .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_get_fs_quota_info ( struct cli_state * cli ,
int quota_fnum ,
SMB_NTQUOTA_STRUCT * pqt )
{
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 cleanup ;
}
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto cleanup ;
}
status = map_fnum_to_smb2_handle ( cli , quota_fnum , & ph ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto cleanup ;
}
status = smb2cli_query_info (
cli - > conn , cli - > timeout , cli - > smb2 . session , cli - > smb2 . tcon ,
2 , /* in_info_type */
SMB_FS_QUOTA_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 cleanup ;
}
status = parse_fs_quota_buffer ( outbuf . data , outbuf . length , pqt ) ;
cleanup :
2016-12-13 02:52:11 +03:00
cli - > raw_status = status ;
2016-09-20 06:46:28 +03:00
TALLOC_FREE ( frame ) ;
return status ;
}
2016-09-21 19:35:39 +03:00
/***************************************************************
Wrapper that allows SMB2 to set user quota .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_set_user_quota ( struct cli_state * cli ,
int quota_fnum ,
SMB_NTQUOTA_LIST * qtl )
{
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 cleanup ;
}
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto cleanup ;
}
status = map_fnum_to_smb2_handle ( cli , quota_fnum , & ph ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto cleanup ;
}
status = build_user_quota_buffer ( qtl , 0 , talloc_tos ( ) , & inbuf , NULL ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto cleanup ;
}
status = smb2cli_set_info ( cli - > conn , cli - > timeout , cli - > smb2 . session ,
cli - > smb2 . tcon , 4 , /* in_info_type */
0 , /* in_file_info_class */
& inbuf , /* in_input_buffer */
0 , /* in_additional_info */
ph - > fid_persistent , ph - > fid_volatile ) ;
cleanup :
2016-12-13 02:52:11 +03:00
cli - > raw_status = status ;
2016-09-21 19:35:39 +03:00
TALLOC_FREE ( frame ) ;
return status ;
}
2016-09-22 01:03:41 +03:00
NTSTATUS cli_smb2_set_fs_quota_info ( struct cli_state * cli ,
int quota_fnum ,
SMB_NTQUOTA_STRUCT * pqt )
{
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 cleanup ;
}
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto cleanup ;
}
status = map_fnum_to_smb2_handle ( cli , quota_fnum , & ph ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto cleanup ;
}
status = build_fs_quota_buffer ( talloc_tos ( ) , pqt , & inbuf , 0 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2016-12-13 09:10:56 +03:00
goto cleanup ;
2016-09-22 01:03:41 +03:00
}
status = smb2cli_set_info (
cli - > conn , cli - > timeout , cli - > smb2 . session , cli - > smb2 . tcon ,
2 , /* in_info_type */
SMB_FS_QUOTA_INFORMATION - 1000 , /* in_file_info_class */
& inbuf , /* in_input_buffer */
0 , /* in_additional_info */
ph - > fid_persistent , ph - > fid_volatile ) ;
cleanup :
2016-12-13 02:52:11 +03:00
cli - > raw_status = status ;
2016-09-22 01:03:41 +03:00
TALLOC_FREE ( frame ) ;
return status ;
}
2013-08-08 02:54:05 +04:00
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 ) ) {
2016-05-02 23:48:14 +03:00
state - > cli - > raw_status = status ;
2013-08-08 02:54:05 +04:00
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 ;
2016-05-02 23:48:14 +03:00
state - > cli - > raw_status = NT_STATUS_OK ;
2013-08-08 02:54:05 +04:00
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 ) ) {
2016-05-02 23:48:14 +03:00
state - > cli - > raw_status = status ;
2013-08-08 02:54:05 +04:00
tevent_req_received ( req ) ;
return status ;
}
if ( pwritten ! = NULL ) {
* pwritten = ( size_t ) state - > written ;
}
2016-05-02 23:48:14 +03:00
state - > cli - > raw_status = NT_STATUS_OK ;
2013-08-08 02:54:05 +04:00
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 ) ) {
2016-05-02 23:48:14 +03:00
state - > cli - > raw_status = status ;
2013-08-08 02:54:05 +04:00
return status ;
}
if ( pwritten ! = NULL ) {
* pwritten = ( size_t ) state - > written ;
}
2016-05-02 23:48:14 +03:00
state - > cli - > raw_status = NT_STATUS_OK ;
2013-08-08 02:54:05 +04:00
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 ) ) {
2016-05-02 23:48:14 +03:00
state - > cli - > raw_status = status ;
2015-05-28 01:13:15 +03:00
tevent_req_received ( req ) ;
return status ;
}
if ( written ! = NULL ) {
* written = state - > written ;
}
2016-05-02 23:48:14 +03:00
state - > cli - > raw_status = NT_STATUS_OK ;
2015-05-28 01:13:15 +03:00
tevent_req_received ( req ) ;
return NT_STATUS_OK ;
}
2016-08-17 01:26:53 +03:00
/***************************************************************
SMB2 enum shadow copy data .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct cli_smb2_shadow_copy_data_fnum_state {
struct cli_state * cli ;
uint16_t fnum ;
struct smb2_hnd * ph ;
DATA_BLOB out_input_buffer ;
DATA_BLOB out_output_buffer ;
} ;
static void cli_smb2_shadow_copy_data_fnum_done ( struct tevent_req * subreq ) ;
static struct tevent_req * cli_smb2_shadow_copy_data_fnum_send (
TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
uint16_t fnum ,
bool get_names )
{
struct tevent_req * req , * subreq ;
2016-10-19 02:33:49 +03:00
struct cli_smb2_shadow_copy_data_fnum_state * state ;
2016-08-17 01:26:53 +03:00
NTSTATUS status ;
req = tevent_req_create ( mem_ctx , & state ,
struct cli_smb2_shadow_copy_data_fnum_state ) ;
if ( req = = NULL ) {
return NULL ;
}
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
}
state - > cli = cli ;
state - > fnum = fnum ;
status = map_fnum_to_smb2_handle ( cli , fnum , & state - > ph ) ;
if ( tevent_req_nterror ( req , status ) ) {
return tevent_req_post ( req , ev ) ;
}
/*
* TODO . Under SMB2 we should send a zero max_output_length
* ioctl to get the required size , then send another ioctl
* to get the data , but the current SMB1 implementation just
* does one roundtrip with a 64 K buffer size . Do the same
* for now . JRA .
*/
subreq = smb2cli_ioctl_send ( state , ev , state - > cli - > conn ,
state - > cli - > timeout ,
state - > cli - > smb2 . session ,
state - > cli - > smb2 . tcon ,
state - > ph - > fid_persistent , /* in_fid_persistent */
state - > ph - > fid_volatile , /* in_fid_volatile */
FSCTL_GET_SHADOW_COPY_DATA ,
0 , /* in_max_input_length */
NULL , /* in_input_buffer */
get_names ?
CLI_BUFFER_SIZE : 16 , /* in_max_output_length */
NULL , /* in_output_buffer */
SMB2_IOCTL_FLAG_IS_FSCTL ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq ,
cli_smb2_shadow_copy_data_fnum_done ,
req ) ;
return req ;
}
static void cli_smb2_shadow_copy_data_fnum_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_smb2_shadow_copy_data_fnum_state * state = tevent_req_data (
req , struct cli_smb2_shadow_copy_data_fnum_state ) ;
NTSTATUS status ;
status = smb2cli_ioctl_recv ( subreq , state ,
& state - > out_input_buffer ,
& state - > out_output_buffer ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
tevent_req_done ( req ) ;
}
static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv ( struct tevent_req * req ,
TALLOC_CTX * mem_ctx ,
bool get_names ,
char * * * pnames ,
int * pnum_names )
{
struct cli_smb2_shadow_copy_data_fnum_state * state = tevent_req_data (
req , struct cli_smb2_shadow_copy_data_fnum_state ) ;
char * * names = NULL ;
uint32_t num_names = 0 ;
uint32_t num_names_returned = 0 ;
uint32_t dlength = 0 ;
uint32_t i ;
uint8_t * endp = NULL ;
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
return status ;
}
if ( state - > out_output_buffer . length < 16 ) {
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
num_names = IVAL ( state - > out_output_buffer . data , 0 ) ;
num_names_returned = IVAL ( state - > out_output_buffer . data , 4 ) ;
dlength = IVAL ( state - > out_output_buffer . data , 8 ) ;
if ( num_names > 0x7FFFFFFF ) {
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
if ( get_names = = false ) {
* pnum_names = ( int ) num_names ;
return NT_STATUS_OK ;
}
if ( num_names ! = num_names_returned ) {
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
if ( dlength + 12 < 12 ) {
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
/*
* NB . The below is an allowable return if there are
* more snapshots than the buffer size we told the
* server we can receive . We currently don ' t support
* this .
*/
if ( dlength + 12 > state - > out_output_buffer . length ) {
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
if ( state - > out_output_buffer . length +
( 2 * sizeof ( SHADOW_COPY_LABEL ) ) <
state - > out_output_buffer . length ) {
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
names = talloc_array ( mem_ctx , char * , num_names_returned ) ;
if ( names = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
endp = state - > out_output_buffer . data +
state - > out_output_buffer . length ;
for ( i = 0 ; i < num_names_returned ; i + + ) {
bool ret ;
uint8_t * src ;
size_t converted_size ;
src = state - > out_output_buffer . data + 12 +
( i * 2 * sizeof ( SHADOW_COPY_LABEL ) ) ;
if ( src + ( 2 * sizeof ( SHADOW_COPY_LABEL ) ) > endp ) {
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
ret = convert_string_talloc (
names , CH_UTF16LE , CH_UNIX ,
src , 2 * sizeof ( SHADOW_COPY_LABEL ) ,
& names [ i ] , & converted_size ) ;
if ( ! ret ) {
TALLOC_FREE ( names ) ;
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
}
* pnum_names = num_names ;
* pnames = names ;
return NT_STATUS_OK ;
}
NTSTATUS cli_smb2_shadow_copy_data ( TALLOC_CTX * mem_ctx ,
struct cli_state * cli ,
uint16_t fnum ,
bool get_names ,
char * * * pnames ,
int * pnum_names )
{
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_shadow_copy_data_fnum_send ( frame ,
ev ,
cli ,
fnum ,
get_names ) ;
if ( req = = NULL ) {
goto fail ;
}
if ( ! tevent_req_poll_ntstatus ( req , ev , & status ) ) {
goto fail ;
}
status = cli_smb2_shadow_copy_data_fnum_recv ( req ,
mem_ctx ,
get_names ,
pnames ,
pnum_names ) ;
fail :
2016-12-13 02:52:11 +03:00
cli - > raw_status = status ;
2016-08-17 01:26:53 +03:00
TALLOC_FREE ( frame ) ;
return status ;
}
2016-12-22 00:55:50 +03:00
/***************************************************************
Wrapper that allows SMB2 to truncate a file .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_ftruncate ( struct cli_state * cli ,
uint16_t fnum ,
uint64_t newsize )
{
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 ;
}
inbuf = data_blob_talloc_zero ( frame , 8 ) ;
if ( inbuf . data = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
SBVAL ( inbuf . data , 0 , newsize ) ;
/* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
level 20 ( SMB_FILE_END_OF_FILE_INFORMATION - 1000 ) . */
status = smb2cli_set_info ( cli - > conn ,
cli - > timeout ,
cli - > smb2 . session ,
cli - > smb2 . tcon ,
1 , /* in_info_type */
/* in_file_info_class */
SMB_FILE_END_OF_FILE_INFORMATION - 1000 ,
& inbuf , /* in_input_buffer */
0 , /* in_additional_info */
ph - > fid_persistent ,
ph - > fid_volatile ) ;
fail :
cli - > raw_status = status ;
TALLOC_FREE ( frame ) ;
return status ;
}
2017-07-25 13:12:02 +03:00
NTSTATUS cli_smb2_notify ( struct cli_state * cli , uint16_t fnum ,
uint32_t buffer_size , uint32_t completion_filter ,
bool recursive , TALLOC_CTX * mem_ctx ,
struct notify_change * * pchanges ,
uint32_t * pnum_changes )
{
NTSTATUS status ;
struct smb2_hnd * ph = NULL ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
uint8_t * base ;
uint32_t len , ofs ;
struct notify_change * changes = NULL ;
size_t num_changes = 0 ;
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 = smb2cli_notify ( cli - > conn , cli - > timeout ,
cli - > smb2 . session , cli - > smb2 . tcon ,
buffer_size ,
ph - > fid_persistent , ph - > fid_volatile ,
completion_filter , recursive ,
frame , & base , & len ) ;
ofs = 0 ;
while ( len - ofs > = 12 ) {
struct notify_change * tmp ;
struct notify_change * c ;
uint32_t next_ofs = IVAL ( base , ofs ) ;
uint32_t file_name_length = IVAL ( base , ofs + 8 ) ;
size_t namelen ;
bool ok ;
tmp = talloc_realloc ( frame , changes , struct notify_change ,
num_changes + 1 ) ;
if ( tmp = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
changes = tmp ;
c = & changes [ num_changes ] ;
num_changes + = 1 ;
if ( smb_buffer_oob ( len , ofs , next_ofs ) | |
smb_buffer_oob ( len , ofs + 12 , file_name_length ) ) {
status = NT_STATUS_INVALID_NETWORK_RESPONSE ;
goto fail ;
}
c - > action = IVAL ( base , ofs + 4 ) ;
ok = convert_string_talloc ( changes , CH_UTF16LE , CH_UNIX ,
base + ofs + 12 , file_name_length ,
& c - > name , & namelen ) ;
if ( ! ok ) {
status = NT_STATUS_INVALID_NETWORK_RESPONSE ;
goto fail ;
}
if ( next_ofs = = 0 ) {
break ;
}
ofs + = next_ofs ;
}
* pchanges = talloc_move ( mem_ctx , & changes ) ;
* pnum_changes = num_changes ;
status = NT_STATUS_OK ;
fail :
cli - > raw_status = status ;
TALLOC_FREE ( frame ) ;
return status ;
}