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