• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/source4/libcli/wrepl/
1/*
2   Unix SMB/CIFS implementation.
3
4   low level WINS replication client code
5
6   Copyright (C) Andrew Tridgell 2005
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 3 of the License, or
11   (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program.  If not, see <http://www.gnu.org/licenses/>.
20*/
21
22#include "includes.h"
23#include "lib/events/events.h"
24#include "../lib/util/dlinklist.h"
25#include "lib/socket/socket.h"
26#include "libcli/wrepl/winsrepl.h"
27#include "librpc/gen_ndr/ndr_winsrepl.h"
28#include "lib/stream/packet.h"
29#include "libcli/composite/composite.h"
30#include "system/network.h"
31#include "lib/socket/netif.h"
32#include "param/param.h"
33
34static struct wrepl_request *wrepl_request_finished(struct wrepl_request *req, NTSTATUS status);
35
36/*
37  mark all pending requests as dead - called when a socket error happens
38*/
39static void wrepl_socket_dead(struct wrepl_socket *wrepl_socket, NTSTATUS status)
40{
41	wrepl_socket->dead = true;
42
43	if (wrepl_socket->packet) {
44		packet_recv_disable(wrepl_socket->packet);
45		packet_set_fde(wrepl_socket->packet, NULL);
46		packet_set_socket(wrepl_socket->packet, NULL);
47	}
48
49	if (wrepl_socket->event.fde) {
50		talloc_free(wrepl_socket->event.fde);
51		wrepl_socket->event.fde = NULL;
52	}
53
54	if (wrepl_socket->sock) {
55		talloc_free(wrepl_socket->sock);
56		wrepl_socket->sock = NULL;
57	}
58
59	if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
60		status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
61	}
62	while (wrepl_socket->recv_queue) {
63		struct wrepl_request *req = wrepl_socket->recv_queue;
64		DLIST_REMOVE(wrepl_socket->recv_queue, req);
65		wrepl_request_finished(req, status);
66	}
67
68	talloc_set_destructor(wrepl_socket, NULL);
69	if (wrepl_socket->free_skipped) {
70		talloc_free(wrepl_socket);
71	}
72}
73
74static void wrepl_request_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
75					  struct timeval t, void *ptr)
76{
77	struct wrepl_request *req = talloc_get_type(ptr, struct wrepl_request);
78	wrepl_socket_dead(req->wrepl_socket, NT_STATUS_IO_TIMEOUT);
79}
80
81/*
82  handle recv events
83*/
84static NTSTATUS wrepl_finish_recv(void *private_data, DATA_BLOB packet_blob_in)
85{
86	struct wrepl_socket *wrepl_socket = talloc_get_type(private_data, struct wrepl_socket);
87	struct wrepl_request *req = wrepl_socket->recv_queue;
88	DATA_BLOB blob;
89	enum ndr_err_code ndr_err;
90
91	if (!req) {
92		DEBUG(1,("Received unexpected WINS packet of length %u!\n",
93			 (unsigned)packet_blob_in.length));
94		return NT_STATUS_INVALID_NETWORK_RESPONSE;
95	}
96
97	req->packet = talloc(req, struct wrepl_packet);
98	NT_STATUS_HAVE_NO_MEMORY(req->packet);
99
100	blob.data = packet_blob_in.data + 4;
101	blob.length = packet_blob_in.length - 4;
102
103	/* we have a full request - parse it */
104	ndr_err = ndr_pull_struct_blob(&blob, req->packet, wrepl_socket->iconv_convenience, req->packet,
105				       (ndr_pull_flags_fn_t)ndr_pull_wrepl_packet);
106	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
107		NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
108		wrepl_request_finished(req, status);
109		return NT_STATUS_OK;
110	}
111
112	if (DEBUGLVL(10)) {
113		DEBUG(10,("Received WINS packet of length %u\n",
114			  (unsigned)packet_blob_in.length));
115		NDR_PRINT_DEBUG(wrepl_packet, req->packet);
116	}
117
118	wrepl_request_finished(req, NT_STATUS_OK);
119	return NT_STATUS_OK;
120}
121
122/*
123  handler for winrepl events
124*/
125static void wrepl_handler(struct tevent_context *ev, struct tevent_fd *fde,
126			  uint16_t flags, void *private_data)
127{
128	struct wrepl_socket *wrepl_socket = talloc_get_type(private_data,
129							    struct wrepl_socket);
130	if (flags & EVENT_FD_READ) {
131		packet_recv(wrepl_socket->packet);
132		return;
133	}
134	if (flags & EVENT_FD_WRITE) {
135		packet_queue_run(wrepl_socket->packet);
136	}
137}
138
139static void wrepl_error(void *private_data, NTSTATUS status)
140{
141	struct wrepl_socket *wrepl_socket = talloc_get_type(private_data,
142							    struct wrepl_socket);
143	wrepl_socket_dead(wrepl_socket, status);
144}
145
146
147/*
148  destroy a wrepl_socket destructor
149*/
150static int wrepl_socket_destructor(struct wrepl_socket *sock)
151{
152	if (sock->dead) {
153		sock->free_skipped = true;
154		return -1;
155	}
156	wrepl_socket_dead(sock, NT_STATUS_LOCAL_DISCONNECT);
157	return 0;
158}
159
160/*
161  initialise a wrepl_socket. The event_ctx is optional, if provided then
162  operations will use that event context
163*/
164struct wrepl_socket *wrepl_socket_init(TALLOC_CTX *mem_ctx,
165				       struct tevent_context *event_ctx,
166				       struct smb_iconv_convenience *iconv_convenience)
167{
168	struct wrepl_socket *wrepl_socket;
169	NTSTATUS status;
170
171	wrepl_socket = talloc_zero(mem_ctx, struct wrepl_socket);
172	if (!wrepl_socket) return NULL;
173
174	wrepl_socket->event.ctx = event_ctx;
175	if (!wrepl_socket->event.ctx) goto failed;
176
177	wrepl_socket->iconv_convenience = iconv_convenience;
178
179	status = socket_create("ip", SOCKET_TYPE_STREAM, &wrepl_socket->sock, 0);
180	if (!NT_STATUS_IS_OK(status)) goto failed;
181
182	talloc_steal(wrepl_socket, wrepl_socket->sock);
183
184	wrepl_socket->request_timeout	= WREPL_SOCKET_REQUEST_TIMEOUT;
185
186	talloc_set_destructor(wrepl_socket, wrepl_socket_destructor);
187
188	return wrepl_socket;
189
190failed:
191	talloc_free(wrepl_socket);
192	return NULL;
193}
194
195/*
196  initialise a wrepl_socket from an already existing connection
197*/
198struct wrepl_socket *wrepl_socket_merge(TALLOC_CTX *mem_ctx,
199				        struct tevent_context *event_ctx,
200					struct socket_context *sock,
201					struct packet_context *pack)
202{
203	struct wrepl_socket *wrepl_socket;
204
205	wrepl_socket = talloc_zero(mem_ctx, struct wrepl_socket);
206	if (wrepl_socket == NULL) goto failed;
207
208	wrepl_socket->event.ctx = event_ctx;
209	if (wrepl_socket->event.ctx == NULL) goto failed;
210
211	wrepl_socket->sock = sock;
212	talloc_steal(wrepl_socket, wrepl_socket->sock);
213
214
215	wrepl_socket->request_timeout	= WREPL_SOCKET_REQUEST_TIMEOUT;
216
217	wrepl_socket->event.fde = event_add_fd(wrepl_socket->event.ctx, wrepl_socket,
218					       socket_get_fd(wrepl_socket->sock),
219					       EVENT_FD_READ,
220					       wrepl_handler, wrepl_socket);
221	if (wrepl_socket->event.fde == NULL) {
222		goto failed;
223	}
224
225	wrepl_socket->packet = pack;
226	talloc_steal(wrepl_socket, wrepl_socket->packet);
227	packet_set_private(wrepl_socket->packet, wrepl_socket);
228	packet_set_socket(wrepl_socket->packet, wrepl_socket->sock);
229	packet_set_callback(wrepl_socket->packet, wrepl_finish_recv);
230	packet_set_full_request(wrepl_socket->packet, packet_full_request_u32);
231	packet_set_error_handler(wrepl_socket->packet, wrepl_error);
232	packet_set_event_context(wrepl_socket->packet, wrepl_socket->event.ctx);
233	packet_set_fde(wrepl_socket->packet, wrepl_socket->event.fde);
234	packet_set_serialise(wrepl_socket->packet);
235
236	talloc_set_destructor(wrepl_socket, wrepl_socket_destructor);
237
238	return wrepl_socket;
239
240failed:
241	talloc_free(wrepl_socket);
242	return NULL;
243}
244
245/*
246  destroy a wrepl_request
247*/
248static int wrepl_request_destructor(struct wrepl_request *req)
249{
250	if (req->state == WREPL_REQUEST_RECV) {
251		DLIST_REMOVE(req->wrepl_socket->recv_queue, req);
252	}
253	req->state = WREPL_REQUEST_ERROR;
254	return 0;
255}
256
257/*
258  wait for a request to complete
259*/
260static NTSTATUS wrepl_request_wait(struct wrepl_request *req)
261{
262	NT_STATUS_HAVE_NO_MEMORY(req);
263	while (req->state < WREPL_REQUEST_DONE) {
264		event_loop_once(req->wrepl_socket->event.ctx);
265	}
266	return req->status;
267}
268
269struct wrepl_connect_state {
270	struct composite_context *result;
271	struct wrepl_socket *wrepl_socket;
272	struct composite_context *creq;
273};
274
275/*
276  handler for winrepl connection completion
277*/
278static void wrepl_connect_handler(struct composite_context *creq)
279{
280	struct wrepl_connect_state *state = talloc_get_type(creq->async.private_data,
281					    struct wrepl_connect_state);
282	struct wrepl_socket *wrepl_socket = state->wrepl_socket;
283	struct composite_context *result = state->result;
284
285	result->status = socket_connect_recv(state->creq);
286	if (!composite_is_ok(result)) return;
287
288	wrepl_socket->event.fde = event_add_fd(wrepl_socket->event.ctx, wrepl_socket,
289					       socket_get_fd(wrepl_socket->sock),
290					       EVENT_FD_READ,
291					       wrepl_handler, wrepl_socket);
292	if (composite_nomem(wrepl_socket->event.fde, result)) return;
293
294	/* setup the stream -> packet parser */
295	wrepl_socket->packet = packet_init(wrepl_socket);
296	if (composite_nomem(wrepl_socket->packet, result)) return;
297	packet_set_private(wrepl_socket->packet, wrepl_socket);
298	packet_set_socket(wrepl_socket->packet, wrepl_socket->sock);
299	packet_set_callback(wrepl_socket->packet, wrepl_finish_recv);
300	packet_set_full_request(wrepl_socket->packet, packet_full_request_u32);
301	packet_set_error_handler(wrepl_socket->packet, wrepl_error);
302	packet_set_event_context(wrepl_socket->packet, wrepl_socket->event.ctx);
303	packet_set_fde(wrepl_socket->packet, wrepl_socket->event.fde);
304	packet_set_serialise(wrepl_socket->packet);
305
306	composite_done(result);
307}
308
309const char *wrepl_best_ip(struct loadparm_context *lp_ctx, const char *peer_ip)
310{
311	struct interface *ifaces;
312	load_interfaces(lp_ctx, lp_interfaces(lp_ctx), &ifaces);
313	return iface_best_ip(ifaces, peer_ip);
314}
315
316
317/*
318  connect a wrepl_socket to a WINS server
319*/
320struct composite_context *wrepl_connect_send(struct wrepl_socket *wrepl_socket,
321					     const char *our_ip, const char *peer_ip)
322{
323	struct composite_context *result;
324	struct wrepl_connect_state *state;
325	struct socket_address *peer, *us;
326
327	result = talloc_zero(wrepl_socket, struct composite_context);
328	if (!result) return NULL;
329
330	result->state		= COMPOSITE_STATE_IN_PROGRESS;
331	result->event_ctx	= wrepl_socket->event.ctx;
332
333	state = talloc_zero(result, struct wrepl_connect_state);
334	if (composite_nomem(state, result)) return result;
335	result->private_data	= state;
336	state->result		= result;
337	state->wrepl_socket	= wrepl_socket;
338
339	us = socket_address_from_strings(state, wrepl_socket->sock->backend_name,
340					 our_ip, 0);
341	if (composite_nomem(us, result)) return result;
342
343	peer = socket_address_from_strings(state, wrepl_socket->sock->backend_name,
344					   peer_ip, WINS_REPLICATION_PORT);
345	if (composite_nomem(peer, result)) return result;
346
347	state->creq = socket_connect_send(wrepl_socket->sock, us, peer,
348					  0, wrepl_socket->event.ctx);
349	composite_continue(result, state->creq, wrepl_connect_handler, state);
350	return result;
351}
352
353/*
354  connect a wrepl_socket to a WINS server - recv side
355*/
356NTSTATUS wrepl_connect_recv(struct composite_context *result)
357{
358	struct wrepl_connect_state *state = talloc_get_type(result->private_data,
359					    struct wrepl_connect_state);
360	struct wrepl_socket *wrepl_socket = state->wrepl_socket;
361	NTSTATUS status = composite_wait(result);
362
363	if (!NT_STATUS_IS_OK(status)) {
364		wrepl_socket_dead(wrepl_socket, status);
365	}
366
367	talloc_free(result);
368	return status;
369}
370
371/*
372  connect a wrepl_socket to a WINS server - sync API
373*/
374NTSTATUS wrepl_connect(struct wrepl_socket *wrepl_socket,
375		       const char *our_ip, const char *peer_ip)
376{
377	struct composite_context *c_req = wrepl_connect_send(wrepl_socket, our_ip, peer_ip);
378	return wrepl_connect_recv(c_req);
379}
380
381/*
382   callback from wrepl_request_trigger()
383*/
384static void wrepl_request_trigger_handler(struct tevent_context *ev, struct tevent_timer *te,
385					  struct timeval t, void *ptr)
386{
387	struct wrepl_request *req = talloc_get_type(ptr, struct wrepl_request);
388	if (req->async.fn) {
389		req->async.fn(req);
390	}
391}
392
393/*
394  trigger an immediate event on a wrepl_request
395  the return value should only be used in wrepl_request_send()
396  this is the only place where req->trigger is true
397*/
398static struct wrepl_request *wrepl_request_finished(struct wrepl_request *req, NTSTATUS status)
399{
400	struct tevent_timer *te;
401
402	if (req->state == WREPL_REQUEST_RECV) {
403		DLIST_REMOVE(req->wrepl_socket->recv_queue, req);
404	}
405
406	if (!NT_STATUS_IS_OK(status)) {
407		req->state	= WREPL_REQUEST_ERROR;
408	} else {
409		req->state	= WREPL_REQUEST_DONE;
410	}
411
412	req->status	= status;
413
414	if (req->trigger) {
415		req->trigger = false;
416		/* a zero timeout means immediate */
417		te = event_add_timed(req->wrepl_socket->event.ctx,
418				     req, timeval_zero(),
419				     wrepl_request_trigger_handler, req);
420		if (!te) {
421			talloc_free(req);
422			return NULL;
423		}
424		return req;
425	}
426
427	if (req->async.fn) {
428		req->async.fn(req);
429	}
430	return NULL;
431}
432
433struct wrepl_send_ctrl_state {
434	struct wrepl_send_ctrl ctrl;
435	struct wrepl_request *req;
436	struct wrepl_socket *wrepl_sock;
437};
438
439static int wrepl_send_ctrl_destructor(struct wrepl_send_ctrl_state *s)
440{
441	struct wrepl_request *req = s->wrepl_sock->recv_queue;
442
443	/* check if the request is still in WREPL_STATE_RECV,
444	 * we need this here because the caller has may called
445	 * talloc_free(req) and wrepl_send_ctrl_state isn't
446	 * a talloc child of the request, so our s->req pointer
447	 * is maybe invalid!
448	 */
449	for (; req; req = req->next) {
450		if (req == s->req) break;
451	}
452	if (!req) return 0;
453
454	/* here, we need to make sure the async request handler is called
455	 * later in the next event_loop and now now
456	 */
457	req->trigger = true;
458	wrepl_request_finished(req, NT_STATUS_OK);
459
460	if (s->ctrl.disconnect_after_send) {
461		wrepl_socket_dead(s->wrepl_sock, NT_STATUS_LOCAL_DISCONNECT);
462	}
463
464	return 0;
465}
466
467/*
468  send a generic wins replication request
469*/
470struct wrepl_request *wrepl_request_send(struct wrepl_socket *wrepl_socket,
471					 struct wrepl_packet *packet,
472					 struct wrepl_send_ctrl *ctrl)
473{
474	struct wrepl_request *req;
475	struct wrepl_wrap wrap;
476	DATA_BLOB blob;
477	NTSTATUS status;
478	enum ndr_err_code ndr_err;
479
480	req = talloc_zero(wrepl_socket, struct wrepl_request);
481	if (!req) return NULL;
482	req->wrepl_socket = wrepl_socket;
483	req->state        = WREPL_REQUEST_RECV;
484	req->trigger      = true;
485
486	DLIST_ADD_END(wrepl_socket->recv_queue, req, struct wrepl_request *);
487	talloc_set_destructor(req, wrepl_request_destructor);
488
489	if (wrepl_socket->dead) {
490		return wrepl_request_finished(req, NT_STATUS_INVALID_CONNECTION);
491	}
492
493	wrap.packet = *packet;
494	ndr_err = ndr_push_struct_blob(&blob, req, wrepl_socket->iconv_convenience, &wrap,
495				       (ndr_push_flags_fn_t)ndr_push_wrepl_wrap);
496	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
497		status = ndr_map_error2ntstatus(ndr_err);
498		return wrepl_request_finished(req, status);
499	}
500
501	if (DEBUGLVL(10)) {
502		DEBUG(10,("Sending WINS packet of length %u\n",
503			  (unsigned)blob.length));
504		NDR_PRINT_DEBUG(wrepl_packet, &wrap.packet);
505	}
506
507	if (wrepl_socket->request_timeout > 0) {
508		req->te = event_add_timed(wrepl_socket->event.ctx, req,
509					  timeval_current_ofs(wrepl_socket->request_timeout, 0),
510					  wrepl_request_timeout_handler, req);
511		if (!req->te) return wrepl_request_finished(req, NT_STATUS_NO_MEMORY);
512	}
513
514	if (ctrl && (ctrl->send_only || ctrl->disconnect_after_send)) {
515		struct wrepl_send_ctrl_state *s = talloc(blob.data, struct wrepl_send_ctrl_state);
516		if (!s) return wrepl_request_finished(req, NT_STATUS_NO_MEMORY);
517		s->ctrl		= *ctrl;
518		s->req		= req;
519		s->wrepl_sock	= wrepl_socket;
520		talloc_set_destructor(s, wrepl_send_ctrl_destructor);
521	}
522
523	status = packet_send(wrepl_socket->packet, blob);
524	if (!NT_STATUS_IS_OK(status)) {
525		return wrepl_request_finished(req, status);
526	}
527
528	req->trigger = false;
529	return req;
530}
531
532/*
533  receive a generic WINS replication reply
534*/
535NTSTATUS wrepl_request_recv(struct wrepl_request *req,
536			    TALLOC_CTX *mem_ctx,
537			    struct wrepl_packet **packet)
538{
539	NTSTATUS status = wrepl_request_wait(req);
540	if (NT_STATUS_IS_OK(status) && packet) {
541		*packet = talloc_steal(mem_ctx, req->packet);
542	}
543	talloc_free(req);
544	return status;
545}
546
547/*
548  a full WINS replication request/response
549*/
550NTSTATUS wrepl_request(struct wrepl_socket *wrepl_socket,
551		       TALLOC_CTX *mem_ctx,
552		       struct wrepl_packet *req_packet,
553		       struct wrepl_packet **reply_packet)
554{
555	struct wrepl_request *req = wrepl_request_send(wrepl_socket, req_packet, NULL);
556	return wrepl_request_recv(req, mem_ctx, reply_packet);
557}
558
559
560/*
561  setup an association - send
562*/
563struct wrepl_request *wrepl_associate_send(struct wrepl_socket *wrepl_socket,
564					   struct wrepl_associate *io)
565{
566	struct wrepl_packet *packet;
567	struct wrepl_request *req;
568
569	packet = talloc_zero(wrepl_socket, struct wrepl_packet);
570	if (packet == NULL) return NULL;
571
572	packet->opcode                      = WREPL_OPCODE_BITS;
573	packet->mess_type                   = WREPL_START_ASSOCIATION;
574	packet->message.start.minor_version = 2;
575	packet->message.start.major_version = 5;
576
577	/*
578	 * nt4 uses 41 bytes for the start_association call
579	 * so do it the same and as we don't know th emeanings of this bytes
580	 * we just send zeros and nt4, w2k and w2k3 seems to be happy with this
581	 *
582	 * if we don't do this nt4 uses an old version of the wins replication protocol
583	 * and that would break nt4 <-> samba replication
584	 */
585	packet->padding	= data_blob_talloc(packet, NULL, 21);
586	if (packet->padding.data == NULL) {
587		talloc_free(packet);
588		return NULL;
589	}
590	memset(packet->padding.data, 0, packet->padding.length);
591
592	req = wrepl_request_send(wrepl_socket, packet, NULL);
593
594	talloc_free(packet);
595
596	return req;
597}
598
599/*
600  setup an association - recv
601*/
602NTSTATUS wrepl_associate_recv(struct wrepl_request *req,
603			      struct wrepl_associate *io)
604{
605	struct wrepl_packet *packet=NULL;
606	NTSTATUS status;
607	status = wrepl_request_recv(req, req->wrepl_socket, &packet);
608	NT_STATUS_NOT_OK_RETURN(status);
609	if (packet->mess_type != WREPL_START_ASSOCIATION_REPLY) {
610		status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
611	}
612	if (NT_STATUS_IS_OK(status)) {
613		io->out.assoc_ctx = packet->message.start_reply.assoc_ctx;
614		io->out.major_version = packet->message.start_reply.major_version;
615	}
616	talloc_free(packet);
617	return status;
618}
619
620/*
621  setup an association - sync api
622*/
623NTSTATUS wrepl_associate(struct wrepl_socket *wrepl_socket,
624			 struct wrepl_associate *io)
625{
626	struct wrepl_request *req = wrepl_associate_send(wrepl_socket, io);
627	return wrepl_associate_recv(req, io);
628}
629
630
631/*
632  stop an association - send
633*/
634struct wrepl_request *wrepl_associate_stop_send(struct wrepl_socket *wrepl_socket,
635						struct wrepl_associate_stop *io)
636{
637	struct wrepl_packet *packet;
638	struct wrepl_request *req;
639	struct wrepl_send_ctrl ctrl;
640
641	packet = talloc_zero(wrepl_socket, struct wrepl_packet);
642	if (packet == NULL) return NULL;
643
644	packet->opcode			= WREPL_OPCODE_BITS;
645	packet->assoc_ctx		= io->in.assoc_ctx;
646	packet->mess_type		= WREPL_STOP_ASSOCIATION;
647	packet->message.stop.reason	= io->in.reason;
648
649	ZERO_STRUCT(ctrl);
650	if (io->in.reason == 0) {
651		ctrl.send_only			= true;
652		ctrl.disconnect_after_send	= true;
653	}
654
655	req = wrepl_request_send(wrepl_socket, packet, &ctrl);
656
657	talloc_free(packet);
658
659	return req;
660}
661
662/*
663  stop an association - recv
664*/
665NTSTATUS wrepl_associate_stop_recv(struct wrepl_request *req,
666				   struct wrepl_associate_stop *io)
667{
668	struct wrepl_packet *packet=NULL;
669	NTSTATUS status;
670	status = wrepl_request_recv(req, req->wrepl_socket, &packet);
671	NT_STATUS_NOT_OK_RETURN(status);
672	talloc_free(packet);
673	return status;
674}
675
676/*
677  setup an association - sync api
678*/
679NTSTATUS wrepl_associate_stop(struct wrepl_socket *wrepl_socket,
680			      struct wrepl_associate_stop *io)
681{
682	struct wrepl_request *req = wrepl_associate_stop_send(wrepl_socket, io);
683	return wrepl_associate_stop_recv(req, io);
684}
685
686/*
687  fetch the partner tables - send
688*/
689struct wrepl_request *wrepl_pull_table_send(struct wrepl_socket *wrepl_socket,
690					    struct wrepl_pull_table *io)
691{
692	struct wrepl_packet *packet;
693	struct wrepl_request *req;
694
695	packet = talloc_zero(wrepl_socket, struct wrepl_packet);
696	if (packet == NULL) return NULL;
697
698	packet->opcode                      = WREPL_OPCODE_BITS;
699	packet->assoc_ctx                   = io->in.assoc_ctx;
700	packet->mess_type                   = WREPL_REPLICATION;
701	packet->message.replication.command = WREPL_REPL_TABLE_QUERY;
702
703	req = wrepl_request_send(wrepl_socket, packet, NULL);
704
705	talloc_free(packet);
706
707	return req;
708}
709
710
711/*
712  fetch the partner tables - recv
713*/
714NTSTATUS wrepl_pull_table_recv(struct wrepl_request *req,
715			       TALLOC_CTX *mem_ctx,
716			       struct wrepl_pull_table *io)
717{
718	struct wrepl_packet *packet=NULL;
719	NTSTATUS status;
720	struct wrepl_table *table;
721	int i;
722
723	status = wrepl_request_recv(req, req->wrepl_socket, &packet);
724	NT_STATUS_NOT_OK_RETURN(status);
725	if (packet->mess_type != WREPL_REPLICATION) {
726		status = NT_STATUS_NETWORK_ACCESS_DENIED;
727	} else if (packet->message.replication.command != WREPL_REPL_TABLE_REPLY) {
728		status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
729	}
730	if (!NT_STATUS_IS_OK(status)) goto failed;
731
732	table = &packet->message.replication.info.table;
733	io->out.num_partners = table->partner_count;
734	io->out.partners = talloc_steal(mem_ctx, table->partners);
735	for (i=0;i<io->out.num_partners;i++) {
736		talloc_steal(io->out.partners, io->out.partners[i].address);
737	}
738
739failed:
740	talloc_free(packet);
741	return status;
742}
743
744
745/*
746  fetch the partner table - sync api
747*/
748NTSTATUS wrepl_pull_table(struct wrepl_socket *wrepl_socket,
749			  TALLOC_CTX *mem_ctx,
750			  struct wrepl_pull_table *io)
751{
752	struct wrepl_request *req = wrepl_pull_table_send(wrepl_socket, io);
753	return wrepl_pull_table_recv(req, mem_ctx, io);
754}
755
756
757/*
758  fetch the names for a WINS partner - send
759*/
760struct wrepl_request *wrepl_pull_names_send(struct wrepl_socket *wrepl_socket,
761					    struct wrepl_pull_names *io)
762{
763	struct wrepl_packet *packet;
764	struct wrepl_request *req;
765
766	packet = talloc_zero(wrepl_socket, struct wrepl_packet);
767	if (packet == NULL) return NULL;
768
769	packet->opcode                         = WREPL_OPCODE_BITS;
770	packet->assoc_ctx                      = io->in.assoc_ctx;
771	packet->mess_type                      = WREPL_REPLICATION;
772	packet->message.replication.command    = WREPL_REPL_SEND_REQUEST;
773	packet->message.replication.info.owner = io->in.partner;
774
775	req = wrepl_request_send(wrepl_socket, packet, NULL);
776
777	talloc_free(packet);
778
779	return req;
780}
781
782/*
783  fetch the names for a WINS partner - recv
784*/
785NTSTATUS wrepl_pull_names_recv(struct wrepl_request *req,
786			       TALLOC_CTX *mem_ctx,
787			       struct wrepl_pull_names *io)
788{
789	struct wrepl_packet *packet=NULL;
790	NTSTATUS status;
791	int i;
792
793	status = wrepl_request_recv(req, req->wrepl_socket, &packet);
794	NT_STATUS_NOT_OK_RETURN(status);
795	if (packet->mess_type != WREPL_REPLICATION ||
796	    packet->message.replication.command != WREPL_REPL_SEND_REPLY) {
797		status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
798	}
799	if (!NT_STATUS_IS_OK(status)) goto failed;
800
801	io->out.num_names = packet->message.replication.info.reply.num_names;
802
803	io->out.names = talloc_array(packet, struct wrepl_name, io->out.num_names);
804	if (io->out.names == NULL) goto nomem;
805
806	/* convert the list of names and addresses to a sane format */
807	for (i=0;i<io->out.num_names;i++) {
808		struct wrepl_wins_name *wname = &packet->message.replication.info.reply.names[i];
809		struct wrepl_name *name = &io->out.names[i];
810
811		name->name	= *wname->name;
812		talloc_steal(io->out.names, wname->name);
813		name->type	= WREPL_NAME_TYPE(wname->flags);
814		name->state	= WREPL_NAME_STATE(wname->flags);
815		name->node	= WREPL_NAME_NODE(wname->flags);
816		name->is_static	= WREPL_NAME_IS_STATIC(wname->flags);
817		name->raw_flags	= wname->flags;
818		name->version_id= wname->id;
819		name->owner	= talloc_strdup(io->out.names, io->in.partner.address);
820		if (name->owner == NULL) goto nomem;
821
822		/* trying to save 1 or 2 bytes on the wire isn't a good idea */
823		if (wname->flags & 2) {
824			int j;
825
826			name->num_addresses = wname->addresses.addresses.num_ips;
827			name->addresses = talloc_array(io->out.names,
828						       struct wrepl_address,
829						       name->num_addresses);
830			if (name->addresses == NULL) goto nomem;
831			for (j=0;j<name->num_addresses;j++) {
832				name->addresses[j].owner =
833					talloc_steal(name->addresses,
834						     wname->addresses.addresses.ips[j].owner);
835				name->addresses[j].address =
836					talloc_steal(name->addresses,
837						     wname->addresses.addresses.ips[j].ip);
838			}
839		} else {
840			name->num_addresses = 1;
841			name->addresses = talloc(io->out.names, struct wrepl_address);
842			if (name->addresses == NULL) goto nomem;
843			name->addresses[0].owner = talloc_strdup(name->addresses,io->in.partner.address);
844			if (name->addresses[0].owner == NULL) goto nomem;
845			name->addresses[0].address = talloc_steal(name->addresses,
846								  wname->addresses.ip);
847		}
848	}
849
850	talloc_steal(mem_ctx, io->out.names);
851	talloc_free(packet);
852	return NT_STATUS_OK;
853nomem:
854	status = NT_STATUS_NO_MEMORY;
855failed:
856	talloc_free(packet);
857	return status;
858}
859
860
861
862/*
863  fetch the names for a WINS partner - sync api
864*/
865NTSTATUS wrepl_pull_names(struct wrepl_socket *wrepl_socket,
866			  TALLOC_CTX *mem_ctx,
867			  struct wrepl_pull_names *io)
868{
869	struct wrepl_request *req = wrepl_pull_names_send(wrepl_socket, io);
870	return wrepl_pull_names_recv(req, mem_ctx, io);
871}
872