2011-07-18 16:35:03 +04:00
/*
Unix SMB / CIFS implementation .
Infrastructure for async SMB client requests
Copyright ( C ) Volker Lendecke 2008
2011-08-11 15:29:59 +04:00
Copyright ( C ) Stefan Metzmacher 2011
2011-07-18 16:35:03 +04:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
2011-08-11 15:29:59 +04:00
# include "system/network.h"
2011-07-18 16:35:03 +04:00
# include "../lib/async_req/async_sock.h"
# include "../lib/util/tevent_ntstatus.h"
# include "../lib/util/tevent_unix.h"
2011-08-11 15:29:59 +04:00
# include "lib/util/util_net.h"
2011-09-03 12:18:17 +04:00
# include "lib/util/dlinklist.h"
2015-02-17 23:16:45 +03:00
# include "lib/util/iov_buf.h"
2011-08-11 15:29:59 +04:00
# include "../libcli/smb/smb_common.h"
2011-07-18 16:35:03 +04:00
# include "../libcli/smb/smb_seal.h"
2011-08-11 15:29:59 +04:00
# include "../libcli/smb/smb_signing.h"
2011-07-18 16:35:03 +04:00
# include "../libcli/smb/read_smb.h"
2011-08-11 15:29:59 +04:00
# include "smbXcli_base.h"
# include "librpc/ndr/libndr.h"
2014-09-23 06:09:16 +04:00
# include "libcli/smb/smb2_negotiate_context.h"
2019-03-04 18:59:51 +03:00
# include "libcli/smb/smb2_signing.h"
2011-07-18 16:35:03 +04:00
2019-06-26 07:41:05 +03:00
# include "lib/crypto/gnutls_helpers.h"
2018-10-17 19:09:06 +03:00
# include <gnutls/gnutls.h>
# include <gnutls/crypto.h>
2011-09-03 12:18:17 +04:00
struct smbXcli_conn ;
struct smbXcli_req ;
struct smbXcli_session ;
2012-06-02 20:03:20 +04:00
struct smbXcli_tcon ;
2011-09-03 12:18:17 +04:00
2011-08-11 15:29:59 +04:00
struct smbXcli_conn {
2015-05-28 14:22:19 +03:00
int sock_fd ;
2011-08-11 15:29:59 +04:00
struct sockaddr_storage local_ss ;
struct sockaddr_storage remote_ss ;
const char * remote_name ;
struct tevent_queue * outgoing ;
struct tevent_req * * pending ;
struct tevent_req * read_smb_req ;
2015-05-29 16:29:31 +03:00
struct tevent_req * suicide_req ;
2011-08-11 15:29:59 +04:00
2014-09-26 23:15:00 +04:00
enum protocol_types min_protocol ;
enum protocol_types max_protocol ;
2011-08-11 15:29:59 +04:00
enum protocol_types protocol ;
bool allow_signing ;
bool desire_signing ;
bool mandatory_signing ;
/*
* The incoming dispatch function should return :
* - NT_STATUS_RETRY , if more incoming PDUs are expected .
* - NT_STATUS_OK , if no more processing is desired , e . g .
* the dispatch function called
* tevent_req_done ( ) .
* - All other return values disconnect the connection .
*/
NTSTATUS ( * dispatch_incoming ) ( struct smbXcli_conn * conn ,
TALLOC_CTX * tmp_mem ,
uint8_t * inbuf ) ;
struct {
struct {
uint32_t capabilities ;
uint32_t max_xmit ;
} client ;
struct {
uint32_t capabilities ;
uint32_t max_xmit ;
uint16_t max_mux ;
uint16_t security_mode ;
bool readbraw ;
bool writebraw ;
bool lockread ;
bool writeunlock ;
uint32_t session_key ;
struct GUID guid ;
DATA_BLOB gss_blob ;
uint8_t challenge [ 8 ] ;
const char * workgroup ;
2011-09-15 16:02:49 +04:00
const char * name ;
2011-08-11 15:29:59 +04:00
int time_zone ;
NTTIME system_time ;
} server ;
uint32_t capabilities ;
uint32_t max_xmit ;
uint16_t mid ;
2022-03-08 05:05:41 +03:00
struct smb1_signing_state * signing ;
2011-08-11 15:29:59 +04:00
struct smb_trans_enc_state * trans_enc ;
2011-11-25 17:49:24 +04:00
struct tevent_req * read_braw_req ;
2011-08-11 15:29:59 +04:00
} smb1 ;
2011-09-15 14:23:05 +04:00
struct {
struct {
2012-02-29 05:02:29 +04:00
uint32_t capabilities ;
2011-09-15 14:23:05 +04:00
uint16_t security_mode ;
2011-09-15 15:21:42 +04:00
struct GUID guid ;
2021-03-10 01:49:19 +03:00
struct smb311_capabilities smb3_capabilities ;
2011-09-15 14:23:05 +04:00
} client ;
struct {
uint32_t capabilities ;
uint16_t security_mode ;
struct GUID guid ;
uint32_t max_trans_size ;
uint32_t max_read_size ;
uint32_t max_write_size ;
NTTIME system_time ;
NTTIME start_time ;
DATA_BLOB gss_blob ;
2020-11-11 15:18:24 +03:00
uint16_t sign_algo ;
2014-09-23 06:09:16 +04:00
uint16_t cipher ;
2022-08-25 16:16:10 +03:00
bool smb311_posix ;
2011-09-15 14:23:05 +04:00
} server ;
uint64_t mid ;
2011-09-06 19:52:02 +04:00
uint16_t cur_credits ;
uint16_t max_credits ;
2014-09-23 06:09:16 +04:00
2015-05-28 01:13:15 +03:00
uint32_t cc_chunk_len ;
uint32_t cc_max_chunks ;
2015-05-08 13:52:23 +03:00
uint8_t io_priority ;
2018-01-11 13:25:49 +03:00
bool force_channel_sequence ;
2014-09-23 06:09:16 +04:00
uint8_t preauth_sha512 [ 64 ] ;
2011-09-15 14:23:05 +04:00
} smb2 ;
2011-09-03 12:18:17 +04:00
struct smbXcli_session * sessions ;
} ;
2012-07-26 04:36:37 +04:00
struct smb2cli_session {
uint64_t session_id ;
uint16_t session_flags ;
2021-03-05 18:43:29 +03:00
struct smb2_signing_key * application_key ;
2019-03-04 18:59:51 +03:00
struct smb2_signing_key * signing_key ;
2012-07-26 04:36:37 +04:00
bool should_sign ;
bool should_encrypt ;
2019-03-14 11:34:23 +03:00
struct smb2_signing_key * encryption_key ;
2019-03-14 11:48:54 +03:00
struct smb2_signing_key * decryption_key ;
2015-05-28 16:20:54 +03:00
uint64_t nonce_high_random ;
uint64_t nonce_high_max ;
2012-07-26 04:36:37 +04:00
uint64_t nonce_high ;
uint64_t nonce_low ;
2012-07-26 03:54:33 +04:00
uint16_t channel_sequence ;
2014-07-10 15:16:04 +04:00
bool replay_active ;
2018-11-09 17:17:19 +03:00
bool require_signed_response ;
2012-07-26 04:36:37 +04:00
} ;
2011-09-03 12:18:17 +04:00
struct smbXcli_session {
struct smbXcli_session * prev , * next ;
struct smbXcli_conn * conn ;
2012-06-02 14:49:22 +04:00
struct {
uint16_t session_id ;
2016-04-18 18:33:11 +03:00
uint16_t action ;
2012-08-01 10:53:30 +04:00
DATA_BLOB application_key ;
2012-08-01 11:01:25 +04:00
bool protected_key ;
2012-06-02 14:49:22 +04:00
} smb1 ;
2012-07-26 04:36:37 +04:00
struct smb2cli_session * smb2 ;
2011-09-03 12:18:17 +04:00
struct {
2019-03-04 18:59:51 +03:00
struct smb2_signing_key * signing_key ;
2014-09-25 00:58:49 +04:00
uint8_t preauth_sha512 [ 64 ] ;
2012-07-26 04:36:37 +04:00
} smb2_channel ;
2012-10-22 16:18:20 +04:00
/*
* this should be a short term hack
* until the upper layers have implemented
* re - authentication .
*/
bool disconnect_expired ;
2011-08-11 15:29:59 +04:00
} ;
2012-06-02 20:03:20 +04:00
struct smbXcli_tcon {
2013-09-13 13:07:32 +04:00
bool is_smb1 ;
2013-09-27 07:02:09 +04:00
uint32_t fs_attributes ;
2013-09-13 13:07:32 +04:00
2012-06-02 20:03:20 +04:00
struct {
uint16_t tcon_id ;
uint16_t optional_support ;
uint32_t maximal_access ;
uint32_t guest_maximal_access ;
char * service ;
char * fs_type ;
} smb1 ;
struct {
uint32_t tcon_id ;
uint8_t type ;
uint32_t flags ;
uint32_t capabilities ;
uint32_t maximal_access ;
2014-09-26 08:29:02 +04:00
bool should_sign ;
2012-07-25 14:34:20 +04:00
bool should_encrypt ;
2012-06-02 20:03:20 +04:00
} smb2 ;
} ;
2011-08-11 15:29:59 +04:00
struct smbXcli_req_state {
struct tevent_context * ev ;
struct smbXcli_conn * conn ;
2011-09-03 12:18:32 +04:00
struct smbXcli_session * session ; /* maybe NULL */
2012-07-23 23:34:58 +04:00
struct smbXcli_tcon * tcon ; /* maybe NULL */
2011-08-11 15:29:59 +04:00
uint8_t length_hdr [ 4 ] ;
bool one_way ;
uint8_t * inbuf ;
2015-05-29 17:14:40 +03:00
struct tevent_req * write_req ;
2018-10-28 04:03:28 +03:00
struct timeval endtime ;
2011-08-11 15:29:59 +04:00
struct {
/* Space for the header including the wct */
uint8_t hdr [ HDR_VWV ] ;
/*
* For normal requests , smb1cli_req_send chooses a mid .
* SecondaryV trans requests need to use the mid of the primary
* request , so we need a place to store it .
* Assume it is set if ! = 0.
*/
uint16_t mid ;
uint16_t * vwv ;
uint8_t bytecount_buf [ 2 ] ;
2011-11-28 18:28:31 +04:00
# define MAX_SMB_IOV 10
2011-08-11 15:29:59 +04:00
/* length_hdr, hdr, words, byte_count, buffers */
struct iovec iov [ 1 + 3 + MAX_SMB_IOV ] ;
int iov_count ;
2011-11-18 12:24:11 +04:00
bool one_way_seqnum ;
2011-08-11 15:29:59 +04:00
uint32_t seqnum ;
struct tevent_req * * chained_requests ;
2011-11-16 14:11:18 +04:00
uint8_t recv_cmd ;
NTSTATUS recv_status ;
/* always an array of 3 talloc elements */
struct iovec * recv_iov ;
2011-08-11 15:29:59 +04:00
} smb1 ;
2011-09-15 14:23:05 +04:00
struct {
const uint8_t * fixed ;
uint16_t fixed_len ;
const uint8_t * dyn ;
uint32_t dyn_len ;
2012-07-23 12:14:53 +04:00
uint8_t transform [ SMB2_TF_HDR_SIZE ] ;
2012-07-23 11:44:06 +04:00
uint8_t hdr [ SMB2_HDR_BODY ] ;
2011-09-15 14:23:05 +04:00
uint8_t pad [ 7 ] ; /* padding space for compounding */
2012-07-23 10:11:59 +04:00
/*
* always an array of 3 talloc elements
* ( without a SMB2_TRANSFORM header ! )
*
* HDR , BODY , DYN
*/
2011-09-15 14:23:05 +04:00
struct iovec * recv_iov ;
2011-09-06 19:52:02 +04:00
2013-08-13 11:50:29 +04:00
/*
* the expected max for the response dyn_len
*/
uint32_t max_dyn_len ;
2011-09-06 19:52:02 +04:00
uint16_t credit_charge ;
2011-09-03 12:18:32 +04:00
2012-07-23 12:00:50 +04:00
bool should_sign ;
2012-07-23 12:14:53 +04:00
bool should_encrypt ;
2012-08-14 11:30:43 +04:00
uint64_t encryption_session_id ;
2012-07-23 12:00:50 +04:00
2011-09-03 12:18:32 +04:00
bool signing_skipped ;
2018-11-09 17:26:44 +03:00
bool require_signed_response ;
2011-10-27 19:20:27 +04:00
bool notify_async ;
bool got_async ;
2015-05-08 13:05:06 +03:00
uint16_t cancel_flags ;
uint64_t cancel_mid ;
uint64_t cancel_aid ;
2011-09-15 14:23:05 +04:00
} smb2 ;
2011-08-11 15:29:59 +04:00
} ;
static int smbXcli_conn_destructor ( struct smbXcli_conn * conn )
{
/*
* NT_STATUS_OK , means we do not notify the callers
*/
smbXcli_conn_disconnect ( conn , NT_STATUS_OK ) ;
2011-09-03 12:18:17 +04:00
while ( conn - > sessions ) {
conn - > sessions - > conn = NULL ;
DLIST_REMOVE ( conn - > sessions , conn - > sessions ) ;
}
2011-08-11 15:29:59 +04:00
if ( conn - > smb1 . trans_enc ) {
2012-01-14 08:30:34 +04:00
TALLOC_FREE ( conn - > smb1 . trans_enc ) ;
2011-08-11 15:29:59 +04:00
}
return 0 ;
}
struct smbXcli_conn * smbXcli_conn_create ( TALLOC_CTX * mem_ctx ,
int fd ,
const char * remote_name ,
enum smb_signing_setting signing_state ,
2011-09-15 15:21:42 +04:00
uint32_t smb1_capabilities ,
2012-02-29 05:02:29 +04:00
struct GUID * client_guid ,
2021-03-10 01:49:19 +03:00
uint32_t smb2_capabilities ,
const struct smb311_capabilities * smb3_capabilities )
2011-08-11 15:29:59 +04:00
{
struct smbXcli_conn * conn = NULL ;
void * ss = NULL ;
struct sockaddr * sa = NULL ;
socklen_t sa_length ;
int ret ;
2021-03-10 01:38:51 +03:00
if ( smb3_capabilities ! = NULL ) {
2021-03-11 13:04:14 +03:00
const struct smb3_signing_capabilities * sign_algos =
& smb3_capabilities - > signing ;
2021-03-10 01:38:51 +03:00
const struct smb3_encryption_capabilities * ciphers =
& smb3_capabilities - > encryption ;
2021-03-11 13:04:14 +03:00
SMB_ASSERT ( sign_algos - > num_algos < = SMB3_SIGNING_CAPABILITIES_MAX_ALGOS ) ;
2021-03-10 01:38:51 +03:00
SMB_ASSERT ( ciphers - > num_algos < = SMB3_ENCRYTION_CAPABILITIES_MAX_ALGOS ) ;
}
2011-08-11 15:29:59 +04:00
conn = talloc_zero ( mem_ctx , struct smbXcli_conn ) ;
if ( ! conn ) {
return NULL ;
}
2020-11-24 19:35:26 +03:00
ret = set_blocking ( fd , false ) ;
if ( ret < 0 ) {
goto error ;
}
2015-05-28 14:22:19 +03:00
conn - > sock_fd = fd ;
2011-09-25 05:15:54 +04:00
2011-08-11 15:29:59 +04:00
conn - > remote_name = talloc_strdup ( conn , remote_name ) ;
if ( conn - > remote_name = = NULL ) {
goto error ;
}
ss = ( void * ) & conn - > local_ss ;
sa = ( struct sockaddr * ) ss ;
sa_length = sizeof ( conn - > local_ss ) ;
ret = getsockname ( fd , sa , & sa_length ) ;
if ( ret = = - 1 ) {
goto error ;
}
ss = ( void * ) & conn - > remote_ss ;
sa = ( struct sockaddr * ) ss ;
sa_length = sizeof ( conn - > remote_ss ) ;
ret = getpeername ( fd , sa , & sa_length ) ;
if ( ret = = - 1 ) {
goto error ;
}
conn - > outgoing = tevent_queue_create ( conn , " smbXcli_outgoing " ) ;
if ( conn - > outgoing = = NULL ) {
goto error ;
}
conn - > pending = NULL ;
2014-09-26 23:15:00 +04:00
conn - > min_protocol = PROTOCOL_NONE ;
conn - > max_protocol = PROTOCOL_NONE ;
2011-08-11 15:29:59 +04:00
conn - > protocol = PROTOCOL_NONE ;
switch ( signing_state ) {
case SMB_SIGNING_OFF :
/* never */
conn - > allow_signing = false ;
conn - > desire_signing = false ;
conn - > mandatory_signing = false ;
break ;
case SMB_SIGNING_DEFAULT :
case SMB_SIGNING_IF_REQUIRED :
/* if the server requires it */
conn - > allow_signing = true ;
conn - > desire_signing = false ;
conn - > mandatory_signing = false ;
break ;
2015-06-30 15:16:19 +03:00
case SMB_SIGNING_DESIRED :
/* if the server desires it */
conn - > allow_signing = true ;
conn - > desire_signing = true ;
conn - > mandatory_signing = false ;
break ;
2015-12-16 11:55:37 +03:00
case SMB_SIGNING_IPC_DEFAULT :
2011-08-11 15:29:59 +04:00
case SMB_SIGNING_REQUIRED :
/* always */
conn - > allow_signing = true ;
conn - > desire_signing = true ;
conn - > mandatory_signing = true ;
break ;
}
conn - > smb1 . client . capabilities = smb1_capabilities ;
conn - > smb1 . client . max_xmit = UINT16_MAX ;
conn - > smb1 . capabilities = conn - > smb1 . client . capabilities ;
conn - > smb1 . max_xmit = 1024 ;
conn - > smb1 . mid = 1 ;
/* initialise signing */
2022-03-08 06:12:45 +03:00
conn - > smb1 . signing = smb1_signing_init ( conn ,
2011-08-11 15:29:59 +04:00
conn - > allow_signing ,
conn - > desire_signing ,
conn - > mandatory_signing ) ;
if ( ! conn - > smb1 . signing ) {
goto error ;
}
2011-09-15 14:23:05 +04:00
conn - > smb2 . client . security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED ;
if ( conn - > mandatory_signing ) {
conn - > smb2 . client . security_mode | = SMB2_NEGOTIATE_SIGNING_REQUIRED ;
}
2011-09-15 15:21:42 +04:00
if ( client_guid ) {
conn - > smb2 . client . guid = * client_guid ;
}
2012-02-29 05:02:29 +04:00
conn - > smb2 . client . capabilities = smb2_capabilities ;
2021-03-10 01:49:19 +03:00
if ( smb3_capabilities ! = NULL ) {
conn - > smb2 . client . smb3_capabilities = * smb3_capabilities ;
}
2011-09-15 14:23:05 +04:00
2011-09-06 19:52:02 +04:00
conn - > smb2 . cur_credits = 1 ;
conn - > smb2 . max_credits = 0 ;
2015-05-08 13:52:23 +03:00
conn - > smb2 . io_priority = 1 ;
2011-09-06 19:52:02 +04:00
2015-05-28 01:13:15 +03:00
/*
* Samba and Windows servers accept a maximum of 16 MiB with a maximum
* chunk length of 1 MiB .
*/
conn - > smb2 . cc_chunk_len = 1024 * 1024 ;
conn - > smb2 . cc_max_chunks = 16 ;
2011-08-11 15:29:59 +04:00
talloc_set_destructor ( conn , smbXcli_conn_destructor ) ;
return conn ;
error :
TALLOC_FREE ( conn ) ;
return NULL ;
}
bool smbXcli_conn_is_connected ( struct smbXcli_conn * conn )
{
if ( conn = = NULL ) {
return false ;
}
2015-05-28 14:22:19 +03:00
if ( conn - > sock_fd = = - 1 ) {
2011-08-11 15:29:59 +04:00
return false ;
}
return true ;
}
enum protocol_types smbXcli_conn_protocol ( struct smbXcli_conn * conn )
{
return conn - > protocol ;
}
bool smbXcli_conn_use_unicode ( struct smbXcli_conn * conn )
{
if ( conn - > protocol > = PROTOCOL_SMB2_02 ) {
return true ;
}
if ( conn - > smb1 . capabilities & CAP_UNICODE ) {
return true ;
}
return false ;
}
2017-08-29 16:35:49 +03:00
bool smbXcli_conn_signing_mandatory ( struct smbXcli_conn * conn )
{
return conn - > mandatory_signing ;
}
2022-08-25 16:16:10 +03:00
bool smbXcli_conn_have_posix ( struct smbXcli_conn * conn )
{
if ( conn - > protocol > = PROTOCOL_SMB3_11 ) {
return conn - > smb2 . server . smb311_posix ;
}
if ( conn - > protocol < = PROTOCOL_NT1 ) {
return ( conn - > smb1 . capabilities & CAP_UNIX ) ;
}
return false ;
}
2017-03-26 08:10:34 +03:00
/*
* [ MS - SMB ] 2.2 .2 .3 .5 - SMB1 support for passing through
* query / set commands to the file system
*/
bool smbXcli_conn_support_passthrough ( struct smbXcli_conn * conn )
{
if ( conn - > protocol > = PROTOCOL_SMB2_02 ) {
return true ;
}
if ( conn - > smb1 . capabilities & CAP_W2K_SMBS ) {
return true ;
}
return false ;
}
2011-08-11 15:29:59 +04:00
void smbXcli_conn_set_sockopt ( struct smbXcli_conn * conn , const char * options )
{
2015-05-28 14:22:19 +03:00
set_socket_options ( conn - > sock_fd , options ) ;
2011-08-11 15:29:59 +04:00
}
const struct sockaddr_storage * smbXcli_conn_local_sockaddr ( struct smbXcli_conn * conn )
{
return & conn - > local_ss ;
}
const struct sockaddr_storage * smbXcli_conn_remote_sockaddr ( struct smbXcli_conn * conn )
{
return & conn - > remote_ss ;
}
const char * smbXcli_conn_remote_name ( struct smbXcli_conn * conn )
{
return conn - > remote_name ;
}
2011-09-15 16:02:49 +04:00
uint16_t smbXcli_conn_max_requests ( struct smbXcli_conn * conn )
{
if ( conn - > protocol > = PROTOCOL_SMB2_02 ) {
/*
* TODO . . .
*/
return 1 ;
}
return conn - > smb1 . server . max_mux ;
}
NTTIME smbXcli_conn_server_system_time ( struct smbXcli_conn * conn )
{
if ( conn - > protocol > = PROTOCOL_SMB2_02 ) {
return conn - > smb2 . server . system_time ;
}
return conn - > smb1 . server . system_time ;
}
const DATA_BLOB * smbXcli_conn_server_gss_blob ( struct smbXcli_conn * conn )
{
if ( conn - > protocol > = PROTOCOL_SMB2_02 ) {
return & conn - > smb2 . server . gss_blob ;
}
return & conn - > smb1 . server . gss_blob ;
}
const struct GUID * smbXcli_conn_server_guid ( struct smbXcli_conn * conn )
{
if ( conn - > protocol > = PROTOCOL_SMB2_02 ) {
return & conn - > smb2 . server . guid ;
}
return & conn - > smb1 . server . guid ;
}
2018-01-11 13:25:49 +03:00
bool smbXcli_conn_get_force_channel_sequence ( struct smbXcli_conn * conn )
{
return conn - > smb2 . force_channel_sequence ;
}
void smbXcli_conn_set_force_channel_sequence ( struct smbXcli_conn * conn ,
bool v )
{
conn - > smb2 . force_channel_sequence = v ;
}
2012-01-04 16:28:07 +04:00
struct smbXcli_conn_samba_suicide_state {
struct smbXcli_conn * conn ;
struct iovec iov ;
uint8_t buf [ 9 ] ;
2015-05-29 16:29:31 +03:00
struct tevent_req * write_req ;
2012-01-04 16:28:07 +04:00
} ;
2015-05-29 16:29:31 +03:00
static void smbXcli_conn_samba_suicide_cleanup ( struct tevent_req * req ,
enum tevent_req_state req_state ) ;
2012-01-04 16:28:07 +04:00
static void smbXcli_conn_samba_suicide_done ( struct tevent_req * subreq ) ;
struct tevent_req * smbXcli_conn_samba_suicide_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct smbXcli_conn * conn ,
uint8_t exitcode )
{
struct tevent_req * req , * subreq ;
struct smbXcli_conn_samba_suicide_state * state ;
req = tevent_req_create ( mem_ctx , & state ,
struct smbXcli_conn_samba_suicide_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > conn = conn ;
2019-03-21 13:21:21 +03:00
SIVAL ( state - > buf , 4 , SMB_SUICIDE_PACKET ) ;
2012-01-04 16:28:07 +04:00
SCVAL ( state - > buf , 8 , exitcode ) ;
_smb_setlen_nbt ( state - > buf , sizeof ( state - > buf ) - 4 ) ;
2015-05-29 16:29:31 +03:00
if ( conn - > suicide_req ! = NULL ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
}
2012-01-04 16:28:07 +04:00
state - > iov . iov_base = state - > buf ;
state - > iov . iov_len = sizeof ( state - > buf ) ;
2015-05-28 14:22:19 +03:00
subreq = writev_send ( state , ev , conn - > outgoing , conn - > sock_fd ,
2012-01-04 16:28:07 +04:00
false , & state - > iov , 1 ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , smbXcli_conn_samba_suicide_done , req ) ;
2015-05-29 16:29:31 +03:00
state - > write_req = subreq ;
tevent_req_set_cleanup_fn ( req , smbXcli_conn_samba_suicide_cleanup ) ;
/*
* We need to use tevent_req_defer_callback ( )
* in order to allow smbXcli_conn_disconnect ( )
* to do a safe cleanup .
*/
tevent_req_defer_callback ( req , ev ) ;
conn - > suicide_req = req ;
2012-01-04 16:28:07 +04:00
return req ;
}
2015-05-29 16:29:31 +03:00
static void smbXcli_conn_samba_suicide_cleanup ( struct tevent_req * req ,
enum tevent_req_state req_state )
{
struct smbXcli_conn_samba_suicide_state * state = tevent_req_data (
req , struct smbXcli_conn_samba_suicide_state ) ;
TALLOC_FREE ( state - > write_req ) ;
if ( state - > conn = = NULL ) {
return ;
}
if ( state - > conn - > suicide_req = = req ) {
state - > conn - > suicide_req = NULL ;
}
state - > conn = NULL ;
}
2012-01-04 16:28:07 +04:00
static void smbXcli_conn_samba_suicide_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct smbXcli_conn_samba_suicide_state * state = tevent_req_data (
req , struct smbXcli_conn_samba_suicide_state ) ;
ssize_t nwritten ;
int err ;
2015-05-29 16:29:31 +03:00
state - > write_req = NULL ;
2012-01-04 16:28:07 +04:00
nwritten = writev_recv ( subreq , & err ) ;
TALLOC_FREE ( subreq ) ;
if ( nwritten = = - 1 ) {
2015-05-29 16:29:31 +03:00
/* here, we need to notify all pending requests */
2012-01-04 16:28:07 +04:00
NTSTATUS status = map_nt_error_from_unix_common ( err ) ;
smbXcli_conn_disconnect ( state - > conn , status ) ;
return ;
}
tevent_req_done ( req ) ;
}
NTSTATUS smbXcli_conn_samba_suicide_recv ( struct tevent_req * req )
{
return tevent_req_simple_recv_ntstatus ( req ) ;
}
NTSTATUS smbXcli_conn_samba_suicide ( struct smbXcli_conn * conn ,
uint8_t exitcode )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct tevent_context * ev ;
struct tevent_req * req ;
NTSTATUS status = NT_STATUS_NO_MEMORY ;
bool ok ;
if ( smbXcli_conn_has_async_calls ( conn ) ) {
/*
* Can ' t use sync call while an async call is in flight
*/
status = NT_STATUS_INVALID_PARAMETER_MIX ;
goto fail ;
}
2013-02-18 12:07:11 +04:00
ev = samba_tevent_context_init ( frame ) ;
2012-01-04 16:28:07 +04:00
if ( ev = = NULL ) {
goto fail ;
}
req = smbXcli_conn_samba_suicide_send ( frame , ev , conn , exitcode ) ;
if ( req = = NULL ) {
goto fail ;
}
2015-02-25 23:42:33 +03:00
ok = tevent_req_poll_ntstatus ( req , ev , & status ) ;
2012-01-04 16:28:07 +04:00
if ( ! ok ) {
goto fail ;
}
status = smbXcli_conn_samba_suicide_recv ( req ) ;
fail :
TALLOC_FREE ( frame ) ;
return status ;
}
2011-09-15 16:02:49 +04:00
uint32_t smb1cli_conn_capabilities ( struct smbXcli_conn * conn )
{
return conn - > smb1 . capabilities ;
}
uint32_t smb1cli_conn_max_xmit ( struct smbXcli_conn * conn )
{
return conn - > smb1 . max_xmit ;
}
2013-08-13 16:05:05 +04:00
bool smb1cli_conn_req_possible ( struct smbXcli_conn * conn )
{
2015-05-29 16:48:26 +03:00
size_t pending = talloc_array_length ( conn - > pending ) ;
2013-08-13 16:05:05 +04:00
uint16_t possible = conn - > smb1 . server . max_mux ;
if ( pending > = possible ) {
return false ;
}
return true ;
}
2011-09-15 16:02:49 +04:00
uint32_t smb1cli_conn_server_session_key ( struct smbXcli_conn * conn )
{
return conn - > smb1 . server . session_key ;
}
const uint8_t * smb1cli_conn_server_challenge ( struct smbXcli_conn * conn )
{
return conn - > smb1 . server . challenge ;
}
uint16_t smb1cli_conn_server_security_mode ( struct smbXcli_conn * conn )
{
return conn - > smb1 . server . security_mode ;
}
2011-11-25 18:13:38 +04:00
bool smb1cli_conn_server_readbraw ( struct smbXcli_conn * conn )
{
return conn - > smb1 . server . readbraw ;
}
bool smb1cli_conn_server_writebraw ( struct smbXcli_conn * conn )
{
return conn - > smb1 . server . writebraw ;
}
bool smb1cli_conn_server_lockread ( struct smbXcli_conn * conn )
{
return conn - > smb1 . server . lockread ;
}
bool smb1cli_conn_server_writeunlock ( struct smbXcli_conn * conn )
{
return conn - > smb1 . server . writeunlock ;
}
2011-09-15 16:02:49 +04:00
int smb1cli_conn_server_time_zone ( struct smbXcli_conn * conn )
{
return conn - > smb1 . server . time_zone ;
}
2011-08-11 15:29:59 +04:00
bool smb1cli_conn_activate_signing ( struct smbXcli_conn * conn ,
const DATA_BLOB user_session_key ,
const DATA_BLOB response )
{
2022-03-08 06:29:57 +03:00
return smb1_signing_activate ( conn - > smb1 . signing ,
2011-08-11 15:29:59 +04:00
user_session_key ,
response ) ;
}
bool smb1cli_conn_check_signing ( struct smbXcli_conn * conn ,
const uint8_t * buf , uint32_t seqnum )
{
2012-08-03 11:58:29 +04:00
const uint8_t * hdr = buf + NBT_HDR_SIZE ;
size_t len = smb_len_nbt ( buf ) ;
2022-03-08 06:26:54 +03:00
return smb1_signing_check_pdu ( conn - > smb1 . signing , hdr , len , seqnum ) ;
2011-08-11 15:29:59 +04:00
}
bool smb1cli_conn_signing_is_active ( struct smbXcli_conn * conn )
{
2022-03-08 06:31:34 +03:00
return smb1_signing_is_active ( conn - > smb1 . signing ) ;
2011-08-11 15:29:59 +04:00
}
void smb1cli_conn_set_encryption ( struct smbXcli_conn * conn ,
struct smb_trans_enc_state * es )
{
/* Replace the old state, if any. */
if ( conn - > smb1 . trans_enc ) {
2012-01-14 08:30:34 +04:00
TALLOC_FREE ( conn - > smb1 . trans_enc ) ;
2011-08-11 15:29:59 +04:00
}
conn - > smb1 . trans_enc = es ;
}
bool smb1cli_conn_encryption_on ( struct smbXcli_conn * conn )
{
return common_encryption_on ( conn - > smb1 . trans_enc ) ;
}
2011-11-16 14:14:16 +04:00
static NTSTATUS smb1cli_pull_raw_error ( const uint8_t * hdr )
2011-07-18 16:35:03 +04:00
{
uint32_t flags2 = SVAL ( hdr , HDR_FLG2 ) ;
NTSTATUS status = NT_STATUS ( IVAL ( hdr , HDR_RCLS ) ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
return NT_STATUS_OK ;
}
if ( flags2 & FLAGS2_32_BIT_ERROR_CODES ) {
return status ;
}
return NT_STATUS_DOS ( CVAL ( hdr , HDR_RCLS ) , SVAL ( hdr , HDR_ERR ) ) ;
}
2011-08-11 15:29:59 +04:00
/**
* Is the SMB command able to hold an AND_X successor
* @ param [ in ] cmd The SMB command in question
* @ retval Can we add a chained request after " cmd " ?
*/
bool smb1cli_is_andx_req ( uint8_t cmd )
{
switch ( cmd ) {
case SMBtconX :
case SMBlockingX :
case SMBopenX :
case SMBreadX :
case SMBwriteX :
case SMBsesssetupX :
case SMBulogoffX :
case SMBntcreateX :
return true ;
break ;
default :
break ;
}
2011-07-18 16:35:03 +04:00
2011-08-11 15:29:59 +04:00
return false ;
}
2011-07-18 16:35:03 +04:00
2011-08-11 15:29:59 +04:00
static uint16_t smb1cli_alloc_mid ( struct smbXcli_conn * conn )
2011-07-18 16:35:03 +04:00
{
2011-08-11 15:29:59 +04:00
size_t num_pending = talloc_array_length ( conn - > pending ) ;
2011-07-18 16:35:03 +04:00
uint16_t result ;
2013-09-17 06:09:03 +04:00
if ( conn - > protocol = = PROTOCOL_NONE ) {
/*
* This is what windows sends on the SMB1 Negprot request
* and some vendors reuse the SMB1 MID as SMB2 sequence number .
*/
return 0 ;
}
2011-07-18 16:35:03 +04:00
while ( true ) {
2011-08-11 15:29:59 +04:00
size_t i ;
2011-07-18 16:35:03 +04:00
2011-08-11 15:29:59 +04:00
result = conn - > smb1 . mid + + ;
2011-07-18 16:35:03 +04:00
if ( ( result = = 0 ) | | ( result = = 0xffff ) ) {
continue ;
}
for ( i = 0 ; i < num_pending ; i + + ) {
2011-08-11 15:29:59 +04:00
if ( result = = smb1cli_req_mid ( conn - > pending [ i ] ) ) {
2011-07-18 16:35:03 +04:00
break ;
}
}
if ( i = = num_pending ) {
return result ;
}
}
}
2016-09-15 12:46:33 +03:00
static NTSTATUS smbXcli_req_cancel_write_req ( struct tevent_req * req )
{
struct smbXcli_req_state * state =
tevent_req_data ( req ,
struct smbXcli_req_state ) ;
struct smbXcli_conn * conn = state - > conn ;
size_t num_pending = talloc_array_length ( conn - > pending ) ;
ssize_t ret ;
int err ;
bool ok ;
if ( state - > write_req = = NULL ) {
return NT_STATUS_OK ;
}
/*
* Check if it ' s possible to cancel the request .
2017-10-30 15:46:04 +03:00
* If the result is true it ' s not too late .
2016-09-15 12:46:33 +03:00
* See writev_cancel ( ) .
*/
ok = tevent_req_cancel ( state - > write_req ) ;
if ( ok ) {
TALLOC_FREE ( state - > write_req ) ;
if ( conn - > protocol > = PROTOCOL_SMB2_02 ) {
/*
* SMB2 has a sane signing state .
*/
return NT_STATUS_OK ;
}
if ( num_pending > 1 ) {
/*
* We have more pending requests following us . This
* means the signing state will be broken for them .
*
* As a solution we could add the requests directly to
* our outgoing queue and do the signing in the trigger
* function and then use writev_send ( ) without passing a
* queue . That way we ' ll only sign packets we ' re most
* likely send to the wire .
*/
return NT_STATUS_REQUEST_OUT_OF_SEQUENCE ;
}
/*
* If we ' re the only request that ' s
* pending , we ' re able to recover the signing
* state .
*/
2022-03-08 06:20:27 +03:00
smb1_signing_cancel_reply ( conn - > smb1 . signing ,
2016-09-15 12:46:33 +03:00
state - > smb1 . one_way_seqnum ) ;
return NT_STATUS_OK ;
}
ret = writev_recv ( state - > write_req , & err ) ;
TALLOC_FREE ( state - > write_req ) ;
if ( ret = = - 1 ) {
return map_nt_error_from_unix_common ( err ) ;
}
return NT_STATUS_OK ;
}
2011-08-11 15:29:59 +04:00
void smbXcli_req_unset_pending ( struct tevent_req * req )
2011-07-18 16:35:03 +04:00
{
2011-08-11 15:29:59 +04:00
struct smbXcli_req_state * state =
tevent_req_data ( req ,
struct smbXcli_req_state ) ;
struct smbXcli_conn * conn = state - > conn ;
size_t num_pending = talloc_array_length ( conn - > pending ) ;
size_t i ;
2016-09-15 12:46:33 +03:00
NTSTATUS cancel_status ;
2011-08-11 15:29:59 +04:00
2016-09-15 12:46:33 +03:00
cancel_status = smbXcli_req_cancel_write_req ( req ) ;
2015-05-29 17:14:40 +03:00
2011-08-11 15:29:59 +04:00
if ( state - > smb1 . mid ! = 0 ) {
2011-07-18 16:35:03 +04:00
/*
* This is a [ nt ] trans [ 2 ] request which waits
* for more than one reply .
*/
2016-09-15 12:46:33 +03:00
if ( ! NT_STATUS_IS_OK ( cancel_status ) ) {
/*
* If the write_req cancel didn ' t work
* we can ' t use the connection anymore .
*/
smbXcli_conn_disconnect ( conn , cancel_status ) ;
return ;
}
2011-07-18 16:35:03 +04:00
return ;
}
2014-01-08 13:31:15 +04:00
tevent_req_set_cleanup_fn ( req , NULL ) ;
2011-07-18 16:35:03 +04:00
if ( num_pending = = 1 ) {
/*
* The pending read_smb tevent_req is a child of
2011-08-11 15:29:59 +04:00
* conn - > pending . So if nothing is pending anymore , we need to
2011-07-18 16:35:03 +04:00
* delete the socket read fde .
*/
2016-09-15 12:46:33 +03:00
/* TODO: smbXcli_conn_cancel_read_req */
2011-08-11 15:29:59 +04:00
TALLOC_FREE ( conn - > pending ) ;
conn - > read_smb_req = NULL ;
2016-09-15 12:46:33 +03:00
if ( ! NT_STATUS_IS_OK ( cancel_status ) ) {
/*
* If the write_req cancel didn ' t work
* we can ' t use the connection anymore .
*/
smbXcli_conn_disconnect ( conn , cancel_status ) ;
return ;
}
2011-07-18 16:35:03 +04:00
return ;
}
for ( i = 0 ; i < num_pending ; i + + ) {
2011-08-11 15:29:59 +04:00
if ( req = = conn - > pending [ i ] ) {
2011-07-18 16:35:03 +04:00
break ;
}
}
if ( i = = num_pending ) {
/*
* Something ' s seriously broken . Just returning here is the
* right thing nevertheless , the point of this routine is to
2011-08-11 15:29:59 +04:00
* remove ourselves from conn - > pending .
2011-07-18 16:35:03 +04:00
*/
2016-09-15 12:46:33 +03:00
if ( ! NT_STATUS_IS_OK ( cancel_status ) ) {
/*
* If the write_req cancel didn ' t work
* we can ' t use the connection anymore .
*/
smbXcli_conn_disconnect ( conn , cancel_status ) ;
return ;
}
2011-07-18 16:35:03 +04:00
return ;
}
/*
2011-08-11 15:29:59 +04:00
* Remove ourselves from the conn - > pending array
2011-07-18 16:35:03 +04:00
*/
for ( ; i < ( num_pending - 1 ) ; i + + ) {
2011-08-11 15:29:59 +04:00
conn - > pending [ i ] = conn - > pending [ i + 1 ] ;
2011-07-18 16:35:03 +04:00
}
/*
* No NULL check here , we ' re shrinking by sizeof ( void * ) , and
* talloc_realloc just adjusts the size for this .
*/
2011-08-11 15:29:59 +04:00
conn - > pending = talloc_realloc ( NULL , conn - > pending , struct tevent_req * ,
num_pending - 1 ) ;
2016-09-15 12:46:33 +03:00
if ( ! NT_STATUS_IS_OK ( cancel_status ) ) {
/*
* If the write_req cancel didn ' t work
* we can ' t use the connection anymore .
*/
smbXcli_conn_disconnect ( conn , cancel_status ) ;
return ;
}
2011-07-18 16:35:03 +04:00
return ;
}
2014-01-08 13:31:15 +04:00
static void smbXcli_req_cleanup ( struct tevent_req * req ,
enum tevent_req_state req_state )
2011-07-18 16:35:03 +04:00
{
2011-08-11 15:29:59 +04:00
struct smbXcli_req_state * state =
tevent_req_data ( req ,
struct smbXcli_req_state ) ;
2016-09-15 12:46:33 +03:00
struct smbXcli_conn * conn = state - > conn ;
NTSTATUS cancel_status ;
2015-05-29 17:14:40 +03:00
2014-01-08 13:31:15 +04:00
switch ( req_state ) {
case TEVENT_REQ_RECEIVED :
/*
* Make sure we really remove it from
* the pending array on destruction .
2016-09-15 12:46:33 +03:00
*
* smbXcli_req_unset_pending ( ) calls
* smbXcli_req_cancel_write_req ( ) internal
2014-01-08 13:31:15 +04:00
*/
state - > smb1 . mid = 0 ;
smbXcli_req_unset_pending ( req ) ;
return ;
default :
2016-09-15 12:46:33 +03:00
cancel_status = smbXcli_req_cancel_write_req ( req ) ;
if ( ! NT_STATUS_IS_OK ( cancel_status ) ) {
/*
* If the write_req cancel didn ' t work
* we can ' t use the connection anymore .
*/
smbXcli_conn_disconnect ( conn , cancel_status ) ;
return ;
}
2014-01-08 13:31:15 +04:00
return ;
}
2011-07-18 16:35:03 +04:00
}
2011-09-24 08:06:46 +04:00
static bool smb1cli_req_cancel ( struct tevent_req * req ) ;
static bool smb2cli_req_cancel ( struct tevent_req * req ) ;
static bool smbXcli_req_cancel ( struct tevent_req * req )
{
struct smbXcli_req_state * state =
tevent_req_data ( req ,
struct smbXcli_req_state ) ;
if ( ! smbXcli_conn_is_connected ( state - > conn ) ) {
return false ;
}
if ( state - > conn - > protocol = = PROTOCOL_NONE ) {
return false ;
}
if ( state - > conn - > protocol > = PROTOCOL_SMB2_02 ) {
return smb2cli_req_cancel ( req ) ;
}
return smb1cli_req_cancel ( req ) ;
}
2011-08-11 15:29:59 +04:00
static bool smbXcli_conn_receive_next ( struct smbXcli_conn * conn ) ;
2011-07-18 16:35:03 +04:00
2011-08-11 15:29:59 +04:00
bool smbXcli_req_set_pending ( struct tevent_req * req )
2011-07-18 16:35:03 +04:00
{
2011-08-11 15:29:59 +04:00
struct smbXcli_req_state * state =
tevent_req_data ( req ,
struct smbXcli_req_state ) ;
struct smbXcli_conn * conn ;
2011-07-18 16:35:03 +04:00
struct tevent_req * * pending ;
2011-08-11 15:29:59 +04:00
size_t num_pending ;
2011-07-18 16:35:03 +04:00
2011-08-11 15:29:59 +04:00
conn = state - > conn ;
2011-07-18 16:35:03 +04:00
2011-08-11 15:29:59 +04:00
if ( ! smbXcli_conn_is_connected ( conn ) ) {
return false ;
}
num_pending = talloc_array_length ( conn - > pending ) ;
pending = talloc_realloc ( conn , conn - > pending , struct tevent_req * ,
2011-07-18 16:35:03 +04:00
num_pending + 1 ) ;
if ( pending = = NULL ) {
return false ;
}
pending [ num_pending ] = req ;
2011-08-11 15:29:59 +04:00
conn - > pending = pending ;
2014-01-08 13:31:15 +04:00
tevent_req_set_cleanup_fn ( req , smbXcli_req_cleanup ) ;
2011-09-24 08:06:46 +04:00
tevent_req_set_cancel_fn ( req , smbXcli_req_cancel ) ;
2011-07-18 16:35:03 +04:00
2011-08-11 15:29:59 +04:00
if ( ! smbXcli_conn_receive_next ( conn ) ) {
2011-07-18 16:35:03 +04:00
/*
* the caller should notify the current request
*
* And all other pending requests get notified
2011-08-11 15:29:59 +04:00
* by smbXcli_conn_disconnect ( ) .
2011-07-18 16:35:03 +04:00
*/
2011-08-11 15:29:59 +04:00
smbXcli_req_unset_pending ( req ) ;
smbXcli_conn_disconnect ( conn , NT_STATUS_NO_MEMORY ) ;
2011-07-18 16:35:03 +04:00
return false ;
}
return true ;
}
2011-08-11 15:29:59 +04:00
static void smbXcli_conn_received ( struct tevent_req * subreq ) ;
2011-07-18 16:35:03 +04:00
2011-08-11 15:29:59 +04:00
static bool smbXcli_conn_receive_next ( struct smbXcli_conn * conn )
2011-07-18 16:35:03 +04:00
{
2011-08-11 15:29:59 +04:00
size_t num_pending = talloc_array_length ( conn - > pending ) ;
2011-07-18 16:35:03 +04:00
struct tevent_req * req ;
2011-08-11 15:29:59 +04:00
struct smbXcli_req_state * state ;
2011-07-18 16:35:03 +04:00
2011-08-11 15:29:59 +04:00
if ( conn - > read_smb_req ! = NULL ) {
2011-07-18 16:35:03 +04:00
return true ;
}
if ( num_pending = = 0 ) {
2011-09-15 14:23:05 +04:00
if ( conn - > smb2 . mid < UINT64_MAX ) {
/* no more pending requests, so we are done for now */
return true ;
}
/*
* If there are no more SMB2 requests possible ,
* because we are out of message ids ,
* we need to disconnect .
*/
smbXcli_conn_disconnect ( conn , NT_STATUS_CONNECTION_ABORTED ) ;
2011-07-18 16:35:03 +04:00
return true ;
}
2011-08-11 15:29:59 +04:00
req = conn - > pending [ 0 ] ;
state = tevent_req_data ( req , struct smbXcli_req_state ) ;
2011-07-18 16:35:03 +04:00
/*
* We ' re the first ones , add the read_smb request that waits for the
* answer from the server
*/
2011-09-25 05:15:54 +04:00
conn - > read_smb_req = read_smb_send ( conn - > pending ,
state - > ev ,
2015-05-28 14:22:19 +03:00
conn - > sock_fd ) ;
2011-08-11 15:29:59 +04:00
if ( conn - > read_smb_req = = NULL ) {
2011-07-18 16:35:03 +04:00
return false ;
}
2011-08-11 15:29:59 +04:00
tevent_req_set_callback ( conn - > read_smb_req , smbXcli_conn_received , conn ) ;
2011-07-18 16:35:03 +04:00
return true ;
}
2011-08-11 15:29:59 +04:00
void smbXcli_conn_disconnect ( struct smbXcli_conn * conn , NTSTATUS status )
2011-07-18 16:35:03 +04:00
{
2012-07-26 03:54:33 +04:00
struct smbXcli_session * session ;
2015-05-28 14:22:19 +03:00
int sock_fd = conn - > sock_fd ;
2012-07-26 03:54:33 +04:00
2011-11-28 13:23:23 +04:00
tevent_queue_stop ( conn - > outgoing ) ;
2015-05-28 14:22:19 +03:00
conn - > sock_fd = - 1 ;
2011-07-18 16:35:03 +04:00
2012-07-26 03:54:33 +04:00
session = conn - > sessions ;
if ( talloc_array_length ( conn - > pending ) = = 0 ) {
/*
* if we do not have pending requests
* there is no need to update the channel_sequence
*/
session = NULL ;
}
for ( ; session ; session = session - > next ) {
smb2cli_session_increment_channel_sequence ( session ) ;
}
2015-05-29 16:29:31 +03:00
if ( conn - > suicide_req ! = NULL ) {
/*
* smbXcli_conn_samba_suicide_send ( )
* used tevent_req_defer_callback ( ) already .
*/
if ( ! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( conn - > suicide_req , status ) ;
}
conn - > suicide_req = NULL ;
}
2011-07-18 16:35:03 +04:00
/*
* Cancel all pending requests . We do not do a for - loop walking
2011-08-11 15:29:59 +04:00
* conn - > pending because that array changes in
* smbXcli_req_unset_pending .
2011-07-18 16:35:03 +04:00
*/
2019-07-10 13:22:49 +03:00
while ( conn - > pending ! = NULL & &
talloc_array_length ( conn - > pending ) > 0 ) {
2011-07-18 16:35:03 +04:00
struct tevent_req * req ;
2011-08-11 15:29:59 +04:00
struct smbXcli_req_state * state ;
2011-11-18 13:30:33 +04:00
struct tevent_req * * chain ;
size_t num_chained ;
size_t i ;
2011-07-18 16:35:03 +04:00
2011-08-11 15:29:59 +04:00
req = conn - > pending [ 0 ] ;
state = tevent_req_data ( req , struct smbXcli_req_state ) ;
2011-07-18 16:35:03 +04:00
2011-11-18 13:30:33 +04:00
if ( state - > smb1 . chained_requests = = NULL ) {
2016-09-15 12:46:33 +03:00
bool in_progress ;
2011-11-18 13:30:33 +04:00
/*
* We ' re dead . No point waiting for trans2
* replies .
*/
state - > smb1 . mid = 0 ;
2011-08-11 15:29:59 +04:00
2011-11-18 13:30:33 +04:00
smbXcli_req_unset_pending ( req ) ;
2011-07-18 16:35:03 +04:00
2011-11-18 13:30:33 +04:00
if ( NT_STATUS_IS_OK ( status ) ) {
/* do not notify the callers */
continue ;
}
2016-09-15 12:46:33 +03:00
in_progress = tevent_req_is_in_progress ( req ) ;
if ( ! in_progress ) {
/*
* already finished
*/
continue ;
}
2011-11-18 13:30:33 +04:00
/*
* we need to defer the callback , because we may notify
* more then one caller .
*/
tevent_req_defer_callback ( req , state - > ev ) ;
tevent_req_nterror ( req , status ) ;
2011-08-11 15:29:59 +04:00
continue ;
}
2011-07-18 16:35:03 +04:00
2011-11-18 13:30:33 +04:00
chain = talloc_move ( conn , & state - > smb1 . chained_requests ) ;
num_chained = talloc_array_length ( chain ) ;
for ( i = 0 ; i < num_chained ; i + + ) {
2016-09-15 12:46:33 +03:00
bool in_progress ;
2011-11-18 13:30:33 +04:00
req = chain [ i ] ;
state = tevent_req_data ( req , struct smbXcli_req_state ) ;
/*
* We ' re dead . No point waiting for trans2
* replies .
*/
state - > smb1 . mid = 0 ;
smbXcli_req_unset_pending ( req ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
/* do not notify the callers */
continue ;
}
2016-09-15 12:46:33 +03:00
in_progress = tevent_req_is_in_progress ( req ) ;
if ( ! in_progress ) {
/*
* already finished
*/
continue ;
}
2011-11-18 13:30:33 +04:00
/*
* we need to defer the callback , because we may notify
2011-11-21 15:12:53 +04:00
* more than one caller .
2011-11-18 13:30:33 +04:00
*/
tevent_req_defer_callback ( req , state - > ev ) ;
tevent_req_nterror ( req , status ) ;
}
TALLOC_FREE ( chain ) ;
2011-07-18 16:35:03 +04:00
}
2015-05-28 14:09:11 +03:00
2015-05-28 14:22:19 +03:00
if ( sock_fd ! = - 1 ) {
close ( sock_fd ) ;
2015-05-28 14:09:11 +03:00
}
2011-07-18 16:35:03 +04:00
}
/*
* Fetch a smb request ' s mid . Only valid after the request has been sent by
2011-08-11 15:29:59 +04:00
* smb1cli_req_send ( ) .
2011-07-18 16:35:03 +04:00
*/
2011-08-11 15:29:59 +04:00
uint16_t smb1cli_req_mid ( struct tevent_req * req )
2011-07-18 16:35:03 +04:00
{
2011-08-11 15:29:59 +04:00
struct smbXcli_req_state * state =
tevent_req_data ( req ,
struct smbXcli_req_state ) ;
2011-07-18 16:35:03 +04:00
2011-08-11 15:29:59 +04:00
if ( state - > smb1 . mid ! = 0 ) {
return state - > smb1 . mid ;
2011-07-18 16:35:03 +04:00
}
2011-08-11 15:29:59 +04:00
return SVAL ( state - > smb1 . hdr , HDR_MID ) ;
2011-07-18 16:35:03 +04:00
}
2011-08-11 15:29:59 +04:00
void smb1cli_req_set_mid ( struct tevent_req * req , uint16_t mid )
2011-07-18 16:35:03 +04:00
{
2011-08-11 15:29:59 +04:00
struct smbXcli_req_state * state =
tevent_req_data ( req ,
struct smbXcli_req_state ) ;
state - > smb1 . mid = mid ;
2011-07-18 16:35:03 +04:00
}
2011-08-11 15:29:59 +04:00
uint32_t smb1cli_req_seqnum ( struct tevent_req * req )
2011-07-18 16:35:03 +04:00
{
2011-08-11 15:29:59 +04:00
struct smbXcli_req_state * state =
tevent_req_data ( req ,
struct smbXcli_req_state ) ;
return state - > smb1 . seqnum ;
2011-07-18 16:35:03 +04:00
}
2011-08-11 15:29:59 +04:00
void smb1cli_req_set_seqnum ( struct tevent_req * req , uint32_t seqnum )
2011-07-18 16:35:03 +04:00
{
2011-08-11 15:29:59 +04:00
struct smbXcli_req_state * state =
tevent_req_data ( req ,
struct smbXcli_req_state ) ;
state - > smb1 . seqnum = seqnum ;
2011-07-18 16:35:03 +04:00
}
2011-08-11 15:29:59 +04:00
static size_t smbXcli_iov_len ( const struct iovec * iov , int count )
2011-07-18 16:35:03 +04:00
{
2015-02-17 23:16:45 +03:00
ssize_t ret = iov_buflen ( iov , count ) ;
/* Ignore the overflow case for now ... */
return ret ;
2011-07-18 16:35:03 +04:00
}
2011-09-07 21:07:51 +04:00
static void smb1cli_req_flags ( enum protocol_types protocol ,
uint32_t smb1_capabilities ,
uint8_t smb_command ,
uint8_t additional_flags ,
uint8_t clear_flags ,
uint8_t * _flags ,
uint16_t additional_flags2 ,
uint16_t clear_flags2 ,
uint16_t * _flags2 )
{
uint8_t flags = 0 ;
uint16_t flags2 = 0 ;
if ( protocol > = PROTOCOL_LANMAN1 ) {
flags | = FLAG_CASELESS_PATHNAMES ;
flags | = FLAG_CANONICAL_PATHNAMES ;
}
if ( protocol > = PROTOCOL_LANMAN2 ) {
flags2 | = FLAGS2_LONG_PATH_COMPONENTS ;
flags2 | = FLAGS2_EXTENDED_ATTRIBUTES ;
}
if ( protocol > = PROTOCOL_NT1 ) {
flags2 | = FLAGS2_IS_LONG_NAME ;
if ( smb1_capabilities & CAP_UNICODE ) {
flags2 | = FLAGS2_UNICODE_STRINGS ;
}
if ( smb1_capabilities & CAP_STATUS32 ) {
flags2 | = FLAGS2_32_BIT_ERROR_CODES ;
}
if ( smb1_capabilities & CAP_EXTENDED_SECURITY ) {
flags2 | = FLAGS2_EXTENDED_SECURITY ;
}
}
flags | = additional_flags ;
flags & = ~ clear_flags ;
flags2 | = additional_flags2 ;
flags2 & = ~ clear_flags2 ;
* _flags = flags ;
* _flags2 = flags2 ;
}
2011-09-24 08:06:46 +04:00
static void smb1cli_req_cancel_done ( struct tevent_req * subreq ) ;
static bool smb1cli_req_cancel ( struct tevent_req * req )
{
struct smbXcli_req_state * state =
tevent_req_data ( req ,
struct smbXcli_req_state ) ;
uint8_t flags ;
uint16_t flags2 ;
uint32_t pid ;
uint16_t mid ;
struct tevent_req * subreq ;
NTSTATUS status ;
flags = CVAL ( state - > smb1 . hdr , HDR_FLG ) ;
flags2 = SVAL ( state - > smb1 . hdr , HDR_FLG2 ) ;
pid = SVAL ( state - > smb1 . hdr , HDR_PID ) ;
pid | = SVAL ( state - > smb1 . hdr , HDR_PIDHIGH ) < < 16 ;
mid = SVAL ( state - > smb1 . hdr , HDR_MID ) ;
subreq = smb1cli_req_create ( state , state - > ev ,
state - > conn ,
SMBntcancel ,
flags , 0 ,
flags2 , 0 ,
0 , /* timeout */
2012-07-23 23:34:58 +04:00
pid ,
state - > tcon ,
2012-07-23 22:15:21 +04:00
state - > session ,
2011-09-24 08:06:46 +04:00
0 , NULL , /* vwv */
0 , NULL ) ; /* bytes */
if ( subreq = = NULL ) {
return false ;
}
smb1cli_req_set_mid ( subreq , mid ) ;
status = smb1cli_req_chain_submit ( & subreq , 1 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( subreq ) ;
return false ;
}
smb1cli_req_set_mid ( subreq , 0 ) ;
tevent_req_set_callback ( subreq , smb1cli_req_cancel_done , NULL ) ;
return true ;
}
static void smb1cli_req_cancel_done ( struct tevent_req * subreq )
{
/* we do not care about the result */
TALLOC_FREE ( subreq ) ;
}
2011-08-11 15:29:59 +04:00
struct tevent_req * smb1cli_req_create ( TALLOC_CTX * mem_ctx ,
2011-07-18 16:35:03 +04:00
struct tevent_context * ev ,
2011-08-11 15:29:59 +04:00
struct smbXcli_conn * conn ,
2011-07-18 16:35:03 +04:00
uint8_t smb_command ,
uint8_t additional_flags ,
2011-08-11 15:29:59 +04:00
uint8_t clear_flags ,
uint16_t additional_flags2 ,
uint16_t clear_flags2 ,
uint32_t timeout_msec ,
uint32_t pid ,
2012-07-23 23:34:58 +04:00
struct smbXcli_tcon * tcon ,
2012-07-23 22:15:21 +04:00
struct smbXcli_session * session ,
2011-07-18 16:35:03 +04:00
uint8_t wct , uint16_t * vwv ,
int iov_count ,
struct iovec * bytes_iov )
{
2011-08-11 15:29:59 +04:00
struct tevent_req * req ;
struct smbXcli_req_state * state ;
uint8_t flags = 0 ;
uint16_t flags2 = 0 ;
2012-07-23 22:15:21 +04:00
uint16_t uid = 0 ;
2012-07-23 23:34:58 +04:00
uint16_t tid = 0 ;
2015-02-17 23:18:37 +03:00
ssize_t num_bytes ;
2011-07-18 16:35:03 +04:00
if ( iov_count > MAX_SMB_IOV ) {
/*
* Should not happen : - )
*/
return NULL ;
}
2011-08-11 15:29:59 +04:00
req = tevent_req_create ( mem_ctx , & state ,
struct smbXcli_req_state ) ;
if ( req = = NULL ) {
2011-07-18 16:35:03 +04:00
return NULL ;
}
state - > ev = ev ;
2011-08-11 15:29:59 +04:00
state - > conn = conn ;
2012-07-23 22:15:21 +04:00
state - > session = session ;
2012-07-23 23:34:58 +04:00
state - > tcon = tcon ;
2012-07-23 22:15:21 +04:00
if ( session ) {
uid = session - > smb1 . session_id ;
}
2011-07-18 16:35:03 +04:00
2012-07-23 23:34:58 +04:00
if ( tcon ) {
tid = tcon - > smb1 . tcon_id ;
2013-09-18 05:31:33 +04:00
2013-09-27 07:31:07 +04:00
if ( tcon - > fs_attributes & FILE_CASE_SENSITIVE_SEARCH ) {
clear_flags | = FLAG_CASELESS_PATHNAMES ;
} else {
/* Default setting, case insensitive. */
additional_flags | = FLAG_CASELESS_PATHNAMES ;
}
2013-09-18 05:31:33 +04:00
if ( smbXcli_conn_dfs_supported ( conn ) & &
smbXcli_tcon_is_dfs_share ( tcon ) )
{
additional_flags2 | = FLAGS2_DFS_PATHNAMES ;
}
2012-07-23 23:34:58 +04:00
}
2011-11-16 14:11:18 +04:00
state - > smb1 . recv_cmd = 0xFF ;
state - > smb1 . recv_status = NT_STATUS_INTERNAL_ERROR ;
state - > smb1 . recv_iov = talloc_zero_array ( state , struct iovec , 3 ) ;
if ( state - > smb1 . recv_iov = = NULL ) {
TALLOC_FREE ( req ) ;
return NULL ;
}
2011-09-07 21:07:51 +04:00
smb1cli_req_flags ( conn - > protocol ,
conn - > smb1 . capabilities ,
smb_command ,
additional_flags ,
clear_flags ,
& flags ,
additional_flags2 ,
clear_flags2 ,
& flags2 ) ;
2011-08-11 15:29:59 +04:00
SIVAL ( state - > smb1 . hdr , 0 , SMB_MAGIC ) ;
SCVAL ( state - > smb1 . hdr , HDR_COM , smb_command ) ;
SIVAL ( state - > smb1 . hdr , HDR_RCLS , NT_STATUS_V ( NT_STATUS_OK ) ) ;
SCVAL ( state - > smb1 . hdr , HDR_FLG , flags ) ;
SSVAL ( state - > smb1 . hdr , HDR_FLG2 , flags2 ) ;
SSVAL ( state - > smb1 . hdr , HDR_PIDHIGH , pid > > 16 ) ;
SSVAL ( state - > smb1 . hdr , HDR_TID , tid ) ;
SSVAL ( state - > smb1 . hdr , HDR_PID , pid ) ;
SSVAL ( state - > smb1 . hdr , HDR_UID , uid ) ;
SSVAL ( state - > smb1 . hdr , HDR_MID , 0 ) ; /* this comes later */
2011-11-28 17:50:03 +04:00
SCVAL ( state - > smb1 . hdr , HDR_WCT , wct ) ;
2011-08-11 15:29:59 +04:00
state - > smb1 . vwv = vwv ;
2015-02-17 23:18:37 +03:00
num_bytes = iov_buflen ( bytes_iov , iov_count ) ;
if ( num_bytes = = - 1 ) {
/*
* I ' d love to add a check for num_bytes < = UINT16_MAX here , but
* the smbclient - > samba connections can lie and transfer more .
*/
TALLOC_FREE ( req ) ;
return NULL ;
}
SSVAL ( state - > smb1 . bytecount_buf , 0 , num_bytes ) ;
2011-08-11 15:29:59 +04:00
state - > smb1 . iov [ 0 ] . iov_base = ( void * ) state - > length_hdr ;
state - > smb1 . iov [ 0 ] . iov_len = sizeof ( state - > length_hdr ) ;
state - > smb1 . iov [ 1 ] . iov_base = ( void * ) state - > smb1 . hdr ;
state - > smb1 . iov [ 1 ] . iov_len = sizeof ( state - > smb1 . hdr ) ;
state - > smb1 . iov [ 2 ] . iov_base = ( void * ) state - > smb1 . vwv ;
state - > smb1 . iov [ 2 ] . iov_len = wct * sizeof ( uint16_t ) ;
state - > smb1 . iov [ 3 ] . iov_base = ( void * ) state - > smb1 . bytecount_buf ;
state - > smb1 . iov [ 3 ] . iov_len = sizeof ( uint16_t ) ;
2011-07-18 16:35:03 +04:00
if ( iov_count ! = 0 ) {
2011-08-11 15:29:59 +04:00
memcpy ( & state - > smb1 . iov [ 4 ] , bytes_iov ,
2011-07-18 16:35:03 +04:00
iov_count * sizeof ( * bytes_iov ) ) ;
}
2011-08-11 15:29:59 +04:00
state - > smb1 . iov_count = iov_count + 4 ;
2011-07-18 16:35:03 +04:00
2011-08-11 15:29:59 +04:00
if ( timeout_msec > 0 ) {
2018-10-28 04:04:51 +03:00
state - > endtime = timeval_current_ofs_msec ( timeout_msec ) ;
if ( ! tevent_req_set_endtime ( req , ev , state - > endtime ) ) {
2011-08-11 15:29:59 +04:00
return req ;
2011-07-18 16:35:03 +04:00
}
}
switch ( smb_command ) {
case SMBtranss :
case SMBtranss2 :
case SMBnttranss :
2011-11-18 12:24:11 +04:00
state - > one_way = true ;
break ;
2011-07-18 16:35:03 +04:00
case SMBntcancel :
state - > one_way = true ;
2011-11-18 12:24:11 +04:00
state - > smb1 . one_way_seqnum = true ;
2011-07-18 16:35:03 +04:00
break ;
case SMBlockingX :
if ( ( wct = = 8 ) & &
( CVAL ( vwv + 3 , 0 ) = = LOCKING_ANDX_OPLOCK_RELEASE ) ) {
state - > one_way = true ;
}
break ;
}
2011-08-11 15:29:59 +04:00
return req ;
2011-07-18 16:35:03 +04:00
}
2011-08-11 15:29:59 +04:00
static NTSTATUS smb1cli_conn_signv ( struct smbXcli_conn * conn ,
struct iovec * iov , int iov_count ,
2011-11-18 12:24:11 +04:00
uint32_t * seqnum ,
bool one_way_seqnum )
2011-07-18 16:35:03 +04:00
{
2011-11-25 16:12:35 +04:00
TALLOC_CTX * frame = NULL ;
2019-04-11 11:19:16 +03:00
NTSTATUS status ;
2011-07-18 16:35:03 +04:00
uint8_t * buf ;
/*
* Obvious optimization : Make cli_calculate_sign_mac work with struct
* iovec directly . MD5Update would do that just fine .
*/
2011-08-11 15:29:59 +04:00
if ( iov_count < 4 ) {
return NT_STATUS_INVALID_PARAMETER_MIX ;
}
if ( iov [ 0 ] . iov_len ! = NBT_HDR_SIZE ) {
return NT_STATUS_INVALID_PARAMETER_MIX ;
}
if ( iov [ 1 ] . iov_len ! = ( MIN_SMB_SIZE - sizeof ( uint16_t ) ) ) {
return NT_STATUS_INVALID_PARAMETER_MIX ;
}
if ( iov [ 2 ] . iov_len > ( 0xFF * sizeof ( uint16_t ) ) ) {
return NT_STATUS_INVALID_PARAMETER_MIX ;
}
if ( iov [ 3 ] . iov_len ! = sizeof ( uint16_t ) ) {
return NT_STATUS_INVALID_PARAMETER_MIX ;
2011-07-18 16:35:03 +04:00
}
2011-11-25 16:12:35 +04:00
frame = talloc_stackframe ( ) ;
2017-02-22 19:21:15 +03:00
buf = iov_concat ( frame , & iov [ 1 ] , iov_count - 1 ) ;
2011-07-18 16:35:03 +04:00
if ( buf = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2022-03-08 06:18:39 +03:00
* seqnum = smb1_signing_next_seqnum ( conn - > smb1 . signing ,
2011-11-18 12:24:11 +04:00
one_way_seqnum ) ;
2022-03-08 06:22:51 +03:00
status = smb1_signing_sign_pdu ( conn - > smb1 . signing ,
2019-04-11 11:19:16 +03:00
buf ,
talloc_get_size ( buf ) ,
* seqnum ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2012-08-03 11:58:29 +04:00
memcpy ( iov [ 1 ] . iov_base , buf , iov [ 1 ] . iov_len ) ;
2011-07-18 16:35:03 +04:00
2011-11-25 16:12:35 +04:00
TALLOC_FREE ( frame ) ;
2011-07-18 16:35:03 +04:00
return NT_STATUS_OK ;
}
2011-08-11 15:29:59 +04:00
static void smb1cli_req_writev_done ( struct tevent_req * subreq ) ;
static NTSTATUS smb1cli_conn_dispatch_incoming ( struct smbXcli_conn * conn ,
TALLOC_CTX * tmp_mem ,
uint8_t * inbuf ) ;
2011-07-18 16:35:03 +04:00
2011-08-11 15:29:59 +04:00
static NTSTATUS smb1cli_req_writev_submit ( struct tevent_req * req ,
struct smbXcli_req_state * state ,
struct iovec * iov , int iov_count )
2011-07-18 16:35:03 +04:00
{
struct tevent_req * subreq ;
NTSTATUS status ;
2011-11-25 17:49:24 +04:00
uint8_t cmd ;
2011-08-11 15:29:59 +04:00
uint16_t mid ;
2015-02-17 23:19:10 +03:00
ssize_t nbtlen ;
2011-07-18 16:35:03 +04:00
2011-08-11 15:29:59 +04:00
if ( ! smbXcli_conn_is_connected ( state - > conn ) ) {
2011-07-18 16:35:03 +04:00
return NT_STATUS_CONNECTION_DISCONNECTED ;
}
2011-08-11 15:29:59 +04:00
if ( state - > conn - > protocol > PROTOCOL_NT1 ) {
2017-08-16 23:27:15 +03:00
DBG_ERR ( " called for dialect[%s] server[%s] \n " ,
smb_protocol_types_string ( state - > conn - > protocol ) ,
smbXcli_conn_remote_name ( state - > conn ) ) ;
2011-08-11 15:29:59 +04:00
return NT_STATUS_REVISION_MISMATCH ;
}
if ( iov_count < 4 ) {
return NT_STATUS_INVALID_PARAMETER_MIX ;
}
if ( iov [ 0 ] . iov_len ! = NBT_HDR_SIZE ) {
return NT_STATUS_INVALID_PARAMETER_MIX ;
}
if ( iov [ 1 ] . iov_len ! = ( MIN_SMB_SIZE - sizeof ( uint16_t ) ) ) {
return NT_STATUS_INVALID_PARAMETER_MIX ;
}
if ( iov [ 2 ] . iov_len > ( 0xFF * sizeof ( uint16_t ) ) ) {
return NT_STATUS_INVALID_PARAMETER_MIX ;
}
if ( iov [ 3 ] . iov_len ! = sizeof ( uint16_t ) ) {
return NT_STATUS_INVALID_PARAMETER_MIX ;
2011-07-18 16:35:03 +04:00
}
2011-11-25 17:49:24 +04:00
cmd = CVAL ( iov [ 1 ] . iov_base , HDR_COM ) ;
if ( cmd = = SMBreadBraw ) {
if ( smbXcli_conn_has_async_calls ( state - > conn ) ) {
return NT_STATUS_INVALID_PARAMETER_MIX ;
}
state - > conn - > smb1 . read_braw_req = req ;
}
2011-08-11 15:29:59 +04:00
if ( state - > smb1 . mid ! = 0 ) {
mid = state - > smb1 . mid ;
2011-07-18 16:35:03 +04:00
} else {
2011-08-11 15:29:59 +04:00
mid = smb1cli_alloc_mid ( state - > conn ) ;
2011-07-18 16:35:03 +04:00
}
2011-08-11 15:29:59 +04:00
SSVAL ( iov [ 1 ] . iov_base , HDR_MID , mid ) ;
2011-07-18 16:35:03 +04:00
2015-02-17 23:19:10 +03:00
nbtlen = iov_buflen ( & iov [ 1 ] , iov_count - 1 ) ;
if ( ( nbtlen = = - 1 ) | | ( nbtlen > 0x1FFFF ) ) {
return NT_STATUS_INVALID_PARAMETER_MIX ;
}
_smb_setlen_nbt ( iov [ 0 ] . iov_base , nbtlen ) ;
2011-07-18 16:35:03 +04:00
2011-08-11 15:29:59 +04:00
status = smb1cli_conn_signv ( state - > conn , iov , iov_count ,
2011-11-18 12:24:11 +04:00
& state - > smb1 . seqnum ,
state - > smb1 . one_way_seqnum ) ;
2011-07-18 16:35:03 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2011-08-11 15:29:59 +04:00
/*
2022-04-01 10:07:47 +03:00
* If we supported multiple encryption contexts
2011-08-11 15:29:59 +04:00
* here we ' d look up based on tid .
*/
if ( common_encryption_on ( state - > conn - > smb1 . trans_enc ) ) {
2011-07-18 16:35:03 +04:00
char * buf , * enc_buf ;
2017-02-22 19:21:15 +03:00
buf = ( char * ) iov_concat ( talloc_tos ( ) , iov , iov_count ) ;
2011-07-18 16:35:03 +04:00
if ( buf = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2011-08-11 15:29:59 +04:00
status = common_encrypt_buffer ( state - > conn - > smb1 . trans_enc ,
2011-07-18 16:35:03 +04:00
( char * ) buf , & enc_buf ) ;
TALLOC_FREE ( buf ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Error in encrypting client message: %s \n " ,
nt_errstr ( status ) ) ) ;
return status ;
}
buf = ( char * ) talloc_memdup ( state , enc_buf ,
smb_len_nbt ( enc_buf ) + 4 ) ;
SAFE_FREE ( enc_buf ) ;
if ( buf = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
iov [ 0 ] . iov_base = ( void * ) buf ;
iov [ 0 ] . iov_len = talloc_get_size ( buf ) ;
iov_count = 1 ;
}
2011-08-11 15:29:59 +04:00
if ( state - > conn - > dispatch_incoming = = NULL ) {
state - > conn - > dispatch_incoming = smb1cli_conn_dispatch_incoming ;
}
2015-05-29 16:48:26 +03:00
if ( ! smbXcli_req_set_pending ( req ) ) {
return NT_STATUS_NO_MEMORY ;
}
2011-09-24 08:06:46 +04:00
tevent_req_set_cancel_fn ( req , smbXcli_req_cancel ) ;
2011-08-11 15:29:59 +04:00
subreq = writev_send ( state , state - > ev , state - > conn - > outgoing ,
2015-05-28 14:22:19 +03:00
state - > conn - > sock_fd , false , iov , iov_count ) ;
2011-07-18 16:35:03 +04:00
if ( subreq = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2011-08-11 15:29:59 +04:00
tevent_req_set_callback ( subreq , smb1cli_req_writev_done , req ) ;
2015-05-29 17:14:40 +03:00
state - > write_req = subreq ;
2011-07-18 16:35:03 +04:00
return NT_STATUS_OK ;
}
2011-08-11 15:29:59 +04:00
struct tevent_req * smb1cli_req_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct smbXcli_conn * conn ,
uint8_t smb_command ,
uint8_t additional_flags ,
uint8_t clear_flags ,
uint16_t additional_flags2 ,
uint16_t clear_flags2 ,
uint32_t timeout_msec ,
uint32_t pid ,
2012-07-23 23:34:58 +04:00
struct smbXcli_tcon * tcon ,
2012-07-23 22:15:21 +04:00
struct smbXcli_session * session ,
2011-08-11 15:29:59 +04:00
uint8_t wct , uint16_t * vwv ,
uint32_t num_bytes ,
const uint8_t * bytes )
2011-07-18 16:35:03 +04:00
{
struct tevent_req * req ;
struct iovec iov ;
NTSTATUS status ;
iov . iov_base = discard_const_p ( void , bytes ) ;
iov . iov_len = num_bytes ;
2011-08-11 15:29:59 +04:00
req = smb1cli_req_create ( mem_ctx , ev , conn , smb_command ,
additional_flags , clear_flags ,
additional_flags2 , clear_flags2 ,
timeout_msec ,
2012-07-23 23:34:58 +04:00
pid , tcon , session ,
2011-08-11 15:29:59 +04:00
wct , vwv , 1 , & iov ) ;
2011-07-18 16:35:03 +04:00
if ( req = = NULL ) {
return NULL ;
}
if ( ! tevent_req_is_in_progress ( req ) ) {
return tevent_req_post ( req , ev ) ;
}
2011-08-11 15:29:59 +04:00
status = smb1cli_req_chain_submit ( & req , 1 ) ;
if ( tevent_req_nterror ( req , status ) ) {
2011-07-18 16:35:03 +04:00
return tevent_req_post ( req , ev ) ;
}
return req ;
}
2011-08-11 15:29:59 +04:00
static void smb1cli_req_writev_done ( struct tevent_req * subreq )
2011-07-18 16:35:03 +04:00
{
2011-08-11 15:29:59 +04:00
struct tevent_req * req =
tevent_req_callback_data ( subreq ,
struct tevent_req ) ;
struct smbXcli_req_state * state =
tevent_req_data ( req ,
struct smbXcli_req_state ) ;
2011-07-18 16:35:03 +04:00
ssize_t nwritten ;
int err ;
2015-05-29 17:14:40 +03:00
state - > write_req = NULL ;
2011-07-18 16:35:03 +04:00
nwritten = writev_recv ( subreq , & err ) ;
TALLOC_FREE ( subreq ) ;
if ( nwritten = = - 1 ) {
2015-05-29 16:48:26 +03:00
/* here, we need to notify all pending requests */
2011-07-18 16:35:03 +04:00
NTSTATUS status = map_nt_error_from_unix_common ( err ) ;
2011-08-11 15:29:59 +04:00
smbXcli_conn_disconnect ( state - > conn , status ) ;
2011-07-18 16:35:03 +04:00
return ;
}
if ( state - > one_way ) {
state - > inbuf = NULL ;
tevent_req_done ( req ) ;
return ;
}
}
2011-08-11 15:29:59 +04:00
static void smbXcli_conn_received ( struct tevent_req * subreq )
2011-07-18 16:35:03 +04:00
{
2011-08-11 15:29:59 +04:00
struct smbXcli_conn * conn =
tevent_req_callback_data ( subreq ,
struct smbXcli_conn ) ;
2011-07-18 16:35:03 +04:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
NTSTATUS status ;
uint8_t * inbuf ;
ssize_t received ;
int err ;
2011-08-11 15:29:59 +04:00
if ( subreq ! = conn - > read_smb_req ) {
2011-07-18 16:35:03 +04:00
DEBUG ( 1 , ( " Internal error: cli_smb_received called with "
" unexpected subreq \n " ) ) ;
2013-06-09 20:02:27 +04:00
smbXcli_conn_disconnect ( conn , NT_STATUS_INTERNAL_ERROR ) ;
2011-07-18 16:35:03 +04:00
TALLOC_FREE ( frame ) ;
return ;
}
2011-08-11 15:29:59 +04:00
conn - > read_smb_req = NULL ;
2011-07-18 16:35:03 +04:00
received = read_smb_recv ( subreq , frame , & inbuf , & err ) ;
TALLOC_FREE ( subreq ) ;
if ( received = = - 1 ) {
status = map_nt_error_from_unix_common ( err ) ;
2011-08-11 15:29:59 +04:00
smbXcli_conn_disconnect ( conn , status ) ;
2011-07-18 16:35:03 +04:00
TALLOC_FREE ( frame ) ;
return ;
}
2011-08-11 15:29:59 +04:00
status = conn - > dispatch_incoming ( conn , frame , inbuf ) ;
2011-07-18 16:35:03 +04:00
TALLOC_FREE ( frame ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
/*
* We should not do any more processing
* as the dispatch function called
* tevent_req_done ( ) .
*/
return ;
2013-06-09 13:41:32 +04:00
}
if ( ! NT_STATUS_EQUAL ( status , NT_STATUS_RETRY ) ) {
2011-07-18 16:35:03 +04:00
/*
* We got an error , so notify all pending requests
*/
2011-08-11 15:29:59 +04:00
smbXcli_conn_disconnect ( conn , status ) ;
2011-07-18 16:35:03 +04:00
return ;
}
/*
* We got NT_STATUS_RETRY , so we may ask for a
* next incoming pdu .
*/
2011-08-11 15:29:59 +04:00
if ( ! smbXcli_conn_receive_next ( conn ) ) {
smbXcli_conn_disconnect ( conn , NT_STATUS_NO_MEMORY ) ;
2011-07-18 16:35:03 +04:00
}
}
2011-11-16 14:20:15 +04:00
static NTSTATUS smb1cli_inbuf_parse_chain ( uint8_t * buf , TALLOC_CTX * mem_ctx ,
struct iovec * * piov , int * pnum_iov )
{
struct iovec * iov ;
2017-12-07 19:01:39 +03:00
size_t num_iov ;
2011-11-16 14:20:15 +04:00
size_t buflen ;
size_t taken ;
size_t remaining ;
uint8_t * hdr ;
uint8_t cmd ;
uint32_t wct_ofs ;
2012-08-16 08:55:36 +04:00
NTSTATUS status ;
size_t min_size = MIN_SMB_SIZE ;
2011-11-16 14:20:15 +04:00
2013-03-14 02:23:52 +04:00
buflen = smb_len_tcp ( buf ) ;
2011-11-16 14:20:15 +04:00
taken = 0 ;
hdr = buf + NBT_HDR_SIZE ;
2012-08-16 08:55:36 +04:00
status = smb1cli_pull_raw_error ( hdr ) ;
if ( NT_STATUS_IS_ERR ( status ) ) {
/*
* This is an ugly hack to support OS / 2
* which skips the byte_count in the DATA block
* on some error responses .
*
* See bug # 9096
*/
min_size - = sizeof ( uint16_t ) ;
}
if ( buflen < min_size ) {
2011-11-16 14:20:15 +04:00
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
/*
* This returns iovec elements in the following order :
*
* - SMB header
*
* - Parameter Block
* - Data Block
*
* - Parameter Block
* - Data Block
*
* - Parameter Block
* - Data Block
*/
num_iov = 1 ;
iov = talloc_array ( mem_ctx , struct iovec , num_iov ) ;
if ( iov = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
iov [ 0 ] . iov_base = hdr ;
iov [ 0 ] . iov_len = HDR_WCT ;
taken + = HDR_WCT ;
cmd = CVAL ( hdr , HDR_COM ) ;
wct_ofs = HDR_WCT ;
while ( true ) {
size_t len = buflen - taken ;
struct iovec * cur ;
struct iovec * iov_tmp ;
uint8_t wct ;
uint32_t bcc_ofs ;
uint16_t bcc ;
size_t needed ;
/*
2012-08-16 08:55:36 +04:00
* we need at least WCT
2011-11-16 14:20:15 +04:00
*/
2012-08-16 08:55:36 +04:00
needed = sizeof ( uint8_t ) ;
2011-11-16 14:20:15 +04:00
if ( len < needed ) {
DEBUG ( 10 , ( " %s: %d bytes left, expected at least %d \n " ,
__location__ , ( int ) len , ( int ) needed ) ) ;
goto inval ;
}
/*
* Now we check if the specified words are there
*/
wct = CVAL ( hdr , wct_ofs ) ;
needed + = wct * sizeof ( uint16_t ) ;
if ( len < needed ) {
DEBUG ( 10 , ( " %s: %d bytes left, expected at least %d \n " ,
__location__ , ( int ) len , ( int ) needed ) ) ;
goto inval ;
}
2012-08-16 08:55:36 +04:00
if ( ( num_iov = = 1 ) & &
( len = = needed ) & &
NT_STATUS_IS_ERR ( status ) )
{
/*
* This is an ugly hack to support OS / 2
* which skips the byte_count in the DATA block
* on some error responses .
*
* See bug # 9096
*/
iov_tmp = talloc_realloc ( mem_ctx , iov , struct iovec ,
num_iov + 2 ) ;
if ( iov_tmp = = NULL ) {
TALLOC_FREE ( iov ) ;
return NT_STATUS_NO_MEMORY ;
}
iov = iov_tmp ;
cur = & iov [ num_iov ] ;
num_iov + = 2 ;
cur [ 0 ] . iov_len = 0 ;
cur [ 0 ] . iov_base = hdr + ( wct_ofs + sizeof ( uint8_t ) ) ;
cur [ 1 ] . iov_len = 0 ;
cur [ 1 ] . iov_base = cur [ 0 ] . iov_base ;
taken + = needed ;
break ;
}
/*
* we need at least BCC
*/
needed + = sizeof ( uint16_t ) ;
if ( len < needed ) {
DEBUG ( 10 , ( " %s: %d bytes left, expected at least %d \n " ,
__location__ , ( int ) len , ( int ) needed ) ) ;
goto inval ;
}
2011-11-16 14:20:15 +04:00
/*
* Now we check if the specified bytes are there
*/
bcc_ofs = wct_ofs + sizeof ( uint8_t ) + wct * sizeof ( uint16_t ) ;
bcc = SVAL ( hdr , bcc_ofs ) ;
needed + = bcc * sizeof ( uint8_t ) ;
if ( len < needed ) {
DEBUG ( 10 , ( " %s: %d bytes left, expected at least %d \n " ,
__location__ , ( int ) len , ( int ) needed ) ) ;
goto inval ;
}
/*
* we allocate 2 iovec structures for words and bytes
*/
iov_tmp = talloc_realloc ( mem_ctx , iov , struct iovec ,
num_iov + 2 ) ;
if ( iov_tmp = = NULL ) {
TALLOC_FREE ( iov ) ;
return NT_STATUS_NO_MEMORY ;
}
iov = iov_tmp ;
cur = & iov [ num_iov ] ;
num_iov + = 2 ;
cur [ 0 ] . iov_len = wct * sizeof ( uint16_t ) ;
cur [ 0 ] . iov_base = hdr + ( wct_ofs + sizeof ( uint8_t ) ) ;
cur [ 1 ] . iov_len = bcc * sizeof ( uint8_t ) ;
cur [ 1 ] . iov_base = hdr + ( bcc_ofs + sizeof ( uint16_t ) ) ;
taken + = needed ;
if ( ! smb1cli_is_andx_req ( cmd ) ) {
/*
* If the current command does not have AndX chanining
* we are done .
*/
break ;
}
if ( wct = = 0 & & bcc = = 0 ) {
/*
* An empty response also ends the chain ,
* most likely with an error .
*/
break ;
}
if ( wct < 2 ) {
DEBUG ( 10 , ( " %s: wct[%d] < 2 for cmd[0x%02X] \n " ,
__location__ , ( int ) wct , ( int ) cmd ) ) ;
goto inval ;
}
cmd = CVAL ( cur [ 0 ] . iov_base , 0 ) ;
if ( cmd = = 0xFF ) {
/*
* If it is the end of the chain we are also done .
*/
break ;
}
wct_ofs = SVAL ( cur [ 0 ] . iov_base , 2 ) ;
if ( wct_ofs < taken ) {
2018-03-30 21:10:14 +03:00
goto inval ;
2011-11-16 14:20:15 +04:00
}
if ( wct_ofs > buflen ) {
2018-03-30 21:10:14 +03:00
goto inval ;
2011-11-16 14:20:15 +04:00
}
/*
* we consumed everything up to the start of the next
* parameter block .
*/
taken = wct_ofs ;
}
remaining = buflen - taken ;
if ( remaining > 0 & & num_iov > = 3 ) {
/*
* The last DATA block gets the remaining
* bytes , this is needed to support
* CAP_LARGE_WRITEX and CAP_LARGE_READX .
*/
iov [ num_iov - 1 ] . iov_len + = remaining ;
}
* piov = iov ;
* pnum_iov = num_iov ;
return NT_STATUS_OK ;
inval :
TALLOC_FREE ( iov ) ;
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
2011-08-11 15:29:59 +04:00
static NTSTATUS smb1cli_conn_dispatch_incoming ( struct smbXcli_conn * conn ,
TALLOC_CTX * tmp_mem ,
uint8_t * inbuf )
2011-07-18 16:35:03 +04:00
{
struct tevent_req * req ;
2011-08-11 15:29:59 +04:00
struct smbXcli_req_state * state ;
2011-07-18 16:35:03 +04:00
NTSTATUS status ;
2011-08-11 15:29:59 +04:00
size_t num_pending ;
size_t i ;
2011-11-16 14:35:50 +04:00
uint8_t cmd ;
2011-07-18 16:35:03 +04:00
uint16_t mid ;
bool oplock_break ;
2012-08-03 11:58:29 +04:00
uint8_t * inhdr = inbuf + NBT_HDR_SIZE ;
2013-03-14 02:23:52 +04:00
size_t len = smb_len_tcp ( inbuf ) ;
2011-11-16 14:35:50 +04:00
struct iovec * iov = NULL ;
int num_iov = 0 ;
2011-11-21 16:08:58 +04:00
struct tevent_req * * chain = NULL ;
size_t num_chained = 0 ;
size_t num_responses = 0 ;
2011-07-18 16:35:03 +04:00
2011-11-25 17:49:24 +04:00
if ( conn - > smb1 . read_braw_req ! = NULL ) {
req = conn - > smb1 . read_braw_req ;
conn - > smb1 . read_braw_req = NULL ;
state = tevent_req_data ( req , struct smbXcli_req_state ) ;
smbXcli_req_unset_pending ( req ) ;
if ( state - > smb1 . recv_iov = = NULL ) {
/*
* For requests with more than
* one response , we have to readd the
* recv_iov array .
*/
state - > smb1 . recv_iov = talloc_zero_array ( state ,
struct iovec ,
3 ) ;
if ( tevent_req_nomem ( state - > smb1 . recv_iov , req ) ) {
return NT_STATUS_OK ;
}
}
2012-08-03 11:58:29 +04:00
state - > smb1 . recv_iov [ 0 ] . iov_base = ( void * ) ( inhdr ) ;
state - > smb1 . recv_iov [ 0 ] . iov_len = len ;
2011-11-25 17:49:24 +04:00
ZERO_STRUCT ( state - > smb1 . recv_iov [ 1 ] ) ;
ZERO_STRUCT ( state - > smb1 . recv_iov [ 2 ] ) ;
state - > smb1 . recv_cmd = SMBreadBraw ;
state - > smb1 . recv_status = NT_STATUS_OK ;
state - > inbuf = talloc_move ( state - > smb1 . recv_iov , & inbuf ) ;
tevent_req_done ( req ) ;
return NT_STATUS_OK ;
}
2011-07-18 16:35:03 +04:00
if ( ( IVAL ( inhdr , 0 ) ! = SMB_MAGIC ) /* 0xFF"SMB" */
& & ( SVAL ( inhdr , 0 ) ! = 0x45ff ) ) /* 0xFF"E" */ {
DEBUG ( 10 , ( " Got non-SMB PDU \n " ) ) ;
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
2011-08-11 15:29:59 +04:00
/*
2022-04-01 10:07:47 +03:00
* If we supported multiple encryption contexts
2011-08-11 15:29:59 +04:00
* here we ' d look up based on tid .
*/
if ( common_encryption_on ( conn - > smb1 . trans_enc )
& & ( CVAL ( inbuf , 0 ) = = 0 ) ) {
2011-07-18 16:35:03 +04:00
uint16_t enc_ctx_num ;
status = get_enc_ctx_num ( inbuf , & enc_ctx_num ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " get_enc_ctx_num returned %s \n " ,
nt_errstr ( status ) ) ) ;
return status ;
}
2011-08-11 15:29:59 +04:00
if ( enc_ctx_num ! = conn - > smb1 . trans_enc - > enc_ctx_num ) {
2011-07-18 16:35:03 +04:00
DEBUG ( 10 , ( " wrong enc_ctx %d, expected %d \n " ,
enc_ctx_num ,
2011-08-11 15:29:59 +04:00
conn - > smb1 . trans_enc - > enc_ctx_num ) ) ;
2011-07-18 16:35:03 +04:00
return NT_STATUS_INVALID_HANDLE ;
}
2011-08-11 15:29:59 +04:00
status = common_decrypt_buffer ( conn - > smb1 . trans_enc ,
2011-07-18 16:35:03 +04:00
( char * ) inbuf ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " common_decrypt_buffer returned %s \n " ,
nt_errstr ( status ) ) ) ;
return status ;
}
2012-08-03 11:58:29 +04:00
inhdr = inbuf + NBT_HDR_SIZE ;
len = smb_len_nbt ( inbuf ) ;
2011-07-18 16:35:03 +04:00
}
mid = SVAL ( inhdr , HDR_MID ) ;
2011-08-11 15:29:59 +04:00
num_pending = talloc_array_length ( conn - > pending ) ;
2011-07-18 16:35:03 +04:00
for ( i = 0 ; i < num_pending ; i + + ) {
2011-08-11 15:29:59 +04:00
if ( mid = = smb1cli_req_mid ( conn - > pending [ i ] ) ) {
2011-07-18 16:35:03 +04:00
break ;
}
}
if ( i = = num_pending ) {
/* Dump unexpected reply */
return NT_STATUS_RETRY ;
}
oplock_break = false ;
if ( mid = = 0xffff ) {
/*
* Paranoia checks that this is really an oplock break request .
*/
2012-08-03 11:58:29 +04:00
oplock_break = ( len = = 51 ) ; /* hdr + 8 words */
2011-07-18 16:35:03 +04:00
oplock_break & = ( ( CVAL ( inhdr , HDR_FLG ) & FLAG_REPLY ) = = 0 ) ;
oplock_break & = ( CVAL ( inhdr , HDR_COM ) = = SMBlockingX ) ;
oplock_break & = ( SVAL ( inhdr , HDR_VWV + VWV ( 6 ) ) = = 0 ) ;
oplock_break & = ( SVAL ( inhdr , HDR_VWV + VWV ( 7 ) ) = = 0 ) ;
if ( ! oplock_break ) {
/* Dump unexpected reply */
return NT_STATUS_RETRY ;
}
}
2011-08-11 15:29:59 +04:00
req = conn - > pending [ i ] ;
state = tevent_req_data ( req , struct smbXcli_req_state ) ;
2011-07-18 16:35:03 +04:00
if ( ! oplock_break /* oplock breaks are not signed */
2022-03-08 06:26:54 +03:00
& & ! smb1_signing_check_pdu ( conn - > smb1 . signing ,
2012-08-03 11:58:29 +04:00
inhdr , len , state - > smb1 . seqnum + 1 ) ) {
2011-07-18 16:35:03 +04:00
DEBUG ( 10 , ( " cli_check_sign_mac failed \n " ) ) ;
return NT_STATUS_ACCESS_DENIED ;
}
2011-11-16 14:35:50 +04:00
status = smb1cli_inbuf_parse_chain ( inbuf , tmp_mem ,
& iov , & num_iov ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " smb1cli_inbuf_parse_chain - %s \n " ,
nt_errstr ( status ) ) ) ;
return status ;
}
cmd = CVAL ( inhdr , HDR_COM ) ;
status = smb1cli_pull_raw_error ( inhdr ) ;
2012-10-22 16:18:20 +04:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NETWORK_SESSION_EXPIRED ) & &
( state - > session ! = NULL ) & & state - > session - > disconnect_expired )
{
/*
* this should be a short term hack
* until the upper layers have implemented
* re - authentication .
*/
return status ;
}
2011-11-21 16:08:58 +04:00
if ( state - > smb1 . chained_requests = = NULL ) {
if ( num_iov ! = 3 ) {
2011-11-16 14:35:50 +04:00
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
2011-07-18 16:35:03 +04:00
2011-11-21 16:08:58 +04:00
smbXcli_req_unset_pending ( req ) ;
2011-07-18 16:35:03 +04:00
2011-11-28 20:48:44 +04:00
if ( state - > smb1 . recv_iov = = NULL ) {
/*
* For requests with more than
* one response , we have to readd the
* recv_iov array .
*/
state - > smb1 . recv_iov = talloc_zero_array ( state ,
struct iovec ,
3 ) ;
if ( tevent_req_nomem ( state - > smb1 . recv_iov , req ) ) {
return NT_STATUS_OK ;
}
}
2011-11-21 16:08:58 +04:00
state - > smb1 . recv_cmd = cmd ;
state - > smb1 . recv_status = status ;
state - > inbuf = talloc_move ( state - > smb1 . recv_iov , & inbuf ) ;
2011-07-18 16:35:03 +04:00
2011-11-21 16:08:58 +04:00
state - > smb1 . recv_iov [ 0 ] = iov [ 0 ] ;
state - > smb1 . recv_iov [ 1 ] = iov [ 1 ] ;
state - > smb1 . recv_iov [ 2 ] = iov [ 2 ] ;
2011-07-18 16:35:03 +04:00
2011-11-21 16:08:58 +04:00
if ( talloc_array_length ( conn - > pending ) = = 0 ) {
tevent_req_done ( req ) ;
return NT_STATUS_OK ;
}
2011-07-18 16:35:03 +04:00
2011-11-21 16:08:58 +04:00
tevent_req_defer_callback ( req , state - > ev ) ;
tevent_req_done ( req ) ;
return NT_STATUS_RETRY ;
}
2011-07-18 16:35:03 +04:00
2011-11-21 16:08:58 +04:00
chain = talloc_move ( tmp_mem , & state - > smb1 . chained_requests ) ;
num_chained = talloc_array_length ( chain ) ;
num_responses = ( num_iov - 1 ) / 2 ;
2011-11-16 14:35:50 +04:00
2011-11-21 16:08:58 +04:00
if ( num_responses > num_chained ) {
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
2011-11-16 14:35:50 +04:00
2011-11-21 16:08:58 +04:00
for ( i = 0 ; i < num_chained ; i + + ) {
size_t iov_idx = 1 + ( i * 2 ) ;
struct iovec * cur = & iov [ iov_idx ] ;
uint8_t * inbuf_ref ;
2011-07-18 16:35:03 +04:00
2011-11-21 16:08:58 +04:00
req = chain [ i ] ;
state = tevent_req_data ( req , struct smbXcli_req_state ) ;
2011-11-16 14:35:50 +04:00
2011-11-21 16:08:58 +04:00
smbXcli_req_unset_pending ( req ) ;
2011-11-16 14:35:50 +04:00
2011-11-21 16:08:58 +04:00
/*
* as we finish multiple requests here
* we need to defer the callbacks as
* they could destroy our current stack state .
*/
tevent_req_defer_callback ( req , state - > ev ) ;
if ( i > = num_responses ) {
tevent_req_nterror ( req , NT_STATUS_REQUEST_ABORTED ) ;
continue ;
2011-07-18 16:35:03 +04:00
}
2011-11-28 20:48:44 +04:00
if ( state - > smb1 . recv_iov = = NULL ) {
/*
* For requests with more than
* one response , we have to readd the
* recv_iov array .
*/
state - > smb1 . recv_iov = talloc_zero_array ( state ,
struct iovec ,
3 ) ;
if ( tevent_req_nomem ( state - > smb1 . recv_iov , req ) ) {
continue ;
}
}
2011-11-21 16:08:58 +04:00
state - > smb1 . recv_cmd = cmd ;
2011-11-16 14:35:50 +04:00
2011-11-21 16:08:58 +04:00
if ( i = = ( num_responses - 1 ) ) {
/*
* The last request in the chain gets the status
*/
state - > smb1 . recv_status = status ;
} else {
cmd = CVAL ( cur [ 0 ] . iov_base , 0 ) ;
state - > smb1 . recv_status = NT_STATUS_OK ;
}
2011-07-18 16:35:03 +04:00
2011-11-21 16:08:58 +04:00
state - > inbuf = inbuf ;
2011-07-18 16:35:03 +04:00
2011-11-21 16:08:58 +04:00
/*
* Note : here we use talloc_reference ( ) in a way
* that does not expose it to the caller .
*/
inbuf_ref = talloc_reference ( state - > smb1 . recv_iov , inbuf ) ;
if ( tevent_req_nomem ( inbuf_ref , req ) ) {
continue ;
}
/* copy the related buffers */
state - > smb1 . recv_iov [ 0 ] = iov [ 0 ] ;
state - > smb1 . recv_iov [ 1 ] = cur [ 0 ] ;
state - > smb1 . recv_iov [ 2 ] = cur [ 1 ] ;
2011-11-16 14:35:50 +04:00
2011-07-18 16:35:03 +04:00
tevent_req_done ( req ) ;
}
return NT_STATUS_RETRY ;
}
2011-08-11 15:29:59 +04:00
NTSTATUS smb1cli_req_recv ( struct tevent_req * req ,
2011-11-16 14:37:05 +04:00
TALLOC_CTX * mem_ctx ,
struct iovec * * piov ,
uint8_t * * phdr ,
uint8_t * pwct ,
uint16_t * * pvwv ,
uint32_t * pvwv_offset ,
uint32_t * pnum_bytes ,
uint8_t * * pbytes ,
uint32_t * pbytes_offset ,
uint8_t * * pinbuf ,
const struct smb1cli_req_expected_response * expected ,
size_t num_expected )
2011-07-18 16:35:03 +04:00
{
2011-08-11 15:29:59 +04:00
struct smbXcli_req_state * state =
tevent_req_data ( req ,
struct smbXcli_req_state ) ;
2011-07-18 16:35:03 +04:00
NTSTATUS status = NT_STATUS_OK ;
2011-11-16 14:37:05 +04:00
struct iovec * recv_iov = NULL ;
uint8_t * hdr = NULL ;
uint8_t wct = 0 ;
uint32_t vwv_offset = 0 ;
uint16_t * vwv = NULL ;
uint32_t num_bytes = 0 ;
uint32_t bytes_offset = 0 ;
uint8_t * bytes = NULL ;
size_t i ;
bool found_status = false ;
bool found_size = false ;
2011-07-18 16:35:03 +04:00
2011-11-16 14:37:05 +04:00
if ( piov ! = NULL ) {
* piov = NULL ;
2011-07-18 16:35:03 +04:00
}
2011-11-16 14:37:05 +04:00
if ( phdr ! = NULL ) {
* phdr = 0 ;
}
if ( pwct ! = NULL ) {
* pwct = 0 ;
}
if ( pvwv ! = NULL ) {
* pvwv = NULL ;
}
if ( pvwv_offset ! = NULL ) {
* pvwv_offset = 0 ;
}
if ( pnum_bytes ! = NULL ) {
* pnum_bytes = 0 ;
}
if ( pbytes ! = NULL ) {
* pbytes = NULL ;
}
if ( pbytes_offset ! = NULL ) {
* pbytes_offset = 0 ;
}
if ( pinbuf ! = NULL ) {
* pinbuf = NULL ;
2011-07-18 16:35:03 +04:00
}
2011-11-16 14:37:05 +04:00
if ( state - > inbuf ! = NULL ) {
recv_iov = state - > smb1 . recv_iov ;
2011-11-28 20:48:44 +04:00
state - > smb1 . recv_iov = NULL ;
2011-11-25 17:49:24 +04:00
if ( state - > smb1 . recv_cmd ! = SMBreadBraw ) {
hdr = ( uint8_t * ) recv_iov [ 0 ] . iov_base ;
wct = recv_iov [ 1 ] . iov_len / 2 ;
vwv = ( uint16_t * ) recv_iov [ 1 ] . iov_base ;
vwv_offset = PTR_DIFF ( vwv , hdr ) ;
num_bytes = recv_iov [ 2 ] . iov_len ;
bytes = ( uint8_t * ) recv_iov [ 2 ] . iov_base ;
bytes_offset = PTR_DIFF ( bytes , hdr ) ;
}
2011-11-16 14:37:05 +04:00
}
2011-07-18 16:35:03 +04:00
2011-11-16 14:37:05 +04:00
if ( tevent_req_is_nterror ( req , & status ) ) {
for ( i = 0 ; i < num_expected ; i + + ) {
if ( NT_STATUS_EQUAL ( status , expected [ i ] . status ) ) {
found_status = true ;
break ;
2011-07-18 16:35:03 +04:00
}
}
2011-11-16 14:37:05 +04:00
if ( found_status ) {
return NT_STATUS_UNEXPECTED_NETWORK_ERROR ;
2011-07-18 16:35:03 +04:00
}
2011-11-16 14:37:05 +04:00
return status ;
}
2011-07-18 16:35:03 +04:00
2011-11-16 14:37:05 +04:00
if ( num_expected = = 0 ) {
found_status = true ;
found_size = true ;
2011-07-18 16:35:03 +04:00
}
2011-11-16 14:37:05 +04:00
status = state - > smb1 . recv_status ;
2011-07-18 16:35:03 +04:00
2011-11-16 14:37:05 +04:00
for ( i = 0 ; i < num_expected ; i + + ) {
if ( ! NT_STATUS_EQUAL ( status , expected [ i ] . status ) ) {
continue ;
}
2011-07-18 16:35:03 +04:00
2011-11-16 14:37:05 +04:00
found_status = true ;
if ( expected [ i ] . wct = = 0 ) {
found_size = true ;
break ;
2011-07-18 16:35:03 +04:00
}
2011-11-16 14:37:05 +04:00
if ( expected [ i ] . wct = = wct ) {
found_size = true ;
break ;
2011-07-18 16:35:03 +04:00
}
}
2011-11-16 14:37:05 +04:00
if ( ! found_status ) {
return status ;
}
2011-07-18 16:35:03 +04:00
2011-11-16 14:37:05 +04:00
if ( ! found_size ) {
2011-07-18 16:35:03 +04:00
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
2011-11-16 14:37:05 +04:00
if ( piov ! = NULL ) {
* piov = talloc_move ( mem_ctx , & recv_iov ) ;
2011-07-18 16:35:03 +04:00
}
2011-11-16 14:37:05 +04:00
if ( phdr ! = NULL ) {
* phdr = hdr ;
}
2011-07-18 16:35:03 +04:00
if ( pwct ! = NULL ) {
* pwct = wct ;
}
if ( pvwv ! = NULL ) {
2011-11-16 14:37:05 +04:00
* pvwv = vwv ;
}
if ( pvwv_offset ! = NULL ) {
* pvwv_offset = vwv_offset ;
2011-07-18 16:35:03 +04:00
}
if ( pnum_bytes ! = NULL ) {
* pnum_bytes = num_bytes ;
}
if ( pbytes ! = NULL ) {
2011-11-16 14:37:05 +04:00
* pbytes = bytes ;
2011-07-18 16:35:03 +04:00
}
2011-11-16 14:37:05 +04:00
if ( pbytes_offset ! = NULL ) {
* pbytes_offset = bytes_offset ;
}
if ( pinbuf ! = NULL ) {
* pinbuf = state - > inbuf ;
2011-07-18 16:35:03 +04:00
}
return status ;
}
2011-08-11 15:29:59 +04:00
size_t smb1cli_req_wct_ofs ( struct tevent_req * * reqs , int num_reqs )
2011-07-18 16:35:03 +04:00
{
size_t wct_ofs ;
int i ;
2011-08-11 15:29:59 +04:00
wct_ofs = HDR_WCT ;
2011-07-18 16:35:03 +04:00
for ( i = 0 ; i < num_reqs ; i + + ) {
2011-08-11 15:29:59 +04:00
struct smbXcli_req_state * state ;
state = tevent_req_data ( reqs [ i ] , struct smbXcli_req_state ) ;
wct_ofs + = smbXcli_iov_len ( state - > smb1 . iov + 2 ,
state - > smb1 . iov_count - 2 ) ;
2011-07-18 16:35:03 +04:00
wct_ofs = ( wct_ofs + 3 ) & ~ 3 ;
}
return wct_ofs ;
}
2011-08-11 15:29:59 +04:00
NTSTATUS smb1cli_req_chain_submit ( struct tevent_req * * reqs , int num_reqs )
2011-07-18 16:35:03 +04:00
{
2011-08-11 15:29:59 +04:00
struct smbXcli_req_state * first_state =
tevent_req_data ( reqs [ 0 ] ,
struct smbXcli_req_state ) ;
struct smbXcli_req_state * state ;
2011-07-18 16:35:03 +04:00
size_t wct_offset ;
size_t chain_padding = 0 ;
int i , iovlen ;
struct iovec * iov = NULL ;
struct iovec * this_iov ;
NTSTATUS status ;
2015-02-17 23:19:33 +03:00
ssize_t nbt_len ;
2011-08-11 15:29:59 +04:00
if ( num_reqs = = 1 ) {
return smb1cli_req_writev_submit ( reqs [ 0 ] , first_state ,
first_state - > smb1 . iov ,
first_state - > smb1 . iov_count ) ;
}
2011-07-18 16:35:03 +04:00
iovlen = 0 ;
for ( i = 0 ; i < num_reqs ; i + + ) {
if ( ! tevent_req_is_in_progress ( reqs [ i ] ) ) {
return NT_STATUS_INTERNAL_ERROR ;
}
2011-08-11 15:29:59 +04:00
state = tevent_req_data ( reqs [ i ] , struct smbXcli_req_state ) ;
if ( state - > smb1 . iov_count < 4 ) {
return NT_STATUS_INVALID_PARAMETER_MIX ;
}
if ( i = = 0 ) {
/*
* The NBT and SMB header
*/
iovlen + = 2 ;
} else {
/*
* Chain padding
*/
iovlen + = 1 ;
}
/*
* words and bytes
*/
iovlen + = state - > smb1 . iov_count - 2 ;
2011-07-18 16:35:03 +04:00
}
2011-11-18 13:28:40 +04:00
iov = talloc_zero_array ( first_state , struct iovec , iovlen ) ;
2011-07-18 16:35:03 +04:00
if ( iov = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2011-08-11 15:29:59 +04:00
first_state - > smb1 . chained_requests = ( struct tevent_req * * ) talloc_memdup (
2011-11-18 13:28:40 +04:00
first_state , reqs , sizeof ( * reqs ) * num_reqs ) ;
2011-08-11 15:29:59 +04:00
if ( first_state - > smb1 . chained_requests = = NULL ) {
2011-07-18 16:35:03 +04:00
TALLOC_FREE ( iov ) ;
return NT_STATUS_NO_MEMORY ;
}
2011-08-11 15:29:59 +04:00
wct_offset = HDR_WCT ;
2011-07-18 16:35:03 +04:00
this_iov = iov ;
for ( i = 0 ; i < num_reqs ; i + + ) {
size_t next_padding = 0 ;
uint16_t * vwv ;
2011-08-11 15:29:59 +04:00
state = tevent_req_data ( reqs [ i ] , struct smbXcli_req_state ) ;
2011-07-18 16:35:03 +04:00
if ( i < num_reqs - 1 ) {
2011-08-11 15:29:59 +04:00
if ( ! smb1cli_is_andx_req ( CVAL ( state - > smb1 . hdr , HDR_COM ) )
| | CVAL ( state - > smb1 . hdr , HDR_WCT ) < 2 ) {
2011-07-18 16:35:03 +04:00
TALLOC_FREE ( iov ) ;
2011-08-11 15:29:59 +04:00
TALLOC_FREE ( first_state - > smb1 . chained_requests ) ;
return NT_STATUS_INVALID_PARAMETER_MIX ;
2011-07-18 16:35:03 +04:00
}
}
2011-08-11 15:29:59 +04:00
wct_offset + = smbXcli_iov_len ( state - > smb1 . iov + 2 ,
state - > smb1 . iov_count - 2 ) + 1 ;
2011-07-18 16:35:03 +04:00
if ( ( wct_offset % 4 ) ! = 0 ) {
next_padding = 4 - ( wct_offset % 4 ) ;
}
wct_offset + = next_padding ;
2011-08-11 15:29:59 +04:00
vwv = state - > smb1 . vwv ;
2011-07-18 16:35:03 +04:00
if ( i < num_reqs - 1 ) {
2011-08-11 15:29:59 +04:00
struct smbXcli_req_state * next_state =
tevent_req_data ( reqs [ i + 1 ] ,
struct smbXcli_req_state ) ;
SCVAL ( vwv + 0 , 0 , CVAL ( next_state - > smb1 . hdr , HDR_COM ) ) ;
2011-07-18 16:35:03 +04:00
SCVAL ( vwv + 0 , 1 , 0 ) ;
SSVAL ( vwv + 1 , 0 , wct_offset ) ;
2011-08-11 15:29:59 +04:00
} else if ( smb1cli_is_andx_req ( CVAL ( state - > smb1 . hdr , HDR_COM ) ) ) {
2011-07-18 16:35:03 +04:00
/* properly end the chain */
SCVAL ( vwv + 0 , 0 , 0xff ) ;
SCVAL ( vwv + 0 , 1 , 0xff ) ;
SSVAL ( vwv + 1 , 0 , 0 ) ;
}
if ( i = = 0 ) {
2011-08-11 15:29:59 +04:00
/*
* The NBT and SMB header
*/
this_iov [ 0 ] = state - > smb1 . iov [ 0 ] ;
this_iov [ 1 ] = state - > smb1 . iov [ 1 ] ;
this_iov + = 2 ;
2011-07-18 16:35:03 +04:00
} else {
/*
* This one is a bit subtle . We have to add
* chain_padding bytes between the requests , and we
* have to also include the wct field of the
* subsequent requests . We use the subsequent header
* for the padding , it contains the wct field in its
* last byte .
*/
this_iov [ 0 ] . iov_len = chain_padding + 1 ;
2011-08-11 15:29:59 +04:00
this_iov [ 0 ] . iov_base = ( void * ) & state - > smb1 . hdr [
sizeof ( state - > smb1 . hdr ) - this_iov [ 0 ] . iov_len ] ;
2011-07-18 16:35:03 +04:00
memset ( this_iov [ 0 ] . iov_base , 0 , this_iov [ 0 ] . iov_len - 1 ) ;
2011-08-11 15:29:59 +04:00
this_iov + = 1 ;
2011-07-18 16:35:03 +04:00
}
2011-08-11 15:29:59 +04:00
/*
* copy the words and bytes
*/
memcpy ( this_iov , state - > smb1 . iov + 2 ,
sizeof ( struct iovec ) * ( state - > smb1 . iov_count - 2 ) ) ;
this_iov + = state - > smb1 . iov_count - 2 ;
2011-07-18 16:35:03 +04:00
chain_padding = next_padding ;
}
2015-02-17 23:19:33 +03:00
nbt_len = iov_buflen ( & iov [ 1 ] , iovlen - 1 ) ;
if ( ( nbt_len = = - 1 ) | | ( nbt_len > first_state - > conn - > smb1 . max_xmit ) ) {
2011-08-11 15:29:59 +04:00
TALLOC_FREE ( iov ) ;
TALLOC_FREE ( first_state - > smb1 . chained_requests ) ;
return NT_STATUS_INVALID_PARAMETER_MIX ;
}
2011-11-18 13:28:40 +04:00
status = smb1cli_req_writev_submit ( reqs [ 0 ] , first_state , iov , iovlen ) ;
2011-07-18 16:35:03 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( iov ) ;
2011-08-11 15:29:59 +04:00
TALLOC_FREE ( first_state - > smb1 . chained_requests ) ;
2011-07-18 16:35:03 +04:00
return status ;
}
return NT_STATUS_OK ;
}
2019-08-29 13:28:14 +03:00
struct tevent_queue * smbXcli_conn_send_queue ( struct smbXcli_conn * conn )
{
return conn - > outgoing ;
}
2011-08-11 15:29:59 +04:00
bool smbXcli_conn_has_async_calls ( struct smbXcli_conn * conn )
2011-07-18 16:35:03 +04:00
{
2011-08-11 15:29:59 +04:00
return ( ( tevent_queue_length ( conn - > outgoing ) ! = 0 )
| | ( talloc_array_length ( conn - > pending ) ! = 0 ) ) ;
2011-07-18 16:35:03 +04:00
}
2011-09-15 13:47:11 +04:00
2013-05-17 22:41:45 +04:00
bool smbXcli_conn_dfs_supported ( struct smbXcli_conn * conn )
{
if ( conn - > protocol > = PROTOCOL_SMB2_02 ) {
return ( smb2cli_conn_server_capabilities ( conn ) & SMB2_CAP_DFS ) ;
}
return ( smb1cli_conn_capabilities ( conn ) & CAP_DFS ) ;
}
2013-08-13 17:49:19 +04:00
bool smb2cli_conn_req_possible ( struct smbXcli_conn * conn , uint32_t * max_dyn_len )
{
uint16_t credits = 1 ;
if ( conn - > smb2 . cur_credits = = 0 ) {
if ( max_dyn_len ! = NULL ) {
* max_dyn_len = 0 ;
}
return false ;
}
if ( conn - > smb2 . server . capabilities & SMB2_CAP_LARGE_MTU ) {
credits = conn - > smb2 . cur_credits ;
}
if ( max_dyn_len ! = NULL ) {
* max_dyn_len = credits * 65536 ;
}
return true ;
}
2011-09-15 16:02:49 +04:00
uint32_t smb2cli_conn_server_capabilities ( struct smbXcli_conn * conn )
{
return conn - > smb2 . server . capabilities ;
}
uint16_t smb2cli_conn_server_security_mode ( struct smbXcli_conn * conn )
{
return conn - > smb2 . server . security_mode ;
}
2021-07-14 17:23:54 +03:00
uint16_t smb2cli_conn_server_signing_algo ( struct smbXcli_conn * conn )
{
return conn - > smb2 . server . sign_algo ;
}
uint16_t smb2cli_conn_server_encryption_algo ( struct smbXcli_conn * conn )
{
return conn - > smb2 . server . cipher ;
}
2011-09-15 16:02:49 +04:00
uint32_t smb2cli_conn_max_trans_size ( struct smbXcli_conn * conn )
{
return conn - > smb2 . server . max_trans_size ;
}
uint32_t smb2cli_conn_max_read_size ( struct smbXcli_conn * conn )
{
return conn - > smb2 . server . max_read_size ;
}
uint32_t smb2cli_conn_max_write_size ( struct smbXcli_conn * conn )
{
return conn - > smb2 . server . max_write_size ;
}
2011-09-06 19:52:02 +04:00
void smb2cli_conn_set_max_credits ( struct smbXcli_conn * conn ,
uint16_t max_credits )
{
conn - > smb2 . max_credits = max_credits ;
}
2017-02-27 14:29:25 +03:00
uint16_t smb2cli_conn_get_cur_credits ( struct smbXcli_conn * conn )
{
return conn - > smb2 . cur_credits ;
}
2015-05-08 13:52:23 +03:00
uint8_t smb2cli_conn_get_io_priority ( struct smbXcli_conn * conn )
{
if ( conn - > protocol < PROTOCOL_SMB3_11 ) {
return 0 ;
}
return conn - > smb2 . io_priority ;
}
void smb2cli_conn_set_io_priority ( struct smbXcli_conn * conn ,
uint8_t io_priority )
{
conn - > smb2 . io_priority = io_priority ;
}
2015-05-28 01:13:15 +03:00
uint32_t smb2cli_conn_cc_chunk_len ( struct smbXcli_conn * conn )
{
return conn - > smb2 . cc_chunk_len ;
}
void smb2cli_conn_set_cc_chunk_len ( struct smbXcli_conn * conn ,
uint32_t chunk_len )
{
conn - > smb2 . cc_chunk_len = chunk_len ;
}
uint32_t smb2cli_conn_cc_max_chunks ( struct smbXcli_conn * conn )
{
return conn - > smb2 . cc_max_chunks ;
}
void smb2cli_conn_set_cc_max_chunks ( struct smbXcli_conn * conn ,
uint32_t max_chunks )
{
conn - > smb2 . cc_max_chunks = max_chunks ;
}
2011-09-24 08:06:46 +04:00
static void smb2cli_req_cancel_done ( struct tevent_req * subreq ) ;
static bool smb2cli_req_cancel ( struct tevent_req * req )
{
struct smbXcli_req_state * state =
tevent_req_data ( req ,
struct smbXcli_req_state ) ;
2012-07-25 12:36:27 +04:00
struct smbXcli_tcon * tcon = state - > tcon ;
2011-09-24 08:06:46 +04:00
struct smbXcli_session * session = state - > session ;
uint8_t * fixed = state - > smb2 . pad ;
uint16_t fixed_len = 4 ;
struct tevent_req * subreq ;
struct smbXcli_req_state * substate ;
NTSTATUS status ;
2021-05-07 00:07:13 +03:00
if ( state - > smb2 . cancel_mid = = UINT64_MAX ) {
/*
* We already send a cancel ,
* make sure we don ' t do it
* twice , otherwise we may
* expose the same NONCE for
* AES - 128 - GMAC signing
*/
return true ;
}
2011-09-24 08:06:46 +04:00
SSVAL ( fixed , 0 , 0x04 ) ;
SSVAL ( fixed , 2 , 0 ) ;
subreq = smb2cli_req_create ( state , state - > ev ,
state - > conn ,
SMB2_OP_CANCEL ,
2015-05-08 13:05:06 +03:00
0 , 0 , /* flags */
2011-09-24 08:06:46 +04:00
0 , /* timeout */
2012-07-25 12:58:34 +04:00
tcon , session ,
2011-09-24 08:06:46 +04:00
fixed , fixed_len ,
2013-08-13 11:54:42 +04:00
NULL , 0 , 0 ) ;
2011-09-24 08:06:46 +04:00
if ( subreq = = NULL ) {
return false ;
}
substate = tevent_req_data ( subreq , struct smbXcli_req_state ) ;
2021-05-07 00:07:13 +03:00
substate - > smb2 . cancel_mid = BVAL ( state - > smb2 . hdr , SMB2_HDR_MESSAGE_ID ) ;
2015-05-08 13:05:06 +03:00
SIVAL ( substate - > smb2 . hdr , SMB2_HDR_FLAGS , state - > smb2 . cancel_flags ) ;
SBVAL ( substate - > smb2 . hdr , SMB2_HDR_MESSAGE_ID , state - > smb2 . cancel_mid ) ;
SBVAL ( substate - > smb2 . hdr , SMB2_HDR_ASYNC_ID , state - > smb2 . cancel_aid ) ;
2011-09-24 08:06:46 +04:00
2021-05-07 00:07:13 +03:00
/*
* remember that we don ' t send a cancel again
*/
state - > smb2 . cancel_mid = UINT64_MAX ;
2011-09-24 08:06:46 +04:00
status = smb2cli_req_compound_submit ( & subreq , 1 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( subreq ) ;
return false ;
}
tevent_req_set_callback ( subreq , smb2cli_req_cancel_done , NULL ) ;
return true ;
}
static void smb2cli_req_cancel_done ( struct tevent_req * subreq )
{
/* we do not care about the result */
TALLOC_FREE ( subreq ) ;
}
2018-10-28 04:03:28 +03:00
struct timeval smbXcli_req_endtime ( struct tevent_req * req )
{
struct smbXcli_req_state * state = tevent_req_data (
req , struct smbXcli_req_state ) ;
return state - > endtime ;
}
2011-09-15 13:47:11 +04:00
struct tevent_req * smb2cli_req_create ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
2011-09-15 14:23:05 +04:00
struct smbXcli_conn * conn ,
2011-09-15 13:47:11 +04:00
uint16_t cmd ,
uint32_t additional_flags ,
uint32_t clear_flags ,
2011-09-15 14:23:05 +04:00
uint32_t timeout_msec ,
2012-07-25 12:36:27 +04:00
struct smbXcli_tcon * tcon ,
2011-09-03 12:18:17 +04:00
struct smbXcli_session * session ,
2011-09-15 13:47:11 +04:00
const uint8_t * fixed ,
uint16_t fixed_len ,
const uint8_t * dyn ,
2013-08-13 11:54:42 +04:00
uint32_t dyn_len ,
uint32_t max_dyn_len )
2011-09-15 13:47:11 +04:00
{
struct tevent_req * req ;
2011-09-15 14:23:05 +04:00
struct smbXcli_req_state * state ;
2011-09-15 13:47:11 +04:00
uint32_t flags = 0 ;
2012-07-25 12:36:27 +04:00
uint32_t tid = 0 ;
2011-09-03 12:18:17 +04:00
uint64_t uid = 0 ;
2018-01-11 13:25:49 +03:00
bool use_channel_sequence = conn - > smb2 . force_channel_sequence ;
2012-07-26 03:54:33 +04:00
uint16_t channel_sequence = 0 ;
2014-07-10 15:16:04 +04:00
bool use_replay_flag = false ;
2022-09-29 12:08:12 +03:00
enum protocol_types proto = smbXcli_conn_protocol ( conn ) ;
2011-09-15 13:47:11 +04:00
req = tevent_req_create ( mem_ctx , & state ,
2011-09-15 14:23:05 +04:00
struct smbXcli_req_state ) ;
2011-09-15 13:47:11 +04:00
if ( req = = NULL ) {
return NULL ;
}
2011-09-15 14:23:05 +04:00
2022-09-29 12:08:12 +03:00
if ( ( proto > PROTOCOL_NONE ) & & ( proto < PROTOCOL_SMB2_02 ) ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return req ;
}
2011-09-15 13:47:11 +04:00
state - > ev = ev ;
2011-09-15 14:23:05 +04:00
state - > conn = conn ;
2011-09-03 12:18:17 +04:00
state - > session = session ;
2012-07-25 12:36:27 +04:00
state - > tcon = tcon ;
2011-09-03 12:18:17 +04:00
2012-07-26 03:54:33 +04:00
if ( conn - > smb2 . server . capabilities & SMB2_CAP_PERSISTENT_HANDLES ) {
use_channel_sequence = true ;
} else if ( conn - > smb2 . server . capabilities & SMB2_CAP_MULTI_CHANNEL ) {
use_channel_sequence = true ;
}
2014-07-10 15:16:04 +04:00
if ( smbXcli_conn_protocol ( conn ) > = PROTOCOL_SMB3_00 ) {
use_replay_flag = true ;
}
2015-05-08 13:52:23 +03:00
if ( smbXcli_conn_protocol ( conn ) > = PROTOCOL_SMB3_11 ) {
flags | = SMB2_PRIORITY_VALUE_TO_MASK ( conn - > smb2 . io_priority ) ;
}
2011-09-03 12:18:17 +04:00
if ( session ) {
2012-07-26 04:36:37 +04:00
uid = session - > smb2 - > session_id ;
2012-07-23 12:00:50 +04:00
2012-07-26 03:54:33 +04:00
if ( use_channel_sequence ) {
channel_sequence = session - > smb2 - > channel_sequence ;
}
2014-07-10 15:16:04 +04:00
if ( use_replay_flag & & session - > smb2 - > replay_active ) {
additional_flags | = SMB2_HDR_FLAG_REPLAY_OPERATION ;
}
2012-07-26 04:36:37 +04:00
state - > smb2 . should_sign = session - > smb2 - > should_sign ;
state - > smb2 . should_encrypt = session - > smb2 - > should_encrypt ;
2018-11-09 17:26:44 +03:00
state - > smb2 . require_signed_response =
session - > smb2 - > require_signed_response ;
2012-07-23 12:14:53 +04:00
2012-07-23 12:00:50 +04:00
if ( cmd = = SMB2_OP_SESSSETUP & &
2019-03-04 18:59:51 +03:00
! smb2_signing_key_valid ( session - > smb2_channel . signing_key ) & &
smb2_signing_key_valid ( session - > smb2 - > signing_key ) )
2014-12-12 16:55:38 +03:00
{
/*
* a session bind needs to be signed
*/
2012-07-23 12:00:50 +04:00
state - > smb2 . should_sign = true ;
}
2012-07-23 12:14:53 +04:00
2012-07-23 13:38:31 +04:00
if ( cmd = = SMB2_OP_SESSSETUP & &
2019-03-04 18:59:51 +03:00
! smb2_signing_key_valid ( session - > smb2_channel . signing_key ) ) {
2012-07-23 12:14:53 +04:00
state - > smb2 . should_encrypt = false ;
}
2014-09-25 03:22:29 +04:00
if ( additional_flags & SMB2_HDR_FLAG_SIGNED ) {
2019-03-04 18:59:51 +03:00
if ( ! smb2_signing_key_valid ( session - > smb2_channel . signing_key ) ) {
2014-09-25 03:22:29 +04:00
tevent_req_nterror ( req , NT_STATUS_NO_USER_SESSION_KEY ) ;
return req ;
}
additional_flags & = ~ SMB2_HDR_FLAG_SIGNED ;
state - > smb2 . should_sign = true ;
}
2012-07-25 12:36:27 +04:00
}
2012-07-23 12:14:53 +04:00
2012-07-25 12:36:27 +04:00
if ( tcon ) {
tid = tcon - > smb2 . tcon_id ;
2014-09-26 08:29:02 +04:00
if ( tcon - > smb2 . should_sign ) {
state - > smb2 . should_sign = true ;
}
2012-07-25 14:34:20 +04:00
if ( tcon - > smb2 . should_encrypt ) {
state - > smb2 . should_encrypt = true ;
}
2012-07-25 12:36:27 +04:00
}
if ( state - > smb2 . should_encrypt ) {
state - > smb2 . should_sign = false ;
2011-09-03 12:18:17 +04:00
}
2011-09-15 13:47:11 +04:00
2011-09-15 14:23:05 +04:00
state - > smb2 . recv_iov = talloc_zero_array ( state , struct iovec , 3 ) ;
2022-09-29 12:00:41 +03:00
if ( tevent_req_nomem ( state - > smb2 . recv_iov , req ) ) {
return req ;
2011-09-15 13:47:11 +04:00
}
flags | = additional_flags ;
flags & = ~ clear_flags ;
2011-09-15 14:23:05 +04:00
state - > smb2 . fixed = fixed ;
state - > smb2 . fixed_len = fixed_len ;
state - > smb2 . dyn = dyn ;
state - > smb2 . dyn_len = dyn_len ;
2013-08-13 11:54:42 +04:00
state - > smb2 . max_dyn_len = max_dyn_len ;
2011-09-15 14:23:05 +04:00
2012-07-23 12:14:53 +04:00
if ( state - > smb2 . should_encrypt ) {
SIVAL ( state - > smb2 . transform , SMB2_TF_PROTOCOL_ID , SMB2_TF_MAGIC ) ;
SBVAL ( state - > smb2 . transform , SMB2_TF_SESSION_ID , uid ) ;
}
2011-09-15 14:23:05 +04:00
SIVAL ( state - > smb2 . hdr , SMB2_HDR_PROTOCOL_ID , SMB2_MAGIC ) ;
SSVAL ( state - > smb2 . hdr , SMB2_HDR_LENGTH , SMB2_HDR_BODY ) ;
SSVAL ( state - > smb2 . hdr , SMB2_HDR_OPCODE , cmd ) ;
2012-07-26 03:54:33 +04:00
SSVAL ( state - > smb2 . hdr , SMB2_HDR_CHANNEL_SEQUENCE , channel_sequence ) ;
2011-09-15 14:23:05 +04:00
SIVAL ( state - > smb2 . hdr , SMB2_HDR_FLAGS , flags ) ;
2012-07-25 12:58:34 +04:00
SIVAL ( state - > smb2 . hdr , SMB2_HDR_PID , 0 ) ; /* reserved */
2011-09-15 14:23:05 +04:00
SIVAL ( state - > smb2 . hdr , SMB2_HDR_TID , tid ) ;
SBVAL ( state - > smb2 . hdr , SMB2_HDR_SESSION_ID , uid ) ;
switch ( cmd ) {
case SMB2_OP_CANCEL :
state - > one_way = true ;
break ;
2011-09-22 23:24:42 +04:00
case SMB2_OP_BREAK :
/*
* If this is a dummy request , it will have
* UINT64_MAX as message id .
* If we send on break acknowledgement ,
* this gets overwritten later .
*/
SBVAL ( state - > smb2 . hdr , SMB2_HDR_MESSAGE_ID , UINT64_MAX ) ;
break ;
2011-09-15 14:23:05 +04:00
}
if ( timeout_msec > 0 ) {
2018-10-28 04:04:51 +03:00
state - > endtime = timeval_current_ofs_msec ( timeout_msec ) ;
if ( ! tevent_req_set_endtime ( req , ev , state - > endtime ) ) {
2011-09-15 13:47:11 +04:00
return req ;
}
}
return req ;
}
2011-10-27 19:20:27 +04:00
void smb2cli_req_set_notify_async ( struct tevent_req * req )
{
struct smbXcli_req_state * state =
tevent_req_data ( req ,
struct smbXcli_req_state ) ;
state - > smb2 . notify_async = true ;
}
2011-11-28 13:24:18 +04:00
static void smb2cli_req_writev_done ( struct tevent_req * subreq ) ;
2011-09-15 14:23:05 +04:00
static NTSTATUS smb2cli_conn_dispatch_incoming ( struct smbXcli_conn * conn ,
TALLOC_CTX * tmp_mem ,
uint8_t * inbuf ) ;
2011-09-15 13:47:11 +04:00
NTSTATUS smb2cli_req_compound_submit ( struct tevent_req * * reqs ,
int num_reqs )
{
2011-09-15 14:23:05 +04:00
struct smbXcli_req_state * state ;
2011-09-15 13:47:11 +04:00
struct tevent_req * subreq ;
struct iovec * iov ;
int i , num_iov , nbt_len ;
2012-08-14 11:30:43 +04:00
int tf_iov = - 1 ;
2019-03-14 12:27:06 +03:00
struct smb2_signing_key * encryption_key = NULL ;
2012-08-14 11:30:43 +04:00
uint64_t encryption_session_id = 0 ;
2015-05-28 16:20:54 +03:00
uint64_t nonce_high = UINT64_MAX ;
uint64_t nonce_low = UINT64_MAX ;
2011-09-15 13:47:11 +04:00
/*
2012-08-14 11:30:43 +04:00
* 1 for the nbt length , optional TRANSFORM
* per request : HDR , fixed , dyn , padding
2011-09-15 13:47:11 +04:00
* - 1 because the last one does not need padding
*/
2012-08-14 11:30:43 +04:00
iov = talloc_array ( reqs [ 0 ] , struct iovec , 1 + 1 + 4 * num_reqs - 1 ) ;
2011-09-15 13:47:11 +04:00
if ( iov = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
num_iov = 1 ;
nbt_len = 0 ;
2012-08-14 11:30:43 +04:00
/*
* the session of the first request that requires encryption
* specifies the encryption key .
*/
for ( i = 0 ; i < num_reqs ; i + + ) {
if ( ! tevent_req_is_in_progress ( reqs [ i ] ) ) {
return NT_STATUS_INTERNAL_ERROR ;
}
state = tevent_req_data ( reqs [ i ] , struct smbXcli_req_state ) ;
if ( ! smbXcli_conn_is_connected ( state - > conn ) ) {
return NT_STATUS_CONNECTION_DISCONNECTED ;
}
if ( ( state - > conn - > protocol ! = PROTOCOL_NONE ) & &
( state - > conn - > protocol < PROTOCOL_SMB2_02 ) ) {
return NT_STATUS_REVISION_MISMATCH ;
}
if ( state - > session = = NULL ) {
continue ;
}
if ( ! state - > smb2 . should_encrypt ) {
continue ;
}
2019-03-14 11:34:23 +03:00
encryption_key = state - > session - > smb2 - > encryption_key ;
if ( ! smb2_signing_key_valid ( encryption_key ) ) {
2012-08-14 11:30:43 +04:00
return NT_STATUS_INVALID_PARAMETER_MIX ;
}
encryption_session_id = state - > session - > smb2 - > session_id ;
2015-05-28 16:20:54 +03:00
state - > session - > smb2 - > nonce_low + = 1 ;
if ( state - > session - > smb2 - > nonce_low = = 0 ) {
state - > session - > smb2 - > nonce_high + = 1 ;
state - > session - > smb2 - > nonce_low + = 1 ;
}
/*
* CCM and GCM algorithms must never have their
* nonce wrap , or the security of the whole
* communication and the keys is destroyed .
* We must drop the connection once we have
2023-04-27 16:58:18 +03:00
* transferred too much data .
2015-05-28 16:20:54 +03:00
*
* NOTE : We assume nonces greater than 8 bytes .
*/
if ( state - > session - > smb2 - > nonce_high > =
state - > session - > smb2 - > nonce_high_max )
{
return NT_STATUS_ENCRYPTION_FAILED ;
}
nonce_high = state - > session - > smb2 - > nonce_high_random ;
nonce_high + = state - > session - > smb2 - > nonce_high ;
nonce_low = state - > session - > smb2 - > nonce_low ;
2012-08-14 11:30:43 +04:00
tf_iov = num_iov ;
iov [ num_iov ] . iov_base = state - > smb2 . transform ;
iov [ num_iov ] . iov_len = sizeof ( state - > smb2 . transform ) ;
num_iov + = 1 ;
SBVAL ( state - > smb2 . transform , SMB2_TF_PROTOCOL_ID , SMB2_TF_MAGIC ) ;
SBVAL ( state - > smb2 . transform , SMB2_TF_NONCE ,
2015-05-28 16:20:54 +03:00
nonce_low ) ;
2012-08-14 11:30:43 +04:00
SBVAL ( state - > smb2 . transform , SMB2_TF_NONCE + 8 ,
2015-05-28 16:20:54 +03:00
nonce_high ) ;
2012-08-14 11:30:43 +04:00
SBVAL ( state - > smb2 . transform , SMB2_TF_SESSION_ID ,
encryption_session_id ) ;
nbt_len + = SMB2_TF_HDR_SIZE ;
break ;
}
2011-09-15 13:47:11 +04:00
for ( i = 0 ; i < num_reqs ; i + + ) {
2011-09-03 12:18:32 +04:00
int hdr_iov ;
2011-09-15 13:47:11 +04:00
size_t reqlen ;
bool ret ;
2011-09-24 08:06:46 +04:00
uint16_t opcode ;
2011-09-06 19:52:02 +04:00
uint64_t avail ;
uint16_t charge ;
uint16_t credits ;
2011-09-15 13:47:11 +04:00
uint64_t mid ;
2019-03-13 21:34:23 +03:00
struct smb2_signing_key * signing_key = NULL ;
2011-09-15 13:47:11 +04:00
if ( ! tevent_req_is_in_progress ( reqs [ i ] ) ) {
return NT_STATUS_INTERNAL_ERROR ;
}
2011-09-15 14:23:05 +04:00
state = tevent_req_data ( reqs [ i ] , struct smbXcli_req_state ) ;
2011-09-15 13:47:11 +04:00
2011-09-15 14:23:05 +04:00
if ( ! smbXcli_conn_is_connected ( state - > conn ) ) {
2011-09-15 13:47:11 +04:00
return NT_STATUS_CONNECTION_DISCONNECTED ;
}
2011-09-15 14:23:05 +04:00
if ( ( state - > conn - > protocol ! = PROTOCOL_NONE ) & &
( state - > conn - > protocol < PROTOCOL_SMB2_02 ) ) {
return NT_STATUS_REVISION_MISMATCH ;
}
2011-09-24 08:06:46 +04:00
opcode = SVAL ( state - > smb2 . hdr , SMB2_HDR_OPCODE ) ;
if ( opcode = = SMB2_OP_CANCEL ) {
goto skip_credits ;
}
2011-09-06 19:52:02 +04:00
avail = UINT64_MAX - state - > conn - > smb2 . mid ;
if ( avail < 1 ) {
2011-09-15 13:47:11 +04:00
return NT_STATUS_CONNECTION_ABORTED ;
}
2011-09-06 19:52:02 +04:00
if ( state - > conn - > smb2 . server . capabilities & SMB2_CAP_LARGE_MTU ) {
2013-08-13 11:50:29 +04:00
uint32_t max_dyn_len = 1 ;
max_dyn_len = MAX ( max_dyn_len , state - > smb2 . dyn_len ) ;
max_dyn_len = MAX ( max_dyn_len , state - > smb2 . max_dyn_len ) ;
charge = ( max_dyn_len - 1 ) / 65536 + 1 ;
2011-09-06 19:52:02 +04:00
} else {
charge = 1 ;
}
charge = MAX ( state - > smb2 . credit_charge , charge ) ;
avail = MIN ( avail , state - > conn - > smb2 . cur_credits ) ;
if ( avail < charge ) {
2019-01-07 02:06:15 +03:00
DBG_ERR ( " Insufficient credits. "
" % " PRIu64 " available, % " PRIu16 " needed \n " ,
avail , charge ) ;
2011-09-06 19:52:02 +04:00
return NT_STATUS_INTERNAL_ERROR ;
}
credits = 0 ;
if ( state - > conn - > smb2 . max_credits > state - > conn - > smb2 . cur_credits ) {
credits = state - > conn - > smb2 . max_credits -
state - > conn - > smb2 . cur_credits ;
}
if ( state - > conn - > smb2 . max_credits > = state - > conn - > smb2 . cur_credits ) {
credits + = 1 ;
}
2011-09-15 14:23:05 +04:00
mid = state - > conn - > smb2 . mid ;
2011-09-06 19:52:02 +04:00
state - > conn - > smb2 . mid + = charge ;
state - > conn - > smb2 . cur_credits - = charge ;
2011-09-15 13:47:11 +04:00
2011-09-06 19:52:02 +04:00
if ( state - > conn - > smb2 . server . capabilities & SMB2_CAP_LARGE_MTU ) {
SSVAL ( state - > smb2 . hdr , SMB2_HDR_CREDIT_CHARGE , charge ) ;
}
SSVAL ( state - > smb2 . hdr , SMB2_HDR_CREDIT , credits ) ;
2011-09-15 14:23:05 +04:00
SBVAL ( state - > smb2 . hdr , SMB2_HDR_MESSAGE_ID , mid ) ;
2011-09-15 13:47:11 +04:00
2021-05-07 00:07:13 +03:00
state - > smb2 . cancel_flags = SVAL ( state - > smb2 . hdr , SMB2_HDR_FLAGS ) ;
state - > smb2 . cancel_flags & = ~ SMB2_HDR_FLAG_CHAINED ;
2021-09-28 23:24:32 +03:00
if ( state - > conn - > smb2 . server . sign_algo > = SMB2_SIGNING_AES128_GMAC ) {
state - > smb2 . cancel_mid = mid ;
} else {
state - > smb2 . cancel_mid = 0 ;
}
2015-05-08 13:05:06 +03:00
state - > smb2 . cancel_aid = 0 ;
2011-09-24 08:06:46 +04:00
skip_credits :
2012-08-14 11:30:43 +04:00
if ( state - > session & & encryption_key = = NULL ) {
2012-02-27 11:48:55 +04:00
/*
* We prefer the channel signing key if it is
* already there .
*/
2012-07-23 12:00:50 +04:00
if ( state - > smb2 . should_sign ) {
2019-03-04 18:59:51 +03:00
signing_key = state - > session - > smb2_channel . signing_key ;
2012-02-27 11:48:55 +04:00
}
/*
* If it is a channel binding , we already have the main
* signing key and try that one .
*/
2019-06-07 20:00:25 +03:00
if ( signing_key ! = NULL & &
! smb2_signing_key_valid ( signing_key ) ) {
2019-03-04 18:59:51 +03:00
signing_key = state - > session - > smb2 - > signing_key ;
2012-02-27 11:48:55 +04:00
}
/*
* If we do not have any session key yet , we skip the
* signing of SMB2_OP_SESSSETUP requests .
*/
2019-06-07 20:00:25 +03:00
if ( signing_key ! = NULL & &
! smb2_signing_key_valid ( signing_key ) ) {
2012-02-27 11:48:55 +04:00
signing_key = NULL ;
}
2011-09-19 21:05:20 +04:00
}
2012-07-19 13:16:16 +04:00
hdr_iov = num_iov ;
iov [ num_iov ] . iov_base = state - > smb2 . hdr ;
iov [ num_iov ] . iov_len = sizeof ( state - > smb2 . hdr ) ;
num_iov + = 1 ;
iov [ num_iov ] . iov_base = discard_const ( state - > smb2 . fixed ) ;
iov [ num_iov ] . iov_len = state - > smb2 . fixed_len ;
num_iov + = 1 ;
if ( state - > smb2 . dyn ! = NULL ) {
iov [ num_iov ] . iov_base = discard_const ( state - > smb2 . dyn ) ;
iov [ num_iov ] . iov_len = state - > smb2 . dyn_len ;
num_iov + = 1 ;
}
reqlen = sizeof ( state - > smb2 . hdr ) ;
reqlen + = state - > smb2 . fixed_len ;
reqlen + = state - > smb2 . dyn_len ;
if ( i < num_reqs - 1 ) {
if ( ( reqlen % 8 ) > 0 ) {
uint8_t pad = 8 - ( reqlen % 8 ) ;
iov [ num_iov ] . iov_base = state - > smb2 . pad ;
iov [ num_iov ] . iov_len = pad ;
num_iov + = 1 ;
reqlen + = pad ;
}
SIVAL ( state - > smb2 . hdr , SMB2_HDR_NEXT_COMMAND , reqlen ) ;
}
2012-08-14 11:30:43 +04:00
state - > smb2 . encryption_session_id = encryption_session_id ;
2012-07-23 12:14:53 +04:00
2012-08-14 11:30:43 +04:00
if ( signing_key ! = NULL ) {
2011-09-03 12:18:32 +04:00
NTSTATUS status ;
2019-03-13 21:34:23 +03:00
status = smb2_signing_sign_pdu ( signing_key ,
2011-09-03 12:18:32 +04:00
& iov [ hdr_iov ] , num_iov - hdr_iov ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
}
2012-07-23 12:07:19 +04:00
nbt_len + = reqlen ;
2011-09-15 14:23:05 +04:00
ret = smbXcli_req_set_pending ( reqs [ i ] ) ;
2011-09-15 13:47:11 +04:00
if ( ! ret ) {
return NT_STATUS_NO_MEMORY ;
}
}
2011-09-15 14:23:05 +04:00
state = tevent_req_data ( reqs [ 0 ] , struct smbXcli_req_state ) ;
_smb_setlen_tcp ( state - > length_hdr , nbt_len ) ;
iov [ 0 ] . iov_base = state - > length_hdr ;
iov [ 0 ] . iov_len = sizeof ( state - > length_hdr ) ;
2011-09-15 13:47:11 +04:00
2012-08-14 11:30:43 +04:00
if ( encryption_key ! = NULL ) {
NTSTATUS status ;
size_t buflen = nbt_len - SMB2_TF_HDR_SIZE ;
uint8_t * buf ;
int vi ;
buf = talloc_array ( iov , uint8_t , buflen ) ;
if ( buf = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
/*
* We copy the buffers before encrypting them ,
* this is at least currently needed for the
* to keep state - > smb2 . hdr .
*
* Also the callers may expect there buffers
* to be const .
*/
for ( vi = tf_iov + 1 ; vi < num_iov ; vi + + ) {
struct iovec * v = & iov [ vi ] ;
const uint8_t * o = ( const uint8_t * ) v - > iov_base ;
memcpy ( buf , o , v - > iov_len ) ;
v - > iov_base = ( void * ) buf ;
buf + = v - > iov_len ;
}
2019-03-14 12:27:06 +03:00
status = smb2_signing_encrypt_pdu ( encryption_key ,
2012-08-14 11:30:43 +04:00
& iov [ tf_iov ] , num_iov - tf_iov ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
}
2011-09-15 14:23:05 +04:00
if ( state - > conn - > dispatch_incoming = = NULL ) {
state - > conn - > dispatch_incoming = smb2cli_conn_dispatch_incoming ;
}
subreq = writev_send ( state , state - > ev , state - > conn - > outgoing ,
2015-05-28 14:22:19 +03:00
state - > conn - > sock_fd , false , iov , num_iov ) ;
2011-09-15 13:47:11 +04:00
if ( subreq = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2011-11-28 13:24:18 +04:00
tevent_req_set_callback ( subreq , smb2cli_req_writev_done , reqs [ 0 ] ) ;
2015-05-29 17:14:40 +03:00
state - > write_req = subreq ;
2011-09-15 13:47:11 +04:00
return NT_STATUS_OK ;
}
2011-09-06 19:52:02 +04:00
void smb2cli_req_set_credit_charge ( struct tevent_req * req , uint16_t charge )
{
struct smbXcli_req_state * state =
tevent_req_data ( req ,
struct smbXcli_req_state ) ;
state - > smb2 . credit_charge = charge ;
}
2011-09-15 13:47:11 +04:00
struct tevent_req * smb2cli_req_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
2011-09-15 14:23:05 +04:00
struct smbXcli_conn * conn ,
2011-09-15 13:47:11 +04:00
uint16_t cmd ,
uint32_t additional_flags ,
uint32_t clear_flags ,
2011-09-15 14:23:05 +04:00
uint32_t timeout_msec ,
2012-07-25 12:36:27 +04:00
struct smbXcli_tcon * tcon ,
2011-09-03 12:18:17 +04:00
struct smbXcli_session * session ,
2011-09-15 13:47:11 +04:00
const uint8_t * fixed ,
uint16_t fixed_len ,
const uint8_t * dyn ,
2013-08-13 12:25:52 +04:00
uint32_t dyn_len ,
uint32_t max_dyn_len )
2011-09-15 13:47:11 +04:00
{
struct tevent_req * req ;
NTSTATUS status ;
2011-09-15 14:23:05 +04:00
req = smb2cli_req_create ( mem_ctx , ev , conn , cmd ,
2011-09-15 13:47:11 +04:00
additional_flags , clear_flags ,
2011-09-15 14:23:05 +04:00
timeout_msec ,
2012-07-25 12:58:34 +04:00
tcon , session ,
2013-08-13 11:54:42 +04:00
fixed , fixed_len ,
dyn , dyn_len ,
max_dyn_len ) ;
2011-09-15 13:47:11 +04:00
if ( req = = NULL ) {
return NULL ;
}
if ( ! tevent_req_is_in_progress ( req ) ) {
return tevent_req_post ( req , ev ) ;
}
status = smb2cli_req_compound_submit ( & req , 1 ) ;
if ( tevent_req_nterror ( req , status ) ) {
return tevent_req_post ( req , ev ) ;
}
return req ;
}
2011-11-28 13:24:18 +04:00
static void smb2cli_req_writev_done ( struct tevent_req * subreq )
2011-09-15 13:47:11 +04:00
{
struct tevent_req * req =
tevent_req_callback_data ( subreq ,
struct tevent_req ) ;
2011-09-15 14:23:05 +04:00
struct smbXcli_req_state * state =
2011-09-15 13:47:11 +04:00
tevent_req_data ( req ,
2011-09-15 14:23:05 +04:00
struct smbXcli_req_state ) ;
2011-09-15 13:47:11 +04:00
ssize_t nwritten ;
int err ;
2015-05-29 17:14:40 +03:00
state - > write_req = NULL ;
2011-09-15 13:47:11 +04:00
nwritten = writev_recv ( subreq , & err ) ;
TALLOC_FREE ( subreq ) ;
if ( nwritten = = - 1 ) {
/* here, we need to notify all pending requests */
NTSTATUS status = map_nt_error_from_unix_common ( err ) ;
2011-09-15 14:23:05 +04:00
smbXcli_conn_disconnect ( state - > conn , status ) ;
2011-09-15 13:47:11 +04:00
return ;
}
}
2015-10-21 22:04:47 +03:00
static struct smbXcli_session * smbXcli_session_by_uid ( struct smbXcli_conn * conn ,
uint64_t uid )
{
struct smbXcli_session * s = conn - > sessions ;
for ( ; s ; s = s - > next ) {
if ( s - > smb2 - > session_id ! = uid ) {
continue ;
}
break ;
}
return s ;
}
2012-07-20 11:19:24 +04:00
static NTSTATUS smb2cli_inbuf_parse_compound ( struct smbXcli_conn * conn ,
uint8_t * buf ,
size_t buflen ,
TALLOC_CTX * mem_ctx ,
2017-12-07 19:01:39 +03:00
struct iovec * * piov ,
size_t * pnum_iov )
2011-09-15 13:47:11 +04:00
{
struct iovec * iov ;
2012-07-20 11:19:24 +04:00
int num_iov = 0 ;
size_t taken = 0 ;
uint8_t * first_hdr = buf ;
2012-08-14 11:33:01 +04:00
size_t verified_buflen = 0 ;
uint8_t * tf = NULL ;
size_t tf_len = 0 ;
2011-09-15 13:47:11 +04:00
iov = talloc_array ( mem_ctx , struct iovec , num_iov ) ;
if ( iov = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
while ( taken < buflen ) {
size_t len = buflen - taken ;
uint8_t * hdr = first_hdr + taken ;
struct iovec * cur ;
size_t full_size ;
size_t next_command_ofs ;
uint16_t body_size ;
struct iovec * iov_tmp ;
2012-08-14 11:33:01 +04:00
if ( verified_buflen > taken ) {
len = verified_buflen - taken ;
} else {
tf = NULL ;
tf_len = 0 ;
}
2012-07-23 11:16:05 +04:00
if ( len < 4 ) {
DEBUG ( 10 , ( " %d bytes left, expected at least %d \n " ,
( int ) len , 4 ) ) ;
goto inval ;
}
if ( IVAL ( hdr , 0 ) = = SMB2_TF_MAGIC ) {
struct smbXcli_session * s ;
uint64_t uid ;
struct iovec tf_iov [ 2 ] ;
2012-08-17 10:31:52 +04:00
size_t enc_len ;
2012-07-23 11:16:05 +04:00
NTSTATUS status ;
if ( len < SMB2_TF_HDR_SIZE ) {
DEBUG ( 10 , ( " %d bytes left, expected at least %d \n " ,
( int ) len , SMB2_TF_HDR_SIZE ) ) ;
goto inval ;
}
tf = hdr ;
tf_len = SMB2_TF_HDR_SIZE ;
taken + = tf_len ;
hdr = first_hdr + taken ;
2012-08-17 10:31:52 +04:00
enc_len = IVAL ( tf , SMB2_TF_MSG_SIZE ) ;
2012-07-23 11:16:05 +04:00
uid = BVAL ( tf , SMB2_TF_SESSION_ID ) ;
2012-08-17 10:31:52 +04:00
if ( len < SMB2_TF_HDR_SIZE + enc_len ) {
DEBUG ( 10 , ( " %d bytes left, expected at least %d \n " ,
( int ) len ,
( int ) ( SMB2_TF_HDR_SIZE + enc_len ) ) ) ;
goto inval ;
}
2015-10-21 22:04:47 +03:00
s = smbXcli_session_by_uid ( conn , uid ) ;
2012-07-23 11:16:05 +04:00
if ( s = = NULL ) {
DEBUG ( 10 , ( " unknown session_id %llu \n " ,
( unsigned long long ) uid ) ) ;
goto inval ;
}
tf_iov [ 0 ] . iov_base = ( void * ) tf ;
tf_iov [ 0 ] . iov_len = tf_len ;
tf_iov [ 1 ] . iov_base = ( void * ) hdr ;
2012-08-17 10:31:52 +04:00
tf_iov [ 1 ] . iov_len = enc_len ;
2012-07-23 11:16:05 +04:00
2019-03-14 12:53:23 +03:00
status = smb2_signing_decrypt_pdu ( s - > smb2 - > decryption_key ,
2012-07-23 11:16:05 +04:00
tf_iov , 2 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( iov ) ;
return status ;
}
2012-08-14 11:33:01 +04:00
2012-08-17 10:31:52 +04:00
verified_buflen = taken + enc_len ;
len = enc_len ;
2012-07-23 11:16:05 +04:00
}
2011-09-15 13:47:11 +04:00
/*
* We need the header plus the body length field
*/
if ( len < SMB2_HDR_BODY + 2 ) {
DEBUG ( 10 , ( " %d bytes left, expected at least %d \n " ,
( int ) len , SMB2_HDR_BODY ) ) ;
goto inval ;
}
if ( IVAL ( hdr , 0 ) ! = SMB2_MAGIC ) {
DEBUG ( 10 , ( " Got non-SMB2 PDU: %x \n " ,
IVAL ( hdr , 0 ) ) ) ;
goto inval ;
}
if ( SVAL ( hdr , 4 ) ! = SMB2_HDR_BODY ) {
DEBUG ( 10 , ( " Got HDR len %d, expected %d \n " ,
SVAL ( hdr , 4 ) , SMB2_HDR_BODY ) ) ;
goto inval ;
}
full_size = len ;
next_command_ofs = IVAL ( hdr , SMB2_HDR_NEXT_COMMAND ) ;
body_size = SVAL ( hdr , SMB2_HDR_BODY ) ;
if ( next_command_ofs ! = 0 ) {
if ( next_command_ofs < ( SMB2_HDR_BODY + 2 ) ) {
goto inval ;
}
if ( next_command_ofs > full_size ) {
goto inval ;
}
full_size = next_command_ofs ;
}
if ( body_size < 2 ) {
goto inval ;
}
body_size & = 0xfffe ;
if ( body_size > ( full_size - SMB2_HDR_BODY ) ) {
goto inval ;
}
iov_tmp = talloc_realloc ( mem_ctx , iov , struct iovec ,
2012-07-23 10:11:59 +04:00
num_iov + 4 ) ;
2011-09-15 13:47:11 +04:00
if ( iov_tmp = = NULL ) {
TALLOC_FREE ( iov ) ;
return NT_STATUS_NO_MEMORY ;
}
iov = iov_tmp ;
cur = & iov [ num_iov ] ;
2012-07-23 10:11:59 +04:00
num_iov + = 4 ;
2011-09-15 13:47:11 +04:00
2012-07-23 10:11:59 +04:00
cur [ 0 ] . iov_base = tf ;
cur [ 0 ] . iov_len = tf_len ;
cur [ 1 ] . iov_base = hdr ;
cur [ 1 ] . iov_len = SMB2_HDR_BODY ;
cur [ 2 ] . iov_base = hdr + SMB2_HDR_BODY ;
cur [ 2 ] . iov_len = body_size ;
cur [ 3 ] . iov_base = hdr + SMB2_HDR_BODY + body_size ;
cur [ 3 ] . iov_len = full_size - ( SMB2_HDR_BODY + body_size ) ;
2011-09-15 13:47:11 +04:00
taken + = full_size ;
}
* piov = iov ;
* pnum_iov = num_iov ;
return NT_STATUS_OK ;
inval :
TALLOC_FREE ( iov ) ;
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
2011-09-15 14:23:05 +04:00
static struct tevent_req * smb2cli_conn_find_pending ( struct smbXcli_conn * conn ,
uint64_t mid )
2011-09-15 13:47:11 +04:00
{
2011-09-15 14:23:05 +04:00
size_t num_pending = talloc_array_length ( conn - > pending ) ;
size_t i ;
2011-09-15 13:47:11 +04:00
for ( i = 0 ; i < num_pending ; i + + ) {
2011-09-15 14:23:05 +04:00
struct tevent_req * req = conn - > pending [ i ] ;
struct smbXcli_req_state * state =
2011-09-15 13:47:11 +04:00
tevent_req_data ( req ,
2011-09-15 14:23:05 +04:00
struct smbXcli_req_state ) ;
2011-09-15 13:47:11 +04:00
2011-09-15 14:23:05 +04:00
if ( mid = = BVAL ( state - > smb2 . hdr , SMB2_HDR_MESSAGE_ID ) ) {
2011-09-15 13:47:11 +04:00
return req ;
}
}
return NULL ;
}
2011-09-15 14:23:05 +04:00
static NTSTATUS smb2cli_conn_dispatch_incoming ( struct smbXcli_conn * conn ,
TALLOC_CTX * tmp_mem ,
uint8_t * inbuf )
2011-09-15 13:47:11 +04:00
{
struct tevent_req * req ;
2011-09-15 14:23:05 +04:00
struct smbXcli_req_state * state = NULL ;
2016-06-07 06:42:15 +03:00
struct iovec * iov = NULL ;
2017-12-07 19:01:39 +03:00
size_t i , num_iov = 0 ;
2011-09-15 13:47:11 +04:00
NTSTATUS status ;
bool defer = true ;
2011-09-03 12:18:32 +04:00
struct smbXcli_session * last_session = NULL ;
2012-07-20 11:19:24 +04:00
size_t inbuf_len = smb_len_tcp ( inbuf ) ;
2011-09-15 13:47:11 +04:00
2012-07-20 11:19:24 +04:00
status = smb2cli_inbuf_parse_compound ( conn ,
inbuf + NBT_HDR_SIZE ,
inbuf_len ,
tmp_mem ,
2011-09-15 13:47:11 +04:00
& iov , & num_iov ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-09-15 14:23:05 +04:00
return status ;
2011-09-15 13:47:11 +04:00
}
2012-07-23 10:11:59 +04:00
for ( i = 0 ; i < num_iov ; i + = 4 ) {
2011-09-15 13:47:11 +04:00
uint8_t * inbuf_ref = NULL ;
struct iovec * cur = & iov [ i ] ;
2012-07-23 10:11:59 +04:00
uint8_t * inhdr = ( uint8_t * ) cur [ 1 ] . iov_base ;
2011-09-15 13:47:11 +04:00
uint16_t opcode = SVAL ( inhdr , SMB2_HDR_OPCODE ) ;
uint32_t flags = IVAL ( inhdr , SMB2_HDR_FLAGS ) ;
uint64_t mid = BVAL ( inhdr , SMB2_HDR_MESSAGE_ID ) ;
uint16_t req_opcode ;
2011-09-03 12:18:32 +04:00
uint32_t req_flags ;
2011-09-06 19:52:02 +04:00
uint16_t credits = SVAL ( inhdr , SMB2_HDR_CREDIT ) ;
uint32_t new_credits ;
2011-09-03 12:18:32 +04:00
struct smbXcli_session * session = NULL ;
2019-03-14 19:42:34 +03:00
struct smb2_signing_key * signing_key = NULL ;
2012-08-14 11:35:59 +04:00
bool was_encrypted = false ;
2011-09-06 19:52:02 +04:00
new_credits = conn - > smb2 . cur_credits ;
new_credits + = credits ;
if ( new_credits > UINT16_MAX ) {
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
conn - > smb2 . cur_credits + = credits ;
2011-09-15 13:47:11 +04:00
2011-09-15 14:23:05 +04:00
req = smb2cli_conn_find_pending ( conn , mid ) ;
2011-09-15 13:47:11 +04:00
if ( req = = NULL ) {
2011-09-15 14:23:05 +04:00
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
2011-09-15 13:47:11 +04:00
}
2011-09-15 14:23:05 +04:00
state = tevent_req_data ( req , struct smbXcli_req_state ) ;
2011-09-15 13:47:11 +04:00
2011-09-15 14:23:05 +04:00
req_opcode = SVAL ( state - > smb2 . hdr , SMB2_HDR_OPCODE ) ;
2011-09-15 13:47:11 +04:00
if ( opcode ! = req_opcode ) {
2011-09-15 14:23:05 +04:00
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
2011-09-15 13:47:11 +04:00
}
2011-09-03 12:18:32 +04:00
req_flags = SVAL ( state - > smb2 . hdr , SMB2_HDR_FLAGS ) ;
2011-09-15 13:47:11 +04:00
if ( ! ( flags & SMB2_HDR_FLAG_REDIRECT ) ) {
2011-09-15 14:23:05 +04:00
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
2011-09-15 13:47:11 +04:00
}
status = NT_STATUS ( IVAL ( inhdr , SMB2_HDR_STATUS ) ) ;
if ( ( flags & SMB2_HDR_FLAG_ASYNC ) & &
2020-06-19 22:55:13 +03:00
NT_STATUS_EQUAL ( status , NT_STATUS_PENDING ) ) {
2011-09-15 13:47:11 +04:00
uint64_t async_id = BVAL ( inhdr , SMB2_HDR_ASYNC_ID ) ;
2014-08-28 12:20:36 +04:00
if ( state - > smb2 . got_async ) {
/* We only expect one STATUS_PENDING response */
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
state - > smb2 . got_async = true ;
2011-09-03 12:18:32 +04:00
/*
* async interim responses are not signed ,
* even if the SMB2_HDR_FLAG_SIGNED flag
* is set .
*/
2021-05-07 00:07:13 +03:00
state - > smb2 . cancel_flags | = SMB2_HDR_FLAG_ASYNC ;
2015-05-08 13:05:06 +03:00
state - > smb2 . cancel_aid = async_id ;
2011-10-27 19:20:27 +04:00
if ( state - > smb2 . notify_async ) {
tevent_req_defer_callback ( req , state - > ev ) ;
tevent_req_notify_callback ( req ) ;
}
2011-09-15 13:47:11 +04:00
continue ;
}
2011-09-03 12:18:32 +04:00
session = state - > session ;
if ( req_flags & SMB2_HDR_FLAG_CHAINED ) {
session = last_session ;
}
last_session = session ;
if ( flags & SMB2_HDR_FLAG_SIGNED ) {
uint64_t uid = BVAL ( inhdr , SMB2_HDR_SESSION_ID ) ;
if ( session = = NULL ) {
2015-10-21 22:04:47 +03:00
session = smbXcli_session_by_uid ( state - > conn ,
uid ) ;
2011-09-03 12:18:32 +04:00
}
if ( session = = NULL ) {
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
last_session = session ;
2019-03-04 18:59:51 +03:00
signing_key = session - > smb2_channel . signing_key ;
2011-09-03 12:18:32 +04:00
}
2012-02-27 11:48:55 +04:00
if ( opcode = = SMB2_OP_SESSSETUP ) {
2011-09-03 12:18:32 +04:00
/*
2012-02-27 11:48:55 +04:00
* We prefer the channel signing key , if it is
* already there .
*
* If we do not have a channel signing key yet ,
* we try the main signing key , if it is not
* the final response .
2011-09-03 12:18:32 +04:00
*/
2019-06-07 20:00:25 +03:00
if ( signing_key ! = NULL & &
! smb2_signing_key_valid ( signing_key ) & &
2012-02-27 11:48:55 +04:00
! NT_STATUS_IS_OK ( status ) ) {
2019-03-04 18:59:51 +03:00
signing_key = session - > smb2 - > signing_key ;
2012-02-27 11:48:55 +04:00
}
2019-06-07 20:00:25 +03:00
if ( signing_key ! = NULL & &
! smb2_signing_key_valid ( signing_key ) ) {
2012-02-27 11:48:55 +04:00
/*
* If we do not have a session key to
* verify the signature , we defer the
* signing check to the caller .
*
* The caller gets NT_STATUS_OK , it
* has to call
* smb2cli_session_set_session_key ( )
* or
* smb2cli_session_set_channel_key ( )
* which will check the signature
* with the channel signing key .
*/
signing_key = NULL ;
}
2018-11-11 00:00:04 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
/*
* Only check the signature of the last response
2023-04-27 16:58:18 +03:00
* of a successful session auth . This matches
2018-11-11 00:00:04 +03:00
* Windows behaviour for NTLM auth and reauth .
*/
state - > smb2 . require_signed_response = false ;
}
2011-09-03 12:18:32 +04:00
}
2018-11-11 00:00:04 +03:00
if ( state - > smb2 . should_sign | |
state - > smb2 . require_signed_response )
{
2018-11-10 23:56:28 +03:00
if ( ! ( flags & SMB2_HDR_FLAG_SIGNED ) ) {
return NT_STATUS_ACCESS_DENIED ;
}
}
2019-03-04 18:59:51 +03:00
if ( ! smb2_signing_key_valid ( signing_key ) & &
state - > smb2 . require_signed_response ) {
signing_key = session - > smb2_channel . signing_key ;
2018-11-11 00:00:04 +03:00
}
2012-08-14 11:35:59 +04:00
if ( cur [ 0 ] . iov_len = = SMB2_TF_HDR_SIZE ) {
const uint8_t * tf = ( const uint8_t * ) cur [ 0 ] . iov_base ;
uint64_t uid = BVAL ( tf , SMB2_TF_SESSION_ID ) ;
/*
* If the response was encrypted in a SMB2_TRANSFORM
* pdu , which belongs to the correct session ,
* we do not need to do signing checks
*
* It could be the session the response belongs to
* or the session that was used to encrypt the
* SMB2_TRANSFORM request .
*/
if ( ( session & & session - > smb2 - > session_id = = uid ) | |
( state - > smb2 . encryption_session_id = = uid ) ) {
signing_key = NULL ;
was_encrypted = true ;
}
}
2011-09-03 12:18:32 +04:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_USER_SESSION_DELETED ) ) {
/*
* if the server returns NT_STATUS_USER_SESSION_DELETED
* the response is not signed and we should
* propagate the NT_STATUS_USER_SESSION_DELETED
* status to the caller .
*/
2012-08-14 11:35:59 +04:00
state - > smb2 . signing_skipped = true ;
2012-02-27 12:24:38 +04:00
signing_key = NULL ;
2012-08-14 11:35:59 +04:00
}
2021-03-08 04:03:30 +03:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_REQUEST_OUT_OF_SEQUENCE ) ) {
/*
* if the server returns
* NT_STATUS_REQUEST_OUT_OF_SEQUENCE for a session setup
* request , the response is not signed and we should
* propagate the NT_STATUS_REQUEST_OUT_OF_SEQUENCE
* status to the caller
*/
if ( opcode = = SMB2_OP_SESSSETUP ) {
state - > smb2 . signing_skipped = true ;
signing_key = NULL ;
}
}
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NOT_SUPPORTED ) ) {
/*
* if the server returns NT_STATUS_NOT_SUPPORTED
* for a session setup request , the response is not
* signed and we should propagate the NT_STATUS_NOT_SUPPORTED
* status to the caller .
*/
if ( opcode = = SMB2_OP_SESSSETUP ) {
state - > smb2 . signing_skipped = true ;
signing_key = NULL ;
}
}
if ( NT_STATUS_EQUAL ( status , NT_STATUS_ACCESS_DENIED ) ) {
/*
* if the server returns
* NT_STATUS_ACCESS_DENIED for a session setup
* request , the response is not signed and we should
* propagate the NT_STATUS_ACCESS_DENIED
* status to the caller without disconnecting
* the connection because we where not able to
* verify the response signature .
*/
if ( opcode = = SMB2_OP_SESSSETUP ) {
state - > smb2 . signing_skipped = true ;
signing_key = NULL ;
}
}
2012-08-14 11:35:59 +04:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_INVALID_PARAMETER ) ) {
/*
* if the server returns
* NT_STATUS_INVALID_PARAMETER
* the response might not be encrypted .
*/
if ( state - > smb2 . should_encrypt & & ! was_encrypted ) {
state - > smb2 . signing_skipped = true ;
signing_key = NULL ;
}
}
if ( state - > smb2 . should_encrypt & & ! was_encrypted ) {
if ( ! state - > smb2 . signing_skipped ) {
2012-07-23 12:14:53 +04:00
return NT_STATUS_ACCESS_DENIED ;
}
2011-09-03 12:18:32 +04:00
}
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NETWORK_NAME_DELETED ) | |
NT_STATUS_EQUAL ( status , NT_STATUS_FILE_CLOSED ) | |
NT_STATUS_EQUAL ( status , NT_STATUS_INVALID_PARAMETER ) ) {
/*
* if the server returns
* NT_STATUS_NETWORK_NAME_DELETED
* NT_STATUS_FILE_CLOSED
* NT_STATUS_INVALID_PARAMETER
* the response might not be signed
* as this happens before the signing checks .
*
* If server echos the signature ( or all zeros )
* we should report the status from the server
* to the caller .
*/
if ( signing_key ) {
2022-05-11 03:07:43 +03:00
bool cmp ;
2011-09-03 12:18:32 +04:00
2022-05-11 03:07:43 +03:00
cmp = mem_equal_const_time ( inhdr + SMB2_HDR_SIGNATURE ,
state - > smb2 . hdr + SMB2_HDR_SIGNATURE ,
16 ) ;
if ( cmp ) {
2011-09-03 12:18:32 +04:00
state - > smb2 . signing_skipped = true ;
signing_key = NULL ;
}
}
if ( signing_key ) {
2016-12-31 15:45:51 +03:00
bool zero ;
zero = all_zero ( inhdr + SMB2_HDR_SIGNATURE , 16 ) ;
if ( zero ) {
2011-09-03 12:18:32 +04:00
state - > smb2 . signing_skipped = true ;
signing_key = NULL ;
}
}
}
if ( signing_key ) {
2018-11-07 16:00:25 +03:00
NTSTATUS signing_status ;
2019-03-14 19:42:34 +03:00
signing_status = smb2_signing_check_pdu ( signing_key ,
2018-11-07 16:00:25 +03:00
& cur [ 1 ] , 3 ) ;
if ( ! NT_STATUS_IS_OK ( signing_status ) ) {
2011-09-03 12:18:32 +04:00
/*
* If the signing check fails , we disconnect
* the connection .
*/
2018-11-07 16:00:25 +03:00
return signing_status ;
2011-09-03 12:18:32 +04:00
}
}
2012-10-22 16:18:20 +04:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NETWORK_SESSION_EXPIRED ) & &
( session ! = NULL ) & & session - > disconnect_expired )
{
/*
* this should be a short term hack
* until the upper layers have implemented
* re - authentication .
*/
return status ;
}
2011-09-15 14:23:05 +04:00
smbXcli_req_unset_pending ( req ) ;
2011-09-15 13:47:11 +04:00
/*
* There might be more than one response
* we need to defer the notifications
*/
2012-07-23 10:11:59 +04:00
if ( ( num_iov = = 5 ) & & ( talloc_array_length ( conn - > pending ) = = 0 ) ) {
2011-09-15 13:47:11 +04:00
defer = false ;
}
if ( defer ) {
tevent_req_defer_callback ( req , state - > ev ) ;
}
/*
* Note : here we use talloc_reference ( ) in a way
* that does not expose it to the caller .
*/
2011-09-15 14:23:05 +04:00
inbuf_ref = talloc_reference ( state - > smb2 . recv_iov , inbuf ) ;
2011-09-15 13:47:11 +04:00
if ( tevent_req_nomem ( inbuf_ref , req ) ) {
continue ;
}
/* copy the related buffers */
2012-07-23 10:11:59 +04:00
state - > smb2 . recv_iov [ 0 ] = cur [ 1 ] ;
state - > smb2 . recv_iov [ 1 ] = cur [ 2 ] ;
state - > smb2 . recv_iov [ 2 ] = cur [ 3 ] ;
2011-09-15 13:47:11 +04:00
tevent_req_done ( req ) ;
}
2011-09-15 14:23:05 +04:00
if ( defer ) {
return NT_STATUS_RETRY ;
2011-09-15 13:47:11 +04:00
}
2011-09-15 14:23:05 +04:00
return NT_STATUS_OK ;
2011-09-15 13:47:11 +04:00
}
NTSTATUS smb2cli_req_recv ( struct tevent_req * req , TALLOC_CTX * mem_ctx ,
struct iovec * * piov ,
const struct smb2cli_req_expected_response * expected ,
size_t num_expected )
{
2011-09-15 14:23:05 +04:00
struct smbXcli_req_state * state =
2011-09-15 13:47:11 +04:00
tevent_req_data ( req ,
2011-09-15 14:23:05 +04:00
struct smbXcli_req_state ) ;
2011-09-15 13:47:11 +04:00
NTSTATUS status ;
size_t body_size ;
bool found_status = false ;
bool found_size = false ;
size_t i ;
if ( piov ! = NULL ) {
* piov = NULL ;
}
2014-08-28 12:20:36 +04:00
if ( tevent_req_is_in_progress ( req ) & & state - > smb2 . got_async ) {
2020-06-19 22:55:13 +03:00
return NT_STATUS_PENDING ;
2011-10-27 19:20:27 +04:00
}
2011-09-15 13:47:11 +04:00
if ( tevent_req_is_nterror ( req , & status ) ) {
for ( i = 0 ; i < num_expected ; i + + ) {
if ( NT_STATUS_EQUAL ( status , expected [ i ] . status ) ) {
2020-06-09 17:15:46 +03:00
return NT_STATUS_UNEXPECTED_NETWORK_ERROR ;
2011-09-15 13:47:11 +04:00
}
}
return status ;
}
if ( num_expected = = 0 ) {
found_status = true ;
found_size = true ;
}
2011-09-15 14:23:05 +04:00
status = NT_STATUS ( IVAL ( state - > smb2 . recv_iov [ 0 ] . iov_base , SMB2_HDR_STATUS ) ) ;
body_size = SVAL ( state - > smb2 . recv_iov [ 1 ] . iov_base , 0 ) ;
2011-09-15 13:47:11 +04:00
for ( i = 0 ; i < num_expected ; i + + ) {
if ( ! NT_STATUS_EQUAL ( status , expected [ i ] . status ) ) {
continue ;
}
found_status = true ;
if ( expected [ i ] . body_size = = 0 ) {
found_size = true ;
break ;
}
if ( expected [ i ] . body_size = = body_size ) {
found_size = true ;
break ;
}
}
if ( ! found_status ) {
return status ;
}
2011-09-03 12:18:32 +04:00
if ( state - > smb2 . signing_skipped ) {
if ( num_expected > 0 ) {
return NT_STATUS_ACCESS_DENIED ;
}
if ( ! NT_STATUS_IS_ERR ( status ) ) {
return NT_STATUS_ACCESS_DENIED ;
}
}
2011-09-15 13:47:11 +04:00
if ( ! found_size ) {
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
if ( piov ! = NULL ) {
2011-09-15 14:23:05 +04:00
* piov = talloc_move ( mem_ctx , & state - > smb2 . recv_iov ) ;
2011-09-15 13:47:11 +04:00
}
return status ;
}
2011-09-15 15:12:43 +04:00
2014-09-24 10:59:58 +04:00
NTSTATUS smb2cli_req_get_sent_iov ( struct tevent_req * req ,
struct iovec * sent_iov )
{
struct smbXcli_req_state * state =
tevent_req_data ( req ,
struct smbXcli_req_state ) ;
if ( tevent_req_is_in_progress ( req ) ) {
2020-06-19 22:55:13 +03:00
return NT_STATUS_PENDING ;
2014-09-24 10:59:58 +04:00
}
sent_iov [ 0 ] . iov_base = state - > smb2 . hdr ;
sent_iov [ 0 ] . iov_len = sizeof ( state - > smb2 . hdr ) ;
sent_iov [ 1 ] . iov_base = discard_const ( state - > smb2 . fixed ) ;
sent_iov [ 1 ] . iov_len = state - > smb2 . fixed_len ;
if ( state - > smb2 . dyn ! = NULL ) {
sent_iov [ 2 ] . iov_base = discard_const ( state - > smb2 . dyn ) ;
sent_iov [ 2 ] . iov_len = state - > smb2 . dyn_len ;
} else {
sent_iov [ 2 ] . iov_base = NULL ;
sent_iov [ 2 ] . iov_len = 0 ;
}
return NT_STATUS_OK ;
}
2011-09-15 15:12:43 +04:00
static const struct {
enum protocol_types proto ;
const char * smb1_name ;
} smb1cli_prots [ ] = {
{ PROTOCOL_CORE , " PC NETWORK PROGRAM 1.0 " } ,
{ PROTOCOL_COREPLUS , " MICROSOFT NETWORKS 1.03 " } ,
{ PROTOCOL_LANMAN1 , " MICROSOFT NETWORKS 3.0 " } ,
{ PROTOCOL_LANMAN1 , " LANMAN1.0 " } ,
{ PROTOCOL_LANMAN2 , " LM1.2X002 " } ,
{ PROTOCOL_LANMAN2 , " DOS LANMAN2.1 " } ,
{ PROTOCOL_LANMAN2 , " LANMAN2.1 " } ,
{ PROTOCOL_LANMAN2 , " Samba " } ,
{ PROTOCOL_NT1 , " NT LANMAN 1.0 " } ,
{ PROTOCOL_NT1 , " NT LM 0.12 " } ,
{ PROTOCOL_SMB2_02 , " SMB 2.002 " } ,
2011-08-30 13:04:46 +04:00
{ PROTOCOL_SMB2_10 , " SMB 2.??? " } ,
2011-09-15 15:12:43 +04:00
} ;
static const struct {
enum protocol_types proto ;
uint16_t smb2_dialect ;
} smb2cli_prots [ ] = {
{ PROTOCOL_SMB2_02 , SMB2_DIALECT_REVISION_202 } ,
2011-08-30 13:04:46 +04:00
{ PROTOCOL_SMB2_10 , SMB2_DIALECT_REVISION_210 } ,
2012-05-05 11:33:43 +04:00
{ PROTOCOL_SMB3_00 , SMB3_DIALECT_REVISION_300 } ,
2013-09-13 13:27:01 +04:00
{ PROTOCOL_SMB3_02 , SMB3_DIALECT_REVISION_302 } ,
2015-03-04 09:02:38 +03:00
{ PROTOCOL_SMB3_11 , SMB3_DIALECT_REVISION_311 } ,
2011-09-15 15:12:43 +04:00
} ;
struct smbXcli_negprot_state {
struct smbXcli_conn * conn ;
struct tevent_context * ev ;
2022-08-25 10:54:52 +03:00
struct smb2_negotiate_contexts * in_ctx ;
struct smb2_negotiate_contexts * out_ctx ;
2011-09-15 15:12:43 +04:00
uint32_t timeout_msec ;
struct {
uint8_t fixed [ 36 ] ;
} smb2 ;
} ;
static void smbXcli_negprot_invalid_done ( struct tevent_req * subreq ) ;
static struct tevent_req * smbXcli_negprot_smb1_subreq ( struct smbXcli_negprot_state * state ) ;
static void smbXcli_negprot_smb1_done ( struct tevent_req * subreq ) ;
static struct tevent_req * smbXcli_negprot_smb2_subreq ( struct smbXcli_negprot_state * state ) ;
static void smbXcli_negprot_smb2_done ( struct tevent_req * subreq ) ;
static NTSTATUS smbXcli_negprot_dispatch_incoming ( struct smbXcli_conn * conn ,
TALLOC_CTX * frame ,
uint8_t * inbuf ) ;
struct tevent_req * smbXcli_negprot_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct smbXcli_conn * conn ,
uint32_t timeout_msec ,
enum protocol_types min_protocol ,
2017-02-27 18:14:39 +03:00
enum protocol_types max_protocol ,
2022-08-25 10:54:52 +03:00
uint16_t max_credits ,
struct smb2_negotiate_contexts * in_ctx )
2011-09-15 15:12:43 +04:00
{
struct tevent_req * req , * subreq ;
struct smbXcli_negprot_state * state ;
req = tevent_req_create ( mem_ctx , & state ,
struct smbXcli_negprot_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > conn = conn ;
state - > ev = ev ;
2022-08-25 10:54:52 +03:00
state - > in_ctx = in_ctx ;
2011-09-15 15:12:43 +04:00
state - > timeout_msec = timeout_msec ;
if ( min_protocol = = PROTOCOL_NONE ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER_MIX ) ;
return tevent_req_post ( req , ev ) ;
}
if ( max_protocol = = PROTOCOL_NONE ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER_MIX ) ;
return tevent_req_post ( req , ev ) ;
}
if ( min_protocol > max_protocol ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER_MIX ) ;
return tevent_req_post ( req , ev ) ;
}
2014-09-26 23:15:00 +04:00
conn - > min_protocol = min_protocol ;
conn - > max_protocol = max_protocol ;
conn - > protocol = PROTOCOL_NONE ;
2017-02-27 18:14:39 +03:00
if ( max_protocol > = PROTOCOL_SMB2_02 ) {
conn - > smb2 . max_credits = max_credits ;
}
2011-09-15 15:12:43 +04:00
if ( ( min_protocol < PROTOCOL_SMB2_02 ) & &
( max_protocol < PROTOCOL_SMB2_02 ) ) {
/*
* SMB1 only . . .
*/
conn - > dispatch_incoming = smb1cli_conn_dispatch_incoming ;
subreq = smbXcli_negprot_smb1_subreq ( state ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , smbXcli_negprot_smb1_done , req ) ;
return req ;
}
if ( ( min_protocol > = PROTOCOL_SMB2_02 ) & &
( max_protocol > = PROTOCOL_SMB2_02 ) ) {
/*
* SMB2 only . . .
*/
conn - > dispatch_incoming = smb2cli_conn_dispatch_incoming ;
subreq = smbXcli_negprot_smb2_subreq ( state ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , smbXcli_negprot_smb2_done , req ) ;
return req ;
}
/*
* We send an SMB1 negprot with the SMB2 dialects
* and expect a SMB1 or a SMB2 response .
*
* smbXcli_negprot_dispatch_incoming ( ) will fix the
* callback to match protocol of the response .
*/
conn - > dispatch_incoming = smbXcli_negprot_dispatch_incoming ;
subreq = smbXcli_negprot_smb1_subreq ( state ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , smbXcli_negprot_invalid_done , req ) ;
return req ;
}
static void smbXcli_negprot_invalid_done ( struct tevent_req * subreq )
{
struct tevent_req * req =
tevent_req_callback_data ( subreq ,
struct tevent_req ) ;
NTSTATUS status ;
/*
* we just want the low level error
*/
status = tevent_req_simple_recv_ntstatus ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
/* this should never happen */
tevent_req_nterror ( req , NT_STATUS_INTERNAL_ERROR ) ;
}
static struct tevent_req * smbXcli_negprot_smb1_subreq ( struct smbXcli_negprot_state * state )
{
size_t i ;
DATA_BLOB bytes = data_blob_null ;
uint8_t flags ;
uint16_t flags2 ;
/* setup the protocol strings */
for ( i = 0 ; i < ARRAY_SIZE ( smb1cli_prots ) ; i + + ) {
uint8_t c = 2 ;
bool ok ;
2014-09-26 23:15:00 +04:00
if ( smb1cli_prots [ i ] . proto < state - > conn - > min_protocol ) {
2011-09-15 15:12:43 +04:00
continue ;
}
2014-09-26 23:15:00 +04:00
if ( smb1cli_prots [ i ] . proto > state - > conn - > max_protocol ) {
2011-09-15 15:12:43 +04:00
continue ;
}
ok = data_blob_append ( state , & bytes , & c , sizeof ( c ) ) ;
if ( ! ok ) {
return NULL ;
}
/*
2023-09-06 01:54:46 +03:00
* We know it is already ascii and
2011-09-15 15:12:43 +04:00
* we want NULL termination .
*/
ok = data_blob_append ( state , & bytes ,
smb1cli_prots [ i ] . smb1_name ,
strlen ( smb1cli_prots [ i ] . smb1_name ) + 1 ) ;
if ( ! ok ) {
return NULL ;
}
}
2014-09-26 23:15:00 +04:00
smb1cli_req_flags ( state - > conn - > max_protocol ,
2011-09-15 15:12:43 +04:00
state - > conn - > smb1 . client . capabilities ,
SMBnegprot ,
0 , 0 , & flags ,
0 , 0 , & flags2 ) ;
return smb1cli_req_send ( state , state - > ev , state - > conn ,
SMBnegprot ,
flags , ~ flags ,
flags2 , ~ flags2 ,
state - > timeout_msec ,
2012-07-23 22:15:21 +04:00
0xFFFE , 0 , NULL , /* pid, tid, session */
2011-09-15 15:12:43 +04:00
0 , NULL , /* wct, vwv */
bytes . length , bytes . data ) ;
}
static void smbXcli_negprot_smb1_done ( struct tevent_req * subreq )
{
struct tevent_req * req =
tevent_req_callback_data ( subreq ,
struct tevent_req ) ;
struct smbXcli_negprot_state * state =
tevent_req_data ( req ,
struct smbXcli_negprot_state ) ;
struct smbXcli_conn * conn = state - > conn ;
struct iovec * recv_iov = NULL ;
2019-07-10 13:37:34 +03:00
uint8_t * inhdr = NULL ;
2011-09-15 15:12:43 +04:00
uint8_t wct ;
uint16_t * vwv ;
uint32_t num_bytes ;
uint8_t * bytes ;
NTSTATUS status ;
uint16_t protnum ;
size_t i ;
size_t num_prots = 0 ;
uint8_t flags ;
uint32_t client_capabilities = conn - > smb1 . client . capabilities ;
uint32_t both_capabilities ;
uint32_t server_capabilities = 0 ;
uint32_t capabilities ;
uint32_t client_max_xmit = conn - > smb1 . client . max_xmit ;
uint32_t server_max_xmit = 0 ;
uint32_t max_xmit ;
uint32_t server_max_mux = 0 ;
uint16_t server_security_mode = 0 ;
uint32_t server_session_key = 0 ;
bool server_readbraw = false ;
bool server_writebraw = false ;
bool server_lockread = false ;
bool server_writeunlock = false ;
struct GUID server_guid = GUID_zero ( ) ;
DATA_BLOB server_gss_blob = data_blob_null ;
uint8_t server_challenge [ 8 ] ;
char * server_workgroup = NULL ;
char * server_name = NULL ;
int server_time_zone = 0 ;
NTTIME server_system_time = 0 ;
static const struct smb1cli_req_expected_response expected [ ] = {
{
. status = NT_STATUS_OK ,
. wct = 0x11 , /* NT1 */
} ,
{
. status = NT_STATUS_OK ,
. wct = 0x0D , /* LM */
} ,
{
. status = NT_STATUS_OK ,
. wct = 0x01 , /* CORE */
}
} ;
ZERO_STRUCT ( server_challenge ) ;
status = smb1cli_req_recv ( subreq , state ,
& recv_iov ,
& inhdr ,
& wct ,
& vwv ,
NULL , /* pvwv_offset */
& num_bytes ,
& bytes ,
NULL , /* pbytes_offset */
NULL , /* pinbuf */
expected , ARRAY_SIZE ( expected ) ) ;
TALLOC_FREE ( subreq ) ;
2022-08-22 06:50:02 +03:00
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
if ( inhdr = = NULL ) {
tevent_req_nterror ( req , NT_STATUS_INTERNAL_ERROR ) ;
2011-09-15 15:12:43 +04:00
return ;
}
flags = CVAL ( inhdr , HDR_FLG ) ;
protnum = SVAL ( vwv , 0 ) ;
for ( i = 0 ; i < ARRAY_SIZE ( smb1cli_prots ) ; i + + ) {
2014-09-26 23:15:00 +04:00
if ( smb1cli_prots [ i ] . proto < state - > conn - > min_protocol ) {
2011-09-15 15:12:43 +04:00
continue ;
}
2014-09-26 23:15:00 +04:00
if ( smb1cli_prots [ i ] . proto > state - > conn - > max_protocol ) {
2011-09-15 15:12:43 +04:00
continue ;
}
if ( protnum ! = num_prots ) {
num_prots + + ;
continue ;
}
conn - > protocol = smb1cli_prots [ i ] . proto ;
break ;
}
if ( conn - > protocol = = PROTOCOL_NONE ) {
2018-09-27 00:53:24 +03:00
DBG_ERR ( " No compatible protocol selected by server. \n " ) ;
2011-09-15 15:12:43 +04:00
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
if ( ( conn - > protocol < PROTOCOL_NT1 ) & & conn - > mandatory_signing ) {
DEBUG ( 0 , ( " smbXcli_negprot: SMB signing is mandatory "
" and the selected protocol level doesn't support it. \n " ) ) ;
tevent_req_nterror ( req , NT_STATUS_ACCESS_DENIED ) ;
return ;
}
if ( flags & FLAG_SUPPORT_LOCKREAD ) {
server_lockread = true ;
server_writeunlock = true ;
}
if ( conn - > protocol > = PROTOCOL_NT1 ) {
const char * client_signing = NULL ;
bool server_mandatory = false ;
bool server_allowed = false ;
const char * server_signing = NULL ;
bool ok ;
uint8_t key_len ;
if ( wct ! = 0x11 ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
/* NT protocol */
server_security_mode = CVAL ( vwv + 1 , 0 ) ;
server_max_mux = SVAL ( vwv + 1 , 1 ) ;
server_max_xmit = IVAL ( vwv + 3 , 1 ) ;
server_session_key = IVAL ( vwv + 7 , 1 ) ;
server_time_zone = SVALS ( vwv + 15 , 1 ) ;
server_time_zone * = 60 ;
/* this time arrives in real GMT */
server_system_time = BVAL ( vwv + 11 , 1 ) ;
server_capabilities = IVAL ( vwv + 9 , 1 ) ;
key_len = CVAL ( vwv + 16 , 1 ) ;
if ( server_capabilities & CAP_RAW_MODE ) {
server_readbraw = true ;
server_writebraw = true ;
}
if ( server_capabilities & CAP_LOCK_AND_READ ) {
server_lockread = true ;
}
if ( server_capabilities & CAP_EXTENDED_SECURITY ) {
DATA_BLOB blob1 , blob2 ;
if ( num_bytes < 16 ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
blob1 = data_blob_const ( bytes , 16 ) ;
status = GUID_from_data_blob ( & blob1 , & server_guid ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
blob1 = data_blob_const ( bytes + 16 , num_bytes - 16 ) ;
blob2 = data_blob_dup_talloc ( state , blob1 ) ;
if ( blob1 . length > 0 & &
tevent_req_nomem ( blob2 . data , req ) ) {
return ;
}
server_gss_blob = blob2 ;
} else {
DATA_BLOB blob1 , blob2 ;
if ( num_bytes < key_len ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
if ( key_len ! = 0 & & key_len ! = 8 ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
if ( key_len = = 8 ) {
memcpy ( server_challenge , bytes , 8 ) ;
}
blob1 = data_blob_const ( bytes + key_len , num_bytes - key_len ) ;
blob2 = data_blob_const ( bytes + key_len , num_bytes - key_len ) ;
if ( blob1 . length > 0 ) {
size_t len ;
2023-11-09 02:33:43 +03:00
len = utf16_null_terminated_len_n ( blob1 . data ,
blob1 . length ) ;
2011-09-15 15:12:43 +04:00
blob1 . length = len ;
ok = convert_string_talloc ( state ,
CH_UTF16LE ,
CH_UNIX ,
blob1 . data ,
blob1 . length ,
& server_workgroup ,
& len ) ;
if ( ! ok ) {
status = map_nt_error_from_unix_common ( errno ) ;
tevent_req_nterror ( req , status ) ;
return ;
}
}
blob2 . data + = blob1 . length ;
blob2 . length - = blob1 . length ;
if ( blob2 . length > 0 ) {
size_t len ;
ok = convert_string_talloc ( state ,
CH_UTF16LE ,
CH_UNIX ,
blob2 . data ,
blob2 . length ,
& server_name ,
& len ) ;
if ( ! ok ) {
status = map_nt_error_from_unix_common ( errno ) ;
tevent_req_nterror ( req , status ) ;
return ;
}
}
}
client_signing = " disabled " ;
if ( conn - > allow_signing ) {
client_signing = " allowed " ;
}
if ( conn - > mandatory_signing ) {
client_signing = " required " ;
}
server_signing = " not supported " ;
if ( server_security_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED ) {
server_signing = " supported " ;
server_allowed = true ;
2013-03-18 18:02:55 +04:00
} else if ( conn - > mandatory_signing ) {
/*
* We have mandatory signing as client
* lets assume the server will look at our
* FLAGS2_SMB_SECURITY_SIGNATURES_REQUIRED
* flag in the session setup
*/
server_signing = " not announced " ;
server_allowed = true ;
2011-09-15 15:12:43 +04:00
}
if ( server_security_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED ) {
server_signing = " required " ;
server_mandatory = true ;
}
2022-03-08 06:38:35 +03:00
ok = smb1_signing_set_negotiated ( conn - > smb1 . signing ,
2011-09-15 15:12:43 +04:00
server_allowed ,
server_mandatory ) ;
if ( ! ok ) {
DEBUG ( 1 , ( " cli_negprot: SMB signing is required, "
" but client[%s] and server[%s] mismatch \n " ,
client_signing , server_signing ) ) ;
tevent_req_nterror ( req , NT_STATUS_ACCESS_DENIED ) ;
return ;
}
} else if ( conn - > protocol > = PROTOCOL_LANMAN1 ) {
DATA_BLOB blob1 ;
uint8_t key_len ;
time_t t ;
if ( wct ! = 0x0D ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
server_security_mode = SVAL ( vwv + 1 , 0 ) ;
server_max_xmit = SVAL ( vwv + 2 , 0 ) ;
server_max_mux = SVAL ( vwv + 3 , 0 ) ;
server_readbraw = ( ( SVAL ( vwv + 5 , 0 ) & 0x1 ) ! = 0 ) ;
server_writebraw = ( ( SVAL ( vwv + 5 , 0 ) & 0x2 ) ! = 0 ) ;
server_session_key = IVAL ( vwv + 6 , 0 ) ;
server_time_zone = SVALS ( vwv + 10 , 0 ) ;
server_time_zone * = 60 ;
/* this time is converted to GMT by make_unix_date */
t = pull_dos_date ( ( const uint8_t * ) ( vwv + 8 ) , server_time_zone ) ;
unix_to_nt_time ( & server_system_time , t ) ;
key_len = SVAL ( vwv + 11 , 0 ) ;
if ( num_bytes < key_len ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
if ( key_len ! = 0 & & key_len ! = 8 ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
if ( key_len = = 8 ) {
memcpy ( server_challenge , bytes , 8 ) ;
}
blob1 = data_blob_const ( bytes + key_len , num_bytes - key_len ) ;
if ( blob1 . length > 0 ) {
size_t len ;
bool ok ;
2023-11-09 02:33:43 +03:00
len = utf16_null_terminated_len_n ( blob1 . data ,
blob1 . length ) ;
2011-09-15 15:12:43 +04:00
blob1 . length = len ;
ok = convert_string_talloc ( state ,
CH_DOS ,
CH_UNIX ,
blob1 . data ,
blob1 . length ,
& server_workgroup ,
& len ) ;
if ( ! ok ) {
status = map_nt_error_from_unix_common ( errno ) ;
tevent_req_nterror ( req , status ) ;
return ;
}
}
} else {
/* the old core protocol */
server_time_zone = get_time_zone ( time ( NULL ) ) ;
server_max_xmit = 1024 ;
server_max_mux = 1 ;
}
if ( server_max_xmit < 1024 ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
if ( server_max_mux < 1 ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
/*
* Now calculate the negotiated capabilities
* based on the mask for :
* - client only flags
* - flags used in both directions
* - server only flags
*/
both_capabilities = client_capabilities & server_capabilities ;
capabilities = client_capabilities & SMB_CAP_CLIENT_MASK ;
capabilities | = both_capabilities & SMB_CAP_BOTH_MASK ;
capabilities | = server_capabilities & SMB_CAP_SERVER_MASK ;
max_xmit = MIN ( client_max_xmit , server_max_xmit ) ;
conn - > smb1 . server . capabilities = server_capabilities ;
conn - > smb1 . capabilities = capabilities ;
conn - > smb1 . server . max_xmit = server_max_xmit ;
conn - > smb1 . max_xmit = max_xmit ;
conn - > smb1 . server . max_mux = server_max_mux ;
conn - > smb1 . server . security_mode = server_security_mode ;
conn - > smb1 . server . readbraw = server_readbraw ;
conn - > smb1 . server . writebraw = server_writebraw ;
conn - > smb1 . server . lockread = server_lockread ;
conn - > smb1 . server . writeunlock = server_writeunlock ;
conn - > smb1 . server . session_key = server_session_key ;
talloc_steal ( conn , server_gss_blob . data ) ;
conn - > smb1 . server . gss_blob = server_gss_blob ;
conn - > smb1 . server . guid = server_guid ;
memcpy ( conn - > smb1 . server . challenge , server_challenge , 8 ) ;
conn - > smb1 . server . workgroup = talloc_move ( conn , & server_workgroup ) ;
conn - > smb1 . server . name = talloc_move ( conn , & server_name ) ;
conn - > smb1 . server . time_zone = server_time_zone ;
conn - > smb1 . server . system_time = server_system_time ;
tevent_req_done ( req ) ;
}
2014-09-23 06:09:16 +04:00
static size_t smbXcli_padding_helper ( uint32_t offset , size_t n )
{
if ( ( offset & ( n - 1 ) ) = = 0 ) return 0 ;
return n - ( offset & ( n - 1 ) ) ;
}
2011-09-15 15:12:43 +04:00
static struct tevent_req * smbXcli_negprot_smb2_subreq ( struct smbXcli_negprot_state * state )
{
size_t i ;
uint8_t * buf ;
uint16_t dialect_count = 0 ;
2014-09-23 06:09:16 +04:00
DATA_BLOB dyn = data_blob_null ;
2011-09-15 15:12:43 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( smb2cli_prots ) ; i + + ) {
2014-09-23 06:09:16 +04:00
bool ok ;
uint8_t val [ 2 ] ;
2014-09-26 23:15:00 +04:00
if ( smb2cli_prots [ i ] . proto < state - > conn - > min_protocol ) {
2011-09-15 15:12:43 +04:00
continue ;
}
2014-09-26 23:15:00 +04:00
if ( smb2cli_prots [ i ] . proto > state - > conn - > max_protocol ) {
2011-09-15 15:12:43 +04:00
continue ;
}
2014-09-23 06:09:16 +04:00
SSVAL ( val , 0 , smb2cli_prots [ i ] . smb2_dialect ) ;
ok = data_blob_append ( state , & dyn , val , sizeof ( val ) ) ;
if ( ! ok ) {
return NULL ;
}
2011-09-15 15:12:43 +04:00
dialect_count + + ;
}
buf = state - > smb2 . fixed ;
SSVAL ( buf , 0 , 36 ) ;
SSVAL ( buf , 2 , dialect_count ) ;
SSVAL ( buf , 4 , state - > conn - > smb2 . client . security_mode ) ;
SSVAL ( buf , 6 , 0 ) ; /* Reserved */
2020-11-11 17:14:12 +03:00
if ( state - > conn - > max_protocol > = PROTOCOL_SMB3_00 ) {
2012-02-29 05:02:29 +04:00
SIVAL ( buf , 8 , state - > conn - > smb2 . client . capabilities ) ;
} else {
SIVAL ( buf , 8 , 0 ) ; /* Capabilities */
}
2014-09-26 23:15:00 +04:00
if ( state - > conn - > max_protocol > = PROTOCOL_SMB2_10 ) {
2011-08-30 13:04:46 +04:00
NTSTATUS status ;
2020-09-29 11:53:42 +03:00
struct GUID_ndr_buf guid_buf = { . buf = { 0 } , } ;
2011-08-30 13:04:46 +04:00
2020-09-29 11:53:42 +03:00
status = GUID_to_ndr_buf ( & state - > conn - > smb2 . client . guid ,
& guid_buf ) ;
2011-08-30 13:04:46 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return NULL ;
}
2020-09-29 11:53:42 +03:00
memcpy ( buf + 12 , guid_buf . buf , 16 ) ; /* ClientGuid */
2011-08-30 13:04:46 +04:00
} else {
memset ( buf + 12 , 0 , 16 ) ; /* ClientGuid */
}
2014-09-23 06:09:16 +04:00
2020-11-11 17:14:12 +03:00
if ( state - > conn - > max_protocol > = PROTOCOL_SMB3_11 ) {
2021-03-11 13:04:14 +03:00
const struct smb3_signing_capabilities * client_sign_algos =
& state - > conn - > smb2 . client . smb3_capabilities . signing ;
2021-03-10 01:38:51 +03:00
const struct smb3_encryption_capabilities * client_ciphers =
& state - > conn - > smb2 . client . smb3_capabilities . encryption ;
2014-09-23 06:09:16 +04:00
NTSTATUS status ;
struct smb2_negotiate_contexts c = { . num_contexts = 0 , } ;
2019-07-25 15:38:26 +03:00
uint8_t * netname_utf16 = NULL ;
size_t netname_utf16_len = 0 ;
2014-09-23 06:09:16 +04:00
uint32_t offset ;
DATA_BLOB b ;
uint8_t p [ 38 ] ;
const uint8_t zeros [ 8 ] = { 0 , } ;
size_t pad ;
bool ok ;
SSVAL ( p , 0 , 1 ) ; /* HashAlgorithmCount */
SSVAL ( p , 2 , 32 ) ; /* SaltLength */
SSVAL ( p , 4 , SMB2_PREAUTH_INTEGRITY_SHA512 ) ;
generate_random_buffer ( p + 6 , 32 ) ;
2019-02-11 11:03:39 +03:00
status = smb2_negotiate_context_add (
state , & c , SMB2_PREAUTH_INTEGRITY_CAPABILITIES , p , 38 ) ;
2014-09-23 06:09:16 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return NULL ;
}
2021-03-10 01:38:51 +03:00
if ( client_ciphers - > num_algos > 0 ) {
size_t ofs = 0 ;
SSVAL ( p , ofs , client_ciphers - > num_algos ) ;
ofs + = 2 ;
2019-03-15 18:25:28 +03:00
2021-03-10 01:38:51 +03:00
for ( i = 0 ; i < client_ciphers - > num_algos ; i + + ) {
size_t next_ofs = ofs + 2 ;
SMB_ASSERT ( next_ofs < ARRAY_SIZE ( p ) ) ;
SSVAL ( p , ofs , client_ciphers - > algos [ i ] ) ;
ofs = next_ofs ;
}
2014-09-23 06:09:16 +04:00
2021-03-10 01:38:51 +03:00
status = smb2_negotiate_context_add (
state , & c , SMB2_ENCRYPTION_CAPABILITIES , p , ofs ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return NULL ;
}
2014-09-23 06:09:16 +04:00
}
2021-03-11 13:04:14 +03:00
if ( client_sign_algos - > num_algos > 0 ) {
size_t ofs = 0 ;
SSVAL ( p , ofs , client_sign_algos - > num_algos ) ;
ofs + = 2 ;
for ( i = 0 ; i < client_sign_algos - > num_algos ; i + + ) {
size_t next_ofs = ofs + 2 ;
SMB_ASSERT ( next_ofs < ARRAY_SIZE ( p ) ) ;
SSVAL ( p , ofs , client_sign_algos - > algos [ i ] ) ;
ofs = next_ofs ;
}
status = smb2_negotiate_context_add (
state , & c , SMB2_SIGNING_CAPABILITIES , p , ofs ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return NULL ;
}
}
2019-07-25 15:38:26 +03:00
ok = convert_string_talloc ( state , CH_UNIX , CH_UTF16 ,
state - > conn - > remote_name ,
strlen ( state - > conn - > remote_name ) ,
& netname_utf16 , & netname_utf16_len ) ;
if ( ! ok ) {
return NULL ;
}
status = smb2_negotiate_context_add ( state , & c ,
SMB2_NETNAME_NEGOTIATE_CONTEXT_ID ,
netname_utf16 , netname_utf16_len ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return NULL ;
}
2022-08-25 10:54:52 +03:00
if ( state - > in_ctx ! = NULL ) {
struct smb2_negotiate_contexts * ctxs = state - > in_ctx ;
for ( i = 0 ; i < ctxs - > num_contexts ; i + + ) {
struct smb2_negotiate_context * ctx =
& ctxs - > contexts [ i ] ;
status = smb2_negotiate_context_add (
state ,
& c ,
ctx - > type ,
ctx - > data . data ,
ctx - > data . length ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return NULL ;
}
}
}
2014-09-23 06:09:16 +04:00
status = smb2_negotiate_context_push ( state , & b , c ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return NULL ;
}
offset = SMB2_HDR_BODY + sizeof ( state - > smb2 . fixed ) + dyn . length ;
pad = smbXcli_padding_helper ( offset , 8 ) ;
ok = data_blob_append ( state , & dyn , zeros , pad ) ;
if ( ! ok ) {
return NULL ;
}
offset + = pad ;
ok = data_blob_append ( state , & dyn , b . data , b . length ) ;
if ( ! ok ) {
return NULL ;
}
SIVAL ( buf , 28 , offset ) ; /* NegotiateContextOffset */
SSVAL ( buf , 32 , c . num_contexts ) ; /* NegotiateContextCount */
SSVAL ( buf , 34 , 0 ) ; /* Reserved */
} else {
SBVAL ( buf , 28 , 0 ) ; /* Reserved/ClientStartTime */
}
2011-09-15 15:12:43 +04:00
return smb2cli_req_send ( state , state - > ev ,
state - > conn , SMB2_OP_NEGPROT ,
0 , 0 , /* flags */
state - > timeout_msec ,
2012-07-25 12:58:34 +04:00
NULL , NULL , /* tcon, session */
2011-09-15 15:12:43 +04:00
state - > smb2 . fixed , sizeof ( state - > smb2 . fixed ) ,
2014-09-23 06:09:16 +04:00
dyn . data , dyn . length ,
2013-08-13 12:25:52 +04:00
UINT16_MAX ) ; /* max_dyn_len */
2011-09-15 15:12:43 +04:00
}
2021-07-14 13:13:49 +03:00
static NTSTATUS smbXcli_negprot_smb3_check_capabilities ( struct tevent_req * req ) ;
2011-09-15 15:12:43 +04:00
static void smbXcli_negprot_smb2_done ( struct tevent_req * subreq )
{
struct tevent_req * req =
tevent_req_callback_data ( subreq ,
struct tevent_req ) ;
struct smbXcli_negprot_state * state =
tevent_req_data ( req ,
struct smbXcli_negprot_state ) ;
struct smbXcli_conn * conn = state - > conn ;
size_t security_offset , security_length ;
DATA_BLOB blob ;
NTSTATUS status ;
2019-07-10 13:41:29 +03:00
struct iovec * iov = NULL ;
2011-09-15 15:12:43 +04:00
uint8_t * body ;
size_t i ;
uint16_t dialect_revision ;
2014-09-23 06:09:16 +04:00
uint32_t negotiate_context_offset = 0 ;
uint16_t negotiate_context_count = 0 ;
DATA_BLOB negotiate_context_blob = data_blob_null ;
size_t avail ;
size_t ctx_ofs ;
size_t needed ;
struct smb2_negotiate_context * preauth = NULL ;
uint16_t hash_count ;
uint16_t salt_length ;
uint16_t hash_selected ;
2018-10-17 19:09:06 +03:00
gnutls_hash_hd_t hash_hnd = NULL ;
2021-03-11 13:04:14 +03:00
struct smb2_negotiate_context * sign_algo = NULL ;
2014-09-23 06:09:16 +04:00
struct smb2_negotiate_context * cipher = NULL ;
2022-08-25 16:16:10 +03:00
struct smb2_negotiate_context * posix = NULL ;
2019-07-10 13:46:44 +03:00
struct iovec sent_iov [ 3 ] = { { 0 } , { 0 } , { 0 } } ;
2011-09-15 15:12:43 +04:00
static const struct smb2cli_req_expected_response expected [ ] = {
{
. status = NT_STATUS_OK ,
. body_size = 0x41
}
} ;
2018-10-17 19:09:06 +03:00
int rc ;
2011-09-15 15:12:43 +04:00
status = smb2cli_req_recv ( subreq , state , & iov ,
expected , ARRAY_SIZE ( expected ) ) ;
2022-08-22 07:56:46 +03:00
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
if ( iov = = NULL ) {
tevent_req_nterror ( req , NT_STATUS_INTERNAL_ERROR ) ;
2011-09-15 15:12:43 +04:00
return ;
}
body = ( uint8_t * ) iov [ 1 ] . iov_base ;
dialect_revision = SVAL ( body , 4 ) ;
for ( i = 0 ; i < ARRAY_SIZE ( smb2cli_prots ) ; i + + ) {
2014-09-26 23:15:00 +04:00
if ( smb2cli_prots [ i ] . proto < state - > conn - > min_protocol ) {
2011-09-15 15:12:43 +04:00
continue ;
}
2014-09-26 23:15:00 +04:00
if ( smb2cli_prots [ i ] . proto > state - > conn - > max_protocol ) {
2011-09-15 15:12:43 +04:00
continue ;
}
if ( smb2cli_prots [ i ] . smb2_dialect ! = dialect_revision ) {
continue ;
}
conn - > protocol = smb2cli_prots [ i ] . proto ;
break ;
}
if ( conn - > protocol = = PROTOCOL_NONE ) {
2014-09-23 06:09:16 +04:00
TALLOC_FREE ( subreq ) ;
2014-09-26 23:15:00 +04:00
if ( state - > conn - > min_protocol > = PROTOCOL_SMB2_02 ) {
2011-08-30 13:04:46 +04:00
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
if ( dialect_revision ! = SMB2_DIALECT_REVISION_2FF ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
/* make sure we do not loop forever */
2014-09-26 23:15:00 +04:00
state - > conn - > min_protocol = PROTOCOL_SMB2_02 ;
2011-08-30 13:04:46 +04:00
/*
* send a SMB2 negprot , in order to negotiate
2012-01-27 16:39:54 +04:00
* the SMB2 dialect .
2011-08-30 13:04:46 +04:00
*/
subreq = smbXcli_negprot_smb2_subreq ( state ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , smbXcli_negprot_smb2_done , req ) ;
2011-09-15 15:12:43 +04:00
return ;
}
conn - > smb2 . server . security_mode = SVAL ( body , 2 ) ;
2020-11-11 17:14:12 +03:00
if ( conn - > protocol > = PROTOCOL_SMB3_11 ) {
2014-09-23 06:09:16 +04:00
negotiate_context_count = SVAL ( body , 6 ) ;
}
2011-09-15 15:12:43 +04:00
blob = data_blob_const ( body + 8 , 16 ) ;
status = GUID_from_data_blob ( & blob , & conn - > smb2 . server . guid ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
conn - > smb2 . server . capabilities = IVAL ( body , 24 ) ;
conn - > smb2 . server . max_trans_size = IVAL ( body , 28 ) ;
conn - > smb2 . server . max_read_size = IVAL ( body , 32 ) ;
conn - > smb2 . server . max_write_size = IVAL ( body , 36 ) ;
conn - > smb2 . server . system_time = BVAL ( body , 40 ) ;
conn - > smb2 . server . start_time = BVAL ( body , 48 ) ;
2023-03-21 20:34:46 +03:00
if ( conn - > smb2 . server . max_trans_size = = 0 | |
conn - > smb2 . server . max_read_size = = 0 | |
conn - > smb2 . server . max_write_size = = 0 ) {
/*
* We can ' t connect to servers we can ' t
* do any operations on .
*/
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
2011-09-15 15:12:43 +04:00
security_offset = SVAL ( body , 56 ) ;
security_length = SVAL ( body , 58 ) ;
libcli/smb: allow SMB2 Negotiate responses with security_offset = 0 and security_length = 0
This fixes connections against the Azure SMB3 server.
It's not possible to demonstrate the bug with a test and a knownfail
entry, because it fails to even startup the test environments,
but the following change to our server demonstrates the problem
and shows the fix works:
diff --git a/source3/smbd/smb2_negprot.c b/source3/smbd/smb2_negprot.c
index da567951c0bf..25fdaea2df7b 100644
--- a/source3/smbd/smb2_negprot.c
+++ b/source3/smbd/smb2_negprot.c
@@ -711,6 +711,8 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
}
}
+ security_buffer = data_blob_null;
+
if (out_negotiate_context_blob.length != 0) {
static const uint8_t zeros[8];
size_t pad = 0;
@@ -759,6 +761,8 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
}
+ security_offset = 0;
+
SSVAL(outbody.data, 0x00, 0x40 + 1); /* struct size */
SSVAL(outbody.data, 0x02,
security_mode); /* security mode */
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15050
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
Autobuild-User(master): Jeremy Allison <jra@samba.org>
Autobuild-Date(master): Mon May 2 20:13:10 UTC 2022 on sn-devel-184
2022-04-26 11:38:15 +03:00
if ( security_offset = = 0 ) {
/*
* Azure sends security_offset = 0 and security_length = 0
*
* We just set security_offset to the expected value
* in order to allow the further logic to work
* as before .
*/
if ( security_length ! = 0 ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
security_offset = SMB2_HDR_BODY + iov [ 1 ] . iov_len ;
}
2011-09-15 15:12:43 +04:00
if ( security_offset ! = SMB2_HDR_BODY + iov [ 1 ] . iov_len ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
if ( security_length > iov [ 2 ] . iov_len ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
conn - > smb2 . server . gss_blob = data_blob_talloc ( conn ,
iov [ 2 ] . iov_base ,
security_length ) ;
if ( tevent_req_nomem ( conn - > smb2 . server . gss_blob . data , req ) ) {
return ;
}
2020-11-11 17:14:12 +03:00
if ( conn - > protocol > = PROTOCOL_SMB3_00 ) {
2020-11-11 15:18:24 +03:00
conn - > smb2 . server . sign_algo = SMB2_SIGNING_AES128_CMAC ;
} else {
conn - > smb2 . server . sign_algo = SMB2_SIGNING_HMAC_SHA256 ;
}
2020-11-11 17:14:12 +03:00
if ( conn - > protocol < PROTOCOL_SMB3_11 ) {
2014-09-23 06:09:16 +04:00
TALLOC_FREE ( subreq ) ;
if ( conn - > smb2 . server . capabilities & SMB2_CAP_ENCRYPTION ) {
conn - > smb2 . server . cipher = SMB2_ENCRYPTION_AES128_CCM ;
}
2021-07-14 13:13:49 +03:00
status = smbXcli_negprot_smb3_check_capabilities ( req ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
2014-09-23 06:09:16 +04:00
tevent_req_done ( req ) ;
return ;
}
2017-09-12 02:36:47 +03:00
/*
* Here we are now at SMB3_11 , so encryption should be
* negotiated via context , not capabilities .
*/
2014-10-13 12:39:45 +04:00
if ( conn - > smb2 . server . capabilities & SMB2_CAP_ENCRYPTION ) {
2017-09-12 02:36:47 +03:00
/*
* Server set SMB2_CAP_ENCRYPTION capability ,
* but * SHOULD * not , not * MUST * not . Just mask it off .
* NetApp seems to do this :
* BUG : https : //bugzilla.samba.org/show_bug.cgi?id=13009
*/
conn - > smb2 . server . capabilities & = ~ SMB2_CAP_ENCRYPTION ;
2014-10-13 12:39:45 +04:00
}
2014-09-23 06:09:16 +04:00
negotiate_context_offset = IVAL ( body , 60 ) ;
if ( negotiate_context_offset < security_offset ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
ctx_ofs = negotiate_context_offset - security_offset ;
if ( ctx_ofs > iov [ 2 ] . iov_len ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
avail = iov [ 2 ] . iov_len - security_length ;
needed = iov [ 2 ] . iov_len - ctx_ofs ;
if ( needed > avail ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
negotiate_context_blob . data = ( uint8_t * ) iov [ 2 ] . iov_base ;
negotiate_context_blob . length = iov [ 2 ] . iov_len ;
negotiate_context_blob . data + = ctx_ofs ;
negotiate_context_blob . length - = ctx_ofs ;
2022-08-25 10:54:52 +03:00
state - > out_ctx = talloc_zero ( state , struct smb2_negotiate_contexts ) ;
if ( tevent_req_nomem ( state - > out_ctx , req ) ) {
return ;
}
status = smb2_negotiate_context_parse ( state - > out_ctx ,
2021-05-09 22:16:00 +03:00
negotiate_context_blob ,
negotiate_context_count ,
2022-08-25 10:54:52 +03:00
state - > out_ctx ) ;
2021-05-09 22:16:00 +03:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_INVALID_PARAMETER ) ) {
status = NT_STATUS_INVALID_NETWORK_RESPONSE ;
2014-09-23 06:09:16 +04:00
}
2021-05-09 22:16:00 +03:00
if ( tevent_req_nterror ( req , status ) ) {
2014-09-23 06:09:16 +04:00
return ;
}
2022-08-25 10:54:52 +03:00
preauth = smb2_negotiate_context_find (
state - > out_ctx , SMB2_PREAUTH_INTEGRITY_CAPABILITIES ) ;
2014-09-23 06:09:16 +04:00
if ( preauth = = NULL ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
if ( preauth - > data . length < 6 ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
hash_count = SVAL ( preauth - > data . data , 0 ) ;
salt_length = SVAL ( preauth - > data . data , 2 ) ;
hash_selected = SVAL ( preauth - > data . data , 4 ) ;
if ( hash_count ! = 1 ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
if ( preauth - > data . length ! = ( 6 + salt_length ) ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
if ( hash_selected ! = SMB2_PREAUTH_INTEGRITY_SHA512 ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
2022-08-25 10:54:52 +03:00
sign_algo = smb2_negotiate_context_find (
state - > out_ctx , SMB2_SIGNING_CAPABILITIES ) ;
2021-03-11 13:04:14 +03:00
if ( sign_algo ! = NULL ) {
const struct smb3_signing_capabilities * client_sign_algos =
& state - > conn - > smb2 . client . smb3_capabilities . signing ;
bool found_selected = false ;
uint16_t sign_algo_count ;
uint16_t sign_algo_selected ;
if ( client_sign_algos - > num_algos = = 0 ) {
/*
* We didn ' t ask for SMB2_ENCRYPTION_CAPABILITIES
*/
tevent_req_nterror ( req ,
NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
if ( sign_algo - > data . length < 2 ) {
tevent_req_nterror ( req ,
NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
sign_algo_count = SVAL ( sign_algo - > data . data , 0 ) ;
if ( sign_algo_count ! = 1 ) {
tevent_req_nterror ( req ,
NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
if ( sign_algo - > data . length < ( 2 + 2 * sign_algo_count ) ) {
tevent_req_nterror ( req ,
NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
sign_algo_selected = SVAL ( sign_algo - > data . data , 2 ) ;
for ( i = 0 ; i < client_sign_algos - > num_algos ; i + + ) {
if ( client_sign_algos - > algos [ i ] = = sign_algo_selected ) {
/*
* We found a match
*/
found_selected = true ;
break ;
}
}
if ( ! found_selected ) {
/*
* The server send a sign_algo we didn ' t offer .
*/
tevent_req_nterror ( req ,
NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
conn - > smb2 . server . sign_algo = sign_algo_selected ;
}
2022-08-25 10:54:52 +03:00
cipher = smb2_negotiate_context_find (
state - > out_ctx , SMB2_ENCRYPTION_CAPABILITIES ) ;
2014-09-23 06:09:16 +04:00
if ( cipher ! = NULL ) {
2021-03-10 01:38:51 +03:00
const struct smb3_encryption_capabilities * client_ciphers =
& state - > conn - > smb2 . client . smb3_capabilities . encryption ;
bool found_selected = false ;
2014-09-23 06:09:16 +04:00
uint16_t cipher_count ;
2021-03-10 01:38:51 +03:00
uint16_t cipher_selected ;
if ( client_ciphers - > num_algos = = 0 ) {
/*
* We didn ' t ask for SMB2_ENCRYPTION_CAPABILITIES
*/
tevent_req_nterror ( req ,
NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
2014-09-23 06:09:16 +04:00
if ( cipher - > data . length < 2 ) {
tevent_req_nterror ( req ,
NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
cipher_count = SVAL ( cipher - > data . data , 0 ) ;
2021-03-10 01:38:51 +03:00
if ( cipher_count ! = 1 ) {
2014-09-23 06:09:16 +04:00
tevent_req_nterror ( req ,
NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
2019-02-14 12:17:28 +03:00
if ( cipher - > data . length < ( 2 + 2 * cipher_count ) ) {
2014-09-23 06:09:16 +04:00
tevent_req_nterror ( req ,
NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
2021-03-10 01:38:51 +03:00
cipher_selected = SVAL ( cipher - > data . data , 2 ) ;
2014-09-23 06:09:16 +04:00
2021-03-10 01:38:51 +03:00
for ( i = 0 ; i < client_ciphers - > num_algos ; i + + ) {
if ( cipher_selected = = SMB2_ENCRYPTION_NONE ) {
/*
* encryption not supported
*/
found_selected = true ;
break ;
}
if ( client_ciphers - > algos [ i ] = = cipher_selected ) {
/*
* We found a match
*/
found_selected = true ;
2014-10-07 17:59:48 +04:00
break ;
2014-09-23 06:09:16 +04:00
}
}
2021-03-10 01:38:51 +03:00
if ( ! found_selected ) {
/*
* The server send a cipher we didn ' t offer .
*/
tevent_req_nterror ( req ,
NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
conn - > smb2 . server . cipher = cipher_selected ;
2014-09-23 06:09:16 +04:00
}
2022-08-25 16:16:10 +03:00
posix = smb2_negotiate_context_find (
state - > out_ctx , SMB2_POSIX_EXTENSIONS_AVAILABLE ) ;
if ( posix ! = NULL ) {
DATA_BLOB posix_blob = data_blob_const (
SMB2_CREATE_TAG_POSIX , strlen ( SMB2_CREATE_TAG_POSIX ) ) ;
int cmp = data_blob_cmp ( & posix - > data , & posix_blob ) ;
conn - > smb2 . server . smb311_posix = ( cmp = = 0 ) ;
}
2014-09-23 06:09:16 +04:00
/* First we hash the request */
smb2cli_req_get_sent_iov ( subreq , sent_iov ) ;
2018-10-17 19:09:06 +03:00
rc = gnutls_hash_init ( & hash_hnd , GNUTLS_DIG_SHA512 ) ;
if ( rc < 0 ) {
tevent_req_nterror ( req ,
2019-06-11 13:18:01 +03:00
gnutls_error_to_ntstatus ( rc , NT_STATUS_HASH_NOT_SUPPORTED ) ) ;
2018-10-17 19:09:06 +03:00
return ;
}
rc = gnutls_hash ( hash_hnd ,
conn - > smb2 . preauth_sha512 ,
sizeof ( conn - > smb2 . preauth_sha512 ) ) ;
if ( rc < 0 ) {
gnutls_hash_deinit ( hash_hnd , NULL ) ;
tevent_req_nterror ( req ,
2019-06-11 13:18:01 +03:00
gnutls_error_to_ntstatus ( rc , NT_STATUS_HASH_NOT_SUPPORTED ) ) ;
2018-10-17 19:09:06 +03:00
return ;
}
2014-09-23 06:09:16 +04:00
for ( i = 0 ; i < 3 ; i + + ) {
2018-10-17 19:09:06 +03:00
rc = gnutls_hash ( hash_hnd ,
sent_iov [ i ] . iov_base ,
sent_iov [ i ] . iov_len ) ;
if ( rc < 0 ) {
gnutls_hash_deinit ( hash_hnd , NULL ) ;
tevent_req_nterror ( req ,
2019-06-11 13:18:01 +03:00
gnutls_error_to_ntstatus ( rc , NT_STATUS_HASH_NOT_SUPPORTED ) ) ;
2018-10-17 19:09:06 +03:00
return ;
}
2014-09-23 06:09:16 +04:00
}
2018-10-17 19:09:06 +03:00
/* This resets the hash state */
gnutls_hash_output ( hash_hnd , conn - > smb2 . preauth_sha512 ) ;
2014-09-23 06:09:16 +04:00
TALLOC_FREE ( subreq ) ;
/* And now we hash the response */
2018-10-17 19:09:06 +03:00
rc = gnutls_hash ( hash_hnd ,
conn - > smb2 . preauth_sha512 ,
sizeof ( conn - > smb2 . preauth_sha512 ) ) ;
if ( rc < 0 ) {
gnutls_hash_deinit ( hash_hnd , NULL ) ;
tevent_req_nterror ( req ,
2019-06-11 13:18:01 +03:00
gnutls_error_to_ntstatus ( rc , NT_STATUS_HASH_NOT_SUPPORTED ) ) ;
2018-10-17 19:09:06 +03:00
return ;
}
2014-09-23 06:09:16 +04:00
for ( i = 0 ; i < 3 ; i + + ) {
2018-10-17 19:09:06 +03:00
rc = gnutls_hash ( hash_hnd ,
iov [ i ] . iov_base ,
iov [ i ] . iov_len ) ;
if ( rc < 0 ) {
gnutls_hash_deinit ( hash_hnd , NULL ) ;
tevent_req_nterror ( req ,
2019-06-11 13:18:01 +03:00
gnutls_error_to_ntstatus ( rc , NT_STATUS_HASH_NOT_SUPPORTED ) ) ;
2018-10-17 19:09:06 +03:00
return ;
}
}
gnutls_hash_deinit ( hash_hnd , conn - > smb2 . preauth_sha512 ) ;
if ( rc < 0 ) {
tevent_req_nterror ( req ,
NT_STATUS_UNSUCCESSFUL ) ;
return ;
2014-09-23 06:09:16 +04:00
}
2021-07-14 13:13:49 +03:00
status = smbXcli_negprot_smb3_check_capabilities ( req ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
2011-09-15 15:12:43 +04:00
tevent_req_done ( req ) ;
}
2021-07-14 13:13:49 +03:00
static NTSTATUS smbXcli_negprot_smb3_check_capabilities ( struct tevent_req * req )
{
struct smbXcli_negprot_state * state =
tevent_req_data ( req ,
struct smbXcli_negprot_state ) ;
struct smbXcli_conn * conn = state - > conn ;
return smb311_capabilities_check ( & conn - > smb2 . client . smb3_capabilities ,
" smbXcli_negprot " ,
DBGLVL_ERR ,
NT_STATUS_ACCESS_DENIED ,
" client " ,
conn - > protocol ,
2021-07-13 22:26:19 +03:00
conn - > smb2 . server . sign_algo ,
2021-07-14 13:13:49 +03:00
conn - > smb2 . server . cipher ) ;
}
2011-09-15 15:12:43 +04:00
static NTSTATUS smbXcli_negprot_dispatch_incoming ( struct smbXcli_conn * conn ,
TALLOC_CTX * tmp_mem ,
uint8_t * inbuf )
{
size_t num_pending = talloc_array_length ( conn - > pending ) ;
struct tevent_req * subreq ;
struct smbXcli_req_state * substate ;
struct tevent_req * req ;
2012-07-20 11:20:43 +04:00
uint32_t protocol_magic ;
size_t inbuf_len = smb_len_nbt ( inbuf ) ;
2011-09-15 15:12:43 +04:00
if ( num_pending ! = 1 ) {
return NT_STATUS_INTERNAL_ERROR ;
}
2012-07-20 11:20:43 +04:00
if ( inbuf_len < 4 ) {
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
2011-09-15 15:12:43 +04:00
subreq = conn - > pending [ 0 ] ;
substate = tevent_req_data ( subreq , struct smbXcli_req_state ) ;
req = tevent_req_callback_data ( subreq , struct tevent_req ) ;
2012-07-20 11:20:43 +04:00
protocol_magic = IVAL ( inbuf , 4 ) ;
2011-09-15 15:12:43 +04:00
switch ( protocol_magic ) {
case SMB_MAGIC :
tevent_req_set_callback ( subreq , smbXcli_negprot_smb1_done , req ) ;
conn - > dispatch_incoming = smb1cli_conn_dispatch_incoming ;
return smb1cli_conn_dispatch_incoming ( conn , tmp_mem , inbuf ) ;
case SMB2_MAGIC :
if ( substate - > smb2 . recv_iov = = NULL ) {
/*
* For the SMB1 negprot we have move it .
*/
substate - > smb2 . recv_iov = substate - > smb1 . recv_iov ;
substate - > smb1 . recv_iov = NULL ;
}
2012-01-27 16:39:54 +04:00
/*
* we got an SMB2 answer , which consumed sequence number 0
2013-08-14 10:12:08 +04:00
* so we need to use 1 as the next one .
*
* we also need to set the current credits to 0
* as we consumed the initial one . The SMB2 answer
* hopefully grant us a new credit .
2012-01-27 16:39:54 +04:00
*/
conn - > smb2 . mid = 1 ;
2013-08-14 10:12:08 +04:00
conn - > smb2 . cur_credits = 0 ;
2011-09-15 15:12:43 +04:00
tevent_req_set_callback ( subreq , smbXcli_negprot_smb2_done , req ) ;
conn - > dispatch_incoming = smb2cli_conn_dispatch_incoming ;
return smb2cli_conn_dispatch_incoming ( conn , tmp_mem , inbuf ) ;
}
DEBUG ( 10 , ( " Got non-SMB PDU \n " ) ) ;
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
2022-08-25 10:54:52 +03:00
NTSTATUS smbXcli_negprot_recv (
struct tevent_req * req ,
TALLOC_CTX * mem_ctx ,
struct smb2_negotiate_contexts * * out_ctx )
2011-09-15 15:12:43 +04:00
{
2022-08-25 10:54:52 +03:00
struct smbXcli_negprot_state * state = tevent_req_data (
req , struct smbXcli_negprot_state ) ;
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
tevent_req_received ( req ) ;
return status ;
}
if ( out_ctx ! = NULL ) {
* out_ctx = talloc_move ( mem_ctx , & state - > out_ctx ) ;
}
tevent_req_received ( req ) ;
return NT_STATUS_OK ;
2011-09-15 15:12:43 +04:00
}
NTSTATUS smbXcli_negprot ( struct smbXcli_conn * conn ,
uint32_t timeout_msec ,
enum protocol_types min_protocol ,
2023-09-19 21:10:12 +03:00
enum protocol_types max_protocol ,
struct smb2_negotiate_contexts * in_ctx ,
TALLOC_CTX * mem_ctx ,
struct smb2_negotiate_contexts * * out_ctx )
2011-09-15 15:12:43 +04:00
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct tevent_context * ev ;
struct tevent_req * req ;
NTSTATUS status = NT_STATUS_NO_MEMORY ;
bool ok ;
if ( smbXcli_conn_has_async_calls ( conn ) ) {
/*
* Can ' t use sync call while an async call is in flight
*/
status = NT_STATUS_INVALID_PARAMETER_MIX ;
goto fail ;
}
2013-02-18 12:07:11 +04:00
ev = samba_tevent_context_init ( frame ) ;
2011-09-15 15:12:43 +04:00
if ( ev = = NULL ) {
goto fail ;
}
2022-08-25 10:54:52 +03:00
req = smbXcli_negprot_send (
frame ,
ev ,
conn ,
timeout_msec ,
min_protocol ,
max_protocol ,
WINDOWS_CLIENT_PURE_SMB2_NEGPROT_INITIAL_CREDIT_ASK ,
2023-09-19 21:10:12 +03:00
in_ctx ) ;
2011-09-15 15:12:43 +04:00
if ( req = = NULL ) {
goto fail ;
}
2015-02-25 23:42:33 +03:00
ok = tevent_req_poll_ntstatus ( req , ev , & status ) ;
2011-09-15 15:12:43 +04:00
if ( ! ok ) {
goto fail ;
}
2023-09-19 21:10:12 +03:00
status = smbXcli_negprot_recv ( req , mem_ctx , out_ctx ) ;
2011-09-15 15:12:43 +04:00
fail :
TALLOC_FREE ( frame ) ;
return status ;
}
2011-09-03 12:18:17 +04:00
2014-09-26 23:15:00 +04:00
struct smb2cli_validate_negotiate_info_state {
struct smbXcli_conn * conn ;
DATA_BLOB in_input_buffer ;
DATA_BLOB in_output_buffer ;
DATA_BLOB out_input_buffer ;
DATA_BLOB out_output_buffer ;
uint16_t dialect ;
} ;
static void smb2cli_validate_negotiate_info_done ( struct tevent_req * subreq ) ;
struct tevent_req * smb2cli_validate_negotiate_info_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct smbXcli_conn * conn ,
uint32_t timeout_msec ,
struct smbXcli_session * session ,
struct smbXcli_tcon * tcon )
{
struct tevent_req * req ;
struct smb2cli_validate_negotiate_info_state * state ;
uint8_t * buf ;
uint16_t dialect_count = 0 ;
struct tevent_req * subreq ;
bool _save_should_sign ;
size_t i ;
req = tevent_req_create ( mem_ctx , & state ,
struct smb2cli_validate_negotiate_info_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > conn = conn ;
state - > in_input_buffer = data_blob_talloc_zero ( state ,
4 + 16 + 1 + 1 + 2 ) ;
if ( tevent_req_nomem ( state - > in_input_buffer . data , req ) ) {
return tevent_req_post ( req , ev ) ;
}
buf = state - > in_input_buffer . data ;
2020-11-11 17:14:12 +03:00
if ( state - > conn - > max_protocol > = PROTOCOL_SMB3_00 ) {
2014-09-26 23:15:00 +04:00
SIVAL ( buf , 0 , conn - > smb2 . client . capabilities ) ;
} else {
SIVAL ( buf , 0 , 0 ) ; /* Capabilities */
}
if ( state - > conn - > max_protocol > = PROTOCOL_SMB2_10 ) {
NTSTATUS status ;
2020-09-29 11:55:07 +03:00
struct GUID_ndr_buf guid_buf = { . buf = { 0 } , } ;
2014-09-26 23:15:00 +04:00
2020-09-29 11:55:07 +03:00
status = GUID_to_ndr_buf ( & conn - > smb2 . client . guid ,
& guid_buf ) ;
2014-09-26 23:15:00 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return NULL ;
}
2020-09-29 11:55:07 +03:00
memcpy ( buf + 4 , guid_buf . buf , 16 ) ; /* ClientGuid */
2014-09-26 23:15:00 +04:00
} else {
memset ( buf + 4 , 0 , 16 ) ; /* ClientGuid */
}
2014-10-06 16:19:39 +04:00
if ( state - > conn - > min_protocol > = PROTOCOL_SMB2_02 ) {
SCVAL ( buf , 20 , conn - > smb2 . client . security_mode ) ;
} else {
SCVAL ( buf , 20 , 0 ) ;
}
2014-09-26 23:15:00 +04:00
SCVAL ( buf , 21 , 0 ) ; /* reserved */
for ( i = 0 ; i < ARRAY_SIZE ( smb2cli_prots ) ; i + + ) {
bool ok ;
size_t ofs ;
if ( smb2cli_prots [ i ] . proto < state - > conn - > min_protocol ) {
continue ;
}
if ( smb2cli_prots [ i ] . proto > state - > conn - > max_protocol ) {
continue ;
}
if ( smb2cli_prots [ i ] . proto = = state - > conn - > protocol ) {
state - > dialect = smb2cli_prots [ i ] . smb2_dialect ;
}
ofs = state - > in_input_buffer . length ;
ok = data_blob_realloc ( state , & state - > in_input_buffer ,
ofs + 2 ) ;
if ( ! ok ) {
tevent_req_oom ( req ) ;
return tevent_req_post ( req , ev ) ;
}
buf = state - > in_input_buffer . data ;
SSVAL ( buf , ofs , smb2cli_prots [ i ] . smb2_dialect ) ;
dialect_count + + ;
}
buf = state - > in_input_buffer . data ;
SSVAL ( buf , 22 , dialect_count ) ;
_save_should_sign = smb2cli_tcon_is_signing_on ( tcon ) ;
smb2cli_tcon_should_sign ( tcon , true ) ;
subreq = smb2cli_ioctl_send ( state , ev , conn ,
timeout_msec , session , tcon ,
UINT64_MAX , /* in_fid_persistent */
UINT64_MAX , /* in_fid_volatile */
FSCTL_VALIDATE_NEGOTIATE_INFO ,
0 , /* in_max_input_length */
& state - > in_input_buffer ,
24 , /* in_max_output_length */
& state - > in_output_buffer ,
SMB2_IOCTL_FLAG_IS_FSCTL ) ;
smb2cli_tcon_should_sign ( tcon , _save_should_sign ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq ,
smb2cli_validate_negotiate_info_done ,
req ) ;
return req ;
}
static void smb2cli_validate_negotiate_info_done ( struct tevent_req * subreq )
{
struct tevent_req * req =
tevent_req_callback_data ( subreq ,
struct tevent_req ) ;
struct smb2cli_validate_negotiate_info_state * state =
tevent_req_data ( req ,
struct smb2cli_validate_negotiate_info_state ) ;
NTSTATUS status ;
const uint8_t * buf ;
uint32_t capabilities ;
DATA_BLOB guid_blob ;
struct GUID server_guid ;
uint16_t security_mode ;
uint16_t dialect ;
status = smb2cli_ioctl_recv ( subreq , state ,
& state - > out_input_buffer ,
& state - > out_output_buffer ) ;
TALLOC_FREE ( subreq ) ;
2021-01-06 20:03:05 +03:00
/*
* This response must be signed correctly for
* these " normal " error codes to be processed .
* If the packet wasn ' t signed correctly we will get
* NT_STATUS_ACCESS_DENIED or NT_STATUS_HMAC_NOT_SUPPORTED ,
* or NT_STATUS_INVALID_NETWORK_RESPONSE
* from smb2_signing_check_pdu ( ) .
*
* We must never ignore the above errors here .
*/
2014-09-26 23:15:00 +04:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_FILE_CLOSED ) ) {
/*
* The response was signed , but not supported
*
* Older Windows and Samba releases return
* NT_STATUS_FILE_CLOSED .
*/
tevent_req_done ( req ) ;
return ;
}
if ( NT_STATUS_EQUAL ( status , NT_STATUS_INVALID_DEVICE_REQUEST ) ) {
/*
* The response was signed , but not supported
*
* This is returned by the NTVFS based Samba 4. x file server
* for file shares .
*/
tevent_req_done ( req ) ;
return ;
}
if ( NT_STATUS_EQUAL ( status , NT_STATUS_FS_DRIVER_REQUIRED ) ) {
/*
* The response was signed , but not supported
*
* This is returned by the NTVFS based Samba 4. x file server
* for ipc shares .
*/
tevent_req_done ( req ) ;
2017-05-30 17:30:33 +03:00
return ;
}
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NOT_SUPPORTED ) ) {
/*
* The response was signed , but not supported
*
* This might be returned by older Windows versions or by
* NetApp SMB server implementations .
*
* See
*
* https : //blogs.msdn.microsoft.com/openspecification/2012/06/28/smb3-secure-dialect-negotiation/
*
*/
tevent_req_done ( req ) ;
2014-09-26 23:15:00 +04:00
return ;
}
2021-01-06 20:03:05 +03:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_INVALID_PARAMETER ) ) {
/*
* The response was signed , but not supported
*
* This might be returned by NetApp Ontap 7.3 .7 SMB server
* implementations .
*
* BUG : https : //bugzilla.samba.org/show_bug.cgi?id=14607
*
*/
tevent_req_done ( req ) ;
return ;
}
2014-09-26 23:15:00 +04:00
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
if ( state - > out_output_buffer . length ! = 24 ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
buf = state - > out_output_buffer . data ;
capabilities = IVAL ( buf , 0 ) ;
guid_blob = data_blob_const ( buf + 4 , 16 ) ;
status = GUID_from_data_blob ( & guid_blob , & server_guid ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
security_mode = CVAL ( buf , 20 ) ;
dialect = SVAL ( buf , 22 ) ;
if ( capabilities ! = state - > conn - > smb2 . server . capabilities ) {
tevent_req_nterror ( req , NT_STATUS_ACCESS_DENIED ) ;
return ;
}
if ( ! GUID_equal ( & server_guid , & state - > conn - > smb2 . server . guid ) ) {
tevent_req_nterror ( req , NT_STATUS_ACCESS_DENIED ) ;
return ;
}
if ( security_mode ! = state - > conn - > smb2 . server . security_mode ) {
tevent_req_nterror ( req , NT_STATUS_ACCESS_DENIED ) ;
return ;
}
if ( dialect ! = state - > dialect ) {
tevent_req_nterror ( req , NT_STATUS_ACCESS_DENIED ) ;
return ;
}
tevent_req_done ( req ) ;
}
NTSTATUS smb2cli_validate_negotiate_info_recv ( struct tevent_req * req )
{
return tevent_req_simple_recv_ntstatus ( req ) ;
}
2011-09-03 12:18:17 +04:00
static int smbXcli_session_destructor ( struct smbXcli_session * session )
{
if ( session - > conn = = NULL ) {
return 0 ;
}
DLIST_REMOVE ( session - > conn - > sessions , session ) ;
return 0 ;
}
struct smbXcli_session * smbXcli_session_create ( TALLOC_CTX * mem_ctx ,
struct smbXcli_conn * conn )
{
struct smbXcli_session * session ;
2021-03-05 18:43:29 +03:00
NTSTATUS status ;
2011-09-03 12:18:17 +04:00
session = talloc_zero ( mem_ctx , struct smbXcli_session ) ;
if ( session = = NULL ) {
return NULL ;
}
2012-07-26 04:36:37 +04:00
session - > smb2 = talloc_zero ( session , struct smb2cli_session ) ;
if ( session - > smb2 = = NULL ) {
talloc_free ( session ) ;
return NULL ;
}
2011-09-03 12:18:17 +04:00
talloc_set_destructor ( session , smbXcli_session_destructor ) ;
2021-03-05 18:43:29 +03:00
status = smb2_signing_key_sign_create ( session - > smb2 ,
conn - > smb2 . server . sign_algo ,
NULL , /* no master key */
NULL , /* derivations */
& session - > smb2 - > signing_key ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2019-06-07 19:58:43 +03:00
talloc_free ( session ) ;
return NULL ;
}
2016-02-05 13:32:18 +03:00
DLIST_ADD_END ( conn - > sessions , session ) ;
2011-09-03 12:18:17 +04:00
session - > conn = conn ;
2021-03-05 18:43:29 +03:00
status = smb2_signing_key_sign_create ( session ,
conn - > smb2 . server . sign_algo ,
NULL , /* no master key */
NULL , /* derivations */
& session - > smb2_channel . signing_key ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2019-06-07 19:58:43 +03:00
talloc_free ( session ) ;
return NULL ;
}
2014-09-25 00:58:49 +04:00
memcpy ( session - > smb2_channel . preauth_sha512 ,
conn - > smb2 . preauth_sha512 ,
sizeof ( session - > smb2_channel . preauth_sha512 ) ) ;
2011-09-03 12:18:17 +04:00
return session ;
}
2019-06-11 18:42:38 +03:00
struct smbXcli_session * smbXcli_session_shallow_copy ( TALLOC_CTX * mem_ctx ,
2013-01-29 04:51:25 +04:00
struct smbXcli_session * src )
{
struct smbXcli_session * session ;
2019-06-11 18:44:04 +03:00
struct timespec ts ;
NTTIME nt ;
2013-01-29 04:51:25 +04:00
session = talloc_zero ( mem_ctx , struct smbXcli_session ) ;
if ( session = = NULL ) {
return NULL ;
}
session - > smb2 = talloc_zero ( session , struct smb2cli_session ) ;
if ( session - > smb2 = = NULL ) {
talloc_free ( session ) ;
return NULL ;
}
2019-06-11 18:42:38 +03:00
/*
* Note we keep a pointer to the session keys of the
* main session and rely on the caller to free the
* shallow copy first !
*/
2013-01-29 04:51:25 +04:00
session - > conn = src - > conn ;
* session - > smb2 = * src - > smb2 ;
session - > smb2_channel = src - > smb2_channel ;
session - > disconnect_expired = src - > disconnect_expired ;
2019-06-11 18:44:04 +03:00
/*
* This is only supposed to be called in test code
* but we should not reuse nonces !
*
* Add the current timestamp as NTTIME to nonce_high
* and set nonce_low to a value we can recognize in captures .
*/
clock_gettime_mono ( & ts ) ;
nt = unix_timespec_to_nt_time ( ts ) ;
nt & = session - > smb2 - > nonce_high_max ;
if ( nt = = session - > smb2 - > nonce_high_max | | nt < UINT8_MAX ) {
talloc_free ( session ) ;
return NULL ;
}
session - > smb2 - > nonce_high + = nt ;
session - > smb2 - > nonce_low = UINT32_MAX ;
2016-02-05 13:32:18 +03:00
DLIST_ADD_END ( src - > conn - > sessions , session ) ;
2013-01-29 04:51:25 +04:00
talloc_set_destructor ( session , smbXcli_session_destructor ) ;
return session ;
}
2016-04-18 18:38:46 +03:00
bool smbXcli_session_is_guest ( struct smbXcli_session * session )
{
if ( session = = NULL ) {
return false ;
}
if ( session - > conn = = NULL ) {
return false ;
}
2016-04-20 12:26:57 +03:00
if ( session - > conn - > mandatory_signing ) {
return false ;
}
2016-04-18 18:38:46 +03:00
if ( session - > conn - > protocol > = PROTOCOL_SMB2_02 ) {
if ( session - > smb2 - > session_flags & SMB2_SESSION_FLAG_IS_GUEST ) {
return true ;
}
return false ;
}
if ( session - > smb1 . action & SMB_SETUP_GUEST ) {
return true ;
}
return false ;
}
2014-09-25 03:46:15 +04:00
bool smbXcli_session_is_authenticated ( struct smbXcli_session * session )
{
const DATA_BLOB * application_key ;
2016-04-20 21:09:53 +03:00
if ( session = = NULL ) {
return false ;
}
2014-09-25 03:46:15 +04:00
if ( session - > conn = = NULL ) {
return false ;
}
/*
* If we have an application key we had a session key negotiated
* at auth time .
*/
if ( session - > conn - > protocol > = PROTOCOL_SMB2_02 ) {
2021-03-05 18:43:29 +03:00
if ( ! smb2_signing_key_valid ( session - > smb2 - > application_key ) ) {
return false ;
}
application_key = & session - > smb2 - > application_key - > blob ;
2014-09-25 03:46:15 +04:00
} else {
application_key = & session - > smb1 . application_key ;
}
if ( application_key - > length = = 0 ) {
return false ;
}
return true ;
}
2013-01-29 04:51:25 +04:00
2019-02-06 21:23:35 +03:00
NTSTATUS smb2cli_session_signing_key ( struct smbXcli_session * session ,
TALLOC_CTX * mem_ctx ,
DATA_BLOB * key )
{
2019-03-04 18:59:51 +03:00
const struct smb2_signing_key * sig = NULL ;
2019-02-06 21:23:35 +03:00
if ( session - > conn = = NULL ) {
return NT_STATUS_NO_USER_SESSION_KEY ;
}
/*
* Use channel signing key if there is one , otherwise fallback
* to session .
*/
2019-03-04 18:59:51 +03:00
if ( smb2_signing_key_valid ( session - > smb2_channel . signing_key ) ) {
sig = session - > smb2_channel . signing_key ;
} else if ( smb2_signing_key_valid ( session - > smb2 - > signing_key ) ) {
sig = session - > smb2 - > signing_key ;
2019-02-06 21:23:35 +03:00
} else {
return NT_STATUS_NO_USER_SESSION_KEY ;
}
2019-03-04 18:59:51 +03:00
* key = data_blob_dup_talloc ( mem_ctx , sig - > blob ) ;
2019-02-06 21:23:35 +03:00
if ( key - > data = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
return NT_STATUS_OK ;
}
NTSTATUS smb2cli_session_encryption_key ( struct smbXcli_session * session ,
TALLOC_CTX * mem_ctx ,
DATA_BLOB * key )
{
if ( session - > conn = = NULL ) {
return NT_STATUS_NO_USER_SESSION_KEY ;
}
if ( session - > conn - > protocol < PROTOCOL_SMB3_00 ) {
return NT_STATUS_NO_USER_SESSION_KEY ;
}
2019-03-14 11:34:23 +03:00
if ( ! smb2_signing_key_valid ( session - > smb2 - > encryption_key ) ) {
2019-02-06 21:23:35 +03:00
return NT_STATUS_NO_USER_SESSION_KEY ;
}
2019-03-14 11:34:23 +03:00
* key = data_blob_dup_talloc ( mem_ctx , session - > smb2 - > encryption_key - > blob ) ;
2019-02-06 21:23:35 +03:00
if ( key - > data = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
return NT_STATUS_OK ;
}
NTSTATUS smb2cli_session_decryption_key ( struct smbXcli_session * session ,
TALLOC_CTX * mem_ctx ,
DATA_BLOB * key )
{
if ( session - > conn = = NULL ) {
return NT_STATUS_NO_USER_SESSION_KEY ;
}
if ( session - > conn - > protocol < PROTOCOL_SMB3_00 ) {
return NT_STATUS_NO_USER_SESSION_KEY ;
}
2019-03-14 11:48:54 +03:00
if ( ! smb2_signing_key_valid ( session - > smb2 - > decryption_key ) ) {
2019-02-06 21:23:35 +03:00
return NT_STATUS_NO_USER_SESSION_KEY ;
}
2019-03-14 11:48:54 +03:00
* key = data_blob_dup_talloc ( mem_ctx , session - > smb2 - > decryption_key - > blob ) ;
2019-02-06 21:23:35 +03:00
if ( key - > data = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
return NT_STATUS_OK ;
}
2012-08-01 10:59:01 +04:00
NTSTATUS smbXcli_session_application_key ( struct smbXcli_session * session ,
TALLOC_CTX * mem_ctx ,
DATA_BLOB * key )
{
const DATA_BLOB * application_key ;
* key = data_blob_null ;
if ( session - > conn = = NULL ) {
return NT_STATUS_NO_USER_SESSION_KEY ;
}
if ( session - > conn - > protocol > = PROTOCOL_SMB2_02 ) {
2021-03-05 18:43:29 +03:00
if ( ! smb2_signing_key_valid ( session - > smb2 - > application_key ) ) {
return NT_STATUS_NO_USER_SESSION_KEY ;
}
application_key = & session - > smb2 - > application_key - > blob ;
2012-08-01 10:59:01 +04:00
} else {
application_key = & session - > smb1 . application_key ;
}
if ( application_key - > length = = 0 ) {
return NT_STATUS_NO_USER_SESSION_KEY ;
}
* key = data_blob_dup_talloc ( mem_ctx , * application_key ) ;
if ( key - > data = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
return NT_STATUS_OK ;
}
2012-10-22 16:18:20 +04:00
void smbXcli_session_set_disconnect_expired ( struct smbXcli_session * session )
{
session - > disconnect_expired = true ;
}
2012-06-02 14:49:22 +04:00
uint16_t smb1cli_session_current_id ( struct smbXcli_session * session )
{
return session - > smb1 . session_id ;
}
void smb1cli_session_set_id ( struct smbXcli_session * session ,
uint16_t session_id )
{
session - > smb1 . session_id = session_id ;
}
2016-04-18 18:33:11 +03:00
void smb1cli_session_set_action ( struct smbXcli_session * session ,
uint16_t action )
{
session - > smb1 . action = action ;
}
2012-08-01 10:53:30 +04:00
NTSTATUS smb1cli_session_set_session_key ( struct smbXcli_session * session ,
const DATA_BLOB _session_key )
{
struct smbXcli_conn * conn = session - > conn ;
uint8_t session_key [ 16 ] ;
if ( conn = = NULL ) {
return NT_STATUS_INVALID_PARAMETER_MIX ;
}
if ( session - > smb1 . application_key . length ! = 0 ) {
2012-08-01 16:14:39 +04:00
/*
* TODO : do not allow this . . .
*
* return NT_STATUS_INVALID_PARAMETER_MIX ;
*/
data_blob_clear_free ( & session - > smb1 . application_key ) ;
2012-08-01 11:01:25 +04:00
session - > smb1 . protected_key = false ;
2012-08-01 10:53:30 +04:00
}
if ( _session_key . length = = 0 ) {
return NT_STATUS_OK ;
}
ZERO_STRUCT ( session_key ) ;
memcpy ( session_key , _session_key . data ,
MIN ( _session_key . length , sizeof ( session_key ) ) ) ;
session - > smb1 . application_key = data_blob_talloc ( session ,
session_key ,
sizeof ( session_key ) ) ;
ZERO_STRUCT ( session_key ) ;
if ( session - > smb1 . application_key . data = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2012-08-01 11:01:25 +04:00
session - > smb1 . protected_key = false ;
return NT_STATUS_OK ;
}
NTSTATUS smb1cli_session_protect_session_key ( struct smbXcli_session * session )
{
2019-04-11 11:29:04 +03:00
NTSTATUS status ;
2012-08-01 11:01:25 +04:00
if ( session - > smb1 . protected_key ) {
/* already protected */
return NT_STATUS_OK ;
}
if ( session - > smb1 . application_key . length ! = 16 ) {
return NT_STATUS_INVALID_PARAMETER_MIX ;
}
2022-03-08 06:41:31 +03:00
status = smb1_key_derivation ( session - > smb1 . application_key . data ,
2019-04-11 11:29:04 +03:00
session - > smb1 . application_key . length ,
session - > smb1 . application_key . data ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2012-08-01 11:01:25 +04:00
session - > smb1 . protected_key = true ;
2012-08-01 10:53:30 +04:00
return NT_STATUS_OK ;
}
2011-09-03 12:18:17 +04:00
uint8_t smb2cli_session_security_mode ( struct smbXcli_session * session )
{
struct smbXcli_conn * conn = session - > conn ;
uint8_t security_mode = 0 ;
if ( conn = = NULL ) {
return security_mode ;
}
security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED ;
if ( conn - > mandatory_signing ) {
security_mode | = SMB2_NEGOTIATE_SIGNING_REQUIRED ;
}
2015-09-30 22:23:25 +03:00
if ( session - > smb2 - > should_sign ) {
security_mode | = SMB2_NEGOTIATE_SIGNING_REQUIRED ;
}
2011-09-03 12:18:17 +04:00
return security_mode ;
}
uint64_t smb2cli_session_current_id ( struct smbXcli_session * session )
{
2012-07-26 04:36:37 +04:00
return session - > smb2 - > session_id ;
2011-09-03 12:18:17 +04:00
}
2012-04-16 14:45:02 +04:00
uint16_t smb2cli_session_get_flags ( struct smbXcli_session * session )
{
2012-07-26 04:36:37 +04:00
return session - > smb2 - > session_flags ;
2012-04-16 14:45:02 +04:00
}
2011-09-03 12:18:17 +04:00
void smb2cli_session_set_id_and_flags ( struct smbXcli_session * session ,
uint64_t session_id ,
uint16_t session_flags )
{
2012-07-26 04:36:37 +04:00
session - > smb2 - > session_id = session_id ;
session - > smb2 - > session_flags = session_flags ;
2011-09-03 12:18:17 +04:00
}
2012-07-26 03:54:33 +04:00
void smb2cli_session_increment_channel_sequence ( struct smbXcli_session * session )
{
session - > smb2 - > channel_sequence + = 1 ;
}
2014-07-10 13:00:10 +04:00
uint16_t smb2cli_session_reset_channel_sequence ( struct smbXcli_session * session ,
uint16_t channel_sequence )
{
uint16_t prev_cs ;
prev_cs = session - > smb2 - > channel_sequence ;
session - > smb2 - > channel_sequence = channel_sequence ;
return prev_cs ;
}
2016-03-01 17:15:10 +03:00
uint16_t smb2cli_session_current_channel_sequence ( struct smbXcli_session * session )
{
return session - > smb2 - > channel_sequence ;
}
2014-07-10 15:16:04 +04:00
void smb2cli_session_start_replay ( struct smbXcli_session * session )
{
session - > smb2 - > replay_active = true ;
}
void smb2cli_session_stop_replay ( struct smbXcli_session * session )
{
session - > smb2 - > replay_active = false ;
}
2018-11-09 17:17:19 +03:00
void smb2cli_session_require_signed_response ( struct smbXcli_session * session ,
bool require_signed_response )
{
session - > smb2 - > require_signed_response = require_signed_response ;
}
2014-09-25 00:58:49 +04:00
NTSTATUS smb2cli_session_update_preauth ( struct smbXcli_session * session ,
const struct iovec * iov )
{
2018-10-17 19:09:06 +03:00
gnutls_hash_hd_t hash_hnd = NULL ;
2014-09-25 00:58:49 +04:00
size_t i ;
2018-10-17 19:09:06 +03:00
int rc ;
2014-09-25 00:58:49 +04:00
if ( session - > conn = = NULL ) {
return NT_STATUS_INTERNAL_ERROR ;
}
2020-11-11 17:14:12 +03:00
if ( session - > conn - > protocol < PROTOCOL_SMB3_11 ) {
2014-09-25 00:58:49 +04:00
return NT_STATUS_OK ;
}
2019-03-04 18:59:51 +03:00
if ( smb2_signing_key_valid ( session - > smb2_channel . signing_key ) ) {
2014-09-25 00:58:49 +04:00
return NT_STATUS_OK ;
}
2018-10-17 19:09:06 +03:00
rc = gnutls_hash_init ( & hash_hnd ,
GNUTLS_DIG_SHA512 ) ;
if ( rc < 0 ) {
2019-06-11 13:18:01 +03:00
return gnutls_error_to_ntstatus ( rc , NT_STATUS_HASH_NOT_SUPPORTED ) ;
2018-10-17 19:09:06 +03:00
}
rc = gnutls_hash ( hash_hnd ,
session - > smb2_channel . preauth_sha512 ,
sizeof ( session - > smb2_channel . preauth_sha512 ) ) ;
if ( rc < 0 ) {
gnutls_hash_deinit ( hash_hnd , NULL ) ;
2019-06-11 13:18:01 +03:00
return gnutls_error_to_ntstatus ( rc , NT_STATUS_HASH_NOT_SUPPORTED ) ;
2018-10-17 19:09:06 +03:00
}
2014-09-25 00:58:49 +04:00
for ( i = 0 ; i < 3 ; i + + ) {
2018-10-17 19:09:06 +03:00
rc = gnutls_hash ( hash_hnd ,
iov [ i ] . iov_base ,
iov [ i ] . iov_len ) ;
if ( rc < 0 ) {
gnutls_hash_deinit ( hash_hnd , NULL ) ;
2019-06-11 13:18:01 +03:00
return gnutls_error_to_ntstatus ( rc , NT_STATUS_HASH_NOT_SUPPORTED ) ;
2018-10-17 19:09:06 +03:00
}
2014-09-25 00:58:49 +04:00
}
2018-10-17 19:09:06 +03:00
gnutls_hash_deinit ( hash_hnd , session - > smb2_channel . preauth_sha512 ) ;
2014-09-25 00:58:49 +04:00
return NT_STATUS_OK ;
}
2012-02-27 11:48:55 +04:00
NTSTATUS smb2cli_session_set_session_key ( struct smbXcli_session * session ,
const DATA_BLOB _session_key ,
const struct iovec * recv_iov )
2011-09-03 12:18:17 +04:00
{
struct smbXcli_conn * conn = session - > conn ;
2016-04-20 12:26:57 +03:00
uint16_t no_sign_flags = 0 ;
2013-09-18 04:24:30 +04:00
bool check_signature = true ;
uint32_t hdr_flags ;
2011-09-03 12:18:17 +04:00
NTSTATUS status ;
2021-03-05 18:14:35 +03:00
struct smb2_signing_derivations derivations = {
. signing = NULL ,
2019-01-15 17:42:09 +03:00
} ;
2021-03-05 18:14:35 +03:00
DATA_BLOB preauth_hash = data_blob_null ;
2015-05-28 16:20:54 +03:00
size_t nonce_size = 0 ;
2011-09-03 12:18:17 +04:00
if ( conn = = NULL ) {
return NT_STATUS_INVALID_PARAMETER_MIX ;
}
2013-09-18 04:24:30 +04:00
if ( recv_iov [ 0 ] . iov_len ! = SMB2_HDR_BODY ) {
return NT_STATUS_INVALID_PARAMETER_MIX ;
}
2016-04-20 12:26:57 +03:00
if ( ! conn - > mandatory_signing ) {
/*
* only allow guest sessions without
* mandatory signing .
*
* If we try an authentication with username ! = " "
* and the server let us in without verifying the
* password we don ' t have a negotiated session key
* for signing .
*/
no_sign_flags = SMB2_SESSION_FLAG_IS_GUEST ;
}
2011-09-03 12:18:17 +04:00
2012-07-26 04:36:37 +04:00
if ( session - > smb2 - > session_flags & no_sign_flags ) {
session - > smb2 - > should_sign = false ;
2011-09-03 12:18:17 +04:00
return NT_STATUS_OK ;
}
2019-03-04 18:59:51 +03:00
if ( smb2_signing_key_valid ( session - > smb2 - > signing_key ) ) {
2012-04-16 14:41:30 +04:00
return NT_STATUS_INVALID_PARAMETER_MIX ;
}
2020-11-11 17:14:12 +03:00
if ( conn - > protocol > = PROTOCOL_SMB3_11 ) {
2021-03-05 18:14:35 +03:00
preauth_hash = data_blob_const ( session - > smb2_channel . preauth_sha512 ,
2014-09-25 00:58:49 +04:00
sizeof ( session - > smb2_channel . preauth_sha512 ) ) ;
}
2021-03-05 18:14:35 +03:00
smb2_signing_derivations_fill_const_stack ( & derivations ,
conn - > protocol ,
preauth_hash ) ;
2021-03-05 18:43:29 +03:00
status = smb2_signing_key_sign_create ( session - > smb2 ,
conn - > smb2 . server . sign_algo ,
& _session_key ,
derivations . signing ,
& session - > smb2 - > signing_key ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2012-07-20 11:30:05 +04:00
}
2021-03-05 18:43:29 +03:00
status = smb2_signing_key_cipher_create ( session - > smb2 ,
conn - > smb2 . server . cipher ,
& _session_key ,
derivations . cipher_c2s ,
& session - > smb2 - > encryption_key ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2012-07-20 11:30:05 +04:00
}
2021-03-05 18:43:29 +03:00
status = smb2_signing_key_cipher_create ( session - > smb2 ,
conn - > smb2 . server . cipher ,
& _session_key ,
derivations . cipher_s2c ,
& session - > smb2 - > decryption_key ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2012-02-27 12:03:54 +04:00
}
2021-03-05 18:43:29 +03:00
status = smb2_signing_key_sign_create ( session - > smb2 ,
conn - > smb2 . server . sign_algo ,
& _session_key ,
derivations . application ,
& session - > smb2 - > application_key ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2012-02-27 12:33:46 +04:00
}
2021-03-05 18:43:29 +03:00
status = smb2_signing_key_copy ( session ,
session - > smb2 - > signing_key ,
& session - > smb2_channel . signing_key ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2011-09-03 12:18:17 +04:00
}
2013-09-18 04:24:30 +04:00
check_signature = conn - > mandatory_signing ;
hdr_flags = IVAL ( recv_iov [ 0 ] . iov_base , SMB2_HDR_FLAGS ) ;
if ( hdr_flags & SMB2_HDR_FLAG_SIGNED ) {
2013-09-17 06:12:30 +04:00
/*
* Sadly some vendors don ' t sign the
* final SMB2 session setup response
*
* At least Windows and Samba are always doing this
* if there ' s a session key available .
2013-09-18 04:24:30 +04:00
*
* We only check the signature if it ' s mandatory
* or SMB2_HDR_FLAG_SIGNED is provided .
2013-09-17 06:12:30 +04:00
*/
2013-09-18 04:24:30 +04:00
check_signature = true ;
}
2020-11-11 17:14:12 +03:00
if ( conn - > protocol > = PROTOCOL_SMB3_11 ) {
2014-09-25 00:58:49 +04:00
check_signature = true ;
}
2013-09-18 04:24:30 +04:00
if ( check_signature ) {
2019-03-14 19:42:34 +03:00
status = smb2_signing_check_pdu ( session - > smb2_channel . signing_key ,
2013-09-18 04:24:30 +04:00
recv_iov , 3 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2013-09-17 06:12:30 +04:00
return status ;
}
2011-09-03 12:18:17 +04:00
}
2012-07-26 04:36:37 +04:00
session - > smb2 - > should_sign = false ;
session - > smb2 - > should_encrypt = false ;
2011-09-03 12:18:17 +04:00
if ( conn - > desire_signing ) {
2012-07-26 04:36:37 +04:00
session - > smb2 - > should_sign = true ;
2011-09-03 12:18:17 +04:00
}
if ( conn - > smb2 . server . security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED ) {
2012-07-26 04:36:37 +04:00
session - > smb2 - > should_sign = true ;
2011-09-03 12:18:17 +04:00
}
2012-07-26 04:36:37 +04:00
if ( session - > smb2 - > session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA ) {
session - > smb2 - > should_encrypt = true ;
2012-07-23 13:38:31 +04:00
}
2020-11-11 17:14:12 +03:00
if ( conn - > protocol < PROTOCOL_SMB3_00 ) {
2012-07-26 04:36:37 +04:00
session - > smb2 - > should_encrypt = false ;
2012-07-23 13:38:31 +04:00
}
2014-10-13 12:39:45 +04:00
if ( conn - > smb2 . server . cipher = = 0 ) {
2012-07-26 04:36:37 +04:00
session - > smb2 - > should_encrypt = false ;
2012-07-23 13:38:31 +04:00
}
2015-05-28 16:20:54 +03:00
/*
* CCM and GCM algorithms must never have their
* nonce wrap , or the security of the whole
* communication and the keys is destroyed .
* We must drop the connection once we have
2023-04-27 16:58:18 +03:00
* transferred too much data .
2015-05-28 16:20:54 +03:00
*
* NOTE : We assume nonces greater than 8 bytes .
*/
2019-07-31 16:25:35 +03:00
generate_nonce_buffer ( ( uint8_t * ) & session - > smb2 - > nonce_high_random ,
sizeof ( session - > smb2 - > nonce_high_random ) ) ;
2015-05-28 16:20:54 +03:00
switch ( conn - > smb2 . server . cipher ) {
case SMB2_ENCRYPTION_AES128_CCM :
2019-02-26 20:12:57 +03:00
nonce_size = SMB2_AES_128_CCM_NONCE_SIZE ;
2015-05-28 16:20:54 +03:00
break ;
case SMB2_ENCRYPTION_AES128_GCM :
2019-02-26 20:12:57 +03:00
nonce_size = gnutls_cipher_get_iv_size ( GNUTLS_CIPHER_AES_128_GCM ) ;
2015-05-28 16:20:54 +03:00
break ;
2020-11-10 03:25:19 +03:00
case SMB2_ENCRYPTION_AES256_CCM :
nonce_size = SMB2_AES_128_CCM_NONCE_SIZE ;
break ;
case SMB2_ENCRYPTION_AES256_GCM :
nonce_size = gnutls_cipher_get_iv_size ( GNUTLS_CIPHER_AES_256_GCM ) ;
break ;
2015-05-28 16:20:54 +03:00
default :
nonce_size = 0 ;
break ;
}
session - > smb2 - > nonce_high_max = SMB2_NONCE_HIGH_MAX ( nonce_size ) ;
session - > smb2 - > nonce_high = 0 ;
session - > smb2 - > nonce_low = 0 ;
2012-07-20 11:30:05 +04:00
2011-09-03 12:18:17 +04:00
return NT_STATUS_OK ;
}
2011-09-19 21:05:20 +04:00
NTSTATUS smb2cli_session_create_channel ( TALLOC_CTX * mem_ctx ,
struct smbXcli_session * session1 ,
struct smbXcli_conn * conn ,
struct smbXcli_session * * _session2 )
{
struct smbXcli_session * session2 ;
2021-03-05 18:43:29 +03:00
NTSTATUS status ;
2011-09-19 21:05:20 +04:00
2019-03-04 18:59:51 +03:00
if ( ! smb2_signing_key_valid ( session1 - > smb2 - > signing_key ) ) {
2012-07-20 11:30:05 +04:00
return NT_STATUS_INVALID_PARAMETER_MIX ;
}
2011-09-19 21:05:20 +04:00
if ( conn = = NULL ) {
return NT_STATUS_INVALID_PARAMETER_MIX ;
}
session2 = talloc_zero ( mem_ctx , struct smbXcli_session ) ;
if ( session2 = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2012-07-26 04:36:37 +04:00
session2 - > smb2 = talloc_reference ( session2 , session1 - > smb2 ) ;
if ( session2 - > smb2 = = NULL ) {
talloc_free ( session2 ) ;
2012-07-20 11:30:05 +04:00
return NT_STATUS_NO_MEMORY ;
}
2011-09-19 21:05:20 +04:00
talloc_set_destructor ( session2 , smbXcli_session_destructor ) ;
2016-02-05 13:32:18 +03:00
DLIST_ADD_END ( conn - > sessions , session2 ) ;
2011-09-19 21:05:20 +04:00
session2 - > conn = conn ;
2021-03-05 18:43:29 +03:00
status = smb2_signing_key_sign_create ( session2 ,
conn - > smb2 . server . sign_algo ,
NULL , /* no master key */
NULL , /* derivations */
& session2 - > smb2_channel . signing_key ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2019-06-07 19:58:43 +03:00
talloc_free ( session2 ) ;
return NT_STATUS_NO_MEMORY ;
}
2014-09-25 00:58:49 +04:00
memcpy ( session2 - > smb2_channel . preauth_sha512 ,
conn - > smb2 . preauth_sha512 ,
sizeof ( session2 - > smb2_channel . preauth_sha512 ) ) ;
2011-09-19 21:05:20 +04:00
* _session2 = session2 ;
return NT_STATUS_OK ;
}
2012-02-27 11:48:55 +04:00
NTSTATUS smb2cli_session_set_channel_key ( struct smbXcli_session * session ,
const DATA_BLOB _channel_key ,
const struct iovec * recv_iov )
{
struct smbXcli_conn * conn = session - > conn ;
uint8_t channel_key [ 16 ] ;
NTSTATUS status ;
2014-09-25 00:58:49 +04:00
struct _derivation {
DATA_BLOB label ;
DATA_BLOB context ;
} ;
struct {
struct _derivation signing ;
2019-01-15 17:42:09 +03:00
} derivation = {
. signing . label . length = 0 ,
} ;
2012-02-27 11:48:55 +04:00
if ( conn = = NULL ) {
return NT_STATUS_INVALID_PARAMETER_MIX ;
}
2019-03-04 18:59:51 +03:00
if ( smb2_signing_key_valid ( session - > smb2_channel . signing_key ) ) {
2012-02-27 11:48:55 +04:00
return NT_STATUS_INVALID_PARAMETER_MIX ;
}
2020-11-11 17:14:12 +03:00
if ( conn - > protocol > = PROTOCOL_SMB3_11 ) {
2014-09-25 00:58:49 +04:00
struct _derivation * d ;
DATA_BLOB p ;
p = data_blob_const ( session - > smb2_channel . preauth_sha512 ,
sizeof ( session - > smb2_channel . preauth_sha512 ) ) ;
d = & derivation . signing ;
d - > label = data_blob_string_const_null ( " SMBSigningKey " ) ;
d - > context = p ;
2020-11-11 17:14:12 +03:00
} else if ( conn - > protocol > = PROTOCOL_SMB3_00 ) {
2014-09-25 00:58:49 +04:00
struct _derivation * d ;
d = & derivation . signing ;
d - > label = data_blob_string_const_null ( " SMB2AESCMAC " ) ;
d - > context = data_blob_string_const_null ( " SmbSign " ) ;
}
2012-02-27 11:48:55 +04:00
ZERO_STRUCT ( channel_key ) ;
memcpy ( channel_key , _channel_key . data ,
MIN ( _channel_key . length , sizeof ( channel_key ) ) ) ;
2019-03-04 18:59:51 +03:00
session - > smb2_channel . signing_key - > blob =
data_blob_talloc ( session - > smb2_channel . signing_key ,
channel_key ,
sizeof ( channel_key ) ) ;
if ( ! smb2_signing_key_valid ( session - > smb2_channel . signing_key ) ) {
2012-02-27 12:33:46 +04:00
ZERO_STRUCT ( channel_key ) ;
2012-02-27 11:48:55 +04:00
return NT_STATUS_NO_MEMORY ;
}
2020-11-11 17:14:12 +03:00
if ( conn - > protocol > = PROTOCOL_SMB3_00 ) {
2014-09-25 00:58:49 +04:00
struct _derivation * d = & derivation . signing ;
2012-02-27 12:33:46 +04:00
2023-11-29 01:36:57 +03:00
status = samba_gnutls_sp800_108_derive_key (
channel_key ,
sizeof ( channel_key ) ,
2023-11-29 05:46:30 +03:00
NULL ,
0 ,
2023-11-29 01:36:57 +03:00
d - > label . data ,
d - > label . length ,
d - > context . data ,
d - > context . length ,
GNUTLS_MAC_SHA256 ,
session - > smb2_channel . signing_key - > blob . data ,
session - > smb2_channel . signing_key - > blob . length ) ;
2019-06-11 13:03:33 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2012-02-27 12:33:46 +04:00
}
ZERO_STRUCT ( channel_key ) ;
2019-03-14 19:42:34 +03:00
status = smb2_signing_check_pdu ( session - > smb2_channel . signing_key ,
2012-02-27 11:48:55 +04:00
recv_iov , 3 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
return NT_STATUS_OK ;
}
2012-06-02 20:03:20 +04:00
2013-08-16 21:44:34 +04:00
NTSTATUS smb2cli_session_encryption_on ( struct smbXcli_session * session )
{
2015-09-30 22:23:25 +03:00
if ( ! session - > smb2 - > should_sign ) {
/*
* We need required signing on the session
* in order to prevent man in the middle attacks .
*/
return NT_STATUS_INVALID_PARAMETER_MIX ;
}
2013-08-16 21:44:34 +04:00
if ( session - > smb2 - > should_encrypt ) {
return NT_STATUS_OK ;
}
2020-11-11 17:14:12 +03:00
if ( session - > conn - > protocol < PROTOCOL_SMB3_00 ) {
2013-08-16 21:44:34 +04:00
return NT_STATUS_NOT_SUPPORTED ;
}
2014-10-13 12:39:45 +04:00
if ( session - > conn - > smb2 . server . cipher = = 0 ) {
2013-08-16 21:44:34 +04:00
return NT_STATUS_NOT_SUPPORTED ;
}
2019-03-04 18:59:51 +03:00
if ( ! smb2_signing_key_valid ( session - > smb2 - > signing_key ) ) {
2013-08-16 21:44:34 +04:00
return NT_STATUS_NOT_SUPPORTED ;
}
session - > smb2 - > should_encrypt = true ;
return NT_STATUS_OK ;
}
2020-08-20 13:09:05 +03:00
uint16_t smb2cli_session_get_encryption_cipher ( struct smbXcli_session * session )
{
2020-11-11 17:14:12 +03:00
if ( session - > conn - > protocol < PROTOCOL_SMB3_00 ) {
2020-08-20 13:09:05 +03:00
return 0 ;
}
if ( ! session - > smb2 - > should_encrypt ) {
return 0 ;
}
return session - > conn - > smb2 . server . cipher ;
}
2012-06-02 20:03:20 +04:00
struct smbXcli_tcon * smbXcli_tcon_create ( TALLOC_CTX * mem_ctx )
{
struct smbXcli_tcon * tcon ;
tcon = talloc_zero ( mem_ctx , struct smbXcli_tcon ) ;
if ( tcon = = NULL ) {
return NULL ;
}
return tcon ;
}
2017-06-14 02:06:22 +03:00
/*
* Return a deep structure copy of a struct smbXcli_tcon *
*/
struct smbXcli_tcon * smbXcli_tcon_copy ( TALLOC_CTX * mem_ctx ,
const struct smbXcli_tcon * tcon_in )
{
struct smbXcli_tcon * tcon ;
tcon = talloc_memdup ( mem_ctx , tcon_in , sizeof ( struct smbXcli_tcon ) ) ;
if ( tcon = = NULL ) {
return NULL ;
}
/* Deal with the SMB1 strings. */
if ( tcon_in - > smb1 . service ! = NULL ) {
tcon - > smb1 . service = talloc_strdup ( tcon , tcon_in - > smb1 . service ) ;
if ( tcon - > smb1 . service = = NULL ) {
TALLOC_FREE ( tcon ) ;
return NULL ;
}
}
if ( tcon - > smb1 . fs_type ! = NULL ) {
tcon - > smb1 . fs_type = talloc_strdup ( tcon , tcon_in - > smb1 . fs_type ) ;
if ( tcon - > smb1 . fs_type = = NULL ) {
TALLOC_FREE ( tcon ) ;
return NULL ;
}
}
return tcon ;
}
2013-09-27 07:02:09 +04:00
void smbXcli_tcon_set_fs_attributes ( struct smbXcli_tcon * tcon ,
uint32_t fs_attributes )
{
tcon - > fs_attributes = fs_attributes ;
}
uint32_t smbXcli_tcon_get_fs_attributes ( struct smbXcli_tcon * tcon )
{
return tcon - > fs_attributes ;
}
2013-09-13 13:07:32 +04:00
bool smbXcli_tcon_is_dfs_share ( struct smbXcli_tcon * tcon )
{
if ( tcon = = NULL ) {
return false ;
}
if ( tcon - > is_smb1 ) {
if ( tcon - > smb1 . optional_support & SMB_SHARE_IN_DFS ) {
return true ;
}
return false ;
}
if ( tcon - > smb2 . capabilities & SMB2_SHARE_CAP_DFS ) {
return true ;
}
return false ;
}
2012-06-02 20:03:20 +04:00
uint16_t smb1cli_tcon_current_id ( struct smbXcli_tcon * tcon )
{
return tcon - > smb1 . tcon_id ;
}
void smb1cli_tcon_set_id ( struct smbXcli_tcon * tcon , uint16_t tcon_id )
{
2013-09-13 13:07:32 +04:00
tcon - > is_smb1 = true ;
2012-06-02 20:03:20 +04:00
tcon - > smb1 . tcon_id = tcon_id ;
}
bool smb1cli_tcon_set_values ( struct smbXcli_tcon * tcon ,
uint16_t tcon_id ,
uint16_t optional_support ,
uint32_t maximal_access ,
uint32_t guest_maximal_access ,
const char * service ,
const char * fs_type )
{
2013-09-13 13:07:32 +04:00
tcon - > is_smb1 = true ;
2013-09-27 07:02:09 +04:00
tcon - > fs_attributes = 0 ;
2012-06-02 20:03:20 +04:00
tcon - > smb1 . tcon_id = tcon_id ;
tcon - > smb1 . optional_support = optional_support ;
tcon - > smb1 . maximal_access = maximal_access ;
tcon - > smb1 . guest_maximal_access = guest_maximal_access ;
TALLOC_FREE ( tcon - > smb1 . service ) ;
tcon - > smb1 . service = talloc_strdup ( tcon , service ) ;
if ( service ! = NULL & & tcon - > smb1 . service = = NULL ) {
return false ;
}
TALLOC_FREE ( tcon - > smb1 . fs_type ) ;
tcon - > smb1 . fs_type = talloc_strdup ( tcon , fs_type ) ;
if ( fs_type ! = NULL & & tcon - > smb1 . fs_type = = NULL ) {
return false ;
}
return true ;
}
uint32_t smb2cli_tcon_current_id ( struct smbXcli_tcon * tcon )
{
return tcon - > smb2 . tcon_id ;
}
2017-06-14 02:08:22 +03:00
void smb2cli_tcon_set_id ( struct smbXcli_tcon * tcon , uint32_t tcon_id )
{
tcon - > smb2 . tcon_id = tcon_id ;
}
2012-07-25 11:27:00 +04:00
uint32_t smb2cli_tcon_capabilities ( struct smbXcli_tcon * tcon )
{
return tcon - > smb2 . capabilities ;
}
2015-10-10 01:08:05 +03:00
uint32_t smb2cli_tcon_flags ( struct smbXcli_tcon * tcon )
{
return tcon - > smb2 . flags ;
}
2012-06-02 20:03:20 +04:00
void smb2cli_tcon_set_values ( struct smbXcli_tcon * tcon ,
2012-07-25 14:33:39 +04:00
struct smbXcli_session * session ,
2012-06-02 20:03:20 +04:00
uint32_t tcon_id ,
uint8_t type ,
uint32_t flags ,
uint32_t capabilities ,
uint32_t maximal_access )
{
2013-09-13 13:07:32 +04:00
tcon - > is_smb1 = false ;
2013-09-27 07:02:09 +04:00
tcon - > fs_attributes = 0 ;
2012-06-02 20:03:20 +04:00
tcon - > smb2 . tcon_id = tcon_id ;
tcon - > smb2 . type = type ;
tcon - > smb2 . flags = flags ;
tcon - > smb2 . capabilities = capabilities ;
tcon - > smb2 . maximal_access = maximal_access ;
2012-07-25 14:34:20 +04:00
2014-09-26 08:29:02 +04:00
tcon - > smb2 . should_sign = false ;
2012-07-25 14:34:20 +04:00
tcon - > smb2 . should_encrypt = false ;
if ( session = = NULL ) {
return ;
}
2014-09-26 08:29:02 +04:00
tcon - > smb2 . should_sign = session - > smb2 - > should_sign ;
2012-07-26 04:36:37 +04:00
tcon - > smb2 . should_encrypt = session - > smb2 - > should_encrypt ;
2012-07-25 14:34:20 +04:00
if ( flags & SMB2_SHAREFLAG_ENCRYPT_DATA ) {
tcon - > smb2 . should_encrypt = true ;
}
2012-06-02 20:03:20 +04:00
}
2013-09-20 09:46:54 +04:00
2014-09-26 08:29:02 +04:00
void smb2cli_tcon_should_sign ( struct smbXcli_tcon * tcon ,
bool should_sign )
{
tcon - > smb2 . should_sign = should_sign ;
}
bool smb2cli_tcon_is_signing_on ( struct smbXcli_tcon * tcon )
{
if ( tcon - > smb2 . should_encrypt ) {
return true ;
}
return tcon - > smb2 . should_sign ;
}
2014-09-26 08:25:53 +04:00
void smb2cli_tcon_should_encrypt ( struct smbXcli_tcon * tcon ,
bool should_encrypt )
{
tcon - > smb2 . should_encrypt = should_encrypt ;
}
2013-09-20 09:46:54 +04:00
bool smb2cli_tcon_is_encryption_on ( struct smbXcli_tcon * tcon )
{
return tcon - > smb2 . should_encrypt ;
}
2017-02-26 11:28:12 +03:00
void smb2cli_conn_set_mid ( struct smbXcli_conn * conn , uint64_t mid )
{
conn - > smb2 . mid = mid ;
}
uint64_t smb2cli_conn_get_mid ( struct smbXcli_conn * conn )
{
return conn - > smb2 . mid ;
}
2021-06-29 16:24:13 +03:00
NTSTATUS smb2cli_parse_dyn_buffer ( uint32_t dyn_offset ,
const DATA_BLOB dyn_buffer ,
uint32_t min_offset ,
uint32_t buffer_offset ,
uint32_t buffer_length ,
uint32_t max_length ,
uint32_t * next_offset ,
DATA_BLOB * buffer )
{
uint32_t offset ;
bool oob ;
* buffer = data_blob_null ;
* next_offset = dyn_offset ;
if ( buffer_offset = = 0 ) {
/*
* If the offset is 0 , we better ignore
* the buffer_length field .
*/
return NT_STATUS_OK ;
}
if ( buffer_length = = 0 ) {
/*
* If the length is 0 , we better ignore
* the buffer_offset field .
*/
return NT_STATUS_OK ;
}
if ( ( buffer_offset % 8 ) ! = 0 ) {
/*
* The offset needs to be 8 byte aligned .
*/
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
/*
* We used to enforce buffer_offset to be
* an exact match of the expected minimum ,
* but the NetApp Ontap 7.3 .7 SMB server
* gets the padding wrong and aligns the
* input_buffer_offset by a value of 8.
*
* So we just enforce that the offset is
* not lower than the expected value .
*/
SMB_ASSERT ( min_offset > = dyn_offset ) ;
if ( buffer_offset < min_offset ) {
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
/*
* Make [ input | output ] _buffer_offset relative to " dyn_buffer "
*/
offset = buffer_offset - dyn_offset ;
oob = smb_buffer_oob ( dyn_buffer . length , offset , buffer_length ) ;
if ( oob ) {
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
/*
* Give the caller a hint what we consumed ,
* the caller may need to add possible padding .
*/
* next_offset = buffer_offset + buffer_length ;
if ( max_length = = 0 ) {
/*
* If max_input_length is 0 we ignore the
* input_buffer_length , because Windows 2008 echos the
* DCERPC request from the requested input_buffer to
* the response input_buffer .
*
* We just use the same logic also for max_output_length . . .
*/
buffer_length = 0 ;
}
if ( buffer_length > max_length ) {
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
* buffer = ( DATA_BLOB ) {
. data = dyn_buffer . data + offset ,
. length = buffer_length ,
} ;
return NT_STATUS_OK ;
}