• 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/libcli/cldap/
1/*
2   Unix SMB/CIFS implementation.
3
4   cldap client library
5
6   Copyright (C) Andrew Tridgell 2005
7   Copyright (C) Stefan Metzmacher 2009
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/*
24  see RFC1798 for details of CLDAP
25
26  basic properties
27    - carried over UDP on port 389
28    - request and response matched by message ID
29    - request consists of only a single searchRequest element
30    - response can be in one of two forms
31       - a single searchResponse, followed by a searchResult
32       - a single searchResult
33*/
34
35#include "includes.h"
36#include <tevent.h>
37#include "../lib/util/dlinklist.h"
38#include "../libcli/ldap/ldap_message.h"
39#include "../libcli/ldap/ldap_ndr.h"
40#include "../libcli/cldap/cldap.h"
41#include "../lib/tsocket/tsocket.h"
42#include "../libcli/security/dom_sid.h"
43#include "../librpc/gen_ndr/ndr_nbt.h"
44#include "../lib/util/asn1.h"
45#include "../lib/util/tevent_ntstatus.h"
46
47#undef strcasecmp
48
49/*
50  context structure for operations on cldap packets
51*/
52struct cldap_socket {
53	/* the low level socket */
54	struct tdgram_context *sock;
55
56	/*
57	 * Are we in connected mode, which means
58	 * we get ICMP errors back instead of timing
59	 * out requests. And we can only send requests
60	 * to the connected peer.
61	 */
62	bool connected;
63
64	/*
65	 * we allow sync requests only, if the caller
66	 * did not pass an event context to cldap_socket_init()
67	 */
68	struct {
69		bool allow_poll;
70		struct tevent_context *ctx;
71	} event;
72
73	/* the queue for outgoing dgrams */
74	struct tevent_queue *send_queue;
75
76	/* do we have an async tsocket_recvfrom request pending */
77	struct tevent_req *recv_subreq;
78
79	struct {
80		/* a queue of pending search requests */
81		struct cldap_search_state *list;
82
83		/* mapping from message_id to pending request */
84		struct idr_context *idr;
85	} searches;
86
87	/* what to do with incoming request packets */
88	struct {
89		void (*handler)(struct cldap_socket *,
90				void *private_data,
91				struct cldap_incoming *);
92		void *private_data;
93	} incoming;
94};
95
96struct cldap_search_state {
97	struct cldap_search_state *prev, *next;
98
99	struct {
100		struct cldap_socket *cldap;
101	} caller;
102
103	int message_id;
104
105	struct {
106		uint32_t idx;
107		uint32_t delay;
108		uint32_t count;
109		struct tsocket_address *dest;
110		DATA_BLOB blob;
111	} request;
112
113	struct {
114		struct cldap_incoming *in;
115		struct asn1_data *asn1;
116	} response;
117
118	struct tevent_req *req;
119};
120
121static int cldap_socket_destructor(struct cldap_socket *c)
122{
123	while (c->searches.list) {
124		struct cldap_search_state *s = c->searches.list;
125		DLIST_REMOVE(c->searches.list, s);
126		ZERO_STRUCT(s->caller);
127	}
128
129	talloc_free(c->recv_subreq);
130	talloc_free(c->send_queue);
131	talloc_free(c->sock);
132	return 0;
133}
134
135static void cldap_recvfrom_done(struct tevent_req *subreq);
136
137static bool cldap_recvfrom_setup(struct cldap_socket *c)
138{
139	if (c->recv_subreq) {
140		return true;
141	}
142
143	if (!c->searches.list && !c->incoming.handler) {
144		return true;
145	}
146
147	c->recv_subreq = tdgram_recvfrom_send(c, c->event.ctx, c->sock);
148	if (!c->recv_subreq) {
149		return false;
150	}
151	tevent_req_set_callback(c->recv_subreq, cldap_recvfrom_done, c);
152
153	return true;
154}
155
156static void cldap_recvfrom_stop(struct cldap_socket *c)
157{
158	if (!c->recv_subreq) {
159		return;
160	}
161
162	if (c->searches.list || c->incoming.handler) {
163		return;
164	}
165
166	talloc_free(c->recv_subreq);
167	c->recv_subreq = NULL;
168}
169
170static void cldap_socket_recv_dgram(struct cldap_socket *c,
171				    struct cldap_incoming *in);
172
173static void cldap_recvfrom_done(struct tevent_req *subreq)
174{
175	struct cldap_socket *c = tevent_req_callback_data(subreq,
176				 struct cldap_socket);
177	struct cldap_incoming *in = NULL;
178	ssize_t ret;
179
180	c->recv_subreq = NULL;
181
182	in = talloc_zero(c, struct cldap_incoming);
183	if (!in) {
184		goto nomem;
185	}
186
187	ret = tdgram_recvfrom_recv(subreq,
188				   &in->recv_errno,
189				   in,
190				   &in->buf,
191				   &in->src);
192	talloc_free(subreq);
193	subreq = NULL;
194	if (ret >= 0) {
195		in->len = ret;
196	}
197	if (ret == -1 && in->recv_errno == 0) {
198		in->recv_errno = EIO;
199	}
200
201	/* this function should free or steal 'in' */
202	cldap_socket_recv_dgram(c, in);
203	in = NULL;
204
205	if (!cldap_recvfrom_setup(c)) {
206		goto nomem;
207	}
208
209	return;
210
211nomem:
212	talloc_free(subreq);
213	talloc_free(in);
214	/*TODO: call a dead socket handler */
215	return;
216}
217
218/*
219  handle recv events on a cldap socket
220*/
221static void cldap_socket_recv_dgram(struct cldap_socket *c,
222				    struct cldap_incoming *in)
223{
224	DATA_BLOB blob;
225	struct asn1_data *asn1;
226	void *p;
227	struct cldap_search_state *search;
228	NTSTATUS status;
229
230	if (in->recv_errno != 0) {
231		goto error;
232	}
233
234	blob = data_blob_const(in->buf, in->len);
235
236	asn1 = asn1_init(in);
237	if (!asn1) {
238		goto nomem;
239	}
240
241	if (!asn1_load(asn1, blob)) {
242		goto nomem;
243	}
244
245	in->ldap_msg = talloc(in, struct ldap_message);
246	if (in->ldap_msg == NULL) {
247		goto nomem;
248	}
249
250	/* this initial decode is used to find the message id */
251	status = ldap_decode(asn1, NULL, in->ldap_msg);
252	if (!NT_STATUS_IS_OK(status)) {
253		goto nterror;
254	}
255
256	/* find the pending request */
257	p = idr_find(c->searches.idr, in->ldap_msg->messageid);
258	if (p == NULL) {
259		if (!c->incoming.handler) {
260			goto done;
261		}
262
263		/* this function should free or steal 'in' */
264		c->incoming.handler(c, c->incoming.private_data, in);
265		return;
266	}
267
268	search = talloc_get_type(p, struct cldap_search_state);
269	search->response.in = talloc_move(search, &in);
270	search->response.asn1 = asn1;
271	search->response.asn1->ofs = 0;
272
273	tevent_req_done(search->req);
274	goto done;
275
276nomem:
277	in->recv_errno = ENOMEM;
278error:
279	status = map_nt_error_from_unix(in->recv_errno);
280nterror:
281	/* in connected mode the first pending search gets the error */
282	if (!c->connected) {
283		/* otherwise we just ignore the error */
284		goto done;
285	}
286	if (!c->searches.list) {
287		goto done;
288	}
289	tevent_req_nterror(c->searches.list->req, status);
290done:
291	talloc_free(in);
292}
293
294/*
295  initialise a cldap_sock
296*/
297NTSTATUS cldap_socket_init(TALLOC_CTX *mem_ctx,
298			   struct tevent_context *ev,
299			   const struct tsocket_address *local_addr,
300			   const struct tsocket_address *remote_addr,
301			   struct cldap_socket **_cldap)
302{
303	struct cldap_socket *c = NULL;
304	struct tsocket_address *any = NULL;
305	NTSTATUS status;
306	int ret;
307
308	c = talloc_zero(mem_ctx, struct cldap_socket);
309	if (!c) {
310		goto nomem;
311	}
312
313	if (!ev) {
314		ev = tevent_context_init(c);
315		if (!ev) {
316			goto nomem;
317		}
318		c->event.allow_poll = true;
319	}
320	c->event.ctx = ev;
321
322	if (!local_addr) {
323		ret = tsocket_address_inet_from_strings(c, "ip",
324							NULL, 0,
325							&any);
326		if (ret != 0) {
327			status = map_nt_error_from_unix(errno);
328			goto nterror;
329		}
330		local_addr = any;
331	}
332
333	c->searches.idr = idr_init(c);
334	if (!c->searches.idr) {
335		goto nomem;
336	}
337
338	ret = tdgram_inet_udp_socket(local_addr, remote_addr,
339				     c, &c->sock);
340	if (ret != 0) {
341		status = map_nt_error_from_unix(errno);
342		goto nterror;
343	}
344	talloc_free(any);
345
346	if (remote_addr) {
347		c->connected = true;
348	}
349
350	c->send_queue = tevent_queue_create(c, "cldap_send_queue");
351	if (!c->send_queue) {
352		goto nomem;
353	}
354
355	talloc_set_destructor(c, cldap_socket_destructor);
356
357	*_cldap = c;
358	return NT_STATUS_OK;
359
360nomem:
361	status = NT_STATUS_NO_MEMORY;
362nterror:
363	talloc_free(c);
364	return status;
365}
366
367/*
368  setup a handler for incoming requests
369*/
370NTSTATUS cldap_set_incoming_handler(struct cldap_socket *c,
371				    void (*handler)(struct cldap_socket *,
372						    void *private_data,
373						    struct cldap_incoming *),
374				    void *private_data)
375{
376	if (c->connected) {
377		return NT_STATUS_PIPE_CONNECTED;
378	}
379
380	/* if sync requests are allowed, we don't allow an incoming handler */
381	if (c->event.allow_poll) {
382		return NT_STATUS_INVALID_PIPE_STATE;
383	}
384
385	c->incoming.handler = handler;
386	c->incoming.private_data = private_data;
387
388	if (!cldap_recvfrom_setup(c)) {
389		ZERO_STRUCT(c->incoming);
390		return NT_STATUS_NO_MEMORY;
391	}
392
393	return NT_STATUS_OK;
394}
395
396struct cldap_reply_state {
397	struct tsocket_address *dest;
398	DATA_BLOB blob;
399};
400
401static void cldap_reply_state_destroy(struct tevent_req *subreq);
402
403/*
404  queue a cldap reply for send
405*/
406NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
407{
408	struct cldap_reply_state *state = NULL;
409	struct ldap_message *msg;
410	DATA_BLOB blob1, blob2;
411	NTSTATUS status;
412	struct tevent_req *subreq;
413
414	if (cldap->connected) {
415		return NT_STATUS_PIPE_CONNECTED;
416	}
417
418	if (!io->dest) {
419		return NT_STATUS_INVALID_ADDRESS;
420	}
421
422	state = talloc(cldap, struct cldap_reply_state);
423	NT_STATUS_HAVE_NO_MEMORY(state);
424
425	state->dest = tsocket_address_copy(io->dest, state);
426	if (!state->dest) {
427		goto nomem;
428	}
429
430	msg = talloc(state, struct ldap_message);
431	if (!msg) {
432		goto nomem;
433	}
434
435	msg->messageid       = io->messageid;
436	msg->controls        = NULL;
437
438	if (io->response) {
439		msg->type = LDAP_TAG_SearchResultEntry;
440		msg->r.SearchResultEntry = *io->response;
441
442		if (!ldap_encode(msg, NULL, &blob1, state)) {
443			status = NT_STATUS_INVALID_PARAMETER;
444			goto failed;
445		}
446	} else {
447		blob1 = data_blob(NULL, 0);
448	}
449
450	msg->type = LDAP_TAG_SearchResultDone;
451	msg->r.SearchResultDone = *io->result;
452
453	if (!ldap_encode(msg, NULL, &blob2, state)) {
454		status = NT_STATUS_INVALID_PARAMETER;
455		goto failed;
456	}
457	talloc_free(msg);
458
459	state->blob = data_blob_talloc(state, NULL, blob1.length + blob2.length);
460	if (!state->blob.data) {
461		goto nomem;
462	}
463
464	memcpy(state->blob.data, blob1.data, blob1.length);
465	memcpy(state->blob.data+blob1.length, blob2.data, blob2.length);
466	data_blob_free(&blob1);
467	data_blob_free(&blob2);
468
469	subreq = tdgram_sendto_queue_send(state,
470					  cldap->event.ctx,
471					  cldap->sock,
472					  cldap->send_queue,
473					  state->blob.data,
474					  state->blob.length,
475					  state->dest);
476	if (!subreq) {
477		goto nomem;
478	}
479	/* the callback will just free the state, as we don't need a result */
480	tevent_req_set_callback(subreq, cldap_reply_state_destroy, state);
481
482	return NT_STATUS_OK;
483
484nomem:
485	status = NT_STATUS_NO_MEMORY;
486failed:
487	talloc_free(state);
488	return status;
489}
490
491static void cldap_reply_state_destroy(struct tevent_req *subreq)
492{
493	struct cldap_reply_state *state = tevent_req_callback_data(subreq,
494					  struct cldap_reply_state);
495
496	/* we don't want to know the result here, we just free the state */
497	talloc_free(subreq);
498	talloc_free(state);
499}
500
501static int cldap_search_state_destructor(struct cldap_search_state *s)
502{
503	if (s->caller.cldap) {
504		if (s->message_id != -1) {
505			idr_remove(s->caller.cldap->searches.idr, s->message_id);
506			s->message_id = -1;
507		}
508		DLIST_REMOVE(s->caller.cldap->searches.list, s);
509		cldap_recvfrom_stop(s->caller.cldap);
510		ZERO_STRUCT(s->caller);
511	}
512
513	return 0;
514}
515
516static void cldap_search_state_queue_done(struct tevent_req *subreq);
517static void cldap_search_state_wakeup_done(struct tevent_req *subreq);
518
519/*
520  queue a cldap reply for send
521*/
522struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx,
523				    struct cldap_socket *cldap,
524				    const struct cldap_search *io)
525{
526	struct tevent_req *req, *subreq;
527	struct cldap_search_state *state = NULL;
528	struct ldap_message *msg;
529	struct ldap_SearchRequest *search;
530	struct timeval now;
531	struct timeval end;
532	uint32_t i;
533	int ret;
534
535	req = tevent_req_create(mem_ctx, &state,
536				struct cldap_search_state);
537	if (!req) {
538		return NULL;
539	}
540	ZERO_STRUCTP(state);
541	state->req = req;
542	state->caller.cldap = cldap;
543	state->message_id = -1;
544
545	talloc_set_destructor(state, cldap_search_state_destructor);
546
547	if (io->in.dest_address) {
548		if (cldap->connected) {
549			tevent_req_nterror(req, NT_STATUS_PIPE_CONNECTED);
550			goto post;
551		}
552		ret = tsocket_address_inet_from_strings(state,
553						        "ip",
554						        io->in.dest_address,
555						        io->in.dest_port,
556							&state->request.dest);
557		if (ret != 0) {
558			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
559			goto post;
560		}
561	} else {
562		if (!cldap->connected) {
563			tevent_req_nterror(req, NT_STATUS_INVALID_ADDRESS);
564			goto post;
565		}
566		state->request.dest = NULL;
567	}
568
569	state->message_id = idr_get_new_random(cldap->searches.idr,
570					       state, UINT16_MAX);
571	if (state->message_id == -1) {
572		tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
573		goto post;
574	}
575
576	msg = talloc(state, struct ldap_message);
577	if (tevent_req_nomem(msg, req)) {
578		goto post;
579	}
580
581	msg->messageid	= state->message_id;
582	msg->type	= LDAP_TAG_SearchRequest;
583	msg->controls	= NULL;
584	search = &msg->r.SearchRequest;
585
586	search->basedn		= "";
587	search->scope		= LDAP_SEARCH_SCOPE_BASE;
588	search->deref		= LDAP_DEREFERENCE_NEVER;
589	search->timelimit	= 0;
590	search->sizelimit	= 0;
591	search->attributesonly	= false;
592	search->num_attributes	= str_list_length(io->in.attributes);
593	search->attributes	= io->in.attributes;
594	search->tree		= ldb_parse_tree(msg, io->in.filter);
595	if (tevent_req_nomem(search->tree, req)) {
596		goto post;
597	}
598
599	if (!ldap_encode(msg, NULL, &state->request.blob, state)) {
600		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
601		goto post;
602	}
603	talloc_free(msg);
604
605	state->request.idx = 0;
606	state->request.delay = 10*1000*1000;
607	state->request.count = 3;
608	if (io->in.timeout > 0) {
609		state->request.delay = io->in.timeout * 1000 * 1000;
610		state->request.count = io->in.retries + 1;
611	}
612
613	now = tevent_timeval_current();
614	end = now;
615	for (i = 0; i < state->request.count; i++) {
616		end = tevent_timeval_add(&end, 0, state->request.delay);
617	}
618
619	if (!tevent_req_set_endtime(req, state->caller.cldap->event.ctx, end)) {
620		tevent_req_nomem(NULL, req);
621		goto post;
622	}
623
624	subreq = tdgram_sendto_queue_send(state,
625					  state->caller.cldap->event.ctx,
626					  state->caller.cldap->sock,
627					  state->caller.cldap->send_queue,
628					  state->request.blob.data,
629					  state->request.blob.length,
630					  state->request.dest);
631	if (tevent_req_nomem(subreq, req)) {
632		goto post;
633	}
634	tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
635
636	DLIST_ADD_END(cldap->searches.list, state, struct cldap_search_state *);
637
638	return req;
639
640 post:
641	return tevent_req_post(req, cldap->event.ctx);
642}
643
644static void cldap_search_state_queue_done(struct tevent_req *subreq)
645{
646	struct tevent_req *req = tevent_req_callback_data(subreq,
647				 struct tevent_req);
648	struct cldap_search_state *state = tevent_req_data(req,
649					   struct cldap_search_state);
650	ssize_t ret;
651	int sys_errno = 0;
652	struct timeval next;
653
654	ret = tdgram_sendto_queue_recv(subreq, &sys_errno);
655	talloc_free(subreq);
656	if (ret == -1) {
657		NTSTATUS status;
658		status = map_nt_error_from_unix(sys_errno);
659		DLIST_REMOVE(state->caller.cldap->searches.list, state);
660		ZERO_STRUCT(state->caller.cldap);
661		tevent_req_nterror(req, status);
662		return;
663	}
664
665	state->request.idx++;
666
667	/* wait for incoming traffic */
668	if (!cldap_recvfrom_setup(state->caller.cldap)) {
669		tevent_req_nomem(NULL, req);
670		return;
671	}
672
673	if (state->request.idx > state->request.count) {
674		/* we just wait for the response or a timeout */
675		return;
676	}
677
678	next = tevent_timeval_current_ofs(0, state->request.delay);
679	subreq = tevent_wakeup_send(state,
680				    state->caller.cldap->event.ctx,
681				    next);
682	if (tevent_req_nomem(subreq, req)) {
683		return;
684	}
685	tevent_req_set_callback(subreq, cldap_search_state_wakeup_done, req);
686}
687
688static void cldap_search_state_wakeup_done(struct tevent_req *subreq)
689{
690	struct tevent_req *req = tevent_req_callback_data(subreq,
691				 struct tevent_req);
692	struct cldap_search_state *state = tevent_req_data(req,
693					   struct cldap_search_state);
694	bool ok;
695
696	ok = tevent_wakeup_recv(subreq);
697	talloc_free(subreq);
698	if (!ok) {
699		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
700		return;
701	}
702
703	subreq = tdgram_sendto_queue_send(state,
704					  state->caller.cldap->event.ctx,
705					  state->caller.cldap->sock,
706					  state->caller.cldap->send_queue,
707					  state->request.blob.data,
708					  state->request.blob.length,
709					  state->request.dest);
710	if (tevent_req_nomem(subreq, req)) {
711		return;
712	}
713	tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
714}
715
716/*
717  receive a cldap reply
718*/
719NTSTATUS cldap_search_recv(struct tevent_req *req,
720			   TALLOC_CTX *mem_ctx,
721			   struct cldap_search *io)
722{
723	struct cldap_search_state *state = tevent_req_data(req,
724					   struct cldap_search_state);
725	struct ldap_message *ldap_msg;
726	NTSTATUS status;
727
728	if (tevent_req_is_nterror(req, &status)) {
729		goto failed;
730	}
731
732	ldap_msg = talloc(mem_ctx, struct ldap_message);
733	if (!ldap_msg) {
734		goto nomem;
735	}
736
737	status = ldap_decode(state->response.asn1, NULL, ldap_msg);
738	if (!NT_STATUS_IS_OK(status)) {
739		goto failed;
740	}
741
742	ZERO_STRUCT(io->out);
743
744	/* the first possible form has a search result in first place */
745	if (ldap_msg->type == LDAP_TAG_SearchResultEntry) {
746		io->out.response = talloc(mem_ctx, struct ldap_SearchResEntry);
747		if (!io->out.response) {
748			goto nomem;
749		}
750		*io->out.response = ldap_msg->r.SearchResultEntry;
751
752		/* decode the 2nd part */
753		status = ldap_decode(state->response.asn1, NULL, ldap_msg);
754		if (!NT_STATUS_IS_OK(status)) {
755			goto failed;
756		}
757	}
758
759	if (ldap_msg->type != LDAP_TAG_SearchResultDone) {
760		status = NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
761		goto failed;
762	}
763
764	io->out.result = talloc(mem_ctx, struct ldap_Result);
765	if (!io->out.result) {
766		goto nomem;
767	}
768	*io->out.result = ldap_msg->r.SearchResultDone;
769
770	if (io->out.result->resultcode != LDAP_SUCCESS) {
771		status = NT_STATUS_LDAP(io->out.result->resultcode);
772		goto failed;
773	}
774
775	tevent_req_received(req);
776	return NT_STATUS_OK;
777
778nomem:
779	status = NT_STATUS_NO_MEMORY;
780failed:
781	tevent_req_received(req);
782	return status;
783}
784
785
786/*
787  synchronous cldap search
788*/
789NTSTATUS cldap_search(struct cldap_socket *cldap,
790		      TALLOC_CTX *mem_ctx,
791		      struct cldap_search *io)
792{
793	struct tevent_req *req;
794	NTSTATUS status;
795
796	if (!cldap->event.allow_poll) {
797		return NT_STATUS_INVALID_PIPE_STATE;
798	}
799
800	if (cldap->searches.list) {
801		return NT_STATUS_PIPE_BUSY;
802	}
803
804	req = cldap_search_send(mem_ctx, cldap, io);
805	NT_STATUS_HAVE_NO_MEMORY(req);
806
807	if (!tevent_req_poll(req, cldap->event.ctx)) {
808		talloc_free(req);
809		return NT_STATUS_INTERNAL_ERROR;
810	}
811
812	status = cldap_search_recv(req, mem_ctx, io);
813	talloc_free(req);
814
815	return status;
816}
817
818struct cldap_netlogon_state {
819	struct cldap_search search;
820};
821
822static void cldap_netlogon_state_done(struct tevent_req *subreq);
823/*
824  queue a cldap netlogon for send
825*/
826struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx,
827				      struct cldap_socket *cldap,
828				      const struct cldap_netlogon *io)
829{
830	struct tevent_req *req, *subreq;
831	struct cldap_netlogon_state *state;
832	char *filter;
833	static const char * const attr[] = { "NetLogon", NULL };
834
835	req = tevent_req_create(mem_ctx, &state,
836				struct cldap_netlogon_state);
837	if (!req) {
838		return NULL;
839	}
840
841	filter = talloc_asprintf(state, "(&(NtVer=%s)",
842				 ldap_encode_ndr_uint32(state, io->in.version));
843	if (tevent_req_nomem(filter, req)) {
844		goto post;
845	}
846	if (io->in.user) {
847		filter = talloc_asprintf_append_buffer(filter, "(User=%s)", io->in.user);
848		if (tevent_req_nomem(filter, req)) {
849			goto post;
850		}
851	}
852	if (io->in.host) {
853		filter = talloc_asprintf_append_buffer(filter, "(Host=%s)", io->in.host);
854		if (tevent_req_nomem(filter, req)) {
855			goto post;
856		}
857	}
858	if (io->in.realm) {
859		filter = talloc_asprintf_append_buffer(filter, "(DnsDomain=%s)", io->in.realm);
860		if (tevent_req_nomem(filter, req)) {
861			goto post;
862		}
863	}
864	if (io->in.acct_control != -1) {
865		filter = talloc_asprintf_append_buffer(filter, "(AAC=%s)",
866						ldap_encode_ndr_uint32(state, io->in.acct_control));
867		if (tevent_req_nomem(filter, req)) {
868			goto post;
869		}
870	}
871	if (io->in.domain_sid) {
872		struct dom_sid *sid = dom_sid_parse_talloc(state, io->in.domain_sid);
873		if (tevent_req_nomem(sid, req)) {
874			goto post;
875		}
876		filter = talloc_asprintf_append_buffer(filter, "(domainSid=%s)",
877						ldap_encode_ndr_dom_sid(state, sid));
878		if (tevent_req_nomem(filter, req)) {
879			goto post;
880		}
881	}
882	if (io->in.domain_guid) {
883		struct GUID guid;
884		NTSTATUS status;
885		status = GUID_from_string(io->in.domain_guid, &guid);
886		if (tevent_req_nterror(req, status)) {
887			goto post;
888		}
889		filter = talloc_asprintf_append_buffer(filter, "(DomainGuid=%s)",
890						ldap_encode_ndr_GUID(state, &guid));
891		if (tevent_req_nomem(filter, req)) {
892			goto post;
893		}
894	}
895	filter = talloc_asprintf_append_buffer(filter, ")");
896	if (tevent_req_nomem(filter, req)) {
897		goto post;
898	}
899
900	if (io->in.dest_address) {
901		state->search.in.dest_address = talloc_strdup(state,
902						io->in.dest_address);
903		if (tevent_req_nomem(state->search.in.dest_address, req)) {
904			goto post;
905		}
906		state->search.in.dest_port = io->in.dest_port;
907	} else {
908		state->search.in.dest_address	= NULL;
909		state->search.in.dest_port	= 0;
910	}
911	state->search.in.filter		= filter;
912	state->search.in.attributes	= attr;
913	state->search.in.timeout	= 2;
914	state->search.in.retries	= 2;
915
916	subreq = cldap_search_send(state, cldap, &state->search);
917	if (tevent_req_nomem(subreq, req)) {
918		goto post;
919	}
920	tevent_req_set_callback(subreq, cldap_netlogon_state_done, req);
921
922	return req;
923post:
924	return tevent_req_post(req, cldap->event.ctx);
925}
926
927static void cldap_netlogon_state_done(struct tevent_req *subreq)
928{
929	struct tevent_req *req = tevent_req_callback_data(subreq,
930				 struct tevent_req);
931	struct cldap_netlogon_state *state = tevent_req_data(req,
932					     struct cldap_netlogon_state);
933	NTSTATUS status;
934
935	status = cldap_search_recv(subreq, state, &state->search);
936	talloc_free(subreq);
937
938	if (tevent_req_nterror(req, status)) {
939		return;
940	}
941
942	tevent_req_done(req);
943}
944
945/*
946  receive a cldap netlogon reply
947*/
948NTSTATUS cldap_netlogon_recv(struct tevent_req *req,
949			     struct smb_iconv_convenience *iconv_convenience,
950			     TALLOC_CTX *mem_ctx,
951			     struct cldap_netlogon *io)
952{
953	struct cldap_netlogon_state *state = tevent_req_data(req,
954					     struct cldap_netlogon_state);
955	NTSTATUS status;
956	DATA_BLOB *data;
957
958	if (tevent_req_is_nterror(req, &status)) {
959		goto failed;
960	}
961
962	if (state->search.out.response == NULL) {
963		status = NT_STATUS_NOT_FOUND;
964		goto failed;
965	}
966
967	if (state->search.out.response->num_attributes != 1 ||
968	    strcasecmp(state->search.out.response->attributes[0].name, "netlogon") != 0 ||
969	    state->search.out.response->attributes[0].num_values != 1 ||
970	    state->search.out.response->attributes[0].values->length < 2) {
971		status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
972		goto failed;
973	}
974	data = state->search.out.response->attributes[0].values;
975
976	status = pull_netlogon_samlogon_response(data, mem_ctx,
977						 iconv_convenience,
978						 &io->out.netlogon);
979	if (!NT_STATUS_IS_OK(status)) {
980		goto failed;
981	}
982
983	if (io->in.map_response) {
984		map_netlogon_samlogon_response(&io->out.netlogon);
985	}
986
987	status =  NT_STATUS_OK;
988failed:
989	tevent_req_received(req);
990	return status;
991}
992
993/*
994  sync cldap netlogon search
995*/
996NTSTATUS cldap_netlogon(struct cldap_socket *cldap,
997			struct smb_iconv_convenience *iconv_convenience,
998			TALLOC_CTX *mem_ctx,
999			struct cldap_netlogon *io)
1000{
1001	struct tevent_req *req;
1002	NTSTATUS status;
1003
1004	if (!cldap->event.allow_poll) {
1005		return NT_STATUS_INVALID_PIPE_STATE;
1006	}
1007
1008	if (cldap->searches.list) {
1009		return NT_STATUS_PIPE_BUSY;
1010	}
1011
1012	req = cldap_netlogon_send(mem_ctx, cldap, io);
1013	NT_STATUS_HAVE_NO_MEMORY(req);
1014
1015	if (!tevent_req_poll(req, cldap->event.ctx)) {
1016		talloc_free(req);
1017		return NT_STATUS_INTERNAL_ERROR;
1018	}
1019
1020	status = cldap_netlogon_recv(req, iconv_convenience, mem_ctx, io);
1021	talloc_free(req);
1022
1023	return status;
1024}
1025
1026
1027/*
1028  send an empty reply (used on any error, so the client doesn't keep waiting
1029  or send the bad request again)
1030*/
1031NTSTATUS cldap_empty_reply(struct cldap_socket *cldap,
1032			   uint32_t message_id,
1033			   struct tsocket_address *dest)
1034{
1035	NTSTATUS status;
1036	struct cldap_reply reply;
1037	struct ldap_Result result;
1038
1039	reply.messageid    = message_id;
1040	reply.dest         = dest;
1041	reply.response     = NULL;
1042	reply.result       = &result;
1043
1044	ZERO_STRUCT(result);
1045
1046	status = cldap_reply_send(cldap, &reply);
1047
1048	return status;
1049}
1050
1051/*
1052  send an error reply (used on any error, so the client doesn't keep waiting
1053  or send the bad request again)
1054*/
1055NTSTATUS cldap_error_reply(struct cldap_socket *cldap,
1056			   uint32_t message_id,
1057			   struct tsocket_address *dest,
1058			   int resultcode,
1059			   const char *errormessage)
1060{
1061	NTSTATUS status;
1062	struct cldap_reply reply;
1063	struct ldap_Result result;
1064
1065	reply.messageid    = message_id;
1066	reply.dest         = dest;
1067	reply.response     = NULL;
1068	reply.result       = &result;
1069
1070	ZERO_STRUCT(result);
1071	result.resultcode	= resultcode;
1072	result.errormessage	= errormessage;
1073
1074	status = cldap_reply_send(cldap, &reply);
1075
1076	return status;
1077}
1078
1079
1080/*
1081  send a netlogon reply
1082*/
1083NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap,
1084			      struct smb_iconv_convenience *iconv_convenience,
1085			      uint32_t message_id,
1086			      struct tsocket_address *dest,
1087			      uint32_t version,
1088			      struct netlogon_samlogon_response *netlogon)
1089{
1090	NTSTATUS status;
1091	struct cldap_reply reply;
1092	struct ldap_SearchResEntry response;
1093	struct ldap_Result result;
1094	TALLOC_CTX *tmp_ctx = talloc_new(cldap);
1095	DATA_BLOB blob;
1096
1097	status = push_netlogon_samlogon_response(&blob, tmp_ctx,
1098						 iconv_convenience,
1099						 netlogon);
1100	if (!NT_STATUS_IS_OK(status)) {
1101		talloc_free(tmp_ctx);
1102		return status;
1103	}
1104	reply.messageid    = message_id;
1105	reply.dest         = dest;
1106	reply.response     = &response;
1107	reply.result       = &result;
1108
1109	ZERO_STRUCT(result);
1110
1111	response.dn = "";
1112	response.num_attributes = 1;
1113	response.attributes = talloc(tmp_ctx, struct ldb_message_element);
1114	NT_STATUS_HAVE_NO_MEMORY(response.attributes);
1115	response.attributes->name = "netlogon";
1116	response.attributes->num_values = 1;
1117	response.attributes->values = &blob;
1118
1119	status = cldap_reply_send(cldap, &reply);
1120
1121	talloc_free(tmp_ctx);
1122
1123	return status;
1124}
1125
1126