2009-05-15 13:20:34 +04:00
/*
Unix SMB / CIFS implementation .
Core SMB2 server
Copyright ( C ) Stefan Metzmacher 2009
2010-05-18 00:05:22 +04:00
Copyright ( C ) Jeremy Allison 2010
2009-05-15 13:20:34 +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-03-22 18:57:01 +03:00
# include "smbd/smbd.h"
2009-05-15 13:20:34 +04:00
# include "smbd/globals.h"
2009-08-12 19:52:55 +04:00
# include "../libcli/smb/smb_common.h"
2011-07-26 09:11:47 +04:00
# include "../auth/gensec/gensec.h"
2011-03-24 15:46:20 +03:00
# include "auth.h"
2011-06-16 18:03:03 +04:00
# include "../lib/tsocket/tsocket.h"
2011-07-19 05:57:05 +04:00
# include "../libcli/security/security.h"
2012-05-12 12:16:41 +04:00
# include "../lib/util/tevent_ntstatus.h"
2014-10-10 16:04:25 +04:00
# include "lib/crypto/sha512.h"
2015-05-20 15:01:44 +03:00
# include "lib/crypto/aes.h"
# include "lib/crypto/aes_ccm_128.h"
# include "lib/crypto/aes_gcm_128.h"
2009-05-15 13:20:34 +04:00
2015-05-02 17:21:25 +03:00
static struct tevent_req * smbd_smb2_session_setup_wrap_send ( TALLOC_CTX * mem_ctx ,
2012-05-12 12:16:41 +04:00
struct tevent_context * ev ,
struct smbd_smb2_request * smb2req ,
uint64_t in_session_id ,
uint8_t in_flags ,
uint8_t in_security_mode ,
uint64_t in_previous_session_id ,
DATA_BLOB in_security_buffer ) ;
2015-05-02 17:21:25 +03:00
static NTSTATUS smbd_smb2_session_setup_wrap_recv ( struct tevent_req * req ,
2012-05-12 12:16:41 +04:00
uint16_t * out_session_flags ,
TALLOC_CTX * mem_ctx ,
DATA_BLOB * out_security_buffer ,
uint64_t * out_session_id ) ;
2012-05-12 12:20:55 +04:00
static void smbd_smb2_request_sesssetup_done ( struct tevent_req * subreq ) ;
2010-05-18 00:05:22 +04:00
NTSTATUS smbd_smb2_request_process_sesssetup ( struct smbd_smb2_request * smb2req )
2009-05-15 13:20:34 +04:00
{
const uint8_t * inhdr ;
const uint8_t * inbody ;
uint64_t in_session_id ;
2012-05-12 11:48:19 +04:00
uint8_t in_flags ;
2009-05-23 00:58:39 +04:00
uint8_t in_security_mode ;
2012-04-18 17:00:06 +04:00
uint64_t in_previous_session_id ;
2009-05-15 13:20:34 +04:00
uint16_t in_security_offset ;
uint16_t in_security_length ;
DATA_BLOB in_security_buffer ;
NTSTATUS status ;
2012-05-12 12:20:55 +04:00
struct tevent_req * subreq ;
2009-05-15 13:20:34 +04:00
2011-09-06 16:01:43 +04:00
status = smbd_smb2_request_verify_sizes ( smb2req , 0x19 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return smbd_smb2_request_error ( smb2req , status ) ;
2009-05-15 13:20:34 +04:00
}
2012-08-05 17:00:23 +04:00
inhdr = SMBD_SMB2_IN_HDR_PTR ( smb2req ) ;
inbody = SMBD_SMB2_IN_BODY_PTR ( smb2req ) ;
2009-05-15 13:20:34 +04:00
2012-04-18 17:00:06 +04:00
in_session_id = BVAL ( inhdr , SMB2_HDR_SESSION_ID ) ;
2012-05-12 11:48:19 +04:00
in_flags = CVAL ( inbody , 0x02 ) ;
2012-04-18 17:00:06 +04:00
in_security_mode = CVAL ( inbody , 0x03 ) ;
/* Capabilities = IVAL(inbody, 0x04) */
/* Channel = IVAL(inbody, 0x08) */
2009-05-15 13:20:34 +04:00
in_security_offset = SVAL ( inbody , 0x0C ) ;
in_security_length = SVAL ( inbody , 0x0E ) ;
2012-04-18 17:00:06 +04:00
in_previous_session_id = BVAL ( inbody , 0x10 ) ;
2009-05-15 13:20:34 +04:00
2012-08-05 17:00:23 +04:00
if ( in_security_offset ! = ( SMB2_HDR_BODY + SMBD_SMB2_IN_BODY_LEN ( smb2req ) ) ) {
2010-05-18 00:05:22 +04:00
return smbd_smb2_request_error ( smb2req , NT_STATUS_INVALID_PARAMETER ) ;
2009-05-15 13:20:34 +04:00
}
2012-08-05 17:00:23 +04:00
if ( in_security_length > SMBD_SMB2_IN_DYN_LEN ( smb2req ) ) {
2010-05-18 00:05:22 +04:00
return smbd_smb2_request_error ( smb2req , NT_STATUS_INVALID_PARAMETER ) ;
2009-05-15 13:20:34 +04:00
}
2012-08-05 17:00:23 +04:00
in_security_buffer . data = SMBD_SMB2_IN_DYN_PTR ( smb2req ) ;
2009-05-15 13:20:34 +04:00
in_security_buffer . length = in_security_length ;
2015-05-02 17:21:25 +03:00
subreq = smbd_smb2_session_setup_wrap_send ( smb2req ,
smb2req - > sconn - > ev_ctx ,
smb2req ,
in_session_id ,
in_flags ,
in_security_mode ,
in_previous_session_id ,
in_security_buffer ) ;
2012-05-12 12:20:55 +04:00
if ( subreq = = NULL ) {
return smbd_smb2_request_error ( smb2req , NT_STATUS_NO_MEMORY ) ;
}
tevent_req_set_callback ( subreq , smbd_smb2_request_sesssetup_done , smb2req ) ;
return smbd_smb2_request_pending_queue ( smb2req , subreq , 500 ) ;
}
static void smbd_smb2_request_sesssetup_done ( struct tevent_req * subreq )
{
struct smbd_smb2_request * smb2req =
tevent_req_callback_data ( subreq ,
struct smbd_smb2_request ) ;
uint8_t * outhdr ;
DATA_BLOB outbody ;
DATA_BLOB outdyn ;
2013-12-10 20:49:44 +04:00
uint16_t out_session_flags = 0 ;
uint64_t out_session_id = 0 ;
2012-05-12 12:20:55 +04:00
uint16_t out_security_offset ;
DATA_BLOB out_security_buffer = data_blob_null ;
NTSTATUS status ;
NTSTATUS error ; /* transport error */
2015-05-02 17:21:25 +03:00
status = smbd_smb2_session_setup_wrap_recv ( subreq ,
& out_session_flags ,
smb2req ,
& out_security_buffer ,
& out_session_id ) ;
2012-05-12 12:20:55 +04:00
TALLOC_FREE ( subreq ) ;
2009-05-15 13:20:34 +04:00
if ( ! NT_STATUS_IS_OK ( status ) & &
! NT_STATUS_EQUAL ( status , NT_STATUS_MORE_PROCESSING_REQUIRED ) ) {
status = nt_status_squash ( status ) ;
2012-05-12 12:20:55 +04:00
error = smbd_smb2_request_error ( smb2req , status ) ;
if ( ! NT_STATUS_IS_OK ( error ) ) {
2014-06-11 14:15:48 +04:00
smbd_server_connection_terminate ( smb2req - > xconn ,
2012-05-12 12:20:55 +04:00
nt_errstr ( error ) ) ;
return ;
}
return ;
2009-05-15 13:20:34 +04:00
}
out_security_offset = SMB2_HDR_BODY + 0x08 ;
2012-08-05 17:00:23 +04:00
outhdr = SMBD_SMB2_OUT_HDR_PTR ( smb2req ) ;
2009-05-15 13:20:34 +04:00
2013-12-04 17:59:07 +04:00
outbody = smbd_smb2_generate_outbody ( smb2req , 0x08 ) ;
2009-05-15 13:20:34 +04:00
if ( outbody . data = = NULL ) {
2012-05-12 12:20:55 +04:00
error = smbd_smb2_request_error ( smb2req , NT_STATUS_NO_MEMORY ) ;
if ( ! NT_STATUS_IS_OK ( error ) ) {
2014-06-11 14:15:48 +04:00
smbd_server_connection_terminate ( smb2req - > xconn ,
2012-05-12 12:20:55 +04:00
nt_errstr ( error ) ) ;
return ;
}
return ;
2009-05-15 13:20:34 +04:00
}
SBVAL ( outhdr , SMB2_HDR_SESSION_ID , out_session_id ) ;
SSVAL ( outbody . data , 0x00 , 0x08 + 1 ) ; /* struct size */
2009-05-23 00:58:39 +04:00
SSVAL ( outbody . data , 0x02 ,
out_session_flags ) ; /* session flags */
2009-05-15 13:20:34 +04:00
SSVAL ( outbody . data , 0x04 ,
out_security_offset ) ; /* security buffer offset */
SSVAL ( outbody . data , 0x06 ,
out_security_buffer . length ) ; /* security buffer length */
outdyn = out_security_buffer ;
2012-05-12 12:20:55 +04:00
error = smbd_smb2_request_done_ex ( smb2req , status , outbody , & outdyn ,
__location__ ) ;
if ( ! NT_STATUS_IS_OK ( error ) ) {
2014-06-11 14:15:48 +04:00
smbd_server_connection_terminate ( smb2req - > xconn ,
2012-05-12 12:20:55 +04:00
nt_errstr ( error ) ) ;
return ;
}
2009-05-15 13:20:34 +04:00
}
2012-03-27 13:09:05 +04:00
static NTSTATUS smbd_smb2_auth_generic_return ( struct smbXsrv_session * session ,
2015-07-29 17:48:55 +03:00
struct smbXsrv_session_auth0 * * _auth ,
2010-05-18 00:05:22 +04:00
struct smbd_smb2_request * smb2req ,
uint8_t in_security_mode ,
2012-05-17 02:30:43 +04:00
struct auth_session_info * session_info ,
2010-05-18 05:22:19 +04:00
uint16_t * out_session_flags ,
uint64_t * out_session_id )
2010-05-18 00:05:22 +04:00
{
2012-03-16 18:01:27 +04:00
NTSTATUS status ;
2011-09-21 05:56:30 +04:00
bool guest = false ;
2012-03-16 18:01:27 +04:00
uint8_t session_key [ 16 ] ;
2012-03-27 13:09:05 +04:00
struct smbXsrv_session * x = session ;
2015-07-29 17:48:55 +03:00
struct smbXsrv_session_auth0 * auth = * _auth ;
2014-06-12 12:47:51 +04:00
struct smbXsrv_connection * xconn = smb2req - > xconn ;
2015-07-29 18:42:55 +03:00
size_t i ;
2014-10-10 16:04:25 +04:00
struct _derivation {
DATA_BLOB label ;
DATA_BLOB context ;
} ;
struct {
struct _derivation signing ;
struct _derivation encryption ;
struct _derivation decryption ;
struct _derivation application ;
} derivation = { } ;
2015-07-29 17:48:55 +03:00
* _auth = NULL ;
2014-10-10 16:04:25 +04:00
if ( xconn - > protocol > = PROTOCOL_SMB3_10 ) {
struct smbXsrv_preauth * preauth ;
struct _derivation * d ;
DATA_BLOB p ;
struct hc_sha512state sctx ;
2015-07-29 17:48:55 +03:00
preauth = talloc_move ( smb2req , & auth - > preauth ) ;
2014-10-10 16:04:25 +04:00
samba_SHA512_Init ( & sctx ) ;
samba_SHA512_Update ( & sctx , preauth - > sha512_value ,
sizeof ( preauth - > sha512_value ) ) ;
for ( i = 1 ; i < smb2req - > in . vector_count ; i + + ) {
samba_SHA512_Update ( & sctx ,
smb2req - > in . vector [ i ] . iov_base ,
smb2req - > in . vector [ i ] . iov_len ) ;
}
samba_SHA512_Final ( preauth - > sha512_value , & sctx ) ;
p = data_blob_const ( preauth - > sha512_value ,
sizeof ( preauth - > sha512_value ) ) ;
d = & derivation . signing ;
d - > label = data_blob_string_const_null ( " SMBSigningKey " ) ;
d - > context = p ;
d = & derivation . decryption ;
d - > label = data_blob_string_const_null ( " SMBC2SCipherKey " ) ;
d - > context = p ;
d = & derivation . encryption ;
d - > label = data_blob_string_const_null ( " SMBS2CCipherKey " ) ;
d - > context = p ;
d = & derivation . application ;
d - > label = data_blob_string_const_null ( " SMBAppKey " ) ;
d - > context = p ;
} else if ( xconn - > protocol > = PROTOCOL_SMB2_24 ) {
struct _derivation * d ;
d = & derivation . signing ;
d - > label = data_blob_string_const_null ( " SMB2AESCMAC " ) ;
d - > context = data_blob_string_const_null ( " SmbSign " ) ;
d = & derivation . decryption ;
d - > label = data_blob_string_const_null ( " SMB2AESCCM " ) ;
d - > context = data_blob_string_const_null ( " ServerIn " ) ;
d = & derivation . encryption ;
d - > label = data_blob_string_const_null ( " SMB2AESCCM " ) ;
d - > context = data_blob_string_const_null ( " ServerOut " ) ;
d = & derivation . application ;
d - > label = data_blob_string_const_null ( " SMB2APP " ) ;
d - > context = data_blob_string_const_null ( " SmbRpc " ) ;
}
2011-09-21 05:56:30 +04:00
2009-05-23 00:58:39 +04:00
if ( ( in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED ) | |
2015-02-23 21:15:05 +03:00
lp_server_signing ( ) = = SMB_SIGNING_REQUIRED ) {
2012-03-16 18:01:27 +04:00
x - > global - > signing_required = true ;
2009-05-23 00:58:39 +04:00
}
2015-07-01 19:07:26 +03:00
if ( ( lp_smb_encrypt ( - 1 ) > = SMB_SIGNING_DESIRED ) & &
2015-02-25 18:59:26 +03:00
( xconn - > smb2 . client . capabilities & SMB2_CAP_ENCRYPTION ) ) {
2015-07-01 19:07:26 +03:00
x - > encryption_desired = true ;
2015-02-25 18:59:26 +03:00
}
2012-08-08 08:25:10 +04:00
if ( lp_smb_encrypt ( - 1 ) = = SMB_SIGNING_REQUIRED ) {
2015-07-01 19:07:26 +03:00
x - > encryption_desired = true ;
2012-08-08 08:25:10 +04:00
x - > global - > encryption_required = true ;
}
2012-03-27 13:09:05 +04:00
if ( security_session_user_level ( session_info , NULL ) < SECURITY_USER ) {
2009-05-23 00:58:39 +04:00
/* we map anonymous to guest internally */
* out_session_flags | = SMB2_SESSION_FLAG_IS_GUEST ;
* out_session_flags | = SMB2_SESSION_FLAG_IS_NULL ;
/* force no signing */
2012-03-16 18:01:27 +04:00
x - > global - > signing_required = false ;
2011-09-21 05:56:30 +04:00
guest = true ;
2009-05-23 00:58:39 +04:00
}
2012-08-08 08:25:10 +04:00
if ( guest & & x - > global - > encryption_required ) {
DEBUG ( 1 , ( " reject guest session as encryption is required \n " ) ) ;
return NT_STATUS_ACCESS_DENIED ;
}
2014-10-13 13:07:01 +04:00
if ( xconn - > smb2 . server . cipher = = 0 ) {
2012-08-08 08:25:10 +04:00
if ( x - > global - > encryption_required ) {
DEBUG ( 1 , ( " reject session with dialect[0x%04X] "
" as encryption is required \n " ,
2014-06-12 12:47:51 +04:00
xconn - > smb2 . server . dialect ) ) ;
2012-08-08 08:25:10 +04:00
return NT_STATUS_ACCESS_DENIED ;
}
}
2015-07-01 19:07:26 +03:00
if ( x - > encryption_desired ) {
2012-08-08 08:25:10 +04:00
* out_session_flags | = SMB2_SESSION_FLAG_ENCRYPT_DATA ;
}
2012-03-16 18:01:27 +04:00
ZERO_STRUCT ( session_key ) ;
2012-03-27 13:09:05 +04:00
memcpy ( session_key , session_info - > session_key . data ,
MIN ( session_info - > session_key . length , sizeof ( session_key ) ) ) ;
2012-03-16 18:01:27 +04:00
x - > global - > signing_key = data_blob_talloc ( x - > global ,
session_key ,
sizeof ( session_key ) ) ;
if ( x - > global - > signing_key . data = = NULL ) {
ZERO_STRUCT ( session_key ) ;
return NT_STATUS_NO_MEMORY ;
}
2014-06-12 12:47:51 +04:00
if ( xconn - > protocol > = PROTOCOL_SMB2_24 ) {
2014-10-10 16:04:25 +04:00
struct _derivation * d = & derivation . signing ;
2012-03-16 18:01:27 +04:00
smb2_key_derivation ( session_key , sizeof ( session_key ) ,
2014-10-10 16:04:25 +04:00
d - > label . data , d - > label . length ,
d - > context . data , d - > context . length ,
2012-03-16 18:01:27 +04:00
x - > global - > signing_key . data ) ;
}
2014-06-12 12:47:51 +04:00
if ( xconn - > protocol > = PROTOCOL_SMB2_24 ) {
2014-10-10 16:04:25 +04:00
struct _derivation * d = & derivation . decryption ;
2012-08-08 11:32:22 +04:00
x - > global - > decryption_key = data_blob_talloc ( x - > global ,
session_key ,
sizeof ( session_key ) ) ;
if ( x - > global - > decryption_key . data = = NULL ) {
ZERO_STRUCT ( session_key ) ;
return NT_STATUS_NO_MEMORY ;
}
smb2_key_derivation ( session_key , sizeof ( session_key ) ,
2014-10-10 16:04:25 +04:00
d - > label . data , d - > label . length ,
d - > context . data , d - > context . length ,
2012-08-08 11:32:22 +04:00
x - > global - > decryption_key . data ) ;
}
2014-06-12 12:47:51 +04:00
if ( xconn - > protocol > = PROTOCOL_SMB2_24 ) {
2014-10-10 16:04:25 +04:00
struct _derivation * d = & derivation . encryption ;
2015-05-20 15:01:44 +03:00
size_t nonce_size ;
2012-08-08 11:32:22 +04:00
x - > global - > encryption_key = data_blob_talloc ( x - > global ,
session_key ,
sizeof ( session_key ) ) ;
if ( x - > global - > encryption_key . data = = NULL ) {
ZERO_STRUCT ( session_key ) ;
return NT_STATUS_NO_MEMORY ;
}
smb2_key_derivation ( session_key , sizeof ( session_key ) ,
2014-10-10 16:04:25 +04:00
d - > label . data , d - > label . length ,
d - > context . data , d - > context . length ,
2012-08-08 11:32:22 +04:00
x - > global - > encryption_key . data ) ;
2012-08-22 12:30:52 +04:00
2015-05-20 15:01:44 +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
* transfered too much data .
*
* NOTE : We assume nonces greater than 8 bytes .
*/
generate_random_buffer ( ( uint8_t * ) & x - > nonce_high_random ,
sizeof ( x - > nonce_high_random ) ) ;
switch ( xconn - > smb2 . server . cipher ) {
case SMB2_ENCRYPTION_AES128_CCM :
nonce_size = AES_CCM_128_NONCE_SIZE ;
break ;
case SMB2_ENCRYPTION_AES128_GCM :
nonce_size = AES_GCM_128_IV_SIZE ;
break ;
default :
2015-06-17 01:50:30 +03:00
nonce_size = 0 ;
break ;
2015-05-20 15:01:44 +03:00
}
x - > nonce_high_max = SMB2_NONCE_HIGH_MAX ( nonce_size ) ;
x - > nonce_high = 0 ;
x - > nonce_low = 0 ;
2012-08-08 11:32:22 +04:00
}
2012-03-16 18:01:27 +04:00
x - > global - > application_key = data_blob_dup_talloc ( x - > global ,
x - > global - > signing_key ) ;
if ( x - > global - > application_key . data = = NULL ) {
ZERO_STRUCT ( session_key ) ;
return NT_STATUS_NO_MEMORY ;
}
2014-06-12 12:47:51 +04:00
if ( xconn - > protocol > = PROTOCOL_SMB2_24 ) {
2014-10-10 16:04:25 +04:00
struct _derivation * d = & derivation . application ;
2012-03-16 18:01:27 +04:00
smb2_key_derivation ( session_key , sizeof ( session_key ) ,
2014-10-10 16:04:25 +04:00
d - > label . data , d - > label . length ,
d - > context . data , d - > context . length ,
2012-03-16 18:01:27 +04:00
x - > global - > application_key . data ) ;
}
2012-03-16 18:01:27 +04:00
ZERO_STRUCT ( session_key ) ;
x - > global - > channels [ 0 ] . signing_key = data_blob_dup_talloc ( x - > global - > channels ,
x - > global - > signing_key ) ;
if ( x - > global - > channels [ 0 ] . signing_key . data = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2009-05-23 00:58:39 +04:00
2012-03-16 18:01:27 +04:00
data_blob_clear_free ( & session_info - > session_key ) ;
session_info - > session_key = data_blob_dup_talloc ( session_info ,
x - > global - > application_key ) ;
if ( session_info - > session_key . data = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2012-03-27 13:09:05 +04:00
session - > compat = talloc_zero ( session , struct user_struct ) ;
if ( session - > compat = = NULL ) {
2009-05-27 20:33:45 +04:00
return NT_STATUS_NO_MEMORY ;
}
2012-03-27 13:09:05 +04:00
session - > compat - > session = session ;
session - > compat - > homes_snum = - 1 ;
session - > compat - > session_info = session_info ;
session - > compat - > session_keystr = NULL ;
session - > compat - > vuid = session - > global - > session_wire_id ;
DLIST_ADD ( smb2req - > sconn - > users , session - > compat ) ;
smb2req - > sconn - > num_users + + ;
2009-05-27 20:33:45 +04:00
2012-03-27 13:09:05 +04:00
if ( security_session_user_level ( session_info , NULL ) > = SECURITY_USER ) {
session - > compat - > homes_snum =
register_homes_share ( session_info - > unix_info - > unix_name ) ;
2010-05-18 05:22:19 +04:00
}
2012-03-27 13:09:05 +04:00
set_current_user_info ( session_info - > unix_info - > sanitized_username ,
session_info - > unix_info - > unix_name ,
session_info - > info - > domain_name ) ;
2012-01-25 08:22:38 +04:00
reload_services ( smb2req - > sconn , conn_snum_used , true ) ;
2010-05-18 05:22:19 +04:00
2012-03-27 13:09:05 +04:00
session - > status = NT_STATUS_OK ;
2015-07-29 18:07:29 +03:00
session - > global - > auth_session_info = talloc_move ( session - > global ,
& session_info ) ;
2012-03-27 13:09:05 +04:00
session - > global - > auth_session_info_seqnum + = 1 ;
2015-07-29 18:42:55 +03:00
for ( i = 0 ; i < session - > global - > num_channels ; i + + ) {
struct smbXsrv_channel_global0 * _c =
& session - > global - > channels [ i ] ;
_c - > auth_session_info_seqnum =
session - > global - > auth_session_info_seqnum ;
}
2014-06-12 11:49:28 +04:00
session - > global - > auth_time = timeval_to_nttime ( & smb2req - > request_time ) ;
2015-07-29 17:48:55 +03:00
session - > global - > expiration_time = gensec_expire_time ( auth - > gensec ) ;
2012-03-16 18:01:27 +04:00
2012-08-27 13:03:25 +04:00
if ( ! session_claim ( session ) ) {
DEBUG ( 1 , ( " smb2: Failed to claim session "
" for vuid=%llu \n " ,
( unsigned long long ) session - > compat - > vuid ) ) ;
return NT_STATUS_LOGON_FAILURE ;
}
2015-07-29 17:48:55 +03:00
TALLOC_FREE ( auth ) ;
2012-03-27 13:09:05 +04:00
status = smbXsrv_session_update ( session ) ;
2012-03-16 18:01:27 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " smb2: Failed to update session for vuid=%llu - %s \n " ,
2012-03-27 13:09:05 +04:00
( unsigned long long ) session - > compat - > vuid ,
2012-03-16 18:01:27 +04:00
nt_errstr ( status ) ) ) ;
return NT_STATUS_LOGON_FAILURE ;
}
2009-05-23 00:58:39 +04:00
/*
* we attach the session to the request
* so that the response can be signed
*/
2011-09-21 05:56:30 +04:00
if ( ! guest ) {
2010-05-18 00:05:22 +04:00
smb2req - > do_signing = true ;
}
global_client_caps | = ( CAP_LEVEL_II_OPLOCKS | CAP_STATUS32 ) ;
2010-05-18 05:22:19 +04:00
2012-03-27 13:09:05 +04:00
* out_session_id = session - > global - > session_wire_id ;
2010-05-18 05:22:19 +04:00
2010-05-18 00:05:22 +04:00
return NT_STATUS_OK ;
}
2012-05-14 16:24:08 +04:00
static NTSTATUS smbd_smb2_reauth_generic_return ( struct smbXsrv_session * session ,
2015-07-29 17:48:55 +03:00
struct smbXsrv_session_auth0 * * _auth ,
2012-05-14 16:24:08 +04:00
struct smbd_smb2_request * smb2req ,
2012-05-17 02:30:43 +04:00
struct auth_session_info * session_info ,
2012-05-14 16:24:08 +04:00
uint16_t * out_session_flags ,
uint64_t * out_session_id )
{
NTSTATUS status ;
struct smbXsrv_session * x = session ;
2015-07-29 17:48:55 +03:00
struct smbXsrv_session_auth0 * auth = * _auth ;
2015-09-09 16:08:56 +03:00
struct smbXsrv_connection * xconn = smb2req - > xconn ;
2015-07-29 18:44:37 +03:00
size_t i ;
2015-07-29 17:48:55 +03:00
* _auth = NULL ;
2012-05-14 16:24:08 +04:00
data_blob_clear_free ( & session_info - > session_key ) ;
session_info - > session_key = data_blob_dup_talloc ( session_info ,
x - > global - > application_key ) ;
if ( session_info - > session_key . data = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
session - > compat - > session_info = session_info ;
session - > compat - > vuid = session - > global - > session_wire_id ;
session - > compat - > homes_snum =
register_homes_share ( session_info - > unix_info - > unix_name ) ;
set_current_user_info ( session_info - > unix_info - > sanitized_username ,
session_info - > unix_info - > unix_name ,
session_info - > info - > domain_name ) ;
reload_services ( smb2req - > sconn , conn_snum_used , true ) ;
session - > status = NT_STATUS_OK ;
TALLOC_FREE ( session - > global - > auth_session_info ) ;
2015-07-29 18:07:29 +03:00
session - > global - > auth_session_info = talloc_move ( session - > global ,
& session_info ) ;
2012-05-14 16:24:08 +04:00
session - > global - > auth_session_info_seqnum + = 1 ;
2015-07-29 18:44:37 +03:00
for ( i = 0 ; i < session - > global - > num_channels ; i + + ) {
struct smbXsrv_channel_global0 * _c =
& session - > global - > channels [ i ] ;
_c - > auth_session_info_seqnum =
session - > global - > auth_session_info_seqnum ;
}
2014-06-12 11:49:28 +04:00
session - > global - > auth_time = timeval_to_nttime ( & smb2req - > request_time ) ;
2015-07-29 17:48:55 +03:00
session - > global - > expiration_time = gensec_expire_time ( auth - > gensec ) ;
2012-05-14 16:24:08 +04:00
2015-07-29 17:48:55 +03:00
TALLOC_FREE ( auth ) ;
2012-05-14 16:24:08 +04:00
status = smbXsrv_session_update ( session ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " smb2: Failed to update session for vuid=%llu - %s \n " ,
( unsigned long long ) session - > compat - > vuid ,
nt_errstr ( status ) ) ) ;
return NT_STATUS_LOGON_FAILURE ;
}
2015-09-09 16:08:56 +03:00
conn_clear_vuid_caches ( xconn - > client - > sconn , session - > compat - > vuid ) ;
2012-05-14 16:24:08 +04:00
2014-12-12 11:22:15 +03:00
if ( security_session_user_level ( session_info , NULL ) > = SECURITY_USER ) {
smb2req - > do_signing = true ;
}
2012-05-14 16:24:08 +04:00
* out_session_id = session - > global - > session_wire_id ;
return NT_STATUS_OK ;
}
2012-05-12 12:16:41 +04:00
struct smbd_smb2_session_setup_state {
struct tevent_context * ev ;
struct smbd_smb2_request * smb2req ;
uint64_t in_session_id ;
uint8_t in_flags ;
uint8_t in_security_mode ;
uint64_t in_previous_session_id ;
DATA_BLOB in_security_buffer ;
2012-05-16 17:56:15 +04:00
struct smbXsrv_session * session ;
2015-07-29 17:48:55 +03:00
struct smbXsrv_session_auth0 * auth ;
2012-05-17 02:30:43 +04:00
struct auth_session_info * session_info ;
2012-05-12 12:16:41 +04:00
uint16_t out_session_flags ;
DATA_BLOB out_security_buffer ;
uint64_t out_session_id ;
} ;
2012-05-17 02:30:43 +04:00
static void smbd_smb2_session_setup_gensec_done ( struct tevent_req * subreq ) ;
2012-05-17 02:32:40 +04:00
static void smbd_smb2_session_setup_previous_done ( struct tevent_req * subreq ) ;
2014-06-12 11:19:29 +04:00
static void smbd_smb2_session_setup_auth_return ( struct tevent_req * req ) ;
2012-05-16 18:05:48 +04:00
2012-05-12 12:16:41 +04:00
static struct tevent_req * smbd_smb2_session_setup_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct smbd_smb2_request * smb2req ,
uint64_t in_session_id ,
uint8_t in_flags ,
uint8_t in_security_mode ,
uint64_t in_previous_session_id ,
DATA_BLOB in_security_buffer )
{
struct tevent_req * req ;
struct smbd_smb2_session_setup_state * state ;
NTSTATUS status ;
2012-05-16 17:56:15 +04:00
NTTIME now = timeval_to_nttime ( & smb2req - > request_time ) ;
2012-05-16 18:05:48 +04:00
struct tevent_req * subreq ;
2015-07-29 12:19:55 +03:00
struct smbXsrv_channel_global0 * c = NULL ;
2012-05-12 12:16:41 +04:00
req = tevent_req_create ( mem_ctx , & state ,
struct smbd_smb2_session_setup_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
state - > smb2req = smb2req ;
state - > in_session_id = in_session_id ;
state - > in_flags = in_flags ;
state - > in_security_mode = in_security_mode ;
state - > in_previous_session_id = in_previous_session_id ;
state - > in_security_buffer = in_security_buffer ;
2012-07-26 02:11:13 +04:00
if ( in_flags & SMB2_SESSION_FLAG_BINDING ) {
2014-06-12 10:38:48 +04:00
if ( smb2req - > xconn - > protocol < PROTOCOL_SMB2_22 ) {
2012-07-26 02:11:13 +04:00
tevent_req_nterror ( req , NT_STATUS_REQUEST_NOT_ACCEPTED ) ;
return tevent_req_post ( req , ev ) ;
}
/*
* We do not support multi channel .
*/
tevent_req_nterror ( req , NT_STATUS_NOT_SUPPORTED ) ;
return tevent_req_post ( req , ev ) ;
}
2012-05-16 17:56:15 +04:00
if ( state - > in_session_id = = 0 ) {
/* create a new session */
2014-06-12 10:38:48 +04:00
status = smbXsrv_session_create ( state - > smb2req - > xconn ,
2012-05-16 17:56:15 +04:00
now , & state - > session ) ;
if ( tevent_req_nterror ( req , status ) ) {
return tevent_req_post ( req , ev ) ;
}
2015-05-02 17:27:26 +03:00
smb2req - > session = state - > session ;
2012-05-16 17:56:15 +04:00
} else {
2014-09-15 02:10:11 +04:00
if ( smb2req - > session = = NULL ) {
tevent_req_nterror ( req , NT_STATUS_USER_SESSION_DELETED ) ;
return tevent_req_post ( req , ev ) ;
}
state - > session = smb2req - > session ;
status = state - > session - > status ;
2012-05-16 17:56:15 +04:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NETWORK_SESSION_EXPIRED ) ) {
status = NT_STATUS_OK ;
}
2015-07-29 17:48:55 +03:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_MORE_PROCESSING_REQUIRED ) ) {
status = NT_STATUS_OK ;
2012-05-16 17:56:15 +04:00
}
2015-07-29 17:48:55 +03:00
if ( tevent_req_nterror ( req , status ) ) {
2012-05-16 17:56:15 +04:00
return tevent_req_post ( req , ev ) ;
}
2015-07-29 17:48:55 +03:00
if ( ! ( in_flags & SMB2_SESSION_FLAG_BINDING ) ) {
state - > session - > status = NT_STATUS_MORE_PROCESSING_REQUIRED ;
}
2012-05-16 17:56:15 +04:00
}
2015-07-29 12:19:55 +03:00
status = smbXsrv_session_find_channel ( smb2req - > session ,
smb2req - > xconn , & c ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
}
2015-07-29 17:48:55 +03:00
status = smbXsrv_session_find_auth ( state - > session , smb2req - > xconn ,
now , & state - > auth ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
status = smbXsrv_session_create_auth ( state - > session ,
smb2req - > xconn , now ,
in_flags , in_security_mode ,
& state - > auth ) ;
if ( tevent_req_nterror ( req , status ) ) {
return tevent_req_post ( req , ev ) ;
}
}
if ( state - > auth - > gensec = = NULL ) {
status = auth_generic_prepare ( state - > auth ,
2014-06-12 12:47:51 +04:00
state - > smb2req - > xconn - > remote_address ,
2015-07-29 17:48:55 +03:00
& state - > auth - > gensec ) ;
2012-05-16 17:56:15 +04:00
if ( tevent_req_nterror ( req , status ) ) {
return tevent_req_post ( req , ev ) ;
}
2015-07-29 17:48:55 +03:00
gensec_want_feature ( state - > auth - > gensec , GENSEC_FEATURE_SESSION_KEY ) ;
gensec_want_feature ( state - > auth - > gensec , GENSEC_FEATURE_UNIX_TOKEN ) ;
2012-05-16 17:56:15 +04:00
2015-07-29 17:48:55 +03:00
status = gensec_start_mech_by_oid ( state - > auth - > gensec ,
2012-05-16 17:56:15 +04:00
GENSEC_OID_SPNEGO ) ;
if ( tevent_req_nterror ( req , status ) ) {
return tevent_req_post ( req , ev ) ;
}
}
2015-07-29 17:48:55 +03:00
status = smbXsrv_session_update ( state - > session ) ;
if ( tevent_req_nterror ( req , status ) ) {
return tevent_req_post ( req , ev ) ;
}
2012-05-16 17:56:15 +04:00
become_root ( ) ;
2012-05-16 18:05:48 +04:00
subreq = gensec_update_send ( state , state - > ev ,
2015-07-29 17:48:55 +03:00
state - > auth - > gensec ,
2012-05-16 18:05:48 +04:00
state - > in_security_buffer ) ;
2012-05-16 17:56:15 +04:00
unbecome_root ( ) ;
2012-05-16 18:05:48 +04:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
2012-05-17 02:30:43 +04:00
tevent_req_set_callback ( subreq , smbd_smb2_session_setup_gensec_done , req ) ;
2012-05-16 18:05:48 +04:00
return req ;
}
2012-05-17 02:30:43 +04:00
static void smbd_smb2_session_setup_gensec_done ( struct tevent_req * subreq )
2012-05-16 18:05:48 +04:00
{
struct tevent_req * req =
tevent_req_callback_data ( subreq ,
struct tevent_req ) ;
struct smbd_smb2_session_setup_state * state =
tevent_req_data ( req ,
struct smbd_smb2_session_setup_state ) ;
NTSTATUS status ;
become_root ( ) ;
status = gensec_update_recv ( subreq , state ,
& state - > out_security_buffer ) ;
unbecome_root ( ) ;
TALLOC_FREE ( subreq ) ;
2012-05-16 17:56:15 +04:00
if ( ! NT_STATUS_EQUAL ( status , NT_STATUS_MORE_PROCESSING_REQUIRED ) & &
! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( req , status ) ;
2012-05-16 18:05:48 +04:00
return ;
2012-05-16 17:56:15 +04:00
}
if ( NT_STATUS_EQUAL ( status , NT_STATUS_MORE_PROCESSING_REQUIRED ) ) {
state - > out_session_id = state - > session - > global - > session_wire_id ;
2015-07-29 17:48:55 +03:00
state - > smb2req - > preauth = state - > auth - > preauth ;
2012-05-16 17:56:15 +04:00
tevent_req_nterror ( req , status ) ;
2012-05-16 18:05:48 +04:00
return ;
2012-05-16 17:56:15 +04:00
}
2015-07-29 17:48:55 +03:00
status = gensec_session_info ( state - > auth - > gensec ,
2015-07-29 18:07:29 +03:00
state ,
2012-05-17 02:30:43 +04:00
& state - > session_info ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
2012-05-17 02:32:40 +04:00
if ( ( state - > in_previous_session_id ! = 0 ) & &
( state - > session - > global - > session_wire_id ! =
state - > in_previous_session_id ) )
{
subreq = smb2srv_session_close_previous_send ( state , state - > ev ,
2014-06-12 12:47:51 +04:00
state - > smb2req - > xconn ,
2012-05-17 02:32:40 +04:00
state - > session_info ,
state - > in_previous_session_id ,
state - > session - > global - > session_wire_id ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq ,
smbd_smb2_session_setup_previous_done ,
req ) ;
return ;
}
2014-06-12 11:19:29 +04:00
smbd_smb2_session_setup_auth_return ( req ) ;
2012-05-17 02:32:40 +04:00
}
static void smbd_smb2_session_setup_previous_done ( struct tevent_req * subreq )
{
struct tevent_req * req =
tevent_req_callback_data ( subreq ,
struct tevent_req ) ;
NTSTATUS status ;
status = smb2srv_session_close_previous_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
2014-06-12 11:19:29 +04:00
smbd_smb2_session_setup_auth_return ( req ) ;
}
static void smbd_smb2_session_setup_auth_return ( struct tevent_req * req )
{
struct smbd_smb2_session_setup_state * state =
tevent_req_data ( req ,
struct smbd_smb2_session_setup_state ) ;
NTSTATUS status ;
2012-05-16 17:56:15 +04:00
if ( state - > session - > global - > auth_session_info ! = NULL ) {
status = smbd_smb2_reauth_generic_return ( state - > session ,
2015-07-29 17:48:55 +03:00
& state - > auth ,
2012-05-16 17:56:15 +04:00
state - > smb2req ,
2012-05-17 02:30:43 +04:00
state - > session_info ,
2012-05-16 17:56:15 +04:00
& state - > out_session_flags ,
& state - > out_session_id ) ;
if ( tevent_req_nterror ( req , status ) ) {
2012-05-16 18:05:48 +04:00
return ;
2012-05-16 17:56:15 +04:00
}
tevent_req_done ( req ) ;
2012-05-16 18:05:48 +04:00
return ;
2012-05-12 12:16:41 +04:00
}
2012-05-16 17:56:15 +04:00
status = smbd_smb2_auth_generic_return ( state - > session ,
2015-07-29 17:48:55 +03:00
& state - > auth ,
2012-05-16 17:56:15 +04:00
state - > smb2req ,
state - > in_security_mode ,
2012-05-17 02:30:43 +04:00
state - > session_info ,
2012-05-16 17:56:15 +04:00
& state - > out_session_flags ,
& state - > out_session_id ) ;
2012-05-12 12:16:41 +04:00
if ( tevent_req_nterror ( req , status ) ) {
2012-05-16 18:05:48 +04:00
return ;
2012-05-12 12:16:41 +04:00
}
tevent_req_done ( req ) ;
2012-05-16 18:05:48 +04:00
return ;
2012-05-12 12:16:41 +04:00
}
static NTSTATUS smbd_smb2_session_setup_recv ( struct tevent_req * req ,
uint16_t * out_session_flags ,
TALLOC_CTX * mem_ctx ,
DATA_BLOB * out_security_buffer ,
uint64_t * out_session_id )
{
struct smbd_smb2_session_setup_state * state =
tevent_req_data ( req ,
struct smbd_smb2_session_setup_state ) ;
NTSTATUS status ;
2015-05-02 17:21:25 +03:00
if ( tevent_req_is_nterror ( req , & status ) ) {
if ( ! NT_STATUS_EQUAL ( status , NT_STATUS_MORE_PROCESSING_REQUIRED ) ) {
tevent_req_received ( req ) ;
return nt_status_squash ( status ) ;
}
} else {
status = NT_STATUS_OK ;
}
* out_session_flags = state - > out_session_flags ;
* out_security_buffer = state - > out_security_buffer ;
* out_session_id = state - > out_session_id ;
talloc_steal ( mem_ctx , out_security_buffer - > data ) ;
tevent_req_received ( req ) ;
return status ;
}
struct smbd_smb2_session_setup_wrap_state {
struct tevent_context * ev ;
struct smbd_smb2_request * smb2req ;
uint64_t in_session_id ;
uint8_t in_flags ;
uint8_t in_security_mode ;
uint64_t in_previous_session_id ;
DATA_BLOB in_security_buffer ;
uint16_t out_session_flags ;
DATA_BLOB out_security_buffer ;
uint64_t out_session_id ;
NTSTATUS error ;
} ;
static void smbd_smb2_session_setup_wrap_setup_done ( struct tevent_req * subreq ) ;
static void smbd_smb2_session_setup_wrap_shutdown_done ( struct tevent_req * subreq ) ;
static struct tevent_req * smbd_smb2_session_setup_wrap_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct smbd_smb2_request * smb2req ,
uint64_t in_session_id ,
uint8_t in_flags ,
uint8_t in_security_mode ,
uint64_t in_previous_session_id ,
DATA_BLOB in_security_buffer )
{
struct tevent_req * req ;
struct smbd_smb2_session_setup_wrap_state * state ;
struct tevent_req * subreq ;
req = tevent_req_create ( mem_ctx , & state ,
struct smbd_smb2_session_setup_wrap_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
state - > smb2req = smb2req ;
state - > in_session_id = in_session_id ;
state - > in_flags = in_flags ;
state - > in_security_mode = in_security_mode ;
state - > in_previous_session_id = in_previous_session_id ;
state - > in_security_buffer = in_security_buffer ;
subreq = smbd_smb2_session_setup_send ( state , state - > ev ,
state - > smb2req ,
state - > in_session_id ,
state - > in_flags ,
state - > in_security_mode ,
state - > in_previous_session_id ,
state - > in_security_buffer ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq ,
smbd_smb2_session_setup_wrap_setup_done , req ) ;
return req ;
}
static void smbd_smb2_session_setup_wrap_setup_done ( struct tevent_req * subreq )
{
struct tevent_req * req =
tevent_req_callback_data ( subreq ,
struct tevent_req ) ;
struct smbd_smb2_session_setup_wrap_state * state =
tevent_req_data ( req ,
struct smbd_smb2_session_setup_wrap_state ) ;
NTSTATUS status ;
status = smbd_smb2_session_setup_recv ( subreq ,
& state - > out_session_flags ,
state ,
& state - > out_security_buffer ,
& state - > out_session_id ) ;
TALLOC_FREE ( subreq ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
tevent_req_done ( req ) ;
return ;
}
if ( NT_STATUS_EQUAL ( status , NT_STATUS_MORE_PROCESSING_REQUIRED ) ) {
tevent_req_nterror ( req , status ) ;
return ;
}
if ( state - > smb2req - > session = = NULL ) {
tevent_req_nterror ( req , status ) ;
return ;
}
state - > error = status ;
subreq = smb2srv_session_shutdown_send ( state , state - > ev ,
state - > smb2req - > session ,
state - > smb2req ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq ,
smbd_smb2_session_setup_wrap_shutdown_done ,
req ) ;
}
static void smbd_smb2_session_setup_wrap_shutdown_done ( struct tevent_req * subreq )
{
struct tevent_req * req =
tevent_req_callback_data ( subreq ,
struct tevent_req ) ;
struct smbd_smb2_session_setup_wrap_state * state =
tevent_req_data ( req ,
struct smbd_smb2_session_setup_wrap_state ) ;
NTSTATUS status ;
status = smb2srv_session_shutdown_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
/*
* we may need to sign the response , so we need to keep
* the session until the response is sent to the wire .
*/
talloc_steal ( state - > smb2req , state - > smb2req - > session ) ;
tevent_req_nterror ( req , state - > error ) ;
}
static NTSTATUS smbd_smb2_session_setup_wrap_recv ( struct tevent_req * req ,
uint16_t * out_session_flags ,
TALLOC_CTX * mem_ctx ,
DATA_BLOB * out_security_buffer ,
uint64_t * out_session_id )
{
struct smbd_smb2_session_setup_wrap_state * state =
tevent_req_data ( req ,
struct smbd_smb2_session_setup_wrap_state ) ;
NTSTATUS status ;
2012-05-12 12:16:41 +04:00
if ( tevent_req_is_nterror ( req , & status ) ) {
if ( ! NT_STATUS_EQUAL ( status , NT_STATUS_MORE_PROCESSING_REQUIRED ) ) {
tevent_req_received ( req ) ;
2012-05-16 17:32:08 +04:00
return nt_status_squash ( status ) ;
2012-05-12 12:16:41 +04:00
}
} else {
status = NT_STATUS_OK ;
}
* out_session_flags = state - > out_session_flags ;
* out_security_buffer = state - > out_security_buffer ;
* out_session_id = state - > out_session_id ;
talloc_steal ( mem_ctx , out_security_buffer - > data ) ;
tevent_req_received ( req ) ;
return status ;
}
2014-03-10 12:53:18 +04:00
static struct tevent_req * smbd_smb2_logoff_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct smbd_smb2_request * smb2req ) ;
static NTSTATUS smbd_smb2_logoff_recv ( struct tevent_req * req ) ;
static void smbd_smb2_request_logoff_done ( struct tevent_req * subreq ) ;
2009-05-15 13:40:19 +04:00
NTSTATUS smbd_smb2_request_process_logoff ( struct smbd_smb2_request * req )
{
2011-09-06 16:01:43 +04:00
NTSTATUS status ;
2014-03-10 12:53:18 +04:00
struct tevent_req * subreq = NULL ;
2009-05-15 13:40:19 +04:00
2011-09-06 16:01:43 +04:00
status = smbd_smb2_request_verify_sizes ( req , 0x04 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return smbd_smb2_request_error ( req , status ) ;
2009-05-15 13:40:19 +04:00
}
2014-03-10 12:53:18 +04:00
subreq = smbd_smb2_logoff_send ( req , req - > sconn - > ev_ctx , req ) ;
if ( subreq = = NULL ) {
return smbd_smb2_request_error ( req , NT_STATUS_NO_MEMORY ) ;
}
tevent_req_set_callback ( subreq , smbd_smb2_request_logoff_done , req ) ;
2009-05-15 13:40:19 +04:00
/*
2014-03-10 12:53:18 +04:00
* Wait a long time before going async on this to allow
* requests we ' re waiting on to finish . Set timeout to 10 secs .
2009-05-15 13:40:19 +04:00
*/
2014-03-10 12:53:18 +04:00
return smbd_smb2_request_pending_queue ( req , subreq , 10000000 ) ;
}
static void smbd_smb2_request_logoff_done ( struct tevent_req * subreq )
{
struct smbd_smb2_request * smb2req =
tevent_req_callback_data ( subreq ,
struct smbd_smb2_request ) ;
DATA_BLOB outbody ;
NTSTATUS status ;
NTSTATUS error ;
status = smbd_smb2_logoff_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
2012-03-27 13:09:05 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2014-03-10 12:53:18 +04:00
error = smbd_smb2_request_error ( smb2req , status ) ;
if ( ! NT_STATUS_IS_OK ( error ) ) {
2014-06-11 14:15:48 +04:00
smbd_server_connection_terminate ( smb2req - > xconn ,
2014-03-10 12:53:18 +04:00
nt_errstr ( error ) ) ;
return ;
}
return ;
}
outbody = smbd_smb2_generate_outbody ( smb2req , 0x04 ) ;
if ( outbody . data = = NULL ) {
error = smbd_smb2_request_error ( smb2req , NT_STATUS_NO_MEMORY ) ;
if ( ! NT_STATUS_IS_OK ( error ) ) {
2014-06-11 14:15:48 +04:00
smbd_server_connection_terminate ( smb2req - > xconn ,
2014-03-10 12:53:18 +04:00
nt_errstr ( error ) ) ;
return ;
}
return ;
}
SSVAL ( outbody . data , 0x00 , 0x04 ) ; /* struct size */
SSVAL ( outbody . data , 0x02 , 0 ) ; /* reserved */
error = smbd_smb2_request_done ( smb2req , outbody , NULL ) ;
if ( ! NT_STATUS_IS_OK ( error ) ) {
2014-06-11 14:15:48 +04:00
smbd_server_connection_terminate ( smb2req - > xconn ,
2014-03-10 12:53:18 +04:00
nt_errstr ( error ) ) ;
return ;
}
}
2015-05-02 17:20:06 +03:00
struct smbd_smb2_logoff_state {
2014-03-10 12:53:18 +04:00
struct smbd_smb2_request * smb2req ;
} ;
2015-05-02 17:20:06 +03:00
static void smbd_smb2_logoff_shutdown_done ( struct tevent_req * subreq ) ;
2014-03-10 12:53:18 +04:00
2014-03-10 12:53:18 +04:00
static struct tevent_req * smbd_smb2_logoff_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct smbd_smb2_request * smb2req )
{
struct tevent_req * req ;
2015-05-02 17:20:06 +03:00
struct smbd_smb2_logoff_state * state ;
2014-03-10 12:53:18 +04:00
struct tevent_req * subreq ;
2014-03-10 12:53:18 +04:00
req = tevent_req_create ( mem_ctx , & state ,
2015-05-02 17:20:06 +03:00
struct smbd_smb2_logoff_state ) ;
2014-03-10 12:53:18 +04:00
if ( req = = NULL ) {
return NULL ;
}
state - > smb2req = smb2req ;
2015-05-02 17:20:06 +03:00
subreq = smb2srv_session_shutdown_send ( state , ev ,
smb2req - > session ,
smb2req ) ;
2014-03-10 12:53:18 +04:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
2015-05-02 17:20:06 +03:00
tevent_req_set_callback ( subreq , smbd_smb2_logoff_shutdown_done , req ) ;
2014-03-10 12:53:18 +04:00
return req ;
}
2015-05-02 17:20:06 +03:00
static void smbd_smb2_logoff_shutdown_done ( struct tevent_req * subreq )
2014-03-10 12:53:18 +04:00
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
2015-05-02 17:20:06 +03:00
struct smbd_smb2_logoff_state * state = tevent_req_data (
req , struct smbd_smb2_logoff_state ) ;
2014-03-10 12:53:18 +04:00
NTSTATUS status ;
2015-05-02 17:20:06 +03:00
status = smb2srv_session_shutdown_recv ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
2014-03-10 12:53:18 +04:00
TALLOC_FREE ( subreq ) ;
/*
* As we ' ve been awoken , we may have changed
* uid in the meantime . Ensure we ' re still
* root ( SMB2_OP_LOGOFF has . as_root = true ) .
*/
change_to_root_user ( ) ;
2014-03-10 12:53:18 +04:00
status = smbXsrv_session_logoff ( state - > smb2req - > session ) ;
if ( tevent_req_nterror ( req , status ) ) {
2014-03-10 12:53:18 +04:00
return ;
2012-03-27 13:09:05 +04:00
}
2009-05-15 13:40:19 +04:00
/*
* we may need to sign the response , so we need to keep
* the session until the response is sent to the wire .
*/
2014-03-10 12:53:18 +04:00
talloc_steal ( state - > smb2req , state - > smb2req - > session ) ;
2009-05-15 13:40:19 +04:00
2014-03-10 12:53:18 +04:00
tevent_req_done ( req ) ;
}
2009-05-15 13:40:19 +04:00
2014-03-10 12:53:18 +04:00
static NTSTATUS smbd_smb2_logoff_recv ( struct tevent_req * req )
{
return tevent_req_simple_recv_ntstatus ( req ) ;
2009-05-15 13:40:19 +04:00
}