trigger SIGPIPE...
[metze/samba/wip.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_common(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_common(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_oom(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_common(sys_errno);
254                 tevent_req_nterror(req, status);
255                 return;
256         }
257
258         smb_msleep(5000);
259         tevent_req_done(req);
260 }
261
262 /*
263   connect a wrepl_socket to a WINS server - recv side
264 */
265 NTSTATUS wrepl_connect_recv(struct tevent_req *req)
266 {
267         struct wrepl_connect_state *state = tevent_req_data(req,
268                                             struct wrepl_connect_state);
269         struct wrepl_socket *wrepl_socket = state->caller.wrepl_socket;
270         NTSTATUS status;
271
272         if (tevent_req_is_nterror(req, &status)) {
273                 tevent_req_received(req);
274                 return status;
275         }
276
277         wrepl_socket->stream = talloc_move(wrepl_socket, &state->stream);
278
279         tevent_req_received(req);
280         return NT_STATUS_OK;
281 }
282
283 /*
284   connect a wrepl_socket to a WINS server - sync API
285 */
286 NTSTATUS wrepl_connect(struct wrepl_socket *wrepl_socket,
287                        const char *our_ip, const char *peer_ip)
288 {
289         struct tevent_req *subreq;
290         bool ok;
291         NTSTATUS status;
292
293         subreq = wrepl_connect_send(wrepl_socket, wrepl_socket->event.ctx,
294                                     wrepl_socket, our_ip, peer_ip);
295         NT_STATUS_HAVE_NO_MEMORY(subreq);
296
297         ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
298         if (!ok) {
299                 TALLOC_FREE(subreq);
300                 return NT_STATUS_INTERNAL_ERROR;
301         }
302
303         status = wrepl_connect_recv(subreq);
304         TALLOC_FREE(subreq);
305         NT_STATUS_NOT_OK_RETURN(status);
306
307         return NT_STATUS_OK;
308 }
309
310 struct wrepl_request_state {
311         struct {
312                 struct wrepl_socket *wrepl_socket;
313                 struct tevent_context *ev;
314         } caller;
315         struct wrepl_send_ctrl ctrl;
316         struct {
317                 struct wrepl_wrap wrap;
318                 DATA_BLOB blob;
319                 struct iovec iov;
320         } req;
321         bool one_way;
322         struct {
323                 DATA_BLOB blob;
324                 struct wrepl_packet *packet;
325         } rep;
326 };
327
328 static void wrepl_request_trigger(struct tevent_req *req,
329                                   void *private_data);
330
331 struct tevent_req *wrepl_request_send(TALLOC_CTX *mem_ctx,
332                                       struct tevent_context *ev,
333                                       struct wrepl_socket *wrepl_socket,
334                                       const struct wrepl_packet *packet,
335                                       const struct wrepl_send_ctrl *ctrl)
336 {
337         struct tevent_req *req;
338         struct wrepl_request_state *state;
339         NTSTATUS status;
340         enum ndr_err_code ndr_err;
341         bool ok;
342
343         if (wrepl_socket->event.ctx != ev) {
344                 /* TODO: remove wrepl_socket->event.ctx !!! */
345                 smb_panic("wrepl_associate_stop_send event context mismatch!");
346                 return NULL;
347         }
348
349         req = tevent_req_create(mem_ctx, &state,
350                                 struct wrepl_request_state);
351         if (req == NULL) {
352                 return NULL;
353         }
354
355         state->caller.wrepl_socket = wrepl_socket;
356         state->caller.ev = ev;
357
358         if (ctrl) {
359                 state->ctrl = *ctrl;
360         }
361
362         if (wrepl_socket->stream == NULL) {
363                 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
364                 return tevent_req_post(req, ev);
365         }
366
367         state->req.wrap.packet = *packet;
368         ndr_err = ndr_push_struct_blob(&state->req.blob, state,
369                                        &state->req.wrap,
370                                        (ndr_push_flags_fn_t)ndr_push_wrepl_wrap);
371         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
372                 status = ndr_map_error2ntstatus(ndr_err);
373                 tevent_req_nterror(req, status);
374                 return tevent_req_post(req, ev);
375         }
376
377         state->req.iov.iov_base = (char *) state->req.blob.data;
378         state->req.iov.iov_len = state->req.blob.length;
379
380         ok = tevent_queue_add(wrepl_socket->request_queue,
381                               ev,
382                               req,
383                               wrepl_request_trigger,
384                               NULL);
385         if (!ok) {
386                 tevent_req_oom(req);
387                 return tevent_req_post(req, ev);
388         }
389
390         if (wrepl_socket->request_timeout > 0) {
391                 struct timeval endtime;
392                 endtime = tevent_timeval_current_ofs(wrepl_socket->request_timeout, 0);
393                 ok = tevent_req_set_endtime(req, ev, endtime);
394                 if (!ok) {
395                         return tevent_req_post(req, ev);
396                 }
397         }
398
399         return req;
400 }
401
402 static void wrepl_request_writev_done(struct tevent_req *subreq);
403
404 static void wrepl_request_trigger(struct tevent_req *req,
405                                   void *private_data)
406 {
407         struct wrepl_request_state *state = tevent_req_data(req,
408                                             struct wrepl_request_state);
409         struct tevent_req *subreq;
410
411         if (state->caller.wrepl_socket->stream == NULL) {
412                 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
413                 return;
414         }
415
416         if (DEBUGLVL(10)) {
417                 DEBUG(10,("Sending WINS packet of length %u\n",
418                           (unsigned)state->req.blob.length));
419                 NDR_PRINT_DEBUG(wrepl_packet, &state->req.wrap.packet);
420         }
421
422         subreq = tstream_writev_send(state,
423                                      state->caller.ev,
424                                      state->caller.wrepl_socket->stream,
425                                      &state->req.iov, 1);
426         if (tevent_req_nomem(subreq, req)) {
427                 return;
428         }
429         tevent_req_set_callback(subreq, wrepl_request_writev_done, req);
430 }
431
432 static void wrepl_request_disconnect_done(struct tevent_req *subreq);
433 static void wrepl_request_read_pdu_done(struct tevent_req *subreq);
434
435 static void wrepl_request_writev_done(struct tevent_req *subreq)
436 {
437         struct tevent_req *req = tevent_req_callback_data(subreq,
438                                  struct tevent_req);
439         struct wrepl_request_state *state = tevent_req_data(req,
440                                             struct wrepl_request_state);
441         int ret;
442         int sys_errno;
443
444         ret = tstream_writev_recv(subreq, &sys_errno);
445         TALLOC_FREE(subreq);
446         if (ret == -1) {
447                 NTSTATUS status = map_nt_error_from_unix_common(sys_errno);
448                 TALLOC_FREE(state->caller.wrepl_socket->stream);
449                 tevent_req_nterror(req, status);
450                 return;
451         }
452
453         if (state->caller.wrepl_socket->stream == NULL) {
454                 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
455                 return;
456         }
457
458         if (state->ctrl.disconnect_after_send) {
459                 subreq = tstream_disconnect_send(state,
460                                                  state->caller.ev,
461                                                  state->caller.wrepl_socket->stream);
462                 if (tevent_req_nomem(subreq, req)) {
463                         return;
464                 }
465                 tevent_req_set_callback(subreq, wrepl_request_disconnect_done, req);
466                 return;
467         }
468
469         if (state->ctrl.send_only) {
470                 tevent_req_done(req);
471                 return;
472         }
473
474         subreq = tstream_read_pdu_blob_send(state,
475                                             state->caller.ev,
476                                             state->caller.wrepl_socket->stream,
477                                             4, /* initial_read_size */
478                                             packet_full_request_u32,
479                                             NULL);
480         if (tevent_req_nomem(subreq, req)) {
481                 return;
482         }
483         tevent_req_set_callback(subreq, wrepl_request_read_pdu_done, req);
484 }
485
486 static void wrepl_request_disconnect_done(struct tevent_req *subreq)
487 {
488         struct tevent_req *req = tevent_req_callback_data(subreq,
489                                  struct tevent_req);
490         struct wrepl_request_state *state = tevent_req_data(req,
491                                             struct wrepl_request_state);
492         int ret;
493         int sys_errno;
494
495         ret = tstream_disconnect_recv(subreq, &sys_errno);
496         TALLOC_FREE(subreq);
497         if (ret == -1) {
498                 NTSTATUS status = map_nt_error_from_unix_common(sys_errno);
499                 TALLOC_FREE(state->caller.wrepl_socket->stream);
500                 tevent_req_nterror(req, status);
501                 return;
502         }
503
504         DEBUG(10,("WINS connection disconnected\n"));
505         TALLOC_FREE(state->caller.wrepl_socket->stream);
506
507         tevent_req_done(req);
508 }
509
510 static void wrepl_request_read_pdu_done(struct tevent_req *subreq)
511 {
512         struct tevent_req *req = tevent_req_callback_data(subreq,
513                                  struct tevent_req);
514         struct wrepl_request_state *state = tevent_req_data(req,
515                                             struct wrepl_request_state);
516         NTSTATUS status;
517         DATA_BLOB blob;
518         enum ndr_err_code ndr_err;
519
520         status = tstream_read_pdu_blob_recv(subreq, state, &state->rep.blob);
521         if (!NT_STATUS_IS_OK(status)) {
522                 TALLOC_FREE(state->caller.wrepl_socket->stream);
523                 tevent_req_nterror(req, status);
524                 return;
525         }
526
527         state->rep.packet = talloc(state, struct wrepl_packet);
528         if (tevent_req_nomem(state->rep.packet, req)) {
529                 return;
530         }
531
532         blob.data = state->rep.blob.data + 4;
533         blob.length = state->rep.blob.length - 4;
534
535         /* we have a full request - parse it */
536         ndr_err = ndr_pull_struct_blob(&blob,
537                                        state->rep.packet,
538                                        state->rep.packet,
539                                        (ndr_pull_flags_fn_t)ndr_pull_wrepl_packet);
540         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
541                 status = ndr_map_error2ntstatus(ndr_err);
542                 tevent_req_nterror(req, status);
543                 return;
544         }
545
546         if (DEBUGLVL(10)) {
547                 DEBUG(10,("Received WINS packet of length %u\n",
548                           (unsigned)state->rep.blob.length));
549                 NDR_PRINT_DEBUG(wrepl_packet, state->rep.packet);
550         }
551
552         tevent_req_done(req);
553 }
554
555 NTSTATUS wrepl_request_recv(struct tevent_req *req,
556                             TALLOC_CTX *mem_ctx,
557                             struct wrepl_packet **packet)
558 {
559         struct wrepl_request_state *state = tevent_req_data(req,
560                                             struct wrepl_request_state);
561         NTSTATUS status;
562
563         if (tevent_req_is_nterror(req, &status)) {
564                 TALLOC_FREE(state->caller.wrepl_socket->stream);
565                 tevent_req_received(req);
566                 return status;
567         }
568
569         if (packet) {
570                 *packet = talloc_move(mem_ctx, &state->rep.packet);
571         }
572
573         tevent_req_received(req);
574         return NT_STATUS_OK;
575 }
576
577 /*
578   a full WINS replication request/response
579 */
580 NTSTATUS wrepl_request(struct wrepl_socket *wrepl_socket,
581                        TALLOC_CTX *mem_ctx,
582                        const struct wrepl_packet *req_packet,
583                        struct wrepl_packet **reply_packet)
584 {
585         struct tevent_req *subreq;
586         bool ok;
587         NTSTATUS status;
588
589         subreq = wrepl_request_send(mem_ctx, wrepl_socket->event.ctx,
590                                     wrepl_socket, req_packet, NULL);
591         NT_STATUS_HAVE_NO_MEMORY(subreq);
592
593         ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
594         if (!ok) {
595                 TALLOC_FREE(subreq);
596                 return NT_STATUS_INTERNAL_ERROR;
597         }
598
599         status = wrepl_request_recv(subreq, mem_ctx, reply_packet);
600         TALLOC_FREE(subreq);
601         NT_STATUS_NOT_OK_RETURN(status);
602
603         return NT_STATUS_OK;
604 }
605
606
607 struct wrepl_associate_state {
608         struct wrepl_packet packet;
609         uint32_t assoc_ctx;
610         uint16_t major_version;
611 };
612
613 static void wrepl_associate_done(struct tevent_req *subreq);
614
615 struct tevent_req *wrepl_associate_send(TALLOC_CTX *mem_ctx,
616                                         struct tevent_context *ev,
617                                         struct wrepl_socket *wrepl_socket,
618                                         const struct wrepl_associate *io)
619 {
620         struct tevent_req *req;
621         struct wrepl_associate_state *state;
622         struct tevent_req *subreq;
623
624         if (wrepl_socket->event.ctx != ev) {
625                 /* TODO: remove wrepl_socket->event.ctx !!! */
626                 smb_panic("wrepl_associate_send event context mismatch!");
627                 return NULL;
628         }
629
630         req = tevent_req_create(mem_ctx, &state,
631                                 struct wrepl_associate_state);
632         if (req == NULL) {
633                 return NULL;
634         };
635
636         state->packet.opcode                            = WREPL_OPCODE_BITS;
637         state->packet.mess_type                         = WREPL_START_ASSOCIATION;
638         state->packet.message.start.minor_version       = 2;
639         state->packet.message.start.major_version       = 5;
640
641         /*
642          * nt4 uses 41 bytes for the start_association call
643          * so do it the same and as we don't know th emeanings of this bytes
644          * we just send zeros and nt4, w2k and w2k3 seems to be happy with this
645          *
646          * if we don't do this nt4 uses an old version of the wins replication protocol
647          * and that would break nt4 <-> samba replication
648          */
649         state->packet.padding   = data_blob_talloc(state, NULL, 21);
650         if (tevent_req_nomem(state->packet.padding.data, req)) {
651                 return tevent_req_post(req, ev);
652         }
653         memset(state->packet.padding.data, 0, state->packet.padding.length);
654
655         subreq = wrepl_request_send(state, ev, wrepl_socket, &state->packet, NULL);
656         if (tevent_req_nomem(subreq, req)) {
657                 return tevent_req_post(req, ev);
658         }
659         tevent_req_set_callback(subreq, wrepl_associate_done, req);
660
661         return req;
662 }
663
664 static void wrepl_associate_done(struct tevent_req *subreq)
665 {
666         struct tevent_req *req = tevent_req_callback_data(subreq,
667                                  struct tevent_req);
668         struct wrepl_associate_state *state = tevent_req_data(req,
669                                               struct wrepl_associate_state);
670         NTSTATUS status;
671         struct wrepl_packet *packet;
672
673         status = wrepl_request_recv(subreq, state, &packet);
674         TALLOC_FREE(subreq);
675         if (!NT_STATUS_IS_OK(status)) {
676                 tevent_req_nterror(req, status);
677                 return;
678         }
679
680         if (packet->mess_type != WREPL_START_ASSOCIATION_REPLY) {
681                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
682                 return;
683         }
684
685         state->assoc_ctx = packet->message.start_reply.assoc_ctx;
686         state->major_version = packet->message.start_reply.major_version;
687
688         tevent_req_done(req);
689 }
690
691 /*
692   setup an association - recv
693 */
694 NTSTATUS wrepl_associate_recv(struct tevent_req *req,
695                               struct wrepl_associate *io)
696 {
697         struct wrepl_associate_state *state = tevent_req_data(req,
698                                               struct wrepl_associate_state);
699         NTSTATUS status;
700
701         if (tevent_req_is_nterror(req, &status)) {
702                 tevent_req_received(req);
703                 return status;
704         }
705
706         io->out.assoc_ctx = state->assoc_ctx;
707         io->out.major_version = state->major_version;
708
709         tevent_req_received(req);
710         return NT_STATUS_OK;
711 }
712
713 /*
714   setup an association - sync api
715 */
716 NTSTATUS wrepl_associate(struct wrepl_socket *wrepl_socket,
717                          struct wrepl_associate *io)
718 {
719         struct tevent_req *subreq;
720         bool ok;
721         NTSTATUS status;
722
723         subreq = wrepl_associate_send(wrepl_socket, wrepl_socket->event.ctx,
724                                       wrepl_socket, io);
725         NT_STATUS_HAVE_NO_MEMORY(subreq);
726
727         ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
728         if (!ok) {
729                 TALLOC_FREE(subreq);
730                 return NT_STATUS_INTERNAL_ERROR;
731         }
732
733         status = wrepl_associate_recv(subreq, io);
734         TALLOC_FREE(subreq);
735         NT_STATUS_NOT_OK_RETURN(status);
736
737         return NT_STATUS_OK;
738 }
739
740 struct wrepl_associate_stop_state {
741         struct wrepl_packet packet;
742         struct wrepl_send_ctrl ctrl;
743 };
744
745 static void wrepl_associate_stop_done(struct tevent_req *subreq);
746
747 struct tevent_req *wrepl_associate_stop_send(TALLOC_CTX *mem_ctx,
748                                              struct tevent_context *ev,
749                                              struct wrepl_socket *wrepl_socket,
750                                              const struct wrepl_associate_stop *io)
751 {
752         struct tevent_req *req;
753         struct wrepl_associate_stop_state *state;
754         struct tevent_req *subreq;
755
756         if (wrepl_socket->event.ctx != ev) {
757                 /* TODO: remove wrepl_socket->event.ctx !!! */
758                 smb_panic("wrepl_associate_stop_send event context mismatch!");
759                 return NULL;
760         }
761
762         req = tevent_req_create(mem_ctx, &state,
763                                 struct wrepl_associate_stop_state);
764         if (req == NULL) {
765                 return NULL;
766         };
767
768         state->packet.opcode                    = WREPL_OPCODE_BITS;
769         state->packet.assoc_ctx                 = io->in.assoc_ctx;
770         state->packet.mess_type                 = WREPL_STOP_ASSOCIATION;
771         state->packet.message.stop.reason       = io->in.reason;
772
773         if (io->in.reason == 0) {
774                 state->ctrl.send_only                   = true;
775                 state->ctrl.disconnect_after_send       = true;
776         }
777
778         subreq = wrepl_request_send(state, ev, wrepl_socket, &state->packet, &state->ctrl);
779         if (tevent_req_nomem(subreq, req)) {
780                 return tevent_req_post(req, ev);
781         }
782         tevent_req_set_callback(subreq, wrepl_associate_stop_done, req);
783
784         return req;
785 }
786
787 static void wrepl_associate_stop_done(struct tevent_req *subreq)
788 {
789         struct tevent_req *req = tevent_req_callback_data(subreq,
790                                  struct tevent_req);
791         struct wrepl_associate_stop_state *state = tevent_req_data(req,
792                                                    struct wrepl_associate_stop_state);
793         NTSTATUS status;
794
795         /* currently we don't care about a possible response */
796         status = wrepl_request_recv(subreq, state, NULL);
797         TALLOC_FREE(subreq);
798         if (!NT_STATUS_IS_OK(status)) {
799                 tevent_req_nterror(req, status);
800                 return;
801         }
802
803         tevent_req_done(req);
804 }
805
806 /*
807   stop an association - recv
808 */
809 NTSTATUS wrepl_associate_stop_recv(struct tevent_req *req,
810                                    struct wrepl_associate_stop *io)
811 {
812         NTSTATUS status;
813
814         if (tevent_req_is_nterror(req, &status)) {
815                 tevent_req_received(req);
816                 return status;
817         }
818
819         tevent_req_received(req);
820         return NT_STATUS_OK;
821 }
822
823 /*
824   setup an association - sync api
825 */
826 NTSTATUS wrepl_associate_stop(struct wrepl_socket *wrepl_socket,
827                               struct wrepl_associate_stop *io)
828 {
829         struct tevent_req *subreq;
830         bool ok;
831         NTSTATUS status;
832
833         subreq = wrepl_associate_stop_send(wrepl_socket, wrepl_socket->event.ctx,
834                                            wrepl_socket, io);
835         NT_STATUS_HAVE_NO_MEMORY(subreq);
836
837         ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
838         if (!ok) {
839                 TALLOC_FREE(subreq);
840                 return NT_STATUS_INTERNAL_ERROR;
841         }
842
843         status = wrepl_associate_stop_recv(subreq, io);
844         TALLOC_FREE(subreq);
845         NT_STATUS_NOT_OK_RETURN(status);
846
847         return NT_STATUS_OK;
848 }
849
850 struct wrepl_pull_table_state {
851         struct wrepl_packet packet;
852         uint32_t num_partners;
853         struct wrepl_wins_owner *partners;
854 };
855
856 static void wrepl_pull_table_done(struct tevent_req *subreq);
857
858 struct tevent_req *wrepl_pull_table_send(TALLOC_CTX *mem_ctx,
859                                          struct tevent_context *ev,
860                                          struct wrepl_socket *wrepl_socket,
861                                          const struct wrepl_pull_table *io)
862 {
863         struct tevent_req *req;
864         struct wrepl_pull_table_state *state;
865         struct tevent_req *subreq;
866
867         if (wrepl_socket->event.ctx != ev) {
868                 /* TODO: remove wrepl_socket->event.ctx !!! */
869                 smb_panic("wrepl_pull_table_send event context mismatch!");
870                 return NULL;
871         }
872
873         req = tevent_req_create(mem_ctx, &state,
874                                 struct wrepl_pull_table_state);
875         if (req == NULL) {
876                 return NULL;
877         };
878
879         state->packet.opcode                            = WREPL_OPCODE_BITS;
880         state->packet.assoc_ctx                         = io->in.assoc_ctx;
881         state->packet.mess_type                         = WREPL_REPLICATION;
882         state->packet.message.replication.command       = WREPL_REPL_TABLE_QUERY;
883
884         subreq = wrepl_request_send(state, ev, wrepl_socket, &state->packet, NULL);
885         if (tevent_req_nomem(subreq, req)) {
886                 return tevent_req_post(req, ev);
887         }
888         tevent_req_set_callback(subreq, wrepl_pull_table_done, req);
889
890         return req;
891 }
892
893 static void wrepl_pull_table_done(struct tevent_req *subreq)
894 {
895         struct tevent_req *req = tevent_req_callback_data(subreq,
896                                  struct tevent_req);
897         struct wrepl_pull_table_state *state = tevent_req_data(req,
898                                                struct wrepl_pull_table_state);
899         NTSTATUS status;
900         struct wrepl_packet *packet;
901         struct wrepl_table *table;
902
903         status = wrepl_request_recv(subreq, state, &packet);
904         TALLOC_FREE(subreq);
905         if (!NT_STATUS_IS_OK(status)) {
906                 tevent_req_nterror(req, status);
907                 return;
908         }
909
910         if (packet->mess_type != WREPL_REPLICATION) {
911                 tevent_req_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
912                 return;
913         }
914
915         if (packet->message.replication.command != WREPL_REPL_TABLE_REPLY) {
916                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
917                 return;
918         }
919
920         table = &packet->message.replication.info.table;
921
922         state->num_partners = table->partner_count;
923         state->partners = talloc_move(state, &table->partners);
924
925         tevent_req_done(req);
926 }
927
928 /*
929   fetch the partner tables - recv
930 */
931 NTSTATUS wrepl_pull_table_recv(struct tevent_req *req,
932                                TALLOC_CTX *mem_ctx,
933                                struct wrepl_pull_table *io)
934 {
935         struct wrepl_pull_table_state *state = tevent_req_data(req,
936                                                struct wrepl_pull_table_state);
937         NTSTATUS status;
938
939         if (tevent_req_is_nterror(req, &status)) {
940                 tevent_req_received(req);
941                 return status;
942         }
943
944         io->out.num_partners = state->num_partners;
945         io->out.partners = talloc_move(mem_ctx, &state->partners);
946
947         tevent_req_received(req);
948         return NT_STATUS_OK;
949 }
950
951 /*
952   fetch the partner table - sync api
953 */
954 NTSTATUS wrepl_pull_table(struct wrepl_socket *wrepl_socket,
955                           TALLOC_CTX *mem_ctx,
956                           struct wrepl_pull_table *io)
957 {
958         struct tevent_req *subreq;
959         bool ok;
960         NTSTATUS status;
961
962         subreq = wrepl_pull_table_send(mem_ctx, wrepl_socket->event.ctx,
963                                        wrepl_socket, io);
964         NT_STATUS_HAVE_NO_MEMORY(subreq);
965
966         ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
967         if (!ok) {
968                 TALLOC_FREE(subreq);
969                 return NT_STATUS_INTERNAL_ERROR;
970         }
971
972         status = wrepl_pull_table_recv(subreq, mem_ctx, io);
973         TALLOC_FREE(subreq);
974         NT_STATUS_NOT_OK_RETURN(status);
975
976         return NT_STATUS_OK;
977 }
978
979
980 struct wrepl_pull_names_state {
981         struct {
982                 const struct wrepl_pull_names *io;
983         } caller;
984         struct wrepl_packet packet;
985         uint32_t num_names;
986         struct wrepl_name *names;
987 };
988
989 static void wrepl_pull_names_done(struct tevent_req *subreq);
990
991 struct tevent_req *wrepl_pull_names_send(TALLOC_CTX *mem_ctx,
992                                          struct tevent_context *ev,
993                                          struct wrepl_socket *wrepl_socket,
994                                          const struct wrepl_pull_names *io)
995 {
996         struct tevent_req *req;
997         struct wrepl_pull_names_state *state;
998         struct tevent_req *subreq;
999
1000         if (wrepl_socket->event.ctx != ev) {
1001                 /* TODO: remove wrepl_socket->event.ctx !!! */
1002                 smb_panic("wrepl_pull_names_send event context mismatch!");
1003                 return NULL;
1004         }
1005
1006         req = tevent_req_create(mem_ctx, &state,
1007                                 struct wrepl_pull_names_state);
1008         if (req == NULL) {
1009                 return NULL;
1010         };
1011         state->caller.io = io;
1012
1013         state->packet.opcode                            = WREPL_OPCODE_BITS;
1014         state->packet.assoc_ctx                         = io->in.assoc_ctx;
1015         state->packet.mess_type                         = WREPL_REPLICATION;
1016         state->packet.message.replication.command       = WREPL_REPL_SEND_REQUEST;
1017         state->packet.message.replication.info.owner    = io->in.partner;
1018
1019         subreq = wrepl_request_send(state, ev, wrepl_socket, &state->packet, NULL);
1020         if (tevent_req_nomem(subreq, req)) {
1021                 return tevent_req_post(req, ev);
1022         }
1023         tevent_req_set_callback(subreq, wrepl_pull_names_done, req);
1024
1025         return req;
1026 }
1027
1028 static void wrepl_pull_names_done(struct tevent_req *subreq)
1029 {
1030         struct tevent_req *req = tevent_req_callback_data(subreq,
1031                                  struct tevent_req);
1032         struct wrepl_pull_names_state *state = tevent_req_data(req,
1033                                                struct wrepl_pull_names_state);
1034         NTSTATUS status;
1035         struct wrepl_packet *packet;
1036         uint32_t i;
1037
1038         status = wrepl_request_recv(subreq, state, &packet);
1039         TALLOC_FREE(subreq);
1040         if (!NT_STATUS_IS_OK(status)) {
1041                 tevent_req_nterror(req, status);
1042                 return;
1043         }
1044
1045         if (packet->mess_type != WREPL_REPLICATION) {
1046                 tevent_req_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
1047                 return;
1048         }
1049
1050         if (packet->message.replication.command != WREPL_REPL_SEND_REPLY) {
1051                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1052                 return;
1053         }
1054
1055         state->num_names = packet->message.replication.info.reply.num_names;
1056
1057         state->names = talloc_array(state, struct wrepl_name, state->num_names);
1058         if (tevent_req_nomem(state->names, req)) {
1059                 return;
1060         }
1061
1062         /* convert the list of names and addresses to a sane format */
1063         for (i=0; i < state->num_names; i++) {
1064                 struct wrepl_wins_name *wname = &packet->message.replication.info.reply.names[i];
1065                 struct wrepl_name *name = &state->names[i];
1066
1067                 name->name      = *wname->name;
1068                 talloc_steal(state->names, wname->name);
1069                 name->type      = WREPL_NAME_TYPE(wname->flags);
1070                 name->state     = WREPL_NAME_STATE(wname->flags);
1071                 name->node      = WREPL_NAME_NODE(wname->flags);
1072                 name->is_static = WREPL_NAME_IS_STATIC(wname->flags);
1073                 name->raw_flags = wname->flags;
1074                 name->version_id= wname->id;
1075                 name->owner     = talloc_strdup(state->names,
1076                                                 state->caller.io->in.partner.address);
1077                 if (tevent_req_nomem(name->owner, req)) {
1078                         return;
1079                 }
1080
1081                 /* trying to save 1 or 2 bytes on the wire isn't a good idea */
1082                 if (wname->flags & 2) {
1083                         uint32_t j;
1084
1085                         name->num_addresses = wname->addresses.addresses.num_ips;
1086                         name->addresses = talloc_array(state->names,
1087                                                        struct wrepl_address,
1088                                                        name->num_addresses);
1089                         if (tevent_req_nomem(name->addresses, req)) {
1090                                 return;
1091                         }
1092
1093                         for (j=0;j<name->num_addresses;j++) {
1094                                 name->addresses[j].owner =
1095                                         talloc_move(name->addresses,
1096                                                     &wname->addresses.addresses.ips[j].owner);
1097                                 name->addresses[j].address = 
1098                                         talloc_move(name->addresses,
1099                                                     &wname->addresses.addresses.ips[j].ip);
1100                         }
1101                 } else {
1102                         name->num_addresses = 1;
1103                         name->addresses = talloc_array(state->names,
1104                                                        struct wrepl_address,
1105                                                        name->num_addresses);
1106                         if (tevent_req_nomem(name->addresses, req)) {
1107                                 return;
1108                         }
1109
1110                         name->addresses[0].owner = talloc_strdup(name->addresses, name->owner);
1111                         if (tevent_req_nomem(name->addresses[0].owner, req)) {
1112                                 return;
1113                         }
1114                         name->addresses[0].address = talloc_move(name->addresses,
1115                                                                  &wname->addresses.ip);
1116                 }
1117         }
1118
1119         tevent_req_done(req);
1120 }
1121
1122 /*
1123   fetch the names for a WINS partner - recv
1124 */
1125 NTSTATUS wrepl_pull_names_recv(struct tevent_req *req,
1126                                TALLOC_CTX *mem_ctx,
1127                                struct wrepl_pull_names *io)
1128 {
1129         struct wrepl_pull_names_state *state = tevent_req_data(req,
1130                                                struct wrepl_pull_names_state);
1131         NTSTATUS status;
1132
1133         if (tevent_req_is_nterror(req, &status)) {
1134                 tevent_req_received(req);
1135                 return status;
1136         }
1137
1138         io->out.num_names = state->num_names;
1139         io->out.names = talloc_move(mem_ctx, &state->names);
1140
1141         tevent_req_received(req);
1142         return NT_STATUS_OK;
1143 }
1144
1145
1146
1147 /*
1148   fetch the names for a WINS partner - sync api
1149 */
1150 NTSTATUS wrepl_pull_names(struct wrepl_socket *wrepl_socket,
1151                           TALLOC_CTX *mem_ctx,
1152                           struct wrepl_pull_names *io)
1153 {
1154         struct tevent_req *subreq;
1155         bool ok;
1156         NTSTATUS status;
1157
1158         subreq = wrepl_pull_names_send(mem_ctx, wrepl_socket->event.ctx,
1159                                        wrepl_socket, io);
1160         NT_STATUS_HAVE_NO_MEMORY(subreq);
1161
1162         ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
1163         if (!ok) {
1164                 TALLOC_FREE(subreq);
1165                 return NT_STATUS_INTERNAL_ERROR;
1166         }
1167
1168         status = wrepl_pull_names_recv(subreq, mem_ctx, io);
1169         TALLOC_FREE(subreq);
1170         NT_STATUS_NOT_OK_RETURN(status);
1171
1172         return NT_STATUS_OK;
1173 }