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