move source4/libcli/cldap => libcli/cldap
[bbaumbach/samba-autobuild/.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 tsocket_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         tsocket_disconnect(c->sock);
124
125         while (c->searches.list) {
126                 struct cldap_search_state *s = c->searches.list;
127                 DLIST_REMOVE(c->searches.list, s);
128                 ZERO_STRUCT(s->caller);
129         }
130
131         talloc_free(c->recv_subreq);
132         talloc_free(c->send_queue);
133         talloc_free(c->sock);
134         return 0;
135 }
136
137 static void cldap_recvfrom_done(struct tevent_req *subreq);
138
139 static bool cldap_recvfrom_setup(struct cldap_socket *c)
140 {
141         if (c->recv_subreq) {
142                 return true;
143         }
144
145         if (!c->searches.list && !c->incoming.handler) {
146                 return true;
147         }
148
149         c->recv_subreq = tsocket_recvfrom_send(c->sock, c);
150         if (!c->recv_subreq) {
151                 return false;
152         }
153         tevent_req_set_callback(c->recv_subreq, cldap_recvfrom_done, c);
154
155         return true;
156 }
157
158 static void cldap_recvfrom_stop(struct cldap_socket *c)
159 {
160         if (!c->recv_subreq) {
161                 return;
162         }
163
164         if (c->searches.list || c->incoming.handler) {
165                 return;
166         }
167
168         talloc_free(c->recv_subreq);
169         c->recv_subreq = NULL;
170 }
171
172 static void cldap_socket_recv_dgram(struct cldap_socket *c,
173                                     struct cldap_incoming *in);
174
175 static void cldap_recvfrom_done(struct tevent_req *subreq)
176 {
177         struct cldap_socket *c = tevent_req_callback_data(subreq,
178                                  struct cldap_socket);
179         struct cldap_incoming *in = NULL;
180         ssize_t ret;
181
182         c->recv_subreq = NULL;
183
184         in = talloc_zero(c, struct cldap_incoming);
185         if (!in) {
186                 goto nomem;
187         }
188
189         ret = tsocket_recvfrom_recv(subreq,
190                                     &in->recv_errno,
191                                     in,
192                                     &in->buf,
193                                     &in->src);
194         talloc_free(subreq);
195         subreq = NULL;
196         if (ret >= 0) {
197                 in->len = ret;
198         }
199         if (ret == -1 && in->recv_errno == 0) {
200                 in->recv_errno = EIO;
201         }
202
203         /* this function should free or steal 'in' */
204         cldap_socket_recv_dgram(c, in);
205         in = NULL;
206
207         if (!cldap_recvfrom_setup(c)) {
208                 goto nomem;
209         }
210
211         return;
212
213 nomem:
214         talloc_free(subreq);
215         talloc_free(in);
216         /*TODO: call a dead socket handler */
217         return;
218 }
219
220 /*
221   handle recv events on a cldap socket
222 */
223 static void cldap_socket_recv_dgram(struct cldap_socket *c,
224                                     struct cldap_incoming *in)
225 {
226         DATA_BLOB blob;
227         struct asn1_data *asn1;
228         void *p;
229         struct cldap_search_state *search;
230         NTSTATUS status;
231
232         if (in->recv_errno != 0) {
233                 goto error;
234         }
235
236         blob = data_blob_const(in->buf, in->len);
237
238         asn1 = asn1_init(in);
239         if (!asn1) {
240                 goto nomem;
241         }
242
243         if (!asn1_load(asn1, blob)) {
244                 goto nomem;
245         }
246
247         in->ldap_msg = talloc(in, struct ldap_message);
248         if (in->ldap_msg == NULL) {
249                 goto nomem;
250         }
251
252         /* this initial decode is used to find the message id */
253         status = ldap_decode(asn1, NULL, in->ldap_msg);
254         if (!NT_STATUS_IS_OK(status)) {
255                 goto nterror;
256         }
257
258         /* find the pending request */
259         p = idr_find(c->searches.idr, in->ldap_msg->messageid);
260         if (p == NULL) {
261                 if (!c->incoming.handler) {
262                         goto done;
263                 }
264
265                 /* this function should free or steal 'in' */
266                 c->incoming.handler(c, c->incoming.private_data, in);
267                 return;
268         }
269
270         search = talloc_get_type(p, struct cldap_search_state);
271         search->response.in = talloc_move(search, &in);
272         search->response.asn1 = asn1;
273         search->response.asn1->ofs = 0;
274
275         tevent_req_done(search->req);
276         goto done;
277
278 nomem:
279         in->recv_errno = ENOMEM;
280 error:
281         status = map_nt_error_from_unix(in->recv_errno);
282 nterror:
283         /* in connected mode the first pending search gets the error */
284         if (!c->connected) {
285                 /* otherwise we just ignore the error */
286                 goto done;
287         }
288         if (!c->searches.list) {
289                 goto done;
290         }
291         tevent_req_nterror(c->searches.list->req, status);
292 done:
293         talloc_free(in);
294 }
295
296 /*
297   initialise a cldap_sock
298 */
299 NTSTATUS cldap_socket_init(TALLOC_CTX *mem_ctx,
300                            struct tevent_context *ev,
301                            const struct tsocket_address *local_addr,
302                            const struct tsocket_address *remote_addr,
303                            struct cldap_socket **_cldap)
304 {
305         struct cldap_socket *c = NULL;
306         struct tsocket_address *any = NULL;
307         NTSTATUS status;
308         int ret;
309
310         c = talloc_zero(mem_ctx, struct cldap_socket);
311         if (!c) {
312                 goto nomem;
313         }
314
315         if (!ev) {
316                 ev = tevent_context_init(c);
317                 if (!ev) {
318                         goto nomem;
319                 }
320                 c->event.allow_poll = true;
321         }
322         c->event.ctx = ev;
323
324         if (!local_addr) {
325                 ret = tsocket_address_inet_from_strings(c, "ipv4",
326                                                         NULL, 0,
327                                                         &any);
328                 if (ret != 0) {
329                         status = map_nt_error_from_unix(errno);
330                         goto nterror;
331                 }
332                 local_addr = any;
333         }
334
335         c->searches.idr = idr_init(c);
336         if (!c->searches.idr) {
337                 goto nomem;
338         }
339
340         ret = tsocket_address_create_socket(local_addr,
341                                             TSOCKET_TYPE_DGRAM,
342                                             c, &c->sock);
343         if (ret != 0) {
344                 status = map_nt_error_from_unix(errno);
345                 goto nterror;
346         }
347         talloc_free(any);
348
349         tsocket_set_event_context(c->sock, c->event.ctx);
350
351         if (remote_addr) {
352                 ret = tsocket_connect(c->sock, remote_addr);
353                 if (ret != 0) {
354                         status = map_nt_error_from_unix(errno);
355                         goto nterror;
356                 }
357                 c->connected = true;
358         }
359
360         c->send_queue = tevent_queue_create(c, "cldap_send_queue");
361         if (!c->send_queue) {
362                 goto nomem;
363         }
364
365         talloc_set_destructor(c, cldap_socket_destructor);
366
367         *_cldap = c;
368         return NT_STATUS_OK;
369
370 nomem:
371         status = NT_STATUS_NO_MEMORY;
372 nterror:
373         talloc_free(c);
374         return status;
375 }
376
377 /*
378   setup a handler for incoming requests
379 */
380 NTSTATUS cldap_set_incoming_handler(struct cldap_socket *c,
381                                     void (*handler)(struct cldap_socket *,
382                                                     void *private_data,
383                                                     struct cldap_incoming *),
384                                     void *private_data)
385 {
386         if (c->connected) {
387                 return NT_STATUS_PIPE_CONNECTED;
388         }
389
390         /* if sync requests are allowed, we don't allow an incoming handler */
391         if (c->event.allow_poll) {
392                 return NT_STATUS_INVALID_PIPE_STATE;
393         }
394
395         c->incoming.handler = handler;
396         c->incoming.private_data = private_data;
397
398         if (!cldap_recvfrom_setup(c)) {
399                 ZERO_STRUCT(c->incoming);
400                 return NT_STATUS_NO_MEMORY;
401         }
402
403         return NT_STATUS_OK;
404 }
405
406 struct cldap_reply_state {
407         struct tsocket_address *dest;
408         DATA_BLOB blob;
409 };
410
411 static void cldap_reply_state_destroy(struct tevent_req *req);
412
413 /*
414   queue a cldap reply for send
415 */
416 NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
417 {
418         struct cldap_reply_state *state = NULL;
419         struct ldap_message *msg;
420         DATA_BLOB blob1, blob2;
421         NTSTATUS status;
422         struct tevent_req *req;
423
424         if (cldap->connected) {
425                 return NT_STATUS_PIPE_CONNECTED;
426         }
427
428         if (!io->dest) {
429                 return NT_STATUS_INVALID_ADDRESS;
430         }
431
432         state = talloc(cldap, struct cldap_reply_state);
433         NT_STATUS_HAVE_NO_MEMORY(state);
434
435         state->dest = tsocket_address_copy(io->dest, state);
436         if (!state->dest) {
437                 goto nomem;
438         }
439
440         msg = talloc(state, struct ldap_message);
441         if (!msg) {
442                 goto nomem;
443         }
444
445         msg->messageid       = io->messageid;
446         msg->controls        = NULL;
447
448         if (io->response) {
449                 msg->type = LDAP_TAG_SearchResultEntry;
450                 msg->r.SearchResultEntry = *io->response;
451
452                 if (!ldap_encode(msg, NULL, &blob1, state)) {
453                         status = NT_STATUS_INVALID_PARAMETER;
454                         goto failed;
455                 }
456         } else {
457                 blob1 = data_blob(NULL, 0);
458         }
459
460         msg->type = LDAP_TAG_SearchResultDone;
461         msg->r.SearchResultDone = *io->result;
462
463         if (!ldap_encode(msg, NULL, &blob2, state)) {
464                 status = NT_STATUS_INVALID_PARAMETER;
465                 goto failed;
466         }
467         talloc_free(msg);
468
469         state->blob = data_blob_talloc(state, NULL, blob1.length + blob2.length);
470         if (!state->blob.data) {
471                 goto nomem;
472         }
473
474         memcpy(state->blob.data, blob1.data, blob1.length);
475         memcpy(state->blob.data+blob1.length, blob2.data, blob2.length);
476         data_blob_free(&blob1);
477         data_blob_free(&blob2);
478
479         req = tsocket_sendto_queue_send(state,
480                                         cldap->sock,
481                                         cldap->send_queue,
482                                         state->blob.data,
483                                         state->blob.length,
484                                         state->dest);
485         if (!req) {
486                 goto nomem;
487         }
488         /* the callback will just free the state, as we don't need a result */
489         tevent_req_set_callback(req, cldap_reply_state_destroy, state);
490
491         return NT_STATUS_OK;
492
493 nomem:
494         status = NT_STATUS_NO_MEMORY;
495 failed:
496         talloc_free(state);
497         return status;
498 }
499
500 static void cldap_reply_state_destroy(struct tevent_req *req)
501 {
502         struct cldap_reply_state *state = tevent_req_callback_data(req,
503                                           struct cldap_reply_state);
504
505         /* we don't want to know the result here, we just free the state */
506         talloc_free(req);
507         talloc_free(state);
508 }
509
510 static int cldap_search_state_destructor(struct cldap_search_state *s)
511 {
512         if (s->caller.cldap) {
513                 DLIST_REMOVE(s->caller.cldap->searches.list, s);
514                 cldap_recvfrom_stop(s->caller.cldap);
515                 ZERO_STRUCT(s->caller);
516         }
517
518         return 0;
519 }
520
521 static void cldap_search_state_queue_done(struct tevent_req *subreq);
522 static void cldap_search_state_wakeup_done(struct tevent_req *subreq);
523
524 /*
525   queue a cldap reply for send
526 */
527 struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx,
528                                     struct cldap_socket *cldap,
529                                     const struct cldap_search *io)
530 {
531         struct tevent_req *req, *subreq;
532         struct cldap_search_state *state = NULL;
533         struct ldap_message *msg;
534         struct ldap_SearchRequest *search;
535         struct timeval now;
536         struct timeval end;
537         uint32_t i;
538         int ret;
539
540         req = tevent_req_create(mem_ctx, &state,
541                                 struct cldap_search_state);
542         if (!req) {
543                 return NULL;
544         }
545         state->req = req;
546         state->caller.cldap = cldap;
547
548         if (io->in.dest_address) {
549                 if (cldap->connected) {
550                         tevent_req_nterror(req, NT_STATUS_PIPE_CONNECTED);
551                         goto post;
552                 }
553                 ret = tsocket_address_inet_from_strings(state,
554                                                         "ipv4",
555                                                         io->in.dest_address,
556                                                         io->in.dest_port,
557                                                         &state->request.dest);
558                 if (ret != 0) {
559                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
560                         goto post;
561                 }
562         } else {
563                 if (!cldap->connected) {
564                         tevent_req_nterror(req, NT_STATUS_INVALID_ADDRESS);
565                         goto post;
566                 }
567                 state->request.dest = NULL;
568         }
569
570         state->message_id = idr_get_new_random(cldap->searches.idr,
571                                                state, UINT16_MAX);
572         if (state->message_id == -1) {
573                 tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
574                 goto post;
575         }
576
577         msg = talloc(state, struct ldap_message);
578         if (tevent_req_nomem(msg, req)) {
579                 goto post;
580         }
581
582         msg->messageid  = state->message_id;
583         msg->type       = LDAP_TAG_SearchRequest;
584         msg->controls   = NULL;
585         search = &msg->r.SearchRequest;
586
587         search->basedn          = "";
588         search->scope           = LDAP_SEARCH_SCOPE_BASE;
589         search->deref           = LDAP_DEREFERENCE_NEVER;
590         search->timelimit       = 0;
591         search->sizelimit       = 0;
592         search->attributesonly  = false;
593         search->num_attributes  = str_list_length(io->in.attributes);
594         search->attributes      = io->in.attributes;
595         search->tree            = ldb_parse_tree(msg, io->in.filter);
596         if (tevent_req_nomem(search->tree, req)) {
597                 goto post;
598         }
599
600         if (!ldap_encode(msg, NULL, &state->request.blob, state)) {
601                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
602                 goto post;
603         }
604         talloc_free(msg);
605
606         state->request.idx = 0;
607         state->request.delay = 10*1000*1000;
608         state->request.count = 3;
609         if (io->in.timeout > 0) {
610                 state->request.delay = io->in.timeout * 1000 * 1000;
611                 state->request.count = io->in.retries + 1;
612         }
613
614         now = tevent_timeval_current();
615         end = now;
616         for (i = 0; i < state->request.count; i++) {
617                 end = tevent_timeval_add(&end, 0, state->request.delay);
618         }
619
620         if (!tevent_req_set_endtime(req, state->caller.cldap->event.ctx, end)) {
621                 tevent_req_nomem(NULL, req);
622                 goto post;
623         }
624
625         subreq = tsocket_sendto_queue_send(state,
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         talloc_set_destructor(state, cldap_search_state_destructor);
638
639         return req;
640
641  post:
642         return tevent_req_post(req, cldap->event.ctx);
643 }
644
645 static void cldap_search_state_queue_done(struct tevent_req *subreq)
646 {
647         struct tevent_req *req = tevent_req_callback_data(subreq,
648                                  struct tevent_req);
649         struct cldap_search_state *state = tevent_req_data(req,
650                                            struct cldap_search_state);
651         ssize_t ret;
652         int sys_errno = 0;
653         struct timeval next;
654
655         ret = tsocket_sendto_queue_recv(subreq, &sys_errno);
656         talloc_free(subreq);
657         if (ret == -1) {
658                 NTSTATUS status;
659                 status = map_nt_error_from_unix(sys_errno);
660                 DLIST_REMOVE(state->caller.cldap->searches.list, state);
661                 ZERO_STRUCT(state->caller.cldap);
662                 tevent_req_nterror(req, status);
663                 return;
664         }
665
666         state->request.idx++;
667
668         /* wait for incoming traffic */
669         if (!cldap_recvfrom_setup(state->caller.cldap)) {
670                 tevent_req_nomem(NULL, req);
671                 return;
672         }
673
674         if (state->request.idx > state->request.count) {
675                 /* we just wait for the response or a timeout */
676                 return;
677         }
678
679         next = tevent_timeval_current_ofs(0, state->request.delay);
680         subreq = tevent_wakeup_send(state,
681                                     state->caller.cldap->event.ctx,
682                                     next);
683         if (tevent_req_nomem(subreq, req)) {
684                 return;
685         }
686         tevent_req_set_callback(subreq, cldap_search_state_wakeup_done, req);
687 }
688
689 static void cldap_search_state_wakeup_done(struct tevent_req *subreq)
690 {
691         struct tevent_req *req = tevent_req_callback_data(subreq,
692                                  struct tevent_req);
693         struct cldap_search_state *state = tevent_req_data(req,
694                                            struct cldap_search_state);
695         bool ok;
696
697         ok = tevent_wakeup_recv(subreq);
698         talloc_free(subreq);
699         if (!ok) {
700                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
701                 return;
702         }
703
704         subreq = tsocket_sendto_queue_send(state,
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