2005-11-12 05:12:51 +03:00
/*
Unix SMB / CIFS implementation .
SMB2 composite connection setup
Copyright ( C ) Andrew Tridgell 2005
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
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2005-11-12 05:12:51 +03:00
( 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
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2005-11-12 05:12:51 +03:00
*/
# include "includes.h"
2011-04-27 10:57:41 +04:00
# include <tevent.h>
# include "lib/util/tevent_ntstatus.h"
2005-11-12 05:12:51 +03:00
# include "libcli/raw/libcliraw.h"
2008-04-02 06:53:27 +04:00
# include "libcli/raw/raw_proto.h"
2005-11-12 05:12:51 +03:00
# include "libcli/smb2/smb2.h"
# include "libcli/smb2/smb2_calls.h"
# include "libcli/composite/composite.h"
2006-03-07 14:07:23 +03:00
# include "libcli/resolve/resolve.h"
2007-09-08 16:42:09 +04:00
# include "param/param.h"
2011-11-30 11:50:11 +04:00
# include "auth/credentials/credentials.h"
2011-09-20 22:59:45 +04:00
# include "../libcli/smb/smbXcli_base.h"
2005-11-12 05:12:51 +03:00
struct smb2_connect_state {
2011-04-27 10:57:41 +04:00
struct tevent_context * ev ;
2005-11-12 05:12:51 +03:00
struct cli_credentials * credentials ;
2018-07-19 00:52:30 +03:00
bool fallback_to_anonymous ;
2012-02-26 04:43:50 +04:00
uint64_t previous_session_id ;
2008-01-03 03:39:01 +03:00
struct resolve_context * resolve_ctx ;
2005-11-12 05:12:51 +03:00
const char * host ;
const char * share ;
2014-09-29 12:50:18 +04:00
const char * unc ;
2008-11-02 00:42:09 +03:00
const char * * ports ;
const char * socket_options ;
2011-11-30 11:50:11 +04:00
struct nbt_name calling , called ;
2008-11-02 18:20:00 +03:00
struct gensec_settings * gensec_settings ;
2008-05-30 11:03:54 +04:00
struct smbcli_options options ;
2011-09-20 22:59:45 +04:00
struct smb2_transport * transport ;
2005-11-12 05:12:51 +03:00
struct smb2_session * session ;
struct smb2_tree * tree ;
} ;
2018-07-18 17:43:32 +03:00
static void smb2_connect_session_start ( struct tevent_req * req ) ;
2011-11-30 11:50:11 +04:00
static void smb2_connect_socket_done ( struct composite_context * creq ) ;
2005-11-12 05:12:51 +03:00
/*
a composite function that does a full negprot / sesssetup / tcon , returning
a connected smb2_tree
*/
2011-04-27 10:57:41 +04:00
struct tevent_req * smb2_connect_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
const char * host ,
const char * * ports ,
const char * share ,
struct resolve_context * resolve_ctx ,
struct cli_credentials * credentials ,
2018-07-19 00:52:30 +03:00
bool fallback_to_anonymous ,
2018-07-18 17:44:16 +03:00
struct smbXcli_conn * * existing_conn ,
2012-02-26 04:43:50 +04:00
uint64_t previous_session_id ,
2013-09-25 09:16:39 +04:00
const struct smbcli_options * options ,
2011-04-27 10:57:41 +04:00
const char * socket_options ,
struct gensec_settings * gensec_settings )
2005-11-12 05:12:51 +03:00
{
2011-04-27 10:57:41 +04:00
struct tevent_req * req ;
2005-11-12 05:12:51 +03:00
struct smb2_connect_state * state ;
2005-11-19 02:15:32 +03:00
struct composite_context * creq ;
2011-11-30 11:50:11 +04:00
static const char * default_ports [ ] = { " 445 " , " 139 " , NULL } ;
2005-11-12 05:12:51 +03:00
2011-04-27 10:57:41 +04:00
req = tevent_req_create ( mem_ctx , & state ,
struct smb2_connect_state ) ;
if ( req = = NULL ) {
return NULL ;
}
2005-11-12 05:12:51 +03:00
2011-04-27 10:57:41 +04:00
state - > ev = ev ;
2005-11-12 05:12:51 +03:00
state - > credentials = credentials ;
2018-07-19 00:52:30 +03:00
state - > fallback_to_anonymous = fallback_to_anonymous ;
2012-02-26 04:43:50 +04:00
state - > previous_session_id = previous_session_id ;
2008-05-30 11:03:54 +04:00
state - > options = * options ;
2011-04-27 10:57:41 +04:00
state - > host = host ;
state - > ports = ports ;
state - > share = share ;
state - > resolve_ctx = resolve_ctx ;
state - > socket_options = socket_options ;
state - > gensec_settings = gensec_settings ;
2005-11-12 05:12:51 +03:00
2011-11-30 11:50:11 +04:00
if ( state - > ports = = NULL ) {
state - > ports = default_ports ;
2011-04-27 10:57:41 +04:00
}
2005-11-12 05:12:51 +03:00
2011-11-30 11:50:11 +04:00
make_nbt_name_client ( & state - > calling ,
cli_credentials_get_workstation ( credentials ) ) ;
2011-04-28 18:06:05 +04:00
2011-11-30 11:50:11 +04:00
nbt_choose_called_name ( state , & state - > called ,
host , NBT_NAME_SERVER ) ;
2011-04-28 18:04:19 +04:00
2014-09-29 12:50:18 +04:00
state - > unc = talloc_asprintf ( state , " \\ \\ %s \\ %s " ,
state - > host , state - > share ) ;
if ( tevent_req_nomem ( state - > unc , req ) ) {
return tevent_req_post ( req , ev ) ;
}
2018-07-18 17:44:16 +03:00
if ( existing_conn ! = NULL ) {
NTSTATUS status ;
status = smb2_transport_raw_init ( state , ev ,
existing_conn ,
options ,
& state - > transport ) ;
if ( tevent_req_nterror ( req , status ) ) {
return tevent_req_post ( req , ev ) ;
}
smb2_connect_session_start ( req ) ;
if ( ! tevent_req_is_in_progress ( req ) ) {
return tevent_req_post ( req , ev ) ;
}
return req ;
}
2011-11-30 11:50:11 +04:00
creq = smbcli_sock_connect_send ( state , NULL , state - > ports ,
2011-04-28 18:04:19 +04:00
state - > host , state - > resolve_ctx ,
2011-11-30 11:50:11 +04:00
state - > ev , state - > socket_options ,
& state - > calling ,
& state - > called ) ;
2011-04-28 18:04:19 +04:00
if ( tevent_req_nomem ( creq , req ) ) {
2011-11-30 11:50:11 +04:00
return tevent_req_post ( req , ev ) ;
2011-04-28 18:04:19 +04:00
}
creq - > async . fn = smb2_connect_socket_done ;
creq - > async . private_data = req ;
2011-11-30 11:50:11 +04:00
return req ;
2011-04-28 18:04:19 +04:00
}
2011-09-20 22:59:45 +04:00
static void smb2_connect_negprot_done ( struct tevent_req * subreq ) ;
2011-04-28 18:07:49 +04:00
2011-04-28 18:06:05 +04:00
static void smb2_connect_socket_done ( struct composite_context * creq )
{
struct tevent_req * req =
talloc_get_type_abort ( creq - > async . private_data ,
struct tevent_req ) ;
struct smb2_connect_state * state =
tevent_req_data ( req ,
struct smb2_connect_state ) ;
struct smbcli_socket * sock ;
2011-09-20 22:59:45 +04:00
struct tevent_req * subreq ;
2011-04-28 18:06:05 +04:00
NTSTATUS status ;
2011-09-20 22:59:45 +04:00
uint32_t timeout_msec ;
2016-02-27 06:14:39 +03:00
enum protocol_types min_protocol ;
2011-04-28 18:06:05 +04:00
status = smbcli_sock_connect_recv ( creq , state , & sock ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
2011-09-20 22:59:45 +04:00
state - > transport = smb2_transport_init ( sock , state , & state - > options ) ;
if ( tevent_req_nomem ( state - > transport , req ) ) {
2011-04-28 18:06:05 +04:00
return ;
}
2011-09-20 22:59:45 +04:00
timeout_msec = state - > transport - > options . request_timeout * 1000 ;
2016-02-27 06:14:39 +03:00
min_protocol = state - > transport - > options . min_protocol ;
if ( min_protocol < PROTOCOL_SMB2_02 ) {
min_protocol = PROTOCOL_SMB2_02 ;
}
2011-04-28 18:06:05 +04:00
2011-09-20 22:59:45 +04:00
subreq = smbXcli_negprot_send ( state , state - > ev ,
state - > transport - > conn , timeout_msec ,
2016-02-27 06:14:39 +03:00
min_protocol ,
2017-02-27 18:14:39 +03:00
state - > transport - > options . max_protocol ,
state - > transport - > options . max_credits ) ;
2011-09-20 22:59:45 +04:00
if ( tevent_req_nomem ( subreq , req ) ) {
2011-04-28 18:06:05 +04:00
return ;
}
2011-09-20 22:59:45 +04:00
tevent_req_set_callback ( subreq , smb2_connect_negprot_done , req ) ;
2011-04-28 18:06:05 +04:00
}
2011-04-27 20:24:01 +04:00
static void smb2_connect_session_done ( struct tevent_req * subreq ) ;
2011-04-28 18:09:35 +04:00
2011-09-20 22:59:45 +04:00
static void smb2_connect_negprot_done ( struct tevent_req * subreq )
2011-04-28 18:07:49 +04:00
{
struct tevent_req * req =
2011-09-20 22:59:45 +04:00
tevent_req_callback_data ( subreq ,
2011-04-28 18:07:49 +04:00
struct tevent_req ) ;
NTSTATUS status ;
2011-09-20 22:59:45 +04:00
status = smbXcli_negprot_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
2011-04-28 18:07:49 +04:00
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
2018-07-18 17:43:32 +03:00
smb2_connect_session_start ( req ) ;
}
static void smb2_connect_session_start ( struct tevent_req * req )
{
struct smb2_connect_state * state =
tevent_req_data ( req ,
struct smb2_connect_state ) ;
struct smb2_transport * transport = state - > transport ;
struct tevent_req * subreq = NULL ;
2014-07-10 10:21:22 +04:00
state - > session = smb2_session_init ( transport , state - > gensec_settings , state ) ;
2011-04-28 18:07:49 +04:00
if ( tevent_req_nomem ( state - > session , req ) ) {
return ;
}
2011-04-27 20:24:01 +04:00
subreq = smb2_session_setup_spnego_send ( state , state - > ev ,
state - > session ,
2012-02-26 01:32:03 +04:00
state - > credentials ,
2012-02-26 04:43:50 +04:00
state - > previous_session_id ) ;
2011-04-27 20:24:01 +04:00
if ( tevent_req_nomem ( subreq , req ) ) {
2011-04-28 18:07:49 +04:00
return ;
}
2011-04-27 20:24:01 +04:00
tevent_req_set_callback ( subreq , smb2_connect_session_done , req ) ;
2011-04-28 18:07:49 +04:00
}
2014-09-29 12:50:18 +04:00
static void smb2_connect_tcon_done ( struct tevent_req * subreq ) ;
2011-04-28 18:11:50 +04:00
2011-04-27 20:24:01 +04:00
static void smb2_connect_session_done ( struct tevent_req * subreq )
2011-04-28 18:09:35 +04:00
{
struct tevent_req * req =
2011-04-27 20:24:01 +04:00
tevent_req_callback_data ( subreq ,
2011-04-28 18:09:35 +04:00
struct tevent_req ) ;
struct smb2_connect_state * state =
tevent_req_data ( req ,
struct smb2_connect_state ) ;
NTSTATUS status ;
2014-09-29 12:50:18 +04:00
uint32_t timeout_msec ;
2011-04-28 18:09:35 +04:00
2011-04-27 20:24:01 +04:00
status = smb2_session_setup_spnego_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
2018-07-19 00:52:30 +03:00
if ( ! NT_STATUS_IS_OK ( status ) & &
! cli_credentials_is_anonymous ( state - > credentials ) & &
state - > fallback_to_anonymous ) {
struct cli_credentials * anon_creds = NULL ;
/*
* The transport was moved to session ,
* we need to revert that before removing
* the old broken session .
*/
state - > transport = talloc_move ( state , & state - > session - > transport ) ;
TALLOC_FREE ( state - > session ) ;
anon_creds = cli_credentials_init_anon ( state ) ;
if ( tevent_req_nomem ( anon_creds , req ) ) {
return ;
}
cli_credentials_set_workstation ( anon_creds ,
cli_credentials_get_workstation ( state - > credentials ) ,
CRED_SPECIFIED ) ;
/*
* retry with anonymous credentials
*/
state - > credentials = anon_creds ;
smb2_connect_session_start ( req ) ;
return ;
}
2011-04-28 18:09:35 +04:00
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
2014-09-29 12:50:18 +04:00
state - > tree = smb2_tree_init ( state - > session , state , true ) ;
if ( tevent_req_nomem ( state - > tree , req ) ) {
2011-04-28 18:09:35 +04:00
return ;
}
2014-09-29 12:50:18 +04:00
timeout_msec = state - > transport - > options . request_timeout * 1000 ;
subreq = smb2cli_tcon_send ( state , state - > ev ,
state - > transport - > conn ,
timeout_msec ,
state - > session - > smbXcli ,
state - > tree - > smbXcli ,
0 , /* flags */
state - > unc ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
2011-04-28 18:09:35 +04:00
return ;
}
2014-09-29 12:50:18 +04:00
tevent_req_set_callback ( subreq , smb2_connect_tcon_done , req ) ;
2011-04-28 18:09:35 +04:00
}
2014-09-29 12:50:18 +04:00
static void smb2_connect_tcon_done ( struct tevent_req * subreq )
2011-04-28 18:11:50 +04:00
{
struct tevent_req * req =
2014-09-29 12:50:18 +04:00
tevent_req_callback_data ( subreq ,
2011-04-28 18:11:50 +04:00
struct tevent_req ) ;
NTSTATUS status ;
2014-09-29 12:50:18 +04:00
status = smb2cli_tcon_recv ( subreq ) ;
2011-04-28 18:11:50 +04:00
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
tevent_req_done ( req ) ;
}
2011-04-27 10:57:41 +04:00
NTSTATUS smb2_connect_recv ( struct tevent_req * req ,
TALLOC_CTX * mem_ctx ,
2005-11-12 05:12:51 +03:00
struct smb2_tree * * tree )
{
2011-04-27 10:57:41 +04:00
struct smb2_connect_state * state =
tevent_req_data ( req ,
struct smb2_connect_state ) ;
2005-11-12 05:12:51 +03:00
NTSTATUS status ;
2011-04-27 10:57:41 +04:00
if ( tevent_req_is_nterror ( req , & status ) ) {
tevent_req_received ( req ) ;
return status ;
2005-11-12 05:12:51 +03:00
}
2011-04-27 10:57:41 +04:00
* tree = talloc_move ( mem_ctx , & state - > tree ) ;
tevent_req_received ( req ) ;
return NT_STATUS_OK ;
2005-11-12 05:12:51 +03:00
}
/*
sync version of smb2_connect
*/
2012-02-26 04:45:00 +04:00
NTSTATUS smb2_connect_ext ( TALLOC_CTX * mem_ctx ,
const char * host ,
const char * * ports ,
const char * share ,
struct resolve_context * resolve_ctx ,
struct cli_credentials * credentials ,
uint64_t previous_session_id ,
struct smb2_tree * * tree ,
struct tevent_context * ev ,
2013-09-25 09:16:39 +04:00
const struct smbcli_options * options ,
2012-02-26 04:45:00 +04:00
const char * socket_options ,
struct gensec_settings * gensec_settings )
2005-11-12 05:12:51 +03:00
{
2011-04-27 10:57:41 +04:00
struct tevent_req * subreq ;
NTSTATUS status ;
bool ok ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
if ( frame = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
subreq = smb2_connect_send ( frame ,
ev ,
host ,
ports ,
share ,
resolve_ctx ,
credentials ,
2018-07-19 00:52:30 +03:00
false , /* fallback_to_anonymous */
2018-07-18 17:44:16 +03:00
NULL , /* existing_conn */
2012-02-26 04:45:00 +04:00
previous_session_id ,
2011-04-27 10:57:41 +04:00
options ,
socket_options ,
gensec_settings ) ;
if ( subreq = = NULL ) {
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
ok = tevent_req_poll ( subreq , ev ) ;
if ( ! ok ) {
2011-06-20 08:55:32 +04:00
status = map_nt_error_from_unix_common ( errno ) ;
2011-04-27 10:57:41 +04:00
TALLOC_FREE ( frame ) ;
return status ;
}
status = smb2_connect_recv ( subreq , mem_ctx , tree ) ;
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( frame ) ;
return status ;
}
TALLOC_FREE ( frame ) ;
return NT_STATUS_OK ;
2005-11-12 05:12:51 +03:00
}
2012-02-26 04:45:00 +04:00
NTSTATUS smb2_connect ( TALLOC_CTX * mem_ctx ,
const char * host ,
const char * * ports ,
const char * share ,
struct resolve_context * resolve_ctx ,
struct cli_credentials * credentials ,
struct smb2_tree * * tree ,
struct tevent_context * ev ,
struct smbcli_options * options ,
const char * socket_options ,
struct gensec_settings * gensec_settings )
{
NTSTATUS status ;
status = smb2_connect_ext ( mem_ctx , host , ports , share , resolve_ctx ,
credentials ,
0 , /* previous_session_id */
tree , ev , options , socket_options ,
gensec_settings ) ;
return status ;
}