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