2009-05-14 17:32:02 +04:00
/*
Unix SMB / CIFS implementation .
Core SMB2 server
Copyright ( C ) Stefan Metzmacher 2009
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-03-22 18:57:01 +03:00
# include "smbd/smbd.h"
2009-05-14 17:32:02 +04:00
# include "smbd/globals.h"
2009-08-12 19:52:55 +04:00
# include "../libcli/smb/smb_common.h"
2014-10-08 21:25:15 +04:00
# include "../libcli/smb/smb2_negotiate_context.h"
2012-03-10 05:08:36 +04:00
# include "../lib/tsocket/tsocket.h"
2011-12-15 17:45:56 +04:00
# include "../librpc/ndr/libndr.h"
2015-07-15 11:57:03 +03:00
# include "../libcli/smb/smb_signing.h"
2022-03-11 20:18:04 +03:00
# include "auth.h"
# include "auth/gensec/gensec.h"
# include "lib/util/string_wrappers.h"
2022-11-30 18:28:56 +03:00
# include "source3/lib/substitute.h"
2023-04-25 18:38:30 +03:00
# ifdef HAVE_VALGRIND_CALLGRIND_H
# include <valgrind/callgrind.h>
# endif /* HAVE_VALGRIND_CALLGRIND_H */
2009-05-14 17:32:02 +04:00
2018-03-21 22:01:05 +03:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_SMB2
2009-05-19 12:47:51 +04:00
/*
* this is the entry point if SMB2 is selected via
2011-09-05 15:14:40 +04:00
* the SMB negprot and the given dialect .
2009-05-19 12:47:51 +04:00
*/
2019-11-26 23:21:06 +03:00
static NTSTATUS reply_smb20xx ( struct smb_request * req , uint16_t dialect )
2009-05-19 12:47:51 +04:00
{
2014-06-24 21:28:51 +04:00
uint8_t * smb2_inpdu ;
2009-05-19 12:47:51 +04:00
uint8_t * smb2_hdr ;
uint8_t * smb2_body ;
uint8_t * smb2_dyn ;
2014-06-24 21:28:51 +04:00
size_t len = SMB2_HDR_BODY + 0x24 + 2 ;
2009-05-19 12:47:51 +04:00
2014-06-24 21:28:51 +04:00
smb2_inpdu = talloc_zero_array ( talloc_tos ( ) , uint8_t , len ) ;
if ( smb2_inpdu = = NULL ) {
2009-05-19 12:47:51 +04:00
DEBUG ( 0 , ( " Could not push spnego blob \n " ) ) ;
reply_nterror ( req , NT_STATUS_NO_MEMORY ) ;
2019-11-26 23:21:06 +03:00
return NT_STATUS_NO_MEMORY ;
2009-05-19 12:47:51 +04:00
}
2014-06-24 21:28:51 +04:00
smb2_hdr = smb2_inpdu ;
2009-05-19 12:47:51 +04:00
smb2_body = smb2_hdr + SMB2_HDR_BODY ;
smb2_dyn = smb2_body + 0x24 ;
SIVAL ( smb2_hdr , SMB2_HDR_PROTOCOL_ID , SMB2_MAGIC ) ;
SIVAL ( smb2_hdr , SMB2_HDR_LENGTH , SMB2_HDR_BODY ) ;
SSVAL ( smb2_body , 0x00 , 0x0024 ) ; /* struct size */
SSVAL ( smb2_body , 0x02 , 0x0001 ) ; /* dialect count */
2011-09-05 15:14:40 +04:00
SSVAL ( smb2_dyn , 0x00 , dialect ) ;
2009-05-19 12:47:51 +04:00
req - > outbuf = NULL ;
2019-11-26 23:21:06 +03:00
return smbd_smb2_process_negprot ( req - > xconn , 0 , smb2_inpdu , len ) ;
2009-05-19 12:47:51 +04:00
}
2011-09-05 15:14:40 +04:00
/*
* this is the entry point if SMB2 is selected via
* the SMB negprot and the " SMB 2.002 " dialect .
*/
2019-11-26 23:43:25 +03:00
NTSTATUS reply_smb2002 ( struct smb_request * req , uint16_t choice )
2011-09-05 15:14:40 +04:00
{
2019-11-26 23:43:25 +03:00
return reply_smb20xx ( req , SMB2_DIALECT_REVISION_202 ) ;
2011-09-05 15:14:40 +04:00
}
/*
* this is the entry point if SMB2 is selected via
* the SMB negprot and the " SMB 2.??? " dialect .
*/
2019-11-26 23:43:25 +03:00
NTSTATUS reply_smb20ff ( struct smb_request * req , uint16_t choice )
2011-09-05 15:14:40 +04:00
{
2014-06-12 10:38:48 +04:00
struct smbXsrv_connection * xconn = req - > xconn ;
2014-05-23 12:07:21 +04:00
xconn - > smb2 . allow_2ff = true ;
2019-11-26 23:43:25 +03:00
return reply_smb20xx ( req , SMB2_DIALECT_REVISION_2FF ) ;
2011-09-05 15:14:40 +04:00
}
2014-06-21 08:29:26 +04:00
enum protocol_types smbd_smb2_protocol_dialect_match ( const uint8_t * indyn ,
const int dialect_count ,
uint16_t * dialect )
2009-05-14 17:32:02 +04:00
{
2014-09-26 08:31:58 +04:00
struct {
enum protocol_types proto ;
uint16_t dialect ;
} pd [ ] = {
2014-10-13 13:01:59 +04:00
{ PROTOCOL_SMB3_11 , SMB3_DIALECT_REVISION_311 } ,
2014-10-13 13:01:59 +04:00
{ PROTOCOL_SMB3_02 , SMB3_DIALECT_REVISION_302 } ,
2014-09-26 08:31:58 +04:00
{ PROTOCOL_SMB3_00 , SMB3_DIALECT_REVISION_300 } ,
{ PROTOCOL_SMB2_10 , SMB2_DIALECT_REVISION_210 } ,
{ PROTOCOL_SMB2_02 , SMB2_DIALECT_REVISION_202 } ,
} ;
size_t i ;
for ( i = 0 ; i < ARRAY_SIZE ( pd ) ; i + + ) {
2019-02-11 11:02:39 +03:00
int c = 0 ;
2014-09-26 08:31:58 +04:00
if ( lp_server_max_protocol ( ) < pd [ i ] . proto ) {
continue ;
2011-09-05 15:14:40 +04:00
}
2014-09-26 08:31:58 +04:00
if ( lp_server_min_protocol ( ) > pd [ i ] . proto ) {
continue ;
2011-09-05 15:14:40 +04:00
}
2014-09-26 08:31:58 +04:00
for ( c = 0 ; c < dialect_count ; c + + ) {
* dialect = SVAL ( indyn , c * 2 ) ;
if ( * dialect = = pd [ i ] . dialect ) {
return pd [ i ] . proto ;
}
2009-05-14 17:32:02 +04:00
}
}
2014-09-26 08:31:58 +04:00
return PROTOCOL_NONE ;
2014-06-21 08:29:26 +04:00
}
2020-07-06 18:27:05 +03:00
struct smbd_smb2_request_process_negprot_state {
struct smbd_smb2_request * req ;
DATA_BLOB outbody ;
DATA_BLOB outdyn ;
} ;
static void smbd_smb2_request_process_negprot_mc_done ( struct tevent_req * subreq ) ;
2014-06-21 08:29:26 +04:00
NTSTATUS smbd_smb2_request_process_negprot ( struct smbd_smb2_request * req )
{
2020-07-06 18:27:05 +03:00
struct smbd_smb2_request_process_negprot_state * state = NULL ;
2014-06-12 10:38:48 +04:00
struct smbXsrv_connection * xconn = req - > xconn ;
2020-07-06 18:27:05 +03:00
struct tevent_req * subreq = NULL ;
2014-06-21 08:29:26 +04:00
NTSTATUS status ;
const uint8_t * inbody ;
const uint8_t * indyn = NULL ;
DATA_BLOB outbody ;
DATA_BLOB outdyn ;
DATA_BLOB negprot_spnego_blob ;
uint16_t security_offset ;
DATA_BLOB security_buffer ;
size_t expected_dyn_size = 0 ;
size_t c ;
uint16_t security_mode ;
uint16_t dialect_count ;
uint16_t in_security_mode ;
uint32_t in_capabilities ;
DATA_BLOB in_guid_blob ;
struct GUID in_guid ;
2014-10-08 21:25:15 +04:00
struct smb2_negotiate_contexts in_c = { . num_contexts = 0 , } ;
struct smb2_negotiate_context * in_preauth = NULL ;
struct smb2_negotiate_context * in_cipher = NULL ;
2020-11-11 16:27:30 +03:00
struct smb2_negotiate_context * in_sign_algo = NULL ;
2014-10-08 21:25:15 +04:00
struct smb2_negotiate_contexts out_c = { . num_contexts = 0 , } ;
2022-01-27 22:36:19 +03:00
struct smb2_negotiate_context * in_posix = NULL ;
2021-07-13 19:16:10 +03:00
const struct smb311_capabilities default_smb3_capabilities =
smb311_capabilities_parse ( " server " ,
2021-07-13 22:26:19 +03:00
lp_server_smb3_signing_algorithms ( ) ,
2021-07-13 19:16:10 +03:00
lp_server_smb3_encryption_algorithms ( ) ) ;
2014-10-08 21:25:15 +04:00
DATA_BLOB out_negotiate_context_blob = data_blob_null ;
uint32_t out_negotiate_context_offset = 0 ;
uint16_t out_negotiate_context_count = 0 ;
2014-06-21 08:29:26 +04:00
uint16_t dialect = 0 ;
uint32_t capabilities ;
DATA_BLOB out_guid_blob ;
struct GUID out_guid ;
enum protocol_types protocol = PROTOCOL_NONE ;
uint32_t max_limit ;
uint32_t max_trans = lp_smb2_max_trans ( ) ;
uint32_t max_read = lp_smb2_max_read ( ) ;
uint32_t max_write = lp_smb2_max_write ( ) ;
NTTIME now = timeval_to_nttime ( & req - > request_time ) ;
2016-04-13 18:44:26 +03:00
bool ok ;
2014-06-21 08:29:26 +04:00
status = smbd_smb2_request_verify_sizes ( req , 0x24 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return smbd_smb2_request_error ( req , status ) ;
}
inbody = SMBD_SMB2_IN_BODY_PTR ( req ) ;
dialect_count = SVAL ( inbody , 0x02 ) ;
in_security_mode = SVAL ( inbody , 0x04 ) ;
in_capabilities = IVAL ( inbody , 0x08 ) ;
in_guid_blob = data_blob_const ( inbody + 0x0C , 16 ) ;
if ( dialect_count = = 0 ) {
return smbd_smb2_request_error ( req , NT_STATUS_INVALID_PARAMETER ) ;
}
status = GUID_from_ndr_blob ( & in_guid_blob , & in_guid ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return smbd_smb2_request_error ( req , status ) ;
}
expected_dyn_size = dialect_count * 2 ;
if ( SMBD_SMB2_IN_DYN_LEN ( req ) < expected_dyn_size ) {
return smbd_smb2_request_error ( req , NT_STATUS_INVALID_PARAMETER ) ;
}
indyn = SMBD_SMB2_IN_DYN_PTR ( req ) ;
protocol = smbd_smb2_protocol_dialect_match ( indyn ,
dialect_count ,
& dialect ) ;
2011-09-05 15:14:40 +04:00
for ( c = 0 ; protocol = = PROTOCOL_NONE & & c < dialect_count ; c + + ) {
2014-02-04 06:09:09 +04:00
if ( lp_server_max_protocol ( ) < PROTOCOL_SMB2_10 ) {
2011-09-05 15:14:40 +04:00
break ;
}
dialect = SVAL ( indyn , c * 2 ) ;
if ( dialect = = SMB2_DIALECT_REVISION_2FF ) {
2014-05-23 12:07:21 +04:00
if ( xconn - > smb2 . allow_2ff ) {
xconn - > smb2 . allow_2ff = false ;
2011-09-05 15:14:40 +04:00
protocol = PROTOCOL_SMB2_10 ;
break ;
}
}
}
2011-09-05 14:23:51 +04:00
if ( protocol = = PROTOCOL_NONE ) {
return smbd_smb2_request_error ( req , NT_STATUS_NOT_SUPPORTED ) ;
2009-05-14 17:32:02 +04:00
}
2020-11-11 17:14:12 +03:00
if ( protocol > = PROTOCOL_SMB3_11 ) {
2014-10-08 21:25:15 +04:00
uint32_t in_negotiate_context_offset = 0 ;
uint16_t in_negotiate_context_count = 0 ;
DATA_BLOB in_negotiate_context_blob = data_blob_null ;
size_t ofs ;
in_negotiate_context_offset = IVAL ( inbody , 0x1C ) ;
in_negotiate_context_count = SVAL ( inbody , 0x20 ) ;
ofs = SMB2_HDR_BODY ;
ofs + = SMBD_SMB2_IN_BODY_LEN ( req ) ;
ofs + = expected_dyn_size ;
if ( ( ofs % 8 ) ! = 0 ) {
ofs + = 8 - ( ofs % 8 ) ;
}
if ( in_negotiate_context_offset ! = ofs ) {
return smbd_smb2_request_error ( req ,
NT_STATUS_INVALID_PARAMETER ) ;
}
ofs - = SMB2_HDR_BODY ;
ofs - = SMBD_SMB2_IN_BODY_LEN ( req ) ;
if ( SMBD_SMB2_IN_DYN_LEN ( req ) < ofs ) {
return smbd_smb2_request_error ( req ,
NT_STATUS_INVALID_PARAMETER ) ;
}
in_negotiate_context_blob = data_blob_const ( indyn ,
SMBD_SMB2_IN_DYN_LEN ( req ) ) ;
in_negotiate_context_blob . data + = ofs ;
in_negotiate_context_blob . length - = ofs ;
status = smb2_negotiate_context_parse ( req ,
2021-05-09 22:16:00 +03:00
in_negotiate_context_blob ,
in_negotiate_context_count ,
& in_c ) ;
2014-10-08 21:25:15 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return smbd_smb2_request_error ( req , status ) ;
}
2022-01-27 22:36:19 +03:00
2023-09-19 02:54:05 +03:00
in_posix = smb2_negotiate_context_find (
& in_c ,
SMB2_POSIX_EXTENSIONS_AVAILABLE ) ;
if ( in_posix ! = NULL ) {
const uint8_t * inbuf = in_posix - > data . data ;
size_t inbuflen = in_posix - > data . length ;
bool posix_found = false ;
/*
* For now the server only supports one variant .
* Check it ' s the right one .
*/
if ( ( inbuflen % 16 ) ! = 0 ) {
return smbd_smb2_request_error (
req ,
NT_STATUS_INVALID_PARAMETER ) ;
}
SMB_ASSERT ( strlen ( SMB2_CREATE_TAG_POSIX ) = = 16 ) ;
for ( ofs = 0 ; ofs < inbuflen ; ofs + = 16 ) {
if ( memcmp ( inbuf + ofs ,
SMB2_CREATE_TAG_POSIX ,
16 ) = = 0 ) {
posix_found = true ;
break ;
2022-01-27 22:36:19 +03:00
}
}
2023-09-19 02:54:05 +03:00
if ( posix_found ) {
DBG_DEBUG ( " Client requested SMB2 unix "
" extensions \n " ) ;
} else {
DBG_DEBUG ( " Client requested unknown "
" SMB2 unix extensions: \n " ) ;
dump_data ( 10 , inbuf , inbuflen ) ;
in_posix = NULL ;
}
2022-01-27 22:36:19 +03:00
}
2014-10-08 21:25:15 +04:00
}
2016-04-13 18:44:26 +03:00
if ( ( dialect ! = SMB2_DIALECT_REVISION_2FF ) & &
( protocol > = PROTOCOL_SMB2_10 ) & &
! GUID_all_zero ( & in_guid ) )
{
ok = remote_arch_cache_update ( & in_guid ) ;
if ( ! ok ) {
return smbd_smb2_request_error (
req , NT_STATUS_UNSUCCESSFUL ) ;
}
}
2016-03-02 21:18:34 +03:00
switch ( get_remote_arch ( ) ) {
case RA_VISTA :
case RA_SAMBA :
case RA_CIFSFS :
case RA_OSX :
break ;
default :
2009-05-14 17:32:02 +04:00
set_remote_arch ( RA_VISTA ) ;
2016-03-02 21:18:34 +03:00
break ;
2009-05-14 17:32:02 +04:00
}
2022-11-30 18:28:56 +03:00
{
fstring proto ;
fstr_sprintf ( proto ,
" SMB%X_%02X " ,
( dialect > > 8 ) & 0xFF , dialect & 0xFF ) ;
set_remote_proto ( proto ) ;
DEBUG ( 3 , ( " Selected protocol %s \n " , proto ) ) ;
}
2012-12-13 13:44:07 +04:00
reload_services ( req - > sconn , conn_snum_used , true ) ;
2014-10-08 21:25:15 +04:00
in_preauth = smb2_negotiate_context_find ( & in_c ,
SMB2_PREAUTH_INTEGRITY_CAPABILITIES ) ;
2020-11-11 17:14:12 +03:00
if ( protocol > = PROTOCOL_SMB3_11 & & in_preauth = = NULL ) {
2014-10-08 21:25:15 +04:00
return smbd_smb2_request_error ( req , NT_STATUS_INVALID_PARAMETER ) ;
}
in_cipher = smb2_negotiate_context_find ( & in_c ,
SMB2_ENCRYPTION_CAPABILITIES ) ;
2020-11-11 16:27:30 +03:00
in_sign_algo = smb2_negotiate_context_find ( & in_c ,
SMB2_SIGNING_CAPABILITIES ) ;
2014-10-08 21:25:15 +04:00
2023-09-07 07:09:38 +03:00
/* negprot_spnego() returns the server guid in the first 16 bytes */
2014-06-11 14:41:26 +04:00
negprot_spnego_blob = negprot_spnego ( req , xconn ) ;
2009-05-14 17:32:02 +04:00
if ( negprot_spnego_blob . data = = NULL ) {
return smbd_smb2_request_error ( req , NT_STATUS_NO_MEMORY ) ;
}
if ( negprot_spnego_blob . length < 16 ) {
return smbd_smb2_request_error ( req , NT_STATUS_INTERNAL_ERROR ) ;
}
2012-10-03 23:50:42 +04:00
security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED ;
2022-03-08 06:04:23 +03:00
if ( xconn - > smb2 . signing_mandatory ) {
2012-10-03 23:50:42 +04:00
security_mode | = SMB2_NEGOTIATE_SIGNING_REQUIRED ;
2009-05-22 23:26:03 +04:00
}
capabilities = 0 ;
if ( lp_host_msdfs ( ) ) {
capabilities | = SMB2_CAP_DFS ;
}
2014-10-29 01:31:46 +03:00
if ( protocol > = PROTOCOL_SMB2_10 & &
lp_smb2_leases ( ) & &
lp_oplocks ( GLOBAL_SECTION_SNUM ) & &
! lp_kernel_oplocks ( GLOBAL_SECTION_SNUM ) )
{
capabilities | = SMB2_CAP_LEASING ;
}
2020-11-11 17:14:12 +03:00
if ( ( protocol > = PROTOCOL_SMB3_00 ) & &
2020-05-26 10:34:54 +03:00
( lp_server_smb_encrypt ( - 1 ) ! = SMB_ENCRYPTION_OFF ) & &
2012-09-12 18:43:36 +04:00
( in_capabilities & SMB2_CAP_ENCRYPTION ) ) {
capabilities | = SMB2_CAP_ENCRYPTION ;
2012-08-08 09:07:53 +04:00
}
2011-09-05 14:14:06 +04:00
/*
* 0x10000 ( 65536 ) is the maximum allowed message size
2012-02-27 17:57:47 +04:00
* for SMB 2.0
2011-09-05 14:14:06 +04:00
*/
max_limit = 0x10000 ;
2012-02-27 17:57:47 +04:00
if ( protocol > = PROTOCOL_SMB2_10 ) {
2012-06-25 23:40:00 +04:00
int p = 0 ;
2012-02-27 17:57:47 +04:00
2012-06-25 23:40:00 +04:00
if ( tsocket_address_is_inet ( req - > sconn - > local_address , " ip " ) ) {
p = tsocket_address_inet_port ( req - > sconn - > local_address ) ;
}
/* largeMTU is not supported over NBT (tcp port 139) */
if ( p ! = NBT_SMB_PORT ) {
2012-02-27 17:57:47 +04:00
capabilities | = SMB2_CAP_LARGE_MTU ;
2014-05-23 14:10:23 +04:00
xconn - > smb2 . credits . multicredit = true ;
2012-02-27 17:57:47 +04:00
2014-09-26 08:13:10 +04:00
/*
2015-02-25 16:00:49 +03:00
* We allow up to almost 16 MB .
2014-09-26 08:13:10 +04:00
*
* The maximum PDU size is 0xFFFFFF ( 16776960 )
* and we need some space for the header .
*/
max_limit = 0xFFFF00 ;
2012-02-27 17:57:47 +04:00
}
}
/*
2014-06-13 03:55:21 +04:00
* the defaults are 8 MB , but we ' ll limit this to max_limit based on
* the dialect ( 64 kb for SMB 2.0 , 8 MB for SMB > = 2.1 with LargeMTU )
2012-02-27 17:57:47 +04:00
*
* user configured values exceeding the limits will be overwritten ,
* only smaller values will be accepted
*/
max_trans = MIN ( max_limit , lp_smb2_max_trans ( ) ) ;
max_read = MIN ( max_limit , lp_smb2_max_read ( ) ) ;
max_write = MIN ( max_limit , lp_smb2_max_write ( ) ) ;
2011-09-05 14:14:06 +04:00
2014-10-08 21:25:15 +04:00
if ( in_preauth ! = NULL ) {
size_t needed = 4 ;
uint16_t hash_count ;
uint16_t salt_length ;
uint16_t selected_preauth = 0 ;
const uint8_t * p ;
uint8_t buf [ 38 ] ;
size_t i ;
if ( in_preauth - > data . length < needed ) {
return smbd_smb2_request_error ( req ,
NT_STATUS_INVALID_PARAMETER ) ;
}
hash_count = SVAL ( in_preauth - > data . data , 0 ) ;
salt_length = SVAL ( in_preauth - > data . data , 2 ) ;
if ( hash_count = = 0 ) {
return smbd_smb2_request_error ( req ,
NT_STATUS_INVALID_PARAMETER ) ;
}
p = in_preauth - > data . data + needed ;
needed + = hash_count * 2 ;
needed + = salt_length ;
if ( in_preauth - > data . length < needed ) {
return smbd_smb2_request_error ( req ,
NT_STATUS_INVALID_PARAMETER ) ;
}
for ( i = 0 ; i < hash_count ; i + + ) {
uint16_t v ;
v = SVAL ( p , 0 ) ;
p + = 2 ;
if ( v = = SMB2_PREAUTH_INTEGRITY_SHA512 ) {
selected_preauth = v ;
break ;
}
}
if ( selected_preauth = = 0 ) {
return smbd_smb2_request_error ( req ,
NT_STATUS_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP ) ;
}
SSVAL ( buf , 0 , 1 ) ; /* HashAlgorithmCount */
SSVAL ( buf , 2 , 32 ) ; /* SaltLength */
SSVAL ( buf , 4 , selected_preauth ) ;
generate_random_buffer ( buf + 6 , 32 ) ;
2019-02-11 11:03:39 +03:00
status = smb2_negotiate_context_add (
req ,
& out_c ,
SMB2_PREAUTH_INTEGRITY_CAPABILITIES ,
buf ,
sizeof ( buf ) ) ;
2014-10-08 21:25:15 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return smbd_smb2_request_error ( req , status ) ;
}
req - > preauth = & req - > xconn - > smb2 . preauth ;
}
2020-11-11 17:14:12 +03:00
if ( protocol > = PROTOCOL_SMB3_00 ) {
2020-11-11 15:18:24 +03:00
xconn - > smb2 . server . sign_algo = SMB2_SIGNING_AES128_CMAC ;
} else {
xconn - > smb2 . server . sign_algo = SMB2_SIGNING_HMAC_SHA256 ;
}
2017-01-05 14:14:35 +03:00
if ( ( capabilities & SMB2_CAP_ENCRYPTION ) & & ( in_cipher ! = NULL ) ) {
2021-03-10 18:34:54 +03:00
const struct smb3_encryption_capabilities * srv_ciphers =
& default_smb3_capabilities . encryption ;
uint16_t srv_preferred_idx = UINT16_MAX ;
2014-10-08 21:25:15 +04:00
size_t needed = 2 ;
uint16_t cipher_count ;
const uint8_t * p ;
uint8_t buf [ 4 ] ;
size_t i ;
capabilities & = ~ SMB2_CAP_ENCRYPTION ;
if ( in_cipher - > data . length < needed ) {
return smbd_smb2_request_error ( req ,
NT_STATUS_INVALID_PARAMETER ) ;
}
cipher_count = SVAL ( in_cipher - > data . data , 0 ) ;
if ( cipher_count = = 0 ) {
return smbd_smb2_request_error ( req ,
NT_STATUS_INVALID_PARAMETER ) ;
}
p = in_cipher - > data . data + needed ;
needed + = cipher_count * 2 ;
if ( in_cipher - > data . length < needed ) {
return smbd_smb2_request_error ( req ,
NT_STATUS_INVALID_PARAMETER ) ;
}
for ( i = 0 ; i < cipher_count ; i + + ) {
2021-03-10 18:34:54 +03:00
uint16_t si ;
2014-10-08 21:25:15 +04:00
uint16_t v ;
v = SVAL ( p , 0 ) ;
p + = 2 ;
2021-03-10 18:34:54 +03:00
for ( si = 0 ; si < srv_ciphers - > num_algos ; si + + ) {
if ( srv_ciphers - > algos [ si ] ! = v ) {
continue ;
}
/*
* The server ciphers are listed
* with the lowest idx being preferred .
*/
if ( si < srv_preferred_idx ) {
srv_preferred_idx = si ;
}
break ;
2014-10-08 21:25:15 +04:00
}
}
2021-03-10 18:34:54 +03:00
if ( srv_preferred_idx ! = UINT16_MAX ) {
xconn - > smb2 . server . cipher =
srv_ciphers - > algos [ srv_preferred_idx ] ;
2015-08-17 09:56:43 +03:00
}
2014-10-08 21:25:15 +04:00
SSVAL ( buf , 0 , 1 ) ; /* ChiperCount */
SSVAL ( buf , 2 , xconn - > smb2 . server . cipher ) ;
2019-02-11 11:03:39 +03:00
status = smb2_negotiate_context_add (
req ,
& out_c ,
SMB2_ENCRYPTION_CAPABILITIES ,
buf ,
sizeof ( buf ) ) ;
2014-10-08 21:25:15 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return smbd_smb2_request_error ( req , status ) ;
}
}
2014-10-13 13:07:01 +04:00
if ( capabilities & SMB2_CAP_ENCRYPTION ) {
xconn - > smb2 . server . cipher = SMB2_ENCRYPTION_AES128_CCM ;
}
2020-11-11 16:27:30 +03:00
if ( in_sign_algo ! = NULL ) {
const struct smb3_signing_capabilities * srv_sign_algos =
& default_smb3_capabilities . signing ;
uint16_t srv_preferred_idx = UINT16_MAX ;
size_t needed = 2 ;
uint16_t sign_algo_count ;
const uint8_t * p ;
size_t i ;
if ( in_sign_algo - > data . length < needed ) {
return smbd_smb2_request_error ( req ,
NT_STATUS_INVALID_PARAMETER ) ;
}
sign_algo_count = SVAL ( in_sign_algo - > data . data , 0 ) ;
if ( sign_algo_count = = 0 ) {
return smbd_smb2_request_error ( req ,
NT_STATUS_INVALID_PARAMETER ) ;
}
p = in_sign_algo - > data . data + needed ;
needed + = sign_algo_count * 2 ;
if ( in_sign_algo - > data . length < needed ) {
return smbd_smb2_request_error ( req ,
NT_STATUS_INVALID_PARAMETER ) ;
}
for ( i = 0 ; i < sign_algo_count ; i + + ) {
uint16_t si ;
uint16_t v ;
v = SVAL ( p , 0 ) ;
p + = 2 ;
for ( si = 0 ; si < srv_sign_algos - > num_algos ; si + + ) {
if ( srv_sign_algos - > algos [ si ] ! = v ) {
continue ;
}
/*
* The server sign_algos are listed
* with the lowest idx being preferred .
*/
if ( si < srv_preferred_idx ) {
srv_preferred_idx = si ;
}
break ;
}
}
/*
* If we found a match announce it
* otherwise we ' ll keep the default
* of SMB2_SIGNING_AES128_CMAC
*/
if ( srv_preferred_idx ! = UINT16_MAX ) {
uint8_t buf [ 4 ] ;
xconn - > smb2 . server . sign_algo =
srv_sign_algos - > algos [ srv_preferred_idx ] ;
SSVAL ( buf , 0 , 1 ) ; /* SigningAlgorithmCount */
SSVAL ( buf , 2 , xconn - > smb2 . server . sign_algo ) ;
status = smb2_negotiate_context_add (
req ,
& out_c ,
SMB2_SIGNING_CAPABILITIES ,
buf ,
sizeof ( buf ) ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return smbd_smb2_request_error ( req , status ) ;
}
}
}
2021-07-14 13:13:49 +03:00
status = smb311_capabilities_check ( & default_smb3_capabilities ,
" smb2srv_negprot " ,
DBGLVL_NOTICE ,
NT_STATUS_INVALID_PARAMETER ,
" server " ,
protocol ,
2021-07-13 22:26:19 +03:00
xconn - > smb2 . server . sign_algo ,
2021-07-14 13:13:49 +03:00
xconn - > smb2 . server . cipher ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return smbd_smb2_request_error ( req , status ) ;
}
2020-11-11 17:14:12 +03:00
if ( protocol > = PROTOCOL_SMB3_00 & &
2016-01-21 02:16:33 +03:00
xconn - > client - > server_multi_channel_enabled )
{
if ( in_capabilities & SMB2_CAP_MULTI_CHANNEL ) {
capabilities | = SMB2_CAP_MULTI_CHANNEL ;
}
}
2009-05-14 17:32:02 +04:00
security_offset = SMB2_HDR_BODY + 0x40 ;
2009-06-04 22:14:20 +04:00
# if 1
/* Try SPNEGO auth... */
2009-05-14 17:32:02 +04:00
security_buffer = data_blob_const ( negprot_spnego_blob . data + 16 ,
negprot_spnego_blob . length - 16 ) ;
2009-06-04 22:14:20 +04:00
# else
2009-05-20 21:45:28 +04:00
/* for now we want raw NTLMSSP */
security_buffer = data_blob_const ( NULL , 0 ) ;
2009-06-04 22:14:20 +04:00
# endif
2009-05-20 21:45:28 +04:00
2022-01-27 22:36:19 +03:00
if ( in_posix ! = NULL ) {
/* Client correctly negotiated SMB2 unix extensions. */
const uint8_t * buf = ( const uint8_t * ) SMB2_CREATE_TAG_POSIX ;
status = smb2_negotiate_context_add (
req ,
& out_c ,
SMB2_POSIX_EXTENSIONS_AVAILABLE ,
buf ,
16 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return smbd_smb2_request_error ( req , status ) ;
}
xconn - > smb2 . server . posix_extensions_negotiated = true ;
}
2014-10-08 21:25:15 +04:00
if ( out_c . num_contexts ! = 0 ) {
status = smb2_negotiate_context_push ( req ,
& out_negotiate_context_blob ,
out_c ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return smbd_smb2_request_error ( req , status ) ;
}
}
if ( out_negotiate_context_blob . length ! = 0 ) {
static const uint8_t zeros [ 8 ] ;
size_t pad = 0 ;
size_t ofs ;
outdyn = data_blob_dup_talloc ( req , security_buffer ) ;
if ( outdyn . length ! = security_buffer . length ) {
return smbd_smb2_request_error ( req ,
NT_STATUS_NO_MEMORY ) ;
}
ofs = security_offset + security_buffer . length ;
if ( ( ofs % 8 ) ! = 0 ) {
pad = 8 - ( ofs % 8 ) ;
}
ofs + = pad ;
ok = data_blob_append ( req , & outdyn , zeros , pad ) ;
if ( ! ok ) {
return smbd_smb2_request_error ( req ,
NT_STATUS_NO_MEMORY ) ;
}
ok = data_blob_append ( req , & outdyn ,
out_negotiate_context_blob . data ,
out_negotiate_context_blob . length ) ;
if ( ! ok ) {
return smbd_smb2_request_error ( req ,
NT_STATUS_NO_MEMORY ) ;
}
out_negotiate_context_offset = ofs ;
out_negotiate_context_count = out_c . num_contexts ;
} else {
outdyn = security_buffer ;
}
2011-12-15 17:45:56 +04:00
out_guid_blob = data_blob_const ( negprot_spnego_blob . data , 16 ) ;
status = GUID_from_ndr_blob ( & out_guid_blob , & out_guid ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return smbd_smb2_request_error ( req , status ) ;
}
2013-12-04 17:59:07 +04:00
outbody = smbd_smb2_generate_outbody ( req , 0x40 ) ;
2009-05-14 17:32:02 +04:00
if ( outbody . data = = NULL ) {
return smbd_smb2_request_error ( req , NT_STATUS_NO_MEMORY ) ;
}
SSVAL ( outbody . data , 0x00 , 0x40 + 1 ) ; /* struct size */
2009-05-22 23:26:03 +04:00
SSVAL ( outbody . data , 0x02 ,
security_mode ) ; /* security mode */
2009-05-14 17:32:02 +04:00
SSVAL ( outbody . data , 0x04 , dialect ) ; /* dialect revision */
2014-10-08 21:25:15 +04:00
SSVAL ( outbody . data , 0x06 ,
out_negotiate_context_count ) ; /* reserved/NegotiateContextCount */
2009-05-14 17:32:02 +04:00
memcpy ( outbody . data + 0x08 ,
2011-12-15 17:45:56 +04:00
out_guid_blob . data , 16 ) ; /* server guid */
2009-05-22 23:26:03 +04:00
SIVAL ( outbody . data , 0x18 ,
capabilities ) ; /* capabilities */
2011-09-05 14:14:06 +04:00
SIVAL ( outbody . data , 0x1C , max_trans ) ; /* max transact size */
2012-02-27 17:56:57 +04:00
SIVAL ( outbody . data , 0x20 , max_read ) ; /* max read size */
SIVAL ( outbody . data , 0x24 , max_write ) ; /* max write size */
2012-07-26 11:55:29 +04:00
SBVAL ( outbody . data , 0x28 , now ) ; /* system time */
2009-05-14 17:32:02 +04:00
SBVAL ( outbody . data , 0x30 , 0 ) ; /* server start time */
SSVAL ( outbody . data , 0x38 ,
security_offset ) ; /* security buffer offset */
SSVAL ( outbody . data , 0x3A ,
security_buffer . length ) ; /* security buffer length */
2014-10-08 21:25:15 +04:00
SIVAL ( outbody . data , 0x3C ,
out_negotiate_context_offset ) ; /* reserved/NegotiateContextOffset */
2009-05-14 17:32:02 +04:00
2011-05-30 18:30:54 +04:00
req - > sconn - > using_smb2 = true ;
2012-05-11 17:19:20 +04:00
2017-10-19 09:13:59 +03:00
if ( dialect = = SMB2_DIALECT_REVISION_2FF ) {
return smbd_smb2_request_done ( req , outbody , & outdyn ) ;
}
2011-12-15 17:45:56 +04:00
2017-10-19 09:13:59 +03:00
status = smbXsrv_connection_init_tables ( xconn , protocol ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return smbd_smb2_request_error ( req , status ) ;
}
2011-12-15 17:45:56 +04:00
2017-10-19 09:13:59 +03:00
xconn - > smb2 . client . capabilities = in_capabilities ;
xconn - > smb2 . client . security_mode = in_security_mode ;
xconn - > smb2 . client . guid = in_guid ;
xconn - > smb2 . client . num_dialects = dialect_count ;
xconn - > smb2 . client . dialects = talloc_array ( xconn ,
uint16_t ,
dialect_count ) ;
if ( xconn - > smb2 . client . dialects = = NULL ) {
return smbd_smb2_request_error ( req , NT_STATUS_NO_MEMORY ) ;
}
for ( c = 0 ; c < dialect_count ; c + + ) {
xconn - > smb2 . client . dialects [ c ] = SVAL ( indyn , c * 2 ) ;
}
2016-01-26 12:12:46 +03:00
2017-10-19 09:13:59 +03:00
xconn - > smb2 . server . capabilities = capabilities ;
xconn - > smb2 . server . security_mode = security_mode ;
xconn - > smb2 . server . guid = out_guid ;
xconn - > smb2 . server . dialect = dialect ;
xconn - > smb2 . server . max_trans = max_trans ;
xconn - > smb2 . server . max_read = max_read ;
xconn - > smb2 . server . max_write = max_write ;
2016-01-26 12:12:46 +03:00
2017-10-19 09:13:59 +03:00
if ( xconn - > protocol < PROTOCOL_SMB2_10 ) {
/*
* SMB2_02 doesn ' t support client guids
*/
return smbd_smb2_request_done ( req , outbody , & outdyn ) ;
}
2016-01-26 12:12:46 +03:00
2017-10-19 09:13:59 +03:00
if ( ! xconn - > client - > server_multi_channel_enabled ) {
/*
* Only deal with the client guid database
* if multi - channel is enabled .
2020-07-08 14:59:26 +03:00
*
* But we still need to setup
* xconn - > client - > global - > client_guid to
* the correct value .
2017-10-19 09:13:59 +03:00
*/
2020-07-08 14:59:26 +03:00
xconn - > client - > global - > client_guid =
xconn - > smb2 . client . guid ;
2017-10-19 09:13:59 +03:00
return smbd_smb2_request_done ( req , outbody , & outdyn ) ;
}
2016-01-26 12:12:46 +03:00
2017-10-19 09:13:59 +03:00
if ( xconn - > smb2 . client . guid_verified ) {
2016-01-26 12:12:46 +03:00
/*
2017-10-19 09:13:59 +03:00
* The connection was passed from another
* smbd process .
2016-01-26 12:12:46 +03:00
*/
2017-10-19 09:13:59 +03:00
return smbd_smb2_request_done ( req , outbody , & outdyn ) ;
}
2016-01-26 12:12:46 +03:00
2020-07-06 18:27:05 +03:00
state = talloc_zero ( req , struct smbd_smb2_request_process_negprot_state ) ;
if ( state = = NULL ) {
return smbd_smb2_request_error ( req , NT_STATUS_NO_MEMORY ) ;
}
* state = ( struct smbd_smb2_request_process_negprot_state ) {
. req = req ,
. outbody = outbody ,
. outdyn = outdyn ,
} ;
subreq = smb2srv_client_mc_negprot_send ( state ,
req - > xconn - > client - > raw_ev_ctx ,
req ) ;
if ( subreq = = NULL ) {
return smbd_smb2_request_error ( req , NT_STATUS_NO_MEMORY ) ;
}
tevent_req_set_callback ( subreq ,
smbd_smb2_request_process_negprot_mc_done ,
state ) ;
return NT_STATUS_OK ;
}
static void smbd_smb2_request_process_negprot_mc_done ( struct tevent_req * subreq )
{
struct smbd_smb2_request_process_negprot_state * state =
tevent_req_callback_data ( subreq ,
struct smbd_smb2_request_process_negprot_state ) ;
struct smbd_smb2_request * req = state - > req ;
struct smbXsrv_connection * xconn = req - > xconn ;
NTSTATUS status ;
status = smb2srv_client_mc_negprot_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_MESSAGE_RETRIEVED ) ) {
2017-10-19 09:13:59 +03:00
/*
2020-07-06 18:27:05 +03:00
* The connection was passed to another process
2017-10-19 09:13:59 +03:00
*/
2020-07-06 18:27:05 +03:00
smbd_server_connection_terminate ( xconn ,
" passed connection " ) ;
/*
* smbd_server_connection_terminate ( ) should not return !
*/
smb_panic ( __location__ ) ;
return ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
status = smbd_smb2_request_error ( req , status ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
return ;
2017-10-19 09:13:59 +03:00
}
2016-01-26 12:12:46 +03:00
2020-07-06 18:27:05 +03:00
/*
* The connection was passed to another process
*/
smbd_server_connection_terminate ( xconn , nt_errstr ( status ) ) ;
/*
* smbd_server_connection_terminate ( ) should not return !
*/
smb_panic ( __location__ ) ;
return ;
}
2017-10-19 09:13:59 +03:00
2020-07-06 18:27:05 +03:00
/*
* We ' re the first connection . . .
*/
status = smbd_smb2_request_done ( req , state - > outbody , & state - > outdyn ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
2023-04-25 18:38:30 +03:00
/*
* This allows us to support starting smbd under
* callgrind and only start the overhead and
* instrumentation after the SMB2 negprot ,
* this allows us to profile only useful
* stuff and not all the smbd startup , forking
* and multichannel handling .
*
* valgrind - - tool = callgrind - - instr - atstart = no smbd
*/
# ifdef CALLGRIND_START_INSTRUMENTATION
CALLGRIND_START_INSTRUMENTATION ;
# endif
2020-07-06 18:27:05 +03:00
return ;
2012-05-11 17:19:20 +04:00
}
2011-05-30 18:30:54 +04:00
2020-07-06 18:27:05 +03:00
/*
* The connection was passed to another process
*/
smbd_server_connection_terminate ( xconn , nt_errstr ( status ) ) ;
/*
* smbd_server_connection_terminate ( ) should not return !
*/
smb_panic ( __location__ ) ;
return ;
2009-05-14 17:32:02 +04:00
}
2022-03-11 20:18:04 +03:00
/****************************************************************************
Generate the spnego negprot reply blob . Return the number of bytes used .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
DATA_BLOB negprot_spnego ( TALLOC_CTX * ctx , struct smbXsrv_connection * xconn )
{
DATA_BLOB blob = data_blob_null ;
DATA_BLOB blob_out = data_blob_null ;
nstring dos_name ;
fstring unix_name ;
NTSTATUS status ;
# ifdef DEVELOPER
size_t slen ;
# endif
struct gensec_security * gensec_security ;
/* See if we can get an SPNEGO blob */
status = auth_generic_prepare ( talloc_tos ( ) ,
xconn - > remote_address ,
xconn - > local_address ,
" SMB " ,
& gensec_security ) ;
/*
* Despite including it above , there is no need to set a
* remote address or similar as we are just interested in the
* SPNEGO blob , we never keep this context .
*/
if ( NT_STATUS_IS_OK ( status ) ) {
status = gensec_start_mech_by_oid ( gensec_security , GENSEC_OID_SPNEGO ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
status = gensec_update ( gensec_security , ctx ,
data_blob_null , & blob ) ;
/* If we get the list of OIDs, the 'OK' answer
* is NT_STATUS_MORE_PROCESSING_REQUIRED */
if ( ! NT_STATUS_EQUAL ( status , NT_STATUS_MORE_PROCESSING_REQUIRED ) ) {
DEBUG ( 0 , ( " Failed to start SPNEGO handler for negprot OID list! \n " ) ) ;
blob = data_blob_null ;
}
}
TALLOC_FREE ( gensec_security ) ;
}
2022-03-11 20:43:16 +03:00
# if defined(WITH_SMB1SERVER)
2022-03-11 20:18:04 +03:00
xconn - > smb1 . negprot . spnego = true ;
2022-03-11 20:43:16 +03:00
# endif
2022-03-11 20:18:04 +03:00
/* strangely enough, NT does not sent the single OID NTLMSSP when
not a ADS member , it sends no OIDs at all
2023-07-18 12:30:18 +03:00
OLD COMMENT : " we can't do this until we teach our session setup parser to know
2022-03-11 20:18:04 +03:00
about raw NTLMSSP ( clients send no ASN .1 wrapping if we do this ) "
Our sessionsetup code now handles raw NTLMSSP connects , so we can go
back to doing what W2K3 does here . This is needed to make PocketPC 2003
CIFS connections work with SPNEGO . See bugzilla bugs # 1828 and # 3133
for details . JRA .
*/
if ( blob . length = = 0 | | blob . data = = NULL ) {
return data_blob_null ;
}
blob_out = data_blob_talloc ( ctx , NULL , 16 + blob . length ) ;
if ( blob_out . data = = NULL ) {
data_blob_free ( & blob ) ;
return data_blob_null ;
}
memset ( blob_out . data , ' \0 ' , 16 ) ;
checked_strlcpy ( unix_name , lp_netbios_name ( ) , sizeof ( unix_name ) ) ;
( void ) strlower_m ( unix_name ) ;
push_ascii_nstring ( dos_name , unix_name ) ;
strlcpy ( ( char * ) blob_out . data , dos_name , 17 ) ;
# ifdef DEVELOPER
/* Fix valgrind 'uninitialized bytes' issue. */
slen = strlen ( dos_name ) ;
if ( slen < 16 ) {
memset ( blob_out . data + slen , ' \0 ' , 16 - slen ) ;
}
# endif
memcpy ( & blob_out . data [ 16 ] , blob . data , blob . length ) ;
data_blob_free ( & blob ) ;
return blob_out ;
}
2022-03-23 15:43:40 +03:00
/*
* MS - CIFS , 2.2 .4 .52 .2 SMB_COM_NEGOTIATE Response :
* If the server does not support any of the listed dialects , it MUST return a
* DialectIndex of 0 XFFFF
*/
# define NO_PROTOCOL_CHOSEN 0xffff
# define PROT_SMB_2_002 0x1000
# define PROT_SMB_2_FF 0x2000
/* List of supported SMB1 protocols, most desired first.
* This is for enabling multi - protocol negotiation in SMB2 when SMB1
* is disabled .
*/
static const struct {
const char * proto_name ;
const char * short_name ;
NTSTATUS ( * proto_reply_fn ) ( struct smb_request * req , uint16_t choice ) ;
int protocol_level ;
} supported_protocols [ ] = {
{ " SMB 2.??? " , " SMB2_FF " , reply_smb20ff , PROTOCOL_SMB2_10 } ,
{ " SMB 2.002 " , " SMB2_02 " , reply_smb2002 , PROTOCOL_SMB2_02 } ,
{ NULL , NULL , NULL , 0 } ,
} ;
/****************************************************************************
Reply to a negprot .
conn POINTER CAN BE NULL HERE !
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-03-30 11:57:21 +03:00
NTSTATUS smb2_multi_protocol_reply_negprot ( struct smb_request * req )
2022-03-23 15:43:40 +03:00
{
size_t choice = 0 ;
bool choice_set = false ;
int protocol ;
const char * p ;
int num_cliprotos ;
char * * cliprotos ;
size_t i ;
size_t converted_size ;
struct smbXsrv_connection * xconn = req - > xconn ;
struct smbd_server_connection * sconn = req - > sconn ;
int max_proto ;
int min_proto ;
NTSTATUS status ;
START_PROFILE ( SMBnegprot ) ;
if ( req - > buflen = = 0 ) {
DEBUG ( 0 , ( " negprot got no protocols \n " ) ) ;
reply_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
END_PROFILE ( SMBnegprot ) ;
2022-03-30 11:57:21 +03:00
return NT_STATUS_INVALID_PARAMETER ;
2022-03-23 15:43:40 +03:00
}
if ( req - > buf [ req - > buflen - 1 ] ! = ' \0 ' ) {
DEBUG ( 0 , ( " negprot protocols not 0-terminated \n " ) ) ;
reply_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
END_PROFILE ( SMBnegprot ) ;
2022-03-30 11:57:21 +03:00
return NT_STATUS_INVALID_PARAMETER ;
2022-03-23 15:43:40 +03:00
}
p = ( const char * ) req - > buf + 1 ;
num_cliprotos = 0 ;
cliprotos = NULL ;
while ( smbreq_bufrem ( req , p ) > 0 ) {
char * * tmp ;
tmp = talloc_realloc ( talloc_tos ( ) , cliprotos , char * ,
num_cliprotos + 1 ) ;
if ( tmp = = NULL ) {
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
TALLOC_FREE ( cliprotos ) ;
reply_nterror ( req , NT_STATUS_NO_MEMORY ) ;
END_PROFILE ( SMBnegprot ) ;
2022-03-30 11:57:21 +03:00
return NT_STATUS_NO_MEMORY ;
2022-03-23 15:43:40 +03:00
}
cliprotos = tmp ;
if ( ! pull_ascii_talloc ( cliprotos , & cliprotos [ num_cliprotos ] , p ,
& converted_size ) ) {
DEBUG ( 0 , ( " pull_ascii_talloc failed \n " ) ) ;
TALLOC_FREE ( cliprotos ) ;
reply_nterror ( req , NT_STATUS_NO_MEMORY ) ;
END_PROFILE ( SMBnegprot ) ;
2022-03-30 11:57:21 +03:00
return NT_STATUS_NO_MEMORY ;
2022-03-23 15:43:40 +03:00
}
DEBUG ( 3 , ( " Requested protocol [%s] \n " ,
cliprotos [ num_cliprotos ] ) ) ;
num_cliprotos + = 1 ;
p + = strlen ( p ) + 2 ;
}
/* possibly reload - change of architecture */
reload_services ( sconn , conn_snum_used , true ) ;
/*
* Anything higher than PROTOCOL_SMB2_10 still
* needs to go via " SMB 2.??? " , which is marked
* as PROTOCOL_SMB2_10 .
*
* The real negotiation happens via reply_smb20ff ( )
* using SMB2 Negotiation .
*/
max_proto = lp_server_max_protocol ( ) ;
if ( max_proto > PROTOCOL_SMB2_10 ) {
max_proto = PROTOCOL_SMB2_10 ;
}
min_proto = lp_server_min_protocol ( ) ;
if ( min_proto > PROTOCOL_SMB2_10 ) {
min_proto = PROTOCOL_SMB2_10 ;
}
/* Check for protocols, most desirable first */
for ( protocol = 0 ; supported_protocols [ protocol ] . proto_name ; protocol + + ) {
i = 0 ;
if ( ( supported_protocols [ protocol ] . protocol_level < = max_proto ) & &
( supported_protocols [ protocol ] . protocol_level > = min_proto ) )
while ( i < num_cliprotos ) {
if ( strequal ( cliprotos [ i ] , supported_protocols [ protocol ] . proto_name ) ) {
choice = i ;
choice_set = true ;
}
i + + ;
}
if ( choice_set ) {
break ;
}
}
if ( ! choice_set ) {
bool ok ;
DBG_NOTICE ( " No protocol supported ! \n " ) ;
2022-04-05 05:53:20 +03:00
reply_smb1_outbuf ( req , 1 , 0 ) ;
2022-03-23 15:43:40 +03:00
SSVAL ( req - > outbuf , smb_vwv0 , NO_PROTOCOL_CHOSEN ) ;
2023-06-05 16:45:35 +03:00
ok = smb1_srv_send ( xconn , ( char * ) req - > outbuf , false , 0 , false ) ;
2022-03-23 15:43:40 +03:00
if ( ! ok ) {
2022-03-31 22:09:13 +03:00
DBG_NOTICE ( " smb1_srv_send failed \n " ) ;
2022-03-23 15:43:40 +03:00
}
exit_server_cleanly ( " no protocol supported \n " ) ;
}
2022-11-30 18:28:56 +03:00
set_remote_proto ( supported_protocols [ protocol ] . short_name ) ;
2022-03-23 15:43:40 +03:00
reload_services ( sconn , conn_snum_used , true ) ;
status = supported_protocols [ protocol ] . proto_reply_fn ( req , choice ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
exit_server_cleanly ( " negprot function failed \n " ) ;
}
DEBUG ( 3 , ( " Selected protocol %s \n " , supported_protocols [ protocol ] . proto_name ) ) ;
DBG_INFO ( " negprot index=%zu \n " , choice ) ;
TALLOC_FREE ( cliprotos ) ;
END_PROFILE ( SMBnegprot ) ;
2022-03-30 11:57:21 +03:00
return NT_STATUS_OK ;
2022-03-23 15:43:40 +03:00
}