2005-02-16 10:03:18 +00:00
/*
Unix SMB / CIFS implementation .
low level WINS replication client code
Copyright ( C ) Andrew Tridgell 2005
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 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 , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
# include "lib/events/events.h"
# include "dlinklist.h"
# include "lib/socket/socket.h"
2005-09-09 16:00:02 +00:00
# include "libcli/wrepl/winsrepl.h"
2005-12-12 21:31:42 +00:00
# include "lib/stream/packet.h"
# include "libcli/composite/composite.h"
static struct wrepl_request * wrepl_request_finished ( struct wrepl_request * req , NTSTATUS status ) ;
2005-02-16 10:03:18 +00:00
/*
mark all pending requests as dead - called when a socket error happens
*/
2005-09-27 16:53:08 +00:00
static void wrepl_socket_dead ( struct wrepl_socket * wrepl_socket , NTSTATUS status )
2005-02-16 10:03:18 +00:00
{
2005-10-06 14:38:07 +00:00
talloc_set_destructor ( wrepl_socket , NULL ) ;
2005-09-27 10:31:57 +00:00
wrepl_socket - > dead = True ;
2005-12-12 21:31:42 +00:00
if ( wrepl_socket - > event . fde ) {
packet_recv_disable ( wrepl_socket - > packet ) ;
packet_set_fde ( wrepl_socket - > packet , NULL ) ;
talloc_free ( wrepl_socket - > event . fde ) ;
wrepl_socket - > event . fde = NULL ;
2005-09-27 16:53:08 +00:00
}
if ( wrepl_socket - > sock ) {
2005-12-12 21:31:42 +00:00
packet_set_socket ( wrepl_socket - > packet , NULL ) ;
2005-09-27 16:53:08 +00:00
talloc_free ( wrepl_socket - > sock ) ;
wrepl_socket - > sock = NULL ;
}
2005-02-16 10:03:18 +00:00
2005-09-27 16:53:08 +00:00
if ( NT_STATUS_EQUAL ( NT_STATUS_UNSUCCESSFUL , status ) ) {
status = NT_STATUS_UNEXPECTED_NETWORK_ERROR ;
}
2005-02-16 10:03:18 +00:00
while ( wrepl_socket - > recv_queue ) {
struct wrepl_request * req = wrepl_socket - > recv_queue ;
DLIST_REMOVE ( wrepl_socket - > recv_queue , req ) ;
2005-12-12 21:31:42 +00:00
wrepl_request_finished ( req , status ) ;
2005-02-16 10:03:18 +00:00
}
}
2005-09-27 16:53:08 +00:00
static void wrepl_request_timeout_handler ( struct event_context * ev , struct timed_event * te ,
struct timeval t , void * ptr )
{
struct wrepl_request * req = talloc_get_type ( ptr , struct wrepl_request ) ;
wrepl_socket_dead ( req - > wrepl_socket , NT_STATUS_IO_TIMEOUT ) ;
}
2005-02-16 10:03:18 +00:00
/*
handle recv events
*/
2005-12-12 21:31:42 +00:00
static NTSTATUS wrepl_finish_recv ( void * private , DATA_BLOB packet_blob_in )
2005-02-16 10:03:18 +00:00
{
2005-12-12 21:31:42 +00:00
struct wrepl_socket * wrepl_socket = talloc_get_type ( private , struct wrepl_socket ) ;
2005-02-16 10:03:18 +00:00
struct wrepl_request * req = wrepl_socket - > recv_queue ;
DATA_BLOB blob ;
req - > packet = talloc ( req , struct wrepl_packet ) ;
2005-12-12 21:31:42 +00:00
NT_STATUS_HAVE_NO_MEMORY ( req - > packet ) ;
2005-02-16 10:03:18 +00:00
2005-12-12 21:31:42 +00:00
blob . data = packet_blob_in . data + 4 ;
blob . length = packet_blob_in . length - 4 ;
2005-02-16 10:03:18 +00:00
/* we have a full request - parse it */
req - > status = ndr_pull_struct_blob ( & blob ,
req - > packet , req - > packet ,
( ndr_pull_flags_fn_t ) ndr_pull_wrepl_packet ) ;
if ( ! NT_STATUS_IS_OK ( req - > status ) ) {
2005-12-12 21:31:42 +00:00
wrepl_request_finished ( req , req - > status ) ;
return NT_STATUS_OK ;
2005-02-16 10:03:18 +00:00
}
if ( DEBUGLVL ( 10 ) ) {
2005-12-12 21:31:42 +00:00
DEBUG ( 10 , ( " Received WINS packet of length %u \n " , packet_blob_in . length ) ) ;
2005-02-16 10:03:18 +00:00
NDR_PRINT_DEBUG ( wrepl_packet , req - > packet ) ;
}
2005-12-12 21:31:42 +00:00
wrepl_request_finished ( req , req - > status ) ;
return NT_STATUS_OK ;
2005-02-16 10:03:18 +00:00
}
/*
handler for winrepl events
*/
static void wrepl_handler ( struct event_context * ev , struct fd_event * fde ,
uint16_t flags , void * private )
{
struct wrepl_socket * wrepl_socket = talloc_get_type ( private ,
struct wrepl_socket ) ;
if ( flags & EVENT_FD_READ ) {
2005-12-12 21:31:42 +00:00
packet_recv ( wrepl_socket - > packet ) ;
return ;
}
if ( flags & EVENT_FD_WRITE ) {
packet_queue_run ( wrepl_socket - > packet ) ;
2005-02-16 10:03:18 +00:00
}
}
2005-12-12 21:31:42 +00:00
static void wrepl_error ( void * private , NTSTATUS status )
2005-02-16 10:03:18 +00:00
{
struct wrepl_socket * wrepl_socket = talloc_get_type ( private ,
struct wrepl_socket ) ;
2005-12-12 21:31:42 +00:00
wrepl_socket_dead ( wrepl_socket , status ) ;
2005-02-16 10:03:18 +00:00
}
2005-12-12 21:31:42 +00:00
2005-09-27 16:53:08 +00:00
/*
destroy a wrepl_socket destructor
*/
static int wrepl_socket_destructor ( void * ptr )
{
struct wrepl_socket * sock = talloc_get_type ( ptr , struct wrepl_socket ) ;
2005-10-06 14:38:07 +00:00
wrepl_socket_dead ( sock , NT_STATUS_LOCAL_DISCONNECT ) ;
2005-09-27 16:53:08 +00:00
return 0 ;
}
2005-02-16 10:03:18 +00:00
/*
initialise a wrepl_socket . The event_ctx is optional , if provided then
operations will use that event context
*/
struct wrepl_socket * wrepl_socket_init ( TALLOC_CTX * mem_ctx ,
struct event_context * event_ctx )
{
struct wrepl_socket * wrepl_socket ;
NTSTATUS status ;
2005-12-12 21:31:42 +00:00
wrepl_socket = talloc_zero ( mem_ctx , struct wrepl_socket ) ;
if ( ! wrepl_socket ) return NULL ;
2005-02-16 10:03:18 +00:00
if ( event_ctx = = NULL ) {
2005-12-12 21:31:42 +00:00
wrepl_socket - > event . ctx = event_context_init ( wrepl_socket ) ;
2005-02-16 10:03:18 +00:00
} else {
2005-12-12 21:31:42 +00:00
wrepl_socket - > event . ctx = talloc_reference ( wrepl_socket , event_ctx ) ;
2005-02-16 10:03:18 +00:00
}
2005-12-12 21:31:42 +00:00
if ( ! wrepl_socket - > event . ctx ) goto failed ;
2005-02-16 10:03:18 +00:00
status = socket_create ( " ip " , SOCKET_TYPE_STREAM , & wrepl_socket - > sock , 0 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) goto failed ;
talloc_steal ( wrepl_socket , wrepl_socket - > sock ) ;
2005-09-27 16:53:08 +00:00
wrepl_socket - > request_timeout = WREPL_SOCKET_REQUEST_TIMEOUT ;
2005-09-30 01:55:29 +00:00
talloc_set_destructor ( wrepl_socket , wrepl_socket_destructor ) ;
return wrepl_socket ;
failed :
talloc_free ( wrepl_socket ) ;
return NULL ;
}
/*
initialise a wrepl_socket from an already existing connection
*/
struct wrepl_socket * wrepl_socket_merge ( TALLOC_CTX * mem_ctx ,
struct event_context * event_ctx ,
2005-12-12 21:31:42 +00:00
struct socket_context * socket ,
struct packet_context * packet )
2005-09-30 01:55:29 +00:00
{
struct wrepl_socket * wrepl_socket ;
2005-12-12 21:31:42 +00:00
wrepl_socket = talloc_zero ( mem_ctx , struct wrepl_socket ) ;
2005-09-30 01:55:29 +00:00
if ( wrepl_socket = = NULL ) goto failed ;
2005-12-12 21:31:42 +00:00
wrepl_socket - > event . ctx = talloc_reference ( wrepl_socket , event_ctx ) ;
if ( wrepl_socket - > event . ctx = = NULL ) goto failed ;
2005-09-30 01:55:29 +00:00
wrepl_socket - > sock = socket ;
talloc_steal ( wrepl_socket , wrepl_socket - > sock ) ;
2005-12-12 21:31:42 +00:00
2005-09-30 01:55:29 +00:00
wrepl_socket - > request_timeout = WREPL_SOCKET_REQUEST_TIMEOUT ;
2005-12-12 21:31:42 +00:00
wrepl_socket - > event . fde = event_add_fd ( wrepl_socket - > event . ctx , wrepl_socket ,
socket_get_fd ( wrepl_socket - > sock ) ,
EVENT_FD_READ ,
wrepl_handler , wrepl_socket ) ;
if ( wrepl_socket - > event . fde = = NULL ) {
2005-09-30 01:55:29 +00:00
goto failed ;
}
2005-12-12 21:31:42 +00:00
wrepl_socket - > packet = packet ;
talloc_steal ( wrepl_socket , wrepl_socket - > packet ) ;
packet_set_private ( wrepl_socket - > packet , wrepl_socket ) ;
packet_set_socket ( wrepl_socket - > packet , wrepl_socket - > sock ) ;
packet_set_callback ( wrepl_socket - > packet , wrepl_finish_recv ) ;
packet_set_full_request ( wrepl_socket - > packet , packet_full_request_u32 ) ;
packet_set_error_handler ( wrepl_socket - > packet , wrepl_error ) ;
packet_set_event_context ( wrepl_socket - > packet , wrepl_socket - > event . ctx ) ;
packet_set_fde ( wrepl_socket - > packet , wrepl_socket - > event . fde ) ;
packet_set_serialise ( wrepl_socket - > packet ) ;
2005-09-27 16:53:08 +00:00
talloc_set_destructor ( wrepl_socket , wrepl_socket_destructor ) ;
2005-02-16 10:03:18 +00:00
return wrepl_socket ;
failed :
talloc_free ( wrepl_socket ) ;
return NULL ;
}
/*
destroy a wrepl_request
*/
static int wrepl_request_destructor ( void * ptr )
{
struct wrepl_request * req = talloc_get_type ( ptr , struct wrepl_request ) ;
if ( req - > state = = WREPL_REQUEST_RECV ) {
DLIST_REMOVE ( req - > wrepl_socket - > recv_queue , req ) ;
}
req - > state = WREPL_REQUEST_ERROR ;
return 0 ;
}
/*
wait for a request to complete
*/
static NTSTATUS wrepl_request_wait ( struct wrepl_request * req )
{
NT_STATUS_HAVE_NO_MEMORY ( req ) ;
while ( req - > state < WREPL_REQUEST_DONE ) {
2005-12-12 21:31:42 +00:00
event_loop_once ( req - > wrepl_socket - > event . ctx ) ;
2005-02-16 10:03:18 +00:00
}
return req - > status ;
}
2005-12-12 21:31:42 +00:00
struct wrepl_connect_state {
struct composite_context * result ;
struct wrepl_socket * wrepl_socket ;
struct composite_context * creq ;
} ;
2005-02-16 10:03:18 +00:00
/*
2005-12-12 21:31:42 +00:00
handler for winrepl connection completion
2005-02-16 10:03:18 +00:00
*/
2005-12-12 21:31:42 +00:00
static void wrepl_connect_handler ( struct composite_context * creq )
2005-02-16 10:03:18 +00:00
{
2005-12-12 21:31:42 +00:00
struct wrepl_connect_state * state = talloc_get_type ( creq - > async . private_data ,
struct wrepl_connect_state ) ;
struct wrepl_socket * wrepl_socket = state - > wrepl_socket ;
struct composite_context * result = state - > result ;
result - > status = socket_connect_recv ( state - > creq ) ;
if ( ! composite_is_ok ( result ) ) return ;
wrepl_socket - > event . fde = event_add_fd ( wrepl_socket - > event . ctx , wrepl_socket ,
socket_get_fd ( wrepl_socket - > sock ) ,
EVENT_FD_READ ,
wrepl_handler , wrepl_socket ) ;
if ( composite_nomem ( wrepl_socket - > event . fde , result ) ) return ;
/* setup the stream -> packet parser */
wrepl_socket - > packet = packet_init ( wrepl_socket ) ;
if ( composite_nomem ( wrepl_socket - > packet , result ) ) return ;
packet_set_private ( wrepl_socket - > packet , wrepl_socket ) ;
packet_set_socket ( wrepl_socket - > packet , wrepl_socket - > sock ) ;
packet_set_callback ( wrepl_socket - > packet , wrepl_finish_recv ) ;
packet_set_full_request ( wrepl_socket - > packet , packet_full_request_u32 ) ;
packet_set_error_handler ( wrepl_socket - > packet , wrepl_error ) ;
packet_set_event_context ( wrepl_socket - > packet , wrepl_socket - > event . ctx ) ;
packet_set_fde ( wrepl_socket - > packet , wrepl_socket - > event . fde ) ;
packet_set_serialise ( wrepl_socket - > packet ) ;
composite_done ( result ) ;
}
2005-02-16 10:03:18 +00:00
2005-12-12 21:31:42 +00:00
/*
connect a wrepl_socket to a WINS server
*/
struct composite_context * wrepl_connect_send ( struct wrepl_socket * wrepl_socket ,
const char * our_ip , const char * peer_ip )
{
struct composite_context * result ;
struct wrepl_connect_state * state ;
2005-02-16 10:03:18 +00:00
2005-12-12 21:31:42 +00:00
result = talloc_zero ( wrepl_socket , struct composite_context ) ;
if ( ! result ) return NULL ;
2005-02-16 10:03:18 +00:00
2005-12-12 21:31:42 +00:00
result - > state = COMPOSITE_STATE_IN_PROGRESS ;
result - > event_ctx = wrepl_socket - > event . ctx ;
2005-02-16 10:03:18 +00:00
2005-12-12 21:31:42 +00:00
state = talloc_zero ( result , struct wrepl_connect_state ) ;
if ( composite_nomem ( state , result ) ) return result ;
result - > private_data = state ;
state - > result = result ;
state - > wrepl_socket = wrepl_socket ;
2005-10-06 14:38:07 +00:00
if ( ! our_ip ) {
our_ip = iface_best_ip ( peer_ip ) ;
}
2005-12-12 21:31:42 +00:00
state - > creq = socket_connect_send ( wrepl_socket - > sock , our_ip , 0 ,
peer_ip , WINS_REPLICATION_PORT ,
0 , wrepl_socket - > event . ctx ) ;
composite_continue ( result , state - > creq , wrepl_connect_handler , state ) ;
return result ;
2005-02-16 10:03:18 +00:00
}
/*
connect a wrepl_socket to a WINS server - recv side
*/
2005-12-12 21:31:42 +00:00
NTSTATUS wrepl_connect_recv ( struct composite_context * result )
2005-02-16 10:03:18 +00:00
{
2005-12-12 21:31:42 +00:00
struct wrepl_connect_state * state = talloc_get_type ( result - > private_data ,
struct wrepl_connect_state ) ;
struct wrepl_socket * wrepl_socket = state - > wrepl_socket ;
NTSTATUS status = composite_wait ( result ) ;
2005-02-16 10:03:18 +00:00
2005-12-12 21:31:42 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
wrepl_socket_dead ( wrepl_socket , status ) ;
}
talloc_free ( result ) ;
return status ;
}
2005-02-16 10:03:18 +00:00
/*
connect a wrepl_socket to a WINS server - sync API
*/
2005-10-06 14:38:07 +00:00
NTSTATUS wrepl_connect ( struct wrepl_socket * wrepl_socket , const char * our_ip , const char * peer_ip )
2005-02-16 10:03:18 +00:00
{
2005-12-12 21:31:42 +00:00
struct composite_context * c_req = wrepl_connect_send ( wrepl_socket , our_ip , peer_ip ) ;
return wrepl_connect_recv ( c_req ) ;
2005-02-16 10:03:18 +00:00
}
2005-09-27 10:31:57 +00:00
/*
callback from wrepl_request_trigger ( )
*/
static void wrepl_request_trigger_handler ( struct event_context * ev , struct timed_event * te ,
struct timeval t , void * ptr )
{
struct wrepl_request * req = talloc_get_type ( ptr , struct wrepl_request ) ;
if ( req - > async . fn ) {
req - > async . fn ( req ) ;
}
}
/*
trigger an immediate event on a wrepl_request
2005-12-12 21:31:42 +00:00
the return value should only be used in wrepl_request_send ( )
this is the only place where req - > trigger is True
2005-09-27 10:31:57 +00:00
*/
2005-12-12 21:31:42 +00:00
static struct wrepl_request * wrepl_request_finished ( struct wrepl_request * req , NTSTATUS status )
2005-09-27 10:31:57 +00:00
{
2005-12-12 21:31:42 +00:00
struct timed_event * te ;
2005-11-03 18:38:41 +00:00
if ( req - > state = = WREPL_REQUEST_RECV ) {
DLIST_REMOVE ( req - > wrepl_socket - > recv_queue , req ) ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
req - > state = WREPL_REQUEST_ERROR ;
} else {
req - > state = WREPL_REQUEST_DONE ;
}
req - > status = status ;
2005-12-12 21:31:42 +00:00
if ( req - > trigger ) {
req - > trigger = False ;
/* a zero timeout means immediate */
te = event_add_timed ( req - > wrepl_socket - > event . ctx ,
req , timeval_zero ( ) ,
wrepl_request_trigger_handler , req ) ;
if ( ! te ) {
talloc_free ( req ) ;
return NULL ;
}
return req ;
}
if ( req - > async . fn ) {
req - > async . fn ( req ) ;
}
return NULL ;
2005-09-27 10:31:57 +00:00
}
2005-12-12 21:31:42 +00:00
struct wrepl_send_ctrl_state {
struct wrepl_send_ctrl ctrl ;
struct wrepl_request * req ;
struct wrepl_socket * wrepl_sock ;
} ;
static int wrepl_send_ctrl_destructor ( void * ptr )
{
struct wrepl_send_ctrl_state * s = talloc_get_type ( ptr , struct wrepl_send_ctrl_state ) ;
struct wrepl_request * req = s - > wrepl_sock - > recv_queue ;
/* check if the request is still in WREPL_STATE_RECV,
* we need this here because the caller has may called
* talloc_free ( req ) and wrepl_send_ctrl_state isn ' t
* a talloc child of the request , so our s - > req pointer
* is maybe invalid !
*/
for ( ; req ; req = req - > next ) {
if ( req = = s - > req ) break ;
}
if ( ! req ) return 0 ;
/* here, we need to make sure the async request handler is called
* later in the next event_loop and now now
*/
req - > trigger = True ;
wrepl_request_finished ( req , NT_STATUS_OK ) ;
if ( s - > ctrl . disconnect_after_send ) {
wrepl_socket_dead ( s - > wrepl_sock , NT_STATUS_LOCAL_DISCONNECT ) ;
}
return 0 ;
}
2005-02-16 10:03:18 +00:00
/*
send a generic wins replication request
*/
struct wrepl_request * wrepl_request_send ( struct wrepl_socket * wrepl_socket ,
2005-12-12 21:31:42 +00:00
struct wrepl_packet * packet ,
struct wrepl_send_ctrl * ctrl )
2005-02-16 10:03:18 +00:00
{
struct wrepl_request * req ;
struct wrepl_wrap wrap ;
2005-12-12 21:31:42 +00:00
DATA_BLOB blob ;
2005-02-16 10:03:18 +00:00
req = talloc_zero ( wrepl_socket , struct wrepl_request ) ;
2005-12-12 21:31:42 +00:00
if ( ! req ) return NULL ;
2005-11-03 18:38:41 +00:00
req - > wrepl_socket = wrepl_socket ;
2005-12-12 21:31:42 +00:00
req - > state = WREPL_REQUEST_RECV ;
req - > trigger = True ;
2005-11-03 18:38:41 +00:00
2005-12-12 21:31:42 +00:00
DLIST_ADD_END ( wrepl_socket - > recv_queue , req , struct wrepl_request * ) ;
2005-11-03 18:38:41 +00:00
talloc_set_destructor ( req , wrepl_request_destructor ) ;
2005-09-27 10:31:57 +00:00
if ( wrepl_socket - > dead ) {
2005-12-12 21:31:42 +00:00
return wrepl_request_finished ( req , NT_STATUS_INVALID_CONNECTION ) ;
2005-09-27 10:31:57 +00:00
}
2005-02-16 10:03:18 +00:00
wrap . packet = * packet ;
2005-12-12 21:31:42 +00:00
req - > status = ndr_push_struct_blob ( & blob , req , & wrap ,
2005-09-27 10:31:57 +00:00
( ndr_push_flags_fn_t ) ndr_push_wrepl_wrap ) ;
2005-12-12 21:31:42 +00:00
if ( ! NT_STATUS_IS_OK ( req - > status ) ) {
return wrepl_request_finished ( req , req - > status ) ;
}
2005-02-16 10:03:18 +00:00
if ( DEBUGLVL ( 10 ) ) {
2005-12-12 21:31:42 +00:00
DEBUG ( 10 , ( " Sending WINS packet of length %u \n " , blob . length ) ) ;
2005-02-16 10:03:18 +00:00
NDR_PRINT_DEBUG ( wrepl_packet , & wrap . packet ) ;
}
2005-09-27 16:53:08 +00:00
if ( wrepl_socket - > request_timeout > 0 ) {
2005-12-12 21:31:42 +00:00
req - > te = event_add_timed ( wrepl_socket - > event . ctx , req ,
2005-09-27 16:53:08 +00:00
timeval_current_ofs ( wrepl_socket - > request_timeout , 0 ) ,
wrepl_request_timeout_handler , req ) ;
2005-12-12 21:31:42 +00:00
if ( ! req - > te ) return wrepl_request_finished ( req , NT_STATUS_NO_MEMORY ) ;
2005-09-27 16:53:08 +00:00
}
2005-12-12 21:31:42 +00:00
if ( ctrl & & ( ctrl - > send_only | | ctrl - > disconnect_after_send ) ) {
struct wrepl_send_ctrl_state * s = talloc ( blob . data , struct wrepl_send_ctrl_state ) ;
if ( ! s ) return wrepl_request_finished ( req , NT_STATUS_NO_MEMORY ) ;
s - > ctrl = * ctrl ;
s - > req = req ;
s - > wrepl_sock = wrepl_socket ;
talloc_set_destructor ( s , wrepl_send_ctrl_destructor ) ;
}
2005-02-16 10:03:18 +00:00
2005-12-12 21:31:42 +00:00
req - > status = packet_send ( wrepl_socket - > packet , blob ) ;
if ( ! NT_STATUS_IS_OK ( req - > status ) ) {
return wrepl_request_finished ( req , req - > status ) ;
}
req - > trigger = False ;
return req ;
2005-02-16 10:03:18 +00:00
}
/*
receive a generic WINS replication reply
*/
NTSTATUS wrepl_request_recv ( struct wrepl_request * req ,
TALLOC_CTX * mem_ctx ,
struct wrepl_packet * * packet )
{
NTSTATUS status = wrepl_request_wait ( req ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
* packet = talloc_steal ( mem_ctx , req - > packet ) ;
}
talloc_free ( req ) ;
return status ;
}
/*
a full WINS replication request / response
*/
NTSTATUS wrepl_request ( struct wrepl_socket * wrepl_socket ,
TALLOC_CTX * mem_ctx ,
struct wrepl_packet * req_packet ,
struct wrepl_packet * * reply_packet )
{
2005-12-12 21:31:42 +00:00
struct wrepl_request * req = wrepl_request_send ( wrepl_socket , req_packet , NULL ) ;
2005-02-16 10:03:18 +00:00
return wrepl_request_recv ( req , mem_ctx , reply_packet ) ;
}
2005-02-18 23:13:51 +00:00
/*
setup an association - send
*/
struct wrepl_request * wrepl_associate_send ( struct wrepl_socket * wrepl_socket ,
struct wrepl_associate * io )
{
struct wrepl_packet * packet ;
struct wrepl_request * req ;
packet = talloc_zero ( wrepl_socket , struct wrepl_packet ) ;
if ( packet = = NULL ) return NULL ;
packet - > opcode = WREPL_OPCODE_BITS ;
packet - > mess_type = WREPL_START_ASSOCIATION ;
packet - > message . start . minor_version = 2 ;
packet - > message . start . major_version = 5 ;
2005-12-12 21:31:42 +00:00
req = wrepl_request_send ( wrepl_socket , packet , NULL ) ;
2005-02-18 23:13:51 +00:00
talloc_free ( packet ) ;
return req ;
}
/*
setup an association - recv
*/
NTSTATUS wrepl_associate_recv ( struct wrepl_request * req ,
struct wrepl_associate * io )
{
struct wrepl_packet * packet = NULL ;
NTSTATUS status ;
status = wrepl_request_recv ( req , req - > wrepl_socket , & packet ) ;
2005-09-27 10:31:57 +00:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
2005-02-18 23:13:51 +00:00
if ( packet - > mess_type ! = WREPL_START_ASSOCIATION_REPLY ) {
status = NT_STATUS_UNEXPECTED_NETWORK_ERROR ;
}
if ( NT_STATUS_IS_OK ( status ) ) {
io - > out . assoc_ctx = packet - > message . start_reply . assoc_ctx ;
}
talloc_free ( packet ) ;
return status ;
}
/*
setup an association - sync api
*/
NTSTATUS wrepl_associate ( struct wrepl_socket * wrepl_socket ,
struct wrepl_associate * io )
{
struct wrepl_request * req = wrepl_associate_send ( wrepl_socket , io ) ;
return wrepl_associate_recv ( req , io ) ;
}
2005-10-06 14:38:07 +00:00
/*
stop an association - send
*/
struct wrepl_request * wrepl_associate_stop_send ( struct wrepl_socket * wrepl_socket ,
struct wrepl_associate_stop * io )
{
struct wrepl_packet * packet ;
struct wrepl_request * req ;
2005-12-12 21:31:42 +00:00
struct wrepl_send_ctrl ctrl ;
2005-10-06 14:38:07 +00:00
packet = talloc_zero ( wrepl_socket , struct wrepl_packet ) ;
if ( packet = = NULL ) return NULL ;
packet - > opcode = WREPL_OPCODE_BITS ;
packet - > assoc_ctx = io - > in . assoc_ctx ;
packet - > mess_type = WREPL_STOP_ASSOCIATION ;
packet - > message . stop . reason = io - > in . reason ;
2005-12-12 21:31:42 +00:00
ZERO_STRUCT ( ctrl ) ;
if ( io - > in . reason = = 0 ) {
ctrl . send_only = True ;
ctrl . disconnect_after_send = True ;
2005-10-06 14:38:07 +00:00
}
2005-12-12 21:31:42 +00:00
req = wrepl_request_send ( wrepl_socket , packet , & ctrl ) ;
2005-10-06 14:38:07 +00:00
talloc_free ( packet ) ;
return req ;
}
/*
stop an association - recv
*/
NTSTATUS wrepl_associate_stop_recv ( struct wrepl_request * req ,
struct wrepl_associate_stop * io )
{
struct wrepl_packet * packet = NULL ;
NTSTATUS status ;
status = wrepl_request_recv ( req , req - > wrepl_socket , & packet ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
talloc_free ( packet ) ;
return status ;
}
/*
setup an association - sync api
*/
NTSTATUS wrepl_associate_stop ( struct wrepl_socket * wrepl_socket ,
struct wrepl_associate_stop * io )
{
struct wrepl_request * req = wrepl_associate_stop_send ( wrepl_socket , io ) ;
return wrepl_associate_stop_recv ( req , io ) ;
}
2005-02-18 23:13:51 +00:00
/*
fetch the partner tables - send
*/
struct wrepl_request * wrepl_pull_table_send ( struct wrepl_socket * wrepl_socket ,
struct wrepl_pull_table * io )
{
struct wrepl_packet * packet ;
struct wrepl_request * req ;
packet = talloc_zero ( wrepl_socket , struct wrepl_packet ) ;
if ( packet = = NULL ) return NULL ;
packet - > opcode = WREPL_OPCODE_BITS ;
packet - > assoc_ctx = io - > in . assoc_ctx ;
packet - > mess_type = WREPL_REPLICATION ;
packet - > message . replication . command = WREPL_REPL_TABLE_QUERY ;
2005-12-12 21:31:42 +00:00
req = wrepl_request_send ( wrepl_socket , packet , NULL ) ;
2005-02-18 23:13:51 +00:00
talloc_free ( packet ) ;
return req ;
}
/*
fetch the partner tables - recv
*/
NTSTATUS wrepl_pull_table_recv ( struct wrepl_request * req ,
TALLOC_CTX * mem_ctx ,
struct wrepl_pull_table * io )
{
struct wrepl_packet * packet = NULL ;
NTSTATUS status ;
struct wrepl_table * table ;
int i ;
status = wrepl_request_recv ( req , req - > wrepl_socket , & packet ) ;
2005-09-27 10:31:57 +00:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
2005-02-18 23:13:51 +00:00
if ( packet - > mess_type ! = WREPL_REPLICATION ) {
status = NT_STATUS_NETWORK_ACCESS_DENIED ;
} else if ( packet - > message . replication . command ! = WREPL_REPL_TABLE_REPLY ) {
status = NT_STATUS_UNEXPECTED_NETWORK_ERROR ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) goto failed ;
table = & packet - > message . replication . info . table ;
io - > out . num_partners = table - > partner_count ;
io - > out . partners = talloc_steal ( mem_ctx , table - > partners ) ;
for ( i = 0 ; i < io - > out . num_partners ; i + + ) {
talloc_steal ( io - > out . partners , io - > out . partners [ i ] . address ) ;
}
failed :
talloc_free ( packet ) ;
return status ;
}
/*
fetch the partner table - sync api
*/
NTSTATUS wrepl_pull_table ( struct wrepl_socket * wrepl_socket ,
TALLOC_CTX * mem_ctx ,
struct wrepl_pull_table * io )
{
struct wrepl_request * req = wrepl_pull_table_send ( wrepl_socket , io ) ;
return wrepl_pull_table_recv ( req , mem_ctx , io ) ;
}
/*
fetch the names for a WINS partner - send
*/
struct wrepl_request * wrepl_pull_names_send ( struct wrepl_socket * wrepl_socket ,
struct wrepl_pull_names * io )
{
struct wrepl_packet * packet ;
struct wrepl_request * req ;
packet = talloc_zero ( wrepl_socket , struct wrepl_packet ) ;
if ( packet = = NULL ) return NULL ;
packet - > opcode = WREPL_OPCODE_BITS ;
packet - > assoc_ctx = io - > in . assoc_ctx ;
packet - > mess_type = WREPL_REPLICATION ;
packet - > message . replication . command = WREPL_REPL_SEND_REQUEST ;
packet - > message . replication . info . owner = io - > in . partner ;
2005-12-12 21:31:42 +00:00
req = wrepl_request_send ( wrepl_socket , packet , NULL ) ;
2005-02-18 23:13:51 +00:00
talloc_free ( packet ) ;
return req ;
}
/*
fetch the names for a WINS partner - recv
*/
NTSTATUS wrepl_pull_names_recv ( struct wrepl_request * req ,
TALLOC_CTX * mem_ctx ,
struct wrepl_pull_names * io )
{
struct wrepl_packet * packet = NULL ;
NTSTATUS status ;
int i ;
status = wrepl_request_recv ( req , req - > wrepl_socket , & packet ) ;
2005-09-27 10:31:57 +00:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
2005-02-18 23:13:51 +00:00
if ( packet - > mess_type ! = WREPL_REPLICATION | |
packet - > message . replication . command ! = WREPL_REPL_SEND_REPLY ) {
status = NT_STATUS_UNEXPECTED_NETWORK_ERROR ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) goto failed ;
io - > out . num_names = packet - > message . replication . info . reply . num_names ;
io - > out . names = talloc_array ( packet , struct wrepl_name , io - > out . num_names ) ;
2005-09-28 09:58:58 +00:00
if ( io - > out . names = = NULL ) goto nomem ;
2005-02-18 23:13:51 +00:00
/* convert the list of names and addresses to a sane format */
for ( i = 0 ; i < io - > out . num_names ; i + + ) {
struct wrepl_wins_name * wname = & packet - > message . replication . info . reply . names [ i ] ;
struct wrepl_name * name = & io - > out . names [ i ] ;
2005-10-06 07:26:05 +00:00
name - > name = * wname - > name ;
talloc_steal ( io - > out . names , wname - > name ) ;
2005-09-29 14:00:07 +00:00
name - > type = WREPL_NAME_TYPE ( wname - > flags ) ;
name - > state = WREPL_NAME_STATE ( wname - > flags ) ;
2005-09-29 22:06:24 +00:00
name - > node = WREPL_NAME_NODE ( wname - > flags ) ;
2005-09-29 14:00:07 +00:00
name - > is_static = WREPL_NAME_IS_STATIC ( wname - > flags ) ;
name - > raw_flags = wname - > flags ;
2005-09-28 09:58:58 +00:00
name - > version_id = wname - > id ;
name - > owner = talloc_strdup ( io - > out . names , io - > in . partner . address ) ;
if ( name - > owner = = NULL ) goto nomem ;
2005-02-18 23:13:51 +00:00
/* trying to save 1 or 2 bytes on the wire isn't a good idea */
if ( wname - > flags & 2 ) {
int j ;
name - > num_addresses = wname - > addresses . addresses . num_ips ;
name - > addresses = talloc_array ( io - > out . names ,
struct wrepl_address ,
name - > num_addresses ) ;
2005-09-28 09:58:58 +00:00
if ( name - > addresses = = NULL ) goto nomem ;
2005-02-18 23:13:51 +00:00
for ( j = 0 ; j < name - > num_addresses ; j + + ) {
name - > addresses [ j ] . owner =
talloc_steal ( name - > addresses ,
wname - > addresses . addresses . ips [ j ] . owner ) ;
name - > addresses [ j ] . address =
talloc_steal ( name - > addresses ,
wname - > addresses . addresses . ips [ j ] . ip ) ;
}
} else {
name - > num_addresses = 1 ;
name - > addresses = talloc ( io - > out . names , struct wrepl_address ) ;
2005-09-28 09:58:58 +00:00
if ( name - > addresses = = NULL ) goto nomem ;
name - > addresses [ 0 ] . owner = talloc_strdup ( name - > addresses , io - > in . partner . address ) ;
if ( name - > addresses [ 0 ] . owner = = NULL ) goto nomem ;
2005-02-18 23:13:51 +00:00
name - > addresses [ 0 ] . address = talloc_steal ( name - > addresses ,
2005-09-09 19:55:34 +00:00
wname - > addresses . ip ) ;
2005-02-18 23:13:51 +00:00
}
}
talloc_steal ( mem_ctx , io - > out . names ) ;
2005-09-28 09:58:58 +00:00
talloc_free ( packet ) ;
return NT_STATUS_OK ;
nomem :
status = NT_STATUS_NO_MEMORY ;
2005-02-18 23:13:51 +00:00
failed :
talloc_free ( packet ) ;
return status ;
}
/*
fetch the names for a WINS partner - sync api
*/
NTSTATUS wrepl_pull_names ( struct wrepl_socket * wrepl_socket ,
TALLOC_CTX * mem_ctx ,
struct wrepl_pull_names * io )
{
struct wrepl_request * req = wrepl_pull_names_send ( wrepl_socket , io ) ;
return wrepl_pull_names_recv ( req , mem_ctx , io ) ;
}