2005-01-16 01:28:11 +00:00
/*
Unix SMB / CIFS implementation .
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
the Free Software Foundation ; either version 2 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 , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
/*
a composite API for making a full SMB connection
*/
# include "includes.h"
# include "libcli/raw/libcliraw.h"
# include "libcli/composite/composite.h"
/* the stages of this call */
2005-01-21 11:18:56 +00:00
enum connect_stage { CONNECT_RESOLVE ,
CONNECT_SOCKET ,
2005-01-16 01:28:11 +00:00
CONNECT_SESSION_REQUEST ,
CONNECT_NEGPROT ,
CONNECT_SESSION_SETUP ,
CONNECT_TCON } ;
struct connect_state {
2005-01-22 02:51:39 +00:00
enum connect_stage stage ;
2005-01-16 01:28:11 +00:00
struct smbcli_socket * sock ;
struct smbcli_transport * transport ;
struct smbcli_session * session ;
2005-01-16 21:58:28 +00:00
struct smb_composite_connect * io ;
union smb_tcon * io_tcon ;
struct smb_composite_sesssetup * io_setup ;
2005-01-16 22:22:13 +00:00
struct smbcli_request * req ;
struct smbcli_composite * creq ;
2005-01-16 01:28:11 +00:00
} ;
static void request_handler ( struct smbcli_request * ) ;
static void composite_handler ( struct smbcli_composite * ) ;
/*
setup a negprot send
*/
static NTSTATUS connect_send_negprot ( struct smbcli_composite * c ,
struct smb_composite_connect * io )
{
2005-01-16 23:23:45 +00:00
struct connect_state * state = talloc_get_type ( c - > private , struct connect_state ) ;
2005-01-16 01:28:11 +00:00
2005-01-16 22:22:13 +00:00
state - > req = smb_raw_negotiate_send ( state - > transport , lp_maxprotocol ( ) ) ;
NT_STATUS_HAVE_NO_MEMORY ( state - > req ) ;
2005-01-16 01:28:11 +00:00
2005-01-16 22:22:13 +00:00
state - > req - > async . fn = request_handler ;
state - > req - > async . private = c ;
2005-01-22 02:51:39 +00:00
state - > stage = CONNECT_NEGPROT ;
2005-01-16 01:28:11 +00:00
return NT_STATUS_OK ;
}
/*
a tree connect request has competed
*/
static NTSTATUS connect_tcon ( struct smbcli_composite * c ,
struct smb_composite_connect * io )
{
2005-01-16 23:23:45 +00:00
struct connect_state * state = talloc_get_type ( c - > private , struct connect_state ) ;
2005-01-16 01:28:11 +00:00
NTSTATUS status ;
2005-01-16 22:22:13 +00:00
status = smb_tree_connect_recv ( state - > req , c , state - > io_tcon ) ;
2005-01-16 01:28:11 +00:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
2005-01-16 21:58:28 +00:00
io - > out . tree - > tid = state - > io_tcon - > tconx . out . tid ;
if ( state - > io_tcon - > tconx . out . dev_type ) {
2005-01-16 01:28:11 +00:00
io - > out . tree - > device = talloc_strdup ( io - > out . tree ,
2005-01-16 21:58:28 +00:00
state - > io_tcon - > tconx . out . dev_type ) ;
2005-01-16 01:28:11 +00:00
}
2005-01-16 21:58:28 +00:00
if ( state - > io_tcon - > tconx . out . fs_type ) {
2005-01-16 01:28:11 +00:00
io - > out . tree - > fs_type = talloc_strdup ( io - > out . tree ,
2005-01-16 21:58:28 +00:00
state - > io_tcon - > tconx . out . fs_type ) ;
2005-01-16 01:28:11 +00:00
}
/* all done! */
c - > state = SMBCLI_REQUEST_DONE ;
return NT_STATUS_OK ;
}
/*
a session setup request has competed
*/
static NTSTATUS connect_session_setup ( struct smbcli_composite * c ,
struct smb_composite_connect * io )
{
2005-01-16 23:23:45 +00:00
struct connect_state * state = talloc_get_type ( c - > private , struct connect_state ) ;
2005-01-16 01:28:11 +00:00
NTSTATUS status ;
2005-01-16 22:22:13 +00:00
status = smb_composite_sesssetup_recv ( state - > creq ) ;
2005-01-16 01:28:11 +00:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
2005-01-16 21:58:28 +00:00
state - > session - > vuid = state - > io_setup - > out . vuid ;
2005-01-16 01:28:11 +00:00
/* setup for a tconx */
2005-01-24 00:57:14 +00:00
io - > out . tree = smbcli_tree_init ( state - > session , state , True ) ;
2005-01-16 01:28:11 +00:00
NT_STATUS_HAVE_NO_MEMORY ( io - > out . tree ) ;
2005-01-16 21:58:28 +00:00
state - > io_tcon = talloc ( c , union smb_tcon ) ;
NT_STATUS_HAVE_NO_MEMORY ( state - > io_tcon ) ;
2005-01-16 01:28:11 +00:00
/* connect to a share using a tree connect */
2005-01-16 21:58:28 +00:00
state - > io_tcon - > generic . level = RAW_TCON_TCONX ;
state - > io_tcon - > tconx . in . flags = 0 ;
state - > io_tcon - > tconx . in . password = data_blob ( NULL , 0 ) ;
2005-01-16 01:28:11 +00:00
2005-01-16 21:58:28 +00:00
state - > io_tcon - > tconx . in . path = talloc_asprintf ( state - > io_tcon ,
2005-01-16 01:28:11 +00:00
" \\ \\ %s \\ %s " ,
io - > in . called_name ,
io - > in . service ) ;
2005-01-16 21:58:28 +00:00
NT_STATUS_HAVE_NO_MEMORY ( state - > io_tcon - > tconx . in . path ) ;
2005-01-16 01:28:11 +00:00
if ( ! io - > in . service_type ) {
2005-01-16 21:58:28 +00:00
state - > io_tcon - > tconx . in . device = " ????? " ;
2005-01-16 01:28:11 +00:00
} else {
2005-01-16 21:58:28 +00:00
state - > io_tcon - > tconx . in . device = io - > in . service_type ;
2005-01-16 01:28:11 +00:00
}
2005-01-16 22:22:13 +00:00
state - > req = smb_tree_connect_send ( io - > out . tree , state - > io_tcon ) ;
NT_STATUS_HAVE_NO_MEMORY ( state - > req ) ;
2005-01-16 01:28:11 +00:00
2005-01-16 22:22:13 +00:00
state - > req - > async . fn = request_handler ;
state - > req - > async . private = c ;
2005-01-22 02:51:39 +00:00
state - > stage = CONNECT_TCON ;
2005-01-16 01:28:11 +00:00
return NT_STATUS_OK ;
}
/*
a negprot request has competed
*/
static NTSTATUS connect_negprot ( struct smbcli_composite * c ,
struct smb_composite_connect * io )
{
2005-01-16 23:23:45 +00:00
struct connect_state * state = talloc_get_type ( c - > private , struct connect_state ) ;
2005-01-16 01:28:11 +00:00
NTSTATUS status ;
2005-01-16 22:22:13 +00:00
status = smb_raw_negotiate_recv ( state - > req ) ;
2005-01-16 01:28:11 +00:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
/* next step is a session setup */
2005-01-24 00:57:14 +00:00
state - > session = smbcli_session_init ( state - > transport , state , True ) ;
2005-01-16 01:28:11 +00:00
NT_STATUS_HAVE_NO_MEMORY ( state - > session ) ;
2005-01-16 21:58:28 +00:00
state - > io_setup = talloc ( c , struct smb_composite_sesssetup ) ;
NT_STATUS_HAVE_NO_MEMORY ( state - > io_setup ) ;
2005-01-16 01:28:11 +00:00
/* prepare a session setup to establish a security context */
2005-01-16 21:58:28 +00:00
state - > io_setup - > in . sesskey = state - > transport - > negotiate . sesskey ;
state - > io_setup - > in . capabilities = state - > transport - > negotiate . capabilities ;
state - > io_setup - > in . domain = io - > in . domain ;
state - > io_setup - > in . user = io - > in . user ;
state - > io_setup - > in . password = io - > in . password ;
2005-01-16 01:28:11 +00:00
2005-01-16 22:22:13 +00:00
state - > creq = smb_composite_sesssetup_send ( state - > session , state - > io_setup ) ;
NT_STATUS_HAVE_NO_MEMORY ( state - > creq ) ;
2005-01-16 01:28:11 +00:00
2005-01-16 22:22:13 +00:00
state - > creq - > async . fn = composite_handler ;
state - > creq - > async . private = c ;
2005-01-22 02:51:39 +00:00
state - > stage = CONNECT_SESSION_SETUP ;
2005-01-16 01:28:11 +00:00
return NT_STATUS_OK ;
}
/*
a session request operation has competed
*/
static NTSTATUS connect_session_request ( struct smbcli_composite * c ,
struct smb_composite_connect * io )
{
2005-01-16 23:23:45 +00:00
struct connect_state * state = talloc_get_type ( c - > private , struct connect_state ) ;
2005-01-16 01:28:11 +00:00
NTSTATUS status ;
2005-01-16 22:22:13 +00:00
status = smbcli_transport_connect_recv ( state - > req ) ;
2005-01-16 01:28:11 +00:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
/* next step is a negprot */
return connect_send_negprot ( c , io ) ;
}
/*
a socket connection operation has competed
*/
static NTSTATUS connect_socket ( struct smbcli_composite * c ,
struct smb_composite_connect * io )
{
2005-01-16 23:23:45 +00:00
struct connect_state * state = talloc_get_type ( c - > private , struct connect_state ) ;
2005-01-16 01:28:11 +00:00
NTSTATUS status ;
2005-01-21 11:18:56 +00:00
struct nbt_name calling , called ;
2005-01-16 01:28:11 +00:00
2005-01-16 22:22:13 +00:00
status = smbcli_sock_connect_recv ( state - > creq ) ;
2005-01-16 01:28:11 +00:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
/* the socket is up - we can initialise the smbcli transport layer */
2005-01-24 00:57:14 +00:00
state - > transport = smbcli_transport_init ( state - > sock , state , True ) ;
2005-01-16 01:28:11 +00:00
NT_STATUS_HAVE_NO_MEMORY ( state - > transport ) ;
2005-01-21 22:01:57 +00:00
calling . name = io - > in . calling_name ;
calling . type = NBT_NAME_CLIENT ;
calling . scope = NULL ;
nbt_choose_called_name ( state , & called , io - > in . called_name , NBT_NAME_SERVER ) ;
2005-01-16 01:28:11 +00:00
/* we have a connected socket - next step is a session
request , if needed . Port 445 doesn ' t need it , so it goes
straight to the negprot */
if ( state - > sock - > port = = 445 ) {
2005-01-21 22:01:57 +00:00
status = nbt_name_dup ( state - > transport , & called ,
& state - > transport - > called ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
2005-01-16 01:28:11 +00:00
return connect_send_negprot ( c , io ) ;
}
2005-01-16 22:22:13 +00:00
state - > req = smbcli_transport_connect_send ( state - > transport , & calling , & called ) ;
NT_STATUS_HAVE_NO_MEMORY ( state - > req ) ;
2005-01-16 01:28:11 +00:00
2005-01-16 22:22:13 +00:00
state - > req - > async . fn = request_handler ;
state - > req - > async . private = c ;
2005-01-22 02:51:39 +00:00
state - > stage = CONNECT_SESSION_REQUEST ;
2005-01-16 01:28:11 +00:00
return NT_STATUS_OK ;
}
2005-01-21 11:18:56 +00:00
/*
called when name resolution is finished
*/
static NTSTATUS connect_resolve ( struct smbcli_composite * c ,
struct smb_composite_connect * io )
{
struct connect_state * state = talloc_get_type ( c - > private , struct connect_state ) ;
NTSTATUS status ;
const char * address ;
status = resolve_name_recv ( state - > creq , state , & address ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
state - > creq = smbcli_sock_connect_send ( state - > sock , address , state - > io - > in . port ) ;
NT_STATUS_HAVE_NO_MEMORY ( state - > creq ) ;
2005-01-22 02:51:39 +00:00
state - > stage = CONNECT_SOCKET ;
2005-01-21 11:18:56 +00:00
state - > creq - > async . private = c ;
state - > creq - > async . fn = composite_handler ;
return NT_STATUS_OK ;
}
2005-01-16 01:28:11 +00:00
/*
handle and dispatch state transitions
*/
static void state_handler ( struct smbcli_composite * c )
{
2005-01-16 23:23:45 +00:00
struct connect_state * state = talloc_get_type ( c - > private , struct connect_state ) ;
2005-01-16 21:58:28 +00:00
2005-01-22 02:51:39 +00:00
switch ( state - > stage ) {
2005-01-21 11:18:56 +00:00
case CONNECT_RESOLVE :
2005-01-23 08:19:38 +00:00
c - > status = connect_resolve ( c , state - > io ) ;
2005-01-21 11:18:56 +00:00
break ;
2005-01-16 01:28:11 +00:00
case CONNECT_SOCKET :
2005-01-23 08:19:38 +00:00
c - > status = connect_socket ( c , state - > io ) ;
2005-01-16 01:28:11 +00:00
break ;
case CONNECT_SESSION_REQUEST :
2005-01-23 08:19:38 +00:00
c - > status = connect_session_request ( c , state - > io ) ;
2005-01-16 01:28:11 +00:00
break ;
case CONNECT_NEGPROT :
2005-01-23 08:19:38 +00:00
c - > status = connect_negprot ( c , state - > io ) ;
2005-01-16 01:28:11 +00:00
break ;
case CONNECT_SESSION_SETUP :
2005-01-23 08:19:38 +00:00
c - > status = connect_session_setup ( c , state - > io ) ;
2005-01-16 01:28:11 +00:00
break ;
case CONNECT_TCON :
2005-01-23 08:19:38 +00:00
c - > status = connect_tcon ( c , state - > io ) ;
2005-01-16 01:28:11 +00:00
break ;
}
2005-01-23 08:19:38 +00:00
if ( ! NT_STATUS_IS_OK ( c - > status ) ) {
2005-01-16 01:28:11 +00:00
c - > state = SMBCLI_REQUEST_ERROR ;
2005-01-23 08:19:38 +00:00
}
if ( c - > state > = SMBCLI_REQUEST_DONE & &
c - > async . fn ) {
c - > async . fn ( c ) ;
2005-01-16 01:28:11 +00:00
}
}
/*
handler for completion of a smbcli_request sub - request
*/
static void request_handler ( struct smbcli_request * req )
{
2005-01-17 04:08:24 +00:00
struct smbcli_composite * c = talloc_get_type ( req - > async . private ,
struct smbcli_composite ) ;
2005-01-16 01:28:11 +00:00
return state_handler ( c ) ;
}
/*
handler for completion of a smbcli_composite sub - request
*/
static void composite_handler ( struct smbcli_composite * req )
{
2005-01-17 04:08:24 +00:00
struct smbcli_composite * c = talloc_get_type ( req - > async . private ,
struct smbcli_composite ) ;
2005-01-16 01:28:11 +00:00
return state_handler ( c ) ;
}
/*
a function to establish a smbcli_tree from scratch
*/
2005-01-23 09:01:46 +00:00
struct smbcli_composite * smb_composite_connect_send ( struct smb_composite_connect * io ,
struct event_context * event_ctx )
2005-01-16 01:28:11 +00:00
{
2005-01-16 22:22:13 +00:00
struct smbcli_composite * c ;
2005-01-16 01:28:11 +00:00
struct connect_state * state ;
2005-01-21 11:18:56 +00:00
struct nbt_name name ;
2005-01-16 01:28:11 +00:00
c = talloc_zero ( NULL , struct smbcli_composite ) ;
if ( c = = NULL ) goto failed ;
state = talloc ( c , struct connect_state ) ;
if ( state = = NULL ) goto failed ;
2005-01-23 09:01:46 +00:00
state - > sock = smbcli_sock_init ( state , event_ctx ) ;
2005-01-16 01:28:11 +00:00
if ( state - > sock = = NULL ) goto failed ;
2005-01-16 21:58:28 +00:00
state - > io = io ;
2005-01-22 02:51:39 +00:00
state - > stage = CONNECT_RESOLVE ;
2005-01-16 21:58:28 +00:00
2005-01-16 01:28:11 +00:00
c - > state = SMBCLI_REQUEST_SEND ;
2005-01-23 09:01:46 +00:00
c - > event_ctx = talloc_reference ( c , state - > sock - > event . ctx ) ;
2005-01-16 01:28:11 +00:00
c - > private = state ;
2005-01-21 11:18:56 +00:00
name . name = io - > in . dest_host ;
name . type = NBT_NAME_SERVER ;
name . scope = NULL ;
state - > creq = resolve_name_send ( & name , c - > event_ctx ) ;
2005-01-16 22:22:13 +00:00
if ( state - > creq = = NULL ) goto failed ;
2005-01-16 01:28:11 +00:00
2005-01-16 22:22:13 +00:00
state - > creq - > async . private = c ;
state - > creq - > async . fn = composite_handler ;
2005-01-16 01:28:11 +00:00
return c ;
failed :
talloc_free ( c ) ;
return NULL ;
}
/*
recv half of async composite connect code
*/
NTSTATUS smb_composite_connect_recv ( struct smbcli_composite * c , TALLOC_CTX * mem_ctx )
{
NTSTATUS status ;
status = smb_composite_wait ( c ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
2005-01-16 23:23:45 +00:00
struct connect_state * state = talloc_get_type ( c - > private , struct connect_state ) ;
2005-01-16 21:58:28 +00:00
talloc_steal ( mem_ctx , state - > io - > out . tree ) ;
2005-01-16 01:28:11 +00:00
}
talloc_free ( c ) ;
return status ;
}
/*
sync version of smb_composite_connect
*/
NTSTATUS smb_composite_connect ( struct smb_composite_connect * io , TALLOC_CTX * mem_ctx )
{
2005-01-23 09:01:46 +00:00
struct smbcli_composite * c = smb_composite_connect_send ( io , NULL ) ;
2005-01-16 01:28:11 +00:00
return smb_composite_connect_recv ( c , mem_ctx ) ;
}