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/>.
*/
2024-09-19 00:35:20 +03:00
# define SOURCE4_LIBRPC_INTERNALS 1
2007-07-16 15:27:29 +04:00
# 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"
2014-02-14 04:08:31 +04:00
# include "lib/util/util_net.h"
2007-07-16 15:27:29 +04:00
struct sec_conn_state {
struct dcerpc_pipe * pipe ;
struct dcerpc_pipe * pipe2 ;
2014-02-13 19:28:54 +04:00
struct dcerpc_binding * binding ;
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 ) ;
2014-02-13 12:53:49 +04:00
static void continue_open_ncalrpc ( struct composite_context * ctx ) ;
static void continue_open_ncacn_unix ( struct composite_context * ctx ) ;
2007-07-16 15:27:29 +04:00
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 ,
2014-02-12 15:19:48 +04:00
const struct dcerpc_binding * b )
2007-07-16 15:27:29 +04:00
{
struct composite_context * c ;
struct sec_conn_state * s ;
struct composite_context * pipe_smb_req ;
struct composite_context * pipe_tcp_req ;
2014-02-14 04:08:31 +04:00
const char * localaddress = NULL ;
2007-07-16 15:27:29 +04:00
struct composite_context * pipe_ncalrpc_req ;
2014-02-13 12:53:49 +04:00
const char * ncalrpc_dir = NULL ;
struct composite_context * pipe_unix_req ;
2014-02-14 04:08:31 +04:00
const char * host ;
2014-02-04 13:03:09 +04:00
const char * target_hostname ;
2014-02-04 14:30:38 +04:00
const char * endpoint ;
2007-07-16 15:27:29 +04:00
/* 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 ;
2014-02-13 19:28:54 +04:00
s - > binding = dcerpc_binding_dup ( s , b ) ;
if ( composite_nomem ( s - > binding , c ) ) return c ;
2007-07-16 15:27:29 +04:00
/* 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 ;
2014-02-14 04:08:31 +04:00
host = dcerpc_binding_get_string_option ( s - > binding , " host " ) ;
if ( host = = NULL ) {
/*
* We may fallback to the host of the given connection
*/
host = dcerpc_binding_get_string_option ( s - > pipe - > binding ,
" host " ) ;
}
2014-02-04 13:03:09 +04:00
target_hostname = dcerpc_binding_get_string_option ( s - > binding , " target_hostname " ) ;
2014-02-14 04:08:31 +04:00
if ( target_hostname = = NULL ) {
/*
* We may fallback to the target_hostname of the given connection
*/
target_hostname = dcerpc_binding_get_string_option ( s - > pipe - > binding ,
" target_hostname " ) ;
}
2014-02-04 14:30:38 +04:00
endpoint = dcerpc_binding_get_string_option ( s - > binding , " endpoint " ) ;
if ( endpoint = = NULL ) {
/*
* We may fallback to the endpoint of the given connection
*/
endpoint = dcerpc_binding_get_string_option ( s - > pipe - > binding , " endpoint " ) ;
}
if ( endpoint = = NULL ) {
composite_error ( c , NT_STATUS_INVALID_PARAMETER_MIX ) ;
return c ;
}
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 :
2014-02-04 14:30:38 +04:00
pipe_smb_req = dcerpc_secondary_smb_send ( s - > pipe - > conn ,
s - > pipe2 - > conn ,
endpoint ) ;
2007-07-16 15:27:29 +04:00
composite_continue ( c , pipe_smb_req , continue_open_smb , c ) ;
return c ;
case NCACN_IP_TCP :
2014-02-14 04:08:31 +04:00
if ( host = = NULL ) {
composite_error ( c , NT_STATUS_INVALID_PARAMETER_MIX ) ;
2008-12-18 02:09:17 +03:00
return c ;
}
2014-02-14 04:08:31 +04:00
if ( ! is_ipaddress ( host ) ) {
/*
* We may fallback to the host of the given connection
*/
host = dcerpc_binding_get_string_option ( s - > pipe - > binding ,
" host " ) ;
if ( host = = NULL ) {
composite_error ( c , NT_STATUS_INVALID_PARAMETER_MIX ) ;
return c ;
}
if ( ! is_ipaddress ( host ) ) {
composite_error ( c , NT_STATUS_INVALID_PARAMETER_MIX ) ;
return c ;
}
}
localaddress = dcerpc_binding_get_string_option ( s - > binding ,
2014-01-16 18:39:55 +04:00
" localaddress " ) ;
2014-02-14 04:08:31 +04:00
if ( localaddress = = NULL ) {
/*
* We may fallback to the localaddress of the given connection
*/
localaddress = dcerpc_binding_get_string_option ( s - > pipe - > binding ,
" localaddress " ) ;
}
2014-01-16 18:39:55 +04:00
2007-07-16 15:27:29 +04:00
pipe_tcp_req = dcerpc_pipe_open_tcp_send ( s - > pipe2 - > conn ,
2014-02-14 04:08:31 +04:00
localaddress ,
host ,
2014-02-04 13:03:09 +04:00
target_hostname ,
2014-02-04 14:30:38 +04:00
atoi ( 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 :
2014-02-13 12:53:49 +04:00
ncalrpc_dir = dcerpc_binding_get_string_option ( s - > binding ,
" ncalrpc_dir " ) ;
if ( ncalrpc_dir = = NULL ) {
ncalrpc_dir = dcerpc_binding_get_string_option ( s - > pipe - > binding ,
" ncalrpc_dir " ) ;
}
if ( ncalrpc_dir = = NULL ) {
composite_error ( c , NT_STATUS_INVALID_PARAMETER_MIX ) ;
return c ;
}
pipe_ncalrpc_req = dcerpc_pipe_open_pipe_send ( s - > pipe2 - > conn ,
ncalrpc_dir ,
endpoint ) ;
composite_continue ( c , pipe_ncalrpc_req , continue_open_ncalrpc , c ) ;
return c ;
2008-09-30 06:01:47 +04:00
case NCACN_UNIX_STREAM :
2014-02-13 12:53:49 +04:00
pipe_unix_req = dcerpc_pipe_open_unix_stream_send ( s - > pipe2 - > conn ,
endpoint ) ;
composite_continue ( c , pipe_unix_req , continue_open_ncacn_unix , c ) ;
2007-07-16 15:27:29 +04:00
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 ) ;
2014-02-13 19:28:54 +04:00
struct sec_conn_state * s = talloc_get_type_abort ( c - > private_data ,
struct sec_conn_state ) ;
char * localaddr = NULL ;
char * remoteaddr = NULL ;
2014-02-13 19:27:22 +04:00
2014-02-13 19:28:54 +04:00
c - > status = dcerpc_pipe_open_tcp_recv ( ctx , s , & localaddr , & remoteaddr ) ;
if ( ! composite_is_ok ( c ) ) return ;
c - > status = dcerpc_binding_set_string_option ( s - > binding ,
" localaddress " ,
localaddr ) ;
if ( ! composite_is_ok ( c ) ) return ;
c - > status = dcerpc_binding_set_string_option ( s - > binding ,
" host " ,
remoteaddr ) ;
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 ncalrpc
*/
2014-02-13 12:53:49 +04:00
static void continue_open_ncalrpc ( 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 2 of secondary_connection : Receive result of pipe open request on ncacn_unix
*/
static void continue_open_ncacn_unix ( struct composite_context * ctx )
2007-07-16 15:27:29 +04:00
{
struct composite_context * c = talloc_get_type ( ctx - > async . private_data ,
struct composite_context ) ;
2014-02-04 14:06:21 +04:00
c - > status = dcerpc_pipe_open_unix_stream_recv ( ctx ) ;
2007-07-16 15:27:29 +04:00
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 ;
2013-09-19 20:23:37 +04:00
s - > pipe2 - > binding = dcerpc_binding_dup ( s - > pipe2 , s - > binding ) ;
if ( composite_nomem ( s - > pipe2 - > binding , c ) ) {
2007-07-16 15:27:29 +04:00
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 , 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 ;
2014-02-12 15:19:48 +04:00
const 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 ,
2014-02-12 15:19:48 +04:00
const 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 ;
}
2014-01-17 12:31:51 +04:00
_PUBLIC_ NTSTATUS dcerpc_secondary_auth_connection ( struct dcerpc_pipe * p ,
const struct dcerpc_binding * binding ,
const struct ndr_interface_table * table ,
struct cli_credentials * credentials ,
struct loadparm_context * lp_ctx ,
TALLOC_CTX * mem_ctx ,
struct dcerpc_pipe * * p2 )
{
struct composite_context * c ;
c = dcerpc_secondary_auth_connection_send ( p , binding , table ,
credentials , lp_ctx ) ;
return dcerpc_secondary_auth_connection_recv ( c , mem_ctx , p2 ) ;
}