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