2009-05-15 13:50:20 +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-15 13:50:20 +04:00
# include "smbd/globals.h"
2009-08-12 19:52:55 +04:00
# include "../libcli/smb/smb_common.h"
2010-10-12 08:27:50 +04:00
# include "../libcli/security/security.h"
2011-03-24 15:46:20 +03:00
# include "auth.h"
2011-06-29 09:33:54 +04:00
# include "lib/param/loadparm.h"
2012-05-13 19:47:07 +04:00
# include "../lib/util/tevent_ntstatus.h"
2009-05-15 13:50:20 +04:00
2018-03-21 22:01:05 +03:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_SMB2
2012-05-13 19:47:07 +04:00
static struct tevent_req * smbd_smb2_tree_connect_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct smbd_smb2_request * smb2req ,
const char * in_path ) ;
static NTSTATUS smbd_smb2_tree_connect_recv ( struct tevent_req * req ,
uint8_t * out_share_type ,
uint32_t * out_share_flags ,
uint32_t * out_capabilities ,
uint32_t * out_maximal_access ,
2015-05-28 16:35:25 +03:00
uint32_t * out_tree_id ,
bool * disconnect ) ;
2012-05-13 19:47:07 +04:00
2012-05-14 10:41:03 +04:00
static void smbd_smb2_request_tcon_done ( struct tevent_req * subreq ) ;
2009-05-15 13:50:20 +04:00
NTSTATUS smbd_smb2_request_process_tcon ( struct smbd_smb2_request * req )
{
const uint8_t * inbody ;
uint16_t in_path_offset ;
uint16_t in_path_length ;
DATA_BLOB in_path_buffer ;
char * in_path_string ;
size_t in_path_string_size ;
NTSTATUS status ;
bool ok ;
2012-05-14 10:41:03 +04:00
struct tevent_req * subreq ;
2009-05-15 13:50:20 +04:00
2011-09-06 16:01:43 +04:00
status = smbd_smb2_request_verify_sizes ( req , 0x09 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return smbd_smb2_request_error ( req , status ) ;
2009-05-15 13:50:20 +04:00
}
2012-08-05 17:00:23 +04:00
inbody = SMBD_SMB2_IN_BODY_PTR ( req ) ;
2009-05-15 13:50:20 +04:00
in_path_offset = SVAL ( inbody , 0x04 ) ;
in_path_length = SVAL ( inbody , 0x06 ) ;
2012-08-05 17:00:23 +04:00
if ( in_path_offset ! = ( SMB2_HDR_BODY + SMBD_SMB2_IN_BODY_LEN ( req ) ) ) {
2009-05-15 13:50:20 +04:00
return smbd_smb2_request_error ( req , NT_STATUS_INVALID_PARAMETER ) ;
}
2012-08-05 17:00:23 +04:00
if ( in_path_length > SMBD_SMB2_IN_DYN_LEN ( req ) ) {
2009-05-15 13:50:20 +04:00
return smbd_smb2_request_error ( req , NT_STATUS_INVALID_PARAMETER ) ;
}
2012-08-05 17:00:23 +04:00
in_path_buffer . data = SMBD_SMB2_IN_DYN_PTR ( req ) ;
2009-05-15 13:50:20 +04:00
in_path_buffer . length = in_path_length ;
ok = convert_string_talloc ( req , CH_UTF16 , CH_UNIX ,
in_path_buffer . data ,
in_path_buffer . length ,
& in_path_string ,
2011-03-24 02:59:41 +03:00
& in_path_string_size ) ;
2009-05-15 13:50:20 +04:00
if ( ! ok ) {
return smbd_smb2_request_error ( req , NT_STATUS_ILLEGAL_CHARACTER ) ;
}
2011-09-06 16:14:52 +04:00
if ( in_path_buffer . length = = 0 ) {
in_path_string_size = 0 ;
}
if ( strlen ( in_path_string ) ! = in_path_string_size ) {
return smbd_smb2_request_error ( req , NT_STATUS_BAD_NETWORK_NAME ) ;
}
2012-05-14 10:41:03 +04:00
subreq = smbd_smb2_tree_connect_send ( req ,
2018-12-27 17:18:55 +03:00
req - > sconn - > ev_ctx ,
2012-05-14 10:41:03 +04:00
req ,
in_path_string ) ;
if ( subreq = = NULL ) {
return smbd_smb2_request_error ( req , NT_STATUS_NO_MEMORY ) ;
}
tevent_req_set_callback ( subreq , smbd_smb2_request_tcon_done , req ) ;
2019-01-24 11:10:11 +03:00
/*
* Avoid sending a STATUS_PENDING message , it ' s very likely
* the client won ' t expect that .
*/
return smbd_smb2_request_pending_queue ( req , subreq , 0 ) ;
2012-05-14 10:41:03 +04:00
}
static void smbd_smb2_request_tcon_done ( struct tevent_req * subreq )
{
struct smbd_smb2_request * req =
tevent_req_callback_data ( subreq ,
struct smbd_smb2_request ) ;
uint8_t * outhdr ;
DATA_BLOB outbody ;
uint8_t out_share_type = 0 ;
uint32_t out_share_flags = 0 ;
uint32_t out_capabilities = 0 ;
uint32_t out_maximal_access = 0 ;
uint32_t out_tree_id = 0 ;
2015-05-28 16:35:25 +03:00
bool disconnect = false ;
2012-05-14 10:41:03 +04:00
NTSTATUS status ;
NTSTATUS error ;
status = smbd_smb2_tree_connect_recv ( subreq ,
& out_share_type ,
& out_share_flags ,
& out_capabilities ,
& out_maximal_access ,
2015-05-28 16:35:25 +03:00
& out_tree_id ,
& disconnect ) ;
2012-05-14 10:41:03 +04:00
TALLOC_FREE ( subreq ) ;
2009-05-15 13:50:20 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2015-05-28 16:35:25 +03:00
if ( disconnect ) {
smbd_server_connection_terminate ( req - > xconn ,
nt_errstr ( status ) ) ;
return ;
}
2012-05-14 10:41:03 +04:00
error = smbd_smb2_request_error ( req , status ) ;
if ( ! NT_STATUS_IS_OK ( error ) ) {
2014-06-11 14:15:48 +04:00
smbd_server_connection_terminate ( req - > xconn ,
2012-05-14 10:41:03 +04:00
nt_errstr ( error ) ) ;
return ;
}
return ;
2009-05-15 13:50:20 +04:00
}
2012-08-05 17:00:23 +04:00
outhdr = SMBD_SMB2_OUT_HDR_PTR ( req ) ;
2009-05-15 13:50:20 +04:00
2013-12-04 17:59:07 +04:00
outbody = smbd_smb2_generate_outbody ( req , 0x10 ) ;
2009-05-15 13:50:20 +04:00
if ( outbody . data = = NULL ) {
2012-05-14 10:41:03 +04:00
error = smbd_smb2_request_error ( req , NT_STATUS_NO_MEMORY ) ;
if ( ! NT_STATUS_IS_OK ( error ) ) {
2014-06-11 14:15:48 +04:00
smbd_server_connection_terminate ( req - > xconn ,
2012-05-14 10:41:03 +04:00
nt_errstr ( error ) ) ;
return ;
}
return ;
2009-05-15 13:50:20 +04:00
}
SIVAL ( outhdr , SMB2_HDR_TID , out_tree_id ) ;
SSVAL ( outbody . data , 0x00 , 0x10 ) ; /* struct size */
2009-06-03 13:31:43 +04:00
SCVAL ( outbody . data , 0x02 ,
out_share_type ) ; /* share type */
2009-05-15 13:50:20 +04:00
SCVAL ( outbody . data , 0x03 , 0 ) ; /* reserved */
2009-06-03 13:31:43 +04:00
SIVAL ( outbody . data , 0x04 ,
out_share_flags ) ; /* share flags */
SIVAL ( outbody . data , 0x08 ,
out_capabilities ) ; /* capabilities */
SIVAL ( outbody . data , 0x0C ,
out_maximal_access ) ; /* maximal access */
2009-05-15 13:50:20 +04:00
2012-05-14 10:41:03 +04:00
error = smbd_smb2_request_done ( req , outbody , NULL ) ;
if ( ! NT_STATUS_IS_OK ( error ) ) {
2014-06-11 14:15:48 +04:00
smbd_server_connection_terminate ( req - > xconn ,
2012-05-14 10:41:03 +04:00
nt_errstr ( error ) ) ;
return ;
}
2009-05-15 13:50:20 +04:00
}
static NTSTATUS smbd_smb2_tree_connect ( struct smbd_smb2_request * req ,
const char * in_path ,
2009-06-03 13:31:43 +04:00
uint8_t * out_share_type ,
uint32_t * out_share_flags ,
uint32_t * out_capabilities ,
uint32_t * out_maximal_access ,
2015-05-28 16:35:25 +03:00
uint32_t * out_tree_id ,
bool * disconnect )
2009-05-15 13:50:20 +04:00
{
2014-06-12 10:38:48 +04:00
struct smbXsrv_connection * conn = req - > xconn ;
2009-05-15 13:50:20 +04:00
const char * share = in_path ;
2010-11-10 02:07:49 +03:00
char * service = NULL ;
2009-05-15 13:50:20 +04:00
int snum = - 1 ;
2012-03-27 13:09:05 +04:00
struct smbXsrv_tcon * tcon ;
NTTIME now = timeval_to_nttime ( & req - > request_time ) ;
2010-02-25 05:11:07 +03:00
connection_struct * compat_conn = NULL ;
2012-03-27 13:09:05 +04:00
struct user_struct * compat_vuser = req - > session - > compat ;
2009-05-27 20:40:42 +04:00
NTSTATUS status ;
2015-11-09 19:23:29 +03:00
bool encryption_desired = req - > session - > global - > encryption_flags & SMBXSRV_ENCRYPTION_DESIRED ;
bool encryption_required = req - > session - > global - > encryption_flags & SMBXSRV_ENCRYPTION_REQUIRED ;
2012-08-08 08:25:10 +04:00
bool guest_session = false ;
2015-05-28 16:35:25 +03:00
bool require_signed_tcon = false ;
* disconnect = false ;
2009-05-15 13:50:20 +04:00
if ( strncmp ( share , " \\ \\ " , 2 ) = = 0 ) {
const char * p = strchr ( share + 2 , ' \\ ' ) ;
if ( p ) {
share = p + 1 ;
}
}
DEBUG ( 10 , ( " smbd_smb2_tree_connect: path[%s] share[%s] \n " ,
in_path , share ) ) ;
2015-05-28 16:35:25 +03:00
if ( security_session_user_level ( compat_vuser - > session_info , NULL ) < SECURITY_USER ) {
guest_session = true ;
}
if ( conn - > protocol > = PROTOCOL_SMB3_11 & & ! guest_session ) {
require_signed_tcon = true ;
}
if ( require_signed_tcon & & ! req - > do_encryption & & ! req - > do_signing ) {
DEBUG ( 1 , ( " smbd_smb2_tree_connect: reject request to share "
" [%s] as '%s \\ %s' without encryption or signing. "
" Disconnecting. \n " ,
share ,
req - > session - > global - > auth_session_info - > info - > domain_name ,
req - > session - > global - > auth_session_info - > info - > account_name ) ) ;
* disconnect = true ;
return NT_STATUS_ACCESS_DENIED ;
}
2010-11-10 02:07:49 +03:00
service = talloc_strdup ( talloc_tos ( ) , share ) ;
if ( ! service ) {
return NT_STATUS_NO_MEMORY ;
}
2009-05-15 13:50:20 +04:00
2012-08-09 04:01:00 +04:00
if ( ! strlower_m ( service ) ) {
DEBUG ( 2 , ( " strlower_m %s failed \n " , service ) ) ;
return NT_STATUS_INVALID_PARAMETER ;
}
2009-05-15 13:50:20 +04:00
2010-05-20 08:27:43 +04:00
/* TODO: do more things... */
if ( strequal ( service , HOMES_NAME ) ) {
if ( compat_vuser - > homes_snum = = - 1 ) {
DEBUG ( 2 , ( " [homes] share not available for "
" user %s because it was not found "
" or created at session setup "
" time \n " ,
2011-07-15 09:55:31 +04:00
compat_vuser - > session_info - > unix_info - > unix_name ) ) ;
2010-05-20 08:27:43 +04:00
return NT_STATUS_BAD_NETWORK_NAME ;
}
snum = compat_vuser - > homes_snum ;
} else if ( ( compat_vuser - > homes_snum ! = - 1 )
& & strequal ( service ,
2012-07-18 09:37:23 +04:00
lp_servicename ( talloc_tos ( ) , compat_vuser - > homes_snum ) ) ) {
2010-05-20 08:27:43 +04:00
snum = compat_vuser - > homes_snum ;
} else {
2010-11-10 02:07:49 +03:00
snum = find_service ( talloc_tos ( ) , service , & service ) ;
if ( ! service ) {
return NT_STATUS_NO_MEMORY ;
}
2010-05-20 08:27:43 +04:00
}
2009-05-15 13:50:20 +04:00
if ( snum < 0 ) {
2009-12-02 22:06:37 +03:00
DEBUG ( 3 , ( " smbd_smb2_tree_connect: couldn't find service %s \n " ,
2009-05-15 13:50:20 +04:00
service ) ) ;
return NT_STATUS_BAD_NETWORK_NAME ;
}
2018-03-29 11:00:41 +03:00
/* Handle non-DFS clients attempting connections to msdfs proxy */
if ( lp_host_msdfs ( ) ) {
char * proxy = lp_msdfs_proxy ( talloc_tos ( ) , snum ) ;
if ( ( proxy ! = NULL ) & & ( * proxy ! = ' \0 ' ) ) {
DBG_NOTICE ( " refusing connection to dfs proxy share "
" '%s' (pointing to %s) \n " ,
service ,
proxy ) ;
TALLOC_FREE ( proxy ) ;
return NT_STATUS_BAD_NETWORK_NAME ;
}
TALLOC_FREE ( proxy ) ;
}
2015-07-01 19:07:52 +03:00
if ( ( lp_smb_encrypt ( snum ) > = SMB_SIGNING_DESIRED ) & &
2017-01-16 14:56:10 +03:00
( conn - > smb2 . server . cipher ! = 0 ) )
{
2015-07-01 19:07:52 +03:00
encryption_desired = true ;
2015-02-25 18:59:26 +03:00
}
2012-07-23 15:47:24 +04:00
if ( lp_smb_encrypt ( snum ) = = SMB_SIGNING_REQUIRED ) {
2015-07-01 19:07:52 +03:00
encryption_desired = true ;
2012-08-08 08:25:10 +04:00
encryption_required = true ;
}
if ( guest_session & & encryption_required ) {
DEBUG ( 1 , ( " reject guest as encryption is required for service %s \n " ,
service ) ) ;
return NT_STATUS_ACCESS_DENIED ;
}
2014-10-13 13:07:01 +04:00
if ( conn - > smb2 . server . cipher = = 0 ) {
2012-08-08 08:25:10 +04:00
if ( encryption_required ) {
DEBUG ( 1 , ( " reject tcon with dialect[0x%04X] "
" as encryption is required for service %s \n " ,
conn - > smb2 . server . dialect , service ) ) ;
return NT_STATUS_ACCESS_DENIED ;
}
2012-07-23 15:47:24 +04:00
}
2009-05-15 13:50:20 +04:00
/* create a new tcon as child of the session */
2012-03-27 13:09:05 +04:00
status = smb2srv_tcon_create ( req - > session , now , & tcon ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2009-05-15 13:50:20 +04:00
}
2015-11-09 19:23:29 +03:00
if ( encryption_desired ) {
tcon - > global - > encryption_flags | = SMBXSRV_ENCRYPTION_DESIRED ;
}
if ( encryption_required ) {
tcon - > global - > encryption_flags | = SMBXSRV_ENCRYPTION_REQUIRED ;
}
2012-08-08 08:25:10 +04:00
2014-09-15 05:47:41 +04:00
compat_conn = make_connection_smb2 ( req ,
2012-03-27 13:09:05 +04:00
tcon , snum ,
req - > session - > compat ,
2012-02-03 11:03:10 +04:00
" ??? " ,
2009-05-27 20:40:42 +04:00
& status ) ;
2010-02-25 05:11:07 +03:00
if ( compat_conn = = NULL ) {
2009-05-27 20:40:42 +04:00
TALLOC_FREE ( tcon ) ;
return status ;
}
2012-07-18 09:37:23 +04:00
tcon - > global - > share_name = lp_servicename ( tcon - > global ,
SNUM ( compat_conn ) ) ;
2012-03-27 13:09:05 +04:00
if ( tcon - > global - > share_name = = NULL ) {
conn_free ( compat_conn ) ;
TALLOC_FREE ( tcon ) ;
return NT_STATUS_NO_MEMORY ;
}
2012-10-18 15:40:08 +04:00
tcon - > global - > session_global_id =
req - > session - > global - > session_global_id ;
2012-03-27 13:09:05 +04:00
tcon - > compat = talloc_move ( tcon , & compat_conn ) ;
tcon - > status = NT_STATUS_OK ;
status = smbXsrv_tcon_update ( tcon ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( tcon ) ;
return status ;
}
if ( IS_PRINT ( tcon - > compat ) ) {
2010-05-22 03:56:10 +04:00
* out_share_type = SMB2_SHARE_TYPE_PRINT ;
2012-03-27 13:09:05 +04:00
} else if ( IS_IPC ( tcon - > compat ) ) {
2010-05-22 03:56:10 +04:00
* out_share_type = SMB2_SHARE_TYPE_PIPE ;
2010-04-27 08:36:01 +04:00
} else {
2010-05-22 03:56:10 +04:00
* out_share_type = SMB2_SHARE_TYPE_DISK ;
2010-04-27 08:36:01 +04:00
}
2010-05-22 03:56:10 +04:00
2011-11-24 16:49:17 +04:00
* out_share_flags = 0 ;
2010-05-22 03:56:10 +04:00
2012-03-27 13:09:05 +04:00
if ( lp_msdfs_root ( SNUM ( tcon - > compat ) ) & & lp_host_msdfs ( ) ) {
2010-05-22 03:56:10 +04:00
* out_share_flags | = ( SMB2_SHAREFLAG_DFS | SMB2_SHAREFLAG_DFS_ROOT ) ;
* out_capabilities = SMB2_SHARE_CAP_DFS ;
} else {
* out_capabilities = 0 ;
}
2012-03-27 13:09:05 +04:00
switch ( lp_csc_policy ( SNUM ( tcon - > compat ) ) ) {
2010-05-22 03:56:10 +04:00
case CSC_POLICY_MANUAL :
break ;
case CSC_POLICY_DOCUMENTS :
* out_share_flags | = SMB2_SHAREFLAG_AUTO_CACHING ;
break ;
case CSC_POLICY_PROGRAMS :
* out_share_flags | = SMB2_SHAREFLAG_VDO_CACHING ;
break ;
case CSC_POLICY_DISABLE :
* out_share_flags | = SMB2_SHAREFLAG_NO_CACHING ;
break ;
default :
break ;
}
2014-02-04 06:08:58 +04:00
if ( lp_hide_unreadable ( SNUM ( tcon - > compat ) ) | |
2014-02-04 06:08:59 +04:00
lp_hide_unwriteable_files ( SNUM ( tcon - > compat ) ) ) {
2011-11-24 17:42:21 +04:00
* out_share_flags | = SMB2_SHAREFLAG_ACCESS_BASED_DIRECTORY_ENUM ;
}
2015-07-01 19:07:52 +03:00
if ( encryption_desired ) {
2012-08-08 08:25:10 +04:00
* out_share_flags | = SMB2_SHAREFLAG_ENCRYPT_DATA ;
}
2012-03-27 13:09:05 +04:00
* out_maximal_access = tcon - > compat - > share_access ;
2009-06-03 13:31:43 +04:00
2012-03-27 13:09:05 +04:00
* out_tree_id = tcon - > global - > tcon_wire_id ;
2017-06-16 00:01:18 +03:00
req - > last_tid = tcon - > global - > tcon_wire_id ;
2009-05-15 13:50:20 +04:00
return NT_STATUS_OK ;
}
2012-05-13 19:47:07 +04:00
struct smbd_smb2_tree_connect_state {
const char * in_path ;
uint8_t out_share_type ;
uint32_t out_share_flags ;
uint32_t out_capabilities ;
uint32_t out_maximal_access ;
uint32_t out_tree_id ;
2015-05-28 16:35:25 +03:00
bool disconnect ;
2012-05-13 19:47:07 +04:00
} ;
static struct tevent_req * smbd_smb2_tree_connect_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct smbd_smb2_request * smb2req ,
const char * in_path )
{
struct tevent_req * req ;
struct smbd_smb2_tree_connect_state * state ;
NTSTATUS status ;
req = tevent_req_create ( mem_ctx , & state ,
struct smbd_smb2_tree_connect_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > in_path = in_path ;
status = smbd_smb2_tree_connect ( smb2req ,
state - > in_path ,
& state - > out_share_type ,
& state - > out_share_flags ,
& state - > out_capabilities ,
& state - > out_maximal_access ,
2015-05-28 16:35:25 +03:00
& state - > out_tree_id ,
& state - > disconnect ) ;
2012-05-13 19:47:07 +04:00
if ( tevent_req_nterror ( req , status ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
}
static NTSTATUS smbd_smb2_tree_connect_recv ( struct tevent_req * req ,
uint8_t * out_share_type ,
uint32_t * out_share_flags ,
uint32_t * out_capabilities ,
uint32_t * out_maximal_access ,
2015-05-28 16:35:25 +03:00
uint32_t * out_tree_id ,
bool * disconnect )
2012-05-13 19:47:07 +04:00
{
struct smbd_smb2_tree_connect_state * state =
tevent_req_data ( req ,
struct smbd_smb2_tree_connect_state ) ;
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
tevent_req_received ( req ) ;
return status ;
}
* out_share_type = state - > out_share_type ;
* out_share_flags = state - > out_share_flags ;
* out_capabilities = state - > out_capabilities ;
* out_maximal_access = state - > out_maximal_access ;
* out_tree_id = state - > out_tree_id ;
2015-05-28 16:35:25 +03:00
* disconnect = state - > disconnect ;
2012-05-13 19:47:07 +04:00
tevent_req_received ( req ) ;
return NT_STATUS_OK ;
}
2014-03-10 12:53:18 +04:00
static struct tevent_req * smbd_smb2_tdis_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct smbd_smb2_request * smb2req ) ;
static NTSTATUS smbd_smb2_tdis_recv ( struct tevent_req * req ) ;
static void smbd_smb2_request_tdis_done ( struct tevent_req * subreq ) ;
2009-05-22 14:42:24 +04:00
NTSTATUS smbd_smb2_request_process_tdis ( 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-22 14:42:24 +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-22 14:42:24 +04:00
}
2018-12-27 17:18:55 +03:00
subreq = smbd_smb2_tdis_send ( req , req - > sconn - > ev_ctx , req ) ;
2014-03-10 12:53:18 +04:00
if ( subreq = = NULL ) {
return smbd_smb2_request_error ( req , NT_STATUS_NO_MEMORY ) ;
}
tevent_req_set_callback ( subreq , smbd_smb2_request_tdis_done , req ) ;
2009-05-22 14:42:24 +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-22 14:42:24 +04:00
*/
2014-03-10 12:53:18 +04:00
return smbd_smb2_request_pending_queue ( req , subreq , 10000000 ) ;
}
static void smbd_smb2_request_tdis_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_tdis_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 ;
2012-03-27 13:09:05 +04:00
}
2014-03-10 12:53:18 +04:00
outbody = smbd_smb2_generate_outbody ( smb2req , 0x04 ) ;
2009-05-22 14:42:24 +04:00
if ( outbody . data = = NULL ) {
2014-03-10 12:53:18 +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 ,
2014-03-10 12:53:18 +04:00
nt_errstr ( error ) ) ;
return ;
}
return ;
2009-05-22 14:42:24 +04:00
}
SSVAL ( outbody . data , 0x00 , 0x04 ) ; /* struct size */
SSVAL ( outbody . data , 0x02 , 0 ) ; /* reserved */
2014-03-10 12:53:18 +04:00
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 ;
}
}
struct smbd_smb2_tdis_state {
struct smbd_smb2_request * smb2req ;
2014-03-10 12:53:18 +04:00
struct tevent_queue * wait_queue ;
2014-03-10 12:53:18 +04:00
} ;
2014-03-10 12:53:18 +04:00
static void smbd_smb2_tdis_wait_done ( struct tevent_req * subreq ) ;
2014-03-10 12:53:18 +04:00
static struct tevent_req * smbd_smb2_tdis_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct smbd_smb2_request * smb2req )
{
struct tevent_req * req ;
struct smbd_smb2_tdis_state * state ;
2014-03-10 12:53:18 +04:00
struct tevent_req * subreq ;
2015-05-01 17:50:55 +03:00
struct smbXsrv_connection * xconn = NULL ;
2014-03-10 12:53:18 +04:00
req = tevent_req_create ( mem_ctx , & state ,
struct smbd_smb2_tdis_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > smb2req = smb2req ;
2014-03-10 12:53:18 +04:00
state - > wait_queue = tevent_queue_create ( state , " tdis_wait_queue " ) ;
if ( tevent_req_nomem ( state - > wait_queue , req ) ) {
return tevent_req_post ( req , ev ) ;
}
/*
* Make sure that no new request will be able to use this tcon .
*/
smb2req - > tcon - > status = NT_STATUS_NETWORK_NAME_DELETED ;
2015-05-01 17:50:55 +03:00
xconn = smb2req - > xconn - > client - > connections ;
for ( ; xconn ! = NULL ; xconn = xconn - > next ) {
struct smbd_smb2_request * preq ;
for ( preq = xconn - > smb2 . requests ; preq ! = NULL ; preq = preq - > next ) {
if ( preq = = smb2req ) {
/* Can't cancel current request. */
continue ;
}
if ( preq - > tcon ! = smb2req - > tcon ) {
/* Request on different tcon. */
continue ;
}
/*
* Never cancel anything in a compound
* request . Way too hard to deal with
* the result .
*/
if ( ! preq - > compound_related & & preq - > subreq ! = NULL ) {
tevent_req_cancel ( preq - > subreq ) ;
}
/*
* Now wait until the request is finished .
*
* We don ' t set a callback , as we just want to block the
* wait queue and the talloc_free ( ) of the request will
* remove the item from the wait queue .
*/
subreq = tevent_queue_wait_send ( preq , ev , state - > wait_queue ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
2014-03-10 12:53:18 +04:00
}
}
2014-03-10 12:53:18 +04:00
/*
2014-03-10 12:53:18 +04:00
* Now we add our own waiter to the end of the queue ,
* this way we get notified when all pending requests are finished
* and send to the socket .
2014-03-10 12:53:18 +04:00
*/
2014-03-10 12:53:18 +04:00
subreq = tevent_queue_wait_send ( state , ev , state - > wait_queue ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , smbd_smb2_tdis_wait_done , req ) ;
return req ;
}
static void smbd_smb2_tdis_wait_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct smbd_smb2_tdis_state * state = tevent_req_data (
req , struct smbd_smb2_tdis_state ) ;
NTSTATUS status ;
tevent_queue_wait_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
/*
* As we ' ve been awoken , we may have changed
* uid in the meantime . Ensure we ' re still
* root ( SMB2_OP_TDIS has . as_root = true ) .
*/
change_to_root_user ( ) ;
2014-03-10 12:53:18 +04:00
status = smbXsrv_tcon_disconnect ( state - > smb2req - > tcon ,
state - > smb2req - > tcon - > compat - > vuid ) ;
if ( tevent_req_nterror ( req , status ) ) {
2014-03-10 12:53:18 +04:00
return ;
2014-03-10 12:53:18 +04:00
}
/* We did tear down the tcon. */
TALLOC_FREE ( state - > smb2req - > tcon ) ;
tevent_req_done ( req ) ;
}
static NTSTATUS smbd_smb2_tdis_recv ( struct tevent_req * req )
{
return tevent_req_simple_recv_ntstatus ( req ) ;
2009-05-22 14:42:24 +04:00
}