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"
2017-05-26 17:50:18 +03:00
# include "librpc/gen_ndr/ndr_quota.h"
2020-08-07 21:17:34 +03:00
# include "lib/util/string_wrappers.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 ;
2019-02-20 19:23:46 +03:00
struct smb2_create_blobs in_cblobs ;
struct smb2_create_blobs out_cblobs ;
2014-06-20 12:23:47 +04:00
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
2019-02-15 20:24:31 +03: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 impersonation_level ,
uint32_t desired_access ,
uint32_t file_attributes ,
uint32_t share_access ,
uint32_t create_disposition ,
2019-02-20 19:23:46 +03:00
uint32_t create_options ,
const struct smb2_create_blobs * in_cblobs )
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 ;
2019-02-20 19:23:46 +03:00
NTSTATUS status ;
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 ;
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 ) ;
2019-02-20 19:06:32 +03:00
status = smb2_create_blob_add (
state ,
2019-02-20 19:23:46 +03:00
& state - > in_cblobs ,
2019-02-20 19:06:32 +03:00
SMB2_CREATE_TAG_TWRP ,
twrp_blob ) ;
2016-08-20 03:00:25 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
}
}
2019-02-20 19:23:46 +03:00
if ( in_cblobs ! = NULL ) {
uint32_t i ;
for ( i = 0 ; i < in_cblobs - > num_blobs ; i + + ) {
struct smb2_create_blob * b = & in_cblobs - > blobs [ i ] ;
status = smb2_create_blob_add (
state , & state - > in_cblobs , b - > tag , b - > data ) ;
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 ) ,
2018-12-07 18:32:05 +03:00
impersonation_level ,
2014-06-20 12:23:47 +04:00
desired_access ,
file_attributes ,
share_access ,
create_disposition ,
create_options ,
2019-02-20 19:23:46 +03:00
& state - > in_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 ;
2019-02-20 19:23:46 +03:00
status = smb2cli_create_recv (
subreq ,
& h . fid_persistent ,
& h . fid_volatile , & state - > cr ,
state ,
& state - > out_cblobs ) ;
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 ) ;
}
2019-02-20 19:23:46 +03:00
NTSTATUS cli_smb2_create_fnum_recv (
struct tevent_req * req ,
uint16_t * pfnum ,
struct smb_create_returns * cr ,
TALLOC_CTX * mem_ctx ,
struct smb2_create_blobs * out_cblobs )
2014-06-20 12:23:47 +04:00
{
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 ;
}
2019-02-20 19:23:46 +03:00
if ( out_cblobs ! = NULL ) {
* out_cblobs = ( struct smb2_create_blobs ) {
. num_blobs = state - > out_cblobs . num_blobs ,
. blobs = talloc_move (
mem_ctx , & state - > out_cblobs . blobs ) ,
} ;
}
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 ;
}
2019-02-15 20:24:31 +03:00
NTSTATUS cli_smb2_create_fnum (
struct cli_state * cli ,
const char * fname ,
uint32_t create_flags ,
uint32_t impersonation_level ,
uint32_t desired_access ,
uint32_t file_attributes ,
uint32_t share_access ,
uint32_t create_disposition ,
uint32_t create_options ,
2019-02-20 19:23:46 +03:00
const struct smb2_create_blobs * in_cblobs ,
2019-02-15 20:24:31 +03:00
uint16_t * pfid ,
2019-02-20 19:23:46 +03:00
struct smb_create_returns * cr ,
TALLOC_CTX * mem_ctx ,
struct smb2_create_blobs * out_cblobs )
2014-06-20 12:23:47 +04:00
{
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 ;
}
2019-02-15 20:24:31 +03:00
req = cli_smb2_create_fnum_send (
frame ,
ev ,
cli ,
fname ,
create_flags ,
impersonation_level ,
desired_access ,
file_attributes ,
share_access ,
create_disposition ,
2019-02-20 19:23:46 +03:00
create_options ,
in_cblobs ) ;
2014-06-20 12:23:47 +04:00
if ( req = = NULL ) {
goto fail ;
}
if ( ! tevent_req_poll_ntstatus ( req , ev , & status ) ) {
goto fail ;
}
2019-02-20 19:23:46 +03:00
status = cli_smb2_create_fnum_recv ( req , pfid , cr , mem_ctx , out_cblobs ) ;
2014-06-20 12:23:47 +04:00
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 ;
}
2019-03-17 11:17:11 +03:00
struct cli_smb2_set_info_fnum_state {
uint8_t dummy ;
} ;
static void cli_smb2_set_info_fnum_done ( struct tevent_req * subreq ) ;
struct tevent_req * cli_smb2_set_info_fnum_send (
TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
uint16_t fnum ,
uint8_t in_info_type ,
uint8_t in_info_class ,
const DATA_BLOB * in_input_buffer ,
uint32_t in_additional_info )
{
struct tevent_req * req = NULL , * subreq = NULL ;
struct cli_smb2_set_info_fnum_state * state = NULL ;
struct smb2_hnd * ph = NULL ;
NTSTATUS status ;
req = tevent_req_create (
mem_ctx , & state , struct cli_smb2_set_info_fnum_state ) ;
if ( req = = NULL ) {
return NULL ;
}
status = map_fnum_to_smb2_handle ( cli , fnum , & ph ) ;
if ( tevent_req_nterror ( req , status ) ) {
return tevent_req_post ( req , ev ) ;
}
subreq = smb2cli_set_info_send (
state ,
ev ,
cli - > conn ,
cli - > timeout ,
cli - > smb2 . session ,
cli - > smb2 . tcon ,
in_info_type ,
in_info_class ,
in_input_buffer ,
in_additional_info ,
ph - > fid_persistent ,
ph - > fid_volatile ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , cli_smb2_set_info_fnum_done , req ) ;
return req ;
}
static void cli_smb2_set_info_fnum_done ( struct tevent_req * subreq )
{
NTSTATUS status = smb2cli_set_info_recv ( subreq ) ;
tevent_req_simple_finish_ntstatus ( subreq , status ) ;
}
NTSTATUS cli_smb2_set_info_fnum_recv ( struct tevent_req * req )
{
return tevent_req_simple_recv_ntstatus ( req ) ;
}
NTSTATUS cli_smb2_set_info_fnum (
struct cli_state * cli ,
uint16_t fnum ,
uint8_t in_info_type ,
uint8_t in_info_class ,
const DATA_BLOB * in_input_buffer ,
uint32_t in_additional_info )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct tevent_context * ev = NULL ;
struct tevent_req * req = NULL ;
NTSTATUS status = NT_STATUS_NO_MEMORY ;
bool ok ;
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_set_info_fnum_send (
frame ,
ev ,
cli ,
fnum ,
in_info_type ,
in_info_class ,
in_input_buffer ,
in_additional_info ) ;
if ( req = = NULL ) {
goto fail ;
}
ok = tevent_req_poll_ntstatus ( req , ev , & status ) ;
if ( ! ok ) {
goto fail ;
}
status = cli_smb2_set_info_fnum_recv ( req ) ;
fail :
TALLOC_FREE ( frame ) ;
return status ;
}
2017-06-20 09:35:13 +03:00
struct cli_smb2_delete_on_close_state {
struct cli_state * cli ;
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 ;
req = tevent_req_create ( mem_ctx , & state ,
struct cli_smb2_delete_on_close_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > cli = cli ;
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
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 ;
2019-03-17 11:25:42 +03:00
subreq = cli_smb2_set_info_fnum_send (
state ,
ev ,
cli ,
fnum ,
in_info_type ,
in_file_info_class ,
& state - > inbuf ,
0 ) ;
2017-06-20 09:35:13 +03:00
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 )
{
2019-03-17 11:25:42 +03:00
NTSTATUS status = cli_smb2_set_info_fnum_recv ( subreq ) ;
2017-06-20 09:35:13 +03:00
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 ;
}
2020-05-26 23:21:14 +03:00
struct cli_smb2_mkdir_state {
struct tevent_context * ev ;
struct cli_state * cli ;
} ;
static void cli_smb2_mkdir_opened ( struct tevent_req * subreq ) ;
static void cli_smb2_mkdir_closed ( struct tevent_req * subreq ) ;
struct tevent_req * cli_smb2_mkdir_send (
TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
const char * dname )
{
struct tevent_req * req = NULL , * subreq = NULL ;
struct cli_smb2_mkdir_state * state = NULL ;
req = tevent_req_create (
mem_ctx , & state , struct cli_smb2_mkdir_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
state - > cli = cli ;
/* Ensure this is a directory. */
subreq = cli_smb2_create_fnum_send (
state , /* mem_ctx */
ev , /* ev */
cli , /* cli */
dname , /* fname */
0 , /* create_flags */
SMB2_IMPERSONATION_IMPERSONATION , /* impersonation_level */
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 */
NULL ) ; /* in_cblobs */
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , cli_smb2_mkdir_opened , req ) ;
return req ;
}
static void cli_smb2_mkdir_opened ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_smb2_mkdir_state * state = tevent_req_data (
req , struct cli_smb2_mkdir_state ) ;
NTSTATUS status ;
2020-11-25 13:34:09 +03:00
uint16_t fnum = 0xffff ;
2020-05-26 23:21:14 +03:00
status = cli_smb2_create_fnum_recv ( subreq , & fnum , NULL , NULL , NULL ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
subreq = cli_smb2_close_fnum_send ( state , state - > ev , state - > cli , fnum ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , cli_smb2_mkdir_closed , req ) ;
}
static void cli_smb2_mkdir_closed ( struct tevent_req * subreq )
{
NTSTATUS status = cli_smb2_close_fnum_recv ( subreq ) ;
tevent_req_simple_finish_ntstatus ( subreq , status ) ;
}
NTSTATUS cli_smb2_mkdir_recv ( struct tevent_req * req )
{
return tevent_req_simple_recv_ntstatus ( req ) ;
}
2019-02-28 15:47:22 +03:00
struct cli_smb2_rmdir_state {
struct tevent_context * ev ;
struct cli_state * cli ;
const char * dname ;
2019-03-04 22:40:14 +03:00
const struct smb2_create_blobs * in_cblobs ;
2019-02-28 15:47:22 +03:00
uint16_t fnum ;
NTSTATUS status ;
} ;
2013-08-08 02:54:05 +04:00
2019-02-28 15:47:22 +03:00
static void cli_smb2_rmdir_opened1 ( struct tevent_req * subreq ) ;
static void cli_smb2_rmdir_opened2 ( struct tevent_req * subreq ) ;
static void cli_smb2_rmdir_disp_set ( struct tevent_req * subreq ) ;
static void cli_smb2_rmdir_closed ( struct tevent_req * subreq ) ;
2019-03-04 22:40:14 +03:00
struct tevent_req * cli_smb2_rmdir_send (
TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
const char * dname ,
const struct smb2_create_blobs * in_cblobs )
2013-08-08 02:54:05 +04:00
{
2019-02-28 15:47:22 +03:00
struct tevent_req * req = NULL , * subreq = NULL ;
struct cli_smb2_rmdir_state * state = NULL ;
2013-08-08 02:54:05 +04:00
2019-02-28 15:47:22 +03:00
req = tevent_req_create ( mem_ctx , & state , struct cli_smb2_rmdir_state ) ;
if ( req = = NULL ) {
return NULL ;
2013-08-08 02:54:05 +04:00
}
2019-02-28 15:47:22 +03:00
state - > ev = ev ;
state - > cli = cli ;
state - > dname = dname ;
2019-03-04 22:40:14 +03:00
state - > in_cblobs = in_cblobs ;
2013-08-08 02:54:05 +04:00
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
2019-02-28 15:47:22 +03:00
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
2013-08-08 02:54:05 +04:00
}
2019-02-28 15:47:22 +03:00
subreq = cli_smb2_create_fnum_send (
state ,
state - > ev ,
state - > cli ,
state - > dname ,
0 , /* create_flags */
SMB2_IMPERSONATION_IMPERSONATION ,
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 , /* create_options */
2019-03-04 22:40:14 +03:00
state - > in_cblobs ) ; /* in_cblobs */
2019-02-28 15:47:22 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , cli_smb2_rmdir_opened1 , req ) ;
return req ;
}
static void cli_smb2_rmdir_opened1 ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_smb2_rmdir_state * state = tevent_req_data (
req , struct cli_smb2_rmdir_state ) ;
NTSTATUS status ;
status = cli_smb2_create_fnum_recv (
subreq , & state - > fnum , NULL , NULL , NULL ) ;
TALLOC_FREE ( subreq ) ;
2013-08-08 02:54:05 +04:00
2017-11-29 02:46:40 +03:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_STOPPED_ON_SYMLINK ) ) {
/*
* Naive option to match our SMB1 code . Assume the
* symlink path that tripped us up was the last
* component and try again . Eventually we will have to
* deal with the returned path unprocessed component . JRA .
*/
2019-02-28 15:47:22 +03:00
subreq = cli_smb2_create_fnum_send (
state ,
state - > ev ,
state - > cli ,
state - > dname ,
2017-11-29 02:46:40 +03:00
0 , /* create_flags */
2018-12-07 18:42:06 +03:00
SMB2_IMPERSONATION_IMPERSONATION ,
2017-11-29 02:46:40 +03:00
DELETE_ACCESS , /* desired_access */
FILE_ATTRIBUTE_DIRECTORY , /* file attributes */
2019-02-28 15:47:22 +03:00
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE ,
2017-11-29 02:46:40 +03:00
FILE_OPEN , /* create_disposition */
FILE_DIRECTORY_FILE |
2019-02-28 15:47:22 +03:00
FILE_DELETE_ON_CLOSE |
FILE_OPEN_REPARSE_POINT , /* create_options */
2019-03-04 22:40:14 +03:00
state - > in_cblobs ) ; /* in_cblobs */
2019-02-28 15:47:22 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , cli_smb2_rmdir_opened2 , req ) ;
return ;
2017-11-29 02:46:40 +03:00
}
2019-02-28 15:47:22 +03:00
if ( tevent_req_nterror ( req , status ) ) {
return ;
2013-08-08 02:54:05 +04:00
}
2018-08-09 09:58:41 +03:00
2019-02-28 15:47:22 +03:00
subreq = cli_smb2_delete_on_close_send (
state , state - > ev , state - > cli , state - > fnum , true ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , cli_smb2_rmdir_disp_set , req ) ;
}
static void cli_smb2_rmdir_opened2 ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_smb2_rmdir_state * state = tevent_req_data (
req , struct cli_smb2_rmdir_state ) ;
NTSTATUS status ;
status = cli_smb2_create_fnum_recv (
subreq , & state - > fnum , NULL , NULL , NULL ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
subreq = cli_smb2_delete_on_close_send (
state , state - > ev , state - > cli , state - > fnum , true ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , cli_smb2_rmdir_disp_set , req ) ;
}
static void cli_smb2_rmdir_disp_set ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_smb2_rmdir_state * state = tevent_req_data (
req , struct cli_smb2_rmdir_state ) ;
state - > status = cli_smb2_delete_on_close_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
/*
* Close the fd even if the set_disp failed
*/
subreq = cli_smb2_close_fnum_send (
state , state - > ev , state - > cli , state - > fnum ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , cli_smb2_rmdir_closed , req ) ;
}
static void cli_smb2_rmdir_closed ( struct tevent_req * subreq )
{
2019-02-28 23:18:06 +03:00
NTSTATUS status = cli_smb2_close_fnum_recv ( subreq ) ;
tevent_req_simple_finish_ntstatus ( subreq , status ) ;
2019-02-28 15:47:22 +03:00
}
NTSTATUS cli_smb2_rmdir_recv ( struct tevent_req * req )
{
struct cli_smb2_rmdir_state * state = tevent_req_data (
req , struct cli_smb2_rmdir_state ) ;
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
2018-08-09 09:58:41 +03:00
return status ;
}
2019-02-28 15:47:22 +03:00
return state - > status ;
}
2018-08-09 09:58:41 +03:00
2013-08-08 02:54:05 +04:00
/***************************************************************
Small wrapper that allows SMB2 to unlink a pathname .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2019-03-04 22:38:24 +03:00
struct cli_smb2_unlink_state {
struct tevent_context * ev ;
struct cli_state * cli ;
const char * fname ;
2019-03-04 22:40:14 +03:00
const struct smb2_create_blobs * in_cblobs ;
2019-03-04 22:38:24 +03:00
} ;
static void cli_smb2_unlink_opened1 ( struct tevent_req * subreq ) ;
static void cli_smb2_unlink_opened2 ( struct tevent_req * subreq ) ;
static void cli_smb2_unlink_closed ( struct tevent_req * subreq ) ;
struct tevent_req * cli_smb2_unlink_send (
TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
2019-03-04 22:40:14 +03:00
const char * fname ,
const struct smb2_create_blobs * in_cblobs )
2013-08-08 02:54:05 +04:00
{
2019-03-04 22:38:24 +03:00
struct tevent_req * req = NULL , * subreq = NULL ;
struct cli_smb2_unlink_state * state = NULL ;
2013-08-08 02:54:05 +04:00
2019-03-04 22:38:24 +03:00
req = tevent_req_create ( mem_ctx , & state , struct cli_smb2_unlink_state ) ;
if ( req = = NULL ) {
return NULL ;
2013-08-08 02:54:05 +04:00
}
2019-03-04 22:38:24 +03:00
state - > ev = ev ;
state - > cli = cli ;
state - > fname = fname ;
2019-03-04 22:40:14 +03:00
state - > in_cblobs = in_cblobs ;
2013-08-08 02:54:05 +04:00
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
2019-03-04 22:38:24 +03:00
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
2013-08-08 02:54:05 +04:00
}
2019-03-04 22:38:24 +03:00
subreq = cli_smb2_create_fnum_send (
state , /* mem_ctx */
state - > ev , /* tevent_context */
state - > cli , /* cli_struct */
state - > fname , /* filename */
0 , /* create_flags */
SMB2_IMPERSONATION_IMPERSONATION ,
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 */
2019-03-04 22:40:14 +03:00
state - > in_cblobs ) ; /* in_cblobs */
2019-03-04 22:38:24 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , cli_smb2_unlink_opened1 , req ) ;
return req ;
}
static void cli_smb2_unlink_opened1 ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_smb2_unlink_state * state = tevent_req_data (
req , struct cli_smb2_unlink_state ) ;
2020-11-25 13:34:09 +03:00
uint16_t fnum = 0xffff ;
2019-03-04 22:38:24 +03:00
NTSTATUS status ;
status = cli_smb2_create_fnum_recv ( subreq , & fnum , NULL , NULL , NULL ) ;
TALLOC_FREE ( subreq ) ;
2013-08-08 02:54:05 +04:00
2017-11-29 02:46:40 +03:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_STOPPED_ON_SYMLINK ) ) {
/*
* Naive option to match our SMB1 code . Assume the
* symlink path that tripped us up was the last
* component and try again . Eventually we will have to
* deal with the returned path unprocessed component . JRA .
*/
2019-03-04 22:38:24 +03:00
subreq = cli_smb2_create_fnum_send (
state , /* mem_ctx */
state - > ev , /* tevent_context */
state - > cli , /* cli_struct */
state - > fname , /* filename */
2017-11-29 02:46:40 +03:00
0 , /* create_flags */
2018-12-07 18:42:06 +03:00
SMB2_IMPERSONATION_IMPERSONATION ,
2017-11-29 02:46:40 +03:00
DELETE_ACCESS , /* desired_access */
FILE_ATTRIBUTE_NORMAL , /* file attributes */
2019-03-04 22:38:24 +03:00
FILE_SHARE_READ |
FILE_SHARE_WRITE |
FILE_SHARE_DELETE , /* share_access */
2017-11-29 02:46:40 +03:00
FILE_OPEN , /* create_disposition */
FILE_DELETE_ON_CLOSE |
2019-03-04 22:38:24 +03:00
FILE_OPEN_REPARSE_POINT , /* create_options */
2019-03-04 22:40:14 +03:00
state - > in_cblobs ) ; /* in_cblobs */
2019-03-04 22:38:24 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , cli_smb2_unlink_opened2 , req ) ;
return ;
2017-11-29 02:46:40 +03:00
}
2019-03-04 22:38:24 +03:00
if ( tevent_req_nterror ( req , status ) ) {
return ;
2013-08-08 02:54:05 +04:00
}
2019-03-04 22:38:24 +03:00
subreq = cli_smb2_close_fnum_send ( state , state - > ev , state - > cli , fnum ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , cli_smb2_unlink_closed , req ) ;
}
static void cli_smb2_unlink_opened2 ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_smb2_unlink_state * state = tevent_req_data (
req , struct cli_smb2_unlink_state ) ;
2020-11-25 13:34:09 +03:00
uint16_t fnum = 0xffff ;
2019-03-04 22:38:24 +03:00
NTSTATUS status ;
status = cli_smb2_create_fnum_recv ( subreq , & fnum , NULL , NULL , NULL ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
subreq = cli_smb2_close_fnum_send ( state , state - > ev , state - > cli , fnum ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , cli_smb2_unlink_closed , req ) ;
}
static void cli_smb2_unlink_closed ( struct tevent_req * subreq )
{
NTSTATUS status = cli_smb2_close_fnum_recv ( subreq ) ;
tevent_req_simple_finish_ntstatus ( subreq , status ) ;
}
NTSTATUS cli_smb2_unlink_recv ( struct tevent_req * req )
{
return tevent_req_simple_recv_ntstatus ( req ) ;
}
2013-08-08 02:54:05 +04:00
/***************************************************************
Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-05-16 18:33:38 +03:00
static NTSTATUS parse_finfo_id_both_directory_info ( const uint8_t * dir_data ,
2013-08-08 02:54:05 +04:00
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 ;
}
2018-04-06 23:35:05 +03:00
finfo - > btime_ts = interpret_long_date ( ( const char * ) dir_data + 8 ) ;
2013-08-08 02:54:05 +04:00
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 ) ;
2019-01-18 03:59:08 +03:00
finfo - > allocated_size = IVAL2_TO_SMB_BIG_UINT ( dir_data + 48 , 0 ) ;
2020-06-03 20:48:10 +03:00
finfo - > attr = IVAL ( dir_data + 56 , 0 ) ;
2019-01-18 03:13:23 +03:00
finfo - > ino = IVAL2_TO_SMB_BIG_UINT ( dir_data + 96 , 0 ) ;
2013-08-08 02:54:05 +04:00
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 ;
}
2020-05-11 22:23:49 +03:00
if ( finfo - > name = = NULL ) {
/* Bad conversion. */
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
2013-08-08 02:54:05 +04:00
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 ;
}
2020-11-14 20:31:22 +03:00
struct cli_smb2_list_dir_data {
uint8_t * data ;
uint32_t length ;
} ;
struct cli_smb2_list_state {
struct tevent_context * ev ;
struct cli_state * cli ;
const char * mask ;
uint16_t fnum ;
2013-08-08 02:54:05 +04:00
NTSTATUS status ;
2020-11-14 20:31:22 +03:00
struct cli_smb2_list_dir_data * response ;
uint32_t offset ;
} ;
static void cli_smb2_list_opened ( struct tevent_req * subreq ) ;
static void cli_smb2_list_done ( struct tevent_req * subreq ) ;
static void cli_smb2_list_closed ( struct tevent_req * subreq ) ;
struct tevent_req * cli_smb2_list_send (
TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
const char * pathname )
{
struct tevent_req * req = NULL , * subreq = NULL ;
struct cli_smb2_list_state * state = NULL ;
char * parent = NULL ;
2019-01-07 05:28:12 +03:00
bool ok ;
2013-08-08 02:54:05 +04:00
2020-11-14 20:31:22 +03:00
req = tevent_req_create ( mem_ctx , & state , struct cli_smb2_list_state ) ;
if ( req = = NULL ) {
return NULL ;
2013-08-08 02:54:05 +04:00
}
2020-11-14 20:31:22 +03:00
state - > ev = ev ;
state - > cli = cli ;
state - > status = NT_STATUS_OK ;
2013-08-08 02:54:05 +04:00
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
2020-11-14 20:31:22 +03:00
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
}
ok = windows_parent_dirname ( state , pathname , & parent , & state - > mask ) ;
if ( ! ok ) {
tevent_req_oom ( req ) ;
return tevent_req_post ( req , ev ) ;
2013-08-08 02:54:05 +04:00
}
2020-11-14 20:31:22 +03:00
subreq = cli_smb2_create_fnum_send (
state , /* mem_ctx */
ev , /* ev */
cli , /* cli */
parent , /* fname */
0 , /* create_flags */
SMB2_IMPERSONATION_IMPERSONATION , /* impersonation_level */
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 */
NULL ) ; /* in_cblobs */
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , cli_smb2_list_opened , req ) ;
return req ;
}
static void cli_smb2_list_opened ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_smb2_list_state * state = tevent_req_data (
req , struct cli_smb2_list_state ) ;
NTSTATUS status ;
status = cli_smb2_create_fnum_recv (
subreq , & state - > fnum , NULL , NULL , NULL ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
/*
* Make our caller get back to us via cli_smb2_list_recv ( ) ,
* triggering the smb2_query_directory_send ( )
*/
tevent_req_defer_callback ( req , state - > ev ) ;
tevent_req_notify_callback ( req ) ;
}
static void cli_smb2_list_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_smb2_list_state * state = tevent_req_data (
req , struct cli_smb2_list_state ) ;
struct cli_smb2_list_dir_data * response = NULL ;
response = talloc ( state , struct cli_smb2_list_dir_data ) ;
if ( tevent_req_nomem ( response , req ) ) {
return ;
}
state - > status = smb2cli_query_directory_recv (
subreq , response , & response - > data , & response - > length ) ;
TALLOC_FREE ( subreq ) ;
if ( NT_STATUS_IS_OK ( state - > status ) ) {
state - > response = response ;
state - > offset = 0 ;
tevent_req_defer_callback ( req , state - > ev ) ;
tevent_req_notify_callback ( req ) ;
return ;
}
TALLOC_FREE ( response ) ;
subreq = cli_smb2_close_fnum_send (
state , state - > ev , state - > cli , state - > fnum ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , cli_smb2_list_closed , req ) ;
}
static void cli_smb2_list_closed ( struct tevent_req * subreq )
{
NTSTATUS status = cli_smb2_close_fnum_recv ( subreq ) ;
tevent_req_simple_finish_ntstatus ( subreq , status ) ;
}
/*
* Return the next finfo directory .
*
* This parses the blob returned from QUERY_DIRECTORY step by step . If
* the blob ends , this triggers a fresh QUERY_DIRECTORY and returns
* NT_STATUS_RETRY , which will then trigger the caller again when the
* QUERY_DIRECTORY has returned with another buffer . This way we
* guarantee that no asynchronous request is open after this call
* returns an entry , so that other synchronous requests can be issued
* on the same connection while the directoy listing proceeds .
*/
NTSTATUS cli_smb2_list_recv (
struct tevent_req * req ,
TALLOC_CTX * mem_ctx ,
struct file_info * * pfinfo )
{
struct cli_smb2_list_state * state = tevent_req_data (
req , struct cli_smb2_list_state ) ;
struct cli_smb2_list_dir_data * response = NULL ;
struct file_info * finfo = NULL ;
NTSTATUS status ;
uint32_t next_offset = 0 ;
bool in_progress ;
in_progress = tevent_req_is_in_progress ( req ) ;
if ( ! in_progress ) {
if ( ! tevent_req_is_nterror ( req , & status ) ) {
status = NT_STATUS_NO_MORE_FILES ;
}
2013-08-08 02:54:05 +04:00
goto fail ;
2020-11-14 20:31:22 +03:00
}
2013-08-08 02:54:05 +04:00
2020-11-14 20:31:22 +03:00
response = state - > response ;
if ( response = = NULL ) {
struct tevent_req * subreq = NULL ;
struct cli_state * cli = state - > cli ;
struct smb2_hnd * ph = NULL ;
uint32_t max_trans , max_avail_len ;
bool ok ;
2014-10-22 01:41:32 +04:00
2020-11-14 20:31:22 +03:00
if ( ! NT_STATUS_IS_OK ( state - > status ) ) {
status = state - > status ;
goto fail ;
}
status = map_fnum_to_smb2_handle ( cli , state - > fnum , & ph ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
2013-08-08 02:54:05 +04:00
2020-11-14 20:31:22 +03:00
max_trans = smb2cli_conn_max_trans_size ( cli - > conn ) ;
ok = smb2cli_conn_req_possible ( cli - > conn , & max_avail_len ) ;
if ( ok ) {
max_trans = MIN ( max_trans , max_avail_len ) ;
}
subreq = smb2cli_query_directory_send (
state , /* mem_ctx */
state - > ev , /* ev */
cli - > conn , /* conn */
cli - > timeout , /* timeout_msec */
cli - > smb2 . session , /* session */
cli - > smb2 . tcon , /* tcon */
SMB2_FIND_ID_BOTH_DIRECTORY_INFO , /* level */
0 , /* flags */
0 , /* file_index */
ph - > fid_persistent , /* fid_persistent */
ph - > fid_volatile , /* fid_volatile */
state - > mask , /* mask */
max_trans ) ; /* outbuf_len */
if ( subreq = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
tevent_req_set_callback ( subreq , cli_smb2_list_done , req ) ;
return NT_STATUS_RETRY ;
}
SMB_ASSERT ( response - > length > state - > offset ) ;
finfo = talloc_zero ( mem_ctx , struct file_info ) ;
if ( finfo = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
status = parse_finfo_id_both_directory_info (
response - > data + state - > offset ,
response - > length - state - > offset ,
finfo ,
& next_offset ) ;
2013-08-08 02:54:05 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
2020-11-14 20:31:22 +03:00
status = is_bad_finfo_name ( state - > cli , finfo ) ;
2013-08-08 02:54:05 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
2019-01-07 05:28:12 +03:00
/*
2020-11-14 20:31:22 +03:00
* parse_finfo_id_both_directory_info ( ) checks for overflow ,
* no need to check again here .
2019-01-07 05:28:12 +03:00
*/
2020-11-14 20:31:22 +03:00
state - > offset + = next_offset ;
2013-08-08 02:54:05 +04:00
2020-11-14 20:31:22 +03:00
if ( next_offset = = 0 ) {
TALLOC_FREE ( state - > response ) ;
}
2013-08-08 02:54:05 +04:00
2020-11-14 20:31:22 +03:00
tevent_req_defer_callback ( req , state - > ev ) ;
tevent_req_notify_callback ( req ) ;
2013-08-08 02:54:05 +04:00
2020-11-14 20:31:22 +03:00
* pfinfo = finfo ;
return NT_STATUS_OK ;
2013-08-08 02:54:05 +04:00
2020-11-14 20:31:22 +03:00
fail :
TALLOC_FREE ( finfo ) ;
tevent_req_received ( req ) ;
return status ;
}
2013-08-08 02:54:05 +04:00
/***************************************************************
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 ] = = ' \\ ' ) {
2020-04-21 09:05:57 +03:00
char * modname = talloc_strndup ( talloc_tos ( ) , name , namelen - 1 ) ;
2020-04-21 09:02:35 +03:00
if ( modname = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2013-08-08 02:54:05 +04:00
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 */
2018-12-07 18:42:06 +03:00
SMB2_IMPERSONATION_IMPERSONATION ,
2013-08-08 02:54:05 +04:00
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 */
2019-02-20 19:23:46 +03:00
NULL ,
2013-08-08 02:54:05 +04:00
& fnum ,
2019-02-20 19:23:46 +03:00
& cr ,
NULL ,
NULL ) ;
2013-08-08 02:54:05 +04:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NOT_A_DIRECTORY ) ) {
/* Maybe a file ? */
status = cli_smb2_create_fnum ( cli ,
name ,
0 , /* create_flags */
2018-12-07 18:42:06 +03:00
SMB2_IMPERSONATION_IMPERSONATION ,
2013-08-08 02:54:05 +04:00
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 */
2019-02-20 19:23:46 +03:00
NULL ,
2013-08-08 02:54:05 +04:00
& fnum ,
2019-02-20 19:23:46 +03:00
& cr ,
NULL ,
NULL ) ;
2013-08-08 02:54:05 +04:00
}
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
}
2019-03-10 20:49:55 +03:00
struct cli_smb2_query_info_fnum_state {
DATA_BLOB outbuf ;
} ;
static void cli_smb2_query_info_fnum_done ( struct tevent_req * subreq ) ;
struct tevent_req * cli_smb2_query_info_fnum_send (
TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
uint16_t fnum ,
uint8_t in_info_type ,
uint8_t in_info_class ,
uint32_t in_max_output_length ,
const DATA_BLOB * in_input_buffer ,
uint32_t in_additional_info ,
uint32_t in_flags )
{
struct tevent_req * req = NULL , * subreq = NULL ;
struct cli_smb2_query_info_fnum_state * state = NULL ;
struct smb2_hnd * ph = NULL ;
NTSTATUS status ;
req = tevent_req_create (
mem_ctx , & state , struct cli_smb2_query_info_fnum_state ) ;
if ( req = = NULL ) {
return req ;
}
status = map_fnum_to_smb2_handle ( cli , fnum , & ph ) ;
if ( tevent_req_nterror ( req , status ) ) {
return tevent_req_post ( req , ev ) ;
}
subreq = smb2cli_query_info_send (
state ,
ev ,
cli - > conn ,
cli - > timeout ,
cli - > smb2 . session ,
cli - > smb2 . tcon ,
in_info_type ,
in_info_class ,
in_max_output_length ,
in_input_buffer ,
in_additional_info ,
in_flags ,
ph - > fid_persistent ,
ph - > fid_volatile ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , cli_smb2_query_info_fnum_done , req ) ;
return req ;
}
static void cli_smb2_query_info_fnum_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_smb2_query_info_fnum_state * state = tevent_req_data (
req , struct cli_smb2_query_info_fnum_state ) ;
DATA_BLOB outbuf ;
NTSTATUS status ;
status = smb2cli_query_info_recv ( subreq , state , & outbuf ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
/*
* We have to dup the memory here because outbuf . data is not
* returned as a talloc object by smb2cli_query_info_recv .
* It ' s a pointer into the received buffer .
*/
state - > outbuf = data_blob_dup_talloc ( state , outbuf ) ;
if ( ( outbuf . length ! = 0 ) & &
tevent_req_nomem ( state - > outbuf . data , req ) ) {
return ;
}
tevent_req_done ( req ) ;
}
NTSTATUS cli_smb2_query_info_fnum_recv (
struct tevent_req * req , TALLOC_CTX * mem_ctx , DATA_BLOB * outbuf )
{
struct cli_smb2_query_info_fnum_state * state = tevent_req_data (
req , struct cli_smb2_query_info_fnum_state ) ;
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
return status ;
}
* outbuf = ( DATA_BLOB ) {
. data = talloc_move ( mem_ctx , & state - > outbuf . data ) ,
. length = state - > outbuf . length ,
} ;
return NT_STATUS_OK ;
}
NTSTATUS cli_smb2_query_info_fnum (
struct cli_state * cli ,
uint16_t fnum ,
uint8_t in_info_type ,
uint8_t in_info_class ,
uint32_t in_max_output_length ,
const DATA_BLOB * in_input_buffer ,
uint32_t in_additional_info ,
uint32_t in_flags ,
TALLOC_CTX * mem_ctx ,
DATA_BLOB * outbuf )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct tevent_context * ev = NULL ;
struct tevent_req * req = NULL ;
NTSTATUS status = NT_STATUS_NO_MEMORY ;
bool ok ;
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_query_info_fnum_send (
frame ,
ev ,
cli ,
fnum ,
in_info_type ,
in_info_class ,
in_max_output_length ,
in_input_buffer ,
in_additional_info ,
in_flags ) ;
if ( req = = NULL ) {
goto fail ;
}
ok = tevent_req_poll_ntstatus ( req , ev , & status ) ;
if ( ! ok ) {
goto fail ;
}
status = cli_smb2_query_info_fnum_recv ( req , mem_ctx , outbuf ) ;
fail :
TALLOC_FREE ( frame ) ;
return status ;
}
2013-08-08 02:54:05 +04:00
/***************************************************************
Helper function for pathname operations .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-11-13 14:59:55 +03:00
struct get_fnum_from_path_state {
struct tevent_context * ev ;
struct cli_state * cli ;
const char * name ;
uint32_t desired_access ;
uint16_t fnum ;
} ;
static void get_fnum_from_path_opened_file ( struct tevent_req * subreq ) ;
static void get_fnum_from_path_opened_reparse ( struct tevent_req * subreq ) ;
static void get_fnum_from_path_opened_dir ( struct tevent_req * subreq ) ;
static struct tevent_req * get_fnum_from_path_send (
TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
const char * name ,
uint32_t desired_access )
2013-08-08 02:54:05 +04:00
{
2020-11-13 14:59:55 +03:00
struct tevent_req * req = NULL , * subreq = NULL ;
struct get_fnum_from_path_state * state = NULL ;
2013-08-08 02:54:05 +04:00
size_t namelen = strlen ( name ) ;
2020-11-13 14:59:55 +03:00
req = tevent_req_create (
mem_ctx , & state , struct get_fnum_from_path_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
state - > cli = cli ;
state - > name = name ;
state - > desired_access = desired_access ;
/*
* SMB2 is pickier about pathnames . Ensure it doesn ' t end in a
* ' \ '
*/
2013-08-08 02:54:05 +04:00
if ( namelen > 0 & & name [ namelen - 1 ] = = ' \\ ' ) {
2020-11-13 14:59:55 +03:00
state - > name = talloc_strndup ( state , name , namelen - 1 ) ;
if ( tevent_req_nomem ( state - > name , req ) ) {
return tevent_req_post ( req , ev ) ;
2013-08-08 02:54:05 +04:00
}
}
2020-11-13 14:59:55 +03:00
subreq = cli_smb2_create_fnum_send (
state , /* mem_ctx, */
ev , /* ev */
cli , /* cli */
state - > name , /* fname */
0 , /* create_flags */
SMB2_IMPERSONATION_IMPERSONATION , /* impersonation_level */
desired_access , /* desired_access */
0 , /* file_attributes */
FILE_SHARE_READ |
FILE_SHARE_WRITE |
FILE_SHARE_DELETE , /* share_access */
FILE_OPEN , /* create_disposition */
0 , /* create_options */
NULL ) ; /* in_cblobs */
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , get_fnum_from_path_opened_file , req ) ;
return req ;
}
static void get_fnum_from_path_opened_file ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct get_fnum_from_path_state * state = tevent_req_data (
req , struct get_fnum_from_path_state ) ;
NTSTATUS status ;
status = cli_smb2_create_fnum_recv (
subreq , & state - > fnum , NULL , NULL , NULL ) ;
TALLOC_FREE ( subreq ) ;
2017-11-29 02:46:40 +03:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_STOPPED_ON_SYMLINK ) ) {
/*
* Naive option to match our SMB1 code . Assume the
* symlink path that tripped us up was the last
* component and try again . Eventually we will have to
* deal with the returned path unprocessed component . JRA .
*/
2020-11-13 14:59:55 +03:00
subreq = cli_smb2_create_fnum_send (
state , /* mem_ctx, */
state - > ev , /* ev */
state - > cli , /* cli */
state - > name , /* fname */
0 , /* create_flags */
SMB2_IMPERSONATION_IMPERSONATION , /* impersonation */
state - > desired_access , /* desired_access */
0 , /* file_attributes */
FILE_SHARE_READ |
FILE_SHARE_WRITE |
FILE_SHARE_DELETE , /* share_access */
FILE_OPEN , /* create_disposition */
FILE_OPEN_REPARSE_POINT , /* create_options */
NULL ) ; /* in_cblobs */
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback (
subreq , get_fnum_from_path_opened_reparse , req ) ;
return ;
2017-11-29 02:46:40 +03:00
}
2013-08-08 02:54:05 +04:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_FILE_IS_A_DIRECTORY ) ) {
2020-11-13 14:59:55 +03:00
subreq = cli_smb2_create_fnum_send (
state , /* mem_ctx, */
state - > ev , /* ev */
state - > cli , /* cli */
state - > name , /* fname */
0 , /* create_flags */
SMB2_IMPERSONATION_IMPERSONATION , /* impersonation */
state - > desired_access , /* desired_access */
0 , /* file_attributes */
FILE_SHARE_READ |
FILE_SHARE_WRITE |
FILE_SHARE_DELETE , /* share_access */
FILE_OPEN , /* create_disposition */
FILE_DIRECTORY_FILE , /* create_options */
NULL ) ; /* in_cblobs */
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback (
subreq , get_fnum_from_path_opened_dir , req ) ;
return ;
2013-08-08 02:54:05 +04:00
}
2020-11-13 14:59:55 +03:00
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
tevent_req_done ( req ) ;
}
static void get_fnum_from_path_opened_reparse ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct get_fnum_from_path_state * state = tevent_req_data (
req , struct get_fnum_from_path_state ) ;
NTSTATUS status = cli_smb2_create_fnum_recv (
subreq , & state - > fnum , NULL , NULL , NULL ) ;
tevent_req_simple_finish_ntstatus ( subreq , status ) ;
}
2013-08-08 02:54:05 +04:00
2020-11-13 14:59:55 +03:00
static void get_fnum_from_path_opened_dir ( struct tevent_req * subreq )
{
/* Abstraction violation, but these two are just the same... */
get_fnum_from_path_opened_reparse ( subreq ) ;
}
static NTSTATUS get_fnum_from_path_recv (
struct tevent_req * req , uint16_t * pfnum )
{
struct get_fnum_from_path_state * state = tevent_req_data (
req , struct get_fnum_from_path_state ) ;
NTSTATUS status = NT_STATUS_OK ;
if ( ! tevent_req_is_nterror ( req , & status ) ) {
* pfnum = state - > fnum ;
}
tevent_req_received ( req ) ;
return status ;
}
static NTSTATUS get_fnum_from_path ( struct cli_state * cli ,
const char * name ,
uint32_t desired_access ,
uint16_t * pfnum )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct tevent_context * ev = NULL ;
struct tevent_req * req = NULL ;
NTSTATUS status = NT_STATUS_NO_MEMORY ;
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
ev = samba_tevent_context_init ( frame ) ;
if ( ev = = NULL ) {
goto fail ;
}
req = get_fnum_from_path_send ( frame , ev , cli , name , desired_access ) ;
if ( req = = NULL ) {
goto fail ;
}
if ( ! tevent_req_poll_ntstatus ( req , ev , & status ) ) {
goto fail ;
}
status = get_fnum_from_path_recv ( req , pfnum ) ;
fail :
2013-08-08 02:54:05 +04:00
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
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 ;
}
2019-03-10 21:08:20 +03:00
status = cli_smb2_query_info_fnum (
cli ,
fnum ,
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 */
frame ,
& outbuf ) ;
2013-08-08 02:54:05 +04:00
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 get pathname attributes .
Synchronous only .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_smb2_getatr ( struct cli_state * cli ,
const char * name ,
2020-06-03 22:13:33 +03:00
uint32_t * pattr ,
2013-08-08 02:54:05 +04:00
off_t * size ,
time_t * write_time )
{
NTSTATUS status ;
2013-08-20 00:36:02 +04:00
uint16_t fnum = 0xffff ;
2020-06-04 16:22:04 +03:00
struct timespec write_time_ts ;
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 ;
}
2020-06-04 16:22:04 +03:00
status = cli_qfileinfo_basic (
cli ,
fnum ,
pattr ,
size ,
NULL , /* create_time */
NULL , /* access_time */
& write_time_ts ,
NULL , /* change_time */
NULL ) ; /* ino */
2013-08-08 02:54:05 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
2020-06-04 16:22:04 +03:00
if ( write_time ! = NULL ) {
* write_time = write_time_ts . tv_sec ;
}
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 ( frame ) ;
return status ;
}
/***************************************************************
Wrapper that allows SMB2 to query a pathname info ( basic level ) .
2020-06-04 16:26:31 +03:00
Implement on top of cli_qfileinfo_basic ( ) .
2013-08-08 02:54:05 +04:00
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 ,
2020-06-03 22:17:30 +03:00
uint32_t * pattr ,
2013-08-08 02:54:05 +04:00
SMB_INO_T * ino )
{
NTSTATUS status ;
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 ;
}
2020-06-04 16:26:31 +03:00
status = cli_qfileinfo_basic (
cli ,
fnum ,
pattr ,
size ,
create_time ,
access_time ,
write_time ,
change_time ,
ino ) ;
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 ( 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 ;
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 ;
}
/* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
level 22 ( SMB2_FILE_STREAM_INFORMATION ) . */
2019-03-10 21:08:20 +03:00
status = cli_smb2_query_info_fnum (
cli ,
fnum ,
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 */
frame ,
& outbuf ) ;
2013-08-08 02:54:05 +04:00
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 ;
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 ;
}
2019-03-17 16:00:09 +03:00
status = cli_smb2_set_info_fnum (
cli ,
fnum ,
in_info_type ,
in_file_info_class ,
p_in_data , /* in_input_buffer */
0 ) ; /* in_additional_info */
2017-07-21 22:41:11 +03:00
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 ,
2020-06-03 23:50:57 +03:00
uint32_t attr ,
2013-08-08 02:54:05 +04:00
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 ;
}
2020-06-03 23:50:57 +03:00
SIVAL ( 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 )
{
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 ;
}
/* 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 ) ;
}
2019-03-17 16:00:09 +03:00
cli - > raw_status = cli_smb2_set_info_fnum (
cli ,
fnum ,
1 , /* in_info_type */
SMB_FILE_BASIC_INFORMATION - 1000 , /* in_file_info_class */
& inbuf , /* in_input_buffer */
0 ) ; /* in_additional_info */
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 ;
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 */
2018-12-07 18:42:06 +03:00
SMB2_IMPERSONATION_IMPERSONATION ,
2013-08-08 02:54:05 +04:00
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 */
2019-02-20 19:23:46 +03:00
NULL ,
2013-08-08 02:54:05 +04:00
& fnum ,
2019-02-20 19:23:46 +03:00
NULL ,
NULL ,
2013-08-08 02:54:05 +04:00
NULL ) ;
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 ) . */
2019-03-10 21:08:20 +03:00
status = cli_smb2_query_info_fnum (
cli ,
fnum ,
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 */
frame ,
& outbuf ) ;
2013-08-08 02:54:05 +04:00
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 ;
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 */
2018-12-07 18:42:06 +03:00
SMB2_IMPERSONATION_IMPERSONATION ,
2017-11-15 00:52:03 +03:00
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 */
2019-02-20 19:23:46 +03:00
NULL ,
2017-11-15 00:52:03 +03:00
& fnum ,
2019-02-20 19:23:46 +03:00
NULL ,
NULL ,
2017-11-15 00:52:03 +03:00
NULL ) ;
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 ) . */
2019-03-10 21:08:20 +03:00
status = cli_smb2_query_info_fnum (
cli ,
fnum ,
2019-03-29 13:08:12 +03:00
SMB2_0_INFO_FILESYSTEM , /* in_info_type */
2019-03-10 21:08:20 +03:00
SMB_FS_FULL_SIZE_INFORMATION - 1000 , /* in_file_info_class */
0xFFFF , /* in_max_output_length */
NULL , /* in_input_buffer */
0 , /* in_additional_info */
0 , /* in_flags */
frame ,
& outbuf ) ;
2017-11-15 00:52:03 +03:00
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 ;
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 */
2018-12-07 18:42:06 +03:00
SMB2_IMPERSONATION_IMPERSONATION ,
2016-09-20 14:32:06 +03:00
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 */
2019-02-20 19:23:46 +03:00
NULL ,
2016-09-20 14:32:06 +03:00
& fnum ,
2019-02-20 19:23:46 +03:00
NULL ,
NULL ,
2016-09-20 14:32:06 +03:00
NULL ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
2019-03-10 21:08:20 +03:00
status = cli_smb2_query_info_fnum (
cli ,
fnum ,
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 */
frame ,
& outbuf ) ;
2016-09-20 14:32:06 +03:00
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 ;
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 */
2018-12-07 18:42:06 +03:00
SMB2_IMPERSONATION_IMPERSONATION ,
2017-11-15 02:42:14 +03:00
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 */
2019-02-20 19:23:46 +03:00
NULL ,
2017-11-15 02:42:14 +03:00
& fnum ,
2019-02-20 19:23:46 +03:00
NULL ,
NULL ,
2017-11-15 02:42:14 +03:00
NULL ) ;
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 ) . */
2019-03-10 21:08:20 +03:00
status = cli_smb2_query_info_fnum (
cli ,
fnum ,
2019-03-29 13:08:12 +03:00
SMB2_0_INFO_FILESYSTEM , /* in_info_type */
2019-03-10 21:08:20 +03:00
/* 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 */
frame ,
& outbuf ) ;
2017-11-15 02:42:14 +03:00
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 ;
}
2020-05-17 13:57:32 +03:00
pull_string_talloc ( mem_ctx ,
( const char * ) outbuf . data ,
0 ,
& volume_name ,
outbuf . data + 18 ,
nlen ,
STR_UNICODE ) ;
2017-11-15 02:42:14 +03:00
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 ;
2016-12-13 02:52:11 +03:00
2013-08-08 02:54:05 +04:00
TALLOC_FREE ( frame ) ;
return status ;
}
2019-03-01 11:48:25 +03:00
struct cli_smb2_mxac_state {
struct tevent_context * ev ;
struct cli_state * cli ;
const char * fname ;
struct smb2_create_blobs in_cblobs ;
uint16_t fnum ;
NTSTATUS status ;
uint32_t mxac ;
} ;
static void cli_smb2_mxac_opened ( struct tevent_req * subreq ) ;
static void cli_smb2_mxac_closed ( struct tevent_req * subreq ) ;
struct tevent_req * cli_smb2_query_mxac_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
const char * fname )
{
struct tevent_req * req = NULL , * subreq = NULL ;
struct cli_smb2_mxac_state * state = NULL ;
NTSTATUS status ;
req = tevent_req_create ( mem_ctx , & state , struct cli_smb2_mxac_state ) ;
if ( req = = NULL ) {
return NULL ;
}
* state = ( struct cli_smb2_mxac_state ) {
2019-04-23 12:03:27 +03:00
. ev = ev ,
. cli = cli ,
. fname = fname ,
2019-03-01 11:48:25 +03:00
} ;
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
}
status = smb2_create_blob_add ( state ,
& state - > in_cblobs ,
SMB2_CREATE_TAG_MXAC ,
data_blob ( NULL , 0 ) ) ;
if ( tevent_req_nterror ( req , status ) ) {
return tevent_req_post ( req , ev ) ;
}
subreq = cli_smb2_create_fnum_send (
state ,
state - > ev ,
state - > cli ,
state - > fname ,
0 , /* create_flags */
SMB2_IMPERSONATION_IMPERSONATION ,
FILE_READ_ATTRIBUTES ,
0 , /* file attributes */
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE ,
FILE_OPEN ,
0 , /* create_options */
& state - > in_cblobs ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , cli_smb2_mxac_opened , req ) ;
return req ;
}
static void cli_smb2_mxac_opened ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_smb2_mxac_state * state = tevent_req_data (
req , struct cli_smb2_mxac_state ) ;
struct smb2_create_blobs out_cblobs = { 0 } ;
2019-03-04 23:21:57 +03:00
struct smb2_create_blob * mxac_blob = NULL ;
2019-03-01 11:48:25 +03:00
NTSTATUS status ;
status = cli_smb2_create_fnum_recv (
subreq , & state - > fnum , NULL , state , & out_cblobs ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
2019-03-04 23:21:57 +03:00
mxac_blob = smb2_create_blob_find ( & out_cblobs , SMB2_CREATE_TAG_MXAC ) ;
2019-03-01 11:48:25 +03:00
if ( mxac_blob = = NULL ) {
state - > status = NT_STATUS_INVALID_NETWORK_RESPONSE ;
goto close ;
}
2019-03-04 23:21:57 +03:00
if ( mxac_blob - > data . length ! = 8 ) {
2019-03-01 11:48:25 +03:00
state - > status = NT_STATUS_INVALID_NETWORK_RESPONSE ;
goto close ;
}
2019-03-04 23:21:57 +03:00
state - > status = NT_STATUS ( IVAL ( mxac_blob - > data . data , 0 ) ) ;
state - > mxac = IVAL ( mxac_blob - > data . data , 4 ) ;
2019-03-01 11:48:25 +03:00
close :
subreq = cli_smb2_close_fnum_send (
state , state - > ev , state - > cli , state - > fnum ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , cli_smb2_mxac_closed , req ) ;
return ;
}
static void cli_smb2_mxac_closed ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
NTSTATUS status ;
status = cli_smb2_close_fnum_recv ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
tevent_req_done ( req ) ;
}
NTSTATUS cli_smb2_query_mxac_recv ( struct tevent_req * req , uint32_t * mxac )
{
struct cli_smb2_mxac_state * state = tevent_req_data (
req , struct cli_smb2_mxac_state ) ;
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
return status ;
}
if ( ! NT_STATUS_IS_OK ( state - > status ) ) {
return state - > status ;
}
* mxac = state - > mxac ;
return NT_STATUS_OK ;
}
NTSTATUS cli_smb2_query_mxac ( struct cli_state * cli ,
const char * fname ,
uint32_t * _mxac )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct tevent_context * ev = NULL ;
struct tevent_req * req = NULL ;
NTSTATUS status = NT_STATUS_INTERNAL_ERROR ;
bool ok ;
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_query_mxac_send ( frame , ev , cli , fname ) ;
if ( req = = NULL ) {
goto fail ;
}
ok = tevent_req_poll_ntstatus ( req , ev , & status ) ;
if ( ! ok ) {
goto fail ;
}
status = cli_smb2_query_mxac_recv ( req , _mxac ) ;
fail :
cli - > raw_status = status ;
TALLOC_FREE ( frame ) ;
return status ;
}
2020-11-13 17:31:16 +03:00
struct cli_smb2_rename_fnum_state {
DATA_BLOB inbuf ;
} ;
2013-08-08 02:54:05 +04:00
2020-11-13 17:31:16 +03:00
static void cli_smb2_rename_fnum_done ( struct tevent_req * subreq ) ;
static struct tevent_req * cli_smb2_rename_fnum_send (
TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
uint16_t fnum ,
const char * fname_dst ,
bool replace )
2013-08-08 02:54:05 +04:00
{
2020-11-13 17:31:16 +03:00
struct tevent_req * req = NULL , * subreq = NULL ;
struct cli_smb2_rename_fnum_state * state = NULL ;
size_t namelen = strlen ( fname_dst ) ;
2013-08-08 02:54:05 +04:00
smb_ucs2_t * converted_str = NULL ;
size_t converted_size_bytes = 0 ;
2020-07-01 00:00:41 +03:00
size_t inbuf_size ;
2020-11-13 17:31:16 +03:00
bool ok ;
2013-08-08 02:54:05 +04:00
2020-11-13 17:31:16 +03:00
req = tevent_req_create (
mem_ctx , & state , struct cli_smb2_rename_fnum_state ) ;
if ( req = = NULL ) {
return NULL ;
2013-08-08 02:54:05 +04:00
}
2020-11-13 17:31:16 +03:00
/*
* SMB2 is pickier about pathnames . Ensure it doesn ' t start in
* a ' \ '
*/
2013-08-08 02:54:05 +04:00
if ( * fname_dst = = ' \\ ' ) {
fname_dst + + ;
}
2020-11-13 17:31:16 +03:00
/*
* SMB2 is pickier about pathnames . Ensure it doesn ' t end in a
* ' \ '
*/
2013-08-08 02:54:05 +04:00
if ( namelen > 0 & & fname_dst [ namelen - 1 ] = = ' \\ ' ) {
2020-11-13 17:31:16 +03:00
fname_dst = talloc_strndup ( state , fname_dst , namelen - 1 ) ;
if ( tevent_req_nomem ( fname_dst , req ) ) {
return tevent_req_post ( req , ev ) ;
}
2013-08-08 02:54:05 +04:00
}
2020-11-13 17:31:16 +03:00
ok = push_ucs2_talloc (
state , & converted_str , fname_dst , & converted_size_bytes ) ;
if ( ! ok ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
2013-08-08 02:54:05 +04:00
}
2020-11-13 17:31:16 +03:00
/*
* W2K8 insists the dest name is not null terminated . Remove
* the last 2 zero bytes and reduce the name length .
*/
2013-08-08 02:54:05 +04:00
if ( converted_size_bytes < 2 ) {
2020-11-13 17:31:16 +03:00
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
2013-08-08 02:54:05 +04:00
}
converted_size_bytes - = 2 ;
2020-07-01 00:00:41 +03:00
inbuf_size = 20 + converted_size_bytes ;
if ( inbuf_size < 20 ) {
/* Integer wrap check. */
2020-11-13 17:31:16 +03:00
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
2020-07-01 00:00:41 +03:00
}
/*
* The Windows 10 SMB2 server has a minimum length
* for a SMB2_FILE_RENAME_INFORMATION buffer of
* 24 bytes . It returns NT_STATUS_INFO_LENGTH_MISMATCH
* if the length is less . This isn ' t an alignment
* issue as Windows client happily 2 - byte align
* for larget target name sizes . Also the Windows 10
* SMB1 server doesn ' t have this restriction .
*
* BUG : https : //bugzilla.samba.org/show_bug.cgi?id=14403
*/
2020-11-13 17:31:16 +03:00
inbuf_size = MAX ( inbuf_size , 24 ) ;
2020-07-01 00:00:41 +03:00
2020-11-13 17:31:16 +03:00
state - > inbuf = data_blob_talloc_zero ( state , inbuf_size ) ;
if ( tevent_req_nomem ( state - > inbuf . data , req ) ) {
return tevent_req_post ( req , ev ) ;
2013-08-08 02:54:05 +04:00
}
2017-03-22 00:02:48 +03:00
if ( replace ) {
2020-11-13 17:31:16 +03:00
SCVAL ( state - > inbuf . data , 0 , 1 ) ;
2017-03-22 00:02:48 +03:00
}
2020-11-13 17:31:16 +03:00
SIVAL ( state - > inbuf . data , 16 , converted_size_bytes ) ;
memcpy ( state - > inbuf . data + 20 , converted_str , converted_size_bytes ) ;
TALLOC_FREE ( converted_str ) ;
2013-08-08 02:54:05 +04:00
/* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
level SMB2_FILE_RENAME_INFORMATION ( SMB_FILE_RENAME_INFORMATION - 1000 ) */
2020-11-13 17:31:16 +03:00
subreq = cli_smb2_set_info_fnum_send (
state , /* mem_ctx */
ev , /* ev */
cli , /* cli */
fnum , /* fnum */
2019-03-17 16:00:09 +03:00
1 , /* in_info_type */
SMB_FILE_RENAME_INFORMATION - 1000 , /* in_file_info_class */
2020-11-13 17:31:16 +03:00
& state - > inbuf , /* in_input_buffer */
0 ) ; /* in_additional_info */
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , cli_smb2_rename_fnum_done , req ) ;
return req ;
}
2013-08-08 02:54:05 +04:00
2020-11-13 17:31:16 +03:00
static void cli_smb2_rename_fnum_done ( struct tevent_req * subreq )
{
NTSTATUS status = cli_smb2_set_info_fnum_recv ( subreq ) ;
tevent_req_simple_finish_ntstatus ( subreq , status ) ;
}
2013-08-08 02:54:05 +04:00
2020-11-13 17:31:16 +03:00
static NTSTATUS cli_smb2_rename_fnum_recv ( struct tevent_req * req )
{
return tevent_req_simple_recv_ntstatus ( req ) ;
}
/***************************************************************
Wrapper that allows SMB2 to rename a file .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct cli_smb2_rename_state {
struct tevent_context * ev ;
struct cli_state * cli ;
const char * fname_dst ;
bool replace ;
uint16_t fnum ;
NTSTATUS rename_status ;
} ;
static void cli_smb2_rename_opened ( struct tevent_req * subreq ) ;
static void cli_smb2_rename_renamed ( struct tevent_req * subreq ) ;
static void cli_smb2_rename_closed ( struct tevent_req * subreq ) ;
struct tevent_req * cli_smb2_rename_send (
TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
const char * fname_src ,
const char * fname_dst ,
bool replace )
{
struct tevent_req * req = NULL , * subreq = NULL ;
struct cli_smb2_rename_state * state = NULL ;
2022-02-04 02:59:51 +03:00
NTSTATUS status ;
2020-11-13 17:31:16 +03:00
req = tevent_req_create (
mem_ctx , & state , struct cli_smb2_rename_state ) ;
if ( req = = NULL ) {
return NULL ;
2013-08-08 02:54:05 +04:00
}
2022-02-04 02:59:51 +03:00
/*
* Strip a MSDFS path from fname_dst if we were given one .
*/
status = cli_dfs_target_check ( state ,
cli ,
fname_src ,
fname_dst ,
& fname_dst ) ;
if ( tevent_req_nterror ( req , status ) ) {
return tevent_req_post ( req , ev ) ;
}
2020-11-13 17:31:16 +03:00
state - > ev = ev ;
state - > cli = cli ;
state - > fname_dst = fname_dst ;
state - > replace = replace ;
2013-08-08 02:54:05 +04:00
2020-11-13 17:31:16 +03:00
subreq = get_fnum_from_path_send (
state , ev , cli , fname_src , DELETE_ACCESS ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , cli_smb2_rename_opened , req ) ;
return req ;
}
2016-12-13 02:52:11 +03:00
2020-11-13 17:31:16 +03:00
static void cli_smb2_rename_opened ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_smb2_rename_state * state = tevent_req_data (
req , struct cli_smb2_rename_state ) ;
NTSTATUS status ;
status = get_fnum_from_path_recv ( subreq , & state - > fnum ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
subreq = cli_smb2_rename_fnum_send (
state ,
state - > ev ,
state - > cli ,
state - > fnum ,
state - > fname_dst ,
state - > replace ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , cli_smb2_rename_renamed , req ) ;
}
static void cli_smb2_rename_renamed ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_smb2_rename_state * state = tevent_req_data (
req , struct cli_smb2_rename_state ) ;
state - > rename_status = cli_smb2_rename_fnum_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
subreq = cli_smb2_close_fnum_send (
state , state - > ev , state - > cli , state - > fnum ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , cli_smb2_rename_closed , req ) ;
}
static void cli_smb2_rename_closed ( struct tevent_req * subreq )
{
NTSTATUS status = cli_smb2_close_fnum_recv ( subreq ) ;
tevent_req_simple_finish_ntstatus ( subreq , status ) ;
}
NTSTATUS cli_smb2_rename_recv ( struct tevent_req * req )
{
struct cli_smb2_rename_state * state = tevent_req_data (
req , struct cli_smb2_rename_state ) ;
NTSTATUS status = NT_STATUS_OK ;
if ( ! tevent_req_is_nterror ( req , & status ) ) {
status = state - > rename_status ;
}
tevent_req_received ( req ) ;
return status ;
}
2013-08-08 02:54:05 +04:00
/***************************************************************
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 ;
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 ;
}
/* 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 ) . */
2019-03-17 16:00:09 +03:00
status = cli_smb2_set_info_fnum (
cli ,
fnum ,
1 , /* in_info_type */
SMB_FILE_FULL_EA_INFORMATION - 1000 , /* in_file_info_class */
& inbuf , /* in_input_buffer */
0 ) ; /* in_additional_info */
2013-08-08 02:54:05 +04:00
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 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 ;
}
/* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
level 15 ( SMB_FILE_FULL_EA_INFORMATION - 1000 ) . */
2019-03-10 21:08:20 +03:00
status = cli_smb2_query_info_fnum (
cli ,
fnum ,
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 */
frame ,
& outbuf ) ;
2013-08-08 02:54:05 +04:00
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 ;
2017-05-26 17:50:18 +03:00
DATA_BLOB info_blob = data_blob_null ;
2016-09-12 22:38:15 +03:00
DATA_BLOB outbuf = data_blob_null ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
unsigned sid_len ;
unsigned int offset ;
2017-05-26 17:50:18 +03:00
struct smb2_query_quota_info query = { 0 } ;
struct file_get_quota_info info = { 0 } ;
enum ndr_err_code err ;
struct ndr_push * ndr_push = NULL ;
2016-09-12 22:38:15 +03: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 ;
}
sid_len = ndr_size_dom_sid ( & pqt - > sid , 0 ) ;
2017-05-26 17:50:18 +03:00
query . return_single = 1 ;
info . next_entry_offset = 0 ;
info . sid_length = sid_len ;
info . sid = pqt - > sid ;
err = ndr_push_struct_blob (
& info_blob ,
frame ,
& info ,
( ndr_push_flags_fn_t ) ndr_push_file_get_quota_info ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( err ) ) {
status = NT_STATUS_INTERNAL_ERROR ;
goto fail ;
}
query . sid_list_length = info_blob . length ;
ndr_push = ndr_push_init_ctx ( frame ) ;
if ( ! ndr_push ) {
2016-09-12 22:38:15 +03:00
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
2017-05-26 17:50:18 +03:00
err = ndr_push_smb2_query_quota_info ( ndr_push ,
NDR_SCALARS | NDR_BUFFERS ,
& query ) ;
2016-09-12 22:38:15 +03:00
2017-05-26 17:50:18 +03:00
if ( ! NDR_ERR_CODE_IS_SUCCESS ( err ) ) {
status = NT_STATUS_INTERNAL_ERROR ;
2016-09-12 22:38:15 +03:00
goto fail ;
}
2017-05-26 17:50:18 +03:00
err = ndr_push_array_uint8 ( ndr_push , NDR_SCALARS , info_blob . data ,
info_blob . length ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( err ) ) {
status = NT_STATUS_INTERNAL_ERROR ;
goto fail ;
}
inbuf . data = ndr_push - > data ;
inbuf . length = ndr_push - > offset ;
2016-09-12 22:38:15 +03:00
2019-03-10 21:08:20 +03:00
status = cli_smb2_query_info_fnum (
cli ,
quota_fnum ,
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 */
frame ,
& outbuf ) ;
2016-09-12 22:38:15 +03:00
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 ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2017-05-26 17:50:18 +03:00
struct smb2_query_quota_info info = { 0 } ;
enum ndr_err_code err ;
2016-09-19 22:17:10 +03: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 cleanup ;
}
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto cleanup ;
}
2017-05-26 17:50:18 +03:00
info . restart_scan = first ? 1 : 0 ;
err = ndr_push_struct_blob (
& inbuf ,
frame ,
& info ,
( ndr_push_flags_fn_t ) ndr_push_smb2_query_quota_info ) ;
2016-09-19 22:17:10 +03:00
2017-05-26 17:50:18 +03:00
if ( ! NDR_ERR_CODE_IS_SUCCESS ( err ) ) {
status = NT_STATUS_INTERNAL_ERROR ;
goto cleanup ;
}
2016-09-19 22:17:10 +03:00
2019-03-10 21:08:20 +03:00
status = cli_smb2_query_info_fnum (
cli ,
quota_fnum ,
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 */
frame ,
& outbuf ) ;
2016-09-19 22:17:10 +03:00
2017-02-28 18:04:16 +03:00
/*
* safeguard against panic from calling parse_user_quota_list with
* NULL buffer
*/
if ( NT_STATUS_IS_OK ( status ) & & outbuf . length = = 0 ) {
status = NT_STATUS_NO_MORE_ENTRIES ;
}
2016-09-19 22:17:10 +03:00
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 ;
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 ;
}
2019-03-10 21:08:20 +03:00
status = cli_smb2_query_info_fnum (
cli ,
quota_fnum ,
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 */
frame ,
& outbuf ) ;
2016-09-20 06:46:28 +03:00
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 ;
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 = build_user_quota_buffer ( qtl , 0 , talloc_tos ( ) , & inbuf , NULL ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto cleanup ;
}
2019-03-17 16:00:09 +03:00
status = cli_smb2_set_info_fnum (
cli ,
quota_fnum ,
4 , /* in_info_type */
0 , /* in_file_info_class */
& inbuf , /* in_input_buffer */
0 ) ; /* in_additional_info */
2016-09-21 19:35:39 +03:00
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 ;
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 = 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
}
2019-03-17 16:00:09 +03:00
status = cli_smb2_set_info_fnum (
cli ,
quota_fnum ,
2 , /* in_info_type */
SMB_FS_QUOTA_INFORMATION - 1000 , /* in_file_info_class */
& inbuf , /* in_input_buffer */
0 ) ; /* in_additional_info */
2016-09-22 01:03:41 +03:00
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 ) ;
2019-02-28 23:18:06 +03:00
tevent_req_simple_finish_ntstatus ( subreq , status ) ;
2016-08-17 01:26:53 +03:00
}
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 ;
2019-03-17 14:24:05 +03:00
uint8_t buf [ 8 ] = { 0 } ;
DATA_BLOB inbuf = { . data = buf , . length = sizeof ( buf ) } ;
2016-12-22 00:55:50 +03: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 ;
}
2019-03-17 14:24:05 +03:00
SBVAL ( buf , 0 , newsize ) ;
2016-12-22 00:55:50 +03:00
/* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
level 20 ( SMB_FILE_END_OF_FILE_INFORMATION - 1000 ) . */
2019-03-17 16:00:09 +03:00
status = cli_smb2_set_info_fnum (
cli ,
fnum ,
1 , /* in_info_type */
SMB_FILE_END_OF_FILE_INFORMATION - 1000 , /* in_file_info_class */
& inbuf , /* in_input_buffer */
0 ) ;
2016-12-22 00:55:50 +03:00
fail :
cli - > raw_status = status ;
TALLOC_FREE ( frame ) ;
return status ;
}
2017-07-25 13:12:02 +03:00
2018-11-16 15:47:00 +03:00
struct cli_smb2_notify_state {
struct tevent_req * subreq ;
struct notify_change * changes ;
size_t num_changes ;
} ;
static void cli_smb2_notify_done ( struct tevent_req * subreq ) ;
static bool cli_smb2_notify_cancel ( struct tevent_req * req ) ;
struct tevent_req * cli_smb2_notify_send (
TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
uint16_t fnum ,
uint32_t buffer_size ,
uint32_t completion_filter ,
bool recursive )
2017-07-25 13:12:02 +03:00
{
2018-11-16 15:47:00 +03:00
struct tevent_req * req = NULL ;
struct cli_smb2_notify_state * state = NULL ;
2017-07-25 13:12:02 +03:00
struct smb2_hnd * ph = NULL ;
2018-11-16 15:47:00 +03:00
NTSTATUS status ;
2017-07-25 13:12:02 +03:00
2018-11-16 15:47:00 +03:00
req = tevent_req_create ( mem_ctx , & state ,
struct cli_smb2_notify_state ) ;
if ( req = = NULL ) {
return NULL ;
2017-07-25 13:12:02 +03:00
}
if ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_SMB2_02 ) {
2018-11-16 15:47:00 +03:00
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
2017-07-25 13:12:02 +03:00
}
status = map_fnum_to_smb2_handle ( cli , fnum , & ph ) ;
2018-11-16 15:47:00 +03:00
if ( tevent_req_nterror ( req , status ) ) {
return tevent_req_post ( req , ev ) ;
2017-07-25 13:12:02 +03:00
}
2018-11-16 15:47:00 +03:00
state - > subreq = smb2cli_notify_send (
state ,
ev ,
cli - > conn ,
cli - > timeout ,
cli - > smb2 . session ,
cli - > smb2 . tcon ,
buffer_size ,
ph - > fid_persistent ,
ph - > fid_volatile ,
completion_filter ,
recursive ) ;
if ( tevent_req_nomem ( state - > subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( state - > subreq , cli_smb2_notify_done , req ) ;
tevent_req_set_cancel_fn ( req , cli_smb2_notify_cancel ) ;
return req ;
}
static bool cli_smb2_notify_cancel ( struct tevent_req * req )
{
struct cli_smb2_notify_state * state = tevent_req_data (
req , struct cli_smb2_notify_state ) ;
bool ok ;
ok = tevent_req_cancel ( state - > subreq ) ;
return ok ;
}
static void cli_smb2_notify_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_smb2_notify_state * state = tevent_req_data (
req , struct cli_smb2_notify_state ) ;
uint8_t * base ;
uint32_t len ;
uint32_t ofs ;
NTSTATUS status ;
status = smb2cli_notify_recv ( subreq , state , & base , & len ) ;
TALLOC_FREE ( subreq ) ;
2017-07-25 13:12:02 +03:00
2017-10-30 16:36:46 +03:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_IO_TIMEOUT ) ) {
2018-11-16 15:47:00 +03:00
tevent_req_done ( req ) ;
return ;
2017-10-30 16:36:46 +03:00
}
2018-11-16 15:47:00 +03:00
if ( tevent_req_nterror ( req , status ) ) {
return ;
2017-10-30 16:36:46 +03:00
}
2017-07-25 13:12:02 +03:00
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 ;
2018-11-16 15:47:00 +03:00
tmp = talloc_realloc (
state ,
state - > changes ,
struct notify_change ,
state - > num_changes + 1 ) ;
if ( tevent_req_nomem ( tmp , req ) ) {
return ;
2017-07-25 13:12:02 +03:00
}
2018-11-16 15:47:00 +03:00
state - > changes = tmp ;
c = & state - > changes [ state - > num_changes ] ;
state - > num_changes + = 1 ;
2017-07-25 13:12:02 +03:00
if ( smb_buffer_oob ( len , ofs , next_ofs ) | |
smb_buffer_oob ( len , ofs + 12 , file_name_length ) ) {
2018-11-16 15:47:00 +03:00
tevent_req_nterror (
req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
2017-07-25 13:12:02 +03:00
}
c - > action = IVAL ( base , ofs + 4 ) ;
2018-11-16 15:47:00 +03:00
ok = convert_string_talloc (
state - > changes ,
CH_UTF16LE ,
CH_UNIX ,
base + ofs + 12 ,
file_name_length ,
& c - > name ,
& namelen ) ;
2017-07-25 13:12:02 +03:00
if ( ! ok ) {
2018-11-16 15:47:00 +03:00
tevent_req_nterror (
req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
2017-07-25 13:12:02 +03:00
}
if ( next_ofs = = 0 ) {
break ;
}
ofs + = next_ofs ;
}
2018-11-16 15:47:00 +03:00
tevent_req_done ( req ) ;
}
2017-07-25 13:12:02 +03:00
2018-11-16 15:47:00 +03:00
NTSTATUS cli_smb2_notify_recv ( struct tevent_req * req ,
TALLOC_CTX * mem_ctx ,
struct notify_change * * pchanges ,
uint32_t * pnum_changes )
{
struct cli_smb2_notify_state * state = tevent_req_data (
req , struct cli_smb2_notify_state ) ;
NTSTATUS status ;
2017-07-25 13:12:02 +03:00
2018-11-16 15:47:00 +03:00
if ( tevent_req_is_nterror ( req , & status ) ) {
return status ;
}
* pchanges = talloc_move ( mem_ctx , & state - > changes ) ;
* pnum_changes = state - > num_changes ;
return NT_STATUS_OK ;
}
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 )
{
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_notify_send (
frame ,
ev ,
cli ,
fnum ,
buffer_size ,
completion_filter ,
recursive ) ;
if ( req = = NULL ) {
goto fail ;
}
if ( ! tevent_req_poll_ntstatus ( req , ev , & status ) ) {
goto fail ;
}
status = cli_smb2_notify_recv ( req , mem_ctx , pchanges , pnum_changes ) ;
fail :
2017-07-25 13:12:02 +03:00
TALLOC_FREE ( frame ) ;
return status ;
}
2017-11-29 01:09:39 +03:00
struct cli_smb2_set_reparse_point_fnum_state {
struct cli_state * cli ;
uint16_t fnum ;
struct smb2_hnd * ph ;
DATA_BLOB input_buffer ;
} ;
static void cli_smb2_set_reparse_point_fnum_done ( struct tevent_req * subreq ) ;
struct tevent_req * cli_smb2_set_reparse_point_fnum_send (
TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
uint16_t fnum ,
DATA_BLOB in_buf )
{
struct tevent_req * req , * subreq ;
struct cli_smb2_set_reparse_point_fnum_state * state = NULL ;
NTSTATUS status ;
req = tevent_req_create ( mem_ctx , & state ,
struct cli_smb2_set_reparse_point_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 ) ;
}
state - > input_buffer = data_blob_talloc ( state ,
in_buf . data ,
in_buf . length ) ;
if ( state - > input_buffer . data = = NULL ) {
tevent_req_nterror ( req , NT_STATUS_NO_MEMORY ) ;
return tevent_req_post ( req , ev ) ;
}
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_SET_REPARSE_POINT ,
0 , /* in_max_input_length */
& state - > input_buffer ,
0 ,
NULL ,
SMB2_IOCTL_FLAG_IS_FSCTL ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq ,
cli_smb2_set_reparse_point_fnum_done ,
req ) ;
return req ;
}
static void cli_smb2_set_reparse_point_fnum_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_smb2_set_reparse_point_fnum_state * state = tevent_req_data (
req , struct cli_smb2_set_reparse_point_fnum_state ) ;
NTSTATUS status ;
status = smb2cli_ioctl_recv ( subreq , state ,
NULL ,
NULL ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
tevent_req_done ( req ) ;
}
NTSTATUS cli_smb2_set_reparse_point_fnum_recv ( struct tevent_req * req )
{
return tevent_req_simple_recv_ntstatus ( req ) ;
}
2017-11-29 23:37:36 +03:00
struct cli_smb2_get_reparse_point_fnum_state {
struct cli_state * cli ;
uint16_t fnum ;
struct smb2_hnd * ph ;
DATA_BLOB output_buffer ;
} ;
static void cli_smb2_get_reparse_point_fnum_done ( struct tevent_req * subreq ) ;
struct tevent_req * cli_smb2_get_reparse_point_fnum_send (
TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
uint16_t fnum )
{
struct tevent_req * req , * subreq ;
2019-03-25 11:11:51 +03:00
struct cli_smb2_get_reparse_point_fnum_state * state = NULL ;
2017-11-29 23:37:36 +03:00
NTSTATUS status ;
req = tevent_req_create ( mem_ctx , & state ,
struct cli_smb2_get_reparse_point_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 ) ;
}
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_REPARSE_POINT ,
0 , /* in_max_input_length */
NULL ,
64 * 1024 ,
NULL ,
SMB2_IOCTL_FLAG_IS_FSCTL ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq ,
cli_smb2_get_reparse_point_fnum_done ,
req ) ;
return req ;
}
static void cli_smb2_get_reparse_point_fnum_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_smb2_get_reparse_point_fnum_state * state = tevent_req_data (
req , struct cli_smb2_get_reparse_point_fnum_state ) ;
2019-03-26 12:56:27 +03:00
struct cli_state * cli = state - > cli ;
2017-11-29 23:37:36 +03:00
NTSTATUS status ;
status = smb2cli_ioctl_recv ( subreq , state ,
NULL ,
& state - > output_buffer ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
2019-03-26 12:56:27 +03:00
cli - > raw_status = status ;
2017-11-29 23:37:36 +03:00
return ;
}
tevent_req_done ( req ) ;
}
NTSTATUS cli_smb2_get_reparse_point_fnum_recv ( struct tevent_req * req ,
TALLOC_CTX * mem_ctx ,
DATA_BLOB * output )
{
struct cli_smb2_get_reparse_point_fnum_state * state = tevent_req_data (
req , struct cli_smb2_get_reparse_point_fnum_state ) ;
if ( tevent_req_is_nterror ( req , & state - > cli - > raw_status ) ) {
2019-03-26 12:56:27 +03:00
NTSTATUS status = state - > cli - > raw_status ;
2017-11-29 23:37:36 +03:00
tevent_req_received ( req ) ;
2019-03-26 12:56:27 +03:00
return status ;
2017-11-29 23:37:36 +03:00
}
* output = data_blob_dup_talloc ( mem_ctx , state - > output_buffer ) ;
if ( output - > data = = NULL ) {
tevent_req_received ( req ) ;
return NT_STATUS_NO_MEMORY ;
}
tevent_req_received ( req ) ;
return NT_STATUS_OK ;
}