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 "lib/socket/socket.h"
27 #include "libcli/wrepl/winsrepl.h"
28 #include "librpc/gen_ndr/ndr_winsrepl.h"
29 #include "lib/stream/packet.h"
30 #include "libcli/composite/composite.h"
31 #include "system/network.h"
32 #include "lib/socket/netif.h"
33 #include "param/param.h"
34 #include "lib/util/tevent_ntstatus.h"
36 enum wrepl_request_internal_state {
37 WREPL_REQUEST_INIT = 0,
38 WREPL_REQUEST_RECV = 1,
39 WREPL_REQUEST_DONE = 2,
40 WREPL_REQUEST_ERROR = 3
44 a WINS replication request
46 struct wrepl_request {
47 struct wrepl_request *next, *prev;
48 struct wrepl_socket *wrepl_socket;
50 enum wrepl_request_internal_state state;
54 struct tevent_timer *te;
56 struct wrepl_packet *packet;
59 void (*fn)(struct wrepl_request *);
64 static struct wrepl_request *wrepl_request_finished(struct wrepl_request *req, NTSTATUS status);
67 mark all pending requests as dead - called when a socket error happens
69 static void wrepl_socket_dead(struct wrepl_socket *wrepl_socket, NTSTATUS status)
71 wrepl_socket->dead = true;
73 if (wrepl_socket->packet) {
74 packet_recv_disable(wrepl_socket->packet);
75 packet_set_fde(wrepl_socket->packet, NULL);
76 packet_set_socket(wrepl_socket->packet, NULL);
79 if (wrepl_socket->event.fde) {
80 talloc_free(wrepl_socket->event.fde);
81 wrepl_socket->event.fde = NULL;
84 if (wrepl_socket->sock) {
85 talloc_free(wrepl_socket->sock);
86 wrepl_socket->sock = NULL;
89 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
90 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
92 while (wrepl_socket->recv_queue) {
93 struct wrepl_request *req = wrepl_socket->recv_queue;
94 DLIST_REMOVE(wrepl_socket->recv_queue, req);
95 wrepl_request_finished(req, status);
98 talloc_set_destructor(wrepl_socket, NULL);
99 if (wrepl_socket->free_skipped) {
100 talloc_free(wrepl_socket);
104 bool wrepl_socket_is_connected(struct wrepl_socket *wrepl_sock)
110 if (wrepl_sock->dead) {
114 if (!wrepl_sock->sock) {
121 static void wrepl_request_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
122 struct timeval t, void *ptr)
124 struct wrepl_request *req = talloc_get_type(ptr, struct wrepl_request);
125 wrepl_socket_dead(req->wrepl_socket, NT_STATUS_IO_TIMEOUT);
131 static NTSTATUS wrepl_finish_recv(void *private_data, DATA_BLOB packet_blob_in)
133 struct wrepl_socket *wrepl_socket = talloc_get_type(private_data, struct wrepl_socket);
134 struct wrepl_request *req = wrepl_socket->recv_queue;
136 enum ndr_err_code ndr_err;
139 DEBUG(1,("Received unexpected WINS packet of length %u!\n",
140 (unsigned)packet_blob_in.length));
141 return NT_STATUS_INVALID_NETWORK_RESPONSE;
144 req->packet = talloc(req, struct wrepl_packet);
145 NT_STATUS_HAVE_NO_MEMORY(req->packet);
147 blob.data = packet_blob_in.data + 4;
148 blob.length = packet_blob_in.length - 4;
150 /* we have a full request - parse it */
151 ndr_err = ndr_pull_struct_blob(&blob, req->packet, wrepl_socket->iconv_convenience, req->packet,
152 (ndr_pull_flags_fn_t)ndr_pull_wrepl_packet);
153 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
154 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
155 wrepl_request_finished(req, status);
160 DEBUG(10,("Received WINS packet of length %u\n",
161 (unsigned)packet_blob_in.length));
162 NDR_PRINT_DEBUG(wrepl_packet, req->packet);
165 wrepl_request_finished(req, NT_STATUS_OK);
170 handler for winrepl events
172 static void wrepl_handler(struct tevent_context *ev, struct tevent_fd *fde,
173 uint16_t flags, void *private_data)
175 struct wrepl_socket *wrepl_socket = talloc_get_type(private_data,
176 struct wrepl_socket);
177 if (flags & EVENT_FD_READ) {
178 packet_recv(wrepl_socket->packet);
181 if (flags & EVENT_FD_WRITE) {
182 packet_queue_run(wrepl_socket->packet);
186 static void wrepl_error(void *private_data, NTSTATUS status)
188 struct wrepl_socket *wrepl_socket = talloc_get_type(private_data,
189 struct wrepl_socket);
190 wrepl_socket_dead(wrepl_socket, status);
195 destroy a wrepl_socket destructor
197 static int wrepl_socket_destructor(struct wrepl_socket *sock)
200 sock->free_skipped = true;
203 wrepl_socket_dead(sock, NT_STATUS_LOCAL_DISCONNECT);
208 initialise a wrepl_socket. The event_ctx is optional, if provided then
209 operations will use that event context
211 struct wrepl_socket *wrepl_socket_init(TALLOC_CTX *mem_ctx,
212 struct tevent_context *event_ctx,
213 struct smb_iconv_convenience *iconv_convenience)
215 struct wrepl_socket *wrepl_socket;
218 wrepl_socket = talloc_zero(mem_ctx, struct wrepl_socket);
219 if (!wrepl_socket) return NULL;
221 wrepl_socket->event.ctx = event_ctx;
222 if (!wrepl_socket->event.ctx) goto failed;
224 wrepl_socket->iconv_convenience = iconv_convenience;
226 status = socket_create("ip", SOCKET_TYPE_STREAM, &wrepl_socket->sock, 0);
227 if (!NT_STATUS_IS_OK(status)) goto failed;
229 talloc_steal(wrepl_socket, wrepl_socket->sock);
231 wrepl_socket->request_timeout = WREPL_SOCKET_REQUEST_TIMEOUT;
233 talloc_set_destructor(wrepl_socket, wrepl_socket_destructor);
238 talloc_free(wrepl_socket);
243 initialise a wrepl_socket from an already existing connection
245 struct wrepl_socket *wrepl_socket_merge(TALLOC_CTX *mem_ctx,
246 struct tevent_context *event_ctx,
247 struct socket_context *sock,
248 struct packet_context *pack)
250 struct wrepl_socket *wrepl_socket;
252 wrepl_socket = talloc_zero(mem_ctx, struct wrepl_socket);
253 if (wrepl_socket == NULL) goto failed;
255 wrepl_socket->event.ctx = event_ctx;
256 if (wrepl_socket->event.ctx == NULL) goto failed;
258 wrepl_socket->sock = sock;
259 talloc_steal(wrepl_socket, wrepl_socket->sock);
262 wrepl_socket->request_timeout = WREPL_SOCKET_REQUEST_TIMEOUT;
264 wrepl_socket->event.fde = event_add_fd(wrepl_socket->event.ctx, wrepl_socket,
265 socket_get_fd(wrepl_socket->sock),
267 wrepl_handler, wrepl_socket);
268 if (wrepl_socket->event.fde == NULL) {
272 wrepl_socket->packet = pack;
273 talloc_steal(wrepl_socket, wrepl_socket->packet);
274 packet_set_private(wrepl_socket->packet, wrepl_socket);
275 packet_set_socket(wrepl_socket->packet, wrepl_socket->sock);
276 packet_set_callback(wrepl_socket->packet, wrepl_finish_recv);
277 packet_set_full_request(wrepl_socket->packet, packet_full_request_u32);
278 packet_set_error_handler(wrepl_socket->packet, wrepl_error);
279 packet_set_event_context(wrepl_socket->packet, wrepl_socket->event.ctx);
280 packet_set_fde(wrepl_socket->packet, wrepl_socket->event.fde);
281 packet_set_serialise(wrepl_socket->packet);
283 talloc_set_destructor(wrepl_socket, wrepl_socket_destructor);
288 talloc_free(wrepl_socket);
293 destroy a wrepl_request
295 static int wrepl_request_destructor(struct wrepl_request *req)
297 if (req->state == WREPL_REQUEST_RECV) {
298 DLIST_REMOVE(req->wrepl_socket->recv_queue, req);
300 req->state = WREPL_REQUEST_ERROR;
305 wait for a request to complete
307 static NTSTATUS wrepl_request_wait(struct wrepl_request *req)
309 NT_STATUS_HAVE_NO_MEMORY(req);
310 while (req->state < WREPL_REQUEST_DONE) {
311 event_loop_once(req->wrepl_socket->event.ctx);
316 const char *wrepl_best_ip(struct loadparm_context *lp_ctx, const char *peer_ip)
318 struct interface *ifaces;
319 load_interfaces(lp_ctx, lp_interfaces(lp_ctx), &ifaces);
320 return iface_best_ip(ifaces, peer_ip);
323 struct wrepl_connect_state {
324 struct wrepl_socket *wrepl_socket;
327 static void wrepl_connect_handler(struct composite_context *creq);
329 struct tevent_req *wrepl_connect_send(TALLOC_CTX *mem_ctx,
330 struct tevent_context *ev,
331 struct wrepl_socket *wrepl_socket,
332 const char *our_ip, const char *peer_ip)
334 struct tevent_req *req;
335 struct wrepl_connect_state *state;
336 struct composite_context *subreq;
337 struct socket_address *peer, *us;
339 req = tevent_req_create(mem_ctx, &state,
340 struct wrepl_connect_state);
345 state->wrepl_socket = wrepl_socket;
347 us = socket_address_from_strings(state, wrepl_socket->sock->backend_name,
349 if (tevent_req_nomem(us, req)) {
350 return tevent_req_post(req, ev);
353 peer = socket_address_from_strings(state, wrepl_socket->sock->backend_name,
354 peer_ip, WINS_REPLICATION_PORT);
355 if (tevent_req_nomem(peer, req)) {
356 return tevent_req_post(req, ev);
359 subreq = socket_connect_send(wrepl_socket->sock, us, peer,
360 0, wrepl_socket->event.ctx);
361 if (tevent_req_nomem(subreq, req)) {
362 return tevent_req_post(req, ev);
365 subreq->async.fn = wrepl_connect_handler;
366 subreq->async.private_data = req;
371 static void wrepl_connect_handler(struct composite_context *subreq)
373 struct tevent_req *req = talloc_get_type_abort(subreq->async.private_data,
375 struct wrepl_connect_state *state = tevent_req_data(req,
376 struct wrepl_connect_state);
377 struct wrepl_socket *wrepl_socket = state->wrepl_socket;
380 status = socket_connect_recv(subreq);
381 if (!NT_STATUS_IS_OK(status)) {
382 tevent_req_nterror(req, status);
386 wrepl_socket->event.fde = event_add_fd(wrepl_socket->event.ctx, wrepl_socket,
387 socket_get_fd(wrepl_socket->sock),
389 wrepl_handler, wrepl_socket);
390 if (tevent_req_nomem(wrepl_socket->event.fde, req)) {
394 /* setup the stream -> packet parser */
395 wrepl_socket->packet = packet_init(wrepl_socket);
396 if (tevent_req_nomem(wrepl_socket->packet, req)) {
399 packet_set_private(wrepl_socket->packet, wrepl_socket);
400 packet_set_socket(wrepl_socket->packet, wrepl_socket->sock);
401 packet_set_callback(wrepl_socket->packet, wrepl_finish_recv);
402 packet_set_full_request(wrepl_socket->packet, packet_full_request_u32);
403 packet_set_error_handler(wrepl_socket->packet, wrepl_error);
404 packet_set_event_context(wrepl_socket->packet, wrepl_socket->event.ctx);
405 packet_set_fde(wrepl_socket->packet, wrepl_socket->event.fde);
406 packet_set_serialise(wrepl_socket->packet);
408 tevent_req_done(req);
412 connect a wrepl_socket to a WINS server - recv side
414 NTSTATUS wrepl_connect_recv(struct tevent_req *req)
416 struct wrepl_connect_state *state = tevent_req_data(req,
417 struct wrepl_connect_state);
418 struct wrepl_socket *wrepl_socket = state->wrepl_socket;
421 if (tevent_req_is_nterror(req, &status)) {
422 wrepl_socket_dead(wrepl_socket, status);
423 tevent_req_received(req);
427 tevent_req_received(req);
432 connect a wrepl_socket to a WINS server - sync API
434 NTSTATUS wrepl_connect(struct wrepl_socket *wrepl_socket,
435 const char *our_ip, const char *peer_ip)
437 struct tevent_req *subreq;
441 subreq = wrepl_connect_send(wrepl_socket, wrepl_socket->event.ctx,
442 wrepl_socket, our_ip, peer_ip);
443 NT_STATUS_HAVE_NO_MEMORY(subreq);
445 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
448 return NT_STATUS_INTERNAL_ERROR;
451 status = wrepl_connect_recv(subreq);
453 NT_STATUS_NOT_OK_RETURN(status);
459 callback from wrepl_request_trigger()
461 static void wrepl_request_trigger_handler(struct tevent_context *ev, struct tevent_timer *te,
462 struct timeval t, void *ptr)
464 struct wrepl_request *req = talloc_get_type(ptr, struct wrepl_request);
471 trigger an immediate event on a wrepl_request
472 the return value should only be used in wrepl_request_send()
473 this is the only place where req->trigger is true
475 static struct wrepl_request *wrepl_request_finished(struct wrepl_request *req, NTSTATUS status)
477 struct tevent_timer *te;
479 if (req->state == WREPL_REQUEST_RECV) {
480 DLIST_REMOVE(req->wrepl_socket->recv_queue, req);
483 if (!NT_STATUS_IS_OK(status)) {
484 req->state = WREPL_REQUEST_ERROR;
486 req->state = WREPL_REQUEST_DONE;
489 req->status = status;
492 req->trigger = false;
493 /* a zero timeout means immediate */
494 te = event_add_timed(req->wrepl_socket->event.ctx,
496 wrepl_request_trigger_handler, req);
510 struct wrepl_send_ctrl_state {
511 struct wrepl_send_ctrl ctrl;
512 struct wrepl_request *req;
513 struct wrepl_socket *wrepl_sock;
516 static int wrepl_send_ctrl_destructor(struct wrepl_send_ctrl_state *s)
518 struct wrepl_request *req = s->wrepl_sock->recv_queue;
520 /* check if the request is still in WREPL_STATE_RECV,
521 * we need this here because the caller has may called
522 * talloc_free(req) and wrepl_send_ctrl_state isn't
523 * a talloc child of the request, so our s->req pointer
526 for (; req; req = req->next) {
527 if (req == s->req) break;
531 /* here, we need to make sure the async request handler is called
532 * later in the next event_loop and now now
535 wrepl_request_finished(req, NT_STATUS_OK);
537 if (s->ctrl.disconnect_after_send) {
538 wrepl_socket_dead(s->wrepl_sock, NT_STATUS_LOCAL_DISCONNECT);
545 send a generic wins replication request
547 static struct wrepl_request *wrepl_request_internal_send(struct wrepl_socket *wrepl_socket,
548 const struct wrepl_packet *packet,
549 const struct wrepl_send_ctrl *ctrl)
551 struct wrepl_request *req;
552 struct wrepl_wrap wrap;
555 enum ndr_err_code ndr_err;
557 req = talloc_zero(wrepl_socket, struct wrepl_request);
558 if (!req) return NULL;
559 req->wrepl_socket = wrepl_socket;
560 req->state = WREPL_REQUEST_RECV;
563 DLIST_ADD_END(wrepl_socket->recv_queue, req, struct wrepl_request *);
564 talloc_set_destructor(req, wrepl_request_destructor);
566 if (wrepl_socket->dead) {
567 return wrepl_request_finished(req, NT_STATUS_INVALID_CONNECTION);
570 wrap.packet = *packet;
571 ndr_err = ndr_push_struct_blob(&blob, req, wrepl_socket->iconv_convenience, &wrap,
572 (ndr_push_flags_fn_t)ndr_push_wrepl_wrap);
573 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
574 status = ndr_map_error2ntstatus(ndr_err);
575 return wrepl_request_finished(req, status);
579 DEBUG(10,("Sending WINS packet of length %u\n",
580 (unsigned)blob.length));
581 NDR_PRINT_DEBUG(wrepl_packet, &wrap.packet);
584 if (wrepl_socket->request_timeout > 0) {
585 req->te = event_add_timed(wrepl_socket->event.ctx, req,
586 timeval_current_ofs(wrepl_socket->request_timeout, 0),
587 wrepl_request_timeout_handler, req);
588 if (!req->te) return wrepl_request_finished(req, NT_STATUS_NO_MEMORY);
591 if (ctrl && (ctrl->send_only || ctrl->disconnect_after_send)) {
592 struct wrepl_send_ctrl_state *s = talloc(blob.data, struct wrepl_send_ctrl_state);
593 if (!s) return wrepl_request_finished(req, NT_STATUS_NO_MEMORY);
596 s->wrepl_sock = wrepl_socket;
597 talloc_set_destructor(s, wrepl_send_ctrl_destructor);
600 status = packet_send(wrepl_socket->packet, blob);
601 if (!NT_STATUS_IS_OK(status)) {
602 return wrepl_request_finished(req, status);
605 req->trigger = false;
610 receive a generic WINS replication reply
612 static NTSTATUS wrepl_request_internal_recv(struct wrepl_request *req,
614 struct wrepl_packet **packet)
616 NTSTATUS status = wrepl_request_wait(req);
617 if (NT_STATUS_IS_OK(status) && packet) {
618 *packet = talloc_steal(mem_ctx, req->packet);
624 struct wrepl_request_state {
625 struct wrepl_packet *packet;
628 static void wrepl_request_done(struct wrepl_request *subreq);
630 struct tevent_req *wrepl_request_send(TALLOC_CTX *mem_ctx,
631 struct tevent_context *ev,
632 struct wrepl_socket *wrepl_socket,
633 const struct wrepl_packet *packet,
634 const struct wrepl_send_ctrl *ctrl)
636 struct tevent_req *req;
637 struct wrepl_request_state *state;
638 struct wrepl_request *subreq;
640 if (wrepl_socket->event.ctx != ev) {
641 /* TODO: remove wrepl_socket->event.ctx !!! */
642 smb_panic("wrepl_associate_stop_send event context mismatch!");
646 req = tevent_req_create(mem_ctx, &state,
647 struct wrepl_request_state);
652 subreq = wrepl_request_internal_send(wrepl_socket, packet, ctrl);
653 if (tevent_req_nomem(subreq, req)) {
654 return tevent_req_post(req, ev);
656 subreq->async.fn = wrepl_request_done;
657 subreq->async.private_data = req;
662 static void wrepl_request_done(struct wrepl_request *subreq)
664 struct tevent_req *req = talloc_get_type_abort(subreq->async.private_data,
666 struct wrepl_request_state *state = tevent_req_data(req,
667 struct wrepl_request_state);
670 status = wrepl_request_internal_recv(subreq, state, &state->packet);
671 if (!NT_STATUS_IS_OK(status)) {
672 tevent_req_nterror(req, status);
676 tevent_req_done(req);
679 NTSTATUS wrepl_request_recv(struct tevent_req *req,
681 struct wrepl_packet **packet)
683 struct wrepl_request_state *state = tevent_req_data(req,
684 struct wrepl_request_state);
687 if (tevent_req_is_nterror(req, &status)) {
688 tevent_req_received(req);
693 *packet = talloc_move(mem_ctx, &state->packet);
696 tevent_req_received(req);
701 a full WINS replication request/response
703 NTSTATUS wrepl_request(struct wrepl_socket *wrepl_socket,
705 const struct wrepl_packet *req_packet,
706 struct wrepl_packet **reply_packet)
708 struct tevent_req *subreq;
712 subreq = wrepl_request_send(mem_ctx, wrepl_socket->event.ctx,
713 wrepl_socket, req_packet, NULL);
714 NT_STATUS_HAVE_NO_MEMORY(subreq);
716 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
719 return NT_STATUS_INTERNAL_ERROR;
722 status = wrepl_request_recv(subreq, mem_ctx, reply_packet);
724 NT_STATUS_NOT_OK_RETURN(status);
730 struct wrepl_associate_state {
731 struct wrepl_packet packet;
733 uint16_t major_version;
736 static void wrepl_associate_done(struct tevent_req *subreq);
738 struct tevent_req *wrepl_associate_send(TALLOC_CTX *mem_ctx,
739 struct tevent_context *ev,
740 struct wrepl_socket *wrepl_socket,
741 const struct wrepl_associate *io)
743 struct tevent_req *req;
744 struct wrepl_associate_state *state;
745 struct tevent_req *subreq;
747 if (wrepl_socket->event.ctx != ev) {
748 /* TODO: remove wrepl_socket->event.ctx !!! */
749 smb_panic("wrepl_associate_send event context mismatch!");
753 req = tevent_req_create(mem_ctx, &state,
754 struct wrepl_associate_state);
759 state->packet.opcode = WREPL_OPCODE_BITS;
760 state->packet.mess_type = WREPL_START_ASSOCIATION;
761 state->packet.message.start.minor_version = 2;
762 state->packet.message.start.major_version = 5;
765 * nt4 uses 41 bytes for the start_association call
766 * so do it the same and as we don't know th emeanings of this bytes
767 * we just send zeros and nt4, w2k and w2k3 seems to be happy with this
769 * if we don't do this nt4 uses an old version of the wins replication protocol
770 * and that would break nt4 <-> samba replication
772 state->packet.padding = data_blob_talloc(state, NULL, 21);
773 if (tevent_req_nomem(state->packet.padding.data, req)) {
774 return tevent_req_post(req, ev);
776 memset(state->packet.padding.data, 0, state->packet.padding.length);
778 subreq = wrepl_request_send(state, ev, wrepl_socket, &state->packet, NULL);
779 if (tevent_req_nomem(subreq, req)) {
780 return tevent_req_post(req, ev);
782 tevent_req_set_callback(subreq, wrepl_associate_done, req);
787 static void wrepl_associate_done(struct tevent_req *subreq)
789 struct tevent_req *req = tevent_req_callback_data(subreq,
791 struct wrepl_associate_state *state = tevent_req_data(req,
792 struct wrepl_associate_state);
794 struct wrepl_packet *packet;
796 status = wrepl_request_recv(subreq, state, &packet);
798 if (!NT_STATUS_IS_OK(status)) {
799 tevent_req_nterror(req, status);
803 if (packet->mess_type != WREPL_START_ASSOCIATION_REPLY) {
804 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
808 state->assoc_ctx = packet->message.start_reply.assoc_ctx;
809 state->major_version = packet->message.start_reply.major_version;
811 tevent_req_done(req);
815 setup an association - recv
817 NTSTATUS wrepl_associate_recv(struct tevent_req *req,
818 struct wrepl_associate *io)
820 struct wrepl_associate_state *state = tevent_req_data(req,
821 struct wrepl_associate_state);
824 if (tevent_req_is_nterror(req, &status)) {
825 tevent_req_received(req);
829 io->out.assoc_ctx = state->assoc_ctx;
830 io->out.major_version = state->major_version;
832 tevent_req_received(req);
837 setup an association - sync api
839 NTSTATUS wrepl_associate(struct wrepl_socket *wrepl_socket,
840 struct wrepl_associate *io)
842 struct tevent_req *subreq;
846 subreq = wrepl_associate_send(wrepl_socket, wrepl_socket->event.ctx,
848 NT_STATUS_HAVE_NO_MEMORY(subreq);
850 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
853 return NT_STATUS_INTERNAL_ERROR;
856 status = wrepl_associate_recv(subreq, io);
858 NT_STATUS_NOT_OK_RETURN(status);
863 struct wrepl_associate_stop_state {
864 struct wrepl_packet packet;
865 struct wrepl_send_ctrl ctrl;
868 static void wrepl_associate_stop_done(struct tevent_req *subreq);
870 struct tevent_req *wrepl_associate_stop_send(TALLOC_CTX *mem_ctx,
871 struct tevent_context *ev,
872 struct wrepl_socket *wrepl_socket,
873 const struct wrepl_associate_stop *io)
875 struct tevent_req *req;
876 struct wrepl_associate_stop_state *state;
877 struct tevent_req *subreq;
879 if (wrepl_socket->event.ctx != ev) {
880 /* TODO: remove wrepl_socket->event.ctx !!! */
881 smb_panic("wrepl_associate_stop_send event context mismatch!");
885 req = tevent_req_create(mem_ctx, &state,
886 struct wrepl_associate_stop_state);
891 state->packet.opcode = WREPL_OPCODE_BITS;
892 state->packet.assoc_ctx = io->in.assoc_ctx;
893 state->packet.mess_type = WREPL_STOP_ASSOCIATION;
894 state->packet.message.stop.reason = io->in.reason;
896 if (io->in.reason == 0) {
897 state->ctrl.send_only = true;
898 state->ctrl.disconnect_after_send = true;
901 subreq = wrepl_request_send(state, ev, wrepl_socket, &state->packet, &state->ctrl);
902 if (tevent_req_nomem(subreq, req)) {
903 return tevent_req_post(req, ev);
905 tevent_req_set_callback(subreq, wrepl_associate_stop_done, req);
910 static void wrepl_associate_stop_done(struct tevent_req *subreq)
912 struct tevent_req *req = tevent_req_callback_data(subreq,
914 struct wrepl_associate_stop_state *state = tevent_req_data(req,
915 struct wrepl_associate_stop_state);
918 /* currently we don't care about a possible response */
919 status = wrepl_request_recv(subreq, state, NULL);
921 if (!NT_STATUS_IS_OK(status)) {
922 tevent_req_nterror(req, status);
926 tevent_req_done(req);
930 stop an association - recv
932 NTSTATUS wrepl_associate_stop_recv(struct tevent_req *req,
933 struct wrepl_associate_stop *io)
937 if (tevent_req_is_nterror(req, &status)) {
938 tevent_req_received(req);
942 tevent_req_received(req);
947 setup an association - sync api
949 NTSTATUS wrepl_associate_stop(struct wrepl_socket *wrepl_socket,
950 struct wrepl_associate_stop *io)
952 struct tevent_req *subreq;
956 subreq = wrepl_associate_stop_send(wrepl_socket, wrepl_socket->event.ctx,
958 NT_STATUS_HAVE_NO_MEMORY(subreq);
960 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
963 return NT_STATUS_INTERNAL_ERROR;
966 status = wrepl_associate_stop_recv(subreq, io);
968 NT_STATUS_NOT_OK_RETURN(status);
973 struct wrepl_pull_table_state {
974 struct wrepl_packet packet;
975 uint32_t num_partners;
976 struct wrepl_wins_owner *partners;
979 static void wrepl_pull_table_done(struct tevent_req *subreq);
981 struct tevent_req *wrepl_pull_table_send(TALLOC_CTX *mem_ctx,
982 struct tevent_context *ev,
983 struct wrepl_socket *wrepl_socket,
984 const struct wrepl_pull_table *io)
986 struct tevent_req *req;
987 struct wrepl_pull_table_state *state;
988 struct tevent_req *subreq;
990 if (wrepl_socket->event.ctx != ev) {
991 /* TODO: remove wrepl_socket->event.ctx !!! */
992 smb_panic("wrepl_pull_table_send event context mismatch!");
996 req = tevent_req_create(mem_ctx, &state,
997 struct wrepl_pull_table_state);
1002 state->packet.opcode = WREPL_OPCODE_BITS;
1003 state->packet.assoc_ctx = io->in.assoc_ctx;
1004 state->packet.mess_type = WREPL_REPLICATION;
1005 state->packet.message.replication.command = WREPL_REPL_TABLE_QUERY;
1007 subreq = wrepl_request_send(state, ev, wrepl_socket, &state->packet, NULL);
1008 if (tevent_req_nomem(subreq, req)) {
1009 return tevent_req_post(req, ev);
1011 tevent_req_set_callback(subreq, wrepl_pull_table_done, req);
1016 static void wrepl_pull_table_done(struct tevent_req *subreq)
1018 struct tevent_req *req = tevent_req_callback_data(subreq,
1020 struct wrepl_pull_table_state *state = tevent_req_data(req,
1021 struct wrepl_pull_table_state);
1023 struct wrepl_packet *packet;
1024 struct wrepl_table *table;
1026 status = wrepl_request_recv(subreq, state, &packet);
1027 TALLOC_FREE(subreq);
1028 if (!NT_STATUS_IS_OK(status)) {
1029 tevent_req_nterror(req, status);
1033 if (packet->mess_type != WREPL_REPLICATION) {
1034 tevent_req_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
1038 if (packet->message.replication.command != WREPL_REPL_TABLE_REPLY) {
1039 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1043 table = &packet->message.replication.info.table;
1045 state->num_partners = table->partner_count;
1046 state->partners = talloc_move(state, &table->partners);
1048 tevent_req_done(req);
1052 fetch the partner tables - recv
1054 NTSTATUS wrepl_pull_table_recv(struct tevent_req *req,
1055 TALLOC_CTX *mem_ctx,
1056 struct wrepl_pull_table *io)
1058 struct wrepl_pull_table_state *state = tevent_req_data(req,
1059 struct wrepl_pull_table_state);
1062 if (tevent_req_is_nterror(req, &status)) {
1063 tevent_req_received(req);
1067 io->out.num_partners = state->num_partners;
1068 io->out.partners = talloc_move(mem_ctx, &state->partners);
1070 tevent_req_received(req);
1071 return NT_STATUS_OK;
1075 fetch the partner table - sync api
1077 NTSTATUS wrepl_pull_table(struct wrepl_socket *wrepl_socket,
1078 TALLOC_CTX *mem_ctx,
1079 struct wrepl_pull_table *io)
1081 struct tevent_req *subreq;
1085 subreq = wrepl_pull_table_send(mem_ctx, wrepl_socket->event.ctx,
1087 NT_STATUS_HAVE_NO_MEMORY(subreq);
1089 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
1091 TALLOC_FREE(subreq);
1092 return NT_STATUS_INTERNAL_ERROR;
1095 status = wrepl_pull_table_recv(subreq, mem_ctx, io);
1096 TALLOC_FREE(subreq);
1097 NT_STATUS_NOT_OK_RETURN(status);
1099 return NT_STATUS_OK;
1103 struct wrepl_pull_names_state {
1105 const struct wrepl_pull_names *io;
1107 struct wrepl_packet packet;
1109 struct wrepl_name *names;
1112 static void wrepl_pull_names_done(struct tevent_req *subreq);
1114 struct tevent_req *wrepl_pull_names_send(TALLOC_CTX *mem_ctx,
1115 struct tevent_context *ev,
1116 struct wrepl_socket *wrepl_socket,
1117 const struct wrepl_pull_names *io)
1119 struct tevent_req *req;
1120 struct wrepl_pull_names_state *state;
1121 struct tevent_req *subreq;
1123 if (wrepl_socket->event.ctx != ev) {
1124 /* TODO: remove wrepl_socket->event.ctx !!! */
1125 smb_panic("wrepl_pull_names_send event context mismatch!");
1129 req = tevent_req_create(mem_ctx, &state,
1130 struct wrepl_pull_names_state);
1134 state->caller.io = io;
1136 state->packet.opcode = WREPL_OPCODE_BITS;
1137 state->packet.assoc_ctx = io->in.assoc_ctx;
1138 state->packet.mess_type = WREPL_REPLICATION;
1139 state->packet.message.replication.command = WREPL_REPL_SEND_REQUEST;
1140 state->packet.message.replication.info.owner = io->in.partner;
1142 subreq = wrepl_request_send(state, ev, wrepl_socket, &state->packet, NULL);
1143 if (tevent_req_nomem(subreq, req)) {
1144 return tevent_req_post(req, ev);
1146 tevent_req_set_callback(subreq, wrepl_pull_names_done, req);
1151 static void wrepl_pull_names_done(struct tevent_req *subreq)
1153 struct tevent_req *req = tevent_req_callback_data(subreq,
1155 struct wrepl_pull_names_state *state = tevent_req_data(req,
1156 struct wrepl_pull_names_state);
1158 struct wrepl_packet *packet;
1161 status = wrepl_request_recv(subreq, state, &packet);
1162 TALLOC_FREE(subreq);
1163 if (!NT_STATUS_IS_OK(status)) {
1164 tevent_req_nterror(req, status);
1168 if (packet->mess_type != WREPL_REPLICATION) {
1169 tevent_req_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
1173 if (packet->message.replication.command != WREPL_REPL_SEND_REPLY) {
1174 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1178 state->num_names = packet->message.replication.info.reply.num_names;
1180 state->names = talloc_array(state, struct wrepl_name, state->num_names);
1181 if (tevent_req_nomem(state->names, req)) {
1185 /* convert the list of names and addresses to a sane format */
1186 for (i=0; i < state->num_names; i++) {
1187 struct wrepl_wins_name *wname = &packet->message.replication.info.reply.names[i];
1188 struct wrepl_name *name = &state->names[i];
1190 name->name = *wname->name;
1191 talloc_steal(state->names, wname->name);
1192 name->type = WREPL_NAME_TYPE(wname->flags);
1193 name->state = WREPL_NAME_STATE(wname->flags);
1194 name->node = WREPL_NAME_NODE(wname->flags);
1195 name->is_static = WREPL_NAME_IS_STATIC(wname->flags);
1196 name->raw_flags = wname->flags;
1197 name->version_id= wname->id;
1198 name->owner = talloc_strdup(state->names,
1199 state->caller.io->in.partner.address);
1200 if (tevent_req_nomem(name->owner, req)) {
1204 /* trying to save 1 or 2 bytes on the wire isn't a good idea */
1205 if (wname->flags & 2) {
1208 name->num_addresses = wname->addresses.addresses.num_ips;
1209 name->addresses = talloc_array(state->names,
1210 struct wrepl_address,
1211 name->num_addresses);
1212 if (tevent_req_nomem(name->addresses, req)) {
1216 for (j=0;j<name->num_addresses;j++) {
1217 name->addresses[j].owner =
1218 talloc_move(name->addresses,
1219 &wname->addresses.addresses.ips[j].owner);
1220 name->addresses[j].address =
1221 talloc_move(name->addresses,
1222 &wname->addresses.addresses.ips[j].ip);
1225 name->num_addresses = 1;
1226 name->addresses = talloc_array(state->names,
1227 struct wrepl_address,
1228 name->num_addresses);
1229 if (tevent_req_nomem(name->addresses, req)) {
1233 name->addresses[0].owner = talloc_strdup(name->addresses, name->owner);
1234 if (tevent_req_nomem(name->addresses[0].owner, req)) {
1237 name->addresses[0].address = talloc_move(name->addresses,
1238 &wname->addresses.ip);
1242 tevent_req_done(req);
1246 fetch the names for a WINS partner - recv
1248 NTSTATUS wrepl_pull_names_recv(struct tevent_req *req,
1249 TALLOC_CTX *mem_ctx,
1250 struct wrepl_pull_names *io)
1252 struct wrepl_pull_names_state *state = tevent_req_data(req,
1253 struct wrepl_pull_names_state);
1256 if (tevent_req_is_nterror(req, &status)) {
1257 tevent_req_received(req);
1261 io->out.num_names = state->num_names;
1262 io->out.names = talloc_move(mem_ctx, &state->names);
1264 tevent_req_received(req);
1265 return NT_STATUS_OK;
1271 fetch the names for a WINS partner - sync api
1273 NTSTATUS wrepl_pull_names(struct wrepl_socket *wrepl_socket,
1274 TALLOC_CTX *mem_ctx,
1275 struct wrepl_pull_names *io)
1277 struct tevent_req *subreq;
1281 subreq = wrepl_pull_names_send(mem_ctx, wrepl_socket->event.ctx,
1283 NT_STATUS_HAVE_NO_MEMORY(subreq);
1285 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
1287 TALLOC_FREE(subreq);
1288 return NT_STATUS_INTERNAL_ERROR;
1291 status = wrepl_pull_names_recv(subreq, mem_ctx, io);
1292 TALLOC_FREE(subreq);
1293 NT_STATUS_NOT_OK_RETURN(status);
1295 return NT_STATUS_OK;