2 Unix SMB/CIFS implementation.
4 low level WINS replication client code
6 Copyright (C) Andrew Tridgell 2005
7 Copyright (C) Stefan Metzmacher 2005-2010
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "lib/events/events.h"
25 #include "../lib/util/dlinklist.h"
26 #include "lib/socket/socket.h"
27 #include "libcli/wrepl/winsrepl.h"
28 #include "librpc/gen_ndr/ndr_winsrepl.h"
29 #include "lib/stream/packet.h"
30 #include "libcli/composite/composite.h"
31 #include "system/network.h"
32 #include "lib/socket/netif.h"
33 #include "param/param.h"
34 #include "lib/util/tevent_ntstatus.h"
36 static struct wrepl_request
*wrepl_request_finished(struct wrepl_request
*req
, NTSTATUS status
);
39 mark all pending requests as dead - called when a socket error happens
41 static void wrepl_socket_dead(struct wrepl_socket
*wrepl_socket
, NTSTATUS status
)
43 wrepl_socket
->dead
= true;
45 if (wrepl_socket
->packet
) {
46 packet_recv_disable(wrepl_socket
->packet
);
47 packet_set_fde(wrepl_socket
->packet
, NULL
);
48 packet_set_socket(wrepl_socket
->packet
, NULL
);
51 if (wrepl_socket
->event
.fde
) {
52 talloc_free(wrepl_socket
->event
.fde
);
53 wrepl_socket
->event
.fde
= NULL
;
56 if (wrepl_socket
->sock
) {
57 talloc_free(wrepl_socket
->sock
);
58 wrepl_socket
->sock
= NULL
;
61 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL
, status
)) {
62 status
= NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
64 while (wrepl_socket
->recv_queue
) {
65 struct wrepl_request
*req
= wrepl_socket
->recv_queue
;
66 DLIST_REMOVE(wrepl_socket
->recv_queue
, req
);
67 wrepl_request_finished(req
, status
);
70 talloc_set_destructor(wrepl_socket
, NULL
);
71 if (wrepl_socket
->free_skipped
) {
72 talloc_free(wrepl_socket
);
76 static void wrepl_request_timeout_handler(struct tevent_context
*ev
, struct tevent_timer
*te
,
77 struct timeval t
, void *ptr
)
79 struct wrepl_request
*req
= talloc_get_type(ptr
, struct wrepl_request
);
80 wrepl_socket_dead(req
->wrepl_socket
, NT_STATUS_IO_TIMEOUT
);
86 static NTSTATUS
wrepl_finish_recv(void *private_data
, DATA_BLOB packet_blob_in
)
88 struct wrepl_socket
*wrepl_socket
= talloc_get_type(private_data
, struct wrepl_socket
);
89 struct wrepl_request
*req
= wrepl_socket
->recv_queue
;
91 enum ndr_err_code ndr_err
;
94 DEBUG(1,("Received unexpected WINS packet of length %u!\n",
95 (unsigned)packet_blob_in
.length
));
96 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
99 req
->packet
= talloc(req
, struct wrepl_packet
);
100 NT_STATUS_HAVE_NO_MEMORY(req
->packet
);
102 blob
.data
= packet_blob_in
.data
+ 4;
103 blob
.length
= packet_blob_in
.length
- 4;
105 /* we have a full request - parse it */
106 ndr_err
= ndr_pull_struct_blob(&blob
, req
->packet
, wrepl_socket
->iconv_convenience
, req
->packet
,
107 (ndr_pull_flags_fn_t
)ndr_pull_wrepl_packet
);
108 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
109 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
110 wrepl_request_finished(req
, status
);
115 DEBUG(10,("Received WINS packet of length %u\n",
116 (unsigned)packet_blob_in
.length
));
117 NDR_PRINT_DEBUG(wrepl_packet
, req
->packet
);
120 wrepl_request_finished(req
, NT_STATUS_OK
);
125 handler for winrepl events
127 static void wrepl_handler(struct tevent_context
*ev
, struct tevent_fd
*fde
,
128 uint16_t flags
, void *private_data
)
130 struct wrepl_socket
*wrepl_socket
= talloc_get_type(private_data
,
131 struct wrepl_socket
);
132 if (flags
& EVENT_FD_READ
) {
133 packet_recv(wrepl_socket
->packet
);
136 if (flags
& EVENT_FD_WRITE
) {
137 packet_queue_run(wrepl_socket
->packet
);
141 static void wrepl_error(void *private_data
, NTSTATUS status
)
143 struct wrepl_socket
*wrepl_socket
= talloc_get_type(private_data
,
144 struct wrepl_socket
);
145 wrepl_socket_dead(wrepl_socket
, status
);
150 destroy a wrepl_socket destructor
152 static int wrepl_socket_destructor(struct wrepl_socket
*sock
)
155 sock
->free_skipped
= true;
158 wrepl_socket_dead(sock
, NT_STATUS_LOCAL_DISCONNECT
);
163 initialise a wrepl_socket. The event_ctx is optional, if provided then
164 operations will use that event context
166 struct wrepl_socket
*wrepl_socket_init(TALLOC_CTX
*mem_ctx
,
167 struct tevent_context
*event_ctx
,
168 struct smb_iconv_convenience
*iconv_convenience
)
170 struct wrepl_socket
*wrepl_socket
;
173 wrepl_socket
= talloc_zero(mem_ctx
, struct wrepl_socket
);
174 if (!wrepl_socket
) return NULL
;
176 wrepl_socket
->event
.ctx
= event_ctx
;
177 if (!wrepl_socket
->event
.ctx
) goto failed
;
179 wrepl_socket
->iconv_convenience
= iconv_convenience
;
181 status
= socket_create("ip", SOCKET_TYPE_STREAM
, &wrepl_socket
->sock
, 0);
182 if (!NT_STATUS_IS_OK(status
)) goto failed
;
184 talloc_steal(wrepl_socket
, wrepl_socket
->sock
);
186 wrepl_socket
->request_timeout
= WREPL_SOCKET_REQUEST_TIMEOUT
;
188 talloc_set_destructor(wrepl_socket
, wrepl_socket_destructor
);
193 talloc_free(wrepl_socket
);
198 initialise a wrepl_socket from an already existing connection
200 struct wrepl_socket
*wrepl_socket_merge(TALLOC_CTX
*mem_ctx
,
201 struct tevent_context
*event_ctx
,
202 struct socket_context
*sock
,
203 struct packet_context
*pack
)
205 struct wrepl_socket
*wrepl_socket
;
207 wrepl_socket
= talloc_zero(mem_ctx
, struct wrepl_socket
);
208 if (wrepl_socket
== NULL
) goto failed
;
210 wrepl_socket
->event
.ctx
= event_ctx
;
211 if (wrepl_socket
->event
.ctx
== NULL
) goto failed
;
213 wrepl_socket
->sock
= sock
;
214 talloc_steal(wrepl_socket
, wrepl_socket
->sock
);
217 wrepl_socket
->request_timeout
= WREPL_SOCKET_REQUEST_TIMEOUT
;
219 wrepl_socket
->event
.fde
= event_add_fd(wrepl_socket
->event
.ctx
, wrepl_socket
,
220 socket_get_fd(wrepl_socket
->sock
),
222 wrepl_handler
, wrepl_socket
);
223 if (wrepl_socket
->event
.fde
== NULL
) {
227 wrepl_socket
->packet
= pack
;
228 talloc_steal(wrepl_socket
, wrepl_socket
->packet
);
229 packet_set_private(wrepl_socket
->packet
, wrepl_socket
);
230 packet_set_socket(wrepl_socket
->packet
, wrepl_socket
->sock
);
231 packet_set_callback(wrepl_socket
->packet
, wrepl_finish_recv
);
232 packet_set_full_request(wrepl_socket
->packet
, packet_full_request_u32
);
233 packet_set_error_handler(wrepl_socket
->packet
, wrepl_error
);
234 packet_set_event_context(wrepl_socket
->packet
, wrepl_socket
->event
.ctx
);
235 packet_set_fde(wrepl_socket
->packet
, wrepl_socket
->event
.fde
);
236 packet_set_serialise(wrepl_socket
->packet
);
238 talloc_set_destructor(wrepl_socket
, wrepl_socket_destructor
);
243 talloc_free(wrepl_socket
);
248 destroy a wrepl_request
250 static int wrepl_request_destructor(struct wrepl_request
*req
)
252 if (req
->state
== WREPL_REQUEST_RECV
) {
253 DLIST_REMOVE(req
->wrepl_socket
->recv_queue
, req
);
255 req
->state
= WREPL_REQUEST_ERROR
;
260 wait for a request to complete
262 static NTSTATUS
wrepl_request_wait(struct wrepl_request
*req
)
264 NT_STATUS_HAVE_NO_MEMORY(req
);
265 while (req
->state
< WREPL_REQUEST_DONE
) {
266 event_loop_once(req
->wrepl_socket
->event
.ctx
);
271 const char *wrepl_best_ip(struct loadparm_context
*lp_ctx
, const char *peer_ip
)
273 struct interface
*ifaces
;
274 load_interfaces(lp_ctx
, lp_interfaces(lp_ctx
), &ifaces
);
275 return iface_best_ip(ifaces
, peer_ip
);
278 struct wrepl_connect_state
{
279 struct wrepl_socket
*wrepl_socket
;
282 static void wrepl_connect_handler(struct composite_context
*creq
);
284 struct tevent_req
*wrepl_connect_send(TALLOC_CTX
*mem_ctx
,
285 struct tevent_context
*ev
,
286 struct wrepl_socket
*wrepl_socket
,
287 const char *our_ip
, const char *peer_ip
)
289 struct tevent_req
*req
;
290 struct wrepl_connect_state
*state
;
291 struct composite_context
*subreq
;
292 struct socket_address
*peer
, *us
;
294 req
= tevent_req_create(mem_ctx
, &state
,
295 struct wrepl_connect_state
);
300 state
->wrepl_socket
= wrepl_socket
;
302 us
= socket_address_from_strings(state
, wrepl_socket
->sock
->backend_name
,
304 if (tevent_req_nomem(us
, req
)) {
305 return tevent_req_post(req
, ev
);
308 peer
= socket_address_from_strings(state
, wrepl_socket
->sock
->backend_name
,
309 peer_ip
, WINS_REPLICATION_PORT
);
310 if (tevent_req_nomem(peer
, req
)) {
311 return tevent_req_post(req
, ev
);
314 subreq
= socket_connect_send(wrepl_socket
->sock
, us
, peer
,
315 0, wrepl_socket
->event
.ctx
);
316 if (tevent_req_nomem(subreq
, req
)) {
317 return tevent_req_post(req
, ev
);
320 subreq
->async
.fn
= wrepl_connect_handler
;
321 subreq
->async
.private_data
= req
;
326 static void wrepl_connect_handler(struct composite_context
*subreq
)
328 struct tevent_req
*req
= talloc_get_type_abort(subreq
->async
.private_data
,
330 struct wrepl_connect_state
*state
= tevent_req_data(req
,
331 struct wrepl_connect_state
);
332 struct wrepl_socket
*wrepl_socket
= state
->wrepl_socket
;
335 status
= socket_connect_recv(subreq
);
336 if (!NT_STATUS_IS_OK(status
)) {
337 tevent_req_nterror(req
, status
);
341 wrepl_socket
->event
.fde
= event_add_fd(wrepl_socket
->event
.ctx
, wrepl_socket
,
342 socket_get_fd(wrepl_socket
->sock
),
344 wrepl_handler
, wrepl_socket
);
345 if (tevent_req_nomem(wrepl_socket
->event
.fde
, req
)) {
349 /* setup the stream -> packet parser */
350 wrepl_socket
->packet
= packet_init(wrepl_socket
);
351 if (tevent_req_nomem(wrepl_socket
->packet
, req
)) {
354 packet_set_private(wrepl_socket
->packet
, wrepl_socket
);
355 packet_set_socket(wrepl_socket
->packet
, wrepl_socket
->sock
);
356 packet_set_callback(wrepl_socket
->packet
, wrepl_finish_recv
);
357 packet_set_full_request(wrepl_socket
->packet
, packet_full_request_u32
);
358 packet_set_error_handler(wrepl_socket
->packet
, wrepl_error
);
359 packet_set_event_context(wrepl_socket
->packet
, wrepl_socket
->event
.ctx
);
360 packet_set_fde(wrepl_socket
->packet
, wrepl_socket
->event
.fde
);
361 packet_set_serialise(wrepl_socket
->packet
);
363 tevent_req_done(req
);
367 connect a wrepl_socket to a WINS server - recv side
369 NTSTATUS
wrepl_connect_recv(struct tevent_req
*req
)
371 struct wrepl_connect_state
*state
= tevent_req_data(req
,
372 struct wrepl_connect_state
);
373 struct wrepl_socket
*wrepl_socket
= state
->wrepl_socket
;
376 if (tevent_req_is_nterror(req
, &status
)) {
377 wrepl_socket_dead(wrepl_socket
, status
);
378 tevent_req_received(req
);
382 tevent_req_received(req
);
387 connect a wrepl_socket to a WINS server - sync API
389 NTSTATUS
wrepl_connect(struct wrepl_socket
*wrepl_socket
,
390 const char *our_ip
, const char *peer_ip
)
392 struct tevent_req
*subreq
;
396 subreq
= wrepl_connect_send(wrepl_socket
, wrepl_socket
->event
.ctx
,
397 wrepl_socket
, our_ip
, peer_ip
);
398 NT_STATUS_HAVE_NO_MEMORY(subreq
);
400 ok
= tevent_req_poll(subreq
, wrepl_socket
->event
.ctx
);
403 return NT_STATUS_INTERNAL_ERROR
;
406 status
= wrepl_connect_recv(subreq
);
408 NT_STATUS_NOT_OK_RETURN(status
);
414 callback from wrepl_request_trigger()
416 static void wrepl_request_trigger_handler(struct tevent_context
*ev
, struct tevent_timer
*te
,
417 struct timeval t
, void *ptr
)
419 struct wrepl_request
*req
= talloc_get_type(ptr
, struct wrepl_request
);
426 trigger an immediate event on a wrepl_request
427 the return value should only be used in wrepl_request_send()
428 this is the only place where req->trigger is true
430 static struct wrepl_request
*wrepl_request_finished(struct wrepl_request
*req
, NTSTATUS status
)
432 struct tevent_timer
*te
;
434 if (req
->state
== WREPL_REQUEST_RECV
) {
435 DLIST_REMOVE(req
->wrepl_socket
->recv_queue
, req
);
438 if (!NT_STATUS_IS_OK(status
)) {
439 req
->state
= WREPL_REQUEST_ERROR
;
441 req
->state
= WREPL_REQUEST_DONE
;
444 req
->status
= status
;
447 req
->trigger
= false;
448 /* a zero timeout means immediate */
449 te
= event_add_timed(req
->wrepl_socket
->event
.ctx
,
451 wrepl_request_trigger_handler
, req
);
465 struct wrepl_send_ctrl_state
{
466 struct wrepl_send_ctrl ctrl
;
467 struct wrepl_request
*req
;
468 struct wrepl_socket
*wrepl_sock
;
471 static int wrepl_send_ctrl_destructor(struct wrepl_send_ctrl_state
*s
)
473 struct wrepl_request
*req
= s
->wrepl_sock
->recv_queue
;
475 /* check if the request is still in WREPL_STATE_RECV,
476 * we need this here because the caller has may called
477 * talloc_free(req) and wrepl_send_ctrl_state isn't
478 * a talloc child of the request, so our s->req pointer
481 for (; req
; req
= req
->next
) {
482 if (req
== s
->req
) break;
486 /* here, we need to make sure the async request handler is called
487 * later in the next event_loop and now now
490 wrepl_request_finished(req
, NT_STATUS_OK
);
492 if (s
->ctrl
.disconnect_after_send
) {
493 wrepl_socket_dead(s
->wrepl_sock
, NT_STATUS_LOCAL_DISCONNECT
);
500 send a generic wins replication request
502 struct wrepl_request
*wrepl_request_send(struct wrepl_socket
*wrepl_socket
,
503 struct wrepl_packet
*packet
,
504 struct wrepl_send_ctrl
*ctrl
)
506 struct wrepl_request
*req
;
507 struct wrepl_wrap wrap
;
510 enum ndr_err_code ndr_err
;
512 req
= talloc_zero(wrepl_socket
, struct wrepl_request
);
513 if (!req
) return NULL
;
514 req
->wrepl_socket
= wrepl_socket
;
515 req
->state
= WREPL_REQUEST_RECV
;
518 DLIST_ADD_END(wrepl_socket
->recv_queue
, req
, struct wrepl_request
*);
519 talloc_set_destructor(req
, wrepl_request_destructor
);
521 if (wrepl_socket
->dead
) {
522 return wrepl_request_finished(req
, NT_STATUS_INVALID_CONNECTION
);
525 wrap
.packet
= *packet
;
526 ndr_err
= ndr_push_struct_blob(&blob
, req
, wrepl_socket
->iconv_convenience
, &wrap
,
527 (ndr_push_flags_fn_t
)ndr_push_wrepl_wrap
);
528 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
529 status
= ndr_map_error2ntstatus(ndr_err
);
530 return wrepl_request_finished(req
, status
);
534 DEBUG(10,("Sending WINS packet of length %u\n",
535 (unsigned)blob
.length
));
536 NDR_PRINT_DEBUG(wrepl_packet
, &wrap
.packet
);
539 if (wrepl_socket
->request_timeout
> 0) {
540 req
->te
= event_add_timed(wrepl_socket
->event
.ctx
, req
,
541 timeval_current_ofs(wrepl_socket
->request_timeout
, 0),
542 wrepl_request_timeout_handler
, req
);
543 if (!req
->te
) return wrepl_request_finished(req
, NT_STATUS_NO_MEMORY
);
546 if (ctrl
&& (ctrl
->send_only
|| ctrl
->disconnect_after_send
)) {
547 struct wrepl_send_ctrl_state
*s
= talloc(blob
.data
, struct wrepl_send_ctrl_state
);
548 if (!s
) return wrepl_request_finished(req
, NT_STATUS_NO_MEMORY
);
551 s
->wrepl_sock
= wrepl_socket
;
552 talloc_set_destructor(s
, wrepl_send_ctrl_destructor
);
555 status
= packet_send(wrepl_socket
->packet
, blob
);
556 if (!NT_STATUS_IS_OK(status
)) {
557 return wrepl_request_finished(req
, status
);
560 req
->trigger
= false;
565 receive a generic WINS replication reply
567 NTSTATUS
wrepl_request_recv(struct wrepl_request
*req
,
569 struct wrepl_packet
**packet
)
571 NTSTATUS status
= wrepl_request_wait(req
);
572 if (NT_STATUS_IS_OK(status
) && packet
) {
573 *packet
= talloc_steal(mem_ctx
, req
->packet
);
580 a full WINS replication request/response
582 NTSTATUS
wrepl_request(struct wrepl_socket
*wrepl_socket
,
584 struct wrepl_packet
*req_packet
,
585 struct wrepl_packet
**reply_packet
)
587 struct wrepl_request
*req
= wrepl_request_send(wrepl_socket
, req_packet
, NULL
);
588 return wrepl_request_recv(req
, mem_ctx
, reply_packet
);
592 struct wrepl_associate_state
{
593 struct wrepl_packet packet
;
595 uint16_t major_version
;
598 static void wrepl_associate_done(struct wrepl_request
*subreq
);
600 struct tevent_req
*wrepl_associate_send(TALLOC_CTX
*mem_ctx
,
601 struct tevent_context
*ev
,
602 struct wrepl_socket
*wrepl_socket
,
603 const struct wrepl_associate
*io
)
605 struct tevent_req
*req
;
606 struct wrepl_associate_state
*state
;
607 struct wrepl_request
*subreq
;
609 if (wrepl_socket
->event
.ctx
!= ev
) {
610 /* TODO: remove wrepl_socket->event.ctx !!! */
611 smb_panic("wrepl_associate_send event context mismatch!");
615 req
= tevent_req_create(mem_ctx
, &state
,
616 struct wrepl_associate_state
);
621 state
->packet
.opcode
= WREPL_OPCODE_BITS
;
622 state
->packet
.mess_type
= WREPL_START_ASSOCIATION
;
623 state
->packet
.message
.start
.minor_version
= 2;
624 state
->packet
.message
.start
.major_version
= 5;
627 * nt4 uses 41 bytes for the start_association call
628 * so do it the same and as we don't know th emeanings of this bytes
629 * we just send zeros and nt4, w2k and w2k3 seems to be happy with this
631 * if we don't do this nt4 uses an old version of the wins replication protocol
632 * and that would break nt4 <-> samba replication
634 state
->packet
.padding
= data_blob_talloc(state
, NULL
, 21);
635 if (tevent_req_nomem(state
->packet
.padding
.data
, req
)) {
636 return tevent_req_post(req
, ev
);
638 memset(state
->packet
.padding
.data
, 0, state
->packet
.padding
.length
);
640 subreq
= wrepl_request_send(wrepl_socket
, &state
->packet
, NULL
);
641 if (tevent_req_nomem(subreq
, req
)) {
642 return tevent_req_post(req
, ev
);
644 subreq
->async
.fn
= wrepl_associate_done
;
645 subreq
->async
.private_data
= req
;
650 static void wrepl_associate_done(struct wrepl_request
*subreq
)
652 struct tevent_req
*req
= talloc_get_type_abort(subreq
->async
.private_data
,
654 struct wrepl_associate_state
*state
= tevent_req_data(req
,
655 struct wrepl_associate_state
);
657 struct wrepl_packet
*packet
;
659 status
= wrepl_request_recv(subreq
, state
, &packet
);
660 if (!NT_STATUS_IS_OK(status
)) {
661 tevent_req_nterror(req
, status
);
665 if (packet
->mess_type
!= WREPL_START_ASSOCIATION_REPLY
) {
666 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
670 state
->assoc_ctx
= packet
->message
.start_reply
.assoc_ctx
;
671 state
->major_version
= packet
->message
.start_reply
.major_version
;
673 tevent_req_done(req
);
677 setup an association - recv
679 NTSTATUS
wrepl_associate_recv(struct tevent_req
*req
,
680 struct wrepl_associate
*io
)
682 struct wrepl_associate_state
*state
= tevent_req_data(req
,
683 struct wrepl_associate_state
);
686 if (tevent_req_is_nterror(req
, &status
)) {
687 tevent_req_received(req
);
691 io
->out
.assoc_ctx
= state
->assoc_ctx
;
692 io
->out
.major_version
= state
->major_version
;
694 tevent_req_received(req
);
699 setup an association - sync api
701 NTSTATUS
wrepl_associate(struct wrepl_socket
*wrepl_socket
,
702 struct wrepl_associate
*io
)
704 struct tevent_req
*subreq
;
708 subreq
= wrepl_associate_send(wrepl_socket
, wrepl_socket
->event
.ctx
,
710 NT_STATUS_HAVE_NO_MEMORY(subreq
);
712 ok
= tevent_req_poll(subreq
, wrepl_socket
->event
.ctx
);
715 return NT_STATUS_INTERNAL_ERROR
;
718 status
= wrepl_associate_recv(subreq
, io
);
720 NT_STATUS_NOT_OK_RETURN(status
);
725 struct wrepl_associate_stop_state
{
726 struct wrepl_packet packet
;
727 struct wrepl_send_ctrl ctrl
;
730 static void wrepl_associate_stop_done(struct wrepl_request
*subreq
);
732 struct tevent_req
*wrepl_associate_stop_send(TALLOC_CTX
*mem_ctx
,
733 struct tevent_context
*ev
,
734 struct wrepl_socket
*wrepl_socket
,
735 const struct wrepl_associate_stop
*io
)
737 struct tevent_req
*req
;
738 struct wrepl_associate_stop_state
*state
;
739 struct wrepl_request
*subreq
;
741 if (wrepl_socket
->event
.ctx
!= ev
) {
742 /* TODO: remove wrepl_socket->event.ctx !!! */
743 smb_panic("wrepl_associate_stop_send event context mismatch!");
747 req
= tevent_req_create(mem_ctx
, &state
,
748 struct wrepl_associate_stop_state
);
753 state
->packet
.opcode
= WREPL_OPCODE_BITS
;
754 state
->packet
.assoc_ctx
= io
->in
.assoc_ctx
;
755 state
->packet
.mess_type
= WREPL_STOP_ASSOCIATION
;
756 state
->packet
.message
.stop
.reason
= io
->in
.reason
;
758 if (io
->in
.reason
== 0) {
759 state
->ctrl
.send_only
= true;
760 state
->ctrl
.disconnect_after_send
= true;
763 subreq
= wrepl_request_send(wrepl_socket
, &state
->packet
, &state
->ctrl
);
764 if (tevent_req_nomem(subreq
, req
)) {
765 return tevent_req_post(req
, ev
);
767 subreq
->async
.fn
= wrepl_associate_stop_done
;
768 subreq
->async
.private_data
= req
;
773 static void wrepl_associate_stop_done(struct wrepl_request
*subreq
)
775 struct tevent_req
*req
= talloc_get_type_abort(subreq
->async
.private_data
,
777 struct wrepl_associate_stop_state
*state
= tevent_req_data(req
,
778 struct wrepl_associate_stop_state
);
781 /* currently we don't care about a possible response */
782 status
= wrepl_request_recv(subreq
, state
, NULL
);
783 if (!NT_STATUS_IS_OK(status
)) {
784 tevent_req_nterror(req
, status
);
788 tevent_req_done(req
);
792 stop an association - recv
794 NTSTATUS
wrepl_associate_stop_recv(struct tevent_req
*req
,
795 struct wrepl_associate_stop
*io
)
799 if (tevent_req_is_nterror(req
, &status
)) {
800 tevent_req_received(req
);
804 tevent_req_received(req
);
809 setup an association - sync api
811 NTSTATUS
wrepl_associate_stop(struct wrepl_socket
*wrepl_socket
,
812 struct wrepl_associate_stop
*io
)
814 struct tevent_req
*subreq
;
818 subreq
= wrepl_associate_stop_send(wrepl_socket
, wrepl_socket
->event
.ctx
,
820 NT_STATUS_HAVE_NO_MEMORY(subreq
);
822 ok
= tevent_req_poll(subreq
, wrepl_socket
->event
.ctx
);
825 return NT_STATUS_INTERNAL_ERROR
;
828 status
= wrepl_associate_stop_recv(subreq
, io
);
830 NT_STATUS_NOT_OK_RETURN(status
);
835 struct wrepl_pull_table_state
{
836 struct wrepl_packet packet
;
837 uint32_t num_partners
;
838 struct wrepl_wins_owner
*partners
;
841 static void wrepl_pull_table_done(struct wrepl_request
*subreq
);
843 struct tevent_req
*wrepl_pull_table_send(TALLOC_CTX
*mem_ctx
,
844 struct tevent_context
*ev
,
845 struct wrepl_socket
*wrepl_socket
,
846 const struct wrepl_pull_table
*io
)
848 struct tevent_req
*req
;
849 struct wrepl_pull_table_state
*state
;
850 struct wrepl_request
*subreq
;
852 if (wrepl_socket
->event
.ctx
!= ev
) {
853 /* TODO: remove wrepl_socket->event.ctx !!! */
854 smb_panic("wrepl_pull_table_send event context mismatch!");
858 req
= tevent_req_create(mem_ctx
, &state
,
859 struct wrepl_pull_table_state
);
864 state
->packet
.opcode
= WREPL_OPCODE_BITS
;
865 state
->packet
.assoc_ctx
= io
->in
.assoc_ctx
;
866 state
->packet
.mess_type
= WREPL_REPLICATION
;
867 state
->packet
.message
.replication
.command
= WREPL_REPL_TABLE_QUERY
;
869 subreq
= wrepl_request_send(wrepl_socket
, &state
->packet
, NULL
);
870 if (tevent_req_nomem(subreq
, req
)) {
871 return tevent_req_post(req
, ev
);
873 subreq
->async
.fn
= wrepl_pull_table_done
;
874 subreq
->async
.private_data
= req
;
879 static void wrepl_pull_table_done(struct wrepl_request
*subreq
)
881 struct tevent_req
*req
= talloc_get_type_abort(subreq
->async
.private_data
,
883 struct wrepl_pull_table_state
*state
= tevent_req_data(req
,
884 struct wrepl_pull_table_state
);
886 struct wrepl_packet
*packet
;
887 struct wrepl_table
*table
;
889 status
= wrepl_request_recv(subreq
, state
, &packet
);
890 if (!NT_STATUS_IS_OK(status
)) {
891 tevent_req_nterror(req
, status
);
895 if (packet
->mess_type
!= WREPL_REPLICATION
) {
896 tevent_req_nterror(req
, NT_STATUS_NETWORK_ACCESS_DENIED
);
900 if (packet
->message
.replication
.command
!= WREPL_REPL_TABLE_REPLY
) {
901 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
905 table
= &packet
->message
.replication
.info
.table
;
907 state
->num_partners
= table
->partner_count
;
908 state
->partners
= talloc_move(state
, &table
->partners
);
910 tevent_req_done(req
);
914 fetch the partner tables - recv
916 NTSTATUS
wrepl_pull_table_recv(struct tevent_req
*req
,
918 struct wrepl_pull_table
*io
)
920 struct wrepl_pull_table_state
*state
= tevent_req_data(req
,
921 struct wrepl_pull_table_state
);
924 if (tevent_req_is_nterror(req
, &status
)) {
925 tevent_req_received(req
);
929 io
->out
.num_partners
= state
->num_partners
;
930 io
->out
.partners
= talloc_move(mem_ctx
, &state
->partners
);
932 tevent_req_received(req
);
937 fetch the partner table - sync api
939 NTSTATUS
wrepl_pull_table(struct wrepl_socket
*wrepl_socket
,
941 struct wrepl_pull_table
*io
)
943 struct tevent_req
*subreq
;
947 subreq
= wrepl_pull_table_send(mem_ctx
, wrepl_socket
->event
.ctx
,
949 NT_STATUS_HAVE_NO_MEMORY(subreq
);
951 ok
= tevent_req_poll(subreq
, wrepl_socket
->event
.ctx
);
954 return NT_STATUS_INTERNAL_ERROR
;
957 status
= wrepl_pull_table_recv(subreq
, mem_ctx
, io
);
959 NT_STATUS_NOT_OK_RETURN(status
);
965 struct wrepl_pull_names_state
{
967 const struct wrepl_pull_names
*io
;
969 struct wrepl_packet packet
;
971 struct wrepl_name
*names
;
974 static void wrepl_pull_names_done(struct wrepl_request
*subreq
);
976 struct tevent_req
*wrepl_pull_names_send(TALLOC_CTX
*mem_ctx
,
977 struct tevent_context
*ev
,
978 struct wrepl_socket
*wrepl_socket
,
979 const struct wrepl_pull_names
*io
)
981 struct tevent_req
*req
;
982 struct wrepl_pull_names_state
*state
;
983 struct wrepl_request
*subreq
;
985 if (wrepl_socket
->event
.ctx
!= ev
) {
986 /* TODO: remove wrepl_socket->event.ctx !!! */
987 smb_panic("wrepl_pull_names_send event context mismatch!");
991 req
= tevent_req_create(mem_ctx
, &state
,
992 struct wrepl_pull_names_state
);
996 state
->caller
.io
= io
;
998 state
->packet
.opcode
= WREPL_OPCODE_BITS
;
999 state
->packet
.assoc_ctx
= io
->in
.assoc_ctx
;
1000 state
->packet
.mess_type
= WREPL_REPLICATION
;
1001 state
->packet
.message
.replication
.command
= WREPL_REPL_SEND_REQUEST
;
1002 state
->packet
.message
.replication
.info
.owner
= io
->in
.partner
;
1004 subreq
= wrepl_request_send(wrepl_socket
, &state
->packet
, NULL
);
1005 if (tevent_req_nomem(subreq
, req
)) {
1006 return tevent_req_post(req
, ev
);
1008 subreq
->async
.fn
= wrepl_pull_names_done
;
1009 subreq
->async
.private_data
= req
;
1014 static void wrepl_pull_names_done(struct wrepl_request
*subreq
)
1016 struct tevent_req
*req
= talloc_get_type_abort(subreq
->async
.private_data
,
1018 struct wrepl_pull_names_state
*state
= tevent_req_data(req
,
1019 struct wrepl_pull_names_state
);
1021 struct wrepl_packet
*packet
;
1024 status
= wrepl_request_recv(subreq
, state
, &packet
);
1025 if (!NT_STATUS_IS_OK(status
)) {
1026 tevent_req_nterror(req
, status
);
1030 if (packet
->mess_type
!= WREPL_REPLICATION
) {
1031 tevent_req_nterror(req
, NT_STATUS_NETWORK_ACCESS_DENIED
);
1035 if (packet
->message
.replication
.command
!= WREPL_REPL_SEND_REPLY
) {
1036 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
1040 state
->num_names
= packet
->message
.replication
.info
.reply
.num_names
;
1042 state
->names
= talloc_array(state
, struct wrepl_name
, state
->num_names
);
1043 if (tevent_req_nomem(state
->names
, req
)) {
1047 /* convert the list of names and addresses to a sane format */
1048 for (i
=0; i
< state
->num_names
; i
++) {
1049 struct wrepl_wins_name
*wname
= &packet
->message
.replication
.info
.reply
.names
[i
];
1050 struct wrepl_name
*name
= &state
->names
[i
];
1052 name
->name
= *wname
->name
;
1053 talloc_steal(state
->names
, wname
->name
);
1054 name
->type
= WREPL_NAME_TYPE(wname
->flags
);
1055 name
->state
= WREPL_NAME_STATE(wname
->flags
);
1056 name
->node
= WREPL_NAME_NODE(wname
->flags
);
1057 name
->is_static
= WREPL_NAME_IS_STATIC(wname
->flags
);
1058 name
->raw_flags
= wname
->flags
;
1059 name
->version_id
= wname
->id
;
1060 name
->owner
= talloc_strdup(state
->names
,
1061 state
->caller
.io
->in
.partner
.address
);
1062 if (tevent_req_nomem(name
->owner
, req
)) {
1066 /* trying to save 1 or 2 bytes on the wire isn't a good idea */
1067 if (wname
->flags
& 2) {
1070 name
->num_addresses
= wname
->addresses
.addresses
.num_ips
;
1071 name
->addresses
= talloc_array(state
->names
,
1072 struct wrepl_address
,
1073 name
->num_addresses
);
1074 if (tevent_req_nomem(name
->addresses
, req
)) {
1078 for (j
=0;j
<name
->num_addresses
;j
++) {
1079 name
->addresses
[j
].owner
=
1080 talloc_move(name
->addresses
,
1081 &wname
->addresses
.addresses
.ips
[j
].owner
);
1082 name
->addresses
[j
].address
=
1083 talloc_move(name
->addresses
,
1084 &wname
->addresses
.addresses
.ips
[j
].ip
);
1087 name
->num_addresses
= 1;
1088 name
->addresses
= talloc_array(state
->names
,
1089 struct wrepl_address
,
1090 name
->num_addresses
);
1091 if (tevent_req_nomem(name
->addresses
, req
)) {
1095 name
->addresses
[0].owner
= talloc_strdup(name
->addresses
, name
->owner
);
1096 if (tevent_req_nomem(name
->addresses
[0].owner
, req
)) {
1099 name
->addresses
[0].address
= talloc_move(name
->addresses
,
1100 &wname
->addresses
.ip
);
1104 tevent_req_done(req
);
1108 fetch the names for a WINS partner - recv
1110 NTSTATUS
wrepl_pull_names_recv(struct tevent_req
*req
,
1111 TALLOC_CTX
*mem_ctx
,
1112 struct wrepl_pull_names
*io
)
1114 struct wrepl_pull_names_state
*state
= tevent_req_data(req
,
1115 struct wrepl_pull_names_state
);
1118 if (tevent_req_is_nterror(req
, &status
)) {
1119 tevent_req_received(req
);
1123 io
->out
.num_names
= state
->num_names
;
1124 io
->out
.names
= talloc_move(mem_ctx
, &state
->names
);
1126 tevent_req_received(req
);
1127 return NT_STATUS_OK
;
1133 fetch the names for a WINS partner - sync api
1135 NTSTATUS
wrepl_pull_names(struct wrepl_socket
*wrepl_socket
,
1136 TALLOC_CTX
*mem_ctx
,
1137 struct wrepl_pull_names
*io
)
1139 struct tevent_req
*subreq
;
1143 subreq
= wrepl_pull_names_send(mem_ctx
, wrepl_socket
->event
.ctx
,
1145 NT_STATUS_HAVE_NO_MEMORY(subreq
);
1147 ok
= tevent_req_poll(subreq
, wrepl_socket
->event
.ctx
);
1149 TALLOC_FREE(subreq
);
1150 return NT_STATUS_INTERNAL_ERROR
;
1153 status
= wrepl_pull_names_recv(subreq
, mem_ctx
, io
);
1154 TALLOC_FREE(subreq
);
1155 NT_STATUS_NOT_OK_RETURN(status
);
1157 return NT_STATUS_OK
;