s4:libcli/wrepl: add wrepl_socket_is_connected()
[sfrench/samba-autobuild/.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 "lib/socket/socket.h"
27 #include "libcli/wrepl/winsrepl.h"
28 #include "librpc/gen_ndr/ndr_winsrepl.h"
29 #include "lib/stream/packet.h"
30 #include "libcli/composite/composite.h"
31 #include "system/network.h"
32 #include "lib/socket/netif.h"
33 #include "param/param.h"
34 #include "lib/util/tevent_ntstatus.h"
35
36 enum wrepl_request_internal_state {
37         WREPL_REQUEST_INIT  = 0,
38         WREPL_REQUEST_RECV  = 1,
39         WREPL_REQUEST_DONE  = 2,
40         WREPL_REQUEST_ERROR = 3
41 };
42
43 /*
44   a WINS replication request
45 */
46 struct wrepl_request {
47         struct wrepl_request *next, *prev;
48         struct wrepl_socket *wrepl_socket;
49
50         enum wrepl_request_internal_state state;
51         bool trigger;
52         NTSTATUS status;
53
54         struct tevent_timer *te;
55
56         struct wrepl_packet *packet;
57
58         struct {
59                 void (*fn)(struct wrepl_request *);
60                 void *private_data;
61         } async;
62 };
63
64 static struct wrepl_request *wrepl_request_finished(struct wrepl_request *req, NTSTATUS status);
65
66 /*
67   mark all pending requests as dead - called when a socket error happens
68 */
69 static void wrepl_socket_dead(struct wrepl_socket *wrepl_socket, NTSTATUS status)
70 {
71         wrepl_socket->dead = true;
72
73         if (wrepl_socket->packet) {
74                 packet_recv_disable(wrepl_socket->packet);
75                 packet_set_fde(wrepl_socket->packet, NULL);
76                 packet_set_socket(wrepl_socket->packet, NULL);
77         }
78
79         if (wrepl_socket->event.fde) {
80                 talloc_free(wrepl_socket->event.fde);
81                 wrepl_socket->event.fde = NULL;
82         }
83
84         if (wrepl_socket->sock) {
85                 talloc_free(wrepl_socket->sock);
86                 wrepl_socket->sock = NULL;
87         }
88
89         if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
90                 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
91         }
92         while (wrepl_socket->recv_queue) {
93                 struct wrepl_request *req = wrepl_socket->recv_queue;
94                 DLIST_REMOVE(wrepl_socket->recv_queue, req);
95                 wrepl_request_finished(req, status);
96         }
97
98         talloc_set_destructor(wrepl_socket, NULL);
99         if (wrepl_socket->free_skipped) {
100                 talloc_free(wrepl_socket);
101         }
102 }
103
104 bool wrepl_socket_is_connected(struct wrepl_socket *wrepl_sock)
105 {
106         if (!wrepl_sock) {
107                 return false;
108         }
109
110         if (wrepl_sock->dead) {
111                 return false;
112         }
113
114         if (!wrepl_sock->sock) {
115                 return false;
116         }
117
118         return true;
119 }
120
121 static void wrepl_request_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
122                                           struct timeval t, void *ptr)
123 {
124         struct wrepl_request *req = talloc_get_type(ptr, struct wrepl_request);
125         wrepl_socket_dead(req->wrepl_socket, NT_STATUS_IO_TIMEOUT);
126 }
127
128 /*
129   handle recv events 
130 */
131 static NTSTATUS wrepl_finish_recv(void *private_data, DATA_BLOB packet_blob_in)
132 {
133         struct wrepl_socket *wrepl_socket = talloc_get_type(private_data, struct wrepl_socket);
134         struct wrepl_request *req = wrepl_socket->recv_queue;
135         DATA_BLOB blob;
136         enum ndr_err_code ndr_err;
137
138         if (!req) {
139                 DEBUG(1,("Received unexpected WINS packet of length %u!\n", 
140                          (unsigned)packet_blob_in.length));
141                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
142         }
143
144         req->packet = talloc(req, struct wrepl_packet);
145         NT_STATUS_HAVE_NO_MEMORY(req->packet);
146
147         blob.data = packet_blob_in.data + 4;
148         blob.length = packet_blob_in.length - 4;
149         
150         /* we have a full request - parse it */
151         ndr_err = ndr_pull_struct_blob(&blob, req->packet, wrepl_socket->iconv_convenience, req->packet,
152                                        (ndr_pull_flags_fn_t)ndr_pull_wrepl_packet);
153         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
154                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
155                 wrepl_request_finished(req, status);
156                 return NT_STATUS_OK;
157         }
158
159         if (DEBUGLVL(10)) {
160                 DEBUG(10,("Received WINS packet of length %u\n", 
161                           (unsigned)packet_blob_in.length));
162                 NDR_PRINT_DEBUG(wrepl_packet, req->packet);
163         }
164
165         wrepl_request_finished(req, NT_STATUS_OK);
166         return NT_STATUS_OK;
167 }
168
169 /*
170   handler for winrepl events
171 */
172 static void wrepl_handler(struct tevent_context *ev, struct tevent_fd *fde, 
173                           uint16_t flags, void *private_data)
174 {
175         struct wrepl_socket *wrepl_socket = talloc_get_type(private_data,
176                                                             struct wrepl_socket);
177         if (flags & EVENT_FD_READ) {
178                 packet_recv(wrepl_socket->packet);
179                 return;
180         }
181         if (flags & EVENT_FD_WRITE) {
182                 packet_queue_run(wrepl_socket->packet);
183         }
184 }
185
186 static void wrepl_error(void *private_data, NTSTATUS status)
187 {
188         struct wrepl_socket *wrepl_socket = talloc_get_type(private_data,
189                                                             struct wrepl_socket);
190         wrepl_socket_dead(wrepl_socket, status);
191 }
192
193
194 /*
195   destroy a wrepl_socket destructor
196 */
197 static int wrepl_socket_destructor(struct wrepl_socket *sock)
198 {
199         if (sock->dead) {
200                 sock->free_skipped = true;
201                 return -1;
202         }
203         wrepl_socket_dead(sock, NT_STATUS_LOCAL_DISCONNECT);
204         return 0;
205 }
206
207 /*
208   initialise a wrepl_socket. The event_ctx is optional, if provided then
209   operations will use that event context
210 */
211 struct wrepl_socket *wrepl_socket_init(TALLOC_CTX *mem_ctx, 
212                                        struct tevent_context *event_ctx,
213                                        struct smb_iconv_convenience *iconv_convenience)
214 {
215         struct wrepl_socket *wrepl_socket;
216         NTSTATUS status;
217
218         wrepl_socket = talloc_zero(mem_ctx, struct wrepl_socket);
219         if (!wrepl_socket) return NULL;
220
221         wrepl_socket->event.ctx = event_ctx;
222         if (!wrepl_socket->event.ctx) goto failed;
223
224         wrepl_socket->iconv_convenience = iconv_convenience;
225
226         status = socket_create("ip", SOCKET_TYPE_STREAM, &wrepl_socket->sock, 0);
227         if (!NT_STATUS_IS_OK(status)) goto failed;
228
229         talloc_steal(wrepl_socket, wrepl_socket->sock);
230
231         wrepl_socket->request_timeout   = WREPL_SOCKET_REQUEST_TIMEOUT;
232
233         talloc_set_destructor(wrepl_socket, wrepl_socket_destructor);
234
235         return wrepl_socket;
236
237 failed:
238         talloc_free(wrepl_socket);
239         return NULL;
240 }
241
242 /*
243   initialise a wrepl_socket from an already existing connection
244 */
245 struct wrepl_socket *wrepl_socket_merge(TALLOC_CTX *mem_ctx, 
246                                         struct tevent_context *event_ctx,
247                                         struct socket_context *sock,
248                                         struct packet_context *pack)
249 {
250         struct wrepl_socket *wrepl_socket;
251
252         wrepl_socket = talloc_zero(mem_ctx, struct wrepl_socket);
253         if (wrepl_socket == NULL) goto failed;
254
255         wrepl_socket->event.ctx = event_ctx;
256         if (wrepl_socket->event.ctx == NULL) goto failed;
257
258         wrepl_socket->sock = sock;
259         talloc_steal(wrepl_socket, wrepl_socket->sock);
260
261
262         wrepl_socket->request_timeout   = WREPL_SOCKET_REQUEST_TIMEOUT;
263
264         wrepl_socket->event.fde = event_add_fd(wrepl_socket->event.ctx, wrepl_socket,
265                                                socket_get_fd(wrepl_socket->sock), 
266                                                EVENT_FD_READ,
267                                                wrepl_handler, wrepl_socket);
268         if (wrepl_socket->event.fde == NULL) {
269                 goto failed;
270         }
271
272         wrepl_socket->packet = pack;
273         talloc_steal(wrepl_socket, wrepl_socket->packet);
274         packet_set_private(wrepl_socket->packet, wrepl_socket);
275         packet_set_socket(wrepl_socket->packet, wrepl_socket->sock);
276         packet_set_callback(wrepl_socket->packet, wrepl_finish_recv);
277         packet_set_full_request(wrepl_socket->packet, packet_full_request_u32);
278         packet_set_error_handler(wrepl_socket->packet, wrepl_error);
279         packet_set_event_context(wrepl_socket->packet, wrepl_socket->event.ctx);
280         packet_set_fde(wrepl_socket->packet, wrepl_socket->event.fde);
281         packet_set_serialise(wrepl_socket->packet);
282
283         talloc_set_destructor(wrepl_socket, wrepl_socket_destructor);
284         
285         return wrepl_socket;
286
287 failed:
288         talloc_free(wrepl_socket);
289         return NULL;
290 }
291
292 /*
293   destroy a wrepl_request
294 */
295 static int wrepl_request_destructor(struct wrepl_request *req)
296 {
297         if (req->state == WREPL_REQUEST_RECV) {
298                 DLIST_REMOVE(req->wrepl_socket->recv_queue, req);
299         }
300         req->state = WREPL_REQUEST_ERROR;
301         return 0;
302 }
303
304 /*
305   wait for a request to complete
306 */
307 static NTSTATUS wrepl_request_wait(struct wrepl_request *req)
308 {
309         NT_STATUS_HAVE_NO_MEMORY(req);
310         while (req->state < WREPL_REQUEST_DONE) {
311                 event_loop_once(req->wrepl_socket->event.ctx);
312         }
313         return req->status;
314 }
315
316 const char *wrepl_best_ip(struct loadparm_context *lp_ctx, const char *peer_ip)
317 {
318         struct interface *ifaces;
319         load_interfaces(lp_ctx, lp_interfaces(lp_ctx), &ifaces);
320         return iface_best_ip(ifaces, peer_ip);
321 }
322
323 struct wrepl_connect_state {
324         struct wrepl_socket *wrepl_socket;
325 };
326
327 static void wrepl_connect_handler(struct composite_context *creq);
328
329 struct tevent_req *wrepl_connect_send(TALLOC_CTX *mem_ctx,
330                                       struct tevent_context *ev,
331                                       struct wrepl_socket *wrepl_socket,
332                                       const char *our_ip, const char *peer_ip)
333 {
334         struct tevent_req *req;
335         struct wrepl_connect_state *state;
336         struct composite_context *subreq;
337         struct socket_address *peer, *us;
338
339         req = tevent_req_create(mem_ctx, &state,
340                                 struct wrepl_connect_state);
341         if (req == NULL) {
342                 return NULL;
343         }
344
345         state->wrepl_socket     = wrepl_socket;
346
347         us = socket_address_from_strings(state, wrepl_socket->sock->backend_name,
348                                          our_ip, 0);
349         if (tevent_req_nomem(us, req)) {
350                 return tevent_req_post(req, ev);
351         }
352
353         peer = socket_address_from_strings(state, wrepl_socket->sock->backend_name,
354                                            peer_ip, WINS_REPLICATION_PORT);
355         if (tevent_req_nomem(peer, req)) {
356                 return tevent_req_post(req, ev);
357         }
358
359         subreq = socket_connect_send(wrepl_socket->sock, us, peer,
360                                      0, wrepl_socket->event.ctx);
361         if (tevent_req_nomem(subreq, req)) {
362                 return tevent_req_post(req, ev);
363         }
364
365         subreq->async.fn = wrepl_connect_handler;
366         subreq->async.private_data = req;
367
368         return req;
369 }
370
371 static void wrepl_connect_handler(struct composite_context *subreq)
372 {
373         struct tevent_req *req = talloc_get_type_abort(subreq->async.private_data,
374                                  struct tevent_req);
375         struct wrepl_connect_state *state = tevent_req_data(req,
376                                             struct wrepl_connect_state);
377         struct wrepl_socket *wrepl_socket = state->wrepl_socket;
378         NTSTATUS status;
379
380         status = socket_connect_recv(subreq);
381         if (!NT_STATUS_IS_OK(status)) {
382                 tevent_req_nterror(req, status);
383                 return;
384         }
385
386         wrepl_socket->event.fde = event_add_fd(wrepl_socket->event.ctx, wrepl_socket, 
387                                                socket_get_fd(wrepl_socket->sock), 
388                                                EVENT_FD_READ,
389                                                wrepl_handler, wrepl_socket);
390         if (tevent_req_nomem(wrepl_socket->event.fde, req)) {
391                 return;
392         }
393
394         /* setup the stream -> packet parser */
395         wrepl_socket->packet = packet_init(wrepl_socket);
396         if (tevent_req_nomem(wrepl_socket->packet, req)) {
397                 return;
398         }
399         packet_set_private(wrepl_socket->packet, wrepl_socket);
400         packet_set_socket(wrepl_socket->packet, wrepl_socket->sock);
401         packet_set_callback(wrepl_socket->packet, wrepl_finish_recv);
402         packet_set_full_request(wrepl_socket->packet, packet_full_request_u32);
403         packet_set_error_handler(wrepl_socket->packet, wrepl_error);
404         packet_set_event_context(wrepl_socket->packet, wrepl_socket->event.ctx);
405         packet_set_fde(wrepl_socket->packet, wrepl_socket->event.fde);
406         packet_set_serialise(wrepl_socket->packet);
407
408         tevent_req_done(req);
409 }
410
411 /*
412   connect a wrepl_socket to a WINS server - recv side
413 */
414 NTSTATUS wrepl_connect_recv(struct tevent_req *req)
415 {
416         struct wrepl_connect_state *state = tevent_req_data(req,
417                                             struct wrepl_connect_state);
418         struct wrepl_socket *wrepl_socket = state->wrepl_socket;
419         NTSTATUS status;
420
421         if (tevent_req_is_nterror(req, &status)) {
422                 wrepl_socket_dead(wrepl_socket, status);
423                 tevent_req_received(req);
424                 return status;
425         }
426
427         tevent_req_received(req);
428         return NT_STATUS_OK;
429 }
430
431 /*
432   connect a wrepl_socket to a WINS server - sync API
433 */
434 NTSTATUS wrepl_connect(struct wrepl_socket *wrepl_socket,
435                        const char *our_ip, const char *peer_ip)
436 {
437         struct tevent_req *subreq;
438         bool ok;
439         NTSTATUS status;
440
441         subreq = wrepl_connect_send(wrepl_socket, wrepl_socket->event.ctx,
442                                     wrepl_socket, our_ip, peer_ip);
443         NT_STATUS_HAVE_NO_MEMORY(subreq);
444
445         ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
446         if (!ok) {
447                 TALLOC_FREE(subreq);
448                 return NT_STATUS_INTERNAL_ERROR;
449         }
450
451         status = wrepl_connect_recv(subreq);
452         TALLOC_FREE(subreq);
453         NT_STATUS_NOT_OK_RETURN(status);
454
455         return NT_STATUS_OK;
456 }
457
458 /* 
459    callback from wrepl_request_trigger() 
460 */
461 static void wrepl_request_trigger_handler(struct tevent_context *ev, struct tevent_timer *te,
462                                           struct timeval t, void *ptr)
463 {
464         struct wrepl_request *req = talloc_get_type(ptr, struct wrepl_request);
465         if (req->async.fn) {
466                 req->async.fn(req);
467         }
468 }
469
470 /*
471   trigger an immediate event on a wrepl_request
472   the return value should only be used in wrepl_request_send()
473   this is the only place where req->trigger is true
474 */
475 static struct wrepl_request *wrepl_request_finished(struct wrepl_request *req, NTSTATUS status)
476 {
477         struct tevent_timer *te;
478
479         if (req->state == WREPL_REQUEST_RECV) {
480                 DLIST_REMOVE(req->wrepl_socket->recv_queue, req);
481         }
482
483         if (!NT_STATUS_IS_OK(status)) {
484                 req->state      = WREPL_REQUEST_ERROR;
485         } else {
486                 req->state      = WREPL_REQUEST_DONE;
487         }
488
489         req->status     = status;
490
491         if (req->trigger) {
492                 req->trigger = false;
493                 /* a zero timeout means immediate */
494                 te = event_add_timed(req->wrepl_socket->event.ctx,
495                                      req, timeval_zero(),
496                                      wrepl_request_trigger_handler, req);
497                 if (!te) {
498                         talloc_free(req);
499                         return NULL;
500                 }
501                 return req;
502         }
503
504         if (req->async.fn) {
505                 req->async.fn(req);
506         }
507         return NULL;
508 }
509
510 struct wrepl_send_ctrl_state {
511         struct wrepl_send_ctrl ctrl;
512         struct wrepl_request *req;
513         struct wrepl_socket *wrepl_sock;
514 };
515
516 static int wrepl_send_ctrl_destructor(struct wrepl_send_ctrl_state *s)
517 {
518         struct wrepl_request *req = s->wrepl_sock->recv_queue;
519
520         /* check if the request is still in WREPL_STATE_RECV,
521          * we need this here because the caller has may called 
522          * talloc_free(req) and wrepl_send_ctrl_state isn't
523          * a talloc child of the request, so our s->req pointer
524          * is maybe invalid!
525          */
526         for (; req; req = req->next) {
527                 if (req == s->req) break;
528         }
529         if (!req) return 0;
530
531         /* here, we need to make sure the async request handler is called
532          * later in the next event_loop and now now
533          */
534         req->trigger = true;
535         wrepl_request_finished(req, NT_STATUS_OK);
536
537         if (s->ctrl.disconnect_after_send) {
538                 wrepl_socket_dead(s->wrepl_sock, NT_STATUS_LOCAL_DISCONNECT);
539         }
540
541         return 0;
542 }
543
544 /*
545   send a generic wins replication request
546 */
547 static struct wrepl_request *wrepl_request_internal_send(struct wrepl_socket *wrepl_socket,
548                                                          const struct wrepl_packet *packet,
549                                                          const struct wrepl_send_ctrl *ctrl)
550 {
551         struct wrepl_request *req;
552         struct wrepl_wrap wrap;
553         DATA_BLOB blob;
554         NTSTATUS status;
555         enum ndr_err_code ndr_err;
556
557         req = talloc_zero(wrepl_socket, struct wrepl_request);
558         if (!req) return NULL;
559         req->wrepl_socket = wrepl_socket;
560         req->state        = WREPL_REQUEST_RECV;
561         req->trigger      = true;
562
563         DLIST_ADD_END(wrepl_socket->recv_queue, req, struct wrepl_request *);
564         talloc_set_destructor(req, wrepl_request_destructor);
565
566         if (wrepl_socket->dead) {
567                 return wrepl_request_finished(req, NT_STATUS_INVALID_CONNECTION);
568         }
569
570         wrap.packet = *packet;
571         ndr_err = ndr_push_struct_blob(&blob, req, wrepl_socket->iconv_convenience, &wrap, 
572                                        (ndr_push_flags_fn_t)ndr_push_wrepl_wrap);
573         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
574                 status = ndr_map_error2ntstatus(ndr_err);
575                 return wrepl_request_finished(req, status);
576         }
577
578         if (DEBUGLVL(10)) {
579                 DEBUG(10,("Sending WINS packet of length %u\n", 
580                           (unsigned)blob.length));
581                 NDR_PRINT_DEBUG(wrepl_packet, &wrap.packet);
582         }
583
584         if (wrepl_socket->request_timeout > 0) {
585                 req->te = event_add_timed(wrepl_socket->event.ctx, req, 
586                                           timeval_current_ofs(wrepl_socket->request_timeout, 0), 
587                                           wrepl_request_timeout_handler, req);
588                 if (!req->te) return wrepl_request_finished(req, NT_STATUS_NO_MEMORY);
589         }
590
591         if (ctrl && (ctrl->send_only || ctrl->disconnect_after_send)) {
592                 struct wrepl_send_ctrl_state *s = talloc(blob.data, struct wrepl_send_ctrl_state);
593                 if (!s) return wrepl_request_finished(req, NT_STATUS_NO_MEMORY);
594                 s->ctrl         = *ctrl;
595                 s->req          = req;
596                 s->wrepl_sock   = wrepl_socket;
597                 talloc_set_destructor(s, wrepl_send_ctrl_destructor);
598         }
599
600         status = packet_send(wrepl_socket->packet, blob);
601         if (!NT_STATUS_IS_OK(status)) {
602                 return wrepl_request_finished(req, status);
603         }
604
605         req->trigger = false;
606         return req;
607 }
608
609 /*
610   receive a generic WINS replication reply
611 */
612 static NTSTATUS wrepl_request_internal_recv(struct wrepl_request *req,
613                                             TALLOC_CTX *mem_ctx,
614                                             struct wrepl_packet **packet)
615 {
616         NTSTATUS status = wrepl_request_wait(req);
617         if (NT_STATUS_IS_OK(status) && packet) {
618                 *packet = talloc_steal(mem_ctx, req->packet);
619         }
620         talloc_free(req);
621         return status;
622 }
623
624 struct wrepl_request_state {
625         struct wrepl_packet *packet;
626 };
627
628 static void wrepl_request_done(struct wrepl_request *subreq);
629
630 struct tevent_req *wrepl_request_send(TALLOC_CTX *mem_ctx,
631                                       struct tevent_context *ev,
632                                       struct wrepl_socket *wrepl_socket,
633                                       const struct wrepl_packet *packet,
634                                       const struct wrepl_send_ctrl *ctrl)
635 {
636         struct tevent_req *req;
637         struct wrepl_request_state *state;
638         struct wrepl_request *subreq;
639
640         if (wrepl_socket->event.ctx != ev) {
641                 /* TODO: remove wrepl_socket->event.ctx !!! */
642                 smb_panic("wrepl_associate_stop_send event context mismatch!");
643                 return NULL;
644         }
645
646         req = tevent_req_create(mem_ctx, &state,
647                                 struct wrepl_request_state);
648         if (req == NULL) {
649                 return NULL;
650         }
651
652         subreq = wrepl_request_internal_send(wrepl_socket, packet, ctrl);
653         if (tevent_req_nomem(subreq, req)) {
654                 return tevent_req_post(req, ev);
655         }
656         subreq->async.fn = wrepl_request_done;
657         subreq->async.private_data = req;
658
659         return req;
660 }
661
662 static void wrepl_request_done(struct wrepl_request *subreq)
663 {
664         struct tevent_req *req = talloc_get_type_abort(subreq->async.private_data,
665                                  struct tevent_req);
666         struct wrepl_request_state *state = tevent_req_data(req,
667                                             struct wrepl_request_state);
668         NTSTATUS status;
669
670         status = wrepl_request_internal_recv(subreq, state, &state->packet);
671         if (!NT_STATUS_IS_OK(status)) {
672                 tevent_req_nterror(req, status);
673                 return;
674         }
675
676         tevent_req_done(req);
677 }
678
679 NTSTATUS wrepl_request_recv(struct tevent_req *req,
680                             TALLOC_CTX *mem_ctx,
681                             struct wrepl_packet **packet)
682 {
683         struct wrepl_request_state *state = tevent_req_data(req,
684                                             struct wrepl_request_state);
685         NTSTATUS status;
686
687         if (tevent_req_is_nterror(req, &status)) {
688                 tevent_req_received(req);
689                 return status;
690         }
691
692         if (packet) {
693                 *packet = talloc_move(mem_ctx, &state->packet);
694         }
695
696         tevent_req_received(req);
697         return NT_STATUS_OK;
698 }
699
700 /*
701   a full WINS replication request/response
702 */
703 NTSTATUS wrepl_request(struct wrepl_socket *wrepl_socket,
704                        TALLOC_CTX *mem_ctx,
705                        const struct wrepl_packet *req_packet,
706                        struct wrepl_packet **reply_packet)
707 {
708         struct tevent_req *subreq;
709         bool ok;
710         NTSTATUS status;
711
712         subreq = wrepl_request_send(mem_ctx, wrepl_socket->event.ctx,
713                                     wrepl_socket, req_packet, NULL);
714         NT_STATUS_HAVE_NO_MEMORY(subreq);
715
716         ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
717         if (!ok) {
718                 TALLOC_FREE(subreq);
719                 return NT_STATUS_INTERNAL_ERROR;
720         }
721
722         status = wrepl_request_recv(subreq, mem_ctx, reply_packet);
723         TALLOC_FREE(subreq);
724         NT_STATUS_NOT_OK_RETURN(status);
725
726         return NT_STATUS_OK;
727 }
728
729
730 struct wrepl_associate_state {
731         struct wrepl_packet packet;
732         uint32_t assoc_ctx;
733         uint16_t major_version;
734 };
735
736 static void wrepl_associate_done(struct tevent_req *subreq);
737
738 struct tevent_req *wrepl_associate_send(TALLOC_CTX *mem_ctx,
739                                         struct tevent_context *ev,
740                                         struct wrepl_socket *wrepl_socket,
741                                         const struct wrepl_associate *io)
742 {
743         struct tevent_req *req;
744         struct wrepl_associate_state *state;
745         struct tevent_req *subreq;
746
747         if (wrepl_socket->event.ctx != ev) {
748                 /* TODO: remove wrepl_socket->event.ctx !!! */
749                 smb_panic("wrepl_associate_send event context mismatch!");
750                 return NULL;
751         }
752
753         req = tevent_req_create(mem_ctx, &state,
754                                 struct wrepl_associate_state);
755         if (req == NULL) {
756                 return NULL;
757         };
758
759         state->packet.opcode                            = WREPL_OPCODE_BITS;
760         state->packet.mess_type                         = WREPL_START_ASSOCIATION;
761         state->packet.message.start.minor_version       = 2;
762         state->packet.message.start.major_version       = 5;
763
764         /*
765          * nt4 uses 41 bytes for the start_association call
766          * so do it the same and as we don't know th emeanings of this bytes
767          * we just send zeros and nt4, w2k and w2k3 seems to be happy with this
768          *
769          * if we don't do this nt4 uses an old version of the wins replication protocol
770          * and that would break nt4 <-> samba replication
771          */
772         state->packet.padding   = data_blob_talloc(state, NULL, 21);
773         if (tevent_req_nomem(state->packet.padding.data, req)) {
774                 return tevent_req_post(req, ev);
775         }
776         memset(state->packet.padding.data, 0, state->packet.padding.length);
777
778         subreq = wrepl_request_send(state, ev, wrepl_socket, &state->packet, NULL);
779         if (tevent_req_nomem(subreq, req)) {
780                 return tevent_req_post(req, ev);
781         }
782         tevent_req_set_callback(subreq, wrepl_associate_done, req);
783
784         return req;
785 }
786
787 static void wrepl_associate_done(struct tevent_req *subreq)
788 {
789         struct tevent_req *req = tevent_req_callback_data(subreq,
790                                  struct tevent_req);
791         struct wrepl_associate_state *state = tevent_req_data(req,
792                                               struct wrepl_associate_state);
793         NTSTATUS status;
794         struct wrepl_packet *packet;
795
796         status = wrepl_request_recv(subreq, state, &packet);
797         TALLOC_FREE(subreq);
798         if (!NT_STATUS_IS_OK(status)) {
799                 tevent_req_nterror(req, status);
800                 return;
801         }
802
803         if (packet->mess_type != WREPL_START_ASSOCIATION_REPLY) {
804                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
805                 return;
806         }
807
808         state->assoc_ctx = packet->message.start_reply.assoc_ctx;
809         state->major_version = packet->message.start_reply.major_version;
810
811         tevent_req_done(req);
812 }
813
814 /*
815   setup an association - recv
816 */
817 NTSTATUS wrepl_associate_recv(struct tevent_req *req,
818                               struct wrepl_associate *io)
819 {
820         struct wrepl_associate_state *state = tevent_req_data(req,
821                                               struct wrepl_associate_state);
822         NTSTATUS status;
823
824         if (tevent_req_is_nterror(req, &status)) {
825                 tevent_req_received(req);
826                 return status;
827         }
828
829         io->out.assoc_ctx = state->assoc_ctx;
830         io->out.major_version = state->major_version;
831
832         tevent_req_received(req);
833         return NT_STATUS_OK;
834 }
835
836 /*
837   setup an association - sync api
838 */
839 NTSTATUS wrepl_associate(struct wrepl_socket *wrepl_socket,
840                          struct wrepl_associate *io)
841 {
842         struct tevent_req *subreq;
843         bool ok;
844         NTSTATUS status;
845
846         subreq = wrepl_associate_send(wrepl_socket, wrepl_socket->event.ctx,
847                                       wrepl_socket, io);
848         NT_STATUS_HAVE_NO_MEMORY(subreq);
849
850         ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
851         if (!ok) {
852                 TALLOC_FREE(subreq);
853                 return NT_STATUS_INTERNAL_ERROR;
854         }
855
856         status = wrepl_associate_recv(subreq, io);
857         TALLOC_FREE(subreq);
858         NT_STATUS_NOT_OK_RETURN(status);
859
860         return NT_STATUS_OK;
861 }
862
863 struct wrepl_associate_stop_state {
864         struct wrepl_packet packet;
865         struct wrepl_send_ctrl ctrl;
866 };
867
868 static void wrepl_associate_stop_done(struct tevent_req *subreq);
869
870 struct tevent_req *wrepl_associate_stop_send(TALLOC_CTX *mem_ctx,
871                                              struct tevent_context *ev,
872                                              struct wrepl_socket *wrepl_socket,
873                                              const struct wrepl_associate_stop *io)
874 {
875         struct tevent_req *req;
876         struct wrepl_associate_stop_state *state;
877         struct tevent_req *subreq;
878
879         if (wrepl_socket->event.ctx != ev) {
880                 /* TODO: remove wrepl_socket->event.ctx !!! */
881                 smb_panic("wrepl_associate_stop_send event context mismatch!");
882                 return NULL;
883         }
884
885         req = tevent_req_create(mem_ctx, &state,
886                                 struct wrepl_associate_stop_state);
887         if (req == NULL) {
888                 return NULL;
889         };
890
891         state->packet.opcode                    = WREPL_OPCODE_BITS;
892         state->packet.assoc_ctx                 = io->in.assoc_ctx;
893         state->packet.mess_type                 = WREPL_STOP_ASSOCIATION;
894         state->packet.message.stop.reason       = io->in.reason;
895
896         if (io->in.reason == 0) {
897                 state->ctrl.send_only                   = true;
898                 state->ctrl.disconnect_after_send       = true;
899         }
900
901         subreq = wrepl_request_send(state, ev, wrepl_socket, &state->packet, &state->ctrl);
902         if (tevent_req_nomem(subreq, req)) {
903                 return tevent_req_post(req, ev);
904         }
905         tevent_req_set_callback(subreq, wrepl_associate_stop_done, req);
906
907         return req;
908 }
909
910 static void wrepl_associate_stop_done(struct tevent_req *subreq)
911 {
912         struct tevent_req *req = tevent_req_callback_data(subreq,
913                                  struct tevent_req);
914         struct wrepl_associate_stop_state *state = tevent_req_data(req,
915                                                    struct wrepl_associate_stop_state);
916         NTSTATUS status;
917
918         /* currently we don't care about a possible response */
919         status = wrepl_request_recv(subreq, state, NULL);
920         TALLOC_FREE(subreq);
921         if (!NT_STATUS_IS_OK(status)) {
922                 tevent_req_nterror(req, status);
923                 return;
924         }
925
926         tevent_req_done(req);
927 }
928
929 /*
930   stop an association - recv
931 */
932 NTSTATUS wrepl_associate_stop_recv(struct tevent_req *req,
933                                    struct wrepl_associate_stop *io)
934 {
935         NTSTATUS status;
936
937         if (tevent_req_is_nterror(req, &status)) {
938                 tevent_req_received(req);
939                 return status;
940         }
941
942         tevent_req_received(req);
943         return NT_STATUS_OK;
944 }
945
946 /*
947   setup an association - sync api
948 */
949 NTSTATUS wrepl_associate_stop(struct wrepl_socket *wrepl_socket,
950                               struct wrepl_associate_stop *io)
951 {
952         struct tevent_req *subreq;
953         bool ok;
954         NTSTATUS status;
955
956         subreq = wrepl_associate_stop_send(wrepl_socket, wrepl_socket->event.ctx,
957                                            wrepl_socket, io);
958         NT_STATUS_HAVE_NO_MEMORY(subreq);
959
960         ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
961         if (!ok) {
962                 TALLOC_FREE(subreq);
963                 return NT_STATUS_INTERNAL_ERROR;
964         }
965
966         status = wrepl_associate_stop_recv(subreq, io);
967         TALLOC_FREE(subreq);
968         NT_STATUS_NOT_OK_RETURN(status);
969
970         return NT_STATUS_OK;
971 }
972
973 struct wrepl_pull_table_state {
974         struct wrepl_packet packet;
975         uint32_t num_partners;
976         struct wrepl_wins_owner *partners;
977 };
978
979 static void wrepl_pull_table_done(struct tevent_req *subreq);
980
981 struct tevent_req *wrepl_pull_table_send(TALLOC_CTX *mem_ctx,
982                                          struct tevent_context *ev,
983                                          struct wrepl_socket *wrepl_socket,
984                                          const struct wrepl_pull_table *io)
985 {
986         struct tevent_req *req;
987         struct wrepl_pull_table_state *state;
988         struct tevent_req *subreq;
989
990         if (wrepl_socket->event.ctx != ev) {
991                 /* TODO: remove wrepl_socket->event.ctx !!! */
992                 smb_panic("wrepl_pull_table_send event context mismatch!");
993                 return NULL;
994         }
995
996         req = tevent_req_create(mem_ctx, &state,
997                                 struct wrepl_pull_table_state);
998         if (req == NULL) {
999                 return NULL;
1000         };
1001
1002         state->packet.opcode                            = WREPL_OPCODE_BITS;
1003         state->packet.assoc_ctx                         = io->in.assoc_ctx;
1004         state->packet.mess_type                         = WREPL_REPLICATION;
1005         state->packet.message.replication.command       = WREPL_REPL_TABLE_QUERY;
1006
1007         subreq = wrepl_request_send(state, ev, wrepl_socket, &state->packet, NULL);
1008         if (tevent_req_nomem(subreq, req)) {
1009                 return tevent_req_post(req, ev);
1010         }
1011         tevent_req_set_callback(subreq, wrepl_pull_table_done, req);
1012
1013         return req;
1014 }
1015
1016 static void wrepl_pull_table_done(struct tevent_req *subreq)
1017 {
1018         struct tevent_req *req = tevent_req_callback_data(subreq,
1019                                  struct tevent_req);
1020         struct wrepl_pull_table_state *state = tevent_req_data(req,
1021                                                struct wrepl_pull_table_state);
1022         NTSTATUS status;
1023         struct wrepl_packet *packet;
1024         struct wrepl_table *table;
1025
1026         status = wrepl_request_recv(subreq, state, &packet);
1027         TALLOC_FREE(subreq);
1028         if (!NT_STATUS_IS_OK(status)) {
1029                 tevent_req_nterror(req, status);
1030                 return;
1031         }
1032
1033         if (packet->mess_type != WREPL_REPLICATION) {
1034                 tevent_req_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
1035                 return;
1036         }
1037
1038         if (packet->message.replication.command != WREPL_REPL_TABLE_REPLY) {
1039                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1040                 return;
1041         }
1042
1043         table = &packet->message.replication.info.table;
1044
1045         state->num_partners = table->partner_count;
1046         state->partners = talloc_move(state, &table->partners);
1047
1048         tevent_req_done(req);
1049 }
1050
1051 /*
1052   fetch the partner tables - recv
1053 */
1054 NTSTATUS wrepl_pull_table_recv(struct tevent_req *req,
1055                                TALLOC_CTX *mem_ctx,
1056                                struct wrepl_pull_table *io)
1057 {
1058         struct wrepl_pull_table_state *state = tevent_req_data(req,
1059                                                struct wrepl_pull_table_state);
1060         NTSTATUS status;
1061
1062         if (tevent_req_is_nterror(req, &status)) {
1063                 tevent_req_received(req);
1064                 return status;
1065         }
1066
1067         io->out.num_partners = state->num_partners;
1068         io->out.partners = talloc_move(mem_ctx, &state->partners);
1069
1070         tevent_req_received(req);
1071         return NT_STATUS_OK;
1072 }
1073
1074 /*
1075   fetch the partner table - sync api
1076 */
1077 NTSTATUS wrepl_pull_table(struct wrepl_socket *wrepl_socket,
1078                           TALLOC_CTX *mem_ctx,
1079                           struct wrepl_pull_table *io)
1080 {
1081         struct tevent_req *subreq;
1082         bool ok;
1083         NTSTATUS status;
1084
1085         subreq = wrepl_pull_table_send(mem_ctx, wrepl_socket->event.ctx,
1086                                        wrepl_socket, io);
1087         NT_STATUS_HAVE_NO_MEMORY(subreq);
1088
1089         ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
1090         if (!ok) {
1091                 TALLOC_FREE(subreq);
1092                 return NT_STATUS_INTERNAL_ERROR;
1093         }
1094
1095         status = wrepl_pull_table_recv(subreq, mem_ctx, io);
1096         TALLOC_FREE(subreq);
1097         NT_STATUS_NOT_OK_RETURN(status);
1098
1099         return NT_STATUS_OK;
1100 }
1101
1102
1103 struct wrepl_pull_names_state {
1104         struct {
1105                 const struct wrepl_pull_names *io;
1106         } caller;
1107         struct wrepl_packet packet;
1108         uint32_t num_names;
1109         struct wrepl_name *names;
1110 };
1111
1112 static void wrepl_pull_names_done(struct tevent_req *subreq);
1113
1114 struct tevent_req *wrepl_pull_names_send(TALLOC_CTX *mem_ctx,
1115                                          struct tevent_context *ev,
1116                                          struct wrepl_socket *wrepl_socket,
1117                                          const struct wrepl_pull_names *io)
1118 {
1119         struct tevent_req *req;
1120         struct wrepl_pull_names_state *state;
1121         struct tevent_req *subreq;
1122
1123         if (wrepl_socket->event.ctx != ev) {
1124                 /* TODO: remove wrepl_socket->event.ctx !!! */
1125                 smb_panic("wrepl_pull_names_send event context mismatch!");
1126                 return NULL;
1127         }
1128
1129         req = tevent_req_create(mem_ctx, &state,
1130                                 struct wrepl_pull_names_state);
1131         if (req == NULL) {
1132                 return NULL;
1133         };
1134         state->caller.io = io;
1135
1136         state->packet.opcode                            = WREPL_OPCODE_BITS;
1137         state->packet.assoc_ctx                         = io->in.assoc_ctx;
1138         state->packet.mess_type                         = WREPL_REPLICATION;
1139         state->packet.message.replication.command       = WREPL_REPL_SEND_REQUEST;
1140         state->packet.message.replication.info.owner    = io->in.partner;
1141
1142         subreq = wrepl_request_send(state, ev, wrepl_socket, &state->packet, NULL);
1143         if (tevent_req_nomem(subreq, req)) {
1144                 return tevent_req_post(req, ev);
1145         }
1146         tevent_req_set_callback(subreq, wrepl_pull_names_done, req);
1147
1148         return req;
1149 }
1150
1151 static void wrepl_pull_names_done(struct tevent_req *subreq)
1152 {
1153         struct tevent_req *req = tevent_req_callback_data(subreq,
1154                                  struct tevent_req);
1155         struct wrepl_pull_names_state *state = tevent_req_data(req,
1156                                                struct wrepl_pull_names_state);
1157         NTSTATUS status;
1158         struct wrepl_packet *packet;
1159         uint32_t i;
1160
1161         status = wrepl_request_recv(subreq, state, &packet);
1162         TALLOC_FREE(subreq);
1163         if (!NT_STATUS_IS_OK(status)) {
1164                 tevent_req_nterror(req, status);
1165                 return;
1166         }
1167
1168         if (packet->mess_type != WREPL_REPLICATION) {
1169                 tevent_req_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
1170                 return;
1171         }
1172
1173         if (packet->message.replication.command != WREPL_REPL_SEND_REPLY) {
1174                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1175                 return;
1176         }
1177
1178         state->num_names = packet->message.replication.info.reply.num_names;
1179
1180         state->names = talloc_array(state, struct wrepl_name, state->num_names);
1181         if (tevent_req_nomem(state->names, req)) {
1182                 return;
1183         }
1184
1185         /* convert the list of names and addresses to a sane format */
1186         for (i=0; i < state->num_names; i++) {
1187                 struct wrepl_wins_name *wname = &packet->message.replication.info.reply.names[i];
1188                 struct wrepl_name *name = &state->names[i];
1189
1190                 name->name      = *wname->name;
1191                 talloc_steal(state->names, wname->name);
1192                 name->type      = WREPL_NAME_TYPE(wname->flags);
1193                 name->state     = WREPL_NAME_STATE(wname->flags);
1194                 name->node      = WREPL_NAME_NODE(wname->flags);
1195                 name->is_static = WREPL_NAME_IS_STATIC(wname->flags);
1196                 name->raw_flags = wname->flags;
1197                 name->version_id= wname->id;
1198                 name->owner     = talloc_strdup(state->names,
1199                                                 state->caller.io->in.partner.address);
1200                 if (tevent_req_nomem(name->owner, req)) {
1201                         return;
1202                 }
1203
1204                 /* trying to save 1 or 2 bytes on the wire isn't a good idea */
1205                 if (wname->flags & 2) {
1206                         uint32_t j;
1207
1208                         name->num_addresses = wname->addresses.addresses.num_ips;
1209                         name->addresses = talloc_array(state->names,
1210                                                        struct wrepl_address,
1211                                                        name->num_addresses);
1212                         if (tevent_req_nomem(name->addresses, req)) {
1213                                 return;
1214                         }
1215
1216                         for (j=0;j<name->num_addresses;j++) {
1217                                 name->addresses[j].owner =
1218                                         talloc_move(name->addresses,
1219                                                     &wname->addresses.addresses.ips[j].owner);
1220                                 name->addresses[j].address = 
1221                                         talloc_move(name->addresses,
1222                                                     &wname->addresses.addresses.ips[j].ip);
1223                         }
1224                 } else {
1225                         name->num_addresses = 1;
1226                         name->addresses = talloc_array(state->names,
1227                                                        struct wrepl_address,
1228                                                        name->num_addresses);
1229                         if (tevent_req_nomem(name->addresses, req)) {
1230                                 return;
1231                         }
1232
1233                         name->addresses[0].owner = talloc_strdup(name->addresses, name->owner);
1234                         if (tevent_req_nomem(name->addresses[0].owner, req)) {
1235                                 return;
1236                         }
1237                         name->addresses[0].address = talloc_move(name->addresses,
1238                                                                  &wname->addresses.ip);
1239                 }
1240         }
1241
1242         tevent_req_done(req);
1243 }
1244
1245 /*
1246   fetch the names for a WINS partner - recv
1247 */
1248 NTSTATUS wrepl_pull_names_recv(struct tevent_req *req,
1249                                TALLOC_CTX *mem_ctx,
1250                                struct wrepl_pull_names *io)
1251 {
1252         struct wrepl_pull_names_state *state = tevent_req_data(req,
1253                                                struct wrepl_pull_names_state);
1254         NTSTATUS status;
1255
1256         if (tevent_req_is_nterror(req, &status)) {
1257                 tevent_req_received(req);
1258                 return status;
1259         }
1260
1261         io->out.num_names = state->num_names;
1262         io->out.names = talloc_move(mem_ctx, &state->names);
1263
1264         tevent_req_received(req);
1265         return NT_STATUS_OK;
1266 }
1267
1268
1269
1270 /*
1271   fetch the names for a WINS partner - sync api
1272 */
1273 NTSTATUS wrepl_pull_names(struct wrepl_socket *wrepl_socket,
1274                           TALLOC_CTX *mem_ctx,
1275                           struct wrepl_pull_names *io)
1276 {
1277         struct tevent_req *subreq;
1278         bool ok;
1279         NTSTATUS status;
1280
1281         subreq = wrepl_pull_names_send(mem_ctx, wrepl_socket->event.ctx,
1282                                        wrepl_socket, io);
1283         NT_STATUS_HAVE_NO_MEMORY(subreq);
1284
1285         ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
1286         if (!ok) {
1287                 TALLOC_FREE(subreq);
1288                 return NT_STATUS_INTERNAL_ERROR;
1289         }
1290
1291         status = wrepl_pull_names_recv(subreq, mem_ctx, io);
1292         TALLOC_FREE(subreq);
1293         NT_STATUS_NOT_OK_RETURN(status);
1294
1295         return NT_STATUS_OK;
1296 }