87f82b9b0dec7238b555e6ef5253453542f5dc0c
[metze/samba/wip.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 (state->caller.cldap == NULL) {
589                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
590                 goto post;
591         }
592
593         if (io->in.dest_address) {
594                 if (cldap->connected) {
595                         tevent_req_nterror(req, NT_STATUS_PIPE_CONNECTED);
596                         goto post;
597                 }
598                 ret = tsocket_address_inet_from_strings(state,
599                                                         "ip",
600                                                         io->in.dest_address,
601                                                         io->in.dest_port,
602                                                         &state->request.dest);
603                 if (ret != 0) {
604                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
605                         goto post;
606                 }
607         } else {
608                 if (!cldap->connected) {
609                         tevent_req_nterror(req, NT_STATUS_INVALID_ADDRESS);
610                         goto post;
611                 }
612                 state->request.dest = NULL;
613         }
614
615         state->message_id = idr_get_new_random(cldap->searches.idr,
616                                                state, UINT16_MAX);
617         if (state->message_id == -1) {
618                 tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
619                 goto post;
620         }
621
622         msg = talloc(state, struct ldap_message);
623         if (tevent_req_nomem(msg, req)) {
624                 goto post;
625         }
626
627         msg->messageid  = state->message_id;
628         msg->type       = LDAP_TAG_SearchRequest;
629         msg->controls   = NULL;
630         search = &msg->r.SearchRequest;
631
632         search->basedn          = "";
633         search->scope           = LDAP_SEARCH_SCOPE_BASE;
634         search->deref           = LDAP_DEREFERENCE_NEVER;
635         search->timelimit       = 0;
636         search->sizelimit       = 0;
637         search->attributesonly  = false;
638         search->num_attributes  = str_list_length(io->in.attributes);
639         search->attributes      = io->in.attributes;
640         search->tree            = ldb_parse_tree(msg, io->in.filter);
641         if (tevent_req_nomem(search->tree, req)) {
642                 goto post;
643         }
644
645         if (!ldap_encode(msg, NULL, &state->request.blob, state)) {
646                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
647                 goto post;
648         }
649         talloc_free(msg);
650
651         state->request.idx = 0;
652         state->request.delay = 10*1000*1000;
653         state->request.count = 3;
654         if (io->in.timeout > 0) {
655                 state->request.delay = io->in.timeout * 1000 * 1000;
656                 state->request.count = io->in.retries + 1;
657         }
658
659         now = tevent_timeval_current();
660         end = now;
661         for (i = 0; i < state->request.count; i++) {
662                 end = tevent_timeval_add(&end, state->request.delay / 1000000,
663                                          state->request.delay % 1000000);
664         }
665
666         if (!tevent_req_set_endtime(req, state->caller.ev, end)) {
667                 tevent_req_oom(req);
668                 goto post;
669         }
670
671         subreq = tdgram_sendto_queue_send(state,
672                                           state->caller.ev,
673                                           state->caller.cldap->sock,
674                                           state->caller.cldap->send_queue,
675                                           state->request.blob.data,
676                                           state->request.blob.length,
677                                           state->request.dest);
678         if (tevent_req_nomem(subreq, req)) {
679                 goto post;
680         }
681         tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
682
683         DLIST_ADD_END(cldap->searches.list, state);
684
685         return req;
686
687  post:
688         return tevent_req_post(req, state->caller.ev);
689 }
690
691 static void cldap_search_state_queue_done(struct tevent_req *subreq)
692 {
693         struct tevent_req *req = tevent_req_callback_data(subreq,
694                                  struct tevent_req);
695         struct cldap_search_state *state = tevent_req_data(req,
696                                            struct cldap_search_state);
697         ssize_t ret;
698         int sys_errno = 0;
699         struct timeval next;
700
701         ret = tdgram_sendto_queue_recv(subreq, &sys_errno);
702         talloc_free(subreq);
703         if (ret == -1) {
704                 NTSTATUS status;
705                 status = map_nt_error_from_unix_common(sys_errno);
706                 DLIST_REMOVE(state->caller.cldap->searches.list, state);
707                 ZERO_STRUCT(state->caller.cldap);
708                 tevent_req_nterror(req, status);
709                 return;
710         }
711
712         state->request.idx++;
713
714         /* wait for incoming traffic */
715         if (!cldap_recvfrom_setup(state->caller.cldap)) {
716                 tevent_req_oom(req);
717                 return;
718         }
719
720         if (state->request.idx > state->request.count) {
721                 /* we just wait for the response or a timeout */
722                 return;
723         }
724
725         next = tevent_timeval_current_ofs(state->request.delay / 1000000,
726                                           state->request.delay % 1000000);
727         subreq = tevent_wakeup_send(state,
728                                     state->caller.ev,
729                                     next);
730         if (tevent_req_nomem(subreq, req)) {
731                 return;
732         }
733         tevent_req_set_callback(subreq, cldap_search_state_wakeup_done, req);
734 }
735
736 static void cldap_search_state_wakeup_done(struct tevent_req *subreq)
737 {
738         struct tevent_req *req = tevent_req_callback_data(subreq,
739                                  struct tevent_req);
740         struct cldap_search_state *state = tevent_req_data(req,
741                                            struct cldap_search_state);
742         bool ok;
743
744         ok = tevent_wakeup_recv(subreq);
745         talloc_free(subreq);
746         if (!ok) {
747                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
748                 return;
749         }
750
751         subreq = tdgram_sendto_queue_send(state,
752                                           state->caller.ev,
753                                           state->caller.cldap->sock,
754                                           state->caller.cldap->send_queue,
755                                           state->request.blob.data,
756                                           state->request.blob.length,
757                                           state->request.dest);
758         if (tevent_req_nomem(subreq, req)) {
759                 return;
760         }
761         tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
762 }
763
764 /*
765   receive a cldap reply
766 */
767 NTSTATUS cldap_search_recv(struct tevent_req *req,
768                            TALLOC_CTX *mem_ctx,
769                            struct cldap_search *io)
770 {
771         struct cldap_search_state *state = tevent_req_data(req,
772                                            struct cldap_search_state);
773         struct ldap_message *ldap_msg;
774         NTSTATUS status;
775
776         if (tevent_req_is_nterror(req, &status)) {
777                 goto failed;
778         }
779
780         ldap_msg = talloc(mem_ctx, struct ldap_message);
781         if (!ldap_msg) {
782                 goto nomem;
783         }
784
785         status = ldap_decode(state->response.asn1, NULL, ldap_msg);
786         if (!NT_STATUS_IS_OK(status)) {
787                 goto failed;
788         }
789
790         ZERO_STRUCT(io->out);
791
792         /* the first possible form has a search result in first place */
793         if (ldap_msg->type == LDAP_TAG_SearchResultEntry) {
794                 io->out.response = talloc(mem_ctx, struct ldap_SearchResEntry);
795                 if (!io->out.response) {
796                         goto nomem;
797                 }
798                 *io->out.response = ldap_msg->r.SearchResultEntry;
799
800                 /* decode the 2nd part */
801                 status = ldap_decode(state->response.asn1, NULL, ldap_msg);
802                 if (!NT_STATUS_IS_OK(status)) {
803                         goto failed;
804                 }
805         }
806
807         if (ldap_msg->type != LDAP_TAG_SearchResultDone) {
808                 status = NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
809                 goto failed;
810         }
811
812         io->out.result = talloc(mem_ctx, struct ldap_Result);
813         if (!io->out.result) {
814                 goto nomem;
815         }
816         *io->out.result = ldap_msg->r.SearchResultDone;
817
818         if (io->out.result->resultcode != LDAP_SUCCESS) {
819                 status = NT_STATUS_LDAP(io->out.result->resultcode);
820                 goto failed;
821         }
822
823         tevent_req_received(req);
824         return NT_STATUS_OK;
825
826 nomem:
827         status = NT_STATUS_NO_MEMORY;
828 failed:
829         tevent_req_received(req);
830         return status;
831 }
832
833
834 /*
835   synchronous cldap search
836 */
837 NTSTATUS cldap_search(struct cldap_socket *cldap,
838                       TALLOC_CTX *mem_ctx,
839                       struct cldap_search *io)
840 {
841         TALLOC_CTX *frame;
842         struct tevent_req *req;
843         struct tevent_context *ev;
844         NTSTATUS status;
845
846         if (cldap->searches.list) {
847                 return NT_STATUS_PIPE_BUSY;
848         }
849
850         if (cldap->incoming.handler) {
851                 return NT_STATUS_INVALID_PIPE_STATE;
852         }
853
854         frame = talloc_stackframe();
855
856         ev = samba_tevent_context_init(frame);
857         if (ev == NULL) {
858                 TALLOC_FREE(frame);
859                 return NT_STATUS_NO_MEMORY;
860         }
861
862         req = cldap_search_send(mem_ctx, ev, cldap, io);
863         if (req == NULL) {
864                 TALLOC_FREE(frame);
865                 return NT_STATUS_NO_MEMORY;
866         }
867
868         if (!tevent_req_poll(req, ev)) {
869                 status = map_nt_error_from_unix_common(errno);
870                 TALLOC_FREE(frame);
871                 return status;
872         }
873
874         status = cldap_search_recv(req, mem_ctx, io);
875         if (!NT_STATUS_IS_OK(status)) {
876                 TALLOC_FREE(frame);
877                 return status;
878         }
879
880         TALLOC_FREE(frame);
881         return NT_STATUS_OK;
882 }
883
884 struct cldap_netlogon_state {
885         struct cldap_search search;
886 };
887
888 char *cldap_netlogon_create_filter(TALLOC_CTX *mem_ctx,
889                                    const struct cldap_netlogon *io)
890 {
891         char *filter;
892
893         filter = talloc_asprintf(mem_ctx, "(&(NtVer=%s)",
894                                  ldap_encode_ndr_uint32(mem_ctx, io->in.version));
895         if (filter == NULL)
896                 return NULL;
897
898         if (io->in.user) {
899                 filter = talloc_asprintf_append_buffer(filter, "(User=%s)", io->in.user);
900                 if (filter == NULL) {
901                         return NULL;
902                 }
903         }
904         if (io->in.host) {
905                 filter = talloc_asprintf_append_buffer(filter, "(Host=%s)", io->in.host);
906                 if (filter == NULL) {
907                         return NULL;
908                 }
909         }
910         if (io->in.realm) {
911                 filter = talloc_asprintf_append_buffer(filter, "(DnsDomain=%s)", io->in.realm);
912                 if (filter == NULL) {
913                         return NULL;
914                 }
915         }
916         if (io->in.acct_control != -1) {
917                 filter = talloc_asprintf_append_buffer(filter, "(AAC=%s)", 
918                                                 ldap_encode_ndr_uint32(mem_ctx, io->in.acct_control));
919                 if (filter == NULL) {
920                         return NULL;
921                 }
922         }
923         if (io->in.domain_sid) {
924                 struct dom_sid *sid = dom_sid_parse_talloc(mem_ctx, io->in.domain_sid);
925
926                 filter = talloc_asprintf_append_buffer(filter, "(domainSid=%s)",
927                                                 ldap_encode_ndr_dom_sid(mem_ctx, sid));
928                 if (filter == NULL) {
929                         return NULL;
930                 }
931         }
932         if (io->in.domain_guid) {
933                 struct GUID guid;
934                 GUID_from_string(io->in.domain_guid, &guid);
935
936                 filter = talloc_asprintf_append_buffer(filter, "(DomainGuid=%s)",
937                                                 ldap_encode_ndr_GUID(mem_ctx, &guid));
938                 if (filter == NULL) {
939                         return NULL;
940                 }
941         }
942         filter = talloc_asprintf_append_buffer(filter, ")");
943
944         return filter;
945 }
946
947 static void cldap_netlogon_state_done(struct tevent_req *subreq);
948 /*
949   queue a cldap netlogon for send
950 */
951 struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx,
952                                        struct tevent_context *ev,
953                                        struct cldap_socket *cldap,
954                                        const struct cldap_netlogon *io)
955 {
956         struct tevent_req *req, *subreq;
957         struct cldap_netlogon_state *state;
958         char *filter;
959         static const char * const attr[] = { "NetLogon", NULL };
960
961         req = tevent_req_create(mem_ctx, &state,
962                                 struct cldap_netlogon_state);
963         if (!req) {
964                 return NULL;
965         }
966
967         filter = cldap_netlogon_create_filter(state, io);
968         if (tevent_req_nomem(filter, req)) {
969                 goto post;
970         }
971
972         if (io->in.dest_address) {
973                 state->search.in.dest_address = talloc_strdup(state,
974                                                 io->in.dest_address);
975                 if (tevent_req_nomem(state->search.in.dest_address, req)) {
976                         goto post;
977                 }
978                 state->search.in.dest_port = io->in.dest_port;
979         } else {
980                 state->search.in.dest_address   = NULL;
981                 state->search.in.dest_port      = 0;
982         }
983         state->search.in.filter         = filter;
984         state->search.in.attributes     = attr;
985         state->search.in.timeout        = 2;
986         state->search.in.retries        = 2;
987
988         subreq = cldap_search_send(state, ev, cldap, &state->search);
989         if (tevent_req_nomem(subreq, req)) {
990                 goto post;
991         }
992         tevent_req_set_callback(subreq, cldap_netlogon_state_done, req);
993
994         return req;
995 post:
996         return tevent_req_post(req, ev);
997 }
998
999 static void cldap_netlogon_state_done(struct tevent_req *subreq)
1000 {
1001         struct tevent_req *req = tevent_req_callback_data(subreq,
1002                                  struct tevent_req);
1003         struct cldap_netlogon_state *state = tevent_req_data(req,
1004                                              struct cldap_netlogon_state);
1005         NTSTATUS status;
1006
1007         status = cldap_search_recv(subreq, state, &state->search);
1008         talloc_free(subreq);
1009
1010         if (tevent_req_nterror(req, status)) {
1011                 return;
1012         }
1013
1014         tevent_req_done(req);
1015 }
1016
1017 /*
1018   receive a cldap netlogon reply
1019 */
1020 NTSTATUS cldap_netlogon_recv(struct tevent_req *req,
1021                              TALLOC_CTX *mem_ctx,
1022                              struct cldap_netlogon *io)
1023 {
1024         struct cldap_netlogon_state *state = tevent_req_data(req,
1025                                              struct cldap_netlogon_state);
1026         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1027         DATA_BLOB *data;
1028
1029         if (tevent_req_is_nterror(req, &status)) {
1030                 goto failed;
1031         }
1032
1033         if (state->search.out.response == NULL) {
1034                 status = NT_STATUS_NOT_FOUND;
1035                 goto failed;
1036         }
1037
1038         if (state->search.out.response->num_attributes != 1 ||
1039             strcasecmp(state->search.out.response->attributes[0].name, "netlogon") != 0 ||
1040             state->search.out.response->attributes[0].num_values != 1 ||
1041             state->search.out.response->attributes[0].values->length < 2) {
1042                 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1043                 goto failed;
1044         }
1045         data = state->search.out.response->attributes[0].values;
1046
1047         status = pull_netlogon_samlogon_response(data, mem_ctx,
1048                                                  &io->out.netlogon);
1049         if (!NT_STATUS_IS_OK(status)) {
1050                 goto failed;
1051         }
1052
1053         if (io->in.map_response) {
1054                 map_netlogon_samlogon_response(&io->out.netlogon);
1055         }
1056
1057         status =  NT_STATUS_OK;
1058 failed:
1059         tevent_req_received(req);
1060         return status;
1061 }
1062
1063 /*
1064   sync cldap netlogon search
1065 */
1066 NTSTATUS cldap_netlogon(struct cldap_socket *cldap,
1067                         TALLOC_CTX *mem_ctx,
1068                         struct cldap_netlogon *io)
1069 {
1070         TALLOC_CTX *frame;
1071         struct tevent_req *req;
1072         struct tevent_context *ev;
1073         NTSTATUS status;
1074
1075         if (cldap->searches.list) {
1076                 return NT_STATUS_PIPE_BUSY;
1077         }
1078
1079         if (cldap->incoming.handler) {
1080                 return NT_STATUS_INVALID_PIPE_STATE;
1081         }
1082
1083         frame = talloc_stackframe();
1084
1085         ev = samba_tevent_context_init(frame);
1086         if (ev == NULL) {
1087                 TALLOC_FREE(frame);
1088                 return NT_STATUS_NO_MEMORY;
1089         }
1090
1091         req = cldap_netlogon_send(mem_ctx, ev, cldap, io);
1092         if (req == NULL) {
1093                 TALLOC_FREE(frame);
1094                 return NT_STATUS_NO_MEMORY;
1095         }
1096
1097         if (!tevent_req_poll(req, ev)) {
1098                 status = map_nt_error_from_unix_common(errno);
1099                 TALLOC_FREE(frame);
1100                 return status;
1101         }
1102
1103         status = cldap_netlogon_recv(req, mem_ctx, io);
1104         if (!NT_STATUS_IS_OK(status)) {
1105                 TALLOC_FREE(frame);
1106                 return status;
1107         }
1108
1109         TALLOC_FREE(frame);
1110         return NT_STATUS_OK;
1111 }
1112
1113
1114 /*
1115   send an empty reply (used on any error, so the client doesn't keep waiting
1116   or send the bad request again)
1117 */
1118 NTSTATUS cldap_empty_reply(struct cldap_socket *cldap,
1119                            uint32_t message_id,
1120                            struct tsocket_address *dest)
1121 {
1122         NTSTATUS status;
1123         struct cldap_reply reply;
1124         struct ldap_Result result;
1125
1126         reply.messageid    = message_id;
1127         reply.dest         = dest;
1128         reply.response     = NULL;
1129         reply.result       = &result;
1130
1131         ZERO_STRUCT(result);
1132
1133         status = cldap_reply_send(cldap, &reply);
1134
1135         return status;
1136 }
1137
1138 /*
1139   send an error reply (used on any error, so the client doesn't keep waiting
1140   or send the bad request again)
1141 */
1142 NTSTATUS cldap_error_reply(struct cldap_socket *cldap,
1143                            uint32_t message_id,
1144                            struct tsocket_address *dest,
1145                            int resultcode,
1146                            const char *errormessage)
1147 {
1148         NTSTATUS status;
1149         struct cldap_reply reply;
1150         struct ldap_Result result;
1151
1152         reply.messageid    = message_id;
1153         reply.dest         = dest;
1154         reply.response     = NULL;
1155         reply.result       = &result;
1156
1157         ZERO_STRUCT(result);
1158         result.resultcode       = resultcode;
1159         result.errormessage     = errormessage;
1160
1161         status = cldap_reply_send(cldap, &reply);
1162
1163         return status;
1164 }
1165
1166
1167 /*
1168   send a netlogon reply 
1169 */
1170 NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap,
1171                               uint32_t message_id,
1172                               struct tsocket_address *dest,
1173                               uint32_t version,
1174                               struct netlogon_samlogon_response *netlogon)
1175 {
1176         NTSTATUS status;
1177         struct cldap_reply reply;
1178         struct ldap_SearchResEntry response;
1179         struct ldap_Result result;
1180         TALLOC_CTX *tmp_ctx = talloc_new(cldap);
1181         DATA_BLOB blob;
1182
1183         status = push_netlogon_samlogon_response(&blob, tmp_ctx,
1184                                                  netlogon);
1185         if (!NT_STATUS_IS_OK(status)) {
1186                 talloc_free(tmp_ctx);
1187                 return status;
1188         }
1189         reply.messageid    = message_id;
1190         reply.dest         = dest;
1191         reply.response     = &response;
1192         reply.result       = &result;
1193
1194         ZERO_STRUCT(result);
1195
1196         response.dn = "";
1197         response.num_attributes = 1;
1198         response.attributes = talloc(tmp_ctx, struct ldb_message_element);
1199         NT_STATUS_HAVE_NO_MEMORY(response.attributes);
1200         response.attributes->name = "netlogon";
1201         response.attributes->num_values = 1;
1202         response.attributes->values = &blob;
1203
1204         status = cldap_reply_send(cldap, &reply);
1205
1206         talloc_free(tmp_ctx);
1207
1208         return status;
1209 }
1210