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
);
111 /* as client we want to drain the recv queue on error */
112 tstream_bsd_fail_readv_first_error(wrepl_socket
->stream
, false);
117 initialise a wrepl_socket from an already existing connection
119 NTSTATUS
wrepl_socket_split_stream(struct wrepl_socket
*wrepl_socket
,
121 struct tstream_context
**stream
)
125 if (!wrepl_socket
->stream
) {
126 return NT_STATUS_CONNECTION_INVALID
;
129 num_requests
= tevent_queue_length(wrepl_socket
->request_queue
);
130 if (num_requests
> 0) {
131 return NT_STATUS_CONNECTION_IN_USE
;
134 *stream
= talloc_move(wrepl_socket
, &wrepl_socket
->stream
);
138 const char *wrepl_best_ip(struct loadparm_context
*lp_ctx
, const char *peer_ip
)
140 struct interface
*ifaces
;
141 load_interface_list(lp_ctx
, lp_ctx
, &ifaces
);
142 return iface_list_best_ip(ifaces
, peer_ip
);
145 struct wrepl_connect_state
{
147 struct wrepl_socket
*wrepl_socket
;
148 struct tevent_context
*ev
;
150 struct tsocket_address
*local_address
;
151 struct tsocket_address
*remote_address
;
152 struct tstream_context
*stream
;
155 static void wrepl_connect_trigger(struct tevent_req
*req
,
158 struct tevent_req
*wrepl_connect_send(TALLOC_CTX
*mem_ctx
,
159 struct tevent_context
*ev
,
160 struct wrepl_socket
*wrepl_socket
,
161 const char *our_ip
, const char *peer_ip
)
163 struct tevent_req
*req
;
164 struct wrepl_connect_state
*state
;
168 req
= tevent_req_create(mem_ctx
, &state
,
169 struct wrepl_connect_state
);
174 state
->caller
.wrepl_socket
= wrepl_socket
;
175 state
->caller
.ev
= ev
;
177 if (wrepl_socket
->stream
) {
178 tevent_req_nterror(req
, NT_STATUS_CONNECTION_ACTIVE
);
179 return tevent_req_post(req
, ev
);
182 ret
= tsocket_address_inet_from_strings(state
, "ipv4",
184 &state
->local_address
);
186 NTSTATUS status
= map_nt_error_from_unix_common(errno
);
187 tevent_req_nterror(req
, status
);
188 return tevent_req_post(req
, ev
);
191 ret
= tsocket_address_inet_from_strings(state
, "ipv4",
192 peer_ip
, WINS_REPLICATION_PORT
,
193 &state
->remote_address
);
195 NTSTATUS status
= map_nt_error_from_unix_common(errno
);
196 tevent_req_nterror(req
, status
);
197 return tevent_req_post(req
, ev
);
200 ok
= tevent_queue_add(wrepl_socket
->request_queue
,
203 wrepl_connect_trigger
,
207 return tevent_req_post(req
, ev
);
210 if (wrepl_socket
->request_timeout
> 0) {
211 struct timeval endtime
;
212 endtime
= tevent_timeval_current_ofs(wrepl_socket
->request_timeout
, 0);
213 ok
= tevent_req_set_endtime(req
, ev
, endtime
);
215 return tevent_req_post(req
, ev
);
222 static void wrepl_connect_done(struct tevent_req
*subreq
);
224 static void wrepl_connect_trigger(struct tevent_req
*req
,
227 struct wrepl_connect_state
*state
= tevent_req_data(req
,
228 struct wrepl_connect_state
);
229 struct tevent_req
*subreq
;
231 subreq
= tstream_inet_tcp_connect_send(state
,
233 state
->local_address
,
234 state
->remote_address
);
235 if (tevent_req_nomem(subreq
, req
)) {
238 tevent_req_set_callback(subreq
, wrepl_connect_done
, req
);
243 static void wrepl_connect_done(struct tevent_req
*subreq
)
245 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
247 struct wrepl_connect_state
*state
= tevent_req_data(req
,
248 struct wrepl_connect_state
);
252 ret
= tstream_inet_tcp_connect_recv(subreq
, &sys_errno
,
253 state
, &state
->stream
, NULL
);
255 NTSTATUS status
= map_nt_error_from_unix_common(sys_errno
);
256 tevent_req_nterror(req
, status
);
260 tevent_req_done(req
);
264 connect a wrepl_socket to a WINS server - recv side
266 NTSTATUS
wrepl_connect_recv(struct tevent_req
*req
)
268 struct wrepl_connect_state
*state
= tevent_req_data(req
,
269 struct wrepl_connect_state
);
270 struct wrepl_socket
*wrepl_socket
= state
->caller
.wrepl_socket
;
273 if (tevent_req_is_nterror(req
, &status
)) {
274 tevent_req_received(req
);
278 wrepl_socket
->stream
= talloc_move(wrepl_socket
, &state
->stream
);
280 tevent_req_received(req
);
285 connect a wrepl_socket to a WINS server - sync API
287 NTSTATUS
wrepl_connect(struct wrepl_socket
*wrepl_socket
,
288 const char *our_ip
, const char *peer_ip
)
290 struct tevent_req
*subreq
;
294 subreq
= wrepl_connect_send(wrepl_socket
, wrepl_socket
->event
.ctx
,
295 wrepl_socket
, our_ip
, peer_ip
);
296 NT_STATUS_HAVE_NO_MEMORY(subreq
);
298 ok
= tevent_req_poll(subreq
, wrepl_socket
->event
.ctx
);
301 return NT_STATUS_INTERNAL_ERROR
;
304 status
= wrepl_connect_recv(subreq
);
306 NT_STATUS_NOT_OK_RETURN(status
);
311 struct wrepl_request_state
{
313 struct wrepl_socket
*wrepl_socket
;
314 struct tevent_context
*ev
;
316 struct wrepl_send_ctrl ctrl
;
318 struct wrepl_wrap wrap
;
325 struct wrepl_packet
*packet
;
329 static void wrepl_request_trigger(struct tevent_req
*req
,
332 struct tevent_req
*wrepl_request_send(TALLOC_CTX
*mem_ctx
,
333 struct tevent_context
*ev
,
334 struct wrepl_socket
*wrepl_socket
,
335 const struct wrepl_packet
*packet
,
336 const struct wrepl_send_ctrl
*ctrl
)
338 struct tevent_req
*req
;
339 struct wrepl_request_state
*state
;
341 enum ndr_err_code ndr_err
;
344 if (wrepl_socket
->event
.ctx
!= ev
) {
345 /* TODO: remove wrepl_socket->event.ctx !!! */
346 smb_panic("wrepl_associate_stop_send event context mismatch!");
350 req
= tevent_req_create(mem_ctx
, &state
,
351 struct wrepl_request_state
);
356 state
->caller
.wrepl_socket
= wrepl_socket
;
357 state
->caller
.ev
= ev
;
363 if (wrepl_socket
->stream
== NULL
) {
364 tevent_req_nterror(req
, NT_STATUS_CONNECTION_DISCONNECTED
);
365 return tevent_req_post(req
, ev
);
368 state
->req
.wrap
.packet
= *packet
;
369 ndr_err
= ndr_push_struct_blob(&state
->req
.blob
, state
,
371 (ndr_push_flags_fn_t
)ndr_push_wrepl_wrap
);
372 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
373 status
= ndr_map_error2ntstatus(ndr_err
);
374 tevent_req_nterror(req
, status
);
375 return tevent_req_post(req
, ev
);
378 state
->req
.iov
.iov_base
= (char *) state
->req
.blob
.data
;
379 state
->req
.iov
.iov_len
= state
->req
.blob
.length
;
381 ok
= tevent_queue_add(wrepl_socket
->request_queue
,
384 wrepl_request_trigger
,
388 return tevent_req_post(req
, ev
);
391 if (wrepl_socket
->request_timeout
> 0) {
392 struct timeval endtime
;
393 endtime
= tevent_timeval_current_ofs(wrepl_socket
->request_timeout
, 0);
394 ok
= tevent_req_set_endtime(req
, ev
, endtime
);
396 return tevent_req_post(req
, ev
);
403 static void wrepl_request_writev_done(struct tevent_req
*subreq
);
405 static void wrepl_request_trigger(struct tevent_req
*req
,
408 struct wrepl_request_state
*state
= tevent_req_data(req
,
409 struct wrepl_request_state
);
410 struct tevent_req
*subreq
;
412 if (state
->caller
.wrepl_socket
->stream
== NULL
) {
413 tevent_req_nterror(req
, NT_STATUS_CONNECTION_DISCONNECTED
);
418 DEBUG(10,("Sending WINS packet of length %u\n",
419 (unsigned)state
->req
.blob
.length
));
420 NDR_PRINT_DEBUG(wrepl_packet
, &state
->req
.wrap
.packet
);
423 subreq
= tstream_writev_send(state
,
425 state
->caller
.wrepl_socket
->stream
,
427 if (tevent_req_nomem(subreq
, req
)) {
430 tevent_req_set_callback(subreq
, wrepl_request_writev_done
, req
);
433 static void wrepl_request_disconnect_done(struct tevent_req
*subreq
);
434 static void wrepl_request_read_pdu_done(struct tevent_req
*subreq
);
436 static void wrepl_request_writev_done(struct tevent_req
*subreq
)
438 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
440 struct wrepl_request_state
*state
= tevent_req_data(req
,
441 struct wrepl_request_state
);
445 ret
= tstream_writev_recv(subreq
, &sys_errno
);
448 NTSTATUS status
= map_nt_error_from_unix_common(sys_errno
);
449 TALLOC_FREE(state
->caller
.wrepl_socket
->stream
);
450 tevent_req_nterror(req
, status
);
454 if (state
->caller
.wrepl_socket
->stream
== NULL
) {
455 tevent_req_nterror(req
, NT_STATUS_CONNECTION_DISCONNECTED
);
459 if (state
->ctrl
.disconnect_after_send
) {
460 subreq
= tstream_disconnect_send(state
,
462 state
->caller
.wrepl_socket
->stream
);
463 if (tevent_req_nomem(subreq
, req
)) {
466 tevent_req_set_callback(subreq
, wrepl_request_disconnect_done
, req
);
470 if (state
->ctrl
.send_only
) {
471 tevent_req_done(req
);
475 subreq
= tstream_read_pdu_blob_send(state
,
477 state
->caller
.wrepl_socket
->stream
,
478 4, /* initial_read_size */
479 tstream_full_request_u32
,
481 if (tevent_req_nomem(subreq
, req
)) {
484 tevent_req_set_callback(subreq
, wrepl_request_read_pdu_done
, req
);
487 static void wrepl_request_disconnect_done(struct tevent_req
*subreq
)
489 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
491 struct wrepl_request_state
*state
= tevent_req_data(req
,
492 struct wrepl_request_state
);
496 ret
= tstream_disconnect_recv(subreq
, &sys_errno
);
499 NTSTATUS status
= map_nt_error_from_unix_common(sys_errno
);
500 TALLOC_FREE(state
->caller
.wrepl_socket
->stream
);
501 tevent_req_nterror(req
, status
);
505 DEBUG(10,("WINS connection disconnected\n"));
506 TALLOC_FREE(state
->caller
.wrepl_socket
->stream
);
508 tevent_req_done(req
);
511 static void wrepl_request_read_pdu_done(struct tevent_req
*subreq
)
513 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
515 struct wrepl_request_state
*state
= tevent_req_data(req
,
516 struct wrepl_request_state
);
519 enum ndr_err_code ndr_err
;
521 status
= tstream_read_pdu_blob_recv(subreq
, state
, &state
->rep
.blob
);
522 if (!NT_STATUS_IS_OK(status
)) {
523 TALLOC_FREE(state
->caller
.wrepl_socket
->stream
);
524 tevent_req_nterror(req
, status
);
528 state
->rep
.packet
= talloc(state
, struct wrepl_packet
);
529 if (tevent_req_nomem(state
->rep
.packet
, req
)) {
533 blob
.data
= state
->rep
.blob
.data
+ 4;
534 blob
.length
= state
->rep
.blob
.length
- 4;
536 /* we have a full request - parse it */
537 ndr_err
= ndr_pull_struct_blob(&blob
,
540 (ndr_pull_flags_fn_t
)ndr_pull_wrepl_packet
);
541 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
542 status
= ndr_map_error2ntstatus(ndr_err
);
543 tevent_req_nterror(req
, status
);
548 DEBUG(10,("Received WINS packet of length %u\n",
549 (unsigned)state
->rep
.blob
.length
));
550 NDR_PRINT_DEBUG(wrepl_packet
, state
->rep
.packet
);
553 tevent_req_done(req
);
556 NTSTATUS
wrepl_request_recv(struct tevent_req
*req
,
558 struct wrepl_packet
**packet
)
560 struct wrepl_request_state
*state
= tevent_req_data(req
,
561 struct wrepl_request_state
);
564 if (tevent_req_is_nterror(req
, &status
)) {
565 TALLOC_FREE(state
->caller
.wrepl_socket
->stream
);
566 tevent_req_received(req
);
571 *packet
= talloc_move(mem_ctx
, &state
->rep
.packet
);
574 tevent_req_received(req
);
579 a full WINS replication request/response
581 NTSTATUS
wrepl_request(struct wrepl_socket
*wrepl_socket
,
583 const struct wrepl_packet
*req_packet
,
584 struct wrepl_packet
**reply_packet
)
586 struct tevent_req
*subreq
;
590 subreq
= wrepl_request_send(mem_ctx
, wrepl_socket
->event
.ctx
,
591 wrepl_socket
, req_packet
, NULL
);
592 NT_STATUS_HAVE_NO_MEMORY(subreq
);
594 ok
= tevent_req_poll(subreq
, wrepl_socket
->event
.ctx
);
597 return NT_STATUS_INTERNAL_ERROR
;
600 status
= wrepl_request_recv(subreq
, mem_ctx
, reply_packet
);
602 NT_STATUS_NOT_OK_RETURN(status
);
608 struct wrepl_associate_state
{
609 struct wrepl_packet packet
;
611 uint16_t major_version
;
614 static void wrepl_associate_done(struct tevent_req
*subreq
);
616 struct tevent_req
*wrepl_associate_send(TALLOC_CTX
*mem_ctx
,
617 struct tevent_context
*ev
,
618 struct wrepl_socket
*wrepl_socket
,
619 const struct wrepl_associate
*io
)
621 struct tevent_req
*req
;
622 struct wrepl_associate_state
*state
;
623 struct tevent_req
*subreq
;
625 if (wrepl_socket
->event
.ctx
!= ev
) {
626 /* TODO: remove wrepl_socket->event.ctx !!! */
627 smb_panic("wrepl_associate_send event context mismatch!");
631 req
= tevent_req_create(mem_ctx
, &state
,
632 struct wrepl_associate_state
);
637 state
->packet
.opcode
= WREPL_OPCODE_BITS
;
638 state
->packet
.mess_type
= WREPL_START_ASSOCIATION
;
639 state
->packet
.message
.start
.minor_version
= 2;
640 state
->packet
.message
.start
.major_version
= 5;
643 * nt4 uses 41 bytes for the start_association call
644 * so do it the same and as we don't know the meanings of these bytes
645 * we just send zeros and nt4, w2k and w2k3 seems to be happy with this
647 * if we don't do this nt4 uses an old version of the wins replication protocol
648 * and that would break nt4 <-> samba replication
650 state
->packet
.padding
= data_blob_talloc(state
, NULL
, 21);
651 if (tevent_req_nomem(state
->packet
.padding
.data
, req
)) {
652 return tevent_req_post(req
, ev
);
654 memset(state
->packet
.padding
.data
, 0, state
->packet
.padding
.length
);
656 subreq
= wrepl_request_send(state
, ev
, wrepl_socket
, &state
->packet
, NULL
);
657 if (tevent_req_nomem(subreq
, req
)) {
658 return tevent_req_post(req
, ev
);
660 tevent_req_set_callback(subreq
, wrepl_associate_done
, req
);
665 static void wrepl_associate_done(struct tevent_req
*subreq
)
667 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
669 struct wrepl_associate_state
*state
= tevent_req_data(req
,
670 struct wrepl_associate_state
);
672 struct wrepl_packet
*packet
;
674 status
= wrepl_request_recv(subreq
, state
, &packet
);
676 if (!NT_STATUS_IS_OK(status
)) {
677 tevent_req_nterror(req
, status
);
681 if (packet
->mess_type
!= WREPL_START_ASSOCIATION_REPLY
) {
682 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
686 state
->assoc_ctx
= packet
->message
.start_reply
.assoc_ctx
;
687 state
->major_version
= packet
->message
.start_reply
.major_version
;
689 tevent_req_done(req
);
693 setup an association - recv
695 NTSTATUS
wrepl_associate_recv(struct tevent_req
*req
,
696 struct wrepl_associate
*io
)
698 struct wrepl_associate_state
*state
= tevent_req_data(req
,
699 struct wrepl_associate_state
);
702 if (tevent_req_is_nterror(req
, &status
)) {
703 tevent_req_received(req
);
707 io
->out
.assoc_ctx
= state
->assoc_ctx
;
708 io
->out
.major_version
= state
->major_version
;
710 tevent_req_received(req
);
715 setup an association - sync api
717 NTSTATUS
wrepl_associate(struct wrepl_socket
*wrepl_socket
,
718 struct wrepl_associate
*io
)
720 struct tevent_req
*subreq
;
724 subreq
= wrepl_associate_send(wrepl_socket
, wrepl_socket
->event
.ctx
,
726 NT_STATUS_HAVE_NO_MEMORY(subreq
);
728 ok
= tevent_req_poll(subreq
, wrepl_socket
->event
.ctx
);
731 return NT_STATUS_INTERNAL_ERROR
;
734 status
= wrepl_associate_recv(subreq
, io
);
736 NT_STATUS_NOT_OK_RETURN(status
);
741 struct wrepl_associate_stop_state
{
742 struct wrepl_packet packet
;
743 struct wrepl_send_ctrl ctrl
;
746 static void wrepl_associate_stop_done(struct tevent_req
*subreq
);
748 struct tevent_req
*wrepl_associate_stop_send(TALLOC_CTX
*mem_ctx
,
749 struct tevent_context
*ev
,
750 struct wrepl_socket
*wrepl_socket
,
751 const struct wrepl_associate_stop
*io
)
753 struct tevent_req
*req
;
754 struct wrepl_associate_stop_state
*state
;
755 struct tevent_req
*subreq
;
757 if (wrepl_socket
->event
.ctx
!= ev
) {
758 /* TODO: remove wrepl_socket->event.ctx !!! */
759 smb_panic("wrepl_associate_stop_send event context mismatch!");
763 req
= tevent_req_create(mem_ctx
, &state
,
764 struct wrepl_associate_stop_state
);
769 state
->packet
.opcode
= WREPL_OPCODE_BITS
;
770 state
->packet
.assoc_ctx
= io
->in
.assoc_ctx
;
771 state
->packet
.mess_type
= WREPL_STOP_ASSOCIATION
;
772 state
->packet
.message
.stop
.reason
= io
->in
.reason
;
774 if (io
->in
.reason
== 0) {
775 state
->ctrl
.send_only
= true;
776 state
->ctrl
.disconnect_after_send
= true;
779 subreq
= wrepl_request_send(state
, ev
, wrepl_socket
, &state
->packet
, &state
->ctrl
);
780 if (tevent_req_nomem(subreq
, req
)) {
781 return tevent_req_post(req
, ev
);
783 tevent_req_set_callback(subreq
, wrepl_associate_stop_done
, req
);
788 static void wrepl_associate_stop_done(struct tevent_req
*subreq
)
790 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
792 struct wrepl_associate_stop_state
*state
= tevent_req_data(req
,
793 struct wrepl_associate_stop_state
);
796 /* currently we don't care about a possible response */
797 status
= wrepl_request_recv(subreq
, state
, NULL
);
799 if (!NT_STATUS_IS_OK(status
)) {
800 tevent_req_nterror(req
, status
);
804 tevent_req_done(req
);
808 stop an association - recv
810 NTSTATUS
wrepl_associate_stop_recv(struct tevent_req
*req
,
811 struct wrepl_associate_stop
*io
)
815 if (tevent_req_is_nterror(req
, &status
)) {
816 tevent_req_received(req
);
820 tevent_req_received(req
);
825 setup an association - sync api
827 NTSTATUS
wrepl_associate_stop(struct wrepl_socket
*wrepl_socket
,
828 struct wrepl_associate_stop
*io
)
830 struct tevent_req
*subreq
;
834 subreq
= wrepl_associate_stop_send(wrepl_socket
, wrepl_socket
->event
.ctx
,
836 NT_STATUS_HAVE_NO_MEMORY(subreq
);
838 ok
= tevent_req_poll(subreq
, wrepl_socket
->event
.ctx
);
841 return NT_STATUS_INTERNAL_ERROR
;
844 status
= wrepl_associate_stop_recv(subreq
, io
);
846 NT_STATUS_NOT_OK_RETURN(status
);
851 struct wrepl_pull_table_state
{
852 struct wrepl_packet packet
;
853 uint32_t num_partners
;
854 struct wrepl_wins_owner
*partners
;
857 static void wrepl_pull_table_done(struct tevent_req
*subreq
);
859 struct tevent_req
*wrepl_pull_table_send(TALLOC_CTX
*mem_ctx
,
860 struct tevent_context
*ev
,
861 struct wrepl_socket
*wrepl_socket
,
862 const struct wrepl_pull_table
*io
)
864 struct tevent_req
*req
;
865 struct wrepl_pull_table_state
*state
;
866 struct tevent_req
*subreq
;
868 if (wrepl_socket
->event
.ctx
!= ev
) {
869 /* TODO: remove wrepl_socket->event.ctx !!! */
870 smb_panic("wrepl_pull_table_send event context mismatch!");
874 req
= tevent_req_create(mem_ctx
, &state
,
875 struct wrepl_pull_table_state
);
880 state
->packet
.opcode
= WREPL_OPCODE_BITS
;
881 state
->packet
.assoc_ctx
= io
->in
.assoc_ctx
;
882 state
->packet
.mess_type
= WREPL_REPLICATION
;
883 state
->packet
.message
.replication
.command
= WREPL_REPL_TABLE_QUERY
;
885 subreq
= wrepl_request_send(state
, ev
, wrepl_socket
, &state
->packet
, NULL
);
886 if (tevent_req_nomem(subreq
, req
)) {
887 return tevent_req_post(req
, ev
);
889 tevent_req_set_callback(subreq
, wrepl_pull_table_done
, req
);
894 static void wrepl_pull_table_done(struct tevent_req
*subreq
)
896 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
898 struct wrepl_pull_table_state
*state
= tevent_req_data(req
,
899 struct wrepl_pull_table_state
);
901 struct wrepl_packet
*packet
;
902 struct wrepl_table
*table
;
904 status
= wrepl_request_recv(subreq
, state
, &packet
);
906 if (!NT_STATUS_IS_OK(status
)) {
907 tevent_req_nterror(req
, status
);
911 if (packet
->mess_type
!= WREPL_REPLICATION
) {
912 tevent_req_nterror(req
, NT_STATUS_NETWORK_ACCESS_DENIED
);
916 if (packet
->message
.replication
.command
!= WREPL_REPL_TABLE_REPLY
) {
917 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
921 table
= &packet
->message
.replication
.info
.table
;
923 state
->num_partners
= table
->partner_count
;
924 state
->partners
= talloc_move(state
, &table
->partners
);
926 tevent_req_done(req
);
930 fetch the partner tables - recv
932 NTSTATUS
wrepl_pull_table_recv(struct tevent_req
*req
,
934 struct wrepl_pull_table
*io
)
936 struct wrepl_pull_table_state
*state
= tevent_req_data(req
,
937 struct wrepl_pull_table_state
);
940 if (tevent_req_is_nterror(req
, &status
)) {
941 tevent_req_received(req
);
945 io
->out
.num_partners
= state
->num_partners
;
946 io
->out
.partners
= talloc_move(mem_ctx
, &state
->partners
);
948 tevent_req_received(req
);
953 fetch the partner table - sync api
955 NTSTATUS
wrepl_pull_table(struct wrepl_socket
*wrepl_socket
,
957 struct wrepl_pull_table
*io
)
959 struct tevent_req
*subreq
;
963 subreq
= wrepl_pull_table_send(mem_ctx
, wrepl_socket
->event
.ctx
,
965 NT_STATUS_HAVE_NO_MEMORY(subreq
);
967 ok
= tevent_req_poll(subreq
, wrepl_socket
->event
.ctx
);
970 return NT_STATUS_INTERNAL_ERROR
;
973 status
= wrepl_pull_table_recv(subreq
, mem_ctx
, io
);
975 NT_STATUS_NOT_OK_RETURN(status
);
981 struct wrepl_pull_names_state
{
983 const struct wrepl_pull_names
*io
;
985 struct wrepl_packet packet
;
987 struct wrepl_name
*names
;
990 static void wrepl_pull_names_done(struct tevent_req
*subreq
);
992 struct tevent_req
*wrepl_pull_names_send(TALLOC_CTX
*mem_ctx
,
993 struct tevent_context
*ev
,
994 struct wrepl_socket
*wrepl_socket
,
995 const struct wrepl_pull_names
*io
)
997 struct tevent_req
*req
;
998 struct wrepl_pull_names_state
*state
;
999 struct tevent_req
*subreq
;
1001 if (wrepl_socket
->event
.ctx
!= ev
) {
1002 /* TODO: remove wrepl_socket->event.ctx !!! */
1003 smb_panic("wrepl_pull_names_send event context mismatch!");
1007 req
= tevent_req_create(mem_ctx
, &state
,
1008 struct wrepl_pull_names_state
);
1012 state
->caller
.io
= io
;
1014 state
->packet
.opcode
= WREPL_OPCODE_BITS
;
1015 state
->packet
.assoc_ctx
= io
->in
.assoc_ctx
;
1016 state
->packet
.mess_type
= WREPL_REPLICATION
;
1017 state
->packet
.message
.replication
.command
= WREPL_REPL_SEND_REQUEST
;
1018 state
->packet
.message
.replication
.info
.owner
= io
->in
.partner
;
1020 subreq
= wrepl_request_send(state
, ev
, wrepl_socket
, &state
->packet
, NULL
);
1021 if (tevent_req_nomem(subreq
, req
)) {
1022 return tevent_req_post(req
, ev
);
1024 tevent_req_set_callback(subreq
, wrepl_pull_names_done
, req
);
1029 static void wrepl_pull_names_done(struct tevent_req
*subreq
)
1031 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
1033 struct wrepl_pull_names_state
*state
= tevent_req_data(req
,
1034 struct wrepl_pull_names_state
);
1036 struct wrepl_packet
*packet
;
1039 status
= wrepl_request_recv(subreq
, state
, &packet
);
1040 TALLOC_FREE(subreq
);
1041 if (!NT_STATUS_IS_OK(status
)) {
1042 tevent_req_nterror(req
, status
);
1046 if (packet
->mess_type
!= WREPL_REPLICATION
) {
1047 tevent_req_nterror(req
, NT_STATUS_NETWORK_ACCESS_DENIED
);
1051 if (packet
->message
.replication
.command
!= WREPL_REPL_SEND_REPLY
) {
1052 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
1056 state
->num_names
= packet
->message
.replication
.info
.reply
.num_names
;
1058 state
->names
= talloc_array(state
, struct wrepl_name
, state
->num_names
);
1059 if (tevent_req_nomem(state
->names
, req
)) {
1063 /* convert the list of names and addresses to a sane format */
1064 for (i
=0; i
< state
->num_names
; i
++) {
1065 struct wrepl_wins_name
*wname
= &packet
->message
.replication
.info
.reply
.names
[i
];
1066 struct wrepl_name
*name
= &state
->names
[i
];
1068 name
->name
= *wname
->name
;
1069 talloc_steal(state
->names
, wname
->name
);
1070 name
->type
= WREPL_NAME_TYPE(wname
->flags
);
1071 name
->state
= WREPL_NAME_STATE(wname
->flags
);
1072 name
->node
= WREPL_NAME_NODE(wname
->flags
);
1073 name
->is_static
= WREPL_NAME_IS_STATIC(wname
->flags
);
1074 name
->raw_flags
= wname
->flags
;
1075 name
->version_id
= wname
->id
;
1076 name
->owner
= talloc_strdup(state
->names
,
1077 state
->caller
.io
->in
.partner
.address
);
1078 if (tevent_req_nomem(name
->owner
, req
)) {
1082 /* trying to save 1 or 2 bytes on the wire isn't a good idea */
1083 if (wname
->flags
& 2) {
1086 name
->num_addresses
= wname
->addresses
.addresses
.num_ips
;
1087 name
->addresses
= talloc_array(state
->names
,
1088 struct wrepl_address
,
1089 name
->num_addresses
);
1090 if (tevent_req_nomem(name
->addresses
, req
)) {
1094 for (j
=0;j
<name
->num_addresses
;j
++) {
1095 name
->addresses
[j
].owner
=
1096 talloc_move(name
->addresses
,
1097 &wname
->addresses
.addresses
.ips
[j
].owner
);
1098 name
->addresses
[j
].address
=
1099 talloc_move(name
->addresses
,
1100 &wname
->addresses
.addresses
.ips
[j
].ip
);
1103 name
->num_addresses
= 1;
1104 name
->addresses
= talloc_array(state
->names
,
1105 struct wrepl_address
,
1106 name
->num_addresses
);
1107 if (tevent_req_nomem(name
->addresses
, req
)) {
1111 name
->addresses
[0].owner
= talloc_strdup(name
->addresses
, name
->owner
);
1112 if (tevent_req_nomem(name
->addresses
[0].owner
, req
)) {
1115 name
->addresses
[0].address
= talloc_move(name
->addresses
,
1116 &wname
->addresses
.ip
);
1120 tevent_req_done(req
);
1124 fetch the names for a WINS partner - recv
1126 NTSTATUS
wrepl_pull_names_recv(struct tevent_req
*req
,
1127 TALLOC_CTX
*mem_ctx
,
1128 struct wrepl_pull_names
*io
)
1130 struct wrepl_pull_names_state
*state
= tevent_req_data(req
,
1131 struct wrepl_pull_names_state
);
1134 if (tevent_req_is_nterror(req
, &status
)) {
1135 tevent_req_received(req
);
1139 io
->out
.num_names
= state
->num_names
;
1140 io
->out
.names
= talloc_move(mem_ctx
, &state
->names
);
1142 tevent_req_received(req
);
1143 return NT_STATUS_OK
;
1149 fetch the names for a WINS partner - sync api
1151 NTSTATUS
wrepl_pull_names(struct wrepl_socket
*wrepl_socket
,
1152 TALLOC_CTX
*mem_ctx
,
1153 struct wrepl_pull_names
*io
)
1155 struct tevent_req
*subreq
;
1159 subreq
= wrepl_pull_names_send(mem_ctx
, wrepl_socket
->event
.ctx
,
1161 NT_STATUS_HAVE_NO_MEMORY(subreq
);
1163 ok
= tevent_req_poll(subreq
, wrepl_socket
->event
.ctx
);
1165 TALLOC_FREE(subreq
);
1166 return NT_STATUS_INTERNAL_ERROR
;
1169 status
= wrepl_pull_names_recv(subreq
, mem_ctx
, io
);
1170 TALLOC_FREE(subreq
);
1171 NT_STATUS_NOT_OK_RETURN(status
);
1173 return NT_STATUS_OK
;