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-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-09-27 10:31:57 +00:00
wrepl_socket - > dead = True ;
2005-09-27 16:53:08 +00:00
if ( wrepl_socket - > fde ) {
talloc_free ( wrepl_socket - > fde ) ;
wrepl_socket - > fde = NULL ;
}
if ( wrepl_socket - > sock ) {
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 - > send_queue ) {
struct wrepl_request * req = wrepl_socket - > send_queue ;
DLIST_REMOVE ( wrepl_socket - > send_queue , req ) ;
req - > state = WREPL_REQUEST_ERROR ;
2005-09-27 16:53:08 +00:00
req - > status = status ;
2005-02-16 10:03:18 +00:00
if ( req - > async . fn ) {
req - > async . fn ( req ) ;
}
}
while ( wrepl_socket - > recv_queue ) {
struct wrepl_request * req = wrepl_socket - > recv_queue ;
DLIST_REMOVE ( wrepl_socket - > recv_queue , req ) ;
req - > state = WREPL_REQUEST_ERROR ;
2005-09-27 16:53:08 +00:00
req - > status = status ;
2005-02-16 10:03:18 +00:00
if ( req - > async . fn ) {
req - > async . fn ( req ) ;
}
}
}
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 send events
*/
static void wrepl_handler_send ( struct wrepl_socket * wrepl_socket )
{
while ( wrepl_socket - > send_queue ) {
struct wrepl_request * req = wrepl_socket - > send_queue ;
size_t nsent ;
NTSTATUS status ;
status = socket_send ( wrepl_socket - > sock , & req - > buffer , & nsent , 0 ) ;
if ( NT_STATUS_IS_ERR ( status ) ) {
2005-09-27 16:53:08 +00:00
wrepl_socket_dead ( wrepl_socket , status ) ;
2005-02-16 10:03:18 +00:00
return ;
}
if ( ! NT_STATUS_IS_OK ( status ) | | nsent = = 0 ) return ;
req - > buffer . data + = nsent ;
req - > buffer . length - = nsent ;
if ( req - > buffer . length ! = 0 ) {
return ;
}
DLIST_REMOVE ( wrepl_socket - > send_queue , req ) ;
DLIST_ADD_END ( wrepl_socket - > recv_queue , req , struct wrepl_request * ) ;
req - > state = WREPL_REQUEST_RECV ;
EVENT_FD_READABLE ( wrepl_socket - > fde ) ;
}
EVENT_FD_NOT_WRITEABLE ( wrepl_socket - > fde ) ;
}
/*
handle recv events
*/
static void wrepl_handler_recv ( struct wrepl_socket * wrepl_socket )
{
size_t nread ;
struct wrepl_request * req = wrepl_socket - > recv_queue ;
DATA_BLOB blob ;
if ( req = = NULL ) {
2005-09-27 16:53:08 +00:00
NTSTATUS status ;
2005-02-16 10:03:18 +00:00
EVENT_FD_NOT_READABLE ( wrepl_socket - > fde ) ;
2005-09-27 16:53:08 +00:00
status = socket_recv ( wrepl_socket - > sock , NULL , 0 , & nread , 0 ) ;
if ( NT_STATUS_EQUAL ( NT_STATUS_END_OF_FILE , status ) ) return ;
if ( NT_STATUS_IS_ERR ( status ) ) {
wrepl_socket_dead ( wrepl_socket , status ) ;
return ;
}
2005-02-16 10:03:18 +00:00
return ;
}
if ( req - > buffer . length = = 0 ) {
req - > buffer = data_blob_talloc ( req , NULL , 4 ) ;
if ( req - > buffer . data = = NULL ) {
req - > status = NT_STATUS_NO_MEMORY ;
goto failed ;
}
req - > num_read = 0 ;
}
/* read in the packet length */
if ( req - > num_read < 4 ) {
uint32_t req_length ;
req - > status = socket_recv ( wrepl_socket - > sock ,
req - > buffer . data + req - > num_read ,
4 - req - > num_read ,
& nread , 0 ) ;
2005-09-27 10:31:57 +00:00
if ( NT_STATUS_IS_ERR ( req - > status ) ) {
2005-09-27 16:53:08 +00:00
wrepl_socket_dead ( wrepl_socket , req - > status ) ;
2005-09-27 10:31:57 +00:00
return ;
}
2005-02-16 10:03:18 +00:00
if ( ! NT_STATUS_IS_OK ( req - > status ) ) return ;
req - > num_read + = nread ;
if ( req - > num_read ! = 4 ) return ;
req_length = RIVAL ( req - > buffer . data , 0 ) + 4 ;
req - > buffer . data = talloc_realloc ( req , req - > buffer . data ,
uint8_t , req_length ) ;
if ( req - > buffer . data = = NULL ) {
req - > status = NT_STATUS_NO_MEMORY ;
goto failed ;
}
req - > buffer . length = req_length ;
}
/* read in the body */
req - > status = socket_recv ( wrepl_socket - > sock ,
req - > buffer . data + req - > num_read ,
req - > buffer . length - req - > num_read ,
& nread , 0 ) ;
2005-09-27 10:31:57 +00:00
if ( NT_STATUS_IS_ERR ( req - > status ) ) {
2005-09-27 16:53:08 +00:00
wrepl_socket_dead ( wrepl_socket , req - > status ) ;
2005-09-27 10:31:57 +00:00
return ;
}
2005-02-16 10:03:18 +00:00
if ( ! NT_STATUS_IS_OK ( req - > status ) ) return ;
req - > num_read + = nread ;
if ( req - > num_read ! = req - > buffer . length ) return ;
req - > packet = talloc ( req , struct wrepl_packet ) ;
if ( req - > packet = = NULL ) {
req - > status = NT_STATUS_NO_MEMORY ;
goto failed ;
}
blob . data = req - > buffer . data + 4 ;
blob . length = req - > buffer . length - 4 ;
/* 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 ) ) {
DEBUG ( 2 , ( " Failed to parse incoming WINS packet - %s \n " ,
nt_errstr ( req - > status ) ) ) ;
2005-07-17 09:20:52 +00:00
DEBUG ( 10 , ( " packet length %d \n " , ( int ) req - > buffer . length ) ) ;
2005-02-16 10:03:18 +00:00
NDR_PRINT_DEBUG ( wrepl_packet , req - > packet ) ;
goto failed ;
}
if ( DEBUGLVL ( 10 ) ) {
2005-07-17 09:20:52 +00:00
DEBUG ( 10 , ( " Received WINS packet of length %d \n " , ( int ) req - > buffer . length ) ) ;
2005-02-16 10:03:18 +00:00
NDR_PRINT_DEBUG ( wrepl_packet , req - > packet ) ;
}
DLIST_REMOVE ( wrepl_socket - > recv_queue , req ) ;
req - > state = WREPL_REQUEST_DONE ;
if ( req - > async . fn ) {
req - > async . fn ( req ) ;
}
return ;
failed :
if ( req - > state = = WREPL_REQUEST_RECV ) {
DLIST_REMOVE ( wrepl_socket - > recv_queue , req ) ;
}
req - > state = WREPL_REQUEST_ERROR ;
if ( req - > async . fn ) {
req - > async . fn ( req ) ;
}
}
/*
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_WRITE ) {
wrepl_handler_send ( wrepl_socket ) ;
}
if ( flags & EVENT_FD_READ ) {
wrepl_handler_recv ( wrepl_socket ) ;
}
}
/*
handler for winrepl connection completion
*/
static void wrepl_connect_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 ) ;
struct wrepl_request * req = wrepl_socket - > recv_queue ;
2005-09-27 16:53:08 +00:00
talloc_free ( wrepl_socket - > fde ) ;
wrepl_socket - > fde = NULL ;
2005-02-16 10:03:18 +00:00
if ( req = = NULL ) return ;
req - > status = socket_connect_complete ( wrepl_socket - > sock , 0 ) ;
if ( NT_STATUS_IS_ERR ( req - > status ) ) goto failed ;
if ( ! NT_STATUS_IS_OK ( req - > status ) ) return ;
wrepl_socket - > fde = event_add_fd ( wrepl_socket - > event_ctx , wrepl_socket ,
socket_get_fd ( wrepl_socket - > sock ) ,
0 ,
wrepl_handler , wrepl_socket ) ;
if ( wrepl_socket - > fde = = NULL ) {
req - > status = NT_STATUS_NO_MEMORY ;
}
failed :
DLIST_REMOVE ( wrepl_socket - > recv_queue , req ) ;
if ( ! NT_STATUS_IS_OK ( req - > status ) ) {
req - > state = WREPL_REQUEST_ERROR ;
} else {
req - > state = WREPL_REQUEST_DONE ;
}
if ( req - > async . fn ) {
req - > async . fn ( req ) ;
}
}
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 ) ;
wrepl_socket_dead ( sock , NT_STATUS_CONNECTION_DISCONNECTED ) ;
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 ;
wrepl_socket = talloc ( mem_ctx , struct wrepl_socket ) ;
if ( wrepl_socket = = NULL ) goto failed ;
if ( event_ctx = = NULL ) {
wrepl_socket - > event_ctx = event_context_init ( wrepl_socket ) ;
} else {
wrepl_socket - > event_ctx = talloc_reference ( wrepl_socket , event_ctx ) ;
}
if ( wrepl_socket - > event_ctx = = NULL ) goto failed ;
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 - > send_queue = NULL ;
wrepl_socket - > recv_queue = NULL ;
wrepl_socket - > request_timeout = WREPL_SOCKET_REQUEST_TIMEOUT ;
wrepl_socket - > dead = False ;
2005-02-16 10:03:18 +00:00
wrepl_socket - > fde = event_add_fd ( wrepl_socket - > event_ctx , wrepl_socket ,
socket_get_fd ( wrepl_socket - > sock ) ,
EVENT_FD_WRITE ,
wrepl_connect_handler , wrepl_socket ) ;
set_blocking ( socket_get_fd ( wrepl_socket - > sock ) , False ) ;
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_SEND ) {
DLIST_REMOVE ( req - > wrepl_socket - > send_queue , req ) ;
}
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 ) {
event_loop_once ( req - > wrepl_socket - > event_ctx ) ;
}
return req - > status ;
}
/*
connect a wrepl_socket to a WINS server
*/
struct wrepl_request * wrepl_connect_send ( struct wrepl_socket * wrepl_socket ,
const char * address )
{
struct wrepl_request * req ;
NTSTATUS status ;
req = talloc_zero ( wrepl_socket , struct wrepl_request ) ;
if ( req = = NULL ) goto failed ;
req - > wrepl_socket = wrepl_socket ;
req - > state = WREPL_REQUEST_RECV ;
DLIST_ADD ( wrepl_socket - > recv_queue , req ) ;
talloc_set_destructor ( req , wrepl_request_destructor ) ;
2005-09-09 16:01:49 +00:00
status = socket_connect ( wrepl_socket - > sock , iface_best_ip ( address ) , 0 , address ,
2005-02-16 10:03:18 +00:00
WINS_REPLICATION_PORT , 0 ) ;
if ( ! NT_STATUS_EQUAL ( status , NT_STATUS_MORE_PROCESSING_REQUIRED ) ) goto failed ;
return req ;
failed :
talloc_free ( req ) ;
return NULL ;
}
/*
connect a wrepl_socket to a WINS server - recv side
*/
NTSTATUS wrepl_connect_recv ( struct wrepl_request * req )
{
return wrepl_request_wait ( req ) ;
}
/*
connect a wrepl_socket to a WINS server - sync API
*/
NTSTATUS wrepl_connect ( struct wrepl_socket * wrepl_socket , const char * address )
{
struct wrepl_request * req = wrepl_connect_send ( wrepl_socket , address ) ;
return wrepl_connect_recv ( req ) ;
}
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
*/
static void wrepl_request_trigger ( struct wrepl_request * req )
{
/* a zero timeout means immediate */
event_add_timed ( req - > wrepl_socket - > event_ctx ,
req , timeval_zero ( ) ,
wrepl_request_trigger_handler , req ) ;
}
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 ,
struct wrepl_packet * packet )
{
struct wrepl_request * req ;
struct wrepl_wrap wrap ;
req = talloc_zero ( wrepl_socket , struct wrepl_request ) ;
if ( req = = NULL ) goto failed ;
2005-09-27 10:31:57 +00:00
if ( wrepl_socket - > dead ) {
req - > wrepl_socket = wrepl_socket ;
req - > state = WREPL_REQUEST_ERROR ;
req - > status = NT_STATUS_INVALID_CONNECTION ;
wrepl_request_trigger ( req ) ;
return req ;
}
2005-02-16 10:03:18 +00:00
req - > wrepl_socket = wrepl_socket ;
req - > state = WREPL_REQUEST_SEND ;
wrap . packet = * packet ;
req - > status = ndr_push_struct_blob ( & req - > buffer , req , & wrap ,
2005-09-27 10:31:57 +00:00
( ndr_push_flags_fn_t ) ndr_push_wrepl_wrap ) ;
2005-02-16 10:03:18 +00:00
if ( ! NT_STATUS_IS_OK ( req - > status ) ) goto failed ;
if ( DEBUGLVL ( 10 ) ) {
2005-07-17 09:20:52 +00:00
DEBUG ( 10 , ( " Sending WINS packet of length %d \n " , ( int ) req - > buffer . length ) ) ;
2005-02-16 10:03:18 +00:00
NDR_PRINT_DEBUG ( wrepl_packet , & wrap . packet ) ;
}
DLIST_ADD ( wrepl_socket - > send_queue , req ) ;
talloc_set_destructor ( req , wrepl_request_destructor ) ;
2005-09-27 16:53:08 +00:00
if ( wrepl_socket - > request_timeout > 0 ) {
req - > te = event_add_timed ( wrepl_socket - > event_ctx , req ,
timeval_current_ofs ( wrepl_socket - > request_timeout , 0 ) ,
wrepl_request_timeout_handler , req ) ;
}
2005-02-16 10:03:18 +00:00
EVENT_FD_WRITEABLE ( wrepl_socket - > fde ) ;
return req ;
failed :
talloc_free ( req ) ;
return NULL ;
}
/*
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 )
{
struct wrepl_request * req = wrepl_request_send ( wrepl_socket , req_packet ) ;
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 ;
req = wrepl_request_send ( wrepl_socket , packet ) ;
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 ) ;
}
/*
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 ;
req = wrepl_request_send ( wrepl_socket , packet ) ;
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 ;
req = wrepl_request_send ( wrepl_socket , packet ) ;
talloc_free ( packet ) ;
return req ;
}
/*
extract a nbt_name from a WINS name buffer
*/
static NTSTATUS wrepl_extract_name ( struct nbt_name * name ,
TALLOC_CTX * mem_ctx ,
uint8_t * namebuf , uint32_t len )
{
char * s ;
/* oh wow, what a nasty bug in windows ... */
if ( namebuf [ 0 ] = = 0x1b & & len > = 16 ) {
namebuf [ 0 ] = namebuf [ 15 ] ;
namebuf [ 15 ] = 0x1b ;
}
if ( len < 17 ) {
2005-09-27 16:53:08 +00:00
make_nbt_name_client ( name , talloc_strndup ( mem_ctx , ( char * ) namebuf , len ) ) ;
2005-02-18 23:13:51 +00:00
return NT_STATUS_OK ;
}
2005-09-27 16:53:08 +00:00
s = talloc_strndup ( mem_ctx , ( char * ) namebuf , 15 ) ;
2005-02-18 23:13:51 +00:00
trim_string ( s , NULL , " " ) ;
name - > name = s ;
name - > type = namebuf [ 15 ] ;
if ( len > 18 ) {
2005-09-27 16:53:08 +00:00
name - > scope = talloc_strndup ( mem_ctx , ( char * ) ( namebuf + 17 ) , len - 17 ) ;
2005-02-18 23:13:51 +00:00
} else {
name - > scope = NULL ;
}
return NT_STATUS_OK ;
}
/*
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 ;
status = NT_STATUS_NO_MEMORY ;
io - > out . names = talloc_array ( packet , struct wrepl_name , io - > out . num_names ) ;
if ( io - > out . names = = NULL ) goto failed ;
/* 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 ] ;
status = wrepl_extract_name ( & name - > name , io - > out . names ,
wname - > name , wname - > name_len ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) goto failed ;
/* 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 ) ;
if ( name - > addresses = = NULL ) goto failed ;
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 ) ;
if ( name - > addresses = = NULL ) goto failed ;
2005-09-09 19:55:34 +00:00
name - > addresses [ 0 ] . owner = io - > in . partner . address ;
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 ) ;
status = NT_STATUS_OK ;
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 ) ;
}