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