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);
259 tevent_req_done(req);
263 connect a wrepl_socket to a WINS server - recv side
265 NTSTATUS wrepl_connect_recv(struct tevent_req *req)
267 struct wrepl_connect_state *state = tevent_req_data(req,
268 struct wrepl_connect_state);
269 struct wrepl_socket *wrepl_socket = state->caller.wrepl_socket;
272 if (tevent_req_is_nterror(req, &status)) {
273 tevent_req_received(req);
277 wrepl_socket->stream = talloc_move(wrepl_socket, &state->stream);
279 tevent_req_received(req);
284 connect a wrepl_socket to a WINS server - sync API
286 NTSTATUS wrepl_connect(struct wrepl_socket *wrepl_socket,
287 const char *our_ip, const char *peer_ip)
289 struct tevent_req *subreq;
293 subreq = wrepl_connect_send(wrepl_socket, wrepl_socket->event.ctx,
294 wrepl_socket, our_ip, peer_ip);
295 NT_STATUS_HAVE_NO_MEMORY(subreq);
297 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
300 return NT_STATUS_INTERNAL_ERROR;
303 status = wrepl_connect_recv(subreq);
305 NT_STATUS_NOT_OK_RETURN(status);
310 struct wrepl_request_state {
312 struct wrepl_socket *wrepl_socket;
313 struct tevent_context *ev;
315 struct wrepl_send_ctrl ctrl;
317 struct wrepl_wrap wrap;
324 struct wrepl_packet *packet;
328 static void wrepl_request_trigger(struct tevent_req *req,
331 struct tevent_req *wrepl_request_send(TALLOC_CTX *mem_ctx,
332 struct tevent_context *ev,
333 struct wrepl_socket *wrepl_socket,
334 const struct wrepl_packet *packet,
335 const struct wrepl_send_ctrl *ctrl)
337 struct tevent_req *req;
338 struct wrepl_request_state *state;
340 enum ndr_err_code ndr_err;
343 if (wrepl_socket->event.ctx != ev) {
344 /* TODO: remove wrepl_socket->event.ctx !!! */
345 smb_panic("wrepl_associate_stop_send event context mismatch!");
349 req = tevent_req_create(mem_ctx, &state,
350 struct wrepl_request_state);
355 state->caller.wrepl_socket = wrepl_socket;
356 state->caller.ev = ev;
362 if (wrepl_socket->stream == NULL) {
363 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
364 return tevent_req_post(req, ev);
367 state->req.wrap.packet = *packet;
368 ndr_err = ndr_push_struct_blob(&state->req.blob, state,
370 (ndr_push_flags_fn_t)ndr_push_wrepl_wrap);
371 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
372 status = ndr_map_error2ntstatus(ndr_err);
373 tevent_req_nterror(req, status);
374 return tevent_req_post(req, ev);
377 state->req.iov.iov_base = (char *) state->req.blob.data;
378 state->req.iov.iov_len = state->req.blob.length;
380 ok = tevent_queue_add(wrepl_socket->request_queue,
383 wrepl_request_trigger,
387 return tevent_req_post(req, ev);
390 if (wrepl_socket->request_timeout > 0) {
391 struct timeval endtime;
392 endtime = tevent_timeval_current_ofs(wrepl_socket->request_timeout, 0);
393 ok = tevent_req_set_endtime(req, ev, endtime);
395 return tevent_req_post(req, ev);
402 static void wrepl_request_writev_done(struct tevent_req *subreq);
404 static void wrepl_request_trigger(struct tevent_req *req,
407 struct wrepl_request_state *state = tevent_req_data(req,
408 struct wrepl_request_state);
409 struct tevent_req *subreq;
411 if (state->caller.wrepl_socket->stream == NULL) {
412 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
417 DEBUG(10,("Sending WINS packet of length %u\n",
418 (unsigned)state->req.blob.length));
419 NDR_PRINT_DEBUG(wrepl_packet, &state->req.wrap.packet);
422 subreq = tstream_writev_send(state,
424 state->caller.wrepl_socket->stream,
426 if (tevent_req_nomem(subreq, req)) {
429 tevent_req_set_callback(subreq, wrepl_request_writev_done, req);
432 static void wrepl_request_disconnect_done(struct tevent_req *subreq);
433 static void wrepl_request_read_pdu_done(struct tevent_req *subreq);
435 static void wrepl_request_writev_done(struct tevent_req *subreq)
437 struct tevent_req *req = tevent_req_callback_data(subreq,
439 struct wrepl_request_state *state = tevent_req_data(req,
440 struct wrepl_request_state);
444 ret = tstream_writev_recv(subreq, &sys_errno);
447 NTSTATUS status = map_nt_error_from_unix_common(sys_errno);
448 TALLOC_FREE(state->caller.wrepl_socket->stream);
449 tevent_req_nterror(req, status);
453 if (state->caller.wrepl_socket->stream == NULL) {
454 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
458 if (state->ctrl.disconnect_after_send) {
459 subreq = tstream_disconnect_send(state,
461 state->caller.wrepl_socket->stream);
462 if (tevent_req_nomem(subreq, req)) {
465 tevent_req_set_callback(subreq, wrepl_request_disconnect_done, req);
469 if (state->ctrl.send_only) {
470 tevent_req_done(req);
474 subreq = tstream_read_pdu_blob_send(state,
476 state->caller.wrepl_socket->stream,
477 4, /* initial_read_size */
478 packet_full_request_u32,
480 if (tevent_req_nomem(subreq, req)) {
483 tevent_req_set_callback(subreq, wrepl_request_read_pdu_done, req);
486 static void wrepl_request_disconnect_done(struct tevent_req *subreq)
488 struct tevent_req *req = tevent_req_callback_data(subreq,
490 struct wrepl_request_state *state = tevent_req_data(req,
491 struct wrepl_request_state);
495 ret = tstream_disconnect_recv(subreq, &sys_errno);
498 NTSTATUS status = map_nt_error_from_unix_common(sys_errno);
499 TALLOC_FREE(state->caller.wrepl_socket->stream);
500 tevent_req_nterror(req, status);
504 DEBUG(10,("WINS connection disconnected\n"));
505 TALLOC_FREE(state->caller.wrepl_socket->stream);
507 tevent_req_done(req);
510 static void wrepl_request_read_pdu_done(struct tevent_req *subreq)
512 struct tevent_req *req = tevent_req_callback_data(subreq,
514 struct wrepl_request_state *state = tevent_req_data(req,
515 struct wrepl_request_state);
518 enum ndr_err_code ndr_err;
520 status = tstream_read_pdu_blob_recv(subreq, state, &state->rep.blob);
521 if (!NT_STATUS_IS_OK(status)) {
522 TALLOC_FREE(state->caller.wrepl_socket->stream);
523 tevent_req_nterror(req, status);
527 state->rep.packet = talloc(state, struct wrepl_packet);
528 if (tevent_req_nomem(state->rep.packet, req)) {
532 blob.data = state->rep.blob.data + 4;
533 blob.length = state->rep.blob.length - 4;
535 /* we have a full request - parse it */
536 ndr_err = ndr_pull_struct_blob(&blob,
539 (ndr_pull_flags_fn_t)ndr_pull_wrepl_packet);
540 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
541 status = ndr_map_error2ntstatus(ndr_err);
542 tevent_req_nterror(req, status);
547 DEBUG(10,("Received WINS packet of length %u\n",
548 (unsigned)state->rep.blob.length));
549 NDR_PRINT_DEBUG(wrepl_packet, state->rep.packet);
552 tevent_req_done(req);
555 NTSTATUS wrepl_request_recv(struct tevent_req *req,
557 struct wrepl_packet **packet)
559 struct wrepl_request_state *state = tevent_req_data(req,
560 struct wrepl_request_state);
563 if (tevent_req_is_nterror(req, &status)) {
564 TALLOC_FREE(state->caller.wrepl_socket->stream);
565 tevent_req_received(req);
570 *packet = talloc_move(mem_ctx, &state->rep.packet);
573 tevent_req_received(req);
578 a full WINS replication request/response
580 NTSTATUS wrepl_request(struct wrepl_socket *wrepl_socket,
582 const struct wrepl_packet *req_packet,
583 struct wrepl_packet **reply_packet)
585 struct tevent_req *subreq;
589 subreq = wrepl_request_send(mem_ctx, wrepl_socket->event.ctx,
590 wrepl_socket, req_packet, NULL);
591 NT_STATUS_HAVE_NO_MEMORY(subreq);
593 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
596 return NT_STATUS_INTERNAL_ERROR;
599 status = wrepl_request_recv(subreq, mem_ctx, reply_packet);
601 NT_STATUS_NOT_OK_RETURN(status);
607 struct wrepl_associate_state {
608 struct wrepl_packet packet;
610 uint16_t major_version;
613 static void wrepl_associate_done(struct tevent_req *subreq);
615 struct tevent_req *wrepl_associate_send(TALLOC_CTX *mem_ctx,
616 struct tevent_context *ev,
617 struct wrepl_socket *wrepl_socket,
618 const struct wrepl_associate *io)
620 struct tevent_req *req;
621 struct wrepl_associate_state *state;
622 struct tevent_req *subreq;
624 if (wrepl_socket->event.ctx != ev) {
625 /* TODO: remove wrepl_socket->event.ctx !!! */
626 smb_panic("wrepl_associate_send event context mismatch!");
630 req = tevent_req_create(mem_ctx, &state,
631 struct wrepl_associate_state);
636 state->packet.opcode = WREPL_OPCODE_BITS;
637 state->packet.mess_type = WREPL_START_ASSOCIATION;
638 state->packet.message.start.minor_version = 2;
639 state->packet.message.start.major_version = 5;
642 * nt4 uses 41 bytes for the start_association call
643 * so do it the same and as we don't know th emeanings of this bytes
644 * we just send zeros and nt4, w2k and w2k3 seems to be happy with this
646 * if we don't do this nt4 uses an old version of the wins replication protocol
647 * and that would break nt4 <-> samba replication
649 state->packet.padding = data_blob_talloc(state, NULL, 21);
650 if (tevent_req_nomem(state->packet.padding.data, req)) {
651 return tevent_req_post(req, ev);
653 memset(state->packet.padding.data, 0, state->packet.padding.length);
655 subreq = wrepl_request_send(state, ev, wrepl_socket, &state->packet, NULL);
656 if (tevent_req_nomem(subreq, req)) {
657 return tevent_req_post(req, ev);
659 tevent_req_set_callback(subreq, wrepl_associate_done, req);
664 static void wrepl_associate_done(struct tevent_req *subreq)
666 struct tevent_req *req = tevent_req_callback_data(subreq,
668 struct wrepl_associate_state *state = tevent_req_data(req,
669 struct wrepl_associate_state);
671 struct wrepl_packet *packet;
673 status = wrepl_request_recv(subreq, state, &packet);
675 if (!NT_STATUS_IS_OK(status)) {
676 tevent_req_nterror(req, status);
680 if (packet->mess_type != WREPL_START_ASSOCIATION_REPLY) {
681 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
685 state->assoc_ctx = packet->message.start_reply.assoc_ctx;
686 state->major_version = packet->message.start_reply.major_version;
688 tevent_req_done(req);
692 setup an association - recv
694 NTSTATUS wrepl_associate_recv(struct tevent_req *req,
695 struct wrepl_associate *io)
697 struct wrepl_associate_state *state = tevent_req_data(req,
698 struct wrepl_associate_state);
701 if (tevent_req_is_nterror(req, &status)) {
702 tevent_req_received(req);
706 io->out.assoc_ctx = state->assoc_ctx;
707 io->out.major_version = state->major_version;
709 tevent_req_received(req);
714 setup an association - sync api
716 NTSTATUS wrepl_associate(struct wrepl_socket *wrepl_socket,
717 struct wrepl_associate *io)
719 struct tevent_req *subreq;
723 subreq = wrepl_associate_send(wrepl_socket, wrepl_socket->event.ctx,
725 NT_STATUS_HAVE_NO_MEMORY(subreq);
727 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
730 return NT_STATUS_INTERNAL_ERROR;
733 status = wrepl_associate_recv(subreq, io);
735 NT_STATUS_NOT_OK_RETURN(status);
740 struct wrepl_associate_stop_state {
741 struct wrepl_packet packet;
742 struct wrepl_send_ctrl ctrl;
745 static void wrepl_associate_stop_done(struct tevent_req *subreq);
747 struct tevent_req *wrepl_associate_stop_send(TALLOC_CTX *mem_ctx,
748 struct tevent_context *ev,
749 struct wrepl_socket *wrepl_socket,
750 const struct wrepl_associate_stop *io)
752 struct tevent_req *req;
753 struct wrepl_associate_stop_state *state;
754 struct tevent_req *subreq;
756 if (wrepl_socket->event.ctx != ev) {
757 /* TODO: remove wrepl_socket->event.ctx !!! */
758 smb_panic("wrepl_associate_stop_send event context mismatch!");
762 req = tevent_req_create(mem_ctx, &state,
763 struct wrepl_associate_stop_state);
768 state->packet.opcode = WREPL_OPCODE_BITS;
769 state->packet.assoc_ctx = io->in.assoc_ctx;
770 state->packet.mess_type = WREPL_STOP_ASSOCIATION;
771 state->packet.message.stop.reason = io->in.reason;
773 if (io->in.reason == 0) {
774 state->ctrl.send_only = true;
775 state->ctrl.disconnect_after_send = true;
778 subreq = wrepl_request_send(state, ev, wrepl_socket, &state->packet, &state->ctrl);
779 if (tevent_req_nomem(subreq, req)) {
780 return tevent_req_post(req, ev);
782 tevent_req_set_callback(subreq, wrepl_associate_stop_done, req);
787 static void wrepl_associate_stop_done(struct tevent_req *subreq)
789 struct tevent_req *req = tevent_req_callback_data(subreq,
791 struct wrepl_associate_stop_state *state = tevent_req_data(req,
792 struct wrepl_associate_stop_state);
795 /* currently we don't care about a possible response */
796 status = wrepl_request_recv(subreq, state, NULL);
798 if (!NT_STATUS_IS_OK(status)) {
799 tevent_req_nterror(req, status);
803 tevent_req_done(req);
807 stop an association - recv
809 NTSTATUS wrepl_associate_stop_recv(struct tevent_req *req,
810 struct wrepl_associate_stop *io)
814 if (tevent_req_is_nterror(req, &status)) {
815 tevent_req_received(req);
819 tevent_req_received(req);
824 setup an association - sync api
826 NTSTATUS wrepl_associate_stop(struct wrepl_socket *wrepl_socket,
827 struct wrepl_associate_stop *io)
829 struct tevent_req *subreq;
833 subreq = wrepl_associate_stop_send(wrepl_socket, wrepl_socket->event.ctx,
835 NT_STATUS_HAVE_NO_MEMORY(subreq);
837 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
840 return NT_STATUS_INTERNAL_ERROR;
843 status = wrepl_associate_stop_recv(subreq, io);
845 NT_STATUS_NOT_OK_RETURN(status);
850 struct wrepl_pull_table_state {
851 struct wrepl_packet packet;
852 uint32_t num_partners;
853 struct wrepl_wins_owner *partners;
856 static void wrepl_pull_table_done(struct tevent_req *subreq);
858 struct tevent_req *wrepl_pull_table_send(TALLOC_CTX *mem_ctx,
859 struct tevent_context *ev,
860 struct wrepl_socket *wrepl_socket,
861 const struct wrepl_pull_table *io)
863 struct tevent_req *req;
864 struct wrepl_pull_table_state *state;
865 struct tevent_req *subreq;
867 if (wrepl_socket->event.ctx != ev) {
868 /* TODO: remove wrepl_socket->event.ctx !!! */
869 smb_panic("wrepl_pull_table_send event context mismatch!");
873 req = tevent_req_create(mem_ctx, &state,
874 struct wrepl_pull_table_state);
879 state->packet.opcode = WREPL_OPCODE_BITS;
880 state->packet.assoc_ctx = io->in.assoc_ctx;
881 state->packet.mess_type = WREPL_REPLICATION;
882 state->packet.message.replication.command = WREPL_REPL_TABLE_QUERY;
884 subreq = wrepl_request_send(state, ev, wrepl_socket, &state->packet, NULL);
885 if (tevent_req_nomem(subreq, req)) {
886 return tevent_req_post(req, ev);
888 tevent_req_set_callback(subreq, wrepl_pull_table_done, req);
893 static void wrepl_pull_table_done(struct tevent_req *subreq)
895 struct tevent_req *req = tevent_req_callback_data(subreq,
897 struct wrepl_pull_table_state *state = tevent_req_data(req,
898 struct wrepl_pull_table_state);
900 struct wrepl_packet *packet;
901 struct wrepl_table *table;
903 status = wrepl_request_recv(subreq, state, &packet);
905 if (!NT_STATUS_IS_OK(status)) {
906 tevent_req_nterror(req, status);
910 if (packet->mess_type != WREPL_REPLICATION) {
911 tevent_req_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
915 if (packet->message.replication.command != WREPL_REPL_TABLE_REPLY) {
916 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
920 table = &packet->message.replication.info.table;
922 state->num_partners = table->partner_count;
923 state->partners = talloc_move(state, &table->partners);
925 tevent_req_done(req);
929 fetch the partner tables - recv
931 NTSTATUS wrepl_pull_table_recv(struct tevent_req *req,
933 struct wrepl_pull_table *io)
935 struct wrepl_pull_table_state *state = tevent_req_data(req,
936 struct wrepl_pull_table_state);
939 if (tevent_req_is_nterror(req, &status)) {
940 tevent_req_received(req);
944 io->out.num_partners = state->num_partners;
945 io->out.partners = talloc_move(mem_ctx, &state->partners);
947 tevent_req_received(req);
952 fetch the partner table - sync api
954 NTSTATUS wrepl_pull_table(struct wrepl_socket *wrepl_socket,
956 struct wrepl_pull_table *io)
958 struct tevent_req *subreq;
962 subreq = wrepl_pull_table_send(mem_ctx, wrepl_socket->event.ctx,
964 NT_STATUS_HAVE_NO_MEMORY(subreq);
966 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
969 return NT_STATUS_INTERNAL_ERROR;
972 status = wrepl_pull_table_recv(subreq, mem_ctx, io);
974 NT_STATUS_NOT_OK_RETURN(status);
980 struct wrepl_pull_names_state {
982 const struct wrepl_pull_names *io;
984 struct wrepl_packet packet;
986 struct wrepl_name *names;
989 static void wrepl_pull_names_done(struct tevent_req *subreq);
991 struct tevent_req *wrepl_pull_names_send(TALLOC_CTX *mem_ctx,
992 struct tevent_context *ev,
993 struct wrepl_socket *wrepl_socket,
994 const struct wrepl_pull_names *io)
996 struct tevent_req *req;
997 struct wrepl_pull_names_state *state;
998 struct tevent_req *subreq;
1000 if (wrepl_socket->event.ctx != ev) {
1001 /* TODO: remove wrepl_socket->event.ctx !!! */
1002 smb_panic("wrepl_pull_names_send event context mismatch!");
1006 req = tevent_req_create(mem_ctx, &state,
1007 struct wrepl_pull_names_state);
1011 state->caller.io = io;
1013 state->packet.opcode = WREPL_OPCODE_BITS;
1014 state->packet.assoc_ctx = io->in.assoc_ctx;
1015 state->packet.mess_type = WREPL_REPLICATION;
1016 state->packet.message.replication.command = WREPL_REPL_SEND_REQUEST;
1017 state->packet.message.replication.info.owner = io->in.partner;
1019 subreq = wrepl_request_send(state, ev, wrepl_socket, &state->packet, NULL);
1020 if (tevent_req_nomem(subreq, req)) {
1021 return tevent_req_post(req, ev);
1023 tevent_req_set_callback(subreq, wrepl_pull_names_done, req);
1028 static void wrepl_pull_names_done(struct tevent_req *subreq)
1030 struct tevent_req *req = tevent_req_callback_data(subreq,
1032 struct wrepl_pull_names_state *state = tevent_req_data(req,
1033 struct wrepl_pull_names_state);
1035 struct wrepl_packet *packet;
1038 status = wrepl_request_recv(subreq, state, &packet);
1039 TALLOC_FREE(subreq);
1040 if (!NT_STATUS_IS_OK(status)) {
1041 tevent_req_nterror(req, status);
1045 if (packet->mess_type != WREPL_REPLICATION) {
1046 tevent_req_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
1050 if (packet->message.replication.command != WREPL_REPL_SEND_REPLY) {
1051 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1055 state->num_names = packet->message.replication.info.reply.num_names;
1057 state->names = talloc_array(state, struct wrepl_name, state->num_names);
1058 if (tevent_req_nomem(state->names, req)) {
1062 /* convert the list of names and addresses to a sane format */
1063 for (i=0; i < state->num_names; i++) {
1064 struct wrepl_wins_name *wname = &packet->message.replication.info.reply.names[i];
1065 struct wrepl_name *name = &state->names[i];
1067 name->name = *wname->name;
1068 talloc_steal(state->names, wname->name);
1069 name->type = WREPL_NAME_TYPE(wname->flags);
1070 name->state = WREPL_NAME_STATE(wname->flags);
1071 name->node = WREPL_NAME_NODE(wname->flags);
1072 name->is_static = WREPL_NAME_IS_STATIC(wname->flags);
1073 name->raw_flags = wname->flags;
1074 name->version_id= wname->id;
1075 name->owner = talloc_strdup(state->names,
1076 state->caller.io->in.partner.address);
1077 if (tevent_req_nomem(name->owner, req)) {
1081 /* trying to save 1 or 2 bytes on the wire isn't a good idea */
1082 if (wname->flags & 2) {
1085 name->num_addresses = wname->addresses.addresses.num_ips;
1086 name->addresses = talloc_array(state->names,
1087 struct wrepl_address,
1088 name->num_addresses);
1089 if (tevent_req_nomem(name->addresses, req)) {
1093 for (j=0;j<name->num_addresses;j++) {
1094 name->addresses[j].owner =
1095 talloc_move(name->addresses,
1096 &wname->addresses.addresses.ips[j].owner);
1097 name->addresses[j].address =
1098 talloc_move(name->addresses,
1099 &wname->addresses.addresses.ips[j].ip);
1102 name->num_addresses = 1;
1103 name->addresses = talloc_array(state->names,
1104 struct wrepl_address,
1105 name->num_addresses);
1106 if (tevent_req_nomem(name->addresses, req)) {
1110 name->addresses[0].owner = talloc_strdup(name->addresses, name->owner);
1111 if (tevent_req_nomem(name->addresses[0].owner, req)) {
1114 name->addresses[0].address = talloc_move(name->addresses,
1115 &wname->addresses.ip);
1119 tevent_req_done(req);
1123 fetch the names for a WINS partner - recv
1125 NTSTATUS wrepl_pull_names_recv(struct tevent_req *req,
1126 TALLOC_CTX *mem_ctx,
1127 struct wrepl_pull_names *io)
1129 struct wrepl_pull_names_state *state = tevent_req_data(req,
1130 struct wrepl_pull_names_state);
1133 if (tevent_req_is_nterror(req, &status)) {
1134 tevent_req_received(req);
1138 io->out.num_names = state->num_names;
1139 io->out.names = talloc_move(mem_ctx, &state->names);
1141 tevent_req_received(req);
1142 return NT_STATUS_OK;
1148 fetch the names for a WINS partner - sync api
1150 NTSTATUS wrepl_pull_names(struct wrepl_socket *wrepl_socket,
1151 TALLOC_CTX *mem_ctx,
1152 struct wrepl_pull_names *io)
1154 struct tevent_req *subreq;
1158 subreq = wrepl_pull_names_send(mem_ctx, wrepl_socket->event.ctx,
1160 NT_STATUS_HAVE_NO_MEMORY(subreq);
1162 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
1164 TALLOC_FREE(subreq);
1165 return NT_STATUS_INTERNAL_ERROR;
1168 status = wrepl_pull_names_recv(subreq, mem_ctx, io);
1169 TALLOC_FREE(subreq);
1170 NT_STATUS_NOT_OK_RETURN(status);
1172 return NT_STATUS_OK;