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