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"
33 #include "lib/util/tevent_ntstatus.h"
35 static struct wrepl_request
*wrepl_request_finished(struct wrepl_request
*req
, NTSTATUS status
);
38 mark all pending requests as dead - called when a socket error happens
40 static void wrepl_socket_dead(struct wrepl_socket
*wrepl_socket
, NTSTATUS status
)
42 wrepl_socket
->dead
= true;
44 if (wrepl_socket
->packet
) {
45 packet_recv_disable(wrepl_socket
->packet
);
46 packet_set_fde(wrepl_socket
->packet
, NULL
);
47 packet_set_socket(wrepl_socket
->packet
, NULL
);
50 if (wrepl_socket
->event
.fde
) {
51 talloc_free(wrepl_socket
->event
.fde
);
52 wrepl_socket
->event
.fde
= NULL
;
55 if (wrepl_socket
->sock
) {
56 talloc_free(wrepl_socket
->sock
);
57 wrepl_socket
->sock
= NULL
;
60 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL
, status
)) {
61 status
= NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
63 while (wrepl_socket
->recv_queue
) {
64 struct wrepl_request
*req
= wrepl_socket
->recv_queue
;
65 DLIST_REMOVE(wrepl_socket
->recv_queue
, req
);
66 wrepl_request_finished(req
, status
);
69 talloc_set_destructor(wrepl_socket
, NULL
);
70 if (wrepl_socket
->free_skipped
) {
71 talloc_free(wrepl_socket
);
75 static void wrepl_request_timeout_handler(struct tevent_context
*ev
, struct tevent_timer
*te
,
76 struct timeval t
, void *ptr
)
78 struct wrepl_request
*req
= talloc_get_type(ptr
, struct wrepl_request
);
79 wrepl_socket_dead(req
->wrepl_socket
, NT_STATUS_IO_TIMEOUT
);
85 static NTSTATUS
wrepl_finish_recv(void *private_data
, DATA_BLOB packet_blob_in
)
87 struct wrepl_socket
*wrepl_socket
= talloc_get_type(private_data
, struct wrepl_socket
);
88 struct wrepl_request
*req
= wrepl_socket
->recv_queue
;
90 enum ndr_err_code ndr_err
;
93 DEBUG(1,("Received unexpected WINS packet of length %u!\n",
94 (unsigned)packet_blob_in
.length
));
95 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
98 req
->packet
= talloc(req
, struct wrepl_packet
);
99 NT_STATUS_HAVE_NO_MEMORY(req
->packet
);
101 blob
.data
= packet_blob_in
.data
+ 4;
102 blob
.length
= packet_blob_in
.length
- 4;
104 /* we have a full request - parse it */
105 ndr_err
= ndr_pull_struct_blob(&blob
, req
->packet
, wrepl_socket
->iconv_convenience
, req
->packet
,
106 (ndr_pull_flags_fn_t
)ndr_pull_wrepl_packet
);
107 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
108 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
109 wrepl_request_finished(req
, status
);
114 DEBUG(10,("Received WINS packet of length %u\n",
115 (unsigned)packet_blob_in
.length
));
116 NDR_PRINT_DEBUG(wrepl_packet
, req
->packet
);
119 wrepl_request_finished(req
, NT_STATUS_OK
);
124 handler for winrepl events
126 static void wrepl_handler(struct tevent_context
*ev
, struct tevent_fd
*fde
,
127 uint16_t flags
, void *private_data
)
129 struct wrepl_socket
*wrepl_socket
= talloc_get_type(private_data
,
130 struct wrepl_socket
);
131 if (flags
& EVENT_FD_READ
) {
132 packet_recv(wrepl_socket
->packet
);
135 if (flags
& EVENT_FD_WRITE
) {
136 packet_queue_run(wrepl_socket
->packet
);
140 static void wrepl_error(void *private_data
, NTSTATUS status
)
142 struct wrepl_socket
*wrepl_socket
= talloc_get_type(private_data
,
143 struct wrepl_socket
);
144 wrepl_socket_dead(wrepl_socket
, status
);
149 destroy a wrepl_socket destructor
151 static int wrepl_socket_destructor(struct wrepl_socket
*sock
)
154 sock
->free_skipped
= true;
157 wrepl_socket_dead(sock
, NT_STATUS_LOCAL_DISCONNECT
);
162 initialise a wrepl_socket. The event_ctx is optional, if provided then
163 operations will use that event context
165 struct wrepl_socket
*wrepl_socket_init(TALLOC_CTX
*mem_ctx
,
166 struct tevent_context
*event_ctx
,
167 struct smb_iconv_convenience
*iconv_convenience
)
169 struct wrepl_socket
*wrepl_socket
;
172 wrepl_socket
= talloc_zero(mem_ctx
, struct wrepl_socket
);
173 if (!wrepl_socket
) return NULL
;
175 wrepl_socket
->event
.ctx
= event_ctx
;
176 if (!wrepl_socket
->event
.ctx
) goto failed
;
178 wrepl_socket
->iconv_convenience
= iconv_convenience
;
180 status
= socket_create("ip", SOCKET_TYPE_STREAM
, &wrepl_socket
->sock
, 0);
181 if (!NT_STATUS_IS_OK(status
)) goto failed
;
183 talloc_steal(wrepl_socket
, wrepl_socket
->sock
);
185 wrepl_socket
->request_timeout
= WREPL_SOCKET_REQUEST_TIMEOUT
;
187 talloc_set_destructor(wrepl_socket
, wrepl_socket_destructor
);
192 talloc_free(wrepl_socket
);
197 initialise a wrepl_socket from an already existing connection
199 struct wrepl_socket
*wrepl_socket_merge(TALLOC_CTX
*mem_ctx
,
200 struct tevent_context
*event_ctx
,
201 struct socket_context
*sock
,
202 struct packet_context
*pack
)
204 struct wrepl_socket
*wrepl_socket
;
206 wrepl_socket
= talloc_zero(mem_ctx
, struct wrepl_socket
);
207 if (wrepl_socket
== NULL
) goto failed
;
209 wrepl_socket
->event
.ctx
= event_ctx
;
210 if (wrepl_socket
->event
.ctx
== NULL
) goto failed
;
212 wrepl_socket
->sock
= sock
;
213 talloc_steal(wrepl_socket
, wrepl_socket
->sock
);
216 wrepl_socket
->request_timeout
= WREPL_SOCKET_REQUEST_TIMEOUT
;
218 wrepl_socket
->event
.fde
= event_add_fd(wrepl_socket
->event
.ctx
, wrepl_socket
,
219 socket_get_fd(wrepl_socket
->sock
),
221 wrepl_handler
, wrepl_socket
);
222 if (wrepl_socket
->event
.fde
== NULL
) {
226 wrepl_socket
->packet
= pack
;
227 talloc_steal(wrepl_socket
, wrepl_socket
->packet
);
228 packet_set_private(wrepl_socket
->packet
, wrepl_socket
);
229 packet_set_socket(wrepl_socket
->packet
, wrepl_socket
->sock
);
230 packet_set_callback(wrepl_socket
->packet
, wrepl_finish_recv
);
231 packet_set_full_request(wrepl_socket
->packet
, packet_full_request_u32
);
232 packet_set_error_handler(wrepl_socket
->packet
, wrepl_error
);
233 packet_set_event_context(wrepl_socket
->packet
, wrepl_socket
->event
.ctx
);
234 packet_set_fde(wrepl_socket
->packet
, wrepl_socket
->event
.fde
);
235 packet_set_serialise(wrepl_socket
->packet
);
237 talloc_set_destructor(wrepl_socket
, wrepl_socket_destructor
);
242 talloc_free(wrepl_socket
);
247 destroy a wrepl_request
249 static int wrepl_request_destructor(struct wrepl_request
*req
)
251 if (req
->state
== WREPL_REQUEST_RECV
) {
252 DLIST_REMOVE(req
->wrepl_socket
->recv_queue
, req
);
254 req
->state
= WREPL_REQUEST_ERROR
;
259 wait for a request to complete
261 static NTSTATUS
wrepl_request_wait(struct wrepl_request
*req
)
263 NT_STATUS_HAVE_NO_MEMORY(req
);
264 while (req
->state
< WREPL_REQUEST_DONE
) {
265 event_loop_once(req
->wrepl_socket
->event
.ctx
);
270 const char *wrepl_best_ip(struct loadparm_context
*lp_ctx
, const char *peer_ip
)
272 struct interface
*ifaces
;
273 load_interfaces(lp_ctx
, lp_interfaces(lp_ctx
), &ifaces
);
274 return iface_best_ip(ifaces
, peer_ip
);
277 struct wrepl_connect_state
{
278 struct wrepl_socket
*wrepl_socket
;
281 static void wrepl_connect_handler(struct composite_context
*creq
);
283 struct tevent_req
*wrepl_connect_send(TALLOC_CTX
*mem_ctx
,
284 struct tevent_context
*ev
,
285 struct wrepl_socket
*wrepl_socket
,
286 const char *our_ip
, const char *peer_ip
)
288 struct tevent_req
*req
;
289 struct wrepl_connect_state
*state
;
290 struct composite_context
*subreq
;
291 struct socket_address
*peer
, *us
;
293 req
= tevent_req_create(mem_ctx
, &state
,
294 struct wrepl_connect_state
);
299 state
->wrepl_socket
= wrepl_socket
;
301 us
= socket_address_from_strings(state
, wrepl_socket
->sock
->backend_name
,
303 if (tevent_req_nomem(us
, req
)) {
304 return tevent_req_post(req
, ev
);
307 peer
= socket_address_from_strings(state
, wrepl_socket
->sock
->backend_name
,
308 peer_ip
, WINS_REPLICATION_PORT
);
309 if (tevent_req_nomem(peer
, req
)) {
310 return tevent_req_post(req
, ev
);
313 subreq
= socket_connect_send(wrepl_socket
->sock
, us
, peer
,
314 0, wrepl_socket
->event
.ctx
);
315 if (tevent_req_nomem(subreq
, req
)) {
316 return tevent_req_post(req
, ev
);
319 subreq
->async
.fn
= wrepl_connect_handler
;
320 subreq
->async
.private_data
= req
;
325 static void wrepl_connect_handler(struct composite_context
*subreq
)
327 struct tevent_req
*req
= talloc_get_type_abort(subreq
->async
.private_data
,
329 struct wrepl_connect_state
*state
= tevent_req_data(req
,
330 struct wrepl_connect_state
);
331 struct wrepl_socket
*wrepl_socket
= state
->wrepl_socket
;
334 status
= socket_connect_recv(subreq
);
335 if (!NT_STATUS_IS_OK(status
)) {
336 tevent_req_nterror(req
, status
);
340 wrepl_socket
->event
.fde
= event_add_fd(wrepl_socket
->event
.ctx
, wrepl_socket
,
341 socket_get_fd(wrepl_socket
->sock
),
343 wrepl_handler
, wrepl_socket
);
344 if (tevent_req_nomem(wrepl_socket
->event
.fde
, req
)) {
348 /* setup the stream -> packet parser */
349 wrepl_socket
->packet
= packet_init(wrepl_socket
);
350 if (tevent_req_nomem(wrepl_socket
->packet
, req
)) {
353 packet_set_private(wrepl_socket
->packet
, wrepl_socket
);
354 packet_set_socket(wrepl_socket
->packet
, wrepl_socket
->sock
);
355 packet_set_callback(wrepl_socket
->packet
, wrepl_finish_recv
);
356 packet_set_full_request(wrepl_socket
->packet
, packet_full_request_u32
);
357 packet_set_error_handler(wrepl_socket
->packet
, wrepl_error
);
358 packet_set_event_context(wrepl_socket
->packet
, wrepl_socket
->event
.ctx
);
359 packet_set_fde(wrepl_socket
->packet
, wrepl_socket
->event
.fde
);
360 packet_set_serialise(wrepl_socket
->packet
);
362 tevent_req_done(req
);
366 connect a wrepl_socket to a WINS server - recv side
368 NTSTATUS
wrepl_connect_recv(struct tevent_req
*req
)
370 struct wrepl_connect_state
*state
= tevent_req_data(req
,
371 struct wrepl_connect_state
);
372 struct wrepl_socket
*wrepl_socket
= state
->wrepl_socket
;
375 if (tevent_req_is_nterror(req
, &status
)) {
376 wrepl_socket_dead(wrepl_socket
, status
);
377 tevent_req_received(req
);
381 tevent_req_received(req
);
386 connect a wrepl_socket to a WINS server - sync API
388 NTSTATUS
wrepl_connect(struct wrepl_socket
*wrepl_socket
,
389 const char *our_ip
, const char *peer_ip
)
391 struct tevent_req
*subreq
;
395 subreq
= wrepl_connect_send(wrepl_socket
, wrepl_socket
->event
.ctx
,
396 wrepl_socket
, our_ip
, peer_ip
);
397 NT_STATUS_HAVE_NO_MEMORY(subreq
);
399 ok
= tevent_req_poll(subreq
, wrepl_socket
->event
.ctx
);
402 return NT_STATUS_INTERNAL_ERROR
;
405 status
= wrepl_connect_recv(subreq
);
407 NT_STATUS_NOT_OK_RETURN(status
);
413 callback from wrepl_request_trigger()
415 static void wrepl_request_trigger_handler(struct tevent_context
*ev
, struct tevent_timer
*te
,
416 struct timeval t
, void *ptr
)
418 struct wrepl_request
*req
= talloc_get_type(ptr
, struct wrepl_request
);
425 trigger an immediate event on a wrepl_request
426 the return value should only be used in wrepl_request_send()
427 this is the only place where req->trigger is true
429 static struct wrepl_request
*wrepl_request_finished(struct wrepl_request
*req
, NTSTATUS status
)
431 struct tevent_timer
*te
;
433 if (req
->state
== WREPL_REQUEST_RECV
) {
434 DLIST_REMOVE(req
->wrepl_socket
->recv_queue
, req
);
437 if (!NT_STATUS_IS_OK(status
)) {
438 req
->state
= WREPL_REQUEST_ERROR
;
440 req
->state
= WREPL_REQUEST_DONE
;
443 req
->status
= status
;
446 req
->trigger
= false;
447 /* a zero timeout means immediate */
448 te
= event_add_timed(req
->wrepl_socket
->event
.ctx
,
450 wrepl_request_trigger_handler
, req
);
464 struct wrepl_send_ctrl_state
{
465 struct wrepl_send_ctrl ctrl
;
466 struct wrepl_request
*req
;
467 struct wrepl_socket
*wrepl_sock
;
470 static int wrepl_send_ctrl_destructor(struct wrepl_send_ctrl_state
*s
)
472 struct wrepl_request
*req
= s
->wrepl_sock
->recv_queue
;
474 /* check if the request is still in WREPL_STATE_RECV,
475 * we need this here because the caller has may called
476 * talloc_free(req) and wrepl_send_ctrl_state isn't
477 * a talloc child of the request, so our s->req pointer
480 for (; req
; req
= req
->next
) {
481 if (req
== s
->req
) break;
485 /* here, we need to make sure the async request handler is called
486 * later in the next event_loop and now now
489 wrepl_request_finished(req
, NT_STATUS_OK
);
491 if (s
->ctrl
.disconnect_after_send
) {
492 wrepl_socket_dead(s
->wrepl_sock
, NT_STATUS_LOCAL_DISCONNECT
);
499 send a generic wins replication request
501 struct wrepl_request
*wrepl_request_send(struct wrepl_socket
*wrepl_socket
,
502 struct wrepl_packet
*packet
,
503 struct wrepl_send_ctrl
*ctrl
)
505 struct wrepl_request
*req
;
506 struct wrepl_wrap wrap
;
509 enum ndr_err_code ndr_err
;
511 req
= talloc_zero(wrepl_socket
, struct wrepl_request
);
512 if (!req
) return NULL
;
513 req
->wrepl_socket
= wrepl_socket
;
514 req
->state
= WREPL_REQUEST_RECV
;
517 DLIST_ADD_END(wrepl_socket
->recv_queue
, req
, struct wrepl_request
*);
518 talloc_set_destructor(req
, wrepl_request_destructor
);
520 if (wrepl_socket
->dead
) {
521 return wrepl_request_finished(req
, NT_STATUS_INVALID_CONNECTION
);
524 wrap
.packet
= *packet
;
525 ndr_err
= ndr_push_struct_blob(&blob
, req
, wrepl_socket
->iconv_convenience
, &wrap
,
526 (ndr_push_flags_fn_t
)ndr_push_wrepl_wrap
);
527 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
528 status
= ndr_map_error2ntstatus(ndr_err
);
529 return wrepl_request_finished(req
, status
);
533 DEBUG(10,("Sending WINS packet of length %u\n",
534 (unsigned)blob
.length
));
535 NDR_PRINT_DEBUG(wrepl_packet
, &wrap
.packet
);
538 if (wrepl_socket
->request_timeout
> 0) {
539 req
->te
= event_add_timed(wrepl_socket
->event
.ctx
, req
,
540 timeval_current_ofs(wrepl_socket
->request_timeout
, 0),
541 wrepl_request_timeout_handler
, req
);
542 if (!req
->te
) return wrepl_request_finished(req
, NT_STATUS_NO_MEMORY
);
545 if (ctrl
&& (ctrl
->send_only
|| ctrl
->disconnect_after_send
)) {
546 struct wrepl_send_ctrl_state
*s
= talloc(blob
.data
, struct wrepl_send_ctrl_state
);
547 if (!s
) return wrepl_request_finished(req
, NT_STATUS_NO_MEMORY
);
550 s
->wrepl_sock
= wrepl_socket
;
551 talloc_set_destructor(s
, wrepl_send_ctrl_destructor
);
554 status
= packet_send(wrepl_socket
->packet
, blob
);
555 if (!NT_STATUS_IS_OK(status
)) {
556 return wrepl_request_finished(req
, status
);
559 req
->trigger
= false;
564 receive a generic WINS replication reply
566 NTSTATUS
wrepl_request_recv(struct wrepl_request
*req
,
568 struct wrepl_packet
**packet
)
570 NTSTATUS status
= wrepl_request_wait(req
);
571 if (NT_STATUS_IS_OK(status
) && packet
) {
572 *packet
= talloc_steal(mem_ctx
, req
->packet
);
579 a full WINS replication request/response
581 NTSTATUS
wrepl_request(struct wrepl_socket
*wrepl_socket
,
583 struct wrepl_packet
*req_packet
,
584 struct wrepl_packet
**reply_packet
)
586 struct wrepl_request
*req
= wrepl_request_send(wrepl_socket
, req_packet
, NULL
);
587 return wrepl_request_recv(req
, mem_ctx
, reply_packet
);
591 struct wrepl_associate_state
{
592 struct wrepl_packet packet
;
594 uint16_t major_version
;
597 static void wrepl_associate_done(struct wrepl_request
*subreq
);
599 struct tevent_req
*wrepl_associate_send(TALLOC_CTX
*mem_ctx
,
600 struct tevent_context
*ev
,
601 struct wrepl_socket
*wrepl_socket
,
602 const struct wrepl_associate
*io
)
604 struct tevent_req
*req
;
605 struct wrepl_associate_state
*state
;
606 struct wrepl_request
*subreq
;
608 if (wrepl_socket
->event
.ctx
!= ev
) {
609 /* TODO: remove wrepl_socket->event.ctx !!! */
610 smb_panic("wrepl_associate_send event context mismatch!");
614 req
= tevent_req_create(mem_ctx
, &state
,
615 struct wrepl_associate_state
);
620 state
->packet
.opcode
= WREPL_OPCODE_BITS
;
621 state
->packet
.mess_type
= WREPL_START_ASSOCIATION
;
622 state
->packet
.message
.start
.minor_version
= 2;
623 state
->packet
.message
.start
.major_version
= 5;
626 * nt4 uses 41 bytes for the start_association call
627 * so do it the same and as we don't know th emeanings of this bytes
628 * we just send zeros and nt4, w2k and w2k3 seems to be happy with this
630 * if we don't do this nt4 uses an old version of the wins replication protocol
631 * and that would break nt4 <-> samba replication
633 state
->packet
.padding
= data_blob_talloc(state
, NULL
, 21);
634 if (tevent_req_nomem(state
->packet
.padding
.data
, req
)) {
635 return tevent_req_post(req
, ev
);
637 memset(state
->packet
.padding
.data
, 0, state
->packet
.padding
.length
);
639 subreq
= wrepl_request_send(wrepl_socket
, &state
->packet
, NULL
);
640 if (tevent_req_nomem(subreq
, req
)) {
641 return tevent_req_post(req
, ev
);
643 subreq
->async
.fn
= wrepl_associate_done
;
644 subreq
->async
.private_data
= req
;
649 static void wrepl_associate_done(struct wrepl_request
*subreq
)
651 struct tevent_req
*req
= talloc_get_type_abort(subreq
->async
.private_data
,
653 struct wrepl_associate_state
*state
= tevent_req_data(req
,
654 struct wrepl_associate_state
);
656 struct wrepl_packet
*packet
;
658 status
= wrepl_request_recv(subreq
, state
, &packet
);
659 if (!NT_STATUS_IS_OK(status
)) {
660 tevent_req_nterror(req
, status
);
664 if (packet
->mess_type
!= WREPL_START_ASSOCIATION_REPLY
) {
665 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
669 state
->assoc_ctx
= packet
->message
.start_reply
.assoc_ctx
;
670 state
->major_version
= packet
->message
.start_reply
.major_version
;
672 tevent_req_done(req
);
676 setup an association - recv
678 NTSTATUS
wrepl_associate_recv(struct tevent_req
*req
,
679 struct wrepl_associate
*io
)
681 struct wrepl_associate_state
*state
= tevent_req_data(req
,
682 struct wrepl_associate_state
);
685 if (tevent_req_is_nterror(req
, &status
)) {
686 tevent_req_received(req
);
690 io
->out
.assoc_ctx
= state
->assoc_ctx
;
691 io
->out
.major_version
= state
->major_version
;
693 tevent_req_received(req
);
698 setup an association - sync api
700 NTSTATUS
wrepl_associate(struct wrepl_socket
*wrepl_socket
,
701 struct wrepl_associate
*io
)
703 struct tevent_req
*subreq
;
707 subreq
= wrepl_associate_send(wrepl_socket
, wrepl_socket
->event
.ctx
,
709 NT_STATUS_HAVE_NO_MEMORY(subreq
);
711 ok
= tevent_req_poll(subreq
, wrepl_socket
->event
.ctx
);
714 return NT_STATUS_INTERNAL_ERROR
;
717 status
= wrepl_associate_recv(subreq
, io
);
719 NT_STATUS_NOT_OK_RETURN(status
);
725 stop an association - send
727 struct wrepl_request
*wrepl_associate_stop_send(struct wrepl_socket
*wrepl_socket
,
728 struct wrepl_associate_stop
*io
)
730 struct wrepl_packet
*packet
;
731 struct wrepl_request
*req
;
732 struct wrepl_send_ctrl ctrl
;
734 packet
= talloc_zero(wrepl_socket
, struct wrepl_packet
);
735 if (packet
== NULL
) return NULL
;
737 packet
->opcode
= WREPL_OPCODE_BITS
;
738 packet
->assoc_ctx
= io
->in
.assoc_ctx
;
739 packet
->mess_type
= WREPL_STOP_ASSOCIATION
;
740 packet
->message
.stop
.reason
= io
->in
.reason
;
743 if (io
->in
.reason
== 0) {
744 ctrl
.send_only
= true;
745 ctrl
.disconnect_after_send
= true;
748 req
= wrepl_request_send(wrepl_socket
, packet
, &ctrl
);
756 stop an association - recv
758 NTSTATUS
wrepl_associate_stop_recv(struct wrepl_request
*req
,
759 struct wrepl_associate_stop
*io
)
761 struct wrepl_packet
*packet
=NULL
;
763 status
= wrepl_request_recv(req
, req
->wrepl_socket
, &packet
);
764 NT_STATUS_NOT_OK_RETURN(status
);
770 setup an association - sync api
772 NTSTATUS
wrepl_associate_stop(struct wrepl_socket
*wrepl_socket
,
773 struct wrepl_associate_stop
*io
)
775 struct wrepl_request
*req
= wrepl_associate_stop_send(wrepl_socket
, io
);
776 return wrepl_associate_stop_recv(req
, io
);
779 struct wrepl_pull_table_state
{
780 struct wrepl_packet packet
;
781 uint32_t num_partners
;
782 struct wrepl_wins_owner
*partners
;
785 static void wrepl_pull_table_done(struct wrepl_request
*subreq
);
787 struct tevent_req
*wrepl_pull_table_send(TALLOC_CTX
*mem_ctx
,
788 struct tevent_context
*ev
,
789 struct wrepl_socket
*wrepl_socket
,
790 const struct wrepl_pull_table
*io
)
792 struct tevent_req
*req
;
793 struct wrepl_pull_table_state
*state
;
794 struct wrepl_request
*subreq
;
796 if (wrepl_socket
->event
.ctx
!= ev
) {
797 /* TODO: remove wrepl_socket->event.ctx !!! */
798 smb_panic("wrepl_pull_table_send event context mismatch!");
802 req
= tevent_req_create(mem_ctx
, &state
,
803 struct wrepl_pull_table_state
);
808 state
->packet
.opcode
= WREPL_OPCODE_BITS
;
809 state
->packet
.assoc_ctx
= io
->in
.assoc_ctx
;
810 state
->packet
.mess_type
= WREPL_REPLICATION
;
811 state
->packet
.message
.replication
.command
= WREPL_REPL_TABLE_QUERY
;
813 subreq
= wrepl_request_send(wrepl_socket
, &state
->packet
, NULL
);
814 if (tevent_req_nomem(subreq
, req
)) {
815 return tevent_req_post(req
, ev
);
817 subreq
->async
.fn
= wrepl_pull_table_done
;
818 subreq
->async
.private_data
= req
;
823 static void wrepl_pull_table_done(struct wrepl_request
*subreq
)
825 struct tevent_req
*req
= talloc_get_type_abort(subreq
->async
.private_data
,
827 struct wrepl_pull_table_state
*state
= tevent_req_data(req
,
828 struct wrepl_pull_table_state
);
830 struct wrepl_packet
*packet
;
831 struct wrepl_table
*table
;
833 status
= wrepl_request_recv(subreq
, state
, &packet
);
834 if (!NT_STATUS_IS_OK(status
)) {
835 tevent_req_nterror(req
, status
);
839 if (packet
->mess_type
!= WREPL_REPLICATION
) {
840 tevent_req_nterror(req
, NT_STATUS_NETWORK_ACCESS_DENIED
);
844 if (packet
->message
.replication
.command
!= WREPL_REPL_TABLE_REPLY
) {
845 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
849 table
= &packet
->message
.replication
.info
.table
;
851 state
->num_partners
= table
->partner_count
;
852 state
->partners
= talloc_move(state
, &table
->partners
);
854 tevent_req_done(req
);
858 fetch the partner tables - recv
860 NTSTATUS
wrepl_pull_table_recv(struct tevent_req
*req
,
862 struct wrepl_pull_table
*io
)
864 struct wrepl_pull_table_state
*state
= tevent_req_data(req
,
865 struct wrepl_pull_table_state
);
868 if (tevent_req_is_nterror(req
, &status
)) {
869 tevent_req_received(req
);
873 io
->out
.num_partners
= state
->num_partners
;
874 io
->out
.partners
= talloc_move(mem_ctx
, &state
->partners
);
876 tevent_req_received(req
);
881 fetch the partner table - sync api
883 NTSTATUS
wrepl_pull_table(struct wrepl_socket
*wrepl_socket
,
885 struct wrepl_pull_table
*io
)
887 struct tevent_req
*subreq
;
891 subreq
= wrepl_pull_table_send(mem_ctx
, wrepl_socket
->event
.ctx
,
893 NT_STATUS_HAVE_NO_MEMORY(subreq
);
895 ok
= tevent_req_poll(subreq
, wrepl_socket
->event
.ctx
);
898 return NT_STATUS_INTERNAL_ERROR
;
901 status
= wrepl_pull_table_recv(subreq
, mem_ctx
, io
);
903 NT_STATUS_NOT_OK_RETURN(status
);
909 struct wrepl_pull_names_state
{
911 const struct wrepl_pull_names
*io
;
913 struct wrepl_packet packet
;
915 struct wrepl_name
*names
;
918 static void wrepl_pull_names_done(struct wrepl_request
*subreq
);
920 struct tevent_req
*wrepl_pull_names_send(TALLOC_CTX
*mem_ctx
,
921 struct tevent_context
*ev
,
922 struct wrepl_socket
*wrepl_socket
,
923 const struct wrepl_pull_names
*io
)
925 struct tevent_req
*req
;
926 struct wrepl_pull_names_state
*state
;
927 struct wrepl_request
*subreq
;
929 if (wrepl_socket
->event
.ctx
!= ev
) {
930 /* TODO: remove wrepl_socket->event.ctx !!! */
931 smb_panic("wrepl_pull_names_send event context mismatch!");
935 req
= tevent_req_create(mem_ctx
, &state
,
936 struct wrepl_pull_names_state
);
940 state
->caller
.io
= io
;
942 state
->packet
.opcode
= WREPL_OPCODE_BITS
;
943 state
->packet
.assoc_ctx
= io
->in
.assoc_ctx
;
944 state
->packet
.mess_type
= WREPL_REPLICATION
;
945 state
->packet
.message
.replication
.command
= WREPL_REPL_SEND_REQUEST
;
946 state
->packet
.message
.replication
.info
.owner
= io
->in
.partner
;
948 subreq
= wrepl_request_send(wrepl_socket
, &state
->packet
, NULL
);
949 if (tevent_req_nomem(subreq
, req
)) {
950 return tevent_req_post(req
, ev
);
952 subreq
->async
.fn
= wrepl_pull_names_done
;
953 subreq
->async
.private_data
= req
;
958 static void wrepl_pull_names_done(struct wrepl_request
*subreq
)
960 struct tevent_req
*req
= talloc_get_type_abort(subreq
->async
.private_data
,
962 struct wrepl_pull_names_state
*state
= tevent_req_data(req
,
963 struct wrepl_pull_names_state
);
965 struct wrepl_packet
*packet
;
968 status
= wrepl_request_recv(subreq
, state
, &packet
);
969 if (!NT_STATUS_IS_OK(status
)) {
970 tevent_req_nterror(req
, status
);
974 if (packet
->mess_type
!= WREPL_REPLICATION
) {
975 tevent_req_nterror(req
, NT_STATUS_NETWORK_ACCESS_DENIED
);
979 if (packet
->message
.replication
.command
!= WREPL_REPL_SEND_REPLY
) {
980 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
984 state
->num_names
= packet
->message
.replication
.info
.reply
.num_names
;
986 state
->names
= talloc_array(state
, struct wrepl_name
, state
->num_names
);
987 if (tevent_req_nomem(state
->names
, req
)) {
991 /* convert the list of names and addresses to a sane format */
992 for (i
=0; i
< state
->num_names
; i
++) {
993 struct wrepl_wins_name
*wname
= &packet
->message
.replication
.info
.reply
.names
[i
];
994 struct wrepl_name
*name
= &state
->names
[i
];
996 name
->name
= *wname
->name
;
997 talloc_steal(state
->names
, wname
->name
);
998 name
->type
= WREPL_NAME_TYPE(wname
->flags
);
999 name
->state
= WREPL_NAME_STATE(wname
->flags
);
1000 name
->node
= WREPL_NAME_NODE(wname
->flags
);
1001 name
->is_static
= WREPL_NAME_IS_STATIC(wname
->flags
);
1002 name
->raw_flags
= wname
->flags
;
1003 name
->version_id
= wname
->id
;
1004 name
->owner
= talloc_strdup(state
->names
,
1005 state
->caller
.io
->in
.partner
.address
);
1006 if (tevent_req_nomem(name
->owner
, req
)) {
1010 /* trying to save 1 or 2 bytes on the wire isn't a good idea */
1011 if (wname
->flags
& 2) {
1014 name
->num_addresses
= wname
->addresses
.addresses
.num_ips
;
1015 name
->addresses
= talloc_array(state
->names
,
1016 struct wrepl_address
,
1017 name
->num_addresses
);
1018 if (tevent_req_nomem(name
->addresses
, req
)) {
1022 for (j
=0;j
<name
->num_addresses
;j
++) {
1023 name
->addresses
[j
].owner
=
1024 talloc_move(name
->addresses
,
1025 &wname
->addresses
.addresses
.ips
[j
].owner
);
1026 name
->addresses
[j
].address
=
1027 talloc_move(name
->addresses
,
1028 &wname
->addresses
.addresses
.ips
[j
].ip
);
1031 name
->num_addresses
= 1;
1032 name
->addresses
= talloc_array(state
->names
,
1033 struct wrepl_address
,
1034 name
->num_addresses
);
1035 if (tevent_req_nomem(name
->addresses
, req
)) {
1039 name
->addresses
[0].owner
= talloc_strdup(name
->addresses
, name
->owner
);
1040 if (tevent_req_nomem(name
->addresses
[0].owner
, req
)) {
1043 name
->addresses
[0].address
= talloc_move(name
->addresses
,
1044 &wname
->addresses
.ip
);
1048 tevent_req_done(req
);
1052 fetch the names for a WINS partner - recv
1054 NTSTATUS
wrepl_pull_names_recv(struct tevent_req
*req
,
1055 TALLOC_CTX
*mem_ctx
,
1056 struct wrepl_pull_names
*io
)
1058 struct wrepl_pull_names_state
*state
= tevent_req_data(req
,
1059 struct wrepl_pull_names_state
);
1062 if (tevent_req_is_nterror(req
, &status
)) {
1063 tevent_req_received(req
);
1067 io
->out
.num_names
= state
->num_names
;
1068 io
->out
.names
= talloc_move(mem_ctx
, &state
->names
);
1070 tevent_req_received(req
);
1071 return NT_STATUS_OK
;
1077 fetch the names for a WINS partner - sync api
1079 NTSTATUS
wrepl_pull_names(struct wrepl_socket
*wrepl_socket
,
1080 TALLOC_CTX
*mem_ctx
,
1081 struct wrepl_pull_names
*io
)
1083 struct tevent_req
*subreq
;
1087 subreq
= wrepl_pull_names_send(mem_ctx
, wrepl_socket
->event
.ctx
,
1089 NT_STATUS_HAVE_NO_MEMORY(subreq
);
1091 ok
= tevent_req_poll(subreq
, wrepl_socket
->event
.ctx
);
1093 TALLOC_FREE(subreq
);
1094 return NT_STATUS_INTERNAL_ERROR
;
1097 status
= wrepl_pull_names_recv(subreq
, mem_ctx
, io
);
1098 TALLOC_FREE(subreq
);
1099 NT_STATUS_NOT_OK_RETURN(status
);
1101 return NT_STATUS_OK
;