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