s4 dns: Split up the code into multiple files for easier development
[Samba.git] / libcli / cldap / cldap.c
blobf5585c2b730e16d7cd0484233f4ed20f0d6700da
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(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(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(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, 0, state->request.delay);
632 if (!tevent_req_set_endtime(req, state->caller.cldap->event.ctx, end)) {
633 tevent_req_nomem(NULL, req);
634 goto post;
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;
647 tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
649 DLIST_ADD_END(cldap->searches.list, state, struct cldap_search_state *);
651 return req;
653 post:
654 return tevent_req_post(req, cldap->event.ctx);
657 static void cldap_search_state_queue_done(struct tevent_req *subreq)
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;
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;
678 state->request.idx++;
680 /* wait for incoming traffic */
681 if (!cldap_recvfrom_setup(state->caller.cldap)) {
682 tevent_req_nomem(NULL, req);
683 return;
686 if (state->request.idx > state->request.count) {
687 /* we just wait for the response or a timeout */
688 return;
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;
698 tevent_req_set_callback(subreq, cldap_search_state_wakeup_done, req);
701 static void cldap_search_state_wakeup_done(struct tevent_req *subreq)
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;
709 ok = tevent_wakeup_recv(subreq);
710 talloc_free(subreq);
711 if (!ok) {
712 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
713 return;
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;
726 tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
730 receive a cldap reply
732 NTSTATUS cldap_search_recv(struct tevent_req *req,
733 TALLOC_CTX *mem_ctx,
734 struct cldap_search *io)
736 struct cldap_search_state *state = tevent_req_data(req,
737 struct cldap_search_state);
738 struct ldap_message *ldap_msg;
739 NTSTATUS status;
741 if (tevent_req_is_nterror(req, &status)) {
742 goto failed;
745 ldap_msg = talloc(mem_ctx, struct ldap_message);
746 if (!ldap_msg) {
747 goto nomem;
750 status = ldap_decode(state->response.asn1, NULL, ldap_msg);
751 if (!NT_STATUS_IS_OK(status)) {
752 goto failed;
755 ZERO_STRUCT(io->out);
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;
763 *io->out.response = ldap_msg->r.SearchResultEntry;
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;
772 if (ldap_msg->type != LDAP_TAG_SearchResultDone) {
773 status = NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
774 goto failed;
777 io->out.result = talloc(mem_ctx, struct ldap_Result);
778 if (!io->out.result) {
779 goto nomem;
781 *io->out.result = ldap_msg->r.SearchResultDone;
783 if (io->out.result->resultcode != LDAP_SUCCESS) {
784 status = NT_STATUS_LDAP(io->out.result->resultcode);
785 goto failed;
788 tevent_req_received(req);
789 return NT_STATUS_OK;
791 nomem:
792 status = NT_STATUS_NO_MEMORY;
793 failed:
794 tevent_req_received(req);
795 return status;
800 synchronous cldap search
802 NTSTATUS cldap_search(struct cldap_socket *cldap,
803 TALLOC_CTX *mem_ctx,
804 struct cldap_search *io)
806 struct tevent_req *req;
807 NTSTATUS status;
809 if (!cldap->event.allow_poll) {
810 return NT_STATUS_INVALID_PIPE_STATE;
813 if (cldap->searches.list) {
814 return NT_STATUS_PIPE_BUSY;
817 req = cldap_search_send(mem_ctx, cldap, io);
818 NT_STATUS_HAVE_NO_MEMORY(req);
820 if (!tevent_req_poll(req, cldap->event.ctx)) {
821 talloc_free(req);
822 return NT_STATUS_INTERNAL_ERROR;
825 status = cldap_search_recv(req, mem_ctx, io);
826 talloc_free(req);
828 return status;
831 struct cldap_netlogon_state {
832 struct cldap_search search;
835 static void cldap_netlogon_state_done(struct tevent_req *subreq);
837 queue a cldap netlogon for send
839 struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx,
840 struct cldap_socket *cldap,
841 const struct cldap_netlogon *io)
843 struct tevent_req *req, *subreq;
844 struct cldap_netlogon_state *state;
845 char *filter;
846 static const char * const attr[] = { "NetLogon", NULL };
848 req = tevent_req_create(mem_ctx, &state,
849 struct cldap_netlogon_state);
850 if (!req) {
851 return NULL;
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;
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;
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;
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;
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;
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;
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;
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;
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;
908 filter = talloc_asprintf_append_buffer(filter, ")");
909 if (tevent_req_nomem(filter, req)) {
910 goto post;
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;
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;
924 state->search.in.filter = filter;
925 state->search.in.attributes = attr;
926 state->search.in.timeout = 2;
927 state->search.in.retries = 2;
929 subreq = cldap_search_send(state, cldap, &state->search);
930 if (tevent_req_nomem(subreq, req)) {
931 goto post;
933 tevent_req_set_callback(subreq, cldap_netlogon_state_done, req);
935 return req;
936 post:
937 return tevent_req_post(req, cldap->event.ctx);
940 static void cldap_netlogon_state_done(struct tevent_req *subreq)
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;
948 status = cldap_search_recv(subreq, state, &state->search);
949 talloc_free(subreq);
951 if (tevent_req_nterror(req, status)) {
952 return;
955 tevent_req_done(req);
959 receive a cldap netlogon reply
961 NTSTATUS cldap_netlogon_recv(struct tevent_req *req,
962 TALLOC_CTX *mem_ctx,
963 struct cldap_netlogon *io)
965 struct cldap_netlogon_state *state = tevent_req_data(req,
966 struct cldap_netlogon_state);
967 NTSTATUS status;
968 DATA_BLOB *data;
970 if (tevent_req_is_nterror(req, &status)) {
971 goto failed;
974 if (state->search.out.response == NULL) {
975 status = NT_STATUS_NOT_FOUND;
976 goto failed;
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;
986 data = state->search.out.response->attributes[0].values;
988 status = pull_netlogon_samlogon_response(data, mem_ctx,
989 &io->out.netlogon);
990 if (!NT_STATUS_IS_OK(status)) {
991 goto failed;
994 if (io->in.map_response) {
995 map_netlogon_samlogon_response(&io->out.netlogon);
998 status = NT_STATUS_OK;
999 failed:
1000 tevent_req_received(req);
1001 return status;
1005 sync cldap netlogon search
1007 NTSTATUS cldap_netlogon(struct cldap_socket *cldap,
1008 TALLOC_CTX *mem_ctx,
1009 struct cldap_netlogon *io)
1011 struct tevent_req *req;
1012 NTSTATUS status;
1014 if (!cldap->event.allow_poll) {
1015 return NT_STATUS_INVALID_PIPE_STATE;
1018 if (cldap->searches.list) {
1019 return NT_STATUS_PIPE_BUSY;
1022 req = cldap_netlogon_send(mem_ctx, cldap, io);
1023 NT_STATUS_HAVE_NO_MEMORY(req);
1025 if (!tevent_req_poll(req, cldap->event.ctx)) {
1026 talloc_free(req);
1027 return NT_STATUS_INTERNAL_ERROR;
1030 status = cldap_netlogon_recv(req, mem_ctx, io);
1031 talloc_free(req);
1033 return status;
1038 send an empty reply (used on any error, so the client doesn't keep waiting
1039 or send the bad request again)
1041 NTSTATUS cldap_empty_reply(struct cldap_socket *cldap,
1042 uint32_t message_id,
1043 struct tsocket_address *dest)
1045 NTSTATUS status;
1046 struct cldap_reply reply;
1047 struct ldap_Result result;
1049 reply.messageid = message_id;
1050 reply.dest = dest;
1051 reply.response = NULL;
1052 reply.result = &result;
1054 ZERO_STRUCT(result);
1056 status = cldap_reply_send(cldap, &reply);
1058 return status;
1062 send an error reply (used on any error, so the client doesn't keep waiting
1063 or send the bad request again)
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)
1071 NTSTATUS status;
1072 struct cldap_reply reply;
1073 struct ldap_Result result;
1075 reply.messageid = message_id;
1076 reply.dest = dest;
1077 reply.response = NULL;
1078 reply.result = &result;
1080 ZERO_STRUCT(result);
1081 result.resultcode = resultcode;
1082 result.errormessage = errormessage;
1084 status = cldap_reply_send(cldap, &reply);
1086 return status;
1091 send a netlogon reply
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)
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;
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;
1112 reply.messageid = message_id;
1113 reply.dest = dest;
1114 reply.response = &response;
1115 reply.result = &result;
1117 ZERO_STRUCT(result);
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;
1127 status = cldap_reply_send(cldap, &reply);
1129 talloc_free(tmp_ctx);
1131 return status;