2010-06-18 19:00:38 +04:00
/*
Unix SMB / Netbios implementation .
Generic infrstructure for RPC Daemons
Copyright ( C ) Simo Sorce 2010
2011-07-18 16:26:31 +04:00
Copyright ( C ) Andrew Bartlett 2011
2011-07-21 15:13:35 +04:00
Copyright ( C ) Andreas Schneider 2011
2010-06-18 19:00:38 +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-07-21 19:02:59 +04:00
# include "rpc_server/rpc_pipes.h"
2010-06-18 19:00:38 +04:00
# include "rpc_server/rpc_server.h"
2010-06-18 18:40:19 +04:00
# include "rpc_dce.h"
# include "librpc/gen_ndr/netlogon.h"
2011-02-09 06:22:16 +03:00
# include "librpc/gen_ndr/auth.h"
2010-06-18 18:55:44 +04:00
# include "lib/tsocket/tsocket.h"
2010-06-18 18:56:58 +04:00
# include "libcli/named_pipe_auth/npa_tstream.h"
2011-02-09 06:22:16 +03:00
# include "../auth/auth_sam_reply.h"
2011-03-24 14:08:15 +03:00
# include "auth.h"
2011-04-29 18:40:24 +04:00
# include "rpc_server/rpc_ncacn_np.h"
2011-04-30 01:32:28 +04:00
# include "rpc_server/srv_pipe_hnd.h"
2011-05-02 15:27:45 +04:00
# include "rpc_server/srv_pipe.h"
2010-06-18 18:40:19 +04:00
2011-02-14 12:29:14 +03:00
# define SERVER_TCP_LOW_PORT 1024
# define SERVER_TCP_HIGH_PORT 1300
2011-08-10 23:02:24 +04:00
/* the default is "embedded" so this table
* lists only daemons that are not using
* the default in order to keep enumerating it
* in rpc_daemon_type ( ) as short as possible
*/
struct rpc_daemon_defaults {
const char * name ;
const char * def_type ;
} rpc_daemon_defaults [ ] = {
{ " epmd " , " fork " } ,
/* { "spoolssd", "embedded" }, */
/* { "lsasd", "embedded" }, */
{ NULL , NULL }
} ;
enum rpc_daemon_type_e rpc_daemon_type ( const char * name )
{
const char * rpcsrv_type ;
enum rpc_daemon_type_e type ;
const char * def ;
int i ;
def = " embedded " ;
for ( i = 0 ; rpc_daemon_defaults [ i ] . name ; i + + ) {
if ( strcasecmp_m ( name , rpc_daemon_defaults [ i ] . name ) = = 0 ) {
def = rpc_daemon_defaults [ i ] . def_type ;
}
}
rpcsrv_type = lp_parm_const_string ( GLOBAL_SECTION_SNUM ,
" rpc_daemon " , name , def ) ;
if ( strcasecmp_m ( rpcsrv_type , " embedded " ) = = 0 ) {
type = RPC_DAEMON_EMBEDDED ;
} else if ( strcasecmp_m ( rpcsrv_type , " fork " ) = = 0 ) {
type = RPC_DAEMON_FORK ;
} else {
type = RPC_DAEMON_DISABLED ;
}
return type ;
}
2011-02-14 12:29:14 +03:00
static NTSTATUS auth_anonymous_session_info ( TALLOC_CTX * mem_ctx ,
2011-04-05 10:15:27 +04:00
struct auth_session_info * * session_info )
2011-02-14 12:29:14 +03:00
{
NTSTATUS status ;
2011-07-18 07:10:30 +04:00
status = make_session_info_guest ( mem_ctx , session_info ) ;
2011-02-14 12:29:14 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
return NT_STATUS_OK ;
}
2010-06-18 18:40:19 +04:00
/* Creates a pipes_struct and initializes it with the information
* sent from the client */
static int make_server_pipes_struct ( TALLOC_CTX * mem_ctx ,
2011-07-21 12:43:56 +04:00
struct messaging_context * msg_ctx ,
2010-06-18 18:40:19 +04:00
const char * pipe_name ,
2011-03-03 16:20:26 +03:00
enum dcerpc_transport_t transport ,
2011-03-14 12:47:41 +03:00
bool ncalrpc_as_system ,
2011-06-07 19:03:13 +04:00
const struct tsocket_address * local_address ,
const struct tsocket_address * remote_address ,
2011-04-05 10:15:27 +04:00
struct auth_session_info * session_info ,
2010-06-18 18:40:19 +04:00
struct pipes_struct * * _p ,
int * perrno )
{
struct pipes_struct * p ;
NTSTATUS status ;
2011-07-21 19:02:59 +04:00
int ret ;
2011-07-21 21:54:01 +04:00
ret = make_base_pipes_struct ( mem_ctx , msg_ctx , pipe_name ,
2011-07-21 19:02:59 +04:00
transport , RPC_LITTLE_ENDIAN ,
ncalrpc_as_system ,
remote_address , local_address , & p ) ;
if ( ret ) {
* perrno = ret ;
2010-06-18 18:40:19 +04:00
return - 1 ;
}
2011-07-18 06:23:04 +04:00
if ( session_info - > unix_token & & session_info - > unix_info & & session_info - > security_token ) {
/* Don't call create_local_token(), we already have the full details here */
2011-07-18 07:10:30 +04:00
p - > session_info = talloc_steal ( p , session_info ) ;
2011-07-18 06:23:04 +04:00
} else {
2011-07-18 06:58:25 +04:00
struct auth_user_info_dc * auth_user_info_dc ;
2011-07-18 06:23:04 +04:00
struct auth_serversupplied_info * server_info ;
2011-07-18 06:58:25 +04:00
struct netr_SamInfo3 * info3 ;
/* Fake up an auth_user_info_dc for now, to make an info3, to make the session_info structure */
auth_user_info_dc = talloc_zero ( p , struct auth_user_info_dc ) ;
if ( ! auth_user_info_dc ) {
TALLOC_FREE ( p ) ;
* perrno = ENOMEM ;
return - 1 ;
}
auth_user_info_dc - > num_sids = session_info - > security_token - > num_sids ;
auth_user_info_dc - > sids = session_info - > security_token - > sids ;
auth_user_info_dc - > info = session_info - > info ;
auth_user_info_dc - > user_session_key = session_info - > session_key ;
/* This creates the input structure that make_server_info_info3 is looking for */
status = auth_convert_user_info_dc_saminfo3 ( p , auth_user_info_dc ,
& info3 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " Failed to convert auth_user_info_dc into netr_SamInfo3 \n " ) ) ;
TALLOC_FREE ( p ) ;
* perrno = EINVAL ;
return - 1 ;
}
2011-07-18 06:23:04 +04:00
status = make_server_info_info3 ( p ,
info3 - > base . account_name . string ,
info3 - > base . domain . string ,
& server_info , info3 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " Failed to init server info \n " ) ) ;
TALLOC_FREE ( p ) ;
* perrno = EINVAL ;
return - 1 ;
}
2010-06-18 18:40:19 +04:00
2011-07-18 06:23:04 +04:00
/*
* Some internal functions need a local token to determine access to
* resources .
*/
2011-07-26 07:37:36 +04:00
status = create_local_token ( p , server_info , & session_info - > session_key , info3 - > base . account_name . string ,
& p - > session_info ) ;
2011-07-18 06:23:04 +04:00
talloc_free ( server_info ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " Failed to init local auth token \n " ) ) ;
TALLOC_FREE ( p ) ;
* perrno = EINVAL ;
return - 1 ;
}
2010-06-18 18:40:19 +04:00
}
* _p = p ;
return 0 ;
}
2010-06-18 18:55:44 +04:00
/* Start listening on the appropriate unix socket and setup all is needed to
* dispatch requests to the pipes rpc implementation */
2010-06-18 19:00:38 +04:00
2011-02-15 14:57:26 +03:00
struct dcerpc_ncacn_listen_state {
2011-02-14 12:29:14 +03:00
struct ndr_syntax_id syntax_id ;
2010-06-18 19:00:38 +04:00
int fd ;
2011-02-15 14:57:26 +03:00
union {
char * name ;
uint16_t port ;
} ep ;
2011-02-14 12:29:14 +03:00
struct tevent_context * ev_ctx ;
struct messaging_context * msg_ctx ;
2011-03-14 14:29:49 +03:00
dcerpc_ncacn_disconnect_fn disconnect_fn ;
2010-06-18 19:00:38 +04:00
} ;
static void named_pipe_listener ( struct tevent_context * ev ,
struct tevent_fd * fde ,
uint16_t flags ,
2010-05-20 17:16:29 +04:00
void * private_data ) ;
2010-06-18 19:00:38 +04:00
2011-04-21 23:05:12 +04:00
int create_named_pipe_socket ( const char * pipe_name )
2010-06-18 19:00:38 +04:00
{
2011-04-21 23:05:12 +04:00
char * np_dir = NULL ;
int fd = - 1 ;
2011-07-18 13:42:43 +04:00
2011-05-17 12:32:38 +04:00
/*
* As lp_ncalrpc_dir ( ) should have 0755 , but
* lp_ncalrpc_dir ( ) / np should have 0700 , we need to
* create lp_ncalrpc_dir ( ) first .
*/
if ( ! directory_create_or_exist ( lp_ncalrpc_dir ( ) , geteuid ( ) , 0755 ) ) {
DEBUG ( 0 , ( " Failed to create pipe directory %s - %s \n " ,
lp_ncalrpc_dir ( ) , strerror ( errno ) ) ) ;
goto out ;
}
2011-04-21 23:05:12 +04:00
np_dir = talloc_asprintf ( talloc_tos ( ) , " %s/np " , lp_ncalrpc_dir ( ) ) ;
2010-06-18 19:00:38 +04:00
if ( ! np_dir ) {
DEBUG ( 0 , ( " Out of memory \n " ) ) ;
goto out ;
}
2011-05-17 12:31:14 +04:00
if ( ! directory_create_or_exist ( np_dir , geteuid ( ) , 0700 ) ) {
DEBUG ( 0 , ( " Failed to create pipe directory %s - %s \n " ,
np_dir , strerror ( errno ) ) ) ;
goto out ;
}
2011-04-21 23:05:12 +04:00
fd = create_pipe_sock ( np_dir , pipe_name , 0700 ) ;
if ( fd = = - 1 ) {
2010-06-18 19:00:38 +04:00
DEBUG ( 0 , ( " Failed to create pipe socket! [%s/%s] \n " ,
np_dir , pipe_name ) ) ;
goto out ;
}
2011-04-21 23:05:12 +04:00
DEBUG ( 10 , ( " Openened pipe socket fd %d for %s \n " , fd , pipe_name ) ) ;
out :
2011-07-21 13:11:51 +04:00
talloc_free ( np_dir ) ;
2011-04-21 23:05:12 +04:00
return fd ;
}
bool setup_named_pipe_socket ( const char * pipe_name ,
struct tevent_context * ev_ctx ,
struct messaging_context * msg_ctx )
{
struct dcerpc_ncacn_listen_state * state ;
struct tevent_fd * fde ;
state = talloc ( ev_ctx , struct dcerpc_ncacn_listen_state ) ;
if ( ! state ) {
DEBUG ( 0 , ( " Out of memory \n " ) ) ;
return false ;
}
state - > ep . name = talloc_strdup ( state , pipe_name ) ;
if ( state - > ep . name = = NULL ) {
DEBUG ( 0 , ( " Out of memory \n " ) ) ;
goto out ;
}
state - > fd = create_named_pipe_socket ( pipe_name ) ;
if ( state - > fd = = - 1 ) {
goto out ;
}
state - > ev_ctx = ev_ctx ;
state - > msg_ctx = msg_ctx ;
2010-06-18 19:00:38 +04:00
DEBUG ( 10 , ( " Openened pipe socket fd %d for %s \n " ,
state - > fd , pipe_name ) ) ;
fde = tevent_add_fd ( ev_ctx ,
state , state - > fd , TEVENT_FD_READ ,
named_pipe_listener , state ) ;
if ( ! fde ) {
DEBUG ( 0 , ( " Failed to add event handler! \n " ) ) ;
goto out ;
}
tevent_fd_set_auto_close ( fde ) ;
return true ;
out :
if ( state - > fd ! = - 1 ) {
close ( state - > fd ) ;
}
TALLOC_FREE ( state ) ;
return false ;
}
2010-05-20 17:16:29 +04:00
static void named_pipe_listener ( struct tevent_context * ev ,
struct tevent_fd * fde ,
uint16_t flags ,
void * private_data )
{
2011-02-15 14:57:26 +03:00
struct dcerpc_ncacn_listen_state * state =
2010-05-20 17:16:29 +04:00
talloc_get_type_abort ( private_data ,
2011-02-15 14:57:26 +03:00
struct dcerpc_ncacn_listen_state ) ;
2010-05-20 17:16:29 +04:00
struct sockaddr_un sunaddr ;
socklen_t len ;
int sd = - 1 ;
/* TODO: should we have a limit to the number of clients ? */
len = sizeof ( sunaddr ) ;
2011-03-03 17:06:45 +03:00
sd = accept ( state - > fd ,
( struct sockaddr * ) ( void * ) & sunaddr , & len ) ;
2010-05-20 17:16:29 +04:00
if ( sd = = - 1 ) {
2011-03-03 17:06:45 +03:00
if ( errno ! = EINTR ) {
DEBUG ( 6 , ( " Failed to get a valid socket [%s] \n " ,
strerror ( errno ) ) ) ;
}
2010-05-20 17:16:29 +04:00
return ;
}
DEBUG ( 6 , ( " Accepted socket %d \n " , sd ) ) ;
2011-07-08 13:38:03 +04:00
named_pipe_accept_function ( state - > ev_ctx ,
state - > msg_ctx ,
state - > ep . name ,
2011-04-26 01:24:15 +04:00
sd , NULL , 0 ) ;
2010-05-20 17:16:29 +04:00
}
2010-06-18 18:56:58 +04:00
/* This is the core of the rpc server.
* Accepts connections from clients and process requests using the appropriate
* dispatcher table . */
struct named_pipe_client {
const char * pipe_name ;
struct tevent_context * ev ;
2011-02-09 16:21:24 +03:00
struct messaging_context * msg_ctx ;
2010-06-18 18:56:58 +04:00
uint16_t file_type ;
uint16_t device_state ;
uint64_t allocation_size ;
struct tstream_context * tstream ;
struct tsocket_address * client ;
char * client_name ;
struct tsocket_address * server ;
char * server_name ;
2011-06-07 19:03:13 +04:00
2011-04-05 10:15:27 +04:00
struct auth_session_info * session_info ;
2010-06-18 18:56:58 +04:00
struct pipes_struct * p ;
struct tevent_queue * write_queue ;
struct iovec * iov ;
size_t count ;
2011-04-26 01:24:15 +04:00
named_pipe_termination_fn * term_fn ;
void * private_data ;
2010-06-18 18:56:58 +04:00
} ;
2011-04-26 01:24:15 +04:00
static int named_pipe_destructor ( struct named_pipe_client * npc )
{
if ( npc - > term_fn ) {
npc - > term_fn ( npc - > private_data ) ;
}
return 0 ;
}
2010-06-18 18:56:58 +04:00
static void named_pipe_accept_done ( struct tevent_req * subreq ) ;
2011-04-21 23:05:12 +04:00
void named_pipe_accept_function ( struct tevent_context * ev_ctx ,
struct messaging_context * msg_ctx ,
2011-04-26 01:24:15 +04:00
const char * pipe_name , int fd ,
named_pipe_termination_fn * term_fn ,
void * private_data )
2010-05-20 17:16:29 +04:00
{
2010-06-18 18:56:58 +04:00
struct named_pipe_client * npc ;
struct tstream_context * plain ;
struct tevent_req * subreq ;
int ret ;
2011-07-26 14:07:20 +04:00
npc = talloc_zero ( ev_ctx , struct named_pipe_client ) ;
2010-06-18 18:56:58 +04:00
if ( ! npc ) {
DEBUG ( 0 , ( " Out of memory! \n " ) ) ;
close ( fd ) ;
return ;
}
2011-07-21 13:21:30 +04:00
npc - > pipe_name = talloc_strdup ( npc , pipe_name ) ;
if ( npc - > pipe_name = = NULL ) {
DEBUG ( 0 , ( " Out of memory! \n " ) ) ;
TALLOC_FREE ( npc ) ;
close ( fd ) ;
return ;
}
2011-07-08 13:38:03 +04:00
npc - > ev = ev_ctx ;
npc - > msg_ctx = msg_ctx ;
2011-04-26 01:24:15 +04:00
npc - > term_fn = term_fn ;
npc - > private_data = private_data ;
talloc_set_destructor ( npc , named_pipe_destructor ) ;
2010-06-18 18:56:58 +04:00
/* make sure socket is in NON blocking state */
ret = set_blocking ( fd , false ) ;
if ( ret ! = 0 ) {
DEBUG ( 2 , ( " Failed to make socket non-blocking \n " ) ) ;
TALLOC_FREE ( npc ) ;
close ( fd ) ;
return ;
}
ret = tstream_bsd_existing_socket ( npc , fd , & plain ) ;
if ( ret ! = 0 ) {
DEBUG ( 2 , ( " Failed to create tstream socket \n " ) ) ;
TALLOC_FREE ( npc ) ;
close ( fd ) ;
return ;
}
npc - > file_type = FILE_TYPE_MESSAGE_MODE_PIPE ;
npc - > device_state = 0xff | 0x0400 | 0x0100 ;
npc - > allocation_size = 4096 ;
subreq = tstream_npa_accept_existing_send ( npc , npc - > ev , plain ,
npc - > file_type ,
npc - > device_state ,
npc - > allocation_size ) ;
if ( ! subreq ) {
DEBUG ( 2 , ( " Failed to start async accept procedure \n " ) ) ;
TALLOC_FREE ( npc ) ;
close ( fd ) ;
return ;
}
tevent_req_set_callback ( subreq , named_pipe_accept_done , npc ) ;
}
static void named_pipe_packet_process ( struct tevent_req * subreq ) ;
static void named_pipe_packet_done ( struct tevent_req * subreq ) ;
static void named_pipe_accept_done ( struct tevent_req * subreq )
{
2011-04-05 10:15:27 +04:00
struct auth_session_info_transport * session_info_transport ;
2010-06-18 18:56:58 +04:00
struct named_pipe_client * npc =
tevent_req_callback_data ( subreq , struct named_pipe_client ) ;
int error ;
int ret ;
ret = tstream_npa_accept_existing_recv ( subreq , & error , npc ,
& npc - > tstream ,
& npc - > client ,
& npc - > client_name ,
& npc - > server ,
& npc - > server_name ,
2011-04-05 10:15:27 +04:00
& session_info_transport ) ;
npc - > session_info = talloc_move ( npc , & session_info_transport - > session_info ) ;
2010-06-18 18:56:58 +04:00
TALLOC_FREE ( subreq ) ;
if ( ret ! = 0 ) {
DEBUG ( 2 , ( " Failed to accept named pipe connection! (%s) \n " ,
strerror ( error ) ) ) ;
TALLOC_FREE ( npc ) ;
return ;
}
ret = make_server_pipes_struct ( npc ,
2011-07-21 12:43:56 +04:00
npc - > msg_ctx ,
2011-05-25 19:26:01 +04:00
npc - > pipe_name , NCACN_NP ,
2011-06-07 19:03:13 +04:00
false , npc - > server , npc - > client , npc - > session_info ,
2010-06-18 18:56:58 +04:00
& npc - > p , & error ) ;
if ( ret ! = 0 ) {
DEBUG ( 2 , ( " Failed to create pipes_struct! (%s) \n " ,
strerror ( error ) ) ) ;
goto fail ;
}
npc - > write_queue = tevent_queue_create ( npc , " np_server_write_queue " ) ;
if ( ! npc - > write_queue ) {
DEBUG ( 2 , ( " Failed to set up write queue! \n " ) ) ;
goto fail ;
}
2011-03-31 14:02:26 +04:00
/* And now start receiving and processing packets */
2011-02-25 15:50:37 +03:00
subreq = dcerpc_read_ncacn_packet_send ( npc , npc - > ev , npc - > tstream ) ;
2010-06-18 18:56:58 +04:00
if ( ! subreq ) {
DEBUG ( 2 , ( " Failed to start receving packets \n " ) ) ;
goto fail ;
}
tevent_req_set_callback ( subreq , named_pipe_packet_process , npc ) ;
return ;
fail :
DEBUG ( 2 , ( " Fatal error. Terminating client(%s) connection! \n " ,
npc - > client_name ) ) ;
/* terminate client connection */
talloc_free ( npc ) ;
return ;
}
static void named_pipe_packet_process ( struct tevent_req * subreq )
{
struct named_pipe_client * npc =
tevent_req_callback_data ( subreq , struct named_pipe_client ) ;
struct _output_data * out = & npc - > p - > out_data ;
2010-09-15 15:24:44 +04:00
DATA_BLOB recv_buffer = data_blob_null ;
2011-02-25 15:50:37 +03:00
struct ncacn_packet * pkt ;
2010-06-18 18:56:58 +04:00
NTSTATUS status ;
ssize_t data_left ;
ssize_t data_used ;
char * data ;
uint32_t to_send ;
2011-08-04 01:44:21 +04:00
size_t i ;
2010-06-18 18:56:58 +04:00
bool ok ;
2011-02-25 15:50:37 +03:00
status = dcerpc_read_ncacn_packet_recv ( subreq , npc , & pkt , & recv_buffer ) ;
2010-06-18 18:56:58 +04:00
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
data_left = recv_buffer . length ;
data = ( char * ) recv_buffer . data ;
while ( data_left ) {
data_used = process_incoming_data ( npc - > p , data , data_left ) ;
if ( data_used < 0 ) {
DEBUG ( 3 , ( " Failed to process dceprc request! \n " ) ) ;
status = NT_STATUS_UNEXPECTED_IO_ERROR ;
goto fail ;
}
data_left - = data_used ;
data + = data_used ;
}
/* Do not leak this buffer, npc is a long lived context */
talloc_free ( recv_buffer . data ) ;
2011-02-25 15:50:37 +03:00
talloc_free ( pkt ) ;
2010-06-18 18:56:58 +04:00
/* this is needed because of the way DCERPC Binds work in
* the RPC marshalling code */
to_send = out - > frag . length - out - > current_pdu_sent ;
if ( to_send > 0 ) {
npc - > iov = talloc_zero ( npc , struct iovec ) ;
if ( ! npc - > iov ) {
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
npc - > count = 1 ;
npc - > iov [ 0 ] . iov_base = out - > frag . data
+ out - > current_pdu_sent ;
npc - > iov [ 0 ] . iov_len = to_send ;
out - > current_pdu_sent + = to_send ;
}
/* this condition is false for bind packets, or when we haven't
* yet got a full request , and need to wait for more data from
* the client */
while ( out - > data_sent_length < out - > rdata . length ) {
ok = create_next_pdu ( npc - > p ) ;
if ( ! ok ) {
DEBUG ( 3 , ( " Failed to create next PDU! \n " ) ) ;
status = NT_STATUS_UNEXPECTED_IO_ERROR ;
goto fail ;
}
npc - > iov = talloc_realloc ( npc , npc - > iov ,
struct iovec , npc - > count + 1 ) ;
if ( ! npc - > iov ) {
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
npc - > iov [ npc - > count ] . iov_base = out - > frag . data ;
npc - > iov [ npc - > count ] . iov_len = out - > frag . length ;
npc - > count + + ;
}
/* we still don't have a complete request, go back and wait for more
* data */
if ( npc - > count = = 0 ) {
/* Wait for the next packet */
2011-02-25 15:50:37 +03:00
subreq = dcerpc_read_ncacn_packet_send ( npc , npc - > ev , npc - > tstream ) ;
2010-06-18 18:56:58 +04:00
if ( ! subreq ) {
DEBUG ( 2 , ( " Failed to start receving packets \n " ) ) ;
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
tevent_req_set_callback ( subreq , named_pipe_packet_process , npc ) ;
return ;
}
2011-08-04 01:44:21 +04:00
DEBUG ( 10 , ( " Sending %u fragments in a total of %u bytes \n " ,
( unsigned int ) npc - > count ,
2010-06-18 18:56:58 +04:00
( unsigned int ) npc - > p - > out_data . data_sent_length ) ) ;
2011-08-04 01:44:21 +04:00
for ( i = 0 ; i < npc - > count ; i + + ) {
DEBUG ( 10 , ( " Sending PDU number: %d, PDU Length: %u \n " ,
( unsigned int ) i ,
( unsigned int ) npc - > iov [ i ] . iov_len ) ) ;
dump_data ( 11 , ( const uint8_t * ) npc - > iov [ i ] . iov_base ,
npc - > iov [ i ] . iov_len ) ;
subreq = tstream_writev_queue_send ( npc ,
npc - > ev ,
npc - > tstream ,
npc - > write_queue ,
( npc - > iov + i ) ,
1 ) ;
if ( ! subreq ) {
DEBUG ( 2 , ( " Failed to send packet \n " ) ) ;
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
tevent_req_set_callback ( subreq , named_pipe_packet_done , npc ) ;
2010-06-18 18:56:58 +04:00
}
2011-08-04 01:44:21 +04:00
2010-06-18 18:56:58 +04:00
return ;
fail :
DEBUG ( 2 , ( " Fatal error(%s). "
" Terminating client(%s) connection! \n " ,
nt_errstr ( status ) , npc - > client_name ) ) ;
/* terminate client connection */
talloc_free ( npc ) ;
2010-05-20 17:16:29 +04:00
return ;
}
2010-06-18 18:56:58 +04:00
static void named_pipe_packet_done ( struct tevent_req * subreq )
{
struct named_pipe_client * npc =
tevent_req_callback_data ( subreq , struct named_pipe_client ) ;
int sys_errno ;
int ret ;
ret = tstream_writev_queue_recv ( subreq , & sys_errno ) ;
TALLOC_FREE ( subreq ) ;
if ( ret = = - 1 ) {
DEBUG ( 2 , ( " Writev failed! \n " ) ) ;
goto fail ;
}
2011-08-04 01:44:21 +04:00
if ( tevent_queue_length ( npc - > write_queue ) > 0 ) {
return ;
}
2010-06-18 18:56:58 +04:00
/* clear out any data that may have been left around */
npc - > count = 0 ;
TALLOC_FREE ( npc - > iov ) ;
data_blob_free ( & npc - > p - > in_data . data ) ;
data_blob_free ( & npc - > p - > out_data . frag ) ;
data_blob_free ( & npc - > p - > out_data . rdata ) ;
2011-07-26 14:07:20 +04:00
talloc_free_children ( npc - > p - > mem_ctx ) ;
2010-06-18 18:56:58 +04:00
/* Wait for the next packet */
2011-02-25 15:50:37 +03:00
subreq = dcerpc_read_ncacn_packet_send ( npc , npc - > ev , npc - > tstream ) ;
2010-06-18 18:56:58 +04:00
if ( ! subreq ) {
DEBUG ( 2 , ( " Failed to start receving packets \n " ) ) ;
sys_errno = ENOMEM ;
goto fail ;
}
tevent_req_set_callback ( subreq , named_pipe_packet_process , npc ) ;
return ;
fail :
DEBUG ( 2 , ( " Fatal error(%s). "
" Terminating client(%s) connection! \n " ,
strerror ( sys_errno ) , npc - > client_name ) ) ;
/* terminate client connection */
talloc_free ( npc ) ;
return ;
2011-02-23 04:40:24 +03:00
}
2011-02-14 12:29:14 +03:00
/********************************************************************
* Start listening on the tcp / ip socket
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void dcerpc_ncacn_tcpip_listener ( struct tevent_context * ev ,
struct tevent_fd * fde ,
uint16_t flags ,
void * private_data ) ;
2011-05-23 18:00:30 +04:00
int create_tcpip_socket ( const struct sockaddr_storage * ifss , uint16_t * port )
{
int fd = - 1 ;
if ( * port = = 0 ) {
uint16_t i ;
for ( i = SERVER_TCP_LOW_PORT ; i < = SERVER_TCP_HIGH_PORT ; i + + ) {
fd = open_socket_in ( SOCK_STREAM ,
i ,
0 ,
ifss ,
false ) ;
if ( fd > 0 ) {
* port = i ;
break ;
}
}
} else {
fd = open_socket_in ( SOCK_STREAM ,
* port ,
0 ,
ifss ,
true ) ;
}
if ( fd = = - 1 ) {
DEBUG ( 0 , ( " Failed to create socket on port %u! \n " , * port ) ) ;
return - 1 ;
}
DEBUG ( 10 , ( " Opened tcpip socket fd %d for port %u \n " , fd , * port ) ) ;
return fd ;
}
2011-02-14 12:29:14 +03:00
uint16_t setup_dcerpc_ncacn_tcpip_socket ( struct tevent_context * ev_ctx ,
struct messaging_context * msg_ctx ,
const struct sockaddr_storage * ifss ,
uint16_t port )
{
struct dcerpc_ncacn_listen_state * state ;
struct tevent_fd * fde ;
int rc ;
state = talloc ( ev_ctx , struct dcerpc_ncacn_listen_state ) ;
if ( state = = NULL ) {
DEBUG ( 0 , ( " setup_dcerpc_ncacn_tcpip_socket: Out of memory \n " ) ) ;
2011-02-23 04:40:24 +03:00
return 0 ;
2011-02-14 12:29:14 +03:00
}
state - > fd = - 1 ;
state - > ep . port = port ;
2011-03-14 14:29:49 +03:00
state - > disconnect_fn = NULL ;
2011-02-14 12:29:14 +03:00
2011-05-23 18:00:30 +04:00
state - > fd = create_tcpip_socket ( ifss , & state - > ep . port ) ;
2011-02-14 12:29:14 +03:00
if ( state - > fd = = - 1 ) {
goto out ;
}
state - > ev_ctx = ev_ctx ;
state - > msg_ctx = msg_ctx ;
/* ready to listen */
set_socket_options ( state - > fd , " SO_KEEPALIVE " ) ;
set_socket_options ( state - > fd , lp_socket_options ( ) ) ;
/* Set server socket to non-blocking for the accept. */
set_blocking ( state - > fd , false ) ;
rc = listen ( state - > fd , SMBD_LISTEN_BACKLOG ) ;
if ( rc = = - 1 ) {
DEBUG ( 0 , ( " setup_tcpip_socket: listen - %s \n " , strerror ( errno ) ) ) ;
goto out ;
}
DEBUG ( 10 , ( " setup_tcpip_socket: openened socket fd %d for port %u \n " ,
state - > fd , state - > ep . port ) ) ;
fde = tevent_add_fd ( state - > ev_ctx ,
state ,
state - > fd ,
TEVENT_FD_READ ,
dcerpc_ncacn_tcpip_listener ,
state ) ;
if ( fde = = NULL ) {
DEBUG ( 0 , ( " setup_tcpip_socket: Failed to add event handler! \n " ) ) ;
goto out ;
}
tevent_fd_set_auto_close ( fde ) ;
return state - > ep . port ;
out :
if ( state - > fd ! = - 1 ) {
close ( state - > fd ) ;
}
TALLOC_FREE ( state ) ;
return 0 ;
}
static void dcerpc_ncacn_tcpip_listener ( struct tevent_context * ev ,
struct tevent_fd * fde ,
uint16_t flags ,
void * private_data )
{
struct dcerpc_ncacn_listen_state * state =
talloc_get_type_abort ( private_data ,
struct dcerpc_ncacn_listen_state ) ;
2011-02-22 17:14:34 +03:00
struct tsocket_address * cli_addr = NULL ;
struct tsocket_address * srv_addr = NULL ;
2011-02-14 12:29:14 +03:00
struct sockaddr_storage addr ;
socklen_t in_addrlen = sizeof ( addr ) ;
int s = - 1 ;
int rc ;
2011-03-03 17:07:02 +03:00
s = accept ( state - > fd , ( struct sockaddr * ) ( void * ) & addr , & in_addrlen ) ;
2011-02-14 12:29:14 +03:00
if ( s = = - 1 ) {
2011-03-03 17:07:02 +03:00
if ( errno ! = EINTR ) {
DEBUG ( 0 , ( " tcpip_listener accept: %s \n " ,
strerror ( errno ) ) ) ;
}
2011-02-14 12:29:14 +03:00
return ;
}
rc = tsocket_address_bsd_from_sockaddr ( state ,
( struct sockaddr * ) ( void * ) & addr ,
in_addrlen ,
& cli_addr ) ;
if ( rc < 0 ) {
close ( s ) ;
return ;
}
2011-02-22 17:14:34 +03:00
rc = getsockname ( s , ( struct sockaddr * ) ( void * ) & addr , & in_addrlen ) ;
if ( rc < 0 ) {
close ( s ) ;
return ;
}
rc = tsocket_address_bsd_from_sockaddr ( state ,
( struct sockaddr * ) ( void * ) & addr ,
in_addrlen ,
& srv_addr ) ;
if ( rc < 0 ) {
close ( s ) ;
return ;
}
2011-02-14 12:29:14 +03:00
DEBUG ( 6 , ( " tcpip_listener: Accepted socket %d \n " , s ) ) ;
dcerpc_ncacn_accept ( state - > ev_ctx ,
state - > msg_ctx ,
NCACN_IP_TCP ,
NULL ,
cli_addr ,
2011-02-22 17:14:34 +03:00
srv_addr ,
2011-03-14 14:29:49 +03:00
s ,
NULL ) ;
2011-02-14 12:29:14 +03:00
}
2011-02-23 04:40:54 +03:00
/********************************************************************
* Start listening on the ncalrpc socket
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void dcerpc_ncalrpc_listener ( struct tevent_context * ev ,
struct tevent_fd * fde ,
uint16_t flags ,
void * private_data ) ;
bool setup_dcerpc_ncalrpc_socket ( struct tevent_context * ev_ctx ,
struct messaging_context * msg_ctx ,
2011-03-14 14:29:49 +03:00
const char * name ,
dcerpc_ncacn_disconnect_fn fn )
2011-02-23 04:40:54 +03:00
{
struct dcerpc_ncacn_listen_state * state ;
struct tevent_fd * fde ;
state = talloc ( ev_ctx , struct dcerpc_ncacn_listen_state ) ;
if ( state = = NULL ) {
DEBUG ( 0 , ( " Out of memory \n " ) ) ;
return false ;
}
state - > fd = - 1 ;
2011-03-14 14:29:49 +03:00
state - > disconnect_fn = fn ;
2011-02-23 04:40:54 +03:00
if ( name = = NULL ) {
name = " DEFAULT " ;
}
state - > ep . name = talloc_strdup ( state , name ) ;
if ( state - > ep . name = = NULL ) {
DEBUG ( 0 , ( " Out of memory \n " ) ) ;
talloc_free ( state ) ;
return false ;
}
2011-05-17 12:31:14 +04:00
if ( ! directory_create_or_exist ( lp_ncalrpc_dir ( ) , geteuid ( ) , 0755 ) ) {
DEBUG ( 0 , ( " Failed to create pipe directory %s - %s \n " ,
lp_ncalrpc_dir ( ) , strerror ( errno ) ) ) ;
goto out ;
}
2011-05-08 12:29:27 +04:00
state - > fd = create_pipe_sock ( lp_ncalrpc_dir ( ) , name , 0755 ) ;
2011-02-23 04:40:54 +03:00
if ( state - > fd = = - 1 ) {
DEBUG ( 0 , ( " Failed to create pipe socket! [%s/%s] \n " ,
lp_ncalrpc_dir ( ) , name ) ) ;
goto out ;
}
DEBUG ( 10 , ( " Openened pipe socket fd %d for %s \n " , state - > fd , name ) ) ;
state - > ev_ctx = ev_ctx ;
state - > msg_ctx = msg_ctx ;
/* Set server socket to non-blocking for the accept. */
set_blocking ( state - > fd , false ) ;
fde = tevent_add_fd ( state - > ev_ctx ,
state ,
state - > fd ,
TEVENT_FD_READ ,
dcerpc_ncalrpc_listener ,
state ) ;
if ( fde = = NULL ) {
DEBUG ( 0 , ( " Failed to add event handler for ncalrpc! \n " ) ) ;
goto out ;
}
tevent_fd_set_auto_close ( fde ) ;
return true ;
out :
if ( state - > fd ! = - 1 ) {
close ( state - > fd ) ;
}
TALLOC_FREE ( state ) ;
return 0 ;
}
static void dcerpc_ncalrpc_listener ( struct tevent_context * ev ,
struct tevent_fd * fde ,
uint16_t flags ,
void * private_data )
{
struct dcerpc_ncacn_listen_state * state =
talloc_get_type_abort ( private_data ,
struct dcerpc_ncacn_listen_state ) ;
struct tsocket_address * cli_addr = NULL ;
struct sockaddr_un sunaddr ;
struct sockaddr * addr = ( struct sockaddr * ) ( void * ) & sunaddr ;
2011-02-25 16:26:29 +03:00
socklen_t len = sizeof ( sunaddr ) ;
2011-02-23 04:40:54 +03:00
int sd = - 1 ;
int rc ;
2011-02-25 16:26:29 +03:00
ZERO_STRUCT ( sunaddr ) ;
2011-03-03 17:07:16 +03:00
sd = accept ( state - > fd , addr , & len ) ;
2011-02-23 04:40:54 +03:00
if ( sd = = - 1 ) {
2011-03-03 17:07:16 +03:00
if ( errno ! = EINTR ) {
DEBUG ( 0 , ( " ncalrpc accept() failed: %s \n " , strerror ( errno ) ) ) ;
}
2011-02-23 04:40:54 +03:00
return ;
}
rc = tsocket_address_bsd_from_sockaddr ( state ,
addr , len ,
& cli_addr ) ;
if ( rc < 0 ) {
close ( sd ) ;
return ;
}
DEBUG ( 10 , ( " Accepted ncalrpc socket %d \n " , sd ) ) ;
dcerpc_ncacn_accept ( state - > ev_ctx ,
state - > msg_ctx ,
2011-05-25 19:26:01 +04:00
NCALRPC ,
2011-07-15 20:03:47 +04:00
state - > ep . name ,
2011-03-14 14:29:49 +03:00
cli_addr , NULL , sd ,
state - > disconnect_fn ) ;
2011-02-23 04:40:54 +03:00
}
2011-02-14 12:29:14 +03:00
struct dcerpc_ncacn_conn {
enum dcerpc_transport_t transport ;
int sock ;
struct pipes_struct * p ;
2011-03-14 14:29:49 +03:00
dcerpc_ncacn_disconnect_fn disconnect_fn ;
2011-02-14 12:29:14 +03:00
struct tevent_context * ev_ctx ;
struct messaging_context * msg_ctx ;
struct tstream_context * tstream ;
struct tevent_queue * send_queue ;
struct tsocket_address * client ;
char * client_name ;
struct tsocket_address * server ;
char * server_name ;
2011-04-05 10:15:27 +04:00
struct auth_session_info * session_info ;
2011-02-14 12:29:14 +03:00
struct iovec * iov ;
size_t count ;
} ;
static void dcerpc_ncacn_packet_process ( struct tevent_req * subreq ) ;
static void dcerpc_ncacn_packet_done ( struct tevent_req * subreq ) ;
2011-07-20 18:26:48 +04:00
void dcerpc_ncacn_accept ( struct tevent_context * ev_ctx ,
struct messaging_context * msg_ctx ,
enum dcerpc_transport_t transport ,
const char * name ,
struct tsocket_address * cli_addr ,
struct tsocket_address * srv_addr ,
int s ,
dcerpc_ncacn_disconnect_fn fn ) {
2011-02-14 12:29:14 +03:00
struct dcerpc_ncacn_conn * ncacn_conn ;
struct tevent_req * subreq ;
2011-03-02 12:56:46 +03:00
bool system_user = false ;
2011-02-14 12:29:14 +03:00
char * pipe_name ;
NTSTATUS status ;
int sys_errno ;
2011-03-02 12:56:46 +03:00
uid_t uid ;
2011-02-14 12:29:14 +03:00
int rc ;
2011-02-23 04:40:24 +03:00
DEBUG ( 10 , ( " dcerpc_ncacn_accept \n " ) ) ;
2011-02-14 12:29:14 +03:00
ncacn_conn = talloc_zero ( ev_ctx , struct dcerpc_ncacn_conn ) ;
if ( ncacn_conn = = NULL ) {
2011-02-23 04:40:24 +03:00
DEBUG ( 0 , ( " Out of memory! \n " ) ) ;
2011-02-14 12:29:14 +03:00
close ( s ) ;
return ;
}
ncacn_conn - > transport = transport ;
ncacn_conn - > ev_ctx = ev_ctx ;
ncacn_conn - > msg_ctx = msg_ctx ;
ncacn_conn - > sock = s ;
2011-03-14 14:29:49 +03:00
ncacn_conn - > disconnect_fn = fn ;
2011-02-14 12:29:14 +03:00
ncacn_conn - > client = talloc_move ( ncacn_conn , & cli_addr ) ;
2011-02-22 17:14:34 +03:00
if ( tsocket_address_is_inet ( ncacn_conn - > client , " ip " ) ) {
ncacn_conn - > client_name =
tsocket_address_inet_addr_string ( ncacn_conn - > client ,
ncacn_conn ) ;
} else {
ncacn_conn - > client_name =
tsocket_address_unix_path ( ncacn_conn - > client ,
ncacn_conn ) ;
}
if ( ncacn_conn - > client_name = = NULL ) {
2011-02-23 04:40:24 +03:00
DEBUG ( 0 , ( " Out of memory! \n " ) ) ;
2011-02-22 17:14:34 +03:00
talloc_free ( ncacn_conn ) ;
close ( s ) ;
return ;
}
if ( srv_addr ! = NULL ) {
ncacn_conn - > server = talloc_move ( ncacn_conn , & srv_addr ) ;
ncacn_conn - > server_name =
tsocket_address_inet_addr_string ( ncacn_conn - > server ,
ncacn_conn ) ;
if ( ncacn_conn - > server_name = = NULL ) {
2011-02-23 04:40:24 +03:00
DEBUG ( 0 , ( " Out of memory! \n " ) ) ;
2011-02-22 17:14:34 +03:00
talloc_free ( ncacn_conn ) ;
close ( s ) ;
return ;
}
}
2011-02-14 12:29:14 +03:00
2011-03-01 21:10:02 +03:00
switch ( transport ) {
case NCACN_IP_TCP :
pipe_name = tsocket_address_string ( ncacn_conn - > client ,
ncacn_conn ) ;
if ( pipe_name = = NULL ) {
close ( s ) ;
talloc_free ( ncacn_conn ) ;
return ;
}
break ;
case NCALRPC :
2011-03-02 12:56:46 +03:00
rc = sys_getpeereid ( s , & uid ) ;
if ( rc < 0 ) {
DEBUG ( 2 , ( " Failed to get ncalrpc connecting uid! " ) ) ;
} else {
if ( uid = = sec_initial_uid ( ) ) {
system_user = true ;
}
}
2011-03-01 21:10:02 +03:00
case NCACN_NP :
pipe_name = talloc_strdup ( ncacn_conn ,
name ) ;
if ( pipe_name = = NULL ) {
close ( s ) ;
talloc_free ( ncacn_conn ) ;
return ;
}
break ;
default :
DEBUG ( 0 , ( " unknown dcerpc transport: %u! \n " ,
transport ) ) ;
talloc_free ( ncacn_conn ) ;
close ( s ) ;
return ;
}
2011-02-14 12:29:14 +03:00
rc = set_blocking ( s , false ) ;
if ( rc < 0 ) {
2011-02-23 04:40:24 +03:00
DEBUG ( 2 , ( " Failed to set dcerpc socket to non-blocking \n " ) ) ;
2011-02-14 12:29:14 +03:00
talloc_free ( ncacn_conn ) ;
close ( s ) ;
return ;
}
/*
2011-02-23 04:40:24 +03:00
* As soon as we have tstream_bsd_existing_socket set up it will
* take care of closing the socket .
2011-02-14 12:29:14 +03:00
*/
rc = tstream_bsd_existing_socket ( ncacn_conn , s , & ncacn_conn - > tstream ) ;
if ( rc < 0 ) {
2011-02-23 04:40:24 +03:00
DEBUG ( 2 , ( " Failed to create tstream socket for dcerpc \n " ) ) ;
2011-02-14 12:29:14 +03:00
talloc_free ( ncacn_conn ) ;
close ( s ) ;
return ;
}
if ( ncacn_conn - > session_info = = NULL ) {
status = auth_anonymous_session_info ( ncacn_conn ,
& ncacn_conn - > session_info ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-02-23 04:40:24 +03:00
DEBUG ( 2 , ( " Failed to create "
2011-02-14 12:29:14 +03:00
" auth_anonymous_session_info - %s \n " ,
nt_errstr ( status ) ) ) ;
talloc_free ( ncacn_conn ) ;
return ;
}
}
rc = make_server_pipes_struct ( ncacn_conn ,
2011-07-21 12:43:56 +04:00
ncacn_conn - > msg_ctx ,
2011-02-14 12:29:14 +03:00
pipe_name ,
2011-03-03 16:20:26 +03:00
ncacn_conn - > transport ,
2011-03-02 12:56:46 +03:00
system_user ,
2011-06-07 19:03:13 +04:00
ncacn_conn - > server ,
ncacn_conn - > client ,
2011-02-14 12:29:14 +03:00
ncacn_conn - > session_info ,
& ncacn_conn - > p ,
& sys_errno ) ;
if ( rc < 0 ) {
2011-02-23 04:40:24 +03:00
DEBUG ( 2 , ( " Failed to create pipe struct - %s " ,
strerror ( sys_errno ) ) ) ;
2011-02-14 12:29:14 +03:00
talloc_free ( ncacn_conn ) ;
return ;
}
ncacn_conn - > send_queue = tevent_queue_create ( ncacn_conn ,
2011-02-23 04:40:24 +03:00
" dcerpc send queue " ) ;
2011-02-14 12:29:14 +03:00
if ( ncacn_conn - > send_queue = = NULL ) {
2011-02-23 04:40:24 +03:00
DEBUG ( 0 , ( " Out of memory! \n " ) ) ;
2011-02-14 12:29:14 +03:00
talloc_free ( ncacn_conn ) ;
return ;
}
2011-02-25 15:50:37 +03:00
subreq = dcerpc_read_ncacn_packet_send ( ncacn_conn ,
2011-02-14 12:29:14 +03:00
ncacn_conn - > ev_ctx ,
ncacn_conn - > tstream ) ;
if ( subreq = = NULL ) {
2011-02-23 04:40:24 +03:00
DEBUG ( 2 , ( " Failed to send ncacn packet \n " ) ) ;
2011-02-14 12:29:14 +03:00
talloc_free ( ncacn_conn ) ;
return ;
}
tevent_req_set_callback ( subreq , dcerpc_ncacn_packet_process , ncacn_conn ) ;
2011-02-23 04:40:24 +03:00
DEBUG ( 10 , ( " dcerpc_ncacn_accept done \n " ) ) ;
2011-02-14 12:29:14 +03:00
return ;
}
static void dcerpc_ncacn_packet_process ( struct tevent_req * subreq )
{
struct dcerpc_ncacn_conn * ncacn_conn =
tevent_req_callback_data ( subreq , struct dcerpc_ncacn_conn ) ;
struct _output_data * out = & ncacn_conn - > p - > out_data ;
DATA_BLOB recv_buffer = data_blob_null ;
2011-02-25 15:50:37 +03:00
struct ncacn_packet * pkt ;
2011-02-14 12:29:14 +03:00
ssize_t data_left ;
ssize_t data_used ;
uint32_t to_send ;
char * data ;
NTSTATUS status ;
bool ok ;
2011-02-25 15:50:37 +03:00
status = dcerpc_read_ncacn_packet_recv ( subreq , ncacn_conn , & pkt , & recv_buffer ) ;
2011-02-14 12:29:14 +03:00
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-03-14 14:29:49 +03:00
if ( ncacn_conn - > disconnect_fn ! = NULL ) {
ok = ncacn_conn - > disconnect_fn ( ncacn_conn - > p ) ;
if ( ! ok ) {
DEBUG ( 3 , ( " Failed to call disconnect function \n " ) ) ;
}
}
2011-02-14 12:29:14 +03:00
goto fail ;
}
data_left = recv_buffer . length ;
data = ( char * ) recv_buffer . data ;
while ( data_left ) {
data_used = process_incoming_data ( ncacn_conn - > p , data , data_left ) ;
if ( data_used < 0 ) {
DEBUG ( 3 , ( " Failed to process dcerpc request! \n " ) ) ;
status = NT_STATUS_UNEXPECTED_IO_ERROR ;
goto fail ;
}
data_left - = data_used ;
data + = data_used ;
}
/* Do not leak this buffer */
talloc_free ( recv_buffer . data ) ;
2011-02-25 15:50:37 +03:00
talloc_free ( pkt ) ;
2011-02-14 12:29:14 +03:00
/*
* This is needed because of the way DCERPC binds work in the RPC
* marshalling code
*/
to_send = out - > frag . length - out - > current_pdu_sent ;
if ( to_send > 0 ) {
DEBUG ( 10 , ( " Current_pdu_len = %u, "
" current_pdu_sent = %u "
" Returning %u bytes \n " ,
( unsigned int ) out - > frag . length ,
( unsigned int ) out - > current_pdu_sent ,
( unsigned int ) to_send ) ) ;
ncacn_conn - > iov = talloc_zero ( ncacn_conn , struct iovec ) ;
if ( ncacn_conn - > iov = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
2011-03-02 12:56:46 +03:00
DEBUG ( 3 , ( " Out of memory! \n " ) ) ;
2011-02-14 12:29:14 +03:00
goto fail ;
}
ncacn_conn - > count = 1 ;
ncacn_conn - > iov [ 0 ] . iov_base = out - > frag . data
+ out - > current_pdu_sent ;
ncacn_conn - > iov [ 0 ] . iov_len = to_send ;
out - > current_pdu_sent + = to_send ;
}
/*
* This condition is false for bind packets , or when we haven ' t yet got
* a full request , and need to wait for more data from the client
*/
while ( out - > data_sent_length < out - > rdata . length ) {
ok = create_next_pdu ( ncacn_conn - > p ) ;
if ( ! ok ) {
DEBUG ( 3 , ( " Failed to create next PDU! \n " ) ) ;
status = NT_STATUS_UNEXPECTED_IO_ERROR ;
goto fail ;
}
ncacn_conn - > iov = talloc_realloc ( ncacn_conn ,
ncacn_conn - > iov ,
struct iovec ,
ncacn_conn - > count + 1 ) ;
if ( ncacn_conn - > iov = = NULL ) {
2011-03-02 12:56:46 +03:00
DEBUG ( 3 , ( " Out of memory! \n " ) ) ;
2011-02-14 12:29:14 +03:00
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
ncacn_conn - > iov [ ncacn_conn - > count ] . iov_base = out - > frag . data ;
ncacn_conn - > iov [ ncacn_conn - > count ] . iov_len = out - > frag . length ;
DEBUG ( 10 , ( " PDU number: %d, PDU Length: %u \n " ,
( unsigned int ) ncacn_conn - > count ,
( unsigned int ) ncacn_conn - > iov [ ncacn_conn - > count ] . iov_len ) ) ;
dump_data ( 11 , ( const uint8_t * ) ncacn_conn - > iov [ ncacn_conn - > count ] . iov_base ,
ncacn_conn - > iov [ ncacn_conn - > count ] . iov_len ) ;
ncacn_conn - > count + + ;
}
/*
* We still don ' t have a complete request , go back and wait for more
* data .
*/
if ( ncacn_conn - > count = = 0 ) {
/* Wait for the next packet */
2011-02-25 15:50:37 +03:00
subreq = dcerpc_read_ncacn_packet_send ( ncacn_conn ,
2011-02-14 12:29:14 +03:00
ncacn_conn - > ev_ctx ,
ncacn_conn - > tstream ) ;
if ( subreq = = NULL ) {
DEBUG ( 2 , ( " Failed to start receving packets \n " ) ) ;
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
tevent_req_set_callback ( subreq , dcerpc_ncacn_packet_process , ncacn_conn ) ;
return ;
}
DEBUG ( 10 , ( " Sending a total of %u bytes \n " ,
( unsigned int ) ncacn_conn - > p - > out_data . data_sent_length ) ) ;
subreq = tstream_writev_queue_send ( ncacn_conn ,
ncacn_conn - > ev_ctx ,
ncacn_conn - > tstream ,
ncacn_conn - > send_queue ,
ncacn_conn - > iov ,
ncacn_conn - > count ) ;
if ( subreq = = NULL ) {
DEBUG ( 2 , ( " Failed to send packet \n " ) ) ;
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
tevent_req_set_callback ( subreq , dcerpc_ncacn_packet_done , ncacn_conn ) ;
return ;
fail :
2011-03-08 18:10:07 +03:00
DEBUG ( 3 , ( " Terminating client(%s) connection! - '%s' \n " ,
ncacn_conn - > client_name , nt_errstr ( status ) ) ) ;
2011-02-14 12:29:14 +03:00
/* Terminate client connection */
talloc_free ( ncacn_conn ) ;
return ;
}
static void dcerpc_ncacn_packet_done ( struct tevent_req * subreq )
{
struct dcerpc_ncacn_conn * ncacn_conn =
tevent_req_callback_data ( subreq , struct dcerpc_ncacn_conn ) ;
2011-03-08 18:10:07 +03:00
NTSTATUS status = NT_STATUS_OK ;
2011-02-14 12:29:14 +03:00
int sys_errno ;
int rc ;
rc = tstream_writev_queue_recv ( subreq , & sys_errno ) ;
TALLOC_FREE ( subreq ) ;
if ( rc < 0 ) {
DEBUG ( 2 , ( " Writev failed! \n " ) ) ;
2011-03-08 18:10:07 +03:00
status = map_nt_error_from_unix ( sys_errno ) ;
2011-02-14 12:29:14 +03:00
goto fail ;
}
/* clear out any data that may have been left around */
ncacn_conn - > count = 0 ;
TALLOC_FREE ( ncacn_conn - > iov ) ;
data_blob_free ( & ncacn_conn - > p - > in_data . data ) ;
data_blob_free ( & ncacn_conn - > p - > out_data . frag ) ;
data_blob_free ( & ncacn_conn - > p - > out_data . rdata ) ;
2011-07-26 14:07:20 +04:00
talloc_free_children ( ncacn_conn - > p - > mem_ctx ) ;
2011-02-14 12:29:14 +03:00
/* Wait for the next packet */
2011-02-25 15:50:37 +03:00
subreq = dcerpc_read_ncacn_packet_send ( ncacn_conn ,
2011-02-14 12:29:14 +03:00
ncacn_conn - > ev_ctx ,
ncacn_conn - > tstream ) ;
if ( subreq = = NULL ) {
DEBUG ( 2 , ( " Failed to start receving packets \n " ) ) ;
2011-03-08 18:10:07 +03:00
status = NT_STATUS_NO_MEMORY ;
2011-02-14 12:29:14 +03:00
goto fail ;
}
tevent_req_set_callback ( subreq , dcerpc_ncacn_packet_process , ncacn_conn ) ;
return ;
fail :
2011-03-08 18:10:07 +03:00
DEBUG ( 3 , ( " Terminating client(%s) connection! - '%s' \n " ,
ncacn_conn - > client_name , nt_errstr ( status ) ) ) ;
2011-02-14 12:29:14 +03:00
/* Terminate client connection */
talloc_free ( ncacn_conn ) ;
return ;
}
/* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */