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 "libcli/wrepl/winsrepl.h"
27 #include "librpc/gen_ndr/ndr_winsrepl.h"
28 #include "lib/stream/packet.h"
29 #include "system/network.h"
30 #include "lib/socket/netif.h"
31 #include "param/param.h"
32 #include "lib/util/tevent_ntstatus.h"
33 #include "lib/tsocket/tsocket.h"
34 #include "libcli/util/tstream.h"
37 main context structure for the wins replication client library
41 struct tevent_context
*ctx
;
44 /* the default timeout for requests, 0 means no timeout */
45 #define WREPL_SOCKET_REQUEST_TIMEOUT (60)
46 uint32_t request_timeout
;
48 struct tevent_queue
*request_queue
;
50 struct tstream_context
*stream
;
53 bool wrepl_socket_is_connected(struct wrepl_socket
*wrepl_sock
)
59 if (!wrepl_sock
->stream
) {
67 initialise a wrepl_socket. The event_ctx is optional, if provided then
68 operations will use that event context
70 struct wrepl_socket
*wrepl_socket_init(TALLOC_CTX
*mem_ctx
,
71 struct tevent_context
*event_ctx
)
73 struct wrepl_socket
*wrepl_socket
;
75 wrepl_socket
= talloc_zero(mem_ctx
, struct wrepl_socket
);
80 wrepl_socket
->event
.ctx
= event_ctx
;
81 if (!wrepl_socket
->event
.ctx
) {
85 wrepl_socket
->request_queue
= tevent_queue_create(wrepl_socket
,
86 "wrepl request queue");
87 if (wrepl_socket
->request_queue
== NULL
) {
91 wrepl_socket
->request_timeout
= WREPL_SOCKET_REQUEST_TIMEOUT
;
96 talloc_free(wrepl_socket
);
101 initialise a wrepl_socket from an already existing connection
103 NTSTATUS
wrepl_socket_donate_stream(struct wrepl_socket
*wrepl_socket
,
104 struct tstream_context
**stream
)
106 if (wrepl_socket
->stream
) {
107 return NT_STATUS_CONNECTION_ACTIVE
;
110 wrepl_socket
->stream
= talloc_move(wrepl_socket
, stream
);
115 initialise a wrepl_socket from an already existing connection
117 NTSTATUS
wrepl_socket_split_stream(struct wrepl_socket
*wrepl_socket
,
119 struct tstream_context
**stream
)
123 if (!wrepl_socket
->stream
) {
124 return NT_STATUS_CONNECTION_INVALID
;
127 num_requests
= tevent_queue_length(wrepl_socket
->request_queue
);
128 if (num_requests
> 0) {
129 return NT_STATUS_CONNECTION_IN_USE
;
132 *stream
= talloc_move(wrepl_socket
, &wrepl_socket
->stream
);
136 const char *wrepl_best_ip(struct loadparm_context
*lp_ctx
, const char *peer_ip
)
138 struct interface
*ifaces
;
139 load_interface_list(lp_ctx
, lp_ctx
, &ifaces
);
140 return iface_list_best_ip(ifaces
, peer_ip
);
143 struct wrepl_connect_state
{
145 struct wrepl_socket
*wrepl_socket
;
146 struct tevent_context
*ev
;
148 struct tsocket_address
*local_address
;
149 struct tsocket_address
*remote_address
;
150 struct tstream_context
*stream
;
153 static void wrepl_connect_trigger(struct tevent_req
*req
,
156 struct tevent_req
*wrepl_connect_send(TALLOC_CTX
*mem_ctx
,
157 struct tevent_context
*ev
,
158 struct wrepl_socket
*wrepl_socket
,
159 const char *our_ip
, const char *peer_ip
)
161 struct tevent_req
*req
;
162 struct wrepl_connect_state
*state
;
166 req
= tevent_req_create(mem_ctx
, &state
,
167 struct wrepl_connect_state
);
172 state
->caller
.wrepl_socket
= wrepl_socket
;
173 state
->caller
.ev
= ev
;
175 if (wrepl_socket
->stream
) {
176 tevent_req_nterror(req
, NT_STATUS_CONNECTION_ACTIVE
);
177 return tevent_req_post(req
, ev
);
180 ret
= tsocket_address_inet_from_strings(state
, "ipv4",
182 &state
->local_address
);
184 NTSTATUS status
= map_nt_error_from_unix_common(errno
);
185 tevent_req_nterror(req
, status
);
186 return tevent_req_post(req
, ev
);
189 ret
= tsocket_address_inet_from_strings(state
, "ipv4",
190 peer_ip
, WINS_REPLICATION_PORT
,
191 &state
->remote_address
);
193 NTSTATUS status
= map_nt_error_from_unix_common(errno
);
194 tevent_req_nterror(req
, status
);
195 return tevent_req_post(req
, ev
);
198 ok
= tevent_queue_add(wrepl_socket
->request_queue
,
201 wrepl_connect_trigger
,
205 return tevent_req_post(req
, ev
);
208 if (wrepl_socket
->request_timeout
> 0) {
209 struct timeval endtime
;
210 endtime
= tevent_timeval_current_ofs(wrepl_socket
->request_timeout
, 0);
211 ok
= tevent_req_set_endtime(req
, ev
, endtime
);
213 return tevent_req_post(req
, ev
);
220 static void wrepl_connect_done(struct tevent_req
*subreq
);
222 static void wrepl_connect_trigger(struct tevent_req
*req
,
225 struct wrepl_connect_state
*state
= tevent_req_data(req
,
226 struct wrepl_connect_state
);
227 struct tevent_req
*subreq
;
229 subreq
= tstream_inet_tcp_connect_send(state
,
231 state
->local_address
,
232 state
->remote_address
);
233 if (tevent_req_nomem(subreq
, req
)) {
236 tevent_req_set_callback(subreq
, wrepl_connect_done
, req
);
241 static void wrepl_connect_done(struct tevent_req
*subreq
)
243 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
245 struct wrepl_connect_state
*state
= tevent_req_data(req
,
246 struct wrepl_connect_state
);
250 ret
= tstream_inet_tcp_connect_recv(subreq
, &sys_errno
,
251 state
, &state
->stream
, NULL
);
253 NTSTATUS status
= map_nt_error_from_unix_common(sys_errno
);
254 tevent_req_nterror(req
, status
);
258 tevent_req_done(req
);
262 connect a wrepl_socket to a WINS server - recv side
264 NTSTATUS
wrepl_connect_recv(struct tevent_req
*req
)
266 struct wrepl_connect_state
*state
= tevent_req_data(req
,
267 struct wrepl_connect_state
);
268 struct wrepl_socket
*wrepl_socket
= state
->caller
.wrepl_socket
;
271 if (tevent_req_is_nterror(req
, &status
)) {
272 tevent_req_received(req
);
276 wrepl_socket
->stream
= talloc_move(wrepl_socket
, &state
->stream
);
278 tevent_req_received(req
);
283 connect a wrepl_socket to a WINS server - sync API
285 NTSTATUS
wrepl_connect(struct wrepl_socket
*wrepl_socket
,
286 const char *our_ip
, const char *peer_ip
)
288 struct tevent_req
*subreq
;
292 subreq
= wrepl_connect_send(wrepl_socket
, wrepl_socket
->event
.ctx
,
293 wrepl_socket
, our_ip
, peer_ip
);
294 NT_STATUS_HAVE_NO_MEMORY(subreq
);
296 ok
= tevent_req_poll(subreq
, wrepl_socket
->event
.ctx
);
299 return NT_STATUS_INTERNAL_ERROR
;
302 status
= wrepl_connect_recv(subreq
);
304 NT_STATUS_NOT_OK_RETURN(status
);
309 struct wrepl_request_state
{
311 struct wrepl_socket
*wrepl_socket
;
312 struct tevent_context
*ev
;
314 struct wrepl_send_ctrl ctrl
;
316 struct wrepl_wrap wrap
;
323 struct wrepl_packet
*packet
;
327 static void wrepl_request_trigger(struct tevent_req
*req
,
330 struct tevent_req
*wrepl_request_send(TALLOC_CTX
*mem_ctx
,
331 struct tevent_context
*ev
,
332 struct wrepl_socket
*wrepl_socket
,
333 const struct wrepl_packet
*packet
,
334 const struct wrepl_send_ctrl
*ctrl
)
336 struct tevent_req
*req
;
337 struct wrepl_request_state
*state
;
339 enum ndr_err_code ndr_err
;
342 if (wrepl_socket
->event
.ctx
!= ev
) {
343 /* TODO: remove wrepl_socket->event.ctx !!! */
344 smb_panic("wrepl_associate_stop_send event context mismatch!");
348 req
= tevent_req_create(mem_ctx
, &state
,
349 struct wrepl_request_state
);
354 state
->caller
.wrepl_socket
= wrepl_socket
;
355 state
->caller
.ev
= ev
;
361 if (wrepl_socket
->stream
== NULL
) {
362 tevent_req_nterror(req
, NT_STATUS_CONNECTION_DISCONNECTED
);
363 return tevent_req_post(req
, ev
);
366 state
->req
.wrap
.packet
= *packet
;
367 ndr_err
= ndr_push_struct_blob(&state
->req
.blob
, state
,
369 (ndr_push_flags_fn_t
)ndr_push_wrepl_wrap
);
370 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
371 status
= ndr_map_error2ntstatus(ndr_err
);
372 tevent_req_nterror(req
, status
);
373 return tevent_req_post(req
, ev
);
376 state
->req
.iov
.iov_base
= (char *) state
->req
.blob
.data
;
377 state
->req
.iov
.iov_len
= state
->req
.blob
.length
;
379 ok
= tevent_queue_add(wrepl_socket
->request_queue
,
382 wrepl_request_trigger
,
386 return tevent_req_post(req
, ev
);
389 if (wrepl_socket
->request_timeout
> 0) {
390 struct timeval endtime
;
391 endtime
= tevent_timeval_current_ofs(wrepl_socket
->request_timeout
, 0);
392 ok
= tevent_req_set_endtime(req
, ev
, endtime
);
394 return tevent_req_post(req
, ev
);
401 static void wrepl_request_writev_done(struct tevent_req
*subreq
);
403 static void wrepl_request_trigger(struct tevent_req
*req
,
406 struct wrepl_request_state
*state
= tevent_req_data(req
,
407 struct wrepl_request_state
);
408 struct tevent_req
*subreq
;
410 if (state
->caller
.wrepl_socket
->stream
== NULL
) {
411 tevent_req_nterror(req
, NT_STATUS_CONNECTION_DISCONNECTED
);
416 DEBUG(10,("Sending WINS packet of length %u\n",
417 (unsigned)state
->req
.blob
.length
));
418 NDR_PRINT_DEBUG(wrepl_packet
, &state
->req
.wrap
.packet
);
421 subreq
= tstream_writev_send(state
,
423 state
->caller
.wrepl_socket
->stream
,
425 if (tevent_req_nomem(subreq
, req
)) {
428 tevent_req_set_callback(subreq
, wrepl_request_writev_done
, req
);
431 static void wrepl_request_disconnect_done(struct tevent_req
*subreq
);
432 static void wrepl_request_read_pdu_done(struct tevent_req
*subreq
);
434 static void wrepl_request_writev_done(struct tevent_req
*subreq
)
436 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
438 struct wrepl_request_state
*state
= tevent_req_data(req
,
439 struct wrepl_request_state
);
443 ret
= tstream_writev_recv(subreq
, &sys_errno
);
446 NTSTATUS status
= map_nt_error_from_unix_common(sys_errno
);
447 TALLOC_FREE(state
->caller
.wrepl_socket
->stream
);
448 tevent_req_nterror(req
, status
);
452 if (state
->caller
.wrepl_socket
->stream
== NULL
) {
453 tevent_req_nterror(req
, NT_STATUS_CONNECTION_DISCONNECTED
);
457 if (state
->ctrl
.disconnect_after_send
) {
458 subreq
= tstream_disconnect_send(state
,
460 state
->caller
.wrepl_socket
->stream
);
461 if (tevent_req_nomem(subreq
, req
)) {
464 tevent_req_set_callback(subreq
, wrepl_request_disconnect_done
, req
);
468 if (state
->ctrl
.send_only
) {
469 tevent_req_done(req
);
473 subreq
= tstream_read_pdu_blob_send(state
,
475 state
->caller
.wrepl_socket
->stream
,
476 4, /* initial_read_size */
477 packet_full_request_u32
,
479 if (tevent_req_nomem(subreq
, req
)) {
482 tevent_req_set_callback(subreq
, wrepl_request_read_pdu_done
, req
);
485 static void wrepl_request_disconnect_done(struct tevent_req
*subreq
)
487 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
489 struct wrepl_request_state
*state
= tevent_req_data(req
,
490 struct wrepl_request_state
);
494 ret
= tstream_disconnect_recv(subreq
, &sys_errno
);
497 NTSTATUS status
= map_nt_error_from_unix_common(sys_errno
);
498 TALLOC_FREE(state
->caller
.wrepl_socket
->stream
);
499 tevent_req_nterror(req
, status
);
503 DEBUG(10,("WINS connection disconnected\n"));
504 TALLOC_FREE(state
->caller
.wrepl_socket
->stream
);
506 tevent_req_done(req
);
509 static void wrepl_request_read_pdu_done(struct tevent_req
*subreq
)
511 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
513 struct wrepl_request_state
*state
= tevent_req_data(req
,
514 struct wrepl_request_state
);
517 enum ndr_err_code ndr_err
;
519 status
= tstream_read_pdu_blob_recv(subreq
, state
, &state
->rep
.blob
);
520 if (!NT_STATUS_IS_OK(status
)) {
521 TALLOC_FREE(state
->caller
.wrepl_socket
->stream
);
522 tevent_req_nterror(req
, status
);
526 state
->rep
.packet
= talloc(state
, struct wrepl_packet
);
527 if (tevent_req_nomem(state
->rep
.packet
, req
)) {
531 blob
.data
= state
->rep
.blob
.data
+ 4;
532 blob
.length
= state
->rep
.blob
.length
- 4;
534 /* we have a full request - parse it */
535 ndr_err
= ndr_pull_struct_blob(&blob
,
538 (ndr_pull_flags_fn_t
)ndr_pull_wrepl_packet
);
539 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
540 status
= ndr_map_error2ntstatus(ndr_err
);
541 tevent_req_nterror(req
, status
);
546 DEBUG(10,("Received WINS packet of length %u\n",
547 (unsigned)state
->rep
.blob
.length
));
548 NDR_PRINT_DEBUG(wrepl_packet
, state
->rep
.packet
);
551 tevent_req_done(req
);
554 NTSTATUS
wrepl_request_recv(struct tevent_req
*req
,
556 struct wrepl_packet
**packet
)
558 struct wrepl_request_state
*state
= tevent_req_data(req
,
559 struct wrepl_request_state
);
562 if (tevent_req_is_nterror(req
, &status
)) {
563 TALLOC_FREE(state
->caller
.wrepl_socket
->stream
);
564 tevent_req_received(req
);
569 *packet
= talloc_move(mem_ctx
, &state
->rep
.packet
);
572 tevent_req_received(req
);
577 a full WINS replication request/response
579 NTSTATUS
wrepl_request(struct wrepl_socket
*wrepl_socket
,
581 const struct wrepl_packet
*req_packet
,
582 struct wrepl_packet
**reply_packet
)
584 struct tevent_req
*subreq
;
588 subreq
= wrepl_request_send(mem_ctx
, wrepl_socket
->event
.ctx
,
589 wrepl_socket
, req_packet
, NULL
);
590 NT_STATUS_HAVE_NO_MEMORY(subreq
);
592 ok
= tevent_req_poll(subreq
, wrepl_socket
->event
.ctx
);
595 return NT_STATUS_INTERNAL_ERROR
;
598 status
= wrepl_request_recv(subreq
, mem_ctx
, reply_packet
);
600 NT_STATUS_NOT_OK_RETURN(status
);
606 struct wrepl_associate_state
{
607 struct wrepl_packet packet
;
609 uint16_t major_version
;
612 static void wrepl_associate_done(struct tevent_req
*subreq
);
614 struct tevent_req
*wrepl_associate_send(TALLOC_CTX
*mem_ctx
,
615 struct tevent_context
*ev
,
616 struct wrepl_socket
*wrepl_socket
,
617 const struct wrepl_associate
*io
)
619 struct tevent_req
*req
;
620 struct wrepl_associate_state
*state
;
621 struct tevent_req
*subreq
;
623 if (wrepl_socket
->event
.ctx
!= ev
) {
624 /* TODO: remove wrepl_socket->event.ctx !!! */
625 smb_panic("wrepl_associate_send event context mismatch!");
629 req
= tevent_req_create(mem_ctx
, &state
,
630 struct wrepl_associate_state
);
635 state
->packet
.opcode
= WREPL_OPCODE_BITS
;
636 state
->packet
.mess_type
= WREPL_START_ASSOCIATION
;
637 state
->packet
.message
.start
.minor_version
= 2;
638 state
->packet
.message
.start
.major_version
= 5;
641 * nt4 uses 41 bytes for the start_association call
642 * so do it the same and as we don't know th emeanings of this bytes
643 * we just send zeros and nt4, w2k and w2k3 seems to be happy with this
645 * if we don't do this nt4 uses an old version of the wins replication protocol
646 * and that would break nt4 <-> samba replication
648 state
->packet
.padding
= data_blob_talloc(state
, NULL
, 21);
649 if (tevent_req_nomem(state
->packet
.padding
.data
, req
)) {
650 return tevent_req_post(req
, ev
);
652 memset(state
->packet
.padding
.data
, 0, state
->packet
.padding
.length
);
654 subreq
= wrepl_request_send(state
, ev
, wrepl_socket
, &state
->packet
, NULL
);
655 if (tevent_req_nomem(subreq
, req
)) {
656 return tevent_req_post(req
, ev
);
658 tevent_req_set_callback(subreq
, wrepl_associate_done
, req
);
663 static void wrepl_associate_done(struct tevent_req
*subreq
)
665 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
667 struct wrepl_associate_state
*state
= tevent_req_data(req
,
668 struct wrepl_associate_state
);
670 struct wrepl_packet
*packet
;
672 status
= wrepl_request_recv(subreq
, state
, &packet
);
674 if (!NT_STATUS_IS_OK(status
)) {
675 tevent_req_nterror(req
, status
);
679 if (packet
->mess_type
!= WREPL_START_ASSOCIATION_REPLY
) {
680 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
684 state
->assoc_ctx
= packet
->message
.start_reply
.assoc_ctx
;
685 state
->major_version
= packet
->message
.start_reply
.major_version
;
687 tevent_req_done(req
);
691 setup an association - recv
693 NTSTATUS
wrepl_associate_recv(struct tevent_req
*req
,
694 struct wrepl_associate
*io
)
696 struct wrepl_associate_state
*state
= tevent_req_data(req
,
697 struct wrepl_associate_state
);
700 if (tevent_req_is_nterror(req
, &status
)) {
701 tevent_req_received(req
);
705 io
->out
.assoc_ctx
= state
->assoc_ctx
;
706 io
->out
.major_version
= state
->major_version
;
708 tevent_req_received(req
);
713 setup an association - sync api
715 NTSTATUS
wrepl_associate(struct wrepl_socket
*wrepl_socket
,
716 struct wrepl_associate
*io
)
718 struct tevent_req
*subreq
;
722 subreq
= wrepl_associate_send(wrepl_socket
, wrepl_socket
->event
.ctx
,
724 NT_STATUS_HAVE_NO_MEMORY(subreq
);
726 ok
= tevent_req_poll(subreq
, wrepl_socket
->event
.ctx
);
729 return NT_STATUS_INTERNAL_ERROR
;
732 status
= wrepl_associate_recv(subreq
, io
);
734 NT_STATUS_NOT_OK_RETURN(status
);
739 struct wrepl_associate_stop_state
{
740 struct wrepl_packet packet
;
741 struct wrepl_send_ctrl ctrl
;
744 static void wrepl_associate_stop_done(struct tevent_req
*subreq
);
746 struct tevent_req
*wrepl_associate_stop_send(TALLOC_CTX
*mem_ctx
,
747 struct tevent_context
*ev
,
748 struct wrepl_socket
*wrepl_socket
,
749 const struct wrepl_associate_stop
*io
)
751 struct tevent_req
*req
;
752 struct wrepl_associate_stop_state
*state
;
753 struct tevent_req
*subreq
;
755 if (wrepl_socket
->event
.ctx
!= ev
) {
756 /* TODO: remove wrepl_socket->event.ctx !!! */
757 smb_panic("wrepl_associate_stop_send event context mismatch!");
761 req
= tevent_req_create(mem_ctx
, &state
,
762 struct wrepl_associate_stop_state
);
767 state
->packet
.opcode
= WREPL_OPCODE_BITS
;
768 state
->packet
.assoc_ctx
= io
->in
.assoc_ctx
;
769 state
->packet
.mess_type
= WREPL_STOP_ASSOCIATION
;
770 state
->packet
.message
.stop
.reason
= io
->in
.reason
;
772 if (io
->in
.reason
== 0) {
773 state
->ctrl
.send_only
= true;
774 state
->ctrl
.disconnect_after_send
= true;
777 subreq
= wrepl_request_send(state
, ev
, wrepl_socket
, &state
->packet
, &state
->ctrl
);
778 if (tevent_req_nomem(subreq
, req
)) {
779 return tevent_req_post(req
, ev
);
781 tevent_req_set_callback(subreq
, wrepl_associate_stop_done
, req
);
786 static void wrepl_associate_stop_done(struct tevent_req
*subreq
)
788 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
790 struct wrepl_associate_stop_state
*state
= tevent_req_data(req
,
791 struct wrepl_associate_stop_state
);
794 /* currently we don't care about a possible response */
795 status
= wrepl_request_recv(subreq
, state
, NULL
);
797 if (!NT_STATUS_IS_OK(status
)) {
798 tevent_req_nterror(req
, status
);
802 tevent_req_done(req
);
806 stop an association - recv
808 NTSTATUS
wrepl_associate_stop_recv(struct tevent_req
*req
,
809 struct wrepl_associate_stop
*io
)
813 if (tevent_req_is_nterror(req
, &status
)) {
814 tevent_req_received(req
);
818 tevent_req_received(req
);
823 setup an association - sync api
825 NTSTATUS
wrepl_associate_stop(struct wrepl_socket
*wrepl_socket
,
826 struct wrepl_associate_stop
*io
)
828 struct tevent_req
*subreq
;
832 subreq
= wrepl_associate_stop_send(wrepl_socket
, wrepl_socket
->event
.ctx
,
834 NT_STATUS_HAVE_NO_MEMORY(subreq
);
836 ok
= tevent_req_poll(subreq
, wrepl_socket
->event
.ctx
);
839 return NT_STATUS_INTERNAL_ERROR
;
842 status
= wrepl_associate_stop_recv(subreq
, io
);
844 NT_STATUS_NOT_OK_RETURN(status
);
849 struct wrepl_pull_table_state
{
850 struct wrepl_packet packet
;
851 uint32_t num_partners
;
852 struct wrepl_wins_owner
*partners
;
855 static void wrepl_pull_table_done(struct tevent_req
*subreq
);
857 struct tevent_req
*wrepl_pull_table_send(TALLOC_CTX
*mem_ctx
,
858 struct tevent_context
*ev
,
859 struct wrepl_socket
*wrepl_socket
,
860 const struct wrepl_pull_table
*io
)
862 struct tevent_req
*req
;
863 struct wrepl_pull_table_state
*state
;
864 struct tevent_req
*subreq
;
866 if (wrepl_socket
->event
.ctx
!= ev
) {
867 /* TODO: remove wrepl_socket->event.ctx !!! */
868 smb_panic("wrepl_pull_table_send event context mismatch!");
872 req
= tevent_req_create(mem_ctx
, &state
,
873 struct wrepl_pull_table_state
);
878 state
->packet
.opcode
= WREPL_OPCODE_BITS
;
879 state
->packet
.assoc_ctx
= io
->in
.assoc_ctx
;
880 state
->packet
.mess_type
= WREPL_REPLICATION
;
881 state
->packet
.message
.replication
.command
= WREPL_REPL_TABLE_QUERY
;
883 subreq
= wrepl_request_send(state
, ev
, wrepl_socket
, &state
->packet
, NULL
);
884 if (tevent_req_nomem(subreq
, req
)) {
885 return tevent_req_post(req
, ev
);
887 tevent_req_set_callback(subreq
, wrepl_pull_table_done
, req
);
892 static void wrepl_pull_table_done(struct tevent_req
*subreq
)
894 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
896 struct wrepl_pull_table_state
*state
= tevent_req_data(req
,
897 struct wrepl_pull_table_state
);
899 struct wrepl_packet
*packet
;
900 struct wrepl_table
*table
;
902 status
= wrepl_request_recv(subreq
, state
, &packet
);
904 if (!NT_STATUS_IS_OK(status
)) {
905 tevent_req_nterror(req
, status
);
909 if (packet
->mess_type
!= WREPL_REPLICATION
) {
910 tevent_req_nterror(req
, NT_STATUS_NETWORK_ACCESS_DENIED
);
914 if (packet
->message
.replication
.command
!= WREPL_REPL_TABLE_REPLY
) {
915 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
919 table
= &packet
->message
.replication
.info
.table
;
921 state
->num_partners
= table
->partner_count
;
922 state
->partners
= talloc_move(state
, &table
->partners
);
924 tevent_req_done(req
);
928 fetch the partner tables - recv
930 NTSTATUS
wrepl_pull_table_recv(struct tevent_req
*req
,
932 struct wrepl_pull_table
*io
)
934 struct wrepl_pull_table_state
*state
= tevent_req_data(req
,
935 struct wrepl_pull_table_state
);
938 if (tevent_req_is_nterror(req
, &status
)) {
939 tevent_req_received(req
);
943 io
->out
.num_partners
= state
->num_partners
;
944 io
->out
.partners
= talloc_move(mem_ctx
, &state
->partners
);
946 tevent_req_received(req
);
951 fetch the partner table - sync api
953 NTSTATUS
wrepl_pull_table(struct wrepl_socket
*wrepl_socket
,
955 struct wrepl_pull_table
*io
)
957 struct tevent_req
*subreq
;
961 subreq
= wrepl_pull_table_send(mem_ctx
, wrepl_socket
->event
.ctx
,
963 NT_STATUS_HAVE_NO_MEMORY(subreq
);
965 ok
= tevent_req_poll(subreq
, wrepl_socket
->event
.ctx
);
968 return NT_STATUS_INTERNAL_ERROR
;
971 status
= wrepl_pull_table_recv(subreq
, mem_ctx
, io
);
973 NT_STATUS_NOT_OK_RETURN(status
);
979 struct wrepl_pull_names_state
{
981 const struct wrepl_pull_names
*io
;
983 struct wrepl_packet packet
;
985 struct wrepl_name
*names
;
988 static void wrepl_pull_names_done(struct tevent_req
*subreq
);
990 struct tevent_req
*wrepl_pull_names_send(TALLOC_CTX
*mem_ctx
,
991 struct tevent_context
*ev
,
992 struct wrepl_socket
*wrepl_socket
,
993 const struct wrepl_pull_names
*io
)
995 struct tevent_req
*req
;
996 struct wrepl_pull_names_state
*state
;
997 struct tevent_req
*subreq
;
999 if (wrepl_socket
->event
.ctx
!= ev
) {
1000 /* TODO: remove wrepl_socket->event.ctx !!! */
1001 smb_panic("wrepl_pull_names_send event context mismatch!");
1005 req
= tevent_req_create(mem_ctx
, &state
,
1006 struct wrepl_pull_names_state
);
1010 state
->caller
.io
= io
;
1012 state
->packet
.opcode
= WREPL_OPCODE_BITS
;
1013 state
->packet
.assoc_ctx
= io
->in
.assoc_ctx
;
1014 state
->packet
.mess_type
= WREPL_REPLICATION
;
1015 state
->packet
.message
.replication
.command
= WREPL_REPL_SEND_REQUEST
;
1016 state
->packet
.message
.replication
.info
.owner
= io
->in
.partner
;
1018 subreq
= wrepl_request_send(state
, ev
, wrepl_socket
, &state
->packet
, NULL
);
1019 if (tevent_req_nomem(subreq
, req
)) {
1020 return tevent_req_post(req
, ev
);
1022 tevent_req_set_callback(subreq
, wrepl_pull_names_done
, req
);
1027 static void wrepl_pull_names_done(struct tevent_req
*subreq
)
1029 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
1031 struct wrepl_pull_names_state
*state
= tevent_req_data(req
,
1032 struct wrepl_pull_names_state
);
1034 struct wrepl_packet
*packet
;
1037 status
= wrepl_request_recv(subreq
, state
, &packet
);
1038 TALLOC_FREE(subreq
);
1039 if (!NT_STATUS_IS_OK(status
)) {
1040 tevent_req_nterror(req
, status
);
1044 if (packet
->mess_type
!= WREPL_REPLICATION
) {
1045 tevent_req_nterror(req
, NT_STATUS_NETWORK_ACCESS_DENIED
);
1049 if (packet
->message
.replication
.command
!= WREPL_REPL_SEND_REPLY
) {
1050 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
1054 state
->num_names
= packet
->message
.replication
.info
.reply
.num_names
;
1056 state
->names
= talloc_array(state
, struct wrepl_name
, state
->num_names
);
1057 if (tevent_req_nomem(state
->names
, req
)) {
1061 /* convert the list of names and addresses to a sane format */
1062 for (i
=0; i
< state
->num_names
; i
++) {
1063 struct wrepl_wins_name
*wname
= &packet
->message
.replication
.info
.reply
.names
[i
];
1064 struct wrepl_name
*name
= &state
->names
[i
];
1066 name
->name
= *wname
->name
;
1067 talloc_steal(state
->names
, wname
->name
);
1068 name
->type
= WREPL_NAME_TYPE(wname
->flags
);
1069 name
->state
= WREPL_NAME_STATE(wname
->flags
);
1070 name
->node
= WREPL_NAME_NODE(wname
->flags
);
1071 name
->is_static
= WREPL_NAME_IS_STATIC(wname
->flags
);
1072 name
->raw_flags
= wname
->flags
;
1073 name
->version_id
= wname
->id
;
1074 name
->owner
= talloc_strdup(state
->names
,
1075 state
->caller
.io
->in
.partner
.address
);
1076 if (tevent_req_nomem(name
->owner
, req
)) {
1080 /* trying to save 1 or 2 bytes on the wire isn't a good idea */
1081 if (wname
->flags
& 2) {
1084 name
->num_addresses
= wname
->addresses
.addresses
.num_ips
;
1085 name
->addresses
= talloc_array(state
->names
,
1086 struct wrepl_address
,
1087 name
->num_addresses
);
1088 if (tevent_req_nomem(name
->addresses
, req
)) {
1092 for (j
=0;j
<name
->num_addresses
;j
++) {
1093 name
->addresses
[j
].owner
=
1094 talloc_move(name
->addresses
,
1095 &wname
->addresses
.addresses
.ips
[j
].owner
);
1096 name
->addresses
[j
].address
=
1097 talloc_move(name
->addresses
,
1098 &wname
->addresses
.addresses
.ips
[j
].ip
);
1101 name
->num_addresses
= 1;
1102 name
->addresses
= talloc_array(state
->names
,
1103 struct wrepl_address
,
1104 name
->num_addresses
);
1105 if (tevent_req_nomem(name
->addresses
, req
)) {
1109 name
->addresses
[0].owner
= talloc_strdup(name
->addresses
, name
->owner
);
1110 if (tevent_req_nomem(name
->addresses
[0].owner
, req
)) {
1113 name
->addresses
[0].address
= talloc_move(name
->addresses
,
1114 &wname
->addresses
.ip
);
1118 tevent_req_done(req
);
1122 fetch the names for a WINS partner - recv
1124 NTSTATUS
wrepl_pull_names_recv(struct tevent_req
*req
,
1125 TALLOC_CTX
*mem_ctx
,
1126 struct wrepl_pull_names
*io
)
1128 struct wrepl_pull_names_state
*state
= tevent_req_data(req
,
1129 struct wrepl_pull_names_state
);
1132 if (tevent_req_is_nterror(req
, &status
)) {
1133 tevent_req_received(req
);
1137 io
->out
.num_names
= state
->num_names
;
1138 io
->out
.names
= talloc_move(mem_ctx
, &state
->names
);
1140 tevent_req_received(req
);
1141 return NT_STATUS_OK
;
1147 fetch the names for a WINS partner - sync api
1149 NTSTATUS
wrepl_pull_names(struct wrepl_socket
*wrepl_socket
,
1150 TALLOC_CTX
*mem_ctx
,
1151 struct wrepl_pull_names
*io
)
1153 struct tevent_req
*subreq
;
1157 subreq
= wrepl_pull_names_send(mem_ctx
, wrepl_socket
->event
.ctx
,
1159 NT_STATUS_HAVE_NO_MEMORY(subreq
);
1161 ok
= tevent_req_poll(subreq
, wrepl_socket
->event
.ctx
);
1163 TALLOC_FREE(subreq
);
1164 return NT_STATUS_INTERNAL_ERROR
;
1167 status
= wrepl_pull_names_recv(subreq
, mem_ctx
, io
);
1168 TALLOC_FREE(subreq
);
1169 NT_STATUS_NOT_OK_RETURN(status
);
1171 return NT_STATUS_OK
;