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 smb_iconv_convenience *iconv_convenience;
50 struct tevent_queue *request_queue;
52 struct tstream_context *stream;
55 bool wrepl_socket_is_connected(struct wrepl_socket *wrepl_sock)
61 if (!wrepl_sock->stream) {
69 initialise a wrepl_socket. The event_ctx is optional, if provided then
70 operations will use that event context
72 struct wrepl_socket *wrepl_socket_init(TALLOC_CTX *mem_ctx,
73 struct tevent_context *event_ctx,
74 struct smb_iconv_convenience *iconv_convenience)
76 struct wrepl_socket *wrepl_socket;
78 wrepl_socket = talloc_zero(mem_ctx, struct wrepl_socket);
83 wrepl_socket->event.ctx = event_ctx;
84 if (!wrepl_socket->event.ctx) {
88 wrepl_socket->request_queue = tevent_queue_create(wrepl_socket,
89 "wrepl request queue");
90 if (wrepl_socket->request_queue == NULL) {
94 wrepl_socket->iconv_convenience = iconv_convenience;
96 wrepl_socket->request_timeout = WREPL_SOCKET_REQUEST_TIMEOUT;
101 talloc_free(wrepl_socket);
106 initialise a wrepl_socket from an already existing connection
108 NTSTATUS wrepl_socket_donate_stream(struct wrepl_socket *wrepl_socket,
109 struct tstream_context **stream)
111 if (wrepl_socket->stream) {
112 return NT_STATUS_CONNECTION_ACTIVE;
115 wrepl_socket->stream = talloc_move(wrepl_socket, stream);
120 initialise a wrepl_socket from an already existing connection
122 NTSTATUS wrepl_socket_split_stream(struct wrepl_socket *wrepl_socket,
124 struct tstream_context **stream)
128 if (!wrepl_socket->stream) {
129 return NT_STATUS_CONNECTION_INVALID;
132 num_requests = tevent_queue_length(wrepl_socket->request_queue);
133 if (num_requests > 0) {
134 return NT_STATUS_CONNECTION_IN_USE;
137 *stream = talloc_move(wrepl_socket, &wrepl_socket->stream);
141 const char *wrepl_best_ip(struct loadparm_context *lp_ctx, const char *peer_ip)
143 struct interface *ifaces;
144 load_interfaces(lp_ctx, lp_interfaces(lp_ctx), &ifaces);
145 return iface_best_ip(ifaces, peer_ip);
148 struct wrepl_connect_state {
150 struct wrepl_socket *wrepl_socket;
151 struct tevent_context *ev;
153 struct tsocket_address *local_address;
154 struct tsocket_address *remote_address;
155 struct tstream_context *stream;
158 static void wrepl_connect_trigger(struct tevent_req *req,
161 struct tevent_req *wrepl_connect_send(TALLOC_CTX *mem_ctx,
162 struct tevent_context *ev,
163 struct wrepl_socket *wrepl_socket,
164 const char *our_ip, const char *peer_ip)
166 struct tevent_req *req;
167 struct wrepl_connect_state *state;
171 req = tevent_req_create(mem_ctx, &state,
172 struct wrepl_connect_state);
177 state->caller.wrepl_socket = wrepl_socket;
178 state->caller.ev = ev;
180 if (wrepl_socket->stream) {
181 tevent_req_nterror(req, NT_STATUS_CONNECTION_ACTIVE);
182 return tevent_req_post(req, ev);
185 ret = tsocket_address_inet_from_strings(state, "ipv4",
187 &state->local_address);
189 NTSTATUS status = map_nt_error_from_unix(errno);
190 tevent_req_nterror(req, status);
191 return tevent_req_post(req, ev);
194 ret = tsocket_address_inet_from_strings(state, "ipv4",
195 peer_ip, WINS_REPLICATION_PORT,
196 &state->remote_address);
198 NTSTATUS status = map_nt_error_from_unix(errno);
199 tevent_req_nterror(req, status);
200 return tevent_req_post(req, ev);
203 ok = tevent_queue_add(wrepl_socket->request_queue,
206 wrepl_connect_trigger,
209 tevent_req_nomem(NULL, req);
210 return tevent_req_post(req, ev);
213 if (wrepl_socket->request_timeout > 0) {
214 struct timeval endtime;
215 endtime = tevent_timeval_current_ofs(wrepl_socket->request_timeout, 0);
216 ok = tevent_req_set_endtime(req, ev, endtime);
218 return tevent_req_post(req, ev);
225 static void wrepl_connect_done(struct tevent_req *subreq);
227 static void wrepl_connect_trigger(struct tevent_req *req,
230 struct wrepl_connect_state *state = tevent_req_data(req,
231 struct wrepl_connect_state);
232 struct tevent_req *subreq;
234 subreq = tstream_inet_tcp_connect_send(state,
236 state->local_address,
237 state->remote_address);
238 if (tevent_req_nomem(subreq, req)) {
241 tevent_req_set_callback(subreq, wrepl_connect_done, req);
246 static void wrepl_connect_done(struct tevent_req *subreq)
248 struct tevent_req *req = tevent_req_callback_data(subreq,
250 struct wrepl_connect_state *state = tevent_req_data(req,
251 struct wrepl_connect_state);
255 ret = tstream_inet_tcp_connect_recv(subreq, &sys_errno,
256 state, &state->stream);
258 NTSTATUS status = map_nt_error_from_unix(sys_errno);
259 tevent_req_nterror(req, status);
263 tevent_req_done(req);
267 connect a wrepl_socket to a WINS server - recv side
269 NTSTATUS wrepl_connect_recv(struct tevent_req *req)
271 struct wrepl_connect_state *state = tevent_req_data(req,
272 struct wrepl_connect_state);
273 struct wrepl_socket *wrepl_socket = state->caller.wrepl_socket;
276 if (tevent_req_is_nterror(req, &status)) {
277 tevent_req_received(req);
281 wrepl_socket->stream = talloc_move(wrepl_socket, &state->stream);
283 tevent_req_received(req);
288 connect a wrepl_socket to a WINS server - sync API
290 NTSTATUS wrepl_connect(struct wrepl_socket *wrepl_socket,
291 const char *our_ip, const char *peer_ip)
293 struct tevent_req *subreq;
297 subreq = wrepl_connect_send(wrepl_socket, wrepl_socket->event.ctx,
298 wrepl_socket, our_ip, peer_ip);
299 NT_STATUS_HAVE_NO_MEMORY(subreq);
301 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
304 return NT_STATUS_INTERNAL_ERROR;
307 status = wrepl_connect_recv(subreq);
309 NT_STATUS_NOT_OK_RETURN(status);
314 struct wrepl_request_state {
316 struct wrepl_socket *wrepl_socket;
317 struct tevent_context *ev;
319 struct wrepl_send_ctrl ctrl;
321 struct wrepl_wrap wrap;
328 struct wrepl_packet *packet;
332 static void wrepl_request_trigger(struct tevent_req *req,
335 struct tevent_req *wrepl_request_send(TALLOC_CTX *mem_ctx,
336 struct tevent_context *ev,
337 struct wrepl_socket *wrepl_socket,
338 const struct wrepl_packet *packet,
339 const struct wrepl_send_ctrl *ctrl)
341 struct tevent_req *req;
342 struct wrepl_request_state *state;
344 enum ndr_err_code ndr_err;
347 if (wrepl_socket->event.ctx != ev) {
348 /* TODO: remove wrepl_socket->event.ctx !!! */
349 smb_panic("wrepl_associate_stop_send event context mismatch!");
353 req = tevent_req_create(mem_ctx, &state,
354 struct wrepl_request_state);
359 state->caller.wrepl_socket = wrepl_socket;
360 state->caller.ev = ev;
366 if (wrepl_socket->stream == NULL) {
367 tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
368 return tevent_req_post(req, ev);
371 state->req.wrap.packet = *packet;
372 ndr_err = ndr_push_struct_blob(&state->req.blob, state,
373 wrepl_socket->iconv_convenience,
375 (ndr_push_flags_fn_t)ndr_push_wrepl_wrap);
376 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
377 status = ndr_map_error2ntstatus(ndr_err);
378 tevent_req_nterror(req, status);
379 return tevent_req_post(req, ev);
382 state->req.iov.iov_base = state->req.blob.data;
383 state->req.iov.iov_len = state->req.blob.length;
385 ok = tevent_queue_add(wrepl_socket->request_queue,
388 wrepl_request_trigger,
391 tevent_req_nomem(NULL, req);
392 return tevent_req_post(req, ev);
395 if (wrepl_socket->request_timeout > 0) {
396 struct timeval endtime;
397 endtime = tevent_timeval_current_ofs(wrepl_socket->request_timeout, 0);
398 ok = tevent_req_set_endtime(req, ev, endtime);
400 return tevent_req_post(req, ev);
407 static void wrepl_request_writev_done(struct tevent_req *subreq);
409 static void wrepl_request_trigger(struct tevent_req *req,
412 struct wrepl_request_state *state = tevent_req_data(req,
413 struct wrepl_request_state);
414 struct tevent_req *subreq;
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(sys_errno);
448 tevent_req_nterror(req, status);
452 if (state->ctrl.disconnect_after_send) {
453 subreq = tstream_disconnect_send(state,
455 state->caller.wrepl_socket->stream);
456 if (tevent_req_nomem(subreq, req)) {
459 tevent_req_set_callback(subreq, wrepl_request_disconnect_done, req);
463 if (state->ctrl.send_only) {
464 tevent_req_done(req);
468 subreq = tstream_read_pdu_blob_send(state,
470 state->caller.wrepl_socket->stream,
471 4, /* initial_read_size */
472 packet_full_request_u32,
474 if (tevent_req_nomem(subreq, req)) {
477 tevent_req_set_callback(subreq, wrepl_request_read_pdu_done, req);
480 static void wrepl_request_disconnect_done(struct tevent_req *subreq)
482 struct tevent_req *req = tevent_req_callback_data(subreq,
484 struct wrepl_request_state *state = tevent_req_data(req,
485 struct wrepl_request_state);
489 ret = tstream_disconnect_recv(subreq, &sys_errno);
492 NTSTATUS status = map_nt_error_from_unix(sys_errno);
493 tevent_req_nterror(req, status);
497 DEBUG(10,("WINS connection disconnected\n"));
498 state->caller.wrepl_socket->stream = NULL;
500 tevent_req_done(req);
503 static void wrepl_request_read_pdu_done(struct tevent_req *subreq)
505 struct tevent_req *req = tevent_req_callback_data(subreq,
507 struct wrepl_request_state *state = tevent_req_data(req,
508 struct wrepl_request_state);
511 enum ndr_err_code ndr_err;
513 status = tstream_read_pdu_blob_recv(subreq, state, &state->rep.blob);
514 if (!NT_STATUS_IS_OK(status)) {
515 tevent_req_nterror(req, status);
519 state->rep.packet = talloc(state, struct wrepl_packet);
520 if (tevent_req_nomem(state->rep.packet, req)) {
524 blob.data = state->rep.blob.data + 4;
525 blob.length = state->rep.blob.length - 4;
527 /* we have a full request - parse it */
528 ndr_err = ndr_pull_struct_blob(&blob,
530 state->caller.wrepl_socket->iconv_convenience,
532 (ndr_pull_flags_fn_t)ndr_pull_wrepl_packet);
533 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
534 status = ndr_map_error2ntstatus(ndr_err);
535 tevent_req_nterror(req, status);
540 DEBUG(10,("Received WINS packet of length %u\n",
541 (unsigned)state->rep.blob.length));
542 NDR_PRINT_DEBUG(wrepl_packet, state->rep.packet);
545 tevent_req_done(req);
548 NTSTATUS wrepl_request_recv(struct tevent_req *req,
550 struct wrepl_packet **packet)
552 struct wrepl_request_state *state = tevent_req_data(req,
553 struct wrepl_request_state);
556 if (tevent_req_is_nterror(req, &status)) {
557 tevent_req_received(req);
562 *packet = talloc_move(mem_ctx, &state->rep.packet);
565 tevent_req_received(req);
570 a full WINS replication request/response
572 NTSTATUS wrepl_request(struct wrepl_socket *wrepl_socket,
574 const struct wrepl_packet *req_packet,
575 struct wrepl_packet **reply_packet)
577 struct tevent_req *subreq;
581 subreq = wrepl_request_send(mem_ctx, wrepl_socket->event.ctx,
582 wrepl_socket, req_packet, NULL);
583 NT_STATUS_HAVE_NO_MEMORY(subreq);
585 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
588 return NT_STATUS_INTERNAL_ERROR;
591 status = wrepl_request_recv(subreq, mem_ctx, reply_packet);
593 NT_STATUS_NOT_OK_RETURN(status);
599 struct wrepl_associate_state {
600 struct wrepl_packet packet;
602 uint16_t major_version;
605 static void wrepl_associate_done(struct tevent_req *subreq);
607 struct tevent_req *wrepl_associate_send(TALLOC_CTX *mem_ctx,
608 struct tevent_context *ev,
609 struct wrepl_socket *wrepl_socket,
610 const struct wrepl_associate *io)
612 struct tevent_req *req;
613 struct wrepl_associate_state *state;
614 struct tevent_req *subreq;
616 if (wrepl_socket->event.ctx != ev) {
617 /* TODO: remove wrepl_socket->event.ctx !!! */
618 smb_panic("wrepl_associate_send event context mismatch!");
622 req = tevent_req_create(mem_ctx, &state,
623 struct wrepl_associate_state);
628 state->packet.opcode = WREPL_OPCODE_BITS;
629 state->packet.mess_type = WREPL_START_ASSOCIATION;
630 state->packet.message.start.minor_version = 2;
631 state->packet.message.start.major_version = 5;
634 * nt4 uses 41 bytes for the start_association call
635 * so do it the same and as we don't know th emeanings of this bytes
636 * we just send zeros and nt4, w2k and w2k3 seems to be happy with this
638 * if we don't do this nt4 uses an old version of the wins replication protocol
639 * and that would break nt4 <-> samba replication
641 state->packet.padding = data_blob_talloc(state, NULL, 21);
642 if (tevent_req_nomem(state->packet.padding.data, req)) {
643 return tevent_req_post(req, ev);
645 memset(state->packet.padding.data, 0, state->packet.padding.length);
647 subreq = wrepl_request_send(state, ev, wrepl_socket, &state->packet, NULL);
648 if (tevent_req_nomem(subreq, req)) {
649 return tevent_req_post(req, ev);
651 tevent_req_set_callback(subreq, wrepl_associate_done, req);
656 static void wrepl_associate_done(struct tevent_req *subreq)
658 struct tevent_req *req = tevent_req_callback_data(subreq,
660 struct wrepl_associate_state *state = tevent_req_data(req,
661 struct wrepl_associate_state);
663 struct wrepl_packet *packet;
665 status = wrepl_request_recv(subreq, state, &packet);
667 if (!NT_STATUS_IS_OK(status)) {
668 tevent_req_nterror(req, status);
672 if (packet->mess_type != WREPL_START_ASSOCIATION_REPLY) {
673 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
677 state->assoc_ctx = packet->message.start_reply.assoc_ctx;
678 state->major_version = packet->message.start_reply.major_version;
680 tevent_req_done(req);
684 setup an association - recv
686 NTSTATUS wrepl_associate_recv(struct tevent_req *req,
687 struct wrepl_associate *io)
689 struct wrepl_associate_state *state = tevent_req_data(req,
690 struct wrepl_associate_state);
693 if (tevent_req_is_nterror(req, &status)) {
694 tevent_req_received(req);
698 io->out.assoc_ctx = state->assoc_ctx;
699 io->out.major_version = state->major_version;
701 tevent_req_received(req);
706 setup an association - sync api
708 NTSTATUS wrepl_associate(struct wrepl_socket *wrepl_socket,
709 struct wrepl_associate *io)
711 struct tevent_req *subreq;
715 subreq = wrepl_associate_send(wrepl_socket, wrepl_socket->event.ctx,
717 NT_STATUS_HAVE_NO_MEMORY(subreq);
719 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
722 return NT_STATUS_INTERNAL_ERROR;
725 status = wrepl_associate_recv(subreq, io);
727 NT_STATUS_NOT_OK_RETURN(status);
732 struct wrepl_associate_stop_state {
733 struct wrepl_packet packet;
734 struct wrepl_send_ctrl ctrl;
737 static void wrepl_associate_stop_done(struct tevent_req *subreq);
739 struct tevent_req *wrepl_associate_stop_send(TALLOC_CTX *mem_ctx,
740 struct tevent_context *ev,
741 struct wrepl_socket *wrepl_socket,
742 const struct wrepl_associate_stop *io)
744 struct tevent_req *req;
745 struct wrepl_associate_stop_state *state;
746 struct tevent_req *subreq;
748 if (wrepl_socket->event.ctx != ev) {
749 /* TODO: remove wrepl_socket->event.ctx !!! */
750 smb_panic("wrepl_associate_stop_send event context mismatch!");
754 req = tevent_req_create(mem_ctx, &state,
755 struct wrepl_associate_stop_state);
760 state->packet.opcode = WREPL_OPCODE_BITS;
761 state->packet.assoc_ctx = io->in.assoc_ctx;
762 state->packet.mess_type = WREPL_STOP_ASSOCIATION;
763 state->packet.message.stop.reason = io->in.reason;
765 if (io->in.reason == 0) {
766 state->ctrl.send_only = true;
767 state->ctrl.disconnect_after_send = true;
770 subreq = wrepl_request_send(state, ev, wrepl_socket, &state->packet, &state->ctrl);
771 if (tevent_req_nomem(subreq, req)) {
772 return tevent_req_post(req, ev);
774 tevent_req_set_callback(subreq, wrepl_associate_stop_done, req);
779 static void wrepl_associate_stop_done(struct tevent_req *subreq)
781 struct tevent_req *req = tevent_req_callback_data(subreq,
783 struct wrepl_associate_stop_state *state = tevent_req_data(req,
784 struct wrepl_associate_stop_state);
787 /* currently we don't care about a possible response */
788 status = wrepl_request_recv(subreq, state, NULL);
790 if (!NT_STATUS_IS_OK(status)) {
791 tevent_req_nterror(req, status);
795 tevent_req_done(req);
799 stop an association - recv
801 NTSTATUS wrepl_associate_stop_recv(struct tevent_req *req,
802 struct wrepl_associate_stop *io)
806 if (tevent_req_is_nterror(req, &status)) {
807 tevent_req_received(req);
811 tevent_req_received(req);
816 setup an association - sync api
818 NTSTATUS wrepl_associate_stop(struct wrepl_socket *wrepl_socket,
819 struct wrepl_associate_stop *io)
821 struct tevent_req *subreq;
825 subreq = wrepl_associate_stop_send(wrepl_socket, wrepl_socket->event.ctx,
827 NT_STATUS_HAVE_NO_MEMORY(subreq);
829 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
832 return NT_STATUS_INTERNAL_ERROR;
835 status = wrepl_associate_stop_recv(subreq, io);
837 NT_STATUS_NOT_OK_RETURN(status);
842 struct wrepl_pull_table_state {
843 struct wrepl_packet packet;
844 uint32_t num_partners;
845 struct wrepl_wins_owner *partners;
848 static void wrepl_pull_table_done(struct tevent_req *subreq);
850 struct tevent_req *wrepl_pull_table_send(TALLOC_CTX *mem_ctx,
851 struct tevent_context *ev,
852 struct wrepl_socket *wrepl_socket,
853 const struct wrepl_pull_table *io)
855 struct tevent_req *req;
856 struct wrepl_pull_table_state *state;
857 struct tevent_req *subreq;
859 if (wrepl_socket->event.ctx != ev) {
860 /* TODO: remove wrepl_socket->event.ctx !!! */
861 smb_panic("wrepl_pull_table_send event context mismatch!");
865 req = tevent_req_create(mem_ctx, &state,
866 struct wrepl_pull_table_state);
871 state->packet.opcode = WREPL_OPCODE_BITS;
872 state->packet.assoc_ctx = io->in.assoc_ctx;
873 state->packet.mess_type = WREPL_REPLICATION;
874 state->packet.message.replication.command = WREPL_REPL_TABLE_QUERY;
876 subreq = wrepl_request_send(state, ev, wrepl_socket, &state->packet, NULL);
877 if (tevent_req_nomem(subreq, req)) {
878 return tevent_req_post(req, ev);
880 tevent_req_set_callback(subreq, wrepl_pull_table_done, req);
885 static void wrepl_pull_table_done(struct tevent_req *subreq)
887 struct tevent_req *req = tevent_req_callback_data(subreq,
889 struct wrepl_pull_table_state *state = tevent_req_data(req,
890 struct wrepl_pull_table_state);
892 struct wrepl_packet *packet;
893 struct wrepl_table *table;
895 status = wrepl_request_recv(subreq, state, &packet);
897 if (!NT_STATUS_IS_OK(status)) {
898 tevent_req_nterror(req, status);
902 if (packet->mess_type != WREPL_REPLICATION) {
903 tevent_req_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
907 if (packet->message.replication.command != WREPL_REPL_TABLE_REPLY) {
908 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
912 table = &packet->message.replication.info.table;
914 state->num_partners = table->partner_count;
915 state->partners = talloc_move(state, &table->partners);
917 tevent_req_done(req);
921 fetch the partner tables - recv
923 NTSTATUS wrepl_pull_table_recv(struct tevent_req *req,
925 struct wrepl_pull_table *io)
927 struct wrepl_pull_table_state *state = tevent_req_data(req,
928 struct wrepl_pull_table_state);
931 if (tevent_req_is_nterror(req, &status)) {
932 tevent_req_received(req);
936 io->out.num_partners = state->num_partners;
937 io->out.partners = talloc_move(mem_ctx, &state->partners);
939 tevent_req_received(req);
944 fetch the partner table - sync api
946 NTSTATUS wrepl_pull_table(struct wrepl_socket *wrepl_socket,
948 struct wrepl_pull_table *io)
950 struct tevent_req *subreq;
954 subreq = wrepl_pull_table_send(mem_ctx, wrepl_socket->event.ctx,
956 NT_STATUS_HAVE_NO_MEMORY(subreq);
958 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
961 return NT_STATUS_INTERNAL_ERROR;
964 status = wrepl_pull_table_recv(subreq, mem_ctx, io);
966 NT_STATUS_NOT_OK_RETURN(status);
972 struct wrepl_pull_names_state {
974 const struct wrepl_pull_names *io;
976 struct wrepl_packet packet;
978 struct wrepl_name *names;
981 static void wrepl_pull_names_done(struct tevent_req *subreq);
983 struct tevent_req *wrepl_pull_names_send(TALLOC_CTX *mem_ctx,
984 struct tevent_context *ev,
985 struct wrepl_socket *wrepl_socket,
986 const struct wrepl_pull_names *io)
988 struct tevent_req *req;
989 struct wrepl_pull_names_state *state;
990 struct tevent_req *subreq;
992 if (wrepl_socket->event.ctx != ev) {
993 /* TODO: remove wrepl_socket->event.ctx !!! */
994 smb_panic("wrepl_pull_names_send event context mismatch!");
998 req = tevent_req_create(mem_ctx, &state,
999 struct wrepl_pull_names_state);
1003 state->caller.io = io;
1005 state->packet.opcode = WREPL_OPCODE_BITS;
1006 state->packet.assoc_ctx = io->in.assoc_ctx;
1007 state->packet.mess_type = WREPL_REPLICATION;
1008 state->packet.message.replication.command = WREPL_REPL_SEND_REQUEST;
1009 state->packet.message.replication.info.owner = io->in.partner;
1011 subreq = wrepl_request_send(state, ev, wrepl_socket, &state->packet, NULL);
1012 if (tevent_req_nomem(subreq, req)) {
1013 return tevent_req_post(req, ev);
1015 tevent_req_set_callback(subreq, wrepl_pull_names_done, req);
1020 static void wrepl_pull_names_done(struct tevent_req *subreq)
1022 struct tevent_req *req = tevent_req_callback_data(subreq,
1024 struct wrepl_pull_names_state *state = tevent_req_data(req,
1025 struct wrepl_pull_names_state);
1027 struct wrepl_packet *packet;
1030 status = wrepl_request_recv(subreq, state, &packet);
1031 TALLOC_FREE(subreq);
1032 if (!NT_STATUS_IS_OK(status)) {
1033 tevent_req_nterror(req, status);
1037 if (packet->mess_type != WREPL_REPLICATION) {
1038 tevent_req_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
1042 if (packet->message.replication.command != WREPL_REPL_SEND_REPLY) {
1043 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1047 state->num_names = packet->message.replication.info.reply.num_names;
1049 state->names = talloc_array(state, struct wrepl_name, state->num_names);
1050 if (tevent_req_nomem(state->names, req)) {
1054 /* convert the list of names and addresses to a sane format */
1055 for (i=0; i < state->num_names; i++) {
1056 struct wrepl_wins_name *wname = &packet->message.replication.info.reply.names[i];
1057 struct wrepl_name *name = &state->names[i];
1059 name->name = *wname->name;
1060 talloc_steal(state->names, wname->name);
1061 name->type = WREPL_NAME_TYPE(wname->flags);
1062 name->state = WREPL_NAME_STATE(wname->flags);
1063 name->node = WREPL_NAME_NODE(wname->flags);
1064 name->is_static = WREPL_NAME_IS_STATIC(wname->flags);
1065 name->raw_flags = wname->flags;
1066 name->version_id= wname->id;
1067 name->owner = talloc_strdup(state->names,
1068 state->caller.io->in.partner.address);
1069 if (tevent_req_nomem(name->owner, req)) {
1073 /* trying to save 1 or 2 bytes on the wire isn't a good idea */
1074 if (wname->flags & 2) {
1077 name->num_addresses = wname->addresses.addresses.num_ips;
1078 name->addresses = talloc_array(state->names,
1079 struct wrepl_address,
1080 name->num_addresses);
1081 if (tevent_req_nomem(name->addresses, req)) {
1085 for (j=0;j<name->num_addresses;j++) {
1086 name->addresses[j].owner =
1087 talloc_move(name->addresses,
1088 &wname->addresses.addresses.ips[j].owner);
1089 name->addresses[j].address =
1090 talloc_move(name->addresses,
1091 &wname->addresses.addresses.ips[j].ip);
1094 name->num_addresses = 1;
1095 name->addresses = talloc_array(state->names,
1096 struct wrepl_address,
1097 name->num_addresses);
1098 if (tevent_req_nomem(name->addresses, req)) {
1102 name->addresses[0].owner = talloc_strdup(name->addresses, name->owner);
1103 if (tevent_req_nomem(name->addresses[0].owner, req)) {
1106 name->addresses[0].address = talloc_move(name->addresses,
1107 &wname->addresses.ip);
1111 tevent_req_done(req);
1115 fetch the names for a WINS partner - recv
1117 NTSTATUS wrepl_pull_names_recv(struct tevent_req *req,
1118 TALLOC_CTX *mem_ctx,
1119 struct wrepl_pull_names *io)
1121 struct wrepl_pull_names_state *state = tevent_req_data(req,
1122 struct wrepl_pull_names_state);
1125 if (tevent_req_is_nterror(req, &status)) {
1126 tevent_req_received(req);
1130 io->out.num_names = state->num_names;
1131 io->out.names = talloc_move(mem_ctx, &state->names);
1133 tevent_req_received(req);
1134 return NT_STATUS_OK;
1140 fetch the names for a WINS partner - sync api
1142 NTSTATUS wrepl_pull_names(struct wrepl_socket *wrepl_socket,
1143 TALLOC_CTX *mem_ctx,
1144 struct wrepl_pull_names *io)
1146 struct tevent_req *subreq;
1150 subreq = wrepl_pull_names_send(mem_ctx, wrepl_socket->event.ctx,
1152 NT_STATUS_HAVE_NO_MEMORY(subreq);
1154 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
1156 TALLOC_FREE(subreq);
1157 return NT_STATUS_INTERNAL_ERROR;
1160 status = wrepl_pull_names_recv(subreq, mem_ctx, io);
1161 TALLOC_FREE(subreq);
1162 NT_STATUS_NOT_OK_RETURN(status);
1164 return NT_STATUS_OK;