Use tevent_req_oom
[Samba/gebeck_regimport.git] / libcli / cldap / cldap.c
bloba5a0e415988abdf6ac1b9eaf1853c44df4ef2088
1 /*
2 Unix SMB/CIFS implementation.
4 cldap client library
6 Copyright (C) Andrew Tridgell 2005
7 Copyright (C) Stefan Metzmacher 2009
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.
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.
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/>.
24 see RFC1798 for details of CLDAP
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
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"
47 #undef strcasecmp
50 context structure for operations on cldap packets
52 struct cldap_socket {
53 /* the low level socket */
54 struct tdgram_context *sock;
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.
62 bool connected;
65 * we allow sync requests only, if the caller
66 * did not pass an event context to cldap_socket_init()
68 struct {
69 bool allow_poll;
70 struct tevent_context *ctx;
71 } event;
73 /* the queue for outgoing dgrams */
74 struct tevent_queue *send_queue;
76 /* do we have an async tsocket_recvfrom request pending */
77 struct tevent_req *recv_subreq;
79 struct {
80 /* a queue of pending search requests */
81 struct cldap_search_state *list;
83 /* mapping from message_id to pending request */
84 struct idr_context *idr;
85 } searches;
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;
96 struct cldap_search_state {
97 struct cldap_search_state *prev, *next;
99 struct {
100 struct cldap_socket *cldap;
101 } caller;
103 int message_id;
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;
113 struct {
114 struct cldap_incoming *in;
115 struct asn1_data *asn1;
116 } response;
118 struct tevent_req *req;
121 static int cldap_socket_destructor(struct cldap_socket *c)
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);
129 talloc_free(c->recv_subreq);
130 talloc_free(c->send_queue);
131 talloc_free(c->sock);
132 return 0;
135 static void cldap_recvfrom_done(struct tevent_req *subreq);
137 static bool cldap_recvfrom_setup(struct cldap_socket *c)
139 if (c->recv_subreq) {
140 return true;
143 if (!c->searches.list && !c->incoming.handler) {
144 return true;
147 c->recv_subreq = tdgram_recvfrom_send(c, c->event.ctx, c->sock);
148 if (!c->recv_subreq) {
149 return false;
151 tevent_req_set_callback(c->recv_subreq, cldap_recvfrom_done, c);
153 return true;
156 static void cldap_recvfrom_stop(struct cldap_socket *c)
158 if (!c->recv_subreq) {
159 return;
162 if (c->searches.list || c->incoming.handler) {
163 return;
166 talloc_free(c->recv_subreq);
167 c->recv_subreq = NULL;
170 static bool cldap_socket_recv_dgram(struct cldap_socket *c,
171 struct cldap_incoming *in);
173 static void cldap_recvfrom_done(struct tevent_req *subreq)
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;
181 c->recv_subreq = NULL;
183 in = talloc_zero(c, struct cldap_incoming);
184 if (!in) {
185 goto nomem;
188 ret = tdgram_recvfrom_recv(subreq,
189 &in->recv_errno,
191 &in->buf,
192 &in->src);
193 talloc_free(subreq);
194 subreq = NULL;
195 if (ret >= 0) {
196 in->len = ret;
198 if (ret == -1 && in->recv_errno == 0) {
199 in->recv_errno = EIO;
202 /* this function should free or steal 'in' */
203 setup_done = cldap_socket_recv_dgram(c, in);
204 in = NULL;
206 if (!setup_done && !cldap_recvfrom_setup(c)) {
207 goto nomem;
210 return;
212 nomem:
213 talloc_free(subreq);
214 talloc_free(in);
215 /*TODO: call a dead socket handler */
216 return;
220 handle recv events on a cldap socket
222 static bool cldap_socket_recv_dgram(struct cldap_socket *c,
223 struct cldap_incoming *in)
225 DATA_BLOB blob;
226 struct asn1_data *asn1;
227 void *p;
228 struct cldap_search_state *search;
229 NTSTATUS status;
231 if (in->recv_errno != 0) {
232 goto error;
235 blob = data_blob_const(in->buf, in->len);
237 asn1 = asn1_init(in);
238 if (!asn1) {
239 goto nomem;
242 if (!asn1_load(asn1, blob)) {
243 goto nomem;
246 in->ldap_msg = talloc(in, struct ldap_message);
247 if (in->ldap_msg == NULL) {
248 goto nomem;
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;
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;
264 /* this function should free or steal 'in' */
265 c->incoming.handler(c, c->incoming.private_data, in);
266 return false;
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;
274 DLIST_REMOVE(c->searches.list, search);
276 if (!cldap_recvfrom_setup(c)) {
277 goto nomem;
280 tevent_req_done(search->req);
281 talloc_free(in);
282 return true;
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;
294 if (!c->searches.list) {
295 goto done;
297 tevent_req_nterror(c->searches.list->req, status);
298 done:
299 talloc_free(in);
300 return false;
304 initialise a cldap_sock
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)
312 struct cldap_socket *c = NULL;
313 struct tsocket_address *any = NULL;
314 NTSTATUS status;
315 int ret;
317 c = talloc_zero(mem_ctx, struct cldap_socket);
318 if (!c) {
319 goto nomem;
322 if (!ev) {
323 ev = tevent_context_init(c);
324 if (!ev) {
325 goto nomem;
327 c->event.allow_poll = true;
329 c->event.ctx = ev;
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;
343 local_addr = any;
346 c->searches.idr = idr_init(c);
347 if (!c->searches.idr) {
348 goto nomem;
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;
357 talloc_free(any);
359 if (remote_addr) {
360 c->connected = true;
363 c->send_queue = tevent_queue_create(c, "cldap_send_queue");
364 if (!c->send_queue) {
365 goto nomem;
368 talloc_set_destructor(c, cldap_socket_destructor);
370 *_cldap = c;
371 return NT_STATUS_OK;
373 nomem:
374 status = NT_STATUS_NO_MEMORY;
375 nterror:
376 talloc_free(c);
377 return status;
381 setup a handler for incoming requests
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)
389 if (c->connected) {
390 return NT_STATUS_PIPE_CONNECTED;
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;
398 c->incoming.handler = handler;
399 c->incoming.private_data = private_data;
401 if (!cldap_recvfrom_setup(c)) {
402 ZERO_STRUCT(c->incoming);
403 return NT_STATUS_NO_MEMORY;
406 return NT_STATUS_OK;
409 struct cldap_reply_state {
410 struct tsocket_address *dest;
411 DATA_BLOB blob;
414 static void cldap_reply_state_destroy(struct tevent_req *subreq);
417 queue a cldap reply for send
419 NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
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;
427 if (cldap->connected) {
428 return NT_STATUS_PIPE_CONNECTED;
431 if (!io->dest) {
432 return NT_STATUS_INVALID_ADDRESS;
435 state = talloc(cldap, struct cldap_reply_state);
436 NT_STATUS_HAVE_NO_MEMORY(state);
438 state->dest = tsocket_address_copy(io->dest, state);
439 if (!state->dest) {
440 goto nomem;
443 msg = talloc(state, struct ldap_message);
444 if (!msg) {
445 goto nomem;
448 msg->messageid = io->messageid;
449 msg->controls = NULL;
451 if (io->response) {
452 msg->type = LDAP_TAG_SearchResultEntry;
453 msg->r.SearchResultEntry = *io->response;
455 if (!ldap_encode(msg, NULL, &blob1, state)) {
456 status = NT_STATUS_INVALID_PARAMETER;
457 goto failed;
459 } else {
460 blob1 = data_blob(NULL, 0);
463 msg->type = LDAP_TAG_SearchResultDone;
464 msg->r.SearchResultDone = *io->result;
466 if (!ldap_encode(msg, NULL, &blob2, state)) {
467 status = NT_STATUS_INVALID_PARAMETER;
468 goto failed;
470 talloc_free(msg);
472 state->blob = data_blob_talloc(state, NULL, blob1.length + blob2.length);
473 if (!state->blob.data) {
474 goto nomem;
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);
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;
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);
495 return NT_STATUS_OK;
497 nomem:
498 status = NT_STATUS_NO_MEMORY;
499 failed:
500 talloc_free(state);
501 return status;
504 static void cldap_reply_state_destroy(struct tevent_req *subreq)
506 struct cldap_reply_state *state = tevent_req_callback_data(subreq,
507 struct cldap_reply_state);
509 /* we don't want to know the result here, we just free the state */
510 talloc_free(subreq);
511 talloc_free(state);
514 static int cldap_search_state_destructor(struct cldap_search_state *s)
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;
521 DLIST_REMOVE(s->caller.cldap->searches.list, s);
522 cldap_recvfrom_stop(s->caller.cldap);
523 ZERO_STRUCT(s->caller);
526 return 0;
529 static void cldap_search_state_queue_done(struct tevent_req *subreq);
530 static void cldap_search_state_wakeup_done(struct tevent_req *subreq);
533 queue a cldap reply for send
535 struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx,
536 struct cldap_socket *cldap,
537 const struct cldap_search *io)
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;
548 req = tevent_req_create(mem_ctx, &state,
549 struct cldap_search_state);
550 if (!req) {
551 return NULL;
553 ZERO_STRUCTP(state);
554 state->req = req;
555 state->caller.cldap = cldap;
556 state->message_id = -1;
558 talloc_set_destructor(state, cldap_search_state_destructor);
560 if (io->in.dest_address) {
561 if (cldap->connected) {
562 tevent_req_nterror(req, NT_STATUS_PIPE_CONNECTED);
563 goto post;
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;
574 } else {
575 if (!cldap->connected) {
576 tevent_req_nterror(req, NT_STATUS_INVALID_ADDRESS);
577 goto post;
579 state->request.dest = NULL;
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;
589 msg = talloc(state, struct ldap_message);
590 if (tevent_req_nomem(msg, req)) {
591 goto post;
594 msg->messageid = state->message_id;
595 msg->type = LDAP_TAG_SearchRequest;
596 msg->controls = NULL;
597 search = &msg->r.SearchRequest;
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;
612 if (!ldap_encode(msg, NULL, &state->request.blob, state)) {
613 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
614 goto post;
616 talloc_free(msg);
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;
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);
633 if (!tevent_req_set_endtime(req, state->caller.cldap->event.ctx, end)) {
634 tevent_req_oom(req);
635 goto post;
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;
648 tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
650 DLIST_ADD_END(cldap->searches.list, state, struct cldap_search_state *);
652 return req;
654 post:
655 return tevent_req_post(req, cldap->event.ctx);
658 static void cldap_search_state_queue_done(struct tevent_req *subreq)
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;
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;
679 state->request.idx++;
681 /* wait for incoming traffic */
682 if (!cldap_recvfrom_setup(state->caller.cldap)) {
683 tevent_req_oom(req);
684 return;
687 if (state->request.idx > state->request.count) {
688 /* we just wait for the response or a timeout */
689 return;
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;
700 tevent_req_set_callback(subreq, cldap_search_state_wakeup_done, req);
703 static void cldap_search_state_wakeup_done(struct tevent_req *subreq)
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;
711 ok = tevent_wakeup_recv(subreq);
712 talloc_free(subreq);
713 if (!ok) {
714 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
715 return;
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;
728 tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
732 receive a cldap reply
734 NTSTATUS cldap_search_recv(struct tevent_req *req,
735 TALLOC_CTX *mem_ctx,
736 struct cldap_search *io)
738 struct cldap_search_state *state = tevent_req_data(req,
739 struct cldap_search_state);
740 struct ldap_message *ldap_msg;
741 NTSTATUS status;
743 if (tevent_req_is_nterror(req, &status)) {
744 goto failed;
747 ldap_msg = talloc(mem_ctx, struct ldap_message);
748 if (!ldap_msg) {
749 goto nomem;
752 status = ldap_decode(state->response.asn1, NULL, ldap_msg);
753 if (!NT_STATUS_IS_OK(status)) {
754 goto failed;
757 ZERO_STRUCT(io->out);
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;
765 *io->out.response = ldap_msg->r.SearchResultEntry;
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;
774 if (ldap_msg->type != LDAP_TAG_SearchResultDone) {
775 status = NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
776 goto failed;
779 io->out.result = talloc(mem_ctx, struct ldap_Result);
780 if (!io->out.result) {
781 goto nomem;
783 *io->out.result = ldap_msg->r.SearchResultDone;
785 if (io->out.result->resultcode != LDAP_SUCCESS) {
786 status = NT_STATUS_LDAP(io->out.result->resultcode);
787 goto failed;
790 tevent_req_received(req);
791 return NT_STATUS_OK;
793 nomem:
794 status = NT_STATUS_NO_MEMORY;
795 failed:
796 tevent_req_received(req);
797 return status;
802 synchronous cldap search
804 NTSTATUS cldap_search(struct cldap_socket *cldap,
805 TALLOC_CTX *mem_ctx,
806 struct cldap_search *io)
808 struct tevent_req *req;
809 NTSTATUS status;
811 if (!cldap->event.allow_poll) {
812 return NT_STATUS_INVALID_PIPE_STATE;
815 if (cldap->searches.list) {
816 return NT_STATUS_PIPE_BUSY;
819 req = cldap_search_send(mem_ctx, cldap, io);
820 NT_STATUS_HAVE_NO_MEMORY(req);
822 if (!tevent_req_poll(req, cldap->event.ctx)) {
823 talloc_free(req);
824 return NT_STATUS_INTERNAL_ERROR;
827 status = cldap_search_recv(req, mem_ctx, io);
828 talloc_free(req);
830 return status;
833 struct cldap_netlogon_state {
834 struct cldap_search search;
837 static void cldap_netlogon_state_done(struct tevent_req *subreq);
839 queue a cldap netlogon for send
841 struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx,
842 struct cldap_socket *cldap,
843 const struct cldap_netlogon *io)
845 struct tevent_req *req, *subreq;
846 struct cldap_netlogon_state *state;
847 char *filter;
848 static const char * const attr[] = { "NetLogon", NULL };
850 req = tevent_req_create(mem_ctx, &state,
851 struct cldap_netlogon_state);
852 if (!req) {
853 return NULL;
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;
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;
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;
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;
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;
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;
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;
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;
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;
910 filter = talloc_asprintf_append_buffer(filter, ")");
911 if (tevent_req_nomem(filter, req)) {
912 goto post;
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;
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;
926 state->search.in.filter = filter;
927 state->search.in.attributes = attr;
928 state->search.in.timeout = 2;
929 state->search.in.retries = 2;
931 subreq = cldap_search_send(state, cldap, &state->search);
932 if (tevent_req_nomem(subreq, req)) {
933 goto post;
935 tevent_req_set_callback(subreq, cldap_netlogon_state_done, req);
937 return req;
938 post:
939 return tevent_req_post(req, cldap->event.ctx);
942 static void cldap_netlogon_state_done(struct tevent_req *subreq)
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;
950 status = cldap_search_recv(subreq, state, &state->search);
951 talloc_free(subreq);
953 if (tevent_req_nterror(req, status)) {
954 return;
957 tevent_req_done(req);
961 receive a cldap netlogon reply
963 NTSTATUS cldap_netlogon_recv(struct tevent_req *req,
964 TALLOC_CTX *mem_ctx,
965 struct cldap_netlogon *io)
967 struct cldap_netlogon_state *state = tevent_req_data(req,
968 struct cldap_netlogon_state);
969 NTSTATUS status;
970 DATA_BLOB *data;
972 if (tevent_req_is_nterror(req, &status)) {
973 goto failed;
976 if (state->search.out.response == NULL) {
977 status = NT_STATUS_NOT_FOUND;
978 goto failed;
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;
988 data = state->search.out.response->attributes[0].values;
990 status = pull_netlogon_samlogon_response(data, mem_ctx,
991 &io->out.netlogon);
992 if (!NT_STATUS_IS_OK(status)) {
993 goto failed;
996 if (io->in.map_response) {
997 map_netlogon_samlogon_response(&io->out.netlogon);
1000 status = NT_STATUS_OK;
1001 failed:
1002 tevent_req_received(req);
1003 return status;
1007 sync cldap netlogon search
1009 NTSTATUS cldap_netlogon(struct cldap_socket *cldap,
1010 TALLOC_CTX *mem_ctx,
1011 struct cldap_netlogon *io)
1013 struct tevent_req *req;
1014 NTSTATUS status;
1016 if (!cldap->event.allow_poll) {
1017 return NT_STATUS_INVALID_PIPE_STATE;
1020 if (cldap->searches.list) {
1021 return NT_STATUS_PIPE_BUSY;
1024 req = cldap_netlogon_send(mem_ctx, cldap, io);
1025 NT_STATUS_HAVE_NO_MEMORY(req);
1027 if (!tevent_req_poll(req, cldap->event.ctx)) {
1028 talloc_free(req);
1029 return NT_STATUS_INTERNAL_ERROR;
1032 status = cldap_netlogon_recv(req, mem_ctx, io);
1033 talloc_free(req);
1035 return status;
1040 send an empty reply (used on any error, so the client doesn't keep waiting
1041 or send the bad request again)
1043 NTSTATUS cldap_empty_reply(struct cldap_socket *cldap,
1044 uint32_t message_id,
1045 struct tsocket_address *dest)
1047 NTSTATUS status;
1048 struct cldap_reply reply;
1049 struct ldap_Result result;
1051 reply.messageid = message_id;
1052 reply.dest = dest;
1053 reply.response = NULL;
1054 reply.result = &result;
1056 ZERO_STRUCT(result);
1058 status = cldap_reply_send(cldap, &reply);
1060 return status;
1064 send an error reply (used on any error, so the client doesn't keep waiting
1065 or send the bad request again)
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)
1073 NTSTATUS status;
1074 struct cldap_reply reply;
1075 struct ldap_Result result;
1077 reply.messageid = message_id;
1078 reply.dest = dest;
1079 reply.response = NULL;
1080 reply.result = &result;
1082 ZERO_STRUCT(result);
1083 result.resultcode = resultcode;
1084 result.errormessage = errormessage;
1086 status = cldap_reply_send(cldap, &reply);
1088 return status;
1093 send a netlogon reply
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)
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;
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;
1114 reply.messageid = message_id;
1115 reply.dest = dest;
1116 reply.response = &response;
1117 reply.result = &result;
1119 ZERO_STRUCT(result);
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;
1129 status = cldap_reply_send(cldap, &reply);
1131 talloc_free(tmp_ctx);
1133 return status;