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