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