2010-06-04 00:04:08 +04:00
/*
* Unix SMB / CIFS implementation .
* RPC Pipe client / server routines
* Copyright ( C ) Andrew Tridgell 1992 - 1998 ,
* Largely re - written : 2005
* Copyright ( C ) Jeremy Allison 1998 - 2005
2010-07-07 23:24:00 +04:00
* Copyright ( C ) Simo Sorce 2010
2010-06-04 00:04:08 +04:00
*
* 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"
2011-02-28 12:19:44 +03:00
# include "rpc_client/cli_pipe.h"
2010-07-02 12:17:44 +04:00
# include "rpc_server/srv_pipe_internal.h"
2010-08-18 20:26:17 +04:00
# include "rpc_dce.h"
2010-07-07 23:24:00 +04:00
# include "../libcli/named_pipe_auth/npa_tstream.h"
# include "rpc_server/rpc_ncacn_np.h"
# include "librpc/gen_ndr/netlogon.h"
2011-02-09 06:22:16 +03:00
# include "librpc/gen_ndr/auth.h"
# include "../auth/auth_sam_reply.h"
2011-03-24 14:08:15 +03:00
# include "auth.h"
2011-03-25 00:33:07 +03:00
# include "ntdomain.h"
2011-04-28 19:26:40 +04:00
# include "../lib/tsocket/tsocket.h"
2011-04-28 19:38:09 +04:00
# include "../lib/util/tevent_ntstatus.h"
2010-06-04 00:04:08 +04:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_RPC_SRV
static int pipes_open ;
2010-07-28 13:06:36 +04:00
static struct pipes_struct * InternalPipes ;
2010-06-04 00:04:08 +04:00
/* TODO
* the following prototypes are declared here to avoid
* code being moved about too much for a patch to be
* disrupted / less obvious .
*
* these functions , and associated functions that they
* call , should be moved behind a . so module - loading
* system _anyway_ . so that ' s the next step . . .
*/
/****************************************************************************
Internal Pipe iterator functions .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-07-28 11:46:43 +04:00
struct pipes_struct * get_first_internal_pipe ( void )
2010-06-04 00:04:08 +04:00
{
return InternalPipes ;
}
2010-07-28 11:46:43 +04:00
struct pipes_struct * get_next_internal_pipe ( struct pipes_struct * p )
2010-06-04 00:04:08 +04:00
{
return p - > next ;
}
static void free_pipe_rpc_context_internal ( PIPE_RPC_FNS * list )
{
PIPE_RPC_FNS * tmp = list ;
PIPE_RPC_FNS * tmp2 ;
while ( tmp ) {
tmp2 = tmp - > next ;
SAFE_FREE ( tmp ) ;
tmp = tmp2 ;
}
return ;
}
2010-06-07 22:08:05 +04:00
bool check_open_pipes ( void )
{
2010-07-28 11:46:43 +04:00
struct pipes_struct * p ;
2010-06-07 22:08:05 +04:00
for ( p = InternalPipes ; p ! = NULL ; p = p - > next ) {
if ( num_pipe_handles ( p ) ! = 0 ) {
return true ;
}
}
return false ;
}
2010-06-04 00:04:08 +04:00
/****************************************************************************
Close an rpc pipe .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-06-07 23:18:31 +04:00
int close_internal_rpc_pipe_hnd ( struct pipes_struct * p )
2010-06-04 00:04:08 +04:00
{
if ( ! p ) {
DEBUG ( 0 , ( " Invalid pipe in close_internal_rpc_pipe_hnd \n " ) ) ;
return False ;
}
2010-09-04 00:33:45 +04:00
TALLOC_FREE ( p - > auth . auth_ctx ) ;
2010-06-04 00:04:08 +04:00
free_pipe_rpc_context_internal ( p - > contexts ) ;
/* Free the handles database. */
close_policy_by_pipe ( p ) ;
DLIST_REMOVE ( InternalPipes , p ) ;
ZERO_STRUCTP ( p ) ;
return 0 ;
}
/****************************************************************************
Make an internal namedpipes structure
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct pipes_struct * make_internal_rpc_pipe_p ( TALLOC_CTX * mem_ctx ,
const struct ndr_syntax_id * syntax ,
2010-08-16 13:01:26 +04:00
struct client_address * client_id ,
2011-02-21 12:25:52 +03:00
const struct auth_serversupplied_info * session_info ,
2010-08-08 11:08:40 +04:00
struct messaging_context * msg_ctx )
2010-06-04 00:04:08 +04:00
{
2010-07-28 11:46:43 +04:00
struct pipes_struct * p ;
2010-06-04 00:04:08 +04:00
DEBUG ( 4 , ( " Create pipe requested %s \n " ,
get_pipe_name_from_syntax ( talloc_tos ( ) , syntax ) ) ) ;
p = TALLOC_ZERO_P ( mem_ctx , struct pipes_struct ) ;
if ( ! p ) {
DEBUG ( 0 , ( " ERROR! no memory for pipes_struct! \n " ) ) ;
return NULL ;
}
p - > mem_ctx = talloc_named ( p , 0 , " pipe %s %p " ,
get_pipe_name_from_syntax ( talloc_tos ( ) ,
syntax ) , p ) ;
if ( p - > mem_ctx = = NULL ) {
DEBUG ( 0 , ( " open_rpc_pipe_p: talloc_init failed. \n " ) ) ;
TALLOC_FREE ( p ) ;
return NULL ;
}
2010-06-08 01:38:01 +04:00
if ( ! init_pipe_handles ( p , syntax ) ) {
2010-06-04 00:04:08 +04:00
DEBUG ( 0 , ( " open_rpc_pipe_p: init_pipe_handles failed. \n " ) ) ;
TALLOC_FREE ( p ) ;
return NULL ;
}
2011-02-21 12:25:52 +03:00
p - > session_info = copy_serverinfo ( p , session_info ) ;
if ( p - > session_info = = NULL ) {
2010-06-04 00:04:08 +04:00
DEBUG ( 0 , ( " open_rpc_pipe_p: copy_serverinfo failed \n " ) ) ;
close_policy_by_pipe ( p ) ;
TALLOC_FREE ( p ) ;
return NULL ;
}
2010-08-08 11:08:40 +04:00
p - > msg_ctx = msg_ctx ;
2010-07-07 00:52:19 +04:00
2010-06-04 00:04:08 +04:00
DLIST_ADD ( InternalPipes , p ) ;
2010-08-16 13:01:26 +04:00
p - > client_id = client_id ;
2010-06-04 00:04:08 +04:00
p - > endian = RPC_LITTLE_ENDIAN ;
p - > syntax = * syntax ;
2011-03-03 16:20:26 +03:00
p - > transport = NCALRPC ;
2010-06-04 00:04:08 +04:00
DEBUG ( 4 , ( " Created internal pipe %s (pipes_open=%d) \n " ,
get_pipe_name_from_syntax ( talloc_tos ( ) , syntax ) , pipes_open ) ) ;
talloc_set_destructor ( p , close_internal_rpc_pipe_hnd ) ;
return p ;
}
2010-08-07 16:37:21 +04:00
static NTSTATUS rpcint_dispatch ( struct pipes_struct * p ,
TALLOC_CTX * mem_ctx ,
uint32_t opnum ,
const DATA_BLOB * in_data ,
DATA_BLOB * out_data )
{
uint32_t num_cmds = rpc_srv_get_pipe_num_cmds ( & p - > syntax ) ;
const struct api_struct * cmds = rpc_srv_get_pipe_cmds ( & p - > syntax ) ;
uint32_t i ;
bool ok ;
/* set opnum */
p - > opnum = opnum ;
for ( i = 0 ; i < num_cmds ; i + + ) {
if ( cmds [ i ] . opnum = = opnum & & cmds [ i ] . fn ! = NULL ) {
break ;
}
}
if ( i = = num_cmds ) {
return NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE ;
}
p - > in_data . data = * in_data ;
p - > out_data . rdata = data_blob_null ;
ok = cmds [ i ] . fn ( p ) ;
p - > in_data . data = data_blob_null ;
if ( ! ok ) {
data_blob_free ( & p - > out_data . rdata ) ;
talloc_free_children ( p - > mem_ctx ) ;
return NT_STATUS_RPC_CALL_FAILED ;
}
if ( p - > fault_state ) {
p - > fault_state = false ;
data_blob_free ( & p - > out_data . rdata ) ;
talloc_free_children ( p - > mem_ctx ) ;
return NT_STATUS_RPC_CALL_FAILED ;
}
if ( p - > bad_handle_fault_state ) {
p - > bad_handle_fault_state = false ;
data_blob_free ( & p - > out_data . rdata ) ;
talloc_free_children ( p - > mem_ctx ) ;
return NT_STATUS_RPC_SS_CONTEXT_MISMATCH ;
}
if ( p - > rng_fault_state ) {
p - > rng_fault_state = false ;
data_blob_free ( & p - > out_data . rdata ) ;
talloc_free_children ( p - > mem_ctx ) ;
return NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE ;
}
* out_data = p - > out_data . rdata ;
talloc_steal ( mem_ctx , out_data - > data ) ;
p - > out_data . rdata = data_blob_null ;
talloc_free_children ( p - > mem_ctx ) ;
return NT_STATUS_OK ;
}
struct rpcint_bh_state {
struct pipes_struct * p ;
} ;
static bool rpcint_bh_is_connected ( struct dcerpc_binding_handle * h )
{
struct rpcint_bh_state * hs = dcerpc_binding_handle_data ( h ,
struct rpcint_bh_state ) ;
if ( ! hs - > p ) {
return false ;
}
return true ;
}
2010-09-03 22:05:39 +04:00
static uint32_t rpcint_bh_set_timeout ( struct dcerpc_binding_handle * h ,
uint32_t timeout )
{
/* TODO: implement timeouts */
return UINT32_MAX ;
}
2010-08-07 16:37:21 +04:00
struct rpcint_bh_raw_call_state {
DATA_BLOB in_data ;
DATA_BLOB out_data ;
uint32_t out_flags ;
} ;
static struct tevent_req * rpcint_bh_raw_call_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct dcerpc_binding_handle * h ,
const struct GUID * object ,
uint32_t opnum ,
uint32_t in_flags ,
const uint8_t * in_data ,
size_t in_length )
{
struct rpcint_bh_state * hs =
dcerpc_binding_handle_data ( h ,
struct rpcint_bh_state ) ;
struct tevent_req * req ;
struct rpcint_bh_raw_call_state * state ;
bool ok ;
NTSTATUS status ;
req = tevent_req_create ( mem_ctx , & state ,
struct rpcint_bh_raw_call_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > in_data . data = discard_const_p ( uint8_t , in_data ) ;
state - > in_data . length = in_length ;
ok = rpcint_bh_is_connected ( h ) ;
if ( ! ok ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_CONNECTION ) ;
return tevent_req_post ( req , ev ) ;
}
/* TODO: allow async */
status = rpcint_dispatch ( hs - > p , state , opnum ,
& state - > in_data ,
& state - > out_data ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
}
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
}
static NTSTATUS rpcint_bh_raw_call_recv ( struct tevent_req * req ,
TALLOC_CTX * mem_ctx ,
uint8_t * * out_data ,
size_t * out_length ,
uint32_t * out_flags )
{
struct rpcint_bh_raw_call_state * state =
tevent_req_data ( req ,
struct rpcint_bh_raw_call_state ) ;
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
tevent_req_received ( req ) ;
return status ;
}
* out_data = talloc_move ( mem_ctx , & state - > out_data . data ) ;
* out_length = state - > out_data . length ;
* out_flags = 0 ;
tevent_req_received ( req ) ;
return NT_STATUS_OK ;
}
struct rpcint_bh_disconnect_state {
uint8_t _dummy ;
} ;
static struct tevent_req * rpcint_bh_disconnect_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct dcerpc_binding_handle * h )
{
struct rpcint_bh_state * hs = dcerpc_binding_handle_data ( h ,
struct rpcint_bh_state ) ;
struct tevent_req * req ;
struct rpcint_bh_disconnect_state * state ;
bool ok ;
req = tevent_req_create ( mem_ctx , & state ,
struct rpcint_bh_disconnect_state ) ;
if ( req = = NULL ) {
return NULL ;
}
ok = rpcint_bh_is_connected ( h ) ;
if ( ! ok ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_CONNECTION ) ;
return tevent_req_post ( req , ev ) ;
}
/*
* TODO : do a real async disconnect . . .
*
* For now the caller needs to free pipes_struct
*/
hs - > p = NULL ;
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
}
static NTSTATUS rpcint_bh_disconnect_recv ( struct tevent_req * req )
{
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
tevent_req_received ( req ) ;
return status ;
}
tevent_req_received ( req ) ;
return NT_STATUS_OK ;
}
static bool rpcint_bh_ref_alloc ( struct dcerpc_binding_handle * h )
{
return true ;
}
static void rpcint_bh_do_ndr_print ( struct dcerpc_binding_handle * h ,
int ndr_flags ,
const void * _struct_ptr ,
const struct ndr_interface_call * call )
{
void * struct_ptr = discard_const ( _struct_ptr ) ;
2010-10-01 21:48:11 +04:00
if ( DEBUGLEVEL < 11 ) {
2010-08-07 16:37:21 +04:00
return ;
}
if ( ndr_flags & NDR_IN ) {
ndr_print_function_debug ( call - > ndr_print ,
call - > name ,
ndr_flags ,
struct_ptr ) ;
}
if ( ndr_flags & NDR_OUT ) {
ndr_print_function_debug ( call - > ndr_print ,
call - > name ,
ndr_flags ,
struct_ptr ) ;
}
}
static const struct dcerpc_binding_handle_ops rpcint_bh_ops = {
. name = " rpcint " ,
. is_connected = rpcint_bh_is_connected ,
2010-09-03 22:05:39 +04:00
. set_timeout = rpcint_bh_set_timeout ,
2010-08-07 16:37:21 +04:00
. raw_call_send = rpcint_bh_raw_call_send ,
. raw_call_recv = rpcint_bh_raw_call_recv ,
. disconnect_send = rpcint_bh_disconnect_send ,
. disconnect_recv = rpcint_bh_disconnect_recv ,
. ref_alloc = rpcint_bh_ref_alloc ,
. do_ndr_print = rpcint_bh_do_ndr_print ,
} ;
2010-09-03 21:28:00 +04:00
static NTSTATUS rpcint_binding_handle_ex ( TALLOC_CTX * mem_ctx ,
const struct ndr_syntax_id * abstract_syntax ,
const struct ndr_interface_table * ndr_table ,
struct client_address * client_id ,
2011-02-21 12:25:52 +03:00
const struct auth_serversupplied_info * session_info ,
2010-09-03 21:28:00 +04:00
struct messaging_context * msg_ctx ,
struct dcerpc_binding_handle * * binding_handle )
2010-08-07 16:37:21 +04:00
{
struct dcerpc_binding_handle * h ;
struct rpcint_bh_state * hs ;
2010-09-03 21:28:00 +04:00
if ( ndr_table ) {
abstract_syntax = & ndr_table - > syntax_id ;
}
h = dcerpc_binding_handle_create ( mem_ctx ,
2010-08-07 16:37:21 +04:00
& rpcint_bh_ops ,
NULL ,
2010-09-03 21:28:00 +04:00
ndr_table ,
2010-08-07 16:37:21 +04:00
& hs ,
struct rpcint_bh_state ,
__location__ ) ;
if ( h = = NULL ) {
2010-09-03 21:28:00 +04:00
return NT_STATUS_NO_MEMORY ;
}
hs - > p = make_internal_rpc_pipe_p ( hs ,
abstract_syntax ,
client_id ,
2011-02-21 12:25:52 +03:00
session_info ,
2010-09-03 21:28:00 +04:00
msg_ctx ) ;
if ( hs - > p = = NULL ) {
TALLOC_FREE ( h ) ;
return NT_STATUS_NO_MEMORY ;
2010-08-07 16:37:21 +04:00
}
2010-09-03 21:28:00 +04:00
* binding_handle = h ;
return NT_STATUS_OK ;
}
/**
* @ brief Create a new DCERPC Binding Handle which uses a local dispatch function .
*
* @ param [ in ] mem_ctx The memory context to use .
*
* @ param [ in ] ndr_table Normally the ndr_table_ < name > .
*
* @ param [ in ] client_id The info about the connected client .
*
* @ param [ in ] serversupplied_info The server supplied authentication function .
*
* @ param [ in ] msg_ctx The messaging context that can be used by the server
*
* @ param [ out ] binding_handle A pointer to store the connected
* dcerpc_binding_handle
*
* @ return NT_STATUS_OK on success , a corresponding NT status if an
* error occured .
*
* @ code
* struct dcerpc_binding_handle * winreg_binding ;
* NTSTATUS status ;
*
* status = rpcint_binding_handle ( tmp_ctx ,
* & ndr_table_winreg ,
* p - > client_id ,
2011-02-21 12:25:52 +03:00
* p - > session_info ,
2010-09-03 21:28:00 +04:00
* p - > msg_ctx
* & winreg_binding ) ;
* @ endcode
*/
NTSTATUS rpcint_binding_handle ( TALLOC_CTX * mem_ctx ,
const struct ndr_interface_table * ndr_table ,
struct client_address * client_id ,
2011-02-21 12:25:52 +03:00
const struct auth_serversupplied_info * session_info ,
2010-09-03 21:28:00 +04:00
struct messaging_context * msg_ctx ,
struct dcerpc_binding_handle * * binding_handle )
{
return rpcint_binding_handle_ex ( mem_ctx , NULL , ndr_table , client_id ,
2011-02-21 12:25:52 +03:00
session_info , msg_ctx , binding_handle ) ;
2010-08-07 16:37:21 +04:00
}
2010-06-04 00:04:08 +04:00
/**
2011-03-29 14:51:45 +04:00
* @ internal
*
* @ brief Create a new RPC client context which uses a local transport .
*
* This creates a local transport . It is a shortcut to directly call the server
2011-05-12 00:38:46 +04:00
* functions and avoid marshalling .
* NOTE : this function should be used only by rpc_pipe_open_interface ( )
2010-06-04 00:04:08 +04:00
*
* @ param [ in ] mem_ctx The memory context to use .
*
* @ param [ in ] abstract_syntax Normally the syntax_id of the autogenerated
* ndr_table_ < name > .
*
* @ param [ in ] serversupplied_info The server supplied authentication function .
*
2011-03-29 14:51:45 +04:00
* @ param [ in ] client_id The client address information .
*
* @ param [ in ] msg_ctx The messaging context to use .
*
2010-06-04 00:04:08 +04:00
* @ param [ out ] presult A pointer to store the connected rpc client pipe .
*
* @ return NT_STATUS_OK on success , a corresponding NT status if an
* error occured .
*/
2011-05-12 00:38:46 +04:00
static NTSTATUS rpc_pipe_open_internal ( TALLOC_CTX * mem_ctx ,
2010-06-04 00:04:08 +04:00
const struct ndr_syntax_id * abstract_syntax ,
2010-09-15 19:24:08 +04:00
const struct auth_serversupplied_info * serversupplied_info ,
2010-08-16 13:01:26 +04:00
struct client_address * client_id ,
2010-08-08 11:22:05 +04:00
struct messaging_context * msg_ctx ,
2010-06-04 00:04:08 +04:00
struct rpc_pipe_client * * presult )
{
struct rpc_pipe_client * result ;
2010-09-03 21:28:00 +04:00
NTSTATUS status ;
2010-06-04 00:04:08 +04:00
result = TALLOC_ZERO_P ( mem_ctx , struct rpc_pipe_client ) ;
if ( result = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
result - > abstract_syntax = * abstract_syntax ;
result - > transfer_syntax = ndr_transfer_syntax ;
2010-08-16 13:01:26 +04:00
if ( client_id = = NULL ) {
static struct client_address unknown ;
strlcpy ( unknown . addr , " <UNKNOWN> " , sizeof ( unknown . addr ) ) ;
unknown . name = " <UNKNOWN> " ;
client_id = & unknown ;
}
2010-06-04 00:04:08 +04:00
result - > max_xmit_frag = - 1 ;
result - > max_recv_frag = - 1 ;
2010-09-03 21:28:00 +04:00
status = rpcint_binding_handle_ex ( result ,
abstract_syntax ,
NULL ,
client_id ,
serversupplied_info ,
msg_ctx ,
& result - > binding_handle ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-08-07 16:37:21 +04:00
TALLOC_FREE ( result ) ;
2010-09-03 21:28:00 +04:00
return status ;
2010-08-07 16:37:21 +04:00
}
2010-06-04 00:04:08 +04:00
* presult = result ;
return NT_STATUS_OK ;
}
2010-07-07 23:24:00 +04:00
/****************************************************************************
* External pipes functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct np_proxy_state * make_external_rpc_pipe_p ( TALLOC_CTX * mem_ctx ,
const char * pipe_name ,
const struct tsocket_address * local_address ,
const struct tsocket_address * remote_address ,
2011-02-21 12:25:52 +03:00
const struct auth_serversupplied_info * session_info )
2010-07-07 23:24:00 +04:00
{
struct np_proxy_state * result ;
char * socket_np_dir ;
const char * socket_dir ;
struct tevent_context * ev ;
struct tevent_req * subreq ;
2011-02-21 12:25:52 +03:00
struct auth_session_info_transport * session_info_t ;
2011-04-05 10:15:27 +04:00
struct auth_session_info * session_info_npa ;
2011-02-09 06:22:16 +03:00
struct auth_user_info_dc * user_info_dc ;
union netr_Validation val ;
2010-07-07 23:24:00 +04:00
NTSTATUS status ;
bool ok ;
int ret ;
int sys_errno ;
result = talloc ( mem_ctx , struct np_proxy_state ) ;
if ( result = = NULL ) {
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
return NULL ;
}
2011-02-07 12:29:55 +03:00
result - > read_queue = tevent_queue_create ( result , " np_read " ) ;
if ( result - > read_queue = = NULL ) {
DEBUG ( 0 , ( " tevent_queue_create failed \n " ) ) ;
goto fail ;
}
result - > write_queue = tevent_queue_create ( result , " np_write " ) ;
if ( result - > write_queue = = NULL ) {
DEBUG ( 0 , ( " tevent_queue_create failed \n " ) ) ;
goto fail ;
}
2010-07-07 23:24:00 +04:00
ev = s3_tevent_context_init ( talloc_tos ( ) ) ;
if ( ev = = NULL ) {
DEBUG ( 0 , ( " s3_tevent_context_init failed \n " ) ) ;
goto fail ;
}
socket_dir = lp_parm_const_string (
GLOBAL_SECTION_SNUM , " external_rpc_pipe " , " socket_dir " ,
lp_ncalrpc_dir ( ) ) ;
if ( socket_dir = = NULL ) {
DEBUG ( 0 , ( " externan_rpc_pipe:socket_dir not set \n " ) ) ;
goto fail ;
}
socket_np_dir = talloc_asprintf ( talloc_tos ( ) , " %s/np " , socket_dir ) ;
if ( socket_np_dir = = NULL ) {
DEBUG ( 0 , ( " talloc_asprintf failed \n " ) ) ;
goto fail ;
}
2011-04-05 10:15:27 +04:00
session_info_npa = talloc_zero ( talloc_tos ( ) , struct auth_session_info ) ;
if ( session_info_npa = = NULL ) {
2010-07-07 23:24:00 +04:00
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
goto fail ;
}
2011-02-09 06:22:16 +03:00
/* Send the named_pipe_auth server the user's full token */
2011-04-05 10:15:27 +04:00
session_info_npa - > security_token = session_info - > security_token ;
session_info_npa - > session_key = session_info - > session_key ;
2011-02-09 06:22:16 +03:00
2011-02-21 12:25:52 +03:00
val . sam3 = session_info - > info3 ;
2011-02-09 06:22:16 +03:00
/* Convert into something we can build a struct
2011-04-05 10:15:27 +04:00
* auth_session_info from . Most of the work here
2011-02-09 06:22:16 +03:00
* will be to convert the SIDS , which we will then ignore , but
* this is the easier way to handle it */
status = make_user_info_dc_netlogon_validation ( talloc_tos ( ) , " " , 3 , & val , & user_info_dc ) ;
2010-07-07 23:24:00 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-02-09 06:22:16 +03:00
DEBUG ( 0 , ( " conversion of info3 into user_info_dc failed! \n " ) ) ;
2010-07-07 23:24:00 +04:00
goto fail ;
}
2011-04-05 10:15:27 +04:00
session_info_npa - > info = talloc_move ( session_info_npa , & user_info_dc - > info ) ;
2011-02-09 06:22:16 +03:00
talloc_free ( user_info_dc ) ;
2011-04-05 10:15:27 +04:00
session_info_t = talloc_zero ( talloc_tos ( ) , struct auth_session_info_transport ) ;
if ( session_info_npa = = NULL ) {
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
goto fail ;
}
session_info_t - > session_info = talloc_steal ( session_info_t , session_info_npa ) ;
2010-07-07 23:24:00 +04:00
become_root ( ) ;
subreq = tstream_npa_connect_send ( talloc_tos ( ) , ev ,
socket_np_dir ,
pipe_name ,
remote_address , /* client_addr */
NULL , /* client_name */
local_address , /* server_addr */
NULL , /* server_name */
2011-02-21 12:25:52 +03:00
session_info_t ) ;
2010-07-07 23:24:00 +04:00
if ( subreq = = NULL ) {
unbecome_root ( ) ;
DEBUG ( 0 , ( " tstream_npa_connect_send to %s for pipe %s and "
" user %s \\ %s failed \n " ,
2011-04-05 10:15:27 +04:00
socket_np_dir , pipe_name , session_info_t - > session_info - > info - > domain_name ,
session_info_t - > session_info - > info - > account_name ) ) ;
2010-07-07 23:24:00 +04:00
goto fail ;
}
ok = tevent_req_poll ( subreq , ev ) ;
unbecome_root ( ) ;
if ( ! ok ) {
DEBUG ( 0 , ( " tevent_req_poll to %s for pipe %s and user %s \\ %s "
" failed for tstream_npa_connect: %s \n " ,
2011-04-05 10:15:27 +04:00
socket_np_dir , pipe_name , session_info_t - > session_info - > info - > domain_name ,
session_info_t - > session_info - > info - > account_name ,
2010-07-07 23:24:00 +04:00
strerror ( errno ) ) ) ;
goto fail ;
}
ret = tstream_npa_connect_recv ( subreq , & sys_errno ,
result ,
& result - > npipe ,
& result - > file_type ,
& result - > device_state ,
& result - > allocation_size ) ;
TALLOC_FREE ( subreq ) ;
if ( ret ! = 0 ) {
DEBUG ( 0 , ( " tstream_npa_connect_recv to %s for pipe %s and "
" user %s \\ %s failed: %s \n " ,
2011-04-05 10:15:27 +04:00
socket_np_dir , pipe_name , session_info_t - > session_info - > info - > domain_name ,
session_info_t - > session_info - > info - > account_name ,
2010-07-07 23:24:00 +04:00
strerror ( sys_errno ) ) ) ;
goto fail ;
}
return result ;
fail :
TALLOC_FREE ( result ) ;
return NULL ;
}
static NTSTATUS rpc_pipe_open_external ( TALLOC_CTX * mem_ctx ,
const char * pipe_name ,
const struct ndr_syntax_id * abstract_syntax ,
2011-02-21 12:25:52 +03:00
const struct auth_serversupplied_info * session_info ,
2010-07-07 23:24:00 +04:00
struct rpc_pipe_client * * _result )
{
struct tsocket_address * local , * remote ;
struct rpc_pipe_client * result = NULL ;
struct np_proxy_state * proxy_state = NULL ;
struct pipe_auth_data * auth ;
NTSTATUS status ;
int ret ;
/* this is an internal connection, fake up ip addresses */
ret = tsocket_address_inet_from_strings ( talloc_tos ( ) , " ip " ,
NULL , 0 , & local ) ;
if ( ret ) {
return NT_STATUS_NO_MEMORY ;
}
ret = tsocket_address_inet_from_strings ( talloc_tos ( ) , " ip " ,
NULL , 0 , & remote ) ;
if ( ret ) {
return NT_STATUS_NO_MEMORY ;
}
proxy_state = make_external_rpc_pipe_p ( mem_ctx , pipe_name ,
2011-02-21 12:25:52 +03:00
local , remote , session_info ) ;
2010-07-07 23:24:00 +04:00
if ( ! proxy_state ) {
return NT_STATUS_UNSUCCESSFUL ;
}
result = talloc_zero ( mem_ctx , struct rpc_pipe_client ) ;
if ( result = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto done ;
}
result - > abstract_syntax = * abstract_syntax ;
result - > transfer_syntax = ndr_transfer_syntax ;
result - > desthost = get_myname ( result ) ;
result - > srv_name_slash = talloc_asprintf_strupper_m (
result , " \\ \\ %s " , result - > desthost ) ;
if ( ( result - > desthost = = NULL ) | | ( result - > srv_name_slash = = NULL ) ) {
status = NT_STATUS_NO_MEMORY ;
goto done ;
}
result - > max_xmit_frag = RPC_MAX_PDU_FRAG_LEN ;
result - > max_recv_frag = RPC_MAX_PDU_FRAG_LEN ;
status = rpc_transport_tstream_init ( result ,
2010-06-23 02:01:45 +04:00
& proxy_state - > npipe ,
2010-07-07 23:24:00 +04:00
& result - > transport ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto done ;
}
2011-02-09 08:56:25 +03:00
result - > binding_handle = rpccli_bh_create ( result ) ;
if ( result - > binding_handle = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
DEBUG ( 0 , ( " Failed to create binding handle. \n " ) ) ;
goto done ;
}
2010-07-07 23:24:00 +04:00
result - > auth = talloc_zero ( result , struct pipe_auth_data ) ;
if ( ! result - > auth ) {
status = NT_STATUS_NO_MEMORY ;
goto done ;
}
result - > auth - > auth_type = DCERPC_AUTH_TYPE_NONE ;
result - > auth - > auth_level = DCERPC_AUTH_LEVEL_NONE ;
status = rpccli_anon_bind_data ( result , & auth ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Failed to initialize anonymous bind. \n " ) ) ;
goto done ;
}
status = rpc_pipe_bind ( result , auth ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-02-09 08:56:25 +03:00
DEBUG ( 0 , ( " Failed to bind external pipe. \n " ) ) ;
2010-07-07 23:24:00 +04:00
goto done ;
}
2011-02-09 08:56:25 +03:00
2010-07-07 23:24:00 +04:00
done :
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( result ) ;
}
TALLOC_FREE ( proxy_state ) ;
* _result = result ;
return status ;
}
/**
2011-05-12 00:38:46 +04:00
* @ brief Create a new RPC client context which uses a local dispatch function
* or a remote transport , depending on rpc_server configuration for the
* specific service .
*
* @ param [ in ] mem_ctx The memory context to use .
*
* @ param [ in ] abstract_syntax Normally the syntax_id of the autogenerated
* ndr_table_ < name > .
*
* @ param [ in ] serversupplied_info The server supplied authentication function .
2010-07-07 23:24:00 +04:00
*
2011-05-12 00:38:46 +04:00
* @ param [ in ] client_id The client address information .
*
* @ param [ in ] msg_ctx The messaging context to use .
2010-07-07 23:24:00 +04:00
*
2011-05-12 00:38:46 +04:00
* @ param [ out ] presult A pointer to store the connected rpc client pipe .
*
* @ return NT_STATUS_OK on success , a corresponding NT status if an
* error occured .
*
* @ code
* struct rpc_pipe_client * winreg_pipe ;
* NTSTATUS status ;
*
* status = rpc_pipe_open_interface ( tmp_ctx ,
* & ndr_table_winreg . syntax_id ,
* p - > session_info ,
* client_id ,
* & winreg_pipe ) ;
* @ endcode
2010-07-07 23:24:00 +04:00
*/
NTSTATUS rpc_pipe_open_interface ( TALLOC_CTX * mem_ctx ,
const struct ndr_syntax_id * syntax ,
2011-02-21 12:25:52 +03:00
const struct auth_serversupplied_info * session_info ,
2010-07-07 23:24:00 +04:00
struct client_address * client_id ,
struct messaging_context * msg_ctx ,
struct rpc_pipe_client * * cli_pipe )
{
2010-09-15 13:38:53 +04:00
struct rpc_pipe_client * cli = NULL ;
2010-07-07 23:24:00 +04:00
const char * server_type ;
const char * pipe_name ;
NTSTATUS status ;
2010-09-15 13:38:53 +04:00
TALLOC_CTX * tmp_ctx ;
2010-07-07 23:24:00 +04:00
2010-09-15 13:38:53 +04:00
if ( cli_pipe & & rpccli_is_connected ( * cli_pipe ) ) {
2010-07-07 23:24:00 +04:00
return NT_STATUS_OK ;
} else {
TALLOC_FREE ( * cli_pipe ) ;
}
2010-09-15 13:38:53 +04:00
tmp_ctx = talloc_stackframe ( ) ;
if ( tmp_ctx = = NULL ) {
2010-07-07 23:24:00 +04:00
return NT_STATUS_NO_MEMORY ;
}
2010-09-15 13:38:53 +04:00
pipe_name = get_pipe_name_from_syntax ( tmp_ctx , syntax ) ;
if ( pipe_name = = NULL ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto done ;
2010-07-07 23:24:00 +04:00
}
2010-09-16 12:49:39 +04:00
while ( pipe_name [ 0 ] = = ' \\ ' ) {
pipe_name + + ;
}
DEBUG ( 5 , ( " Connecting to %s pipe. \n " , pipe_name ) ) ;
2010-07-07 23:24:00 +04:00
server_type = lp_parm_const_string ( GLOBAL_SECTION_SNUM ,
" rpc_server " , pipe_name ,
" embedded " ) ;
2010-09-16 12:49:39 +04:00
2011-05-13 22:21:30 +04:00
if ( strcasecmp_m ( server_type , " embedded " ) = = 0 ) {
2010-09-15 13:38:53 +04:00
status = rpc_pipe_open_internal ( tmp_ctx ,
2011-02-21 12:25:52 +03:00
syntax , session_info ,
2010-07-07 23:24:00 +04:00
client_id , msg_ctx ,
2010-09-15 13:38:53 +04:00
& cli ) ;
2010-07-07 23:24:00 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto done ;
}
2011-05-13 22:21:30 +04:00
} else if ( strcasecmp_m ( server_type , " daemon " ) = = 0 | |
strcasecmp_m ( server_type , " external " ) = = 0 ) {
2010-07-07 23:24:00 +04:00
/* It would be nice to just use rpc_pipe_open_ncalrpc() but
* for now we need to use the special proxy setup to connect
* to spoolssd . */
2010-09-15 13:38:53 +04:00
status = rpc_pipe_open_external ( tmp_ctx ,
2010-07-07 23:24:00 +04:00
pipe_name , syntax ,
2011-02-21 12:25:52 +03:00
session_info ,
2010-09-15 13:38:53 +04:00
& cli ) ;
2010-07-07 23:24:00 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto done ;
}
2011-03-29 12:58:05 +04:00
} else {
status = NT_STATUS_NOT_IMPLEMENTED ;
DEBUG ( 0 , ( " Wrong servertype specified in config file: %s " ,
nt_errstr ( status ) ) ) ;
goto done ;
}
2010-07-07 23:24:00 +04:00
status = NT_STATUS_OK ;
done :
if ( NT_STATUS_IS_OK ( status ) ) {
2010-09-15 13:38:53 +04:00
* cli_pipe = talloc_move ( mem_ctx , & cli ) ;
2010-07-07 23:24:00 +04:00
}
2010-09-15 13:38:53 +04:00
TALLOC_FREE ( tmp_ctx ) ;
2010-07-07 23:24:00 +04:00
return status ;
}