2007-07-16 15:27:29 +04:00
/*
Unix SMB / CIFS implementation .
dcerpc connect functions
Copyright ( C ) Andrew Tridgell 2003
Copyright ( C ) Jelmer Vernooij 2004
Copyright ( C ) Andrew Bartlett < abartlet @ samba . org > 2005 - 2007
Copyright ( C ) Rafal Szczesniak 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 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"
# include "libcli/composite/composite.h"
# include "lib/events/events.h"
# include "librpc/rpc/dcerpc.h"
2008-04-02 06:53:27 +04:00
# include "librpc/rpc/dcerpc_proto.h"
2007-07-16 15:27:29 +04:00
# include "auth/credentials/credentials.h"
2007-12-06 18:54:34 +03:00
# include "param/param.h"
2007-12-10 20:41:19 +03:00
# include "libcli/resolve/resolve.h"
2008-12-18 02:09:17 +03:00
# include "lib/socket/socket.h"
2007-07-16 15:27:29 +04:00
struct sec_conn_state {
struct dcerpc_pipe * pipe ;
struct dcerpc_pipe * pipe2 ;
struct dcerpc_binding * binding ;
2008-12-18 02:09:17 +03:00
struct socket_address * peer_addr ;
2007-07-16 15:27:29 +04:00
} ;
static void continue_open_smb ( struct composite_context * ctx ) ;
static void continue_open_tcp ( struct composite_context * ctx ) ;
static void continue_open_pipe ( struct composite_context * ctx ) ;
static void continue_pipe_open ( struct composite_context * c ) ;
/*
Send request to create a secondary dcerpc connection from a primary
connection
*/
2008-04-02 06:53:27 +04:00
_PUBLIC_ struct composite_context * dcerpc_secondary_connection_send ( struct dcerpc_pipe * p ,
2007-07-16 15:27:29 +04:00
struct dcerpc_binding * b )
{
struct composite_context * c ;
struct sec_conn_state * s ;
struct composite_context * pipe_smb_req ;
struct composite_context * pipe_tcp_req ;
struct composite_context * pipe_ncalrpc_req ;
/* composite context allocation and setup */
c = composite_create ( p , p - > conn - > event_ctx ) ;
if ( c = = NULL ) return NULL ;
s = talloc_zero ( c , struct sec_conn_state ) ;
if ( composite_nomem ( s , c ) ) return c ;
c - > private_data = s ;
s - > pipe = p ;
s - > binding = b ;
/* initialise second dcerpc pipe based on primary pipe's event context */
2010-05-09 19:20:01 +04:00
s - > pipe2 = dcerpc_pipe_init ( c , s - > pipe - > conn - > event_ctx ) ;
2007-07-16 15:27:29 +04:00
if ( composite_nomem ( s - > pipe2 , c ) ) return c ;
2008-11-02 02:26:04 +03:00
if ( DEBUGLEVEL > = 10 )
s - > pipe2 - > conn - > packet_log_dir = s - > pipe - > conn - > packet_log_dir ;
2007-07-16 15:27:29 +04:00
/* open second dcerpc pipe using the same transport as for primary pipe */
switch ( s - > pipe - > conn - > transport . transport ) {
case NCACN_NP :
2013-09-17 09:18:19 +04:00
pipe_smb_req = dcerpc_secondary_smb_send ( s - > pipe - > conn , s - > pipe2 ,
2007-07-16 15:27:29 +04:00
s - > binding - > endpoint ) ;
composite_continue ( c , pipe_smb_req , continue_open_smb , c ) ;
return c ;
case NCACN_IP_TCP :
2008-12-18 02:09:17 +03:00
s - > peer_addr = dcerpc_socket_peer_addr ( s - > pipe - > conn , s ) ;
if ( ! s - > peer_addr ) {
composite_error ( c , NT_STATUS_INVALID_PARAMETER ) ;
return c ;
}
2007-07-16 15:27:29 +04:00
pipe_tcp_req = dcerpc_pipe_open_tcp_send ( s - > pipe2 - > conn ,
2010-08-27 16:04:07 +04:00
s - > binding - > localaddress ,
2008-12-18 02:09:17 +03:00
s - > peer_addr - > addr ,
2007-07-16 15:27:29 +04:00
s - > binding - > target_hostname ,
2007-12-07 15:30:31 +03:00
atoi ( s - > binding - > endpoint ) ,
2008-12-18 02:09:17 +03:00
resolve_context_init ( s ) ) ;
2007-07-16 15:27:29 +04:00
composite_continue ( c , pipe_tcp_req , continue_open_tcp , c ) ;
return c ;
case NCALRPC :
2008-09-30 06:01:47 +04:00
case NCACN_UNIX_STREAM :
pipe_ncalrpc_req = dcerpc_pipe_open_unix_stream_send ( s - > pipe2 - > conn ,
dcerpc_unix_socket_path ( s - > pipe - > conn ) ) ;
2007-07-16 15:27:29 +04:00
composite_continue ( c , pipe_ncalrpc_req , continue_open_pipe , c ) ;
return c ;
default :
/* looks like a transport we don't support */
composite_error ( c , NT_STATUS_NOT_SUPPORTED ) ;
}
return c ;
}
/*
Stage 2 of secondary_connection : Receive result of pipe open request on smb
*/
static void continue_open_smb ( struct composite_context * ctx )
{
struct composite_context * c = talloc_get_type ( ctx - > async . private_data ,
struct composite_context ) ;
2013-09-17 09:18:19 +04:00
c - > status = dcerpc_secondary_smb_recv ( ctx ) ;
2007-07-16 15:27:29 +04:00
if ( ! composite_is_ok ( c ) ) return ;
continue_pipe_open ( c ) ;
}
/*
Stage 2 of secondary_connection : Receive result of pipe open request on tcp / ip
*/
static void continue_open_tcp ( struct composite_context * ctx )
{
struct composite_context * c = talloc_get_type ( ctx - > async . private_data ,
struct composite_context ) ;
c - > status = dcerpc_pipe_open_tcp_recv ( ctx ) ;
if ( ! composite_is_ok ( c ) ) return ;
continue_pipe_open ( c ) ;
}
/*
Stage 2 of secondary_connection : Receive result of pipe open request on ncalrpc
*/
static void continue_open_pipe ( struct composite_context * ctx )
{
struct composite_context * c = talloc_get_type ( ctx - > async . private_data ,
struct composite_context ) ;
c - > status = dcerpc_pipe_open_pipe_recv ( ctx ) ;
if ( ! composite_is_ok ( c ) ) return ;
continue_pipe_open ( c ) ;
}
/*
Stage 3 of secondary_connection : Get binding data and flags from primary pipe
and say if we ' re done ok .
*/
static void continue_pipe_open ( struct composite_context * c )
{
struct sec_conn_state * s ;
s = talloc_get_type ( c - > private_data , struct sec_conn_state ) ;
s - > pipe2 - > conn - > flags = s - > pipe - > conn - > flags ;
s - > pipe2 - > binding = s - > binding ;
if ( ! talloc_reference ( s - > pipe2 , s - > binding ) ) {
composite_error ( c , NT_STATUS_NO_MEMORY ) ;
return ;
}
composite_done ( c ) ;
}
/*
Receive result of secondary rpc connection request and return
second dcerpc pipe .
*/
2008-04-02 06:53:27 +04:00
_PUBLIC_ NTSTATUS dcerpc_secondary_connection_recv ( struct composite_context * c ,
2007-07-16 15:27:29 +04:00
struct dcerpc_pipe * * p2 )
{
NTSTATUS status = composite_wait ( c ) ;
struct sec_conn_state * s ;
s = talloc_get_type ( c - > private_data , struct sec_conn_state ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
* p2 = talloc_steal ( s - > pipe , s - > pipe2 ) ;
}
talloc_free ( c ) ;
return status ;
}
/*
Create a secondary dcerpc connection from a primary connection
- sync version
If the primary is a SMB connection then the secondary connection
will be on the same SMB connection , but using a new fnum
*/
2008-04-02 06:53:27 +04:00
_PUBLIC_ NTSTATUS dcerpc_secondary_connection ( struct dcerpc_pipe * p ,
2007-07-16 15:27:29 +04:00
struct dcerpc_pipe * * p2 ,
struct dcerpc_binding * b )
{
struct composite_context * c ;
c = dcerpc_secondary_connection_send ( p , b ) ;
return dcerpc_secondary_connection_recv ( c , p2 ) ;
}
/*
Create a secondary DCERPC connection , then bind ( and possibly
authenticate ) using the supplied credentials .
This creates a second connection , to the same host ( and on ncacn_np on the same connection ) as the first
*/
struct sec_auth_conn_state {
struct dcerpc_pipe * pipe2 ;
struct dcerpc_binding * binding ;
2007-08-20 00:46:45 +04:00
const struct ndr_interface_table * table ;
2007-07-16 15:27:29 +04:00
struct cli_credentials * credentials ;
struct composite_context * ctx ;
2007-12-07 04:37:04 +03:00
struct loadparm_context * lp_ctx ;
2007-07-16 15:27:29 +04:00
} ;
static void dcerpc_secondary_auth_connection_bind ( struct composite_context * ctx ) ;
static void dcerpc_secondary_auth_connection_continue ( struct composite_context * ctx ) ;
2008-04-02 06:53:27 +04:00
_PUBLIC_ struct composite_context * dcerpc_secondary_auth_connection_send ( struct dcerpc_pipe * p ,
2007-07-16 15:27:29 +04:00
struct dcerpc_binding * binding ,
2007-08-20 00:46:45 +04:00
const struct ndr_interface_table * table ,
2007-12-07 04:37:04 +03:00
struct cli_credentials * credentials ,
struct loadparm_context * lp_ctx )
2007-07-16 15:27:29 +04:00
{
struct composite_context * c , * secondary_conn_ctx ;
struct sec_auth_conn_state * s ;
/* composite context allocation and setup */
c = composite_create ( p , p - > conn - > event_ctx ) ;
if ( c = = NULL ) return NULL ;
s = talloc_zero ( c , struct sec_auth_conn_state ) ;
if ( composite_nomem ( s , c ) ) return c ;
c - > private_data = s ;
s - > ctx = c ;
s - > binding = binding ;
s - > table = table ;
s - > credentials = credentials ;
2007-12-07 04:37:04 +03:00
s - > lp_ctx = lp_ctx ;
2007-07-16 15:27:29 +04:00
secondary_conn_ctx = dcerpc_secondary_connection_send ( p , binding ) ;
if ( composite_nomem ( secondary_conn_ctx , s - > ctx ) ) {
talloc_free ( c ) ;
return NULL ;
}
composite_continue ( s - > ctx , secondary_conn_ctx , dcerpc_secondary_auth_connection_bind ,
s ) ;
return c ;
}
/*
Stage 2 of secondary_auth_connection :
Having made the secondary connection , we will need to do an ( authenticated ) bind
*/
static void dcerpc_secondary_auth_connection_bind ( struct composite_context * ctx )
{
struct composite_context * secondary_auth_ctx ;
struct sec_auth_conn_state * s = talloc_get_type ( ctx - > async . private_data ,
struct sec_auth_conn_state ) ;
s - > ctx - > status = dcerpc_secondary_connection_recv ( ctx , & s - > pipe2 ) ;
if ( ! composite_is_ok ( s - > ctx ) ) return ;
2007-12-07 04:37:04 +03:00
secondary_auth_ctx = dcerpc_pipe_auth_send ( s - > pipe2 , s - > binding , s - > table , s - > credentials ,
s - > lp_ctx ) ;
2007-07-16 15:27:29 +04:00
composite_continue ( s - > ctx , secondary_auth_ctx , dcerpc_secondary_auth_connection_continue , s ) ;
}
/*
Stage 3 of secondary_auth_connection : Receive result of authenticated bind request
*/
static void dcerpc_secondary_auth_connection_continue ( struct composite_context * ctx )
{
struct sec_auth_conn_state * s = talloc_get_type ( ctx - > async . private_data ,
struct sec_auth_conn_state ) ;
s - > ctx - > status = dcerpc_pipe_auth_recv ( ctx , s , & s - > pipe2 ) ;
if ( ! composite_is_ok ( s - > ctx ) ) return ;
composite_done ( s - > ctx ) ;
}
/*
Receive an authenticated pipe , created as a secondary connection
*/
2008-04-02 06:53:27 +04:00
_PUBLIC_ NTSTATUS dcerpc_secondary_auth_connection_recv ( struct composite_context * c ,
2007-07-16 15:27:29 +04:00
TALLOC_CTX * mem_ctx ,
struct dcerpc_pipe * * p )
{
NTSTATUS status = composite_wait ( c ) ;
struct sec_auth_conn_state * s ;
s = talloc_get_type ( c - > private_data , struct sec_auth_conn_state ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
* p = talloc_steal ( mem_ctx , s - > pipe2 ) ;
}
talloc_free ( c ) ;
return status ;
}