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"
# 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"
2005-11-12 05:12:51 +03:00
struct smb2_connect_state {
struct cli_credentials * credentials ;
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 ;
2008-05-30 11:03:54 +04:00
struct smbcli_options options ;
2005-11-12 05:12:51 +03:00
struct smb2_negprot negprot ;
struct smb2_tree_connect tcon ;
struct smb2_session * session ;
struct smb2_tree * tree ;
} ;
/*
continue after tcon reply
*/
static void continue_tcon ( struct smb2_request * req )
{
2008-05-16 09:03:58 +04:00
struct composite_context * c = talloc_get_type ( req - > async . private_data ,
2005-11-12 05:12:51 +03:00
struct composite_context ) ;
struct smb2_connect_state * state = talloc_get_type ( c - > private_data ,
struct smb2_connect_state ) ;
c - > status = smb2_tree_connect_recv ( req , & state - > tcon ) ;
2005-11-19 02:48:51 +03:00
if ( ! composite_is_ok ( c ) ) return ;
2005-11-12 05:12:51 +03:00
state - > tree - > tid = state - > tcon . out . tid ;
composite_done ( c ) ;
}
/*
continue after a session setup
*/
static void continue_session ( struct composite_context * creq )
{
struct composite_context * c = talloc_get_type ( creq - > async . private_data ,
struct composite_context ) ;
struct smb2_connect_state * state = talloc_get_type ( c - > private_data ,
struct smb2_connect_state ) ;
2005-11-19 02:15:32 +03:00
struct smb2_request * req ;
2005-11-12 05:12:51 +03:00
c - > status = smb2_session_setup_spnego_recv ( creq ) ;
2005-11-19 02:48:51 +03:00
if ( ! composite_is_ok ( c ) ) return ;
2005-11-12 05:12:51 +03:00
2007-10-07 02:28:14 +04:00
state - > tree = smb2_tree_init ( state - > session , state , true ) ;
2005-11-19 02:34:47 +03:00
if ( composite_nomem ( state - > tree , c ) ) return ;
2005-11-12 05:12:51 +03:00
2008-02-13 02:13:28 +03:00
state - > tcon . in . reserved = 0 ;
2005-11-12 05:12:51 +03:00
state - > tcon . in . path = talloc_asprintf ( state , " \\ \\ %s \\ %s " ,
state - > host , state - > share ) ;
2005-11-19 02:34:47 +03:00
if ( composite_nomem ( state - > tcon . in . path , c ) ) return ;
2005-11-12 05:12:51 +03:00
2005-11-19 02:15:32 +03:00
req = smb2_tree_connect_send ( state - > tree , & state - > tcon ) ;
2005-11-19 02:34:47 +03:00
if ( composite_nomem ( req , c ) ) return ;
2005-11-12 05:12:51 +03:00
2005-11-19 02:15:32 +03:00
req - > async . fn = continue_tcon ;
2008-05-16 09:03:58 +04:00
req - > async . private_data = c ;
2005-11-12 05:12:51 +03:00
}
/*
continue after negprot reply
*/
static void continue_negprot ( struct smb2_request * req )
{
2008-05-16 09:03:58 +04:00
struct composite_context * c = talloc_get_type ( req - > async . private_data ,
2005-11-12 05:12:51 +03:00
struct composite_context ) ;
struct smb2_connect_state * state = talloc_get_type ( c - > private_data ,
struct smb2_connect_state ) ;
struct smb2_transport * transport = req - > transport ;
2005-11-19 02:15:32 +03:00
struct composite_context * creq ;
2005-11-12 05:12:51 +03:00
c - > status = smb2_negprot_recv ( req , c , & state - > negprot ) ;
2005-11-19 02:48:51 +03:00
if ( ! composite_is_ok ( c ) ) return ;
2005-11-12 05:12:51 +03:00
2008-05-20 05:57:43 +04:00
transport - > negotiate . system_time = state - > negprot . out . system_time ;
transport - > negotiate . server_start_time = state - > negprot . out . server_start_time ;
2008-05-30 11:03:54 +04:00
transport - > negotiate . security_mode = state - > negprot . out . security_mode ;
switch ( transport - > options . signing ) {
case SMB_SIGNING_OFF :
if ( transport - > negotiate . security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED ) {
composite_error ( c , NT_STATUS_ACCESS_DENIED ) ;
return ;
}
transport - > signing . doing_signing = false ;
break ;
case SMB_SIGNING_SUPPORTED :
case SMB_SIGNING_AUTO :
if ( transport - > negotiate . security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED ) {
transport - > signing . doing_signing = true ;
} else {
transport - > signing . doing_signing = false ;
}
break ;
case SMB_SIGNING_REQUIRED :
if ( transport - > negotiate . security_mode & SMB2_NEGOTIATE_SIGNING_ENABLED ) {
transport - > signing . doing_signing = true ;
} else {
composite_error ( c , NT_STATUS_ACCESS_DENIED ) ;
return ;
}
break ;
}
2008-05-20 05:57:43 +04:00
2007-12-07 18:04:25 +03:00
state - > session = smb2_session_init ( transport , global_loadparm , state , true ) ;
2005-11-19 02:34:47 +03:00
if ( composite_nomem ( state - > session , c ) ) return ;
2005-11-12 05:12:51 +03:00
2005-11-19 02:15:32 +03:00
creq = smb2_session_setup_spnego_send ( state - > session , state - > credentials ) ;
2005-11-12 05:12:51 +03:00
2005-11-19 02:34:47 +03:00
composite_continue ( c , creq , continue_session , c ) ;
2005-11-12 05:12:51 +03:00
}
/*
continue after a socket connect completes
*/
static void continue_socket ( struct composite_context * creq )
{
struct composite_context * c = talloc_get_type ( creq - > async . private_data ,
struct composite_context ) ;
struct smb2_connect_state * state = talloc_get_type ( c - > private_data ,
struct smb2_connect_state ) ;
struct smbcli_socket * sock ;
struct smb2_transport * transport ;
2005-11-19 02:15:32 +03:00
struct smb2_request * req ;
2008-04-16 12:05:53 +04:00
uint16_t dialects [ 2 ] ;
2005-11-12 05:12:51 +03:00
c - > status = smbcli_sock_connect_recv ( creq , state , & sock ) ;
2005-11-19 02:48:51 +03:00
if ( ! composite_is_ok ( c ) ) return ;
2005-11-12 05:12:51 +03:00
2008-05-30 11:03:54 +04:00
transport = smb2_transport_init ( sock , state , & state - > options ) ;
2005-11-19 02:34:47 +03:00
if ( composite_nomem ( transport , c ) ) return ;
2005-11-12 05:12:51 +03:00
ZERO_STRUCT ( state - > negprot ) ;
2008-04-16 12:05:53 +04:00
state - > negprot . in . dialect_count = 2 ;
2008-05-30 11:03:54 +04:00
switch ( transport - > options . signing ) {
case SMB_SIGNING_OFF :
state - > negprot . in . security_mode = 0 ;
break ;
case SMB_SIGNING_SUPPORTED :
case SMB_SIGNING_AUTO :
state - > negprot . in . security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED ;
break ;
case SMB_SIGNING_REQUIRED :
state - > negprot . in . security_mode =
SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED ;
break ;
}
2008-02-12 04:54:44 +03:00
state - > negprot . in . capabilities = 0 ;
unix_to_nt_time ( & state - > negprot . in . start_time , time ( NULL ) ) ;
2008-04-16 12:05:53 +04:00
dialects [ 0 ] = 0 ;
dialects [ 1 ] = SMB2_DIALECT_REVISION ;
2008-02-12 04:54:44 +03:00
state - > negprot . in . dialects = dialects ;
2005-11-16 14:01:15 +03:00
2005-11-19 02:15:32 +03:00
req = smb2_negprot_send ( transport , & state - > negprot ) ;
2005-11-19 02:34:47 +03:00
if ( composite_nomem ( req , c ) ) return ;
2005-11-12 05:12:51 +03:00
2005-11-19 02:15:32 +03:00
req - > async . fn = continue_negprot ;
2008-05-16 09:03:58 +04:00
req - > async . private_data = c ;
2005-11-12 05:12:51 +03:00
}
/*
continue after a resolve finishes
*/
static void continue_resolve ( struct composite_context * creq )
{
struct composite_context * c = talloc_get_type ( creq - > async . private_data ,
struct composite_context ) ;
struct smb2_connect_state * state = talloc_get_type ( c - > private_data ,
struct smb2_connect_state ) ;
const char * addr ;
2007-12-12 04:15:29 +03:00
const char * ports [ 2 ] = { " 445 " , NULL } ;
2005-11-12 05:12:51 +03:00
c - > status = resolve_name_recv ( creq , state , & addr ) ;
2005-11-19 02:48:51 +03:00
if ( ! composite_is_ok ( c ) ) return ;
2005-11-12 05:12:51 +03:00
2008-01-03 03:39:01 +03:00
creq = smbcli_sock_connect_send ( state , addr , ports , state - > host , state - > resolve_ctx , c - > event_ctx ) ;
2005-11-12 05:12:51 +03:00
2005-11-19 02:34:47 +03:00
composite_continue ( c , creq , continue_socket , c ) ;
2005-11-12 05:12:51 +03:00
}
/*
a composite function that does a full negprot / sesssetup / tcon , returning
a connected smb2_tree
*/
struct composite_context * smb2_connect_send ( TALLOC_CTX * mem_ctx ,
const char * host ,
const char * share ,
2007-12-10 20:41:19 +03:00
struct resolve_context * resolve_ctx ,
2005-11-12 05:12:51 +03:00
struct cli_credentials * credentials ,
2008-05-30 11:03:54 +04:00
struct event_context * ev ,
struct smbcli_options * options )
2005-11-12 05:12:51 +03:00
{
struct composite_context * c ;
struct smb2_connect_state * state ;
struct nbt_name name ;
2005-11-19 02:15:32 +03:00
struct composite_context * creq ;
2005-11-12 05:12:51 +03:00
2006-07-30 21:29:02 +04:00
c = composite_create ( mem_ctx , ev ) ;
2005-11-12 05:12:51 +03:00
if ( c = = NULL ) return NULL ;
state = talloc ( c , struct smb2_connect_state ) ;
2006-07-30 21:29:02 +04:00
if ( composite_nomem ( state , c ) ) return c ;
2005-11-12 05:12:51 +03:00
c - > private_data = state ;
state - > credentials = credentials ;
2008-05-30 11:03:54 +04:00
state - > options = * options ;
2005-11-12 05:12:51 +03:00
state - > host = talloc_strdup ( c , host ) ;
2006-07-30 21:29:02 +04:00
if ( composite_nomem ( state - > host , c ) ) return c ;
2005-11-12 05:12:51 +03:00
state - > share = talloc_strdup ( c , share ) ;
2006-07-30 21:29:02 +04:00
if ( composite_nomem ( state - > share , c ) ) return c ;
2008-01-03 03:39:01 +03:00
state - > resolve_ctx = talloc_reference ( state , resolve_ctx ) ;
2005-11-12 05:12:51 +03:00
ZERO_STRUCT ( name ) ;
name . name = host ;
2007-12-10 20:41:19 +03:00
creq = resolve_name_send ( resolve_ctx , & name , c - > event_ctx ) ;
2005-11-19 02:34:47 +03:00
composite_continue ( c , creq , continue_resolve , c ) ;
2005-11-12 05:12:51 +03:00
return c ;
}
/*
receive a connect reply
*/
NTSTATUS smb2_connect_recv ( struct composite_context * c , TALLOC_CTX * mem_ctx ,
struct smb2_tree * * tree )
{
NTSTATUS status ;
struct smb2_connect_state * state = talloc_get_type ( c - > private_data ,
struct smb2_connect_state ) ;
status = composite_wait ( c ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
* tree = talloc_steal ( mem_ctx , state - > tree ) ;
}
talloc_free ( c ) ;
return status ;
}
/*
sync version of smb2_connect
*/
NTSTATUS smb2_connect ( TALLOC_CTX * mem_ctx ,
const char * host , const char * share ,
2007-12-10 20:41:19 +03:00
struct resolve_context * resolve_ctx ,
2005-11-12 05:12:51 +03:00
struct cli_credentials * credentials ,
struct smb2_tree * * tree ,
2008-05-30 11:03:54 +04:00
struct event_context * ev ,
struct smbcli_options * options )
2005-11-12 05:12:51 +03:00
{
struct composite_context * c = smb2_connect_send ( mem_ctx , host , share ,
2007-12-10 20:41:19 +03:00
resolve_ctx ,
2008-05-30 11:03:54 +04:00
credentials , ev , options ) ;
2005-11-12 05:12:51 +03:00
return smb2_connect_recv ( c , mem_ctx , tree ) ;
}