s4:torture: Initialize struct cldap_netlogon
[Samba.git] / source4 / libcli / wrepl / winsrepl.c
blobcf6c1f16d65b5c81d92001889c90acbab39a9ce5
1 /*
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/>.
23 #include "includes.h"
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
39 struct wrepl_socket {
40 struct {
41 struct tevent_context *ctx;
42 } event;
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)
55 if (!wrepl_sock) {
56 return false;
59 if (!wrepl_sock->stream) {
60 return false;
63 return true;
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);
76 if (!wrepl_socket) {
77 return NULL;
80 wrepl_socket->event.ctx = event_ctx;
81 if (!wrepl_socket->event.ctx) {
82 goto failed;
85 wrepl_socket->request_queue = tevent_queue_create(wrepl_socket,
86 "wrepl request queue");
87 if (wrepl_socket->request_queue == NULL) {
88 goto failed;
91 wrepl_socket->request_timeout = WREPL_SOCKET_REQUEST_TIMEOUT;
93 return wrepl_socket;
95 failed:
96 talloc_free(wrepl_socket);
97 return NULL;
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);
113 return NT_STATUS_OK;
117 initialise a wrepl_socket from an already existing connection
119 NTSTATUS wrepl_socket_split_stream(struct wrepl_socket *wrepl_socket,
120 TALLOC_CTX *mem_ctx,
121 struct tstream_context **stream)
123 size_t num_requests;
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);
135 return NT_STATUS_OK;
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 {
146 struct {
147 struct wrepl_socket *wrepl_socket;
148 struct tevent_context *ev;
149 } caller;
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,
156 void *private_date);
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;
165 int ret;
166 bool ok;
168 req = tevent_req_create(mem_ctx, &state,
169 struct wrepl_connect_state);
170 if (req == NULL) {
171 return NULL;
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",
183 our_ip, 0,
184 &state->local_address);
185 if (ret != 0) {
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);
194 if (ret != 0) {
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,
202 req,
203 wrepl_connect_trigger,
204 NULL);
205 if (!ok) {
206 tevent_req_oom(req);
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);
214 if (!ok) {
215 return tevent_req_post(req, ev);
219 return req;
222 static void wrepl_connect_done(struct tevent_req *subreq);
224 static void wrepl_connect_trigger(struct tevent_req *req,
225 void *private_date)
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,
232 state->caller.ev,
233 state->local_address,
234 state->remote_address);
235 if (tevent_req_nomem(subreq, req)) {
236 return;
238 tevent_req_set_callback(subreq, wrepl_connect_done, req);
240 return;
243 static void wrepl_connect_done(struct tevent_req *subreq)
245 struct tevent_req *req = tevent_req_callback_data(subreq,
246 struct tevent_req);
247 struct wrepl_connect_state *state = tevent_req_data(req,
248 struct wrepl_connect_state);
249 int ret;
250 int sys_errno;
252 ret = tstream_inet_tcp_connect_recv(subreq, &sys_errno,
253 state, &state->stream, NULL);
254 if (ret != 0) {
255 NTSTATUS status = map_nt_error_from_unix_common(sys_errno);
256 tevent_req_nterror(req, status);
257 return;
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;
271 NTSTATUS status;
273 if (tevent_req_is_nterror(req, &status)) {
274 tevent_req_received(req);
275 return status;
278 wrepl_socket->stream = talloc_move(wrepl_socket, &state->stream);
280 tevent_req_received(req);
281 return NT_STATUS_OK;
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;
291 bool ok;
292 NTSTATUS status;
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);
299 if (!ok) {
300 TALLOC_FREE(subreq);
301 return NT_STATUS_INTERNAL_ERROR;
304 status = wrepl_connect_recv(subreq);
305 TALLOC_FREE(subreq);
306 NT_STATUS_NOT_OK_RETURN(status);
308 return NT_STATUS_OK;
311 struct wrepl_request_state {
312 struct {
313 struct wrepl_socket *wrepl_socket;
314 struct tevent_context *ev;
315 } caller;
316 struct wrepl_send_ctrl ctrl;
317 struct {
318 struct wrepl_wrap wrap;
319 DATA_BLOB blob;
320 struct iovec iov;
321 } req;
322 bool one_way;
323 struct {
324 DATA_BLOB blob;
325 struct wrepl_packet *packet;
326 } rep;
329 static void wrepl_request_trigger(struct tevent_req *req,
330 void *private_data);
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;
340 NTSTATUS status;
341 enum ndr_err_code ndr_err;
342 bool ok;
344 if (wrepl_socket->event.ctx != ev) {
345 /* TODO: remove wrepl_socket->event.ctx !!! */
346 smb_panic("wrepl_associate_stop_send event context mismatch!");
347 return NULL;
350 req = tevent_req_create(mem_ctx, &state,
351 struct wrepl_request_state);
352 if (req == NULL) {
353 return NULL;
356 state->caller.wrepl_socket = wrepl_socket;
357 state->caller.ev = ev;
359 if (ctrl) {
360 state->ctrl = *ctrl;
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,
370 &state->req.wrap,
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,
383 req,
384 wrepl_request_trigger,
385 NULL);
386 if (!ok) {
387 tevent_req_oom(req);
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);
395 if (!ok) {
396 return tevent_req_post(req, ev);
400 return req;
403 static void wrepl_request_writev_done(struct tevent_req *subreq);
405 static void wrepl_request_trigger(struct tevent_req *req,
406 void *private_data)
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);
414 return;
417 if (DEBUGLVL(10)) {
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,
424 state->caller.ev,
425 state->caller.wrepl_socket->stream,
426 &state->req.iov, 1);
427 if (tevent_req_nomem(subreq, req)) {
428 return;
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,
439 struct tevent_req);
440 struct wrepl_request_state *state = tevent_req_data(req,
441 struct wrepl_request_state);
442 int ret;
443 int sys_errno;
445 ret = tstream_writev_recv(subreq, &sys_errno);
446 TALLOC_FREE(subreq);
447 if (ret == -1) {
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);
451 return;
454 if (state->caller.wrepl_socket->stream == NULL) {
455 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
456 return;
459 if (state->ctrl.disconnect_after_send) {
460 subreq = tstream_disconnect_send(state,
461 state->caller.ev,
462 state->caller.wrepl_socket->stream);
463 if (tevent_req_nomem(subreq, req)) {
464 return;
466 tevent_req_set_callback(subreq, wrepl_request_disconnect_done, req);
467 return;
470 if (state->ctrl.send_only) {
471 tevent_req_done(req);
472 return;
475 subreq = tstream_read_pdu_blob_send(state,
476 state->caller.ev,
477 state->caller.wrepl_socket->stream,
478 4, /* initial_read_size */
479 tstream_full_request_u32,
480 NULL);
481 if (tevent_req_nomem(subreq, req)) {
482 return;
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,
490 struct tevent_req);
491 struct wrepl_request_state *state = tevent_req_data(req,
492 struct wrepl_request_state);
493 int ret;
494 int sys_errno;
496 ret = tstream_disconnect_recv(subreq, &sys_errno);
497 TALLOC_FREE(subreq);
498 if (ret == -1) {
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);
502 return;
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,
514 struct tevent_req);
515 struct wrepl_request_state *state = tevent_req_data(req,
516 struct wrepl_request_state);
517 NTSTATUS status;
518 DATA_BLOB blob;
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);
525 return;
528 state->rep.packet = talloc(state, struct wrepl_packet);
529 if (tevent_req_nomem(state->rep.packet, req)) {
530 return;
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,
538 state->rep.packet,
539 state->rep.packet,
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);
544 return;
547 if (DEBUGLVL(10)) {
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,
557 TALLOC_CTX *mem_ctx,
558 struct wrepl_packet **packet)
560 struct wrepl_request_state *state = tevent_req_data(req,
561 struct wrepl_request_state);
562 NTSTATUS status;
564 if (tevent_req_is_nterror(req, &status)) {
565 TALLOC_FREE(state->caller.wrepl_socket->stream);
566 tevent_req_received(req);
567 return status;
570 if (packet) {
571 *packet = talloc_move(mem_ctx, &state->rep.packet);
574 tevent_req_received(req);
575 return NT_STATUS_OK;
579 a full WINS replication request/response
581 NTSTATUS wrepl_request(struct wrepl_socket *wrepl_socket,
582 TALLOC_CTX *mem_ctx,
583 const struct wrepl_packet *req_packet,
584 struct wrepl_packet **reply_packet)
586 struct tevent_req *subreq;
587 bool ok;
588 NTSTATUS status;
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);
595 if (!ok) {
596 TALLOC_FREE(subreq);
597 return NT_STATUS_INTERNAL_ERROR;
600 status = wrepl_request_recv(subreq, mem_ctx, reply_packet);
601 TALLOC_FREE(subreq);
602 NT_STATUS_NOT_OK_RETURN(status);
604 return NT_STATUS_OK;
608 struct wrepl_associate_state {
609 struct wrepl_packet packet;
610 uint32_t assoc_ctx;
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!");
628 return NULL;
631 req = tevent_req_create(mem_ctx, &state,
632 struct wrepl_associate_state);
633 if (req == NULL) {
634 return NULL;
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);
662 return req;
665 static void wrepl_associate_done(struct tevent_req *subreq)
667 struct tevent_req *req = tevent_req_callback_data(subreq,
668 struct tevent_req);
669 struct wrepl_associate_state *state = tevent_req_data(req,
670 struct wrepl_associate_state);
671 NTSTATUS status;
672 struct wrepl_packet *packet;
674 status = wrepl_request_recv(subreq, state, &packet);
675 TALLOC_FREE(subreq);
676 if (!NT_STATUS_IS_OK(status)) {
677 tevent_req_nterror(req, status);
678 return;
681 if (packet->mess_type != WREPL_START_ASSOCIATION_REPLY) {
682 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
683 return;
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);
700 NTSTATUS status;
702 if (tevent_req_is_nterror(req, &status)) {
703 tevent_req_received(req);
704 return status;
707 io->out.assoc_ctx = state->assoc_ctx;
708 io->out.major_version = state->major_version;
710 tevent_req_received(req);
711 return NT_STATUS_OK;
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;
721 bool ok;
722 NTSTATUS status;
724 subreq = wrepl_associate_send(wrepl_socket, wrepl_socket->event.ctx,
725 wrepl_socket, io);
726 NT_STATUS_HAVE_NO_MEMORY(subreq);
728 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
729 if (!ok) {
730 TALLOC_FREE(subreq);
731 return NT_STATUS_INTERNAL_ERROR;
734 status = wrepl_associate_recv(subreq, io);
735 TALLOC_FREE(subreq);
736 NT_STATUS_NOT_OK_RETURN(status);
738 return NT_STATUS_OK;
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!");
760 return NULL;
763 req = tevent_req_create(mem_ctx, &state,
764 struct wrepl_associate_stop_state);
765 if (req == NULL) {
766 return NULL;
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);
785 return req;
788 static void wrepl_associate_stop_done(struct tevent_req *subreq)
790 struct tevent_req *req = tevent_req_callback_data(subreq,
791 struct tevent_req);
792 struct wrepl_associate_stop_state *state = tevent_req_data(req,
793 struct wrepl_associate_stop_state);
794 NTSTATUS status;
796 /* currently we don't care about a possible response */
797 status = wrepl_request_recv(subreq, state, NULL);
798 TALLOC_FREE(subreq);
799 if (!NT_STATUS_IS_OK(status)) {
800 tevent_req_nterror(req, status);
801 return;
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)
813 NTSTATUS status;
815 if (tevent_req_is_nterror(req, &status)) {
816 tevent_req_received(req);
817 return status;
820 tevent_req_received(req);
821 return NT_STATUS_OK;
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;
831 bool ok;
832 NTSTATUS status;
834 subreq = wrepl_associate_stop_send(wrepl_socket, wrepl_socket->event.ctx,
835 wrepl_socket, io);
836 NT_STATUS_HAVE_NO_MEMORY(subreq);
838 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
839 if (!ok) {
840 TALLOC_FREE(subreq);
841 return NT_STATUS_INTERNAL_ERROR;
844 status = wrepl_associate_stop_recv(subreq, io);
845 TALLOC_FREE(subreq);
846 NT_STATUS_NOT_OK_RETURN(status);
848 return NT_STATUS_OK;
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!");
871 return NULL;
874 req = tevent_req_create(mem_ctx, &state,
875 struct wrepl_pull_table_state);
876 if (req == NULL) {
877 return NULL;
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);
891 return req;
894 static void wrepl_pull_table_done(struct tevent_req *subreq)
896 struct tevent_req *req = tevent_req_callback_data(subreq,
897 struct tevent_req);
898 struct wrepl_pull_table_state *state = tevent_req_data(req,
899 struct wrepl_pull_table_state);
900 NTSTATUS status;
901 struct wrepl_packet *packet;
902 struct wrepl_table *table;
904 status = wrepl_request_recv(subreq, state, &packet);
905 TALLOC_FREE(subreq);
906 if (!NT_STATUS_IS_OK(status)) {
907 tevent_req_nterror(req, status);
908 return;
911 if (packet->mess_type != WREPL_REPLICATION) {
912 tevent_req_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
913 return;
916 if (packet->message.replication.command != WREPL_REPL_TABLE_REPLY) {
917 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
918 return;
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,
933 TALLOC_CTX *mem_ctx,
934 struct wrepl_pull_table *io)
936 struct wrepl_pull_table_state *state = tevent_req_data(req,
937 struct wrepl_pull_table_state);
938 NTSTATUS status;
940 if (tevent_req_is_nterror(req, &status)) {
941 tevent_req_received(req);
942 return status;
945 io->out.num_partners = state->num_partners;
946 io->out.partners = talloc_move(mem_ctx, &state->partners);
948 tevent_req_received(req);
949 return NT_STATUS_OK;
953 fetch the partner table - sync api
955 NTSTATUS wrepl_pull_table(struct wrepl_socket *wrepl_socket,
956 TALLOC_CTX *mem_ctx,
957 struct wrepl_pull_table *io)
959 struct tevent_req *subreq;
960 bool ok;
961 NTSTATUS status;
963 subreq = wrepl_pull_table_send(mem_ctx, wrepl_socket->event.ctx,
964 wrepl_socket, io);
965 NT_STATUS_HAVE_NO_MEMORY(subreq);
967 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
968 if (!ok) {
969 TALLOC_FREE(subreq);
970 return NT_STATUS_INTERNAL_ERROR;
973 status = wrepl_pull_table_recv(subreq, mem_ctx, io);
974 TALLOC_FREE(subreq);
975 NT_STATUS_NOT_OK_RETURN(status);
977 return NT_STATUS_OK;
981 struct wrepl_pull_names_state {
982 struct {
983 const struct wrepl_pull_names *io;
984 } caller;
985 struct wrepl_packet packet;
986 uint32_t num_names;
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!");
1004 return NULL;
1007 req = tevent_req_create(mem_ctx, &state,
1008 struct wrepl_pull_names_state);
1009 if (req == NULL) {
1010 return NULL;
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);
1026 return req;
1029 static void wrepl_pull_names_done(struct tevent_req *subreq)
1031 struct tevent_req *req = tevent_req_callback_data(subreq,
1032 struct tevent_req);
1033 struct wrepl_pull_names_state *state = tevent_req_data(req,
1034 struct wrepl_pull_names_state);
1035 NTSTATUS status;
1036 struct wrepl_packet *packet;
1037 uint32_t i;
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);
1043 return;
1046 if (packet->mess_type != WREPL_REPLICATION) {
1047 tevent_req_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
1048 return;
1051 if (packet->message.replication.command != WREPL_REPL_SEND_REPLY) {
1052 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1053 return;
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)) {
1060 return;
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)) {
1079 return;
1082 /* trying to save 1 or 2 bytes on the wire isn't a good idea */
1083 if (wname->flags & 2) {
1084 uint32_t j;
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)) {
1091 return;
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);
1102 } else {
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)) {
1108 return;
1111 name->addresses[0].owner = talloc_strdup(name->addresses, name->owner);
1112 if (tevent_req_nomem(name->addresses[0].owner, req)) {
1113 return;
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);
1132 NTSTATUS status;
1134 if (tevent_req_is_nterror(req, &status)) {
1135 tevent_req_received(req);
1136 return status;
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;
1156 bool ok;
1157 NTSTATUS status;
1159 subreq = wrepl_pull_names_send(mem_ctx, wrepl_socket->event.ctx,
1160 wrepl_socket, io);
1161 NT_STATUS_HAVE_NO_MEMORY(subreq);
1163 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
1164 if (!ok) {
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;