2009-01-22 20:34:06 +03:00
/*
* Unix SMB / CIFS implementation .
* RPC client transport over named pipes
* Copyright ( C ) Volker Lendecke 2009
*
* 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"
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_RPC_CLI
struct rpc_transport_np_state {
struct cli_state * cli ;
const char * pipe_name ;
uint16_t fnum ;
} ;
static int rpc_transport_np_state_destructor ( struct rpc_transport_np_state * s )
{
bool ret ;
ret = cli_close ( s - > cli , s - > fnum ) ;
if ( ! ret ) {
DEBUG ( 1 , ( " rpc_transport_np_state_destructor: cli_close "
" failed on pipe %s. Error was %s \n " , s - > pipe_name ,
cli_errstr ( s - > cli ) ) ) ;
}
DEBUG ( 10 , ( " rpc_pipe_destructor: closed %s \n " , s - > pipe_name ) ) ;
/*
* We can ' t do much on failure
*/
return 0 ;
}
struct rpc_np_write_state {
size_t size ;
size_t written ;
} ;
2009-03-29 15:28:18 +04:00
static void rpc_np_write_done ( struct tevent_req * subreq ) ;
2009-01-22 20:34:06 +03:00
2009-03-24 01:20:03 +03:00
static struct tevent_req * rpc_np_write_send ( TALLOC_CTX * mem_ctx ,
struct event_context * ev ,
const uint8_t * data , size_t size ,
void * priv )
2009-01-22 20:34:06 +03:00
{
struct rpc_transport_np_state * np_transport = talloc_get_type_abort (
priv , struct rpc_transport_np_state ) ;
2009-03-29 15:28:18 +04:00
struct tevent_req * req , * subreq ;
2009-01-22 20:34:06 +03:00
struct rpc_np_write_state * state ;
2009-03-24 01:20:03 +03:00
req = tevent_req_create ( mem_ctx , & state , struct rpc_np_write_state ) ;
if ( req = = NULL ) {
2009-01-22 20:34:06 +03:00
return NULL ;
}
state - > size = size ;
subreq = cli_write_andx_send ( mem_ctx , ev , np_transport - > cli ,
np_transport - > fnum ,
8 , /* 8 means message mode. */
data , 0 , size ) ;
2009-03-29 15:28:18 +04:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
2009-01-22 20:34:06 +03:00
}
2009-03-29 15:28:18 +04:00
tevent_req_set_callback ( subreq , rpc_np_write_done , req ) ;
2009-03-24 01:20:03 +03:00
return req ;
2009-01-22 20:34:06 +03:00
}
2009-03-29 15:28:18 +04:00
static void rpc_np_write_done ( struct tevent_req * subreq )
2009-01-22 20:34:06 +03:00
{
2009-03-29 15:28:18 +04:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
2009-03-24 01:20:03 +03:00
struct rpc_np_write_state * state = tevent_req_data (
req , struct rpc_np_write_state ) ;
2009-01-22 20:34:06 +03:00
NTSTATUS status ;
status = cli_write_andx_recv ( subreq , & state - > written ) ;
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-03-24 01:20:03 +03:00
tevent_req_nterror ( req , status ) ;
2009-01-22 20:34:06 +03:00
return ;
}
2009-03-24 01:20:03 +03:00
tevent_req_done ( req ) ;
2009-01-22 20:34:06 +03:00
}
2009-03-24 01:20:03 +03:00
static NTSTATUS rpc_np_write_recv ( struct tevent_req * req , ssize_t * pwritten )
2009-01-22 20:34:06 +03:00
{
2009-03-24 01:20:03 +03:00
struct rpc_np_write_state * state = tevent_req_data (
req , struct rpc_np_write_state ) ;
2009-01-22 20:34:06 +03:00
NTSTATUS status ;
2009-03-24 01:20:03 +03:00
if ( tevent_req_is_nterror ( req , & status ) ) {
2009-01-22 20:34:06 +03:00
return status ;
}
* pwritten = state - > written ;
return NT_STATUS_OK ;
}
struct rpc_np_read_state {
uint8_t * data ;
size_t size ;
ssize_t received ;
} ;
2009-03-15 11:54:23 +03:00
static void rpc_np_read_done ( struct tevent_req * subreq ) ;
2009-01-22 20:34:06 +03:00
2009-03-24 01:03:37 +03:00
static struct tevent_req * rpc_np_read_send ( TALLOC_CTX * mem_ctx ,
struct event_context * ev ,
uint8_t * data , size_t size ,
void * priv )
2009-01-22 20:34:06 +03:00
{
struct rpc_transport_np_state * np_transport = talloc_get_type_abort (
priv , struct rpc_transport_np_state ) ;
2009-03-15 11:54:23 +03:00
struct tevent_req * req , * subreq ;
2009-01-22 20:34:06 +03:00
struct rpc_np_read_state * state ;
2009-03-24 01:03:37 +03:00
req = tevent_req_create ( mem_ctx , & state , struct rpc_np_read_state ) ;
if ( req = = NULL ) {
2009-01-22 20:34:06 +03:00
return NULL ;
}
state - > data = data ;
state - > size = size ;
subreq = cli_read_andx_send ( mem_ctx , ev , np_transport - > cli ,
np_transport - > fnum , 0 , size ) ;
if ( subreq = = NULL ) {
goto fail ;
}
2009-03-15 11:54:23 +03:00
tevent_req_set_callback ( subreq , rpc_np_read_done , req ) ;
2009-03-24 01:03:37 +03:00
return req ;
2009-01-22 20:34:06 +03:00
fail :
2009-03-24 01:03:37 +03:00
TALLOC_FREE ( req ) ;
2009-01-22 20:34:06 +03:00
return NULL ;
}
2009-03-15 11:54:23 +03:00
static void rpc_np_read_done ( struct tevent_req * subreq )
2009-01-22 20:34:06 +03:00
{
2009-03-15 11:54:23 +03:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
2009-03-24 01:03:37 +03:00
struct rpc_np_read_state * state = tevent_req_data (
req , struct rpc_np_read_state ) ;
2009-01-22 20:34:06 +03:00
NTSTATUS status ;
uint8_t * rcvbuf ;
status = cli_read_andx_recv ( subreq , & state - > received , & rcvbuf ) ;
/*
* We can ' t TALLOC_FREE ( subreq ) as usual here , as rcvbuf still is a
* child of that .
*/
if ( NT_STATUS_EQUAL ( status , NT_STATUS_BUFFER_TOO_SMALL ) ) {
status = NT_STATUS_OK ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( subreq ) ;
2009-03-24 01:03:37 +03:00
tevent_req_nterror ( req , status ) ;
2009-01-22 20:34:06 +03:00
return ;
}
if ( state - > received > state - > size ) {
TALLOC_FREE ( subreq ) ;
2009-03-24 01:03:37 +03:00
tevent_req_nterror ( req , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
2009-01-22 20:34:06 +03:00
return ;
}
memcpy ( state - > data , rcvbuf , state - > received ) ;
2009-03-24 01:03:37 +03:00
tevent_req_done ( req ) ;
2009-01-22 20:34:06 +03:00
}
2009-03-24 01:03:37 +03:00
static NTSTATUS rpc_np_read_recv ( struct tevent_req * req , ssize_t * preceived )
2009-01-22 20:34:06 +03:00
{
2009-03-24 01:03:37 +03:00
struct rpc_np_read_state * state = tevent_req_data (
req , struct rpc_np_read_state ) ;
2009-01-22 20:34:06 +03:00
NTSTATUS status ;
2009-03-24 01:03:37 +03:00
if ( tevent_req_is_nterror ( req , & status ) ) {
2009-01-22 20:34:06 +03:00
return status ;
}
* preceived = state - > received ;
return NT_STATUS_OK ;
}
struct rpc_np_trans_state {
uint16_t setup [ 2 ] ;
uint8_t * rdata ;
uint32_t rdata_len ;
} ;
2009-04-05 22:51:52 +04:00
static void rpc_np_trans_done ( struct tevent_req * subreq ) ;
2009-01-22 20:34:06 +03:00
2009-03-24 01:30:18 +03:00
static struct tevent_req * rpc_np_trans_send ( TALLOC_CTX * mem_ctx ,
struct event_context * ev ,
uint8_t * data , size_t data_len ,
uint32_t max_rdata_len ,
void * priv )
2009-01-22 20:34:06 +03:00
{
struct rpc_transport_np_state * np_transport = talloc_get_type_abort (
priv , struct rpc_transport_np_state ) ;
2009-04-05 22:51:52 +04:00
struct tevent_req * req , * subreq ;
2009-01-22 20:34:06 +03:00
struct rpc_np_trans_state * state ;
2009-03-24 01:30:18 +03:00
req = tevent_req_create ( mem_ctx , & state , struct rpc_np_trans_state ) ;
if ( req = = NULL ) {
2009-01-22 20:34:06 +03:00
return NULL ;
}
SSVAL ( state - > setup + 0 , 0 , TRANSACT_DCERPCCMD ) ;
SSVAL ( state - > setup + 1 , 0 , np_transport - > fnum ) ;
subreq = cli_trans_send (
state , ev , np_transport - > cli , SMBtrans ,
" \\ PIPE \\ " , 0 , 0 , 0 , state - > setup , 2 , 0 ,
NULL , 0 , 0 , data , data_len , max_rdata_len ) ;
if ( subreq = = NULL ) {
goto fail ;
}
2009-04-05 22:51:52 +04:00
tevent_req_set_callback ( subreq , rpc_np_trans_done , req ) ;
2009-03-24 01:30:18 +03:00
return req ;
2009-01-22 20:34:06 +03:00
fail :
2009-03-24 01:30:18 +03:00
TALLOC_FREE ( req ) ;
2009-01-22 20:34:06 +03:00
return NULL ;
}
2009-04-05 22:51:52 +04:00
static void rpc_np_trans_done ( struct tevent_req * subreq )
2009-01-22 20:34:06 +03:00
{
2009-04-05 22:51:52 +04:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
2009-03-24 01:30:18 +03:00
struct rpc_np_trans_state * state = tevent_req_data (
req , struct rpc_np_trans_state ) ;
2009-01-22 20:34:06 +03:00
NTSTATUS status ;
status = cli_trans_recv ( subreq , state , NULL , NULL , NULL , NULL ,
& state - > rdata , & state - > rdata_len ) ;
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-03-24 01:30:18 +03:00
tevent_req_nterror ( req , status ) ;
2009-01-22 20:34:06 +03:00
return ;
}
2009-03-24 01:30:18 +03:00
tevent_req_done ( req ) ;
2009-01-22 20:34:06 +03:00
}
2009-03-24 01:30:18 +03:00
static NTSTATUS rpc_np_trans_recv ( struct tevent_req * req , TALLOC_CTX * mem_ctx ,
2009-01-22 20:34:06 +03:00
uint8_t * * prdata , uint32_t * prdata_len )
{
2009-03-24 01:30:18 +03:00
struct rpc_np_trans_state * state = tevent_req_data (
req , struct rpc_np_trans_state ) ;
2009-01-22 20:34:06 +03:00
NTSTATUS status ;
2009-03-24 01:30:18 +03:00
if ( tevent_req_is_nterror ( req , & status ) ) {
2009-01-22 20:34:06 +03:00
return status ;
}
* prdata = talloc_move ( mem_ctx , & state - > rdata ) ;
* prdata_len = state - > rdata_len ;
return NT_STATUS_OK ;
}
2009-01-30 00:41:33 +03:00
struct rpc_transport_np_init_state {
struct rpc_cli_transport * transport ;
struct rpc_transport_np_state * transport_np ;
} ;
2009-03-29 22:00:58 +04:00
static void rpc_transport_np_init_pipe_open ( struct tevent_req * subreq ) ;
2009-01-30 00:41:33 +03:00
struct async_req * rpc_transport_np_init_send ( TALLOC_CTX * mem_ctx ,
struct event_context * ev ,
struct cli_state * cli ,
const struct ndr_syntax_id * abstract_syntax )
2009-01-22 20:34:06 +03:00
{
2009-03-29 22:00:58 +04:00
struct async_req * result ;
struct tevent_req * subreq ;
2009-01-30 00:41:33 +03:00
struct rpc_transport_np_init_state * state ;
2009-01-22 20:34:06 +03:00
2009-01-30 00:41:33 +03:00
if ( ! async_req_setup ( mem_ctx , & result , & state ,
struct rpc_transport_np_init_state ) ) {
return NULL ;
2009-01-22 20:34:06 +03:00
}
2009-01-30 00:41:33 +03:00
state - > transport = talloc ( state , struct rpc_cli_transport ) ;
if ( state - > transport = = NULL ) {
goto fail ;
}
state - > transport_np = talloc ( state - > transport ,
struct rpc_transport_np_state ) ;
if ( state - > transport_np = = NULL ) {
goto fail ;
2009-01-22 20:34:06 +03:00
}
2009-01-30 00:41:33 +03:00
state - > transport - > priv = state - > transport_np ;
2009-01-22 20:34:06 +03:00
2009-02-01 02:30:04 +03:00
state - > transport_np - > pipe_name = get_pipe_name_from_iface (
abstract_syntax ) ;
2009-01-30 00:41:33 +03:00
state - > transport_np - > cli = cli ;
subreq = cli_ntcreate_send (
state , ev , cli , state - > transport_np - > pipe_name , 0 ,
DESIRED_ACCESS_PIPE , 0 , FILE_SHARE_READ | FILE_SHARE_WRITE ,
FILE_OPEN , 0 , 0 ) ;
if ( subreq = = NULL ) {
goto fail ;
}
2009-03-29 22:00:58 +04:00
tevent_req_set_callback ( subreq , rpc_transport_np_init_pipe_open ,
result ) ;
2009-01-30 00:41:33 +03:00
return result ;
fail :
TALLOC_FREE ( result ) ;
return NULL ;
}
2009-03-29 22:00:58 +04:00
static void rpc_transport_np_init_pipe_open ( struct tevent_req * subreq )
2009-01-30 00:41:33 +03:00
{
2009-03-29 22:00:58 +04:00
struct async_req * req = tevent_req_callback_data (
subreq , struct async_req ) ;
2009-01-30 00:41:33 +03:00
struct rpc_transport_np_init_state * state = talloc_get_type_abort (
req - > private_data , struct rpc_transport_np_init_state ) ;
NTSTATUS status ;
status = cli_ntcreate_recv ( subreq , & state - > transport_np - > fnum ) ;
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-02-01 18:32:02 +03:00
async_req_nterror ( req , status ) ;
2009-01-30 00:41:33 +03:00
return ;
}
talloc_set_destructor ( state - > transport_np ,
rpc_transport_np_state_destructor ) ;
async_req_done ( req ) ;
}
NTSTATUS rpc_transport_np_init_recv ( struct async_req * req ,
TALLOC_CTX * mem_ctx ,
struct rpc_cli_transport * * presult )
{
struct rpc_transport_np_init_state * state = talloc_get_type_abort (
req - > private_data , struct rpc_transport_np_init_state ) ;
NTSTATUS status ;
2009-01-22 20:34:06 +03:00
2009-02-01 18:32:02 +03:00
if ( async_req_is_nterror ( req , & status ) ) {
2009-01-30 00:41:33 +03:00
return status ;
2009-01-22 20:34:06 +03:00
}
2009-01-30 00:41:33 +03:00
state - > transport - > write_send = rpc_np_write_send ;
state - > transport - > write_recv = rpc_np_write_recv ;
state - > transport - > read_send = rpc_np_read_send ;
state - > transport - > read_recv = rpc_np_read_recv ;
state - > transport - > trans_send = rpc_np_trans_send ;
state - > transport - > trans_recv = rpc_np_trans_recv ;
2009-01-22 20:34:06 +03:00
2009-01-30 00:41:33 +03:00
* presult = talloc_move ( mem_ctx , & state - > transport ) ;
2009-01-22 20:34:06 +03:00
return NT_STATUS_OK ;
}
2009-01-30 00:41:33 +03:00
NTSTATUS rpc_transport_np_init ( TALLOC_CTX * mem_ctx , struct cli_state * cli ,
const struct ndr_syntax_id * abstract_syntax ,
struct rpc_cli_transport * * presult )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct event_context * ev ;
struct async_req * req ;
NTSTATUS status ;
ev = event_context_init ( frame ) ;
if ( ev = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
req = rpc_transport_np_init_send ( frame , ev , cli , abstract_syntax ) ;
if ( req = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
while ( req - > state < ASYNC_REQ_DONE ) {
event_loop_once ( ev ) ;
}
status = rpc_transport_np_init_recv ( req , mem_ctx , presult ) ;
fail :
TALLOC_FREE ( frame ) ;
return status ;
}
2009-01-22 20:34:06 +03:00
struct cli_state * rpc_pipe_np_smb_conn ( struct rpc_pipe_client * p )
{
struct rpc_transport_np_state * state = talloc_get_type (
p - > transport - > priv , struct rpc_transport_np_state ) ;
if ( state = = NULL ) {
return NULL ;
}
return state - > cli ;
}