source: vendor/3.6.0/source4/libcli/wrepl/winsrepl.c

Last change on this file was 740, checked in by Silvan Scherrer, 13 years ago

Samba Server: update vendor to 3.6.0

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