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