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