2 Unix SMB/CIFS implementation.
4 low level WINS replication client code
6 Copyright (C) Andrew Tridgell 2005
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "lib/events/events.h"
24 #include "../lib/util/dlinklist.h"
25 #include "lib/socket/socket.h"
26 #include "libcli/wrepl/winsrepl.h"
27 #include "librpc/gen_ndr/ndr_winsrepl.h"
28 #include "lib/stream/packet.h"
29 #include "libcli/composite/composite.h"
30 #include "system/network.h"
31 #include "lib/socket/netif.h"
32 #include "param/param.h"
34 static struct wrepl_request
*wrepl_request_finished(struct wrepl_request
*req
, NTSTATUS status
);
37 mark all pending requests as dead - called when a socket error happens
39 static void wrepl_socket_dead(struct wrepl_socket
*wrepl_socket
, NTSTATUS status
)
41 wrepl_socket
->dead
= true;
43 if (wrepl_socket
->packet
) {
44 packet_recv_disable(wrepl_socket
->packet
);
45 packet_set_fde(wrepl_socket
->packet
, NULL
);
46 packet_set_socket(wrepl_socket
->packet
, NULL
);
49 if (wrepl_socket
->event
.fde
) {
50 talloc_free(wrepl_socket
->event
.fde
);
51 wrepl_socket
->event
.fde
= NULL
;
54 if (wrepl_socket
->sock
) {
55 talloc_free(wrepl_socket
->sock
);
56 wrepl_socket
->sock
= NULL
;
59 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL
, status
)) {
60 status
= NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
62 while (wrepl_socket
->recv_queue
) {
63 struct wrepl_request
*req
= wrepl_socket
->recv_queue
;
64 DLIST_REMOVE(wrepl_socket
->recv_queue
, req
);
65 wrepl_request_finished(req
, status
);
68 talloc_set_destructor(wrepl_socket
, NULL
);
69 if (wrepl_socket
->free_skipped
) {
70 talloc_free(wrepl_socket
);
74 static void wrepl_request_timeout_handler(struct event_context
*ev
, struct timed_event
*te
,
75 struct timeval t
, void *ptr
)
77 struct wrepl_request
*req
= talloc_get_type(ptr
, struct wrepl_request
);
78 wrepl_socket_dead(req
->wrepl_socket
, NT_STATUS_IO_TIMEOUT
);
84 static NTSTATUS
wrepl_finish_recv(void *private, DATA_BLOB packet_blob_in
)
86 struct wrepl_socket
*wrepl_socket
= talloc_get_type(private, struct wrepl_socket
);
87 struct wrepl_request
*req
= wrepl_socket
->recv_queue
;
89 enum ndr_err_code ndr_err
;
92 DEBUG(1,("Received unexpected WINS packet of length %u!\n",
93 (unsigned)packet_blob_in
.length
));
94 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
97 req
->packet
= talloc(req
, struct wrepl_packet
);
98 NT_STATUS_HAVE_NO_MEMORY(req
->packet
);
100 blob
.data
= packet_blob_in
.data
+ 4;
101 blob
.length
= packet_blob_in
.length
- 4;
103 /* we have a full request - parse it */
104 ndr_err
= ndr_pull_struct_blob(&blob
, req
->packet
, wrepl_socket
->iconv_convenience
, req
->packet
,
105 (ndr_pull_flags_fn_t
)ndr_pull_wrepl_packet
);
106 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
107 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
108 wrepl_request_finished(req
, status
);
113 DEBUG(10,("Received WINS packet of length %u\n",
114 (unsigned)packet_blob_in
.length
));
115 NDR_PRINT_DEBUG(wrepl_packet
, req
->packet
);
118 wrepl_request_finished(req
, NT_STATUS_OK
);
123 handler for winrepl events
125 static void wrepl_handler(struct event_context
*ev
, struct fd_event
*fde
,
126 uint16_t flags
, void *private)
128 struct wrepl_socket
*wrepl_socket
= talloc_get_type(private,
129 struct wrepl_socket
);
130 if (flags
& EVENT_FD_READ
) {
131 packet_recv(wrepl_socket
->packet
);
134 if (flags
& EVENT_FD_WRITE
) {
135 packet_queue_run(wrepl_socket
->packet
);
139 static void wrepl_error(void *private, NTSTATUS status
)
141 struct wrepl_socket
*wrepl_socket
= talloc_get_type(private,
142 struct wrepl_socket
);
143 wrepl_socket_dead(wrepl_socket
, status
);
148 destroy a wrepl_socket destructor
150 static int wrepl_socket_destructor(struct wrepl_socket
*sock
)
153 sock
->free_skipped
= true;
156 wrepl_socket_dead(sock
, NT_STATUS_LOCAL_DISCONNECT
);
161 initialise a wrepl_socket. The event_ctx is optional, if provided then
162 operations will use that event context
164 struct wrepl_socket
*wrepl_socket_init(TALLOC_CTX
*mem_ctx
,
165 struct event_context
*event_ctx
,
166 struct smb_iconv_convenience
*iconv_convenience
)
168 struct wrepl_socket
*wrepl_socket
;
171 wrepl_socket
= talloc_zero(mem_ctx
, struct wrepl_socket
);
172 if (!wrepl_socket
) return NULL
;
174 wrepl_socket
->event
.ctx
= talloc_reference(wrepl_socket
, event_ctx
);
175 if (!wrepl_socket
->event
.ctx
) goto failed
;
177 wrepl_socket
->iconv_convenience
= iconv_convenience
;
179 status
= socket_create("ip", SOCKET_TYPE_STREAM
, &wrepl_socket
->sock
, 0);
180 if (!NT_STATUS_IS_OK(status
)) goto failed
;
182 talloc_steal(wrepl_socket
, wrepl_socket
->sock
);
184 wrepl_socket
->request_timeout
= WREPL_SOCKET_REQUEST_TIMEOUT
;
186 talloc_set_destructor(wrepl_socket
, wrepl_socket_destructor
);
191 talloc_free(wrepl_socket
);
196 initialise a wrepl_socket from an already existing connection
198 struct wrepl_socket
*wrepl_socket_merge(TALLOC_CTX
*mem_ctx
,
199 struct event_context
*event_ctx
,
200 struct socket_context
*sock
,
201 struct packet_context
*pack
)
203 struct wrepl_socket
*wrepl_socket
;
205 wrepl_socket
= talloc_zero(mem_ctx
, struct wrepl_socket
);
206 if (wrepl_socket
== NULL
) goto failed
;
208 wrepl_socket
->event
.ctx
= talloc_reference(wrepl_socket
, event_ctx
);
209 if (wrepl_socket
->event
.ctx
== NULL
) goto failed
;
211 wrepl_socket
->sock
= sock
;
212 talloc_steal(wrepl_socket
, wrepl_socket
->sock
);
215 wrepl_socket
->request_timeout
= WREPL_SOCKET_REQUEST_TIMEOUT
;
217 wrepl_socket
->event
.fde
= event_add_fd(wrepl_socket
->event
.ctx
, wrepl_socket
,
218 socket_get_fd(wrepl_socket
->sock
),
220 wrepl_handler
, wrepl_socket
);
221 if (wrepl_socket
->event
.fde
== NULL
) {
225 wrepl_socket
->packet
= pack
;
226 talloc_steal(wrepl_socket
, wrepl_socket
->packet
);
227 packet_set_private(wrepl_socket
->packet
, wrepl_socket
);
228 packet_set_socket(wrepl_socket
->packet
, wrepl_socket
->sock
);
229 packet_set_callback(wrepl_socket
->packet
, wrepl_finish_recv
);
230 packet_set_full_request(wrepl_socket
->packet
, packet_full_request_u32
);
231 packet_set_error_handler(wrepl_socket
->packet
, wrepl_error
);
232 packet_set_event_context(wrepl_socket
->packet
, wrepl_socket
->event
.ctx
);
233 packet_set_fde(wrepl_socket
->packet
, wrepl_socket
->event
.fde
);
234 packet_set_serialise(wrepl_socket
->packet
);
236 talloc_set_destructor(wrepl_socket
, wrepl_socket_destructor
);
241 talloc_free(wrepl_socket
);
246 destroy a wrepl_request
248 static int wrepl_request_destructor(struct wrepl_request
*req
)
250 if (req
->state
== WREPL_REQUEST_RECV
) {
251 DLIST_REMOVE(req
->wrepl_socket
->recv_queue
, req
);
253 req
->state
= WREPL_REQUEST_ERROR
;
258 wait for a request to complete
260 static NTSTATUS
wrepl_request_wait(struct wrepl_request
*req
)
262 NT_STATUS_HAVE_NO_MEMORY(req
);
263 while (req
->state
< WREPL_REQUEST_DONE
) {
264 event_loop_once(req
->wrepl_socket
->event
.ctx
);
269 struct wrepl_connect_state
{
270 struct composite_context
*result
;
271 struct wrepl_socket
*wrepl_socket
;
272 struct composite_context
*creq
;
276 handler for winrepl connection completion
278 static void wrepl_connect_handler(struct composite_context
*creq
)
280 struct wrepl_connect_state
*state
= talloc_get_type(creq
->async
.private_data
,
281 struct wrepl_connect_state
);
282 struct wrepl_socket
*wrepl_socket
= state
->wrepl_socket
;
283 struct composite_context
*result
= state
->result
;
285 result
->status
= socket_connect_recv(state
->creq
);
286 if (!composite_is_ok(result
)) return;
288 wrepl_socket
->event
.fde
= event_add_fd(wrepl_socket
->event
.ctx
, wrepl_socket
,
289 socket_get_fd(wrepl_socket
->sock
),
291 wrepl_handler
, wrepl_socket
);
292 if (composite_nomem(wrepl_socket
->event
.fde
, result
)) return;
294 /* setup the stream -> packet parser */
295 wrepl_socket
->packet
= packet_init(wrepl_socket
);
296 if (composite_nomem(wrepl_socket
->packet
, result
)) return;
297 packet_set_private(wrepl_socket
->packet
, wrepl_socket
);
298 packet_set_socket(wrepl_socket
->packet
, wrepl_socket
->sock
);
299 packet_set_callback(wrepl_socket
->packet
, wrepl_finish_recv
);
300 packet_set_full_request(wrepl_socket
->packet
, packet_full_request_u32
);
301 packet_set_error_handler(wrepl_socket
->packet
, wrepl_error
);
302 packet_set_event_context(wrepl_socket
->packet
, wrepl_socket
->event
.ctx
);
303 packet_set_fde(wrepl_socket
->packet
, wrepl_socket
->event
.fde
);
304 packet_set_serialise(wrepl_socket
->packet
);
306 composite_done(result
);
309 const char *wrepl_best_ip(struct loadparm_context
*lp_ctx
, const char *peer_ip
)
311 struct interface
*ifaces
;
312 load_interfaces(lp_ctx
, lp_interfaces(lp_ctx
), &ifaces
);
313 return iface_best_ip(ifaces
, peer_ip
);
318 connect a wrepl_socket to a WINS server
320 struct composite_context
*wrepl_connect_send(struct wrepl_socket
*wrepl_socket
,
321 const char *our_ip
, const char *peer_ip
)
323 struct composite_context
*result
;
324 struct wrepl_connect_state
*state
;
325 struct socket_address
*peer
, *us
;
327 result
= talloc_zero(wrepl_socket
, struct composite_context
);
328 if (!result
) return NULL
;
330 result
->state
= COMPOSITE_STATE_IN_PROGRESS
;
331 result
->event_ctx
= wrepl_socket
->event
.ctx
;
333 state
= talloc_zero(result
, struct wrepl_connect_state
);
334 if (composite_nomem(state
, result
)) return result
;
335 result
->private_data
= state
;
336 state
->result
= result
;
337 state
->wrepl_socket
= wrepl_socket
;
339 us
= socket_address_from_strings(state
, wrepl_socket
->sock
->backend_name
,
341 if (composite_nomem(us
, result
)) return result
;
343 peer
= socket_address_from_strings(state
, wrepl_socket
->sock
->backend_name
,
344 peer_ip
, WINS_REPLICATION_PORT
);
345 if (composite_nomem(peer
, result
)) return result
;
347 state
->creq
= socket_connect_send(wrepl_socket
->sock
, us
, peer
,
348 0, wrepl_socket
->event
.ctx
);
349 composite_continue(result
, state
->creq
, wrepl_connect_handler
, state
);
354 connect a wrepl_socket to a WINS server - recv side
356 NTSTATUS
wrepl_connect_recv(struct composite_context
*result
)
358 struct wrepl_connect_state
*state
= talloc_get_type(result
->private_data
,
359 struct wrepl_connect_state
);
360 struct wrepl_socket
*wrepl_socket
= state
->wrepl_socket
;
361 NTSTATUS status
= composite_wait(result
);
363 if (!NT_STATUS_IS_OK(status
)) {
364 wrepl_socket_dead(wrepl_socket
, status
);
372 connect a wrepl_socket to a WINS server - sync API
374 NTSTATUS
wrepl_connect(struct wrepl_socket
*wrepl_socket
,
375 const char *our_ip
, const char *peer_ip
)
377 struct composite_context
*c_req
= wrepl_connect_send(wrepl_socket
, our_ip
, peer_ip
);
378 return wrepl_connect_recv(c_req
);
382 callback from wrepl_request_trigger()
384 static void wrepl_request_trigger_handler(struct event_context
*ev
, struct timed_event
*te
,
385 struct timeval t
, void *ptr
)
387 struct wrepl_request
*req
= talloc_get_type(ptr
, struct wrepl_request
);
394 trigger an immediate event on a wrepl_request
395 the return value should only be used in wrepl_request_send()
396 this is the only place where req->trigger is true
398 static struct wrepl_request
*wrepl_request_finished(struct wrepl_request
*req
, NTSTATUS status
)
400 struct timed_event
*te
;
402 if (req
->state
== WREPL_REQUEST_RECV
) {
403 DLIST_REMOVE(req
->wrepl_socket
->recv_queue
, req
);
406 if (!NT_STATUS_IS_OK(status
)) {
407 req
->state
= WREPL_REQUEST_ERROR
;
409 req
->state
= WREPL_REQUEST_DONE
;
412 req
->status
= status
;
415 req
->trigger
= false;
416 /* a zero timeout means immediate */
417 te
= event_add_timed(req
->wrepl_socket
->event
.ctx
,
419 wrepl_request_trigger_handler
, req
);
433 struct wrepl_send_ctrl_state
{
434 struct wrepl_send_ctrl ctrl
;
435 struct wrepl_request
*req
;
436 struct wrepl_socket
*wrepl_sock
;
439 static int wrepl_send_ctrl_destructor(struct wrepl_send_ctrl_state
*s
)
441 struct wrepl_request
*req
= s
->wrepl_sock
->recv_queue
;
443 /* check if the request is still in WREPL_STATE_RECV,
444 * we need this here because the caller has may called
445 * talloc_free(req) and wrepl_send_ctrl_state isn't
446 * a talloc child of the request, so our s->req pointer
449 for (; req
; req
= req
->next
) {
450 if (req
== s
->req
) break;
454 /* here, we need to make sure the async request handler is called
455 * later in the next event_loop and now now
458 wrepl_request_finished(req
, NT_STATUS_OK
);
460 if (s
->ctrl
.disconnect_after_send
) {
461 wrepl_socket_dead(s
->wrepl_sock
, NT_STATUS_LOCAL_DISCONNECT
);
468 send a generic wins replication request
470 struct wrepl_request
*wrepl_request_send(struct wrepl_socket
*wrepl_socket
,
471 struct wrepl_packet
*packet
,
472 struct wrepl_send_ctrl
*ctrl
)
474 struct wrepl_request
*req
;
475 struct wrepl_wrap wrap
;
478 enum ndr_err_code ndr_err
;
480 req
= talloc_zero(wrepl_socket
, struct wrepl_request
);
481 if (!req
) return NULL
;
482 req
->wrepl_socket
= wrepl_socket
;
483 req
->state
= WREPL_REQUEST_RECV
;
486 DLIST_ADD_END(wrepl_socket
->recv_queue
, req
, struct wrepl_request
*);
487 talloc_set_destructor(req
, wrepl_request_destructor
);
489 if (wrepl_socket
->dead
) {
490 return wrepl_request_finished(req
, NT_STATUS_INVALID_CONNECTION
);
493 wrap
.packet
= *packet
;
494 ndr_err
= ndr_push_struct_blob(&blob
, req
, wrepl_socket
->iconv_convenience
, &wrap
,
495 (ndr_push_flags_fn_t
)ndr_push_wrepl_wrap
);
496 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
497 status
= ndr_map_error2ntstatus(ndr_err
);
498 return wrepl_request_finished(req
, status
);
502 DEBUG(10,("Sending WINS packet of length %u\n",
503 (unsigned)blob
.length
));
504 NDR_PRINT_DEBUG(wrepl_packet
, &wrap
.packet
);
507 if (wrepl_socket
->request_timeout
> 0) {
508 req
->te
= event_add_timed(wrepl_socket
->event
.ctx
, req
,
509 timeval_current_ofs(wrepl_socket
->request_timeout
, 0),
510 wrepl_request_timeout_handler
, req
);
511 if (!req
->te
) return wrepl_request_finished(req
, NT_STATUS_NO_MEMORY
);
514 if (ctrl
&& (ctrl
->send_only
|| ctrl
->disconnect_after_send
)) {
515 struct wrepl_send_ctrl_state
*s
= talloc(blob
.data
, struct wrepl_send_ctrl_state
);
516 if (!s
) return wrepl_request_finished(req
, NT_STATUS_NO_MEMORY
);
519 s
->wrepl_sock
= wrepl_socket
;
520 talloc_set_destructor(s
, wrepl_send_ctrl_destructor
);
523 status
= packet_send(wrepl_socket
->packet
, blob
);
524 if (!NT_STATUS_IS_OK(status
)) {
525 return wrepl_request_finished(req
, status
);
528 req
->trigger
= false;
533 receive a generic WINS replication reply
535 NTSTATUS
wrepl_request_recv(struct wrepl_request
*req
,
537 struct wrepl_packet
**packet
)
539 NTSTATUS status
= wrepl_request_wait(req
);
540 if (NT_STATUS_IS_OK(status
) && packet
) {
541 *packet
= talloc_steal(mem_ctx
, req
->packet
);
548 a full WINS replication request/response
550 NTSTATUS
wrepl_request(struct wrepl_socket
*wrepl_socket
,
552 struct wrepl_packet
*req_packet
,
553 struct wrepl_packet
**reply_packet
)
555 struct wrepl_request
*req
= wrepl_request_send(wrepl_socket
, req_packet
, NULL
);
556 return wrepl_request_recv(req
, mem_ctx
, reply_packet
);
561 setup an association - send
563 struct wrepl_request
*wrepl_associate_send(struct wrepl_socket
*wrepl_socket
,
564 struct wrepl_associate
*io
)
566 struct wrepl_packet
*packet
;
567 struct wrepl_request
*req
;
569 packet
= talloc_zero(wrepl_socket
, struct wrepl_packet
);
570 if (packet
== NULL
) return NULL
;
572 packet
->opcode
= WREPL_OPCODE_BITS
;
573 packet
->mess_type
= WREPL_START_ASSOCIATION
;
574 packet
->message
.start
.minor_version
= 2;
575 packet
->message
.start
.major_version
= 5;
578 * nt4 uses 41 bytes for the start_association call
579 * so do it the same and as we don't know th emeanings of this bytes
580 * we just send zeros and nt4, w2k and w2k3 seems to be happy with this
582 * if we don't do this nt4 uses an old version of the wins replication protocol
583 * and that would break nt4 <-> samba replication
585 packet
->padding
= data_blob_talloc(packet
, NULL
, 21);
586 if (packet
->padding
.data
== NULL
) {
590 memset(packet
->padding
.data
, 0, packet
->padding
.length
);
592 req
= wrepl_request_send(wrepl_socket
, packet
, NULL
);
600 setup an association - recv
602 NTSTATUS
wrepl_associate_recv(struct wrepl_request
*req
,
603 struct wrepl_associate
*io
)
605 struct wrepl_packet
*packet
=NULL
;
607 status
= wrepl_request_recv(req
, req
->wrepl_socket
, &packet
);
608 NT_STATUS_NOT_OK_RETURN(status
);
609 if (packet
->mess_type
!= WREPL_START_ASSOCIATION_REPLY
) {
610 status
= NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
612 if (NT_STATUS_IS_OK(status
)) {
613 io
->out
.assoc_ctx
= packet
->message
.start_reply
.assoc_ctx
;
620 setup an association - sync api
622 NTSTATUS
wrepl_associate(struct wrepl_socket
*wrepl_socket
,
623 struct wrepl_associate
*io
)
625 struct wrepl_request
*req
= wrepl_associate_send(wrepl_socket
, io
);
626 return wrepl_associate_recv(req
, io
);
631 stop an association - send
633 struct wrepl_request
*wrepl_associate_stop_send(struct wrepl_socket
*wrepl_socket
,
634 struct wrepl_associate_stop
*io
)
636 struct wrepl_packet
*packet
;
637 struct wrepl_request
*req
;
638 struct wrepl_send_ctrl ctrl
;
640 packet
= talloc_zero(wrepl_socket
, struct wrepl_packet
);
641 if (packet
== NULL
) return NULL
;
643 packet
->opcode
= WREPL_OPCODE_BITS
;
644 packet
->assoc_ctx
= io
->in
.assoc_ctx
;
645 packet
->mess_type
= WREPL_STOP_ASSOCIATION
;
646 packet
->message
.stop
.reason
= io
->in
.reason
;
649 if (io
->in
.reason
== 0) {
650 ctrl
.send_only
= true;
651 ctrl
.disconnect_after_send
= true;
654 req
= wrepl_request_send(wrepl_socket
, packet
, &ctrl
);
662 stop an association - recv
664 NTSTATUS
wrepl_associate_stop_recv(struct wrepl_request
*req
,
665 struct wrepl_associate_stop
*io
)
667 struct wrepl_packet
*packet
=NULL
;
669 status
= wrepl_request_recv(req
, req
->wrepl_socket
, &packet
);
670 NT_STATUS_NOT_OK_RETURN(status
);
676 setup an association - sync api
678 NTSTATUS
wrepl_associate_stop(struct wrepl_socket
*wrepl_socket
,
679 struct wrepl_associate_stop
*io
)
681 struct wrepl_request
*req
= wrepl_associate_stop_send(wrepl_socket
, io
);
682 return wrepl_associate_stop_recv(req
, io
);
686 fetch the partner tables - send
688 struct wrepl_request
*wrepl_pull_table_send(struct wrepl_socket
*wrepl_socket
,
689 struct wrepl_pull_table
*io
)
691 struct wrepl_packet
*packet
;
692 struct wrepl_request
*req
;
694 packet
= talloc_zero(wrepl_socket
, struct wrepl_packet
);
695 if (packet
== NULL
) return NULL
;
697 packet
->opcode
= WREPL_OPCODE_BITS
;
698 packet
->assoc_ctx
= io
->in
.assoc_ctx
;
699 packet
->mess_type
= WREPL_REPLICATION
;
700 packet
->message
.replication
.command
= WREPL_REPL_TABLE_QUERY
;
702 req
= wrepl_request_send(wrepl_socket
, packet
, NULL
);
711 fetch the partner tables - recv
713 NTSTATUS
wrepl_pull_table_recv(struct wrepl_request
*req
,
715 struct wrepl_pull_table
*io
)
717 struct wrepl_packet
*packet
=NULL
;
719 struct wrepl_table
*table
;
722 status
= wrepl_request_recv(req
, req
->wrepl_socket
, &packet
);
723 NT_STATUS_NOT_OK_RETURN(status
);
724 if (packet
->mess_type
!= WREPL_REPLICATION
) {
725 status
= NT_STATUS_NETWORK_ACCESS_DENIED
;
726 } else if (packet
->message
.replication
.command
!= WREPL_REPL_TABLE_REPLY
) {
727 status
= NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
729 if (!NT_STATUS_IS_OK(status
)) goto failed
;
731 table
= &packet
->message
.replication
.info
.table
;
732 io
->out
.num_partners
= table
->partner_count
;
733 io
->out
.partners
= talloc_steal(mem_ctx
, table
->partners
);
734 for (i
=0;i
<io
->out
.num_partners
;i
++) {
735 talloc_steal(io
->out
.partners
, io
->out
.partners
[i
].address
);
745 fetch the partner table - sync api
747 NTSTATUS
wrepl_pull_table(struct wrepl_socket
*wrepl_socket
,
749 struct wrepl_pull_table
*io
)
751 struct wrepl_request
*req
= wrepl_pull_table_send(wrepl_socket
, io
);
752 return wrepl_pull_table_recv(req
, mem_ctx
, io
);
757 fetch the names for a WINS partner - send
759 struct wrepl_request
*wrepl_pull_names_send(struct wrepl_socket
*wrepl_socket
,
760 struct wrepl_pull_names
*io
)
762 struct wrepl_packet
*packet
;
763 struct wrepl_request
*req
;
765 packet
= talloc_zero(wrepl_socket
, struct wrepl_packet
);
766 if (packet
== NULL
) return NULL
;
768 packet
->opcode
= WREPL_OPCODE_BITS
;
769 packet
->assoc_ctx
= io
->in
.assoc_ctx
;
770 packet
->mess_type
= WREPL_REPLICATION
;
771 packet
->message
.replication
.command
= WREPL_REPL_SEND_REQUEST
;
772 packet
->message
.replication
.info
.owner
= io
->in
.partner
;
774 req
= wrepl_request_send(wrepl_socket
, packet
, NULL
);
782 fetch the names for a WINS partner - recv
784 NTSTATUS
wrepl_pull_names_recv(struct wrepl_request
*req
,
786 struct wrepl_pull_names
*io
)
788 struct wrepl_packet
*packet
=NULL
;
792 status
= wrepl_request_recv(req
, req
->wrepl_socket
, &packet
);
793 NT_STATUS_NOT_OK_RETURN(status
);
794 if (packet
->mess_type
!= WREPL_REPLICATION
||
795 packet
->message
.replication
.command
!= WREPL_REPL_SEND_REPLY
) {
796 status
= NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
798 if (!NT_STATUS_IS_OK(status
)) goto failed
;
800 io
->out
.num_names
= packet
->message
.replication
.info
.reply
.num_names
;
802 io
->out
.names
= talloc_array(packet
, struct wrepl_name
, io
->out
.num_names
);
803 if (io
->out
.names
== NULL
) goto nomem
;
805 /* convert the list of names and addresses to a sane format */
806 for (i
=0;i
<io
->out
.num_names
;i
++) {
807 struct wrepl_wins_name
*wname
= &packet
->message
.replication
.info
.reply
.names
[i
];
808 struct wrepl_name
*name
= &io
->out
.names
[i
];
810 name
->name
= *wname
->name
;
811 talloc_steal(io
->out
.names
, wname
->name
);
812 name
->type
= WREPL_NAME_TYPE(wname
->flags
);
813 name
->state
= WREPL_NAME_STATE(wname
->flags
);
814 name
->node
= WREPL_NAME_NODE(wname
->flags
);
815 name
->is_static
= WREPL_NAME_IS_STATIC(wname
->flags
);
816 name
->raw_flags
= wname
->flags
;
817 name
->version_id
= wname
->id
;
818 name
->owner
= talloc_strdup(io
->out
.names
, io
->in
.partner
.address
);
819 if (name
->owner
== NULL
) goto nomem
;
821 /* trying to save 1 or 2 bytes on the wire isn't a good idea */
822 if (wname
->flags
& 2) {
825 name
->num_addresses
= wname
->addresses
.addresses
.num_ips
;
826 name
->addresses
= talloc_array(io
->out
.names
,
827 struct wrepl_address
,
828 name
->num_addresses
);
829 if (name
->addresses
== NULL
) goto nomem
;
830 for (j
=0;j
<name
->num_addresses
;j
++) {
831 name
->addresses
[j
].owner
=
832 talloc_steal(name
->addresses
,
833 wname
->addresses
.addresses
.ips
[j
].owner
);
834 name
->addresses
[j
].address
=
835 talloc_steal(name
->addresses
,
836 wname
->addresses
.addresses
.ips
[j
].ip
);
839 name
->num_addresses
= 1;
840 name
->addresses
= talloc(io
->out
.names
, struct wrepl_address
);
841 if (name
->addresses
== NULL
) goto nomem
;
842 name
->addresses
[0].owner
= talloc_strdup(name
->addresses
,io
->in
.partner
.address
);
843 if (name
->addresses
[0].owner
== NULL
) goto nomem
;
844 name
->addresses
[0].address
= talloc_steal(name
->addresses
,
845 wname
->addresses
.ip
);
849 talloc_steal(mem_ctx
, io
->out
.names
);
853 status
= NT_STATUS_NO_MEMORY
;
862 fetch the names for a WINS partner - sync api
864 NTSTATUS
wrepl_pull_names(struct wrepl_socket
*wrepl_socket
,
866 struct wrepl_pull_names
*io
)
868 struct wrepl_request
*req
= wrepl_pull_names_send(wrepl_socket
, io
);
869 return wrepl_pull_names_recv(req
, mem_ctx
, io
);