0dee2c56cf32f5fa7c80e92ef732e4d0119d0155
[samba.git] / source4 / libcli / wrepl / winsrepl.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    low level WINS replication client code
5
6    Copyright (C) Andrew Tridgell 2005
7    Copyright (C) Stefan Metzmacher 2005-2010
8    
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.
13    
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.
18    
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/>.
21 */
22
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"
35
36 /*
37   main context structure for the wins replication client library
38 */
39 struct wrepl_socket {
40         struct {
41                 struct tevent_context *ctx;
42         } event;
43
44         /* the default timeout for requests, 0 means no timeout */
45 #define WREPL_SOCKET_REQUEST_TIMEOUT    (60)
46         uint32_t request_timeout;
47
48         struct tevent_queue *request_queue;
49
50         struct tstream_context *stream;
51 };
52
53 bool wrepl_socket_is_connected(struct wrepl_socket *wrepl_sock)
54 {
55         if (!wrepl_sock) {
56                 return false;
57         }
58
59         if (!wrepl_sock->stream) {
60                 return false;
61         }
62
63         return true;
64 }
65
66 /*
67   initialise a wrepl_socket. The event_ctx is optional, if provided then
68   operations will use that event context
69 */
70 struct wrepl_socket *wrepl_socket_init(TALLOC_CTX *mem_ctx,
71                                        struct tevent_context *event_ctx)
72 {
73         struct wrepl_socket *wrepl_socket;
74
75         wrepl_socket = talloc_zero(mem_ctx, struct wrepl_socket);
76         if (!wrepl_socket) {
77                 return NULL;
78         }
79
80         wrepl_socket->event.ctx = event_ctx;
81         if (!wrepl_socket->event.ctx) {
82                 goto failed;
83         }
84
85         wrepl_socket->request_queue = tevent_queue_create(wrepl_socket,
86                                                           "wrepl request queue");
87         if (wrepl_socket->request_queue == NULL) {
88                 goto failed;
89         }
90
91         wrepl_socket->request_timeout   = WREPL_SOCKET_REQUEST_TIMEOUT;
92
93         return wrepl_socket;
94
95 failed:
96         talloc_free(wrepl_socket);
97         return NULL;
98 }
99
100 /*
101   initialise a wrepl_socket from an already existing connection
102 */
103 NTSTATUS wrepl_socket_donate_stream(struct wrepl_socket *wrepl_socket,
104                                     struct tstream_context **stream)
105 {
106         if (wrepl_socket->stream) {
107                 return NT_STATUS_CONNECTION_ACTIVE;
108         }
109
110         wrepl_socket->stream = talloc_move(wrepl_socket, stream);
111         return NT_STATUS_OK;
112 }
113
114 /*
115   initialise a wrepl_socket from an already existing connection
116 */
117 NTSTATUS wrepl_socket_split_stream(struct wrepl_socket *wrepl_socket,
118                                    TALLOC_CTX *mem_ctx,
119                                    struct tstream_context **stream)
120 {
121         size_t num_requests;
122
123         if (!wrepl_socket->stream) {
124                 return NT_STATUS_CONNECTION_INVALID;
125         }
126
127         num_requests = tevent_queue_length(wrepl_socket->request_queue);
128         if (num_requests > 0) {
129                 return NT_STATUS_CONNECTION_IN_USE;
130         }
131
132         *stream = talloc_move(wrepl_socket, &wrepl_socket->stream);
133         return NT_STATUS_OK;
134 }
135
136 const char *wrepl_best_ip(struct loadparm_context *lp_ctx, const char *peer_ip)
137 {
138         struct interface *ifaces;
139         load_interface_list(lp_ctx, lp_ctx, &ifaces);
140         return iface_list_best_ip(ifaces, peer_ip);
141 }
142
143 struct wrepl_connect_state {
144         struct {
145                 struct wrepl_socket *wrepl_socket;
146                 struct tevent_context *ev;
147         } caller;
148         struct tsocket_address *local_address;
149         struct tsocket_address *remote_address;
150         struct tstream_context *stream;
151 };
152
153 static void wrepl_connect_trigger(struct tevent_req *req,
154                                   void *private_date);
155
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)
160 {
161         struct tevent_req *req;
162         struct wrepl_connect_state *state;
163         int ret;
164         bool ok;
165
166         req = tevent_req_create(mem_ctx, &state,
167                                 struct wrepl_connect_state);
168         if (req == NULL) {
169                 return NULL;
170         }
171
172         state->caller.wrepl_socket = wrepl_socket;
173         state->caller.ev = ev;
174
175         if (wrepl_socket->stream) {
176                 tevent_req_nterror(req, NT_STATUS_CONNECTION_ACTIVE);
177                 return tevent_req_post(req, ev);
178         }
179
180         ret = tsocket_address_inet_from_strings(state, "ipv4",
181                                                 our_ip, 0,
182                                                 &state->local_address);
183         if (ret != 0) {
184                 NTSTATUS status = map_nt_error_from_unix(errno);
185                 tevent_req_nterror(req, status);
186                 return tevent_req_post(req, ev);
187         }
188
189         ret = tsocket_address_inet_from_strings(state, "ipv4",
190                                                 peer_ip, WINS_REPLICATION_PORT,
191                                                 &state->remote_address);
192         if (ret != 0) {
193                 NTSTATUS status = map_nt_error_from_unix(errno);
194                 tevent_req_nterror(req, status);
195                 return tevent_req_post(req, ev);
196         }
197
198         ok = tevent_queue_add(wrepl_socket->request_queue,
199                               ev,
200                               req,
201                               wrepl_connect_trigger,
202                               NULL);
203         if (!ok) {
204                 tevent_req_nomem(NULL, req);
205                 return tevent_req_post(req, ev);
206         }
207
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);
212                 if (!ok) {
213                         return tevent_req_post(req, ev);
214                 }
215         }
216
217         return req;
218 }
219
220 static void wrepl_connect_done(struct tevent_req *subreq);
221
222 static void wrepl_connect_trigger(struct tevent_req *req,
223                                   void *private_date)
224 {
225         struct wrepl_connect_state *state = tevent_req_data(req,
226                                             struct wrepl_connect_state);
227         struct tevent_req *subreq;
228
229         subreq = tstream_inet_tcp_connect_send(state,
230                                                state->caller.ev,
231                                                state->local_address,
232                                                state->remote_address);
233         if (tevent_req_nomem(subreq, req)) {
234                 return;
235         }
236         tevent_req_set_callback(subreq, wrepl_connect_done, req);
237
238         return;
239 }
240
241 static void wrepl_connect_done(struct tevent_req *subreq)
242 {
243         struct tevent_req *req = tevent_req_callback_data(subreq,
244                                  struct tevent_req);
245         struct wrepl_connect_state *state = tevent_req_data(req,
246                                             struct wrepl_connect_state);
247         int ret;
248         int sys_errno;
249
250         ret = tstream_inet_tcp_connect_recv(subreq, &sys_errno,
251                                             state, &state->stream, NULL);
252         if (ret != 0) {
253                 NTSTATUS status = map_nt_error_from_unix(sys_errno);
254                 tevent_req_nterror(req, status);
255                 return;
256         }
257
258         tevent_req_done(req);
259 }
260
261 /*
262   connect a wrepl_socket to a WINS server - recv side
263 */
264 NTSTATUS wrepl_connect_recv(struct tevent_req *req)
265 {
266         struct wrepl_connect_state *state = tevent_req_data(req,
267                                             struct wrepl_connect_state);
268         struct wrepl_socket *wrepl_socket = state->caller.wrepl_socket;
269         NTSTATUS status;
270
271         if (tevent_req_is_nterror(req, &status)) {
272                 tevent_req_received(req);
273                 return status;
274         }
275
276         wrepl_socket->stream = talloc_move(wrepl_socket, &state->stream);
277
278         tevent_req_received(req);
279         return NT_STATUS_OK;
280 }
281
282 /*
283   connect a wrepl_socket to a WINS server - sync API
284 */
285 NTSTATUS wrepl_connect(struct wrepl_socket *wrepl_socket,
286                        const char *our_ip, const char *peer_ip)
287 {
288         struct tevent_req *subreq;
289         bool ok;
290         NTSTATUS status;
291
292         subreq = wrepl_connect_send(wrepl_socket, wrepl_socket->event.ctx,
293                                     wrepl_socket, our_ip, peer_ip);
294         NT_STATUS_HAVE_NO_MEMORY(subreq);
295
296         ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
297         if (!ok) {
298                 TALLOC_FREE(subreq);
299                 return NT_STATUS_INTERNAL_ERROR;
300         }
301
302         status = wrepl_connect_recv(subreq);
303         TALLOC_FREE(subreq);
304         NT_STATUS_NOT_OK_RETURN(status);
305
306         return NT_STATUS_OK;
307 }
308
309 struct wrepl_request_state {
310         struct {
311                 struct wrepl_socket *wrepl_socket;
312                 struct tevent_context *ev;
313         } caller;
314         struct wrepl_send_ctrl ctrl;
315         struct {
316                 struct wrepl_wrap wrap;
317                 DATA_BLOB blob;
318                 struct iovec iov;
319         } req;
320         bool one_way;
321         struct {
322                 DATA_BLOB blob;
323                 struct wrepl_packet *packet;
324         } rep;
325 };
326
327 static void wrepl_request_trigger(struct tevent_req *req,
328                                   void *private_data);
329
330 struct tevent_req *wrepl_request_send(TALLOC_CTX *mem_ctx,
331                                       struct tevent_context *ev,
332                                       struct wrepl_socket *wrepl_socket,
333                                       const struct wrepl_packet *packet,
334                                       const struct wrepl_send_ctrl *ctrl)
335 {
336         struct tevent_req *req;
337         struct wrepl_request_state *state;
338         NTSTATUS status;
339         enum ndr_err_code ndr_err;
340         bool ok;
341
342         if (wrepl_socket->event.ctx != ev) {
343                 /* TODO: remove wrepl_socket->event.ctx !!! */
344                 smb_panic("wrepl_associate_stop_send event context mismatch!");
345                 return NULL;
346         }
347
348         req = tevent_req_create(mem_ctx, &state,
349                                 struct wrepl_request_state);
350         if (req == NULL) {
351                 return NULL;
352         }
353
354         state->caller.wrepl_socket = wrepl_socket;
355         state->caller.ev = ev;
356
357         if (ctrl) {
358                 state->ctrl = *ctrl;
359         }
360
361         if (wrepl_socket->stream == NULL) {
362                 tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
363                 return tevent_req_post(req, ev);
364         }
365
366         state->req.wrap.packet = *packet;
367         ndr_err = ndr_push_struct_blob(&state->req.blob, state,
368                                        &state->req.wrap,
369                                        (ndr_push_flags_fn_t)ndr_push_wrepl_wrap);
370         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
371                 status = ndr_map_error2ntstatus(ndr_err);
372                 tevent_req_nterror(req, status);
373                 return tevent_req_post(req, ev);
374         }
375
376         state->req.iov.iov_base = (char *) state->req.blob.data;
377         state->req.iov.iov_len = state->req.blob.length;
378
379         ok = tevent_queue_add(wrepl_socket->request_queue,
380                               ev,
381                               req,
382                               wrepl_request_trigger,
383                               NULL);
384         if (!ok) {
385                 tevent_req_nomem(NULL, req);
386                 return tevent_req_post(req, ev);
387         }
388
389         if (wrepl_socket->request_timeout > 0) {
390                 struct timeval endtime;
391                 endtime = tevent_timeval_current_ofs(wrepl_socket->request_timeout, 0);
392                 ok = tevent_req_set_endtime(req, ev, endtime);
393                 if (!ok) {
394                         return tevent_req_post(req, ev);
395                 }
396         }
397
398         return req;
399 }
400
401 static void wrepl_request_writev_done(struct tevent_req *subreq);
402
403 static void wrepl_request_trigger(struct tevent_req *req,
404                                   void *private_data)
405 {
406         struct wrepl_request_state *state = tevent_req_data(req,
407                                             struct wrepl_request_state);
408         struct tevent_req *subreq;
409
410         if (state->caller.wrepl_socket->stream == NULL) {
411                 tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
412                 return;
413         }
414
415         if (DEBUGLVL(10)) {
416                 DEBUG(10,("Sending WINS packet of length %u\n",
417                           (unsigned)state->req.blob.length));
418                 NDR_PRINT_DEBUG(wrepl_packet, &state->req.wrap.packet);
419         }
420
421         subreq = tstream_writev_send(state,
422                                      state->caller.ev,
423                                      state->caller.wrepl_socket->stream,
424                                      &state->req.iov, 1);
425         if (tevent_req_nomem(subreq, req)) {
426                 return;
427         }
428         tevent_req_set_callback(subreq, wrepl_request_writev_done, req);
429 }
430
431 static void wrepl_request_disconnect_done(struct tevent_req *subreq);
432 static void wrepl_request_read_pdu_done(struct tevent_req *subreq);
433
434 static void wrepl_request_writev_done(struct tevent_req *subreq)
435 {
436         struct tevent_req *req = tevent_req_callback_data(subreq,
437                                  struct tevent_req);
438         struct wrepl_request_state *state = tevent_req_data(req,
439                                             struct wrepl_request_state);
440         int ret;
441         int sys_errno;
442
443         ret = tstream_writev_recv(subreq, &sys_errno);
444         TALLOC_FREE(subreq);
445         if (ret == -1) {
446                 NTSTATUS status = map_nt_error_from_unix(sys_errno);
447                 TALLOC_FREE(state->caller.wrepl_socket->stream);
448                 tevent_req_nterror(req, status);
449                 return;
450         }
451
452         if (state->caller.wrepl_socket->stream == NULL) {
453                 tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
454                 return;
455         }
456
457         if (state->ctrl.disconnect_after_send) {
458                 subreq = tstream_disconnect_send(state,
459                                                  state->caller.ev,
460                                                  state->caller.wrepl_socket->stream);
461                 if (tevent_req_nomem(subreq, req)) {
462                         return;
463                 }
464                 tevent_req_set_callback(subreq, wrepl_request_disconnect_done, req);
465                 return;
466         }
467
468         if (state->ctrl.send_only) {
469                 tevent_req_done(req);
470                 return;
471         }
472
473         subreq = tstream_read_pdu_blob_send(state,
474                                             state->caller.ev,
475                                             state->caller.wrepl_socket->stream,
476                                             4, /* initial_read_size */
477                                             packet_full_request_u32,
478                                             NULL);
479         if (tevent_req_nomem(subreq, req)) {
480                 return;
481         }
482         tevent_req_set_callback(subreq, wrepl_request_read_pdu_done, req);
483 }
484
485 static void wrepl_request_disconnect_done(struct tevent_req *subreq)
486 {
487         struct tevent_req *req = tevent_req_callback_data(subreq,
488                                  struct tevent_req);
489         struct wrepl_request_state *state = tevent_req_data(req,
490                                             struct wrepl_request_state);
491         int ret;
492         int sys_errno;
493
494         ret = tstream_disconnect_recv(subreq, &sys_errno);
495         TALLOC_FREE(subreq);
496         if (ret == -1) {
497                 NTSTATUS status = map_nt_error_from_unix(sys_errno);
498                 TALLOC_FREE(state->caller.wrepl_socket->stream);
499                 tevent_req_nterror(req, status);
500                 return;
501         }
502
503         DEBUG(10,("WINS connection disconnected\n"));
504         TALLOC_FREE(state->caller.wrepl_socket->stream);
505
506         tevent_req_done(req);
507 }
508
509 static void wrepl_request_read_pdu_done(struct tevent_req *subreq)
510 {
511         struct tevent_req *req = tevent_req_callback_data(subreq,
512                                  struct tevent_req);
513         struct wrepl_request_state *state = tevent_req_data(req,
514                                             struct wrepl_request_state);
515         NTSTATUS status;
516         DATA_BLOB blob;
517         enum ndr_err_code ndr_err;
518
519         status = tstream_read_pdu_blob_recv(subreq, state, &state->rep.blob);
520         if (!NT_STATUS_IS_OK(status)) {
521                 TALLOC_FREE(state->caller.wrepl_socket->stream);
522                 tevent_req_nterror(req, status);
523                 return;
524         }
525
526         state->rep.packet = talloc(state, struct wrepl_packet);
527         if (tevent_req_nomem(state->rep.packet, req)) {
528                 return;
529         }
530
531         blob.data = state->rep.blob.data + 4;
532         blob.length = state->rep.blob.length - 4;
533
534         /* we have a full request - parse it */
535         ndr_err = ndr_pull_struct_blob(&blob,
536                                        state->rep.packet,
537                                        state->rep.packet,
538                                        (ndr_pull_flags_fn_t)ndr_pull_wrepl_packet);
539         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
540                 status = ndr_map_error2ntstatus(ndr_err);
541                 tevent_req_nterror(req, status);
542                 return;
543         }
544
545         if (DEBUGLVL(10)) {
546                 DEBUG(10,("Received WINS packet of length %u\n",
547                           (unsigned)state->rep.blob.length));
548                 NDR_PRINT_DEBUG(wrepl_packet, state->rep.packet);
549         }
550
551         tevent_req_done(req);
552 }
553
554 NTSTATUS wrepl_request_recv(struct tevent_req *req,
555                             TALLOC_CTX *mem_ctx,
556                             struct wrepl_packet **packet)
557 {
558         struct wrepl_request_state *state = tevent_req_data(req,
559                                             struct wrepl_request_state);
560         NTSTATUS status;
561
562         if (tevent_req_is_nterror(req, &status)) {
563                 TALLOC_FREE(state->caller.wrepl_socket->stream);
564                 tevent_req_received(req);
565                 return status;
566         }
567
568         if (packet) {
569                 *packet = talloc_move(mem_ctx, &state->rep.packet);
570         }
571
572         tevent_req_received(req);
573         return NT_STATUS_OK;
574 }
575
576 /*
577   a full WINS replication request/response
578 */
579 NTSTATUS wrepl_request(struct wrepl_socket *wrepl_socket,
580                        TALLOC_CTX *mem_ctx,
581                        const struct wrepl_packet *req_packet,
582                        struct wrepl_packet **reply_packet)
583 {
584         struct tevent_req *subreq;
585         bool ok;
586         NTSTATUS status;
587
588         subreq = wrepl_request_send(mem_ctx, wrepl_socket->event.ctx,
589                                     wrepl_socket, req_packet, NULL);
590         NT_STATUS_HAVE_NO_MEMORY(subreq);
591
592         ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
593         if (!ok) {
594                 TALLOC_FREE(subreq);
595                 return NT_STATUS_INTERNAL_ERROR;
596         }
597
598         status = wrepl_request_recv(subreq, mem_ctx, reply_packet);
599         TALLOC_FREE(subreq);
600         NT_STATUS_NOT_OK_RETURN(status);
601
602         return NT_STATUS_OK;
603 }
604
605
606 struct wrepl_associate_state {
607         struct wrepl_packet packet;
608         uint32_t assoc_ctx;
609         uint16_t major_version;
610 };
611
612 static void wrepl_associate_done(struct tevent_req *subreq);
613
614 struct tevent_req *wrepl_associate_send(TALLOC_CTX *mem_ctx,
615                                         struct tevent_context *ev,
616                                         struct wrepl_socket *wrepl_socket,
617                                         const struct wrepl_associate *io)
618 {
619         struct tevent_req *req;
620         struct wrepl_associate_state *state;
621         struct tevent_req *subreq;
622
623         if (wrepl_socket->event.ctx != ev) {
624                 /* TODO: remove wrepl_socket->event.ctx !!! */
625                 smb_panic("wrepl_associate_send event context mismatch!");
626                 return NULL;
627         }
628
629         req = tevent_req_create(mem_ctx, &state,
630                                 struct wrepl_associate_state);
631         if (req == NULL) {
632                 return NULL;
633         };
634
635         state->packet.opcode                            = WREPL_OPCODE_BITS;
636         state->packet.mess_type                         = WREPL_START_ASSOCIATION;
637         state->packet.message.start.minor_version       = 2;
638         state->packet.message.start.major_version       = 5;
639
640         /*
641          * nt4 uses 41 bytes for the start_association call
642          * so do it the same and as we don't know th emeanings of this bytes
643          * we just send zeros and nt4, w2k and w2k3 seems to be happy with this
644          *
645          * if we don't do this nt4 uses an old version of the wins replication protocol
646          * and that would break nt4 <-> samba replication
647          */
648         state->packet.padding   = data_blob_talloc(state, NULL, 21);
649         if (tevent_req_nomem(state->packet.padding.data, req)) {
650                 return tevent_req_post(req, ev);
651         }
652         memset(state->packet.padding.data, 0, state->packet.padding.length);
653
654         subreq = wrepl_request_send(state, ev, wrepl_socket, &state->packet, NULL);
655         if (tevent_req_nomem(subreq, req)) {
656                 return tevent_req_post(req, ev);
657         }
658         tevent_req_set_callback(subreq, wrepl_associate_done, req);
659
660         return req;
661 }
662
663 static void wrepl_associate_done(struct tevent_req *subreq)
664 {
665         struct tevent_req *req = tevent_req_callback_data(subreq,
666                                  struct tevent_req);
667         struct wrepl_associate_state *state = tevent_req_data(req,
668                                               struct wrepl_associate_state);
669         NTSTATUS status;
670         struct wrepl_packet *packet;
671
672         status = wrepl_request_recv(subreq, state, &packet);
673         TALLOC_FREE(subreq);
674         if (!NT_STATUS_IS_OK(status)) {
675                 tevent_req_nterror(req, status);
676                 return;
677         }
678
679         if (packet->mess_type != WREPL_START_ASSOCIATION_REPLY) {
680                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
681                 return;
682         }
683
684         state->assoc_ctx = packet->message.start_reply.assoc_ctx;
685         state->major_version = packet->message.start_reply.major_version;
686
687         tevent_req_done(req);
688 }
689
690 /*
691   setup an association - recv
692 */
693 NTSTATUS wrepl_associate_recv(struct tevent_req *req,
694                               struct wrepl_associate *io)
695 {
696         struct wrepl_associate_state *state = tevent_req_data(req,
697                                               struct wrepl_associate_state);
698         NTSTATUS status;
699
700         if (tevent_req_is_nterror(req, &status)) {
701                 tevent_req_received(req);
702                 return status;
703         }
704
705         io->out.assoc_ctx = state->assoc_ctx;
706         io->out.major_version = state->major_version;
707
708         tevent_req_received(req);
709         return NT_STATUS_OK;
710 }
711
712 /*
713   setup an association - sync api
714 */
715 NTSTATUS wrepl_associate(struct wrepl_socket *wrepl_socket,
716                          struct wrepl_associate *io)
717 {
718         struct tevent_req *subreq;
719         bool ok;
720         NTSTATUS status;
721
722         subreq = wrepl_associate_send(wrepl_socket, wrepl_socket->event.ctx,
723                                       wrepl_socket, io);
724         NT_STATUS_HAVE_NO_MEMORY(subreq);
725
726         ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
727         if (!ok) {
728                 TALLOC_FREE(subreq);
729                 return NT_STATUS_INTERNAL_ERROR;
730         }
731
732         status = wrepl_associate_recv(subreq, io);
733         TALLOC_FREE(subreq);
734         NT_STATUS_NOT_OK_RETURN(status);
735
736         return NT_STATUS_OK;
737 }
738
739 struct wrepl_associate_stop_state {
740         struct wrepl_packet packet;
741         struct wrepl_send_ctrl ctrl;
742 };
743
744 static void wrepl_associate_stop_done(struct tevent_req *subreq);
745
746 struct tevent_req *wrepl_associate_stop_send(TALLOC_CTX *mem_ctx,
747                                              struct tevent_context *ev,
748                                              struct wrepl_socket *wrepl_socket,
749                                              const struct wrepl_associate_stop *io)
750 {
751         struct tevent_req *req;
752         struct wrepl_associate_stop_state *state;
753         struct tevent_req *subreq;
754
755         if (wrepl_socket->event.ctx != ev) {
756                 /* TODO: remove wrepl_socket->event.ctx !!! */
757                 smb_panic("wrepl_associate_stop_send event context mismatch!");
758                 return NULL;
759         }
760
761         req = tevent_req_create(mem_ctx, &state,
762                                 struct wrepl_associate_stop_state);
763         if (req == NULL) {
764                 return NULL;
765         };
766
767         state->packet.opcode                    = WREPL_OPCODE_BITS;
768         state->packet.assoc_ctx                 = io->in.assoc_ctx;
769         state->packet.mess_type                 = WREPL_STOP_ASSOCIATION;
770         state->packet.message.stop.reason       = io->in.reason;
771
772         if (io->in.reason == 0) {
773                 state->ctrl.send_only                   = true;
774                 state->ctrl.disconnect_after_send       = true;
775         }
776
777         subreq = wrepl_request_send(state, ev, wrepl_socket, &state->packet, &state->ctrl);
778         if (tevent_req_nomem(subreq, req)) {
779                 return tevent_req_post(req, ev);
780         }
781         tevent_req_set_callback(subreq, wrepl_associate_stop_done, req);
782
783         return req;
784 }
785
786 static void wrepl_associate_stop_done(struct tevent_req *subreq)
787 {
788         struct tevent_req *req = tevent_req_callback_data(subreq,
789                                  struct tevent_req);
790         struct wrepl_associate_stop_state *state = tevent_req_data(req,
791                                                    struct wrepl_associate_stop_state);
792         NTSTATUS status;
793
794         /* currently we don't care about a possible response */
795         status = wrepl_request_recv(subreq, state, NULL);
796         TALLOC_FREE(subreq);
797         if (!NT_STATUS_IS_OK(status)) {
798                 tevent_req_nterror(req, status);
799                 return;
800         }
801
802         tevent_req_done(req);
803 }
804
805 /*
806   stop an association - recv
807 */
808 NTSTATUS wrepl_associate_stop_recv(struct tevent_req *req,
809                                    struct wrepl_associate_stop *io)
810 {
811         NTSTATUS status;
812
813         if (tevent_req_is_nterror(req, &status)) {
814                 tevent_req_received(req);
815                 return status;
816         }
817
818         tevent_req_received(req);
819         return NT_STATUS_OK;
820 }
821
822 /*
823   setup an association - sync api
824 */
825 NTSTATUS wrepl_associate_stop(struct wrepl_socket *wrepl_socket,
826                               struct wrepl_associate_stop *io)
827 {
828         struct tevent_req *subreq;
829         bool ok;
830         NTSTATUS status;
831
832         subreq = wrepl_associate_stop_send(wrepl_socket, wrepl_socket->event.ctx,
833                                            wrepl_socket, io);
834         NT_STATUS_HAVE_NO_MEMORY(subreq);
835
836         ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
837         if (!ok) {
838                 TALLOC_FREE(subreq);
839                 return NT_STATUS_INTERNAL_ERROR;
840         }
841
842         status = wrepl_associate_stop_recv(subreq, io);
843         TALLOC_FREE(subreq);
844         NT_STATUS_NOT_OK_RETURN(status);
845
846         return NT_STATUS_OK;
847 }
848
849 struct wrepl_pull_table_state {
850         struct wrepl_packet packet;
851         uint32_t num_partners;
852         struct wrepl_wins_owner *partners;
853 };
854
855 static void wrepl_pull_table_done(struct tevent_req *subreq);
856
857 struct tevent_req *wrepl_pull_table_send(TALLOC_CTX *mem_ctx,
858                                          struct tevent_context *ev,
859                                          struct wrepl_socket *wrepl_socket,
860                                          const struct wrepl_pull_table *io)
861 {
862         struct tevent_req *req;
863         struct wrepl_pull_table_state *state;
864         struct tevent_req *subreq;
865
866         if (wrepl_socket->event.ctx != ev) {
867                 /* TODO: remove wrepl_socket->event.ctx !!! */
868                 smb_panic("wrepl_pull_table_send event context mismatch!");
869                 return NULL;
870         }
871
872         req = tevent_req_create(mem_ctx, &state,
873                                 struct wrepl_pull_table_state);
874         if (req == NULL) {
875                 return NULL;
876         };
877
878         state->packet.opcode                            = WREPL_OPCODE_BITS;
879         state->packet.assoc_ctx                         = io->in.assoc_ctx;
880         state->packet.mess_type                         = WREPL_REPLICATION;
881         state->packet.message.replication.command       = WREPL_REPL_TABLE_QUERY;
882
883         subreq = wrepl_request_send(state, ev, wrepl_socket, &state->packet, NULL);
884         if (tevent_req_nomem(subreq, req)) {
885                 return tevent_req_post(req, ev);
886         }
887         tevent_req_set_callback(subreq, wrepl_pull_table_done, req);
888
889         return req;
890 }
891
892 static void wrepl_pull_table_done(struct tevent_req *subreq)
893 {
894         struct tevent_req *req = tevent_req_callback_data(subreq,
895                                  struct tevent_req);
896         struct wrepl_pull_table_state *state = tevent_req_data(req,
897                                                struct wrepl_pull_table_state);
898         NTSTATUS status;
899         struct wrepl_packet *packet;
900         struct wrepl_table *table;
901
902         status = wrepl_request_recv(subreq, state, &packet);
903         TALLOC_FREE(subreq);
904         if (!NT_STATUS_IS_OK(status)) {
905                 tevent_req_nterror(req, status);
906                 return;
907         }
908
909         if (packet->mess_type != WREPL_REPLICATION) {
910                 tevent_req_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
911                 return;
912         }
913
914         if (packet->message.replication.command != WREPL_REPL_TABLE_REPLY) {
915                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
916                 return;
917         }
918
919         table = &packet->message.replication.info.table;
920
921         state->num_partners = table->partner_count;
922         state->partners = talloc_move(state, &table->partners);
923
924         tevent_req_done(req);
925 }
926
927 /*
928   fetch the partner tables - recv
929 */
930 NTSTATUS wrepl_pull_table_recv(struct tevent_req *req,
931                                TALLOC_CTX *mem_ctx,
932                                struct wrepl_pull_table *io)
933 {
934         struct wrepl_pull_table_state *state = tevent_req_data(req,
935                                                struct wrepl_pull_table_state);
936         NTSTATUS status;
937
938         if (tevent_req_is_nterror(req, &status)) {
939                 tevent_req_received(req);
940                 return status;
941         }
942
943         io->out.num_partners = state->num_partners;
944         io->out.partners = talloc_move(mem_ctx, &state->partners);
945
946         tevent_req_received(req);
947         return NT_STATUS_OK;
948 }
949
950 /*
951   fetch the partner table - sync api
952 */
953 NTSTATUS wrepl_pull_table(struct wrepl_socket *wrepl_socket,
954                           TALLOC_CTX *mem_ctx,
955                           struct wrepl_pull_table *io)
956 {
957         struct tevent_req *subreq;
958         bool ok;
959         NTSTATUS status;
960
961         subreq = wrepl_pull_table_send(mem_ctx, wrepl_socket->event.ctx,
962                                        wrepl_socket, io);
963         NT_STATUS_HAVE_NO_MEMORY(subreq);
964
965         ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
966         if (!ok) {
967                 TALLOC_FREE(subreq);
968                 return NT_STATUS_INTERNAL_ERROR;
969         }
970
971         status = wrepl_pull_table_recv(subreq, mem_ctx, io);
972         TALLOC_FREE(subreq);
973         NT_STATUS_NOT_OK_RETURN(status);
974
975         return NT_STATUS_OK;
976 }
977
978
979 struct wrepl_pull_names_state {
980         struct {
981                 const struct wrepl_pull_names *io;
982         } caller;
983         struct wrepl_packet packet;
984         uint32_t num_names;
985         struct wrepl_name *names;
986 };
987
988 static void wrepl_pull_names_done(struct tevent_req *subreq);
989
990 struct tevent_req *wrepl_pull_names_send(TALLOC_CTX *mem_ctx,
991                                          struct tevent_context *ev,
992                                          struct wrepl_socket *wrepl_socket,
993                                          const struct wrepl_pull_names *io)
994 {
995         struct tevent_req *req;
996         struct wrepl_pull_names_state *state;
997         struct tevent_req *subreq;
998
999         if (wrepl_socket->event.ctx != ev) {
1000                 /* TODO: remove wrepl_socket->event.ctx !!! */
1001                 smb_panic("wrepl_pull_names_send event context mismatch!");
1002                 return NULL;
1003         }
1004
1005         req = tevent_req_create(mem_ctx, &state,
1006                                 struct wrepl_pull_names_state);
1007         if (req == NULL) {
1008                 return NULL;
1009         };
1010         state->caller.io = io;
1011
1012         state->packet.opcode                            = WREPL_OPCODE_BITS;
1013         state->packet.assoc_ctx                         = io->in.assoc_ctx;
1014         state->packet.mess_type                         = WREPL_REPLICATION;
1015         state->packet.message.replication.command       = WREPL_REPL_SEND_REQUEST;
1016         state->packet.message.replication.info.owner    = io->in.partner;
1017
1018         subreq = wrepl_request_send(state, ev, wrepl_socket, &state->packet, NULL);
1019         if (tevent_req_nomem(subreq, req)) {
1020                 return tevent_req_post(req, ev);
1021         }
1022         tevent_req_set_callback(subreq, wrepl_pull_names_done, req);
1023
1024         return req;
1025 }
1026
1027 static void wrepl_pull_names_done(struct tevent_req *subreq)
1028 {
1029         struct tevent_req *req = tevent_req_callback_data(subreq,
1030                                  struct tevent_req);
1031         struct wrepl_pull_names_state *state = tevent_req_data(req,
1032                                                struct wrepl_pull_names_state);
1033         NTSTATUS status;
1034         struct wrepl_packet *packet;
1035         uint32_t i;
1036
1037         status = wrepl_request_recv(subreq, state, &packet);
1038         TALLOC_FREE(subreq);
1039         if (!NT_STATUS_IS_OK(status)) {
1040                 tevent_req_nterror(req, status);
1041                 return;
1042         }
1043
1044         if (packet->mess_type != WREPL_REPLICATION) {
1045                 tevent_req_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
1046                 return;
1047         }
1048
1049         if (packet->message.replication.command != WREPL_REPL_SEND_REPLY) {
1050                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1051                 return;
1052         }
1053
1054         state->num_names = packet->message.replication.info.reply.num_names;
1055
1056         state->names = talloc_array(state, struct wrepl_name, state->num_names);
1057         if (tevent_req_nomem(state->names, req)) {
1058                 return;
1059         }
1060
1061         /* convert the list of names and addresses to a sane format */
1062         for (i=0; i < state->num_names; i++) {
1063                 struct wrepl_wins_name *wname = &packet->message.replication.info.reply.names[i];
1064                 struct wrepl_name *name = &state->names[i];
1065
1066                 name->name      = *wname->name;
1067                 talloc_steal(state->names, wname->name);
1068                 name->type      = WREPL_NAME_TYPE(wname->flags);
1069                 name->state     = WREPL_NAME_STATE(wname->flags);
1070                 name->node      = WREPL_NAME_NODE(wname->flags);
1071                 name->is_static = WREPL_NAME_IS_STATIC(wname->flags);
1072                 name->raw_flags = wname->flags;
1073                 name->version_id= wname->id;
1074                 name->owner     = talloc_strdup(state->names,
1075                                                 state->caller.io->in.partner.address);
1076                 if (tevent_req_nomem(name->owner, req)) {
1077                         return;
1078                 }
1079
1080                 /* trying to save 1 or 2 bytes on the wire isn't a good idea */
1081                 if (wname->flags & 2) {
1082                         uint32_t j;
1083
1084                         name->num_addresses = wname->addresses.addresses.num_ips;
1085                         name->addresses = talloc_array(state->names,
1086                                                        struct wrepl_address,
1087                                                        name->num_addresses);
1088                         if (tevent_req_nomem(name->addresses, req)) {
1089                                 return;
1090                         }
1091
1092                         for (j=0;j<name->num_addresses;j++) {
1093                                 name->addresses[j].owner =
1094                                         talloc_move(name->addresses,
1095                                                     &wname->addresses.addresses.ips[j].owner);
1096                                 name->addresses[j].address = 
1097                                         talloc_move(name->addresses,
1098                                                     &wname->addresses.addresses.ips[j].ip);
1099                         }
1100                 } else {
1101                         name->num_addresses = 1;
1102                         name->addresses = talloc_array(state->names,
1103                                                        struct wrepl_address,
1104                                                        name->num_addresses);
1105                         if (tevent_req_nomem(name->addresses, req)) {
1106                                 return;
1107                         }
1108
1109                         name->addresses[0].owner = talloc_strdup(name->addresses, name->owner);
1110                         if (tevent_req_nomem(name->addresses[0].owner, req)) {
1111                                 return;
1112                         }
1113                         name->addresses[0].address = talloc_move(name->addresses,
1114                                                                  &wname->addresses.ip);
1115                 }
1116         }
1117
1118         tevent_req_done(req);
1119 }
1120
1121 /*
1122   fetch the names for a WINS partner - recv
1123 */
1124 NTSTATUS wrepl_pull_names_recv(struct tevent_req *req,
1125                                TALLOC_CTX *mem_ctx,
1126                                struct wrepl_pull_names *io)
1127 {
1128         struct wrepl_pull_names_state *state = tevent_req_data(req,
1129                                                struct wrepl_pull_names_state);
1130         NTSTATUS status;
1131
1132         if (tevent_req_is_nterror(req, &status)) {
1133                 tevent_req_received(req);
1134                 return status;
1135         }
1136
1137         io->out.num_names = state->num_names;
1138         io->out.names = talloc_move(mem_ctx, &state->names);
1139
1140         tevent_req_received(req);
1141         return NT_STATUS_OK;
1142 }
1143
1144
1145
1146 /*
1147   fetch the names for a WINS partner - sync api
1148 */
1149 NTSTATUS wrepl_pull_names(struct wrepl_socket *wrepl_socket,
1150                           TALLOC_CTX *mem_ctx,
1151                           struct wrepl_pull_names *io)
1152 {
1153         struct tevent_req *subreq;
1154         bool ok;
1155         NTSTATUS status;
1156
1157         subreq = wrepl_pull_names_send(mem_ctx, wrepl_socket->event.ctx,
1158                                        wrepl_socket, io);
1159         NT_STATUS_HAVE_NO_MEMORY(subreq);
1160
1161         ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
1162         if (!ok) {
1163                 TALLOC_FREE(subreq);
1164                 return NT_STATUS_INTERNAL_ERROR;
1165         }
1166
1167         status = wrepl_pull_names_recv(subreq, mem_ctx, io);
1168         TALLOC_FREE(subreq);
1169         NT_STATUS_NOT_OK_RETURN(status);
1170
1171         return NT_STATUS_OK;
1172 }