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