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 static struct wrepl_request
*wrepl_request_internal_send(struct wrepl_socket
*wrepl_socket
,
503 const struct wrepl_packet
*packet
,
504 const 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 static NTSTATUS
wrepl_request_internal_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
);
579 struct wrepl_request_state
{
580 struct wrepl_packet
*packet
;
583 static void wrepl_request_done(struct wrepl_request
*subreq
);
585 struct tevent_req
*wrepl_request_send(TALLOC_CTX
*mem_ctx
,
586 struct tevent_context
*ev
,
587 struct wrepl_socket
*wrepl_socket
,
588 const struct wrepl_packet
*packet
,
589 const struct wrepl_send_ctrl
*ctrl
)
591 struct tevent_req
*req
;
592 struct wrepl_request_state
*state
;
593 struct wrepl_request
*subreq
;
595 if (wrepl_socket
->event
.ctx
!= ev
) {
596 /* TODO: remove wrepl_socket->event.ctx !!! */
597 smb_panic("wrepl_associate_stop_send event context mismatch!");
601 req
= tevent_req_create(mem_ctx
, &state
,
602 struct wrepl_request_state
);
607 subreq
= wrepl_request_internal_send(wrepl_socket
, packet
, ctrl
);
608 if (tevent_req_nomem(subreq
, req
)) {
609 return tevent_req_post(req
, ev
);
611 subreq
->async
.fn
= wrepl_request_done
;
612 subreq
->async
.private_data
= req
;
617 static void wrepl_request_done(struct wrepl_request
*subreq
)
619 struct tevent_req
*req
= talloc_get_type_abort(subreq
->async
.private_data
,
621 struct wrepl_request_state
*state
= tevent_req_data(req
,
622 struct wrepl_request_state
);
625 status
= wrepl_request_internal_recv(subreq
, state
, &state
->packet
);
626 if (!NT_STATUS_IS_OK(status
)) {
627 tevent_req_nterror(req
, status
);
631 tevent_req_done(req
);
634 NTSTATUS
wrepl_request_recv(struct tevent_req
*req
,
636 struct wrepl_packet
**packet
)
638 struct wrepl_request_state
*state
= tevent_req_data(req
,
639 struct wrepl_request_state
);
642 if (tevent_req_is_nterror(req
, &status
)) {
643 tevent_req_received(req
);
648 *packet
= talloc_move(mem_ctx
, &state
->packet
);
651 tevent_req_received(req
);
656 a full WINS replication request/response
658 NTSTATUS
wrepl_request(struct wrepl_socket
*wrepl_socket
,
660 const struct wrepl_packet
*req_packet
,
661 struct wrepl_packet
**reply_packet
)
663 struct tevent_req
*subreq
;
667 subreq
= wrepl_request_send(mem_ctx
, wrepl_socket
->event
.ctx
,
668 wrepl_socket
, req_packet
, NULL
);
669 NT_STATUS_HAVE_NO_MEMORY(subreq
);
671 ok
= tevent_req_poll(subreq
, wrepl_socket
->event
.ctx
);
674 return NT_STATUS_INTERNAL_ERROR
;
677 status
= wrepl_request_recv(subreq
, mem_ctx
, reply_packet
);
679 NT_STATUS_NOT_OK_RETURN(status
);
685 struct wrepl_associate_state
{
686 struct wrepl_packet packet
;
688 uint16_t major_version
;
691 static void wrepl_associate_done(struct tevent_req
*subreq
);
693 struct tevent_req
*wrepl_associate_send(TALLOC_CTX
*mem_ctx
,
694 struct tevent_context
*ev
,
695 struct wrepl_socket
*wrepl_socket
,
696 const struct wrepl_associate
*io
)
698 struct tevent_req
*req
;
699 struct wrepl_associate_state
*state
;
700 struct tevent_req
*subreq
;
702 if (wrepl_socket
->event
.ctx
!= ev
) {
703 /* TODO: remove wrepl_socket->event.ctx !!! */
704 smb_panic("wrepl_associate_send event context mismatch!");
708 req
= tevent_req_create(mem_ctx
, &state
,
709 struct wrepl_associate_state
);
714 state
->packet
.opcode
= WREPL_OPCODE_BITS
;
715 state
->packet
.mess_type
= WREPL_START_ASSOCIATION
;
716 state
->packet
.message
.start
.minor_version
= 2;
717 state
->packet
.message
.start
.major_version
= 5;
720 * nt4 uses 41 bytes for the start_association call
721 * so do it the same and as we don't know th emeanings of this bytes
722 * we just send zeros and nt4, w2k and w2k3 seems to be happy with this
724 * if we don't do this nt4 uses an old version of the wins replication protocol
725 * and that would break nt4 <-> samba replication
727 state
->packet
.padding
= data_blob_talloc(state
, NULL
, 21);
728 if (tevent_req_nomem(state
->packet
.padding
.data
, req
)) {
729 return tevent_req_post(req
, ev
);
731 memset(state
->packet
.padding
.data
, 0, state
->packet
.padding
.length
);
733 subreq
= wrepl_request_send(state
, ev
, wrepl_socket
, &state
->packet
, NULL
);
734 if (tevent_req_nomem(subreq
, req
)) {
735 return tevent_req_post(req
, ev
);
737 tevent_req_set_callback(subreq
, wrepl_associate_done
, req
);
742 static void wrepl_associate_done(struct tevent_req
*subreq
)
744 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
746 struct wrepl_associate_state
*state
= tevent_req_data(req
,
747 struct wrepl_associate_state
);
749 struct wrepl_packet
*packet
;
751 status
= wrepl_request_recv(subreq
, state
, &packet
);
753 if (!NT_STATUS_IS_OK(status
)) {
754 tevent_req_nterror(req
, status
);
758 if (packet
->mess_type
!= WREPL_START_ASSOCIATION_REPLY
) {
759 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
763 state
->assoc_ctx
= packet
->message
.start_reply
.assoc_ctx
;
764 state
->major_version
= packet
->message
.start_reply
.major_version
;
766 tevent_req_done(req
);
770 setup an association - recv
772 NTSTATUS
wrepl_associate_recv(struct tevent_req
*req
,
773 struct wrepl_associate
*io
)
775 struct wrepl_associate_state
*state
= tevent_req_data(req
,
776 struct wrepl_associate_state
);
779 if (tevent_req_is_nterror(req
, &status
)) {
780 tevent_req_received(req
);
784 io
->out
.assoc_ctx
= state
->assoc_ctx
;
785 io
->out
.major_version
= state
->major_version
;
787 tevent_req_received(req
);
792 setup an association - sync api
794 NTSTATUS
wrepl_associate(struct wrepl_socket
*wrepl_socket
,
795 struct wrepl_associate
*io
)
797 struct tevent_req
*subreq
;
801 subreq
= wrepl_associate_send(wrepl_socket
, wrepl_socket
->event
.ctx
,
803 NT_STATUS_HAVE_NO_MEMORY(subreq
);
805 ok
= tevent_req_poll(subreq
, wrepl_socket
->event
.ctx
);
808 return NT_STATUS_INTERNAL_ERROR
;
811 status
= wrepl_associate_recv(subreq
, io
);
813 NT_STATUS_NOT_OK_RETURN(status
);
818 struct wrepl_associate_stop_state
{
819 struct wrepl_packet packet
;
820 struct wrepl_send_ctrl ctrl
;
823 static void wrepl_associate_stop_done(struct tevent_req
*subreq
);
825 struct tevent_req
*wrepl_associate_stop_send(TALLOC_CTX
*mem_ctx
,
826 struct tevent_context
*ev
,
827 struct wrepl_socket
*wrepl_socket
,
828 const struct wrepl_associate_stop
*io
)
830 struct tevent_req
*req
;
831 struct wrepl_associate_stop_state
*state
;
832 struct tevent_req
*subreq
;
834 if (wrepl_socket
->event
.ctx
!= ev
) {
835 /* TODO: remove wrepl_socket->event.ctx !!! */
836 smb_panic("wrepl_associate_stop_send event context mismatch!");
840 req
= tevent_req_create(mem_ctx
, &state
,
841 struct wrepl_associate_stop_state
);
846 state
->packet
.opcode
= WREPL_OPCODE_BITS
;
847 state
->packet
.assoc_ctx
= io
->in
.assoc_ctx
;
848 state
->packet
.mess_type
= WREPL_STOP_ASSOCIATION
;
849 state
->packet
.message
.stop
.reason
= io
->in
.reason
;
851 if (io
->in
.reason
== 0) {
852 state
->ctrl
.send_only
= true;
853 state
->ctrl
.disconnect_after_send
= true;
856 subreq
= wrepl_request_send(state
, ev
, wrepl_socket
, &state
->packet
, &state
->ctrl
);
857 if (tevent_req_nomem(subreq
, req
)) {
858 return tevent_req_post(req
, ev
);
860 tevent_req_set_callback(subreq
, wrepl_associate_stop_done
, req
);
865 static void wrepl_associate_stop_done(struct tevent_req
*subreq
)
867 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
869 struct wrepl_associate_stop_state
*state
= tevent_req_data(req
,
870 struct wrepl_associate_stop_state
);
873 /* currently we don't care about a possible response */
874 status
= wrepl_request_recv(subreq
, state
, NULL
);
876 if (!NT_STATUS_IS_OK(status
)) {
877 tevent_req_nterror(req
, status
);
881 tevent_req_done(req
);
885 stop an association - recv
887 NTSTATUS
wrepl_associate_stop_recv(struct tevent_req
*req
,
888 struct wrepl_associate_stop
*io
)
892 if (tevent_req_is_nterror(req
, &status
)) {
893 tevent_req_received(req
);
897 tevent_req_received(req
);
902 setup an association - sync api
904 NTSTATUS
wrepl_associate_stop(struct wrepl_socket
*wrepl_socket
,
905 struct wrepl_associate_stop
*io
)
907 struct tevent_req
*subreq
;
911 subreq
= wrepl_associate_stop_send(wrepl_socket
, wrepl_socket
->event
.ctx
,
913 NT_STATUS_HAVE_NO_MEMORY(subreq
);
915 ok
= tevent_req_poll(subreq
, wrepl_socket
->event
.ctx
);
918 return NT_STATUS_INTERNAL_ERROR
;
921 status
= wrepl_associate_stop_recv(subreq
, io
);
923 NT_STATUS_NOT_OK_RETURN(status
);
928 struct wrepl_pull_table_state
{
929 struct wrepl_packet packet
;
930 uint32_t num_partners
;
931 struct wrepl_wins_owner
*partners
;
934 static void wrepl_pull_table_done(struct tevent_req
*subreq
);
936 struct tevent_req
*wrepl_pull_table_send(TALLOC_CTX
*mem_ctx
,
937 struct tevent_context
*ev
,
938 struct wrepl_socket
*wrepl_socket
,
939 const struct wrepl_pull_table
*io
)
941 struct tevent_req
*req
;
942 struct wrepl_pull_table_state
*state
;
943 struct tevent_req
*subreq
;
945 if (wrepl_socket
->event
.ctx
!= ev
) {
946 /* TODO: remove wrepl_socket->event.ctx !!! */
947 smb_panic("wrepl_pull_table_send event context mismatch!");
951 req
= tevent_req_create(mem_ctx
, &state
,
952 struct wrepl_pull_table_state
);
957 state
->packet
.opcode
= WREPL_OPCODE_BITS
;
958 state
->packet
.assoc_ctx
= io
->in
.assoc_ctx
;
959 state
->packet
.mess_type
= WREPL_REPLICATION
;
960 state
->packet
.message
.replication
.command
= WREPL_REPL_TABLE_QUERY
;
962 subreq
= wrepl_request_send(state
, ev
, wrepl_socket
, &state
->packet
, NULL
);
963 if (tevent_req_nomem(subreq
, req
)) {
964 return tevent_req_post(req
, ev
);
966 tevent_req_set_callback(subreq
, wrepl_pull_table_done
, req
);
971 static void wrepl_pull_table_done(struct tevent_req
*subreq
)
973 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
975 struct wrepl_pull_table_state
*state
= tevent_req_data(req
,
976 struct wrepl_pull_table_state
);
978 struct wrepl_packet
*packet
;
979 struct wrepl_table
*table
;
981 status
= wrepl_request_recv(subreq
, state
, &packet
);
983 if (!NT_STATUS_IS_OK(status
)) {
984 tevent_req_nterror(req
, status
);
988 if (packet
->mess_type
!= WREPL_REPLICATION
) {
989 tevent_req_nterror(req
, NT_STATUS_NETWORK_ACCESS_DENIED
);
993 if (packet
->message
.replication
.command
!= WREPL_REPL_TABLE_REPLY
) {
994 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
998 table
= &packet
->message
.replication
.info
.table
;
1000 state
->num_partners
= table
->partner_count
;
1001 state
->partners
= talloc_move(state
, &table
->partners
);
1003 tevent_req_done(req
);
1007 fetch the partner tables - recv
1009 NTSTATUS
wrepl_pull_table_recv(struct tevent_req
*req
,
1010 TALLOC_CTX
*mem_ctx
,
1011 struct wrepl_pull_table
*io
)
1013 struct wrepl_pull_table_state
*state
= tevent_req_data(req
,
1014 struct wrepl_pull_table_state
);
1017 if (tevent_req_is_nterror(req
, &status
)) {
1018 tevent_req_received(req
);
1022 io
->out
.num_partners
= state
->num_partners
;
1023 io
->out
.partners
= talloc_move(mem_ctx
, &state
->partners
);
1025 tevent_req_received(req
);
1026 return NT_STATUS_OK
;
1030 fetch the partner table - sync api
1032 NTSTATUS
wrepl_pull_table(struct wrepl_socket
*wrepl_socket
,
1033 TALLOC_CTX
*mem_ctx
,
1034 struct wrepl_pull_table
*io
)
1036 struct tevent_req
*subreq
;
1040 subreq
= wrepl_pull_table_send(mem_ctx
, wrepl_socket
->event
.ctx
,
1042 NT_STATUS_HAVE_NO_MEMORY(subreq
);
1044 ok
= tevent_req_poll(subreq
, wrepl_socket
->event
.ctx
);
1046 TALLOC_FREE(subreq
);
1047 return NT_STATUS_INTERNAL_ERROR
;
1050 status
= wrepl_pull_table_recv(subreq
, mem_ctx
, io
);
1051 TALLOC_FREE(subreq
);
1052 NT_STATUS_NOT_OK_RETURN(status
);
1054 return NT_STATUS_OK
;
1058 struct wrepl_pull_names_state
{
1060 const struct wrepl_pull_names
*io
;
1062 struct wrepl_packet packet
;
1064 struct wrepl_name
*names
;
1067 static void wrepl_pull_names_done(struct tevent_req
*subreq
);
1069 struct tevent_req
*wrepl_pull_names_send(TALLOC_CTX
*mem_ctx
,
1070 struct tevent_context
*ev
,
1071 struct wrepl_socket
*wrepl_socket
,
1072 const struct wrepl_pull_names
*io
)
1074 struct tevent_req
*req
;
1075 struct wrepl_pull_names_state
*state
;
1076 struct tevent_req
*subreq
;
1078 if (wrepl_socket
->event
.ctx
!= ev
) {
1079 /* TODO: remove wrepl_socket->event.ctx !!! */
1080 smb_panic("wrepl_pull_names_send event context mismatch!");
1084 req
= tevent_req_create(mem_ctx
, &state
,
1085 struct wrepl_pull_names_state
);
1089 state
->caller
.io
= io
;
1091 state
->packet
.opcode
= WREPL_OPCODE_BITS
;
1092 state
->packet
.assoc_ctx
= io
->in
.assoc_ctx
;
1093 state
->packet
.mess_type
= WREPL_REPLICATION
;
1094 state
->packet
.message
.replication
.command
= WREPL_REPL_SEND_REQUEST
;
1095 state
->packet
.message
.replication
.info
.owner
= io
->in
.partner
;
1097 subreq
= wrepl_request_send(state
, ev
, wrepl_socket
, &state
->packet
, NULL
);
1098 if (tevent_req_nomem(subreq
, req
)) {
1099 return tevent_req_post(req
, ev
);
1101 tevent_req_set_callback(subreq
, wrepl_pull_names_done
, req
);
1106 static void wrepl_pull_names_done(struct tevent_req
*subreq
)
1108 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
1110 struct wrepl_pull_names_state
*state
= tevent_req_data(req
,
1111 struct wrepl_pull_names_state
);
1113 struct wrepl_packet
*packet
;
1116 status
= wrepl_request_recv(subreq
, state
, &packet
);
1117 TALLOC_FREE(subreq
);
1118 if (!NT_STATUS_IS_OK(status
)) {
1119 tevent_req_nterror(req
, status
);
1123 if (packet
->mess_type
!= WREPL_REPLICATION
) {
1124 tevent_req_nterror(req
, NT_STATUS_NETWORK_ACCESS_DENIED
);
1128 if (packet
->message
.replication
.command
!= WREPL_REPL_SEND_REPLY
) {
1129 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
1133 state
->num_names
= packet
->message
.replication
.info
.reply
.num_names
;
1135 state
->names
= talloc_array(state
, struct wrepl_name
, state
->num_names
);
1136 if (tevent_req_nomem(state
->names
, req
)) {
1140 /* convert the list of names and addresses to a sane format */
1141 for (i
=0; i
< state
->num_names
; i
++) {
1142 struct wrepl_wins_name
*wname
= &packet
->message
.replication
.info
.reply
.names
[i
];
1143 struct wrepl_name
*name
= &state
->names
[i
];
1145 name
->name
= *wname
->name
;
1146 talloc_steal(state
->names
, wname
->name
);
1147 name
->type
= WREPL_NAME_TYPE(wname
->flags
);
1148 name
->state
= WREPL_NAME_STATE(wname
->flags
);
1149 name
->node
= WREPL_NAME_NODE(wname
->flags
);
1150 name
->is_static
= WREPL_NAME_IS_STATIC(wname
->flags
);
1151 name
->raw_flags
= wname
->flags
;
1152 name
->version_id
= wname
->id
;
1153 name
->owner
= talloc_strdup(state
->names
,
1154 state
->caller
.io
->in
.partner
.address
);
1155 if (tevent_req_nomem(name
->owner
, req
)) {
1159 /* trying to save 1 or 2 bytes on the wire isn't a good idea */
1160 if (wname
->flags
& 2) {
1163 name
->num_addresses
= wname
->addresses
.addresses
.num_ips
;
1164 name
->addresses
= talloc_array(state
->names
,
1165 struct wrepl_address
,
1166 name
->num_addresses
);
1167 if (tevent_req_nomem(name
->addresses
, req
)) {
1171 for (j
=0;j
<name
->num_addresses
;j
++) {
1172 name
->addresses
[j
].owner
=
1173 talloc_move(name
->addresses
,
1174 &wname
->addresses
.addresses
.ips
[j
].owner
);
1175 name
->addresses
[j
].address
=
1176 talloc_move(name
->addresses
,
1177 &wname
->addresses
.addresses
.ips
[j
].ip
);
1180 name
->num_addresses
= 1;
1181 name
->addresses
= talloc_array(state
->names
,
1182 struct wrepl_address
,
1183 name
->num_addresses
);
1184 if (tevent_req_nomem(name
->addresses
, req
)) {
1188 name
->addresses
[0].owner
= talloc_strdup(name
->addresses
, name
->owner
);
1189 if (tevent_req_nomem(name
->addresses
[0].owner
, req
)) {
1192 name
->addresses
[0].address
= talloc_move(name
->addresses
,
1193 &wname
->addresses
.ip
);
1197 tevent_req_done(req
);
1201 fetch the names for a WINS partner - recv
1203 NTSTATUS
wrepl_pull_names_recv(struct tevent_req
*req
,
1204 TALLOC_CTX
*mem_ctx
,
1205 struct wrepl_pull_names
*io
)
1207 struct wrepl_pull_names_state
*state
= tevent_req_data(req
,
1208 struct wrepl_pull_names_state
);
1211 if (tevent_req_is_nterror(req
, &status
)) {
1212 tevent_req_received(req
);
1216 io
->out
.num_names
= state
->num_names
;
1217 io
->out
.names
= talloc_move(mem_ctx
, &state
->names
);
1219 tevent_req_received(req
);
1220 return NT_STATUS_OK
;
1226 fetch the names for a WINS partner - sync api
1228 NTSTATUS
wrepl_pull_names(struct wrepl_socket
*wrepl_socket
,
1229 TALLOC_CTX
*mem_ctx
,
1230 struct wrepl_pull_names
*io
)
1232 struct tevent_req
*subreq
;
1236 subreq
= wrepl_pull_names_send(mem_ctx
, wrepl_socket
->event
.ctx
,
1238 NT_STATUS_HAVE_NO_MEMORY(subreq
);
1240 ok
= tevent_req_poll(subreq
, wrepl_socket
->event
.ctx
);
1242 TALLOC_FREE(subreq
);
1243 return NT_STATUS_INTERNAL_ERROR
;
1246 status
= wrepl_pull_names_recv(subreq
, mem_ctx
, io
);
1247 TALLOC_FREE(subreq
);
1248 NT_STATUS_NOT_OK_RETURN(status
);
1250 return NT_STATUS_OK
;