libcli-cldap: avoid the case local == remote == NULL
[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         const char *fam = NULL;
316
317         if (local_addr == NULL && remote_addr == NULL) {
318                 return NT_STATUS_INVALID_PARAMETER_MIX;
319         }
320
321         if (remote_addr) {
322                 bool is_ipv4;
323                 bool is_ipv6;
324
325                 is_ipv4 = tsocket_address_is_inet(remote_addr, "ipv4");
326                 is_ipv6 = tsocket_address_is_inet(remote_addr, "ipv6");
327
328                 if (is_ipv4) {
329                         fam = "ipv4";
330                 } else if (is_ipv6) {
331                         fam = "ipv6";
332                 } else {
333                         return NT_STATUS_INVALID_ADDRESS;
334                 }
335         }
336
337         c = talloc_zero(mem_ctx, struct cldap_socket);
338         if (!c) {
339                 goto nomem;
340         }
341
342         if (!local_addr) {
343                 /*
344                  * Here we know the address family of the remote address.
345                  */
346                 if (fam == NULL) {
347                         return NT_STATUS_INVALID_PARAMETER_MIX;
348                 }
349
350                 ret = tsocket_address_inet_from_strings(c, fam,
351                                                         NULL, 0,
352                                                         &any);
353                 if (ret != 0) {
354                         status = map_nt_error_from_unix_common(errno);
355                         goto nterror;
356                 }
357                 local_addr = any;
358         }
359
360         c->searches.idr = idr_init(c);
361         if (!c->searches.idr) {
362                 goto nomem;
363         }
364
365         ret = tdgram_inet_udp_socket(local_addr, remote_addr,
366                                      c, &c->sock);
367         if (ret != 0) {
368                 status = map_nt_error_from_unix_common(errno);
369                 goto nterror;
370         }
371         talloc_free(any);
372
373         if (remote_addr) {
374                 c->connected = true;
375         }
376
377         c->send_queue = tevent_queue_create(c, "cldap_send_queue");
378         if (!c->send_queue) {
379                 goto nomem;
380         }
381
382         talloc_set_destructor(c, cldap_socket_destructor);
383
384         *_cldap = c;
385         return NT_STATUS_OK;
386
387 nomem:
388         status = NT_STATUS_NO_MEMORY;
389 nterror:
390         talloc_free(c);
391         return status;
392 }
393
394 /*
395   setup a handler for incoming requests
396 */
397 NTSTATUS cldap_set_incoming_handler(struct cldap_socket *c,
398                                     struct tevent_context *ev,
399                                     void (*handler)(struct cldap_socket *,
400                                                     void *private_data,
401                                                     struct cldap_incoming *),
402                                     void *private_data)
403 {
404         if (c->connected) {
405                 return NT_STATUS_PIPE_CONNECTED;
406         }
407
408         c->incoming.ev = ev;
409         c->incoming.handler = handler;
410         c->incoming.private_data = private_data;
411
412         if (!cldap_recvfrom_setup(c)) {
413                 ZERO_STRUCT(c->incoming);
414                 return NT_STATUS_NO_MEMORY;
415         }
416
417         return NT_STATUS_OK;
418 }
419
420 struct cldap_reply_state {
421         struct tsocket_address *dest;
422         DATA_BLOB blob;
423 };
424
425 static void cldap_reply_state_destroy(struct tevent_req *subreq);
426
427 /*
428   queue a cldap reply for send
429 */
430 NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
431 {
432         struct cldap_reply_state *state = NULL;
433         struct ldap_message *msg;
434         DATA_BLOB blob1, blob2;
435         NTSTATUS status;
436         struct tevent_req *subreq;
437
438         if (cldap->connected) {
439                 return NT_STATUS_PIPE_CONNECTED;
440         }
441
442         if (cldap->incoming.ev == NULL) {
443                 return NT_STATUS_INVALID_PIPE_STATE;
444         }
445
446         if (!io->dest) {
447                 return NT_STATUS_INVALID_ADDRESS;
448         }
449
450         state = talloc(cldap, struct cldap_reply_state);
451         NT_STATUS_HAVE_NO_MEMORY(state);
452
453         state->dest = tsocket_address_copy(io->dest, state);
454         if (!state->dest) {
455                 goto nomem;
456         }
457
458         msg = talloc(state, struct ldap_message);
459         if (!msg) {
460                 goto nomem;
461         }
462
463         msg->messageid       = io->messageid;
464         msg->controls        = NULL;
465
466         if (io->response) {
467                 msg->type = LDAP_TAG_SearchResultEntry;
468                 msg->r.SearchResultEntry = *io->response;
469
470                 if (!ldap_encode(msg, NULL, &blob1, state)) {
471                         status = NT_STATUS_INVALID_PARAMETER;
472                         goto failed;
473                 }
474         } else {
475                 blob1 = data_blob(NULL, 0);
476         }
477
478         msg->type = LDAP_TAG_SearchResultDone;
479         msg->r.SearchResultDone = *io->result;
480
481         if (!ldap_encode(msg, NULL, &blob2, state)) {
482                 status = NT_STATUS_INVALID_PARAMETER;
483                 goto failed;
484         }
485         talloc_free(msg);
486
487         state->blob = data_blob_talloc(state, NULL, blob1.length + blob2.length);
488         if (!state->blob.data) {
489                 goto nomem;
490         }
491
492         memcpy(state->blob.data, blob1.data, blob1.length);
493         memcpy(state->blob.data+blob1.length, blob2.data, blob2.length);
494         data_blob_free(&blob1);
495         data_blob_free(&blob2);
496
497         subreq = tdgram_sendto_queue_send(state,
498                                           cldap->incoming.ev,
499                                           cldap->sock,
500                                           cldap->send_queue,
501                                           state->blob.data,
502                                           state->blob.length,
503                                           state->dest);
504         if (!subreq) {
505                 goto nomem;
506         }
507         /* the callback will just free the state, as we don't need a result */
508         tevent_req_set_callback(subreq, cldap_reply_state_destroy, state);
509
510         return NT_STATUS_OK;
511
512 nomem:
513         status = NT_STATUS_NO_MEMORY;
514 failed:
515         talloc_free(state);
516         return status;
517 }
518
519 static void cldap_reply_state_destroy(struct tevent_req *subreq)
520 {
521         struct cldap_reply_state *state = tevent_req_callback_data(subreq,
522                                           struct cldap_reply_state);
523
524         /* we don't want to know the result here, we just free the state */
525         talloc_free(subreq);
526         talloc_free(state);
527 }
528
529 static int cldap_search_state_destructor(struct cldap_search_state *s)
530 {
531         if (s->caller.cldap) {
532                 if (s->message_id != -1) {
533                         idr_remove(s->caller.cldap->searches.idr, s->message_id);
534                         s->message_id = -1;
535                 }
536                 DLIST_REMOVE(s->caller.cldap->searches.list, s);
537                 cldap_recvfrom_stop(s->caller.cldap);
538                 ZERO_STRUCT(s->caller);
539         }
540
541         return 0;
542 }
543
544 static void cldap_search_state_queue_done(struct tevent_req *subreq);
545 static void cldap_search_state_wakeup_done(struct tevent_req *subreq);
546
547 /*
548   queue a cldap reply for send
549 */
550 struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx,
551                                      struct tevent_context *ev,
552                                      struct cldap_socket *cldap,
553                                      const struct cldap_search *io)
554 {
555         struct tevent_req *req, *subreq;
556         struct cldap_search_state *state = NULL;
557         struct ldap_message *msg;
558         struct ldap_SearchRequest *search;
559         struct timeval now;
560         struct timeval end;
561         uint32_t i;
562         int ret;
563
564         req = tevent_req_create(mem_ctx, &state,
565                                 struct cldap_search_state);
566         if (!req) {
567                 return NULL;
568         }
569         ZERO_STRUCTP(state);
570         state->caller.ev = ev;
571         state->req = req;
572         state->caller.cldap = cldap;
573         state->message_id = -1;
574
575         talloc_set_destructor(state, cldap_search_state_destructor);
576
577         if (io->in.dest_address) {
578                 if (cldap->connected) {
579                         tevent_req_nterror(req, NT_STATUS_PIPE_CONNECTED);
580                         goto post;
581                 }
582                 ret = tsocket_address_inet_from_strings(state,
583                                                         "ip",
584                                                         io->in.dest_address,
585                                                         io->in.dest_port,
586                                                         &state->request.dest);
587                 if (ret != 0) {
588                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
589                         goto post;
590                 }
591         } else {
592                 if (!cldap->connected) {
593                         tevent_req_nterror(req, NT_STATUS_INVALID_ADDRESS);
594                         goto post;
595                 }
596                 state->request.dest = NULL;
597         }
598
599         state->message_id = idr_get_new_random(cldap->searches.idr,
600                                                state, UINT16_MAX);
601         if (state->message_id == -1) {
602                 tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
603                 goto post;
604         }
605
606         msg = talloc(state, struct ldap_message);
607         if (tevent_req_nomem(msg, req)) {
608                 goto post;
609         }
610
611         msg->messageid  = state->message_id;
612         msg->type       = LDAP_TAG_SearchRequest;
613         msg->controls   = NULL;
614         search = &msg->r.SearchRequest;
615
616         search->basedn          = "";
617         search->scope           = LDAP_SEARCH_SCOPE_BASE;
618         search->deref           = LDAP_DEREFERENCE_NEVER;
619         search->timelimit       = 0;
620         search->sizelimit       = 0;
621         search->attributesonly  = false;
622         search->num_attributes  = str_list_length(io->in.attributes);
623         search->attributes      = io->in.attributes;
624         search->tree            = ldb_parse_tree(msg, io->in.filter);
625         if (tevent_req_nomem(search->tree, req)) {
626                 goto post;
627         }
628
629         if (!ldap_encode(msg, NULL, &state->request.blob, state)) {
630                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
631                 goto post;
632         }
633         talloc_free(msg);
634
635         state->request.idx = 0;
636         state->request.delay = 10*1000*1000;
637         state->request.count = 3;
638         if (io->in.timeout > 0) {
639                 state->request.delay = io->in.timeout * 1000 * 1000;
640                 state->request.count = io->in.retries + 1;
641         }
642
643         now = tevent_timeval_current();
644         end = now;
645         for (i = 0; i < state->request.count; i++) {
646                 end = tevent_timeval_add(&end, state->request.delay / 1000000,
647                                          state->request.delay % 1000000);
648         }
649
650         if (!tevent_req_set_endtime(req, state->caller.ev, end)) {
651                 tevent_req_oom(req);
652                 goto post;
653         }
654
655         subreq = tdgram_sendto_queue_send(state,
656                                           state->caller.ev,
657                                           state->caller.cldap->sock,
658                                           state->caller.cldap->send_queue,
659                                           state->request.blob.data,
660                                           state->request.blob.length,
661                                           state->request.dest);
662         if (tevent_req_nomem(subreq, req)) {
663                 goto post;
664         }
665         tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
666
667         DLIST_ADD_END(cldap->searches.list, state, struct cldap_search_state *);
668
669         return req;
670
671  post:
672         return tevent_req_post(req, state->caller.ev);
673 }
674
675 static void cldap_search_state_queue_done(struct tevent_req *subreq)
676 {
677         struct tevent_req *req = tevent_req_callback_data(subreq,
678                                  struct tevent_req);
679         struct cldap_search_state *state = tevent_req_data(req,
680                                            struct cldap_search_state);
681         ssize_t ret;
682         int sys_errno = 0;
683         struct timeval next;
684
685         ret = tdgram_sendto_queue_recv(subreq, &sys_errno);
686         talloc_free(subreq);
687         if (ret == -1) {
688                 NTSTATUS status;
689                 status = map_nt_error_from_unix_common(sys_errno);
690                 DLIST_REMOVE(state->caller.cldap->searches.list, state);
691                 ZERO_STRUCT(state->caller.cldap);
692                 tevent_req_nterror(req, status);
693                 return;
694         }
695
696         state->request.idx++;
697
698         /* wait for incoming traffic */
699         if (!cldap_recvfrom_setup(state->caller.cldap)) {
700                 tevent_req_oom(req);
701                 return;
702         }
703
704         if (state->request.idx > state->request.count) {
705                 /* we just wait for the response or a timeout */
706                 return;
707         }
708
709         next = tevent_timeval_current_ofs(state->request.delay / 1000000,
710                                           state->request.delay % 1000000);
711         subreq = tevent_wakeup_send(state,
712                                     state->caller.ev,
713                                     next);
714         if (tevent_req_nomem(subreq, req)) {
715                 return;
716         }
717         tevent_req_set_callback(subreq, cldap_search_state_wakeup_done, req);
718 }
719
720 static void cldap_search_state_wakeup_done(struct tevent_req *subreq)
721 {
722         struct tevent_req *req = tevent_req_callback_data(subreq,
723                                  struct tevent_req);
724         struct cldap_search_state *state = tevent_req_data(req,
725                                            struct cldap_search_state);
726         bool ok;
727
728         ok = tevent_wakeup_recv(subreq);
729         talloc_free(subreq);
730         if (!ok) {
731                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
732                 return;
733         }
734
735         subreq = tdgram_sendto_queue_send(state,
736                                           state->caller.ev,
737                                           state->caller.cldap->sock,
738                                           state->caller.cldap->send_queue,
739                                           state->request.blob.data,
740                                           state->request.blob.length,
741                                           state->request.dest);
742         if (tevent_req_nomem(subreq, req)) {
743                 return;
744         }
745         tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
746 }
747
748 /*
749   receive a cldap reply
750 */
751 NTSTATUS cldap_search_recv(struct tevent_req *req,
752                            TALLOC_CTX *mem_ctx,
753                            struct cldap_search *io)
754 {
755         struct cldap_search_state *state = tevent_req_data(req,
756                                            struct cldap_search_state);
757         struct ldap_message *ldap_msg;
758         NTSTATUS status;
759
760         if (tevent_req_is_nterror(req, &status)) {
761                 goto failed;
762         }
763
764         ldap_msg = talloc(mem_ctx, struct ldap_message);
765         if (!ldap_msg) {
766                 goto nomem;
767         }
768
769         status = ldap_decode(state->response.asn1, NULL, ldap_msg);
770         if (!NT_STATUS_IS_OK(status)) {
771                 goto failed;
772         }
773
774         ZERO_STRUCT(io->out);
775
776         /* the first possible form has a search result in first place */
777         if (ldap_msg->type == LDAP_TAG_SearchResultEntry) {
778                 io->out.response = talloc(mem_ctx, struct ldap_SearchResEntry);
779                 if (!io->out.response) {
780                         goto nomem;
781                 }
782                 *io->out.response = ldap_msg->r.SearchResultEntry;
783
784                 /* decode the 2nd part */
785                 status = ldap_decode(state->response.asn1, NULL, ldap_msg);
786                 if (!NT_STATUS_IS_OK(status)) {
787                         goto failed;
788                 }
789         }
790
791         if (ldap_msg->type != LDAP_TAG_SearchResultDone) {
792                 status = NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
793                 goto failed;
794         }
795
796         io->out.result = talloc(mem_ctx, struct ldap_Result);
797         if (!io->out.result) {
798                 goto nomem;
799         }
800         *io->out.result = ldap_msg->r.SearchResultDone;
801
802         if (io->out.result->resultcode != LDAP_SUCCESS) {
803                 status = NT_STATUS_LDAP(io->out.result->resultcode);
804                 goto failed;
805         }
806
807         tevent_req_received(req);
808         return NT_STATUS_OK;
809
810 nomem:
811         status = NT_STATUS_NO_MEMORY;
812 failed:
813         tevent_req_received(req);
814         return status;
815 }
816
817
818 /*
819   synchronous cldap search
820 */
821 NTSTATUS cldap_search(struct cldap_socket *cldap,
822                       TALLOC_CTX *mem_ctx,
823                       struct cldap_search *io)
824 {
825         TALLOC_CTX *frame;
826         struct tevent_req *req;
827         struct tevent_context *ev;
828         NTSTATUS status;
829
830         if (cldap->searches.list) {
831                 return NT_STATUS_PIPE_BUSY;
832         }
833
834         if (cldap->incoming.handler) {
835                 return NT_STATUS_INVALID_PIPE_STATE;
836         }
837
838         frame = talloc_stackframe();
839
840         ev = tevent_context_init(frame);
841         if (ev == NULL) {
842                 TALLOC_FREE(frame);
843                 return NT_STATUS_NO_MEMORY;
844         }
845
846         req = cldap_search_send(mem_ctx, ev, cldap, io);
847         if (req == NULL) {
848                 TALLOC_FREE(frame);
849                 return NT_STATUS_NO_MEMORY;
850         }
851
852         if (!tevent_req_poll(req, ev)) {
853                 status = map_nt_error_from_unix_common(errno);
854                 TALLOC_FREE(frame);
855                 return status;
856         }
857
858         status = cldap_search_recv(req, mem_ctx, io);
859         if (!NT_STATUS_IS_OK(status)) {
860                 TALLOC_FREE(frame);
861                 return status;
862         }
863
864         TALLOC_FREE(frame);
865         return NT_STATUS_OK;
866 }
867
868 struct cldap_netlogon_state {
869         struct cldap_search search;
870 };
871
872 static void cldap_netlogon_state_done(struct tevent_req *subreq);
873 /*
874   queue a cldap netlogon for send
875 */
876 struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx,
877                                        struct tevent_context *ev,
878                                        struct cldap_socket *cldap,
879                                        const struct cldap_netlogon *io)
880 {
881         struct tevent_req *req, *subreq;
882         struct cldap_netlogon_state *state;
883         char *filter;
884         static const char * const attr[] = { "NetLogon", NULL };
885
886         req = tevent_req_create(mem_ctx, &state,
887                                 struct cldap_netlogon_state);
888         if (!req) {
889                 return NULL;
890         }
891
892         filter = talloc_asprintf(state, "(&(NtVer=%s)", 
893                                  ldap_encode_ndr_uint32(state, io->in.version));
894         if (tevent_req_nomem(filter, req)) {
895                 goto post;
896         }
897         if (io->in.user) {
898                 filter = talloc_asprintf_append_buffer(filter, "(User=%s)", io->in.user);
899                 if (tevent_req_nomem(filter, req)) {
900                         goto post;
901                 }
902         }
903         if (io->in.host) {
904                 filter = talloc_asprintf_append_buffer(filter, "(Host=%s)", io->in.host);
905                 if (tevent_req_nomem(filter, req)) {
906                         goto post;
907                 }
908         }
909         if (io->in.realm) {
910                 filter = talloc_asprintf_append_buffer(filter, "(DnsDomain=%s)", io->in.realm);
911                 if (tevent_req_nomem(filter, req)) {
912                         goto post;
913                 }
914         }
915         if (io->in.acct_control != -1) {
916                 filter = talloc_asprintf_append_buffer(filter, "(AAC=%s)", 
917                                                 ldap_encode_ndr_uint32(state, io->in.acct_control));
918                 if (tevent_req_nomem(filter, req)) {
919                         goto post;
920                 }
921         }
922         if (io->in.domain_sid) {
923                 struct dom_sid *sid = dom_sid_parse_talloc(state, io->in.domain_sid);
924                 if (tevent_req_nomem(sid, req)) {
925                         goto post;
926                 }
927                 filter = talloc_asprintf_append_buffer(filter, "(domainSid=%s)",
928                                                 ldap_encode_ndr_dom_sid(state, sid));
929                 if (tevent_req_nomem(filter, req)) {
930                         goto post;
931                 }
932         }
933         if (io->in.domain_guid) {
934                 struct GUID guid;
935                 NTSTATUS status;
936                 status = GUID_from_string(io->in.domain_guid, &guid);
937                 if (tevent_req_nterror(req, status)) {
938                         goto post;
939                 }
940                 filter = talloc_asprintf_append_buffer(filter, "(DomainGuid=%s)",
941                                                 ldap_encode_ndr_GUID(state, &guid));
942                 if (tevent_req_nomem(filter, req)) {
943                         goto post;
944                 }
945         }
946         filter = talloc_asprintf_append_buffer(filter, ")");
947         if (tevent_req_nomem(filter, req)) {
948                 goto post;
949         }
950
951         if (io->in.dest_address) {
952                 state->search.in.dest_address = talloc_strdup(state,
953                                                 io->in.dest_address);
954                 if (tevent_req_nomem(state->search.in.dest_address, req)) {
955                         goto post;
956                 }
957                 state->search.in.dest_port = io->in.dest_port;
958         } else {
959                 state->search.in.dest_address   = NULL;
960                 state->search.in.dest_port      = 0;
961         }
962         state->search.in.filter         = filter;
963         state->search.in.attributes     = attr;
964         state->search.in.timeout        = 2;
965         state->search.in.retries        = 2;
966
967         subreq = cldap_search_send(state, ev, cldap, &state->search);
968         if (tevent_req_nomem(subreq, req)) {
969                 goto post;
970         }
971         tevent_req_set_callback(subreq, cldap_netlogon_state_done, req);
972
973         return req;
974 post:
975         return tevent_req_post(req, ev);
976 }
977
978 static void cldap_netlogon_state_done(struct tevent_req *subreq)
979 {
980         struct tevent_req *req = tevent_req_callback_data(subreq,
981                                  struct tevent_req);
982         struct cldap_netlogon_state *state = tevent_req_data(req,
983                                              struct cldap_netlogon_state);
984         NTSTATUS status;
985
986         status = cldap_search_recv(subreq, state, &state->search);
987         talloc_free(subreq);
988
989         if (tevent_req_nterror(req, status)) {
990                 return;
991         }
992
993         tevent_req_done(req);
994 }
995
996 /*
997   receive a cldap netlogon reply
998 */
999 NTSTATUS cldap_netlogon_recv(struct tevent_req *req,
1000                              TALLOC_CTX *mem_ctx,
1001                              struct cldap_netlogon *io)
1002 {
1003         struct cldap_netlogon_state *state = tevent_req_data(req,
1004                                              struct cldap_netlogon_state);
1005         NTSTATUS status;
1006         DATA_BLOB *data;
1007
1008         if (tevent_req_is_nterror(req, &status)) {
1009                 goto failed;
1010         }
1011
1012         if (state->search.out.response == NULL) {
1013                 status = NT_STATUS_NOT_FOUND;
1014                 goto failed;
1015         }
1016
1017         if (state->search.out.response->num_attributes != 1 ||
1018             strcasecmp(state->search.out.response->attributes[0].name, "netlogon") != 0 ||
1019             state->search.out.response->attributes[0].num_values != 1 ||
1020             state->search.out.response->attributes[0].values->length < 2) {
1021                 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1022                 goto failed;
1023         }
1024         data = state->search.out.response->attributes[0].values;
1025
1026         status = pull_netlogon_samlogon_response(data, mem_ctx,
1027                                                  &io->out.netlogon);
1028         if (!NT_STATUS_IS_OK(status)) {
1029                 goto failed;
1030         }
1031
1032         if (io->in.map_response) {
1033                 map_netlogon_samlogon_response(&io->out.netlogon);
1034         }
1035
1036         status =  NT_STATUS_OK;
1037 failed:
1038         tevent_req_received(req);
1039         return status;
1040 }
1041
1042 /*
1043   sync cldap netlogon search
1044 */
1045 NTSTATUS cldap_netlogon(struct cldap_socket *cldap,
1046                         TALLOC_CTX *mem_ctx,
1047                         struct cldap_netlogon *io)
1048 {
1049         TALLOC_CTX *frame;
1050         struct tevent_req *req;
1051         struct tevent_context *ev;
1052         NTSTATUS status;
1053
1054         if (cldap->searches.list) {
1055                 return NT_STATUS_PIPE_BUSY;
1056         }
1057
1058         if (cldap->incoming.handler) {
1059                 return NT_STATUS_INVALID_PIPE_STATE;
1060         }
1061
1062         frame = talloc_stackframe();
1063
1064         ev = tevent_context_init(frame);
1065         if (ev == NULL) {
1066                 TALLOC_FREE(frame);
1067                 return NT_STATUS_NO_MEMORY;
1068         }
1069
1070         req = cldap_netlogon_send(mem_ctx, ev, cldap, io);
1071         if (req == NULL) {
1072                 TALLOC_FREE(frame);
1073                 return NT_STATUS_NO_MEMORY;
1074         }
1075
1076         if (!tevent_req_poll(req, ev)) {
1077                 status = map_nt_error_from_unix_common(errno);
1078                 TALLOC_FREE(frame);
1079                 return status;
1080         }
1081
1082         status = cldap_netlogon_recv(req, mem_ctx, io);
1083         if (!NT_STATUS_IS_OK(status)) {
1084                 TALLOC_FREE(frame);
1085                 return status;
1086         }
1087
1088         TALLOC_FREE(frame);
1089         return NT_STATUS_OK;
1090 }
1091
1092
1093 /*
1094   send an empty reply (used on any error, so the client doesn't keep waiting
1095   or send the bad request again)
1096 */
1097 NTSTATUS cldap_empty_reply(struct cldap_socket *cldap,
1098                            uint32_t message_id,
1099                            struct tsocket_address *dest)
1100 {
1101         NTSTATUS status;
1102         struct cldap_reply reply;
1103         struct ldap_Result result;
1104
1105         reply.messageid    = message_id;
1106         reply.dest         = dest;
1107         reply.response     = NULL;
1108         reply.result       = &result;
1109
1110         ZERO_STRUCT(result);
1111
1112         status = cldap_reply_send(cldap, &reply);
1113
1114         return status;
1115 }
1116
1117 /*
1118   send an error reply (used on any error, so the client doesn't keep waiting
1119   or send the bad request again)
1120 */
1121 NTSTATUS cldap_error_reply(struct cldap_socket *cldap,
1122                            uint32_t message_id,
1123                            struct tsocket_address *dest,
1124                            int resultcode,
1125                            const char *errormessage)
1126 {
1127         NTSTATUS status;
1128         struct cldap_reply reply;
1129         struct ldap_Result result;
1130
1131         reply.messageid    = message_id;
1132         reply.dest         = dest;
1133         reply.response     = NULL;
1134         reply.result       = &result;
1135
1136         ZERO_STRUCT(result);
1137         result.resultcode       = resultcode;
1138         result.errormessage     = errormessage;
1139
1140         status = cldap_reply_send(cldap, &reply);
1141
1142         return status;
1143 }
1144
1145
1146 /*
1147   send a netlogon reply 
1148 */
1149 NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap,
1150                               uint32_t message_id,
1151                               struct tsocket_address *dest,
1152                               uint32_t version,
1153                               struct netlogon_samlogon_response *netlogon)
1154 {
1155         NTSTATUS status;
1156         struct cldap_reply reply;
1157         struct ldap_SearchResEntry response;
1158         struct ldap_Result result;
1159         TALLOC_CTX *tmp_ctx = talloc_new(cldap);
1160         DATA_BLOB blob;
1161
1162         status = push_netlogon_samlogon_response(&blob, tmp_ctx,
1163                                                  netlogon);
1164         if (!NT_STATUS_IS_OK(status)) {
1165                 talloc_free(tmp_ctx);
1166                 return status;
1167         }
1168         reply.messageid    = message_id;
1169         reply.dest         = dest;
1170         reply.response     = &response;
1171         reply.result       = &result;
1172
1173         ZERO_STRUCT(result);
1174
1175         response.dn = "";
1176         response.num_attributes = 1;
1177         response.attributes = talloc(tmp_ctx, struct ldb_message_element);
1178         NT_STATUS_HAVE_NO_MEMORY(response.attributes);
1179         response.attributes->name = "netlogon";
1180         response.attributes->num_values = 1;
1181         response.attributes->values = &blob;
1182
1183         status = cldap_reply_send(cldap, &reply);
1184
1185         talloc_free(tmp_ctx);
1186
1187         return status;
1188 }
1189