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
2011-07-18 16:26:31 +04:00
* Copyright ( C ) Andrew Bartlett 2011
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-07-21 19:02:59 +04:00
# include "rpc_server/rpc_pipes.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"
2011-05-31 15:33:05 +04:00
# include "rpc_contexts.h"
2011-08-10 23:34:37 +04:00
# include "rpc_server/rpc_config.h"
2010-06-04 00:04:08 +04:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_RPC_SRV
/****************************************************************************
Make an internal namedpipes structure
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct pipes_struct * make_internal_rpc_pipe_p ( TALLOC_CTX * mem_ctx ,
const struct ndr_syntax_id * syntax ,
2011-06-07 19:21:28 +04:00
const struct tsocket_address * remote_address ,
2011-07-18 07:06:47 +04:00
const struct auth_session_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 ;
2011-05-31 15:33:05 +04:00
struct pipe_rpc_fns * context_fns ;
2011-07-21 19:02:59 +04:00
const char * pipe_name ;
int ret ;
2010-06-04 00:04:08 +04:00
2011-07-21 19:02:59 +04:00
pipe_name = get_pipe_name_from_syntax ( talloc_tos ( ) , syntax ) ;
2010-06-04 00:04:08 +04:00
2011-07-21 19:02:59 +04:00
DEBUG ( 4 , ( " Create pipe requested %s \n " , pipe_name ) ) ;
2010-06-04 00:04:08 +04:00
2011-07-21 19:02:59 +04:00
ret = make_base_pipes_struct ( mem_ctx , msg_ctx , pipe_name ,
NCALRPC , RPC_LITTLE_ENDIAN , false ,
remote_address , NULL , & p ) ;
if ( ret ) {
2010-06-04 00:04:08 +04:00
DEBUG ( 0 , ( " ERROR! no memory for pipes_struct! \n " ) ) ;
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-07-15 06:45:17 +04:00
p - > session_info = copy_session_info ( p , session_info ) ;
2011-02-21 12:25:52 +03:00
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 ;
}
2011-07-28 00:40:21 +04:00
context_fns = talloc ( p , struct pipe_rpc_fns ) ;
2011-05-31 15:33:05 +04:00
if ( context_fns = = NULL ) {
2011-07-28 00:40:21 +04:00
DEBUG ( 0 , ( " talloc() failed! \n " ) ) ;
TALLOC_FREE ( p ) ;
return NULL ;
2011-05-31 15:33:05 +04:00
}
context_fns - > next = context_fns - > prev = NULL ;
context_fns - > n_cmds = rpc_srv_get_pipe_num_cmds ( syntax ) ;
context_fns - > cmds = rpc_srv_get_pipe_cmds ( syntax ) ;
context_fns - > context_id = 0 ;
context_fns - > syntax = * syntax ;
/* add to the list of open contexts */
DLIST_ADD ( p - > contexts , context_fns ) ;
2011-07-21 19:02:59 +04:00
DEBUG ( 4 , ( " Created internal pipe %s \n " , pipe_name ) ) ;
2010-06-04 00:04:08 +04:00
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 )
{
2011-05-31 15:33:05 +04:00
struct pipe_rpc_fns * fns = find_pipe_fns_by_context ( p - > contexts , 0 ) ;
uint32_t num_cmds = fns - > n_cmds ;
const struct api_struct * cmds = fns - > cmds ;
2010-08-07 16:37:21 +04:00
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 ) {
2012-06-27 17:21:11 +04:00
NTSTATUS status ;
2010-08-07 16:37:21 +04:00
2012-06-27 17:21:11 +04:00
status = NT_STATUS ( p - > fault_state ) ;
p - > fault_state = 0 ;
2010-08-07 16:37:21 +04:00
data_blob_free ( & p - > out_data . rdata ) ;
talloc_free_children ( p - > mem_ctx ) ;
2012-06-27 17:21:11 +04:00
return status ;
2010-08-07 16:37:21 +04:00
}
* 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 ) {
2011-09-14 19:57:37 +04:00
tevent_req_nterror ( req , NT_STATUS_CONNECTION_DISCONNECTED ) ;
2010-08-07 16:37:21 +04:00
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 ) {
2011-09-14 19:57:37 +04:00
tevent_req_nterror ( req , NT_STATUS_CONNECTION_DISCONNECTED ) ;
2010-08-07 16:37:21 +04:00
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 ,
2011-06-07 19:21:28 +04:00
const struct tsocket_address * remote_address ,
2011-07-18 07:06:47 +04:00
const struct auth_session_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 ,
2011-06-07 19:21:28 +04:00
remote_address ,
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 > .
*
2011-06-07 19:21:28 +04:00
* @ param [ in ] remote_address The info about the connected client .
2010-09-03 21:28:00 +04:00
*
* @ 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 ,
2011-06-07 19:21:28 +04:00
* p - > remote_address ,
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 ,
2011-06-07 19:21:28 +04:00
const struct tsocket_address * remote_address ,
2011-07-18 07:06:47 +04:00
const struct auth_session_info * session_info ,
2010-09-03 21:28:00 +04:00
struct messaging_context * msg_ctx ,
struct dcerpc_binding_handle * * binding_handle )
{
2011-06-07 19:21:28 +04:00
return rpcint_binding_handle_ex ( mem_ctx , NULL , ndr_table , remote_address ,
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-06-07 19:21:28 +04:00
* @ param [ in ] remote_address The client address information .
2011-03-29 14:51:45 +04:00
*
* @ 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-08-12 13:19:09 +04:00
NTSTATUS rpc_pipe_open_internal ( TALLOC_CTX * mem_ctx ,
2010-06-04 00:04:08 +04:00
const struct ndr_syntax_id * abstract_syntax ,
2011-07-18 07:06:47 +04:00
const struct auth_session_info * session_info ,
2011-06-07 19:21:28 +04:00
const struct tsocket_address * remote_address ,
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
2011-06-07 05:44:43 +04:00
result = talloc_zero ( mem_ctx , struct rpc_pipe_client ) ;
2010-06-04 00:04:08 +04:00
if ( result = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
result - > abstract_syntax = * abstract_syntax ;
2012-03-18 19:46:57 +04:00
result - > transfer_syntax = ndr_transfer_syntax_ndr ;
2010-06-04 00:04:08 +04:00
2011-06-07 19:21:28 +04:00
if ( remote_address = = NULL ) {
struct tsocket_address * local ;
int rc ;
rc = tsocket_address_inet_from_strings ( mem_ctx ,
" ip " ,
" 127.0.0.1 " ,
0 ,
& local ) ;
if ( rc < 0 ) {
TALLOC_FREE ( result ) ;
return NT_STATUS_NO_MEMORY ;
}
remote_address = local ;
2010-08-16 13:01:26 +04:00
}
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 ,
2011-06-07 19:21:28 +04:00
remote_address ,
2011-07-15 06:45:17 +04:00
session_info ,
2010-09-03 21:28:00 +04:00
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-07-18 07:06:47 +04:00
const struct auth_session_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 ;
2010-07-07 23:24:00 +04:00
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_t = talloc_zero ( talloc_tos ( ) , struct auth_session_info_transport ) ;
2011-07-18 07:10:30 +04:00
if ( session_info_t = = NULL ) {
2011-04-05 10:15:27 +04:00
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
goto fail ;
}
2011-07-21 19:58:41 +04:00
session_info_t - > session_info = copy_session_info ( session_info_t ,
session_info ) ;
if ( session_info_t - > session_info = = NULL ) {
DEBUG ( 0 , ( " copy_session_info failed \n " ) ) ;
goto fail ;
}
2011-04-05 10:15:27 +04:00
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 ) {
2012-10-20 13:08:19 +04:00
int l = 1 ;
if ( errno = = ENOENT ) {
l = 2 ;
}
DEBUG ( l , ( " tstream_npa_connect_recv to %s for pipe %s and "
2010-07-07 23:24:00 +04:00
" 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-07-18 07:06:47 +04:00
const struct auth_session_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 ;
2012-03-18 19:46:57 +04:00
result - > transfer_syntax = ndr_transfer_syntax_ndr ;
2010-07-07 23:24:00 +04:00
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-06-07 19:21:28 +04:00
* @ param [ in ] remote_address The client address information .
2011-05-12 00:38:46 +04:00
*
* @ 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 ,
2011-06-07 19:21:28 +04:00
* remote_address ,
2011-05-12 00:38:46 +04:00
* & 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-07-18 07:06:47 +04:00
const struct auth_session_info * session_info ,
2011-06-07 19:21:28 +04:00
const struct tsocket_address * remote_address ,
2010-07-07 23:24:00 +04:00
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 ;
2011-08-10 23:34:37 +04:00
enum rpc_service_mode_e pipe_mode ;
2010-07-07 23:24:00 +04:00
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
2012-12-17 20:46:34 +04:00
if ( cli_pipe ! = NULL ) {
if ( rpccli_is_connected ( * cli_pipe ) ) {
return NT_STATUS_OK ;
} else {
TALLOC_FREE ( * cli_pipe ) ;
}
2010-07-07 23:24:00 +04:00
}
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
2011-08-10 23:34:37 +04:00
pipe_mode = rpc_service_mode ( pipe_name ) ;
2010-09-16 12:49:39 +04:00
2011-08-10 23:34:37 +04:00
switch ( pipe_mode ) {
case RPC_SERVICE_MODE_EMBEDDED :
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 ,
2011-06-07 19:21:28 +04:00
remote_address , 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-08-10 23:34:37 +04:00
break ;
case RPC_SERVICE_MODE_EXTERNAL :
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-08-10 23:34:37 +04:00
break ;
case RPC_SERVICE_MODE_DISABLED :
2011-03-29 12:58:05 +04:00
status = NT_STATUS_NOT_IMPLEMENTED ;
2011-08-10 23:34:37 +04:00
DEBUG ( 0 , ( " Service pipe %s is disabled in config file: %s " ,
pipe_name , nt_errstr ( status ) ) ) ;
2011-03-29 12:58:05 +04:00
goto done ;
}
2010-07-07 23:24:00 +04:00
status = NT_STATUS_OK ;
done :
2012-12-17 20:46:34 +04:00
if ( NT_STATUS_IS_OK ( status ) & & cli_pipe ! = NULL ) {
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 ;
}